srcdev-nuxt-components 9.1.49 → 9.1.51

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 (220) hide show
  1. package/.claude/settings.json +2 -4
  2. package/.claude/settings.local.json +22 -2
  3. package/.claude/skills/components/card-core.md +205 -0
  4. package/.claude/skills/components/display-dialog.md +128 -0
  5. package/.claude/skills/components/page-hero-highlights.md +1 -1
  6. package/.claude/skills/components/page-row.md +157 -0
  7. package/.claude/skills/components/services-card-grid.md +4 -4
  8. package/.claude/skills/components/services-section-grid.md +4 -4
  9. package/.claude/skills/components/tab-navigation.md +222 -0
  10. package/.claude/skills/composable-dialog-controls.md +55 -43
  11. package/.claude/skills/index.md +5 -2
  12. package/app/components/01.atoms/card/CONSUMER-STYLING.md +175 -0
  13. package/app/components/01.atoms/card/CardCore.vue +48 -21
  14. package/app/components/01.atoms/display-dialog/CONSUMER-STYLING.md +163 -0
  15. package/app/components/01.atoms/display-dialog/DisplayDialog.vue +277 -0
  16. package/app/components/01.atoms/display-dialog/stories/DisplayDialog.stories.ts +177 -0
  17. package/app/components/01.atoms/display-dialog/tests/DisplayDialog.spec.ts +264 -0
  18. package/app/components/01.atoms/display-dialog/tests/__snapshots__/DisplayDialog.spec.ts.snap +18 -0
  19. package/app/components/01.atoms/page-row/CONSUMER-STYLING.md +90 -0
  20. package/app/components/01.atoms/page-row/PageRow.vue +115 -0
  21. package/app/components/01.atoms/page-row/stories/PageRow.stories.ts +311 -0
  22. package/app/components/01.atoms/page-row/tests/PageRow.spec.ts +191 -0
  23. package/app/components/02.molecules/navigation/tab-navigation/CONSUMER-STYLING.md +145 -0
  24. package/app/components/02.molecules/navigation/tab-navigation/TabNavigation.vue +20 -9
  25. package/app/components/02.molecules/navigation/tab-navigation/tests/__snapshots__/TabNavigation.spec.ts.snap +12 -6
  26. package/app/components/{forms/ui → 05.forms/form-field}/FormField.vue +12 -19
  27. package/app/components/{forms/ui → 05.forms/form-wrapper}/FormWrapper.vue +6 -6
  28. package/app/components/{forms → 05.forms}/input-button/InputButtonCore.vue +2 -0
  29. package/app/components/{forms → 05.forms}/input-button/stories/InputButtonCore.stories.ts +1 -1
  30. package/app/components/{forms → 05.forms}/input-text/InputTextCore.vue +73 -73
  31. package/app/components/{forms → 05.forms}/input-text/variants/InputTextAsNumberWithLabel.vue +29 -29
  32. package/app/components/carousels/CarouselBasic.vue +99 -99
  33. package/app/components/carousels/CarouselInfinite.vue +150 -150
  34. package/app/components/deep-expanding-menu/DeepExpandingMenu.vue +111 -111
  35. package/app/components/responsive-header/ResponsiveHeader.vue +250 -282
  36. package/app/components/test-storybook/TestStorybook.vue +16 -16
  37. package/app/composables/tests/useDialogControls.spec.ts +34 -64
  38. package/app/composables/useDialogControls.ts +19 -33
  39. package/app/composables/useFormControl.ts +0 -2
  40. package/app/layouts/default.vue +9 -7
  41. package/app/pages/auto-grid.vue +37 -20
  42. package/app/pages/banner-video.vue +2 -2
  43. package/app/pages/forms/examples/buttons/index.vue +189 -215
  44. package/app/pages/forms/examples/material/text-fields.vue +2 -2
  45. package/app/pages/grid-stack.vue +10 -10
  46. package/app/pages/index.vue +20 -20
  47. package/app/pages/samaritan.vue +4 -4
  48. package/app/pages/typography/hero-text.vue +6 -6
  49. package/app/pages/typography/index.vue +4 -4
  50. package/app/pages/typography/page-body.vue +4 -4
  51. package/app/pages/typography/page-heading.vue +4 -4
  52. package/app/pages/typography/page-link.vue +4 -4
  53. package/app/pages/ui/accordian.vue +4 -4
  54. package/app/pages/ui/anchor-scroll-tab-navigation.vue +77 -66
  55. package/app/pages/ui/anchor-scroll.vue +94 -70
  56. package/app/pages/ui/animated-svg-text.vue +4 -4
  57. package/app/pages/ui/block-decorators.vue +11 -11
  58. package/app/pages/ui/card-core.vue +9 -9
  59. package/app/pages/ui/carousel-basic.vue +4 -4
  60. package/app/pages/ui/carousel-flip.vue +2 -2
  61. package/app/pages/ui/carousel-infinite.vue +4 -4
  62. package/app/pages/ui/clipped-panels.vue +10 -10
  63. package/app/pages/ui/contact-section.vue +4 -4
  64. package/app/pages/ui/container-glow.vue +2 -3
  65. package/app/pages/ui/deep-expanding-menu.vue +138 -0
  66. package/app/pages/ui/display-avatar.vue +2 -2
  67. package/app/pages/ui/display-banner.vue +2 -2
  68. package/app/pages/ui/display-chip.vue +32 -25
  69. package/app/pages/ui/display-details.vue +6 -10
  70. package/app/pages/ui/display-dialog.vue +96 -131
  71. package/app/pages/ui/display-pill.vue +27 -33
  72. package/app/pages/ui/display-prompt.vue +4 -4
  73. package/app/pages/ui/display-toast.vue +2 -2
  74. package/app/pages/ui/expanding-panel.vue +12 -16
  75. package/app/pages/ui/glowing-border.vue +12 -12
  76. package/app/pages/ui/layout-grid-a.vue +6 -6
  77. package/app/pages/ui/layout-grid-b.vue +4 -4
  78. package/app/pages/ui/magnetic-navigation.vue +6 -6
  79. package/app/pages/ui/marquee-scroller.vue +2 -2
  80. package/app/pages/ui/mask-element.vue +2 -2
  81. package/app/pages/ui/masonry-columns.vue +4 -4
  82. package/app/pages/ui/masonry-grid-ordered-experiment.vue +4 -4
  83. package/app/pages/ui/masonry-grid-ordered.vue +4 -4
  84. package/app/pages/ui/masonry-grid-sorted.vue +4 -4
  85. package/app/pages/ui/masonry-grid.vue +4 -4
  86. package/app/pages/ui/navigation/navigation-horizontal.vue +12 -12
  87. package/app/pages/ui/navigation/tab-navigation.vue +493 -0
  88. package/app/pages/ui/page-row.vue +127 -0
  89. package/app/pages/ui/price-list.vue +4 -4
  90. package/app/pages/ui/profile-section.vue +4 -4
  91. package/app/pages/ui/qr-code/[componentName].vue +6 -6
  92. package/app/pages/ui/rotating-carousel.vue +16 -16
  93. package/app/pages/ui/scroll-reveal-image.vue +20 -20
  94. package/app/pages/ui/section-parallax.vue +7 -7
  95. package/app/pages/ui/services/colour-finder.vue +4 -4
  96. package/app/pages/ui/services/services-cards.vue +4 -4
  97. package/app/pages/ui/services/services-section/[slug].vue +4 -4
  98. package/app/pages/ui/services/services-sections-compact.vue +6 -6
  99. package/app/pages/ui/settings.vue +10 -10
  100. package/app/pages/ui/simple-grid.vue +2 -2
  101. package/app/pages/ui/slider-gallery.vue +5 -5
  102. package/app/pages/ui/tabs-y.vue +2 -3
  103. package/app/pages/ui/tabs.vue +6 -9
  104. package/app/pages/ui/tooltips.vue +9 -9
  105. package/app/pages/ui/wipe-away-vertical.vue +14 -14
  106. package/package.json +1 -1
  107. package/.claude/skills/components/layout-row.md +0 -239
  108. package/app/components/display-dialog/DisplayDialogCore.vue +0 -276
  109. package/app/components/display-dialog/variants/DisplayDialogConfirm.vue +0 -47
  110. package/app/components/display-dialog/variants/DisplayDialogScrollableContent.vue +0 -51
  111. package/app/components/forms/c12/utils.ts +0 -14
  112. package/app/components/layout-row/LayoutRow.vue +0 -171
  113. package/app/components/layout-row/stories/LayoutRow.stories.ts +0 -528
  114. package/app/pages/ui/layout-row.vue +0 -139
  115. /package/app/components/{forms → 05.forms}/form-errors/InputError.vue +0 -0
  116. /package/app/components/{forms → 05.forms}/form-errors/tests/InputError.spec.ts +0 -0
  117. /package/app/components/{forms → 05.forms}/form-fieldset/FormFieldset.vue +0 -0
  118. /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts +0 -0
  119. /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/combo-icons-secondary-chromium-darwin.png +0 -0
  120. /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/combo-icons-secondary-firefox-darwin.png +0 -0
  121. /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/combo-icons-secondary-webkit-darwin.png +0 -0
  122. /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/combo-icons-tertiary-chromium-darwin.png +0 -0
  123. /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/combo-icons-tertiary-firefox-darwin.png +0 -0
  124. /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/combo-icons-tertiary-webkit-darwin.png +0 -0
  125. /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/combo-primary-pending-chromium-darwin.png +0 -0
  126. /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/combo-primary-pending-firefox-darwin.png +0 -0
  127. /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/combo-primary-pending-webkit-darwin.png +0 -0
  128. /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/combo-secondary-pill-chromium-darwin.png +0 -0
  129. /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/combo-secondary-pill-firefox-darwin.png +0 -0
  130. /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/combo-secondary-pill-webkit-darwin.png +0 -0
  131. /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/combo-tertiary-readonly-chromium-darwin.png +0 -0
  132. /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/combo-tertiary-readonly-firefox-darwin.png +0 -0
  133. /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/combo-tertiary-readonly-webkit-darwin.png +0 -0
  134. /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/default-chromium-darwin.png +0 -0
  135. /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/default-firefox-darwin.png +0 -0
  136. /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/default-theme-default-chromium-darwin.png +0 -0
  137. /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/default-theme-default-firefox-darwin.png +0 -0
  138. /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/default-theme-default-webkit-darwin.png +0 -0
  139. /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/default-theme-error-chromium-darwin.png +0 -0
  140. /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/default-theme-error-firefox-darwin.png +0 -0
  141. /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/default-theme-error-webkit-darwin.png +0 -0
  142. /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/default-theme-success-chromium-darwin.png +0 -0
  143. /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/default-theme-success-firefox-darwin.png +0 -0
  144. /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/default-theme-success-webkit-darwin.png +0 -0
  145. /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/default-theme-warning-chromium-darwin.png +0 -0
  146. /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/default-theme-warning-firefox-darwin.png +0 -0
  147. /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/default-theme-warning-webkit-darwin.png +0 -0
  148. /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/default-variant-primary-chromium-darwin.png +0 -0
  149. /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/default-variant-primary-firefox-darwin.png +0 -0
  150. /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/default-variant-primary-webkit-darwin.png +0 -0
  151. /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/default-variant-secondary-chromium-darwin.png +0 -0
  152. /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/default-variant-secondary-firefox-darwin.png +0 -0
  153. /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/default-variant-secondary-webkit-darwin.png +0 -0
  154. /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/default-variant-tertiary-chromium-darwin.png +0 -0
  155. /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/default-variant-tertiary-firefox-darwin.png +0 -0
  156. /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/default-variant-tertiary-webkit-darwin.png +0 -0
  157. /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/default-webkit-darwin.png +0 -0
  158. /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/nuxt-icon-only-component-chromium-darwin.png +0 -0
  159. /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/nuxt-icon-only-component-firefox-darwin.png +0 -0
  160. /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/nuxt-icon-only-component-webkit-darwin.png +0 -0
  161. /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/state-pending-chromium-darwin.png +0 -0
  162. /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/state-pending-firefox-darwin.png +0 -0
  163. /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/state-pending-webkit-darwin.png +0 -0
  164. /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/state-pill-chromium-darwin.png +0 -0
  165. /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/state-pill-firefox-darwin.png +0 -0
  166. /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/state-pill-webkit-darwin.png +0 -0
  167. /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/state-readonly-chromium-darwin.png +0 -0
  168. /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/state-readonly-firefox-darwin.png +0 -0
  169. /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/state-readonly-webkit-darwin.png +0 -0
  170. /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/with-both-nuxt-icon-components-chromium-darwin.png +0 -0
  171. /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/with-both-nuxt-icon-components-firefox-darwin.png +0 -0
  172. /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/with-both-nuxt-icon-components-webkit-darwin.png +0 -0
  173. /package/app/components/{forms → 05.forms}/input-button/tests/InputButtonCore.spec.ts +0 -0
  174. /package/app/components/{forms → 05.forms}/input-button/tests/__snapshots__/InputButtonCore.spec.ts.snap +0 -0
  175. /package/app/components/{forms → 05.forms}/input-checkbox/MultipleCheckboxes.vue +0 -0
  176. /package/app/components/{forms → 05.forms}/input-checkbox/SingleCheckbox.vue +0 -0
  177. /package/app/components/{forms → 05.forms}/input-checkbox/tests/MultipleCheckboxes.spec.ts +0 -0
  178. /package/app/components/{forms → 05.forms}/input-checkbox/tests/data/tags.json +0 -0
  179. /package/app/components/{forms → 05.forms}/input-checkbox-radio/InputCheckboxRadioButton.vue +0 -0
  180. /package/app/components/{forms → 05.forms}/input-checkbox-radio/InputCheckboxRadioCore.vue +0 -0
  181. /package/app/components/{forms → 05.forms}/input-checkbox-radio/InputCheckboxRadioWithLabel.vue +0 -0
  182. /package/app/components/{forms → 05.forms}/input-checkbox-radio/tests/InputCheckboxRadioCore.spec.ts +0 -0
  183. /package/app/components/{forms → 05.forms}/input-copy/InputCopyCore.vue +0 -0
  184. /package/app/components/{forms → 05.forms}/input-copy/stories/InputCopyCore.stories.ts +0 -0
  185. /package/app/components/{forms → 05.forms}/input-copy/tests/InputCopyCore.spec.ts +0 -0
  186. /package/app/components/{forms → 05.forms}/input-copy/tests/__snapshots__/InputCopyCore.spec.ts.snap +0 -0
  187. /package/app/components/{forms → 05.forms}/input-description/InputDescription.vue +0 -0
  188. /package/app/components/{forms → 05.forms}/input-description/tests/InputDescription.spec.ts +0 -0
  189. /package/app/components/{forms → 05.forms}/input-label/InputLabel.vue +0 -0
  190. /package/app/components/{forms → 05.forms}/input-label/tests/InputLabel.spec.ts +0 -0
  191. /package/app/components/{forms → 05.forms}/input-number/InputNumberCore.vue +0 -0
  192. /package/app/components/{forms → 05.forms}/input-number/variants/InputNumberDefault.vue +0 -0
  193. /package/app/components/{forms → 05.forms}/input-radio/MultipleRadiobuttons.vue +0 -0
  194. /package/app/components/{forms → 05.forms}/input-radio/tests/MultipleRadioButtons.spec.ts +0 -0
  195. /package/app/components/{forms → 05.forms}/input-radio/tests/data/tags.json +0 -0
  196. /package/app/components/{forms → 05.forms}/input-range/InputRangeCore.vue +0 -0
  197. /package/app/components/{forms → 05.forms}/input-range/variants/InputRangeDefault.vue +0 -0
  198. /package/app/components/{forms → 05.forms}/input-range-fancy/InputRangeFancyCore.vue +0 -0
  199. /package/app/components/{forms → 05.forms}/input-range-fancy/InputRangeFancyWithLabel.vue +0 -0
  200. /package/app/components/{forms → 05.forms}/input-select/InputSelectCore.vue +0 -0
  201. /package/app/components/{forms → 05.forms}/input-select/variants/InputSelectWithLabel.vue +0 -0
  202. /package/app/components/{forms → 05.forms}/input-text/stories/InputPasswordWithLabel.stories.ts +0 -0
  203. /package/app/components/{forms → 05.forms}/input-text/stories/InputTextAsNumberWithLabel.stories.ts +0 -0
  204. /package/app/components/{forms → 05.forms}/input-text/stories/InputTextCore.stories.ts +0 -0
  205. /package/app/components/{forms → 05.forms}/input-text/stories/InputTextWithLabel.stories.ts +0 -0
  206. /package/app/components/{forms → 05.forms}/input-text/variants/InputPasswordWithLabel.vue +0 -0
  207. /package/app/components/{forms → 05.forms}/input-text/variants/InputTextWithLabel.vue +0 -0
  208. /package/app/components/{forms → 05.forms}/input-textarea/InputTextareaCore.vue +0 -0
  209. /package/app/components/{forms → 05.forms}/input-textarea/stories/InputTextareaCore.stories.ts +0 -0
  210. /package/app/components/{forms → 05.forms}/input-textarea/stories/InputTextareaWithLabel.stories.ts +0 -0
  211. /package/app/components/{forms → 05.forms}/input-textarea/variants/InputTextareaWithLabel.vue +0 -0
  212. /package/app/components/{forms → 05.forms}/pending-effect/PendingEffect.vue +0 -0
  213. /package/app/components/{forms → 05.forms}/toggle-switch/ToggleSwitchCore.vue +0 -0
  214. /package/app/components/{forms → 05.forms}/toggle-switch/stories/ToggleSwitchCore.stories.ts +0 -0
  215. /package/app/components/{forms → 05.forms}/toggle-switch/stories/ToggleSwitchWithLabel.stories.ts +0 -0
  216. /package/app/components/{forms → 05.forms}/toggle-switch/stories/ToggleSwitchWithLabelInline.stories.ts +0 -0
  217. /package/app/components/{forms → 05.forms}/toggle-switch/variants/ToggleSwitchWithLabel.vue +0 -0
  218. /package/app/components/{forms → 05.forms}/toggle-switch/variants/ToggleSwitchWithLabelInline.vue +0 -0
  219. /package/app/components/{forms → 05.forms}/triple-toggle-switch/TripleToggleSwitchCore.vue +0 -0
  220. /package/app/{components/forms/c12/prop-validators/index.ts → utils/prop-validators.ts} +0 -0
@@ -0,0 +1,163 @@
1
+ # DisplayDialog — Consumer Styling Guide
2
+
3
+ ## Public token API
4
+
5
+ All `--display-dialog-*` tokens are the stable override surface. Because dialogs are site-wide UI
6
+ elements — not inline components — the recommended approach is to set tokens once in a **global CSS
7
+ file** rather than per-instance via `styleClassPassthrough`.
8
+
9
+ ### Overlay
10
+
11
+ | Token | Default | Controls |
12
+ |---|---|---|
13
+ | `--display-dialog-backdrop-blur` | `blur(0.5rem)` | CSS filter applied to content behind the overlay |
14
+ | `--display-dialog-backdrop-background` | `rgba(0, 0, 0, 0.5)` | Overlay scrim colour |
15
+ | `--display-dialog-z-index` | `999999` | Stacking order of the overlay |
16
+ | `--display-dialog-transition-duration` | `200ms` | Open/close transition speed (opacity, display, close-button hover) |
17
+
18
+ ### Dialog panel
19
+
20
+ | Token | Default | Controls |
21
+ |---|---|---|
22
+ | `--display-dialog-inner-border-radius` | `0.8rem` | Panel corner rounding |
23
+ | `--display-dialog-inner-border` | `0.1rem solid light-dark(var(--slate-10), var(--slate-02))` | Panel border shorthand |
24
+ | `--display-dialog-inner-outline` | `0.1rem solid light-dark(var(--slate-10), var(--slate-00))` | Panel outer outline (sits outside the border) |
25
+ | `--display-dialog-inner-background` | `light-dark(var(--slate-00), var(--slate-10))` | Panel background colour |
26
+
27
+ ### Header
28
+
29
+ | Token | Default | Controls |
30
+ |---|---|---|
31
+ | `--display-dialog-header-padding` | `1.2rem` | Header area padding |
32
+ | `--display-dialog-header-button-margin` | `0` | Close button margin |
33
+ | `--display-dialog-header-button-padding` | `0.4rem` | Close button padding |
34
+ | `--display-dialog-header-button-border` | `0.1rem solid transparent` | Close button border (resting) |
35
+ | `--display-dialog-header-button-border-radius` | `0.4rem` | Close button corner rounding |
36
+ | `--display-dialog-header-button-outline` | `0.1rem solid transparent` | Close button outline (resting) |
37
+ | `--display-dialog-header-button-border-hover` | `0.1rem solid light-dark(var(--slate-08), var(--slate-04))` | Close button border on hover/focus |
38
+ | `--display-dialog-header-button-outline-hover` | `0.1rem solid light-dark(var(--slate-08), var(--slate-04))` | Close button outline on hover/focus |
39
+ | `--display-dialog-header-button-icon-color` | `light-dark(var(--slate-09), var(--slate-02))` | Close button icon colour |
40
+ | `--display-dialog-header-button-icon-size` | `2.4rem` | Close button icon size |
41
+
42
+ ### Content & footer
43
+
44
+ | Token | Default | Controls |
45
+ |---|---|---|
46
+ | `--display-dialog-content-padding` | `1.2rem` | Content area padding |
47
+ | `--display-dialog-footer-gap` | `1.2rem` | Gap between footer action buttons |
48
+ | `--display-dialog-footer-padding` | `1.2rem` | Footer area padding |
49
+
50
+ ---
51
+
52
+ ## Global theming — recommended approach
53
+
54
+ Create `assets/styles/setup/07.components/display-dialog.css` in the consuming app and set tokens
55
+ on `:root`. This applies to every `DisplayDialog` across the site.
56
+
57
+ ```css
58
+ /* assets/styles/setup/07.components/display-dialog.css */
59
+ :root {
60
+ --display-dialog-backdrop-background: rgba(0, 0, 0, 0.6);
61
+ --display-dialog-inner-border-radius: 1.2rem;
62
+ --display-dialog-inner-background: var(--brand-surface);
63
+ --display-dialog-inner-border: 0.1rem solid var(--brand-border);
64
+ --display-dialog-inner-outline: none;
65
+ --display-dialog-transition-duration: 250ms;
66
+
67
+ --display-dialog-header-button-icon-color: var(--brand-text-muted);
68
+ --display-dialog-footer-gap: 0.8rem;
69
+ }
70
+ ```
71
+
72
+ ---
73
+
74
+ ## Per-variant overrides
75
+
76
+ The `fullscreen` variant bypasses `--_inner-border-radius`, `--_inner-border`, and
77
+ `--_inner-outline` directly (setting them to `0`/`none`). To restyle the fullscreen panel,
78
+ target the private tokens on `.inner.fullscreen`:
79
+
80
+ ```css
81
+ .display-dialog {
82
+ .inner {
83
+ &.confirm {
84
+ /* e.g. constrain confirm panel width further */
85
+ max-width: 40rem;
86
+ }
87
+
88
+ &.alert {
89
+ --display-dialog-inner-border: 0.2rem solid var(--color-danger);
90
+ }
91
+
92
+ &.fullscreen {
93
+ /* private tokens are the only lever here */
94
+ --_inner-background: var(--brand-surface-alt);
95
+ }
96
+ }
97
+ }
98
+ ```
99
+
100
+ ---
101
+
102
+ ## Section targeting
103
+
104
+ Target `.header`, `.dialog-content`, and `.footer` directly to adjust layout within the panel:
105
+
106
+ ```css
107
+ .display-dialog {
108
+ .header {
109
+ border-bottom: 0.1rem solid var(--brand-border);
110
+ }
111
+
112
+ .dialog-content {
113
+ /* content area uses --display-dialog-content-padding */
114
+ }
115
+
116
+ .footer {
117
+ border-top: 0.1rem solid var(--brand-border);
118
+ justify-content: space-between; /* override default flex-end */
119
+ }
120
+ }
121
+ ```
122
+
123
+ ---
124
+
125
+ ## Page-scoped overrides
126
+
127
+ Because `<DisplayDialog>` renders inside the page's DOM tree (even though it is `position: fixed`),
128
+ you can scope overrides to a specific page without affecting the rest of the site:
129
+
130
+ ```css
131
+ /* In the consuming page's unscoped <style> block */
132
+ .checkout-page {
133
+ .display-dialog {
134
+ --display-dialog-inner-border-radius: 0;
135
+ --display-dialog-backdrop-background: rgba(0, 0, 0, 0.8);
136
+
137
+ .footer {
138
+ justify-content: stretch;
139
+ }
140
+ }
141
+ }
142
+ ```
143
+
144
+ ---
145
+
146
+ ## Per-instance overrides via styleClassPassthrough
147
+
148
+ Use sparingly — prefer global or page-scoped CSS for dialogs. When a single instance genuinely
149
+ needs a different look, pass a modifier class and target it alongside `.display-dialog`:
150
+
151
+ ```vue
152
+ <DisplayDialog :style-class-passthrough="['danger-dialog']" ...>
153
+ ```
154
+
155
+ ```css
156
+ .display-dialog.danger-dialog {
157
+ --display-dialog-backdrop-background: rgba(180, 0, 0, 0.4);
158
+
159
+ .inner {
160
+ --display-dialog-inner-border: 0.2rem solid var(--color-danger);
161
+ }
162
+ }
163
+ ```
@@ -0,0 +1,277 @@
1
+ <template>
2
+ <dialog
3
+ class="display-dialog"
4
+ :class="[elementClasses]"
5
+ :role="isAlert ? 'alertdialog' : 'dialog'"
6
+ :align-dialog
7
+ :justify-dialog
8
+ :open
9
+ :data-dialog-id="dataDialogId"
10
+ >
11
+ <focus-trap
12
+ v-model:active="open"
13
+ :escape-deactivates="!isAlert"
14
+ :click-outside-deactivates="!isAlert"
15
+ @deactivate="closeDialog()"
16
+ >
17
+ <div class="inner" :class="[variant]">
18
+ <div class="header">
19
+ <div v-if="hasTitle" class="col-left">
20
+ <slot name="dialogTitle"></slot>
21
+ </div>
22
+
23
+ <div class="col-right">
24
+ <button
25
+ data-test-id="display-dialog-header-close"
26
+ class="display-prompt-action"
27
+ @click.prevent="closeDialog()"
28
+ >
29
+ <Icon name="bitcoin-icons:cross-filled" class="icon" />
30
+ <span class="sr-only">Close</span>
31
+ </button>
32
+ </div>
33
+ </div>
34
+ <div
35
+ v-if="hasContent"
36
+ class="dialog-content"
37
+ :class="[{ 'allow-content-scroll': allowContentScroll }]"
38
+ >
39
+ <slot name="dialogContent"></slot>
40
+ </div>
41
+ <div v-if="hasFooter" class="footer">
42
+ <slot name="actionButtonLeft"></slot>
43
+ <slot name="actionButtonRight"></slot>
44
+ </div>
45
+ </div>
46
+ </focus-trap>
47
+ </dialog>
48
+ </template>
49
+
50
+ <script setup lang="ts">
51
+ import { FocusTrap } from "focus-trap-vue";
52
+ interface Props {
53
+ styleClassPassthrough?: string | string[];
54
+ variant?: "dialog" | "modal" | "confirm" | "alert" | "fullscreen";
55
+ justifyDialog?: "start" | "center" | "end";
56
+ alignDialog?: "start" | "center" | "end";
57
+ lockViewport?: boolean;
58
+ allowContentScroll?: boolean;
59
+ dataDialogId: string;
60
+ }
61
+
62
+ const props = withDefaults(defineProps<Props>(), {
63
+ styleClassPassthrough: () => [],
64
+ variant: "dialog",
65
+ justifyDialog: "center",
66
+ alignDialog: "center",
67
+ lockViewport: true,
68
+ allowContentScroll: false,
69
+ });
70
+
71
+ const { elementClasses } = useStyleClassPassthrough(props.styleClassPassthrough);
72
+
73
+ const isAlert = computed(() => props.variant === "alert");
74
+
75
+ const open = defineModel<boolean>();
76
+
77
+ const closeDialog = () => {
78
+ open.value = false;
79
+ if (props.lockViewport) {
80
+ document.body.classList.remove("lock");
81
+ }
82
+ };
83
+
84
+ const slots = useSlots();
85
+ const hasTitle = computed(() => !!slots.dialogTitle);
86
+ const hasContent = computed(() => !!slots.dialogContent);
87
+ const hasFooter = computed(() => !!(slots.actionButtonLeft || slots.actionButtonRight));
88
+
89
+ onMounted(() => {
90
+ if (props.lockViewport) {
91
+ document.body.classList.add("lock");
92
+ }
93
+ });
94
+ </script>
95
+
96
+ <style lang="css">
97
+ @layer components {
98
+ .display-dialog {
99
+ --_backdrop-blur: var(--display-dialog-backdrop-blur, blur(0.5rem));
100
+ --_backdrop-background: var(--display-dialog-backdrop-background, rgba(0, 0, 0, 0.5));
101
+ --_z-index: var(--display-dialog-z-index, 999999);
102
+ --_transition-duration: var(--display-dialog-transition-duration, 200ms);
103
+
104
+ --_inner-border-radius: var(--display-dialog-inner-border-radius, 0.8rem);
105
+ --_inner-border: var(--display-dialog-inner-border, 0.1rem solid light-dark(var(--slate-10), var(--slate-02)));
106
+ --_inner-outline: var(--display-dialog-inner-outline, 0.1rem solid light-dark(var(--slate-10), var(--slate-00)));
107
+ --_inner-background: var(--display-dialog-inner-background, light-dark(var(--slate-00), var(--slate-10)));
108
+
109
+ --_header-padding: var(--display-dialog-header-padding, 1.2rem);
110
+ --_header-button-margin: var(--display-dialog-header-button-margin, 0);
111
+ --_header-button-padding: var(--display-dialog-header-button-padding, 0.4rem);
112
+ --_header-button-border: var(--display-dialog-header-button-border, 0.1rem solid transparent);
113
+ --_header-button-border-radius: var(--display-dialog-header-button-border-radius, 0.4rem);
114
+ --_header-button-outline: var(--display-dialog-header-button-outline, 0.1rem solid transparent);
115
+ --_header-button-border-hover: var(--display-dialog-header-button-border-hover, 0.1rem solid light-dark(var(--slate-08), var(--slate-04)));
116
+ --_header-button-outline-hover: var(--display-dialog-header-button-outline-hover, 0.1rem solid light-dark(var(--slate-08), var(--slate-04)));
117
+ --_header-button-icon-color: var(--display-dialog-header-button-icon-color, light-dark(var(--slate-09), var(--slate-02)));
118
+ --_header-button-icon-size: var(--display-dialog-header-button-icon-size, 2.4rem);
119
+
120
+ --_content-padding: var(--display-dialog-content-padding, 1.2rem);
121
+ --_footer-gap: var(--display-dialog-footer-gap, 1.2rem);
122
+ --_footer-padding: var(--display-dialog-footer-padding, 1.2rem);
123
+
124
+ position: fixed;
125
+ left: 0;
126
+ top: 0;
127
+ width: 100%;
128
+ height: 100%;
129
+ backdrop-filter: var(--_backdrop-blur);
130
+ background-color: var(--_backdrop-background);
131
+ z-index: var(--_z-index);
132
+ opacity: 0;
133
+ border: none;
134
+ padding: 0;
135
+
136
+ display: none;
137
+ transition:
138
+ opacity var(--_transition-duration),
139
+ display var(--_transition-duration),
140
+ overlay var(--_transition-duration);
141
+ transition-behavior: allow-discrete;
142
+
143
+ &[open] {
144
+ display: flex;
145
+ opacity: 1;
146
+
147
+ @starting-style {
148
+ display: flex;
149
+ opacity: 0;
150
+ }
151
+ }
152
+
153
+ &[justify-dialog="start"] {
154
+ justify-content: flex-start;
155
+ }
156
+
157
+ &[justify-dialog="center"] {
158
+ justify-content: center;
159
+ }
160
+
161
+ &[justify-dialog="end"] {
162
+ justify-content: flex-end;
163
+ }
164
+
165
+ &[align-dialog="start"] {
166
+ align-items: flex-start;
167
+ }
168
+
169
+ &[align-dialog="center"] {
170
+ align-items: center;
171
+ }
172
+
173
+ &[align-dialog="end"] {
174
+ align-items: flex-end;
175
+ }
176
+
177
+ .inner {
178
+ display: grid;
179
+ grid-template-rows: auto 1fr auto;
180
+ border-radius: var(--_inner-border-radius);
181
+ border: var(--_inner-border);
182
+ outline: var(--_inner-outline);
183
+ background-color: var(--_inner-background);
184
+ height: initial;
185
+ width: 100vw;
186
+ overflow: hidden;
187
+
188
+ &.alert {
189
+ width: min(90%, 48rem);
190
+ }
191
+
192
+ &.confirm {
193
+ width: initial;
194
+ }
195
+
196
+ &.dialog {
197
+ height: 70dvh;
198
+ width: min(75%, 72rem);
199
+ }
200
+
201
+ &.fullscreen {
202
+ --_inner-border-radius: 0;
203
+ --_inner-border: none;
204
+ --_inner-outline: none;
205
+ width: 100%;
206
+ height: 100%;
207
+ }
208
+
209
+ &.modal {
210
+ width: initial;
211
+ }
212
+
213
+ .header {
214
+ display: flex;
215
+ align-items: center;
216
+ padding: var(--_header-padding);
217
+
218
+ .col-left {
219
+ flex: 1;
220
+ }
221
+
222
+ .col-right {
223
+ margin-inline-start: auto;
224
+
225
+ .display-prompt-action {
226
+ background-color: transparent;
227
+ display: block flex;
228
+ align-items: center;
229
+ justify-content: center;
230
+ margin: var(--_header-button-margin);
231
+ padding: var(--_header-button-padding);
232
+ border: var(--_header-button-border);
233
+ border-radius: var(--_header-button-border-radius);
234
+ outline: var(--_header-button-outline);
235
+
236
+ transition:
237
+ border-color var(--_transition-duration),
238
+ outline-color var(--_transition-duration);
239
+
240
+ &:hover,
241
+ &:focus-visible {
242
+ cursor: pointer;
243
+ border: var(--_header-button-border-hover);
244
+ outline: var(--_header-button-outline-hover);
245
+ }
246
+
247
+ .icon {
248
+ color: var(--_header-button-icon-color);
249
+ display: block;
250
+ font-size: var(--_header-button-icon-size);
251
+ }
252
+ }
253
+ }
254
+ }
255
+
256
+ .dialog-content {
257
+ overflow: hidden;
258
+ padding: var(--_content-padding);
259
+
260
+ &.allow-content-scroll {
261
+ overflow-y: auto;
262
+ &::-webkit-scrollbar {
263
+ display: none;
264
+ }
265
+ }
266
+ }
267
+
268
+ .footer {
269
+ display: flex;
270
+ gap: var(--_footer-gap);
271
+ justify-content: flex-end;
272
+ padding: var(--_footer-padding);
273
+ }
274
+ }
275
+ }
276
+ }
277
+ </style>
@@ -0,0 +1,177 @@
1
+ import type { Meta, StoryFn } from "@nuxtjs/storybook";
2
+ import { ref } from "vue";
3
+ import StorybookComponent from "../DisplayDialog.vue";
4
+
5
+ type StoryArgs = {
6
+ variant: "dialog" | "modal" | "confirm" | "alert" | "fullscreen";
7
+ allowContentScroll: boolean;
8
+ justifyDialog: "start" | "center" | "end";
9
+ alignDialog: "start" | "center" | "end";
10
+ };
11
+
12
+ export default {
13
+ title: "Atoms/DisplayDialog",
14
+ component: StorybookComponent,
15
+ argTypes: {
16
+ variant: {
17
+ control: { type: "select" },
18
+ options: ["dialog", "modal", "confirm", "alert", "fullscreen"],
19
+ description: "Controls sizing, shape, and ARIA role of the dialog panel",
20
+ table: { category: "Appearance" },
21
+ },
22
+ allowContentScroll: {
23
+ control: { type: "boolean" },
24
+ description: "Allow the content area to scroll independently",
25
+ table: { category: "Behaviour" },
26
+ },
27
+ justifyDialog: {
28
+ control: { type: "inline-radio" },
29
+ options: ["start", "center", "end"],
30
+ description: "Horizontal position of the dialog panel within the overlay",
31
+ table: { category: "Layout" },
32
+ },
33
+ alignDialog: {
34
+ control: { type: "inline-radio" },
35
+ options: ["start", "center", "end"],
36
+ description: "Vertical position of the dialog panel within the overlay",
37
+ table: { category: "Layout" },
38
+ },
39
+ styleClassPassthrough: { table: { disable: true } },
40
+ lockViewport: { table: { disable: true } },
41
+ dataDialogId: { table: { disable: true } },
42
+ },
43
+ args: {
44
+ variant: "dialog",
45
+ allowContentScroll: false,
46
+ justifyDialog: "center",
47
+ alignDialog: "center",
48
+ },
49
+ parameters: {
50
+ docs: {
51
+ description: {
52
+ component:
53
+ "A dialog overlay with header, scrollable content, and footer action slots. Supports `dialog`, `confirm`, `alert`, `modal`, and `fullscreen` variants. The `alert` variant sets `role=alertdialog` and disables dismiss-on-outside-click and Escape.",
54
+ },
55
+ },
56
+ },
57
+ } as Meta<StoryArgs>;
58
+
59
+ const triggerButtonStyles =
60
+ "padding: 0.8rem 1.6rem; border-radius: 0.4rem; border: 0.1rem solid currentColor; background: transparent; cursor: pointer; font-size: 1.4rem;";
61
+
62
+ const actionButtonStyles =
63
+ "padding: 0.8rem 1.6rem; border-radius: 0.4rem; border: 0.1rem solid currentColor; background: transparent; cursor: pointer; font-size: 1.4rem;";
64
+
65
+ const Template: StoryFn<StoryArgs> = (args) => ({
66
+ components: { StorybookComponent },
67
+ setup() {
68
+ const open = ref(false);
69
+ return { args, open };
70
+ },
71
+ template: `
72
+ <div style="padding: 4rem; display: flex; justify-content: center;">
73
+ <button :style="'${triggerButtonStyles}'" @click="open = true">Open dialog</button>
74
+ <StorybookComponent
75
+ v-model="open"
76
+ :variant="args.variant"
77
+ :allow-content-scroll="args.allowContentScroll"
78
+ :justify-dialog="args.justifyDialog"
79
+ :align-dialog="args.alignDialog"
80
+ :lock-viewport="false"
81
+ data-dialog-id="storybook-dialog"
82
+ >
83
+ <template #dialogTitle>
84
+ <p style="margin: 0; font-weight: 700; font-size: 1.6rem;">Dialog title</p>
85
+ </template>
86
+ <template #dialogContent>
87
+ <p style="margin: 0; line-height: 1.6;">
88
+ This is the dialog content area. It accepts any markup via the
89
+ <code>#dialogContent</code> slot.
90
+ </p>
91
+ </template>
92
+ <template #actionButtonLeft>
93
+ <button :style="'${actionButtonStyles}'" @click="open = false">Cancel</button>
94
+ </template>
95
+ <template #actionButtonRight>
96
+ <button :style="'${actionButtonStyles}'" @click="open = false">Confirm</button>
97
+ </template>
98
+ </StorybookComponent>
99
+ </div>
100
+ `,
101
+ });
102
+
103
+ const ScrollableTemplate: StoryFn<StoryArgs> = (args) => ({
104
+ components: { StorybookComponent },
105
+ setup() {
106
+ const open = ref(false);
107
+ return { args, open };
108
+ },
109
+ template: `
110
+ <div style="padding: 4rem; display: flex; justify-content: center;">
111
+ <button :style="'${triggerButtonStyles}'" @click="open = true">Open dialog</button>
112
+ <StorybookComponent
113
+ v-model="open"
114
+ variant="dialog"
115
+ :allow-content-scroll="true"
116
+ :lock-viewport="false"
117
+ data-dialog-id="storybook-scrollable"
118
+ >
119
+ <template #dialogTitle>
120
+ <p style="margin: 0; font-weight: 700; font-size: 1.6rem;">Scrollable content</p>
121
+ </template>
122
+ <template #dialogContent>
123
+ <div style="padding: 1.2rem 0;">
124
+ <p style="margin: 0 0 1.6rem; line-height: 1.6;">Lorem ipsum odor amet, consectetuer adipiscing elit. Scelerisque tincidunt vestibulum litora torquent aliquam a. Sem litora tellus mattis nisi vehicula sodales arcu egestas.</p>
125
+ <p style="margin: 0 0 1.6rem; line-height: 1.6;">Justo molestie felis tellus tellus taciti? Ullamcorper viverra quis felis donec aliquam torquent imperdiet. Curabitur vitae quis malesuada imperdiet hendrerit felis quam dictum.</p>
126
+ <p style="margin: 0 0 1.6rem; line-height: 1.6;">Lobortis efficitur enim litora dictum montes. Sagittis eget etiam curae suspendisse cubilia. Ante aliquam orci mus ultricies nostra.</p>
127
+ <p style="margin: 0 0 1.6rem; line-height: 1.6;">Venenatis adipiscing integer eget donec ridiculus risus. Nulla quis sollicitudin sem nam bibendum ligula. Curabitur malesuada platea egestas venenatis in torquent.</p>
128
+ <p style="margin: 0; line-height: 1.6;">Curae maximus nam tortor porta sodales at, feugiat iaculis integer. Lacus habitasse odio fames natoque neque varius nostra.</p>
129
+ </div>
130
+ </template>
131
+ <template #actionButtonLeft>
132
+ <button :style="'${actionButtonStyles}'" @click="open = false">Cancel</button>
133
+ </template>
134
+ <template #actionButtonRight>
135
+ <button :style="'${actionButtonStyles}'" @click="open = false">Confirm</button>
136
+ </template>
137
+ </StorybookComponent>
138
+ </div>
139
+ `,
140
+ });
141
+
142
+ export const Default = Template.bind({});
143
+ Default.args = { variant: "dialog" };
144
+
145
+ export const Confirm = Template.bind({});
146
+ Confirm.args = { variant: "confirm" };
147
+ Confirm.parameters = {
148
+ docs: {
149
+ description: { story: "Compact dialog sized to its content. Use for simple yes/no confirmations." },
150
+ },
151
+ };
152
+
153
+ export const Alert = Template.bind({});
154
+ Alert.args = { variant: "alert" };
155
+ Alert.parameters = {
156
+ docs: {
157
+ description: {
158
+ story:
159
+ "Sets `role=alertdialog`. Escape and outside-click are both disabled — the user must take explicit action via the footer buttons.",
160
+ },
161
+ },
162
+ };
163
+
164
+ export const Fullscreen = Template.bind({});
165
+ Fullscreen.args = { variant: "fullscreen" };
166
+ Fullscreen.parameters = {
167
+ docs: {
168
+ description: { story: "Fills the entire viewport. No border or border-radius. Useful for immersive multi-step flows." },
169
+ },
170
+ };
171
+
172
+ export const ScrollableContent = ScrollableTemplate.bind({});
173
+ ScrollableContent.parameters = {
174
+ docs: {
175
+ description: { story: "Content area scrolls independently when it overflows the fixed-height dialog panel." },
176
+ },
177
+ };