react-dnd#useDrop TypeScript Examples
The following examples show how to use
react-dnd#useDrop.
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: DragItem.tsx From gio-design with Apache License 2.0 | 6 votes |
DragItem: React.FC<DragItemProps> = (props) => {
const { label, value, onMoved, index, disabled, ...rest } = props;
const prefixCls = `${usePrefixCls(PREFIX)}`;
const ref = useRef<HTMLDivElement>(null);
const [{ handlerId }, drop] = useDrop({
accept: 'drag-item',
collect(monitor) {
return {
handlerId: monitor.getHandlerId(),
};
},
hover(item: { index: number; type: string; id: string }, monitor: DropTargetMonitor) {
const dragIndex = item.index;
const hoverIndex = index;
if (dragIndex === hoverIndex) {
return;
}
const hoverBoundingRect = ref.current?.getBoundingClientRect() || { bottom: 0, top: 0 };
const hoverMiddleY = (hoverBoundingRect.bottom - hoverBoundingRect.top) / 2;
const clientOffset = monitor.getClientOffset();
const hoverClientY = (clientOffset as XYCoord).y - hoverBoundingRect.top;
// Dragging upwards or downwards
if ((dragIndex < hoverIndex && hoverClientY < hoverMiddleY) || (dragIndex > hoverIndex && hoverClientY > hoverMiddleY)) {
return
};
onMoved?.(dragIndex as number, hoverIndex);
// eslint-disable-next-line no-param-reassign
item.index = hoverIndex;
},
});
const [, drag] = useDrag({
item: { type: 'drag-item', id: value, index },
collect: (monitor: DragSourceMonitor) => ({
isDragging: monitor.isDragging(),
}),
canDrag: !disabled,
});
drag(drop(ref));
return (
<div
className={classNames(`${prefixCls}--item`, `${prefixCls}--item--drag`, {
[`${prefixCls}--item--disabled`]: disabled,
})}
ref={ref}
data-handler-id={handlerId}
>
<DragOutlined
className={classNames(`${prefixCls}--item--drag--icon`, {
[`${prefixCls}--item--drag--icon--disabled`]: disabled,
})}
color="#ADB2C2"
size="14px"
/>
<Item label={label} value={value} disabled={disabled} {...rest} />
</div>
);
}
Example #2
Source File: useDropComponent.ts From openchakra with MIT License | 6 votes |
useDropComponent = (
componentId: string,
accept: (ComponentType | MetaComponentType)[] = rootComponents,
canDrop: boolean = true,
) => {
const dispatch = useDispatch()
const [{ isOver }, drop] = useDrop({
accept,
collect: monitor => ({
isOver: monitor.isOver({ shallow: true }) && monitor.canDrop(),
}),
drop: (item: ComponentItemProps, monitor: DropTargetMonitor) => {
if (!monitor.isOver()) {
return
}
if (item.isMoved) {
dispatch.components.moveComponent({
parentId: componentId,
componentId: item.id,
})
} else if (item.isMeta) {
dispatch.components.addMetaComponent(builder[item.type](componentId))
} else {
dispatch.components.addComponent({
parentName: componentId,
type: item.type,
rootParentType: item.rootParentType,
})
}
},
canDrop: () => canDrop,
})
return { drop, isOver }
}
Example #3
Source File: DayCell.tsx From calendar-hack with MIT License | 6 votes |
DayCell: React.FC<Props> = ({ dayDetails, date, units, swap, selected, hovering, }) => {
function canSwap(d1: Date) {
return dayDetails !== undefined;
}
const [{ isOver, canDrop, droppedItem }, drop] = useDrop({
accept: ItemTypes.DAY,
canDrop: () => canSwap(date),
drop: () => { swap(date, droppedItem.date); return; },
collect: (monitor) => ({
isOver: monitor.isOver(),
canDrop: monitor.canDrop(),
droppedItem: monitor.getItem()
}),
})
return (
<div style={{
position: 'relative',
width: '100%',
height: '100%',
}}>
<DropTarget isOver={isOver} canDrop={canDrop} ref={drop}>
{dayDetails && <WorkoutCard dayDetails={dayDetails} date={date} units={units} swap={swap} />}
{!dayDetails && <BlankCard date={date} />}
{isOver && !canDrop && <Overlay color="pink" />}
{isOver && canDrop && <Overlay color="lightgreen" />}
{dayDetails && selected && <Overlay color="pink" />}
{dayDetails && !selected && hovering && <Overlay color="lightgreen" />}
</DropTarget>
</div>
);
}
Example #4
Source File: Dustbin.tsx From jetlinks-ui-antd with MIT License | 6 votes |
Dustbin: React.FC<DustbinProps> = ({
accept,
lastDroppedItem,
dropResult,
onDrop,
}) => {
const [{ isOver, canDrop }, drop] = useDrop({
accept,
drop: onDrop,
collect: monitor => ({
isOver: monitor.isOver(),
canDrop: monitor.canDrop(),
}),
})
const isActive = isOver && canDrop
let backgroundColor = '#222'
if (isActive) {
backgroundColor = 'darkgreen'
} else if (canDrop) {
backgroundColor = 'darkkhaki'
}
return (
<div ref={drop} style={{ ...style, backgroundColor }}>
{/* {isActive
? 'Release to drop'
: `This dustbin accepts: ${accept.join(', ')}`} */}
{/* {lastDroppedItem && ( */}
<p>Last dropped: {JSON.stringify(dropResult)}</p>
{/* )} */}
</div>
)
}
Example #5
Source File: DropHolder.tsx From datart with Apache License 2.0 | 6 votes |
DropHolder: React.FC<DropHolderProps> = memo(
({ tabItem, parentId }) => {
const [{ isOver, canDrop }, refDrop] = useDrop(
() => ({
accept: CONTAINER_TAB,
item: { tabItem, parentId },
drop: () => ({ tabItem, parentId }),
canDrop: (item: any) => {
if (CanDropToWidgetTypes.includes(item.type)) {
return true;
}
return false;
},
collect: (monitor: DropTargetMonitor) => ({
isOver: monitor.isOver(),
canDrop: monitor.canDrop(),
}),
}),
[],
);
const bgColor = useMemo(() => {
let color = 'transparent';
if (canDrop) {
color = '#f1e648c7';
if (isOver) {
color = '#1bcf81d3';
}
}
return color;
}, [isOver, canDrop]);
return (
<DropWrap ref={refDrop} bgColor={bgColor}>
<div className="center">将组件拖入该区域</div>
</DropWrap>
);
},
)
Example #6
Source File: index.tsx From redux-with-domain with MIT License | 6 votes |
AttriItem: FC<Props> = ({ attr: { group, fields }, index }) => {
const dispatch = useDispatch()
const chartId = useSelector(module.selectors.getChartId)
const fieldItems = fields.map(field => {
return (
<div key={field.id} className="attr-field">
{field.name}
</div>
)
})
const [_, drop] = useDrop({
accept: 'FIELD',
drop: (item: any, monitor) => {
dispatch(
module.actions.addField({ group, fieldId: item.id, index, chartId })
)
}
})
return (
<div key={group} className="attr">
<div className="attr-group">{group}</div>
<div className="attr-field-list" ref={drop}>
{fieldItems}
</div>
</div>
)
}
Example #7
Source File: ClassEditor.tsx From legend-studio with Apache License 2.0 | 5 votes |
DerviedPropertiesEditor = observer(
(props: { _class: Class; editorState: ClassEditorState }) => {
const { _class, editorState } = props;
const isReadOnly = editorState.isReadOnly;
const classState = editorState.classState;
const indirectDerivedProperties = getAllClassDerivedProperties(_class)
.filter((property) => !_class.derivedProperties.includes(property))
.sort((p1, p2) => p1.name.localeCompare(p2.name))
.sort(
(p1, p2) =>
(p1._OWNER === _class ? 1 : 0) - (p2._OWNER === _class ? 1 : 0),
);
const deleteDerivedProperty =
(dp: DerivedProperty): (() => void) =>
(): void => {
class_deleteDerivedProperty(_class, dp);
classState.deleteDerivedPropertyState(dp);
if (dp === editorState.selectedProperty) {
editorState.setSelectedProperty(undefined);
}
};
const handleDropDerivedProperty = useCallback(
(item: UMLEditorElementDropTarget): void => {
if (!isReadOnly && item.data.packageableElement instanceof Type) {
const dp = stub_DerivedProperty(item.data.packageableElement, _class);
class_addDerivedProperty(_class, dp);
classState.addDerivedPropertyState(dp);
}
},
[_class, classState, isReadOnly],
);
const [{ isDerivedPropertyDragOver }, dropDerivedPropertyRef] = useDrop(
() => ({
accept: [
CORE_DND_TYPE.PROJECT_EXPLORER_CLASS,
CORE_DND_TYPE.PROJECT_EXPLORER_ENUMERATION,
],
drop: (item: ElementDragSource): void =>
handleDropDerivedProperty(item),
collect: (monitor): { isDerivedPropertyDragOver: boolean } => ({
isDerivedPropertyDragOver: monitor.isOver({ shallow: true }),
}),
}),
[handleDropDerivedProperty],
);
useApplicationNavigationContext(
LEGEND_STUDIO_APPLICATION_NAVIGATION_CONTEXT.CLASS_EDITOR_DERIVED_PROPERTIES,
);
return (
<div
ref={dropDerivedPropertyRef}
className={clsx('panel__content__lists', {
'panel__content__lists--dnd-over':
isDerivedPropertyDragOver && !isReadOnly,
})}
>
{_class.derivedProperties
.concat(indirectDerivedProperties)
.filter((dp): dp is DerivedProperty =>
Boolean(classState.getNullableDerivedPropertyState(dp)),
)
.map((dp) => (
<DerivedPropertyBasicEditor
key={dp._UUID}
derivedProperty={dp}
_class={_class}
editorState={editorState}
deleteDerivedProperty={deleteDerivedProperty(dp)}
isReadOnly={isReadOnly}
/>
))}
</div>
);
},
)
Example #8
Source File: DayOfWeekHeader.tsx From calendar-hack with MIT License | 5 votes |
DayOfWeekHeader: React.FC<Props> = ({ dow, swapDow, selectDow, hoverDow }) => {
const [{ isOver, canDrop, droppedItem }, drop] = useDrop({
accept: ItemTypes.DOW,
canDrop: () => true,
drop: () => { swapDow(dow, droppedItem.dow); return; },
collect: (monitor) => {
if (monitor.isOver()) {
hoverDow(dow);
}
return {
isOver: monitor.isOver(),
canDrop: monitor.canDrop(),
droppedItem: monitor.getItem()
}
},
})
const [{ isDragging }, drag, preview] = useDrag({
item: { type: ItemTypes.DOW, dow: dow },
collect: (monitor) => {
if (monitor.isDragging()) {
selectDow(dow);
}
return {
isDragging: monitor.isDragging(),
};
},
begin: (monitor: DragSourceMonitor) => {
selectDow(dow);
},
end: (item: { dow: dayOfWeek } | undefined, monitor: DragSourceMonitor) => {
const dropResult = monitor.getDropResult()
if (item && dropResult) {
selectDow(undefined);
hoverDow(undefined);
}
},
})
return (
<div style={{
position: 'relative',
width: '100%',
height: '100%',
}}>
<DragSource isDragging={isDragging} dow={dow}>
<DropTarget isOver={isOver} canDrop={canDrop} ref={drop}>
<Preview generator={generateDowPreview} />
<div ref={preview}>
<Root ref={drag}>
<DragHandle viewBox="0 0 32 36" />
<div>{dow}</div>
</Root>
</div>
</DropTarget>
</DragSource>
</div>
)
}
Example #9
Source File: ClassEditor.tsx From legend-studio with Apache License 2.0 | 5 votes |
PropertiesEditor = observer(
(props: { _class: Class; editorState: ClassEditorState }) => {
const { _class, editorState } = props;
const isReadOnly = editorState.isReadOnly;
const deleteProperty =
(property: Property): (() => void) =>
(): void => {
class_deleteProperty(_class, property);
if (property === editorState.selectedProperty) {
editorState.setSelectedProperty(undefined);
}
};
const indirectProperties = getAllClassProperties(_class)
.filter((property) => !_class.properties.includes(property))
.sort((p1, p2) => p1.name.localeCompare(p2.name))
.sort(
(p1, p2) =>
(p1._OWNER === _class ? 1 : 0) - (p2._OWNER === _class ? 1 : 0),
);
const handleDropProperty = useCallback(
(item: UMLEditorElementDropTarget): void => {
if (!isReadOnly && item.data.packageableElement instanceof Type) {
class_addProperty(
_class,
stub_Property(item.data.packageableElement, _class),
);
}
},
[_class, isReadOnly],
);
const [{ isPropertyDragOver }, dropPropertyRef] = useDrop(
() => ({
accept: [
CORE_DND_TYPE.PROJECT_EXPLORER_CLASS,
CORE_DND_TYPE.PROJECT_EXPLORER_ENUMERATION,
],
drop: (item: ElementDragSource): void => handleDropProperty(item),
collect: (monitor): { isPropertyDragOver: boolean } => ({
isPropertyDragOver: monitor.isOver({ shallow: true }),
}),
}),
[handleDropProperty],
);
useApplicationNavigationContext(
LEGEND_STUDIO_APPLICATION_NAVIGATION_CONTEXT.CLASS_EDITOR_PROPERTIES,
);
return (
<div
ref={dropPropertyRef}
className={clsx('panel__content__lists', {
'panel__content__lists--dnd-over': isPropertyDragOver && !isReadOnly,
})}
>
{_class.properties.concat(indirectProperties).map((property) => (
<PropertyBasicEditor
key={property._UUID}
property={property}
_class={_class}
editorState={editorState}
deleteProperty={deleteProperty(property)}
isReadOnly={isReadOnly}
/>
))}
</div>
);
},
)
Example #10
Source File: DragAndDropTreeComponent.tsx From frontend-sample-showcase with MIT License | 5 votes |
DragAndDropNode: React.FC<TreeNodeRendererProps> = (props) => {
const { treeModelSource, treeNodeLoader, isDragging, setDragging } = React.useContext(dragDropContext)!;
// Make node draggable
const [, dragSourceRef] = useDrag({
item: { type: "tree-node", id: props.node.id },
begin: () => setDragging(true),
end: () => setDragging(false),
});
// Make node accept drop events
const [{ isHovered }, dropTargetRef] = useDrop({
accept: "tree-node",
hover: handleHover,
canDrop: handleCanDrop,
drop: handleDrop,
collect: (monitor) => ({ isHovered: monitor.isOver() }),
});
const [canDrop, setCanDrop] = React.useState(false);
function handleCanDrop(item: NodeDragObject): boolean {
// Do not allow dropping a node in such a way that would create a parent-child relationship cycle
const isDroppingOnSelf = props.node.id === item.id && dropArea === DropArea.Inside;
const newCanDrop = !isDroppingOnSelf && !areNodesRelated(treeModelSource.getModel(), item.id, props.node.id);
setCanDrop(newCanDrop);
return newCanDrop;
}
const elementRef = React.useRef<HTMLDivElement>(null);
const [dropArea, setDropArea] = React.useState<DropArea>(DropArea.Inside);
function handleHover(item: NodeDragObject, monitor: DropTargetMonitor): void {
// Determine which drop area is hovered and whether we can drop the node there
const cursorY = monitor.getClientOffset()?.y;
const dropTargetY = elementRef.current?.getBoundingClientRect().y;
if (cursorY !== undefined && dropTargetY !== undefined) {
setDropArea(determineDropArea(25, 7, cursorY - dropTargetY));
handleCanDrop(item);
}
}
function handleDrop(item: NodeDragObject): void {
// The main entry point for drop event handling
const { parentId, index } = getDropLocation(treeModelSource.getModel(), props.node, dropArea);
moveNode(treeModelSource, treeNodeLoader, item.id, parentId, index)
.catch((error) => {
// eslint-disable-next-line no-console
console.error(error);
});
}
const isDropAreaDisplayed = isHovered && canDrop;
const nodeStyle: React.CSSProperties = {
height: 25,
...(isDropAreaDisplayed && dropArea === DropArea.Inside && { background: "var(--buic-row-hover)" }),
};
return (
<div ref={mergeRefs([dragSourceRef, dropTargetRef, elementRef])}>
<div style={{ height: 0 }}>
{isDropAreaDisplayed && dropArea === DropArea.Above && <NodeInsertMarker topOffset={0} />}
{isDropAreaDisplayed && dropArea === DropArea.Below && <NodeInsertMarker topOffset={25} />}
</div>
<BasicTreeNode style={nodeStyle} isHoverDisabled={isDragging} {...props} />
</div>
);
}
Example #11
Source File: BindingElementEditor.tsx From legend-studio with Apache License 2.0 | 5 votes |
BindingScopeEditor = observer(
(props: {
elements: PackageableElementReference<PackageableElement>[];
addElement: () => void;
removeElement: (
val: PackageableElementReference<PackageableElement>,
) => void;
allowAddingElement: boolean;
handleDropElement: (item: UMLEditorElementDropTarget) => void;
isReadOnly: boolean;
}) => {
const {
elements,
addElement,
removeElement,
allowAddingElement,
handleDropElement,
isReadOnly,
} = props;
const [{ isElementDragOver }, dropElementRef] = useDrop(
() => ({
accept: [
CORE_DND_TYPE.PROJECT_EXPLORER_ENUMERATION,
CORE_DND_TYPE.PROJECT_EXPLORER_PACKAGE,
CORE_DND_TYPE.PROJECT_EXPLORER_CLASS,
CORE_DND_TYPE.PROJECT_EXPLORER_PROFILE,
CORE_DND_TYPE.PROJECT_EXPLORER_ASSOCIATION,
CORE_DND_TYPE.PROJECT_EXPLORER_FUNCTION,
],
drop: (item: ElementDragSource): void => handleDropElement(item),
collect: (monitor): { isElementDragOver: boolean } => ({
isElementDragOver: monitor.isOver({ shallow: true }),
}),
}),
[handleDropElement],
);
return (
<div className="binding-scope-editor">
<div
ref={dropElementRef}
className="binding-scope-editor__panel__content dnd__overlay__container"
>
<div
className={clsx({ dnd__overlay: isElementDragOver && !isReadOnly })}
/>
<div className="binding-scope-editor__panel__content__form">
<div className="binding-scope-editor__panel__content__form__section">
<div className="binding-scope-editor__panel__content__form__section__list">
{elements.map((elementRef) => (
<BindingScopeEntryEditor
key={elementRef.value._UUID}
elementRef={elementRef}
removeElement={removeElement}
isReadOnly={isReadOnly}
/>
))}
<div className="binding-scope-editor__panel__content__form__section__list__new-item__add">
<button
className="binding-scope-editor__panel__content__form__section__list__new-item__add-btn btn btn--dark"
disabled={!allowAddingElement}
tabIndex={-1}
onClick={addElement}
title="Add Element"
>
Add Value
</button>
</div>
</div>
</div>
</div>
</div>
</div>
);
},
)
Example #12
Source File: DataDocNavigator.tsx From querybook with Apache License 2.0 | 5 votes |
FavoriteDataDocsSection: React.FC<ICommonSectionProps> = (props) => {
const { selectedDocId, loadedFilterModes, filterString } = props;
const section = 'favorite';
const { collapsed, setCollapsed, load } = useCommonNavigatorState(
section,
props
);
const dataDocs = useSelector(favoriteDataDocsSelector);
const dispatch = useDispatch();
const [{ isOver }, dropRef] = useDrop({
accept: [BoardDraggableType, DataDocDraggableType],
drop: (item: IDragItem<IDataDoc | IProcessedBoardItem>, monitor) => {
if (monitor.didDrop()) {
return;
}
let docId: number = null;
if (item.type === BoardDraggableType) {
const itemInfo = item.itemInfo as IProcessedBoardItem;
if (itemInfo.itemType === 'data_doc') {
docId = itemInfo.itemId;
}
} else {
docId = (item.itemInfo as IDataDoc).id;
}
if (docId != null) {
dispatch(dataDocActions.favoriteDataDoc(docId));
}
},
collect: (monitor) => {
const item: IDragItem = monitor.getItem();
return {
isOver:
item?.type === BoardDraggableType &&
((item?.itemInfo as unknown) as IProcessedBoardItem)
.itemType === 'table'
? false
: monitor.isOver(),
};
},
});
const handleUnfavoriteDataDoc = useCallback(
(dataDoc: IDataDoc) =>
dispatch(dataDocActions.unfavoriteDataDoc(dataDoc.id)),
[]
);
return (
<div
className={isOver ? 'nav-favorite-dragged-over' : ''}
ref={dropRef}
>
<DataDocNavigatorSection
sectionHeader={'Favorites'}
sectionHeaderIcon="Star"
dataDocs={dataDocs}
selectedDocId={selectedDocId}
filterString={filterString}
loaded={!!loadedFilterModes[section]}
loadDataDocs={load}
collapsed={collapsed}
setCollapsed={setCollapsed}
onRemove={handleUnfavoriteDataDoc}
allowReorder
/>
</div>
);
}
Example #13
Source File: QueryBuilderGraphFetchTreePanel.tsx From legend-studio with Apache License 2.0 | 5 votes |
QueryBuilderGraphFetchTreePanel = observer(
(props: { queryBuilderState: QueryBuilderState }) => {
const { queryBuilderState } = props;
const fetchStructureState = queryBuilderState.fetchStructureState;
const graphFetchState = fetchStructureState.graphFetchTreeState;
const treeData = graphFetchState.treeData;
// Deep/Graph Fetch Tree
const updateTreeData = (data: QueryBuilderGraphFetchTreeData): void => {
graphFetchState.setGraphFetchTree(data);
};
// Drag and Drop
const handleDrop = useCallback(
(item: QueryBuilderExplorerTreeDragSource): void => {
graphFetchState.addProperty(item.node);
},
[graphFetchState],
);
const [{ isPropertyDragOver }, dropConnector] = useDrop(
() => ({
accept: [
QUERY_BUILDER_EXPLORER_TREE_DND_TYPE.ENUM_PROPERTY,
QUERY_BUILDER_EXPLORER_TREE_DND_TYPE.PRIMITIVE_PROPERTY,
],
drop: (
item: QueryBuilderExplorerTreeDragSource,
monitor: DropTargetMonitor,
): void => {
if (!monitor.didDrop()) {
handleDrop(item);
} // prevent drop event propagation to accomondate for nested DnD
},
collect: (monitor): { isPropertyDragOver: boolean } => ({
isPropertyDragOver: monitor.isOver({ shallow: true }),
}),
}),
[handleDrop],
);
return (
<div
data-testid={QUERY_BUILDER_TEST_ID.QUERY_BUILDER_GRAPH_FETCH}
className="panel__content dnd__overlay__container"
ref={dropConnector}
>
<div className={clsx({ dnd__overlay: isPropertyDragOver })} />
{(!treeData || isGraphFetchTreeDataEmpty(treeData)) && (
<BlankPanelPlaceholder
placeholderText="Add a graph fetch property"
tooltipText="Drag and drop properties here"
/>
)}
{treeData && !isGraphFetchTreeDataEmpty(treeData) && (
<QueryBuilderGraphFetchTreeExplorer
graphFetchState={graphFetchState}
treeData={treeData}
isReadOnly={false}
updateTreeData={updateTreeData}
/>
)}
</div>
);
},
)
Example #14
Source File: useReorderTodo.tsx From remix-hexagonal-architecture with MIT License | 5 votes |
useReorderTodo = (
todoListId: string,
todo: TodoDto,
currentIndex: number,
onPreviewMove: (todoId: string, newIndex: number) => void
) => {
const todosOrder = useFetcher();
const moveTodo = (newIndex: number) => {
const formData = new FormData();
formData.append("todoId", todo.id);
formData.append("newIndex", newIndex.toString());
todosOrder.submit(formData, {
method: "put",
action: `/l/${todoListId}/order`,
});
};
const [{ isDragging }, drag, preview] = useDrag<
DragItem,
DropResult,
CollectedProps
>({
type: DragTypeTodo,
item: { todoId: todo.id },
collect: (monitor) => ({
isDragging: monitor.isDragging(),
}),
end: (item, monitor) => {
const dropResult = monitor.getDropResult();
if (dropResult?.newIndex != null) moveTodo(dropResult.newIndex);
},
});
const [, drop] = useDrop<DragItem, DropResult>({
accept: DragTypeTodo,
hover: (item) => {
onPreviewMove(item.todoId, currentIndex);
},
drop: () => ({
newIndex: currentIndex,
}),
});
return {
isDragging,
ref: (node: HTMLDivElement | null) => drag(drop(node)),
preview,
};
}
Example #15
Source File: navigator-item-dnd-container.tsx From utopia with MIT License | 5 votes |
NavigatorItemContainer = React.memo((props: NavigatorItemDragAndDropWrapperProps) => {
const [{ isDragging }, drag] = useDrag(
() => ({
type: 'NAVIGATOR_ITEM',
collect: (monitor) => ({
isDragging: monitor.isDragging(),
}),
item: props,
beginDrag: beginDrag,
}),
[props],
)
const dropRef = React.useRef<HTMLDivElement | null>(null)
const [{ isOver }, drop] = useDrop<
NavigatorItemDragAndDropWrapperProps,
unknown,
DropCollectedProps
>(
() => ({
accept: 'NAVIGATOR_ITEM',
collect: (monitor) => ({
isOver: monitor.isOver(),
canDrop: monitor.canDrop(),
}),
hover: (item: NavigatorItemDragAndDropWrapperProps, monitor) => {
onHover(item, props, monitor, dropRef.current)
},
drop: (item: NavigatorItemDragAndDropWrapperProps, monitor) => {
onDrop(item, props, monitor, dropRef.current)
},
}),
[props],
)
const attachDrop = React.useCallback(
(domElement: HTMLDivElement) => {
drop(domElement)
dropRef.current = domElement
},
[drop, dropRef],
)
return (
<div ref={attachDrop}>
<div ref={drag}>
<NavigatorItemDndWrapper {...props} isOver={isOver} isDragging={isDragging} />
</div>
</div>
)
})
Example #16
Source File: index.tsx From ql with MIT License | 5 votes |
DragableBodyRow = ({
index,
moveRow,
className,
style,
...restProps
}: any) => {
const ref = useRef();
const [{ isOver, dropClassName }, drop] = useDrop(
() => ({
accept: type,
collect: (monitor) => {
const { index: dragIndex } = monitor.getItem() || ({} as any);
if (dragIndex === index) {
return {};
}
return {
isOver: monitor.isOver(),
dropClassName:
dragIndex < index ? ' drop-over-downward' : ' drop-over-upward',
};
},
drop: (item: any) => {
moveRow(item.index, index);
},
}),
[index],
);
const [, drag, preview] = useDrag(
() => ({
type,
item: { index },
collect: (monitor) => ({
isDragging: monitor.isDragging(),
}),
}),
[index],
);
drop(drag(ref));
return (
<tr
ref={ref}
className={`${className}${isOver ? dropClassName : ''}`}
style={{ cursor: 'move', ...style }}
{...restProps}
>
{restProps.children}
</tr>
);
}
Example #17
Source File: ContextItem.tsx From next-basics with GNU General Public License v3.0 | 5 votes |
export function ContextItem({
index,
data,
canDrag,
highlighted,
handleDropItem,
handleItemClick,
handleItemDelete,
handleItemHover,
}: ContextItemProps): React.ReactElement {
const ref = useRef();
const [{ isOver, dropClassName }, drop] = useDrop({
accept: type,
collect: (monitor) => {
const { index: dragIndex } = monitor.getItem() || {};
if (dragIndex === index) {
return {};
}
return {
isOver: monitor.isOver(),
dropClassName:
dragIndex < index
? `${styles.dropOverDownward}`
: `${styles.dropOverUpward}`,
};
},
drop: (item: any) => {
handleDropItem(item.index, index);
},
});
const [{ isDragging }, drag] = useDrag({
item: { type, index },
canDrag,
collect: (monitor) => ({
isDragging: monitor.isDragging(),
}),
});
drop(drag(ref));
const handleMouseEnter = (): void => {
handleItemHover(data.name);
};
const handleMouseLeave = (): void => {
handleItemHover();
};
return (
<div
ref={ref}
className={classNames(styles.varItem, {
[dropClassName]: isOver,
[styles.highlighted]: highlighted,
})}
onClick={handleItemClick}
key={data.name}
onMouseEnter={handleMouseEnter}
onMouseLeave={handleMouseLeave}
>
{data.resolve ? (
<LinkOutlined style={{ color: "var(--theme-orange-color)" }} />
) : (
<CodeOutlined style={{ color: "var(--theme-green-color)" }} />
)}
<span className={styles.varName}>{data.name}</span>
<Button
type="link"
danger
icon={<DeleteOutlined />}
className={styles.deleteIcon}
onClick={handleItemDelete}
/>
</div>
);
}
Example #18
Source File: fileitem.tsx From utopia with MIT License | 5 votes |
export function FileBrowserItem(props: FileBrowserItemProps) {
const [{ isDragging }, drag, dragPreview] = useDrag(
() => ({
type: 'files',
canDrag: () => canDragnDrop(props),
collect: (monitor) => ({
isDragging: monitor.isDragging(),
}),
item: () => {
props.dispatch([
EditorActions.switchEditorMode(
EditorModes.insertMode(false, dragAndDropInsertionSubject([props.path])),
),
])
return props
},
}),
[props],
)
const [{ isOver }, drop] = useDrop(
{
accept: 'files',
canDrop: () => true,
drop: (item, monitor) => {
onDrop(props, item)
},
hover: (item: FileBrowserItemProps) => {
const targetDirectory =
props.fileType === 'DIRECTORY' ? props.path : getParentDirectory(props.path)
// do not trigger highlight when it tries to move to it's descendant directories
if (targetDirectory.includes(item.path)) {
if (props.dropTarget != null) {
props.dispatch([EditorActions.setFilebrowserDropTarget(null)], 'leftpane')
}
} else {
if (props.dropTarget !== targetDirectory) {
props.dispatch([EditorActions.setFilebrowserDropTarget(targetDirectory)], 'leftpane')
}
}
},
collect: (monitor) => ({
isOver: monitor.isOver(),
}),
},
[props],
)
const forwardedRef = (node: ConnectableElement) => drag(drop(node))
return (
<FileBrowserItemInner
{...props}
isDragging={isDragging}
isOver={isOver}
connectDragPreview={dragPreview}
// eslint-disable-next-line react/jsx-no-bind
forwardedRef={forwardedRef}
/>
)
}
Example #19
Source File: ElementListItemDraggable.tsx From openchakra with MIT License | 5 votes |
ElementListItemDraggable: React.FC<Props> = ({
type,
id,
onSelect,
moveItem,
index,
onHover,
onUnhover,
name,
}) => {
const ref = useRef<HTMLDivElement>(null)
const [, drop] = useDrop({
accept: ITEM_TYPE,
hover(item: DragObjectWithType, monitor) {
if (!ref.current) {
return
}
// @ts-ignore
const dragIndex = item.index
const hoverIndex = index
if (dragIndex === hoverIndex) {
return
}
const hoverBoundingRect = ref.current.getBoundingClientRect()
const hoverMiddleY =
(hoverBoundingRect.bottom - hoverBoundingRect.top) / 2
const clientOffset = monitor.getClientOffset()
const hoverClientY = (clientOffset as XYCoord).y - hoverBoundingRect.top
if (dragIndex < hoverIndex && hoverClientY < hoverMiddleY) {
return
}
if (dragIndex > hoverIndex && hoverClientY > hoverMiddleY) {
return
}
if (moveItem) {
moveItem(dragIndex, hoverIndex)
}
// @ts-ignore
item.index = hoverIndex
},
})
const [{ isDragging }, drag] = useDrag({
item: { type: ITEM_TYPE, id, index },
collect: monitor => ({
isDragging: monitor.isDragging(),
}),
})
const opacity = isDragging ? 0 : 1
drag(drop(ref))
const onSelectElement = () => {
onSelect(id)
}
const onMouseOver = () => {
onHover(id)
}
return (
<ElementListItem
ref={ref}
onSelect={onSelectElement}
opacity={opacity}
onMouseOver={onMouseOver}
onMouseOut={onUnhover}
type={type}
draggable
name={name}
/>
)
}
Example #20
Source File: BrickTable.tsx From next-basics with GNU General Public License v3.0 | 5 votes |
DraggableBodyRow = ({
index,
moveRow,
className,
style,
...restProps
}) => {
const ref = React.useRef();
const [{ isOver, dropClassName }, drop] = useDrop({
accept: type,
collect: (monitor) => {
const { index: dragIndex } = monitor.getItem() || {};
if (dragIndex === index) {
return {};
}
return {
isOver: monitor.isOver(),
dropClassName:
dragIndex < index
? `${styles.dropOverDownward}`
: `${styles.dropOverUpward}`,
};
},
drop: (item: any) => {
moveRow(item.index, index);
},
});
const [, drag] = useDrag({
item: { type, index },
collect: (monitor) => ({
isDragging: monitor.isDragging(),
}),
});
drop(drag(ref));
return (
<tr
ref={ref}
className={classNames(className, styles.draggableRow, {
[dropClassName]: isOver,
})}
style={{ cursor: "move", ...style }}
{...restProps}
/>
);
}
Example #21
Source File: use-hooks.tsx From erda-ui with GNU Affero General Public License v3.0 | 5 votes |
useListDnD = ({ type, index, onMove, collect }: IDragProps) => {
const dragRef = useRef<HTMLDivElement>(null);
const [, drop] = useDrop({
accept: type,
hover(item: DragItem, monitor: DropTargetMonitor) {
if (!dragRef.current) {
return;
}
const dragIndex = item.index;
const hoverIndex = index;
// Don't replace items with themselves
if (dragIndex === hoverIndex) {
return;
}
// Determine rectangle on screen
const hoverBoundingRect = dragRef.current!.getBoundingClientRect();
// Get vertical middle
const hoverMiddleY = (hoverBoundingRect.bottom - hoverBoundingRect.top) / 2;
// Determine mouse position
const clientOffset = monitor.getClientOffset();
// Get pixels to the top
const hoverClientY = (clientOffset as XYCoord).y - hoverBoundingRect.top;
// Only perform the move when the mouse has crossed half of the items height
// When dragging downwards, only move when the cursor is below 50%
// When dragging upwards, only move when the cursor is above 50%
// Dragging downwards
if (dragIndex < hoverIndex && hoverClientY < hoverMiddleY) {
return;
}
// Dragging upwards
if (dragIndex > hoverIndex && hoverClientY > hoverMiddleY) {
return;
}
// Time to actually perform the action
onMove(dragIndex, hoverIndex);
// Note: we're mutating the monitor item here!
// Generally it's better to avoid mutations,
// but it's good here for the sake of performance
// to avoid expensive index searches.
item.index = hoverIndex;
},
});
const [collectedProps, drag, previewRef] = useDrag({
item: { index, type },
collect,
});
drag(drop(dragRef));
return [dragRef, previewRef, collectedProps];
}
Example #22
Source File: DragSortEditTable.tsx From datart with Apache License 2.0 | 5 votes |
DraggableAndEditableBodyRow = ({
index,
moveRow,
className,
style,
...restProps
}) => {
const [form] = Form.useForm();
const ref = useRef(null);
const [{ isOver, dropClassName }, drop] = useDrop({
accept: type,
collect: monitor => {
const { index: dragIndex } = monitor.getItem<{ index: number }>() || {};
if (dragIndex === index) {
return {};
}
return {
isOver: monitor.isOver(),
dropClassName:
dragIndex < index ? ' drop-over-downward' : ' drop-over-upward',
};
},
drop: (item: { index: number }) => {
moveRow(item.index, index);
},
});
const [, drag] = useDrag({
type,
item: { index },
collect: monitor => ({
isDragging: monitor.isDragging(),
}),
});
drop(drag(ref));
return (
<Form form={form} component={false}>
<EditableContext.Provider value={form}>
<tr
ref={ref}
className={`${className}${isOver ? dropClassName : ''}`}
style={{ cursor: 'move', ...style }}
{...restProps}
/>
</EditableContext.Provider>
</Form>
);
}
Example #23
Source File: OperationSetImplementationEditor.tsx From legend-studio with Apache License 2.0 | 4 votes |
OperationSetImplementationEditor = observer(
(props: {
setImplementation: OperationSetImplementation;
isReadOnly: boolean;
}) => {
const { setImplementation, isReadOnly } = props;
const editorStore = useEditorStore();
const mappingEditorState =
editorStore.getCurrentEditorState(MappingEditorState);
const mapping = mappingEditorState.mapping;
// Parameters
const setImplementationOptions = getClassMappingsByClass(
mapping,
setImplementation.class.value,
)
.filter(
(si) =>
// filter out the current set impl
si.id.value !== setImplementation.id.value &&
// filter out set impls already included through a container or the actual container itself
!getAllChildSetImplementations(setImplementation).includes(si),
)
.map((si) => ({ value: si, label: si.id.value }));
const filterOption = createFilter({
stringify: (option: SetImplementationOption): string => option.label,
});
const addParameter = (): void =>
operationMapping_addParameter(
setImplementation,
new SetImplementationContainer(
SetImplementationExplicitReference.create(
new OperationSetImplementation(
InferableMappingElementIdExplicitValue.create('', ''),
new Mapping(''),
PackageableElementExplicitReference.create(new Class('')),
InferableMappingElementRootExplicitValue.create(false),
OperationType.STORE_UNION,
),
),
),
);
const deleteParameter =
(val: SetImplementationContainer): (() => void) =>
(): void =>
operationMapping_deleteParameter(setImplementation, val);
const changeParamater =
(
val: SetImplementationContainer,
): ((option: SetImplementationOption | null) => void) =>
(option: SetImplementationOption | null): void => {
const setImpl = option?.value;
if (setImpl) {
operationMapping_changeParameter(
setImplementation,
val,
new SetImplementationContainer(
SetImplementationExplicitReference.create(setImpl),
),
);
}
};
// Drag and Drop
const handleDrop = useCallback(
(item: OperationSetImplementationDropTarget): void => {
const mappingElement = item.data;
if (
mappingElement instanceof SetImplementation &&
setImplementation.operation !== OperationType.INHERITANCE &&
mappingElement.class.value === setImplementation.class.value &&
!setImplementation.parameters.find(
(param) => param.setImplementation.value === mappingElement,
) &&
mappingElement !== setImplementation
) {
operationMapping_addParameter(
setImplementation,
new SetImplementationContainer(
SetImplementationExplicitReference.create(mappingElement),
),
);
}
},
[setImplementation],
);
const [{ isDragOver }, dropRef] = useDrop(
() => ({
accept: CORE_DND_TYPE.MAPPING_EXPLORER_CLASS_MAPPING,
drop: (item: MappingElementDragSource): void => handleDrop(item),
collect: (monitor): { isDragOver: boolean } => ({
isDragOver: monitor.isOver({ shallow: true }),
}),
}),
[handleDrop],
);
// actions
const visit =
(param: SetImplementationContainer): (() => void) =>
(): void => {
const parent = param.setImplementation.value._PARENT;
// TODO: think more about this flow. Right now we open the mapping element in the parent mapping
if (parent !== mappingEditorState.element) {
editorStore.openElement(parent);
editorStore
.getCurrentEditorState(MappingEditorState)
.openMappingElement(param.setImplementation.value, false);
} else {
mappingEditorState.openMappingElement(
param.setImplementation.value,
true,
);
}
};
useEffect(() => {
if (!isReadOnly) {
setImplementation.accept_SetImplementationVisitor(
new MappingElementDecorator(editorStore),
);
}
return isReadOnly
? noop()
: (): void =>
setImplementation.accept_SetImplementationVisitor(
new MappingElementDecorationCleaner(editorStore),
);
}, [setImplementation, isReadOnly, editorStore]);
return (
<div className="mapping-element-editor__content">
<div className="panel">
<div className="panel__header">
<div className="panel__header__title">
<div className="panel__header__title__content">PARAMETERS</div>
</div>
<div className="panel__header__actions">
<button
className="panel__header__action"
disabled={
isReadOnly ||
setImplementation.operation === OperationType.INHERITANCE
}
onClick={addParameter}
tabIndex={-1}
title={'Add parameter'}
>
<PlusIcon />
</button>
</div>
</div>
<div
ref={dropRef}
className={clsx('panel__content', {
'operation-mapping-editor__parameters--dnd-over':
isDragOver && !isReadOnly,
})}
>
{setImplementation.parameters.map((param) => (
<div
key={param._UUID}
className="operation-mapping-editor__parameter"
>
<div className="operation-mapping-editor__parameter__selector">
<CustomSelectorInput
options={setImplementationOptions}
disabled={isReadOnly}
onChange={changeParamater(param)}
filterOption={filterOption}
value={{
value: param,
label: param.setImplementation.value.id.value,
}}
placeholder={`Select parameter ID`}
/>
</div>
<button
className="operation-mapping-editor__parameter__visit-btn"
onClick={visit(param)}
tabIndex={-1}
title={'Visit mapping element'}
>
<ArrowCircleRightIcon />
</button>
{!isReadOnly && (
<button
className="operation-mapping-editor__parameter__remove-btn"
disabled={isReadOnly}
onClick={deleteParameter(param)}
tabIndex={-1}
title={'Remove'}
>
<TimesIcon />
</button>
)}
</div>
))}
</div>
</div>
</div>
);
},
)
Example #24
Source File: ThumbnailItem.tsx From datart with Apache License 2.0 | 4 votes |
ThumbnailItem: React.FC<IProps> = ({
page,
index,
selected,
moveCard,
moveEnd,
}) => {
const dispatch = useDispatch();
const ItemRef = useRef<HTMLDivElement>(null);
const dashboard = useSelector((state: { board: BoardState }) =>
makeSelectBoardConfigById()(state, page.relId),
);
useEffect(() => {
try {
const { thumbnail, name } = dashboard as Dashboard;
dispatch(
storyActions.updateStoryPageNameAndThumbnail({
storyId: page.storyId,
pageId: page.id,
name,
thumbnail,
}),
);
} catch (error) {}
// storyActions.updateStoryPageNameAndThumbnail
}, [dashboard, dispatch, page.id, page.storyId]);
const [{ handlerId }, drop] = useDrop({
accept: 'storyBoardListDnd',
collect(monitor) {
return {
handlerId: monitor.getHandlerId(),
};
},
hover(item: DragItem, monitor: DropTargetMonitor) {
if (!ItemRef.current) {
return;
}
const dragIndex = item.index;
const hoverIndex = page.index;
const hoverSelected = item.selected;
// const dragId = item.id;
// Don't replace items with themselves
if (dragIndex === hoverIndex) {
return;
}
// Determine rectangle on screen
const hoverBoundingRect = ItemRef.current?.getBoundingClientRect();
// Get vertical middle
const hoverMiddleY =
(hoverBoundingRect.bottom - hoverBoundingRect.top) / 2;
// Determine mouse position
const clientOffset = monitor.getClientOffset();
// Get pixels to the top
const hoverClientY = (clientOffset as XYCoord).y - hoverBoundingRect.top;
// Only perform the move when the mouse has crossed half of the items height
// When dragging downwards, only move when the cursor is below 50%
// When dragging upwards, only move when the cursor is above 50%
// Dragging downwards
if (dragIndex < hoverIndex && hoverClientY < hoverMiddleY) {
return;
}
// Dragging upwards
if (dragIndex > hoverIndex && hoverClientY > hoverMiddleY) {
return;
}
// Time to actually perform the action
moveCard(item.id, page.id);
// Note: we're mutating the monitor item here!
// Generally it's better to avoid mutations,
// but it's good here for the sake of performance
// to avoid expensive index searches.
item.index = hoverIndex;
item.selected = hoverSelected;
},
});
const [{ isDragging }, drag] = useDrag({
type: 'storyBoardListDnd',
item: () => {
return {
id: page.id,
index: page.index,
selected: selected,
};
},
collect: (monitor: any) => ({
isDragging: monitor.isDragging(),
}),
end() {
moveEnd();
},
});
const opacity = isDragging ? 0.1 : 1;
// 使用 drag 和 drop 包装 ref
drag(drop(ItemRef));
return (
<ItemWrap selected={selected}>
<div
className="item"
ref={ItemRef}
data-handler-id={handlerId}
style={{ opacity }}
>
<p>{index}</p>
<h4>{page.name}</h4>
</div>
</ItemWrap>
);
}
Example #25
Source File: MappingTestEditor.tsx From legend-studio with Apache License 2.0 | 4 votes |
MappingTestQueryEditor = observer(
(props: { testState: MappingTestState; isReadOnly: boolean }) => {
const { testState, isReadOnly } = props;
const queryState = testState.queryState;
const editorStore = useEditorStore();
const applicationStore = useApplicationStore();
const extraQueryEditorActions = editorStore.pluginManager
.getStudioPlugins()
.flatMap(
(plugin) =>
(
plugin as DSLMapping_LegendStudioPlugin_Extension
).getExtraMappingTestQueryEditorActionConfigurations?.() ?? [],
)
.map((config) => (
<Fragment key={config.key}>
{config.renderer(testState, isReadOnly)}
</Fragment>
));
// Class mapping selector
const [openClassMappingSelectorModal, setOpenClassMappingSelectorModal] =
useState(false);
const showClassMappingSelectorModal = (): void =>
setOpenClassMappingSelectorModal(true);
const hideClassMappingSelectorModal = (): void =>
setOpenClassMappingSelectorModal(false);
const changeClassMapping = useCallback(
(setImplementation: SetImplementation | undefined): void => {
// do all the necessary updates
flowResult(
queryState.updateLamba(
setImplementation
? editorStore.graphManagerState.graphManager.HACKY__createGetAllLambda(
guaranteeType(
getMappingElementTarget(setImplementation),
Class,
),
)
: stub_RawLambda(),
),
).catch(applicationStore.alertUnhandledError);
hideClassMappingSelectorModal();
// Attempt to generate data for input data panel as we pick the class mapping
if (setImplementation) {
editorStore.setActionAlertInfo({
message: 'Mapping test input data is already set',
prompt: 'Do you want to regenerate the input data?',
type: ActionAlertType.CAUTION,
onEnter: (): void => editorStore.setBlockGlobalHotkeys(true),
onClose: (): void => editorStore.setBlockGlobalHotkeys(false),
actions: [
{
label: 'Regenerate',
type: ActionAlertActionType.PROCEED_WITH_CAUTION,
handler: (): void =>
testState.setInputDataStateBasedOnSource(
getMappingElementSource(
setImplementation,
editorStore.pluginManager.getStudioPlugins(),
),
true,
),
},
{
label: 'Keep my input data',
type: ActionAlertActionType.PROCEED,
default: true,
},
],
});
}
},
[applicationStore, editorStore, testState, queryState],
);
// Drag and Drop
const handleDrop = useCallback(
(item: MappingElementDragSource): void => {
changeClassMapping(guaranteeType(item.data, SetImplementation));
},
[changeClassMapping],
);
const [{ isDragOver, canDrop }, dropRef] = useDrop(
() => ({
accept: CORE_DND_TYPE.MAPPING_EXPLORER_CLASS_MAPPING,
drop: (item: MappingElementDragSource): void => handleDrop(item),
collect: (monitor): { isDragOver: boolean; canDrop: boolean } => ({
isDragOver: monitor.isOver({ shallow: true }),
canDrop: monitor.canDrop(),
}),
}),
[handleDrop],
);
const clearQuery = applicationStore.guardUnhandledError(() =>
flowResult(testState.queryState.updateLamba(stub_RawLambda())),
);
return (
<div className="panel mapping-test-editor__query-panel">
<div className="panel__header">
<div className="panel__header__title">
<div className="panel__header__title__label">query</div>
</div>
<div className="panel__header__actions">
{extraQueryEditorActions}
<button
className="panel__header__action"
tabIndex={-1}
disabled={isReadOnly}
onClick={clearQuery}
title={'Clear query'}
>
<TimesIcon />
</button>
</div>
</div>
{!isStubbed_RawLambda(queryState.query) && (
<div className="panel__content">
<div className="mapping-test-editor__query-panel__query">
<StudioTextInputEditor
inputValue={queryState.lambdaString}
isReadOnly={true}
language={EDITOR_LANGUAGE.PURE}
showMiniMap={false}
/>
</div>
</div>
)}
{isStubbed_RawLambda(queryState.query) && (
<div ref={dropRef} className="panel__content">
<BlankPanelPlaceholder
placeholderText="Choose a class mapping"
onClick={showClassMappingSelectorModal}
clickActionType="add"
tooltipText="Drop a class mapping, or click to choose one to start building the query"
dndProps={{
isDragOver: isDragOver,
canDrop: canDrop,
}}
/>
</div>
)}
{openClassMappingSelectorModal && (
<ClassMappingSelectorModal
mappingEditorState={testState.mappingEditorState}
hideClassMappingSelectorModal={hideClassMappingSelectorModal}
changeClassMapping={changeClassMapping}
/>
)}
</div>
);
},
)
Example #26
Source File: ColumnHeader.tsx From firetable with Apache License 2.0 | 4 votes |
export default function DraggableHeaderRenderer<R>({
column,
}: HeaderRendererProps<R> & {
onColumnsReorder: (sourceKey: string, targetKey: string) => void;
}) {
const classes = useStyles();
const {
tableState,
tableActions,
userClaims,
columnMenuRef,
} = useFiretableContext();
const [{ isDragging }, drag] = useDrag({
item: { key: column.key, type: "COLUMN_DRAG" },
collect: (monitor) => ({
isDragging: !!monitor.isDragging(),
}),
});
const [{ isOver }, drop] = useDrop({
accept: "COLUMN_DRAG",
drop({ key, type }: ColumnDragObject) {
if (type === "COLUMN_DRAG") {
// onColumnsReorder(key, props.column.key);
tableActions?.column.reorder(key, column.key);
}
},
collect: (monitor) => ({
isOver: !!monitor.isOver(),
canDrop: !!monitor.canDrop(),
}),
});
const headerRef = useCombinedRefs(drag, drop);
if (!columnMenuRef || !tableState || !tableActions) return null;
const { orderBy } = tableState;
const handleClick = (
event: React.MouseEvent<HTMLButtonElement, MouseEvent>
) =>
columnMenuRef?.current?.setSelectedColumnHeader({
column,
anchorEl: event.currentTarget,
});
const isSorted = orderBy?.[0]?.key === (column.key as string);
const isAsc = isSorted && orderBy?.[0]?.direction === "asc";
const handleSortClick = () => {
if (isAsc) {
const ordering: FiretableOrderBy = [
{ key: column.key as string, direction: "desc" },
];
tableActions.table.orderBy(ordering);
} else {
const ordering: FiretableOrderBy = [
{ key: column.key as string, direction: "asc" },
];
tableActions.table.orderBy(ordering);
}
};
return (
<Grid
ref={headerRef}
container
className={clsx(
classes.root,
isDragging && classes.isDragging,
isOver && !isDragging && classes.isOver
)}
alignItems="center"
wrap="nowrap"
>
<Tooltip
title={
<>
<Typography variant="subtitle2" component="p">
{column.key as string}
</Typography>
<Typography variant="body2" component="p">
<small>(Click to copy)</small>
</Typography>
</>
}
enterDelay={1000}
placement="bottom-start"
>
<Grid
item
onClick={() => {
navigator.clipboard.writeText(column.key as string);
}}
>
{getFieldProp("icon", (column as any).type)}
</Grid>
</Tooltip>
<Grid item xs className={classes.columnNameContainer}>
<Tooltip
title={<Typography variant="subtitle2">{column.name}</Typography>}
enterDelay={1000}
placement="bottom-start"
PopperProps={{
modifiers: {
flip: { enabled: false },
preventOverflow: {
enabled: false,
boundariesElement: "scrollParent",
},
hide: { enabled: false },
},
}}
TransitionComponent={Fade}
classes={{ tooltip: classes.columnNameTooltip }}
>
<Typography
variant="subtitle2"
noWrap
className={classes.columnName}
component="div"
color="inherit"
>
{column.name}
</Typography>
</Tooltip>
</Grid>
{(column as any).type !== FieldType.id && (
<Grid
item
className={clsx(
classes.sortIconContainer,
isSorted && classes.sortIconContainerSorted
)}
>
<IconButton
disableFocusRipple={true}
size="small"
onClick={handleSortClick}
color="inherit"
aria-label={`Sort by ${isAsc ? "descending" : "ascending"}`}
className={clsx(classes.sortIcon, isAsc && classes.sortIconAsc)}
>
<SortDescIcon />
</IconButton>
</Grid>
)}
{(userClaims?.roles?.includes("ADMIN") ||
(userClaims?.roles?.includes("OPS") &&
[FieldType.multiSelect, FieldType.singleSelect].includes(
(column as any).type
))) && (
<Grid item>
<IconButton
size="small"
className={classes.dropdownButton}
aria-label={`Show ${column.name} column dropdown`}
color="inherit"
onClick={handleClick}
>
<DropdownIcon />
</IconButton>
</Grid>
)}
</Grid>
);
// return (
// <div
// ref={useCombinedRefs(drag, drop)}
// style={{
// opacity: isDragging ? 0.5 : 1,
// backgroundColor: isOver ? '#ececec' : 'inherit',
// cursor: 'move'
// }}
// >
// {props.column.name}
// </div>
// );
}
Example #27
Source File: EnumerationEditor.tsx From legend-studio with Apache License 2.0 | 4 votes |
EnumEditor = observer(
(props: { _enum: Enum; deselectValue: () => void; isReadOnly: boolean }) => {
const { _enum, deselectValue, isReadOnly } = props;
// Tab
const [selectedTab, setSelectedTab] = useState<UML_EDITOR_TAB>(
UML_EDITOR_TAB.TAGGED_VALUES,
);
const tabs = [UML_EDITOR_TAB.TAGGED_VALUES, UML_EDITOR_TAB.STEREOTYPES];
const changeTab =
(tab: UML_EDITOR_TAB): (() => void) =>
(): void =>
setSelectedTab(tab);
// Tagged value and Stereotype
let addButtonTitle = '';
switch (selectedTab) {
case UML_EDITOR_TAB.TAGGED_VALUES:
addButtonTitle = 'Add tagged value';
break;
case UML_EDITOR_TAB.STEREOTYPES:
addButtonTitle = 'Add stereotype';
break;
default:
break;
}
const addValue = (): void => {
if (!isReadOnly) {
if (selectedTab === UML_EDITOR_TAB.TAGGED_VALUES) {
annotatedElement_addTaggedValue(
_enum,
stub_TaggedValue(stub_Tag(stub_Profile())),
);
} else if (selectedTab === UML_EDITOR_TAB.STEREOTYPES) {
annotatedElement_addStereotype(
_enum,
StereotypeExplicitReference.create(stub_Stereotype(stub_Profile())),
);
}
}
};
const _deleteStereotype =
(val: StereotypeReference): (() => void) =>
(): void =>
annotatedElement_deleteStereotype(_enum, val);
const _deleteTaggedValue =
(val: TaggedValue): (() => void) =>
(): void =>
annotatedElement_deleteTaggedValue(_enum, val);
// Drag and Drop
const handleDropTaggedValue = useCallback(
(item: UMLEditorElementDropTarget): void => {
if (!isReadOnly && item.data.packageableElement instanceof Profile) {
annotatedElement_addTaggedValue(
_enum,
stub_TaggedValue(stub_Tag(item.data.packageableElement)),
);
}
},
[_enum, isReadOnly],
);
const [{ isTaggedValueDragOver }, dropTaggedValueRef] = useDrop(
() => ({
accept: [CORE_DND_TYPE.PROJECT_EXPLORER_PROFILE],
drop: (item: ElementDragSource): void => handleDropTaggedValue(item),
collect: (monitor): { isTaggedValueDragOver: boolean } => ({
isTaggedValueDragOver: monitor.isOver({ shallow: true }),
}),
}),
[handleDropTaggedValue],
);
const handleDropStereotype = useCallback(
(item: UMLEditorElementDropTarget): void => {
if (!isReadOnly && item.data.packageableElement instanceof Profile) {
annotatedElement_addStereotype(
_enum,
StereotypeExplicitReference.create(
stub_Stereotype(item.data.packageableElement),
),
);
}
},
[_enum, isReadOnly],
);
const [{ isStereotypeDragOver }, dropStereotypeRef] = useDrop(
() => ({
accept: [CORE_DND_TYPE.PROJECT_EXPLORER_PROFILE],
drop: (item: ElementDragSource): void => handleDropStereotype(item),
collect: (monitor): { isStereotypeDragOver: boolean } => ({
isStereotypeDragOver: monitor.isOver({ shallow: true }),
}),
}),
[handleDropStereotype],
);
return (
<div className="uml-element-editor enum-editor">
<div data-testid={LEGEND_STUDIO_TEST_ID.PANEL} className="panel">
<div className="panel__header">
<div className="panel__header__title">
{isReadOnly && (
<div className="uml-element-editor__header__lock">
<LockIcon />
</div>
)}
<div className="panel__header__title__label">enum</div>
<div className="panel__header__title__content">{_enum.name}</div>
</div>
<div className="panel__header__actions">
<button
className="panel__header__action"
onClick={deselectValue}
tabIndex={-1}
title={'Close'}
>
<TimesIcon />
</button>
</div>
</div>
<div
data-testid={LEGEND_STUDIO_TEST_ID.UML_ELEMENT_EDITOR__TABS_HEADER}
className="panel__header uml-element-editor__tabs__header"
>
<div className="uml-element-editor__tabs">
{tabs.map((tab) => (
<div
key={tab}
onClick={changeTab(tab)}
className={clsx('uml-element-editor__tab', {
'uml-element-editor__tab--active': tab === selectedTab,
})}
>
{prettyCONSTName(tab)}
</div>
))}
</div>
<div className="panel__header__actions">
<button
className="panel__header__action"
disabled={isReadOnly}
onClick={addValue}
tabIndex={-1}
title={addButtonTitle}
>
<PlusIcon />
</button>
</div>
</div>
<div className="panel__content">
{selectedTab === UML_EDITOR_TAB.TAGGED_VALUES && (
<div
ref={dropTaggedValueRef}
className={clsx('panel__content__lists', {
'panel__content__lists--dnd-over':
isTaggedValueDragOver && !isReadOnly,
})}
>
{_enum.taggedValues.map((taggedValue) => (
<TaggedValueEditor
key={taggedValue._UUID}
taggedValue={taggedValue}
deleteValue={_deleteTaggedValue(taggedValue)}
isReadOnly={isReadOnly}
/>
))}
</div>
)}
{selectedTab === UML_EDITOR_TAB.STEREOTYPES && (
<div
ref={dropStereotypeRef}
className={clsx('panel__content__lists', {
'panel__content__lists--dnd-over':
isStereotypeDragOver && !isReadOnly,
})}
>
{_enum.stereotypes.map((stereotype) => (
<StereotypeSelector
key={stereotype.value._UUID}
stereotype={stereotype}
deleteStereotype={_deleteStereotype(stereotype)}
isReadOnly={isReadOnly}
/>
))}
</div>
)}
</div>
</div>
</div>
);
},
)
Example #28
Source File: DropTarget.tsx From gear-js with GNU General Public License v3.0 | 4 votes |
DropTarget = ({ type, setDroppedFile }: Props) => {
const alert = useAlert();
const [wrongFormat, setWrongFormat] = useState(false);
const inputRef = useRef<HTMLInputElement>(null);
if (wrongFormat) {
setTimeout(() => setWrongFormat(false), 3000);
}
const checkFileFormat = useCallback((files: any) => {
if (typeof files[0]?.name === 'string') {
const fileExt: string = files[0].name.split('.').pop().toLowerCase();
return fileExt !== 'wasm';
}
return true;
}, []);
const handleFilesUpload = useCallback(
(file: File) => {
setDroppedFile({ file, type });
},
[setDroppedFile, type]
);
const emulateInputClick = () => {
inputRef.current?.click();
};
const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
const {
target: { files },
} = event;
if (files?.length) {
const isCorrectFormat = checkFileFormat(files);
setWrongFormat(isCorrectFormat);
if (!isCorrectFormat) {
handleFilesUpload(files[0]);
// since type='file' input can't be controlled,
// reset it's value to trigger onChange again in case the same file selected twice
event.target.value = '';
} else {
alert.error('Wrong file format');
setWrongFormat(false);
}
}
};
const handleFileDrop = useCallback(
(item) => {
if (item) {
const { files } = item;
const isCorrectFormat = checkFileFormat(files);
setWrongFormat(isCorrectFormat);
if (!isCorrectFormat) {
handleFilesUpload(files[0]);
} else {
alert.error('Wrong file format');
setWrongFormat(false);
}
}
},
// eslint-disable-next-line react-hooks/exhaustive-deps
[checkFileFormat, handleFilesUpload]
);
const [{ canDrop, isOver }, drop] = useDrop(
() => ({
accept: [NativeTypes.FILE],
drop(item: { files: any[] }) {
if (handleFileDrop) {
handleFileDrop(item);
}
},
collect: (monitor: DropTargetMonitor) => ({
isOver: monitor.isOver(),
canDrop: monitor.canDrop(),
}),
}),
[handleFileDrop]
);
const isActive = canDrop && isOver;
const className = clsx(styles.drop, isActive && styles.active);
const isProgramUpload = type === UploadTypes.PROGRAM;
const buttonText = `Upload ${type}`;
return (
<div className={className} ref={drop}>
{isActive ? (
<div className={styles.file}>
<span className={styles.text}>Drop your .wasm files here to upload</span>
</div>
) : (
<div className={styles.noFile}>
<input className={styles.input} ref={inputRef} type="file" onChange={handleChange} />
<Button
text={buttonText}
icon={isProgramUpload ? upload : editor}
color={isProgramUpload ? 'primary' : 'secondary'}
onClick={emulateInputClick}
/>
<div className={styles.text}>{`Click “${buttonText}” to browse or drag and drop your .wasm files here`}</div>
</div>
)}
</div>
);
}
Example #29
Source File: NameItem.tsx From datart with Apache License 2.0 | 4 votes |
NameItem: React.FC<NameItemProps> = ({
index,
card,
zIndex,
moveCard,
moveEnd,
widgetType,
}) => {
const widget = useContext(WidgetContext);
const ItemRef = useRef<HTMLDivElement>(null);
const [{ handlerId }, drop] = useDrop({
accept: 'WidgetNameListDnd',
collect(monitor) {
return {
handlerId: monitor.getHandlerId(),
};
},
hover(item: DragItem, monitor: DropTargetMonitor) {
if (!ItemRef.current) {
return;
}
const dragIndex = item.index;
const hoverIndex = index;
const dragZIndex = item.zIndex;
const hoverZIndex = card.index;
const hoverSelected = card.selected;
// Don't replace items with themselves
if (dragIndex === hoverIndex) {
return;
}
// Determine rectangle on screen
const hoverBoundingRect = ItemRef.current?.getBoundingClientRect();
// Get vertical middle
const hoverMiddleY =
(hoverBoundingRect.bottom - hoverBoundingRect.top) / 2;
// Determine mouse position
const clientOffset = monitor.getClientOffset();
// Get pixels to the top
const hoverClientY = (clientOffset as XYCoord).y - hoverBoundingRect.top;
// Only perform the move when the mouse has crossed half of the items height
// When dragging downwards, only move when the cursor is below 50%
// When dragging upwards, only move when the cursor is above 50%
// Dragging downwards
if (dragIndex < hoverIndex && hoverClientY < hoverMiddleY) {
return;
}
// Dragging upwards
if (dragIndex > hoverIndex && hoverClientY > hoverMiddleY) {
return;
}
// Time to actually perform the action
moveCard(dragIndex, hoverIndex, dragZIndex, hoverZIndex);
// Note: we're mutating the monitor item here!
// Generally it's better to avoid mutations,
// but it's good here for the sake of performance
// to avoid expensive index searches.
item.index = hoverIndex;
item.zIndex = hoverZIndex;
item.selected = hoverSelected;
},
});
const [{ isDragging }, drag] = useDrag({
type: 'WidgetNameListDnd',
item: () => {
return { id: card.id, index, zIndex, selected: card.selected };
},
collect: (monitor: any) => ({
isDragging: monitor.isDragging(),
}),
end() {
moveEnd();
},
});
const opacity = isDragging ? 0.1 : 1;
// 使用 drag 和 drop 包装 ref
drag(drop(ItemRef));
const dispatch = useDispatch();
const selectWidget = useCallback(
(e: React.MouseEvent<HTMLDivElement>) => {
e.stopPropagation();
let newSelected = !card.selected;
if (card.selected) {
newSelected = card.selected;
}
dispatch(
editWidgetInfoActions.selectWidget({
multipleKey: e.shiftKey,
id: card.id,
selected: newSelected,
}),
);
},
[card, dispatch],
);
return (
<ItemWrap
selected={card.selected}
onMouseDown={selectWidget}
onClick={e => e.stopPropagation()}
>
<div
className={classNames('name-item', {
'selected-Item': card.selected,
})}
ref={ItemRef}
data-handler-id={handlerId}
style={{ opacity }}
>
<span className="name" title={card.name || 'untitled-widget'}>
{card.name || 'untitled-widget'}
</span>
<WidgetActionDropdown widget={widget} />
</div>
</ItemWrap>
);
}