diff --git a/Changelog.md b/Changelog.md index 9ce4eac44..4a075f9ba 100644 --- a/Changelog.md +++ b/Changelog.md @@ -4,6 +4,9 @@ - **Improved** styling on icon buttons ([#675](https://github.com/aws/graph-explorer/pull/675)) +- **Improved** styling on checkboxes across the app, and specifically the export + options popover and entity filters sidebar + ([#676](https://github.com/aws/graph-explorer/pull/676)) ## Release 1.11.0 diff --git a/packages/graph-explorer/package.json b/packages/graph-explorer/package.json index f1558ac30..2c47eb32b 100644 --- a/packages/graph-explorer/package.json +++ b/packages/graph-explorer/package.json @@ -28,6 +28,7 @@ "@radix-ui/react-checkbox": "^1.1.2", "@radix-ui/react-form": "^0.1.0", "@radix-ui/react-label": "^2.1.0", + "@radix-ui/react-popover": "^1.1.2", "@radix-ui/react-select": "^2.1.2", "@radix-ui/react-toggle": "^1.1.0", "@react-aria/button": "3.9.8", diff --git a/packages/graph-explorer/src/components/Checkbox/Checkbox.styles.ts b/packages/graph-explorer/src/components/Checkbox/Checkbox.styles.ts deleted file mode 100644 index 32f313e86..000000000 --- a/packages/graph-explorer/src/components/Checkbox/Checkbox.styles.ts +++ /dev/null @@ -1,72 +0,0 @@ -import { css } from "@emotion/css"; -import { fade, ThemeStyleFn } from "@/core"; - -export const checkboxStyles: ThemeStyleFn = ({ theme }) => { - const { forms, palette } = theme; - return css` - margin-right: 4px; - cursor: pointer; - - &.checkbox-readonly { - pointer-events: none; - cursor: auto; - } - &.checkbox-disabled { - filter: opacity(30%); - pointer-events: none; - cursor: not-allowed; - } - - &.checkbox-selected { - rect:first-of-type { - fill: ${palette.primary.main}; - stroke: none; - } - - path:first-of-type { - fill: ${palette.primary.contrastText}; - } - } - - &.checkbox-indeterminate { - rect:first-of-type { - fill: ${palette.border}; - stroke: none; - } - } - - &.checkbox-invalid { - rect:first-of-type { - stroke: ${fade(palette.error.main, 0.7)}; - } - } - rect:first-of-type { - fill: none; - stroke: ${palette.border}; - } - - path:first-of-type { - fill: ${palette.primary.contrastText}; - } - - rect ~ rect { - stroke: ${forms?.focus?.outlineColor || palette.primary.main}; - } - `; -}; - -export const labelStyles: ThemeStyleFn = ({ theme }) => css` - display: flex; - align-items: center; - color: ${theme.forms?.label?.color || theme.palette.text.primary}; - &.checkbox-label-invalid { - color: ${theme.forms?.error?.labelColor || theme.palette.error.main}; - } - &.checkbox-label-readonly { - pointer-events: none; - } - &.checkbox-label-disabled { - cursor: not-allowed; - } - cursor: pointer; -`; diff --git a/packages/graph-explorer/src/components/Checkbox/Checkbox.tsx b/packages/graph-explorer/src/components/Checkbox/Checkbox.tsx deleted file mode 100644 index 09563e400..000000000 --- a/packages/graph-explorer/src/components/Checkbox/Checkbox.tsx +++ /dev/null @@ -1,142 +0,0 @@ -import { cn } from "@/utils"; -import { useCheckbox } from "@react-aria/checkbox"; -import { useFocusRing } from "@react-aria/focus"; -import { VisuallyHidden } from "@react-aria/visually-hidden"; -import type { AriaCheckboxProps } from "@react-types/checkbox"; -import type { PropsWithChildren } from "react"; -import { useCallback, useRef } from "react"; -import { useWithTheme } from "@/core"; -import { checkboxStyles, labelStyles } from "./Checkbox.styles"; - -export enum CheckboxSizes { - "sm" = "sm", - "md" = "md", - "lg" = "lg", -} - -export interface CheckboxProps - extends Omit { - /* size of the Checkbox sm, md or lg*/ - size?: CheckboxSizes | keyof typeof CheckboxSizes; - onChange: (isSelected: boolean) => void; - className?: string; -} - -const defaultSizeMap: Record = { - sm: 24, - md: 28, - lg: 32, -}; - -const scaconstick = (size: number) => { - return size / defaultSizeMap.md; -}; - -const NOOP = () => {}; - -export const Checkbox = ({ - size = "md", - className, - ...props -}: PropsWithChildren) => { - const ref = useRef(null); - - const sizeMap = defaultSizeMap; - - const { isSelected, isIndeterminate, onChange, children } = props; - - const handleChange = useCallback( - (isSelected: boolean) => { - onChange(isSelected); - }, - [onChange] - ); - - const { inputProps } = useCheckbox( - props, - { - isSelected: isSelected || false, - setSelected: handleChange, - toggle: NOOP, - }, - ref - ); - const { isFocusVisible, focusProps } = useFocusRing(); - - const isSelectedOrIndeterminate = isSelected || isIndeterminate; - const computedSize = sizeMap[size] || 28; - - const styleWithTheme = useWithTheme(); - return ( - - ); -}; - -export default Checkbox; diff --git a/packages/graph-explorer/src/components/Checkbox/index.ts b/packages/graph-explorer/src/components/Checkbox/index.ts deleted file mode 100644 index c391828bd..000000000 --- a/packages/graph-explorer/src/components/Checkbox/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export { default } from "./Checkbox"; -export type { CheckboxProps } from "./Checkbox"; diff --git a/packages/graph-explorer/src/components/CheckboxList.tsx b/packages/graph-explorer/src/components/CheckboxList.tsx new file mode 100644 index 000000000..771657980 --- /dev/null +++ b/packages/graph-explorer/src/components/CheckboxList.tsx @@ -0,0 +1,105 @@ +import { cn } from "@/utils"; +import { ReactNode } from "react"; +import { Checkbox, Label } from "./radix"; +import Divider from "./Divider"; + +export type CheckboxListItemProps = { + id: string; + text: ReactNode; + endAdornment?: ReactNode; + isDisabled?: boolean; +}; + +export type CheckboxListProps = { + /** + * Override or extend the styles applied to the component. + */ + className?: string; + /** + * The content to display as element title. + */ + title?: string; + /** + * Checkboxes array to be displayed. + */ + checkboxes: Array; + /** + * Id values shown as selected checkboxes + */ + selectedIds: Set; + /** + * If true true the component is disabled + */ + isDisabled?: boolean; + /** + * Callback fired when the state is changed + */ + onChange(id: string, isSelected: boolean): void; + /** + * Callback fired when the state of all checkboxes it wants to be changed. + * If this method is not defined, the "all/none" Checkbox is removed. + */ + onChangeAll?(isSelected: boolean): void; +}; + +export default function CheckboxList({ + className, + title, + checkboxes, + isDisabled, + selectedIds, + onChange, + onChangeAll, +}: CheckboxListProps) { + const numOfSelections = selectedIds.size; + const totalCheckboxes = checkboxes.length; + const allDisabled = checkboxes.reduce( + (disabled, ch) => disabled && !!ch.isDisabled, + true + ); + + return ( +
+ {title &&
{title}
} +
+ {checkboxes.map(checkbox => { + return ( + + ); + })} + + {onChangeAll && ( + + )} +
+
+ ); +} diff --git a/packages/graph-explorer/src/components/CheckboxList/CheckboxList.styles.ts b/packages/graph-explorer/src/components/CheckboxList/CheckboxList.styles.ts deleted file mode 100644 index b49448d4d..000000000 --- a/packages/graph-explorer/src/components/CheckboxList/CheckboxList.styles.ts +++ /dev/null @@ -1,71 +0,0 @@ -import { css } from "@emotion/css"; -import type { ThemeStyleFn } from "@/core"; - -const defaultStyles: ThemeStyleFn = ({ theme, isDarkTheme }) => css` - &.checkbox-list { - display: flex; - flex-grow: 1; - flex-direction: column; - width: 100%; - height: 100%; - - .title { - padding: ${theme.spacing["2x"]} 0; - font-weight: bold; - font-size: ${theme.typography.sizes.xs}; - } - - .content { - position: relative; - display: flex; - flex-direction: column; - overflow: auto; - max-height: 25rem; - row-gap: ${theme.spacing["2x"]}; - padding: ${theme.spacing["2x"]} 0 0; - border: solid 1px ${theme.palette.border}; - border-radius: ${theme.shape.borderRadius}; - margin-bottom: ${theme.spacing["4x"]}; - } - - .checkbox-container { - padding: 0 ${theme.spacing["2x"]}; - } - .checkbox { - svg { - min-width: 28px; - } - } - - .checkbox-content { - user-select: none; - width: 100%; - display: flex; - justify-content: space-between; - align-items: center; - word-break: break-word; - gap: ${theme.spacing["2x"]}; - } - - .icon { - > svg { - width: 16px; - height: 16px; - color: ${theme.palette.primary.main}; - } - } - - .selector { - user-select: none; - position: sticky; - bottom: 0; - background: ${isDarkTheme - ? theme.palette.background.secondary - : theme.palette.background.default}; - border-top: solid 1px ${theme.palette.border}; - padding-top: ${theme.spacing.base}; - } - } -`; - -export default defaultStyles; diff --git a/packages/graph-explorer/src/components/CheckboxList/CheckboxList.tsx b/packages/graph-explorer/src/components/CheckboxList/CheckboxList.tsx deleted file mode 100644 index 74fec2b38..000000000 --- a/packages/graph-explorer/src/components/CheckboxList/CheckboxList.tsx +++ /dev/null @@ -1,116 +0,0 @@ -import { cn } from "@/utils"; -import { ReactNode } from "react"; -import { useWithTheme } from "@/core"; -import Checkbox from "@/components/Checkbox/Checkbox"; -import defaultStyles from "./CheckboxList.styles"; - -export type CheckboxListItemProps = { - id: string; - text: ReactNode; - endAdornment?: ReactNode; - isDisabled?: boolean; -}; - -export type CheckboxListProps = { - /** - * Override or extend the styles applied to the component. - */ - className?: string; - /** - * The content to display as element title. - */ - title?: string; - /** - * Checkboxes array to be displayed. - */ - checkboxes: Array; - /** - * Id values shown as selected checkboxes - */ - selectedIds: Set; - /** - * If true true the component is disabled - */ - isDisabled?: boolean; - /** - * Callback fired when the state is changed - */ - onChange(id: string, isSelected: boolean): void; - /** - * Callback fired when the state of all checkboxes it wants to be changed. - * If this method is not defined, the "all/none" Checkbox is removed. - */ - onChangeAll?(isSelected: boolean): void; -}; - -export const CheckboxList = ({ - className, - title, - checkboxes, - isDisabled, - selectedIds, - onChange, - onChangeAll, -}: CheckboxListProps) => { - const stylesWithTheme = useWithTheme(); - - const numOfSelections = selectedIds.size; - const totalCheckboxes = checkboxes.length; - const allDisabled = checkboxes.reduce( - (disabled, ch) => disabled && !!ch.isDisabled, - true - ); - - return ( -
- {title &&
{title}
} -
- {checkboxes.map(checkbox => { - return ( -
- onChange(checkbox.id, isSelected)} - className={"checkbox"} - > -
-
{checkbox.text}
-
{checkbox.endAdornment}
-
-
-
- ); - })} - {onChangeAll && ( -
-
- 0 && numOfSelections !== totalCheckboxes - } - isSelected={numOfSelections === totalCheckboxes} - isDisabled={isDisabled || allDisabled} - onChange={isSelected => { - onChangeAll(isSelected); - }} - > -
-
- {numOfSelections} selected of {totalCheckboxes} -
-
-
-
-
- )} -
-
- ); -}; - -export default CheckboxList; diff --git a/packages/graph-explorer/src/components/CheckboxList/index.ts b/packages/graph-explorer/src/components/CheckboxList/index.ts deleted file mode 100644 index b9f489786..000000000 --- a/packages/graph-explorer/src/components/CheckboxList/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export { default } from "./CheckboxList"; -export type { CheckboxListProps, CheckboxListItemProps } from "./CheckboxList"; diff --git a/packages/graph-explorer/src/components/Chip/Chip.tsx b/packages/graph-explorer/src/components/Chip.tsx similarity index 100% rename from packages/graph-explorer/src/components/Chip/Chip.tsx rename to packages/graph-explorer/src/components/Chip.tsx diff --git a/packages/graph-explorer/src/components/Chip/index.ts b/packages/graph-explorer/src/components/Chip/index.ts deleted file mode 100644 index 4729fe635..000000000 --- a/packages/graph-explorer/src/components/Chip/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export { default } from "./Chip"; -export type { ChipProps } from "./Chip"; diff --git a/packages/graph-explorer/src/components/Popover.tsx b/packages/graph-explorer/src/components/Popover.tsx new file mode 100644 index 000000000..41ffc7e9e --- /dev/null +++ b/packages/graph-explorer/src/components/Popover.tsx @@ -0,0 +1,33 @@ +"use client"; + +import * as React from "react"; +import * as PopoverPrimitive from "@radix-ui/react-popover"; + +import { cn } from "@/utils"; + +const Popover = PopoverPrimitive.Root; + +const PopoverTrigger = PopoverPrimitive.Trigger; + +const PopoverAnchor = PopoverPrimitive.Anchor; + +const PopoverContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, align = "center", sideOffset = 4, ...props }, ref) => ( + + + +)); +PopoverContent.displayName = PopoverPrimitive.Content.displayName; + +export { Popover, PopoverTrigger, PopoverContent, PopoverAnchor }; diff --git a/packages/graph-explorer/src/components/Tabular/ModuleContainerTabularHeader/ModuleContainerTabularHeader.styles.ts b/packages/graph-explorer/src/components/Tabular/ModuleContainerTabularHeader/ModuleContainerTabularHeader.styles.ts index 2544b471a..342570c06 100644 --- a/packages/graph-explorer/src/components/Tabular/ModuleContainerTabularHeader/ModuleContainerTabularHeader.styles.ts +++ b/packages/graph-explorer/src/components/Tabular/ModuleContainerTabularHeader/ModuleContainerTabularHeader.styles.ts @@ -6,7 +6,6 @@ const defaultStyles: ThemeStyleFn = ({ theme }) => { return css` &.entities-tabular-header { position: relative; - z-index: 100; display: flex; align-items: center; width: 100%; diff --git a/packages/graph-explorer/src/components/Tabular/Tabular.tsx b/packages/graph-explorer/src/components/Tabular/Tabular.tsx index a8bd6affe..538f5d8b8 100644 --- a/packages/graph-explorer/src/components/Tabular/Tabular.tsx +++ b/packages/graph-explorer/src/components/Tabular/Tabular.tsx @@ -23,7 +23,6 @@ import { } from "./controls"; import type { TabularInstance } from "./helpers/tableInstanceToTabularInstance"; import tableInstanceToTabularInstance from "./helpers/tableInstanceToTabularInstance"; -import { TABULAR_SELECTION_COL_ID } from "./hooks/useSelectionColumn"; import defaultStyles from "./Tabular.styles"; import TabularControlsProvider, { useTabularControl, @@ -145,14 +144,8 @@ const TabularContent = ({ const [stickyHeaderTop, setStickyHeaderTop] = useState(0); const styleWithTheme = useWithTheme(); - const { - getTableProps, - getTableBodyProps, - headerGroups, - rows, - page, - setHiddenColumns, - } = tableInstance; + const { getTableProps, getTableBodyProps, headerGroups, rows, page } = + tableInstance; const actualRows = useDeepMemo(() => { if (disablePagination) { @@ -194,21 +187,6 @@ const TabularContent = ({ // headerControlsChildren can affect to the container's height }, [headerControlsRef, headerControlsChildren, headerControlsPosition]); - useEffect(() => { - if (rowSelectionMode !== "checkbox") { - setHiddenColumns(hiddenColumns => [ - TABULAR_SELECTION_COL_ID, - ...hiddenColumns, - ]); - - return; - } - - setHiddenColumns(hiddenColumns => - hiddenColumns.filter(col => col !== TABULAR_SELECTION_COL_ID) - ); - }, [setHiddenColumns, rowSelectionMode]); - return (
css` - z-index: 1000; - - .card { - border-radius: 2px; - margin: 0 4px; - padding: 16px; - max-height: 90vh; - overflow-y: auto; - } - - .title { - padding: 8px 0; - font-size: 0.75rem; - } - - .columns-container { - width: 90%; - min-width: 200px; - min-height: 32px; - max-height: 200px; - overflow-y: auto; - padding: 8px; - margin: 0 auto; - display: flex; - flex-direction: column; - border: solid 1px var(--palette-border); - border-radius: 4px; - } - - .actions { - padding: 8px 4px; - display: flex; - flex-direction: column; - align-content: center; - justify-content: center; - } -`; - -export default defaultStyles; diff --git a/packages/graph-explorer/src/components/Tabular/controls/ExportControl/ExternalExportControl.tsx b/packages/graph-explorer/src/components/Tabular/controls/ExportControl/ExternalExportControl.tsx index 16aa97047..c8ed6633e 100644 --- a/packages/graph-explorer/src/components/Tabular/controls/ExportControl/ExternalExportControl.tsx +++ b/packages/graph-explorer/src/components/Tabular/controls/ExportControl/ExternalExportControl.tsx @@ -1,77 +1,40 @@ -import { css } from "@emotion/css"; -import { cn } from "@/utils"; import { saveAs } from "file-saver"; import { useCallback, useState } from "react"; -import { useLayer } from "react-laag"; import { Row } from "react-table"; -import Button from "@/components/Button"; -import Card from "@/components/Card"; -import Checkbox from "@/components/Checkbox"; +import { Button, Input, Select } from "@/components"; +import { Checkbox, Label } from "@/components/radix"; import { IconButton } from "@/components"; import { TrayArrowIcon } from "@/components/icons"; -import Input from "@/components/Input"; -import Select from "@/components/Select"; import { TabularInstance } from "@/components/Tabular/helpers/tableInstanceToTabularInstance"; -import defaultStyles from "./ExportControl.styles"; + import transformToCsv from "./transfomerToCsv"; import transformToJson from "./transfomerToJson"; import { toCsvFileData, toJsonFileData } from "@/utils/fileData"; - -const rootStyles = () => css` - position: relative; - display: flex; - align-items: center; -`; +import { Popover, PopoverContent, PopoverTrigger } from "@/components"; type ExportControlProps> = { - className?: string; omittedColumnsIds?: string[]; instance: TabularInstance; }; export function ExternalExportControl>({ - className, omittedColumnsIds, instance, }: ExportControlProps) { - const [isContentVisible, setIsContentVisible] = useState(false); - - const { renderLayer, triggerProps, layerProps } = useLayer({ - isOpen: isContentVisible, - onOutsideClick: () => { - setIsContentVisible(false); - }, - onDisappear: () => { - setIsContentVisible(false); - }, - overflowContainer: true, - auto: true, - placement: "bottom-end", - triggerOffset: 4, - }); - return ( -
- } - onPress={() => setIsContentVisible(visible => !visible)} - {...triggerProps} - /> - {renderLayer( -
- {isContentVisible && ( - - )} -
- )} -
+ + + } /> + + + + + ); } @@ -141,78 +104,93 @@ function ExportOptionsModal>({ ]); return ( - -
Export columns
-
- {columnOrder.map(columnId => - omittedColumnsIds?.includes(columnId) || - !visibleColumns[columnId] ? null : ( +
+
+
Export columns
+
+ {columnOrder.map(columnId => + omittedColumnsIds?.includes(columnId) || + !visibleColumns[columnId] ? null : ( + + ) + )} +
+
+
+
Options
+
+ + +
+
+
+ + setFormat(f as string)} - options={[ - { - label: "CSV", - value: "csv", - }, - { label: "JSON", value: "json" }, - ]} - /> -
Save as
- -
-
- +
); } diff --git a/packages/graph-explorer/src/components/Tabular/hooks/useSelectionColumn.tsx b/packages/graph-explorer/src/components/Tabular/hooks/useSelectionColumn.tsx deleted file mode 100644 index e90466a79..000000000 --- a/packages/graph-explorer/src/components/Tabular/hooks/useSelectionColumn.tsx +++ /dev/null @@ -1,55 +0,0 @@ -/** - * This hook creates a new columns placed at the first position - * that allows to Select rows using a Checkbox - */ - -import type { Hooks, Row } from "react-table"; - -import { Checkbox, CheckboxSizes } from "@/components/Checkbox/Checkbox"; -import type { TabularOptions } from "../useTabular"; - -export const TABULAR_SELECTION_COL_ID = "__tabular-auto-generated-selection"; - -const useSelectionColumn = - (options: TabularOptions) => - (hooks: Hooks) => { - if (options.rowSelectionMode !== "checkbox") { - return; - } - - hooks.visibleColumns.push(columns => [ - { - id: TABULAR_SELECTION_COL_ID, - disableResizing: true, - disableSortBy: true, - minWidth: 48, - width: 48, - Header: ({ state, isAllRowsSelected, toggleAllRowsSelected }) => { - const someIsSelected = Object.values(state.selectedRowIds).some( - selection => selection === true - ); - return ( - - ); - }, - Cell: ({ row }: { row: Row }) => { - return ( - - ); - }, - }, - ...columns, - ]); - }; - -export default useSelectionColumn; diff --git a/packages/graph-explorer/src/components/Tabular/useTabular.ts b/packages/graph-explorer/src/components/Tabular/useTabular.ts index e544cf002..1f5c05c3b 100644 --- a/packages/graph-explorer/src/components/Tabular/useTabular.ts +++ b/packages/graph-explorer/src/components/Tabular/useTabular.ts @@ -33,7 +33,6 @@ import { useTheme } from "@/core"; import { useDeepMemo } from "@/hooks"; import TextFilter from "./filters/TextFilter"; import columnDefinitionToColumn from "./helpers/columnDefinitionToColumn"; -import useSelectionColumn from "./hooks/useSelectionColumn"; import useDiffState from "./plugins/useDiffState"; import useFullWidth from "./plugins/useFullWidth"; @@ -443,8 +442,7 @@ export const useTabular = (options: TabularOptions) => { useDiffState, useSortBy, usePagination, - useRowSelect, - useSelectionColumn(options) + useRowSelect ); }; diff --git a/packages/graph-explorer/src/components/index.ts b/packages/graph-explorer/src/components/index.ts index 991cb31c1..d74a4d905 100644 --- a/packages/graph-explorer/src/components/index.ts +++ b/packages/graph-explorer/src/components/index.ts @@ -9,9 +9,6 @@ export * from "./Button"; export { default as Card } from "./Card"; export * from "./Card"; -export { default as Checkbox } from "./Checkbox"; -export * from "./Checkbox"; - export { default as CheckboxList } from "./CheckboxList"; export * from "./CheckboxList"; @@ -44,6 +41,7 @@ export { default as LoadingSpinner } from "./LoadingSpinner"; export * from "./LoadingSpinner"; export * from "./Panel"; +export * from "./Popover"; export { default as NotInProduction } from "./NotInProduction"; diff --git a/packages/graph-explorer/src/components/radix/Label.tsx b/packages/graph-explorer/src/components/radix/Label.tsx index dba07b3c2..88a7c661c 100644 --- a/packages/graph-explorer/src/components/radix/Label.tsx +++ b/packages/graph-explorer/src/components/radix/Label.tsx @@ -9,7 +9,7 @@ const Label = React.forwardRef<
- { - onFormChange("proxyConnection")(e.target.checked); - }} - label={"Using Proxy-Server"} - /> +
{form.proxyConnection && (
@@ -296,14 +298,16 @@ const CreateConnection = ({ )} {form.proxyConnection && (
- { - onFormChange("awsAuthEnabled")(e.target.checked); - }} - label={"AWS IAM Auth Enabled"} - /> +
)} {form.proxyConnection && form.awsAuthEnabled && ( @@ -337,27 +341,22 @@ const CreateConnection = ({ )}
- { - onFormChange("fetchTimeoutEnabled")(e.target.checked); - }} - styles={{ - label: { - display: "block", - }, - }} - label={ -
- Enable Fetch Timeout - - Large datasets may require a large amount of time to fetch. If - the timeout is exceeded, the request will be cancelled. - -
- } - /> + {form.fetchTimeoutEnabled && (
- { - onFormChange("nodeExpansionLimitEnabled")(e.target.checked); - }} - styles={{ - label: { - display: "block", - }, - }} - label={ -
- Enable Node Expansion Limit - - Large datasets may require a default limit to the amount of - neighbors that are returned during any single expansion. - -
- } - /> + {form.nodeExpansionLimitEnabled && (
-
-
{vertexType}
+
+
{vertexType}
-
+