@dxos/plugin-navtree 0.8.4-main.3f58842 → 0.8.4-main.52d7546f51

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 (184) 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 +85 -96
  10. package/dist/lib/browser/index.mjs.map +4 -4
  11. package/dist/lib/browser/{keyboard-QRS6WOQH.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 +32 -3
  48. package/dist/types/src/components/NavTree/NavTree.d.ts.map +1 -1
  49. package/dist/types/src/components/NavTree/NavTree.stories.d.ts +29 -4
  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 +33 -4
  58. package/dist/types/src/components/NavTreeItem/NavTreeItemAction.stories.d.ts.map +1 -1
  59. package/dist/types/src/components/NavTreeItem/NavTreeItemColumns.d.ts +2 -2
  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 +6 -7
  64. package/dist/types/src/components/Sidebar/L1Panel.d.ts.map +1 -1
  65. package/dist/types/src/components/Sidebar/L1Tabs.d.ts +12 -0
  66. package/dist/types/src/components/Sidebar/L1Tabs.d.ts.map +1 -0
  67. package/dist/types/src/components/Sidebar/index.d.ts +1 -0
  68. package/dist/types/src/components/Sidebar/index.d.ts.map +1 -1
  69. package/dist/types/src/components/UserAccountAvatar/UserAccountAvatar.d.ts.map +1 -1
  70. package/dist/types/src/components/UserAccountAvatar/UserAccountAvatar.stories.d.ts +8 -5
  71. package/dist/types/src/components/UserAccountAvatar/UserAccountAvatar.stories.d.ts.map +1 -1
  72. package/dist/types/src/components/index.d.ts.map +1 -1
  73. package/dist/types/src/components/types.d.ts +8 -8
  74. package/dist/types/src/components/types.d.ts.map +1 -1
  75. package/dist/types/src/experimental/Tree.d.ts +1 -2
  76. package/dist/types/src/experimental/Tree.d.ts.map +1 -1
  77. package/dist/types/src/experimental/Tree.stories.d.ts +23 -6
  78. package/dist/types/src/experimental/Tree.stories.d.ts.map +1 -1
  79. package/dist/types/src/hooks.d.ts +32 -1
  80. package/dist/types/src/hooks.d.ts.map +1 -1
  81. package/dist/types/src/index.d.ts +1 -2
  82. package/dist/types/src/index.d.ts.map +1 -1
  83. package/dist/types/src/meta.d.ts +3 -4
  84. package/dist/types/src/meta.d.ts.map +1 -1
  85. package/dist/types/src/testing/app-graph-builder.d.ts +2 -3
  86. package/dist/types/src/testing/app-graph-builder.d.ts.map +1 -1
  87. package/dist/types/src/testing/generator.d.ts +5 -6
  88. package/dist/types/src/testing/generator.d.ts.map +1 -1
  89. package/dist/types/src/testing/update-state.d.ts +2 -2
  90. package/dist/types/src/testing/update-state.d.ts.map +1 -1
  91. package/dist/types/src/translations.d.ts +1 -0
  92. package/dist/types/src/translations.d.ts.map +1 -1
  93. package/dist/types/src/types/capabilities.d.ts +16 -0
  94. package/dist/types/src/types/capabilities.d.ts.map +1 -0
  95. package/dist/types/src/types/events.d.ts +5 -0
  96. package/dist/types/src/types/events.d.ts.map +1 -0
  97. package/dist/types/src/types/index.d.ts +4 -0
  98. package/dist/types/src/types/index.d.ts.map +1 -0
  99. package/dist/types/src/{types.d.ts → types/schema.d.ts} +10 -9
  100. package/dist/types/src/types/schema.d.ts.map +1 -0
  101. package/dist/types/src/util.d.ts +8 -9
  102. package/dist/types/src/util.d.ts.map +1 -1
  103. package/dist/types/tsconfig.tsbuildinfo +1 -1
  104. package/package.json +56 -53
  105. package/src/NavTreePlugin.tsx +63 -83
  106. package/src/capabilities/app-graph-builder/app-graph-builder.ts +42 -0
  107. package/src/capabilities/app-graph-builder/index.ts +7 -0
  108. package/src/capabilities/index.ts +5 -9
  109. package/src/capabilities/keyboard/index.ts +7 -0
  110. package/src/capabilities/keyboard/keyboard.ts +66 -0
  111. package/src/capabilities/operation-resolver/index.ts +7 -0
  112. package/src/capabilities/operation-resolver/operation-resolver.ts +42 -0
  113. package/src/capabilities/react-surface/index.ts +7 -0
  114. package/src/capabilities/react-surface/react-surface.tsx +55 -0
  115. package/src/capabilities/state/index.ts +7 -0
  116. package/src/capabilities/state/state.ts +122 -0
  117. package/src/components/CommandsDialog/CommandsDialog.tsx +108 -98
  118. package/src/components/CommandsDialog/CommandsTrigger.tsx +6 -15
  119. package/src/components/NavTree/NavTree.stories.tsx +99 -93
  120. package/src/components/NavTree/NavTree.tsx +12 -18
  121. package/src/components/NavTreeContainer.tsx +282 -257
  122. package/src/components/NavTreeDocumentTitle.tsx +5 -4
  123. package/src/components/NavTreeItem/NavTreeItemAction.stories.tsx +20 -12
  124. package/src/components/NavTreeItem/NavTreeItemAction.tsx +25 -18
  125. package/src/components/NavTreeItem/NavTreeItemColumns.tsx +38 -32
  126. package/src/components/Sidebar/L0Menu.tsx +115 -143
  127. package/src/components/Sidebar/L1Panel.tsx +177 -121
  128. package/src/components/Sidebar/L1Tabs.tsx +33 -0
  129. package/src/components/Sidebar/index.ts +1 -0
  130. package/src/components/UserAccountAvatar/UserAccountAvatar.stories.tsx +9 -8
  131. package/src/components/UserAccountAvatar/UserAccountAvatar.tsx +20 -12
  132. package/src/components/index.ts +1 -0
  133. package/src/components/types.ts +9 -8
  134. package/src/experimental/Tree.stories.tsx +69 -77
  135. package/src/experimental/Tree.tsx +7 -24
  136. package/src/hooks.ts +54 -2
  137. package/src/index.ts +1 -2
  138. package/src/meta.ts +11 -8
  139. package/src/testing/app-graph-builder.ts +159 -234
  140. package/src/testing/generator.ts +20 -18
  141. package/src/testing/update-state.ts +6 -6
  142. package/src/translations.ts +1 -0
  143. package/src/types/capabilities.ts +21 -0
  144. package/src/types/events.ts +12 -0
  145. package/src/types/index.ts +7 -0
  146. package/src/{types.ts → types/schema.ts} +9 -8
  147. package/src/util.ts +14 -35
  148. package/dist/lib/browser/app-graph-builder-5J4LRWDX.mjs +0 -45
  149. package/dist/lib/browser/app-graph-builder-5J4LRWDX.mjs.map +0 -7
  150. package/dist/lib/browser/chunk-ERDGQTH5.mjs +0 -16
  151. package/dist/lib/browser/chunk-ERDGQTH5.mjs.map +0 -7
  152. package/dist/lib/browser/chunk-SICQTLXC.mjs +0 -1442
  153. package/dist/lib/browser/chunk-SICQTLXC.mjs.map +0 -7
  154. package/dist/lib/browser/chunk-WCARAZ7J.mjs +0 -15
  155. package/dist/lib/browser/chunk-WCARAZ7J.mjs.map +0 -7
  156. package/dist/lib/browser/intent-resolver-3XYN2CBU.mjs +0 -47
  157. package/dist/lib/browser/intent-resolver-3XYN2CBU.mjs.map +0 -7
  158. package/dist/lib/browser/keyboard-QRS6WOQH.mjs.map +0 -7
  159. package/dist/lib/browser/react-surface-WURHCBQQ.mjs +0 -51
  160. package/dist/lib/browser/react-surface-WURHCBQQ.mjs.map +0 -7
  161. package/dist/lib/browser/state-54DY3DOY.mjs +0 -117
  162. package/dist/lib/browser/state-54DY3DOY.mjs.map +0 -7
  163. package/dist/types/src/capabilities/app-graph-builder.d.ts +0 -4
  164. package/dist/types/src/capabilities/app-graph-builder.d.ts.map +0 -1
  165. package/dist/types/src/capabilities/capabilities.d.ts +0 -21
  166. package/dist/types/src/capabilities/capabilities.d.ts.map +0 -1
  167. package/dist/types/src/capabilities/intent-resolver.d.ts +0 -4
  168. package/dist/types/src/capabilities/intent-resolver.d.ts.map +0 -1
  169. package/dist/types/src/capabilities/keyboard.d.ts +0 -4
  170. package/dist/types/src/capabilities/keyboard.d.ts.map +0 -1
  171. package/dist/types/src/capabilities/react-surface.d.ts +0 -4
  172. package/dist/types/src/capabilities/react-surface.d.ts.map +0 -1
  173. package/dist/types/src/capabilities/state.d.ts +0 -20
  174. package/dist/types/src/capabilities/state.d.ts.map +0 -1
  175. package/dist/types/src/events.d.ts +0 -4
  176. package/dist/types/src/events.d.ts.map +0 -1
  177. package/dist/types/src/types.d.ts.map +0 -1
  178. package/src/capabilities/app-graph-builder.ts +0 -52
  179. package/src/capabilities/capabilities.ts +0 -20
  180. package/src/capabilities/intent-resolver.ts +0 -37
  181. package/src/capabilities/keyboard.ts +0 -59
  182. package/src/capabilities/react-surface.tsx +0 -45
  183. package/src/capabilities/state.ts +0 -104
  184. package/src/events.ts +0 -11
@@ -12,9 +12,9 @@ import {
12
12
  extractClosestEdge,
13
13
  } from '@atlaskit/pragmatic-drag-and-drop-hitbox/closest-edge';
14
14
  import React, {
15
- forwardRef,
16
15
  type MouseEvent,
17
16
  type PropsWithChildren,
17
+ forwardRef,
18
18
  useCallback,
19
19
  useLayoutEffect,
20
20
  useMemo,
@@ -23,16 +23,26 @@ import React, {
23
23
  } from 'react';
24
24
 
25
25
  import { type Node } from '@dxos/app-graph';
26
- import { invariant } from '@dxos/invariant';
27
- import { Icon, ListItem, ScrollArea, Tooltip, toLocalizedString, useMediaQuery, useTranslation } from '@dxos/react-ui';
28
- import { MenuProvider, DropdownMenu, type MenuItem } from '@dxos/react-ui-menu';
26
+ import { DxAvatar } from '@dxos/lit-ui/react';
27
+ import { useActionRunner } from '@dxos/plugin-graph';
28
+ import {
29
+ Icon,
30
+ ListItem,
31
+ ScrollArea,
32
+ type ThemedClassName,
33
+ Tooltip,
34
+ toLocalizedString,
35
+ useMediaQuery,
36
+ useTranslation,
37
+ } from '@dxos/react-ui';
38
+ import { DropdownMenu, type MenuItem, MenuProvider } from '@dxos/react-ui-menu';
29
39
  import type { StackItemRearrangeHandler } from '@dxos/react-ui-stack';
30
40
  import { Tabs } from '@dxos/react-ui-tabs';
31
- import { mx } from '@dxos/react-ui-theme';
32
- import { arrayMove, getFirstTwoRenderableChars } from '@dxos/util';
41
+ import { mx } from '@dxos/ui-theme';
42
+ import { arrayMove } from '@dxos/util';
33
43
 
34
- import { useLoadDescendents } from '../../hooks';
35
- import { NAVTREE_PLUGIN } from '../../meta';
44
+ import { useNavTreeState } from '../../hooks';
45
+ import { meta } from '../../meta';
36
46
  import { l0ItemType } from '../../util';
37
47
  import { useNavTreeContext } from '../NavTreeContext';
38
48
  import { UserAccountAvatar } from '../UserAccountAvatar';
@@ -47,43 +57,41 @@ type L0ItemData = {
47
57
  };
48
58
 
49
59
  type L0ItemRootProps = {
50
- item: Node<any>;
51
- parent?: Node<any>;
60
+ item: Node.Node;
61
+ parent?: Node.Node;
52
62
  path: string[];
53
63
  };
54
64
 
55
65
  type L0ItemProps = L0ItemRootProps & {
56
- item: Node<any>;
57
- parent?: Node<any>;
66
+ item: Node.Node;
67
+ parent?: Node.Node;
58
68
  path: string[];
59
69
  pinned?: boolean;
60
70
  onRearrange?: StackItemRearrangeHandler<L0ItemData>;
61
71
  };
62
72
 
63
73
  const useL0ItemClick = ({ item, parent, path }: L0ItemProps, type: string) => {
64
- const { tab, isCurrent, onSelect, onTabChange } = useNavTreeContext();
65
- const [isLg] = useMediaQuery('lg', { ssr: false });
74
+ const { tab, onSelect, onTabChange } = useNavTreeContext();
75
+ const { getItem } = useNavTreeState();
76
+ const [isLg] = useMediaQuery('lg');
77
+ const runAction = useActionRunner();
66
78
 
67
79
  return useCallback(
68
80
  (event: MouseEvent) => {
69
81
  switch (type) {
70
82
  case 'action': {
71
- const {
72
- data: invoke,
73
- properties: { caller },
74
- } = item;
75
-
76
- return invoke?.(caller ? { node: parent, caller } : { node: parent });
83
+ const { properties: { caller } = {} } = item;
84
+ return void runAction(item as Node.Action, caller ? { parent, caller } : { parent });
77
85
  }
78
86
 
79
87
  case 'tab':
80
88
  return onTabChange?.(item);
81
89
 
82
90
  case 'link':
83
- return onSelect?.({ item, path, current: !isCurrent(path, item), option: event.altKey });
91
+ return onSelect?.({ item, path, current: !getItem(path).current, option: event.altKey });
84
92
  }
85
93
  },
86
- [item, parent, type, tab, isCurrent, onSelect, onTabChange, isLg],
94
+ [item, parent, type, tab, getItem, onSelect, onTabChange, isLg, runAction],
87
95
  );
88
96
  };
89
97
 
@@ -92,7 +100,7 @@ const l0Breakpoints: Record<string, string> = {
92
100
  };
93
101
 
94
102
  const l0ItemRoot =
95
- 'group/l0item flex w-full justify-center items-center relative data[type!="collection"]:cursor-pointer app-no-drag dx-focus-ring-group';
103
+ 'group/l0item flex is-full justify-center items-center relative data[type!="collection"]:cursor-pointer app-no-drag dx-focus-ring-group';
96
104
 
97
105
  const l0ItemContent = 'flex justify-center items-center dx-focus-ring-group-indicator transition-colors rounded-sm';
98
106
 
@@ -103,55 +111,43 @@ const L0ItemRoot = forwardRef<HTMLElement, PropsWithChildren<L0ItemRootProps>>(
103
111
  const type = l0ItemType(item);
104
112
  const itemPath = useMemo(() => [...path, item.id], [item.id, path]);
105
113
 
106
- const { t } = useTranslation(NAVTREE_PLUGIN);
114
+ const { t } = useTranslation(meta.id);
107
115
  const localizedString = toLocalizedString(item.properties.label, t);
108
116
 
109
117
  const handleClick = useL0ItemClick({ item, parent, path: itemPath }, type);
110
118
  const rootProps =
111
119
  type === 'tab'
112
- ? { value: item.id, tabIndex: 0, onClick: handleClick, 'data-testid': testId, 'data-itemid': id }
113
- : type !== 'collection'
114
- ? { onClick: handleClick, 'data-testid': testId, 'data-itemid': id }
115
- : { onClick: handleClick };
116
-
117
- const Root = type === 'collection' ? 'h2' : type === 'tab' ? Tabs.TabPrimitive : 'button';
120
+ ? { value: item.id, tabIndex: 0, onClick: handleClick, 'data-testid': testId, 'data-object-id': id }
121
+ : { onClick: handleClick, 'data-testid': testId, 'data-object-id': id };
118
122
 
119
123
  return (
120
124
  <Tooltip.Trigger asChild delayDuration={0} side='right' content={localizedString}>
121
- <Root
125
+ <Tabs.TabPrimitive
122
126
  {...(rootProps as any)}
123
127
  data-type={type}
124
128
  className={mx(l0ItemRoot, l0Breakpoints[item.properties.l0Breakpoint])}
125
129
  ref={forwardedRef}
126
130
  >
127
131
  {children}
128
- </Root>
132
+ </Tabs.TabPrimitive>
129
133
  </Tooltip.Trigger>
130
134
  );
131
135
  },
132
136
  );
133
137
 
134
- const L0Avatar = ({ item }: Pick<L0ItemProps, 'item'>) => {
135
- const { t } = useTranslation(NAVTREE_PLUGIN);
136
- const type = l0ItemType(item);
137
- const hue = item.properties.hue ?? null;
138
- const hueFgStyle = hue && { style: { color: `var(--dx-${hue}SurfaceText)` } };
139
- const localizedString = toLocalizedString(item.properties.label, t);
140
- const avatarValue = useMemo(
141
- () => (type === 'tab' ? getFirstTwoRenderableChars(localizedString).join('').toUpperCase() : []),
142
- [type, item.properties.label, t],
143
- );
144
-
145
- return (
146
- <span role='img' className='place-self-center text-xl font-light' {...hueFgStyle}>
147
- {avatarValue}
148
- </span>
149
- );
150
- };
138
+ export const L0ItemActiveTabIndicator = ({ classNames }: ThemedClassName<{}>) => (
139
+ <div
140
+ role='none'
141
+ className={mx(
142
+ 'hidden group-aria-selected/l0item:block absolute inline-start-0 inset-block-2 is-1 bg-accentSurface rounded-ie',
143
+ classNames,
144
+ )}
145
+ />
146
+ );
151
147
 
152
148
  // TODO(burdon): Factor out pinned (non-draggable) items.
153
149
  const L0Item = ({ item, parent, path, pinned, onRearrange }: L0ItemProps) => {
154
- const { t } = useTranslation(NAVTREE_PLUGIN);
150
+ const { t } = useTranslation(meta.id);
155
151
  const itemElement = useRef<HTMLElement | null>(null);
156
152
  const [closestEdge, setEdge] = useState<Edge | null>(null);
157
153
  const localizedString = toLocalizedString(item.properties.label, t);
@@ -228,10 +224,7 @@ const L0Item = ({ item, parent, path, pinned, onRearrange }: L0ItemProps) => {
228
224
  >
229
225
  <ItemAvatar item={item} />
230
226
  </div>
231
- <div
232
- role='none'
233
- className='hidden group-aria-selected/l0item:block absolute inline-start-0 inset-block-2 is-1 bg-accentSurface rounded-ie'
234
- />
227
+ <L0ItemActiveTabIndicator />
235
228
  <span id={`${item.id}__label`} className='sr-only'>
236
229
  {localizedString}
237
230
  </span>
@@ -241,83 +234,68 @@ const L0Item = ({ item, parent, path, pinned, onRearrange }: L0ItemProps) => {
241
234
  };
242
235
 
243
236
  const ItemAvatar = ({ item }: Pick<L0ItemProps, 'item'>) => {
237
+ const { t } = useTranslation(meta.id);
244
238
  const type = l0ItemType(item);
245
239
  if (item.properties.icon) {
246
240
  const hue = item.properties.hue ?? null;
247
241
  const hueFgStyle = hue && { style: { color: `var(--dx-${hue}SurfaceText)` } };
248
- return <Icon icon={item.properties.icon} size={5} {...hueFgStyle} />;
242
+ return <Icon icon={item.properties.icon} size={6} {...hueFgStyle} />;
249
243
  }
250
244
 
251
245
  if (type === 'tab' && item.properties.disposition !== 'pin-end') {
252
- return <L0Avatar item={item} />;
246
+ const hue = item.properties.hue ?? null;
247
+ const localizedString = toLocalizedString(item.properties.label, t);
248
+ return <DxAvatar hue={hue} hueVariant='surface' variant='square' size={12} fallback={localizedString} />;
253
249
  }
254
250
 
255
251
  return null;
256
252
  };
257
253
 
258
254
  //
259
- // L0Collection
255
+ // L0Menu
260
256
  //
261
257
 
262
- const L0Collection = ({ item, path }: L0ItemProps) => {
263
- const navTreeContext = useNavTreeContext();
264
- useLoadDescendents(item);
265
- const collectionItems = navTreeContext.useItems(item);
266
- const groupPath = useMemo(() => [...path, item.id], [item.id, path]);
267
- const { id, testId } = navTreeContext.getProps?.(item, path) ?? {};
258
+ export type L0MenuProps = {
259
+ menuActions: MenuItem[];
260
+ topLevelItems: Node.Node[];
261
+ pinnedItems: Node.Node[];
262
+ userAccountItem?: Node.Node;
263
+ parent?: Node.Node;
264
+ path: string[];
265
+ };
266
+
267
+ export const L0Menu = ({ menuActions, topLevelItems, pinnedItems, userAccountItem, parent, path }: L0MenuProps) => {
268
+ const { t } = useTranslation(meta.id);
269
+ const runAction = useActionRunner();
270
+ const handleAction = useCallback(
271
+ (action: Node.Action, params: Node.InvokeProps) => {
272
+ void runAction(action, params);
273
+ },
274
+ [runAction],
275
+ );
268
276
 
269
277
  const handleRearrange = useCallback<StackItemRearrangeHandler<L0ItemData>>(
270
278
  (source, target, closestEdge) => {
271
- invariant(item.properties.onRearrangeChildren);
272
- const sourceIndex = collectionItems.findIndex((i) => i.id === source.id);
273
- const targetIndex = collectionItems.findIndex((i) => i.id === target.id);
279
+ const sourceItem = topLevelItems.find((i) => i.id === source.id);
280
+ if (!sourceItem?.properties.onRearrange) {
281
+ return;
282
+ }
283
+
284
+ const sourceIndex = topLevelItems.findIndex((i) => i.id === source.id);
285
+ const targetIndex = topLevelItems.findIndex((i) => i.id === target.id);
274
286
  const insertIndex =
275
287
  source.id === target.id
276
288
  ? sourceIndex
277
289
  : targetIndex +
278
290
  (sourceIndex < targetIndex ? (closestEdge === 'top' ? -1 : 0) : closestEdge === 'bottom' ? 1 : 0);
279
- const nextOrder = arrayMove([...collectionItems], sourceIndex, insertIndex);
280
- return item.properties.onRearrangeChildren(nextOrder);
291
+ const nextOrder = arrayMove([...topLevelItems], sourceIndex, insertIndex);
292
+ return sourceItem.properties.onRearrange(nextOrder.map((item) => item.data));
281
293
  },
282
- [collectionItems, item.properties.onRearrangeChildren],
294
+ [topLevelItems],
283
295
  );
284
296
 
285
- return (
286
- <div
287
- role='group'
288
- className='contents group/l0c'
289
- aria-labelledby={`${item.id}__label`}
290
- data-itemid={id}
291
- data-testid={testId}
292
- >
293
- {collectionItems.map((collectionItem) => (
294
- <L0Item
295
- key={collectionItem.id}
296
- item={collectionItem}
297
- parent={item}
298
- path={groupPath}
299
- {...(item.properties.onRearrangeChildren && { onRearrange: handleRearrange })}
300
- />
301
- ))}
302
- </div>
303
- );
304
- };
305
-
306
- //
307
- // L0Menu
308
- //
309
-
310
- export type L0MenuProps = {
311
- menuActions: MenuItem[];
312
- topLevelItems: Node<any>[];
313
- pinnedItems: Node<any>[];
314
- userAccountItem?: Node<any>;
315
- parent?: Node<any>;
316
- path: string[];
317
- };
318
-
319
- export const L0Menu = ({ menuActions, topLevelItems, pinnedItems, userAccountItem, parent, path }: L0MenuProps) => {
320
- const { t } = useTranslation(NAVTREE_PLUGIN);
297
+ // Check if any items have onRearrange to enable drag-and-drop.
298
+ const hasRearrangeableItems = topLevelItems.some((item) => item.properties.onRearrange);
321
299
 
322
300
  return (
323
301
  <Tabs.Tablist
@@ -328,59 +306,62 @@ export const L0Menu = ({ menuActions, topLevelItems, pinnedItems, userAccountIte
328
306
  ]}
329
307
  >
330
308
  {/* TODO(wittjosiah): Use L0Item trigger. */}
331
- <MenuProvider>
309
+ <MenuProvider onAction={handleAction}>
332
310
  <DropdownMenu.Root group={parent} items={menuActions}>
333
311
  <Tooltip.Trigger content={t('app menu label')} side='right' asChild>
334
- <DropdownMenu.Trigger
335
- data-testid='spacePlugin.addSpace'
336
- className={mx(l0ItemRoot, 'grid place-items-center')}
337
- >
338
- <div
339
- role='none'
312
+ <Tabs.TabPrimitive value='options' asChild role='button'>
313
+ <DropdownMenu.Trigger
314
+ data-testid='spacePlugin.addSpace'
340
315
  className={mx(
341
- l0ItemContent,
342
- 'is-[--rail-action] bs-[--rail-action] group-hover/l0item:bg-hoverSurface',
316
+ l0ItemRoot,
317
+ 'grid place-items-center dx-focus-ring-group',
318
+ '[body[data-platform="macos"]_&]:mt-[30px]',
343
319
  )}
344
320
  >
345
- <Icon icon='ph--list--regular' size={5} />
346
- </div>
347
- </DropdownMenu.Trigger>
321
+ <div
322
+ role='none'
323
+ className={mx(
324
+ l0ItemContent,
325
+ 'bs-[--rail-action] is-[--rail-action] group-hover/l0item:bg-hoverSurface',
326
+ )}
327
+ >
328
+ <Icon icon='ph--list--regular' size={5} />
329
+ </div>
330
+ </DropdownMenu.Trigger>
331
+ </Tabs.TabPrimitive>
348
332
  </Tooltip.Trigger>
349
333
  </DropdownMenu.Root>
350
334
  </MenuProvider>
351
335
 
352
336
  {/* Space list. */}
353
- <ScrollArea.Root>
337
+ <ScrollArea.Root thin orientation='vertical'>
354
338
  <ScrollArea.Viewport>
355
339
  <div
356
340
  role='none'
357
341
  className={mx([
358
342
  'flex flex-col gap-1 pbs-1',
359
- '[body[data-platform="darwin"]_&]:pbs-[calc(30px+0.25rem)]',
343
+ '[body[data-platform="macos"]_&]:pbs-[30px]',
360
344
  '[body[data-platform="ios"]_&]:pbs-[max(env(safe-area-inset-top),0.25rem)]',
361
345
  ])}
362
346
  >
363
- {topLevelItems.map((item) => {
364
- if (l0ItemType(item) === 'collection') {
365
- return <L0Collection key={item.id} item={item} parent={parent} path={path} />;
366
- } else {
367
- return <L0Item key={item.id} item={item} parent={parent} path={path} />;
368
- }
369
- })}
347
+ {topLevelItems.map((item) => (
348
+ <L0Item
349
+ key={item.id}
350
+ item={item}
351
+ parent={parent}
352
+ path={path}
353
+ {...(hasRearrangeableItems && { onRearrange: handleRearrange })}
354
+ />
355
+ ))}
370
356
  </div>
371
- <ScrollArea.Scrollbar orientation='vertical'>
372
- <ScrollArea.Thumb />
373
- </ScrollArea.Scrollbar>
374
357
  </ScrollArea.Viewport>
375
358
  </ScrollArea.Root>
376
359
 
377
360
  {/* Actions. */}
378
361
  <div role='none' className='grid grid-cols-1 auto-rows-[--rail-action] pbs-2'>
379
- {pinnedItems
380
- .filter((item) => l0ItemType(item) !== 'collection')
381
- .map((item) => (
382
- <L0Item key={item.id} item={item} parent={parent} path={path} pinned />
383
- ))}
362
+ {pinnedItems.map((item) => (
363
+ <L0Item key={item.id} item={item} parent={parent} path={path} pinned />
364
+ ))}
384
365
  </div>
385
366
 
386
367
  {userAccountItem && (
@@ -396,15 +377,6 @@ export const L0Menu = ({ menuActions, topLevelItems, pinnedItems, userAccountIte
396
377
  </L0ItemRoot>
397
378
  </div>
398
379
  )}
399
-
400
- <div
401
- role='none'
402
- className='hidden [body[data-platform="darwin"]_&]:block absolute block-start-0 is-[calc(var(--l0-size)-1px)] bs-[calc(40px+0.25rem)]'
403
- style={{
404
- background:
405
- 'linear-gradient(to bottom, var(--dx-sidebarSurface) 0%, var(--dx-sidebarSurface) 70%, transparent 100%)',
406
- }}
407
- />
408
380
  </Tabs.Tablist>
409
381
  );
410
382
  };