srcdev-nuxt-components 9.5.5 → 9.5.7

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.
Files changed (98) hide show
  1. package/.claude/skills/component-compliance-checklist.md +6 -2
  2. package/.claude/skills/components/action-menu.md +21 -15
  3. package/.claude/skills/components/deep-expanding-menu.md +18 -6
  4. package/.claude/skills/components/display-tooltip-defined.md +2 -1
  5. package/.claude/skills/components/display-tooltip.md +10 -4
  6. package/.claude/skills/components/navigation-items.md +1 -0
  7. package/.claude/skills/components/opening-hours.md +12 -0
  8. package/.claude/skills/components/pop-over.md +11 -8
  9. package/.claude/skills/components/price-list.md +10 -1
  10. package/.claude/skills/components/responsive-header.md +25 -0
  11. package/.claude/skills/components/select-menu.md +18 -8
  12. package/.claude/skills/components/site-header.md +2 -0
  13. package/.claude/skills/components/ui-block-decorated.md +7 -0
  14. package/.claude/skills/composable-anchored-popover.md +108 -0
  15. package/.claude/skills/composable-tooltips-guide.md +3 -1
  16. package/.claude/skills/index.md +1 -0
  17. package/.claude/skills/storybook-add-story.md +14 -0
  18. package/.vscode/srcdev-component-responsive-header.code-snippets +3 -1
  19. package/.vscode/srcdev-component-site-header.code-snippets +3 -1
  20. package/app/assets/styles/setup/06.utility-classes/animations/_animation-scroller-x.css +5 -3
  21. package/app/assets/styles/setup/06.utility-classes/animations/_auto-rotate.css +5 -3
  22. package/app/assets/styles/setup/06.utility-classes/animations/_entry-exit-blur.css +5 -3
  23. package/app/assets/styles/setup/06.utility-classes/animations/_entry-slide-in.css +5 -3
  24. package/app/assets/styles/setup/06.utility-classes/animations/_entry-zoom-reveal.css +5 -3
  25. package/app/components/01.atoms/animations/entry/CONSUMER-STYLING.md +6 -2
  26. package/app/components/01.atoms/display-tooltip/CONSUMER-STYLING.md +15 -3
  27. package/app/components/01.atoms/display-tooltip/DisplayTooltip.vue +62 -3
  28. package/app/components/01.atoms/display-tooltip/tests/DisplayTooltip.spec.ts +36 -1
  29. package/app/components/01.atoms/display-tooltip/tests/__snapshots__/DisplayTooltip.spec.ts.snap +1 -1
  30. package/app/components/01.atoms/navigation/skip-links/SkipLinks.vue +1 -1
  31. package/app/components/01.atoms/pop-over/CONSUMER-STYLING.md +9 -3
  32. package/app/components/01.atoms/pop-over/PopOver.vue +70 -9
  33. package/app/components/01.atoms/pop-over/tests/PopOver.spec.ts +53 -0
  34. package/app/components/01.atoms/pop-over/tests/__snapshots__/PopOver.spec.ts.snap +1 -1
  35. package/app/components/01.atoms/ui-block-decorated/CONSUMER-STYLING.md +12 -4
  36. package/app/components/01.atoms/ui-block-decorated/UiBlockDecorated.vue +20 -16
  37. package/app/components/01.atoms/ui-block-decorated/stories/UiBlockDecorated.stories.ts +124 -96
  38. package/app/components/02.molecules/action-menu/ActionMenu.vue +41 -16
  39. package/app/components/02.molecules/action-menu/CONSUMER-STYLING.md +16 -3
  40. package/app/components/02.molecules/action-menu/tests/ActionMenu.spec.ts +28 -0
  41. package/app/components/02.molecules/action-menu/tests/__snapshots__/ActionMenu.spec.ts.snap +3 -3
  42. package/app/components/02.molecules/display-tooltip-defined/DisplayTooltipDefined.vue +2 -1
  43. package/app/components/02.molecules/display-tooltip-defined/stories/DisplayTooltipDefined.stories.ts +7 -4
  44. package/app/components/02.molecules/display-tooltip-defined/tests/DisplayTooltipDefined.spec.ts +20 -1
  45. package/app/components/02.molecules/display-tooltip-defined/tests/__snapshots__/DisplayTooltipDefined.spec.ts.snap +1 -1
  46. package/app/components/02.molecules/navigation/deep-expanding-menu/CONSUMER-STYLING.md +18 -4
  47. package/app/components/02.molecules/navigation/deep-expanding-menu/DeepExpandingMenu.vue +87 -16
  48. package/app/components/02.molecules/navigation/deep-expanding-menu/tests/DeepExpandingMenu.spec.ts +83 -1
  49. package/app/components/02.molecules/navigation/deep-expanding-menu/tests/__snapshots__/DeepExpandingMenu.spec.ts.snap +2 -2
  50. package/app/components/02.molecules/navigation/site-navigation/SiteNavigation.vue +1 -1
  51. package/app/components/02.molecules/navigation/tab-navigation/TabNavigation.vue +1 -1
  52. package/app/components/02.molecules/opening-hours/CONSUMER-STYLING.md +11 -1
  53. package/app/components/02.molecules/opening-hours/OpeningHours.vue +71 -43
  54. package/app/components/02.molecules/opening-hours/stories/OpeningHours.stories.ts +138 -6
  55. package/app/components/02.molecules/opening-hours/tests/OpeningHours.spec.ts +53 -0
  56. package/app/components/02.molecules/opening-hours/tests/__snapshots__/OpeningHours.spec.ts.snap +1 -1
  57. package/app/components/02.molecules/opening-hours/tests/buildOpeningHoursSpecification.spec.ts +37 -1
  58. package/app/components/02.molecules/price-list/CONSUMER-STYLING.md +17 -5
  59. package/app/components/02.molecules/price-list/PriceList.vue +32 -9
  60. package/app/components/02.molecules/price-list/stories/PriceList.stories.ts +125 -29
  61. package/app/components/02.molecules/price-list/tests/PriceList.spec.ts +20 -0
  62. package/app/components/02.molecules/select-menu/CONSUMER-STYLING.md +17 -5
  63. package/app/components/02.molecules/select-menu/SelectMenu.vue +51 -16
  64. package/app/components/02.molecules/select-menu/tests/SelectMenu.spec.ts +36 -0
  65. package/app/components/03.organisms/google-reviews/stories/GoogleReviews.stories.ts +9 -4
  66. package/app/components/03.organisms/responsive-header/CONSUMER-STYLING.md +14 -0
  67. package/app/components/03.organisms/responsive-header/NavigationItems.vue +23 -14
  68. package/app/components/03.organisms/responsive-header/ResponsiveHeader.vue +58 -30
  69. package/app/components/03.organisms/responsive-header/stories/ResponsiveHeader.stories.ts +149 -18
  70. package/app/components/03.organisms/responsive-header/tests/.nuxt/app.config.mjs +21 -0
  71. package/app/components/03.organisms/responsive-header/tests/.nuxt/components.d.ts +66 -0
  72. package/app/components/03.organisms/responsive-header/tests/.nuxt/imports.d.ts +30 -0
  73. package/app/components/03.organisms/responsive-header/tests/.nuxt/manifest/meta/test.json +1 -0
  74. package/app/components/03.organisms/responsive-header/tests/.nuxt/types/app.config.d.ts +35 -0
  75. package/app/components/03.organisms/responsive-header/tests/.nuxt/types/build.d.ts +23 -0
  76. package/app/components/03.organisms/responsive-header/tests/.nuxt/types/builder-env.d.ts +1 -0
  77. package/app/components/03.organisms/responsive-header/tests/.nuxt/types/components.d.ts +71 -0
  78. package/app/components/03.organisms/responsive-header/tests/.nuxt/types/imports.d.ts +386 -0
  79. package/app/components/03.organisms/responsive-header/tests/.nuxt/types/middleware.d.ts +11 -0
  80. package/app/components/03.organisms/responsive-header/tests/.nuxt/types/modules.d.ts +79 -0
  81. package/app/components/03.organisms/responsive-header/tests/.nuxt/types/nitro-layouts.d.ts +17 -0
  82. package/app/components/03.organisms/responsive-header/tests/.nuxt/types/nitro-nuxt.d.ts +64 -0
  83. package/app/components/03.organisms/responsive-header/tests/.nuxt/types/plugins.d.ts +29 -0
  84. package/app/components/03.organisms/responsive-header/tests/.nuxt/types/runtime-config.d.ts +32 -0
  85. package/app/components/03.organisms/responsive-header/tests/.nuxt/types/shared-imports.d.ts +10 -0
  86. package/app/components/03.organisms/responsive-header/tests/.nuxt/types/vue-shim.d.ts +0 -0
  87. package/app/components/03.organisms/responsive-header/tests/NavigationItems.spec.ts +16 -0
  88. package/app/components/03.organisms/responsive-header/tests/ResponsiveHeader.spec.ts +91 -6
  89. package/app/components/03.organisms/responsive-header/tests/__snapshots__/ResponsiveHeader.spec.ts.snap +9 -9
  90. package/app/components/03.organisms/responsive-header/tests/node_modules/.cache/nuxt/chrome-workspace.json +1 -0
  91. package/app/components/03.organisms/site-header/SiteHeader.vue +8 -0
  92. package/app/components/03.organisms/site-header/tests/__snapshots__/SiteHeader.spec.ts.snap +1 -1
  93. package/app/composables/tests/useAnchoredPopover.spec.ts +231 -0
  94. package/app/composables/tests/useTooltips.spec.ts +69 -0
  95. package/app/composables/useAnchoredPopover.ts +183 -0
  96. package/app/composables/useTooltips.ts +37 -20
  97. package/app/utils/opening-hours.ts +23 -2
  98. package/package.json +1 -1
@@ -13,7 +13,8 @@ skip silently. Notes marked **Existing component** only apply when migrating.
13
13
 
14
14
  A component passes when its Component Ledger row (`node .claude/component-ledger/build.mjs`, then
15
15
  `.claude/component-ledger/audit.json`) shows `score: 5`, a real tier, and `variants`, `legacy_props`,
16
- `story_args_bug`, `eslint_issues`, `redundant_priv_tokens` and `styling_doc_outdated` all `false`.
16
+ `story_args_bug`, `eslint_issues`, `redundant_priv_tokens`, `styling_doc_outdated` and `missing_stress_story`
17
+ all `false`.
17
18
  The ledger can't see items 9, 10, 11 and 14, so check those by hand.
18
19
 
19
20
  ## The checklist
@@ -131,7 +132,10 @@ The ledger can't see items 9, 10, 11 and 14, so check those by hand.
131
132
  covers ellipsis too (`1` is single-line ellipsis). Default it to `none` unless the layout
132
133
  clearly needs a cap, and never clamp text that must stay readable (legal or attribution text,
133
134
  link text that names its destination). Shape and rules: `theming-component-token-pattern.md`,
134
- "Line-clamp tokens". Add a unit test for any logic fix. A component that takes no data or copy
135
+ "Line-clamp tokens". Give each line-clamp token a Controls-panel select in the stories (set on
136
+ a wrapper `:style`, stripped from the component's args), labelled as a story-only CSS token so
137
+ nobody mistakes it for a prop: `storybook-add-story.md`, "Label token controls as story-only".
138
+ Add a unit test for any logic fix. A component that takes no data or copy
135
139
  (e.g. a pure layout wrapper) still gets one with oversized slot content.
136
140
  7. **Skill doc** — create or update `.claude/skills/components/<component-name>.md`, following the
137
141
  pattern of an existing one. A labelled `<Name>Field` wrapper (or any other wrapper) is documented
@@ -8,7 +8,7 @@
8
8
  Clicking it opens an anchored menu list populated via indexed dynamic slots (`item-{n}`). Each slot
9
9
  should contain a single `ActionMenuItem` — either a `<button>` (for actions) or a link (for
10
10
  navigation). The popover API and CSS anchor positioning handle positioning and dismiss behaviour
11
- natively; no JavaScript click-outside logic is needed.
11
+ natively, with a JS fallback for older Safari (see Notes).
12
12
 
13
13
  **Location**: `app/components/02.molecules/action-menu/`
14
14
 
@@ -16,7 +16,7 @@ natively; no JavaScript click-outside logic is needed.
16
16
 
17
17
  ## Components
18
18
 
19
- ### ActionMenu
19
+ ### `ActionMenu`
20
20
 
21
21
  | Prop | Type | Default | Notes |
22
22
  |---|---|---|---|
@@ -24,7 +24,7 @@ natively; no JavaScript click-outside logic is needed.
24
24
  | `triggerIcon` | `string` | `"lucide:ellipsis"` | Icon on the trigger button. |
25
25
  | `styleClassPassthrough` | `string \| string[]` | `[]` | Extra classes on the root `<div>`. |
26
26
 
27
- **Slots**
27
+ #### Slots
28
28
 
29
29
  | Slot | When used |
30
30
  |---|---|
@@ -32,7 +32,7 @@ natively; no JavaScript click-outside logic is needed.
32
32
 
33
33
  ---
34
34
 
35
- ### ActionMenuItem
35
+ ### `ActionMenuItem`
36
36
 
37
37
  | Prop | Type | Default | Notes |
38
38
  |---|---|---|---|
@@ -41,19 +41,20 @@ natively; no JavaScript click-outside logic is needed.
41
41
  | `arrowIcon` | `string` | `"lucide:arrow-right"` | Decorative trailing arrow icon. |
42
42
  | `styleClassPassthrough` | `string \| string[]` | `[]` | Extra classes on the root element. |
43
43
 
44
- **Slots**
44
+ #### Slots
45
45
 
46
46
  | Slot | Content |
47
47
  |---|---|
48
48
  | `#icon` | Optional left icon (e.g. `<Icon name="lucide:pencil" />`). Wrapped in `aria-hidden` span. |
49
49
 
50
- **Emits**
50
+ #### Emits
51
51
 
52
52
  | Event | Payload | Notes |
53
53
  |---|---|---|
54
54
  | `click` | `MouseEvent` | Fired on every click regardless of whether the item is a button or link. |
55
55
 
56
- **Notes on routing**
56
+ #### Notes on routing
57
+
57
58
  - Internal paths (`/…`) resolve to `<NuxtLink>` via `resolveComponent`.
58
59
  - External URLs or relative paths without a leading `/` render as plain `<a>`.
59
60
  - `type="button"` is set automatically on `<button>` elements to prevent accidental form submission.
@@ -63,7 +64,7 @@ natively; no JavaScript click-outside logic is needed.
63
64
  ## Basic usage
64
65
 
65
66
  ```vue
66
- <ActionMenu :item-count="3" label="Row actions">
67
+ <ActionMenu label="Row actions">
67
68
  <template #item-0>
68
69
  <ActionMenuItem label="Edit" @click="handleEdit">
69
70
  <template #icon><Icon name="lucide:pencil" /></template>
@@ -122,13 +123,18 @@ Quick reference:
122
123
 
123
124
  ## Notes
124
125
 
125
- - **Popover API + CSS anchor positioning** — the menu uses the `popover` attribute (broadly supported)
126
- and `position-anchor` (newer: Chromium 125+, Safari 26+). Without anchor positioning the popover
127
- still opens, just not anchored to the trigger. No polyfill is included.
128
- - **Auto-close** — clicking any `<li>` row fires `hidePopover()` on the menu. The `ActionMenuItem`
129
- emitting `click` triggers normally before the menu closes.
130
- - **Focus management** — on open the `toggle` event fires `handleToggle`, which moves focus to the
131
- first `[role="menuitem"]` inside the popover.
126
+ - **Popover API + CSS anchor positioning, with fallbacks** — open/close and positioning go through
127
+ the shared `useAnchoredPopover` composable, same as `SelectMenu`. Without anchor
128
+ positioning (Safari 17–18) JS measures the trigger and writes `--_anchor-*` px values
129
+ for the `@supports not (anchor-name: --a)` block. Without the Popover API (Safari 16) the trigger
130
+ toggles `isOpen`, `.action-menu-popover-open` shows the menu, outside pointerdown and Escape
131
+ close it, and `--action-menu-popover-z-index` (default `999999`) applies. See the `select-menu`
132
+ skill doc for the details and the `:popover-open` selector-list caveat.
133
+ - **`aria-expanded`** on the trigger tracks the open state in every browser (added 2026-10-05).
134
+ - **Auto-close** — clicking any `<li>` row calls the composable's `hide()` (native `hidePopover()`
135
+ or the fallback). The `ActionMenuItem` emitting `click` triggers normally before the menu closes.
136
+ - **Focus management** — on open (the `toggle` event, or after render in the fallback), focus moves
137
+ to the first `[role="menuitem"]` inside the popover.
132
138
  - **Keyboard navigation `currentIndex === -1` guard** — `handleKeydown` computes the current
133
139
  position via `items.indexOf(document.activeElement)`. When focus is outside the menu this returns
134
140
  `-1`. Always guard explicitly before applying wrap-around math: `ArrowDown` should focus
@@ -13,12 +13,12 @@ type: reference
13
13
  anchor-positioning (`anchor-name`/`position-anchor`/`anchor()`) and the native Popover API
14
14
  (`popover`/`popovertarget`).
15
15
 
16
- **Browser support caveat:** CSS anchor-positioning and the Popover API are both comparatively
17
- recent — check current browser support before shipping this on a page that must work everywhere,
18
- same caution as `ExpandingPanel`'s `::details-content` gap (CLAUDE.md pitfall #19). If broad
19
- support is a hard requirement, use [`DeepExpandingMenuClassic`](deep-expanding-menu-classic.md)
20
- instead — same API and visual result, built on `<details>`/`<summary>` +
21
- `onClickOutside` instead.
16
+ **Browser support:** since 2026-10-05 open/close and positioning go through the shared
17
+ `useAnchoredPopover` composable (see `composable-anchored-popover.md`), so the menu also works
18
+ without anchor positioning (Safari 17–18: JS-measured `position: fixed`) and without the Popover
19
+ API (Safari 16: JS open/close, outside click and Escape). Before that, panels never opened on
20
+ Safari 16. [`DeepExpandingMenuClassic`](deep-expanding-menu-classic.md) is still the alternative
21
+ built on `<details>`/`<summary>`: same API and visual result, with no popover layer involved.
22
22
 
23
23
  ## Props
24
24
 
@@ -82,6 +82,18 @@ See `CONSUMER-STYLING.md` for the full token API and what's not tokenised.
82
82
  - Auto-imported in Nuxt — no manual import needed.
83
83
  - Anchor names and popover target ids are generated per-instance via `useId()`, so multiple
84
84
  instances on one page don't collide.
85
+ - One `useAnchoredPopover` instance serves every group: `activeKey` tracks the open group, and the
86
+ composable's `triggerRef`/`popoverRef` are computeds over per-group element maps (filled by
87
+ function refs). Native `toggle` events for two auto popovers can arrive in either order (B opens,
88
+ then A closes), so a close event is ignored unless it's for the active group.
89
+ - Each group toggle has `aria-expanded`; the caret flip keys off it rather than
90
+ `:has(:popover-open)`, so it works in the fallback too.
91
+ - Panels have no ARIA role: this is the disclosure-navigation pattern (a toggle with
92
+ `aria-expanded` revealing ordinary links), not an ARIA menu. `role="menu"` was removed 2026-10-05
93
+ because it requires `menuitem` children and arrow-key handling the panels don't have, so screen
94
+ readers announced a menu that didn't behave like one. Don't add it back.
95
+ - 2026-10-05: removed two never-referenced `@position-try` blocks (`--anchor-left`, and an invalid
96
+ `@position-try-fallbacks --anchor-right` at-rule).
85
97
  - 2026-09-07 migration: moved from an unplaced top-level folder into
86
98
  `02.molecules/navigation/deep-expanding-menu/`; converted options-style `defineProps` to
87
99
  `interface Props` + `withDefaults`; the previous hardcoded `nav-1` anchor/popover id prefix
@@ -10,7 +10,8 @@ type: reference
10
10
 
11
11
  `DisplayTooltipDefined` composes [`DisplayTooltip`](display-tooltip.md), supplying a structured
12
12
  title/body/action content shape (each rendered with a consumer-chosen tag) plus a built-in close
13
- button wired to the popover's `popovertarget`. Use this when you want the standard tooltip content
13
+ button wired to the popover's `popovertarget` and to `DisplayTooltip`'s scoped `close()`, so it also
14
+ closes the tooltip on Safari 16 (no Popover API). Use this when you want the standard tooltip content
14
15
  layout without hand-building the `tooltipContent` slot markup each time; use plain `DisplayTooltip`
15
16
  directly when you need full control over the popover's content.
16
17
 
@@ -14,9 +14,11 @@ the native Popover API (`popover`/`popovertarget`) and CSS anchor-positioning
14
14
  with a built-in close button, see [`DisplayTooltipDefined`](display-tooltip-defined.md), which
15
15
  composes this component.
16
16
 
17
- **Browser support caveat:** CSS anchor-positioning and the Popover API are both comparatively
18
- recent — check current browser support before relying on this where broad support is a hard
19
- requirement, same caution as `DeepExpandingMenu`'s equivalent gap.
17
+ **Browser support:** since 2026-10-05 open/close and positioning go through the shared
18
+ `useAnchoredPopover` composable (`side: "right"`, see `composable-anchored-popover.md`). Without
19
+ anchor positioning (Safari 17–18) the panel is placed from the trigger's measured position, flipping
20
+ to the left when there's no room on the right. Without the Popover API (Safari 16) it opens and
21
+ closes in JS, with outside-click and Escape dismissal. The trigger has `aria-expanded`.
20
22
 
21
23
  ## Props
22
24
 
@@ -32,7 +34,7 @@ requirement, same caution as `DeepExpandingMenu`'s equivalent gap.
32
34
  | Slot | Description |
33
35
  |------|-------------|
34
36
  | `triggerContent` | Optional content rendered before the trigger button (e.g. a label the tooltip icon sits next to). |
35
- | `tooltipContent` | Content rendered inside the popover panel. |
37
+ | `tooltipContent` | Content rendered inside the popover panel. Scoped prop `close()` hides the panel in every browser: wire your own close button to it (`#tooltipContent="{ close }"`), since `popovertargetaction="hide"` alone does nothing without the Popover API. |
36
38
 
37
39
  ## Basic usage
38
40
 
@@ -54,6 +56,10 @@ popover width/colours/radius, and the close-button tokens `DisplayTooltipDefined
54
56
 
55
57
  ## Notes
56
58
 
59
+ - Slotted content: direct children of `tooltipContent` get `margin-block: 0` (in `:where()`, so
60
+ consumer margins win) and the panel sets `--display-tooltip-popover-font-size` (`1.4rem`) and
61
+ `-line-height` (`1.4`), so a bare `<p>` reads as tooltip text without extra styling.
62
+
57
63
  - Auto-imported in Nuxt — no manual import needed.
58
64
  - `tooltipId` is only reactive at mount — changing it after mount does not regenerate the linked
59
65
  `popovertarget`/`id` pair reactively beyond Vue's normal re-render, since both derive from the
@@ -18,6 +18,7 @@ active-route highlighting, hover indicator).
18
18
  | `mainNavigationState` | `ResponsiveHeaderState` | `{ clonedNavLinks: {}, navListVisibility: {}, hasSecondNav: false }` | Shared geometry/visibility state, normally supplied by the parent `ResponsiveHeader` — not something a consumer constructs by hand outside of tests/stories. |
19
19
  | `panelVariant` | `"modern" \| "classic"` | `"classic"` | Which panel component renders a dropdown's submenu: `ExpandingPanel` (`"modern"`) or `ExpandingPanelClassic` (`"classic"`, default). `"modern"` is known not to work correctly on WebKit. Normally set via `ResponsiveHeader`'s own `panelVariant` prop rather than directly. See CLAUDE.md pitfall #19. |
20
20
  | `ariaLabel` | `string` | `"Overflow navigation menu"` | aria-label on the root `role="menu"` element — override for localisation. Normally set via `ResponsiveHeader`'s own `overflowMenuAriaLabel` prop rather than directly. |
21
+ | `submenuAriaLabel` | `string` | `"{title} submenu"` | aria-label on each submenu summary; `{title}` is replaced with `childLinksTitle` (or `name`). Normally set via `ResponsiveHeader`'s `submenuAriaLabel`. |
21
22
  | `styleClassPassthrough` | `string \| string[]` | `[]` | Extra CSS classes applied to the root `.overflow-navigation-wrapper` element. |
22
23
 
23
24
  ---
@@ -78,6 +78,18 @@ earlier than `opens` means the session runs past midnight and is displayed as gi
78
78
  - Grouping compares status, sessions and note; only **consecutive** days (in `week-starts-on`
79
79
  order) group. No wrap-around from Sunday to Monday.
80
80
  - Exceptions don't alter the weekly table; they are listed separately.
81
+ - **Bad data never throws** (since 2026-10-05): a time that isn't a valid `HH:MM` from `00:00` to
82
+ `23:59` (e.g. `"abc"`, `"25:99"`, `"24:00"`) and an exception date that isn't a real
83
+ `YYYY-MM-DD` are shown exactly as written. An invalid `locale` falls back to `en-GB`, and an
84
+ invalid `timeZone` to the browser's own. An exception whose `to` is before its `from` is shown
85
+ the right way round, and duplicate exception dates both render. The checks are the
86
+ auto-imported `parseOpeningTime` and `parseOpeningDate` utils (`app/utils/opening-hours.ts`).
87
+ - A session that closes after midnight (`22:00`–`02:00`) displays as written; schema.org reads
88
+ `closes` before `opens` as the next day.
89
+ - `status: "open"` with no sessions is treated as closed (since 2026-10-05): the row shows
90
+ `closedLabel`, gets `data-status="closed"`, and structured data treats it as closed too.
91
+ - Long text wraps rather than overflowing; notes and exception labels have line-clamp tokens
92
+ (`CONSUMER-STYLING.md`). The `StressTest` story covers the worst-case data.
81
93
  - Today's highlight and past-exception hiding run in `onMounted`, never on the server, so cached
82
94
  HTML can't carry a stale day. Past exceptions are briefly visible before hydration.
83
95
  - **Structured data**: emits `{ "@type": structuredData.type ?? "LocalBusiness", "@id", name,
@@ -15,9 +15,12 @@ with fully consumer-supplied content, built on the native Popover API
15
15
  text) or `ActionMenu` (menu semantics with arrow-key navigation), `PopOver` makes no assumption
16
16
  about what the trigger or content look like, and always renders its own visible close button.
17
17
 
18
- **Browser support caveat:** CSS anchor-positioning and the Popover API are both comparatively
19
- recent — check current browser support before relying on this where broad support is a hard
20
- requirement, same caution as `DisplayTooltip`/`DeepExpandingMenu`'s equivalent gap.
18
+ **Browser support:** since 2026-10-05 open/close and positioning go through the shared
19
+ `useAnchoredPopover` composable, with `side` following the `placement` prop (see
20
+ `composable-anchored-popover.md`). Without anchor positioning (Safari 17–18) the panel is placed
21
+ from the trigger's measured position on the `placement` side, flipping to the opposite side when
22
+ there's no room. Without the Popover API (Safari 16) it opens and closes in JS, with outside-click
23
+ and Escape dismissal.
21
24
 
22
25
  ## Props
23
26
 
@@ -72,11 +75,11 @@ the only source of space above/below the slotted content — a plain `<p>` doesn
72
75
 
73
76
  ## Behaviour
74
77
 
75
- - Opening/closing is handled natively by the Popover API: clicking the trigger toggles the panel,
76
- clicking the close button or pressing Escape hides it, and focus returns to the trigger
77
- automatically on close.
78
- - On open, focus moves to the close button (`handleToggle`, driven by the popover's native
79
- `toggle` event) so keyboard users land inside the panel immediately.
78
+ - Clicking the trigger toggles the panel; the close button, Escape or an outside click hides it,
79
+ and focus returns to the trigger. Natively this is the Popover API; on Safari 16 the composable
80
+ does the same in JS. The trigger has `aria-expanded` in every browser.
81
+ - On open, focus moves to the close button (the composable's `onOpen`) so keyboard users land
82
+ inside the panel immediately.
80
83
 
81
84
  ## CSS custom properties
82
85
 
@@ -4,7 +4,8 @@
4
4
 
5
5
  `PriceList` (`app/components/02.molecules/price-list/`) renders a service/menu-style price list:
6
6
  one or more columns, each with a heading (optional icon) and a `<dl>` of description/price rows.
7
- Columns stack below `48em` and sit two-up above it. Not a SaaS plan comparison, use `PricingCard`
7
+ Columns stack in a narrow container and sit two-up once the component itself is wide enough
8
+ (a container-width grid since 2026-10-05, not a viewport media query). Not a SaaS plan comparison, use `PricingCard`
8
9
  for that.
9
10
 
10
11
  ---
@@ -48,6 +49,8 @@ No slots, no events.
48
49
  - Column titles are `HeroText` headings at `heading-tag`. Prices are plain `<span>`s inside `<dd>`,
49
50
  not headings (before 2026-09-27 each price was an `<h2>`, which flooded the heading outline).
50
51
  - Rows are `<div>`-wrapped `<dt>`/`<dd>` pairs, valid inside `<dl>`.
52
+ - A column with an empty `headingtext` renders no heading at all (no empty `<h2>`); its rows still
53
+ render.
51
54
 
52
55
  ---
53
56
 
@@ -57,6 +60,12 @@ All tokens are `--price-list-*`; full table in `CONSUMER-STYLING.md` next to the
57
60
  Common ones: `--price-list-divider-colour`, `--price-list-divider-opacity`,
58
61
  `--price-list-price-font-size`, `--price-list-heading-margin-block-end`.
59
62
 
63
+ Layout and long data: `--price-list-column-min-inline-size` (`32rem`) and `--price-list-max-columns`
64
+ (`2`) control when columns sit side by side; `--price-list-price-max-inline-size` (`50%`) caps the
65
+ price so a long price wraps instead of crushing the description; `--price-list-description-line-clamp`
66
+ (`none`) caps description lines. Unbroken strings wrap anywhere. The `StressTest` story covers the
67
+ worst-case data.
68
+
60
69
  ---
61
70
 
62
71
  ## Usage
@@ -110,8 +110,33 @@ buggy toggle-based version too.
110
110
  | `mainNavAriaLabel` | `string` | `"Main navigation"` | aria-label on the primary nav landmark — override for localisation. |
111
111
  | `secondaryNavAriaLabel` | `string` | `"Secondary navigation"` | aria-label on the secondary (overflow) nav landmark — override for localisation. |
112
112
  | `overflowMenuAriaLabel` | `string` | `"Overflow navigation menu"` | Forwarded to `NavigationItems`' `ariaLabel` — override for localisation. |
113
+ | `overflowButtonLabel` | `string` | `"More navigation"` | Accessible name of the overflow/burger button, which shows only icons. |
114
+ | `submenuAriaLabel` | `string` | `"{title} submenu"` | aria-label on each dropdown summary, top bar and overflow panel; `{title}` is replaced with `childLinksTitle` (or `name`). Forwarded to `NavigationItems`. |
113
115
  | `styleClassPassthrough` | `string \| string[]` | `[]` | Extra CSS classes applied to the root `.navigation` element. |
114
116
 
117
+ ## Data edge cases (since 2026-10-05)
118
+
119
+ - A dropdown with no `childLinksTitle` shows its `name` instead (it used to render an empty
120
+ summary labelled "undefined submenu").
121
+ - Child links are keyed by index, so duplicate names are fine.
122
+ - The overflow button appears whenever any item is hidden, whatever the group keys are called.
123
+ It used to read `navListVisibility.firstNav`/`secondNav` only, so a group named anything else
124
+ (e.g. `main`) kept the burger showing even when everything fitted. Empty nav data never shows
125
+ it, and still completes the geometry pass.
126
+ - The top-bar dropdown and the overflow panel are capped in width and height (tokens in
127
+ `CONSUMER-STYLING.md`); long names wrap and long lists scroll inside them.
128
+ - **Fit check (fixed 2026-10-05):** an item is visible when its right edge is at or before the main
129
+ nav's own measured right edge (which already has the secondary nav and gap reserved as
130
+ `margin-inline-end`). It used to compare against the wrapper while adding the gap a second time
131
+ with a strict `<`, so the last item of a flush-right second group (e.g. "Contact") was always
132
+ sent to the overflow menu, however wide the screen.
133
+ - The component copies `responsiveNavLinks` before measuring. It used to write each item's
134
+ `config` straight into the consumer's own nav data object.
135
+ - The `StressTest` story covers all of the above.
136
+ - **Alignment (added 2026-10-05):** `--responsive-header-main-nav-justify-content`
137
+ (default `space-between`) sets how the main nav's groups sit along the bar; use `safe end` /
138
+ `safe center`, never plain `end`/`center`. The `MainNavAlignment` story shows the options.
139
+
115
140
  ## Slots
116
141
 
117
142
  | Slot | Purpose |
@@ -171,11 +171,22 @@ Quick reference:
171
171
 
172
172
  ## Notes
173
173
 
174
- - **Popover API + CSS anchor positioning** — same mechanism as `ActionMenu`. The Popover API is
175
- broadly supported (Chrome 114+, Firefox 125+, Safari 17+), but CSS anchor positioning is much
176
- newer (Chromium 125+, Safari 26+), and without it the popover isn't placed under the trigger. No
177
- polyfill or fallback is included, so check support before using this where older devices
178
- matter; a native `<select>` (`InputSelect`) is the safer choice there.
174
+ - **Popover API + CSS anchor positioning, with fallbacks** — same mechanism as `ActionMenu`, both
175
+ via the shared `useAnchoredPopover` composable (`app/composables/useAnchoredPopover.ts`). The
176
+ Popover API arrived in Safari 17 and CSS anchor positioning in Safari 26, so:
177
+ - No anchor positioning (Safari 17–18): JS measures the trigger and writes `--_anchor-*` px values for the
178
+ `@supports not (anchor-name: --a)` block, re-measuring on scroll/resize and flipping above
179
+ (`data-placement="top"`) when there's no room below.
180
+ - No Popover API (Safari 16, e.g. first-generation iPad Pros that can't update): the trigger's
181
+ `@click` toggles `isOpen`, `.select-menu-popover-open` shows the list, and document listeners
182
+ close it on outside pointerdown and Escape. Not top-layer here, hence
183
+ `--select-menu-popover-z-index` (default `999999`).
184
+ - Detection runs in `onMounted` (`typeof HTMLElement.prototype.showPopover`, `CSS.supports`), so
185
+ SSR markup is identical everywhere. Every close goes through the composable's `hide()`, never
186
+ `hidePopover()` directly, so it works in both modes.
187
+ - Never put `:popover-open` in a selector list with the fallback class: browsers without it
188
+ drop the whole rule.
189
+ Confirmed broken on a Safari 16 iPad before this (trigger rendered, menu never opened).
179
190
  - **Left-aligned popover** (`left: anchor(left)`) — unlike `ActionMenu` which right-aligns. Matches
180
191
  native `<select>` dropdown behaviour. Flips above the trigger near the bottom of the viewport.
181
192
  - **Keyboard navigation** follows the WAI-ARIA listbox pattern: `ArrowDown`/`ArrowUp` move between
@@ -198,9 +209,8 @@ Quick reference:
198
209
  weight doesn't resize the popover. Hover/focus has `-text-color-hover` and `-border-hover`, which
199
210
  fall back to the row's *current* state (selected or resting), not always to resting. There's no
200
211
  hover font-weight token on purpose: the width reserve only covers one alternate weight.
201
- - **Chevron rotation is pure CSS** via `:has(.select-menu-popover:popover-open)` on the root — no
202
- JS state drives the visual. `isOpen` is still tracked internally, but only to set `aria-expanded`
203
- on the trigger.
212
+ - **Chevron rotation** keys off the trigger's `aria-expanded` (from the composable's `isOpen`), not
213
+ `:has(...:popover-open)`, so it also works without the Popover API (changed 2026-10-05).
204
214
  - **No native `<select>`/`appearance: base-select` involved** — this is a from-scratch popover
205
215
  listbox, not a styled native select, so it doesn't inherit `InputSelectCore`'s WebKit
206
216
  `appearance: base-select` constraints.
@@ -27,6 +27,8 @@ Branding (logo/wordmark) is entirely consumer-authored via the `#branding` slot
27
27
  | `mainNavAriaLabel` | `string` | `"Main navigation"` | Forwarded to `ResponsiveHeader`'s `mainNavAriaLabel` — override for localisation. |
28
28
  | `secondaryNavAriaLabel` | `string` | `"Secondary navigation"` | Forwarded to `ResponsiveHeader`'s `secondaryNavAriaLabel` — override for localisation. |
29
29
  | `overflowMenuAriaLabel` | `string` | `"Overflow navigation menu"` | Forwarded to `ResponsiveHeader`'s `overflowMenuAriaLabel` — override for localisation. |
30
+ | `overflowButtonLabel` | `string` | `"More navigation"` | Forwarded to `ResponsiveHeader`'s `overflowButtonLabel`, the burger button's accessible name. |
31
+ | `submenuAriaLabel` | `string` | `"{title} submenu"` | Forwarded to `ResponsiveHeader`'s `submenuAriaLabel`; `{title}` is replaced with the item's title. |
30
32
 
31
33
  ---
32
34
 
@@ -42,6 +42,13 @@ short: `--ui-block-decorated-border-1` .. `-6`, `--ui-block-decorated-shadow-1`
42
42
  `--ui-block-decorated-inner-shadow-1` .. `-4`, and `--ui-block-decorated-inner-shadow-highlight`
43
43
  (layered on top of every inner shadow level).
44
44
 
45
+ To recolour every level at once (added 2026-10-05): `--ui-block-decorated-border-colour` (default
46
+ `var(--theme-border)`), `--ui-block-decorated-shadow-colour` (default `#000`) and
47
+ `--ui-block-decorated-inner-shadow-colour` (default: the shadow colour). Each shadow level mixes the
48
+ colour with its own opacity via `color-mix()` (8% .. 18%), so defaults render exactly as before.
49
+ The per-level tokens still override the whole value. The story has colour pickers for all three,
50
+ plus story-only background and text colour controls for checking contrast.
51
+
45
52
  ## Notes
46
53
 
47
54
  - 2026-09-16 migration: previously used options-style `defineProps` and referenced six families of
@@ -0,0 +1,108 @@
1
+ # useAnchoredPopover
2
+
3
+ `app/composables/useAnchoredPopover.ts`. Open/close state and positioning for a trigger + `popover`
4
+ element anchored with CSS anchor positioning, with fallbacks for browsers that lack either
5
+ feature. Used by `ActionMenu`, `SelectMenu`, `DeepExpandingMenu` (all `side: "bottom"`, the default)
6
+ `DisplayTooltip` (`side: "right"`) and `PopOver` (`side: () => props.placement`). Use it for any new anchored popover instead of calling `showPopover()`/`hidePopover()`
7
+ directly.
8
+
9
+ Several popovers where only one is open at a time (e.g. `DeepExpandingMenu`'s groups) can share
10
+ one instance: keep an `activeKey`, pass computeds over per-item element maps as `triggerRef`/
11
+ `popoverRef` (the options accept readonly refs), and ignore a `toggle` close event that isn't for
12
+ the active item, since auto popovers' open and close events can arrive in either order.
13
+
14
+ ## Why
15
+
16
+ - The Popover API arrived in Safari 17; CSS anchor positioning only in Safari 26.
17
+ - Safari 16 (e.g. first-generation iPad Pros, which can't update past iPadOS 16) has neither: the
18
+ trigger renders but the menu never opens.
19
+ - Safari 17–18 has the Popover API but no anchor positioning: the menu opens in the wrong place.
20
+
21
+ ## Modes (detected in `onMounted`, so SSR markup is the same everywhere)
22
+
23
+ | Support | Behaviour |
24
+ |---|---|
25
+ | Popover API + anchor positioning | Fully native. The composable only tracks `isOpen` from `toggle`. |
26
+ | Popover API, no anchor positioning | JS measures the trigger on `beforetoggle`/`toggle` and on scroll/resize, and writes the trigger's edges as `--_anchor-*` px values (see below); flips to the opposite side (`data-placement`) when the preferred side has no room and the opposite side does. |
27
+ | No Popover API | Also opens/closes in JS: trigger `@click` toggles `isOpen`, document `pointerdown` outside the root and `Escape` close it, and `hide()` returns focus to the trigger when focus was inside the popover, as native popovers do. The component shows the popover from a fallback class. |
28
+
29
+ ## API
30
+
31
+ ```ts
32
+ const {
33
+ isOpen, // Ref<boolean>, accurate in every mode; bind to aria-expanded
34
+ usesFallbackPopover, // Ref<boolean>, true without the Popover API
35
+ needsPositioning, // Ref<boolean>, true without anchor positioning
36
+ positionStyle, // bind to the popover's :style (undefined when not needed)
37
+ popoverPlacement, // bind to :data-placement: the resolved side, or undefined when native
38
+ show, hide, // always use these, never showPopover()/hidePopover() directly
39
+ handleTriggerClick, // trigger @click (no-op where popovertarget works)
40
+ handleBeforeToggle, // popover @beforetoggle
41
+ handleToggle, // popover @toggle
42
+ } = useAnchoredPopover({ rootRef, triggerRef, popoverRef, side: "bottom", onOpen: focusFirstItem });
43
+ ```
44
+
45
+ `rootRef` must contain both the trigger and the popover (outside-click detection). `onOpen` runs
46
+ after the popover is visible, so it can move focus into it.
47
+
48
+ `side` (`"bottom"` default, `"top"`, `"right"`, `"left"`, or a ref/getter of one, e.g. `() => props.placement`) is the preferred side for the fallback
49
+ flip; it doesn't affect native anchor positioning, which the component's own CSS controls.
50
+
51
+ ### Fallback position variables
52
+
53
+ They mirror `anchor()`: `--_anchor-{top|bottom|left|right}` is the trigger edge in viewport px, for
54
+ the `top`/`left` properties (`top: anchor(bottom)` becomes `top: var(--_anchor-bottom)`).
55
+ `--_anchor-{edge}-inverse` is the same edge measured from the viewport's bottom/right, for the
56
+ `bottom`/`right` properties (`right: anchor(left)` becomes `right: var(--_anchor-left-inverse)`).
57
+ All eight are always written, so CSS picks what each side needs.
58
+
59
+ ## Component wiring
60
+
61
+ ```vue
62
+ <div ref="rootRef" class="x-menu">
63
+ <button ref="triggerRef" :popovertarget="id" :aria-expanded="isOpen" @click="handleTriggerClick">…</button>
64
+ <div
65
+ :id="id"
66
+ ref="popoverRef"
67
+ popover
68
+ class="x-menu-popover"
69
+ :class="{ 'x-menu-popover-open': usesFallbackPopover && isOpen }"
70
+ :style="positionStyle"
71
+ :data-placement="popoverPlacement"
72
+ @beforetoggle="handleBeforeToggle"
73
+ @toggle="handleToggle"
74
+ >…</div>
75
+ </div>
76
+ ```
77
+
78
+ ```css
79
+ .x-menu-popover {
80
+ &:popover-open { display: block; }
81
+ /* Separate rule: a selector list containing :popover-open is dropped whole where unsupported. */
82
+ &.x-menu-popover-open { display: block; }
83
+
84
+ @supports not (anchor-name: --a) {
85
+ position: fixed;
86
+ top: calc(var(--_anchor-bottom, 0px) + var(--x-menu-block-distance, 0.4rem));
87
+ left: var(--_anchor-left, 0px);
88
+ z-index: var(--x-menu-popover-z-index, 999999);
89
+
90
+ &[data-placement="top"] {
91
+ top: auto;
92
+ bottom: calc(var(--_anchor-top-inverse, 0px) + var(--x-menu-block-distance, 0.4rem));
93
+ }
94
+ }
95
+ }
96
+ ```
97
+
98
+ Drive any "open" visuals (e.g. a chevron) from `[aria-expanded="true"]` on the trigger, not
99
+ `:has(:popover-open)`.
100
+
101
+ ## Caveats
102
+
103
+ - In the no-Popover-API mode the popover isn't in the top layer: give it a public z-index token
104
+ (default `999999`, pitfall #17), and an ancestor with `transform`/`filter`/`contain` becomes its
105
+ containing block and can misplace it.
106
+ - Tests: happy-dom has no Popover API and its `CSS.supports` can't be spied on. Define/undefine
107
+ `HTMLElement.prototype.showPopover` and swap `globalThis.CSS` (restore it in `afterEach`); see
108
+ `app/composables/tests/useAnchoredPopover.spec.ts`.
@@ -8,7 +8,7 @@
8
8
 
9
9
  ## Prerequisites
10
10
 
11
- - Uses the native HTML Popover API — supported in all modern browsers (Chrome 114+, Firefox 125+, Safari 17+)
11
+ - Built around the native Popover API (Chrome 114+, Firefox 125+, Safari 17+). With `DisplayTooltip`/`DisplayTooltipDefined` it also works on Safari 16, because those components fall back to JS open/close (`useAnchoredPopover`) and the guide drives them through their trigger buttons. Hand-written raw `[popover]` markup like the example below still needs the Popover API.
12
12
  - Popovers must have `id` attributes and corresponding trigger buttons with `popovertarget` and `popovertargetaction="toggle"` attributes
13
13
  - Close buttons inside each popover must have `popovertargetaction="hide"`
14
14
 
@@ -74,6 +74,8 @@ await startGuide()
74
74
  2. If `autoStart` is `true`, calls `startGuide()` which iterates the popovers in DOM order.
75
75
  3. For each popover: finds the `[popovertarget][popovertargetaction="toggle"]` trigger button and clicks it to open the popover, then waits for the `[popovertargetaction="hide"]` button to be clicked before advancing.
76
76
  4. After the last popover is dismissed, `autoRunGuide` is set to `false` and `isGuideRunning` becomes `false`.
77
+ 5. With no close button, a step ends when the trigger's `aria-expanded` turns `"false"` (a `MutationObserver`), or on the popover's `toggle` event with `newState: "closed"` when there's no trigger either.
78
+ 6. `stopGuide()`/`restartGuide()` close an open step by clicking its trigger when `aria-expanded="true"`, or with `hidePopover()` where `:popover-open` is supported. They never call `togglePopover()` or match `:popover-open` unguarded, both of which throw on Safari 16.
77
79
 
78
80
  ## API reference
79
81
 
@@ -66,6 +66,7 @@ Each skill is a single markdown file named `<area>-<task>.md`.
66
66
  ├── composable-tooltips-guide.md — useTooltipsGuide: sequential popover guide with auto-start, dismiss-to-advance, manual controls
67
67
  ├── composable-cookie-consent.md — useCookieConsent: unset/granted/denied state, cookie persistence, wraps @nuxt/scripts' useScriptTriggerConsent
68
68
  ├── composable-analytics.md — useAnalytics: provider-agnostic trackEvent/page-view tracking (google-analytics only implemented), consent-gated, single call site for setup + firing events
69
+ ├── composable-anchored-popover.md — useAnchoredPopover: popover + anchor positioning with JS fallbacks for Safari 16 (no Popover API) and 17–18 (no anchor positioning); used by ActionMenu/SelectMenu/DeepExpandingMenu/DisplayTooltip/PopOver
69
70
  └── components/
70
71
  ├── alert-content.md — AlertContent + AlertContentInner: themed alert panel (icon/title/content/actions/dismiss) under DisplayToast, DisplayPrompt and AlertMaskedContent; showIcon, #actions row, --alert-content-* tokens, app.config icon map
71
72
  ├── alert-mask-core.md — AlertMaskCore: SVG border/background mask sized to slotted content via ResizeObserver, config-prop-driven geometry/colour (no CSS token API)
@@ -271,6 +271,20 @@ Key points:
271
271
  - Extra args must be stripped before `v-bind` — spreading unknown keys onto a component makes them unknown HTML attributes.
272
272
  - CSS custom properties set via `:style` on the component root are picked up by `var()` in the component's scoped CSS.
273
273
 
274
+ ### Label token controls as story-only
275
+
276
+ A control that drives a CSS token (a line clamp, a colour) looks exactly like a prop in the
277
+ Controls panel and the generated docs table, so a developer reading the story can assume it's a
278
+ prop and try to pass it. Make it unmistakable:
279
+
280
+ - Put it in the category `"CSS tokens (story only, set in your CSS)"`.
281
+ - Start the description with `**Story control, not a prop.**`, name the token, and show the CSS a
282
+ consumer would write instead, e.g.
283
+ `` `.salon-menu { --price-list-description-line-clamp: 2; }` ``.
284
+ - If a story's docs text tells people to try the control, say there too that it's a CSS token.
285
+
286
+ `PriceList.stories.ts` and `GoogleReviews.stories.ts` (line-clamp controls) follow this.
287
+
274
288
  ## Notes
275
289
 
276
290
  - **Colour scheme:** `.storybook/preview.ts` pins every story to the light scheme
@@ -24,7 +24,9 @@
24
24
  " main-nav-aria-label=\"${2:Main navigation}\"",
25
25
  " secondary-nav-aria-label=\"${3:Secondary navigation}\"",
26
26
  " overflow-menu-aria-label=\"${4:Overflow navigation menu}\"",
27
- "/>"
27
+ " overflow-button-label=\"${5:More navigation}\"",
28
+ " submenu-aria-label=\"${6:{title\\} submenu}\"",
29
+ "></ResponsiveHeader>"
28
30
  ]
29
31
  },
30
32
  "SRCDEV ResponsiveHeader Nav Data (with dropdown)": {
@@ -40,9 +40,11 @@
40
40
  " main-nav-aria-label=\"${3:Main navigation}\"",
41
41
  " secondary-nav-aria-label=\"${4:Secondary navigation}\"",
42
42
  " overflow-menu-aria-label=\"${5:Overflow navigation menu}\"",
43
+ " overflow-button-label=\"${6:More navigation}\"",
44
+ " submenu-aria-label=\"${7:{title\\} submenu}\"",
43
45
  ">",
44
46
  " <template #branding>",
45
- " <NuxtLink to=\"/\" class=\"home-link\">$6Brand</NuxtLink>",
47
+ " <NuxtLink to=\"/\" class=\"home-link\">$8Brand</NuxtLink>",
46
48
  " </template>",
47
49
  "</SiteHeader>"
48
50
  ]
@@ -14,8 +14,10 @@
14
14
  /* Used to scroll scale elements when scrolling x-axis like a carousel. */
15
15
 
16
16
  @media (prefers-reduced-motion: no-preference) {
17
- .animation-scroller-x {
18
- animation: scroller linear both;
19
- animation-timeline: view(x);
17
+ @supports (animation-timeline: view()) {
18
+ .animation-scroller-x {
19
+ animation: scroller linear both;
20
+ animation-timeline: view(x);
21
+ }
20
22
  }
21
23
  }
@@ -8,8 +8,10 @@
8
8
  }
9
9
 
10
10
  @media (prefers-reduced-motion: no-preference) {
11
- .auto-rotate {
12
- animation: autoRotateAnimation;
13
- animation-timeline: view();
11
+ @supports (animation-timeline: view()) {
12
+ .auto-rotate {
13
+ animation: autoRotateAnimation;
14
+ animation-timeline: view();
15
+ }
14
16
  }
15
17
  }