@synopackageland/ui 0.17.11 → 0.17.13

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/CHANGELOG.md CHANGED
@@ -1,5 +1,21 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.17.13 (2026-10-30)
4
+
5
+ Settings pages lay out as DSM's Control Panel, measured on a live DSM 7.3.2 (docs/dsm-native-metrics.md, Settings page), and every Callout can be closed. Breaking, with no compatibility layer: tables fill their container unless `:fill="false"`, `Callout`'s `closable` is gone (a close button is now the default; `:dismissible="false"` removes it), and `Fieldset` is no longer collapsible unless asked (`collapsible` adds the chevron back).
6
+
7
+ - Add `SettingsPage`: a settings tab's sections in a scrolling body over a footer that stays at the bottom (`#footer`, Reset then Apply, right-aligned capsules over a divider, DSM's 48px). With a height to fill only the body scrolls; in a page's own flow (a phone) the footer sticks to the bottom of the viewport above the safe area.
8
+ - `SectionTabs` takes `fill`: the strip stays at the top and the panel takes the rest of the height (`data-ui-section-tabs-fill`); without a height the strip sticks to the top. Tab labels are DSM's 12px bold (`--ui-font-size-tab`) and the first tab starts 8px in, level with a section title.
9
+ - `Fieldset` draws DSM's section: a 15px regular blue title (`--ui-font-size-section`) over a dashed divider at 70% (`--ui-fieldset-divider`), title text and body 8px in (`--ui-fieldset-inset`, `data-fieldset-body`), 8px to the next section (`--ui-fieldset-gap`); the description is a 28px row across the whole width.
10
+ - In a form, a `Checkbox` description is a 13px line of its own under the label (`data-ui-checkbox-description`), as DSM's help text under a checkbox. A horizontal `FormItem` label sits 4px from the row top, as DSM's.
11
+ - A number `Input`'s unit stays right after the field however long the unit is.
12
+ - `DataGrid` and `DataTable` take `fill` (default `true`): in a flex-column container they take the height left, keep the header row, scroll the rows inside, and a DataGrid's footer stays at the container's bottom, sticking above the safe area when the page scrolls (`data-fill`, `.ui-grid-footer-pinned`). `DataTable`'s header row now stays while its rows scroll. `:fill="false"` sizes a table to its rows, for a short table in a form or a dialog.
13
+ - `Callout` is dismissible by default: a ✕ in the top-right corner in the tone, labelled "Close" and focusable (`data-ui-callout-close`). Closing hides it (it stays in the DOM, `hidden`) and emits `close`; it comes back when its tone, title, code or text changes, or its `dismissKey`. The JSON catalog's Callout takes `dismissible` and `dismissKey`.
14
+
15
+ ## 0.17.12 (2026-10-30)
16
+
17
+ - Upload callbacks can throw an error with `final: true` to fail immediately, disable manual retry and hide retry controls for permanent failures; other errors still retry twice by default.
18
+
3
19
  ## 0.17.11 (2026-10-30)
4
20
 
5
21
  Settings forms follow DSM's own Control Panel layout by default. Two DOM changes: `Fieldset`'s chevron points up while open and down while collapsed (it was down and right), and a `password` `Input` is now an outer `<span>` (layout attrs) around an inner one holding the field and its toggle.
package/README.md CHANGED
@@ -522,7 +522,7 @@ DSM-style application building blocks:
522
522
 
523
523
  - SearchField
524
524
  - SettingsRow / SettingsSection
525
- - Form / FormItem / FormGroup / FormNote / InfoBox / FormActions / Fieldset (DSM-native settings structure, see [docs/layout-rules.md](docs/layout-rules.md))
525
+ - SettingsPage / Form / FormItem / FormGroup / FormNote / InfoBox / FormActions / Fieldset (DSM-native settings structure, see [docs/layout-rules.md](docs/layout-rules.md))
526
526
  - Callout (see [docs/callout.md](docs/callout.md) for when to use a Callout, a toast or an inline note) / EmptyState / StepList
527
527
  - ConnectionTopology
528
528
  - DataTable / DataGrid
@@ -674,6 +674,23 @@ size (arrow keys and swipes), and `UploadQueue` lists uploads with progress,
674
674
  retry and cancel. `useUploadQueue(upload, { concurrency, retries })` runs the
675
675
  uploads it shows. `FilePicker` takes pasted files with `paste`.
676
676
 
677
+ An upload failure is retried twice by default, after 1 second and 3 seconds.
678
+ For permanent errors such as a refused file type, an oversized file or denied
679
+ permission, throw an `Error` with `final: true`:
680
+
681
+ ```ts
682
+ throw Object.assign(new Error('This file type is not allowed'), { final: true })
683
+ ```
684
+
685
+ The queue immediately marks that task `failed`, keeps the error message and
686
+ calls `onFailed` once. Its `final` flag disables `queue.retry(key)` and hides
687
+ the task's retry button in `UploadQueue`; "Retry all" appears only when at
688
+ least two failed tasks can be retried. Other errors keep the usual retry
689
+ behavior. This also applies to `RichTextEditor`'s `upload` callback. Apps
690
+ providing their own `UploadQueueItem[]` can set `final: true` on failed items
691
+ and should skip them in their `retryAll` handler; the queue's `retry` method
692
+ already does so.
693
+
677
694
  ```vue
678
695
  <CommentItem v-for="c in comments" :key="c.id" :author="c.author.name" :time="c.when" :body="c.body" :mentions="people" :files="fileById" :edited="!!c.editedAt" :deleted="c.deleted" />
679
696
  <RichTextEditor v-model="text" variant="compact" :candidates="people" :filter="false" :maxlength="4000" :upload="sendFile" :files="fileById" @search="findPeople" @submit="post" />
@@ -7,12 +7,18 @@ type __VLS_Props = {
7
7
  ariaLabel?: string;
8
8
  modelValue: string;
9
9
  items: SectionTab[];
10
+ /**
11
+ * Fills the container's height: the strip stays at the top and the panel
12
+ * takes the rest, for a SettingsPage that scrolls its body over a fixed
13
+ * footer. Without a height to fill (a phone page) the strip sticks to the top.
14
+ */
15
+ fill?: boolean;
10
16
  };
11
- declare var __VLS_7: {}, __VLS_10: `panel-${string}`, __VLS_11: {};
17
+ declare var __VLS_14: {}, __VLS_17: `panel-${string}`, __VLS_18: {};
12
18
  type __VLS_Slots = {} & {
13
- [K in NonNullable<typeof __VLS_10>]?: (props: typeof __VLS_11) => any;
19
+ [K in NonNullable<typeof __VLS_17>]?: (props: typeof __VLS_18) => any;
14
20
  } & {
15
- actions?: (props: typeof __VLS_7) => any;
21
+ actions?: (props: typeof __VLS_14) => any;
16
22
  };
17
23
  declare const __VLS_base: import('vue').DefineComponent<__VLS_Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {
18
24
  "update:modelValue": (value: string) => any;
@@ -0,0 +1,15 @@
1
+ declare var __VLS_1: {}, __VLS_9: {};
2
+ type __VLS_Slots = {} & {
3
+ default?: (props: typeof __VLS_1) => any;
4
+ } & {
5
+ footer?: (props: typeof __VLS_9) => any;
6
+ };
7
+ declare const __VLS_base: import('vue').DefineComponent<{}, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, true, {}, any>;
8
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
9
+ declare const _default: typeof __VLS_export;
10
+ export default _default;
11
+ type __VLS_WithSlots<T, S> = T & {
12
+ new (): {
13
+ $slots: S;
14
+ };
15
+ };
@@ -3,7 +3,14 @@ type __VLS_Props = {
3
3
  /** `soft`: a compact tinted panel. `inline`: a status line with no panel, for a short note under a field or a section. */
4
4
  variant?: 'soft' | 'inline';
5
5
  title?: string;
6
- closable?: boolean;
6
+ /**
7
+ * Shows a close button (default). Closing hides the callout until its
8
+ * tone, title or text (or `dismissKey`) changes. Turn it off only for a
9
+ * state that must stay in view, such as a blocking setup requirement.
10
+ */
11
+ dismissible?: boolean;
12
+ /** What a dismissal is remembered by, instead of the tone and the rendered text. */
13
+ dismissKey?: string;
7
14
  closeLabel?: string;
8
15
  /** A machine code (e.g. `login_wait_timeout`), shown after the message in a quieter style. */
9
16
  code?: string;
@@ -36,7 +43,7 @@ declare const __VLS_base: import('vue').DefineComponent<__VLS_PublicProps, {}, {
36
43
  fill: boolean;
37
44
  variant: "soft" | "inline";
38
45
  tone: "info" | "success" | "warning" | "danger";
39
- closable: boolean;
46
+ dismissible: boolean;
40
47
  }, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, any>;
41
48
  declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
42
49
  declare const _default: typeof __VLS_export;
@@ -185,6 +185,13 @@ type __VLS_Props = {
185
185
  refreshable?: boolean;
186
186
  refreshing?: boolean;
187
187
  maxHeight?: string;
188
+ /**
189
+ * Fills the height its flex-column container leaves (the default, DSM's
190
+ * list): the header stays, the rows scroll inside, and the footer sits at
191
+ * the container's bottom whatever the row count. `false` sizes the grid
192
+ * to its rows, for a short table inside a form or a dialog.
193
+ */
194
+ fill?: boolean;
188
195
  labels?: Partial<DataGridLabels>;
189
196
  /** @deprecated Use `labels.empty`. */
190
197
  emptyText?: string;
@@ -293,6 +300,7 @@ declare const __VLS_base: import('vue').DefineComponent<__VLS_Props, {
293
300
  footer: boolean;
294
301
  filter: string;
295
302
  sort: DataGridSort | null;
303
+ fill: boolean;
296
304
  loading: boolean;
297
305
  group: DataGridGroup | null;
298
306
  loadingText: string;
@@ -18,6 +18,12 @@ type __VLS_Props = {
18
18
  mobileView?: 'auto' | 'cards' | 'table' | 'container';
19
19
  /** Width in px under which `mobileView="container"` shows cards. */
20
20
  containerBreakpoint?: number;
21
+ /**
22
+ * Fills the height its flex-column container leaves (the default): the
23
+ * header stays and the rows scroll inside. `false` sizes the table to its
24
+ * rows, for a short table inside a form or a dialog.
25
+ */
26
+ fill?: boolean;
21
27
  };
22
28
  declare var __VLS_2: `cell-${string}`, __VLS_3: {
23
29
  row: Record<string, unknown>;
@@ -40,6 +46,7 @@ type __VLS_Slots = {} & {
40
46
  [K in NonNullable<typeof __VLS_16>]?: (props: typeof __VLS_17) => any;
41
47
  };
42
48
  declare const __VLS_base: import('vue').DefineComponent<__VLS_Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
49
+ fill: boolean;
43
50
  compact: boolean;
44
51
  rowKey: string;
45
52
  mobileView: "auto" | "cards" | "table" | "container";
@@ -6,6 +6,8 @@ export type UploadQueueItem = {
6
6
  loaded: number;
7
7
  status: UploadStatus;
8
8
  error?: string;
9
+ /** A permanent failure; hides this task's retry button and excludes it from Retry all. */
10
+ final?: boolean;
9
11
  };
10
12
  type __VLS_Props = {
11
13
  tasks: UploadQueueItem[];
@@ -29,8 +31,8 @@ declare const __VLS_export: import('vue').DefineComponent<__VLS_Props, {}, {}, {
29
31
  onCancelAll?: (() => any) | undefined;
30
32
  }>, {
31
33
  collapsible: boolean;
32
- closable: boolean;
33
34
  processing: number;
35
+ closable: boolean;
34
36
  }, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, any>;
35
37
  declare const _default: typeof __VLS_export;
36
38
  export default _default;
@@ -7,6 +7,7 @@ type __VLS_Props = {
7
7
  title?: FieldsetTitle;
8
8
  /** One line under the title, across the whole width (DSM's "Enter the server name, ..."). */
9
9
  description?: string;
10
+ /** Adds DSM's disclosure chevron (Control Panel › Network); off by default, as Control Panel › Security. */
10
11
  collapsible?: boolean;
11
12
  /** Mouse gesture that toggles; Enter/Space always works on the header. */
12
13
  collapseTriggerEvent?: FieldsetCollapseTrigger;
package/dist/index.d.ts CHANGED
@@ -224,6 +224,7 @@ export { default as StackedBar } from './components/composite/stacked-bar/Stacke
224
224
  export type { StackedBarSegment, StackedBarTone } from './components/composite/stacked-bar/StackedBar.vue';
225
225
  export { default as PageContent } from './components/app/page-content/PageContent.vue';
226
226
  export { default as SectionTabs } from './components/app/section-tabs/SectionTabs.vue';
227
+ export { default as SettingsPage } from './components/app/settings-page/SettingsPage.vue';
227
228
  export type { SectionTab } from './components/app/section-tabs/SectionTabs.vue';
228
229
  export { default as ConfigProvider } from './components/composite/config-provider/ConfigProvider.vue';
229
230
  export { useProps, provideConfigManager } from './composables/configCascade';