@pnx-mixtape/mxds 0.0.26 → 0.0.27

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 (34) hide show
  1. package/.storybook/main.ts +4 -1
  2. package/.storybook/vitest.setup.ts +37 -1
  3. package/dist/build/accordion.css +1 -103
  4. package/dist/build/accordion.entry.js +1 -1
  5. package/dist/build/chunks/{DropMenu-plGsgySm.js → DropMenu-LnJEp-sg.js} +1 -1
  6. package/dist/build/constants.css +1 -100
  7. package/dist/build/drop-menu.entry.js +2 -2
  8. package/dist/build/filters.entry.js +1 -1
  9. package/dist/build/header.entry.js +450 -330
  10. package/dist/build/popover.entry.js +1 -1
  11. package/dist/build/tabs.entry.js +2 -2
  12. package/package.json +9 -11
  13. package/src/Component/Accordion/__snapshots__/AccordionItem.stories.ts.snap +1 -1
  14. package/src/Component/Dialog/__snapshots__/Dialog.stories.ts.snap +6 -6
  15. package/src/Component/DropMenu/__snapshots__/DropMenu.stories.ts.snap +4 -4
  16. package/src/Component/Filters/__snapshots__/FilterItem.stories.ts.snap +2 -2
  17. package/src/Component/Filters/__snapshots__/Filters.stories.ts.snap +8 -8
  18. package/src/Component/GlobalAlert/__snapshots__/GlobalAlert.stories.ts.snap +2 -2
  19. package/src/Component/InPageNavigation/Elements/InPageNavigation.ts +22 -3
  20. package/src/Component/InPageNavigation/InPageNavigation.stories.ts +10 -0
  21. package/src/Component/InPageNavigation/__snapshots__/InPageNavigation.stories.ts.snap +24 -19
  22. package/src/Component/InPageNavigation/in-page-navigation.css +3 -1
  23. package/src/Component/InPageNavigation/in-page-navigation.twig +3 -2
  24. package/src/Component/Navigation/__snapshots__/Navigation.stories.ts.snap +18 -18
  25. package/src/Component/Popover/__snapshots__/Popover.stories.ts.snap +26 -26
  26. package/src/Component/Tabs/__snapshots__/Tabs.stories.ts.snap +8 -8
  27. package/src/Component/UtilityList/__snapshots__/UtilityList.stories.ts.snap +6 -6
  28. package/src/Form/FormItem/__snapshots__/FormItem.stories.ts.snap +8 -8
  29. package/src/Form/Search/search-form.twig +2 -1
  30. package/src/Form/Select/__snapshots__/Select.stories.ts.snap +1 -1
  31. package/src/Form/Textarea/__snapshots__/Textarea.stories.ts.snap +1 -1
  32. package/src/Layout/Header/__snapshots__/Header.stories.ts.snap +23 -23
  33. /package/dist/build/chunks/{Accordion-Dwh42fp7.js → Accordion-BzKLBuWL.js} +0 -0
  34. /package/dist/build/chunks/{Popover-Bws25suh.js → Popover-C4gisyxr.js} +0 -0
@@ -1 +1 @@
1
- import "./chunks/Popover-Bws25suh.js";
1
+ import "./chunks/Popover-C4gisyxr.js";
@@ -1,6 +1,6 @@
1
1
  import { i as makeAnchor, t as createElement } from "./chunks/utilities-DepaJdUg.js";
2
- import "./chunks/Popover-Bws25suh.js";
3
- import { t as DropMenu } from "./chunks/DropMenu-plGsgySm.js";
2
+ import "./chunks/Popover-C4gisyxr.js";
3
+ import { t as DropMenu } from "./chunks/DropMenu-LnJEp-sg.js";
4
4
  let PopoverPlacementModifier = /* @__PURE__ */ function(e) {
5
5
  return e.TOP = "top", e.TOP_START = "top-start", e.TOP_END = "top-end", e.RIGHT = "right", e.RIGHT_START = "right-start", e.RIGHT_END = "right-end", e.LEFT = "left", e.LEFT_START = "left-start", e.LEFT_END = "left-end", e.BOTTOM = "bottom", e.BOTTOM_START = "bottom-start", e.BOTTOM_END = "bottom-end", e;
6
6
  }({});
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.0.26",
4
+ "version": "0.0.27",
5
5
  "dependencies": {
6
6
  "@floating-ui/dom": "^1.7.4",
7
7
  "@oddbird/popover-polyfill": "^0.6.1",
@@ -17,9 +17,8 @@
17
17
  "react-stately": "^3.42.0"
18
18
  },
19
19
  "devDependencies": {
20
- "@csstools/postcss-global-data": "^3.1.0",
21
- "@csstools/stylelint-formatter-github": "^1.0.0",
22
- "@rollup/plugin-terser": "^0.4.4",
20
+ "@csstools/postcss-global-data": "^4.0.0",
21
+ "@csstools/stylelint-formatter-github": "^2.0.0",
23
22
  "@storybook/addon-a11y": "^10.1.4",
24
23
  "@storybook/addon-docs": "^10.1.4",
25
24
  "@storybook/addon-links": "^10.1.4",
@@ -32,7 +31,7 @@
32
31
  "@testing-library/jest-dom": "^6.9.1",
33
32
  "@testing-library/react": "^16.3.0",
34
33
  "@testing-library/user-event": "^14.6.1",
35
- "@types/node": "^24.10.1",
34
+ "@types/node": "^25.0.3",
36
35
  "@vitejs/plugin-react": "^5.1.1",
37
36
  "@vitest/browser-playwright": "^4.0.15",
38
37
  "@vitest/coverage-v8": "^4.0.15",
@@ -48,17 +47,16 @@
48
47
  "postcss-design-tokens": "^1.3.0",
49
48
  "postcss-inline-svg": "^6.0.0",
50
49
  "postcss-mixins": "^12.1.2",
51
- "postcss-preset-env": "^10.5.0",
50
+ "postcss-preset-env": "^11.1.1",
52
51
  "postcss-pxtorem": "^6.1.0",
53
52
  "prettier": "^3.7.4",
54
- "storybook": "^10.1.4",
55
- "stylelint": "^16.26.1",
56
- "stylelint-config-standard": "^39.0.1",
53
+ "storybook": "^10.1.10",
54
+ "stylelint": "^17.0.0",
55
+ "stylelint-config-standard": "^40.0.0",
57
56
  "stylelint-use-logical-spec": "^5.0.1",
58
- "tinyglobby": "^0.2.15",
59
57
  "twig": "^1.17.1",
60
58
  "typescript": "^5.9.3",
61
- "vite": "8.0.0-beta.0",
59
+ "vite": "8.0.0-beta.8",
62
60
  "vite-plugin-twig-drupal": "^1.6.2",
63
61
  "vitest": "^4.0.15"
64
62
  },
@@ -18,7 +18,7 @@ exports[`Accordion Item 1`] = `
18
18
 
19
19
  exports[`Div 1`] = `
20
20
  "<mx-accordiondiv class="mx-accordion mx-accordion--divided">
21
- <button type="button" class="mx-accordion__toggle" aria-expanded="false" aria-controls="music">
21
+ <button type="button" class="mx-accordion__toggle" aria-expanded="false" aria-controls="unique-0">
22
22
  Music
23
23
  <span class="mx-button mx-icon mx-button--small mx-button--icon-only mx-icon--chevron-down" aria-hidden="true"></span>
24
24
  </button>
@@ -3,14 +3,14 @@
3
3
  exports[`Dialog 1`] = `
4
4
  "
5
5
 
6
- <a href="#example-dialog" aria-controls="example-dialog">
6
+ <a href="#example-dialog" aria-controls="unique-0">
7
7
 
8
8
  <span>Open dialog</span>
9
9
 
10
10
  </a>
11
11
 
12
12
 
13
- <mx-dialog id="example-dialog">
13
+ <mx-dialog id="unique-0">
14
14
  <dialog class="mx-dialog">
15
15
  <button autofocus="" class="mx-button mx-button--icon-only mx-icon mx-icon--close" data-close="">Close dialog</button>
16
16
  <div class="mx-dialog__content mx-vertical-flow">
@@ -36,14 +36,14 @@ exports[`Dialog 1`] = `
36
36
  exports[`Fullscreen 1`] = `
37
37
  "
38
38
 
39
- <button aria-controls="example-fullscreen" class="mx-button mx-button--dark" type="button">
39
+ <button aria-controls="unique-0" class="mx-button mx-button--dark" type="button">
40
40
 
41
41
  <span>Open fullscreen modal</span>
42
42
 
43
43
  </button>
44
44
 
45
45
 
46
- <mx-dialog id="example-fullscreen" data-modal="">
46
+ <mx-dialog id="unique-0" data-modal="">
47
47
  <dialog class="mx-dialog mx-dialog--fullscreen">
48
48
  <button autofocus="" class="mx-button mx-button--icon-only mx-icon mx-icon--close" data-close="">Close dialog</button>
49
49
  <div class="mx-dialog__content mx-vertical-flow">
@@ -69,14 +69,14 @@ exports[`Fullscreen 1`] = `
69
69
  exports[`Modal 1`] = `
70
70
  "
71
71
 
72
- <button aria-controls="example-modal" class="mx-button mx-button--dark" type="button">
72
+ <button aria-controls="unique-0" class="mx-button mx-button--dark" type="button">
73
73
 
74
74
  <span>Open modal</span>
75
75
 
76
76
  </button>
77
77
 
78
78
 
79
- <mx-dialog id="example-modal" data-modal="">
79
+ <mx-dialog id="unique-0" data-modal="">
80
80
  <dialog class="mx-dialog">
81
81
  <button autofocus="" class="mx-button mx-button--icon-only mx-icon mx-icon--close" data-close="">Close dialog</button>
82
82
  <div class="mx-dialog__content mx-vertical-flow">
@@ -2,10 +2,10 @@
2
2
 
3
3
  exports[`Buttons 1`] = `
4
4
  "<mx-dropmenu closeonclick="">
5
- <button id="dropdown-menu-target" class="mx-popover__trigger mx-button mx-icon mx-icon--chevron-down mx-icon--end" popovertarget="dropdown-menu" style="anchor-name: --dropdown-menu">
5
+ <button id="unique-0" class="mx-popover__trigger mx-button mx-icon mx-icon--chevron-down mx-icon--end" popovertarget="dropdown-menu" style="anchor-name: --dropdown-menu">
6
6
  Categories
7
7
  </button>
8
- <div class="mx-popover mx-drop-menu" id="dropdown-menu" aria-describedby="dropdown-menu-target" style="position-anchor: --dropdown-menu" data-placement="bottom-start" popover="" role="menu">
8
+ <div class="mx-popover mx-drop-menu" id="dropdown-menu" aria-describedby="unique-0" style="position-anchor: --dropdown-menu" data-placement="bottom-start" popover="" role="menu">
9
9
  <button type="button" data-id="news" role="menuitemradio" aria-checked="false">News</button>
10
10
  <button type="button" data-id="events" role="menuitemradio" aria-checked="false">Events</button>
11
11
  <button type="button" data-id="stories" role="menuitemradio" aria-checked="false">Stories</button>
@@ -16,10 +16,10 @@ exports[`Buttons 1`] = `
16
16
 
17
17
  exports[`Drop Menu 1`] = `
18
18
  "<mx-dropmenu closeonclick="">
19
- <button id="dropdown-menu-target" class="mx-popover__trigger mx-button mx-icon mx-icon--chevron-down mx-icon--end" popovertarget="dropdown-menu" style="anchor-name: --dropdown-menu">
19
+ <button id="unique-0" class="mx-popover__trigger mx-button mx-icon mx-icon--chevron-down mx-icon--end" popovertarget="dropdown-menu" style="anchor-name: --dropdown-menu">
20
20
  Categories
21
21
  </button>
22
- <div class="mx-popover mx-drop-menu" id="dropdown-menu" aria-describedby="dropdown-menu-target" style="position-anchor: --dropdown-menu" data-placement="bottom-start" popover="">
22
+ <div class="mx-popover mx-drop-menu" id="dropdown-menu" aria-describedby="unique-0" style="position-anchor: --dropdown-menu" data-placement="bottom-start" popover="">
23
23
  <a href="#news">News</a>
24
24
  <a href="#events">Events</a>
25
25
  <a href="#stories">Stories</a>
@@ -46,12 +46,12 @@ exports[`Filters 1`] = `
46
46
 
47
47
  <label class="mx-label" for="filter-keywords">Keywords</label>
48
48
 
49
- <div class="mx-description" id="help-filter-keywords" role="tooltip">
49
+ <div class="mx-description" id="unique-0" role="tooltip">
50
50
  Search by keywords
51
51
  </div>
52
52
 
53
53
 
54
- <input class="mx-input__text" id="filter-keywords" name="example-keywords" type="text" value="" aria-describedby="help-filter-keywords">
54
+ <input class="mx-input__text" id="filter-keywords" name="unique-0" type="text" value="" aria-describedby="unique-0">
55
55
 
56
56
 
57
57
 
@@ -23,9 +23,9 @@ exports[`Collapsible Counter 1`] = `
23
23
 
24
24
 
25
25
 
26
- <input class="mx-input__text" id="filter-keywords" name="example-keywords" type="text" value="" aria-label="Keywords" aria-describedby="help-filter-keywords">
26
+ <input class="mx-input__text" id="filter-keywords" name="unique-0" type="text" value="" aria-label="Keywords" aria-describedby="unique-0">
27
27
 
28
- <div class="mx-description" id="help-filter-keywords" role="tooltip">
28
+ <div class="mx-description" id="unique-0" role="tooltip">
29
29
  Search by keywords
30
30
  </div>
31
31
 
@@ -120,12 +120,12 @@ exports[`Collapsible Right 1`] = `
120
120
 
121
121
  <div class="mx-form-item mx-accordion__content">
122
122
 
123
- <div class="mx-description" id="help-filter-keywords" role="tooltip">
123
+ <div class="mx-description" id="unique-0" role="tooltip">
124
124
  Search by keywords
125
125
  </div>
126
126
 
127
127
 
128
- <input class="mx-input__text" id="filter-keywords" name="example-keywords" type="text" value="" aria-label="Keywords" aria-describedby="help-filter-keywords">
128
+ <input class="mx-input__text" id="filter-keywords" name="unique-0" type="text" value="" aria-label="Keywords" aria-describedby="unique-0">
129
129
 
130
130
 
131
131
 
@@ -208,12 +208,12 @@ exports[`Filters 1`] = `
208
208
 
209
209
  <label class="mx-label" for="filter-keywords">Keywords</label>
210
210
 
211
- <div class="mx-description" id="help-filter-keywords" role="tooltip">
211
+ <div class="mx-description" id="unique-0" role="tooltip">
212
212
  Search by keywords
213
213
  </div>
214
214
 
215
215
 
216
- <input class="mx-input__text" id="filter-keywords" name="example-keywords" type="text" value="" aria-describedby="help-filter-keywords">
216
+ <input class="mx-input__text" id="filter-keywords" name="unique-0" type="text" value="" aria-describedby="unique-0">
217
217
 
218
218
 
219
219
 
@@ -286,12 +286,12 @@ exports[`Instant 1`] = `
286
286
 
287
287
  <label class="mx-label" for="filter-keywords">Keywords</label>
288
288
 
289
- <div class="mx-description" id="help-filter-keywords" role="tooltip">
289
+ <div class="mx-description" id="unique-0" role="tooltip">
290
290
  Search by keywords
291
291
  </div>
292
292
 
293
293
 
294
- <input class="mx-input__text" id="filter-keywords" name="example-keywords" type="text" value="" aria-describedby="help-filter-keywords">
294
+ <input class="mx-input__text" id="filter-keywords" name="unique-0" type="text" value="" aria-describedby="unique-0">
295
295
 
296
296
 
297
297
 
@@ -19,7 +19,7 @@ exports[`Critical 1`] = `
19
19
 
20
20
  exports[`Global Alert 1`] = `
21
21
  "
22
- <mx-closable-alert class="mx-global-alert mx-page mx-global-alert--light" id="light-alertlight">
22
+ <mx-closable-alert class="mx-global-alert mx-page mx-global-alert--light" id="unique-0">
23
23
  <div class="mx-global-alert__inner" data-container="">
24
24
  <div class="mx-global-alert__content">
25
25
 
@@ -28,7 +28,7 @@ exports[`Global Alert 1`] = `
28
28
  <p>Something happened that requires your attention</p>
29
29
 
30
30
  </div>
31
- <button class="mx-icon mx-icon--close" aria-controls="light-alertlight" aria-label="Close GlobalAlert" type="button"></button></div>
31
+ <button class="mx-icon mx-icon--close" aria-controls="unique-0" aria-label="Close GlobalAlert" type="button"></button></div>
32
32
  </mx-closable-alert>
33
33
 
34
34
  "
@@ -9,6 +9,8 @@ export default class InPageNavigation extends HTMLElement {
9
9
  internals_: ElementInternals
10
10
  controller: AbortController
11
11
  headingLevels: string
12
+ title: string
13
+ titleClass: string = "is-excluded mx-heading--m"
12
14
  items: { link: HTMLAnchorElement; heading: HTMLHeadingElement }[]
13
15
  active: { link: HTMLAnchorElement; heading: HTMLHeadingElement } | undefined
14
16
 
@@ -17,11 +19,16 @@ export default class InPageNavigation extends HTMLElement {
17
19
  this.internals_ = this.attachInternals()
18
20
  this.controller = new AbortController()
19
21
  this.headingLevels = this.dataset?.headings || "h2"
22
+ this.title = this.dataset?.title || "On this page"
20
23
  this.items = []
21
24
  }
22
25
 
23
26
  connectedCallback(): void {
24
27
  if (!this.menu || !this.headings) return
28
+ const headingElement: HTMLHeadingElement = createElement(
29
+ `<h2 class="${this.titleClass}">${this.title}</h2>`,
30
+ ) as HTMLHeadingElement
31
+ this.nav.insertBefore(headingElement, this.menu)
25
32
  if (!this.links.length) {
26
33
  // Build links if not provided.
27
34
  this.headings.forEach((heading: HTMLHeadingElement) => {
@@ -71,10 +78,22 @@ export default class InPageNavigation extends HTMLElement {
71
78
 
72
79
  get menu(): HTMLUListElement | HTMLOListElement | null {
73
80
  const menu: HTMLUListElement | HTMLOListElement | null = this.querySelector("ul, ol")
74
- if (!menu) {
75
- throw new Error(`${this.localName} must contain a <ul> or <ol> element.`)
81
+ if (menu) {
82
+ return menu
76
83
  }
77
- return menu
84
+ if (!this.nav) {
85
+ throw new Error(`${this.localName} must contain a <nav> element.`)
86
+ }
87
+ if (this.items.length === 0 && this.headings.length === 0) {
88
+ return null
89
+ }
90
+ const list = document.createElement("ul")
91
+ this.nav.appendChild(list)
92
+ return list
93
+ }
94
+
95
+ get nav(): HTMLElement | null {
96
+ return this.querySelector("nav")
78
97
  }
79
98
 
80
99
  get container(): HTMLElement | null {
@@ -98,3 +98,13 @@ export const Nested: Story = {
98
98
  levels: [HeadingTypes.TWO, HeadingTypes.THREE],
99
99
  },
100
100
  }
101
+
102
+ /**
103
+ * No headings found: page content contains no headings.
104
+ */
105
+ export const NoHeadings: Story = {
106
+ args: {
107
+ items: [],
108
+ levels: [HeadingTypes.FOUR],
109
+ },
110
+ }
@@ -1,14 +1,9 @@
1
1
  // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2
2
 
3
3
  exports[`Generated Items 1`] = `
4
- "<mx-in-page-navigation data-content=".js-content" data-headings="">
4
+ "<mx-in-page-navigation data-content=".js-content" data-headings="" data-title="On this page">
5
5
  <nav class="mx-nav mx-nav--list mx-in-page-navigation mx-vertical-flow">
6
-
7
- <h2 class="is-excluded mx-heading--m">On this page</h2>
8
-
9
- <ul>
10
- <li class="mx-in-page-navigation__level--h2"><a href="#section-1"><span class="mx-icon mx-icon--chevron-right"></span><span>Section 1</span></a></li><li class="mx-in-page-navigation__level--h2"><a href="#section-2"><span class="mx-icon mx-icon--chevron-right"></span><span>Section 2</span></a></li><li class="mx-in-page-navigation__level--h2"><a href="#section-3"><span class="mx-icon mx-icon--chevron-right"></span><span>Section 3</span></a></li></ul>
11
- </nav>
6
+ <h2 class="is-excluded mx-heading--m">On this page</h2><ul><li class="mx-in-page-navigation__level--h2"><a href="#section-1"><span class="mx-icon mx-icon--chevron-right"></span><span>Section 1</span></a></li><li class="mx-in-page-navigation__level--h2"><a href="#section-2"><span class="mx-icon mx-icon--chevron-right"></span><span>Section 2</span></a></li><li class="mx-in-page-navigation__level--h2"><a href="#section-3"><span class="mx-icon mx-icon--chevron-right"></span><span>Section 3</span></a></li></ul></nav>
12
7
  </mx-in-page-navigation>
13
8
  <div class="js-content mx-rich-text mx-vertical-flow mx-section--l">
14
9
  <h2 id="section-1">Section 1</h2>
@@ -24,12 +19,9 @@ exports[`Generated Items 1`] = `
24
19
  `;
25
20
 
26
21
  exports[`In Page Navigation 1`] = `
27
- "<mx-in-page-navigation data-content=".js-content" data-headings="">
22
+ "<mx-in-page-navigation data-content=".js-content" data-headings="" data-title="On this page">
28
23
  <nav class="mx-nav mx-nav--list mx-in-page-navigation mx-vertical-flow">
29
-
30
- <h2 class="is-excluded mx-heading--m">On this page</h2>
31
-
32
- <ul>
24
+ <h2 class="is-excluded mx-heading--m">On this page</h2><ul>
33
25
  <li>
34
26
  <a href="#section-1">
35
27
 
@@ -58,7 +50,7 @@ exports[`In Page Navigation 1`] = `
58
50
  </a>
59
51
  </li>
60
52
  </ul>
61
- </nav>
53
+ </nav>
62
54
  </mx-in-page-navigation>
63
55
  <div class="js-content mx-rich-text mx-vertical-flow mx-section--l">
64
56
  <h2 id="section-1">Section 1</h2>
@@ -74,14 +66,27 @@ exports[`In Page Navigation 1`] = `
74
66
  `;
75
67
 
76
68
  exports[`Nested 1`] = `
77
- "<mx-in-page-navigation data-content=".js-content" data-headings="h2,h3">
69
+ "<mx-in-page-navigation data-content=".js-content" data-headings="h2,h3" data-title="On this page">
78
70
  <nav class="mx-nav mx-nav--list mx-in-page-navigation mx-vertical-flow">
79
-
80
- <h2 class="is-excluded mx-heading--m">On this page</h2>
71
+ <h2 class="is-excluded mx-heading--m">On this page</h2><ul><li class="mx-in-page-navigation__level--h2"><a href="#section-1"><span class="mx-icon mx-icon--chevron-right"></span><span>Section 1</span></a></li><li class="mx-in-page-navigation__level--h2"><a href="#section-2"><span class="mx-icon mx-icon--chevron-right"></span><span>Section 2</span></a></li><li class="mx-in-page-navigation__level--h3"><a href="#test-level-3"><span class="mx-icon mx-icon--chevron-right"></span><span>Test level 3</span></a></li><li class="mx-in-page-navigation__level--h2"><a href="#section-3"><span class="mx-icon mx-icon--chevron-right"></span><span>Section 3</span></a></li></ul></nav>
72
+ </mx-in-page-navigation>
73
+ <div class="js-content mx-rich-text mx-vertical-flow mx-section--l">
74
+ <h2 id="section-1">Section 1</h2>
75
+ <p>In publishing and graphic design, lorem ipsum is a placeholder text commonly used to demonstrate the visual form of a document without relying on meaningful content. Replacing the actual content with placeholder text allows designers to design the form of the content before the content itself has been produced.</p>
76
+ <h2 id="section-2">Section 2</h2>
77
+ <p>In publishing and graphic design, lorem ipsum is a placeholder text commonly used to demonstrate the visual form of a document without relying on meaningful content. Replacing the actual content with placeholder text allows designers to design the form of the content before the content itself has been produced.</p>
78
+ <h3 id="test-level-3">Test level 3</h3>
79
+ <p>In publishing and graphic design, lorem ipsum is a placeholder text commonly used to demonstrate the visual form of a document without relying on meaningful content. Replacing the actual content with placeholder text allows designers to design the form of the content before the content itself has been produced.</p>
80
+ <h2 id="section-3">Section 3</h2>
81
+ <p>In publishing and graphic design, lorem ipsum is a placeholder text commonly used to demonstrate the visual form of a document without relying on meaningful content. Replacing the actual content with placeholder text allows designers to design the form of the content before the content itself has been produced.</p>
82
+ </div>
83
+ "
84
+ `;
81
85
 
82
- <ul>
83
- <li class="mx-in-page-navigation__level--h2"><a href="#section-1"><span class="mx-icon mx-icon--chevron-right"></span><span>Section 1</span></a></li><li class="mx-in-page-navigation__level--h2"><a href="#section-2"><span class="mx-icon mx-icon--chevron-right"></span><span>Section 2</span></a></li><li class="mx-in-page-navigation__level--h3"><a href="#test-level-3"><span class="mx-icon mx-icon--chevron-right"></span><span>Test level 3</span></a></li><li class="mx-in-page-navigation__level--h2"><a href="#section-3"><span class="mx-icon mx-icon--chevron-right"></span><span>Section 3</span></a></li></ul>
84
- </nav>
86
+ exports[`No Headings 1`] = `
87
+ "<mx-in-page-navigation data-content=".js-content" data-headings="h4" data-title="On this page">
88
+ <nav class="mx-nav mx-nav--list mx-in-page-navigation mx-vertical-flow">
89
+ </nav>
85
90
  </mx-in-page-navigation>
86
91
  <div class="js-content mx-rich-text mx-vertical-flow mx-section--l">
87
92
  <h2 id="section-1">Section 1</h2>
@@ -13,7 +13,9 @@
13
13
  --link-colour: var(--colour-link);
14
14
  --nav-underline: underline;
15
15
 
16
- margin-block-end: var(--flow-gap, var(--gap));
16
+ &:has(ul, ol) {
17
+ margin-block-end: var(--flow-gap, var(--gap));
18
+ }
17
19
 
18
20
  & .mx-in-page-navigation__level--h3 {
19
21
  padding-inline-start: var(--indent, var(--spacing-s));
@@ -5,13 +5,14 @@
5
5
  'mx-vertical-flow'
6
6
  ] %}
7
7
  {% set attributes = (attributes ?? create_attribute()).addClass(classes) %}
8
- <mx-in-page-navigation data-content=".js-content" data-headings="{{ levels|join(",") }}">
8
+ <mx-in-page-navigation data-content=".js-content" data-headings="{{ levels|join(",") }}" data-title="{{ title|striptags|trim }}">
9
9
  <nav{{ attributes }}>
10
- {{ title }}
10
+ {% if items %}
11
11
  <ul>
12
12
  {% for item in items %}
13
13
  <li>{{ item }}</li>
14
14
  {% endfor %}
15
15
  </ul>
16
+ {% endif %}
16
17
  </nav>
17
18
  </mx-in-page-navigation>
@@ -12,22 +12,22 @@ exports[`Collapsible 1`] = `
12
12
  </a>
13
13
  </li>
14
14
  <li class="mx-nav__has-subnav">
15
- <a href="#" id="list-label-subnav-0--what-we-do">
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="subnav-0--what-we-do">Sub-navigation</button>
19
- <ul class="mx-nav__level-2" inert="" id="subnav-0--what-we-do" aria-labelledby="list-label-subnav-0--what-we-do">
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>
19
+ <ul class="mx-nav__level-2" inert="" id="unique-0" aria-labelledby="unique-1">
20
20
  <li>
21
21
  <a href="#">
22
22
  Events
23
23
  </a>
24
24
  </li>
25
25
  <li class="mx-nav__has-subnav">
26
- <a href="#" id="list-label-subnav-1--who-we-are">
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="subnav-1--who-we-are">Sub-navigation</button>
30
- <ul class="mx-nav__level-3" inert="" id="subnav-1--who-we-are" aria-labelledby="list-label-subnav-1--who-we-are">
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>
30
+ <ul class="mx-nav__level-3" inert="" id="unique-1" aria-labelledby="unique-3">
31
31
  <li>
32
32
  <a href="#">
33
33
  Our team
@@ -88,11 +88,11 @@ exports[`Dropdown 1`] = `
88
88
  </a>
89
89
  </li>
90
90
  <li class="mx-nav__has-subnav">
91
- <a href="#" id="list-label-subnav-0--what-we-do">
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="subnav-0--what-we-do">Sub-navigation</button>
95
- <ul class="mx-nav__level-2" inert="" id="subnav-0--what-we-do" aria-labelledby="list-label-subnav-0--what-we-do">
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>
95
+ <ul class="mx-nav__level-2" inert="" id="unique-0" aria-labelledby="unique-1">
96
96
  <li>
97
97
  <a href="#">
98
98
  Events
@@ -145,17 +145,17 @@ exports[`Mega 1`] = `
145
145
  </a>
146
146
  </li>
147
147
  <li class="mx-nav__has-subnav">
148
- <a href="#" id="list-label-subnav-0--about">
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="subnav-0--about">Sub-navigation</button>
152
- <ul class="mx-nav__level-2" inert="" id="subnav-0--about" aria-labelledby="list-label-subnav-0--about">
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>
152
+ <ul class="mx-nav__level-2" inert="" id="unique-0" aria-labelledby="unique-1">
153
153
  <li class="mx-nav__has-subnav">
154
- <a href="#" aria-current="page" id="list-label-subnav-1--who">
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="subnav-1--who">Sub-navigation</button>
158
- <ul class="mx-nav__level-3" inert="" id="subnav-1--who" aria-labelledby="list-label-subnav-1--who">
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>
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">
161
161
  How come?
@@ -188,11 +188,11 @@ exports[`Mega 1`] = `
188
188
 
189
189
  </li>
190
190
  <li class="mx-nav__has-subnav">
191
- <a href="#" id="list-label-subnav-2--contact">
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="subnav-2--contact">Sub-navigation</button>
195
- <ul class="mx-nav__level-2" inert="" id="subnav-2--contact" aria-labelledby="list-label-subnav-2--contact">
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>
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">
198
198
  How