@dxos/plugin-deck 0.8.1-main.ae460ac → 0.8.1-staging.31c3ee1
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/{app-graph-builder-IYHAGFA3.mjs → app-graph-builder-VYZ4IWI3.mjs} +3 -3
- package/dist/lib/browser/{check-app-scheme-S3EYUPMF.mjs → check-app-scheme-SEYECDHI.mjs} +2 -2
- package/dist/lib/browser/{chunk-YCKJNTKG.mjs → chunk-6ZSOFCPP.mjs} +26 -6
- package/dist/lib/browser/chunk-6ZSOFCPP.mjs.map +7 -0
- package/dist/lib/browser/chunk-B4LOJUWW.mjs +24 -0
- package/dist/lib/browser/{chunk-J2B4CMLT.mjs → chunk-FJBMNSUC.mjs} +649 -488
- package/dist/lib/browser/chunk-FJBMNSUC.mjs.map +7 -0
- package/dist/lib/browser/chunk-FLOVGNYB.mjs +81 -0
- package/dist/lib/browser/chunk-FLOVGNYB.mjs.map +7 -0
- package/dist/lib/browser/{chunk-N7TEPFVR.mjs → chunk-NSATFAEE.mjs} +3 -3
- package/dist/lib/browser/{chunk-N7TEPFVR.mjs.map → chunk-NSATFAEE.mjs.map} +2 -2
- package/dist/lib/browser/{chunk-FYKBOM3C.mjs → chunk-RJNCG4ND.mjs} +66 -40
- package/dist/lib/browser/chunk-RJNCG4ND.mjs.map +7 -0
- package/dist/lib/browser/{chunk-22AQ5IVX.mjs → chunk-XMCG42ID.mjs} +2 -3
- package/dist/lib/browser/chunk-XMCG42ID.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +14 -9
- package/dist/lib/browser/index.mjs.map +3 -3
- package/dist/lib/browser/{intent-resolver-P5BVUQKU.mjs → intent-resolver-UDYKO2QW.mjs} +78 -88
- package/dist/lib/browser/intent-resolver-UDYKO2QW.mjs.map +7 -0
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/{react-root-VFIADBSU.mjs → react-root-XLXN2VEW.mjs} +8 -10
- package/dist/lib/browser/react-root-XLXN2VEW.mjs.map +7 -0
- package/dist/lib/browser/{react-surface-HUPQXFTF.mjs → react-surface-WNGMZL7I.mjs} +11 -10
- package/dist/lib/browser/react-surface-WNGMZL7I.mjs.map +7 -0
- package/dist/lib/browser/{settings-X3P2HKQJ.mjs → settings-HMDGSBGO.mjs} +5 -4
- package/dist/lib/browser/settings-HMDGSBGO.mjs.map +7 -0
- package/dist/lib/browser/{state-2MOTLKVR.mjs → state-7TN26M42.mjs} +7 -11
- package/dist/lib/browser/state-7TN26M42.mjs.map +7 -0
- package/dist/lib/browser/tools-SC6QEN7R.mjs +78 -0
- package/dist/lib/browser/tools-SC6QEN7R.mjs.map +7 -0
- package/dist/lib/browser/types.mjs +12 -6
- package/dist/lib/browser/{url-handler-MVHTKUYA.mjs → url-handler-ODG4B6NX.mjs} +7 -9
- package/dist/lib/browser/url-handler-ODG4B6NX.mjs.map +7 -0
- package/dist/types/src/DeckPlugin.d.ts.map +1 -1
- package/dist/types/src/capabilities/capabilities.d.ts +36 -14
- package/dist/types/src/capabilities/capabilities.d.ts.map +1 -1
- package/dist/types/src/capabilities/intent-resolver.d.ts.map +1 -1
- package/dist/types/src/capabilities/react-root.d.ts.map +1 -1
- package/dist/types/src/capabilities/react-surface.d.ts.map +1 -1
- package/dist/types/src/capabilities/settings.d.ts.map +1 -1
- package/dist/types/src/capabilities/state.d.ts +18 -6
- package/dist/types/src/capabilities/state.d.ts.map +1 -1
- package/dist/types/src/capabilities/tools.d.ts +1 -0
- package/dist/types/src/capabilities/tools.d.ts.map +1 -1
- package/dist/types/src/capabilities/url-handler.d.ts.map +1 -1
- package/dist/types/src/components/DeckLayout/ActiveNode.d.ts +2 -1
- package/dist/types/src/components/DeckLayout/ActiveNode.d.ts.map +1 -1
- package/dist/types/src/components/DeckLayout/Banner.d.ts +2 -1
- package/dist/types/src/components/DeckLayout/Banner.d.ts.map +1 -1
- package/dist/types/src/components/DeckLayout/ContentEmpty.d.ts +2 -1
- package/dist/types/src/components/DeckLayout/ContentEmpty.d.ts.map +1 -1
- package/dist/types/src/components/DeckLayout/DeckLayout.d.ts +2 -4
- package/dist/types/src/components/DeckLayout/DeckLayout.d.ts.map +1 -1
- package/dist/types/src/components/DeckLayout/Fallback.d.ts +2 -1
- package/dist/types/src/components/DeckLayout/Fallback.d.ts.map +1 -1
- package/dist/types/src/components/DeckLayout/Fullscreen.d.ts +2 -1
- package/dist/types/src/components/DeckLayout/Fullscreen.d.ts.map +1 -1
- package/dist/types/src/components/DeckLayout/StatusBar.d.ts +2 -1
- package/dist/types/src/components/DeckLayout/StatusBar.d.ts.map +1 -1
- package/dist/types/src/components/DeckLayout/Toast.d.ts +2 -1
- package/dist/types/src/components/DeckLayout/Toast.d.ts.map +1 -1
- package/dist/types/src/components/DeckLayout/Topbar.d.ts +2 -1
- package/dist/types/src/components/DeckLayout/Topbar.d.ts.map +1 -1
- package/dist/types/src/components/DeckLayout/index.d.ts +1 -0
- package/dist/types/src/components/DeckLayout/index.d.ts.map +1 -1
- package/dist/types/src/components/DeckSettings/DeckSettings.d.ts +6 -0
- package/dist/types/src/components/DeckSettings/DeckSettings.d.ts.map +1 -0
- package/dist/types/src/components/DeckSettings/index.d.ts +2 -0
- package/dist/types/src/components/DeckSettings/index.d.ts.map +1 -0
- package/dist/types/src/components/Plank/Plank.d.ts +14 -0
- package/dist/types/src/components/Plank/Plank.d.ts.map +1 -0
- package/dist/types/src/components/Plank/Plank.stories.d.ts +8 -0
- package/dist/types/src/components/Plank/Plank.stories.d.ts.map +1 -0
- package/dist/types/src/components/{DeckLayout → Plank}/PlankControls.d.ts +8 -1
- package/dist/types/src/components/Plank/PlankControls.d.ts.map +1 -0
- package/dist/types/src/components/Plank/PlankError.d.ts +13 -0
- package/dist/types/src/components/Plank/PlankError.d.ts.map +1 -0
- package/dist/types/src/components/Plank/PlankHeading.d.ts +20 -0
- package/dist/types/src/components/Plank/PlankHeading.d.ts.map +1 -0
- package/dist/types/src/components/Plank/PlankLoading.d.ts +3 -0
- package/dist/types/src/components/Plank/PlankLoading.d.ts.map +1 -0
- package/dist/types/src/components/Plank/index.d.ts +6 -0
- package/dist/types/src/components/Plank/index.d.ts.map +1 -0
- package/dist/types/src/components/{DeckLayout → Sidebar}/ComplementarySidebar.d.ts +2 -1
- package/dist/types/src/components/Sidebar/ComplementarySidebar.d.ts.map +1 -0
- package/dist/types/src/components/Sidebar/Sidebar.d.ts +3 -0
- package/dist/types/src/components/Sidebar/Sidebar.d.ts.map +1 -0
- package/dist/types/src/components/Sidebar/SidebarButton.d.ts +8 -0
- package/dist/types/src/components/Sidebar/SidebarButton.d.ts.map +1 -0
- package/dist/types/src/components/Sidebar/index.d.ts +4 -0
- package/dist/types/src/components/Sidebar/index.d.ts.map +1 -0
- package/dist/types/src/components/index.d.ts +1 -1
- package/dist/types/src/components/index.d.ts.map +1 -1
- package/dist/types/src/events.d.ts +0 -1
- package/dist/types/src/events.d.ts.map +1 -1
- package/dist/types/src/hooks/index.d.ts +0 -1
- package/dist/types/src/hooks/index.d.ts.map +1 -1
- package/dist/types/src/index.d.ts +1 -0
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/layout.d.ts +7 -1
- package/dist/types/src/layout.d.ts.map +1 -1
- package/dist/types/src/meta.d.ts +2 -5
- package/dist/types/src/meta.d.ts.map +1 -1
- package/dist/types/src/translations.d.ts +4 -0
- package/dist/types/src/translations.d.ts.map +1 -1
- package/dist/types/src/types.d.ts +60 -58
- package/dist/types/src/types.d.ts.map +1 -1
- package/dist/types/src/util/index.d.ts +1 -0
- package/dist/types/src/util/index.d.ts.map +1 -1
- package/dist/types/src/util/set-active.d.ts +2 -2
- package/dist/types/src/util/set-active.d.ts.map +1 -1
- package/dist/types/src/util/useCompanions.d.ts +8 -0
- package/dist/types/src/util/useCompanions.d.ts.map +1 -0
- package/dist/types/src/util/useHoistStatusbar.d.ts.map +1 -1
- package/package.json +30 -31
- package/src/DeckPlugin.ts +0 -1
- package/src/capabilities/capabilities.ts +3 -4
- package/src/capabilities/intent-resolver.ts +63 -9
- package/src/capabilities/react-root.tsx +1 -9
- package/src/capabilities/react-surface.tsx +3 -4
- package/src/capabilities/settings.ts +7 -2
- package/src/capabilities/state.ts +4 -11
- package/src/capabilities/tools.ts +34 -22
- package/src/capabilities/url-handler.ts +2 -8
- package/src/components/DeckLayout/ActiveNode.tsx +2 -1
- package/src/components/DeckLayout/Banner.tsx +5 -3
- package/src/components/DeckLayout/ContentEmpty.tsx +1 -1
- package/src/components/DeckLayout/DeckLayout.tsx +62 -26
- package/src/components/DeckLayout/Fullscreen.tsx +1 -1
- package/src/components/DeckLayout/Toast.tsx +1 -1
- package/src/components/DeckLayout/index.ts +2 -0
- package/src/components/{LayoutSettings.tsx → DeckSettings/DeckSettings.tsx} +15 -10
- package/src/components/DeckSettings/index.ts +5 -0
- package/src/components/Plank/Plank.stories.tsx +43 -0
- package/src/components/Plank/Plank.tsx +230 -0
- package/src/components/{DeckLayout → Plank}/PlankControls.tsx +73 -27
- package/src/components/{DeckLayout → Plank}/PlankError.tsx +3 -3
- package/src/components/Plank/PlankHeading.tsx +207 -0
- package/src/components/Plank/index.ts +9 -0
- package/src/components/{DeckLayout → Sidebar}/ComplementarySidebar.tsx +65 -81
- package/src/components/Sidebar/index.ts +7 -0
- package/src/components/index.ts +1 -1
- package/src/events.ts +0 -1
- package/src/hooks/index.ts +0 -1
- package/src/index.ts +1 -0
- package/src/layout.ts +19 -2
- package/src/meta.ts +4 -4
- package/src/translations.ts +4 -0
- package/src/types.ts +81 -79
- package/src/util/index.ts +1 -0
- package/src/util/set-active.ts +2 -2
- package/src/util/useCompanions.ts +18 -0
- package/src/util/useHoistStatusbar.ts +2 -2
- package/dist/lib/browser/chunk-22AQ5IVX.mjs.map +0 -7
- package/dist/lib/browser/chunk-FYKBOM3C.mjs.map +0 -7
- package/dist/lib/browser/chunk-J2B4CMLT.mjs.map +0 -7
- package/dist/lib/browser/chunk-KTIGBCFT.mjs +0 -24
- package/dist/lib/browser/chunk-YCKJNTKG.mjs.map +0 -7
- package/dist/lib/browser/intent-resolver-P5BVUQKU.mjs.map +0 -7
- package/dist/lib/browser/react-root-VFIADBSU.mjs.map +0 -7
- package/dist/lib/browser/react-surface-HUPQXFTF.mjs.map +0 -7
- package/dist/lib/browser/settings-X3P2HKQJ.mjs.map +0 -7
- package/dist/lib/browser/state-2MOTLKVR.mjs.map +0 -7
- package/dist/lib/browser/tools-64LXGLYR.mjs +0 -59
- package/dist/lib/browser/tools-64LXGLYR.mjs.map +0 -7
- package/dist/lib/browser/url-handler-MVHTKUYA.mjs.map +0 -7
- package/dist/types/src/components/DeckLayout/ComplementarySidebar.d.ts.map +0 -1
- package/dist/types/src/components/DeckLayout/NodePlankHeading.d.ts +0 -15
- package/dist/types/src/components/DeckLayout/NodePlankHeading.d.ts.map +0 -1
- package/dist/types/src/components/DeckLayout/Plank.d.ts +0 -13
- package/dist/types/src/components/DeckLayout/Plank.d.ts.map +0 -1
- package/dist/types/src/components/DeckLayout/PlankControls.d.ts.map +0 -1
- package/dist/types/src/components/DeckLayout/PlankError.d.ts +0 -12
- package/dist/types/src/components/DeckLayout/PlankError.d.ts.map +0 -1
- package/dist/types/src/components/DeckLayout/PlankLoading.d.ts +0 -2
- package/dist/types/src/components/DeckLayout/PlankLoading.d.ts.map +0 -1
- package/dist/types/src/components/DeckLayout/Sidebar.d.ts +0 -2
- package/dist/types/src/components/DeckLayout/Sidebar.d.ts.map +0 -1
- package/dist/types/src/components/DeckLayout/SidebarButton.d.ts +0 -7
- package/dist/types/src/components/DeckLayout/SidebarButton.d.ts.map +0 -1
- package/dist/types/src/components/LayoutSettings.d.ts +0 -5
- package/dist/types/src/components/LayoutSettings.d.ts.map +0 -1
- package/dist/types/src/hooks/useNode.d.ts +0 -11
- package/dist/types/src/hooks/useNode.d.ts.map +0 -1
- package/src/components/DeckLayout/NodePlankHeading.tsx +0 -148
- package/src/components/DeckLayout/Plank.tsx +0 -149
- package/src/hooks/useNode.ts +0 -46
- /package/dist/lib/browser/{app-graph-builder-IYHAGFA3.mjs.map → app-graph-builder-VYZ4IWI3.mjs.map} +0 -0
- /package/dist/lib/browser/{check-app-scheme-S3EYUPMF.mjs.map → check-app-scheme-SEYECDHI.mjs.map} +0 -0
- /package/dist/lib/browser/{chunk-KTIGBCFT.mjs.map → chunk-B4LOJUWW.mjs.map} +0 -0
- /package/src/components/{DeckLayout → Plank}/PlankLoading.tsx +0 -0
- /package/src/components/{DeckLayout → Sidebar}/Sidebar.tsx +0 -0
- /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,
|
|
@@ -19,39 +20,37 @@ import {
|
|
|
19
20
|
Dialog as NaturalDialog,
|
|
20
21
|
Main,
|
|
21
22
|
Popover,
|
|
22
|
-
useOnTransition,
|
|
23
23
|
type MainProps,
|
|
24
24
|
useMediaQuery,
|
|
25
|
+
useOnTransition,
|
|
25
26
|
} from '@dxos/react-ui';
|
|
26
27
|
import { Stack, StackContext, DEFAULT_HORIZONTAL_SIZE } from '@dxos/react-ui-stack';
|
|
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 { Sidebar } from './Sidebar';
|
|
35
|
-
import { ToggleComplementarySidebarButton, ToggleSidebarButton } from './SidebarButton';
|
|
36
33
|
import { StatusBar } from './StatusBar';
|
|
37
34
|
import { Toast } from './Toast';
|
|
38
35
|
import { Topbar } from './Topbar';
|
|
39
36
|
import { DeckCapabilities } from '../../capabilities';
|
|
40
|
-
import {
|
|
37
|
+
import { DECK_PLUGIN } from '../../meta';
|
|
38
|
+
import { type DeckSettingsProps, getMode } from '../../types';
|
|
41
39
|
import { calculateOverscroll, layoutAppliesTopbar, useBreakpoints, useHoistStatusbar } from '../../util';
|
|
40
|
+
import { Plank, PlankContentError } from '../Plank';
|
|
41
|
+
import { ComplementarySidebar, Sidebar, ToggleComplementarySidebarButton, ToggleSidebarButton } from '../Sidebar';
|
|
42
42
|
import { fixedComplementarySidebarToggleStyles, fixedSidebarToggleStyles } from '../fragments';
|
|
43
43
|
|
|
44
44
|
export type DeckLayoutProps = {
|
|
45
|
-
overscroll: Overscroll;
|
|
46
|
-
showHints: boolean;
|
|
47
45
|
onDismissToast: (id: string) => void;
|
|
48
46
|
};
|
|
49
47
|
|
|
50
|
-
const PlankSeparator = ({
|
|
51
|
-
|
|
48
|
+
const PlankSeparator = ({ order }: { order: number }) =>
|
|
49
|
+
order > 0 ? <span role='separator' className='row-span-2 bg-deck is-4' style={{ gridColumn: order }} /> : null;
|
|
52
50
|
|
|
53
|
-
export const DeckLayout = ({
|
|
51
|
+
export const DeckLayout = ({ onDismissToast }: DeckLayoutProps) => {
|
|
54
52
|
const { dispatchPromise: dispatch } = useIntentDispatcher();
|
|
53
|
+
const settings = useCapability(Capabilities.SettingsStore).getStore<DeckSettingsProps>(DECK_PLUGIN)!.value;
|
|
55
54
|
const context = useCapability(DeckCapabilities.MutableDeckState);
|
|
56
55
|
const {
|
|
57
56
|
sidebarState,
|
|
@@ -67,7 +66,7 @@ export const DeckLayout = ({ overscroll, showHints, onDismissToast }: DeckLayout
|
|
|
67
66
|
deck,
|
|
68
67
|
toasts,
|
|
69
68
|
} = context;
|
|
70
|
-
const { active, fullscreen, solo, plankSizing } = deck;
|
|
69
|
+
const { active, activeCompanions, fullscreen, solo, plankSizing } = deck;
|
|
71
70
|
const breakpoint = useBreakpoints();
|
|
72
71
|
const topbar = layoutAppliesTopbar(breakpoint);
|
|
73
72
|
const hoistStatusbar = useHoistStatusbar(breakpoint);
|
|
@@ -119,6 +118,15 @@ export const DeckLayout = ({ overscroll, showHints, onDismissToast }: DeckLayout
|
|
|
119
118
|
}
|
|
120
119
|
}, [isNotMobile, deck, dispatch]);
|
|
121
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
|
+
|
|
122
130
|
/**
|
|
123
131
|
* Clear scroll restoration state if the window is resized
|
|
124
132
|
*/
|
|
@@ -155,11 +163,11 @@ export const DeckLayout = ({ overscroll, showHints, onDismissToast }: DeckLayout
|
|
|
155
163
|
const isEmpty = !solo && active.length === 0;
|
|
156
164
|
|
|
157
165
|
const padding = useMemo(() => {
|
|
158
|
-
if (!solo && overscroll === 'centering') {
|
|
166
|
+
if (!solo && settings.overscroll === 'centering') {
|
|
159
167
|
return calculateOverscroll(active.length);
|
|
160
168
|
}
|
|
161
169
|
return {};
|
|
162
|
-
}, [solo, overscroll, deck]);
|
|
170
|
+
}, [solo, settings.overscroll, deck]);
|
|
163
171
|
|
|
164
172
|
const mainPosition = useMemo(
|
|
165
173
|
() => [
|
|
@@ -186,6 +194,17 @@ export const DeckLayout = ({ overscroll, showHints, onDismissToast }: DeckLayout
|
|
|
186
194
|
);
|
|
187
195
|
const handlePopoverClose = useCallback(() => handlePopoverOpenChange(false), [handlePopoverOpenChange]);
|
|
188
196
|
|
|
197
|
+
const { order, itemsCount }: { order: Record<string, number>; itemsCount: number } = useMemo(() => {
|
|
198
|
+
return active.reduce(
|
|
199
|
+
(acc: { order: Record<string, number>; itemsCount: number }, entryId) => {
|
|
200
|
+
acc.order[entryId] = acc.itemsCount + 1;
|
|
201
|
+
acc.itemsCount += activeCompanions?.[entryId] ? 3 : 2;
|
|
202
|
+
return acc;
|
|
203
|
+
},
|
|
204
|
+
{ order: {}, itemsCount: 0 },
|
|
205
|
+
);
|
|
206
|
+
}, [active, activeCompanions]);
|
|
207
|
+
|
|
189
208
|
return (
|
|
190
209
|
<Popover.Root modal open={!!(popoverAnchorId && delayedPopoverVisibility)} onOpenChange={handlePopoverOpenChange}>
|
|
191
210
|
<ActiveNode />
|
|
@@ -248,18 +267,26 @@ export const DeckLayout = ({ overscroll, showHints, onDismissToast }: DeckLayout
|
|
|
248
267
|
{!topbar && <ToggleSidebarButton classNames={fixedSidebarToggleStyles} />}
|
|
249
268
|
{!topbar && <ToggleComplementarySidebarButton classNames={fixedComplementarySidebarToggleStyles} />}
|
|
250
269
|
<Stack
|
|
270
|
+
ref={deckRef}
|
|
251
271
|
orientation='horizontal'
|
|
252
272
|
size='contain'
|
|
253
273
|
classNames={['absolute inset-block-0 -inset-inline-px', mainPaddingTransitions]}
|
|
254
|
-
|
|
255
|
-
itemsCount={2 * (active.length ?? 0) - 1}
|
|
274
|
+
itemsCount={itemsCount - 1}
|
|
256
275
|
style={padding}
|
|
257
|
-
|
|
276
|
+
onScroll={handleScroll}
|
|
258
277
|
>
|
|
259
|
-
{active.map((entryId
|
|
278
|
+
{active.map((entryId) => (
|
|
260
279
|
<Fragment key={entryId}>
|
|
261
|
-
<PlankSeparator
|
|
262
|
-
<Plank
|
|
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
|
+
/>
|
|
263
290
|
</Fragment>
|
|
264
291
|
))}
|
|
265
292
|
</Stack>
|
|
@@ -272,15 +299,23 @@ export const DeckLayout = ({ overscroll, showHints, onDismissToast }: DeckLayout
|
|
|
272
299
|
{!topbar && <ToggleSidebarButton classNames={fixedSidebarToggleStyles} />}
|
|
273
300
|
{!topbar && <ToggleComplementarySidebarButton classNames={fixedComplementarySidebarToggleStyles} />}
|
|
274
301
|
<StackContext.Provider value={{ size: 'contain', orientation: 'horizontal', rail: true }}>
|
|
275
|
-
<Plank
|
|
302
|
+
<Plank
|
|
303
|
+
id={solo}
|
|
304
|
+
companionId={solo ? activeCompanions?.[solo] : undefined}
|
|
305
|
+
part='solo'
|
|
306
|
+
layoutMode={layoutMode}
|
|
307
|
+
settings={settings}
|
|
308
|
+
/>
|
|
276
309
|
</StackContext.Provider>
|
|
277
310
|
</div>
|
|
278
311
|
</Main.Content>
|
|
279
312
|
)}
|
|
280
313
|
|
|
281
|
-
{/*
|
|
314
|
+
{/* Topbar. */}
|
|
282
315
|
{topbar && <Topbar />}
|
|
283
|
-
|
|
316
|
+
|
|
317
|
+
{/* Status bar. */}
|
|
318
|
+
{hoistStatusbar && <StatusBar showHints={settings.showHints} />}
|
|
284
319
|
</Main.Root>
|
|
285
320
|
)}
|
|
286
321
|
|
|
@@ -303,10 +338,11 @@ export const DeckLayout = ({ overscroll, showHints, onDismissToast }: DeckLayout
|
|
|
303
338
|
onOpenChange={(nextOpen) => (context.dialogOpen = nextOpen)}
|
|
304
339
|
>
|
|
305
340
|
{dialogBlockAlign === 'end' ? (
|
|
306
|
-
|
|
341
|
+
// TODO(burdon): Placeholder creates a suspense boundary; replace with defaults.
|
|
342
|
+
<Surface role='dialog' data={dialogContent} limit={1} fallback={PlankContentError} placeholder={<div />} />
|
|
307
343
|
) : (
|
|
308
344
|
<Dialog.Overlay blockAlign={dialogBlockAlign}>
|
|
309
|
-
<Surface role='dialog' data={dialogContent} limit={1} />
|
|
345
|
+
<Surface role='dialog' data={dialogContent} limit={1} fallback={PlankContentError} />
|
|
310
346
|
</Dialog.Overlay>
|
|
311
347
|
)}
|
|
312
348
|
</Dialog.Root>
|
|
@@ -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();
|
|
@@ -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 '
|
|
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 '
|
|
17
|
+
} from '../../types';
|
|
18
18
|
|
|
19
19
|
const isSocket = !!(globalThis as any).__args;
|
|
20
20
|
|
|
21
|
-
export const
|
|
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,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
|
+
};
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2024 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import React, {
|
|
6
|
+
Fragment,
|
|
7
|
+
type KeyboardEvent,
|
|
8
|
+
type PropsWithChildren,
|
|
9
|
+
memo,
|
|
10
|
+
useCallback,
|
|
11
|
+
useLayoutEffect,
|
|
12
|
+
useMemo,
|
|
13
|
+
useRef,
|
|
14
|
+
} from 'react';
|
|
15
|
+
|
|
16
|
+
import {
|
|
17
|
+
LayoutAction,
|
|
18
|
+
Surface,
|
|
19
|
+
createIntent,
|
|
20
|
+
useCapability,
|
|
21
|
+
useAppGraph,
|
|
22
|
+
useIntentDispatcher,
|
|
23
|
+
} from '@dxos/app-framework';
|
|
24
|
+
import { debounce } from '@dxos/async';
|
|
25
|
+
import { useNode, type Node } from '@dxos/plugin-graph';
|
|
26
|
+
import { ATTENDABLE_PATH_SEPARATOR, useAttendableAttributes } from '@dxos/react-ui-attention';
|
|
27
|
+
import { StackItem, railGridHorizontal } from '@dxos/react-ui-stack';
|
|
28
|
+
import { mainIntrinsicSize, mx } from '@dxos/react-ui-theme';
|
|
29
|
+
|
|
30
|
+
import { PlankContentError, PlankError } from './PlankError';
|
|
31
|
+
import { PlankHeading } from './PlankHeading';
|
|
32
|
+
import { PlankLoading } from './PlankLoading';
|
|
33
|
+
import { DeckCapabilities } from '../../capabilities';
|
|
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';
|
|
38
|
+
|
|
39
|
+
const UNKNOWN_ID = 'unknown_id';
|
|
40
|
+
|
|
41
|
+
export type PlankProps = {
|
|
42
|
+
id?: string;
|
|
43
|
+
companionId?: string;
|
|
44
|
+
part: Part;
|
|
45
|
+
path?: string[];
|
|
46
|
+
order?: number;
|
|
47
|
+
active?: string[];
|
|
48
|
+
layoutMode: LayoutMode;
|
|
49
|
+
settings?: DeckSettingsProps;
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
type PlankImplProps = Omit<PlankProps, 'id' | 'companionId' | 'part'> & {
|
|
53
|
+
id: string;
|
|
54
|
+
part: ResolvedPart;
|
|
55
|
+
node?: Node;
|
|
56
|
+
companioned?: 'primary' | 'companion';
|
|
57
|
+
primary?: Node;
|
|
58
|
+
companions?: Node[];
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
const PlankImpl = memo(
|
|
62
|
+
({ id, node, part, path, order, active, layoutMode, companioned, primary, companions, settings }: PlankImplProps) => {
|
|
63
|
+
const { dispatchPromise: dispatch } = useIntentDispatcher();
|
|
64
|
+
const { deck, popoverAnchorId, scrollIntoView } = useCapability(DeckCapabilities.DeckState);
|
|
65
|
+
const rootElement = useRef<HTMLDivElement | null>(null);
|
|
66
|
+
const canResize = layoutMode === 'deck';
|
|
67
|
+
const Root = part.startsWith('solo') ? 'article' : StackItem.Root;
|
|
68
|
+
|
|
69
|
+
const attendableAttrs = useAttendableAttributes(primary?.id ?? id);
|
|
70
|
+
const index = active ? active.findIndex((entryId) => entryId === id) : 0;
|
|
71
|
+
const length = active?.length ?? 1;
|
|
72
|
+
const canIncrementStart = active && index !== undefined && index > 0 && length !== undefined && length > 1;
|
|
73
|
+
const canIncrementEnd = active && index !== undefined && index < length - 1 && length !== undefined;
|
|
74
|
+
|
|
75
|
+
const { variant } = parseEntryId(id);
|
|
76
|
+
const sizeKey = `${id.split('+')[0]}${variant ? `${ATTENDABLE_PATH_SEPARATOR}${variant}` : ''}`;
|
|
77
|
+
const size = deck.plankSizing[sizeKey] as number | undefined;
|
|
78
|
+
const setSize = useCallback(
|
|
79
|
+
debounce((nextSize: number) => {
|
|
80
|
+
return dispatch(createIntent(DeckAction.UpdatePlankSize, { id: sizeKey, size: nextSize }));
|
|
81
|
+
}, 200),
|
|
82
|
+
[dispatch, sizeKey],
|
|
83
|
+
);
|
|
84
|
+
|
|
85
|
+
// TODO(thure): Tabster’s focus group should handle moving focus to Main, but something is blocking it.
|
|
86
|
+
const handleKeyDown = useCallback((event: KeyboardEvent) => {
|
|
87
|
+
if (event.target === event.currentTarget && event.key === 'Escape') {
|
|
88
|
+
rootElement.current?.closest('main')?.focus();
|
|
89
|
+
}
|
|
90
|
+
}, []);
|
|
91
|
+
|
|
92
|
+
useLayoutEffect(() => {
|
|
93
|
+
if (scrollIntoView === id) {
|
|
94
|
+
// TODO(wittjosiah): When focused on page load, the focus is always visible.
|
|
95
|
+
// Forcing focus to something smaller than the plank prevents large focus ring in the interim.
|
|
96
|
+
const focusable = rootElement.current?.querySelector('button') || rootElement.current;
|
|
97
|
+
focusable?.focus({ preventScroll: true });
|
|
98
|
+
layoutMode === 'deck' && focusable?.scrollIntoView({ behavior: 'smooth', inline: 'center' });
|
|
99
|
+
// Clear the scroll into view state once it has been actioned.
|
|
100
|
+
void dispatch(createIntent(LayoutAction.ScrollIntoView, { part: 'current', subject: undefined }));
|
|
101
|
+
}
|
|
102
|
+
}, [id, scrollIntoView, layoutMode]);
|
|
103
|
+
|
|
104
|
+
const isSolo = layoutMode === 'solo' && part === 'solo';
|
|
105
|
+
const isAttendable =
|
|
106
|
+
(layoutMode === 'solo' && part.startsWith('solo')) || (layoutMode === 'deck' && part === 'deck');
|
|
107
|
+
|
|
108
|
+
const sizeAttrs = useMainSize();
|
|
109
|
+
|
|
110
|
+
const data = useMemo(
|
|
111
|
+
() =>
|
|
112
|
+
node && {
|
|
113
|
+
subject: node.data,
|
|
114
|
+
companionTo: primary?.data,
|
|
115
|
+
variant,
|
|
116
|
+
path,
|
|
117
|
+
popoverAnchorId,
|
|
118
|
+
},
|
|
119
|
+
[node, node?.data, path, popoverAnchorId, primary?.data],
|
|
120
|
+
);
|
|
121
|
+
|
|
122
|
+
// TODO(wittjosiah): Change prop to accept a component.
|
|
123
|
+
const placeholder = useMemo(() => <PlankLoading />, []);
|
|
124
|
+
|
|
125
|
+
const className = mx(
|
|
126
|
+
'attention-surface relative',
|
|
127
|
+
isSolo && mainIntrinsicSize,
|
|
128
|
+
isSolo && railGridHorizontal,
|
|
129
|
+
isSolo && 'absolute inset-0',
|
|
130
|
+
part.startsWith('solo') && 'grid',
|
|
131
|
+
part === 'deck' && (companioned === 'companion' ? '!border-separator border-ie' : '!border-separator border-li'),
|
|
132
|
+
part.startsWith('solo-') && 'row-span-2 grid-rows-subgrid min-is-0',
|
|
133
|
+
part === 'solo-companion' && '!border-separator border-is',
|
|
134
|
+
);
|
|
135
|
+
|
|
136
|
+
return (
|
|
137
|
+
<Root
|
|
138
|
+
ref={rootElement}
|
|
139
|
+
data-testid='deck.plank'
|
|
140
|
+
tabIndex={0}
|
|
141
|
+
{...(part.startsWith('solo')
|
|
142
|
+
? ({ ...sizeAttrs, className } as any)
|
|
143
|
+
: {
|
|
144
|
+
item: { id },
|
|
145
|
+
size,
|
|
146
|
+
onSizeChange: setSize,
|
|
147
|
+
classNames: className,
|
|
148
|
+
order,
|
|
149
|
+
role: 'article',
|
|
150
|
+
})}
|
|
151
|
+
{...(isAttendable ? attendableAttrs : {})}
|
|
152
|
+
onKeyDown={handleKeyDown}
|
|
153
|
+
>
|
|
154
|
+
{node ? (
|
|
155
|
+
<>
|
|
156
|
+
<PlankHeading
|
|
157
|
+
id={id}
|
|
158
|
+
part={part.startsWith('solo-') ? 'solo' : part}
|
|
159
|
+
node={node}
|
|
160
|
+
deckEnabled={settings?.enableDeck}
|
|
161
|
+
canIncrementStart={canIncrementStart}
|
|
162
|
+
canIncrementEnd={canIncrementEnd}
|
|
163
|
+
popoverAnchorId={popoverAnchorId}
|
|
164
|
+
primaryId={primary?.id}
|
|
165
|
+
companioned={companioned}
|
|
166
|
+
companions={companions}
|
|
167
|
+
/>
|
|
168
|
+
<Surface
|
|
169
|
+
key={node.id}
|
|
170
|
+
role='article'
|
|
171
|
+
data={data}
|
|
172
|
+
limit={1}
|
|
173
|
+
fallback={PlankContentError}
|
|
174
|
+
placeholder={placeholder}
|
|
175
|
+
/>
|
|
176
|
+
</>
|
|
177
|
+
) : (
|
|
178
|
+
<PlankError id={id} part={part} />
|
|
179
|
+
)}
|
|
180
|
+
{canResize && <StackItem.ResizeHandle />}
|
|
181
|
+
</Root>
|
|
182
|
+
);
|
|
183
|
+
},
|
|
184
|
+
);
|
|
185
|
+
|
|
186
|
+
const SplitFrame = ({ children }: PropsWithChildren<{}>) => {
|
|
187
|
+
const sizeAttrs = useMainSize();
|
|
188
|
+
return (
|
|
189
|
+
<div
|
|
190
|
+
role='none'
|
|
191
|
+
className={mx('grid grid-cols-[1fr_1fr] absolute inset-0', railGridHorizontal, mainIntrinsicSize)}
|
|
192
|
+
{...sizeAttrs}
|
|
193
|
+
>
|
|
194
|
+
{children}
|
|
195
|
+
</div>
|
|
196
|
+
);
|
|
197
|
+
};
|
|
198
|
+
|
|
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
|
+
|
|
205
|
+
if (props.companionId) {
|
|
206
|
+
const Root = props.part === 'solo' ? SplitFrame : Fragment;
|
|
207
|
+
return (
|
|
208
|
+
<Root>
|
|
209
|
+
<PlankImpl
|
|
210
|
+
id={id}
|
|
211
|
+
node={node}
|
|
212
|
+
companioned='primary'
|
|
213
|
+
{...props}
|
|
214
|
+
{...(props.part === 'solo' ? { part: 'solo-primary' } : {})}
|
|
215
|
+
/>
|
|
216
|
+
<PlankImpl
|
|
217
|
+
id={props.companionId}
|
|
218
|
+
node={currentCompanion}
|
|
219
|
+
companioned='companion'
|
|
220
|
+
primary={node}
|
|
221
|
+
companions={companions}
|
|
222
|
+
{...props}
|
|
223
|
+
{...(props.part === 'solo' ? { part: 'solo-companion' } : { order: props.order! + 1 })}
|
|
224
|
+
/>
|
|
225
|
+
</Root>
|
|
226
|
+
);
|
|
227
|
+
} else {
|
|
228
|
+
return <PlankImpl id={id} node={node} companions={companions} {...props} />;
|
|
229
|
+
}
|
|
230
|
+
};
|