react-beautiful-dnd#DroppableProvided TypeScript Examples
The following examples show how to use
react-beautiful-dnd#DroppableProvided.
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: TaskList.tsx From knboard with MIT License | 6 votes |
TaskList = ({ columnId, listType, tasks: tasks, index }: Props) => (
<Droppable droppableId={columnId.toString()} type={listType}>
{(
dropProvided: DroppableProvided,
dropSnapshot: DroppableStateSnapshot
) => (
<Wrapper
isDraggingOver={dropSnapshot.isDraggingOver}
isDraggingFrom={Boolean(dropSnapshot.draggingFromThisWith)}
{...dropProvided.droppableProps}
>
<InnerList
columnId={columnId}
tasks={tasks}
dropProvided={dropProvided}
index={index}
/>
</Wrapper>
)}
</Droppable>
)
Example #2
Source File: Tree.tsx From react-beautiful-tree with Apache License 2.0 | 6 votes |
patchDroppableProvided = (provided: DroppableProvided): DroppableProvided => {
return {
...provided,
innerRef: (el: HTMLElement) => {
this.containerElement = el
provided.innerRef(el)
},
}
}
Example #3
Source File: dnd.ts From revite with GNU Affero General Public License v3.0 | 5 votes |
Droppable = rbdDroppable as unknown as (
props: Omit<DroppableProps, "children"> & {
children(
provided: DroppableProvided,
snapshot: DroppableStateSnapshot,
): JSX.Element;
},
) => JSX.Element
Example #4
Source File: Tree.tsx From react-beautiful-tree with Apache License 2.0 | 5 votes |
render() {
const {
isNestingEnabled,
isVirtualizationEnabled,
virtualItemHeight,
} = this.props
const { flattenedTree } = this.state
const renderedItems = this.renderItems()
return (
<DragDropContext
onDragStart={this.onDragStart}
onDragEnd={this.onDragEnd}
onDragUpdate={this.onDragUpdate}
>
<Droppable
droppableId="tree"
isCombineEnabled={isNestingEnabled}
ignoreContainerClipping
mode={isVirtualizationEnabled ? 'virtual' : 'standard'}
renderClone={
isVirtualizationEnabled
? (provided, snapshot, rubric) =>
this.renderVirtualItem({
provided,
snapshot,
flatItem: flattenedTree[rubric.source.index],
})
: undefined
}
>
{(provided: DroppableProvided) => {
const finalProvided: DroppableProvided = this.patchDroppableProvided(
provided
)
return isVirtualizationEnabled ? (
<AutoSizer defaultHeight={1} defaultWidth={1}>
{({ height, width }: { height: number; width: number }) => (
<FixedSizeList
height={height}
itemCount={flattenedTree.length}
itemSize={virtualItemHeight}
width={width}
outerRef={provided.innerRef}
itemData={flattenedTree}
>
{this.renderVirtualRow}
</FixedSizeList>
)}
</AutoSizer>
) : (
<div
ref={finalProvided.innerRef}
style={{ pointerEvents: 'auto' }}
onTouchMove={this.onPointerMove}
onMouseMove={this.onPointerMove}
{...finalProvided.droppableProps}
>
{renderedItems}
{provided.placeholder}
</div>
)
}}
</Droppable>
</DragDropContext>
)
}
Example #5
Source File: BoardColumn.tsx From projectboard with MIT License | 5 votes |
IssueCol = ({ title, status, tasks }: Props) => {
let statusIcon = <StatusIcon status={status} />;
let tasksItems = (tasks || []).map((task, idx) => <BoardItem task={task} index={idx} />);
const history = useHistory();
const match = useRouteMatch<MatchParams>();
const onAddClick = () => {
history.push(`/projects/${match.params.projectId}/create-task`, {
status
});
};
return (
<div className="flex flex-col flex-shrink-0 mr-3 select-none w-90">
<div className="flex items-center justify-between pb-3 text-sm">
{/* left info */}
<div className="flex items-center">
{statusIcon}
<span className="ml-3 mr-3 font-medium">{title}</span>
<span className="mr-3 font-normal text-gray-400">{tasks?.length || 0}</span>
</div>
{/* action buttons */}
<div className="flex items-center">
<button
onClick={onAddClick}
className="flex items-center justify-center border-none rounded h-7 w-7 hover:bg-gray-200 focus:outline-none"
>
<AddIcon className="w-3.5 text-gray-400 hover:text-gray-700" />
</button>
</div>
</div>
<Droppable droppableId={status} key={status} type="category">
{(provided: DroppableProvided) => {
return (
<div
ref={provided.innerRef}
{...provided.droppableProps}
className="flex flex-col flex-1 w-full overflow-y-auto border-gray-200 pt-0.5"
>
{React.Children.toArray(tasksItems)}
{provided.placeholder}
</div>
);
}}
</Droppable>
</div>
);
}
Example #6
Source File: main.tsx From webminidisc with GNU General Public License v2.0 | 4 votes |
Main = (props: {}) => {
let dispatch = useDispatch();
const disc = useShallowEqualSelector(state => state.main.disc);
const deviceName = useShallowEqualSelector(state => state.main.deviceName);
const deviceStatus = useShallowEqualSelector(state => state.main.deviceStatus);
const { vintageMode } = useShallowEqualSelector(state => state.appState);
const [selected, setSelected] = React.useState<number[]>([]);
const [uploadedFiles, setUploadedFiles] = React.useState<File[]>([]);
const [lastClicked, setLastClicked] = useState(-1);
const [moveMenuAnchorEl, setMoveMenuAnchorEl] = React.useState<null | HTMLElement>(null);
const handleShowMoveMenu = useCallback(
(event: React.MouseEvent<HTMLButtonElement>) => {
setMoveMenuAnchorEl(event.currentTarget);
},
[setMoveMenuAnchorEl]
);
const handleCloseMoveMenu = useCallback(() => {
setMoveMenuAnchorEl(null);
}, [setMoveMenuAnchorEl]);
const handleMoveSelectedTrack = useCallback(
(destIndex: number) => {
dispatch(moveTrack(selected[0], destIndex));
handleCloseMoveMenu();
},
[dispatch, selected, handleCloseMoveMenu]
);
const handleDrop = useCallback(
(result: DropResult, provided: ResponderProvided) => {
if (!result.destination) return;
let sourceList = parseInt(result.source.droppableId),
sourceIndex = result.source.index,
targetList = parseInt(result.destination.droppableId),
targetIndex = result.destination.index;
dispatch(dragDropTrack(sourceList, sourceIndex, targetList, targetIndex));
},
[dispatch]
);
const handleShowDumpDialog = useCallback(() => {
dispatch(dumpDialogActions.setVisible(true));
}, [dispatch]);
useEffect(() => {
dispatch(listContent());
}, [dispatch]);
useEffect(() => {
setSelected([]); // Reset selection if disc changes
}, [disc]);
const onDrop = useCallback(
(acceptedFiles: File[], rejectedFiles: File[]) => {
setUploadedFiles(acceptedFiles);
dispatch(convertDialogActions.setVisible(true));
},
[dispatch]
);
const { getRootProps, getInputProps, isDragActive, open } = useDropzone({
onDrop,
accept: [`audio/*`, `video/mp4`],
noClick: true,
});
const classes = useStyles();
const tracks = useMemo(() => getSortedTracks(disc), [disc]);
const groupedTracks = useMemo(() => getGroupedTracks(disc), [disc]);
// Action Handlers
const handleSelectTrackClick = useCallback(
(event: React.MouseEvent, item: number) => {
if (event.shiftKey && selected.length && lastClicked !== -1) {
let rangeBegin = Math.min(lastClicked + 1, item),
rangeEnd = Math.max(lastClicked - 1, item);
let copy = [...selected];
for (let i = rangeBegin; i <= rangeEnd; i++) {
let index = copy.indexOf(i);
if (index === -1) copy.push(i);
else copy.splice(index, 1);
}
if (!copy.includes(item)) copy.push(item);
setSelected(copy);
} else if (selected.includes(item)) {
setSelected(selected.filter(i => i !== item));
} else {
setSelected([...selected, item]);
}
setLastClicked(item);
},
[selected, setSelected, lastClicked, setLastClicked]
);
const handleSelectAllClick = useCallback(
(event: React.ChangeEvent<HTMLInputElement>) => {
if (selected.length < tracks.length) {
setSelected(tracks.map(t => t.index));
} else {
setSelected([]);
}
},
[selected, tracks]
);
const handleRenameTrack = useCallback(
(event: React.MouseEvent, index: number) => {
let track = tracks.find(t => t.index === index);
if (!track) {
return;
}
dispatch(
batchActions([
renameDialogActions.setVisible(true),
renameDialogActions.setGroupIndex(null),
renameDialogActions.setCurrentName(track.title),
renameDialogActions.setCurrentFullWidthName(track.fullWidthTitle),
renameDialogActions.setIndex(track.index),
])
);
},
[dispatch, tracks]
);
const handleRenameGroup = useCallback(
(event: React.MouseEvent, index: number) => {
let group = groupedTracks.find(g => g.index === index);
if (!group) {
return;
}
dispatch(
batchActions([
renameDialogActions.setVisible(true),
renameDialogActions.setGroupIndex(index),
renameDialogActions.setCurrentName(group.title ?? ''),
renameDialogActions.setCurrentFullWidthName(group.fullWidthTitle ?? ''),
renameDialogActions.setIndex(-1),
])
);
},
[dispatch, groupedTracks]
);
const handleRenameActionClick = useCallback(
(event: React.MouseEvent) => {
if (event.detail !== 1) return; //Event retriggering when hitting enter in the dialog
handleRenameTrack(event, selected[0]);
},
[handleRenameTrack, selected]
);
const handleDeleteSelected = useCallback(
(event: React.MouseEvent) => {
dispatch(deleteTracks(selected));
},
[dispatch, selected]
);
const handleGroupTracks = useCallback(
(event: React.MouseEvent) => {
dispatch(groupTracks(selected));
},
[dispatch, selected]
);
const handleDeleteGroup = useCallback(
(event: React.MouseEvent, index: number) => {
dispatch(deleteGroup(index));
},
[dispatch]
);
const handleTogglePlayPauseTrack = useCallback(
(event: React.MouseEvent, track: number) => {
if (!deviceStatus) {
return;
}
if (deviceStatus.track !== track) {
dispatch(control('goto', track));
dispatch(control('play'));
} else if (deviceStatus.state === 'playing') {
dispatch(control('pause'));
} else {
dispatch(control('play'));
}
},
[dispatch, deviceStatus]
);
const canGroup = useMemo(() => {
return (
tracks.filter(n => n.group === null && selected.includes(n.index)).length === selected.length &&
isSequential(selected.sort((a, b) => a - b))
);
}, [tracks, selected]);
const selectedCount = selected.length;
if (vintageMode) {
const p = {
disc,
deviceName,
selected,
setSelected,
selectedCount,
tracks,
uploadedFiles,
setUploadedFiles,
onDrop,
getRootProps,
getInputProps,
isDragActive,
open,
moveMenuAnchorEl,
setMoveMenuAnchorEl,
handleShowMoveMenu,
handleCloseMoveMenu,
handleMoveSelectedTrack,
handleShowDumpDialog,
handleDeleteSelected,
handleRenameActionClick,
handleRenameTrack,
handleSelectAllClick,
handleSelectTrackClick,
};
return <W95Main {...p} />;
}
return (
<React.Fragment>
<Box className={classes.headBox}>
<Typography component="h1" variant="h4">
{deviceName || `Loading...`}
</Typography>
<TopMenu />
</Box>
<Typography component="h2" variant="body2">
{disc !== null ? (
<React.Fragment>
<span>{`${formatTimeFromFrames(disc.left, false)} left of ${formatTimeFromFrames(disc.total, false)} `}</span>
<Tooltip
title={
<React.Fragment>
<span>{`${formatTimeFromFrames(disc.left * 2, false)} left in LP2 Mode`}</span>
<br />
<span>{`${formatTimeFromFrames(disc.left * 4, false)} left in LP4 Mode`}</span>
</React.Fragment>
}
arrow
>
<span className={classes.remainingTimeTooltip}>SP Mode</span>
</Tooltip>
</React.Fragment>
) : (
`Loading...`
)}
</Typography>
<Toolbar
className={clsx(classes.toolbar, {
[classes.toolbarHighlight]: selectedCount > 0,
})}
>
{selectedCount > 0 ? (
<Checkbox
indeterminate={selectedCount > 0 && selectedCount < tracks.length}
checked={selectedCount > 0}
onChange={handleSelectAllClick}
inputProps={{ 'aria-label': 'select all tracks' }}
/>
) : null}
{selectedCount > 0 ? (
<Typography className={classes.toolbarLabel} color="inherit" variant="subtitle1">
{selectedCount} selected
</Typography>
) : (
<Typography component="h3" variant="h6" className={classes.toolbarLabel}>
{disc?.fullWidthTitle && `${disc.fullWidthTitle} / `}
{disc?.title || `Untitled Disc`}
</Typography>
)}
{selectedCount > 0 ? (
<React.Fragment>
<Tooltip title="Record from MD">
<Button aria-label="Record" onClick={handleShowDumpDialog}>
Record
</Button>
</Tooltip>
</React.Fragment>
) : null}
{selectedCount > 0 ? (
<Tooltip title="Delete">
<IconButton aria-label="delete" onClick={handleDeleteSelected}>
<DeleteIcon />
</IconButton>
</Tooltip>
) : null}
{selectedCount > 0 ? (
<Tooltip title={canGroup ? 'Group' : ''}>
<IconButton aria-label="group" disabled={!canGroup} onClick={handleGroupTracks}>
<CreateNewFolderIcon />
</IconButton>
</Tooltip>
) : null}
{selectedCount > 0 ? (
<Tooltip title="Rename">
<IconButton aria-label="rename" disabled={selectedCount !== 1} onClick={handleRenameActionClick}>
<EditIcon />
</IconButton>
</Tooltip>
) : null}
</Toolbar>
<Box className={classes.main} {...getRootProps()} id="main">
<input {...getInputProps()} />
<Table size="small">
<TableHead>
<TableRow>
<TableCell className={classes.dragHandleEmpty}></TableCell>
<TableCell className={classes.indexCell}>#</TableCell>
<TableCell>Title</TableCell>
<TableCell align="right">Duration</TableCell>
</TableRow>
</TableHead>
<DragDropContext onDragEnd={handleDrop}>
<TableBody>
{groupedTracks.map((group, index) => (
<TableRow key={`${index}`}>
<TableCell colSpan={4} style={{ padding: '0' }}>
<Table size="small">
<Droppable droppableId={`${index}`} key={`${index}`}>
{(provided: DroppableProvided, snapshot: DroppableStateSnapshot) => (
<TableBody
{...provided.droppableProps}
ref={provided.innerRef}
className={clsx({ [classes.hoveringOverGroup]: snapshot.isDraggingOver })}
>
{group.title !== null && (
<GroupRow
group={group}
onRename={handleRenameGroup}
onDelete={handleDeleteGroup}
/>
)}
{group.title === null && group.tracks.length === 0 && (
<TableRow style={{ height: '1px' }} />
)}
{group.tracks.map((t, tidx) => (
<Draggable
draggableId={`${group.index}-${t.index}`}
key={`t-${t.index}`}
index={tidx}
>
{(provided: DraggableProvided) => (
<TrackRow
track={t}
draggableProvided={provided}
inGroup={group.title !== null}
isSelected={selected.includes(t.index)}
trackStatus={getTrackStatus(t, deviceStatus)}
onSelect={handleSelectTrackClick}
onRename={handleRenameTrack}
onTogglePlayPause={handleTogglePlayPauseTrack}
/>
)}
</Draggable>
))}
{provided.placeholder}
</TableBody>
)}
</Droppable>
</Table>
</TableCell>
</TableRow>
))}
</TableBody>
</DragDropContext>
</Table>
{isDragActive ? (
<Backdrop className={classes.backdrop} open={isDragActive}>
Drop your Music to Upload
</Backdrop>
) : null}
</Box>
<Fab color="primary" aria-label="add" className={classes.add} onClick={open}>
<AddIcon />
</Fab>
<UploadDialog />
<RenameDialog />
<ErrorDialog />
<ConvertDialog files={uploadedFiles} />
<RecordDialog />
<DumpDialog trackIndexes={selected} />
<AboutDialog />
<PanicDialog />
</React.Fragment>
);
}
Example #7
Source File: PipelineEditComponents.tsx From baleen3 with Apache License 2.0 | 4 votes |
PipelineEditComponents: React.FC<PipelineEditComponentsProps> = ({
id,
type,
components,
addComponents,
moveComponent,
removeComponent,
setComponentName,
setComponentSettings,
}: PipelineEditComponentsProps) => {
const handleDrag = (result: DropResult): void => {
const { source, destination } = result
if (destination === undefined) {
return
}
if (destination.index === source.index) {
return
}
moveComponent(source.index, destination.index)
}
return (
<DragDropContext onDragEnd={handleDrag}>
<Droppable droppableId={id}>
{(provided: DroppableProvided): React.ReactElement => (
<Column
alignItems="center"
{...provided.droppableProps}
// eslint-disable-next-line @typescript-eslint/unbound-method
ref={provided.innerRef}
>
{components.map((component, index) => {
return (
<Draggable
key={component.id}
draggableId={component.id}
index={index}
>
{(
provider: DraggableProvided,
snapshot: DraggableStateSnapshot
): React.ReactElement => (
<Column
width={1}
alignItems="center"
// eslint-disable-next-line @typescript-eslint/unbound-method
ref={provider.innerRef}
{...provider.draggableProps}
>
<PipelineEditComponentSeparator
onInsert={(components: ComponentInfo[]): void =>
addComponents(components, index)
}
isDragging={snapshot.isDragging}
type={type}
/>
<PipelineComponent
{...provider.dragHandleProps}
type={type}
descriptor={component}
setName={setComponentName}
setSettings={setComponentSettings}
onDelete={removeComponent}
/>
</Column>
)}
</Draggable>
)
})}
{provided.placeholder}
<PipelineEditComponentSeparator
onInsert={(components: ComponentInfo[]): void =>
addComponents(components)
}
isDragging={false}
type={type}
/>
</Column>
)}
</Droppable>
</DragDropContext>
)
}
Example #8
Source File: Board.tsx From knboard with MIT License | 4 votes |
Board = () => {
const detail = useSelector((state: RootState) => state.board.detail);
const error = useSelector((state: RootState) => state.board.detailError);
const columns = useSelector(columnSelectors.selectAll);
const tasksByColumn = useSelector((state: RootState) => state.task.byColumn);
const tasksById = useSelector((state: RootState) => state.task.byId);
const dispatch = useDispatch();
const { id } = useParams();
React.useEffect(() => {
if (id) {
dispatch(fetchBoardById({ boardId: id }));
}
}, [id]);
const onDragEnd = (result: DropResult) => {
// dropped nowhere
if (!result.destination) {
return;
}
const source: DraggableLocation = result.source;
const destination: DraggableLocation = result.destination;
// did not move anywhere - can bail early
if (
source.droppableId === destination.droppableId &&
source.index === destination.index
) {
return;
}
// reordering column
if (result.type === "COLUMN") {
const newOrdered: IColumn[] = reorder(
columns,
source.index,
destination.index
);
dispatch(updateColumns(newOrdered));
return;
}
const data = reorderTasks({
tasksByColumn,
source,
destination,
});
dispatch(updateTasksByColumn(data.tasksByColumn));
};
const detailDataExists = detail?.id.toString() === id;
if (error) {
return <PageError>{error}</PageError>;
}
if (!detailDataExists) {
return <Spinner loading={!detailDataExists} />;
}
return (
<>
<SEO title={detail?.name} />
{columns.length !== 0 ? (
<BoardContainer data-testid="board-container">
<ColumnsBlock>
<DragDropContext onDragEnd={onDragEnd}>
<Droppable
droppableId="board"
type="COLUMN"
direction="horizontal"
>
{(provided: DroppableProvided) => (
<ColumnContainer
ref={provided.innerRef}
{...provided.droppableProps}
>
{columns.map((column: IColumn, index: number) => (
<Column
key={column.id}
id={column.id}
title={column.title}
index={index}
tasks={tasksByColumn[column.id].map(
(taskId) => tasksById[taskId]
)}
/>
))}
{provided.placeholder}
</ColumnContainer>
)}
</Droppable>
</DragDropContext>
</ColumnsBlock>
<RightMargin />
</BoardContainer>
) : (
<EmptyBoard>This board is empty.</EmptyBoard>
)}
</>
);
}
Example #9
Source File: MediaMenu.tsx From sync-party with GNU General Public License v3.0 | 4 votes |
export default function MediaMenu({
socket,
setPlayerFocused,
emitPlayWish,
freezeUiVisible,
isPlaying,
playerState
}: Props): JSX.Element {
const party: ClientParty | null = useSelector(
(state: RootAppState) => state.globalState.party
);
const playingItem: MediaItem | null = useSelector(
(state: RootAppState) => state.globalState.playingItem
);
const uiVisible = useSelector(
(state: RootAppState) => state.globalState.uiVisible
);
const uiFocused = useSelector(
(state: RootAppState) => state.globalState.uiFocused
);
const [hoverTimestamp, setHoverTimestamp] = useState(0);
const hoverTimestampRef = useRef(hoverTimestamp);
hoverTimestampRef.current = hoverTimestamp;
const [addMediaIsActive, setAddMediaIsActive] = useState(false);
const [partyItemsSet, setPartyItemsSet] = useState<Set<string>>(new Set());
const partyItemListRef = useRef<HTMLDivElement | null>(null);
const dispatch = useDispatch();
const { t } = useTranslation();
// Collect items in active party in a set for faster checks
useEffect(() => {
if (party) {
const itemsSet = new Set<string>();
party.items.forEach((item) => {
itemsSet.add(item.id);
});
setPartyItemsSet(itemsSet);
}
}, [party]);
const handleRemoveItemFromParty = async (
item: MediaItem
): Promise<void> => {
if (socket && party) {
if (
party.items.length === 1 &&
playerState.playingItem &&
playerState.playingItem.id === item.id
) {
dispatch(
setGlobalState({
errorMessage: t(`errors.removeLastItemError`)
})
);
return Promise.reject();
}
try {
const response = await Axios.delete('/api/partyItems', {
data: { itemId: item.id, partyId: party.id },
...axiosConfig()
});
if (response.data.success) {
const currentIndex = playerState.playlistIndex;
if (
playerState.playingItem &&
playerState.playingItem.id === item.id
) {
emitPlayWish(
party.items[
currentIndex < party.items.length - 1
? currentIndex + 1
: currentIndex - 1
],
playerState.isPlaying,
null,
false,
0
);
}
socket.emit('partyUpdate', {
partyId: party.id
});
setPlayerFocused(true);
} else {
dispatch(
setGlobalState({
errorMessage: t(
`apiResponseMessages.${response.data.msg}`
)
})
);
}
} catch (error) {
dispatch(
setGlobalState({
errorMessage: t(`errors.removeItemError`)
})
);
}
}
};
const handleItemEditSave = async (item: MediaItem): Promise<void> => {
if (socket && party) {
try {
const response = await Axios.put(
'/api/mediaItem/' + item.id,
item,
axiosConfig()
);
if (response.data.success) {
await getUpdatedUserItems(dispatch, t);
socket.emit('partyUpdate', { partyId: party.id });
setPlayerFocused(true);
} else {
dispatch(
setGlobalState({
errorMessage: t(
`apiResponseMessages.${response.data.msg}`
)
})
);
}
} catch (error) {
dispatch(
setGlobalState({
errorMessage: t(`errors.itemSaveError`)
})
);
}
}
};
const handleItemClick = (chosenItem: MediaItem): void => {
if (party) {
const newSource = party.items.filter((mediaItem: MediaItem) => {
return mediaItem.id === chosenItem.id;
})[0];
emitPlayWish(
newSource,
true,
playerState.playingItem ? playerState.playingItem.id : null,
true,
0
);
}
};
const onDragEnd = async (result: DropResult): Promise<void> => {
if (socket && party) {
// Dropped outside the list
if (!result.destination) {
return;
}
const orderedItems = reorderItems(
party.items,
result.source.index,
result.destination.index
);
try {
const response = await Axios.put(
'/api/partyItems',
{ orderedItems: orderedItems, partyId: party.id },
axiosConfig()
);
if (response.data.success) {
socket.emit('partyUpdate', { partyId: party.id });
} else {
dispatch(
setGlobalState({
errorMessage: t(
`apiResponseMessages.${response.data.msg}`
)
})
);
}
} catch (error) {
dispatch(
setGlobalState({
errorMessage: t(`errors.reorderError`)
})
);
}
}
};
return (
<div
className={
'mediaMenu fixed top-0 right-0 flex flex-col mt-16 p-2 border border-gray-500 rounded m-2 shadow-md backgroundShade z-50' +
(uiVisible || !playingItem || !playingItem.url ? '' : ' hidden')
}
onMouseOver={(): void => {
const now = Date.now();
if (hoverTimestampRef.current + 10000 < now) {
freezeUiVisible(true);
setHoverTimestamp(now);
}
}}
onMouseLeave={(): void => {
if (!uiFocused.chat && !addMediaIsActive) {
freezeUiVisible(false);
setHoverTimestamp(0);
}
}}
>
{party && party.items.length ? (
<div className="partyItemList" ref={partyItemListRef}>
<DragDropContext onDragEnd={onDragEnd}>
<Droppable droppableId="droppable">
{(provided: DroppableProvided): JSX.Element => (
<div
{...provided.droppableProps}
ref={provided.innerRef}
>
{party.items.map(
(
mediaItem: MediaItem,
index: number
) => {
const isCurrentlyPlayingItem =
playingItem &&
playingItem.id === mediaItem.id
? true
: false;
const alreadyPlayed =
party.metadata.played &&
party.metadata.played[
mediaItem.id
]
? true
: false;
return (
<MediaMenuDraggable
key={mediaItem.id}
mediaItemId={mediaItem.id}
index={index}
>
<ItemListed
item={mediaItem}
isPlaying={isPlaying}
isCurrentlyPlayingItem={
isCurrentlyPlayingItem
}
alreadyPlayed={
alreadyPlayed
}
nameEditingAllowed={
false
}
handleItemClick={(): void =>
handleItemClick(
mediaItem
)
}
onRemoveButtonClick={(
item: MediaItem
): void => {
handleRemoveItemFromParty(
item
);
}}
handleItemSave={(
item: MediaItem
): void => {
handleItemEditSave(
item
);
}}
setPlayerFocused={
setPlayerFocused
}
partyItemListRef={
partyItemListRef
}
></ItemListed>
</MediaMenuDraggable>
);
}
)}
</div>
)}
</Droppable>
</DragDropContext>
</div>
) : (
<div className="mb-2">There's nothing.</div>
)}
<AddMedia
isActive={addMediaIsActive}
partyItemsSet={partyItemsSet}
setAddMediaIsActive={setAddMediaIsActive}
handleItemEditSave={handleItemEditSave}
setPlayerFocused={(focused: boolean): void =>
setPlayerFocused(focused)
}
socket={socket}
></AddMedia>
</div>
);
}