@synopackageland/ui 0.17.4 → 0.17.5

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,15 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.17.5 (2026-10-29)
4
+
5
+ Additive only: existing props, defaults and DOM stay as they were.
6
+
7
+ - `SectionTabs` takes an `#actions` slot for page actions on the tab row: right-aligned over the same baseline, and on a row too narrow for both they wrap onto a line of their own above the tabs, still right-aligned (`data-ui-section-tabs-row`, `data-ui-section-tabs-actions`). Use tool buttons there. Without the slot the strip renders as before; attributes stay on the strip.
8
+ - Add `StatTile`: a KPI tile with a `label`, a `value` (or slot) with an optional `unit`, a `note` and an optional `tone` dot. With `v-model` it is a toggle button (`aria-pressed`, Enter and Space, focus ring, accent border and fill when pressed); without one it is a plain tile.
9
+ - Add `StatTileGroup`: a filter bar of `StatTile`s keyed by `filter`, a named `role="group"` in equal columns at least `--ui-stat-tile-min` (10rem) wide. An array model lets several be on, a string model one.
10
+ - Add `StackedBar`: the parts of a whole in one 6px bar with a legend. With `total` the rest is shown as free space; without it the parts fill the bar. Each part has a label and a tone (or a CSS `color`); values are formatted with `formatFileSize` unless `format` says otherwise. The whole is one `role="img"` named by every part, the free part and the total, in the UI language.
11
+ - New strings in all nine built-in languages: "Free" and "Total {size}".
12
+
3
13
  ## 0.17.4 (2026-10-28)
4
14
 
5
15
  - `ListItem` takes a `#leading` slot for an icon, avatar or initials tile before the title (`data-ui-list-item-leading`). It does not shrink, and the title, description and extra content keep their room beside it; a list item without it renders as before, inside one more wrapper.
package/README.md CHANGED
@@ -530,7 +530,8 @@ DSM-style application building blocks:
530
530
  - AppRoot (DSM-embedded app root)
531
531
  - AppLayout / AppSidebar / AppToolbar / AppActionBar
532
532
  - PageHeader / SectionTabs
533
- - SplitPane / StorageMeter (see [docs/size-and-split.md](docs/size-and-split.md))
533
+ - Statistic / StatTile / StatTileGroup
534
+ - SplitPane / StorageMeter / StackedBar (see [docs/size-and-split.md](docs/size-and-split.md))
534
535
 
535
536
  `Tabs` and `SectionTabs` move a raised selection notch in 120ms. Selected labels
536
537
  are blue; main labels are bold 14px and section labels bold 13px. `Tabs` fades its
@@ -551,11 +552,51 @@ and End move focus between tabs; Enter or Space selects one. In a grid or flex p
551
552
  </SectionTabs>
552
553
  ```
553
554
 
555
+ Page actions for the shown section go in `#actions`, on the tab row at the
556
+ right edge over the same baseline; when the row is too narrow for both, the
557
+ actions wrap onto a line of their own above the tabs, still right-aligned.
558
+ They are tool buttons ([button policy](docs/button-policy.md)). Attributes stay
559
+ on the strip (`nav`).
560
+
561
+ ```vue
562
+ <SectionTabs v-model="section" :items="sections">
563
+ <template #actions>
564
+ <Button>Export</Button>
565
+ <Button>Check again</Button>
566
+ </template>
567
+ </SectionTabs>
568
+ ```
569
+
554
570
  Navigation-only `SectionTabs` usage still works. For content managed separately
555
571
  by the caller, add `class="ui-tab-panel"` to a panel keyed by the selected value
556
572
  to use the same short fade. These effects and the loading ring respect the
557
573
  system's reduced-motion preference.
558
574
 
575
+ ### StatTile: counts that filter
576
+
577
+ `StatTile` is a KPI tile: a small `label`, the figure (`value`, or the default
578
+ slot) with an optional `unit` word after it, and a `note` (or `#note`). `tone`
579
+ (`neutral`, `info`, `success`, `warning`, `danger`) puts a status dot before
580
+ the label; the label still says what the number means. The app formats the
581
+ value, as for `Statistic`.
582
+
583
+ Without a model it is a plain tile. With `v-model` it is a toggle button
584
+ (`aria-pressed`): Tab reaches it, Enter or Space presses it, it shows the focus
585
+ ring, and a pressed tile has the accent border and a light accent fill.
586
+ `disabled` keeps it in place, dimmed. In a `StatTileGroup` the group owns the
587
+ state and each tile's `filter` is its key: an array model lets several be on
588
+ (a filter bar), a string model or `type="single"` one, and pressing it again
589
+ clears it. The group is a named `role="group"` (`label`) laying the tiles out in
590
+ equal columns at least `--ui-stat-tile-min` (10rem) wide, one per row when
591
+ narrower.
592
+
593
+ ```vue
594
+ <StatTileGroup v-model="filters" label="Filter devices">
595
+ <StatTile filter="outdated" label="Outdated DSM" :value="4" unit="devices" tone="warning" />
596
+ <StatTile filter="failed" label="Failed sign-in" :value="27" unit="attempts" tone="danger" note="Last 24 hours" />
597
+ </StatTileGroup>
598
+ ```
599
+
559
600
  ### Status: StatusDot, StepList, ConnectionTopology
560
601
 
561
602
  `StatusDot` is an 8px tone dot; `pulse` ripples a ring out of it for a state
@@ -8,9 +8,11 @@ type __VLS_Props = {
8
8
  modelValue: string;
9
9
  items: SectionTab[];
10
10
  };
11
- declare var __VLS_2: `panel-${string}`, __VLS_3: {};
11
+ declare var __VLS_7: {}, __VLS_10: `panel-${string}`, __VLS_11: {};
12
12
  type __VLS_Slots = {} & {
13
- [K in NonNullable<typeof __VLS_2>]?: (props: typeof __VLS_3) => any;
13
+ [K in NonNullable<typeof __VLS_10>]?: (props: typeof __VLS_11) => any;
14
+ } & {
15
+ actions?: (props: typeof __VLS_7) => any;
14
16
  };
15
17
  declare const __VLS_base: import('vue').DefineComponent<__VLS_Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {
16
18
  "update:modelValue": (value: string) => any;
@@ -0,0 +1,31 @@
1
+ export type StackedBarTone = 'primary' | 'info' | 'success' | 'warning' | 'danger' | 'neutral';
2
+ export type StackedBarSegment = {
3
+ label: string;
4
+ value: number;
5
+ tone?: StackedBarTone;
6
+ /** A CSS colour for a part no tone fits; it wins over `tone`. */
7
+ color?: string;
8
+ /** Identity for the part's hooks (`data-key`); defaults to its label. */
9
+ key?: string;
10
+ };
11
+ type __VLS_Props = {
12
+ segments: StackedBarSegment[];
13
+ /** The whole, such as the volume's size; what the parts leave is shown as free. */
14
+ total?: number;
15
+ /** Names the bar for assistive technology, before the parts: `Volume 1`. */
16
+ label?: string;
17
+ /** The rest of `total` in the legend and summary; an empty string leaves it out. */
18
+ remainderLabel?: string;
19
+ legend?: boolean;
20
+ /** Formats a value; DSM sizes (`formatFileSize`) by default. */
21
+ format?: (value: number) => string;
22
+ };
23
+ declare const __VLS_export: import('vue').DefineComponent<__VLS_Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
24
+ label: string;
25
+ legend: boolean;
26
+ format: (value: number) => string;
27
+ total: number;
28
+ remainderLabel: string;
29
+ }, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, any>;
30
+ declare const _default: typeof __VLS_export;
31
+ export default _default;
@@ -0,0 +1,42 @@
1
+ export type StatTileTone = 'neutral' | 'info' | 'success' | 'warning' | 'danger';
2
+ type __VLS_Props = {
3
+ label: string;
4
+ value?: string | number;
5
+ /** A word after the figure, in the label's size: `12 devices`. */
6
+ unit?: string;
7
+ note?: string;
8
+ /** A dot before the label; the label still says what the figure means. */
9
+ tone?: StatTileTone;
10
+ /** Pressed state of a standalone filter tile; leave unset for a plain tile. */
11
+ modelValue?: boolean;
12
+ /** The tile's key inside a StatTileGroup. */
13
+ filter?: string;
14
+ disabled?: boolean;
15
+ };
16
+ declare var __VLS_13: {}, __VLS_15: {};
17
+ type __VLS_Slots = {} & {
18
+ default?: (props: typeof __VLS_13) => any;
19
+ } & {
20
+ note?: (props: typeof __VLS_15) => any;
21
+ };
22
+ declare const __VLS_base: import('vue').DefineComponent<__VLS_Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {
23
+ "update:modelValue": (value: boolean) => any;
24
+ }, string, import('vue').PublicProps, Readonly<__VLS_Props> & Readonly<{
25
+ "onUpdate:modelValue"?: ((value: boolean) => any) | undefined;
26
+ }>, {
27
+ filter: string;
28
+ disabled: boolean;
29
+ value: string | number;
30
+ modelValue: boolean;
31
+ tone: StatTileTone;
32
+ unit: string;
33
+ note: string;
34
+ }, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, any>;
35
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
36
+ declare const _default: typeof __VLS_export;
37
+ export default _default;
38
+ type __VLS_WithSlots<T, S> = T & {
39
+ new (): {
40
+ $slots: S;
41
+ };
42
+ };
@@ -0,0 +1,30 @@
1
+ type __VLS_Props = {
2
+ modelValue?: string | string[];
3
+ /** Accessible name for the group (`aria-label`). */
4
+ label?: string;
5
+ /** Defaults to single select, or multi-select when the model is an array. */
6
+ type?: 'single' | 'multiple';
7
+ disabled?: boolean;
8
+ };
9
+ declare var __VLS_10: {};
10
+ type __VLS_Slots = {} & {
11
+ default?: (props: typeof __VLS_10) => any;
12
+ };
13
+ declare const __VLS_base: import('vue').DefineComponent<__VLS_Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {
14
+ "update:modelValue": (value: string | string[]) => any;
15
+ }, string, import('vue').PublicProps, Readonly<__VLS_Props> & Readonly<{
16
+ "onUpdate:modelValue"?: ((value: string | string[]) => any) | undefined;
17
+ }>, {
18
+ label: string;
19
+ type: "single" | "multiple";
20
+ disabled: boolean;
21
+ modelValue: string | string[];
22
+ }, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, any>;
23
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
24
+ declare const _default: typeof __VLS_export;
25
+ export default _default;
26
+ type __VLS_WithSlots<T, S> = T & {
27
+ new (): {
28
+ $slots: S;
29
+ };
30
+ };
@@ -39,6 +39,8 @@ export declare const englishUiText: {
39
39
  readonly "Resize panes": "Resize panes";
40
40
  readonly "Free now": "Free now";
41
41
  readonly "Free after": "Free after";
42
+ readonly Free: "Free";
43
+ readonly "Total {size}": "Total {size}";
42
44
  readonly "At least {size}": "At least {size}";
43
45
  readonly "Free now {now}, free after {after}": "Free now {now}, free after {after}";
44
46
  readonly Sections: "Sections";
package/dist/index.d.ts CHANGED
@@ -127,6 +127,9 @@ export { default as CellText } from './components/composite/table-cell/CellText.
127
127
  export { default as CellStatus } from './components/composite/table-cell/CellStatus.vue';
128
128
  export { default as ListItem } from './components/composite/list-item/ListItem.vue';
129
129
  export { default as Statistic } from './components/composite/statistic/Statistic.vue';
130
+ export { default as StatTile } from './components/composite/stat-tile/StatTile.vue';
131
+ export type { StatTileTone } from './components/composite/stat-tile/StatTile.vue';
132
+ export { default as StatTileGroup } from './components/composite/stat-tile/StatTileGroup.vue';
130
133
  export type { DataTableColumn } from './components/composite/data-table/DataTable.vue';
131
134
  export { default as DataGrid } from './components/composite/data-grid/DataGrid.vue';
132
135
  export type { DataGridColumn, DataGridColumnWidths, DataGridLabels, ResolvedDataGridLabels, DataGridSort, DataGridGroup, DataGridExpandable, DataGridDraggable, DataGridReorder, DataGridCellUpdate, DataGridAdapter, DataGridCellSlotProps } from './components/composite/data-grid/DataGrid.vue';
@@ -199,6 +202,8 @@ export { default as PageHeader } from './components/app/page-header/PageHeader.v
199
202
  export { default as SplitPane } from './components/containers/split-pane/SplitPane.vue';
200
203
  export { default as StorageMeter } from './components/composite/storage-meter/StorageMeter.vue';
201
204
  export type { StorageMeterLabels } from './components/composite/storage-meter/StorageMeter.vue';
205
+ export { default as StackedBar } from './components/composite/stacked-bar/StackedBar.vue';
206
+ export type { StackedBarSegment, StackedBarTone } from './components/composite/stacked-bar/StackedBar.vue';
202
207
  export { default as PageContent } from './components/app/page-content/PageContent.vue';
203
208
  export { default as SectionTabs } from './components/app/section-tabs/SectionTabs.vue';
204
209
  export type { SectionTab } from './components/app/section-tabs/SectionTabs.vue';