@dxos/plugin-navtree 0.8.4-main.f9ba587 → 0.8.4-main.fffef41

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 (138) hide show
  1. package/dist/lib/browser/{app-graph-builder-5J4LRWDX.mjs → app-graph-builder-OHSCN3GX.mjs} +13 -12
  2. package/dist/lib/browser/app-graph-builder-OHSCN3GX.mjs.map +7 -0
  3. package/dist/lib/browser/{chunk-WCARAZ7J.mjs → chunk-5VLWX4PK.mjs} +4 -4
  4. package/dist/lib/browser/chunk-5VLWX4PK.mjs.map +7 -0
  5. package/dist/lib/browser/{chunk-TZA65AKW.mjs → chunk-7D2MPHXV.mjs} +317 -262
  6. package/dist/lib/browser/chunk-7D2MPHXV.mjs.map +7 -0
  7. package/dist/lib/browser/chunk-E6MZBCU5.mjs +19 -0
  8. package/dist/lib/browser/chunk-E6MZBCU5.mjs.map +7 -0
  9. package/dist/lib/browser/index.mjs +8 -11
  10. package/dist/lib/browser/index.mjs.map +3 -3
  11. package/dist/lib/browser/{intent-resolver-3XYN2CBU.mjs → intent-resolver-YUVXVPHG.mjs} +7 -7
  12. package/dist/lib/browser/intent-resolver-YUVXVPHG.mjs.map +7 -0
  13. package/dist/lib/browser/{keyboard-QRS6WOQH.mjs → keyboard-YYTYJW4M.mjs} +4 -4
  14. package/dist/lib/{node-esm/keyboard-MOZWHFUM.mjs.map → browser/keyboard-YYTYJW4M.mjs.map} +2 -2
  15. package/dist/lib/browser/meta.json +1 -1
  16. package/dist/lib/browser/{react-surface-N2HPMYCU.mjs → react-surface-J7MWWAGD.mjs} +10 -10
  17. package/dist/lib/browser/react-surface-J7MWWAGD.mjs.map +7 -0
  18. package/dist/lib/browser/{state-54DY3DOY.mjs → state-EUSVT6BI.mjs} +7 -7
  19. package/dist/lib/browser/state-EUSVT6BI.mjs.map +7 -0
  20. package/dist/types/src/NavTreePlugin.d.ts +1 -1
  21. package/dist/types/src/NavTreePlugin.d.ts.map +1 -1
  22. package/dist/types/src/capabilities/app-graph-builder.d.ts +1 -1
  23. package/dist/types/src/capabilities/app-graph-builder.d.ts.map +1 -1
  24. package/dist/types/src/capabilities/capabilities.d.ts.map +1 -1
  25. package/dist/types/src/capabilities/index.d.ts +18 -15
  26. package/dist/types/src/capabilities/index.d.ts.map +1 -1
  27. package/dist/types/src/capabilities/intent-resolver.d.ts +2 -2
  28. package/dist/types/src/capabilities/intent-resolver.d.ts.map +1 -1
  29. package/dist/types/src/capabilities/keyboard.d.ts +1 -1
  30. package/dist/types/src/capabilities/keyboard.d.ts.map +1 -1
  31. package/dist/types/src/capabilities/react-surface.d.ts +1 -1
  32. package/dist/types/src/capabilities/state.d.ts +2 -2
  33. package/dist/types/src/capabilities/state.d.ts.map +1 -1
  34. package/dist/types/src/components/CommandsDialog/CommandsDialog.d.ts.map +1 -1
  35. package/dist/types/src/components/CommandsDialog/CommandsTrigger.d.ts.map +1 -1
  36. package/dist/types/src/components/NavTree/NavTree.d.ts +2 -2
  37. package/dist/types/src/components/NavTree/NavTree.d.ts.map +1 -1
  38. package/dist/types/src/components/NavTree/NavTree.stories.d.ts +26 -4
  39. package/dist/types/src/components/NavTree/NavTree.stories.d.ts.map +1 -1
  40. package/dist/types/src/components/NavTreeContainer.d.ts.map +1 -1
  41. package/dist/types/src/components/NavTreeItem/NavTreeItemAction.d.ts.map +1 -1
  42. package/dist/types/src/components/NavTreeItem/NavTreeItemAction.stories.d.ts +32 -4
  43. package/dist/types/src/components/NavTreeItem/NavTreeItemAction.stories.d.ts.map +1 -1
  44. package/dist/types/src/components/NavTreeItem/NavTreeItemColumns.d.ts +2 -2
  45. package/dist/types/src/components/NavTreeItem/NavTreeItemColumns.d.ts.map +1 -1
  46. package/dist/types/src/components/Sidebar/L0Menu.d.ts +2 -0
  47. package/dist/types/src/components/Sidebar/L0Menu.d.ts.map +1 -1
  48. package/dist/types/src/components/Sidebar/L1Panel.d.ts +5 -6
  49. package/dist/types/src/components/Sidebar/L1Panel.d.ts.map +1 -1
  50. package/dist/types/src/components/Sidebar/L1Tabs.d.ts +12 -0
  51. package/dist/types/src/components/Sidebar/L1Tabs.d.ts.map +1 -0
  52. package/dist/types/src/components/Sidebar/index.d.ts +1 -0
  53. package/dist/types/src/components/Sidebar/index.d.ts.map +1 -1
  54. package/dist/types/src/components/UserAccountAvatar/UserAccountAvatar.d.ts.map +1 -1
  55. package/dist/types/src/components/UserAccountAvatar/UserAccountAvatar.stories.d.ts +8 -5
  56. package/dist/types/src/components/UserAccountAvatar/UserAccountAvatar.stories.d.ts.map +1 -1
  57. package/dist/types/src/components/index.d.ts +1 -1
  58. package/dist/types/src/components/index.d.ts.map +1 -1
  59. package/dist/types/src/components/types.d.ts +2 -2
  60. package/dist/types/src/components/types.d.ts.map +1 -1
  61. package/dist/types/src/events.d.ts.map +1 -1
  62. package/dist/types/src/experimental/Tree.d.ts +4 -5
  63. package/dist/types/src/experimental/Tree.d.ts.map +1 -1
  64. package/dist/types/src/experimental/Tree.stories.d.ts +7 -4
  65. package/dist/types/src/experimental/Tree.stories.d.ts.map +1 -1
  66. package/dist/types/src/meta.d.ts +2 -3
  67. package/dist/types/src/meta.d.ts.map +1 -1
  68. package/dist/types/src/testing/app-graph-builder.d.ts.map +1 -1
  69. package/dist/types/src/testing/generator.d.ts +1 -1
  70. package/dist/types/src/testing/generator.d.ts.map +1 -1
  71. package/dist/types/src/translations.d.ts +1 -0
  72. package/dist/types/src/translations.d.ts.map +1 -1
  73. package/dist/types/src/types.d.ts +4 -3
  74. package/dist/types/src/types.d.ts.map +1 -1
  75. package/dist/types/src/util.d.ts +1 -2
  76. package/dist/types/src/util.d.ts.map +1 -1
  77. package/dist/types/tsconfig.tsbuildinfo +1 -1
  78. package/package.json +49 -50
  79. package/src/NavTreePlugin.tsx +75 -76
  80. package/src/capabilities/app-graph-builder.ts +10 -9
  81. package/src/capabilities/capabilities.ts +2 -2
  82. package/src/capabilities/intent-resolver.ts +2 -2
  83. package/src/capabilities/keyboard.ts +2 -2
  84. package/src/capabilities/react-surface.tsx +5 -5
  85. package/src/capabilities/state.ts +4 -3
  86. package/src/components/CommandsDialog/CommandsDialog.tsx +15 -7
  87. package/src/components/CommandsDialog/CommandsTrigger.tsx +6 -7
  88. package/src/components/NavTree/NavTree.stories.tsx +67 -53
  89. package/src/components/NavTree/NavTree.tsx +7 -3
  90. package/src/components/NavTreeContainer.tsx +91 -36
  91. package/src/components/NavTreeDocumentTitle.tsx +2 -2
  92. package/src/components/NavTreeItem/NavTreeItemAction.stories.tsx +4 -6
  93. package/src/components/NavTreeItem/NavTreeItemAction.tsx +11 -10
  94. package/src/components/NavTreeItem/NavTreeItemColumns.tsx +33 -27
  95. package/src/components/Sidebar/L0Menu.tsx +56 -55
  96. package/src/components/Sidebar/L1Panel.tsx +72 -97
  97. package/src/components/Sidebar/L1Tabs.tsx +58 -0
  98. package/src/components/Sidebar/index.ts +1 -0
  99. package/src/components/UserAccountAvatar/UserAccountAvatar.stories.tsx +9 -8
  100. package/src/components/UserAccountAvatar/UserAccountAvatar.tsx +20 -12
  101. package/src/components/index.ts +1 -1
  102. package/src/components/types.ts +3 -2
  103. package/src/events.ts +2 -2
  104. package/src/experimental/Tree.stories.tsx +36 -38
  105. package/src/experimental/Tree.tsx +17 -35
  106. package/src/meta.ts +10 -7
  107. package/src/testing/app-graph-builder.ts +20 -19
  108. package/src/testing/generator.ts +2 -2
  109. package/src/translations.ts +1 -0
  110. package/src/types.ts +4 -3
  111. package/src/util.ts +2 -20
  112. package/dist/lib/browser/app-graph-builder-5J4LRWDX.mjs.map +0 -7
  113. package/dist/lib/browser/chunk-ERDGQTH5.mjs +0 -16
  114. package/dist/lib/browser/chunk-ERDGQTH5.mjs.map +0 -7
  115. package/dist/lib/browser/chunk-TZA65AKW.mjs.map +0 -7
  116. package/dist/lib/browser/chunk-WCARAZ7J.mjs.map +0 -7
  117. package/dist/lib/browser/intent-resolver-3XYN2CBU.mjs.map +0 -7
  118. package/dist/lib/browser/keyboard-QRS6WOQH.mjs.map +0 -7
  119. package/dist/lib/browser/react-surface-N2HPMYCU.mjs.map +0 -7
  120. package/dist/lib/browser/state-54DY3DOY.mjs.map +0 -7
  121. package/dist/lib/node-esm/app-graph-builder-GY7GCTGU.mjs +0 -46
  122. package/dist/lib/node-esm/app-graph-builder-GY7GCTGU.mjs.map +0 -7
  123. package/dist/lib/node-esm/chunk-CY7QWR4R.mjs +0 -1429
  124. package/dist/lib/node-esm/chunk-CY7QWR4R.mjs.map +0 -7
  125. package/dist/lib/node-esm/chunk-P2JGW3WR.mjs +0 -18
  126. package/dist/lib/node-esm/chunk-P2JGW3WR.mjs.map +0 -7
  127. package/dist/lib/node-esm/chunk-V3QXFDDP.mjs +0 -16
  128. package/dist/lib/node-esm/chunk-V3QXFDDP.mjs.map +0 -7
  129. package/dist/lib/node-esm/index.mjs +0 -150
  130. package/dist/lib/node-esm/index.mjs.map +0 -7
  131. package/dist/lib/node-esm/intent-resolver-R7UNPSZY.mjs +0 -48
  132. package/dist/lib/node-esm/intent-resolver-R7UNPSZY.mjs.map +0 -7
  133. package/dist/lib/node-esm/keyboard-MOZWHFUM.mjs +0 -52
  134. package/dist/lib/node-esm/meta.json +0 -1
  135. package/dist/lib/node-esm/react-surface-EW5FDMW4.mjs +0 -52
  136. package/dist/lib/node-esm/react-surface-EW5FDMW4.mjs.map +0 -7
  137. package/dist/lib/node-esm/state-Z3OTRC2I.mjs +0 -118
  138. package/dist/lib/node-esm/state-Z3OTRC2I.mjs.map +0 -7
@@ -7,6 +7,8 @@ import React from 'react';
7
7
  import { Avatar, type AvatarStatus, type Size } from '@dxos/react-ui';
8
8
  import { hexToFallback } from '@dxos/util';
9
9
 
10
+ import { L0ItemActiveTabIndicator } from '../Sidebar';
11
+
10
12
  export type UserAccountAvatarProps = {
11
13
  size?: Size;
12
14
  userId?: string;
@@ -19,17 +21,23 @@ export const UserAccountAvatar = ({ size, userId, hue, emoji, status }: UserAcco
19
21
  const fallbackValue = hexToFallback(userId ?? '0');
20
22
 
21
23
  return (
22
- <div className='grid place-items-center' data-joyride='welcome/account'>
23
- <Avatar.Root>
24
- <Avatar.Content
25
- variant='circle'
26
- size={size ?? 12}
27
- status={status ?? 'active'}
28
- hue={hue || fallbackValue.hue}
29
- fallback={emoji || fallbackValue.emoji}
30
- data-testid='treeView.userAccount'
31
- />
32
- </Avatar.Root>
33
- </div>
24
+ <>
25
+ <L0ItemActiveTabIndicator classNames='inset-block-6' />
26
+ <div
27
+ className='grid place-items-center dx-focus-ring-group-indicator rounded-full'
28
+ data-joyride='welcome/account'
29
+ >
30
+ <Avatar.Root>
31
+ <Avatar.Content
32
+ variant='circle'
33
+ size={size ?? 12}
34
+ status={status ?? 'active'}
35
+ hue={hue || fallbackValue.hue}
36
+ fallback={emoji || fallbackValue.emoji}
37
+ data-testid='treeView.userAccount'
38
+ />
39
+ </Avatar.Root>
40
+ </div>
41
+ </>
34
42
  );
35
43
  };
@@ -7,4 +7,4 @@ export * from './NavTree';
7
7
  export * from './NavTreeContainer';
8
8
  export * from './NavTreeContext';
9
9
  export * from './NavTreeDocumentTitle';
10
- export * from './types';
10
+ export type * from './types';
@@ -9,9 +9,10 @@ import type { Density } from '@dxos/react-ui';
9
9
  import type { TreeProps } from '@dxos/react-ui-list';
10
10
  import type { MaybePromise } from '@dxos/util';
11
11
 
12
- import type { L1PanelProps } from './Sidebar';
13
12
  import type { FlattenedActions, NavTreeItemGraphNode } from '../types';
14
13
 
14
+ import type { L1PanelProps } from './Sidebar';
15
+
15
16
  export type NavTreeContextValue = Pick<
16
17
  TreeProps<NavTreeItemGraphNode, { disposition?: string; sort?: boolean }>,
17
18
  'useItems' | 'getProps' | 'isCurrent' | 'isOpen' | 'canDrop' | 'onOpenChange' | 'onSelect'
@@ -21,7 +22,7 @@ export type NavTreeContextValue = Pick<
21
22
  topbar?: boolean;
22
23
  popoverAnchorId?: string;
23
24
  renderItemEnd?: FC<{ node: Node; open: boolean }>;
24
- getActions: (node: Node) => FlattenedActions;
25
+ useActions: (node: Node) => FlattenedActions;
25
26
  loadDescendents?: (node: Node) => MaybePromise<void>;
26
27
  isAlternateTree?: (path: string[], item: NavTreeItemGraphNode) => boolean;
27
28
  setAlternateTree?: (path: string[], open: boolean) => void;
package/src/events.ts CHANGED
@@ -4,8 +4,8 @@
4
4
 
5
5
  import { Events } from '@dxos/app-framework';
6
6
 
7
- import { NAVTREE_PLUGIN } from './meta';
7
+ import { meta } from './meta';
8
8
 
9
9
  export namespace NavTreeEvents {
10
- export const StateReady = Events.createStateEvent(NAVTREE_PLUGIN);
10
+ export const StateReady = Events.createStateEvent(meta.id);
11
11
  }
@@ -2,15 +2,13 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
- import '@dxos-theme';
6
-
7
- import { House, List, Planet, PlusCircle, Sailboat } from '@phosphor-icons/react';
8
5
  import { type Meta } from '@storybook/react-vite';
9
6
  import React, { type JSX, type PropsWithChildren, useEffect, useState } from 'react';
10
7
 
11
8
  import { faker } from '@dxos/random';
12
- import { modalSurface, mx } from '@dxos/react-ui-theme';
13
- import { withLayout, withTheme } from '@dxos/storybook-utils';
9
+ import { Icon, IconButton } from '@dxos/react-ui';
10
+ import { withLayout, withTheme } from '@dxos/react-ui/testing';
11
+ import { mx } from '@dxos/react-ui-theme';
14
12
 
15
13
  import { type ItemMap, Tree, type TreeNodeData, type TreeProps, visitNodes, visitor } from './Tree';
16
14
 
@@ -32,7 +30,7 @@ const Container = ({ children, sidebar }: PropsWithChildren<{ sidebar: JSX.Eleme
32
30
  <div className='flex'>
33
31
  {/* TODO(burdon): Custom thin scrollbar. */}
34
32
  {/* TODO(burdon): Horizontal scrolling within navtree? */}
35
- <div className='flex flex-col overflow-y-auto w-[300px] bg-neutral-100 dark:bg-neutral-950'>{sidebar}</div>
33
+ <div className='flex flex-col overflow-y-auto is-[300px] bg-neutral-100 dark:bg-neutral-950'>{sidebar}</div>
36
34
  <div className='flex flex-col grow overflow-hidden'>{children}</div>
37
35
  </div>
38
36
  );
@@ -48,7 +46,7 @@ const data: TreeNodeData[] = [
48
46
  id: faker.string.uuid(),
49
47
  title: 'plugins/Personal Space',
50
48
  color: 'text-green-400',
51
- Icon: House,
49
+ iconName: 'ph--house--regular',
52
50
  children: [
53
51
  {
54
52
  id: faker.string.uuid(),
@@ -83,7 +81,7 @@ const data: TreeNodeData[] = [
83
81
  {
84
82
  id: faker.string.uuid(),
85
83
  title: faker.commerce.productName(),
86
- Icon: Planet,
84
+ iconName: 'ph--planet--regular',
87
85
  children: [
88
86
  {
89
87
  id: faker.string.uuid(),
@@ -94,38 +92,17 @@ const data: TreeNodeData[] = [
94
92
  {
95
93
  id: faker.string.uuid(),
96
94
  title: faker.commerce.productName(),
97
- Icon: Sailboat,
95
+ iconName: 'ph--sailboat--regular',
98
96
  },
99
97
  {
100
98
  id: faker.string.uuid(),
101
99
  title: faker.commerce.productName(),
102
- Icon: Planet,
100
+ iconName: 'ph--planet--regular',
103
101
  },
104
102
  ],
105
103
  },
106
104
  ];
107
105
 
108
- export const Default = () => {
109
- return <Container sidebar={<Sidebar mutate />} />;
110
- };
111
-
112
- export const Visitor = () => {
113
- const [items] = useState(data);
114
- const root = items[0];
115
- const [openItems] = useState<ItemMap>({ [root.children![0].id]: true });
116
- return (
117
- <div className='flex flex-col'>
118
- {Array.from(visitor(root, openItems)).map(({ node: { id, title }, depth }) => (
119
- <div key={id} className='grid grid-cols-[40px_400px_400px] font-mono'>
120
- <div>{depth}</div>
121
- <div>{id}</div>
122
- <div>{title}</div>
123
- </div>
124
- ))}
125
- </div>
126
- );
127
- };
128
-
129
106
  const Sidebar = ({ mutate }: { mutate?: boolean }) => {
130
107
  const [items, setItems] = useState(data);
131
108
  const root = items[0];
@@ -181,7 +158,7 @@ const Sidebar = ({ mutate }: { mutate?: boolean }) => {
181
158
  setItems((items) => {
182
159
  items[0].children?.push({
183
160
  id: faker.string.uuid(),
184
- Icon: Planet,
161
+ iconName: 'ph--planet--regular',
185
162
  title: faker.commerce.productName(),
186
163
  });
187
164
 
@@ -212,21 +189,42 @@ const Sidebar = ({ mutate }: { mutate?: boolean }) => {
212
189
  />
213
190
  </div>
214
191
 
215
- <div className='flex items-center my-2 px-2 gap-2'>
216
- <PlusCircle onClick={handleCreateSpace} />
192
+ <div className='flex items-center my-2 pli-2 gap-2'>
193
+ <IconButton icon='ph--plus-circle--regular' iconOnly label='Create space' onClick={handleCreateSpace} />
217
194
  <span className='grow text-sm' onClick={handleCreateSpace}>
218
195
  New space
219
196
  </span>
220
- <List />
197
+ <Icon icon='ph--list--regular' />
221
198
  </div>
222
199
  </div>
223
200
  );
224
201
  };
225
202
 
226
- const meta: Meta = {
203
+ const meta = {
227
204
  title: 'plugins/plugin-navtree/experimental/Tree',
228
205
  component: Tree,
229
- decorators: [withTheme, withLayout({ fullscreen: true, classNames: modalSurface })],
230
- };
206
+ decorators: [withTheme, withLayout({ container: 'column' })],
207
+ } satisfies Meta<typeof Tree>;
231
208
 
232
209
  export default meta;
210
+
211
+ export const Default = () => {
212
+ return <Container sidebar={<Sidebar mutate />} />;
213
+ };
214
+
215
+ export const Visitor = () => {
216
+ const [items] = useState(data);
217
+ const root = items[0];
218
+ const [openItems] = useState<ItemMap>({ [root.children![0].id]: true });
219
+ return (
220
+ <div className='flex flex-col'>
221
+ {Array.from(visitor(root, openItems)).map(({ node: { id, title }, depth }) => (
222
+ <div key={id} className='grid grid-cols-[40px_400px_400px] font-mono'>
223
+ <div>{depth}</div>
224
+ <div>{id}</div>
225
+ <div>{title}</div>
226
+ </div>
227
+ ))}
228
+ </div>
229
+ );
230
+ };
@@ -2,34 +2,25 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
- import { CaretRight, Circle, File, Folder, type Icon, type IconProps, Plus, UserCircle } from '@phosphor-icons/react';
6
5
  import React, { type HTMLAttributes, type PropsWithChildren } from 'react';
7
6
 
8
- import { type ClassNameValue, type Size } from '@dxos/react-ui';
9
- import { getSize, mx } from '@dxos/react-ui-theme';
10
-
11
- // TODO(burdon): Rounded border if first/last.
12
- const styles = {
13
- hover: 'hover:bg-slate-400 dark:hover:bg-slate-800',
14
- selected: '!bg-slate-300 dark:!bg-slate-700',
15
- };
7
+ import { type ClassNameValue, Icon, type Size } from '@dxos/react-ui';
8
+ import { mx } from '@dxos/react-ui-theme';
16
9
 
17
10
  export const IconButton = ({
18
- Icon,
11
+ iconName,
19
12
  classNames,
20
13
  size = 4,
21
14
  onClick,
22
- ...props
23
15
  }: {
24
- Icon: Icon;
16
+ iconName: string;
25
17
  classNames?: ClassNameValue;
26
18
  size?: Size;
27
- } & Pick<IconProps, 'weight'> &
28
- Pick<HTMLAttributes<HTMLDivElement>, 'onClick'>) => {
19
+ } & Pick<HTMLAttributes<HTMLDivElement>, 'onClick'>) => {
29
20
  // TODO(burdon): Density aware.
30
21
  return (
31
- <div className={mx('flex w-6 h-6 items-center justify-center select-none', classNames)} onClick={onClick}>
32
- <Icon className={mx('cursor-pointer', getSize(size))} {...props} />
22
+ <div className={mx('flex is-6 bs-6 items-center justify-center select-none', classNames)} onClick={onClick}>
23
+ <Icon icon={iconName} classNames='cursor-pointer' size={size} />
33
24
  </div>
34
25
  );
35
26
  };
@@ -37,7 +28,7 @@ export const IconButton = ({
37
28
  export type TreeNodeData = {
38
29
  id: string;
39
30
  title: string;
40
- Icon?: Icon;
31
+ iconName?: string;
41
32
  color?: string;
42
33
  children?: TreeNodeData[];
43
34
  };
@@ -123,9 +114,8 @@ const StateIcon = ({ node, open, selected, active }: TreeNodeProps) => {
123
114
  // TODO(burdon): No animation if opening/closing folder.
124
115
  return (
125
116
  <IconButton
126
- Icon={isActive ? UserCircle : Circle}
117
+ iconName={isActive ? 'ph--user-circle--regular' : 'ph--circle--regular'}
127
118
  size={4}
128
- weight={selected?.[id] ? 'fill' : 'duotone'}
129
119
  classNames={mx(
130
120
  'text-slate-500',
131
121
  !isChildActive && 'opacity-0 transition duration-500',
@@ -143,7 +133,7 @@ const OpenIcon = ({
143
133
  return (
144
134
  (children?.length && open && (
145
135
  <IconButton
146
- Icon={CaretRight}
136
+ iconName='ph--caret-right--regular'
147
137
  size={3}
148
138
  classNames={mx('transition duration-200', open?.[id] ? 'rotate-90' : 'transform-none')}
149
139
  onClick={(ev) => {
@@ -157,23 +147,15 @@ const OpenIcon = ({
157
147
 
158
148
  // TODO(burdon): Drag handle,
159
149
  const ItemIcon = ({
160
- node: { children, Icon = children?.length ? Folder : File, color },
150
+ node: { children, iconName = children?.length ? 'ph--folder--regular' : 'ph--file--regular', color },
161
151
  }: Pick<TreeNodeProps, 'node'>) => {
162
- return (
163
- (Icon && (
164
- <IconButton
165
- Icon={Icon}
166
- classNames={color ?? 'text-neutral-700 dark:text-neutral-300'}
167
- weight={color ? 'duotone' : 'regular'}
168
- />
169
- )) || <div />
170
- );
152
+ return (iconName && <IconButton iconName={iconName} classNames={color ?? 'text-subdued'} />) || <div />;
171
153
  };
172
154
 
173
155
  const MenuItem = ({ node: { id }, onMenuAction }: Pick<TreeNodeProps, 'node' | 'onMenuAction'>) => {
174
156
  return (
175
157
  <IconButton
176
- Icon={Plus}
158
+ iconName='ph--plus--regular'
177
159
  classNames='invisible group-hover:visible'
178
160
  onClick={(ev) => {
179
161
  ev.stopPropagation();
@@ -211,9 +193,9 @@ export const TreeNodeRow = (props: TreeNodeProps & { className?: string }) => {
211
193
  <Grid
212
194
  style={{ paddingLeft: `${(depth - 1) * 24}px` }}
213
195
  className={mx(
214
- 'group w-full items-center cursor-pointer',
215
- styles.hover,
216
- 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',
217
199
  className,
218
200
  )}
219
201
  onClick={() => selected && onChangeSelected?.(id, !selected[id])}
@@ -256,7 +238,7 @@ export const TreeChildNodes = ({
256
238
  } = props;
257
239
  return (
258
240
  <div className={mx('flex flex-col mt-0.5 gap-0.5', className)}>
259
- {children?.map((child, i) => (
241
+ {children?.map((child) => (
260
242
  <TreeNode key={child.id} {...props} depth={depth + 1} node={child} ancestors={[...ancestors, props.node]} />
261
243
  ))}
262
244
  </div>
package/src/meta.ts CHANGED
@@ -3,15 +3,18 @@
3
3
  //
4
4
 
5
5
  import { type PluginMeta } 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: PluginMeta = {
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,12 +2,13 @@
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 Function from 'effect/Function';
7
+ import * as Option from 'effect/Option';
7
8
 
8
9
  import { type PluginContext } from '@dxos/app-framework';
9
10
  import { log } from '@dxos/log';
10
- import { createExtension, ROOT_ID, type BuilderExtensions } from '@dxos/plugin-graph';
11
+ import { type BuilderExtensions, ROOT_ID, createExtension } from '@dxos/plugin-graph';
11
12
  import { faker } from '@dxos/random';
12
13
 
13
14
  export const storybookGraphBuilders = (context: PluginContext): BuilderExtensions => {
@@ -27,8 +28,8 @@ export const storybookGraphBuilders = (context: PluginContext): BuilderExtension
27
28
  createExtension({
28
29
  id: 'app-menu',
29
30
  actions: (node) =>
30
- Rx.make((get) =>
31
- pipe(
31
+ Atom.make((get) =>
32
+ Function.pipe(
32
33
  get(node),
33
34
  Option.flatMap((node) => (node.id === ROOT_ID ? Option.some(node) : Option.none())),
34
35
  Option.map((node) => {
@@ -54,8 +55,8 @@ export const storybookGraphBuilders = (context: PluginContext): BuilderExtension
54
55
  createExtension({
55
56
  id: 'user-account',
56
57
  connector: (node) =>
57
- Rx.make((get) =>
58
- pipe(
58
+ Atom.make((get) =>
59
+ Function.pipe(
59
60
  get(node),
60
61
  Option.flatMap((node) => (node.id === ROOT_ID ? Option.some(node) : Option.none())),
61
62
  Option.map(() => {
@@ -111,8 +112,8 @@ export const storybookGraphBuilders = (context: PluginContext): BuilderExtension
111
112
  id: 'spaces-root',
112
113
  position: 'hoist',
113
114
  connector: (node) =>
114
- Rx.make((get) =>
115
- pipe(
115
+ Atom.make((get) =>
116
+ Function.pipe(
116
117
  get(node),
117
118
  Option.flatMap((node) => (node.id === ROOT_ID ? Option.some(node) : Option.none())),
118
119
  Option.map(() => {
@@ -137,7 +138,7 @@ export const storybookGraphBuilders = (context: PluginContext): BuilderExtension
137
138
  createExtension({
138
139
  id: 'spaces',
139
140
  connector: (node) => {
140
- const count = Rx.make((get) => {
141
+ const count = Atom.make((get) => {
141
142
  let value = 3;
142
143
  const interval = setInterval(() => {
143
144
  if (value >= 10) {
@@ -152,8 +153,8 @@ export const storybookGraphBuilders = (context: PluginContext): BuilderExtension
152
153
  return value;
153
154
  });
154
155
 
155
- return Rx.make((get) =>
156
- pipe(
156
+ return Atom.make((get) =>
157
+ Function.pipe(
157
158
  get(node),
158
159
  Option.flatMap((node) => (node.id === 'spaces-root' ? Option.some(node) : Option.none())),
159
160
  Option.map(() => {
@@ -178,8 +179,8 @@ export const storybookGraphBuilders = (context: PluginContext): BuilderExtension
178
179
  createExtension({
179
180
  id: 'space-actions',
180
181
  actions: (node) =>
181
- Rx.make((get) =>
182
- pipe(
182
+ Atom.make((get) =>
183
+ Function.pipe(
183
184
  get(node),
184
185
  Option.flatMap((node) => (node.type === 'space' ? Option.some(node) : Option.none())),
185
186
  Option.map((node) => {
@@ -204,7 +205,7 @@ export const storybookGraphBuilders = (context: PluginContext): BuilderExtension
204
205
  createExtension({
205
206
  id: 'objects',
206
207
  connector: (node) => {
207
- const count = Rx.make((get) => {
208
+ const count = Atom.make((get) => {
208
209
  let value = 3;
209
210
  const interval = setInterval(() => {
210
211
  if (value >= 20) {
@@ -219,8 +220,8 @@ export const storybookGraphBuilders = (context: PluginContext): BuilderExtension
219
220
  return value;
220
221
  });
221
222
 
222
- return Rx.make((get) =>
223
- pipe(
223
+ return Atom.make((get) =>
224
+ Function.pipe(
224
225
  get(node),
225
226
  Option.flatMap((node) => (node.type === 'space' ? Option.some(node) : Option.none())),
226
227
  Option.map((node) => {
@@ -244,8 +245,8 @@ export const storybookGraphBuilders = (context: PluginContext): BuilderExtension
244
245
  createExtension({
245
246
  id: 'object-actions',
246
247
  actions: (node) =>
247
- Rx.make((get) =>
248
- pipe(
248
+ Atom.make((get) =>
249
+ Function.pipe(
249
250
  get(node),
250
251
  Option.flatMap((node) => (node.type === 'object' ? Option.some(node) : Option.none())),
251
252
  Option.map((node) => {
@@ -2,11 +2,11 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
- import { Schema } from 'effect';
5
+ import * as Schema from 'effect/Schema';
6
6
 
7
7
  import { type NodeArg } from '@dxos/app-graph';
8
8
  import { type Live, Obj, Type } from '@dxos/echo';
9
- import { TypedObject } from '@dxos/echo-schema';
9
+ import { TypedObject } from '@dxos/echo/internal';
10
10
  import { faker } from '@dxos/random';
11
11
  import { range } from '@dxos/util';
12
12
 
@@ -18,6 +18,7 @@ export const translations = [
18
18
  'node actions menu invoker label': 'More options',
19
19
  'tree item actions label': 'More actions',
20
20
  'empty branch message': ' ',
21
+ 'button back': 'Back to Space',
21
22
  },
22
23
  },
23
24
  },
package/src/types.ts CHANGED
@@ -28,13 +28,14 @@ export type FlattenedActions = {
28
28
  };
29
29
 
30
30
  type SharedProperties = {
31
- label: Label;
32
- icon?: string;
31
+ testId?: string;
33
32
  disabled?: boolean;
34
33
  position?: Position;
35
- testId?: string;
34
+ label: Label;
36
35
  className?: string;
37
36
  headingClassName?: string;
37
+ icon?: string;
38
+ iconHue?: string;
38
39
  };
39
40
 
40
41
  export type NodeProperties = SharedProperties & {
package/src/util.ts CHANGED
@@ -2,10 +2,10 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
- import { type Action, type Node, type ReadableGraph, isAction, isActionLike } from '@dxos/app-graph';
5
+ import { type Action, type Node, type ReadableGraph, isActionLike } from '@dxos/app-graph';
6
6
  import { isNonNullable } from '@dxos/util';
7
7
 
8
- import { type FlattenedActions, type NavTreeItemGraphNode } from './types';
8
+ import { type NavTreeItemGraphNode } from './types';
9
9
 
10
10
  export const getParent = (
11
11
  graph: ReadableGraph,
@@ -88,24 +88,6 @@ export const getChildren = (
88
88
  .filter(isNonNullable) as NavTreeItemGraphNode[];
89
89
  };
90
90
 
91
- export const getActions = (graph: ReadableGraph, node: Node): FlattenedActions => {
92
- return graph.getActions(node.id).reduce(
93
- (acc: FlattenedActions, arg) => {
94
- if (arg.properties.disposition === 'item') {
95
- return acc;
96
- }
97
-
98
- acc.actions.push(arg);
99
- if (!isAction(arg)) {
100
- const actionGroup = graph.getActions(arg.id);
101
- acc.groupedActions[arg.id] = actionGroup;
102
- }
103
- return acc;
104
- },
105
- { actions: [], groupedActions: {} },
106
- );
107
- };
108
-
109
91
  export const l0ItemType = (item: Node<any>) => {
110
92
  if (item.properties.disposition === 'collection') {
111
93
  return 'collection';
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../src/capabilities/app-graph-builder.ts"],
4
- "sourcesContent": ["//\n// Copyright 2025 DXOS.org\n//\n\nimport { Rx } from '@effect-rx/rx-react';\nimport { Option, pipe } from 'effect';\n\nimport { Capabilities, contributes, type PluginContext, createIntent, LayoutAction } from '@dxos/app-framework';\nimport { createExtension, ROOT_ID } from '@dxos/plugin-graph';\n\nimport { COMMANDS_DIALOG, NAVTREE_PLUGIN } from '../meta';\n\nexport default (context: PluginContext) =>\n contributes(\n Capabilities.AppGraphBuilder,\n createExtension({\n id: NAVTREE_PLUGIN,\n actions: (node) =>\n Rx.make((get) =>\n pipe(\n get(node),\n Option.flatMap((node) => (node.id === ROOT_ID ? Option.some(node) : Option.none())),\n Option.map(() => [\n {\n id: COMMANDS_DIALOG,\n data: async () => {\n const { dispatchPromise: dispatch } = context.getCapability(Capabilities.IntentDispatcher);\n await dispatch(\n createIntent(LayoutAction.UpdateDialog, {\n part: 'dialog',\n subject: COMMANDS_DIALOG,\n options: {\n blockAlign: 'start',\n },\n }),\n );\n },\n properties: {\n label: ['open commands label', { ns: NAVTREE_PLUGIN }],\n icon: 'ph--magnifying-glass--regular',\n keyBinding: {\n macos: 'meta+k',\n windows: 'ctrl+k',\n },\n },\n },\n ]),\n Option.getOrElse(() => []),\n ),\n ),\n }),\n );\n"],
5
- "mappings": ";;;;;;AAIA,SAASA,UAAU;AACnB,SAASC,QAAQC,YAAY;AAE7B,SAASC,cAAcC,aAAiCC,cAAcC,oBAAoB;AAC1F,SAASC,iBAAiBC,eAAe;AAIzC,IAAA,4BAAe,CAACC,YACdC,YACEC,aAAaC,iBACbC,gBAAgB;EACdC,IAAIC;EACJC,SAAS,CAACC,SACRC,GAAGC,KAAK,CAACC,QACPC,KACED,IAAIH,IAAAA,GACJK,OAAOC,QAAQ,CAACN,UAAUA,MAAKH,OAAOU,UAAUF,OAAOG,KAAKR,KAAAA,IAAQK,OAAOI,KAAI,CAAA,GAC/EJ,OAAOK,IAAI,MAAM;IACf;MACEb,IAAIc;MACJC,MAAM,YAAA;AACJ,cAAM,EAAEC,iBAAiBC,SAAQ,IAAKtB,QAAQuB,cAAcrB,aAAasB,gBAAgB;AACzF,cAAMF,SACJG,aAAaC,aAAaC,cAAc;UACtCC,MAAM;UACNC,SAASV;UACTW,SAAS;YACPC,YAAY;UACd;QACF,CAAA,CAAA;MAEJ;MACAC,YAAY;QACVC,OAAO;UAAC;UAAuB;YAAEC,IAAI5B;UAAe;;QACpD6B,MAAM;QACNC,YAAY;UACVC,OAAO;UACPC,SAAS;QACX;MACF;IACF;GACD,GACDzB,OAAO0B,UAAU,MAAM,CAAA,CAAE,CAAA,CAAA;AAGjC,CAAA,CAAA;",
6
- "names": ["Rx", "Option", "pipe", "Capabilities", "contributes", "createIntent", "LayoutAction", "createExtension", "ROOT_ID", "context", "contributes", "Capabilities", "AppGraphBuilder", "createExtension", "id", "NAVTREE_PLUGIN", "actions", "node", "Rx", "make", "get", "pipe", "Option", "flatMap", "ROOT_ID", "some", "none", "map", "COMMANDS_DIALOG", "data", "dispatchPromise", "dispatch", "getCapability", "IntentDispatcher", "createIntent", "LayoutAction", "UpdateDialog", "part", "subject", "options", "blockAlign", "properties", "label", "ns", "icon", "keyBinding", "macos", "windows", "getOrElse"]
7
- }
@@ -1,16 +0,0 @@
1
- // src/meta.ts
2
- var NAVTREE_PLUGIN = "dxos.org/plugin/navtree";
3
- var KEY_BINDING = "KeyBinding";
4
- var COMMANDS_DIALOG = `${NAVTREE_PLUGIN}/CommandsDialog`;
5
- var meta = {
6
- id: NAVTREE_PLUGIN,
7
- name: "Navtree"
8
- };
9
-
10
- export {
11
- NAVTREE_PLUGIN,
12
- KEY_BINDING,
13
- COMMANDS_DIALOG,
14
- meta
15
- };
16
- //# sourceMappingURL=chunk-ERDGQTH5.mjs.map
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../src/meta.ts"],
4
- "sourcesContent": ["//\n// Copyright 2023 DXOS.org\n//\n\nimport { type PluginMeta } from '@dxos/app-framework';\n\nexport const NAVTREE_PLUGIN = 'dxos.org/plugin/navtree';\n\n// TODO(wittjosiah): Factor out.\nexport const KEY_BINDING = 'KeyBinding';\n// TODO(wittjosiah): Factor out.\nexport const COMMANDS_DIALOG = `${NAVTREE_PLUGIN}/CommandsDialog`;\n\nexport const meta: PluginMeta = {\n id: NAVTREE_PLUGIN,\n name: 'Navtree',\n};\n"],
5
- "mappings": ";AAMO,IAAMA,iBAAiB;AAGvB,IAAMC,cAAc;AAEpB,IAAMC,kBAAkB,GAAGF,cAAAA;AAE3B,IAAMG,OAAmB;EAC9BC,IAAIJ;EACJK,MAAM;AACR;",
6
- "names": ["NAVTREE_PLUGIN", "KEY_BINDING", "COMMANDS_DIALOG", "meta", "id", "name"]
7
- }