@dxos/plugin-navtree 0.7.5-main.9d26e3a → 0.7.5-main.9d2a38b

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 (81) hide show
  1. package/dist/lib/browser/app-graph-builder-OF4MMBLH.mjs +42 -0
  2. package/dist/lib/browser/app-graph-builder-OF4MMBLH.mjs.map +7 -0
  3. package/dist/lib/browser/chunk-IMGT2LAL.mjs +658 -0
  4. package/dist/lib/browser/chunk-IMGT2LAL.mjs.map +7 -0
  5. package/dist/lib/browser/{chunk-VAXG4OAG.mjs → chunk-KOXMEAOS.mjs} +3 -3
  6. package/dist/lib/browser/{chunk-VAXG4OAG.mjs.map → chunk-KOXMEAOS.mjs.map} +3 -3
  7. package/dist/lib/browser/chunk-OI7AAA6Q.mjs +15 -0
  8. package/dist/lib/browser/chunk-OI7AAA6Q.mjs.map +7 -0
  9. package/dist/lib/browser/index.mjs +105 -1191
  10. package/dist/lib/browser/index.mjs.map +4 -4
  11. package/dist/lib/browser/intent-resolver-74JPWYBP.mjs +42 -0
  12. package/dist/lib/browser/intent-resolver-74JPWYBP.mjs.map +7 -0
  13. package/dist/lib/browser/keyboard-MUBRTPI5.mjs +46 -0
  14. package/dist/lib/browser/keyboard-MUBRTPI5.mjs.map +7 -0
  15. package/dist/lib/browser/meta.json +1 -1
  16. package/dist/lib/browser/react-surface-6QWXI53A.mjs +189 -0
  17. package/dist/lib/browser/react-surface-6QWXI53A.mjs.map +7 -0
  18. package/dist/lib/browser/state-HT65TAYL.mjs +111 -0
  19. package/dist/lib/browser/state-HT65TAYL.mjs.map +7 -0
  20. package/dist/types/src/NavTreePlugin.d.ts +1 -3
  21. package/dist/types/src/NavTreePlugin.d.ts.map +1 -1
  22. package/dist/types/src/capabilities/app-graph-builder.d.ts +181 -0
  23. package/dist/types/src/capabilities/app-graph-builder.d.ts.map +1 -0
  24. package/dist/types/src/capabilities/capabilities.d.ts +17 -0
  25. package/dist/types/src/capabilities/capabilities.d.ts.map +1 -0
  26. package/dist/types/src/capabilities/index.d.ts +195 -0
  27. package/dist/types/src/capabilities/index.d.ts.map +1 -0
  28. package/dist/types/src/capabilities/intent-resolver.d.ts +4 -0
  29. package/dist/types/src/capabilities/intent-resolver.d.ts.map +1 -0
  30. package/dist/types/src/capabilities/keyboard.d.ts +4 -0
  31. package/dist/types/src/capabilities/keyboard.d.ts.map +1 -0
  32. package/dist/types/src/capabilities/react-surface.d.ts +4 -0
  33. package/dist/types/src/capabilities/react-surface.d.ts.map +1 -0
  34. package/dist/types/src/capabilities/state.d.ts +17 -0
  35. package/dist/types/src/capabilities/state.d.ts.map +1 -0
  36. package/dist/types/src/components/NavTree.d.ts +0 -2
  37. package/dist/types/src/components/NavTree.d.ts.map +1 -1
  38. package/dist/types/src/components/NavTreeContainer.d.ts.map +1 -1
  39. package/dist/types/src/components/NavTreeFooter.d.ts.map +1 -1
  40. package/dist/types/src/components/NavTreeItemAction.d.ts +4 -8
  41. package/dist/types/src/components/NavTreeItemAction.d.ts.map +1 -1
  42. package/dist/types/src/components/NavTreeItemAction.stories.d.ts +0 -5
  43. package/dist/types/src/components/NavTreeItemAction.stories.d.ts.map +1 -1
  44. package/dist/types/src/components/NotchStart.d.ts.map +1 -1
  45. package/dist/types/src/components/index.d.ts +1 -0
  46. package/dist/types/src/components/index.d.ts.map +1 -1
  47. package/dist/types/src/events.d.ts +4 -0
  48. package/dist/types/src/events.d.ts.map +1 -0
  49. package/dist/types/src/index.d.ts +3 -2
  50. package/dist/types/src/index.d.ts.map +1 -1
  51. package/dist/types/src/meta.d.ts +1 -2
  52. package/dist/types/src/meta.d.ts.map +1 -1
  53. package/dist/types/src/translations.d.ts +0 -1
  54. package/dist/types/src/translations.d.ts.map +1 -1
  55. package/dist/types/src/types.d.ts +1 -1
  56. package/dist/types/src/types.d.ts.map +1 -1
  57. package/dist/types/tsconfig.tsbuildinfo +1 -1
  58. package/package.json +31 -38
  59. package/src/NavTreePlugin.tsx +70 -292
  60. package/src/capabilities/app-graph-builder.ts +40 -0
  61. package/src/capabilities/capabilities.ts +18 -0
  62. package/src/capabilities/index.ts +13 -0
  63. package/src/capabilities/intent-resolver.ts +30 -0
  64. package/src/capabilities/keyboard.ts +54 -0
  65. package/src/capabilities/react-surface.tsx +82 -0
  66. package/src/capabilities/state.ts +100 -0
  67. package/src/components/CommandsTrigger.tsx +1 -1
  68. package/src/components/NavTree.tsx +1 -9
  69. package/src/components/NavTreeContainer.tsx +15 -27
  70. package/src/components/NavTreeFooter.tsx +18 -16
  71. package/src/components/NavTreeItemAction.stories.tsx +0 -2
  72. package/src/components/NavTreeItemAction.tsx +51 -317
  73. package/src/components/NotchStart.tsx +5 -4
  74. package/src/components/index.ts +1 -0
  75. package/src/events.ts +11 -0
  76. package/src/index.ts +3 -4
  77. package/src/meta.ts +1 -1
  78. package/src/translations.ts +0 -1
  79. package/src/types.ts +1 -1
  80. package/dist/lib/browser/meta.mjs +0 -13
  81. package/dist/lib/browser/meta.mjs.map +0 -7
@@ -0,0 +1,100 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import { effect } from '@preact/signals-core';
6
+
7
+ import { Capabilities, contributes, type PluginsContext } from '@dxos/app-framework';
8
+ import { type ReactiveObject, create } from '@dxos/live-object';
9
+ import { Path } from '@dxos/react-ui-mosaic';
10
+
11
+ import { NavTreeCapabilities } from './capabilities';
12
+ import { NAVTREE_PLUGIN } from '../meta';
13
+
14
+ const KEY = `${NAVTREE_PLUGIN}/state`;
15
+
16
+ const getInitialState = () => {
17
+ const stringified = localStorage.getItem(KEY);
18
+ if (!stringified) {
19
+ return;
20
+ }
21
+
22
+ try {
23
+ const cached: [string, { open: boolean; current: boolean }][] = JSON.parse(stringified);
24
+ return cached.map(
25
+ ([key, value]): [
26
+ string,
27
+ ReactiveObject<{
28
+ open: boolean;
29
+ current: boolean;
30
+ }>,
31
+ ] => [key, create({ open: value.open, current: false })],
32
+ );
33
+ } catch {}
34
+ };
35
+
36
+ export default (context: PluginsContext) => {
37
+ // TODO(wittjosiah): This currently needs to be not a ReactiveObject at the root.
38
+ // If it is a ReactiveObject then React errors when initializing new paths because of state change during render.
39
+ // Ideally this could be a ReactiveObject but be able to access and update the root level without breaking render.
40
+ // Wrapping accesses and updates in `untracked` didn't seem to work in all cases.
41
+ const state = new Map<string, ReactiveObject<{ open: boolean; current: boolean }>>(
42
+ getInitialState() ?? [
43
+ // TODO(thure): Initialize these dynamically.
44
+ ['root', create({ open: true, current: false })],
45
+ ['root~dxos.org/plugin/space-spaces', create({ open: true, current: false })],
46
+ ['root~dxos.org/plugin/files', create({ open: true, current: false })],
47
+ ],
48
+ );
49
+
50
+ const getItem = (_path: string[]) => {
51
+ const path = Path.create(..._path);
52
+ const value = state.get(path) ?? create({ open: false, current: false });
53
+ if (!state.has(path)) {
54
+ state.set(path, value);
55
+ }
56
+
57
+ return value;
58
+ };
59
+
60
+ const setItem = (path: string[], key: 'open' | 'current', next: boolean) => {
61
+ const value = getItem(path);
62
+ value[key] = next;
63
+
64
+ localStorage.setItem(KEY, JSON.stringify(Array.from(state.entries())));
65
+ };
66
+
67
+ const isOpen = (path: string[]) => getItem(path).open;
68
+ const isCurrent = (path: string[]) => getItem(path).current;
69
+
70
+ const location = context.requestCapability(Capabilities.Location);
71
+ const layout = context.requestCapability(Capabilities.Layout);
72
+
73
+ let previous: string[] = [];
74
+ const unsubscribe = effect(() => {
75
+ const part = layout.layoutMode === 'solo' ? 'solo' : 'main';
76
+ const current = location.active[part]?.map(({ id }) => id) ?? [];
77
+ const removed = previous.filter((id) => !current.includes(id));
78
+ previous = current;
79
+
80
+ // TODO(wittjosiah): This is setTimeout because there's a race between the keys be initialized.
81
+ // This could be avoided if the location was a path as well and not just an id.
82
+ setTimeout(() => {
83
+ removed.forEach((id) => {
84
+ const keys = Array.from(state.keys()).filter((key) => Path.last(key) === id);
85
+ keys.forEach((key) => {
86
+ setItem(Path.parts(key), 'current', false);
87
+ });
88
+ });
89
+
90
+ current.forEach((id) => {
91
+ const keys = Array.from(new Set([...state.keys(), id])).filter((key) => Path.last(key) === id);
92
+ keys.forEach((key) => {
93
+ setItem(Path.parts(key), 'current', true);
94
+ });
95
+ });
96
+ });
97
+ });
98
+
99
+ return contributes(NavTreeCapabilities.State, { state, getItem, setItem, isOpen, isCurrent }, () => unsubscribe());
100
+ };
@@ -17,7 +17,7 @@ export const CommandsTrigger = () => {
17
17
  const { t } = useTranslation(NAVTREE_PLUGIN);
18
18
  return (
19
19
  <Button
20
- classNames='w-full h-full !rounded-none'
20
+ classNames='m-1 !pli-1 lg:!pli-2'
21
21
  onClick={() =>
22
22
  dispatch(
23
23
  createIntent(LayoutAction.SetLayout, {
@@ -23,15 +23,13 @@ export type NavTreeProps = Omit<
23
23
 
24
24
  export const NavTree = ({ getActions, loadDescendents, renderItemEnd, popoverAnchorId, ...props }: NavTreeProps) => {
25
25
  const renderColumns = useCallback<NonNullable<TreeProps<NavTreeItemGraphNode>['renderColumns']>>(
26
- ({ item, path, open, menuOpen, setMenuOpen }) => {
26
+ ({ item, path, open }) => {
27
27
  return (
28
28
  <NavTreeColumns
29
29
  path={path}
30
30
  node={item}
31
31
  getActions={getActions}
32
32
  open={open}
33
- menuOpen={menuOpen}
34
- setMenuOpen={setMenuOpen}
35
33
  loadDescendents={loadDescendents}
36
34
  renderItemEnd={renderItemEnd}
37
35
  popoverAnchorId={popoverAnchorId}
@@ -56,8 +54,6 @@ type NavTreeColumnsProps = {
56
54
  node: Node;
57
55
  getActions: (node: Node) => FlattenedActions;
58
56
  open: boolean;
59
- menuOpen: boolean;
60
- setMenuOpen: (open: boolean) => void;
61
57
  loadDescendents?: (node: Node) => MaybePromise<void>;
62
58
  renderItemEnd?: FC<{ node: Node; open: boolean }>;
63
59
  popoverAnchorId?: string;
@@ -68,8 +64,6 @@ const NavTreeColumns = ({
68
64
  node,
69
65
  getActions,
70
66
  open,
71
- menuOpen,
72
- setMenuOpen,
73
67
  loadDescendents,
74
68
  renderItemEnd: ItemEnd,
75
69
  popoverAnchorId,
@@ -126,8 +120,6 @@ const NavTreeColumns = ({
126
120
  menuActions={actions}
127
121
  menuType='dropdown'
128
122
  caller={NAV_TREE_ITEM}
129
- menuOpen={menuOpen}
130
- onChangeMenuOpen={setMenuOpen}
131
123
  />
132
124
  ) : (
133
125
  <Treegrid.Cell />
@@ -7,7 +7,7 @@ import { extractInstruction, type Instruction } from '@atlaskit/pragmatic-drag-a
7
7
  import { untracked } from '@preact/signals-core';
8
8
  import React, { memo, useCallback, useEffect } from 'react';
9
9
 
10
- import { createIntent, LayoutAction, NavigationAction, Surface, useIntentDispatcher } from '@dxos/app-framework';
10
+ import { createIntent, LayoutAction, NavigationAction, useIntentDispatcher, Surface } from '@dxos/app-framework';
11
11
  import { isAction, isActionLike, type Node } from '@dxos/app-graph';
12
12
  import { useGraph } from '@dxos/plugin-graph';
13
13
  import { isEchoObject, isSpace } from '@dxos/react-client/echo';
@@ -17,7 +17,6 @@ import { mx } from '@dxos/react-ui-theme';
17
17
  import { arrayMove } from '@dxos/util';
18
18
 
19
19
  import { NAV_TREE_ITEM, NavTree, type NavTreeProps } from './NavTree';
20
- import { NavTreeFooter } from './NavTreeFooter';
21
20
  import { NAVTREE_PLUGIN } from '../meta';
22
21
  import { type NavTreeItemGraphNode } from '../types';
23
22
  import {
@@ -202,31 +201,20 @@ export const NavTreeContainer = memo(({ isCurrent, popoverAnchorId, ...props }:
202
201
  });
203
202
  }, [graph]);
204
203
 
204
+ // TODO(thure): What gives this an inline `overflow: initial`?
205
205
  return (
206
- <div role='none' className='grid grid-cols-1 grid-rows-[var(--rail-size)_1fr_min-content] bs-full overflow-hidden'>
207
- {/* TODO(wittjosiah): Factor out surfaces to layout? */}
208
- <div role='none' className='border-be border-separator'>
209
- <Surface role='search-input' limit={1} />
210
- </div>
211
-
212
- {/* TODO(thure): What gives this an inline `overflow: initial`? */}
213
- <div role='none' className='border-be border-separator !overflow-y-auto'>
214
- <NavTree
215
- id={graph.root.id}
216
- getActions={getActions}
217
- getItems={getItems}
218
- getProps={getProps}
219
- isCurrent={isCurrent}
220
- loadDescendents={loadDescendents}
221
- renderItemEnd={renderItemEnd}
222
- popoverAnchorId={popoverAnchorId}
223
- canDrop={canDrop}
224
- onSelect={handleSelect}
225
- {...props}
226
- />
227
- </div>
228
-
229
- <NavTreeFooter />
230
- </div>
206
+ <NavTree
207
+ id={graph.root.id}
208
+ getActions={getActions}
209
+ getItems={getItems}
210
+ getProps={getProps}
211
+ isCurrent={isCurrent}
212
+ loadDescendents={loadDescendents}
213
+ renderItemEnd={renderItemEnd}
214
+ popoverAnchorId={popoverAnchorId}
215
+ canDrop={canDrop}
216
+ onSelect={handleSelect}
217
+ {...props}
218
+ />
231
219
  );
232
220
  });
@@ -2,17 +2,15 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
- import { ArrowSquareOut, GearSix, Warning } from '@phosphor-icons/react';
6
5
  import { formatDistance } from 'date-fns/formatDistance';
7
6
  import React from 'react';
8
7
 
9
8
  import {
10
9
  type LayoutPart,
11
10
  SettingsAction,
12
- parseNavigationPlugin,
13
- useResolvePlugin,
14
11
  useIntentDispatcher,
15
12
  createIntent,
13
+ usePluginManager,
16
14
  } from '@dxos/app-framework';
17
15
  import { useConfig } from '@dxos/react-client';
18
16
  import {
@@ -25,13 +23,15 @@ import {
25
23
  useDefaultValue,
26
24
  useSidebars,
27
25
  useTranslation,
26
+ Icon,
27
+ IconButton,
28
28
  } from '@dxos/react-ui';
29
29
  import { LayoutControls } from '@dxos/react-ui-stack';
30
- import { getSize, mx } from '@dxos/react-ui-theme';
30
+ import { mx } from '@dxos/react-ui-theme';
31
31
 
32
32
  import { NAVTREE_PLUGIN } from '../meta';
33
33
 
34
- const buttonStyles = 'pli-1.5 text-xs font-normal';
34
+ const buttonStyles = '!pli-1.5 text-xs font-normal';
35
35
 
36
36
  const repo = 'https://github.com/dxos/dxos';
37
37
 
@@ -44,7 +44,7 @@ export const NavTreeFooter = (props: { layoutPart?: LayoutPart }) => {
44
44
  const { navigationSidebarOpen } = useSidebars(NAVTREE_PLUGIN);
45
45
  const { dispatchPromise: dispatch } = useIntentDispatcher();
46
46
  const { version, timestamp, commitHash } = config.values.runtime?.app?.build ?? {};
47
- const navigationPlugin = useResolvePlugin(parseNavigationPlugin);
47
+ const manager = usePluginManager();
48
48
  const [_, v] = version?.match(VERSION_REGEX) ?? [];
49
49
 
50
50
  const releaseUrl =
@@ -58,7 +58,7 @@ export const NavTreeFooter = (props: { layoutPart?: LayoutPart }) => {
58
58
  <div
59
59
  role='none'
60
60
  className={mx(
61
- 'flex bs-[--rail-size] pbe-[env(safe-area-inset-bottom)] box-content justify-end',
61
+ 'flex pbe-[env(safe-area-inset-bottom)] box-content justify-end',
62
62
  layoutPart === 'complementary' && 'md:justify-end flex-row-reverse',
63
63
  )}
64
64
  >
@@ -76,7 +76,7 @@ export const NavTreeFooter = (props: { layoutPart?: LayoutPart }) => {
76
76
  >
77
77
  <Message.Root valence='warning' className='rounded-be-none p-5'>
78
78
  <Message.Title>
79
- <Warning weight='duotone' className='inline mie-2 is-6 bs-6' />
79
+ <Icon icon='ph--warning--duotone' size={6} classNames='inline mie-2' />
80
80
  <span>{t('warning title')}</span>
81
81
  </Message.Title>
82
82
  <Message.Body>
@@ -84,7 +84,7 @@ export const NavTreeFooter = (props: { layoutPart?: LayoutPart }) => {
84
84
  <br />
85
85
  <Link href={previewUrl} target='_blank' rel='noreferrer' variant='neutral'>
86
86
  {t('learn more label')}
87
- <ArrowSquareOut className='inline mis-1' weight='bold' />
87
+ <Icon icon='ph--arrow-square-out--bold' classNames='inline mis-1' />
88
88
  </Link>
89
89
  </Message.Body>
90
90
  </Message.Root>
@@ -97,7 +97,7 @@ export const NavTreeFooter = (props: { layoutPart?: LayoutPart }) => {
97
97
  <br />
98
98
  <Link href={releaseUrl} target='_blank' rel='noreferrer' variant='neutral'>
99
99
  {t('see release label')}
100
- <ArrowSquareOut className='inline mis-1' weight='bold' />
100
+ <Icon icon='ph--arrow-square-out--bold' classNames='inline mis-1' />
101
101
  </Link>
102
102
  </p>
103
103
  )}
@@ -121,17 +121,19 @@ export const NavTreeFooter = (props: { layoutPart?: LayoutPart }) => {
121
121
  <Tooltip.Root>
122
122
  <Tooltip.Trigger asChild>
123
123
  {/* TODO(burdon): Reconcile with action created by LayoutPlugin. */}
124
- <Button
124
+ <IconButton
125
+ icon='ph--gear-six--regular'
126
+ iconOnly
127
+ label={t('open settings label')}
128
+ size={4}
125
129
  variant='ghost'
126
130
  classNames={buttonStyles}
127
131
  data-testid='treeView.openSettings'
128
132
  data-joyride='welcome/settings'
129
133
  {...(!navigationSidebarOpen && { tabIndex: -1 })}
134
+ iconClassNames='rotate-90'
130
135
  onClick={() => dispatch(createIntent(SettingsAction.Open))}
131
- >
132
- <span className='sr-only'>{t('open settings label')}</span>
133
- <GearSix className={mx(getSize(5), 'rotate-90')} />
134
- </Button>
136
+ />
135
137
  </Tooltip.Trigger>
136
138
  <Tooltip.Portal>
137
139
  <Tooltip.Content classNames='z-[12]'>
@@ -142,7 +144,7 @@ export const NavTreeFooter = (props: { layoutPart?: LayoutPart }) => {
142
144
  </Tooltip.Root>
143
145
 
144
146
  {/* NOTE(thure): Unpinning from the NavTree’s default position in Deck is temporarily disabled. */}
145
- {navigationPlugin?.meta.id === 'dxos.org/plugin/deck' && (
147
+ {manager.enabled.includes('dxos.org/plugin/deck') && (
146
148
  <LayoutControls
147
149
  variant='hide-disabled'
148
150
  capabilities={{
@@ -53,5 +53,3 @@ export default {
53
53
  };
54
54
 
55
55
  export const Default = {};
56
-
57
- export const SearchList = { args: { menuType: 'searchList' } };