react-dnd-html5-backend#getEmptyImage TypeScript Examples

The following examples show how to use react-dnd-html5-backend#getEmptyImage. 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: index.tsx    From hive with MIT License 6 votes vote down vote up
componentDidMount() {
        const { connectDragPreview } = this.props;

        if (connectDragPreview) {
            connectDragPreview(getEmptyImage(), {
                captureDraggingState: true,
            });
        }
    }
Example #2
Source File: QueryBuilderFunctionsExplorerPanel.tsx    From legend-studio with Apache License 2.0 5 votes vote down vote up
QueryBuilderFunctionsExplorerListEntry = observer(
  (props: {
    queryBuilderState: QueryBuilderState;
    element: ConcreteFunctionDefinition;
    rootPackageName: ROOT_PACKAGE_NAME;
  }) => {
    const { queryBuilderState, element, rootPackageName } = props;
    const node = generateFunctionsExplorerTreeNodeData(
      queryBuilderState,
      element,
      rootPackageName,
    );
    const functionSignature = generateFunctionSignature(element, true);
    const [, dragConnector, dragPreviewConnector] = useDrag(
      () => ({
        type: QUERY_BUILDER_FUNCTIONS_EXPLORER_TREE_DND_TYPE.FUNCTION,
        item: { node: node },
      }),
      [node],
    );
    // hide default HTML5 preview image
    useEffect(() => {
      dragPreviewConnector(getEmptyImage(), { captureDraggingState: true });
    }, [dragPreviewConnector]);

    return (
      <div
        className="query-builder__functions-explorer__function"
        ref={dragConnector}
      >
        <div className="query-builder__functions-explorer__function__content">
          <div className="query-builder__functions-explorer__function__icon">
            <div className="query-builder__functions-explorer__function-icon">
              <PURE_FunctionIcon />
            </div>
          </div>
          <div
            className="query-builder__functions-explorer__function__label"
            title={functionSignature}
          >
            {functionSignature}
          </div>
        </div>
        <div className="query-builder__functions-explorer__function__actions">
          <QueryBuilderFunctionInfoTooltip
            element={node.packageableElement as ConcreteFunctionDefinition}
          >
            <div className="query-builder__functions-explorer__function__action query-builder__functions-explorer__function__node__info">
              <InfoCircleIcon />
            </div>
          </QueryBuilderFunctionInfoTooltip>
        </div>
      </div>
    );
  },
)
Example #3
Source File: QueryBuilderParameterPanel.tsx    From legend-studio with Apache License 2.0 5 votes vote down vote up
VariableExpressionViewer = observer(
  (props: {
    queryBuilderState: QueryBuilderState;
    variableExpressionState: QueryParameterState;
  }) => {
    const { queryBuilderState, variableExpressionState } = props;
    const queryParameterState = queryBuilderState.queryParametersState;
    const variable = variableExpressionState.parameter;
    const name = variable.name;
    const variableType = variable.genericType?.value.rawType;
    const typeName = variableType?.name;
    const editVariable = (): void => {
      queryParameterState.setSelectedParameter(variableExpressionState);
    };
    const deleteVariable = (): void =>
      queryParameterState.removeParameter(variableExpressionState);
    const [, dragConnector, dragPreviewConnector] = useDrag(
      () => ({
        type: QUERY_BUILDER_PARAMETER_TREE_DND_TYPE.VARIABLE,
        item: { variable: variableExpressionState },
      }),
      [variableExpressionState],
    );
    // hide default HTML5 preview image
    useEffect(() => {
      dragPreviewConnector(getEmptyImage(), { captureDraggingState: true });
    }, [dragPreviewConnector]);
    return (
      <div className="query-builder__parameters__parameter" ref={dragConnector}>
        <QueryBuilderParameterDragLayer queryBuilderState={queryBuilderState} />
        <div className="query-builder__parameters__parameter__content">
          <div className="query-builder__parameters__parameter__icon">
            <div className="query-builder__parameters__parameter-icon">
              <DollarIcon />
            </div>
          </div>
          <div className="query-builder__parameters__parameter__label">
            {name}
            <div className="query-builder__parameters__parameter__type">
              <div className="query-builder__parameters__parameter__type__label">
                {typeName}
              </div>
            </div>
          </div>
        </div>
        <div className="query-builder__parameters__parameter__actions">
          <button
            className="query-builder__parameters__parameter__action"
            tabIndex={-1}
            onClick={editVariable}
            title="Edit Parameter"
          >
            <PencilIcon />
          </button>
          <button
            className="query-builder__parameters__parameter__action"
            onClick={deleteVariable}
            title="Remove"
          >
            <TimesIcon />
          </button>
        </div>
      </div>
    );
  },
)
Example #4
Source File: index.tsx    From uno-game with MIT License 5 votes vote down vote up
DraggableCard: React.FC<CardProps> = (props) => {
	const {
		card,
		index,
		style,
		className,
		onClick,
		selected,
		isDraggingAnyCard,
		onDragEnd,
		canBePartOfCurrentCombo,
		isMoreThanOneCardBeingDragged,
	} = props

	const draggableCardRef = useRef(null)

	const canCardBeUsed = canBePartOfCurrentCombo || card.canBeUsed

	const [{ isDragging }, drag, preview] = useDrag({
		item: {
			type: CARD_TYPE,
			id: card.id,
			index,
			src: card.src,
			name: card.name,
			cardType: card.type,
			selected,
			className,
		} as DraggedCardItem,
		collect: monitor => ({
			isDragging: monitor.isDragging(),
		}),
		canDrag: canCardBeUsed,
		end: onDragEnd,
	})

	drag(draggableCardRef)

	useDidMount(() => {
		preview(getEmptyImage(), { captureDraggingState: true })
	})

	return (
		<img
			ref={draggableCardRef}
			key={card.name}
			className={className}
			alt={card.name}
			src={card.src}
			style={{
				...style,
				opacity: (isDragging || (isDraggingAnyCard && isMoreThanOneCardBeingDragged && selected)) ? 0 : 1,
				filter: !canCardBeUsed ? "brightness(0.5)" : "saturate(1.5)",
				pointerEvents: canCardBeUsed ? "all" : "none",
				...(selected ? {
					border: `${Device.isMobile ? "3px" : "5px"} solid #EC0000`,
					borderRadius: Device.isMobile ? "8px" : "16px",
				} : {}),
			}}
			onClick={onClick}
		/>
	)
}
Example #5
Source File: QueryBuilderExplorerPanel.tsx    From legend-studio with Apache License 2.0 4 votes vote down vote up
QueryBuilderExplorerTreeNodeContainer = observer(
  (
    props: TreeNodeContainerProps<
      QueryBuilderExplorerTreeNodeData,
      {
        queryBuilderState: QueryBuilderState;
      }
    >,
  ) => {
    const { node, level, stepPaddingInRem, onNodeSelect, innerProps } = props;
    const { queryBuilderState } = innerProps;
    const [isSelectedFromContextMenu, setIsSelectedFromContextMenu] =
      useState(false);
    const applicationStore = useApplicationStore();
    const explorerState = queryBuilderState.explorerState;
    const [, dragConnector, dragPreviewConnector] = useDrag(
      () => ({
        type:
          node instanceof QueryBuilderExplorerTreePropertyNodeData
            ? node.type instanceof Enumeration
              ? QUERY_BUILDER_EXPLORER_TREE_DND_TYPE.ENUM_PROPERTY
              : node.type instanceof Class
              ? QUERY_BUILDER_EXPLORER_TREE_DND_TYPE.CLASS_PROPERTY
              : QUERY_BUILDER_EXPLORER_TREE_DND_TYPE.PRIMITIVE_PROPERTY
            : QUERY_BUILDER_EXPLORER_TREE_DND_TYPE.ROOT,
        item: (): { node?: QueryBuilderExplorerTreePropertyNodeData } =>
          node instanceof QueryBuilderExplorerTreePropertyNodeData
            ? { node }
            : {},
      }),
      [node],
    );
    const isExpandable = Boolean(node.childrenIds.length);
    const isDerivedProperty =
      node instanceof QueryBuilderExplorerTreePropertyNodeData &&
      node.property instanceof DerivedProperty;
    const isMultiple =
      (node instanceof QueryBuilderExplorerTreePropertyNodeData &&
        (node.property.multiplicity.upperBound === undefined ||
          node.property.multiplicity.upperBound > 1)) ||
      (node instanceof QueryBuilderExplorerTreeSubTypeNodeData &&
        (node.multiplicity.upperBound === undefined ||
          node.multiplicity.upperBound > 1));
    const allowPreview =
      node.mappingData.mapped &&
      node instanceof QueryBuilderExplorerTreePropertyNodeData &&
      node.type instanceof PrimitiveType &&
      !node.isPartOfDerivedPropertyBranch;
    const nodeExpandIcon = isExpandable ? (
      node.isOpen ? (
        <ChevronDownIcon />
      ) : (
        <ChevronRightIcon />
      )
    ) : (
      <div />
    );
    const selectNode = (): void => onNodeSelect?.(node);
    const openNode = (): void => {
      if (!node.isOpen) {
        onNodeSelect?.(node);
      }
    };
    // context menu
    const showContextMenu =
      node instanceof QueryBuilderExplorerTreeRootNodeData ||
      (node instanceof QueryBuilderExplorerTreePropertyNodeData &&
        !(node.type instanceof PrimitiveType));
    const onContextMenuOpen = (): void => setIsSelectedFromContextMenu(true);
    const onContextMenuClose = (): void => setIsSelectedFromContextMenu(false);
    const previewData = (): void => {
      if (node instanceof QueryBuilderExplorerTreePropertyNodeData) {
        flowResult(
          queryBuilderState.fetchStructureState.projectionState.previewData(
            node,
          ),
        ).catch(applicationStore.alertUnhandledError);
      }
    };
    // hide default HTML5 preview image
    useEffect(() => {
      dragPreviewConnector(getEmptyImage(), { captureDraggingState: true });
    }, [dragPreviewConnector]);

    if (
      !node.mappingData.mapped &&
      !explorerState.showUnmappedProperties &&
      queryBuilderState.querySetupState.isMappingCompatible
    ) {
      return null;
    }
    return (
      <ContextMenu
        content={
          <QueryBuilderExplorerContextMenu
            queryBuilderState={queryBuilderState}
            openNode={openNode}
            node={node}
          />
        }
        disabled={
          !showContextMenu ||
          // NOTE: this might make it hard to modularize
          queryBuilderState.fetchStructureState.projectionState.hasParserError
        }
        menuProps={{ elevation: 7 }}
        onOpen={onContextMenuOpen}
        onClose={onContextMenuClose}
      >
        <div
          className={clsx(
            'tree-view__node__container query-builder-explorer-tree__node__container',
            {
              'query-builder-explorer-tree__node__container--selected-from-context-menu':
                isSelectedFromContextMenu,
              'query-builder-explorer-tree__node__container--unmapped':
                !node.mappingData.mapped,
            },
          )}
          title={
            !node.mappingData.mapped ? 'Property is not mapped' : undefined
          }
          onClick={selectNode}
          ref={
            node.mappingData.mapped && !isExpandable ? dragConnector : undefined
          }
          style={{
            paddingLeft: `${(level - 1) * (stepPaddingInRem ?? 1) + 0.5}rem`,
            display: 'flex',
          }}
        >
          {node instanceof QueryBuilderExplorerTreeRootNodeData && (
            // NOTE: since the root of the tree is the class, not the property, we want to display it differently
            <>
              <div className="query-builder-explorer-tree__expand-icon">
                {nodeExpandIcon}
              </div>
              <div className="tree-view__node__label query-builder-explorer-tree__root-node__label">
                <div className="query-builder-explorer-tree__root-node__label__icon">
                  <PURE_ClassIcon />
                </div>
                <div className="query-builder-explorer-tree__root-node__label__text">
                  {node.label}
                </div>
              </div>
            </>
          )}
          {(node instanceof QueryBuilderExplorerTreePropertyNodeData ||
            node instanceof QueryBuilderExplorerTreeSubTypeNodeData) && (
            <>
              <div className="tree-view__node__icon query-builder-explorer-tree__node__icon">
                <div className="query-builder-explorer-tree__expand-icon">
                  {nodeExpandIcon}
                </div>
                <div className="query-builder-explorer-tree__type-icon">
                  {renderPropertyTypeIcon(node.type)}
                </div>
              </div>
              <div
                className={clsx(
                  'tree-view__node__label query-builder-explorer-tree__node__label query-builder-explorer-tree__node__label--with-action',
                  {
                    'query-builder-explorer-tree__node__label--with-preview':
                      allowPreview,
                  },
                )}
              >
                {explorerState.humanizePropertyName
                  ? node instanceof QueryBuilderExplorerTreeSubTypeNodeData
                    ? TYPE_CAST_TOKEN + prettyPropertyName(node.label)
                    : prettyPropertyName(node.label)
                  : node instanceof QueryBuilderExplorerTreeSubTypeNodeData
                  ? TYPE_CAST_TOKEN + node.label
                  : node.label}
                {isDerivedProperty && (
                  <div
                    className="query-builder-explorer-tree__node__label__derived-property"
                    title="Property is derived and may require user to specify parameter values"
                  >
                    (...)
                  </div>
                )}
                {isMultiple && (
                  <div
                    className="query-builder-explorer-tree__node__label__multiple"
                    title="Multiple values of this property can cause row explosion"
                  >
                    *
                  </div>
                )}
              </div>
              <div className="query-builder-explorer-tree__node__actions">
                {allowPreview && (
                  <button
                    className="query-builder-explorer-tree__node__action"
                    disabled={
                      explorerState.previewDataState.isGeneratingPreviewData
                    }
                    tabIndex={-1}
                    title="Preview Data"
                    onClick={previewData}
                  >
                    <EyeIcon />
                  </button>
                )}
                {node instanceof QueryBuilderExplorerTreePropertyNodeData && (
                  <QueryBuilderPropertyInfoTooltip
                    property={node.property}
                    path={node.id}
                    isMapped={node.mappingData.mapped}
                  >
                    <div className="query-builder-explorer-tree__node__action query-builder-explorer-tree__node__info">
                      <InfoCircleIcon />
                    </div>
                  </QueryBuilderPropertyInfoTooltip>
                )}
                {node instanceof QueryBuilderExplorerTreeSubTypeNodeData && (
                  <QueryBuilderSubclassInfoTooltip
                    subclass={node.subclass}
                    path={node.id}
                    isMapped={node.mappingData.mapped}
                    multiplicity={node.multiplicity}
                  >
                    <div className="query-builder-explorer-tree__node__action query-builder-explorer-tree__node__info">
                      <InfoCircleIcon />
                    </div>
                  </QueryBuilderSubclassInfoTooltip>
                )}
              </div>
            </>
          )}
        </div>
      </ContextMenu>
    );
  },
)
Example #6
Source File: QueryBuilderFilterPanel.tsx    From legend-studio with Apache License 2.0 4 votes vote down vote up
QueryBuilderFilterTreeNodeContainer = observer(
  (
    props: TreeNodeContainerProps<
      QueryBuilderFilterTreeNodeData,
      {
        queryBuilderState: QueryBuilderState;
      }
    >,
  ) => {
    const { node, level, stepPaddingInRem, onNodeSelect, innerProps } = props;
    const { queryBuilderState } = innerProps;
    const ref = useRef<HTMLDivElement>(null);
    const [isSelectedFromContextMenu, setIsSelectedFromContextMenu] =
      useState(false);
    const applicationStore = useApplicationStore();
    const filterState = queryBuilderState.filterState;
    const isExpandable = node instanceof QueryBuilderFilterTreeGroupNodeData;
    const selectNode = (): void => onNodeSelect?.(node);
    const toggleExpandNode = (): void => node.setIsOpen(!node.isOpen);
    const removeNode = (): void => filterState.removeNodeAndPruneBranch(node);

    // Drag and Drop
    const handleDrop = useCallback(
      (item: QueryBuilderFilterDropTarget, type: string): void => {
        if (
          Object.values<string>(QUERY_BUILDER_FILTER_DND_TYPE).includes(type)
        ) {
          // const dropNode = (item as QueryBuilderFilterConditionDragSource).node;
          // TODO: re-arrange
        } else {
          const dropNode = (item as QueryBuilderExplorerTreeDragSource).node;
          let filterConditionState: FilterConditionState;
          try {
            filterConditionState = new FilterConditionState(
              filterState,
              buildPropertyExpressionFromExplorerTreeNodeData(
                filterState.queryBuilderState.explorerState.nonNullableTreeData,
                dropNode,
                filterState.queryBuilderState.graphManagerState.graph,
              ),
            );
          } catch (error) {
            assertErrorThrown(error);
            applicationStore.notifyWarning(error.message);
            return;
          }
          if (node instanceof QueryBuilderFilterTreeGroupNodeData) {
            filterState.addNodeFromNode(
              new QueryBuilderFilterTreeConditionNodeData(
                undefined,
                filterConditionState,
              ),
              node,
            );
          } else if (node instanceof QueryBuilderFilterTreeConditionNodeData) {
            filterState.newGroupWithConditionFromNode(
              new QueryBuilderFilterTreeConditionNodeData(
                undefined,
                filterConditionState,
              ),
              node,
            );
          } else if (
            node instanceof QueryBuilderFilterTreeBlankConditionNodeData
          ) {
            filterState.replaceBlankNodeWithNode(
              new QueryBuilderFilterTreeConditionNodeData(
                undefined,
                filterConditionState,
              ),
              node,
            );
          }
        }
      },
      [applicationStore, filterState, node],
    );
    const [{ isPropertyDragOver }, dropConnector] = useDrop(
      () => ({
        accept: [
          ...Object.values(QUERY_BUILDER_FILTER_DND_TYPE),
          QUERY_BUILDER_EXPLORER_TREE_DND_TYPE.ENUM_PROPERTY,
          QUERY_BUILDER_EXPLORER_TREE_DND_TYPE.PRIMITIVE_PROPERTY,
        ],
        drop: (
          item: QueryBuilderFilterConditionDragSource,
          monitor: DropTargetMonitor,
        ): void => {
          if (!monitor.didDrop()) {
            handleDrop(item, monitor.getItemType() as string);
          } // prevent drop event propagation to accomondate for nested DnD
        },
        // canDrop: (item: QueryBuilderFilterConditionDragSource, monitor: DropTargetMonitor): boolean => {
        //   // prevent drop inside of children
        //   // prevent dropping inside my direct ancestor
        //   return true;
        // },
        collect: (monitor): { isPropertyDragOver: boolean } => ({
          isPropertyDragOver: monitor.isOver({ shallow: true }),
        }),
      }),
      [handleDrop],
    );
    const [, dragConnector, dragPreviewConnector] = useDrag(
      () => ({
        type:
          node instanceof QueryBuilderFilterTreeGroupNodeData
            ? QUERY_BUILDER_FILTER_DND_TYPE.GROUP_CONDITION
            : node instanceof QueryBuilderFilterTreeConditionNodeData
            ? QUERY_BUILDER_FILTER_DND_TYPE.CONDITION
            : QUERY_BUILDER_FILTER_DND_TYPE.BLANK_CONDITION,
        item: (): QueryBuilderFilterConditionDragSource => ({ node }),
        end: (): void => filterState.setRearrangingConditions(false),
      }),
      [node, filterState],
    );
    dragConnector(dropConnector(ref));
    // hide default HTML5 preview image
    useEffect(() => {
      dragPreviewConnector(getEmptyImage(), { captureDraggingState: true });
    }, [dragPreviewConnector]);
    // context menu
    const onContextMenuOpen = (): void => setIsSelectedFromContextMenu(true);
    const onContextMenuClose = (): void => setIsSelectedFromContextMenu(false);

    return (
      <ContextMenu
        content={
          <QueryBuilderFilterConditionContextMenu
            queryBuilderState={queryBuilderState}
            node={node}
          />
        }
        menuProps={{ elevation: 7 }}
        onOpen={onContextMenuOpen}
        onClose={onContextMenuClose}
      >
        <div
          ref={ref}
          className={clsx(
            'tree-view__node__container query-builder-filter-tree__node__container',
            {
              'query-builder-filter-tree__node__container--no-hover':
                filterState.isRearrangingConditions,
              'query-builder-filter-tree__node__container--selected':
                node === filterState.selectedNode,
              'query-builder-filter-tree__node__container--selected-from-context-menu':
                isSelectedFromContextMenu,
            },
          )}
        >
          <div
            className="query-builder-filter-tree__node__content"
            style={{
              paddingLeft: `${(level - 1) * (stepPaddingInRem ?? 2) + 1.5}rem`,
              display: 'flex',
            }}
            onClick={selectNode}
          >
            {isExpandable && (
              <div
                className="query-builder-filter-tree__expand-icon"
                onClick={toggleExpandNode}
              >
                {node.isOpen ? <ChevronDownIcon /> : <ChevronRightIcon />}
              </div>
            )}
            <div
              className={clsx(
                'tree-view__node__label query-builder-filter-tree__node__label',
                {
                  'query-builder-filter-tree__node__label--expandable':
                    isExpandable,
                },
              )}
            >
              {node instanceof QueryBuilderFilterTreeGroupNodeData && (
                <QueryBuilderFilterGroupConditionEditor
                  node={node}
                  isPropertyDragOver={isPropertyDragOver}
                />
              )}
              {node instanceof QueryBuilderFilterTreeConditionNodeData && (
                <QueryBuilderFilterConditionEditor
                  node={node}
                  isPropertyDragOver={isPropertyDragOver}
                />
              )}
              {node instanceof QueryBuilderFilterTreeBlankConditionNodeData && (
                <QueryBuilderFilterBlankConditionEditor
                  node={node}
                  isPropertyDragOver={isPropertyDragOver}
                />
              )}
            </div>
          </div>
          <div className="query-builder-filter-tree__node__actions">
            <button
              className="query-builder-filter-tree__node__action"
              tabIndex={-1}
              title="Remove"
              onClick={removeNode}
            >
              <TimesIcon />
            </button>
          </div>
        </div>
      </ContextMenu>
    );
  },
)
Example #7
Source File: QueryBuilderFunctionsExplorerPanel.tsx    From legend-studio with Apache License 2.0 4 votes vote down vote up
QueryBuilderFunctionsExplorerTreeNodeContainer = observer(
  (
    props: TreeNodeContainerProps<
      QueryBuilderFunctionsExplorerTreeNodeData,
      {
        queryBuilderState: QueryBuilderState;
      }
    >,
  ) => {
    const { node, level, stepPaddingInRem, onNodeSelect } = props;
    const isPackage = node.packageableElement instanceof Package;
    const name =
      node.packageableElement instanceof ConcreteFunctionDefinition
        ? generateFunctionSignature(node.packageableElement, false)
        : node.packageableElement.name;
    const isExpandable = Boolean(node.childrenIds.length);
    const nodeExpandIcon = isExpandable ? (
      node.isOpen ? (
        <ChevronDownIcon />
      ) : (
        <ChevronRightIcon />
      )
    ) : (
      <div />
    );
    const iconPackageColor = isDependencyTreeNode(node)
      ? 'color--dependency'
      : '';
    const nodeTypeIcon = isPackage ? (
      node.isOpen ? (
        <FolderOpenIcon className={iconPackageColor} />
      ) : (
        <FolderIcon className={iconPackageColor} />
      )
    ) : (
      <PURE_FunctionIcon />
    );
    const selectNode = (): void => {
      onNodeSelect?.(node);
    };
    const [, dragConnector, dragPreviewConnector] = useDrag(
      () => ({
        type:
          node.packageableElement instanceof ConcreteFunctionDefinition
            ? QUERY_BUILDER_FUNCTIONS_EXPLORER_TREE_DND_TYPE.FUNCTION
            : QUERY_BUILDER_FUNCTIONS_EXPLORER_TREE_DND_TYPE.PACKAGE,
        item: (): { node?: QueryBuilderFunctionsExplorerTreeNodeData } =>
          node.packageableElement instanceof ConcreteFunctionDefinition
            ? { node }
            : {},
      }),
      [node],
    );
    // hide default HTML5 preview image
    useEffect(() => {
      dragPreviewConnector(getEmptyImage(), { captureDraggingState: true });
    }, [dragPreviewConnector]);

    return (
      <div>
        <div
          className="tree-view__node__container query-builder__functions-explorer__tree__node__container"
          onClick={selectNode}
          ref={!isExpandable ? dragConnector : undefined}
          style={{
            paddingLeft: `${(level - 1) * (stepPaddingInRem ?? 1) + 0.5}rem`,
            display: 'flex',
          }}
        >
          {
            <>
              <div className="tree-view__node__icon query-builder__functions-explorer__tree__node__icon">
                <div className="query-builder__functions-explorer__tree__expand-icon">
                  {nodeExpandIcon}
                </div>
                <div
                  className={
                    'query-builder__functions-explorer__tree__type-icon'
                  }
                >
                  {nodeTypeIcon}
                </div>
              </div>
              <div
                className="tree-view__node__label query-builder__functions-explorer__tree__node__label--with-action"
                title={name}
              >
                {name}
              </div>
              <div className="query-builder__functions-explorer__tree__node__actions">
                {node.packageableElement instanceof
                  ConcreteFunctionDefinition && (
                  <QueryBuilderFunctionInfoTooltip
                    element={node.packageableElement}
                  >
                    <div className="query-builder__functions-explorer__tree__node__action query-builder__functions-explorer__tree__node__info">
                      <InfoCircleIcon />
                    </div>
                  </QueryBuilderFunctionInfoTooltip>
                )}
              </div>
            </>
          }
        </div>
      </div>
    );
  },
)
Example #8
Source File: QueryBuilderPostFilterPanel.tsx    From legend-studio with Apache License 2.0 4 votes vote down vote up
QueryBuilderPostFilterTreeNodeContainer = observer(
  (
    props: TreeNodeContainerProps<
      QueryBuilderPostFilterTreeNodeData,
      {
        queryBuilderState: QueryBuilderState;
      }
    >,
  ) => {
    const { node, level, stepPaddingInRem, onNodeSelect, innerProps } = props;
    const { queryBuilderState } = innerProps;
    const ref = useRef<HTMLDivElement>(null);
    const [isSelectedFromContextMenu, setIsSelectedFromContextMenu] =
      useState(false);
    const applicationStore = useApplicationStore();
    const postFilterState = queryBuilderState.postFilterState;
    const isExpandable =
      node instanceof QueryBuilderPostFilterTreeGroupNodeData;
    const selectNode = (): void => onNodeSelect?.(node);
    const toggleExpandNode = (): void => node.setIsOpen(!node.isOpen);
    const removeNode = (): void =>
      postFilterState.removeNodeAndPruneBranch(node);
    const handleDrop = useCallback(
      (item: QueryBuilderPostFilterDropTarget, type: string): void => {
        if (type === QUERY_BUILDER_PROJECTION_DND_TYPE.PROJECTION_COLUMN) {
          const columnState = (item as QueryBuilderProjectionColumnDragSource)
            .columnState;
          let conditionState: PostFilterConditionState;
          try {
            conditionState = new PostFilterConditionState(
              postFilterState,
              columnState,
              undefined,
              undefined,
            );
            conditionState.setValue(
              conditionState.operator.getDefaultFilterConditionValue(
                conditionState,
              ),
            );
          } catch (error) {
            assertErrorThrown(error);
            applicationStore.notifyWarning(error.message);
            return;
          }

          if (node instanceof QueryBuilderPostFilterTreeGroupNodeData) {
            postFilterState.addNodeFromNode(
              new QueryBuilderPostFilterTreeConditionNodeData(
                undefined,
                conditionState,
              ),
              node,
            );
          } else if (
            node instanceof QueryBuilderPostFilterTreeConditionNodeData
          ) {
            postFilterState.newGroupWithConditionFromNode(
              new QueryBuilderPostFilterTreeConditionNodeData(
                undefined,
                conditionState,
              ),
              node,
            );
          } else if (
            node instanceof QueryBuilderPostFilterTreeBlankConditionNodeData
          ) {
            postFilterState.replaceBlankNodeWithNode(
              new QueryBuilderPostFilterTreeConditionNodeData(
                undefined,
                conditionState,
              ),
              node,
            );
          }
        }
      },
      [applicationStore, postFilterState, node],
    );
    const [{ isPropertyDragOver }, dropConnector] = useDrop(
      () => ({
        accept: [
          ...Object.values(QUERY_BUILDER_POST_FILTER_DND_TYPE),
          QUERY_BUILDER_PROJECTION_DND_TYPE.PROJECTION_COLUMN,
        ],
        drop: (
          item: QueryBuilderPostFilterConditionDragSource,
          monitor: DropTargetMonitor,
        ): void => {
          if (!monitor.didDrop()) {
            handleDrop(item, monitor.getItemType() as string);
          } // prevent drop event propagation to accomondate for nested DnD
        },
        collect: (monitor): { isPropertyDragOver: boolean } => ({
          isPropertyDragOver: monitor.isOver({ shallow: true }),
        }),
      }),
      [handleDrop],
    );

    const [, dragConnector, dragPreviewConnector] = useDrag(
      () => ({
        type:
          node instanceof QueryBuilderPostFilterTreeGroupNodeData
            ? QUERY_BUILDER_POST_FILTER_DND_TYPE.GROUP_CONDITION
            : node instanceof QueryBuilderPostFilterTreeConditionNodeData
            ? QUERY_BUILDER_POST_FILTER_DND_TYPE.CONDITION
            : QUERY_BUILDER_POST_FILTER_DND_TYPE.BLANK_CONDITION,
        item: (): QueryBuilderPostFilterConditionDragSource => ({ node }),
        end: (): void => postFilterState.setRearrangingConditions(false),
      }),
      [node, postFilterState],
    );
    dragConnector(dropConnector(ref));
    // hide default HTML5 preview image
    useEffect(() => {
      dragPreviewConnector(getEmptyImage(), { captureDraggingState: true });
    }, [dragPreviewConnector]);
    // context menu
    const onContextMenuOpen = (): void => setIsSelectedFromContextMenu(true);
    const onContextMenuClose = (): void => setIsSelectedFromContextMenu(false);

    return (
      <ContextMenu
        content={
          <QueryBuilderPostFilterConditionContextMenu
            queryBuilderState={queryBuilderState}
            node={node}
          />
        }
        menuProps={{ elevation: 7 }}
        onOpen={onContextMenuOpen}
        onClose={onContextMenuClose}
      >
        <div
          ref={ref}
          className={clsx(
            'tree-view__node__container query-builder-post-filter-tree__node__container',
            {
              'query-builder-post-filter-tree__node__container--no-hover':
                postFilterState.isRearrangingConditions,
              'query-builder-post-filter-tree__node__container--selected':
                node === postFilterState.selectedNode,
              'query-builder-post-filter-tree__node__container--selected-from-context-menu':
                isSelectedFromContextMenu,
            },
          )}
        >
          <div
            className="query-builder-post-filter-tree__node__content"
            style={{
              paddingLeft: `${(level - 1) * (stepPaddingInRem ?? 2) + 1.5}rem`,
              display: 'flex',
            }}
            onClick={selectNode}
          >
            {isExpandable && (
              <div
                className="query-builder-post-filter-tree__expand-icon"
                onClick={toggleExpandNode}
              >
                {node.isOpen ? <ChevronDownIcon /> : <ChevronRightIcon />}
              </div>
            )}
            <div
              className={clsx(
                'tree-view__node__label query-builder-post-filter-tree__node__label',
                {
                  'query-builder-post-filter-tree__node__label--expandable':
                    isExpandable,
                },
              )}
            >
              {node instanceof QueryBuilderPostFilterTreeGroupNodeData && (
                <QueryBuilderPostFilterGroupConditionEditor
                  node={node}
                  isPropertyDragOver={isPropertyDragOver}
                />
              )}
              {node instanceof QueryBuilderPostFilterTreeConditionNodeData && (
                <QueryBuilderPostFilterConditionEditor
                  node={node}
                  isPropertyDragOver={isPropertyDragOver}
                />
              )}
              {node instanceof
                QueryBuilderPostFilterTreeBlankConditionNodeData && (
                <QueryBuilderPostFilterBlankConditionEditor
                  node={node}
                  isPropertyDragOver={isPropertyDragOver}
                />
              )}
            </div>
          </div>
          <div className="query-builder-post-filter-tree__node__actions">
            <button
              className="query-builder-post-filter-tree__node__action"
              tabIndex={-1}
              title="Remove"
              onClick={removeNode}
            >
              <TimesIcon />
            </button>
          </div>
        </div>
      </ContextMenu>
    );
  },
)
Example #9
Source File: QueryBuilderProjectionPanel.tsx    From legend-studio with Apache License 2.0 4 votes vote down vote up
QueryBuilderProjectionColumnEditor = observer(
  (props: {
    projectionColumnState: QueryBuilderProjectionColumnState;
    isRearrangingColumns: boolean;
  }) => {
    const ref = useRef<HTMLDivElement>(null);

    const [isSelectedFromContextMenu, setIsSelectedFromContextMenu] =
      useState(false);
    const onContextMenuOpen = (): void => setIsSelectedFromContextMenu(true);
    const onContextMenuClose = (): void => setIsSelectedFromContextMenu(false);

    const { projectionColumnState, isRearrangingColumns } = props;
    const queryBuilderState =
      projectionColumnState.projectionState.queryBuilderState;
    const projectionState =
      queryBuilderState.fetchStructureState.projectionState;
    const removeColumn = (): void =>
      projectionState.removeColumn(projectionColumnState);

    // name
    const changeColumnName: React.ChangeEventHandler<HTMLInputElement> = (
      event,
    ) => projectionColumnState.setColumnName(event.target.value);
    const isDuplicatedColumnName =
      projectionColumnState.projectionState.columns.filter(
        (column) => column.columnName === projectionColumnState.columnName,
      ).length > 1;

    // aggregation
    const aggregateColumnState = projectionState.aggregationState.columns.find(
      (column) => column.projectionColumnState === projectionColumnState,
    );
    const aggreateOperators = projectionState.aggregationState.operators.filter(
      (op) => op.isCompatibleWithColumn(projectionColumnState),
    );
    const changeOperator =
      (val: QueryBuilderAggregateOperator | undefined) => (): void =>
        projectionState.aggregationState.changeColumnAggregateOperator(
          val,
          projectionColumnState,
        );

    // Drag and Drop
    const handleHover = useCallback(
      (
        item: QueryBuilderProjectionColumnDragSource,
        monitor: DropTargetMonitor,
      ): void => {
        const dragIndex = projectionState.columns.findIndex(
          (e) => e === item.columnState,
        );
        const hoverIndex = projectionState.columns.findIndex(
          (e) => e === projectionColumnState,
        );
        if (dragIndex === -1 || hoverIndex === -1 || dragIndex === hoverIndex) {
          return;
        }
        // move the item being hovered on when the dragged item position is beyond the its middle point
        const hoverBoundingReact = ref.current?.getBoundingClientRect();
        const distanceThreshold =
          ((hoverBoundingReact?.bottom ?? 0) - (hoverBoundingReact?.top ?? 0)) /
          2;
        const dragDistance =
          (monitor.getClientOffset() as XYCoord).y -
          (hoverBoundingReact?.top ?? 0);
        if (dragIndex < hoverIndex && dragDistance < distanceThreshold) {
          return;
        }
        if (dragIndex > hoverIndex && dragDistance > distanceThreshold) {
          return;
        }
        projectionState.moveColumn(dragIndex, hoverIndex);
      },
      [projectionColumnState, projectionState],
    );
    const [, dropConnector] = useDrop(
      () => ({
        accept: [QUERY_BUILDER_PROJECTION_DND_TYPE.PROJECTION_COLUMN],
        hover: (
          item: QueryBuilderProjectionColumnDragSource,
          monitor: DropTargetMonitor,
        ): void => handleHover(item, monitor),
      }),
      [handleHover],
    );
    const [, dragConnector, dragPreviewConnector] = useDrag(
      () => ({
        type: QUERY_BUILDER_PROJECTION_DND_TYPE.PROJECTION_COLUMN,
        item: (): QueryBuilderProjectionColumnDragSource => {
          projectionColumnState.setIsBeingDragged(true);
          return { columnState: projectionColumnState };
        },
        end: (item: QueryBuilderProjectionColumnDragSource | undefined): void =>
          item?.columnState.setIsBeingDragged(false),
      }),
      [projectionColumnState],
    );
    dragConnector(dropConnector(ref));

    // hide default HTML5 preview image
    useEffect(() => {
      dragPreviewConnector(getEmptyImage(), { captureDraggingState: true });
    }, [dragPreviewConnector]);

    return (
      <div
        ref={ref}
        className={clsx('query-builder__projection__column', {
          'query-builder__projection__column--dragged':
            projectionColumnState.isBeingDragged,
          'query-builder__projection__column--no-hover': isRearrangingColumns,
        })}
      >
        {projectionColumnState.isBeingDragged && (
          <div className="query-builder__projection__column__dnd__placeholder__container">
            <div className="query-builder__dnd__placeholder query-builder__projection__column__dnd__placeholder" />
          </div>
        )}
        {!projectionColumnState.isBeingDragged && (
          <ContextMenu
            content={
              <QueryBuilderProjectionColumnContextMenu
                projectionColumnState={projectionColumnState}
              />
            }
            disabled={
              !(
                projectionColumnState instanceof
                QueryBuilderSimpleProjectionColumnState
              )
            }
            className={clsx('query-builder__projection__column__context-menu', {
              'query-builder__projection__column--selected-from-context-menu':
                isSelectedFromContextMenu,
            })}
            menuProps={{ elevation: 7 }}
            onOpen={onContextMenuOpen}
            onClose={onContextMenuClose}
          >
            <div className="query-builder__projection__column__dnd__indicator">
              <div className="query-builder__projection__column__dnd__indicator__handler">
                <VerticalDragHandleIcon />
              </div>
            </div>
            <div className="query-builder__projection__column__name">
              <InputWithInlineValidation
                className="query-builder__projection__column__name__input input-group__input"
                spellCheck={false}
                value={projectionColumnState.columnName}
                onChange={changeColumnName}
                validationErrorMessage={
                  isDuplicatedColumnName ? 'Duplicated column' : undefined
                }
              />
            </div>
            <div className="query-builder__projection__column__value">
              {projectionColumnState instanceof
                QueryBuilderSimpleProjectionColumnState && (
                <QueryBuilderSimpleProjectionColumnEditor
                  projectionColumnState={projectionColumnState}
                />
              )}
              {projectionColumnState instanceof
                QueryBuilderDerivationProjectionColumnState && (
                <QueryBuilderDerivationProjectionColumnEditor
                  projectionColumnState={projectionColumnState}
                />
              )}
            </div>
            <div className="query-builder__projection__column__aggregate">
              <div className="query-builder__projection__column__aggregate__operator">
                {aggregateColumnState && (
                  <div className="query-builder__projection__column__aggregate__operator__label">
                    {aggregateColumnState.operator.getLabel(
                      projectionColumnState,
                    )}
                  </div>
                )}

                <DropdownMenu
                  className="query-builder__projection__column__aggregate__operator__dropdown"
                  disabled={!aggreateOperators.length}
                  content={
                    <MenuContent>
                      {aggregateColumnState && (
                        <MenuContentItem
                          className="query-builder__projection__column__aggregate__operator__dropdown__option"
                          onClick={changeOperator(undefined)}
                        >
                          (none)
                        </MenuContentItem>
                      )}
                      {aggreateOperators.map((op) => (
                        <MenuContentItem
                          key={op.uuid}
                          className="query-builder__projection__column__aggregate__operator__dropdown__option"
                          onClick={changeOperator(op)}
                        >
                          {op.getLabel(projectionColumnState)}
                        </MenuContentItem>
                      ))}
                    </MenuContent>
                  }
                  menuProps={{
                    anchorOrigin: { vertical: 'bottom', horizontal: 'left' },
                    transformOrigin: { vertical: 'top', horizontal: 'left' },
                    elevation: 7,
                  }}
                >
                  <button
                    className={clsx(
                      'query-builder__projection__column__aggregate__operator__badge',
                      {
                        'query-builder__projection__column__aggregate__operator__badge--activated':
                          Boolean(aggregateColumnState),
                      },
                    )}
                    tabIndex={-1}
                    title="Choose Aggregate Operator..."
                  >
                    <SigmaIcon />
                  </button>
                  <button
                    className="query-builder__projection__column__aggregate__operator__dropdown__trigger"
                    tabIndex={-1}
                    title="Choose Aggregate Operator..."
                  >
                    <CaretDownIcon />
                  </button>
                </DropdownMenu>
              </div>
            </div>
            <div className="query-builder__projection__column__actions">
              <button
                className="query-builder__projection__column__action"
                tabIndex={-1}
                onClick={removeColumn}
                title="Remove"
              >
                <TimesIcon />
              </button>
            </div>
          </ContextMenu>
        )}
      </div>
    );
  },
)
Example #10
Source File: GenerationSpecificationEditor.tsx    From legend-studio with Apache License 2.0 4 votes vote down vote up
ModelGenerationItem = observer(
  (props: {
    specState: GenerationSpecificationEditorState;
    nodeState: GenerationTreeNodeState;
    options: PackageableElementOption<PackageableElement>[];
    isRearrangingNodes: boolean;
  }) => {
    const ref = useRef<HTMLDivElement>(null);
    const { nodeState, specState, options, isRearrangingNodes } = props;
    const generationTreeNode = nodeState.node;
    const editorStore = useEditorStore();
    const modelGenerationRef = generationTreeNode.generationElement;
    const modelGeneration = modelGenerationRef.value;
    const value = { label: modelGeneration.name, value: modelGeneration };
    const onChange = (
      val: PackageableElementOption<FileGenerationSpecification> | null,
    ): void => {
      if (val !== null) {
        packageableElementReference_setValue(modelGenerationRef, val.value);
      }
    };
    const deleteNode = (): void =>
      specState.deleteGenerationTreeNode(generationTreeNode);
    const visitModelGeneration = (): void =>
      editorStore.openElement(modelGeneration);
    // generation id
    const isUnique =
      specState.spec.generationNodes.filter(
        (n) => n.id === generationTreeNode.id,
      ).length < 2;
    const isDefault =
      generationTreeNode.id ===
        generationTreeNode.generationElement.value.path && isUnique;
    const changeNodeId: React.ChangeEventHandler<HTMLInputElement> = (event) =>
      generationSpecification_setId(generationTreeNode, event.target.value);
    // Drag and Drop
    const handleHover = useCallback(
      (
        item: GenerationSpecNodeDropTarget,
        monitor: DropTargetMonitor,
      ): void => {
        const dragIndex = specState.generationTreeNodeStates.findIndex(
          (e) => e === item.nodeState,
        );
        const hoverIndex = specState.generationTreeNodeStates.findIndex(
          (e) => e === nodeState,
        );
        if (dragIndex === -1 || hoverIndex === -1 || dragIndex === hoverIndex) {
          return;
        }
        // move the item being hovered on when the dragged item position is beyond the its middle point
        const hoverBoundingReact = ref.current?.getBoundingClientRect();
        const distanceThreshold =
          ((hoverBoundingReact?.bottom ?? 0) - (hoverBoundingReact?.top ?? 0)) /
          2;
        const dragDistance =
          (monitor.getClientOffset() as XYCoord).y -
          (hoverBoundingReact?.top ?? 0);
        if (dragIndex < hoverIndex && dragDistance < distanceThreshold) {
          return;
        }
        if (dragIndex > hoverIndex && dragDistance > distanceThreshold) {
          return;
        }
        specState.moveGenerationNode(dragIndex, hoverIndex);
      },
      [nodeState, specState],
    );
    const [, dropConnector] = useDrop(
      () => ({
        accept: [CORE_DND_TYPE.GENERATION_SPEC_NODE],
        hover: (
          item: GenerationSpecNodeDragSource,
          monitor: DropTargetMonitor,
        ): void => handleHover(item, monitor),
      }),
      [handleHover],
    );
    const [, dragConnector, dragPreviewConnector] = useDrag(
      () => ({
        type: CORE_DND_TYPE.GENERATION_SPEC_NODE,
        item: (): GenerationSpecNodeDragSource => {
          nodeState.setIsBeingDragged(true);
          return { nodeState };
        },
        end: (item: GenerationSpecNodeDragSource | undefined): void =>
          item?.nodeState.setIsBeingDragged(false),
      }),
      [nodeState],
    );
    dragConnector(dropConnector(ref));
    // hide default HTML5 preview image
    useEffect(() => {
      dragPreviewConnector(getEmptyImage(), { captureDraggingState: true });
    }, [dragPreviewConnector]);
    return (
      <div
        ref={ref}
        className={clsx('generation-spec-model-generation-editor__item', {
          'generation-spec-model-generation-editor__item--dragged':
            nodeState.isBeingDragged,
          'generation-spec-model-generation-editor__item---no-hover':
            isRearrangingNodes,
        })}
      >
        {nodeState.isBeingDragged && (
          <div className="generation-spec-editor__dnd__placeholder" />
        )}
        {!nodeState.isBeingDragged && (
          <>
            <div className="btn--sm generation-spec-model-generation-editor__item__label">
              {getElementIcon(editorStore, modelGeneration)}
            </div>
            <input
              className={clsx(
                'generation-spec-model-generation-editor__item__id',
                {
                  'generation-spec-model-generation-editor__item__id--has-error':
                    !isUnique,
                },
              )}
              spellCheck={false}
              value={isDefault ? 'DEFAULT' : generationTreeNode.id}
              onChange={changeNodeId}
              disabled={isDefault}
            />
            <CustomSelectorInput
              className="generation-spec-model-generation-editor__item__dropdown"
              options={options}
              onChange={onChange}
              value={value}
              darkMode={true}
            />
            <button
              className="btn--dark btn--sm"
              onClick={visitModelGeneration}
              tabIndex={-1}
              title={'See mapping'}
            >
              <LongArrowRightIcon />
            </button>
            <button
              className="generation-spec-model-generation-editor__item__remove-btn"
              onClick={deleteNode}
              tabIndex={-1}
              title={'Remove'}
            >
              <TimesIcon />
            </button>
          </>
        )}
      </div>
    );
  },
)