@tpzdsp/next-toolkit 2.5.0 → 3.0.0
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/package.json +22 -13
- package/src/assets/styles/globals.css +75 -95
- package/src/assets/styles/ol.css +57 -16
- package/src/assets/styles/utils.css +80 -0
- package/src/components/Accordion/Accordion.css +85 -0
- package/src/components/Accordion/Accordion.stories.tsx +264 -0
- package/src/components/Accordion/Accordion.tsx +98 -0
- package/src/components/Alert/Alert.css +129 -0
- package/src/components/Alert/Alert.stories.tsx +291 -0
- package/src/components/Alert/Alert.tsx +76 -0
- package/src/components/BackLink/BackLink.css +12 -0
- package/src/components/BackLink/BackLink.stories.tsx +52 -0
- package/src/components/BackLink/BackLink.tsx +44 -0
- package/src/components/BackToTop/BackToTop.css +23 -0
- package/src/components/BackToTop/BackToTop.stories.tsx +41 -0
- package/src/components/BackToTop/BackToTop.tsx +48 -0
- package/src/components/Breadcrumb/Breadcrumb.css +42 -0
- package/src/components/Breadcrumb/Breadcrumb.stories.tsx +94 -0
- package/src/components/Breadcrumb/Breadcrumb.tsx +135 -0
- package/src/components/Button/Button.css +229 -0
- package/src/components/Button/Button.stories.tsx +140 -20
- package/src/components/Button/Button.tsx +53 -28
- package/src/components/Button/ButtonSkeleton.stories.tsx +50 -0
- package/src/components/Button/ButtonSkeleton.tsx +14 -0
- package/src/components/ButtonGroup/ButtonGroup.css +52 -0
- package/src/components/ButtonGroup/ButtonGroup.stories.tsx +156 -0
- package/src/components/ButtonGroup/ButtonGroup.tsx +50 -0
- package/src/components/ButtonLink/ButtonLink.css +114 -0
- package/src/components/ButtonLink/ButtonLink.stories.tsx +38 -51
- package/src/components/ButtonLink/ButtonLink.tsx +54 -23
- package/src/components/Card/Card.css +13 -0
- package/src/components/Card/Card.stories.tsx +98 -57
- package/src/components/Card/Card.tsx +4 -13
- package/src/components/CardGroup/CardGroup.css +10 -0
- package/src/components/CardGroup/CardGroup.stories.tsx +81 -0
- package/src/components/CardGroup/CardGroup.tsx +9 -0
- package/src/components/Checkbox/Checkbox.css +49 -0
- package/src/components/Checkbox/Checkbox.stories.tsx +86 -0
- package/src/components/Checkbox/Checkbox.tsx +32 -0
- package/src/components/Chip/Chip.css +54 -0
- package/src/components/Chip/Chip.stories.tsx +94 -0
- package/src/components/Chip/Chip.tsx +34 -0
- package/src/components/CookieBanner/CookieBanner.css +19 -0
- package/src/components/CookieBanner/CookieBanner.stories.tsx +52 -0
- package/src/components/CookieBanner/CookieBanner.tsx +55 -0
- package/src/components/CopyButton/CopyButton.stories.tsx +28 -0
- package/src/components/CopyButton/CopyButton.tsx +65 -0
- package/src/components/DateInput/DateInput.css +13 -0
- package/src/components/DateInput/DateInput.stories.tsx +131 -0
- package/src/components/DateInput/DateInput.test.tsx +21 -0
- package/src/components/DateInput/DateInput.tsx +98 -0
- package/src/components/Details/Details.css +28 -0
- package/src/components/Details/Details.stories.tsx +48 -0
- package/src/components/Details/Details.tsx +41 -0
- package/src/components/Dropdown/Dropdown.css +81 -0
- package/src/components/Dropdown/Dropdown.stories.tsx +131 -0
- package/src/components/Dropdown/Dropdown.tsx +69 -0
- package/src/components/ErrorBoundary/ErrorBoundary.stories.tsx +4 -39
- package/src/components/ErrorBoundary/ErrorBoundary.tsx +7 -4
- package/src/components/ErrorBoundary/ErrorFallback.tsx +32 -66
- package/src/components/ErrorModal/ErrorModal.css +32 -0
- package/src/components/ErrorModal/ErrorModal.stories.tsx +101 -0
- package/src/components/ErrorModal/ErrorModal.tsx +120 -0
- package/src/components/ErrorText/ErrorText.css +22 -0
- package/src/components/ErrorText/ErrorText.stories.tsx +42 -27
- package/src/components/ErrorText/ErrorText.tsx +10 -8
- package/src/components/ExternalLink/ExternalLink.css +12 -0
- package/src/components/ExternalLink/ExternalLink.stories.tsx +43 -0
- package/src/components/ExternalLink/ExternalLink.tsx +43 -0
- package/src/components/Fieldset/Fieldset.css +103 -0
- package/src/components/Fieldset/Fieldset.stories.tsx +304 -0
- package/src/components/Fieldset/Fieldset.tsx +38 -0
- package/src/components/FileUpload/FileUpload.css +85 -0
- package/src/components/FileUpload/FileUpload.stories.tsx +106 -0
- package/src/components/FileUpload/FileUpload.tsx +99 -0
- package/src/components/{layout/footer → Footer}/Copyright.tsx +4 -2
- package/src/components/Footer/Footer.stories.tsx +24 -0
- package/src/components/Footer/Footer.tsx +41 -0
- package/src/components/Footer/Licence.tsx +18 -0
- package/src/components/{layout/footer → Footer}/MetaLinks.tsx +8 -3
- package/src/components/Footer/Small/SmallFooter.tsx +43 -42
- package/src/components/Form/FormGroup.css +18 -0
- package/src/components/Form/FormGroup.stories.tsx +87 -0
- package/src/components/Form/FormGroup.tsx +16 -0
- package/src/components/{layout/header → Header}/Header.stories.tsx +26 -12
- package/src/components/Header/Header.test.tsx +87 -0
- package/src/components/Header/Header.tsx +303 -0
- package/src/components/Header/HeaderAppContent.tsx +120 -0
- package/src/components/Heading/Heading.css +40 -0
- package/src/components/Heading/Heading.stories.tsx +15 -5
- package/src/components/Heading/Heading.tsx +21 -44
- package/src/components/Heading/HeadingSkeleton.stories.tsx +30 -0
- package/src/components/Heading/HeadingSkeleton.tsx +14 -0
- package/src/components/Hero/Hero.css +19 -0
- package/src/components/Hero/Hero.stories.tsx +41 -0
- package/src/components/Hero/Hero.tsx +14 -0
- package/src/components/HintText/HintText.css +5 -0
- package/src/components/HintText/HintText.stories.tsx +29 -0
- package/src/components/HintText/HintText.tsx +13 -0
- package/src/components/InfoBox/InfoBox.css +38 -0
- package/src/components/InfoBox/InfoBox.stories.tsx +51 -403
- package/src/components/InfoBox/InfoBox.tsx +31 -158
- package/src/components/Input/Input.css +77 -0
- package/src/components/Input/Input.stories.tsx +123 -0
- package/src/components/Input/Input.tsx +74 -0
- package/src/components/InputGroup/InputGroup.css +140 -0
- package/src/components/InputGroup/InputGroup.stories.tsx +125 -0
- package/src/components/InputGroup/InputGroup.tsx +47 -0
- package/src/components/InsetText/InsetText.css +5 -0
- package/src/components/InsetText/InsetText.stories.tsx +30 -0
- package/src/components/InsetText/InsetText.tsx +9 -0
- package/src/components/Keyboard/Keyboard.css +9 -0
- package/src/components/Keyboard/Keyboard.stories.tsx +63 -0
- package/src/components/Keyboard/Keyboard.tsx +30 -0
- package/src/components/Label/Label.css +27 -0
- package/src/components/Label/Label.stories.tsx +40 -0
- package/src/components/Label/Label.tsx +17 -0
- package/src/components/LayerSwitcher/LayerSwitcher.css +59 -0
- package/src/components/LayerSwitcher/LayerSwitcher.stories.tsx +112 -0
- package/src/components/LayerSwitcher/LayerSwitcher.tsx +61 -0
- package/src/components/Layout/401/401.stories.tsx +23 -0
- package/src/components/Layout/401/401.tsx +1 -0
- package/src/components/Layout/403/403.stories.tsx +23 -0
- package/src/components/Layout/403/403.tsx +21 -0
- package/src/components/Layout/404/404.stories.tsx +23 -0
- package/src/components/Layout/404/404.tsx +28 -0
- package/src/components/Layout/500/500.stories.tsx +56 -0
- package/src/components/Layout/500/500.tsx +63 -0
- package/src/components/Layout/ButtonGroup/ButtonGroup.css +52 -0
- package/src/components/Layout/ButtonGroup/ButtonGroup.stories.tsx +156 -0
- package/src/components/Layout/ButtonGroup/ButtonGroup.tsx +50 -0
- package/src/components/Layout/HeadingGroup/HeadingGroup.css +21 -0
- package/src/components/Layout/HeadingGroup/HeadingGroup.stories.tsx +84 -0
- package/src/components/Layout/HeadingGroup/HeadingGroup.tsx +9 -0
- package/src/components/Layout/MainWrapper/MainWrapper.css +12 -0
- package/src/components/Layout/MainWrapper/MainWrapper.stories.tsx +36 -0
- package/src/components/Layout/MainWrapper/MainWrapper.tsx +14 -0
- package/src/components/Layout/PageShell/PageShell.css +42 -0
- package/src/components/Layout/PageShell/PageShell.stories.tsx +108 -0
- package/src/components/Layout/PageShell/PageShell.tsx +31 -0
- package/src/components/Layout/ParagraphGroup/ParagraphGroup.css +5 -0
- package/src/components/Layout/ParagraphGroup/ParagraphGroup.stories.tsx +34 -0
- package/src/components/Layout/ParagraphGroup/ParagraphGroup.tsx +9 -0
- package/src/components/Layout/Stack/Stack.css +29 -0
- package/src/components/Layout/Stack/Stack.stories.tsx +83 -0
- package/src/components/Layout/Stack/Stack.tsx +19 -0
- package/src/components/Layout/WidthContainer/WidthContainer.css +17 -0
- package/src/components/Layout/WidthContainer/WidthContainer.stories.tsx +59 -0
- package/src/components/Layout/WidthContainer/WidthContainer.tsx +13 -0
- package/src/components/Legend/Legend.css +95 -0
- package/src/components/Legend/Legend.stories.tsx +81 -0
- package/src/components/Legend/Legend.tsx +32 -0
- package/src/components/Legend/LegendDot.tsx +15 -0
- package/src/components/Legend/LegendPanel.stories.tsx +101 -0
- package/src/components/Legend/LegendPanel.tsx +68 -0
- package/src/components/Legend/LegendSkeleton.stories.tsx +87 -0
- package/src/components/Legend/LegendSkeleton.tsx +73 -0
- package/src/components/LegendSelect/LegendSelect.css +8 -0
- package/src/components/LegendSelect/LegendSelect.stories.tsx +80 -0
- package/src/components/LegendSelect/LegendSelect.tsx +26 -0
- package/src/components/Link/Link.css +98 -0
- package/src/components/Link/Link.stories.tsx +70 -0
- package/src/components/Link/Link.tsx +52 -0
- package/src/components/LinkButton/LinkButton.css +67 -0
- package/src/components/LinkButton/LinkButton.stories.tsx +90 -42
- package/src/components/LinkButton/LinkButton.tsx +50 -63
- package/src/components/LinkList/LinkList.css +28 -0
- package/src/components/LinkList/LinkList.stories.tsx +46 -0
- package/src/components/LinkList/LinkList.tsx +23 -0
- package/src/components/List/Li.tsx +9 -0
- package/src/components/List/List.css +9 -0
- package/src/components/List/OrderedList.stories.tsx +36 -0
- package/src/components/List/OrderedList.tsx +9 -0
- package/src/components/List/UnorderedList.stories.tsx +36 -0
- package/src/components/List/UnorderedList.tsx +9 -0
- package/src/components/LoadingBox/LoadingBox.css +27 -0
- package/src/components/LoadingBox/LoadingBox.stories.tsx +66 -0
- package/src/components/LoadingBox/LoadingBox.tsx +40 -0
- package/src/components/Modal/Modal.css +114 -0
- package/src/components/Modal/Modal.stories.tsx +41 -160
- package/src/components/Modal/Modal.tsx +132 -75
- package/src/components/NoScriptBanner/NoScriptBanner.css +17 -0
- package/src/components/NoScriptBanner/NoScriptBanner.stories.tsx +46 -0
- package/src/components/NoScriptBanner/NoScriptBanner.tsx +26 -0
- package/src/components/Paragraph/Paragraph.css +22 -0
- package/src/components/Paragraph/Paragraph.stories.tsx +1 -42
- package/src/components/Paragraph/Paragraph.tsx +4 -3
- package/src/components/Paragraph/ParagraphSkeleton.stories.tsx +44 -0
- package/src/components/Paragraph/ParagraphSkeleton.tsx +33 -0
- package/src/components/PasswordInput/PasswordInput.css +3 -0
- package/src/components/PasswordInput/PasswordInput.stories.tsx +47 -0
- package/src/components/PasswordInput/PasswordInput.tsx +45 -0
- package/src/components/PhaseBanner/PhaseBanner.css +12 -0
- package/src/components/PhaseBanner/PhaseBanner.stories.tsx +61 -0
- package/src/components/PhaseBanner/PhaseBanner.tsx +17 -0
- package/src/components/Popover/Popover.css +43 -0
- package/src/components/Popover/Popover.stories.tsx +102 -0
- package/src/components/Popover/Popover.tsx +40 -0
- package/src/components/Radio/Radio.css +69 -0
- package/src/components/Radio/Radio.stories.tsx +169 -0
- package/src/components/Radio/Radio.tsx +56 -0
- package/src/components/Resizable/Resizable.css +86 -0
- package/src/components/Resizable/Resizable.stories.tsx +123 -0
- package/src/components/Resizable/Resizable.tsx +86 -0
- package/src/components/ScrollArea/ScrollArea.css +9 -0
- package/src/components/ScrollArea/ScrollArea.stories.tsx +42 -0
- package/src/components/ScrollArea/ScrollArea.tsx +11 -0
- package/src/components/SearchBox/SearchBox.stories.tsx +88 -0
- package/src/components/SearchBox/SearchBox.tsx +36 -0
- package/src/components/Select/AsyncSelect.stories.tsx +84 -0
- package/src/components/Select/AsyncSelect.tsx +41 -0
- package/src/components/Select/Select.css +194 -0
- package/src/components/Select/Select.stories.tsx +162 -0
- package/src/components/Select/Select.test.tsx +36 -0
- package/src/components/Select/Select.tsx +291 -0
- package/src/components/Select/SelectSkeleton.stories.tsx +51 -0
- package/src/components/Select/SelectSkeleton.tsx +23 -0
- package/src/components/Separator/Separator.css +41 -0
- package/src/components/Separator/Separator.stories.tsx +63 -0
- package/src/components/Separator/Separator.tsx +42 -0
- package/src/components/Sidebar/ResizableSidebar.tsx +118 -0
- package/src/components/Sidebar/Sidebar.css +203 -0
- package/src/components/Sidebar/Sidebar.stories.tsx +438 -0
- package/src/components/Sidebar/Sidebar.tsx +225 -0
- package/src/components/Skeleton/Skeleton.css +16 -0
- package/src/components/Skeleton/Skeleton.stories.tsx +39 -0
- package/src/components/Skeleton/Skeleton.tsx +12 -0
- package/src/components/SkipLink/SkipLink.css +16 -0
- package/src/components/SkipLink/SkipLink.stories.tsx +40 -0
- package/src/components/SkipLink/SkipLink.tsx +15 -0
- package/src/components/Spinner/Spinner.css +30 -0
- package/src/components/Spinner/Spinner.stories.tsx +36 -0
- package/src/components/Spinner/Spinner.tsx +45 -0
- package/src/components/StartButton/StartButton.css +13 -0
- package/src/components/StartButton/StartButton.stories.tsx +68 -0
- package/src/components/StartButton/StartButton.tsx +50 -0
- package/src/components/SubmitButton/SubmitButton.stories.tsx +31 -0
- package/src/components/SubmitButton/SubmitButton.tsx +14 -0
- package/src/components/SummaryList/SummaryList.css +71 -0
- package/src/components/SummaryList/SummaryList.stories.tsx +211 -0
- package/src/components/SummaryList/SummaryList.tsx +41 -0
- package/src/components/SummaryList/SummaryListSkeleton.stories.tsx +67 -0
- package/src/components/SummaryList/SummaryListSkeleton.tsx +40 -0
- package/src/components/Tabs/Tabs.css +84 -0
- package/src/components/Tabs/Tabs.stories.tsx +133 -0
- package/src/components/Tabs/Tabs.tsx +66 -0
- package/src/components/Tag/Tag.css +8 -0
- package/src/components/Tag/Tag.stories.tsx +96 -0
- package/src/components/Tag/Tag.tsx +34 -0
- package/src/components/Textarea/Textarea.css +38 -0
- package/src/components/Textarea/Textarea.stories.tsx +131 -0
- package/src/components/Textarea/Textarea.tsx +50 -0
- package/src/components/TextareaCount/TextareaCount.css +17 -0
- package/src/components/TextareaCount/TextareaCount.stories.tsx +131 -0
- package/src/components/TextareaCount/TextareaCount.tsx +108 -0
- package/src/components/Tooltip/Tooltip.css +43 -0
- package/src/components/Tooltip/Tooltip.stories.tsx +110 -0
- package/src/components/Tooltip/Tooltip.tsx +53 -0
- package/src/components/WarningText/WarningText.css +20 -0
- package/src/components/WarningText/WarningText.stories.tsx +29 -0
- package/src/components/WarningText/WarningText.tsx +17 -0
- package/src/components/index.ts +342 -61
- package/src/errors/errorDisplay.ts +70 -0
- package/src/errors/index.ts +1 -0
- package/src/http/constants.ts +1 -0
- package/src/http/fetch.ts +7 -3
- package/src/map/LayerSwitcherPanel.tsx +2 -173
- package/src/map/LegendShim.tsx +2 -0
- package/src/map/MapComponent.tsx +7 -17
- package/src/map/MapControlsOverlay.tsx +68 -175
- package/src/map/Popup.tsx +71 -24
- package/src/map/geocoder/Geocoder.test.tsx +46 -3
- package/src/map/geocoder/Geocoder.tsx +155 -278
- package/src/map/index.ts +1 -1
- package/src/types/utils.ts +0 -10
- package/src/utils/components.ts +96 -0
- package/src/utils/index.ts +1 -0
- package/src/utils/utils.ts +0 -12
- package/src/assets/images/defra-logo.svg +0 -51
- package/src/assets/images/ea-logo.svg +0 -58
- package/src/assets/images/ogl.svg +0 -1
- package/src/components/Button/Button.test.tsx +0 -53
- package/src/components/ButtonLink/ButtonLink.test.tsx +0 -154
- package/src/components/Card/Card.test.tsx +0 -51
- package/src/components/ErrorBoundary/ErrorBoundary.test.tsx +0 -75
- package/src/components/ErrorBoundary/ErrorFallback.test.tsx +0 -107
- package/src/components/ErrorText/ErrorText.test.tsx +0 -33
- package/src/components/Heading/Heading.test.tsx +0 -22
- package/src/components/Hint/Hint.stories.tsx +0 -58
- package/src/components/Hint/Hint.test.tsx +0 -33
- package/src/components/Hint/Hint.tsx +0 -12
- package/src/components/InfoBox/InfoBox.test.tsx +0 -330
- package/src/components/InfoBox/types.ts +0 -6
- package/src/components/LinkButton/LinkButton.test.tsx +0 -177
- package/src/components/Modal/Modal.test.tsx +0 -246
- package/src/components/NotificationBanner/NotificationBanner.stories.tsx +0 -45
- package/src/components/NotificationBanner/NotificationBanner.test.tsx +0 -58
- package/src/components/NotificationBanner/NotificationBanner.tsx +0 -45
- package/src/components/Paragraph/Paragraph.test.tsx +0 -10
- package/src/components/SlidingPanel/SlidingPanel.stories.tsx +0 -129
- package/src/components/SlidingPanel/SlidingPanel.test.tsx +0 -83
- package/src/components/SlidingPanel/SlidingPanel.tsx +0 -258
- package/src/components/accordion/Accordion.stories.tsx +0 -234
- package/src/components/accordion/Accordion.test.tsx +0 -192
- package/src/components/accordion/Accordion.tsx +0 -73
- package/src/components/backToTop/BackToTop.stories.tsx +0 -407
- package/src/components/backToTop/BackToTop.test.tsx +0 -57
- package/src/components/backToTop/BackToTop.tsx +0 -134
- package/src/components/chip/Chip.stories.tsx +0 -61
- package/src/components/chip/Chip.test.tsx +0 -31
- package/src/components/chip/Chip.tsx +0 -23
- package/src/components/container/Container.tsx +0 -42
- package/src/components/cookieBanner/CookieBanner.stories.tsx +0 -257
- package/src/components/cookieBanner/CookieBanner.test.tsx +0 -68
- package/src/components/cookieBanner/CookieBanner.tsx +0 -73
- package/src/components/divider/RuleDivider.stories.tsx +0 -254
- package/src/components/divider/RuleDivider.test.tsx +0 -164
- package/src/components/divider/RuleDivider.tsx +0 -23
- package/src/components/dropdown/DropdownMenu.test.tsx +0 -211
- package/src/components/dropdown/DropdownMenu.tsx +0 -108
- package/src/components/dropdown/useDropdownMenu.ts +0 -249
- package/src/components/form/Input.stories.tsx +0 -435
- package/src/components/form/Input.test.tsx +0 -206
- package/src/components/form/Input.tsx +0 -23
- package/src/components/form/TextArea.stories.tsx +0 -464
- package/src/components/form/TextArea.test.tsx +0 -232
- package/src/components/form/TextArea.tsx +0 -23
- package/src/components/layout/footer/Footer.tsx +0 -26
- package/src/components/layout/footer/Licence.tsx +0 -19
- package/src/components/layout/header/Header.test.tsx +0 -36
- package/src/components/layout/header/Header.tsx +0 -90
- package/src/components/layout/header/HeaderAuthClient.test.tsx +0 -45
- package/src/components/layout/header/HeaderAuthClient.tsx +0 -40
- package/src/components/layout/header/HeaderNavClient.test.tsx +0 -44
- package/src/components/layout/header/HeaderNavClient.tsx +0 -67
- package/src/components/link/ExternalLink.test.tsx +0 -102
- package/src/components/link/ExternalLink.tsx +0 -29
- package/src/components/link/Link.tsx +0 -26
- package/src/components/select/Select.stories.tsx +0 -336
- package/src/components/select/Select.test.tsx +0 -474
- package/src/components/select/Select.tsx +0 -125
- package/src/components/select/SelectSkeleton.stories.tsx +0 -194
- package/src/components/select/SelectSkeleton.test.tsx +0 -104
- package/src/components/select/SelectSkeleton.tsx +0 -23
- package/src/components/select/common.ts +0 -3
- package/src/components/select/index.ts +0 -18
- package/src/components/skipLink/SkipLink.stories.tsx +0 -346
- package/src/components/skipLink/SkipLink.test.tsx +0 -22
- package/src/components/skipLink/SkipLink.tsx +0 -49
- package/src/map/LegendPanel.tsx +0 -85
- /package/src/{components → assets}/images/DefraLogo.tsx +0 -0
- /package/src/{components → assets}/images/EaLogo.tsx +0 -0
- /package/src/{components → assets}/images/OglLogo.tsx +0 -0
- /package/src/components/{googleAnalytics → GoogleAnalytics}/GlobalVars.tsx +0 -0
- /package/src/components/{googleAnalytics → GoogleAnalytics}/GoogleAnalytics.tsx +0 -0
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { ComponentProps } from 'react';
|
|
2
|
+
|
|
3
|
+
import { cn } from '../../utils/components';
|
|
4
|
+
import { Heading } from '../Heading/Heading';
|
|
5
|
+
import { HeadingGroup } from '../Layout/HeadingGroup/HeadingGroup';
|
|
6
|
+
|
|
7
|
+
export type NoScriptBannerProps = ComponentProps<'div'>;
|
|
8
|
+
|
|
9
|
+
export const NoScriptBanner = ({ className, children, ...props }: NoScriptBannerProps) => (
|
|
10
|
+
<noscript>
|
|
11
|
+
<div
|
|
12
|
+
role="region"
|
|
13
|
+
aria-label="JavaScript is not available"
|
|
14
|
+
className={cn('cn-noscript-banner', className)}
|
|
15
|
+
{...props}
|
|
16
|
+
>
|
|
17
|
+
<div className="cn-noscript-banner-inner">
|
|
18
|
+
<HeadingGroup>
|
|
19
|
+
<Heading level="h2">JavaScript is not available</Heading>
|
|
20
|
+
|
|
21
|
+
{children}
|
|
22
|
+
</HeadingGroup>
|
|
23
|
+
</div>
|
|
24
|
+
</div>
|
|
25
|
+
</noscript>
|
|
26
|
+
);
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
@layer components {
|
|
2
|
+
/* MARK: Paragraph */
|
|
3
|
+
.cn-paragraph {
|
|
4
|
+
@apply text-base;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
/* MARK: Skeleton
|
|
8
|
+
Stacks one bar per wrapped line. Overrides cn-skeleton's inline-block,
|
|
9
|
+
these are meant to be full lines, not inline text. */
|
|
10
|
+
.cn-paragraph-skeleton {
|
|
11
|
+
@apply flex flex-col gap-2;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
.cn-paragraph-skeleton-line {
|
|
15
|
+
@apply block h-4 w-full;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/* Shorter, matching where real wrapped text would naturally end mid-line. */
|
|
19
|
+
.cn-paragraph-skeleton-line-last {
|
|
20
|
+
@apply w-3/4;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -1,24 +1,16 @@
|
|
|
1
1
|
import type { Meta, StoryObj } from '@storybook/react-vite';
|
|
2
2
|
|
|
3
3
|
import { Paragraph } from './Paragraph';
|
|
4
|
-
import { ExternalLink } from '../link/ExternalLink';
|
|
5
4
|
|
|
6
5
|
const meta: Meta<typeof Paragraph> = {
|
|
7
|
-
title: 'Components/Paragraph',
|
|
6
|
+
title: 'Components/Paragraph/Paragraph',
|
|
8
7
|
component: Paragraph,
|
|
9
|
-
parameters: {
|
|
10
|
-
layout: 'padded',
|
|
11
|
-
},
|
|
12
8
|
tags: ['autodocs'],
|
|
13
9
|
argTypes: {
|
|
14
10
|
children: {
|
|
15
11
|
description: 'Content of the paragraph',
|
|
16
12
|
control: false,
|
|
17
13
|
},
|
|
18
|
-
className: {
|
|
19
|
-
description: 'Additional TailwindCSS classes to apply to the paragraph',
|
|
20
|
-
control: 'text',
|
|
21
|
-
},
|
|
22
14
|
},
|
|
23
15
|
args: {
|
|
24
16
|
children: 'Hello, this is some simple text',
|
|
@@ -31,13 +23,6 @@ type Story = StoryObj<typeof Paragraph>;
|
|
|
31
23
|
|
|
32
24
|
export const Default: Story = {};
|
|
33
25
|
|
|
34
|
-
export const CustomStyling: Story = {
|
|
35
|
-
args: {
|
|
36
|
-
className: 'text-yellow-800 p-2',
|
|
37
|
-
children: 'Hello, this is some simple text with custom styling',
|
|
38
|
-
},
|
|
39
|
-
};
|
|
40
|
-
|
|
41
26
|
export const LongText: Story = {
|
|
42
27
|
args: {
|
|
43
28
|
children:
|
|
@@ -45,29 +30,3 @@ export const LongText: Story = {
|
|
|
45
30
|
'It is used to test how the Paragraph component handles large amounts of text.',
|
|
46
31
|
},
|
|
47
32
|
};
|
|
48
|
-
|
|
49
|
-
export const WithLink: Story = {
|
|
50
|
-
args: {
|
|
51
|
-
children: (
|
|
52
|
-
<span>
|
|
53
|
-
This paragraph contains a <ExternalLink href="https://storybook.js.org/">link</ExternalLink>
|
|
54
|
-
.
|
|
55
|
-
</span>
|
|
56
|
-
),
|
|
57
|
-
},
|
|
58
|
-
};
|
|
59
|
-
|
|
60
|
-
export const ImageAndText: Story = {
|
|
61
|
-
args: {
|
|
62
|
-
children: (
|
|
63
|
-
<div>
|
|
64
|
-
<img
|
|
65
|
-
src="https://images.unsplash.com/photo-1563991655280-cb95c90ca2fb?w=500&auto=format&fit=crop&q=60&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxzZWFyY2h8M3x8bm8lMjBjb3B5cmlnaHR8ZW58MHx8MHx8fDA%3D"
|
|
66
|
-
alt="Card"
|
|
67
|
-
/>
|
|
68
|
-
|
|
69
|
-
<p>This is text about the image</p>
|
|
70
|
-
</div>
|
|
71
|
-
),
|
|
72
|
-
},
|
|
73
|
-
};
|
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { ComponentProps } from 'react';
|
|
2
|
+
|
|
2
3
|
import { cn } from '../../utils';
|
|
3
4
|
|
|
4
|
-
export type ParagraphProps =
|
|
5
|
+
export type ParagraphProps = ComponentProps<'p'>;
|
|
5
6
|
|
|
6
7
|
export const Paragraph = ({ className, children, ...props }: ParagraphProps) => {
|
|
7
8
|
return (
|
|
8
|
-
<p className={cn('
|
|
9
|
+
<p className={cn('cn-paragraph', className)} {...props}>
|
|
9
10
|
{children}
|
|
10
11
|
</p>
|
|
11
12
|
);
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react-vite';
|
|
2
|
+
|
|
3
|
+
import { ParagraphSkeleton } from './ParagraphSkeleton';
|
|
4
|
+
|
|
5
|
+
const meta: Meta<typeof ParagraphSkeleton> = {
|
|
6
|
+
title: 'Components/Paragraph/Skeleton',
|
|
7
|
+
component: ParagraphSkeleton,
|
|
8
|
+
tags: ['autodocs'],
|
|
9
|
+
parameters: {
|
|
10
|
+
docs: {
|
|
11
|
+
description: {
|
|
12
|
+
component:
|
|
13
|
+
'Placeholder for a Paragraph while its real text is loading. Renders one bar per wrapped line (`lines`, defaults to 3), with the last line narrower to mimic where real text naturally wraps.',
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
argTypes: {
|
|
18
|
+
lines: { control: { type: 'number', min: 1, max: 6 } },
|
|
19
|
+
},
|
|
20
|
+
args: {
|
|
21
|
+
lines: 3,
|
|
22
|
+
},
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export default meta;
|
|
26
|
+
|
|
27
|
+
type Story = StoryObj<typeof ParagraphSkeleton>;
|
|
28
|
+
|
|
29
|
+
export const Default: Story = {
|
|
30
|
+
render: (args) => (
|
|
31
|
+
<div className="max-w-md">
|
|
32
|
+
<ParagraphSkeleton {...args} />
|
|
33
|
+
</div>
|
|
34
|
+
),
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export const SingleLine: Story = {
|
|
38
|
+
args: { lines: 1 },
|
|
39
|
+
render: (args) => (
|
|
40
|
+
<div className="max-w-md">
|
|
41
|
+
<ParagraphSkeleton {...args} />
|
|
42
|
+
</div>
|
|
43
|
+
),
|
|
44
|
+
};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { ComponentProps } from 'react';
|
|
2
|
+
|
|
3
|
+
import { cn } from '../../utils/components';
|
|
4
|
+
import { Skeleton } from '../Skeleton/Skeleton';
|
|
5
|
+
|
|
6
|
+
// Stable, fixed identifiers rather than the array index, even though these
|
|
7
|
+
// are decorative and never reorder, so a line's identity is never tied to
|
|
8
|
+
// its position at render time.
|
|
9
|
+
const LINE_KEYS = ['line-1', 'line-2', 'line-3', 'line-4', 'line-5', 'line-6'] as const;
|
|
10
|
+
|
|
11
|
+
export type ParagraphSkeletonProps = Omit<ComponentProps<'div'>, 'children'> & {
|
|
12
|
+
children?: never;
|
|
13
|
+
/** Number of wrapped lines to show. Defaults to 3. */
|
|
14
|
+
lines?: number;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export const ParagraphSkeleton = ({ className, lines = 3, ...props }: ParagraphSkeletonProps) => {
|
|
18
|
+
const lineKeys = LINE_KEYS.slice(0, lines);
|
|
19
|
+
|
|
20
|
+
return (
|
|
21
|
+
<div aria-hidden className={cn('cn-paragraph-skeleton', className)} {...props}>
|
|
22
|
+
{lineKeys.map((key, index) => (
|
|
23
|
+
<Skeleton
|
|
24
|
+
key={key}
|
|
25
|
+
className={cn(
|
|
26
|
+
'cn-paragraph-skeleton-line',
|
|
27
|
+
index === lineKeys.length - 1 && 'cn-paragraph-skeleton-line-last',
|
|
28
|
+
)}
|
|
29
|
+
/>
|
|
30
|
+
))}
|
|
31
|
+
</div>
|
|
32
|
+
);
|
|
33
|
+
};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react-vite';
|
|
2
|
+
|
|
3
|
+
import { PasswordInput } from './PasswordInput';
|
|
4
|
+
import { ErrorText } from '../ErrorText/ErrorText';
|
|
5
|
+
import { FormGroup } from '../Form/FormGroup';
|
|
6
|
+
import { Label } from '../Label/Label';
|
|
7
|
+
|
|
8
|
+
const meta: Meta<typeof PasswordInput> = {
|
|
9
|
+
title: 'Components/PasswordInput',
|
|
10
|
+
component: PasswordInput,
|
|
11
|
+
tags: ['autodocs'],
|
|
12
|
+
parameters: {
|
|
13
|
+
docs: {
|
|
14
|
+
description: {
|
|
15
|
+
component: 'Help users to create and enter passwords.',
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
argTypes: {},
|
|
20
|
+
args: {},
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export default meta;
|
|
24
|
+
|
|
25
|
+
type Story = StoryObj<typeof PasswordInput>;
|
|
26
|
+
|
|
27
|
+
export const Default: Story = {};
|
|
28
|
+
|
|
29
|
+
export const Disabled: Story = {
|
|
30
|
+
render: () => (
|
|
31
|
+
<fieldset disabled>
|
|
32
|
+
<PasswordInput />
|
|
33
|
+
</fieldset>
|
|
34
|
+
),
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export const Invalid: Story = {
|
|
38
|
+
render: () => (
|
|
39
|
+
<FormGroup invalid>
|
|
40
|
+
<Label htmlFor="password-invalid">Password</Label>
|
|
41
|
+
|
|
42
|
+
<ErrorText id="password-error">Enter your password</ErrorText>
|
|
43
|
+
|
|
44
|
+
<PasswordInput id="password-invalid" aria-invalid aria-describedby="password-error" />
|
|
45
|
+
</FormGroup>
|
|
46
|
+
),
|
|
47
|
+
};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { useId, useState, type ComponentProps } from 'react';
|
|
4
|
+
|
|
5
|
+
import { LuEye, LuEyeClosed } from 'react-icons/lu';
|
|
6
|
+
|
|
7
|
+
import { Button } from '../Button/Button';
|
|
8
|
+
import { Input } from '../Input/Input';
|
|
9
|
+
import { InputGroup, InputSuffix } from '../InputGroup/InputGroup';
|
|
10
|
+
|
|
11
|
+
export type PasswordInputProps = Omit<
|
|
12
|
+
ComponentProps<typeof Input>,
|
|
13
|
+
'type' | 'size' | 'appearance' | 'children'
|
|
14
|
+
>;
|
|
15
|
+
|
|
16
|
+
export const PasswordInput = ({ autoComplete, id, ...props }: PasswordInputProps) => {
|
|
17
|
+
const generatedId = useId();
|
|
18
|
+
const inputId = id ?? generatedId;
|
|
19
|
+
|
|
20
|
+
const [shown, setShown] = useState(false);
|
|
21
|
+
|
|
22
|
+
return (
|
|
23
|
+
<InputGroup>
|
|
24
|
+
<Input
|
|
25
|
+
id={inputId}
|
|
26
|
+
type={shown ? 'text' : 'password'}
|
|
27
|
+
autoComplete={autoComplete ?? 'current-password'}
|
|
28
|
+
spellCheck={false}
|
|
29
|
+
{...props}
|
|
30
|
+
/>
|
|
31
|
+
|
|
32
|
+
<InputSuffix>
|
|
33
|
+
<Button
|
|
34
|
+
appearance="secondary"
|
|
35
|
+
variant="icon"
|
|
36
|
+
aria-label={shown ? 'Hide password' : 'Show password'}
|
|
37
|
+
aria-controls={inputId}
|
|
38
|
+
onClick={() => setShown((previous) => !previous)}
|
|
39
|
+
>
|
|
40
|
+
{shown ? <LuEye aria-hidden /> : <LuEyeClosed aria-hidden />}
|
|
41
|
+
</Button>
|
|
42
|
+
</InputSuffix>
|
|
43
|
+
</InputGroup>
|
|
44
|
+
);
|
|
45
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
@layer components {
|
|
2
|
+
/* MARK: Phase banner
|
|
3
|
+
Displayed at the top of the page to communicate service phase (Alpha, Beta).
|
|
4
|
+
Bottom border matches GDS. Layout is flex rather than the legacy display:table. */
|
|
5
|
+
.cn-phase-banner {
|
|
6
|
+
@apply py-gds-2 border-b border-divider;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
.cn-phase-banner-content {
|
|
10
|
+
@apply flex items-center gap-gds-2 text-base m-0;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react-vite';
|
|
2
|
+
|
|
3
|
+
import { PhaseBanner } from './PhaseBanner';
|
|
4
|
+
import { Link } from '../Link/Link';
|
|
5
|
+
import { Tag } from '../Tag/Tag';
|
|
6
|
+
|
|
7
|
+
const meta: Meta<typeof PhaseBanner> = {
|
|
8
|
+
title: 'Components/PhaseBanner',
|
|
9
|
+
component: PhaseBanner,
|
|
10
|
+
tags: ['autodocs'],
|
|
11
|
+
parameters: {
|
|
12
|
+
docs: {
|
|
13
|
+
description: {
|
|
14
|
+
component:
|
|
15
|
+
'Displayed at the top of a page to communicate that a service is in an early development phase. Accepts a `Tag` via the `tag` prop and descriptive text as `children`.',
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
args: {
|
|
20
|
+
children: 'This is a new service – your feedback will help us to improve it.',
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export default meta;
|
|
25
|
+
|
|
26
|
+
type Story = StoryObj<typeof PhaseBanner>;
|
|
27
|
+
|
|
28
|
+
export const Alpha: Story = {
|
|
29
|
+
args: {
|
|
30
|
+
tag: (
|
|
31
|
+
<Tag size="sm" appearance="info">
|
|
32
|
+
Alpha
|
|
33
|
+
</Tag>
|
|
34
|
+
),
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
export const Beta: Story = {
|
|
39
|
+
args: {
|
|
40
|
+
tag: (
|
|
41
|
+
<Tag size="sm" appearance="info">
|
|
42
|
+
Beta
|
|
43
|
+
</Tag>
|
|
44
|
+
),
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
export const WithFeedbackLink: Story = {
|
|
49
|
+
args: {
|
|
50
|
+
tag: (
|
|
51
|
+
<Tag size="sm" appearance="info">
|
|
52
|
+
Beta
|
|
53
|
+
</Tag>
|
|
54
|
+
),
|
|
55
|
+
children: (
|
|
56
|
+
<>
|
|
57
|
+
This is a new service – <Link href="#">give your feedback</Link> to help us improve it.
|
|
58
|
+
</>
|
|
59
|
+
),
|
|
60
|
+
},
|
|
61
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { ComponentProps, ReactElement } from 'react';
|
|
2
|
+
|
|
3
|
+
import { cn } from '../../utils/components';
|
|
4
|
+
import { Tag } from '../Tag/Tag';
|
|
5
|
+
|
|
6
|
+
export type PhaseBannerProps = ComponentProps<'div'> & {
|
|
7
|
+
tag: ReactElement<ComponentProps<typeof Tag>, typeof Tag>;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export const PhaseBanner = ({ tag, children, className, ...props }: PhaseBannerProps) => (
|
|
11
|
+
<div data-slot="phase-banner" className={cn('cn-phase-banner', className)} {...props}>
|
|
12
|
+
<p className="cn-phase-banner-content">
|
|
13
|
+
{tag}
|
|
14
|
+
<span className="cn-phase-banner-text">{children}</span>
|
|
15
|
+
</p>
|
|
16
|
+
</div>
|
|
17
|
+
);
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
@layer components {
|
|
2
|
+
/* MARK: Popover content
|
|
3
|
+
Same panel treatment as Tooltip (panel bg + border) but with more
|
|
4
|
+
padding and no max-width cap, consumers control width via className.
|
|
5
|
+
Portal-rendered so DOM order is always safe above page content, but
|
|
6
|
+
cn-z-overlay still matters against other elements that set their own
|
|
7
|
+
high z-index (e.g. a resizable handle's cn-z-top). */
|
|
8
|
+
.cn-popover-content {
|
|
9
|
+
@apply panel cn-z-overlay p-gds-3 text-base text-body;
|
|
10
|
+
|
|
11
|
+
&[data-state='open'] {
|
|
12
|
+
animation: cn-popover-in 0.1s ease-out;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
&[data-state='closed'] {
|
|
16
|
+
animation: cn-popover-out 0.075s ease-in;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
.cn-popover-arrow {
|
|
21
|
+
fill: var(--color-panel-border);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
@keyframes cn-popover-in {
|
|
25
|
+
from {
|
|
26
|
+
opacity: 0;
|
|
27
|
+
transform: scale(0.97);
|
|
28
|
+
}
|
|
29
|
+
to {
|
|
30
|
+
opacity: 1;
|
|
31
|
+
transform: scale(1);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
@keyframes cn-popover-out {
|
|
36
|
+
from {
|
|
37
|
+
opacity: 1;
|
|
38
|
+
}
|
|
39
|
+
to {
|
|
40
|
+
opacity: 0;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react-vite';
|
|
2
|
+
|
|
3
|
+
import { Popover, PopoverContent, PopoverTrigger } from './Popover';
|
|
4
|
+
import { Button } from '../Button/Button';
|
|
5
|
+
import { Label } from '../Label/Label';
|
|
6
|
+
import { Paragraph } from '../Paragraph/Paragraph';
|
|
7
|
+
import { Textarea } from '../Textarea/Textarea';
|
|
8
|
+
|
|
9
|
+
const meta: Meta<typeof Popover> = {
|
|
10
|
+
title: 'Components/Popover',
|
|
11
|
+
component: Popover,
|
|
12
|
+
tags: ['autodocs'],
|
|
13
|
+
parameters: {
|
|
14
|
+
docs: {
|
|
15
|
+
description: {
|
|
16
|
+
component:
|
|
17
|
+
'A floating panel anchored to a trigger element, activated by click or tap. Use it to surface supplementary content, filters, or short forms without navigating away from the current page. Because it activates on click rather than hover, it works correctly on both desktop and touch devices. Prefer Popover over Tooltip whenever touch support is needed or the content is longer than a short label.',
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export default meta;
|
|
24
|
+
|
|
25
|
+
type Story = StoryObj<typeof Popover>;
|
|
26
|
+
|
|
27
|
+
export const Default: Story = {
|
|
28
|
+
render: () => (
|
|
29
|
+
<div className="flex items-center justify-center min-h-40">
|
|
30
|
+
<Popover>
|
|
31
|
+
<PopoverTrigger asChild>
|
|
32
|
+
<Button appearance="secondary">More information</Button>
|
|
33
|
+
</PopoverTrigger>
|
|
34
|
+
|
|
35
|
+
<PopoverContent>
|
|
36
|
+
<Paragraph>
|
|
37
|
+
Payments are issued quarterly once your evidence has been reviewed and approved by your
|
|
38
|
+
area coordinator.
|
|
39
|
+
</Paragraph>
|
|
40
|
+
</PopoverContent>
|
|
41
|
+
</Popover>
|
|
42
|
+
</div>
|
|
43
|
+
),
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
export const WithForm: Story = {
|
|
47
|
+
parameters: {
|
|
48
|
+
docs: {
|
|
49
|
+
description: {
|
|
50
|
+
story:
|
|
51
|
+
'Interactive content inside the popover. Popover does not trap focus, so tab order continues naturally through any form controls inside it.',
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
render: () => (
|
|
56
|
+
<div className="flex items-center justify-center min-h-40">
|
|
57
|
+
<Popover>
|
|
58
|
+
<PopoverTrigger asChild>
|
|
59
|
+
<Button appearance="secondary">Add note</Button>
|
|
60
|
+
</PopoverTrigger>
|
|
61
|
+
|
|
62
|
+
<PopoverContent className="w-72">
|
|
63
|
+
<div className="flex flex-col gap-gds-2">
|
|
64
|
+
<Label className="text-sm font-bold" htmlFor="popover-note">
|
|
65
|
+
Note
|
|
66
|
+
</Label>
|
|
67
|
+
|
|
68
|
+
<Textarea id="popover-note" rows={3} placeholder="Enter a note..." />
|
|
69
|
+
|
|
70
|
+
<Button className="self-end">Save</Button>
|
|
71
|
+
</div>
|
|
72
|
+
</PopoverContent>
|
|
73
|
+
</Popover>
|
|
74
|
+
</div>
|
|
75
|
+
),
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
export const Positions: Story = {
|
|
79
|
+
parameters: {
|
|
80
|
+
docs: {
|
|
81
|
+
description: {
|
|
82
|
+
story:
|
|
83
|
+
'The popover repositions automatically when it would overflow the viewport, but you can set a preferred side.',
|
|
84
|
+
},
|
|
85
|
+
},
|
|
86
|
+
},
|
|
87
|
+
render: () => (
|
|
88
|
+
<div className="flex gap-gds-4 flex-wrap items-center justify-center min-h-40">
|
|
89
|
+
{(['top', 'right', 'bottom', 'left'] as const).map((side) => (
|
|
90
|
+
<Popover key={side}>
|
|
91
|
+
<PopoverTrigger asChild>
|
|
92
|
+
<Button appearance="secondary">{side}</Button>
|
|
93
|
+
</PopoverTrigger>
|
|
94
|
+
|
|
95
|
+
<PopoverContent side={side}>
|
|
96
|
+
<Paragraph>Appears on the {side}</Paragraph>
|
|
97
|
+
</PopoverContent>
|
|
98
|
+
</Popover>
|
|
99
|
+
))}
|
|
100
|
+
</div>
|
|
101
|
+
),
|
|
102
|
+
};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import type { ComponentProps } from 'react';
|
|
4
|
+
|
|
5
|
+
import { Popover as PopoverPrimitive } from 'radix-ui';
|
|
6
|
+
|
|
7
|
+
import { cn } from '../../utils/components';
|
|
8
|
+
|
|
9
|
+
export const Popover = ({ ...props }: ComponentProps<typeof PopoverPrimitive.Root>) => (
|
|
10
|
+
<PopoverPrimitive.Root data-slot="popover" {...props} />
|
|
11
|
+
);
|
|
12
|
+
|
|
13
|
+
export const PopoverTrigger = ({ ...props }: ComponentProps<typeof PopoverPrimitive.Trigger>) => (
|
|
14
|
+
<PopoverPrimitive.Trigger data-slot="popover-trigger" {...props} />
|
|
15
|
+
);
|
|
16
|
+
|
|
17
|
+
export const PopoverAnchor = ({ ...props }: ComponentProps<typeof PopoverPrimitive.Anchor>) => (
|
|
18
|
+
<PopoverPrimitive.Anchor data-slot="popover-anchor" {...props} />
|
|
19
|
+
);
|
|
20
|
+
|
|
21
|
+
export const PopoverContent = ({
|
|
22
|
+
className,
|
|
23
|
+
align = 'center',
|
|
24
|
+
sideOffset = 6,
|
|
25
|
+
children,
|
|
26
|
+
...props
|
|
27
|
+
}: ComponentProps<typeof PopoverPrimitive.Content>) => (
|
|
28
|
+
<PopoverPrimitive.Portal>
|
|
29
|
+
<PopoverPrimitive.Content
|
|
30
|
+
data-slot="popover-content"
|
|
31
|
+
align={align}
|
|
32
|
+
sideOffset={sideOffset}
|
|
33
|
+
className={cn('cn-popover-content', className)}
|
|
34
|
+
{...props}
|
|
35
|
+
>
|
|
36
|
+
{children}
|
|
37
|
+
<PopoverPrimitive.Arrow className="cn-popover-arrow" />
|
|
38
|
+
</PopoverPrimitive.Content>
|
|
39
|
+
</PopoverPrimitive.Portal>
|
|
40
|
+
);
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
@layer components {
|
|
2
|
+
/* MARK: Radio
|
|
3
|
+
Radix RadioGroup.Item renders a <button role="radio">.
|
|
4
|
+
Border is explicit (not @apply cn-form-border) because appearance:none on
|
|
5
|
+
<button> can override utility-layer border styles. */
|
|
6
|
+
.cn-radio {
|
|
7
|
+
@apply relative rounded-full appearance-none cursor-pointer flex-none box-border bg-white p-0
|
|
8
|
+
outline-none;
|
|
9
|
+
border: var(--border-width-form) solid var(--color-divider-input);
|
|
10
|
+
|
|
11
|
+
&:focus:not(:disabled) {
|
|
12
|
+
@apply outline-focus border-4 outline-offset-1;
|
|
13
|
+
box-shadow: 0 0 0 var(--outline-width-focus) var(--color-focus);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
&:disabled {
|
|
17
|
+
@apply opacity-50 cursor-not-allowed;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/* MARK: Indicator
|
|
22
|
+
RadioGroup.Indicator only mounts when checked, styled as a black dot.
|
|
23
|
+
Absolutely positioned + translate(-50%, -50%) rather than the parent's
|
|
24
|
+
flex items-center/justify-center: flex centering resolves (container -
|
|
25
|
+
item) / 2 during layout, which has to snap to a whole device pixel, so
|
|
26
|
+
a fractional remainder rounds asymmetrically (one side up, one down) at
|
|
27
|
+
1x DPR, visible as the dot sitting a pixel off-centre, while the exact
|
|
28
|
+
same fraction is imperceptible at 2x/3x DPR where it still lands on a
|
|
29
|
+
clean device pixel either way. translate is resolved in the compositor
|
|
30
|
+
rather than layout, so it isn't pixel-snapped the same way. This also
|
|
31
|
+
matches real GDS: govuk-radios positions its own dot with absolute
|
|
32
|
+
top/left, not flexbox. */
|
|
33
|
+
.cn-radio-indicator {
|
|
34
|
+
@apply absolute top-1/2 left-1/2 -translate-1/2 block rounded-full bg-body;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/* MARK: Sizes */
|
|
38
|
+
.cn-radio-size-sm {
|
|
39
|
+
@apply w-6 h-6;
|
|
40
|
+
|
|
41
|
+
& .cn-radio-indicator {
|
|
42
|
+
@apply w-3 h-3;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.cn-radio-size-base {
|
|
47
|
+
@apply w-10 h-10;
|
|
48
|
+
|
|
49
|
+
& .cn-radio-indicator {
|
|
50
|
+
@apply w-5 h-5;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/* MARK: Group
|
|
55
|
+
gap-gds-2 matches GDS's own govuk-radios__item margin-bottom (10px).
|
|
56
|
+
Radix reflects the orientation prop as aria-orientation on the group's
|
|
57
|
+
own root, but doesn't do anything visual with it itself (it's only used
|
|
58
|
+
internally for arrow-key roving focus direction), so the row layout for
|
|
59
|
+
orientation="horizontal" has to be applied here. flex-wrap + the wider
|
|
60
|
+
gap-x match GDS's own govuk-radios--inline (wraps rather than
|
|
61
|
+
overflowing, govuk-spacing(4) between items horizontally). */
|
|
62
|
+
.cn-radio-group {
|
|
63
|
+
@apply flex flex-col gap-gds-2;
|
|
64
|
+
|
|
65
|
+
&[aria-orientation='horizontal'] {
|
|
66
|
+
@apply flex-row flex-wrap items-center gap-x-gds-4 gap-y-gds-2;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|