@pnx-mixtape/mxds 0.1.0-rc.5 → 0.1.0-rc.6

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 (77) hide show
  1. package/DESIGN.md +1 -1
  2. package/README.md +1 -1
  3. package/dist/build/accordion.entry.js +1 -1
  4. package/dist/build/base.css +1 -1
  5. package/dist/build/chunks/{Accordion-D2wp8hBG.js → Accordion-Bqe8vTNR.js} +1 -1
  6. package/dist/build/chunks/{AccordionMobile-D3sTeiM5.js → AccordionMobile-D517oXYZ.js} +1 -1
  7. package/dist/build/chunks/{ClosableAlert-yy84gae6.js → ClosableAlert-CZ114JsL.js} +1 -1
  8. package/dist/build/chunks/{Dialog-DWoXW-7Z.js → Dialog-DoYcGqhW.js} +1 -1
  9. package/dist/build/chunks/{FeedbackForm-BochXEDx.js → FeedbackForm-BsL7fv8s.js} +1 -1
  10. package/dist/build/chunks/{Gallery-Rkfv7Mbb.js → Gallery-DqJPujX5.js} +2 -2
  11. package/dist/build/chunks/{GlobalToggle-CzlkpLpc.js → GlobalToggle-7H3F1Wvc.js} +1 -1
  12. package/dist/build/chunks/{InPageNavigation-D1Kk-rCm.js → InPageNavigation-D7m3IN89.js} +1 -1
  13. package/dist/build/chunks/{Navigation-CDQnN61h.js → Navigation-CRModT40.js} +13 -18
  14. package/dist/build/chunks/{Sticky-DoVndENm.js → Sticky-C1H8MNqK.js} +1 -1
  15. package/dist/build/chunks/{Tabs-BDlxCDNh.js → Tabs-BJD3kABL.js} +1 -1
  16. package/dist/build/chunks/{Translate-bmM38j6z.js → Translate-yAgySwet.js} +1 -1
  17. package/dist/build/chunks/{utilities-Dd-08SW6.js → utilities-B9mNRs7V.js} +1 -1
  18. package/dist/build/dialog.entry.js +1 -1
  19. package/dist/build/elements.js +13 -13
  20. package/dist/build/feedback-form.entry.js +1 -1
  21. package/dist/build/filters.entry.js +3 -3
  22. package/dist/build/form.css +1 -1
  23. package/dist/build/gallery.entry.js +1 -1
  24. package/dist/build/global-alert.entry.js +1 -1
  25. package/dist/build/header.entry.js +1 -1
  26. package/dist/build/in-page-navigation.entry.js +1 -1
  27. package/dist/build/navigation.css +1 -1
  28. package/dist/build/navigation.entry.js +1 -1
  29. package/dist/build/react.js +230 -209
  30. package/dist/build/side-navigation.css +1 -1
  31. package/dist/build/sidebar.css +1 -1
  32. package/dist/build/sticky.entry.js +1 -1
  33. package/dist/build/tabs.entry.js +1 -1
  34. package/dist/build/translate.entry.js +1 -1
  35. package/dist/types/Component/Navigation/Elements/Navigation.d.ts +2 -3
  36. package/dist/types/Component/Navigation/Elements/Navigation.d.ts.map +1 -1
  37. package/dist/types/Component/SideNavigation/Components/SideNavigationTree.d.ts +3 -3
  38. package/dist/types/Component/SideNavigation/Components/SideNavigationTree.d.ts.map +1 -1
  39. package/dist/types/Component/SideNavigation/SideNavigation.d.ts +3 -1
  40. package/dist/types/Component/SideNavigation/SideNavigation.d.ts.map +1 -1
  41. package/dist/types/tokens.d.ts +1 -0
  42. package/dist/types/tokens.d.ts.map +1 -1
  43. package/docs/CSSGuidelines.md +2 -0
  44. package/package.json +5 -5
  45. package/src/Atom/Link/_links.css +1 -0
  46. package/src/Component/Navigation/Elements/Navigation.ts +25 -29
  47. package/src/Component/Navigation/README.md +11 -10
  48. package/src/Component/Navigation/__snapshots__/Navigation.stories.ts.snap +8 -8
  49. package/src/Component/Navigation/_navigation-dropdown.css +9 -11
  50. package/src/Component/Navigation/_navigation-mega.css +5 -11
  51. package/src/Component/Navigation/_navigation.css +5 -3
  52. package/src/Component/Navigation/menu.twig +1 -1
  53. package/src/Component/Navigation/navigation.twig +0 -1
  54. package/src/Component/SideNavigation/Components/SideNavigationTree.tsx +68 -24
  55. package/src/Component/SideNavigation/README.md +78 -32
  56. package/src/Component/SideNavigation/SideNavigation.stories.ts +41 -2
  57. package/src/Component/SideNavigation/SideNavigation.stories.tsx +31 -0
  58. package/src/Component/SideNavigation/SideNavigation.tsx +13 -3
  59. package/src/Component/SideNavigation/__snapshots__/SideNavigation.stories.ts.snap +87 -3
  60. package/src/Component/SideNavigation/__snapshots__/SideNavigation.stories.tsx.snap +2 -0
  61. package/src/Component/SideNavigation/side-navigation.css +3 -3
  62. package/src/Component/SideNavigation/side-navigation.twig +10 -3
  63. package/src/Component/Translate/README.md +4 -2
  64. package/src/Component/Translate/Translate.stories.ts +2 -2
  65. package/src/Component/Translate/Translate.stories.tsx +2 -2
  66. package/src/Component/Translate/Translate.tsx +1 -1
  67. package/src/Component/Translate/__snapshots__/Translate.stories.ts.snap +1 -1
  68. package/src/Component/Translate/__snapshots__/Translate.stories.tsx.snap +1 -1
  69. package/src/Component/Translate/translate.twig +1 -1
  70. package/src/Form/form.css +17 -19
  71. package/src/Introduction.mdx +1 -1
  72. package/src/Layout/Footer/__snapshots__/Footer.stories.ts.snap +3 -3
  73. package/src/Layout/Header/__snapshots__/Header.stories.ts.snap +6 -6
  74. package/src/Layout/Sidebar/sidebar.css +10 -3
  75. package/src/Utility/Elements/google-translate-widget.ts +1 -1
  76. package/src/_custom-media.css +2 -0
  77. package/src/tokens.js +1 -0
@@ -1 +1 @@
1
- @layer popover-polyfill,design-system.defaults,design-system.atoms,design-system.layout,design-system.utilities;@layer design-system.components{.mx-side-nav__parent{border-block-end:var(--line-width,2px) solid var(--line-colour,currentcolor);& a{color:inherit;padding:var(--item-spacing,var(--spacing-xxs));font-weight:var(--font-weight-bold);text-decoration-line:none;display:block;&:hover{text-decoration-line:underline}}}.mx-side-nav{--outline-offset:-1px;& ul li{position:relative;&:has([aria-current=page],.is-active)>a{font-weight:var(--font-weight-bold)}& a{color:inherit;border-block-end:var(--line-width,1px) solid var(--line-colour,var(--colour-border));padding-block:var(--item-spacing,var(--spacing-xxs));padding-inline:var(--indent,var(--spacing-xxs)) var(--item-spacing,var(--spacing-xxs));display:block}}& .mx-nav__level-2>li>a{--indent:var(--spacing-s);@media (width>=720px){--indent:var(--spacing-m)}}& .mx-nav__level-3>li>a{--indent:var(--spacing-m);@media (width>=720px){--indent:var(--spacing-l)}}& :is([aria-current=page],.is-active>a){background-color:var(--nav-active-background,var(--background,var(--colour-background-alt)));color:var(--nav-active-foreground,inherit)}& .mx-nav__toggle{display:none}}}
1
+ @layer popover-polyfill,design-system.defaults,design-system.atoms,design-system.layout,design-system.utilities;@layer design-system.components{.mx-side-nav__parent{border-block-end:var(--line-width,2px) solid var(--line-colour,currentcolor);& a{color:inherit;padding:var(--item-spacing,var(--spacing-xxs));font-weight:var(--font-weight-bold);text-decoration-line:none;display:block;&:hover{text-decoration-line:underline}}}.mx-side-nav{--outline-offset:-1px;& ul li{position:relative;&:has([aria-current=page],.is-active)>a{font-weight:var(--font-weight-bold)}& a{color:inherit;border-block-end:var(--line-width,1px) solid var(--line-colour,var(--colour-border));padding-block:var(--item-spacing,var(--spacing-xxs));padding-inline:var(--indent,var(--spacing-xxs)) var(--item-spacing,var(--spacing-xxs));display:block}}& .mx-nav__level-2>li>a{--indent:var(--spacing-s);@media (width>=720px){--indent:var(--spacing-m)}}& .mx-nav__level-3>li>a{--indent:var(--spacing-m);@media (width>=720px){--indent:var(--spacing-l)}}& :is([aria-current=page],.is-active>a){background-color:var(--nav-active-background,var(--background,var(--colour-background-alt)));color:var(--nav-active-foreground,inherit)}&:not(.mx-nav--collapsible) .mx-nav__toggle{display:none}}}
@@ -1 +1 @@
1
- @layer popover-polyfill,design-system.defaults,design-system.atoms,design-system.layout,design-system.utilities,design-system.components;@layer design-system.layouts{.mx-grid--sidebar{&:where(:not(:has(>aside))){grid-column:narrow}&:where(:has(>aside)){flex-flow:var(--sidebar-direction,column) wrap;gap:var(--sidebar-gap,var(--gap));justify-content:space-between;display:flex;@media (width>=720px){--sidebar-direction:row}&>aside{flex-grow:1;align-content:start;@media (width>=720px){max-inline-size:var(--sidebar-width,24ch)}}&>section{min-inline-size:var(--content-min,50%);max-inline-size:var(--container-max-width,76ch);flex-grow:999;flex-basis:0;& .mx-grid{--grid-min:18ch}}&.mx-grid--sidebar-rev{@media (width>=720px){--sidebar-direction:row-reverse}}&.mx-grid--sidebar-rev-lg{@media (width>=946px){--sidebar-direction:row-reverse}}}}}
1
+ @layer popover-polyfill,design-system.defaults,design-system.atoms,design-system.layout,design-system.utilities,design-system.components;@layer design-system.layouts{.mx-grid--sidebar{&:where(:not(:has(>aside))){grid-column:narrow}&:where(:has(>aside)){flex-flow:var(--sidebar-direction,column) wrap;gap:var(--sidebar-gap,var(--gap));justify-content:space-between;align-items:start;display:flex;@media (width>=720px){--sidebar-direction:row}&>aside{inline-size:100%;border-block-start:var(--line-width,6px) solid var(--line-colour,var(--colour-primary));flex-grow:1;align-content:start;padding-block-start:var(--line-gap,var(--gap));@media (width>=720px){max-inline-size:var(--sidebar-width,24ch);border-block-start:unset;padding-block-start:unset}}&>section{min-inline-size:var(--content-min,50%);inline-size:100%;max-inline-size:var(--container-max-width,76ch);flex-grow:999;flex-basis:0;& .mx-grid{--grid-min:18ch}}&.mx-grid--sidebar-rev{@media (width>=720px){--sidebar-direction:row-reverse}}&.mx-grid--sidebar-rev-lg{@media (width>=946px){--sidebar-direction:row-reverse}}}}}
@@ -1 +1 @@
1
- import "./chunks/Sticky-DoVndENm.js";
1
+ import "./chunks/Sticky-C1H8MNqK.js";
@@ -1 +1 @@
1
- import "./chunks/Tabs-BDlxCDNh.js";
1
+ import "./chunks/Tabs-BJD3kABL.js";
@@ -1 +1 @@
1
- import "./chunks/Translate-bmM38j6z.js";
1
+ import "./chunks/Translate-yAgySwet.js";
@@ -17,17 +17,16 @@ export default class Navigation extends HTMLElement {
17
17
  keyboard: Keyboard;
18
18
  subNavs?: Map<string, SubNavType>;
19
19
  flyout?: boolean;
20
- edgeCheck: boolean;
20
+ openActive: boolean;
21
21
  mq: string;
22
- iO?: IntersectionObserver;
23
22
  constructor();
24
23
  connectedCallback(): void;
25
24
  disconnectedCallback(): void;
26
25
  handleDisclosure: ({ detail }: CustomEvent<DisclosureWidgetEvent>) => void;
27
26
  handleCloseAny: () => void;
27
+ handleOpenActive: () => void;
28
28
  handleFlyout: (event: MouseEvent) => void;
29
29
  handleBreakpoint: ({ matches }: MediaQueryList | MediaQueryListEvent) => void;
30
- handleEdgeCheck(): void;
31
30
  get links(): NodeListOf<HTMLAnchorElement> | null;
32
31
  get lists(): NodeListOf<HTMLUListElement> | null;
33
32
  get breakpoint(): MediaQueryList;
@@ -1 +1 @@
1
- {"version":3,"file":"Navigation.d.ts","sourceRoot":"","sources":["../../../../../src/Component/Navigation/Elements/Navigation.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EACL,QAAQ,EAER,gBAAgB,EAChB,qBAAqB,EACtB,MAAM,4BAA4B,CAAA;AAEnC,KAAK,UAAU,GAAG;IAChB,IAAI,EAAE,WAAW,CAAA;IACjB,OAAO,EAAE,iBAAiB,CAAA;IAC1B,IAAI,EAAE,iBAAiB,CAAA;IACvB,IAAI,CAAC,EAAE,aAAa,CAAA;IACpB,MAAM,CAAC,EAAE,gBAAgB,CAAA;IACzB,UAAU,CAAC,EAAE,gBAAgB,CAAA;CAC9B,CAAA;AAED,MAAM,CAAC,OAAO,OAAO,UAAW,SAAQ,WAAW;IACjD,UAAU,EAAE,gBAAgB,CAAA;IAC5B,UAAU,EAAE,eAAe,CAAA;IAC3B,QAAQ,EAAE,QAAQ,CAAA;IAClB,OAAO,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAAA;IACjC,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,SAAS,EAAG,OAAO,CAAA;IACnB,EAAE,EAAG,MAAM,CAAA;IACX,EAAE,CAAC,EAAE,oBAAoB,CAAA;IAEzB,cAKC;IAED,iBAAiB,IAAI,IAAI,CA0CxB;IAED,oBAAoB,IAAI,IAAI,CAI3B;IAED,gBAAgB,eAAgB,WAAW,CAAC,qBAAqB,CAAC,KAAG,IAAI,CASxE;IAED,cAAc,QAAO,IAAI,CAKxB;IAED,YAAY,UAAW,UAAU,KAAG,IAAI,CAWvC;IAED,gBAAgB,gBAAiB,cAAc,GAAG,mBAAmB,KAAG,IAAI,CAU3E;IAED,eAAe,SAad;IAED,IAAI,KAAK,IAAI,UAAU,CAAC,iBAAiB,CAAC,GAAG,IAAI,CAMhD;IAED,IAAI,KAAK,IAAI,UAAU,CAAC,gBAAgB,CAAC,GAAG,IAAI,CAE/C;IAED,IAAI,UAAU,IAAI,cAAc,CAE/B;CACF;AAID,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,QAAQ,EAAE,UAAU,CAAA;KACrB;CACF"}
1
+ {"version":3,"file":"Navigation.d.ts","sourceRoot":"","sources":["../../../../../src/Component/Navigation/Elements/Navigation.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EACL,QAAQ,EAER,gBAAgB,EAChB,qBAAqB,EACtB,MAAM,4BAA4B,CAAA;AAEnC,KAAK,UAAU,GAAG;IAChB,IAAI,EAAE,WAAW,CAAA;IACjB,OAAO,EAAE,iBAAiB,CAAA;IAC1B,IAAI,EAAE,iBAAiB,CAAA;IACvB,IAAI,CAAC,EAAE,aAAa,CAAA;IACpB,MAAM,CAAC,EAAE,gBAAgB,CAAA;IACzB,UAAU,CAAC,EAAE,gBAAgB,CAAA;CAC9B,CAAA;AAED,MAAM,CAAC,OAAO,OAAO,UAAW,SAAQ,WAAW;IACjD,UAAU,EAAE,gBAAgB,CAAA;IAC5B,UAAU,EAAE,eAAe,CAAA;IAC3B,QAAQ,EAAE,QAAQ,CAAA;IAClB,OAAO,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAAA;IACjC,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,UAAU,EAAG,OAAO,CAAA;IACpB,EAAE,EAAG,MAAM,CAAA;IAEX,cAIC;IAED,iBAAiB,IAAI,IAAI,CA6CxB;IAED,oBAAoB,IAAI,IAAI,CAG3B;IAED,gBAAgB,eAAgB,WAAW,CAAC,qBAAqB,CAAC,KAAG,IAAI,CASxE;IAED,cAAc,QAAO,IAAI,CAKxB;IAED,gBAAgB,QAAO,IAAI,CAU1B;IAED,YAAY,UAAW,UAAU,KAAG,IAAI,CAWvC;IAED,gBAAgB,gBAAiB,cAAc,GAAG,mBAAmB,KAAG,IAAI,CAS3E;IAED,IAAI,KAAK,IAAI,UAAU,CAAC,iBAAiB,CAAC,GAAG,IAAI,CAMhD;IAED,IAAI,KAAK,IAAI,UAAU,CAAC,gBAAgB,CAAC,GAAG,IAAI,CAE/C;IAED,IAAI,UAAU,IAAI,cAAc,CAE/B;CACF;AAID,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,QAAQ,EAAE,UAAU,CAAA;KACrB;CACF"}
@@ -1,9 +1,9 @@
1
- import { JSX } from "react";
1
+ import { JSX, ComponentPropsWithoutRef } from "react";
2
2
  import { MenuTree } from "@pnx-mixtape/ids-shape";
3
- type SideNavigationTreeProps = {
3
+ type SideNavigationTreeProps = ComponentPropsWithoutRef<"ul"> & {
4
4
  items: MenuTree[];
5
5
  level?: number;
6
6
  };
7
- declare const SideNavigationTree: ({ items, level }: SideNavigationTreeProps) => JSX.Element;
7
+ declare const SideNavigationTree: ({ items, level, ...props }: SideNavigationTreeProps) => JSX.Element;
8
8
  export default SideNavigationTree;
9
9
  //# sourceMappingURL=SideNavigationTree.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"SideNavigationTree.d.ts","sourceRoot":"","sources":["../../../../../src/Component/SideNavigation/Components/SideNavigationTree.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,OAAO,CAAA;AAC3B,OAAO,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAA;AAGjD,KAAK,uBAAuB,GAAG;IAC7B,KAAK,EAAE,QAAQ,EAAE,CAAA;IACjB,KAAK,CAAC,EAAE,MAAM,CAAA;CACf,CAAA;AAED,QAAA,MAAM,kBAAkB,qBAA0B,uBAAuB,KAAG,GAAG,CAAC,OA2B/E,CAAA;eACc,kBAAkB"}
1
+ {"version":3,"file":"SideNavigationTree.d.ts","sourceRoot":"","sources":["../../../../../src/Component/SideNavigation/Components/SideNavigationTree.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,wBAAwB,EAAqB,MAAM,OAAO,CAAA;AAExE,OAAO,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAA;AAIjD,KAAK,uBAAuB,GAAG,wBAAwB,CAAC,IAAI,CAAC,GAAG;IAC9D,KAAK,EAAE,QAAQ,EAAE,CAAA;IACjB,KAAK,CAAC,EAAE,MAAM,CAAA;CACf,CAAA;AA2DD,QAAA,MAAM,kBAAkB,+BAIrB,uBAAuB,KAAG,GAAG,CAAC,OAQhC,CAAA;eACc,kBAAkB"}
@@ -3,8 +3,10 @@ type SideNavigationProps = PropsWithChildren & {
3
3
  parent?: ReactNode;
4
4
  title?: string;
5
5
  id?: string;
6
+ collapsible?: boolean;
6
7
  className?: string;
7
8
  };
8
- declare const SideNavigation: ({ children, parent, title, id, className, }: SideNavigationProps) => JSX.Element;
9
+ export declare const SideNavigationContext: import("react").Context<boolean>;
10
+ declare const SideNavigation: ({ children, parent, title, id, collapsible, className, }: SideNavigationProps) => JSX.Element;
9
11
  export default SideNavigation;
10
12
  //# sourceMappingURL=SideNavigation.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"SideNavigation.d.ts","sourceRoot":"","sources":["../../../../src/Component/SideNavigation/SideNavigation.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,SAAS,EAAE,iBAAiB,EAAS,MAAM,OAAO,CAAA;AAGhE,KAAK,mBAAmB,GAAG,iBAAiB,GAAG;IAC7C,MAAM,CAAC,EAAE,SAAS,CAAA;IAClB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,CAAA;AAED,QAAA,MAAM,cAAc,gDAMjB,mBAAmB,KAAG,GAAG,CAAC,OAe5B,CAAA;eAEc,cAAc"}
1
+ {"version":3,"file":"SideNavigation.d.ts","sourceRoot":"","sources":["../../../../src/Component/SideNavigation/SideNavigation.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,SAAS,EAAE,iBAAiB,EAAwB,MAAM,OAAO,CAAA;AAG/E,KAAK,mBAAmB,GAAG,iBAAiB,GAAG;IAC7C,MAAM,CAAC,EAAE,SAAS,CAAA;IAClB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,CAAA;AAGD,eAAO,MAAM,qBAAqB,kCAAgC,CAAA;AAElE,QAAA,MAAM,cAAc,6DAOjB,mBAAmB,KAAG,GAAG,CAAC,OAoB5B,CAAA;eAEc,cAAc"}
@@ -42,6 +42,7 @@ declare const _default: {
42
42
  contentCard: string;
43
43
  collapsedCard: string;
44
44
  dropMenu: string;
45
+ sidebar: string;
45
46
  };
46
47
  colour: {
47
48
  primary: {
@@ -1 +1 @@
1
- {"version":3,"file":"tokens.d.ts","sourceRoot":"","sources":["../../src/tokens.js"],"names":[],"mappings":"AACA,eAAO,MAAM,MAAM;IACjB,IAAI;QACF,KAAK;QACL,IAAI;QACJ,GAAG;QACH,EAAE;QACF,CAAC;QACD,CAAC;QACD,CAAC;QACD,EAAE;QACF,GAAG;QACH,IAAI;QACJ,KAAK;QACL,EAAE;QACF,GAAG;QACH,IAAI;;IAEN,UAAU;QACR,WAAW;QACX,WAAW;QACX,UAAU;QACV,UAAU;QACV,aAAa;QACb,eAAe;QACf,YAAY;QACZ,WAAW;;IAEb,MAAM;QACJ,OAAO;QACP,MAAM;;CAET,CAAA;;IAGC,UAAU;QACR,GAAG;QACH,EAAE;QACF,CAAC;QACD,CAAC;QACD,CAAC;QACD,EAAE;QACF,SAAS;QACT,WAAW;QACX,aAAa;QACb,QAAQ;;IAEV,MAAM;QACJ,OAAO;YACL,MAAM;YACN,MAAM;;QAER,MAAM;YACJ,MAAM;YACN,MAAM;;QAER,IAAI;YACF,EAAE;YACF,EAAE;YACF,KAAK;YACL,KAAK;YACL,MAAM;YACN,IAAI;YACJ,MAAM;;QAER,OAAO;YACL,EAAE;YACF,EAAE;YACF,KAAK;YACL,KAAK;YACL,MAAM;YACN,IAAI;YACJ,MAAM;;QAER,IAAI;QACJ,OAAO;QACP,OAAO;QACP,KAAK;;IAEP,IAAI;QACF,MAAM;QACN,UAAU;YACR,IAAI;YACJ,OAAO;YACP,EAAE;;QAEJ,MAAM;YACJ,IAAI;YACJ,IAAI;;QAEN,IAAI;YACF,UAAU;YACV,KAAK;YACL,MAAM;YACN,IAAI;;;IAGR,IAAI;QACF,OAAO;YACL,KAAK;YACL,IAAI;YACJ,GAAG;YACH,EAAE;YACF,CAAC;YACD,CAAC;YACD,CAAC;YACD,EAAE;YACF,GAAG;YACH,IAAI;YACJ,KAAK;YACL,EAAE;YACF,GAAG;YACH,IAAI;;QAEN,GAAG;YACD,CAAC;YACD,CAAC;YACD,CAAC;YACD,EAAE;;QAEJ,SAAS;YACP,IAAI;YACJ,KAAK;YACL,OAAO;YACP,MAAM;YACN,SAAS;YACT,SAAS;;;IAGb,OAAO;QACL,OAAO;YACL,KAAK;YACL,KAAK;YACL,MAAM;;QAER,MAAM;YACJ,CAAC;YACD,CAAC;YACD,KAAK;;QAEP,MAAM;YACJ,MAAM;YACN,IAAI;;QAEN,KAAK"}
1
+ {"version":3,"file":"tokens.d.ts","sourceRoot":"","sources":["../../src/tokens.js"],"names":[],"mappings":"AACA,eAAO,MAAM,MAAM;IACjB,IAAI;QACF,KAAK;QACL,IAAI;QACJ,GAAG;QACH,EAAE;QACF,CAAC;QACD,CAAC;QACD,CAAC;QACD,EAAE;QACF,GAAG;QACH,IAAI;QACJ,KAAK;QACL,EAAE;QACF,GAAG;QACH,IAAI;;IAEN,UAAU;QACR,WAAW;QACX,WAAW;QACX,UAAU;QACV,UAAU;QACV,aAAa;QACb,eAAe;QACf,YAAY;QACZ,WAAW;;IAEb,MAAM;QACJ,OAAO;QACP,MAAM;;CAET,CAAA;;IAGC,UAAU;QACR,GAAG;QACH,EAAE;QACF,CAAC;QACD,CAAC;QACD,CAAC;QACD,EAAE;QACF,SAAS;QACT,WAAW;QACX,aAAa;QACb,QAAQ;QACR,OAAO;;IAET,MAAM;QACJ,OAAO;YACL,MAAM;YACN,MAAM;;QAER,MAAM;YACJ,MAAM;YACN,MAAM;;QAER,IAAI;YACF,EAAE;YACF,EAAE;YACF,KAAK;YACL,KAAK;YACL,MAAM;YACN,IAAI;YACJ,MAAM;;QAER,OAAO;YACL,EAAE;YACF,EAAE;YACF,KAAK;YACL,KAAK;YACL,MAAM;YACN,IAAI;YACJ,MAAM;;QAER,IAAI;QACJ,OAAO;QACP,OAAO;QACP,KAAK;;IAEP,IAAI;QACF,MAAM;QACN,UAAU;YACR,IAAI;YACJ,OAAO;YACP,EAAE;;QAEJ,MAAM;YACJ,IAAI;YACJ,IAAI;;QAEN,IAAI;YACF,UAAU;YACV,KAAK;YACL,MAAM;YACN,IAAI;;;IAGR,IAAI;QACF,OAAO;YACL,KAAK;YACL,IAAI;YACJ,GAAG;YACH,EAAE;YACF,CAAC;YACD,CAAC;YACD,CAAC;YACD,EAAE;YACF,GAAG;YACH,IAAI;YACJ,KAAK;YACL,EAAE;YACF,GAAG;YACH,IAAI;;QAEN,GAAG;YACD,CAAC;YACD,CAAC;YACD,CAAC;YACD,EAAE;;QAEJ,SAAS;YACP,IAAI;YACJ,KAAK;YACL,OAAO;YACP,MAAM;YACN,SAAS;YACT,SAAS;;;IAGb,OAAO;QACL,OAAO;YACL,KAAK;YACL,KAAK;YACL,MAAM;;QAER,MAAM;YACJ,CAAC;YACD,CAAC;YACD,KAAK;;QAEP,MAAM;YACJ,MAAM;YACN,IAAI;;QAEN,KAAK"}
@@ -278,6 +278,8 @@ Import custom media in every CSS file that uses them:
278
278
  @media (--global-nav-down) /* < 720px */
279
279
  @media (--collapse-card-up) /* >= 400px - Card collapse */
280
280
  @media (--collapse-card-down) /* < 400px */
281
+ @media (--sidebar-up) /* >= 720px - Sidebar breakpoint */
282
+ @media (--sidebar-down) /* < 720px */
281
283
 
282
284
  /* Interaction */
283
285
  @media (--touch) /* Touch devices (no hover) */
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@pnx-mixtape/mxds",
3
3
  "description": "The Mixtape Design System",
4
- "version": "0.1.0-rc.5",
4
+ "version": "0.1.0-rc.6",
5
5
  "license": "MIT",
6
6
  "dependencies": {
7
7
  "@floating-ui/dom": "^1.7.6",
@@ -37,8 +37,8 @@
37
37
  "@testing-library/user-event": "^14.6.1",
38
38
  "@types/node": "^26.0.0",
39
39
  "@vitejs/plugin-react": "^6.0.2",
40
- "@vitest/browser-playwright": "4.1.11",
41
- "@vitest/coverage-v8": "4.1.11",
40
+ "@vitest/browser-playwright": "4.1.12",
41
+ "@vitest/coverage-v8": "4.1.12",
42
42
  "chromatic": "^18.0.1",
43
43
  "concurrently": "^10.0.3",
44
44
  "cz-conventional-changelog": "^3.3.0",
@@ -46,7 +46,7 @@
46
46
  "drupal-twig-extensions": "1.0.0-beta.5",
47
47
  "jsdom": "^30.0.0",
48
48
  "lightningcss": "^1.32.0",
49
- "oxfmt": "^0.72.0",
49
+ "oxfmt": "^0.74.0",
50
50
  "oxlint": "^1.71.0",
51
51
  "playwright": "^1.61.0",
52
52
  "postcss": "^8.5.15",
@@ -63,7 +63,7 @@
63
63
  "typescript": "^7.0.2",
64
64
  "vite": "^8.2.2",
65
65
  "vite-plugin-twig-drupal": "^1.7.0",
66
- "vitest": "4.1.11"
66
+ "vitest": "4.1.12"
67
67
  },
68
68
  "config": {
69
69
  "commitizen": {
@@ -28,6 +28,7 @@
28
28
  &::after {
29
29
  content: "";
30
30
  display: inline-block;
31
+ flex-shrink: 0;
31
32
  mask-image: url("../images/external-link.svg");
32
33
  mask-repeat: no-repeat;
33
34
  mask-size: contain;
@@ -25,18 +25,18 @@ export default class Navigation extends HTMLElement {
25
25
  keyboard: Keyboard
26
26
  subNavs?: Map<string, SubNavType>
27
27
  flyout?: boolean
28
- edgeCheck!: boolean
28
+ openActive!: boolean
29
29
  mq!: string
30
- iO?: IntersectionObserver
31
30
 
32
31
  constructor() {
33
32
  super()
34
33
  this.internals_ = this.attachInternals()
35
34
  this.controller = new AbortController()
36
- this.flyout = this.hasAttribute("flyout")
37
35
  }
38
36
 
39
37
  connectedCallback(): void {
38
+ this.flyout = this.hasAttribute("flyout")
39
+ this.openActive = this.hasAttribute("openActive")
40
40
  const { signal }: AbortController = this.controller
41
41
 
42
42
  // Add keyboard navigation events.
@@ -69,21 +69,21 @@ export default class Navigation extends HTMLElement {
69
69
  }
70
70
  })
71
71
 
72
- this.addEventListener("disclosure-toggle", this.handleDisclosure)
72
+ if (this.openActive && this.subNavs.size > 0) this.handleOpenActive()
73
73
 
74
- if (!this.flyout) return
75
- this.edgeCheck = this.hasAttribute("edgeCheck")
76
- this.mq = this.getAttribute("mq") || "(min-width: 720px)"
77
- this.handleBreakpoint(this.breakpoint)
78
- this.breakpoint.addEventListener("change", this.handleBreakpoint, {
79
- signal,
80
- })
74
+ if (this.flyout) {
75
+ this.mq = this.getAttribute("mq") || "(min-width: 720px)"
76
+ this.handleBreakpoint(this.breakpoint)
77
+ this.breakpoint.addEventListener("change", this.handleBreakpoint, {
78
+ signal,
79
+ })
80
+ this.addEventListener("disclosure-toggle", this.handleDisclosure)
81
+ }
81
82
  }
82
83
 
83
84
  disconnectedCallback(): void {
84
85
  this.controller.abort()
85
86
  this.subNavs?.forEach((subNav: SubNavType): void => subNav.widget.detach())
86
- this.iO?.disconnect()
87
87
  }
88
88
 
89
89
  handleDisclosure = ({ detail }: CustomEvent<DisclosureWidgetEvent>): void => {
@@ -104,6 +104,18 @@ export default class Navigation extends HTMLElement {
104
104
  })
105
105
  }
106
106
 
107
+ handleOpenActive = (): void => {
108
+ this.subNavs?.forEach(({ widget, list, link }: SubNavType): void => {
109
+ if (!widget || widget.isOpen) return
110
+ if (
111
+ !link.hasAttribute("aria-current") &&
112
+ !list.querySelector("[aria-current=page], .is-active")
113
+ )
114
+ return
115
+ widget.handleToggle()
116
+ })
117
+ }
118
+
107
119
  handleFlyout = (event: MouseEvent): void => {
108
120
  const target = event.target as HTMLElement
109
121
  const parent: HTMLLIElement = target.closest("li")
@@ -122,32 +134,16 @@ export default class Navigation extends HTMLElement {
122
134
  if (matches) {
123
135
  this.addEventListener("mouseover", this.handleFlyout, { signal })
124
136
  this.addEventListener("mouseleave", this.handleCloseAny, { signal })
125
- if (this.edgeCheck) this.handleEdgeCheck()
126
137
  } else {
127
138
  this.removeEventListener("mouseover", this.handleFlyout)
128
139
  this.removeEventListener("mouseleave", this.handleCloseAny)
129
140
  }
130
141
  }
131
142
 
132
- handleEdgeCheck() {
133
- const windowInnerWidth: number = window.innerWidth
134
- this.iO = new IntersectionObserver((entries, obs) => {
135
- entries.forEach(({ boundingClientRect, target }) => {
136
- if (windowInnerWidth < boundingClientRect.right) target.classList.add("mx-nav--reverse")
137
- obs.unobserve(target)
138
- })
139
- })
140
- this.subNavs?.forEach(({ list }: SubNavType): void => {
141
- this.iO.observe(list)
142
- const nestedLists: NodeListOf<HTMLUListElement> = list.querySelectorAll("ul")
143
- nestedLists?.forEach(nestedList => this.iO.observe(nestedList))
144
- })
145
- }
146
-
147
143
  get links(): NodeListOf<HTMLAnchorElement> | null {
148
144
  const links: NodeListOf<HTMLAnchorElement> | null = this.querySelectorAll("a")
149
145
  if (!links.length) {
150
- throw new Error(`${this.localName} must links`)
146
+ throw new Error(`${this.localName} must contain links`)
151
147
  }
152
148
  return links
153
149
  }
@@ -170,15 +170,17 @@ Behind the scenes, each top-level item with children is rendered by `DropdownLev
170
170
  </mx-nav>
171
171
  ```
172
172
 
173
- The `<mx-nav>` Web Component wires up keyboard navigation, hover flyouts (when the `flyout` attribute is set), edge detection (when `edgeCheck` is set), and `inert`/`aria-expanded` toggling on sub-menus.
173
+ The `<mx-nav>` Web Component wires up keyboard navigation, hover flyouts (when the `flyout` attribute is set) and `inert`/`aria-expanded` toggling on sub-menus.
174
174
 
175
175
  **`<mx-nav>` attributes:**
176
176
 
177
- | Attribute | Description |
178
- | ----------- | -------------------------------------------------------------------- |
179
- | `flyout` | Opens sub-menus on hover at or above `mq` |
180
- | `edgeCheck` | Adds `mx-nav--reverse` to sub-menus that would overflow the viewport |
181
- | `mq` | Media query for hover behaviour (default: `"(min-width: 720px)"`) |
177
+ | Attribute | Description |
178
+ | ------------ | ------------------------------------------------------------------------------------------------- |
179
+ | `flyout` | Opens sub-menus on hover at or above `mq` |
180
+ | `openActive` | Opens sub-menus whose parent link or descendants are `aria-current="page"` / `.is-active` on load |
181
+ | `mq` | Media query for hover behaviour (default: `"(min-width: 720px)"`) |
182
+
183
+ **Sub-menu positioning:** at `--global-nav-up`, dropdown and mega sub-menus use CSS anchor positioning — no JS. Each `li` with a sub-menu is its own anchor (`anchor-name` + `anchor-scope: --mx-nav-item`), and the sub-menu is `position: fixed` with `position-try-fallbacks: flip-inline`, so it flips to the other side when it would overflow the viewport. Level-2 chevrons always point inline-end, even when the sub-menu has flipped — `@container anchored(fallback: flip-inline)` could fix that, but Lightning CSS can't parse it yet.
182
184
 
183
185
  ---
184
186
 
@@ -210,7 +212,7 @@ Two templates are provided. `navigation.twig` is a thin wrapper that sets modifi
210
212
  | ------------- | ----------------------------------- | --------------------- | ------------------------- |
211
213
  | `collapsible` | `mx-nav--collapsible` | yes | — |
212
214
  | `dropdown` | `mx-nav--dropdown` | yes | `flyout` |
213
- | `mega` | `mx-nav--dropdown mx-nav--mega-nav` | yes | `edgeCheck` |
215
+ | `mega` | `mx-nav--dropdown mx-nav--mega-nav` | yes | — |
214
216
  | `footer` | `mx-nav--footer` | no | sub-lists are not `inert` |
215
217
 
216
218
  **`MenuItem` shape** (consumed by `menu.twig`):
@@ -234,8 +236,7 @@ Two templates are provided. `navigation.twig` is a thin wrapper that sets modifi
234
236
  | `mx-nav--dropdown` | React `Dropdown` / Twig `type: 'dropdown'` | Horizontal top level, absolute-positioned level-2 panels |
235
237
  | `mx-nav--mega-nav` | Twig `type: 'mega'` | Extends `--dropdown` for a third level positioned to the side of level 2 |
236
238
  | `mx-nav--footer` | Twig `type: 'footer'` | Used by Footer layout; sub-lists stay visible (not `inert`) |
237
- | `mx-nav--reverse` | `<mx-nav edgeCheck>` JS | Flips sub-menu alignment when it would overflow the viewport |
238
- | `mx-nav--open` | `<mx-nav>` JS | Added to `<li>` while its sub-menu is open |
239
+ | `mx-nav--open` | `<mx-nav flyout>` JS | Added to `<li>` while its sub-menu is open (flyout navs only — chevron rotation keys off `aria-expanded`) |
239
240
  | `mx-nav__level-1` / `__level-2` / `__level-3` | Structural | Sub-list nesting level |
240
241
  | `mx-nav__has-subnav` | Structural | Applied to any `<li>` that contains a child `<ul>` |
241
242
  | `mx-nav__toggle` | Structural | The chevron button that opens a sub-menu |
@@ -248,7 +249,7 @@ Two templates are provided. `navigation.twig` is a thin wrapper that sets modifi
248
249
  - The outer `<nav>` receives an `aria-label` from the `title` prop — always provide a meaningful label so screen-reader users can distinguish multiple navs on a page (e.g. "Primary navigation", "Footer links").
249
250
  - Sub-menu toggle buttons expose `aria-expanded` (true/false) and `aria-controls` pointing to the `id` of their `<ul>`.
250
251
  - Sub-lists that are closed use the `inert` attribute — removing them from the tab order and from assistive tech — so no additional ARIA is needed on the list itself.
251
- - The `<mx-nav>` Web Component attaches keyboard handling via the shared `Keyboard` utility: arrow keys move between links, `Escape` closes open sub-menus.
252
+ - The `<mx-nav>` Web Component attaches keyboard handling via the shared `Keyboard` utility: arrow keys move between links. `Escape` closes open sub-menus only on `flyout` navs (dropdown) — collapsible and mega navs close via their toggle button.
252
253
  - `DropdownLevel` (React) handles these keys on the toggle button itself: `Escape`/`ArrowUp` close; `ArrowDown`/`Enter`/`Space` open.
253
254
  - The chevron button uses `mx-icon--only` — its accessible name comes from the text "Sub-navigation" inside the button. Never rely on the chevron rotation alone to convey state.
254
255
  - Current-page items should carry `aria-current="page"`; collapsible navigation styles this with a bold weight and an accent background.
@@ -15,7 +15,7 @@ exports[`Collapsible 1`] = `
15
15
  <a href="#" id="unique-2">
16
16
  What we do
17
17
  </a>
18
- <button class="mx-nav__toggle mx-icon mx-icon--chevron-down mx-icon--only" aria-expanded="false" aria-controls="unique-0">Sub-navigation</button>
18
+ <button class="mx-nav__toggle mx-icon mx-icon--chevron-down mx-icon--only" type="button" aria-expanded="false" aria-controls="unique-0">Sub-navigation</button>
19
19
  <ul class="mx-nav__level-2" inert="" id="unique-0" aria-labelledby="unique-1">
20
20
  <li>
21
21
  <a href="#">
@@ -26,7 +26,7 @@ exports[`Collapsible 1`] = `
26
26
  <a href="#" id="unique-3">
27
27
  Who we are
28
28
  </a>
29
- <button class="mx-nav__toggle mx-icon mx-icon--chevron-down mx-icon--only" aria-expanded="false" aria-controls="unique-2">Sub-navigation</button>
29
+ <button class="mx-nav__toggle mx-icon mx-icon--chevron-down mx-icon--only" type="button" aria-expanded="false" aria-controls="unique-2">Sub-navigation</button>
30
30
  <ul class="mx-nav__level-3" inert="" id="unique-1" aria-labelledby="unique-3">
31
31
  <li>
32
32
  <a href="#">
@@ -91,7 +91,7 @@ exports[`Dropdown 1`] = `
91
91
  <a href="#" id="unique-1">
92
92
  What we do
93
93
  </a>
94
- <button class="mx-nav__toggle mx-icon mx-icon--chevron-down mx-icon--only" aria-expanded="false" aria-controls="unique-0">Sub-navigation</button>
94
+ <button class="mx-nav__toggle mx-icon mx-icon--chevron-down mx-icon--only" type="button" aria-expanded="false" aria-controls="unique-0">Sub-navigation</button>
95
95
  <ul class="mx-nav__level-2" id="unique-0" aria-labelledby="unique-1" inert="">
96
96
  <li>
97
97
  <a href="#">
@@ -136,7 +136,7 @@ exports[`Dropdown 1`] = `
136
136
  exports[`Mega 1`] = `
137
137
  "
138
138
 
139
- <mx-nav edgecheck="">
139
+ <mx-nav>
140
140
  <nav class="mx-nav mx-nav--dropdown mx-nav--mega-nav" aria-label="Links" id="links-story">
141
141
  <ul class="mx-nav__level-1">
142
142
  <li>
@@ -148,13 +148,13 @@ exports[`Mega 1`] = `
148
148
  <a href="#" id="unique-3">
149
149
  About
150
150
  </a>
151
- <button class="mx-nav__toggle mx-icon mx-icon--chevron-down mx-icon--only" aria-expanded="false" aria-controls="unique-0">Sub-navigation</button>
151
+ <button class="mx-nav__toggle mx-icon mx-icon--chevron-down mx-icon--only" type="button" aria-expanded="false" aria-controls="unique-0">Sub-navigation</button>
152
152
  <ul class="mx-nav__level-2" inert="" id="unique-0" aria-labelledby="unique-1">
153
153
  <li class="mx-nav__has-subnav">
154
154
  <a href="#" aria-current="page" id="unique-4">
155
155
  Who
156
156
  </a>
157
- <button class="mx-nav__toggle mx-icon mx-icon--chevron-down mx-icon--only" aria-expanded="false" aria-controls="unique-2">Sub-navigation</button>
157
+ <button class="mx-nav__toggle mx-icon mx-icon--chevron-down mx-icon--only" type="button" aria-expanded="false" aria-controls="unique-2">Sub-navigation</button>
158
158
  <ul class="mx-nav__level-3" inert="" id="unique-1" aria-labelledby="unique-3">
159
159
  <li>
160
160
  <a href="#" aria-current="page">
@@ -191,7 +191,7 @@ exports[`Mega 1`] = `
191
191
  <a href="#" id="unique-5">
192
192
  Contact
193
193
  </a>
194
- <button class="mx-nav__toggle mx-icon mx-icon--chevron-down mx-icon--only" aria-expanded="false" aria-controls="unique-4">Sub-navigation</button>
194
+ <button class="mx-nav__toggle mx-icon mx-icon--chevron-down mx-icon--only" type="button" aria-expanded="false" aria-controls="unique-4">Sub-navigation</button>
195
195
  <ul class="mx-nav__level-2" inert="" id="unique-2" aria-labelledby="unique-5">
196
196
  <li>
197
197
  <a href="#" aria-current="page">
@@ -259,7 +259,7 @@ exports[`Screen Reader Announcements 1`] = `
259
259
  <a href="#" id="unique-1">
260
260
  What we do
261
261
  </a>
262
- <button class="mx-nav__toggle mx-icon mx-icon--chevron-down mx-icon--only" aria-expanded="false" aria-controls="unique-0">Sub-navigation</button>
262
+ <button class="mx-nav__toggle mx-icon mx-icon--chevron-down mx-icon--only" type="button" aria-expanded="false" aria-controls="unique-0">Sub-navigation</button>
263
263
  <ul class="mx-nav__level-2" id="unique-0" aria-labelledby="unique-1" inert="">
264
264
  <li>
265
265
  <a href="#">
@@ -20,6 +20,10 @@
20
20
  &:is(.mx-nav__has-subnav, :has(> ul)) {
21
21
  position: relative;
22
22
 
23
+ /* Each sub-menu anchors to its own parent item. */
24
+ anchor-scope: --mx-nav-item;
25
+ anchor-name: --mx-nav-item;
26
+
23
27
  & > a {
24
28
  --toggle-gap: var(--spacing-l);
25
29
  }
@@ -90,7 +94,11 @@
90
94
  margin: 0;
91
95
 
92
96
  @media (--global-nav-up) {
93
- position: absolute;
97
+ /* Fixed so fallbacks flip against the viewport, not the parent item. */
98
+ position: fixed;
99
+ position-anchor: --mx-nav-item;
100
+ position-area: block-end span-inline-end;
101
+ position-try-fallbacks: flip-inline;
94
102
  inline-size: var(--dropdown-width, 270px);
95
103
  border-radius: var(--border-radius);
96
104
  background-color: var(
@@ -113,16 +121,6 @@
113
121
  }
114
122
  }
115
123
 
116
- & .mx-nav--reverse .nav__level-2 {
117
- @media (--global-nav-up) {
118
- inset-inline: auto 0;
119
-
120
- & .mx-nav__toggle::before {
121
- transform: rotate(90deg);
122
- }
123
- }
124
- }
125
-
126
124
  & .mx-nav__separator {
127
125
  border-block-start: var(--line-width, 1px) solid var(--line-colour, var(--colour-border));
128
126
  }
@@ -17,11 +17,12 @@
17
17
  inline-size: 100%;
18
18
 
19
19
  @media (--global-nav-up) {
20
- position: absolute;
21
- inset-inline-start: var(--dropdown-width, 270px);
22
- inset-block-start: 0;
20
+ position: fixed;
21
+ position-anchor: --mx-nav-item;
22
+ position-area: span-block-end inline-end;
23
+ position-try-fallbacks: flip-inline;
23
24
  inline-size: var(--dropdown-width, 270px);
24
- min-block-size: 100%;
25
+ min-block-size: anchor-size(block);
25
26
  padding-inline-start: 0;
26
27
  border-block-start: 0;
27
28
  border-radius: 0 var(--border-radius) var(--border-radius) 0;
@@ -37,12 +38,5 @@
37
38
  }
38
39
  }
39
40
  }
40
-
41
- & .mx-nav--reverse .mx-nav__level-2 ul {
42
- @media (--global-nav-up) {
43
- inset-inline-start: calc(var(--dropdown-width, 270px) * -1);
44
- border-radius: var(--border-radius) 0 0 var(--border-radius);
45
- }
46
- }
47
41
  }
48
42
  }
@@ -45,11 +45,13 @@
45
45
  inset-block-start: var(--toggle-top, 12px);
46
46
  inset-inline-end: 0;
47
47
  cursor: pointer;
48
- }
49
48
 
50
- .mx-nav--open {
51
- & > .mx-nav__toggle::before {
49
+ &[aria-expanded="true"]::before {
52
50
  transform: rotate(180deg);
53
51
  }
54
52
  }
53
+
54
+ mx-nav:not(:defined) .mx-nav__toggle {
55
+ display: none;
56
+ }
55
57
  }
@@ -23,7 +23,7 @@
23
23
  {{ item.link.title }}
24
24
  {% endif %}
25
25
  {% if item.items is not empty %}
26
- <button class="mx-nav__toggle mx-icon mx-icon--chevron-down mx-icon--only">Sub-navigation</button>
26
+ <button class="mx-nav__toggle mx-icon mx-icon--chevron-down mx-icon--only" type="button">Sub-navigation</button>
27
27
  {{ nav.menutree(item.items, level + 1, setInert, baseClass) }}
28
28
  {% endif %}
29
29
  </li>
@@ -14,7 +14,6 @@
14
14
  {% if type == "mega" %}
15
15
  {# Horizontal menu with 3 levels deep, no hover flyout. #}
16
16
  {% set needsJs = true %}
17
- {% set componentAttributes = componentAttributes.addAttribute("edgeCheck") %}
18
17
  {% set modifiers = ['dropdown', 'mega-nav'] %}
19
18
  {% endif %}
20
19
  {% if type == "footer" %}
@@ -1,37 +1,81 @@
1
- import { JSX } from "react"
1
+ import { JSX, ComponentPropsWithoutRef, useContext, useId } from "react"
2
+ import { useDisclosureState } from "react-stately"
2
3
  import { MenuTree } from "@pnx-mixtape/ids-shape"
3
4
  import Link from "../../../Atom/Link/Link"
5
+ import { SideNavigationContext } from "../SideNavigation"
4
6
 
5
- type SideNavigationTreeProps = {
7
+ type SideNavigationTreeProps = ComponentPropsWithoutRef<"ul"> & {
6
8
  items: MenuTree[]
7
9
  level?: number
8
10
  }
9
11
 
10
- const SideNavigationTree = ({ items, level = 0 }: SideNavigationTreeProps): JSX.Element => (
11
- <ul className={`mx-nav__level-${level + 1}`}>
12
+ type SideNavigationItemProps = {
13
+ item: MenuTree
14
+ level: number
15
+ }
16
+
17
+ // True when this item, or any descendant, is the current page.
18
+ const hasCurrent = ({ link, items }: MenuTree): boolean =>
19
+ Boolean(link.current) || Boolean(items?.some(hasCurrent))
20
+
21
+ const SideNavigationItem = ({ item, level }: SideNavigationItemProps): JSX.Element => {
22
+ const collapsible = useContext(SideNavigationContext)
23
+ const { isExpanded, toggle } = useDisclosureState({ defaultExpanded: hasCurrent(item) })
24
+ const listId = useId()
25
+ const labelId = useId()
26
+ const hasItems = item.items && item.items.length > 0
27
+
28
+ return (
29
+ <li className={hasItems ? "mx-nav__has-subnav" : undefined}>
30
+ {item.link.href ? (
31
+ <Link
32
+ to={item.link.href}
33
+ id={hasItems && collapsible ? labelId : undefined}
34
+ aria-current={item.link.current ? "page" : undefined}
35
+ >
36
+ {item.link.title}
37
+ </Link>
38
+ ) : (
39
+ item.link.title
40
+ )}
41
+ {hasItems && (
42
+ <>
43
+ <button
44
+ className="mx-nav__toggle mx-icon mx-icon--chevron-down mx-icon--only"
45
+ type="button"
46
+ {...(collapsible && {
47
+ "aria-expanded": isExpanded,
48
+ "aria-controls": listId,
49
+ onClick: toggle,
50
+ })}
51
+ >
52
+ Sub-navigation
53
+ </button>
54
+ <SideNavigationTree
55
+ items={item.items}
56
+ level={level + 1}
57
+ {...(collapsible && {
58
+ id: listId,
59
+ "aria-labelledby": item.link.href ? labelId : undefined,
60
+ inert: !isExpanded,
61
+ })}
62
+ />
63
+ </>
64
+ )}
65
+ </li>
66
+ )
67
+ }
68
+
69
+ const SideNavigationTree = ({
70
+ items,
71
+ level = 0,
72
+ ...props
73
+ }: SideNavigationTreeProps): JSX.Element => (
74
+ <ul className={`mx-nav__level-${level + 1}`} {...props}>
12
75
  {items.map((item, i) => (
13
76
  // Menu items have no stable id; index is the only available key.
14
77
  // oxlint-disable-next-line react/no-array-index-key
15
- <li key={i} className={item.items?.length ? "mx-nav__has-subnav" : undefined}>
16
- {item.link.href ? (
17
- <Link to={item.link.href} aria-current={item.link.current ? "page" : undefined}>
18
- {item.link.title}
19
- </Link>
20
- ) : (
21
- item.link.title
22
- )}
23
- {item.items && item.items.length > 0 && (
24
- <>
25
- <button
26
- className="mx-nav__toggle mx-icon mx-icon--chevron-down mx-icon--only"
27
- type="button"
28
- >
29
- Sub-navigation
30
- </button>
31
- <SideNavigationTree items={item.items} level={level + 1} />
32
- </>
33
- )}
34
- </li>
78
+ <SideNavigationItem key={i} item={item} level={level} />
35
79
  ))}
36
80
  </ul>
37
81
  )