@brandlab-digital/site-next 3.13.0 → 3.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (274) hide show
  1. package/README.md +79 -0
  2. package/dist/analytics.d.ts +1 -1
  3. package/dist/analytics.d.ts.map +1 -1
  4. package/dist/analytics.js +2 -0
  5. package/dist/analytics.js.map +1 -1
  6. package/dist/contact/delivery.d.ts +81 -0
  7. package/dist/contact/delivery.d.ts.map +1 -0
  8. package/dist/contact/delivery.js +138 -0
  9. package/dist/contact/delivery.js.map +1 -0
  10. package/dist/contact/resend-webhook.d.ts +72 -0
  11. package/dist/contact/resend-webhook.d.ts.map +1 -0
  12. package/dist/contact/resend-webhook.js +300 -0
  13. package/dist/contact/resend-webhook.js.map +1 -0
  14. package/dist/contact/route-handler.d.ts +16 -0
  15. package/dist/contact/route-handler.d.ts.map +1 -1
  16. package/dist/contact/route-handler.js +8 -0
  17. package/dist/contact/route-handler.js.map +1 -1
  18. package/dist/contact/server-entry.d.ts +2 -0
  19. package/dist/contact/server-entry.d.ts.map +1 -1
  20. package/dist/contact/server-entry.js +2 -0
  21. package/dist/contact/server-entry.js.map +1 -1
  22. package/dist/contact/server.d.ts +26 -0
  23. package/dist/contact/server.d.ts.map +1 -1
  24. package/dist/contact/server.js +48 -3
  25. package/dist/contact/server.js.map +1 -1
  26. package/dist/navigation/constants.d.ts +11 -2
  27. package/dist/navigation/constants.d.ts.map +1 -1
  28. package/dist/navigation/constants.js +11 -2
  29. package/dist/navigation/constants.js.map +1 -1
  30. package/dist/navigation/index.d.ts +1 -1
  31. package/dist/navigation/index.d.ts.map +1 -1
  32. package/dist/navigation/index.js +1 -1
  33. package/dist/navigation/index.js.map +1 -1
  34. package/dist/navigation/use-back-to-top.d.ts.map +1 -1
  35. package/dist/navigation/use-back-to-top.js +12 -4
  36. package/dist/navigation/use-back-to-top.js.map +1 -1
  37. package/dist/navigation/use-header-metrics.d.ts +1 -1
  38. package/dist/navigation/use-header-metrics.js +1 -1
  39. package/dist/navigation/use-header-metrics.js.map +1 -1
  40. package/dist/navigation/use-sticky-call-bar.d.ts +2 -1
  41. package/dist/navigation/use-sticky-call-bar.d.ts.map +1 -1
  42. package/dist/navigation/use-sticky-call-bar.js +11 -2
  43. package/dist/navigation/use-sticky-call-bar.js.map +1 -1
  44. package/dist/next-config.d.ts +17 -1
  45. package/dist/next-config.d.ts.map +1 -1
  46. package/dist/next-config.js +36 -2
  47. package/dist/next-config.js.map +1 -1
  48. package/dist/ui-kit/brandlab-skin.d.ts +50 -1
  49. package/dist/ui-kit/brandlab-skin.d.ts.map +1 -1
  50. package/dist/ui-kit/brandlab-skin.js.map +1 -1
  51. package/dist/ui-kit/form/photo-upload.d.ts +4 -1
  52. package/dist/ui-kit/form/photo-upload.d.ts.map +1 -1
  53. package/dist/ui-kit/form/photo-upload.js +4 -4
  54. package/dist/ui-kit/form/photo-upload.js.map +1 -1
  55. package/dist/ui-kit/form/quote-form.d.ts +4 -1
  56. package/dist/ui-kit/form/quote-form.d.ts.map +1 -1
  57. package/dist/ui-kit/form/quote-form.js.map +1 -1
  58. package/dist/ui-kit/form/thank-you.d.ts +4 -1
  59. package/dist/ui-kit/form/thank-you.d.ts.map +1 -1
  60. package/dist/ui-kit/form/thank-you.js +2 -2
  61. package/dist/ui-kit/form/thank-you.js.map +1 -1
  62. package/dist/ui-kit/icon-glyphs.d.ts +41 -0
  63. package/dist/ui-kit/icon-glyphs.d.ts.map +1 -0
  64. package/dist/ui-kit/icon-glyphs.js +138 -0
  65. package/dist/ui-kit/icon-glyphs.js.map +1 -0
  66. package/dist/ui-kit/icon-sprite.d.ts +19 -0
  67. package/dist/ui-kit/icon-sprite.d.ts.map +1 -0
  68. package/dist/ui-kit/icon-sprite.js +44 -0
  69. package/dist/ui-kit/icon-sprite.js.map +1 -0
  70. package/dist/ui-kit/icons.d.ts +38 -3
  71. package/dist/ui-kit/icons.d.ts.map +1 -1
  72. package/dist/ui-kit/icons.js +47 -64
  73. package/dist/ui-kit/icons.js.map +1 -1
  74. package/dist/ui-kit/prefetch.d.ts +19 -10
  75. package/dist/ui-kit/prefetch.d.ts.map +1 -1
  76. package/dist/ui-kit/prefetch.js +23 -10
  77. package/dist/ui-kit/prefetch.js.map +1 -1
  78. package/dist/ui-kit/primitives/badge.d.ts +25 -0
  79. package/dist/ui-kit/primitives/badge.d.ts.map +1 -0
  80. package/dist/ui-kit/primitives/badge.js +21 -0
  81. package/dist/ui-kit/primitives/badge.js.map +1 -0
  82. package/dist/ui-kit/primitives/breadcrumbs.d.ts +27 -0
  83. package/dist/ui-kit/primitives/breadcrumbs.d.ts.map +1 -0
  84. package/dist/ui-kit/primitives/breadcrumbs.js +40 -0
  85. package/dist/ui-kit/primitives/breadcrumbs.js.map +1 -0
  86. package/dist/ui-kit/primitives/button.d.ts +32 -0
  87. package/dist/ui-kit/primitives/button.d.ts.map +1 -0
  88. package/dist/ui-kit/primitives/button.js +8 -0
  89. package/dist/ui-kit/primitives/button.js.map +1 -0
  90. package/dist/ui-kit/primitives/card.d.ts +40 -0
  91. package/dist/ui-kit/primitives/card.d.ts.map +1 -0
  92. package/dist/ui-kit/primitives/card.js +8 -0
  93. package/dist/ui-kit/primitives/card.js.map +1 -0
  94. package/dist/ui-kit/primitives/index.d.ts +11 -2
  95. package/dist/ui-kit/primitives/index.d.ts.map +1 -1
  96. package/dist/ui-kit/primitives/index.js +11 -2
  97. package/dist/ui-kit/primitives/index.js.map +1 -1
  98. package/dist/ui-kit/primitives/layout.d.ts +12 -0
  99. package/dist/ui-kit/primitives/layout.d.ts.map +1 -1
  100. package/dist/ui-kit/primitives/layout.js +20 -2
  101. package/dist/ui-kit/primitives/layout.js.map +1 -1
  102. package/dist/ui-kit/primitives/links.d.ts +15 -0
  103. package/dist/ui-kit/primitives/links.d.ts.map +1 -1
  104. package/dist/ui-kit/primitives/links.js +6 -2
  105. package/dist/ui-kit/primitives/links.js.map +1 -1
  106. package/dist/ui-kit/primitives/lists.d.ts +51 -0
  107. package/dist/ui-kit/primitives/lists.d.ts.map +1 -0
  108. package/dist/ui-kit/primitives/lists.js +34 -0
  109. package/dist/ui-kit/primitives/lists.js.map +1 -0
  110. package/dist/ui-kit/primitives/media-frame.d.ts +28 -0
  111. package/dist/ui-kit/primitives/media-frame.d.ts.map +1 -0
  112. package/dist/ui-kit/primitives/media-frame.js +58 -0
  113. package/dist/ui-kit/primitives/media-frame.js.map +1 -0
  114. package/dist/ui-kit/primitives/media.d.ts +38 -0
  115. package/dist/ui-kit/primitives/media.d.ts.map +1 -0
  116. package/dist/ui-kit/primitives/media.js +9 -0
  117. package/dist/ui-kit/primitives/media.js.map +1 -0
  118. package/dist/ui-kit/primitives/quote-button.d.ts +25 -2
  119. package/dist/ui-kit/primitives/quote-button.d.ts.map +1 -1
  120. package/dist/ui-kit/primitives/quote-button.js +25 -3
  121. package/dist/ui-kit/primitives/quote-button.js.map +1 -1
  122. package/dist/ui-kit/primitives/stat.d.ts +25 -0
  123. package/dist/ui-kit/primitives/stat.d.ts.map +1 -0
  124. package/dist/ui-kit/primitives/stat.js +7 -0
  125. package/dist/ui-kit/primitives/stat.js.map +1 -0
  126. package/dist/ui-kit/repeated-slots.d.ts +153 -0
  127. package/dist/ui-kit/repeated-slots.d.ts.map +1 -0
  128. package/dist/ui-kit/repeated-slots.js +97 -0
  129. package/dist/ui-kit/repeated-slots.js.map +1 -0
  130. package/dist/ui-kit/sections/accordion.d.ts +4 -1
  131. package/dist/ui-kit/sections/accordion.d.ts.map +1 -1
  132. package/dist/ui-kit/sections/accordion.js +2 -2
  133. package/dist/ui-kit/sections/accordion.js.map +1 -1
  134. package/dist/ui-kit/sections/area-map.d.ts +64 -0
  135. package/dist/ui-kit/sections/area-map.d.ts.map +1 -0
  136. package/dist/ui-kit/sections/area-map.js +142 -0
  137. package/dist/ui-kit/sections/area-map.js.map +1 -0
  138. package/dist/ui-kit/sections/before-after.d.ts +59 -0
  139. package/dist/ui-kit/sections/before-after.d.ts.map +1 -0
  140. package/dist/ui-kit/sections/before-after.js +42 -0
  141. package/dist/ui-kit/sections/before-after.js.map +1 -0
  142. package/dist/ui-kit/sections/contact-block.d.ts +4 -1
  143. package/dist/ui-kit/sections/contact-block.d.ts.map +1 -1
  144. package/dist/ui-kit/sections/contact-block.js +3 -3
  145. package/dist/ui-kit/sections/contact-block.js.map +1 -1
  146. package/dist/ui-kit/sections/council-rules.d.ts +64 -0
  147. package/dist/ui-kit/sections/council-rules.d.ts.map +1 -0
  148. package/dist/ui-kit/sections/council-rules.js +46 -0
  149. package/dist/ui-kit/sections/council-rules.js.map +1 -0
  150. package/dist/ui-kit/sections/coverage.d.ts +53 -0
  151. package/dist/ui-kit/sections/coverage.d.ts.map +1 -0
  152. package/dist/ui-kit/sections/coverage.js +57 -0
  153. package/dist/ui-kit/sections/coverage.js.map +1 -0
  154. package/dist/ui-kit/sections/emergency-band.d.ts +60 -0
  155. package/dist/ui-kit/sections/emergency-band.d.ts.map +1 -0
  156. package/dist/ui-kit/sections/emergency-band.js +43 -0
  157. package/dist/ui-kit/sections/emergency-band.js.map +1 -0
  158. package/dist/ui-kit/sections/faqs.d.ts +4 -1
  159. package/dist/ui-kit/sections/faqs.d.ts.map +1 -1
  160. package/dist/ui-kit/sections/faqs.js +4 -5
  161. package/dist/ui-kit/sections/faqs.js.map +1 -1
  162. package/dist/ui-kit/sections/gallery.d.ts +60 -0
  163. package/dist/ui-kit/sections/gallery.d.ts.map +1 -0
  164. package/dist/ui-kit/sections/gallery.js +39 -0
  165. package/dist/ui-kit/sections/gallery.js.map +1 -0
  166. package/dist/ui-kit/sections/hero.d.ts +118 -0
  167. package/dist/ui-kit/sections/hero.d.ts.map +1 -0
  168. package/dist/ui-kit/sections/hero.js +58 -0
  169. package/dist/ui-kit/sections/hero.js.map +1 -0
  170. package/dist/ui-kit/sections/index.d.ts +16 -1
  171. package/dist/ui-kit/sections/index.d.ts.map +1 -1
  172. package/dist/ui-kit/sections/index.js +16 -1
  173. package/dist/ui-kit/sections/index.js.map +1 -1
  174. package/dist/ui-kit/sections/licences.d.ts +72 -0
  175. package/dist/ui-kit/sections/licences.d.ts.map +1 -0
  176. package/dist/ui-kit/sections/licences.js +46 -0
  177. package/dist/ui-kit/sections/licences.js.map +1 -0
  178. package/dist/ui-kit/sections/local-facts.d.ts +78 -0
  179. package/dist/ui-kit/sections/local-facts.d.ts.map +1 -0
  180. package/dist/ui-kit/sections/local-facts.js +32 -0
  181. package/dist/ui-kit/sections/local-facts.js.map +1 -0
  182. package/dist/ui-kit/sections/nearby-areas.d.ts +50 -0
  183. package/dist/ui-kit/sections/nearby-areas.d.ts.map +1 -0
  184. package/dist/ui-kit/sections/nearby-areas.js +49 -0
  185. package/dist/ui-kit/sections/nearby-areas.js.map +1 -0
  186. package/dist/ui-kit/sections/nearby-jobs.d.ts +66 -0
  187. package/dist/ui-kit/sections/nearby-jobs.d.ts.map +1 -0
  188. package/dist/ui-kit/sections/nearby-jobs.js +49 -0
  189. package/dist/ui-kit/sections/nearby-jobs.js.map +1 -0
  190. package/dist/ui-kit/sections/price-guide.d.ts +4 -1
  191. package/dist/ui-kit/sections/price-guide.d.ts.map +1 -1
  192. package/dist/ui-kit/sections/price-guide.js +3 -3
  193. package/dist/ui-kit/sections/price-guide.js.map +1 -1
  194. package/dist/ui-kit/sections/price-table.d.ts +7 -9
  195. package/dist/ui-kit/sections/price-table.d.ts.map +1 -1
  196. package/dist/ui-kit/sections/price-table.js +8 -8
  197. package/dist/ui-kit/sections/price-table.js.map +1 -1
  198. package/dist/ui-kit/sections/projects.d.ts +79 -0
  199. package/dist/ui-kit/sections/projects.d.ts.map +1 -0
  200. package/dist/ui-kit/sections/projects.js +69 -0
  201. package/dist/ui-kit/sections/projects.js.map +1 -0
  202. package/dist/ui-kit/sections/proof-strip.d.ts +4 -1
  203. package/dist/ui-kit/sections/proof-strip.d.ts.map +1 -1
  204. package/dist/ui-kit/sections/proof-strip.js +2 -2
  205. package/dist/ui-kit/sections/proof-strip.js.map +1 -1
  206. package/dist/ui-kit/sections/quote-checklist.d.ts +43 -0
  207. package/dist/ui-kit/sections/quote-checklist.d.ts.map +1 -0
  208. package/dist/ui-kit/sections/quote-checklist.js +19 -0
  209. package/dist/ui-kit/sections/quote-checklist.js.map +1 -0
  210. package/dist/ui-kit/sections/related-services.d.ts +41 -0
  211. package/dist/ui-kit/sections/related-services.d.ts.map +1 -0
  212. package/dist/ui-kit/sections/related-services.js +52 -0
  213. package/dist/ui-kit/sections/related-services.js.map +1 -0
  214. package/dist/ui-kit/sections/reviews-band.d.ts +16 -2
  215. package/dist/ui-kit/sections/reviews-band.d.ts.map +1 -1
  216. package/dist/ui-kit/sections/reviews-band.js +13 -2
  217. package/dist/ui-kit/sections/reviews-band.js.map +1 -1
  218. package/dist/ui-kit/sections/services-grid.d.ts +82 -0
  219. package/dist/ui-kit/sections/services-grid.d.ts.map +1 -0
  220. package/dist/ui-kit/sections/services-grid.js +90 -0
  221. package/dist/ui-kit/sections/services-grid.js.map +1 -0
  222. package/dist/ui-kit/sections/site-footer.d.ts +4 -1
  223. package/dist/ui-kit/sections/site-footer.d.ts.map +1 -1
  224. package/dist/ui-kit/sections/site-footer.js +6 -6
  225. package/dist/ui-kit/sections/site-footer.js.map +1 -1
  226. package/dist/ui-kit/sections/work-photos.d.ts +15 -0
  227. package/dist/ui-kit/sections/work-photos.d.ts.map +1 -0
  228. package/dist/ui-kit/sections/work-photos.js +24 -0
  229. package/dist/ui-kit/sections/work-photos.js.map +1 -0
  230. package/dist/ui-kit/shell/back-to-top.js +1 -1
  231. package/dist/ui-kit/shell/back-to-top.js.map +1 -1
  232. package/dist/ui-kit/shell/current-link.d.ts +21 -5
  233. package/dist/ui-kit/shell/current-link.d.ts.map +1 -1
  234. package/dist/ui-kit/shell/current-link.js +16 -5
  235. package/dist/ui-kit/shell/current-link.js.map +1 -1
  236. package/dist/ui-kit/shell/drawer-client.js +1 -1
  237. package/dist/ui-kit/shell/drawer-client.js.map +1 -1
  238. package/dist/ui-kit/shell/intent-prefetch.d.ts.map +1 -1
  239. package/dist/ui-kit/shell/intent-prefetch.js +3 -2
  240. package/dist/ui-kit/shell/intent-prefetch.js.map +1 -1
  241. package/dist/ui-kit/shell/mobile-call-bar.d.ts +6 -1
  242. package/dist/ui-kit/shell/mobile-call-bar.d.ts.map +1 -1
  243. package/dist/ui-kit/shell/mobile-call-bar.js +6 -3
  244. package/dist/ui-kit/shell/mobile-call-bar.js.map +1 -1
  245. package/dist/ui-kit/shell/mobile-drawer.d.ts +7 -3
  246. package/dist/ui-kit/shell/mobile-drawer.d.ts.map +1 -1
  247. package/dist/ui-kit/shell/mobile-drawer.js +21 -5
  248. package/dist/ui-kit/shell/mobile-drawer.js.map +1 -1
  249. package/dist/ui-kit/shell/shell-quote.d.ts +10 -0
  250. package/dist/ui-kit/shell/shell-quote.d.ts.map +1 -0
  251. package/dist/ui-kit/shell/shell-quote.js +13 -0
  252. package/dist/ui-kit/shell/shell-quote.js.map +1 -0
  253. package/dist/ui-kit/shell/site-header.d.ts +5 -2
  254. package/dist/ui-kit/shell/site-header.d.ts.map +1 -1
  255. package/dist/ui-kit/shell/site-header.js +9 -9
  256. package/dist/ui-kit/shell/site-header.js.map +1 -1
  257. package/dist/ui-kit/shell/social-links.d.ts +1 -2
  258. package/dist/ui-kit/shell/social-links.d.ts.map +1 -1
  259. package/dist/ui-kit/shell/social-links.js +6 -3
  260. package/dist/ui-kit/shell/social-links.js.map +1 -1
  261. package/dist/ui-kit/shell/utility-bar.d.ts +4 -1
  262. package/dist/ui-kit/shell/utility-bar.d.ts.map +1 -1
  263. package/dist/ui-kit/shell/utility-bar.js +2 -2
  264. package/dist/ui-kit/shell/utility-bar.js.map +1 -1
  265. package/dist/ui-kit/skin-index.d.ts +2 -1
  266. package/dist/ui-kit/skin-index.d.ts.map +1 -1
  267. package/dist/ui-kit/skin-index.js +2 -1
  268. package/dist/ui-kit/skin-index.js.map +1 -1
  269. package/dist/ui-kit/skin.d.ts +21 -4
  270. package/dist/ui-kit/skin.d.ts.map +1 -1
  271. package/dist/ui-kit/skin.js +14 -1
  272. package/dist/ui-kit/skin.js.map +1 -1
  273. package/dist/ui-kit/structure.css +793 -10
  274. package/package.json +6 -2
@@ -0,0 +1 @@
1
+ {"version":3,"file":"media-frame.js","sourceRoot":"","sources":["../../../src/ui-kit/primitives/media-frame.tsx"],"names":[],"mappings":"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","sourcesContent":["/**\n * `MediaFrame` (3.14.0, F13): one image from the site's media manifest in a frame of an allowed ratio. Server\n * component over `next/image`, and the library's one image path: `Media` and the hero render through it, so the\n * \"Illustration\" label and the sizing rule below live here only. It is provenance-aware: the root carries\n * `data-provenance`, and an AI image shows the locked visible label \"Illustration\" inside the `<figcaption>`, so the\n * figure's accessible caption names it an illustration too. A caption (\"{what}, {suburb}, {month year}\") or the label\n * makes the root a `<figure>`; otherwise it is a `<div>`.\n *\n * Sizing (cost item 1g) is one of two kinds, and the type takes exactly one:\n * - **fluid** (`sizes`, which must have a `vw` part, for example `(min-width: 1024px) 50vw, 100vw`): Next keeps only the\n * widths the layout can use.\n * - **fixed** (`displayWidth`, the CSS width in pixels): no `sizes` at all, so Next emits a 1x and a 2x candidate only.\n * A `sizes` without `vw` (for example `sizes=\"148px\"`) makes Next list all 16 widths, which was 28–30% of some pages'\n * HTML; it is refused here.\n *\n * `priority` is for the page's largest image (the hero): preloaded and fetched with high priority, never lazy. Every\n * other image loads lazily.\n */\nimport Image from 'next/image'\nimport type { ReactNode } from 'react'\nimport { BRANDLAB_MEDIA_RATIOS, type BrandlabMediaEntry, type BrandlabMediaRatio } from '@brandlab-digital/site-core/media'\nimport { slot, type SkinEntry } from '../skin.js'\n\n/** What a frame needs from a `media.ts` entry; a whole `BrandlabMediaEntry` fits. */\nexport type UiMedia = Pick<BrandlabMediaEntry, 'src' | 'width' | 'height' | 'alt' | 'provenance'> &\n Partial<Pick<BrandlabMediaEntry, 'decorative' | 'focalPoint'>>\n\nexport type MediaFrameSlot = 'root' | 'img' | 'caption' | 'label'\nexport type MediaFrameSkin = SkinEntry<MediaFrameSlot>\n\n/** The locked visible label on an AI image (F13; truth wording, not site copy). */\nexport const ILLUSTRATION_LABEL = 'Illustration'\n\n/** Exactly one sizing: `sizes` with a `vw` part for a fluid image, or `displayWidth` for a fixed-size one. */\nexport type MediaFrameSizing =\n | { readonly sizes: string; readonly displayWidth?: never }\n | { readonly displayWidth: number; readonly sizes?: never }\n\nexport type MediaFrameProps = MediaFrameSkin &\n MediaFrameSizing & {\n readonly media: UiMedia\n /** Crop to an allowed ratio; by default the frame keeps the image's own shape. */\n readonly ratio?: BrandlabMediaRatio\n /** \"{what}, {suburb}, {month year}\", only when the photo really shows that job. */\n readonly caption?: ReactNode\n /** The page's largest image: preloaded, high fetch priority, never lazy. */\n readonly priority?: boolean\n }\n\n/** Next's own test for a `vw` part in `sizes` (shared/lib/get-img-props). */\nconst VIEWPORT_WIDTH = /(^|\\s)(1?\\d?\\d)vw/\n\nfunction ratioOf(ratio: BrandlabMediaRatio): number {\n const [width, height] = ratio.split(':').map(Number) as [number, number]\n return height / width\n}\n\nexport function MediaFrame(props: MediaFrameProps) {\n const { media, ratio, caption, priority = false, classes } = props\n if (ratio !== undefined && !(BRANDLAB_MEDIA_RATIOS as readonly string[]).includes(ratio)) {\n throw new Error(`MediaFrame ${media.src}: ratio \"${ratio}\" is not one of ${BRANDLAB_MEDIA_RATIOS.join(', ')}.`)\n }\n let width = media.width\n let height = media.height\n let sizes: string | undefined\n if (props.sizes !== undefined) {\n if (!VIEWPORT_WIDTH.test(props.sizes)) {\n throw new Error(\n `MediaFrame ${media.src}: sizes \"${props.sizes}\" has no vw part, so Next would list every width. Give a fluid image a vw size, or a fixed-size image its displayWidth instead.`,\n )\n }\n sizes = props.sizes\n } else {\n if (!Number.isInteger(props.displayWidth) || props.displayWidth <= 0) {\n throw new Error(`MediaFrame ${media.src}: displayWidth must be the image's CSS width in whole pixels.`)\n }\n width = props.displayWidth\n height = Math.round(props.displayWidth * (ratio ? ratioOf(ratio) : media.height / media.width))\n }\n const illustration = media.provenance === 'illustrative-ai'\n const hasCaption = caption !== undefined && caption !== null && caption !== ''\n const Root = illustration || hasCaption ? 'figure' : 'div'\n const focal = media.focalPoint ? { objectPosition: `${media.focalPoint.x}% ${media.focalPoint.y}%` } : undefined\n return (\n <Root\n data-bl=\"media\"\n data-ratio={ratio}\n data-fit={sizes ? 'fluid' : 'fixed'}\n data-provenance={media.provenance}\n className={classes?.root}\n >\n <Image\n src={media.src}\n alt={media.decorative ? '' : media.alt}\n width={width}\n height={height}\n sizes={sizes}\n style={focal}\n {...(priority ? { preload: true, fetchPriority: 'high' as const } : { loading: 'lazy' as const })}\n {...slot(classes, 'img')}\n />\n {illustration || hasCaption ? (\n <figcaption {...slot(classes, 'caption')}>\n {illustration ? <span {...slot(classes, 'label')}>{ILLUSTRATION_LABEL}</span> : null}\n {illustration && hasCaption ? ' ' : null}\n {hasCaption ? caption : null}\n </figcaption>\n ) : null}\n </Root>\n )\n}\n"]}
@@ -0,0 +1,38 @@
1
+ /**
2
+ * `Media` (F13, 3.14.0): one image from the site's media manifest (`src/data/media.ts`, `defineMedia`), rendered through
3
+ * `MediaFrame`, the library's one image path. Server component. It takes a skin entry with `layout.ratio`, which the
4
+ * services grid uses for its photos; everything else (provenance, the locked "Illustration" label, the focal point
5
+ * and the sizing rule) is `MediaFrame`'s.
6
+ *
7
+ * - `sizes` is required. A number is a fixed CSS width (logos, avatars, thumbnails, the header's featured image): it
8
+ * becomes `MediaFrame`'s `displayWidth`, so the image renders no `sizes` and Next emits only the 1x and 2x candidates
9
+ * (cost item 1g). A string is a fluid `sizes` value and must have a `vw` part.
10
+ * - `preload` is for the page's main (hero) image only: preloaded at high priority and never lazy.
11
+ * - `layout.ratio` crops to one of the allowed ratios, keeping the entry's focal point in view.
12
+ */
13
+ import type { ReactNode } from 'react';
14
+ import type { BrandlabMediaEntry, BrandlabMediaRatio } from '@brandlab-digital/site-core/media';
15
+ import type { SkinEntry } from '../skin.js';
16
+ export type MediaSlot = 'root' | 'img' | 'caption' | 'label';
17
+ export interface MediaLayout {
18
+ /** Crop to one of the allowed ratios (16:9, 4:5, 4:3, 3:2). Left out, the image keeps its own shape. */
19
+ readonly ratio?: BrandlabMediaRatio;
20
+ }
21
+ export type MediaSkin = SkinEntry<MediaSlot, never, MediaLayout>;
22
+ /** The visible label on an AI image (F13). Locked: a site can't rename or hide it. The same value as `ILLUSTRATION_LABEL`. */
23
+ export declare const MEDIA_ILLUSTRATION_LABEL = "Illustration";
24
+ export interface MediaProps extends MediaSkin {
25
+ /** The manifest entry, for example `media['castle-hill-gum-removal']`. */
26
+ readonly media: BrandlabMediaEntry;
27
+ /**
28
+ * The rendered width: a whole number of CSS pixels for a fixed-size image (no `sizes`, so 1x and 2x only), or a
29
+ * fluid `sizes` string with a `vw` part such as `(min-width: 1024px) 50vw, 100vw`.
30
+ */
31
+ readonly sizes: number | string;
32
+ /** The page's main image: preloaded at high priority, never lazy. One per page. */
33
+ readonly preload?: boolean;
34
+ /** A visible caption, for example "Gum removal over a pool, Epping, March 2026". */
35
+ readonly caption?: ReactNode;
36
+ }
37
+ export declare function Media({ media, sizes, preload, caption, layout, classes }: MediaProps): import("react/jsx-runtime").JSX.Element;
38
+ //# sourceMappingURL=media.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"media.d.ts","sourceRoot":"","sources":["../../../src/ui-kit/primitives/media.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AACtC,OAAO,KAAK,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,mCAAmC,CAAA;AAC/F,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AAG3C,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG,KAAK,GAAG,SAAS,GAAG,OAAO,CAAA;AAC5D,MAAM,WAAW,WAAW;IAC1B,wGAAwG;IACxG,QAAQ,CAAC,KAAK,CAAC,EAAE,kBAAkB,CAAA;CACpC;AACD,MAAM,MAAM,SAAS,GAAG,SAAS,CAAC,SAAS,EAAE,KAAK,EAAE,WAAW,CAAC,CAAA;AAEhE,8HAA8H;AAC9H,eAAO,MAAM,wBAAwB,iBAAqB,CAAA;AAE1D,MAAM,WAAW,UAAW,SAAQ,SAAS;IAC3C,0EAA0E;IAC1E,QAAQ,CAAC,KAAK,EAAE,kBAAkB,CAAA;IAClC;;;OAGG;IACH,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAA;IAC/B,mFAAmF;IACnF,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAA;IAC1B,oFAAoF;IACpF,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,CAAA;CAC7B;AAED,wBAAgB,KAAK,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,OAAe,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE,UAAU,2CAK5F"}
@@ -0,0 +1,9 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { ILLUSTRATION_LABEL, MediaFrame } from './media-frame.js';
3
+ /** The visible label on an AI image (F13). Locked: a site can't rename or hide it. The same value as `ILLUSTRATION_LABEL`. */
4
+ export const MEDIA_ILLUSTRATION_LABEL = ILLUSTRATION_LABEL;
5
+ export function Media({ media, sizes, preload = false, caption, layout, classes }) {
6
+ const sizing = typeof sizes === 'number' ? { displayWidth: sizes } : { sizes };
7
+ return (_jsx(MediaFrame, { media: media, ...sizing, ratio: layout?.ratio, caption: caption, priority: preload, classes: classes }));
8
+ }
9
+ //# sourceMappingURL=media.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"media.js","sourceRoot":"","sources":["../../../src/ui-kit/primitives/media.tsx"],"names":[],"mappings":";AAeA,OAAO,EAAE,kBAAkB,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AASjE,8HAA8H;AAC9H,MAAM,CAAC,MAAM,wBAAwB,GAAG,kBAAkB,CAAA;AAgB1D,MAAM,UAAU,KAAK,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,GAAG,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAc;IAC3F,MAAM,MAAM,GAAG,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAA;IAC9E,OAAO,CACL,KAAC,UAAU,IAAC,KAAK,EAAE,KAAK,KAAM,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,GAAI,CACtH,CAAA;AACH,CAAC","sourcesContent":["/**\n * `Media` (F13, 3.14.0): one image from the site's media manifest (`src/data/media.ts`, `defineMedia`), rendered through\n * `MediaFrame`, the library's one image path. Server component. It takes a skin entry with `layout.ratio`, which the\n * services grid uses for its photos; everything else (provenance, the locked \"Illustration\" label, the focal point\n * and the sizing rule) is `MediaFrame`'s.\n *\n * - `sizes` is required. A number is a fixed CSS width (logos, avatars, thumbnails, the header's featured image): it\n * becomes `MediaFrame`'s `displayWidth`, so the image renders no `sizes` and Next emits only the 1x and 2x candidates\n * (cost item 1g). A string is a fluid `sizes` value and must have a `vw` part.\n * - `preload` is for the page's main (hero) image only: preloaded at high priority and never lazy.\n * - `layout.ratio` crops to one of the allowed ratios, keeping the entry's focal point in view.\n */\nimport type { ReactNode } from 'react'\nimport type { BrandlabMediaEntry, BrandlabMediaRatio } from '@brandlab-digital/site-core/media'\nimport type { SkinEntry } from '../skin.js'\nimport { ILLUSTRATION_LABEL, MediaFrame } from './media-frame.js'\n\nexport type MediaSlot = 'root' | 'img' | 'caption' | 'label'\nexport interface MediaLayout {\n /** Crop to one of the allowed ratios (16:9, 4:5, 4:3, 3:2). Left out, the image keeps its own shape. */\n readonly ratio?: BrandlabMediaRatio\n}\nexport type MediaSkin = SkinEntry<MediaSlot, never, MediaLayout>\n\n/** The visible label on an AI image (F13). Locked: a site can't rename or hide it. The same value as `ILLUSTRATION_LABEL`. */\nexport const MEDIA_ILLUSTRATION_LABEL = ILLUSTRATION_LABEL\n\nexport interface MediaProps extends MediaSkin {\n /** The manifest entry, for example `media['castle-hill-gum-removal']`. */\n readonly media: BrandlabMediaEntry\n /**\n * The rendered width: a whole number of CSS pixels for a fixed-size image (no `sizes`, so 1x and 2x only), or a\n * fluid `sizes` string with a `vw` part such as `(min-width: 1024px) 50vw, 100vw`.\n */\n readonly sizes: number | string\n /** The page's main image: preloaded at high priority, never lazy. One per page. */\n readonly preload?: boolean\n /** A visible caption, for example \"Gum removal over a pool, Epping, March 2026\". */\n readonly caption?: ReactNode\n}\n\nexport function Media({ media, sizes, preload = false, caption, layout, classes }: MediaProps) {\n const sizing = typeof sizes === 'number' ? { displayWidth: sizes } : { sizes }\n return (\n <MediaFrame media={media} {...sizing} ratio={layout?.ratio} caption={caption} priority={preload} classes={classes} />\n )\n}\n"]}
@@ -16,8 +16,31 @@ export interface QuoteButtonProps extends QuoteButtonSkin {
16
16
  readonly placement: LeadCtaPlacement;
17
17
  /** A stable id for `lead_cta_click`, for example `quote-header` or `quote-cta`. */
18
18
  readonly ctaId: string;
19
- /** `auto` by default: the main quote action keeps Next's prefetch (`LINK_PREFETCH_POLICY.primaryAction`). */
19
+ /**
20
+ * `auto` by default: the main quote action keeps Next's prefetch (`LINK_PREFETCH_POLICY.primaryAction`). A link to a
21
+ * place on the same page (`#quote-hero`) never prefetches, and in the header, drawer and call bar the button never
22
+ * prefetches its own page (on `/contact`, `/contact#quote`).
23
+ */
20
24
  readonly prefetch?: LinkPrefetch;
21
25
  }
22
- export declare function QuoteButton({ label, href, placement, ctaId, prefetch, variant, layout, classes }: QuoteButtonProps): import("react/jsx-runtime").JSX.Element;
26
+ /**
27
+ * The quote button's anchor props and content (internal; not exported from the subpath). `QuoteButton` renders them
28
+ * through `next/link`; the shell's header, drawer and call bar render them through a link that also turns prefetch
29
+ * off on the quote page itself.
30
+ */
31
+ export declare function quoteButtonParts({ label, href, placement, ctaId, variant, layout, classes }: QuoteButtonProps, options?: {
32
+ readonly compactLabel?: string | undefined;
33
+ }): {
34
+ href: string;
35
+ hooks: {
36
+ 'data-bl': string;
37
+ 'data-variant': "primary" | "secondary" | "quiet";
38
+ 'data-size': "regular" | "large";
39
+ 'data-bl-cta': string;
40
+ 'data-bl-cta-placement': "header" | "footer" | "hero" | "page" | "section" | "navigation" | "floating";
41
+ className: string | undefined;
42
+ };
43
+ children: import("react/jsx-runtime").JSX.Element;
44
+ };
45
+ export declare function QuoteButton(props: QuoteButtonProps): import("react/jsx-runtime").JSX.Element;
23
46
  //# sourceMappingURL=quote-button.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"quote-button.d.ts","sourceRoot":"","sources":["../../../src/ui-kit/primitives/quote-button.tsx"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAA;AAE1D,OAAO,EAAqB,KAAK,YAAY,EAAE,MAAM,gBAAgB,CAAA;AACrE,OAAO,EAAQ,KAAK,SAAS,EAAE,MAAM,YAAY,CAAA;AACjD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAE/C,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,CAAA;AACvD,MAAM,MAAM,eAAe,GAAG,SAAS,CAAC,eAAe,EAAE,aAAa,EAAE;IAAE,IAAI,CAAC,EAAE,SAAS,GAAG,OAAO,CAAC;IAAC,IAAI,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC,CAAA;AAEvH,MAAM,WAAW,gBAAiB,SAAQ,eAAe;IACvD,yGAAyG;IACzG,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,uFAAuF;IACvF,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,mDAAmD;IACnD,QAAQ,CAAC,SAAS,EAAE,gBAAgB,CAAA;IACpC,mFAAmF;IACnF,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,6GAA6G;IAC7G,QAAQ,CAAC,QAAQ,CAAC,EAAE,YAAY,CAAA;CACjC;AAED,wBAAgB,WAAW,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAmB,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE,gBAAgB,2CAoB9H"}
1
+ {"version":3,"file":"quote-button.d.ts","sourceRoot":"","sources":["../../../src/ui-kit/primitives/quote-button.tsx"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAA;AAE1D,OAAO,EAAqB,KAAK,YAAY,EAAE,MAAM,gBAAgB,CAAA;AACrE,OAAO,EAAQ,KAAK,SAAS,EAAE,MAAM,YAAY,CAAA;AACjD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAE/C,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,CAAA;AACvD,MAAM,MAAM,eAAe,GAAG,SAAS,CAAC,eAAe,EAAE,aAAa,EAAE;IAAE,IAAI,CAAC,EAAE,SAAS,GAAG,OAAO,CAAC;IAAC,IAAI,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC,CAAA;AAEvH,MAAM,WAAW,gBAAiB,SAAQ,eAAe;IACvD,yGAAyG;IACzG,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,uFAAuF;IACvF,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,mDAAmD;IACnD,QAAQ,CAAC,SAAS,EAAE,gBAAgB,CAAA;IACpC,mFAAmF;IACnF,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB;;;;OAIG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,YAAY,CAAA;CACjC;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAC9B,EAAE,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,OAAmB,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE,gBAAgB,EACzF,OAAO,GAAE;IAAE,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CAAO;;;;;;;;;;;EAiC7D;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,gBAAgB,2CAOlD"}
@@ -1,4 +1,4 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  /**
3
3
  * `QuoteButton`: the quote action. A server-rendered link to the page's quote form (for example `/contact#quote`), so
4
4
  * it works before scripts run. When a `QuoteDialog` is on the page (3.10.0) it opens the dialog instead; on the
@@ -10,7 +10,29 @@ import Link from 'next/link';
10
10
  import { Icon } from '../icons.js';
11
11
  import { linkPrefetchProps } from '../prefetch.js';
12
12
  import { slot } from '../skin.js';
13
- export function QuoteButton({ label, href, placement, ctaId, prefetch, variant = 'primary', layout, classes }) {
14
- return (_jsxs(Link, { href: href, ...linkPrefetchProps(prefetch), "data-bl": "quote-button", "data-variant": variant, "data-size": layout?.size ?? 'regular', "data-bl-cta": ctaId, "data-bl-cta-placement": placement, className: classes?.root, children: [_jsx("span", { ...slot(classes, 'label'), children: label }), layout?.icon === false ? null : (_jsx("span", { ...slot(classes, 'icon'), children: _jsx(Icon, { name: "arrow" }) }))] }));
13
+ /**
14
+ * The quote button's anchor props and content (internal; not exported from the subpath). `QuoteButton` renders them
15
+ * through `next/link`; the shell's header, drawer and call bar render them through a link that also turns prefetch
16
+ * off on the quote page itself.
17
+ */
18
+ export function quoteButtonParts({ label, href, placement, ctaId, variant = 'primary', layout, classes }, options = {}) {
19
+ const compact = options.compactLabel?.trim();
20
+ if (compact !== undefined && (compact === '' || !label.toLowerCase().includes(compact.toLowerCase()))) {
21
+ throw new Error(`The compact quote label "${options.compactLabel}" must be part of the quote label "${label}" (WCAG 2.5.3: the visible label is in the name).`);
22
+ }
23
+ const hooks = {
24
+ 'data-bl': 'quote-button',
25
+ 'data-variant': variant,
26
+ 'data-size': layout?.size ?? 'regular',
27
+ 'data-bl-cta': ctaId,
28
+ 'data-bl-cta-placement': placement,
29
+ className: classes?.root,
30
+ };
31
+ const children = (_jsxs(_Fragment, { children: [compact ? (_jsx("span", { ...slot(classes, 'label'), "data-compact-label": compact, children: _jsx("span", { "data-bl-full-label": "", children: label }) })) : (_jsx("span", { ...slot(classes, 'label'), children: label })), layout?.icon === false ? null : (_jsx("span", { ...slot(classes, 'icon'), children: _jsx(Icon, { name: "arrow" }) }))] }));
32
+ return { href, hooks, children };
33
+ }
34
+ export function QuoteButton(props) {
35
+ const { href, hooks, children } = quoteButtonParts(props);
36
+ return (_jsx(Link, { href: href, ...linkPrefetchProps(props.prefetch, href), ...hooks, children: children }));
15
37
  }
16
38
  //# sourceMappingURL=quote-button.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"quote-button.js","sourceRoot":"","sources":["../../../src/ui-kit/primitives/quote-button.tsx"],"names":[],"mappings":";AAAA;;;;;;GAMG;AACH,OAAO,IAAI,MAAM,WAAW,CAAA;AAE5B,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAA;AAClC,OAAO,EAAE,iBAAiB,EAAqB,MAAM,gBAAgB,CAAA;AACrE,OAAO,EAAE,IAAI,EAAkB,MAAM,YAAY,CAAA;AAmBjD,MAAM,UAAU,WAAW,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,GAAG,SAAS,EAAE,MAAM,EAAE,OAAO,EAAoB;IAC7H,OAAO,CACL,MAAC,IAAI,IACH,IAAI,EAAE,IAAI,KACN,iBAAiB,CAAC,QAAQ,CAAC,aACvB,cAAc,kBACR,OAAO,eACV,MAAM,EAAE,IAAI,IAAI,SAAS,iBACvB,KAAK,2BACK,SAAS,EAChC,SAAS,EAAE,OAAO,EAAE,IAAI,aAExB,kBAAU,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,YAAG,KAAK,GAAQ,EAC/C,MAAM,EAAE,IAAI,KAAK,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAC/B,kBAAU,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,YAC7B,KAAC,IAAI,IAAC,IAAI,EAAC,OAAO,GAAG,GAChB,CACR,IACI,CACR,CAAA;AACH,CAAC","sourcesContent":["/**\n * `QuoteButton`: the quote action. A server-rendered link to the page's quote form (for example `/contact#quote`), so\n * it works before scripts run. When a `QuoteDialog` is on the page (3.10.0) it opens the dialog instead; on the\n * contact page the link scrolls to the form. It carries the `data-bl-cta` hooks only: from 3.9.0 the shared\n * instrumentation reads them and sends `lead_cta_click` when lead diagnostics are on. Nothing is sent in 3.8.0, and\n * nothing here emits events itself.\n */\nimport Link from 'next/link'\nimport type { LeadCtaPlacement } from '../../analytics.js'\nimport { Icon } from '../icons.js'\nimport { linkPrefetchProps, type LinkPrefetch } from '../prefetch.js'\nimport { slot, type SkinEntry } from '../skin.js'\nimport type { ButtonVariant } from './links.js'\n\nexport type QuoteButtonSlot = 'root' | 'label' | 'icon'\nexport type QuoteButtonSkin = SkinEntry<QuoteButtonSlot, ButtonVariant, { size?: 'regular' | 'large'; icon?: boolean }>\n\nexport interface QuoteButtonProps extends QuoteButtonSkin {\n /** The site's recorded quote label, or one from the closed list (C5), for example \"Get a free quote\". */\n readonly label: string\n /** The quote form this falls back to without scripts, for example `/contact#quote`. */\n readonly href: string\n /** Where the button sits, for `lead_cta_click`. */\n readonly placement: LeadCtaPlacement\n /** A stable id for `lead_cta_click`, for example `quote-header` or `quote-cta`. */\n readonly ctaId: string\n /** `auto` by default: the main quote action keeps Next's prefetch (`LINK_PREFETCH_POLICY.primaryAction`). */\n readonly prefetch?: LinkPrefetch\n}\n\nexport function QuoteButton({ label, href, placement, ctaId, prefetch, variant = 'primary', layout, classes }: QuoteButtonProps) {\n return (\n <Link\n href={href}\n {...linkPrefetchProps(prefetch)}\n data-bl=\"quote-button\"\n data-variant={variant}\n data-size={layout?.size ?? 'regular'}\n data-bl-cta={ctaId}\n data-bl-cta-placement={placement}\n className={classes?.root}\n >\n <span {...slot(classes, 'label')}>{label}</span>\n {layout?.icon === false ? null : (\n <span {...slot(classes, 'icon')}>\n <Icon name=\"arrow\" />\n </span>\n )}\n </Link>\n )\n}\n"]}
1
+ {"version":3,"file":"quote-button.js","sourceRoot":"","sources":["../../../src/ui-kit/primitives/quote-button.tsx"],"names":[],"mappings":";AAAA;;;;;;GAMG;AACH,OAAO,IAAI,MAAM,WAAW,CAAA;AAE5B,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAA;AAClC,OAAO,EAAE,iBAAiB,EAAqB,MAAM,gBAAgB,CAAA;AACrE,OAAO,EAAE,IAAI,EAAkB,MAAM,YAAY,CAAA;AAuBjD;;;;GAIG;AACH,MAAM,UAAU,gBAAgB,CAC9B,EAAE,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,OAAO,GAAG,SAAS,EAAE,MAAM,EAAE,OAAO,EAAoB,EACzF,UAA0D,EAAE;IAE5D,MAAM,OAAO,GAAG,OAAO,CAAC,YAAY,EAAE,IAAI,EAAE,CAAA;IAC5C,IAAI,OAAO,KAAK,SAAS,IAAI,CAAC,OAAO,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC,EAAE,CAAC;QACtG,MAAM,IAAI,KAAK,CAAC,4BAA4B,OAAO,CAAC,YAAY,sCAAsC,KAAK,mDAAmD,CAAC,CAAA;IACjK,CAAC;IACD,MAAM,KAAK,GAAG;QACZ,SAAS,EAAE,cAAc;QACzB,cAAc,EAAE,OAAO;QACvB,WAAW,EAAE,MAAM,EAAE,IAAI,IAAI,SAAS;QACtC,aAAa,EAAE,KAAK;QACpB,uBAAuB,EAAE,SAAS;QAClC,SAAS,EAAE,OAAO,EAAE,IAAI;KACzB,CAAA;IACD,MAAM,QAAQ,GAAG,CACf,8BACG,OAAO,CAAC,CAAC,CAAC,CAGT,kBAAU,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,wBAAsB,OAAO,YAC3D,qCAAyB,EAAE,YAAE,KAAK,GAAQ,GACrC,CACR,CAAC,CAAC,CAAC,CACF,kBAAU,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,YAAG,KAAK,GAAQ,CACjD,EACA,MAAM,EAAE,IAAI,KAAK,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAC/B,kBAAU,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,YAC7B,KAAC,IAAI,IAAC,IAAI,EAAC,OAAO,GAAG,GAChB,CACR,IACA,CACJ,CAAA;IACD,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAA;AAClC,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,KAAuB;IACjD,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,gBAAgB,CAAC,KAAK,CAAC,CAAA;IACzD,OAAO,CACL,KAAC,IAAI,IAAC,IAAI,EAAE,IAAI,KAAM,iBAAiB,CAAC,KAAK,CAAC,QAAQ,EAAE,IAAI,CAAC,KAAM,KAAK,YACrE,QAAQ,GACJ,CACR,CAAA;AACH,CAAC","sourcesContent":["/**\n * `QuoteButton`: the quote action. A server-rendered link to the page's quote form (for example `/contact#quote`), so\n * it works before scripts run. When a `QuoteDialog` is on the page (3.10.0) it opens the dialog instead; on the\n * contact page the link scrolls to the form. It carries the `data-bl-cta` hooks only: from 3.9.0 the shared\n * instrumentation reads them and sends `lead_cta_click` when lead diagnostics are on. Nothing is sent in 3.8.0, and\n * nothing here emits events itself.\n */\nimport Link from 'next/link'\nimport type { LeadCtaPlacement } from '../../analytics.js'\nimport { Icon } from '../icons.js'\nimport { linkPrefetchProps, type LinkPrefetch } from '../prefetch.js'\nimport { slot, type SkinEntry } from '../skin.js'\nimport type { ButtonVariant } from './links.js'\n\nexport type QuoteButtonSlot = 'root' | 'label' | 'icon'\nexport type QuoteButtonSkin = SkinEntry<QuoteButtonSlot, ButtonVariant, { size?: 'regular' | 'large'; icon?: boolean }>\n\nexport interface QuoteButtonProps extends QuoteButtonSkin {\n /** The site's recorded quote label, or one from the closed list (C5), for example \"Get a free quote\". */\n readonly label: string\n /** The quote form this falls back to without scripts, for example `/contact#quote`. */\n readonly href: string\n /** Where the button sits, for `lead_cta_click`. */\n readonly placement: LeadCtaPlacement\n /** A stable id for `lead_cta_click`, for example `quote-header` or `quote-cta`. */\n readonly ctaId: string\n /**\n * `auto` by default: the main quote action keeps Next's prefetch (`LINK_PREFETCH_POLICY.primaryAction`). A link to a\n * place on the same page (`#quote-hero`) never prefetches, and in the header, drawer and call bar the button never\n * prefetches its own page (on `/contact`, `/contact#quote`).\n */\n readonly prefetch?: LinkPrefetch\n}\n\n/**\n * The quote button's anchor props and content (internal; not exported from the subpath). `QuoteButton` renders them\n * through `next/link`; the shell's header, drawer and call bar render them through a link that also turns prefetch\n * off on the quote page itself.\n */\nexport function quoteButtonParts(\n { label, href, placement, ctaId, variant = 'primary', layout, classes }: QuoteButtonProps,\n options: { readonly compactLabel?: string | undefined } = {},\n) {\n const compact = options.compactLabel?.trim()\n if (compact !== undefined && (compact === '' || !label.toLowerCase().includes(compact.toLowerCase()))) {\n throw new Error(`The compact quote label \"${options.compactLabel}\" must be part of the quote label \"${label}\" (WCAG 2.5.3: the visible label is in the name).`)\n }\n const hooks = {\n 'data-bl': 'quote-button',\n 'data-variant': variant,\n 'data-size': layout?.size ?? 'regular',\n 'data-bl-cta': ctaId,\n 'data-bl-cta-placement': placement,\n className: classes?.root,\n }\n const children = (\n <>\n {compact ? (\n // The compact label is drawn from the attribute by the structure CSS on narrow phones (with empty alternative\n // text), so the text, the accessible name and C5 still read the full label.\n <span {...slot(classes, 'label')} data-compact-label={compact}>\n <span data-bl-full-label=\"\">{label}</span>\n </span>\n ) : (\n <span {...slot(classes, 'label')}>{label}</span>\n )}\n {layout?.icon === false ? null : (\n <span {...slot(classes, 'icon')}>\n <Icon name=\"arrow\" />\n </span>\n )}\n </>\n )\n return { href, hooks, children }\n}\n\nexport function QuoteButton(props: QuoteButtonProps) {\n const { href, hooks, children } = quoteButtonParts(props)\n return (\n <Link href={href} {...linkPrefetchProps(props.prefetch, href)} {...hooks}>\n {children}\n </Link>\n )\n}\n"]}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * `Stat` (3.14.0): one proof figure, set large with its label (AA's proof strip, Astute's work numbers). Server
3
+ * component. The value comes from a verified fact and is the final text in the server HTML: no count-up and nothing
4
+ * hidden before scripts run. An optional link says where the figure can be checked (the reviews, the licence register).
5
+ *
6
+ * Stats are rendered once per entry of a strip, so their parts take no class (3.14.0 repeated slots): the site styles
7
+ * `[data-bl="stat"]` once in `src/site/skin.css`.
8
+ */
9
+ import type { RepeatedSlotOf } from '../repeated-slots.js';
10
+ import { type SkinEntry } from '../skin.js';
11
+ import type { UiLink } from '../types.js';
12
+ export type StatSlot = RepeatedSlotOf<'stat'>;
13
+ export type StatSkin = SkinEntry<StatSlot, never, Record<never, never>, StatSlot>;
14
+ export interface StatProps extends StatSkin {
15
+ /** The figure itself, for example "1,200+" or "4.9". From a verified fact, never typed for effect. */
16
+ readonly value: string;
17
+ /** What it counts, for example "trees removed safely since 2009". */
18
+ readonly label: string;
19
+ /** Where to check it, for example `{ label: 'Read the reviews', href: '/reviews' }`. Never prefetched. */
20
+ readonly link?: UiLink;
21
+ /** `li` inside a list the caller renders, or `div` (the default). */
22
+ readonly as?: 'div' | 'li';
23
+ }
24
+ export declare function Stat({ value, label, link, as: Root }: StatProps): import("react/jsx-runtime").JSX.Element;
25
+ //# sourceMappingURL=stat.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stat.d.ts","sourceRoot":"","sources":["../../../src/ui-kit/primitives/stat.tsx"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AAC1D,OAAO,EAAgB,KAAK,SAAS,EAAE,MAAM,YAAY,CAAA;AACzD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAGzC,MAAM,MAAM,QAAQ,GAAG,cAAc,CAAC,MAAM,CAAC,CAAA;AAC7C,MAAM,MAAM,QAAQ,GAAG,SAAS,CAAC,QAAQ,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,EAAE,QAAQ,CAAC,CAAA;AAEjF,MAAM,WAAW,SAAU,SAAQ,QAAQ;IACzC,sGAAsG;IACtG,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,qEAAqE;IACrE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,0GAA0G;IAC1G,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAA;IACtB,qEAAqE;IACrE,QAAQ,CAAC,EAAE,CAAC,EAAE,KAAK,GAAG,IAAI,CAAA;CAC3B;AAED,wBAAgB,IAAI,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,EAAE,IAAY,EAAE,EAAE,SAAS,2CAWvE"}
@@ -0,0 +1,7 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { repeatedSlot } from '../skin.js';
3
+ import { Anchor } from './links.js';
4
+ export function Stat({ value, label, link, as: Root = 'div' }) {
5
+ return (_jsxs(Root, { "data-bl": "stat", children: [_jsx("span", { ...repeatedSlot('value'), children: value }), " ", _jsx("span", { ...repeatedSlot('label'), children: label }), link ? (_jsx(Anchor, { href: link.href, prefetch: false, hooks: { 'data-slot': 'link' }, children: link.label })) : null] }));
6
+ }
7
+ //# sourceMappingURL=stat.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stat.js","sourceRoot":"","sources":["../../../src/ui-kit/primitives/stat.tsx"],"names":[],"mappings":";AASA,OAAO,EAAE,YAAY,EAAkB,MAAM,YAAY,CAAA;AAEzD,OAAO,EAAE,MAAM,EAAE,MAAM,YAAY,CAAA;AAgBnC,MAAM,UAAU,IAAI,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,EAAE,IAAI,GAAG,KAAK,EAAa;IACtE,OAAO,CACL,MAAC,IAAI,eAAS,MAAM,aAClB,kBAAU,YAAY,CAAC,OAAO,CAAC,YAAG,KAAK,GAAQ,OAAC,kBAAU,YAAY,CAAC,OAAO,CAAC,YAAG,KAAK,GAAQ,EAC9F,IAAI,CAAC,CAAC,CAAC,CACN,KAAC,MAAM,IAAC,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,WAAW,EAAE,MAAM,EAAE,YACrE,IAAI,CAAC,KAAK,GACJ,CACV,CAAC,CAAC,CAAC,IAAI,IACH,CACR,CAAA;AACH,CAAC","sourcesContent":["/**\n * `Stat` (3.14.0): one proof figure, set large with its label (AA's proof strip, Astute's work numbers). Server\n * component. The value comes from a verified fact and is the final text in the server HTML: no count-up and nothing\n * hidden before scripts run. An optional link says where the figure can be checked (the reviews, the licence register).\n *\n * Stats are rendered once per entry of a strip, so their parts take no class (3.14.0 repeated slots): the site styles\n * `[data-bl=\"stat\"]` once in `src/site/skin.css`.\n */\nimport type { RepeatedSlotOf } from '../repeated-slots.js'\nimport { repeatedSlot, type SkinEntry } from '../skin.js'\nimport type { UiLink } from '../types.js'\nimport { Anchor } from './links.js'\n\nexport type StatSlot = RepeatedSlotOf<'stat'>\nexport type StatSkin = SkinEntry<StatSlot, never, Record<never, never>, StatSlot>\n\nexport interface StatProps extends StatSkin {\n /** The figure itself, for example \"1,200+\" or \"4.9\". From a verified fact, never typed for effect. */\n readonly value: string\n /** What it counts, for example \"trees removed safely since 2009\". */\n readonly label: string\n /** Where to check it, for example `{ label: 'Read the reviews', href: '/reviews' }`. Never prefetched. */\n readonly link?: UiLink\n /** `li` inside a list the caller renders, or `div` (the default). */\n readonly as?: 'div' | 'li'\n}\n\nexport function Stat({ value, label, link, as: Root = 'div' }: StatProps) {\n return (\n <Root data-bl=\"stat\">\n <span {...repeatedSlot('value')}>{value}</span> <span {...repeatedSlot('label')}>{label}</span>\n {link ? (\n <Anchor href={link.href} prefetch={false} hooks={{ 'data-slot': 'link' }}>\n {link.label}\n </Anchor>\n ) : null}\n </Root>\n )\n}\n"]}
@@ -0,0 +1,153 @@
1
+ /**
2
+ * The repeated slots of every shared component (3.14.0): the parts a component renders once per entry of a list in
3
+ * its data. They carry their `data-slot` hook and never a class, so a long class string is not repeated in the HTML and
4
+ * the RSC payload for every link, review, star, card or chip. A site styles them once in `src/site/skin.css`:
5
+ *
6
+ * ```css
7
+ * @layer components {
8
+ * [data-bl="footer"] [data-slot="link"] { @apply text-sm text-white/80 hover:text-white; }
9
+ * [data-bl="header"] [data-slot="list"] [data-slot="panelLink"] { padding: 0.5rem 0.75rem; }
10
+ * }
11
+ * ```
12
+ *
13
+ * `scope` is the selector that holds the repeated slots without reaching a nested component that reuses a slot name
14
+ * (the drawer sits inside the header; the rating chip inside the reviews band uses `stars` too).
15
+ * `repeatedSlotSelector()` joins the two. Pure data: safe to import anywhere.
16
+ */
17
+ export declare const REPEATED_SLOTS: {
18
+ readonly siteHeader: {
19
+ readonly scope: "[data-bl=\"header\"] [data-slot=\"list\"]";
20
+ readonly slots: readonly ["item", "itemRow", "link", "trigger", "panel", "panelBody", "panelList", "panelGroup", "panelHeading", "panelLink", "panelLabel", "panelText", "featured", "featuredMedia", "featuredLabel", "featuredText"];
21
+ };
22
+ readonly mobileDrawer: {
23
+ readonly scope: "[data-bl=\"drawer\"]";
24
+ readonly slots: readonly ["group", "groupTrigger", "groupLinks", "groupLink", "link", "socialLink"];
25
+ };
26
+ readonly utilityBar: {
27
+ readonly scope: "[data-bl=\"utility\"]";
28
+ readonly slots: readonly ["item", "licence", "socialLink"];
29
+ };
30
+ readonly siteFooter: {
31
+ readonly scope: "[data-bl=\"footer\"]";
32
+ readonly slots: readonly ["licenceLink", "socialLink", "column", "heading", "toggle", "list", "link", "policyLink"];
33
+ };
34
+ readonly accordion: {
35
+ readonly scope: "[data-bl=\"accordion\"]";
36
+ readonly slots: readonly ["item", "summary", "label", "marker", "content"];
37
+ };
38
+ readonly faqs: {
39
+ readonly scope: "[data-bl-section=\"faqs\"] [data-slot=\"columns\"]";
40
+ readonly slots: readonly ["column", "group", "subheading", "accordion", "item", "summary", "label", "marker", "content"];
41
+ /** The nested accordion's root is its own component: `data-bl="accordion"`, not a `data-slot`. */
42
+ readonly hooks: {
43
+ readonly accordion: "[data-bl=\"accordion\"]";
44
+ };
45
+ };
46
+ readonly priceTable: {
47
+ readonly scope: "[data-bl=\"price-table\"]";
48
+ readonly slots: readonly ["row", "job", "cell", "label", "range", "unit", "gst", "parts", "part", "includes", "excludes"];
49
+ };
50
+ readonly priceGuide: {
51
+ readonly scope: "[data-bl-section=\"price-guide\"]";
52
+ readonly slots: readonly ["row", "job", "cell", "label", "range", "unit", "gst", "parts", "part", "includes", "excludes", "card", "title", "figures", "band", "factor", "name", "effect", "detail"];
53
+ };
54
+ readonly proofStrip: {
55
+ readonly scope: "[data-bl-section=\"proof-strip\"] [data-slot=\"list\"]";
56
+ readonly slots: readonly ["item", "icon", "stars", "value", "label"];
57
+ };
58
+ readonly reviewsBand: {
59
+ readonly scope: "[data-bl-section=\"reviews\"] [data-slot=\"list\"]";
60
+ readonly slots: readonly ["item", "stars", "quote", "more", "author", "avatar", "name", "date"];
61
+ };
62
+ readonly contactBlock: {
63
+ readonly scope: "[data-bl-section=\"contact\"] [data-slot=\"details\"]";
64
+ readonly slots: readonly ["line"];
65
+ };
66
+ readonly servicesGrid: {
67
+ readonly scope: "[data-bl-section=\"services\"] [data-slot=\"list\"]";
68
+ readonly slots: readonly ["item", "body", "media", "title", "summary", "points", "point", "action", "link"];
69
+ };
70
+ readonly breadcrumbs: {
71
+ readonly scope: "[data-bl=\"breadcrumbs\"]";
72
+ readonly slots: readonly ["item", "link", "current"];
73
+ };
74
+ readonly localFacts: {
75
+ readonly scope: "[data-bl-section=\"local-facts\"]";
76
+ readonly slots: readonly ["fact", "factSource", "fee"];
77
+ };
78
+ readonly councilRules: {
79
+ readonly scope: "[data-bl-section=\"council-rules\"]";
80
+ readonly slots: readonly ["fee"];
81
+ };
82
+ readonly nearbyJobs: {
83
+ readonly scope: "[data-bl-section=\"nearby-jobs\"] [data-slot=\"list\"]";
84
+ readonly slots: readonly ["item", "body", "media", "title", "link", "outcome"];
85
+ };
86
+ readonly coverage: {
87
+ readonly scope: "[data-bl-section=\"coverage\"] [data-slot=\"groups\"]";
88
+ readonly slots: readonly ["group", "groupHeading"];
89
+ };
90
+ readonly relatedServices: {
91
+ readonly scope: "[data-bl-section=\"related-services\"] [data-slot=\"list\"]";
92
+ readonly slots: readonly ["item", "body", "media", "title", "summary", "link"];
93
+ };
94
+ readonly gallery: {
95
+ readonly scope: "[data-bl-section=\"gallery\"] [data-slot=\"list\"]";
96
+ readonly slots: readonly ["item", "link"];
97
+ };
98
+ readonly beforeAfter: {
99
+ readonly scope: "[data-bl-section=\"before-after\"] [data-slot=\"list\"]";
100
+ readonly slots: readonly ["pair", "frames", "frame", "note"];
101
+ };
102
+ readonly licences: {
103
+ readonly scope: "[data-bl-section=\"licences\"] [data-slot=\"list\"]";
104
+ readonly slots: readonly ["row", "label", "value", "number", "holder", "classes", "class", "register", "cover", "amount"];
105
+ };
106
+ readonly thankYou: {
107
+ readonly scope: "[data-bl=\"thank-you\"]";
108
+ readonly slots: readonly ["step"];
109
+ };
110
+ readonly photoUpload: {
111
+ readonly scope: "[data-bl=\"photo-upload\"]";
112
+ readonly slots: readonly ["photo", "thumb", "remove"];
113
+ };
114
+ readonly quoteForm: {
115
+ readonly scope: "[data-bl=\"quote-form\"] [data-bl=\"photo-upload\"]";
116
+ readonly slots: readonly ["photo", "thumb", "remove"];
117
+ };
118
+ readonly card: {
119
+ readonly scope: "[data-bl=\"card\"]";
120
+ readonly slots: readonly ["media", "body", "title", "link", "text", "meta"];
121
+ };
122
+ readonly badge: {
123
+ readonly scope: "[data-bl=\"badge\"]";
124
+ readonly slots: readonly ["icon", "label"];
125
+ };
126
+ readonly chip: {
127
+ readonly scope: "[data-bl=\"chip\"]";
128
+ readonly slots: readonly ["icon", "label"];
129
+ };
130
+ readonly stat: {
131
+ readonly scope: "[data-bl=\"stat\"]";
132
+ readonly slots: readonly ["value", "label", "link"];
133
+ };
134
+ readonly tickList: {
135
+ readonly scope: "[data-bl=\"tick-list\"]";
136
+ readonly slots: readonly ["item", "tick", "text", "link"];
137
+ };
138
+ /** A lean list (cost item 1f): plain `<li><a>` entries with no `data-slot`, reached by element. */
139
+ readonly linkList: {
140
+ readonly scope: "[data-bl=\"link-list\"]";
141
+ readonly slots: readonly ["item", "link"];
142
+ readonly hooks: {
143
+ readonly item: "> li";
144
+ readonly link: "> li > a";
145
+ };
146
+ };
147
+ };
148
+ export type RepeatedSlotComponent = keyof typeof REPEATED_SLOTS;
149
+ /** The repeated slots of one component, for example `RepeatedSlotOf<'siteFooter'>` is `'licenceLink' | … | 'policyLink'`. */
150
+ export type RepeatedSlotOf<Component extends RepeatedSlotComponent> = (typeof REPEATED_SLOTS)[Component]['slots'][number];
151
+ /** The selector a skin stylesheet uses for one repeated slot, for example `[data-bl="footer"] [data-slot="link"]`. */
152
+ export declare function repeatedSlotSelector<Component extends RepeatedSlotComponent>(component: Component, slot: RepeatedSlotOf<Component>): string;
153
+ //# sourceMappingURL=repeated-slots.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"repeated-slots.d.ts","sourceRoot":"","sources":["../../src/ui-kit/repeated-slots.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;QAqBvB,kGAAkG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAmDpG,mGAAmG;;;;;;;;;CAE3F,CAAA;AAEV,MAAM,MAAM,qBAAqB,GAAG,MAAM,OAAO,cAAc,CAAA;AAC/D,6HAA6H;AAC7H,MAAM,MAAM,cAAc,CAAC,SAAS,SAAS,qBAAqB,IAAI,CAAC,OAAO,cAAc,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAA;AAEzH,sHAAsH;AACtH,wBAAgB,oBAAoB,CAAC,SAAS,SAAS,qBAAqB,EAAE,SAAS,EAAE,SAAS,EAAE,IAAI,EAAE,cAAc,CAAC,SAAS,CAAC,GAAG,MAAM,CAG3I"}
@@ -0,0 +1,97 @@
1
+ /**
2
+ * The repeated slots of every shared component (3.14.0): the parts a component renders once per entry of a list in
3
+ * its data. They carry their `data-slot` hook and never a class, so a long class string is not repeated in the HTML and
4
+ * the RSC payload for every link, review, star, card or chip. A site styles them once in `src/site/skin.css`:
5
+ *
6
+ * ```css
7
+ * @layer components {
8
+ * [data-bl="footer"] [data-slot="link"] { @apply text-sm text-white/80 hover:text-white; }
9
+ * [data-bl="header"] [data-slot="list"] [data-slot="panelLink"] { padding: 0.5rem 0.75rem; }
10
+ * }
11
+ * ```
12
+ *
13
+ * `scope` is the selector that holds the repeated slots without reaching a nested component that reuses a slot name
14
+ * (the drawer sits inside the header; the rating chip inside the reviews band uses `stars` too).
15
+ * `repeatedSlotSelector()` joins the two. Pure data: safe to import anywhere.
16
+ */
17
+ export const REPEATED_SLOTS = {
18
+ siteHeader: {
19
+ scope: '[data-bl="header"] [data-slot="list"]',
20
+ slots: [
21
+ 'item', 'itemRow', 'link', 'trigger', 'panel', 'panelBody', 'panelList', 'panelGroup', 'panelHeading', 'panelLink',
22
+ 'panelLabel', 'panelText', 'featured', 'featuredMedia', 'featuredLabel', 'featuredText',
23
+ ],
24
+ },
25
+ mobileDrawer: {
26
+ scope: '[data-bl="drawer"]',
27
+ slots: ['group', 'groupTrigger', 'groupLinks', 'groupLink', 'link', 'socialLink'],
28
+ },
29
+ utilityBar: { scope: '[data-bl="utility"]', slots: ['item', 'licence', 'socialLink'] },
30
+ siteFooter: {
31
+ scope: '[data-bl="footer"]',
32
+ slots: ['licenceLink', 'socialLink', 'column', 'heading', 'toggle', 'list', 'link', 'policyLink'],
33
+ },
34
+ accordion: { scope: '[data-bl="accordion"]', slots: ['item', 'summary', 'label', 'marker', 'content'] },
35
+ faqs: {
36
+ scope: '[data-bl-section="faqs"] [data-slot="columns"]',
37
+ slots: ['column', 'group', 'subheading', 'accordion', 'item', 'summary', 'label', 'marker', 'content'],
38
+ /** The nested accordion's root is its own component: `data-bl="accordion"`, not a `data-slot`. */
39
+ hooks: { accordion: '[data-bl="accordion"]' },
40
+ },
41
+ priceTable: {
42
+ scope: '[data-bl="price-table"]',
43
+ slots: ['row', 'job', 'cell', 'label', 'range', 'unit', 'gst', 'parts', 'part', 'includes', 'excludes'],
44
+ },
45
+ priceGuide: {
46
+ scope: '[data-bl-section="price-guide"]',
47
+ slots: [
48
+ 'row', 'job', 'cell', 'label', 'range', 'unit', 'gst', 'parts', 'part', 'includes', 'excludes', 'card', 'title',
49
+ 'figures', 'band', 'factor', 'name', 'effect', 'detail',
50
+ ],
51
+ },
52
+ proofStrip: { scope: '[data-bl-section="proof-strip"] [data-slot="list"]', slots: ['item', 'icon', 'stars', 'value', 'label'] },
53
+ reviewsBand: {
54
+ scope: '[data-bl-section="reviews"] [data-slot="list"]',
55
+ slots: ['item', 'stars', 'quote', 'more', 'author', 'avatar', 'name', 'date'],
56
+ },
57
+ contactBlock: { scope: '[data-bl-section="contact"] [data-slot="details"]', slots: ['line'] },
58
+ servicesGrid: {
59
+ scope: '[data-bl-section="services"] [data-slot="list"]',
60
+ slots: ['item', 'body', 'media', 'title', 'summary', 'points', 'point', 'action', 'link'],
61
+ },
62
+ breadcrumbs: { scope: '[data-bl="breadcrumbs"]', slots: ['item', 'link', 'current'] },
63
+ // Location sections (3.15.0). Their link lists are `LinkList`s, reached through `linkList` (`[data-bl="link-list"]`).
64
+ localFacts: { scope: '[data-bl-section="local-facts"]', slots: ['fact', 'factSource', 'fee'] },
65
+ councilRules: { scope: '[data-bl-section="council-rules"]', slots: ['fee'] },
66
+ nearbyJobs: { scope: '[data-bl-section="nearby-jobs"] [data-slot="list"]', slots: ['item', 'body', 'media', 'title', 'link', 'outcome'] },
67
+ coverage: { scope: '[data-bl-section="coverage"] [data-slot="groups"]', slots: ['group', 'groupHeading'] },
68
+ relatedServices: {
69
+ scope: '[data-bl-section="related-services"] [data-slot="list"]',
70
+ slots: ['item', 'body', 'media', 'title', 'summary', 'link'],
71
+ },
72
+ // Proof sections (3.15.0). Their photos are nested `[data-bl="media"]` frames; project cards are `[data-bl="card"]`.
73
+ gallery: { scope: '[data-bl-section="gallery"] [data-slot="list"]', slots: ['item', 'link'] },
74
+ beforeAfter: { scope: '[data-bl-section="before-after"] [data-slot="list"]', slots: ['pair', 'frames', 'frame', 'note'] },
75
+ licences: {
76
+ scope: '[data-bl-section="licences"] [data-slot="list"]',
77
+ slots: ['row', 'label', 'value', 'number', 'holder', 'classes', 'class', 'register', 'cover', 'amount'],
78
+ },
79
+ thankYou: { scope: '[data-bl="thank-you"]', slots: ['step'] },
80
+ photoUpload: { scope: '[data-bl="photo-upload"]', slots: ['photo', 'thumb', 'remove'] },
81
+ quoteForm: { scope: '[data-bl="quote-form"] [data-bl="photo-upload"]', slots: ['photo', 'thumb', 'remove'] },
82
+ // Primitives rendered once per list entry (3.14.0): every part is repeated, the root included (style the root
83
+ // through its own hook, `[data-bl="card"]`).
84
+ card: { scope: '[data-bl="card"]', slots: ['media', 'body', 'title', 'link', 'text', 'meta'] },
85
+ badge: { scope: '[data-bl="badge"]', slots: ['icon', 'label'] },
86
+ chip: { scope: '[data-bl="chip"]', slots: ['icon', 'label'] },
87
+ stat: { scope: '[data-bl="stat"]', slots: ['value', 'label', 'link'] },
88
+ tickList: { scope: '[data-bl="tick-list"]', slots: ['item', 'tick', 'text', 'link'] },
89
+ /** A lean list (cost item 1f): plain `<li><a>` entries with no `data-slot`, reached by element. */
90
+ linkList: { scope: '[data-bl="link-list"]', slots: ['item', 'link'], hooks: { item: '> li', link: '> li > a' } },
91
+ };
92
+ /** The selector a skin stylesheet uses for one repeated slot, for example `[data-bl="footer"] [data-slot="link"]`. */
93
+ export function repeatedSlotSelector(component, slot) {
94
+ const entry = REPEATED_SLOTS[component];
95
+ return `${entry.scope} ${entry.hooks?.[slot] ?? `[data-slot="${slot}"]`}`;
96
+ }
97
+ //# sourceMappingURL=repeated-slots.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"repeated-slots.js","sourceRoot":"","sources":["../../src/ui-kit/repeated-slots.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The repeated slots of every shared component (3.14.0): the parts a component renders once per entry of a list in\n * its data. They carry their `data-slot` hook and never a class, so a long class string is not repeated in the HTML and\n * the RSC payload for every link, review, star, card or chip. A site styles them once in `src/site/skin.css`:\n *\n * ```css\n * @layer components {\n * [data-bl=\"footer\"] [data-slot=\"link\"] { @apply text-sm text-white/80 hover:text-white; }\n * [data-bl=\"header\"] [data-slot=\"list\"] [data-slot=\"panelLink\"] { padding: 0.5rem 0.75rem; }\n * }\n * ```\n *\n * `scope` is the selector that holds the repeated slots without reaching a nested component that reuses a slot name\n * (the drawer sits inside the header; the rating chip inside the reviews band uses `stars` too).\n * `repeatedSlotSelector()` joins the two. Pure data: safe to import anywhere.\n */\nexport const REPEATED_SLOTS = {\n siteHeader: {\n scope: '[data-bl=\"header\"] [data-slot=\"list\"]',\n slots: [\n 'item', 'itemRow', 'link', 'trigger', 'panel', 'panelBody', 'panelList', 'panelGroup', 'panelHeading', 'panelLink',\n 'panelLabel', 'panelText', 'featured', 'featuredMedia', 'featuredLabel', 'featuredText',\n ],\n },\n mobileDrawer: {\n scope: '[data-bl=\"drawer\"]',\n slots: ['group', 'groupTrigger', 'groupLinks', 'groupLink', 'link', 'socialLink'],\n },\n utilityBar: { scope: '[data-bl=\"utility\"]', slots: ['item', 'licence', 'socialLink'] },\n siteFooter: {\n scope: '[data-bl=\"footer\"]',\n slots: ['licenceLink', 'socialLink', 'column', 'heading', 'toggle', 'list', 'link', 'policyLink'],\n },\n accordion: { scope: '[data-bl=\"accordion\"]', slots: ['item', 'summary', 'label', 'marker', 'content'] },\n faqs: {\n scope: '[data-bl-section=\"faqs\"] [data-slot=\"columns\"]',\n slots: ['column', 'group', 'subheading', 'accordion', 'item', 'summary', 'label', 'marker', 'content'],\n /** The nested accordion's root is its own component: `data-bl=\"accordion\"`, not a `data-slot`. */\n hooks: { accordion: '[data-bl=\"accordion\"]' },\n },\n priceTable: {\n scope: '[data-bl=\"price-table\"]',\n slots: ['row', 'job', 'cell', 'label', 'range', 'unit', 'gst', 'parts', 'part', 'includes', 'excludes'],\n },\n priceGuide: {\n scope: '[data-bl-section=\"price-guide\"]',\n slots: [\n 'row', 'job', 'cell', 'label', 'range', 'unit', 'gst', 'parts', 'part', 'includes', 'excludes', 'card', 'title',\n 'figures', 'band', 'factor', 'name', 'effect', 'detail',\n ],\n },\n proofStrip: { scope: '[data-bl-section=\"proof-strip\"] [data-slot=\"list\"]', slots: ['item', 'icon', 'stars', 'value', 'label'] },\n reviewsBand: {\n scope: '[data-bl-section=\"reviews\"] [data-slot=\"list\"]',\n slots: ['item', 'stars', 'quote', 'more', 'author', 'avatar', 'name', 'date'],\n },\n contactBlock: { scope: '[data-bl-section=\"contact\"] [data-slot=\"details\"]', slots: ['line'] },\n servicesGrid: {\n scope: '[data-bl-section=\"services\"] [data-slot=\"list\"]',\n slots: ['item', 'body', 'media', 'title', 'summary', 'points', 'point', 'action', 'link'],\n },\n breadcrumbs: { scope: '[data-bl=\"breadcrumbs\"]', slots: ['item', 'link', 'current'] },\n // Location sections (3.15.0). Their link lists are `LinkList`s, reached through `linkList` (`[data-bl=\"link-list\"]`).\n localFacts: { scope: '[data-bl-section=\"local-facts\"]', slots: ['fact', 'factSource', 'fee'] },\n councilRules: { scope: '[data-bl-section=\"council-rules\"]', slots: ['fee'] },\n nearbyJobs: { scope: '[data-bl-section=\"nearby-jobs\"] [data-slot=\"list\"]', slots: ['item', 'body', 'media', 'title', 'link', 'outcome'] },\n coverage: { scope: '[data-bl-section=\"coverage\"] [data-slot=\"groups\"]', slots: ['group', 'groupHeading'] },\n relatedServices: {\n scope: '[data-bl-section=\"related-services\"] [data-slot=\"list\"]',\n slots: ['item', 'body', 'media', 'title', 'summary', 'link'],\n },\n // Proof sections (3.15.0). Their photos are nested `[data-bl=\"media\"]` frames; project cards are `[data-bl=\"card\"]`.\n gallery: { scope: '[data-bl-section=\"gallery\"] [data-slot=\"list\"]', slots: ['item', 'link'] },\n beforeAfter: { scope: '[data-bl-section=\"before-after\"] [data-slot=\"list\"]', slots: ['pair', 'frames', 'frame', 'note'] },\n licences: {\n scope: '[data-bl-section=\"licences\"] [data-slot=\"list\"]',\n slots: ['row', 'label', 'value', 'number', 'holder', 'classes', 'class', 'register', 'cover', 'amount'],\n },\n thankYou: { scope: '[data-bl=\"thank-you\"]', slots: ['step'] },\n photoUpload: { scope: '[data-bl=\"photo-upload\"]', slots: ['photo', 'thumb', 'remove'] },\n quoteForm: { scope: '[data-bl=\"quote-form\"] [data-bl=\"photo-upload\"]', slots: ['photo', 'thumb', 'remove'] },\n // Primitives rendered once per list entry (3.14.0): every part is repeated, the root included (style the root\n // through its own hook, `[data-bl=\"card\"]`).\n card: { scope: '[data-bl=\"card\"]', slots: ['media', 'body', 'title', 'link', 'text', 'meta'] },\n badge: { scope: '[data-bl=\"badge\"]', slots: ['icon', 'label'] },\n chip: { scope: '[data-bl=\"chip\"]', slots: ['icon', 'label'] },\n stat: { scope: '[data-bl=\"stat\"]', slots: ['value', 'label', 'link'] },\n tickList: { scope: '[data-bl=\"tick-list\"]', slots: ['item', 'tick', 'text', 'link'] },\n /** A lean list (cost item 1f): plain `<li><a>` entries with no `data-slot`, reached by element. */\n linkList: { scope: '[data-bl=\"link-list\"]', slots: ['item', 'link'], hooks: { item: '> li', link: '> li > a' } },\n} as const\n\nexport type RepeatedSlotComponent = keyof typeof REPEATED_SLOTS\n/** The repeated slots of one component, for example `RepeatedSlotOf<'siteFooter'>` is `'licenceLink' | … | 'policyLink'`. */\nexport type RepeatedSlotOf<Component extends RepeatedSlotComponent> = (typeof REPEATED_SLOTS)[Component]['slots'][number]\n\n/** The selector a skin stylesheet uses for one repeated slot, for example `[data-bl=\"footer\"] [data-slot=\"link\"]`. */\nexport function repeatedSlotSelector<Component extends RepeatedSlotComponent>(component: Component, slot: RepeatedSlotOf<Component>): string {\n const entry: { readonly scope: string; readonly hooks?: Readonly<Record<string, string>> } = REPEATED_SLOTS[component]\n return `${entry.scope} ${entry.hooks?.[slot] ?? `[data-slot=\"${slot}\"]`}`\n}\n"]}
@@ -5,9 +5,12 @@
5
5
  * the native `open` attribute, so skins style `[open]`.
6
6
  */
7
7
  import type { ReactNode } from 'react';
8
+ import type { RepeatedSlotOf } from '../repeated-slots.js';
8
9
  import { type SkinEntry } from '../skin.js';
9
10
  export type AccordionSlot = 'root' | 'item' | 'summary' | 'label' | 'marker' | 'content';
10
- export type AccordionSkin = SkinEntry<AccordionSlot>;
11
+ /** Rendered once per item: styled from the skin stylesheet, never by class (3.14.0). */
12
+ export type AccordionRepeatedSlot = RepeatedSlotOf<'accordion'>;
13
+ export type AccordionSkin = SkinEntry<AccordionSlot, never, Record<never, never>, AccordionRepeatedSlot>;
11
14
  export interface AccordionItem {
12
15
  /** A stable slug, unique in the group. The item's element id is `{name}-{id}`, so it can be linked to. */
13
16
  readonly id: string;
@@ -1 +1 @@
1
- {"version":3,"file":"accordion.d.ts","sourceRoot":"","sources":["../../../src/ui-kit/sections/accordion.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAEtC,OAAO,EAAQ,KAAK,SAAS,EAAE,MAAM,YAAY,CAAA;AAEjD,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,MAAM,GAAG,SAAS,GAAG,OAAO,GAAG,QAAQ,GAAG,SAAS,CAAA;AACxF,MAAM,MAAM,aAAa,GAAG,SAAS,CAAC,aAAa,CAAC,CAAA;AAEpD,MAAM,WAAW,aAAa;IAC5B,0GAA0G;IAC1G,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,OAAO,EAAE,SAAS,CAAA;IAC3B,QAAQ,CAAC,OAAO,EAAE,SAAS,CAAA;CAC5B;AAED,MAAM,WAAW,cAAe,SAAQ,aAAa;IACnD,QAAQ,CAAC,KAAK,EAAE,SAAS,aAAa,EAAE,CAAA;IACxC,8EAA8E;IAC9E,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,wEAAwE;IACxE,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CAC1C;AAED,wBAAgB,SAAS,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,EAAE,cAAc,kDAoB9E"}
1
+ {"version":3,"file":"accordion.d.ts","sourceRoot":"","sources":["../../../src/ui-kit/sections/accordion.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAEtC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AAC1D,OAAO,EAAsB,KAAK,SAAS,EAAE,MAAM,YAAY,CAAA;AAE/D,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,MAAM,GAAG,SAAS,GAAG,OAAO,GAAG,QAAQ,GAAG,SAAS,CAAA;AACxF,wFAAwF;AACxF,MAAM,MAAM,qBAAqB,GAAG,cAAc,CAAC,WAAW,CAAC,CAAA;AAC/D,MAAM,MAAM,aAAa,GAAG,SAAS,CAAC,aAAa,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,EAAE,qBAAqB,CAAC,CAAA;AAExG,MAAM,WAAW,aAAa;IAC5B,0GAA0G;IAC1G,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,OAAO,EAAE,SAAS,CAAA;IAC3B,QAAQ,CAAC,OAAO,EAAE,SAAS,CAAA;CAC5B;AAED,MAAM,WAAW,cAAe,SAAQ,aAAa;IACnD,QAAQ,CAAC,KAAK,EAAE,SAAS,aAAa,EAAE,CAAA;IACxC,8EAA8E;IAC9E,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,wEAAwE;IACxE,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CAC1C;AAED,wBAAgB,SAAS,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,EAAE,cAAc,kDAoB9E"}
@@ -1,6 +1,6 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { Icon } from '../icons.js';
3
- import { slot } from '../skin.js';
3
+ import { repeatedSlot, slot } from '../skin.js';
4
4
  export function Accordion({ items, name, defaultOpen, classes }) {
5
5
  if (items.length === 0)
6
6
  return null;
@@ -9,6 +9,6 @@ export function Accordion({ items, name, defaultOpen, classes }) {
9
9
  throw new Error(`Accordion "${name}": item ids must be unique.`);
10
10
  if (defaultOpen !== undefined && !ids.has(defaultOpen))
11
11
  throw new Error(`Accordion "${name}": defaultOpen "${defaultOpen}" is not an item.`);
12
- return (_jsx("div", { "data-bl": "accordion", className: classes?.root, children: items.map((item) => (_jsxs("details", { id: `${name}-${item.id}`, name: name, open: item.id === defaultOpen, ...slot(classes, 'item'), children: [_jsxs("summary", { ...slot(classes, 'summary'), children: [_jsx("span", { ...slot(classes, 'label'), children: item.summary }), _jsx("span", { ...slot(classes, 'marker'), "aria-hidden": "true", children: _jsx(Icon, { name: "chevron" }) })] }), _jsx("div", { ...slot(classes, 'content'), children: item.content })] }, item.id))) }));
12
+ return (_jsx("div", { "data-bl": "accordion", className: classes?.root, children: items.map((item) => (_jsxs("details", { id: `${name}-${item.id}`, name: name, open: item.id === defaultOpen, ...repeatedSlot('item'), children: [_jsxs("summary", { ...repeatedSlot('summary'), children: [_jsx("span", { ...repeatedSlot('label'), children: item.summary }), _jsx("span", { ...repeatedSlot('marker'), "aria-hidden": "true", children: _jsx(Icon, { name: "chevron" }) })] }), _jsx("div", { ...repeatedSlot('content'), children: item.content })] }, item.id))) }));
13
13
  }
14
14
  //# sourceMappingURL=accordion.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"accordion.js","sourceRoot":"","sources":["../../../src/ui-kit/sections/accordion.tsx"],"names":[],"mappings":";AAOA,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAA;AAClC,OAAO,EAAE,IAAI,EAAkB,MAAM,YAAY,CAAA;AAoBjD,MAAM,UAAU,SAAS,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAkB;IAC7E,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAA;IACnC,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAA;IACjD,IAAI,GAAG,CAAC,IAAI,KAAK,KAAK,CAAC,MAAM;QAAE,MAAM,IAAI,KAAK,CAAC,cAAc,IAAI,6BAA6B,CAAC,CAAA;IAC/F,IAAI,WAAW,KAAK,SAAS,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,WAAW,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,cAAc,IAAI,mBAAmB,WAAW,mBAAmB,CAAC,CAAA;IAC5I,OAAO,CACL,yBAAa,WAAW,EAAC,SAAS,EAAE,OAAO,EAAE,IAAI,YAC9C,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CACnB,mBAAuB,EAAE,EAAE,GAAG,IAAI,IAAI,IAAI,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,KAAK,WAAW,KAAM,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,aACnH,sBAAa,IAAI,CAAC,OAAO,EAAE,SAAS,CAAC,aACnC,kBAAU,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,YAAG,IAAI,CAAC,OAAO,GAAQ,EACvD,kBAAU,IAAI,CAAC,OAAO,EAAE,QAAQ,CAAC,iBAAc,MAAM,YACnD,KAAC,IAAI,IAAC,IAAI,EAAC,SAAS,GAAG,GAClB,IACC,EACV,iBAAS,IAAI,CAAC,OAAO,EAAE,SAAS,CAAC,YAAG,IAAI,CAAC,OAAO,GAAO,KAP3C,IAAI,CAAC,EAAE,CAQX,CACX,CAAC,GACE,CACP,CAAA;AACH,CAAC","sourcesContent":["/**\n * `Accordion`: a list of disclosures on `<details name>`. Server component: items sharing a `name` open one at a time\n * natively (no script), and every item's content is in the server HTML whether open or closed (K7). Items are closed\n * by default; `defaultOpen` opens one only where a site recorded it (Gabrael: Eastern Suburbs open). The open state is\n * the native `open` attribute, so skins style `[open]`.\n */\nimport type { ReactNode } from 'react'\nimport { Icon } from '../icons.js'\nimport { slot, type SkinEntry } from '../skin.js'\n\nexport type AccordionSlot = 'root' | 'item' | 'summary' | 'label' | 'marker' | 'content'\nexport type AccordionSkin = SkinEntry<AccordionSlot>\n\nexport interface AccordionItem {\n /** A stable slug, unique in the group. The item's element id is `{name}-{id}`, so it can be linked to. */\n readonly id: string\n readonly summary: ReactNode\n readonly content: ReactNode\n}\n\nexport interface AccordionProps extends AccordionSkin {\n readonly items: readonly AccordionItem[]\n /** The group: items sharing a name open one at a time. Unique on the page. */\n readonly name: string\n /** The id of the item open on load, only when the site recorded one. */\n readonly defaultOpen?: string | undefined\n}\n\nexport function Accordion({ items, name, defaultOpen, classes }: AccordionProps) {\n if (items.length === 0) return null\n const ids = new Set(items.map((item) => item.id))\n if (ids.size !== items.length) throw new Error(`Accordion \"${name}\": item ids must be unique.`)\n if (defaultOpen !== undefined && !ids.has(defaultOpen)) throw new Error(`Accordion \"${name}\": defaultOpen \"${defaultOpen}\" is not an item.`)\n return (\n <div data-bl=\"accordion\" className={classes?.root}>\n {items.map((item) => (\n <details key={item.id} id={`${name}-${item.id}`} name={name} open={item.id === defaultOpen} {...slot(classes, 'item')}>\n <summary {...slot(classes, 'summary')}>\n <span {...slot(classes, 'label')}>{item.summary}</span>\n <span {...slot(classes, 'marker')} aria-hidden=\"true\">\n <Icon name=\"chevron\" />\n </span>\n </summary>\n <div {...slot(classes, 'content')}>{item.content}</div>\n </details>\n ))}\n </div>\n )\n}\n"]}
1
+ {"version":3,"file":"accordion.js","sourceRoot":"","sources":["../../../src/ui-kit/sections/accordion.tsx"],"names":[],"mappings":";AAOA,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAA;AAElC,OAAO,EAAE,YAAY,EAAE,IAAI,EAAkB,MAAM,YAAY,CAAA;AAsB/D,MAAM,UAAU,SAAS,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAkB;IAC7E,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAA;IACnC,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAA;IACjD,IAAI,GAAG,CAAC,IAAI,KAAK,KAAK,CAAC,MAAM;QAAE,MAAM,IAAI,KAAK,CAAC,cAAc,IAAI,6BAA6B,CAAC,CAAA;IAC/F,IAAI,WAAW,KAAK,SAAS,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,WAAW,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,cAAc,IAAI,mBAAmB,WAAW,mBAAmB,CAAC,CAAA;IAC5I,OAAO,CACL,yBAAa,WAAW,EAAC,SAAS,EAAE,OAAO,EAAE,IAAI,YAC9C,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CACnB,mBAAuB,EAAE,EAAE,GAAG,IAAI,IAAI,IAAI,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,KAAK,WAAW,KAAM,YAAY,CAAC,MAAM,CAAC,aAClH,sBAAa,YAAY,CAAC,SAAS,CAAC,aAClC,kBAAU,YAAY,CAAC,OAAO,CAAC,YAAG,IAAI,CAAC,OAAO,GAAQ,EACtD,kBAAU,YAAY,CAAC,QAAQ,CAAC,iBAAc,MAAM,YAClD,KAAC,IAAI,IAAC,IAAI,EAAC,SAAS,GAAG,GAClB,IACC,EACV,iBAAS,YAAY,CAAC,SAAS,CAAC,YAAG,IAAI,CAAC,OAAO,GAAO,KAP1C,IAAI,CAAC,EAAE,CAQX,CACX,CAAC,GACE,CACP,CAAA;AACH,CAAC","sourcesContent":["/**\n * `Accordion`: a list of disclosures on `<details name>`. Server component: items sharing a `name` open one at a time\n * natively (no script), and every item's content is in the server HTML whether open or closed (K7). Items are closed\n * by default; `defaultOpen` opens one only where a site recorded it (Gabrael: Eastern Suburbs open). The open state is\n * the native `open` attribute, so skins style `[open]`.\n */\nimport type { ReactNode } from 'react'\nimport { Icon } from '../icons.js'\nimport type { RepeatedSlotOf } from '../repeated-slots.js'\nimport { repeatedSlot, slot, type SkinEntry } from '../skin.js'\n\nexport type AccordionSlot = 'root' | 'item' | 'summary' | 'label' | 'marker' | 'content'\n/** Rendered once per item: styled from the skin stylesheet, never by class (3.14.0). */\nexport type AccordionRepeatedSlot = RepeatedSlotOf<'accordion'>\nexport type AccordionSkin = SkinEntry<AccordionSlot, never, Record<never, never>, AccordionRepeatedSlot>\n\nexport interface AccordionItem {\n /** A stable slug, unique in the group. The item's element id is `{name}-{id}`, so it can be linked to. */\n readonly id: string\n readonly summary: ReactNode\n readonly content: ReactNode\n}\n\nexport interface AccordionProps extends AccordionSkin {\n readonly items: readonly AccordionItem[]\n /** The group: items sharing a name open one at a time. Unique on the page. */\n readonly name: string\n /** The id of the item open on load, only when the site recorded one. */\n readonly defaultOpen?: string | undefined\n}\n\nexport function Accordion({ items, name, defaultOpen, classes }: AccordionProps) {\n if (items.length === 0) return null\n const ids = new Set(items.map((item) => item.id))\n if (ids.size !== items.length) throw new Error(`Accordion \"${name}\": item ids must be unique.`)\n if (defaultOpen !== undefined && !ids.has(defaultOpen)) throw new Error(`Accordion \"${name}\": defaultOpen \"${defaultOpen}\" is not an item.`)\n return (\n <div data-bl=\"accordion\" className={classes?.root}>\n {items.map((item) => (\n <details key={item.id} id={`${name}-${item.id}`} name={name} open={item.id === defaultOpen} {...repeatedSlot('item')}>\n <summary {...repeatedSlot('summary')}>\n <span {...repeatedSlot('label')}>{item.summary}</span>\n <span {...repeatedSlot('marker')} aria-hidden=\"true\">\n <Icon name=\"chevron\" />\n </span>\n </summary>\n <div {...repeatedSlot('content')}>{item.content}</div>\n </details>\n ))}\n </div>\n )\n}\n"]}