@dxos/plugin-deck 0.6.13 → 0.6.14-main.1366248

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 (57) hide show
  1. package/dist/lib/browser/{chunk-YVHGFQQR.mjs → chunk-GVOGPULO.mjs} +1 -1
  2. package/dist/lib/browser/chunk-GVOGPULO.mjs.map +7 -0
  3. package/dist/lib/browser/chunk-NIRHDTX4.mjs +17 -0
  4. package/dist/lib/browser/chunk-NIRHDTX4.mjs.map +7 -0
  5. package/dist/lib/browser/index.mjs +334 -314
  6. package/dist/lib/browser/index.mjs.map +4 -4
  7. package/dist/lib/browser/meta.json +1 -1
  8. package/dist/lib/browser/meta.mjs +1 -1
  9. package/dist/lib/browser/types.mjs +11 -0
  10. package/dist/lib/browser/types.mjs.map +7 -0
  11. package/dist/types/src/DeckPlugin.d.ts.map +1 -1
  12. package/dist/types/src/components/DeckLayout/ActiveNode.d.ts +1 -3
  13. package/dist/types/src/components/DeckLayout/ActiveNode.d.ts.map +1 -1
  14. package/dist/types/src/components/DeckLayout/ComplementarySidebar.d.ts +4 -4
  15. package/dist/types/src/components/DeckLayout/ComplementarySidebar.d.ts.map +1 -1
  16. package/dist/types/src/components/DeckLayout/DeckLayout.d.ts +5 -5
  17. package/dist/types/src/components/DeckLayout/DeckLayout.d.ts.map +1 -1
  18. package/dist/types/src/components/DeckLayout/NodePlankHeading.d.ts +9 -7
  19. package/dist/types/src/components/DeckLayout/NodePlankHeading.d.ts.map +1 -1
  20. package/dist/types/src/components/DeckLayout/Plank.d.ts +2 -2
  21. package/dist/types/src/components/DeckLayout/Plank.d.ts.map +1 -1
  22. package/dist/types/src/components/DeckLayout/PlankError.d.ts +1 -2
  23. package/dist/types/src/components/DeckLayout/PlankError.d.ts.map +1 -1
  24. package/dist/types/src/components/DeckLayout/Sidebar.d.ts +2 -3
  25. package/dist/types/src/components/DeckLayout/Sidebar.d.ts.map +1 -1
  26. package/dist/types/src/components/DeckLayout/StatusBar.d.ts +3 -1
  27. package/dist/types/src/components/DeckLayout/StatusBar.d.ts.map +1 -1
  28. package/dist/types/src/components/DeckLayout/Toast.d.ts.map +1 -1
  29. package/dist/types/src/components/LayoutSettings.d.ts.map +1 -1
  30. package/dist/types/src/hooks/useNode.d.ts.map +1 -1
  31. package/dist/types/src/layout.d.ts.map +1 -1
  32. package/dist/types/src/meta.d.ts.map +1 -1
  33. package/dist/types/src/translations.d.ts +1 -3
  34. package/dist/types/src/translations.d.ts.map +1 -1
  35. package/dist/types/src/types.d.ts +14 -2
  36. package/dist/types/src/types.d.ts.map +1 -1
  37. package/dist/types/src/util/overscroll.d.ts +1 -1
  38. package/dist/types/src/util/overscroll.d.ts.map +1 -1
  39. package/package.json +42 -33
  40. package/src/DeckPlugin.tsx +104 -80
  41. package/src/components/DeckLayout/ActiveNode.tsx +4 -1
  42. package/src/components/DeckLayout/ComplementarySidebar.tsx +59 -28
  43. package/src/components/DeckLayout/DeckLayout.tsx +67 -98
  44. package/src/components/DeckLayout/NodePlankHeading.tsx +130 -127
  45. package/src/components/DeckLayout/Plank.tsx +48 -32
  46. package/src/components/DeckLayout/PlankError.tsx +1 -9
  47. package/src/components/DeckLayout/Sidebar.tsx +7 -8
  48. package/src/components/DeckLayout/StatusBar.tsx +12 -3
  49. package/src/components/DeckLayout/Toast.tsx +3 -3
  50. package/src/components/LayoutSettings.tsx +17 -20
  51. package/src/hooks/useNode.ts +5 -1
  52. package/src/layout.ts +1 -0
  53. package/src/meta.ts +3 -1
  54. package/src/translations.ts +1 -3
  55. package/src/types.ts +16 -1
  56. package/src/util/overscroll.ts +5 -5
  57. package/dist/lib/browser/chunk-YVHGFQQR.mjs.map +0 -7
@@ -1,15 +1,20 @@
1
1
  import {
2
2
  DECK_PLUGIN,
3
3
  meta_default
4
- } from "./chunk-YVHGFQQR.mjs";
4
+ } from "./chunk-GVOGPULO.mjs";
5
+ import {
6
+ NewPlankPositions,
7
+ OverscrollOptions,
8
+ parsePanelPlugin
9
+ } from "./chunk-NIRHDTX4.mjs";
5
10
 
6
11
  // packages/plugins/plugin-deck/src/DeckPlugin.tsx
7
- import { ArrowsOut } from "@phosphor-icons/react";
8
- import { batch, effect } from "@preact/signals-core";
12
+ import { batch } from "@preact/signals-core";
9
13
  import { setAutoFreeze } from "immer";
10
14
  import React15 from "react";
11
- import { IntentAction, LayoutAction as LayoutAction3, NavigationAction as NavigationAction3, parseGraphPlugin, parseIntentPlugin, resolvePlugin, Toast as ToastSchema, SLUG_PATH_SEPARATOR as SLUG_PATH_SEPARATOR5, isLayoutParts, isLayoutAdjustment, isLayoutMode, openIds as openIds2 } from "@dxos/app-framework";
15
+ import { IntentAction, LayoutAction as LayoutAction3, NavigationAction as NavigationAction4, parseGraphPlugin, parseIntentPlugin, resolvePlugin, Toast as ToastSchema, SLUG_PATH_SEPARATOR as SLUG_PATH_SEPARATOR4, isLayoutParts, isLayoutAdjustment, isLayoutMode, openIds as openIds2, filterPlugins } from "@dxos/app-framework";
12
16
  import { create, getTypename, isReactiveObject } from "@dxos/echo-schema";
17
+ import { scheduledEffect } from "@dxos/echo-signals/core";
13
18
  import { LocalStorageStore } from "@dxos/local-storage";
14
19
  import { log } from "@dxos/log";
15
20
  import { parseAttentionPlugin } from "@dxos/plugin-attention";
@@ -18,7 +23,6 @@ import { createExtension } from "@dxos/plugin-graph";
18
23
  import { ObservabilityAction } from "@dxos/plugin-observability/meta";
19
24
  import { fullyQualifiedId } from "@dxos/react-client/echo";
20
25
  import { translations as deckTranslations } from "@dxos/react-ui-deck";
21
- import { Mosaic } from "@dxos/react-ui-mosaic";
22
26
 
23
27
  // packages/plugins/plugin-deck/src/components/DeckLayout/constants.ts
24
28
  var NAV_ID = "NavTree";
@@ -26,22 +30,27 @@ var SURFACE_PREFIX = "surface:";
26
30
 
27
31
  // packages/plugins/plugin-deck/src/components/DeckLayout/DeckLayout.tsx
28
32
  import { Sidebar as MenuIcon } from "@phosphor-icons/react";
29
- import React13, { useCallback as useCallback2, useEffect as useEffect5, useMemo as useMemo2, useRef as useRef2, useState as useState3, useLayoutEffect as useLayoutEffect2 } from "react";
30
- import { SLUG_PATH_SEPARATOR as SLUG_PATH_SEPARATOR3, Surface as Surface9, firstIdInPart, usePlugin } from "@dxos/app-framework";
31
- import { Button as Button3, Dialog, Main as Main3, Popover as Popover2, useTranslation as useTranslation5 } from "@dxos/react-ui";
33
+ import { untracked } from "@preact/signals-core";
34
+ import React13, { useCallback as useCallback2, useEffect as useEffect5, useMemo as useMemo5, useRef as useRef2 } from "react";
35
+ import { Surface as Surface9, firstIdInPart, usePlugin } from "@dxos/app-framework";
36
+ import { Button as Button3, Dialog, Main as Main3, Popover as Popover2, useOnTransition, useTranslation as useTranslation5 } from "@dxos/react-ui";
32
37
  import { Deck } from "@dxos/react-ui-deck";
33
- import { getSize } from "@dxos/react-ui-theme";
38
+ import { getSize, mainPaddingTransitions as mainPaddingTransitions2 } from "@dxos/react-ui-theme";
34
39
 
35
40
  // packages/plugins/plugin-deck/src/components/DeckLayout/ActiveNode.tsx
36
41
  import React from "react";
37
42
  import { Surface } from "@dxos/app-framework";
38
43
  import { useGraph } from "@dxos/plugin-graph";
44
+ import { useAttended } from "@dxos/react-ui-attention";
39
45
 
40
46
  // packages/plugins/plugin-deck/src/hooks/useNode.ts
41
47
  import { useEffect, useState } from "react";
42
48
  var useNode = (graph, id, timeout) => {
43
- const [nodeState, setNodeState] = useState(id ? graph.findNode(id) : void 0);
49
+ const [nodeState, setNodeState] = useState(id ? graph.findNode(id, false) : void 0);
44
50
  useEffect(() => {
51
+ if (!id && nodeState) {
52
+ setNodeState(void 0);
53
+ }
45
54
  if (nodeState?.id === id || !id) {
46
55
  return;
47
56
  }
@@ -96,7 +105,8 @@ var useMainSize = () => {
96
105
  };
97
106
 
98
107
  // packages/plugins/plugin-deck/src/components/DeckLayout/ActiveNode.tsx
99
- var ActiveNode = ({ id }) => {
108
+ var ActiveNode = () => {
109
+ const [id] = useAttended();
100
110
  const { graph } = useGraph();
101
111
  const activeNode = useNode(graph, id);
102
112
  useNodeActionExpander(activeNode);
@@ -113,36 +123,25 @@ var ActiveNode = ({ id }) => {
113
123
  };
114
124
 
115
125
  // packages/plugins/plugin-deck/src/components/DeckLayout/ComplementarySidebar.tsx
116
- import React5 from "react";
117
- import { SLUG_PATH_SEPARATOR as SLUG_PATH_SEPARATOR2, Surface as Surface3 } from "@dxos/app-framework";
126
+ import React5, { useMemo as useMemo2 } from "react";
127
+ import { NavigationAction as NavigationAction2, SLUG_PATH_SEPARATOR as SLUG_PATH_SEPARATOR2, Surface as Surface3, useIntentDispatcher as useIntentDispatcher2 } from "@dxos/app-framework";
118
128
  import { useGraph as useGraph3 } from "@dxos/plugin-graph";
119
129
  import { Main } from "@dxos/react-ui";
120
- import { createAttendableAttributes } from "@dxos/react-ui-attention";
130
+ import { useAttended as useAttended2 } from "@dxos/react-ui-attention";
121
131
  import { deckGrid } from "@dxos/react-ui-deck";
122
132
  import { mx as mx2 } from "@dxos/react-ui-theme";
123
133
 
124
134
  // packages/plugins/plugin-deck/src/components/DeckLayout/NodePlankHeading.tsx
125
- import { Placeholder } from "@phosphor-icons/react";
126
- import React2, { Fragment, useEffect as useEffect3 } from "react";
127
- import { LayoutAction, NavigationAction, SLUG_COLLECTION_INDICATOR, SLUG_PATH_SEPARATOR, Surface as Surface2, useIntentDispatcher, indexInPart, partLength } from "@dxos/app-framework";
135
+ import React2, { Fragment, memo, useEffect as useEffect3, useMemo } from "react";
136
+ import { LayoutAction, NavigationAction, SLUG_PATH_SEPARATOR, Surface as Surface2, useIntentDispatcher } from "@dxos/app-framework";
128
137
  import { useGraph as useGraph2 } from "@dxos/plugin-graph";
129
- import { Popover, toLocalizedString, useMediaQuery, useTranslation } from "@dxos/react-ui";
130
- import { PlankHeading, plankHeadingIconProps } from "@dxos/react-ui-deck";
138
+ import { Icon, Popover, toLocalizedString, useMediaQuery, useTranslation } from "@dxos/react-ui";
139
+ import { PlankHeading } from "@dxos/react-ui-deck";
131
140
  import { TextTooltip } from "@dxos/react-ui-text-tooltip";
132
- var NodePlankHeading = ({
133
- node,
134
- id,
135
- layoutParts,
136
- layoutPart,
137
- // TODO(wittjosiah): Unused?
138
- layoutEntry,
139
- popoverAnchorId,
140
- pending,
141
- flatDeck
142
- }) => {
141
+ var NodePlankHeading = /* @__PURE__ */ memo(({ coordinate, node, canIncrementStart, canIncrementEnd, popoverAnchorId, pending, flatDeck, actions = [] }) => {
143
142
  const { t } = useTranslation(DECK_PLUGIN);
144
143
  const { graph } = useGraph2();
145
- const Icon = node?.properties?.icon ?? Placeholder;
144
+ const icon = node?.properties?.icon ?? "ph--placeholder--regular";
146
145
  const label = pending ? t("pending heading") : toLocalizedString(node?.properties?.label ?? [
147
146
  "plank heading fallback label",
148
147
  {
@@ -160,22 +159,29 @@ var NodePlankHeading = ({
160
159
  }, [
161
160
  node
162
161
  ]);
163
- const attendableId = id?.split(SLUG_PATH_SEPARATOR).at(0);
164
- const layoutCoordinate = layoutPart !== void 0 && id !== void 0 ? {
165
- part: layoutPart,
166
- entryId: id
167
- } : void 0;
168
- const index = indexInPart(layoutParts, layoutCoordinate);
169
- const length = partLength(layoutParts, layoutPart);
170
- const canIncrementStart = layoutPart === "main" && index !== void 0 && index > 0 && length !== void 0 && length > 1;
171
- const canIncrementEnd = layoutPart === "main" && index !== void 0 && index < length - 1 && length !== void 0;
162
+ const layoutPart = coordinate.part;
163
+ const attendableId = coordinate.entryId.split(SLUG_PATH_SEPARATOR).at(0);
164
+ const capabilities = useMemo(() => ({
165
+ solo: (layoutPart === "solo" || layoutPart === "main") && isNotMobile,
166
+ incrementStart: canIncrementStart,
167
+ incrementEnd: canIncrementEnd
168
+ }), [
169
+ isNotMobile,
170
+ layoutPart,
171
+ canIncrementStart,
172
+ canIncrementEnd
173
+ ]);
172
174
  return /* @__PURE__ */ React2.createElement(PlankHeading.Root, (layoutPart !== "main" || !flatDeck) && {
173
175
  classNames: "pie-1 border-b border-separator"
174
176
  }, /* @__PURE__ */ React2.createElement(ActionRoot, null, node ? /* @__PURE__ */ React2.createElement(PlankHeading.ActionsMenu, {
175
- Icon,
177
+ icon,
178
+ related: layoutPart === "complementary",
176
179
  attendableId,
177
180
  triggerLabel: t("actions menu label"),
178
- actions: graph.actions(node),
181
+ actions: [
182
+ actions,
183
+ graph.actions(node)
184
+ ].filter((a) => a.length > 0),
179
185
  onAction: (action) => typeof action.data === "function" && action.data?.({
180
186
  node: action,
181
187
  caller: DECK_PLUGIN
@@ -187,11 +193,15 @@ var NodePlankHeading = ({
187
193
  }
188
194
  })) : /* @__PURE__ */ React2.createElement(PlankHeading.Button, null, /* @__PURE__ */ React2.createElement("span", {
189
195
  className: "sr-only"
190
- }, label), /* @__PURE__ */ React2.createElement(Icon, plankHeadingIconProps))), /* @__PURE__ */ React2.createElement(TextTooltip, {
196
+ }, label), /* @__PURE__ */ React2.createElement(Icon, {
197
+ icon,
198
+ size: 5
199
+ }))), /* @__PURE__ */ React2.createElement(TextTooltip, {
191
200
  text: label,
192
201
  onlyWhenTruncating: true
193
202
  }, /* @__PURE__ */ React2.createElement(PlankHeading.Label, {
194
- attendableId: node?.id,
203
+ attendableId,
204
+ related: layoutPart === "complementary",
195
205
  ...pending && {
196
206
  classNames: "text-description"
197
207
  }
@@ -203,11 +213,7 @@ var NodePlankHeading = ({
203
213
  object: node.data
204
214
  }
205
215
  }), /* @__PURE__ */ React2.createElement(PlankHeading.Controls, {
206
- capabilities: {
207
- solo: (layoutPart === "solo" || layoutPart === "main") && isNotMobile,
208
- incrementStart: canIncrementStart,
209
- incrementEnd: canIncrementEnd
210
- },
216
+ capabilities,
211
217
  isSolo: layoutPart === "solo",
212
218
  onClick: (eventType) => {
213
219
  if (!layoutPart) {
@@ -221,41 +227,45 @@ var NodePlankHeading = ({
221
227
  type: eventType,
222
228
  layoutCoordinate: {
223
229
  part: "main",
224
- entryId: id
230
+ entryId: coordinate.entryId
225
231
  }
226
232
  }
227
233
  }
228
234
  ]);
229
- }
230
- return dispatch(eventType === "close" ? layoutPart === "complementary" ? {
231
- action: LayoutAction.SET_LAYOUT,
232
- data: {
233
- element: "complementary",
234
- state: false
235
+ } else if (eventType === "close") {
236
+ if (layoutPart === "complementary") {
237
+ return dispatch({
238
+ action: LayoutAction.SET_LAYOUT,
239
+ data: {
240
+ element: "complementary",
241
+ state: false
242
+ }
243
+ });
244
+ } else {
245
+ return dispatch({
246
+ action: NavigationAction.CLOSE,
247
+ data: {
248
+ activeParts: {
249
+ [layoutPart]: [
250
+ coordinate.entryId
251
+ ]
252
+ }
253
+ }
254
+ });
235
255
  }
236
- } : {
237
- action: NavigationAction.CLOSE,
238
- data: {
239
- activeParts: {
240
- complementary: [
241
- `${id}${SLUG_PATH_SEPARATOR}comments${SLUG_COLLECTION_INDICATOR}`
242
- ],
243
- [layoutPart]: [
244
- id
245
- ]
256
+ } else {
257
+ return dispatch({
258
+ action: NavigationAction.ADJUST,
259
+ data: {
260
+ type: eventType,
261
+ layoutCoordinate: coordinate
246
262
  }
247
- }
248
- } : {
249
- action: NavigationAction.ADJUST,
250
- data: {
251
- type: eventType,
252
- layoutCoordinate
253
- }
254
- });
263
+ });
264
+ }
255
265
  },
256
- close: layoutCoordinate?.part === "complementary" ? "minify-end" : true
266
+ close: layoutPart === "complementary" ? "minify-end" : true
257
267
  }));
258
- };
268
+ });
259
269
 
260
270
  // packages/plugins/plugin-deck/src/components/DeckLayout/PlankError.tsx
261
271
  import React4, { useEffect as useEffect4, useState as useState2 } from "react";
@@ -291,15 +301,14 @@ var PlankContentError = ({ error }) => {
291
301
  )
292
302
  }, error ? error.toString() : t("error fallback message")));
293
303
  };
294
- var PlankError = ({ layoutCoordinate, id, node, error, flatDeck }) => {
304
+ var PlankError = ({ layoutCoordinate, node, error, flatDeck }) => {
295
305
  const [timedOut, setTimedOut] = useState2(false);
296
306
  useEffect4(() => {
297
307
  setTimeout(() => setTimedOut(true), 5e3);
298
308
  }, []);
299
309
  return /* @__PURE__ */ React4.createElement(React4.Fragment, null, /* @__PURE__ */ React4.createElement(NodePlankHeading, {
310
+ coordinate: layoutCoordinate,
300
311
  node,
301
- id,
302
- layoutPart: layoutCoordinate.part,
303
312
  pending: !timedOut,
304
313
  flatDeck
305
314
  }), timedOut ? /* @__PURE__ */ React4.createElement(PlankContentError, {
@@ -314,33 +323,65 @@ var LayoutContext = createContext(null);
314
323
  var useLayout = () => useContext(LayoutContext) ?? raise(new Error("Missing LayoutContext"));
315
324
 
316
325
  // packages/plugins/plugin-deck/src/components/DeckLayout/ComplementarySidebar.tsx
317
- var ComplementarySidebar = ({ id, layoutParts, flatDeck }) => {
326
+ var ComplementarySidebar = ({ panels, current, flatDeck }) => {
318
327
  const { popoverAnchorId } = useLayout();
328
+ const attended = useAttended2();
329
+ const panel = (panels.find((p) => p.id === current) ?? panels[0])?.id;
330
+ const id = attended[0] ? `${attended[0]}${SLUG_PATH_SEPARATOR2}${panel}` : void 0;
319
331
  const { graph } = useGraph3();
320
332
  const node = useNode(graph, id);
321
- const complementaryAttrs = createAttendableAttributes(id?.split(SLUG_PATH_SEPARATOR2)[0] ?? "never");
333
+ const dispatch = useIntentDispatcher2();
322
334
  useNodeActionExpander(node);
323
- return /* @__PURE__ */ React5.createElement(Main.ComplementarySidebar, complementaryAttrs, node ? /* @__PURE__ */ React5.createElement("div", {
335
+ const actions = useMemo2(() => panels.map(({ id: id2, label, icon }) => ({
336
+ id: `complementary-${id2}`,
337
+ data: () => {
338
+ void dispatch({
339
+ action: NavigationAction2.OPEN,
340
+ data: {
341
+ activeParts: {
342
+ complementary: id2
343
+ }
344
+ }
345
+ });
346
+ },
347
+ properties: {
348
+ label,
349
+ icon,
350
+ menuItemType: "toggle",
351
+ isChecked: panel === id2
352
+ }
353
+ })), [
354
+ panel
355
+ ]);
356
+ const coordinate = useMemo2(() => ({
357
+ entryId: id ?? "unknown",
358
+ part: "complementary"
359
+ }), [
360
+ id
361
+ ]);
362
+ return /* @__PURE__ */ React5.createElement(Main.ComplementarySidebar, null, /* @__PURE__ */ React5.createElement("div", {
324
363
  role: "none",
325
364
  className: mx2(deckGrid, "grid-cols-1 bs-full")
326
365
  }, /* @__PURE__ */ React5.createElement(NodePlankHeading, {
366
+ coordinate,
327
367
  node,
328
- id,
329
- layoutParts,
330
- layoutPart: "complementary",
331
368
  popoverAnchorId,
332
- flatDeck
333
- }), /* @__PURE__ */ React5.createElement(Surface3, {
334
- role: "article",
369
+ flatDeck,
370
+ actions
371
+ }), /* @__PURE__ */ React5.createElement("div", {
372
+ className: "row-span-2 divide-y divide-separator overflow-x-hidden overflow-y-scroll"
373
+ }, node && /* @__PURE__ */ React5.createElement(Surface3, {
374
+ key: id,
375
+ role: `complementary--${panel}`,
376
+ limit: 1,
335
377
  data: {
336
- subject: node.data,
337
- part: "complementary",
378
+ id,
379
+ subject: node.properties.object ?? node.properties.space,
338
380
  popoverAnchorId
339
381
  },
340
- limit: 1,
341
382
  fallback: PlankContentError,
342
383
  placeholder: /* @__PURE__ */ React5.createElement(PlankLoading, null)
343
- })) : null);
384
+ }))));
344
385
  };
345
386
 
346
387
  // packages/plugins/plugin-deck/src/components/DeckLayout/ContentEmpty.tsx
@@ -400,12 +441,12 @@ var Fullscreen = ({ id }) => {
400
441
 
401
442
  // packages/plugins/plugin-deck/src/components/DeckLayout/Plank.tsx
402
443
  import { Plus } from "@phosphor-icons/react";
403
- import React9, { useCallback, useLayoutEffect, useRef } from "react";
404
- import { LayoutAction as LayoutAction2, NavigationAction as NavigationAction2, Surface as Surface6, useIntentDispatcher as useIntentDispatcher2 } from "@dxos/app-framework";
444
+ import React9, { memo as memo2, useCallback, useLayoutEffect, useMemo as useMemo3, useRef } from "react";
445
+ import { LayoutAction as LayoutAction2, NavigationAction as NavigationAction3, Surface as Surface6, useIntentDispatcher as useIntentDispatcher3, indexInPart, partLength } from "@dxos/app-framework";
405
446
  import { debounce } from "@dxos/async";
406
447
  import { useGraph as useGraph5 } from "@dxos/plugin-graph";
407
448
  import { Button, Tooltip, useTranslation as useTranslation4 } from "@dxos/react-ui";
408
- import { createAttendableAttributes as createAttendableAttributes2 } from "@dxos/react-ui-attention";
449
+ import { useAttendableAttributes } from "@dxos/react-ui-attention";
409
450
  import { Plank as NaturalPlank } from "@dxos/react-ui-deck";
410
451
  import { mainIntrinsicSize } from "@dxos/react-ui-theme";
411
452
 
@@ -416,32 +457,38 @@ var DeckContext = createContext2(null);
416
457
  var useDeckContext = () => useContext2(DeckContext) ?? raise2(new Error("Missing DeckContext"));
417
458
 
418
459
  // packages/plugins/plugin-deck/src/components/DeckLayout/Plank.tsx
419
- var Plank = ({ entry, layoutParts, part, flatDeck, searchEnabled, layoutMode }) => {
460
+ var UNKNOWN_ID = "unknown_id";
461
+ var Plank = /* @__PURE__ */ memo2(({ entry, layoutParts, part, flatDeck, searchEnabled, layoutMode }) => {
420
462
  const { t } = useTranslation4(DECK_PLUGIN);
421
- const dispatch = useIntentDispatcher2();
463
+ const dispatch = useIntentDispatcher3();
464
+ const coordinate = useMemo3(() => ({
465
+ part,
466
+ entryId: entry?.id ?? UNKNOWN_ID
467
+ }), [
468
+ entry?.id,
469
+ part
470
+ ]);
422
471
  const { popoverAnchorId, scrollIntoView } = useLayout();
423
472
  const { plankSizing } = useDeckContext();
424
473
  const { graph } = useGraph5();
425
- const node = useNode(graph, entry.id);
474
+ const node = useNode(graph, entry?.id);
426
475
  const rootElement = useRef(null);
427
476
  const resizeable = layoutMode === "deck";
428
- const attendableAttrs = createAttendableAttributes2(entry.id);
429
- const coordinate = {
430
- part,
431
- entryId: entry.id
432
- };
433
- const size = plankSizing?.[entry.id];
434
- const setSize = useCallback(debounce((newSize) => {
435
- void dispatch({
436
- action: DeckAction.UPDATE_PLANK_SIZE,
437
- data: {
438
- id: entry.id,
439
- size: newSize
440
- }
441
- });
442
- }, 200), [
477
+ const attendableAttrs = useAttendableAttributes(coordinate.entryId);
478
+ const index = indexInPart(layoutParts, coordinate);
479
+ const length = partLength(layoutParts, part);
480
+ const canIncrementStart = part === "main" && index !== void 0 && index > 0 && length !== void 0 && length > 1;
481
+ const canIncrementEnd = part === "main" && index !== void 0 && index < length - 1 && length !== void 0;
482
+ const size = plankSizing?.[coordinate.entryId];
483
+ const setSize = useCallback(debounce((newSize) => dispatch({
484
+ action: DeckAction.UPDATE_PLANK_SIZE,
485
+ data: {
486
+ id: coordinate.entryId,
487
+ size: newSize
488
+ }
489
+ }), 200), [
443
490
  dispatch,
444
- entry.id
491
+ coordinate.entryId
445
492
  ]);
446
493
  const handleKeyDown = useCallback((event) => {
447
494
  if (event.target === event.currentTarget && event.key === "Escape") {
@@ -449,7 +496,7 @@ var Plank = ({ entry, layoutParts, part, flatDeck, searchEnabled, layoutMode })
449
496
  }
450
497
  }, []);
451
498
  useLayoutEffect(() => {
452
- if (scrollIntoView === entry.id) {
499
+ if (scrollIntoView === coordinate.entryId) {
453
500
  rootElement.current?.focus({
454
501
  preventScroll: true
455
502
  });
@@ -459,12 +506,30 @@ var Plank = ({ entry, layoutParts, part, flatDeck, searchEnabled, layoutMode })
459
506
  });
460
507
  }
461
508
  }, [
509
+ coordinate.entryId,
462
510
  scrollIntoView,
463
511
  layoutMode
464
512
  ]);
465
513
  const isSolo = layoutMode === "solo" && part === "solo";
466
- const isSuppressed = layoutMode === "solo" && part !== "solo";
514
+ const isSuppressed = layoutMode === "solo" && part !== "solo" || layoutMode === "deck" && part === "solo" || coordinate.entryId === UNKNOWN_ID;
467
515
  const sizeAttrs = useMainSize();
516
+ const data = useMemo3(() => node && {
517
+ ...entry?.path ? {
518
+ subject: node.data,
519
+ path: entry.path
520
+ } : {
521
+ object: node.data
522
+ },
523
+ coordinate,
524
+ popoverAnchorId
525
+ }, [
526
+ node,
527
+ node?.data,
528
+ entry?.path,
529
+ coordinate,
530
+ popoverAnchorId
531
+ ]);
532
+ const placeholder = useMemo3(() => /* @__PURE__ */ React9.createElement(PlankLoading, null), []);
468
533
  return /* @__PURE__ */ React9.createElement(NaturalPlank.Root, {
469
534
  size,
470
535
  setSize,
@@ -487,30 +552,20 @@ var Plank = ({ entry, layoutParts, part, flatDeck, searchEnabled, layoutMode })
487
552
  inlineSize: ""
488
553
  } : {}
489
554
  }, node ? /* @__PURE__ */ React9.createElement(React9.Fragment, null, /* @__PURE__ */ React9.createElement(NodePlankHeading, {
490
- id: entry.id,
555
+ coordinate,
491
556
  node,
492
- layoutPart: coordinate.part,
493
- layoutParts,
557
+ canIncrementStart,
558
+ canIncrementEnd,
494
559
  popoverAnchorId,
495
560
  flatDeck
496
561
  }), /* @__PURE__ */ React9.createElement(Surface6, {
497
562
  role: "article",
498
- data: {
499
- ...entry.path ? {
500
- subject: node.data,
501
- path: entry.path
502
- } : {
503
- object: node.data
504
- },
505
- coordinate,
506
- popoverAnchorId
507
- },
563
+ data,
508
564
  limit: 1,
509
565
  fallback: PlankContentError,
510
- placeholder: /* @__PURE__ */ React9.createElement(PlankLoading, null)
566
+ placeholder
511
567
  })) : /* @__PURE__ */ React9.createElement(PlankError, {
512
568
  layoutCoordinate: coordinate,
513
- id: entry.id,
514
569
  flatDeck
515
570
  })), searchEnabled && resizeable ? /* @__PURE__ */ React9.createElement("div", {
516
571
  role: "none",
@@ -529,7 +584,7 @@ var Plank = ({ entry, layoutParts, part, flatDeck, searchEnabled, layoutMode })
529
584
  component: "dxos.org/plugin/search/Dialog",
530
585
  dialogBlockAlign: "start",
531
586
  subject: {
532
- action: NavigationAction2.SET,
587
+ action: NavigationAction3.SET,
533
588
  position: "add-after",
534
589
  coordinate
535
590
  }
@@ -546,33 +601,31 @@ var Plank = ({ entry, layoutParts, part, flatDeck, searchEnabled, layoutMode })
546
601
  })) : resizeable ? /* @__PURE__ */ React9.createElement(NaturalPlank.ResizeHandle, {
547
602
  classNames: "row-span-3"
548
603
  }) : null);
549
- };
604
+ });
550
605
 
551
606
  // packages/plugins/plugin-deck/src/components/DeckLayout/Sidebar.tsx
552
- import React10, { useMemo } from "react";
607
+ import React10, { useMemo as useMemo4 } from "react";
553
608
  import { openIds, Surface as Surface7 } from "@dxos/app-framework";
554
609
  import { Main as Main2 } from "@dxos/react-ui";
555
- var Sidebar = ({ attention, layoutParts }) => {
610
+ var Sidebar = ({ layoutParts }) => {
556
611
  const { layoutMode, popoverAnchorId } = useLayout();
557
- const activeIds = useMemo(() => {
612
+ const activeIds = useMemo4(() => {
558
613
  if (layoutMode === "solo") {
559
- return new Set(layoutParts?.solo?.map((e) => e.id) ?? []);
614
+ return Array.from(new Set(layoutParts?.solo?.map((e) => e.id) ?? []));
560
615
  } else if (layoutMode === "deck") {
561
- return new Set(layoutParts?.main?.map((e) => e.id) ?? []);
616
+ return Array.from(new Set(layoutParts?.main?.map((e) => e.id) ?? []));
562
617
  }
563
- return new Set(openIds(layoutParts));
618
+ return Array.from(new Set(openIds(layoutParts)));
564
619
  }, [
565
620
  layoutParts,
566
621
  layoutMode
567
622
  ]);
568
- const navigationData = useMemo(() => ({
623
+ const navigationData = useMemo4(() => ({
569
624
  popoverAnchorId,
570
- activeIds,
571
- attended: attention.attended
625
+ activeIds
572
626
  }), [
573
627
  popoverAnchorId,
574
- activeIds,
575
- attention.attended
628
+ activeIds
576
629
  ]);
577
630
  return /* @__PURE__ */ React10.createElement(Main2.NavigationSidebar, null, /* @__PURE__ */ React10.createElement(Surface7, {
578
631
  role: "navigation",
@@ -586,14 +639,19 @@ var Sidebar = ({ attention, layoutParts }) => {
586
639
  // packages/plugins/plugin-deck/src/components/DeckLayout/StatusBar.tsx
587
640
  import React11 from "react";
588
641
  import { Surface as Surface8 } from "@dxos/app-framework";
589
- import { mainPadding, mx as mx4 } from "@dxos/react-ui-theme";
590
- var StatusBar = () => {
642
+ import { mainPadding, mainPaddingTransitions, mx as mx4 } from "@dxos/react-ui-theme";
643
+ var StatusBar = ({ showHints }) => {
591
644
  const sizeAttrs = useMainSize();
592
645
  return /* @__PURE__ */ React11.createElement("div", {
593
646
  role: "none",
594
647
  ...sizeAttrs,
595
- className: mx4("fixed block-end-0 inset-inline-0 z-[2]", mainPadding)
596
- }, /* @__PURE__ */ React11.createElement(Surface8, {
648
+ className: mx4("fixed flex justify-between block-end-0 inset-inline-0 items-center border-bs border-separator z-[2]", mainPadding, mainPaddingTransitions)
649
+ }, /* @__PURE__ */ React11.createElement("div", {
650
+ role: "none"
651
+ }, showHints && /* @__PURE__ */ React11.createElement(Surface8, {
652
+ role: "hints",
653
+ limit: 1
654
+ })), /* @__PURE__ */ React11.createElement(Surface8, {
597
655
  role: "status-bar",
598
656
  limit: 1
599
657
  }));
@@ -601,15 +659,19 @@ var StatusBar = () => {
601
659
 
602
660
  // packages/plugins/plugin-deck/src/components/DeckLayout/Toast.tsx
603
661
  import React12 from "react";
604
- import { Button as Button2, Toast as NaturalToast } from "@dxos/react-ui";
662
+ import { Button as Button2, Icon as Icon2, Toast as NaturalToast } from "@dxos/react-ui";
605
663
  var Toast = ({ id, title, description, icon, duration, actionLabel, actionAlt, closeLabel, onAction, onOpenChange }) => {
606
664
  return /* @__PURE__ */ React12.createElement(NaturalToast.Root, {
607
665
  "data-testid": id,
608
666
  defaultOpen: true,
609
667
  duration,
610
668
  onOpenChange
611
- }, /* @__PURE__ */ React12.createElement(NaturalToast.Body, null, /* @__PURE__ */ React12.createElement(NaturalToast.Title, null, icon?.({
612
- className: "inline mr-1"
669
+ }, /* @__PURE__ */ React12.createElement(NaturalToast.Body, null, /* @__PURE__ */ React12.createElement(NaturalToast.Title, {
670
+ classNames: "items-center"
671
+ }, /* @__PURE__ */ React12.createElement(Icon2, {
672
+ icon,
673
+ size: 5,
674
+ classNames: "inline mr-1"
613
675
  }), /* @__PURE__ */ React12.createElement("span", null, title)), description && /* @__PURE__ */ React12.createElement(NaturalToast.Description, null, description)), /* @__PURE__ */ React12.createElement(NaturalToast.Actions, null, onAction && actionAlt && actionLabel && /* @__PURE__ */ React12.createElement(NaturalToast.Action, {
614
676
  altText: actionAlt,
615
677
  asChild: true
@@ -646,7 +708,10 @@ var getEffectivePart = (partName, layoutMode) => layoutMode === "solo" && partNa
646
708
  import { PLANK_DEFAULTS } from "@dxos/react-ui-deck";
647
709
  var calculateOverscroll = (planks, plankSizing, sidebarOpen, complementarySidebarOpen) => {
648
710
  if (!planks?.length) {
649
- return;
711
+ return {
712
+ paddingInlineStart: 0,
713
+ paddingInlineEnd: 0
714
+ };
650
715
  }
651
716
  const sidebarWidth = sidebarOpen ? "270px" : "0px";
652
717
  const complementarySidebarWidth = complementarySidebarOpen ? "360px" : "0px";
@@ -656,8 +721,8 @@ var calculateOverscroll = (planks, plankSizing, sidebarOpen, complementarySideba
656
721
  const plankSize = getPlankSize(plank.id);
657
722
  const overscrollPadding = `max(0px, calc(((100dvw - ${sidebarWidth} - ${complementarySidebarWidth} - (${plankSize} + 20px)) / 2)))`;
658
723
  return {
659
- paddingLeft: overscrollPadding,
660
- paddingRight: overscrollPadding
724
+ paddingInlineStart: overscrollPadding,
725
+ paddingInlineEnd: overscrollPadding
661
726
  };
662
727
  } else {
663
728
  const first = planks[0];
@@ -665,27 +730,34 @@ var calculateOverscroll = (planks, plankSizing, sidebarOpen, complementarySideba
665
730
  const last = planks[planks.length - 1];
666
731
  const lastSize = getPlankSize(last.id);
667
732
  return {
668
- paddingLeft: `max(0px, calc(((100dvw - (${firstSize} + 20px)) / 2) - ${sidebarWidth}))`,
669
- paddingRight: `max(0px, calc(((100dvw - (${lastSize} + 20px)) / 2) - ${complementarySidebarWidth}))`
733
+ paddingInlineStart: `max(0px, calc(((100dvw - (${firstSize} + 20px)) / 2) - ${sidebarWidth}))`,
734
+ paddingInlineEnd: `max(0px, calc(((100dvw - (${lastSize} + 20px)) / 2) - ${complementarySidebarWidth}))`
670
735
  };
671
736
  }
672
737
  };
673
738
 
674
739
  // packages/plugins/plugin-deck/src/components/DeckLayout/DeckLayout.tsx
675
- var DeckLayout = ({ layoutParts, attention, toasts, flatDeck, overscroll, showHintsFooter, slots, onDismissToast }) => {
740
+ var DeckLayout = ({ layoutParts, toasts, flatDeck, overscroll, showHints, slots, panels, onDismissToast }) => {
676
741
  const context = useLayout();
677
742
  const { layoutMode, sidebarOpen, complementarySidebarOpen, dialogOpen, dialogContent, dialogBlockAlign, popoverOpen, popoverContent, popoverAnchorId } = context;
678
743
  const { t } = useTranslation5(DECK_PLUGIN);
679
744
  const { plankSizing } = useDeckContext();
745
+ const attentionPlugin = usePlugin("dxos.org/plugin/attention");
680
746
  const searchPlugin = usePlugin("dxos.org/plugin/search");
681
- const fullScreenSlug = useMemo2(() => firstIdInPart(layoutParts, "fullScreen"), [
747
+ const fullScreenSlug = useMemo5(() => firstIdInPart(layoutParts, "fullScreen"), [
682
748
  layoutParts
683
749
  ]);
684
- const [scrollLeft, setScrollLeft] = useState3(null);
750
+ const scrollLeftRef = useRef2();
685
751
  const deckRef = useRef2(null);
686
- const restoreScrollRef = useRef2(false);
752
+ useEffect5(() => {
753
+ const attended = untracked(() => attentionPlugin?.provides.attention.attended ?? []);
754
+ const firstId = layoutMode === "solo" ? firstIdInPart(layoutParts, "solo") : firstIdInPart(layoutParts, "main");
755
+ if (attended.length === 0 && firstId) {
756
+ document.querySelector(`article[data-attendable-id="${firstId}"] button`)?.focus();
757
+ }
758
+ }, []);
687
759
  const handleResize = useCallback2(() => {
688
- setScrollLeft(null);
760
+ scrollLeftRef.current = null;
689
761
  }, []);
690
762
  useEffect5(() => {
691
763
  window.addEventListener("resize", handleResize);
@@ -693,58 +765,33 @@ var DeckLayout = ({ layoutParts, attention, toasts, flatDeck, overscroll, showHi
693
765
  }, [
694
766
  handleResize
695
767
  ]);
696
- useLayoutEffect2(() => {
697
- if (layoutMode !== "deck") {
698
- restoreScrollRef.current = true;
699
- } else if (restoreScrollRef.current && deckRef.current && scrollLeft) {
700
- deckRef.current.scrollLeft = scrollLeft;
701
- restoreScrollRef.current = false;
768
+ const restoreScroll = useCallback2(() => {
769
+ if (deckRef.current && scrollLeftRef.current != null) {
770
+ deckRef.current.scrollLeft = scrollLeftRef.current;
702
771
  }
703
- }, [
704
- layoutMode,
705
- deckRef.current,
706
- scrollLeft
707
- ]);
772
+ }, []);
773
+ useOnTransition(layoutMode, (mode) => mode !== "deck", "deck", restoreScroll);
708
774
  const handleScroll = useCallback2((event) => {
709
775
  if (layoutMode === "deck" && event.currentTarget === event.target) {
710
- setScrollLeft(event.target.scrollLeft);
776
+ scrollLeftRef.current = event.target.scrollLeft;
711
777
  }
712
778
  }, [
713
779
  layoutMode
714
780
  ]);
715
- const complementarySlug = useMemo2(() => {
716
- const entry = layoutParts.complementary?.at(0);
717
- if (entry) {
718
- return entry.path ? `${entry.id}${SLUG_PATH_SEPARATOR3}${entry.path}` : entry.id;
719
- }
720
- }, [
721
- layoutParts
722
- ]);
723
- const firstAttendedId = useMemo2(() => Array.from(attention.attended ?? [])[0], [
724
- attention.attended
725
- ]);
726
- useEffect5(() => {
727
- if (layoutMode === "deck" && firstAttendedId) {
781
+ const isEmpty = layoutParts.main?.length === 0 && layoutParts.solo?.length === 0;
782
+ const padding = useMemo5(() => {
783
+ if (layoutMode === "deck" && overscroll === "centering") {
784
+ return calculateOverscroll(layoutParts.main, plankSizing, sidebarOpen, complementarySidebarOpen);
728
785
  }
786
+ return {};
729
787
  }, [
730
788
  layoutMode,
731
- firstAttendedId
732
- ]);
733
- const parts = useMemo2(() => {
734
- const parts2 = [
735
- ...layoutParts.main ?? []
736
- ];
737
- for (const part of layoutParts.solo ?? []) {
738
- if (!parts2.find((entry) => entry.id === part.id)) {
739
- parts2.push(part);
740
- }
741
- }
742
- return parts2;
743
- }, [
789
+ overscroll,
744
790
  layoutParts.main,
745
- layoutParts.solo
791
+ plankSizing,
792
+ sidebarOpen,
793
+ complementarySidebarOpen
746
794
  ]);
747
- const padding = layoutMode === "deck" && overscroll === "centering" ? calculateOverscroll(layoutParts.main, plankSizing, sidebarOpen, complementarySidebarOpen) : {};
748
795
  if (layoutMode === "fullscreen") {
749
796
  return /* @__PURE__ */ React13.createElement(Fullscreen, {
750
797
  id: fullScreenSlug
@@ -761,24 +808,16 @@ var DeckLayout = ({ layoutParts, attention, toasts, flatDeck, overscroll, showHi
761
808
  context.popoverAnchorId = void 0;
762
809
  }
763
810
  }
764
- }, /* @__PURE__ */ React13.createElement(ActiveNode, {
765
- id: firstAttendedId
766
- }), /* @__PURE__ */ React13.createElement(Main3.Root, {
811
+ }, /* @__PURE__ */ React13.createElement(ActiveNode, null), /* @__PURE__ */ React13.createElement(Main3.Root, {
767
812
  navigationSidebarOpen: context.sidebarOpen,
768
813
  onNavigationSidebarOpenChange: (next) => context.sidebarOpen = next,
769
- ...complementarySidebarOpen !== null && {
770
- complementarySidebarOpen: (
771
- /* complementaryAvailable && */
772
- context.complementarySidebarOpen
773
- ),
774
- onComplementarySidebarOpenChange: (next) => context.complementarySidebarOpen = next
775
- }
814
+ complementarySidebarOpen: context.complementarySidebarOpen,
815
+ onComplementarySidebarOpenChange: (next) => context.complementarySidebarOpen = next
776
816
  }, /* @__PURE__ */ React13.createElement(Main3.Notch, {
777
817
  classNames: "z-[21]"
778
818
  }, /* @__PURE__ */ React13.createElement(Surface9, {
779
819
  role: "notch-start"
780
820
  }), /* @__PURE__ */ React13.createElement(Button3, {
781
- // disabled={!sidebarAvailable}
782
821
  onClick: () => context.sidebarOpen = !context.sidebarOpen,
783
822
  variant: "ghost",
784
823
  classNames: "p-1"
@@ -788,7 +827,6 @@ var DeckLayout = ({ layoutParts, attention, toasts, flatDeck, overscroll, showHi
788
827
  weight: "light",
789
828
  className: getSize(5)
790
829
  })), /* @__PURE__ */ React13.createElement(Button3, {
791
- // disabled={!complementaryAvailable}
792
830
  onClick: () => context.complementarySidebarOpen = !context.complementarySidebarOpen,
793
831
  variant: "ghost",
794
832
  classNames: "p-1"
@@ -801,15 +839,14 @@ var DeckLayout = ({ layoutParts, attention, toasts, flatDeck, overscroll, showHi
801
839
  })), /* @__PURE__ */ React13.createElement(Surface9, {
802
840
  role: "notch-end"
803
841
  })), /* @__PURE__ */ React13.createElement(Sidebar, {
804
- attention,
805
842
  layoutParts
806
843
  }), /* @__PURE__ */ React13.createElement(ComplementarySidebar, {
807
- id: complementarySlug,
808
- layoutParts,
844
+ panels,
845
+ current: layoutParts.complementary?.[0].id,
809
846
  flatDeck
810
- }), /* @__PURE__ */ React13.createElement(Main3.Overlay, null), parts.length === 0 && /* @__PURE__ */ React13.createElement(Main3.Content, {
847
+ }), /* @__PURE__ */ React13.createElement(Main3.Overlay, null), isEmpty && /* @__PURE__ */ React13.createElement(Main3.Content, {
811
848
  handlesFocus: true
812
- }, /* @__PURE__ */ React13.createElement(ContentEmpty, null)), parts.length !== 0 && /* @__PURE__ */ React13.createElement(Main3.Content, {
849
+ }, /* @__PURE__ */ React13.createElement(ContentEmpty, null)), !isEmpty && /* @__PURE__ */ React13.createElement(Main3.Content, {
813
850
  bounce: true,
814
851
  classNames: "grid block-end-[--statusbar-size]",
815
852
  handlesFocus: true
@@ -820,26 +857,31 @@ var DeckLayout = ({ layoutParts, attention, toasts, flatDeck, overscroll, showHi
820
857
  style: padding,
821
858
  classNames: [
822
859
  !flatDeck && "bg-deck",
860
+ mainPaddingTransitions2,
823
861
  "absolute inset-0",
824
862
  slots?.wallpaper?.classNames
825
863
  ],
826
864
  solo: layoutMode === "solo",
827
865
  onScroll: handleScroll,
828
866
  ref: deckRef
829
- }, parts.map((layoutEntry) => /* @__PURE__ */ React13.createElement(Plank, {
867
+ }, /* @__PURE__ */ React13.createElement(Plank, {
868
+ entry: layoutParts.solo?.[0],
869
+ layoutParts,
870
+ part: "solo",
871
+ layoutMode,
872
+ flatDeck,
873
+ searchEnabled: !!searchPlugin
874
+ }), layoutParts.main?.map((layoutEntry) => /* @__PURE__ */ React13.createElement(Plank, {
830
875
  key: layoutEntry.id,
831
876
  entry: layoutEntry,
832
877
  layoutParts,
833
- part: layoutMode === "solo" && layoutEntry.id === layoutParts.solo?.[0]?.id ? "solo" : "main",
878
+ part: "main",
834
879
  layoutMode,
835
880
  flatDeck,
836
881
  searchEnabled: !!searchPlugin
837
- }))))), /* @__PURE__ */ React13.createElement(StatusBar, null), showHintsFooter && /* @__PURE__ */ React13.createElement("div", {
838
- className: "fixed bottom-0 left-0 right-0 h-[32px] z-[1] flex justify-center"
839
- }, /* @__PURE__ */ React13.createElement(Surface9, {
840
- role: "hints",
841
- limit: 1
842
- })), /* @__PURE__ */ React13.createElement(Popover2.Portal, null, /* @__PURE__ */ React13.createElement(Popover2.Content, {
882
+ }))))), /* @__PURE__ */ React13.createElement(StatusBar, {
883
+ showHints
884
+ }), /* @__PURE__ */ React13.createElement(Popover2.Portal, null, /* @__PURE__ */ React13.createElement(Popover2.Content, {
843
885
  classNames: "z-[60]",
844
886
  onEscapeKeyDown: () => {
845
887
  context.popoverOpen = false;
@@ -870,24 +912,12 @@ var DeckLayout = ({ layoutParts, attention, toasts, flatDeck, overscroll, showHi
870
912
 
871
913
  // packages/plugins/plugin-deck/src/components/LayoutSettings.tsx
872
914
  import React14 from "react";
873
- import { SettingsValue } from "@dxos/plugin-settings";
874
915
  import { Input, Select, useTranslation as useTranslation6 } from "@dxos/react-ui";
875
-
876
- // packages/plugins/plugin-deck/src/types.ts
877
- var NewPlankPositions = [
878
- "start",
879
- "end"
880
- ];
881
- var OverscrollOptions = [
882
- "none",
883
- "centering"
884
- ];
885
-
886
- // packages/plugins/plugin-deck/src/components/LayoutSettings.tsx
916
+ import { DeprecatedFormInput } from "@dxos/react-ui-data";
887
917
  var isSocket = !!globalThis.__args;
888
918
  var LayoutSettings = ({ settings }) => {
889
919
  const { t } = useTranslation6(DECK_PLUGIN);
890
- return /* @__PURE__ */ React14.createElement(React14.Fragment, null, /* @__PURE__ */ React14.createElement(SettingsValue, {
920
+ return /* @__PURE__ */ React14.createElement(React14.Fragment, null, /* @__PURE__ */ React14.createElement(DeprecatedFormInput, {
891
921
  label: t("select new plank positioning label")
892
922
  }, /* @__PURE__ */ React14.createElement(Select.Root, {
893
923
  value: settings.newPlankPositioning ?? "start",
@@ -897,7 +927,7 @@ var LayoutSettings = ({ settings }) => {
897
927
  }), /* @__PURE__ */ React14.createElement(Select.Portal, null, /* @__PURE__ */ React14.createElement(Select.Content, null, /* @__PURE__ */ React14.createElement(Select.Viewport, null, NewPlankPositions.map((position) => /* @__PURE__ */ React14.createElement(Select.Option, {
898
928
  key: position,
899
929
  value: position
900
- }, t(`settings new plank position ${position} label`)))))))), /* @__PURE__ */ React14.createElement(SettingsValue, {
930
+ }, t(`settings new plank position ${position} label`)))))))), /* @__PURE__ */ React14.createElement(DeprecatedFormInput, {
901
931
  label: t("settings overscroll label")
902
932
  }, /* @__PURE__ */ React14.createElement(Select.Root, {
903
933
  value: settings.overscroll ?? "none",
@@ -907,32 +937,32 @@ var LayoutSettings = ({ settings }) => {
907
937
  }), /* @__PURE__ */ React14.createElement(Select.Portal, null, /* @__PURE__ */ React14.createElement(Select.Content, null, /* @__PURE__ */ React14.createElement(Select.Viewport, null, OverscrollOptions.map((option) => /* @__PURE__ */ React14.createElement(Select.Option, {
908
938
  key: option,
909
939
  value: option
910
- }, t(`settings overscroll ${option} label`)))))))), /* @__PURE__ */ React14.createElement(SettingsValue, {
911
- label: t("settings show footer label")
940
+ }, t(`settings overscroll ${option} label`)))))))), /* @__PURE__ */ React14.createElement(DeprecatedFormInput, {
941
+ label: t("settings show hints label")
912
942
  }, /* @__PURE__ */ React14.createElement(Input.Switch, {
913
- checked: settings.showFooter,
914
- onCheckedChange: (checked) => settings.showFooter = !!checked
915
- })), !isSocket && /* @__PURE__ */ React14.createElement(SettingsValue, {
943
+ checked: settings.showHints,
944
+ onCheckedChange: (checked) => settings.showHints = checked
945
+ })), !isSocket && /* @__PURE__ */ React14.createElement(DeprecatedFormInput, {
916
946
  label: t("settings native redirect label")
917
947
  }, /* @__PURE__ */ React14.createElement(Input.Switch, {
918
948
  checked: settings.enableNativeRedirect,
919
- onCheckedChange: (checked) => settings.enableNativeRedirect = !!checked
920
- })), /* @__PURE__ */ React14.createElement(SettingsValue, {
949
+ onCheckedChange: (checked) => settings.enableNativeRedirect = checked
950
+ })), /* @__PURE__ */ React14.createElement(DeprecatedFormInput, {
921
951
  label: t("settings custom slots")
922
952
  }, /* @__PURE__ */ React14.createElement(Input.Switch, {
923
953
  checked: settings.customSlots,
924
- onCheckedChange: (checked) => settings.customSlots = !!checked
925
- })), /* @__PURE__ */ React14.createElement(SettingsValue, {
954
+ onCheckedChange: (checked) => settings.customSlots = checked
955
+ })), /* @__PURE__ */ React14.createElement(DeprecatedFormInput, {
926
956
  label: t("settings flat deck")
927
957
  }, /* @__PURE__ */ React14.createElement(Input.Switch, {
928
958
  checked: settings.flatDeck,
929
- onCheckedChange: (checked) => settings.flatDeck = !!checked
959
+ onCheckedChange: (checked) => settings.flatDeck = checked
930
960
  })));
931
961
  };
932
962
 
933
963
  // packages/plugins/plugin-deck/src/layout.ts
934
964
  import { produce } from "immer";
935
- import { SLUG_ENTRY_SEPARATOR, SLUG_KEY_VALUE_SEPARATOR, SLUG_LIST_SEPARATOR, SLUG_PATH_SEPARATOR as SLUG_PATH_SEPARATOR4 } from "@dxos/app-framework";
965
+ import { SLUG_ENTRY_SEPARATOR, SLUG_KEY_VALUE_SEPARATOR, SLUG_LIST_SEPARATOR, SLUG_PATH_SEPARATOR as SLUG_PATH_SEPARATOR3 } from "@dxos/app-framework";
936
966
  var partsThatSupportIncrement = [
937
967
  "main"
938
968
  ];
@@ -1045,7 +1075,7 @@ var mergeLayoutParts = (...layoutParts) => {
1045
1075
  }), {});
1046
1076
  };
1047
1077
  var parseLayoutEntry = (itemString) => {
1048
- const [id, path] = itemString.split(SLUG_PATH_SEPARATOR4);
1078
+ const [id, path] = itemString.split(SLUG_PATH_SEPARATOR3);
1049
1079
  const entry = {
1050
1080
  id
1051
1081
  };
@@ -1072,7 +1102,7 @@ var soloPartToUri = (layout) => {
1072
1102
  return "";
1073
1103
  }
1074
1104
  const entry = soloPart[0];
1075
- return `${entry.id}${entry.path ? SLUG_PATH_SEPARATOR4 + entry.path : ""}`;
1105
+ return `${entry.id}${entry.path ? SLUG_PATH_SEPARATOR3 + entry.path : ""}`;
1076
1106
  };
1077
1107
 
1078
1108
  // packages/plugins/plugin-deck/src/translations.ts
@@ -1083,12 +1113,11 @@ var translations_default = [
1083
1113
  "main header label": "Main header",
1084
1114
  "open navigation sidebar label": "Open navigation sidebar.",
1085
1115
  "open complementary sidebar label": "Open complementary sidebar.",
1086
- "open settings label": "Show settings",
1087
1116
  "plugin error message": "Content failed to render.",
1088
1117
  "content fallback message": "Unsupported",
1089
1118
  "content fallback description": "No plugin had a response for the address you navigated\xA0to. Double-check the URL, and ensure you\u2019ve enabled a plugin that supports the\xA0object.",
1090
1119
  "toggle fullscreen label": "Toggle fullscreen",
1091
- "settings show footer label": "Show footer (experimental)",
1120
+ "settings show hints label": "Show hints",
1092
1121
  "settings native redirect label": "Enable native url redirect (experimental)",
1093
1122
  "settings custom slots": "Theme option (experimental)",
1094
1123
  "settings new plank position start label": "Start",
@@ -1099,7 +1128,6 @@ var translations_default = [
1099
1128
  "undo action label": "Undo",
1100
1129
  "undo action alt": "Undo previous action",
1101
1130
  "undo close label": "Dismiss",
1102
- "open comments label": "Open comments",
1103
1131
  "error fallback message": "Unable to open this item",
1104
1132
  "plank heading fallback label": "Untitled",
1105
1133
  "actions menu label": "Options",
@@ -1141,8 +1169,9 @@ var DeckPlugin = ({ observability } = {}) => {
1141
1169
  const unsubscriptionCallbacks = [];
1142
1170
  let currentUndoId;
1143
1171
  let handleNavigation;
1172
+ const panels = [];
1144
1173
  const settings = new LocalStorageStore("dxos.org/settings/layout", {
1145
- showFooter: false,
1174
+ showHints: false,
1146
1175
  customSlots: false,
1147
1176
  flatDeck: false,
1148
1177
  enableNativeRedirect: false,
@@ -1227,6 +1256,22 @@ var DeckPlugin = ({ observability } = {}) => {
1227
1256
  }
1228
1257
  }
1229
1258
  };
1259
+ const handleSetLocation = (next) => {
1260
+ if (attentionPlugin) {
1261
+ const attended = attentionPlugin.provides.attention.attended;
1262
+ const [attendedId] = Array.from(attended);
1263
+ const ids = (layout.values.layoutMode === "deck" ? next.main : next.solo)?.map(({ id }) => id) ?? [];
1264
+ const isAttendedAvailable = !!attendedId && ids.includes(attendedId);
1265
+ if (!isAttendedAvailable) {
1266
+ requestAnimationFrame(() => {
1267
+ const nextAttended = layout.values.layoutMode === "solo" ? next.solo?.[0].id : next.main?.[0]?.id;
1268
+ const article = document.querySelector(`article[data-attendable-id="${nextAttended}"]`);
1269
+ article?.focus();
1270
+ });
1271
+ }
1272
+ }
1273
+ location.values.active = next;
1274
+ };
1230
1275
  return {
1231
1276
  meta: meta_default,
1232
1277
  ready: async (plugins) => {
@@ -1236,63 +1281,51 @@ var DeckPlugin = ({ observability } = {}) => {
1236
1281
  clientPlugin = resolvePlugin(plugins, parseClientPlugin);
1237
1282
  layout.prop({
1238
1283
  key: "layoutMode",
1239
- storageKey: "layout-mode",
1240
1284
  type: LocalStorageStore.enum()
1241
1285
  }).prop({
1242
1286
  key: "sidebarOpen",
1243
- storageKey: "sidebar-open",
1244
1287
  type: LocalStorageStore.bool()
1245
1288
  }).prop({
1246
1289
  key: "complementarySidebarOpen",
1247
- storageKey: "complementary-sidebar-open",
1248
1290
  type: LocalStorageStore.bool()
1249
1291
  });
1250
1292
  deck.prop({
1251
1293
  key: "plankSizing",
1252
- storageKey: "plank-sizing",
1253
1294
  type: LocalStorageStore.json()
1254
1295
  });
1255
1296
  location.prop({
1256
1297
  key: "active",
1257
- storageKey: "active",
1258
1298
  type: LocalStorageStore.json()
1259
1299
  }).prop({
1260
1300
  key: "closed",
1261
- storageKey: "closed",
1262
1301
  type: LocalStorageStore.json()
1263
1302
  });
1303
+ panels.push(...filterPlugins(plugins, parsePanelPlugin).flatMap((plugin) => plugin.provides.complementary.panels));
1264
1304
  unsubscriptionCallbacks.push(clientPlugin?.provides.client.shell.onReset(() => {
1265
1305
  layout.expunge();
1266
1306
  location.expunge();
1267
1307
  deck.expunge();
1268
1308
  }));
1269
1309
  settings.prop({
1270
- key: "showFooter",
1271
- storageKey: "show-footer",
1310
+ key: "showHints",
1272
1311
  type: LocalStorageStore.bool()
1273
1312
  }).prop({
1274
1313
  key: "customSlots",
1275
- storageKey: "customSlots",
1276
1314
  type: LocalStorageStore.bool()
1277
1315
  }).prop({
1278
1316
  key: "flatDeck",
1279
- storageKey: "flatDeck",
1280
1317
  type: LocalStorageStore.bool()
1281
1318
  }).prop({
1282
1319
  key: "enableNativeRedirect",
1283
- storageKey: "enable-native-redirect",
1284
1320
  type: LocalStorageStore.bool()
1285
1321
  }).prop({
1286
1322
  key: "disableDeck",
1287
- storageKey: "disable-deck",
1288
1323
  type: LocalStorageStore.bool()
1289
1324
  }).prop({
1290
1325
  key: "newPlankPositioning",
1291
- storageKey: "newPlankPositioning",
1292
1326
  type: LocalStorageStore.enum()
1293
1327
  }).prop({
1294
1328
  key: "overscroll",
1295
- storageKey: "overscroll",
1296
1329
  type: LocalStorageStore.enum()
1297
1330
  });
1298
1331
  if (!isSocket2 && settings.values.enableNativeRedirect) {
@@ -1301,13 +1334,13 @@ var DeckPlugin = ({ observability } = {}) => {
1301
1334
  handleNavigation = async () => {
1302
1335
  const pathname = window.location.pathname;
1303
1336
  if (pathname === "/reset") {
1304
- location.values.active = {
1337
+ handleSetLocation({
1305
1338
  sidebar: [
1306
1339
  {
1307
1340
  id: NAV_ID
1308
1341
  }
1309
1342
  ]
1310
- };
1343
+ });
1311
1344
  location.values.closed = [];
1312
1345
  layout.values.layoutMode = "solo";
1313
1346
  window.location.pathname = "/";
@@ -1318,26 +1351,16 @@ var DeckPlugin = ({ observability } = {}) => {
1318
1351
  return;
1319
1352
  }
1320
1353
  const startingLayout = removePart(location.values.active, "solo");
1321
- location.values.active = mergeLayoutParts(layoutFromUri, startingLayout);
1354
+ handleSetLocation(mergeLayoutParts(layoutFromUri, startingLayout));
1322
1355
  layout.values.layoutMode = "solo";
1323
1356
  };
1324
1357
  await handleNavigation();
1325
1358
  window.addEventListener("popstate", handleNavigation);
1326
- unsubscriptionCallbacks.push(effect(() => {
1327
- const selectedPath = soloPartToUri(location.values.active);
1359
+ unsubscriptionCallbacks.push(scheduledEffect(() => ({
1360
+ selectedPath: soloPartToUri(location.values.active)
1361
+ }), ({ selectedPath }) => {
1328
1362
  history.pushState(null, "", `/${selectedPath}${window.location.search}`);
1329
1363
  }));
1330
- unsubscriptionCallbacks.push(effect(() => {
1331
- const soloId = location.values.active.solo?.[0].id;
1332
- if (layout.values.layoutMode === "solo" && soloId && layout.values.scrollIntoView !== soloId) {
1333
- void intentPlugin?.provides.intent.dispatch({
1334
- action: LayoutAction3.SCROLL_INTO_VIEW,
1335
- data: {
1336
- id: soloId
1337
- }
1338
- });
1339
- }
1340
- }));
1341
1364
  layoutModeHistory.values.push(`${layout.values.layoutMode}`);
1342
1365
  },
1343
1366
  unload: async () => {
@@ -1380,8 +1403,7 @@ var DeckPlugin = ({ observability } = {}) => {
1380
1403
  ns: DECK_PLUGIN
1381
1404
  }
1382
1405
  ],
1383
- icon: (props) => /* @__PURE__ */ React15.createElement(ArrowsOut, props),
1384
- iconSymbol: "ph--arrows-out--regular",
1406
+ icon: "ph--arrows-out--regular",
1385
1407
  keyBinding: {
1386
1408
  macos: "ctrl+meta+f",
1387
1409
  windows: "shift+ctrl+f"
@@ -1398,16 +1420,14 @@ var DeckPlugin = ({ observability } = {}) => {
1398
1420
  value: deck.values
1399
1421
  }, props.children)),
1400
1422
  root: () => {
1401
- return /* @__PURE__ */ React15.createElement(Mosaic.Root, null, /* @__PURE__ */ React15.createElement(DeckLayout, {
1402
- attention: attentionPlugin?.provides.attention ?? {
1403
- attended: /* @__PURE__ */ new Set()
1404
- },
1423
+ return /* @__PURE__ */ React15.createElement(DeckLayout, {
1405
1424
  layoutParts: location.values.active,
1406
- showHintsFooter: settings.values.showFooter,
1425
+ showHints: settings.values.showHints,
1407
1426
  overscroll: settings.values.overscroll,
1408
1427
  flatDeck: settings.values.flatDeck,
1409
1428
  slots: settings.values.customSlots ? customSlots : void 0,
1410
1429
  toasts: layout.values.toasts,
1430
+ panels,
1411
1431
  onDismissToast: (id) => {
1412
1432
  const index = layout.values.toasts.findIndex((toast) => toast.id === id);
1413
1433
  if (index !== -1) {
@@ -1419,7 +1439,7 @@ var DeckPlugin = ({ observability } = {}) => {
1419
1439
  }, 1e3);
1420
1440
  }
1421
1441
  }
1422
- }), /* @__PURE__ */ React15.createElement(Mosaic.DragOverlay, null));
1442
+ });
1423
1443
  },
1424
1444
  surface: {
1425
1445
  component: ({ data, role }) => {
@@ -1455,7 +1475,7 @@ var DeckPlugin = ({ observability } = {}) => {
1455
1475
  } else {
1456
1476
  log.warn("Invalid layout mode", intent?.data?.layoutMode, {
1457
1477
  F: __dxlog_file,
1458
- L: 390,
1478
+ L: 406,
1459
1479
  S: void 0,
1460
1480
  C: (f, a) => f(...a)
1461
1481
  });
@@ -1501,7 +1521,7 @@ var DeckPlugin = ({ observability } = {}) => {
1501
1521
  data: true
1502
1522
  };
1503
1523
  }
1504
- case NavigationAction3.OPEN: {
1524
+ case NavigationAction4.OPEN: {
1505
1525
  const previouslyOpenIds = new Set(openIds2(location.values.active));
1506
1526
  const layoutMode = layout.values.layoutMode;
1507
1527
  batch(() => {
@@ -1510,7 +1530,7 @@ var DeckPlugin = ({ observability } = {}) => {
1510
1530
  }
1511
1531
  const processLayoutEntry = (partName, entryString, currentLayout) => {
1512
1532
  const toggle = true;
1513
- const [id, path] = entryString.split(SLUG_PATH_SEPARATOR5);
1533
+ const [id, path] = entryString.split(SLUG_PATH_SEPARATOR4);
1514
1534
  const layoutEntry = {
1515
1535
  id,
1516
1536
  ...path ? {
@@ -1539,7 +1559,7 @@ var DeckPlugin = ({ observability } = {}) => {
1539
1559
  newLayout = processLayoutEntry(partName, layoutEntries, newLayout);
1540
1560
  }
1541
1561
  });
1542
- location.values.active = newLayout;
1562
+ handleSetLocation(newLayout);
1543
1563
  });
1544
1564
  const ids = openIds2(location.values.active);
1545
1565
  const newlyOpen = ids.filter((i) => !previouslyOpenIds.has(i));
@@ -1558,7 +1578,7 @@ var DeckPlugin = ({ observability } = {}) => {
1558
1578
  ] : [],
1559
1579
  intent.data?.object ? [
1560
1580
  {
1561
- action: NavigationAction3.EXPOSE,
1581
+ action: NavigationAction4.EXPOSE,
1562
1582
  data: {
1563
1583
  id: fullyQualifiedId(intent.data.object)
1564
1584
  }
@@ -1581,16 +1601,16 @@ var DeckPlugin = ({ observability } = {}) => {
1581
1601
  ]
1582
1602
  };
1583
1603
  }
1584
- case NavigationAction3.ADD_TO_ACTIVE: {
1604
+ case NavigationAction4.ADD_TO_ACTIVE: {
1585
1605
  const data = intent.data;
1586
1606
  const layoutEntry = {
1587
1607
  id: data.id
1588
1608
  };
1589
1609
  const effectivePart = getEffectivePart(data.part, layout.values.layoutMode);
1590
- location.values.active = openEntry(location.values.active, effectivePart, layoutEntry, {
1610
+ handleSetLocation(openEntry(location.values.active, effectivePart, layoutEntry, {
1591
1611
  positioning: data.positioning ?? settings.values.newPlankPositioning,
1592
1612
  pivotId: data.pivotId
1593
- });
1613
+ }));
1594
1614
  const intents = [];
1595
1615
  if (data.scrollIntoView && layout.values.layoutMode === "deck") {
1596
1616
  intents.push([
@@ -1607,7 +1627,7 @@ var DeckPlugin = ({ observability } = {}) => {
1607
1627
  intents
1608
1628
  };
1609
1629
  }
1610
- case NavigationAction3.CLOSE: {
1630
+ case NavigationAction4.CLOSE: {
1611
1631
  return batch(() => {
1612
1632
  if (!intent.data) {
1613
1633
  return;
@@ -1632,32 +1652,32 @@ var DeckPlugin = ({ observability } = {}) => {
1632
1652
  });
1633
1653
  }
1634
1654
  });
1635
- location.values.active = newLayout;
1655
+ handleSetLocation(newLayout);
1636
1656
  return {
1637
1657
  data: true
1638
1658
  };
1639
1659
  });
1640
1660
  }
1641
1661
  // TODO(wittjosiah): Factor out.
1642
- case NavigationAction3.SET: {
1662
+ case NavigationAction4.SET: {
1643
1663
  return batch(() => {
1644
1664
  if (isLayoutParts(intent.data?.activeParts)) {
1645
- location.values.active = intent.data.activeParts;
1665
+ handleSetLocation(intent.data.activeParts);
1646
1666
  }
1647
1667
  return {
1648
1668
  data: true
1649
1669
  };
1650
1670
  });
1651
1671
  }
1652
- case NavigationAction3.ADJUST: {
1672
+ case NavigationAction4.ADJUST: {
1653
1673
  return batch(() => {
1654
1674
  if (isLayoutAdjustment(intent.data)) {
1655
1675
  const adjustment = intent.data;
1656
1676
  if (adjustment.type === "increment-end" || adjustment.type === "increment-start") {
1657
- location.values.active = incrementPlank(location.values.active, {
1677
+ handleSetLocation(incrementPlank(location.values.active, {
1658
1678
  type: adjustment.type,
1659
1679
  layoutCoordinate: adjustment.layoutCoordinate
1660
- });
1680
+ }));
1661
1681
  }
1662
1682
  if (adjustment.type === "solo") {
1663
1683
  const entryId = adjustment.layoutCoordinate.entryId;
@@ -1673,7 +1693,7 @@ var DeckPlugin = ({ observability } = {}) => {
1673
1693
  }
1674
1694
  },
1675
1695
  {
1676
- action: NavigationAction3.OPEN,
1696
+ action: NavigationAction4.OPEN,
1677
1697
  data: {
1678
1698
  activeParts: {
1679
1699
  solo: [
@@ -1697,7 +1717,7 @@ var DeckPlugin = ({ observability } = {}) => {
1697
1717
  }
1698
1718
  },
1699
1719
  {
1700
- action: NavigationAction3.CLOSE,
1720
+ action: NavigationAction4.CLOSE,
1701
1721
  data: {
1702
1722
  activeParts: {
1703
1723
  solo: [
@@ -1707,7 +1727,7 @@ var DeckPlugin = ({ observability } = {}) => {
1707
1727
  }
1708
1728
  },
1709
1729
  {
1710
- action: NavigationAction3.OPEN,
1730
+ action: NavigationAction4.OPEN,
1711
1731
  data: {
1712
1732
  noToggle: true,
1713
1733
  activeParts: {