@brandlab-digital/site-next 3.8.0 → 3.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. package/dist/instrumentation-client.d.ts +23 -4
  2. package/dist/instrumentation-client.d.ts.map +1 -1
  3. package/dist/instrumentation-client.js +65 -3
  4. package/dist/instrumentation-client.js.map +1 -1
  5. package/dist/navigation/constants.d.ts +25 -0
  6. package/dist/navigation/constants.d.ts.map +1 -0
  7. package/dist/navigation/constants.js +30 -0
  8. package/dist/navigation/constants.js.map +1 -0
  9. package/dist/navigation/index.d.ts +11 -0
  10. package/dist/navigation/index.d.ts.map +1 -0
  11. package/dist/navigation/index.js +11 -0
  12. package/dist/navigation/index.js.map +1 -0
  13. package/dist/navigation/use-back-to-top.d.ts +5 -0
  14. package/dist/navigation/use-back-to-top.d.ts.map +1 -0
  15. package/dist/navigation/use-back-to-top.js +32 -0
  16. package/dist/navigation/use-back-to-top.js.map +1 -0
  17. package/dist/navigation/use-header-metrics.d.ts +17 -0
  18. package/dist/navigation/use-header-metrics.d.ts.map +1 -0
  19. package/dist/navigation/use-header-metrics.js +52 -0
  20. package/dist/navigation/use-header-metrics.js.map +1 -0
  21. package/dist/navigation/use-navigation-menu.d.ts +39 -0
  22. package/dist/navigation/use-navigation-menu.d.ts.map +1 -0
  23. package/dist/navigation/use-navigation-menu.js +206 -0
  24. package/dist/navigation/use-navigation-menu.js.map +1 -0
  25. package/dist/navigation/use-sticky-call-bar.d.ts +15 -0
  26. package/dist/navigation/use-sticky-call-bar.d.ts.map +1 -0
  27. package/dist/navigation/use-sticky-call-bar.js +110 -0
  28. package/dist/navigation/use-sticky-call-bar.js.map +1 -0
  29. package/dist/ui-kit/brandlab-skin.d.ts +10 -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/shell/back-to-top-client.d.ts +9 -0
  33. package/dist/ui-kit/shell/back-to-top-client.d.ts.map +1 -0
  34. package/dist/ui-kit/shell/back-to-top-client.js +8 -0
  35. package/dist/ui-kit/shell/back-to-top-client.js.map +1 -0
  36. package/dist/ui-kit/shell/back-to-top.d.ts +13 -0
  37. package/dist/ui-kit/shell/back-to-top.d.ts.map +1 -0
  38. package/dist/ui-kit/shell/back-to-top.js +14 -0
  39. package/dist/ui-kit/shell/back-to-top.js.map +1 -0
  40. package/dist/ui-kit/shell/call-bar-client.d.ts +7 -0
  41. package/dist/ui-kit/shell/call-bar-client.d.ts.map +1 -0
  42. package/dist/ui-kit/shell/call-bar-client.js +13 -0
  43. package/dist/ui-kit/shell/call-bar-client.js.map +1 -0
  44. package/dist/ui-kit/shell/current-link.d.ts +15 -0
  45. package/dist/ui-kit/shell/current-link.d.ts.map +1 -0
  46. package/dist/ui-kit/shell/current-link.js +34 -0
  47. package/dist/ui-kit/shell/current-link.js.map +1 -0
  48. package/dist/ui-kit/shell/drawer-client.d.ts +22 -0
  49. package/dist/ui-kit/shell/drawer-client.d.ts.map +1 -0
  50. package/dist/ui-kit/shell/drawer-client.js +70 -0
  51. package/dist/ui-kit/shell/drawer-client.js.map +1 -0
  52. package/dist/ui-kit/shell/header-client.d.ts +44 -0
  53. package/dist/ui-kit/shell/header-client.d.ts.map +1 -0
  54. package/dist/ui-kit/shell/header-client.js +59 -0
  55. package/dist/ui-kit/shell/header-client.js.map +1 -0
  56. package/dist/ui-kit/shell/index.d.ts +6 -0
  57. package/dist/ui-kit/shell/index.d.ts.map +1 -0
  58. package/dist/ui-kit/shell/index.js +6 -0
  59. package/dist/ui-kit/shell/index.js.map +1 -0
  60. package/dist/ui-kit/shell/mobile-call-bar.d.ts +16 -0
  61. package/dist/ui-kit/shell/mobile-call-bar.d.ts.map +1 -0
  62. package/dist/ui-kit/shell/mobile-call-bar.js +15 -0
  63. package/dist/ui-kit/shell/mobile-call-bar.js.map +1 -0
  64. package/dist/ui-kit/shell/mobile-drawer.d.ts +37 -0
  65. package/dist/ui-kit/shell/mobile-drawer.d.ts.map +1 -0
  66. package/dist/ui-kit/shell/mobile-drawer.js +25 -0
  67. package/dist/ui-kit/shell/mobile-drawer.js.map +1 -0
  68. package/dist/ui-kit/shell/shell-context.d.ts +3 -0
  69. package/dist/ui-kit/shell/shell-context.d.ts.map +1 -0
  70. package/dist/ui-kit/shell/shell-context.js +5 -0
  71. package/dist/ui-kit/shell/shell-context.js.map +1 -0
  72. package/dist/ui-kit/shell/site-header.d.ts +52 -0
  73. package/dist/ui-kit/shell/site-header.d.ts.map +1 -0
  74. package/dist/ui-kit/shell/site-header.js +36 -0
  75. package/dist/ui-kit/shell/site-header.js.map +1 -0
  76. package/dist/ui-kit/shell/social-links.d.ts +8 -0
  77. package/dist/ui-kit/shell/social-links.d.ts.map +1 -0
  78. package/dist/ui-kit/shell/social-links.js +9 -0
  79. package/dist/ui-kit/shell/social-links.js.map +1 -0
  80. package/dist/ui-kit/shell/utility-bar.d.ts +30 -0
  81. package/dist/ui-kit/shell/utility-bar.d.ts.map +1 -0
  82. package/dist/ui-kit/shell/utility-bar.js +15 -0
  83. package/dist/ui-kit/shell/utility-bar.js.map +1 -0
  84. package/dist/ui-kit/structure.css +594 -0
  85. package/package.json +10 -2
@@ -0,0 +1,22 @@
1
+ import { type ReactNode } from 'react';
2
+ export interface DrawerControllerClasses {
3
+ readonly root?: string | undefined;
4
+ readonly menuButton?: string | undefined;
5
+ readonly menuLabel?: string | undefined;
6
+ readonly panel?: string | undefined;
7
+ readonly top?: string | undefined;
8
+ readonly close?: string | undefined;
9
+ readonly title?: string | undefined;
10
+ readonly logo?: string | undefined;
11
+ }
12
+ export declare function DrawerController({ id, variant, side, classes, logo, menuIcon, closeIcon, children, }: {
13
+ readonly id: string;
14
+ readonly variant: string;
15
+ readonly side: string;
16
+ readonly classes: DrawerControllerClasses;
17
+ readonly logo?: ReactNode;
18
+ readonly menuIcon: ReactNode;
19
+ readonly closeIcon: ReactNode;
20
+ readonly children: ReactNode;
21
+ }): import("react/jsx-runtime").JSX.Element;
22
+ //# sourceMappingURL=drawer-client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"drawer-client.d.ts","sourceRoot":"","sources":["../../../src/ui-kit/shell/drawer-client.tsx"],"names":[],"mappings":"AAUA,OAAO,EAAwD,KAAK,SAAS,EAAE,MAAM,OAAO,CAAA;AAG5F,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAClC,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IACxC,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IACvC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IACnC,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IACjC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IACnC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IACnC,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CACnC;AAED,wBAAgB,gBAAgB,CAAC,EAC/B,EAAE,EACF,OAAO,EACP,IAAI,EACJ,OAAO,EACP,IAAI,EACJ,QAAQ,EACR,SAAS,EACT,QAAQ,GACT,EAAE;IACD,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,OAAO,EAAE,uBAAuB,CAAA;IACzC,QAAQ,CAAC,IAAI,CAAC,EAAE,SAAS,CAAA;IACzB,QAAQ,CAAC,QAAQ,EAAE,SAAS,CAAA;IAC5B,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAA;IAC7B,QAAQ,CAAC,QAAQ,EAAE,SAAS,CAAA;CAC7B,2CAkGA"}
@@ -0,0 +1,70 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
+ /**
4
+ * The drawer's client leaf: the Menu button and the modal `<dialog>` (top layer, the page inert, focus kept inside).
5
+ * The menu, the actions and the social links are server-rendered children. The drawer closes on Escape, the close
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
8
+ * toggle listener below keeps that rule in browsers without exclusive `<details>`.
9
+ */
10
+ import { usePathname } from 'next/navigation';
11
+ import { useCallback, useContext, useEffect, useRef, useState } from 'react';
12
+ import { HeaderModeContext } from './shell-context.js';
13
+ export function DrawerController({ id, variant, side, classes, logo, menuIcon, closeIcon, children, }) {
14
+ const pathname = usePathname();
15
+ const mode = useContext(HeaderModeContext);
16
+ const dialogRef = useRef(null);
17
+ const buttonRef = useRef(null);
18
+ const closeRef = useRef(null);
19
+ const [open, setOpen] = useState(false);
20
+ const titleId = `${id}-title`;
21
+ const close = useCallback(() => {
22
+ const dialog = dialogRef.current;
23
+ if (dialog?.open)
24
+ dialog.close();
25
+ }, []);
26
+ const show = () => {
27
+ const dialog = dialogRef.current;
28
+ if (!dialog || dialog.open)
29
+ return;
30
+ for (const group of dialog.querySelectorAll('details[open]'))
31
+ group.open = false;
32
+ dialog.showModal();
33
+ // The close button comes first in focus order and takes focus when the drawer opens.
34
+ closeRef.current?.focus();
35
+ setOpen(true);
36
+ };
37
+ // A route change or a mode change (breakpoint crossing) resets the drawer.
38
+ useEffect(() => {
39
+ close();
40
+ }, [pathname, mode, close]);
41
+ useEffect(() => {
42
+ const dialog = dialogRef.current;
43
+ if (!dialog)
44
+ return;
45
+ const onToggle = (event) => {
46
+ const opened = event.target;
47
+ if (!(opened instanceof HTMLDetailsElement) || !opened.open)
48
+ return;
49
+ for (const other of dialog.querySelectorAll('details[open]'))
50
+ if (other !== opened)
51
+ other.open = false;
52
+ };
53
+ dialog.addEventListener('toggle', onToggle, true);
54
+ return () => dialog.removeEventListener('toggle', onToggle, true);
55
+ }, []);
56
+ return (_jsxs(_Fragment, { children: [_jsxs("button", { ref: buttonRef, type: "button", "data-slot": "menuButton", "aria-haspopup": "dialog", "aria-expanded": open, "aria-controls": id, className: classes.menuButton, onClick: show, children: [menuIcon, _jsx("span", { "data-slot": "menuLabel", className: classes.menuLabel, children: "Menu" })] }), _jsx("dialog", { ref: dialogRef, id: id, "data-bl": "drawer", "data-variant": variant, "data-side": side, "aria-labelledby": titleId, className: classes.root, ...{ closedby: 'any' }, onClose: () => {
57
+ setOpen(false);
58
+ // Safari doesn't focus a clicked button, so the dialog may have nothing to return focus to.
59
+ const active = document.activeElement;
60
+ if (!active || active === document.body || dialogRef.current?.contains(active))
61
+ buttonRef.current?.focus();
62
+ }, onClick: (event) => {
63
+ // A tap on the backdrop (where closedby="any" isn't supported yet) or on any link closes the drawer.
64
+ if (event.target === dialogRef.current)
65
+ close();
66
+ else if (event.target.closest('a[href]'))
67
+ close();
68
+ }, children: _jsxs("div", { "data-slot": "panel", className: classes.panel, children: [_jsxs("div", { "data-slot": "top", className: classes.top, children: [_jsx("button", { ref: closeRef, type: "button", "data-slot": "close", "aria-label": "Close menu", className: classes.close, onClick: close, children: closeIcon }), _jsx("p", { id: titleId, "data-slot": "title", className: classes.title, children: "Menu" }), logo ? (_jsx("span", { "data-slot": "logo", "aria-hidden": "true", className: classes.logo, children: logo })) : null] }), children] }) })] }));
69
+ }
70
+ //# sourceMappingURL=drawer-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"drawer-client.js","sourceRoot":"","sources":["../../../src/ui-kit/shell/drawer-client.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAA;;AAEZ;;;;;;GAMG;AACH,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAA;AAC7C,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAkB,MAAM,OAAO,CAAA;AAC5F,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAA;AAatD,MAAM,UAAU,gBAAgB,CAAC,EAC/B,EAAE,EACF,OAAO,EACP,IAAI,EACJ,OAAO,EACP,IAAI,EACJ,QAAQ,EACR,SAAS,EACT,QAAQ,GAUT;IACC,MAAM,QAAQ,GAAG,WAAW,EAAE,CAAA;IAC9B,MAAM,IAAI,GAAG,UAAU,CAAC,iBAAiB,CAAC,CAAA;IAC1C,MAAM,SAAS,GAAG,MAAM,CAAoB,IAAI,CAAC,CAAA;IACjD,MAAM,SAAS,GAAG,MAAM,CAAoB,IAAI,CAAC,CAAA;IACjD,MAAM,QAAQ,GAAG,MAAM,CAAoB,IAAI,CAAC,CAAA;IAChD,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAA;IACvC,MAAM,OAAO,GAAG,GAAG,EAAE,QAAQ,CAAA;IAE7B,MAAM,KAAK,GAAG,WAAW,CAAC,GAAG,EAAE;QAC7B,MAAM,MAAM,GAAG,SAAS,CAAC,OAAO,CAAA;QAChC,IAAI,MAAM,EAAE,IAAI;YAAE,MAAM,CAAC,KAAK,EAAE,CAAA;IAClC,CAAC,EAAE,EAAE,CAAC,CAAA;IAEN,MAAM,IAAI,GAAG,GAAG,EAAE;QAChB,MAAM,MAAM,GAAG,SAAS,CAAC,OAAO,CAAA;QAChC,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,IAAI;YAAE,OAAM;QAClC,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,gBAAgB,CAAqB,eAAe,CAAC;YAAE,KAAK,CAAC,IAAI,GAAG,KAAK,CAAA;QACpG,MAAM,CAAC,SAAS,EAAE,CAAA;QAClB,qFAAqF;QACrF,QAAQ,CAAC,OAAO,EAAE,KAAK,EAAE,CAAA;QACzB,OAAO,CAAC,IAAI,CAAC,CAAA;IACf,CAAC,CAAA;IAED,2EAA2E;IAC3E,SAAS,CAAC,GAAG,EAAE;QACb,KAAK,EAAE,CAAA;IACT,CAAC,EAAE,CAAC,QAAQ,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC,CAAA;IAE3B,SAAS,CAAC,GAAG,EAAE;QACb,MAAM,MAAM,GAAG,SAAS,CAAC,OAAO,CAAA;QAChC,IAAI,CAAC,MAAM;YAAE,OAAM;QACnB,MAAM,QAAQ,GAAG,CAAC,KAAY,EAAE,EAAE;YAChC,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,CAAA;YAC3B,IAAI,CAAC,CAAC,MAAM,YAAY,kBAAkB,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI;gBAAE,OAAM;YACnE,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,gBAAgB,CAAqB,eAAe,CAAC;gBAAE,IAAI,KAAK,KAAK,MAAM;oBAAE,KAAK,CAAC,IAAI,GAAG,KAAK,CAAA;QAC5H,CAAC,CAAA;QACD,MAAM,CAAC,gBAAgB,CAAC,QAAQ,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAA;QACjD,OAAO,GAAG,EAAE,CAAC,MAAM,CAAC,mBAAmB,CAAC,QAAQ,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAA;IACnE,CAAC,EAAE,EAAE,CAAC,CAAA;IAEN,OAAO,CACL,8BACE,kBACE,GAAG,EAAE,SAAS,EACd,IAAI,EAAC,QAAQ,eACH,YAAY,mBACR,QAAQ,mBACP,IAAI,mBACJ,EAAE,EACjB,SAAS,EAAE,OAAO,CAAC,UAAU,EAC7B,OAAO,EAAE,IAAI,aAEZ,QAAQ,EACT,4BAAgB,WAAW,EAAC,SAAS,EAAE,OAAO,CAAC,SAAS,qBAEjD,IACA,EACT,iBACE,GAAG,EAAE,SAAS,EACd,EAAE,EAAE,EAAE,aACE,QAAQ,kBACF,OAAO,eACV,IAAI,qBACE,OAAO,EACxB,SAAS,EAAE,OAAO,CAAC,IAAI,KAClB,EAAE,QAAQ,EAAE,KAAK,EAA6B,EACnD,OAAO,EAAE,GAAG,EAAE;oBACZ,OAAO,CAAC,KAAK,CAAC,CAAA;oBACd,4FAA4F;oBAC5F,MAAM,MAAM,GAAG,QAAQ,CAAC,aAAa,CAAA;oBACrC,IAAI,CAAC,MAAM,IAAI,MAAM,KAAK,QAAQ,CAAC,IAAI,IAAI,SAAS,CAAC,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC;wBAAE,SAAS,CAAC,OAAO,EAAE,KAAK,EAAE,CAAA;gBAC5G,CAAC,EACD,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE;oBACjB,qGAAqG;oBACrG,IAAI,KAAK,CAAC,MAAM,KAAK,SAAS,CAAC,OAAO;wBAAE,KAAK,EAAE,CAAA;yBAC1C,IAAK,KAAK,CAAC,MAAkB,CAAC,OAAO,CAAC,SAAS,CAAC;wBAAE,KAAK,EAAE,CAAA;gBAChE,CAAC,YAED,4BAAe,OAAO,EAAC,SAAS,EAAE,OAAO,CAAC,KAAK,aAC7C,4BAAe,KAAK,EAAC,SAAS,EAAE,OAAO,CAAC,GAAG,aACzC,iBAAQ,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAC,QAAQ,eAAW,OAAO,gBAAY,YAAY,EAAC,SAAS,EAAE,OAAO,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,YACpH,SAAS,GACH,EACT,YAAG,EAAE,EAAE,OAAO,eAAY,OAAO,EAAC,SAAS,EAAE,OAAO,CAAC,KAAK,qBAEtD,EACH,IAAI,CAAC,CAAC,CAAC,CACN,4BAAgB,MAAM,iBAAa,MAAM,EAAC,SAAS,EAAE,OAAO,CAAC,IAAI,YAC9D,IAAI,GACA,CACR,CAAC,CAAC,CAAC,IAAI,IACJ,EACL,QAAQ,IACL,GACC,IACR,CACJ,CAAA;AACH,CAAC","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"]}
@@ -0,0 +1,44 @@
1
+ import { type ReactNode } from 'react';
2
+ /** The `<header>` root: measures the header (mode, height, compact) and shares its mode. */
3
+ export declare function HeaderRoot({ variant, navAlign, compactAfterScroll, className, children, }: {
4
+ readonly variant: string;
5
+ readonly navAlign: string;
6
+ readonly compactAfterScroll: boolean;
7
+ readonly className?: string | undefined;
8
+ readonly children: ReactNode;
9
+ }): import("react/jsx-runtime").JSX.Element;
10
+ /** The `<nav>` landmark and the menu state (F3 engine) for the items inside it. */
11
+ export declare function NavController({ label, className, children }: {
12
+ readonly label: string;
13
+ readonly className?: string | undefined;
14
+ readonly children: ReactNode;
15
+ }): import("react/jsx-runtime").JSX.Element;
16
+ /**
17
+ * One top-level item. `data-current` marks the current section: the page is the item's hub or one of its active
18
+ * paths (or below them), or one of its panel links is the current page.
19
+ */
20
+ export declare function NavItem({ menuId, paths, className, children, }: {
21
+ /** Set for an item with a panel. */
22
+ readonly menuId?: string;
23
+ readonly paths: readonly string[];
24
+ readonly className?: string | undefined;
25
+ readonly children: ReactNode;
26
+ }): import("react/jsx-runtime").JSX.Element;
27
+ /** The disclosure button beside an item's hub link, named "{label} menu". */
28
+ export declare function NavTrigger({ menuId, panelId, label, className, children, }: {
29
+ readonly menuId: string;
30
+ readonly panelId: string;
31
+ readonly label: string;
32
+ readonly className?: string | undefined;
33
+ readonly children: ReactNode;
34
+ }): import("react/jsx-runtime").JSX.Element;
35
+ /** The panel box. Its links are the server-rendered children; the panel only changes state. */
36
+ export declare function NavPanel({ menuId, panelId, variant, columns, className, children, }: {
37
+ readonly menuId: string;
38
+ readonly panelId: string;
39
+ readonly variant: string;
40
+ readonly columns?: number | undefined;
41
+ readonly className?: string | undefined;
42
+ readonly children: ReactNode;
43
+ }): import("react/jsx-runtime").JSX.Element;
44
+ //# sourceMappingURL=header-client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"header-client.d.ts","sourceRoot":"","sources":["../../../src/ui-kit/shell/header-client.tsx"],"names":[],"mappings":"AASA,OAAO,EAA0D,KAAK,SAAS,EAAE,MAAM,OAAO,CAAA;AAM9F,4FAA4F;AAC5F,wBAAgB,UAAU,CAAC,EACzB,OAAO,EACP,QAAQ,EACR,kBAAkB,EAClB,SAAS,EACT,QAAQ,GACT,EAAE;IACD,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,QAAQ,CAAC,kBAAkB,EAAE,OAAO,CAAA;IACpC,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IACvC,QAAQ,CAAC,QAAQ,EAAE,SAAS,CAAA;CAC7B,2CAQA;AASD,mFAAmF;AACnF,wBAAgB,aAAa,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,EAAE;IAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,SAAS,CAAA;CAAE,2CAY9J;AAED;;;GAGG;AACH,wBAAgB,OAAO,CAAC,EACtB,MAAM,EACN,KAAK,EACL,SAAS,EACT,QAAQ,GACT,EAAE;IACD,oCAAoC;IACpC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAA;IACjC,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IACvC,QAAQ,CAAC,QAAQ,EAAE,SAAS,CAAA;CAC7B,2CAuBA;AAED,6EAA6E;AAC7E,wBAAgB,UAAU,CAAC,EACzB,MAAM,EACN,OAAO,EACP,KAAK,EACL,SAAS,EACT,QAAQ,GACT,EAAE;IACD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IACvC,QAAQ,CAAC,QAAQ,EAAE,SAAS,CAAA;CAC7B,2CAgBA;AAED,+FAA+F;AAC/F,wBAAgB,QAAQ,CAAC,EACvB,MAAM,EACN,OAAO,EACP,OAAO,EACP,OAAO,EACP,SAAS,EACT,QAAQ,GACT,EAAE;IACD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IACrC,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IACvC,QAAQ,CAAC,QAAQ,EAAE,SAAS,CAAA;CAC7B,2CAkBA"}
@@ -0,0 +1,59 @@
1
+ 'use client';
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ /**
4
+ * The header's client leaves. They receive ids, labels, flags and class strings only; every link and panel is
5
+ * server-rendered and passed in as `children`. The leaves toggle `data-state`, `aria-expanded` and `inert` on those
6
+ * server nodes, so opening a panel never re-renders its links. `inert` is added only after hydration: closed panels
7
+ * are `visibility: hidden` in the server HTML, and inert content would break the pre-hydration hover fallback.
8
+ */
9
+ import { usePathname } from 'next/navigation';
10
+ import { createContext, useContext, useEffect, useRef, useState } from 'react';
11
+ import { useHeaderMetrics } from '../../navigation/use-header-metrics.js';
12
+ import { useNavigationMenu } from '../../navigation/use-navigation-menu.js';
13
+ import { isCurrentSection } from './current-link.js';
14
+ import { HeaderModeContext } from './shell-context.js';
15
+ /** The `<header>` root: measures the header (mode, height, compact) and shares its mode. */
16
+ export function HeaderRoot({ variant, navAlign, compactAfterScroll, className, children, }) {
17
+ const ref = useRef(null);
18
+ const { mode } = useHeaderMetrics(ref, { compactAfterScroll });
19
+ return (_jsx("header", { ref: ref, "data-bl": "header", "data-variant": variant, "data-nav-align": navAlign, className: className, children: _jsx(HeaderModeContext, { value: mode, children: children }) }));
20
+ }
21
+ const NavContext = createContext(null);
22
+ /** The `<nav>` landmark and the menu state (F3 engine) for the items inside it. */
23
+ export function NavController({ label, className, children }) {
24
+ const navRef = useRef(null);
25
+ const pathname = usePathname();
26
+ const mode = useContext(HeaderModeContext);
27
+ const menu = useNavigationMenu(navRef, `${pathname}|${mode}`);
28
+ const [hydrated, setHydrated] = useState(false);
29
+ useEffect(() => setHydrated(true), []);
30
+ return (_jsx("nav", { ref: navRef, "aria-label": label, "data-slot": "nav", className: className, children: _jsx(NavContext, { value: { menu, hydrated }, children: children }) }));
31
+ }
32
+ /**
33
+ * One top-level item. `data-current` marks the current section: the page is the item's hub or one of its active
34
+ * paths (or below them), or one of its panel links is the current page.
35
+ */
36
+ export function NavItem({ menuId, paths, className, children, }) {
37
+ const ref = useRef(null);
38
+ const pathname = usePathname();
39
+ const nav = useContext(NavContext);
40
+ const [panelLinkCurrent, setPanelLinkCurrent] = useState(false);
41
+ useEffect(() => {
42
+ setPanelLinkCurrent(ref.current?.querySelector('[data-slot="panel"] [aria-current="page"]') != null);
43
+ }, [pathname]);
44
+ const current = panelLinkCurrent || isCurrentSection(pathname, paths);
45
+ const open = menuId !== undefined && nav?.menu.openId === menuId;
46
+ return (_jsx("li", { ref: ref, "data-slot": "item", "data-has-panel": menuId !== undefined ? 'true' : undefined, "data-state": menuId !== undefined ? (open ? 'open' : 'closed') : undefined, "data-current": current ? 'true' : undefined, className: className, ...(menuId !== undefined && nav ? nav.menu.itemHandlers(menuId) : {}), children: children }));
47
+ }
48
+ /** The disclosure button beside an item's hub link, named "{label} menu". */
49
+ export function NavTrigger({ menuId, panelId, label, className, children, }) {
50
+ const nav = useContext(NavContext);
51
+ return (_jsx("button", { type: "button", "data-slot": "trigger", "data-menu-id": menuId, "aria-expanded": nav?.menu.openId === menuId, "aria-controls": panelId, "aria-label": `${label} menu`, className: className, ...nav?.menu.triggerHandlers(menuId), children: children }));
52
+ }
53
+ /** The panel box. Its links are the server-rendered children; the panel only changes state. */
54
+ export function NavPanel({ menuId, panelId, variant, columns, className, children, }) {
55
+ const nav = useContext(NavContext);
56
+ const open = nav?.menu.openId === menuId;
57
+ return (_jsx("div", { id: panelId, "data-slot": "panel", "data-menu-id": menuId, "data-variant": variant, "data-columns": columns, "data-state": open ? 'open' : 'closed', inert: Boolean(nav?.hydrated) && !open, className: className, ...nav?.menu.panelHandlers(menuId), children: children }));
58
+ }
59
+ //# sourceMappingURL=header-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"header-client.js","sourceRoot":"","sources":["../../../src/ui-kit/shell/header-client.tsx"],"names":[],"mappings":"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","sourcesContent":["'use client'\n\n/**\n * The header's client leaves. They receive ids, labels, flags and class strings only; every link and panel is\n * server-rendered and passed in as `children`. The leaves toggle `data-state`, `aria-expanded` and `inert` on those\n * server nodes, so opening a panel never re-renders its links. `inert` is added only after hydration: closed panels\n * are `visibility: hidden` in the server HTML, and inert content would break the pre-hydration hover fallback.\n */\nimport { usePathname } from 'next/navigation'\nimport { createContext, useContext, useEffect, useRef, useState, type ReactNode } from 'react'\nimport { useHeaderMetrics } from '../../navigation/use-header-metrics.js'\nimport { useNavigationMenu, type NavigationMenu } from '../../navigation/use-navigation-menu.js'\nimport { isCurrentSection } from './current-link.js'\nimport { HeaderModeContext } from './shell-context.js'\n\n/** The `<header>` root: measures the header (mode, height, compact) and shares its mode. */\nexport function HeaderRoot({\n variant,\n navAlign,\n compactAfterScroll,\n className,\n children,\n}: {\n readonly variant: string\n readonly navAlign: string\n readonly compactAfterScroll: boolean\n readonly className?: string | undefined\n readonly children: ReactNode\n}) {\n const ref = useRef<HTMLElement>(null)\n const { mode } = useHeaderMetrics(ref, { compactAfterScroll })\n return (\n <header ref={ref} data-bl=\"header\" data-variant={variant} data-nav-align={navAlign} className={className}>\n <HeaderModeContext value={mode}>{children}</HeaderModeContext>\n </header>\n )\n}\n\ninterface NavState {\n readonly menu: NavigationMenu\n readonly hydrated: boolean\n}\n\nconst NavContext = createContext<NavState | null>(null)\n\n/** The `<nav>` landmark and the menu state (F3 engine) for the items inside it. */\nexport function NavController({ label, className, children }: { readonly label: string; readonly className?: string | undefined; readonly children: ReactNode }) {\n const navRef = useRef<HTMLElement>(null)\n const pathname = usePathname()\n const mode = useContext(HeaderModeContext)\n const menu = useNavigationMenu(navRef, `${pathname}|${mode}`)\n const [hydrated, setHydrated] = useState(false)\n useEffect(() => setHydrated(true), [])\n return (\n <nav ref={navRef} aria-label={label} data-slot=\"nav\" className={className}>\n <NavContext value={{ menu, hydrated }}>{children}</NavContext>\n </nav>\n )\n}\n\n/**\n * One top-level item. `data-current` marks the current section: the page is the item's hub or one of its active\n * paths (or below them), or one of its panel links is the current page.\n */\nexport function NavItem({\n menuId,\n paths,\n className,\n children,\n}: {\n /** Set for an item with a panel. */\n readonly menuId?: string\n readonly paths: readonly string[]\n readonly className?: string | undefined\n readonly children: ReactNode\n}) {\n const ref = useRef<HTMLLIElement>(null)\n const pathname = usePathname()\n const nav = useContext(NavContext)\n const [panelLinkCurrent, setPanelLinkCurrent] = useState(false)\n useEffect(() => {\n setPanelLinkCurrent(ref.current?.querySelector('[data-slot=\"panel\"] [aria-current=\"page\"]') != null)\n }, [pathname])\n const current = panelLinkCurrent || isCurrentSection(pathname, paths)\n const open = menuId !== undefined && nav?.menu.openId === menuId\n return (\n <li\n ref={ref}\n data-slot=\"item\"\n data-has-panel={menuId !== undefined ? 'true' : undefined}\n data-state={menuId !== undefined ? (open ? 'open' : 'closed') : undefined}\n data-current={current ? 'true' : undefined}\n className={className}\n {...(menuId !== undefined && nav ? nav.menu.itemHandlers(menuId) : {})}\n >\n {children}\n </li>\n )\n}\n\n/** The disclosure button beside an item's hub link, named \"{label} menu\". */\nexport function NavTrigger({\n menuId,\n panelId,\n label,\n className,\n children,\n}: {\n readonly menuId: string\n readonly panelId: string\n readonly label: string\n readonly className?: string | undefined\n readonly children: ReactNode\n}) {\n const nav = useContext(NavContext)\n return (\n <button\n type=\"button\"\n data-slot=\"trigger\"\n data-menu-id={menuId}\n aria-expanded={nav?.menu.openId === menuId}\n aria-controls={panelId}\n aria-label={`${label} menu`}\n className={className}\n {...nav?.menu.triggerHandlers(menuId)}\n >\n {children}\n </button>\n )\n}\n\n/** The panel box. Its links are the server-rendered children; the panel only changes state. */\nexport function NavPanel({\n menuId,\n panelId,\n variant,\n columns,\n className,\n children,\n}: {\n readonly menuId: string\n readonly panelId: string\n readonly variant: string\n readonly columns?: number | undefined\n readonly className?: string | undefined\n readonly children: ReactNode\n}) {\n const nav = useContext(NavContext)\n const open = nav?.menu.openId === menuId\n return (\n <div\n id={panelId}\n data-slot=\"panel\"\n data-menu-id={menuId}\n data-variant={variant}\n data-columns={columns}\n data-state={open ? 'open' : 'closed'}\n inert={Boolean(nav?.hydrated) && !open}\n className={className}\n {...nav?.menu.panelHandlers(menuId)}\n >\n {children}\n </div>\n )\n}\n"]}
@@ -0,0 +1,6 @@
1
+ export { SITE_HEADER_VARIANTS, SiteHeader, type SiteHeaderLayout, type SiteHeaderProps, type SiteHeaderSkin, type SiteHeaderSlot, type SiteHeaderVariant, } from './site-header.js';
2
+ export { MOBILE_DRAWER_VARIANTS, MobileDrawer, type MobileDrawerLayout, type MobileDrawerProps, type MobileDrawerSkin, type MobileDrawerSlot, type MobileDrawerVariant, type ShellQuote, } from './mobile-drawer.js';
3
+ export { UtilityBar, type UtilityBarLayout, type UtilityBarProps, type UtilityBarSkin, type UtilityBarSlot, type UtilityLicence, type UtilityRating, } from './utility-bar.js';
4
+ export { MOBILE_CALL_BAR_VARIANTS, MobileCallBar, type MobileCallBarProps, type MobileCallBarSkin, type MobileCallBarSlot, type MobileCallBarVariant, } from './mobile-call-bar.js';
5
+ export { BACK_TO_TOP_OFFSETS, BackToTop, type BackToTopLayout, type BackToTopProps, type BackToTopSkin, type BackToTopSlot } from './back-to-top.js';
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/ui-kit/shell/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,oBAAoB,EACpB,UAAU,EACV,KAAK,gBAAgB,EACrB,KAAK,eAAe,EACpB,KAAK,cAAc,EACnB,KAAK,cAAc,EACnB,KAAK,iBAAiB,GACvB,MAAM,kBAAkB,CAAA;AACzB,OAAO,EACL,sBAAsB,EACtB,YAAY,EACZ,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EACrB,KAAK,mBAAmB,EACxB,KAAK,UAAU,GAChB,MAAM,oBAAoB,CAAA;AAC3B,OAAO,EACL,UAAU,EACV,KAAK,gBAAgB,EACrB,KAAK,eAAe,EACpB,KAAK,cAAc,EACnB,KAAK,cAAc,EACnB,KAAK,cAAc,EACnB,KAAK,aAAa,GACnB,MAAM,kBAAkB,CAAA;AACzB,OAAO,EACL,wBAAwB,EACxB,aAAa,EACb,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACtB,KAAK,iBAAiB,EACtB,KAAK,oBAAoB,GAC1B,MAAM,sBAAsB,CAAA;AAC7B,OAAO,EAAE,mBAAmB,EAAE,SAAS,EAAE,KAAK,eAAe,EAAE,KAAK,cAAc,EAAE,KAAK,aAAa,EAAE,KAAK,aAAa,EAAE,MAAM,kBAAkB,CAAA"}
@@ -0,0 +1,6 @@
1
+ export { SITE_HEADER_VARIANTS, SiteHeader, } from './site-header.js';
2
+ export { MOBILE_DRAWER_VARIANTS, MobileDrawer, } from './mobile-drawer.js';
3
+ export { UtilityBar, } from './utility-bar.js';
4
+ export { MOBILE_CALL_BAR_VARIANTS, MobileCallBar, } from './mobile-call-bar.js';
5
+ export { BACK_TO_TOP_OFFSETS, BackToTop } from './back-to-top.js';
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/ui-kit/shell/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,oBAAoB,EACpB,UAAU,GAMX,MAAM,kBAAkB,CAAA;AACzB,OAAO,EACL,sBAAsB,EACtB,YAAY,GAOb,MAAM,oBAAoB,CAAA;AAC3B,OAAO,EACL,UAAU,GAOX,MAAM,kBAAkB,CAAA;AACzB,OAAO,EACL,wBAAwB,EACxB,aAAa,GAKd,MAAM,sBAAsB,CAAA;AAC7B,OAAO,EAAE,mBAAmB,EAAE,SAAS,EAAqF,MAAM,kBAAkB,CAAA","sourcesContent":["export {\n SITE_HEADER_VARIANTS,\n SiteHeader,\n type SiteHeaderLayout,\n type SiteHeaderProps,\n type SiteHeaderSkin,\n type SiteHeaderSlot,\n type SiteHeaderVariant,\n} from './site-header.js'\nexport {\n MOBILE_DRAWER_VARIANTS,\n MobileDrawer,\n type MobileDrawerLayout,\n type MobileDrawerProps,\n type MobileDrawerSkin,\n type MobileDrawerSlot,\n type MobileDrawerVariant,\n type ShellQuote,\n} from './mobile-drawer.js'\nexport {\n UtilityBar,\n type UtilityBarLayout,\n type UtilityBarProps,\n type UtilityBarSkin,\n type UtilityBarSlot,\n type UtilityLicence,\n type UtilityRating,\n} from './utility-bar.js'\nexport {\n MOBILE_CALL_BAR_VARIANTS,\n MobileCallBar,\n type MobileCallBarProps,\n type MobileCallBarSkin,\n type MobileCallBarSlot,\n type MobileCallBarVariant,\n} from './mobile-call-bar.js'\nexport { BACK_TO_TOP_OFFSETS, BackToTop, type BackToTopLayout, type BackToTopProps, type BackToTopSkin, type BackToTopSlot } from './back-to-top.js'\n"]}
@@ -0,0 +1,16 @@
1
+ import type { SkinEntry } from '../skin.js';
2
+ import type { UiPhone } from '../types.js';
3
+ import type { ShellQuote } from './mobile-drawer.js';
4
+ export type MobileCallBarSlot = 'root' | 'call' | 'quote';
5
+ export declare const MOBILE_CALL_BAR_VARIANTS: readonly ["bar", "float"];
6
+ /** `bar`: full width; `float`: two pills at the end. */
7
+ export type MobileCallBarVariant = (typeof MOBILE_CALL_BAR_VARIANTS)[number];
8
+ export type MobileCallBarSkin = SkinEntry<MobileCallBarSlot, MobileCallBarVariant>;
9
+ export interface MobileCallBarProps extends MobileCallBarSkin {
10
+ readonly phone: UiPhone;
11
+ /** Words before the number, for example "Call". The button's name always includes the number. */
12
+ readonly phoneLabel?: string | undefined;
13
+ readonly quote: ShellQuote;
14
+ }
15
+ export declare function MobileCallBar({ phone, phoneLabel, quote, variant, classes }: MobileCallBarProps): import("react/jsx-runtime").JSX.Element;
16
+ //# sourceMappingURL=mobile-call-bar.d.ts.map
@@ -0,0 +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"}
@@ -0,0 +1,15 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /**
3
+ * F6: the phone call bar (server component). Call and quote always one tap away below 1024 px: it shows once the
4
+ * hero's own call and quote buttons (`data-bl-call-path`) have scrolled out, and hides over the footer, the drawer, a
5
+ * dialog, any call path and while a form field has focus. Call reports placement `fab`; the quote button sends
6
+ * `lead_cta_click` with placement `floating`. Render it once, after the page's `<main>`.
7
+ */
8
+ import { PhoneLink } from '../primitives/links.js';
9
+ import { QuoteButton } from '../primitives/quote-button.js';
10
+ import { CallBarController } from './call-bar-client.js';
11
+ 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 } })] }));
14
+ }
15
+ //# sourceMappingURL=mobile-call-bar.js.map
@@ -0,0 +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"]}
@@ -0,0 +1,37 @@
1
+ /**
2
+ * F4: the phone and compact-band menu (server component). A modal dialog named "Menu", sliding in at
3
+ * `min(100%, 420px)`: the close button first, then the groups as accordions (one open at a time), the plain links,
4
+ * full-width Call and quote buttons, and the social links. Every link is in the server HTML. `SiteHeader` renders it;
5
+ * render it on its own only inside a recorded bespoke header.
6
+ */
7
+ import type { BrandlabNavigation } from '@brandlab-digital/site-core/navigation';
8
+ import type { ReactNode } from 'react';
9
+ import { type SkinEntry } from '../skin.js';
10
+ import type { UiPhone, UiSocial } from '../types.js';
11
+ export type MobileDrawerSlot = 'root' | 'menuButton' | 'menuLabel' | 'panel' | 'top' | 'close' | 'title' | 'logo' | 'nav' | 'group' | 'groupTrigger' | 'groupLinks' | 'groupLink' | 'links' | 'link' | 'actions' | 'call' | 'quote' | 'social' | 'socialLink';
12
+ export declare const MOBILE_DRAWER_VARIANTS: readonly ["side", "full"];
13
+ export type MobileDrawerVariant = (typeof MOBILE_DRAWER_VARIANTS)[number];
14
+ export interface MobileDrawerLayout {
15
+ /** The side the panel slides from (`side` variant). */
16
+ readonly side?: 'end' | 'start';
17
+ }
18
+ export type MobileDrawerSkin = SkinEntry<MobileDrawerSlot, MobileDrawerVariant, MobileDrawerLayout>;
19
+ /** The quote action. `href` is the quote form it falls back to without scripts, for example `/contact#quote`. */
20
+ export interface ShellQuote {
21
+ readonly label: string;
22
+ readonly href: string;
23
+ }
24
+ export interface MobileDrawerProps extends MobileDrawerSkin {
25
+ readonly navigation: BrandlabNavigation;
26
+ readonly phone: UiPhone;
27
+ /** Words before the number on the Call button, for example "Call". */
28
+ readonly phoneLabel?: string | undefined;
29
+ readonly quote: ShellQuote;
30
+ readonly socials?: readonly UiSocial[] | undefined;
31
+ /** An optional logo in the drawer's top bar (decorative there). */
32
+ readonly logo?: ReactNode;
33
+ /** Prefix for element ids; one per header on the page. */
34
+ readonly idPrefix?: string | undefined;
35
+ }
36
+ export declare function MobileDrawer({ navigation, phone, phoneLabel, quote, socials, logo, idPrefix, variant, layout, classes, }: MobileDrawerProps): import("react/jsx-runtime").JSX.Element;
37
+ //# sourceMappingURL=mobile-drawer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mobile-drawer.d.ts","sourceRoot":"","sources":["../../../src/ui-kit/shell/mobile-drawer.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAAE,kBAAkB,EAA4C,MAAM,wCAAwC,CAAA;AAC1H,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAItC,OAAO,EAAQ,KAAK,SAAS,EAAE,MAAM,YAAY,CAAA;AACjD,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AAKpD,MAAM,MAAM,gBAAgB,GACxB,MAAM,GACN,YAAY,GACZ,WAAW,GACX,OAAO,GACP,KAAK,GACL,OAAO,GACP,OAAO,GACP,MAAM,GACN,KAAK,GACL,OAAO,GACP,cAAc,GACd,YAAY,GACZ,WAAW,GACX,OAAO,GACP,MAAM,GACN,SAAS,GACT,MAAM,GACN,OAAO,GACP,QAAQ,GACR,YAAY,CAAA;AAChB,eAAO,MAAM,sBAAsB,2BAA4B,CAAA;AAC/D,MAAM,MAAM,mBAAmB,GAAG,CAAC,OAAO,sBAAsB,CAAC,CAAC,MAAM,CAAC,CAAA;AACzE,MAAM,WAAW,kBAAkB;IACjC,uDAAuD;IACvD,QAAQ,CAAC,IAAI,CAAC,EAAE,KAAK,GAAG,OAAO,CAAA;CAChC;AACD,MAAM,MAAM,gBAAgB,GAAG,SAAS,CAAC,gBAAgB,EAAE,mBAAmB,EAAE,kBAAkB,CAAC,CAAA;AAEnG,iHAAiH;AACjH,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CACtB;AAED,MAAM,WAAW,iBAAkB,SAAQ,gBAAgB;IACzD,QAAQ,CAAC,UAAU,EAAE,kBAAkB,CAAA;IACvC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAA;IACvB,sEAAsE;IACtE,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IACxC,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAA;IAC1B,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,QAAQ,EAAE,GAAG,SAAS,CAAA;IAClD,mEAAmE;IACnE,QAAQ,CAAC,IAAI,CAAC,EAAE,SAAS,CAAA;IACzB,0DAA0D;IAC1D,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CACvC;AAED,wBAAgB,YAAY,CAAC,EAC3B,UAAU,EACV,KAAK,EACL,UAAU,EACV,KAAK,EACL,OAAY,EACZ,IAAI,EACJ,QAAsB,EACtB,OAAgB,EAChB,MAAM,EACN,OAAO,GACR,EAAE,iBAAiB,2CAwEnB"}
@@ -0,0 +1,25 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Icon } from '../icons.js';
3
+ import { PhoneLink } from '../primitives/links.js';
4
+ import { QuoteButton } from '../primitives/quote-button.js';
5
+ import { slot } from '../skin.js';
6
+ import { CurrentLink } from './current-link.js';
7
+ import { DrawerController } from './drawer-client.js';
8
+ import { SocialLinks } from './social-links.js';
9
+ export const MOBILE_DRAWER_VARIANTS = ['side', 'full'];
10
+ export function MobileDrawer({ navigation, phone, phoneLabel, quote, socials = [], logo, idPrefix = 'bl-header', variant = 'side', layout, classes, }) {
11
+ const id = `${idPrefix}-drawer`;
12
+ const groups = navigation.items.filter((item) => item.kind === 'menu');
13
+ const links = navigation.items.filter((item) => item.kind === 'link');
14
+ return (_jsxs(DrawerController, { id: id, variant: variant, side: layout?.side ?? 'end', classes: {
15
+ root: classes?.root,
16
+ menuButton: classes?.menuButton,
17
+ menuLabel: classes?.menuLabel,
18
+ panel: classes?.panel,
19
+ top: classes?.top,
20
+ close: classes?.close,
21
+ title: classes?.title,
22
+ logo: classes?.logo,
23
+ }, logo: logo, menuIcon: _jsx(Icon, { name: "menu" }), closeIcon: _jsx(Icon, { name: "close" }), children: [_jsxs("nav", { "aria-label": "Main", ...slot(classes, 'nav'), children: [groups.map((group) => (_jsxs("details", { name: `${id}-groups`, ...slot(classes, 'group'), children: [_jsxs("summary", { ...slot(classes, 'groupTrigger'), children: [_jsx("span", { children: group.label }), _jsx(Icon, { name: "chevron" })] }), _jsxs("ul", { ...slot(classes, 'groupLinks'), children: [_jsx("li", { children: _jsx(CurrentLink, { href: group.href, slot: "groupLink", prefetch: false, hub: true, className: classes?.groupLink, children: group.hubLabel }) }), group.featured && !group.links.some((link) => link.href === group.featured?.href) ? (_jsx("li", { children: _jsx(CurrentLink, { href: group.featured.href, slot: "groupLink", prefetch: false, className: classes?.groupLink, children: group.featured.label }) })) : null, group.links.map((link) => (_jsx("li", { children: _jsx(CurrentLink, { href: link.href, slot: "groupLink", prefetch: false, className: classes?.groupLink, children: link.label }) }, link.href)))] })] }, group.id))), links.length > 0 ? (_jsx("ul", { ...slot(classes, 'links'), children: links.map((link) => (_jsx("li", { children: _jsx(CurrentLink, { href: link.href, slot: "link", prefetch: false, className: classes?.link, children: link.label }) }, link.id))) })) : null] }), _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, linkClassName: classes?.socialLink })] }));
24
+ }
25
+ //# sourceMappingURL=mobile-drawer.js.map
@@ -0,0 +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 groups as accordions (one open at a time), the plain links,\n * full-width Call and quote 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 { 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}\nexport type MobileDrawerSkin = SkinEntry<MobileDrawerSlot, MobileDrawerVariant, MobileDrawerLayout>\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 const groups = navigation.items.filter((item): item is BrandlabNavMenuItem => item.kind === 'menu')\n const links = navigation.items.filter((item): item is BrandlabNavLinkItem => item.kind === 'link')\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 {groups.map((group) => (\n <details key={group.id} name={`${id}-groups`} {...slot(classes, 'group')}>\n <summary {...slot(classes, 'groupTrigger')}>\n <span>{group.label}</span>\n <Icon name=\"chevron\" />\n </summary>\n <ul {...slot(classes, 'groupLinks')}>\n <li>\n <CurrentLink href={group.href} slot=\"groupLink\" prefetch={false} hub className={classes?.groupLink}>\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} className={classes?.groupLink}>\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} className={classes?.groupLink}>\n {link.label}\n </CurrentLink>\n </li>\n ))}\n </ul>\n </details>\n ))}\n {links.length > 0 ? (\n <ul {...slot(classes, 'links')}>\n {links.map((link) => (\n <li key={link.id}>\n <CurrentLink href={link.href} slot=\"link\" prefetch={false} className={classes?.link}>\n {link.label}\n </CurrentLink>\n </li>\n ))}\n </ul>\n ) : null}\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} linkClassName={classes?.socialLink} />\n </DrawerController>\n )\n}\n"]}
@@ -0,0 +1,3 @@
1
+ import type { HeaderMode } from '../../navigation/constants.js';
2
+ export declare const HeaderModeContext: import("react").Context<HeaderMode | null>;
3
+ //# sourceMappingURL=shell-context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shell-context.d.ts","sourceRoot":"","sources":["../../../src/ui-kit/shell/shell-context.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAA;AAE/D,eAAO,MAAM,iBAAiB,4CAAyC,CAAA"}
@@ -0,0 +1,5 @@
1
+ 'use client';
2
+ /** The header's measured mode, shared by the header root with the menu and the drawer (both reset when it changes). */
3
+ import { createContext } from 'react';
4
+ export const HeaderModeContext = createContext(null);
5
+ //# sourceMappingURL=shell-context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shell-context.js","sourceRoot":"","sources":["../../../src/ui-kit/shell/shell-context.ts"],"names":[],"mappings":"AAAA,YAAY,CAAA;AAEZ,uHAAuH;AACvH,OAAO,EAAE,aAAa,EAAE,MAAM,OAAO,CAAA;AAGrC,MAAM,CAAC,MAAM,iBAAiB,GAAG,aAAa,CAAoB,IAAI,CAAC,CAAA","sourcesContent":["'use client'\n\n/** The header's measured mode, shared by the header root with the menu and the drawer (both reset when it changes). */\nimport { createContext } from 'react'\nimport type { HeaderMode } from '../../navigation/constants.js'\n\nexport const HeaderModeContext = createContext<HeaderMode | null>(null)\n"]}
@@ -0,0 +1,52 @@
1
+ /**
2
+ * F2: the header shell (server component). The same structure on every site: the skip link, the optional utility
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
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
+ * Menu button. Every menu, hub and panel link is an `<a href>` in the server HTML (F3); client leaves only change
7
+ * state.
8
+ */
9
+ import type { BrandlabNavigation } from '@brandlab-digital/site-core/navigation';
10
+ import type { ReactNode } from 'react';
11
+ import { type SkinEntry } from '../skin.js';
12
+ import type { UiPhone, UiSocial } from '../types.js';
13
+ import { type MobileDrawerSkin, type ShellQuote } from './mobile-drawer.js';
14
+ export type SiteHeaderSlot = 'skip' | 'root' | 'bar' | 'inner' | 'logo' | 'nav' | 'list' | 'item' | 'itemRow' | 'link' | 'trigger' | 'panel' | 'panelBody' | 'panelList' | 'panelGroup' | 'panelHeading' | 'panelLink' | 'panelLabel' | 'panelText' | 'featured' | 'featuredMedia' | 'featuredLabel' | 'featuredText' | 'actions' | 'phone' | 'phoneIcon' | 'phoneLabel' | 'phoneNumber' | 'quote' | 'quoteLabel' | 'quoteIcon' | 'menuButton' | 'menuLabel';
15
+ export declare const SITE_HEADER_VARIANTS: readonly ["standard", "call-first"];
16
+ /**
17
+ * `call-first` (recorded exceptions, v1 §9.10): the phone is the primary action (a button with its number at every
18
+ * width); the quote button still follows it, as on `standard`.
19
+ */
20
+ export type SiteHeaderVariant = (typeof SITE_HEADER_VARIANTS)[number];
21
+ export interface SiteHeaderLayout {
22
+ /** Where the menu sits between the logo and the actions. */
23
+ readonly navAlign?: 'center' | 'end';
24
+ /** Compact the header (`data-compact="true"`) once the page has scrolled 80 px. It never hides. */
25
+ readonly compactAfterScroll?: boolean;
26
+ }
27
+ export type SiteHeaderSkin = SkinEntry<SiteHeaderSlot, SiteHeaderVariant, SiteHeaderLayout>;
28
+ export interface SiteHeaderProps extends SiteHeaderSkin {
29
+ readonly navigation: BrandlabNavigation;
30
+ /** The logo link's accessible name. */
31
+ readonly brandName: string;
32
+ readonly homeHref: string;
33
+ readonly logo: ReactNode;
34
+ /** From the derived business facts, never typed by hand. */
35
+ readonly phone: UiPhone;
36
+ /** The small line above the number, for example "Call us". Also leads the drawer's Call button. */
37
+ readonly phoneLabel?: string | undefined;
38
+ readonly quote: ShellQuote;
39
+ readonly socials?: readonly UiSocial[] | undefined;
40
+ /** The site's skip-link text, for example "Skip to main content". It targets `#main`. */
41
+ readonly skipLabel: string;
42
+ /** The optional utility bar (`<UtilityBar>`), placed between the skip link and the header. */
43
+ readonly utility?: ReactNode;
44
+ /** The site's `mobileDrawer` skin entry. */
45
+ readonly drawer?: MobileDrawerSkin | undefined;
46
+ /** An optional logo for the drawer's top bar. */
47
+ readonly drawerLogo?: ReactNode;
48
+ /** Prefix for element ids; one per header on the page. */
49
+ readonly idPrefix?: string | undefined;
50
+ }
51
+ export declare function SiteHeader({ navigation, brandName, homeHref, logo, phone, phoneLabel, quote, socials, skipLabel, utility, drawer, drawerLogo, idPrefix, variant, layout, classes, }: SiteHeaderProps): import("react/jsx-runtime").JSX.Element;
52
+ //# sourceMappingURL=site-header.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"site-header.d.ts","sourceRoot":"","sources":["../../../src/ui-kit/shell/site-header.tsx"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,KAAK,EAAE,kBAAkB,EAA4C,MAAM,wCAAwC,CAAA;AAG1H,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAMtC,OAAO,EAAY,KAAK,SAAS,EAAoB,MAAM,YAAY,CAAA;AACvE,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AAGpD,OAAO,EAAgB,KAAK,gBAAgB,EAAE,KAAK,UAAU,EAAE,MAAM,oBAAoB,CAAA;AAEzF,MAAM,MAAM,cAAc,GACtB,MAAM,GACN,MAAM,GACN,KAAK,GACL,OAAO,GACP,MAAM,GACN,KAAK,GACL,MAAM,GACN,MAAM,GACN,SAAS,GACT,MAAM,GACN,SAAS,GACT,OAAO,GACP,WAAW,GACX,WAAW,GACX,YAAY,GACZ,cAAc,GACd,WAAW,GACX,YAAY,GACZ,WAAW,GACX,UAAU,GACV,eAAe,GACf,eAAe,GACf,cAAc,GACd,SAAS,GACT,OAAO,GACP,WAAW,GACX,YAAY,GACZ,aAAa,GACb,OAAO,GACP,YAAY,GACZ,WAAW,GACX,YAAY,GACZ,WAAW,CAAA;AACf,eAAO,MAAM,oBAAoB,qCAAsC,CAAA;AACvE;;;GAGG;AACH,MAAM,MAAM,iBAAiB,GAAG,CAAC,OAAO,oBAAoB,CAAC,CAAC,MAAM,CAAC,CAAA;AACrE,MAAM,WAAW,gBAAgB;IAC/B,4DAA4D;IAC5D,QAAQ,CAAC,QAAQ,CAAC,EAAE,QAAQ,GAAG,KAAK,CAAA;IACpC,mGAAmG;IACnG,QAAQ,CAAC,kBAAkB,CAAC,EAAE,OAAO,CAAA;CACtC;AACD,MAAM,MAAM,cAAc,GAAG,SAAS,CAAC,cAAc,EAAE,iBAAiB,EAAE,gBAAgB,CAAC,CAAA;AAE3F,MAAM,WAAW,eAAgB,SAAQ,cAAc;IACrD,QAAQ,CAAC,UAAU,EAAE,kBAAkB,CAAA;IACvC,uCAAuC;IACvC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAA;IACxB,4DAA4D;IAC5D,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAA;IACvB,mGAAmG;IACnG,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IACxC,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAA;IAC1B,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,QAAQ,EAAE,GAAG,SAAS,CAAA;IAClD,yFAAyF;IACzF,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,8FAA8F;IAC9F,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,CAAA;IAC5B,4CAA4C;IAC5C,QAAQ,CAAC,MAAM,CAAC,EAAE,gBAAgB,GAAG,SAAS,CAAA;IAC9C,iDAAiD;IACjD,QAAQ,CAAC,UAAU,CAAC,EAAE,SAAS,CAAA;IAC/B,0DAA0D;IAC1D,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CACvC;AAED,wBAAgB,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,QAAsB,EACtB,OAAoB,EACpB,MAAM,EACN,OAAO,GACR,EAAE,eAAe,2CAoEjB"}
@@ -0,0 +1,36 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import Image from 'next/image';
3
+ import Link from 'next/link';
4
+ import { SkipLink } from '../../ui.js';
5
+ import { MAIN_CONTENT_ID } from '../../navigation/constants.js';
6
+ import { Icon } from '../icons.js';
7
+ import { PhoneLink } from '../primitives/links.js';
8
+ import { QuoteButton } from '../primitives/quote-button.js';
9
+ import { cx, slot } from '../skin.js';
10
+ import { CurrentLink } from './current-link.js';
11
+ import { HeaderRoot, NavController, NavItem, NavPanel, NavTrigger } from './header-client.js';
12
+ import { MobileDrawer } from './mobile-drawer.js';
13
+ export const SITE_HEADER_VARIANTS = ['standard', 'call-first'];
14
+ export function SiteHeader({ navigation, brandName, homeHref, logo, phone, phoneLabel, quote, socials, skipLabel, utility, drawer, drawerLogo, idPrefix = 'bl-header', variant = 'standard', layout, classes, }) {
15
+ const callFirst = variant === 'call-first';
16
+ 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(Link, { href: homeHref, "aria-label": brandName, ...slot(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, classes: classes }, item.id)) : (_jsx(MenuItem, { item: item, panelId: `${idPrefix}-panel-${item.id}`, classes: classes }, 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: {
17
+ ...drawer?.classes,
18
+ menuButton: cx(drawer?.classes?.menuButton, classes?.menuButton),
19
+ menuLabel: cx(drawer?.classes?.menuLabel, classes?.menuLabel),
20
+ }, navigation: navigation, phone: phone, phoneLabel: phoneLabel, quote: quote, socials: socials, logo: drawerLogo, idPrefix: idPrefix })] })] }) }) })] }));
21
+ }
22
+ function LinkItem({ item, classes }) {
23
+ return (_jsx(NavItem, { paths: [item.href, ...(item.activePaths ?? [])], className: classes?.item, children: _jsx(CurrentLink, { href: item.href, slot: "link", className: classes?.link, children: item.label }) }));
24
+ }
25
+ function MenuItem({ item, panelId, classes }) {
26
+ const groups = item.panel === 'columns' && item.groups && item.groups.length > 0 ? item.groups : undefined;
27
+ // A columns panel never drops a link: links outside every group follow in a last group without a heading.
28
+ const grouped = new Set(groups?.flatMap((group) => group.links.map((link) => link.href)));
29
+ const ungrouped = groups ? item.links.filter((link) => !grouped.has(link.href)) : [];
30
+ const columnCount = groups ? groups.length + (ungrouped.length > 0 ? 1 : 0) : 0;
31
+ return (_jsxs(NavItem, { menuId: item.id, paths: [item.href, ...(item.activePaths ?? [])], className: classes?.item, children: [_jsxs("span", { ...slot(classes, 'itemRow'), children: [_jsx(CurrentLink, { href: item.href, slot: "link", className: classes?.link, children: item.label }), _jsx(NavTrigger, { menuId: item.id, panelId: panelId, label: item.label, className: classes?.trigger, 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, className: classes?.panel, children: _jsxs("div", { ...slot(classes, 'panelBody'), children: [item.panel === 'featured' && item.featured ? (_jsxs(CurrentLink, { href: item.featured.href, slot: "featured", prefetch: false, className: classes?.featured, children: [_jsx("span", { ...slot(classes, '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", { ...slot(classes, 'featuredLabel'), children: item.featured.label }), _jsx("span", { ...slot(classes, 'featuredText'), children: item.featured.description })] })) : null, _jsxs("ul", { ...slot(classes, 'panelList'), children: [_jsx("li", { children: _jsxs(CurrentLink, { href: item.href, slot: "panelLink", hub: true, prefetch: false, className: classes?.panelLink, children: [_jsx("span", { ...slot(classes, 'panelLabel'), children: item.hubLabel }), _jsx(Icon, { name: "arrow" })] }) }), groups ? null : item.links.map((link) => _jsx(PanelLink, { link: link, classes: classes }, link.href))] }), groups?.map((group) => (_jsxs("div", { ...slot(classes, 'panelGroup'), children: [_jsx("p", { ...slot(classes, 'panelHeading'), children: group.heading }), _jsx("ul", { ...slot(classes, 'panelList'), children: group.links.map((link) => (_jsx(PanelLink, { link: link, classes: classes }, link.href))) })] }, group.heading))), ungrouped.length > 0 ? (_jsx("div", { ...slot(classes, 'panelGroup'), children: _jsx("ul", { ...slot(classes, 'panelList'), children: ungrouped.map((link) => (_jsx(PanelLink, { link: link, classes: classes }, link.href))) }) })) : null] }) })] }));
32
+ }
33
+ function PanelLink({ link, classes }) {
34
+ return (_jsx("li", { children: _jsxs(CurrentLink, { href: link.href, slot: "panelLink", prefetch: false, className: classes?.panelLink, children: [_jsx("span", { ...slot(classes, 'panelLabel'), children: link.label }), link.description ? _jsx("span", { ...slot(classes, 'panelText'), children: link.description }) : null] }) }));
35
+ }
36
+ //# sourceMappingURL=site-header.js.map