srcdev-nuxt-components 9.5.4 → 9.5.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.
@@ -188,6 +188,16 @@ Quick reference:
188
188
  `[role="option"]` if one exists (in `multiple` mode, the first checked item), otherwise the first
189
189
  option (unlike `ActionMenu`, which always focuses the first item since it has no selection state).
190
190
  - **`aria-multiselectable="true"`** is set on the listbox only when `multiple` is `true`.
191
+ - **Selected rows are tinted** via `[aria-selected="true"]` (`--select-menu-item-surface-selected`,
192
+ default `--theme-surface-subtle`), in both single and multiple mode. Hover/focus is declared after
193
+ it at equal specificity, so the hover surface still shows on a selected row. Selected text colour,
194
+ font weight and border colour have their own `-selected` tokens falling back to the resting ones.
195
+ The row border width (`--select-menu-item-border-width`, default `0`) applies to every row with a
196
+ transparent resting colour, so a selected border never shifts layout. A hidden `::after` carrying
197
+ `data-label` in the selected weight reserves the label column's width, so a bolder selected
198
+ weight doesn't resize the popover. Hover/focus has `-text-color-hover` and `-border-hover`, which
199
+ fall back to the row's *current* state (selected or resting), not always to resting. There's no
200
+ hover font-weight token on purpose: the width reserve only covers one alternate weight.
191
201
  - **Chevron rotation is pure CSS** via `:has(.select-menu-popover:popover-open)` on the root — no
192
202
  JS state drives the visual. `isOpen` is still tracked internally, but only to set `aria-expanded`
193
203
  on the trigger.
@@ -28,7 +28,7 @@ for that for a theme switch; use `TripleToggleSwitch` directly for any other thr
28
28
  | `name` | `string` | `"triple-toggle-switch"` | Shared radio `name`. Give each instance on a page its own. |
29
29
  | `aria-label` | `string` | `""` | Accessible name for the `role="radiogroup"`. Omitted from the DOM when empty. Always pass one. |
30
30
  | `theme` | `FormUiTheme` | `"default"` | Rendered as `data-theme`. |
31
- | `step-animation-duration` | `string` | `"250ms"` | Marker slide duration. Ignored under `prefers-reduced-motion`. |
31
+ | `step-animation-duration` | `string` | `"250ms"` | Marker slide duration; also times the icon colour swap (see Behaviour). Ignored under `prefers-reduced-motion`. |
32
32
  | `style-class-passthrough` | `string \| string[]` | `[]` | Classes on the root. |
33
33
 
34
34
  Option `id`s are used as element ids (and as a class on each icon), so they must be unique on the
@@ -66,6 +66,12 @@ const options = ref<IFormMultipleOptions>({
66
66
  - The marker is measured from the first option's width on mount and fades in after ~250ms. It
67
67
  isn't re-measured on resize, so changing the icon-size/padding tokens after mount (e.g. toggling
68
68
  a class) leaves the marker at its old size.
69
+ - Icon colour swaps are timed to the marker: the newly active icon waits half of
70
+ `stepAnimationDuration`, then fades to the active colour over the other half, so it lands as the
71
+ marker arrives rather than turning white on the bare track. The previous icon fades back straight
72
+ away. The marker takes the same time whatever the distance, so no per-index delay is needed.
73
+ - Option circles are sized by their content (1em icon + equal padding) with `place-items: center`,
74
+ not `aspect-ratio`; older iPad Safari mis-centred the icons under the `aspect-ratio` version.
69
75
  - Marker gradients only exist for the values `system`, `light` and `dark`; other values get the
70
76
  plain `--triple-toggle-switch-marker-surface` background.
71
77
 
@@ -49,6 +49,15 @@ global token so it matches the rest of the design system out of the box.
49
49
  | `--select-menu-item-text-color` | `var(--theme-text)` | Option label colour |
50
50
  | `--select-menu-item-font-size` | `1.5rem` | Option label font size |
51
51
  | `--select-menu-item-surface-hover` | `var(--theme-input-surface-hover)` | Option row background on hover/focus |
52
+ | `--select-menu-item-surface-selected` | `var(--theme-surface-subtle)` | Background of selected/checked option rows (hover/focus still wins) |
53
+ | `--select-menu-item-text-color-selected` | `--select-menu-item-text-color` | Selected row label colour (the checkmark follows via `currentcolor`) |
54
+ | `--select-menu-item-font-weight` | inherited | Option row font weight |
55
+ | `--select-menu-item-font-weight-selected` | `--select-menu-item-font-weight` | Selected row font weight; the popover reserves the bolder width, so selecting doesn't resize it |
56
+ | `--select-menu-item-border-width` | `0` | Block (top/bottom) border width on **every** row, so a selected border never shifts layout |
57
+ | `--select-menu-item-border` | `transparent` | Resting row border colour |
58
+ | `--select-menu-item-border-selected` | `--select-menu-item-border` | Selected row border colour. Two adjacent selected rows show both borders where they meet |
59
+ | `--select-menu-item-text-color-hover` | the row's current colour | Label colour on hover/focus. Unset, a selected row keeps its selected colour |
60
+ | `--select-menu-item-border-hover` | the row's current border | Border colour on hover/focus. Unset, a selected row keeps its selected border |
52
61
  | `--select-menu-item-check-size` | `1.6rem` | Checkmark icon box size |
53
62
  | `--select-menu-item-check-color` | `currentcolor` | Checkmark icon colour |
54
63
  | `--select-menu-item-icon-size` | `1.8rem` | Per-option icon size |
@@ -184,4 +193,3 @@ story.
184
193
  the bottom of the viewport (`position-try-fallbacks: flip-block`).
185
194
  - **Chevron rotation** is pure CSS via `:has(.select-menu-popover:popover-open)` — no JS state
186
195
  needed for the visual, though `isOpen` is still tracked internally to drive `aria-expanded`.
187
-
@@ -41,6 +41,7 @@
41
41
  role="option"
42
42
  tabindex="-1"
43
43
  :aria-selected="isSelected(option)"
44
+ :data-label="option.label"
44
45
  @click="selectOption(option)"
45
46
  >
46
47
  <span class="select-menu-item-check" aria-hidden="true">
@@ -343,15 +344,50 @@ watch(
343
344
  gap: var(--select-menu-item-gap, 0.8rem);
344
345
  padding-block: var(--select-menu-item-padding-block, 1rem);
345
346
  padding-inline: var(--select-menu-item-padding-inline, 1.2rem);
347
+ --_text-color: var(--select-menu-item-text-color, var(--theme-text));
348
+ --_border: var(--select-menu-item-border, transparent);
349
+
346
350
  cursor: pointer;
347
- color: var(--select-menu-item-text-color, var(--theme-text));
351
+ color: var(--_text-color);
348
352
  font-family: var(--font-family);
349
353
  font-size: var(--select-menu-item-font-size, 1.5rem);
350
- transition: background-color var(--select-menu-transition-duration, 200ms) ease;
354
+ /* No fallback: unset means invalid at computed time, so the weight inherits. */
355
+ font-weight: var(--select-menu-item-font-weight);
356
+ border-block: var(--select-menu-item-border-width, 0) solid var(--_border);
357
+ transition:
358
+ background-color var(--select-menu-transition-duration, 200ms) ease,
359
+ border-color var(--select-menu-transition-duration, 200ms) ease,
360
+ color var(--select-menu-transition-duration, 200ms) ease;
361
+
362
+ /* Reserves the selected label width so a bolder selected weight doesn't resize the popover. */
363
+ &::after {
364
+ content: attr(data-label);
365
+ grid-column: 3;
366
+ grid-row: 1;
367
+ block-size: 0;
368
+ overflow: hidden;
369
+ visibility: hidden;
370
+ white-space: nowrap;
371
+ font-weight: var(--select-menu-item-font-weight-selected, var(--select-menu-item-font-weight));
372
+ }
373
+
374
+ &[aria-selected="true"] {
375
+ --_text-color: var(
376
+ --select-menu-item-text-color-selected,
377
+ var(--select-menu-item-text-color, var(--theme-text))
378
+ );
379
+ --_border: var(--select-menu-item-border-selected, var(--select-menu-item-border, transparent));
380
+
381
+ background-color: var(--select-menu-item-surface-selected, var(--theme-surface-subtle));
382
+ font-weight: var(--select-menu-item-font-weight-selected, var(--select-menu-item-font-weight));
383
+ }
351
384
 
385
+ /* Hover falls back to the row's current state, so an unset hover token keeps a selected row's colours. */
352
386
  &:hover,
353
387
  &:focus-visible {
354
388
  background-color: var(--select-menu-item-surface-hover, var(--theme-input-surface-hover));
389
+ color: var(--select-menu-item-text-color-hover, var(--_text-color));
390
+ border-color: var(--select-menu-item-border-hover, var(--_border));
355
391
  }
356
392
 
357
393
  &:focus-visible {
@@ -386,6 +422,7 @@ watch(
386
422
 
387
423
  .select-menu-item-label {
388
424
  grid-column: 3;
425
+ grid-row: 1;
389
426
  white-space: nowrap;
390
427
  overflow: hidden;
391
428
  text-overflow: ellipsis;
@@ -6,9 +6,9 @@ exports[`SelectMenu > Snapshots > default 1`] = `
6
6
  </button>
7
7
  <div id="select-menu-v-0-0" popover="" class="select-menu-popover">
8
8
  <ul class="select-menu-list" role="listbox" aria-label="Language">
9
- <li class="select-menu-list-item" role="option" tabindex="-1" aria-selected="false"><span class="select-menu-item-check" aria-hidden="true"><!--v-if--></span><span class="iconify i-flag:gb-4x3 select-menu-item-icon" aria-hidden="true"></span><span class="select-menu-item-label">English</span></li>
10
- <li class="select-menu-list-item" role="option" tabindex="-1" aria-selected="false"><span class="select-menu-item-check" aria-hidden="true"><!--v-if--></span><span class="iconify i-flag:fr-4x3 select-menu-item-icon" aria-hidden="true"></span><span class="select-menu-item-label">Français</span></li>
11
- <li class="select-menu-list-item" role="option" tabindex="-1" aria-selected="false"><span class="select-menu-item-check" aria-hidden="true"><!--v-if--></span><span class="iconify i-flag:de-4x3 select-menu-item-icon" aria-hidden="true"></span><span class="select-menu-item-label">Deutsch</span></li>
9
+ <li class="select-menu-list-item" role="option" tabindex="-1" aria-selected="false" data-label="English"><span class="select-menu-item-check" aria-hidden="true"><!--v-if--></span><span class="iconify i-flag:gb-4x3 select-menu-item-icon" aria-hidden="true"></span><span class="select-menu-item-label">English</span></li>
10
+ <li class="select-menu-list-item" role="option" tabindex="-1" aria-selected="false" data-label="Français"><span class="select-menu-item-check" aria-hidden="true"><!--v-if--></span><span class="iconify i-flag:fr-4x3 select-menu-item-icon" aria-hidden="true"></span><span class="select-menu-item-label">Français</span></li>
11
+ <li class="select-menu-list-item" role="option" tabindex="-1" aria-selected="false" data-label="Deutsch"><span class="select-menu-item-check" aria-hidden="true"><!--v-if--></span><span class="iconify i-flag:de-4x3 select-menu-item-icon" aria-hidden="true"></span><span class="select-menu-item-label">Deutsch</span></li>
12
12
  </ul>
13
13
  </div>
14
14
  </div>"
@@ -21,9 +21,9 @@ exports[`SelectMenu > Snapshots > icon-only trigger 1`] = `
21
21
  </button>
22
22
  <div id="select-menu-v-0-0" popover="" class="select-menu-popover">
23
23
  <ul class="select-menu-list" role="listbox" aria-label="Language">
24
- <li class="select-menu-list-item" role="option" tabindex="-1" aria-selected="true"><span class="select-menu-item-check" aria-hidden="true"><span class="iconify i-lucide:check select-menu-item-check-icon" aria-hidden="true"></span></span><span class="iconify i-flag:gb-4x3 select-menu-item-icon" aria-hidden="true"></span><span class="select-menu-item-label">English</span></li>
25
- <li class="select-menu-list-item" role="option" tabindex="-1" aria-selected="false"><span class="select-menu-item-check" aria-hidden="true"><!--v-if--></span><span class="iconify i-flag:fr-4x3 select-menu-item-icon" aria-hidden="true"></span><span class="select-menu-item-label">Français</span></li>
26
- <li class="select-menu-list-item" role="option" tabindex="-1" aria-selected="false"><span class="select-menu-item-check" aria-hidden="true"><!--v-if--></span><span class="iconify i-flag:de-4x3 select-menu-item-icon" aria-hidden="true"></span><span class="select-menu-item-label">Deutsch</span></li>
24
+ <li class="select-menu-list-item" role="option" tabindex="-1" aria-selected="true" data-label="English"><span class="select-menu-item-check" aria-hidden="true"><span class="iconify i-lucide:check select-menu-item-check-icon" aria-hidden="true"></span></span><span class="iconify i-flag:gb-4x3 select-menu-item-icon" aria-hidden="true"></span><span class="select-menu-item-label">English</span></li>
25
+ <li class="select-menu-list-item" role="option" tabindex="-1" aria-selected="false" data-label="Français"><span class="select-menu-item-check" aria-hidden="true"><!--v-if--></span><span class="iconify i-flag:fr-4x3 select-menu-item-icon" aria-hidden="true"></span><span class="select-menu-item-label">Français</span></li>
26
+ <li class="select-menu-list-item" role="option" tabindex="-1" aria-selected="false" data-label="Deutsch"><span class="select-menu-item-check" aria-hidden="true"><!--v-if--></span><span class="iconify i-flag:de-4x3 select-menu-item-icon" aria-hidden="true"></span><span class="select-menu-item-label">Deutsch</span></li>
27
27
  </ul>
28
28
  </div>
29
29
  </div>"
@@ -33,9 +33,9 @@ exports[`SelectMenu > Snapshots > with a selected value 1`] = `
33
33
  "<div class="select-menu normal" style="--_anchor-name: --select-menu-anchor-v-0-0;"><button popovertarget="select-menu-v-0-0" popovertargetaction="toggle" type="button" class="select-menu-trigger" aria-label="Language" aria-haspopup="listbox" aria-expanded="false"><span class="iconify i-flag:fr-4x3 select-menu-trigger-icon" aria-hidden="true"></span><span class="select-menu-trigger-label">Français</span><span class="iconify i-lucide:chevron-down select-menu-trigger-chevron" aria-hidden="true"></span></button>
34
34
  <div id="select-menu-v-0-0" popover="" class="select-menu-popover">
35
35
  <ul class="select-menu-list" role="listbox" aria-label="Language">
36
- <li class="select-menu-list-item" role="option" tabindex="-1" aria-selected="false"><span class="select-menu-item-check" aria-hidden="true"><!--v-if--></span><span class="iconify i-flag:gb-4x3 select-menu-item-icon" aria-hidden="true"></span><span class="select-menu-item-label">English</span></li>
37
- <li class="select-menu-list-item" role="option" tabindex="-1" aria-selected="true"><span class="select-menu-item-check" aria-hidden="true"><span class="iconify i-lucide:check select-menu-item-check-icon" aria-hidden="true"></span></span><span class="iconify i-flag:fr-4x3 select-menu-item-icon" aria-hidden="true"></span><span class="select-menu-item-label">Français</span></li>
38
- <li class="select-menu-list-item" role="option" tabindex="-1" aria-selected="false"><span class="select-menu-item-check" aria-hidden="true"><!--v-if--></span><span class="iconify i-flag:de-4x3 select-menu-item-icon" aria-hidden="true"></span><span class="select-menu-item-label">Deutsch</span></li>
36
+ <li class="select-menu-list-item" role="option" tabindex="-1" aria-selected="false" data-label="English"><span class="select-menu-item-check" aria-hidden="true"><!--v-if--></span><span class="iconify i-flag:gb-4x3 select-menu-item-icon" aria-hidden="true"></span><span class="select-menu-item-label">English</span></li>
37
+ <li class="select-menu-list-item" role="option" tabindex="-1" aria-selected="true" data-label="Français"><span class="select-menu-item-check" aria-hidden="true"><span class="iconify i-lucide:check select-menu-item-check-icon" aria-hidden="true"></span></span><span class="iconify i-flag:fr-4x3 select-menu-item-icon" aria-hidden="true"></span><span class="select-menu-item-label">Français</span></li>
38
+ <li class="select-menu-list-item" role="option" tabindex="-1" aria-selected="false" data-label="Deutsch"><span class="select-menu-item-check" aria-hidden="true"><!--v-if--></span><span class="iconify i-flag:de-4x3 select-menu-item-icon" aria-hidden="true"></span><span class="select-menu-item-label">Deutsch</span></li>
39
39
  </ul>
40
40
  </div>
41
41
  </div>"
@@ -186,10 +186,9 @@ onMounted(() => {
186
186
  position: relative;
187
187
 
188
188
  .option-group {
189
- aspect-ratio: 1;
190
189
  display: grid;
191
190
  grid-template-areas: "icon-stack";
192
- place-content: center;
191
+ place-items: center;
193
192
  background: transparent;
194
193
  border: var(--form-element-border-width) solid var(--triple-toggle-switch-option-border, #00000025);
195
194
  outline: var(--form-element-outline-width) solid transparent;
@@ -214,10 +213,18 @@ onMounted(() => {
214
213
  grid-area: icon-stack;
215
214
  display: block;
216
215
  font-size: var(--_scheme-icon-font-size);
216
+ width: 1em;
217
+ height: 1em;
217
218
  color: var(--triple-toggle-switch-option-icon-color, var(--slate-10));
219
+ transition: color calc(v-bind(stepAnimationDuration) / 2) ease-in-out;
218
220
 
219
221
  &.active {
220
222
  color: var(--triple-toggle-switch-option-icon-color-active, var(--slate-00));
223
+ transition-delay: calc(v-bind(stepAnimationDuration) / 2);
224
+ }
225
+
226
+ @media (prefers-reduced-motion: reduce) {
227
+ transition: none;
221
228
  }
222
229
 
223
230
  &:hover {
@@ -227,9 +234,10 @@ onMounted(() => {
227
234
 
228
235
  .option-input {
229
236
  grid-area: icon-stack;
237
+ appearance: none;
230
238
  opacity: 0;
231
- aspect-ratio: 1;
232
239
  width: var(--_scheme-icon-font-size);
240
+ height: var(--_scheme-icon-font-size);
233
241
 
234
242
  &:hover {
235
243
  cursor: pointer;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "srcdev-nuxt-components",
3
3
  "type": "module",
4
- "version": "9.5.4",
4
+ "version": "9.5.5",
5
5
  "main": "nuxt.config.ts",
6
6
  "types": "types.d.ts",
7
7
  "license": "MIT",