@dxos/plugin-navtree 0.10.0 → 0.11.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/PLUGIN.mdl +8 -6
- package/dist/lib/NavTreePlugin.mjs +40 -0
- package/dist/lib/NavTreePlugin.mjs.map +1 -0
- package/dist/lib/capabilities.mjs +11 -0
- package/dist/lib/capabilities.mjs.map +1 -0
- package/dist/lib/chunk-CommandsDialogContent.mjs +100 -0
- package/dist/lib/chunk-CommandsDialogContent.mjs.map +1 -0
- package/dist/lib/chunk-CommandsTrigger.mjs +27 -0
- package/dist/lib/chunk-CommandsTrigger.mjs.map +1 -0
- package/dist/lib/chunk-NavTreeDocumentTitle.mjs +17 -0
- package/dist/lib/chunk-NavTreeDocumentTitle.mjs.map +1 -0
- package/dist/lib/chunk-app-graph-builder.mjs +33 -0
- package/dist/lib/chunk-app-graph-builder.mjs.map +1 -0
- package/dist/lib/chunk-expose.mjs +31 -0
- package/dist/lib/chunk-expose.mjs.map +1 -0
- package/dist/lib/chunk-keyboard.mjs +49 -0
- package/dist/lib/chunk-keyboard.mjs.map +1 -0
- package/dist/lib/{neutral/chunk-IRQMJLRY.mjs → chunk-meta.mjs} +14 -23
- package/dist/lib/chunk-meta.mjs.map +1 -0
- package/dist/lib/chunk-operation-handler.mjs +11 -0
- package/dist/lib/chunk-operation-handler.mjs.map +1 -0
- package/dist/lib/chunk-react-surface.mjs +46 -0
- package/dist/lib/chunk-react-surface.mjs.map +1 -0
- package/dist/lib/chunk-state.mjs +106 -0
- package/dist/lib/chunk-state.mjs.map +1 -0
- package/dist/lib/chunk-types.mjs +26 -0
- package/dist/lib/chunk-types.mjs.map +1 -0
- package/dist/lib/chunk-util.mjs +51 -0
- package/dist/lib/chunk-util.mjs.map +1 -0
- package/dist/lib/components.mjs +723 -0
- package/dist/lib/components.mjs.map +1 -0
- package/dist/lib/containers.mjs +231 -0
- package/dist/lib/containers.mjs.map +1 -0
- package/dist/lib/hooks.mjs +162 -0
- package/dist/lib/hooks.mjs.map +1 -0
- package/dist/lib/index.mjs +4 -0
- package/dist/lib/meta.mjs +2 -0
- package/dist/lib/operations.mjs +7 -0
- package/dist/lib/operations.mjs.map +1 -0
- package/dist/lib/plugin.mjs +9 -0
- package/dist/lib/plugin.mjs.map +1 -0
- package/dist/lib/testing.mjs +397 -0
- package/dist/lib/testing.mjs.map +1 -0
- package/dist/lib/translations.mjs +17 -0
- package/dist/lib/translations.mjs.map +1 -0
- package/dist/lib/types.mjs +2 -0
- package/dist/types/src/NavTreePlugin.d.ts.map +1 -1
- package/dist/types/src/capabilities/app-graph-builder.d.ts +1 -1
- package/dist/types/src/capabilities/keyboard.d.ts +1 -1
- package/dist/types/src/capabilities/nav-tree-view-state.d.ts +12 -0
- package/dist/types/src/capabilities/nav-tree-view-state.d.ts.map +1 -0
- package/dist/types/src/capabilities/nav-tree-view-state.test.d.ts +2 -0
- package/dist/types/src/capabilities/nav-tree-view-state.test.d.ts.map +1 -0
- package/dist/types/src/capabilities/operation-handler.d.ts +1 -1
- package/dist/types/src/capabilities/react-surface.d.ts +1 -1
- package/dist/types/src/capabilities/react-surface.d.ts.map +1 -1
- package/dist/types/src/capabilities/state.d.ts +1 -1
- package/dist/types/src/components/NavTree/NavTree.d.ts.map +1 -1
- package/dist/types/src/components/NavTree/NavTree.stories.d.ts +3 -0
- package/dist/types/src/components/NavTree/NavTree.stories.d.ts.map +1 -1
- package/dist/types/src/components/NavTreeContext/NavTreeContext.d.ts.map +1 -1
- package/dist/types/src/components/NavTreeItem/NavTreeItemAction.d.ts +1 -1
- package/dist/types/src/components/NavTreeItem/NavTreeItemAction.d.ts.map +1 -1
- package/dist/types/src/components/Sidebar/L0Menu.d.ts.map +1 -1
- package/dist/types/src/components/Sidebar/L1Panel.d.ts +5 -2
- package/dist/types/src/components/Sidebar/L1Panel.d.ts.map +1 -1
- package/dist/types/src/components/Sidebar/L1Tabs.d.ts.map +1 -1
- package/dist/types/src/containers/CommandsDialogContent/CommandsDialogContent.d.ts.map +1 -1
- package/dist/types/src/containers/CommandsDialogContent/CommandsDialogContent.stories.d.ts +2 -0
- package/dist/types/src/containers/CommandsDialogContent/CommandsDialogContent.stories.d.ts.map +1 -1
- package/dist/types/src/containers/CommandsTrigger/CommandsTrigger.d.ts +4 -1
- package/dist/types/src/containers/CommandsTrigger/CommandsTrigger.d.ts.map +1 -1
- package/dist/types/src/containers/NavTreeContainer/NavTreeContainer.d.ts.map +1 -1
- package/dist/types/src/containers/NavTreeDocumentTitle/NavTreeDocumentTitle.d.ts +5 -2
- package/dist/types/src/containers/NavTreeDocumentTitle/NavTreeDocumentTitle.d.ts.map +1 -1
- package/dist/types/src/experimental/Tree.d.ts +0 -1
- package/dist/types/src/experimental/Tree.d.ts.map +1 -1
- package/dist/types/src/experimental/Tree.stories.d.ts.map +1 -1
- package/dist/types/src/experimental/visit-nodes.d.ts +3 -0
- package/dist/types/src/experimental/visit-nodes.d.ts.map +1 -0
- package/dist/types/src/hooks/useActions.d.ts +3 -1
- package/dist/types/src/hooks/useActions.d.ts.map +1 -1
- package/dist/types/src/translations.d.ts +2 -0
- package/dist/types/src/translations.d.ts.map +1 -1
- package/dist/types/src/types/NavTreeCapabilities.d.ts +1 -1
- package/dist/types/src/types/NavTreeCapabilities.d.ts.map +1 -1
- package/dist/types/src/types/schema.d.ts +1 -1
- package/dist/types/src/types/schema.d.ts.map +1 -1
- package/dist/types/src/util.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +47 -52
- package/src/NavTreePlugin.tsx +3 -1
- package/src/capabilities/nav-tree-view-state.test.ts +55 -0
- package/src/capabilities/nav-tree-view-state.ts +19 -0
- package/src/capabilities/{react-surface.tsx → react-surface.ts} +8 -9
- package/src/capabilities/state.ts +47 -38
- package/src/components/NavTree/NavTree.stories.tsx +26 -5
- package/src/components/NavTree/NavTree.tsx +10 -13
- package/src/components/NavTreeItem/NavTreeItemAction.tsx +1 -1
- package/src/components/Sidebar/L0Menu.tsx +9 -3
- package/src/components/Sidebar/L1Panel.tsx +52 -20
- package/src/components/Sidebar/L1Tabs.tsx +6 -0
- package/src/containers/CommandsDialogContent/CommandsDialogContent.tsx +49 -44
- package/src/containers/CommandsTrigger/CommandsTrigger.tsx +2 -0
- package/src/containers/NavTreeContainer/NavTreeContainer.tsx +17 -18
- package/src/containers/NavTreeDocumentTitle/NavTreeDocumentTitle.tsx +2 -0
- package/src/experimental/Tree.stories.tsx +2 -1
- package/src/experimental/Tree.tsx +2 -18
- package/src/experimental/visit-nodes.ts +27 -0
- package/src/hooks/useActions.ts +15 -4
- package/src/hooks/useNavTreeModel.ts +1 -1
- package/src/operations/expose.ts +2 -2
- package/src/testing/app-graph-builder.ts +1 -1
- package/src/translations.ts +3 -0
- package/src/types/NavTreeCapabilities.ts +1 -1
- package/src/types/schema.ts +1 -1
- package/src/util.ts +7 -9
- package/dist/lib/neutral/CommandsDialogContent-TEKBCQ3U.mjs +0 -112
- package/dist/lib/neutral/CommandsDialogContent-TEKBCQ3U.mjs.map +0 -7
- package/dist/lib/neutral/CommandsTrigger-HGCI22SP.mjs +0 -27
- package/dist/lib/neutral/CommandsTrigger-HGCI22SP.mjs.map +0 -7
- package/dist/lib/neutral/NavTreeContainer-ICDKC2GI.mjs +0 -12
- package/dist/lib/neutral/NavTreeContainer-ICDKC2GI.mjs.map +0 -7
- package/dist/lib/neutral/NavTreeDocumentTitle-RMERXZGK.mjs +0 -22
- package/dist/lib/neutral/NavTreeDocumentTitle-RMERXZGK.mjs.map +0 -7
- package/dist/lib/neutral/NavTreePlugin.mjs +0 -68
- package/dist/lib/neutral/NavTreePlugin.mjs.map +0 -7
- package/dist/lib/neutral/NavTreePlugin.node.mjs +0 -18
- package/dist/lib/neutral/NavTreePlugin.node.mjs.map +0 -7
- package/dist/lib/neutral/NavTreePlugin.workerd.mjs +0 -16
- package/dist/lib/neutral/NavTreePlugin.workerd.mjs.map +0 -7
- package/dist/lib/neutral/app-graph-builder-2DYAIROU.mjs +0 -42
- package/dist/lib/neutral/app-graph-builder-2DYAIROU.mjs.map +0 -7
- package/dist/lib/neutral/capabilities/index.mjs +0 -17
- package/dist/lib/neutral/capabilities/index.mjs.map +0 -7
- package/dist/lib/neutral/chunk-4RN6TH36.mjs +0 -292
- package/dist/lib/neutral/chunk-4RN6TH36.mjs.map +0 -7
- package/dist/lib/neutral/chunk-BAVI2K7A.mjs +0 -27
- package/dist/lib/neutral/chunk-BAVI2K7A.mjs.map +0 -7
- package/dist/lib/neutral/chunk-EAN4K6OL.mjs +0 -8
- package/dist/lib/neutral/chunk-EAN4K6OL.mjs.map +0 -7
- package/dist/lib/neutral/chunk-IRQMJLRY.mjs.map +0 -7
- package/dist/lib/neutral/chunk-J5LGTIGS.mjs +0 -10
- package/dist/lib/neutral/chunk-J5LGTIGS.mjs.map +0 -7
- package/dist/lib/neutral/chunk-JOSNCOV4.mjs +0 -79
- package/dist/lib/neutral/chunk-JOSNCOV4.mjs.map +0 -7
- package/dist/lib/neutral/components/index.mjs +0 -814
- package/dist/lib/neutral/components/index.mjs.map +0 -7
- package/dist/lib/neutral/containers/index.mjs +0 -20
- package/dist/lib/neutral/containers/index.mjs.map +0 -7
- package/dist/lib/neutral/expose-HIBA2NQG.mjs +0 -38
- package/dist/lib/neutral/expose-HIBA2NQG.mjs.map +0 -7
- package/dist/lib/neutral/hooks/index.mjs +0 -181
- package/dist/lib/neutral/hooks/index.mjs.map +0 -7
- package/dist/lib/neutral/index.mjs +0 -34
- package/dist/lib/neutral/index.mjs.map +0 -7
- package/dist/lib/neutral/keyboard-JM2HCF5N.mjs +0 -58
- package/dist/lib/neutral/keyboard-JM2HCF5N.mjs.map +0 -7
- package/dist/lib/neutral/meta.json +0 -1
- package/dist/lib/neutral/meta.mjs +0 -12
- package/dist/lib/neutral/meta.mjs.map +0 -7
- package/dist/lib/neutral/operation-handler-ORDOJUL2.mjs +0 -13
- package/dist/lib/neutral/operation-handler-ORDOJUL2.mjs.map +0 -7
- package/dist/lib/neutral/operations/index.mjs +0 -8
- package/dist/lib/neutral/operations/index.mjs.map +0 -7
- package/dist/lib/neutral/plugin.mjs +0 -16
- package/dist/lib/neutral/plugin.mjs.map +0 -7
- package/dist/lib/neutral/react-surface-QPMUEDZX.mjs +0 -48
- package/dist/lib/neutral/react-surface-QPMUEDZX.mjs.map +0 -7
- package/dist/lib/neutral/state-PDZU4PIP.mjs +0 -126
- package/dist/lib/neutral/state-PDZU4PIP.mjs.map +0 -7
- package/dist/lib/neutral/testing/index.mjs +0 -439
- package/dist/lib/neutral/testing/index.mjs.map +0 -7
- package/dist/lib/neutral/translations.mjs +0 -23
- package/dist/lib/neutral/translations.mjs.map +0 -7
- package/dist/lib/neutral/types/index.mjs +0 -10
- package/dist/lib/neutral/types/index.mjs.map +0 -7
- package/dist/types/src/NavTreePlugin.node.d.ts +0 -4
- package/dist/types/src/NavTreePlugin.node.d.ts.map +0 -1
- package/dist/types/src/NavTreePlugin.test.d.ts +0 -2
- package/dist/types/src/NavTreePlugin.test.d.ts.map +0 -1
- package/dist/types/src/NavTreePlugin.workerd.d.ts +0 -4
- package/dist/types/src/NavTreePlugin.workerd.d.ts.map +0 -1
- package/src/NavTreePlugin.node.ts +0 -17
- package/src/NavTreePlugin.test.ts +0 -27
- package/src/NavTreePlugin.workerd.ts +0 -16
- /package/src/components/NavTreeContext/{NavTreeContext.tsx → NavTreeContext.ts} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"components.mjs","names":[],"sources":["../../src/components/NavTreeContext/NavTreeContext.ts","../../src/components/UserAccountAvatar/UserAccountAvatar.tsx","../../src/components/Sidebar/L0Menu.tsx","../../src/components/NavTreeItem/NavTreeItemAction.tsx","../../src/components/NavTreeItem/NavTreeItemColumns.tsx","../../src/components/Sidebar/L1Panel.tsx","../../src/components/Sidebar/L1Tabs.tsx","../../src/components/NavTree/NavTree.tsx"],"sourcesContent":["//\n// Copyright 2025 DXOS.org\n//\n\nimport { createContext, useContext } from 'react';\n\nimport { raise } from '@dxos/debug';\n\nimport { type NavTreeContextValue } from '../types';\n\nexport const NavTreeContext = createContext<NavTreeContextValue | null>(null);\n\nexport const useNavTreeContext = () => useContext(NavTreeContext) ?? raise(new Error('Missing NavTreeContext'));\n","//\n// Copyright 2023 DXOS.org\n//\n\nimport React from 'react';\n\nimport { Avatar, type AvatarStatus, type Size } from '@dxos/react-ui';\nimport { hexToFallback } from '@dxos/util';\n\nimport { L0ItemActiveTabIndicator } from '../Sidebar';\n\nexport type UserAccountAvatarProps = {\n size?: Size;\n userId?: string;\n hue?: string;\n emoji?: string;\n status?: AvatarStatus;\n};\n\nexport const UserAccountAvatar = ({ size, userId, hue, emoji, status }: UserAccountAvatarProps) => {\n const fallbackValue = hexToFallback(userId ?? '0');\n\n return (\n <>\n <L0ItemActiveTabIndicator classNames='inset-y-6' />\n <div\n className='grid place-items-center dx-focus-ring-group-indicator rounded-full'\n data-joyride='welcome/account'\n >\n <Avatar.Root>\n <Avatar.Content\n variant='circle'\n size={size ?? 12}\n status={status ?? 'active'}\n hue={hue || fallbackValue.hue}\n fallback={emoji || fallbackValue.emoji}\n data-testid='treeView.userAccount'\n />\n </Avatar.Root>\n </div>\n </>\n );\n};\n","//\n// Copyright 2025 DXOS.org\n//\n\nimport {\n type Edge,\n attachClosestEdge,\n extractClosestEdge,\n} from '@atlaskit/pragmatic-drag-and-drop-hitbox/closest-edge';\nimport { combine } from '@atlaskit/pragmatic-drag-and-drop/combine';\nimport { draggable, dropTargetForElements } from '@atlaskit/pragmatic-drag-and-drop/element/adapter';\nimport { preserveOffsetOnSource } from '@atlaskit/pragmatic-drag-and-drop/element/preserve-offset-on-source';\nimport { scrollJustEnoughIntoView } from '@atlaskit/pragmatic-drag-and-drop/element/scroll-just-enough-into-view';\nimport { useAtomValue } from '@effect-atom/atom-react';\nimport React, {\n type MouseEvent,\n type PropsWithChildren,\n forwardRef,\n memo,\n useCallback,\n useLayoutEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\n\nimport { type Node } from '@dxos/app-graph';\nimport { DxAvatar } from '@dxos/lit-ui/react';\nimport { useActionRunner } from '@dxos/plugin-graph/hooks';\nimport {\n Icon,\n IconButton,\n ScrollArea,\n type ThemedClassName,\n Tooltip,\n toLocalizedString,\n useMediaQuery,\n useTranslation,\n} from '@dxos/react-ui';\nimport { DropIndicator } from '@dxos/react-ui-list';\nimport { Menu, type MenuItem } from '@dxos/react-ui-menu';\nimport { Tabs } from '@dxos/react-ui-tabs';\nimport { mx } from '@dxos/ui-theme';\nimport { arrayMove } from '@dxos/util';\n\nimport { useNavTreeState } from '#hooks';\nimport { meta } from '#meta';\n\nimport { l0ItemType } from '../../util';\nimport { useNavTreeContext } from '../NavTreeContext';\nimport { UserAccountAvatar } from '../UserAccountAvatar';\n\n//\n// L0Item\n//\n\ntype L0ItemData = {\n id: L0ItemProps['item']['id'];\n type: 'l0Item';\n};\n\n// Local rearrange-handler callback shape; drag-and-drop is wired directly via pragmatic-dnd in `L0Item`,\n// so only the callback signature is needed here.\ntype StackItemRearrangeHandler<Data extends { id: string } = { id: string }> = (\n source: Data,\n target: Data,\n closestEdge: Edge | null,\n) => void;\n\ntype L0ItemRootProps = {\n item: Node.Node;\n parent?: Node.Node;\n path: string[];\n onMouseEnter?: () => void;\n};\n\ntype L0ItemProps = L0ItemRootProps & {\n item: Node.Node;\n parent?: Node.Node;\n path: string[];\n pinned?: boolean;\n onRearrange?: StackItemRearrangeHandler<L0ItemData>;\n onItemHover?: (params: { item: Node.Node }) => void;\n};\n\nconst useL0ItemClick = ({ item, parent, path }: L0ItemProps, type: string) => {\n const { onSelect, onTabChange } = useNavTreeContext();\n const { getItem } = useNavTreeState();\n const [isLg] = useMediaQuery('lg');\n const runAction = useActionRunner();\n\n return useCallback(\n (event: MouseEvent) => {\n switch (type) {\n case 'action': {\n const { properties: { caller } = {} } = item;\n return void runAction(item as Node.Action, caller ? { parent, path, caller } : { parent, path });\n }\n case 'tab':\n return onTabChange?.(item);\n case 'link':\n return onSelect?.({\n item,\n path,\n current: !getItem(path).current,\n option: event.altKey,\n shift: event.shiftKey,\n });\n }\n },\n [item, parent, type, getItem, onSelect, onTabChange, isLg, runAction],\n );\n};\n\nconst l0Breakpoints: Record<string, string> = {\n lg: 'hidden lg:grid',\n};\n\nconst L0ItemRoot = memo(\n forwardRef<HTMLButtonElement, PropsWithChildren<L0ItemRootProps>>(\n ({ item, parent, path, onMouseEnter, children }, forwardedRef) => {\n const { t } = useTranslation(meta.profile.key);\n const { model } = useNavTreeContext();\n const itemPath = useMemo(() => [...path, item.id], [item.id, path]);\n const { id, testId } = useAtomValue(model.itemProps(itemPath));\n const localizedString = toLocalizedString(item.properties.label, t);\n\n const type = l0ItemType(item);\n const handleClick = useL0ItemClick({ item, parent, path: itemPath }, type);\n\n return (\n <Tooltip.Trigger asChild delayDuration={0} side='right' content={localizedString}>\n <Tabs.TabPrimitive\n className={mx(\n 'group/l0item flex w-full justify-center items-center relative',\n 'dx-app-no-drag dx-focus-ring-group data[type!=\"collection\"]:cursor-pointer',\n l0Breakpoints[item.properties.l0Breakpoint],\n )}\n tabIndex={type === 'tab' ? 0 : undefined}\n data-type={type}\n data-testid={testId}\n data-object-id={id}\n value={item.id}\n onClick={handleClick}\n onMouseEnter={onMouseEnter}\n ref={forwardedRef}\n >\n {children}\n </Tabs.TabPrimitive>\n </Tooltip.Trigger>\n );\n },\n ),\n);\n\nexport const L0ItemActiveTabIndicator = ({ classNames }: ThemedClassName<{}>) => (\n <div\n className={mx(\n 'hidden group-aria-selected/l0item:block absolute start-0 h-6 w-1.5 bg-accent-bg rounded-sm',\n classNames,\n )}\n />\n);\n\n// TODO(burdon): Factor out pinned (non-draggable) items.\nconst L0Item = memo(({ item, parent, path, pinned, onRearrange, onItemHover }: L0ItemProps) => {\n const { t } = useTranslation(meta.profile.key);\n const itemElement = useRef<HTMLButtonElement | null>(null);\n const [closestEdge, setEdge] = useState<Edge | null>(null);\n const localizedString = toLocalizedString(item.properties.label, t);\n const hue = item.properties.hue ?? null;\n\n useLayoutEffect(() => {\n if (!itemElement.current || !onRearrange) {\n return;\n }\n\n return combine(\n draggable({\n element: itemElement.current,\n getInitialData: () => ({ id: item.id, type: 'l0Item' }) satisfies L0ItemData,\n onGenerateDragPreview: ({ nativeSetDragImage, source, location }) => {\n document.body.setAttribute('data-drag-preview', 'true');\n const element = source.element.querySelector('[data-frame]') as HTMLElement;\n scrollJustEnoughIntoView({ element });\n const { x, y } = preserveOffsetOnSource({ element, input: location.current.input })({\n container: (element.offsetParent ?? document.body) as HTMLElement,\n });\n nativeSetDragImage?.(element, x, y);\n },\n onDragStart: () => {\n document.body.removeAttribute('data-drag-preview');\n itemElement.current!.closest('[data-drag-autoscroll]')?.setAttribute('data-drag-autoscroll', 'active');\n },\n onDrop: () => {\n itemElement.current!.closest('[data-drag-autoscroll]')?.setAttribute('data-drag-autoscroll', 'idle');\n },\n }),\n dropTargetForElements({\n element: itemElement.current,\n getData: ({ input, element }) => {\n return attachClosestEdge(\n { id: item.id, type: 'l0Item' },\n { input, element, allowedEdges: ['top', 'bottom'] },\n );\n },\n onDragEnter: ({ self, source }) => {\n if (source.data.type === self.data.type) {\n setEdge(extractClosestEdge(self.data));\n }\n },\n onDrag: ({ self, source }) => {\n if (source.data.type === self.data.type) {\n setEdge(extractClosestEdge(self.data));\n }\n },\n onDragLeave: () => setEdge(null),\n onDrop: ({ self, source }) => {\n setEdge(null);\n if (source.data.type === self.data.type) {\n onRearrange(source.data as L0ItemData, self.data as L0ItemData, extractClosestEdge(self.data));\n }\n },\n }),\n );\n }, [item, onRearrange]);\n\n const handleMouseEnter = useCallback(() => onItemHover?.({ item }), [item, onItemHover]);\n\n return (\n <L0ItemRoot ref={itemElement} item={item} parent={parent} path={path} onMouseEnter={handleMouseEnter}>\n <div\n data-frame={true}\n {...(hue && { style: { background: `var(--color-${hue}-surface)` } })}\n className={mx(\n 'flex justify-center items-center dx-focus-ring-group-indicator transition-colors rounded-sm',\n pinned\n ? 'p-2 group-hover/l0item:bg-current-surface'\n : 'w-(--dx-l0-avatar-size) h-(--dx-l0-avatar-size) bg-current-surface',\n )}\n >\n <ItemAvatar item={item} />\n </div>\n <L0ItemActiveTabIndicator />\n <span id={`${item.id}__label`} className='sr-only'>\n {localizedString}\n </span>\n {closestEdge && <DropIndicator edge={closestEdge} />}\n </L0ItemRoot>\n );\n});\n\nconst ItemAvatar = ({ item }: Pick<L0ItemProps, 'item'>) => {\n const { t } = useTranslation(meta.profile.key);\n\n // Actions.\n if (item.properties.icon) {\n const hue = item.properties.hue ?? null;\n const hueFgStyle = hue && { style: { color: `var(--color-${hue}-fg)` } };\n return <Icon icon={item.properties.icon} size={6} {...hueFgStyle} />;\n }\n\n const type = l0ItemType(item);\n if (type === 'tab' && item.properties.disposition !== 'pin-end') {\n const hue = item.properties.hue ?? null;\n const localizedString = toLocalizedString(item.properties.label, t);\n return <DxAvatar hue={hue} hueVariant='surface' variant='square' size={12} fallback={localizedString} />;\n }\n\n return null;\n};\n\n//\n// L0Menu\n//\n\nexport type L0MenuProps = {\n menuActions: MenuItem[];\n topLevelItems: Node.Node[];\n pinnedItems: Node.Node[];\n userAccountItem?: Node.Node;\n parent?: Node.Node;\n path: string[];\n onItemHover?: (params: { item: Node.Node }) => void;\n};\n\nexport const L0Menu = ({\n menuActions,\n topLevelItems,\n pinnedItems,\n userAccountItem,\n parent,\n path,\n onItemHover,\n}: L0MenuProps) => {\n const { t } = useTranslation(meta.profile.key);\n const runAction = useActionRunner();\n const handleAction = useCallback(\n (action: Node.Action, params: Node.InvokeProps) => {\n void runAction(action, params);\n },\n [runAction],\n );\n\n const handleRearrange = useCallback<StackItemRearrangeHandler<L0ItemData>>(\n (source, target, closestEdge) => {\n const sourceItem = topLevelItems.find((i) => i.id === source.id);\n if (!sourceItem?.properties.onRearrange) {\n return;\n }\n\n const sourceIndex = topLevelItems.findIndex((i) => i.id === source.id);\n const targetIndex = topLevelItems.findIndex((i) => i.id === target.id);\n const insertIndex =\n source.id === target.id\n ? sourceIndex\n : targetIndex +\n (sourceIndex < targetIndex ? (closestEdge === 'top' ? -1 : 0) : closestEdge === 'bottom' ? 1 : 0);\n const nextOrder = arrayMove([...topLevelItems], sourceIndex, insertIndex);\n return sourceItem.properties.onRearrange(nextOrder.map((item) => item.data));\n },\n [topLevelItems],\n );\n\n // Check if any items have onRearrange to enable drag-and-drop.\n const hasRearrangeableItems = topLevelItems.some((item) => item.properties.onRearrange);\n\n return (\n <Tabs.Tablist\n data-tauri-drag-region\n classNames={[\n 'group/l0 absolute z-[1] inset-y-0 start-0 rounded-is',\n 'grid grid-cols-[var(--dx-l0-size)] grid-rows-[var(--dx-rail-size)_1fr_min-content_var(--dx-l0-size)] dx-contain-layout',\n 'w-(--dx-l0-size) dx-l0-surface dx-app-drag pb-[env(safe-area-inset-bottom)]',\n '[body[data-platform=\"macos\"]_&]:pt-[30px]',\n '[body[data-platform=\"ios\"]_&]:pt-[max(env(safe-area-inset-top),0.25rem)]',\n ]}\n >\n {/* TODO(wittjosiah): Use L0Item trigger. */}\n <Menu.Root onAction={handleAction}>\n <Menu.Trigger asChild data-testid='spacePlugin.addSpace'>\n <div className='grid place-items-center'>\n <IconButton\n density='lg'\n variant='ghost'\n size={5}\n icon='ph--list--regular'\n iconOnly\n square\n label={t('app-menu.label')}\n />\n </div>\n </Menu.Trigger>\n <Menu.Content group={parent} items={menuActions} />\n </Menu.Root>\n\n {/* Space list. */}\n <ScrollArea.Root centered thin orientation='vertical'>\n <ScrollArea.Viewport classNames='flex flex-col gap-2 py-1'>\n {topLevelItems.map((item) => (\n <L0Item\n key={item.id}\n item={item}\n parent={parent}\n path={path}\n onItemHover={onItemHover}\n {...(hasRearrangeableItems && { onRearrange: handleRearrange })}\n />\n ))}\n </ScrollArea.Viewport>\n </ScrollArea.Root>\n\n {/* Actions. */}\n <div className='grid grid-cols-1 auto-rows-(--dx-rail-action) pt-2'>\n {pinnedItems.map((item) => (\n <L0Item key={item.id} item={item} parent={parent} path={path} pinned />\n ))}\n </div>\n\n {userAccountItem && (\n <div className='grid dx-app-no-drag'>\n <L0ItemRoot key={userAccountItem.id} item={userAccountItem} parent={parent} path={path}>\n <UserAccountAvatar\n userId={userAccountItem.properties.userId}\n hue={userAccountItem.properties.hue}\n emoji={userAccountItem.properties.emoji}\n status={userAccountItem.properties.status}\n size={10}\n />\n </L0ItemRoot>\n </div>\n )}\n </Tabs.Tablist>\n );\n};\n","//\n// Copyright 2023 DXOS.org\n//\n\nimport React, { useCallback } from 'react';\n\nimport { type Node } from '@dxos/app-graph';\nimport { useActionRunner } from '@dxos/plugin-graph/hooks';\nimport { IconButton, toLocalizedString, useDensityContext, useTranslation } from '@dxos/react-ui';\nimport { composable, composableProps } from '@dxos/react-ui';\nimport { Menu, type MenuItem } from '@dxos/react-ui-menu';\nimport { hoverableControlItem, hoverableOpenControlItem } from '@dxos/ui-theme';\n\nimport { meta } from '#meta';\nimport { type ActionProperties } from '#types';\n\nconst fallbackIcon = 'ph--circle-dashed--regular';\n\nconst mdActionButtonProps = {\n size: 4 as const,\n density: 'md' as const,\n};\n\nconst lgActionButtonProps = {\n size: 5 as const,\n density: 'lg' as const,\n};\n\nexport type NavTreeItemActionMenuProps = ActionProperties & {\n parent: Node.Node;\n path?: string[];\n caller?: string;\n monolithic?: boolean;\n menuActions?: Node.Action[];\n};\n\nexport const NavTreeItemActionDropdownMenu = composable<HTMLButtonElement, NavTreeItemActionMenuProps>(\n ({ parent, path, label, icon, testId, menuActions, caller, ...props }, forwardedRef) => {\n const { t } = useTranslation(meta.profile.key);\n const density = useDensityContext();\n const runAction = useActionRunner();\n const handleAction = useCallback(\n (action: Node.Action, params: Node.InvokeProps = {}) => runAction(action, { ...params, path }),\n [runAction, path],\n );\n\n return (\n <Menu.Root caller={caller} onAction={handleAction}>\n <Menu.Trigger asChild>\n <IconButton\n {...(density === 'lg' ? lgActionButtonProps : mdActionButtonProps)}\n {...composableProps(props)}\n classNames={['shrink-0 px-2 pointer-fine:px-1', hoverableControlItem, hoverableOpenControlItem]}\n variant='ghost'\n icon={icon ?? fallbackIcon}\n iconOnly\n label={toLocalizedString(label, t)}\n data-testid={testId}\n ref={forwardedRef}\n />\n </Menu.Trigger>\n <Menu.Content group={parent} items={menuActions as MenuItem[]} />\n </Menu.Root>\n );\n },\n);\n\nNavTreeItemActionDropdownMenu.displayName = 'NavTreeItemActionDropdownMenu';\n\nexport const NavTreeItemMonolithicAction = (\n props: Node.Action & {\n parent: Node.Node;\n path?: string[];\n onAction?: (action: Node.Action) => void;\n baseLabel: string;\n },\n) => {\n const {\n parent,\n path,\n properties: { disabled, caller, testId, icon, variant = 'ghost', iconOnly = true } = { label: 'never' },\n baseLabel,\n } = props;\n const density = useDensityContext();\n const runAction = useActionRunner();\n return (\n <IconButton\n {...(density === 'lg' ? lgActionButtonProps : mdActionButtonProps)}\n variant={variant}\n classNames={[\n 'shrink-0',\n hoverableControlItem,\n hoverableOpenControlItem,\n iconOnly ? 'px-2 pointer-fine:px-1' : 'p-2 pointer-fine:p-2 me-1',\n ]}\n icon={icon ?? fallbackIcon}\n iconOnly={iconOnly}\n label={baseLabel}\n disabled={disabled}\n onClick={(event) => {\n event.stopPropagation();\n if (disabled) {\n return;\n }\n\n void runAction(props, caller ? { parent, caller, path } : { parent, path });\n }}\n data-testid={testId}\n />\n );\n};\n\nexport const NavTreeItemAction = ({\n monolithic,\n menuActions,\n menuType,\n parent,\n path,\n ...props\n}: NavTreeItemActionMenuProps) => {\n const { t } = useTranslation(meta.profile.key);\n\n const monolithicAction = menuActions?.length === 1 && menuActions[0];\n const baseLabel = toLocalizedString(monolithicAction ? monolithicAction.properties!.label : props.label, t);\n return monolithic && menuActions?.length === 1 ? (\n <NavTreeItemMonolithicAction baseLabel={baseLabel} parent={parent} path={path} {...menuActions[0]} />\n ) : (\n <NavTreeItemActionDropdownMenu {...props} label={baseLabel} parent={parent} path={path} menuActions={menuActions} />\n );\n};\n","//\n// Copyright 2025 DXOS.org\n//\n\nimport React, { Fragment, memo, useMemo } from 'react';\n\nimport { Popover, toLocalizedString, useTranslation } from '@dxos/react-ui';\nimport { Treegrid } from '@dxos/react-ui-list';\n\nimport { getListActions, useActions } from '#hooks';\nimport { meta } from '#meta';\n\nimport { NAV_TREE_ITEM } from '../NavTree';\nimport { useNavTreeContext } from '../NavTreeContext';\nimport { type NavTreeItemColumnsProps } from '../types';\nimport { NavTreeItemActionDropdownMenu, NavTreeItemMonolithicAction } from './NavTreeItemAction';\n\nexport const NavTreeItemColumns = memo(({ path, item, open }: NavTreeItemColumnsProps) => {\n const { t } = useTranslation(meta.profile.key);\n const { renderItemEnd: ItemEnd, popoverAnchorId } = useNavTreeContext();\n\n const level = path.length - 2;\n const flattenedActions = useActions(item);\n const allActions = useMemo(() => getListActions(flattenedActions), [flattenedActions]);\n\n const anchored = popoverAnchorId === `${NAV_TREE_ITEM}:${item.id}`;\n const ActionRoot = anchored ? Popover.Anchor : Fragment;\n\n return (\n // `data-popover-anchor` lets the enclosing row highlight itself while a popover (e.g. rename) is open on it.\n <div className='contents dx-app-no-drag' {...(anchored && { 'data-popover-anchor': '' })}>\n <ActionRoot>\n {allActions.length === 1 ? (\n <Treegrid.Cell classNames='contents'>\n <NavTreeItemMonolithicAction\n baseLabel={toLocalizedString(allActions[0].properties?.label, t)}\n parent={item}\n path={path}\n {...allActions[0]}\n />\n </Treegrid.Cell>\n ) : allActions.length > 1 ? (\n <Treegrid.Cell classNames='contents'>\n <NavTreeItemActionDropdownMenu\n testId={`navtree.treeItem.actionsLevel${level}`}\n label={t('tree-item-actions.label')}\n icon='ph--dots-three-vertical--regular'\n parent={item}\n path={path}\n menuActions={allActions}\n caller={NAV_TREE_ITEM}\n />\n </Treegrid.Cell>\n ) : (\n <Treegrid.Cell />\n )}\n </ActionRoot>\n {ItemEnd && (\n <Treegrid.Cell classNames='contents'>\n <ItemEnd node={item} open={open} />\n </Treegrid.Cell>\n )}\n </div>\n );\n});\n","//\n// Copyright 2025 DXOS.org\n//\n\nimport * as Option from 'effect/Option';\nimport React, { memo, useCallback, useMemo } from 'react';\n\nimport { Node } from '@dxos/app-graph';\nimport { GraphPath } from '@dxos/app-toolkit';\nimport { useAppGraph } from '@dxos/app-toolkit/ui';\nimport { Graph } from '@dxos/plugin-graph';\nimport { useActionRunner, useEdges } from '@dxos/plugin-graph/hooks';\nimport { DensityProvider, IconButton, ScrollArea, toLocalizedString, useTranslation } from '@dxos/react-ui';\nimport { Empty, Tree } from '@dxos/react-ui-list';\nimport { Menu, type MenuItem } from '@dxos/react-ui-menu';\nimport { Tabs } from '@dxos/react-ui-tabs';\nimport { hoverableControlItem, hoverableOpenControlItem } from '@dxos/ui-theme';\n\nimport { getListActions, useActions, useLoadDescendents } from '#hooks';\nimport { meta } from '#meta';\n\nimport { NAV_TREE_ITEM } from '../NavTree';\nimport { useNavTreeContext } from '../NavTreeContext';\nimport { NavTreeItemColumns } from '../NavTreeItem/NavTreeItemColumns';\n\n/**\n * Delay before the unavailable-workspace message appears: a workspace whose space is still loading has\n * no graph node yet and materializes into a real panel on its own, so it must not flash during that window.\n */\nconst RENDER_DELAY = '1s';\n\nexport type L1PanelProps = {\n open?: boolean;\n path: string[];\n /** The tab's workspace id, which may name a workspace that has no graph node. */\n id: string;\n /** Absent when the workspace is not in the graph; the panel then renders the unavailable message. */\n item?: Node.Node;\n isCurrent: boolean;\n onBack?: () => void;\n};\n\n/**\n * Space or settings panel. Without an `item` — a link to a workspace this identity never had or which no\n * longer exists, or persisted deck state pointing at one after a profile switch — the panel body is the\n * unavailable-workspace message, so the sidebar is never blank.\n */\nconst L1PanelInner = ({ open, path, id, item, isCurrent, onBack }: L1PanelProps) => {\n const { t } = useTranslation(meta.profile.key);\n const title = item ? toLocalizedString(item.properties.label, t) : t('workspace-unavailable.heading');\n const isActivated = useIsActivatedWorkspace(id);\n const shouldRenderContent = isCurrent || isActivated;\n\n return (\n <Tabs.Panel\n key={id}\n value={id}\n classNames={[\n 'absolute inset-y-0 end-0',\n 'w-[calc(100%-var(--dx-l0-size))] lg:w-(--dx-l1-size) grid-cols-1 grid-rows-[var(--dx-rail-size)_1fr]',\n 'py-[env(safe-area-inset-top)]',\n isCurrent && 'grid',\n ]}\n tabIndex={-1}\n aria-label={title}\n // An unavailable workspace has no tab in the rail, so the generated `aria-labelledby` would\n // reference a missing element.\n {...(!item && { 'aria-labelledby': undefined })}\n {...(isCurrent && {\n 'data-testid': item ? 'navtree.workspace.visible' : 'navtree.workspace.unavailable',\n })}\n {...(!open && { inert: true })}\n >\n {shouldRenderContent &&\n (item ? (\n <L1PanelContent open={open} path={path} item={item} onBack={onBack} />\n ) : (\n <Empty\n label={t('workspace-unavailable.description')}\n // Second grid row, so the message clears the rail exactly as the tree does, and hugging its\n // top rather than stretching to the row's full height.\n classNames='row-start-2 self-start animate-fade-in'\n style={{ animationDelay: RENDER_DELAY, animationFillMode: 'backwards' }}\n />\n ))}\n </Tabs.Panel>\n );\n};\n\n/** Determines whether a workspace tab has been populated with real child content (i.e. expanded at least once). */\nconst useIsActivatedWorkspace = (id: string): boolean => {\n const { graph } = useAppGraph();\n const edges = useEdges(graph, id);\n\n return useMemo(() => {\n const childIds = edges[Graph.relationKey('child')] ?? [];\n return childIds.some((childId) => {\n const child = Graph.getNode(graph, childId);\n if (Option.isNone(child)) {\n return false;\n }\n return child.value.properties.disposition === undefined;\n });\n }, [edges, graph]);\n};\n\n/**\n * Mounted panel content for active or previously-visited tabs.\n */\nconst L1PanelContent = ({\n path,\n item,\n onBack,\n}: Pick<L1PanelProps, 'open' | 'path' | 'onBack'> & { item: Node.Node }) => {\n const navTreeContext = useNavTreeContext();\n\n return (\n <DensityProvider density='md'>\n <L1PanelHeader path={path} item={item} onBack={onBack} />\n <ScrollArea.Root centered thin orientation='vertical'>\n <ScrollArea.Viewport>\n <Tree\n classNames='pt-[2px]'\n model={navTreeContext.model}\n id={item.id}\n rootId={item.id}\n path={path}\n levelOffset={5}\n draggable\n gridTemplateColumns='[tree-row-start] minmax(0, 1fr) min-content min-content [tree-row-end]'\n renderColumns={NavTreeItemColumns}\n blockInstruction={navTreeContext.blockInstruction}\n canDrop={navTreeContext.canDrop}\n canSelect={navTreeContext.canSelect}\n onOpenChange={navTreeContext.onOpenChange}\n onSelect={navTreeContext.onSelect}\n onItemHover={navTreeContext.onItemHover}\n />\n </ScrollArea.Viewport>\n </ScrollArea.Root>\n </DensityProvider>\n );\n};\n\n/**\n * Header row.\n */\nconst L1PanelHeader = ({ item, path, onBack }: Pick<L1PanelProps, 'path' | 'onBack'> & { item: Node.Node }) => {\n const { t } = useTranslation(meta.profile.key);\n const { renderItemEnd: ItemEnd } = useNavTreeContext();\n const title = toLocalizedString(item.properties.label, t);\n const backCapableWorkspace = GraphPath.isPinnedWorkspace(item.id);\n\n const { menuActions, onAction } = useL1MenuActions({ item, path });\n useLoadDescendents(item);\n\n return (\n <div\n data-tauri-drag-region\n className='grid grid-cols-[28px_1fr_min-content_min-content] w-full items-center dx-app-drag dx-density-lg'\n >\n {backCapableWorkspace ? (\n <IconButton\n classNames={[hoverableControlItem, hoverableOpenControlItem]}\n variant='ghost'\n icon='ph--caret-left--regular'\n iconOnly\n size={4}\n label={t('button-back.button')}\n data-testid='treeView.primaryTreeButton'\n onClick={() => onBack?.()}\n />\n ) : (\n <div />\n )}\n <h2 data-tauri-drag-region className='flex-1 truncate min-w-0'>\n {title}\n </h2>\n <div className='contents dx-app-no-drag'>\n <MenuActions item={item} menuActions={menuActions} onAction={onAction} />\n {ItemEnd && <ItemEnd node={item} open />}\n </div>\n </div>\n );\n};\n\ntype L1MenuActions = {\n menuActions: Node.Action[];\n onAction: (action: Node.Action, params?: Node.InvokeProps) => void;\n};\n\n/**\n * Header menu actions for an L1 workspace tab. Renders nothing for an empty\n * `menuActions`, a single inline icon button for one action, and a\n * `…`-menu trigger for multiple.\n */\nconst MenuActions = ({\n item,\n menuActions,\n onAction,\n}: {\n item: Node.Node;\n} & Pick<L1MenuActions, 'menuActions' | 'onAction'>) => {\n const { t } = useTranslation(meta.profile.key);\n\n if (menuActions.length === 0) {\n return null;\n }\n\n if (menuActions.length === 1) {\n return (\n <IconButton\n classNames={['shrink-0 px-2 pointer-fine:px-1', hoverableControlItem, hoverableOpenControlItem]}\n variant='ghost'\n icon={menuActions[0].properties?.icon ?? 'ph--circle-dashed--regular'}\n iconOnly\n size={4}\n label={toLocalizedString(menuActions[0].properties?.label, t)}\n data-testid={menuActions[0].properties?.testId}\n onClick={() => onAction(menuActions[0] as Node.Action)}\n />\n );\n }\n\n return (\n <Menu.Root caller={NAV_TREE_ITEM} onAction={onAction}>\n <Menu.Trigger asChild>\n <IconButton\n classNames={['shrink-0 px-2 pointer-fine:px-1', hoverableControlItem, hoverableOpenControlItem]}\n variant='ghost'\n icon='ph--dots-three-vertical--regular'\n iconOnly\n size={4}\n label={t('tree-item-actions.label')}\n data-testid='navtree.treeItem.actionsLevel0'\n />\n </Menu.Trigger>\n <Menu.Content group={item} items={menuActions as MenuItem[]} />\n </Menu.Root>\n );\n};\n\n/**\n * Builds the menu actions for the L1 panel header.\n */\nconst useL1MenuActions = ({ item, path }: Pick<L1PanelProps, 'path'> & { item: Node.Node }): L1MenuActions => {\n const runAction = useActionRunner();\n\n const menuActions = getListActions(useActions(item));\n\n const onAction = useCallback(\n (action: Node.Action, params?: Node.InvokeProps) => {\n void runAction(action, { ...params, path });\n },\n [runAction, path],\n );\n\n return { menuActions, onAction };\n};\n\nexport const L1Panel = memo(L1PanelInner);\n","//\n// Copyright 2025 DXOS.org\n//\n\nimport React from 'react';\n\nimport { type Node } from '@dxos/app-graph';\n\nimport { l0ItemType } from '../../util';\nimport { L1Panel, type L1PanelProps } from './L1Panel';\n\nexport type L1TabsProps = Pick<L1PanelProps, 'open' | 'onBack'> & {\n currentItemId: string;\n path: string[];\n topLevelItems: Node.Node[];\n};\n\n/**\n * Each workspace is an L1 tab.\n */\nexport const L1Tabs = ({ topLevelItems, currentItemId, onBack, open, path }: L1TabsProps) => {\n // The current tab can name a workspace that is not in the graph, in which case it gets an item-less\n // panel carrying the unavailable message rather than no panel at all (a blank sidebar).\n const hasCurrentPanel = topLevelItems.some((item) => item.id === currentItemId && l0ItemType(item) === 'tab');\n\n return (\n <>\n {topLevelItems.map((item) => {\n const type = l0ItemType(item);\n if (type === 'tab') {\n return (\n <L1Panel\n key={item.id}\n id={item.id}\n item={item}\n path={path}\n open={open}\n onBack={onBack}\n isCurrent={item.id === currentItemId}\n />\n );\n }\n return null;\n })}\n {!hasCurrentPanel && <L1Panel key={currentItemId} id={currentItemId} path={path} open={open} isCurrent />}\n </>\n );\n};\n","//\n// Copyright 2024 DXOS.org\n//\n\nimport React, { forwardRef, useMemo } from 'react';\n\nimport { useAppGraph } from '@dxos/app-toolkit/ui';\nimport { Node } from '@dxos/plugin-graph';\nimport { useConnections, useActions as useGraphActions } from '@dxos/plugin-graph/hooks';\nimport { type MenuItem } from '@dxos/react-ui-menu';\nimport { Tabs } from '@dxos/react-ui-tabs';\nimport { Position } from '@dxos/util';\n\nimport { useLoadDescendents } from '#hooks';\n\nimport { useNavTreeContext } from '../NavTreeContext';\nimport { L0Menu, L1Tabs, type L1TabsProps } from '../Sidebar';\n\nexport const NAV_TREE_ITEM = 'NavTreeItem';\n\nexport type NavTreeProps = { id: string; root?: Node.Node; tab: string } & Pick<L1TabsProps, 'open'>;\n\n// TODO(wittjosiah): Refactor to Radix-style.\nexport const NavTree = forwardRef<HTMLDivElement, NavTreeProps>(({ id, root, tab, ...props }, forwardedRef) => {\n const { onBack, onItemHover } = useNavTreeContext();\n const { topLevelActions, l0Items, pinnedItems, userAccountItem, topLevelItems } = useTopLevelNavItems(root);\n\n useLoadDescendents(root);\n const path = useMemo(() => [id], [id]);\n\n return (\n // TODO(thure): `Tabs.Root` forces all items that should be able to receive focus to use `Tabs.Tab(Primitive)` since\n // it uses RovingFocus and doesn't support moving focus to an item that is not a tab. Assess whether this situation\n // should change including whether it should motivate a change in the design/taxonomy, or if this means this should\n // not use `react-ui-tabs` at all.\n <Tabs.Root value={tab} orientation='vertical' classNames='relative' ref={forwardedRef}>\n <L0Menu\n menuActions={topLevelActions as MenuItem[]}\n topLevelItems={l0Items}\n pinnedItems={pinnedItems}\n userAccountItem={userAccountItem}\n path={path}\n parent={root}\n onItemHover={onItemHover}\n />\n <L1Tabs topLevelItems={topLevelItems} path={path} currentItemId={tab} onBack={onBack} {...props} />\n </Tabs.Root>\n );\n});\n\n/**\n * Partitions root children into workspaces, pinned items, user-account, and top-level actions.\n */\nconst useTopLevelNavItems = (root?: Node.Node) => {\n const { graph } = useAppGraph();\n const rootId = root?.id ?? Node.RootId;\n const rootOutboundItems = useConnections(graph, rootId, 'child');\n const rootActions = useGraphActions(graph, rootId);\n\n const { topLevelActions, l0Items, pinnedItems, userAccountItem } = useMemo(() => {\n const topLevelWorkspaces: Node.Node[] = [];\n const outboundPinnedItems: Node.Node[] = [];\n let userAccountItem: Node.Node | undefined;\n for (const node of rootOutboundItems) {\n if (Node.hasDisposition(node, 'workspace')) {\n topLevelWorkspaces.push(node);\n } else if (Node.hasDisposition(node, 'pin-end')) {\n outboundPinnedItems.push(node);\n } else if (Node.hasDisposition(node, 'user-account')) {\n userAccountItem ??= node;\n }\n }\n\n const topLevelActions = rootActions\n .filter((action) => Node.hasDisposition(action, 'menu'))\n .toSorted((a, b) => Position.compare(a.properties, b.properties));\n const pinnedItems = [\n ...outboundPinnedItems,\n ...rootActions.filter((action) => Node.hasDisposition(action, 'pin-end')),\n ].toSorted((a, b) => Position.compare(a.properties, b.properties));\n\n return {\n pinnedItems,\n topLevelActions,\n userAccountItem,\n l0Items: topLevelWorkspaces,\n };\n }, [rootActions, rootOutboundItems]);\n\n const topLevelItems = useMemo(\n () => [...l0Items, ...pinnedItems, ...(userAccountItem ? [userAccountItem] : [])],\n [l0Items, pinnedItems, userAccountItem],\n );\n\n return { topLevelActions, l0Items, pinnedItems, userAccountItem, topLevelItems };\n};\n"],"mappings":"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"}
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
import { i as __exportAll } from "./chunk-types.mjs";
|
|
2
|
+
import { o as resolveMigrationOperation, r as getParent, t as filterItems } from "./chunk-util.mjs";
|
|
3
|
+
import { arrayMove } from "@dxos/util";
|
|
4
|
+
import { meta } from "#meta";
|
|
5
|
+
import { LayoutOperation } from "@dxos/app-toolkit";
|
|
6
|
+
import { Graph, Node } from "@dxos/plugin-graph";
|
|
7
|
+
import { forwardRef, lazy, memo, useCallback, useEffect, useMemo, useRef } from "react";
|
|
8
|
+
import { AppSurface, useAppGraph, useLayout } from "@dxos/app-toolkit/ui";
|
|
9
|
+
import { useActionRunner } from "@dxos/plugin-graph/hooks";
|
|
10
|
+
import { useNavTreeModel, useNavTreeState } from "#hooks";
|
|
11
|
+
import { monitorForElements } from "@atlaskit/pragmatic-drag-and-drop/element/adapter";
|
|
12
|
+
import { useAtomValue } from "@effect-atom/atom-react";
|
|
13
|
+
import { useMediaQuery, useSidebars } from "@dxos/react-ui";
|
|
14
|
+
import { isTreeData } from "@dxos/react-ui-list";
|
|
15
|
+
import { jsx } from "react/jsx-runtime";
|
|
16
|
+
import { extractInstruction } from "@atlaskit/pragmatic-drag-and-drop-hitbox/tree-item";
|
|
17
|
+
import { Surface, useOperationInvoker } from "@dxos/app-framework/ui";
|
|
18
|
+
import { NAV_TREE_ITEM, NavTree, NavTreeContext } from "#components";
|
|
19
|
+
//#region src/containers/NavTreeContainer/NavTreeContainer.tsx
|
|
20
|
+
var NODE_TYPE = "dxos/app-graph/node";
|
|
21
|
+
var NavTreeItemEnd = ({ node, open }) => {
|
|
22
|
+
const data = useMemo(() => ({
|
|
23
|
+
id: node.id,
|
|
24
|
+
subject: node.data,
|
|
25
|
+
open
|
|
26
|
+
}), [
|
|
27
|
+
node.id,
|
|
28
|
+
node.data,
|
|
29
|
+
open
|
|
30
|
+
]);
|
|
31
|
+
return /* @__PURE__ */ jsx(Surface.Surface, {
|
|
32
|
+
type: AppSurface.NavtreeItemEnd,
|
|
33
|
+
data,
|
|
34
|
+
limit: 1
|
|
35
|
+
});
|
|
36
|
+
};
|
|
37
|
+
var getItems = (graph, node, disposition) => {
|
|
38
|
+
return Graph.getConnections(graph, node?.id ?? Node.RootId, "child").filter((node) => filterItems(node, disposition));
|
|
39
|
+
};
|
|
40
|
+
var NavTreeContainer$1 = memo(forwardRef(({ tab, popoverAnchorId }, forwardedRef) => {
|
|
41
|
+
const [isLg] = useMediaQuery("lg");
|
|
42
|
+
const { invokePromise } = useOperationInvoker();
|
|
43
|
+
const runAction = useActionRunner();
|
|
44
|
+
const { graph } = useAppGraph();
|
|
45
|
+
const { getItem, setItem } = useNavTreeState();
|
|
46
|
+
const layout = useLayout();
|
|
47
|
+
const model = useNavTreeModel(Node.RootId);
|
|
48
|
+
const { navigationSidebarState } = useSidebars(meta.profile.key);
|
|
49
|
+
const latestRef = useRef({
|
|
50
|
+
tab,
|
|
51
|
+
activeItems: layout.active,
|
|
52
|
+
navigationSidebarState,
|
|
53
|
+
isLg
|
|
54
|
+
});
|
|
55
|
+
useEffect(() => {
|
|
56
|
+
latestRef.current = {
|
|
57
|
+
tab,
|
|
58
|
+
activeItems: layout.active,
|
|
59
|
+
navigationSidebarState,
|
|
60
|
+
isLg
|
|
61
|
+
};
|
|
62
|
+
}, [
|
|
63
|
+
tab,
|
|
64
|
+
layout.active,
|
|
65
|
+
navigationSidebarState,
|
|
66
|
+
isLg
|
|
67
|
+
]);
|
|
68
|
+
const handleOpenChange = useCallback(({ item: { id }, path, open }) => {
|
|
69
|
+
setItem(path, "open", open);
|
|
70
|
+
Graph.expand(graph, id, "child");
|
|
71
|
+
}, [graph, setItem]);
|
|
72
|
+
const handleTabChange = useCallback((node) => {
|
|
73
|
+
Graph.expand(graph, node.id, "child");
|
|
74
|
+
const { tab: activeTab, activeItems, navigationSidebarState: currentSidebarState, isLg: latestIsLg } = latestRef.current;
|
|
75
|
+
invokePromise(LayoutOperation.UpdateSidebar, { state: node.id === activeTab ? currentSidebarState === "expanded" ? latestIsLg ? "collapsed" : "closed" : "expanded" : "expanded" });
|
|
76
|
+
invokePromise(LayoutOperation.SwitchWorkspace, { subject: node.id });
|
|
77
|
+
if (activeItems.length === 0) {
|
|
78
|
+
const [item] = getItems(graph, node).filter((node) => !Node.isActionLike(node));
|
|
79
|
+
if (item && item.data) invokePromise(LayoutOperation.Open, { subject: [item.id] });
|
|
80
|
+
}
|
|
81
|
+
}, [invokePromise, graph]);
|
|
82
|
+
const blockInstruction = useCallback(({ instruction, source, target }) => {
|
|
83
|
+
return target.item.properties.blockInstruction?.(source, instruction) ?? false;
|
|
84
|
+
}, []);
|
|
85
|
+
const canDrop = useCallback(({ source, target }) => {
|
|
86
|
+
return target.item.properties.canDrop?.(source) ?? false;
|
|
87
|
+
}, []);
|
|
88
|
+
const canSelect = useCallback(({ item }) => {
|
|
89
|
+
return item.properties.selectable ?? true;
|
|
90
|
+
}, []);
|
|
91
|
+
const handleSelect = useCallback(({ item: node, path, option, shift }) => {
|
|
92
|
+
if (!node.data) return;
|
|
93
|
+
if (Node.isAction(node)) {
|
|
94
|
+
const [parent] = Graph.getConnections(graph, node.id, Node.childRelation("inbound"));
|
|
95
|
+
if (parent) runAction(node, {
|
|
96
|
+
parent,
|
|
97
|
+
path,
|
|
98
|
+
caller: NAV_TREE_ITEM
|
|
99
|
+
});
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
if (!getItem(path).current) invokePromise(LayoutOperation.Open, {
|
|
103
|
+
subject: [node.id],
|
|
104
|
+
disposition: "solo",
|
|
105
|
+
modifiers: { shift }
|
|
106
|
+
});
|
|
107
|
+
else if (option) invokePromise(LayoutOperation.Close, { subject: [node.id] });
|
|
108
|
+
else invokePromise(LayoutOperation.ScrollIntoView, { subject: node.id });
|
|
109
|
+
const defaultAction = Graph.getActions(graph, node.id).find((action) => Node.hasDisposition(action, "default"));
|
|
110
|
+
if (Node.isAction(defaultAction)) runAction(defaultAction);
|
|
111
|
+
if (!isLg) invokePromise(LayoutOperation.UpdateSidebar, { state: "closed" });
|
|
112
|
+
}, [
|
|
113
|
+
graph,
|
|
114
|
+
invokePromise,
|
|
115
|
+
getItem,
|
|
116
|
+
runAction,
|
|
117
|
+
isLg
|
|
118
|
+
]);
|
|
119
|
+
const handleBack = useCallback(() => void invokePromise(LayoutOperation.RevertWorkspace), [invokePromise]);
|
|
120
|
+
useEffect(() => {
|
|
121
|
+
return monitorForElements({
|
|
122
|
+
canMonitor: ({ source }) => isTreeData(source.data),
|
|
123
|
+
onDrop: ({ location, source }) => {
|
|
124
|
+
if (!location.current.dropTargets.length) return;
|
|
125
|
+
const target = location.current.dropTargets[0];
|
|
126
|
+
const instruction = extractInstruction(target.data);
|
|
127
|
+
if (instruction !== null && instruction.type !== "instruction-blocked") {
|
|
128
|
+
const sourceNode = source.data.item;
|
|
129
|
+
const targetNode = target.data.item;
|
|
130
|
+
const sourcePath = source.data.path;
|
|
131
|
+
const targetPath = target.data.path;
|
|
132
|
+
const operation = sourcePath.slice(0, -1).join() === targetPath.slice(0, -1).join() && instruction.type !== "make-child" ? "rearrange" : resolveMigrationOperation(graph, sourceNode, targetPath, targetNode);
|
|
133
|
+
const sourceParent = getParent(graph, sourceNode, sourcePath);
|
|
134
|
+
const targetParent = getParent(graph, targetNode, targetPath);
|
|
135
|
+
const sourceItems = getItems(graph, sourceParent);
|
|
136
|
+
const targetItems = getItems(graph, targetParent);
|
|
137
|
+
const sourceIndex = sourceItems.findIndex(({ id }) => id === sourceNode.id);
|
|
138
|
+
const targetIndex = targetItems.findIndex(({ id }) => id === targetNode.id);
|
|
139
|
+
const migrationIndex = instruction.type === "make-child" ? void 0 : instruction.type === "reorder-below" ? targetIndex + 1 : targetIndex;
|
|
140
|
+
switch (operation) {
|
|
141
|
+
case "rearrange": {
|
|
142
|
+
const nextItems = sourceItems.map(({ data }) => data);
|
|
143
|
+
arrayMove(nextItems, sourceIndex, targetIndex);
|
|
144
|
+
sourceNode.properties.onRearrange?.(nextItems);
|
|
145
|
+
break;
|
|
146
|
+
}
|
|
147
|
+
case "copy":
|
|
148
|
+
(instruction.type === "make-child" ? targetNode : targetParent)?.properties.onCopy?.(sourceNode, migrationIndex);
|
|
149
|
+
break;
|
|
150
|
+
case "transfer": {
|
|
151
|
+
const target = instruction.type === "make-child" ? targetNode : targetParent;
|
|
152
|
+
if (!target?.properties.onTransferStart || target?.id === sourceParent?.id) break;
|
|
153
|
+
target?.properties.onTransferStart(sourceNode, migrationIndex);
|
|
154
|
+
sourceParent?.properties.onTransferEnd?.(sourceNode, target);
|
|
155
|
+
break;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
}, [graph]);
|
|
162
|
+
const workspaceChildren = useAtomValue(graph.connections(tab, "child"));
|
|
163
|
+
useEffect(() => {
|
|
164
|
+
for (const child of workspaceChildren) if (Node.hasDisposition(child, "group")) {
|
|
165
|
+
setItem([
|
|
166
|
+
Node.RootId,
|
|
167
|
+
tab,
|
|
168
|
+
child.id
|
|
169
|
+
], "open", true);
|
|
170
|
+
Graph.expand(graph, child.id, "child");
|
|
171
|
+
}
|
|
172
|
+
}, [
|
|
173
|
+
workspaceChildren,
|
|
174
|
+
tab,
|
|
175
|
+
setItem,
|
|
176
|
+
graph
|
|
177
|
+
]);
|
|
178
|
+
const onItemHover = useCallback(({ item }) => Graph.expand(graph, item.id, "child"), [graph]);
|
|
179
|
+
const navTreeContextValue = useMemo(() => ({
|
|
180
|
+
model,
|
|
181
|
+
popoverAnchorId,
|
|
182
|
+
renderItemEnd: NavTreeItemEnd,
|
|
183
|
+
blockInstruction,
|
|
184
|
+
canDrop,
|
|
185
|
+
canSelect,
|
|
186
|
+
onBack: handleBack,
|
|
187
|
+
onOpenChange: handleOpenChange,
|
|
188
|
+
onSelect: handleSelect,
|
|
189
|
+
onTabChange: handleTabChange,
|
|
190
|
+
onItemHover
|
|
191
|
+
}), [
|
|
192
|
+
model,
|
|
193
|
+
popoverAnchorId,
|
|
194
|
+
blockInstruction,
|
|
195
|
+
canDrop,
|
|
196
|
+
canSelect,
|
|
197
|
+
handleBack,
|
|
198
|
+
handleOpenChange,
|
|
199
|
+
handleSelect,
|
|
200
|
+
handleTabChange,
|
|
201
|
+
onItemHover
|
|
202
|
+
]);
|
|
203
|
+
return /* @__PURE__ */ jsx(NavTreeContext.Provider, {
|
|
204
|
+
value: navTreeContextValue,
|
|
205
|
+
children: /* @__PURE__ */ jsx(NavTree, {
|
|
206
|
+
id: Node.RootId,
|
|
207
|
+
root: Graph.getRoot(graph),
|
|
208
|
+
tab,
|
|
209
|
+
open: layout.sidebarOpen,
|
|
210
|
+
ref: forwardedRef
|
|
211
|
+
})
|
|
212
|
+
});
|
|
213
|
+
}));
|
|
214
|
+
NavTreeContainer$1.displayName = "NavTreeContainer";
|
|
215
|
+
//#endregion
|
|
216
|
+
//#region src/containers/NavTreeContainer/index.ts
|
|
217
|
+
var NavTreeContainer_exports = /* @__PURE__ */ __exportAll({
|
|
218
|
+
NODE_TYPE: () => NODE_TYPE,
|
|
219
|
+
NavTreeContainer: () => NavTreeContainer$1,
|
|
220
|
+
default: () => NavTreeContainer$1
|
|
221
|
+
});
|
|
222
|
+
//#endregion
|
|
223
|
+
//#region src/containers/index.ts
|
|
224
|
+
var CommandsDialogContent = lazy(() => import("./chunk-CommandsDialogContent.mjs"));
|
|
225
|
+
var CommandsTrigger = lazy(() => import("./chunk-CommandsTrigger.mjs"));
|
|
226
|
+
var NavTreeContainer = lazy(() => Promise.resolve().then(() => NavTreeContainer_exports));
|
|
227
|
+
var NavTreeDocumentTitle = lazy(() => import("./chunk-NavTreeDocumentTitle.mjs"));
|
|
228
|
+
//#endregion
|
|
229
|
+
export { CommandsDialogContent, CommandsTrigger, NODE_TYPE, NavTreeContainer, NavTreeDocumentTitle };
|
|
230
|
+
|
|
231
|
+
//# sourceMappingURL=containers.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"containers.mjs","names":[],"sources":["../../src/containers/NavTreeContainer/NavTreeContainer.tsx","../../src/containers/NavTreeContainer/index.ts","../../src/containers/index.ts"],"sourcesContent":["//\n// Copyright 2023 DXOS.org\n//\n\nimport { type Instruction, extractInstruction } from '@atlaskit/pragmatic-drag-and-drop-hitbox/tree-item';\nimport { monitorForElements } from '@atlaskit/pragmatic-drag-and-drop/element/adapter';\nimport { useAtomValue } from '@effect-atom/atom-react';\nimport React, { forwardRef, memo, useCallback, useEffect, useMemo, useRef } from 'react';\n\nimport { Surface, useOperationInvoker } from '@dxos/app-framework/ui';\nimport { LayoutOperation } from '@dxos/app-toolkit';\nimport { AppSurface, useAppGraph, useLayout } from '@dxos/app-toolkit/ui';\nimport { Graph, Node } from '@dxos/plugin-graph';\nimport { useActionRunner } from '@dxos/plugin-graph/hooks';\nimport { useMediaQuery, useSidebars } from '@dxos/react-ui';\nimport { type TreeData, isTreeData } from '@dxos/react-ui-list';\nimport { arrayMove } from '@dxos/util';\n\nimport { NAV_TREE_ITEM, NavTree, NavTreeContext } from '#components';\nimport { useNavTreeModel, useNavTreeState } from '#hooks';\nimport { meta } from '#meta';\nimport { type NavTreeItemGraphNode } from '#types';\n\nimport { filterItems, getParent, resolveMigrationOperation } from '../../util';\n\n// TODO(thure): Is NavTree truly authoritative in this regard?\nexport const NODE_TYPE = 'dxos/app-graph/node';\n\n// TODO(wittjosiah): Avoid using Surface within the navtree, prefer declarative data flow.\nconst NavTreeItemEnd = ({ node, open }: { node: Node.Node; open: boolean }) => {\n const data = useMemo(() => ({ id: node.id, subject: node.data, open }), [node.id, node.data, open]);\n return <Surface.Surface type={AppSurface.NavtreeItemEnd} data={data} limit={1} />;\n};\n\nconst getItems = (graph: Graph.ReadableGraph, node?: Node.Node, disposition?: string) => {\n return Graph.getConnections(graph, node?.id ?? Node.RootId, 'child').filter((node) => filterItems(node, disposition));\n};\n\nexport type NavTreeContainerProps = {\n popoverAnchorId?: string;\n tab: string;\n};\n\nexport const NavTreeContainer$ = forwardRef<HTMLDivElement, NavTreeContainerProps>(\n ({ tab, popoverAnchorId }, forwardedRef) => {\n const [isLg] = useMediaQuery('lg');\n const { invokePromise } = useOperationInvoker();\n const runAction = useActionRunner();\n const { graph } = useAppGraph();\n const { getItem, setItem } = useNavTreeState();\n const layout = useLayout();\n const model = useNavTreeModel(Node.RootId);\n const { navigationSidebarState } = useSidebars(meta.profile.key);\n const latestRef = useRef({\n tab,\n activeItems: layout.active,\n navigationSidebarState,\n isLg,\n });\n\n useEffect(() => {\n latestRef.current = {\n tab,\n activeItems: layout.active,\n navigationSidebarState,\n isLg,\n };\n }, [tab, layout.active, navigationSidebarState, isLg]);\n\n const handleOpenChange = useCallback(\n ({ item: { id }, path, open }: { item: Node.Node; path: string[]; open: boolean }) => {\n // TODO(thure): This might become a localstorage leak; openItemIds that no longer exist should be removed from this map.\n setItem(path, 'open', open);\n Graph.expand(graph, id, 'child');\n },\n [graph, setItem],\n );\n\n const handleTabChange = useCallback(\n (node: NavTreeItemGraphNode) => {\n Graph.expand(graph, node.id, 'child');\n\n const {\n tab: activeTab,\n activeItems,\n navigationSidebarState: currentSidebarState,\n isLg: latestIsLg,\n } = latestRef.current;\n void invokePromise(LayoutOperation.UpdateSidebar, {\n state:\n node.id === activeTab\n ? currentSidebarState === 'expanded'\n ? latestIsLg\n ? 'collapsed'\n : 'closed'\n : 'expanded'\n : 'expanded',\n });\n\n void invokePromise(LayoutOperation.SwitchWorkspace, { subject: node.id });\n\n // Open the first item if the workspace is empty.\n if (activeItems.length === 0) {\n const [item] = getItems(graph, node).filter((node) => !Node.isActionLike(node));\n if (item && item.data) {\n void invokePromise(LayoutOperation.Open, { subject: [item.id] });\n }\n }\n },\n [invokePromise, graph],\n );\n\n const blockInstruction = useCallback(\n ({ instruction, source, target }: { instruction: Instruction; source: TreeData; target: TreeData }) => {\n return target.item.properties.blockInstruction?.(source, instruction) ?? false;\n },\n [],\n );\n\n const canDrop = useCallback(({ source, target }: { source: TreeData; target: TreeData }) => {\n return target.item.properties.canDrop?.(source) ?? false;\n }, []);\n\n const canSelect = useCallback(({ item }: { item: Node.Node }) => {\n return item.properties.selectable ?? true;\n }, []);\n\n const handleSelect = useCallback(\n ({ item: node, path, option, shift }: { item: Node.Node; path: string[]; option: boolean; shift: boolean }) => {\n if (!node.data) {\n return;\n }\n\n if (Node.isAction(node)) {\n const [parent] = Graph.getConnections(graph, node.id, Node.childRelation('inbound'));\n if (parent) {\n void runAction(node, { parent, path, caller: NAV_TREE_ITEM });\n }\n return;\n }\n\n const current = getItem(path).current;\n if (!current) {\n // Plain click navigates (the deck becomes this item); shift forces a new plank (see the Open\n // handler, which upgrades any disposition to add when shift is held).\n void invokePromise(LayoutOperation.Open, {\n subject: [node.id],\n disposition: 'solo',\n modifiers: { shift },\n });\n } else if (option) {\n void invokePromise(LayoutOperation.Close, { subject: [node.id] });\n } else {\n void invokePromise(LayoutOperation.ScrollIntoView, { subject: node.id });\n }\n\n const defaultAction = Graph.getActions(graph, node.id).find((action) => Node.hasDisposition(action, 'default'));\n if (Node.isAction(defaultAction)) {\n void runAction(defaultAction);\n }\n\n if (!isLg) {\n void invokePromise(LayoutOperation.UpdateSidebar, { state: 'closed' });\n }\n },\n [graph, invokePromise, getItem, runAction, isLg],\n );\n\n const handleBack = useCallback(() => void invokePromise(LayoutOperation.RevertWorkspace), [invokePromise]);\n\n // TODO(wittjosiah): Factor out hook.\n useEffect(() => {\n return monitorForElements({\n canMonitor: ({ source }) => isTreeData(source.data),\n onDrop: ({ location, source }) => {\n // Didn't drop on anything.\n if (!location.current.dropTargets.length) {\n return;\n }\n const target = location.current.dropTargets[0];\n const instruction: Instruction | null = extractInstruction(target.data);\n if (instruction !== null && instruction.type !== 'instruction-blocked') {\n const sourceNode = source.data.item as NavTreeItemGraphNode;\n const targetNode = target.data.item as NavTreeItemGraphNode;\n const sourcePath = source.data.path as string[];\n const targetPath = target.data.path as string[];\n const sameParent = sourcePath.slice(0, -1).join() === targetPath.slice(0, -1).join();\n const operation =\n sameParent && instruction.type !== 'make-child'\n ? 'rearrange'\n : resolveMigrationOperation(graph, sourceNode, targetPath, targetNode);\n const sourceParent = getParent(graph, sourceNode, sourcePath);\n const targetParent = getParent(graph, targetNode, targetPath);\n const sourceItems = getItems(graph, sourceParent);\n const targetItems = getItems(graph, targetParent);\n const sourceIndex = sourceItems.findIndex(({ id }) => id === sourceNode.id);\n const targetIndex = targetItems.findIndex(({ id }) => id === targetNode.id);\n const migrationIndex =\n instruction.type === 'make-child'\n ? undefined\n : instruction.type === 'reorder-below'\n ? targetIndex + 1\n : targetIndex;\n switch (operation) {\n case 'rearrange': {\n const nextItems = sourceItems.map(({ data }) => data);\n arrayMove(nextItems, sourceIndex, targetIndex);\n void sourceNode.properties.onRearrange?.(nextItems);\n break;\n }\n case 'copy': {\n const target = instruction.type === 'make-child' ? targetNode : targetParent;\n void target?.properties.onCopy?.(sourceNode, migrationIndex);\n break;\n }\n case 'transfer': {\n const target = instruction.type === 'make-child' ? targetNode : targetParent;\n if (!target?.properties.onTransferStart || target?.id === sourceParent?.id) {\n break;\n }\n void target?.properties.onTransferStart(sourceNode, migrationIndex);\n void sourceParent?.properties.onTransferEnd?.(sourceNode, target);\n break;\n }\n }\n }\n },\n });\n }, [graph]);\n\n // Group nodes are always expanded and have no toggle, so they never trigger Graph.expand through\n // user interaction. Watch the workspace's children reactively and mark any group nodes as open\n // so the state machinery treats them consistently with regular open nodes (including on next load).\n const workspaceChildren = useAtomValue(graph.connections(tab, 'child'));\n useEffect(() => {\n for (const child of workspaceChildren) {\n if (Node.hasDisposition(child, 'group')) {\n setItem([Node.RootId, tab, child.id], 'open', true);\n Graph.expand(graph, child.id, 'child');\n }\n }\n }, [workspaceChildren, tab, setItem, graph]);\n\n const onItemHover = useCallback(({ item }: { item: Node.Node }) => Graph.expand(graph, item.id, 'child'), [graph]);\n\n const navTreeContextValue = useMemo(\n () => ({\n model,\n popoverAnchorId,\n renderItemEnd: NavTreeItemEnd,\n blockInstruction,\n canDrop,\n canSelect,\n onBack: handleBack,\n onOpenChange: handleOpenChange,\n onSelect: handleSelect,\n onTabChange: handleTabChange,\n onItemHover,\n }),\n [\n model,\n popoverAnchorId,\n blockInstruction,\n canDrop,\n canSelect,\n handleBack,\n handleOpenChange,\n handleSelect,\n handleTabChange,\n onItemHover,\n ],\n );\n\n return (\n <NavTreeContext.Provider value={navTreeContextValue}>\n <NavTree id={Node.RootId} root={Graph.getRoot(graph)} tab={tab} open={layout.sidebarOpen} ref={forwardedRef} />\n </NavTreeContext.Provider>\n );\n },\n);\n\nexport const NavTreeContainer = memo(NavTreeContainer$);\n\nNavTreeContainer.displayName = 'NavTreeContainer';\n","//\n// Copyright 2023 DXOS.org\n//\n\nexport { NavTreeContainer, NODE_TYPE } from './NavTreeContainer';\nexport { NavTreeContainer as default } from './NavTreeContainer';\n","//\n// Copyright 2023 DXOS.org\n//\n\nimport { type ComponentType, lazy } from 'react';\n\nexport { NODE_TYPE } from './NavTreeContainer';\n\nexport const CommandsDialogContent: ComponentType<any> = lazy(() => import('./CommandsDialogContent'));\nexport const CommandsTrigger: ComponentType<any> = lazy(() => import('./CommandsTrigger'));\nexport const NavTreeContainer: ComponentType<any> = lazy(() => import('./NavTreeContainer'));\nexport const NavTreeDocumentTitle: ComponentType<any> = lazy(() => import('./NavTreeDocumentTitle'));\n"],"mappings":"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"}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import { t as filterItems } from "./chunk-util.mjs";
|
|
2
|
+
import { Graph, Node } from "@dxos/plugin-graph";
|
|
3
|
+
import { NavTreeCapabilities } from "#types";
|
|
4
|
+
import { useEffect, useMemo } from "react";
|
|
5
|
+
import { useAppGraph } from "@dxos/app-toolkit/ui";
|
|
6
|
+
import { useActions as useActions$1 } from "@dxos/plugin-graph/hooks";
|
|
7
|
+
import { useAtomValue } from "@effect-atom/atom-react";
|
|
8
|
+
import { Path } from "@dxos/react-ui-list";
|
|
9
|
+
import { applyPresentation } from "@dxos/react-ui-menu";
|
|
10
|
+
import { mx } from "@dxos/ui-theme";
|
|
11
|
+
import * as Option from "effect/Option";
|
|
12
|
+
import { useCapability } from "@dxos/app-framework/ui";
|
|
13
|
+
import { Atom } from "@effect-atom/atom";
|
|
14
|
+
import { PLANK_COMPANION_TYPE } from "@dxos/plugin-deck";
|
|
15
|
+
//#region src/hooks/useActions.ts
|
|
16
|
+
/** Dispositions rendered as navtree item (row/header) actions, most-primary first. */
|
|
17
|
+
var LIST_ITEM_DISPOSITIONS = ["list-item-primary", "list-item"];
|
|
18
|
+
/**
|
|
19
|
+
* Flattens grouped actions and filters to the list-item dispositions rendered as
|
|
20
|
+
* navtree item actions. Shared by row (`NavTreeItemColumns`) and header (`L1Panel`)
|
|
21
|
+
* so both apply the same normalization rule. Applies each action's `presentation['list-item'
|
|
22
|
+
* | 'list-item-primary']` chrome override, if any, so an action multi-targeting the toolbar
|
|
23
|
+
* and the nav-tree can render appropriately in each.
|
|
24
|
+
*/
|
|
25
|
+
var getListActions = ({ actions, groupedActions }) => actions.flatMap((action) => Node.isAction(action) ? [action] : groupedActions[action.id] ?? []).filter((action) => Node.hasDisposition(action, LIST_ITEM_DISPOSITIONS)).map((action) => {
|
|
26
|
+
const surface = LIST_ITEM_DISPOSITIONS.find((disposition) => Node.hasDisposition(action, disposition));
|
|
27
|
+
return surface ? applyPresentation(action, surface) : action;
|
|
28
|
+
});
|
|
29
|
+
/** Returns flattened actions and grouped sub-actions for a given graph node. */
|
|
30
|
+
var useActions = (node) => {
|
|
31
|
+
const { graph } = useAppGraph();
|
|
32
|
+
const actions = useActions$1(graph, node.id);
|
|
33
|
+
return useMemo(() => {
|
|
34
|
+
return actions.reduce((acc, arg) => {
|
|
35
|
+
if (Node.hasDisposition(arg, "item")) return acc;
|
|
36
|
+
acc.actions.push(arg);
|
|
37
|
+
if (!Node.isAction(arg)) {
|
|
38
|
+
const actionGroup = Graph.getActions(graph, arg.id);
|
|
39
|
+
acc.groupedActions[arg.id] = actionGroup;
|
|
40
|
+
}
|
|
41
|
+
return acc;
|
|
42
|
+
}, {
|
|
43
|
+
actions: [],
|
|
44
|
+
groupedActions: {}
|
|
45
|
+
});
|
|
46
|
+
}, [actions]);
|
|
47
|
+
};
|
|
48
|
+
//#endregion
|
|
49
|
+
//#region src/hooks/useLoadDescendents.ts
|
|
50
|
+
/**
|
|
51
|
+
* Expands a root node in the app graph.
|
|
52
|
+
*/
|
|
53
|
+
var useLoadDescendents = (root) => {
|
|
54
|
+
const { graph } = useAppGraph();
|
|
55
|
+
useEffect(() => {
|
|
56
|
+
if (!root) return;
|
|
57
|
+
Graph.expand(graph, root.id, "child");
|
|
58
|
+
}, [graph, root]);
|
|
59
|
+
};
|
|
60
|
+
//#endregion
|
|
61
|
+
//#region src/hooks/useNavTreeState.ts
|
|
62
|
+
/**
|
|
63
|
+
* Hook that provides access to navtree state functions.
|
|
64
|
+
* For reactive subscriptions, use `useNavTreeItemState` or `useAtomValue(getItemAtom(path))`.
|
|
65
|
+
*/
|
|
66
|
+
var useNavTreeState = () => {
|
|
67
|
+
return useCapability(NavTreeCapabilities.State);
|
|
68
|
+
};
|
|
69
|
+
/**
|
|
70
|
+
* Hook that subscribes to a single navtree item's state.
|
|
71
|
+
* Use this for fine-grained reactivity.
|
|
72
|
+
*/
|
|
73
|
+
var useNavTreeItemState = (path) => {
|
|
74
|
+
const { getItemAtom } = useCapability(NavTreeCapabilities.State);
|
|
75
|
+
return useAtomValue(useMemo(() => getItemAtom(path), [getItemAtom, useMemo(() => path.join("~"), [path])]));
|
|
76
|
+
};
|
|
77
|
+
//#endregion
|
|
78
|
+
//#region src/hooks/useNavTreeModel.ts
|
|
79
|
+
var isVisibleChild = (node) => node.type !== PLANK_COMPANION_TYPE && node.properties.disposition !== "hidden";
|
|
80
|
+
/** Create an atom family for item display props keyed by path. */
|
|
81
|
+
var createItemPropsFamily = (graph) => Atom.family((pathKey) => {
|
|
82
|
+
const path = Path.parts(pathKey);
|
|
83
|
+
const id = Path.last(pathKey);
|
|
84
|
+
return Atom.make((get) => {
|
|
85
|
+
const nodeOpt = get(graph.node(id));
|
|
86
|
+
const node = Option.getOrElse(nodeOpt, () => void 0);
|
|
87
|
+
if (!node) return {
|
|
88
|
+
id,
|
|
89
|
+
label: id
|
|
90
|
+
};
|
|
91
|
+
const visibleChildren = get(graph.connections(node.id, "child")).filter((child) => !path.includes(child.id)).filter(isVisibleChild);
|
|
92
|
+
const parentOf = visibleChildren.length > 0 ? visibleChildren.map((child) => child.id) : node.properties.role === "branch" ? [] : void 0;
|
|
93
|
+
const parentId = path.length >= 2 ? path[path.length - 2] : void 0;
|
|
94
|
+
const parentNode = parentId ? Option.getOrElse(get(graph.node(parentId)), () => void 0) : void 0;
|
|
95
|
+
const droppable = node.properties.droppable === false || parentNode?.properties.childrenDroppable === false ? false : void 0;
|
|
96
|
+
const disposition = node.properties.disposition;
|
|
97
|
+
const isGroup = disposition === "group";
|
|
98
|
+
return {
|
|
99
|
+
id: node.id,
|
|
100
|
+
parentOf: isGroup ? void 0 : parentOf,
|
|
101
|
+
disposition,
|
|
102
|
+
disabled: isGroup || node.properties.disabled,
|
|
103
|
+
draggable: isGroup ? false : node.properties.draggable,
|
|
104
|
+
droppable: isGroup ? false : droppable,
|
|
105
|
+
label: node.properties.label ?? node.id,
|
|
106
|
+
className: mx(node.properties.className, node.properties.modified && "italic"),
|
|
107
|
+
headingClassName: node.properties.headingClassName,
|
|
108
|
+
icon: node.properties.icon,
|
|
109
|
+
iconHue: node.properties.iconHue,
|
|
110
|
+
testId: node.properties.testId,
|
|
111
|
+
count: node.properties.count,
|
|
112
|
+
modifiedCount: node.properties.modifiedCount
|
|
113
|
+
};
|
|
114
|
+
}).pipe(Atom.keepAlive);
|
|
115
|
+
});
|
|
116
|
+
/** Create an atom family for outbound child IDs keyed by parent ID (pre-sorted by position on write). */
|
|
117
|
+
var createChildIdsFamily = (graph) => Atom.family((id) => Atom.make((get) => get(graph.connections(id, "child")).map((child) => child.id)).pipe(Atom.keepAlive));
|
|
118
|
+
/** Create an atom family for item resolution keyed by ID. */
|
|
119
|
+
var createItemFamily = (graph) => Atom.family((id) => Atom.make((get) => {
|
|
120
|
+
const node = Option.getOrElse(get(graph.node(id)), () => void 0);
|
|
121
|
+
return node && filterItems(node) ? node : void 0;
|
|
122
|
+
}).pipe(Atom.keepAlive));
|
|
123
|
+
/** Create an atom family for open state keyed by path. */
|
|
124
|
+
var createItemOpenFamily = (getItemAtom) => Atom.family((pathKey) => {
|
|
125
|
+
const stateAtom = getItemAtom(Path.parts(pathKey));
|
|
126
|
+
return Atom.make((get) => get(stateAtom).open).pipe(Atom.keepAlive);
|
|
127
|
+
});
|
|
128
|
+
/** Create an atom family for current (selected) state keyed by path. */
|
|
129
|
+
var createItemCurrentFamily = (getItemAtom) => Atom.family((pathKey) => {
|
|
130
|
+
const stateAtom = getItemAtom(Path.parts(pathKey));
|
|
131
|
+
return Atom.make((get) => get(stateAtom).current).pipe(Atom.keepAlive);
|
|
132
|
+
});
|
|
133
|
+
/**
|
|
134
|
+
* Creates a TreeModel backed by the app graph and navtree state.
|
|
135
|
+
*/
|
|
136
|
+
var useNavTreeModel = (rootId) => {
|
|
137
|
+
const { graph } = useAppGraph();
|
|
138
|
+
const { getItemAtom } = useNavTreeState();
|
|
139
|
+
const itemPropsFamily = useMemo(() => createItemPropsFamily(graph), [graph]);
|
|
140
|
+
const childIdsFamily = useMemo(() => createChildIdsFamily(graph), [graph]);
|
|
141
|
+
const itemFamily = useMemo(() => createItemFamily(graph), [graph]);
|
|
142
|
+
const itemOpenFamily = useMemo(() => createItemOpenFamily(getItemAtom), [getItemAtom]);
|
|
143
|
+
const itemCurrentFamily = useMemo(() => createItemCurrentFamily(getItemAtom), [getItemAtom]);
|
|
144
|
+
return useMemo(() => ({
|
|
145
|
+
item: (id) => itemFamily(id),
|
|
146
|
+
itemProps: (path) => itemPropsFamily(Path.create(...path)),
|
|
147
|
+
itemOpen: (path) => itemOpenFamily(Path.create(...path)),
|
|
148
|
+
itemCurrent: (path) => itemCurrentFamily(Path.create(...path)),
|
|
149
|
+
childIds: (parentId) => childIdsFamily(parentId ?? rootId)
|
|
150
|
+
}), [
|
|
151
|
+
itemFamily,
|
|
152
|
+
itemPropsFamily,
|
|
153
|
+
itemOpenFamily,
|
|
154
|
+
itemCurrentFamily,
|
|
155
|
+
childIdsFamily,
|
|
156
|
+
rootId
|
|
157
|
+
]);
|
|
158
|
+
};
|
|
159
|
+
//#endregion
|
|
160
|
+
export { getListActions, useActions, useLoadDescendents, useNavTreeItemState, useNavTreeModel, useNavTreeState };
|
|
161
|
+
|
|
162
|
+
//# sourceMappingURL=hooks.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hooks.mjs","names":[],"sources":["../../src/hooks/useActions.ts","../../src/hooks/useLoadDescendents.ts","../../src/hooks/useNavTreeState.ts","../../src/hooks/useNavTreeModel.ts"],"sourcesContent":["//\n// Copyright 2025 DXOS.org\n//\n\nimport { useMemo } from 'react';\n\nimport { useAppGraph } from '@dxos/app-toolkit/ui';\nimport { Graph, Node } from '@dxos/plugin-graph';\nimport { useActions as useGraphActions } from '@dxos/plugin-graph/hooks';\nimport { applyPresentation } from '@dxos/react-ui-menu';\n\nimport { type FlattenedActions } from '#types';\n\n/** Dispositions rendered as navtree item (row/header) actions, most-primary first. */\nconst LIST_ITEM_DISPOSITIONS = ['list-item-primary', 'list-item'];\n\n/**\n * Flattens grouped actions and filters to the list-item dispositions rendered as\n * navtree item actions. Shared by row (`NavTreeItemColumns`) and header (`L1Panel`)\n * so both apply the same normalization rule. Applies each action's `presentation['list-item'\n * | 'list-item-primary']` chrome override, if any, so an action multi-targeting the toolbar\n * and the nav-tree can render appropriately in each.\n */\nexport const getListActions = ({ actions, groupedActions }: FlattenedActions): Node.Action[] =>\n actions\n .flatMap((action) => (Node.isAction(action) ? [action] : (groupedActions[action.id] ?? [])))\n .filter((action) => Node.hasDisposition(action, LIST_ITEM_DISPOSITIONS))\n .map((action) => {\n const surface = LIST_ITEM_DISPOSITIONS.find((disposition) => Node.hasDisposition(action, disposition));\n return surface ? applyPresentation(action, surface) : action;\n });\n\n/** Returns flattened actions and grouped sub-actions for a given graph node. */\nexport const useActions = (node: Node.Node): FlattenedActions => {\n const { graph } = useAppGraph();\n const actions = useGraphActions(graph, node.id);\n\n return useMemo(() => {\n return actions.reduce(\n (acc: FlattenedActions, arg) => {\n if (Node.hasDisposition(arg, 'item')) {\n return acc;\n }\n\n acc.actions.push(arg);\n if (!Node.isAction(arg)) {\n const actionGroup = Graph.getActions(graph, arg.id);\n acc.groupedActions[arg.id] = actionGroup;\n }\n return acc;\n },\n { actions: [], groupedActions: {} },\n );\n }, [actions]);\n};\n","//\n// Copyright 2025 DXOS.org\n//\n\nimport { useEffect } from 'react';\n\nimport { type Node } from '@dxos/app-graph';\nimport { useAppGraph } from '@dxos/app-toolkit/ui';\nimport { Graph } from '@dxos/plugin-graph';\n\n/**\n * Expands a root node in the app graph.\n */\nexport const useLoadDescendents = (root?: Node.Node) => {\n const { graph } = useAppGraph();\n useEffect(() => {\n if (!root) {\n return;\n }\n\n Graph.expand(graph, root.id, 'child');\n }, [graph, root]);\n};\n","//\n// Copyright 2025 DXOS.org\n//\n\nimport { type Atom, useAtomValue } from '@effect-atom/atom-react';\nimport { useMemo } from 'react';\n\nimport { useCapability } from '@dxos/app-framework/ui';\n\nimport { NavTreeCapabilities } from '#types';\n\nexport type UseNavTreeStateResult = {\n getItem: (path: string[]) => NavTreeCapabilities.NavTreeItemState;\n getItemAtom: (path: string[]) => Atom.Atom<NavTreeCapabilities.NavTreeItemState>;\n setItem: (path: string[], key: 'open' | 'current', next: boolean) => void;\n};\n\n/**\n * Hook that provides access to navtree state functions.\n * For reactive subscriptions, use `useNavTreeItemState` or `useAtomValue(getItemAtom(path))`.\n */\nexport const useNavTreeState = (): UseNavTreeStateResult => {\n return useCapability(NavTreeCapabilities.State);\n};\n\n/**\n * Hook that subscribes to a single navtree item's state.\n * Use this for fine-grained reactivity.\n */\nexport const useNavTreeItemState = (path: string[]): NavTreeCapabilities.NavTreeItemState => {\n const { getItemAtom } = useCapability(NavTreeCapabilities.State);\n const pathKey = useMemo(() => path.join('~'), [path]);\n const atom = useMemo(() => getItemAtom(path), [getItemAtom, pathKey]);\n return useAtomValue(atom);\n};\n","//\n// Copyright 2025 DXOS.org\n//\n\nimport { Atom } from '@effect-atom/atom';\nimport * as Option from 'effect/Option';\nimport { useMemo } from 'react';\n\nimport { useAppGraph } from '@dxos/app-toolkit/ui';\nimport { PLANK_COMPANION_TYPE } from '@dxos/plugin-deck';\nimport { type Node } from '@dxos/plugin-graph';\nimport { Path, type TreeModel } from '@dxos/react-ui-list';\nimport { mx } from '@dxos/ui-theme';\n\nimport { type NavTreeItemGraphNode } from '#types';\n\nimport { filterItems } from '../util';\nimport { useNavTreeState } from './useNavTreeState';\n\n// TODO(wittjosiah): Move companion/hidden nodes to their own edge categories so this filter is unnecessary.\nconst isVisibleChild = (node: Node.Node): boolean =>\n node.type !== PLANK_COMPANION_TYPE && node.properties.disposition !== 'hidden';\n\n/** Create an atom family for item display props keyed by path. */\nconst createItemPropsFamily = (graph: ReturnType<typeof useAppGraph>['graph']) =>\n Atom.family((pathKey: string) => {\n const path = Path.parts(pathKey);\n const id = Path.last(pathKey);\n return Atom.make((get) => {\n const nodeOpt = get(graph.node(id));\n const node = Option.getOrElse(nodeOpt, () => undefined);\n if (!node) {\n return { id, label: id };\n }\n const safeChildren = get(graph.connections(node.id, 'child')).filter((child) => !path.includes(child.id));\n const visibleChildren = safeChildren.filter(isVisibleChild);\n const parentOf =\n visibleChildren.length > 0\n ? visibleChildren.map((child) => child.id)\n : node.properties.role === 'branch'\n ? []\n : undefined;\n const parentId = path.length >= 2 ? path[path.length - 2] : undefined;\n const parentNode = parentId ? Option.getOrElse(get(graph.node(parentId)), () => undefined) : undefined;\n const droppable =\n node.properties.droppable === false || parentNode?.properties.childrenDroppable === false ? false : undefined;\n\n const disposition = node.properties.disposition as string | undefined;\n const isGroup = disposition === 'group';\n\n return {\n id: node.id,\n parentOf: isGroup ? undefined : parentOf,\n disposition,\n disabled: isGroup || node.properties.disabled,\n draggable: isGroup ? false : node.properties.draggable,\n droppable: isGroup ? false : droppable,\n label: node.properties.label ?? node.id,\n className: mx(node.properties.className, node.properties.modified && 'italic'),\n headingClassName: node.properties.headingClassName,\n icon: node.properties.icon,\n iconHue: node.properties.iconHue,\n testId: node.properties.testId,\n count: node.properties.count,\n modifiedCount: node.properties.modifiedCount,\n };\n }).pipe(Atom.keepAlive);\n });\n\n/** Create an atom family for outbound child IDs keyed by parent ID (pre-sorted by position on write). */\nconst createChildIdsFamily = (graph: ReturnType<typeof useAppGraph>['graph']) =>\n Atom.family((id: string) =>\n Atom.make((get) => get(graph.connections(id, 'child')).map((child) => child.id)).pipe(Atom.keepAlive),\n );\n\n/** Create an atom family for item resolution keyed by ID. */\nconst createItemFamily = (graph: ReturnType<typeof useAppGraph>['graph']) =>\n Atom.family((id: string) =>\n Atom.make((get) => {\n const node = Option.getOrElse(get(graph.node(id)), () => undefined);\n return node && filterItems(node) ? node : undefined;\n }).pipe(Atom.keepAlive),\n );\n\n/** Create an atom family for open state keyed by path. */\nconst createItemOpenFamily = (getItemAtom: ReturnType<typeof useNavTreeState>['getItemAtom']) =>\n Atom.family((pathKey: string) => {\n const path = Path.parts(pathKey);\n const stateAtom = getItemAtom(path);\n return Atom.make((get) => get(stateAtom).open).pipe(Atom.keepAlive);\n });\n\n/** Create an atom family for current (selected) state keyed by path. */\nconst createItemCurrentFamily = (getItemAtom: ReturnType<typeof useNavTreeState>['getItemAtom']) =>\n Atom.family((pathKey: string) => {\n const path = Path.parts(pathKey);\n const stateAtom = getItemAtom(path);\n return Atom.make((get) => get(stateAtom).current).pipe(Atom.keepAlive);\n });\n\n/**\n * Creates a TreeModel backed by the app graph and navtree state.\n */\nexport const useNavTreeModel = (rootId: string): TreeModel<NavTreeItemGraphNode> => {\n const { graph } = useAppGraph();\n const { getItemAtom } = useNavTreeState();\n\n const itemPropsFamily = useMemo(() => createItemPropsFamily(graph), [graph]);\n const childIdsFamily = useMemo(() => createChildIdsFamily(graph), [graph]);\n const itemFamily = useMemo(() => createItemFamily(graph), [graph]);\n const itemOpenFamily = useMemo(() => createItemOpenFamily(getItemAtom), [getItemAtom]);\n const itemCurrentFamily = useMemo(() => createItemCurrentFamily(getItemAtom), [getItemAtom]);\n\n return useMemo(\n () => ({\n item: (id: string) => itemFamily(id),\n itemProps: (path: string[]) => itemPropsFamily(Path.create(...path)),\n itemOpen: (path: string[]) => itemOpenFamily(Path.create(...path)),\n itemCurrent: (path: string[]) => itemCurrentFamily(Path.create(...path)),\n childIds: (parentId?: string) => childIdsFamily(parentId ?? rootId),\n }),\n [itemFamily, itemPropsFamily, itemOpenFamily, itemCurrentFamily, childIdsFamily, rootId],\n );\n};\n"],"mappings":"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"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { n as NavTreeCapabilities_exports, t as NavTreeEvents_exports } from "./chunk-types.mjs";
|
|
2
|
+
import { n as KEY_BINDING, r as meta, t as COMMANDS_DIALOG } from "./chunk-meta.mjs";
|
|
3
|
+
import { a as l0ItemType, i as getPersistenceParent, n as getChildren, o as resolveMigrationOperation, r as getParent, s as sortActions, t as filterItems } from "./chunk-util.mjs";
|
|
4
|
+
export { COMMANDS_DIALOG, KEY_BINDING, NavTreeCapabilities_exports as NavTreeCapabilities, NavTreeEvents_exports as NavTreeEvents, filterItems, getChildren, getParent, getPersistenceParent, l0ItemType, meta, resolveMigrationOperation, sortActions };
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { OperationHandlerSet } from "@dxos/compute";
|
|
2
|
+
//#region src/operations/index.ts
|
|
3
|
+
var NavTreeOperationHandlerSet = OperationHandlerSet.lazy(() => import("./chunk-expose.mjs"));
|
|
4
|
+
//#endregion
|
|
5
|
+
export { NavTreeOperationHandlerSet };
|
|
6
|
+
|
|
7
|
+
//# sourceMappingURL=operations.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"operations.mjs","names":[],"sources":["../../src/operations/index.ts"],"sourcesContent":["//\n// Copyright 2025 DXOS.org\n//\n\nimport { OperationHandlerSet } from '@dxos/compute';\n\nexport const NavTreeOperationHandlerSet = OperationHandlerSet.lazy(() => import('./expose'));\n"],"mappings":";;AAMA,IAAa,6BAA6B,oBAAoB,WAAW,OAAO,qBAAW"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { r as meta } from "./chunk-meta.mjs";
|
|
2
|
+
import { NavTreeOperationHandlerSet } from "./operations.mjs";
|
|
3
|
+
import { Plugin } from "@dxos/app-framework";
|
|
4
|
+
//#region src/plugin.ts
|
|
5
|
+
var NavTreePlugin = Plugin.lazy(meta, () => import("#plugin"));
|
|
6
|
+
//#endregion
|
|
7
|
+
export { NavTreeOperationHandlerSet, NavTreePlugin };
|
|
8
|
+
|
|
9
|
+
//# sourceMappingURL=plugin.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin.mjs","names":[],"sources":["../../src/plugin.ts"],"sourcesContent":["//\n// Copyright 2023 DXOS.org\n//\n\nimport { Plugin } from '@dxos/app-framework';\n\nimport { meta } from './meta';\n\nexport const NavTreePlugin = Plugin.lazy(meta, () => import('#plugin'));\n\nexport { NavTreeOperationHandlerSet } from './operations';\n"],"mappings":";;;;AAQA,IAAa,gBAAgB,OAAO,KAAK,YAAY,OAAO,UAAU"}
|