@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,26 @@
|
|
|
1
|
+
import { Meta, StoryObj } from "@storybook/react-vite"
|
|
2
|
+
import RadioCard, { FormRadioCard } from "./RadioCard"
|
|
3
|
+
import { Page } from "../../../.storybook-react/decorators"
|
|
4
|
+
|
|
5
|
+
const meta: Meta<typeof RadioCard> = {
|
|
6
|
+
decorators: [Page],
|
|
7
|
+
component: RadioCard,
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export default meta
|
|
11
|
+
export const RadioCards: StoryObj<typeof FormRadioCard> = {
|
|
12
|
+
render: ({ children, ...args }) => <FormRadioCard {...args}>{children}</FormRadioCard>,
|
|
13
|
+
args: {
|
|
14
|
+
label: "Do you hold a current concession card?",
|
|
15
|
+
children: (
|
|
16
|
+
<>
|
|
17
|
+
<RadioCard value="yes" hint="Pensioner Concession, Health Care or DVA card">
|
|
18
|
+
Yes, I hold a card
|
|
19
|
+
</RadioCard>
|
|
20
|
+
<RadioCard value="no" hint="You may still be eligible based on your income">
|
|
21
|
+
No
|
|
22
|
+
</RadioCard>
|
|
23
|
+
</>
|
|
24
|
+
),
|
|
25
|
+
},
|
|
26
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { JSX, PropsWithChildren, useRef, createContext, use, useId } from "react"
|
|
2
|
+
import { useRadio, useRadioGroup, AriaRadioProps, AriaRadioGroupProps } from "react-aria"
|
|
3
|
+
import { useRadioGroupState, RadioGroupState } from "react-stately"
|
|
4
|
+
import classNames from "classnames"
|
|
5
|
+
import FormItem from "../FormItem/FormItem"
|
|
6
|
+
import { FormStatus } from "../../enums"
|
|
7
|
+
|
|
8
|
+
const RadioCardContext = createContext<RadioGroupState>(null)
|
|
9
|
+
|
|
10
|
+
type FormRadioCardProps = PropsWithChildren &
|
|
11
|
+
AriaRadioGroupProps & {
|
|
12
|
+
label?: string
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const FormRadioCard = ({ label, children, ...props }: FormRadioCardProps): JSX.Element => {
|
|
16
|
+
const state = useRadioGroupState(props)
|
|
17
|
+
const { radioGroupProps } = useRadioGroup(props, state)
|
|
18
|
+
|
|
19
|
+
return (
|
|
20
|
+
<FormItem fieldset {...radioGroupProps} legend={label}>
|
|
21
|
+
<RadioCardContext value={state}>{children}</RadioCardContext>
|
|
22
|
+
</FormItem>
|
|
23
|
+
)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
type RadioCardProps = PropsWithChildren &
|
|
27
|
+
AriaRadioProps & {
|
|
28
|
+
hint?: string
|
|
29
|
+
status?: FormStatus
|
|
30
|
+
className?: string
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const RadioCard = ({
|
|
34
|
+
children,
|
|
35
|
+
hint = null,
|
|
36
|
+
status = FormStatus.DEFAULT,
|
|
37
|
+
className = "",
|
|
38
|
+
...props
|
|
39
|
+
}: RadioCardProps): JSX.Element => {
|
|
40
|
+
const id = useId()
|
|
41
|
+
const ref = useRef<HTMLInputElement>(null)
|
|
42
|
+
const state = use(RadioCardContext)
|
|
43
|
+
const { inputProps } = useRadio(props, state, ref)
|
|
44
|
+
|
|
45
|
+
const classes = classNames("mx-radio", "mx-choice-card", className)
|
|
46
|
+
|
|
47
|
+
return (
|
|
48
|
+
<div className={classes}>
|
|
49
|
+
<input id={id} {...inputProps} ref={ref} aria-invalid={status === FormStatus.INVALID} />
|
|
50
|
+
<label htmlFor={id}>
|
|
51
|
+
{children}
|
|
52
|
+
{hint && <span className="mx-choice-card__hint">{hint}</span>}
|
|
53
|
+
</label>
|
|
54
|
+
</div>
|
|
55
|
+
)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export default RadioCard
|
|
59
|
+
export { FormRadioCard }
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
|
2
|
+
|
|
3
|
+
exports[`Checked 1`] = `
|
|
4
|
+
"
|
|
5
|
+
<fieldset class="mx-form-item mx-fieldset">
|
|
6
|
+
|
|
7
|
+
<legend class="mx-legend">
|
|
8
|
+
Do you hold a current concession card?
|
|
9
|
+
</legend>
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
<div class="mx-radio mx-choice-card">
|
|
13
|
+
<input id="card-yes" type="radio" name="card" value="yes" checked="checked">
|
|
14
|
+
<label for="card-yes">
|
|
15
|
+
Yes, I hold a card
|
|
16
|
+
<span class="mx-choice-card__hint">Pensioner Concession, Health Care or DVA card</span> </label>
|
|
17
|
+
</div>
|
|
18
|
+
<div class="mx-radio mx-choice-card">
|
|
19
|
+
<input id="card-no" type="radio" name="card" value="no">
|
|
20
|
+
<label for="card-no">
|
|
21
|
+
No
|
|
22
|
+
<span class="mx-choice-card__hint">You may still be eligible based on your income</span> </label>
|
|
23
|
+
</div>
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
</fieldset>
|
|
28
|
+
"
|
|
29
|
+
`;
|
|
30
|
+
|
|
31
|
+
exports[`Radio Card 1`] = `
|
|
32
|
+
"
|
|
33
|
+
<fieldset class="mx-form-item mx-fieldset">
|
|
34
|
+
|
|
35
|
+
<legend class="mx-legend">
|
|
36
|
+
Do you hold a current concession card?
|
|
37
|
+
</legend>
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
<div class="mx-radio mx-choice-card">
|
|
41
|
+
<input id="card-yes" type="radio" name="card" value="yes">
|
|
42
|
+
<label for="card-yes">
|
|
43
|
+
Yes, I hold a card
|
|
44
|
+
<span class="mx-choice-card__hint">Pensioner Concession, Health Care or DVA card</span> </label>
|
|
45
|
+
</div>
|
|
46
|
+
<div class="mx-radio mx-choice-card">
|
|
47
|
+
<input id="card-applied" type="radio" name="card" value="applied">
|
|
48
|
+
<label for="card-applied">
|
|
49
|
+
I have applied but not received it
|
|
50
|
+
<span class="mx-choice-card__hint">You can continue, but we may ask for evidence later</span> </label>
|
|
51
|
+
</div>
|
|
52
|
+
<div class="mx-radio mx-choice-card">
|
|
53
|
+
<input id="card-no" type="radio" name="card" value="no">
|
|
54
|
+
<label for="card-no">
|
|
55
|
+
No
|
|
56
|
+
<span class="mx-choice-card__hint">You may still be eligible based on your income</span> </label>
|
|
57
|
+
</div>
|
|
58
|
+
<div class="mx-choice-divider">or</div><div class="mx-radio mx-choice-card">
|
|
59
|
+
<input id="card-unsure" type="radio" name="card" value="unsure">
|
|
60
|
+
<label for="card-unsure">
|
|
61
|
+
I am not sure
|
|
62
|
+
<span class="mx-choice-card__hint">We will ask a few more questions to work it out</span> </label>
|
|
63
|
+
</div>
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
</fieldset>
|
|
68
|
+
"
|
|
69
|
+
`;
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
|
2
|
+
|
|
3
|
+
exports[`Radio Cards 1`] = `"<fieldset class="mx-form-item mx-fieldset" role="radiogroup" aria-orientation="vertical" id="react-aria-_r_0_"><legend class="mx-legend">Do you hold a current concession card?</legend><div class="mx-radio mx-choice-card"><input id="_r_6_" data-react-aria-pressable="true" tabindex="0" aria-invalid="false" type="radio" value="yes" name="react-aria-_r_5_"><label for="_r_6_">Yes, I hold a card<span class="mx-choice-card__hint">Pensioner Concession, Health Care or DVA card</span></label></div><div class="mx-radio mx-choice-card"><input id="_r_8_" data-react-aria-pressable="true" tabindex="0" aria-invalid="false" type="radio" value="no" name="react-aria-_r_5_"><label for="_r_8_">No<span class="mx-choice-card__hint">You may still be eligible based on your income</span></label></div></fieldset>"`;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{% set classes = [
|
|
2
|
+
'mx-radio',
|
|
3
|
+
'mx-choice-card',
|
|
4
|
+
] %}
|
|
5
|
+
{% set attributes = (attributes ?? create_attribute()).addClass(classes) %}
|
|
6
|
+
<div{{ attributes }}>
|
|
7
|
+
<input
|
|
8
|
+
id="{{ id }}"
|
|
9
|
+
type="radio"
|
|
10
|
+
name="{{ name }}"
|
|
11
|
+
value="{{ value }}"
|
|
12
|
+
{% if checked %} checked="checked"{% endif %}
|
|
13
|
+
{% if status == "invalid" %} aria-invalid="true"{% endif %}
|
|
14
|
+
{% if required %} required{% endif %}
|
|
15
|
+
>
|
|
16
|
+
<label for="{{ id }}">
|
|
17
|
+
{{ label }}
|
|
18
|
+
{% if hint %}<span class="mx-choice-card__hint">{{ hint }}</span>{% endif %}
|
|
19
|
+
</label>
|
|
20
|
+
</div>
|
|
@@ -32,10 +32,7 @@ const FormSelect = ({
|
|
|
32
32
|
const handleChange: ChangeEventHandler<HTMLSelectElement> = ({ currentTarget }) =>
|
|
33
33
|
setInputValue(currentTarget.value)
|
|
34
34
|
|
|
35
|
-
const classes = classNames("mx-input__select", className
|
|
36
|
-
error: status === FormStatus.INVALID,
|
|
37
|
-
success: status === FormStatus.VALID,
|
|
38
|
-
})
|
|
35
|
+
const classes = classNames("mx-input__select", className)
|
|
39
36
|
|
|
40
37
|
const items = options.map(({ label: optionLabel, value }) => (
|
|
41
38
|
<Option label={optionLabel} value={value} key={value} />
|
|
@@ -14,3 +14,17 @@ const meta: Meta<typeof Component> = {
|
|
|
14
14
|
|
|
15
15
|
export default meta
|
|
16
16
|
export const TextInput: StoryObj<typeof Component> = {}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* `mx-validate` opts the input into live native validation — see the Twig
|
|
20
|
+
* `TextInput` stories for the full explanation.
|
|
21
|
+
*/
|
|
22
|
+
export const Validate: StoryObj<typeof Component> = {
|
|
23
|
+
args: {
|
|
24
|
+
type: "email",
|
|
25
|
+
placeholder: "you@example.com",
|
|
26
|
+
"aria-label": "Email address",
|
|
27
|
+
required: true,
|
|
28
|
+
className: "mx-validate",
|
|
29
|
+
},
|
|
30
|
+
}
|
|
@@ -22,10 +22,7 @@ const FormText = ({
|
|
|
22
22
|
const handleChange: ChangeEventHandler<HTMLInputElement> = ({ currentTarget }) =>
|
|
23
23
|
setInputValue(currentTarget.value)
|
|
24
24
|
|
|
25
|
-
const classes = classNames("mx-input__text", className
|
|
26
|
-
error: status === FormStatus.INVALID,
|
|
27
|
-
success: status === FormStatus.VALID,
|
|
28
|
-
})
|
|
25
|
+
const classes = classNames("mx-input__text", className)
|
|
29
26
|
|
|
30
27
|
return (
|
|
31
28
|
<input
|
|
@@ -1,3 +1,5 @@
|
|
|
1
1
|
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
|
2
2
|
|
|
3
3
|
exports[`Text Input 1`] = `"<input class="mx-input__text" id="mix-text" aria-describedby="help-mix-text" aria-invalid="false" placeholder="Placeholder" aria-label="Text input" type="text" value="">"`;
|
|
4
|
+
|
|
5
|
+
exports[`Validate 1`] = `"<input class="mx-input__text mx-validate" id="mix-text" required="" aria-describedby="help-mix-text" aria-invalid="false" placeholder="you@example.com" aria-label="Email address" type="email" value="">"`;
|
|
@@ -21,10 +21,7 @@ const FormTextarea = ({
|
|
|
21
21
|
const handleChange: ChangeEventHandler<HTMLTextAreaElement> = ({ currentTarget }) =>
|
|
22
22
|
setInputValue(currentTarget.value)
|
|
23
23
|
|
|
24
|
-
const classes = classNames("mx-input__textarea", className
|
|
25
|
-
error: status === FormStatus.INVALID,
|
|
26
|
-
success: status === FormStatus.VALID,
|
|
27
|
-
})
|
|
24
|
+
const classes = classNames("mx-input__textarea", className)
|
|
28
25
|
|
|
29
26
|
return (
|
|
30
27
|
<textarea
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import { Meta, StoryObj } from "@storybook/html-vite"
|
|
2
|
+
import FormItem from "./FormItem/form-item.twig"
|
|
3
|
+
import Label from "./Label/label.twig"
|
|
4
|
+
import TextInput from "./TextInput/input-text.twig"
|
|
5
|
+
import Textarea from "./Textarea/input-textarea.twig"
|
|
6
|
+
import Select from "./Select/input-select.twig"
|
|
7
|
+
import Radio from "./Radio/input-radio.twig"
|
|
8
|
+
import Checkbox from "./Checkbox/input-checkbox.twig"
|
|
9
|
+
import Autocomplete from "./Autocomplete/autocomplete.twig"
|
|
10
|
+
import Button from "../Atom/Button/button.twig"
|
|
11
|
+
import "./form.css"
|
|
12
|
+
import "./Autocomplete/autocomplete.css"
|
|
13
|
+
import "./Autocomplete/Elements/Autocomplete"
|
|
14
|
+
import { InputTypeTypes } from "@pnx-mixtape/ids-shape"
|
|
15
|
+
import { DrupalAttribute } from "drupal-attribute"
|
|
16
|
+
|
|
17
|
+
const meta: Meta = {
|
|
18
|
+
tags: ["autodocs"],
|
|
19
|
+
parameters: {
|
|
20
|
+
a11y: {
|
|
21
|
+
config: {
|
|
22
|
+
rules: [
|
|
23
|
+
{
|
|
24
|
+
// ID's are not unique due to test-runner.
|
|
25
|
+
id: "label",
|
|
26
|
+
enabled: false,
|
|
27
|
+
},
|
|
28
|
+
],
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
render: () =>
|
|
33
|
+
`<form class="mx-vertical-flow">${[
|
|
34
|
+
FormItem({
|
|
35
|
+
id: "validate-text",
|
|
36
|
+
label: Label({ id: "validate-text", title: "Email address", required: true }),
|
|
37
|
+
fields: TextInput({
|
|
38
|
+
id: "validate-text",
|
|
39
|
+
type: InputTypeTypes.EMAIL,
|
|
40
|
+
name: "validate-text",
|
|
41
|
+
placeholder: "you@example.com",
|
|
42
|
+
required: true,
|
|
43
|
+
attributes: new DrupalAttribute().addClass("mx-validate"),
|
|
44
|
+
}),
|
|
45
|
+
}),
|
|
46
|
+
FormItem({
|
|
47
|
+
id: "validate-textarea",
|
|
48
|
+
label: Label({ id: "validate-textarea", title: "Message", required: true }),
|
|
49
|
+
fields: Textarea({
|
|
50
|
+
id: "validate-textarea",
|
|
51
|
+
name: "validate-textarea",
|
|
52
|
+
required: true,
|
|
53
|
+
attributes: new DrupalAttribute().addClass("mx-validate"),
|
|
54
|
+
}),
|
|
55
|
+
}),
|
|
56
|
+
FormItem({
|
|
57
|
+
id: "validate-select",
|
|
58
|
+
label: Label({ id: "validate-select", title: "Favourite colour", required: true }),
|
|
59
|
+
fields: Select({
|
|
60
|
+
id: "validate-select",
|
|
61
|
+
name: "validate-select",
|
|
62
|
+
required: true,
|
|
63
|
+
attributes: new DrupalAttribute().addClass("mx-validate"),
|
|
64
|
+
options: [
|
|
65
|
+
{ label: "Choose an option", value: "" },
|
|
66
|
+
{ label: "Red", value: "red" },
|
|
67
|
+
{ label: "Green", value: "green" },
|
|
68
|
+
{ label: "Blue", value: "blue" },
|
|
69
|
+
],
|
|
70
|
+
}),
|
|
71
|
+
}),
|
|
72
|
+
FormItem({
|
|
73
|
+
id: "validate-radio",
|
|
74
|
+
as: "fieldset",
|
|
75
|
+
label: Label({ title: "Do you like music?", as: "legend", required: true }),
|
|
76
|
+
fields: [
|
|
77
|
+
Radio({
|
|
78
|
+
id: "validate-radio-yes",
|
|
79
|
+
name: "validate-radio",
|
|
80
|
+
label: "Yes",
|
|
81
|
+
value: "yes",
|
|
82
|
+
required: true,
|
|
83
|
+
attributes: new DrupalAttribute().addClass("mx-validate"),
|
|
84
|
+
}),
|
|
85
|
+
Radio({
|
|
86
|
+
id: "validate-radio-no",
|
|
87
|
+
name: "validate-radio",
|
|
88
|
+
label: "No",
|
|
89
|
+
value: "no",
|
|
90
|
+
required: true,
|
|
91
|
+
attributes: new DrupalAttribute().addClass("mx-validate"),
|
|
92
|
+
}),
|
|
93
|
+
].join(""),
|
|
94
|
+
}),
|
|
95
|
+
FormItem({
|
|
96
|
+
id: "validate-checkbox",
|
|
97
|
+
as: "fieldset",
|
|
98
|
+
label: Label({ title: "Which genres do you like?", as: "legend", required: true }),
|
|
99
|
+
fields: [
|
|
100
|
+
Checkbox({
|
|
101
|
+
id: "validate-checkbox-rock",
|
|
102
|
+
name: "validate-checkbox-rock",
|
|
103
|
+
label: "Rock",
|
|
104
|
+
value: "rock",
|
|
105
|
+
required: true,
|
|
106
|
+
attributes: new DrupalAttribute().addClass("mx-validate"),
|
|
107
|
+
}),
|
|
108
|
+
Checkbox({
|
|
109
|
+
id: "validate-checkbox-jazz",
|
|
110
|
+
name: "validate-checkbox-jazz",
|
|
111
|
+
label: "Jazz",
|
|
112
|
+
value: "jazz",
|
|
113
|
+
required: true,
|
|
114
|
+
attributes: new DrupalAttribute().addClass("mx-validate"),
|
|
115
|
+
}),
|
|
116
|
+
].join(""),
|
|
117
|
+
}),
|
|
118
|
+
FormItem({
|
|
119
|
+
id: "validate-autocomplete",
|
|
120
|
+
label: Label({ id: "validate-autocomplete", title: "Favourite fruit", required: true }),
|
|
121
|
+
fields: Autocomplete({
|
|
122
|
+
id: "validate-autocomplete",
|
|
123
|
+
name: "validate-autocomplete",
|
|
124
|
+
label: "Favourite fruit",
|
|
125
|
+
type: InputTypeTypes.TEXT,
|
|
126
|
+
required: true,
|
|
127
|
+
attributes: new DrupalAttribute().addClass("mx-validate"),
|
|
128
|
+
options: [
|
|
129
|
+
{ label: "Apple", value: "apple" },
|
|
130
|
+
{ label: "Banana", value: "banana" },
|
|
131
|
+
{ label: "Cherry", value: "cherry" },
|
|
132
|
+
],
|
|
133
|
+
}),
|
|
134
|
+
}),
|
|
135
|
+
Button({ title: "Submit", as: "submit" }),
|
|
136
|
+
].join("")}</form>`,
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
export default meta
|
|
140
|
+
type Story = StoryObj
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* `mx-validate` opts a control into live native validation — the border
|
|
144
|
+
* turns red once the browser rejects the value and the field has been
|
|
145
|
+
* interacted with, green once it's accepted.
|
|
146
|
+
*
|
|
147
|
+
* Add the class to the control itself (text input, textarea, select), or on
|
|
148
|
+
* the `.mx-radio` / `.mx-checkbox` / `.mx-autocomplete` wrapper for
|
|
149
|
+
* components that put `attributes` on the wrapper rather than the input.
|
|
150
|
+
*
|
|
151
|
+
* Hit Submit to trigger the invalid states on the empty required fields.
|
|
152
|
+
*/
|
|
153
|
+
export const Validation: Story = {}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
|
2
|
+
|
|
3
|
+
exports[`Validation 1`] = `
|
|
4
|
+
"<form class="mx-vertical-flow">
|
|
5
|
+
<div class="mx-form-item">
|
|
6
|
+
|
|
7
|
+
<label class="mx-label" for="validate-text">
|
|
8
|
+
Email address
|
|
9
|
+
<span class="mx-required">(required)</span></label>
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
<input class="mx-validate mx-input__text" id="validate-text" name="validate-text" type="email" value="" placeholder="you@example.com" required="">
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
</div>
|
|
18
|
+
|
|
19
|
+
<div class="mx-form-item">
|
|
20
|
+
|
|
21
|
+
<label class="mx-label" for="validate-textarea">
|
|
22
|
+
Message
|
|
23
|
+
<span class="mx-required">(required)</span></label>
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
<textarea class="mx-validate mx-input__textarea" id="unique-4" name="unique-0" aria-describedby="unique-0" required=""></textarea>
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
</div>
|
|
32
|
+
|
|
33
|
+
<div class="mx-form-item">
|
|
34
|
+
|
|
35
|
+
<label class="mx-label" for="validate-select">
|
|
36
|
+
Favourite colour
|
|
37
|
+
<span class="mx-required">(required)</span></label>
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
<select class="mx-validate mx-input__select" id="unique-5" name="unique-1" aria-describedby="unique-1" required="">
|
|
42
|
+
<button>
|
|
43
|
+
<selectedcontent>Choose an option</selectedcontent>
|
|
44
|
+
</button>
|
|
45
|
+
<option value="">Choose an option</option>
|
|
46
|
+
<option value="red">Red</option>
|
|
47
|
+
<option value="green">Green</option>
|
|
48
|
+
<option value="blue">Blue</option>
|
|
49
|
+
</select>
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
</div>
|
|
54
|
+
|
|
55
|
+
<fieldset class="mx-form-item mx-fieldset">
|
|
56
|
+
|
|
57
|
+
<legend class="mx-legend">
|
|
58
|
+
Do you like music?
|
|
59
|
+
<span class="mx-required">(required)</span></legend>
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
<div class="mx-validate mx-radio">
|
|
63
|
+
<input id="validate-radio-yes" type="radio" name="validate-radio" value="yes" required="">
|
|
64
|
+
<label for="validate-radio-yes">Yes</label>
|
|
65
|
+
</div>
|
|
66
|
+
<div class="mx-validate mx-radio">
|
|
67
|
+
<input id="validate-radio-no" type="radio" name="validate-radio" value="no" required="">
|
|
68
|
+
<label for="validate-radio-no">No</label>
|
|
69
|
+
</div>
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
</fieldset>
|
|
74
|
+
|
|
75
|
+
<fieldset class="mx-form-item mx-fieldset">
|
|
76
|
+
|
|
77
|
+
<legend class="mx-legend">
|
|
78
|
+
Which genres do you like?
|
|
79
|
+
<span class="mx-required">(required)</span></legend>
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
<div class="mx-validate mx-checkbox">
|
|
84
|
+
<input id="validate-checkbox-rock" type="checkbox" name="validate-checkbox-rock" value="rock" required="">
|
|
85
|
+
<label for="validate-checkbox-rock">Rock</label>
|
|
86
|
+
</div>
|
|
87
|
+
|
|
88
|
+
<div class="mx-validate mx-checkbox">
|
|
89
|
+
<input id="validate-checkbox-jazz" type="checkbox" name="validate-checkbox-jazz" value="jazz" required="">
|
|
90
|
+
<label for="validate-checkbox-jazz">Jazz</label>
|
|
91
|
+
</div>
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
</fieldset>
|
|
96
|
+
|
|
97
|
+
<div class="mx-form-item">
|
|
98
|
+
|
|
99
|
+
<label class="mx-label" for="validate-autocomplete">
|
|
100
|
+
Favourite fruit
|
|
101
|
+
<span class="mx-required">(required)</span></label>
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
<mx-autocomplete class="mx-autocomplete">
|
|
106
|
+
<div class="mx-autocomplete__control mx-form--inline-button">
|
|
107
|
+
<input class="mx-validate mx-input__text" id="unique-6" name="unique-2" type="text" role="combobox" aria-expanded="false" aria-controls="unique-2" aria-autocomplete="list" aria-activedescendant="" aria-describedby="unique-2" aria-label="Favourite fruit" autocomplete="off" required="">
|
|
108
|
+
</div>
|
|
109
|
+
<div class="mx-autocomplete__suggestions">
|
|
110
|
+
|
|
111
|
+
<ul class="mx-autocomplete__listbox" id="unique-0" role="listbox" hidden="">
|
|
112
|
+
<li class="mx-autocomplete__option" id="validate-autocomplete-option-0" role="option" data-value="apple" aria-selected="false">Apple</li>
|
|
113
|
+
<li class="mx-autocomplete__option" id="validate-autocomplete-option-1" role="option" data-value="banana" aria-selected="false">Banana</li>
|
|
114
|
+
<li class="mx-autocomplete__option" id="validate-autocomplete-option-2" role="option" data-value="cherry" aria-selected="false">Cherry</li>
|
|
115
|
+
</ul>
|
|
116
|
+
<output class="sr-only" aria-live="polite" data-autocomplete-status=""></output>
|
|
117
|
+
</div>
|
|
118
|
+
</mx-autocomplete>
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
</div>
|
|
123
|
+
|
|
124
|
+
<button class="mx-button" type="submit">
|
|
125
|
+
|
|
126
|
+
<span>Submit</span>
|
|
127
|
+
|
|
128
|
+
</button>
|
|
129
|
+
</form>"
|
|
130
|
+
`;
|