@pienter/ui 0.17.0 → 0.19.0
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 +66 -0
- package/CONVENTIONS.md +89 -53
- package/components/feedback/toast/Toast.vue +4 -1
- package/components/feedback/toast/ToastHost.vue +5 -0
- package/components/form/checkbox/checkbox.css +4 -3
- package/components/form/number-field/NumberField.vue +15 -3
- package/components/form/number-field/number-field.css +3 -2
- package/components/form/radio-group/radio-group.css +1 -0
- package/components/form/switch/switch.css +1 -0
- package/components/layout/index/Index.vue +109 -27
- package/components/layout/index/index.css +18 -0
- package/components/layout/index/{useIndex.ts → useIndexQuery.ts} +62 -8
- package/components/layout/index-filters/FilterCheckbox.vue +29 -0
- package/components/layout/index-filters/FilterMultiSelect.vue +110 -0
- package/components/layout/index-filters/FilterRange.vue +80 -0
- package/components/layout/index-filters/FilterSelect.vue +38 -0
- package/components/layout/index-filters/filters.css +65 -0
- package/components/layout/index-filters/useFilterControl.ts +40 -0
- package/components/layout/table/DataTable.vue +10 -0
- package/components/layout/table/Table.vue +4 -1
- package/components/navigation/breadcrumb/Breadcrumb.vue +9 -4
- package/components/navigation/pagination/Pagination.vue +12 -3
- package/package.json +6 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,56 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
## 0.19.0 - 2026-09-16
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- The English accessibility text the icon-only controls and landmarks used
|
|
10
|
+
to hardcode is now a prop with that text as its default, following
|
|
11
|
+
`AppLayout`'s `skipLabel` / `drawerLabel` / `navigationLabel`, so a
|
|
12
|
+
single-language consumer can name them in its own language. `Pagination`
|
|
13
|
+
takes `label` (the `<nav>` landmark, `Pagination`), `previousLabel`
|
|
14
|
+
(`Previous page`) and `nextLabel` (`Next page`); `Breadcrumb` takes
|
|
15
|
+
`label` (`Breadcrumb`); `NumberField` takes `increaseLabel` (`Increase`)
|
|
16
|
+
and `decreaseLabel` (`Decrease`); `Table` takes `selectAllLabel`
|
|
17
|
+
(`Select all rows`), which `DataTable` forwards alongside its own
|
|
18
|
+
`selectRowLabel`, a string or a function of the row that replaces the
|
|
19
|
+
default `Select <first cell>` name; `Toast` takes `closeLabel` (`Close`),
|
|
20
|
+
and `ToastHost` takes the same `closeLabel` for every toast it renders
|
|
21
|
+
next to its existing `label` for the notifications region.
|
|
22
|
+
`PaginationFooter` has no text of its own and is unchanged.
|
|
23
|
+
|
|
24
|
+
## 0.18.0 - 2026-09-16
|
|
25
|
+
|
|
26
|
+
### Changed
|
|
27
|
+
|
|
28
|
+
- `NumberField` takes `steppers` (default `true`); `false` renders a plain
|
|
29
|
+
number input without the +/− column.
|
|
30
|
+
|
|
31
|
+
### Fixed
|
|
32
|
+
|
|
33
|
+
- `Checkbox`, `RadioGroup` and `Switch` inputs are their declared em size
|
|
34
|
+
again. The base `input, textarea, select` rule padded them by `--space-s`,
|
|
35
|
+
which inflated a 1.15em checkbox to 35px; all three reset `padding` to 0.
|
|
36
|
+
|
|
37
|
+
### Added
|
|
38
|
+
|
|
39
|
+
- `FilterCheckbox`, `FilterSelect`, `FilterMultiSelect` and `FilterRange`
|
|
40
|
+
(`@pienter/ui/components/Filter*.vue`), the filter controls an index
|
|
41
|
+
definition declares. Each binds to the index that owns the query — the
|
|
42
|
+
state `Index` provides to its `filters` slot, the one a definition provides
|
|
43
|
+
with `provideIndexQuery`, or an explicit `state` prop — and reads and
|
|
44
|
+
writes only its own filter names; mounted without a state it warns once
|
|
45
|
+
and does nothing. The checkbox writes `'true'` or deletes; the select
|
|
46
|
+
prepends an `emptyLabel` option that deletes; the multi-select is a
|
|
47
|
+
fieldset of checkboxes whose legend reads `Label (n)` with a Clear while
|
|
48
|
+
`n > 0`, optional per-option counts, an optional client-side search, and
|
|
49
|
+
values joined on the comma convention; the range is two NumberFields
|
|
50
|
+
without steppers writing `<name>_min` and `<name>_max` on change, each
|
|
51
|
+
cleared on its own.
|
|
52
|
+
`injectIndexQuery()` joins the composable exports for a control that needs
|
|
53
|
+
the provided state without throwing when there is none.
|
|
54
|
+
|
|
5
55
|
## 0.17.0 - 2026-09-15
|
|
6
56
|
|
|
7
57
|
### Added
|
|
@@ -15,6 +65,22 @@
|
|
|
15
65
|
the allowlist are unchanged. `splitFilterValues('')` is `[]` and
|
|
16
66
|
`joinFilterValues([])` is `undefined`, so clearing deletes the parameter
|
|
17
67
|
rather than sending an empty string. See ADR 0009.
|
|
68
|
+
- `useIndexQuery`, `provideIndexQuery` and `useIndexFilters` in
|
|
69
|
+
`@pienter/ui/composables/useIndexQuery`. `useIndexQuery` is the query state
|
|
70
|
+
`Index` has always owned — query, rows, meta, loading, errors, the setters,
|
|
71
|
+
`reload` and `reset` — exported so an index definition can create it, pass
|
|
72
|
+
it to `Index` through the new `state` prop and share it with filter
|
|
73
|
+
controls rendered outside `Index`, such as a page sidebar. `Index` provides
|
|
74
|
+
its state to its subtree, and `useIndexFilters()` gives a control the small
|
|
75
|
+
surface it needs: `filters`, `filterNames`, `loading`, `setFilter`,
|
|
76
|
+
`setFilters`, `clearFilters`. Without `state` nothing changes; `load` and
|
|
77
|
+
`queryOptions` are required unless `state` is passed.
|
|
78
|
+
- `Index` shows its active filters as a chips row between the toolbar and the
|
|
79
|
+
table: one chip per filter value (a comma-separated multi-value filter is
|
|
80
|
+
one chip per value), each with a "Remove <label> <value>" button, and a
|
|
81
|
+
Clear all that empties `filters` only. New `filterLabels` and
|
|
82
|
+
`filterValueLabels` props name the chips; the raw name and value are the
|
|
83
|
+
fallback.
|
|
18
84
|
|
|
19
85
|
## 0.16.0 - 2026-09-15
|
|
20
86
|
|
package/CONVENTIONS.md
CHANGED
|
@@ -60,6 +60,7 @@ Current consumers:
|
|
|
60
60
|
- `components/form/select/` — `Select` + `Segmented` (the segmented control is a tab-like single-select visual; shares form-primitive scaffolding with Select; will be retrofit in Phase 4)
|
|
61
61
|
- `components/action/button/` — `Button` + `IconButton` (the icon-only control is a square button. `button.css` shares the base/variant/size/state/focus rules across both via a `.pui-btn, .pui-icon-btn` selector group; a `.pui-btn`-only block holds the label, link variant, block layout, and loading fade that must not reach the icon button; a `.pui-icon-btn` rule adds the square box)
|
|
62
62
|
- `components/feedback/toast/` — `Toast` + `ToastHost` (Toast renders one notification; ToastHost orchestrates the visible family and owns the shared `pui-toast-region` block in `toast.css`)
|
|
63
|
+
- `components/layout/index-filters/` — `FilterCheckbox` + `FilterSelect` + `FilterMultiSelect` + `FilterRange` (the filter controls of an index definition; one binding composable and the fieldset chrome the two grouped controls share in `filters.css`)
|
|
63
64
|
|
|
64
65
|
Rules:
|
|
65
66
|
|
|
@@ -1253,59 +1254,63 @@ Each component keeps its own audit next to its source, so a decision and the
|
|
|
1253
1254
|
code it governs move in the same diff. Add an entry when you add a component;
|
|
1254
1255
|
follow the shape of an existing one.
|
|
1255
1256
|
|
|
1256
|
-
| Component
|
|
1257
|
-
|
|
|
1258
|
-
| Accordion
|
|
1259
|
-
| Alert
|
|
1260
|
-
| AlertDialog
|
|
1261
|
-
| AppLayout
|
|
1262
|
-
| Avatar
|
|
1263
|
-
| AvatarStack
|
|
1264
|
-
| Badge
|
|
1265
|
-
| Breadcrumb
|
|
1266
|
-
| Button
|
|
1267
|
-
| Card
|
|
1268
|
-
| Checkbox
|
|
1269
|
-
| Collapsible
|
|
1270
|
-
| Combobox
|
|
1271
|
-
| Command
|
|
1272
|
-
| DataTable
|
|
1273
|
-
| DateInput
|
|
1274
|
-
| DropdownMenu
|
|
1275
|
-
| Empty
|
|
1276
|
-
|
|
|
1277
|
-
|
|
|
1278
|
-
|
|
|
1279
|
-
|
|
|
1280
|
-
|
|
|
1281
|
-
|
|
|
1282
|
-
|
|
|
1283
|
-
|
|
|
1284
|
-
|
|
|
1285
|
-
|
|
|
1286
|
-
|
|
|
1287
|
-
|
|
|
1288
|
-
|
|
|
1289
|
-
|
|
|
1290
|
-
|
|
|
1291
|
-
|
|
|
1292
|
-
|
|
|
1293
|
-
|
|
|
1294
|
-
|
|
|
1295
|
-
|
|
|
1296
|
-
|
|
|
1297
|
-
|
|
|
1298
|
-
|
|
|
1299
|
-
|
|
|
1300
|
-
|
|
|
1301
|
-
|
|
|
1302
|
-
|
|
|
1303
|
-
|
|
|
1304
|
-
|
|
|
1305
|
-
|
|
|
1306
|
-
|
|
|
1307
|
-
|
|
|
1308
|
-
|
|
|
1257
|
+
| Component | Audit |
|
|
1258
|
+
| ----------------- | ------------------------------------------------------------------------------------------ |
|
|
1259
|
+
| Accordion | [`components/layout/accordion/AUDIT.md`](./components/layout/accordion/AUDIT.md) |
|
|
1260
|
+
| Alert | [`components/feedback/alert/AUDIT.md`](./components/feedback/alert/AUDIT.md) |
|
|
1261
|
+
| AlertDialog | [`components/overlay/alert-dialog/AUDIT.md`](./components/overlay/alert-dialog/AUDIT.md) |
|
|
1262
|
+
| AppLayout | [`components/layout/app-layout/AUDIT.md`](./components/layout/app-layout/AUDIT.md) |
|
|
1263
|
+
| Avatar | [`components/display/avatar/AUDIT.md`](./components/display/avatar/AUDIT.md) |
|
|
1264
|
+
| AvatarStack | [`components/display/avatar/AUDIT.md`](./components/display/avatar/AUDIT.md) |
|
|
1265
|
+
| Badge | [`components/display/badge/AUDIT.md`](./components/display/badge/AUDIT.md) |
|
|
1266
|
+
| Breadcrumb | [`components/navigation/breadcrumb/AUDIT.md`](./components/navigation/breadcrumb/AUDIT.md) |
|
|
1267
|
+
| Button | [`components/action/button/AUDIT.md`](./components/action/button/AUDIT.md) |
|
|
1268
|
+
| Card | [`components/layout/card/AUDIT.md`](./components/layout/card/AUDIT.md) |
|
|
1269
|
+
| Checkbox | [`components/form/checkbox/AUDIT.md`](./components/form/checkbox/AUDIT.md) |
|
|
1270
|
+
| Collapsible | [`components/layout/collapsible/AUDIT.md`](./components/layout/collapsible/AUDIT.md) |
|
|
1271
|
+
| Combobox | [`components/form/combobox/AUDIT.md`](./components/form/combobox/AUDIT.md) |
|
|
1272
|
+
| Command | [`components/overlay/command/AUDIT.md`](./components/overlay/command/AUDIT.md) |
|
|
1273
|
+
| DataTable | [`components/layout/table/AUDIT.md`](./components/layout/table/AUDIT.md) |
|
|
1274
|
+
| DateInput | [`components/form/date-input/AUDIT.md`](./components/form/date-input/AUDIT.md) |
|
|
1275
|
+
| DropdownMenu | [`components/overlay/dropdown-menu/AUDIT.md`](./components/overlay/dropdown-menu/AUDIT.md) |
|
|
1276
|
+
| Empty | [`components/display/empty/AUDIT.md`](./components/display/empty/AUDIT.md) |
|
|
1277
|
+
| FilterCheckbox | [`components/layout/index-filters/AUDIT.md`](./components/layout/index-filters/AUDIT.md) |
|
|
1278
|
+
| FilterMultiSelect | [`components/layout/index-filters/AUDIT.md`](./components/layout/index-filters/AUDIT.md) |
|
|
1279
|
+
| FilterRange | [`components/layout/index-filters/AUDIT.md`](./components/layout/index-filters/AUDIT.md) |
|
|
1280
|
+
| FilterSelect | [`components/layout/index-filters/AUDIT.md`](./components/layout/index-filters/AUDIT.md) |
|
|
1281
|
+
| Form | [`components/form/form/AUDIT.md`](./components/form/form/AUDIT.md) |
|
|
1282
|
+
| Icon | [`components/display/icon/AUDIT.md`](./components/display/icon/AUDIT.md) |
|
|
1283
|
+
| IconButton | [`components/action/button/AUDIT.md`](./components/action/button/AUDIT.md) |
|
|
1284
|
+
| InputOTP | [`components/form/input-otp/AUDIT.md`](./components/form/input-otp/AUDIT.md) |
|
|
1285
|
+
| Label | [`components/form/label/AUDIT.md`](./components/form/label/AUDIT.md) |
|
|
1286
|
+
| Modal | [`components/overlay/modal/AUDIT.md`](./components/overlay/modal/AUDIT.md) |
|
|
1287
|
+
| Navbar | [`components/navigation/navbar/AUDIT.md`](./components/navigation/navbar/AUDIT.md) |
|
|
1288
|
+
| NumberField | [`components/form/number-field/AUDIT.md`](./components/form/number-field/AUDIT.md) |
|
|
1289
|
+
| PageAside | [`components/layout/page-aside/AUDIT.md`](./components/layout/page-aside/AUDIT.md) |
|
|
1290
|
+
| Pagination | [`components/navigation/pagination/AUDIT.md`](./components/navigation/pagination/AUDIT.md) |
|
|
1291
|
+
| Panel | [`components/layout/record-layout/AUDIT.md`](./components/layout/record-layout/AUDIT.md) |
|
|
1292
|
+
| Popover | [`components/overlay/popover/AUDIT.md`](./components/overlay/popover/AUDIT.md) |
|
|
1293
|
+
| Progress | [`components/feedback/progress/AUDIT.md`](./components/feedback/progress/AUDIT.md) |
|
|
1294
|
+
| RadioGroup | [`components/form/radio-group/AUDIT.md`](./components/form/radio-group/AUDIT.md) |
|
|
1295
|
+
| Segmented | [`components/form/select/AUDIT.md`](./components/form/select/AUDIT.md) |
|
|
1296
|
+
| Select | [`components/form/select/AUDIT.md`](./components/form/select/AUDIT.md) |
|
|
1297
|
+
| Separator | [`components/layout/separator/AUDIT.md`](./components/layout/separator/AUDIT.md) |
|
|
1298
|
+
| Sheet | [`components/overlay/sheet/AUDIT.md`](./components/overlay/sheet/AUDIT.md) |
|
|
1299
|
+
| Sidebar | [`components/navigation/sidebar/AUDIT.md`](./components/navigation/sidebar/AUDIT.md) |
|
|
1300
|
+
| Skeleton | [`components/feedback/skeleton/AUDIT.md`](./components/feedback/skeleton/AUDIT.md) |
|
|
1301
|
+
| Slider | [`components/form/slider/AUDIT.md`](./components/form/slider/AUDIT.md) |
|
|
1302
|
+
| Spinner | [`components/feedback/spinner/AUDIT.md`](./components/feedback/spinner/AUDIT.md) |
|
|
1303
|
+
| Switch | [`components/form/switch/AUDIT.md`](./components/form/switch/AUDIT.md) |
|
|
1304
|
+
| Table | [`components/layout/table/AUDIT.md`](./components/layout/table/AUDIT.md) |
|
|
1305
|
+
| Tabs | [`components/navigation/tabs/AUDIT.md`](./components/navigation/tabs/AUDIT.md) |
|
|
1306
|
+
| TagsInput | [`components/form/tags-input/AUDIT.md`](./components/form/tags-input/AUDIT.md) |
|
|
1307
|
+
| Textarea | [`components/form/textarea/AUDIT.md`](./components/form/textarea/AUDIT.md) |
|
|
1308
|
+
| TextInput | [`components/form/text-input/AUDIT.md`](./components/form/text-input/AUDIT.md) |
|
|
1309
|
+
| Toast | [`components/feedback/toast/AUDIT.md`](./components/feedback/toast/AUDIT.md) |
|
|
1310
|
+
| ToastHost | [`components/feedback/toast/AUDIT.md`](./components/feedback/toast/AUDIT.md) |
|
|
1311
|
+
| Toggle | [`components/action/toggle/AUDIT.md`](./components/action/toggle/AUDIT.md) |
|
|
1312
|
+
| ToggleGroup | [`components/action/toggle-group/AUDIT.md`](./components/action/toggle-group/AUDIT.md) |
|
|
1313
|
+
| Tooltip | [`components/overlay/tooltip/AUDIT.md`](./components/overlay/tooltip/AUDIT.md) |
|
|
1309
1314
|
|
|
1310
1315
|
## Form submit response contract
|
|
1311
1316
|
|
|
@@ -1470,6 +1475,37 @@ value is a key prefix: `sync-query="contacts"` reads and writes `contacts.page`,
|
|
|
1470
1475
|
`contacts.search`, `contacts.filter[...]` and so on, so a related index shares
|
|
1471
1476
|
its parent page's URL without touching the page's own parameters.
|
|
1472
1477
|
|
|
1478
|
+
That query state is a composable, `useIndexQuery({ load, queryOptions,
|
|
1479
|
+
syncQuery, searchDebounce })` from `@pienter/ui/composables/useIndexQuery`.
|
|
1480
|
+
Index calls it when given `load` and `queryOptions`; an index definition
|
|
1481
|
+
whose filter controls sit outside Index's subtree (a page sidebar) calls it
|
|
1482
|
+
itself, passes the result as `state`, and shares it with
|
|
1483
|
+
`provideIndexQuery(state)`. A control reads `useIndexFilters()` — `filters`,
|
|
1484
|
+
`filterNames`, `loading`, `setFilter`, `setFilters`, `clearFilters` — from
|
|
1485
|
+
the injected state, so the same control works in the `filters` slot, where
|
|
1486
|
+
Index provides its own state, or anywhere the definition provides one. The
|
|
1487
|
+
`filters` slot stays for the toolbar. Index shows the active filters as a
|
|
1488
|
+
chips row above the table: one chip per value, split on the comma convention
|
|
1489
|
+
(ADR 0009), each with a remove button, plus Clear all, which empties
|
|
1490
|
+
`filters` and nothing else. `filterLabels` and `filterValueLabels` name the
|
|
1491
|
+
chips the way `sortLabels` names the sort select.
|
|
1492
|
+
|
|
1493
|
+
The controls a definition declares are `FilterCheckbox` (`name`, `label`;
|
|
1494
|
+
`'true'` or deleted), `FilterSelect` (`name`, `label`, `options`, an
|
|
1495
|
+
`emptyLabel` option that deletes), `FilterMultiSelect` (`name`, `label`,
|
|
1496
|
+
`options` with an optional `count`, `searchable`; a fieldset whose legend
|
|
1497
|
+
counts the selected values, with a Clear, joining values on the comma
|
|
1498
|
+
convention) and `FilterRange` (`name`, `label`, `min`, `max`, `step`; two
|
|
1499
|
+
NumberFields writing `<name>_min` and `<name>_max` on change). Each binds
|
|
1500
|
+
through `useIndexFilters` to the provided state, or to a `state` prop, and
|
|
1501
|
+
touches only its own names; without a state it warns and does nothing. On a
|
|
1502
|
+
module index they live in the `PageAside`: the definition renders them
|
|
1503
|
+
inside `<PageAside title="Filters">` beside `<Index :state>`, both under the
|
|
1504
|
+
component that created and provided the state, and the aside's content grid
|
|
1505
|
+
stacks them. The `filters` slot stays for a toolbar placement; elsewhere a
|
|
1506
|
+
column of them is a consumer grid with a spacing token for its gap. Options
|
|
1507
|
+
and counts are the consumer's (`CONTEXT.md`: Facet).
|
|
1508
|
+
|
|
1473
1509
|
`placement` selects the chrome for the two CMS placements (`CONTEXT.md`, ADR
|
|
1474
1510
|
0008), exposed as `data-placement` on `.pui-index`. `module` (default) is the
|
|
1475
1511
|
page itself: an `h1` header above a divider, an unboxed toolbar, the table with
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
v-if="dismissible"
|
|
20
20
|
class="pui-toast__close"
|
|
21
21
|
type="button"
|
|
22
|
-
aria-label="
|
|
22
|
+
:aria-label="closeLabel"
|
|
23
23
|
@click="$emit('dismiss')"
|
|
24
24
|
>
|
|
25
25
|
<Icon name="x" size="sm" />
|
|
@@ -48,6 +48,8 @@ const props = withDefaults(
|
|
|
48
48
|
dismissible?: boolean;
|
|
49
49
|
icon?: IconName;
|
|
50
50
|
action?: { label: string };
|
|
51
|
+
/** Accessible name of the icon-only close button. */
|
|
52
|
+
closeLabel?: string;
|
|
51
53
|
}>(),
|
|
52
54
|
{
|
|
53
55
|
tone: undefined,
|
|
@@ -55,6 +57,7 @@ const props = withDefaults(
|
|
|
55
57
|
dismissible: true,
|
|
56
58
|
icon: undefined,
|
|
57
59
|
action: undefined,
|
|
60
|
+
closeLabel: 'Close',
|
|
58
61
|
},
|
|
59
62
|
);
|
|
60
63
|
|
|
@@ -17,11 +17,15 @@ interface Timer {
|
|
|
17
17
|
const props = withDefaults(
|
|
18
18
|
defineProps<{
|
|
19
19
|
controller?: ToastController;
|
|
20
|
+
/** Accessible name of the notifications region. */
|
|
20
21
|
label?: string;
|
|
22
|
+
/** Accessible name of every toast's close button. */
|
|
23
|
+
closeLabel?: string;
|
|
21
24
|
}>(),
|
|
22
25
|
{
|
|
23
26
|
controller: () => defaultController,
|
|
24
27
|
label: 'Notifications',
|
|
28
|
+
closeLabel: 'Close',
|
|
25
29
|
},
|
|
26
30
|
);
|
|
27
31
|
const items = computed(() => props.controller.visible.value);
|
|
@@ -151,6 +155,7 @@ onBeforeUnmount(() => {
|
|
|
151
155
|
:dismissible="item.dismissible"
|
|
152
156
|
:icon="item.icon"
|
|
153
157
|
:action="item.action"
|
|
158
|
+
:close-label="closeLabel"
|
|
154
159
|
aria-keyshortcuts="Escape"
|
|
155
160
|
@dismiss="dismiss(item.id)"
|
|
156
161
|
@action="runAction(item)"
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
appearance: none;
|
|
4
4
|
flex: none;
|
|
5
5
|
margin: 0;
|
|
6
|
+
padding: 0;
|
|
6
7
|
width: 1.15em;
|
|
7
8
|
height: 1.15em;
|
|
8
9
|
border: var(--stroke-md) solid var(--border-clr-strong);
|
|
@@ -60,18 +61,18 @@
|
|
|
60
61
|
}
|
|
61
62
|
|
|
62
63
|
/* The label is the click target for the box, so it reads as one. */
|
|
63
|
-
.pui-field:has(.pui-checkbox) .pui-field__label {
|
|
64
|
+
.pui-field:has(> .pui-checkbox) > .pui-field__label {
|
|
64
65
|
cursor: pointer;
|
|
65
66
|
user-select: none;
|
|
66
67
|
}
|
|
67
68
|
|
|
68
69
|
/* Mute the label + cursor when the input is disabled. */
|
|
69
|
-
.pui-field:has(.pui-checkbox:disabled) .pui-field__label {
|
|
70
|
+
.pui-field:has(> .pui-checkbox:disabled) > .pui-field__label {
|
|
70
71
|
color: var(--text-clr-muted);
|
|
71
72
|
cursor: not-allowed;
|
|
72
73
|
}
|
|
73
74
|
|
|
74
|
-
.pui-field[data-readonly='true']:has(.pui-checkbox) .pui-field__label {
|
|
75
|
+
.pui-field[data-readonly='true']:has(> .pui-checkbox) > .pui-field__label {
|
|
75
76
|
cursor: default;
|
|
76
77
|
}
|
|
77
78
|
}
|
|
@@ -35,12 +35,15 @@
|
|
|
35
35
|
@input="onInput"
|
|
36
36
|
@blur="emit('blur')"
|
|
37
37
|
/>
|
|
38
|
-
<div
|
|
38
|
+
<div
|
|
39
|
+
v-if="!readonly && steppers"
|
|
40
|
+
class="pui-number-field__steppers"
|
|
41
|
+
>
|
|
39
42
|
<button
|
|
40
43
|
type="button"
|
|
41
44
|
class="pui-number-field__step"
|
|
42
45
|
data-direction="increment"
|
|
43
|
-
aria-label="
|
|
46
|
+
:aria-label="increaseLabel"
|
|
44
47
|
:disabled="disabled"
|
|
45
48
|
@click="handleStep('increment')"
|
|
46
49
|
>
|
|
@@ -50,7 +53,7 @@
|
|
|
50
53
|
type="button"
|
|
51
54
|
class="pui-number-field__step"
|
|
52
55
|
data-direction="decrement"
|
|
53
|
-
aria-label="
|
|
56
|
+
:aria-label="decreaseLabel"
|
|
54
57
|
:disabled="disabled"
|
|
55
58
|
@click="handleStep('decrement')"
|
|
56
59
|
>
|
|
@@ -95,6 +98,12 @@ const props = withDefaults(
|
|
|
95
98
|
disabled?: boolean;
|
|
96
99
|
/** Read-only: the value shows in the field chrome without steppers, stays focusable and cannot be edited. */
|
|
97
100
|
readonly?: boolean;
|
|
101
|
+
/** The +/− buttons beside the input; off, the field is a plain number input. */
|
|
102
|
+
steppers?: boolean;
|
|
103
|
+
/** Accessible name of the + stepper. */
|
|
104
|
+
increaseLabel?: string;
|
|
105
|
+
/** Accessible name of the − stepper. */
|
|
106
|
+
decreaseLabel?: string;
|
|
98
107
|
hint?: string;
|
|
99
108
|
errors?: string[];
|
|
100
109
|
status?: 'error' | 'success';
|
|
@@ -112,6 +121,9 @@ const props = withDefaults(
|
|
|
112
121
|
required: false,
|
|
113
122
|
disabled: false,
|
|
114
123
|
readonly: false,
|
|
124
|
+
steppers: true,
|
|
125
|
+
increaseLabel: 'Increase',
|
|
126
|
+
decreaseLabel: 'Decrease',
|
|
115
127
|
hint: undefined,
|
|
116
128
|
errors: () => [],
|
|
117
129
|
status: undefined,
|
|
@@ -42,8 +42,9 @@
|
|
|
42
42
|
margin: 0;
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
-
/*
|
|
46
|
-
.pui-field
|
|
45
|
+
/* Without a stepper column the input keeps its own corners. */
|
|
46
|
+
.pui-number-field:not(:has(.pui-number-field__steppers))
|
|
47
|
+
.pui-number-field__input {
|
|
47
48
|
border-top-right-radius: var(--radius-sm);
|
|
48
49
|
border-bottom-right-radius: var(--radius-sm);
|
|
49
50
|
}
|