@dxos/plugin-simple-layout 0.8.4-main.9735255 → 0.8.4-main.abd8ff62ef

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 (259) hide show
  1. package/dist/lib/browser/SimpleLayoutPlugin-Q5BZE6KD.mjs +50 -0
  2. package/dist/lib/browser/SimpleLayoutPlugin-Q5BZE6KD.mjs.map +7 -0
  3. package/dist/lib/browser/index.mjs +18 -96
  4. package/dist/lib/browser/index.mjs.map +4 -4
  5. package/dist/lib/browser/meta.json +1 -1
  6. package/dist/lib/browser/translations.mjs +34 -0
  7. package/dist/lib/browser/translations.mjs.map +7 -0
  8. package/dist/lib/node-esm/SimpleLayoutPlugin-OD45TNPO.mjs +52 -0
  9. package/dist/lib/node-esm/SimpleLayoutPlugin-OD45TNPO.mjs.map +7 -0
  10. package/dist/lib/node-esm/index.mjs +18 -95
  11. package/dist/lib/node-esm/index.mjs.map +4 -4
  12. package/dist/lib/node-esm/meta.json +1 -1
  13. package/dist/lib/node-esm/translations.mjs +36 -0
  14. package/dist/lib/node-esm/translations.mjs.map +7 -0
  15. package/dist/types/src/SimpleLayoutPlugin.d.ts +2 -1
  16. package/dist/types/src/SimpleLayoutPlugin.d.ts.map +1 -1
  17. package/dist/types/src/capabilities/app-graph-builder.d.ts +6 -0
  18. package/dist/types/src/capabilities/app-graph-builder.d.ts.map +1 -0
  19. package/dist/types/src/capabilities/index.d.ts +21 -6
  20. package/dist/types/src/capabilities/index.d.ts.map +1 -1
  21. package/dist/types/src/capabilities/operation-handler.d.ts +6 -0
  22. package/dist/types/src/capabilities/operation-handler.d.ts.map +1 -0
  23. package/dist/types/src/capabilities/{react-root/react-root.d.ts → react-root.d.ts} +1 -1
  24. package/dist/types/src/capabilities/react-root.d.ts.map +1 -0
  25. package/dist/types/src/capabilities/react-surface.d.ts +5 -0
  26. package/dist/types/src/capabilities/react-surface.d.ts.map +1 -0
  27. package/dist/types/src/capabilities/{spotlight-dismiss/spotlight-dismiss.d.ts → spotlight-dismiss.d.ts} +1 -1
  28. package/dist/types/src/capabilities/spotlight-dismiss.d.ts.map +1 -0
  29. package/dist/types/src/capabilities/{state/state.d.ts → state.d.ts} +2 -2
  30. package/dist/types/src/capabilities/state.d.ts.map +1 -0
  31. package/dist/types/src/capabilities/url-handler.d.ts +12 -0
  32. package/dist/types/src/capabilities/url-handler.d.ts.map +1 -0
  33. package/dist/types/src/components/ContentError.stories.d.ts +27 -22
  34. package/dist/types/src/components/ContentError.stories.d.ts.map +1 -1
  35. package/dist/types/src/components/DebugOverlay/DebugOverlay.d.ts +19 -0
  36. package/dist/types/src/components/DebugOverlay/DebugOverlay.d.ts.map +1 -0
  37. package/dist/types/src/components/DebugOverlay/index.d.ts +2 -0
  38. package/dist/types/src/components/DebugOverlay/index.d.ts.map +1 -0
  39. package/dist/types/src/components/Dialog/Dialog.d.ts.map +1 -1
  40. package/dist/types/src/components/Home/Home.d.ts.map +1 -1
  41. package/dist/types/src/components/Loading/Loading.d.ts +3 -0
  42. package/dist/types/src/components/Loading/Loading.d.ts.map +1 -0
  43. package/dist/types/src/components/{ContentLoading.stories.d.ts → Loading/Loading.stories.d.ts} +1 -1
  44. package/dist/types/src/components/Loading/Loading.stories.d.ts.map +1 -0
  45. package/dist/types/src/components/Loading/index.d.ts +2 -0
  46. package/dist/types/src/components/Loading/index.d.ts.map +1 -0
  47. package/dist/types/src/components/MobileLayout/MobileLayout.d.ts +35 -0
  48. package/dist/types/src/components/MobileLayout/MobileLayout.d.ts.map +1 -0
  49. package/dist/types/src/components/MobileLayout/MobileLayout.stories.d.ts +7 -0
  50. package/dist/types/src/components/MobileLayout/MobileLayout.stories.d.ts.map +1 -0
  51. package/dist/types/src/components/MobileLayout/index.d.ts +2 -0
  52. package/dist/types/src/components/MobileLayout/index.d.ts.map +1 -0
  53. package/dist/types/src/components/NavBranch/NavBranch.d.ts +11 -0
  54. package/dist/types/src/components/NavBranch/NavBranch.d.ts.map +1 -0
  55. package/dist/types/src/components/NavBranch/index.d.ts +2 -0
  56. package/dist/types/src/components/NavBranch/index.d.ts.map +1 -0
  57. package/dist/types/src/components/Popover/Popover.d.ts.map +1 -1
  58. package/dist/types/src/components/SimpleLayout/AppBar.d.ts +24 -0
  59. package/dist/types/src/components/SimpleLayout/AppBar.d.ts.map +1 -0
  60. package/dist/types/src/components/SimpleLayout/AppBar.stories.d.ts +54 -0
  61. package/dist/types/src/components/SimpleLayout/AppBar.stories.d.ts.map +1 -0
  62. package/dist/types/src/components/SimpleLayout/Drawer.d.ts +4 -7
  63. package/dist/types/src/components/SimpleLayout/Drawer.d.ts.map +1 -1
  64. package/dist/types/src/components/SimpleLayout/Main.d.ts +4 -7
  65. package/dist/types/src/components/SimpleLayout/Main.d.ts.map +1 -1
  66. package/dist/types/src/components/SimpleLayout/NavBar.d.ts +13 -8
  67. package/dist/types/src/components/SimpleLayout/NavBar.d.ts.map +1 -1
  68. package/dist/types/src/components/SimpleLayout/NavBar.stories.d.ts +32 -26
  69. package/dist/types/src/components/SimpleLayout/NavBar.stories.d.ts.map +1 -1
  70. package/dist/types/src/components/SimpleLayout/SimpleLayout.d.ts.map +1 -1
  71. package/dist/types/src/components/SimpleLayout/SimpleLayout.stories.d.ts +26 -25
  72. package/dist/types/src/components/SimpleLayout/SimpleLayout.stories.d.ts.map +1 -1
  73. package/dist/types/src/components/SimpleLayout/index.d.ts +3 -0
  74. package/dist/types/src/components/SimpleLayout/index.d.ts.map +1 -1
  75. package/dist/types/src/components/hooks.d.ts +4 -2
  76. package/dist/types/src/components/hooks.d.ts.map +1 -1
  77. package/dist/types/src/components/index.d.ts +4 -2
  78. package/dist/types/src/components/index.d.ts.map +1 -1
  79. package/dist/types/src/hooks/actions.d.ts +19 -0
  80. package/dist/types/src/hooks/actions.d.ts.map +1 -0
  81. package/dist/types/src/hooks/index.d.ts +4 -0
  82. package/dist/types/src/hooks/index.d.ts.map +1 -1
  83. package/dist/types/src/hooks/useAppBarProps.d.ts +7 -0
  84. package/dist/types/src/hooks/useAppBarProps.d.ts.map +1 -0
  85. package/dist/types/src/hooks/useCompanions.d.ts +5 -1
  86. package/dist/types/src/hooks/useCompanions.d.ts.map +1 -1
  87. package/dist/types/src/hooks/useDrawerActions.d.ts +13 -0
  88. package/dist/types/src/hooks/useDrawerActions.d.ts.map +1 -0
  89. package/dist/types/src/hooks/useNavbarActions.d.ts +14 -0
  90. package/dist/types/src/hooks/useNavbarActions.d.ts.map +1 -0
  91. package/dist/types/src/hooks/useSimpleLayoutState.d.ts +3 -3
  92. package/dist/types/src/hooks/useSimpleLayoutState.d.ts.map +1 -1
  93. package/dist/types/src/index.d.ts +3 -1
  94. package/dist/types/src/index.d.ts.map +1 -1
  95. package/dist/types/src/operations/close.d.ts +5 -0
  96. package/dist/types/src/operations/close.d.ts.map +1 -0
  97. package/dist/types/src/operations/index.d.ts +3 -0
  98. package/dist/types/src/operations/index.d.ts.map +1 -0
  99. package/dist/types/src/operations/open.d.ts +5 -0
  100. package/dist/types/src/operations/open.d.ts.map +1 -0
  101. package/dist/types/src/operations/revert-workspace.d.ts +5 -0
  102. package/dist/types/src/operations/revert-workspace.d.ts.map +1 -0
  103. package/dist/types/src/operations/set-layout-mode.d.ts +5 -0
  104. package/dist/types/src/operations/set-layout-mode.d.ts.map +1 -0
  105. package/dist/types/src/operations/set.d.ts +5 -0
  106. package/dist/types/src/operations/set.d.ts.map +1 -0
  107. package/dist/types/src/operations/state-access.d.ts +8 -0
  108. package/dist/types/src/operations/state-access.d.ts.map +1 -0
  109. package/dist/types/src/operations/switch-workspace.d.ts +5 -0
  110. package/dist/types/src/operations/switch-workspace.d.ts.map +1 -0
  111. package/dist/types/src/operations/update-complementary.d.ts +5 -0
  112. package/dist/types/src/operations/update-complementary.d.ts.map +1 -0
  113. package/dist/types/src/operations/update-dialog.d.ts +5 -0
  114. package/dist/types/src/operations/update-dialog.d.ts.map +1 -0
  115. package/dist/types/src/operations/update-popover.d.ts +5 -0
  116. package/dist/types/src/operations/update-popover.d.ts.map +1 -0
  117. package/dist/types/src/operations/update-sidebar.d.ts +5 -0
  118. package/dist/types/src/operations/update-sidebar.d.ts.map +1 -0
  119. package/dist/types/src/translations.d.ts +26 -20
  120. package/dist/types/src/translations.d.ts.map +1 -1
  121. package/dist/types/src/types/capabilities.d.ts +17 -8
  122. package/dist/types/src/types/capabilities.d.ts.map +1 -1
  123. package/dist/types/src/types/events.d.ts.map +1 -1
  124. package/dist/types/tsconfig.tsbuildinfo +1 -1
  125. package/package.json +54 -30
  126. package/src/SimpleLayoutPlugin.ts +26 -14
  127. package/src/capabilities/app-graph-builder.ts +21 -0
  128. package/src/capabilities/index.ts +13 -6
  129. package/src/capabilities/operation-handler.ts +14 -0
  130. package/src/capabilities/{react-root/react-root.tsx → react-root.tsx} +4 -4
  131. package/src/capabilities/react-surface.tsx +50 -0
  132. package/src/capabilities/{spotlight-dismiss/spotlight-dismiss.ts → spotlight-dismiss.ts} +2 -2
  133. package/src/capabilities/{state/state.tsx → state.tsx} +6 -5
  134. package/src/capabilities/url-handler.ts +161 -0
  135. package/src/components/ContentError.stories.tsx +9 -8
  136. package/src/components/DebugOverlay/DebugOverlay.tsx +96 -0
  137. package/src/components/DebugOverlay/index.ts +5 -0
  138. package/src/components/Dialog/Dialog.tsx +17 -6
  139. package/src/components/Home/Home.tsx +51 -43
  140. package/src/components/{ContentLoading.stories.tsx → Loading/Loading.stories.tsx} +5 -5
  141. package/src/components/{ContentLoading.tsx → Loading/Loading.tsx} +2 -2
  142. package/src/components/Loading/index.ts +5 -0
  143. package/src/components/MobileLayout/MobileLayout.stories.tsx +133 -0
  144. package/src/components/MobileLayout/MobileLayout.tsx +374 -0
  145. package/src/components/MobileLayout/index.ts +5 -0
  146. package/src/components/NavBranch/NavBranch.tsx +124 -0
  147. package/src/components/{Workspace → NavBranch}/index.ts +1 -1
  148. package/src/components/Popover/Popover.tsx +13 -9
  149. package/src/components/SimpleLayout/AppBar.stories.tsx +144 -0
  150. package/src/components/SimpleLayout/AppBar.tsx +94 -0
  151. package/src/components/SimpleLayout/Drawer.tsx +44 -91
  152. package/src/components/SimpleLayout/Main.tsx +40 -34
  153. package/src/components/SimpleLayout/NavBar.stories.tsx +132 -24
  154. package/src/components/SimpleLayout/NavBar.tsx +18 -51
  155. package/src/components/SimpleLayout/SimpleLayout.stories.tsx +46 -60
  156. package/src/components/SimpleLayout/SimpleLayout.tsx +41 -23
  157. package/src/components/SimpleLayout/index.ts +3 -0
  158. package/src/components/hooks.ts +9 -9
  159. package/src/components/index.ts +4 -2
  160. package/src/hooks/actions.ts +84 -0
  161. package/src/hooks/index.ts +4 -0
  162. package/src/hooks/useAppBarProps.ts +95 -0
  163. package/src/hooks/useCompanions.ts +8 -5
  164. package/src/hooks/useDrawerActions.ts +100 -0
  165. package/src/hooks/useNavbarActions.ts +87 -0
  166. package/src/hooks/useSimpleLayoutState.ts +5 -5
  167. package/src/index.ts +7 -1
  168. package/src/meta.ts +1 -1
  169. package/src/operations/close.ts +34 -0
  170. package/src/operations/index.ts +16 -0
  171. package/src/operations/open.ts +63 -0
  172. package/src/operations/revert-workspace.ts +22 -0
  173. package/src/operations/set-layout-mode.ts +12 -0
  174. package/src/operations/set.ts +23 -0
  175. package/src/operations/state-access.ts +19 -0
  176. package/src/operations/switch-workspace.ts +26 -0
  177. package/src/operations/update-complementary.ts +35 -0
  178. package/src/operations/update-dialog.ts +28 -0
  179. package/src/operations/update-popover.ts +35 -0
  180. package/src/operations/update-sidebar.ts +12 -0
  181. package/src/translations.ts +21 -19
  182. package/src/types/capabilities.ts +14 -10
  183. package/src/types/events.ts +3 -2
  184. package/dist/lib/browser/chunk-LR3EE3VB.mjs +0 -789
  185. package/dist/lib/browser/chunk-LR3EE3VB.mjs.map +0 -7
  186. package/dist/lib/browser/chunk-P77G4YTR.mjs +0 -29
  187. package/dist/lib/browser/chunk-P77G4YTR.mjs.map +0 -7
  188. package/dist/lib/browser/operation-resolver-775UYAC2.mjs +0 -203
  189. package/dist/lib/browser/operation-resolver-775UYAC2.mjs.map +0 -7
  190. package/dist/lib/browser/react-root-KM55OMGJ.mjs +0 -21
  191. package/dist/lib/browser/react-root-KM55OMGJ.mjs.map +0 -7
  192. package/dist/lib/browser/react-surface-BABGAWGY.mjs +0 -39
  193. package/dist/lib/browser/react-surface-BABGAWGY.mjs.map +0 -7
  194. package/dist/lib/browser/spotlight-dismiss-VSNOPETH.mjs +0 -66
  195. package/dist/lib/browser/spotlight-dismiss-VSNOPETH.mjs.map +0 -7
  196. package/dist/lib/browser/state-OUFTC2KV.mjs +0 -47
  197. package/dist/lib/browser/state-OUFTC2KV.mjs.map +0 -7
  198. package/dist/lib/browser/url-handler-DOUFQIAC.mjs +0 -54
  199. package/dist/lib/browser/url-handler-DOUFQIAC.mjs.map +0 -7
  200. package/dist/lib/node-esm/chunk-F5TEKVJG.mjs +0 -31
  201. package/dist/lib/node-esm/chunk-F5TEKVJG.mjs.map +0 -7
  202. package/dist/lib/node-esm/chunk-HB2B3LLG.mjs +0 -790
  203. package/dist/lib/node-esm/chunk-HB2B3LLG.mjs.map +0 -7
  204. package/dist/lib/node-esm/operation-resolver-LDNYS3DI.mjs +0 -204
  205. package/dist/lib/node-esm/operation-resolver-LDNYS3DI.mjs.map +0 -7
  206. package/dist/lib/node-esm/react-root-36UYFEEB.mjs +0 -22
  207. package/dist/lib/node-esm/react-root-36UYFEEB.mjs.map +0 -7
  208. package/dist/lib/node-esm/react-surface-CGHFVWU3.mjs +0 -40
  209. package/dist/lib/node-esm/react-surface-CGHFVWU3.mjs.map +0 -7
  210. package/dist/lib/node-esm/spotlight-dismiss-L5PCWIJG.mjs +0 -68
  211. package/dist/lib/node-esm/spotlight-dismiss-L5PCWIJG.mjs.map +0 -7
  212. package/dist/lib/node-esm/state-Q2ZA26W5.mjs +0 -48
  213. package/dist/lib/node-esm/state-Q2ZA26W5.mjs.map +0 -7
  214. package/dist/lib/node-esm/url-handler-DVAZZEUO.mjs +0 -55
  215. package/dist/lib/node-esm/url-handler-DVAZZEUO.mjs.map +0 -7
  216. package/dist/types/src/capabilities/operation-resolver/index.d.ts +0 -3
  217. package/dist/types/src/capabilities/operation-resolver/index.d.ts.map +0 -1
  218. package/dist/types/src/capabilities/operation-resolver/operation-resolver.d.ts +0 -5
  219. package/dist/types/src/capabilities/operation-resolver/operation-resolver.d.ts.map +0 -1
  220. package/dist/types/src/capabilities/react-root/index.d.ts +0 -6
  221. package/dist/types/src/capabilities/react-root/index.d.ts.map +0 -1
  222. package/dist/types/src/capabilities/react-root/react-root.d.ts.map +0 -1
  223. package/dist/types/src/capabilities/react-surface/index.d.ts +0 -3
  224. package/dist/types/src/capabilities/react-surface/index.d.ts.map +0 -1
  225. package/dist/types/src/capabilities/react-surface/react-surface.d.ts +0 -5
  226. package/dist/types/src/capabilities/react-surface/react-surface.d.ts.map +0 -1
  227. package/dist/types/src/capabilities/spotlight-dismiss/index.d.ts +0 -3
  228. package/dist/types/src/capabilities/spotlight-dismiss/index.d.ts.map +0 -1
  229. package/dist/types/src/capabilities/spotlight-dismiss/spotlight-dismiss.d.ts.map +0 -1
  230. package/dist/types/src/capabilities/state/index.d.ts +0 -13
  231. package/dist/types/src/capabilities/state/index.d.ts.map +0 -1
  232. package/dist/types/src/capabilities/state/state.d.ts.map +0 -1
  233. package/dist/types/src/capabilities/url-handler/index.d.ts +0 -3
  234. package/dist/types/src/capabilities/url-handler/index.d.ts.map +0 -1
  235. package/dist/types/src/capabilities/url-handler/url-handler.d.ts +0 -10
  236. package/dist/types/src/capabilities/url-handler/url-handler.d.ts.map +0 -1
  237. package/dist/types/src/components/ContentError.d.ts +0 -5
  238. package/dist/types/src/components/ContentError.d.ts.map +0 -1
  239. package/dist/types/src/components/ContentLoading.d.ts +0 -3
  240. package/dist/types/src/components/ContentLoading.d.ts.map +0 -1
  241. package/dist/types/src/components/ContentLoading.stories.d.ts.map +0 -1
  242. package/dist/types/src/components/SimpleLayout/Banner.d.ts +0 -8
  243. package/dist/types/src/components/SimpleLayout/Banner.d.ts.map +0 -1
  244. package/dist/types/src/components/Workspace/Workspace.d.ts +0 -9
  245. package/dist/types/src/components/Workspace/Workspace.d.ts.map +0 -1
  246. package/dist/types/src/components/Workspace/index.d.ts +0 -2
  247. package/dist/types/src/components/Workspace/index.d.ts.map +0 -1
  248. package/src/capabilities/operation-resolver/index.ts +0 -10
  249. package/src/capabilities/operation-resolver/operation-resolver.ts +0 -215
  250. package/src/capabilities/react-root/index.ts +0 -7
  251. package/src/capabilities/react-surface/index.ts +0 -7
  252. package/src/capabilities/react-surface/react-surface.tsx +0 -40
  253. package/src/capabilities/spotlight-dismiss/index.ts +0 -7
  254. package/src/capabilities/state/index.ts +0 -9
  255. package/src/capabilities/url-handler/index.ts +0 -7
  256. package/src/capabilities/url-handler/url-handler.ts +0 -80
  257. package/src/components/ContentError.tsx +0 -23
  258. package/src/components/SimpleLayout/Banner.tsx +0 -113
  259. package/src/components/Workspace/Workspace.tsx +0 -115
@@ -0,0 +1,96 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import { createContext } from '@radix-ui/react-context';
6
+ import React, { type PropsWithChildren, useCallback, useRef } from 'react';
7
+
8
+ const DEBUG_OVERLAY_NAME = 'DebugOverlay';
9
+
10
+ //
11
+ // Context
12
+ //
13
+
14
+ type DebugOverlayContextValue = {
15
+ /** Log a timestamped message to the on-screen debug overlay. */
16
+ dbg: (msg: string) => void;
17
+ };
18
+
19
+ // Default to a no-op so hooks can call useDebugLog() safely outside of a provider.
20
+ const [DebugOverlayProvider, useDebugLog] = createContext<DebugOverlayContextValue>(DEBUG_OVERLAY_NAME, {
21
+ dbg: () => {},
22
+ });
23
+
24
+ //
25
+ // Root
26
+ //
27
+
28
+ type DebugOverlayRootProps = PropsWithChildren<{
29
+ /**
30
+ * When true (default), renders the on-screen log panel.
31
+ * Set to false to suppress the overlay while keeping the context available.
32
+ */
33
+ enabled?: boolean;
34
+ maxLines?: number;
35
+ }>;
36
+
37
+ /**
38
+ * Establishes a debug overlay context.
39
+ *
40
+ * When enabled, renders an on-screen monospaced log panel anchored just above
41
+ * the keyboard (via --kb-height CSS variable). Descendants can call
42
+ * useDebugLog() to obtain the dbg() function for logging.
43
+ *
44
+ * Intended for transient mobile debugging in the iOS Simulator where DevTools
45
+ * console output may not be accessible.
46
+ */
47
+ const DebugOverlayRoot = ({ children, enabled = true, maxLines = 10 }: DebugOverlayRootProps) => {
48
+ const overlayRef = useRef<HTMLDivElement>(null);
49
+
50
+ const dbg = useCallback((msg: string) => {
51
+ if (!overlayRef.current) {
52
+ return;
53
+ }
54
+ const line = document.createElement('pre');
55
+ line.textContent = `${(performance.now() / 1000).toFixed(2).padStart(8, ' ')} ${msg}`;
56
+ overlayRef.current.prepend(line);
57
+ while (overlayRef.current.children.length > maxLines) {
58
+ overlayRef.current.lastChild?.remove();
59
+ }
60
+ }, []);
61
+
62
+ return (
63
+ <DebugOverlayProvider dbg={dbg}>
64
+ {children}
65
+ {enabled && (
66
+ <div
67
+ ref={overlayRef}
68
+ style={{
69
+ position: 'fixed',
70
+ bottom: 'calc(var(--kb-height, 0px) + 8px)',
71
+ left: 8,
72
+ right: 8,
73
+ background: 'rgba(0,0,0,0.8)',
74
+ color: '#0f0',
75
+ fontSize: 10,
76
+ fontFamily: 'monospace',
77
+ padding: 6,
78
+ borderRadius: 4,
79
+ zIndex: 9999,
80
+ pointerEvents: 'none',
81
+ }}
82
+ />
83
+ )}
84
+ </DebugOverlayProvider>
85
+ );
86
+ };
87
+
88
+ //
89
+ // Exports
90
+ //
91
+
92
+ export const DebugOverlay = {
93
+ Root: DebugOverlayRoot,
94
+ };
95
+
96
+ export { useDebugLog };
@@ -0,0 +1,5 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ export { DebugOverlay, useDebugLog } from './DebugOverlay';
@@ -4,11 +4,12 @@
4
4
 
5
5
  import React from 'react';
6
6
 
7
- import { Surface } from '@dxos/app-framework/react';
7
+ import { Surface } from '@dxos/app-framework/ui';
8
+ import { AppSurface } from '@dxos/app-toolkit/ui';
8
9
  import { AlertDialog, Dialog as NaturalDialog } from '@dxos/react-ui';
10
+ import { ErrorFallback } from '@dxos/react-ui';
9
11
 
10
- import { useSimpleLayoutState } from '../../hooks';
11
- import { ContentError } from '../ContentError';
12
+ import { useSimpleLayoutState } from '#hooks';
12
13
 
13
14
  export const Dialog = () => {
14
15
  const { state, updateState } = useSimpleLayoutState();
@@ -20,17 +21,27 @@ export const Dialog = () => {
20
21
  <DialogRoot
21
22
  modal={state.dialogBlockAlign !== 'end'}
22
23
  open={state.dialogOpen}
23
- onOpenChange={(nextOpen) => updateState((s) => ({ ...s, dialogOpen: nextOpen }))}
24
+ onOpenChange={(nextOpen) => updateState((state) => ({ ...state, dialogOpen: nextOpen }))}
24
25
  >
25
26
  {state.dialogBlockAlign === 'end' ? (
26
- <Surface role='dialog' data={state.dialogContent} limit={1} fallback={ContentError} />
27
+ <Surface.Surface
28
+ type={AppSurface.Dialog}
29
+ data={state.dialogContent ?? undefined}
30
+ limit={1}
31
+ fallback={ErrorFallback}
32
+ />
27
33
  ) : (
28
34
  <DialogOverlay
29
35
  blockAlign={state.dialogBlockAlign}
30
36
  classNames={state.dialogOverlayClasses}
31
37
  style={state.dialogOverlayStyle}
32
38
  >
33
- <Surface role='dialog' data={state.dialogContent} limit={1} fallback={ContentError} />
39
+ <Surface.Surface
40
+ type={AppSurface.Dialog}
41
+ data={state.dialogContent ?? undefined}
42
+ limit={1}
43
+ fallback={ErrorFallback}
44
+ />
34
45
  </DialogOverlay>
35
46
  )}
36
47
  </DialogRoot>
@@ -4,17 +4,20 @@
4
4
 
5
5
  import React, { useCallback, useEffect, useMemo, useRef } from 'react';
6
6
 
7
- import { Common } from '@dxos/app-framework';
8
- import { useAppGraph, useOperationInvoker } from '@dxos/app-framework/react';
7
+ import { useOperationInvoker } from '@dxos/app-framework/ui';
8
+ import { LayoutOperation } from '@dxos/app-toolkit';
9
+ import { useAppGraph } from '@dxos/app-toolkit/ui';
9
10
  import { Node, useConnections } from '@dxos/plugin-graph';
10
- import { Avatar, Icon, Toolbar, toLocalizedString, useTranslation } from '@dxos/react-ui';
11
- import { Card, Layout, Mosaic, type StackTileComponent } from '@dxos/react-ui-mosaic';
12
- import { SearchList, useSearchListItem, useSearchListResults } from '@dxos/react-ui-searchlist';
11
+ import { Avatar, Icon, ScrollArea, toLocalizedString, useTranslation } from '@dxos/react-ui';
12
+ import { Card } from '@dxos/react-ui';
13
+ import { Mosaic, type MosaicStackTileComponent } from '@dxos/react-ui-mosaic';
14
+ import { SearchPanel, useSearchListItem, useSearchListResults } from '@dxos/react-ui-search';
13
15
  import { mx } from '@dxos/ui-theme';
14
- import { byPosition } from '@dxos/util';
16
+ import { byPosition, getHostPlatform, isTauri } from '@dxos/util';
15
17
 
16
- import { meta } from '../../meta';
17
- import { useLoadDescendents } from '../hooks';
18
+ import { meta } from '#meta';
19
+
20
+ import { useExpandPath } from '../hooks';
18
21
 
19
22
  export type HomeProps = {};
20
23
 
@@ -26,7 +29,7 @@ export const Home = (_: HomeProps) => {
26
29
  const userAccountItem = useItemsByDisposition('user-account')[0];
27
30
  const pinnedItems = useItemsByDisposition('pin-end', true);
28
31
  const workspaceItems = useItemsByDisposition('workspace');
29
- useLoadDescendents(Node.RootId);
32
+ useExpandPath(Node.RootId);
30
33
 
31
34
  const items = useMemo(
32
35
  () => [...(userAccountItem ? [userAccountItem] : []), ...pinnedItems, ...workspaceItems],
@@ -38,44 +41,47 @@ export const Home = (_: HomeProps) => {
38
41
  extract: (node) => toLocalizedString(node.properties.label, t),
39
42
  });
40
43
 
44
+ const autoFocus = !isTauri() || getHostPlatform() !== 'ios';
45
+
41
46
  return (
42
- <Layout.Main toolbar>
43
- <SearchList.Root onSearch={handleSearch}>
44
- <Toolbar.Root>
45
- <SearchList.Input placeholder={t('search placeholder')} autoFocus />
46
- </Toolbar.Root>
47
- <SearchList.Content>
48
- <Mosaic.Container asChild>
49
- <Mosaic.Viewport padding>
50
- <Mosaic.Stack items={results} getId={(node) => node.id} Tile={WorkspaceTile} />
51
- </Mosaic.Viewport>
52
- </Mosaic.Container>
53
- </SearchList.Content>
54
- </SearchList.Root>
55
- </Layout.Main>
47
+ <SearchPanel onSearch={handleSearch}>
48
+ <Mosaic.Container asChild>
49
+ <ScrollArea.Root centered padding thin>
50
+ <ScrollArea.Viewport>
51
+ <Mosaic.Stack
52
+ classNames='gap-1'
53
+ draggable={false}
54
+ items={results}
55
+ getId={(item) => item.id}
56
+ Tile={WorkspaceTile}
57
+ />
58
+ </ScrollArea.Viewport>
59
+ </ScrollArea.Root>
60
+ </Mosaic.Container>
61
+ </SearchPanel>
56
62
  );
57
63
  };
58
64
 
59
- const WorkspaceTile: StackTileComponent<Node.Node> = ({ data }) => {
65
+ const WorkspaceTile: MosaicStackTileComponent<Node.Node> = (props) => {
66
+ const data = props.data;
60
67
  const { t } = useTranslation(meta.id);
61
68
  const { invokePromise } = useOperationInvoker();
62
69
  const { selectedValue, registerItem, unregisterItem } = useSearchListItem();
63
- const ref = useRef<HTMLDivElement>(null);
70
+ const name = toLocalizedString(data.properties.label, t);
71
+ const isSelected = selectedValue === data.id;
72
+ const cardRef = useRef<HTMLDivElement>(null);
73
+
74
+ useExpandPath(data.id);
64
75
 
65
76
  const handleSelect = useCallback(
66
- () => invokePromise(Common.LayoutOperation.SwitchWorkspace, { subject: data.id }),
77
+ () => invokePromise(LayoutOperation.SwitchWorkspace, { subject: data.id }),
67
78
  [invokePromise, data.id],
68
79
  );
69
80
 
70
- useLoadDescendents(data.id);
71
-
72
- const name = toLocalizedString(data.properties.label, t);
73
- const isSelected = selectedValue === data.id;
74
-
75
81
  // Register this workspace with the search context.
76
82
  useEffect(() => {
77
- if (ref.current) {
78
- registerItem(data.id, ref.current, handleSelect);
83
+ if (cardRef.current) {
84
+ registerItem(data.id, cardRef.current, handleSelect);
79
85
  }
80
86
 
81
87
  return () => unregisterItem(data.id);
@@ -83,32 +89,32 @@ const WorkspaceTile: StackTileComponent<Node.Node> = ({ data }) => {
83
89
 
84
90
  // Scroll into view when selected.
85
91
  useEffect(() => {
86
- if (isSelected && ref.current) {
87
- ref.current.scrollIntoView({ block: 'nearest', behavior: 'smooth' });
92
+ if (isSelected && cardRef.current) {
93
+ cardRef.current.scrollIntoView({ block: 'nearest', behavior: 'smooth' });
88
94
  }
89
95
  }, [isSelected]);
90
96
 
91
97
  return (
92
98
  <Card.Root
93
- ref={ref}
94
99
  role='button'
95
100
  fullWidth
96
101
  tabIndex={-1} // TODO(burdon): Use Mosaic.Focus.
97
102
  data-selected={isSelected}
98
- classNames={mx('dx-focus-ring', isSelected && 'bg-hoverOverlay')}
103
+ classNames={mx('dx-focus-ring', isSelected && 'bg-hover-overlay')}
99
104
  onClick={handleSelect}
105
+ ref={cardRef}
100
106
  >
101
- <Card.Toolbar density='coarse'>
107
+ <Card.Toolbar density='fine'>
102
108
  <Avatar.Root>
103
109
  <Avatar.Content
104
110
  icon={data.properties.icon}
105
111
  hue={data.properties.hue}
106
112
  hueVariant='transparent'
107
113
  variant='square'
108
- size={12}
114
+ size={8}
109
115
  fallback={name}
110
116
  />
111
- <Avatar.Label>{name}</Avatar.Label>
117
+ <Avatar.Label classNames='cursor-pointer'>{name}</Avatar.Label>
112
118
  <Icon icon='ph--caret-right--regular' />
113
119
  </Avatar.Root>
114
120
  </Card.Toolbar>
@@ -124,7 +130,9 @@ const filterItems = (node: Node.Node, disposition: string) => {
124
130
  /** Returns root-level items filtered by disposition. */
125
131
  const useItemsByDisposition = (disposition: string, sort = false) => {
126
132
  const { graph } = useAppGraph();
127
- const connections = useConnections(graph, Node.RootId);
128
- const filtered = connections.filter((node) => filterItems(node, disposition));
129
- return sort ? filtered.toSorted((a, b) => byPosition(a.properties, b.properties)) : filtered;
133
+ const connections = useConnections(graph, Node.RootId, 'child');
134
+ return useMemo(() => {
135
+ const filtered = connections.filter((node) => filterItems(node, disposition));
136
+ return sort ? filtered.toSorted((a, b) => byPosition(a.properties, b.properties)) : filtered;
137
+ }, [connections, disposition, sort]);
130
138
  };
@@ -6,16 +6,16 @@ import { type Meta, type StoryObj } from '@storybook/react-vite';
6
6
 
7
7
  import { withTheme } from '@dxos/react-ui/testing';
8
8
 
9
- import { ContentLoading } from './ContentLoading';
9
+ import { Loading } from './Loading';
10
10
 
11
11
  const meta = {
12
- title: 'plugins/plugin-simple-layout/ContentLoading',
13
- component: ContentLoading,
14
- decorators: [withTheme],
12
+ title: 'plugins/plugin-simple-layout/components/Loading',
13
+ component: Loading,
14
+ decorators: [withTheme()],
15
15
  parameters: {
16
16
  layout: 'centered',
17
17
  },
18
- } satisfies Meta<typeof ContentLoading>;
18
+ } satisfies Meta<typeof Loading>;
19
19
 
20
20
  export default meta;
21
21
 
@@ -5,6 +5,6 @@
5
5
  import React from 'react';
6
6
 
7
7
  // TODO(burdon): Show skeleton: https://github.com/dxos/dxos/issues/8259
8
- export const ContentLoading = () => {
9
- return <div role='none' className='grid place-items-center attention-surface' />;
8
+ export const Loading = () => {
9
+ return <div role='none' className='grid place-items-center dx-attention-surface' />;
10
10
  };
@@ -0,0 +1,5 @@
1
+ //
2
+ // Copyright 2024 DXOS.org
3
+ //
4
+
5
+ export * from './Loading';
@@ -0,0 +1,133 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import { type Meta, type StoryObj } from '@storybook/react-vite';
6
+ import React, { type PropsWithChildren, useEffect, useState } from 'react';
7
+
8
+ import { addEventListener, combine } from '@dxos/async';
9
+ import { Column, Flex, Input, Panel, Splitter, type SplitterMode, Toolbar } from '@dxos/react-ui';
10
+ import { withLayout, withTheme } from '@dxos/react-ui/testing';
11
+
12
+ import { MobileLayout, type MobileLayoutRootProps } from './MobileLayout';
13
+
14
+ /**
15
+ * Simulate ios keyboard.
16
+ */
17
+ const WithKeyboard = ({ children }: PropsWithChildren) => {
18
+ const [keyboardOpen, setKeyboardOpen] = useState(false);
19
+
20
+ useEffect(() => {
21
+ return combine(
22
+ addEventListener(document, 'focusin', (event: FocusEvent) => {
23
+ const target = event.target as HTMLElement;
24
+ if (target.tagName === 'INPUT' || target.tagName === 'TEXTAREA' || target.isContentEditable) {
25
+ setKeyboardOpen(true);
26
+ }
27
+ }),
28
+ addEventListener(document, 'focusout', (event: FocusEvent) => {
29
+ const target = event.target as HTMLElement;
30
+ if (target.tagName === 'INPUT' || target.tagName === 'TEXTAREA' || target.isContentEditable) {
31
+ setKeyboardOpen(false);
32
+ }
33
+ }),
34
+ );
35
+ }, []);
36
+
37
+ useEffect(() => {
38
+ const keyboardHeight = keyboardOpen ? 300 : 0;
39
+ document.documentElement.style.setProperty('--kb-height', `${keyboardHeight}px`);
40
+ document.documentElement.style.setProperty('--kb-open', keyboardOpen ? '1' : '0');
41
+
42
+ // Dispatch custom keyboard event that useIOSKeyboard listens for.
43
+ window.dispatchEvent(
44
+ new CustomEvent('keyboard', {
45
+ detail: {
46
+ type: keyboardOpen ? 'show' : 'hide',
47
+ height: keyboardHeight,
48
+ duration: 300,
49
+ },
50
+ }),
51
+ );
52
+ }, [keyboardOpen]);
53
+
54
+ return <div className='h-screen relative'>{children}</div>;
55
+ };
56
+
57
+ const StoryPanel = ({ children, label }: PropsWithChildren<{ label: string }>) => {
58
+ return (
59
+ <Panel.Root>
60
+ <Panel.Toolbar asChild>
61
+ <Toolbar.Root>
62
+ {label}
63
+ <Toolbar.Separator />
64
+ {children}
65
+ </Toolbar.Root>
66
+ </Panel.Toolbar>
67
+ <Panel.Content asChild>
68
+ <Column.Root gutter='xs' classNames='py-form-chrome'>
69
+ <Column.Center>
70
+ <Flex column>
71
+ <Input.Root>
72
+ <Input.TextInput placeholder={label} />
73
+ </Input.Root>
74
+ </Flex>
75
+ </Column.Center>
76
+ </Column.Root>
77
+ </Panel.Content>
78
+ </Panel.Root>
79
+ );
80
+ };
81
+
82
+ const DefaultStory = () => {
83
+ const [splitterMode, setSplitterMode] = useState<SplitterMode>('top');
84
+ const [keyboardOpen, setKeyboardOpen] = useState(false);
85
+
86
+ useEffect(() => {
87
+ setSplitterMode(splitterMode === 'split' ? 'bottom' : splitterMode);
88
+ }, [keyboardOpen]);
89
+
90
+ return (
91
+ <WithKeyboard>
92
+ <MobileLayout.Root onKeyboardOpenChange={setKeyboardOpen}>
93
+ <MobileLayout.Panel safe={{ top: true, bottom: splitterMode === 'top' }}>
94
+ <Splitter.Root mode={splitterMode} ratio={0.5}>
95
+ <Splitter.Panel position='top'>
96
+ <StoryPanel label='Main'>
97
+ {splitterMode === 'top' && (
98
+ <Toolbar.IconButton icon='ph--plus--regular' label='Open' onClick={() => setSplitterMode('split')} />
99
+ )}
100
+ </StoryPanel>
101
+ </Splitter.Panel>
102
+ <Splitter.Panel position='bottom'>
103
+ <StoryPanel label='Drawer'>
104
+ <Toolbar.IconButton
105
+ icon={splitterMode === 'bottom' ? 'ph--arrow-down--regular' : 'ph--arrow-up--regular'}
106
+ label={splitterMode === 'bottom' ? 'Collapse' : 'Expand'}
107
+ onClick={() => setSplitterMode((splitterMode) => (splitterMode === 'split' ? 'bottom' : 'split'))}
108
+ />
109
+ <Toolbar.IconButton icon='ph--x--regular' label='Close' onClick={() => setSplitterMode('top')} />
110
+ </StoryPanel>
111
+ </Splitter.Panel>
112
+ </Splitter.Root>
113
+ </MobileLayout.Panel>
114
+ </MobileLayout.Root>
115
+ </WithKeyboard>
116
+ );
117
+ };
118
+
119
+ const meta: Meta<MobileLayoutRootProps> = {
120
+ title: 'plugins/plugin-simple-layout/components/MobileLayout',
121
+ component: MobileLayout.Root,
122
+ render: DefaultStory,
123
+ decorators: [withTheme(), withLayout({ layout: 'column', classNames: 'relative' })],
124
+ parameters: {
125
+ layout: 'fullscreen',
126
+ },
127
+ };
128
+
129
+ export default meta;
130
+
131
+ type Story = StoryObj<MobileLayoutRootProps>;
132
+
133
+ export const Default: Story = {};