@dxos/plugin-navtree 0.8.4-main.9735255 → 0.8.4-main.9be5663bfe

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 (187) hide show
  1. package/dist/lib/browser/index.mjs +137 -72
  2. package/dist/lib/browser/index.mjs.map +4 -4
  3. package/dist/lib/browser/meta.json +1 -1
  4. package/dist/types/src/NavTreePlugin.d.ts.map +1 -1
  5. package/dist/types/src/capabilities/app-graph-builder.d.ts +6 -0
  6. package/dist/types/src/capabilities/app-graph-builder.d.ts.map +1 -0
  7. package/dist/types/src/capabilities/index.d.ts +7 -5
  8. package/dist/types/src/capabilities/index.d.ts.map +1 -1
  9. package/dist/types/src/capabilities/keyboard.d.ts +5 -0
  10. package/dist/types/src/capabilities/keyboard.d.ts.map +1 -0
  11. package/dist/types/src/capabilities/operation-handler.d.ts +6 -0
  12. package/dist/types/src/capabilities/operation-handler.d.ts.map +1 -0
  13. package/dist/types/src/capabilities/react-surface.d.ts +5 -0
  14. package/dist/types/src/capabilities/react-surface.d.ts.map +1 -0
  15. package/dist/types/src/capabilities/state.d.ts +6 -0
  16. package/dist/types/src/capabilities/state.d.ts.map +1 -0
  17. package/dist/types/src/components/NavTree/NavTree.d.ts +10 -32
  18. package/dist/types/src/components/NavTree/NavTree.d.ts.map +1 -1
  19. package/dist/types/src/components/NavTree/NavTree.stories.d.ts +10 -14
  20. package/dist/types/src/components/NavTree/NavTree.stories.d.ts.map +1 -1
  21. package/dist/types/src/components/{NavTreeContext.d.ts → NavTreeContext/NavTreeContext.d.ts} +1 -1
  22. package/dist/types/src/components/NavTreeContext/NavTreeContext.d.ts.map +1 -0
  23. package/dist/types/src/components/NavTreeContext/index.d.ts +2 -0
  24. package/dist/types/src/components/NavTreeContext/index.d.ts.map +1 -0
  25. package/dist/types/src/components/NavTreeItem/NavTreeItemAction.d.ts +7 -3
  26. package/dist/types/src/components/NavTreeItem/NavTreeItemAction.d.ts.map +1 -1
  27. package/dist/types/src/components/NavTreeItem/NavTreeItemAction.stories.d.ts +1 -1
  28. package/dist/types/src/components/NavTreeItem/NavTreeItemAction.stories.d.ts.map +1 -1
  29. package/dist/types/src/components/NavTreeItem/NavTreeItemColumns.d.ts.map +1 -1
  30. package/dist/types/src/components/Sidebar/L0Menu.d.ts +4 -1
  31. package/dist/types/src/components/Sidebar/L0Menu.d.ts.map +1 -1
  32. package/dist/types/src/components/Sidebar/L1Panel.d.ts +3 -6
  33. package/dist/types/src/components/Sidebar/L1Panel.d.ts.map +1 -1
  34. package/dist/types/src/components/Sidebar/L1Tabs.d.ts +3 -2
  35. package/dist/types/src/components/Sidebar/L1Tabs.d.ts.map +1 -1
  36. package/dist/types/src/components/UserAccountAvatar/UserAccountAvatar.stories.d.ts.map +1 -1
  37. package/dist/types/src/components/index.d.ts +0 -3
  38. package/dist/types/src/components/index.d.ts.map +1 -1
  39. package/dist/types/src/components/types.d.ts +5 -13
  40. package/dist/types/src/components/types.d.ts.map +1 -1
  41. package/dist/types/src/{components/CommandsDialog/CommandsDialog.d.ts → containers/CommandsDialogContent/CommandsDialogContent.d.ts} +1 -1
  42. package/dist/types/src/containers/CommandsDialogContent/CommandsDialogContent.d.ts.map +1 -0
  43. package/dist/types/src/containers/CommandsDialogContent/CommandsDialogContent.stories.d.ts +29 -0
  44. package/dist/types/src/containers/CommandsDialogContent/CommandsDialogContent.stories.d.ts.map +1 -0
  45. package/dist/types/src/containers/CommandsDialogContent/index.d.ts +2 -0
  46. package/dist/types/src/containers/CommandsDialogContent/index.d.ts.map +1 -0
  47. package/dist/types/src/containers/CommandsTrigger/CommandsTrigger.d.ts.map +1 -0
  48. package/dist/types/src/containers/CommandsTrigger/index.d.ts +2 -0
  49. package/dist/types/src/containers/CommandsTrigger/index.d.ts.map +1 -0
  50. package/dist/types/src/containers/NavTreeContainer/NavTreeContainer.d.ts +9 -0
  51. package/dist/types/src/containers/NavTreeContainer/NavTreeContainer.d.ts.map +1 -0
  52. package/dist/types/src/containers/NavTreeContainer/index.d.ts +3 -0
  53. package/dist/types/src/containers/NavTreeContainer/index.d.ts.map +1 -0
  54. package/dist/types/src/containers/NavTreeDocumentTitle/NavTreeDocumentTitle.d.ts.map +1 -0
  55. package/dist/types/src/containers/NavTreeDocumentTitle/index.d.ts +2 -0
  56. package/dist/types/src/containers/NavTreeDocumentTitle/index.d.ts.map +1 -0
  57. package/dist/types/src/containers/index.d.ts +7 -0
  58. package/dist/types/src/containers/index.d.ts.map +1 -0
  59. package/dist/types/src/experimental/Tree.stories.d.ts +18 -4
  60. package/dist/types/src/experimental/Tree.stories.d.ts.map +1 -1
  61. package/dist/types/src/hooks/index.d.ts +5 -0
  62. package/dist/types/src/hooks/index.d.ts.map +1 -0
  63. package/dist/types/src/hooks/useActions.d.ts +5 -0
  64. package/dist/types/src/hooks/useActions.d.ts.map +1 -0
  65. package/dist/types/src/hooks/useLoadDescendents.d.ts +6 -0
  66. package/dist/types/src/hooks/useLoadDescendents.d.ts.map +1 -0
  67. package/dist/types/src/hooks/useNavTreeModel.d.ts +7 -0
  68. package/dist/types/src/hooks/useNavTreeModel.d.ts.map +1 -0
  69. package/dist/types/src/{hooks.d.ts → hooks/useNavTreeState.d.ts} +2 -14
  70. package/dist/types/src/hooks/useNavTreeState.d.ts.map +1 -0
  71. package/dist/types/src/meta.d.ts.map +1 -1
  72. package/dist/types/src/operations/expose.d.ts +5 -0
  73. package/dist/types/src/operations/expose.d.ts.map +1 -0
  74. package/dist/types/src/operations/index.d.ts +3 -0
  75. package/dist/types/src/operations/index.d.ts.map +1 -0
  76. package/dist/types/src/testing/app-graph-builder.d.ts.map +1 -1
  77. package/dist/types/src/testing/generator.d.ts +3 -3
  78. package/dist/types/src/testing/generator.d.ts.map +1 -1
  79. package/dist/types/src/translations.d.ts +9 -10
  80. package/dist/types/src/translations.d.ts.map +1 -1
  81. package/dist/types/src/types/events.d.ts.map +1 -1
  82. package/dist/types/src/util.d.ts +6 -2
  83. package/dist/types/src/util.d.ts.map +1 -1
  84. package/dist/types/tsconfig.tsbuildinfo +1 -1
  85. package/package.json +54 -43
  86. package/src/NavTreePlugin.tsx +26 -27
  87. package/src/capabilities/{app-graph-builder/app-graph-builder.ts → app-graph-builder.ts} +10 -9
  88. package/src/capabilities/index.ts +11 -5
  89. package/src/capabilities/{keyboard/keyboard.ts → keyboard.ts} +7 -6
  90. package/src/capabilities/operation-handler.ts +16 -0
  91. package/src/capabilities/{react-surface/react-surface.tsx → react-surface.tsx} +15 -15
  92. package/src/capabilities/{state/state.ts → state.ts} +43 -15
  93. package/src/components/NavTree/NavTree.stories.tsx +30 -27
  94. package/src/components/NavTree/NavTree.tsx +64 -22
  95. package/src/components/{NavTreeContext.tsx → NavTreeContext/NavTreeContext.tsx} +1 -1
  96. package/src/components/NavTreeContext/index.ts +5 -0
  97. package/src/components/NavTreeItem/NavTreeItemAction.stories.tsx +7 -9
  98. package/src/components/NavTreeItem/NavTreeItemAction.tsx +56 -39
  99. package/src/components/NavTreeItem/NavTreeItemColumns.tsx +43 -17
  100. package/src/components/Sidebar/L0Menu.tsx +104 -113
  101. package/src/components/Sidebar/L1Panel.tsx +253 -94
  102. package/src/components/Sidebar/L1Tabs.tsx +13 -4
  103. package/src/components/UserAccountAvatar/UserAccountAvatar.stories.tsx +2 -3
  104. package/src/components/UserAccountAvatar/UserAccountAvatar.tsx +1 -1
  105. package/src/components/index.ts +0 -3
  106. package/src/components/types.ts +12 -17
  107. package/src/containers/CommandsDialogContent/CommandsDialogContent.stories.tsx +45 -0
  108. package/src/{components/CommandsDialog/CommandsDialog.tsx → containers/CommandsDialogContent/CommandsDialogContent.tsx} +23 -21
  109. package/src/containers/CommandsDialogContent/index.ts +5 -0
  110. package/src/containers/CommandsTrigger/CommandsTrigger.tsx +28 -0
  111. package/src/containers/CommandsTrigger/index.ts +5 -0
  112. package/src/{components → containers/NavTreeContainer}/NavTreeContainer.tsx +85 -142
  113. package/src/containers/NavTreeContainer/index.ts +6 -0
  114. package/src/{components → containers/NavTreeDocumentTitle}/NavTreeDocumentTitle.tsx +2 -2
  115. package/src/containers/NavTreeDocumentTitle/index.ts +5 -0
  116. package/src/containers/index.ts +12 -0
  117. package/src/experimental/Tree.stories.tsx +81 -84
  118. package/src/experimental/Tree.tsx +3 -3
  119. package/src/hooks/index.ts +8 -0
  120. package/src/hooks/useActions.ts +34 -0
  121. package/src/hooks/useLoadDescendents.ts +23 -0
  122. package/src/hooks/useNavTreeModel.ts +118 -0
  123. package/src/{hooks.ts → hooks/useNavTreeState.ts} +3 -34
  124. package/src/meta.ts +2 -2
  125. package/src/operations/expose.ts +42 -0
  126. package/src/operations/index.ts +7 -0
  127. package/src/testing/app-graph-builder.ts +40 -36
  128. package/src/testing/generator.ts +25 -25
  129. package/src/translations.ts +9 -10
  130. package/src/types/capabilities.ts +2 -2
  131. package/src/types/events.ts +4 -3
  132. package/src/util.ts +19 -5
  133. package/dist/lib/browser/app-graph-builder-RSMA6I22.mjs +0 -43
  134. package/dist/lib/browser/app-graph-builder-RSMA6I22.mjs.map +0 -7
  135. package/dist/lib/browser/chunk-6YPQ625I.mjs +0 -1293
  136. package/dist/lib/browser/chunk-6YPQ625I.mjs.map +0 -7
  137. package/dist/lib/browser/chunk-AGQDZBPL.mjs +0 -23
  138. package/dist/lib/browser/chunk-AGQDZBPL.mjs.map +0 -7
  139. package/dist/lib/browser/chunk-YKTYPINZ.mjs +0 -19
  140. package/dist/lib/browser/chunk-YKTYPINZ.mjs.map +0 -7
  141. package/dist/lib/browser/keyboard-32EH3N4K.mjs +0 -52
  142. package/dist/lib/browser/keyboard-32EH3N4K.mjs.map +0 -7
  143. package/dist/lib/browser/operation-resolver-IB75DC5O.mjs +0 -52
  144. package/dist/lib/browser/operation-resolver-IB75DC5O.mjs.map +0 -7
  145. package/dist/lib/browser/react-surface-F6CVMS3Y.mjs +0 -58
  146. package/dist/lib/browser/react-surface-F6CVMS3Y.mjs.map +0 -7
  147. package/dist/lib/browser/state-EVYQOUI3.mjs +0 -120
  148. package/dist/lib/browser/state-EVYQOUI3.mjs.map +0 -7
  149. package/dist/types/src/capabilities/app-graph-builder/app-graph-builder.d.ts +0 -6
  150. package/dist/types/src/capabilities/app-graph-builder/app-graph-builder.d.ts.map +0 -1
  151. package/dist/types/src/capabilities/app-graph-builder/index.d.ts +0 -3
  152. package/dist/types/src/capabilities/app-graph-builder/index.d.ts.map +0 -1
  153. package/dist/types/src/capabilities/keyboard/index.d.ts +0 -3
  154. package/dist/types/src/capabilities/keyboard/index.d.ts.map +0 -1
  155. package/dist/types/src/capabilities/keyboard/keyboard.d.ts +0 -5
  156. package/dist/types/src/capabilities/keyboard/keyboard.d.ts.map +0 -1
  157. package/dist/types/src/capabilities/operation-resolver/index.d.ts +0 -3
  158. package/dist/types/src/capabilities/operation-resolver/index.d.ts.map +0 -1
  159. package/dist/types/src/capabilities/operation-resolver/operation-resolver.d.ts +0 -5
  160. package/dist/types/src/capabilities/operation-resolver/operation-resolver.d.ts.map +0 -1
  161. package/dist/types/src/capabilities/react-surface/index.d.ts +0 -3
  162. package/dist/types/src/capabilities/react-surface/index.d.ts.map +0 -1
  163. package/dist/types/src/capabilities/react-surface/react-surface.d.ts +0 -5
  164. package/dist/types/src/capabilities/react-surface/react-surface.d.ts.map +0 -1
  165. package/dist/types/src/capabilities/state/index.d.ts +0 -3
  166. package/dist/types/src/capabilities/state/index.d.ts.map +0 -1
  167. package/dist/types/src/capabilities/state/state.d.ts +0 -6
  168. package/dist/types/src/capabilities/state/state.d.ts.map +0 -1
  169. package/dist/types/src/components/CommandsDialog/CommandsDialog.d.ts.map +0 -1
  170. package/dist/types/src/components/CommandsDialog/CommandsTrigger.d.ts.map +0 -1
  171. package/dist/types/src/components/CommandsDialog/index.d.ts +0 -3
  172. package/dist/types/src/components/CommandsDialog/index.d.ts.map +0 -1
  173. package/dist/types/src/components/NavTreeContainer.d.ts +0 -16
  174. package/dist/types/src/components/NavTreeContainer.d.ts.map +0 -1
  175. package/dist/types/src/components/NavTreeContext.d.ts.map +0 -1
  176. package/dist/types/src/components/NavTreeDocumentTitle.d.ts.map +0 -1
  177. package/dist/types/src/hooks.d.ts.map +0 -1
  178. package/src/capabilities/app-graph-builder/index.ts +0 -7
  179. package/src/capabilities/keyboard/index.ts +0 -7
  180. package/src/capabilities/operation-resolver/index.ts +0 -7
  181. package/src/capabilities/operation-resolver/operation-resolver.ts +0 -41
  182. package/src/capabilities/react-surface/index.ts +0 -7
  183. package/src/capabilities/state/index.ts +0 -7
  184. package/src/components/CommandsDialog/CommandsTrigger.tsx +0 -26
  185. package/src/components/CommandsDialog/index.ts +0 -6
  186. /package/dist/types/src/{components/CommandsDialog → containers/CommandsTrigger}/CommandsTrigger.d.ts +0 -0
  187. /package/dist/types/src/{components → containers/NavTreeDocumentTitle}/NavTreeDocumentTitle.d.ts +0 -0
@@ -2,19 +2,21 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import { combine } from '@atlaskit/pragmatic-drag-and-drop/combine';
6
- import { draggable, dropTargetForElements } from '@atlaskit/pragmatic-drag-and-drop/element/adapter';
7
- import { preserveOffsetOnSource } from '@atlaskit/pragmatic-drag-and-drop/element/preserve-offset-on-source';
8
- import { scrollJustEnoughIntoView } from '@atlaskit/pragmatic-drag-and-drop/element/scroll-just-enough-into-view';
9
5
  import {
10
6
  type Edge,
11
7
  attachClosestEdge,
12
8
  extractClosestEdge,
13
9
  } from '@atlaskit/pragmatic-drag-and-drop-hitbox/closest-edge';
10
+ import { combine } from '@atlaskit/pragmatic-drag-and-drop/combine';
11
+ import { draggable, dropTargetForElements } from '@atlaskit/pragmatic-drag-and-drop/element/adapter';
12
+ import { preserveOffsetOnSource } from '@atlaskit/pragmatic-drag-and-drop/element/preserve-offset-on-source';
13
+ import { scrollJustEnoughIntoView } from '@atlaskit/pragmatic-drag-and-drop/element/scroll-just-enough-into-view';
14
+ import { useAtomValue } from '@effect-atom/atom-react';
14
15
  import React, {
15
16
  type MouseEvent,
16
17
  type PropsWithChildren,
17
18
  forwardRef,
19
+ memo,
18
20
  useCallback,
19
21
  useLayoutEffect,
20
22
  useMemo,
@@ -27,6 +29,7 @@ import { DxAvatar } from '@dxos/lit-ui/react';
27
29
  import { useActionRunner } from '@dxos/plugin-graph';
28
30
  import {
29
31
  Icon,
32
+ IconButton,
30
33
  ListItem,
31
34
  ScrollArea,
32
35
  type ThemedClassName,
@@ -35,14 +38,15 @@ import {
35
38
  useMediaQuery,
36
39
  useTranslation,
37
40
  } from '@dxos/react-ui';
38
- import { DropdownMenu, type MenuItem, MenuProvider } from '@dxos/react-ui-menu';
41
+ import { Menu, type MenuItem } from '@dxos/react-ui-menu';
39
42
  import type { StackItemRearrangeHandler } from '@dxos/react-ui-stack';
40
43
  import { Tabs } from '@dxos/react-ui-tabs';
41
44
  import { mx } from '@dxos/ui-theme';
42
45
  import { arrayMove } from '@dxos/util';
43
46
 
44
- import { useNavTreeState } from '../../hooks';
45
- import { meta } from '../../meta';
47
+ import { useNavTreeState } from '#hooks';
48
+ import { meta } from '#meta';
49
+
46
50
  import { l0ItemType } from '../../util';
47
51
  import { useNavTreeContext } from '../NavTreeContext';
48
52
  import { UserAccountAvatar } from '../UserAccountAvatar';
@@ -60,6 +64,7 @@ type L0ItemRootProps = {
60
64
  item: Node.Node;
61
65
  parent?: Node.Node;
62
66
  path: string[];
67
+ onMouseEnter?: () => void;
63
68
  };
64
69
 
65
70
  type L0ItemProps = L0ItemRootProps & {
@@ -68,10 +73,11 @@ type L0ItemProps = L0ItemRootProps & {
68
73
  path: string[];
69
74
  pinned?: boolean;
70
75
  onRearrange?: StackItemRearrangeHandler<L0ItemData>;
76
+ onItemHover?: (params: { item: Node.Node }) => void;
71
77
  };
72
78
 
73
79
  const useL0ItemClick = ({ item, parent, path }: L0ItemProps, type: string) => {
74
- const { tab, onSelect, onTabChange } = useNavTreeContext();
80
+ const { onSelect, onTabChange } = useNavTreeContext();
75
81
  const { getItem } = useNavTreeState();
76
82
  const [isLg] = useMediaQuery('lg');
77
83
  const runAction = useActionRunner();
@@ -81,17 +87,15 @@ const useL0ItemClick = ({ item, parent, path }: L0ItemProps, type: string) => {
81
87
  switch (type) {
82
88
  case 'action': {
83
89
  const { properties: { caller } = {} } = item;
84
- return void runAction(item as Node.Action, caller ? { parent, caller } : { parent });
90
+ return void runAction(item as Node.Action, caller ? { parent, path, caller } : { parent, path });
85
91
  }
86
-
87
92
  case 'tab':
88
93
  return onTabChange?.(item);
89
-
90
94
  case 'link':
91
95
  return onSelect?.({ item, path, current: !getItem(path).current, option: event.altKey });
92
96
  }
93
97
  },
94
- [item, parent, type, tab, getItem, onSelect, onTabChange, isLg, runAction],
98
+ [item, parent, type, getItem, onSelect, onTabChange, isLg, runAction],
95
99
  );
96
100
  };
97
101
 
@@ -99,62 +103,62 @@ const l0Breakpoints: Record<string, string> = {
99
103
  lg: 'hidden lg:grid',
100
104
  };
101
105
 
102
- const l0ItemRoot =
103
- 'group/l0item flex is-full justify-center items-center relative data[type!="collection"]:cursor-pointer app-no-drag dx-focus-ring-group';
104
-
105
- const l0ItemContent = 'flex justify-center items-center dx-focus-ring-group-indicator transition-colors rounded-sm';
106
-
107
- const L0ItemRoot = forwardRef<HTMLElement, PropsWithChildren<L0ItemRootProps>>(
108
- ({ item, parent, path, children }, forwardedRef) => {
109
- const { getProps } = useNavTreeContext();
110
- const { id, testId } = getProps?.(item, path) ?? {};
111
- const type = l0ItemType(item);
112
- const itemPath = useMemo(() => [...path, item.id], [item.id, path]);
113
-
114
- const { t } = useTranslation(meta.id);
115
- const localizedString = toLocalizedString(item.properties.label, t);
116
-
117
- const handleClick = useL0ItemClick({ item, parent, path: itemPath }, type);
118
- const rootProps =
119
- type === 'tab'
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 };
122
-
123
- return (
124
- <Tooltip.Trigger asChild delayDuration={0} side='right' content={localizedString}>
125
- <Tabs.TabPrimitive
126
- {...(rootProps as any)}
127
- data-type={type}
128
- className={mx(l0ItemRoot, l0Breakpoints[item.properties.l0Breakpoint])}
129
- ref={forwardedRef}
130
- >
131
- {children}
132
- </Tabs.TabPrimitive>
133
- </Tooltip.Trigger>
134
- );
135
- },
106
+ const L0ItemRoot = memo(
107
+ forwardRef<HTMLButtonElement, PropsWithChildren<L0ItemRootProps>>(
108
+ ({ item, parent, path, onMouseEnter, children }, forwardedRef) => {
109
+ const { t } = useTranslation(meta.id);
110
+ const { model } = useNavTreeContext();
111
+ const itemPath = useMemo(() => [...path, item.id], [item.id, path]);
112
+ const { id, testId } = useAtomValue(model.itemProps(itemPath));
113
+ const localizedString = toLocalizedString(item.properties.label, t);
114
+
115
+ const type = l0ItemType(item);
116
+ const handleClick = useL0ItemClick({ item, parent, path: itemPath }, type);
117
+
118
+ return (
119
+ <Tooltip.Trigger asChild delayDuration={0} side='right' content={localizedString}>
120
+ <Tabs.TabPrimitive
121
+ className={mx(
122
+ 'group/l0item flex w-full justify-center items-center relative',
123
+ 'dx-app-no-drag dx-focus-ring-group data[type!="collection"]:cursor-pointer',
124
+ l0Breakpoints[item.properties.l0Breakpoint],
125
+ )}
126
+ tabIndex={type === 'tab' ? 0 : undefined}
127
+ data-type={type}
128
+ data-testid={testId}
129
+ data-object-id={id}
130
+ value={item.id}
131
+ onClick={handleClick}
132
+ onMouseEnter={onMouseEnter}
133
+ ref={forwardedRef}
134
+ >
135
+ {children}
136
+ </Tabs.TabPrimitive>
137
+ </Tooltip.Trigger>
138
+ );
139
+ },
140
+ ),
136
141
  );
137
142
 
138
143
  export const L0ItemActiveTabIndicator = ({ classNames }: ThemedClassName<{}>) => (
139
144
  <div
140
145
  role='none'
141
146
  className={mx(
142
- 'hidden group-aria-selected/l0item:block absolute inline-start-0 inset-block-2 is-1 bg-accentSurface rounded-ie',
147
+ 'hidden group-aria-selected/l0item:block absolute start-0 h-6 w-1.5 bg-accent-surface rounded-sm',
143
148
  classNames,
144
149
  )}
145
150
  />
146
151
  );
147
152
 
148
153
  // TODO(burdon): Factor out pinned (non-draggable) items.
149
- const L0Item = ({ item, parent, path, pinned, onRearrange }: L0ItemProps) => {
154
+ const L0Item = memo(({ item, parent, path, pinned, onRearrange, onItemHover }: L0ItemProps) => {
150
155
  const { t } = useTranslation(meta.id);
151
- const itemElement = useRef<HTMLElement | null>(null);
156
+ const itemElement = useRef<HTMLButtonElement | null>(null);
152
157
  const [closestEdge, setEdge] = useState<Edge | null>(null);
153
158
  const localizedString = toLocalizedString(item.properties.label, t);
154
159
  const hue = item.properties.hue ?? null;
155
160
 
156
161
  useLayoutEffect(() => {
157
- // NOTE(thure): This is copied from StackItem, perhaps this should be DRYed out.
158
162
  if (!itemElement.current || !onRearrange) {
159
163
  return;
160
164
  }
@@ -209,17 +213,19 @@ const L0Item = ({ item, parent, path, pinned, onRearrange }: L0ItemProps) => {
209
213
  );
210
214
  }, [item, onRearrange]);
211
215
 
216
+ const handleMouseEnter = useCallback(() => onItemHover?.({ item }), [item, onItemHover]);
217
+
212
218
  return (
213
- <L0ItemRoot ref={itemElement} item={item} parent={parent} path={path}>
219
+ <L0ItemRoot ref={itemElement} item={item} parent={parent} path={path} onMouseEnter={handleMouseEnter}>
214
220
  <div
215
221
  role='none'
216
222
  data-frame={true}
217
- {...(hue && { style: { background: `var(--dx-${hue}Surface)` } })}
223
+ {...(hue && { style: { background: `var(--color-${hue}-surface)` } })}
218
224
  className={mx(
219
- l0ItemContent,
225
+ 'flex justify-center items-center dx-focus-ring-group-indicator transition-colors rounded-sm',
220
226
  pinned
221
- ? 'p-2 group-hover/l0item:bg-activeSurface'
222
- : 'is-[--l0-avatar-size] bs-[--l0-avatar-size] bg-activeSurface',
227
+ ? 'p-2 group-hover/l0item:bg-active-surface'
228
+ : 'w-(--dx-l0-avatar-size) h-(--dx-l0-avatar-size) bg-active-surface',
223
229
  )}
224
230
  >
225
231
  <ItemAvatar item={item} />
@@ -231,17 +237,19 @@ const L0Item = ({ item, parent, path, pinned, onRearrange }: L0ItemProps) => {
231
237
  {closestEdge && <ListItem.DropIndicator edge={closestEdge} />}
232
238
  </L0ItemRoot>
233
239
  );
234
- };
240
+ });
235
241
 
236
242
  const ItemAvatar = ({ item }: Pick<L0ItemProps, 'item'>) => {
237
243
  const { t } = useTranslation(meta.id);
238
- const type = l0ItemType(item);
244
+
245
+ // Actions.
239
246
  if (item.properties.icon) {
240
247
  const hue = item.properties.hue ?? null;
241
- const hueFgStyle = hue && { style: { color: `var(--dx-${hue}SurfaceText)` } };
248
+ const hueFgStyle = hue && { style: { color: `var(--color-${hue}-surface-text)` } };
242
249
  return <Icon icon={item.properties.icon} size={6} {...hueFgStyle} />;
243
250
  }
244
251
 
252
+ const type = l0ItemType(item);
245
253
  if (type === 'tab' && item.properties.disposition !== 'pin-end') {
246
254
  const hue = item.properties.hue ?? null;
247
255
  const localizedString = toLocalizedString(item.properties.label, t);
@@ -262,9 +270,18 @@ export type L0MenuProps = {
262
270
  userAccountItem?: Node.Node;
263
271
  parent?: Node.Node;
264
272
  path: string[];
273
+ onItemHover?: (params: { item: Node.Node }) => void;
265
274
  };
266
275
 
267
- export const L0Menu = ({ menuActions, topLevelItems, pinnedItems, userAccountItem, parent, path }: L0MenuProps) => {
276
+ export const L0Menu = ({
277
+ menuActions,
278
+ topLevelItems,
279
+ pinnedItems,
280
+ userAccountItem,
281
+ parent,
282
+ path,
283
+ onItemHover,
284
+ }: L0MenuProps) => {
268
285
  const { t } = useTranslation(meta.id);
269
286
  const runAction = useActionRunner();
270
287
  const handleAction = useCallback(
@@ -299,76 +316,50 @@ export const L0Menu = ({ menuActions, topLevelItems, pinnedItems, userAccountIte
299
316
 
300
317
  return (
301
318
  <Tabs.Tablist
319
+ data-tauri-drag-region
302
320
  classNames={[
303
- 'group/l0 absolute z-[1] inset-block-0 inline-start-0 rounded-is',
304
- 'grid grid-cols-[var(--l0-size)] grid-rows-[var(--rail-size)_1fr_min-content_var(--l0-size)] contain-layout',
305
- '!is-[--l0-size] bg-baseSurface border-ie border-subduedSeparator app-drag pbe-[env(safe-area-inset-bottom)]',
321
+ 'group/l0 absolute z-[1] inset-y-0 start-0 rounded-is',
322
+ 'grid grid-cols-[var(--dx-l0-size)] grid-rows-[var(--dx-rail-size)_1fr_min-content_var(--dx-l0-size)] dx-contain-layout',
323
+ 'w-(--dx-l0-size) bg-toolbar-surface dx-app-drag pb-[env(safe-area-inset-bottom)]',
324
+ '[body[data-platform="macos"]_&]:pt-[30px]',
325
+ '[body[data-platform="ios"]_&]:pt-[max(env(safe-area-inset-top),0.25rem)]',
306
326
  ]}
307
327
  >
308
328
  {/* TODO(wittjosiah): Use L0Item trigger. */}
309
- <MenuProvider onAction={handleAction}>
310
- <DropdownMenu.Root group={parent} items={menuActions}>
311
- <Tooltip.Trigger content={t('app menu label')} side='right' asChild>
312
- <Tabs.TabPrimitive value='options' asChild role='button'>
313
- <DropdownMenu.Trigger
314
- data-testid='spacePlugin.addSpace'
315
- className={mx(
316
- l0ItemRoot,
317
- 'grid place-items-center dx-focus-ring-group',
318
- '[body[data-platform="macos"]_&]:mt-[30px]',
319
- )}
320
- >
321
- <div
322
- role='none'
323
- className={mx(
324
- l0ItemContent,
325
- 'is-[--rail-action] bs-[--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>
332
- </Tooltip.Trigger>
333
- </DropdownMenu.Root>
334
- </MenuProvider>
329
+ <Menu.Root onAction={handleAction}>
330
+ <Menu.Trigger asChild data-testid='spacePlugin.addSpace'>
331
+ <div role='none' className='grid place-items-center'>
332
+ <IconButton variant='ghost' icon='ph--list--regular' iconOnly label={t('app-menu.label')} />
333
+ </div>
334
+ </Menu.Trigger>
335
+ <Menu.Content group={parent} items={menuActions} />
336
+ </Menu.Root>
335
337
 
336
338
  {/* Space list. */}
337
- <ScrollArea.Root>
338
- <ScrollArea.Viewport>
339
- <div
340
- role='none'
341
- className={mx([
342
- 'flex flex-col gap-1 pbs-1',
343
- '[body[data-platform="macos"]_&]:pbs-[30px]',
344
- '[body[data-platform="ios"]_&]:pbs-[max(env(safe-area-inset-top),0.25rem)]',
345
- ])}
346
- >
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
- ))}
356
- </div>
357
- <ScrollArea.Scrollbar orientation='vertical'>
358
- <ScrollArea.Thumb />
359
- </ScrollArea.Scrollbar>
339
+ <ScrollArea.Root centered thin orientation='vertical'>
340
+ <ScrollArea.Viewport classNames='flex flex-col gap-2 py-1'>
341
+ {topLevelItems.map((item) => (
342
+ <L0Item
343
+ key={item.id}
344
+ item={item}
345
+ parent={parent}
346
+ path={path}
347
+ onItemHover={onItemHover}
348
+ {...(hasRearrangeableItems && { onRearrange: handleRearrange })}
349
+ />
350
+ ))}
360
351
  </ScrollArea.Viewport>
361
352
  </ScrollArea.Root>
362
353
 
363
354
  {/* Actions. */}
364
- <div role='none' className='grid grid-cols-1 auto-rows-[--rail-action] pbs-2'>
355
+ <div role='none' className='grid grid-cols-1 auto-rows-(--dx-rail-action) pt-2'>
365
356
  {pinnedItems.map((item) => (
366
357
  <L0Item key={item.id} item={item} parent={parent} path={path} pinned />
367
358
  ))}
368
359
  </div>
369
360
 
370
361
  {userAccountItem && (
371
- <div role='none' className='grid app-no-drag'>
362
+ <div role='none' className='grid dx-app-no-drag'>
372
363
  <L0ItemRoot key={userAccountItem.id} item={userAccountItem} parent={parent} path={path}>
373
364
  <UserAccountAvatar
374
365
  userId={userAccountItem.properties.userId}