@dxos/plugin-deck 0.7.5-main.9d26e3a → 0.7.5-main.e9bb01b
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-CI6ZFMNL.mjs +147 -0
- package/dist/lib/browser/app-graph-builder-CI6ZFMNL.mjs.map +7 -0
- package/dist/lib/browser/check-app-scheme-S3EYUPMF.mjs +33 -0
- package/dist/lib/browser/check-app-scheme-S3EYUPMF.mjs.map +7 -0
- package/dist/lib/browser/chunk-M2L53AIH.mjs +126 -0
- package/dist/lib/browser/chunk-M2L53AIH.mjs.map +7 -0
- package/dist/lib/browser/{chunk-GVOGPULO.mjs → chunk-N7TEPFVR.mjs} +5 -4
- package/dist/lib/browser/chunk-N7TEPFVR.mjs.map +7 -0
- package/dist/lib/browser/chunk-NYZJCVAU.mjs +22 -0
- package/dist/lib/browser/chunk-NYZJCVAU.mjs.map +7 -0
- package/dist/lib/browser/chunk-WXNLVMK2.mjs +1119 -0
- package/dist/lib/browser/chunk-WXNLVMK2.mjs.map +7 -0
- package/dist/lib/browser/chunk-YQ2GWTDU.mjs +17 -0
- package/dist/lib/browser/chunk-YQ2GWTDU.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +90 -1775
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/intent-resolver-CSXFDKTC.mjs +494 -0
- package/dist/lib/browser/intent-resolver-CSXFDKTC.mjs.map +7 -0
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/react-root-ECDQZYQT.mjs +46 -0
- package/dist/lib/browser/react-root-ECDQZYQT.mjs.map +7 -0
- package/dist/lib/browser/react-surface-4WIQZW2S.mjs +38 -0
- package/dist/lib/browser/react-surface-4WIQZW2S.mjs.map +7 -0
- package/dist/lib/browser/settings-WACNLCPB.mjs +28 -0
- package/dist/lib/browser/settings-WACNLCPB.mjs.map +7 -0
- package/dist/lib/browser/state-VPOYUKK6.mjs +117 -0
- package/dist/lib/browser/state-VPOYUKK6.mjs.map +7 -0
- package/dist/lib/browser/types.mjs +16 -4
- package/dist/lib/browser/url-handler-HLF42IHP.mjs +70 -0
- package/dist/lib/browser/url-handler-HLF42IHP.mjs.map +7 -0
- package/dist/types/src/DeckPlugin.d.ts +1 -5
- package/dist/types/src/DeckPlugin.d.ts.map +1 -1
- package/dist/types/src/capabilities/app-graph-builder.d.ts +181 -0
- package/dist/types/src/capabilities/app-graph-builder.d.ts.map +1 -0
- package/dist/types/src/capabilities/capabilities.d.ts +142 -0
- package/dist/types/src/capabilities/capabilities.d.ts.map +1 -0
- package/dist/types/src/capabilities/check-app-scheme.d.ts +4 -0
- package/dist/types/src/capabilities/check-app-scheme.d.ts.map +1 -0
- package/dist/types/src/capabilities/index.d.ts +189 -0
- package/dist/types/src/capabilities/index.d.ts.map +1 -0
- package/dist/types/src/capabilities/intent-resolver.d.ts +4 -0
- package/dist/types/src/capabilities/intent-resolver.d.ts.map +1 -0
- package/dist/types/src/capabilities/react-root.d.ts +7 -0
- package/dist/types/src/capabilities/react-root.d.ts.map +1 -0
- package/dist/types/src/capabilities/react-surface.d.ts +4 -0
- package/dist/types/src/capabilities/react-surface.d.ts.map +1 -0
- package/dist/types/src/capabilities/set-active.d.ts +9 -0
- package/dist/types/src/capabilities/set-active.d.ts.map +1 -0
- package/dist/types/src/capabilities/settings.d.ts +4 -0
- package/dist/types/src/capabilities/settings.d.ts.map +1 -0
- package/dist/types/src/capabilities/state.d.ts +76 -0
- package/dist/types/src/capabilities/state.d.ts.map +1 -0
- package/dist/types/src/capabilities/url-handler.d.ts +4 -0
- package/dist/types/src/capabilities/url-handler.d.ts.map +1 -0
- package/dist/types/src/components/DeckLayout/ActiveNode.d.ts.map +1 -1
- package/dist/types/src/components/DeckLayout/Banner.d.ts +6 -0
- package/dist/types/src/components/DeckLayout/Banner.d.ts.map +1 -0
- package/dist/types/src/components/DeckLayout/ComplementarySidebar.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 +1 -4
- package/dist/types/src/components/DeckLayout/DeckLayout.d.ts.map +1 -1
- package/dist/types/src/components/DeckLayout/Fullscreen.d.ts.map +1 -1
- package/dist/types/src/components/DeckLayout/NodePlankHeading.d.ts +3 -3
- package/dist/types/src/components/DeckLayout/NodePlankHeading.d.ts.map +1 -1
- package/dist/types/src/components/DeckLayout/Plank.d.ts +8 -6
- package/dist/types/src/components/DeckLayout/Plank.d.ts.map +1 -1
- package/dist/types/src/components/DeckLayout/PlankControls.d.ts +2 -2
- package/dist/types/src/components/DeckLayout/PlankControls.d.ts.map +1 -1
- package/dist/types/src/components/DeckLayout/PlankError.d.ts +4 -3
- package/dist/types/src/components/DeckLayout/PlankError.d.ts.map +1 -1
- package/dist/types/src/components/DeckLayout/Sidebar.d.ts +1 -5
- package/dist/types/src/components/DeckLayout/Sidebar.d.ts.map +1 -1
- package/dist/types/src/components/DeckLayout/SidebarButton.d.ts +8 -0
- package/dist/types/src/components/DeckLayout/SidebarButton.d.ts.map +1 -0
- package/dist/types/src/components/DeckLayout/StatusBar.d.ts.map +1 -1
- package/dist/types/src/components/DeckLayout/Toast.d.ts +2 -2
- package/dist/types/src/components/DeckLayout/Toast.d.ts.map +1 -1
- package/dist/types/src/components/DeckLayout/Topbar.d.ts +3 -0
- package/dist/types/src/components/DeckLayout/Topbar.d.ts.map +1 -0
- package/dist/types/src/components/fragments.d.ts +4 -0
- package/dist/types/src/components/fragments.d.ts.map +1 -0
- package/dist/types/src/components/index.d.ts +0 -2
- package/dist/types/src/components/index.d.ts.map +1 -1
- package/dist/types/src/events.d.ts +4 -0
- package/dist/types/src/events.d.ts.map +1 -0
- package/dist/types/src/hooks/useMainSize.d.ts +2 -2
- package/dist/types/src/index.d.ts +3 -2
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/layout.d.ts +5 -19
- package/dist/types/src/layout.d.ts.map +1 -1
- package/dist/types/src/meta.d.ts +4 -4
- package/dist/types/src/meta.d.ts.map +1 -1
- package/dist/types/src/translations.d.ts +4 -2
- package/dist/types/src/translations.d.ts.map +1 -1
- package/dist/types/src/types.d.ts +117 -20
- package/dist/types/src/types.d.ts.map +1 -1
- package/dist/types/src/util/index.d.ts +3 -2
- package/dist/types/src/util/index.d.ts.map +1 -1
- package/dist/types/src/util/layoutAppliesTopbar.d.ts +2 -0
- package/dist/types/src/util/layoutAppliesTopbar.d.ts.map +1 -0
- package/dist/types/src/util/useBreakpoints.d.ts +2 -0
- package/dist/types/src/util/useBreakpoints.d.ts.map +1 -0
- package/dist/types/src/util/useHoistStatusbar.d.ts +2 -0
- package/dist/types/src/util/useHoistStatusbar.d.ts.map +1 -0
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +30 -36
- package/src/DeckPlugin.ts +77 -0
- package/src/capabilities/app-graph-builder.ts +109 -0
- package/src/capabilities/capabilities.ts +18 -0
- package/src/capabilities/check-app-scheme.ts +44 -0
- package/src/capabilities/index.ts +16 -0
- package/src/capabilities/intent-resolver.ts +350 -0
- package/src/capabilities/react-root.tsx +48 -0
- package/src/capabilities/react-surface.tsx +31 -0
- package/src/capabilities/set-active.ts +43 -0
- package/src/capabilities/settings.ts +21 -0
- package/src/capabilities/state.ts +102 -0
- package/src/capabilities/url-handler.ts +63 -0
- package/src/components/DeckLayout/ActiveNode.tsx +2 -3
- package/src/components/DeckLayout/Banner.tsx +37 -0
- package/src/components/DeckLayout/ComplementarySidebar.tsx +128 -55
- package/src/components/DeckLayout/ContentEmpty.tsx +9 -4
- package/src/components/DeckLayout/DeckLayout.tsx +113 -76
- package/src/components/DeckLayout/Fullscreen.tsx +2 -3
- package/src/components/DeckLayout/NodePlankHeading.tsx +64 -77
- package/src/components/DeckLayout/Plank.tsx +34 -43
- package/src/components/DeckLayout/PlankControls.tsx +11 -10
- package/src/components/DeckLayout/PlankError.tsx +6 -5
- package/src/components/DeckLayout/Sidebar.tsx +19 -9
- package/src/components/DeckLayout/SidebarButton.tsx +68 -0
- package/src/components/DeckLayout/StatusBar.tsx +6 -12
- package/src/components/DeckLayout/Toast.tsx +2 -2
- package/src/components/DeckLayout/Topbar.tsx +11 -0
- package/src/components/LayoutSettings.tsx +8 -8
- package/src/components/fragments.ts +14 -0
- package/src/components/index.ts +0 -2
- package/src/events.ts +11 -0
- package/src/hooks/useMainSize.ts +3 -3
- package/src/index.ts +3 -4
- package/src/layout.ts +43 -212
- package/src/meta.ts +3 -2
- package/src/translations.ts +8 -6
- package/src/types.ts +95 -34
- package/src/util/index.ts +3 -2
- package/src/util/layoutAppliesTopbar.ts +7 -0
- package/src/util/useBreakpoints.ts +11 -0
- package/src/util/useHoistStatusbar.ts +24 -0
- package/dist/lib/browser/chunk-GVOGPULO.mjs.map +0 -7
- package/dist/lib/browser/chunk-ZC3K6C2W.mjs +0 -37
- package/dist/lib/browser/chunk-ZC3K6C2W.mjs.map +0 -7
- package/dist/lib/browser/meta.mjs +0 -9
- package/dist/lib/browser/meta.mjs.map +0 -7
- package/dist/types/src/components/DeckContext.d.ts +0 -8
- package/dist/types/src/components/DeckContext.d.ts.map +0 -1
- package/dist/types/src/components/LayoutContext.d.ts +0 -5
- package/dist/types/src/components/LayoutContext.d.ts.map +0 -1
- package/dist/types/src/layout.test.d.ts +0 -2
- package/dist/types/src/layout.test.d.ts.map +0 -1
- package/dist/types/src/util/check-app-scheme.d.ts +0 -2
- package/dist/types/src/util/check-app-scheme.d.ts.map +0 -1
- package/dist/types/src/util/layout-parts.d.ts +0 -7
- package/dist/types/src/util/layout-parts.d.ts.map +0 -1
- package/src/DeckPlugin.tsx +0 -623
- package/src/components/DeckContext.ts +0 -14
- package/src/components/LayoutContext.ts +0 -12
- package/src/layout.test.ts +0 -380
- package/src/util/check-app-scheme.ts +0 -21
- package/src/util/layout-parts.ts +0 -12
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2025 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import React from 'react';
|
|
6
|
+
|
|
7
|
+
import { Surface } from '@dxos/app-framework';
|
|
8
|
+
import { type ThemedClassName } from '@dxos/react-ui';
|
|
9
|
+
import { mx } from '@dxos/react-ui-theme';
|
|
10
|
+
|
|
11
|
+
import { CloseSidebarButton, ToggleSidebarButton } from './SidebarButton';
|
|
12
|
+
|
|
13
|
+
export const Banner = ({ variant, classNames }: ThemedClassName<{ variant?: 'topbar' | 'sidebar' }>) => {
|
|
14
|
+
return (
|
|
15
|
+
<header
|
|
16
|
+
className={mx(
|
|
17
|
+
'flex items-stretch relative plb-1 pis-1 pie-2',
|
|
18
|
+
variant === 'topbar' &&
|
|
19
|
+
'fixed inset-inline-0 block-start-[env(safe-area-inset-top)] bs-[--rail-size] border-be border-separator',
|
|
20
|
+
classNames,
|
|
21
|
+
)}
|
|
22
|
+
>
|
|
23
|
+
{variant === 'sidebar' ? <CloseSidebarButton /> : <ToggleSidebarButton />}
|
|
24
|
+
<span className='self-center grow mis-1'>Composer</span>
|
|
25
|
+
{variant === 'topbar' && (
|
|
26
|
+
<div role='none' className='absolute inset-0 pointer-events-none'>
|
|
27
|
+
<div role='none' className='grid bs-full pointer-fine:p-1 max-is-md mli-auto pointer-events-auto'>
|
|
28
|
+
<Surface role='search-input' limit={1} />
|
|
29
|
+
</div>
|
|
30
|
+
</div>
|
|
31
|
+
)}
|
|
32
|
+
<span role='none' className='grow' />
|
|
33
|
+
<Surface role='header-end' limit={1} />
|
|
34
|
+
<Surface role='notch-start' limit={1} />
|
|
35
|
+
</header>
|
|
36
|
+
);
|
|
37
|
+
};
|
|
@@ -2,28 +2,28 @@
|
|
|
2
2
|
// Copyright 2024 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import React, { useMemo } from 'react';
|
|
5
|
+
import React, { useCallback, useEffect, useMemo, useState, type MouseEvent } from 'react';
|
|
6
6
|
|
|
7
7
|
import {
|
|
8
8
|
createIntent,
|
|
9
|
-
|
|
10
|
-
NavigationAction,
|
|
11
|
-
SLUG_PATH_SEPARATOR,
|
|
9
|
+
LayoutAction,
|
|
12
10
|
Surface,
|
|
11
|
+
useAppGraph,
|
|
12
|
+
useCapability,
|
|
13
13
|
useIntentDispatcher,
|
|
14
14
|
} from '@dxos/app-framework';
|
|
15
|
-
import {
|
|
16
|
-
import { Main, ScrollArea } from '@dxos/react-ui';
|
|
15
|
+
import { Main, useTranslation, toLocalizedString, IconButton, ScrollArea } from '@dxos/react-ui';
|
|
17
16
|
import { useAttended } from '@dxos/react-ui-attention';
|
|
18
|
-
import {
|
|
19
|
-
import { mx } from '@dxos/react-ui-theme';
|
|
17
|
+
import { Tabs } from '@dxos/react-ui-tabs';
|
|
20
18
|
|
|
21
|
-
import { NodePlankHeading } from './NodePlankHeading';
|
|
22
19
|
import { PlankContentError } from './PlankError';
|
|
23
20
|
import { PlankLoading } from './PlankLoading';
|
|
21
|
+
import { ToggleComplementarySidebarButton } from './SidebarButton';
|
|
22
|
+
import { DeckCapabilities } from '../../capabilities';
|
|
24
23
|
import { useNode, useNodeActionExpander } from '../../hooks';
|
|
25
|
-
import {
|
|
26
|
-
import {
|
|
24
|
+
import { DECK_PLUGIN } from '../../meta';
|
|
25
|
+
import { SLUG_PATH_SEPARATOR, type Panel } from '../../types';
|
|
26
|
+
import { layoutAppliesTopbar, useBreakpoints, useHoistStatusbar } from '../../util';
|
|
27
27
|
|
|
28
28
|
export type ComplementarySidebarProps = {
|
|
29
29
|
panels: Panel[];
|
|
@@ -31,60 +31,133 @@ export type ComplementarySidebarProps = {
|
|
|
31
31
|
};
|
|
32
32
|
|
|
33
33
|
export const ComplementarySidebar = ({ panels, current }: ComplementarySidebarProps) => {
|
|
34
|
-
const
|
|
34
|
+
const layout = useCapability(DeckCapabilities.MutableDeckState);
|
|
35
35
|
const attended = useAttended();
|
|
36
|
-
const
|
|
37
|
-
const
|
|
38
|
-
const
|
|
39
|
-
const
|
|
36
|
+
const panelIds = useMemo(() => panels.map((p) => p.id), [panels]);
|
|
37
|
+
const activePanelId = panelIds.find((p) => p === current) ?? panels[0].id;
|
|
38
|
+
const activeEntryId = attended[0] ? `${attended[0]}${SLUG_PATH_SEPARATOR}${activePanelId}` : undefined;
|
|
39
|
+
const { graph } = useAppGraph();
|
|
40
|
+
const node = useNode(graph, activeEntryId);
|
|
41
|
+
const { t } = useTranslation(DECK_PLUGIN);
|
|
40
42
|
const { dispatchPromise: dispatch } = useIntentDispatcher();
|
|
41
43
|
useNodeActionExpander(node);
|
|
44
|
+
const breakpoint = useBreakpoints();
|
|
45
|
+
const topbar = layoutAppliesTopbar(breakpoint);
|
|
46
|
+
const hoistStatusbar = useHoistStatusbar(breakpoint);
|
|
42
47
|
|
|
43
|
-
const
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
void dispatch(createIntent(NavigationAction.Open, { activeParts: { complementary: id } }));
|
|
49
|
-
},
|
|
50
|
-
properties: {
|
|
51
|
-
label,
|
|
52
|
-
icon,
|
|
53
|
-
menuItemType: 'toggle',
|
|
54
|
-
isChecked: panel === id,
|
|
55
|
-
},
|
|
56
|
-
})),
|
|
57
|
-
[panel],
|
|
58
|
-
);
|
|
48
|
+
const [internalValue, setInternalValue] = useState(activePanelId);
|
|
49
|
+
|
|
50
|
+
useEffect(() => {
|
|
51
|
+
setInternalValue(activePanelId);
|
|
52
|
+
}, [activePanelId]);
|
|
59
53
|
|
|
60
|
-
|
|
61
|
-
|
|
54
|
+
const handleTabClick = useCallback(
|
|
55
|
+
(event: MouseEvent) => {
|
|
56
|
+
const nextValue = event.currentTarget.getAttribute('data-value') as string;
|
|
57
|
+
if (nextValue === activePanelId) {
|
|
58
|
+
layout.complementarySidebarState = layout.complementarySidebarState === 'expanded' ? 'collapsed' : 'expanded';
|
|
59
|
+
} else {
|
|
60
|
+
setInternalValue(nextValue);
|
|
61
|
+
layout.complementarySidebarState = 'expanded';
|
|
62
|
+
void dispatch(createIntent(LayoutAction.UpdateComplementary, { part: 'complementary', subject: nextValue }));
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
[layout, activePanelId, dispatch],
|
|
66
|
+
);
|
|
62
67
|
|
|
63
68
|
// TODO(burdon): Scroll area should be controlled by surface.
|
|
64
69
|
return (
|
|
65
|
-
<Main.ComplementarySidebar
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
70
|
+
<Main.ComplementarySidebar
|
|
71
|
+
classNames={[
|
|
72
|
+
topbar && 'block-start-[calc(env(safe-area-inset-top)+var(--rail-size))]',
|
|
73
|
+
hoistStatusbar && 'block-end-[--statusbar-size]',
|
|
74
|
+
]}
|
|
75
|
+
>
|
|
76
|
+
<Tabs.Root
|
|
77
|
+
orientation='vertical'
|
|
78
|
+
verticalVariant='stateless'
|
|
79
|
+
value={internalValue}
|
|
80
|
+
attendableId={attended[0]}
|
|
81
|
+
classNames='contents'
|
|
82
|
+
>
|
|
83
|
+
<div
|
|
84
|
+
role='none'
|
|
85
|
+
className='absolute z-[1] inset-block-0 inline-end-0 !is-[--r0-size] border-is border-separator grid grid-cols-1 grid-rows-[1fr_min-content] bg-baseSurface contain-layout app-drag'
|
|
86
|
+
>
|
|
87
|
+
<Tabs.Tablist classNames='grid grid-cols-1 auto-rows-[--rail-action] p-1 gap-1 !overflow-y-auto'>
|
|
88
|
+
{panels.map((panel) => (
|
|
89
|
+
<Tabs.Tab key={panel.id} value={panel.id} asChild>
|
|
90
|
+
<IconButton
|
|
91
|
+
label={toLocalizedString(panel.label, t)}
|
|
92
|
+
icon={panel.icon}
|
|
93
|
+
size={5}
|
|
94
|
+
iconOnly
|
|
95
|
+
tooltipSide='left'
|
|
96
|
+
data-value={panel.id}
|
|
97
|
+
variant={
|
|
98
|
+
activePanelId === panel.id
|
|
99
|
+
? layout.complementarySidebarState === 'expanded'
|
|
100
|
+
? 'primary'
|
|
101
|
+
: 'default'
|
|
102
|
+
: 'ghost'
|
|
103
|
+
}
|
|
104
|
+
onClick={handleTabClick}
|
|
79
105
|
/>
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
106
|
+
</Tabs.Tab>
|
|
107
|
+
))}
|
|
108
|
+
</Tabs.Tablist>
|
|
109
|
+
{!hoistStatusbar && (
|
|
110
|
+
<div role='none' className='grid grid-cols-1 auto-rows-[--rail-item] p-1 overflow-y-auto'>
|
|
111
|
+
<Surface role='status-bar--r0-footer' limit={1} />
|
|
112
|
+
</div>
|
|
113
|
+
)}
|
|
114
|
+
<div role='none' className='hidden lg:grid grid-cols-1 auto-rows-[--rail-action] p-1'>
|
|
115
|
+
<ToggleComplementarySidebarButton />
|
|
116
|
+
</div>
|
|
86
117
|
</div>
|
|
87
|
-
|
|
118
|
+
{panels.map((panel) => (
|
|
119
|
+
<Tabs.Tabpanel
|
|
120
|
+
key={panel.id}
|
|
121
|
+
value={panel.id}
|
|
122
|
+
classNames='absolute data-[state="inactive"]:-z-[1] inset-block-0 inline-start-0 is-[calc(100%-var(--r0-size))] lg:is-[--r1-size] grid grid-cols-1 grid-rows-[var(--rail-size)_1fr_min-content]'
|
|
123
|
+
{...(layout.complementarySidebarState !== 'expanded' && { inert: 'true' })}
|
|
124
|
+
>
|
|
125
|
+
{panel.id === activePanelId && node && (
|
|
126
|
+
<>
|
|
127
|
+
<h2 className='flex items-center pli-2 border-separator border-be'>
|
|
128
|
+
{toLocalizedString(panel.label, t)}
|
|
129
|
+
</h2>
|
|
130
|
+
<ScrollArea.Root>
|
|
131
|
+
<ScrollArea.Viewport>
|
|
132
|
+
<Surface
|
|
133
|
+
key={activeEntryId}
|
|
134
|
+
role={`complementary--${activePanelId}`}
|
|
135
|
+
data={{
|
|
136
|
+
id: activeEntryId,
|
|
137
|
+
subject: node.properties.object ?? node.properties.space,
|
|
138
|
+
popoverAnchorId: layout.popoverAnchorId,
|
|
139
|
+
}}
|
|
140
|
+
fallback={PlankContentError}
|
|
141
|
+
placeholder={<PlankLoading />}
|
|
142
|
+
/>
|
|
143
|
+
</ScrollArea.Viewport>
|
|
144
|
+
<ScrollArea.Scrollbar orientation='vertical'>
|
|
145
|
+
<ScrollArea.Thumb />
|
|
146
|
+
</ScrollArea.Scrollbar>
|
|
147
|
+
</ScrollArea.Root>
|
|
148
|
+
{!hoistStatusbar && (
|
|
149
|
+
<div
|
|
150
|
+
role='contentinfo'
|
|
151
|
+
className='flex flex-wrap justify-center items-center border-bs border-separator plb-1'
|
|
152
|
+
>
|
|
153
|
+
<Surface role='status-bar--r1-footer' limit={1} />
|
|
154
|
+
</div>
|
|
155
|
+
)}
|
|
156
|
+
</>
|
|
157
|
+
)}
|
|
158
|
+
</Tabs.Tabpanel>
|
|
159
|
+
))}
|
|
160
|
+
</Tabs.Root>
|
|
88
161
|
</Main.ComplementarySidebar>
|
|
89
162
|
);
|
|
90
163
|
};
|
|
@@ -6,16 +6,21 @@ import React from 'react';
|
|
|
6
6
|
|
|
7
7
|
import { Surface } from '@dxos/app-framework';
|
|
8
8
|
|
|
9
|
+
import { ToggleSidebarButton } from './SidebarButton';
|
|
10
|
+
import { layoutAppliesTopbar, useBreakpoints } from '../../util';
|
|
11
|
+
import { fixedSidebarToggleStyles } from '../fragments';
|
|
12
|
+
|
|
9
13
|
export const ContentEmpty = () => {
|
|
14
|
+
const breakpoint = useBreakpoints();
|
|
15
|
+
const topbar = layoutAppliesTopbar(breakpoint);
|
|
10
16
|
return (
|
|
11
17
|
<div
|
|
12
18
|
role='none'
|
|
13
|
-
className='
|
|
19
|
+
className='grid place-items-center p-8 relative bg-deck'
|
|
14
20
|
data-testid='layoutPlugin.firstRunMessage'
|
|
15
21
|
>
|
|
16
|
-
<
|
|
17
|
-
|
|
18
|
-
</div>
|
|
22
|
+
<Surface role='keyshortcuts' />
|
|
23
|
+
{!topbar && <ToggleSidebarButton variant='default' classNames={fixedSidebarToggleStyles} />}
|
|
19
24
|
</div>
|
|
20
25
|
);
|
|
21
26
|
};
|
|
@@ -2,24 +2,29 @@
|
|
|
2
2
|
// Copyright 2023 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import { Sidebar as MenuIcon } from '@phosphor-icons/react';
|
|
6
5
|
import { untracked } from '@preact/signals-core';
|
|
7
6
|
import React, { useCallback, useEffect, useMemo, useRef, type UIEvent, Fragment } from 'react';
|
|
8
7
|
|
|
9
|
-
import {
|
|
10
|
-
|
|
8
|
+
import {
|
|
9
|
+
LayoutAction,
|
|
10
|
+
createIntent,
|
|
11
|
+
Surface,
|
|
12
|
+
useCapability,
|
|
13
|
+
useIntentDispatcher,
|
|
14
|
+
usePluginManager,
|
|
15
|
+
} from '@dxos/app-framework';
|
|
16
|
+
import { AttentionCapabilities } from '@dxos/plugin-attention';
|
|
11
17
|
import {
|
|
12
18
|
AlertDialog,
|
|
13
|
-
Button,
|
|
14
19
|
Dialog as NaturalDialog,
|
|
15
20
|
Main,
|
|
16
21
|
Popover,
|
|
17
22
|
useOnTransition,
|
|
18
|
-
useTranslation,
|
|
19
23
|
type MainProps,
|
|
24
|
+
useMediaQuery,
|
|
20
25
|
} from '@dxos/react-ui';
|
|
21
26
|
import { Stack, StackContext, DEFAULT_HORIZONTAL_SIZE } from '@dxos/react-ui-stack';
|
|
22
|
-
import {
|
|
27
|
+
import { mainPaddingTransitions } from '@dxos/react-ui-theme';
|
|
23
28
|
|
|
24
29
|
import { ActiveNode } from './ActiveNode';
|
|
25
30
|
import { ComplementarySidebar, type ComplementarySidebarProps } from './ComplementarySidebar';
|
|
@@ -27,17 +32,16 @@ import { ContentEmpty } from './ContentEmpty';
|
|
|
27
32
|
import { Fullscreen } from './Fullscreen';
|
|
28
33
|
import { Plank } from './Plank';
|
|
29
34
|
import { Sidebar } from './Sidebar';
|
|
35
|
+
import { ToggleComplementarySidebarButton, ToggleSidebarButton } from './SidebarButton';
|
|
30
36
|
import { StatusBar } from './StatusBar';
|
|
31
37
|
import { Toast } from './Toast';
|
|
32
|
-
import {
|
|
33
|
-
import {
|
|
34
|
-
import {
|
|
35
|
-
import {
|
|
36
|
-
import {
|
|
38
|
+
import { Topbar } from './Topbar';
|
|
39
|
+
import { DeckCapabilities } from '../../capabilities';
|
|
40
|
+
import { getMode, type Overscroll } from '../../types';
|
|
41
|
+
import { calculateOverscroll, layoutAppliesTopbar, useBreakpoints, useHoistStatusbar } from '../../util';
|
|
42
|
+
import { fixedComplementarySidebarToggleStyles, fixedSidebarToggleStyles } from '../fragments';
|
|
37
43
|
|
|
38
44
|
export type DeckLayoutProps = {
|
|
39
|
-
layoutParts: LayoutParts;
|
|
40
|
-
toasts: ToastSchema[];
|
|
41
45
|
overscroll: Overscroll;
|
|
42
46
|
showHints: boolean;
|
|
43
47
|
onDismissToast: (id: string) => void;
|
|
@@ -46,12 +50,13 @@ export type DeckLayoutProps = {
|
|
|
46
50
|
const PlankSeparator = ({ index }: { index: number }) =>
|
|
47
51
|
index > 0 ? <span role='separator' className='row-span-2 bg-deck is-4' style={{ gridColumn: index * 2 }} /> : null;
|
|
48
52
|
|
|
49
|
-
export const DeckLayout = ({
|
|
50
|
-
const
|
|
53
|
+
export const DeckLayout = ({ overscroll, showHints, panels, onDismissToast }: DeckLayoutProps) => {
|
|
54
|
+
const { dispatchPromise: dispatch } = useIntentDispatcher();
|
|
55
|
+
const context = useCapability(DeckCapabilities.MutableDeckState);
|
|
51
56
|
const {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
57
|
+
sidebarState,
|
|
58
|
+
complementarySidebarState,
|
|
59
|
+
complementarySidebarPanel,
|
|
55
60
|
dialogOpen,
|
|
56
61
|
dialogContent,
|
|
57
62
|
dialogBlockAlign,
|
|
@@ -59,22 +64,26 @@ export const DeckLayout = ({ layoutParts, toasts, overscroll, showHints, panels,
|
|
|
59
64
|
popoverOpen,
|
|
60
65
|
popoverContent,
|
|
61
66
|
popoverAnchorId,
|
|
67
|
+
deck,
|
|
68
|
+
toasts,
|
|
62
69
|
} = context;
|
|
63
|
-
const {
|
|
64
|
-
const
|
|
65
|
-
|
|
66
|
-
const
|
|
67
|
-
const
|
|
70
|
+
const { active, fullscreen, solo, plankSizing } = deck;
|
|
71
|
+
const breakpoint = useBreakpoints();
|
|
72
|
+
const topbar = layoutAppliesTopbar(breakpoint);
|
|
73
|
+
const hoistStatusbar = useHoistStatusbar(breakpoint);
|
|
74
|
+
const pluginManager = usePluginManager();
|
|
68
75
|
|
|
69
76
|
const scrollLeftRef = useRef<number | null>();
|
|
70
77
|
const deckRef = useRef<HTMLDivElement>(null);
|
|
71
78
|
|
|
72
|
-
const isSoloModeLoaded = layoutMode === 'solo' && Boolean(layoutParts.solo?.[0]);
|
|
73
|
-
|
|
74
79
|
// Ensure the first plank is attended when the deck is first rendered.
|
|
75
80
|
useEffect(() => {
|
|
76
|
-
|
|
77
|
-
const
|
|
81
|
+
// NOTE: Not `useAttended` so that the layout component is not re-rendered when the attended list changes.
|
|
82
|
+
const attended = untracked(() => {
|
|
83
|
+
const attention = pluginManager.context.requestCapability(AttentionCapabilities.Attention);
|
|
84
|
+
return attention.current;
|
|
85
|
+
});
|
|
86
|
+
const firstId = solo ?? active[0];
|
|
78
87
|
if (attended.length === 0 && firstId) {
|
|
79
88
|
// TODO(wittjosiah): Focusing the type button is a workaround.
|
|
80
89
|
// If the plank is directly focused on first load the focus ring appears.
|
|
@@ -82,6 +91,27 @@ export const DeckLayout = ({ layoutParts, toasts, overscroll, showHints, panels,
|
|
|
82
91
|
}
|
|
83
92
|
}, []);
|
|
84
93
|
|
|
94
|
+
// Not using `breakpoint` to avoid firing when breakpoint changes between tablet and desktop.
|
|
95
|
+
// `ssr: false` to avoid using fallback values and flashing into solo mode on startup.
|
|
96
|
+
const [isNotMobile] = useMediaQuery('md', { ssr: false });
|
|
97
|
+
const shouldRevert = useRef(false);
|
|
98
|
+
useEffect(() => {
|
|
99
|
+
if (!isNotMobile && getMode(deck) === 'deck') {
|
|
100
|
+
// NOTE: Not `useAttended` so that the layout component is not re-rendered when the attended list changes.
|
|
101
|
+
const attended = untracked(() => {
|
|
102
|
+
const attention = pluginManager.context.requestCapability(AttentionCapabilities.Attention);
|
|
103
|
+
return attention.current;
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
shouldRevert.current = true;
|
|
107
|
+
void dispatch(
|
|
108
|
+
createIntent(LayoutAction.SetLayoutMode, { part: 'mode', subject: attended[0], options: { mode: 'solo' } }),
|
|
109
|
+
);
|
|
110
|
+
} else if (isNotMobile && getMode(deck) === 'solo' && shouldRevert.current) {
|
|
111
|
+
void dispatch(createIntent(LayoutAction.SetLayoutMode, { part: 'mode', options: { revert: true } }));
|
|
112
|
+
}
|
|
113
|
+
}, [isNotMobile, deck, dispatch]);
|
|
114
|
+
|
|
85
115
|
/**
|
|
86
116
|
* Clear scroll restoration state if the window is resized
|
|
87
117
|
*/
|
|
@@ -100,6 +130,7 @@ export const DeckLayout = ({ layoutParts, toasts, overscroll, showHints, panels,
|
|
|
100
130
|
}
|
|
101
131
|
}, []);
|
|
102
132
|
|
|
133
|
+
const layoutMode = getMode(deck);
|
|
103
134
|
useOnTransition(layoutMode, (mode) => mode !== 'deck', 'deck', restoreScroll);
|
|
104
135
|
|
|
105
136
|
/**
|
|
@@ -107,21 +138,30 @@ export const DeckLayout = ({ layoutParts, toasts, overscroll, showHints, panels,
|
|
|
107
138
|
*/
|
|
108
139
|
const handleScroll = useCallback(
|
|
109
140
|
(event: UIEvent) => {
|
|
110
|
-
if (
|
|
141
|
+
if (!solo && event.currentTarget === event.target) {
|
|
111
142
|
scrollLeftRef.current = (event.target as HTMLDivElement).scrollLeft;
|
|
112
143
|
}
|
|
113
144
|
},
|
|
114
|
-
[
|
|
145
|
+
[solo],
|
|
115
146
|
);
|
|
116
147
|
|
|
117
|
-
const isEmpty =
|
|
148
|
+
const isEmpty = !solo && active.length === 0;
|
|
118
149
|
|
|
119
150
|
const padding = useMemo(() => {
|
|
120
|
-
if (
|
|
121
|
-
return calculateOverscroll(
|
|
151
|
+
if (!solo && overscroll === 'centering') {
|
|
152
|
+
return calculateOverscroll(active.length);
|
|
122
153
|
}
|
|
123
154
|
return {};
|
|
124
|
-
}, [
|
|
155
|
+
}, [solo, overscroll, deck]);
|
|
156
|
+
|
|
157
|
+
const mainPosition = useMemo(
|
|
158
|
+
() => [
|
|
159
|
+
'grid !block-start-[env(safe-area-inset-top)]',
|
|
160
|
+
topbar && '!block-start-[calc(env(safe-area-inset-top)+var(--rail-size))]',
|
|
161
|
+
hoistStatusbar && 'lg:block-end-[--statusbar-size]',
|
|
162
|
+
],
|
|
163
|
+
[topbar, hoistStatusbar],
|
|
164
|
+
);
|
|
125
165
|
|
|
126
166
|
const Dialog = dialogType === 'alert' ? AlertDialog : NaturalDialog;
|
|
127
167
|
|
|
@@ -140,37 +180,27 @@ export const DeckLayout = ({ layoutParts, toasts, overscroll, showHints, panels,
|
|
|
140
180
|
>
|
|
141
181
|
<ActiveNode />
|
|
142
182
|
|
|
143
|
-
{
|
|
183
|
+
{fullscreen && <Fullscreen id={solo} />}
|
|
144
184
|
|
|
145
|
-
{
|
|
185
|
+
{!fullscreen && (
|
|
146
186
|
<Main.Root
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
187
|
+
navigationSidebarState={context.sidebarState}
|
|
188
|
+
onNavigationSidebarStateChange={(next) => (context.sidebarState = next)}
|
|
189
|
+
complementarySidebarState={context.complementarySidebarState}
|
|
190
|
+
onComplementarySidebarStateChange={(next) => (context.complementarySidebarState = next)}
|
|
151
191
|
>
|
|
152
|
-
{/* Notch */}
|
|
153
|
-
<Main.Notch classNames='z-[21]'>
|
|
154
|
-
<Surface role='notch-start' />
|
|
155
|
-
<Button onClick={() => (context.sidebarOpen = !context.sidebarOpen)} variant='ghost' classNames='p-1'>
|
|
156
|
-
<span className='sr-only'>{t('open navigation sidebar label')}</span>
|
|
157
|
-
<MenuIcon weight='light' className={getSize(5)} />
|
|
158
|
-
</Button>
|
|
159
|
-
<Surface role='notch-end' />
|
|
160
|
-
</Main.Notch>
|
|
161
|
-
|
|
162
192
|
{/* Left sidebar. */}
|
|
163
|
-
<Sidebar
|
|
193
|
+
<Sidebar />
|
|
164
194
|
|
|
165
195
|
{/* Right sidebar. */}
|
|
166
|
-
<ComplementarySidebar panels={panels} current={
|
|
196
|
+
<ComplementarySidebar panels={panels} current={complementarySidebarPanel} />
|
|
167
197
|
|
|
168
198
|
{/* Dialog overlay to dismiss dialogs. */}
|
|
169
199
|
<Main.Overlay />
|
|
170
200
|
|
|
171
201
|
{/* No content. */}
|
|
172
202
|
{isEmpty && (
|
|
173
|
-
<Main.Content handlesFocus>
|
|
203
|
+
<Main.Content bounce handlesFocus classNames={mainPosition}>
|
|
174
204
|
<ContentEmpty />
|
|
175
205
|
</Main.Content>
|
|
176
206
|
)}
|
|
@@ -179,61 +209,68 @@ export const DeckLayout = ({ layoutParts, toasts, overscroll, showHints, panels,
|
|
|
179
209
|
{!isEmpty && (
|
|
180
210
|
<Main.Content
|
|
181
211
|
bounce
|
|
182
|
-
classNames=
|
|
212
|
+
classNames={mainPosition}
|
|
183
213
|
handlesFocus
|
|
184
214
|
style={
|
|
185
215
|
{
|
|
186
|
-
'--dx-main-sidebarWidth':
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
216
|
+
'--dx-main-sidebarWidth':
|
|
217
|
+
sidebarState === 'expanded'
|
|
218
|
+
? 'var(--nav-sidebar-size)'
|
|
219
|
+
: sidebarState === 'collapsed'
|
|
220
|
+
? 'var(--l0-size)'
|
|
221
|
+
: '0',
|
|
222
|
+
'--dx-main-complementaryWidth':
|
|
223
|
+
complementarySidebarState === 'expanded'
|
|
224
|
+
? 'var(--complementary-sidebar-size)'
|
|
225
|
+
: complementarySidebarState === 'collapsed'
|
|
226
|
+
? 'var(--rail-size)'
|
|
227
|
+
: '0',
|
|
228
|
+
'--dx-main-contentFirstWidth': `${plankSizing[active[0] ?? 'never'] ?? DEFAULT_HORIZONTAL_SIZE}rem`,
|
|
229
|
+
'--dx-main-contentLastWidth': `${plankSizing[active[(active.length ?? 1) - 1] ?? 'never'] ?? DEFAULT_HORIZONTAL_SIZE}rem`,
|
|
192
230
|
} as MainProps['style']
|
|
193
231
|
}
|
|
194
232
|
>
|
|
195
233
|
<div
|
|
196
234
|
role='none'
|
|
197
|
-
className={!
|
|
198
|
-
{...(
|
|
235
|
+
className={!solo ? 'relative bg-deck overflow-hidden' : 'sr-only'}
|
|
236
|
+
{...(solo && { inert: '' })}
|
|
199
237
|
>
|
|
238
|
+
{!topbar && <ToggleSidebarButton classNames={fixedSidebarToggleStyles} />}
|
|
239
|
+
{!topbar && <ToggleComplementarySidebarButton classNames={fixedComplementarySidebarToggleStyles} />}
|
|
200
240
|
<Stack
|
|
201
241
|
orientation='horizontal'
|
|
202
242
|
size='contain'
|
|
203
243
|
classNames={['absolute inset-block-0 -inset-inline-px', mainPaddingTransitions]}
|
|
204
244
|
onScroll={handleScroll}
|
|
205
|
-
itemsCount={2 * (
|
|
245
|
+
itemsCount={2 * (active.length ?? 0) - 1}
|
|
206
246
|
style={padding}
|
|
207
247
|
ref={deckRef}
|
|
208
248
|
>
|
|
209
|
-
{
|
|
210
|
-
<Fragment key={
|
|
249
|
+
{active.map((entryId, index) => (
|
|
250
|
+
<Fragment key={entryId}>
|
|
211
251
|
<PlankSeparator index={index} />
|
|
212
|
-
<Plank
|
|
213
|
-
entry={layoutEntry}
|
|
214
|
-
layoutParts={layoutParts}
|
|
215
|
-
part='main'
|
|
216
|
-
layoutMode={layoutMode}
|
|
217
|
-
order={index * 2 + 1}
|
|
218
|
-
/>
|
|
252
|
+
<Plank id={entryId} part='deck' order={index * 2 + 1} active={active} layoutMode={layoutMode} />
|
|
219
253
|
</Fragment>
|
|
220
254
|
))}
|
|
221
255
|
</Stack>
|
|
222
256
|
</div>
|
|
223
257
|
<div
|
|
224
258
|
role='none'
|
|
225
|
-
className={
|
|
226
|
-
{...(!
|
|
259
|
+
className={solo ? 'relative bg-deck overflow-hidden' : 'sr-only'}
|
|
260
|
+
{...(!solo && { inert: '' })}
|
|
227
261
|
>
|
|
262
|
+
{!topbar && <ToggleSidebarButton classNames={fixedSidebarToggleStyles} />}
|
|
263
|
+
{!topbar && <ToggleComplementarySidebarButton classNames={fixedComplementarySidebarToggleStyles} />}
|
|
228
264
|
<StackContext.Provider value={{ size: 'contain', orientation: 'horizontal', rail: true }}>
|
|
229
|
-
<Plank
|
|
265
|
+
<Plank id={solo} part='solo' layoutMode={layoutMode} />
|
|
230
266
|
</StackContext.Provider>
|
|
231
267
|
</div>
|
|
232
268
|
</Main.Content>
|
|
233
269
|
)}
|
|
234
270
|
|
|
235
|
-
{/*
|
|
236
|
-
<
|
|
271
|
+
{/* Status bar. */}
|
|
272
|
+
{topbar && <Topbar />}
|
|
273
|
+
{hoistStatusbar && <StatusBar showHints={showHints} />}
|
|
237
274
|
</Main.Root>
|
|
238
275
|
)}
|
|
239
276
|
|
|
@@ -4,8 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
import React from 'react';
|
|
6
6
|
|
|
7
|
-
import { Surface } from '@dxos/app-framework';
|
|
8
|
-
import { useGraph } from '@dxos/plugin-graph';
|
|
7
|
+
import { Surface, useAppGraph } from '@dxos/app-framework';
|
|
9
8
|
import { fixedInsetFlexLayout } from '@dxos/react-ui-theme';
|
|
10
9
|
|
|
11
10
|
import { Fallback } from './Fallback';
|
|
@@ -13,7 +12,7 @@ import { SURFACE_PREFIX } from './constants';
|
|
|
13
12
|
import { useNode } from '../../hooks';
|
|
14
13
|
|
|
15
14
|
export const Fullscreen = ({ id }: { id?: string }) => {
|
|
16
|
-
const { graph } =
|
|
15
|
+
const { graph } = useAppGraph();
|
|
17
16
|
const fullScreenNode = useNode(graph, id);
|
|
18
17
|
|
|
19
18
|
return (
|