@dxos/plugin-deck 0.7.5-main.9d26e3a → 0.7.5-main.b19bfc8

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 (188) hide show
  1. package/dist/lib/browser/app-graph-builder-IYHAGFA3.mjs +151 -0
  2. package/dist/lib/browser/app-graph-builder-IYHAGFA3.mjs.map +7 -0
  3. package/dist/lib/browser/check-app-scheme-S3EYUPMF.mjs +33 -0
  4. package/dist/lib/browser/check-app-scheme-S3EYUPMF.mjs.map +7 -0
  5. package/dist/lib/browser/chunk-22AQ5IVX.mjs +17 -0
  6. package/dist/lib/browser/chunk-22AQ5IVX.mjs.map +7 -0
  7. package/dist/lib/browser/chunk-CYE6QZBQ.mjs +128 -0
  8. package/dist/lib/browser/chunk-CYE6QZBQ.mjs.map +7 -0
  9. package/dist/lib/browser/chunk-DIM5INBX.mjs +24 -0
  10. package/dist/lib/browser/chunk-DIM5INBX.mjs.map +7 -0
  11. package/dist/lib/browser/chunk-DIXE74SK.mjs +1097 -0
  12. package/dist/lib/browser/chunk-DIXE74SK.mjs.map +7 -0
  13. package/dist/lib/browser/chunk-KANJBSIX.mjs +97 -0
  14. package/dist/lib/browser/chunk-KANJBSIX.mjs.map +7 -0
  15. package/dist/lib/browser/{chunk-GVOGPULO.mjs → chunk-N7TEPFVR.mjs} +5 -4
  16. package/dist/lib/browser/chunk-N7TEPFVR.mjs.map +7 -0
  17. package/dist/lib/browser/index.mjs +104 -1776
  18. package/dist/lib/browser/index.mjs.map +4 -4
  19. package/dist/lib/browser/intent-resolver-MWUADUNI.mjs +488 -0
  20. package/dist/lib/browser/intent-resolver-MWUADUNI.mjs.map +7 -0
  21. package/dist/lib/browser/meta.json +1 -1
  22. package/dist/lib/browser/react-root-IELFERPV.mjs +45 -0
  23. package/dist/lib/browser/react-root-IELFERPV.mjs.map +7 -0
  24. package/dist/lib/browser/react-surface-WL45R43W.mjs +39 -0
  25. package/dist/lib/browser/react-surface-WL45R43W.mjs.map +7 -0
  26. package/dist/lib/browser/settings-YONG3QB7.mjs +28 -0
  27. package/dist/lib/browser/settings-YONG3QB7.mjs.map +7 -0
  28. package/dist/lib/browser/state-MZZL5S2D.mjs +124 -0
  29. package/dist/lib/browser/state-MZZL5S2D.mjs.map +7 -0
  30. package/dist/lib/browser/tools-5LDJNU56.mjs +51 -0
  31. package/dist/lib/browser/tools-5LDJNU56.mjs.map +7 -0
  32. package/dist/lib/browser/types.mjs +16 -4
  33. package/dist/lib/browser/url-handler-MVHTKUYA.mjs +72 -0
  34. package/dist/lib/browser/url-handler-MVHTKUYA.mjs.map +7 -0
  35. package/dist/types/src/DeckPlugin.d.ts +1 -5
  36. package/dist/types/src/DeckPlugin.d.ts.map +1 -1
  37. package/dist/types/src/capabilities/app-graph-builder.d.ts +181 -0
  38. package/dist/types/src/capabilities/app-graph-builder.d.ts.map +1 -0
  39. package/dist/types/src/capabilities/capabilities.d.ts +142 -0
  40. package/dist/types/src/capabilities/capabilities.d.ts.map +1 -0
  41. package/dist/types/src/capabilities/check-app-scheme.d.ts +4 -0
  42. package/dist/types/src/capabilities/check-app-scheme.d.ts.map +1 -0
  43. package/dist/types/src/capabilities/index.d.ts +190 -0
  44. package/dist/types/src/capabilities/index.d.ts.map +1 -0
  45. package/dist/types/src/capabilities/intent-resolver.d.ts +4 -0
  46. package/dist/types/src/capabilities/intent-resolver.d.ts.map +1 -0
  47. package/dist/types/src/capabilities/react-root.d.ts +7 -0
  48. package/dist/types/src/capabilities/react-root.d.ts.map +1 -0
  49. package/dist/types/src/capabilities/react-surface.d.ts +4 -0
  50. package/dist/types/src/capabilities/react-surface.d.ts.map +1 -0
  51. package/dist/types/src/capabilities/settings.d.ts +4 -0
  52. package/dist/types/src/capabilities/settings.d.ts.map +1 -0
  53. package/dist/types/src/capabilities/state.d.ts +79 -0
  54. package/dist/types/src/capabilities/state.d.ts.map +1 -0
  55. package/dist/types/src/capabilities/tools.d.ts +10 -0
  56. package/dist/types/src/capabilities/tools.d.ts.map +1 -0
  57. package/dist/types/src/capabilities/url-handler.d.ts +4 -0
  58. package/dist/types/src/capabilities/url-handler.d.ts.map +1 -0
  59. package/dist/types/src/components/DeckLayout/ActiveNode.d.ts +1 -2
  60. package/dist/types/src/components/DeckLayout/ActiveNode.d.ts.map +1 -1
  61. package/dist/types/src/components/DeckLayout/Banner.d.ts +5 -0
  62. package/dist/types/src/components/DeckLayout/Banner.d.ts.map +1 -0
  63. package/dist/types/src/components/DeckLayout/ComplementarySidebar.d.ts +1 -4
  64. package/dist/types/src/components/DeckLayout/ComplementarySidebar.d.ts.map +1 -1
  65. package/dist/types/src/components/DeckLayout/ContentEmpty.d.ts +1 -2
  66. package/dist/types/src/components/DeckLayout/ContentEmpty.d.ts.map +1 -1
  67. package/dist/types/src/components/DeckLayout/DeckLayout.d.ts +2 -7
  68. package/dist/types/src/components/DeckLayout/DeckLayout.d.ts.map +1 -1
  69. package/dist/types/src/components/DeckLayout/Fallback.d.ts +1 -2
  70. package/dist/types/src/components/DeckLayout/Fallback.d.ts.map +1 -1
  71. package/dist/types/src/components/DeckLayout/Fullscreen.d.ts +1 -2
  72. package/dist/types/src/components/DeckLayout/Fullscreen.d.ts.map +1 -1
  73. package/dist/types/src/components/DeckLayout/NodePlankHeading.d.ts +3 -3
  74. package/dist/types/src/components/DeckLayout/NodePlankHeading.d.ts.map +1 -1
  75. package/dist/types/src/components/DeckLayout/Plank.d.ts +8 -6
  76. package/dist/types/src/components/DeckLayout/Plank.d.ts.map +1 -1
  77. package/dist/types/src/components/DeckLayout/PlankControls.d.ts +2 -2
  78. package/dist/types/src/components/DeckLayout/PlankControls.d.ts.map +1 -1
  79. package/dist/types/src/components/DeckLayout/PlankError.d.ts +6 -6
  80. package/dist/types/src/components/DeckLayout/PlankError.d.ts.map +1 -1
  81. package/dist/types/src/components/DeckLayout/PlankLoading.d.ts +1 -2
  82. package/dist/types/src/components/DeckLayout/PlankLoading.d.ts.map +1 -1
  83. package/dist/types/src/components/DeckLayout/Sidebar.d.ts +1 -6
  84. package/dist/types/src/components/DeckLayout/Sidebar.d.ts.map +1 -1
  85. package/dist/types/src/components/DeckLayout/SidebarButton.d.ts +7 -0
  86. package/dist/types/src/components/DeckLayout/SidebarButton.d.ts.map +1 -0
  87. package/dist/types/src/components/DeckLayout/StatusBar.d.ts +1 -2
  88. package/dist/types/src/components/DeckLayout/StatusBar.d.ts.map +1 -1
  89. package/dist/types/src/components/DeckLayout/Toast.d.ts +2 -3
  90. package/dist/types/src/components/DeckLayout/Toast.d.ts.map +1 -1
  91. package/dist/types/src/components/DeckLayout/Topbar.d.ts +2 -0
  92. package/dist/types/src/components/DeckLayout/Topbar.d.ts.map +1 -0
  93. package/dist/types/src/components/LayoutSettings.d.ts +1 -2
  94. package/dist/types/src/components/LayoutSettings.d.ts.map +1 -1
  95. package/dist/types/src/components/fragments.d.ts +4 -0
  96. package/dist/types/src/components/fragments.d.ts.map +1 -0
  97. package/dist/types/src/components/index.d.ts +0 -2
  98. package/dist/types/src/components/index.d.ts.map +1 -1
  99. package/dist/types/src/events.d.ts +5 -0
  100. package/dist/types/src/events.d.ts.map +1 -0
  101. package/dist/types/src/hooks/useMainSize.d.ts +2 -2
  102. package/dist/types/src/hooks/useNode.d.ts.map +1 -1
  103. package/dist/types/src/index.d.ts +3 -2
  104. package/dist/types/src/index.d.ts.map +1 -1
  105. package/dist/types/src/layout.d.ts +5 -19
  106. package/dist/types/src/layout.d.ts.map +1 -1
  107. package/dist/types/src/meta.d.ts +4 -4
  108. package/dist/types/src/meta.d.ts.map +1 -1
  109. package/dist/types/src/translations.d.ts +4 -2
  110. package/dist/types/src/translations.d.ts.map +1 -1
  111. package/dist/types/src/types.d.ts +121 -20
  112. package/dist/types/src/types.d.ts.map +1 -1
  113. package/dist/types/src/util/index.d.ts +4 -2
  114. package/dist/types/src/util/index.d.ts.map +1 -1
  115. package/dist/types/src/util/layoutAppliesTopbar.d.ts +2 -0
  116. package/dist/types/src/util/layoutAppliesTopbar.d.ts.map +1 -0
  117. package/dist/types/src/util/set-active.d.ts +9 -0
  118. package/dist/types/src/util/set-active.d.ts.map +1 -0
  119. package/dist/types/src/util/useBreakpoints.d.ts +2 -0
  120. package/dist/types/src/util/useBreakpoints.d.ts.map +1 -0
  121. package/dist/types/src/util/useHoistStatusbar.d.ts +2 -0
  122. package/dist/types/src/util/useHoistStatusbar.d.ts.map +1 -0
  123. package/dist/types/tsconfig.tsbuildinfo +1 -1
  124. package/package.json +32 -37
  125. package/src/DeckPlugin.ts +87 -0
  126. package/src/capabilities/app-graph-builder.ts +113 -0
  127. package/src/capabilities/capabilities.ts +15 -0
  128. package/src/capabilities/check-app-scheme.ts +44 -0
  129. package/src/capabilities/index.ts +17 -0
  130. package/src/capabilities/intent-resolver.ts +368 -0
  131. package/src/capabilities/react-root.tsx +46 -0
  132. package/src/capabilities/react-surface.tsx +31 -0
  133. package/src/capabilities/settings.ts +21 -0
  134. package/src/capabilities/state.ts +107 -0
  135. package/src/capabilities/tools.ts +61 -0
  136. package/src/capabilities/url-handler.ts +65 -0
  137. package/src/components/DeckLayout/ActiveNode.tsx +2 -3
  138. package/src/components/DeckLayout/Banner.tsx +37 -0
  139. package/src/components/DeckLayout/ComplementarySidebar.tsx +142 -59
  140. package/src/components/DeckLayout/ContentEmpty.tsx +9 -4
  141. package/src/components/DeckLayout/DeckLayout.tsx +151 -99
  142. package/src/components/DeckLayout/Fullscreen.tsx +2 -3
  143. package/src/components/DeckLayout/NodePlankHeading.tsx +64 -77
  144. package/src/components/DeckLayout/Plank.tsx +35 -43
  145. package/src/components/DeckLayout/PlankControls.tsx +12 -11
  146. package/src/components/DeckLayout/PlankError.tsx +6 -5
  147. package/src/components/DeckLayout/Sidebar.tsx +19 -9
  148. package/src/components/DeckLayout/SidebarButton.tsx +68 -0
  149. package/src/components/DeckLayout/StatusBar.tsx +6 -12
  150. package/src/components/DeckLayout/Toast.tsx +2 -2
  151. package/src/components/DeckLayout/Topbar.tsx +11 -0
  152. package/src/components/LayoutSettings.tsx +8 -8
  153. package/src/components/fragments.ts +14 -0
  154. package/src/components/index.ts +0 -2
  155. package/src/events.ts +12 -0
  156. package/src/hooks/useMainSize.ts +3 -3
  157. package/src/hooks/useNode.ts +3 -1
  158. package/src/index.ts +3 -4
  159. package/src/layout.ts +43 -212
  160. package/src/meta.ts +3 -2
  161. package/src/translations.ts +8 -6
  162. package/src/types.ts +104 -36
  163. package/src/util/index.ts +4 -2
  164. package/src/util/layoutAppliesTopbar.ts +7 -0
  165. package/src/util/set-active.ts +47 -0
  166. package/src/util/useBreakpoints.ts +11 -0
  167. package/src/util/useHoistStatusbar.ts +20 -0
  168. package/dist/lib/browser/chunk-GVOGPULO.mjs.map +0 -7
  169. package/dist/lib/browser/chunk-ZC3K6C2W.mjs +0 -37
  170. package/dist/lib/browser/chunk-ZC3K6C2W.mjs.map +0 -7
  171. package/dist/lib/browser/meta.mjs +0 -9
  172. package/dist/lib/browser/meta.mjs.map +0 -7
  173. package/dist/types/src/components/DeckContext.d.ts +0 -8
  174. package/dist/types/src/components/DeckContext.d.ts.map +0 -1
  175. package/dist/types/src/components/LayoutContext.d.ts +0 -5
  176. package/dist/types/src/components/LayoutContext.d.ts.map +0 -1
  177. package/dist/types/src/layout.test.d.ts +0 -2
  178. package/dist/types/src/layout.test.d.ts.map +0 -1
  179. package/dist/types/src/util/check-app-scheme.d.ts +0 -2
  180. package/dist/types/src/util/check-app-scheme.d.ts.map +0 -1
  181. package/dist/types/src/util/layout-parts.d.ts +0 -7
  182. package/dist/types/src/util/layout-parts.d.ts.map +0 -1
  183. package/src/DeckPlugin.tsx +0 -623
  184. package/src/components/DeckContext.ts +0 -14
  185. package/src/components/LayoutContext.ts +0 -12
  186. package/src/layout.test.ts +0 -380
  187. package/src/util/check-app-scheme.ts +0 -21
  188. package/src/util/layout-parts.ts +0 -12
@@ -5,66 +5,58 @@
5
5
  import React, { type KeyboardEvent, memo, useCallback, useLayoutEffect, useMemo, useRef } from 'react';
6
6
 
7
7
  import {
8
- type LayoutCoordinate,
9
- type LayoutEntry,
10
- type LayoutPart,
11
- type LayoutParts,
8
+ createIntent,
9
+ LayoutAction,
12
10
  Surface,
11
+ useCapability,
12
+ useAppGraph,
13
13
  useIntentDispatcher,
14
- type Layout,
15
- indexInPart,
16
- partLength,
17
- LayoutAction,
18
- createIntent,
19
14
  } from '@dxos/app-framework';
20
15
  import { debounce } from '@dxos/async';
21
- import { useGraph } from '@dxos/plugin-graph';
22
16
  import { useAttendableAttributes } from '@dxos/react-ui-attention';
23
17
  import { StackItem, railGridHorizontal } from '@dxos/react-ui-stack';
24
18
  import { mainIntrinsicSize, mx } from '@dxos/react-ui-theme';
25
19
 
26
- import { NodePlankHeading } from './NodePlankHeading';
20
+ import { NodePlankHeading, type NodePlankHeadingProps } from './NodePlankHeading';
27
21
  import { PlankContentError, PlankError } from './PlankError';
28
22
  import { PlankLoading } from './PlankLoading';
23
+ import { DeckCapabilities } from '../../capabilities';
29
24
  import { useNode, useMainSize } from '../../hooks';
30
- import { DeckAction } from '../../types';
31
- import { useDeckContext } from '../DeckContext';
32
- import { useLayout } from '../LayoutContext';
25
+ import { DeckAction, type LayoutMode } from '../../types';
33
26
 
34
27
  const UNKNOWN_ID = 'unknown_id';
35
28
 
36
29
  export type PlankProps = {
37
- entry?: LayoutEntry;
38
- layoutParts: LayoutParts;
39
- // TODO(wittjosiah): Remove. Pass in LayoutCoordinate instead of LayoutEntry.
40
- part: LayoutPart;
41
- layoutMode: Layout['layoutMode'];
30
+ id?: string;
31
+ part: NodePlankHeadingProps['part'];
32
+ path?: string[];
42
33
  order?: number;
34
+ active?: string[];
35
+ layoutMode: LayoutMode;
43
36
  };
44
37
 
45
- export const Plank = memo(({ entry, layoutParts, part, layoutMode, order }: PlankProps) => {
38
+ export const Plank = memo(({ id = UNKNOWN_ID, part, path, order, active, layoutMode }: PlankProps) => {
46
39
  const { dispatchPromise: dispatch } = useIntentDispatcher();
47
- const coordinate: LayoutCoordinate = useMemo(() => ({ part, entryId: entry?.id ?? UNKNOWN_ID }), [entry?.id, part]);
48
- const { popoverAnchorId, scrollIntoView } = useLayout();
49
- const { plankSizing } = useDeckContext();
50
- const { graph } = useGraph();
51
- const node = useNode(graph, entry?.id);
40
+ const { deck, popoverAnchorId, scrollIntoView } = useCapability(DeckCapabilities.DeckState);
41
+ const { graph } = useAppGraph();
42
+ const node = useNode(graph, id);
52
43
  const rootElement = useRef<HTMLDivElement | null>(null);
53
44
  const canResize = layoutMode === 'deck';
54
45
  const Root = part === 'solo' ? 'article' : StackItem.Root;
55
46
 
56
- const attendableAttrs = useAttendableAttributes(coordinate.entryId);
57
- const index = indexInPart(layoutParts, coordinate);
58
- const length = partLength(layoutParts, part);
59
- const canIncrementStart = part === 'main' && index !== undefined && index > 0 && length !== undefined && length > 1;
60
- const canIncrementEnd = part === 'main' && index !== undefined && index < length - 1 && length !== undefined;
47
+ const attendableAttrs = useAttendableAttributes(id);
48
+ const index = active ? active.findIndex((entryId) => entryId === id) : 0;
49
+ const length = active?.length ?? 1;
50
+ const canIncrementStart = active && index !== undefined && index > 0 && length !== undefined && length > 1;
51
+ const canIncrementEnd = active && index !== undefined && index < length - 1 && length !== undefined;
61
52
 
62
- const size = plankSizing?.[coordinate.entryId] as number | undefined;
53
+ const key = id.split('+')[0];
54
+ const size = deck.plankSizing[key] as number | undefined;
63
55
  const setSize = useCallback(
64
56
  debounce((nextSize: number) => {
65
- return dispatch(createIntent(DeckAction.UpdatePlankSize, { id: coordinate.entryId, size: nextSize }));
57
+ return dispatch(createIntent(DeckAction.UpdatePlankSize, { id: key, size: nextSize }));
66
58
  }, 200),
67
- [dispatch, coordinate.entryId],
59
+ [dispatch, key],
68
60
  );
69
61
 
70
62
  // TODO(thure): Tabster’s focus group should handle moving focus to Main, but something is blocking it.
@@ -75,19 +67,19 @@ export const Plank = memo(({ entry, layoutParts, part, layoutMode, order }: Plan
75
67
  }, []);
76
68
 
77
69
  useLayoutEffect(() => {
78
- if (scrollIntoView === coordinate.entryId) {
70
+ if (scrollIntoView === id) {
79
71
  // TODO(wittjosiah): When focused on page load, the focus is always visible.
80
72
  // Forcing focus to something smaller than the plank prevents large focus ring in the interim.
81
73
  const focusable = rootElement.current?.querySelector('button') || rootElement.current;
82
74
  focusable?.focus({ preventScroll: true });
83
75
  layoutMode === 'deck' && focusable?.scrollIntoView({ behavior: 'smooth', inline: 'center' });
84
76
  // Clear the scroll into view state once it has been actioned.
85
- void dispatch(createIntent(LayoutAction.ScrollIntoView, { id: undefined }));
77
+ void dispatch(createIntent(LayoutAction.ScrollIntoView, { part: 'current', subject: undefined }));
86
78
  }
87
- }, [coordinate.entryId, scrollIntoView, layoutMode]);
79
+ }, [id, scrollIntoView, layoutMode]);
88
80
 
89
81
  const isSolo = layoutMode === 'solo' && part === 'solo';
90
- const isAttendable = isSolo || (layoutMode === 'deck' && part === 'main');
82
+ const isAttendable = isSolo || (layoutMode === 'deck' && part === 'deck');
91
83
 
92
84
  const sizeAttrs = useMainSize();
93
85
 
@@ -95,11 +87,10 @@ export const Plank = memo(({ entry, layoutParts, part, layoutMode, order }: Plan
95
87
  () =>
96
88
  node && {
97
89
  subject: node.data,
98
- path: entry?.path,
99
- coordinate,
90
+ path,
100
91
  popoverAnchorId,
101
92
  },
102
- [node, node?.data, entry?.path, coordinate, popoverAnchorId],
93
+ [node, node?.data, path, popoverAnchorId],
103
94
  );
104
95
 
105
96
  // TODO(wittjosiah): Change prop to accept a component.
@@ -120,7 +111,7 @@ export const Plank = memo(({ entry, layoutParts, part, layoutMode, order }: Plan
120
111
  {...(part === 'solo'
121
112
  ? ({ ...sizeAttrs, className } as any)
122
113
  : {
123
- item: { id: entry?.id ?? 'never' },
114
+ item: { id },
124
115
  size,
125
116
  onSizeChange: setSize,
126
117
  classNames: className,
@@ -133,7 +124,8 @@ export const Plank = memo(({ entry, layoutParts, part, layoutMode, order }: Plan
133
124
  {node ? (
134
125
  <>
135
126
  <NodePlankHeading
136
- coordinate={coordinate}
127
+ id={id}
128
+ part={part}
137
129
  node={node}
138
130
  canIncrementStart={canIncrementStart}
139
131
  canIncrementEnd={canIncrementEnd}
@@ -149,7 +141,7 @@ export const Plank = memo(({ entry, layoutParts, part, layoutMode, order }: Plan
149
141
  />
150
142
  </>
151
143
  ) : (
152
- <PlankError layoutCoordinate={coordinate} />
144
+ <PlankError id={id} part={part} />
153
145
  )}
154
146
  {canResize && <StackItem.ResizeHandle />}
155
147
  </Root>
@@ -4,7 +4,6 @@
4
4
 
5
5
  import React, { forwardRef } from 'react';
6
6
 
7
- import { type PartAdjustment } from '@dxos/app-framework';
8
7
  import {
9
8
  Button,
10
9
  ButtonGroup,
@@ -16,8 +15,9 @@ import {
16
15
  } from '@dxos/react-ui';
17
16
 
18
17
  import { DECK_PLUGIN } from '../../meta';
18
+ import { type DeckAction } from '../../types';
19
19
 
20
- export type PlankControlHandler = (event: PartAdjustment) => void;
20
+ export type PlankControlHandler = (event: DeckAction.PartAdjustment) => void;
21
21
 
22
22
  export type PlankCapabilities = {
23
23
  incrementStart?: boolean;
@@ -40,7 +40,7 @@ const PlankControl = ({ icon, label, ...props }: Omit<ButtonProps, 'children'> &
40
40
  <Tooltip.Trigger asChild>
41
41
  <Button variant='ghost' {...props}>
42
42
  <span className='sr-only'>{label}</span>
43
- <Icon icon={icon} size={4} />
43
+ <Icon icon={icon} size={5} />
44
44
  </Button>
45
45
  </Tooltip.Trigger>
46
46
  <Tooltip.Portal>
@@ -52,17 +52,18 @@ const PlankControl = ({ icon, label, ...props }: Omit<ButtonProps, 'children'> &
52
52
 
53
53
  // TODO(wittjosiah): Duplicate of stack LayoutControls?
54
54
  // Translations were to be duplicated between packages.
55
+ // NOTE(thure): Pinning & unpinning are disabled indefinitely.
55
56
  export const PlankControls = forwardRef<HTMLDivElement, PlankControlsProps>(
56
57
  (
57
- { onClick, variant = 'default', capabilities: can, isSolo, pin, close = false, children, ...props },
58
+ { onClick, variant = 'default', capabilities: can, isSolo, pin, close = false, children, classNames, ...props },
58
59
  forwardedRef,
59
60
  ) => {
60
61
  const { t } = useTranslation(DECK_PLUGIN);
61
- const buttonClassNames = variant === 'hide-disabled' ? 'disabled:hidden !pli-2 !plb-3' : '!pli-2 !plb-3';
62
+ const buttonClassNames = variant === 'hide-disabled' ? 'disabled:hidden pli-2 plb-3' : 'pli-2 plb-3';
62
63
 
63
64
  return (
64
- <ButtonGroup {...props} ref={forwardedRef}>
65
- {pin && !isSolo && ['both', 'start'].includes(pin) && (
65
+ <ButtonGroup {...props} classNames={['app-no-drag', classNames]} ref={forwardedRef}>
66
+ {/* {pin && !isSolo && ['both', 'start'].includes(pin) && (
66
67
  <PlankControl
67
68
  label={t('pin start label')}
68
69
  variant='ghost'
@@ -70,14 +71,14 @@ export const PlankControls = forwardRef<HTMLDivElement, PlankControlsProps>(
70
71
  onClick={() => onClick?.('pin-start')}
71
72
  icon='ph--caret-line-left--regular'
72
73
  />
73
- )}
74
+ )} */}
74
75
 
75
76
  {can.solo && (
76
77
  <PlankControl
77
78
  label={isSolo ? t('show deck plank label') : t('show solo plank label')}
78
79
  classNames={buttonClassNames}
79
80
  onClick={() => onClick?.('solo')}
80
- icon={isSolo ? 'ph--arrow-u-down-left--regular' : 'ph--arrows-out--regular'}
81
+ icon={isSolo ? 'ph--corners-in--regular' : 'ph--corners-out--regular'}
81
82
  />
82
83
  )}
83
84
 
@@ -100,14 +101,14 @@ export const PlankControls = forwardRef<HTMLDivElement, PlankControlsProps>(
100
101
  </>
101
102
  )}
102
103
 
103
- {pin && !isSolo && ['both', 'end'].includes(pin) && (
104
+ {/* {pin && !isSolo && ['both', 'end'].includes(pin) && (
104
105
  <PlankControl
105
106
  label={t('pin end label')}
106
107
  classNames={buttonClassNames}
107
108
  onClick={() => onClick?.('pin-end')}
108
109
  icon='ph--caret-line-right--regular'
109
110
  />
110
- )}
111
+ )} */}
111
112
 
112
113
  {close && !isSolo && (
113
114
  <PlankControl
@@ -4,12 +4,11 @@
4
4
 
5
5
  import React, { useEffect, useState } from 'react';
6
6
 
7
- import { type LayoutCoordinate } from '@dxos/app-framework';
8
7
  import { type Node } from '@dxos/plugin-graph';
9
8
  import { useTranslation } from '@dxos/react-ui';
10
9
  import { descriptionText, mx } from '@dxos/react-ui-theme';
11
10
 
12
- import { NodePlankHeading } from './NodePlankHeading';
11
+ import { NodePlankHeading, type NodePlankHeadingProps } from './NodePlankHeading';
13
12
  import { PlankLoading } from './PlankLoading';
14
13
  import { DECK_PLUGIN } from '../../meta';
15
14
 
@@ -33,11 +32,13 @@ export const PlankContentError = ({ error }: { error?: Error }) => {
33
32
  };
34
33
 
35
34
  export const PlankError = ({
36
- layoutCoordinate,
35
+ id,
36
+ part,
37
37
  node,
38
38
  error,
39
39
  }: {
40
- layoutCoordinate: LayoutCoordinate;
40
+ id: string;
41
+ part: NodePlankHeadingProps['part'];
41
42
  node?: Node;
42
43
  error?: Error;
43
44
  }) => {
@@ -47,7 +48,7 @@ export const PlankError = ({
47
48
  }, []);
48
49
  return (
49
50
  <>
50
- <NodePlankHeading coordinate={layoutCoordinate} node={node} pending={!timedOut} />
51
+ <NodePlankHeading id={id} part={part} node={node} pending={!timedOut} />
51
52
  {timedOut ? <PlankContentError error={error} /> : <PlankLoading />}
52
53
  </>
53
54
  );
@@ -4,21 +4,31 @@
4
4
 
5
5
  import React, { useMemo } from 'react';
6
6
 
7
- import { type LayoutParts, Surface } from '@dxos/app-framework';
7
+ import { Surface, useCapability } from '@dxos/app-framework';
8
8
  import { Main } from '@dxos/react-ui';
9
9
 
10
- import { useLayout } from '../LayoutContext';
10
+ import { DeckCapabilities } from '../../capabilities';
11
+ import { layoutAppliesTopbar, useBreakpoints, useHoistStatusbar } from '../../util';
11
12
 
12
- export type SidebarProps = {
13
- layoutParts: LayoutParts;
14
- };
13
+ export const Sidebar = () => {
14
+ const { popoverAnchorId, activeDeck: current } = useCapability(DeckCapabilities.DeckState);
15
+ const breakpoint = useBreakpoints();
16
+ const topbar = layoutAppliesTopbar(breakpoint);
17
+ const hoistStatusbar = useHoistStatusbar(breakpoint);
15
18
 
16
- export const Sidebar = ({ layoutParts }: SidebarProps) => {
17
- const { popoverAnchorId } = useLayout();
18
- const navigationData = useMemo(() => ({ popoverAnchorId }), [popoverAnchorId]);
19
+ const navigationData = useMemo(
20
+ () => ({ popoverAnchorId, topbar, hoistStatusbar, current }),
21
+ [popoverAnchorId, topbar, hoistStatusbar, current],
22
+ );
19
23
 
20
24
  return (
21
- <Main.NavigationSidebar>
25
+ <Main.NavigationSidebar
26
+ classNames={[
27
+ 'grid',
28
+ topbar && 'block-start-[calc(env(safe-area-inset-top)+var(--rail-size))]',
29
+ hoistStatusbar && 'block-end-[--statusbar-size]',
30
+ ]}
31
+ >
22
32
  <Surface role='navigation' data={navigationData} limit={1} />
23
33
  </Main.NavigationSidebar>
24
34
  );
@@ -0,0 +1,68 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import React from 'react';
6
+
7
+ import { useCapability } from '@dxos/app-framework';
8
+ import { IconButton, type IconButtonProps, type ThemedClassName, useTranslation } from '@dxos/react-ui';
9
+
10
+ import { DeckCapabilities } from '../../capabilities';
11
+ import { DECK_PLUGIN } from '../../meta';
12
+
13
+ export const ToggleSidebarButton = ({
14
+ classNames,
15
+ variant = 'ghost',
16
+ }: ThemedClassName<Pick<IconButtonProps, 'variant'>>) => {
17
+ const layoutContext = useCapability(DeckCapabilities.MutableDeckState);
18
+ const { t } = useTranslation(DECK_PLUGIN);
19
+ return (
20
+ <IconButton
21
+ variant={variant}
22
+ iconOnly
23
+ icon='ph--sidebar--regular'
24
+ size={4}
25
+ label={t('open navigation sidebar label')}
26
+ onClick={() =>
27
+ (layoutContext.sidebarState = layoutContext.sidebarState === 'expanded' ? 'collapsed' : 'expanded')
28
+ }
29
+ classNames={classNames}
30
+ />
31
+ );
32
+ };
33
+
34
+ export const CloseSidebarButton = () => {
35
+ const layoutContext = useCapability(DeckCapabilities.MutableDeckState);
36
+ const { t } = useTranslation(DECK_PLUGIN);
37
+ return (
38
+ <IconButton
39
+ variant='ghost'
40
+ iconOnly
41
+ icon='ph--caret-line-left--regular'
42
+ size={4}
43
+ label={t('close navigation sidebar label')}
44
+ onClick={() => (layoutContext.sidebarState = 'collapsed')}
45
+ classNames='rounded-none pli-1 dx-focus-ring-inset pie-[max(.5rem,env(safe-area-inset-left))]'
46
+ />
47
+ );
48
+ };
49
+
50
+ export const ToggleComplementarySidebarButton = ({ inR0, classNames }: ThemedClassName<{ inR0?: boolean }>) => {
51
+ const layoutContext = useCapability(DeckCapabilities.MutableDeckState);
52
+ const { t } = useTranslation(DECK_PLUGIN);
53
+ return (
54
+ <IconButton
55
+ iconOnly
56
+ onClick={() =>
57
+ (layoutContext.complementarySidebarState =
58
+ layoutContext.complementarySidebarState === 'expanded' ? 'collapsed' : 'expanded')
59
+ }
60
+ variant='ghost'
61
+ label={t('open complementary sidebar label')}
62
+ classNames={['[&>svg]:-scale-x-100', classNames]}
63
+ icon='ph--sidebar-simple--regular'
64
+ size={inR0 ? 5 : 4}
65
+ tooltipSide={inR0 ? 'left' : undefined}
66
+ />
67
+ );
68
+ };
@@ -5,23 +5,17 @@
5
5
  import React from 'react';
6
6
 
7
7
  import { Surface } from '@dxos/app-framework';
8
- import { mainPadding, mainPaddingTransitions, mx } from '@dxos/react-ui-theme';
9
-
10
- import { useMainSize } from '../../hooks';
8
+ import { useLandmarkMover } from '@dxos/react-ui';
11
9
 
12
10
  export const StatusBar = ({ showHints }: { showHints?: boolean }) => {
13
- const sizeAttrs = useMainSize();
11
+ const mover = useLandmarkMover(undefined, '3');
14
12
  return (
15
13
  <div
16
- role='none'
17
- {...sizeAttrs}
18
- className={mx(
19
- 'fixed flex justify-between block-end-0 inset-inline-0 items-center border-bs border-separator z-[2]',
20
- mainPadding,
21
- mainPaddingTransitions,
22
- )}
14
+ role='contentinfo'
15
+ className='fixed block-end-0 inset-inline-0 bs-[--statusbar-size] border-bs border-separator z-[2] flex text-description'
16
+ {...mover}
23
17
  >
24
- <div role='none'>{showHints && <Surface role='hints' limit={1} />}</div>
18
+ {showHints && <Surface role='hints' limit={1} />}
25
19
  <Surface role='status-bar' limit={1} />
26
20
  </div>
27
21
  );
@@ -4,7 +4,7 @@
4
4
 
5
5
  import React from 'react';
6
6
 
7
- import type { Toast as ToastProps } from '@dxos/app-framework';
7
+ import { type LayoutAction } from '@dxos/app-framework';
8
8
  import {
9
9
  Button,
10
10
  Icon,
@@ -28,7 +28,7 @@ export const Toast = ({
28
28
  closeLabel,
29
29
  onAction,
30
30
  onOpenChange,
31
- }: ToastProps & Pick<ToastRootProps, 'onOpenChange'>) => {
31
+ }: LayoutAction.Toast & Pick<ToastRootProps, 'onOpenChange'>) => {
32
32
  const { t } = useTranslation(DECK_PLUGIN);
33
33
 
34
34
  return (
@@ -0,0 +1,11 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import React from 'react';
6
+
7
+ import { Banner } from './Banner';
8
+
9
+ export const Topbar = () => {
10
+ return <Banner variant='topbar' />;
11
+ };
@@ -5,7 +5,7 @@
5
5
  import React from 'react';
6
6
 
7
7
  import { Input, Select, useTranslation } from '@dxos/react-ui';
8
- import { DeprecatedFormInput } from '@dxos/react-ui-form';
8
+ import { DeprecatedFormContainer, DeprecatedFormInput } from '@dxos/react-ui-form';
9
9
 
10
10
  import { DECK_PLUGIN } from '../meta';
11
11
  import {
@@ -22,7 +22,7 @@ export const LayoutSettings = ({ settings }: { settings: DeckSettingsProps }) =>
22
22
  const { t } = useTranslation(DECK_PLUGIN);
23
23
 
24
24
  return (
25
- <>
25
+ <DeprecatedFormContainer>
26
26
  <DeprecatedFormInput label={t('select new plank positioning label')}>
27
27
  <Select.Root
28
28
  value={settings.newPlankPositioning ?? 'start'}
@@ -72,12 +72,12 @@ export const LayoutSettings = ({ settings }: { settings: DeckSettingsProps }) =>
72
72
  />
73
73
  </DeprecatedFormInput>
74
74
  )}
75
- <DeprecatedFormInput label={t('settings custom slots')}>
76
- <Input.Switch checked={settings.customSlots} onCheckedChange={(checked) => (settings.customSlots = checked)} />
75
+ <DeprecatedFormInput label={t('settings enable ide-style statusbar label')}>
76
+ <Input.Switch
77
+ checked={settings.enableIdeStyleStatusbar}
78
+ onCheckedChange={(checked) => (settings.enableIdeStyleStatusbar = checked)}
79
+ />
77
80
  </DeprecatedFormInput>
78
- <DeprecatedFormInput label={t('settings flat deck')}>
79
- <Input.Switch checked={settings.flatDeck} onCheckedChange={(checked) => (settings.flatDeck = checked)} />
80
- </DeprecatedFormInput>
81
- </>
81
+ </DeprecatedFormContainer>
82
82
  );
83
83
  };
@@ -0,0 +1,14 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import { mx } from '@dxos/react-ui-theme';
6
+
7
+ export const soloInlinePadding =
8
+ 'pis-[calc(env(safe-area-inset-left)+.25rem)] pie-[calc(env(safe-area-inset-left)+.25rem)]';
9
+
10
+ const sidebarToggleStyles = 'bs-[--rail-item] is-[--rail-item] absolute block-end-2 z-[1] !bg-deck lg:hidden';
11
+
12
+ export const fixedSidebarToggleStyles = mx(sidebarToggleStyles, 'inline-start-2');
13
+
14
+ export const fixedComplementarySidebarToggleStyles = mx(sidebarToggleStyles, 'inline-end-2');
@@ -3,6 +3,4 @@
3
3
  //
4
4
 
5
5
  export * from './DeckLayout';
6
- export * from './DeckContext';
7
- export * from './LayoutContext';
8
6
  export * from './LayoutSettings';
package/src/events.ts ADDED
@@ -0,0 +1,12 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import { Events } from '@dxos/app-framework';
6
+
7
+ import { DECK_PLUGIN } from './meta';
8
+
9
+ export namespace DeckEvents {
10
+ export const SetupComplementaryPanels = Events.createStateEvent(`${DECK_PLUGIN}/setup-complementary-panels`);
11
+ export const StateReady = Events.createStateEvent(`${DECK_PLUGIN}/state-ready`);
12
+ }
@@ -5,9 +5,9 @@
5
5
  import { useMainContext } from '@dxos/react-ui';
6
6
 
7
7
  export const useMainSize = () => {
8
- const { navigationSidebarOpen, complementarySidebarOpen } = useMainContext('DeckPluginPlank');
8
+ const { navigationSidebarState, complementarySidebarState } = useMainContext('DeckPluginPlank');
9
9
  return {
10
- 'data-sidebar-inline-start-state': navigationSidebarOpen ? 'open' : 'closed',
11
- 'data-sidebar-inline-end-state': complementarySidebarOpen ? 'open' : 'closed',
10
+ 'data-sidebar-inline-start-state': navigationSidebarState,
11
+ 'data-sidebar-inline-end-state': complementarySidebarState,
12
12
  };
13
13
  };
@@ -34,7 +34,9 @@ export const useNode = <T = any>(graph: Graph, id?: string, timeout?: number): N
34
34
  if (node) {
35
35
  setNodeState(node);
36
36
  }
37
- } catch {}
37
+ } catch {
38
+ // TODO(ZaymonFC): This leaves the resolved node in an invalid state in the case of a timeout.
39
+ }
38
40
  });
39
41
 
40
42
  return () => cancelAnimationFrame(frame);
package/src/index.ts CHANGED
@@ -2,8 +2,7 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
- import { DeckPlugin } from './DeckPlugin';
6
-
7
- export default DeckPlugin;
8
-
5
+ export { DeckCapabilities } from './capabilities';
6
+ export { DeckEvents } from './events';
9
7
  export * from './DeckPlugin';
8
+ export * from './meta';