@dxos/plugin-deck 0.8.1 → 0.8.2-main.2f9c567

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.
Files changed (93) hide show
  1. package/dist/lib/browser/{check-app-scheme-SEYECDHI.mjs → check-app-scheme-O7JPE4TM.mjs} +2 -3
  2. package/dist/lib/browser/check-app-scheme-O7JPE4TM.mjs.map +7 -0
  3. package/dist/lib/browser/{chunk-FJBMNSUC.mjs → chunk-AHTP72DY.mjs} +207 -162
  4. package/dist/lib/browser/chunk-AHTP72DY.mjs.map +7 -0
  5. package/dist/lib/browser/chunk-E7TOEOGO.mjs +157 -0
  6. package/dist/lib/browser/chunk-E7TOEOGO.mjs.map +7 -0
  7. package/dist/lib/browser/{chunk-6ZSOFCPP.mjs → chunk-PGSJT5PG.mjs} +8 -7
  8. package/dist/lib/browser/{chunk-6ZSOFCPP.mjs.map → chunk-PGSJT5PG.mjs.map} +3 -3
  9. package/dist/lib/browser/chunk-RKYIMUKW.mjs +24 -0
  10. package/dist/lib/browser/{chunk-B4LOJUWW.mjs.map → chunk-RKYIMUKW.mjs.map} +3 -3
  11. package/dist/lib/browser/index.mjs +5 -3
  12. package/dist/lib/browser/index.mjs.map +2 -2
  13. package/dist/lib/browser/{intent-resolver-UDYKO2QW.mjs → intent-resolver-NO6L67KF.mjs} +78 -53
  14. package/dist/lib/browser/intent-resolver-NO6L67KF.mjs.map +7 -0
  15. package/dist/lib/browser/meta.json +1 -1
  16. package/dist/lib/browser/{react-root-XLXN2VEW.mjs → react-root-5RWCIUXV.mjs} +5 -5
  17. package/dist/lib/browser/{react-surface-WNGMZL7I.mjs → react-surface-DIDOPTH7.mjs} +5 -5
  18. package/dist/lib/browser/{settings-HMDGSBGO.mjs → settings-C7LX2GXF.mjs} +4 -4
  19. package/dist/lib/browser/settings-C7LX2GXF.mjs.map +7 -0
  20. package/dist/lib/browser/{state-7TN26M42.mjs → state-AX74YEJD.mjs} +6 -5
  21. package/dist/lib/browser/state-AX74YEJD.mjs.map +7 -0
  22. package/dist/lib/browser/{tools-SC6QEN7R.mjs → tools-7W7KZRAX.mjs} +7 -7
  23. package/dist/lib/browser/tools-7W7KZRAX.mjs.map +7 -0
  24. package/dist/lib/browser/types.mjs +1 -1
  25. package/dist/lib/browser/{url-handler-ODG4B6NX.mjs → url-handler-AF5SYROZ.mjs} +2 -2
  26. package/dist/types/src/capabilities/app-graph-builder.d.ts.map +1 -1
  27. package/dist/types/src/capabilities/capabilities.d.ts +8 -6
  28. package/dist/types/src/capabilities/capabilities.d.ts.map +1 -1
  29. package/dist/types/src/capabilities/check-app-scheme.d.ts.map +1 -1
  30. package/dist/types/src/capabilities/index.d.ts +2 -2
  31. package/dist/types/src/capabilities/index.d.ts.map +1 -1
  32. package/dist/types/src/capabilities/intent-resolver.d.ts.map +1 -1
  33. package/dist/types/src/capabilities/state.d.ts +5 -4
  34. package/dist/types/src/capabilities/state.d.ts.map +1 -1
  35. package/dist/types/src/capabilities/tools.d.ts.map +1 -1
  36. package/dist/types/src/components/DeckLayout/ContentEmpty.d.ts.map +1 -1
  37. package/dist/types/src/components/DeckLayout/DeckLayout.d.ts.map +1 -1
  38. package/dist/types/src/components/DeckLayout/Dialog.d.ts +3 -0
  39. package/dist/types/src/components/DeckLayout/Dialog.d.ts.map +1 -0
  40. package/dist/types/src/components/DeckLayout/Popover.d.ts +5 -0
  41. package/dist/types/src/components/DeckLayout/Popover.d.ts.map +1 -0
  42. package/dist/types/src/components/Plank/Plank.d.ts.map +1 -1
  43. package/dist/types/src/components/Plank/PlankControls.d.ts +2 -2
  44. package/dist/types/src/components/Plank/PlankControls.d.ts.map +1 -1
  45. package/dist/types/src/components/Plank/PlankError.d.ts.map +1 -1
  46. package/dist/types/src/components/Plank/PlankHeading.d.ts +3 -2
  47. package/dist/types/src/components/Plank/PlankHeading.d.ts.map +1 -1
  48. package/dist/types/src/components/Sidebar/ComplementarySidebar.d.ts.map +1 -1
  49. package/dist/types/src/components/Sidebar/Sidebar.d.ts.map +1 -1
  50. package/dist/types/src/translations.d.ts +2 -0
  51. package/dist/types/src/translations.d.ts.map +1 -1
  52. package/dist/types/src/types.d.ts +106 -104
  53. package/dist/types/src/types.d.ts.map +1 -1
  54. package/dist/types/src/util/layoutAppliesTopbar.d.ts +2 -1
  55. package/dist/types/src/util/layoutAppliesTopbar.d.ts.map +1 -1
  56. package/dist/types/src/util/useHoistStatusbar.d.ts +2 -1
  57. package/dist/types/src/util/useHoistStatusbar.d.ts.map +1 -1
  58. package/package.json +31 -29
  59. package/src/capabilities/check-app-scheme.ts +3 -5
  60. package/src/capabilities/index.ts +2 -2
  61. package/src/capabilities/intent-resolver.ts +120 -96
  62. package/src/capabilities/settings.ts +2 -2
  63. package/src/capabilities/state.ts +3 -2
  64. package/src/capabilities/tools.ts +4 -3
  65. package/src/components/DeckLayout/ContentEmpty.tsx +6 -2
  66. package/src/components/DeckLayout/DeckLayout.tsx +114 -181
  67. package/src/components/DeckLayout/Dialog.tsx +36 -0
  68. package/src/components/DeckLayout/Popover.tsx +104 -0
  69. package/src/components/Plank/Plank.tsx +6 -3
  70. package/src/components/Plank/PlankControls.tsx +40 -34
  71. package/src/components/Plank/PlankError.tsx +2 -6
  72. package/src/components/Plank/PlankHeading.tsx +12 -5
  73. package/src/components/Sidebar/ComplementarySidebar.tsx +30 -20
  74. package/src/components/Sidebar/Sidebar.tsx +5 -3
  75. package/src/translations.ts +2 -0
  76. package/src/types.ts +75 -71
  77. package/src/util/layoutAppliesTopbar.ts +8 -2
  78. package/src/util/useHoistStatusbar.ts +9 -4
  79. package/dist/lib/browser/check-app-scheme-SEYECDHI.mjs.map +0 -7
  80. package/dist/lib/browser/chunk-B4LOJUWW.mjs +0 -24
  81. package/dist/lib/browser/chunk-FJBMNSUC.mjs.map +0 -7
  82. package/dist/lib/browser/chunk-RJNCG4ND.mjs +0 -154
  83. package/dist/lib/browser/chunk-RJNCG4ND.mjs.map +0 -7
  84. package/dist/lib/browser/intent-resolver-UDYKO2QW.mjs.map +0 -7
  85. package/dist/lib/browser/settings-HMDGSBGO.mjs.map +0 -7
  86. package/dist/lib/browser/state-7TN26M42.mjs.map +0 -7
  87. package/dist/lib/browser/tools-SC6QEN7R.mjs.map +0 -7
  88. package/dist/types/src/components/DeckLayout/Fullscreen.d.ts +0 -5
  89. package/dist/types/src/components/DeckLayout/Fullscreen.d.ts.map +0 -1
  90. package/src/components/DeckLayout/Fullscreen.tsx +0 -31
  91. /package/dist/lib/browser/{react-root-XLXN2VEW.mjs.map → react-root-5RWCIUXV.mjs.map} +0 -0
  92. /package/dist/lib/browser/{react-surface-WNGMZL7I.mjs.map → react-surface-DIDOPTH7.mjs.map} +0 -0
  93. /package/dist/lib/browser/{url-handler-ODG4B6NX.mjs.map → url-handler-AF5SYROZ.mjs.map} +0 -0
@@ -3,7 +3,7 @@
3
3
  //
4
4
 
5
5
  import { batch } from '@preact/signals-core';
6
- import { pipe } from 'effect';
6
+ import { Schema, Effect, pipe } from 'effect';
7
7
 
8
8
  import {
9
9
  Capabilities,
@@ -15,9 +15,9 @@ import {
15
15
  createIntent,
16
16
  chain,
17
17
  } from '@dxos/app-framework';
18
- import { getTypename, S } from '@dxos/echo-schema';
18
+ import { getTypename } from '@dxos/echo-schema';
19
19
  import { invariant } from '@dxos/invariant';
20
- import { isReactiveObject } from '@dxos/live-object';
20
+ import { isLiveObject } from '@dxos/live-object';
21
21
  import { log } from '@dxos/log';
22
22
  import { AttentionCapabilities } from '@dxos/plugin-attention';
23
23
  import { type Node } from '@dxos/plugin-graph';
@@ -67,10 +67,10 @@ export default (context: PluginsContext) =>
67
67
  }),
68
68
  createResolver({
69
69
  intent: LayoutAction.UpdateLayout,
70
- // TODO(wittjosiah): This should be able to just be `S.is(LayoutAction.UpdateSidebar.fields.input)`
70
+ // TODO(wittjosiah): This should be able to just be `Schema.is(LayoutAction.UpdateSidebar.fields.input)`
71
71
  // but the filter is not being applied correctly.
72
- filter: (data): data is S.Schema.Type<typeof LayoutAction.UpdateSidebar.fields.input> =>
73
- S.is(LayoutAction.UpdateSidebar.fields.input)(data),
72
+ filter: (data): data is Schema.Schema.Type<typeof LayoutAction.UpdateSidebar.fields.input> =>
73
+ Schema.is(LayoutAction.UpdateSidebar.fields.input)(data),
74
74
  resolve: ({ options }) => {
75
75
  const layout = context.requestCapability(DeckCapabilities.MutableDeckState);
76
76
  const next = options?.state ?? layout.sidebarState;
@@ -81,10 +81,10 @@ export default (context: PluginsContext) =>
81
81
  }),
82
82
  createResolver({
83
83
  intent: LayoutAction.UpdateLayout,
84
- // TODO(wittjosiah): This should be able to just be `S.is(LayoutAction.UpdateComplementary.fields.input)`
84
+ // TODO(wittjosiah): This should be able to just be `Schema.is(LayoutAction.UpdateComplementary.fields.input)`
85
85
  // but the filter is not being applied correctly.
86
- filter: (data): data is S.Schema.Type<typeof LayoutAction.UpdateComplementary.fields.input> =>
87
- S.is(LayoutAction.UpdateComplementary.fields.input)(data),
86
+ filter: (data): data is Schema.Schema.Type<typeof LayoutAction.UpdateComplementary.fields.input> =>
87
+ Schema.is(LayoutAction.UpdateComplementary.fields.input)(data),
88
88
  resolve: ({ subject, options }) => {
89
89
  const layout = context.requestCapability(DeckCapabilities.MutableDeckState);
90
90
 
@@ -100,10 +100,10 @@ export default (context: PluginsContext) =>
100
100
  }),
101
101
  createResolver({
102
102
  intent: LayoutAction.UpdateLayout,
103
- // TODO(wittjosiah): This should be able to just be `S.is(LayoutAction.UpdateDialog.fields.input)`
103
+ // TODO(wittjosiah): This should be able to just be `Schema.is(LayoutAction.UpdateDialog.fields.input)`
104
104
  // but the filter is not being applied correctly.
105
- filter: (data): data is S.Schema.Type<typeof LayoutAction.UpdateDialog.fields.input> =>
106
- S.is(LayoutAction.UpdateDialog.fields.input)(data),
105
+ filter: (data): data is Schema.Schema.Type<typeof LayoutAction.UpdateDialog.fields.input> =>
106
+ Schema.is(LayoutAction.UpdateDialog.fields.input)(data),
107
107
  resolve: ({ subject, options }) => {
108
108
  const layout = context.requestCapability(DeckCapabilities.MutableDeckState);
109
109
  layout.dialogOpen = options.state ?? Boolean(subject);
@@ -114,24 +114,29 @@ export default (context: PluginsContext) =>
114
114
  }),
115
115
  createResolver({
116
116
  intent: LayoutAction.UpdateLayout,
117
- // TODO(wittjosiah): This should be able to just be `S.is(LayoutAction.UpdatePopover.fields.input)`
117
+ // TODO(wittjosiah): This should be able to just be `Schema.is(LayoutAction.UpdatePopover.fields.input)`
118
118
  // but the filter is not being applied correctly.
119
- filter: (data): data is S.Schema.Type<typeof LayoutAction.UpdatePopover.fields.input> =>
120
- S.is(LayoutAction.UpdatePopover.fields.input)(data),
119
+ filter: (data): data is Schema.Schema.Type<typeof LayoutAction.UpdatePopover.fields.input> =>
120
+ Schema.is(LayoutAction.UpdatePopover.fields.input)(data),
121
121
  resolve: ({ subject, options }) => {
122
122
  const layout = context.requestCapability(DeckCapabilities.MutableDeckState);
123
123
  layout.popoverOpen = options.state ?? Boolean(subject);
124
- layout.popoverContent = subject ? { component: subject, props: options.props } : null;
125
- layout.popoverAnchorId = options.anchorId;
124
+ layout.popoverContent =
125
+ typeof subject === 'string' ? { component: subject, props: options.props } : subject ? { subject } : null;
126
126
  layout.popoverSide = options.side;
127
+ if (options.variant === 'virtual') {
128
+ layout.popoverAnchor = options.anchor;
129
+ } else {
130
+ layout.popoverAnchorId = options.anchorId;
131
+ }
127
132
  },
128
133
  }),
129
134
  createResolver({
130
135
  intent: LayoutAction.UpdateLayout,
131
- // TODO(wittjosiah): This should be able to just be `S.is(LayoutAction.AddToast.fields.input)`
136
+ // TODO(wittjosiah): This should be able to just be `Schema.is(LayoutAction.AddToast.fields.input)`
132
137
  // but the filter is not being applied correctly.
133
- filter: (data): data is S.Schema.Type<typeof LayoutAction.AddToast.fields.input> =>
134
- S.is(LayoutAction.AddToast.fields.input)(data),
138
+ filter: (data): data is Schema.Schema.Type<typeof LayoutAction.AddToast.fields.input> =>
139
+ Schema.is(LayoutAction.AddToast.fields.input)(data),
135
140
  resolve: ({ subject }) => {
136
141
  const layout = context.requestCapability(DeckCapabilities.MutableDeckState);
137
142
  layout.toasts.push(subject);
@@ -139,10 +144,10 @@ export default (context: PluginsContext) =>
139
144
  }),
140
145
  createResolver({
141
146
  intent: LayoutAction.UpdateLayout,
142
- // TODO(wittjosiah): This should be able to just be `S.is(LayoutAction.SetLayoutMode.fields.input)`
147
+ // TODO(wittjosiah): This should be able to just be `Schema.is(LayoutAction.SetLayoutMode.fields.input)`
143
148
  // but the filter is not being applied correctly.
144
- filter: (data): data is S.Schema.Type<typeof LayoutAction.SetLayoutMode.fields.input> => {
145
- if (!S.is(LayoutAction.SetLayoutMode.fields.input)(data)) {
149
+ filter: (data): data is Schema.Schema.Type<typeof LayoutAction.SetLayoutMode.fields.input> => {
150
+ if (!Schema.is(LayoutAction.SetLayoutMode.fields.input)(data)) {
146
151
  return false;
147
152
  }
148
153
 
@@ -174,10 +179,8 @@ export default (context: PluginsContext) =>
174
179
  deck.initialized = true;
175
180
  }
176
181
 
177
- if (mode === 'fullscreen' && !deck.fullscreen) {
178
- deck.fullscreen = true;
179
- } else if (mode !== 'fullscreen' && deck.fullscreen) {
180
- deck.fullscreen = false;
182
+ if (mode === 'solo--fullscreen') {
183
+ deck.fullscreen = !deck.fullscreen;
181
184
  }
182
185
  };
183
186
 
@@ -199,8 +202,8 @@ export default (context: PluginsContext) =>
199
202
  }),
200
203
  createResolver({
201
204
  intent: LayoutAction.UpdateLayout,
202
- filter: (data): data is S.Schema.Type<typeof LayoutAction.SwitchWorkspace.fields.input> =>
203
- S.is(LayoutAction.SwitchWorkspace.fields.input)(data),
205
+ filter: (data): data is Schema.Schema.Type<typeof LayoutAction.SwitchWorkspace.fields.input> =>
206
+ Schema.is(LayoutAction.SwitchWorkspace.fields.input)(data),
204
207
  resolve: ({ subject }) => {
205
208
  const state = context.requestCapability(DeckCapabilities.MutableDeckState);
206
209
  batch(() => {
@@ -225,8 +228,8 @@ export default (context: PluginsContext) =>
225
228
  }),
226
229
  createResolver({
227
230
  intent: LayoutAction.UpdateLayout,
228
- filter: (data): data is S.Schema.Type<typeof LayoutAction.RevertWorkspace.fields.input> =>
229
- S.is(LayoutAction.RevertWorkspace.fields.input)(data),
231
+ filter: (data): data is Schema.Schema.Type<typeof LayoutAction.RevertWorkspace.fields.input> =>
232
+ Schema.is(LayoutAction.RevertWorkspace.fields.input)(data),
230
233
  resolve: () => {
231
234
  const state = context.requestCapability(DeckCapabilities.MutableDeckState);
232
235
  return {
@@ -236,62 +239,70 @@ export default (context: PluginsContext) =>
236
239
  }),
237
240
  createResolver({
238
241
  intent: LayoutAction.UpdateLayout,
239
- filter: (data): data is S.Schema.Type<typeof LayoutAction.Open.fields.input> =>
240
- S.is(LayoutAction.Open.fields.input)(data),
241
- resolve: ({ subject, options }) => {
242
- const { graph } = context.requestCapability(Capabilities.AppGraph);
243
- const state = context.requestCapability(DeckCapabilities.MutableDeckState);
244
- const attention = context.requestCapability(AttentionCapabilities.Attention);
245
- const settings = context
246
- .requestCapabilities(Capabilities.SettingsStore)[0]
247
- ?.getStore<DeckSettingsProps>(DECK_PLUGIN)?.value;
242
+ filter: (data): data is Schema.Schema.Type<typeof LayoutAction.Open.fields.input> =>
243
+ Schema.is(LayoutAction.Open.fields.input)(data),
244
+ resolve: ({ subject, options }) =>
245
+ Effect.gen(function* () {
246
+ const { graph } = context.requestCapability(Capabilities.AppGraph);
247
+ const state = context.requestCapability(DeckCapabilities.MutableDeckState);
248
+ const attention = context.requestCapability(AttentionCapabilities.Attention);
249
+ const settings = context
250
+ .requestCapabilities(Capabilities.SettingsStore)[0]
251
+ ?.getStore<DeckSettingsProps>(DECK_PLUGIN)?.value;
248
252
 
249
- const previouslyOpenIds = new Set<string>(state.deck.solo ? [state.deck.solo] : state.deck.active);
250
- batch(() => {
251
- const next = state.deck.solo
252
- ? (subject as string[]).map((id) => createEntryId(id, options?.variant))
253
- : subject.reduce(
254
- (acc, entryId) =>
255
- openEntry(acc, entryId, {
256
- key: options?.key,
257
- positioning: options?.positioning ?? settings?.newPlankPositioning,
258
- pivotId: options?.pivotId,
259
- variant: options?.variant,
260
- }),
261
- state.deck.active,
262
- );
253
+ if (options?.workspace && state.activeDeck !== options?.workspace) {
254
+ const { dispatch } = context.requestCapability(Capabilities.IntentDispatcher);
255
+ yield* dispatch(
256
+ createIntent(LayoutAction.SwitchWorkspace, { part: 'workspace', subject: options.workspace }),
257
+ );
258
+ }
263
259
 
264
- return setActive({ next, state, attention });
265
- });
260
+ const previouslyOpenIds = new Set<string>(state.deck.solo ? [state.deck.solo] : state.deck.active);
261
+ batch(() => {
262
+ const next = state.deck.solo
263
+ ? (subject as string[]).map((id) => createEntryId(id, options?.variant))
264
+ : subject.reduce(
265
+ (acc, entryId) =>
266
+ openEntry(acc, entryId, {
267
+ key: options?.key,
268
+ positioning: options?.positioning ?? settings?.newPlankPositioning,
269
+ pivotId: options?.pivotId,
270
+ variant: options?.variant,
271
+ }),
272
+ state.deck.active,
273
+ );
266
274
 
267
- const ids = state.deck.solo ? [state.deck.solo] : state.deck.active;
268
- const newlyOpen = ids.filter((i) => !previouslyOpenIds.has(i));
275
+ return setActive({ next, state, attention });
276
+ });
269
277
 
270
- return {
271
- intents: [
272
- ...(options?.scrollIntoView !== false
273
- ? [createIntent(LayoutAction.ScrollIntoView, { part: 'current', subject: newlyOpen[0] ?? subject[0] })]
274
- : []),
275
- createIntent(LayoutAction.Expose, { part: 'navigation', subject: newlyOpen[0] ?? subject[0] }),
276
- ...newlyOpen.map((subjectId) => {
277
- const active = graph?.findNode(subjectId)?.data;
278
- const typename = isReactiveObject(active) ? getTypename(active) : undefined;
279
- return createIntent(ObservabilityAction.SendEvent, {
280
- name: 'navigation.activate',
281
- properties: {
282
- subjectId,
283
- typename,
284
- },
285
- });
286
- }),
287
- ],
288
- };
289
- },
278
+ const ids = state.deck.solo ? [state.deck.solo] : state.deck.active;
279
+ const newlyOpen = ids.filter((i) => !previouslyOpenIds.has(i));
280
+
281
+ return {
282
+ intents: [
283
+ ...(options?.scrollIntoView !== false
284
+ ? [createIntent(LayoutAction.ScrollIntoView, { part: 'current', subject: newlyOpen[0] ?? subject[0] })]
285
+ : []),
286
+ createIntent(LayoutAction.Expose, { part: 'navigation', subject: newlyOpen[0] ?? subject[0] }),
287
+ ...newlyOpen.map((subjectId) => {
288
+ const active = graph?.findNode(subjectId)?.data;
289
+ const typename = isLiveObject(active) ? getTypename(active) : undefined;
290
+ return createIntent(ObservabilityAction.SendEvent, {
291
+ name: 'navigation.activate',
292
+ properties: {
293
+ subjectId,
294
+ typename,
295
+ },
296
+ });
297
+ }),
298
+ ],
299
+ };
300
+ }),
290
301
  }),
291
302
  createResolver({
292
303
  intent: LayoutAction.UpdateLayout,
293
- filter: (data): data is S.Schema.Type<typeof LayoutAction.Close.fields.input> =>
294
- S.is(LayoutAction.Close.fields.input)(data),
304
+ filter: (data): data is Schema.Schema.Type<typeof LayoutAction.Close.fields.input> =>
305
+ Schema.is(LayoutAction.Close.fields.input)(data),
295
306
  resolve: ({ subject }) => {
296
307
  const state = context.requestCapability(DeckCapabilities.MutableDeckState);
297
308
  const attention = context.requestCapability(AttentionCapabilities.Attention);
@@ -313,8 +324,8 @@ export default (context: PluginsContext) =>
313
324
  }),
314
325
  createResolver({
315
326
  intent: LayoutAction.UpdateLayout,
316
- filter: (data): data is S.Schema.Type<typeof LayoutAction.Set.fields.input> =>
317
- S.is(LayoutAction.Set.fields.input)(data),
327
+ filter: (data): data is Schema.Schema.Type<typeof LayoutAction.Set.fields.input> =>
328
+ Schema.is(LayoutAction.Set.fields.input)(data),
318
329
  resolve: ({ subject }) => {
319
330
  const state = context.requestCapability(DeckCapabilities.MutableDeckState);
320
331
  const attention = context.requestCapability(AttentionCapabilities.Attention);
@@ -326,8 +337,8 @@ export default (context: PluginsContext) =>
326
337
  }),
327
338
  createResolver({
328
339
  intent: LayoutAction.UpdateLayout,
329
- filter: (data): data is S.Schema.Type<typeof LayoutAction.ScrollIntoView.fields.input> =>
330
- S.is(LayoutAction.ScrollIntoView.fields.input)(data),
340
+ filter: (data): data is Schema.Schema.Type<typeof LayoutAction.ScrollIntoView.fields.input> =>
341
+ Schema.is(LayoutAction.ScrollIntoView.fields.input)(data),
331
342
  resolve: ({ subject }) => {
332
343
  const layout = context.requestCapability(DeckCapabilities.MutableDeckState);
333
344
  layout.scrollIntoView = subject;
@@ -390,7 +401,7 @@ export default (context: PluginsContext) =>
390
401
  }
391
402
  }
392
403
 
393
- if (adjustment.type === 'solo') {
404
+ if (adjustment.type.startsWith('solo')) {
394
405
  const entryId = adjustment.id;
395
406
  if (!state.deck.solo) {
396
407
  // Solo the entry.
@@ -399,21 +410,34 @@ export default (context: PluginsContext) =>
399
410
  createIntent(LayoutAction.SetLayoutMode, {
400
411
  part: 'mode',
401
412
  subject: entryId,
402
- options: { mode: 'solo' },
413
+ options: { mode: adjustment.type },
403
414
  }),
404
415
  ],
405
416
  };
406
417
  } else {
407
- // Un-solo the current entry.
408
- return {
409
- intents: [
410
- // NOTE: The order of these is important.
411
- pipe(
412
- createIntent(LayoutAction.SetLayoutMode, { part: 'mode', options: { mode: 'deck' } }),
413
- chain(LayoutAction.Open, { part: 'main', subject: [entryId] }),
414
- ),
415
- ],
416
- };
418
+ if (adjustment.type === 'solo--fullscreen') {
419
+ // Toggle fullscreen on the current entry.
420
+ return {
421
+ intents: [
422
+ createIntent(LayoutAction.SetLayoutMode, {
423
+ part: 'mode',
424
+ subject: entryId,
425
+ options: { mode: 'solo--fullscreen' },
426
+ }),
427
+ ],
428
+ };
429
+ } else if (adjustment.type === 'solo') {
430
+ // Un-solo the current entry.
431
+ return {
432
+ intents: [
433
+ // NOTE: The order of these is important.
434
+ pipe(
435
+ createIntent(LayoutAction.SetLayoutMode, { part: 'mode', options: { mode: 'deck' } }),
436
+ chain(LayoutAction.Open, { part: 'main', subject: [entryId] }),
437
+ ),
438
+ ],
439
+ };
440
+ }
417
441
  }
418
442
  }
419
443
  });
@@ -3,13 +3,13 @@
3
3
  //
4
4
 
5
5
  import { Capabilities, contributes } from '@dxos/app-framework';
6
- import { create } from '@dxos/live-object';
6
+ import { live } from '@dxos/live-object';
7
7
 
8
8
  import { DECK_PLUGIN } from '../meta';
9
9
  import { DeckSettingsSchema, type DeckSettingsProps } from '../types';
10
10
 
11
11
  export default () => {
12
- const settings = create<DeckSettingsProps>({
12
+ const settings = live<DeckSettingsProps>({
13
13
  showHints: false,
14
14
  enableDeck: true,
15
15
  enableNativeRedirect: false,
@@ -4,7 +4,7 @@
4
4
 
5
5
  import { Capabilities, contributes } from '@dxos/app-framework';
6
6
  import { invariant } from '@dxos/invariant';
7
- import { create } from '@dxos/live-object';
7
+ import { live } from '@dxos/live-object';
8
8
  import { LocalStorageStore } from '@dxos/local-storage';
9
9
  import { type SidebarState } from '@dxos/react-ui';
10
10
 
@@ -41,6 +41,7 @@ export default () => {
41
41
  dialogBlockAlign: undefined,
42
42
  dialogType: undefined,
43
43
  popoverContent: null,
44
+ popoverAnchor: undefined,
44
45
  popoverAnchorId: undefined,
45
46
  popoverOpen: false,
46
47
  toasts: [],
@@ -67,7 +68,7 @@ export default () => {
67
68
  .prop({ key: 'activeDeck', type: LocalStorageStore.string() })
68
69
  .prop({ key: 'previousDeck', type: LocalStorageStore.string() });
69
70
 
70
- const layout = create<Capabilities.Layout>({
71
+ const layout = live<Capabilities.Layout>({
71
72
  get mode() {
72
73
  return getMode(state.values.deck);
73
74
  },
@@ -2,6 +2,8 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
+ import { Schema } from 'effect';
6
+
5
7
  import {
6
8
  contributes,
7
9
  createIntent,
@@ -10,7 +12,6 @@ import {
10
12
  type PromiseIntentDispatcher,
11
13
  } from '@dxos/app-framework';
12
14
  import { defineTool, ToolResult } from '@dxos/artifact';
13
- import { S } from '@dxos/echo-schema';
14
15
  import { invariant } from '@dxos/invariant';
15
16
 
16
17
  import { meta } from '../meta';
@@ -35,8 +36,8 @@ export default () =>
35
36
  `,
36
37
  caption: 'Showing item...',
37
38
  // TODO(wittjosiah): Refactor Layout/Navigation/Deck actions so that they can be used directly.
38
- schema: S.Struct({
39
- id: S.String.annotations({
39
+ schema: Schema.Struct({
40
+ id: Schema.String.annotations({
40
41
  description: 'The ID of the item to show.',
41
42
  }),
42
43
  }),
@@ -4,15 +4,19 @@
4
4
 
5
5
  import React from 'react';
6
6
 
7
- import { Surface } from '@dxos/app-framework';
7
+ import { Surface, useCapability } from '@dxos/app-framework';
8
8
 
9
+ import { DeckCapabilities } from '../../capabilities';
10
+ import { getMode } from '../../types';
9
11
  import { layoutAppliesTopbar, useBreakpoints } from '../../util';
10
12
  import { ToggleSidebarButton } from '../Sidebar';
11
13
  import { fixedSidebarToggleStyles } from '../fragments';
12
14
 
13
15
  export const ContentEmpty = () => {
14
16
  const breakpoint = useBreakpoints();
15
- const topbar = layoutAppliesTopbar(breakpoint);
17
+ const { deck } = useCapability(DeckCapabilities.MutableDeckState);
18
+ const layoutMode = getMode(deck);
19
+ const topbar = layoutAppliesTopbar(breakpoint, layoutMode);
16
20
  return (
17
21
  <div
18
22
  role='none'