@dxos/plugin-navtree 0.8.4-main.1f223c7 → 0.8.4-main.2244d791bb

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 (178) hide show
  1. package/dist/lib/browser/app-graph-builder-XGA4GPGL.mjs +44 -0
  2. package/dist/lib/browser/app-graph-builder-XGA4GPGL.mjs.map +7 -0
  3. package/dist/lib/browser/chunk-63YLDLLE.mjs +1373 -0
  4. package/dist/lib/browser/chunk-63YLDLLE.mjs.map +7 -0
  5. package/dist/lib/browser/chunk-X2HDG62A.mjs +23 -0
  6. package/dist/lib/browser/chunk-X2HDG62A.mjs.map +7 -0
  7. package/dist/lib/browser/chunk-YKTYPINZ.mjs +19 -0
  8. package/dist/lib/browser/chunk-YKTYPINZ.mjs.map +7 -0
  9. package/dist/lib/browser/index.mjs +83 -93
  10. package/dist/lib/browser/index.mjs.map +4 -4
  11. package/dist/lib/browser/{keyboard-HMTMA33N.mjs → keyboard-46XQHY2O.mjs} +21 -19
  12. package/dist/lib/browser/keyboard-46XQHY2O.mjs.map +7 -0
  13. package/dist/lib/browser/meta.json +1 -1
  14. package/dist/lib/browser/operation-resolver-NNNDII45.mjs +53 -0
  15. package/dist/lib/browser/operation-resolver-NNNDII45.mjs.map +7 -0
  16. package/dist/lib/browser/react-surface-APSEG23H.mjs +59 -0
  17. package/dist/lib/browser/react-surface-APSEG23H.mjs.map +7 -0
  18. package/dist/lib/browser/state-M5YUCIQU.mjs +121 -0
  19. package/dist/lib/browser/state-M5YUCIQU.mjs.map +7 -0
  20. package/dist/types/src/NavTreePlugin.d.ts +2 -1
  21. package/dist/types/src/NavTreePlugin.d.ts.map +1 -1
  22. package/dist/types/src/capabilities/app-graph-builder/app-graph-builder.d.ts +6 -0
  23. package/dist/types/src/capabilities/app-graph-builder/app-graph-builder.d.ts.map +1 -0
  24. package/dist/types/src/capabilities/app-graph-builder/index.d.ts +3 -0
  25. package/dist/types/src/capabilities/app-graph-builder/index.d.ts.map +1 -0
  26. package/dist/types/src/capabilities/index.d.ts +5 -105
  27. package/dist/types/src/capabilities/index.d.ts.map +1 -1
  28. package/dist/types/src/capabilities/keyboard/index.d.ts +3 -0
  29. package/dist/types/src/capabilities/keyboard/index.d.ts.map +1 -0
  30. package/dist/types/src/capabilities/keyboard/keyboard.d.ts +5 -0
  31. package/dist/types/src/capabilities/keyboard/keyboard.d.ts.map +1 -0
  32. package/dist/types/src/capabilities/operation-resolver/index.d.ts +3 -0
  33. package/dist/types/src/capabilities/operation-resolver/index.d.ts.map +1 -0
  34. package/dist/types/src/capabilities/operation-resolver/operation-resolver.d.ts +5 -0
  35. package/dist/types/src/capabilities/operation-resolver/operation-resolver.d.ts.map +1 -0
  36. package/dist/types/src/capabilities/react-surface/index.d.ts +3 -0
  37. package/dist/types/src/capabilities/react-surface/index.d.ts.map +1 -0
  38. package/dist/types/src/capabilities/react-surface/react-surface.d.ts +5 -0
  39. package/dist/types/src/capabilities/react-surface/react-surface.d.ts.map +1 -0
  40. package/dist/types/src/capabilities/state/index.d.ts +3 -0
  41. package/dist/types/src/capabilities/state/index.d.ts.map +1 -0
  42. package/dist/types/src/capabilities/state/state.d.ts +6 -0
  43. package/dist/types/src/capabilities/state/state.d.ts.map +1 -0
  44. package/dist/types/src/components/CommandsDialog/CommandsDialog.d.ts +3 -2
  45. package/dist/types/src/components/CommandsDialog/CommandsDialog.d.ts.map +1 -1
  46. package/dist/types/src/components/CommandsDialog/CommandsTrigger.d.ts.map +1 -1
  47. package/dist/types/src/components/NavTree/NavTree.d.ts +30 -1
  48. package/dist/types/src/components/NavTree/NavTree.d.ts.map +1 -1
  49. package/dist/types/src/components/NavTree/NavTree.stories.d.ts +5 -3
  50. package/dist/types/src/components/NavTree/NavTree.stories.d.ts.map +1 -1
  51. package/dist/types/src/components/NavTreeContainer.d.ts +8 -1
  52. package/dist/types/src/components/NavTreeContainer.d.ts.map +1 -1
  53. package/dist/types/src/components/NavTreeDocumentTitle.d.ts +1 -1
  54. package/dist/types/src/components/NavTreeDocumentTitle.d.ts.map +1 -1
  55. package/dist/types/src/components/NavTreeItem/NavTreeItemAction.d.ts +6 -6
  56. package/dist/types/src/components/NavTreeItem/NavTreeItemAction.d.ts.map +1 -1
  57. package/dist/types/src/components/NavTreeItem/NavTreeItemAction.stories.d.ts +3 -3
  58. package/dist/types/src/components/NavTreeItem/NavTreeItemAction.stories.d.ts.map +1 -1
  59. package/dist/types/src/components/NavTreeItem/NavTreeItemColumns.d.ts +1 -1
  60. package/dist/types/src/components/NavTreeItem/NavTreeItemColumns.d.ts.map +1 -1
  61. package/dist/types/src/components/Sidebar/L0Menu.d.ts +6 -4
  62. package/dist/types/src/components/Sidebar/L0Menu.d.ts.map +1 -1
  63. package/dist/types/src/components/Sidebar/L1Panel.d.ts +2 -2
  64. package/dist/types/src/components/Sidebar/L1Panel.d.ts.map +1 -1
  65. package/dist/types/src/components/Sidebar/L1Tabs.d.ts +2 -2
  66. package/dist/types/src/components/Sidebar/L1Tabs.d.ts.map +1 -1
  67. package/dist/types/src/components/UserAccountAvatar/UserAccountAvatar.d.ts.map +1 -1
  68. package/dist/types/src/components/UserAccountAvatar/UserAccountAvatar.stories.d.ts +1 -2
  69. package/dist/types/src/components/UserAccountAvatar/UserAccountAvatar.stories.d.ts.map +1 -1
  70. package/dist/types/src/components/index.d.ts.map +1 -1
  71. package/dist/types/src/components/types.d.ts +7 -7
  72. package/dist/types/src/components/types.d.ts.map +1 -1
  73. package/dist/types/src/experimental/Tree.d.ts +1 -2
  74. package/dist/types/src/experimental/Tree.d.ts.map +1 -1
  75. package/dist/types/src/experimental/Tree.stories.d.ts +18 -5
  76. package/dist/types/src/experimental/Tree.stories.d.ts.map +1 -1
  77. package/dist/types/src/hooks.d.ts +32 -1
  78. package/dist/types/src/hooks.d.ts.map +1 -1
  79. package/dist/types/src/index.d.ts +1 -2
  80. package/dist/types/src/index.d.ts.map +1 -1
  81. package/dist/types/src/meta.d.ts +3 -4
  82. package/dist/types/src/meta.d.ts.map +1 -1
  83. package/dist/types/src/testing/app-graph-builder.d.ts +2 -3
  84. package/dist/types/src/testing/app-graph-builder.d.ts.map +1 -1
  85. package/dist/types/src/testing/generator.d.ts +5 -6
  86. package/dist/types/src/testing/generator.d.ts.map +1 -1
  87. package/dist/types/src/testing/update-state.d.ts +2 -2
  88. package/dist/types/src/testing/update-state.d.ts.map +1 -1
  89. package/dist/types/src/types/capabilities.d.ts +16 -0
  90. package/dist/types/src/types/capabilities.d.ts.map +1 -0
  91. package/dist/types/src/types/events.d.ts +5 -0
  92. package/dist/types/src/types/events.d.ts.map +1 -0
  93. package/dist/types/src/types/index.d.ts +4 -0
  94. package/dist/types/src/types/index.d.ts.map +1 -0
  95. package/dist/types/src/{types.d.ts → types/schema.d.ts} +10 -9
  96. package/dist/types/src/types/schema.d.ts.map +1 -0
  97. package/dist/types/src/util.d.ts +7 -7
  98. package/dist/types/src/util.d.ts.map +1 -1
  99. package/dist/types/tsconfig.tsbuildinfo +1 -1
  100. package/package.json +55 -53
  101. package/src/NavTreePlugin.tsx +63 -83
  102. package/src/capabilities/app-graph-builder/app-graph-builder.ts +42 -0
  103. package/src/capabilities/app-graph-builder/index.ts +7 -0
  104. package/src/capabilities/index.ts +5 -9
  105. package/src/capabilities/keyboard/index.ts +7 -0
  106. package/src/capabilities/keyboard/keyboard.ts +66 -0
  107. package/src/capabilities/operation-resolver/index.ts +7 -0
  108. package/src/capabilities/operation-resolver/operation-resolver.ts +42 -0
  109. package/src/capabilities/react-surface/index.ts +7 -0
  110. package/src/capabilities/react-surface/react-surface.tsx +55 -0
  111. package/src/capabilities/state/index.ts +7 -0
  112. package/src/capabilities/state/state.ts +122 -0
  113. package/src/components/CommandsDialog/CommandsDialog.tsx +108 -98
  114. package/src/components/CommandsDialog/CommandsTrigger.tsx +6 -15
  115. package/src/components/NavTree/NavTree.stories.tsx +95 -89
  116. package/src/components/NavTree/NavTree.tsx +9 -15
  117. package/src/components/NavTreeContainer.tsx +256 -257
  118. package/src/components/NavTreeDocumentTitle.tsx +5 -4
  119. package/src/components/NavTreeItem/NavTreeItemAction.stories.tsx +18 -10
  120. package/src/components/NavTreeItem/NavTreeItemAction.tsx +23 -16
  121. package/src/components/NavTreeItem/NavTreeItemColumns.tsx +32 -26
  122. package/src/components/Sidebar/L0Menu.tsx +113 -141
  123. package/src/components/Sidebar/L1Panel.tsx +155 -77
  124. package/src/components/Sidebar/L1Tabs.tsx +6 -31
  125. package/src/components/UserAccountAvatar/UserAccountAvatar.stories.tsx +3 -4
  126. package/src/components/UserAccountAvatar/UserAccountAvatar.tsx +20 -12
  127. package/src/components/index.ts +1 -0
  128. package/src/components/types.ts +7 -7
  129. package/src/experimental/Tree.stories.tsx +67 -77
  130. package/src/experimental/Tree.tsx +7 -24
  131. package/src/hooks.ts +54 -2
  132. package/src/index.ts +1 -2
  133. package/src/meta.ts +11 -8
  134. package/src/testing/app-graph-builder.ts +159 -234
  135. package/src/testing/generator.ts +20 -18
  136. package/src/testing/update-state.ts +6 -6
  137. package/src/types/capabilities.ts +21 -0
  138. package/src/types/events.ts +12 -0
  139. package/src/types/index.ts +7 -0
  140. package/src/{types.ts → types/schema.ts} +9 -8
  141. package/src/util.ts +13 -16
  142. package/dist/lib/browser/app-graph-builder-6JDBQ25U.mjs +0 -45
  143. package/dist/lib/browser/app-graph-builder-6JDBQ25U.mjs.map +0 -7
  144. package/dist/lib/browser/chunk-ERDGQTH5.mjs +0 -16
  145. package/dist/lib/browser/chunk-ERDGQTH5.mjs.map +0 -7
  146. package/dist/lib/browser/chunk-WCARAZ7J.mjs +0 -15
  147. package/dist/lib/browser/chunk-WCARAZ7J.mjs.map +0 -7
  148. package/dist/lib/browser/chunk-ZKVY35IG.mjs +0 -1469
  149. package/dist/lib/browser/chunk-ZKVY35IG.mjs.map +0 -7
  150. package/dist/lib/browser/intent-resolver-N35ZIHFD.mjs +0 -47
  151. package/dist/lib/browser/intent-resolver-N35ZIHFD.mjs.map +0 -7
  152. package/dist/lib/browser/keyboard-HMTMA33N.mjs.map +0 -7
  153. package/dist/lib/browser/react-surface-5PZ4XJT7.mjs +0 -51
  154. package/dist/lib/browser/react-surface-5PZ4XJT7.mjs.map +0 -7
  155. package/dist/lib/browser/state-P5DGL7KS.mjs +0 -117
  156. package/dist/lib/browser/state-P5DGL7KS.mjs.map +0 -7
  157. package/dist/types/src/capabilities/app-graph-builder.d.ts +0 -4
  158. package/dist/types/src/capabilities/app-graph-builder.d.ts.map +0 -1
  159. package/dist/types/src/capabilities/capabilities.d.ts +0 -21
  160. package/dist/types/src/capabilities/capabilities.d.ts.map +0 -1
  161. package/dist/types/src/capabilities/intent-resolver.d.ts +0 -4
  162. package/dist/types/src/capabilities/intent-resolver.d.ts.map +0 -1
  163. package/dist/types/src/capabilities/keyboard.d.ts +0 -4
  164. package/dist/types/src/capabilities/keyboard.d.ts.map +0 -1
  165. package/dist/types/src/capabilities/react-surface.d.ts +0 -4
  166. package/dist/types/src/capabilities/react-surface.d.ts.map +0 -1
  167. package/dist/types/src/capabilities/state.d.ts +0 -20
  168. package/dist/types/src/capabilities/state.d.ts.map +0 -1
  169. package/dist/types/src/events.d.ts +0 -4
  170. package/dist/types/src/events.d.ts.map +0 -1
  171. package/dist/types/src/types.d.ts.map +0 -1
  172. package/src/capabilities/app-graph-builder.ts +0 -52
  173. package/src/capabilities/capabilities.ts +0 -20
  174. package/src/capabilities/intent-resolver.ts +0 -37
  175. package/src/capabilities/keyboard.ts +0 -59
  176. package/src/capabilities/react-surface.tsx +0 -45
  177. package/src/capabilities/state.ts +0 -105
  178. package/src/events.ts +0 -11
@@ -5,29 +5,21 @@
5
5
  import React, { type HTMLAttributes, type PropsWithChildren } from 'react';
6
6
 
7
7
  import { type ClassNameValue, Icon, type Size } from '@dxos/react-ui';
8
- import { mx } from '@dxos/react-ui-theme';
9
-
10
- // TODO(burdon): Rounded border if first/last.
11
- const styles = {
12
- hover: 'hover:bg-slate-400 dark:hover:bg-slate-800',
13
- selected: '!bg-slate-300 dark:!bg-slate-700',
14
- };
8
+ import { mx } from '@dxos/ui-theme';
15
9
 
16
10
  export const IconButton = ({
17
11
  iconName,
18
12
  classNames,
19
13
  size = 4,
20
14
  onClick,
21
- weight = 'regular',
22
15
  }: {
23
16
  iconName: string;
24
17
  classNames?: ClassNameValue;
25
18
  size?: Size;
26
- weight?: 'regular' | 'duotone' | 'fill';
27
19
  } & Pick<HTMLAttributes<HTMLDivElement>, 'onClick'>) => {
28
20
  // TODO(burdon): Density aware.
29
21
  return (
30
- <div className={mx('flex w-6 h-6 items-center justify-center select-none', classNames)} onClick={onClick}>
22
+ <div className={mx('flex is-6 bs-6 items-center justify-center select-none', classNames)} onClick={onClick}>
31
23
  <Icon icon={iconName} classNames='cursor-pointer' size={size} />
32
24
  </div>
33
25
  );
@@ -124,7 +116,6 @@ const StateIcon = ({ node, open, selected, active }: TreeNodeProps) => {
124
116
  <IconButton
125
117
  iconName={isActive ? 'ph--user-circle--regular' : 'ph--circle--regular'}
126
118
  size={4}
127
- weight={selected?.[id] ? 'fill' : 'duotone'}
128
119
  classNames={mx(
129
120
  'text-slate-500',
130
121
  !isChildActive && 'opacity-0 transition duration-500',
@@ -158,15 +149,7 @@ const OpenIcon = ({
158
149
  const ItemIcon = ({
159
150
  node: { children, iconName = children?.length ? 'ph--folder--regular' : 'ph--file--regular', color },
160
151
  }: Pick<TreeNodeProps, 'node'>) => {
161
- return (
162
- (iconName && (
163
- <IconButton
164
- iconName={iconName}
165
- classNames={color ?? 'text-neutral-700 dark:text-neutral-300'}
166
- weight={color ? 'duotone' : 'regular'}
167
- />
168
- )) || <div />
169
- );
152
+ return (iconName && <IconButton iconName={iconName} classNames={color ?? 'text-subdued'} />) || <div />;
170
153
  };
171
154
 
172
155
  const MenuItem = ({ node: { id }, onMenuAction }: Pick<TreeNodeProps, 'node' | 'onMenuAction'>) => {
@@ -210,9 +193,9 @@ export const TreeNodeRow = (props: TreeNodeProps & { className?: string }) => {
210
193
  <Grid
211
194
  style={{ paddingLeft: `${(depth - 1) * 24}px` }}
212
195
  className={mx(
213
- 'group w-full items-center cursor-pointer',
214
- styles.hover,
215
- selected?.[id] && styles.selected,
196
+ 'group is-full items-center cursor-pointer bg-hoverSurface',
197
+ // TODO(burdon): Use data-active.
198
+ selected?.[id] && 'bg-activeSurface',
216
199
  className,
217
200
  )}
218
201
  onClick={() => selected && onChangeSelected?.(id, !selected[id])}
@@ -255,7 +238,7 @@ export const TreeChildNodes = ({
255
238
  } = props;
256
239
  return (
257
240
  <div className={mx('flex flex-col mt-0.5 gap-0.5', className)}>
258
- {children?.map((child, i) => (
241
+ {children?.map((child) => (
259
242
  <TreeNode key={child.id} {...props} depth={depth + 1} node={child} ancestors={[...ancestors, props.node]} />
260
243
  ))}
261
244
  </div>
package/src/hooks.ts CHANGED
@@ -2,13 +2,16 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import { useEffect } from 'react';
5
+ import { type Atom, useAtomValue } from '@effect-atom/atom-react';
6
+ import { useEffect, useMemo } from 'react';
6
7
 
8
+ import { useCapability } from '@dxos/app-framework/ui';
7
9
  import { type Node } from '@dxos/app-graph';
8
10
 
9
11
  import { useNavTreeContext } from './components';
12
+ import { NavTreeCapabilities } from './types';
10
13
 
11
- export const useLoadDescendents = (root?: Node) => {
14
+ export const useLoadDescendents = (root?: Node.Node) => {
12
15
  const { loadDescendents } = useNavTreeContext();
13
16
  useEffect(() => {
14
17
  const frame = requestAnimationFrame(() => {
@@ -19,3 +22,52 @@ export const useLoadDescendents = (root?: Node) => {
19
22
  return () => cancelAnimationFrame(frame);
20
23
  }, [root]);
21
24
  };
25
+
26
+ export type UseNavTreeStateResult = {
27
+ getItem: (path: string[]) => NavTreeCapabilities.NavTreeItemState;
28
+ getItemAtom: (path: string[]) => Atom.Atom<NavTreeCapabilities.NavTreeItemState>;
29
+ setItem: (path: string[], key: 'open' | 'current' | 'alternateTree', next: boolean) => void;
30
+ };
31
+
32
+ /**
33
+ * Hook that provides access to navtree state functions.
34
+ * For reactive subscriptions, use `useNavTreeItemState` or `useAtomValue(getItemAtom(path))`.
35
+ */
36
+ export const useNavTreeState = (): UseNavTreeStateResult => {
37
+ return useCapability(NavTreeCapabilities.State);
38
+ };
39
+
40
+ /**
41
+ * Hook that subscribes to a single navtree item's state.
42
+ * Use this for fine-grained reactivity.
43
+ */
44
+ export const useNavTreeItemState = (path: string[]): NavTreeCapabilities.NavTreeItemState => {
45
+ const { getItemAtom } = useCapability(NavTreeCapabilities.State);
46
+ // Memoize the path to avoid creating new atoms on every render.
47
+ const pathKey = useMemo(() => path.join('~'), [path]);
48
+ const atom = useMemo(() => getItemAtom(path), [getItemAtom, pathKey]);
49
+ return useAtomValue(atom);
50
+ };
51
+
52
+ /**
53
+ * Hook that subscribes to the open state for a tree item.
54
+ * Designed to be passed to Tree component as useIsOpen prop.
55
+ */
56
+ export const useIsOpen = (path: string[], _item?: any): boolean => {
57
+ return useNavTreeItemState(path).open;
58
+ };
59
+
60
+ /**
61
+ * Hook that subscribes to the current state for a tree item.
62
+ * Designed to be passed to Tree component as useIsCurrent prop.
63
+ */
64
+ export const useIsCurrent = (path: string[], _item?: any): boolean => {
65
+ return useNavTreeItemState(path).current;
66
+ };
67
+
68
+ /**
69
+ * Hook that subscribes to the alternateTree state for a tree item.
70
+ */
71
+ export const useIsAlternateTree = (path: string[], _item?: any): boolean => {
72
+ return useNavTreeItemState(path).alternateTree ?? false;
73
+ };
package/src/index.ts CHANGED
@@ -2,8 +2,7 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
- export { NavTreeCapabilities } from './capabilities';
6
- export { NavTreeEvents } from './events';
5
+ export { NavTreeCapabilities, NavTreeEvents } from './types';
7
6
  export * from './NavTreePlugin';
8
7
  export * from './meta';
9
8
  export * from './util';
package/src/meta.ts CHANGED
@@ -2,16 +2,19 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
- import { type PluginMeta } from '@dxos/app-framework';
5
+ import { type Plugin } from '@dxos/app-framework';
6
+ import { trim } from '@dxos/util';
6
7
 
7
- export const NAVTREE_PLUGIN = 'dxos.org/plugin/navtree';
8
+ export const meta: Plugin.Meta = {
9
+ id: 'dxos.org/plugin/navtree',
10
+ name: 'Navtree',
11
+ description: trim`
12
+ Hierarchical navigation tree for browsing spaces, folders, and objects.
13
+ Provides sidebar navigation with collapsible sections and quick access to workspace content.
14
+ `,
15
+ };
8
16
 
9
17
  // TODO(wittjosiah): Factor out.
10
18
  export const KEY_BINDING = 'KeyBinding';
11
19
  // TODO(wittjosiah): Factor out.
12
- export const COMMANDS_DIALOG = `${NAVTREE_PLUGIN}/CommandsDialog`;
13
-
14
- export const meta: PluginMeta = {
15
- id: NAVTREE_PLUGIN,
16
- name: 'Navtree',
17
- };
20
+ export const COMMANDS_DIALOG = `${meta.id}/CommandsDialog`;
@@ -2,15 +2,15 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import { Rx } from '@effect-rx/rx-react';
6
- import { Option, pipe } from 'effect';
5
+ import { Atom } from '@effect-atom/atom-react';
6
+ import * as Effect from 'effect/Effect';
7
7
 
8
- import { type PluginContext } from '@dxos/app-framework';
8
+ import { type BuilderExtensions } from '@dxos/app-graph';
9
9
  import { log } from '@dxos/log';
10
- import { type BuilderExtensions, ROOT_ID, createExtension } from '@dxos/plugin-graph';
10
+ import { GraphBuilder, NodeMatcher } from '@dxos/plugin-graph';
11
11
  import { faker } from '@dxos/random';
12
12
 
13
- export const storybookGraphBuilders = (context: PluginContext): BuilderExtensions => {
13
+ export const storybookGraphBuilders = (): BuilderExtensions => {
14
14
  const propertiesCache = new Map<string, Record<string, unknown>>();
15
15
  const getProperties = (id: string, defaults: Record<string, unknown>) => {
16
16
  const cached = propertiesCache.get(id);
@@ -22,249 +22,174 @@ export const storybookGraphBuilders = (context: PluginContext): BuilderExtension
22
22
  return defaults;
23
23
  };
24
24
 
25
- return [
26
- // Create app menu actions.
27
- createExtension({
28
- id: 'app-menu',
29
- actions: (node) =>
30
- Rx.make((get) =>
31
- pipe(
32
- get(node),
33
- Option.flatMap((node) => (node.id === ROOT_ID ? Option.some(node) : Option.none())),
34
- Option.map((node) => {
35
- return [
36
- ...Array.from({ length: 5 }, (_, i) => ({
37
- id: `${node.id}/action-${i}`,
38
- data: () => {
39
- log.info('action', { id: node.id, index: i });
40
- },
41
- properties: {
42
- label: `Action ${i}`,
43
- icon: faker.properties.icon(),
44
- disposition: 'menu',
45
- },
46
- })),
47
- ];
48
- }),
49
- Option.getOrElse(() => []),
25
+ return Effect.runSync(
26
+ Effect.all([
27
+ // Create app menu actions.
28
+ GraphBuilder.createExtension({
29
+ id: 'app-menu',
30
+ match: NodeMatcher.whenRoot,
31
+ actions: () =>
32
+ Effect.succeed(
33
+ Array.from({ length: 5 }, (_, i) => ({
34
+ id: `app-menu/action-${i}`,
35
+ data: Effect.fnUntraced(function* () {
36
+ log.info('action', { id: 'app-menu', index: i });
37
+ }),
38
+ properties: {
39
+ label: `Action ${i}`,
40
+ icon: faker.properties.icon(),
41
+ disposition: 'menu',
42
+ },
43
+ })),
50
44
  ),
51
- ),
52
- }),
53
- // Create user account node.
54
- createExtension({
55
- id: 'user-account',
56
- connector: (node) =>
57
- Rx.make((get) =>
58
- pipe(
59
- get(node),
60
- Option.flatMap((node) => (node.id === ROOT_ID ? Option.some(node) : Option.none())),
61
- Option.map(() => {
62
- return [
45
+ }),
46
+ // Create user account node.
47
+ GraphBuilder.createExtension({
48
+ id: 'user-account',
49
+ match: NodeMatcher.whenRoot,
50
+ connector: () =>
51
+ Effect.succeed([
52
+ {
53
+ id: 'user-account',
54
+ type: 'user-account',
55
+ properties: {
56
+ label: 'User profile',
57
+ icon: 'ph--user--regular',
58
+ disposition: 'user-account',
59
+ userId: '1234567890ABCDEF',
60
+ hue: faker.properties.hue(),
61
+ emoji: faker.properties.emoji(),
62
+ status: 'active',
63
+ },
64
+ nodes: [
63
65
  {
64
- id: 'user-account',
65
- type: 'user-account',
66
+ id: 'profile',
67
+ type: 'profile',
66
68
  properties: {
67
- label: 'User Account',
69
+ label: 'Profile',
68
70
  icon: 'ph--user--regular',
69
- disposition: 'user-account',
70
- userId: '1234567890ABCDEF',
71
- hue: faker.properties.hue(),
72
- emoji: faker.properties.emoji(),
73
- status: 'active',
74
71
  },
75
- nodes: [
76
- {
77
- id: 'profile',
78
- type: 'profile',
79
- properties: {
80
- label: 'Profile',
81
- icon: 'ph--user--regular',
82
- },
83
- },
84
- {
85
- id: 'devices',
86
- type: 'devices',
87
- properties: {
88
- label: 'Devices',
89
- icon: 'ph--devices--regular',
90
- },
91
- },
92
- {
93
- id: 'security',
94
- type: 'security',
95
- properties: {
96
- label: 'Security',
97
- icon: 'ph--key--regular',
98
- },
99
- },
100
- ],
101
72
  },
102
- ];
103
- }),
104
- Option.getOrElse(() => []),
105
- ),
106
- ),
107
- }),
108
- // TODO(wittjosiah): This group node probably is unnecessary now with the flat L0 structure.
109
- // Create spaces group node.
110
- createExtension({
111
- id: 'spaces-root',
112
- position: 'hoist',
113
- connector: (node) =>
114
- Rx.make((get) =>
115
- pipe(
116
- get(node),
117
- Option.flatMap((node) => (node.id === ROOT_ID ? Option.some(node) : Option.none())),
118
- Option.map(() => {
119
- return [
120
73
  {
121
- id: 'spaces-root',
122
- type: 'spaces-root',
74
+ id: 'devices',
75
+ type: 'devices',
123
76
  properties: {
124
- label: 'Spaces',
125
- icon: 'ph--planet--regular',
126
- role: 'branch',
127
- disposition: 'collection',
77
+ label: 'Devices',
78
+ icon: 'ph--devices--regular',
128
79
  },
129
80
  },
130
- ];
131
- }),
132
- Option.getOrElse(() => []),
133
- ),
134
- ),
135
- }),
136
- // Create space nodes.
137
- createExtension({
138
- id: 'spaces',
139
- connector: (node) => {
140
- const count = Rx.make((get) => {
141
- let value = 3;
142
- const interval = setInterval(() => {
143
- if (value >= 10) {
144
- clearInterval(interval);
145
- return;
146
- }
81
+ {
82
+ id: 'security',
83
+ type: 'security',
84
+ properties: {
85
+ label: 'Security',
86
+ icon: 'ph--key--regular',
87
+ },
88
+ },
89
+ ],
90
+ },
91
+ ]),
92
+ }),
93
+ // Create space (workspace) nodes directly under root.
94
+ GraphBuilder.createExtension({
95
+ id: 'spaces',
96
+ match: NodeMatcher.whenRoot,
97
+ connector: (_, get) =>
98
+ Effect.sync(() => {
99
+ const count = Atom.make((get) => {
100
+ let value = 3;
101
+ const interval = setInterval(() => {
102
+ if (value >= 10) {
103
+ clearInterval(interval);
104
+ return;
105
+ }
147
106
 
148
- value++;
149
- get.setSelf(value);
150
- }, 5000);
151
- get.addFinalizer(() => clearInterval(interval));
152
- return value;
153
- });
107
+ value++;
108
+ get.setSelf(value);
109
+ }, 5000);
110
+ get.addFinalizer(() => clearInterval(interval));
111
+ return value;
112
+ });
154
113
 
155
- return Rx.make((get) =>
156
- pipe(
157
- get(node),
158
- Option.flatMap((node) => (node.id === 'spaces-root' ? Option.some(node) : Option.none())),
159
- Option.map(() => {
160
- return [
161
- ...Array.from({ length: get(count) }, (_, i) => ({
162
- id: `space-${i}`,
163
- type: 'space',
164
- properties: getProperties(`space-${i}`, {
165
- label: `Space ${i}`,
166
- icon: faker.properties.icon(),
167
- hue: faker.properties.hue(),
168
- }),
169
- })),
170
- ];
171
- }),
172
- Option.getOrElse(() => []),
173
- ),
174
- );
175
- },
176
- }),
177
- // Create space actions.
178
- createExtension({
179
- id: 'space-actions',
180
- actions: (node) =>
181
- Rx.make((get) =>
182
- pipe(
183
- get(node),
184
- Option.flatMap((node) => (node.type === 'space' ? Option.some(node) : Option.none())),
185
- Option.map((node) => {
186
- return [
187
- ...Array.from({ length: 5 }, (_, i) => ({
188
- id: `${node.id}/action-${i}`,
189
- data: () => {
190
- log.info('action', { id: node.id, index: i });
191
- },
192
- properties: getProperties(`${node.id}/action-${i}`, {
193
- label: `Action ${i}`,
194
- icon: faker.properties.icon(),
195
- }),
196
- })),
197
- ];
198
- }),
199
- Option.getOrElse(() => []),
114
+ return Array.from({ length: get(count) }, (_, i) => ({
115
+ id: `space-${i}`,
116
+ type: 'space',
117
+ properties: getProperties(`space-${i}`, {
118
+ label: `Space ${i}`,
119
+ icon: faker.properties.icon(),
120
+ hue: faker.properties.hue(),
121
+ disposition: 'workspace',
122
+ }),
123
+ }));
124
+ }),
125
+ }),
126
+ // Create space actions.
127
+ GraphBuilder.createExtension({
128
+ id: 'space-actions',
129
+ match: NodeMatcher.whenNodeType('space'),
130
+ actions: () =>
131
+ Effect.succeed(
132
+ Array.from({ length: 5 }, (_, i) => ({
133
+ id: `space-actions/action-${i}`,
134
+ data: Effect.fnUntraced(function* () {
135
+ log.info('action', { id: 'space-actions', index: i });
136
+ }),
137
+ properties: getProperties(`space-actions/action-${i}`, {
138
+ label: `Action ${i}`,
139
+ icon: faker.properties.icon(),
140
+ }),
141
+ })),
200
142
  ),
201
- ),
202
- }),
203
- // Create object nodes.
204
- createExtension({
205
- id: 'objects',
206
- connector: (node) => {
207
- const count = Rx.make((get) => {
208
- let value = 3;
209
- const interval = setInterval(() => {
210
- if (value >= 20) {
211
- clearInterval(interval);
212
- return;
213
- }
143
+ }),
144
+ // Create object nodes.
145
+ GraphBuilder.createExtension({
146
+ id: 'objects',
147
+ match: NodeMatcher.whenNodeType('space'),
148
+ connector: (_, get) =>
149
+ Effect.sync(() => {
150
+ const count = Atom.make((get) => {
151
+ let value = 3;
152
+ const interval = setInterval(() => {
153
+ if (value >= 20) {
154
+ clearInterval(interval);
155
+ return;
156
+ }
214
157
 
215
- value++;
216
- get.setSelf(value);
217
- }, 5000);
218
- get.addFinalizer(() => clearInterval(interval));
219
- return value;
220
- });
158
+ value++;
159
+ get.setSelf(value);
160
+ }, 5000);
161
+ get.addFinalizer(() => clearInterval(interval));
162
+ return value;
163
+ });
221
164
 
222
- return Rx.make((get) =>
223
- pipe(
224
- get(node),
225
- Option.flatMap((node) => (node.type === 'space' ? Option.some(node) : Option.none())),
226
- Option.map((node) => {
227
- return [
228
- ...Array.from({ length: get(count) }, (_, i) => ({
229
- id: `${node.id}/object-${i}`,
230
- type: 'object',
231
- properties: getProperties(`${node.id}/object-${i}`, {
232
- label: `Object ${i}`,
233
- icon: faker.properties.icon(),
234
- }),
235
- })),
236
- ];
237
- }),
238
- Option.getOrElse(() => []),
239
- ),
240
- );
241
- },
242
- }),
243
- // Create object actions.
244
- createExtension({
245
- id: 'object-actions',
246
- actions: (node) =>
247
- Rx.make((get) =>
248
- pipe(
249
- get(node),
250
- Option.flatMap((node) => (node.type === 'object' ? Option.some(node) : Option.none())),
251
- Option.map((node) => {
252
- return [
253
- ...Array.from({ length: 5 }, (_, i) => ({
254
- id: `${node.id}/action-${i}`,
255
- data: () => {
256
- log.info('action', { id: node.id, index: i });
257
- },
258
- properties: getProperties(`${node.id}/action-${i}`, {
259
- label: `Action ${i}`,
260
- icon: faker.properties.icon(),
261
- }),
262
- })),
263
- ];
264
- }),
265
- Option.getOrElse(() => []),
165
+ return Array.from({ length: get(count) }, (_, i) => ({
166
+ id: `object-${i}`,
167
+ type: 'object',
168
+ properties: getProperties(`object-${i}`, {
169
+ label: `Object ${i}`,
170
+ icon: faker.properties.icon(),
171
+ }),
172
+ }));
173
+ }),
174
+ }),
175
+ // Create object actions.
176
+ GraphBuilder.createExtension({
177
+ id: 'object-actions',
178
+ match: NodeMatcher.whenNodeType('object'),
179
+ actions: () =>
180
+ Effect.succeed(
181
+ Array.from({ length: 5 }, (_, i) => ({
182
+ id: `object-actions/action-${i}`,
183
+ data: Effect.fnUntraced(function* () {
184
+ log.info('action', { id: 'object-actions', index: i });
185
+ }),
186
+ properties: getProperties(`object-actions/action-${i}`, {
187
+ label: `Action ${i}`,
188
+ icon: faker.properties.icon(),
189
+ }),
190
+ })),
266
191
  ),
267
- ),
268
- }),
269
- ];
192
+ }),
193
+ ]),
194
+ );
270
195
  };