@synopackageland/ui 0.17.13 → 0.17.15

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.
@@ -29,18 +29,38 @@ These rules keep pages built from `@synopackageland/ui` consistent. The componen
29
29
  - Labels sit above their controls (`Form direction="vertical"`), except in short DSM-style dialogs.
30
30
  - Size a field by its content: number fields are 128px; text fields use `fieldWidth`. Put two short fields side by side rather than stretching one across the page.
31
31
  - A checkbox's text sits on the same line as its box. Do not apply `display: grid` to `label` in App CSS; `Checkbox` renders its own label.
32
+ - For 2–4 mutually exclusive settings, use `RadioGroup` (vertical by default, `orientation="horizontal"` when labels fit). In a wizard step, `variant="card"` draws the options as choice cards with an optional `icon` each. A checkbox enables an independent option; a switch turns a feature on or off immediately. Keep the circular radio with a dot, square checkbox with a tick, and pill switch with a moving thumb.
33
+ - Reserve `SegmentControl` for toolbar view switching: its selected item is a primary-filled capsule. `variant="sheet"` and `SectionTabs` are navigation tabs. Do not use either as a form value selector.
32
34
  - Choices side by side are 34px apart (`--ui-choice-inline-gap`, DSM's Task Scheduler) and share one top whether checked or not. For a set of checkboxes use `CheckboxGroup` (`orientation="horizontal"` for a row, `v-model` an array of values), as `RadioGroup` for one choice; Checkboxes written one after another get the same gap. Do not add margins between them.
33
35
  - A password field has a show/hide toggle; `Input type="password"` adds it.
34
36
  - Show a NAS path with `PathDisplay`, not a read-only input. It truncates from the start, shows the full path in a tooltip when it is cut, and offers copy. In a table cell use `display="name"`: the folder's name on one line, the full path always in its tooltip, copy still copies the full path.
35
37
 
38
+ ### Settings choice example
39
+
40
+ ```vue
41
+ <FormItem label="Domain and LDAP people">
42
+ <RadioGroup
43
+ v-model="directoryReadMode"
44
+ :options="[
45
+ { value: 'lookup', label: 'When someone looks them up' },
46
+ { value: 'never', label: 'Not read' },
47
+ ]"
48
+ />
49
+ </FormItem>
50
+ ```
51
+
52
+ The setting is a form value, saved with the page's Apply action. It does not navigate between views.
53
+
36
54
  ## Settings pages
37
55
 
56
+ - Use `<SectionTabs fill keep-mounted>` for settings with local unsaved drafts. `keep-mounted` mounts every supplied item panel immediately and hides inactive panels with `v-show`; their effects stay active. Without it, switching tabs unmounts the previous panel. `fill` alone only controls layout. Keep persistent business data and background work in the app when needed.
57
+ - `SettingsPage` spaces direct sibling `SettingsSection`s by `--ui-space-6` (24px); place them directly in its default slot without a `Space` wrapper. `Fieldset` keeps its own DSM spacing.
38
58
  - A settings page has one label column. `FormItem` (horizontal), `SettingsRow` and `KeyValueRow` share `--ui-label-column` (`--ui-label-width`, at most 40% of a narrow row) and `--ui-label-gap`, so SDK panels and App rows line up; `FormActions inset` starts at the same edge. Labels and `KeyValueRow` values break between words, not inside one. Do not pass a different `labelWidth` per section.
39
59
  - Labels sit left in the column, as on DSM's own settings pages: the eye runs down one edge, and a long label wraps instead of pushing the value.
40
60
  - Colours are fixed by role: section title `--ui-text` semibold 14px, label and value `--ui-text`, help text `--ui-text-secondary` 12px.
41
61
  - A `SettingsRow` with a `description` aligns its label with the control's first line, not the middle of control and description.
42
62
  - A row that is only a button: give it a `SettingsRow` label when it acts on one thing, or put it in the section `#footer`. Inside a horizontal form, use `FormActions inset` so the button starts on the value edge.
43
- - A DSM-native settings page reads its structure from indentation and spacing (Control Panel > Security; measurements in [dsm-native-metrics.md](dsm-native-metrics.md#settings-page-control-panel--security-network)). Each section is a `Fieldset`: a 15px blue title over a dashed divider across the whole width, no chevron (`collapsible` adds one, as Control Panel > Network). The title text and the fields start 8px in; the next section's title follows 8px after the body. A one-line explanation of the section is the Fieldset's `description`, directly under the title and across the whole width, not in the label column. Fields are one `Form` with one `labelWidth` (or the theme's column) and `FormItem`s; one `Form` may hold several Fieldsets.
63
+ - A DSM-native settings page reads its structure from indentation and spacing (Control Panel > Security; measurements in [dsm-native-metrics.md](dsm-native-metrics.md#settings-page-control-panel--security-network)). Each section is a `Fieldset`: a 15px blue title over a dashed divider across the whole width, collapsible and expanded by default, with a chevron pointing up when expanded and down when collapsed (as Control Panel > Network). Use `:collapsible="false"` for a fixed section without a chevron (as Control Panel > Security). The title text and the fields start 8px in; the next section's title follows 8px after the body. A one-line explanation of the section is the Fieldset's `description`, directly under the title and across the whole width, not in the label column. Fields are one `Form` with one `labelWidth` (or the theme's column) and `FormItem`s; one `Form` may hold several Fieldsets.
44
64
  - A checkbox option is a `FormItem :label="false"` with a `Checkbox`: the box sits on the section's left edge and its help text (`description`) is a line of its own under the label text. Do not put a label beside a checkbox or a switch that already says what it does.
45
65
  - A read-only value is a `FormItem` with `text-only`: plain text in the control column, level with its label. A button that acts on it (Edit) goes in the item's `#after` slot and follows the field column.
46
66
  - Options that only matter while a checkbox or switch is on go in a `FormGroup` right after it, with `:disabled="!on"`. The parent is a `FormItem :label="false"`, so it starts at the section's left edge. The group indents one 28px step, disables and dims every control inside, and the labels inside give up the indent so the controls stay on the form's column, as DSM draws them. Nest a `FormGroup` for a second level. Do not indent with your own padding or disable each child by hand.
@@ -65,7 +85,7 @@ These rules keep pages built from `@synopackageland/ui` consistent. The componen
65
85
  ## Fields
66
86
 
67
87
  - A field with buttons acting on it (a URL and its Install button) goes in `InputGroup`: one line, 8px gap, the field takes the room left.
68
- - Stack page sections with `Space direction="column"` and a pixel `spacing`; add `wrap` to a row of tags or buttons that may run out of room.
88
+ - Outside `SettingsPage`, stack page sections with `Space direction="column"` and a pixel `spacing`; add `wrap` to a row of tags or buttons that may run out of room.
69
89
 
70
90
  ## Numbers and times
71
91
 
package/docs/wizard.md CHANGED
@@ -53,6 +53,12 @@ const open = ref(false)
53
53
  - **Text.** `description` is one short line at the top of the step, under the
54
54
  hero, without a closing period. Keep the content to the controls the step
55
55
  needs; it may be wide (a row of cards) or a form.
56
+ - **Choices.** A step's 2–4 options are choice cards:
57
+ `<RadioGroup variant="card" orientation="horizontal" :options>`. Each card
58
+ shows the option's `icon` in a tile, its label and one line, and keeps the
59
+ radio dot; the whole card picks it and the chosen card takes the primary
60
+ border and a soft fill. The cards share the row (180px at least) and wrap
61
+ in a narrow window.
56
62
  - **Types.** `welcome` offers only Start; `done` drops Back and Cancel, fills
57
63
  the progress and turns the main action into Finish. The last step without
58
64
  `next-step-key` turns it into Apply.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@synopackageland/ui",
3
- "version": "0.17.13",
3
+ "version": "0.17.15",
4
4
  "description": "Shared Vue 3 UI component library with a DSM 7 inspired application theme",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -52,6 +52,48 @@
52
52
  "./themes/dsm7-embedded-reset.css": "./dist/themes/dsm7-embedded-reset.css",
53
53
  "./themes/dsm7-embedded-theme.css": "./dist/themes/dsm7-embedded-theme.css"
54
54
  },
55
+ "scripts": {
56
+ "dev": "vite build --watch",
57
+ "build": "vite build && vite build --mode json && vite build --mode rich-text && vite build --mode cli && vite build --mode preview && vite build --mode embedded && node scripts/postbuild.mjs",
58
+ "lint": "eslint .",
59
+ "typecheck": "vue-tsc --noEmit -p tsconfig.json",
60
+ "test": "vitest run",
61
+ "test:watch": "vitest",
62
+ "test:changed": "echo \"test:changed skips the tests the changes since ${SYNOPKGLAND_GATE_BASE:-origin/master} do not reach (vitest --changed); pnpm check runs them all\" && vitest run --changed ${SYNOPKGLAND_GATE_BASE:-origin/master}",
63
+ "story": "histoire dev",
64
+ "story:build": "histoire build",
65
+ "check:host": "node scripts/dsm-host-shots.mjs",
66
+ "check:switch": "node scripts/check-switch.mjs",
67
+ "check:tabs": "node scripts/check-tabs.mjs",
68
+ "check:narrow": "node scripts/check-narrow-controls.mjs",
69
+ "check:responsive": "node scripts/check-responsive.mjs",
70
+ "check:adaptive": "node scripts/check-adaptive.mjs",
71
+ "check:sidebar-focus": "node scripts/check-sidebar-focus.mjs",
72
+ "check:json-render": "node scripts/check-json-render.mjs",
73
+ "check:motion": "node scripts/check-motion.mjs",
74
+ "check:topology": "node scripts/check-topology.mjs",
75
+ "check:wizard": "node scripts/check-wizard.mjs",
76
+ "check:edges": "node scripts/check-edges.mjs",
77
+ "check:data-grid": "node scripts/check-data-grid.mjs",
78
+ "check:truncation": "node scripts/check-truncation.mjs",
79
+ "check:link": "node scripts/check-link.mjs",
80
+ "check:text-select": "node scripts/check-text-select.mjs",
81
+ "check:date-picker": "node scripts/check-date-picker.mjs",
82
+ "check:full-page": "node scripts/check-full-page.mjs",
83
+ "check:internal": "node --test scripts/check-internal-content.test.mjs scripts/check-npm-metadata.test.mjs && node scripts/check-internal-content.mjs --repo .",
84
+ "check:npm-metadata": "node scripts/check-npm-metadata.mjs",
85
+ "check:package": "node scripts/check-package-content.mjs",
86
+ "notices:update": "node scripts/third-party-notices.mjs --write",
87
+ "notices:check": "node scripts/third-party-notices.mjs --check",
88
+ "check": "bash scripts/docker-check.sh 'pnpm check:internal && pnpm build && node scripts/run-parallel.mjs lint typecheck test && pnpm check:package'",
89
+ "check:fast": "bash scripts/docker-check.sh 'pnpm check:internal && pnpm build && node scripts/run-parallel.mjs lint typecheck test:changed && pnpm check:package'",
90
+ "check:local-browser": "node scripts/app-local-browser.mjs",
91
+ "check:infotip": "node scripts/check-infotip.mjs",
92
+ "release:stage": "node scripts/stage-release.mjs",
93
+ "check:polish": "bash scripts/docker-check.sh --build --out .polish-shots 'node scripts/check-polish.mjs'",
94
+ "check:acceptance": "node scripts/check-acceptance.mjs",
95
+ "check:palette": "node scripts/check-palette.mjs"
96
+ },
55
97
  "peerDependencies": {
56
98
  "vue": "^3.5.0"
57
99
  },
@@ -71,9 +113,42 @@
71
113
  "@tiptap/vue-3": "3.32.1",
72
114
  "zod": "^4.6.5"
73
115
  },
116
+ "devDependencies": {
117
+ "@eslint/js": "10.0.1",
118
+ "@histoire/plugin-vue": "1.0.0-beta.1",
119
+ "@tailwindcss/vite": "4.3.3",
120
+ "@vitejs/plugin-vue": "6.0.9",
121
+ "@vue/test-utils": "2.5.1",
122
+ "eslint": "10.11.0",
123
+ "eslint-plugin-vue": "10.11.1",
124
+ "flexsearch": "0.8.212",
125
+ "globals": "17.12.0",
126
+ "histoire": "1.0.0-beta.1",
127
+ "jsdom": "30.1.1",
128
+ "playwright": "1.58.2",
129
+ "reka-ui": "2.10.5",
130
+ "tailwindcss": "4.3.3",
131
+ "typescript": "5.9.3",
132
+ "typescript-eslint": "8.71.0",
133
+ "vite": "7.3.6",
134
+ "vite-plugin-dts": "5.1.1",
135
+ "vitest": "5.0.2",
136
+ "vscode-oniguruma": "2.0.1",
137
+ "vscode-textmate": "9.3.2",
138
+ "vue": "3.5.43",
139
+ "vue-eslint-parser": "10.4.1",
140
+ "vue-tsc": "3.3.11"
141
+ },
74
142
  "engines": {
75
143
  "node": ">=20"
76
144
  },
145
+ "packageManager": "pnpm@10.33.2",
146
+ "pnpm": {
147
+ "onlyBuiltDependencies": [
148
+ "esbuild",
149
+ "vue-demi"
150
+ ]
151
+ },
77
152
  "config": {
78
153
  "bundledRuntime": {
79
154
  "reka-ui": "2.10.5"