@pnx-mixtape/mxds 0.1.0-rc.0 → 0.1.0-rc.2
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.
- package/.storybook/decorators.ts +15 -0
- package/.storybook/preview.ts +4 -1
- package/.storybook/themes/campus-vibrant.css +181 -0
- package/.storybook/themes/civic-formal.css +246 -0
- package/.storybook/{theme-demo.css → themes/demo.css} +14 -7
- package/.storybook/themes/health-services.css +255 -0
- package/.storybook/themes/research-faculty.css +169 -0
- package/dist/build/accordion.css +1 -1
- package/dist/build/base.css +1 -1
- package/dist/build/button.css +1 -1
- package/dist/build/chunks/DropMenu-1baQc8Yc.js +1 -0
- package/dist/build/chunks/InPageNavigation-CVieEl9u.js +1 -0
- package/dist/build/chunks/Popover-Cxg-s5Jn.js +1 -0
- package/dist/build/chunks/Sticky-cWUVSOXN.js +1 -0
- package/dist/build/chunks/{Tabs-Dm8g301e.js → Tabs-DA_Ez8pv.js} +2 -2
- package/dist/build/chunks/polyfills-C7pRt54M.js +1 -0
- package/dist/build/constants.css +1 -1
- package/dist/build/drop-menu.css +1 -1
- package/dist/build/drop-menu.entry.js +1 -1
- package/dist/build/elements.js +1 -1
- package/dist/build/form.css +1 -1
- package/dist/build/grid.css +1 -1
- package/dist/build/header.css +1 -1
- package/dist/build/icon.css +1 -1
- package/dist/build/in-page-alert.css +1 -1
- package/dist/build/in-page-navigation.entry.js +1 -1
- package/dist/build/navigation.css +1 -1
- package/dist/build/pagination.css +1 -1
- package/dist/build/popover.entry.js +1 -1
- package/dist/build/print.css +1 -1
- package/dist/build/progress-indicator.css +1 -0
- package/dist/build/react.js +1 -1
- package/dist/build/side-navigation.css +1 -1
- package/dist/build/sidebar.css +1 -1
- package/dist/build/steps.css +1 -1
- package/dist/build/sticky.entry.js +1 -1
- package/dist/build/tabs.entry.js +1 -1
- package/dist/build/tag.css +1 -1
- package/dist/build/utilities.css +1 -1
- package/dist/types/Atom/DefinitionList/DefinitionList.d.ts +3 -2
- package/dist/types/Atom/DefinitionList/DefinitionList.d.ts.map +1 -1
- package/dist/types/Atom/Heading/Heading.d.ts.map +1 -1
- package/dist/types/Atom/List/List.d.ts +10 -0
- package/dist/types/Atom/List/List.d.ts.map +1 -0
- package/dist/types/Component/DropMenu/Elements/DropMenu.d.ts.map +1 -1
- package/dist/types/Component/InPageNavigation/Elements/InPageNavigation.d.ts +2 -2
- package/dist/types/Component/InPageNavigation/Elements/InPageNavigation.d.ts.map +1 -1
- package/dist/types/Component/InPageNavigation/Hooks/useInPageNavigation.d.ts.map +1 -1
- package/dist/types/Component/ProgressIndicator/ProgressIndicator.d.ts +9 -0
- package/dist/types/Component/ProgressIndicator/ProgressIndicator.d.ts.map +1 -0
- package/dist/types/Component/Tabs/Elements/Tabs.d.ts.map +1 -1
- package/dist/types/Component/Tag/Tag.d.ts +4 -2
- package/dist/types/Component/Tag/Tag.d.ts.map +1 -1
- package/dist/types/Form/Autocomplete/Autocomplete.d.ts.map +1 -1
- package/dist/types/Form/Checkbox/FormCheckbox.d.ts.map +1 -1
- package/dist/types/Form/CheckboxCard/CheckboxCard.d.ts +23 -0
- package/dist/types/Form/CheckboxCard/CheckboxCard.d.ts.map +1 -0
- package/dist/types/Form/Radio/FormRadio.d.ts.map +1 -1
- package/dist/types/Form/RadioCard/RadioCard.d.ts +16 -0
- package/dist/types/Form/RadioCard/RadioCard.d.ts.map +1 -0
- package/dist/types/Form/Select/FormSelect.d.ts.map +1 -1
- package/dist/types/Form/TextInput/FormText.d.ts.map +1 -1
- package/dist/types/Form/Textarea/FormTextarea.d.ts.map +1 -1
- package/dist/types/enums.d.ts +15 -0
- package/dist/types/enums.d.ts.map +1 -1
- package/dist/types/react.d.ts +4 -0
- package/dist/types/react.d.ts.map +1 -1
- package/package.json +7 -8
- package/src/Atom/Background/_background.css +2 -2
- package/src/Atom/Blockquote/_blockquote.css +9 -2
- package/src/Atom/Button/README.md +1 -0
- package/src/Atom/Button/_buttons-styles.css +6 -6
- package/src/Atom/Button/_buttons.css +6 -3
- package/src/Atom/DefinitionList/DefinitionList.stories.ts +39 -2
- package/src/Atom/DefinitionList/DefinitionList.stories.tsx +36 -0
- package/src/Atom/DefinitionList/DefinitionList.tsx +4 -1
- package/src/Atom/DefinitionList/DefinitionListItem.stories.ts +1 -1
- package/src/Atom/DefinitionList/README.md +43 -0
- package/src/Atom/DefinitionList/__snapshots__/DefinitionList.stories.ts.snap +37 -3
- package/src/Atom/DefinitionList/__snapshots__/DefinitionList.stories.tsx.snap +2 -0
- package/src/Atom/DefinitionList/__snapshots__/DefinitionListItem.stories.ts.snap +3 -3
- package/src/Atom/DefinitionList/definition-list-item.twig +1 -0
- package/src/Atom/DefinitionList/definition-list.twig +6 -1
- package/src/Atom/Heading/Heading.tsx +6 -0
- package/src/Atom/Heading/_headings.css +2 -1
- package/src/Atom/Icon/_extended-set.css +30 -30
- package/src/Atom/Icon/_icon.css +37 -36
- package/src/Atom/Image/README.md +2 -2
- package/src/Atom/Image/_image.css +12 -6
- package/src/Atom/List/List.stories.ts +102 -0
- package/src/Atom/List/List.stories.tsx +103 -0
- package/src/Atom/List/List.tsx +22 -0
- package/src/Atom/List/README.md +150 -0
- package/src/Atom/List/__snapshots__/List.stories.ts.snap +43 -0
- package/src/Atom/List/__snapshots__/List.stories.tsx.snap +13 -0
- package/src/Atom/List/_list.css +123 -0
- package/src/Atom/List/list.twig +5 -0
- package/src/Atom/Media/Media.stories.ts +1 -1
- package/src/Atom/Media/__snapshots__/Media.stories.ts.snap +2 -2
- package/src/Atom/Spacing/_spacing.css +24 -24
- package/src/Atom/Table/__snapshots__/Table.stories.ts.snap +24 -4
- package/src/Atom/Table/_table.css +15 -3
- package/src/Atom/Table/table.twig +6 -1
- package/src/Atom/Text/__snapshots__/Text.stories.ts.snap +3 -2
- package/src/Atom/Text/_text-styles.css +21 -1
- package/src/Atom/Text/twig/text-styles-example.twig +3 -2
- package/src/Atom/_base.css +6 -0
- package/src/Atom/_flow.css +1 -1
- package/src/Atom/_generic.css +18 -11
- package/src/Component/Accordion/accordion.css +2 -0
- package/src/Component/Card/__snapshots__/Card.stories.ts.snap +2 -2
- package/src/Component/Card/card.twig +1 -1
- package/src/Component/Carousel/Carousel.stories.ts +46 -23
- package/src/Component/DropMenu/Elements/DropMenu.ts +10 -1
- package/src/Component/InPageAlert/in-page-alert.css +2 -1
- package/src/Component/InPageNavigation/Elements/InPageNavigation.ts +10 -5
- package/src/Component/InPageNavigation/Hooks/useInPageNavigation.ts +10 -5
- package/src/Component/InPageNavigation/InPageNavigation.stories.ts +33 -0
- package/src/Component/InPageNavigation/InPageNavigation.stories.tsx +52 -0
- package/src/Component/InPageNavigation/__snapshots__/InPageNavigation.stories.ts.snap +26 -0
- package/src/Component/InPageNavigation/__snapshots__/InPageNavigation.stories.tsx.snap +2 -0
- package/src/Component/InPageNavigation/twig/content-example-duplicate-headings.twig +20 -0
- package/src/Component/InPageNavigation/twig/in-page-navigation-story-duplicate-headings.twig +2 -0
- package/src/Component/ListItem/__snapshots__/ListItem.stories.ts.snap +4 -4
- package/src/Component/ListItem/list-item.twig +2 -2
- package/src/Component/Navigation/_navigation.css +1 -1
- package/src/Component/Pagination/Pagination.stories.ts +8 -4
- package/src/Component/Pagination/pagination.css +3 -3
- package/src/Component/ProgressIndicator/ProgressIndicator.stories.ts +36 -0
- package/src/Component/ProgressIndicator/ProgressIndicator.stories.tsx +30 -0
- package/src/Component/ProgressIndicator/ProgressIndicator.tsx +60 -0
- package/src/Component/ProgressIndicator/README.md +111 -0
- package/src/Component/ProgressIndicator/__snapshots__/ProgressIndicator.stories.ts.snap +67 -0
- package/src/Component/ProgressIndicator/__snapshots__/ProgressIndicator.stories.tsx.snap +7 -0
- package/src/Component/ProgressIndicator/progress-indicator.css +59 -0
- package/src/Component/ProgressIndicator/progress-indicator.twig +22 -0
- package/src/Component/Sticky/Elements/Sticky.ts +1 -1
- package/src/Component/Sticky/sticky.css +3 -3
- package/src/Component/Tabs/Elements/Tabs.ts +3 -1
- package/src/Component/Tabs/Tabs.stories.ts +55 -21
- package/src/Component/Tabs/__snapshots__/Tabs.stories.ts.snap +2 -2
- package/src/Component/Tag/README.md +52 -26
- package/src/Component/Tag/Tag.stories.tsx +24 -0
- package/src/Component/Tag/Tag.tsx +12 -2
- package/src/Component/Tag/TagItem.stories.ts +25 -0
- package/src/Component/Tag/__snapshots__/Tag.stories.ts.snap +2 -2
- package/src/Component/Tag/__snapshots__/Tag.stories.tsx.snap +2 -0
- package/src/Component/Tag/tag-item.twig +2 -2
- package/src/Component/Tag/tag.css +76 -2
- package/src/Form/Autocomplete/Autocomplete.stories.ts +8 -3
- package/src/Form/Autocomplete/Autocomplete.tsx +1 -4
- package/src/Form/Autocomplete/README.md +26 -26
- package/src/Form/Autocomplete/__snapshots__/Autocomplete.stories.ts.snap +1 -1
- package/src/Form/Autocomplete/__snapshots__/Autocomplete.stories.tsx.snap +1 -1
- package/src/Form/Autocomplete/autocomplete.twig +0 -2
- package/src/Form/Checkbox/FormCheckbox.tsx +2 -8
- package/src/Form/Checkbox/README.md +23 -18
- package/src/Form/Checkbox/input-checkbox.twig +0 -2
- package/src/Form/CheckboxCard/CheckboxCard.stories.ts +90 -0
- package/src/Form/CheckboxCard/CheckboxCard.stories.tsx +43 -0
- package/src/Form/CheckboxCard/CheckboxCard.tsx +102 -0
- package/src/Form/CheckboxCard/README.md +163 -0
- package/src/Form/CheckboxCard/__snapshots__/CheckboxCard.stories.ts.snap +63 -0
- package/src/Form/CheckboxCard/__snapshots__/CheckboxCard.stories.tsx.snap +7 -0
- package/src/Form/CheckboxCard/checkbox-card.twig +29 -0
- package/src/Form/FormItem/__snapshots__/FormItem.stories.ts.snap +2 -2
- package/src/Form/README.md +65 -13
- package/src/Form/Radio/FormRadio.tsx +1 -4
- package/src/Form/Radio/input-radio.twig +0 -2
- package/src/Form/RadioCard/README.md +146 -0
- package/src/Form/RadioCard/RadioCard.stories.ts +95 -0
- package/src/Form/RadioCard/RadioCard.stories.tsx +26 -0
- package/src/Form/RadioCard/RadioCard.tsx +59 -0
- package/src/Form/RadioCard/__snapshots__/RadioCard.stories.ts.snap +69 -0
- package/src/Form/RadioCard/__snapshots__/RadioCard.stories.tsx.snap +3 -0
- package/src/Form/RadioCard/radio-card.twig +20 -0
- package/src/Form/Select/FormSelect.tsx +1 -4
- package/src/Form/Select/input-select.twig +0 -2
- package/src/Form/TextInput/FormText.stories.tsx +14 -0
- package/src/Form/TextInput/FormText.tsx +1 -4
- package/src/Form/TextInput/__snapshots__/FormText.stories.tsx.snap +2 -0
- package/src/Form/TextInput/input-text.twig +0 -2
- package/src/Form/Textarea/FormTextarea.tsx +1 -4
- package/src/Form/Textarea/input-textarea.twig +0 -2
- package/src/Form/Validation.stories.ts +153 -0
- package/src/Form/__snapshots__/Validation.stories.ts.snap +130 -0
- package/src/Form/form.css +155 -28
- package/src/Layout/Grid/grid.css +4 -4
- package/src/Layout/Sidebar/__snapshots__/Sidebar.stories.ts.snap +5 -5
- package/src/Layout/Sidebar/sidebar.css +1 -0
- package/src/Layout/Sidebar/sidebar.twig +1 -1
- package/src/Utility/_layout-utils.css +8 -0
- package/src/Utility/print.css +50 -28
- package/src/Utility/utilities.css +2 -2
- package/src/constants.css +12 -2
- package/src/enums.ts +17 -0
- package/src/react.ts +4 -0
- package/tools/lib/extract-classnames.mjs +0 -0
- package/tools/lint-classnames.mjs +1 -1
- package/dist/build/chunks/DropMenu-Co9jZZ4S.js +0 -1
- package/dist/build/chunks/InPageNavigation-CzR_KZaz.js +0 -1
- package/dist/build/chunks/Popover-De_CQqcd.js +0 -1
- package/dist/build/chunks/Sticky-Kyjykb36.js +0 -1
- package/dist/build/chunks/polyfills-Dokbkxxk.js +0 -1
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
|
2
|
+
|
|
3
|
+
exports[`Last Step 1`] = `
|
|
4
|
+
"
|
|
5
|
+
<div class="mx-progress-indicator">
|
|
6
|
+
<p class="mx-progress-indicator__count">Step 5 of 5 — Review and submit</p>
|
|
7
|
+
<div class="mx-progress-indicator__track" aria-hidden="true">
|
|
8
|
+
<i class="mx-progress-indicator__marker mx-progress-indicator__marker--done"></i>
|
|
9
|
+
<i class="mx-progress-indicator__marker mx-progress-indicator__marker--done"></i>
|
|
10
|
+
<i class="mx-progress-indicator__marker mx-progress-indicator__marker--done"></i>
|
|
11
|
+
<i class="mx-progress-indicator__marker mx-progress-indicator__marker--done"></i>
|
|
12
|
+
<i class="mx-progress-indicator__marker mx-progress-indicator__marker--now"></i>
|
|
13
|
+
</div>
|
|
14
|
+
<ol class="mx-progress-indicator__steps">
|
|
15
|
+
<li class="mx-progress-indicator__step mx-progress-indicator__step--done">Your card</li>
|
|
16
|
+
<li class="mx-progress-indicator__step mx-progress-indicator__step--done">Your details</li>
|
|
17
|
+
<li class="mx-progress-indicator__step mx-progress-indicator__step--done">Your income</li>
|
|
18
|
+
<li class="mx-progress-indicator__step mx-progress-indicator__step--done">Evidence</li>
|
|
19
|
+
<li class="mx-progress-indicator__step" aria-current="step">Review and submit</li>
|
|
20
|
+
</ol>
|
|
21
|
+
</div>
|
|
22
|
+
"
|
|
23
|
+
`;
|
|
24
|
+
|
|
25
|
+
exports[`Middle Step 1`] = `
|
|
26
|
+
"
|
|
27
|
+
<div class="mx-progress-indicator">
|
|
28
|
+
<p class="mx-progress-indicator__count">Step 3 of 5 — Your income</p>
|
|
29
|
+
<div class="mx-progress-indicator__track" aria-hidden="true">
|
|
30
|
+
<i class="mx-progress-indicator__marker mx-progress-indicator__marker--done"></i>
|
|
31
|
+
<i class="mx-progress-indicator__marker mx-progress-indicator__marker--done"></i>
|
|
32
|
+
<i class="mx-progress-indicator__marker mx-progress-indicator__marker--now"></i>
|
|
33
|
+
<i class="mx-progress-indicator__marker"></i>
|
|
34
|
+
<i class="mx-progress-indicator__marker"></i>
|
|
35
|
+
</div>
|
|
36
|
+
<ol class="mx-progress-indicator__steps">
|
|
37
|
+
<li class="mx-progress-indicator__step mx-progress-indicator__step--done">Your card</li>
|
|
38
|
+
<li class="mx-progress-indicator__step mx-progress-indicator__step--done">Your details</li>
|
|
39
|
+
<li class="mx-progress-indicator__step" aria-current="step">Your income</li>
|
|
40
|
+
<li class="mx-progress-indicator__step">Evidence</li>
|
|
41
|
+
<li class="mx-progress-indicator__step">Review and submit</li>
|
|
42
|
+
</ol>
|
|
43
|
+
</div>
|
|
44
|
+
"
|
|
45
|
+
`;
|
|
46
|
+
|
|
47
|
+
exports[`Progress Indicator 1`] = `
|
|
48
|
+
"
|
|
49
|
+
<div class="mx-progress-indicator">
|
|
50
|
+
<p class="mx-progress-indicator__count">Step 1 of 5 — Your card</p>
|
|
51
|
+
<div class="mx-progress-indicator__track" aria-hidden="true">
|
|
52
|
+
<i class="mx-progress-indicator__marker mx-progress-indicator__marker--now"></i>
|
|
53
|
+
<i class="mx-progress-indicator__marker"></i>
|
|
54
|
+
<i class="mx-progress-indicator__marker"></i>
|
|
55
|
+
<i class="mx-progress-indicator__marker"></i>
|
|
56
|
+
<i class="mx-progress-indicator__marker"></i>
|
|
57
|
+
</div>
|
|
58
|
+
<ol class="mx-progress-indicator__steps">
|
|
59
|
+
<li class="mx-progress-indicator__step" aria-current="step">Your card</li>
|
|
60
|
+
<li class="mx-progress-indicator__step">Your details</li>
|
|
61
|
+
<li class="mx-progress-indicator__step">Your income</li>
|
|
62
|
+
<li class="mx-progress-indicator__step">Evidence</li>
|
|
63
|
+
<li class="mx-progress-indicator__step">Review and submit</li>
|
|
64
|
+
</ol>
|
|
65
|
+
</div>
|
|
66
|
+
"
|
|
67
|
+
`;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
|
2
|
+
|
|
3
|
+
exports[`Last Step 1`] = `"<div class="mx-progress-indicator"><p class="mx-progress-indicator__count">Step 5 of 5 — Review and submit</p><div class="mx-progress-indicator__track" aria-hidden="true"><i class="mx-progress-indicator__marker mx-progress-indicator__marker--done"></i><i class="mx-progress-indicator__marker mx-progress-indicator__marker--done"></i><i class="mx-progress-indicator__marker mx-progress-indicator__marker--done"></i><i class="mx-progress-indicator__marker mx-progress-indicator__marker--done"></i><i class="mx-progress-indicator__marker mx-progress-indicator__marker--now"></i></div><ol class="mx-progress-indicator__steps"><li class="mx-progress-indicator__step mx-progress-indicator__step--done">Your card</li><li class="mx-progress-indicator__step mx-progress-indicator__step--done">Your details</li><li class="mx-progress-indicator__step mx-progress-indicator__step--done">Your income</li><li class="mx-progress-indicator__step mx-progress-indicator__step--done">Evidence</li><li class="mx-progress-indicator__step" aria-current="step">Review and submit</li></ol></div>"`;
|
|
4
|
+
|
|
5
|
+
exports[`Middle Step 1`] = `"<div class="mx-progress-indicator"><p class="mx-progress-indicator__count">Step 3 of 5 — Your income</p><div class="mx-progress-indicator__track" aria-hidden="true"><i class="mx-progress-indicator__marker mx-progress-indicator__marker--done"></i><i class="mx-progress-indicator__marker mx-progress-indicator__marker--done"></i><i class="mx-progress-indicator__marker mx-progress-indicator__marker--now"></i><i class="mx-progress-indicator__marker"></i><i class="mx-progress-indicator__marker"></i></div><ol class="mx-progress-indicator__steps"><li class="mx-progress-indicator__step mx-progress-indicator__step--done">Your card</li><li class="mx-progress-indicator__step mx-progress-indicator__step--done">Your details</li><li class="mx-progress-indicator__step" aria-current="step">Your income</li><li class="mx-progress-indicator__step">Evidence</li><li class="mx-progress-indicator__step">Review and submit</li></ol></div>"`;
|
|
6
|
+
|
|
7
|
+
exports[`Progress Indicator 1`] = `"<div class="mx-progress-indicator"><p class="mx-progress-indicator__count">Step 1 of 5 — Your card</p><div class="mx-progress-indicator__track" aria-hidden="true"><i class="mx-progress-indicator__marker mx-progress-indicator__marker--now"></i><i class="mx-progress-indicator__marker"></i><i class="mx-progress-indicator__marker"></i><i class="mx-progress-indicator__marker"></i><i class="mx-progress-indicator__marker"></i></div><ol class="mx-progress-indicator__steps"><li class="mx-progress-indicator__step" aria-current="step">Your card</li><li class="mx-progress-indicator__step">Your details</li><li class="mx-progress-indicator__step">Your income</li><li class="mx-progress-indicator__step">Evidence</li><li class="mx-progress-indicator__step">Review and submit</li></ol></div>"`;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ProgressIndicator
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
@layer design-system.components {
|
|
6
|
+
.mx-progress-indicator {
|
|
7
|
+
/* @public --gap */
|
|
8
|
+
display: grid;
|
|
9
|
+
gap: var(--gap, var(--spacing-xs));
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
.mx-progress-indicator__count {
|
|
13
|
+
margin: 0;
|
|
14
|
+
font-size: var(--font-size-s);
|
|
15
|
+
font-weight: var(--font-weight-bold);
|
|
16
|
+
color: var(--colour-foreground-alt);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.mx-progress-indicator__track {
|
|
20
|
+
/* @public --track-gap --marker-size --marker-colour --marker-colour-complete --marker-colour-active */
|
|
21
|
+
display: flex;
|
|
22
|
+
gap: var(--track-gap, var(--spacing-xxxs));
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
.mx-progress-indicator__marker {
|
|
26
|
+
flex: 1;
|
|
27
|
+
block-size: var(--marker-size, var(--spacing-xxxs));
|
|
28
|
+
border-radius: var(--border-radius);
|
|
29
|
+
background-color: var(--marker-colour, var(--colour-border));
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.mx-progress-indicator__marker--done {
|
|
33
|
+
background-color: var(--marker-colour-complete, var(--colour-primary));
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
.mx-progress-indicator__marker--now {
|
|
37
|
+
background-color: var(--marker-colour-active, var(--colour-primary));
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
.mx-progress-indicator__steps {
|
|
41
|
+
display: flex;
|
|
42
|
+
flex-wrap: wrap;
|
|
43
|
+
gap: var(--spacing-xxxs) var(--spacing-m);
|
|
44
|
+
margin: 0;
|
|
45
|
+
padding-inline-start: 0;
|
|
46
|
+
list-style: none;
|
|
47
|
+
font-size: var(--font-size-xs);
|
|
48
|
+
color: var(--colour-foreground-alt);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.mx-progress-indicator__step[aria-current="step"] {
|
|
52
|
+
color: var(--marker-colour-active, var(--colour-primary));
|
|
53
|
+
font-weight: var(--font-weight-bold);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
.mx-progress-indicator__step--done::before {
|
|
57
|
+
content: "✓ ";
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{% set attributes = (attributes ?? create_attribute()).addClass('mx-progress-indicator') %}
|
|
2
|
+
{% set total = steps|length %}
|
|
3
|
+
|
|
4
|
+
<div{{ attributes }}>
|
|
5
|
+
<p class="mx-progress-indicator__count">Step {{ current }} of {{ total }} — {{ steps[current - 1] }}</p>
|
|
6
|
+
<div class="mx-progress-indicator__track" aria-hidden="true">
|
|
7
|
+
{% for step in steps %}
|
|
8
|
+
{% set markerClass = 'mx-progress-indicator__marker' %}
|
|
9
|
+
{% if loop.index < current %}
|
|
10
|
+
{% set markerClass = markerClass ~ ' mx-progress-indicator__marker--done' %}
|
|
11
|
+
{% elseif loop.index == current %}
|
|
12
|
+
{% set markerClass = markerClass ~ ' mx-progress-indicator__marker--now' %}
|
|
13
|
+
{% endif %}
|
|
14
|
+
<i class="{{ markerClass }}"></i>
|
|
15
|
+
{% endfor %}
|
|
16
|
+
</div>
|
|
17
|
+
<ol class="mx-progress-indicator__steps">
|
|
18
|
+
{% for step in steps %}
|
|
19
|
+
<li class="mx-progress-indicator__step{% if loop.index < current %} mx-progress-indicator__step--done{% endif %}"{% if loop.index == current %} aria-current="step"{% endif %}>{{ step }}</li>
|
|
20
|
+
{% endfor %}
|
|
21
|
+
</ol>
|
|
22
|
+
</div>
|
|
@@ -25,7 +25,7 @@ export default class Sticky extends HTMLElement {
|
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
connectedCallback(): void {
|
|
28
|
-
this.offsetPropName = this.getAttribute("offsetpropname")
|
|
28
|
+
this.offsetPropName = this.getAttribute("offsetpropname") || "--sticky-offset"
|
|
29
29
|
const options: IOOptions = {
|
|
30
30
|
root: this.root,
|
|
31
31
|
rootMargin: this.rootMargin,
|
|
@@ -16,18 +16,18 @@
|
|
|
16
16
|
|
|
17
17
|
@layer design-system.components {
|
|
18
18
|
.mx-sticky {
|
|
19
|
-
@mixin sticky;
|
|
19
|
+
@add-mixin sticky;
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
.mx-sticky--m {
|
|
23
23
|
@media (--medium-up) {
|
|
24
|
-
@mixin sticky;
|
|
24
|
+
@add-mixin sticky;
|
|
25
25
|
}
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
.mx-sticky--l {
|
|
29
29
|
@media (--large-up) {
|
|
30
|
-
@mixin sticky;
|
|
30
|
+
@add-mixin sticky;
|
|
31
31
|
}
|
|
32
32
|
}
|
|
33
33
|
|
|
@@ -227,14 +227,16 @@ export default class Tabs extends HTMLElement {
|
|
|
227
227
|
}
|
|
228
228
|
|
|
229
229
|
set active(id: string) {
|
|
230
|
-
this.tabs.forEach(({ tab, panel }: TabsType, key: string): void => {
|
|
230
|
+
this.tabs.forEach(({ tab, button, panel }: TabsType, key: string): void => {
|
|
231
231
|
if (key === id) {
|
|
232
232
|
tab.setAttribute("aria-selected", "true")
|
|
233
|
+
button.setAttribute("aria-selected", "true")
|
|
233
234
|
tab.setAttribute("tabindex", "0")
|
|
234
235
|
panel.removeAttribute("inert")
|
|
235
236
|
this.dropMenuTrigger.textContent = tab.textContent
|
|
236
237
|
} else {
|
|
237
238
|
tab.setAttribute("aria-selected", "false")
|
|
239
|
+
button.setAttribute("aria-selected", "false")
|
|
238
240
|
tab.setAttribute("tabindex", "-1")
|
|
239
241
|
panel.setAttribute("inert", "")
|
|
240
242
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Meta, StoryObj } from "@storybook/html-vite"
|
|
2
|
-
import { expect } from "storybook/test"
|
|
2
|
+
import { expect, waitFor } from "storybook/test"
|
|
3
3
|
import Component from "./tabs.twig"
|
|
4
4
|
import TabItem from "./tab-item.twig"
|
|
5
5
|
import { HeadingTypes, Tabs as TabsType } from "@pnx-mixtape/ids-shape"
|
|
@@ -98,47 +98,81 @@ type Story = StoryObj<TabsType>
|
|
|
98
98
|
|
|
99
99
|
export const Tabs: Story = {
|
|
100
100
|
play: async ({ canvas, canvasElement, userEvent, step }) => {
|
|
101
|
-
const
|
|
102
|
-
const
|
|
103
|
-
const
|
|
101
|
+
const isMobile = matchMedia("(max-width: 767px)").matches
|
|
102
|
+
const [button1, tab1] = canvas.getAllByRole("tab", { name: "Funk", hidden: true })
|
|
103
|
+
const [button2, tab2] = canvas.getAllByRole("tab", { name: "Soul", hidden: true })
|
|
104
|
+
const [button3, tab3] = canvas.getAllByRole("tab", { name: "Motown", hidden: true })
|
|
104
105
|
const panel = (id: string): HTMLElement => canvasElement.querySelector(`#${id}`) as HTMLElement
|
|
105
106
|
|
|
106
107
|
await step("Funk starts selected", async () => {
|
|
107
|
-
|
|
108
|
+
if (isMobile) {
|
|
109
|
+
await expect(button1).toHaveAttribute("aria-selected", "true")
|
|
110
|
+
} else {
|
|
111
|
+
await expect(tab1).toHaveAttribute("aria-selected", "true")
|
|
112
|
+
}
|
|
108
113
|
await expect(panel("tab-1")).not.toHaveAttribute("inert")
|
|
109
114
|
await expect(panel("tab-2")).toHaveAttribute("inert")
|
|
110
115
|
})
|
|
111
116
|
|
|
112
117
|
await step("Click selects a tab and moves focus to its panel", async () => {
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
118
|
+
if (isMobile) {
|
|
119
|
+
await userEvent.click(button2)
|
|
120
|
+
await waitFor(() => expect(button2).toHaveAttribute("aria-selected", "true"))
|
|
121
|
+
await expect(button1).toHaveAttribute("aria-selected", "false")
|
|
122
|
+
} else {
|
|
123
|
+
await userEvent.click(tab2)
|
|
124
|
+
await waitFor(() => expect(tab2).toHaveAttribute("aria-selected", "true"))
|
|
125
|
+
await expect(tab1).toHaveAttribute("aria-selected", "false")
|
|
126
|
+
}
|
|
116
127
|
await expect(panel("tab-2")).not.toHaveAttribute("inert")
|
|
117
128
|
await expect(panel("tab-1")).toHaveAttribute("inert")
|
|
118
129
|
await expect(panel("tab-2")).toHaveFocus()
|
|
119
130
|
})
|
|
120
131
|
|
|
121
132
|
await step("ArrowRight/ArrowLeft move focus, with wraparound", async () => {
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
133
|
+
if (isMobile) {
|
|
134
|
+
button2.focus()
|
|
135
|
+
await userEvent.keyboard("{ArrowRight}")
|
|
136
|
+
await expect(button3).toHaveFocus()
|
|
137
|
+
await userEvent.keyboard("{ArrowRight}")
|
|
138
|
+
await expect(button1).toHaveFocus()
|
|
139
|
+
await userEvent.keyboard("{ArrowLeft}")
|
|
140
|
+
await expect(button3).toHaveFocus()
|
|
141
|
+
} else {
|
|
142
|
+
tab2.focus()
|
|
143
|
+
await userEvent.keyboard("{ArrowRight}")
|
|
144
|
+
await expect(tab3).toHaveFocus()
|
|
145
|
+
await userEvent.keyboard("{ArrowRight}")
|
|
146
|
+
await expect(tab1).toHaveFocus()
|
|
147
|
+
await userEvent.keyboard("{ArrowLeft}")
|
|
148
|
+
await expect(tab3).toHaveFocus()
|
|
149
|
+
}
|
|
129
150
|
})
|
|
130
151
|
|
|
131
152
|
await step("Home/End jump to first/last tab", async () => {
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
153
|
+
if (isMobile) {
|
|
154
|
+
await userEvent.keyboard("{Home}")
|
|
155
|
+
await expect(button1).toHaveFocus()
|
|
156
|
+
await userEvent.keyboard("{End}")
|
|
157
|
+
await expect(button3).toHaveFocus()
|
|
158
|
+
} else {
|
|
159
|
+
await userEvent.keyboard("{Home}")
|
|
160
|
+
await expect(tab1).toHaveFocus()
|
|
161
|
+
await userEvent.keyboard("{End}")
|
|
162
|
+
await expect(tab3).toHaveFocus()
|
|
163
|
+
}
|
|
136
164
|
})
|
|
137
165
|
|
|
138
166
|
await step("Reset: reselect Funk and clear the ?tab= param", async () => {
|
|
139
|
-
|
|
140
|
-
|
|
167
|
+
if (isMobile) {
|
|
168
|
+
await userEvent.click(button1)
|
|
169
|
+
await expect(button1).toHaveAttribute("aria-selected", "true")
|
|
170
|
+
} else {
|
|
171
|
+
await userEvent.click(tab1)
|
|
172
|
+
await expect(tab1).toHaveAttribute("aria-selected", "true")
|
|
173
|
+
}
|
|
141
174
|
window.history.replaceState({}, "", window.location.pathname)
|
|
175
|
+
await userEvent.click(canvasElement)
|
|
142
176
|
})
|
|
143
177
|
},
|
|
144
178
|
}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
exports[`Tabs 1`] = `
|
|
4
4
|
"
|
|
5
5
|
|
|
6
|
-
<mx-tabs class="mx-tabs mx-tabs--lined" id="tab-example"><mx-dropmenu closeonclick="true"><button id="unique-3" class="mx-popover__trigger mx-button mx-icon mx-icon--chevron-down mx-icon--end" popovertarget="tab-example" style="anchor-name: --tab-example" hidden="">Funk</button><div class="mx-popover mx-drop-menu" id="tab-example" aria-describedby="unique-0" style="position-anchor: --tab-example" data-placement="bottom-start" popover="" role="tablist"><button type="button" role="tab" aria-controls="unique-1" aria-selected="
|
|
6
|
+
<mx-tabs class="mx-tabs mx-tabs--lined" id="tab-example"><mx-dropmenu closeonclick="true"><button id="unique-3" class="mx-popover__trigger mx-button mx-icon mx-icon--chevron-down mx-icon--end" popovertarget="tab-example" style="anchor-name: --tab-example" hidden="">Funk</button><div class="mx-popover mx-drop-menu" id="tab-example" aria-describedby="unique-0" style="position-anchor: --tab-example" data-placement="bottom-start" popover="" role="tablist"><button type="button" role="tab" aria-controls="unique-1" aria-selected="true">Funk</button><button type="button" role="tab" aria-controls="unique-2" aria-selected="false">Soul</button><button type="button" role="tab" aria-controls="unique-3" aria-selected="false">Motown</button></div></mx-dropmenu><div class="mx-tabs__list" role="tablist"><button type="button" role="tab" aria-controls="unique-4" aria-selected="true" tabindex="0">Funk</button><button type="button" role="tab" aria-controls="unique-5" aria-selected="false" tabindex="-1">Soul</button><button type="button" role="tab" aria-controls="unique-6" aria-selected="false" tabindex="-1">Motown</button></div>
|
|
7
7
|
<div class="mx-tabs__panel mx-vertical-flow mx-container" id="unique-0" data-tab="Funk" role="tabpanel" tabindex="-1" aria-label="Funk">
|
|
8
8
|
Funk is the ipsum dolor sit amet, consectetur adipiscing elit. Proin at finibus velit. Curabitur consequat, dolor venenatis ullamcorper commodo, quam mi iaculis sem, non varius massa risus et enim. Interdum et malesuada fames ac ante ipsum primis in faucibus. Phasellus non mi lorem. Morbi semper sagittis euismod. Vestibulum non ornare orci.
|
|
9
9
|
</div>
|
|
@@ -23,7 +23,7 @@ exports[`With Heading 1`] = `
|
|
|
23
23
|
|
|
24
24
|
<h2>Tabs heading</h2>
|
|
25
25
|
|
|
26
|
-
<mx-tabs class="mx-tabs mx-tabs--lined" id="tab-example"><mx-dropmenu closeonclick="true"><button id="unique-3" class="mx-popover__trigger mx-button mx-icon mx-icon--chevron-down mx-icon--end" popovertarget="tab-example" style="anchor-name: --tab-example" hidden="">Funk</button><div class="mx-popover mx-drop-menu" id="tab-example" aria-describedby="unique-0" style="position-anchor: --tab-example" data-placement="bottom-start" popover="" role="tablist"><button type="button" role="tab" aria-controls="unique-1" aria-selected="
|
|
26
|
+
<mx-tabs class="mx-tabs mx-tabs--lined" id="tab-example"><mx-dropmenu closeonclick="true"><button id="unique-3" class="mx-popover__trigger mx-button mx-icon mx-icon--chevron-down mx-icon--end" popovertarget="tab-example" style="anchor-name: --tab-example" hidden="">Funk</button><div class="mx-popover mx-drop-menu" id="tab-example" aria-describedby="unique-0" style="position-anchor: --tab-example" data-placement="bottom-start" popover="" role="tablist"><button type="button" role="tab" aria-controls="unique-1" aria-selected="true">Funk</button><button type="button" role="tab" aria-controls="unique-2" aria-selected="false">Soul</button><button type="button" role="tab" aria-controls="unique-3" aria-selected="false">Motown</button></div></mx-dropmenu><div class="mx-tabs__list" role="tablist"><button type="button" role="tab" aria-controls="unique-4" aria-selected="true" tabindex="0">Funk</button><button type="button" role="tab" aria-controls="unique-5" aria-selected="false" tabindex="-1">Soul</button><button type="button" role="tab" aria-controls="unique-6" aria-selected="false" tabindex="-1">Motown</button></div>
|
|
27
27
|
<div class="mx-tabs__panel mx-vertical-flow mx-container" id="unique-0" data-tab="Funk" role="tabpanel" tabindex="-1" aria-label="Funk">
|
|
28
28
|
Funk is the ipsum dolor sit amet, consectetur adipiscing elit. Proin at finibus velit. Curabitur consequat, dolor venenatis ullamcorper commodo, quam mi iaculis sem, non varius massa risus et enim. Interdum et malesuada fames ac ante ipsum primis in faucibus. Phasellus non mi lorem. Morbi semper sagittis euismod. Vestibulum non ornare orci.
|
|
29
29
|
</div>
|
|
@@ -39,14 +39,15 @@ A small inline label used to categorise content. Renders as plain text metadata,
|
|
|
39
39
|
|
|
40
40
|
**tags.twig props** (`Tags` type from `ids-shape`):
|
|
41
41
|
|
|
42
|
-
| Prop | Type | Description
|
|
43
|
-
| --------------- | ------------------------------------- |
|
|
44
|
-
| `type` | `TagTypes` | Controls which markup is rendered per item. One of `text`, `link`, `checkbox`. Changing the type also changes the required shape of `items`.
|
|
45
|
-
| `items` | `string[] \| Link[] \| FormControl[]` | List of tag items. Shape depends on `type` — see below.
|
|
46
|
-
| `attributes` | `Attribute` | Extra attributes on the outer `<ul class="mx-tags">`
|
|
47
|
-
| `tagAttributes` | `Attribute` | Extra attributes on each `.mx-tag` element
|
|
48
|
-
| `dismissible` | `boolean` | When true, plain (`text`) tags render a remove button (`mx-tag--dismissible`). Wire up removal behaviour in the consuming app.
|
|
49
|
-
| `removeLabel` | `string` | Accessible label for the remove button. Defaults to `"Remove"`.
|
|
42
|
+
| Prop | Type | Description |
|
|
43
|
+
| --------------- | ------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
44
|
+
| `type` | `TagTypes` | Controls which markup is rendered per item. One of `text`, `link`, `checkbox`. Changing the type also changes the required shape of `items`. |
|
|
45
|
+
| `items` | `string[] \| Link[] \| FormControl[]` | List of tag items. Shape depends on `type` — see below. |
|
|
46
|
+
| `attributes` | `Attribute` | Extra attributes on the outer `<ul class="mx-tags">` |
|
|
47
|
+
| `tagAttributes` | `Attribute` | Extra attributes on each `.mx-tag` element |
|
|
48
|
+
| `dismissible` | `boolean` | When true, plain (`text`) tags render a remove button (`mx-tag--dismissible`). Wire up removal behaviour in the consuming app. |
|
|
49
|
+
| `removeLabel` | `string` | Accessible label for the remove button. Defaults to `"Remove"`. |
|
|
50
|
+
| `variant` | `TagVariants` | Colour variant: `info`, `success`, `warning`, `error`, `featured`. Applied per-item via `tag-item.twig`. Defaults to the neutral, unstyled tag. |
|
|
50
51
|
|
|
51
52
|
**Item shapes per `type`:**
|
|
52
53
|
|
|
@@ -78,20 +79,20 @@ Link tags:
|
|
|
78
79
|
</ul>
|
|
79
80
|
```
|
|
80
81
|
|
|
81
|
-
Checkbox tags (the `<input>` is visually hidden off-screen; the `<label>` is the click target):
|
|
82
|
+
Checkbox tags (the `<input>` is visually hidden off-screen; the `<label>` is the click target). The `mx-icon mx-icon--tick` classes on the label render the shared checkmark icon (from `@pnx-mixtape/mxds/src/Atom/Icon/icon.css`) — its space is always reserved, but it's only visible once the input is checked, so checking a tag doesn't change its size:
|
|
82
83
|
|
|
83
84
|
```html
|
|
84
85
|
<ul class="mx-tags">
|
|
85
86
|
<li>
|
|
86
87
|
<div class="mx-tag">
|
|
87
88
|
<input type="checkbox" id="music" name="tag" value="music" />
|
|
88
|
-
<label for="music">Music</label>
|
|
89
|
+
<label class="mx-icon mx-icon--tick" for="music">Music</label>
|
|
89
90
|
</div>
|
|
90
91
|
</li>
|
|
91
92
|
<li>
|
|
92
93
|
<div class="mx-tag">
|
|
93
94
|
<input type="checkbox" id="news" name="tag" value="news" checked />
|
|
94
|
-
<label for="news">News</label>
|
|
95
|
+
<label class="mx-icon mx-icon--tick" for="news">News</label>
|
|
95
96
|
</div>
|
|
96
97
|
</li>
|
|
97
98
|
</ul>
|
|
@@ -131,7 +132,7 @@ import { AsTags } from "@pnx-mixtape/mxds/src/enums"
|
|
|
131
132
|
<li>
|
|
132
133
|
<div className="mx-tag">
|
|
133
134
|
<input type="checkbox" id="music" name="tag" value="music" />
|
|
134
|
-
<label htmlFor="music">Music</label>
|
|
135
|
+
<label className="mx-icon mx-icon--tick" htmlFor="music">Music</label>
|
|
135
136
|
</div>
|
|
136
137
|
</li>
|
|
137
138
|
</ul>
|
|
@@ -139,13 +140,14 @@ import { AsTags } from "@pnx-mixtape/mxds/src/enums"
|
|
|
139
140
|
|
|
140
141
|
**`Tag` props:**
|
|
141
142
|
|
|
142
|
-
| Prop | Type
|
|
143
|
-
| ------------- |
|
|
144
|
-
| `as` | `AsTags`
|
|
145
|
-
| `className` | `string`
|
|
146
|
-
| `children` | `ReactNode`
|
|
147
|
-
| `onRemove` | `() => void`
|
|
148
|
-
| `removeLabel` | `string`
|
|
143
|
+
| Prop | Type | Default | Description |
|
|
144
|
+
| ------------- | ------------- | ---------- | --------------------------------------------------------------------------------------------------------- |
|
|
145
|
+
| `as` | `AsTags` | `div` | Semantic element for the tag: `div`, `li`, `article`, `aside`, `section` |
|
|
146
|
+
| `className` | `string` | — | Extra class on the tag element |
|
|
147
|
+
| `children` | `ReactNode` | — | Tag label content |
|
|
148
|
+
| `onRemove` | `() => void` | — | When set, renders a remove button (`mx-tag--dismissible`). Consumer removes the tag from state. |
|
|
149
|
+
| `removeLabel` | `string` | `"Remove"` | Accessible label for the remove button |
|
|
150
|
+
| `variant` | `TagVariants` | — | Colour variant: `info`, `success`, `warning`, `error`, `featured`. Defaults to the neutral, unstyled tag. |
|
|
149
151
|
|
|
150
152
|
> For filter UIs, tag removal can also be handled upstream (e.g. via the checkbox type toggling its checked state, or via the Filters component). Use `onRemove` when you need a self-contained dismissible chip.
|
|
151
153
|
|
|
@@ -155,11 +157,11 @@ import { AsTags } from "@pnx-mixtape/mxds/src/enums"
|
|
|
155
157
|
|
|
156
158
|
The `type` prop on the Twig template maps to `TagTypes` values from `@pnx-mixtape/ids-shape`. The same base `mx-tag` class is used for all variants — the variant changes the inner element, not the class.
|
|
157
159
|
|
|
158
|
-
| `TagTypes` value | Element rendered | Visual intent
|
|
159
|
-
| ---------------- | --------------------------------------------------------------------- |
|
|
160
|
-
| `text` | `<span class="mx-tag">` | Read-only metadata label (e.g. category shown on a Card)
|
|
161
|
-
| `link` | `<a class="mx-tag" href>` | Navigational tag — clicking takes the user to a filtered / category view
|
|
162
|
-
| `checkbox` | `<div class="mx-tag">` wrapping `<input type="checkbox">` + `<label>` | Toggleable filter tag inside a form; checked state
|
|
160
|
+
| `TagTypes` value | Element rendered | Visual intent |
|
|
161
|
+
| ---------------- | --------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
162
|
+
| `text` | `<span class="mx-tag">` | Read-only metadata label (e.g. category shown on a Card) |
|
|
163
|
+
| `link` | `<a class="mx-tag" href>` | Navigational tag — clicking takes the user to a filtered / category view |
|
|
164
|
+
| `checkbox` | `<div class="mx-tag">` wrapping `<input type="checkbox">` + `<label>` | Toggleable filter tag inside a form; checked state fills the tag with the primary link colour (or the variant's own colour) and prefixes the label with a checkmark icon |
|
|
163
165
|
|
|
164
166
|
---
|
|
165
167
|
|
|
@@ -168,7 +170,7 @@ The `type` prop on the Twig template maps to `TagTypes` values from `@pnx-mixtap
|
|
|
168
170
|
- **Text tags** are plain `<span>` elements — they are metadata, not interactive. Do not add click handlers or `role` attributes; if a tag needs to be clickable, use the `link` or `checkbox` variant.
|
|
169
171
|
- **Link tags** use a real `<a href>`. Ensure the destination makes sense out of context — the visible label is the accessible name, so labels like "Music" should lead to an unambiguous page (e.g. `/category/music`).
|
|
170
172
|
- **Checkbox tags** rely on a native `<input type="checkbox">` paired with a `<label for="…">`. The `<input>` is positioned off-screen (not `display: none`) so it remains focusable and announceable. The whole `.mx-tag` gets a focus outline via `:has(input:focus)` — do not remove this selector.
|
|
171
|
-
- The checked state is communicated by colour
|
|
173
|
+
- The checked state is communicated by colour (a solid fill) **and** a checkmark icon prefixed to the label — not colour alone. When rendering checkbox tags in a form, ensure surrounding context (a fieldset legend, heading, or `aria-label`) describes what group of filters the tags belong to.
|
|
172
174
|
- If you need to render a list of tags for assistive-tech as a single labelled group, add `aria-label` (or `aria-labelledby`) to the `<ul class="mx-tags">`:
|
|
173
175
|
|
|
174
176
|
```html
|
|
@@ -201,7 +203,31 @@ The `type` prop on the Twig template maps to `TagTypes` values from `@pnx-mixtap
|
|
|
201
203
|
}
|
|
202
204
|
```
|
|
203
205
|
|
|
204
|
-
Hover (on `a.mx-tag`)
|
|
206
|
+
Hover (on `a.mx-tag`) sets `--tag-foreground` to `--link-colour` (falls back to `--colour-primary`). Checked (`:has(input:checked)`) fills `--tag-background`/`--line-colour` with that same colour and switches `--tag-foreground` to `--colour-foreground-reverse`, plus prefixes the label with a checkmark icon — except on a colour variant (see below), where checked keeps the variant's own colours and hover darkens them instead.
|
|
207
|
+
|
|
208
|
+
---
|
|
209
|
+
|
|
210
|
+
## Colour variants — `TagVariants` enum
|
|
211
|
+
|
|
212
|
+
Apply `mx-tag--{variant}` for `info`, `success`, `warning`, `error`, or `featured`. Each variant fills `--tag-background` and sets the border/outline to match; foreground uses `--colour-foreground-reverse` (`featured` excepted, which stays dark-on-light).
|
|
213
|
+
|
|
214
|
+
```tsx
|
|
215
|
+
<Tag variant={TagVariants.INFO}>New</Tag>
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
`tags.twig` itself only prints pre-rendered `items` markup — `variant`, like `dismissible`, is applied per item when building that markup with `tag-item.twig`:
|
|
219
|
+
|
|
220
|
+
```twig
|
|
221
|
+
{{ include('@mixtape/Component/Tag/tag-item.twig', {
|
|
222
|
+
type: 'text',
|
|
223
|
+
item: 'New',
|
|
224
|
+
variant: 'info',
|
|
225
|
+
}) }}
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
- A checked variant tag keeps its own colours (the solid fill and "checked" link colour swap only apply to non-variant tags) — it's already a solid fill. The checkmark icon on checked still applies.
|
|
229
|
+
- The focus outline (`:has(input:focus)`) on a variant tag uses the variant's own colour instead of the standard blue.
|
|
230
|
+
- Hovering a variant **link** tag darkens its background/border by 20% (via `color-mix`) rather than switching to the link hover colour; the text colour is unchanged. `featured` only darkens by 10% — it keeps dark text on its light background, so a smaller step protects contrast.
|
|
205
231
|
|
|
206
232
|
---
|
|
207
233
|
|
|
@@ -2,6 +2,7 @@ import { Meta, StoryObj } from "@storybook/react-vite"
|
|
|
2
2
|
import Component from "./Tag"
|
|
3
3
|
import "./tag.css"
|
|
4
4
|
import { Page } from "../../../.storybook-react/decorators"
|
|
5
|
+
import { TagVariants } from "../../enums"
|
|
5
6
|
|
|
6
7
|
const meta: Meta<typeof Component> = {
|
|
7
8
|
component: Component,
|
|
@@ -9,7 +10,30 @@ const meta: Meta<typeof Component> = {
|
|
|
9
10
|
args: {
|
|
10
11
|
children: "Tag name",
|
|
11
12
|
},
|
|
13
|
+
argTypes: {
|
|
14
|
+
variant: {
|
|
15
|
+
control: {
|
|
16
|
+
type: "select",
|
|
17
|
+
labels: { undefined: "default" },
|
|
18
|
+
},
|
|
19
|
+
options: [undefined, ...Object.values(TagVariants)],
|
|
20
|
+
},
|
|
21
|
+
},
|
|
12
22
|
}
|
|
13
23
|
|
|
14
24
|
export default meta
|
|
15
25
|
export const Tag: StoryObj<typeof meta> = {}
|
|
26
|
+
|
|
27
|
+
const variantsListStyle = { display: "flex", gap: "1rem" }
|
|
28
|
+
|
|
29
|
+
export const Variants: StoryObj<typeof meta> = {
|
|
30
|
+
render: args => (
|
|
31
|
+
<div style={variantsListStyle}>
|
|
32
|
+
{Object.values(TagVariants).map(variant => (
|
|
33
|
+
<Component key={variant} {...args} variant={variant}>
|
|
34
|
+
{variant}
|
|
35
|
+
</Component>
|
|
36
|
+
))}
|
|
37
|
+
</div>
|
|
38
|
+
),
|
|
39
|
+
}
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { JSX, PropsWithChildren } from "react"
|
|
2
2
|
import classNames from "classnames"
|
|
3
|
-
import { AsTags, Icons } from "../../enums"
|
|
3
|
+
import { AsTags, Icons, TagVariants } from "../../enums"
|
|
4
4
|
|
|
5
5
|
type TagProps = PropsWithChildren & {
|
|
6
6
|
className?: string
|
|
7
7
|
as?: AsTags
|
|
8
|
+
/** Colour variant. Defaults to the neutral, unstyled tag. */
|
|
9
|
+
variant?: TagVariants
|
|
8
10
|
/**
|
|
9
11
|
* When provided, renders a remove button. Called when the button is
|
|
10
12
|
* activated — the consumer is responsible for removing the tag from state.
|
|
@@ -18,12 +20,20 @@ const Tag = ({
|
|
|
18
20
|
children,
|
|
19
21
|
className,
|
|
20
22
|
as = AsTags.DIV,
|
|
23
|
+
variant,
|
|
21
24
|
onRemove,
|
|
22
25
|
removeLabel = "Remove",
|
|
23
26
|
}: TagProps): JSX.Element => {
|
|
24
27
|
const TagEl: JSX.ElementType = `${as}` as unknown as JSX.ElementType
|
|
25
28
|
return (
|
|
26
|
-
<TagEl
|
|
29
|
+
<TagEl
|
|
30
|
+
className={classNames(
|
|
31
|
+
"mx-tag",
|
|
32
|
+
{ "mx-tag--dismissible": onRemove },
|
|
33
|
+
variant && `mx-tag--${variant}`,
|
|
34
|
+
className,
|
|
35
|
+
)}
|
|
36
|
+
>
|
|
27
37
|
{children}
|
|
28
38
|
{onRemove && (
|
|
29
39
|
<button
|
|
@@ -2,6 +2,7 @@ import { Meta, StoryObj } from "@storybook/html-vite"
|
|
|
2
2
|
import Component from "./tag-item.twig"
|
|
3
3
|
import "./tag.css"
|
|
4
4
|
import { TagTypes } from "@pnx-mixtape/ids-shape"
|
|
5
|
+
import { TagVariants } from "../../enums"
|
|
5
6
|
|
|
6
7
|
type TagItemType = {
|
|
7
8
|
type: TagTypes
|
|
@@ -11,6 +12,7 @@ type TagItemType = {
|
|
|
11
12
|
| { label: string; id: string; name: string; value: string; checked?: boolean }
|
|
12
13
|
dismissible?: boolean
|
|
13
14
|
removeLabel?: string
|
|
15
|
+
variant?: TagVariants
|
|
14
16
|
}
|
|
15
17
|
|
|
16
18
|
/**
|
|
@@ -49,6 +51,17 @@ const meta: Meta<TagItemType> = {
|
|
|
49
51
|
"When true, plain (text) tags render a remove button. Wire up removal behaviour in the consuming app.",
|
|
50
52
|
control: "boolean",
|
|
51
53
|
},
|
|
54
|
+
variant: {
|
|
55
|
+
description: "Colour variant.",
|
|
56
|
+
control: {
|
|
57
|
+
type: "select",
|
|
58
|
+
labels: { undefined: "default" },
|
|
59
|
+
},
|
|
60
|
+
options: [undefined, ...Object.values(TagVariants)],
|
|
61
|
+
table: {
|
|
62
|
+
type: { summary: "enum" },
|
|
63
|
+
},
|
|
64
|
+
},
|
|
52
65
|
},
|
|
53
66
|
render: args => {
|
|
54
67
|
return `<ul class="mx-tags">${Component({ ...args })}</ul>`
|
|
@@ -99,3 +112,15 @@ export const Checkbox: Story = {
|
|
|
99
112
|
},
|
|
100
113
|
},
|
|
101
114
|
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Colour variants for conveying status or emphasis.
|
|
118
|
+
*/
|
|
119
|
+
export const Variants: Story = {
|
|
120
|
+
render: () => {
|
|
121
|
+
const items = Object.values(TagVariants)
|
|
122
|
+
.map(variant => Component({ type: TagTypes.TEXT, item: variant, variant }))
|
|
123
|
+
.join("")
|
|
124
|
+
return `<ul class="mx-tags">${items}</ul>`
|
|
125
|
+
},
|
|
126
|
+
}
|