@synopackageland/ui 0.25.9 → 0.25.11

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.
@@ -263,6 +263,7 @@ layout only sizes and moves the region). `v-model:aside` is its state:
263
263
  | `collapsed` (default) | the 48px rail | takes the rest |
264
264
  | `open` | `v-model:aside-width` (380, 320–560; the handle on its start edge, Arrow keys, Home and End) | takes the rest |
265
265
  | `open` that would leave the page under 480px, or outside `web` | the 48px rail; the panel floats over the page (`overlay`) | unchanged |
266
+ | `open` in a DSM window with `aside-dock="wide"`, at least 960px wide | as in `web`: `v-model:aside-width` with the handle, unless the page would be left under 480px beside the theme's sidebar | takes the rest |
266
267
  | `expanded` | the whole content area beside the sidebar | `inert`, kept mounted |
267
268
 
268
269
  On a phone the region has no width; its content places itself (a button and a
@@ -298,7 +299,7 @@ const { state, width } = useAsidePreference('studio.aside', 'editor', { state: '
298
299
  | Mode | When | Panel |
299
300
  | --- | --- | --- |
300
301
  | docked | `web`, the page keeps 480px | keeps `--ui-aside-open-width` and slides by `translate` while the region's width moves (`--ui-motion-panel`, ease-in-out both ways); the rail button fades in 150ms into a collapse |
301
- | floating | an open panel the page has no room for, or a 641–959 container | slides over the page from the rail (in `panel` ease-out, out `normal` ease-in); the region keeps its 48px |
302
+ | floating | an open panel the page has no room for, a 641–959 container, or a DSM window without `aside-dock="wide"` | slides over the page from the rail (in `panel` ease-out, out `normal` ease-in); the region keeps its 48px |
302
303
  | sheet | a phone (≤640) | a 48px button at the end corner (above the tab bar and the safe area) opens a 90% bottom sheet; `expanded` is full screen; the scrim, Escape and a downward swipe on the header close it; the page is `aria-hidden` and out of reach |
303
304
 
304
305
  - The panel is never unmounted: collapsed, it is `inert` and `aria-hidden`, and the thread's scroll and the composer's draft stay. The page is `inert` and `aria-hidden` while the panel is expanded (it has no width then). While a sheet is up the page is `aria-hidden` but not `inert`: the sheet keeps it out of reach as an app-local dialog does (docs/app-local-modal.md).
@@ -24,7 +24,7 @@ are in [dsm-native-metrics.md](dsm-native-metrics.md).
24
24
  | Form or window footer | `FormActions`, `AppActionBar`, `Footbar`, `Panel` `#fbar` | capsule | Reset `secondary`, then Apply `primary` |
25
25
  | Notification | `Notification` `confirm` / `cancel` | capsule | Cancel `secondary`, then the action `primary` |
26
26
  | Toolbar | `AppToolbar`, a row above a list | tool | `secondary`; `SplitButton` for Create and its variants |
27
- | Page header | `PageHeader` `#actions` | tool | one refresh `IconButton` per page |
27
+ | Page header | `PageHeader` `#actions`, the SDK `AppShell`'s `#actions` | tool | `secondary`, only the page's own actions (Add); no refresh |
28
28
  | Tab row | `SectionTabs` `#actions` | tool | `secondary`, for the shown section (Export, Check again) |
29
29
  | Section or card | `SettingsSection` / `Card` body, `#actions`, `#footer` | tool | `secondary`; a Save / Cancel row there goes in `FormActions` |
30
30
  | Beside a field | `InputGroup` | tool | `secondary` (Open, Copy, Test) |
@@ -19,7 +19,7 @@ These rules keep pages built from `@synopackageland/ui` consistent. The componen
19
19
  - Buttons that belong together sit in one row with an 8px gap: `FormActions` in a form, the `#footer` slot in a section or card.
20
20
  - Only the bar that closes a dialog or form draws capsule `action` buttons, without a `kind`: `FormActions`, `Footbar`, `AppActionBar`, a `Notification`'s actions, and the footers of `Dialog`, `Wizard`, `Sheet` and `Panel` (`#fbar`), with the main action last. `kind="tool"` opts one button out. A `SettingsSection` or `Card` footer, header actions and content stay `tool` buttons; put a section's Save / Cancel in `FormActions`.
21
21
  - A settings tab's Reset / Apply go in `SettingsPage`'s `#footer`: it stays at the bottom over a divider while only the sections scroll. Do not write your own sticky footer.
22
- - Each page has one refresh, with the page's other buttons: in the bar above the page (the SDK `AppShell`'s `#actions`), or in `PageHeader` where a page draws one. Panels expose `refresh()` for it instead of their own button.
22
+ - A page's header actions (the SDK `AppShell`'s `#actions`, or `PageHeader` `#actions` where a page draws one) hold only the page's own actions, such as Add. There is no page-wide refresh: a page reads its data again on `ctx.reopen` and whenever it is shown, and a failed read puts Retry next to its error. The SDK `AppShell` draws no bar above the page while its `#actions` is empty.
23
23
  - A disabled primary button keeps readable text. Put the reason next to it, such as "Enter the password to confirm."
24
24
  - Danger actions sit apart from the rest: the explanation comes first, then the button, or a confirm dialog.
25
25
  - Return the promise from a `Button` or `IconButton` click handler (`@click="save"` with an `async save`): the button shows a spinner, keeps its width and ignores further clicks until the promise settles. Use the `loading` prop only for work the button did not start.
@@ -42,7 +42,7 @@ the commit footer behave as before.
42
42
  | `--ui-radius-md` / `-lg` (and the 0.23.9 roles on them) | 4 / 6 | 12 / 14: md rounds the control, container and popover roles (fields, tool buttons, inset blocks, menus), lg the panel and nav roles |
43
43
  | `--ui-radius-dialog` / `-window` / `-sheet` | 8 / 8 / 12 | 24 |
44
44
  | Primary, danger and secondary buttons | capsule (action) or 4px (tool) | capsule; a primary's fill is accent step 10 (`#0075db`, 4.6:1 with white) |
45
- | Segmented control | accent pill on a framed track, equal columns | a pill in the primary button's fill (accent step 10, `#0075db`, with the accent's contrast colour, white: 4.6:1, light and dark) on a frameless mist track; 6px sides; up to three segments stay equal columns but one whose label is wider than its share grows to it, so a label is not cut (four ellipsize as before) (`check:phone-layout` checks it) |
45
+ | Segmented control | accent pill on a framed track, equal columns | a pill in the primary button's fill (accent step 10, `#0075db`, with the accent's contrast colour, white: 4.6:1, light and dark) on a frameless mist track; 6px sides; up to four segments stay equal columns but one whose label is wider than its share grows to it, so a label is not cut; labels too wide together scroll the track sideways (`check:phone-layout` checks it) |
46
46
  | Phone bar | white with a hairline | the page's colour, no hairline, 17px bold title, round pressed tint |
47
47
  | Tab bar | full-width white row with a top rule | a floating white pill inset 16px, 8px above the bottom (`--ui-tab-bar-float`); the current tab's icon is white on a round pad in the primary's fill (accent step 10); a tab with a label and no icon takes accent step 10 on its label over the mist pad |
48
48
  | `--ui-text-muted` | 40% grey (2:1) | 80% (4.8:1 on the mist; dark 62%) |
@@ -68,6 +68,18 @@ Numeric preset rows are at least 44px tall on touch. The rich text toolbar
68
68
  counts its 44px touch buttons when deciding which tools fit; the rest move
69
69
  into the existing More menu.
70
70
 
71
+ On a touch phone (`pointer: coarse`) the UI draws no `::-webkit-scrollbar`:
72
+ Chromium, Android included, turns any styled webkit bar into a classic one
73
+ that takes its width from the scroller, which left the right margin 10px
74
+ short of the left. Scrollers keep the browser's overlay bar, and a Select or
75
+ Combobox list a thin one. A natural-height page chain (`flex: 0 0 auto`)
76
+ keeps the full width of a flex row such as `ListDetail` (`inline-size:
77
+ stretch`), so a list is never shrunk to its content. A `SearchField`
78
+ (`data-ui-search-field`), alone or in a wrapper holding only it, grows to its
79
+ row and drops a fixed basis or `max-width`. A DataGrid group row's
80
+ `#group-title` wraps instead of running over the row's links. A page's
81
+ toolbar and header actions wrap within the page.
82
+
71
83
  `pnpm check:mobile` checks the gallery at both phone and tablet sizes. It is
72
84
  a blocking step of `gates:full`; the basic gate selection stays the same.
73
85
  Any remaining audit exceptions are bounded in
@@ -396,6 +408,12 @@ context menu for now; it becomes a phone sheet once pickers move to sheets.
396
408
  The keyboard depends on each field's type, so these are component defaults,
397
409
  not tokens.
398
410
 
411
+ A press on a text field (an `input` that takes text, a `textarea`, editable
412
+ content) is left to the browser's own focus. Android hides the soft keyboard
413
+ it just raised when script focuses the field during the press, so the app
414
+ root's focus handling focuses only buttons, links and other controls on
415
+ pointerdown.
416
+
399
417
  ### Keyboard hints by type
400
418
 
401
419
  `Input` sets these from its `type`, and `SearchField` from `search`. An
@@ -752,6 +770,11 @@ change: the same slot moves.
752
770
  name too long for the screen ends in an ellipsis inside the pill.
753
771
  - Rare or destructive items belong in `headerActions` ("…" in the bar), not
754
772
  in the page actions.
773
+ - Only actions float. While the actions hold anything else (a status badge, a
774
+ count, a date, a field), also content that arrives later through an App's
775
+ own teleport, they stay in the page's own row, which wraps, and no FAB is
776
+ drawn, so nothing floats over the page's rows. Put a page's status in the
777
+ page's meta (the SDK `PageInfo`), not in its actions.
755
778
  - `phone-actions` on `AppLayout`, and on a `PageHeader`, `AppToolbar` or
756
779
  `PushTransition` for one page: `fab` (default), `bar` (icons in the bar) or `inline` (the page's own header row).
757
780
  - `PageFab` picks the FAB explicitly: `<PageFab><Button variant="primary">…</Button></PageFab>`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@synopackageland/ui",
3
- "version": "0.25.9",
3
+ "version": "0.25.11",
4
4
  "description": "Shared Vue 3 UI component library with a DSM 7 inspired application theme",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -60,6 +60,67 @@
60
60
  "./themes/dsm7-embedded-reset.css": "./dist/themes/dsm7-embedded-reset.css",
61
61
  "./themes/dsm7-embedded-theme.css": "./dist/themes/dsm7-embedded-theme.css"
62
62
  },
63
+ "scripts": {
64
+ "check:docs": "node --test scripts/check-doc-versions.test.mjs && node scripts/check-doc-versions.mjs",
65
+ "dev": "vite build --watch",
66
+ "build": "vite build && vite build --mode json && vite build --mode rich-text && vite build --mode grid && vite build --mode cli && vite build --mode preview && vite build --mode embedded && node scripts/postbuild.mjs",
67
+ "lint": "eslint .",
68
+ "typecheck": "vue-tsc --noEmit -p tsconfig.json",
69
+ "test": "vitest run",
70
+ "test:watch": "vitest",
71
+ "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}",
72
+ "story": "histoire dev",
73
+ "story:build": "histoire build",
74
+ "check:host": "node scripts/dsm-host-shots.mjs",
75
+ "check:switch": "node scripts/check-switch.mjs",
76
+ "check:tabs": "node scripts/check-tabs.mjs",
77
+ "check:mobile": "node scripts/check-mobile-overflow.mjs",
78
+ "check:ui-patch": "node scripts/check-ui-patch.mjs",
79
+ "check:narrow": "node scripts/check-narrow-controls.mjs",
80
+ "check:drawer-form": "node scripts/check-drawer-form.mjs",
81
+ "check:responsive": "node scripts/check-responsive.mjs",
82
+ "check:adaptive": "node scripts/check-adaptive.mjs",
83
+ "check:sidebar-focus": "node scripts/check-sidebar-focus.mjs",
84
+ "check:json-render": "node scripts/check-json-render.mjs",
85
+ "check:motion": "node scripts/check-motion.mjs",
86
+ "check:topology": "node scripts/check-topology.mjs",
87
+ "check:wizard": "node scripts/check-wizard.mjs",
88
+ "check:press": "node scripts/check-press.mjs",
89
+ "check:edges": "node scripts/check-edges.mjs",
90
+ "check:data-grid": "node scripts/check-data-grid.mjs",
91
+ "check:truncation": "node scripts/check-truncation.mjs",
92
+ "check:link": "node scripts/check-link.mjs",
93
+ "check:text-select": "node scripts/check-text-select.mjs",
94
+ "check:date-picker": "node scripts/check-date-picker.mjs",
95
+ "check:full-page": "node scripts/check-full-page.mjs",
96
+ "check:short-viewport": "node scripts/check-short-viewport.mjs",
97
+ "check:phone-layout": "node scripts/check-phone-layout.mjs",
98
+ "check:phone-bars": "node scripts/check-phone-bars.mjs",
99
+ "check:phone-fill": "node scripts/check-phone-fill.mjs",
100
+ "check:text-zoom": "node scripts/check-text-zoom.mjs",
101
+ "check:focus-restore": "node scripts/check-focus-restore.mjs",
102
+ "check:detail-surface": "node scripts/check-detail-surface.mjs",
103
+ "check:internal": "node --test scripts/check-internal-content.test.mjs scripts/check-npm-metadata.test.mjs && node scripts/check-internal-content.mjs --repo .",
104
+ "check:npm-metadata": "node scripts/check-npm-metadata.mjs",
105
+ "check:package": "node scripts/check-package-content.mjs",
106
+ "trace:restyle": "node scripts/trace-restyle.mjs",
107
+ "check:public-api-consumer": "node scripts/check-public-api-consumer.mjs",
108
+ "notices:update": "node scripts/third-party-notices.mjs --write",
109
+ "notices:check": "node scripts/third-party-notices.mjs --check",
110
+ "check": "bash scripts/docker-check.sh \"npm run gates\"",
111
+ "check:fast": "bash scripts/docker-check.sh \"npm run gates\"",
112
+ "check:local-browser": "node scripts/app-local-browser.mjs",
113
+ "check:infotip": "node scripts/check-infotip.mjs",
114
+ "release:stage": "node scripts/stage-release.mjs",
115
+ "check:polish": "bash scripts/docker-check.sh --build --out .polish-shots 'node scripts/check-polish.mjs'",
116
+ "check:acceptance": "node scripts/check-acceptance.mjs",
117
+ "check:palette": "node scripts/check-palette.mjs",
118
+ "gates": "node scripts/gates.mjs",
119
+ "gates:full": "node scripts/gates.mjs --full",
120
+ "check:layout": "node scripts/check-layout.mjs",
121
+ "release:smoke": "node scripts/release-smoke.mjs",
122
+ "check:browser-install": "playwright install chromium webkit"
123
+ },
63
124
  "peerDependencies": {
64
125
  "vue": "^3.5.0"
65
126
  },
@@ -79,9 +140,44 @@
79
140
  "@tiptap/vue-3": "3.32.1",
80
141
  "zod": "^4.6.5"
81
142
  },
143
+ "devDependencies": {
144
+ "@eslint/js": "10.0.1",
145
+ "@histoire/plugin-vue": "1.0.0-beta.1",
146
+ "@tailwindcss/vite": "4.3.3",
147
+ "@tanstack/vue-virtual": "3.13.39",
148
+ "@vitejs/plugin-vue": "6.0.9",
149
+ "@vue/test-utils": "2.5.1",
150
+ "@vueuse/core": "14.4.0",
151
+ "eslint": "10.11.0",
152
+ "eslint-plugin-vue": "10.11.1",
153
+ "flexsearch": "0.8.212",
154
+ "globals": "17.12.0",
155
+ "histoire": "1.0.0-beta.1",
156
+ "jsdom": "30.1.1",
157
+ "playwright": "1.58.2",
158
+ "reka-ui": "2.11.0",
159
+ "tailwindcss": "4.3.3",
160
+ "typescript": "5.9.3",
161
+ "typescript-eslint": "8.71.0",
162
+ "vite": "7.3.6",
163
+ "vite-plugin-dts": "5.1.1",
164
+ "vitest": "5.0.2",
165
+ "vscode-oniguruma": "2.0.1",
166
+ "vscode-textmate": "9.3.2",
167
+ "vue": "3.5.43",
168
+ "vue-eslint-parser": "10.4.1",
169
+ "vue-tsc": "3.3.11"
170
+ },
82
171
  "engines": {
83
172
  "node": ">=20"
84
173
  },
174
+ "packageManager": "pnpm@10.33.2",
175
+ "pnpm": {
176
+ "onlyBuiltDependencies": [
177
+ "esbuild",
178
+ "vue-demi"
179
+ ]
180
+ },
85
181
  "config": {
86
182
  "bundledRuntime": {
87
183
  "@tanstack/vue-virtual": "3.13.39",