@dxos/plugin-stack 0.12.0-next-2800d0376abcc62d5544afdd744b16b2b960434e → 0.13.0
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.
- package/PLUGIN.mdl +72 -9
- package/dist/lib/capabilities.browser.mjs +18 -0
- package/dist/lib/capabilities.browser.mjs.map +1 -0
- package/dist/lib/capabilities.mjs +2 -2
- package/dist/lib/capabilities.mjs.map +1 -1
- package/dist/lib/capabilities.node.mjs.map +1 -1
- package/dist/lib/capabilities.tauri.mjs +18 -0
- package/dist/lib/capabilities.tauri.mjs.map +1 -0
- package/dist/lib/capabilities.workerd.mjs.map +1 -1
- package/dist/lib/chunk-PLUGIN.mjs +6 -0
- package/dist/lib/chunk-PLUGIN.mjs.map +1 -0
- package/dist/lib/chunk-StackArticle.mjs +16 -17
- package/dist/lib/chunk-StackArticle.mjs.map +1 -1
- package/dist/lib/chunk-react-surface.mjs +2 -2
- package/dist/lib/chunk-react-surface.mjs.map +1 -1
- package/dist/lib/components.mjs +62 -52
- package/dist/lib/components.mjs.map +1 -1
- package/dist/lib/containers.mjs.map +1 -1
- package/dist/lib/index.mjs +0 -1
- package/dist/lib/meta.mjs.map +1 -1
- package/dist/lib/translations.mjs.map +1 -1
- package/dist/types/src/capabilities/gen/browser.d.ts +5 -0
- package/dist/types/src/capabilities/gen/browser.d.ts.map +1 -0
- package/dist/types/src/capabilities/gen/node.d.ts.map +1 -1
- package/dist/types/src/capabilities/gen/tauri.d.ts +5 -0
- package/dist/types/src/capabilities/gen/tauri.d.ts.map +1 -0
- package/dist/types/src/capabilities/gen/workerd.d.ts.map +1 -1
- package/dist/types/src/capabilities/index.d.ts.map +1 -1
- package/dist/types/src/components/Stack/Stack.d.ts +4 -13
- package/dist/types/src/components/Stack/Stack.d.ts.map +1 -1
- package/dist/types/src/components/Stack/StackContext.d.ts +1 -1
- package/dist/types/src/components/Stack/StackContext.d.ts.map +1 -1
- package/dist/types/src/components/Stack/index.d.ts +2 -2
- package/dist/types/src/components/Stack/index.d.ts.map +1 -1
- package/dist/types/src/components/index.d.ts +1 -1
- package/dist/types/src/components/index.d.ts.map +1 -1
- package/dist/types/src/containers/StackArticle/StackArticle.d.ts +1 -1
- package/dist/types/src/containers/StackArticle/StackArticle.d.ts.map +1 -1
- package/dist/types/src/containers/StackArticle/StackArticle.stories.d.ts +1 -1
- package/dist/types/src/containers/StackArticle/StackArticle.stories.d.ts.map +1 -1
- package/dist/types/src/containers/StackArticle/index.d.ts +1 -1
- package/dist/types/src/containers/StackArticle/index.d.ts.map +1 -1
- package/dist/types/src/containers/index.d.ts.map +1 -1
- package/dist/types/src/index.d.ts +1 -2
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/translations.d.ts.map +1 -1
- package/dist/types/src/types/index.d.ts +2 -2
- package/dist/types/src/types/index.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +34 -32
- package/src/capabilities/gen/browser.ts +27 -0
- package/src/capabilities/gen/node.ts +1 -1
- package/src/capabilities/gen/tauri.ts +27 -0
- package/src/capabilities/gen/workerd.ts +1 -1
- package/src/capabilities/index.ts +2 -2
- package/src/capabilities/react-surface.ts +2 -2
- package/src/components/Stack/Stack.tsx +67 -62
- package/src/components/Stack/StackContext.ts +1 -1
- package/src/components/Stack/index.ts +2 -2
- package/src/components/index.ts +1 -1
- package/src/containers/StackArticle/StackArticle.stories.tsx +4 -4
- package/src/containers/StackArticle/StackArticle.tsx +24 -26
- package/src/containers/StackArticle/index.ts +1 -1
- package/src/containers/index.ts +1 -1
- package/src/index.ts +1 -2
- package/src/meta.ts +1 -1
- package/src/translations.ts +2 -2
- package/src/types/index.ts +2 -2
package/PLUGIN.mdl
CHANGED
|
@@ -15,9 +15,10 @@ Each extension is defined in the Appendix or resolved via its URI.
|
|
|
15
15
|
|-------------|--------------------------------|
|
|
16
16
|
| `type` | `org.dxos.mdl.type@1.0` |
|
|
17
17
|
| `feat` | `org.dxos.mdl.feat@1.0` |
|
|
18
|
-
| `
|
|
18
|
+
| `scenario` | `org.dxos.mdl.scenario@1.0` |
|
|
19
19
|
| `component` | `org.dxos.mdl.component@1.0` |
|
|
20
20
|
| `op` | `org.dxos.mdl.op@1.0` |
|
|
21
|
+
| `test` | `org.dxos.mdl.test@1.0` |
|
|
21
22
|
|
|
22
23
|
## Types
|
|
23
24
|
|
|
@@ -212,7 +213,7 @@ feat F-5: Schema Registration
|
|
|
212
213
|
## Acceptance
|
|
213
214
|
|
|
214
215
|
```mdl
|
|
215
|
-
|
|
216
|
+
scenario T-1: Collection renders as stack
|
|
216
217
|
given: a Collection with three objects is opened in article role
|
|
217
218
|
then:
|
|
218
219
|
- StackArticle is displayed
|
|
@@ -221,14 +222,14 @@ test T-1: Collection renders as stack
|
|
|
221
222
|
```
|
|
222
223
|
|
|
223
224
|
```mdl
|
|
224
|
-
|
|
225
|
+
scenario T-2: Add section via toolbar
|
|
225
226
|
given: StackArticle is open
|
|
226
227
|
when: user clicks the Add Section toolbar button
|
|
227
228
|
then: SpaceOperation.OpenObjectForm is invoked with the collection as target
|
|
228
229
|
```
|
|
229
230
|
|
|
230
231
|
```mdl
|
|
231
|
-
|
|
232
|
+
scenario T-3: Remove section
|
|
232
233
|
given: StackArticle is open with at least one section
|
|
233
234
|
when: user selects Remove from a section dropdown
|
|
234
235
|
then:
|
|
@@ -237,7 +238,7 @@ test T-3: Remove section
|
|
|
237
238
|
```
|
|
238
239
|
|
|
239
240
|
```mdl
|
|
240
|
-
|
|
241
|
+
scenario T-4: Collapse section
|
|
241
242
|
given: a section is expanded
|
|
242
243
|
when: user selects Collapse from the section dropdown
|
|
243
244
|
then:
|
|
@@ -247,20 +248,82 @@ test T-4: Collapse section
|
|
|
247
248
|
```
|
|
248
249
|
|
|
249
250
|
```mdl
|
|
250
|
-
|
|
251
|
+
scenario T-5: Navigate to section
|
|
251
252
|
given: StackArticle is open
|
|
252
253
|
when: user clicks the navigate button on a section heading
|
|
253
254
|
then: LayoutOperation.Open is invoked with the section's DXN id
|
|
254
255
|
```
|
|
255
256
|
|
|
256
257
|
```mdl
|
|
257
|
-
|
|
258
|
+
scenario T-6: StackViewType registered
|
|
258
259
|
given: StackPlugin is active
|
|
259
260
|
then: StackViewType (typename org.dxos.type.stackView) is registered with the ECHO schema module
|
|
260
261
|
```
|
|
261
262
|
|
|
262
263
|
---
|
|
263
264
|
|
|
265
|
+
## QA
|
|
266
|
+
|
|
267
|
+
Executable tests. Each step carries a human instruction (`do`) and, where the step maps to an
|
|
268
|
+
invocable operation, an agent binding (`invoke`). Report failures by test and step number.
|
|
269
|
+
|
|
270
|
+
```mdl
|
|
271
|
+
test QA-1: Render a collection as a stack, add, collapse, and remove a section
|
|
272
|
+
desc: |
|
|
273
|
+
StackPlugin declares no operations of its own — every mutation goes through
|
|
274
|
+
`SpaceOperation.AddObject`/`RemoveObjects` (F-2.1, F-2.3), which belong to `plugin-space`.
|
|
275
|
+
actors: both
|
|
276
|
+
covers: [F-1.1, F-1.2, F-2.3, F-3.1, T-1, T-3, T-4]
|
|
277
|
+
status: unverified
|
|
278
|
+
given:
|
|
279
|
+
- an identity exists
|
|
280
|
+
- space: a space is open
|
|
281
|
+
- plugin-stack is enabled — it is OFF by default for everyone (not listed in
|
|
282
|
+
`getDefaults`, unlike most content plugins in `plugin-defs.tsx`), so no `article` surface
|
|
283
|
+
resolves for a Collection's stack view until it is turned on
|
|
284
|
+
- no collection named "QA Stack" exists — ABORT rather than deleting one this test did not
|
|
285
|
+
create
|
|
286
|
+
steps:
|
|
287
|
+
- name: Create the collection and a section
|
|
288
|
+
do: In the navtree, click + on the space and choose Collection. Name it "QA Stack". Open
|
|
289
|
+
it, click "Add Section" in the toolbar, and choose Markdown, naming it "QA Section".
|
|
290
|
+
invoke: org.dxos.operation.space.createCollection { name: "QA Stack" }
|
|
291
|
+
capture: collection
|
|
292
|
+
expect: "QA Stack" opens as a StackArticle with one StackSection titled "QA Section"
|
|
293
|
+
assert: return $collection.object.name === 'QA Stack';
|
|
294
|
+
note: |
|
|
295
|
+
Coalesce the "Add Section" click with the object creation it triggers — `OpenObjectForm`
|
|
296
|
+
opens a dialog and the resulting object is added via `AddObject`, which is the same
|
|
297
|
+
pattern as `plugin-markdown`'s create+place split.
|
|
298
|
+
- name: Add the section object
|
|
299
|
+
do: (the Add Section dialog places it for you on confirm)
|
|
300
|
+
invoke: org.dxos.operation.markdown.create { name: "QA Section" }
|
|
301
|
+
capture: doc
|
|
302
|
+
expect: a Document named "QA Section" exists
|
|
303
|
+
- name: Place the section in the stack
|
|
304
|
+
do: (as above)
|
|
305
|
+
invoke: org.dxos.operation.space.addObject { object: $doc.object, target: $collection.object }
|
|
306
|
+
expect: a StackSection titled "QA Section" now renders below the toolbar (F-1.2)
|
|
307
|
+
assert: return $collection.object.objects.some((ref) => ref.target?.id === $doc.object.id);
|
|
308
|
+
- name: Collapse the section
|
|
309
|
+
do: Open the section's sigil dropdown and choose Collapse.
|
|
310
|
+
expect: the section shows only its title; the caret points to "expand" (F-3.3, T-4)
|
|
311
|
+
note: NO invoke — collapse state is local StackArticle component state (F-3.4), not an
|
|
312
|
+
ECHO write, so there is nothing to verify against the database.
|
|
313
|
+
- name: Remove the section
|
|
314
|
+
do: Open the dropdown again and choose Remove.
|
|
315
|
+
invoke: org.dxos.operation.space.removeObjects { objects: [$doc.object], target: $collection.object }
|
|
316
|
+
expect: the section no longer appears in the stack (T-3)
|
|
317
|
+
assert: return !$collection.object.objects.some((ref) => ref.target?.id === $doc.object.id);
|
|
318
|
+
after:
|
|
319
|
+
- name: Delete the collection
|
|
320
|
+
do: Right-click "QA Stack" in the navtree and choose Delete.
|
|
321
|
+
invoke: org.dxos.operation.space.removeObjects { objects: [$collection.object], target: $given.space }
|
|
322
|
+
expect: the row leaves the navtree and its plank closes
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
---
|
|
326
|
+
|
|
264
327
|
## Appendix: Extension Definitions
|
|
265
328
|
|
|
266
329
|
```mdl
|
|
@@ -285,8 +348,8 @@ ext feat
|
|
|
285
348
|
```
|
|
286
349
|
|
|
287
350
|
```mdl
|
|
288
|
-
ext
|
|
289
|
-
uri: org.dxos.mdl.
|
|
351
|
+
ext scenario
|
|
352
|
+
uri: org.dxos.mdl.scenario@1.0
|
|
290
353
|
desc: An acceptance scenario expressed as given / when / then steps.
|
|
291
354
|
fields:
|
|
292
355
|
given?: Step | Step[]
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { t as PLUGIN_default } from "./chunk-PLUGIN.mjs";
|
|
2
|
+
import * as AppCapability from "@dxos/app-toolkit/AppCapability";
|
|
3
|
+
import { translations } from "#translations";
|
|
4
|
+
import { meta } from "#meta";
|
|
5
|
+
//#region src/capabilities/gen/browser.ts
|
|
6
|
+
var PluginAsset = AppCapability.pluginAsset({
|
|
7
|
+
pluginId: meta.profile.key,
|
|
8
|
+
path: "PLUGIN.mdl",
|
|
9
|
+
content: PLUGIN_default,
|
|
10
|
+
mimeType: "application/x-mdl"
|
|
11
|
+
});
|
|
12
|
+
var ReactSurface = AppCapability.surface(() => import("./chunk-react-surface.mjs"), { roles: ["org.dxos.role.article"] });
|
|
13
|
+
var Schema = AppCapability.schema(() => import("./chunk-schema.mjs"));
|
|
14
|
+
var Translations = AppCapability.translations(translations);
|
|
15
|
+
//#endregion
|
|
16
|
+
export { PluginAsset, ReactSurface, Schema, Translations };
|
|
17
|
+
|
|
18
|
+
//# sourceMappingURL=capabilities.browser.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capabilities.browser.mjs","names":[],"sources":["../../src/capabilities/gen/browser.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\n// GENERATED by dx-plugin — do not edit. Sliced from ../index.ts for the 'browser' condition.\n\nimport * as AppCapability from '@dxos/app-toolkit/AppCapability';\n\nimport { meta } from '#meta';\nimport { translations } from '#translations';\n\nimport pluginSpec from '../../../PLUGIN.mdl?raw';\n\nexport const PluginAsset = AppCapability.pluginAsset({\n pluginId: meta.profile.key,\n path: 'PLUGIN.mdl',\n content: pluginSpec,\n mimeType: 'application/x-mdl',\n});\n\nexport const ReactSurface = AppCapability.surface(() => import('../react-surface.ts'), {\n roles: ['org.dxos.role.article'],\n});\n\nexport const Schema = AppCapability.schema(() => import('../schema.ts'));\n\nexport const Translations = AppCapability.translations(translations);\n"],"mappings":";;;;;AAaA,IAAa,cAAc,cAAc,YAAY;CACnD,UAAU,KAAK,QAAQ;CACvB,MAAM;CACN,SAAS;CACT,UAAU;AACZ,CAAC;AAED,IAAa,eAAe,cAAc,cAAc,OAAO,8BAAwB,EACrF,OAAO,CAAC,uBAAuB,EACjC,CAAC;AAED,IAAa,SAAS,cAAc,aAAa,OAAO,qBAAe;AAEvE,IAAa,eAAe,cAAc,aAAa,YAAY"}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
+
import { t as PLUGIN_default } from "./chunk-PLUGIN.mjs";
|
|
1
2
|
import * as AppCapability from "@dxos/app-toolkit/AppCapability";
|
|
2
3
|
import { translations } from "#translations";
|
|
3
4
|
import { meta } from "#meta";
|
|
4
|
-
//#endregion
|
|
5
5
|
//#region src/capabilities/index.ts
|
|
6
6
|
var PluginAsset = AppCapability.pluginAsset({
|
|
7
7
|
pluginId: meta.profile.key,
|
|
8
8
|
path: "PLUGIN.mdl",
|
|
9
|
-
content:
|
|
9
|
+
content: PLUGIN_default,
|
|
10
10
|
mimeType: "application/x-mdl"
|
|
11
11
|
});
|
|
12
12
|
var ReactSurface = AppCapability.surface(() => import("./chunk-react-surface.mjs"), { roles: ["org.dxos.role.article"] });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"capabilities.mjs","names":[],"sources":["../../src/capabilities/index.ts"],"sourcesContent":["//\n// Copyright 2025 DXOS.org\n//\n\nimport * as AppCapability from '@dxos/app-toolkit/AppCapability';\n\nimport { meta } from '#meta';\nimport { translations } from '#translations';\n\n// eslint-disable-next-line import/no-relative-packages\nimport pluginSpec from '../../PLUGIN.mdl?raw';\n\nexport const PluginAsset = AppCapability.pluginAsset({\n pluginId: meta.profile.key,\n path: 'PLUGIN.mdl',\n content: pluginSpec,\n mimeType: 'application/x-mdl',\n});\nexport const ReactSurface = AppCapability.surface(() => import('./react-surface'), {\n roles: ['org.dxos.role.article'],\n});\nexport const Schema = AppCapability.schema(() => import('./schema'));\nexport const Translations = AppCapability.translations(translations);\n"],"mappings":";;;;;AAYA,IAAa,cAAc,cAAc,YAAY;CACnD,UAAU,KAAK,QAAQ;CACvB,MAAM;CACN,SAAS;CACT,UAAU;AACZ,CAAC;AACD,IAAa,eAAe,cAAc,cAAc,OAAO,
|
|
1
|
+
{"version":3,"file":"capabilities.mjs","names":[],"sources":["../../src/capabilities/index.ts"],"sourcesContent":["//\n// Copyright 2025 DXOS.org\n//\n\nimport * as AppCapability from '@dxos/app-toolkit/AppCapability';\n\nimport { meta } from '#meta';\nimport { translations } from '#translations';\n\n// eslint-disable-next-line import/no-relative-packages\nimport pluginSpec from '../../PLUGIN.mdl?raw';\n\nexport const PluginAsset = AppCapability.pluginAsset({\n pluginId: meta.profile.key,\n path: 'PLUGIN.mdl',\n content: pluginSpec,\n mimeType: 'application/x-mdl',\n});\nexport const ReactSurface = AppCapability.surface(() => import('./react-surface.ts'), {\n roles: ['org.dxos.role.article'],\n});\nexport const Schema = AppCapability.schema(() => import('./schema.ts'));\nexport const Translations = AppCapability.translations(translations);\n"],"mappings":";;;;;AAYA,IAAa,cAAc,cAAc,YAAY;CACnD,UAAU,KAAK,QAAQ;CACvB,MAAM;CACN,SAAS;CACT,UAAU;AACZ,CAAC;AACD,IAAa,eAAe,cAAc,cAAc,OAAO,8BAAuB,EACpF,OAAO,CAAC,uBAAuB,EACjC,CAAC;AACD,IAAa,SAAS,cAAc,aAAa,OAAO,qBAAc;AACtE,IAAa,eAAe,cAAc,aAAa,YAAY"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"capabilities.node.mjs","names":[],"sources":["../../src/capabilities/gen/node.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\n// GENERATED by dx-plugin — do not edit. Sliced from ../index.ts for the 'node' condition.\n\nimport * as AppCapability from '@dxos/app-toolkit/AppCapability';\n\nimport { translations } from '#translations';\n\nexport const Schema = AppCapability.schema(() => import('../schema'));\n\nexport const Translations = AppCapability.translations(translations);\n\nexport const PluginAsset = undefined;\nexport const ReactSurface = undefined;\n"],"mappings":";;;AAUA,IAAa,SAAS,cAAc,aAAa,OAAO,
|
|
1
|
+
{"version":3,"file":"capabilities.node.mjs","names":[],"sources":["../../src/capabilities/gen/node.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\n// GENERATED by dx-plugin — do not edit. Sliced from ../index.ts for the 'node' condition.\n\nimport * as AppCapability from '@dxos/app-toolkit/AppCapability';\n\nimport { translations } from '#translations';\n\nexport const Schema = AppCapability.schema(() => import('../schema.ts'));\n\nexport const Translations = AppCapability.translations(translations);\n\nexport const PluginAsset = undefined;\nexport const ReactSurface = undefined;\n"],"mappings":";;;AAUA,IAAa,SAAS,cAAc,aAAa,OAAO,qBAAe;AAEvE,IAAa,eAAe,cAAc,aAAa,YAAY;AAEnE,IAAa,cAAc,KAAA;AAC3B,IAAa,eAAe,KAAA"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { t as PLUGIN_default } from "./chunk-PLUGIN.mjs";
|
|
2
|
+
import * as AppCapability from "@dxos/app-toolkit/AppCapability";
|
|
3
|
+
import { translations } from "#translations";
|
|
4
|
+
import { meta } from "#meta";
|
|
5
|
+
//#region src/capabilities/gen/tauri.ts
|
|
6
|
+
var PluginAsset = AppCapability.pluginAsset({
|
|
7
|
+
pluginId: meta.profile.key,
|
|
8
|
+
path: "PLUGIN.mdl",
|
|
9
|
+
content: PLUGIN_default,
|
|
10
|
+
mimeType: "application/x-mdl"
|
|
11
|
+
});
|
|
12
|
+
var ReactSurface = AppCapability.surface(() => import("./chunk-react-surface.mjs"), { roles: ["org.dxos.role.article"] });
|
|
13
|
+
var Schema = AppCapability.schema(() => import("./chunk-schema.mjs"));
|
|
14
|
+
var Translations = AppCapability.translations(translations);
|
|
15
|
+
//#endregion
|
|
16
|
+
export { PluginAsset, ReactSurface, Schema, Translations };
|
|
17
|
+
|
|
18
|
+
//# sourceMappingURL=capabilities.tauri.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capabilities.tauri.mjs","names":[],"sources":["../../src/capabilities/gen/tauri.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\n// GENERATED by dx-plugin — do not edit. Sliced from ../index.ts for the 'tauri' condition.\n\nimport * as AppCapability from '@dxos/app-toolkit/AppCapability';\n\nimport { meta } from '#meta';\nimport { translations } from '#translations';\n\nimport pluginSpec from '../../../PLUGIN.mdl?raw';\n\nexport const PluginAsset = AppCapability.pluginAsset({\n pluginId: meta.profile.key,\n path: 'PLUGIN.mdl',\n content: pluginSpec,\n mimeType: 'application/x-mdl',\n});\n\nexport const ReactSurface = AppCapability.surface(() => import('../react-surface.ts'), {\n roles: ['org.dxos.role.article'],\n});\n\nexport const Schema = AppCapability.schema(() => import('../schema.ts'));\n\nexport const Translations = AppCapability.translations(translations);\n"],"mappings":";;;;;AAaA,IAAa,cAAc,cAAc,YAAY;CACnD,UAAU,KAAK,QAAQ;CACvB,MAAM;CACN,SAAS;CACT,UAAU;AACZ,CAAC;AAED,IAAa,eAAe,cAAc,cAAc,OAAO,8BAAwB,EACrF,OAAO,CAAC,uBAAuB,EACjC,CAAC;AAED,IAAa,SAAS,cAAc,aAAa,OAAO,qBAAe;AAEvE,IAAa,eAAe,cAAc,aAAa,YAAY"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"capabilities.workerd.mjs","names":[],"sources":["../../src/capabilities/gen/workerd.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\n// GENERATED by dx-plugin — do not edit. Sliced from ../index.ts for the 'workerd' condition.\n\nimport * as AppCapability from '@dxos/app-toolkit/AppCapability';\n\nimport { translations } from '#translations';\n\nexport const Schema = AppCapability.schema(() => import('../schema'));\n\nexport const Translations = AppCapability.translations(translations);\n\nexport const PluginAsset = undefined;\nexport const ReactSurface = undefined;\n"],"mappings":";;;AAUA,IAAa,SAAS,cAAc,aAAa,OAAO,
|
|
1
|
+
{"version":3,"file":"capabilities.workerd.mjs","names":[],"sources":["../../src/capabilities/gen/workerd.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\n// GENERATED by dx-plugin — do not edit. Sliced from ../index.ts for the 'workerd' condition.\n\nimport * as AppCapability from '@dxos/app-toolkit/AppCapability';\n\nimport { translations } from '#translations';\n\nexport const Schema = AppCapability.schema(() => import('../schema.ts'));\n\nexport const Translations = AppCapability.translations(translations);\n\nexport const PluginAsset = undefined;\nexport const ReactSurface = undefined;\n"],"mappings":";;;AAUA,IAAa,SAAS,cAAc,aAAa,OAAO,qBAAe;AAEvE,IAAa,eAAe,cAAc,aAAa,YAAY;AAEnE,IAAa,cAAc,KAAA;AAC3B,IAAa,eAAe,KAAA"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
//#region PLUGIN.mdl?raw
|
|
2
|
+
var PLUGIN_default = "---\nid: org.dxos.plugin.stack\nname: StackPlugin\nversion: 0.1.0\n---\n\nCollections plugin for `DXOS` Composer — renders any `Collection` object as a vertically scrollable stack of collapsible sections, where each section displays an arbitrary ECHO object via the `section` surface role. Supports adding, removing, navigating, and collapsing individual sections.\n\n## Extensions\n\nThe following extension dialects are used in this document.\nEach extension is defined in the Appendix or resolved via its URI.\n\n| Term | URI |\n|-------------|--------------------------------|\n| `type` | `org.dxos.mdl.type@1.0` |\n| `feat` | `org.dxos.mdl.feat@1.0` |\n| `scenario` | `org.dxos.mdl.scenario@1.0` |\n| `component` | `org.dxos.mdl.component@1.0` |\n| `op` | `org.dxos.mdl.op@1.0` |\n| `test` | `org.dxos.mdl.test@1.0` |\n\n## Types\n\n```mdl\ntype SectionSchema\n fields:\n height?: number # explicit height override for the section\n custom?: Record<string, any> # view-instance-specific data (e.g. cover mode for images)\n```\n\n```mdl\ntype StackViewType\n typename: org.dxos.type.stackView\n version: 0.1.0\n fields:\n sections: Record<string, SectionSchema>\n```\n\n```mdl\ntype StackSectionView\n fields:\n title?: string\n size?: StackItemSize\n height?: number\n collapsed?: boolean\n custom?: Record<string, any>\n```\n\n```mdl\ntype StackSectionMetadata\n fields:\n icon?: string\n placeholder?: Label\n viewActions?: (item: CollectionItem) => StackSectionAction\n```\n\n```mdl\ntype StackSectionItem\n fields:\n id: string # DXN string for the contained object\n object: Obj.Unknown\n view: StackSectionView\n metadata: StackSectionMetadata\n```\n\n```mdl\ntype AddSectionPosition\n literals: before | after | beforeAll | afterAll\n```\n\n```mdl\ntype StackSettingsProps\n fields:\n separation: boolean # whether visual separators are shown between sections\n```\n\n## Components\n\n```mdl\ncomponent StackArticle\n desc: Full-page article view of a Collection — renders items as a vertical stack of StackSection components with a toolbar for adding sections.\n props:\n subject: Collection\n role: AppSurface.Role\n attendableId?: string\n state:\n collapsedSections: Record<string, boolean> # collapsed state by DXN string\n items: StackSectionItem[] # derived from collection objects\n slots:\n (none)\n actions:\n handleAdd(id: string, position: AddSectionPosition)\n handleDelete(id: string)\n handleNavigate(id: string)\n handleCollapse(id: string, collapsed: boolean)\n handleAddSection()\n emits:\n (none)\n layout: |\n ┌──────────────────────────────┐\n │ Toolbar [+ Add Section] │\n ├──────────────────────────────┤\n │ Stack (vertical, intrinsic) │\n │ ┌────────────────────────┐ │\n │ │ StackSection │ │\n │ │ ▾ [icon] Title [→] │ │\n │ │ └─ Surface:section │ │\n │ └────────────────────────┘ │\n │ ┌────────────────────────┐ │\n │ │ StackSection (collapsed│ │\n │ │ ▸ [icon] Title [↕] │ │\n │ └────────────────────────┘ │\n │ … │\n └──────────────────────────────┘\n```\n\n```mdl\ncomponent StackSection\n desc: A single collapsible section in the stack — shows a sigil icon button with a dropdown menu and delegates content rendering to the section surface slot.\n props:\n id: string\n object: Obj.Unknown\n view: StackSectionView\n metadata: StackSectionMetadata\n state:\n optionsMenuOpen: boolean\n attendableId: string # composed as parentAttendableId/object.id\n slots:\n content: ReactNode # rendered by Surface(type=section, subject=object)\n actions:\n navigate(id: string)\n add(id: string, position: AddSectionPosition)\n collapse(id: string, collapsed: boolean)\n delete(id: string)\n layout: |\n ┌─────────────────────────────────┐\n │ StackItem.Heading │\n │ [sigil▾] (sticky) [→ or ↕] │\n ├─────────────────────────────────┤\n │ CollapsibleContent │\n │ Surface type=section │\n └─────────────────────────────────┘\n```\n\n```mdl\ncomponent StackSettings\n desc: Settings panel for configuring stack-level display preferences such as section separation.\n props:\n settings: StackSettingsProps\n layout: |\n ┌─────────────────────────────┐\n │ Settings.Section │\n │ Separation [toggle] │\n └─────────────────────────────┘\n```\n\n## Features\n\n```mdl\nfeat F-1: Stack Rendering\n\n req F-1.1: StackPlugin registers a surface for the article role filtered to Collection objects.\n req F-1.2: StackArticle renders each item in the collection as a StackSection in document order.\n req F-1.3: Each StackSection title is derived from the object's title property or graph node label.\n req F-1.4: The icon displayed on the section sigil is taken from the object schema's IconAnnotation.\n```\n\n```mdl\nfeat F-2: Section Management\n\n req F-2.1:\n when: user clicks the Add Section button in the toolbar\n then: SpaceOperation.OpenObjectForm dialog is invoked with the collection as target\n req F-2.2:\n when: user selects \"Add Before\" or \"Add After\" from a section dropdown\n then: LayoutOperation.UpdateDialog is invoked with the AddSectionDialog, position, and collection context\n req F-2.3:\n when: user selects \"Remove\" from a section dropdown\n then: SpaceOperation.RemoveObjects is invoked; section is removed from the collection\n req F-2.4:\n when: user selects \"Navigate to\" from a collapsed section dropdown or the navigate button\n then: LayoutOperation.Open is invoked with the section's id\n```\n\n```mdl\nfeat F-3: Collapse / Expand\n\n req F-3.1: Each section can be individually collapsed via the dropdown menu or caret trigger.\n req F-3.2:\n when: section is expanded\n then: full Surface:section content is visible; navigate button shown in heading\n req F-3.3:\n when: section is collapsed\n then: only the title is shown in StackItem.Content; expand toggle shown in heading\n req F-3.4: Collapsed state is managed locally in StackArticle component state (not persisted).\n```\n\n```mdl\nfeat F-4: Settings\n\n req F-4.1: StackPlugin exposes a settings panel via the StackSettings component.\n req F-4.2: The separation setting controls whether visual separators appear between sections.\n```\n\n```mdl\nfeat F-5: Schema Registration\n\n req F-5.1: StackPlugin registers StackViewType with the ECHO schema module on activation.\n req F-5.2: StackViewType stores per-section metadata (height, custom data) keyed by object id.\n```\n\n## Acceptance\n\n```mdl\nscenario T-1: Collection renders as stack\n given: a Collection with three objects is opened in article role\n then:\n - StackArticle is displayed\n - three StackSection components are rendered in order\n - each section shows the object's title\n```\n\n```mdl\nscenario T-2: Add section via toolbar\n given: StackArticle is open\n when: user clicks the Add Section toolbar button\n then: SpaceOperation.OpenObjectForm is invoked with the collection as target\n```\n\n```mdl\nscenario T-3: Remove section\n given: StackArticle is open with at least one section\n when: user selects Remove from a section dropdown\n then:\n - SpaceOperation.RemoveObjects is invoked\n - section no longer appears in the stack\n```\n\n```mdl\nscenario T-4: Collapse section\n given: a section is expanded\n when: user selects Collapse from the section dropdown\n then:\n - section content is hidden\n - section title is shown in collapsed state\n - expand toggle is visible in heading\n```\n\n```mdl\nscenario T-5: Navigate to section\n given: StackArticle is open\n when: user clicks the navigate button on a section heading\n then: LayoutOperation.Open is invoked with the section's DXN id\n```\n\n```mdl\nscenario T-6: StackViewType registered\n given: StackPlugin is active\n then: StackViewType (typename org.dxos.type.stackView) is registered with the ECHO schema module\n```\n\n---\n\n## QA\n\nExecutable tests. Each step carries a human instruction (`do`) and, where the step maps to an\ninvocable operation, an agent binding (`invoke`). Report failures by test and step number.\n\n```mdl\ntest QA-1: Render a collection as a stack, add, collapse, and remove a section\n desc: |\n StackPlugin declares no operations of its own — every mutation goes through\n `SpaceOperation.AddObject`/`RemoveObjects` (F-2.1, F-2.3), which belong to `plugin-space`.\n actors: both\n covers: [F-1.1, F-1.2, F-2.3, F-3.1, T-1, T-3, T-4]\n status: unverified\n given:\n - an identity exists\n - space: a space is open\n - plugin-stack is enabled — it is OFF by default for everyone (not listed in\n `getDefaults`, unlike most content plugins in `plugin-defs.tsx`), so no `article` surface\n resolves for a Collection's stack view until it is turned on\n - no collection named \"QA Stack\" exists — ABORT rather than deleting one this test did not\n create\n steps:\n - name: Create the collection and a section\n do: In the navtree, click + on the space and choose Collection. Name it \"QA Stack\". Open\n it, click \"Add Section\" in the toolbar, and choose Markdown, naming it \"QA Section\".\n invoke: org.dxos.operation.space.createCollection { name: \"QA Stack\" }\n capture: collection\n expect: \"QA Stack\" opens as a StackArticle with one StackSection titled \"QA Section\"\n assert: return $collection.object.name === 'QA Stack';\n note: |\n Coalesce the \"Add Section\" click with the object creation it triggers — `OpenObjectForm`\n opens a dialog and the resulting object is added via `AddObject`, which is the same\n pattern as `plugin-markdown`'s create+place split.\n - name: Add the section object\n do: (the Add Section dialog places it for you on confirm)\n invoke: org.dxos.operation.markdown.create { name: \"QA Section\" }\n capture: doc\n expect: a Document named \"QA Section\" exists\n - name: Place the section in the stack\n do: (as above)\n invoke: org.dxos.operation.space.addObject { object: $doc.object, target: $collection.object }\n expect: a StackSection titled \"QA Section\" now renders below the toolbar (F-1.2)\n assert: return $collection.object.objects.some((ref) => ref.target?.id === $doc.object.id);\n - name: Collapse the section\n do: Open the section's sigil dropdown and choose Collapse.\n expect: the section shows only its title; the caret points to \"expand\" (F-3.3, T-4)\n note: NO invoke — collapse state is local StackArticle component state (F-3.4), not an\n ECHO write, so there is nothing to verify against the database.\n - name: Remove the section\n do: Open the dropdown again and choose Remove.\n invoke: org.dxos.operation.space.removeObjects { objects: [$doc.object], target: $collection.object }\n expect: the section no longer appears in the stack (T-3)\n assert: return !$collection.object.objects.some((ref) => ref.target?.id === $doc.object.id);\n after:\n - name: Delete the collection\n do: Right-click \"QA Stack\" in the navtree and choose Delete.\n invoke: org.dxos.operation.space.removeObjects { objects: [$collection.object], target: $given.space }\n expect: the row leaves the navtree and its plank closes\n```\n\n---\n\n## Appendix: Extension Definitions\n\n```mdl\next type\n uri: org.dxos.mdl.type@1.0\n desc: A named data structure with typed fields and optional literals.\n fields:\n desc?: Prose\n fields?: FieldMap\n literals?: UnionList\n extends?: TypeRef[]\n```\n\n```mdl\next feat\n uri: org.dxos.mdl.feat@1.0\n desc: A named feature grouping one or more requirements.\n fields:\n desc?: Prose\n req: RequirementList\n nesting: self\n```\n\n```mdl\next scenario\n uri: org.dxos.mdl.scenario@1.0\n desc: An acceptance scenario expressed as given / when / then steps.\n fields:\n given?: Step | Step[]\n when?: Step | Step[]\n then: Step | Step[]\n tags?: TagList\n```\n\n```mdl\next component\n uri: org.dxos.mdl.component@1.0\n desc: A UI component with props, internal state, slots, actions, and events.\n fields:\n desc?: Prose\n props?: FieldMap\n state?: FieldMap\n slots?: FieldMap\n actions?: ActionMap\n emits?: EventMap\n layout?: CodeBlock\n```\n\n```mdl\next op\n uri: org.dxos.mdl.op@1.0\n desc: |\n A named operation with typed inputs, outputs, and declared errors.\n Pure ops have no effects or requires. Effectful ops declare both.\n fields:\n desc?: Prose\n input?: FieldMap\n output?: TypeExpr\n errors?: ErrorMap\n effects?: EffectList\n requires?: ServiceList\n note?: Prose\n```\n";
|
|
3
|
+
//#endregion
|
|
4
|
+
export { PLUGIN_default as t };
|
|
5
|
+
|
|
6
|
+
//# sourceMappingURL=chunk-PLUGIN.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chunk-PLUGIN.mjs","names":[],"sources":[],"mappings":""}
|
|
@@ -1,20 +1,23 @@
|
|
|
1
1
|
import { meta } from "#meta";
|
|
2
2
|
import { useCallback, useId, useMemo, useState } from "react";
|
|
3
|
-
import { useOperationInvoker } from "@dxos/app-framework/ui";
|
|
4
3
|
import { Obj } from "@dxos/echo";
|
|
5
|
-
import { Panel, Toolbar, useTranslation } from "@dxos/react-ui";
|
|
6
4
|
import { Mosaic } from "@dxos/react-ui-mosaic";
|
|
5
|
+
import * as UiHooks from "@dxos/react-ui/Hooks";
|
|
7
6
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
8
7
|
import { arrayMove, isNonNullable } from "@dxos/util";
|
|
9
8
|
import { useAtomValue } from "@effect/atom-react/Hooks";
|
|
10
|
-
import * as Atom from "effect/
|
|
9
|
+
import * as Atom from "effect/reactivity/Atom";
|
|
10
|
+
import * as Hooks from "@dxos/app-framework/Hooks";
|
|
11
11
|
import * as SpaceOperation from "@dxos/plugin-space/SpaceOperation";
|
|
12
|
-
import {
|
|
12
|
+
import { ActionMenu, createMenuAction } from "@dxos/react-ui-menu";
|
|
13
|
+
import * as Button from "@dxos/react-ui/Button";
|
|
14
|
+
import * as Panel from "@dxos/react-ui/Panel";
|
|
15
|
+
import * as Toolbar from "@dxos/react-ui/Toolbar";
|
|
13
16
|
import { Stack } from "#components";
|
|
14
17
|
//#region src/containers/StackArticle/StackArticle.tsx
|
|
15
18
|
var StackArticle = ({ attendableId, subject: collection }) => {
|
|
16
|
-
const { invokePromise } = useOperationInvoker();
|
|
17
|
-
const { t } = useTranslation(meta.profile.key);
|
|
19
|
+
const { invokePromise } = Hooks.useOperationInvoker();
|
|
20
|
+
const { t } = UiHooks.useTranslation(meta.profile.key);
|
|
18
21
|
const [collapsedSections, setCollapsedSections] = useState({});
|
|
19
22
|
const collectionObjects = useAtomValue(createCollectionObjects(collection));
|
|
20
23
|
const items = useMemo(() => collectionObjects.map((object) => ({
|
|
@@ -98,13 +101,12 @@ var StackArticle = ({ attendableId, subject: collection }) => {
|
|
|
98
101
|
target: collection,
|
|
99
102
|
navigable: false
|
|
100
103
|
}), [collection, invokePromise]);
|
|
101
|
-
return /* @__PURE__ */ jsxs(Panel.Root, { children: [/* @__PURE__ */ jsx(Panel.
|
|
104
|
+
return /* @__PURE__ */ jsxs(Panel.Root, { children: [/* @__PURE__ */ jsx(Panel.Header, {
|
|
102
105
|
classNames: "dx-toolbar-surface",
|
|
103
106
|
children: /* @__PURE__ */ jsxs(Toolbar.Root, {
|
|
104
107
|
classNames: "dx-document",
|
|
105
108
|
children: [
|
|
106
|
-
/* @__PURE__ */ jsx(
|
|
107
|
-
square: true,
|
|
109
|
+
/* @__PURE__ */ jsx(Button.Root, {
|
|
108
110
|
icon: "ph--plus--regular",
|
|
109
111
|
iconOnly: true,
|
|
110
112
|
label: t("add-section.label"),
|
|
@@ -112,19 +114,18 @@ var StackArticle = ({ attendableId, subject: collection }) => {
|
|
|
112
114
|
onClick: handleAddSection
|
|
113
115
|
}),
|
|
114
116
|
/* @__PURE__ */ jsx(Toolbar.Separator, {}),
|
|
115
|
-
/* @__PURE__ */
|
|
116
|
-
|
|
117
|
-
children: /* @__PURE__ */ jsx(
|
|
118
|
-
square: true,
|
|
117
|
+
/* @__PURE__ */ jsx(ActionMenu, {
|
|
118
|
+
actions: optionsMenu,
|
|
119
|
+
children: /* @__PURE__ */ jsx(Button.Root, {
|
|
119
120
|
icon: "ph--dots-three-vertical--regular",
|
|
120
121
|
iconOnly: true,
|
|
121
122
|
label: t("options.label"),
|
|
122
123
|
"data-testid": "stack.options"
|
|
123
124
|
})
|
|
124
|
-
})
|
|
125
|
+
})
|
|
125
126
|
]
|
|
126
127
|
})
|
|
127
|
-
}), /* @__PURE__ */ jsx(Panel.
|
|
128
|
+
}), /* @__PURE__ */ jsx(Panel.Body, { children: /* @__PURE__ */ jsx(Stack.Root, {
|
|
128
129
|
id: Obj.getURI(collection),
|
|
129
130
|
attendableId,
|
|
130
131
|
collapsed,
|
|
@@ -135,8 +136,6 @@ var StackArticle = ({ attendableId, subject: collection }) => {
|
|
|
135
136
|
onMoveDown: handleMoveDown,
|
|
136
137
|
onDelete: handleDelete,
|
|
137
138
|
children: /* @__PURE__ */ jsx(Stack.Content, {
|
|
138
|
-
centered: true,
|
|
139
|
-
padding: true,
|
|
140
139
|
"data-testid": "main.stack",
|
|
141
140
|
children: /* @__PURE__ */ jsx(Stack.Viewport, { children: /* @__PURE__ */ jsx(Mosaic.Stack, {
|
|
142
141
|
classNames: "dx-document",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chunk-StackArticle.mjs","names":[],"sources":["../../src/containers/StackArticle/StackArticle.tsx"],"sourcesContent":["//\n// Copyright 2023 DXOS.org\n//\n\nimport { useAtomValue } from '@effect/atom-react/Hooks';\nimport * as Atom from 'effect/unstable/reactivity/Atom';\nimport React, { useCallback, useId, useMemo, useState } from 'react';\n\nimport { useOperationInvoker } from '@dxos/app-framework/ui';\nimport { type AppSurface } from '@dxos/app-toolkit/ui';\nimport { type Collection, Obj } from '@dxos/echo';\nimport * as SpaceOperation from '@dxos/plugin-space/SpaceOperation';\nimport { Panel, Toolbar, useTranslation } from '@dxos/react-ui';\nimport { type DndContainerHandler } from '@dxos/react-ui-dnd';\nimport { Menu, createMenuAction } from '@dxos/react-ui-menu';\nimport { Mosaic } from '@dxos/react-ui-mosaic';\nimport { arrayMove, isNonNullable } from '@dxos/util';\n\nimport { Stack, type StackSectionItem } from '#components';\nimport { meta } from '#meta';\n\nexport type StackArticleProps = AppSurface.ObjectArticleProps<Collection.Collection>;\n\nexport const StackArticle = ({ attendableId, subject: collection }: StackArticleProps) => {\n const { invokePromise } = useOperationInvoker();\n const { t } = useTranslation(meta.profile.key);\n const [collapsedSections, setCollapsedSections] = useState<Record<string, boolean>>({});\n\n const collectionObjects = useAtomValue(createCollectionObjects(collection));\n const items = useMemo<StackSectionItem[]>(\n () => collectionObjects.map((object) => ({ id: Obj.getURI(object), object })),\n [collectionObjects],\n );\n\n const collapsed = useMemo<ReadonlySet<string>>(\n () => new Set(Object.keys(collapsedSections).filter((id) => collapsedSections[id])),\n [collapsedSections],\n );\n\n // Index of a section within the collection by its object URI.\n const findIndex = useCallback(\n (id: string) => collection.objects.findIndex((ref) => ref.target != null && Obj.getURI(ref.target) === id),\n [collection],\n );\n\n // Per-instance discriminator so the same collection opened in two planks doesn't collide in the Mosaic registry.\n const instanceId = useId();\n\n // Reorder sections in place. Placeholder/tile drop locations are 1-based with half-step placeholders\n // between tiles, so the floor of the drop location is the destination array index (see Mosaic.Stack).\n const eventHandler = useMemo<DndContainerHandler<StackSectionItem>>(\n () => ({\n id: `${Obj.getURI(collection)}:${instanceId}`,\n canDrop: ({ source }) =>\n collection.objects.some((ref) => ref.target != null && Obj.getURI(ref.target) === source.id),\n onDrop: ({ source, target }) => {\n const to =\n target?.type === 'tile' || target?.type === 'placeholder'\n ? target.location\n : target?.type === 'container'\n ? collection.objects.length\n : -1;\n const insert = typeof to === 'number' && to >= 0 ? Math.floor(to) : -1;\n if (insert < 0) {\n return;\n }\n\n Obj.update(collection, (collection) => {\n const from = findIndex(source.id);\n if (from !== -1) {\n arrayMove(collection.objects, from, insert);\n }\n });\n },\n }),\n [collection, findIndex, instanceId],\n );\n\n const handleMoveUp = useCallback(\n (id: string) => {\n const index = findIndex(id);\n if (index > 0) {\n Obj.update(collection, (collection) => {\n const [ref] = collection.objects.splice(index, 1);\n collection.objects.splice(index - 1, 0, ref);\n });\n }\n },\n [collection, findIndex],\n );\n\n const handleMoveDown = useCallback(\n (id: string) => {\n const index = findIndex(id);\n if (index >= 0 && index < collection.objects.length - 1) {\n Obj.update(collection, (collection) => {\n const [ref] = collection.objects.splice(index, 1);\n collection.objects.splice(index + 1, 0, ref);\n });\n }\n },\n [collection, findIndex],\n );\n\n const handleDelete = useCallback(\n (id: string) => {\n const index = findIndex(id);\n if (index >= 0) {\n Obj.update(collection, (collection) => {\n collection.objects.splice(index, 1);\n });\n }\n },\n [collection, findIndex],\n );\n\n const handleAdd = useCallback(\n async (id: string) => {\n const { data } = await invokePromise(SpaceOperation.OpenObjectForm, {\n target: collection,\n navigable: false,\n });\n const object = data?.target;\n if (!object) {\n return;\n }\n\n // The created object is appended; move it to immediately after the originating section.\n const from = findIndex(Obj.getURI(object));\n const anchor = findIndex(id);\n if (from >= 0 && anchor >= 0) {\n Obj.update(collection, (collection) => {\n const [ref] = collection.objects.splice(from, 1);\n collection.objects.splice(anchor < from ? anchor + 1 : anchor, 0, ref);\n });\n }\n },\n [collection, invokePromise, findIndex],\n );\n\n const handleCollapse = useCallback(\n (id: string, value: boolean) => setCollapsedSections((prev) => ({ ...prev, [id]: value })),\n [],\n );\n\n const handleCollapseAll = useCallback(\n () => setCollapsedSections(Object.fromEntries(collectionObjects.map((object) => [Obj.getURI(object), true]))),\n [collectionObjects],\n );\n\n const handleExpandAll = useCallback(() => setCollapsedSections({}), []);\n\n const optionsMenu = useMemo(\n () => [\n createMenuAction('collapse-all', handleCollapseAll, {\n label: ['collapse-all.label', { ns: meta.profile.key }],\n icon: 'ph--arrows-in-line-vertical--regular',\n testId: 'stack.collapse-all',\n }),\n createMenuAction('expand-all', handleExpandAll, {\n label: ['expand-all.label', { ns: meta.profile.key }],\n icon: 'ph--arrows-out-line-vertical--regular',\n testId: 'stack.expand-all',\n }),\n ],\n [handleCollapseAll, handleExpandAll],\n );\n\n const handleAddSection = useCallback(\n () =>\n invokePromise(SpaceOperation.OpenObjectForm, {\n target: collection,\n navigable: false,\n }),\n [collection, invokePromise],\n );\n\n return (\n <Panel.Root>\n <Panel.Toolbar classNames='dx-toolbar-surface'>\n <Toolbar.Root classNames='dx-document'>\n <Toolbar.IconButton\n square\n icon='ph--plus--regular'\n iconOnly\n label={t('add-section.label')}\n data-testid='stack.addSection'\n onClick={handleAddSection}\n />\n <Toolbar.Separator />\n <Menu.Root>\n <Menu.Trigger asChild>\n <Toolbar.IconButton\n square\n icon='ph--dots-three-vertical--regular'\n iconOnly\n label={t('options.label')}\n data-testid='stack.options'\n />\n </Menu.Trigger>\n <Menu.Content items={optionsMenu} />\n </Menu.Root>\n </Toolbar.Root>\n </Panel.Toolbar>\n <Panel.Content>\n <Stack.Root\n id={Obj.getURI(collection)}\n attendableId={attendableId}\n collapsed={collapsed}\n eventHandler={eventHandler}\n onCollapse={handleCollapse}\n onAdd={handleAdd}\n onMoveUp={handleMoveUp}\n onMoveDown={handleMoveDown}\n onDelete={handleDelete}\n >\n <Stack.Content centered padding data-testid='main.stack'>\n <Stack.Viewport>\n <Mosaic.Stack classNames='dx-document' items={items} getId={getId} Tile={Stack.Section} />\n </Stack.Viewport>\n </Stack.Content>\n </Stack.Root>\n </Panel.Content>\n </Panel.Root>\n );\n};\n\nconst getId = (item: StackSectionItem) => item.id;\n\nconst createCollectionObjects = Atom.family((collection: Collection.Collection) =>\n Atom.make((get) => {\n const snapshot = get(Obj.atom(collection));\n return snapshot.objects.map((ref) => get(Obj.atomReactive(ref))).filter(isNonNullable);\n }),\n);\n\nStackArticle.displayName = 'StackArticle';\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"chunk-StackArticle.mjs","names":[],"sources":["../../src/containers/StackArticle/StackArticle.tsx"],"sourcesContent":["//\n// Copyright 2023 DXOS.org\n//\n\nimport { useAtomValue } from '@effect/atom-react/Hooks';\nimport * as Atom from 'effect/reactivity/Atom';\nimport React, { useCallback, useId, useMemo, useState } from 'react';\n\nimport * as Hooks from '@dxos/app-framework/Hooks';\nimport type * as AppSurface from '@dxos/app-toolkit/AppSurface';\nimport { type Collection, Obj } from '@dxos/echo';\nimport * as SpaceOperation from '@dxos/plugin-space/SpaceOperation';\nimport { type DndContainerHandler } from '@dxos/react-ui-dnd';\nimport { ActionMenu, createMenuAction } from '@dxos/react-ui-menu';\nimport { Mosaic } from '@dxos/react-ui-mosaic';\nimport * as Button from '@dxos/react-ui/Button';\nimport * as UiHooks from '@dxos/react-ui/Hooks';\nimport * as Panel from '@dxos/react-ui/Panel';\nimport * as Toolbar from '@dxos/react-ui/Toolbar';\nimport { arrayMove, isNonNullable } from '@dxos/util';\n\nimport { Stack, type StackSectionItem } from '#components';\nimport { meta } from '#meta';\n\nexport type StackArticleProps = AppSurface.ObjectArticleProps<Collection.Collection>;\n\nexport const StackArticle = ({ attendableId, subject: collection }: StackArticleProps) => {\n const { invokePromise } = Hooks.useOperationInvoker();\n const { t } = UiHooks.useTranslation(meta.profile.key);\n const [collapsedSections, setCollapsedSections] = useState<Record<string, boolean>>({});\n\n const collectionObjects = useAtomValue(createCollectionObjects(collection));\n const items = useMemo<StackSectionItem[]>(\n () => collectionObjects.map((object) => ({ id: Obj.getURI(object), object })),\n [collectionObjects],\n );\n\n const collapsed = useMemo<ReadonlySet<string>>(\n () => new Set(Object.keys(collapsedSections).filter((id) => collapsedSections[id])),\n [collapsedSections],\n );\n\n // Index of a section within the collection by its object URI.\n const findIndex = useCallback(\n (id: string) => collection.objects.findIndex((ref) => ref.target != null && Obj.getURI(ref.target) === id),\n [collection],\n );\n\n // Per-instance discriminator so the same collection opened in two planks doesn't collide in the Mosaic registry.\n const instanceId = useId();\n\n // Reorder sections in place. Placeholder/tile drop locations are 1-based with half-step placeholders\n // between tiles, so the floor of the drop location is the destination array index (see Mosaic.Stack).\n const eventHandler = useMemo<DndContainerHandler<StackSectionItem>>(\n () => ({\n id: `${Obj.getURI(collection)}:${instanceId}`,\n canDrop: ({ source }) =>\n collection.objects.some((ref) => ref.target != null && Obj.getURI(ref.target) === source.id),\n onDrop: ({ source, target }) => {\n const to =\n target?.type === 'tile' || target?.type === 'placeholder'\n ? target.location\n : target?.type === 'container'\n ? collection.objects.length\n : -1;\n const insert = typeof to === 'number' && to >= 0 ? Math.floor(to) : -1;\n if (insert < 0) {\n return;\n }\n\n Obj.update(collection, (collection) => {\n const from = findIndex(source.id);\n if (from !== -1) {\n arrayMove(collection.objects, from, insert);\n }\n });\n },\n }),\n [collection, findIndex, instanceId],\n );\n\n const handleMoveUp = useCallback(\n (id: string) => {\n const index = findIndex(id);\n if (index > 0) {\n Obj.update(collection, (collection) => {\n const [ref] = collection.objects.splice(index, 1);\n collection.objects.splice(index - 1, 0, ref);\n });\n }\n },\n [collection, findIndex],\n );\n\n const handleMoveDown = useCallback(\n (id: string) => {\n const index = findIndex(id);\n if (index >= 0 && index < collection.objects.length - 1) {\n Obj.update(collection, (collection) => {\n const [ref] = collection.objects.splice(index, 1);\n collection.objects.splice(index + 1, 0, ref);\n });\n }\n },\n [collection, findIndex],\n );\n\n const handleDelete = useCallback(\n (id: string) => {\n const index = findIndex(id);\n if (index >= 0) {\n Obj.update(collection, (collection) => {\n collection.objects.splice(index, 1);\n });\n }\n },\n [collection, findIndex],\n );\n\n const handleAdd = useCallback(\n async (id: string) => {\n const { data } = await invokePromise(SpaceOperation.OpenObjectForm, {\n target: collection,\n navigable: false,\n });\n const object = data?.target;\n if (!object) {\n return;\n }\n\n // The created object is appended; move it to immediately after the originating section.\n const from = findIndex(Obj.getURI(object));\n const anchor = findIndex(id);\n if (from >= 0 && anchor >= 0) {\n Obj.update(collection, (collection) => {\n const [ref] = collection.objects.splice(from, 1);\n collection.objects.splice(anchor < from ? anchor + 1 : anchor, 0, ref);\n });\n }\n },\n [collection, invokePromise, findIndex],\n );\n\n const handleCollapse = useCallback(\n (id: string, value: boolean) => setCollapsedSections((prev) => ({ ...prev, [id]: value })),\n [],\n );\n\n const handleCollapseAll = useCallback(\n () => setCollapsedSections(Object.fromEntries(collectionObjects.map((object) => [Obj.getURI(object), true]))),\n [collectionObjects],\n );\n\n const handleExpandAll = useCallback(() => setCollapsedSections({}), []);\n\n const optionsMenu = useMemo(\n () => [\n createMenuAction('collapse-all', handleCollapseAll, {\n label: ['collapse-all.label', { ns: meta.profile.key }],\n icon: 'ph--arrows-in-line-vertical--regular',\n testId: 'stack.collapse-all',\n }),\n createMenuAction('expand-all', handleExpandAll, {\n label: ['expand-all.label', { ns: meta.profile.key }],\n icon: 'ph--arrows-out-line-vertical--regular',\n testId: 'stack.expand-all',\n }),\n ],\n [handleCollapseAll, handleExpandAll],\n );\n\n const handleAddSection = useCallback(\n () =>\n invokePromise(SpaceOperation.OpenObjectForm, {\n target: collection,\n navigable: false,\n }),\n [collection, invokePromise],\n );\n\n return (\n <Panel.Root>\n <Panel.Header classNames='dx-toolbar-surface'>\n <Toolbar.Root classNames='dx-document'>\n <Button.Root\n icon='ph--plus--regular'\n iconOnly\n label={t('add-section.label')}\n data-testid='stack.addSection'\n onClick={handleAddSection}\n />\n <Toolbar.Separator />\n <ActionMenu actions={optionsMenu}>\n <Button.Root\n icon='ph--dots-three-vertical--regular'\n iconOnly\n label={t('options.label')}\n data-testid='stack.options'\n />\n </ActionMenu>\n </Toolbar.Root>\n </Panel.Header>\n <Panel.Body>\n <Stack.Root\n id={Obj.getURI(collection)}\n attendableId={attendableId}\n collapsed={collapsed}\n eventHandler={eventHandler}\n onCollapse={handleCollapse}\n onAdd={handleAdd}\n onMoveUp={handleMoveUp}\n onMoveDown={handleMoveDown}\n onDelete={handleDelete}\n >\n <Stack.Content data-testid='main.stack'>\n <Stack.Viewport>\n <Mosaic.Stack classNames='dx-document' items={items} getId={getId} Tile={Stack.Section} />\n </Stack.Viewport>\n </Stack.Content>\n </Stack.Root>\n </Panel.Body>\n </Panel.Root>\n );\n};\n\nconst getId = (item: StackSectionItem) => item.id;\n\nconst createCollectionObjects = Atom.family((collection: Collection.Collection) =>\n Atom.make((get) => {\n const snapshot = get(Obj.atom(collection));\n return snapshot.objects.map((ref) => get(Obj.atomReactive(ref))).filter(isNonNullable);\n }),\n);\n\nStackArticle.displayName = 'StackArticle';\n"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
1
|
+
import * as Surface from "@dxos/app-framework/Surface";
|
|
2
|
+
import * as AppSurface from "@dxos/app-toolkit/AppSurface";
|
|
3
3
|
import { Collection } from "@dxos/echo";
|
|
4
4
|
import * as Effect from "effect/Effect";
|
|
5
5
|
import * as Capabilities from "@dxos/app-framework/Capabilities";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chunk-react-surface.mjs","names":[],"sources":["../../src/capabilities/react-surface.ts"],"sourcesContent":["//\n// Copyright 2025 DXOS.org\n//\n\nimport * as Effect from 'effect/Effect';\n\nimport * as Capabilities from '@dxos/app-framework/Capabilities';\nimport * as Capability from '@dxos/app-framework/Capability';\nimport
|
|
1
|
+
{"version":3,"file":"chunk-react-surface.mjs","names":[],"sources":["../../src/capabilities/react-surface.ts"],"sourcesContent":["//\n// Copyright 2025 DXOS.org\n//\n\nimport * as Effect from 'effect/Effect';\n\nimport * as Capabilities from '@dxos/app-framework/Capabilities';\nimport * as Capability from '@dxos/app-framework/Capability';\nimport * as Surface from '@dxos/app-framework/Surface';\nimport * as AppSurface from '@dxos/app-toolkit/AppSurface';\nimport { Collection } from '@dxos/echo';\n\nimport { StackArticle } from '#containers';\n\nexport default Capability.makeModule(() =>\n Effect.succeed(\n Capability.contribute(\n Capabilities.ReactSurface,\n Surface.create({\n id: 'article',\n filter: AppSurface.object(AppSurface.Article, Collection.Collection),\n component: StackArticle,\n props: ({ role, data: { subject, attendableId } }) => ({ role, subject, attendableId }),\n }),\n ),\n ),\n);\n"],"mappings":";;;;;;;;AAcA,IAAA,wBAAe,WAAW,iBACxB,OAAO,QACL,WAAW,WACT,aAAa,cACb,QAAQ,OAAO;CACb,IAAI;CACJ,QAAQ,WAAW,OAAO,WAAW,SAAS,WAAW,UAAU;CACnE,WAAW;CACX,QAAQ,EAAE,MAAM,MAAM,EAAE,SAAS,sBAAsB;EAAE;EAAM;EAAS;CAAa;AACvF,CAAC,CACH,CACF,CACF"}
|
package/dist/lib/components.mjs
CHANGED
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
import { meta } from "#meta";
|
|
2
2
|
import { createContext, forwardRef, useCallback, useContext, useMemo, useState } from "react";
|
|
3
|
-
import
|
|
3
|
+
import * as Surface from "@dxos/app-framework/Surface";
|
|
4
|
+
import * as AppSurface from "@dxos/app-toolkit/AppSurface";
|
|
5
|
+
import * as AttentionSigil from "@dxos/app-toolkit/AttentionSigil";
|
|
4
6
|
import * as GraphPath from "@dxos/app-toolkit/GraphPath";
|
|
5
|
-
import { AppSurface, AttentionSigilButton } from "@dxos/app-toolkit/ui";
|
|
6
7
|
import { Obj } from "@dxos/echo";
|
|
7
|
-
import { DropdownMenu, Icon, ScrollArea, useTranslation } from "@dxos/react-ui";
|
|
8
8
|
import { useAttentionAttributes } from "@dxos/react-ui-attention";
|
|
9
9
|
import { Mosaic } from "@dxos/react-ui-mosaic";
|
|
10
|
+
import * as Hooks from "@dxos/react-ui/Hooks";
|
|
11
|
+
import * as Icon from "@dxos/react-ui/Icon";
|
|
12
|
+
import * as Menu from "@dxos/react-ui/Menu";
|
|
13
|
+
import * as ScrollArea from "@dxos/react-ui/ScrollArea";
|
|
10
14
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
11
15
|
//#region src/components/Stack/StackContext.ts
|
|
12
16
|
var StackContext = createContext(void 0);
|
|
@@ -94,7 +98,7 @@ var DragHandleGlyph = () => /* @__PURE__ */ jsx("svg", {
|
|
|
94
98
|
height: 16,
|
|
95
99
|
viewBox: "0 0 10 16",
|
|
96
100
|
"aria-hidden": true,
|
|
97
|
-
className: "shrink-0 text-
|
|
101
|
+
className: "shrink-0 text-fg-muted",
|
|
98
102
|
children: [
|
|
99
103
|
3,
|
|
100
104
|
8,
|
|
@@ -108,7 +112,7 @@ var DragHandleGlyph = () => /* @__PURE__ */ jsx("svg", {
|
|
|
108
112
|
});
|
|
109
113
|
var StackSection = ({ data, ...tileProps }) => {
|
|
110
114
|
const { id, object } = data;
|
|
111
|
-
const { t } = useTranslation(meta.profile.key);
|
|
115
|
+
const { t } = Hooks.useTranslation(meta.profile.key);
|
|
112
116
|
const { attendableId: parentAttendableId, collapsed, onAdd, onMoveUp, onMoveDown, onCollapse, onDelete } = useStack();
|
|
113
117
|
const [optionsMenuOpen, setOptionsMenuOpen] = useState(false);
|
|
114
118
|
const attendableId = GraphPath.getCollectionObjectPath(parentAttendableId, object.id);
|
|
@@ -124,70 +128,76 @@ var StackSection = ({ data, ...tileProps }) => {
|
|
|
124
128
|
className: "grid grid-rows-[min-content_1fr]",
|
|
125
129
|
children: [/* @__PURE__ */ jsx("div", {
|
|
126
130
|
className: "p-1 dx-toolbar-surface",
|
|
127
|
-
children: /* @__PURE__ */ jsxs(
|
|
131
|
+
children: /* @__PURE__ */ jsxs(Menu.Root, {
|
|
128
132
|
open: optionsMenuOpen,
|
|
129
|
-
onOpenChange: setOptionsMenuOpen,
|
|
130
|
-
children: [/* @__PURE__ */ jsx(
|
|
133
|
+
onOpenChange: ({ open }) => setOptionsMenuOpen(open),
|
|
134
|
+
children: [/* @__PURE__ */ jsx(Menu.Trigger, {
|
|
131
135
|
asChild: true,
|
|
132
|
-
children: /* @__PURE__ */ jsx(
|
|
136
|
+
children: /* @__PURE__ */ jsx(AttentionSigil.Button, {
|
|
133
137
|
size: "md",
|
|
134
138
|
attendableId,
|
|
135
|
-
children: /* @__PURE__ */ jsx(Icon, {
|
|
139
|
+
children: /* @__PURE__ */ jsx(Icon.Icon, {
|
|
136
140
|
icon,
|
|
137
141
|
classNames: "transition-opacity"
|
|
138
142
|
})
|
|
139
143
|
})
|
|
140
|
-
}), /* @__PURE__ */
|
|
141
|
-
isCollapsed ? /* @__PURE__ */
|
|
144
|
+
}), /* @__PURE__ */ jsxs(Menu.Content, { children: [
|
|
145
|
+
isCollapsed ? /* @__PURE__ */ jsx(Menu.Item, {
|
|
146
|
+
item: {
|
|
147
|
+
value: "section.expand",
|
|
148
|
+
label: t("expand.label"),
|
|
149
|
+
icon: "ph--arrows-out-line-vertical--regular"
|
|
150
|
+
},
|
|
142
151
|
onClick: () => onCollapse(id, false),
|
|
143
|
-
"data-testid": "section.expand"
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
152
|
+
"data-testid": "section.expand"
|
|
153
|
+
}) : /* @__PURE__ */ jsx(Menu.Item, {
|
|
154
|
+
item: {
|
|
155
|
+
value: "section.collapse",
|
|
156
|
+
label: t("collapse.label"),
|
|
157
|
+
icon: "ph--arrows-in-line-vertical--regular"
|
|
158
|
+
},
|
|
149
159
|
onClick: () => onCollapse(id, true),
|
|
150
|
-
"data-testid": "section.collapse"
|
|
151
|
-
children: [/* @__PURE__ */ jsx(Icon, { icon: "ph--arrows-in-line-vertical--regular" }), /* @__PURE__ */ jsx("span", {
|
|
152
|
-
className: "ms-2 grow",
|
|
153
|
-
children: t("collapse.label")
|
|
154
|
-
})]
|
|
160
|
+
"data-testid": "section.collapse"
|
|
155
161
|
}),
|
|
156
|
-
/* @__PURE__ */ jsx(
|
|
157
|
-
/* @__PURE__ */
|
|
162
|
+
/* @__PURE__ */ jsx(Menu.Separator, {}),
|
|
163
|
+
/* @__PURE__ */ jsx(Menu.Item, {
|
|
164
|
+
item: {
|
|
165
|
+
value: "section.add",
|
|
166
|
+
label: t("add-section.label"),
|
|
167
|
+
icon: "ph--plus--regular"
|
|
168
|
+
},
|
|
158
169
|
onClick: () => onAdd(id),
|
|
159
|
-
"data-testid": "section.add"
|
|
160
|
-
children: [/* @__PURE__ */ jsx(Icon, { icon: "ph--plus--regular" }), /* @__PURE__ */ jsx("span", {
|
|
161
|
-
className: "ms-2 grow",
|
|
162
|
-
children: t("add-section.label")
|
|
163
|
-
})]
|
|
170
|
+
"data-testid": "section.add"
|
|
164
171
|
}),
|
|
165
|
-
/* @__PURE__ */
|
|
172
|
+
/* @__PURE__ */ jsx(Menu.Item, {
|
|
173
|
+
item: {
|
|
174
|
+
value: "section.move-up",
|
|
175
|
+
label: t("move-up.label"),
|
|
176
|
+
icon: "ph--arrow-line-up--regular"
|
|
177
|
+
},
|
|
166
178
|
onClick: () => onMoveUp(id),
|
|
167
|
-
"data-testid": "section.move-up"
|
|
168
|
-
children: [/* @__PURE__ */ jsx(Icon, { icon: "ph--arrow-line-up--regular" }), /* @__PURE__ */ jsx("span", {
|
|
169
|
-
className: "ms-2 grow",
|
|
170
|
-
children: t("move-up.label")
|
|
171
|
-
})]
|
|
179
|
+
"data-testid": "section.move-up"
|
|
172
180
|
}),
|
|
173
|
-
/* @__PURE__ */
|
|
181
|
+
/* @__PURE__ */ jsx(Menu.Item, {
|
|
182
|
+
item: {
|
|
183
|
+
value: "section.move-down",
|
|
184
|
+
label: t("move-down.label"),
|
|
185
|
+
icon: "ph--arrow-line-down--regular"
|
|
186
|
+
},
|
|
174
187
|
onClick: () => onMoveDown(id),
|
|
175
|
-
"data-testid": "section.move-down"
|
|
176
|
-
children: [/* @__PURE__ */ jsx(Icon, { icon: "ph--arrow-line-down--regular" }), /* @__PURE__ */ jsx("span", {
|
|
177
|
-
className: "ms-2 grow",
|
|
178
|
-
children: t("move-down.label")
|
|
179
|
-
})]
|
|
188
|
+
"data-testid": "section.move-down"
|
|
180
189
|
}),
|
|
181
|
-
/* @__PURE__ */ jsx(
|
|
182
|
-
/* @__PURE__ */
|
|
190
|
+
/* @__PURE__ */ jsx(Menu.Separator, {}),
|
|
191
|
+
/* @__PURE__ */ jsx(Menu.Item, {
|
|
192
|
+
item: {
|
|
193
|
+
value: "section.remove",
|
|
194
|
+
label: t("remove-section.label"),
|
|
195
|
+
icon: "ph--trash--regular"
|
|
196
|
+
},
|
|
183
197
|
onClick: () => onDelete(id),
|
|
184
|
-
"data-testid": "section.remove"
|
|
185
|
-
children: [/* @__PURE__ */ jsx(Icon, { icon: "ph--trash--regular" }), /* @__PURE__ */ jsx("span", {
|
|
186
|
-
className: "ms-2 grow",
|
|
187
|
-
children: t("remove-section.label")
|
|
188
|
-
})]
|
|
198
|
+
"data-testid": "section.remove"
|
|
189
199
|
})
|
|
190
|
-
] })
|
|
200
|
+
] })]
|
|
191
201
|
})
|
|
192
202
|
}), /* @__PURE__ */ jsx("div", {
|
|
193
203
|
className: "p-1",
|
|
@@ -202,9 +212,9 @@ var StackSection = ({ data, ...tileProps }) => {
|
|
|
202
212
|
return /* @__PURE__ */ jsxs(Mosaic.Tile, {
|
|
203
213
|
...tileProps,
|
|
204
214
|
data,
|
|
205
|
-
classNames: "grid grid-cols-[var(--dx-rail-action)_1fr] dx-attention-surface border border-
|
|
215
|
+
classNames: "grid grid-cols-[var(--dx-rail-action)_1fr] dx-attention-surface border border-separator-subtle",
|
|
206
216
|
children: [/* @__PURE__ */ jsx("div", {
|
|
207
|
-
className: "border-e border-
|
|
217
|
+
className: "border-e border-separator-subtle",
|
|
208
218
|
children: /* @__PURE__ */ jsx("div", {
|
|
209
219
|
className: "sticky top-0 flex flex-col items-center",
|
|
210
220
|
children: rail
|