@dxos/plugin-deck 0.6.13 → 0.6.14-main.69511f5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/lib/browser/{chunk-YVHGFQQR.mjs → chunk-GVOGPULO.mjs} +1 -1
- package/dist/lib/browser/chunk-GVOGPULO.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +340 -288
- package/dist/lib/browser/index.mjs.map +3 -3
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/meta.mjs +1 -1
- package/dist/types/src/DeckPlugin.d.ts.map +1 -1
- package/dist/types/src/components/DeckLayout/ActiveNode.d.ts +1 -3
- package/dist/types/src/components/DeckLayout/ActiveNode.d.ts.map +1 -1
- package/dist/types/src/components/DeckLayout/ComplementarySidebar.d.ts +2 -4
- package/dist/types/src/components/DeckLayout/ComplementarySidebar.d.ts.map +1 -1
- package/dist/types/src/components/DeckLayout/DeckLayout.d.ts +3 -4
- package/dist/types/src/components/DeckLayout/DeckLayout.d.ts.map +1 -1
- package/dist/types/src/components/DeckLayout/NodePlankHeading.d.ts +9 -7
- package/dist/types/src/components/DeckLayout/NodePlankHeading.d.ts.map +1 -1
- package/dist/types/src/components/DeckLayout/Plank.d.ts +1 -1
- package/dist/types/src/components/DeckLayout/Plank.d.ts.map +1 -1
- package/dist/types/src/components/DeckLayout/PlankError.d.ts +1 -2
- package/dist/types/src/components/DeckLayout/PlankError.d.ts.map +1 -1
- package/dist/types/src/components/DeckLayout/Sidebar.d.ts +2 -3
- package/dist/types/src/components/DeckLayout/Sidebar.d.ts.map +1 -1
- package/dist/types/src/components/DeckLayout/StatusBar.d.ts +3 -1
- package/dist/types/src/components/DeckLayout/StatusBar.d.ts.map +1 -1
- package/dist/types/src/components/DeckLayout/Toast.d.ts.map +1 -1
- package/dist/types/src/components/LayoutSettings.d.ts.map +1 -1
- package/dist/types/src/hooks/useNode.d.ts.map +1 -1
- package/dist/types/src/layout.d.ts.map +1 -1
- package/dist/types/src/meta.d.ts.map +1 -1
- package/dist/types/src/translations.d.ts +5 -3
- package/dist/types/src/translations.d.ts.map +1 -1
- package/dist/types/src/types.d.ts +1 -1
- package/dist/types/src/types.d.ts.map +1 -1
- package/dist/types/src/util/overscroll.d.ts +1 -1
- package/dist/types/src/util/overscroll.d.ts.map +1 -1
- package/package.json +35 -33
- package/src/DeckPlugin.tsx +89 -79
- package/src/components/DeckLayout/ActiveNode.tsx +4 -1
- package/src/components/DeckLayout/ComplementarySidebar.tsx +72 -28
- package/src/components/DeckLayout/DeckLayout.tsx +64 -96
- package/src/components/DeckLayout/NodePlankHeading.tsx +130 -127
- package/src/components/DeckLayout/Plank.tsx +31 -22
- package/src/components/DeckLayout/PlankError.tsx +1 -9
- package/src/components/DeckLayout/Sidebar.tsx +7 -8
- package/src/components/DeckLayout/StatusBar.tsx +12 -3
- package/src/components/DeckLayout/Toast.tsx +3 -3
- package/src/components/LayoutSettings.tsx +17 -20
- package/src/hooks/useNode.ts +5 -1
- package/src/layout.ts +1 -0
- package/src/meta.ts +3 -1
- package/src/translations.ts +7 -3
- package/src/types.ts +1 -1
- package/src/util/overscroll.ts +5 -5
- package/dist/lib/browser/chunk-YVHGFQQR.mjs.map +0 -7
|
@@ -3,21 +3,14 @@
|
|
|
3
3
|
//
|
|
4
4
|
|
|
5
5
|
import { Sidebar as MenuIcon } from '@phosphor-icons/react';
|
|
6
|
-
import
|
|
6
|
+
import { untracked } from '@preact/signals-core';
|
|
7
|
+
import React, { useCallback, useEffect, useMemo, useRef, type UIEvent } from 'react';
|
|
7
8
|
|
|
8
|
-
import {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
type LayoutEntry,
|
|
12
|
-
type LayoutParts,
|
|
13
|
-
Surface,
|
|
14
|
-
type Toast as ToastSchema,
|
|
15
|
-
firstIdInPart,
|
|
16
|
-
usePlugin,
|
|
17
|
-
} from '@dxos/app-framework';
|
|
18
|
-
import { Button, Dialog, Main, Popover, useTranslation } from '@dxos/react-ui';
|
|
9
|
+
import { type LayoutParts, Surface, type Toast as ToastSchema, firstIdInPart, usePlugin } from '@dxos/app-framework';
|
|
10
|
+
import { type AttentionPluginProvides } from '@dxos/plugin-attention';
|
|
11
|
+
import { Button, Dialog, Main, Popover, useOnTransition, useTranslation } from '@dxos/react-ui';
|
|
19
12
|
import { Deck } from '@dxos/react-ui-deck';
|
|
20
|
-
import { getSize } from '@dxos/react-ui-theme';
|
|
13
|
+
import { getSize, mainPaddingTransitions } from '@dxos/react-ui-theme';
|
|
21
14
|
|
|
22
15
|
import { ActiveNode } from './ActiveNode';
|
|
23
16
|
import { ComplementarySidebar } from './ComplementarySidebar';
|
|
@@ -35,11 +28,10 @@ import { useLayout } from '../LayoutContext';
|
|
|
35
28
|
|
|
36
29
|
export type DeckLayoutProps = {
|
|
37
30
|
layoutParts: LayoutParts;
|
|
38
|
-
attention: Attention;
|
|
39
31
|
toasts: ToastSchema[];
|
|
40
32
|
flatDeck?: boolean;
|
|
41
33
|
overscroll: Overscroll;
|
|
42
|
-
|
|
34
|
+
showHints: boolean;
|
|
43
35
|
slots?: {
|
|
44
36
|
wallpaper?: { classNames?: string };
|
|
45
37
|
};
|
|
@@ -48,11 +40,10 @@ export type DeckLayoutProps = {
|
|
|
48
40
|
|
|
49
41
|
export const DeckLayout = ({
|
|
50
42
|
layoutParts,
|
|
51
|
-
attention,
|
|
52
43
|
toasts,
|
|
53
44
|
flatDeck,
|
|
54
45
|
overscroll,
|
|
55
|
-
|
|
46
|
+
showHints,
|
|
56
47
|
slots,
|
|
57
48
|
onDismissToast,
|
|
58
49
|
}: DeckLayoutProps) => {
|
|
@@ -70,36 +61,44 @@ export const DeckLayout = ({
|
|
|
70
61
|
} = context;
|
|
71
62
|
const { t } = useTranslation(DECK_PLUGIN);
|
|
72
63
|
const { plankSizing } = useDeckContext();
|
|
64
|
+
// NOTE: Not `useAttended` so that the layout component is not re-rendered when the attended list changes.
|
|
65
|
+
const attentionPlugin = usePlugin<AttentionPluginProvides>('dxos.org/plugin/attention');
|
|
73
66
|
const searchPlugin = usePlugin('dxos.org/plugin/search');
|
|
74
67
|
const fullScreenSlug = useMemo(() => firstIdInPart(layoutParts, 'fullScreen'), [layoutParts]);
|
|
75
68
|
|
|
76
|
-
const
|
|
77
|
-
const deckRef = useRef<HTMLDivElement
|
|
78
|
-
|
|
69
|
+
const scrollLeftRef = useRef<number | null>();
|
|
70
|
+
const deckRef = useRef<HTMLDivElement>(null);
|
|
71
|
+
|
|
72
|
+
// Ensure the first plank is attended when the deck is first rendered.
|
|
73
|
+
useEffect(() => {
|
|
74
|
+
const attended = untracked(() => attentionPlugin?.provides.attention.attended ?? []);
|
|
75
|
+
const firstId = layoutMode === 'solo' ? firstIdInPart(layoutParts, 'solo') : firstIdInPart(layoutParts, 'main');
|
|
76
|
+
if (attended.length === 0 && firstId) {
|
|
77
|
+
// TODO(wittjosiah): Focusing the type button is a workaround.
|
|
78
|
+
// If the plank is directly focused on first load the focus ring appears.
|
|
79
|
+
document.querySelector<HTMLElement>(`article[data-attendable-id="${firstId}"] button`)?.focus();
|
|
80
|
+
}
|
|
81
|
+
}, []);
|
|
79
82
|
|
|
80
83
|
/**
|
|
81
84
|
* Clear scroll restoration state if the window is resized
|
|
82
85
|
*/
|
|
83
86
|
const handleResize = useCallback(() => {
|
|
84
|
-
|
|
87
|
+
scrollLeftRef.current = null;
|
|
85
88
|
}, []);
|
|
89
|
+
|
|
86
90
|
useEffect(() => {
|
|
87
91
|
window.addEventListener('resize', handleResize);
|
|
88
92
|
return () => window.removeEventListener('resize', handleResize);
|
|
89
93
|
}, [handleResize]);
|
|
90
94
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
useLayoutEffect(() => {
|
|
95
|
-
if (layoutMode !== 'deck') {
|
|
96
|
-
restoreScrollRef.current = true;
|
|
97
|
-
} else if (restoreScrollRef.current && deckRef.current && scrollLeft) {
|
|
98
|
-
// console.log('[restoring scrollLeft]', scrollLeft);
|
|
99
|
-
deckRef.current.scrollLeft = scrollLeft;
|
|
100
|
-
restoreScrollRef.current = false;
|
|
95
|
+
const restoreScroll = useCallback(() => {
|
|
96
|
+
if (deckRef.current && scrollLeftRef.current != null) {
|
|
97
|
+
deckRef.current.scrollLeft = scrollLeftRef.current;
|
|
101
98
|
}
|
|
102
|
-
}, [
|
|
99
|
+
}, []);
|
|
100
|
+
|
|
101
|
+
useOnTransition(layoutMode, (mode) => mode !== 'deck', 'deck', restoreScroll);
|
|
103
102
|
|
|
104
103
|
/**
|
|
105
104
|
* Save scroll position as the user scrolls
|
|
@@ -107,48 +106,20 @@ export const DeckLayout = ({
|
|
|
107
106
|
const handleScroll = useCallback(
|
|
108
107
|
(event: UIEvent) => {
|
|
109
108
|
if (layoutMode === 'deck' && event.currentTarget === event.target) {
|
|
110
|
-
|
|
111
|
-
setScrollLeft((event.target as HTMLDivElement).scrollLeft);
|
|
109
|
+
scrollLeftRef.current = (event.target as HTMLDivElement).scrollLeft;
|
|
112
110
|
}
|
|
113
111
|
},
|
|
114
112
|
[layoutMode],
|
|
115
113
|
);
|
|
116
114
|
|
|
117
|
-
const
|
|
118
|
-
const entry = layoutParts.complementary?.at(0);
|
|
119
|
-
if (entry) {
|
|
120
|
-
return entry.path ? `${entry.id}${SLUG_PATH_SEPARATOR}${entry.path}` : entry.id;
|
|
121
|
-
}
|
|
122
|
-
}, [layoutParts]);
|
|
123
|
-
|
|
124
|
-
const firstAttendedId = useMemo(() => Array.from(attention.attended ?? [])[0], [attention.attended]);
|
|
115
|
+
const isEmpty = layoutParts.main?.length === 0 && layoutParts.solo?.length === 0;
|
|
125
116
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
if (layoutMode === 'deck' && firstAttendedId) {
|
|
130
|
-
// setTimeout(() => {
|
|
131
|
-
// const el = deckRef.current?.querySelector(`article[data-attendable-id="${firstAttendedId}"]`);
|
|
132
|
-
// el?.scrollIntoView({ behavior: 'smooth', inline: 'center' });
|
|
133
|
-
// }, 0);
|
|
134
|
-
}
|
|
135
|
-
}, [layoutMode, firstAttendedId]);
|
|
136
|
-
|
|
137
|
-
// TODO(burdon): Needs cleaning up.
|
|
138
|
-
const parts: LayoutEntry[] = useMemo(() => {
|
|
139
|
-
const parts = [...(layoutParts.main ?? [])];
|
|
140
|
-
for (const part of layoutParts.solo ?? []) {
|
|
141
|
-
if (!parts.find((entry) => entry.id === part.id)) {
|
|
142
|
-
parts.push(part);
|
|
143
|
-
}
|
|
117
|
+
const padding = useMemo(() => {
|
|
118
|
+
if (layoutMode === 'deck' && overscroll === 'centering') {
|
|
119
|
+
return calculateOverscroll(layoutParts.main, plankSizing, sidebarOpen, complementarySidebarOpen);
|
|
144
120
|
}
|
|
145
|
-
return
|
|
146
|
-
}, [layoutParts.main,
|
|
147
|
-
|
|
148
|
-
const padding =
|
|
149
|
-
layoutMode === 'deck' && overscroll === 'centering'
|
|
150
|
-
? calculateOverscroll(layoutParts.main, plankSizing, sidebarOpen, complementarySidebarOpen)
|
|
151
|
-
: {};
|
|
121
|
+
return {};
|
|
122
|
+
}, [layoutMode, overscroll, layoutParts.main, plankSizing, sidebarOpen, complementarySidebarOpen]);
|
|
152
123
|
|
|
153
124
|
if (layoutMode === 'fullscreen') {
|
|
154
125
|
return <Fullscreen id={fullScreenSlug} />;
|
|
@@ -167,31 +138,22 @@ export const DeckLayout = ({
|
|
|
167
138
|
}
|
|
168
139
|
}}
|
|
169
140
|
>
|
|
170
|
-
|
|
171
|
-
<ActiveNode id={firstAttendedId} />
|
|
141
|
+
<ActiveNode />
|
|
172
142
|
|
|
173
143
|
<Main.Root
|
|
174
144
|
navigationSidebarOpen={context.sidebarOpen}
|
|
175
145
|
onNavigationSidebarOpenChange={(next) => (context.sidebarOpen = next)}
|
|
176
|
-
{
|
|
177
|
-
|
|
178
|
-
onComplementarySidebarOpenChange: (next) => (context.complementarySidebarOpen = next),
|
|
179
|
-
})}
|
|
146
|
+
complementarySidebarOpen={context.complementarySidebarOpen}
|
|
147
|
+
onComplementarySidebarOpenChange={(next) => (context.complementarySidebarOpen = next)}
|
|
180
148
|
>
|
|
181
149
|
{/* Notch */}
|
|
182
150
|
<Main.Notch classNames='z-[21]'>
|
|
183
151
|
<Surface role='notch-start' />
|
|
184
|
-
<Button
|
|
185
|
-
// disabled={!sidebarAvailable}
|
|
186
|
-
onClick={() => (context.sidebarOpen = !context.sidebarOpen)}
|
|
187
|
-
variant='ghost'
|
|
188
|
-
classNames='p-1'
|
|
189
|
-
>
|
|
152
|
+
<Button onClick={() => (context.sidebarOpen = !context.sidebarOpen)} variant='ghost' classNames='p-1'>
|
|
190
153
|
<span className='sr-only'>{t('open navigation sidebar label')}</span>
|
|
191
154
|
<MenuIcon weight='light' className={getSize(5)} />
|
|
192
155
|
</Button>
|
|
193
156
|
<Button
|
|
194
|
-
// disabled={!complementaryAvailable}
|
|
195
157
|
onClick={() => (context.complementarySidebarOpen = !context.complementarySidebarOpen)}
|
|
196
158
|
variant='ghost'
|
|
197
159
|
classNames='p-1'
|
|
@@ -203,38 +165,51 @@ export const DeckLayout = ({
|
|
|
203
165
|
</Main.Notch>
|
|
204
166
|
|
|
205
167
|
{/* Left sidebar. */}
|
|
206
|
-
<Sidebar
|
|
168
|
+
<Sidebar layoutParts={layoutParts} />
|
|
207
169
|
|
|
208
170
|
{/* Right sidebar. */}
|
|
209
|
-
<ComplementarySidebar
|
|
171
|
+
<ComplementarySidebar panel={layoutParts.complementary?.[0].id} flatDeck={flatDeck} />
|
|
210
172
|
|
|
211
173
|
{/* Dialog overlay to dismiss dialogs. */}
|
|
212
174
|
<Main.Overlay />
|
|
213
175
|
|
|
214
176
|
{/* No content. */}
|
|
215
|
-
{
|
|
177
|
+
{isEmpty && (
|
|
216
178
|
<Main.Content handlesFocus>
|
|
217
179
|
<ContentEmpty />
|
|
218
180
|
</Main.Content>
|
|
219
181
|
)}
|
|
220
182
|
|
|
221
183
|
{/* Solo/deck mode. */}
|
|
222
|
-
{
|
|
184
|
+
{!isEmpty && (
|
|
223
185
|
<Main.Content bounce classNames='grid block-end-[--statusbar-size]' handlesFocus>
|
|
224
186
|
<div role='none' className='relative'>
|
|
225
187
|
<Deck.Root
|
|
226
188
|
style={padding}
|
|
227
|
-
classNames={[
|
|
189
|
+
classNames={[
|
|
190
|
+
!flatDeck && 'bg-deck',
|
|
191
|
+
mainPaddingTransitions,
|
|
192
|
+
'absolute inset-0',
|
|
193
|
+
slots?.wallpaper?.classNames,
|
|
194
|
+
]}
|
|
228
195
|
solo={layoutMode === 'solo'}
|
|
229
196
|
onScroll={handleScroll}
|
|
230
197
|
ref={deckRef}
|
|
231
198
|
>
|
|
232
|
-
|
|
199
|
+
<Plank
|
|
200
|
+
entry={layoutParts.solo?.[0] ?? { id: 'unknown-solo' }}
|
|
201
|
+
layoutParts={layoutParts}
|
|
202
|
+
part='solo'
|
|
203
|
+
layoutMode={layoutMode}
|
|
204
|
+
flatDeck={flatDeck}
|
|
205
|
+
searchEnabled={!!searchPlugin}
|
|
206
|
+
/>
|
|
207
|
+
{layoutParts.main?.map((layoutEntry) => (
|
|
233
208
|
<Plank
|
|
234
209
|
key={layoutEntry.id}
|
|
235
210
|
entry={layoutEntry}
|
|
236
211
|
layoutParts={layoutParts}
|
|
237
|
-
part=
|
|
212
|
+
part='main'
|
|
238
213
|
layoutMode={layoutMode}
|
|
239
214
|
flatDeck={flatDeck}
|
|
240
215
|
searchEnabled={!!searchPlugin}
|
|
@@ -245,15 +220,8 @@ export const DeckLayout = ({
|
|
|
245
220
|
</Main.Content>
|
|
246
221
|
)}
|
|
247
222
|
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
{/* Help hints. */}
|
|
251
|
-
{/* TODO(burdon): Need to make room for this in status bar. */}
|
|
252
|
-
{showHintsFooter && (
|
|
253
|
-
<div className='fixed bottom-0 left-0 right-0 h-[32px] z-[1] flex justify-center'>
|
|
254
|
-
<Surface role='hints' limit={1} />
|
|
255
|
-
</div>
|
|
256
|
-
)}
|
|
223
|
+
{/* Footer status. */}
|
|
224
|
+
<StatusBar showHints={showHints} />
|
|
257
225
|
|
|
258
226
|
{/* Global popovers. */}
|
|
259
227
|
<Popover.Portal>
|
|
@@ -2,157 +2,160 @@
|
|
|
2
2
|
// Copyright 2024 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import {
|
|
6
|
-
import React, { Fragment, useEffect } from 'react';
|
|
5
|
+
import React, { Fragment, memo, useEffect, useMemo } from 'react';
|
|
7
6
|
|
|
8
7
|
import {
|
|
9
8
|
LayoutAction,
|
|
10
9
|
NavigationAction,
|
|
11
|
-
SLUG_COLLECTION_INDICATOR,
|
|
12
10
|
SLUG_PATH_SEPARATOR,
|
|
13
11
|
Surface,
|
|
14
12
|
useIntentDispatcher,
|
|
15
|
-
|
|
16
|
-
partLength,
|
|
17
|
-
type LayoutParts,
|
|
18
|
-
type LayoutPart,
|
|
19
|
-
type LayoutEntry,
|
|
13
|
+
type LayoutCoordinate,
|
|
20
14
|
} from '@dxos/app-framework';
|
|
21
15
|
import { type Node, useGraph } from '@dxos/plugin-graph';
|
|
22
|
-
import { Popover, toLocalizedString, useMediaQuery, useTranslation } from '@dxos/react-ui';
|
|
23
|
-
import { PlankHeading,
|
|
16
|
+
import { Icon, Popover, toLocalizedString, useMediaQuery, useTranslation } from '@dxos/react-ui';
|
|
17
|
+
import { PlankHeading, type PlankHeadingAction } from '@dxos/react-ui-deck';
|
|
24
18
|
import { TextTooltip } from '@dxos/react-ui-text-tooltip';
|
|
25
19
|
|
|
26
20
|
import { DECK_PLUGIN } from '../../meta';
|
|
27
21
|
|
|
28
|
-
export
|
|
29
|
-
|
|
30
|
-
id,
|
|
31
|
-
layoutParts,
|
|
32
|
-
layoutPart,
|
|
33
|
-
// TODO(wittjosiah): Unused?
|
|
34
|
-
layoutEntry,
|
|
35
|
-
popoverAnchorId,
|
|
36
|
-
pending,
|
|
37
|
-
flatDeck,
|
|
38
|
-
}: {
|
|
22
|
+
export type NodePlankHeadingProps = {
|
|
23
|
+
coordinate: LayoutCoordinate;
|
|
39
24
|
node?: Node;
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
layoutPart?: LayoutPart;
|
|
43
|
-
layoutEntry?: LayoutEntry;
|
|
25
|
+
canIncrementStart?: boolean;
|
|
26
|
+
canIncrementEnd?: boolean;
|
|
44
27
|
popoverAnchorId?: string;
|
|
45
28
|
pending?: boolean;
|
|
46
29
|
flatDeck?: boolean;
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
const { graph } = useGraph();
|
|
50
|
-
const Icon = node?.properties?.icon ?? Placeholder;
|
|
51
|
-
const label = pending
|
|
52
|
-
? t('pending heading')
|
|
53
|
-
: toLocalizedString(node?.properties?.label ?? ['plank heading fallback label', { ns: DECK_PLUGIN }], t);
|
|
54
|
-
const dispatch = useIntentDispatcher();
|
|
55
|
-
const ActionRoot = node && popoverAnchorId === `dxos.org/ui/${DECK_PLUGIN}/${node.id}` ? Popover.Anchor : Fragment;
|
|
56
|
-
const [isNotMobile] = useMediaQuery('md');
|
|
57
|
-
|
|
58
|
-
useEffect(() => {
|
|
59
|
-
const frame = requestAnimationFrame(() => {
|
|
60
|
-
// Load actions for the node.
|
|
61
|
-
node && graph.actions(node);
|
|
62
|
-
});
|
|
30
|
+
actions?: PlankHeadingAction[];
|
|
31
|
+
};
|
|
63
32
|
|
|
64
|
-
|
|
65
|
-
|
|
33
|
+
export const NodePlankHeading = memo(
|
|
34
|
+
({
|
|
35
|
+
coordinate,
|
|
36
|
+
node,
|
|
37
|
+
canIncrementStart,
|
|
38
|
+
canIncrementEnd,
|
|
39
|
+
popoverAnchorId,
|
|
40
|
+
pending,
|
|
41
|
+
flatDeck,
|
|
42
|
+
actions = [],
|
|
43
|
+
}: NodePlankHeadingProps) => {
|
|
44
|
+
const { t } = useTranslation(DECK_PLUGIN);
|
|
45
|
+
const { graph } = useGraph();
|
|
46
|
+
const icon = node?.properties?.icon ?? 'ph--placeholder--regular';
|
|
47
|
+
const label = pending
|
|
48
|
+
? t('pending heading')
|
|
49
|
+
: toLocalizedString(node?.properties?.label ?? ['plank heading fallback label', { ns: DECK_PLUGIN }], t);
|
|
50
|
+
const dispatch = useIntentDispatcher();
|
|
51
|
+
const ActionRoot = node && popoverAnchorId === `dxos.org/ui/${DECK_PLUGIN}/${node.id}` ? Popover.Anchor : Fragment;
|
|
52
|
+
const [isNotMobile] = useMediaQuery('md');
|
|
66
53
|
|
|
67
|
-
|
|
68
|
-
|
|
54
|
+
useEffect(() => {
|
|
55
|
+
const frame = requestAnimationFrame(() => {
|
|
56
|
+
// Load actions for the node.
|
|
57
|
+
node && graph.actions(node);
|
|
58
|
+
});
|
|
69
59
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
const length = partLength(layoutParts, layoutPart);
|
|
60
|
+
return () => cancelAnimationFrame(frame);
|
|
61
|
+
}, [node]);
|
|
73
62
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
63
|
+
const layoutPart = coordinate.part;
|
|
64
|
+
// NOTE(Zan): Node ids may now contain a path like `${space}:${id}~comments`
|
|
65
|
+
const attendableId = coordinate.entryId.split(SLUG_PATH_SEPARATOR).at(0);
|
|
66
|
+
const capabilities = useMemo(
|
|
67
|
+
() => ({
|
|
68
|
+
solo: (layoutPart === 'solo' || layoutPart === 'main') && isNotMobile,
|
|
69
|
+
incrementStart: canIncrementStart,
|
|
70
|
+
incrementEnd: canIncrementEnd,
|
|
71
|
+
}),
|
|
72
|
+
[isNotMobile, layoutPart, canIncrementStart, canIncrementEnd],
|
|
73
|
+
);
|
|
77
74
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
75
|
+
return (
|
|
76
|
+
<PlankHeading.Root
|
|
77
|
+
{...((layoutPart !== 'main' || !flatDeck) && { classNames: 'pie-1 border-b border-separator' })}
|
|
78
|
+
>
|
|
79
|
+
<ActionRoot>
|
|
80
|
+
{node ? (
|
|
81
|
+
<PlankHeading.ActionsMenu
|
|
82
|
+
icon={icon}
|
|
83
|
+
related={layoutPart === 'complementary'}
|
|
84
|
+
attendableId={attendableId}
|
|
85
|
+
triggerLabel={t('actions menu label')}
|
|
86
|
+
actions={[actions, graph.actions(node)].filter((a) => a.length > 0)}
|
|
87
|
+
onAction={(action) =>
|
|
88
|
+
typeof action.data === 'function' && action.data?.({ node: action as Node, caller: DECK_PLUGIN })
|
|
89
|
+
}
|
|
90
|
+
>
|
|
91
|
+
<Surface role='menu-footer' data={{ object: node.data }} />
|
|
92
|
+
</PlankHeading.ActionsMenu>
|
|
93
|
+
) : (
|
|
94
|
+
<PlankHeading.Button>
|
|
95
|
+
<span className='sr-only'>{label}</span>
|
|
96
|
+
<Icon icon={icon} size={5} />
|
|
97
|
+
</PlankHeading.Button>
|
|
98
|
+
)}
|
|
99
|
+
</ActionRoot>
|
|
100
|
+
<TextTooltip text={label} onlyWhenTruncating>
|
|
101
|
+
<PlankHeading.Label
|
|
84
102
|
attendableId={attendableId}
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
onAction={(action) =>
|
|
88
|
-
typeof action.data === 'function' && action.data?.({ node: action as Node, caller: DECK_PLUGIN })
|
|
89
|
-
}
|
|
103
|
+
related={layoutPart === 'complementary'}
|
|
104
|
+
{...(pending && { classNames: 'text-description' })}
|
|
90
105
|
>
|
|
91
|
-
|
|
92
|
-
</PlankHeading.
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
</PlankHeading.Button>
|
|
106
|
+
{label}
|
|
107
|
+
</PlankHeading.Label>
|
|
108
|
+
</TextTooltip>
|
|
109
|
+
{node && layoutPart !== 'complementary' && (
|
|
110
|
+
// TODO(Zan): What are we doing with layout coordinate here?
|
|
111
|
+
<Surface role='navbar-end' direction='inline-reverse' data={{ object: node.data }} />
|
|
98
112
|
)}
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
{
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
<Surface role='navbar-end' direction='inline-reverse' data={{ object: node.data }} />
|
|
108
|
-
)}
|
|
109
|
-
{/* NOTE(thure): Pinning & unpinning are temporarily disabled */}
|
|
110
|
-
<PlankHeading.Controls
|
|
111
|
-
capabilities={{
|
|
112
|
-
solo: (layoutPart === 'solo' || layoutPart === 'main') && isNotMobile,
|
|
113
|
-
incrementStart: canIncrementStart,
|
|
114
|
-
incrementEnd: canIncrementEnd,
|
|
115
|
-
}}
|
|
116
|
-
isSolo={layoutPart === 'solo'}
|
|
117
|
-
onClick={(eventType) => {
|
|
118
|
-
if (!layoutPart) {
|
|
119
|
-
return;
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
if (eventType === 'solo') {
|
|
123
|
-
return dispatch([
|
|
124
|
-
{
|
|
125
|
-
action: NavigationAction.ADJUST,
|
|
126
|
-
data: { type: eventType, layoutCoordinate: { part: 'main', entryId: id } },
|
|
127
|
-
},
|
|
128
|
-
]);
|
|
129
|
-
}
|
|
113
|
+
{/* NOTE(thure): Pinning & unpinning are temporarily disabled */}
|
|
114
|
+
<PlankHeading.Controls
|
|
115
|
+
capabilities={capabilities}
|
|
116
|
+
isSolo={layoutPart === 'solo'}
|
|
117
|
+
onClick={(eventType) => {
|
|
118
|
+
if (!layoutPart) {
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
130
121
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
122
|
+
// TODO(Zan): Update this to use the new layout actions.
|
|
123
|
+
if (eventType === 'solo') {
|
|
124
|
+
return dispatch([
|
|
125
|
+
{
|
|
126
|
+
action: NavigationAction.ADJUST,
|
|
127
|
+
data: { type: eventType, layoutCoordinate: { part: 'main', entryId: coordinate.entryId } },
|
|
128
|
+
},
|
|
129
|
+
]);
|
|
130
|
+
} else if (eventType === 'close') {
|
|
131
|
+
if (layoutPart === 'complementary') {
|
|
132
|
+
return dispatch({
|
|
133
|
+
action: LayoutAction.SET_LAYOUT,
|
|
134
|
+
data: {
|
|
135
|
+
element: 'complementary',
|
|
136
|
+
state: false,
|
|
137
|
+
},
|
|
138
|
+
});
|
|
139
|
+
} else {
|
|
140
|
+
return dispatch({
|
|
141
|
+
action: NavigationAction.CLOSE,
|
|
142
|
+
data: {
|
|
143
|
+
activeParts: {
|
|
144
|
+
[layoutPart]: [coordinate.entryId],
|
|
149
145
|
},
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
}
|
|
146
|
+
},
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
} else {
|
|
150
|
+
return dispatch({
|
|
151
|
+
action: NavigationAction.ADJUST,
|
|
152
|
+
data: { type: eventType, layoutCoordinate: coordinate },
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
}}
|
|
156
|
+
close={layoutPart === 'complementary' ? 'minify-end' : true}
|
|
157
|
+
/>
|
|
158
|
+
</PlankHeading.Root>
|
|
159
|
+
);
|
|
160
|
+
},
|
|
161
|
+
);
|