@dxos/plugin-deck 0.8.1 → 0.8.2-main.2f9c567
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/{check-app-scheme-SEYECDHI.mjs → check-app-scheme-O7JPE4TM.mjs} +2 -3
- package/dist/lib/browser/check-app-scheme-O7JPE4TM.mjs.map +7 -0
- package/dist/lib/browser/{chunk-FJBMNSUC.mjs → chunk-AHTP72DY.mjs} +207 -162
- package/dist/lib/browser/chunk-AHTP72DY.mjs.map +7 -0
- package/dist/lib/browser/chunk-E7TOEOGO.mjs +157 -0
- package/dist/lib/browser/chunk-E7TOEOGO.mjs.map +7 -0
- package/dist/lib/browser/{chunk-6ZSOFCPP.mjs → chunk-PGSJT5PG.mjs} +8 -7
- package/dist/lib/browser/{chunk-6ZSOFCPP.mjs.map → chunk-PGSJT5PG.mjs.map} +3 -3
- package/dist/lib/browser/chunk-RKYIMUKW.mjs +24 -0
- package/dist/lib/browser/{chunk-B4LOJUWW.mjs.map → chunk-RKYIMUKW.mjs.map} +3 -3
- 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-NO6L67KF.mjs} +78 -53
- package/dist/lib/browser/intent-resolver-NO6L67KF.mjs.map +7 -0
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/{react-root-XLXN2VEW.mjs → react-root-5RWCIUXV.mjs} +5 -5
- package/dist/lib/browser/{react-surface-WNGMZL7I.mjs → react-surface-DIDOPTH7.mjs} +5 -5
- package/dist/lib/browser/{settings-HMDGSBGO.mjs → settings-C7LX2GXF.mjs} +4 -4
- package/dist/lib/browser/settings-C7LX2GXF.mjs.map +7 -0
- package/dist/lib/browser/{state-7TN26M42.mjs → state-AX74YEJD.mjs} +6 -5
- package/dist/lib/browser/state-AX74YEJD.mjs.map +7 -0
- package/dist/lib/browser/{tools-SC6QEN7R.mjs → tools-7W7KZRAX.mjs} +7 -7
- package/dist/lib/browser/tools-7W7KZRAX.mjs.map +7 -0
- package/dist/lib/browser/types.mjs +1 -1
- package/dist/lib/browser/{url-handler-ODG4B6NX.mjs → url-handler-AF5SYROZ.mjs} +2 -2
- package/dist/types/src/capabilities/app-graph-builder.d.ts.map +1 -1
- 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/check-app-scheme.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/capabilities/tools.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/PlankError.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 +106 -104
- 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 +31 -29
- package/src/capabilities/check-app-scheme.ts +3 -5
- package/src/capabilities/index.ts +2 -2
- package/src/capabilities/intent-resolver.ts +120 -96
- package/src/capabilities/settings.ts +2 -2
- package/src/capabilities/state.ts +3 -2
- package/src/capabilities/tools.ts +4 -3
- 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 +104 -0
- package/src/components/Plank/Plank.tsx +6 -3
- package/src/components/Plank/PlankControls.tsx +40 -34
- package/src/components/Plank/PlankError.tsx +2 -6
- package/src/components/Plank/PlankHeading.tsx +12 -5
- 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 +75 -71
- package/src/util/layoutAppliesTopbar.ts +8 -2
- package/src/util/useHoistStatusbar.ts +9 -4
- package/dist/lib/browser/check-app-scheme-SEYECDHI.mjs.map +0 -7
- package/dist/lib/browser/chunk-B4LOJUWW.mjs +0 -24
- package/dist/lib/browser/chunk-FJBMNSUC.mjs.map +0 -7
- package/dist/lib/browser/chunk-RJNCG4ND.mjs +0 -154
- 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/lib/browser/tools-SC6QEN7R.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-5RWCIUXV.mjs.map} +0 -0
- /package/dist/lib/browser/{react-surface-WNGMZL7I.mjs.map → react-surface-DIDOPTH7.mjs.map} +0 -0
- /package/dist/lib/browser/{url-handler-ODG4B6NX.mjs.map → url-handler-AF5SYROZ.mjs.map} +0 -0
|
@@ -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,104 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2025 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { createContext } from '@radix-ui/react-context';
|
|
6
|
+
import React, { type PropsWithChildren, useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
7
|
+
|
|
8
|
+
import { Surface, useCapability } from '@dxos/app-framework';
|
|
9
|
+
import { Popover, type PopoverContentInteractOutsideEvent } from '@dxos/react-ui';
|
|
10
|
+
|
|
11
|
+
import { DeckCapabilities } from '../../capabilities';
|
|
12
|
+
|
|
13
|
+
export type DeckPopoverRootProps = PropsWithChildren<{}>;
|
|
14
|
+
|
|
15
|
+
const DEBOUNCE_DELAY = 40;
|
|
16
|
+
|
|
17
|
+
type DeckPopoverContextValue = {
|
|
18
|
+
setOpen: (open: boolean) => void;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const [DeckPopoverProvider, useDeckPopoverContext] = createContext<DeckPopoverContextValue>('DeckPopover');
|
|
22
|
+
|
|
23
|
+
export const PopoverRoot = ({ children }: DeckPopoverRootProps) => {
|
|
24
|
+
const layout = useCapability(DeckCapabilities.MutableDeckState);
|
|
25
|
+
const virtualRef = useRef<HTMLButtonElement | null>(null);
|
|
26
|
+
const [virtualIter, setVirtualIter] = useState(0);
|
|
27
|
+
const [open, setOpen] = useState(false);
|
|
28
|
+
const debounceRef = useRef<NodeJS.Timeout | null>(null);
|
|
29
|
+
|
|
30
|
+
// TODO(thure): This is a workaround for the race condition between displaying a Popover and either rendering
|
|
31
|
+
// the anchor further down the tree or measuring the virtual trigger’s client rect.
|
|
32
|
+
useEffect(() => {
|
|
33
|
+
setOpen(false);
|
|
34
|
+
if (layout.popoverOpen) {
|
|
35
|
+
if (debounceRef.current) {
|
|
36
|
+
clearTimeout(debounceRef.current);
|
|
37
|
+
}
|
|
38
|
+
if (layout.popoverAnchor && virtualRef.current !== layout.popoverAnchor) {
|
|
39
|
+
virtualRef.current = layout.popoverAnchor ?? null;
|
|
40
|
+
setVirtualIter((iter) => iter + 1);
|
|
41
|
+
}
|
|
42
|
+
debounceRef.current = setTimeout(() => setOpen(true), DEBOUNCE_DELAY);
|
|
43
|
+
}
|
|
44
|
+
}, [layout.popoverOpen, layout.popoverAnchorId, layout.popoverAnchor, layout.popoverContent]);
|
|
45
|
+
|
|
46
|
+
return (
|
|
47
|
+
<DeckPopoverProvider setOpen={setOpen}>
|
|
48
|
+
<Popover.Root modal={false} open={open}>
|
|
49
|
+
{layout.popoverAnchor && <Popover.VirtualTrigger key={virtualIter} virtualRef={virtualRef} />}
|
|
50
|
+
{children}
|
|
51
|
+
</Popover.Root>
|
|
52
|
+
</DeckPopoverProvider>
|
|
53
|
+
);
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
export const PopoverContent = () => {
|
|
57
|
+
const layout = useCapability(DeckCapabilities.MutableDeckState);
|
|
58
|
+
const { setOpen } = useDeckPopoverContext('PopoverContent');
|
|
59
|
+
|
|
60
|
+
const handleClose = useCallback(
|
|
61
|
+
(event: KeyboardEvent | PopoverContentInteractOutsideEvent) => {
|
|
62
|
+
if (
|
|
63
|
+
// TODO(thure): CodeMirror should not focus itself when it updates.
|
|
64
|
+
event.type === 'dismissableLayer.focusOutside' &&
|
|
65
|
+
(event.currentTarget as HTMLElement | undefined)?.classList.contains('cm-content')
|
|
66
|
+
) {
|
|
67
|
+
event.preventDefault();
|
|
68
|
+
} else {
|
|
69
|
+
setOpen(false);
|
|
70
|
+
layout.popoverOpen = false;
|
|
71
|
+
layout.popoverAnchor = undefined;
|
|
72
|
+
layout.popoverAnchorId = undefined;
|
|
73
|
+
layout.popoverSide = undefined;
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
[setOpen],
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
const collisionBoundaries: HTMLElement[] = useMemo(() => {
|
|
80
|
+
const closest = layout.popoverAnchor?.closest('[data-popover-collision-boundary]') as
|
|
81
|
+
| HTMLElement
|
|
82
|
+
| null
|
|
83
|
+
| undefined;
|
|
84
|
+
return closest ? [closest] : [];
|
|
85
|
+
}, [layout.popoverAnchor]);
|
|
86
|
+
|
|
87
|
+
return (
|
|
88
|
+
<Popover.Portal>
|
|
89
|
+
<Popover.Content
|
|
90
|
+
side={layout.popoverSide}
|
|
91
|
+
onInteractOutside={handleClose}
|
|
92
|
+
onEscapeKeyDown={handleClose}
|
|
93
|
+
collisionBoundary={collisionBoundaries}
|
|
94
|
+
sticky='always'
|
|
95
|
+
hideWhenDetached
|
|
96
|
+
>
|
|
97
|
+
<Popover.Viewport>
|
|
98
|
+
<Surface role='popover' data={layout.popoverContent} limit={1} />
|
|
99
|
+
</Popover.Viewport>
|
|
100
|
+
<Popover.Arrow />
|
|
101
|
+
</Popover.Content>
|
|
102
|
+
</Popover.Portal>
|
|
103
|
+
);
|
|
104
|
+
};
|
|
@@ -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
|
|
|
@@ -116,7 +116,7 @@ const PlankImpl = memo(
|
|
|
116
116
|
path,
|
|
117
117
|
popoverAnchorId,
|
|
118
118
|
},
|
|
119
|
-
[node, node?.data, path, popoverAnchorId, primary?.data],
|
|
119
|
+
[node, node?.data, path, popoverAnchorId, primary?.data, variant],
|
|
120
120
|
);
|
|
121
121
|
|
|
122
122
|
// TODO(wittjosiah): Change prop to accept a component.
|
|
@@ -131,6 +131,8 @@ const PlankImpl = memo(
|
|
|
131
131
|
part === 'deck' && (companioned === 'companion' ? '!border-separator border-ie' : '!border-separator border-li'),
|
|
132
132
|
part.startsWith('solo-') && 'row-span-2 grid-rows-subgrid min-is-0',
|
|
133
133
|
part === 'solo-companion' && '!border-separator border-is',
|
|
134
|
+
layoutMode === 'solo--fullscreen' &&
|
|
135
|
+
'!transition-[margin-block-start,inline-size] -mbs-[--rail-action] has-[[data-plank-heading]:hover]:mbs-0',
|
|
134
136
|
);
|
|
135
137
|
|
|
136
138
|
return (
|
|
@@ -157,6 +159,7 @@ const PlankImpl = memo(
|
|
|
157
159
|
id={id}
|
|
158
160
|
part={part.startsWith('solo-') ? 'solo' : part}
|
|
159
161
|
node={node}
|
|
162
|
+
layoutMode={layoutMode}
|
|
160
163
|
deckEnabled={settings?.enableDeck}
|
|
161
164
|
canIncrementStart={canIncrementStart}
|
|
162
165
|
canIncrementEnd={canIncrementEnd}
|