@dxos/plugin-deck 0.7.4 → 0.7.5-labs.5f04cf6

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 (174) hide show
  1. package/dist/lib/browser/app-graph-builder-67VRUD5K.mjs +121 -0
  2. package/dist/lib/browser/app-graph-builder-67VRUD5K.mjs.map +7 -0
  3. package/dist/lib/browser/check-app-scheme-GEX6W2R5.mjs +33 -0
  4. package/dist/lib/browser/check-app-scheme-GEX6W2R5.mjs.map +7 -0
  5. package/dist/lib/browser/chunk-2PJNBVCY.mjs +39 -0
  6. package/dist/lib/browser/chunk-2PJNBVCY.mjs.map +7 -0
  7. package/dist/lib/browser/chunk-4C2AFTET.mjs +186 -0
  8. package/dist/lib/browser/chunk-4C2AFTET.mjs.map +7 -0
  9. package/dist/lib/browser/chunk-5VFDMW5M.mjs +17 -0
  10. package/dist/lib/browser/chunk-5VFDMW5M.mjs.map +7 -0
  11. package/dist/lib/browser/{chunk-GVOGPULO.mjs → chunk-JQJ5UWVB.mjs} +3 -3
  12. package/dist/lib/browser/chunk-JQJ5UWVB.mjs.map +7 -0
  13. package/dist/lib/browser/chunk-KY5WXIXY.mjs +44 -0
  14. package/dist/lib/browser/chunk-KY5WXIXY.mjs.map +7 -0
  15. package/dist/lib/browser/chunk-WUMAJGVA.mjs +1052 -0
  16. package/dist/lib/browser/chunk-WUMAJGVA.mjs.map +7 -0
  17. package/dist/lib/browser/deck-PLCSKPGL.mjs +26 -0
  18. package/dist/lib/browser/deck-PLCSKPGL.mjs.map +7 -0
  19. package/dist/lib/browser/index.mjs +142 -1803
  20. package/dist/lib/browser/index.mjs.map +4 -4
  21. package/dist/lib/browser/intent-resolver-FVOQSTBX.mjs +152 -0
  22. package/dist/lib/browser/intent-resolver-FVOQSTBX.mjs.map +7 -0
  23. package/dist/lib/browser/intent-resolver-K7GW4A2I.mjs +249 -0
  24. package/dist/lib/browser/intent-resolver-K7GW4A2I.mjs.map +7 -0
  25. package/dist/lib/browser/location-AIO6V3MK.mjs +35 -0
  26. package/dist/lib/browser/location-AIO6V3MK.mjs.map +7 -0
  27. package/dist/lib/browser/meta.json +1 -1
  28. package/dist/lib/browser/react-context-G6PDXUI5.mjs +32 -0
  29. package/dist/lib/browser/react-context-G6PDXUI5.mjs.map +7 -0
  30. package/dist/lib/browser/react-root-AWYSGU4Q.mjs +50 -0
  31. package/dist/lib/browser/react-root-AWYSGU4Q.mjs.map +7 -0
  32. package/dist/lib/browser/react-surface-CLUABFNX.mjs +28 -0
  33. package/dist/lib/browser/react-surface-CLUABFNX.mjs.map +7 -0
  34. package/dist/lib/browser/settings-FNWW6WIJ.mjs +29 -0
  35. package/dist/lib/browser/settings-FNWW6WIJ.mjs.map +7 -0
  36. package/dist/lib/browser/state-7I5BD7SE.mjs +34 -0
  37. package/dist/lib/browser/state-7I5BD7SE.mjs.map +7 -0
  38. package/dist/lib/browser/tools-4XY7KFQF.mjs +46 -0
  39. package/dist/lib/browser/tools-4XY7KFQF.mjs.map +7 -0
  40. package/dist/lib/browser/types.mjs +10 -5
  41. package/dist/lib/browser/url-handler-JRAQRY73.mjs +76 -0
  42. package/dist/lib/browser/url-handler-JRAQRY73.mjs.map +7 -0
  43. package/dist/types/src/DeckPlugin.d.ts +1 -14
  44. package/dist/types/src/DeckPlugin.d.ts.map +1 -1
  45. package/dist/types/src/capabilities/capabilities.d.ts +13 -0
  46. package/dist/types/src/capabilities/capabilities.d.ts.map +1 -0
  47. package/dist/types/src/capabilities/index.d.ts +5 -0
  48. package/dist/types/src/capabilities/index.d.ts.map +1 -0
  49. package/dist/types/src/capabilities/layout/app-graph-builder.d.ts +181 -0
  50. package/dist/types/src/capabilities/layout/app-graph-builder.d.ts.map +1 -0
  51. package/dist/types/src/capabilities/layout/deck.d.ts +4 -0
  52. package/dist/types/src/capabilities/layout/deck.d.ts.map +1 -0
  53. package/dist/types/src/capabilities/layout/index.d.ts +229 -0
  54. package/dist/types/src/capabilities/layout/index.d.ts.map +1 -0
  55. package/dist/types/src/capabilities/layout/intent-resolver.d.ts +4 -0
  56. package/dist/types/src/capabilities/layout/intent-resolver.d.ts.map +1 -0
  57. package/dist/types/src/capabilities/layout/react-context.d.ts +8 -0
  58. package/dist/types/src/capabilities/layout/react-context.d.ts.map +1 -0
  59. package/dist/types/src/capabilities/layout/react-root.d.ts +7 -0
  60. package/dist/types/src/capabilities/layout/react-root.d.ts.map +1 -0
  61. package/dist/types/src/capabilities/layout/state.d.ts +42 -0
  62. package/dist/types/src/capabilities/layout/state.d.ts.map +1 -0
  63. package/dist/types/src/capabilities/navigation/check-app-scheme.d.ts +4 -0
  64. package/dist/types/src/capabilities/navigation/check-app-scheme.d.ts.map +1 -0
  65. package/dist/types/src/capabilities/navigation/index.d.ts +6 -0
  66. package/dist/types/src/capabilities/navigation/index.d.ts.map +1 -0
  67. package/dist/types/src/capabilities/navigation/intent-resolver.d.ts +4 -0
  68. package/dist/types/src/capabilities/navigation/intent-resolver.d.ts.map +1 -0
  69. package/dist/types/src/capabilities/navigation/location.d.ts +4 -0
  70. package/dist/types/src/capabilities/navigation/location.d.ts.map +1 -0
  71. package/dist/types/src/capabilities/navigation/set-location.d.ts +10 -0
  72. package/dist/types/src/capabilities/navigation/set-location.d.ts.map +1 -0
  73. package/dist/types/src/capabilities/navigation/tools.d.ts +9 -0
  74. package/dist/types/src/capabilities/navigation/tools.d.ts.map +1 -0
  75. package/dist/types/src/capabilities/navigation/url-handler.d.ts +4 -0
  76. package/dist/types/src/capabilities/navigation/url-handler.d.ts.map +1 -0
  77. package/dist/types/src/capabilities/settings/index.d.ts +3 -0
  78. package/dist/types/src/capabilities/settings/index.d.ts.map +1 -0
  79. package/dist/types/src/capabilities/settings/react-surface.d.ts +4 -0
  80. package/dist/types/src/capabilities/settings/react-surface.d.ts.map +1 -0
  81. package/dist/types/src/capabilities/settings/settings.d.ts +4 -0
  82. package/dist/types/src/capabilities/settings/settings.d.ts.map +1 -0
  83. package/dist/types/src/components/DeckContext.d.ts +3 -0
  84. package/dist/types/src/components/DeckContext.d.ts.map +1 -1
  85. package/dist/types/src/components/DeckLayout/Banner.d.ts +6 -0
  86. package/dist/types/src/components/DeckLayout/Banner.d.ts.map +1 -0
  87. package/dist/types/src/components/DeckLayout/ComplementarySidebar.d.ts.map +1 -1
  88. package/dist/types/src/components/DeckLayout/ContentEmpty.d.ts.map +1 -1
  89. package/dist/types/src/components/DeckLayout/DeckLayout.d.ts.map +1 -1
  90. package/dist/types/src/components/DeckLayout/NodePlankHeading.d.ts.map +1 -1
  91. package/dist/types/src/components/DeckLayout/Plank.d.ts +1 -1
  92. package/dist/types/src/components/DeckLayout/Plank.d.ts.map +1 -1
  93. package/dist/types/src/components/DeckLayout/PlankControls.d.ts +2 -2
  94. package/dist/types/src/components/DeckLayout/PlankControls.d.ts.map +1 -1
  95. package/dist/types/src/components/DeckLayout/Sidebar.d.ts +1 -5
  96. package/dist/types/src/components/DeckLayout/Sidebar.d.ts.map +1 -1
  97. package/dist/types/src/components/DeckLayout/SidebarButton.d.ts +6 -0
  98. package/dist/types/src/components/DeckLayout/SidebarButton.d.ts.map +1 -0
  99. package/dist/types/src/components/DeckLayout/Toast.d.ts.map +1 -1
  100. package/dist/types/src/components/DeckLayout/Topbar.d.ts +3 -0
  101. package/dist/types/src/components/DeckLayout/Topbar.d.ts.map +1 -0
  102. package/dist/types/src/components/fragments.d.ts +2 -0
  103. package/dist/types/src/components/fragments.d.ts.map +1 -0
  104. package/dist/types/src/events.d.ts +4 -0
  105. package/dist/types/src/events.d.ts.map +1 -0
  106. package/dist/types/src/index.d.ts +3 -2
  107. package/dist/types/src/index.d.ts.map +1 -1
  108. package/dist/types/src/meta.d.ts +3 -4
  109. package/dist/types/src/meta.d.ts.map +1 -1
  110. package/dist/types/src/translations.d.ts +5 -0
  111. package/dist/types/src/translations.d.ts.map +1 -1
  112. package/dist/types/src/types.d.ts +25 -17
  113. package/dist/types/src/types.d.ts.map +1 -1
  114. package/dist/types/src/util/index.d.ts +1 -1
  115. package/dist/types/src/util/index.d.ts.map +1 -1
  116. package/dist/types/src/util/useBreakpoints.d.ts +2 -0
  117. package/dist/types/src/util/useBreakpoints.d.ts.map +1 -0
  118. package/dist/types/src/util/useHoistStatusbar.d.ts +2 -0
  119. package/dist/types/src/util/useHoistStatusbar.d.ts.map +1 -0
  120. package/dist/types/tsconfig.tsbuildinfo +1 -0
  121. package/package.json +31 -35
  122. package/src/DeckPlugin.ts +129 -0
  123. package/src/capabilities/capabilities.ts +17 -0
  124. package/src/capabilities/index.ts +8 -0
  125. package/src/capabilities/layout/app-graph-builder.ts +101 -0
  126. package/src/capabilities/layout/deck.ts +25 -0
  127. package/src/capabilities/layout/index.ts +12 -0
  128. package/src/capabilities/layout/intent-resolver.ts +128 -0
  129. package/src/capabilities/layout/react-context.tsx +26 -0
  130. package/src/capabilities/layout/react-root.tsx +52 -0
  131. package/src/capabilities/layout/state.ts +32 -0
  132. package/src/capabilities/navigation/check-app-scheme.ts +44 -0
  133. package/src/capabilities/navigation/index.ts +11 -0
  134. package/src/capabilities/navigation/intent-resolver.ts +216 -0
  135. package/src/capabilities/navigation/location.ts +28 -0
  136. package/src/capabilities/navigation/set-location.ts +38 -0
  137. package/src/capabilities/navigation/tools.ts +57 -0
  138. package/src/capabilities/navigation/url-handler.ts +67 -0
  139. package/src/capabilities/settings/index.ts +8 -0
  140. package/src/capabilities/settings/react-surface.tsx +23 -0
  141. package/src/capabilities/settings/settings.ts +22 -0
  142. package/src/components/DeckContext.ts +6 -1
  143. package/src/components/DeckLayout/ActiveNode.tsx +1 -1
  144. package/src/components/DeckLayout/Banner.tsx +37 -0
  145. package/src/components/DeckLayout/ComplementarySidebar.tsx +76 -53
  146. package/src/components/DeckLayout/ContentEmpty.tsx +10 -2
  147. package/src/components/DeckLayout/DeckLayout.tsx +31 -40
  148. package/src/components/DeckLayout/Fullscreen.tsx +1 -1
  149. package/src/components/DeckLayout/NodePlankHeading.tsx +30 -49
  150. package/src/components/DeckLayout/Plank.tsx +13 -11
  151. package/src/components/DeckLayout/PlankControls.tsx +3 -5
  152. package/src/components/DeckLayout/Sidebar.tsx +22 -26
  153. package/src/components/DeckLayout/SidebarButton.tsx +74 -0
  154. package/src/components/DeckLayout/StatusBar.tsx +2 -2
  155. package/src/components/DeckLayout/Toast.tsx +19 -6
  156. package/src/components/DeckLayout/Topbar.tsx +11 -0
  157. package/src/components/fragments.ts +6 -0
  158. package/src/events.ts +11 -0
  159. package/src/index.ts +3 -4
  160. package/src/meta.ts +2 -2
  161. package/src/translations.ts +5 -0
  162. package/src/types.ts +27 -37
  163. package/src/util/index.ts +1 -1
  164. package/src/util/useBreakpoints.ts +11 -0
  165. package/src/util/useHoistStatusbar.ts +15 -0
  166. package/dist/lib/browser/chunk-GVOGPULO.mjs.map +0 -7
  167. package/dist/lib/browser/chunk-NIRHDTX4.mjs +0 -17
  168. package/dist/lib/browser/chunk-NIRHDTX4.mjs.map +0 -7
  169. package/dist/lib/browser/meta.mjs +0 -9
  170. package/dist/lib/browser/meta.mjs.map +0 -7
  171. package/dist/types/src/util/check-app-scheme.d.ts +0 -2
  172. package/dist/types/src/util/check-app-scheme.d.ts.map +0 -1
  173. package/src/DeckPlugin.tsx +0 -657
  174. package/src/util/check-app-scheme.ts +0 -21
@@ -2,25 +2,21 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
- import React, { useMemo } from 'react';
5
+ import React, { useCallback, useEffect, useMemo, useState } from 'react';
6
6
 
7
- import {
8
- type LayoutCoordinate,
9
- NavigationAction,
10
- SLUG_PATH_SEPARATOR,
11
- Surface,
12
- useIntentDispatcher,
13
- } from '@dxos/app-framework';
7
+ import { createIntent, NavigationAction, SLUG_PATH_SEPARATOR, Surface, useIntentDispatcher } from '@dxos/app-framework';
14
8
  import { useGraph } from '@dxos/plugin-graph';
15
- import { Main, ScrollArea } from '@dxos/react-ui';
9
+ import { Main, ScrollArea, useTranslation, toLocalizedString } from '@dxos/react-ui';
16
10
  import { useAttended } from '@dxos/react-ui-attention';
17
- import { railGridHorizontal, StackContext } from '@dxos/react-ui-stack';
11
+ import { railGridHorizontal, StackContext, StackItem } from '@dxos/react-ui-stack';
12
+ import { Tabs } from '@dxos/react-ui-tabs';
18
13
  import { mx } from '@dxos/react-ui-theme';
19
14
 
20
- import { NodePlankHeading } from './NodePlankHeading';
21
15
  import { PlankContentError } from './PlankError';
22
16
  import { PlankLoading } from './PlankLoading';
17
+ import { CloseComplementarySidebarButton } from './SidebarButton';
23
18
  import { useNode, useNodeActionExpander } from '../../hooks';
19
+ import { DECK_PLUGIN } from '../../meta';
24
20
  import { type Panel } from '../../types';
25
21
  import { useLayout } from '../LayoutContext';
26
22
 
@@ -32,56 +28,83 @@ export type ComplementarySidebarProps = {
32
28
  export const ComplementarySidebar = ({ panels, current }: ComplementarySidebarProps) => {
33
29
  const { popoverAnchorId } = useLayout();
34
30
  const attended = useAttended();
35
- const panel = (panels.find((p) => p.id === current) ?? panels[0])?.id;
36
- const id = attended[0] ? `${attended[0]}${SLUG_PATH_SEPARATOR}${panel}` : undefined;
31
+ const panelIds = useMemo(() => panels.map((p) => p.id), [panels]);
32
+ const activePanelId = panelIds.find((p) => p === current) ?? panels[0].id;
33
+ const activeEntryId = attended[0] ? `${attended[0]}${SLUG_PATH_SEPARATOR}${activePanelId}` : undefined;
37
34
  const { graph } = useGraph();
38
- const node = useNode(graph, id);
39
- const dispatch = useIntentDispatcher();
35
+ const node = useNode(graph, activeEntryId);
36
+ const { t } = useTranslation(DECK_PLUGIN);
37
+ const { dispatchPromise: dispatch } = useIntentDispatcher();
40
38
  useNodeActionExpander(node);
41
39
 
42
- const actions = useMemo(
43
- () =>
44
- panels.map(({ id, label, icon }) => ({
45
- id: `complementary-${id}`,
46
- data: () => {
47
- void dispatch({ action: NavigationAction.OPEN, data: { activeParts: { complementary: id } } });
48
- },
49
- properties: {
50
- label,
51
- icon,
52
- menuItemType: 'toggle',
53
- isChecked: panel === id,
54
- },
55
- })),
56
- [panel],
57
- );
40
+ const [internalValue, setInternalValue] = useState(activePanelId);
41
+
42
+ useEffect(() => {
43
+ setInternalValue(activePanelId);
44
+ }, [activePanelId]);
58
45
 
59
- // TODO(wittjosiah): Ensure that id is always defined.
60
- const coordinate: LayoutCoordinate = useMemo(() => ({ entryId: id ?? 'unknown', part: 'complementary' }), [id]);
46
+ const handleValueChange = useCallback(
47
+ (nextValue: string) => {
48
+ setInternalValue(nextValue);
49
+ void dispatch(createIntent(NavigationAction.Open, { activeParts: { complementary: nextValue } }));
50
+ },
51
+ [dispatch],
52
+ );
61
53
 
62
54
  // TODO(burdon): Scroll area should be controlled by surface.
63
55
  return (
64
- <Main.ComplementarySidebar>
65
- <StackContext.Provider value={{ size: 'contain', orientation: 'horizontal', separators: false, rail: true }}>
56
+ <Main.ComplementarySidebar classNames='lg:block-start-[calc(env(safe-area-inset-top)+var(--rail-size))]'>
57
+ <StackContext.Provider value={{ size: 'contain', orientation: 'horizontal', rail: true }}>
66
58
  <div role='none' className={mx(railGridHorizontal, 'grid grid-cols-[100%] bs-full')}>
67
- <NodePlankHeading coordinate={coordinate} node={node} popoverAnchorId={popoverAnchorId} actions={actions} />
68
- <ScrollArea.Root>
69
- <ScrollArea.Viewport>
70
- {node && (
71
- <Surface
72
- key={id}
73
- role={`complementary--${panel}`}
74
- limit={1}
75
- data={{ id, subject: node.properties.object ?? node.properties.space, popoverAnchorId }}
76
- fallback={PlankContentError}
77
- placeholder={<PlankLoading />}
78
- />
79
- )}
80
- <ScrollArea.Scrollbar orientation='vertical'>
81
- <ScrollArea.Thumb />
82
- </ScrollArea.Scrollbar>
83
- </ScrollArea.Viewport>
84
- </ScrollArea.Root>
59
+ <Tabs.Root
60
+ orientation='horizontal'
61
+ value={internalValue}
62
+ onValueChange={handleValueChange}
63
+ attendableId={attended[0]}
64
+ classNames='contents'
65
+ >
66
+ <StackItem.Heading classNames='border-be border-separator grid grid-cols-[1fr_min-content] items-stretch'>
67
+ <ScrollArea.Root classNames='flex-1 min-is-0'>
68
+ <ScrollArea.Viewport>
69
+ <Tabs.Tablist classNames='bs-[--rail-content] is-min items-stretch pis-[max(.5rem,env(safe-area-inset-left))] sm:pis-2'>
70
+ {panels.map((panel) => (
71
+ <Tabs.Tab key={panel.id} value={panel.id} classNames='!min-bs-0'>
72
+ {toLocalizedString(panel.label, t)}
73
+ </Tabs.Tab>
74
+ ))}
75
+ </Tabs.Tablist>
76
+ <ScrollArea.Scrollbar orientation='horizontal'>
77
+ <ScrollArea.Thumb />
78
+ </ScrollArea.Scrollbar>
79
+ </ScrollArea.Viewport>
80
+ </ScrollArea.Root>
81
+ <CloseComplementarySidebarButton />
82
+ </StackItem.Heading>
83
+ <ScrollArea.Root>
84
+ <ScrollArea.Viewport>
85
+ {panels.map((panel) => (
86
+ <Tabs.Tabpanel key={panel.id} value={panel.id} classNames='pbe-[env(safe-area-inset-bottom)]'>
87
+ {panel.id === activePanelId && node && (
88
+ <Surface
89
+ key={activeEntryId}
90
+ role={`complementary--${activePanelId}`}
91
+ data={{
92
+ id: activeEntryId,
93
+ subject: node.properties.object ?? node.properties.space,
94
+ popoverAnchorId,
95
+ }}
96
+ fallback={PlankContentError}
97
+ placeholder={<PlankLoading />}
98
+ />
99
+ )}
100
+ </Tabs.Tabpanel>
101
+ ))}
102
+ <ScrollArea.Scrollbar orientation='vertical'>
103
+ <ScrollArea.Thumb />
104
+ </ScrollArea.Scrollbar>
105
+ </ScrollArea.Viewport>
106
+ </ScrollArea.Root>
107
+ </Tabs.Root>
85
108
  </div>
86
109
  </StackContext.Provider>
87
110
  </Main.ComplementarySidebar>
@@ -5,15 +5,23 @@
5
5
  import React from 'react';
6
6
 
7
7
  import { Surface } from '@dxos/app-framework';
8
+ import { mx } from '@dxos/react-ui-theme';
9
+
10
+ import { ToggleSidebarButton } from './SidebarButton';
11
+ import { soloInlinePadding } from '../fragments';
8
12
 
9
13
  export const ContentEmpty = () => {
10
14
  return (
11
15
  <div
12
16
  role='none'
13
- className='min-bs-screen is-dvw sm:is-full flex items-center justify-center p-8'
17
+ className='min-bs-screen is-dvw sm:is-full p-8 grid grid-rows-[var(--rail-size)_1fr] lg:grid-rows-1'
14
18
  data-testid='layoutPlugin.firstRunMessage'
15
19
  >
16
- <div role='none' className='grid place-items-center grid-rows-[min-content_min-content]'>
20
+ <div role='toolbar' className={mx(soloInlinePadding, 'bs-[--rail-action] flex items-stretch lg:hidden')}>
21
+ <ToggleSidebarButton />
22
+ <span role='none' className='grow' />
23
+ </div>
24
+ <div role='none' className='grid place-items-center'>
17
25
  <Surface role='keyshortcuts' />
18
26
  </div>
19
27
  </div>
@@ -2,24 +2,20 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
- import { Sidebar as MenuIcon } from '@phosphor-icons/react';
6
5
  import { untracked } from '@preact/signals-core';
7
6
  import React, { useCallback, useEffect, useMemo, useRef, type UIEvent, Fragment } from 'react';
8
7
 
9
- import { type LayoutParts, Surface, type Toast as ToastSchema, firstIdInPart, usePlugin } from '@dxos/app-framework';
10
- import { type AttentionPluginProvides } from '@dxos/plugin-attention';
11
8
  import {
12
- AlertDialog,
13
- Button,
14
- Dialog as NaturalDialog,
15
- Main,
16
- Popover,
17
- useOnTransition,
18
- useTranslation,
19
- type MainProps,
20
- } from '@dxos/react-ui';
9
+ firstIdInPart,
10
+ Surface,
11
+ usePluginManager,
12
+ type LayoutParts,
13
+ type Toast as ToastSchema,
14
+ } from '@dxos/app-framework';
15
+ import { AttentionCapabilities } from '@dxos/plugin-attention';
16
+ import { AlertDialog, Dialog as NaturalDialog, Main, Popover, useOnTransition, type MainProps } from '@dxos/react-ui';
21
17
  import { Stack, StackContext, DEFAULT_HORIZONTAL_SIZE } from '@dxos/react-ui-stack';
22
- import { getSize, mainPaddingTransitions } from '@dxos/react-ui-theme';
18
+ import { mainPaddingTransitions } from '@dxos/react-ui-theme';
23
19
 
24
20
  import { ActiveNode } from './ActiveNode';
25
21
  import { ComplementarySidebar, type ComplementarySidebarProps } from './ComplementarySidebar';
@@ -29,9 +25,10 @@ import { Plank } from './Plank';
29
25
  import { Sidebar } from './Sidebar';
30
26
  import { StatusBar } from './StatusBar';
31
27
  import { Toast } from './Toast';
32
- import { DECK_PLUGIN } from '../../meta';
28
+ import { Topbar } from './Topbar';
33
29
  import { type Overscroll } from '../../types';
34
- import { calculateOverscroll } from '../../util';
30
+ import { calculateOverscroll, useBreakpoints } from '../../util';
31
+ import { useHoistStatusbar } from '../../util/useHoistStatusbar';
35
32
  import { useDeckContext } from '../DeckContext';
36
33
  import { useLayout } from '../LayoutContext';
37
34
 
@@ -60,10 +57,10 @@ export const DeckLayout = ({ layoutParts, toasts, overscroll, showHints, panels,
60
57
  popoverContent,
61
58
  popoverAnchorId,
62
59
  } = context;
63
- const { t } = useTranslation(DECK_PLUGIN);
60
+ const breakpoint = useBreakpoints();
61
+ const hoistStatusbar = useHoistStatusbar(breakpoint);
64
62
  const { plankSizing } = useDeckContext();
65
- // NOTE: Not `useAttended` so that the layout component is not re-rendered when the attended list changes.
66
- const attentionPlugin = usePlugin<AttentionPluginProvides>('dxos.org/plugin/attention');
63
+ const pluginManager = usePluginManager();
67
64
  const fullScreenSlug = useMemo(() => firstIdInPart(layoutParts, 'fullScreen'), [layoutParts]);
68
65
 
69
66
  const scrollLeftRef = useRef<number | null>();
@@ -73,7 +70,11 @@ export const DeckLayout = ({ layoutParts, toasts, overscroll, showHints, panels,
73
70
 
74
71
  // Ensure the first plank is attended when the deck is first rendered.
75
72
  useEffect(() => {
76
- const attended = untracked(() => attentionPlugin?.provides.attention.attended ?? []);
73
+ // NOTE: Not `useAttended` so that the layout component is not re-rendered when the attended list changes.
74
+ const attended = untracked(() => {
75
+ const attention = pluginManager.context.requestCapability(AttentionCapabilities.Attention);
76
+ return attention.current;
77
+ });
77
78
  const firstId = isSoloModeLoaded ? firstIdInPart(layoutParts, 'solo') : firstIdInPart(layoutParts, 'main');
78
79
  if (attended.length === 0 && firstId) {
79
80
  // TODO(wittjosiah): Focusing the type button is a workaround.
@@ -149,18 +150,8 @@ export const DeckLayout = ({ layoutParts, toasts, overscroll, showHints, panels,
149
150
  complementarySidebarOpen={context.complementarySidebarOpen}
150
151
  onComplementarySidebarOpenChange={(next) => (context.complementarySidebarOpen = next)}
151
152
  >
152
- {/* Notch */}
153
- <Main.Notch classNames='z-[21]'>
154
- <Surface role='notch-start' />
155
- <Button onClick={() => (context.sidebarOpen = !context.sidebarOpen)} variant='ghost' classNames='p-1'>
156
- <span className='sr-only'>{t('open navigation sidebar label')}</span>
157
- <MenuIcon weight='light' className={getSize(5)} />
158
- </Button>
159
- <Surface role='notch-end' />
160
- </Main.Notch>
161
-
162
153
  {/* Left sidebar. */}
163
- <Sidebar layoutParts={layoutParts} />
154
+ <Sidebar />
164
155
 
165
156
  {/* Right sidebar. */}
166
157
  <ComplementarySidebar panels={panels} current={layoutParts.complementary?.[0].id} />
@@ -179,7 +170,10 @@ export const DeckLayout = ({ layoutParts, toasts, overscroll, showHints, panels,
179
170
  {!isEmpty && (
180
171
  <Main.Content
181
172
  bounce
182
- classNames='grid block-end-[--statusbar-size]'
173
+ classNames={[
174
+ 'grid !block-start-[env(safe-area-inset-top)] lg:!block-start-[calc(env(safe-area-inset-top)+var(--rail-size))]',
175
+ hoistStatusbar && 'lg:block-end-[--statusbar-size]',
176
+ ]}
183
177
  handlesFocus
184
178
  style={
185
179
  {
@@ -198,7 +192,6 @@ export const DeckLayout = ({ layoutParts, toasts, overscroll, showHints, panels,
198
192
  {...(isSoloModeLoaded && { inert: '' })}
199
193
  >
200
194
  <Stack
201
- separators={false}
202
195
  orientation='horizontal'
203
196
  size='contain'
204
197
  classNames={['absolute inset-block-0 -inset-inline-px', mainPaddingTransitions]}
@@ -226,31 +219,29 @@ export const DeckLayout = ({ layoutParts, toasts, overscroll, showHints, panels,
226
219
  className={isSoloModeLoaded ? 'relative bg-deck overflow-hidden' : 'sr-only'}
227
220
  {...(!isSoloModeLoaded && { inert: '' })}
228
221
  >
229
- <StackContext.Provider
230
- value={{ size: 'contain', orientation: 'horizontal', separators: false, rail: true }}
231
- >
222
+ <StackContext.Provider value={{ size: 'contain', orientation: 'horizontal', rail: true }}>
232
223
  <Plank entry={layoutParts.solo?.[0]} layoutParts={layoutParts} part='solo' layoutMode={layoutMode} />
233
224
  </StackContext.Provider>
234
225
  </div>
235
226
  </Main.Content>
236
227
  )}
237
228
 
238
- {/* Footer status. */}
239
- <StatusBar showHints={showHints} />
229
+ {/* Status bar. */}
230
+ {breakpoint === 'desktop' && <Topbar />}
231
+ {hoistStatusbar && <StatusBar showHints={showHints} />}
240
232
  </Main.Root>
241
233
  )}
242
234
 
243
235
  {/* Global popovers. */}
244
236
  <Popover.Portal>
245
237
  <Popover.Content
246
- classNames='z-[60]'
247
238
  onEscapeKeyDown={() => {
248
239
  context.popoverOpen = false;
249
240
  context.popoverAnchorId = undefined;
250
241
  }}
251
242
  >
252
243
  <Popover.Viewport>
253
- <Surface role='popover' data={popoverContent} />
244
+ <Surface role='popover' data={popoverContent} limit={1} />
254
245
  </Popover.Viewport>
255
246
  <Popover.Arrow />
256
247
  </Popover.Content>
@@ -259,7 +250,7 @@ export const DeckLayout = ({ layoutParts, toasts, overscroll, showHints, panels,
259
250
  {/* Global dialog. */}
260
251
  <Dialog.Root open={dialogOpen} onOpenChange={(nextOpen) => (context.dialogOpen = nextOpen)}>
261
252
  <Dialog.Overlay blockAlign={dialogBlockAlign}>
262
- <Surface role='dialog' data={dialogContent} />
253
+ <Surface role='dialog' data={dialogContent} limit={1} />
263
254
  </Dialog.Overlay>
264
255
  </Dialog.Root>
265
256
 
@@ -23,7 +23,7 @@ export const Fullscreen = ({ id }: { id?: string }) => {
23
23
  limit={1}
24
24
  fallback={Fallback}
25
25
  data={{
26
- active: fullScreenNode?.data,
26
+ subject: fullScreenNode?.data,
27
27
  component: id?.startsWith(SURFACE_PREFIX) ? id.slice(SURFACE_PREFIX.length) : undefined,
28
28
  }}
29
29
  />
@@ -5,6 +5,7 @@
5
5
  import React, { Fragment, memo, useEffect, useMemo } from 'react';
6
6
 
7
7
  import {
8
+ createIntent,
8
9
  LayoutAction,
9
10
  NavigationAction,
10
11
  SLUG_PATH_SEPARATOR,
@@ -13,13 +14,15 @@ import {
13
14
  type LayoutCoordinate,
14
15
  } from '@dxos/app-framework';
15
16
  import { type Node, useGraph } from '@dxos/plugin-graph';
16
- import { Icon, Popover, toLocalizedString, useMediaQuery, useTranslation, IconButton } from '@dxos/react-ui';
17
+ import { Icon, Popover, toLocalizedString, useTranslation } from '@dxos/react-ui';
17
18
  import { StackItem, type StackItemSigilAction } from '@dxos/react-ui-stack';
18
19
  import { TextTooltip } from '@dxos/react-ui-text-tooltip';
19
20
 
20
21
  import { PlankControls } from './PlankControls';
22
+ import { ToggleComplementarySidebarButton, ToggleSidebarButton } from './SidebarButton';
21
23
  import { DECK_PLUGIN } from '../../meta';
22
- import { useLayout } from '../LayoutContext';
24
+ import { useBreakpoints } from '../../util';
25
+ import { soloInlinePadding } from '../fragments';
23
26
 
24
27
  export type NodePlankHeadingProps = {
25
28
  coordinate: LayoutCoordinate;
@@ -41,16 +44,15 @@ export const NodePlankHeading = memo(
41
44
  pending,
42
45
  actions = [],
43
46
  }: NodePlankHeadingProps) => {
44
- const layoutContext = useLayout();
45
47
  const { t } = useTranslation(DECK_PLUGIN);
46
48
  const { graph } = useGraph();
47
49
  const icon = node?.properties?.icon ?? 'ph--placeholder--regular';
48
50
  const label = pending
49
51
  ? t('pending heading')
50
52
  : toLocalizedString(node?.properties?.label ?? ['plank heading fallback label', { ns: DECK_PLUGIN }], t);
51
- const dispatch = useIntentDispatcher();
53
+ const { dispatchPromise: dispatch } = useIntentDispatcher();
52
54
  const ActionRoot = node && popoverAnchorId === `dxos.org/ui/${DECK_PLUGIN}/${node.id}` ? Popover.Anchor : Fragment;
53
- const [isNotMobile] = useMediaQuery('md');
55
+ const breakpoint = useBreakpoints();
54
56
 
55
57
  useEffect(() => {
56
58
  const frame = requestAnimationFrame(() => {
@@ -66,15 +68,20 @@ export const NodePlankHeading = memo(
66
68
  const attendableId = coordinate.entryId.split(SLUG_PATH_SEPARATOR).at(0);
67
69
  const capabilities = useMemo(
68
70
  () => ({
69
- solo: (layoutPart === 'solo' || layoutPart === 'main') && isNotMobile,
71
+ solo: layoutPart === 'solo' || layoutPart === 'main',
70
72
  incrementStart: canIncrementStart,
71
73
  incrementEnd: canIncrementEnd,
72
74
  }),
73
- [isNotMobile, layoutPart, canIncrementStart, canIncrementEnd],
75
+ [breakpoint, layoutPart, canIncrementStart, canIncrementEnd],
74
76
  );
75
77
 
76
78
  return (
77
- <StackItem.Heading classNames='pie-1 border-be border-separator'>
79
+ <StackItem.Heading
80
+ classNames={[
81
+ 'plb-1 border-be border-separator items-stretch gap-1',
82
+ layoutPart === 'solo' ? soloInlinePadding : 'pli-1',
83
+ ]}
84
+ >
78
85
  <ActionRoot>
79
86
  {node ? (
80
87
  <StackItem.Sigil
@@ -87,7 +94,7 @@ export const NodePlankHeading = memo(
87
94
  typeof action.data === 'function' && action.data?.({ node: action as Node, caller: DECK_PLUGIN })
88
95
  }
89
96
  >
90
- <Surface role='menu-footer' data={{ object: node.data }} />
97
+ <Surface role='menu-footer' data={{ subject: node.data }} />
91
98
  </StackItem.Sigil>
92
99
  ) : (
93
100
  <StackItem.SigilButton>
@@ -96,6 +103,7 @@ export const NodePlankHeading = memo(
96
103
  </StackItem.SigilButton>
97
104
  )}
98
105
  </ActionRoot>
106
+ {breakpoint !== 'desktop' && <ToggleSidebarButton />}
99
107
  <TextTooltip text={label} onlyWhenTruncating>
100
108
  <StackItem.HeadingLabel
101
109
  attendableId={attendableId}
@@ -107,13 +115,12 @@ export const NodePlankHeading = memo(
107
115
  </TextTooltip>
108
116
  {node && layoutPart !== 'complementary' && (
109
117
  // TODO(Zan): What are we doing with layout coordinate here?
110
- <Surface role='navbar-end' direction='inline-reverse' data={{ object: node.data }} />
118
+ <Surface role='navbar-end' data={{ subject: node.data }} />
111
119
  )}
112
120
  {/* NOTE(thure): Pinning & unpinning are temporarily disabled */}
113
121
  <PlankControls
114
122
  capabilities={capabilities}
115
123
  isSolo={layoutPart === 'solo'}
116
- classNames='mx-1'
117
124
  onClick={(eventType) => {
118
125
  if (!layoutPart) {
119
126
  return;
@@ -121,53 +128,27 @@ export const NodePlankHeading = memo(
121
128
 
122
129
  // TODO(Zan): Update this to use the new layout actions.
123
130
  if (eventType === 'solo') {
124
- return dispatch([
125
- {
126
- action: NavigationAction.ADJUST,
127
- data: { type: eventType, layoutCoordinate: { part: 'main', entryId: coordinate.entryId } },
128
- },
129
- ]);
131
+ return dispatch(
132
+ createIntent(NavigationAction.Adjust, {
133
+ type: eventType,
134
+ layoutCoordinate: { part: 'main', entryId: coordinate.entryId },
135
+ }),
136
+ );
130
137
  } else if (eventType === 'close') {
131
138
  if (layoutPart === 'complementary') {
132
- return dispatch({
133
- action: LayoutAction.SET_LAYOUT,
134
- data: {
135
- element: 'complementary',
136
- state: false,
137
- },
138
- });
139
+ return dispatch(createIntent(LayoutAction.SetLayout, { element: 'complementary', state: false }));
139
140
  } else {
140
- return dispatch({
141
- action: NavigationAction.CLOSE,
142
- data: {
143
- activeParts: {
144
- [layoutPart]: [coordinate.entryId],
145
- },
146
- },
147
- });
141
+ return dispatch(
142
+ createIntent(NavigationAction.Close, { activeParts: { [layoutPart]: [coordinate.entryId] } }),
143
+ );
148
144
  }
149
145
  } else {
150
- return dispatch({
151
- action: NavigationAction.ADJUST,
152
- data: { type: eventType, layoutCoordinate: coordinate },
153
- });
146
+ return dispatch(createIntent(NavigationAction.Adjust, { type: eventType, layoutCoordinate: coordinate }));
154
147
  }
155
148
  }}
156
149
  close={layoutPart === 'complementary' ? 'minify-end' : true}
157
150
  >
158
- {/* TODO(wittjosiah): This doesn't behave exactly the same as the rest of the button group. */}
159
- {layoutPart !== 'complementary' && (
160
- <IconButton
161
- iconOnly
162
- onClick={() => (layoutContext.complementarySidebarOpen = !layoutContext.complementarySidebarOpen)}
163
- variant='ghost'
164
- label={t('open complementary sidebar label')}
165
- classNames='!pli-2 !plb-3 [&>svg]:-scale-x-100'
166
- icon='ph--sidebar-simple--regular'
167
- size={4}
168
- tooltipZIndex='70'
169
- />
170
- )}
151
+ <ToggleComplementarySidebarButton />
171
152
  </PlankControls>
172
153
  </StackItem.Heading>
173
154
  );
@@ -5,16 +5,17 @@
5
5
  import React, { type KeyboardEvent, memo, useCallback, useLayoutEffect, useMemo, useRef } from 'react';
6
6
 
7
7
  import {
8
+ createIntent,
9
+ indexInPart,
10
+ LayoutAction,
11
+ partLength,
12
+ Surface,
13
+ useIntentDispatcher,
14
+ type Layout,
8
15
  type LayoutCoordinate,
9
16
  type LayoutEntry,
10
17
  type LayoutPart,
11
18
  type LayoutParts,
12
- Surface,
13
- useIntentDispatcher,
14
- type Layout,
15
- indexInPart,
16
- partLength,
17
- LayoutAction,
18
19
  } from '@dxos/app-framework';
19
20
  import { debounce } from '@dxos/async';
20
21
  import { useGraph } from '@dxos/plugin-graph';
@@ -25,8 +26,8 @@ import { mainIntrinsicSize, mx } from '@dxos/react-ui-theme';
25
26
  import { NodePlankHeading } from './NodePlankHeading';
26
27
  import { PlankContentError, PlankError } from './PlankError';
27
28
  import { PlankLoading } from './PlankLoading';
28
- import { DeckAction } from '../../DeckPlugin';
29
29
  import { useNode, useMainSize } from '../../hooks';
30
+ import { DeckAction } from '../../types';
30
31
  import { useDeckContext } from '../DeckContext';
31
32
  import { useLayout } from '../LayoutContext';
32
33
 
@@ -42,7 +43,7 @@ export type PlankProps = {
42
43
  };
43
44
 
44
45
  export const Plank = memo(({ entry, layoutParts, part, layoutMode, order }: PlankProps) => {
45
- const dispatch = useIntentDispatcher();
46
+ const { dispatchPromise: dispatch } = useIntentDispatcher();
46
47
  const coordinate: LayoutCoordinate = useMemo(() => ({ part, entryId: entry?.id ?? UNKNOWN_ID }), [entry?.id, part]);
47
48
  const { popoverAnchorId, scrollIntoView } = useLayout();
48
49
  const { plankSizing } = useDeckContext();
@@ -61,7 +62,7 @@ export const Plank = memo(({ entry, layoutParts, part, layoutMode, order }: Plan
61
62
  const size = plankSizing?.[coordinate.entryId] as number | undefined;
62
63
  const setSize = useCallback(
63
64
  debounce((nextSize: number) => {
64
- return dispatch({ action: DeckAction.UPDATE_PLANK_SIZE, data: { id: coordinate.entryId, size: nextSize } });
65
+ return dispatch(createIntent(DeckAction.UpdatePlankSize, { id: coordinate.entryId, size: nextSize }));
65
66
  }, 200),
66
67
  [dispatch, coordinate.entryId],
67
68
  );
@@ -81,7 +82,7 @@ export const Plank = memo(({ entry, layoutParts, part, layoutMode, order }: Plan
81
82
  focusable?.focus({ preventScroll: true });
82
83
  layoutMode === 'deck' && focusable?.scrollIntoView({ behavior: 'smooth', inline: 'center' });
83
84
  // Clear the scroll into view state once it has been actioned.
84
- void dispatch({ action: LayoutAction.SCROLL_INTO_VIEW, data: { id: undefined } });
85
+ void dispatch(createIntent(LayoutAction.ScrollIntoView, { id: undefined }));
85
86
  }
86
87
  }, [coordinate.entryId, scrollIntoView, layoutMode]);
87
88
 
@@ -93,7 +94,8 @@ export const Plank = memo(({ entry, layoutParts, part, layoutMode, order }: Plan
93
94
  const data = useMemo(
94
95
  () =>
95
96
  node && {
96
- ...(entry?.path ? { subject: node.data, path: entry.path } : { object: node.data }),
97
+ subject: node.data,
98
+ path: entry?.path,
97
99
  coordinate,
98
100
  popoverAnchorId,
99
101
  },
@@ -4,6 +4,7 @@
4
4
 
5
5
  import React, { forwardRef } from 'react';
6
6
 
7
+ import { type PartAdjustment } from '@dxos/app-framework';
7
8
  import {
8
9
  Button,
9
10
  ButtonGroup,
@@ -16,8 +17,7 @@ import {
16
17
 
17
18
  import { DECK_PLUGIN } from '../../meta';
18
19
 
19
- export type PlankControlEvent = 'solo' | 'close' | `${'pin' | 'increment'}-${'start' | 'end'}`;
20
- export type PlankControlHandler = (event: PlankControlEvent) => void;
20
+ export type PlankControlHandler = (event: PartAdjustment) => void;
21
21
 
22
22
  export type PlankCapabilities = {
23
23
  incrementStart?: boolean;
@@ -44,9 +44,7 @@ const PlankControl = ({ icon, label, ...props }: Omit<ButtonProps, 'children'> &
44
44
  </Button>
45
45
  </Tooltip.Trigger>
46
46
  <Tooltip.Portal>
47
- <Tooltip.Content side='bottom' classNames='z-[70]'>
48
- {label}
49
- </Tooltip.Content>
47
+ <Tooltip.Content side='bottom'>{label}</Tooltip.Content>
50
48
  </Tooltip.Portal>
51
49
  </Tooltip.Root>
52
50
  );