@dxos/plugin-deck 0.8.1-main.303c73a → 0.8.1-main.81238a8
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-K4KVSHNT.mjs} +3 -3
- package/dist/lib/browser/{check-app-scheme-S3EYUPMF.mjs → check-app-scheme-6SS6I3RN.mjs} +2 -2
- package/dist/lib/browser/{chunk-N7TEPFVR.mjs → chunk-2WTHB3TG.mjs} +1 -1
- package/dist/lib/browser/{chunk-N7TEPFVR.mjs.map → chunk-2WTHB3TG.mjs.map} +2 -2
- package/dist/lib/browser/chunk-7A5DLPQ3.mjs +24 -0
- package/dist/lib/browser/{chunk-FYKBOM3C.mjs → chunk-7X43JKZG.mjs} +33 -3
- package/dist/lib/browser/chunk-7X43JKZG.mjs.map +7 -0
- package/dist/lib/browser/{chunk-63K74E3J.mjs → chunk-7YPIAXSW.mjs} +174 -69
- package/dist/lib/browser/chunk-7YPIAXSW.mjs.map +7 -0
- package/dist/lib/browser/{chunk-YCKJNTKG.mjs → chunk-RZLH5F56.mjs} +2 -2
- package/dist/lib/browser/{chunk-22AQ5IVX.mjs → chunk-WCNPMAR4.mjs} +2 -2
- package/dist/lib/browser/index.mjs +5 -4
- package/dist/lib/browser/index.mjs.map +2 -2
- package/dist/lib/browser/{intent-resolver-P5BVUQKU.mjs → intent-resolver-MEBOMCYI.mjs} +46 -17
- package/dist/lib/browser/intent-resolver-MEBOMCYI.mjs.map +7 -0
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/{react-root-ZQCTDM4Y.mjs → react-root-PPKFVPO7.mjs} +7 -7
- package/dist/lib/browser/{react-surface-RG3PVPY3.mjs → react-surface-7JBPPUHM.mjs} +7 -7
- package/dist/lib/browser/{settings-X3P2HKQJ.mjs → settings-DYS3FFMN.mjs} +3 -3
- package/dist/lib/browser/{state-2MOTLKVR.mjs → state-DRRCGMU2.mjs} +7 -11
- package/dist/lib/browser/state-DRRCGMU2.mjs.map +7 -0
- package/dist/lib/browser/tools-NDEUSO4R.mjs +78 -0
- package/dist/lib/browser/tools-NDEUSO4R.mjs.map +7 -0
- package/dist/lib/browser/types.mjs +10 -4
- package/dist/lib/browser/{url-handler-MVHTKUYA.mjs → url-handler-4BCN7AYC.mjs} +7 -9
- package/dist/lib/browser/url-handler-4BCN7AYC.mjs.map +7 -0
- package/dist/types/src/capabilities/capabilities.d.ts +26 -2
- 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/state.d.ts +13 -1
- 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/DeckLayout.d.ts.map +1 -1
- package/dist/types/src/components/DeckLayout/NodePlankHeading.d.ts +6 -2
- package/dist/types/src/components/DeckLayout/NodePlankHeading.d.ts.map +1 -1
- package/dist/types/src/components/DeckLayout/Plank.d.ts +4 -4
- package/dist/types/src/components/DeckLayout/Plank.d.ts.map +1 -1
- package/dist/types/src/components/DeckLayout/PlankControls.d.ts +6 -1
- package/dist/types/src/components/DeckLayout/PlankControls.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 +1 -0
- package/dist/types/src/translations.d.ts.map +1 -1
- package/dist/types/src/types.d.ts +41 -10
- package/dist/types/src/types.d.ts.map +1 -1
- package/package.json +31 -31
- package/src/capabilities/intent-resolver.ts +29 -3
- package/src/capabilities/state.ts +2 -9
- package/src/capabilities/tools.ts +34 -22
- package/src/capabilities/url-handler.ts +2 -8
- package/src/components/DeckLayout/DeckLayout.tsx +34 -10
- package/src/components/DeckLayout/NodePlankHeading.tsx +49 -29
- package/src/components/DeckLayout/Plank.tsx +181 -111
- package/src/components/DeckLayout/PlankControls.tsx +34 -3
- package/src/meta.ts +2 -2
- package/src/translations.ts +1 -0
- package/src/types.ts +29 -0
- package/dist/lib/browser/chunk-63K74E3J.mjs.map +0 -7
- package/dist/lib/browser/chunk-ATPSUXXK.mjs +0 -24
- package/dist/lib/browser/chunk-FYKBOM3C.mjs.map +0 -7
- package/dist/lib/browser/intent-resolver-P5BVUQKU.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/lib/browser/{app-graph-builder-IYHAGFA3.mjs.map → app-graph-builder-K4KVSHNT.mjs.map} +0 -0
- /package/dist/lib/browser/{check-app-scheme-S3EYUPMF.mjs.map → check-app-scheme-6SS6I3RN.mjs.map} +0 -0
- /package/dist/lib/browser/{chunk-ATPSUXXK.mjs.map → chunk-7A5DLPQ3.mjs.map} +0 -0
- /package/dist/lib/browser/{chunk-YCKJNTKG.mjs.map → chunk-RZLH5F56.mjs.map} +0 -0
- /package/dist/lib/browser/{chunk-22AQ5IVX.mjs.map → chunk-WCNPMAR4.mjs.map} +0 -0
- /package/dist/lib/browser/{react-root-ZQCTDM4Y.mjs.map → react-root-PPKFVPO7.mjs.map} +0 -0
- /package/dist/lib/browser/{react-surface-RG3PVPY3.mjs.map → react-surface-7JBPPUHM.mjs.map} +0 -0
- /package/dist/lib/browser/{settings-X3P2HKQJ.mjs.map → settings-DYS3FFMN.mjs.map} +0 -0
|
@@ -2,7 +2,16 @@
|
|
|
2
2
|
// Copyright 2024 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import React, {
|
|
5
|
+
import React, {
|
|
6
|
+
Fragment,
|
|
7
|
+
type KeyboardEvent,
|
|
8
|
+
memo,
|
|
9
|
+
type PropsWithChildren,
|
|
10
|
+
useCallback,
|
|
11
|
+
useLayoutEffect,
|
|
12
|
+
useMemo,
|
|
13
|
+
useRef,
|
|
14
|
+
} from 'react';
|
|
6
15
|
|
|
7
16
|
import {
|
|
8
17
|
createIntent,
|
|
@@ -17,133 +26,194 @@ import { useAttendableAttributes } from '@dxos/react-ui-attention';
|
|
|
17
26
|
import { StackItem, railGridHorizontal } from '@dxos/react-ui-stack';
|
|
18
27
|
import { mainIntrinsicSize, mx } from '@dxos/react-ui-theme';
|
|
19
28
|
|
|
20
|
-
import { NodePlankHeading
|
|
29
|
+
import { NodePlankHeading } from './NodePlankHeading';
|
|
21
30
|
import { PlankContentError, PlankError } from './PlankError';
|
|
22
31
|
import { PlankLoading } from './PlankLoading';
|
|
23
32
|
import { DeckCapabilities } from '../../capabilities';
|
|
24
33
|
import { useNode, useMainSize } from '../../hooks';
|
|
25
|
-
import { DeckAction, type LayoutMode } from '../../types';
|
|
34
|
+
import { DeckAction, type LayoutMode, type Part, type ResolvedPart, surfaceVariantSeparator } from '../../types';
|
|
26
35
|
|
|
27
36
|
const UNKNOWN_ID = 'unknown_id';
|
|
28
37
|
|
|
29
38
|
export type PlankProps = {
|
|
30
39
|
id?: string;
|
|
31
|
-
|
|
40
|
+
companionId?: string;
|
|
41
|
+
part: Part;
|
|
32
42
|
path?: string[];
|
|
33
43
|
order?: number;
|
|
34
44
|
active?: string[];
|
|
35
45
|
layoutMode: LayoutMode;
|
|
36
46
|
};
|
|
37
47
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
const canResize = layoutMode === 'deck';
|
|
45
|
-
const Root = part === 'solo' ? 'article' : StackItem.Root;
|
|
46
|
-
|
|
47
|
-
const attendableAttrs = useAttendableAttributes(id);
|
|
48
|
-
const index = active ? active.findIndex((entryId) => entryId === id) : 0;
|
|
49
|
-
const length = active?.length ?? 1;
|
|
50
|
-
const canIncrementStart = active && index !== undefined && index > 0 && length !== undefined && length > 1;
|
|
51
|
-
const canIncrementEnd = active && index !== undefined && index < length - 1 && length !== undefined;
|
|
52
|
-
|
|
53
|
-
const key = id.split('+')[0];
|
|
54
|
-
const size = deck.plankSizing[key] as number | undefined;
|
|
55
|
-
const setSize = useCallback(
|
|
56
|
-
debounce((nextSize: number) => {
|
|
57
|
-
return dispatch(createIntent(DeckAction.UpdatePlankSize, { id: key, size: nextSize }));
|
|
58
|
-
}, 200),
|
|
59
|
-
[dispatch, key],
|
|
60
|
-
);
|
|
61
|
-
|
|
62
|
-
// TODO(thure): Tabster’s focus group should handle moving focus to Main, but something is blocking it.
|
|
63
|
-
const handleKeyDown = useCallback((event: KeyboardEvent) => {
|
|
64
|
-
if (event.target === event.currentTarget && event.key === 'Escape') {
|
|
65
|
-
rootElement.current?.closest('main')?.focus();
|
|
66
|
-
}
|
|
67
|
-
}, []);
|
|
68
|
-
|
|
69
|
-
useLayoutEffect(() => {
|
|
70
|
-
if (scrollIntoView === id) {
|
|
71
|
-
// TODO(wittjosiah): When focused on page load, the focus is always visible.
|
|
72
|
-
// Forcing focus to something smaller than the plank prevents large focus ring in the interim.
|
|
73
|
-
const focusable = rootElement.current?.querySelector('button') || rootElement.current;
|
|
74
|
-
focusable?.focus({ preventScroll: true });
|
|
75
|
-
layoutMode === 'deck' && focusable?.scrollIntoView({ behavior: 'smooth', inline: 'center' });
|
|
76
|
-
// Clear the scroll into view state once it has been actioned.
|
|
77
|
-
void dispatch(createIntent(LayoutAction.ScrollIntoView, { part: 'current', subject: undefined }));
|
|
78
|
-
}
|
|
79
|
-
}, [id, scrollIntoView, layoutMode]);
|
|
80
|
-
|
|
81
|
-
const isSolo = layoutMode === 'solo' && part === 'solo';
|
|
82
|
-
const isAttendable = isSolo || (layoutMode === 'deck' && part === 'deck');
|
|
48
|
+
type PlankImplProps = Omit<PlankProps, 'companionId' | 'part'> & {
|
|
49
|
+
part: ResolvedPart;
|
|
50
|
+
surfaceVariant?: string;
|
|
51
|
+
companioned?: 'primary' | 'companion';
|
|
52
|
+
primaryId?: string;
|
|
53
|
+
};
|
|
83
54
|
|
|
55
|
+
const PlankImpl = memo(
|
|
56
|
+
({
|
|
57
|
+
id = UNKNOWN_ID,
|
|
58
|
+
part,
|
|
59
|
+
path,
|
|
60
|
+
order,
|
|
61
|
+
active,
|
|
62
|
+
layoutMode,
|
|
63
|
+
surfaceVariant,
|
|
64
|
+
companioned,
|
|
65
|
+
primaryId,
|
|
66
|
+
}: PlankImplProps) => {
|
|
67
|
+
const { dispatchPromise: dispatch } = useIntentDispatcher();
|
|
68
|
+
const { deck, popoverAnchorId, scrollIntoView } = useCapability(DeckCapabilities.DeckState);
|
|
69
|
+
const { graph } = useAppGraph();
|
|
70
|
+
const node = useNode(graph, id);
|
|
71
|
+
const rootElement = useRef<HTMLDivElement | null>(null);
|
|
72
|
+
const canResize = layoutMode === 'deck';
|
|
73
|
+
const Root = part.startsWith('solo') ? 'article' : StackItem.Root;
|
|
74
|
+
|
|
75
|
+
const attendableAttrs = useAttendableAttributes(id);
|
|
76
|
+
const index = active ? active.findIndex((entryId) => entryId === id) : 0;
|
|
77
|
+
const length = active?.length ?? 1;
|
|
78
|
+
const canIncrementStart = active && index !== undefined && index > 0 && length !== undefined && length > 1;
|
|
79
|
+
const canIncrementEnd = active && index !== undefined && index < length - 1 && length !== undefined;
|
|
80
|
+
|
|
81
|
+
const sizeKey = `${id.split('+')[0]}${surfaceVariant ? `${surfaceVariantSeparator}${surfaceVariant}` : ''}`;
|
|
82
|
+
const size = deck.plankSizing[sizeKey] as number | undefined;
|
|
83
|
+
const setSize = useCallback(
|
|
84
|
+
debounce((nextSize: number) => {
|
|
85
|
+
return dispatch(createIntent(DeckAction.UpdatePlankSize, { id: sizeKey, size: nextSize }));
|
|
86
|
+
}, 200),
|
|
87
|
+
[dispatch, sizeKey],
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
// TODO(thure): Tabster’s focus group should handle moving focus to Main, but something is blocking it.
|
|
91
|
+
const handleKeyDown = useCallback((event: KeyboardEvent) => {
|
|
92
|
+
if (event.target === event.currentTarget && event.key === 'Escape') {
|
|
93
|
+
rootElement.current?.closest('main')?.focus();
|
|
94
|
+
}
|
|
95
|
+
}, []);
|
|
96
|
+
|
|
97
|
+
useLayoutEffect(() => {
|
|
98
|
+
if (scrollIntoView === id) {
|
|
99
|
+
// TODO(wittjosiah): When focused on page load, the focus is always visible.
|
|
100
|
+
// Forcing focus to something smaller than the plank prevents large focus ring in the interim.
|
|
101
|
+
const focusable = rootElement.current?.querySelector('button') || rootElement.current;
|
|
102
|
+
focusable?.focus({ preventScroll: true });
|
|
103
|
+
layoutMode === 'deck' && focusable?.scrollIntoView({ behavior: 'smooth', inline: 'center' });
|
|
104
|
+
// Clear the scroll into view state once it has been actioned.
|
|
105
|
+
void dispatch(createIntent(LayoutAction.ScrollIntoView, { part: 'current', subject: undefined }));
|
|
106
|
+
}
|
|
107
|
+
}, [id, scrollIntoView, layoutMode]);
|
|
108
|
+
|
|
109
|
+
const isSolo = layoutMode === 'solo' && part === 'solo';
|
|
110
|
+
const isAttendable = isSolo || (layoutMode === 'deck' && part === 'deck');
|
|
111
|
+
|
|
112
|
+
const sizeAttrs = useMainSize();
|
|
113
|
+
|
|
114
|
+
const data = useMemo(
|
|
115
|
+
() =>
|
|
116
|
+
node && {
|
|
117
|
+
subject: node.data,
|
|
118
|
+
variant: surfaceVariant,
|
|
119
|
+
path,
|
|
120
|
+
popoverAnchorId,
|
|
121
|
+
},
|
|
122
|
+
[node, node?.data, path, popoverAnchorId, surfaceVariant],
|
|
123
|
+
);
|
|
124
|
+
|
|
125
|
+
// TODO(wittjosiah): Change prop to accept a component.
|
|
126
|
+
const placeholder = useMemo(() => <PlankLoading />, []);
|
|
127
|
+
|
|
128
|
+
const className = mx(
|
|
129
|
+
'attention-surface relative',
|
|
130
|
+
isSolo && mainIntrinsicSize,
|
|
131
|
+
isSolo && railGridHorizontal,
|
|
132
|
+
isSolo && 'grid absolute inset-0',
|
|
133
|
+
part === 'deck' && (companioned === 'companion' ? '!border-separator border-ie' : '!border-separator border-li'),
|
|
134
|
+
part.startsWith('solo-') && 'row-span-2 min-is-0',
|
|
135
|
+
part === 'solo-companion' && '!border-separator border-is',
|
|
136
|
+
);
|
|
137
|
+
|
|
138
|
+
return (
|
|
139
|
+
<Root
|
|
140
|
+
ref={rootElement}
|
|
141
|
+
data-testid='deck.plank'
|
|
142
|
+
tabIndex={0}
|
|
143
|
+
{...(part.startsWith('solo')
|
|
144
|
+
? ({ ...sizeAttrs, className } as any)
|
|
145
|
+
: {
|
|
146
|
+
item: { id },
|
|
147
|
+
size,
|
|
148
|
+
onSizeChange: setSize,
|
|
149
|
+
classNames: className,
|
|
150
|
+
order,
|
|
151
|
+
role: 'article',
|
|
152
|
+
})}
|
|
153
|
+
{...(isAttendable ? attendableAttrs : {})}
|
|
154
|
+
onKeyDown={handleKeyDown}
|
|
155
|
+
>
|
|
156
|
+
{node ? (
|
|
157
|
+
<>
|
|
158
|
+
<NodePlankHeading
|
|
159
|
+
id={id}
|
|
160
|
+
part={part.startsWith('solo-') ? 'solo' : part}
|
|
161
|
+
node={node}
|
|
162
|
+
canIncrementStart={canIncrementStart}
|
|
163
|
+
canIncrementEnd={canIncrementEnd}
|
|
164
|
+
popoverAnchorId={popoverAnchorId}
|
|
165
|
+
companioned={companioned}
|
|
166
|
+
primaryId={primaryId}
|
|
167
|
+
surfaceVariant={surfaceVariant}
|
|
168
|
+
/>
|
|
169
|
+
<Surface
|
|
170
|
+
key={node.id}
|
|
171
|
+
role='article'
|
|
172
|
+
data={data}
|
|
173
|
+
limit={1}
|
|
174
|
+
fallback={PlankContentError}
|
|
175
|
+
placeholder={placeholder}
|
|
176
|
+
/>
|
|
177
|
+
</>
|
|
178
|
+
) : (
|
|
179
|
+
<PlankError id={id} part={part} />
|
|
180
|
+
)}
|
|
181
|
+
{canResize && <StackItem.ResizeHandle />}
|
|
182
|
+
</Root>
|
|
183
|
+
);
|
|
184
|
+
},
|
|
185
|
+
);
|
|
186
|
+
|
|
187
|
+
const SplitFrame = ({ children }: PropsWithChildren<{}>) => {
|
|
84
188
|
const sizeAttrs = useMainSize();
|
|
85
|
-
|
|
86
|
-
const data = useMemo(
|
|
87
|
-
() =>
|
|
88
|
-
node && {
|
|
89
|
-
subject: node.data,
|
|
90
|
-
path,
|
|
91
|
-
popoverAnchorId,
|
|
92
|
-
},
|
|
93
|
-
[node, node?.data, path, popoverAnchorId],
|
|
94
|
-
);
|
|
95
|
-
|
|
96
|
-
// TODO(wittjosiah): Change prop to accept a component.
|
|
97
|
-
const placeholder = useMemo(() => <PlankLoading />, []);
|
|
98
|
-
|
|
99
|
-
const className = mx(
|
|
100
|
-
'attention-surface relative',
|
|
101
|
-
isSolo && mainIntrinsicSize,
|
|
102
|
-
isSolo && railGridHorizontal,
|
|
103
|
-
isSolo ? 'grid absolute inset-0' : '!border-separator border-li',
|
|
104
|
-
);
|
|
105
|
-
|
|
106
189
|
return (
|
|
107
|
-
<
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
{...(part === 'solo'
|
|
112
|
-
? ({ ...sizeAttrs, className } as any)
|
|
113
|
-
: {
|
|
114
|
-
item: { id },
|
|
115
|
-
size,
|
|
116
|
-
onSizeChange: setSize,
|
|
117
|
-
classNames: className,
|
|
118
|
-
order,
|
|
119
|
-
role: 'article',
|
|
120
|
-
})}
|
|
121
|
-
{...(isAttendable ? attendableAttrs : {})}
|
|
122
|
-
onKeyDown={handleKeyDown}
|
|
190
|
+
<div
|
|
191
|
+
role='none'
|
|
192
|
+
className={mx('grid grid-cols-[1fr_1fr] absolute inset-0', railGridHorizontal, mainIntrinsicSize)}
|
|
193
|
+
{...sizeAttrs}
|
|
123
194
|
>
|
|
124
|
-
{
|
|
125
|
-
|
|
126
|
-
<NodePlankHeading
|
|
127
|
-
id={id}
|
|
128
|
-
part={part}
|
|
129
|
-
node={node}
|
|
130
|
-
canIncrementStart={canIncrementStart}
|
|
131
|
-
canIncrementEnd={canIncrementEnd}
|
|
132
|
-
popoverAnchorId={popoverAnchorId}
|
|
133
|
-
/>
|
|
134
|
-
<Surface
|
|
135
|
-
key={node.id}
|
|
136
|
-
role='article'
|
|
137
|
-
data={data}
|
|
138
|
-
limit={1}
|
|
139
|
-
fallback={PlankContentError}
|
|
140
|
-
placeholder={placeholder}
|
|
141
|
-
/>
|
|
142
|
-
</>
|
|
143
|
-
) : (
|
|
144
|
-
<PlankError id={id} part={part} />
|
|
145
|
-
)}
|
|
146
|
-
{canResize && <StackItem.ResizeHandle />}
|
|
147
|
-
</Root>
|
|
195
|
+
{children}
|
|
196
|
+
</div>
|
|
148
197
|
);
|
|
149
|
-
}
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
export const Plank = (props: PlankProps) => {
|
|
201
|
+
if (props.companionId) {
|
|
202
|
+
const Root = props.part === 'solo' ? SplitFrame : Fragment;
|
|
203
|
+
return (
|
|
204
|
+
<Root>
|
|
205
|
+
<PlankImpl {...props} {...(props.part === 'solo' ? { part: 'solo-primary' } : {})} companioned='primary' />
|
|
206
|
+
<PlankImpl
|
|
207
|
+
{...props}
|
|
208
|
+
{...(props.companionId.startsWith(surfaceVariantSeparator)
|
|
209
|
+
? { surfaceVariant: props.companionId.substring(2) }
|
|
210
|
+
: { id: props.companionId, primaryId: props.id })}
|
|
211
|
+
{...(props.part === 'solo' ? { part: 'solo-companion' } : { order: props.order! + 1 })}
|
|
212
|
+
companioned='companion'
|
|
213
|
+
/>
|
|
214
|
+
</Root>
|
|
215
|
+
);
|
|
216
|
+
} else {
|
|
217
|
+
return <PlankImpl {...props} />;
|
|
218
|
+
}
|
|
219
|
+
};
|
|
@@ -2,8 +2,10 @@
|
|
|
2
2
|
// Copyright 2024 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import React, { forwardRef } from 'react';
|
|
5
|
+
import React, { forwardRef, useCallback } from 'react';
|
|
6
6
|
|
|
7
|
+
import { createIntent, useIntentDispatcher } from '@dxos/app-framework';
|
|
8
|
+
import { invariant } from '@dxos/invariant';
|
|
7
9
|
import {
|
|
8
10
|
Button,
|
|
9
11
|
ButtonGroup,
|
|
@@ -15,7 +17,7 @@ import {
|
|
|
15
17
|
} from '@dxos/react-ui';
|
|
16
18
|
|
|
17
19
|
import { DECK_PLUGIN } from '../../meta';
|
|
18
|
-
import {
|
|
20
|
+
import { DeckAction } from '../../types';
|
|
19
21
|
|
|
20
22
|
export type PlankControlHandler = (event: DeckAction.PartAdjustment) => void;
|
|
21
23
|
|
|
@@ -50,6 +52,34 @@ const PlankControl = ({ icon, label, ...props }: Omit<ButtonProps, 'children'> &
|
|
|
50
52
|
);
|
|
51
53
|
};
|
|
52
54
|
|
|
55
|
+
const plankControlSpacing = 'pli-2 plb-3';
|
|
56
|
+
|
|
57
|
+
type PlankComplimentControlsProps = {
|
|
58
|
+
primary?: string;
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
export const PlankCompanionControls = forwardRef<HTMLDivElement, PlankComplimentControlsProps>(
|
|
62
|
+
({ primary }, forwardedRef) => {
|
|
63
|
+
const { t } = useTranslation(DECK_PLUGIN);
|
|
64
|
+
const { dispatchPromise: dispatch } = useIntentDispatcher();
|
|
65
|
+
const handleCloseCompanion = useCallback(() => {
|
|
66
|
+
invariant(primary);
|
|
67
|
+
return dispatch(createIntent(DeckAction.ChangeCompanion, { primary, companion: null }));
|
|
68
|
+
}, []);
|
|
69
|
+
return (
|
|
70
|
+
<div ref={forwardedRef} className='contents app-no-drag'>
|
|
71
|
+
<PlankControl
|
|
72
|
+
label={t('close companion label')}
|
|
73
|
+
variant='ghost'
|
|
74
|
+
icon='ph--minus--regular'
|
|
75
|
+
onClick={handleCloseCompanion}
|
|
76
|
+
classNames={plankControlSpacing}
|
|
77
|
+
/>
|
|
78
|
+
</div>
|
|
79
|
+
);
|
|
80
|
+
},
|
|
81
|
+
);
|
|
82
|
+
|
|
53
83
|
// TODO(wittjosiah): Duplicate of stack LayoutControls?
|
|
54
84
|
// Translations were to be duplicated between packages.
|
|
55
85
|
// NOTE(thure): Pinning & unpinning are disabled indefinitely.
|
|
@@ -59,7 +89,8 @@ export const PlankControls = forwardRef<HTMLDivElement, PlankControlsProps>(
|
|
|
59
89
|
forwardedRef,
|
|
60
90
|
) => {
|
|
61
91
|
const { t } = useTranslation(DECK_PLUGIN);
|
|
62
|
-
const buttonClassNames =
|
|
92
|
+
const buttonClassNames =
|
|
93
|
+
variant === 'hide-disabled' ? `disabled:hidden ${plankControlSpacing}` : plankControlSpacing;
|
|
63
94
|
|
|
64
95
|
return (
|
|
65
96
|
<ButtonGroup {...props} classNames={['app-no-drag', classNames]} ref={forwardedRef}>
|
package/src/meta.ts
CHANGED
|
@@ -6,8 +6,8 @@ import { type PluginMeta } from '@dxos/app-framework';
|
|
|
6
6
|
|
|
7
7
|
export const DECK_PLUGIN = 'dxos.org/plugin/deck' as const;
|
|
8
8
|
|
|
9
|
-
export const meta = {
|
|
9
|
+
export const meta: PluginMeta = {
|
|
10
10
|
id: DECK_PLUGIN,
|
|
11
11
|
name: 'Deck',
|
|
12
12
|
icon: 'ph--columns--regular',
|
|
13
|
-
}
|
|
13
|
+
};
|
package/src/translations.ts
CHANGED
package/src/types.ts
CHANGED
|
@@ -17,6 +17,9 @@ export type NewPlankPositioning = (typeof NewPlankPositions)[number];
|
|
|
17
17
|
export const OverscrollOptions = ['none', 'centering'] as const;
|
|
18
18
|
export type Overscroll = (typeof OverscrollOptions)[number];
|
|
19
19
|
|
|
20
|
+
export type Part = 'solo' | 'deck' | 'complementary';
|
|
21
|
+
export type ResolvedPart = Part | 'solo-primary' | 'solo-companion';
|
|
22
|
+
|
|
20
23
|
export type Panel = {
|
|
21
24
|
id: string;
|
|
22
25
|
label: Label;
|
|
@@ -53,13 +56,31 @@ export const Deck = S.Struct({
|
|
|
53
56
|
description: "If false, the deck has not yet left solo mode and new planks should be solo'd.",
|
|
54
57
|
}),
|
|
55
58
|
active: S.mutable(S.Array(S.String)),
|
|
59
|
+
// TODO(wittjosiah): Piping into both mutable and optional caused invalid typescript output.
|
|
60
|
+
activeCompanions: S.optional(S.mutable(S.Record({ key: S.String, value: S.String }))),
|
|
56
61
|
inactive: S.mutable(S.Array(S.String)),
|
|
57
62
|
solo: S.optional(S.String),
|
|
58
63
|
fullscreen: S.Boolean,
|
|
59
64
|
plankSizing: S.mutable(PlankSizing),
|
|
65
|
+
companionFrameSizing: S.mutable(PlankSizing),
|
|
60
66
|
});
|
|
61
67
|
export type Deck = S.Schema.Type<typeof Deck>;
|
|
62
68
|
|
|
69
|
+
export const defaultDeck = {
|
|
70
|
+
initialized: false,
|
|
71
|
+
active: [],
|
|
72
|
+
activeCompanions: {},
|
|
73
|
+
inactive: [],
|
|
74
|
+
fullscreen: false,
|
|
75
|
+
solo: undefined,
|
|
76
|
+
plankSizing: {},
|
|
77
|
+
companionFrameSizing: {},
|
|
78
|
+
} satisfies Deck;
|
|
79
|
+
|
|
80
|
+
export const surfaceVariantSeparator = '--';
|
|
81
|
+
|
|
82
|
+
export const surfaceVariant = (id: string) => `${surfaceVariantSeparator}${id}`;
|
|
83
|
+
|
|
63
84
|
export const DeckState = S.mutable(
|
|
64
85
|
S.Struct({
|
|
65
86
|
sidebarState: S.Literal('closed', 'collapsed', 'expanded'),
|
|
@@ -139,4 +160,12 @@ export namespace DeckAction {
|
|
|
139
160
|
}),
|
|
140
161
|
output: S.Void,
|
|
141
162
|
}) {}
|
|
163
|
+
|
|
164
|
+
export class ChangeCompanion extends S.TaggedClass<ChangeCompanion>()(`${DECK_ACTION}/change-companion`, {
|
|
165
|
+
input: S.Struct({
|
|
166
|
+
primary: S.String,
|
|
167
|
+
companion: S.Union(S.String, S.Null),
|
|
168
|
+
}),
|
|
169
|
+
output: S.Void,
|
|
170
|
+
}) {}
|
|
142
171
|
}
|