@pnx-mixtape/mxds 0.1.0-rc.4 → 0.1.0-rc.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/skills/create-mxds-component/SKILL.md +77 -0
- package/DESIGN.md +595 -0
- package/README.md +2 -3
- package/dist/build/accordion.entry.js +2 -1
- package/dist/build/autocomplete.entry.js +1 -1
- package/dist/build/back-to-top.css +1 -0
- package/dist/build/back-to-top.entry.js +1 -0
- package/dist/build/base.css +1 -1
- package/dist/build/button.css +1 -1
- package/dist/build/card.css +1 -1
- package/dist/build/chunks/Accordion-Bqe8vTNR.js +44 -0
- package/dist/build/chunks/AccordionGroup-BYtoAFxg.js +47 -0
- package/dist/build/chunks/AccordionMobile-D517oXYZ.js +26 -0
- package/dist/build/chunks/Autocomplete-kRo8RNbC.js +135 -0
- package/dist/build/chunks/BackToTop-4M-Wl7z3.js +64 -0
- package/dist/build/chunks/ClosableAlert-CZ114JsL.js +55 -0
- package/dist/build/chunks/CookieConsent-wd8gQ2Oe.js +18 -0
- package/dist/build/chunks/Dialog-DoYcGqhW.js +48 -0
- package/dist/build/chunks/DropMenu-CSTZq0Zt.js +68 -0
- package/dist/build/chunks/FeedbackForm-BsL7fv8s.js +64 -0
- package/dist/build/chunks/Gallery-DqJPujX5.js +165 -0
- package/dist/build/chunks/GlobalToggle-7H3F1Wvc.js +82 -0
- package/dist/build/chunks/InPageNavigation-D7m3IN89.js +86 -0
- package/dist/build/chunks/Navigation-CRModT40.js +142 -0
- package/dist/build/chunks/Popover-CiTAftNU.js +30 -0
- package/dist/build/chunks/Sticky-C1H8MNqK.js +51 -0
- package/dist/build/chunks/Tabs-BJD3kABL.js +160 -0
- package/dist/build/chunks/Translate-yAgySwet.js +46 -0
- package/dist/build/chunks/cookie-compliance-CG6x-TcV.js +119 -0
- package/dist/build/chunks/enums-BrHxPZZ_.js +36 -0
- package/dist/build/chunks/polyfills-D-qh1a_2.js +33 -0
- package/dist/build/chunks/utilities-B9mNRs7V.js +255 -0
- package/dist/build/content-block.css +1 -1
- package/dist/build/cookie-consent.entry.js +1 -1
- package/dist/build/dialog.entry.js +1 -1
- package/dist/build/drop-menu.entry.js +1 -1
- package/dist/build/elements.js +147 -1
- package/dist/build/feedback-form.css +1 -0
- package/dist/build/feedback-form.entry.js +1 -0
- package/dist/build/filters.entry.js +145 -1
- package/dist/build/form.css +1 -1
- package/dist/build/gallery.entry.js +1 -1
- package/dist/build/global-alert.entry.js +1 -1
- package/dist/build/header.css +1 -1
- package/dist/build/header.entry.js +1 -1
- package/dist/build/icon.css +1 -1
- package/dist/build/in-page-navigation.entry.js +1 -1
- package/dist/build/navigation.css +1 -1
- package/dist/build/navigation.entry.js +1 -1
- package/dist/build/pagination.css +1 -1
- package/dist/build/popover.entry.js +1 -1
- package/dist/build/react.js +2291 -1
- package/dist/build/side-navigation.css +1 -1
- package/dist/build/sidebar.css +1 -1
- package/dist/build/sticky.entry.js +1 -1
- package/dist/build/tabs.entry.js +1 -1
- package/dist/build/translate.css +1 -0
- package/dist/build/translate.entry.js +1 -0
- package/dist/build/utility-list.entry.js +53 -1
- package/dist/types/Component/BackToTop/BackToTop.d.ts +20 -0
- package/dist/types/Component/BackToTop/BackToTop.d.ts.map +1 -0
- package/dist/types/Component/BackToTop/Elements/BackToTop.d.ts +27 -0
- package/dist/types/Component/BackToTop/Elements/BackToTop.d.ts.map +1 -0
- package/dist/types/Component/BackToTop/back-to-top.entry.d.ts +2 -0
- package/dist/types/Component/BackToTop/back-to-top.entry.d.ts.map +1 -0
- package/dist/types/Component/DropMenu/DropMenu.d.ts +2 -1
- package/dist/types/Component/DropMenu/DropMenu.d.ts.map +1 -1
- package/dist/types/Component/Navigation/Elements/Navigation.d.ts +2 -3
- package/dist/types/Component/Navigation/Elements/Navigation.d.ts.map +1 -1
- package/dist/types/Component/SideNavigation/Components/SideNavigationTree.d.ts +3 -3
- package/dist/types/Component/SideNavigation/Components/SideNavigationTree.d.ts.map +1 -1
- package/dist/types/Component/SideNavigation/SideNavigation.d.ts +3 -1
- package/dist/types/Component/SideNavigation/SideNavigation.d.ts.map +1 -1
- package/dist/types/Component/Tabs/Components/TabDropMenu.d.ts.map +1 -1
- package/dist/types/Component/Tabs/Elements/Tabs.d.ts.map +1 -1
- package/dist/types/Component/Translate/Elements/Translate.d.ts +23 -0
- package/dist/types/Component/Translate/Elements/Translate.d.ts.map +1 -0
- package/dist/types/Component/Translate/Translate.d.ts +37 -0
- package/dist/types/Component/Translate/Translate.d.ts.map +1 -0
- package/dist/types/Component/Translate/languages.d.ts +11 -0
- package/dist/types/Component/Translate/languages.d.ts.map +1 -0
- package/dist/types/Component/Translate/translate.entry.d.ts +2 -0
- package/dist/types/Component/Translate/translate.entry.d.ts.map +1 -0
- package/dist/types/Form/FeedbackForm/Elements/FeedbackForm.d.ts +37 -0
- package/dist/types/Form/FeedbackForm/Elements/FeedbackForm.d.ts.map +1 -0
- package/dist/types/Form/FeedbackForm/FeedbackForm.d.ts +36 -0
- package/dist/types/Form/FeedbackForm/FeedbackForm.d.ts.map +1 -0
- package/dist/types/Form/FeedbackForm/feedback-form.entry.d.ts +2 -0
- package/dist/types/Form/FeedbackForm/feedback-form.entry.d.ts.map +1 -0
- package/dist/types/Utility/Elements/google-translate-widget.d.ts +91 -0
- package/dist/types/Utility/Elements/google-translate-widget.d.ts.map +1 -0
- package/dist/types/Utility/utilities.d.ts +2 -0
- package/dist/types/Utility/utilities.d.ts.map +1 -1
- package/dist/types/elements.d.ts +3 -0
- package/dist/types/elements.d.ts.map +1 -1
- package/dist/types/enums.d.ts +3 -1
- package/dist/types/enums.d.ts.map +1 -1
- package/dist/types/react.d.ts +3 -0
- package/dist/types/react.d.ts.map +1 -1
- package/dist/types/tokens.d.ts +1 -0
- package/dist/types/tokens.d.ts.map +1 -1
- package/docs/API.md +1215 -0
- package/docs/CSSGuidelines.md +893 -0
- package/docs/CodeQuality.md +940 -0
- package/docs/ComponentArchitecture.md +714 -0
- package/docs/Contributing.md +626 -0
- package/docs/MemoryManagement.md +598 -0
- package/docs/Migrations.md +6 -0
- package/docs/README.md +100 -0
- package/docs/Security.md +444 -0
- package/docs/Testing.md +739 -0
- package/docs/Troubleshooting.md +674 -0
- package/package.json +9 -6
- package/src/Atom/Button/Button.tsx +1 -1
- package/src/Atom/Button/__snapshots__/Button.stories.tsx.snap +2 -2
- package/src/Atom/Button/_buttons.css +1 -0
- package/src/Atom/Icon/README.md +1 -1
- package/src/Atom/Icon/_icon.css +1 -0
- package/src/Atom/Icon/images/thumb.svg +1 -0
- package/src/Atom/Link/_links.css +1 -0
- package/src/Atom/Media/__snapshots__/Media.stories.ts.snap +4 -9
- package/src/Atom/Media/media.twig +4 -5
- package/src/Component/BackToTop/BackToTop.stories.ts +127 -0
- package/src/Component/BackToTop/BackToTop.stories.tsx +53 -0
- package/src/Component/BackToTop/BackToTop.tsx +120 -0
- package/src/Component/BackToTop/Elements/BackToTop.ts +119 -0
- package/src/Component/BackToTop/README.md +164 -0
- package/src/Component/BackToTop/__snapshots__/BackToTop.stories.ts.snap +24 -0
- package/src/Component/BackToTop/__snapshots__/BackToTop.stories.tsx.snap +3 -0
- package/src/Component/BackToTop/back-to-top.css +70 -0
- package/src/Component/BackToTop/back-to-top.entry.js +1 -0
- package/src/Component/BackToTop/back-to-top.twig +26 -0
- package/src/Component/Card/Components/CardContent.tsx +1 -1
- package/src/Component/Card/Components/CardMedia.tsx +1 -1
- package/src/Component/Card/__snapshots__/Card.stories.tsx.snap +3 -3
- package/src/Component/Card/card.css +1 -1
- package/src/Component/Carousel/Carousel.stories.ts +66 -36
- package/src/Component/Carousel/__snapshots__/Carousel.stories.tsx.snap +5 -5
- package/src/Component/ContentBlock/Components/ContentBlockMedia.tsx +1 -1
- package/src/Component/ContentBlock/content-block.css +1 -1
- package/src/Component/DropMenu/DropMenu.stories.ts +21 -2
- package/src/Component/DropMenu/DropMenu.tsx +14 -4
- package/src/Component/DropMenu/__snapshots__/DropMenu.stories.ts.snap +3 -3
- package/src/Component/DropMenu/__snapshots__/DropMenu.stories.tsx.snap +2 -2
- package/src/Component/DropMenu/drop-menu.twig +7 -1
- package/src/Component/HeroBanner/__snapshots__/HeroBanner.stories.tsx.snap +1 -1
- package/src/Component/InPageNavigation/__snapshots__/InPageNavigation.stories.ts.snap +48 -13
- package/src/Component/InPageNavigation/in-page-navigation.twig +4 -6
- package/src/Component/ListItem/Components/ListItemMedia.tsx +1 -1
- package/src/Component/Navigation/Elements/Navigation.ts +25 -29
- package/src/Component/Navigation/README.md +11 -10
- package/src/Component/Navigation/__snapshots__/Navigation.stories.ts.snap +8 -8
- package/src/Component/Navigation/_navigation-dropdown.css +9 -11
- package/src/Component/Navigation/_navigation-mega.css +5 -11
- package/src/Component/Navigation/_navigation.css +5 -3
- package/src/Component/Navigation/menu.twig +1 -1
- package/src/Component/Navigation/navigation.twig +0 -1
- package/src/Component/Pagination/Pagination.stories.ts +57 -27
- package/src/Component/Pagination/pagination.css +16 -7
- package/src/Component/Popover/__snapshots__/Popover.stories.tsx.snap +3 -3
- package/src/Component/SideNavigation/Components/SideNavigationTree.tsx +68 -24
- package/src/Component/SideNavigation/README.md +78 -32
- package/src/Component/SideNavigation/SideNavigation.stories.ts +41 -2
- package/src/Component/SideNavigation/SideNavigation.stories.tsx +31 -0
- package/src/Component/SideNavigation/SideNavigation.tsx +13 -3
- package/src/Component/SideNavigation/__snapshots__/SideNavigation.stories.ts.snap +87 -3
- package/src/Component/SideNavigation/__snapshots__/SideNavigation.stories.tsx.snap +2 -0
- package/src/Component/SideNavigation/side-navigation.css +3 -3
- package/src/Component/SideNavigation/side-navigation.twig +10 -3
- package/src/Component/Tabs/Components/TabDropMenu.tsx +7 -1
- package/src/Component/Tabs/Elements/Tabs.ts +13 -3
- package/src/Component/Tabs/Tabs.stories.ts +33 -12
- package/src/Component/Tabs/Tabs.stories.tsx +28 -14
- package/src/Component/Tabs/__snapshots__/Tabs.stories.ts.snap +3 -3
- package/src/Component/Tabs/__snapshots__/Tabs.stories.tsx.snap +2 -2
- package/src/Component/Translate/Elements/Translate.ts +76 -0
- package/src/Component/Translate/README.md +285 -0
- package/src/Component/Translate/Translate.stories.ts +87 -0
- package/src/Component/Translate/Translate.stories.tsx +77 -0
- package/src/Component/Translate/Translate.tsx +213 -0
- package/src/Component/Translate/__snapshots__/Translate.stories.ts.snap +18 -0
- package/src/Component/Translate/__snapshots__/Translate.stories.tsx.snap +3 -0
- package/src/Component/Translate/languages.ts +39 -0
- package/src/Component/Translate/translate.css +62 -0
- package/src/Component/Translate/translate.entry.js +1 -0
- package/src/Component/Translate/translate.twig +44 -0
- package/src/Form/Autocomplete/Autocomplete.stories.tsx +2 -1
- package/src/Form/FeedbackForm/Elements/FeedbackForm.ts +122 -0
- package/src/Form/FeedbackForm/FeedbackForm.stories.ts +99 -0
- package/src/Form/FeedbackForm/FeedbackForm.stories.tsx +73 -0
- package/src/Form/FeedbackForm/FeedbackForm.tsx +196 -0
- package/src/Form/FeedbackForm/README.md +233 -0
- package/src/Form/FeedbackForm/__snapshots__/FeedbackForm.stories.ts.snap +125 -0
- package/src/Form/FeedbackForm/__snapshots__/FeedbackForm.stories.tsx.snap +5 -0
- package/src/Form/FeedbackForm/feedback-form.css +74 -0
- package/src/Form/FeedbackForm/feedback-form.entry.js +1 -0
- package/src/Form/FeedbackForm/feedback-form.twig +80 -0
- package/src/Form/form.css +17 -19
- package/src/Introduction.mdx +1 -1
- package/src/Layout/Footer/__snapshots__/Footer.stories.ts.snap +3 -3
- package/src/Layout/Header/Components/GlobalToggle.tsx +1 -1
- package/src/Layout/Header/Header.stories.ts +53 -48
- package/src/Layout/Header/Header.stories.tsx +35 -22
- package/src/Layout/Header/Header.tsx +2 -2
- package/src/Layout/Header/__snapshots__/Header.stories.ts.snap +18 -14
- package/src/Layout/Header/__snapshots__/Header.stories.tsx.snap +2 -2
- package/src/Layout/Header/_toggles.css +7 -7
- package/src/Layout/Page/__snapshots__/Page.stories.tsx.snap +1 -1
- package/src/Layout/Sidebar/sidebar.css +10 -3
- package/src/Utility/Elements/google-translate-widget.ts +293 -0
- package/src/Utility/global.d.ts +4 -0
- package/src/Utility/utilities.ts +2 -0
- package/src/_custom-media.css +2 -0
- package/src/elements.ts +3 -0
- package/src/enums.ts +2 -0
- package/src/react.ts +3 -0
- package/src/tokens.js +1 -0
- package/dist/build/chunks/Accordion-GN0sME4W.js +0 -1
- package/dist/build/chunks/AccordionGroup-Bzqp5__q.js +0 -1
- package/dist/build/chunks/AccordionMobile-DG5jSe8Q.js +0 -1
- package/dist/build/chunks/Autocomplete-B4RtkAyh.js +0 -1
- package/dist/build/chunks/ClosableAlert-DEhj8Nxm.js +0 -1
- package/dist/build/chunks/CookieConsent-BkCMRVST.js +0 -1
- package/dist/build/chunks/Dialog-Haahn-Yn.js +0 -1
- package/dist/build/chunks/DropMenu-1baQc8Yc.js +0 -1
- package/dist/build/chunks/Gallery-D8NGXy2Q.js +0 -1
- package/dist/build/chunks/GlobalToggle-B52fdBQu.js +0 -1
- package/dist/build/chunks/InPageNavigation-Dyn2TR-N.js +0 -1
- package/dist/build/chunks/Navigation-hOrfLq7h.js +0 -1
- package/dist/build/chunks/Popover-Cxg-s5Jn.js +0 -1
- package/dist/build/chunks/Sticky-BGCuuEJK.js +0 -1
- package/dist/build/chunks/Tabs-DYy1YTdU.js +0 -15
- package/dist/build/chunks/cookie-compliance-Bbm-0vpj.js +0 -1
- package/dist/build/chunks/enums-DLV_1NAf.js +0 -1
- package/dist/build/chunks/polyfills-C7pRt54M.js +0 -1
- package/dist/build/chunks/utilities-_Bq3TxAQ.js +0 -1
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
# FeedbackForm
|
|
2
|
+
|
|
3
|
+
A yes/no "was this page useful?" control that reveals a free-text comment field once a rating
|
|
4
|
+
is chosen.
|
|
5
|
+
|
|
6
|
+
**This component never submits anywhere itself.** Progressive enhancement, native `<form
|
|
7
|
+
action>` submission still works — but the Web Component dispatches a cancelable
|
|
8
|
+
`mx-feedback-form-submit` event (and React calls an `onSubmit` prop) before the form submits, so
|
|
9
|
+
any backend can be wired up by the consumer: a Drupal webform AJAX endpoint, a REST call,
|
|
10
|
+
whatever. This keeps the component usable whether you're posting to a classic HTML form action
|
|
11
|
+
or handling submission entirely in JS.
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## CSS Import
|
|
16
|
+
|
|
17
|
+
```css
|
|
18
|
+
@import "@pnx-mixtape/mxds/src/Form/FeedbackForm/feedback-form.css";
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## Twig
|
|
24
|
+
|
|
25
|
+
```twig
|
|
26
|
+
{% include '@mixtape/Form/FeedbackForm/feedback-form.twig' with {
|
|
27
|
+
id: 'feedback',
|
|
28
|
+
secondaryText: 'If you need a response, ',
|
|
29
|
+
secondaryLinkText: 'contact us',
|
|
30
|
+
secondaryLinkHref: '/contact',
|
|
31
|
+
} %}
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
**feedback-form.twig props:**
|
|
35
|
+
|
|
36
|
+
| Prop | Type | Default | Description |
|
|
37
|
+
| ---------------------- | ----------- | ------------------------------------------ | --------------------------------------------------------------------------------------------------------- |
|
|
38
|
+
| `id` | `string` | `feedback-form` | Root id, used to derive the rating/comment field ids |
|
|
39
|
+
| `name` | `string` | `rating` | `name` on the two rating radios |
|
|
40
|
+
| `question` | `string` | `Was the information on this page useful?` | Rating fieldset `<legend>` text |
|
|
41
|
+
| `yesLabel` / `noLabel` | `string` | `Yes` / `No` | Rating radio labels |
|
|
42
|
+
| `secondaryText` | `string` | — | Optional copy shown below the rating (e.g. pointing to another contact channel) |
|
|
43
|
+
| `secondaryLinkText` | `string` | — | Optional link text — only rendered together with `secondaryLinkHref` |
|
|
44
|
+
| `secondaryLinkHref` | `string` | — | Optional link destination |
|
|
45
|
+
| `commentLabel` | `string` | `How can we make it better?` | Label for the revealed comment field |
|
|
46
|
+
| `commentName` | `string` | `comment` | `name` on the comment `<textarea>` |
|
|
47
|
+
| `commentPlaceholder` | `string` | — | Comment `<textarea>` placeholder |
|
|
48
|
+
| `commentRequired` | `boolean` | `false` | Adds `required` to the comment field, and enables the required-field error message |
|
|
49
|
+
| `requiredErrorMessage` | `string` | `This field is required.` | Message shown when `commentRequired` is set and the comment is submitted empty |
|
|
50
|
+
| `submitLabel` | `string` | `Submit` | Submit button text |
|
|
51
|
+
| `action` | `string` | — | `<form action>` — progressive-enhancement fallback target |
|
|
52
|
+
| `method` | `string` | `post` | `<form method>` |
|
|
53
|
+
| `errorMessage` | `string` | — | Consumer-supplied top-level notice (e.g. after a failed async submit), rendered as a `role="alert"` block |
|
|
54
|
+
| `attributes` | `Attribute` | — | Optional Drupal-style attributes object — `mx-feedback-form` is always merged on top |
|
|
55
|
+
|
|
56
|
+
Registers as `<mx-feedback-form>`. Import the element to activate its behaviour:
|
|
57
|
+
|
|
58
|
+
```js
|
|
59
|
+
import "@pnx-mixtape/mxds/src/Form/FeedbackForm/Elements/FeedbackForm"
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## HTML + Web Component
|
|
65
|
+
|
|
66
|
+
```html
|
|
67
|
+
<mx-feedback-form class="mx-feedback-form">
|
|
68
|
+
<form method="post">
|
|
69
|
+
<fieldset class="mx-fieldset mx-fieldset--plain mx-feedback-form__rating">
|
|
70
|
+
<legend class="mx-legend">Was the information on this page useful?</legend>
|
|
71
|
+
<div class="mx-feedback-form__option">
|
|
72
|
+
<input type="radio" class="sr-only" id="feedback-yes" name="rating" value="yes" />
|
|
73
|
+
<label class="mx-button mx-button--dark mx-button--outline" for="feedback-yes">
|
|
74
|
+
<span class="mx-icon mx-icon--thumb"></span>
|
|
75
|
+
<span>Yes</span>
|
|
76
|
+
</label>
|
|
77
|
+
</div>
|
|
78
|
+
<div class="mx-feedback-form__option">
|
|
79
|
+
<input type="radio" class="sr-only" id="feedback-no" name="rating" value="no" />
|
|
80
|
+
<label class="mx-button mx-button--dark mx-button--outline" for="feedback-no">
|
|
81
|
+
<span class="mx-icon mx-icon--thumb mx-icon--rotate-180"></span>
|
|
82
|
+
<span>No</span>
|
|
83
|
+
</label>
|
|
84
|
+
</div>
|
|
85
|
+
</fieldset>
|
|
86
|
+
<div class="mx-feedback-form__reveal">
|
|
87
|
+
<!-- FormItem-wrapped comment textarea, error status, submit button -->
|
|
88
|
+
</div>
|
|
89
|
+
</form>
|
|
90
|
+
</mx-feedback-form>
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
**Reveal behaviour:** the comment field and submit button are always visible and submittable in
|
|
94
|
+
the static/no-JS markup. Once the `<mx-feedback-form>` element connects, it adds an
|
|
95
|
+
`is-enhanced` class to itself — only then does CSS hide the reveal block until a rating radio is
|
|
96
|
+
checked (`:has()`-driven). This means a blocked or failed script load can never leave the form's
|
|
97
|
+
only submit path permanently hidden — see [Accessibility](#accessibility).
|
|
98
|
+
|
|
99
|
+
**Validation:** when `commentRequired` is set and the comment is empty on submit, the Web
|
|
100
|
+
Component prevents the native submit, marks the textarea `aria-invalid="true"`, reveals the
|
|
101
|
+
pre-rendered `role="alert"` status message, and moves focus to the comment field — rather than
|
|
102
|
+
relying on the browser's native validation bubble (`novalidate` is set on the form).
|
|
103
|
+
|
|
104
|
+
**Submit contract:** on a valid submit, the Web Component dispatches a cancelable
|
|
105
|
+
`mx-feedback-form-submit` `CustomEvent` with `detail: { rating, comment, form }` _before_ the
|
|
106
|
+
form actually submits. If a listener calls `preventDefault()` on that event, the native
|
|
107
|
+
submission is also cancelled — full consumer ownership of the request. If nothing cancels it,
|
|
108
|
+
the browser proceeds with the form's `action`/`method` as normal.
|
|
109
|
+
|
|
110
|
+
```js
|
|
111
|
+
const root = document.querySelector("mx-feedback-form")
|
|
112
|
+
|
|
113
|
+
root.addEventListener("mx-feedback-form-submit", async event => {
|
|
114
|
+
event.preventDefault() // take over submission ourselves
|
|
115
|
+
const { rating, comment } = event.detail
|
|
116
|
+
await fetch("/api/feedback", {
|
|
117
|
+
method: "POST",
|
|
118
|
+
body: JSON.stringify({ rating, comment }),
|
|
119
|
+
})
|
|
120
|
+
})
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
**Pending state:** while your own async submit is in flight, reflect it with the `pending`
|
|
124
|
+
attribute:
|
|
125
|
+
|
|
126
|
+
```js
|
|
127
|
+
root.setAttribute("pending", "")
|
|
128
|
+
// ... await your request ...
|
|
129
|
+
root.removeAttribute("pending")
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
This adds mxds's standard `pending` custom state (`internals_.states`, so `:state(pending)` is
|
|
133
|
+
selectable in CSS) and disables/`aria-busy`s the submit button.
|
|
134
|
+
|
|
135
|
+
---
|
|
136
|
+
|
|
137
|
+
## React
|
|
138
|
+
|
|
139
|
+
```tsx
|
|
140
|
+
import { FeedbackForm } from "@pnx-mixtape/mxds/react"
|
|
141
|
+
|
|
142
|
+
const Example = () => {
|
|
143
|
+
const [pending, setPending] = useState(false)
|
|
144
|
+
|
|
145
|
+
const handleSubmit = async ({ rating, comment }) => {
|
|
146
|
+
setPending(true)
|
|
147
|
+
await fetch("/api/feedback", { method: "POST", body: JSON.stringify({ rating, comment }) })
|
|
148
|
+
setPending(false)
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
return (
|
|
152
|
+
<FeedbackForm
|
|
153
|
+
id="feedback"
|
|
154
|
+
secondaryText="If you need a response, "
|
|
155
|
+
secondaryLinkText="contact us"
|
|
156
|
+
secondaryLinkHref="/contact"
|
|
157
|
+
pending={pending}
|
|
158
|
+
onSubmit={handleSubmit}
|
|
159
|
+
/>
|
|
160
|
+
)
|
|
161
|
+
}
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
**`FeedbackForm` props:** same set as the Twig props above (camelCase, no `attributes`), plus:
|
|
165
|
+
|
|
166
|
+
| Prop | Type | Default | Description |
|
|
167
|
+
| ----------- | --------------------------------------------- | ------- | ------------------------------------------------------------------------------- |
|
|
168
|
+
| `pending` | `boolean` | `false` | Reflected as `aria-busy`/`disabled` on the submit button |
|
|
169
|
+
| `onSubmit` | `(detail: { rating, comment, form }) => void` | — | Called on a valid submit — see [React ⇄ Twig parity](#react--twig-parity) below |
|
|
170
|
+
| `className` | `string` | — | Extra class on the root |
|
|
171
|
+
|
|
172
|
+
---
|
|
173
|
+
|
|
174
|
+
### React ⇄ Twig parity
|
|
175
|
+
|
|
176
|
+
- **Submit ownership differs by design.** In Twig/Web Component, `mx-feedback-form-submit` is a
|
|
177
|
+
_cancelable_ event — the native form submission proceeds unless a listener calls
|
|
178
|
+
`preventDefault()`. In React, supplying `onSubmit` always prevents the native submission (a
|
|
179
|
+
React app wiring up `onSubmit` expects full control, not an opt-in interception) — there's no
|
|
180
|
+
React equivalent of "let it submit natively AND notify me."
|
|
181
|
+
- `pending` has no Twig prop — it's a runtime-only concept. The Twig/Web-Component equivalent is
|
|
182
|
+
the `pending` HTML _attribute_, toggled by your own JS after render (see above), not a
|
|
183
|
+
template-render-time prop.
|
|
184
|
+
- `yesIcon`, `noIcon`, `commentItem`, and `submitButton` in `feedback-form.twig` are internal
|
|
185
|
+
`{% set x %}...{% endset %}` template locals used to pre-render nested `Icon`/`FormItem`/
|
|
186
|
+
`Button` markup for composition — not props, and not present in React (which composes the
|
|
187
|
+
equivalent components directly in JSX). `pnpm audit-parity`'s static extractor doesn't
|
|
188
|
+
recognize the `{% set x %}...{% endset %}` capture-block form (only the inline `{% set x = … %}`
|
|
189
|
+
form), so it misreports these as Twig-only props — a known tool limitation, not a real
|
|
190
|
+
divergence.
|
|
191
|
+
- `commentPlaceholder` and `commentRequired` genuinely are used in Twig — passed through to
|
|
192
|
+
`Form/Textarea/input-textarea.twig` inside a nested `{% include ... with {...} %}` call. The
|
|
193
|
+
audit tool's extractor doesn't scan inside `with {}` object literals, so it misreports these as
|
|
194
|
+
unused — also a known tool limitation.
|
|
195
|
+
|
|
196
|
+
---
|
|
197
|
+
|
|
198
|
+
## Modifiers
|
|
199
|
+
|
|
200
|
+
No BEM modifier classes. `mx-feedback-form--l`-style breakpoint modifiers don't apply here —
|
|
201
|
+
this component isn't visibility/breakpoint-gated the way `BackToTop`/`Sticky` are.
|
|
202
|
+
|
|
203
|
+
---
|
|
204
|
+
|
|
205
|
+
## Accessibility
|
|
206
|
+
|
|
207
|
+
- The rating group uses a real `<fieldset>`/`<legend>` — no `role="radiogroup"` needed, this is
|
|
208
|
+
the native equivalent.
|
|
209
|
+
- Each rating option is a real, focusable `<input type="radio">` paired with a `<label>` styled
|
|
210
|
+
as a button (reusing the `Button` atom's own classes/custom properties — `mx-button
|
|
211
|
+
mx-button--dark mx-button--outline`, with `:has(input:checked)` undoing the outline to show
|
|
212
|
+
the selected state). The input itself is visually hidden with `.sr-only` (clip, not
|
|
213
|
+
`display:none`) so it stays in the tab order and the accessibility tree — only its default
|
|
214
|
+
circular appearance is hidden, keyboard operation (Tab to focus, arrow keys to move within the
|
|
215
|
+
native radio group, Space/click to select) is unaffected. The visible label still carries icon
|
|
216
|
+
- text, not icon-only/visually-hidden text.
|
|
217
|
+
- **The comment field and submit button are reachable without JavaScript.** The reveal-on-rating
|
|
218
|
+
behaviour is only switched on once JS is confirmed running (`is-enhanced`, added by the Web
|
|
219
|
+
Component's `connectedCallback`; always present in React) — a blocked or failed script load
|
|
220
|
+
never leaves the form's only path to submit permanently hidden.
|
|
221
|
+
- The required-field error is a `role="alert"` region, programmatically associated with the
|
|
222
|
+
comment field via `aria-describedby`, and focus moves to the field when validation fails.
|
|
223
|
+
- The top-level `errorMessage` notice is also `role="alert"`.
|
|
224
|
+
|
|
225
|
+
---
|
|
226
|
+
|
|
227
|
+
## Customisation via CSS custom properties
|
|
228
|
+
|
|
229
|
+
```css
|
|
230
|
+
.mx-feedback-form {
|
|
231
|
+
--feedback-form-icon-size: var(--spacing-m); /* size of the thumb icons */
|
|
232
|
+
}
|
|
233
|
+
```
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
|
2
|
+
|
|
3
|
+
exports[`Feedback Form 1`] = `
|
|
4
|
+
"
|
|
5
|
+
|
|
6
|
+
<mx-feedback-form class="mx-feedback-form is-enhanced">
|
|
7
|
+
<form action="" method="post" novalidate="">
|
|
8
|
+
|
|
9
|
+
<fieldset class="mx-fieldset mx-fieldset--plain mx-feedback-form__rating">
|
|
10
|
+
<legend class="mx-legend">Was the information on this page useful?</legend>
|
|
11
|
+
<div class="mx-feedback-form__option">
|
|
12
|
+
<input type="radio" class="sr-only" id="feedback-yes" name="rating" value="yes">
|
|
13
|
+
<label class="mx-button mx-button--dark mx-button--outline" for="feedback-yes">
|
|
14
|
+
|
|
15
|
+
<span class="mx-icon mx-icon--thumb"></span>
|
|
16
|
+
<span>Yes</span>
|
|
17
|
+
</label>
|
|
18
|
+
</div>
|
|
19
|
+
<div class="mx-feedback-form__option">
|
|
20
|
+
<input type="radio" class="sr-only" id="feedback-no" name="rating" value="no">
|
|
21
|
+
<label class="mx-button mx-button--dark mx-button--outline" for="feedback-no">
|
|
22
|
+
|
|
23
|
+
<span class="mx-icon mx-icon--thumb mx-icon--rotate-180"></span>
|
|
24
|
+
<span>No</span>
|
|
25
|
+
</label>
|
|
26
|
+
</div>
|
|
27
|
+
</fieldset>
|
|
28
|
+
|
|
29
|
+
<p class="mx-feedback-form__secondary">
|
|
30
|
+
Your rating will help us improve the website.
|
|
31
|
+
</p>
|
|
32
|
+
|
|
33
|
+
<div class="mx-feedback-form__reveal">
|
|
34
|
+
|
|
35
|
+
<div class="mx-form-item">
|
|
36
|
+
|
|
37
|
+
<label class="mx-label" for="feedback-comment">
|
|
38
|
+
How can we make it better?
|
|
39
|
+
</label>
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
<textarea aria-describedby="unique-0" class="mx-input__textarea" id="feedback-comment" name="unique-0"></textarea>
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
</div>
|
|
48
|
+
|
|
49
|
+
<div class="mx-error-message" id="unique-0" role="alert" hidden="">This field is required.</div>
|
|
50
|
+
<div class="mx-form-actions">
|
|
51
|
+
|
|
52
|
+
<button class="mx-button mx-button--dark" type="submit">
|
|
53
|
+
|
|
54
|
+
<span>Submit</span>
|
|
55
|
+
|
|
56
|
+
</button>
|
|
57
|
+
|
|
58
|
+
</div>
|
|
59
|
+
</div>
|
|
60
|
+
</form>
|
|
61
|
+
</mx-feedback-form>
|
|
62
|
+
"
|
|
63
|
+
`;
|
|
64
|
+
|
|
65
|
+
exports[`Required Comment 1`] = `
|
|
66
|
+
"
|
|
67
|
+
|
|
68
|
+
<mx-feedback-form class="mx-feedback-form is-enhanced">
|
|
69
|
+
<form action="" method="post" novalidate="">
|
|
70
|
+
|
|
71
|
+
<fieldset class="mx-fieldset mx-fieldset--plain mx-feedback-form__rating">
|
|
72
|
+
<legend class="mx-legend">Was the information on this page useful?</legend>
|
|
73
|
+
<div class="mx-feedback-form__option">
|
|
74
|
+
<input type="radio" class="sr-only" id="feedback-required-yes" name="rating" value="yes">
|
|
75
|
+
<label class="mx-button mx-button--dark mx-button--outline" for="feedback-required-yes">
|
|
76
|
+
|
|
77
|
+
<span class="mx-icon mx-icon--thumb"></span>
|
|
78
|
+
<span>Yes</span>
|
|
79
|
+
</label>
|
|
80
|
+
</div>
|
|
81
|
+
<div class="mx-feedback-form__option">
|
|
82
|
+
<input type="radio" class="sr-only" id="feedback-required-no" name="rating" value="no">
|
|
83
|
+
<label class="mx-button mx-button--dark mx-button--outline" for="feedback-required-no">
|
|
84
|
+
|
|
85
|
+
<span class="mx-icon mx-icon--thumb mx-icon--rotate-180"></span>
|
|
86
|
+
<span>No</span>
|
|
87
|
+
</label>
|
|
88
|
+
</div>
|
|
89
|
+
</fieldset>
|
|
90
|
+
|
|
91
|
+
<p class="mx-feedback-form__secondary">
|
|
92
|
+
Your rating will help us improve the website.
|
|
93
|
+
</p>
|
|
94
|
+
|
|
95
|
+
<div class="mx-feedback-form__reveal">
|
|
96
|
+
|
|
97
|
+
<div class="mx-form-item">
|
|
98
|
+
|
|
99
|
+
<label class="mx-label" for="feedback-required-comment">
|
|
100
|
+
How can we make it better?
|
|
101
|
+
</label>
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
<textarea aria-describedby="unique-0" class="mx-input__textarea" id="feedback-required-comment" name="unique-0" required="" aria-invalid="true"></textarea>
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
</div>
|
|
110
|
+
|
|
111
|
+
<div class="mx-error-message" id="unique-0" role="alert">This field is required.</div>
|
|
112
|
+
<div class="mx-form-actions">
|
|
113
|
+
|
|
114
|
+
<button class="mx-button mx-button--dark" type="submit">
|
|
115
|
+
|
|
116
|
+
<span>Submit</span>
|
|
117
|
+
|
|
118
|
+
</button>
|
|
119
|
+
|
|
120
|
+
</div>
|
|
121
|
+
</div>
|
|
122
|
+
</form>
|
|
123
|
+
</mx-feedback-form>
|
|
124
|
+
"
|
|
125
|
+
`;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
|
2
|
+
|
|
3
|
+
exports[`Feedback Form 1`] = `"<div class="mx-feedback-form is-enhanced"><form method="post" novalidate=""><fieldset class="mx-fieldset mx-fieldset--plain mx-feedback-form__rating"><legend class="mx-legend">Was the information on this page useful?</legend><div class="mx-feedback-form__option"><input class="sr-only" id="feedback-yes" type="radio" value="yes" name="rating"><label class="mx-button mx-button--dark mx-button--outline" for="feedback-yes"><span class="mx-icon mx-icon--thumb"></span><span>Yes</span></label></div><div class="mx-feedback-form__option"><input class="sr-only" id="feedback-no" type="radio" value="no" name="rating"><label class="mx-button mx-button--dark mx-button--outline" for="feedback-no"><span class="mx-icon mx-icon--thumb mx-icon--rotate-180"></span><span>No</span></label></div></fieldset><p class="mx-feedback-form__secondary">If you need a response, <a href="#contact" class="mx-link">contact us</a></p><div class="mx-feedback-form__reveal"><div class="mx-form-item"><label class="mx-label" for="feedback-comment">How can we make it better?</label><textarea class="mx-input__textarea" id="feedback-comment" name="comment" aria-describedby="status-feedback-comment"></textarea></div><div class="mx-error-message" id="status-feedback-comment" role="alert" hidden="">This field is required.</div><div class="mx-form-actions"><button class="mx-button mx-button--dark" type="submit" data-pending="false" aria-busy="false"><span>Submit</span></button></div></div></form></div>"`;
|
|
4
|
+
|
|
5
|
+
exports[`Required Comment 1`] = `"<div class="mx-feedback-form is-enhanced"><form method="post" novalidate=""><fieldset class="mx-fieldset mx-fieldset--plain mx-feedback-form__rating"><legend class="mx-legend">Was the information on this page useful?</legend><div class="mx-feedback-form__option"><input class="sr-only" id="feedback-required-yes" type="radio" value="yes" name="rating"><label class="mx-button mx-button--dark mx-button--outline" for="feedback-required-yes"><span class="mx-icon mx-icon--thumb"></span><span>Yes</span></label></div><div class="mx-feedback-form__option"><input class="sr-only" id="feedback-required-no" type="radio" value="no" name="rating"><label class="mx-button mx-button--dark mx-button--outline" for="feedback-required-no"><span class="mx-icon mx-icon--thumb mx-icon--rotate-180"></span><span>No</span></label></div></fieldset><p class="mx-feedback-form__secondary">If you need a response, <a href="#contact" class="mx-link">contact us</a></p><div class="mx-feedback-form__reveal"><div class="mx-form-item"><label class="mx-label" for="feedback-required-comment">How can we make it better?</label><textarea class="mx-input__textarea" id="feedback-required-comment" name="comment" required="" aria-describedby="status-feedback-required-comment"></textarea></div><div class="mx-error-message" id="status-feedback-required-comment" role="alert">This field is required.</div><div class="mx-form-actions"><button class="mx-button mx-button--dark" type="submit" data-pending="false" aria-busy="false"><span>Submit</span></button></div></div></form></div>"`;
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FeedbackForm
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
@layer design-system.defaults {
|
|
6
|
+
mx-feedback-form {
|
|
7
|
+
display: block;
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
@layer design-system.components {
|
|
12
|
+
.mx-feedback-form {
|
|
13
|
+
display: block;
|
|
14
|
+
|
|
15
|
+
& form {
|
|
16
|
+
display: grid;
|
|
17
|
+
gap: var(--flow-gap, var(--gap));
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
& .mx-error-message {
|
|
21
|
+
margin-block-end: unset;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
& .mx-form-actions {
|
|
25
|
+
margin-block-start: var(--flow-gap, var(--gap));
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
.mx-feedback-form__rating {
|
|
30
|
+
display: flex;
|
|
31
|
+
flex-wrap: wrap;
|
|
32
|
+
gap: var(--spacing-s);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/* @public --feedback-form-icon-size */
|
|
36
|
+
.mx-feedback-form__option .mx-icon {
|
|
37
|
+
--icon-size: var(--feedback-form-icon-size, var(--spacing-m));
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/*
|
|
41
|
+
* The radio input stays in the DOM and keyboard/AT-operable (`.sr-only`, not `display:none`) —
|
|
42
|
+
* only its default appearance is hidden. The <label> is styled as a button (reusing the Button
|
|
43
|
+
* atom's own classes/custom properties) so it can act as the visible, clickable control; its
|
|
44
|
+
* `.mx-button--outline` modifier is undone by `:has(input:checked)` to show which is selected.
|
|
45
|
+
*/
|
|
46
|
+
.mx-feedback-form__option label {
|
|
47
|
+
cursor: pointer;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
.mx-feedback-form__option:has(input:checked) label {
|
|
51
|
+
--button-bg: var(--button-dark-bg, var(--link-colour, var(--colour-link)));
|
|
52
|
+
--button-fg: var(--button-dark-fg, var(--colour-foreground-reverse));
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.mx-feedback-form__option:has(input:focus-visible) label {
|
|
56
|
+
outline: var(--outline-size, 2px) var(--outline-style, solid) var(--outline-color, currentcolor);
|
|
57
|
+
outline-offset: var(--outline-offset, 2px);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/*
|
|
61
|
+
* The reveal is only gated behind a checked rating once JS has confirmed it can drive it
|
|
62
|
+
* (`is-enhanced`, added by the Web Component/React on mount) — matches BackToTop's
|
|
63
|
+
* `is-enhanced` convention. Without JS, the comment field and submit button stay visible and
|
|
64
|
+
* submittable so the form is never accidentally unusable.
|
|
65
|
+
*/
|
|
66
|
+
.mx-feedback-form.is-enhanced .mx-feedback-form__reveal {
|
|
67
|
+
display: none;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
.mx-feedback-form.is-enhanced:has(.mx-feedback-form__rating input:checked)
|
|
71
|
+
.mx-feedback-form__reveal {
|
|
72
|
+
display: block;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import "./Elements/FeedbackForm"
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
{% set baseClass = 'mx-feedback-form' %}
|
|
2
|
+
{% set attributes = (attributes ?? create_attribute()).addClass(baseClass) %}
|
|
3
|
+
{% set id = id|default('feedback-form') %}
|
|
4
|
+
{% set name = name|default('rating') %}
|
|
5
|
+
{% set question = question|default('Was the information on this page useful?') %}
|
|
6
|
+
{% set yesLabel = yesLabel|default('Yes') %}
|
|
7
|
+
{% set noLabel = noLabel|default('No') %}
|
|
8
|
+
{% set commentLabel = commentLabel|default('How can we make it better?') %}
|
|
9
|
+
{% set commentName = commentName|default('comment') %}
|
|
10
|
+
{% set requiredErrorMessage = requiredErrorMessage|default('This field is required.') %}
|
|
11
|
+
{% set submitLabel = submitLabel|default('Submit') %}
|
|
12
|
+
{% set method = method|default('post') %}
|
|
13
|
+
{% set commentId = id~'-comment' %}
|
|
14
|
+
|
|
15
|
+
{% set commentLabelMarkup %}
|
|
16
|
+
{% include '@mixtape/Form/Label/label.twig' with { id: commentId, title: commentLabel } only %}
|
|
17
|
+
{% endset %}
|
|
18
|
+
{% set commentField %}
|
|
19
|
+
{% include '@mixtape/Form/Textarea/input-textarea.twig' with {
|
|
20
|
+
id: commentId,
|
|
21
|
+
name: commentName,
|
|
22
|
+
placeholder: commentPlaceholder,
|
|
23
|
+
required: commentRequired,
|
|
24
|
+
attributes: create_attribute().setAttribute('aria-describedby', 'status-'~commentId),
|
|
25
|
+
} only %}
|
|
26
|
+
{% endset %}
|
|
27
|
+
{% set commentItem %}
|
|
28
|
+
{% include '@mixtape/Form/FormItem/form-item.twig' with {
|
|
29
|
+
id: commentId,
|
|
30
|
+
label: commentLabelMarkup,
|
|
31
|
+
fields: commentField,
|
|
32
|
+
} only %}
|
|
33
|
+
{% endset %}
|
|
34
|
+
{% set submitButton %}
|
|
35
|
+
{% include '@mixtape/Atom/Button/button.twig' with {
|
|
36
|
+
as: 'submit',
|
|
37
|
+
title: submitLabel,
|
|
38
|
+
modifiers: ['dark'],
|
|
39
|
+
} only %}
|
|
40
|
+
{% endset %}
|
|
41
|
+
|
|
42
|
+
<mx-feedback-form{{ attributes }}>
|
|
43
|
+
<form action="{{ action }}" method="{{ method }}">
|
|
44
|
+
{% if errorMessage %}
|
|
45
|
+
<div class="mx-feedback-form__error" role="alert">{{ errorMessage }}</div>
|
|
46
|
+
{% endif %}
|
|
47
|
+
|
|
48
|
+
<fieldset class="mx-fieldset mx-fieldset--plain mx-feedback-form__rating">
|
|
49
|
+
<legend class="mx-legend">{{ question }}</legend>
|
|
50
|
+
<div class="mx-feedback-form__option">
|
|
51
|
+
<input type="radio" class="sr-only" id="{{ id }}-yes" name="{{ name }}" value="yes">
|
|
52
|
+
<label class="mx-button mx-button--dark mx-button--outline" for="{{ id }}-yes">
|
|
53
|
+
{% include '@mixtape/Atom/Icon/icon.twig' with { icon: 'thumb' } only %}
|
|
54
|
+
<span>{{ yesLabel }}</span>
|
|
55
|
+
</label>
|
|
56
|
+
</div>
|
|
57
|
+
<div class="mx-feedback-form__option">
|
|
58
|
+
<input type="radio" class="sr-only" id="{{ id }}-no" name="{{ name }}" value="no">
|
|
59
|
+
<label class="mx-button mx-button--dark mx-button--outline" for="{{ id }}-no">
|
|
60
|
+
{% include '@mixtape/Atom/Icon/icon.twig' with { icon: 'thumb', rotate: 'rotate-180' } only %}
|
|
61
|
+
<span>{{ noLabel }}</span>
|
|
62
|
+
</label>
|
|
63
|
+
</div>
|
|
64
|
+
</fieldset>
|
|
65
|
+
|
|
66
|
+
{% if secondaryText %}
|
|
67
|
+
<p class="mx-feedback-form__secondary">
|
|
68
|
+
{{ secondaryText }}
|
|
69
|
+
</p>
|
|
70
|
+
{% endif %}
|
|
71
|
+
|
|
72
|
+
<div class="mx-feedback-form__reveal">
|
|
73
|
+
{{ commentItem }}
|
|
74
|
+
<div class="mx-error-message" id="status-{{ commentId }}" role="alert" hidden>{{ requiredErrorMessage }}</div>
|
|
75
|
+
<div class="mx-form-actions">
|
|
76
|
+
{{ submitButton }}
|
|
77
|
+
</div>
|
|
78
|
+
</div>
|
|
79
|
+
</form>
|
|
80
|
+
</mx-feedback-form>
|
package/src/Form/form.css
CHANGED
|
@@ -462,20 +462,6 @@
|
|
|
462
462
|
*/
|
|
463
463
|
|
|
464
464
|
@layer design-system.atoms {
|
|
465
|
-
@supports (appearance: base-select) {
|
|
466
|
-
.mx-input__select,
|
|
467
|
-
::picker(select) {
|
|
468
|
-
appearance: base-select;
|
|
469
|
-
}
|
|
470
|
-
|
|
471
|
-
::picker(select) {
|
|
472
|
-
border-radius: var(--border-radius);
|
|
473
|
-
inset-block-start: var(--spacing-xxxs);
|
|
474
|
-
border: var(--line-width, 2px) solid
|
|
475
|
-
var(--line-colour, var(--line-colour, var(--colour-border)));
|
|
476
|
-
}
|
|
477
|
-
}
|
|
478
|
-
|
|
479
465
|
.mx-input__select {
|
|
480
466
|
--outline-size: var(--line-width, 2px);
|
|
481
467
|
--outline-offset: calc(var(--outline-size, 2px) * -1);
|
|
@@ -489,21 +475,33 @@
|
|
|
489
475
|
padding-inline-end: var(--spacing-xl);
|
|
490
476
|
|
|
491
477
|
@supports (appearance: base-select) {
|
|
478
|
+
padding-inline-end: var(--form-spacing, var(--spacing-s));
|
|
479
|
+
align-items: center;
|
|
480
|
+
background-image: none;
|
|
481
|
+
|
|
492
482
|
&,
|
|
493
|
-
|
|
483
|
+
&::picker(select) {
|
|
494
484
|
appearance: base-select;
|
|
495
|
-
background-image: none;
|
|
496
|
-
padding-inline-end: 0;
|
|
497
485
|
}
|
|
498
486
|
|
|
499
|
-
|
|
487
|
+
&::picker(select) {
|
|
488
|
+
border-radius: var(--border-radius);
|
|
489
|
+
inset-block-start: var(--spacing-xxxs);
|
|
490
|
+
border: var(--line-width, 2px) solid
|
|
491
|
+
var(--line-colour, var(--line-colour, var(--colour-border)));
|
|
492
|
+
min-inline-size: anchor-size(width);
|
|
493
|
+
position-area: block-end center;
|
|
494
|
+
position-try-fallbacks: flip-block flip-inline;
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
& selectedcontent {
|
|
500
498
|
display: flex;
|
|
501
499
|
align-items: center;
|
|
502
500
|
block-size: 100%;
|
|
503
501
|
column-gap: var(--spacing-xxxs);
|
|
504
502
|
}
|
|
505
503
|
|
|
506
|
-
option {
|
|
504
|
+
& option {
|
|
507
505
|
padding-block: var(--spacing-xxs);
|
|
508
506
|
}
|
|
509
507
|
}
|
package/src/Introduction.mdx
CHANGED
|
@@ -14,7 +14,7 @@ import { Meta, Title, Subtitle } from "@storybook/addon-docs/blocks"
|
|
|
14
14
|
- Javascript is available in both React and Web Component formats.
|
|
15
15
|
- Provides Twig templates for each component
|
|
16
16
|
- Supports PINTO and Experience Builder integration.
|
|
17
|
-
- Is tested against WCAG 2.
|
|
17
|
+
- Is tested against WCAG 2.2 AA to ensure accessibility standards.
|
|
18
18
|
- Follows PreviousNext's high standards.
|
|
19
19
|
- Provide integration Documentation.
|
|
20
20
|
|
|
@@ -14,7 +14,7 @@ exports[`Everything 1`] = `
|
|
|
14
14
|
<a href="#">
|
|
15
15
|
News
|
|
16
16
|
</a>
|
|
17
|
-
<button class="mx-nav__toggle mx-icon mx-icon--chevron-down mx-icon--only">Sub-navigation</button>
|
|
17
|
+
<button class="mx-nav__toggle mx-icon mx-icon--chevron-down mx-icon--only" type="button">Sub-navigation</button>
|
|
18
18
|
<ul class="mx-nav__level-2">
|
|
19
19
|
<li>
|
|
20
20
|
<a href="#">
|
|
@@ -33,7 +33,7 @@ exports[`Everything 1`] = `
|
|
|
33
33
|
<a href="#">
|
|
34
34
|
About us
|
|
35
35
|
</a>
|
|
36
|
-
<button class="mx-nav__toggle mx-icon mx-icon--chevron-down mx-icon--only">Sub-navigation</button>
|
|
36
|
+
<button class="mx-nav__toggle mx-icon mx-icon--chevron-down mx-icon--only" type="button">Sub-navigation</button>
|
|
37
37
|
<ul class="mx-nav__level-2">
|
|
38
38
|
<li>
|
|
39
39
|
<a href="#">
|
|
@@ -57,7 +57,7 @@ exports[`Everything 1`] = `
|
|
|
57
57
|
<a href="#">
|
|
58
58
|
Contact
|
|
59
59
|
</a>
|
|
60
|
-
<button class="mx-nav__toggle mx-icon mx-icon--chevron-down mx-icon--only">Sub-navigation</button>
|
|
60
|
+
<button class="mx-nav__toggle mx-icon mx-icon--chevron-down mx-icon--only" type="button">Sub-navigation</button>
|
|
61
61
|
<ul class="mx-nav__level-2">
|
|
62
62
|
<li>
|
|
63
63
|
<a href="#">
|