@dxos/plugin-deck 0.8.1-staging.5be625a → 0.8.1-staging.9eaf14f

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 (161) hide show
  1. package/dist/lib/browser/{app-graph-builder-K4KVSHNT.mjs → app-graph-builder-VYZ4IWI3.mjs} +3 -3
  2. package/dist/lib/browser/{check-app-scheme-6SS6I3RN.mjs → check-app-scheme-SEYECDHI.mjs} +2 -2
  3. package/dist/lib/browser/{chunk-RZLH5F56.mjs → chunk-6ZSOFCPP.mjs} +26 -6
  4. package/dist/lib/browser/chunk-6ZSOFCPP.mjs.map +7 -0
  5. package/dist/lib/browser/chunk-B4LOJUWW.mjs +24 -0
  6. package/dist/lib/browser/{chunk-MWUT66KV.mjs → chunk-FJBMNSUC.mjs} +547 -493
  7. package/dist/lib/browser/chunk-FJBMNSUC.mjs.map +7 -0
  8. package/dist/lib/browser/chunk-FLOVGNYB.mjs +81 -0
  9. package/dist/lib/browser/chunk-FLOVGNYB.mjs.map +7 -0
  10. package/dist/lib/browser/{chunk-2WTHB3TG.mjs → chunk-NSATFAEE.mjs} +3 -3
  11. package/dist/lib/browser/{chunk-2WTHB3TG.mjs.map → chunk-NSATFAEE.mjs.map} +1 -1
  12. package/dist/lib/browser/{chunk-7X43JKZG.mjs → chunk-RJNCG4ND.mjs} +41 -45
  13. package/dist/lib/browser/chunk-RJNCG4ND.mjs.map +7 -0
  14. package/dist/lib/browser/{chunk-WCNPMAR4.mjs → chunk-XMCG42ID.mjs} +2 -3
  15. package/dist/lib/browser/chunk-XMCG42ID.mjs.map +7 -0
  16. package/dist/lib/browser/index.mjs +12 -8
  17. package/dist/lib/browser/index.mjs.map +3 -3
  18. package/dist/lib/browser/{intent-resolver-MEBOMCYI.mjs → intent-resolver-UDYKO2QW.mjs} +39 -78
  19. package/dist/lib/browser/intent-resolver-UDYKO2QW.mjs.map +7 -0
  20. package/dist/lib/browser/meta.json +1 -1
  21. package/dist/lib/browser/{react-root-USUAHDML.mjs → react-root-XLXN2VEW.mjs} +8 -10
  22. package/dist/lib/browser/react-root-XLXN2VEW.mjs.map +7 -0
  23. package/dist/lib/browser/{react-surface-TQG4YYES.mjs → react-surface-WNGMZL7I.mjs} +11 -10
  24. package/dist/lib/browser/react-surface-WNGMZL7I.mjs.map +7 -0
  25. package/dist/lib/browser/{settings-DYS3FFMN.mjs → settings-HMDGSBGO.mjs} +5 -4
  26. package/dist/lib/browser/settings-HMDGSBGO.mjs.map +7 -0
  27. package/dist/lib/browser/{state-DRRCGMU2.mjs → state-7TN26M42.mjs} +4 -4
  28. package/dist/lib/browser/{state-DRRCGMU2.mjs.map → state-7TN26M42.mjs.map} +2 -2
  29. package/dist/lib/browser/{tools-NDEUSO4R.mjs → tools-SC6QEN7R.mjs} +3 -3
  30. package/dist/lib/browser/types.mjs +12 -12
  31. package/dist/lib/browser/{url-handler-4BCN7AYC.mjs → url-handler-ODG4B6NX.mjs} +4 -4
  32. package/dist/types/src/DeckPlugin.d.ts.map +1 -1
  33. package/dist/types/src/capabilities/capabilities.d.ts +10 -12
  34. package/dist/types/src/capabilities/capabilities.d.ts.map +1 -1
  35. package/dist/types/src/capabilities/intent-resolver.d.ts.map +1 -1
  36. package/dist/types/src/capabilities/react-root.d.ts.map +1 -1
  37. package/dist/types/src/capabilities/react-surface.d.ts.map +1 -1
  38. package/dist/types/src/capabilities/settings.d.ts.map +1 -1
  39. package/dist/types/src/capabilities/state.d.ts +5 -5
  40. package/dist/types/src/components/DeckLayout/ActiveNode.d.ts.map +1 -1
  41. package/dist/types/src/components/DeckLayout/Banner.d.ts.map +1 -1
  42. package/dist/types/src/components/DeckLayout/DeckLayout.d.ts +1 -4
  43. package/dist/types/src/components/DeckLayout/DeckLayout.d.ts.map +1 -1
  44. package/dist/types/src/components/DeckLayout/Toast.d.ts.map +1 -1
  45. package/dist/types/src/components/DeckLayout/index.d.ts +1 -0
  46. package/dist/types/src/components/DeckLayout/index.d.ts.map +1 -1
  47. package/dist/types/src/components/DeckSettings/DeckSettings.d.ts +6 -0
  48. package/dist/types/src/components/DeckSettings/DeckSettings.d.ts.map +1 -0
  49. package/dist/types/src/components/DeckSettings/index.d.ts +2 -0
  50. package/dist/types/src/components/DeckSettings/index.d.ts.map +1 -0
  51. package/dist/types/src/components/Plank/Plank.d.ts +14 -0
  52. package/dist/types/src/components/Plank/Plank.d.ts.map +1 -0
  53. package/dist/types/src/components/Plank/Plank.stories.d.ts +8 -0
  54. package/dist/types/src/components/Plank/Plank.stories.d.ts.map +1 -0
  55. package/dist/types/src/components/{DeckLayout → Plank}/PlankControls.d.ts +2 -0
  56. package/dist/types/src/components/Plank/PlankControls.d.ts.map +1 -0
  57. package/dist/types/src/components/{DeckLayout → Plank}/PlankError.d.ts +2 -2
  58. package/dist/types/src/components/Plank/PlankError.d.ts.map +1 -0
  59. package/dist/types/src/components/{DeckLayout/NodePlankHeading.d.ts → Plank/PlankHeading.d.ts} +7 -6
  60. package/dist/types/src/components/Plank/PlankHeading.d.ts.map +1 -0
  61. package/dist/types/src/components/Plank/PlankLoading.d.ts.map +1 -0
  62. package/dist/types/src/components/Plank/index.d.ts +6 -0
  63. package/dist/types/src/components/Plank/index.d.ts.map +1 -0
  64. package/dist/types/src/components/Sidebar/ComplementarySidebar.d.ts.map +1 -0
  65. package/dist/types/src/components/Sidebar/Sidebar.d.ts.map +1 -0
  66. package/dist/types/src/components/Sidebar/SidebarButton.d.ts.map +1 -0
  67. package/dist/types/src/components/Sidebar/index.d.ts +4 -0
  68. package/dist/types/src/components/Sidebar/index.d.ts.map +1 -0
  69. package/dist/types/src/components/index.d.ts +1 -1
  70. package/dist/types/src/components/index.d.ts.map +1 -1
  71. package/dist/types/src/events.d.ts +0 -1
  72. package/dist/types/src/events.d.ts.map +1 -1
  73. package/dist/types/src/hooks/index.d.ts +0 -1
  74. package/dist/types/src/hooks/index.d.ts.map +1 -1
  75. package/dist/types/src/index.d.ts +1 -0
  76. package/dist/types/src/index.d.ts.map +1 -1
  77. package/dist/types/src/layout.d.ts +7 -1
  78. package/dist/types/src/layout.d.ts.map +1 -1
  79. package/dist/types/src/translations.d.ts +3 -0
  80. package/dist/types/src/translations.d.ts.map +1 -1
  81. package/dist/types/src/types.d.ts +31 -60
  82. package/dist/types/src/types.d.ts.map +1 -1
  83. package/dist/types/src/util/index.d.ts +1 -0
  84. package/dist/types/src/util/index.d.ts.map +1 -1
  85. package/dist/types/src/util/set-active.d.ts +2 -2
  86. package/dist/types/src/util/set-active.d.ts.map +1 -1
  87. package/dist/types/src/util/useCompanions.d.ts +8 -0
  88. package/dist/types/src/util/useCompanions.d.ts.map +1 -0
  89. package/dist/types/src/util/useHoistStatusbar.d.ts.map +1 -1
  90. package/package.json +28 -29
  91. package/src/DeckPlugin.ts +0 -1
  92. package/src/capabilities/capabilities.ts +3 -4
  93. package/src/capabilities/intent-resolver.ts +35 -7
  94. package/src/capabilities/react-root.tsx +1 -9
  95. package/src/capabilities/react-surface.tsx +3 -4
  96. package/src/capabilities/settings.ts +7 -2
  97. package/src/capabilities/state.ts +3 -3
  98. package/src/components/DeckLayout/ActiveNode.tsx +2 -1
  99. package/src/components/DeckLayout/Banner.tsx +5 -3
  100. package/src/components/DeckLayout/ContentEmpty.tsx +1 -1
  101. package/src/components/DeckLayout/DeckLayout.tsx +27 -16
  102. package/src/components/DeckLayout/Fullscreen.tsx +1 -1
  103. package/src/components/DeckLayout/Toast.tsx +1 -1
  104. package/src/components/DeckLayout/index.ts +2 -0
  105. package/src/components/{LayoutSettings.tsx → DeckSettings/DeckSettings.tsx} +15 -10
  106. package/src/components/DeckSettings/index.ts +5 -0
  107. package/src/components/Plank/Plank.stories.tsx +43 -0
  108. package/src/components/{DeckLayout → Plank}/Plank.tsx +46 -37
  109. package/src/components/{DeckLayout → Plank}/PlankControls.tsx +40 -25
  110. package/src/components/{DeckLayout → Plank}/PlankError.tsx +3 -3
  111. package/src/components/{DeckLayout/NodePlankHeading.tsx → Plank/PlankHeading.tsx} +98 -59
  112. package/src/components/Plank/index.ts +9 -0
  113. package/src/components/{DeckLayout → Sidebar}/ComplementarySidebar.tsx +65 -81
  114. package/src/components/Sidebar/index.ts +7 -0
  115. package/src/components/index.ts +1 -1
  116. package/src/events.ts +0 -1
  117. package/src/hooks/index.ts +0 -1
  118. package/src/index.ts +1 -0
  119. package/src/layout.ts +19 -2
  120. package/src/meta.ts +2 -2
  121. package/src/translations.ts +3 -0
  122. package/src/types.ts +59 -86
  123. package/src/util/index.ts +1 -0
  124. package/src/util/set-active.ts +2 -2
  125. package/src/util/useCompanions.ts +18 -0
  126. package/src/util/useHoistStatusbar.ts +2 -2
  127. package/dist/lib/browser/chunk-7X43JKZG.mjs.map +0 -7
  128. package/dist/lib/browser/chunk-MWUT66KV.mjs.map +0 -7
  129. package/dist/lib/browser/chunk-NSNAYFAX.mjs +0 -24
  130. package/dist/lib/browser/chunk-RZLH5F56.mjs.map +0 -7
  131. package/dist/lib/browser/chunk-WCNPMAR4.mjs.map +0 -7
  132. package/dist/lib/browser/intent-resolver-MEBOMCYI.mjs.map +0 -7
  133. package/dist/lib/browser/react-root-USUAHDML.mjs.map +0 -7
  134. package/dist/lib/browser/react-surface-TQG4YYES.mjs.map +0 -7
  135. package/dist/lib/browser/settings-DYS3FFMN.mjs.map +0 -7
  136. package/dist/types/src/components/DeckLayout/ComplementarySidebar.d.ts.map +0 -1
  137. package/dist/types/src/components/DeckLayout/NodePlankHeading.d.ts.map +0 -1
  138. package/dist/types/src/components/DeckLayout/Plank.d.ts +0 -13
  139. package/dist/types/src/components/DeckLayout/Plank.d.ts.map +0 -1
  140. package/dist/types/src/components/DeckLayout/PlankControls.d.ts.map +0 -1
  141. package/dist/types/src/components/DeckLayout/PlankError.d.ts.map +0 -1
  142. package/dist/types/src/components/DeckLayout/PlankLoading.d.ts.map +0 -1
  143. package/dist/types/src/components/DeckLayout/Sidebar.d.ts.map +0 -1
  144. package/dist/types/src/components/DeckLayout/SidebarButton.d.ts.map +0 -1
  145. package/dist/types/src/components/LayoutSettings.d.ts +0 -6
  146. package/dist/types/src/components/LayoutSettings.d.ts.map +0 -1
  147. package/dist/types/src/hooks/useNode.d.ts +0 -11
  148. package/dist/types/src/hooks/useNode.d.ts.map +0 -1
  149. package/src/hooks/useNode.ts +0 -46
  150. /package/dist/lib/browser/{app-graph-builder-K4KVSHNT.mjs.map → app-graph-builder-VYZ4IWI3.mjs.map} +0 -0
  151. /package/dist/lib/browser/{check-app-scheme-6SS6I3RN.mjs.map → check-app-scheme-SEYECDHI.mjs.map} +0 -0
  152. /package/dist/lib/browser/{chunk-NSNAYFAX.mjs.map → chunk-B4LOJUWW.mjs.map} +0 -0
  153. /package/dist/lib/browser/{tools-NDEUSO4R.mjs.map → tools-SC6QEN7R.mjs.map} +0 -0
  154. /package/dist/lib/browser/{url-handler-4BCN7AYC.mjs.map → url-handler-ODG4B6NX.mjs.map} +0 -0
  155. /package/dist/types/src/components/{DeckLayout → Plank}/PlankLoading.d.ts +0 -0
  156. /package/dist/types/src/components/{DeckLayout → Sidebar}/ComplementarySidebar.d.ts +0 -0
  157. /package/dist/types/src/components/{DeckLayout → Sidebar}/Sidebar.d.ts +0 -0
  158. /package/dist/types/src/components/{DeckLayout → Sidebar}/SidebarButton.d.ts +0 -0
  159. /package/src/components/{DeckLayout → Plank}/PlankLoading.tsx +0 -0
  160. /package/src/components/{DeckLayout → Sidebar}/Sidebar.tsx +0 -0
  161. /package/src/components/{DeckLayout → Sidebar}/SidebarButton.tsx +0 -0
@@ -6,9 +6,10 @@ import { untracked } from '@preact/signals-core';
6
6
  import React, { useCallback, useEffect, useMemo, useRef, type UIEvent, Fragment, useState } from 'react';
7
7
 
8
8
  import {
9
+ Capabilities,
9
10
  LayoutAction,
10
- createIntent,
11
11
  Surface,
12
+ createIntent,
12
13
  useCapability,
13
14
  useIntentDispatcher,
14
15
  usePluginManager,
@@ -27,32 +28,29 @@ import { Stack, StackContext, DEFAULT_HORIZONTAL_SIZE } from '@dxos/react-ui-sta
27
28
  import { mainPaddingTransitions } from '@dxos/react-ui-theme';
28
29
 
29
30
  import { ActiveNode } from './ActiveNode';
30
- import { ComplementarySidebar } from './ComplementarySidebar';
31
31
  import { ContentEmpty } from './ContentEmpty';
32
32
  import { Fullscreen } from './Fullscreen';
33
- import { Plank } from './Plank';
34
- import { PlankContentError } from './PlankError';
35
- import { Sidebar } from './Sidebar';
36
- import { ToggleComplementarySidebarButton, ToggleSidebarButton } from './SidebarButton';
37
33
  import { StatusBar } from './StatusBar';
38
34
  import { Toast } from './Toast';
39
35
  import { Topbar } from './Topbar';
40
36
  import { DeckCapabilities } from '../../capabilities';
41
- import { getMode, type Overscroll } from '../../types';
37
+ import { DECK_PLUGIN } from '../../meta';
38
+ import { type DeckSettingsProps, getMode } from '../../types';
42
39
  import { calculateOverscroll, layoutAppliesTopbar, useBreakpoints, useHoistStatusbar } from '../../util';
40
+ import { Plank, PlankContentError } from '../Plank';
41
+ import { ComplementarySidebar, Sidebar, ToggleComplementarySidebarButton, ToggleSidebarButton } from '../Sidebar';
43
42
  import { fixedComplementarySidebarToggleStyles, fixedSidebarToggleStyles } from '../fragments';
44
43
 
45
44
  export type DeckLayoutProps = {
46
- overscroll: Overscroll;
47
- showHints: boolean;
48
45
  onDismissToast: (id: string) => void;
49
46
  };
50
47
 
51
48
  const PlankSeparator = ({ order }: { order: number }) =>
52
49
  order > 0 ? <span role='separator' className='row-span-2 bg-deck is-4' style={{ gridColumn: order }} /> : null;
53
50
 
54
- export const DeckLayout = ({ overscroll, showHints, onDismissToast }: DeckLayoutProps) => {
51
+ export const DeckLayout = ({ onDismissToast }: DeckLayoutProps) => {
55
52
  const { dispatchPromise: dispatch } = useIntentDispatcher();
53
+ const settings = useCapability(Capabilities.SettingsStore).getStore<DeckSettingsProps>(DECK_PLUGIN)!.value;
56
54
  const context = useCapability(DeckCapabilities.MutableDeckState);
57
55
  const {
58
56
  sidebarState,
@@ -120,6 +118,15 @@ export const DeckLayout = ({ overscroll, showHints, onDismissToast }: DeckLayout
120
118
  }
121
119
  }, [isNotMobile, deck, dispatch]);
122
120
 
121
+ // If deck is disabled in settings, ensure that the layout is in solo mode.
122
+ useEffect(() => {
123
+ if (!settings.enableDeck) {
124
+ void dispatch(
125
+ createIntent(LayoutAction.SetLayoutMode, { part: 'mode', subject: active[0], options: { mode: 'solo' } }),
126
+ );
127
+ }
128
+ }, [settings.enableDeck, dispatch, active]);
129
+
123
130
  /**
124
131
  * Clear scroll restoration state if the window is resized
125
132
  */
@@ -156,11 +163,11 @@ export const DeckLayout = ({ overscroll, showHints, onDismissToast }: DeckLayout
156
163
  const isEmpty = !solo && active.length === 0;
157
164
 
158
165
  const padding = useMemo(() => {
159
- if (!solo && overscroll === 'centering') {
166
+ if (!solo && settings.overscroll === 'centering') {
160
167
  return calculateOverscroll(active.length);
161
168
  }
162
169
  return {};
163
- }, [solo, overscroll, deck]);
170
+ }, [solo, settings.overscroll, deck]);
164
171
 
165
172
  const mainPosition = useMemo(
166
173
  () => [
@@ -260,13 +267,13 @@ export const DeckLayout = ({ overscroll, showHints, onDismissToast }: DeckLayout
260
267
  {!topbar && <ToggleSidebarButton classNames={fixedSidebarToggleStyles} />}
261
268
  {!topbar && <ToggleComplementarySidebarButton classNames={fixedComplementarySidebarToggleStyles} />}
262
269
  <Stack
270
+ ref={deckRef}
263
271
  orientation='horizontal'
264
272
  size='contain'
265
273
  classNames={['absolute inset-block-0 -inset-inline-px', mainPaddingTransitions]}
266
- onScroll={handleScroll}
267
274
  itemsCount={itemsCount - 1}
268
275
  style={padding}
269
- ref={deckRef}
276
+ onScroll={handleScroll}
270
277
  >
271
278
  {active.map((entryId) => (
272
279
  <Fragment key={entryId}>
@@ -278,6 +285,7 @@ export const DeckLayout = ({ overscroll, showHints, onDismissToast }: DeckLayout
278
285
  order={order[entryId]}
279
286
  active={active}
280
287
  layoutMode={layoutMode}
288
+ settings={settings}
281
289
  />
282
290
  </Fragment>
283
291
  ))}
@@ -296,15 +304,18 @@ export const DeckLayout = ({ overscroll, showHints, onDismissToast }: DeckLayout
296
304
  companionId={solo ? activeCompanions?.[solo] : undefined}
297
305
  part='solo'
298
306
  layoutMode={layoutMode}
307
+ settings={settings}
299
308
  />
300
309
  </StackContext.Provider>
301
310
  </div>
302
311
  </Main.Content>
303
312
  )}
304
313
 
305
- {/* Status bar. */}
314
+ {/* Topbar. */}
306
315
  {topbar && <Topbar />}
307
- {hoistStatusbar && <StatusBar showHints={showHints} />}
316
+
317
+ {/* Status bar. */}
318
+ {hoistStatusbar && <StatusBar showHints={settings.showHints} />}
308
319
  </Main.Root>
309
320
  )}
310
321
 
@@ -5,11 +5,11 @@
5
5
  import React from 'react';
6
6
 
7
7
  import { Surface, useAppGraph } from '@dxos/app-framework';
8
+ import { useNode } from '@dxos/plugin-graph';
8
9
  import { fixedInsetFlexLayout } from '@dxos/react-ui-theme';
9
10
 
10
11
  import { Fallback } from './Fallback';
11
12
  import { SURFACE_PREFIX } from './constants';
12
- import { useNode } from '../../hooks';
13
13
 
14
14
  export const Fullscreen = ({ id }: { id?: string }) => {
15
15
  const { graph } = useAppGraph();
@@ -9,9 +9,9 @@ import {
9
9
  Button,
10
10
  Icon,
11
11
  Toast as NaturalToast,
12
+ type ToastRootProps,
12
13
  toLocalizedString,
13
14
  useTranslation,
14
- type ToastRootProps,
15
15
  } from '@dxos/react-ui';
16
16
 
17
17
  import { DECK_PLUGIN } from '../../meta';
@@ -3,4 +3,6 @@
3
3
  //
4
4
 
5
5
  export { NAV_ID } from './constants';
6
+
7
+ export * from './Banner';
6
8
  export * from './DeckLayout';
@@ -7,24 +7,28 @@ import React from 'react';
7
7
  import { Input, Select, useTranslation } from '@dxos/react-ui';
8
8
  import { DeprecatedFormContainer, DeprecatedFormInput } from '@dxos/react-ui-form';
9
9
 
10
- import { DECK_PLUGIN } from '../meta';
10
+ import { DECK_PLUGIN } from '../../meta';
11
11
  import {
12
+ type DeckSettingsProps,
12
13
  type NewPlankPositioning,
13
14
  NewPlankPositions,
14
- type DeckSettingsProps,
15
15
  type Overscroll,
16
16
  OverscrollOptions,
17
- } from '../types';
17
+ } from '../../types';
18
18
 
19
19
  const isSocket = !!(globalThis as any).__args;
20
20
 
21
- export const LayoutSettings = ({ settings }: { settings: DeckSettingsProps }) => {
21
+ export const DeckSettings = ({ settings }: { settings: DeckSettingsProps }) => {
22
22
  const { t } = useTranslation(DECK_PLUGIN);
23
23
 
24
24
  return (
25
25
  <DeprecatedFormContainer>
26
+ <DeprecatedFormInput label={t('settings enable deck label')}>
27
+ <Input.Switch checked={settings.enableDeck} onCheckedChange={(checked) => (settings.enableDeck = checked)} />
28
+ </DeprecatedFormInput>
26
29
  <DeprecatedFormInput label={t('select new plank positioning label')}>
27
30
  <Select.Root
31
+ disabled={!settings.enableDeck}
28
32
  value={settings.newPlankPositioning ?? 'start'}
29
33
  onValueChange={(value) => (settings.newPlankPositioning = value as NewPlankPositioning)}
30
34
  >
@@ -44,6 +48,7 @@ export const LayoutSettings = ({ settings }: { settings: DeckSettingsProps }) =>
44
48
  </DeprecatedFormInput>
45
49
  <DeprecatedFormInput label={t('settings overscroll label')}>
46
50
  <Select.Root
51
+ disabled={!settings.enableDeck}
47
52
  value={settings.overscroll ?? 'none'}
48
53
  onValueChange={(value) => (settings.overscroll = value as Overscroll)}
49
54
  >
@@ -61,6 +66,12 @@ export const LayoutSettings = ({ settings }: { settings: DeckSettingsProps }) =>
61
66
  </Select.Portal>
62
67
  </Select.Root>
63
68
  </DeprecatedFormInput>
69
+ <DeprecatedFormInput label={t('settings enable statusbar label')}>
70
+ <Input.Switch
71
+ checked={settings.enableStatusbar}
72
+ onCheckedChange={(checked) => (settings.enableStatusbar = checked)}
73
+ />
74
+ </DeprecatedFormInput>
64
75
  <DeprecatedFormInput label={t('settings show hints label')}>
65
76
  <Input.Switch checked={settings.showHints} onCheckedChange={(checked) => (settings.showHints = checked)} />
66
77
  </DeprecatedFormInput>
@@ -72,12 +83,6 @@ export const LayoutSettings = ({ settings }: { settings: DeckSettingsProps }) =>
72
83
  />
73
84
  </DeprecatedFormInput>
74
85
  )}
75
- <DeprecatedFormInput label={t('settings enable statusbar label')}>
76
- <Input.Switch
77
- checked={settings.enableStatusbar}
78
- onCheckedChange={(checked) => (settings.enableStatusbar = checked)}
79
- />
80
- </DeprecatedFormInput>
81
86
  </DeprecatedFormContainer>
82
87
  );
83
88
  };
@@ -0,0 +1,5 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ export * from './DeckSettings';
@@ -0,0 +1,43 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import '@dxos-theme';
6
+
7
+ import { type StoryObj, type Meta } from '@storybook/react';
8
+
9
+ import { IntentPlugin } from '@dxos/app-framework';
10
+ import { withPluginManager } from '@dxos/app-framework/testing';
11
+ import { GraphPlugin } from '@dxos/plugin-graph';
12
+ import { withTheme, withLayout } from '@dxos/storybook-utils';
13
+
14
+ import { Plank } from './Plank';
15
+ import translations from '../../translations';
16
+
17
+ // TODO(burdon): invariant violation: No capability found for dxos.org/plugin/deck/capability/state
18
+ const meta: Meta<typeof Plank> = {
19
+ title: 'plugins/plugin-deck/Plank',
20
+ component: Plank,
21
+ decorators: [
22
+ withPluginManager({
23
+ plugins: [IntentPlugin(), GraphPlugin()],
24
+ }),
25
+ withTheme,
26
+ withLayout({ fullscreen: true, tooltips: true }),
27
+ ],
28
+ parameters: {
29
+ layout: 'centered',
30
+ translations,
31
+ },
32
+ };
33
+
34
+ export default meta;
35
+
36
+ type Story = StoryObj<typeof meta>;
37
+
38
+ export const Default: Story = {
39
+ args: {
40
+ id: 'plank-1',
41
+ part: 'solo',
42
+ },
43
+ };
@@ -5,8 +5,8 @@
5
5
  import React, {
6
6
  Fragment,
7
7
  type KeyboardEvent,
8
- memo,
9
8
  type PropsWithChildren,
9
+ memo,
10
10
  useCallback,
11
11
  useLayoutEffect,
12
12
  useMemo,
@@ -14,24 +14,27 @@ import React, {
14
14
  } from 'react';
15
15
 
16
16
  import {
17
- createIntent,
18
17
  LayoutAction,
19
18
  Surface,
19
+ createIntent,
20
20
  useCapability,
21
21
  useAppGraph,
22
22
  useIntentDispatcher,
23
23
  } from '@dxos/app-framework';
24
24
  import { debounce } from '@dxos/async';
25
- import { useAttendableAttributes } from '@dxos/react-ui-attention';
25
+ import { useNode, type Node } from '@dxos/plugin-graph';
26
+ import { ATTENDABLE_PATH_SEPARATOR, useAttendableAttributes } from '@dxos/react-ui-attention';
26
27
  import { StackItem, railGridHorizontal } from '@dxos/react-ui-stack';
27
28
  import { mainIntrinsicSize, mx } from '@dxos/react-ui-theme';
28
29
 
29
- import { NodePlankHeading } from './NodePlankHeading';
30
30
  import { PlankContentError, PlankError } from './PlankError';
31
+ import { PlankHeading } from './PlankHeading';
31
32
  import { PlankLoading } from './PlankLoading';
32
33
  import { DeckCapabilities } from '../../capabilities';
33
- import { useNode, useMainSize } from '../../hooks';
34
- import { DeckAction, type LayoutMode, type Part, type ResolvedPart, surfaceVariantSeparator } from '../../types';
34
+ import { useMainSize } from '../../hooks';
35
+ import { parseEntryId } from '../../layout';
36
+ import { DeckAction, type LayoutMode, type Part, type ResolvedPart, type DeckSettingsProps } from '../../types';
37
+ import { useCompanions } from '../../util';
35
38
 
36
39
  const UNKNOWN_ID = 'unknown_id';
37
40
 
@@ -43,42 +46,34 @@ export type PlankProps = {
43
46
  order?: number;
44
47
  active?: string[];
45
48
  layoutMode: LayoutMode;
49
+ settings?: DeckSettingsProps;
46
50
  };
47
51
 
48
- type PlankImplProps = Omit<PlankProps, 'companionId' | 'part'> & {
52
+ type PlankImplProps = Omit<PlankProps, 'id' | 'companionId' | 'part'> & {
53
+ id: string;
49
54
  part: ResolvedPart;
50
- surfaceVariant?: string;
55
+ node?: Node;
51
56
  companioned?: 'primary' | 'companion';
52
- primaryId?: string;
57
+ primary?: Node;
58
+ companions?: Node[];
53
59
  };
54
60
 
55
61
  const PlankImpl = memo(
56
- ({
57
- id = UNKNOWN_ID,
58
- part,
59
- path,
60
- order,
61
- active,
62
- layoutMode,
63
- surfaceVariant,
64
- companioned,
65
- primaryId,
66
- }: PlankImplProps) => {
62
+ ({ id, node, part, path, order, active, layoutMode, companioned, primary, companions, settings }: PlankImplProps) => {
67
63
  const { dispatchPromise: dispatch } = useIntentDispatcher();
68
64
  const { deck, popoverAnchorId, scrollIntoView } = useCapability(DeckCapabilities.DeckState);
69
- const { graph } = useAppGraph();
70
- const node = useNode(graph, id);
71
65
  const rootElement = useRef<HTMLDivElement | null>(null);
72
66
  const canResize = layoutMode === 'deck';
73
67
  const Root = part.startsWith('solo') ? 'article' : StackItem.Root;
74
68
 
75
- const attendableAttrs = useAttendableAttributes(id);
69
+ const attendableAttrs = useAttendableAttributes(primary?.id ?? id);
76
70
  const index = active ? active.findIndex((entryId) => entryId === id) : 0;
77
71
  const length = active?.length ?? 1;
78
72
  const canIncrementStart = active && index !== undefined && index > 0 && length !== undefined && length > 1;
79
73
  const canIncrementEnd = active && index !== undefined && index < length - 1 && length !== undefined;
80
74
 
81
- const sizeKey = `${id.split('+')[0]}${surfaceVariant ? `${surfaceVariantSeparator}${surfaceVariant}` : ''}`;
75
+ const { variant } = parseEntryId(id);
76
+ const sizeKey = `${id.split('+')[0]}${variant ? `${ATTENDABLE_PATH_SEPARATOR}${variant}` : ''}`;
82
77
  const size = deck.plankSizing[sizeKey] as number | undefined;
83
78
  const setSize = useCallback(
84
79
  debounce((nextSize: number) => {
@@ -116,11 +111,12 @@ const PlankImpl = memo(
116
111
  () =>
117
112
  node && {
118
113
  subject: node.data,
119
- variant: surfaceVariant,
114
+ companionTo: primary?.data,
115
+ variant,
120
116
  path,
121
117
  popoverAnchorId,
122
118
  },
123
- [node, node?.data, path, popoverAnchorId, surfaceVariant],
119
+ [node, node?.data, path, popoverAnchorId, primary?.data],
124
120
  );
125
121
 
126
122
  // TODO(wittjosiah): Change prop to accept a component.
@@ -133,7 +129,7 @@ const PlankImpl = memo(
133
129
  isSolo && 'absolute inset-0',
134
130
  part.startsWith('solo') && 'grid',
135
131
  part === 'deck' && (companioned === 'companion' ? '!border-separator border-ie' : '!border-separator border-li'),
136
- part.startsWith('solo-') && 'row-span-2 min-is-0',
132
+ part.startsWith('solo-') && 'row-span-2 grid-rows-subgrid min-is-0',
137
133
  part === 'solo-companion' && '!border-separator border-is',
138
134
  );
139
135
 
@@ -157,16 +153,17 @@ const PlankImpl = memo(
157
153
  >
158
154
  {node ? (
159
155
  <>
160
- <NodePlankHeading
156
+ <PlankHeading
161
157
  id={id}
162
158
  part={part.startsWith('solo-') ? 'solo' : part}
163
159
  node={node}
160
+ deckEnabled={settings?.enableDeck}
164
161
  canIncrementStart={canIncrementStart}
165
162
  canIncrementEnd={canIncrementEnd}
166
163
  popoverAnchorId={popoverAnchorId}
164
+ primaryId={primary?.id}
167
165
  companioned={companioned}
168
- primaryId={primaryId}
169
- surfaceVariant={surfaceVariant}
166
+ companions={companions}
170
167
  />
171
168
  <Surface
172
169
  key={node.id}
@@ -199,23 +196,35 @@ const SplitFrame = ({ children }: PropsWithChildren<{}>) => {
199
196
  );
200
197
  };
201
198
 
202
- export const Plank = (props: PlankProps) => {
199
+ export const Plank = ({ id = UNKNOWN_ID, ...props }: PlankProps) => {
200
+ const { graph } = useAppGraph();
201
+ const node = useNode(graph, id);
202
+ const companions = useCompanions(id);
203
+ const currentCompanion = companions.find(({ id }) => id === props.companionId);
204
+
203
205
  if (props.companionId) {
204
206
  const Root = props.part === 'solo' ? SplitFrame : Fragment;
205
207
  return (
206
208
  <Root>
207
- <PlankImpl {...props} {...(props.part === 'solo' ? { part: 'solo-primary' } : {})} companioned='primary' />
208
209
  <PlankImpl
210
+ id={id}
211
+ node={node}
212
+ companioned='primary'
209
213
  {...props}
210
- {...(props.companionId.startsWith(surfaceVariantSeparator)
211
- ? { surfaceVariant: props.companionId.substring(2) }
212
- : { id: props.companionId, primaryId: props.id })}
213
- {...(props.part === 'solo' ? { part: 'solo-companion' } : { order: props.order! + 1 })}
214
+ {...(props.part === 'solo' ? { part: 'solo-primary' } : {})}
215
+ />
216
+ <PlankImpl
217
+ id={props.companionId}
218
+ node={currentCompanion}
214
219
  companioned='companion'
220
+ primary={node}
221
+ companions={companions}
222
+ {...props}
223
+ {...(props.part === 'solo' ? { part: 'solo-companion' } : { order: props.order! + 1 })}
215
224
  />
216
225
  </Root>
217
226
  );
218
227
  } else {
219
- return <PlankImpl {...props} />;
228
+ return <PlankImpl id={id} node={node} companions={companions} {...props} />;
220
229
  }
221
230
  };
@@ -24,7 +24,9 @@ export type PlankControlHandler = (event: DeckAction.PartAdjustment) => void;
24
24
  export type PlankCapabilities = {
25
25
  incrementStart?: boolean;
26
26
  incrementEnd?: boolean;
27
+ deck?: boolean;
27
28
  solo?: boolean;
29
+ companion?: boolean;
28
30
  };
29
31
 
30
32
  export type PlankControlsProps = Omit<ButtonGroupProps, 'onClick'> & {
@@ -71,7 +73,8 @@ export const PlankCompanionControls = forwardRef<HTMLDivElement, PlankCompliment
71
73
  <PlankControl
72
74
  label={t('close companion label')}
73
75
  variant='ghost'
74
- icon='ph--minus--regular'
76
+ // icon='ph--minus--regular'
77
+ icon='ph--caret-left--regular'
75
78
  onClick={handleCloseCompanion}
76
79
  classNames={plankControlSpacing}
77
80
  />
@@ -85,7 +88,7 @@ export const PlankCompanionControls = forwardRef<HTMLDivElement, PlankCompliment
85
88
  // NOTE(thure): Pinning & unpinning are disabled indefinitely.
86
89
  export const PlankControls = forwardRef<HTMLDivElement, PlankControlsProps>(
87
90
  (
88
- { onClick, variant = 'default', capabilities: can, isSolo, pin, close = false, children, classNames, ...props },
91
+ { children, classNames, variant = 'default', capabilities, isSolo, pin, close = false, onClick, ...props },
89
92
  forwardedRef,
90
93
  ) => {
91
94
  const { t } = useTranslation(DECK_PLUGIN);
@@ -104,31 +107,33 @@ export const PlankControls = forwardRef<HTMLDivElement, PlankControlsProps>(
104
107
  />
105
108
  )} */}
106
109
 
107
- {can.solo && (
108
- <PlankControl
109
- label={isSolo ? t('show deck plank label') : t('show solo plank label')}
110
- classNames={buttonClassNames}
111
- onClick={() => onClick?.('solo')}
112
- icon={isSolo ? 'ph--corners-in--regular' : 'ph--corners-out--regular'}
113
- />
114
- )}
115
-
116
- {!isSolo && can.solo && (
110
+ {capabilities.deck && capabilities.solo && (
117
111
  <>
118
112
  <PlankControl
119
- label={t('increment start label')}
120
- disabled={!can.incrementStart}
113
+ label={isSolo ? t('show deck plank label') : t('show solo plank label')}
121
114
  classNames={buttonClassNames}
122
- onClick={() => onClick?.('increment-start')}
123
- icon='ph--caret-left--regular'
124
- />
125
- <PlankControl
126
- label={t('increment end label')}
127
- disabled={!can.incrementEnd}
128
- classNames={buttonClassNames}
129
- onClick={() => onClick?.('increment-end')}
130
- icon='ph--caret-right--regular'
115
+ icon={isSolo ? 'ph--corners-in--regular' : 'ph--corners-out--regular'}
116
+ onClick={() => onClick?.('solo')}
131
117
  />
118
+
119
+ {!isSolo && (
120
+ <>
121
+ <PlankControl
122
+ label={t('increment start label')}
123
+ disabled={!capabilities.incrementStart}
124
+ classNames={buttonClassNames}
125
+ icon='ph--caret-left--regular'
126
+ onClick={() => onClick?.('increment-start')}
127
+ />
128
+ <PlankControl
129
+ label={t('increment end label')}
130
+ disabled={!capabilities.incrementEnd}
131
+ classNames={buttonClassNames}
132
+ icon='ph--caret-right--regular'
133
+ onClick={() => onClick?.('increment-end')}
134
+ />
135
+ </>
136
+ )}
132
137
  </>
133
138
  )}
134
139
 
@@ -136,8 +141,8 @@ export const PlankControls = forwardRef<HTMLDivElement, PlankControlsProps>(
136
141
  <PlankControl
137
142
  label={t('pin end label')}
138
143
  classNames={buttonClassNames}
139
- onClick={() => onClick?.('pin-end')}
140
144
  icon='ph--caret-line-right--regular'
145
+ onClick={() => onClick?.('pin-end')}
141
146
  />
142
147
  )} */}
143
148
 
@@ -145,7 +150,6 @@ export const PlankControls = forwardRef<HTMLDivElement, PlankControlsProps>(
145
150
  <PlankControl
146
151
  label={t(`${typeof close === 'string' ? 'minify' : 'close'} label`)}
147
152
  classNames={buttonClassNames}
148
- onClick={() => onClick?.('close')}
149
153
  data-testid='plankHeading.close'
150
154
  icon={
151
155
  close === 'minify-start'
@@ -154,6 +158,17 @@ export const PlankControls = forwardRef<HTMLDivElement, PlankControlsProps>(
154
158
  ? 'ph--caret-line-right--regular'
155
159
  : 'ph--x--regular'
156
160
  }
161
+ onClick={() => onClick?.('close')}
162
+ />
163
+ )}
164
+
165
+ {capabilities.companion && (
166
+ <PlankControl
167
+ label={t('open companion label')}
168
+ classNames={buttonClassNames}
169
+ data-testid='plankHeading.companion'
170
+ icon='ph--square-split-horizontal--regular'
171
+ onClick={() => onClick?.('companion')}
157
172
  />
158
173
  )}
159
174
  {children}
@@ -8,7 +8,7 @@ import { type Node } from '@dxos/plugin-graph';
8
8
  import { useTranslation } from '@dxos/react-ui';
9
9
  import { descriptionText, mx } from '@dxos/react-ui-theme';
10
10
 
11
- import { NodePlankHeading, type NodePlankHeadingProps } from './NodePlankHeading';
11
+ import { PlankHeading, type PlankHeadingProps } from './PlankHeading';
12
12
  import { PlankLoading } from './PlankLoading';
13
13
  import { DECK_PLUGIN } from '../../meta';
14
14
 
@@ -38,7 +38,7 @@ export const PlankError = ({
38
38
  error,
39
39
  }: {
40
40
  id: string;
41
- part: NodePlankHeadingProps['part'];
41
+ part: PlankHeadingProps['part'];
42
42
  node?: Node;
43
43
  error?: Error;
44
44
  }) => {
@@ -48,7 +48,7 @@ export const PlankError = ({
48
48
  }, []);
49
49
  return (
50
50
  <>
51
- <NodePlankHeading id={id} part={part} node={node} pending={!timedOut} />
51
+ <PlankHeading id={id} part={part} node={node} pending={!timedOut} />
52
52
  {timedOut ? <PlankContentError error={error} /> : <PlankLoading />}
53
53
  </>
54
54
  );