@synopackageland/ui 0.9.0 → 0.9.2

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 (36) hide show
  1. package/CHANGELOG.md +33 -1
  2. package/README.md +78 -2
  3. package/dist/components/app/app-root/AppRoot.vue.d.ts +12 -1
  4. package/dist/components/composite/connection-topology/ConnectionTopology.vue.d.ts +40 -0
  5. package/dist/components/composite/connection-topology/TopologyLink.vue.d.ts +8 -0
  6. package/dist/components/composite/connection-topology/TopologyNode.vue.d.ts +19 -0
  7. package/dist/components/composite/connection-topology/types.d.ts +30 -0
  8. package/dist/components/composite/data-grid/DataGrid.vue.d.ts +7 -2
  9. package/dist/components/composite/step-list/StepList.vue.d.ts +29 -0
  10. package/dist/components/composite/step-list/types.d.ts +7 -0
  11. package/dist/components/composite/tree-view/TreeView.vue.d.ts +3 -0
  12. package/dist/components/containers/expandable-item/ExpandableItem.vue.d.ts +1 -1
  13. package/dist/components/feedback/notification/Notification.vue.d.ts +1 -1
  14. package/dist/components/primitives/breadcrumb/BreadcrumbCrumb.vue.d.ts +5 -1
  15. package/dist/components/primitives/dialog/Dialog.vue.d.ts +7 -3
  16. package/dist/components/primitives/dialog/FloatingLayer.vue.d.ts +18 -0
  17. package/dist/components/primitives/icon/FileTypeIcon.vue.d.ts +17 -0
  18. package/dist/components/primitives/icon/fileType.d.ts +3 -0
  19. package/dist/components/primitives/status-dot/StatusDot.vue.d.ts +13 -0
  20. package/dist/composables/floatingHost.d.ts +21 -0
  21. package/dist/composables/floatingPlacement.d.ts +14 -0
  22. package/dist/i18n/text.d.ts +9 -0
  23. package/dist/index.d.ts +7 -0
  24. package/dist/index.js +9136 -8483
  25. package/dist/json/catalog.d.ts +2 -2
  26. package/dist/json/registry.d.ts +30 -30
  27. package/dist/json-preview/preview.js +5400 -5125
  28. package/dist/lib/floatingDialog.d.ts +22 -0
  29. package/dist/lib/localModal.d.ts +5 -0
  30. package/dist/reka-runtime.json +1 -1
  31. package/dist/theme.css +1 -1
  32. package/dist/themes/dsm7-embedded-theme.css +1 -1
  33. package/dist/themes/dsm7-embedded.css +1 -1
  34. package/dist/themes/dsm7.css +1 -1
  35. package/docs/app-local-modal.md +47 -0
  36. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -1,6 +1,38 @@
1
1
  # Changelog
2
2
 
3
- ## Unreleased
3
+ ## 0.9.2 (2026-10-12)
4
+
5
+ One behavior change: while a Dialog floats outside its window (`dialog-bounds="viewport"`), focus that lands on the owning DSM window returns to the top Dialog, so Escape closes that Dialog instead of the window. Everything else is additive: Badge looks the same in the DSM 7 theme.
6
+ 一項行為變化:Dialog 浮出視窗外(`dialog-bounds="viewport"`)期間,落到所屬 DSM 視窗的焦點會回到最上層 Dialog,Esc 因此只關該 Dialog,不再關掉視窗。其餘皆為新增;DSM 7 主題下 Badge 外觀不變。
7
+
8
+ - `ConnectionTopology` draws paths from several sources, each through an optional relay, to one shared target, with no product wording built in. Each link is one of `active`, `pending`, `attention`, `error`, `idle` or `unknown`, shown with colour, a glyph and a word: working links flow dots toward the target, changing ones move slow dashes with a pulsing dot. Lanes are buttons that emit `select-lane` (Enter/Space; arrow keys, Home and End move between lanes); `lane-footer-<id>` and `node-<id>` slots add content. Below 600px of container width, or with `compact`, lanes stack with their own target. `pnpm check:topology` checks it in Chrome.
9
+ - 新增 `ConnectionTopology`:畫出多個來源各自經過(可省略的)中繼、連到同一個目標的路徑,元件本身不含產品用語。每段連線是 `active`、`pending`、`attention`、`error`、`idle`、`unknown` 之一,以顏色、圖示與文字表示:運作中的連線有點點流向目標,變化中的連線是慢速虛線加脈動圓點。每條 lane 是按鈕,發出 `select-lane`(Enter/Space;方向鍵、Home、End 在 lane 間移動);`lane-footer-<id>`、`node-<id>` slot 可加內容。容器寬度小於 600px 或設 `compact` 時改為直向堆疊、每條 lane 各帶目標。`pnpm check:topology` 在 Chrome 中檢查。
10
+ - `StatusDot` is a tone dot; `pulse` ripples a ring out of it. `StepList` is a static numbered list of instructions or checklist items, each with an optional status (`done`, `current`, `pending`, `error`, `warning`) and `#description`/`#action` slots.
11
+ - 新增 `StatusDot`(色調圓點,`pulse` 會向外擴散光圈)與 `StepList`(靜態編號步驟清單,可作操作說明或檢查清單;每項可帶狀態 `done`、`current`、`pending`、`error`、`warning`,並有 `#description`/`#action` slot)。
12
+ - Theme tokens `--ui-{neutral,info,success,warning,danger}-soft` and `-text` give each status tone a soft fill and the text that reads on it; `Badge` now uses them (same colours in the DSM 7 theme), so a theme recolours every tone. New keyframes `ui-flow` and `ui-pulse`; both stop under `prefers-reduced-motion`.
13
+ - 新增主題 token `--ui-{neutral,info,success,warning,danger}-soft` 與 `-text`,為每個狀態色提供淡底色與其上的文字色;`Badge` 改用它們(DSM 7 主題下顏色不變),主題可一次改掉所有色調。新增 keyframe `ui-flow`、`ui-pulse`,在 `prefers-reduced-motion` 下皆停止。
14
+ - **Behavior change.** Fix: with `dialog-bounds="viewport"`, Escape after pressing a floating Dialog no longer closes the whole DSM window. The `activate` handler's `toFront()` moved focus to the window's own anchor, so Escape skipped the Dialog and reached the window's keymap. Focus that lands on the owning window while a Dialog floats now returns to the top Dialog, so Escape closes only that Dialog. Apps need no change.
15
+ - **行為變化。** 修正:`dialog-bounds="viewport"` 下,按過浮出的 Dialog 後再按 Esc,不再關掉整個 DSM 視窗。`activate` 處理中的 `toFront()` 會把焦點移到視窗自己的錨點,Esc 因此繞過 Dialog、由視窗 keymap 處理。現在 Dialog 浮出期間,落到所屬視窗的焦點會回到最上層 Dialog,Esc 只關該 Dialog。App 不需修改。
16
+
17
+ ## 0.9.1 (2026-10-12)
18
+
19
+ Two behavior changes: a Dialog without `width` is 520px wide inside `AppRoot`, and Breadcrumb's last level no longer emits `click-item`.
20
+ 兩項行為變化:`AppRoot` 內未指定 `width` 的 Dialog 寬 520px;Breadcrumb 最後一段不再發出 `click-item`。
21
+
22
+ - **Behavior change.** Fix: Dialog's `width` applies again inside `AppRoot`. Since app-local modality, `max-width: calc(100% - 24px) !important` overrode it, so 480px or 800px dialogs stretched to almost the window width. A panel now narrows only when the app (or viewport) is narrower than `width`. Dialogs without `width` now take the 520px default instead of the window width; pass a larger `width` where a wide panel is wanted.
23
+ - **行為變化。** 修正:`AppRoot` 內 Dialog 的 `width` 重新生效。自 app-local modal 起,`max-width: calc(100% - 24px) !important` 蓋掉它,480px/800px 的 Dialog 都被撐到接近視窗寬;現在只在 app(或 viewport)比 `width` 窄時才夾到可用寬度。未指定 `width` 的 Dialog 改用預設 520px,不再是視窗寬;需要寬面板請傳較大的 `width`。
24
+ - Dialog takes `height` and `min-height`, so one row of content no longer leaves a flat panel. Both are capped to the available height, the body fills the panel and the footer stays at the bottom.
25
+ - Dialog 新增 `height` 與 `min-height`,內容只有一列時不再變成扁平面板;兩者都夾到可用高度,內容區撐滿、footer 固定在底部。
26
+ - `AppRoot` takes `dialog-bounds="viewport"` (app mode, default `app`): as in DSM, the mask covers only the owning window, while the Dialog panel can be dragged by its title bar (or moved with the arrow keys on its title) anywhere inside the browser viewport. It stacks with its window, hides with it, follows its moves, and becomes a bottom sheet below 600px or with a coarse pointer. Pressing it emits `activate` so the DSM host can bring the window forward. See `docs/app-local-modal.md`.
27
+ - `AppRoot` 新增 `dialog-bounds="viewport"`(app 模式,預設 `app`):與 DSM 原生一致,遮罩只蓋擁有它的視窗,Dialog 本體可用標題列拖移(或聚焦標題後用方向鍵)到瀏覽器 viewport 內任何位置;它隨視窗疊放與隱藏、跟著視窗移動,600px 以下或粗指標時改為底部 sheet。按下面板會發出 `activate`,讓 DSM host 把視窗帶到前面。詳見 `docs/app-local-modal.md`。
28
+ - **Behavior change:** Breadcrumb's current (last) level is plain text with `aria-current="page"`, no longer a button that emits `click-item`. With an action menu it stays the menu trigger.
29
+ - **行為變化:** Breadcrumb 的目前(最後)一段改為帶 `aria-current="page"` 的文字,不再是會發出 `click-item` 的按鈕;有 action menu 時仍是選單觸發鈕。
30
+ - TreeView takes `selection-style="background"`: a selected row only gets the selected background, and its icon and text keep their colors, as in DSM File Station. The default `accent` is unchanged.
31
+ - TreeView 新增 `selection-style="background"`:選中列只換背景,圖示與文字維持原色(DSM File Station 樣式);預設 `accent` 不變。
32
+ - DataGrid takes `single-select`: no checkbox column, a click selects one row, the rows are in the tab order (the selected row, else the first), the arrow keys move the selection and Enter emits `rowActivate`.
33
+ - DataGrid 新增 `single-select`:無勾選框欄,點列單選;列可用鍵盤聚焦(選中列,否則第一列),方向鍵移動選取,Enter 觸發 `rowActivate`。
34
+ - `FileTypeIcon` draws a folder (`kind="folder"`, `open`) or a file whose extension picks the icon (image, video, audio, archive, text, code, else a plain file). Its colours are the theme tokens `--ui-file-folder` (DSM 7 File Station yellow) and `--ui-file-icon`, so a theme recolours every file list; `fileTypeIcon(name)` returns the icon alone.
35
+ - 新增 `FileTypeIcon`:畫資料夾(`kind="folder"`、`open`)或依副檔名選圖示的檔案(圖片、影片、音訊、壓縮檔、文字、程式碼,其餘為一般檔案)。顏色來自主題 token `--ui-file-folder`(DSM 7 File Station 黃色)與 `--ui-file-icon`,主題可一次改掉所有檔案列表的顏色;`fileTypeIcon(name)` 只回傳圖示元件。
4
36
 
5
37
  ## 0.9.0 (2026-10-11)
6
38
 
package/README.md CHANGED
@@ -253,6 +253,12 @@ const open = ref(false)
253
253
  </template>
254
254
  ```
255
255
 
256
+ `width` (default `520px`) is the panel's maximum width. `height` or
257
+ `min-height` (for example `min-height="420px"`) keeps a panel with little
258
+ content from collapsing. In a DSM window, `<AppRoot dialog-bounds="viewport">`
259
+ lets dialogs be dragged out of the window, within the browser viewport. See
260
+ [docs/app-local-modal.md](docs/app-local-modal.md#floating-dialogs-in-a-dsm-window).
261
+
256
262
  ### Toast notifications
257
263
 
258
264
  Wrap your page with `ToastProvider` in `App.vue`:
@@ -322,6 +328,19 @@ Components use semantic CSS tokens. Import your override stylesheet after the li
322
328
  }
323
329
  ```
324
330
 
331
+ Status tones come in pairs, a soft fill and the text that reads on it:
332
+ `--ui-{neutral,info,success,warning,danger}-soft` and `-text`. `Badge`,
333
+ `StatusDot`, `StepList` and `ConnectionTopology` use only these and the base
334
+ tones (`--ui-success`, …), so a dark theme overrides the pairs once:
335
+
336
+ ```css
337
+ [data-ui-theme='dark'] {
338
+ --ui-success-soft: #173222;
339
+ --ui-success-text: #6fdc8a;
340
+ /* … the other tones, and the surface and text tokens */
341
+ }
342
+ ```
343
+
325
344
  Density can be switched per application subtree:
326
345
 
327
346
  ```html
@@ -338,7 +357,7 @@ Primitives:
338
357
  - Input / Textarea
339
358
  - Checkbox / RadioGroup / Switch
340
359
  - Select
341
- - Badge / Separator / Spinner / LoadingMask / LoadingArea / Progress / Skeleton / Surface
360
+ - Badge / StatusDot / Separator / Spinner / LoadingMask / LoadingArea / Progress / Skeleton / Surface
342
361
  - SplitButton
343
362
  - Tooltip / Popover / DropdownMenu / ContextMenu / Dialog
344
363
  - Sheet / Drawer
@@ -350,7 +369,8 @@ DSM-style application building blocks:
350
369
 
351
370
  - SearchField
352
371
  - SettingsRow / SettingsSection
353
- - Callout / EmptyState
372
+ - Callout / EmptyState / StepList
373
+ - ConnectionTopology
354
374
  - DataTable / DataGrid
355
375
  - TreeView
356
376
  - FilePicker
@@ -379,6 +399,54 @@ by the caller, add `class="ui-tab-panel"` to a panel keyed by the selected value
379
399
  to use the same short fade. These effects and the loading ring respect the
380
400
  system's reduced-motion preference.
381
401
 
402
+ ### Status: StatusDot, StepList, ConnectionTopology
403
+
404
+ `StatusDot` is an 8px tone dot; `pulse` ripples a ring out of it for a state
405
+ that is still changing. It is decorative unless it has a `label`.
406
+
407
+ `StepList` is a static numbered list (`items: { title, description?, status? }[]`)
408
+ for instructions or a checklist. `status` (`done`, `current`, `pending`, `error`,
409
+ `warning`) recolours the marker and is read out to assistive technology;
410
+ `#description` and `#action` scoped slots add content per step. It does not
411
+ navigate; use `Wizard` for that.
412
+
413
+ `ConnectionTopology` draws paths from several sources, each through an optional
414
+ relay, to one shared target. It knows nothing about any product: the caller
415
+ maps its own states to six link states.
416
+
417
+ ```vue
418
+ <ConnectionTopology
419
+ aria-label="Connections"
420
+ :target="{ id: 'server', label: 'Server', caption: 'office-01', icon: Server }"
421
+ :lanes="[{
422
+ id: 'relay',
423
+ source: { id: 'browser', label: 'Any browser', icon: Globe },
424
+ via: { id: 'relay', label: 'Edge relay', icon: Cloud },
425
+ links: [{ state: 'active', label: 'Reachable' }, { state: 'active', label: 'Running' }],
426
+ }]"
427
+ @select-lane="open"
428
+ >
429
+ <template #lane-footer-relay>https://office.example.com</template>
430
+ </ConnectionTopology>
431
+ ```
432
+
433
+ - **States.** `active` (green, dots flow toward the target), `pending` (amber,
434
+ slow dashes and a pulsing dot), `attention` (amber, waits for the user),
435
+ `error` (red), `idle` (grey dashes), `unknown` (grey dots). Every state but
436
+ `idle` has a glyph and every link a word, so colour is never the only cue;
437
+ `link.icon` replaces the glyph (a key for a sign-in, say). A missing `label`
438
+ shows the localized state word (`text` overrides them); `label: ''` hides it.
439
+ - **Keyboard and screen readers.** Each lane is a button named after its nodes
440
+ and link states; Enter or Space emits `select-lane`, the arrow keys, Home and
441
+ End move between lanes. `selectable: false` renders plain rows.
442
+ `lane-footer-<id>` content sits below the lane button, so it may hold its own
443
+ buttons and links; `node-<id>` replaces a node's content.
444
+ - **Layout.** Below 600px of container width (or with `compact`), each lane
445
+ stacks with its own copy of the target and the link words move to a caption
446
+ line. With no lanes, one idle line shows `empty-label`.
447
+ - **Motion.** The keyframes `ui-flow` and `ui-pulse` stop under
448
+ `prefers-reduced-motion`; a working link then turns solid with an arrow.
449
+
382
450
  `FilePicker` owns file selection/validation/drop-zone UI only; applications remain responsible for upload transport.
383
451
 
384
452
  ### DataGrid
@@ -437,6 +505,7 @@ pnpm check # lint, typecheck, tests, and production build
437
505
  pnpm story:build # build the component workbench
438
506
  pnpm check:host # after pnpm build: DSM host simulation screenshots (Chrome)
439
507
  pnpm check:switch # after pnpm build: Switch knob geometry and click toggling (Chrome)
508
+ pnpm check:topology # after pnpm build: ConnectionTopology motion, keyboard and narrow layout (Chrome)
440
509
  ```
441
510
 
442
511
  `pnpm check:host` serves `tests/dsm-host` and screenshots each overlay scene in
@@ -451,6 +520,13 @@ embedded theme (also under `host-simulation.css`), checks in headless Chrome tha
451
520
  inside and centred in the track and that a real mouse click toggles an enabled switch. Screenshots
452
521
  are left in `.switch-shots/`.
453
522
 
523
+ `pnpm check:topology` renders every link state wide, on dark tokens, at 360px and
524
+ empty, on the standalone and the embedded theme. In headless Chrome it checks
525
+ that working links flow and changing ones pulse, that reduced motion stills
526
+ them, that the arrow keys and Enter select a lane with a visible focus ring, and
527
+ that the narrow layout stacks without overflow. Screenshots are left in
528
+ `.topology-shots/`.
529
+
454
530
  In the workbench, open `DSM 7 / App Interior` and `DSM 7 / Advanced Components`
455
531
  for reference compositions. See [SPEC.md](./SPEC.md) for architecture and
456
532
  contribution rules, and [src/index.ts](./src/index.ts) for public exports.
@@ -1,5 +1,11 @@
1
1
  type __VLS_Props = {
2
2
  modalScope?: 'document' | 'app';
3
+ /**
4
+ * `viewport` lets app-local dialogs leave the app window, as DSM's own
5
+ * dialogs do: the mask still covers only this root, the panel can be dragged
6
+ * anywhere in the viewport. Set it only inside a DSM window.
7
+ */
8
+ dialogBounds?: 'app' | 'viewport';
3
9
  };
4
10
  declare var __VLS_7: {}, __VLS_9: {};
5
11
  type __VLS_Slots = {} & {
@@ -7,8 +13,13 @@ type __VLS_Slots = {} & {
7
13
  } & {
8
14
  default?: (props: typeof __VLS_9) => any;
9
15
  };
10
- declare const __VLS_base: import('vue').DefineComponent<__VLS_Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
16
+ declare const __VLS_base: import('vue').DefineComponent<__VLS_Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {
17
+ activate: () => any;
18
+ }, string, import('vue').PublicProps, Readonly<__VLS_Props> & Readonly<{
19
+ onActivate?: (() => any) | undefined;
20
+ }>, {
11
21
  modalScope: "document" | "app";
22
+ dialogBounds: "app" | "viewport";
12
23
  }, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, any>;
13
24
  declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
14
25
  declare const _default: typeof __VLS_export;
@@ -0,0 +1,40 @@
1
+ import { LinkState, TopologyLane, TopologyNode } from './types';
2
+ /**
3
+ * Paths from several sources, each through an optional relay, to one shared
4
+ * target. Each link shows its state with colour, a glyph and text; working
5
+ * links flow toward the target. Every lane is a button that emits
6
+ * `select-lane`. Below 600px of container width the lanes stack compactly.
7
+ */
8
+ type __VLS_Props = {
9
+ target: TopologyNode;
10
+ lanes: TopologyLane[];
11
+ ariaLabel?: string;
12
+ /** Always use the stacked narrow layout. */
13
+ compact?: boolean;
14
+ /** Render lanes as buttons that emit `select-lane`. */
15
+ selectable?: boolean;
16
+ emptyLabel?: string;
17
+ /** State words for links without a label. */
18
+ text?: Partial<Record<LinkState, string>>;
19
+ };
20
+ type __VLS_Slots = Record<`node-${string}`, (props: {
21
+ node: TopologyNode;
22
+ }) => unknown> & Record<`lane-footer-${string}`, (props: {
23
+ lane: TopologyLane;
24
+ }) => unknown>;
25
+ declare const __VLS_base: import('vue').DefineComponent<__VLS_Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {
26
+ "select-lane": (id: string) => any;
27
+ }, string, import('vue').PublicProps, Readonly<__VLS_Props> & Readonly<{
28
+ "onSelect-lane"?: ((id: string) => any) | undefined;
29
+ }>, {
30
+ compact: boolean;
31
+ selectable: boolean;
32
+ }, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, any>;
33
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
34
+ declare const _default: typeof __VLS_export;
35
+ export default _default;
36
+ type __VLS_WithSlots<T, S> = T & {
37
+ new (): {
38
+ $slots: S;
39
+ };
40
+ };
@@ -0,0 +1,8 @@
1
+ import { TopologyLink } from './types';
2
+ type __VLS_Props = {
3
+ link: TopologyLink;
4
+ text: string;
5
+ };
6
+ declare const __VLS_export: import('vue').DefineComponent<__VLS_Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, any>;
7
+ declare const _default: typeof __VLS_export;
8
+ export default _default;
@@ -0,0 +1,19 @@
1
+ import { TopologyNode } from './types';
2
+ type __VLS_Props = {
3
+ node: TopologyNode;
4
+ };
5
+ declare var __VLS_1: {
6
+ node: TopologyNode;
7
+ };
8
+ type __VLS_Slots = {} & {
9
+ default?: (props: typeof __VLS_1) => any;
10
+ };
11
+ declare const __VLS_base: import('vue').DefineComponent<__VLS_Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, any>;
12
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
13
+ declare const _default: typeof __VLS_export;
14
+ export default _default;
15
+ type __VLS_WithSlots<T, S> = T & {
16
+ new (): {
17
+ $slots: S;
18
+ };
19
+ };
@@ -0,0 +1,30 @@
1
+ import { Component } from 'vue';
2
+ /**
3
+ * `active` works, `pending` is still changing, `attention` waits for the user,
4
+ * `error` failed, `idle` is not set up or turned off, `unknown` cannot be told.
5
+ */
6
+ export type LinkState = 'active' | 'pending' | 'attention' | 'error' | 'idle' | 'unknown';
7
+ export interface TopologyNode {
8
+ id: string;
9
+ label: string;
10
+ caption?: string;
11
+ icon?: Component;
12
+ }
13
+ export interface TopologyLink {
14
+ state: LinkState;
15
+ /** Short visible text; the state word stands in when it is missing, and an
16
+ * empty string shows none (the lane's accessible name keeps the state word). */
17
+ label?: string;
18
+ /** Replaces the state's glyph, e.g. a key for a sign-in. */
19
+ icon?: Component;
20
+ }
21
+ export interface TopologyLane {
22
+ id: string;
23
+ /** The far end, e.g. the people or devices that connect. */
24
+ source: TopologyNode;
25
+ /** The relay in between; without it the lane is a direct path. */
26
+ via?: TopologyNode;
27
+ /** Source to relay, then relay to the shared target. */
28
+ links: [TopologyLink, TopologyLink];
29
+ disabled?: boolean;
30
+ }
@@ -103,6 +103,8 @@ type __VLS_Props = {
103
103
  selectable?: boolean;
104
104
  /** With `selectable`: a row click selects that row; Ctrl/Cmd-click toggles it. */
105
105
  selectOnRowClick?: boolean;
106
+ /** One selected row at a time, picked by clicking the row; no checkbox column. */
107
+ singleSelect?: boolean;
106
108
  page?: number;
107
109
  pageSize?: number;
108
110
  totalRows?: number;
@@ -172,6 +174,7 @@ declare const __VLS_base: import('vue').DefineComponent<__VLS_Props, {
172
174
  }) => any;
173
175
  rowClick: (row: Record<string, unknown>) => any;
174
176
  rowDblclick: (row: Record<string, unknown>) => any;
177
+ rowActivate: (row: Record<string, unknown>) => any;
175
178
  rowExpand: (key: string) => any;
176
179
  rowCollapse: (key: string) => any;
177
180
  groupToggle: (groupKey: string, expanded: boolean) => any;
@@ -201,6 +204,7 @@ declare const __VLS_base: import('vue').DefineComponent<__VLS_Props, {
201
204
  }) => any) | undefined;
202
205
  onRowClick?: ((row: Record<string, unknown>) => any) | undefined;
203
206
  onRowDblclick?: ((row: Record<string, unknown>) => any) | undefined;
207
+ onRowActivate?: ((row: Record<string, unknown>) => any) | undefined;
204
208
  onRowExpand?: ((key: string) => any) | undefined;
205
209
  onRowCollapse?: ((key: string) => any) | undefined;
206
210
  onGroupToggle?: ((groupKey: string, expanded: boolean) => any) | undefined;
@@ -222,13 +226,15 @@ declare const __VLS_base: import('vue').DefineComponent<__VLS_Props, {
222
226
  loading: boolean;
223
227
  group: DataGridGroup | null;
224
228
  loadingText: string;
229
+ draggable: boolean | DataGridDraggable;
225
230
  page: number;
226
231
  pageSize: number;
232
+ selectable: boolean;
227
233
  rowKey: string;
228
234
  defaultSort: DataGridSort | null;
229
235
  selectedKeys: string[];
230
- selectable: boolean;
231
236
  selectOnRowClick: boolean;
237
+ singleSelect: boolean;
232
238
  localSort: boolean;
233
239
  localPagination: boolean;
234
240
  loadingRows: number;
@@ -239,7 +245,6 @@ declare const __VLS_base: import('vue').DefineComponent<__VLS_Props, {
239
245
  expandable: DataGridExpandable | null;
240
246
  expandedKeys: string[];
241
247
  defaultExpandedKeys: string[];
242
- draggable: boolean | DataGridDraggable;
243
248
  }, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, any>;
244
249
  declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
245
250
  declare const _default: typeof __VLS_export;
@@ -0,0 +1,29 @@
1
+ import { StepListItem, StepStatus } from './types';
2
+ /**
3
+ * A static, numbered list of steps: instructions to follow or a checklist
4
+ * whose items each carry a status. It does not navigate; see Wizard for that.
5
+ */
6
+ type __VLS_Props = {
7
+ items: StepListItem[];
8
+ /** Status words read to assistive technology. */
9
+ text?: Partial<Record<Exclude<StepStatus, 'pending'>, string>>;
10
+ };
11
+ type __VLS_Slots = {
12
+ description?: (props: {
13
+ item: StepListItem;
14
+ index: number;
15
+ }) => unknown;
16
+ action?: (props: {
17
+ item: StepListItem;
18
+ index: number;
19
+ }) => unknown;
20
+ };
21
+ declare const __VLS_base: import('vue').DefineComponent<__VLS_Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, any>;
22
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
23
+ declare const _default: typeof __VLS_export;
24
+ export default _default;
25
+ type __VLS_WithSlots<T, S> = T & {
26
+ new (): {
27
+ $slots: S;
28
+ };
29
+ };
@@ -0,0 +1,7 @@
1
+ export type StepStatus = 'done' | 'current' | 'pending' | 'error' | 'warning';
2
+ export interface StepListItem {
3
+ title: string;
4
+ description?: string;
5
+ /** Defaults to `pending`. */
6
+ status?: StepStatus;
7
+ }
@@ -16,6 +16,8 @@ type __VLS_Props = {
16
16
  loadChildren?: (node: TreeNode) => Promise<TreeNode[] | undefined>;
17
17
  /** Localise the expand/collapse control. */
18
18
  expandLabel?: (node: TreeNode, expanded: boolean) => string;
19
+ /** `accent` also colors the selected icon and text; `background` only shades the row, as DSM File Station does. */
20
+ selectionStyle?: 'accent' | 'background';
19
21
  };
20
22
  declare function nodeById(id: string): TreeNode | undefined;
21
23
  declare function getCheckedNodes(includeHalf?: boolean): TreeNode[];
@@ -84,6 +86,7 @@ declare const __VLS_base: import('vue').DefineComponent<__VLS_Props, {
84
86
  checkable: boolean;
85
87
  defaultCheckedKeys: string[];
86
88
  loadChildren: (node: TreeNode) => Promise<TreeNode[] | undefined>;
89
+ selectionStyle: "accent" | "background";
87
90
  }, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, any>;
88
91
  declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
89
92
  declare const _default: typeof __VLS_export;
@@ -64,9 +64,9 @@ declare const __VLS_base: import('vue').DefineComponent<__VLS_Props, {}, {}, {},
64
64
  "onDrag-over"?: ((event: DragEvent) => any) | undefined;
65
65
  "onDrag-end"?: ((event: DragEvent) => any) | undefined;
66
66
  }>, {
67
+ draggable: boolean;
67
68
  selectable: boolean;
68
69
  expandable: boolean;
69
- draggable: boolean;
70
70
  expanded: boolean;
71
71
  }, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, any>;
72
72
  declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
@@ -34,8 +34,8 @@ declare const __VLS_base: import('vue').DefineComponent<__VLS_Props, {}, {}, {},
34
34
  open: boolean;
35
35
  tone: NotificationTone;
36
36
  content: string | false;
37
- duration: number | false;
38
37
  cancel: NotificationAction;
38
+ duration: number | false;
39
39
  confirm: NotificationAction;
40
40
  paused: boolean;
41
41
  }, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, any>;
@@ -5,7 +5,11 @@ type __VLS_Props = {
5
5
  /** The level owns the action menu, so it shows a dropdown chevron. */
6
6
  hasMenu?: boolean;
7
7
  };
8
- declare const __VLS_export: import('vue').DefineComponent<__VLS_Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
8
+ declare const __VLS_export: import('vue').DefineComponent<__VLS_Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {
9
+ click: (event: MouseEvent) => any;
10
+ }, string, import('vue').PublicProps, Readonly<__VLS_Props> & Readonly<{
11
+ onClick?: ((event: MouseEvent) => any) | undefined;
12
+ }>, {
9
13
  current: boolean;
10
14
  hasMenu: boolean;
11
15
  }, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, any>;
@@ -4,17 +4,21 @@ type __VLS_Props = {
4
4
  title?: string;
5
5
  description?: string;
6
6
  width?: string;
7
+ /** A fixed panel height, capped to the available height. */
8
+ height?: string;
9
+ /** Keeps the panel from shrinking with short content, capped to the available height. */
10
+ minHeight?: string;
7
11
  closeLabel?: string;
8
12
  /** Hides the header close affordance for fixed-flow dialogs that own their dismiss path. */
9
13
  showClose?: boolean;
10
14
  };
11
- declare var __VLS_14: {}, __VLS_62: {}, __VLS_64: {};
15
+ declare var __VLS_14: {}, __VLS_71: {}, __VLS_73: {};
12
16
  type __VLS_Slots = {} & {
13
17
  trigger?: (props: typeof __VLS_14) => any;
14
18
  } & {
15
- default?: (props: typeof __VLS_62) => any;
19
+ default?: (props: typeof __VLS_71) => any;
16
20
  } & {
17
- footer?: (props: typeof __VLS_64) => any;
21
+ footer?: (props: typeof __VLS_73) => any;
18
22
  };
19
23
  declare const __VLS_base: import('vue').DefineComponent<__VLS_Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {
20
24
  escapeKeyDown: (event: KeyboardEvent) => any;
@@ -0,0 +1,18 @@
1
+ type __VLS_Props = {
2
+ host: HTMLElement | null;
3
+ };
4
+ declare var __VLS_14: {}, __VLS_16: {};
5
+ type __VLS_Slots = {} & {
6
+ default?: (props: typeof __VLS_14) => any;
7
+ } & {
8
+ default?: (props: typeof __VLS_16) => any;
9
+ };
10
+ declare const __VLS_base: import('vue').DefineComponent<__VLS_Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, any>;
11
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
12
+ declare const _default: typeof __VLS_export;
13
+ export default _default;
14
+ type __VLS_WithSlots<T, S> = T & {
15
+ new (): {
16
+ $slots: S;
17
+ };
18
+ };
@@ -0,0 +1,17 @@
1
+ import { IconSize } from './icon';
2
+ type __VLS_Props = {
3
+ kind?: 'folder' | 'file';
4
+ /** A file's name; its extension picks the icon. */
5
+ name?: string;
6
+ /** Draws an open folder. */
7
+ open?: boolean;
8
+ size?: IconSize;
9
+ };
10
+ declare const __VLS_export: import('vue').DefineComponent<__VLS_Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
11
+ size: IconSize;
12
+ name: string;
13
+ open: boolean;
14
+ kind: "folder" | "file";
15
+ }, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, any>;
16
+ declare const _default: typeof __VLS_export;
17
+ export default _default;
@@ -0,0 +1,3 @@
1
+ import { LucideIcon } from '@lucide/vue';
2
+ /** The icon for a file name, from its last extension; `File` when unknown. */
3
+ export declare function fileTypeIcon(name?: string): LucideIcon;
@@ -0,0 +1,13 @@
1
+ type __VLS_Props = {
2
+ tone?: 'neutral' | 'info' | 'success' | 'warning' | 'danger';
3
+ /** Ripple a ring out of the dot, for a state that is still changing. */
4
+ pulse?: boolean;
5
+ /** Names the state for assistive technology; without it the dot is decorative. */
6
+ label?: string;
7
+ };
8
+ declare const __VLS_export: import('vue').DefineComponent<__VLS_Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
9
+ tone: "neutral" | "info" | "success" | "warning" | "danger";
10
+ pulse: boolean;
11
+ }, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, any>;
12
+ declare const _default: typeof __VLS_export;
13
+ export default _default;
@@ -0,0 +1,21 @@
1
+ import { Ref, ShallowRef } from 'vue';
2
+ import { Box, Size } from '../lib/floatingDialog';
3
+ export declare const FLOATING_HOST_KEY = "@synopkgland/floating-host";
4
+ export declare const FLOATING_HOST_ATTRIBUTE = "data-ui-floating";
5
+ export type FloatingHost = {
6
+ element: ShallowRef<HTMLElement | null>;
7
+ /** The app root's box, or null while its window is hidden. */
8
+ owner: ShallowRef<Box | null>;
9
+ viewport: ShallowRef<Size>;
10
+ /** False on a narrow viewport or with a coarse pointer: panels become viewport sheets. */
11
+ draggable: Ref<boolean>;
12
+ };
13
+ export declare function injectFloatingHost(): FloatingHost | null;
14
+ /**
15
+ * A viewport-sized layer for dialogs that may leave the app window, as DSM's
16
+ * own dialogs do. It sits right after the window that owns the app, at that
17
+ * window's z-index, so other DSM windows still stack over both, and it hides
18
+ * with the window. It carries the app root attribute, so the scoped theme
19
+ * styles it, and it lets presses through except on panels.
20
+ */
21
+ export declare function useFloatingHost(root: Ref<HTMLElement | null>, enabled: boolean, activate: () => void): FloatingHost | null;
@@ -0,0 +1,14 @@
1
+ import { Ref } from 'vue';
2
+ import { Point } from '../lib/floatingDialog';
3
+ import { FloatingHost } from './floatingHost';
4
+ /**
5
+ * Places a floating dialog panel: centered over its app window when it opens,
6
+ * then moved by its title bar (pointer) or title (arrow keys), always kept
7
+ * inside the viewport and moved along with the app window.
8
+ */
9
+ export declare function useFloatingPlacement(handle: Ref<HTMLElement | null>, host: FloatingHost | null): {
10
+ position: import('vue').ShallowRef<Point | null, Point | null>;
11
+ draggable: import('vue').ComputedRef<boolean>;
12
+ onPointerdown: (event: PointerEvent) => void;
13
+ onKeydown: (event: KeyboardEvent) => void;
14
+ };
@@ -43,6 +43,15 @@ export declare const englishUiText: {
43
43
  readonly Info: "Info";
44
44
  readonly Warning: "Warning";
45
45
  readonly Error: "Error";
46
+ readonly Completed: "Completed";
47
+ readonly "Current step": "Current step";
48
+ readonly Connected: "Connected";
49
+ readonly Connecting: "Connecting";
50
+ readonly "Needs attention": "Needs attention";
51
+ readonly Failed: "Failed";
52
+ readonly "Not set up": "Not set up";
53
+ readonly Unknown: "Unknown";
54
+ readonly "No connections": "No connections";
46
55
  readonly Reset: "Reset";
47
56
  readonly Custom: "Custom";
48
57
  readonly Color: "Color";
package/dist/index.d.ts CHANGED
@@ -19,6 +19,7 @@ export { default as MultipleSelect } from './components/primitives/multiple-sele
19
19
  export { default as SuperboxSelect } from './components/primitives/superbox-select/SuperboxSelect.vue';
20
20
  export type { SelectAllowCreate, SelectCreateOptions, SelectOptionGroup, SelectOptions, SelectOptionsRecord, SelectSearch, } from './components/primitives/select/internal/types';
21
21
  export { default as Badge } from './components/primitives/badge/Badge.vue';
22
+ export { default as StatusDot } from './components/primitives/status-dot/StatusDot.vue';
22
23
  export { default as Separator } from './components/primitives/separator/Separator.vue';
23
24
  export { default as Spinner } from './components/primitives/spinner/Spinner.vue';
24
25
  export { default as LoadingMask } from './components/primitives/loading/LoadingMask.vue';
@@ -48,6 +49,8 @@ export type { TabItem } from './components/primitives/tabs/Tabs.vue';
48
49
  export { default as Accordion } from './components/primitives/accordion/Accordion.vue';
49
50
  export type { AccordionEntry } from './components/primitives/accordion/Accordion.vue';
50
51
  export { default as Icon } from './components/primitives/icon/Icon.vue';
52
+ export { default as FileTypeIcon } from './components/primitives/icon/FileTypeIcon.vue';
53
+ export { fileTypeIcon } from './components/primitives/icon/fileType';
51
54
  export { useIconButton } from './components/primitives/icon/useIconButton';
52
55
  export type { IconButtonOptions } from './components/primitives/icon/useIconButton';
53
56
  export { clearIconRegistry, getRegisteredIcon, registerIcons } from './components/primitives/icon/iconRegistry';
@@ -101,6 +104,10 @@ export { default as SettingsSection } from './components/composite/settings-sect
101
104
  export { default as Footbar } from './components/composite/footbar/Footbar.vue';
102
105
  export type { FootbarButton, FootbarButtonRegion, FootbarButtonSize, FootbarButtonVariant, } from './components/composite/footbar/types';
103
106
  export { default as Callout } from './components/composite/callout/Callout.vue';
107
+ export { default as StepList } from './components/composite/step-list/StepList.vue';
108
+ export type { StepListItem, StepStatus } from './components/composite/step-list/types';
109
+ export { default as ConnectionTopology } from './components/composite/connection-topology/ConnectionTopology.vue';
110
+ export type { LinkState, TopologyLane, TopologyLink, TopologyNode } from './components/composite/connection-topology/types';
104
111
  export { default as EmptyState } from './components/composite/empty-state/EmptyState.vue';
105
112
  export { default as DataTable } from './components/composite/data-table/DataTable.vue';
106
113
  export type { DataTableColumn } from './components/composite/data-table/DataTable.vue';