@brandlab-digital/site-next 3.14.0 → 3.15.1

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 (148) hide show
  1. package/dist/analytics.d.ts +1 -1
  2. package/dist/analytics.d.ts.map +1 -1
  3. package/dist/analytics.js +2 -0
  4. package/dist/analytics.js.map +1 -1
  5. package/dist/image-runtime.js +6 -1
  6. package/dist/image-runtime.js.map +1 -1
  7. package/dist/navigation/constants.d.ts +11 -2
  8. package/dist/navigation/constants.d.ts.map +1 -1
  9. package/dist/navigation/constants.js +11 -2
  10. package/dist/navigation/constants.js.map +1 -1
  11. package/dist/navigation/index.d.ts +1 -1
  12. package/dist/navigation/index.d.ts.map +1 -1
  13. package/dist/navigation/index.js +1 -1
  14. package/dist/navigation/index.js.map +1 -1
  15. package/dist/navigation/use-back-to-top.d.ts.map +1 -1
  16. package/dist/navigation/use-back-to-top.js +12 -4
  17. package/dist/navigation/use-back-to-top.js.map +1 -1
  18. package/dist/navigation/use-header-metrics.d.ts +1 -1
  19. package/dist/navigation/use-header-metrics.js +1 -1
  20. package/dist/navigation/use-header-metrics.js.map +1 -1
  21. package/dist/navigation/use-sticky-call-bar.d.ts +2 -1
  22. package/dist/navigation/use-sticky-call-bar.d.ts.map +1 -1
  23. package/dist/navigation/use-sticky-call-bar.js +11 -2
  24. package/dist/navigation/use-sticky-call-bar.js.map +1 -1
  25. package/dist/next-sharp.d.ts +14 -9
  26. package/dist/next-sharp.d.ts.map +1 -1
  27. package/dist/next-sharp.js +26 -25
  28. package/dist/next-sharp.js.map +1 -1
  29. package/dist/ui-kit/brandlab-skin.d.ts +26 -0
  30. package/dist/ui-kit/brandlab-skin.d.ts.map +1 -1
  31. package/dist/ui-kit/brandlab-skin.js.map +1 -1
  32. package/dist/ui-kit/prefetch.d.ts +19 -10
  33. package/dist/ui-kit/prefetch.d.ts.map +1 -1
  34. package/dist/ui-kit/prefetch.js +23 -10
  35. package/dist/ui-kit/prefetch.js.map +1 -1
  36. package/dist/ui-kit/primitives/index.d.ts +1 -1
  37. package/dist/ui-kit/primitives/index.d.ts.map +1 -1
  38. package/dist/ui-kit/primitives/index.js.map +1 -1
  39. package/dist/ui-kit/primitives/links.js +1 -1
  40. package/dist/ui-kit/primitives/links.js.map +1 -1
  41. package/dist/ui-kit/primitives/lists.d.ts +9 -1
  42. package/dist/ui-kit/primitives/lists.d.ts.map +1 -1
  43. package/dist/ui-kit/primitives/lists.js +1 -1
  44. package/dist/ui-kit/primitives/lists.js.map +1 -1
  45. package/dist/ui-kit/primitives/quote-button.d.ts +25 -2
  46. package/dist/ui-kit/primitives/quote-button.d.ts.map +1 -1
  47. package/dist/ui-kit/primitives/quote-button.js +25 -3
  48. package/dist/ui-kit/primitives/quote-button.js.map +1 -1
  49. package/dist/ui-kit/repeated-slots.d.ts +32 -0
  50. package/dist/ui-kit/repeated-slots.d.ts.map +1 -1
  51. package/dist/ui-kit/repeated-slots.js +16 -0
  52. package/dist/ui-kit/repeated-slots.js.map +1 -1
  53. package/dist/ui-kit/sections/area-map.d.ts +64 -0
  54. package/dist/ui-kit/sections/area-map.d.ts.map +1 -0
  55. package/dist/ui-kit/sections/area-map.js +142 -0
  56. package/dist/ui-kit/sections/area-map.js.map +1 -0
  57. package/dist/ui-kit/sections/before-after.d.ts +59 -0
  58. package/dist/ui-kit/sections/before-after.d.ts.map +1 -0
  59. package/dist/ui-kit/sections/before-after.js +42 -0
  60. package/dist/ui-kit/sections/before-after.js.map +1 -0
  61. package/dist/ui-kit/sections/council-rules.d.ts +64 -0
  62. package/dist/ui-kit/sections/council-rules.d.ts.map +1 -0
  63. package/dist/ui-kit/sections/council-rules.js +46 -0
  64. package/dist/ui-kit/sections/council-rules.js.map +1 -0
  65. package/dist/ui-kit/sections/coverage.d.ts +53 -0
  66. package/dist/ui-kit/sections/coverage.d.ts.map +1 -0
  67. package/dist/ui-kit/sections/coverage.js +57 -0
  68. package/dist/ui-kit/sections/coverage.js.map +1 -0
  69. package/dist/ui-kit/sections/emergency-band.d.ts +60 -0
  70. package/dist/ui-kit/sections/emergency-band.d.ts.map +1 -0
  71. package/dist/ui-kit/sections/emergency-band.js +43 -0
  72. package/dist/ui-kit/sections/emergency-band.js.map +1 -0
  73. package/dist/ui-kit/sections/gallery.d.ts +60 -0
  74. package/dist/ui-kit/sections/gallery.d.ts.map +1 -0
  75. package/dist/ui-kit/sections/gallery.js +39 -0
  76. package/dist/ui-kit/sections/gallery.js.map +1 -0
  77. package/dist/ui-kit/sections/hero.d.ts +5 -0
  78. package/dist/ui-kit/sections/hero.d.ts.map +1 -1
  79. package/dist/ui-kit/sections/hero.js +1 -1
  80. package/dist/ui-kit/sections/hero.js.map +1 -1
  81. package/dist/ui-kit/sections/index.d.ts +14 -1
  82. package/dist/ui-kit/sections/index.d.ts.map +1 -1
  83. package/dist/ui-kit/sections/index.js +14 -1
  84. package/dist/ui-kit/sections/index.js.map +1 -1
  85. package/dist/ui-kit/sections/licences.d.ts +72 -0
  86. package/dist/ui-kit/sections/licences.d.ts.map +1 -0
  87. package/dist/ui-kit/sections/licences.js +46 -0
  88. package/dist/ui-kit/sections/licences.js.map +1 -0
  89. package/dist/ui-kit/sections/local-facts.d.ts +78 -0
  90. package/dist/ui-kit/sections/local-facts.d.ts.map +1 -0
  91. package/dist/ui-kit/sections/local-facts.js +32 -0
  92. package/dist/ui-kit/sections/local-facts.js.map +1 -0
  93. package/dist/ui-kit/sections/nearby-areas.d.ts +50 -0
  94. package/dist/ui-kit/sections/nearby-areas.d.ts.map +1 -0
  95. package/dist/ui-kit/sections/nearby-areas.js +49 -0
  96. package/dist/ui-kit/sections/nearby-areas.js.map +1 -0
  97. package/dist/ui-kit/sections/nearby-jobs.d.ts +66 -0
  98. package/dist/ui-kit/sections/nearby-jobs.d.ts.map +1 -0
  99. package/dist/ui-kit/sections/nearby-jobs.js +49 -0
  100. package/dist/ui-kit/sections/nearby-jobs.js.map +1 -0
  101. package/dist/ui-kit/sections/projects.d.ts +79 -0
  102. package/dist/ui-kit/sections/projects.d.ts.map +1 -0
  103. package/dist/ui-kit/sections/projects.js +69 -0
  104. package/dist/ui-kit/sections/projects.js.map +1 -0
  105. package/dist/ui-kit/sections/quote-checklist.d.ts +43 -0
  106. package/dist/ui-kit/sections/quote-checklist.d.ts.map +1 -0
  107. package/dist/ui-kit/sections/quote-checklist.js +19 -0
  108. package/dist/ui-kit/sections/quote-checklist.js.map +1 -0
  109. package/dist/ui-kit/sections/related-services.d.ts +41 -0
  110. package/dist/ui-kit/sections/related-services.d.ts.map +1 -0
  111. package/dist/ui-kit/sections/related-services.js +52 -0
  112. package/dist/ui-kit/sections/related-services.js.map +1 -0
  113. package/dist/ui-kit/sections/reviews-band.d.ts +11 -0
  114. package/dist/ui-kit/sections/reviews-band.d.ts.map +1 -1
  115. package/dist/ui-kit/sections/reviews-band.js +11 -0
  116. package/dist/ui-kit/sections/reviews-band.js.map +1 -1
  117. package/dist/ui-kit/sections/services-grid.js +1 -1
  118. package/dist/ui-kit/sections/services-grid.js.map +1 -1
  119. package/dist/ui-kit/sections/work-photos.d.ts +15 -0
  120. package/dist/ui-kit/sections/work-photos.d.ts.map +1 -0
  121. package/dist/ui-kit/sections/work-photos.js +24 -0
  122. package/dist/ui-kit/sections/work-photos.js.map +1 -0
  123. package/dist/ui-kit/shell/back-to-top.js +1 -1
  124. package/dist/ui-kit/shell/back-to-top.js.map +1 -1
  125. package/dist/ui-kit/shell/current-link.d.ts +21 -5
  126. package/dist/ui-kit/shell/current-link.d.ts.map +1 -1
  127. package/dist/ui-kit/shell/current-link.js +16 -5
  128. package/dist/ui-kit/shell/current-link.js.map +1 -1
  129. package/dist/ui-kit/shell/drawer-client.js +1 -1
  130. package/dist/ui-kit/shell/drawer-client.js.map +1 -1
  131. package/dist/ui-kit/shell/intent-prefetch.d.ts.map +1 -1
  132. package/dist/ui-kit/shell/intent-prefetch.js +3 -2
  133. package/dist/ui-kit/shell/intent-prefetch.js.map +1 -1
  134. package/dist/ui-kit/shell/mobile-call-bar.d.ts +6 -1
  135. package/dist/ui-kit/shell/mobile-call-bar.d.ts.map +1 -1
  136. package/dist/ui-kit/shell/mobile-call-bar.js +6 -3
  137. package/dist/ui-kit/shell/mobile-call-bar.js.map +1 -1
  138. package/dist/ui-kit/shell/mobile-drawer.js +2 -2
  139. package/dist/ui-kit/shell/mobile-drawer.js.map +1 -1
  140. package/dist/ui-kit/shell/shell-quote.d.ts +10 -0
  141. package/dist/ui-kit/shell/shell-quote.d.ts.map +1 -0
  142. package/dist/ui-kit/shell/shell-quote.js +13 -0
  143. package/dist/ui-kit/shell/shell-quote.js.map +1 -0
  144. package/dist/ui-kit/shell/site-header.d.ts +1 -1
  145. package/dist/ui-kit/shell/site-header.js +4 -4
  146. package/dist/ui-kit/shell/site-header.js.map +1 -1
  147. package/dist/ui-kit/structure.css +410 -7
  148. package/package.json +2 -2
@@ -1 +1 @@
1
- {"version":3,"file":"back-to-top.js","sourceRoot":"","sources":["../../../src/ui-kit/shell/back-to-top.tsx"],"names":[],"mappings":";AAAA;;;;GAIG;AACH,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAA;AAClC,OAAO,EAAE,IAAI,EAAkB,MAAM,YAAY,CAAA;AACjD,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAA;AAGzD,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,OAAO,EAAE,QAAQ,EAAE,OAAO,CAAU,CAAA;AAWxE,MAAM,UAAU,SAAS,CAAC,EAAE,MAAM,EAAE,OAAO,EAAkB;IAC3D,OAAO,CACL,KAAC,eAAe,IAAC,MAAM,EAAE,MAAM,EAAE,MAAM,IAAI,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,IAAI,QAAQ,EAAE,SAAS,EAAE,OAAO,EAAE,IAAI,YAC5G,kBAAU,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,YAC7B,KAAC,IAAI,IAAC,IAAI,EAAC,UAAU,GAAG,GACnB,GACS,CACnB,CAAA;AACH,CAAC","sourcesContent":["/**\n * F7: back-to-top (server component). A 44 px `<button>` named \"Back to top\" that appears after one and a half\n * screens, sits above the call bar on phones, scrolls smoothly unless the visitor prefers reduced motion and moves\n * focus to `#main`. Never a footer text link. Render it once, after the page's `<main>`.\n */\nimport { Icon } from '../icons.js'\nimport { slot, type SkinEntry } from '../skin.js'\nimport { BackToTopButton } from './back-to-top-client.js'\n\nexport type BackToTopSlot = 'root' | 'icon'\nexport const BACK_TO_TOP_OFFSETS = ['small', 'medium', 'large'] as const\nexport interface BackToTopLayout {\n /** The bottom corner it sits in (default `end`). */\n readonly corner?: 'end' | 'start'\n /** Its distance from the side and from the bottom (or the call bar): 0.75, 1.25 or 2 rem (default `medium`). */\n readonly offset?: (typeof BACK_TO_TOP_OFFSETS)[number]\n}\nexport type BackToTopSkin = SkinEntry<BackToTopSlot, never, BackToTopLayout>\n\nexport type BackToTopProps = BackToTopSkin\n\nexport function BackToTop({ layout, classes }: BackToTopProps) {\n return (\n <BackToTopButton corner={layout?.corner ?? 'end'} offset={layout?.offset ?? 'medium'} className={classes?.root}>\n <span {...slot(classes, 'icon')}>\n <Icon name=\"arrow-up\" />\n </span>\n </BackToTopButton>\n )\n}\n"]}
1
+ {"version":3,"file":"back-to-top.js","sourceRoot":"","sources":["../../../src/ui-kit/shell/back-to-top.tsx"],"names":[],"mappings":";AAAA;;;;GAIG;AACH,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAA;AAClC,OAAO,EAAE,IAAI,EAAkB,MAAM,YAAY,CAAA;AACjD,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAA;AAGzD,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,OAAO,EAAE,QAAQ,EAAE,OAAO,CAAU,CAAA;AAWxE,MAAM,UAAU,SAAS,CAAC,EAAE,MAAM,EAAE,OAAO,EAAkB;IAC3D,OAAO,CACL,KAAC,eAAe,IAAC,MAAM,EAAE,MAAM,EAAE,MAAM,IAAI,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,IAAI,QAAQ,EAAE,SAAS,EAAE,OAAO,EAAE,IAAI,YAC5G,kBAAU,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,YAC7B,KAAC,IAAI,IAAC,IAAI,EAAC,UAAU,GAAG,GACnB,GACS,CACnB,CAAA;AACH,CAAC","sourcesContent":["/**\n * F7: back-to-top (server component). A 44 px `<button>` named \"Back to top\" that appears after one and a half\n * screens, stays hidden while the phone call bar shows (3.15.0; it never covers the bar or the content above it), scrolls smoothly unless the visitor prefers reduced motion and moves\n * focus to `#main`. Never a footer text link. Render it once, after the page's `<main>`.\n */\nimport { Icon } from '../icons.js'\nimport { slot, type SkinEntry } from '../skin.js'\nimport { BackToTopButton } from './back-to-top-client.js'\n\nexport type BackToTopSlot = 'root' | 'icon'\nexport const BACK_TO_TOP_OFFSETS = ['small', 'medium', 'large'] as const\nexport interface BackToTopLayout {\n /** The bottom corner it sits in (default `end`). */\n readonly corner?: 'end' | 'start'\n /** Its distance from the side and from the bottom (or the call bar): 0.75, 1.25 or 2 rem (default `medium`). */\n readonly offset?: (typeof BACK_TO_TOP_OFFSETS)[number]\n}\nexport type BackToTopSkin = SkinEntry<BackToTopSlot, never, BackToTopLayout>\n\nexport type BackToTopProps = BackToTopSkin\n\nexport function BackToTop({ layout, classes }: BackToTopProps) {\n return (\n <BackToTopButton corner={layout?.corner ?? 'end'} offset={layout?.offset ?? 'medium'} className={classes?.root}>\n <span {...slot(classes, 'icon')}>\n <Icon name=\"arrow-up\" />\n </span>\n </BackToTopButton>\n )\n}\n"]}
@@ -1,4 +1,5 @@
1
1
  import type { ReactNode } from 'react';
2
+ import { type LinkPrefetch } from '../prefetch.js';
2
3
  /** True when `href` is the current page. External links are never current. */
3
4
  export declare function isCurrentPage(pathname: string, href: string): boolean;
4
5
  /** True when the page is one of `paths` or below it (the home path matches only itself). */
@@ -8,16 +9,18 @@ export declare function CurrentLink({ href, slot, hub, prefetch, className, chil
8
9
  readonly slot: string;
9
10
  readonly hub?: boolean;
10
11
  /**
11
- * False for links in panels and the drawer: hidden panels count as in view and would prefetch every menu page. The
12
- * current page is never prefetched, whatever this says.
12
+ * The link's prefetch role (`LINK_PREFETCH_POLICY`): `intent` for the top-level menu links, false for links in panels
13
+ * and the drawer (hidden panels count as in view and would prefetch every menu page). The current page is never
14
+ * prefetched, whatever this says.
13
15
  */
14
- readonly prefetch?: boolean | undefined;
16
+ readonly prefetch?: LinkPrefetch | undefined;
15
17
  readonly className?: string | undefined;
16
18
  readonly children: ReactNode;
17
19
  }): import("react/jsx-runtime").JSX.Element;
18
20
  /**
19
- * The header logo's home link: prefetch stays Next's default except on the home page itself, which is never
20
- * prefetched. No `aria-current`: the logo is named by the brand, not as a menu item.
21
+ * The header logo's home link. It never prefetches (3.15.0): the logo is in view on every page, so on landing it
22
+ * prefetched home from every page, and home itself on the home page. No `aria-current`: the logo is named by the
23
+ * brand, not as a menu item.
21
24
  */
22
25
  export declare function LogoLink({ href, label, slot, className, children, }: {
23
26
  readonly href: string;
@@ -26,4 +29,17 @@ export declare function LogoLink({ href, label, slot, className, children, }: {
26
29
  readonly className?: string | undefined;
27
30
  readonly children: ReactNode;
28
31
  }): import("react/jsx-runtime").JSX.Element;
32
+ /**
33
+ * A shell action's link (the quote button in the header, drawer and call bar): its role's prefetch, except that it
34
+ * never prefetches the page it is on (`/contact#quote` on `/contact`) or a place on the same page. The anchor's
35
+ * hooks and content come from the server component that renders it.
36
+ */
37
+ export declare function PageLink({ href, prefetch, hooks, children, }: {
38
+ readonly href: string;
39
+ readonly prefetch?: LinkPrefetch | undefined;
40
+ readonly hooks: {
41
+ readonly className?: string | undefined;
42
+ } & Readonly<Record<`data-${string}`, string | undefined>>;
43
+ readonly children: ReactNode;
44
+ }): import("react/jsx-runtime").JSX.Element;
29
45
  //# sourceMappingURL=current-link.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"current-link.d.ts","sourceRoot":"","sources":["../../../src/ui-kit/shell/current-link.tsx"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAOtC,8EAA8E;AAC9E,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,WAG3D;AAED,4FAA4F;AAC5F,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,MAAM,EAAE,WAO1E;AAED,wBAAgB,WAAW,CAAC,EAC1B,IAAI,EACJ,IAAI,EACJ,GAAW,EACX,QAAQ,EACR,SAAS,EACT,QAAQ,GACT,EAAE;IACD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,GAAG,CAAC,EAAE,OAAO,CAAA;IACtB;;;OAGG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,GAAG,SAAS,CAAA;IACvC,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IACvC,QAAQ,CAAC,QAAQ,EAAE,SAAS,CAAA;CAC7B,2CAeA;AAED;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,EACvB,IAAI,EACJ,KAAK,EACL,IAAI,EACJ,SAAS,EACT,QAAQ,GACT,EAAE;IACD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IACvC,QAAQ,CAAC,QAAQ,EAAE,SAAS,CAAA;CAC7B,2CAOA"}
1
+ {"version":3,"file":"current-link.d.ts","sourceRoot":"","sources":["../../../src/ui-kit/shell/current-link.tsx"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AACtC,OAAO,EAAqC,KAAK,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAOrF,8EAA8E;AAC9E,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,WAG3D;AAED,4FAA4F;AAC5F,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,MAAM,EAAE,WAO1E;AAED,wBAAgB,WAAW,CAAC,EAC1B,IAAI,EACJ,IAAI,EACJ,GAAW,EACX,QAAQ,EACR,SAAS,EACT,QAAQ,GACT,EAAE;IACD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,GAAG,CAAC,EAAE,OAAO,CAAA;IACtB;;;;OAIG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,YAAY,GAAG,SAAS,CAAA;IAC5C,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IACvC,QAAQ,CAAC,QAAQ,EAAE,SAAS,CAAA;CAC7B,2CAeA;AAED;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,EACvB,IAAI,EACJ,KAAK,EACL,IAAI,EACJ,SAAS,EACT,QAAQ,GACT,EAAE;IACD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IACvC,QAAQ,CAAC,QAAQ,EAAE,SAAS,CAAA;CAC7B,2CAMA;AAED;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,EACvB,IAAI,EACJ,QAAQ,EACR,KAAK,EACL,QAAQ,GACT,EAAE;IACD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,QAAQ,CAAC,EAAE,YAAY,GAAG,SAAS,CAAA;IAC5C,QAAQ,CAAC,KAAK,EAAE;QAAE,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;KAAE,GAAG,QAAQ,CAAC,MAAM,CAAC,QAAQ,MAAM,EAAE,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC,CAAA;IACpH,QAAQ,CAAC,QAAQ,EAAE,SAAS,CAAA;CAC7B,2CAQA"}
@@ -3,10 +3,11 @@ import { jsx as _jsx } from "react/jsx-runtime";
3
3
  /**
4
4
  * A menu link that marks itself `aria-current="page"` on its own page. A client leaf only because the root layout
5
5
  * can't read the route: it receives one href and its server-rendered label, and renders in the server HTML with the
6
- * right state.
6
+ * right state. The current page is never prefetched (W2), so a link to it renders `prefetch={false}` whatever its role.
7
7
  */
8
8
  import Link from 'next/link';
9
9
  import { usePathname } from 'next/navigation';
10
+ import { isSamePageHref, linkPrefetchProps } from '../prefetch.js';
10
11
  function normalisePath(path) {
11
12
  const bare = path.split(/[?#]/, 1)[0] ?? '';
12
13
  return bare.replace(/\/+$/, '') || '/';
@@ -30,14 +31,24 @@ export function isCurrentSection(pathname, paths) {
30
31
  export function CurrentLink({ href, slot, hub = false, prefetch, className, children, }) {
31
32
  const pathname = usePathname();
32
33
  const current = isCurrentPage(pathname, href);
33
- return (_jsx(Link, { href: href, prefetch: current ? false : prefetch, "data-slot": slot, "data-hub": hub ? 'true' : undefined, "aria-current": current ? 'page' : undefined, className: className, children: children }));
34
+ return (_jsx(Link, { href: href, ...(current ? { prefetch: false } : linkPrefetchProps(prefetch, href)), "data-slot": slot, "data-hub": hub ? 'true' : undefined, "aria-current": current ? 'page' : undefined, className: className, children: children }));
34
35
  }
35
36
  /**
36
- * The header logo's home link: prefetch stays Next's default except on the home page itself, which is never
37
- * prefetched. No `aria-current`: the logo is named by the brand, not as a menu item.
37
+ * The header logo's home link. It never prefetches (3.15.0): the logo is in view on every page, so on landing it
38
+ * prefetched home from every page, and home itself on the home page. No `aria-current`: the logo is named by the
39
+ * brand, not as a menu item.
38
40
  */
39
41
  export function LogoLink({ href, label, slot, className, children, }) {
42
+ return (_jsx(Link, { href: href, prefetch: false, "aria-label": label, "data-slot": slot, className: className, children: children }));
43
+ }
44
+ /**
45
+ * A shell action's link (the quote button in the header, drawer and call bar): its role's prefetch, except that it
46
+ * never prefetches the page it is on (`/contact#quote` on `/contact`) or a place on the same page. The anchor's
47
+ * hooks and content come from the server component that renders it.
48
+ */
49
+ export function PageLink({ href, prefetch, hooks, children, }) {
40
50
  const pathname = usePathname();
41
- return (_jsx(Link, { href: href, prefetch: isCurrentPage(pathname, href) ? false : undefined, "aria-label": label, "data-slot": slot, className: className, children: children }));
51
+ const current = isSamePageHref(href) || isCurrentPage(pathname, href);
52
+ return (_jsx(Link, { href: href, ...(current ? { prefetch: false } : linkPrefetchProps(prefetch)), ...hooks, children: children }));
42
53
  }
43
54
  //# sourceMappingURL=current-link.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"current-link.js","sourceRoot":"","sources":["../../../src/ui-kit/shell/current-link.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAA;;AAEZ;;;;GAIG;AACH,OAAO,IAAI,MAAM,WAAW,CAAA;AAC5B,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAA;AAG7C,SAAS,aAAa,CAAC,IAAY;IACjC,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAA;IAC3C,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,IAAI,GAAG,CAAA;AACxC,CAAC;AAED,8EAA8E;AAC9E,MAAM,UAAU,aAAa,CAAC,QAAgB,EAAE,IAAY;IAC1D,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,KAAK,CAAA;IAChE,OAAO,aAAa,CAAC,QAAQ,CAAC,KAAK,aAAa,CAAC,IAAI,CAAC,CAAA;AACxD,CAAC;AAED,4FAA4F;AAC5F,MAAM,UAAU,gBAAgB,CAAC,QAAgB,EAAE,KAAwB;IACzE,MAAM,OAAO,GAAG,aAAa,CAAC,QAAQ,CAAC,CAAA;IACvC,OAAO,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE;QACzB,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;YAAE,OAAO,KAAK,CAAA;QAChE,MAAM,OAAO,GAAG,aAAa,CAAC,IAAI,CAAC,CAAA;QACnC,OAAO,OAAO,KAAK,OAAO,IAAI,CAAC,OAAO,KAAK,GAAG,IAAI,OAAO,CAAC,UAAU,CAAC,GAAG,OAAO,GAAG,CAAC,CAAC,CAAA;IACtF,CAAC,CAAC,CAAA;AACJ,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,EAC1B,IAAI,EACJ,IAAI,EACJ,GAAG,GAAG,KAAK,EACX,QAAQ,EACR,SAAS,EACT,QAAQ,GAYT;IACC,MAAM,QAAQ,GAAG,WAAW,EAAE,CAAA;IAC9B,MAAM,OAAO,GAAG,aAAa,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAA;IAC7C,OAAO,CACL,KAAC,IAAI,IACH,IAAI,EAAE,IAAI,EACV,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,eACzB,IAAI,cACL,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,kBACpB,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,EAC1C,SAAS,EAAE,SAAS,YAEnB,QAAQ,GACJ,CACR,CAAA;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,QAAQ,CAAC,EACvB,IAAI,EACJ,KAAK,EACL,IAAI,EACJ,SAAS,EACT,QAAQ,GAOT;IACC,MAAM,QAAQ,GAAG,WAAW,EAAE,CAAA;IAC9B,OAAO,CACL,KAAC,IAAI,IAAC,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,aAAa,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,gBAAc,KAAK,eAAa,IAAI,EAAE,SAAS,EAAE,SAAS,YACpI,QAAQ,GACJ,CACR,CAAA;AACH,CAAC","sourcesContent":["'use client'\n\n/**\n * A menu link that marks itself `aria-current=\"page\"` on its own page. A client leaf only because the root layout\n * can't read the route: it receives one href and its server-rendered label, and renders in the server HTML with the\n * right state.\n */\nimport Link from 'next/link'\nimport { usePathname } from 'next/navigation'\nimport type { ReactNode } from 'react'\n\nfunction normalisePath(path: string) {\n const bare = path.split(/[?#]/, 1)[0] ?? ''\n return bare.replace(/\\/+$/, '') || '/'\n}\n\n/** True when `href` is the current page. External links are never current. */\nexport function isCurrentPage(pathname: string, href: string) {\n if (!href.startsWith('/') || href.startsWith('//')) return false\n return normalisePath(pathname) === normalisePath(href)\n}\n\n/** True when the page is one of `paths` or below it (the home path matches only itself). */\nexport function isCurrentSection(pathname: string, paths: readonly string[]) {\n const current = normalisePath(pathname)\n return paths.some((path) => {\n if (!path.startsWith('/') || path.startsWith('//')) return false\n const section = normalisePath(path)\n return current === section || (section !== '/' && current.startsWith(`${section}/`))\n })\n}\n\nexport function CurrentLink({\n href,\n slot,\n hub = false,\n prefetch,\n className,\n children,\n}: {\n readonly href: string\n readonly slot: string\n readonly hub?: boolean\n /**\n * False for links in panels and the drawer: hidden panels count as in view and would prefetch every menu page. The\n * current page is never prefetched, whatever this says.\n */\n readonly prefetch?: boolean | undefined\n readonly className?: string | undefined\n readonly children: ReactNode\n}) {\n const pathname = usePathname()\n const current = isCurrentPage(pathname, href)\n return (\n <Link\n href={href}\n prefetch={current ? false : prefetch}\n data-slot={slot}\n data-hub={hub ? 'true' : undefined}\n aria-current={current ? 'page' : undefined}\n className={className}\n >\n {children}\n </Link>\n )\n}\n\n/**\n * The header logo's home link: prefetch stays Next's default except on the home page itself, which is never\n * prefetched. No `aria-current`: the logo is named by the brand, not as a menu item.\n */\nexport function LogoLink({\n href,\n label,\n slot,\n className,\n children,\n}: {\n readonly href: string\n readonly label: string\n readonly slot: string\n readonly className?: string | undefined\n readonly children: ReactNode\n}) {\n const pathname = usePathname()\n return (\n <Link href={href} prefetch={isCurrentPage(pathname, href) ? false : undefined} aria-label={label} data-slot={slot} className={className}>\n {children}\n </Link>\n )\n}\n"]}
1
+ {"version":3,"file":"current-link.js","sourceRoot":"","sources":["../../../src/ui-kit/shell/current-link.tsx"],"names":[],"mappings":"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","sourcesContent":["'use client'\n\n/**\n * A menu link that marks itself `aria-current=\"page\"` on its own page. A client leaf only because the root layout\n * can't read the route: it receives one href and its server-rendered label, and renders in the server HTML with the\n * right state. The current page is never prefetched (W2), so a link to it renders `prefetch={false}` whatever its role.\n */\nimport Link from 'next/link'\nimport { usePathname } from 'next/navigation'\nimport type { ReactNode } from 'react'\nimport { isSamePageHref, linkPrefetchProps, type LinkPrefetch } from '../prefetch.js'\n\nfunction normalisePath(path: string) {\n const bare = path.split(/[?#]/, 1)[0] ?? ''\n return bare.replace(/\\/+$/, '') || '/'\n}\n\n/** True when `href` is the current page. External links are never current. */\nexport function isCurrentPage(pathname: string, href: string) {\n if (!href.startsWith('/') || href.startsWith('//')) return false\n return normalisePath(pathname) === normalisePath(href)\n}\n\n/** True when the page is one of `paths` or below it (the home path matches only itself). */\nexport function isCurrentSection(pathname: string, paths: readonly string[]) {\n const current = normalisePath(pathname)\n return paths.some((path) => {\n if (!path.startsWith('/') || path.startsWith('//')) return false\n const section = normalisePath(path)\n return current === section || (section !== '/' && current.startsWith(`${section}/`))\n })\n}\n\nexport function CurrentLink({\n href,\n slot,\n hub = false,\n prefetch,\n className,\n children,\n}: {\n readonly href: string\n readonly slot: string\n readonly hub?: boolean\n /**\n * The link's prefetch role (`LINK_PREFETCH_POLICY`): `intent` for the top-level menu links, false for links in panels\n * and the drawer (hidden panels count as in view and would prefetch every menu page). The current page is never\n * prefetched, whatever this says.\n */\n readonly prefetch?: LinkPrefetch | undefined\n readonly className?: string | undefined\n readonly children: ReactNode\n}) {\n const pathname = usePathname()\n const current = isCurrentPage(pathname, href)\n return (\n <Link\n href={href}\n {...(current ? { prefetch: false as const } : linkPrefetchProps(prefetch, href))}\n data-slot={slot}\n data-hub={hub ? 'true' : undefined}\n aria-current={current ? 'page' : undefined}\n className={className}\n >\n {children}\n </Link>\n )\n}\n\n/**\n * The header logo's home link. It never prefetches (3.15.0): the logo is in view on every page, so on landing it\n * prefetched home from every page, and home itself on the home page. No `aria-current`: the logo is named by the\n * brand, not as a menu item.\n */\nexport function LogoLink({\n href,\n label,\n slot,\n className,\n children,\n}: {\n readonly href: string\n readonly label: string\n readonly slot: string\n readonly className?: string | undefined\n readonly children: ReactNode\n}) {\n return (\n <Link href={href} prefetch={false} aria-label={label} data-slot={slot} className={className}>\n {children}\n </Link>\n )\n}\n\n/**\n * A shell action's link (the quote button in the header, drawer and call bar): its role's prefetch, except that it\n * never prefetches the page it is on (`/contact#quote` on `/contact`) or a place on the same page. The anchor's\n * hooks and content come from the server component that renders it.\n */\nexport function PageLink({\n href,\n prefetch,\n hooks,\n children,\n}: {\n readonly href: string\n readonly prefetch?: LinkPrefetch | undefined\n readonly hooks: { readonly className?: string | undefined } & Readonly<Record<`data-${string}`, string | undefined>>\n readonly children: ReactNode\n}) {\n const pathname = usePathname()\n const current = isSamePageHref(href) || isCurrentPage(pathname, href)\n return (\n <Link href={href} {...(current ? { prefetch: false as const } : linkPrefetchProps(prefetch))} {...hooks}>\n {children}\n </Link>\n )\n}\n"]}
@@ -4,7 +4,7 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
4
4
  * The drawer's client leaf: the Menu button and the modal `<dialog>` (top layer, the page inert, focus kept inside).
5
5
  * The menu, the actions and the social links are server-rendered children. The drawer closes on Escape, the close
6
6
  * button, a tap on the backdrop, a link click, a route change and any change of the header's mode (crossing 1024 or
7
- * 1280 px), so the page is never left inert. Groups are `<details name>` (one open at a time, no script needed); the
7
+ * 1200 px), so the page is never left inert. Groups are `<details name>` (one open at a time, no script needed); the
8
8
  * toggle listener below keeps that rule in browsers without exclusive `<details>`.
9
9
  */
10
10
  import { usePathname } from 'next/navigation';
@@ -1 +1 @@
1
- {"version":3,"file":"drawer-client.js","sourceRoot":"","sources":["../../../src/ui-kit/shell/drawer-client.tsx"],"names":[],"mappings":"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","sourcesContent":["'use client'\n\n/**\n * The drawer's client leaf: the Menu button and the modal `<dialog>` (top layer, the page inert, focus kept inside).\n * The menu, the actions and the social links are server-rendered children. The drawer closes on Escape, the close\n * button, a tap on the backdrop, a link click, a route change and any change of the header's mode (crossing 1024 or\n * 1280 px), so the page is never left inert. Groups are `<details name>` (one open at a time, no script needed); the\n * toggle listener below keeps that rule in browsers without exclusive `<details>`.\n */\nimport { usePathname } from 'next/navigation'\nimport { useCallback, useContext, useEffect, useRef, useState, type ReactNode } from 'react'\nimport { HeaderModeContext } from './shell-context.js'\n\nexport interface DrawerControllerClasses {\n readonly root?: string | undefined\n readonly menuButton?: string | undefined\n readonly menuLabel?: string | undefined\n readonly panel?: string | undefined\n readonly top?: string | undefined\n readonly close?: string | undefined\n readonly title?: string | undefined\n readonly logo?: string | undefined\n}\n\nexport function DrawerController({\n id,\n variant,\n side,\n classes,\n logo,\n menuIcon,\n closeIcon,\n children,\n}: {\n readonly id: string\n readonly variant: string\n readonly side: string\n readonly classes: DrawerControllerClasses\n readonly logo?: ReactNode\n readonly menuIcon: ReactNode\n readonly closeIcon: ReactNode\n readonly children: ReactNode\n}) {\n const pathname = usePathname()\n const mode = useContext(HeaderModeContext)\n const dialogRef = useRef<HTMLDialogElement>(null)\n const buttonRef = useRef<HTMLButtonElement>(null)\n const closeRef = useRef<HTMLButtonElement>(null)\n const [open, setOpen] = useState(false)\n const titleId = `${id}-title`\n\n const close = useCallback(() => {\n const dialog = dialogRef.current\n if (dialog?.open) dialog.close()\n }, [])\n\n const show = () => {\n const dialog = dialogRef.current\n if (!dialog || dialog.open) return\n for (const group of dialog.querySelectorAll<HTMLDetailsElement>('details[open]')) group.open = false\n dialog.showModal()\n // The close button comes first in focus order and takes focus when the drawer opens.\n closeRef.current?.focus()\n setOpen(true)\n }\n\n // A route change or a mode change (breakpoint crossing) resets the drawer.\n useEffect(() => {\n close()\n }, [pathname, mode, close])\n\n useEffect(() => {\n const dialog = dialogRef.current\n if (!dialog) return\n const onToggle = (event: Event) => {\n const opened = event.target\n if (!(opened instanceof HTMLDetailsElement) || !opened.open) return\n for (const other of dialog.querySelectorAll<HTMLDetailsElement>('details[open]')) if (other !== opened) other.open = false\n }\n dialog.addEventListener('toggle', onToggle, true)\n return () => dialog.removeEventListener('toggle', onToggle, true)\n }, [])\n\n return (\n <>\n <button\n ref={buttonRef}\n type=\"button\"\n data-slot=\"menuButton\"\n aria-haspopup=\"dialog\"\n aria-expanded={open}\n aria-controls={id}\n className={classes.menuButton}\n onClick={show}\n >\n {menuIcon}\n <span data-slot=\"menuLabel\" className={classes.menuLabel}>\n Menu\n </span>\n </button>\n <dialog\n ref={dialogRef}\n id={id}\n data-bl=\"drawer\"\n data-variant={variant}\n data-side={side}\n aria-labelledby={titleId}\n className={classes.root}\n {...({ closedby: 'any' } as Record<string, string>)}\n onClose={() => {\n setOpen(false)\n // Safari doesn't focus a clicked button, so the dialog may have nothing to return focus to.\n const active = document.activeElement\n if (!active || active === document.body || dialogRef.current?.contains(active)) buttonRef.current?.focus()\n }}\n onClick={(event) => {\n // A tap on the backdrop (where closedby=\"any\" isn't supported yet) or on any link closes the drawer.\n if (event.target === dialogRef.current) close()\n else if ((event.target as Element).closest('a[href]')) close()\n }}\n >\n <div data-slot=\"panel\" className={classes.panel}>\n <div data-slot=\"top\" className={classes.top}>\n <button ref={closeRef} type=\"button\" data-slot=\"close\" aria-label=\"Close menu\" className={classes.close} onClick={close}>\n {closeIcon}\n </button>\n <p id={titleId} data-slot=\"title\" className={classes.title}>\n Menu\n </p>\n {logo ? (\n <span data-slot=\"logo\" aria-hidden=\"true\" className={classes.logo}>\n {logo}\n </span>\n ) : null}\n </div>\n {children}\n </div>\n </dialog>\n </>\n )\n}\n"]}
1
+ {"version":3,"file":"drawer-client.js","sourceRoot":"","sources":["../../../src/ui-kit/shell/drawer-client.tsx"],"names":[],"mappings":"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","sourcesContent":["'use client'\n\n/**\n * The drawer's client leaf: the Menu button and the modal `<dialog>` (top layer, the page inert, focus kept inside).\n * The menu, the actions and the social links are server-rendered children. The drawer closes on Escape, the close\n * button, a tap on the backdrop, a link click, a route change and any change of the header's mode (crossing 1024 or\n * 1200 px), so the page is never left inert. Groups are `<details name>` (one open at a time, no script needed); the\n * toggle listener below keeps that rule in browsers without exclusive `<details>`.\n */\nimport { usePathname } from 'next/navigation'\nimport { useCallback, useContext, useEffect, useRef, useState, type ReactNode } from 'react'\nimport { HeaderModeContext } from './shell-context.js'\n\nexport interface DrawerControllerClasses {\n readonly root?: string | undefined\n readonly menuButton?: string | undefined\n readonly menuLabel?: string | undefined\n readonly panel?: string | undefined\n readonly top?: string | undefined\n readonly close?: string | undefined\n readonly title?: string | undefined\n readonly logo?: string | undefined\n}\n\nexport function DrawerController({\n id,\n variant,\n side,\n classes,\n logo,\n menuIcon,\n closeIcon,\n children,\n}: {\n readonly id: string\n readonly variant: string\n readonly side: string\n readonly classes: DrawerControllerClasses\n readonly logo?: ReactNode\n readonly menuIcon: ReactNode\n readonly closeIcon: ReactNode\n readonly children: ReactNode\n}) {\n const pathname = usePathname()\n const mode = useContext(HeaderModeContext)\n const dialogRef = useRef<HTMLDialogElement>(null)\n const buttonRef = useRef<HTMLButtonElement>(null)\n const closeRef = useRef<HTMLButtonElement>(null)\n const [open, setOpen] = useState(false)\n const titleId = `${id}-title`\n\n const close = useCallback(() => {\n const dialog = dialogRef.current\n if (dialog?.open) dialog.close()\n }, [])\n\n const show = () => {\n const dialog = dialogRef.current\n if (!dialog || dialog.open) return\n for (const group of dialog.querySelectorAll<HTMLDetailsElement>('details[open]')) group.open = false\n dialog.showModal()\n // The close button comes first in focus order and takes focus when the drawer opens.\n closeRef.current?.focus()\n setOpen(true)\n }\n\n // A route change or a mode change (breakpoint crossing) resets the drawer.\n useEffect(() => {\n close()\n }, [pathname, mode, close])\n\n useEffect(() => {\n const dialog = dialogRef.current\n if (!dialog) return\n const onToggle = (event: Event) => {\n const opened = event.target\n if (!(opened instanceof HTMLDetailsElement) || !opened.open) return\n for (const other of dialog.querySelectorAll<HTMLDetailsElement>('details[open]')) if (other !== opened) other.open = false\n }\n dialog.addEventListener('toggle', onToggle, true)\n return () => dialog.removeEventListener('toggle', onToggle, true)\n }, [])\n\n return (\n <>\n <button\n ref={buttonRef}\n type=\"button\"\n data-slot=\"menuButton\"\n aria-haspopup=\"dialog\"\n aria-expanded={open}\n aria-controls={id}\n className={classes.menuButton}\n onClick={show}\n >\n {menuIcon}\n <span data-slot=\"menuLabel\" className={classes.menuLabel}>\n Menu\n </span>\n </button>\n <dialog\n ref={dialogRef}\n id={id}\n data-bl=\"drawer\"\n data-variant={variant}\n data-side={side}\n aria-labelledby={titleId}\n className={classes.root}\n {...({ closedby: 'any' } as Record<string, string>)}\n onClose={() => {\n setOpen(false)\n // Safari doesn't focus a clicked button, so the dialog may have nothing to return focus to.\n const active = document.activeElement\n if (!active || active === document.body || dialogRef.current?.contains(active)) buttonRef.current?.focus()\n }}\n onClick={(event) => {\n // A tap on the backdrop (where closedby=\"any\" isn't supported yet) or on any link closes the drawer.\n if (event.target === dialogRef.current) close()\n else if ((event.target as Element).closest('a[href]')) close()\n }}\n >\n <div data-slot=\"panel\" className={classes.panel}>\n <div data-slot=\"top\" className={classes.top}>\n <button ref={closeRef} type=\"button\" data-slot=\"close\" aria-label=\"Close menu\" className={classes.close} onClick={close}>\n {closeIcon}\n </button>\n <p id={titleId} data-slot=\"title\" className={classes.title}>\n Menu\n </p>\n {logo ? (\n <span data-slot=\"logo\" aria-hidden=\"true\" className={classes.logo}>\n {logo}\n </span>\n ) : null}\n </div>\n {children}\n </div>\n </dialog>\n </>\n )\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"intent-prefetch.d.ts","sourceRoot":"","sources":["../../../src/ui-kit/shell/intent-prefetch.tsx"],"names":[],"mappings":"AA4BA,sGAAsG;AACtG,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,GAAG,IAAI,CAIvE;AAOD,wBAAgB,cAAc,IAAI,IAAI,CAsBrC"}
1
+ {"version":3,"file":"intent-prefetch.d.ts","sourceRoot":"","sources":["../../../src/ui-kit/shell/intent-prefetch.tsx"],"names":[],"mappings":"AA6BA,sGAAsG;AACtG,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,GAAG,IAAI,CAIvE;AAOD,wBAAgB,cAAc,IAAI,IAAI,CAsBrC"}
@@ -1,7 +1,8 @@
1
1
  'use client';
2
2
  /**
3
- * `IntentPrefetch`: prefetches an in-content card link when a visitor shows intent, not when it scrolls into view.
4
- * Links with `prefetch="intent"` (ButtonLink, TextLink, QuoteButton) render `prefetch={false}` and
3
+ * `IntentPrefetch`: prefetches a top-level header link (from 3.15.0) or an in-content card link when a visitor shows
4
+ * intent, not when it scrolls into view. Links with `prefetch="intent"` (ButtonLink, TextLink, QuoteButton and the
5
+ * SiteHeader's top-level links) render `prefetch={false}` and
5
6
  * `data-prefetch="intent"`; this island holds one document listener for pointer entry, focus and touch, and calls
6
7
  * `router.prefetch(href)` for the one link the visitor points at, focuses or touches, once per page address. A touch
7
8
  * prefetches only the touched link, never the list around it; the current page and links to other sites are never
@@ -1 +1 @@
1
- {"version":3,"file":"intent-prefetch.js","sourceRoot":"","sources":["../../../src/ui-kit/shell/intent-prefetch.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAA;AAEZ;;;;;;;;;;;;;;;;;;;GAmBG;AACH,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAC3C,OAAO,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AACjC,OAAO,EAAE,wBAAwB,EAAE,MAAM,gBAAgB,CAAA;AAEzD,MAAM,aAAa,GAAG,CAAC,cAAc,EAAE,SAAS,EAAE,YAAY,CAAU,CAAA;AAExE,sGAAsG;AACtG,MAAM,UAAU,oBAAoB,CAAC,IAAmB;IACtD,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAA;IACxE,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAA;IAC1C,OAAO,MAAM,IAAI,IAAI,CAAA;AACvB,CAAC;AAED,SAAS,QAAQ,CAAC,MAAc,EAAE,QAAkB;IAClD,MAAM,IAAI,GAAG,CAAC,KAAa,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,IAAI,GAAG,CAAA;IAChE,OAAO,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,KAAK,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAA;AACxE,CAAC;AAED,MAAM,UAAU,cAAc;IAC5B,MAAM,MAAM,GAAG,SAAS,EAAE,CAAA;IAE1B,SAAS,CAAC,GAAG,EAAE;QACb,MAAM,UAAU,GAAG,IAAI,GAAG,EAAU,CAAA;QACpC,MAAM,QAAQ,GAAG,CAAC,KAAY,EAAE,EAAE;YAChC,MAAM,OAAO,GAAG,KAAK,CAAC,MAAM,YAAY,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAA;YACrE,MAAM,IAAI,GAAG,OAAO,EAAE,OAAO,CAAoB,wBAAwB,CAAC,CAAA;YAC1E,MAAM,MAAM,GAAG,oBAAoB,CAAC,IAAI,EAAE,YAAY,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC,CAAA;YACvE,IAAI,CAAC,MAAM,IAAI,UAAU,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,QAAQ,CAAC;gBAAE,OAAM;YAClF,UAAU,CAAC,GAAG,CAAC,MAAM,CAAC,CAAA;YACtB,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAA;QACzB,CAAC,CAAA;QACD,8GAA8G;QAC9G,MAAM,OAAO,GAA4B,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,CAAA;QACzE,KAAK,MAAM,IAAI,IAAI,aAAa;YAAE,QAAQ,CAAC,gBAAgB,CAAC,IAAI,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAA;QACpF,OAAO,GAAG,EAAE;YACV,KAAK,MAAM,IAAI,IAAI,aAAa;gBAAE,QAAQ,CAAC,mBAAmB,CAAC,IAAI,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAA;QACzF,CAAC,CAAA;IACH,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAA;IAEZ,OAAO,IAAI,CAAA;AACb,CAAC","sourcesContent":["'use client'\n\n/**\n * `IntentPrefetch`: prefetches an in-content card link when a visitor shows intent, not when it scrolls into view.\n * Links with `prefetch=\"intent\"` (ButtonLink, TextLink, QuoteButton) render `prefetch={false}` and\n * `data-prefetch=\"intent\"`; this island holds one document listener for pointer entry, focus and touch, and calls\n * `router.prefetch(href)` for the one link the visitor points at, focuses or touches, once per page address. A touch\n * prefetches only the touched link, never the list around it; the current page and links to other sites are never\n * prefetched.\n *\n * Mount it once, in the root layout, beside the header:\n *\n * // src/app/layout.tsx\n * import { IntentPrefetch } from '@brandlab-digital/site-next/ui-kit/shell'\n * <body>\n * <SiteHeader … />\n * <IntentPrefetch />\n * …\n * </body>\n *\n * It renders nothing; without scripts the links still work and simply do not prefetch.\n */\nimport { useRouter } from 'next/navigation'\nimport { useEffect } from 'react'\nimport { INTENT_PREFETCH_SELECTOR } from '../prefetch.js'\n\nconst INTENT_EVENTS = ['pointerenter', 'focusin', 'touchstart'] as const\n\n/** The site path an intent link points to, without its fragment; null for another site or no href. */\nexport function intentPrefetchTarget(href: string | null): string | null {\n if (!href || !href.startsWith('/') || href.startsWith('//')) return null\n const target = href.split('#', 1)[0] ?? ''\n return target || null\n}\n\nfunction samePage(target: string, location: Location) {\n const path = (value: string) => value.replace(/\\/+$/, '') || '/'\n return path(target.split('?', 1)[0] ?? '') === path(location.pathname)\n}\n\nexport function IntentPrefetch(): null {\n const router = useRouter()\n\n useEffect(() => {\n const prefetched = new Set<string>()\n const onIntent = (event: Event) => {\n const element = event.target instanceof Element ? event.target : null\n const link = element?.closest<HTMLAnchorElement>(INTENT_PREFETCH_SELECTOR)\n const target = intentPrefetchTarget(link?.getAttribute('href') ?? null)\n if (!target || prefetched.has(target) || samePage(target, window.location)) return\n prefetched.add(target)\n router.prefetch(target)\n }\n // Capture, so pointerenter (which does not bubble) reaches the document; passive, so touch never waits on it.\n const options: AddEventListenerOptions = { capture: true, passive: true }\n for (const type of INTENT_EVENTS) document.addEventListener(type, onIntent, options)\n return () => {\n for (const type of INTENT_EVENTS) document.removeEventListener(type, onIntent, options)\n }\n }, [router])\n\n return null\n}\n"]}
1
+ {"version":3,"file":"intent-prefetch.js","sourceRoot":"","sources":["../../../src/ui-kit/shell/intent-prefetch.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAA;AAEZ;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAC3C,OAAO,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AACjC,OAAO,EAAE,wBAAwB,EAAE,MAAM,gBAAgB,CAAA;AAEzD,MAAM,aAAa,GAAG,CAAC,cAAc,EAAE,SAAS,EAAE,YAAY,CAAU,CAAA;AAExE,sGAAsG;AACtG,MAAM,UAAU,oBAAoB,CAAC,IAAmB;IACtD,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAA;IACxE,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAA;IAC1C,OAAO,MAAM,IAAI,IAAI,CAAA;AACvB,CAAC;AAED,SAAS,QAAQ,CAAC,MAAc,EAAE,QAAkB;IAClD,MAAM,IAAI,GAAG,CAAC,KAAa,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,IAAI,GAAG,CAAA;IAChE,OAAO,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,KAAK,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAA;AACxE,CAAC;AAED,MAAM,UAAU,cAAc;IAC5B,MAAM,MAAM,GAAG,SAAS,EAAE,CAAA;IAE1B,SAAS,CAAC,GAAG,EAAE;QACb,MAAM,UAAU,GAAG,IAAI,GAAG,EAAU,CAAA;QACpC,MAAM,QAAQ,GAAG,CAAC,KAAY,EAAE,EAAE;YAChC,MAAM,OAAO,GAAG,KAAK,CAAC,MAAM,YAAY,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAA;YACrE,MAAM,IAAI,GAAG,OAAO,EAAE,OAAO,CAAoB,wBAAwB,CAAC,CAAA;YAC1E,MAAM,MAAM,GAAG,oBAAoB,CAAC,IAAI,EAAE,YAAY,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC,CAAA;YACvE,IAAI,CAAC,MAAM,IAAI,UAAU,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,QAAQ,CAAC;gBAAE,OAAM;YAClF,UAAU,CAAC,GAAG,CAAC,MAAM,CAAC,CAAA;YACtB,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAA;QACzB,CAAC,CAAA;QACD,8GAA8G;QAC9G,MAAM,OAAO,GAA4B,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,CAAA;QACzE,KAAK,MAAM,IAAI,IAAI,aAAa;YAAE,QAAQ,CAAC,gBAAgB,CAAC,IAAI,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAA;QACpF,OAAO,GAAG,EAAE;YACV,KAAK,MAAM,IAAI,IAAI,aAAa;gBAAE,QAAQ,CAAC,mBAAmB,CAAC,IAAI,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAA;QACzF,CAAC,CAAA;IACH,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAA;IAEZ,OAAO,IAAI,CAAA;AACb,CAAC","sourcesContent":["'use client'\n\n/**\n * `IntentPrefetch`: prefetches a top-level header link (from 3.15.0) or an in-content card link when a visitor shows\n * intent, not when it scrolls into view. Links with `prefetch=\"intent\"` (ButtonLink, TextLink, QuoteButton and the\n * SiteHeader's top-level links) render `prefetch={false}` and\n * `data-prefetch=\"intent\"`; this island holds one document listener for pointer entry, focus and touch, and calls\n * `router.prefetch(href)` for the one link the visitor points at, focuses or touches, once per page address. A touch\n * prefetches only the touched link, never the list around it; the current page and links to other sites are never\n * prefetched.\n *\n * Mount it once, in the root layout, beside the header:\n *\n * // src/app/layout.tsx\n * import { IntentPrefetch } from '@brandlab-digital/site-next/ui-kit/shell'\n * <body>\n * <SiteHeader … />\n * <IntentPrefetch />\n * …\n * </body>\n *\n * It renders nothing; without scripts the links still work and simply do not prefetch.\n */\nimport { useRouter } from 'next/navigation'\nimport { useEffect } from 'react'\nimport { INTENT_PREFETCH_SELECTOR } from '../prefetch.js'\n\nconst INTENT_EVENTS = ['pointerenter', 'focusin', 'touchstart'] as const\n\n/** The site path an intent link points to, without its fragment; null for another site or no href. */\nexport function intentPrefetchTarget(href: string | null): string | null {\n if (!href || !href.startsWith('/') || href.startsWith('//')) return null\n const target = href.split('#', 1)[0] ?? ''\n return target || null\n}\n\nfunction samePage(target: string, location: Location) {\n const path = (value: string) => value.replace(/\\/+$/, '') || '/'\n return path(target.split('?', 1)[0] ?? '') === path(location.pathname)\n}\n\nexport function IntentPrefetch(): null {\n const router = useRouter()\n\n useEffect(() => {\n const prefetched = new Set<string>()\n const onIntent = (event: Event) => {\n const element = event.target instanceof Element ? event.target : null\n const link = element?.closest<HTMLAnchorElement>(INTENT_PREFETCH_SELECTOR)\n const target = intentPrefetchTarget(link?.getAttribute('href') ?? null)\n if (!target || prefetched.has(target) || samePage(target, window.location)) return\n prefetched.add(target)\n router.prefetch(target)\n }\n // Capture, so pointerenter (which does not bubble) reaches the document; passive, so touch never waits on it.\n const options: AddEventListenerOptions = { capture: true, passive: true }\n for (const type of INTENT_EVENTS) document.addEventListener(type, onIntent, options)\n return () => {\n for (const type of INTENT_EVENTS) document.removeEventListener(type, onIntent, options)\n }\n }, [router])\n\n return null\n}\n"]}
@@ -11,6 +11,11 @@ export interface MobileCallBarProps extends MobileCallBarSkin {
11
11
  /** Words before the number, for example "Call". The button's name always includes the number. */
12
12
  readonly phoneLabel?: string | undefined;
13
13
  readonly quote: ShellQuote;
14
+ /**
15
+ * A shorter quote label for phones narrower than 420 px, for example "Free quote" for "Get a Free Quote". It must be
16
+ * part of the quote label; the button's text and name stay the full label.
17
+ */
18
+ readonly compactLabel?: string | undefined;
14
19
  }
15
- export declare function MobileCallBar({ phone, phoneLabel, quote, variant, classes }: MobileCallBarProps): import("react/jsx-runtime").JSX.Element;
20
+ export declare function MobileCallBar({ phone, phoneLabel, quote, compactLabel, variant, classes }: MobileCallBarProps): import("react/jsx-runtime").JSX.Element;
16
21
  //# sourceMappingURL=mobile-call-bar.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"mobile-call-bar.d.ts","sourceRoot":"","sources":["../../../src/ui-kit/shell/mobile-call-bar.tsx"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AAC3C,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAA;AAE1C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAA;AAEpD,MAAM,MAAM,iBAAiB,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAA;AACzD,eAAO,MAAM,wBAAwB,2BAA4B,CAAA;AACjE,wDAAwD;AACxD,MAAM,MAAM,oBAAoB,GAAG,CAAC,OAAO,wBAAwB,CAAC,CAAC,MAAM,CAAC,CAAA;AAC5E,MAAM,MAAM,iBAAiB,GAAG,SAAS,CAAC,iBAAiB,EAAE,oBAAoB,CAAC,CAAA;AAElF,MAAM,WAAW,kBAAmB,SAAQ,iBAAiB;IAC3D,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAA;IACvB,iGAAiG;IACjG,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IACxC,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAA;CAC3B;AAED,wBAAgB,aAAa,CAAC,EAAE,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,OAAe,EAAE,OAAO,EAAE,EAAE,kBAAkB,2CAOvG"}
1
+ {"version":3,"file":"mobile-call-bar.d.ts","sourceRoot":"","sources":["../../../src/ui-kit/shell/mobile-call-bar.tsx"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AAC3C,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAA;AAE1C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAA;AAEpD,MAAM,MAAM,iBAAiB,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAA;AACzD,eAAO,MAAM,wBAAwB,2BAA4B,CAAA;AACjE,wDAAwD;AACxD,MAAM,MAAM,oBAAoB,GAAG,CAAC,OAAO,wBAAwB,CAAC,CAAC,MAAM,CAAC,CAAA;AAC5E,MAAM,MAAM,iBAAiB,GAAG,SAAS,CAAC,iBAAiB,EAAE,oBAAoB,CAAC,CAAA;AAElF,MAAM,WAAW,kBAAmB,SAAQ,iBAAiB;IAC3D,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAA;IACvB,iGAAiG;IACjG,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IACxC,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAA;IAC1B;;;OAGG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CAC3C;AAED,wBAAgB,aAAa,CAAC,EAAE,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,YAAY,EAAE,OAAe,EAAE,OAAO,EAAE,EAAE,kBAAkB,2CAOrH"}
@@ -4,12 +4,15 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
4
4
  * hero's own call and quote buttons (`data-bl-call-path`) have scrolled out, and hides over the footer, the drawer, a
5
5
  * dialog, any call path and while a form field has focus. Call reports placement `fab`; the quote button sends
6
6
  * `lead_cta_click` with placement `floating`. Render it once, after the page's `<main>`.
7
+ *
8
+ * Both buttons stay on one line down to 360 px (3.15.0): the number never wraps or truncates; below 420 px the verb
9
+ * ("Call") is visually hidden (the link's name keeps it) and the quote button shows `compactLabel` when given.
7
10
  */
8
11
  import { PhoneLink } from '../primitives/links.js';
9
- import { QuoteButton } from '../primitives/quote-button.js';
12
+ import { ShellQuoteButton } from './shell-quote.js';
10
13
  import { CallBarController } from './call-bar-client.js';
11
14
  export const MOBILE_CALL_BAR_VARIANTS = ['bar', 'float'];
12
- export function MobileCallBar({ phone, phoneLabel, quote, variant = 'bar', classes }) {
13
- return (_jsxs(CallBarController, { variant: variant, className: classes?.root, children: [_jsx(PhoneLink, { phone: phone, placement: "fab", label: phoneLabel, showIcon: true, variant: "button", classes: { root: classes?.call } }), _jsx(QuoteButton, { label: quote.label, href: quote.href, placement: "floating", ctaId: "quote-callbar", classes: { root: classes?.quote } })] }));
15
+ export function MobileCallBar({ phone, phoneLabel, quote, compactLabel, variant = 'bar', classes }) {
16
+ return (_jsxs(CallBarController, { variant: variant, className: classes?.root, children: [_jsx(PhoneLink, { phone: phone, placement: "fab", label: phoneLabel, showIcon: true, variant: "button", classes: { root: classes?.call } }), _jsx(ShellQuoteButton, { label: quote.label, href: quote.href, placement: "floating", ctaId: "quote-callbar", compactLabel: compactLabel, classes: { root: classes?.quote } })] }));
14
17
  }
15
18
  //# sourceMappingURL=mobile-call-bar.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"mobile-call-bar.js","sourceRoot":"","sources":["../../../src/ui-kit/shell/mobile-call-bar.tsx"],"names":[],"mappings":";AAAA;;;;;GAKG;AACH,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAA;AAClD,OAAO,EAAE,WAAW,EAAE,MAAM,+BAA+B,CAAA;AAG3D,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAA;AAIxD,MAAM,CAAC,MAAM,wBAAwB,GAAG,CAAC,KAAK,EAAE,OAAO,CAAU,CAAA;AAYjE,MAAM,UAAU,aAAa,CAAC,EAAE,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,OAAO,GAAG,KAAK,EAAE,OAAO,EAAsB;IACtG,OAAO,CACL,MAAC,iBAAiB,IAAC,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,IAAI,aAC3D,KAAC,SAAS,IAAC,KAAK,EAAE,KAAK,EAAE,SAAS,EAAC,KAAK,EAAC,KAAK,EAAE,UAAU,EAAE,QAAQ,QAAC,OAAO,EAAC,QAAQ,EAAC,OAAO,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,GAAI,EAC1H,KAAC,WAAW,IAAC,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,SAAS,EAAC,UAAU,EAAC,KAAK,EAAC,eAAe,EAAC,OAAO,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,GAAI,IACjH,CACrB,CAAA;AACH,CAAC","sourcesContent":["/**\n * F6: the phone call bar (server component). Call and quote always one tap away below 1024 px: it shows once the\n * hero's own call and quote buttons (`data-bl-call-path`) have scrolled out, and hides over the footer, the drawer, a\n * dialog, any call path and while a form field has focus. Call reports placement `fab`; the quote button sends\n * `lead_cta_click` with placement `floating`. Render it once, after the page's `<main>`.\n */\nimport { PhoneLink } from '../primitives/links.js'\nimport { QuoteButton } from '../primitives/quote-button.js'\nimport type { SkinEntry } from '../skin.js'\nimport type { UiPhone } from '../types.js'\nimport { CallBarController } from './call-bar-client.js'\nimport type { ShellQuote } from './mobile-drawer.js'\n\nexport type MobileCallBarSlot = 'root' | 'call' | 'quote'\nexport const MOBILE_CALL_BAR_VARIANTS = ['bar', 'float'] as const\n/** `bar`: full width; `float`: two pills at the end. */\nexport type MobileCallBarVariant = (typeof MOBILE_CALL_BAR_VARIANTS)[number]\nexport type MobileCallBarSkin = SkinEntry<MobileCallBarSlot, MobileCallBarVariant>\n\nexport interface MobileCallBarProps extends MobileCallBarSkin {\n readonly phone: UiPhone\n /** Words before the number, for example \"Call\". The button's name always includes the number. */\n readonly phoneLabel?: string | undefined\n readonly quote: ShellQuote\n}\n\nexport function MobileCallBar({ phone, phoneLabel, quote, variant = 'bar', classes }: MobileCallBarProps) {\n return (\n <CallBarController variant={variant} className={classes?.root}>\n <PhoneLink phone={phone} placement=\"fab\" label={phoneLabel} showIcon variant=\"button\" classes={{ root: classes?.call }} />\n <QuoteButton label={quote.label} href={quote.href} placement=\"floating\" ctaId=\"quote-callbar\" classes={{ root: classes?.quote }} />\n </CallBarController>\n )\n}\n"]}
1
+ {"version":3,"file":"mobile-call-bar.js","sourceRoot":"","sources":["../../../src/ui-kit/shell/mobile-call-bar.tsx"],"names":[],"mappings":";AAAA;;;;;;;;GAQG;AACH,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAA;AAClD,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAA;AAGnD,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAA;AAIxD,MAAM,CAAC,MAAM,wBAAwB,GAAG,CAAC,KAAK,EAAE,OAAO,CAAU,CAAA;AAiBjE,MAAM,UAAU,aAAa,CAAC,EAAE,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,YAAY,EAAE,OAAO,GAAG,KAAK,EAAE,OAAO,EAAsB;IACpH,OAAO,CACL,MAAC,iBAAiB,IAAC,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,IAAI,aAC3D,KAAC,SAAS,IAAC,KAAK,EAAE,KAAK,EAAE,SAAS,EAAC,KAAK,EAAC,KAAK,EAAE,UAAU,EAAE,QAAQ,QAAC,OAAO,EAAC,QAAQ,EAAC,OAAO,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,GAAI,EAC1H,KAAC,gBAAgB,IAAC,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,SAAS,EAAC,UAAU,EAAC,KAAK,EAAC,eAAe,EAAC,YAAY,EAAE,YAAY,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,GAAI,IAClJ,CACrB,CAAA;AACH,CAAC","sourcesContent":["/**\n * F6: the phone call bar (server component). Call and quote always one tap away below 1024 px: it shows once the\n * hero's own call and quote buttons (`data-bl-call-path`) have scrolled out, and hides over the footer, the drawer, a\n * dialog, any call path and while a form field has focus. Call reports placement `fab`; the quote button sends\n * `lead_cta_click` with placement `floating`. Render it once, after the page's `<main>`.\n *\n * Both buttons stay on one line down to 360 px (3.15.0): the number never wraps or truncates; below 420 px the verb\n * (\"Call\") is visually hidden (the link's name keeps it) and the quote button shows `compactLabel` when given.\n */\nimport { PhoneLink } from '../primitives/links.js'\nimport { ShellQuoteButton } from './shell-quote.js'\nimport type { SkinEntry } from '../skin.js'\nimport type { UiPhone } from '../types.js'\nimport { CallBarController } from './call-bar-client.js'\nimport type { ShellQuote } from './mobile-drawer.js'\n\nexport type MobileCallBarSlot = 'root' | 'call' | 'quote'\nexport const MOBILE_CALL_BAR_VARIANTS = ['bar', 'float'] as const\n/** `bar`: full width; `float`: two pills at the end. */\nexport type MobileCallBarVariant = (typeof MOBILE_CALL_BAR_VARIANTS)[number]\nexport type MobileCallBarSkin = SkinEntry<MobileCallBarSlot, MobileCallBarVariant>\n\nexport interface MobileCallBarProps extends MobileCallBarSkin {\n readonly phone: UiPhone\n /** Words before the number, for example \"Call\". The button's name always includes the number. */\n readonly phoneLabel?: string | undefined\n readonly quote: ShellQuote\n /**\n * A shorter quote label for phones narrower than 420 px, for example \"Free quote\" for \"Get a Free Quote\". It must be\n * part of the quote label; the button's text and name stay the full label.\n */\n readonly compactLabel?: string | undefined\n}\n\nexport function MobileCallBar({ phone, phoneLabel, quote, compactLabel, variant = 'bar', classes }: MobileCallBarProps) {\n return (\n <CallBarController variant={variant} className={classes?.root}>\n <PhoneLink phone={phone} placement=\"fab\" label={phoneLabel} showIcon variant=\"button\" classes={{ root: classes?.call }} />\n <ShellQuoteButton label={quote.label} href={quote.href} placement=\"floating\" ctaId=\"quote-callbar\" compactLabel={compactLabel} classes={{ root: classes?.quote }} />\n </CallBarController>\n )\n}\n"]}
@@ -1,7 +1,7 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { Icon } from '../icons.js';
3
3
  import { PhoneLink } from '../primitives/links.js';
4
- import { QuoteButton } from '../primitives/quote-button.js';
4
+ import { ShellQuoteButton } from './shell-quote.js';
5
5
  import { repeatedSlot, slot } from '../skin.js';
6
6
  import { CurrentLink } from './current-link.js';
7
7
  import { DrawerController } from './drawer-client.js';
@@ -32,7 +32,7 @@ export function MobileDrawer({ navigation, phone, phoneLabel, quote, socials = [
32
32
  close: classes?.close,
33
33
  title: classes?.title,
34
34
  logo: classes?.logo,
35
- }, logo: logo, menuIcon: _jsx(Icon, { name: "menu" }), closeIcon: _jsx(Icon, { name: "close" }), children: [_jsx("nav", { "aria-label": "Main", ...slot(classes, 'nav'), children: runs.map((run) => Array.isArray(run) ? (_jsx("ul", { ...slot(classes, 'links'), children: run.map((link) => (_jsx("li", { children: _jsx(CurrentLink, { href: link.href, slot: "link", prefetch: false, children: link.label }) }, link.id))) }, `links-${run[0].id}`)) : (_jsx(GroupAccordion, { group: run, name: `${id}-groups` }, run.id))) }), _jsxs("div", { ...slot(classes, 'actions'), children: [_jsx(PhoneLink, { phone: phone, placement: "header", label: phoneLabel, showIcon: true, variant: "button", classes: { root: classes?.call } }), _jsx(QuoteButton, { label: quote.label, href: quote.href, placement: "navigation", ctaId: "quote-menu", classes: { root: classes?.quote } })] }), _jsx(SocialLinks, { socials: socials, slotName: "social", className: classes?.social })] }));
35
+ }, logo: logo, menuIcon: _jsx(Icon, { name: "menu" }), closeIcon: _jsx(Icon, { name: "close" }), children: [_jsx("nav", { "aria-label": "Main", ...slot(classes, 'nav'), children: runs.map((run) => Array.isArray(run) ? (_jsx("ul", { ...slot(classes, 'links'), children: run.map((link) => (_jsx("li", { children: _jsx(CurrentLink, { href: link.href, slot: "link", prefetch: false, children: link.label }) }, link.id))) }, `links-${run[0].id}`)) : (_jsx(GroupAccordion, { group: run, name: `${id}-groups` }, run.id))) }), _jsxs("div", { ...slot(classes, 'actions'), children: [_jsx(PhoneLink, { phone: phone, placement: "header", label: phoneLabel, showIcon: true, variant: "button", classes: { root: classes?.call } }), _jsx(ShellQuoteButton, { label: quote.label, href: quote.href, placement: "navigation", ctaId: "quote-menu", classes: { root: classes?.quote } })] }), _jsx(SocialLinks, { socials: socials, slotName: "social", className: classes?.social })] }));
36
36
  }
37
37
  /** One dropdown as an accordion: its hub link first, the featured card's page, then its links. */
38
38
  function GroupAccordion({ group, name }) {
@@ -1 +1 @@
1
- {"version":3,"file":"mobile-drawer.js","sourceRoot":"","sources":["../../../src/ui-kit/shell/mobile-drawer.tsx"],"names":[],"mappings":"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","sourcesContent":["/**\n * F4: the phone and compact-band menu (server component). A modal dialog named \"Menu\", sliding in at\n * `min(100%, 420px)`: the close button first, then the menu in the desktop order (F1, 3.14.0), each dropdown an\n * accordion where it stands (one open at a time) and each run of plain links one list, then full-width Call and quote\n * buttons, and the social links. Every link is in the server HTML. `SiteHeader` renders it;\n * render it on its own only inside a recorded bespoke header.\n */\nimport type { BrandlabNavigation, BrandlabNavLinkItem, BrandlabNavMenuItem } from '@brandlab-digital/site-core/navigation'\nimport type { ReactNode } from 'react'\nimport { Icon } from '../icons.js'\nimport { PhoneLink } from '../primitives/links.js'\nimport { QuoteButton } from '../primitives/quote-button.js'\nimport type { RepeatedSlotOf } from '../repeated-slots.js'\nimport { repeatedSlot, slot, type SkinEntry } from '../skin.js'\nimport type { UiPhone, UiSocial } from '../types.js'\nimport { CurrentLink } from './current-link.js'\nimport { DrawerController } from './drawer-client.js'\nimport { SocialLinks } from './social-links.js'\n\nexport type MobileDrawerSlot =\n | 'root'\n | 'menuButton'\n | 'menuLabel'\n | 'panel'\n | 'top'\n | 'close'\n | 'title'\n | 'logo'\n | 'nav'\n | 'group'\n | 'groupTrigger'\n | 'groupLinks'\n | 'groupLink'\n | 'links'\n | 'link'\n | 'actions'\n | 'call'\n | 'quote'\n | 'social'\n | 'socialLink'\nexport const MOBILE_DRAWER_VARIANTS = ['side', 'full'] as const\nexport type MobileDrawerVariant = (typeof MOBILE_DRAWER_VARIANTS)[number]\nexport interface MobileDrawerLayout {\n /** The side the panel slides from (`side` variant). */\n readonly side?: 'end' | 'start'\n}\n/** Rendered once per group, link or social profile: styled from the skin stylesheet, never by class (3.14.0). */\nexport type MobileDrawerRepeatedSlot = RepeatedSlotOf<'mobileDrawer'>\nexport type MobileDrawerSkin = SkinEntry<MobileDrawerSlot, MobileDrawerVariant, MobileDrawerLayout, MobileDrawerRepeatedSlot>\n\n/** The quote action. `href` is the quote form it falls back to without scripts, for example `/contact#quote`. */\nexport interface ShellQuote {\n readonly label: string\n readonly href: string\n}\n\nexport interface MobileDrawerProps extends MobileDrawerSkin {\n readonly navigation: BrandlabNavigation\n readonly phone: UiPhone\n /** Words before the number on the Call button, for example \"Call\". */\n readonly phoneLabel?: string | undefined\n readonly quote: ShellQuote\n readonly socials?: readonly UiSocial[] | undefined\n /** An optional logo in the drawer's top bar (decorative there). */\n readonly logo?: ReactNode\n /** Prefix for element ids; one per header on the page. */\n readonly idPrefix?: string | undefined\n}\n\nexport function MobileDrawer({\n navigation,\n phone,\n phoneLabel,\n quote,\n socials = [],\n logo,\n idPrefix = 'bl-header',\n variant = 'side',\n layout,\n classes,\n}: MobileDrawerProps) {\n const id = `${idPrefix}-drawer`\n // The drawer keeps the desktop menu's order (F1): a dropdown becomes an accordion where it stands, and each run of\n // plain links between dropdowns is one list.\n const runs: (BrandlabNavMenuItem | BrandlabNavLinkItem[])[] = []\n for (const item of navigation.items) {\n if (item.kind === 'menu') runs.push(item)\n else {\n const last = runs[runs.length - 1]\n if (Array.isArray(last)) last.push(item)\n else runs.push([item])\n }\n }\n return (\n <DrawerController\n id={id}\n variant={variant}\n side={layout?.side ?? 'end'}\n classes={{\n root: classes?.root,\n menuButton: classes?.menuButton,\n menuLabel: classes?.menuLabel,\n panel: classes?.panel,\n top: classes?.top,\n close: classes?.close,\n title: classes?.title,\n logo: classes?.logo,\n }}\n logo={logo}\n menuIcon={<Icon name=\"menu\" />}\n closeIcon={<Icon name=\"close\" />}\n >\n <nav aria-label=\"Main\" {...slot(classes, 'nav')}>\n {runs.map((run) =>\n Array.isArray(run) ? (\n <ul key={`links-${run[0]!.id}`} {...slot(classes, 'links')}>\n {run.map((link) => (\n <li key={link.id}>\n <CurrentLink href={link.href} slot=\"link\" prefetch={false}>\n {link.label}\n </CurrentLink>\n </li>\n ))}\n </ul>\n ) : (\n <GroupAccordion key={run.id} group={run} name={`${id}-groups`} />\n ),\n )}\n </nav>\n <div {...slot(classes, 'actions')}>\n <PhoneLink phone={phone} placement=\"header\" label={phoneLabel} showIcon variant=\"button\" classes={{ root: classes?.call }} />\n <QuoteButton label={quote.label} href={quote.href} placement=\"navigation\" ctaId=\"quote-menu\" classes={{ root: classes?.quote }} />\n </div>\n <SocialLinks socials={socials} slotName=\"social\" className={classes?.social} />\n </DrawerController>\n )\n}\n\n/** One dropdown as an accordion: its hub link first, the featured card's page, then its links. */\nfunction GroupAccordion({ group, name }: { readonly group: BrandlabNavMenuItem; readonly name: string }) {\n return (\n <details name={name} {...repeatedSlot('group')}>\n <summary {...repeatedSlot('groupTrigger')}>\n <span>{group.label}</span>\n <Icon name=\"chevron\" />\n </summary>\n <ul {...repeatedSlot('groupLinks')}>\n <li>\n <CurrentLink href={group.href} slot=\"groupLink\" prefetch={false} hub>\n {group.hubLabel}\n </CurrentLink>\n </li>\n {group.featured && !group.links.some((link) => link.href === group.featured?.href) ? (\n <li>\n <CurrentLink href={group.featured.href} slot=\"groupLink\" prefetch={false}>\n {group.featured.label}\n </CurrentLink>\n </li>\n ) : null}\n {group.links.map((link) => (\n <li key={link.href}>\n <CurrentLink href={link.href} slot=\"groupLink\" prefetch={false}>\n {link.label}\n </CurrentLink>\n </li>\n ))}\n </ul>\n </details>\n )\n}\n"]}
1
+ {"version":3,"file":"mobile-drawer.js","sourceRoot":"","sources":["../../../src/ui-kit/shell/mobile-drawer.tsx"],"names":[],"mappings":"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","sourcesContent":["/**\n * F4: the phone and compact-band menu (server component). A modal dialog named \"Menu\", sliding in at\n * `min(100%, 420px)`: the close button first, then the menu in the desktop order (F1, 3.14.0), each dropdown an\n * accordion where it stands (one open at a time) and each run of plain links one list, then full-width Call and quote\n * buttons, and the social links. Every link is in the server HTML. `SiteHeader` renders it;\n * render it on its own only inside a recorded bespoke header.\n */\nimport type { BrandlabNavigation, BrandlabNavLinkItem, BrandlabNavMenuItem } from '@brandlab-digital/site-core/navigation'\nimport type { ReactNode } from 'react'\nimport { Icon } from '../icons.js'\nimport { PhoneLink } from '../primitives/links.js'\nimport { ShellQuoteButton } from './shell-quote.js'\nimport type { RepeatedSlotOf } from '../repeated-slots.js'\nimport { repeatedSlot, slot, type SkinEntry } from '../skin.js'\nimport type { UiPhone, UiSocial } from '../types.js'\nimport { CurrentLink } from './current-link.js'\nimport { DrawerController } from './drawer-client.js'\nimport { SocialLinks } from './social-links.js'\n\nexport type MobileDrawerSlot =\n | 'root'\n | 'menuButton'\n | 'menuLabel'\n | 'panel'\n | 'top'\n | 'close'\n | 'title'\n | 'logo'\n | 'nav'\n | 'group'\n | 'groupTrigger'\n | 'groupLinks'\n | 'groupLink'\n | 'links'\n | 'link'\n | 'actions'\n | 'call'\n | 'quote'\n | 'social'\n | 'socialLink'\nexport const MOBILE_DRAWER_VARIANTS = ['side', 'full'] as const\nexport type MobileDrawerVariant = (typeof MOBILE_DRAWER_VARIANTS)[number]\nexport interface MobileDrawerLayout {\n /** The side the panel slides from (`side` variant). */\n readonly side?: 'end' | 'start'\n}\n/** Rendered once per group, link or social profile: styled from the skin stylesheet, never by class (3.14.0). */\nexport type MobileDrawerRepeatedSlot = RepeatedSlotOf<'mobileDrawer'>\nexport type MobileDrawerSkin = SkinEntry<MobileDrawerSlot, MobileDrawerVariant, MobileDrawerLayout, MobileDrawerRepeatedSlot>\n\n/** The quote action. `href` is the quote form it falls back to without scripts, for example `/contact#quote`. */\nexport interface ShellQuote {\n readonly label: string\n readonly href: string\n}\n\nexport interface MobileDrawerProps extends MobileDrawerSkin {\n readonly navigation: BrandlabNavigation\n readonly phone: UiPhone\n /** Words before the number on the Call button, for example \"Call\". */\n readonly phoneLabel?: string | undefined\n readonly quote: ShellQuote\n readonly socials?: readonly UiSocial[] | undefined\n /** An optional logo in the drawer's top bar (decorative there). */\n readonly logo?: ReactNode\n /** Prefix for element ids; one per header on the page. */\n readonly idPrefix?: string | undefined\n}\n\nexport function MobileDrawer({\n navigation,\n phone,\n phoneLabel,\n quote,\n socials = [],\n logo,\n idPrefix = 'bl-header',\n variant = 'side',\n layout,\n classes,\n}: MobileDrawerProps) {\n const id = `${idPrefix}-drawer`\n // The drawer keeps the desktop menu's order (F1): a dropdown becomes an accordion where it stands, and each run of\n // plain links between dropdowns is one list.\n const runs: (BrandlabNavMenuItem | BrandlabNavLinkItem[])[] = []\n for (const item of navigation.items) {\n if (item.kind === 'menu') runs.push(item)\n else {\n const last = runs[runs.length - 1]\n if (Array.isArray(last)) last.push(item)\n else runs.push([item])\n }\n }\n return (\n <DrawerController\n id={id}\n variant={variant}\n side={layout?.side ?? 'end'}\n classes={{\n root: classes?.root,\n menuButton: classes?.menuButton,\n menuLabel: classes?.menuLabel,\n panel: classes?.panel,\n top: classes?.top,\n close: classes?.close,\n title: classes?.title,\n logo: classes?.logo,\n }}\n logo={logo}\n menuIcon={<Icon name=\"menu\" />}\n closeIcon={<Icon name=\"close\" />}\n >\n <nav aria-label=\"Main\" {...slot(classes, 'nav')}>\n {runs.map((run) =>\n Array.isArray(run) ? (\n <ul key={`links-${run[0]!.id}`} {...slot(classes, 'links')}>\n {run.map((link) => (\n <li key={link.id}>\n <CurrentLink href={link.href} slot=\"link\" prefetch={false}>\n {link.label}\n </CurrentLink>\n </li>\n ))}\n </ul>\n ) : (\n <GroupAccordion key={run.id} group={run} name={`${id}-groups`} />\n ),\n )}\n </nav>\n <div {...slot(classes, 'actions')}>\n <PhoneLink phone={phone} placement=\"header\" label={phoneLabel} showIcon variant=\"button\" classes={{ root: classes?.call }} />\n <ShellQuoteButton label={quote.label} href={quote.href} placement=\"navigation\" ctaId=\"quote-menu\" classes={{ root: classes?.quote }} />\n </div>\n <SocialLinks socials={socials} slotName=\"social\" className={classes?.social} />\n </DrawerController>\n )\n}\n\n/** One dropdown as an accordion: its hub link first, the featured card's page, then its links. */\nfunction GroupAccordion({ group, name }: { readonly group: BrandlabNavMenuItem; readonly name: string }) {\n return (\n <details name={name} {...repeatedSlot('group')}>\n <summary {...repeatedSlot('groupTrigger')}>\n <span>{group.label}</span>\n <Icon name=\"chevron\" />\n </summary>\n <ul {...repeatedSlot('groupLinks')}>\n <li>\n <CurrentLink href={group.href} slot=\"groupLink\" prefetch={false} hub>\n {group.hubLabel}\n </CurrentLink>\n </li>\n {group.featured && !group.links.some((link) => link.href === group.featured?.href) ? (\n <li>\n <CurrentLink href={group.featured.href} slot=\"groupLink\" prefetch={false}>\n {group.featured.label}\n </CurrentLink>\n </li>\n ) : null}\n {group.links.map((link) => (\n <li key={link.href}>\n <CurrentLink href={link.href} slot=\"groupLink\" prefetch={false}>\n {link.label}\n </CurrentLink>\n </li>\n ))}\n </ul>\n </details>\n )\n}\n"]}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * The quote button the shell renders in the header, the drawer and the call bar (internal). The same DOM as
3
+ * `QuoteButton`, through `PageLink`, so it keeps Next's prefetch (`LINK_PREFETCH_POLICY.primaryAction`) everywhere
4
+ * but on its own page: on `/contact` the `/contact#quote` button never prefetches the page the visitor is on (W2).
5
+ */
6
+ import { type QuoteButtonProps } from '../primitives/quote-button.js';
7
+ export declare function ShellQuoteButton({ compactLabel, ...props }: QuoteButtonProps & {
8
+ readonly compactLabel?: string | undefined;
9
+ }): import("react/jsx-runtime").JSX.Element;
10
+ //# sourceMappingURL=shell-quote.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shell-quote.d.ts","sourceRoot":"","sources":["../../../src/ui-kit/shell/shell-quote.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAoB,KAAK,gBAAgB,EAAE,MAAM,+BAA+B,CAAA;AAGvF,wBAAgB,gBAAgB,CAAC,EAAE,YAAY,EAAE,GAAG,KAAK,EAAE,EAAE,gBAAgB,GAAG;IAAE,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,2CAO7H"}
@@ -0,0 +1,13 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ /**
3
+ * The quote button the shell renders in the header, the drawer and the call bar (internal). The same DOM as
4
+ * `QuoteButton`, through `PageLink`, so it keeps Next's prefetch (`LINK_PREFETCH_POLICY.primaryAction`) everywhere
5
+ * but on its own page: on `/contact` the `/contact#quote` button never prefetches the page the visitor is on (W2).
6
+ */
7
+ import { quoteButtonParts } from '../primitives/quote-button.js';
8
+ import { PageLink } from './current-link.js';
9
+ export function ShellQuoteButton({ compactLabel, ...props }) {
10
+ const { href, hooks, children } = quoteButtonParts(props, { compactLabel });
11
+ return (_jsx(PageLink, { href: href, prefetch: props.prefetch, hooks: hooks, children: children }));
12
+ }
13
+ //# sourceMappingURL=shell-quote.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shell-quote.js","sourceRoot":"","sources":["../../../src/ui-kit/shell/shell-quote.tsx"],"names":[],"mappings":";AAAA;;;;GAIG;AACH,OAAO,EAAE,gBAAgB,EAAyB,MAAM,+BAA+B,CAAA;AACvF,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAE5C,MAAM,UAAU,gBAAgB,CAAC,EAAE,YAAY,EAAE,GAAG,KAAK,EAAqE;IAC5H,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,gBAAgB,CAAC,KAAK,EAAE,EAAE,YAAY,EAAE,CAAC,CAAA;IAC3E,OAAO,CACL,KAAC,QAAQ,IAAC,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,CAAC,QAAQ,EAAE,KAAK,EAAE,KAAK,YACzD,QAAQ,GACA,CACZ,CAAA;AACH,CAAC","sourcesContent":["/**\n * The quote button the shell renders in the header, the drawer and the call bar (internal). The same DOM as\n * `QuoteButton`, through `PageLink`, so it keeps Next's prefetch (`LINK_PREFETCH_POLICY.primaryAction`) everywhere\n * but on its own page: on `/contact` the `/contact#quote` button never prefetches the page the visitor is on (W2).\n */\nimport { quoteButtonParts, type QuoteButtonProps } from '../primitives/quote-button.js'\nimport { PageLink } from './current-link.js'\n\nexport function ShellQuoteButton({ compactLabel, ...props }: QuoteButtonProps & { readonly compactLabel?: string | undefined }) {\n const { href, hooks, children } = quoteButtonParts(props, { compactLabel })\n return (\n <PageLink href={href} prefetch={props.prefetch} hooks={hooks}>\n {children}\n </PageLink>\n )\n}\n"]}
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * F2: the header shell (server component). The same structure on every site: the skip link, the optional utility
3
3
  * bar, then a sticky, solid `<header>` holding the logo, the menu, the phone and the quote button. Layout follows the
4
- * header's own width (container queries): from 1280 px the full menu; from 1024 to 1279 px a compact band with the
4
+ * header's own width (container queries): from 1200 px the full menu; from 1024 to 1199 px a compact band with the
5
5
  * phone and its number, the quote button and a Menu button; below 1024 px the logo, a 44 px call button and a 44 px
6
6
  * Menu button. Every menu, hub and panel link is an `<a href>` in the server HTML (F3); client leaves only change
7
7
  * state.
@@ -4,7 +4,7 @@ import { SkipLink } from '../../ui.js';
4
4
  import { MAIN_CONTENT_ID } from '../../navigation/constants.js';
5
5
  import { Icon } from '../icons.js';
6
6
  import { PhoneLink } from '../primitives/links.js';
7
- import { QuoteButton } from '../primitives/quote-button.js';
7
+ import { ShellQuoteButton } from './shell-quote.js';
8
8
  import { cx, repeatedSlot, slot } from '../skin.js';
9
9
  import { CurrentLink, LogoLink } from './current-link.js';
10
10
  import { HeaderRoot, NavController, NavItem, NavPanel, NavTrigger } from './header-client.js';
@@ -12,14 +12,14 @@ import { MobileDrawer } from './mobile-drawer.js';
12
12
  export const SITE_HEADER_VARIANTS = ['standard', 'call-first'];
13
13
  export function SiteHeader({ navigation, brandName, homeHref, logo, phone, phoneLabel, quote, socials, skipLabel, utility, drawer, drawerLogo, idPrefix = 'bl-header', variant = 'standard', layout, classes, }) {
14
14
  const callFirst = variant === 'call-first';
15
- return (_jsxs(_Fragment, { children: [_jsx(SkipLink, { targetId: MAIN_CONTENT_ID, "data-bl": "skip", className: classes?.skip, children: skipLabel }), utility, _jsx(HeaderRoot, { variant: variant, navAlign: layout?.navAlign ?? 'center', compactAfterScroll: layout?.compactAfterScroll ?? false, className: classes?.root, children: _jsx("div", { ...slot(classes, 'bar'), children: _jsxs("div", { ...slot(classes, 'inner'), children: [_jsx(LogoLink, { href: homeHref, label: brandName, slot: "logo", className: classes?.logo, children: logo }), _jsx(NavController, { label: "Main", className: classes?.nav, children: _jsx("ul", { ...slot(classes, 'list'), children: navigation.items.map((item) => item.kind === 'link' ? (_jsx(LinkItem, { item: item }, item.id)) : (_jsx(MenuItem, { item: item, panelId: `${idPrefix}-panel-${item.id}` }, item.id))) }) }), _jsxs("div", { ...slot(classes, 'actions'), children: [_jsx(PhoneLink, { phone: phone, placement: "header", label: phoneLabel, showIcon: true, variant: callFirst ? 'button' : 'text', classes: { root: classes?.phone, icon: classes?.phoneIcon, label: classes?.phoneLabel, number: classes?.phoneNumber } }), _jsx(QuoteButton, { label: quote.label, href: quote.href, placement: "header", ctaId: "quote-header", classes: { root: classes?.quote, label: classes?.quoteLabel, icon: classes?.quoteIcon } }), _jsx(MobileDrawer, { ...drawer, classes: {
15
+ return (_jsxs(_Fragment, { children: [_jsx(SkipLink, { targetId: MAIN_CONTENT_ID, "data-bl": "skip", className: classes?.skip, children: skipLabel }), utility, _jsx(HeaderRoot, { variant: variant, navAlign: layout?.navAlign ?? 'center', compactAfterScroll: layout?.compactAfterScroll ?? false, className: classes?.root, children: _jsx("div", { ...slot(classes, 'bar'), children: _jsxs("div", { ...slot(classes, 'inner'), children: [_jsx(LogoLink, { href: homeHref, label: brandName, slot: "logo", className: classes?.logo, children: logo }), _jsx(NavController, { label: "Main", className: classes?.nav, children: _jsx("ul", { ...slot(classes, 'list'), children: navigation.items.map((item) => item.kind === 'link' ? (_jsx(LinkItem, { item: item }, item.id)) : (_jsx(MenuItem, { item: item, panelId: `${idPrefix}-panel-${item.id}` }, item.id))) }) }), _jsxs("div", { ...slot(classes, 'actions'), children: [_jsx(PhoneLink, { phone: phone, placement: "header", label: phoneLabel, showIcon: true, variant: callFirst ? 'button' : 'text', classes: { root: classes?.phone, icon: classes?.phoneIcon, label: classes?.phoneLabel, number: classes?.phoneNumber } }), _jsx(ShellQuoteButton, { label: quote.label, href: quote.href, placement: "header", ctaId: "quote-header", classes: { root: classes?.quote, label: classes?.quoteLabel, icon: classes?.quoteIcon } }), _jsx(MobileDrawer, { ...drawer, classes: {
16
16
  ...drawer?.classes,
17
17
  menuButton: cx(drawer?.classes?.menuButton, classes?.menuButton),
18
18
  menuLabel: cx(drawer?.classes?.menuLabel, classes?.menuLabel),
19
19
  }, navigation: navigation, phone: phone, phoneLabel: phoneLabel, quote: quote, socials: socials, logo: drawerLogo, idPrefix: idPrefix })] })] }) }) })] }));
20
20
  }
21
21
  function LinkItem({ item }) {
22
- return (_jsx(NavItem, { paths: [item.href, ...(item.activePaths ?? [])], children: _jsx(CurrentLink, { href: item.href, slot: "link", children: item.label }) }));
22
+ return (_jsx(NavItem, { paths: [item.href, ...(item.activePaths ?? [])], children: _jsx(CurrentLink, { href: item.href, slot: "link", prefetch: "intent", children: item.label }) }));
23
23
  }
24
24
  function MenuItem({ item, panelId }) {
25
25
  const groups = item.panel === 'columns' && item.groups && item.groups.length > 0 ? item.groups : undefined;
@@ -27,7 +27,7 @@ function MenuItem({ item, panelId }) {
27
27
  const grouped = new Set(groups?.flatMap((group) => group.links.map((link) => link.href)));
28
28
  const ungrouped = groups ? item.links.filter((link) => !grouped.has(link.href)) : [];
29
29
  const columnCount = groups ? groups.length + (ungrouped.length > 0 ? 1 : 0) : 0;
30
- return (_jsxs(NavItem, { menuId: item.id, paths: [item.href, ...(item.activePaths ?? [])], children: [_jsxs("span", { ...repeatedSlot('itemRow'), children: [_jsx(CurrentLink, { href: item.href, slot: "link", children: item.label }), _jsx(NavTrigger, { menuId: item.id, panelId: panelId, label: item.label, children: _jsx(Icon, { name: "chevron" }) })] }), _jsx(NavPanel, { menuId: item.id, panelId: panelId, variant: item.panel, columns: groups ? Math.min(3, Math.max(2, columnCount)) : undefined, children: _jsxs("div", { ...repeatedSlot('panelBody'), children: [item.panel === 'featured' && item.featured ? (_jsxs(CurrentLink, { href: item.featured.href, slot: "featured", prefetch: false, children: [_jsx("span", { ...repeatedSlot('featuredMedia'), children: _jsx(Image, { src: item.featured.image.src, alt: item.featured.image.alt, width: item.featured.image.width, height: item.featured.image.height, sizes: "240px" }) }), _jsx("span", { ...repeatedSlot('featuredLabel'), children: item.featured.label }), _jsx("span", { ...repeatedSlot('featuredText'), children: item.featured.description })] })) : null, _jsxs("ul", { ...repeatedSlot('panelList'), children: [_jsx("li", { children: _jsxs(CurrentLink, { href: item.href, slot: "panelLink", hub: true, prefetch: false, children: [_jsx("span", { ...repeatedSlot('panelLabel'), children: item.hubLabel }), _jsx(Icon, { name: "arrow" })] }) }), groups ? null : item.links.map((link) => _jsx(PanelLink, { link: link }, link.href))] }), groups?.map((group) => (_jsxs("div", { ...repeatedSlot('panelGroup'), children: [_jsx("p", { ...repeatedSlot('panelHeading'), children: group.heading }), _jsx("ul", { ...repeatedSlot('panelList'), children: group.links.map((link) => (_jsx(PanelLink, { link: link }, link.href))) })] }, group.heading))), ungrouped.length > 0 ? (_jsx("div", { ...repeatedSlot('panelGroup'), children: _jsx("ul", { ...repeatedSlot('panelList'), children: ungrouped.map((link) => (_jsx(PanelLink, { link: link }, link.href))) }) })) : null] }) })] }));
30
+ return (_jsxs(NavItem, { menuId: item.id, paths: [item.href, ...(item.activePaths ?? [])], children: [_jsxs("span", { ...repeatedSlot('itemRow'), children: [_jsx(CurrentLink, { href: item.href, slot: "link", prefetch: "intent", children: item.label }), _jsx(NavTrigger, { menuId: item.id, panelId: panelId, label: item.label, children: _jsx(Icon, { name: "chevron" }) })] }), _jsx(NavPanel, { menuId: item.id, panelId: panelId, variant: item.panel, columns: groups ? Math.min(3, Math.max(2, columnCount)) : undefined, children: _jsxs("div", { ...repeatedSlot('panelBody'), children: [item.panel === 'featured' && item.featured ? (_jsxs(CurrentLink, { href: item.featured.href, slot: "featured", prefetch: false, children: [_jsx("span", { ...repeatedSlot('featuredMedia'), children: _jsx(Image, { src: item.featured.image.src, alt: item.featured.image.alt, width: item.featured.image.width, height: item.featured.image.height, sizes: "240px" }) }), _jsx("span", { ...repeatedSlot('featuredLabel'), children: item.featured.label }), _jsx("span", { ...repeatedSlot('featuredText'), children: item.featured.description })] })) : null, _jsxs("ul", { ...repeatedSlot('panelList'), children: [_jsx("li", { children: _jsxs(CurrentLink, { href: item.href, slot: "panelLink", hub: true, prefetch: false, children: [_jsx("span", { ...repeatedSlot('panelLabel'), children: item.hubLabel }), _jsx(Icon, { name: "arrow" })] }) }), groups ? null : item.links.map((link) => _jsx(PanelLink, { link: link }, link.href))] }), groups?.map((group) => (_jsxs("div", { ...repeatedSlot('panelGroup'), children: [_jsx("p", { ...repeatedSlot('panelHeading'), children: group.heading }), _jsx("ul", { ...repeatedSlot('panelList'), children: group.links.map((link) => (_jsx(PanelLink, { link: link }, link.href))) })] }, group.heading))), ungrouped.length > 0 ? (_jsx("div", { ...repeatedSlot('panelGroup'), children: _jsx("ul", { ...repeatedSlot('panelList'), children: ungrouped.map((link) => (_jsx(PanelLink, { link: link }, link.href))) }) })) : null] }) })] }));
31
31
  }
32
32
  function PanelLink({ link }) {
33
33
  return (_jsx("li", { children: _jsxs(CurrentLink, { href: link.href, slot: "panelLink", prefetch: false, children: [_jsx("span", { ...repeatedSlot('panelLabel'), children: link.label }), link.description ? _jsx("span", { ...repeatedSlot('panelText'), children: link.description }) : null] }) }));
@@ -1 +1 @@
1
- {"version":3,"file":"site-header.js","sourceRoot":"","sources":["../../../src/ui-kit/shell/site-header.tsx"],"names":[],"mappings":";AASA,OAAO,KAAK,MAAM,YAAY,CAAA;AAE9B,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AACtC,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAA;AAC/D,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAA;AAClC,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAA;AAClD,OAAO,EAAE,WAAW,EAAE,MAAM,+BAA+B,CAAA;AAE3D,OAAO,EAAE,EAAE,EAAE,YAAY,EAAE,IAAI,EAAkB,MAAM,YAAY,CAAA;AAEnE,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AACzD,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAA;AAC7F,OAAO,EAAE,YAAY,EAA0C,MAAM,oBAAoB,CAAA;AAoCzF,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,UAAU,EAAE,YAAY,CAAU,CAAA;AAwCvE,MAAM,UAAU,UAAU,CAAC,EACzB,UAAU,EACV,SAAS,EACT,QAAQ,EACR,IAAI,EACJ,KAAK,EACL,UAAU,EACV,KAAK,EACL,OAAO,EACP,SAAS,EACT,OAAO,EACP,MAAM,EACN,UAAU,EACV,QAAQ,GAAG,WAAW,EACtB,OAAO,GAAG,UAAU,EACpB,MAAM,EACN,OAAO,GACS;IAChB,MAAM,SAAS,GAAG,OAAO,KAAK,YAAY,CAAA;IAC1C,OAAO,CACL,8BACE,KAAC,QAAQ,IAAC,QAAQ,EAAE,eAAe,aAAU,MAAM,EAAC,SAAS,EAAE,OAAO,EAAE,IAAI,YACzE,SAAS,GACD,EACV,OAAO,EACR,KAAC,UAAU,IACT,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,MAAM,EAAE,QAAQ,IAAI,QAAQ,EACtC,kBAAkB,EAAE,MAAM,EAAE,kBAAkB,IAAI,KAAK,EACvD,SAAS,EAAE,OAAO,EAAE,IAAI,YAExB,iBAAS,IAAI,CAAC,OAAO,EAAE,KAAK,CAAC,YAC3B,kBAAS,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,aAC7B,KAAC,QAAQ,IAAC,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,EAAC,MAAM,EAAC,SAAS,EAAE,OAAO,EAAE,IAAI,YAC7E,IAAI,GACI,EACX,KAAC,aAAa,IAAC,KAAK,EAAC,MAAM,EAAC,SAAS,EAAE,OAAO,EAAE,GAAG,YACjD,gBAAQ,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,YAC1B,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAC7B,IAAI,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,CACrB,KAAC,QAAQ,IAAe,IAAI,EAAE,IAAI,IAAnB,IAAI,CAAC,EAAE,CAAgB,CACvC,CAAC,CAAC,CAAC,CACF,KAAC,QAAQ,IAAe,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,QAAQ,UAAU,IAAI,CAAC,EAAE,EAAE,IAA5D,IAAI,CAAC,EAAE,CAAyD,CAChF,CACF,GACE,GACS,EAChB,kBAAS,IAAI,CAAC,OAAO,EAAE,SAAS,CAAC,aAE/B,KAAC,SAAS,IACR,KAAK,EAAE,KAAK,EACZ,SAAS,EAAC,QAAQ,EAClB,KAAK,EAAE,UAAU,EACjB,QAAQ,QACR,OAAO,EAAE,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,EACtC,OAAO,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,GACrH,EACF,KAAC,WAAW,IACV,KAAK,EAAE,KAAK,CAAC,KAAK,EAClB,IAAI,EAAE,KAAK,CAAC,IAAI,EAChB,SAAS,EAAC,QAAQ,EAClB,KAAK,EAAC,cAAc,EACpB,OAAO,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,GACvF,EACF,KAAC,YAAY,OACP,MAAM,EACV,OAAO,EAAE;4CACP,GAAG,MAAM,EAAE,OAAO;4CAClB,UAAU,EAAE,EAAE,CAAC,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,UAAU,CAAC;4CAChE,SAAS,EAAE,EAAE,CAAC,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,SAAS,CAAC;yCAC9D,EACD,UAAU,EAAE,UAAU,EACtB,KAAK,EAAE,KAAK,EACZ,UAAU,EAAE,UAAU,EACtB,KAAK,EAAE,KAAK,EACZ,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,UAAU,EAChB,QAAQ,EAAE,QAAQ,GAClB,IACE,IACF,GACF,GACK,IACZ,CACJ,CAAA;AACH,CAAC;AAED,SAAS,QAAQ,CAAC,EAAE,IAAI,EAAiC;IACvD,OAAO,CACL,KAAC,OAAO,IAAC,KAAK,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,CAAC,IAAI,CAAC,WAAW,IAAI,EAAE,CAAC,CAAC,YACtD,KAAC,WAAW,IAAC,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,IAAI,EAAC,MAAM,YACtC,IAAI,CAAC,KAAK,GACC,GACN,CACX,CAAA;AACH,CAAC;AAED,SAAS,QAAQ,CAAC,EAAE,IAAI,EAAE,OAAO,EAAkD;IACjF,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,KAAK,SAAS,IAAI,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAA;IAC1G,0GAA0G;IAC1G,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IACzF,MAAM,SAAS,GAAG,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAA;IACpF,MAAM,WAAW,GAAG,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;IAC/E,OAAO,CACL,MAAC,OAAO,IAAC,MAAM,EAAE,IAAI,CAAC,EAAE,EAAE,KAAK,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,CAAC,IAAI,CAAC,WAAW,IAAI,EAAE,CAAC,CAAC,aACvE,mBAAU,YAAY,CAAC,SAAS,CAAC,aAC/B,KAAC,WAAW,IAAC,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,IAAI,EAAC,MAAM,YACtC,IAAI,CAAC,KAAK,GACC,EACd,KAAC,UAAU,IAAC,MAAM,EAAE,IAAI,CAAC,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,YAC9D,KAAC,IAAI,IAAC,IAAI,EAAC,SAAS,GAAG,GACZ,IACR,EACP,KAAC,QAAQ,IACP,MAAM,EAAE,IAAI,CAAC,EAAE,EACf,OAAO,EAAE,OAAO,EAChB,OAAO,EAAE,IAAI,CAAC,KAAK,EACnB,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,YAGnE,kBAAS,YAAY,CAAC,WAAW,CAAC,aAC/B,IAAI,CAAC,KAAK,KAAK,UAAU,IAAI,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAC5C,MAAC,WAAW,IAAC,IAAI,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,IAAI,EAAC,UAAU,EAAC,QAAQ,EAAE,KAAK,aACpE,kBAAU,YAAY,CAAC,eAAe,CAAC,YACrC,KAAC,KAAK,IACJ,GAAG,EAAE,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,EAC5B,GAAG,EAAE,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,EAC5B,KAAK,EAAE,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,KAAK,EAChC,MAAM,EAAE,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,MAAM,EAClC,KAAK,EAAC,OAAO,GACb,GACG,EACP,kBAAU,YAAY,CAAC,eAAe,CAAC,YAAG,IAAI,CAAC,QAAQ,CAAC,KAAK,GAAQ,EACrE,kBAAU,YAAY,CAAC,cAAc,CAAC,YAAG,IAAI,CAAC,QAAQ,CAAC,WAAW,GAAQ,IAC9D,CACf,CAAC,CAAC,CAAC,IAAI,EAER,iBAAQ,YAAY,CAAC,WAAW,CAAC,aAC/B,uBACE,MAAC,WAAW,IAAC,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,IAAI,EAAC,WAAW,EAAC,GAAG,QAAC,QAAQ,EAAE,KAAK,aAChE,kBAAU,YAAY,CAAC,YAAY,CAAC,YAAG,IAAI,CAAC,QAAQ,GAAQ,EAC5D,KAAC,IAAI,IAAC,IAAI,EAAC,OAAO,GAAG,IACT,GACX,EACJ,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,KAAC,SAAS,IAAiB,IAAI,EAAE,IAAI,IAArB,IAAI,CAAC,IAAI,CAAgB,CAAC,IACjF,EACJ,MAAM,EAAE,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CACtB,kBAA6B,YAAY,CAAC,YAAY,CAAC,aACrD,eAAO,YAAY,CAAC,cAAc,CAAC,YAAG,KAAK,CAAC,OAAO,GAAK,EACxD,gBAAQ,YAAY,CAAC,WAAW,CAAC,YAC9B,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CACzB,KAAC,SAAS,IAAiB,IAAI,EAAE,IAAI,IAArB,IAAI,CAAC,IAAI,CAAgB,CAC1C,CAAC,GACC,KANG,KAAK,CAAC,OAAO,CAOjB,CACP,CAAC,EACD,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CACtB,iBAAS,YAAY,CAAC,YAAY,CAAC,YACjC,gBAAQ,YAAY,CAAC,WAAW,CAAC,YAC9B,SAAS,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CACvB,KAAC,SAAS,IAAiB,IAAI,EAAE,IAAI,IAArB,IAAI,CAAC,IAAI,CAAgB,CAC1C,CAAC,GACC,GACD,CACP,CAAC,CAAC,CAAC,IAAI,IACJ,GACG,IACH,CACX,CAAA;AACH,CAAC;AAED,SAAS,SAAS,CAAC,EAAE,IAAI,EAAkD;IACzE,OAAO,CACL,uBACE,MAAC,WAAW,IAAC,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,IAAI,EAAC,WAAW,EAAC,QAAQ,EAAE,KAAK,aAC5D,kBAAU,YAAY,CAAC,YAAY,CAAC,YAAG,IAAI,CAAC,KAAK,GAAQ,EACxD,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,kBAAU,YAAY,CAAC,WAAW,CAAC,YAAG,IAAI,CAAC,WAAW,GAAQ,CAAC,CAAC,CAAC,IAAI,IAC7E,GACX,CACN,CAAA;AACH,CAAC","sourcesContent":["/**\n * F2: the header shell (server component). The same structure on every site: the skip link, the optional utility\n * bar, then a sticky, solid `<header>` holding the logo, the menu, the phone and the quote button. Layout follows the\n * header's own width (container queries): from 1280 px the full menu; from 1024 to 1279 px a compact band with the\n * phone and its number, the quote button and a Menu button; below 1024 px the logo, a 44 px call button and a 44 px\n * Menu button. Every menu, hub and panel link is an `<a href>` in the server HTML (F3); client leaves only change\n * state.\n */\nimport type { BrandlabNavigation, BrandlabNavLinkItem, BrandlabNavMenuItem } from '@brandlab-digital/site-core/navigation'\nimport Image from 'next/image'\nimport type { ReactNode } from 'react'\nimport { SkipLink } from '../../ui.js'\nimport { MAIN_CONTENT_ID } from '../../navigation/constants.js'\nimport { Icon } from '../icons.js'\nimport { PhoneLink } from '../primitives/links.js'\nimport { QuoteButton } from '../primitives/quote-button.js'\nimport type { RepeatedSlotOf } from '../repeated-slots.js'\nimport { cx, repeatedSlot, slot, type SkinEntry } from '../skin.js'\nimport type { UiPhone, UiSocial } from '../types.js'\nimport { CurrentLink, LogoLink } from './current-link.js'\nimport { HeaderRoot, NavController, NavItem, NavPanel, NavTrigger } from './header-client.js'\nimport { MobileDrawer, type MobileDrawerSkin, type ShellQuote } from './mobile-drawer.js'\n\nexport type SiteHeaderSlot =\n | 'skip'\n | 'root'\n | 'bar'\n | 'inner'\n | 'logo'\n | 'nav'\n | 'list'\n | 'item'\n | 'itemRow'\n | 'link'\n | 'trigger'\n | 'panel'\n | 'panelBody'\n | 'panelList'\n | 'panelGroup'\n | 'panelHeading'\n | 'panelLink'\n | 'panelLabel'\n | 'panelText'\n | 'featured'\n | 'featuredMedia'\n | 'featuredLabel'\n | 'featuredText'\n | 'actions'\n | 'phone'\n | 'phoneIcon'\n | 'phoneLabel'\n | 'phoneNumber'\n | 'quote'\n | 'quoteLabel'\n | 'quoteIcon'\n | 'menuButton'\n | 'menuLabel'\nexport const SITE_HEADER_VARIANTS = ['standard', 'call-first'] as const\n/**\n * `call-first` (recorded exceptions, v1 §9.10): the phone is the primary action (a button with its number at every\n * width); the quote button still follows it, as on `standard`.\n */\nexport type SiteHeaderVariant = (typeof SITE_HEADER_VARIANTS)[number]\nexport interface SiteHeaderLayout {\n /** Where the menu sits between the logo and the actions. */\n readonly navAlign?: 'center' | 'end'\n /** Compact the header (`data-compact=\"true\"`) once the page has scrolled 80 px. It never hides. */\n readonly compactAfterScroll?: boolean\n}\n/** Rendered once per menu item or panel link: styled from the skin stylesheet, never by class (3.14.0). */\nexport type SiteHeaderRepeatedSlot = RepeatedSlotOf<'siteHeader'>\nexport type SiteHeaderSkin = SkinEntry<SiteHeaderSlot, SiteHeaderVariant, SiteHeaderLayout, SiteHeaderRepeatedSlot>\n\nexport interface SiteHeaderProps extends SiteHeaderSkin {\n readonly navigation: BrandlabNavigation\n /** The logo link's accessible name. */\n readonly brandName: string\n readonly homeHref: string\n readonly logo: ReactNode\n /** From the derived business facts, never typed by hand. */\n readonly phone: UiPhone\n /** The small line above the number, for example \"Call us\". Also leads the drawer's Call button. */\n readonly phoneLabel?: string | undefined\n readonly quote: ShellQuote\n readonly socials?: readonly UiSocial[] | undefined\n /** The site's skip-link text, for example \"Skip to main content\". It targets `#main`. */\n readonly skipLabel: string\n /** The optional utility bar (`<UtilityBar>`), placed between the skip link and the header. */\n readonly utility?: ReactNode\n /** The site's `mobileDrawer` skin entry. */\n readonly drawer?: MobileDrawerSkin | undefined\n /** An optional logo for the drawer's top bar. */\n readonly drawerLogo?: ReactNode\n /** Prefix for element ids; one per header on the page. */\n readonly idPrefix?: string | undefined\n}\n\nexport function SiteHeader({\n navigation,\n brandName,\n homeHref,\n logo,\n phone,\n phoneLabel,\n quote,\n socials,\n skipLabel,\n utility,\n drawer,\n drawerLogo,\n idPrefix = 'bl-header',\n variant = 'standard',\n layout,\n classes,\n}: SiteHeaderProps) {\n const callFirst = variant === 'call-first'\n return (\n <>\n <SkipLink targetId={MAIN_CONTENT_ID} data-bl=\"skip\" className={classes?.skip}>\n {skipLabel}\n </SkipLink>\n {utility}\n <HeaderRoot\n variant={variant}\n navAlign={layout?.navAlign ?? 'center'}\n compactAfterScroll={layout?.compactAfterScroll ?? false}\n className={classes?.root}\n >\n <div {...slot(classes, 'bar')}>\n <div {...slot(classes, 'inner')}>\n <LogoLink href={homeHref} label={brandName} slot=\"logo\" className={classes?.logo}>\n {logo}\n </LogoLink>\n <NavController label=\"Main\" className={classes?.nav}>\n <ul {...slot(classes, 'list')}>\n {navigation.items.map((item) =>\n item.kind === 'link' ? (\n <LinkItem key={item.id} item={item} />\n ) : (\n <MenuItem key={item.id} item={item} panelId={`${idPrefix}-panel-${item.id}`} />\n ),\n )}\n </ul>\n </NavController>\n <div {...slot(classes, 'actions')}>\n {/* The phone sits beside the quote button with its icon on the left; its name is its visible text. */}\n <PhoneLink\n phone={phone}\n placement=\"header\"\n label={phoneLabel}\n showIcon\n variant={callFirst ? 'button' : 'text'}\n classes={{ root: classes?.phone, icon: classes?.phoneIcon, label: classes?.phoneLabel, number: classes?.phoneNumber }}\n />\n <QuoteButton\n label={quote.label}\n href={quote.href}\n placement=\"header\"\n ctaId=\"quote-header\"\n classes={{ root: classes?.quote, label: classes?.quoteLabel, icon: classes?.quoteIcon }}\n />\n <MobileDrawer\n {...drawer}\n classes={{\n ...drawer?.classes,\n menuButton: cx(drawer?.classes?.menuButton, classes?.menuButton),\n menuLabel: cx(drawer?.classes?.menuLabel, classes?.menuLabel),\n }}\n navigation={navigation}\n phone={phone}\n phoneLabel={phoneLabel}\n quote={quote}\n socials={socials}\n logo={drawerLogo}\n idPrefix={idPrefix}\n />\n </div>\n </div>\n </div>\n </HeaderRoot>\n </>\n )\n}\n\nfunction LinkItem({ item }: { item: BrandlabNavLinkItem }) {\n return (\n <NavItem paths={[item.href, ...(item.activePaths ?? [])]}>\n <CurrentLink href={item.href} slot=\"link\">\n {item.label}\n </CurrentLink>\n </NavItem>\n )\n}\n\nfunction MenuItem({ item, panelId }: { item: BrandlabNavMenuItem; panelId: string }) {\n const groups = item.panel === 'columns' && item.groups && item.groups.length > 0 ? item.groups : undefined\n // A columns panel never drops a link: links outside every group follow in a last group without a heading.\n const grouped = new Set(groups?.flatMap((group) => group.links.map((link) => link.href)))\n const ungrouped = groups ? item.links.filter((link) => !grouped.has(link.href)) : []\n const columnCount = groups ? groups.length + (ungrouped.length > 0 ? 1 : 0) : 0\n return (\n <NavItem menuId={item.id} paths={[item.href, ...(item.activePaths ?? [])]}>\n <span {...repeatedSlot('itemRow')}>\n <CurrentLink href={item.href} slot=\"link\">\n {item.label}\n </CurrentLink>\n <NavTrigger menuId={item.id} panelId={panelId} label={item.label}>\n <Icon name=\"chevron\" />\n </NavTrigger>\n </span>\n <NavPanel\n menuId={item.id}\n panelId={panelId}\n variant={item.panel}\n columns={groups ? Math.min(3, Math.max(2, columnCount)) : undefined}\n \n >\n <div {...repeatedSlot('panelBody')}>\n {item.panel === 'featured' && item.featured ? (\n <CurrentLink href={item.featured.href} slot=\"featured\" prefetch={false}>\n <span {...repeatedSlot('featuredMedia')}>\n <Image\n src={item.featured.image.src}\n alt={item.featured.image.alt}\n width={item.featured.image.width}\n height={item.featured.image.height}\n sizes=\"240px\"\n />\n </span>\n <span {...repeatedSlot('featuredLabel')}>{item.featured.label}</span>\n <span {...repeatedSlot('featuredText')}>{item.featured.description}</span>\n </CurrentLink>\n ) : null}\n {/* Every panel repeats its hub link first. */}\n <ul {...repeatedSlot('panelList')}>\n <li>\n <CurrentLink href={item.href} slot=\"panelLink\" hub prefetch={false}>\n <span {...repeatedSlot('panelLabel')}>{item.hubLabel}</span>\n <Icon name=\"arrow\" />\n </CurrentLink>\n </li>\n {groups ? null : item.links.map((link) => <PanelLink key={link.href} link={link} />)}\n </ul>\n {groups?.map((group) => (\n <div key={group.heading} {...repeatedSlot('panelGroup')}>\n <p {...repeatedSlot('panelHeading')}>{group.heading}</p>\n <ul {...repeatedSlot('panelList')}>\n {group.links.map((link) => (\n <PanelLink key={link.href} link={link} />\n ))}\n </ul>\n </div>\n ))}\n {ungrouped.length > 0 ? (\n <div {...repeatedSlot('panelGroup')}>\n <ul {...repeatedSlot('panelList')}>\n {ungrouped.map((link) => (\n <PanelLink key={link.href} link={link} />\n ))}\n </ul>\n </div>\n ) : null}\n </div>\n </NavPanel>\n </NavItem>\n )\n}\n\nfunction PanelLink({ link }: { link: BrandlabNavMenuItem['links'][number] }) {\n return (\n <li>\n <CurrentLink href={link.href} slot=\"panelLink\" prefetch={false}>\n <span {...repeatedSlot('panelLabel')}>{link.label}</span>\n {link.description ? <span {...repeatedSlot('panelText')}>{link.description}</span> : null}\n </CurrentLink>\n </li>\n )\n}\n"]}
1
+ {"version":3,"file":"site-header.js","sourceRoot":"","sources":["../../../src/ui-kit/shell/site-header.tsx"],"names":[],"mappings":"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","sourcesContent":["/**\n * F2: the header shell (server component). The same structure on every site: the skip link, the optional utility\n * bar, then a sticky, solid `<header>` holding the logo, the menu, the phone and the quote button. Layout follows the\n * header's own width (container queries): from 1200 px the full menu; from 1024 to 1199 px a compact band with the\n * phone and its number, the quote button and a Menu button; below 1024 px the logo, a 44 px call button and a 44 px\n * Menu button. Every menu, hub and panel link is an `<a href>` in the server HTML (F3); client leaves only change\n * state.\n */\nimport type { BrandlabNavigation, BrandlabNavLinkItem, BrandlabNavMenuItem } from '@brandlab-digital/site-core/navigation'\nimport Image from 'next/image'\nimport type { ReactNode } from 'react'\nimport { SkipLink } from '../../ui.js'\nimport { MAIN_CONTENT_ID } from '../../navigation/constants.js'\nimport { Icon } from '../icons.js'\nimport { PhoneLink } from '../primitives/links.js'\nimport { ShellQuoteButton } from './shell-quote.js'\nimport type { RepeatedSlotOf } from '../repeated-slots.js'\nimport { cx, repeatedSlot, slot, type SkinEntry } from '../skin.js'\nimport type { UiPhone, UiSocial } from '../types.js'\nimport { CurrentLink, LogoLink } from './current-link.js'\nimport { HeaderRoot, NavController, NavItem, NavPanel, NavTrigger } from './header-client.js'\nimport { MobileDrawer, type MobileDrawerSkin, type ShellQuote } from './mobile-drawer.js'\n\nexport type SiteHeaderSlot =\n | 'skip'\n | 'root'\n | 'bar'\n | 'inner'\n | 'logo'\n | 'nav'\n | 'list'\n | 'item'\n | 'itemRow'\n | 'link'\n | 'trigger'\n | 'panel'\n | 'panelBody'\n | 'panelList'\n | 'panelGroup'\n | 'panelHeading'\n | 'panelLink'\n | 'panelLabel'\n | 'panelText'\n | 'featured'\n | 'featuredMedia'\n | 'featuredLabel'\n | 'featuredText'\n | 'actions'\n | 'phone'\n | 'phoneIcon'\n | 'phoneLabel'\n | 'phoneNumber'\n | 'quote'\n | 'quoteLabel'\n | 'quoteIcon'\n | 'menuButton'\n | 'menuLabel'\nexport const SITE_HEADER_VARIANTS = ['standard', 'call-first'] as const\n/**\n * `call-first` (recorded exceptions, v1 §9.10): the phone is the primary action (a button with its number at every\n * width); the quote button still follows it, as on `standard`.\n */\nexport type SiteHeaderVariant = (typeof SITE_HEADER_VARIANTS)[number]\nexport interface SiteHeaderLayout {\n /** Where the menu sits between the logo and the actions. */\n readonly navAlign?: 'center' | 'end'\n /** Compact the header (`data-compact=\"true\"`) once the page has scrolled 80 px. It never hides. */\n readonly compactAfterScroll?: boolean\n}\n/** Rendered once per menu item or panel link: styled from the skin stylesheet, never by class (3.14.0). */\nexport type SiteHeaderRepeatedSlot = RepeatedSlotOf<'siteHeader'>\nexport type SiteHeaderSkin = SkinEntry<SiteHeaderSlot, SiteHeaderVariant, SiteHeaderLayout, SiteHeaderRepeatedSlot>\n\nexport interface SiteHeaderProps extends SiteHeaderSkin {\n readonly navigation: BrandlabNavigation\n /** The logo link's accessible name. */\n readonly brandName: string\n readonly homeHref: string\n readonly logo: ReactNode\n /** From the derived business facts, never typed by hand. */\n readonly phone: UiPhone\n /** The small line above the number, for example \"Call us\". Also leads the drawer's Call button. */\n readonly phoneLabel?: string | undefined\n readonly quote: ShellQuote\n readonly socials?: readonly UiSocial[] | undefined\n /** The site's skip-link text, for example \"Skip to main content\". It targets `#main`. */\n readonly skipLabel: string\n /** The optional utility bar (`<UtilityBar>`), placed between the skip link and the header. */\n readonly utility?: ReactNode\n /** The site's `mobileDrawer` skin entry. */\n readonly drawer?: MobileDrawerSkin | undefined\n /** An optional logo for the drawer's top bar. */\n readonly drawerLogo?: ReactNode\n /** Prefix for element ids; one per header on the page. */\n readonly idPrefix?: string | undefined\n}\n\nexport function SiteHeader({\n navigation,\n brandName,\n homeHref,\n logo,\n phone,\n phoneLabel,\n quote,\n socials,\n skipLabel,\n utility,\n drawer,\n drawerLogo,\n idPrefix = 'bl-header',\n variant = 'standard',\n layout,\n classes,\n}: SiteHeaderProps) {\n const callFirst = variant === 'call-first'\n return (\n <>\n <SkipLink targetId={MAIN_CONTENT_ID} data-bl=\"skip\" className={classes?.skip}>\n {skipLabel}\n </SkipLink>\n {utility}\n <HeaderRoot\n variant={variant}\n navAlign={layout?.navAlign ?? 'center'}\n compactAfterScroll={layout?.compactAfterScroll ?? false}\n className={classes?.root}\n >\n <div {...slot(classes, 'bar')}>\n <div {...slot(classes, 'inner')}>\n <LogoLink href={homeHref} label={brandName} slot=\"logo\" className={classes?.logo}>\n {logo}\n </LogoLink>\n <NavController label=\"Main\" className={classes?.nav}>\n <ul {...slot(classes, 'list')}>\n {navigation.items.map((item) =>\n item.kind === 'link' ? (\n <LinkItem key={item.id} item={item} />\n ) : (\n <MenuItem key={item.id} item={item} panelId={`${idPrefix}-panel-${item.id}`} />\n ),\n )}\n </ul>\n </NavController>\n <div {...slot(classes, 'actions')}>\n {/* The phone sits beside the quote button with its icon on the left; its name is its visible text. */}\n <PhoneLink\n phone={phone}\n placement=\"header\"\n label={phoneLabel}\n showIcon\n variant={callFirst ? 'button' : 'text'}\n classes={{ root: classes?.phone, icon: classes?.phoneIcon, label: classes?.phoneLabel, number: classes?.phoneNumber }}\n />\n <ShellQuoteButton\n label={quote.label}\n href={quote.href}\n placement=\"header\"\n ctaId=\"quote-header\"\n classes={{ root: classes?.quote, label: classes?.quoteLabel, icon: classes?.quoteIcon }}\n />\n <MobileDrawer\n {...drawer}\n classes={{\n ...drawer?.classes,\n menuButton: cx(drawer?.classes?.menuButton, classes?.menuButton),\n menuLabel: cx(drawer?.classes?.menuLabel, classes?.menuLabel),\n }}\n navigation={navigation}\n phone={phone}\n phoneLabel={phoneLabel}\n quote={quote}\n socials={socials}\n logo={drawerLogo}\n idPrefix={idPrefix}\n />\n </div>\n </div>\n </div>\n </HeaderRoot>\n </>\n )\n}\n\nfunction LinkItem({ item }: { item: BrandlabNavLinkItem }) {\n return (\n <NavItem paths={[item.href, ...(item.activePaths ?? [])]}>\n <CurrentLink href={item.href} slot=\"link\" prefetch=\"intent\">\n {item.label}\n </CurrentLink>\n </NavItem>\n )\n}\n\nfunction MenuItem({ item, panelId }: { item: BrandlabNavMenuItem; panelId: string }) {\n const groups = item.panel === 'columns' && item.groups && item.groups.length > 0 ? item.groups : undefined\n // A columns panel never drops a link: links outside every group follow in a last group without a heading.\n const grouped = new Set(groups?.flatMap((group) => group.links.map((link) => link.href)))\n const ungrouped = groups ? item.links.filter((link) => !grouped.has(link.href)) : []\n const columnCount = groups ? groups.length + (ungrouped.length > 0 ? 1 : 0) : 0\n return (\n <NavItem menuId={item.id} paths={[item.href, ...(item.activePaths ?? [])]}>\n <span {...repeatedSlot('itemRow')}>\n <CurrentLink href={item.href} slot=\"link\" prefetch=\"intent\">\n {item.label}\n </CurrentLink>\n <NavTrigger menuId={item.id} panelId={panelId} label={item.label}>\n <Icon name=\"chevron\" />\n </NavTrigger>\n </span>\n <NavPanel\n menuId={item.id}\n panelId={panelId}\n variant={item.panel}\n columns={groups ? Math.min(3, Math.max(2, columnCount)) : undefined}\n \n >\n <div {...repeatedSlot('panelBody')}>\n {item.panel === 'featured' && item.featured ? (\n <CurrentLink href={item.featured.href} slot=\"featured\" prefetch={false}>\n <span {...repeatedSlot('featuredMedia')}>\n <Image\n src={item.featured.image.src}\n alt={item.featured.image.alt}\n width={item.featured.image.width}\n height={item.featured.image.height}\n sizes=\"240px\"\n />\n </span>\n <span {...repeatedSlot('featuredLabel')}>{item.featured.label}</span>\n <span {...repeatedSlot('featuredText')}>{item.featured.description}</span>\n </CurrentLink>\n ) : null}\n {/* Every panel repeats its hub link first. */}\n <ul {...repeatedSlot('panelList')}>\n <li>\n <CurrentLink href={item.href} slot=\"panelLink\" hub prefetch={false}>\n <span {...repeatedSlot('panelLabel')}>{item.hubLabel}</span>\n <Icon name=\"arrow\" />\n </CurrentLink>\n </li>\n {groups ? null : item.links.map((link) => <PanelLink key={link.href} link={link} />)}\n </ul>\n {groups?.map((group) => (\n <div key={group.heading} {...repeatedSlot('panelGroup')}>\n <p {...repeatedSlot('panelHeading')}>{group.heading}</p>\n <ul {...repeatedSlot('panelList')}>\n {group.links.map((link) => (\n <PanelLink key={link.href} link={link} />\n ))}\n </ul>\n </div>\n ))}\n {ungrouped.length > 0 ? (\n <div {...repeatedSlot('panelGroup')}>\n <ul {...repeatedSlot('panelList')}>\n {ungrouped.map((link) => (\n <PanelLink key={link.href} link={link} />\n ))}\n </ul>\n </div>\n ) : null}\n </div>\n </NavPanel>\n </NavItem>\n )\n}\n\nfunction PanelLink({ link }: { link: BrandlabNavMenuItem['links'][number] }) {\n return (\n <li>\n <CurrentLink href={link.href} slot=\"panelLink\" prefetch={false}>\n <span {...repeatedSlot('panelLabel')}>{link.label}</span>\n {link.description ? <span {...repeatedSlot('panelText')}>{link.description}</span> : null}\n </CurrentLink>\n </li>\n )\n}\n"]}