@dxos/plugin-deck 0.8.1 → 0.8.2-main.f081794
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.
- package/dist/lib/browser/{chunk-B4LOJUWW.mjs → chunk-4QSEGMY3.mjs} +10 -10
- package/dist/lib/browser/{chunk-B4LOJUWW.mjs.map → chunk-4QSEGMY3.mjs.map} +3 -3
- package/dist/lib/browser/{chunk-6ZSOFCPP.mjs → chunk-6HJZL3WT.mjs} +8 -7
- package/dist/lib/browser/{chunk-6ZSOFCPP.mjs.map → chunk-6HJZL3WT.mjs.map} +3 -3
- package/dist/lib/browser/{chunk-FJBMNSUC.mjs → chunk-VP6FCWFV.mjs} +171 -151
- package/dist/lib/browser/chunk-VP6FCWFV.mjs.map +7 -0
- package/dist/lib/browser/{chunk-RJNCG4ND.mjs → chunk-ZMJMCN7O.mjs} +9 -6
- package/dist/lib/browser/chunk-ZMJMCN7O.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +5 -3
- package/dist/lib/browser/index.mjs.map +2 -2
- package/dist/lib/browser/{intent-resolver-UDYKO2QW.mjs → intent-resolver-6AK45PT5.mjs} +49 -31
- package/dist/lib/browser/intent-resolver-6AK45PT5.mjs.map +7 -0
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/{react-root-XLXN2VEW.mjs → react-root-KA2IL5RA.mjs} +5 -5
- package/dist/lib/browser/{react-surface-WNGMZL7I.mjs → react-surface-LIPGYEYN.mjs} +5 -5
- package/dist/lib/browser/{settings-HMDGSBGO.mjs → settings-6NU7CF2B.mjs} +4 -4
- package/dist/lib/browser/settings-6NU7CF2B.mjs.map +7 -0
- package/dist/lib/browser/{state-7TN26M42.mjs → state-Z6UY2Z3M.mjs} +6 -5
- package/dist/lib/browser/state-Z6UY2Z3M.mjs.map +7 -0
- package/dist/lib/browser/{tools-SC6QEN7R.mjs → tools-VDVQTJMD.mjs} +2 -2
- package/dist/lib/browser/types.mjs +1 -1
- package/dist/lib/browser/{url-handler-ODG4B6NX.mjs → url-handler-3CARFXQK.mjs} +2 -2
- package/dist/types/src/capabilities/capabilities.d.ts +8 -6
- package/dist/types/src/capabilities/capabilities.d.ts.map +1 -1
- package/dist/types/src/capabilities/index.d.ts +2 -2
- package/dist/types/src/capabilities/index.d.ts.map +1 -1
- package/dist/types/src/capabilities/intent-resolver.d.ts.map +1 -1
- package/dist/types/src/capabilities/state.d.ts +5 -4
- package/dist/types/src/capabilities/state.d.ts.map +1 -1
- package/dist/types/src/components/DeckLayout/ContentEmpty.d.ts.map +1 -1
- package/dist/types/src/components/DeckLayout/DeckLayout.d.ts.map +1 -1
- package/dist/types/src/components/DeckLayout/Dialog.d.ts +3 -0
- package/dist/types/src/components/DeckLayout/Dialog.d.ts.map +1 -0
- package/dist/types/src/components/DeckLayout/Popover.d.ts +5 -0
- package/dist/types/src/components/DeckLayout/Popover.d.ts.map +1 -0
- package/dist/types/src/components/Plank/Plank.d.ts.map +1 -1
- package/dist/types/src/components/Plank/PlankControls.d.ts +2 -2
- package/dist/types/src/components/Plank/PlankControls.d.ts.map +1 -1
- package/dist/types/src/components/Plank/PlankHeading.d.ts +3 -2
- package/dist/types/src/components/Plank/PlankHeading.d.ts.map +1 -1
- package/dist/types/src/components/Sidebar/ComplementarySidebar.d.ts.map +1 -1
- package/dist/types/src/components/Sidebar/Sidebar.d.ts.map +1 -1
- package/dist/types/src/translations.d.ts +2 -0
- package/dist/types/src/translations.d.ts.map +1 -1
- package/dist/types/src/types.d.ts +11 -9
- package/dist/types/src/types.d.ts.map +1 -1
- package/dist/types/src/util/layoutAppliesTopbar.d.ts +2 -1
- package/dist/types/src/util/layoutAppliesTopbar.d.ts.map +1 -1
- package/dist/types/src/util/useHoistStatusbar.d.ts +2 -1
- package/dist/types/src/util/useHoistStatusbar.d.ts.map +1 -1
- package/package.json +28 -28
- package/src/capabilities/index.ts +2 -2
- package/src/capabilities/intent-resolver.ts +36 -20
- package/src/capabilities/settings.ts +2 -2
- package/src/capabilities/state.ts +3 -2
- package/src/components/DeckLayout/ContentEmpty.tsx +6 -2
- package/src/components/DeckLayout/DeckLayout.tsx +114 -181
- package/src/components/DeckLayout/Dialog.tsx +36 -0
- package/src/components/DeckLayout/Popover.tsx +76 -0
- package/src/components/Plank/Plank.tsx +3 -2
- package/src/components/Plank/PlankControls.tsx +33 -33
- package/src/components/Plank/PlankHeading.tsx +6 -4
- package/src/components/Sidebar/ComplementarySidebar.tsx +30 -20
- package/src/components/Sidebar/Sidebar.tsx +5 -3
- package/src/translations.ts +2 -0
- package/src/types.ts +9 -6
- package/src/util/layoutAppliesTopbar.ts +8 -2
- package/src/util/useHoistStatusbar.ts +9 -4
- package/dist/lib/browser/chunk-FJBMNSUC.mjs.map +0 -7
- package/dist/lib/browser/chunk-RJNCG4ND.mjs.map +0 -7
- package/dist/lib/browser/intent-resolver-UDYKO2QW.mjs.map +0 -7
- package/dist/lib/browser/settings-HMDGSBGO.mjs.map +0 -7
- package/dist/lib/browser/state-7TN26M42.mjs.map +0 -7
- package/dist/types/src/components/DeckLayout/Fullscreen.d.ts +0 -5
- package/dist/types/src/components/DeckLayout/Fullscreen.d.ts.map +0 -1
- package/src/components/DeckLayout/Fullscreen.tsx +0 -31
- /package/dist/lib/browser/{react-root-XLXN2VEW.mjs.map → react-root-KA2IL5RA.mjs.map} +0 -0
- /package/dist/lib/browser/{react-surface-WNGMZL7I.mjs.map → react-surface-LIPGYEYN.mjs.map} +0 -0
- /package/dist/lib/browser/{tools-SC6QEN7R.mjs.map → tools-VDVQTJMD.mjs.map} +0 -0
- /package/dist/lib/browser/{url-handler-ODG4B6NX.mjs.map → url-handler-3CARFXQK.mjs.map} +0 -0
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
import { Capabilities, contributes } from '@dxos/app-framework';
|
|
6
6
|
import { invariant } from '@dxos/invariant';
|
|
7
|
-
import {
|
|
7
|
+
import { live } from '@dxos/live-object';
|
|
8
8
|
import { LocalStorageStore } from '@dxos/local-storage';
|
|
9
9
|
import { type SidebarState } from '@dxos/react-ui';
|
|
10
10
|
|
|
@@ -41,6 +41,7 @@ export default () => {
|
|
|
41
41
|
dialogBlockAlign: undefined,
|
|
42
42
|
dialogType: undefined,
|
|
43
43
|
popoverContent: null,
|
|
44
|
+
popoverAnchor: undefined,
|
|
44
45
|
popoverAnchorId: undefined,
|
|
45
46
|
popoverOpen: false,
|
|
46
47
|
toasts: [],
|
|
@@ -67,7 +68,7 @@ export default () => {
|
|
|
67
68
|
.prop({ key: 'activeDeck', type: LocalStorageStore.string() })
|
|
68
69
|
.prop({ key: 'previousDeck', type: LocalStorageStore.string() });
|
|
69
70
|
|
|
70
|
-
const layout =
|
|
71
|
+
const layout = live<Capabilities.Layout>({
|
|
71
72
|
get mode() {
|
|
72
73
|
return getMode(state.values.deck);
|
|
73
74
|
},
|
|
@@ -4,15 +4,19 @@
|
|
|
4
4
|
|
|
5
5
|
import React from 'react';
|
|
6
6
|
|
|
7
|
-
import { Surface } from '@dxos/app-framework';
|
|
7
|
+
import { Surface, useCapability } from '@dxos/app-framework';
|
|
8
8
|
|
|
9
|
+
import { DeckCapabilities } from '../../capabilities';
|
|
10
|
+
import { getMode } from '../../types';
|
|
9
11
|
import { layoutAppliesTopbar, useBreakpoints } from '../../util';
|
|
10
12
|
import { ToggleSidebarButton } from '../Sidebar';
|
|
11
13
|
import { fixedSidebarToggleStyles } from '../fragments';
|
|
12
14
|
|
|
13
15
|
export const ContentEmpty = () => {
|
|
14
16
|
const breakpoint = useBreakpoints();
|
|
15
|
-
const
|
|
17
|
+
const { deck } = useCapability(DeckCapabilities.MutableDeckState);
|
|
18
|
+
const layoutMode = getMode(deck);
|
|
19
|
+
const topbar = layoutAppliesTopbar(breakpoint, layoutMode);
|
|
16
20
|
return (
|
|
17
21
|
<div
|
|
18
22
|
role='none'
|
|
@@ -3,33 +3,25 @@
|
|
|
3
3
|
//
|
|
4
4
|
|
|
5
5
|
import { untracked } from '@preact/signals-core';
|
|
6
|
-
import React, { useCallback, useEffect, useMemo, useRef, type UIEvent, Fragment
|
|
6
|
+
import React, { useCallback, useEffect, useMemo, useRef, type UIEvent, Fragment } from 'react';
|
|
7
7
|
|
|
8
8
|
import {
|
|
9
9
|
Capabilities,
|
|
10
10
|
LayoutAction,
|
|
11
|
-
Surface,
|
|
12
11
|
createIntent,
|
|
13
12
|
useCapability,
|
|
14
13
|
useIntentDispatcher,
|
|
15
14
|
usePluginManager,
|
|
16
15
|
} from '@dxos/app-framework';
|
|
17
16
|
import { AttentionCapabilities } from '@dxos/plugin-attention';
|
|
18
|
-
import {
|
|
19
|
-
AlertDialog,
|
|
20
|
-
Dialog as NaturalDialog,
|
|
21
|
-
Main,
|
|
22
|
-
Popover,
|
|
23
|
-
type MainProps,
|
|
24
|
-
useMediaQuery,
|
|
25
|
-
useOnTransition,
|
|
26
|
-
} from '@dxos/react-ui';
|
|
17
|
+
import { Main, type MainProps, useMediaQuery, useOnTransition } from '@dxos/react-ui';
|
|
27
18
|
import { Stack, StackContext, DEFAULT_HORIZONTAL_SIZE } from '@dxos/react-ui-stack';
|
|
28
19
|
import { mainPaddingTransitions } from '@dxos/react-ui-theme';
|
|
29
20
|
|
|
30
21
|
import { ActiveNode } from './ActiveNode';
|
|
31
22
|
import { ContentEmpty } from './ContentEmpty';
|
|
32
|
-
import {
|
|
23
|
+
import { Dialog } from './Dialog';
|
|
24
|
+
import { PopoverContent, PopoverRoot } from './Popover';
|
|
33
25
|
import { StatusBar } from './StatusBar';
|
|
34
26
|
import { Toast } from './Toast';
|
|
35
27
|
import { Topbar } from './Topbar';
|
|
@@ -37,7 +29,7 @@ import { DeckCapabilities } from '../../capabilities';
|
|
|
37
29
|
import { DECK_PLUGIN } from '../../meta';
|
|
38
30
|
import { type DeckSettingsProps, getMode } from '../../types';
|
|
39
31
|
import { calculateOverscroll, layoutAppliesTopbar, useBreakpoints, useHoistStatusbar } from '../../util';
|
|
40
|
-
import { Plank
|
|
32
|
+
import { Plank } from '../Plank';
|
|
41
33
|
import { ComplementarySidebar, Sidebar, ToggleComplementarySidebarButton, ToggleSidebarButton } from '../Sidebar';
|
|
42
34
|
import { fixedComplementarySidebarToggleStyles, fixedSidebarToggleStyles } from '../fragments';
|
|
43
35
|
|
|
@@ -52,36 +44,17 @@ export const DeckLayout = ({ onDismissToast }: DeckLayoutProps) => {
|
|
|
52
44
|
const { dispatchPromise: dispatch } = useIntentDispatcher();
|
|
53
45
|
const settings = useCapability(Capabilities.SettingsStore).getStore<DeckSettingsProps>(DECK_PLUGIN)!.value;
|
|
54
46
|
const context = useCapability(DeckCapabilities.MutableDeckState);
|
|
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;
|
|
47
|
+
const { sidebarState, complementarySidebarState, complementarySidebarPanel, deck, toasts } = context;
|
|
69
48
|
const { active, activeCompanions, fullscreen, solo, plankSizing } = deck;
|
|
70
49
|
const breakpoint = useBreakpoints();
|
|
71
|
-
const
|
|
72
|
-
const
|
|
50
|
+
const layoutMode = getMode(deck);
|
|
51
|
+
const topbar = layoutAppliesTopbar(breakpoint, layoutMode);
|
|
52
|
+
const hoistStatusbar = useHoistStatusbar(breakpoint, layoutMode);
|
|
73
53
|
const pluginManager = usePluginManager();
|
|
74
54
|
|
|
75
55
|
const scrollLeftRef = useRef<number | null>();
|
|
76
56
|
const deckRef = useRef<HTMLDivElement>(null);
|
|
77
57
|
|
|
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
|
-
|
|
85
58
|
// Ensure the first plank is attended when the deck is first rendered.
|
|
86
59
|
useEffect(() => {
|
|
87
60
|
// NOTE: Not `useAttended` so that the layout component is not re-rendered when the attended list changes.
|
|
@@ -144,8 +117,6 @@ export const DeckLayout = ({ onDismissToast }: DeckLayoutProps) => {
|
|
|
144
117
|
deckRef.current.scrollLeft = scrollLeftRef.current;
|
|
145
118
|
}
|
|
146
119
|
}, []);
|
|
147
|
-
|
|
148
|
-
const layoutMode = getMode(deck);
|
|
149
120
|
useOnTransition(layoutMode, (mode) => mode !== 'deck', 'deck', restoreScroll);
|
|
150
121
|
|
|
151
122
|
/**
|
|
@@ -178,22 +149,6 @@ export const DeckLayout = ({ onDismissToast }: DeckLayoutProps) => {
|
|
|
178
149
|
[topbar, hoistStatusbar],
|
|
179
150
|
);
|
|
180
151
|
|
|
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
|
-
|
|
197
152
|
const { order, itemsCount }: { order: Record<string, number>; itemsCount: number } = useMemo(() => {
|
|
198
153
|
return active.reduce(
|
|
199
154
|
(acc: { order: Record<string, number>; itemsCount: number }, entryId) => {
|
|
@@ -206,146 +161,124 @@ export const DeckLayout = ({ onDismissToast }: DeckLayoutProps) => {
|
|
|
206
161
|
}, [active, activeCompanions]);
|
|
207
162
|
|
|
208
163
|
return (
|
|
209
|
-
<
|
|
164
|
+
<PopoverRoot>
|
|
210
165
|
<ActiveNode />
|
|
211
166
|
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
>
|
|
221
|
-
{/* Left sidebar. */}
|
|
222
|
-
<Sidebar />
|
|
167
|
+
<Main.Root
|
|
168
|
+
navigationSidebarState={fullscreen ? 'closed' : context.sidebarState}
|
|
169
|
+
onNavigationSidebarStateChange={(next) => (context.sidebarState = next)}
|
|
170
|
+
complementarySidebarState={fullscreen ? 'closed' : context.complementarySidebarState}
|
|
171
|
+
onComplementarySidebarStateChange={(next) => (context.complementarySidebarState = next)}
|
|
172
|
+
>
|
|
173
|
+
{/* Left sidebar. */}
|
|
174
|
+
<Sidebar />
|
|
223
175
|
|
|
224
|
-
|
|
225
|
-
|
|
176
|
+
{/* Right sidebar. */}
|
|
177
|
+
<ComplementarySidebar current={complementarySidebarPanel} />
|
|
226
178
|
|
|
227
|
-
|
|
228
|
-
|
|
179
|
+
{/* Dialog overlay to dismiss dialogs. */}
|
|
180
|
+
<Main.Overlay />
|
|
229
181
|
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
182
|
+
{/* No content. */}
|
|
183
|
+
{isEmpty && (
|
|
184
|
+
<Main.Content bounce handlesFocus classNames={mainPosition}>
|
|
185
|
+
<ContentEmpty />
|
|
186
|
+
</Main.Content>
|
|
187
|
+
)}
|
|
236
188
|
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
189
|
+
{/* Solo/deck mode. */}
|
|
190
|
+
{!isEmpty && (
|
|
191
|
+
<Main.Content
|
|
192
|
+
bounce
|
|
193
|
+
classNames={mainPosition}
|
|
194
|
+
handlesFocus
|
|
195
|
+
style={
|
|
196
|
+
{
|
|
197
|
+
'--dx-main-sidebarWidth':
|
|
198
|
+
sidebarState === 'expanded'
|
|
199
|
+
? 'var(--nav-sidebar-size)'
|
|
200
|
+
: sidebarState === 'collapsed'
|
|
201
|
+
? 'var(--l0-size)'
|
|
202
|
+
: '0',
|
|
203
|
+
'--dx-main-complementaryWidth':
|
|
204
|
+
complementarySidebarState === 'expanded'
|
|
205
|
+
? 'var(--complementary-sidebar-size)'
|
|
206
|
+
: complementarySidebarState === 'collapsed'
|
|
207
|
+
? 'var(--rail-size)'
|
|
208
|
+
: '0',
|
|
209
|
+
'--dx-main-contentFirstWidth': `${plankSizing[active[0] ?? 'never'] ?? DEFAULT_HORIZONTAL_SIZE}rem`,
|
|
210
|
+
'--dx-main-contentLastWidth': `${plankSizing[active[(active.length ?? 1) - 1] ?? 'never'] ?? DEFAULT_HORIZONTAL_SIZE}rem`,
|
|
211
|
+
} as MainProps['style']
|
|
212
|
+
}
|
|
213
|
+
>
|
|
214
|
+
<div
|
|
215
|
+
role='none'
|
|
216
|
+
className={!solo ? 'relative bg-deck overflow-hidden' : 'sr-only'}
|
|
217
|
+
{...(solo && { inert: '' })}
|
|
261
218
|
>
|
|
262
|
-
<
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
219
|
+
{!topbar && !fullscreen && <ToggleSidebarButton classNames={fixedSidebarToggleStyles} />}
|
|
220
|
+
{!topbar && !fullscreen && (
|
|
221
|
+
<ToggleComplementarySidebarButton classNames={fixedComplementarySidebarToggleStyles} />
|
|
222
|
+
)}
|
|
223
|
+
<Stack
|
|
224
|
+
ref={deckRef}
|
|
225
|
+
orientation='horizontal'
|
|
226
|
+
size='contain'
|
|
227
|
+
classNames={['absolute inset-block-0 -inset-inline-px', mainPaddingTransitions]}
|
|
228
|
+
itemsCount={itemsCount - 1}
|
|
229
|
+
style={padding}
|
|
230
|
+
onScroll={handleScroll}
|
|
266
231
|
>
|
|
267
|
-
{
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
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
|
-
)}
|
|
232
|
+
{active.map((entryId) => (
|
|
233
|
+
<Fragment key={entryId}>
|
|
234
|
+
<PlankSeparator order={order[entryId] - 1} />
|
|
235
|
+
<Plank
|
|
236
|
+
id={entryId}
|
|
237
|
+
companionId={activeCompanions?.[entryId]}
|
|
238
|
+
part='deck'
|
|
239
|
+
order={order[entryId]}
|
|
240
|
+
active={active}
|
|
241
|
+
layoutMode={layoutMode}
|
|
242
|
+
settings={settings}
|
|
243
|
+
/>
|
|
244
|
+
</Fragment>
|
|
245
|
+
))}
|
|
246
|
+
</Stack>
|
|
247
|
+
</div>
|
|
248
|
+
<div
|
|
249
|
+
role='none'
|
|
250
|
+
className={solo ? 'relative bg-deck overflow-hidden' : 'sr-only'}
|
|
251
|
+
{...(!solo && { inert: '' })}
|
|
252
|
+
>
|
|
253
|
+
{!topbar && !fullscreen && <ToggleSidebarButton classNames={fixedSidebarToggleStyles} />}
|
|
254
|
+
{!topbar && !fullscreen && (
|
|
255
|
+
<ToggleComplementarySidebarButton classNames={fixedComplementarySidebarToggleStyles} />
|
|
256
|
+
)}
|
|
257
|
+
<StackContext.Provider value={{ size: 'contain', orientation: 'horizontal', rail: true }}>
|
|
258
|
+
<Plank
|
|
259
|
+
id={solo}
|
|
260
|
+
companionId={solo ? activeCompanions?.[solo] : undefined}
|
|
261
|
+
part='solo'
|
|
262
|
+
layoutMode={layoutMode}
|
|
263
|
+
settings={settings}
|
|
264
|
+
/>
|
|
265
|
+
</StackContext.Provider>
|
|
266
|
+
</div>
|
|
267
|
+
</Main.Content>
|
|
268
|
+
)}
|
|
313
269
|
|
|
314
|
-
|
|
315
|
-
|
|
270
|
+
{/* Topbar. */}
|
|
271
|
+
{topbar && <Topbar />}
|
|
316
272
|
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
)}
|
|
273
|
+
{/* Status bar. */}
|
|
274
|
+
{hoistStatusbar && <StatusBar showHints={settings.showHints} />}
|
|
275
|
+
</Main.Root>
|
|
321
276
|
|
|
322
277
|
{/* Global popovers. */}
|
|
323
|
-
<
|
|
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>
|
|
278
|
+
<PopoverContent />
|
|
331
279
|
|
|
332
280
|
{/* Global dialog. */}
|
|
333
|
-
|
|
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>
|
|
281
|
+
<Dialog />
|
|
349
282
|
|
|
350
283
|
{/* Global toasts. */}
|
|
351
284
|
{toasts?.map((toast) => (
|
|
@@ -361,6 +294,6 @@ export const DeckLayout = ({ onDismissToast }: DeckLayoutProps) => {
|
|
|
361
294
|
}}
|
|
362
295
|
/>
|
|
363
296
|
))}
|
|
364
|
-
</
|
|
297
|
+
</PopoverRoot>
|
|
365
298
|
);
|
|
366
299
|
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2025 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import React from 'react';
|
|
6
|
+
|
|
7
|
+
import { Surface, useCapability } from '@dxos/app-framework';
|
|
8
|
+
import { AlertDialog, Dialog as NaturalDialog } from '@dxos/react-ui';
|
|
9
|
+
|
|
10
|
+
import { DeckCapabilities } from '../../capabilities';
|
|
11
|
+
import { PlankContentError } from '../Plank';
|
|
12
|
+
|
|
13
|
+
export const Dialog = () => {
|
|
14
|
+
const context = useCapability(DeckCapabilities.MutableDeckState);
|
|
15
|
+
const { dialogType, dialogBlockAlign, dialogContent, dialogOpen } = context;
|
|
16
|
+
const Root = dialogType === 'alert' ? AlertDialog.Root : NaturalDialog.Root;
|
|
17
|
+
const Overlay = dialogType === 'alert' ? AlertDialog.Overlay : NaturalDialog.Overlay;
|
|
18
|
+
|
|
19
|
+
// TODO(thure): End block alignment affecting `modal` and whether the surface renders in an overlay is tailored to the needs of the ambient chat dialog. As the feature matures, consider separating concerns.
|
|
20
|
+
return (
|
|
21
|
+
<Root
|
|
22
|
+
modal={dialogBlockAlign !== 'end'}
|
|
23
|
+
open={dialogOpen}
|
|
24
|
+
onOpenChange={(nextOpen) => (context.dialogOpen = nextOpen)}
|
|
25
|
+
>
|
|
26
|
+
{dialogBlockAlign === 'end' ? (
|
|
27
|
+
// TODO(burdon): Placeholder creates a suspense boundary; replace with defaults.
|
|
28
|
+
<Surface role='dialog' data={dialogContent} limit={1} fallback={PlankContentError} placeholder={<div />} />
|
|
29
|
+
) : (
|
|
30
|
+
<Overlay blockAlign={dialogBlockAlign}>
|
|
31
|
+
<Surface role='dialog' data={dialogContent} limit={1} fallback={PlankContentError} />
|
|
32
|
+
</Overlay>
|
|
33
|
+
)}
|
|
34
|
+
</Root>
|
|
35
|
+
);
|
|
36
|
+
};
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2025 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import React, { type PropsWithChildren, useCallback, useEffect, useRef, useState } from 'react';
|
|
6
|
+
|
|
7
|
+
import { Surface, useCapability } from '@dxos/app-framework';
|
|
8
|
+
import { Popover } from '@dxos/react-ui';
|
|
9
|
+
|
|
10
|
+
import { DeckCapabilities } from '../../capabilities';
|
|
11
|
+
|
|
12
|
+
export type DeckPopoverRootProps = PropsWithChildren<{}>;
|
|
13
|
+
|
|
14
|
+
export const PopoverRoot = ({ children }: DeckPopoverRootProps) => {
|
|
15
|
+
const context = useCapability(DeckCapabilities.MutableDeckState);
|
|
16
|
+
const virtualRef = useRef<HTMLButtonElement | null>(null);
|
|
17
|
+
const [virtualIter, setVirtualIter] = useState(0);
|
|
18
|
+
|
|
19
|
+
// TODO(thure): This is a workaround for the difference in `React`ion time between displaying a Popover and rendering
|
|
20
|
+
// the anchor further down the tree. Refactor to use VirtualTrigger or some other approach which does not cause a lag.
|
|
21
|
+
const [delayedPopoverVisibility, setDelayedPopoverVisibility] = useState(false);
|
|
22
|
+
useEffect(() => {
|
|
23
|
+
context.popoverOpen ? setTimeout(() => setDelayedPopoverVisibility(true), 40) : setDelayedPopoverVisibility(false);
|
|
24
|
+
}, [context.popoverOpen]);
|
|
25
|
+
|
|
26
|
+
const handlePopoverOpenChange = useCallback(
|
|
27
|
+
(nextOpen: boolean) => {
|
|
28
|
+
if (nextOpen && (context.popoverAnchor || context.popoverAnchorId)) {
|
|
29
|
+
context.popoverOpen = true;
|
|
30
|
+
} else {
|
|
31
|
+
context.popoverOpen = false;
|
|
32
|
+
context.popoverAnchor = undefined;
|
|
33
|
+
context.popoverAnchorId = undefined;
|
|
34
|
+
context.popoverSide = undefined;
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
[context],
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
useEffect(() => {
|
|
41
|
+
virtualRef.current = context.popoverAnchor ?? null;
|
|
42
|
+
setVirtualIter((iter) => iter + 1);
|
|
43
|
+
}, [context.popoverAnchor]);
|
|
44
|
+
|
|
45
|
+
return (
|
|
46
|
+
<Popover.Root
|
|
47
|
+
modal
|
|
48
|
+
open={!!((context.popoverAnchor || context.popoverAnchorId) && delayedPopoverVisibility)}
|
|
49
|
+
onOpenChange={handlePopoverOpenChange}
|
|
50
|
+
>
|
|
51
|
+
{context.popoverAnchor && <Popover.VirtualTrigger key={virtualIter} virtualRef={virtualRef} />}
|
|
52
|
+
{children}
|
|
53
|
+
</Popover.Root>
|
|
54
|
+
);
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
export const PopoverContent = () => {
|
|
58
|
+
const context = useCapability(DeckCapabilities.MutableDeckState);
|
|
59
|
+
const handlePopoverClose = useCallback(() => {
|
|
60
|
+
context.popoverOpen = false;
|
|
61
|
+
context.popoverAnchor = undefined;
|
|
62
|
+
context.popoverAnchorId = undefined;
|
|
63
|
+
context.popoverSide = undefined;
|
|
64
|
+
}, [context]);
|
|
65
|
+
|
|
66
|
+
return (
|
|
67
|
+
<Popover.Portal>
|
|
68
|
+
<Popover.Content side={context.popoverSide} onEscapeKeyDown={handlePopoverClose}>
|
|
69
|
+
<Popover.Viewport>
|
|
70
|
+
<Surface role='popover' data={context.popoverContent} limit={1} />
|
|
71
|
+
</Popover.Viewport>
|
|
72
|
+
<Popover.Arrow />
|
|
73
|
+
</Popover.Content>
|
|
74
|
+
</Popover.Portal>
|
|
75
|
+
);
|
|
76
|
+
};
|
|
@@ -101,9 +101,9 @@ const PlankImpl = memo(
|
|
|
101
101
|
}
|
|
102
102
|
}, [id, scrollIntoView, layoutMode]);
|
|
103
103
|
|
|
104
|
-
const isSolo = layoutMode
|
|
104
|
+
const isSolo = layoutMode.startsWith('solo') && part === 'solo';
|
|
105
105
|
const isAttendable =
|
|
106
|
-
(layoutMode
|
|
106
|
+
(layoutMode.startsWith('solo') && part.startsWith('solo')) || (layoutMode === 'deck' && part === 'deck');
|
|
107
107
|
|
|
108
108
|
const sizeAttrs = useMainSize();
|
|
109
109
|
|
|
@@ -157,6 +157,7 @@ const PlankImpl = memo(
|
|
|
157
157
|
id={id}
|
|
158
158
|
part={part.startsWith('solo-') ? 'solo' : part}
|
|
159
159
|
node={node}
|
|
160
|
+
layoutMode={layoutMode}
|
|
160
161
|
deckEnabled={settings?.enableDeck}
|
|
161
162
|
canIncrementStart={canIncrementStart}
|
|
162
163
|
canIncrementEnd={canIncrementEnd}
|