@dxos/plugin-deck 0.7.4-staging.f7e8224 → 0.7.5-main.499c70c
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-ZC3K6C2W.mjs +37 -0
- package/dist/lib/browser/chunk-ZC3K6C2W.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +392 -420
- package/dist/lib/browser/index.mjs.map +3 -3
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/types.mjs +6 -1
- package/dist/types/src/DeckPlugin.d.ts +1 -10
- package/dist/types/src/DeckPlugin.d.ts.map +1 -1
- package/dist/types/src/components/DeckLayout/ComplementarySidebar.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.map +1 -1
- 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/Sidebar.d.ts.map +1 -1
- package/dist/types/src/components/DeckLayout/Toast.d.ts.map +1 -1
- package/dist/types/src/translations.d.ts +3 -0
- package/dist/types/src/translations.d.ts.map +1 -1
- package/dist/types/src/types.d.ts +16 -0
- package/dist/types/src/types.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -0
- package/package.json +29 -28
- package/src/DeckPlugin.tsx +222 -256
- package/src/components/DeckLayout/ActiveNode.tsx +1 -1
- package/src/components/DeckLayout/ComplementarySidebar.tsx +4 -3
- package/src/components/DeckLayout/DeckLayout.tsx +3 -7
- package/src/components/DeckLayout/Fullscreen.tsx +1 -1
- package/src/components/DeckLayout/NodePlankHeading.tsx +15 -29
- package/src/components/DeckLayout/Plank.tsx +7 -5
- package/src/components/DeckLayout/PlankControls.tsx +3 -5
- package/src/components/DeckLayout/Sidebar.tsx +4 -21
- package/src/components/DeckLayout/Toast.tsx +19 -6
- package/src/translations.ts +3 -0
- package/src/types.ts +15 -0
- package/dist/lib/browser/chunk-NIRHDTX4.mjs +0 -17
- package/dist/lib/browser/chunk-NIRHDTX4.mjs.map +0 -7
package/src/DeckPlugin.tsx
CHANGED
|
@@ -3,18 +3,18 @@
|
|
|
3
3
|
//
|
|
4
4
|
|
|
5
5
|
import { batch } from '@preact/signals-core';
|
|
6
|
+
import { pipe } from 'effect';
|
|
6
7
|
import { setAutoFreeze } from 'immer';
|
|
7
8
|
import React, { type PropsWithChildren } from 'react';
|
|
8
9
|
|
|
9
10
|
import {
|
|
11
|
+
chain,
|
|
12
|
+
createIntent,
|
|
13
|
+
createResolver,
|
|
14
|
+
createSurface,
|
|
10
15
|
filterPlugins,
|
|
11
|
-
type GraphProvides,
|
|
12
16
|
IntentAction,
|
|
13
|
-
type IntentData,
|
|
14
17
|
type IntentPluginProvides,
|
|
15
|
-
isLayoutAdjustment,
|
|
16
|
-
isLayoutMode,
|
|
17
|
-
isLayoutParts,
|
|
18
18
|
type Layout,
|
|
19
19
|
LayoutAction,
|
|
20
20
|
type LayoutEntry,
|
|
@@ -32,15 +32,15 @@ import {
|
|
|
32
32
|
Toast as ToastSchema,
|
|
33
33
|
} from '@dxos/app-framework';
|
|
34
34
|
import { type UnsubscribeCallback } from '@dxos/async';
|
|
35
|
-
import { getTypename } from '@dxos/echo-schema';
|
|
35
|
+
import { getTypename, S } from '@dxos/echo-schema';
|
|
36
36
|
import { scheduledEffect } from '@dxos/echo-signals/core';
|
|
37
|
+
import { invariant } from '@dxos/invariant';
|
|
37
38
|
import { create, isReactiveObject } from '@dxos/live-object';
|
|
38
39
|
import { LocalStorageStore } from '@dxos/local-storage';
|
|
39
40
|
import { log } from '@dxos/log';
|
|
40
41
|
import { type AttentionPluginProvides, parseAttentionPlugin } from '@dxos/plugin-attention';
|
|
41
|
-
import { createExtension, type Node } from '@dxos/plugin-graph';
|
|
42
|
-
import { ObservabilityAction } from '@dxos/plugin-observability/
|
|
43
|
-
import { fullyQualifiedId } from '@dxos/react-client/echo';
|
|
42
|
+
import { createExtension, ROOT_ID, type Node } from '@dxos/plugin-graph';
|
|
43
|
+
import { ObservabilityAction } from '@dxos/plugin-observability/types';
|
|
44
44
|
import { translations as stackTranslations } from '@dxos/react-ui-stack';
|
|
45
45
|
|
|
46
46
|
import { DeckContext, type DeckContextType, DeckLayout, LayoutContext, LayoutSettings, NAV_ID } from './components';
|
|
@@ -56,6 +56,7 @@ import {
|
|
|
56
56
|
import meta, { DECK_PLUGIN } from './meta';
|
|
57
57
|
import translations from './translations';
|
|
58
58
|
import {
|
|
59
|
+
DeckAction,
|
|
59
60
|
type DeckPluginProvides,
|
|
60
61
|
type DeckSettingsProps,
|
|
61
62
|
type NewPlankPositioning,
|
|
@@ -75,25 +76,11 @@ const appScheme = 'composer://';
|
|
|
75
76
|
// TODO(Zan): Move this to a more global location if we use immer more broadly.
|
|
76
77
|
setAutoFreeze(false);
|
|
77
78
|
|
|
78
|
-
//
|
|
79
|
-
// Intents
|
|
80
|
-
//
|
|
81
|
-
const DECK_ACTION = 'dxos.org/plugin/deck';
|
|
82
|
-
|
|
83
|
-
export enum DeckAction {
|
|
84
|
-
UPDATE_PLANK_SIZE = `${DECK_ACTION}/update-plank-size`,
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
export namespace DeckAction {
|
|
88
|
-
export type UpdatePlankSize = IntentData<{ id: string; size: number }>;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
79
|
export const DeckPlugin = ({
|
|
92
80
|
observability,
|
|
93
81
|
}: {
|
|
94
82
|
observability?: boolean;
|
|
95
83
|
} = {}): PluginDefinition<DeckPluginProvides> => {
|
|
96
|
-
let graphPlugin: Plugin<GraphProvides> | undefined;
|
|
97
84
|
let intentPlugin: Plugin<IntentPluginProvides> | undefined;
|
|
98
85
|
let attentionPlugin: Plugin<AttentionPluginProvides> | undefined;
|
|
99
86
|
const unsubscriptionCallbacks = [] as (UnsubscribeCallback | undefined)[];
|
|
@@ -149,18 +136,18 @@ export const DeckPlugin = ({
|
|
|
149
136
|
anchorId,
|
|
150
137
|
dialogBlockAlign,
|
|
151
138
|
dialogType,
|
|
152
|
-
}: LayoutAction.SetLayout) => {
|
|
139
|
+
}: LayoutAction.SetLayout['input']) => {
|
|
153
140
|
switch (element) {
|
|
154
141
|
case 'sidebar': {
|
|
155
142
|
layout.values.sidebarOpen = state ?? !layout.values.sidebarOpen;
|
|
156
|
-
|
|
143
|
+
break;
|
|
157
144
|
}
|
|
158
145
|
|
|
159
146
|
case 'complementary': {
|
|
160
147
|
layout.values.complementarySidebarOpen = !!state;
|
|
161
148
|
// TODO(thure): Hoist content into the c11y sidebar of Deck.
|
|
162
149
|
// layout.values.complementarySidebarContent = component || subject ? { component, subject } : null;
|
|
163
|
-
|
|
150
|
+
break;
|
|
164
151
|
}
|
|
165
152
|
|
|
166
153
|
case 'dialog': {
|
|
@@ -168,32 +155,39 @@ export const DeckPlugin = ({
|
|
|
168
155
|
layout.values.dialogContent = component ? { component, subject } : null;
|
|
169
156
|
layout.values.dialogBlockAlign = dialogBlockAlign ?? 'center';
|
|
170
157
|
layout.values.dialogType = dialogType;
|
|
171
|
-
|
|
158
|
+
break;
|
|
172
159
|
}
|
|
173
160
|
|
|
174
161
|
case 'popover': {
|
|
175
162
|
layout.values.popoverOpen = state ?? Boolean(component);
|
|
176
163
|
layout.values.popoverContent = component ? { component, subject } : null;
|
|
177
164
|
layout.values.popoverAnchorId = anchorId;
|
|
178
|
-
|
|
165
|
+
break;
|
|
179
166
|
}
|
|
180
167
|
|
|
181
168
|
case 'toast': {
|
|
182
|
-
if (
|
|
169
|
+
if (S.is(ToastSchema)(subject)) {
|
|
183
170
|
layout.values.toasts = [...layout.values.toasts, subject];
|
|
184
|
-
return { data: true };
|
|
185
171
|
}
|
|
172
|
+
break;
|
|
186
173
|
}
|
|
187
174
|
}
|
|
188
175
|
};
|
|
189
176
|
|
|
190
177
|
/**
|
|
191
|
-
* Update the active state and
|
|
178
|
+
* Update the active state and returns the id of the next attended plank.
|
|
192
179
|
*/
|
|
193
180
|
const handleSetLocation = (next: LayoutParts) => {
|
|
194
181
|
const part = layout.values.layoutMode === 'solo' ? 'solo' : 'main';
|
|
195
182
|
const ids = openIds(next, [part]);
|
|
196
183
|
|
|
184
|
+
const current = openIds(location.values.active, [part]);
|
|
185
|
+
const removed = current.filter((id) => !ids.includes(id));
|
|
186
|
+
const closed = Array.from(new Set([...location.values.closed.filter((id) => !ids.includes(id)), ...removed]));
|
|
187
|
+
|
|
188
|
+
location.values.closed = closed;
|
|
189
|
+
location.values.active = next;
|
|
190
|
+
|
|
197
191
|
if (attentionPlugin) {
|
|
198
192
|
const attended = attentionPlugin.provides.attention.attended;
|
|
199
193
|
const [attendedId] = Array.from(attended);
|
|
@@ -203,28 +197,17 @@ export const DeckPlugin = ({
|
|
|
203
197
|
const attendedIndex = currentIds.indexOf(attendedId);
|
|
204
198
|
// If outside of bounds, focus on the first/last plank, otherwise focus on the new plank in the same position.
|
|
205
199
|
const index = attendedIndex === -1 ? 0 : attendedIndex >= ids.length ? ids.length - 1 : attendedIndex;
|
|
206
|
-
|
|
207
|
-
void intentPlugin?.provides.intent.dispatch({
|
|
208
|
-
action: LayoutAction.SCROLL_INTO_VIEW,
|
|
209
|
-
data: { id: nextAttended },
|
|
210
|
-
});
|
|
200
|
+
return next[part]?.[index].id;
|
|
211
201
|
}
|
|
212
202
|
}
|
|
213
|
-
|
|
214
|
-
const current = openIds(location.values.active, [part]);
|
|
215
|
-
const removed = current.filter((id) => !ids.includes(id));
|
|
216
|
-
const closed = Array.from(new Set([...location.values.closed.filter((id) => !ids.includes(id)), ...removed]));
|
|
217
|
-
|
|
218
|
-
location.values.closed = closed;
|
|
219
|
-
location.values.active = next;
|
|
220
203
|
};
|
|
221
204
|
|
|
222
205
|
return {
|
|
223
206
|
meta,
|
|
224
|
-
ready: async (plugins) => {
|
|
225
|
-
intentPlugin = resolvePlugin(plugins, parseIntentPlugin);
|
|
226
|
-
graphPlugin = resolvePlugin(plugins, parseGraphPlugin);
|
|
207
|
+
ready: async ({ plugins }) => {
|
|
227
208
|
attentionPlugin = resolvePlugin(plugins, parseAttentionPlugin);
|
|
209
|
+
intentPlugin = resolvePlugin(plugins, parseIntentPlugin);
|
|
210
|
+
const dispatch = intentPlugin?.provides.intent.dispatchPromise;
|
|
228
211
|
|
|
229
212
|
layout
|
|
230
213
|
.prop({ key: 'layoutMode', type: LocalStorageStore.enum<LayoutMode>() })
|
|
@@ -267,13 +250,15 @@ export const DeckPlugin = ({
|
|
|
267
250
|
const startingLayout = removePart(location.values.active, 'solo');
|
|
268
251
|
const layoutFromUri = uriToSoloPart(pathname);
|
|
269
252
|
if (!layoutFromUri) {
|
|
270
|
-
handleSetLocation(startingLayout);
|
|
253
|
+
const toAttend = handleSetLocation(startingLayout);
|
|
271
254
|
layout.values.layoutMode = 'deck';
|
|
255
|
+
await dispatch?.(createIntent(LayoutAction.ScrollIntoView, { id: toAttend }));
|
|
272
256
|
return;
|
|
273
257
|
}
|
|
274
258
|
|
|
275
|
-
handleSetLocation(mergeLayoutParts(layoutFromUri, startingLayout));
|
|
259
|
+
const toAttend = handleSetLocation(mergeLayoutParts(layoutFromUri, startingLayout));
|
|
276
260
|
layout.values.layoutMode = 'solo';
|
|
261
|
+
await dispatch?.(createIntent(LayoutAction.ScrollIntoView, { id: toAttend }));
|
|
277
262
|
};
|
|
278
263
|
|
|
279
264
|
await handleNavigation();
|
|
@@ -303,22 +288,24 @@ export const DeckPlugin = ({
|
|
|
303
288
|
location: location.values,
|
|
304
289
|
translations: [...translations, ...stackTranslations],
|
|
305
290
|
graph: {
|
|
306
|
-
builder: () => {
|
|
291
|
+
builder: (plugins) => {
|
|
292
|
+
const dispatch = resolvePlugin(plugins, parseIntentPlugin)?.provides.intent.dispatchPromise;
|
|
293
|
+
const attention = resolvePlugin(plugins, parseAttentionPlugin)?.provides.attention;
|
|
294
|
+
|
|
295
|
+
invariant(dispatch, 'Intent plugin is required for deck plugin.');
|
|
296
|
+
invariant(attention, 'Attention plugin is required for deck plugin.');
|
|
297
|
+
|
|
307
298
|
// TODO(burdon): Root menu isn't visible so nothing bound.
|
|
308
299
|
return createExtension({
|
|
309
300
|
id: DECK_PLUGIN,
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
{
|
|
315
|
-
id: `${LayoutAction.
|
|
301
|
+
filter: (node): node is Node<null> => node.id === ROOT_ID,
|
|
302
|
+
actions: () => {
|
|
303
|
+
// NOTE(Zan): This is currently disabled.
|
|
304
|
+
// TODO(Zan): Fullscreen needs to know the active node and provide that to the layout part.
|
|
305
|
+
const _fullscreen = {
|
|
306
|
+
id: `${LayoutAction.SetLayoutMode._tag}/fullscreen`,
|
|
316
307
|
data: async () => {
|
|
317
|
-
await
|
|
318
|
-
plugin: DECK_PLUGIN,
|
|
319
|
-
action: LayoutAction.SET_LAYOUT_MODE,
|
|
320
|
-
data: { layoutMode: 'fullscreen' },
|
|
321
|
-
});
|
|
308
|
+
await dispatch(createIntent(LayoutAction.SetLayoutMode, { layoutMode: 'fullscreen' }));
|
|
322
309
|
},
|
|
323
310
|
properties: {
|
|
324
311
|
label: ['toggle fullscreen label', { ns: DECK_PLUGIN }],
|
|
@@ -328,8 +315,56 @@ export const DeckPlugin = ({
|
|
|
328
315
|
windows: 'shift+ctrl+f',
|
|
329
316
|
},
|
|
330
317
|
},
|
|
331
|
-
}
|
|
332
|
-
|
|
318
|
+
};
|
|
319
|
+
|
|
320
|
+
const closeCurrent = {
|
|
321
|
+
id: `${NavigationAction.Close._tag}/current`,
|
|
322
|
+
data: async () => {
|
|
323
|
+
const attended = attention.attended.at(-1);
|
|
324
|
+
if (attended) {
|
|
325
|
+
await dispatch(createIntent(NavigationAction.Close, { activeParts: { main: [attended] } }));
|
|
326
|
+
}
|
|
327
|
+
},
|
|
328
|
+
properties: {
|
|
329
|
+
label: ['close current label', { ns: DECK_PLUGIN }],
|
|
330
|
+
icon: 'ph--x--regular',
|
|
331
|
+
},
|
|
332
|
+
};
|
|
333
|
+
|
|
334
|
+
const closeOthers = {
|
|
335
|
+
id: `${NavigationAction.Close._tag}/others`,
|
|
336
|
+
data: async () => {
|
|
337
|
+
const attended = attention.attended.at(-1);
|
|
338
|
+
const ids = openIds(location.values.active, ['main']).filter((id) => id !== attended);
|
|
339
|
+
await dispatch(
|
|
340
|
+
createIntent(NavigationAction.Close, {
|
|
341
|
+
activeParts: { main: ids },
|
|
342
|
+
}),
|
|
343
|
+
);
|
|
344
|
+
},
|
|
345
|
+
properties: {
|
|
346
|
+
label: ['close others label', { ns: DECK_PLUGIN }],
|
|
347
|
+
icon: 'ph--x-square--regular',
|
|
348
|
+
},
|
|
349
|
+
};
|
|
350
|
+
|
|
351
|
+
const closeAll = {
|
|
352
|
+
id: `${NavigationAction.Close._tag}/all`,
|
|
353
|
+
data: async () => {
|
|
354
|
+
await dispatch(
|
|
355
|
+
createIntent(NavigationAction.Close, {
|
|
356
|
+
activeParts: { main: openIds(location.values.active, ['main']) },
|
|
357
|
+
}),
|
|
358
|
+
);
|
|
359
|
+
},
|
|
360
|
+
properties: {
|
|
361
|
+
label: ['close all label', { ns: DECK_PLUGIN }],
|
|
362
|
+
icon: 'ph--x-circle--regular',
|
|
363
|
+
},
|
|
364
|
+
};
|
|
365
|
+
|
|
366
|
+
return layout.values.layoutMode === 'deck' ? [closeCurrent, closeOthers, closeAll] : [];
|
|
367
|
+
},
|
|
333
368
|
});
|
|
334
369
|
},
|
|
335
370
|
},
|
|
@@ -363,22 +398,43 @@ export const DeckPlugin = ({
|
|
|
363
398
|
);
|
|
364
399
|
},
|
|
365
400
|
surface: {
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
401
|
+
definitions: () =>
|
|
402
|
+
createSurface({
|
|
403
|
+
id: DECK_PLUGIN,
|
|
404
|
+
role: 'settings',
|
|
405
|
+
filter: (data): data is any => data.subject === DECK_PLUGIN,
|
|
406
|
+
component: () => <LayoutSettings settings={settings.values} />,
|
|
407
|
+
}),
|
|
373
408
|
},
|
|
374
409
|
intent: {
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
410
|
+
resolvers: ({ plugins }) => {
|
|
411
|
+
const graph = resolvePlugin(plugins, parseGraphPlugin)?.provides.graph;
|
|
412
|
+
|
|
413
|
+
return [
|
|
414
|
+
createResolver(DeckAction.UpdatePlankSize, (data) => {
|
|
415
|
+
deck.values.plankSizing[data.id] = data.size;
|
|
416
|
+
}),
|
|
417
|
+
createResolver(IntentAction.ShowUndo, (data) => {
|
|
418
|
+
// TODO(wittjosiah): Support undoing further back than the last action.
|
|
419
|
+
if (currentUndoId) {
|
|
420
|
+
layout.values.toasts = layout.values.toasts.filter((toast) => toast.id !== currentUndoId);
|
|
421
|
+
}
|
|
422
|
+
currentUndoId = `${IntentAction.ShowUndo._tag}-${Date.now()}`;
|
|
423
|
+
layout.values.toasts = [
|
|
424
|
+
...layout.values.toasts,
|
|
425
|
+
{
|
|
426
|
+
id: currentUndoId,
|
|
427
|
+
title: data.message ?? ['undo available label', { ns: DECK_PLUGIN }],
|
|
428
|
+
duration: 10_000,
|
|
429
|
+
actionLabel: ['undo action label', { ns: DECK_PLUGIN }],
|
|
430
|
+
actionAlt: ['undo action alt', { ns: DECK_PLUGIN }],
|
|
431
|
+
closeLabel: ['undo close label', { ns: DECK_PLUGIN }],
|
|
432
|
+
onAction: () => intentPlugin?.provides.intent.undoPromise?.(),
|
|
433
|
+
},
|
|
434
|
+
];
|
|
435
|
+
}),
|
|
436
|
+
createResolver(LayoutAction.SetLayout, handleSetLayout),
|
|
437
|
+
createResolver(LayoutAction.SetLayoutMode, (data) => {
|
|
382
438
|
const setMode = (mode: LayoutMode) => {
|
|
383
439
|
const main = openIds(location.values.active, ['main']);
|
|
384
440
|
const solo = openIds(location.values.active, ['solo']);
|
|
@@ -394,72 +450,25 @@ export const DeckPlugin = ({
|
|
|
394
450
|
layout.values.layoutMode = mode;
|
|
395
451
|
};
|
|
396
452
|
|
|
397
|
-
// TODO(wittjosiah): Update closed state.
|
|
398
453
|
return batch(() => {
|
|
399
|
-
if (
|
|
400
|
-
return;
|
|
401
|
-
}
|
|
402
|
-
|
|
403
|
-
if (intent.data?.revert) {
|
|
404
|
-
setMode(layoutModeHistory.values.pop() ?? 'solo');
|
|
405
|
-
return { data: true };
|
|
406
|
-
}
|
|
407
|
-
|
|
408
|
-
if (isLayoutMode(intent?.data?.layoutMode)) {
|
|
454
|
+
if ('layoutMode' in data) {
|
|
409
455
|
layoutModeHistory.values.push(layout.values.layoutMode);
|
|
410
|
-
setMode(
|
|
456
|
+
setMode(data.layoutMode);
|
|
457
|
+
} else if (data.revert) {
|
|
458
|
+
setMode(layoutModeHistory.values.pop() ?? 'solo');
|
|
411
459
|
} else {
|
|
412
|
-
log.warn('Invalid layout mode',
|
|
460
|
+
log.warn('Invalid layout mode', data);
|
|
413
461
|
}
|
|
414
|
-
|
|
415
|
-
return { data: true };
|
|
416
462
|
});
|
|
417
|
-
}
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
case DeckAction.UPDATE_PLANK_SIZE: {
|
|
425
|
-
const { id, size } = intent.data as DeckAction.UpdatePlankSize;
|
|
426
|
-
deck.values.plankSizing[id] = size;
|
|
427
|
-
return { data: true };
|
|
428
|
-
}
|
|
429
|
-
|
|
430
|
-
case IntentAction.SHOW_UNDO: {
|
|
431
|
-
// TODO(wittjosiah): Support undoing further back than the last action.
|
|
432
|
-
if (currentUndoId) {
|
|
433
|
-
layout.values.toasts = layout.values.toasts.filter((toast) => toast.id !== currentUndoId);
|
|
434
|
-
}
|
|
435
|
-
currentUndoId = `${IntentAction.SHOW_UNDO}-${Date.now()}`;
|
|
436
|
-
const title =
|
|
437
|
-
// TODO(wittjosiah): How to handle chains better?
|
|
438
|
-
intent.data?.results?.[0]?.result?.undoable?.message ??
|
|
439
|
-
translations[0]['en-US']['dxos.org/plugin/deck']['undo available label'];
|
|
440
|
-
layout.values.toasts = [
|
|
441
|
-
...layout.values.toasts,
|
|
442
|
-
{
|
|
443
|
-
id: currentUndoId,
|
|
444
|
-
title,
|
|
445
|
-
duration: 10_000,
|
|
446
|
-
actionLabel: translations[0]['en-US']['dxos.org/plugin/deck']['undo action label'],
|
|
447
|
-
actionAlt: translations[0]['en-US']['dxos.org/plugin/deck']['undo action alt'],
|
|
448
|
-
closeLabel: translations[0]['en-US']['dxos.org/plugin/deck']['undo close label'],
|
|
449
|
-
onAction: () => intentPlugin?.provides.intent.undo?.(),
|
|
450
|
-
},
|
|
451
|
-
];
|
|
452
|
-
return { data: true };
|
|
453
|
-
}
|
|
454
|
-
|
|
455
|
-
case NavigationAction.OPEN: {
|
|
463
|
+
}),
|
|
464
|
+
createResolver(LayoutAction.ScrollIntoView, ({ id }) => {
|
|
465
|
+
layout.values.scrollIntoView = id;
|
|
466
|
+
}),
|
|
467
|
+
// TODO(wittjosiah): Factor out navgiation from deck plugin.
|
|
468
|
+
createResolver(NavigationAction.Open, (data) => {
|
|
456
469
|
const previouslyOpenIds = new Set<string>(openIds(location.values.active));
|
|
457
470
|
const layoutMode = layout.values.layoutMode;
|
|
458
|
-
batch(() => {
|
|
459
|
-
if (!intent.data || !intent.data?.activeParts) {
|
|
460
|
-
return;
|
|
461
|
-
}
|
|
462
|
-
|
|
471
|
+
const toAttend = batch(() => {
|
|
463
472
|
const processLayoutEntry = (partName: string, entryString: string, currentLayout: any) => {
|
|
464
473
|
// TODO(burdon): Option to toggle?
|
|
465
474
|
const toggle = false;
|
|
@@ -471,7 +480,7 @@ export const DeckPlugin = ({
|
|
|
471
480
|
layoutMode === 'deck' &&
|
|
472
481
|
effectivePart === 'main' &&
|
|
473
482
|
currentLayout[effectivePart]?.some((entry: LayoutEntry) => entry.id === id) &&
|
|
474
|
-
!
|
|
483
|
+
!data?.noToggle
|
|
475
484
|
) {
|
|
476
485
|
// If we're in deck mode and the main part is already open, toggle it closed.
|
|
477
486
|
return closeEntry(currentLayout, { part: effectivePart as LayoutPart, entryId: id });
|
|
@@ -483,7 +492,7 @@ export const DeckPlugin = ({
|
|
|
483
492
|
};
|
|
484
493
|
|
|
485
494
|
let newLayout = location.values.active;
|
|
486
|
-
Object.entries(
|
|
495
|
+
Object.entries(data.activeParts).forEach(([partName, layoutEntries]) => {
|
|
487
496
|
if (Array.isArray(layoutEntries)) {
|
|
488
497
|
layoutEntries.forEach((activePartEntry: string) => {
|
|
489
498
|
newLayout = processLayoutEntry(partName, activePartEntry, newLayout);
|
|
@@ -494,53 +503,34 @@ export const DeckPlugin = ({
|
|
|
494
503
|
}
|
|
495
504
|
});
|
|
496
505
|
|
|
497
|
-
handleSetLocation(newLayout);
|
|
506
|
+
return handleSetLocation(newLayout);
|
|
498
507
|
});
|
|
499
508
|
|
|
500
509
|
const ids = openIds(location.values.active);
|
|
501
510
|
const newlyOpen = ids.filter((i) => !previouslyOpenIds.has(i));
|
|
502
511
|
|
|
503
512
|
return {
|
|
504
|
-
data: { ids },
|
|
513
|
+
data: { open: ids },
|
|
505
514
|
intents: [
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
action: LayoutAction.SCROLL_INTO_VIEW,
|
|
510
|
-
data: { id: newlyOpen[0] },
|
|
511
|
-
},
|
|
512
|
-
]
|
|
513
|
-
: [],
|
|
514
|
-
intent.data?.object
|
|
515
|
-
? [
|
|
516
|
-
{
|
|
517
|
-
action: NavigationAction.EXPOSE,
|
|
518
|
-
data: { id: fullyQualifiedId(intent.data.object) },
|
|
519
|
-
},
|
|
520
|
-
]
|
|
521
|
-
: [],
|
|
522
|
-
observability
|
|
515
|
+
createIntent(LayoutAction.ScrollIntoView, { id: newlyOpen[0] ?? toAttend }),
|
|
516
|
+
...(toAttend ? [createIntent(NavigationAction.Expose, { id: toAttend })] : []),
|
|
517
|
+
...(observability
|
|
523
518
|
? newlyOpen.map((id) => {
|
|
524
|
-
const active =
|
|
519
|
+
const active = graph?.findNode(id)?.data;
|
|
525
520
|
const typename = isReactiveObject(active) ? getTypename(active) : undefined;
|
|
526
|
-
return {
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
id,
|
|
532
|
-
typename,
|
|
533
|
-
},
|
|
521
|
+
return createIntent(ObservabilityAction.SendEvent, {
|
|
522
|
+
name: 'navigation.activate',
|
|
523
|
+
properties: {
|
|
524
|
+
id,
|
|
525
|
+
typename,
|
|
534
526
|
},
|
|
535
|
-
};
|
|
527
|
+
});
|
|
536
528
|
})
|
|
537
|
-
: [],
|
|
529
|
+
: []),
|
|
538
530
|
],
|
|
539
531
|
};
|
|
540
|
-
}
|
|
541
|
-
|
|
542
|
-
case NavigationAction.ADD_TO_ACTIVE: {
|
|
543
|
-
const data = intent.data as NavigationAction.AddToActive;
|
|
532
|
+
}),
|
|
533
|
+
createResolver(NavigationAction.AddToActive, (data) => {
|
|
544
534
|
const layoutEntry = { id: data.id };
|
|
545
535
|
const effectivePart = getEffectivePart(data.part, layout.values.layoutMode);
|
|
546
536
|
|
|
@@ -553,103 +543,79 @@ export const DeckPlugin = ({
|
|
|
553
543
|
|
|
554
544
|
const intents = [];
|
|
555
545
|
if (data.scrollIntoView && layout.values.layoutMode === 'deck') {
|
|
556
|
-
intents.push(
|
|
557
|
-
{
|
|
558
|
-
action: LayoutAction.SCROLL_INTO_VIEW,
|
|
559
|
-
data: { id: data.id },
|
|
560
|
-
},
|
|
561
|
-
]);
|
|
546
|
+
intents.push(createIntent(LayoutAction.ScrollIntoView, { id: data.id }));
|
|
562
547
|
}
|
|
563
548
|
|
|
564
|
-
return {
|
|
565
|
-
}
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
549
|
+
return { intents };
|
|
550
|
+
}),
|
|
551
|
+
createResolver(NavigationAction.Close, (data) => {
|
|
552
|
+
let newLayout = location.values.active;
|
|
553
|
+
const layoutMode = layout.values.layoutMode;
|
|
554
|
+
const intentParts = data.activeParts;
|
|
555
|
+
Object.keys(intentParts).forEach((partName: string) => {
|
|
556
|
+
const effectivePart = getEffectivePart(partName as LayoutPart, layoutMode);
|
|
557
|
+
const ids = intentParts[partName];
|
|
558
|
+
if (Array.isArray(ids)) {
|
|
559
|
+
ids.forEach((id: string) => {
|
|
560
|
+
newLayout = closeEntry(newLayout, { part: effectivePart, entryId: id });
|
|
561
|
+
});
|
|
562
|
+
} else {
|
|
563
|
+
// Legacy single string entry
|
|
564
|
+
newLayout = closeEntry(newLayout, { part: effectivePart, entryId: ids });
|
|
571
565
|
}
|
|
572
|
-
let newLayout = location.values.active;
|
|
573
|
-
const layoutMode = layout.values.layoutMode;
|
|
574
|
-
const intentParts = intent.data.activeParts;
|
|
575
|
-
Object.keys(intentParts).forEach((partName: string) => {
|
|
576
|
-
const effectivePart = getEffectivePart(partName as LayoutPart, layoutMode);
|
|
577
|
-
const ids = intentParts[partName];
|
|
578
|
-
if (Array.isArray(ids)) {
|
|
579
|
-
ids.forEach((id: string) => {
|
|
580
|
-
newLayout = closeEntry(newLayout, { part: effectivePart, entryId: id });
|
|
581
|
-
});
|
|
582
|
-
} else {
|
|
583
|
-
// Legacy single string entry
|
|
584
|
-
newLayout = closeEntry(newLayout, { part: effectivePart, entryId: ids });
|
|
585
|
-
}
|
|
586
|
-
});
|
|
587
|
-
|
|
588
|
-
handleSetLocation(newLayout);
|
|
589
|
-
return { data: true };
|
|
590
566
|
});
|
|
591
|
-
}
|
|
592
567
|
|
|
593
|
-
|
|
594
|
-
|
|
568
|
+
const toAttend = handleSetLocation(newLayout);
|
|
569
|
+
return { intents: [createIntent(LayoutAction.ScrollIntoView, { id: toAttend })] };
|
|
570
|
+
}),
|
|
571
|
+
createResolver(NavigationAction.Set, (data) => {
|
|
595
572
|
return batch(() => {
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
}
|
|
599
|
-
return { data: true };
|
|
573
|
+
const toAttend = handleSetLocation(data.activeParts);
|
|
574
|
+
return { intents: [createIntent(LayoutAction.ScrollIntoView, { id: toAttend })] };
|
|
600
575
|
});
|
|
601
|
-
}
|
|
602
|
-
|
|
603
|
-
case NavigationAction.ADJUST: {
|
|
576
|
+
}),
|
|
577
|
+
createResolver(NavigationAction.Adjust, (adjustment) => {
|
|
604
578
|
return batch(() => {
|
|
605
|
-
if (
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
);
|
|
614
|
-
}
|
|
579
|
+
if (adjustment.type === 'increment-end' || adjustment.type === 'increment-start') {
|
|
580
|
+
handleSetLocation(
|
|
581
|
+
incrementPlank(location.values.active, {
|
|
582
|
+
type: adjustment.type,
|
|
583
|
+
layoutCoordinate: adjustment.layoutCoordinate,
|
|
584
|
+
}),
|
|
585
|
+
);
|
|
586
|
+
}
|
|
615
587
|
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
[
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
[
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
},
|
|
643
|
-
{ action: LayoutAction.SCROLL_INTO_VIEW, data: { id: entryId } },
|
|
644
|
-
],
|
|
645
|
-
],
|
|
646
|
-
};
|
|
647
|
-
}
|
|
588
|
+
if (adjustment.type === 'solo') {
|
|
589
|
+
const entryId = adjustment.layoutCoordinate.entryId;
|
|
590
|
+
if (layout.values.layoutMode !== 'solo') {
|
|
591
|
+
// Solo the entry.
|
|
592
|
+
return {
|
|
593
|
+
intents: [
|
|
594
|
+
// NOTE: The order of these is important.
|
|
595
|
+
pipe(
|
|
596
|
+
createIntent(NavigationAction.Open, { activeParts: { solo: [entryId] } }),
|
|
597
|
+
chain(LayoutAction.SetLayoutMode, { layoutMode: 'solo' }),
|
|
598
|
+
),
|
|
599
|
+
],
|
|
600
|
+
};
|
|
601
|
+
} else {
|
|
602
|
+
// Un-solo the current entry.
|
|
603
|
+
return {
|
|
604
|
+
intents: [
|
|
605
|
+
// NOTE: The order of these is important.
|
|
606
|
+
pipe(
|
|
607
|
+
createIntent(LayoutAction.SetLayoutMode, { layoutMode: 'deck' }),
|
|
608
|
+
chain(NavigationAction.Close, { activeParts: { solo: [entryId] } }),
|
|
609
|
+
chain(NavigationAction.Open, { activeParts: { main: [entryId] }, noToggle: true }),
|
|
610
|
+
chain(LayoutAction.ScrollIntoView, { id: entryId }),
|
|
611
|
+
),
|
|
612
|
+
],
|
|
613
|
+
};
|
|
648
614
|
}
|
|
649
615
|
}
|
|
650
616
|
});
|
|
651
|
-
}
|
|
652
|
-
|
|
617
|
+
}),
|
|
618
|
+
];
|
|
653
619
|
},
|
|
654
620
|
},
|
|
655
621
|
},
|