@dxos/plugin-simple-layout 0.8.4-main.c85a9c8dae → 0.8.4-main.fcfe5033a5

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 (217) hide show
  1. package/dist/lib/browser/index.mjs +35 -56
  2. package/dist/lib/browser/index.mjs.map +4 -4
  3. package/dist/lib/browser/meta.json +1 -1
  4. package/dist/lib/node-esm/index.mjs +35 -55
  5. package/dist/lib/node-esm/index.mjs.map +4 -4
  6. package/dist/lib/node-esm/meta.json +1 -1
  7. package/dist/types/src/SimpleLayoutPlugin.d.ts +1 -1
  8. package/dist/types/src/SimpleLayoutPlugin.d.ts.map +1 -1
  9. package/dist/types/src/capabilities/app-graph-builder.d.ts +6 -0
  10. package/dist/types/src/capabilities/app-graph-builder.d.ts.map +1 -0
  11. package/dist/types/src/capabilities/index.d.ts +21 -6
  12. package/dist/types/src/capabilities/index.d.ts.map +1 -1
  13. package/dist/types/src/capabilities/operation-handler.d.ts +6 -0
  14. package/dist/types/src/capabilities/operation-handler.d.ts.map +1 -0
  15. package/dist/types/src/capabilities/react-root.d.ts.map +1 -0
  16. package/dist/types/src/capabilities/react-surface.d.ts.map +1 -0
  17. package/dist/types/src/capabilities/spotlight-dismiss.d.ts.map +1 -0
  18. package/dist/types/src/capabilities/{state/state.d.ts → state.d.ts} +1 -1
  19. package/dist/types/src/capabilities/state.d.ts.map +1 -0
  20. package/dist/types/src/capabilities/{url-handler/url-handler.d.ts → url-handler.d.ts} +3 -3
  21. package/dist/types/src/capabilities/url-handler.d.ts.map +1 -0
  22. package/dist/types/src/components/ContentError.stories.d.ts +25 -18
  23. package/dist/types/src/components/ContentError.stories.d.ts.map +1 -1
  24. package/dist/types/src/components/DebugOverlay/DebugOverlay.d.ts +19 -0
  25. package/dist/types/src/components/DebugOverlay/DebugOverlay.d.ts.map +1 -0
  26. package/dist/types/src/components/DebugOverlay/index.d.ts +2 -0
  27. package/dist/types/src/components/DebugOverlay/index.d.ts.map +1 -0
  28. package/dist/types/src/components/Dialog/Dialog.d.ts.map +1 -1
  29. package/dist/types/src/components/Home/Home.d.ts.map +1 -1
  30. package/dist/types/src/components/Loading/Loading.d.ts +3 -0
  31. package/dist/types/src/components/Loading/Loading.d.ts.map +1 -0
  32. package/dist/types/src/components/{ContentLoading.stories.d.ts → Loading/Loading.stories.d.ts} +1 -1
  33. package/dist/types/src/components/Loading/Loading.stories.d.ts.map +1 -0
  34. package/dist/types/src/components/Loading/index.d.ts +2 -0
  35. package/dist/types/src/components/Loading/index.d.ts.map +1 -0
  36. package/dist/types/src/components/MobileLayout/MobileLayout.d.ts.map +1 -1
  37. package/dist/types/src/components/MobileLayout/MobileLayout.stories.d.ts.map +1 -1
  38. package/dist/types/src/components/NavBranch/NavBranch.d.ts +11 -0
  39. package/dist/types/src/components/NavBranch/NavBranch.d.ts.map +1 -0
  40. package/dist/types/src/components/NavBranch/index.d.ts +2 -0
  41. package/dist/types/src/components/NavBranch/index.d.ts.map +1 -0
  42. package/dist/types/src/components/Popover/Popover.d.ts.map +1 -1
  43. package/dist/types/src/components/SimpleLayout/AppBar.d.ts +5 -7
  44. package/dist/types/src/components/SimpleLayout/AppBar.d.ts.map +1 -1
  45. package/dist/types/src/components/SimpleLayout/AppBar.stories.d.ts +28 -21
  46. package/dist/types/src/components/SimpleLayout/AppBar.stories.d.ts.map +1 -1
  47. package/dist/types/src/components/SimpleLayout/Drawer.d.ts.map +1 -1
  48. package/dist/types/src/components/SimpleLayout/Main.d.ts.map +1 -1
  49. package/dist/types/src/components/SimpleLayout/NavBar.d.ts +5 -7
  50. package/dist/types/src/components/SimpleLayout/NavBar.d.ts.map +1 -1
  51. package/dist/types/src/components/SimpleLayout/NavBar.stories.d.ts +28 -22
  52. package/dist/types/src/components/SimpleLayout/NavBar.stories.d.ts.map +1 -1
  53. package/dist/types/src/components/SimpleLayout/SimpleLayout.d.ts.map +1 -1
  54. package/dist/types/src/components/SimpleLayout/SimpleLayout.stories.d.ts +26 -25
  55. package/dist/types/src/components/SimpleLayout/SimpleLayout.stories.d.ts.map +1 -1
  56. package/dist/types/src/components/hooks.d.ts +4 -2
  57. package/dist/types/src/components/hooks.d.ts.map +1 -1
  58. package/dist/types/src/components/index.d.ts +3 -2
  59. package/dist/types/src/components/index.d.ts.map +1 -1
  60. package/dist/types/src/hooks/actions.d.ts +4 -5
  61. package/dist/types/src/hooks/actions.d.ts.map +1 -1
  62. package/dist/types/src/hooks/useAppBarProps.d.ts +1 -1
  63. package/dist/types/src/hooks/useAppBarProps.d.ts.map +1 -1
  64. package/dist/types/src/hooks/useDrawerActions.d.ts.map +1 -1
  65. package/dist/types/src/hooks/useNavbarActions.d.ts.map +1 -1
  66. package/dist/types/src/hooks/useSimpleLayoutState.d.ts +1 -1
  67. package/dist/types/src/hooks/useSimpleLayoutState.d.ts.map +1 -1
  68. package/dist/types/src/operations/close.d.ts +5 -0
  69. package/dist/types/src/operations/close.d.ts.map +1 -0
  70. package/dist/types/src/operations/index.d.ts +3 -0
  71. package/dist/types/src/operations/index.d.ts.map +1 -0
  72. package/dist/types/src/operations/open.d.ts +5 -0
  73. package/dist/types/src/operations/open.d.ts.map +1 -0
  74. package/dist/types/src/operations/revert-workspace.d.ts +5 -0
  75. package/dist/types/src/operations/revert-workspace.d.ts.map +1 -0
  76. package/dist/types/src/operations/set-layout-mode.d.ts +5 -0
  77. package/dist/types/src/operations/set-layout-mode.d.ts.map +1 -0
  78. package/dist/types/src/operations/set.d.ts +5 -0
  79. package/dist/types/src/operations/set.d.ts.map +1 -0
  80. package/dist/types/src/operations/state-access.d.ts +8 -0
  81. package/dist/types/src/operations/state-access.d.ts.map +1 -0
  82. package/dist/types/src/operations/switch-workspace.d.ts +5 -0
  83. package/dist/types/src/operations/switch-workspace.d.ts.map +1 -0
  84. package/dist/types/src/operations/update-complementary.d.ts +5 -0
  85. package/dist/types/src/operations/update-complementary.d.ts.map +1 -0
  86. package/dist/types/src/operations/update-dialog.d.ts +5 -0
  87. package/dist/types/src/operations/update-dialog.d.ts.map +1 -0
  88. package/dist/types/src/operations/update-popover.d.ts +5 -0
  89. package/dist/types/src/operations/update-popover.d.ts.map +1 -0
  90. package/dist/types/src/operations/update-sidebar.d.ts +5 -0
  91. package/dist/types/src/operations/update-sidebar.d.ts.map +1 -0
  92. package/dist/types/src/translations.d.ts +26 -19
  93. package/dist/types/src/translations.d.ts.map +1 -1
  94. package/dist/types/src/types/capabilities.d.ts +10 -2
  95. package/dist/types/src/types/capabilities.d.ts.map +1 -1
  96. package/dist/types/tsconfig.tsbuildinfo +1 -1
  97. package/package.json +39 -29
  98. package/src/SimpleLayoutPlugin.ts +16 -6
  99. package/src/capabilities/app-graph-builder.ts +21 -0
  100. package/src/capabilities/index.ts +13 -6
  101. package/src/capabilities/operation-handler.ts +14 -0
  102. package/src/capabilities/{react-root/react-root.tsx → react-root.tsx} +2 -2
  103. package/src/capabilities/{react-surface/react-surface.tsx → react-surface.tsx} +16 -7
  104. package/src/capabilities/{state/state.tsx → state.tsx} +2 -2
  105. package/src/capabilities/url-handler.ts +161 -0
  106. package/src/components/DebugOverlay/DebugOverlay.tsx +96 -0
  107. package/src/components/DebugOverlay/index.ts +5 -0
  108. package/src/components/Dialog/Dialog.tsx +14 -3
  109. package/src/components/Home/Home.tsx +32 -32
  110. package/src/components/{ContentLoading.stories.tsx → Loading/Loading.stories.tsx} +4 -4
  111. package/src/components/{ContentLoading.tsx → Loading/Loading.tsx} +1 -1
  112. package/src/components/Loading/index.ts +5 -0
  113. package/src/components/MobileLayout/MobileLayout.stories.tsx +21 -17
  114. package/src/components/MobileLayout/MobileLayout.tsx +118 -49
  115. package/src/components/{Workspace/Workspace.tsx → NavBranch/NavBranch.tsx} +44 -41
  116. package/src/components/{Workspace → NavBranch}/index.ts +1 -1
  117. package/src/components/Popover/Popover.tsx +10 -16
  118. package/src/components/SimpleLayout/AppBar.stories.tsx +8 -9
  119. package/src/components/SimpleLayout/AppBar.tsx +60 -60
  120. package/src/components/SimpleLayout/Drawer.tsx +30 -31
  121. package/src/components/SimpleLayout/Main.tsx +21 -26
  122. package/src/components/SimpleLayout/NavBar.stories.tsx +1 -2
  123. package/src/components/SimpleLayout/NavBar.tsx +8 -9
  124. package/src/components/SimpleLayout/SimpleLayout.stories.tsx +43 -66
  125. package/src/components/SimpleLayout/SimpleLayout.tsx +33 -34
  126. package/src/components/hooks.ts +8 -8
  127. package/src/components/index.ts +3 -2
  128. package/src/hooks/actions.ts +15 -16
  129. package/src/hooks/useAppBarProps.ts +10 -11
  130. package/src/hooks/useDrawerActions.ts +13 -11
  131. package/src/hooks/useNavbarActions.ts +8 -7
  132. package/src/hooks/useSimpleLayoutState.ts +1 -1
  133. package/src/meta.ts +1 -1
  134. package/src/operations/close.ts +34 -0
  135. package/src/operations/index.ts +16 -0
  136. package/src/operations/open.ts +63 -0
  137. package/src/operations/revert-workspace.ts +22 -0
  138. package/src/operations/set-layout-mode.ts +12 -0
  139. package/src/operations/set.ts +23 -0
  140. package/src/operations/state-access.ts +19 -0
  141. package/src/operations/switch-workspace.ts +26 -0
  142. package/src/operations/update-complementary.ts +35 -0
  143. package/src/operations/update-dialog.ts +28 -0
  144. package/src/operations/update-popover.ts +35 -0
  145. package/src/operations/update-sidebar.ts +12 -0
  146. package/src/translations.ts +21 -19
  147. package/src/types/capabilities.ts +4 -4
  148. package/dist/lib/browser/chunk-7VLT3S46.mjs +0 -29
  149. package/dist/lib/browser/chunk-7VLT3S46.mjs.map +0 -7
  150. package/dist/lib/browser/chunk-TMZNLVT2.mjs +0 -1170
  151. package/dist/lib/browser/chunk-TMZNLVT2.mjs.map +0 -7
  152. package/dist/lib/browser/operation-resolver-BYRIQOQT.mjs +0 -205
  153. package/dist/lib/browser/operation-resolver-BYRIQOQT.mjs.map +0 -7
  154. package/dist/lib/browser/react-root-MMB575WY.mjs +0 -21
  155. package/dist/lib/browser/react-root-MMB575WY.mjs.map +0 -7
  156. package/dist/lib/browser/react-surface-M6CURANW.mjs +0 -41
  157. package/dist/lib/browser/react-surface-M6CURANW.mjs.map +0 -7
  158. package/dist/lib/browser/spotlight-dismiss-67PHYS5B.mjs +0 -66
  159. package/dist/lib/browser/spotlight-dismiss-67PHYS5B.mjs.map +0 -7
  160. package/dist/lib/browser/state-A3PGDWWZ.mjs +0 -48
  161. package/dist/lib/browser/state-A3PGDWWZ.mjs.map +0 -7
  162. package/dist/lib/browser/url-handler-HTIUY6WL.mjs +0 -152
  163. package/dist/lib/browser/url-handler-HTIUY6WL.mjs.map +0 -7
  164. package/dist/lib/node-esm/chunk-FLOYBAHE.mjs +0 -1171
  165. package/dist/lib/node-esm/chunk-FLOYBAHE.mjs.map +0 -7
  166. package/dist/lib/node-esm/chunk-VIDE5UMB.mjs +0 -31
  167. package/dist/lib/node-esm/chunk-VIDE5UMB.mjs.map +0 -7
  168. package/dist/lib/node-esm/operation-resolver-BDTFNCS2.mjs +0 -206
  169. package/dist/lib/node-esm/operation-resolver-BDTFNCS2.mjs.map +0 -7
  170. package/dist/lib/node-esm/react-root-ENZKVSY4.mjs +0 -22
  171. package/dist/lib/node-esm/react-root-ENZKVSY4.mjs.map +0 -7
  172. package/dist/lib/node-esm/react-surface-ITVNQYLG.mjs +0 -42
  173. package/dist/lib/node-esm/react-surface-ITVNQYLG.mjs.map +0 -7
  174. package/dist/lib/node-esm/spotlight-dismiss-RMLRZUVY.mjs +0 -68
  175. package/dist/lib/node-esm/spotlight-dismiss-RMLRZUVY.mjs.map +0 -7
  176. package/dist/lib/node-esm/state-ZCFZTTPL.mjs +0 -49
  177. package/dist/lib/node-esm/state-ZCFZTTPL.mjs.map +0 -7
  178. package/dist/lib/node-esm/url-handler-WBVVKVPC.mjs +0 -153
  179. package/dist/lib/node-esm/url-handler-WBVVKVPC.mjs.map +0 -7
  180. package/dist/types/src/capabilities/operation-resolver/index.d.ts +0 -3
  181. package/dist/types/src/capabilities/operation-resolver/index.d.ts.map +0 -1
  182. package/dist/types/src/capabilities/operation-resolver/operation-resolver.d.ts +0 -5
  183. package/dist/types/src/capabilities/operation-resolver/operation-resolver.d.ts.map +0 -1
  184. package/dist/types/src/capabilities/react-root/index.d.ts +0 -6
  185. package/dist/types/src/capabilities/react-root/index.d.ts.map +0 -1
  186. package/dist/types/src/capabilities/react-root/react-root.d.ts.map +0 -1
  187. package/dist/types/src/capabilities/react-surface/index.d.ts +0 -3
  188. package/dist/types/src/capabilities/react-surface/index.d.ts.map +0 -1
  189. package/dist/types/src/capabilities/react-surface/react-surface.d.ts.map +0 -1
  190. package/dist/types/src/capabilities/spotlight-dismiss/index.d.ts +0 -3
  191. package/dist/types/src/capabilities/spotlight-dismiss/index.d.ts.map +0 -1
  192. package/dist/types/src/capabilities/spotlight-dismiss/spotlight-dismiss.d.ts.map +0 -1
  193. package/dist/types/src/capabilities/state/index.d.ts +0 -13
  194. package/dist/types/src/capabilities/state/index.d.ts.map +0 -1
  195. package/dist/types/src/capabilities/state/state.d.ts.map +0 -1
  196. package/dist/types/src/capabilities/url-handler/index.d.ts +0 -3
  197. package/dist/types/src/capabilities/url-handler/index.d.ts.map +0 -1
  198. package/dist/types/src/capabilities/url-handler/url-handler.d.ts.map +0 -1
  199. package/dist/types/src/components/ContentLoading.d.ts +0 -3
  200. package/dist/types/src/components/ContentLoading.d.ts.map +0 -1
  201. package/dist/types/src/components/ContentLoading.stories.d.ts.map +0 -1
  202. package/dist/types/src/components/Workspace/Workspace.d.ts +0 -11
  203. package/dist/types/src/components/Workspace/Workspace.d.ts.map +0 -1
  204. package/dist/types/src/components/Workspace/index.d.ts +0 -2
  205. package/dist/types/src/components/Workspace/index.d.ts.map +0 -1
  206. package/src/capabilities/operation-resolver/index.ts +0 -10
  207. package/src/capabilities/operation-resolver/operation-resolver.ts +0 -217
  208. package/src/capabilities/react-root/index.ts +0 -7
  209. package/src/capabilities/react-surface/index.ts +0 -7
  210. package/src/capabilities/spotlight-dismiss/index.ts +0 -7
  211. package/src/capabilities/state/index.ts +0 -9
  212. package/src/capabilities/url-handler/index.ts +0 -7
  213. package/src/capabilities/url-handler/url-handler.ts +0 -157
  214. /package/dist/types/src/capabilities/{react-root/react-root.d.ts → react-root.d.ts} +0 -0
  215. /package/dist/types/src/capabilities/{react-surface/react-surface.d.ts → react-surface.d.ts} +0 -0
  216. /package/dist/types/src/capabilities/{spotlight-dismiss/spotlight-dismiss.d.ts → spotlight-dismiss.d.ts} +0 -0
  217. /package/src/capabilities/{spotlight-dismiss/spotlight-dismiss.ts → spotlight-dismiss.ts} +0 -0
@@ -1,217 +0,0 @@
1
- //
2
- // Copyright 2025 DXOS.org
3
- //
4
-
5
- import * as Effect from 'effect/Effect';
6
-
7
- import { Capabilities, Capability } from '@dxos/app-framework';
8
- import { LayoutOperation } from '@dxos/app-toolkit';
9
- import { Operation, OperationResolver } from '@dxos/operation';
10
- import { ATTENDABLE_PATH_SEPARATOR } from '@dxos/react-ui-attention';
11
-
12
- import { type SimpleLayoutState, SimpleLayoutState as SimpleLayoutStateCapability } from '../../types';
13
-
14
- /** Maximum number of items to keep in navigation history. */
15
- const MAX_HISTORY_LENGTH = 50;
16
-
17
- /** Parse entry ID to extract primary ID and variant. */
18
- const parseEntryId = (entryId: string) => {
19
- const [id, variant] = entryId.split(ATTENDABLE_PATH_SEPARATOR);
20
- return { id, variant };
21
- };
22
-
23
- export default Capability.makeModule(
24
- Effect.fnUntraced(function* () {
25
- const registry = yield* Capability.get(Capabilities.AtomRegistry);
26
- const stateAtom = yield* Capability.get(SimpleLayoutStateCapability);
27
-
28
- const getState = () => registry.get(stateAtom);
29
- const updateState = (fn: (current: SimpleLayoutState) => SimpleLayoutState) => {
30
- registry.set(stateAtom, fn(getState()));
31
- };
32
-
33
- return Capability.contributes(Capabilities.OperationResolver, [
34
- //
35
- // SetLayoutMode
36
- //
37
- // TODO(burdon): No-op for to fix startup bug?
38
- OperationResolver.make({
39
- operation: LayoutOperation.SetLayoutMode,
40
- handler: Effect.fnUntraced(function* () {}),
41
- }),
42
-
43
- //
44
- // UpdateSidebar - No-op for simple layout.
45
- //
46
- OperationResolver.make({
47
- operation: LayoutOperation.UpdateSidebar,
48
- handler: () => Effect.void,
49
- }),
50
-
51
- //
52
- // UpdateComplementary - Controls companion drawer.
53
- //
54
- OperationResolver.make({
55
- operation: LayoutOperation.UpdateComplementary,
56
- handler: Effect.fnUntraced(function* (input) {
57
- if (input.state === 'closed') {
58
- updateState((state) => ({
59
- ...state,
60
- drawerState: 'closed',
61
- }));
62
- }
63
- }),
64
- }),
65
-
66
- //
67
- // UpdateDialog
68
- //
69
- OperationResolver.make({
70
- operation: LayoutOperation.UpdateDialog,
71
- handler: Effect.fnUntraced(function* (input) {
72
- updateState((state) => ({
73
- ...state,
74
- dialogOpen: input.state ?? Boolean(input.subject),
75
- dialogType: input.type ?? 'default',
76
- dialogBlockAlign: input.blockAlign ?? 'center',
77
- dialogOverlayClasses: input.overlayClasses,
78
- dialogOverlayStyle: input.overlayStyle,
79
- dialogContent: input.subject ? { component: input.subject, props: input.props } : undefined,
80
- }));
81
- }),
82
- }),
83
-
84
- //
85
- // UpdatePopover
86
- //
87
- OperationResolver.make({
88
- operation: LayoutOperation.UpdatePopover,
89
- handler: Effect.fnUntraced(function* (input) {
90
- updateState((state) => ({
91
- ...state,
92
- popoverOpen: input.state ?? Boolean(input.subject),
93
- popoverKind: input.kind ?? 'base',
94
- popoverTitle: input.kind === 'card' ? input.title : undefined,
95
- popoverContent:
96
- typeof input.subject === 'string'
97
- ? { component: input.subject, props: input.props }
98
- : input.subject
99
- ? { subject: input.subject }
100
- : undefined,
101
- popoverSide: input.side,
102
- popoverVariant: input.variant,
103
- popoverAnchor: input.variant === 'virtual' ? input.anchor : state.popoverAnchor,
104
- popoverAnchorId: input.variant !== 'virtual' ? input.anchorId : state.popoverAnchorId,
105
- }));
106
- }),
107
- }),
108
-
109
- //
110
- // SwitchWorkspace
111
- //
112
- OperationResolver.make({
113
- operation: LayoutOperation.SwitchWorkspace,
114
- handler: Effect.fnUntraced(function* (input) {
115
- updateState((state) => ({
116
- ...state,
117
- // TODO(wittjosiah): This is a hack to prevent the previous deck from being set for pinned items.
118
- // Ideally this should be worked into the data model in a generic way.
119
- previousWorkspace: !state.workspace.startsWith('!') ? state.workspace : state.previousWorkspace,
120
- workspace: input.subject,
121
- active: undefined,
122
- // Clear history when switching workspaces.
123
- history: [],
124
- }));
125
- }),
126
- }),
127
-
128
- //
129
- // RevertWorkspace
130
- //
131
- OperationResolver.make({
132
- operation: LayoutOperation.RevertWorkspace,
133
- handler: Effect.fnUntraced(function* () {
134
- const state = getState();
135
- yield* Operation.invoke(LayoutOperation.SwitchWorkspace, {
136
- subject: state.previousWorkspace,
137
- });
138
- }),
139
- }),
140
-
141
- //
142
- // Open
143
- //
144
- OperationResolver.make({
145
- operation: LayoutOperation.Open,
146
- handler: Effect.fnUntraced(function* (input) {
147
- const id = input.subject[0];
148
- const { id: primaryId, variant } = parseEntryId(id);
149
- const state = getState();
150
-
151
- // Only treat as companion when opening a variant of the current workspace/active (e.g. object~comments).
152
- // IDs like settings~spaceId are alternate-tree nodes and should navigate main content, not open the drawer.
153
- // TODO(wittjosiah): Factor out the change-companion operation from deck to a common layout operation.
154
- const isCompanionOfCurrent = variant && (primaryId === state.workspace || primaryId === state.active);
155
- if (isCompanionOfCurrent) {
156
- updateState((state) => ({
157
- ...state,
158
- companionVariant: variant,
159
- drawerState: state.drawerState === 'closed' || !state.drawerState ? 'open' : state.drawerState,
160
- }));
161
- } else {
162
- // Regular navigation - update active and history (use full id for alternate-tree nodes).
163
- updateState((state) => {
164
- const newHistory = state.active ? [...state.history, state.active] : state.history;
165
- const trimmedHistory =
166
- newHistory.length > MAX_HISTORY_LENGTH ? newHistory.slice(-MAX_HISTORY_LENGTH) : newHistory;
167
- return {
168
- ...state,
169
- active: id,
170
- history: trimmedHistory,
171
- };
172
- });
173
- }
174
- }),
175
- }),
176
-
177
- //
178
- // Close
179
- //
180
- OperationResolver.make({
181
- operation: LayoutOperation.Close,
182
- handler: Effect.fnUntraced(function* () {
183
- updateState((state) => {
184
- // Pop from history if available.
185
- if (state.history.length > 0) {
186
- const newHistory = [...state.history];
187
- const previousActive = newHistory.pop();
188
- return {
189
- ...state,
190
- active: previousActive,
191
- history: newHistory,
192
- };
193
- }
194
- // No history, just clear active.
195
- return {
196
- ...state,
197
- active: undefined,
198
- };
199
- });
200
- }),
201
- }),
202
-
203
- //
204
- // Set
205
- //
206
- OperationResolver.make({
207
- operation: LayoutOperation.Set,
208
- handler: Effect.fnUntraced(function* (input) {
209
- updateState((state) => ({
210
- ...state,
211
- active: input.subject[0],
212
- }));
213
- }),
214
- }),
215
- ]);
216
- }),
217
- );
@@ -1,7 +0,0 @@
1
- //
2
- // Copyright 2025 DXOS.org
3
- //
4
-
5
- import { Capability } from '@dxos/app-framework';
6
-
7
- export const ReactRoot = Capability.lazy('ReactRoot', () => import('./react-root'));
@@ -1,7 +0,0 @@
1
- //
2
- // Copyright 2025 DXOS.org
3
- //
4
-
5
- import { Capability } from '@dxos/app-framework';
6
-
7
- export const ReactSurface = Capability.lazy('ReactSurface', () => import('./react-surface'));
@@ -1,7 +0,0 @@
1
- //
2
- // Copyright 2025 DXOS.org
3
- //
4
-
5
- import { Capability } from '@dxos/app-framework';
6
-
7
- export const SpotlightDismiss = Capability.lazy('SpotlightDismiss', () => import('./spotlight-dismiss'));
@@ -1,9 +0,0 @@
1
- //
2
- // Copyright 2025 DXOS.org
3
- //
4
-
5
- import { Capability } from '@dxos/app-framework';
6
-
7
- export const State = Capability.lazy('State', () => import('./state'));
8
-
9
- export type { SimpleLayoutStateOptions } from './state';
@@ -1,7 +0,0 @@
1
- //
2
- // Copyright 2025 DXOS.org
3
- //
4
-
5
- import { Capability } from '@dxos/app-framework';
6
-
7
- export const UrlHandler = Capability.lazy('UrlHandler', () => import('./url-handler'));
@@ -1,157 +0,0 @@
1
- //
2
- // Copyright 2025 DXOS.org
3
- //
4
-
5
- import * as Effect from 'effect/Effect';
6
-
7
- import { Capabilities, Capability } from '@dxos/app-framework';
8
- import { LayoutOperation } from '@dxos/app-toolkit';
9
- import { log } from '@dxos/log';
10
- import { Node } from '@dxos/plugin-graph';
11
- import { isTauri } from '@dxos/util';
12
-
13
- import { type SimpleLayoutState, SimpleLayoutState as SimpleLayoutStateCapability } from '../../types';
14
-
15
- /**
16
- * URL handler for simple layout that syncs browser URL with layout state.
17
- * URL format: /{workspace} or /{workspace}/{active}
18
- * Root is represented as / or /root.
19
- *
20
- * On mobile Tauri, also listens for deep links via the deep-link plugin.
21
- */
22
- export default Capability.makeModule(
23
- Effect.fnUntraced(function* () {
24
- const { invokeSync } = yield* Capability.get(Capabilities.OperationInvoker);
25
-
26
- /**
27
- * Handle navigation from a pathname.
28
- * Parses path and updates state accordingly.
29
- */
30
- const handlePathNavigation = (pathname: string) => {
31
- log.info('[UrlHandler] Navigating to path', { pathname });
32
-
33
- // Parse URL segments: /{workspace}/{active}
34
- const [_, nextWorkspace, nextActive] = pathname.split('/');
35
-
36
- // Determine target workspace (empty or 'root' means Node.RootId).
37
- const targetWorkspace = !nextWorkspace || nextWorkspace === 'root' ? Node.RootId : nextWorkspace;
38
-
39
- // Navigate via operations (they will update state accordingly).
40
- invokeSync(LayoutOperation.SwitchWorkspace, { subject: targetWorkspace });
41
- if (nextActive) {
42
- invokeSync(LayoutOperation.Open, { subject: [nextActive] });
43
- }
44
- };
45
-
46
- const onNavigation = handleNavigation(handlePathNavigation);
47
-
48
- // Handle initial URL and listen for browser navigation.
49
- yield* Effect.sync(() => onNavigation());
50
- window.addEventListener('popstate', onNavigation);
51
-
52
- // Set up deep link listener for mobile Tauri.
53
- let unlistenDeepLink: (() => void) | undefined;
54
- if (isTauri()) {
55
- yield* Effect.tryPromise({
56
- try: async () => {
57
- const { getCurrent, onOpenUrl } = await import('@tauri-apps/plugin-deep-link');
58
-
59
- // Check if app was launched via deep link (cold start).
60
- const launchUrls = await getCurrent();
61
- if (launchUrls && launchUrls.length > 0) {
62
- log.info('[UrlHandler] App launched with deep links', { urls: launchUrls });
63
- for (const url of launchUrls) {
64
- handleDeepLink(url, handlePathNavigation);
65
- }
66
- }
67
-
68
- // Listen for deep links while app is running.
69
- unlistenDeepLink = await onOpenUrl((urls) => {
70
- log.info('[UrlHandler] Deep links received', { urls });
71
- for (const url of urls) {
72
- handleDeepLink(url, handlePathNavigation);
73
- }
74
- });
75
-
76
- log.info('[UrlHandler] Deep link listener initialized');
77
- },
78
- catch: (error) => {
79
- log.warn('[UrlHandler] Failed to initialize deep link listener', { error });
80
- return error;
81
- },
82
- }).pipe(Effect.catchAll(() => Effect.void));
83
- }
84
-
85
- // Subscribe to state changes to update the URL.
86
- let lastWorkspace: string | undefined;
87
- let lastActive: string | undefined;
88
- const unsubscribe = yield* Capabilities.subscribeAtom(SimpleLayoutStateCapability, (state: SimpleLayoutState) => {
89
- const { workspace, active } = state;
90
-
91
- // Only update URL if relevant state changed.
92
- if (workspace !== lastWorkspace || active !== lastActive) {
93
- lastWorkspace = workspace;
94
- lastActive = active;
95
-
96
- const path = pathFromState(workspace, active);
97
- if (window.location.pathname !== path) {
98
- history.pushState(null, '', `${path}${window.location.search}`);
99
- }
100
- }
101
- });
102
-
103
- return Capability.contributes(Capabilities.Null, null, () =>
104
- Effect.sync(() => {
105
- window.removeEventListener('popstate', onNavigation);
106
- unsubscribe();
107
- unlistenDeepLink?.();
108
- }),
109
- );
110
- }),
111
- );
112
-
113
- // TODO(wittjosiah): Instead of hardcoding redirect paths, we should either:
114
- // 1. Validate that the workspace exists in the graph before navigating.
115
- // 2. Implement more structured routing with explicit route definitions.
116
- /**
117
- * Check if a path is a special redirect path that shouldn't be navigated to.
118
- * These paths are handled by other systems (e.g., OAuth).
119
- */
120
- const isRedirectPath = (pathname: string): boolean => pathname.startsWith('/redirect/');
121
-
122
- /**
123
- * Build pathname from layout state. Root workspace is / or /root/{active}.
124
- */
125
- const pathFromState = (workspace: string, active: string | undefined): string =>
126
- workspace === Node.RootId
127
- ? active
128
- ? `/${Node.RootId}/${active}`
129
- : '/'
130
- : active
131
- ? `/${workspace}/${active}`
132
- : `/${workspace}`;
133
-
134
- /**
135
- * Returns a handler for navigation events (initial load and popstate) that navigates to current pathname.
136
- */
137
- const handleNavigation =
138
- (navigate: (pathname: string) => void): (() => void) =>
139
- () =>
140
- navigate(window.location.pathname);
141
-
142
- /**
143
- * Handle deep link URL from Tauri. Parses the URL and calls navigate unless it's a redirect path.
144
- */
145
- const handleDeepLink = (urlString: string, navigate: (pathname: string) => void): void => {
146
- log.info('[UrlHandler] Deep link received', { url: urlString });
147
- try {
148
- const url = new URL(urlString);
149
- if (isRedirectPath(url.pathname)) {
150
- log.info('[UrlHandler] Skipping redirect path (handled elsewhere)', { pathname: url.pathname });
151
- return;
152
- }
153
- navigate(url.pathname);
154
- } catch (error) {
155
- log.warn('[UrlHandler] Failed to parse deep link URL', { urlString, error });
156
- }
157
- };