@dxos/plugin-deck 0.8.2-main.fbd8ed0 → 0.8.2-staging.7ac8446

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 (151) hide show
  1. package/dist/lib/browser/{app-graph-builder-R7COZ4A6.mjs → app-graph-builder-VYZ4IWI3.mjs} +15 -16
  2. package/dist/lib/browser/app-graph-builder-VYZ4IWI3.mjs.map +7 -0
  3. package/dist/lib/browser/{check-app-scheme-7AXGR6UT.mjs → check-app-scheme-SEYECDHI.mjs} +3 -2
  4. package/dist/lib/browser/check-app-scheme-SEYECDHI.mjs.map +7 -0
  5. package/dist/lib/browser/chunk-6ZSOFCPP.mjs +117 -0
  6. package/dist/lib/browser/chunk-6ZSOFCPP.mjs.map +7 -0
  7. package/dist/lib/browser/chunk-B4LOJUWW.mjs +24 -0
  8. package/dist/lib/browser/chunk-B4LOJUWW.mjs.map +7 -0
  9. package/dist/lib/browser/{chunk-KIGMELV2.mjs → chunk-FJBMNSUC.mjs} +336 -366
  10. package/dist/lib/browser/chunk-FJBMNSUC.mjs.map +7 -0
  11. package/dist/lib/browser/chunk-FLOVGNYB.mjs +81 -0
  12. package/dist/lib/browser/chunk-FLOVGNYB.mjs.map +7 -0
  13. package/dist/lib/browser/chunk-RJNCG4ND.mjs +154 -0
  14. package/dist/lib/browser/chunk-RJNCG4ND.mjs.map +7 -0
  15. package/dist/lib/browser/index.mjs +5 -6
  16. package/dist/lib/browser/index.mjs.map +2 -2
  17. package/dist/lib/browser/{intent-resolver-MAKOS57L.mjs → intent-resolver-UDYKO2QW.mjs} +89 -130
  18. package/dist/lib/browser/intent-resolver-UDYKO2QW.mjs.map +7 -0
  19. package/dist/lib/browser/meta.json +1 -1
  20. package/dist/lib/browser/{react-root-DGQVIHXP.mjs → react-root-XLXN2VEW.mjs} +6 -6
  21. package/dist/lib/browser/{react-surface-PXBXIOPU.mjs → react-surface-WNGMZL7I.mjs} +6 -6
  22. package/dist/lib/browser/{settings-UBWJF7J7.mjs → settings-HMDGSBGO.mjs} +6 -6
  23. package/dist/lib/browser/settings-HMDGSBGO.mjs.map +7 -0
  24. package/dist/lib/browser/{chunk-OF5RIATN.mjs → state-7TN26M42.mjs} +7 -10
  25. package/dist/lib/browser/state-7TN26M42.mjs.map +7 -0
  26. package/dist/lib/browser/{tools-IVPIPTVA.mjs → tools-SC6QEN7R.mjs} +7 -7
  27. package/dist/lib/browser/tools-SC6QEN7R.mjs.map +7 -0
  28. package/dist/lib/browser/types.mjs +1 -1
  29. package/dist/lib/browser/{url-handler-JSYGSVSB.mjs → url-handler-ODG4B6NX.mjs} +4 -4
  30. package/dist/lib/browser/url-handler-ODG4B6NX.mjs.map +7 -0
  31. package/dist/types/src/capabilities/app-graph-builder.d.ts +179 -2
  32. package/dist/types/src/capabilities/app-graph-builder.d.ts.map +1 -1
  33. package/dist/types/src/capabilities/capabilities.d.ts +6 -8
  34. package/dist/types/src/capabilities/capabilities.d.ts.map +1 -1
  35. package/dist/types/src/capabilities/check-app-scheme.d.ts +2 -2
  36. package/dist/types/src/capabilities/check-app-scheme.d.ts.map +1 -1
  37. package/dist/types/src/capabilities/index.d.ts +182 -7
  38. package/dist/types/src/capabilities/index.d.ts.map +1 -1
  39. package/dist/types/src/capabilities/intent-resolver.d.ts +2 -2
  40. package/dist/types/src/capabilities/intent-resolver.d.ts.map +1 -1
  41. package/dist/types/src/capabilities/state.d.ts +6 -7
  42. package/dist/types/src/capabilities/state.d.ts.map +1 -1
  43. package/dist/types/src/capabilities/tools.d.ts.map +1 -1
  44. package/dist/types/src/capabilities/url-handler.d.ts +2 -2
  45. package/dist/types/src/capabilities/url-handler.d.ts.map +1 -1
  46. package/dist/types/src/components/DeckLayout/Banner.d.ts.map +1 -1
  47. package/dist/types/src/components/DeckLayout/ContentEmpty.d.ts.map +1 -1
  48. package/dist/types/src/components/DeckLayout/DeckLayout.d.ts.map +1 -1
  49. package/dist/types/src/components/DeckLayout/Fullscreen.d.ts +5 -0
  50. package/dist/types/src/components/DeckLayout/Fullscreen.d.ts.map +1 -0
  51. package/dist/types/src/components/DeckLayout/StatusBar.d.ts.map +1 -1
  52. package/dist/types/src/components/DeckLayout/Toast.d.ts.map +1 -1
  53. package/dist/types/src/components/DeckSettings/DeckSettings.d.ts.map +1 -1
  54. package/dist/types/src/components/Plank/Plank.d.ts +5 -18
  55. package/dist/types/src/components/Plank/Plank.d.ts.map +1 -1
  56. package/dist/types/src/components/Plank/Plank.stories.d.ts +3 -3
  57. package/dist/types/src/components/Plank/Plank.stories.d.ts.map +1 -1
  58. package/dist/types/src/components/Plank/PlankControls.d.ts +2 -3
  59. package/dist/types/src/components/Plank/PlankControls.d.ts.map +1 -1
  60. package/dist/types/src/components/Plank/PlankError.d.ts.map +1 -1
  61. package/dist/types/src/components/Plank/PlankHeading.d.ts +2 -3
  62. package/dist/types/src/components/Plank/PlankHeading.d.ts.map +1 -1
  63. package/dist/types/src/components/Sidebar/ComplementarySidebar.d.ts.map +1 -1
  64. package/dist/types/src/components/Sidebar/Sidebar.d.ts.map +1 -1
  65. package/dist/types/src/components/Sidebar/SidebarButton.d.ts +1 -2
  66. package/dist/types/src/components/Sidebar/SidebarButton.d.ts.map +1 -1
  67. package/dist/types/src/hooks/index.d.ts +1 -5
  68. package/dist/types/src/hooks/index.d.ts.map +1 -1
  69. package/dist/types/src/hooks/useNodeActionExpander.d.ts.map +1 -1
  70. package/dist/types/src/index.d.ts +1 -1
  71. package/dist/types/src/index.d.ts.map +1 -1
  72. package/dist/types/src/layout.d.ts.map +1 -1
  73. package/dist/types/src/translations.d.ts +0 -2
  74. package/dist/types/src/translations.d.ts.map +1 -1
  75. package/dist/types/src/types.d.ts +104 -106
  76. package/dist/types/src/types.d.ts.map +1 -1
  77. package/dist/types/src/util/index.d.ts +4 -1
  78. package/dist/types/src/util/index.d.ts.map +1 -1
  79. package/dist/types/src/util/layoutAppliesTopbar.d.ts +1 -2
  80. package/dist/types/src/util/layoutAppliesTopbar.d.ts.map +1 -1
  81. package/dist/types/src/util/overscroll.d.ts.map +1 -1
  82. package/dist/types/src/util/set-active.d.ts.map +1 -1
  83. package/dist/types/src/util/useBreakpoints.d.ts.map +1 -0
  84. package/dist/types/src/util/useCompanions.d.ts.map +1 -0
  85. package/dist/types/src/util/useHoistStatusbar.d.ts +2 -0
  86. package/dist/types/src/util/useHoistStatusbar.d.ts.map +1 -0
  87. package/dist/types/tsconfig.tsbuildinfo +1 -1
  88. package/package.json +29 -36
  89. package/src/capabilities/app-graph-builder.ts +92 -120
  90. package/src/capabilities/check-app-scheme.ts +7 -3
  91. package/src/capabilities/index.ts +2 -3
  92. package/src/capabilities/intent-resolver.ts +133 -175
  93. package/src/capabilities/settings.ts +4 -4
  94. package/src/capabilities/state.ts +4 -7
  95. package/src/capabilities/tools.ts +3 -4
  96. package/src/capabilities/url-handler.ts +4 -4
  97. package/src/components/DeckLayout/ContentEmpty.tsx +4 -9
  98. package/src/components/DeckLayout/DeckLayout.tsx +188 -123
  99. package/src/components/DeckLayout/Fullscreen.tsx +31 -0
  100. package/src/components/Plank/Plank.stories.tsx +8 -20
  101. package/src/components/Plank/Plank.tsx +68 -104
  102. package/src/components/Plank/PlankControls.tsx +57 -53
  103. package/src/components/Plank/PlankError.tsx +6 -2
  104. package/src/components/Plank/PlankHeading.tsx +12 -29
  105. package/src/components/Sidebar/ComplementarySidebar.tsx +54 -33
  106. package/src/components/Sidebar/Sidebar.tsx +4 -7
  107. package/src/components/Sidebar/SidebarButton.tsx +7 -30
  108. package/src/components/fragments.ts +1 -1
  109. package/src/hooks/index.ts +1 -5
  110. package/src/hooks/useNodeActionExpander.ts +8 -3
  111. package/src/index.ts +1 -1
  112. package/src/translations.ts +0 -2
  113. package/src/types.ts +71 -75
  114. package/src/util/index.ts +4 -1
  115. package/src/util/layoutAppliesTopbar.ts +2 -8
  116. package/src/{hooks → util}/useCompanions.ts +3 -3
  117. package/src/{hooks → util}/useHoistStatusbar.ts +4 -9
  118. package/dist/lib/browser/app-graph-builder-R7COZ4A6.mjs.map +0 -7
  119. package/dist/lib/browser/check-app-scheme-7AXGR6UT.mjs.map +0 -7
  120. package/dist/lib/browser/chunk-3O2UZVBA.mjs +0 -121
  121. package/dist/lib/browser/chunk-3O2UZVBA.mjs.map +0 -7
  122. package/dist/lib/browser/chunk-JAYQ5BTF.mjs +0 -157
  123. package/dist/lib/browser/chunk-JAYQ5BTF.mjs.map +0 -7
  124. package/dist/lib/browser/chunk-KIGMELV2.mjs.map +0 -7
  125. package/dist/lib/browser/chunk-OF5RIATN.mjs.map +0 -7
  126. package/dist/lib/browser/chunk-TRFYUEBA.mjs +0 -145
  127. package/dist/lib/browser/chunk-TRFYUEBA.mjs.map +0 -7
  128. package/dist/lib/browser/intent-resolver-MAKOS57L.mjs.map +0 -7
  129. package/dist/lib/browser/settings-UBWJF7J7.mjs.map +0 -7
  130. package/dist/lib/browser/state-4WFB4SDO.mjs +0 -10
  131. package/dist/lib/browser/state-4WFB4SDO.mjs.map +0 -7
  132. package/dist/lib/browser/tools-IVPIPTVA.mjs.map +0 -7
  133. package/dist/lib/browser/url-handler-JSYGSVSB.mjs.map +0 -7
  134. package/dist/types/src/components/DeckLayout/Dialog.d.ts +0 -3
  135. package/dist/types/src/components/DeckLayout/Dialog.d.ts.map +0 -1
  136. package/dist/types/src/components/DeckLayout/Popover.d.ts +0 -5
  137. package/dist/types/src/components/DeckLayout/Popover.d.ts.map +0 -1
  138. package/dist/types/src/hooks/useBreakpoints.d.ts.map +0 -1
  139. package/dist/types/src/hooks/useCompanions.d.ts.map +0 -1
  140. package/dist/types/src/hooks/useDeckCompanions.d.ts +0 -13
  141. package/dist/types/src/hooks/useDeckCompanions.d.ts.map +0 -1
  142. package/dist/types/src/hooks/useHoistStatusbar.d.ts +0 -3
  143. package/dist/types/src/hooks/useHoistStatusbar.d.ts.map +0 -1
  144. package/src/components/DeckLayout/Dialog.tsx +0 -36
  145. package/src/components/DeckLayout/Popover.tsx +0 -104
  146. package/src/hooks/useDeckCompanions.ts +0 -33
  147. /package/dist/lib/browser/{react-root-DGQVIHXP.mjs.map → react-root-XLXN2VEW.mjs.map} +0 -0
  148. /package/dist/lib/browser/{react-surface-PXBXIOPU.mjs.map → react-surface-WNGMZL7I.mjs.map} +0 -0
  149. /package/dist/types/src/{hooks → util}/useBreakpoints.d.ts +0 -0
  150. /package/dist/types/src/{hooks → util}/useCompanions.d.ts +0 -0
  151. /package/src/{hooks → util}/useBreakpoints.ts +0 -0
@@ -3,34 +3,41 @@
3
3
  //
4
4
 
5
5
  import { untracked } from '@preact/signals-core';
6
- import React, { useCallback, useEffect, useMemo, useRef, type UIEvent, Fragment } from 'react';
6
+ import React, { useCallback, useEffect, useMemo, useRef, type UIEvent, Fragment, useState } from 'react';
7
7
 
8
8
  import {
9
9
  Capabilities,
10
10
  LayoutAction,
11
+ Surface,
11
12
  createIntent,
12
13
  useCapability,
13
14
  useIntentDispatcher,
14
15
  usePluginManager,
15
16
  } from '@dxos/app-framework';
16
17
  import { AttentionCapabilities } from '@dxos/plugin-attention';
17
- import { Main, type MainProps, useMediaQuery, useOnTransition } from '@dxos/react-ui';
18
+ import {
19
+ AlertDialog,
20
+ Dialog as NaturalDialog,
21
+ Main,
22
+ Popover,
23
+ type MainProps,
24
+ useMediaQuery,
25
+ useOnTransition,
26
+ } from '@dxos/react-ui';
18
27
  import { Stack, StackContext, DEFAULT_HORIZONTAL_SIZE } from '@dxos/react-ui-stack';
19
28
  import { mainPaddingTransitions } from '@dxos/react-ui-theme';
20
29
 
21
30
  import { ActiveNode } from './ActiveNode';
22
31
  import { ContentEmpty } from './ContentEmpty';
23
- import { Dialog } from './Dialog';
24
- import { PopoverContent, PopoverRoot } from './Popover';
32
+ import { Fullscreen } from './Fullscreen';
25
33
  import { StatusBar } from './StatusBar';
26
34
  import { Toast } from './Toast';
27
35
  import { Topbar } from './Topbar';
28
36
  import { DeckCapabilities } from '../../capabilities';
29
- import { useBreakpoints, useHoistStatusbar } from '../../hooks';
30
37
  import { DECK_PLUGIN } from '../../meta';
31
38
  import { type DeckSettingsProps, getMode } from '../../types';
32
- import { calculateOverscroll, layoutAppliesTopbar } from '../../util';
33
- import { Plank } from '../Plank';
39
+ import { calculateOverscroll, layoutAppliesTopbar, useBreakpoints, useHoistStatusbar } from '../../util';
40
+ import { Plank, PlankContentError } from '../Plank';
34
41
  import { ComplementarySidebar, Sidebar, ToggleComplementarySidebarButton, ToggleSidebarButton } from '../Sidebar';
35
42
  import { fixedComplementarySidebarToggleStyles, fixedSidebarToggleStyles } from '../fragments';
36
43
 
@@ -39,28 +46,47 @@ export type DeckLayoutProps = {
39
46
  };
40
47
 
41
48
  const PlankSeparator = ({ order }: { order: number }) =>
42
- order > 0 ? <span role='separator' className='row-span-2 bg-deckSurface is-4' style={{ gridColumn: order }} /> : null;
49
+ order > 0 ? <span role='separator' className='row-span-2 bg-deck is-4' style={{ gridColumn: order }} /> : null;
43
50
 
44
51
  export const DeckLayout = ({ onDismissToast }: DeckLayoutProps) => {
45
52
  const { dispatchPromise: dispatch } = useIntentDispatcher();
46
53
  const settings = useCapability(Capabilities.SettingsStore).getStore<DeckSettingsProps>(DECK_PLUGIN)!.value;
47
54
  const context = useCapability(DeckCapabilities.MutableDeckState);
48
- const { sidebarState, complementarySidebarState, complementarySidebarPanel, deck, toasts } = context;
55
+ const {
56
+ sidebarState,
57
+ complementarySidebarState,
58
+ complementarySidebarPanel,
59
+ dialogOpen,
60
+ dialogContent,
61
+ dialogBlockAlign,
62
+ dialogType,
63
+ popoverOpen,
64
+ popoverContent,
65
+ popoverAnchorId,
66
+ deck,
67
+ toasts,
68
+ } = context;
49
69
  const { active, activeCompanions, fullscreen, solo, plankSizing } = deck;
50
70
  const breakpoint = useBreakpoints();
51
- const layoutMode = getMode(deck);
52
- const topbar = layoutAppliesTopbar(breakpoint, layoutMode);
53
- const hoistStatusbar = useHoistStatusbar(breakpoint, layoutMode);
71
+ const topbar = layoutAppliesTopbar(breakpoint);
72
+ const hoistStatusbar = useHoistStatusbar(breakpoint);
54
73
  const pluginManager = usePluginManager();
55
74
 
56
75
  const scrollLeftRef = useRef<number | null>();
57
76
  const deckRef = useRef<HTMLDivElement>(null);
58
77
 
78
+ // TODO(thure): This is a workaround for the difference in `React`ion time between displaying a Popover and rendering
79
+ // the anchor further down the tree. Refactor to use VirtualTrigger or some other approach which does not cause a lag.
80
+ const [delayedPopoverVisibility, setDelayedPopoverVisibility] = useState(false);
81
+ useEffect(() => {
82
+ popoverOpen ? setTimeout(() => setDelayedPopoverVisibility(true), 40) : setDelayedPopoverVisibility(false);
83
+ }, [popoverOpen]);
84
+
59
85
  // Ensure the first plank is attended when the deck is first rendered.
60
86
  useEffect(() => {
61
87
  // NOTE: Not `useAttended` so that the layout component is not re-rendered when the attended list changes.
62
88
  const attended = untracked(() => {
63
- const attention = pluginManager.context.getCapability(AttentionCapabilities.Attention);
89
+ const attention = pluginManager.context.requestCapability(AttentionCapabilities.Attention);
64
90
  return attention.current;
65
91
  });
66
92
  const firstId = solo ?? active[0];
@@ -79,7 +105,7 @@ export const DeckLayout = ({ onDismissToast }: DeckLayoutProps) => {
79
105
  if (!isNotMobile && getMode(deck) === 'deck') {
80
106
  // NOTE: Not `useAttended` so that the layout component is not re-rendered when the attended list changes.
81
107
  const attended = untracked(() => {
82
- const attention = pluginManager.context.getCapability(AttentionCapabilities.Attention);
108
+ const attention = pluginManager.context.requestCapability(AttentionCapabilities.Attention);
83
109
  return attention.current;
84
110
  });
85
111
 
@@ -92,15 +118,14 @@ export const DeckLayout = ({ onDismissToast }: DeckLayoutProps) => {
92
118
  }
93
119
  }, [isNotMobile, deck, dispatch]);
94
120
 
95
- // When deck is disabled in settings, set to solo mode if the current layout mode is deck.
96
- // TODO(thure): Applying this as an effect should be avoided over emitting the intent only when the setting changes.
121
+ // If deck is disabled in settings, ensure that the layout is in solo mode.
97
122
  useEffect(() => {
98
- if (!settings.enableDeck && layoutMode === 'deck') {
123
+ if (!settings.enableDeck) {
99
124
  void dispatch(
100
125
  createIntent(LayoutAction.SetLayoutMode, { part: 'mode', subject: active[0], options: { mode: 'solo' } }),
101
126
  );
102
127
  }
103
- }, [settings.enableDeck, dispatch, active, layoutMode]);
128
+ }, [settings.enableDeck, dispatch, active]);
104
129
 
105
130
  /**
106
131
  * Clear scroll restoration state if the window is resized
@@ -119,6 +144,8 @@ export const DeckLayout = ({ onDismissToast }: DeckLayoutProps) => {
119
144
  deckRef.current.scrollLeft = scrollLeftRef.current;
120
145
  }
121
146
  }, []);
147
+
148
+ const layoutMode = getMode(deck);
122
149
  useOnTransition(layoutMode, (mode) => mode !== 'deck', 'deck', restoreScroll);
123
150
 
124
151
  /**
@@ -151,6 +178,22 @@ export const DeckLayout = ({ onDismissToast }: DeckLayoutProps) => {
151
178
  [topbar, hoistStatusbar],
152
179
  );
153
180
 
181
+ const Dialog = dialogType === 'alert' ? AlertDialog : NaturalDialog;
182
+
183
+ const handlePopoverOpenChange = useCallback(
184
+ (nextOpen: boolean) => {
185
+ if (nextOpen && popoverAnchorId) {
186
+ context.popoverOpen = true;
187
+ } else {
188
+ context.popoverOpen = false;
189
+ context.popoverAnchorId = undefined;
190
+ context.popoverSide = undefined;
191
+ }
192
+ },
193
+ [context],
194
+ );
195
+ const handlePopoverClose = useCallback(() => handlePopoverOpenChange(false), [handlePopoverOpenChange]);
196
+
154
197
  const { order, itemsCount }: { order: Record<string, number>; itemsCount: number } = useMemo(() => {
155
198
  return active.reduce(
156
199
  (acc: { order: Record<string, number>; itemsCount: number }, entryId) => {
@@ -163,124 +206,146 @@ export const DeckLayout = ({ onDismissToast }: DeckLayoutProps) => {
163
206
  }, [active, activeCompanions]);
164
207
 
165
208
  return (
166
- <PopoverRoot>
209
+ <Popover.Root modal open={!!(popoverAnchorId && delayedPopoverVisibility)} onOpenChange={handlePopoverOpenChange}>
167
210
  <ActiveNode />
168
211
 
169
- <Main.Root
170
- navigationSidebarState={fullscreen ? 'closed' : context.sidebarState}
171
- onNavigationSidebarStateChange={(next) => (context.sidebarState = next)}
172
- complementarySidebarState={fullscreen ? 'closed' : context.complementarySidebarState}
173
- onComplementarySidebarStateChange={(next) => (context.complementarySidebarState = next)}
174
- >
175
- {/* Left sidebar. */}
176
- <Sidebar />
212
+ {fullscreen && <Fullscreen id={solo} />}
177
213
 
178
- {/* Right sidebar. */}
179
- <ComplementarySidebar current={complementarySidebarPanel} />
214
+ {!fullscreen && (
215
+ <Main.Root
216
+ navigationSidebarState={context.sidebarState}
217
+ onNavigationSidebarStateChange={(next) => (context.sidebarState = next)}
218
+ complementarySidebarState={context.complementarySidebarState}
219
+ onComplementarySidebarStateChange={(next) => (context.complementarySidebarState = next)}
220
+ >
221
+ {/* Left sidebar. */}
222
+ <Sidebar />
180
223
 
181
- {/* Dialog overlay to dismiss dialogs. */}
182
- <Main.Overlay />
224
+ {/* Right sidebar. */}
225
+ <ComplementarySidebar current={complementarySidebarPanel} />
183
226
 
184
- {/* No content. */}
185
- {isEmpty && (
186
- <Main.Content bounce handlesFocus classNames={mainPosition}>
187
- <ContentEmpty />
188
- </Main.Content>
189
- )}
227
+ {/* Dialog overlay to dismiss dialogs. */}
228
+ <Main.Overlay />
190
229
 
191
- {/* Solo/deck mode. */}
192
- {!isEmpty && (
193
- <Main.Content
194
- bounce
195
- handlesFocus
196
- classNames={mainPosition}
197
- style={
198
- {
199
- '--dx-main-sidebarWidth':
200
- sidebarState === 'expanded'
201
- ? 'var(--nav-sidebar-size)'
202
- : sidebarState === 'collapsed'
203
- ? 'var(--l0-size)'
204
- : '0',
205
- '--dx-main-complementaryWidth':
206
- complementarySidebarState === 'expanded'
207
- ? 'var(--complementary-sidebar-size)'
208
- : complementarySidebarState === 'collapsed'
209
- ? 'var(--rail-size)'
210
- : '0',
211
- '--dx-main-contentFirstWidth': `${plankSizing[active[0] ?? 'never'] ?? DEFAULT_HORIZONTAL_SIZE}rem`,
212
- '--dx-main-contentLastWidth': `${plankSizing[active[(active.length ?? 1) - 1] ?? 'never'] ?? DEFAULT_HORIZONTAL_SIZE}rem`,
213
- } as MainProps['style']
214
- }
215
- >
216
- <div
217
- role='none'
218
- className={!solo ? 'relative bg-deckSurface overflow-hidden' : 'sr-only'}
219
- {...(solo && { inert: '' })}
230
+ {/* No content. */}
231
+ {isEmpty && (
232
+ <Main.Content bounce handlesFocus classNames={mainPosition}>
233
+ <ContentEmpty />
234
+ </Main.Content>
235
+ )}
236
+
237
+ {/* Solo/deck mode. */}
238
+ {!isEmpty && (
239
+ <Main.Content
240
+ bounce
241
+ classNames={mainPosition}
242
+ handlesFocus
243
+ style={
244
+ {
245
+ '--dx-main-sidebarWidth':
246
+ sidebarState === 'expanded'
247
+ ? 'var(--nav-sidebar-size)'
248
+ : sidebarState === 'collapsed'
249
+ ? 'var(--l0-size)'
250
+ : '0',
251
+ '--dx-main-complementaryWidth':
252
+ complementarySidebarState === 'expanded'
253
+ ? 'var(--complementary-sidebar-size)'
254
+ : complementarySidebarState === 'collapsed'
255
+ ? 'var(--rail-size)'
256
+ : '0',
257
+ '--dx-main-contentFirstWidth': `${plankSizing[active[0] ?? 'never'] ?? DEFAULT_HORIZONTAL_SIZE}rem`,
258
+ '--dx-main-contentLastWidth': `${plankSizing[active[(active.length ?? 1) - 1] ?? 'never'] ?? DEFAULT_HORIZONTAL_SIZE}rem`,
259
+ } as MainProps['style']
260
+ }
220
261
  >
221
- {!topbar && !fullscreen && <ToggleSidebarButton classNames={fixedSidebarToggleStyles} />}
222
- {!topbar && !fullscreen && (
223
- <ToggleComplementarySidebarButton classNames={fixedComplementarySidebarToggleStyles} />
224
- )}
225
- <Stack
226
- ref={deckRef}
227
- orientation='horizontal'
228
- size='contain'
229
- classNames={['absolute inset-block-0 -inset-inline-px', mainPaddingTransitions]}
230
- itemsCount={itemsCount - 1}
231
- style={padding}
232
- onScroll={handleScroll}
262
+ <div
263
+ role='none'
264
+ className={!solo ? 'relative bg-deck overflow-hidden' : 'sr-only'}
265
+ {...(solo && { inert: '' })}
233
266
  >
234
- {active.map((entryId) => (
235
- <Fragment key={entryId}>
236
- <PlankSeparator order={order[entryId] - 1} />
237
- <Plank
238
- id={entryId}
239
- companionId={activeCompanions?.[entryId]}
240
- part='deck'
241
- order={order[entryId]}
242
- active={active}
243
- layoutMode={layoutMode}
244
- settings={settings}
245
- />
246
- </Fragment>
247
- ))}
248
- </Stack>
249
- </div>
250
- <div
251
- role='none'
252
- className={solo ? 'relative bg-deckSurface overflow-hidden' : 'sr-only'}
253
- {...(!solo && { inert: '' })}
254
- >
255
- {!topbar && !fullscreen && <ToggleSidebarButton classNames={fixedSidebarToggleStyles} />}
256
- {!topbar && !fullscreen && (
257
- <ToggleComplementarySidebarButton classNames={fixedComplementarySidebarToggleStyles} />
258
- )}
259
- <StackContext.Provider value={{ size: 'contain', orientation: 'horizontal', rail: true }}>
260
- <Plank
261
- id={solo}
262
- companionId={solo ? activeCompanions?.[solo] : undefined}
263
- part='solo'
264
- layoutMode={layoutMode}
265
- settings={settings}
266
- />
267
- </StackContext.Provider>
268
- </div>
269
- </Main.Content>
270
- )}
267
+ {!topbar && <ToggleSidebarButton classNames={fixedSidebarToggleStyles} />}
268
+ {!topbar && <ToggleComplementarySidebarButton classNames={fixedComplementarySidebarToggleStyles} />}
269
+ <Stack
270
+ ref={deckRef}
271
+ orientation='horizontal'
272
+ size='contain'
273
+ classNames={['absolute inset-block-0 -inset-inline-px', mainPaddingTransitions]}
274
+ itemsCount={itemsCount - 1}
275
+ style={padding}
276
+ onScroll={handleScroll}
277
+ >
278
+ {active.map((entryId) => (
279
+ <Fragment key={entryId}>
280
+ <PlankSeparator order={order[entryId] - 1} />
281
+ <Plank
282
+ id={entryId}
283
+ companionId={activeCompanions?.[entryId]}
284
+ part='deck'
285
+ order={order[entryId]}
286
+ active={active}
287
+ layoutMode={layoutMode}
288
+ settings={settings}
289
+ />
290
+ </Fragment>
291
+ ))}
292
+ </Stack>
293
+ </div>
294
+ <div
295
+ role='none'
296
+ className={solo ? 'relative bg-deck overflow-hidden' : 'sr-only'}
297
+ {...(!solo && { inert: '' })}
298
+ >
299
+ {!topbar && <ToggleSidebarButton classNames={fixedSidebarToggleStyles} />}
300
+ {!topbar && <ToggleComplementarySidebarButton classNames={fixedComplementarySidebarToggleStyles} />}
301
+ <StackContext.Provider value={{ size: 'contain', orientation: 'horizontal', rail: true }}>
302
+ <Plank
303
+ id={solo}
304
+ companionId={solo ? activeCompanions?.[solo] : undefined}
305
+ part='solo'
306
+ layoutMode={layoutMode}
307
+ settings={settings}
308
+ />
309
+ </StackContext.Provider>
310
+ </div>
311
+ </Main.Content>
312
+ )}
271
313
 
272
- {/* Topbar. */}
273
- {topbar && <Topbar />}
314
+ {/* Topbar. */}
315
+ {topbar && <Topbar />}
274
316
 
275
- {/* Status bar. */}
276
- {hoistStatusbar && <StatusBar showHints={settings.showHints} />}
277
- </Main.Root>
317
+ {/* Status bar. */}
318
+ {hoistStatusbar && <StatusBar showHints={settings.showHints} />}
319
+ </Main.Root>
320
+ )}
278
321
 
279
322
  {/* Global popovers. */}
280
- <PopoverContent />
323
+ <Popover.Portal>
324
+ <Popover.Content side={context.popoverSide} onEscapeKeyDown={handlePopoverClose}>
325
+ <Popover.Viewport>
326
+ <Surface role='popover' data={popoverContent} limit={1} />
327
+ </Popover.Viewport>
328
+ <Popover.Arrow />
329
+ </Popover.Content>
330
+ </Popover.Portal>
281
331
 
282
332
  {/* Global dialog. */}
283
- <Dialog />
333
+ {/* TODO(thure): End block alignment affecting `modal` and whether the surface renders in an overlay is tailored
334
+ to the needs of the ambient chat dialog. As the feature matures, consider separating concerns. */}
335
+ <Dialog.Root
336
+ modal={dialogBlockAlign !== 'end'}
337
+ open={dialogOpen}
338
+ onOpenChange={(nextOpen) => (context.dialogOpen = nextOpen)}
339
+ >
340
+ {dialogBlockAlign === 'end' ? (
341
+ // TODO(burdon): Placeholder creates a suspense boundary; replace with defaults.
342
+ <Surface role='dialog' data={dialogContent} limit={1} fallback={PlankContentError} placeholder={<div />} />
343
+ ) : (
344
+ <Dialog.Overlay blockAlign={dialogBlockAlign}>
345
+ <Surface role='dialog' data={dialogContent} limit={1} fallback={PlankContentError} />
346
+ </Dialog.Overlay>
347
+ )}
348
+ </Dialog.Root>
284
349
 
285
350
  {/* Global toasts. */}
286
351
  {toasts?.map((toast) => (
@@ -296,6 +361,6 @@ export const DeckLayout = ({ onDismissToast }: DeckLayoutProps) => {
296
361
  }}
297
362
  />
298
363
  ))}
299
- </PopoverRoot>
364
+ </Popover.Root>
300
365
  );
301
366
  };
@@ -0,0 +1,31 @@
1
+ //
2
+ // Copyright 2024 DXOS.org
3
+ //
4
+
5
+ import React from 'react';
6
+
7
+ import { Surface, useAppGraph } from '@dxos/app-framework';
8
+ import { useNode } from '@dxos/plugin-graph';
9
+ import { fixedInsetFlexLayout } from '@dxos/react-ui-theme';
10
+
11
+ import { Fallback } from './Fallback';
12
+ import { SURFACE_PREFIX } from './constants';
13
+
14
+ export const Fullscreen = ({ id }: { id?: string }) => {
15
+ const { graph } = useAppGraph();
16
+ const fullScreenNode = useNode(graph, id);
17
+
18
+ return (
19
+ <div role='none' className={fixedInsetFlexLayout}>
20
+ <Surface
21
+ role='main'
22
+ limit={1}
23
+ fallback={Fallback}
24
+ data={{
25
+ subject: fullScreenNode?.data,
26
+ component: id?.startsWith(SURFACE_PREFIX) ? id.slice(SURFACE_PREFIX.length) : undefined,
27
+ }}
28
+ />
29
+ </div>
30
+ );
31
+ };
@@ -5,51 +5,39 @@
5
5
  import '@dxos-theme';
6
6
 
7
7
  import { type StoryObj, type Meta } from '@storybook/react';
8
- import React from 'react';
9
8
 
10
- import { IntentPlugin, SettingsPlugin } from '@dxos/app-framework';
9
+ import { IntentPlugin } from '@dxos/app-framework';
11
10
  import { withPluginManager } from '@dxos/app-framework/testing';
12
- import { AttentionPlugin } from '@dxos/plugin-attention';
13
11
  import { GraphPlugin } from '@dxos/plugin-graph';
14
- import { Stack } from '@dxos/react-ui-stack';
15
12
  import { withTheme, withLayout } from '@dxos/storybook-utils';
16
13
 
17
- import { Plank, type PlankProps } from './Plank';
18
- import DeckStateFactory from '../../capabilities/state';
14
+ import { Plank } from './Plank';
19
15
  import translations from '../../translations';
20
16
 
21
- const meta: Meta<PlankProps> = {
17
+ // TODO(burdon): invariant violation: No capability found for dxos.org/plugin/deck/capability/state
18
+ const meta: Meta<typeof Plank> = {
22
19
  title: 'plugins/plugin-deck/Plank',
23
20
  component: Plank,
24
- render: (args) => {
25
- return (
26
- <Stack orientation='horizontal'>
27
- <Plank {...args} />
28
- </Stack>
29
- );
30
- },
31
21
  decorators: [
32
22
  withPluginManager({
33
- plugins: [AttentionPlugin(), SettingsPlugin(), IntentPlugin(), GraphPlugin()],
34
- capabilities: () => DeckStateFactory(),
23
+ plugins: [IntentPlugin(), GraphPlugin()],
35
24
  }),
36
25
  withTheme,
37
- withLayout({ fullscreen: true }),
26
+ withLayout({ fullscreen: true, tooltips: true }),
38
27
  ],
39
28
  parameters: {
29
+ layout: 'centered',
40
30
  translations,
41
31
  },
42
32
  };
43
33
 
44
34
  export default meta;
45
35
 
46
- type Story = StoryObj<PlankProps>;
36
+ type Story = StoryObj<typeof meta>;
47
37
 
48
- // TODO(burdon): Need to define surface provider?
49
38
  export const Default: Story = {
50
39
  args: {
51
40
  id: 'plank-1',
52
41
  part: 'solo',
53
- layoutMode: 'deck',
54
42
  },
55
43
  };