@dxos/plugin-explorer 0.9.1-main.c7dcc2e112 → 0.9.1-staging.ee54ba693a

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.
Files changed (151) hide show
  1. package/dist/lib/neutral/ExplorerArticle-2WPXYTXV.mjs +101 -0
  2. package/dist/lib/neutral/ExplorerArticle-2WPXYTXV.mjs.map +7 -0
  3. package/dist/lib/neutral/ExplorerPlugin.mjs +1 -1
  4. package/dist/lib/neutral/NeighborhoodCompanion-WC6E3YE6.mjs +90 -0
  5. package/dist/lib/neutral/NeighborhoodCompanion-WC6E3YE6.mjs.map +7 -0
  6. package/dist/lib/neutral/app-graph-builder-L2TJ6GNR.mjs +37 -0
  7. package/dist/lib/neutral/app-graph-builder-L2TJ6GNR.mjs.map +7 -0
  8. package/dist/lib/neutral/capabilities/index.mjs +4 -2
  9. package/dist/lib/neutral/capabilities/index.mjs.map +3 -3
  10. package/dist/lib/neutral/{chunk-JXYIG54N.mjs → chunk-4F6AT7RA.mjs} +4 -2
  11. package/dist/lib/neutral/chunk-4F6AT7RA.mjs.map +7 -0
  12. package/dist/lib/neutral/{chunk-7XUDLV6E.mjs → chunk-EZ52JY7X.mjs} +34 -31
  13. package/dist/lib/neutral/chunk-EZ52JY7X.mjs.map +7 -0
  14. package/dist/lib/neutral/{chunk-YBCHBVCJ.mjs → chunk-TTFPTHAQ.mjs} +8 -8
  15. package/dist/lib/neutral/chunk-TTFPTHAQ.mjs.map +7 -0
  16. package/dist/lib/neutral/components/index.mjs +430 -506
  17. package/dist/lib/neutral/components/index.mjs.map +4 -4
  18. package/dist/lib/neutral/containers/index.mjs +4 -2
  19. package/dist/lib/neutral/containers/index.mjs.map +3 -3
  20. package/dist/lib/neutral/{create-object-F6TKVAGV.mjs → create-object-WKIN3OB6.mjs} +3 -4
  21. package/dist/lib/neutral/{create-object-F6TKVAGV.mjs.map → create-object-WKIN3OB6.mjs.map} +3 -3
  22. package/dist/lib/neutral/hooks/index.mjs +64 -1
  23. package/dist/lib/neutral/hooks/index.mjs.map +4 -4
  24. package/dist/lib/neutral/index.mjs +1 -1
  25. package/dist/lib/neutral/meta.json +1 -1
  26. package/dist/lib/neutral/react-surface-EWPG5PUQ.mjs +39 -0
  27. package/dist/lib/neutral/react-surface-EWPG5PUQ.mjs.map +7 -0
  28. package/dist/lib/neutral/testing/index.mjs +2 -2
  29. package/dist/lib/neutral/testing/index.mjs.map +2 -2
  30. package/dist/lib/neutral/translations.mjs +4 -1
  31. package/dist/lib/neutral/translations.mjs.map +2 -2
  32. package/dist/lib/neutral/types/index.mjs +1 -1
  33. package/dist/types/src/ExplorerPlugin.d.ts.map +1 -1
  34. package/dist/types/src/capabilities/app-graph-builder.d.ts +9 -0
  35. package/dist/types/src/capabilities/app-graph-builder.d.ts.map +1 -0
  36. package/dist/types/src/capabilities/create-object.d.ts +1 -7
  37. package/dist/types/src/capabilities/create-object.d.ts.map +1 -1
  38. package/dist/types/src/capabilities/index.d.ts +1 -0
  39. package/dist/types/src/capabilities/index.d.ts.map +1 -1
  40. package/dist/types/src/capabilities/react-surface.d.ts +1 -1
  41. package/dist/types/src/components/Lattice/Lattice.d.ts +1 -1
  42. package/dist/types/src/components/Lattice/Lattice.d.ts.map +1 -1
  43. package/dist/types/src/components/Tree/EdgeBundling.stories.d.ts +1 -1
  44. package/dist/types/src/components/Tree/EdgeBundling.stories.d.ts.map +1 -1
  45. package/dist/types/src/components/Tree/Tree.stories.d.ts +1 -1
  46. package/dist/types/src/components/Tree/Tree.stories.d.ts.map +1 -1
  47. package/dist/types/src/components/Tree/index.d.ts +1 -3
  48. package/dist/types/src/components/Tree/index.d.ts.map +1 -1
  49. package/dist/types/src/components/Tree/types/tree.d.ts +10 -27
  50. package/dist/types/src/components/Tree/types/tree.d.ts.map +1 -1
  51. package/dist/types/src/components/Tree/types/types.d.ts +1 -10
  52. package/dist/types/src/components/Tree/types/types.d.ts.map +1 -1
  53. package/dist/types/src/components/Visualization/Visualization.d.ts +39 -0
  54. package/dist/types/src/components/Visualization/Visualization.d.ts.map +1 -0
  55. package/dist/types/src/components/Visualization/Visualization.stories.d.ts +13 -0
  56. package/dist/types/src/components/Visualization/Visualization.stories.d.ts.map +1 -0
  57. package/dist/types/src/components/Visualization/index.d.ts +3 -0
  58. package/dist/types/src/components/Visualization/index.d.ts.map +1 -0
  59. package/dist/types/src/components/Visualization/variants.d.ts +53 -0
  60. package/dist/types/src/components/Visualization/variants.d.ts.map +1 -0
  61. package/dist/types/src/components/index.d.ts +1 -0
  62. package/dist/types/src/components/index.d.ts.map +1 -1
  63. package/dist/types/src/containers/ExplorerArticle/ExplorerArticle.d.ts +1 -1
  64. package/dist/types/src/containers/ExplorerArticle/ExplorerArticle.d.ts.map +1 -1
  65. package/dist/types/src/containers/ExplorerArticle/ExplorerArticle.stories.d.ts +2 -2
  66. package/dist/types/src/containers/ExplorerArticle/ExplorerArticle.stories.d.ts.map +1 -1
  67. package/dist/types/src/containers/NeighborhoodCompanion/NeighborhoodCompanion.d.ts +14 -0
  68. package/dist/types/src/containers/NeighborhoodCompanion/NeighborhoodCompanion.d.ts.map +1 -0
  69. package/dist/types/src/containers/NeighborhoodCompanion/index.d.ts +2 -0
  70. package/dist/types/src/containers/NeighborhoodCompanion/index.d.ts.map +1 -0
  71. package/dist/types/src/containers/index.d.ts +1 -0
  72. package/dist/types/src/containers/index.d.ts.map +1 -1
  73. package/dist/types/src/hooks/index.d.ts +1 -0
  74. package/dist/types/src/hooks/index.d.ts.map +1 -1
  75. package/dist/types/src/hooks/useNeighborhoodModel.d.ts +14 -0
  76. package/dist/types/src/hooks/useNeighborhoodModel.d.ts.map +1 -0
  77. package/dist/types/src/meta.d.ts +4 -0
  78. package/dist/types/src/meta.d.ts.map +1 -1
  79. package/dist/types/src/testing/relations.d.ts +1 -2
  80. package/dist/types/src/testing/relations.d.ts.map +1 -1
  81. package/dist/types/src/translations.d.ts +6 -0
  82. package/dist/types/src/translations.d.ts.map +1 -1
  83. package/dist/types/src/types/Graph.d.ts +6 -8
  84. package/dist/types/src/types/Graph.d.ts.map +1 -1
  85. package/dist/types/tsconfig.tsbuildinfo +1 -1
  86. package/package.json +41 -37
  87. package/src/ExplorerPlugin.tsx +2 -1
  88. package/src/capabilities/app-graph-builder.ts +40 -0
  89. package/src/capabilities/create-object.ts +3 -2
  90. package/src/capabilities/index.ts +1 -0
  91. package/src/capabilities/react-surface.tsx +14 -4
  92. package/src/components/Lattice/Lattice.tsx +1 -2
  93. package/src/components/Tree/EdgeBundling.stories.tsx +5 -3
  94. package/src/components/Tree/Tree.stories.tsx +7 -2
  95. package/src/components/Tree/index.ts +3 -3
  96. package/src/components/Tree/types/tree.ts +6 -6
  97. package/src/components/Tree/types/types.ts +1 -11
  98. package/src/components/Visualization/Visualization.stories.tsx +104 -0
  99. package/src/components/Visualization/Visualization.tsx +209 -0
  100. package/src/components/Visualization/index.ts +6 -0
  101. package/src/components/Visualization/variants.ts +508 -0
  102. package/src/components/index.ts +1 -0
  103. package/src/containers/ExplorerArticle/ExplorerArticle.stories.tsx +3 -3
  104. package/src/containers/ExplorerArticle/ExplorerArticle.tsx +7 -8
  105. package/src/containers/NeighborhoodCompanion/NeighborhoodCompanion.tsx +102 -0
  106. package/src/containers/NeighborhoodCompanion/index.ts +5 -0
  107. package/src/containers/index.ts +1 -0
  108. package/src/hooks/index.ts +1 -0
  109. package/src/hooks/useNeighborhoodModel.ts +81 -0
  110. package/src/testing/relations.ts +1 -3
  111. package/src/translations.ts +3 -0
  112. package/src/types/Graph.ts +18 -20
  113. package/dist/lib/neutral/ExplorerArticle-MHEINWUL.mjs +0 -460
  114. package/dist/lib/neutral/ExplorerArticle-MHEINWUL.mjs.map +0 -7
  115. package/dist/lib/neutral/chunk-7XUDLV6E.mjs.map +0 -7
  116. package/dist/lib/neutral/chunk-IKHJV3Q4.mjs +0 -20
  117. package/dist/lib/neutral/chunk-IKHJV3Q4.mjs.map +0 -7
  118. package/dist/lib/neutral/chunk-JXYIG54N.mjs.map +0 -7
  119. package/dist/lib/neutral/chunk-YBCHBVCJ.mjs.map +0 -7
  120. package/dist/lib/neutral/react-surface-APBW2VQG.mjs +0 -26
  121. package/dist/lib/neutral/react-surface-APBW2VQG.mjs.map +0 -7
  122. package/dist/types/src/components/Tree/Tree.d.ts +0 -24
  123. package/dist/types/src/components/Tree/Tree.d.ts.map +0 -1
  124. package/dist/types/src/components/Tree/layout/HierarchicalEdgeBundling.d.ts +0 -40
  125. package/dist/types/src/components/Tree/layout/HierarchicalEdgeBundling.d.ts.map +0 -1
  126. package/dist/types/src/components/Tree/layout/RadialTree.d.ts +0 -37
  127. package/dist/types/src/components/Tree/layout/RadialTree.d.ts.map +0 -1
  128. package/dist/types/src/components/Tree/layout/TidyTree.d.ts +0 -26
  129. package/dist/types/src/components/Tree/layout/TidyTree.d.ts.map +0 -1
  130. package/dist/types/src/components/Tree/layout/hierarchy.d.ts +0 -17
  131. package/dist/types/src/components/Tree/layout/hierarchy.d.ts.map +0 -1
  132. package/dist/types/src/components/Tree/layout/index.d.ts +0 -6
  133. package/dist/types/src/components/Tree/layout/index.d.ts.map +0 -1
  134. package/dist/types/src/components/Tree/layout/slots.d.ts +0 -7
  135. package/dist/types/src/components/Tree/layout/slots.d.ts.map +0 -1
  136. package/dist/types/src/components/Tree/layout/useContainerSize.d.ts +0 -15
  137. package/dist/types/src/components/Tree/layout/useContainerSize.d.ts.map +0 -1
  138. package/dist/types/src/containers/ExplorerArticle/Visualization.d.ts +0 -18
  139. package/dist/types/src/containers/ExplorerArticle/Visualization.d.ts.map +0 -1
  140. package/dist/types/src/containers/ExplorerArticle/variants.d.ts +0 -9
  141. package/dist/types/src/containers/ExplorerArticle/variants.d.ts.map +0 -1
  142. package/src/components/Tree/Tree.tsx +0 -81
  143. package/src/components/Tree/layout/HierarchicalEdgeBundling.tsx +0 -335
  144. package/src/components/Tree/layout/RadialTree.tsx +0 -242
  145. package/src/components/Tree/layout/TidyTree.tsx +0 -246
  146. package/src/components/Tree/layout/hierarchy.ts +0 -32
  147. package/src/components/Tree/layout/index.ts +0 -9
  148. package/src/components/Tree/layout/slots.ts +0 -19
  149. package/src/components/Tree/layout/useContainerSize.ts +0 -43
  150. package/src/containers/ExplorerArticle/Visualization.tsx +0 -523
  151. package/src/containers/ExplorerArticle/variants.ts +0 -47
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../src/containers/ExplorerArticle/ExplorerArticle.tsx", "../../../src/containers/ExplorerArticle/variants.ts", "../../../src/containers/ExplorerArticle/Visualization.tsx"],
4
- "sourcesContent": ["//\n// Copyright 2023 DXOS.org\n//\n\nimport React, { useCallback, useEffect, useMemo, useState } from 'react';\n\nimport { AppSurface } from '@dxos/app-toolkit/ui';\nimport { type Filter, Obj, type View } from '@dxos/echo';\nimport { QueryBuilder } from '@dxos/echo-query';\nimport { useObject } from '@dxos/react-client/echo';\nimport { DxAnchorActivate, Icon, Panel, Toolbar } from '@dxos/react-ui';\nimport { QueryEditor, type QueryEditorProps } from '@dxos/react-ui-components';\nimport '@dxos/react-ui-graph/styles/graph.css';\n\nimport { type TreeNode } from '#components';\nimport { useGraphModel } from '#hooks';\n\nimport { type ExplorerArticleVariant, VARIANTS, isVariant } from './variants';\nimport { Visualization } from './Visualization';\n\nexport type { ExplorerArticleVariant } from './variants';\n\nexport type ExplorerArticleProps = AppSurface.ObjectArticleProps<View.View>;\n\nexport const ExplorerArticle = ({ role, subject, variant }: ExplorerArticleProps) => {\n const [view] = useObject(subject);\n const [filter, setFilter] = useState<Filter.Any>();\n\n const db = view && Obj.getDatabase(view);\n const model = useGraphModel(db, filter);\n\n const builder = useMemo(() => new QueryBuilder(), []);\n const handleChange = useCallback<NonNullable<QueryEditorProps['onChange']>>(\n (value) => {\n setFilter(builder.build(value).filter);\n },\n [builder],\n );\n\n const [selected, setSelected] = useState<ExplorerArticleVariant>(isVariant(variant) ? variant : 'force');\n useEffect(() => {\n if (isVariant(variant)) {\n setSelected(variant);\n }\n }, [variant]);\n\n const handleVariantChange = useCallback((value: string) => {\n if (isVariant(value)) {\n setSelected(value);\n }\n }, []);\n\n // Dismiss the preview popover. The dxn/label/trigger fields are placeholders ignored on\n // `state: false`.\n const handleDismiss = useCallback(() => {\n document.defaultView?.dispatchEvent(\n new DxAnchorActivate({ dxn: '', label: '', trigger: document.body, state: false }),\n );\n }, []);\n\n const handleHover = useCallback((node: TreeNode | null, event?: MouseEvent) => {\n // Pointer left the node/label: keep the popover open so it can be hovered/interacted with.\n // The popover is dismissed only on an explicit click on the component surface (handleDismiss).\n if (!node || !event) {\n return;\n }\n const obj = node.data;\n if (!obj || !Obj.isObject(obj)) {\n return;\n }\n const dxn = Obj.getURI(obj);\n if (!dxn) {\n return;\n }\n\n const target = event.target as HTMLElement;\n target.dispatchEvent(\n new DxAnchorActivate({\n dxn,\n kind: 'card',\n trigger: target,\n label: Obj.getLabel(obj) ?? dxn,\n }),\n );\n }, []);\n\n const showToolbar = role === AppSurface.Article.role;\n\n if (!db || !model) {\n return null;\n }\n\n return (\n <Panel.Root role={role}>\n {showToolbar && (\n <Panel.Toolbar asChild>\n <Toolbar.Root>\n <QueryEditor db={db} onChange={handleChange} />\n <Toolbar.ToggleGroup type='single' value={selected} onValueChange={handleVariantChange}>\n {VARIANTS.map(({ value, icon, label }) => (\n <Toolbar.ToggleGroupItem key={value} value={value} aria-label={label} title={label}>\n <Icon icon={icon} size={4} />\n </Toolbar.ToggleGroupItem>\n ))}\n </Toolbar.ToggleGroup>\n </Toolbar.Root>\n </Panel.Toolbar>\n )}\n <Panel.Content>\n <Visualization\n classNames='bg-base-surface'\n variant={selected}\n model={model}\n onNodeHover={handleHover}\n onSurfaceClick={handleDismiss}\n />\n </Panel.Content>\n </Panel.Root>\n );\n};\n", "//\n// Copyright 2026 DXOS.org\n//\n\n/** Visualization variants exposed by `ExplorerArticle`. */\nexport type ExplorerArticleVariant = 'force' | 'cluster' | 'bundle' | 'lattice' | 'swarm' | 'plexus';\n\nexport const VARIANTS: { value: ExplorerArticleVariant; icon: string; label: string }[] = [\n {\n value: 'force',\n icon: 'ph--graph--regular',\n label: 'Force-directed',\n },\n {\n value: 'cluster',\n icon: 'ph--asterisk-simple--regular',\n label: 'Radial',\n },\n {\n value: 'bundle',\n icon: 'ph--circles-three-plus--regular',\n label: 'Connections',\n },\n {\n value: 'plexus',\n icon: 'ph--share-network--regular',\n label: 'Plexus',\n },\n {\n value: 'lattice',\n icon: 'ph--grid-four--regular',\n label: 'Lattice',\n },\n {\n value: 'swarm',\n icon: 'ph--microscope--regular',\n label: 'Swarm',\n },\n];\n\nexport const isVariant = (value: unknown): value is ExplorerArticleVariant =>\n value === 'force' ||\n value === 'cluster' ||\n value === 'bundle' ||\n value === 'lattice' ||\n value === 'swarm' ||\n value === 'plexus';\n", "//\n// Copyright 2026 DXOS.org\n//\n\nimport { curveCatmullRom, line as d3Line } from 'd3';\nimport React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';\n\nimport { Obj } from '@dxos/echo';\nimport { type ThemedClassName } from '@dxos/react-ui';\nimport {\n CLUSTER_NODE_TYPE_LEAF,\n CLUSTER_NODE_TYPE_ROOT,\n GraphBundleProjector,\n GraphClusterProjector,\n GraphForceProjector,\n type GraphLayout,\n type GraphLayoutNode,\n GraphLatticeProjector,\n type GraphLayoutEdge,\n GraphPlexusProjector,\n type GraphProjector,\n GraphSwarmProjector,\n type ModelPoint,\n PLEXUS_NODE_TYPE_FOCUS,\n PLEXUS_NODE_TYPE_RELATION,\n type PlexusRelation,\n type RenderNode,\n SVG,\n type SVGContext,\n type SwarmNode,\n appendRadialGroupLabel,\n appendRadialLeafLabel,\n appendRootLabel,\n} from '@dxos/react-ui-graph';\nimport { type SpaceGraphEdge, type SpaceGraphModel, type SpaceGraphNode } from '@dxos/schema';\nimport { mx } from '@dxos/ui-theme';\n\nimport { type TreeNode } from '#components';\n\nimport { getNodeFillForObject } from '../../util';\nimport { type ExplorerArticleVariant } from './variants';\n\nexport type VisualizationProps = ThemedClassName<{\n debug?: boolean;\n variant: ExplorerArticleVariant;\n model: SpaceGraphModel;\n onNodeHover?: (node: TreeNode | null, event?: MouseEvent) => void;\n /** Called when the user clicks the visualization surface (e.g. to dismiss a node preview). */\n onSurfaceClick?: () => void;\n}>;\n\n/**\n * Renders the active visualization variant.\n */\nexport const Visualization = ({\n classNames,\n debug = true,\n variant,\n model,\n onNodeHover,\n onSurfaceClick,\n}: VisualizationProps) => {\n const svgRef = useRef<SVGContext>(null);\n const [projector, setProjector] = useState<GraphProjector<SpaceGraphNode> | undefined>();\n const projectorRef = useRef<GraphProjector<SpaceGraphNode> | undefined>(undefined);\n projectorRef.current = projector;\n\n // Plexus focus — single source of truth for both the bundle→plexus dispatch and re-focus.\n // `undefined` means \"no node focused\", which dispatches to the bundle projector.\n const [focusId, setFocusId] = useState<string | undefined>(undefined);\n\n // Latest layout we hand to the next SVG projector as `prev`. Captured from the live\n // projector when the variant changes so node x/y survive the swap.\n const lastLayoutRef = useRef<GraphLayout<SpaceGraphNode> | undefined>(undefined);\n\n // Subscribe to the graph atom — keeps it alive across child unmounts (effect-atom\n // disposes atoms with no subscribers) and triggers re-renders when query results land.\n useEffect(() => model?.subscribe(() => undefined), [model]);\n\n // Clear any focus when leaving plexus so returning to it starts from the bundle layout.\n useEffect(() => {\n if (variant !== 'plexus') {\n setFocusId(undefined);\n }\n }, [variant]);\n\n // Recreate the projector when the variant or focus changes; snapshot the live layout\n // first so the next projector animates from where the previous one left off.\n useEffect(() => {\n if (projectorRef.current?.layout) {\n lastLayoutRef.current = projectorRef.current.layout as GraphLayout<SpaceGraphNode>;\n }\n if (!svgRef.current) {\n return;\n }\n\n setProjector(createProjector(svgRef.current, variant, focusId, lastLayoutRef.current));\n }, [variant, focusId]);\n\n // Plexus: clicking an object node re-focuses on it; clicking the current focus clears it\n // (back to the bundle layout). Relation nodes carry no ECHO object, so their clicks are ignored.\n const handleSelect = useCallback(\n (node: GraphLayoutNode<SpaceGraphNode>) => {\n if (variant !== 'plexus') {\n return;\n }\n if (!node.data?.data?.object) {\n return;\n }\n setFocusId((current) => (current === node.id ? undefined : node.id));\n },\n [variant],\n );\n\n const renderNode = useMemo(() => createRenderNode(variant), [variant]);\n\n // Per-tick swarm tail update. Receives the dx-node `<g>` after its transform is set,\n // so the polyline points + gradient axis can live in node-local coordinates.\n const applyNode = useMemo(() => (variant === 'swarm' ? applyNodeSwarm : undefined), [variant]);\n\n // Cursor avoidance for the SVG swarm. The Graph component hands us pre-transformed\n // SVG model coordinates — same space the boids live in.\n const handlePointerMove = useCallback(\n (point: ModelPoint) => {\n if (projector instanceof GraphSwarmProjector) {\n projector.setCursor(point.x, point.y);\n }\n },\n [projector],\n );\n\n const handlePointerLeave = useCallback(() => {\n if (projector instanceof GraphSwarmProjector) {\n projector.setCursor(null);\n }\n }, [projector]);\n\n const handleInspect = useCallback(\n (node: GraphLayoutNode<SpaceGraphNode> | null, event: MouseEvent) => {\n if (variant === 'plexus') {\n return;\n }\n\n onNodeHover?.(node ? { id: node.id, data: node.data?.data?.object } : null, event);\n },\n [variant === 'plexus' ? undefined : onNodeHover],\n );\n\n // Only attach pointer handlers when the SVG swarm is active — other variants don't\n // need them and we want to avoid the per-move CTM math when it'd be a no-op.\n const swarmPointerProps =\n variant === 'swarm' ? { onPointerMove: handlePointerMove, onPointerLeave: handlePointerLeave } : undefined;\n\n return (\n <div className={mx('dx-expander relative', classNames)} onClick={onSurfaceClick}>\n <SVG.Root ref={svgRef}>\n <SVG.Zoom extent={[1 / 2, 2]}>\n <SVG.Graph<SpaceGraphNode, SpaceGraphEdge>\n model={model}\n projector={projector}\n renderNode={renderNode}\n applyNode={applyNode}\n edgeOpacity={variant === 'swarm' ? 0.3 : undefined}\n drag={variant === 'force'}\n highlightOnHover={variant === 'bundle'}\n onSelect={handleSelect}\n onInspect={handleInspect}\n {...swarmPointerProps}\n />\n </SVG.Zoom>\n {debug && <SVG.FPS />}\n </SVG.Root>\n </div>\n );\n};\n\n/** Cross-variant tween duration. Matches the renderer's edge fade timing so node movement and edge enter/exit complete together. */\nconst TWEEN_MS = 500;\n\n/** Fade-in duration applied to labels after the layout tween completes. */\nconst LABEL_FADE_MS = 200;\n\n/** Base radius shared by all plexus leaf + relation nodes; the focus node is double. */\nconst PLEXUS_LEAF_RADIUS = 5;\nconst PLEXUS_FOCUS_RADIUS = PLEXUS_LEAF_RADIUS * 2;\n\n/**\n * Catmull-Rom curve generator (α=0.5, \"centripetal\") for swarm boid trails.\n * Passes through every point and avoids the looping/overshoot artifacts a plain\n * cardinal spline produces when consecutive history samples land close together.\n */\nconst swarmTrailLine = d3Line<[number, number]>().curve(curveCatmullRom.alpha(0.5));\n\n/**\n * Per-tick swarm tail update. The dx-node `<g>` transform has just been written, so we work\n * in node-local coordinates: head at (0,0), history deltas trailing behind. The single\n * `<path>` is stroked with a per-boid `<linearGradient>` whose endpoints we sync to the\n * tail axis so the fade tracks the direction of travel.\n */\nconst applyNodeSwarm = (group: SVGGElement, node: GraphLayoutNode<SpaceGraphNode>): void => {\n const swarm = node as SwarmNode;\n const path = group.querySelector('path.dx-swarm-tail') as SVGPathElement | null;\n const grad = group.querySelector('linearGradient') as SVGLinearGradientElement | null;\n if (!path || !grad) {\n return;\n }\n const history = swarm.history ?? [];\n if (history.length === 0) {\n path.setAttribute('d', '');\n return;\n }\n\n const hx = swarm.x ?? 0;\n const hy = swarm.y ?? 0;\n // Build local-space points head → most-recent → … → oldest (history is push-at-end so\n // we walk it backwards), then run them through a Catmull-Rom curve generator so the\n // trail reads as a smooth arc rather than a polyline. The gradient axis below is still\n // head → oldest, so the fade stays aligned with travel direction.\n const points: Array<[number, number]> = [[0, 0]];\n for (let i = history.length - 1; i >= 0; i--) {\n points.push([history[i].x - hx, history[i].y - hy]);\n }\n path.setAttribute('d', swarmTrailLine(points) ?? '');\n const oldest = history[0];\n grad.setAttribute('x2', String(oldest.x - hx));\n grad.setAttribute('y2', String(oldest.y - hy));\n};\n\nconst createProjector = (\n ctx: SVGContext,\n variant: ExplorerArticleVariant,\n focusId: string | undefined,\n prev?: GraphLayout<SpaceGraphNode>,\n): GraphProjector<SpaceGraphNode> => {\n switch (variant) {\n case 'force':\n // Force has no `duration` — its own simulation drives motion via ticks.\n return new GraphForceProjector<SpaceGraphNode>(ctx, undefined, undefined, prev);\n\n case 'swarm':\n // Swarm in SVG: a per-tick projector mirroring force's emit-positions pattern.\n return new GraphSwarmProjector<SpaceGraphNode>(ctx, undefined, undefined, prev);\n\n case 'lattice':\n return new GraphLatticeProjector<SpaceGraphNode>(\n ctx,\n {\n duration: TWEEN_MS,\n // Plugin-explorer overrides the projector's force-matched default (6)\n // with a smaller node so the lattice reads as a dense matrix.\n radius: 4,\n // Cluster by typename first so same-type rects sit together; break ties by label.\n sortBy: (node: GraphLayoutNode<SpaceGraphNode>) => {\n const obj = node.data?.data?.object;\n const typename = obj ? (Obj.getTypename(obj) ?? '(untyped)') : '(untyped)';\n const label = (obj && Obj.getLabel(obj)) ?? node.data?.data?.label ?? node.id;\n return `${typename} ${label}`;\n },\n },\n undefined,\n prev,\n );\n\n case 'cluster':\n return new GraphClusterProjector<SpaceGraphNode>(\n ctx,\n {\n duration: TWEEN_MS,\n groupOf: typenameGroupOf,\n rootLabel: 'Database',\n groupLabel: shortTypename,\n // All three node kinds share the same radius — leaves, groups, and root read\n // as members of the same circle rather than ranked by size.\n rootRadius: 4,\n groupRadius: 4,\n },\n undefined,\n prev,\n );\n\n case 'bundle':\n return new GraphBundleProjector<SpaceGraphNode>(\n ctx,\n {\n duration: TWEEN_MS,\n groupOf: typenameGroupOf,\n },\n undefined,\n prev,\n );\n\n case 'plexus':\n // No focus → dispatch to the bundle projector (the unfocused overview). Once a node is\n // focused, switch to the focus-centric plexus layout; both receive `prev` so the swap\n // (and every re-focus) animates from the previous node positions.\n if (!focusId) {\n return new GraphBundleProjector<SpaceGraphNode>(\n ctx,\n {\n duration: TWEEN_MS,\n groupOf: typenameGroupOf,\n },\n undefined,\n prev,\n );\n }\n return new GraphPlexusProjector<SpaceGraphNode>(\n ctx,\n {\n duration: TWEEN_MS,\n focus: focusId,\n relationOf: plexusRelationOf,\n leafRadius: PLEXUS_LEAF_RADIUS,\n relationRadius: PLEXUS_LEAF_RADIUS,\n focusRadius: PLEXUS_FOCUS_RADIUS,\n },\n undefined,\n prev,\n );\n }\n};\n\n/**\n * Classify an edge incident to the focus into a relation group. Each relation/property gets two\n * possible nodes: one for the outgoing direction (focus is the edge source, arrow `→`) and one\n * for the incoming direction (focus is the edge target, arrow `←`), so both sides of a relation\n * fan out separately. Relations group by relation typename; references group by their top-level\n * property name. Edges not incident to the focus are ignored.\n */\nconst plexusRelationOf = (edge: GraphLayoutEdge<SpaceGraphNode>, focusId: string): PlexusRelation | undefined => {\n const outgoing = edge.source.id === focusId;\n const incoming = edge.target.id === focusId;\n if (!outgoing && !incoming) {\n return undefined;\n }\n const direction = outgoing ? 'out' : 'in';\n const arrow = outgoing ? '→' : '←';\n\n if (edge.type === 'relation') {\n const relation = (edge.data as any)?.object as Obj.Unknown | undefined;\n const typename = relation ? Obj.getTypename(relation) : undefined;\n const name = typename ? shortTypename(typename) : 'Relation';\n return { key: `relation:${direction}:${typename ?? '?'}`, label: `${name} ${arrow}` };\n }\n\n if (edge.type === 'ref') {\n const property = (edge.data as any)?.property as string | undefined;\n const name = property ?? 'References';\n return { key: `ref:${direction}:${property ?? '?'}`, label: `${name} ${arrow}` };\n }\n\n return undefined;\n};\n\nconst createRenderNode = (variant: ExplorerArticleVariant): RenderNode<SpaceGraphNode> | undefined => {\n switch (variant) {\n case 'force':\n return (group, node) => {\n const r = node.r ?? 6;\n group\n .append('circle')\n .attr('r', r)\n .style('cursor', 'pointer')\n .style('fill', getNodeFillForObject(node.data?.data?.object as Obj.Unknown | undefined));\n };\n\n case 'swarm':\n // Match the force variant's shape so identity-by-id transitions read continuously.\n // The tail is a SINGLE `<path>` traced through head + history points; its stroke\n // uses a per-boid `<linearGradient>` that fades head → tail. Done this way (rather\n // than as N overlapping `<line>` segments) so coincident segment endpoints don't\n // compound their alpha and read as a striped trail.\n return (group, node) => {\n const fill = getNodeFillForObject(node.data?.data?.object as Obj.Unknown | undefined);\n const r = node.r ?? 6;\n const strokeWidth = Math.max(1, r * 0.6);\n // Gradient id must be unique document-wide. node.id is the DXN, which contains\n // characters (`:`, `/`, etc.) that aren't valid in NCName-style ids, so sanitize.\n const gradId = `dx-swarm-grad-${String(node.id).replace(/[^\\w-]/g, '_')}`;\n const grad = group\n .append('defs')\n .append('linearGradient')\n .attr('id', gradId)\n // userSpaceOnUse so x1/y1/x2/y2 are interpreted in the dx-node's local coord space\n // (head at 0,0). The applyNode hook overwrites them per tick to align with the\n // path's head → tail axis.\n .attr('gradientUnits', 'userSpaceOnUse')\n .attr('x1', 0)\n .attr('y1', 0)\n .attr('x2', 0)\n .attr('y2', 0);\n grad.append('stop').attr('offset', 0).attr('stop-color', fill).attr('stop-opacity', 0.7);\n grad.append('stop').attr('offset', 1).attr('stop-color', fill).attr('stop-opacity', 0);\n // Path first so the head circle sits on top.\n group\n .append('path')\n .classed('dx-swarm-tail', true)\n .attr('fill', 'none')\n .attr('stroke', `url(#${gradId})`)\n .attr('stroke-width', strokeWidth)\n .attr('stroke-linecap', 'round')\n .attr('stroke-linejoin', 'round')\n .attr('pointer-events', 'none');\n group.append('circle').attr('r', r).style('cursor', 'pointer').style('fill', fill);\n };\n\n case 'lattice':\n return (group, node) => {\n const r = node.r ?? 6;\n const sz = r * 2;\n group\n .append('rect')\n .attr('x', -r)\n .attr('y', -r)\n .attr('width', sz)\n .attr('height', sz)\n .attr('rx', r * 0.3)\n .attr('ry', r * 0.3)\n .style('cursor', 'pointer')\n .style('fill', getNodeFillForObject(node.data?.data?.object as Obj.Unknown | undefined));\n };\n\n case 'cluster':\n return (group, node) => {\n const obj = node.data?.data?.object as Obj.Unknown | undefined;\n const r = node.r ?? 4;\n // Synthetic root / group nodes have no underlying ECHO object; render them as\n // smaller, neutral circles so the hierarchy reads as \"structure + leaves\".\n group\n .append('circle')\n .attr('r', r)\n .style('cursor', 'pointer')\n .style('fill', obj ? getNodeFillForObject(obj) : 'var(--color-neutral-500)');\n const labelOptions = { delay: TWEEN_MS, duration: LABEL_FADE_MS };\n if (node.type === CLUSTER_NODE_TYPE_LEAF) {\n const text = labelForLeaf(node, obj);\n if (text) {\n appendRadialLeafLabel(group, node, text, r, labelOptions);\n }\n } else if (node.type === CLUSTER_NODE_TYPE_ROOT) {\n if (node.label) {\n appendRootLabel(group, node.label, r, labelOptions);\n }\n } else {\n if (node.label) {\n appendRadialGroupLabel(group, node, node.label, r, labelOptions);\n }\n }\n };\n\n case 'bundle':\n // Bundle layout renders ONLY leaves (root/group are invisible routing anchors).\n return (group, node) => {\n const obj = node.data?.data?.object as Obj.Unknown | undefined;\n const r = node.r ?? 4;\n group\n .append('circle')\n .attr('r', r)\n .style('cursor', 'pointer')\n .style('fill', obj ? getNodeFillForObject(obj) : 'var(--color-neutral-500)');\n const text = labelForLeaf(node, obj);\n if (text) {\n appendRadialLeafLabel(group, node, text, r, { delay: TWEEN_MS, duration: LABEL_FADE_MS });\n }\n };\n\n case 'plexus':\n // Three node kinds: the focus at the centre (larger, object fill), synthetic relation\n // nodes on the inner ring (neutral, labelled by relation/property), and object leaves on\n // the outer ring (object fill). Type tags are set by the projector.\n return (group, node) => {\n const obj = node.data?.data?.object as Obj.Unknown | undefined;\n const labelOptions = { delay: TWEEN_MS, duration: LABEL_FADE_MS };\n\n // Size by node type (not node.r): the renderer bakes the circle radius at enter time\n // from the tween's start value, so a node.r fallback would inherit the previous\n // variant's radius. All leaves + relations share the base size; the focus is double.\n if (node.type === PLEXUS_NODE_TYPE_RELATION) {\n const r = PLEXUS_LEAF_RADIUS;\n group.append('circle').attr('r', r).style('cursor', 'default').style('fill', 'var(--color-neutral-500)');\n if (node.label) {\n appendRadialGroupLabel(group, node, node.label, r, labelOptions);\n }\n return;\n }\n\n const isFocus = node.type === PLEXUS_NODE_TYPE_FOCUS;\n const r = isFocus ? PLEXUS_FOCUS_RADIUS : PLEXUS_LEAF_RADIUS;\n group\n .append('circle')\n .attr('r', r)\n .style('cursor', 'pointer')\n .style('fill', obj ? getNodeFillForObject(obj) : 'var(--color-neutral-500)');\n const text = labelForLeaf(node, obj);\n if (text) {\n if (isFocus) {\n appendRootLabel(group, text, r, labelOptions);\n } else {\n appendRadialLeafLabel(group, node, text, r, labelOptions);\n }\n }\n };\n }\n};\n\n/**\n * Group leaves by typename so same-type leaves cluster together — used by both the\n * cluster (visible structural nodes) and bundle (invisible routing anchors) projectors.\n */\nconst typenameGroupOf = (node: GraphLayoutNode<SpaceGraphNode>): string | undefined => {\n const obj = node.data?.data?.object;\n return obj ? (Obj.getTypename(obj) ?? '(untyped)') : undefined;\n};\n\n/** Drop the package prefix from a typename for display: `org.dxos.type.Person` → `Person`. */\nconst shortTypename = (typename: string): string => {\n const last = typename.split('.').pop() ?? typename;\n return last.charAt(0).toUpperCase() + last.slice(1);\n};\n\n/** Resolve a leaf's display label from its ECHO object, falling back to node-level metadata. */\nconst labelForLeaf = (node: GraphLayoutNode<SpaceGraphNode>, obj: Obj.Unknown | undefined): string | undefined =>\n (obj && Obj.getLabel(obj)) ?? node.data?.data?.label ?? node.id;\n"],
5
- "mappings": "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",
6
- "names": ["React", "useCallback", "useEffect", "useMemo", "useState", "AppSurface", "Obj", "QueryBuilder", "useObject", "DxAnchorActivate", "Icon", "Panel", "Toolbar", "QueryEditor", "useGraphModel", "VARIANTS", "value", "icon", "label", "isVariant", "curveCatmullRom", "line", "d3Line", "React", "useCallback", "useEffect", "useMemo", "useRef", "useState", "Obj", "CLUSTER_NODE_TYPE_LEAF", "CLUSTER_NODE_TYPE_ROOT", "GraphBundleProjector", "GraphClusterProjector", "GraphForceProjector", "GraphLatticeProjector", "GraphPlexusProjector", "GraphSwarmProjector", "PLEXUS_NODE_TYPE_FOCUS", "PLEXUS_NODE_TYPE_RELATION", "SVG", "appendRadialGroupLabel", "appendRadialLeafLabel", "appendRootLabel", "mx", "Visualization", "classNames", "debug", "variant", "model", "onNodeHover", "onSurfaceClick", "svgRef", "useRef", "projector", "setProjector", "useState", "projectorRef", "undefined", "current", "focusId", "setFocusId", "lastLayoutRef", "useEffect", "subscribe", "layout", "createProjector", "handleSelect", "useCallback", "node", "data", "object", "id", "renderNode", "useMemo", "createRenderNode", "applyNode", "applyNodeSwarm", "handlePointerMove", "point", "GraphSwarmProjector", "setCursor", "x", "y", "handlePointerLeave", "handleInspect", "event", "swarmPointerProps", "onPointerMove", "onPointerLeave", "div", "className", "mx", "onClick", "SVG", "Root", "ref", "Zoom", "extent", "Graph", "edgeOpacity", "drag", "highlightOnHover", "onSelect", "onInspect", "FPS", "TWEEN_MS", "LABEL_FADE_MS", "PLEXUS_LEAF_RADIUS", "PLEXUS_FOCUS_RADIUS", "swarmTrailLine", "d3Line", "curve", "curveCatmullRom", "alpha", "group", "swarm", "path", "querySelector", "grad", "history", "length", "setAttribute", "hx", "hy", "points", "i", "push", "oldest", "String", "ctx", "prev", "GraphForceProjector", "GraphLatticeProjector", "duration", "radius", "sortBy", "obj", "typename", "Obj", "getTypename", "label", "getLabel", "GraphClusterProjector", "groupOf", "typenameGroupOf", "rootLabel", "groupLabel", "shortTypename", "rootRadius", "groupRadius", "GraphBundleProjector", "GraphPlexusProjector", "focus", "relationOf", "plexusRelationOf", "leafRadius", "relationRadius", "focusRadius", "edge", "outgoing", "source", "incoming", "target", "direction", "arrow", "type", "relation", "name", "key", "property", "r", "append", "attr", "style", "getNodeFillForObject", "fill", "strokeWidth", "Math", "max", "gradId", "replace", "classed", "sz", "labelOptions", "delay", "CLUSTER_NODE_TYPE_LEAF", "text", "labelForLeaf", "appendRadialLeafLabel", "CLUSTER_NODE_TYPE_ROOT", "appendRootLabel", "appendRadialGroupLabel", "PLEXUS_NODE_TYPE_RELATION", "isFocus", "PLEXUS_NODE_TYPE_FOCUS", "last", "split", "pop", "charAt", "toUpperCase", "slice", "ExplorerArticle", "role", "subject", "variant", "view", "useObject", "filter", "setFilter", "useState", "db", "Obj", "getDatabase", "model", "useGraphModel", "builder", "useMemo", "QueryBuilder", "handleChange", "useCallback", "value", "build", "selected", "setSelected", "isVariant", "useEffect", "handleVariantChange", "handleDismiss", "document", "defaultView", "dispatchEvent", "DxAnchorActivate", "dxn", "label", "trigger", "body", "state", "handleHover", "node", "event", "obj", "data", "isObject", "getURI", "target", "kind", "getLabel", "showToolbar", "AppSurface", "Article", "React", "Panel", "Root", "Toolbar", "asChild", "QueryEditor", "onChange", "ToggleGroup", "type", "onValueChange", "VARIANTS", "map", "icon", "ToggleGroupItem", "key", "aria-label", "title", "Icon", "size", "Content", "Visualization", "classNames", "onNodeHover", "onSurfaceClick"]
7
- }
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../src/components/Tree/types/types.ts", "../../../src/components/Tree/types/tree.ts"],
4
- "sourcesContent": ["//\n// Copyright 2023 DXOS.org\n//\n\nimport { type Key } from '@dxos/echo';\n\nimport { type TreeType } from './tree';\n\n/**\n * In-memory tree shape used by the d3 layouts.\n * `data` carries through to layout callbacks (e.g. hover/inspect) — typically an ECHO object on leaves.\n */\nexport type TreeNode<TData = unknown> = {\n id: string;\n label?: string;\n data?: TData;\n children?: TreeNode<TData>[];\n};\n\n/**\n * Convert an ECHO `TreeType` (id-keyed node map) into a nested `TreeNode` hierarchy.\n * Returns `undefined` if the root id is missing — the tree is then incomplete and shouldn't render.\n */\nexport const treeTypeToTreeNode = (\n tree: TreeType,\n rootId: Key.EntityId = tree.root,\n visited: Set<string> = new Set(),\n): TreeNode | undefined => {\n const node = tree.nodes[rootId];\n if (!node) {\n return undefined;\n }\n if (visited.has(rootId)) {\n return { id: rootId, label: labelOf(node), data: node.data };\n }\n visited.add(rootId);\n\n return {\n id: rootId,\n label: labelOf(node),\n data: node.data,\n children: node.children\n .map((childId) => treeTypeToTreeNode(tree, childId, visited))\n .filter((c): c is TreeNode => Boolean(c)),\n };\n};\n\nconst labelOf = (node: { data: Record<string, any> }): string | undefined => {\n return typeof node.data?.text === 'string' ? node.data.text : undefined;\n};\n", "//\n// Copyright 2023 DXOS.org\n//\n\nimport * as Schema from 'effect/Schema';\n\nimport { DXN, Key, Obj, Ref, Type } from '@dxos/echo';\nimport { TestSchema } from '@dxos/echo/testing';\nimport { invariant } from '@dxos/invariant';\n\n// TODO(burdon): Reconcile with @dxos/graph (i.e., common types).\n\nexport const TreeNodeType = Schema.Struct({\n id: Key.EntityId,\n children: Schema.mutable(Schema.Array(Key.EntityId)),\n data: Schema.mutable(Schema.Record({ key: Schema.String, value: Schema.Any })),\n ref: Schema.optional(Ref.Ref(TestSchema.Expando)),\n}).pipe(Schema.mutable);\n\nexport type TreeNodeType = Schema.Schema.Type<typeof TreeNodeType>;\n\nexport const TreeType = Schema.Struct({\n root: Key.EntityId,\n nodes: Schema.mutable(Schema.Record({ key: Key.EntityId, value: TreeNodeType })),\n}).pipe(Type.makeObject(DXN.make('org.dxos.type.tree', '0.1.0')));\n\nexport type TreeType = Type.InstanceType<typeof TreeType>;\n\n/**\n * Wrapper object for tree.\n */\nexport class Tree {\n static create = (): TreeType => {\n const id = Key.EntityId.random();\n return Obj.make(TreeType, {\n root: id,\n nodes: {\n [id]: {\n id,\n children: [],\n data: { text: '' }, // TODO(burdon): Generic.\n },\n },\n });\n };\n\n private _tree: TreeType;\n\n constructor(tree?: TreeType) {\n this._tree = tree ?? Tree.create();\n }\n\n get tree() {\n return this._tree;\n }\n\n // TODO(burdon): Make reactive.\n get size() {\n return Object.keys(this._tree.nodes).length;\n }\n\n get root() {\n return this.getNode(this._tree.root);\n }\n\n //\n // Traversal\n //\n\n /**\n * Recursively traverse the tree until the callback returns a value.\n */\n tranverse<T>(\n callback: (node: TreeNodeType, depth: number) => T | void,\n root: Key.EntityId = this._tree.root,\n depth = 0,\n ): T | void {\n const node = this._tree.nodes[root];\n const result = callback(node, depth);\n if (result !== undefined) {\n return result;\n }\n\n for (const childId of node.children) {\n const result = this.tranverse(callback, childId, depth + 1);\n if (result !== undefined) {\n return result;\n }\n }\n }\n\n getNode(id: Key.EntityId): TreeNodeType {\n const node = this._tree.nodes[id];\n invariant(node);\n return node;\n }\n\n /**\n * Get the children of a node.\n */\n getChildNodes(node: TreeNodeType): Array<TreeNodeType> {\n return node.children.map((id) => this.getNode(id));\n }\n\n /**\n * Get the parent of a node.\n */\n getParent(node: TreeNodeType): TreeNodeType | null {\n const parent = this.tranverse((n) => {\n if (n.children.includes(node.id)) {\n return n;\n }\n });\n\n return parent ?? null;\n }\n\n /**\n * Get the next node in the tree.\n */\n getNext(node: TreeNodeType, hierarchical = true): TreeNodeType | undefined {\n if (hierarchical && node.children.length) {\n // First child.\n return this.getChildNodes(node)[0];\n } else {\n const parent = this.getParent(node);\n if (parent) {\n const idx = this.getChildNodes(parent).findIndex(({ id }) => id === node.id);\n if (idx < parent.children.length - 1) {\n // Next sibling.\n return this.getNode(parent.children[idx + 1]);\n } else {\n // Get parent's next sibling.\n return this.getNext(parent, false);\n }\n }\n }\n }\n\n /**\n * Get the previous node in the tree.\n */\n getPrevious(node: TreeNodeType, hierarchical = true): TreeNodeType | undefined {\n const parent = this.getParent(node)!;\n const idx = this.getChildNodes(parent).findIndex(({ id }) => id === node.id);\n if (idx === 0) {\n if (hierarchical) {\n return parent;\n }\n } else {\n const previous = this.getNode(parent.children[idx - 1]);\n if (hierarchical && previous.children.length) {\n return this.getLastDescendent(previous);\n }\n\n return previous;\n }\n }\n\n /**\n * Get the last descendent of a node.\n */\n getLastDescendent(node: TreeNodeType): TreeNodeType | undefined {\n const children = this.getChildNodes(node);\n const last = children.length ? children[children.length - 1] : undefined;\n if (last) {\n return this.getLastDescendent(last);\n }\n\n return node;\n }\n\n //\n // Mutations\n //\n\n /**\n * Clear tree.\n */\n clear(): void {\n const root = this._tree.nodes[this._tree.root];\n root.children.length = 0;\n Obj.update(this._tree, (obj) => {\n obj.nodes = {\n [root.id]: root,\n };\n });\n }\n\n /**\n * Add node.\n */\n addNode(parent: TreeNodeType, node?: TreeNodeType, index?: number): TreeNodeType {\n if (!node) {\n const id = Key.EntityId.random();\n node = { id, children: [], data: { text: '' } }; // TODO(burdon): Generic.\n }\n\n const nodeToAdd = node;\n Obj.update(this._tree, (obj) => {\n obj.nodes[nodeToAdd.id] = nodeToAdd;\n parent.children.splice(index ?? parent.children.length, 0, nodeToAdd.id);\n });\n return node;\n }\n\n /**\n * Delete node.\n */\n deleteNode(parent: TreeNodeType, id: Key.EntityId): TreeNodeType | undefined {\n const node = this._tree.nodes[id];\n if (!node) {\n return undefined;\n }\n\n Obj.update(this._tree, (obj) => {\n delete obj.nodes[node.id];\n });\n const idx = parent.children.findIndex((child) => child === id);\n if (idx !== -1) {\n Obj.update(this._tree, () => {\n parent.children.splice(idx, 1);\n });\n }\n\n return node;\n }\n\n /**\n * Move child node.\n */\n moveNode(node: TreeNodeType, from: number, to: number): TreeNodeType | null {\n invariant(from >= 0 && from < node.children.length);\n invariant(to >= 0 && to < node.children.length);\n if (from === to) {\n return null;\n }\n\n const child = node.children[from];\n Obj.update(this._tree, () => {\n node.children.splice(from, 1);\n node.children.splice(to, 0, child);\n });\n return this.getNode(child);\n }\n\n /**\n * Indent node.\n */\n indentNode(node: TreeNodeType): void {\n const parent = this.getParent(node);\n if (!parent) {\n return;\n }\n\n const idx = parent.children.findIndex((child) => child === node.id);\n if (idx < 1 || idx >= parent.children.length) {\n return;\n }\n\n const previous = this.getNode(parent.children[idx - 1]);\n Obj.update(this._tree, () => {\n parent.children.splice(idx, 1);\n previous.children.push(node.id);\n });\n }\n\n /**\n * Unindent node.\n */\n unindentNode(node: TreeNodeType): void {\n const parent = this.getParent(node);\n if (!parent) {\n return;\n }\n\n const ancestor = this.getParent(parent);\n if (!ancestor) {\n return;\n }\n\n // Remove node from parent and get following siblings.\n const nodeIdx = parent.children.findIndex((id) => id === node.id);\n let rest: Key.EntityId[] = [];\n Obj.update(this._tree, () => {\n const removed = parent.children.splice(nodeIdx, parent.children.length - nodeIdx);\n rest = removed.slice(1); // Skip the node itself.\n });\n\n // Add to ancestor.\n const parentIdx = this.getChildNodes(ancestor).findIndex((n) => n.id === parent.id);\n Obj.update(this._tree, () => {\n ancestor.children.splice(parentIdx + 1, 0, node.id);\n });\n\n // Transplant following siblings to current node.\n Obj.update(this._tree, () => {\n node.children.push(...rest);\n });\n }\n}\n"],
5
- "mappings": "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",
6
- "names": ["treeTypeToTreeNode", "tree", "rootId", "root", "visited", "Set", "node", "nodes", "undefined", "has", "id", "label", "labelOf", "data", "add", "children", "map", "childId", "filter", "c", "Boolean", "text", "Schema", "DXN", "Key", "Obj", "Ref", "Type", "TestSchema", "invariant", "children", "data", "String", "ref", "optional", "pipe", "TreeType", "Struct", "EntityId", "nodes", "Record", "key", "TreeNodeType", "makeObject", "id", "make", "root", "_tree", "tree", "result", "callback", "node", "depth", "undefined", "childId", "getNode", "n", "getChildNodes", "parent", "getParent", "idx", "hierarchical", "getLastDescendent", "previous", "length", "last", "update", "obj", "nodeToAdd", "splice", "index", "findIndex", "to", "from", "child", "push", "removed", "rest", "slice", "ancestor", "parentIdx"]
7
- }
@@ -1,20 +0,0 @@
1
- // src/util/node-color.ts
2
- import { Obj } from "@dxos/echo";
3
- import { getHashHue } from "@dxos/ui-theme";
4
- var getNodeFillForTypename = (typename) => {
5
- return `var(--color-${getHashHue(typename)}-400)`;
6
- };
7
- var getNodeFillForObject = (object) => {
8
- return getNodeFillForTypename(object && Obj.getTypename(object));
9
- };
10
-
11
- // src/util/plot.ts
12
- var createAdapter = (prop, accessor) => accessor ? {
13
- transform: (values) => values.map((value) => accessor(value)[prop])
14
- } : prop;
15
-
16
- export {
17
- getNodeFillForObject,
18
- createAdapter
19
- };
20
- //# sourceMappingURL=chunk-IKHJV3Q4.mjs.map
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../src/util/node-color.ts", "../../../src/util/plot.ts"],
4
- "sourcesContent": ["//\n// Copyright 2026 DXOS.org\n//\n\nimport { Obj } from '@dxos/echo';\nimport { getHashHue } from '@dxos/ui-theme';\n\n/**\n * Returns the SVG `fill` value for a node, derived from its typename via the\n * same hue-hash used by the force-directed renderer. Resolves to a Tailwind\n * color token CSS variable so the value reads consistently across themes.\n *\n * Used by every variant of `ExplorerArticle` so nodes are colored consistently\n * regardless of which layout is rendering them.\n */\nexport const getNodeFillForTypename = (typename: string | undefined): string => {\n return `var(--color-${getHashHue(typename)}-400)`;\n};\n\n/** Convenience: derive the fill from an ECHO object's typename. */\nexport const getNodeFillForObject = (object: Obj.Unknown | undefined): string => {\n return getNodeFillForTypename(object && Obj.getTypename(object));\n};\n", "//\n// Copyright 2023 DXOS.org\n//\n\nimport type { ChannelValueSpec } from '@observablehq/plot';\n\nexport type Accessor<T> = (object: any) => T;\n\nexport type Point = {\n x: number;\n y: number;\n};\n\nexport type GeoLocation = {\n lat: number;\n lng: number;\n};\n\nexport const createAdapter = <T extends Record<string, any>>(\n prop: string,\n accessor: Accessor<T> | undefined,\n): ChannelValueSpec =>\n accessor\n ? {\n transform: (values) => values.map((value) => accessor(value)[prop]),\n }\n : prop;\n"],
5
- "mappings": ";AAIA,SAASA,WAAW;AACpB,SAASC,kBAAkB;AAUpB,IAAMC,yBAAyB,CAACC,aAAAA;AACrC,SAAO,eAAeF,WAAWE,QAAAA,CAAAA;AACnC;AAGO,IAAMC,uBAAuB,CAACC,WAAAA;AACnC,SAAOH,uBAAuBG,UAAUL,IAAIM,YAAYD,MAAAA,CAAAA;AAC1D;;;ACJO,IAAME,gBAAgB,CAC3BC,MACAC,aAEAA,WACI;EACEC,WAAW,CAACC,WAAWA,OAAOC,IAAI,CAACC,UAAUJ,SAASI,KAAAA,EAAOL,IAAAA,CAAK;AACpE,IACAA;",
6
- "names": ["Obj", "getHashHue", "getNodeFillForTypename", "typename", "getNodeFillForObject", "object", "getTypename", "createAdapter", "prop", "accessor", "transform", "values", "map", "value"]
7
- }
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../src/ExplorerPlugin.tsx", "raw-loader:/__w/dxos/dxos/packages/plugins/plugin-explorer/PLUGIN.mdl"],
4
- "sourcesContent": ["//\n// Copyright 2023 DXOS.org\n//\n\nimport { Plugin } from '@dxos/app-framework';\nimport { AppPlugin } from '@dxos/app-toolkit';\n\nimport { CreateObject, ReactSurface } from '#capabilities';\nimport { meta } from '#meta';\nimport { translations } from '#translations';\nimport { Graph } from '#types';\n\n// eslint-disable-next-line import/no-relative-packages\nimport pluginSpec from '../PLUGIN.mdl?raw';\n\nexport const ExplorerPlugin = Plugin.define(meta).pipe(\n AppPlugin.addCreateObjectModule({ activate: CreateObject }),\n AppPlugin.addSchemaModule({ schema: [Graph.Graph] }),\n AppPlugin.addSurfaceModule({ activate: ReactSurface }),\n AppPlugin.addTranslationsModule({ translations }),\n AppPlugin.addPluginAssetModule({\n asset: { pluginId: meta.profile.key, path: 'PLUGIN.mdl', content: pluginSpec, mimeType: 'application/x-mdl' },\n }),\n Plugin.make,\n);\n\nexport default ExplorerPlugin;\n", "---\nid: org.dxos.plugin.explorer\nname: ExplorerPlugin\nversion: 0.1.0\n---\n\nAn interactive hypergraph visualization plugin for `DXOS` Composer that reveals relationships between objects in a workspace.\nThe plugin renders a live `Graph` object \u2014 backed by a `View` and a `QueryAST` query \u2014 through four switchable layout\nvariants: force-directed, radial cluster, edge bundling, and lattice.\nNode colours are derived from ECHO object types; hovering a node triggers an anchor-card preview.\n\n## Extensions\n\nThe following extension dialects are used in this document.\nEach extension is defined in the Appendix or resolved via its URI.\n\n| Term | URI |\n|-------------|--------------------------------|\n| `type` | `org.dxos.mdl.type@1.0` |\n| `feat` | `org.dxos.mdl.feat@1.0` |\n| `test` | `org.dxos.mdl.test@1.0` |\n| `component` | `org.dxos.mdl.component@1.0` |\n| `op` | `org.dxos.mdl.op@1.0` |\n\n## Types\n\n```mdl\ntype QueryInput\n fields:\n raw?: string # raw query string entered by the user\n ast: QueryAST.Query # compiled AST produced by QueryBuilder\n```\n\n```mdl\ntype GraphObject\n desc: ECHO-persistent object that describes a hypergraph visualisation session.\n fields:\n name?: string\n view: Ref<View> # schema view that defines visible fields\n query: QueryInput\n```\n\n```mdl\ntype ExplorerVariant\n literals: force | cluster | bundle | lattice\n```\n\n## Components\n\n```mdl\ncomponent ExplorerArticle\n desc: |\n Top-level article / section surface for a Graph object.\n Renders one of four SVG layout variants and a toolbar for switching between them.\n props:\n role: article | section\n subject: Ref<View>\n attendableId?: string\n state:\n variant: ExplorerVariant # active layout; default force\n filter?: Filter.Any # compiled from toolbar query input\n model?: SpaceGraphModel # live reactive graph built from db + filter\n slots:\n toolbar?: ReactNode # shown only when role === article\n actions:\n setVariant(v: ExplorerVariant)\n setFilter(raw: string)\n layout: |\n \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n \u2502 [toolbar slot \u2014 article only] \u2502\n \u2502 [QueryEditor] [variant tabs] \u2502\n \u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n \u2502 \u2502\n \u2502 SVG canvas (force / cluster \u2502\n \u2502 / bundle / lattice) \u2502\n \u2502 \u2502\n \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n```\n\n```mdl\ncomponent Visualization\n desc: |\n Internal component that owns a single persistent SVG.Graph mount.\n Swaps the active GraphProjector when the variant changes, seeding the\n new projector with the previous layout so node positions tween smoothly.\n props:\n variant: ExplorerVariant\n model: SpaceGraphModel\n state:\n projector?: GraphProjector<SpaceGraphNode>\n actions:\n createProjector(variant: ExplorerVariant, prev?: GraphLayout) \u2192 GraphProjector\n createRenderNode(variant: ExplorerVariant) \u2192 RenderNode\n```\n\n## Operations\n\n```mdl\nop createGraph\n desc: |\n Creates a new Graph object scoped to a target space or collection.\n Derives a ViewModel from the database for the selected typename, then\n writes the object via SpaceOperation.AddObject.\n input:\n name?: string\n typename?: string # ECHO typename used to seed the initial view\n target: Space | Collection\n targetNodeId?: string\n output: GraphObject\n effects: [echo:write]\n note: |\n The typename is resolved through ViewModel.makeFromDatabase; the resulting\n View is stored as a Ref inside the Graph object.\n```\n\n```mdl\nop buildFilter\n desc: |\n Compiles a raw query string into a Filter via QueryBuilder.\n Pure \u2014 no side effects; result is passed to SpaceGraphModel.setFilter.\n input:\n raw: string\n output: Filter.Any\n errors:\n ParseError: raw string is not valid query syntax\n```\n\n## Features\n\n```mdl\nfeat F-1: Graph Object\n\n req F-1.1: A Graph object stores a name, a View ref, and a compiled QueryAST.\n req F-1.2:\n when: user creates a new graph\n then: op:createGraph derives a ViewModel from the chosen typename and writes the Graph to ECHO\n\n req F-1.3:\n when: Graph is persisted\n then: it appears in the space object list and can be opened as an article\n```\n\n```mdl\nfeat F-2: Live Graph Model\n\n req F-2.1:\n when: ExplorerArticle mounts with a valid Graph subject\n then: SpaceGraphModel is opened against the subject's database\n\n req F-2.2:\n when: user types a query in the toolbar\n then: op:buildFilter compiles the raw string; model.setFilter applied; SVG re-renders\n\n req F-2.3:\n when: Graph is unmounted\n then: SpaceGraphModel is closed and all subscriptions released\n\n req F-2.4:\n when: an ECHO object in the database changes\n then: SpaceGraphModel emits an update and SVG.Graph re-renders without full remount\n tags: [reactive, collaborative]\n```\n\n```mdl\nfeat F-3: Visualization Variants\n\n req F-3.1:\n when: variant tab is selected\n then: Visualization swaps projector; previous node x/y seed the new projector so positions tween\n\n req F-3.2:\n when: variant is force\n then: SVG.Zoom wrapper is mounted enabling pan/zoom drag interaction\n\n req F-3.3:\n when: variant is cluster or bundle\n then: no SVG.Zoom wrapper; leaves grouped by typename; radial labels fade in after tween\n\n req F-3.4:\n when: variant is lattice\n then: nodes rendered as small rounded rectangles sorted by typename then label\n\n req F-3.5:\n when: variant is cluster and user clicks a root or group node\n then: subtree toggles collapsed/expanded via GraphClusterProjector.toggleCollapsed\n```\n\n```mdl\nfeat F-4: Node Interaction\n\n req F-4.1:\n when: pointer enters a node\n then: DxAnchorActivate event dispatched with the object's DXN and label, kind: card\n\n req F-4.2:\n when: pointer leaves a node\n then: DxAnchorActivate cleared (onNodeHover called with null)\n\n req F-4.3:\n when: node has no underlying ECHO object (synthetic root / group)\n then: no preview dispatched; node rendered in neutral colour\n```\n\n## Acceptance\n\n```mdl\ntest T-1: Graph creation\n given: user opens the object creation dialog and selects Graph\n when: a typename is selected and the form submitted\n then:\n - op:createGraph runs without error\n - new Graph object visible in space object list\n - Graph.view references a valid View object\n```\n\n```mdl\ntest T-2: Article mounts model\n given: a Graph with a populated query\n when: ExplorerArticle is rendered with role === article\n then:\n - SpaceGraphModel is opened\n - SVG canvas renders nodes derived from the database\n - toolbar shows QueryEditor and variant tabs\n```\n\n```mdl\ntest T-3: Variant switch preserves positions\n given: force variant is active with nodes positioned\n when: user switches to cluster variant\n then:\n - projector is recreated from previous layout\n - nodes tween from old positions to cluster target positions\n - SVG.Zoom wrapper is absent in the new mount\n```\n\n```mdl\ntest T-4: Query filter updates graph\n given: ExplorerArticle is open with all objects visible\n when: user types a typename filter in QueryEditor\n then:\n - op:buildFilter returns a Filter without error\n - SpaceGraphModel.setFilter applied\n - only matching nodes remain visible in the SVG\n```\n\n```mdl\ntest T-5: Node hover preview\n given: force-directed graph with at least one ECHO object node\n when: pointer enters that node\n then:\n - DxAnchorActivate event fired with correct DXN\n - kind === card\n```\n\n```mdl\ntest T-6: Lattice sort order\n given: database contains objects of two typenames A and B\n when: lattice variant is active\n then:\n - all typename-A nodes appear before typename-B nodes (or vice-versa, consistent order)\n - within each group nodes are ordered alphabetically by label\n```\n\n```mdl\ntest T-7: Model closed on unmount\n given: ExplorerArticle is mounted and SpaceGraphModel is open\n when: component unmounts\n then:\n - SpaceGraphModel.close() is called\n - no lingering ECHO subscriptions remain\n```\n\n---\n\n## Appendix: Extension Definitions\n\nExtension block types used in this document are defined below using\nthe core `ext` primitive \u2014 the only construct the base language provides.\n\n```mdl\next type\n uri: org.dxos.mdl.type@1.0\n desc: A named data structure with typed fields and optional literals.\n fields:\n desc?: Prose\n fields?: FieldMap # name[?]: TypeExpr (# inline comment)\n literals?: UnionList # a | b | c\n extends?: TypeRef[]\n```\n\n```mdl\next feat\n uri: org.dxos.mdl.feat@1.0\n desc: A named feature grouping one or more requirements.\n fields:\n desc?: Prose\n req: RequirementList\n nesting: self # feat blocks may contain feat blocks\n```\n\n```mdl\next test\n uri: org.dxos.mdl.test@1.0\n desc: An acceptance scenario expressed as given / when / then steps.\n fields:\n given?: Step | Step[]\n when?: Step | Step[]\n then: Step | Step[]\n tags?: TagList\n```\n\n```mdl\next component\n uri: org.dxos.mdl.component@1.0\n desc: A UI component with props, internal state, slots, actions, and events.\n fields:\n desc?: Prose\n props?: FieldMap # external inputs (immutable inside component)\n state?: FieldMap # internal reactive state\n slots?: FieldMap # named ReactNode injection points\n actions?: ActionMap # methods the component exposes or handles\n emits?: EventMap # events the component raises to its parent\n layout?: CodeBlock # ASCII sketch of visual structure (non-normative)\n```\n\n```mdl\next op\n uri: org.dxos.mdl.op@1.0\n desc: |\n A named operation with typed inputs, outputs, and declared errors.\n Pure ops have no effects or requires. Effectful ops declare both.\n fields:\n desc?: Prose\n input?: FieldMap # named input parameters\n output?: TypeExpr # return type\n errors?: ErrorMap # name: Prose (when this error occurs)\n effects?: EffectList # echo:read | echo:write | http | fs | ...\n requires?: ServiceList # injected service dependencies\n note?: Prose # implementation guidance (non-normative)\n```\n"],
5
- "mappings": ";AAIA,SAASA,cAAc;AACvB,SAASC,iBAAiB;AAE1B,SAASC,cAAcC,oBAAoB;AAC3C,SAASC,YAAY;AACrB,SAASC,oBAAoB;AAC7B,SAASC,aAAa;;;ACVtB;;;ADeO,IAAMC,iBAAiBC,OAAOC,OAAOC,IAAAA,EAAMC,KAChDC,UAAUC,sBAAsB;EAAEC,UAAUC;AAAa,CAAA,GACzDH,UAAUI,gBAAgB;EAAEC,QAAQ;IAACC,MAAMA;;AAAO,CAAA,GAClDN,UAAUO,iBAAiB;EAAEL,UAAUM;AAAa,CAAA,GACpDR,UAAUS,sBAAsB;EAAEC;AAAa,CAAA,GAC/CV,UAAUW,qBAAqB;EAC7BC,OAAO;IAAEC,UAAUf,KAAKgB,QAAQC;IAAKC,MAAM;IAAcC,SAASC;IAAYC,UAAU;EAAoB;AAC9G,CAAA,GACAvB,OAAOwB,IAAI;AAGb,IAAA,yBAAezB;",
6
- "names": ["Plugin", "AppPlugin", "CreateObject", "ReactSurface", "meta", "translations", "Graph", "ExplorerPlugin", "Plugin", "define", "meta", "pipe", "AppPlugin", "addCreateObjectModule", "activate", "CreateObject", "addSchemaModule", "schema", "Graph", "addSurfaceModule", "ReactSurface", "addTranslationsModule", "translations", "addPluginAssetModule", "asset", "pluginId", "profile", "key", "path", "content", "pluginSpec", "mimeType", "make"]
7
- }
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../src/types/ExplorerAction.ts", "../../../src/types/Graph.ts"],
4
- "sourcesContent": ["//\n// Copyright 2023 DXOS.org\n//\n\nimport * as Schema from 'effect/Schema';\n\nimport { TypeInputOptionsAnnotation } from '@dxos/plugin-space';\n\nexport const GraphProps = Schema.Struct({\n name: Schema.optional(Schema.String),\n // TODO(wittjosiah): This should be a query input instead.\n typename: Schema.String.pipe(\n Schema.annotations({ title: 'Select type' }),\n TypeInputOptionsAnnotation.set({\n location: ['database', 'runtime'],\n kind: ['user'],\n }),\n Schema.optional,\n ),\n});\n", "//\n// Copyright 2024 DXOS.org\n//\n\nimport * as Schema from 'effect/Schema';\n\nimport { DXN, Annotation, Filter, Obj, Query, QueryAST, Ref, Type, View } from '@dxos/echo';\nimport { FormInputAnnotation, LabelAnnotation } from '@dxos/echo/Annotation';\nimport { ViewAnnotation } from '@dxos/schema';\n\nconst GraphSchema = Schema.Struct({\n name: Schema.optional(Schema.String),\n view: Ref.Ref(View.View).pipe(FormInputAnnotation.set(false)),\n query: Schema.Struct({\n raw: Schema.optional(Schema.String),\n ast: QueryAST.Query,\n }).pipe(FormInputAnnotation.set(false)),\n}).pipe(\n LabelAnnotation.set(['name']),\n ViewAnnotation.set(['view']),\n Annotation.IconAnnotation.set({ icon: 'ph--graph--regular', hue: 'green' }),\n Type.makeObject(DXN.make('org.dxos.type.graph', '0.1.0')),\n);\n// TODO(wittjosiah): Try to clean up this type inference.\nexport interface Graph extends Type.InstanceType<typeof GraphSchema> {}\nexport const Graph: Type.Obj<Graph> = GraphSchema as any;\n\ntype MakeProps = Omit<Partial<Obj.MakeProps<typeof Graph>>, 'view'> & {\n view: View.View;\n};\n\n/**\n * Make a graph as a view of a data set.\n */\nexport const make = ({\n name,\n query = { raw: '', ast: Query.select(Filter.nothing()).ast },\n view,\n}: MakeProps): Graph => {\n return Obj.make(Graph, { name, view: Ref.make(view), query });\n};\n"],
5
- "mappings": ";;;;;AAAA;;;;AAIA,YAAYA,YAAY;AAExB,SAASC,kCAAkC;AAEpC,IAAMC,aAAoBC,cAAO;EACtCC,MAAaC,gBAAgBC,aAAM;;EAEnCC,UAAiBD,cAAOE,KACfC,mBAAY;IAAEC,OAAO;EAAc,CAAA,GAC1CT,2BAA2BU,IAAI;IAC7BC,UAAU;MAAC;MAAY;;IACvBC,MAAM;MAAC;;EACT,CAAA,GACOR,eAAQ;AAEnB,CAAA;;;ACnBA;;;;;AAIA,YAAYS,aAAY;AAExB,SAASC,KAAKC,YAAYC,QAAQC,KAAKC,OAAOC,UAAUC,KAAKC,MAAMC,YAAY;AAC/E,SAASC,qBAAqBC,uBAAuB;AACrD,SAASC,sBAAsB;AAE/B,IAAMC,cAAqBC,eAAO;EAChCC,MAAaC,iBAAgBC,cAAM;EACnCC,MAAMX,IAAIA,IAAIE,KAAKA,IAAI,EAAEU,KAAKT,oBAAoBU,IAAI,KAAA,CAAA;EACtDC,OAAcP,eAAO;IACnBQ,KAAYN,iBAAgBC,cAAM;IAClCM,KAAKjB,SAASD;EAChB,CAAA,EAAGc,KAAKT,oBAAoBU,IAAI,KAAA,CAAA;AAClC,CAAA,EAAGD,KACDR,gBAAgBS,IAAI;EAAC;CAAO,GAC5BR,eAAeQ,IAAI;EAAC;CAAO,GAC3BlB,WAAWsB,eAAeJ,IAAI;EAAEK,MAAM;EAAsBC,KAAK;AAAQ,CAAA,GACzElB,KAAKmB,WAAW1B,IAAI2B,KAAK,uBAAuB,OAAA,CAAA,CAAA;AAI3C,IAAMC,QAAyBhB;AAS/B,IAAMe,OAAO,CAAC,EACnBb,MACAM,QAAQ;EAAEC,KAAK;EAAIC,KAAKlB,MAAMyB,OAAO3B,OAAO4B,QAAO,CAAA,EAAIR;AAAI,GAC3DL,KAAI,MACM;AACV,SAAOd,IAAIwB,KAAKC,OAAO;IAAEd;IAAMG,MAAMX,IAAIqB,KAAKV,IAAAA;IAAOG;EAAM,CAAA;AAC7D;",
6
- "names": ["Schema", "TypeInputOptionsAnnotation", "GraphProps", "Struct", "name", "optional", "String", "typename", "pipe", "annotations", "title", "set", "location", "kind", "Schema", "DXN", "Annotation", "Filter", "Obj", "Query", "QueryAST", "Ref", "Type", "View", "FormInputAnnotation", "LabelAnnotation", "ViewAnnotation", "GraphSchema", "Struct", "name", "optional", "String", "view", "pipe", "set", "query", "raw", "ast", "IconAnnotation", "icon", "hue", "makeObject", "make", "Graph", "select", "nothing"]
7
- }
@@ -1,26 +0,0 @@
1
- import "./chunk-J5LGTIGS.mjs";
2
-
3
- // src/capabilities/react-surface.tsx
4
- import * as Effect from "effect/Effect";
5
- import React from "react";
6
- import { Capabilities, Capability } from "@dxos/app-framework";
7
- import { Surface } from "@dxos/app-framework/ui";
8
- import { AppSurface } from "@dxos/app-toolkit/ui";
9
- import { ExplorerArticle } from "#containers";
10
- import { Graph } from "#types";
11
- var react_surface_default = Capability.makeModule(() => Effect.succeed(Capability.contributes(Capabilities.ReactSurface, Surface.create({
12
- id: "article",
13
- // TODO(wittjosiah): Split into multiple surfaces if this filter proves too strict for non-article roles.
14
- filter: AppSurface.oneOf(AppSurface.object(AppSurface.Article, Graph.Graph), AppSurface.object(AppSurface.Section, Graph.Graph)),
15
- component: ({ data, role }) => {
16
- return /* @__PURE__ */ React.createElement(ExplorerArticle, {
17
- role,
18
- subject: data.subject,
19
- attendableId: data.attendableId
20
- });
21
- }
22
- }))));
23
- export {
24
- react_surface_default as default
25
- };
26
- //# sourceMappingURL=react-surface-APBW2VQG.mjs.map
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../src/capabilities/react-surface.tsx"],
4
- "sourcesContent": ["//\n// Copyright 2025 DXOS.org\n//\n\nimport * as Effect from 'effect/Effect';\nimport React from 'react';\n\nimport { Capabilities, Capability } from '@dxos/app-framework';\nimport { Surface } from '@dxos/app-framework/ui';\nimport { AppSurface } from '@dxos/app-toolkit/ui';\n\nimport { ExplorerArticle } from '#containers';\nimport { Graph } from '#types';\n\nexport default Capability.makeModule(() =>\n Effect.succeed(\n Capability.contributes(\n Capabilities.ReactSurface,\n Surface.create({\n id: 'article',\n // TODO(wittjosiah): Split into multiple surfaces if this filter proves too strict for non-article roles.\n filter: AppSurface.oneOf(\n AppSurface.object(AppSurface.Article, Graph.Graph),\n AppSurface.object(AppSurface.Section, Graph.Graph),\n ),\n component: ({ data, role }) => {\n return <ExplorerArticle role={role} subject={data.subject} attendableId={data.attendableId} />;\n },\n }),\n ),\n ),\n);\n"],
5
- "mappings": ";;;AAIA,YAAYA,YAAY;AACxB,OAAOC,WAAW;AAElB,SAASC,cAAcC,kBAAkB;AACzC,SAASC,eAAe;AACxB,SAASC,kBAAkB;AAE3B,SAASC,uBAAuB;AAChC,SAASC,aAAa;AAEtB,IAAA,wBAAeJ,WAAWK,WAAW,MAC5BC,eACLN,WAAWO,YACTR,aAAaS,cACbP,QAAQQ,OAAO;EACbC,IAAI;;EAEJC,QAAQT,WAAWU,MACjBV,WAAWW,OAAOX,WAAWY,SAASV,MAAMA,KAAK,GACjDF,WAAWW,OAAOX,WAAWa,SAASX,MAAMA,KAAK,CAAA;EAEnDY,WAAW,CAAC,EAAEC,MAAMC,KAAI,MAAE;AACxB,WAAO,sBAAA,cAACf,iBAAAA;MAAgBe;MAAYC,SAASF,KAAKE;MAASC,cAAcH,KAAKG;;EAChF;AACF,CAAA,CAAA,CAAA,CAAA;",
6
- "names": ["Effect", "React", "Capabilities", "Capability", "Surface", "AppSurface", "ExplorerArticle", "Graph", "makeModule", "succeed", "contributes", "ReactSurface", "create", "id", "filter", "oneOf", "object", "Article", "Section", "component", "data", "role", "subject", "attendableId"]
7
- }
@@ -1,24 +0,0 @@
1
- import React from 'react';
2
- import { type ThemedClassName } from '@dxos/react-ui';
3
- import { type BundleEdge, type TreeLayoutSlots } from './layout';
4
- import { type TreeNode } from './types';
5
- export type LayoutVariant = 'tidy' | 'radial' | 'edge';
6
- export type TreeComponentProps = ThemedClassName<{
7
- data: TreeNode;
8
- /** Optional edges for the `edge` variant (hierarchical edge bundling). */
9
- edges?: BundleEdge[];
10
- variant?: LayoutVariant;
11
- label?: (node: TreeNode) => string;
12
- slots?: TreeLayoutSlots;
13
- initialCollapsed?: Iterable<string>;
14
- onNodeClick?: (node: TreeNode) => void;
15
- onNodeHover?: (node: TreeNode | null, event?: MouseEvent) => void;
16
- }>;
17
- /**
18
- * Tree visualization wrapping the three layout variants.
19
- * - `tidy` — horizontal tidy tree (collapsible)
20
- * - `radial` — radial tree (collapsible)
21
- * - `edge` — hierarchical edge bundling (`edges` connect leaves)
22
- */
23
- export declare const Tree: ({ classNames, data, edges, variant, label, slots, initialCollapsed, onNodeClick, onNodeHover, }: TreeComponentProps) => React.JSX.Element;
24
- //# sourceMappingURL=Tree.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"Tree.d.ts","sourceRoot":"","sources":["../../../../../src/components/Tree/Tree.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAkB,MAAM,OAAO,CAAC;AAEvC,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAEtD,OAAO,EAAE,KAAK,UAAU,EAAkD,KAAK,eAAe,EAAE,MAAM,UAAU,CAAC;AACjH,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,SAAS,CAAC;AAExC,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,QAAQ,GAAG,MAAM,CAAC;AAEvD,MAAM,MAAM,kBAAkB,GAAG,eAAe,CAAC;IAC/C,IAAI,EAAE,QAAQ,CAAC;IACf,0EAA0E;IAC1E,KAAK,CAAC,EAAE,UAAU,EAAE,CAAC;IACrB,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,QAAQ,KAAK,MAAM,CAAC;IACnC,KAAK,CAAC,EAAE,eAAe,CAAC;IACxB,gBAAgB,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IACpC,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,QAAQ,KAAK,IAAI,CAAC;IACvC,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,QAAQ,GAAG,IAAI,EAAE,KAAK,CAAC,EAAE,UAAU,KAAK,IAAI,CAAC;CACnE,CAAC,CAAC;AAEH;;;;;GAKG;AACH,eAAO,MAAM,IAAI,oGAUd,kBAAkB,sBAuCpB,CAAC"}
@@ -1,40 +0,0 @@
1
- import React from 'react';
2
- import { type ThemedClassName } from '@dxos/react-ui';
3
- import { type TreeNode } from '../types';
4
- import { type TreeLayoutSlots } from './slots';
5
- /** A directed edge between two leaves of the hierarchy, identified by node id. */
6
- export type BundleEdge = {
7
- source: string;
8
- target: string;
9
- kind?: string;
10
- };
11
- export type HierarchicalEdgeBundlingProps = ThemedClassName<{
12
- /** Hierarchical data; leaves are the connectable entities. */
13
- data: TreeNode;
14
- /** Edges between leaves (by id). Bundled through the hierarchy. */
15
- edges?: BundleEdge[];
16
- /** Label accessor for leaf nodes. */
17
- label?: (d: TreeNode) => string;
18
- /** Padding (in screen pixels) reserved around the radial layout. */
19
- padding?: number;
20
- /** Bundling tension; 0 = straight, 1 = maximally bundled. */
21
- tension?: number;
22
- /** Leaf node circle radius (matches the cluster layout's `r`). */
23
- r?: number;
24
- slots?: TreeLayoutSlots;
25
- /**
26
- * Called when the user hovers a leaf node (with the event so callers can dispatch
27
- * `DxAnchorActivate` for previews). Receives `null` on leave.
28
- */
29
- onNodeHover?: (node: TreeNode | null, event?: MouseEvent) => void;
30
- }>;
31
- /**
32
- * Hierarchical edge bundling.
33
- * https://observablehq.com/@d3/hierarchical-edge-bundling?intent=fork
34
- *
35
- * Leaves are placed on a circle, grouped by their parent in the hierarchy.
36
- * Edges between leaves are drawn as bundled curves that route through their lowest common ancestor.
37
- */
38
- export declare const HierarchicalEdgeBundling: ({ classNames, data, edges, label, padding, tension, r, slots, onNodeHover, }: HierarchicalEdgeBundlingProps) => React.JSX.Element;
39
- export default HierarchicalEdgeBundling;
40
- //# sourceMappingURL=HierarchicalEdgeBundling.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"HierarchicalEdgeBundling.d.ts","sourceRoot":"","sources":["../../../../../../src/components/Tree/layout/HierarchicalEdgeBundling.tsx"],"names":[],"mappings":"AAOA,OAAO,KAAqC,MAAM,OAAO,CAAC;AAG1D,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAItD,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,KAAK,eAAe,EAA0B,MAAM,SAAS,CAAC;AAKvE,kFAAkF;AAClF,MAAM,MAAM,UAAU,GAAG;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,6BAA6B,GAAG,eAAe,CAAC;IAC1D,8DAA8D;IAC9D,IAAI,EAAE,QAAQ,CAAC;IACf,mEAAmE;IACnE,KAAK,CAAC,EAAE,UAAU,EAAE,CAAC;IACrB,qCAAqC;IACrC,KAAK,CAAC,EAAE,CAAC,CAAC,EAAE,QAAQ,KAAK,MAAM,CAAC;IAChC,oEAAoE;IACpE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,6DAA6D;IAC7D,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,kEAAkE;IAClE,CAAC,CAAC,EAAE,MAAM,CAAC;IACX,KAAK,CAAC,EAAE,eAAe,CAAC;IACxB;;;OAGG;IACH,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,QAAQ,GAAG,IAAI,EAAE,KAAK,CAAC,EAAE,UAAU,KAAK,IAAI,CAAC;CACnE,CAAC,CAAC;AAEH;;;;;;GAMG;AACH,eAAO,MAAM,wBAAwB,iFAUlC,6BAA6B,sBAuC/B,CAAC;eAsOa,wBAAwB"}
@@ -1,37 +0,0 @@
1
- import React from 'react';
2
- import { type ThemedClassName } from '@dxos/react-ui';
3
- import { type TreeNode } from '../types';
4
- import { type TreeLayoutSlots } from './slots';
5
- export type RadialTreeProps = ThemedClassName<{
6
- data: TreeNode;
7
- label?: (d: TreeNode) => string;
8
- slots?: TreeLayoutSlots;
9
- /** Node radius. */
10
- r?: number;
11
- /** Optional padding (in screen pixels) reserved around the radial layout. */
12
- padding?: number;
13
- /** Initial set of collapsed node ids. */
14
- initialCollapsed?: Iterable<string>;
15
- /**
16
- * Use `d3.cluster` (all leaves equidistant from center) instead of `d3.tree`.
17
- * Matches https://observablehq.com/@d3/radial-cluster.
18
- */
19
- cluster?: boolean;
20
- /** Notified when the user clicks a node. */
21
- onNodeClick?: (node: TreeNode) => void;
22
- /**
23
- * Notified on pointerenter (and `null` on pointerleave) for nodes. Used to wire previews
24
- * (dispatch `DxAnchorActivate`). The event target on enter is the hovered circle — dispatch
25
- * from it so the preview anchors there.
26
- */
27
- onNodeHover?: (node: TreeNode | null, event?: MouseEvent) => void;
28
- }>;
29
- /**
30
- * Radial tree layout based on the D3 reference component.
31
- * https://observablehq.com/@d3/radial-tree-component
32
- *
33
- * Click a node with children to toggle collapse / expand.
34
- */
35
- export declare const RadialTree: ({ classNames, data, label, slots, r, padding, initialCollapsed, cluster, onNodeClick, onNodeHover, }: RadialTreeProps) => React.JSX.Element;
36
- export default RadialTree;
37
- //# sourceMappingURL=RadialTree.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"RadialTree.d.ts","sourceRoot":"","sources":["../../../../../../src/components/Tree/layout/RadialTree.tsx"],"names":[],"mappings":"AAMA,OAAO,KAA4D,MAAM,OAAO,CAAC;AAGjF,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAItD,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,UAAU,CAAC;AAEzC,OAAO,EAAE,KAAK,eAAe,EAA0B,MAAM,SAAS,CAAC;AAKvE,MAAM,MAAM,eAAe,GAAG,eAAe,CAAC;IAC5C,IAAI,EAAE,QAAQ,CAAC;IACf,KAAK,CAAC,EAAE,CAAC,CAAC,EAAE,QAAQ,KAAK,MAAM,CAAC;IAChC,KAAK,CAAC,EAAE,eAAe,CAAC;IACxB,mBAAmB;IACnB,CAAC,CAAC,EAAE,MAAM,CAAC;IACX,6EAA6E;IAC7E,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,yCAAyC;IACzC,gBAAgB,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IACpC;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,4CAA4C;IAC5C,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,QAAQ,KAAK,IAAI,CAAC;IACvC;;;;OAIG;IACH,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,QAAQ,GAAG,IAAI,EAAE,KAAK,CAAC,EAAE,UAAU,KAAK,IAAI,CAAC;CACnE,CAAC,CAAC;AAEH;;;;;GAKG;AACH,eAAO,MAAM,UAAU,yGAWpB,eAAe,sBA6DjB,CAAC;eAsHa,UAAU"}
@@ -1,26 +0,0 @@
1
- import React from 'react';
2
- import { type ThemedClassName } from '@dxos/react-ui';
3
- import { type TreeNode } from '../types';
4
- import { type TreeLayoutSlots } from './slots';
5
- export type TidyTreeProps = ThemedClassName<{
6
- data: TreeNode;
7
- label?: (d: TreeNode) => string;
8
- slots?: TreeLayoutSlots;
9
- /** Node radius. */
10
- r?: number;
11
- /** Margin in screen pixels reserved around the layout. */
12
- margin?: number;
13
- /** Initial set of collapsed node ids. */
14
- initialCollapsed?: Iterable<string>;
15
- /** Notified when the user clicks a node. */
16
- onNodeClick?: (node: TreeNode) => void;
17
- }>;
18
- /**
19
- * Tidy (horizontal) tree layout based on the D3 reference component.
20
- * https://observablehq.com/@d3/tree-component
21
- *
22
- * Click a node with children to toggle collapse / expand.
23
- */
24
- export declare const TidyTree: ({ classNames, data, label, slots, r, margin, initialCollapsed, onNodeClick, }: TidyTreeProps) => React.JSX.Element;
25
- export default TidyTree;
26
- //# sourceMappingURL=TidyTree.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"TidyTree.d.ts","sourceRoot":"","sources":["../../../../../../src/components/Tree/layout/TidyTree.tsx"],"names":[],"mappings":"AAMA,OAAO,KAA4D,MAAM,OAAO,CAAC;AAEjF,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAGtD,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,UAAU,CAAC;AAEzC,OAAO,EAAE,KAAK,eAAe,EAA0B,MAAM,SAAS,CAAC;AAKvE,MAAM,MAAM,aAAa,GAAG,eAAe,CAAC;IAC1C,IAAI,EAAE,QAAQ,CAAC;IACf,KAAK,CAAC,EAAE,CAAC,CAAC,EAAE,QAAQ,KAAK,MAAM,CAAC;IAChC,KAAK,CAAC,EAAE,eAAe,CAAC;IACxB,mBAAmB;IACnB,CAAC,CAAC,EAAE,MAAM,CAAC;IACX,0DAA0D;IAC1D,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,yCAAyC;IACzC,gBAAgB,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IACpC,4CAA4C;IAC5C,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,QAAQ,KAAK,IAAI,CAAC;CACxC,CAAC,CAAC;AAEH;;;;;GAKG;AACH,eAAO,MAAM,QAAQ,kFASlB,aAAa,sBA0Df,CAAC;eA4Ia,QAAQ"}
@@ -1,17 +0,0 @@
1
- import { type HierarchyNode } from 'd3';
2
- import { type TreeNode } from '../types';
3
- /**
4
- * Build a d3 hierarchy from a TreeNode, pruning children of nodes whose ids are in `collapsed`.
5
- * Nodes that have children but are collapsed retain their identity in the hierarchy and can be
6
- * distinguished by `node._children` (the original list).
7
- */
8
- export declare const buildHierarchy: (data: TreeNode, collapsed?: Set<string>) => HierarchyNode<TreeNode>;
9
- /**
10
- * True when the node has children that have been hidden via collapse.
11
- */
12
- export declare const isCollapsed: (data: TreeNode, collapsed: Set<string>) => boolean;
13
- /**
14
- * True when the node has no children at all (a real leaf, not a collapsed branch).
15
- */
16
- export declare const isLeaf: (data: TreeNode) => boolean;
17
- //# sourceMappingURL=hierarchy.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"hierarchy.d.ts","sourceRoot":"","sources":["../../../../../../src/components/Tree/layout/hierarchy.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,aAAa,EAA4B,MAAM,IAAI,CAAC;AAElE,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,UAAU,CAAC;AAEzC;;;;GAIG;AACH,eAAO,MAAM,cAAc,SAAU,QAAQ,cAAa,GAAG,CAAC,MAAM,CAAC,KAAe,aAAa,CAAC,QAAQ,CAOzG,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,WAAW,SAAU,QAAQ,aAAa,GAAG,CAAC,MAAM,CAAC,KAAG,OACX,CAAC;AAE3D;;GAEG;AACH,eAAO,MAAM,MAAM,SAAU,QAAQ,KAAG,OAAiC,CAAC"}
@@ -1,6 +0,0 @@
1
- export * from './HierarchicalEdgeBundling';
2
- export * from './RadialTree';
3
- export * from './TidyTree';
4
- export * from './hierarchy';
5
- export * from './slots';
6
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../src/components/Tree/layout/index.ts"],"names":[],"mappings":"AAIA,cAAc,4BAA4B,CAAC;AAC3C,cAAc,cAAc,CAAC;AAC7B,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,SAAS,CAAC"}
@@ -1,7 +0,0 @@
1
- export type TreeLayoutSlots = {
2
- node?: string;
3
- path?: string;
4
- text?: string;
5
- };
6
- export declare const defaultTreeLayoutSlots: TreeLayoutSlots;
7
- //# sourceMappingURL=slots.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"slots.d.ts","sourceRoot":"","sources":["../../../../../../src/components/Tree/layout/slots.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,eAAe,GAAG;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,eAAO,MAAM,sBAAsB,EAAE,eAQpC,CAAC"}
@@ -1,15 +0,0 @@
1
- /**
2
- * Track an element's content-box size via ResizeObserver.
3
- * Returns the most recently observed `{ width, height }` plus a callback ref to attach to the element.
4
- *
5
- * Why not `react-resize-detector` directly: its `targetRef` API doesn't pick up a ref whose
6
- * `.current` is set later than the hook runs, and the returned-`ref` API forces the consumer to
7
- * forward a callback ref through their own component — which is awkward for class refs.
8
- * This hook returns a setter so the consumer assigns it directly to `<div ref={setRef}>`.
9
- */
10
- export declare const useContainerSize: () => {
11
- setRef: (el: HTMLDivElement | null) => void;
12
- width: number;
13
- height: number;
14
- };
15
- //# sourceMappingURL=useContainerSize.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"useContainerSize.d.ts","sourceRoot":"","sources":["../../../../../../src/components/Tree/layout/useContainerSize.ts"],"names":[],"mappings":"AAMA;;;;;;;;GAQG;AACH,eAAO,MAAM,gBAAgB,QAAO;IAClC,MAAM,EAAE,CAAC,EAAE,EAAE,cAAc,GAAG,IAAI,KAAK,IAAI,CAAC;IAC5C,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAwBhB,CAAC"}
@@ -1,18 +0,0 @@
1
- import React from 'react';
2
- import { type ThemedClassName } from '@dxos/react-ui';
3
- import { type SpaceGraphModel } from '@dxos/schema';
4
- import { type TreeNode } from '#components';
5
- import { type ExplorerArticleVariant } from './variants';
6
- export type VisualizationProps = ThemedClassName<{
7
- debug?: boolean;
8
- variant: ExplorerArticleVariant;
9
- model: SpaceGraphModel;
10
- onNodeHover?: (node: TreeNode | null, event?: MouseEvent) => void;
11
- /** Called when the user clicks the visualization surface (e.g. to dismiss a node preview). */
12
- onSurfaceClick?: () => void;
13
- }>;
14
- /**
15
- * Renders the active visualization variant.
16
- */
17
- export declare const Visualization: ({ classNames, debug, variant, model, onNodeHover, onSurfaceClick, }: VisualizationProps) => React.JSX.Element;
18
- //# sourceMappingURL=Visualization.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"Visualization.d.ts","sourceRoot":"","sources":["../../../../../src/containers/ExplorerArticle/Visualization.tsx"],"names":[],"mappings":"AAKA,OAAO,KAA4D,MAAM,OAAO,CAAC;AAGjF,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,gBAAgB,CAAC;AA0BtD,OAAO,EAAuB,KAAK,eAAe,EAAuB,MAAM,cAAc,CAAC;AAG9F,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,aAAa,CAAC;AAG5C,OAAO,EAAE,KAAK,sBAAsB,EAAE,MAAM,YAAY,CAAC;AAEzD,MAAM,MAAM,kBAAkB,GAAG,eAAe,CAAC;IAC/C,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,sBAAsB,CAAC;IAChC,KAAK,EAAE,eAAe,CAAC;IACvB,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,QAAQ,GAAG,IAAI,EAAE,KAAK,CAAC,EAAE,UAAU,KAAK,IAAI,CAAC;IAClE,8FAA8F;IAC9F,cAAc,CAAC,EAAE,MAAM,IAAI,CAAC;CAC7B,CAAC,CAAC;AAEH;;GAEG;AACH,eAAO,MAAM,aAAa,wEAOvB,kBAAkB,sBAiHpB,CAAC"}
@@ -1,9 +0,0 @@
1
- /** Visualization variants exposed by `ExplorerArticle`. */
2
- export type ExplorerArticleVariant = 'force' | 'cluster' | 'bundle' | 'lattice' | 'swarm' | 'plexus';
3
- export declare const VARIANTS: {
4
- value: ExplorerArticleVariant;
5
- icon: string;
6
- label: string;
7
- }[];
8
- export declare const isVariant: (value: unknown) => value is ExplorerArticleVariant;
9
- //# sourceMappingURL=variants.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"variants.d.ts","sourceRoot":"","sources":["../../../../../src/containers/ExplorerArticle/variants.ts"],"names":[],"mappings":"AAIA,2DAA2D;AAC3D,MAAM,MAAM,sBAAsB,GAAG,OAAO,GAAG,SAAS,GAAG,QAAQ,GAAG,SAAS,GAAG,OAAO,GAAG,QAAQ,CAAC;AAErG,eAAO,MAAM,QAAQ,EAAE;IAAE,KAAK,EAAE,sBAAsB,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,EA+BpF,CAAC;AAEF,eAAO,MAAM,SAAS,UAAW,OAAO,KAAG,KAAK,IAAI,sBAMhC,CAAC"}