@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,67 @@
|
|
|
1
|
+
@layer components {
|
|
2
|
+
/* MARK: LinkButton
|
|
3
|
+
An <a> styled to look like a Button. Use for navigation that needs
|
|
4
|
+
button affordance (e.g. cancel links in form button groups).
|
|
5
|
+
Thin wrappers over cn-button-* so all appearance/size/focus behaviour
|
|
6
|
+
stays in one place. */
|
|
7
|
+
|
|
8
|
+
.cn-link-button {
|
|
9
|
+
@apply cn-button;
|
|
10
|
+
|
|
11
|
+
/* A link doesn't get the pressed button illusion. Keep the shadow bar
|
|
12
|
+
visible on active instead of clearing it like cn-button does. */
|
|
13
|
+
&:active:not(:disabled):not(:focus) {
|
|
14
|
+
box-shadow: 0 var(--cn-button-shadow-size, 0px) 0 var(--cn-button-shadow-color, transparent);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/* MARK: Appearances */
|
|
19
|
+
|
|
20
|
+
.cn-link-button-appearance-primary {
|
|
21
|
+
@apply cn-button-appearance-primary;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
.cn-link-button-appearance-secondary {
|
|
25
|
+
@apply cn-button-appearance-secondary;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.cn-link-button-appearance-destructive {
|
|
29
|
+
@apply cn-button-appearance-destructive;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.cn-link-button-appearance-inverse {
|
|
33
|
+
@apply cn-button-appearance-inverse;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
.cn-link-button-appearance-ghost {
|
|
37
|
+
@apply cn-button-appearance-ghost;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
.cn-link-button-appearance-panel {
|
|
41
|
+
@apply cn-button-appearance-panel;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/* MARK: Variants */
|
|
45
|
+
|
|
46
|
+
.cn-link-button-variant-cta {
|
|
47
|
+
@apply cn-button-variant-cta;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
.cn-link-button-variant-icon {
|
|
51
|
+
@apply cn-button-variant-icon;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/* MARK: Sizes */
|
|
55
|
+
|
|
56
|
+
.cn-link-button-size-sm {
|
|
57
|
+
@apply cn-button-size-sm;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.cn-link-button-size-base {
|
|
61
|
+
@apply cn-button-size-base;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.cn-link-button-size-lg {
|
|
65
|
+
@apply cn-button-size-lg;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
@@ -1,74 +1,122 @@
|
|
|
1
|
+
import { LuArrowRight } from 'react-icons/lu';
|
|
2
|
+
|
|
1
3
|
import type { Meta, StoryObj } from '@storybook/react-vite';
|
|
2
4
|
|
|
3
5
|
import { LinkButton } from './LinkButton';
|
|
4
6
|
|
|
5
|
-
const meta = {
|
|
7
|
+
const meta: Meta<typeof LinkButton> = {
|
|
6
8
|
title: 'Components/LinkButton',
|
|
7
9
|
component: LinkButton,
|
|
10
|
+
tags: ['autodocs'],
|
|
8
11
|
parameters: {
|
|
9
|
-
|
|
12
|
+
docs: {
|
|
13
|
+
description: {
|
|
14
|
+
component:
|
|
15
|
+
'Use LinkButton to render an anchor styled as a button. Use this instead of Button when the action navigates as it renders a real <a> element with correct link semantics and the same touch target as a Button.',
|
|
16
|
+
},
|
|
17
|
+
},
|
|
10
18
|
},
|
|
11
|
-
tags: ['autodocs'],
|
|
12
19
|
argTypes: {
|
|
20
|
+
appearance: {
|
|
21
|
+
control: { type: 'radio' },
|
|
22
|
+
options: ['primary', 'secondary', 'destructive', 'inverse', 'ghost', 'panel'],
|
|
23
|
+
},
|
|
13
24
|
variant: {
|
|
14
|
-
control: '
|
|
15
|
-
options: ['
|
|
25
|
+
control: { type: 'radio' },
|
|
26
|
+
options: ['default', 'cta', 'icon'],
|
|
16
27
|
},
|
|
17
|
-
|
|
18
|
-
control: '
|
|
28
|
+
size: {
|
|
29
|
+
control: { type: 'radio' },
|
|
30
|
+
options: ['sm', 'base', 'lg'],
|
|
19
31
|
},
|
|
32
|
+
asChild: { control: 'boolean' },
|
|
33
|
+
children: { control: 'text' },
|
|
34
|
+
},
|
|
35
|
+
args: {
|
|
36
|
+
href: '/',
|
|
37
|
+
appearance: 'primary',
|
|
38
|
+
size: 'base',
|
|
39
|
+
children: 'Continue',
|
|
20
40
|
},
|
|
21
|
-
}
|
|
41
|
+
};
|
|
22
42
|
|
|
23
43
|
export default meta;
|
|
24
|
-
|
|
44
|
+
|
|
45
|
+
type Story = StoryObj<typeof LinkButton>;
|
|
25
46
|
|
|
26
47
|
export const Primary: Story = {
|
|
27
|
-
args: {
|
|
28
|
-
children: 'Explore data',
|
|
29
|
-
href: '/explore',
|
|
30
|
-
variant: 'primary',
|
|
31
|
-
},
|
|
48
|
+
args: { appearance: 'primary' },
|
|
32
49
|
};
|
|
33
50
|
|
|
34
51
|
export const Secondary: Story = {
|
|
35
|
-
args: {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
},
|
|
52
|
+
args: { appearance: 'secondary' },
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
export const Destructive: Story = {
|
|
56
|
+
args: { appearance: 'destructive' },
|
|
40
57
|
};
|
|
41
58
|
|
|
42
59
|
export const Inverse: Story = {
|
|
43
|
-
args: {
|
|
44
|
-
children: 'Get started',
|
|
45
|
-
href: '/start',
|
|
46
|
-
variant: 'inverse',
|
|
47
|
-
},
|
|
60
|
+
args: { appearance: 'inverse' },
|
|
48
61
|
};
|
|
49
62
|
|
|
50
|
-
export const
|
|
51
|
-
args: {
|
|
52
|
-
children: 'Visit GOV.UK',
|
|
53
|
-
href: 'https://www.gov.uk',
|
|
54
|
-
variant: 'primary',
|
|
55
|
-
},
|
|
63
|
+
export const Ghost: Story = {
|
|
64
|
+
args: { appearance: 'ghost' },
|
|
56
65
|
};
|
|
57
66
|
|
|
58
|
-
export const
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
67
|
+
export const Sizes: Story = {
|
|
68
|
+
render: (args) => (
|
|
69
|
+
<div className="flex items-center gap-3">
|
|
70
|
+
<LinkButton {...args} size="sm">
|
|
71
|
+
Small
|
|
72
|
+
</LinkButton>
|
|
73
|
+
|
|
74
|
+
<LinkButton {...args} size="base">
|
|
75
|
+
Default
|
|
76
|
+
</LinkButton>
|
|
77
|
+
|
|
78
|
+
<LinkButton {...args} size="lg">
|
|
79
|
+
Large
|
|
80
|
+
</LinkButton>
|
|
81
|
+
</div>
|
|
82
|
+
),
|
|
65
83
|
};
|
|
66
84
|
|
|
67
|
-
export const
|
|
85
|
+
export const ClickToAction: Story = {
|
|
86
|
+
render: (args) => (
|
|
87
|
+
<div className="flex items-center gap-3">
|
|
88
|
+
<LinkButton {...args} appearance="primary" variant="cta">
|
|
89
|
+
Start now
|
|
90
|
+
</LinkButton>
|
|
91
|
+
|
|
92
|
+
<LinkButton {...args} appearance="secondary" variant="cta">
|
|
93
|
+
Learn more
|
|
94
|
+
</LinkButton>
|
|
95
|
+
</div>
|
|
96
|
+
),
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
export const IconButton: Story = {
|
|
68
100
|
args: {
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
variant: 'primary',
|
|
72
|
-
className: 'px-8 py-4 text-xl',
|
|
101
|
+
variant: 'icon',
|
|
102
|
+
children: <LuArrowRight />,
|
|
73
103
|
},
|
|
74
104
|
};
|
|
105
|
+
|
|
106
|
+
export const IconSizes: Story = {
|
|
107
|
+
render: (args) => (
|
|
108
|
+
<div className="flex items-center gap-3">
|
|
109
|
+
<LinkButton {...args} variant="icon" size="sm">
|
|
110
|
+
<LuArrowRight />
|
|
111
|
+
</LinkButton>
|
|
112
|
+
|
|
113
|
+
<LinkButton {...args} variant="icon" size="base">
|
|
114
|
+
<LuArrowRight />
|
|
115
|
+
</LinkButton>
|
|
116
|
+
|
|
117
|
+
<LinkButton {...args} variant="icon" size="lg">
|
|
118
|
+
<LuArrowRight />
|
|
119
|
+
</LinkButton>
|
|
120
|
+
</div>
|
|
121
|
+
),
|
|
122
|
+
};
|
|
@@ -1,80 +1,67 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { ComponentProps } from 'react';
|
|
2
2
|
|
|
3
|
-
import
|
|
3
|
+
import { Slot } from 'radix-ui';
|
|
4
4
|
|
|
5
|
-
import
|
|
6
|
-
import { cn } from '../../utils';
|
|
5
|
+
import { cn } from '../../utils/components';
|
|
7
6
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
openInNewTab?: boolean;
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
export type LinkButtonProps = ExtendProps<'a', Props>;
|
|
7
|
+
const LINK_BUTTON_APPEARANCES = {
|
|
8
|
+
primary: 'cn-link-button-appearance-primary',
|
|
9
|
+
secondary: 'cn-link-button-appearance-secondary',
|
|
10
|
+
destructive: 'cn-link-button-appearance-destructive',
|
|
11
|
+
inverse: 'cn-link-button-appearance-inverse',
|
|
12
|
+
ghost: 'cn-link-button-appearance-ghost',
|
|
13
|
+
panel: 'cn-link-button-appearance-panel',
|
|
14
|
+
} as const;
|
|
20
15
|
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
};
|
|
16
|
+
const LINK_BUTTON_VARIANTS = {
|
|
17
|
+
default: 'cn-link-button-variant-default',
|
|
18
|
+
cta: 'cn-link-button-variant-cta',
|
|
19
|
+
icon: 'cn-link-button-variant-icon',
|
|
20
|
+
} as const;
|
|
26
21
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
if (href.startsWith('http://') || href.startsWith('https://') || href.startsWith('//')) {
|
|
33
|
-
return true;
|
|
34
|
-
}
|
|
22
|
+
const LINK_BUTTON_SIZES = {
|
|
23
|
+
sm: 'cn-link-button-size-sm',
|
|
24
|
+
base: 'cn-link-button-size-base',
|
|
25
|
+
lg: 'cn-link-button-size-lg',
|
|
26
|
+
} as const;
|
|
35
27
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
}
|
|
28
|
+
export type LinkButtonAppearance = keyof typeof LINK_BUTTON_APPEARANCES;
|
|
29
|
+
export type LinkButtonVariant = keyof typeof LINK_BUTTON_VARIANTS;
|
|
30
|
+
export type LinkButtonSize = keyof typeof LINK_BUTTON_SIZES;
|
|
40
31
|
|
|
41
|
-
|
|
32
|
+
export type LinkButtonProps = ComponentProps<'a'> & {
|
|
33
|
+
asChild?: boolean;
|
|
34
|
+
appearance?: LinkButtonAppearance;
|
|
35
|
+
variant?: LinkButtonVariant;
|
|
36
|
+
size?: LinkButtonSize;
|
|
42
37
|
};
|
|
43
38
|
|
|
44
|
-
// NOTE: some of the styles are applied in `tailwind.css`, under `Button Styles`
|
|
45
39
|
export const LinkButton = ({
|
|
46
|
-
href,
|
|
47
|
-
variant = 'primary',
|
|
48
|
-
openInNewTab = false,
|
|
49
40
|
className,
|
|
50
|
-
|
|
41
|
+
appearance = 'primary',
|
|
42
|
+
variant = 'default',
|
|
43
|
+
size = 'base',
|
|
44
|
+
asChild = false,
|
|
51
45
|
...props
|
|
52
46
|
}: LinkButtonProps) => {
|
|
53
|
-
const
|
|
54
|
-
`sm:w-auto text-lg relative inline-flex w-full outline-none items-center border-transparent
|
|
55
|
-
justify-center border-2 text-center active-enabled:translate-y-[2px] focus:shadow-focus
|
|
56
|
-
focus:border-focus focus:shadow-[inset_0_0_0_1px] focus-idle:border-focus
|
|
57
|
-
focus-idle:text-focus-text focus-idle:bg-focus focus-idle:shadow-border-input
|
|
58
|
-
disabled:opacity-50 disabled:hover:cursor-not-allowed button`,
|
|
59
|
-
VARIANTS[variant],
|
|
60
|
-
className,
|
|
61
|
-
);
|
|
62
|
-
|
|
63
|
-
const isExternal = isExternalUrl(href);
|
|
64
|
-
|
|
65
|
-
// External link or forced new tab - use <a> tag with appropriate attributes
|
|
66
|
-
if (isExternal || openInNewTab) {
|
|
67
|
-
return (
|
|
68
|
-
<a href={href} target="_blank" rel="noopener noreferrer" className={buttonClasses} {...props}>
|
|
69
|
-
{children}
|
|
70
|
-
</a>
|
|
71
|
-
);
|
|
72
|
-
}
|
|
47
|
+
const Comp = asChild ? Slot.Root : 'a';
|
|
73
48
|
|
|
74
|
-
// Internal link - use Next.js Link for client-side navigation
|
|
75
49
|
return (
|
|
76
|
-
<
|
|
77
|
-
{
|
|
78
|
-
|
|
50
|
+
<Comp
|
|
51
|
+
{...props}
|
|
52
|
+
data-slot="link-button"
|
|
53
|
+
data-appearance={appearance}
|
|
54
|
+
data-variant={variant}
|
|
55
|
+
data-size={size}
|
|
56
|
+
className={cn(
|
|
57
|
+
'cn-link-button inline-flex shrink-0 items-center justify-center whitespace-nowrap',
|
|
58
|
+
'outline-none select-none',
|
|
59
|
+
'[&_svg]:pointer-events-none [&_svg]:shrink-0',
|
|
60
|
+
LINK_BUTTON_APPEARANCES[appearance],
|
|
61
|
+
LINK_BUTTON_VARIANTS[variant],
|
|
62
|
+
LINK_BUTTON_SIZES[size],
|
|
63
|
+
className,
|
|
64
|
+
)}
|
|
65
|
+
/>
|
|
79
66
|
);
|
|
80
67
|
};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
@layer components {
|
|
2
|
+
/* MARK: LinkList */
|
|
3
|
+
.cn-link-list {
|
|
4
|
+
@apply list-none m-0 p-0 flex flex-col gap-gds-2;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
/* MARK: Item
|
|
8
|
+
Bold applies to whatever link the consumer renders as children, so it
|
|
9
|
+
doesn't need to be repeated at every call site. */
|
|
10
|
+
.cn-link-list-item {
|
|
11
|
+
@apply flex items-center gap-gds-2;
|
|
12
|
+
|
|
13
|
+
& .cn-link {
|
|
14
|
+
@apply font-bold;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/* MARK: Icon
|
|
19
|
+
Decorative circle, shrink-0 so it keeps its size if the link text wraps
|
|
20
|
+
onto a second line. */
|
|
21
|
+
.cn-link-list-item-icon {
|
|
22
|
+
@apply flex items-center justify-center shrink-0 size-8 rounded-full bg-wash text-body;
|
|
23
|
+
|
|
24
|
+
& svg {
|
|
25
|
+
@apply size-5;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react-vite';
|
|
2
|
+
|
|
3
|
+
import { LinkList, LinkListItem } from './LinkList';
|
|
4
|
+
import { Link } from '../Link/Link';
|
|
5
|
+
|
|
6
|
+
const meta: Meta<typeof LinkList> = {
|
|
7
|
+
title: 'Components/LinkList',
|
|
8
|
+
component: LinkList,
|
|
9
|
+
tags: ['autodocs'],
|
|
10
|
+
parameters: {
|
|
11
|
+
docs: {
|
|
12
|
+
description: {
|
|
13
|
+
component:
|
|
14
|
+
'A vertical list of links, each preceded by an arrow icon in a circle. Deliberately has no heading of its own, place one above the list if you need one. No appearance or size variants yet, add them if a second use case needs one.',
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export default meta;
|
|
21
|
+
|
|
22
|
+
type Story = StoryObj<typeof LinkList>;
|
|
23
|
+
|
|
24
|
+
export const Default: Story = {
|
|
25
|
+
render: () => (
|
|
26
|
+
<LinkList className="max-w-xs">
|
|
27
|
+
<LinkListItem>
|
|
28
|
+
<Link href="#" appearance="contrast">
|
|
29
|
+
Frequently asked questions
|
|
30
|
+
</Link>
|
|
31
|
+
</LinkListItem>
|
|
32
|
+
|
|
33
|
+
<LinkListItem>
|
|
34
|
+
<Link href="#" appearance="contrast">
|
|
35
|
+
Glossary
|
|
36
|
+
</Link>
|
|
37
|
+
</LinkListItem>
|
|
38
|
+
|
|
39
|
+
<LinkListItem>
|
|
40
|
+
<Link href="#" appearance="contrast">
|
|
41
|
+
Give feedback
|
|
42
|
+
</Link>
|
|
43
|
+
</LinkListItem>
|
|
44
|
+
</LinkList>
|
|
45
|
+
),
|
|
46
|
+
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { ComponentProps } from 'react';
|
|
2
|
+
|
|
3
|
+
import { LuArrowRight } from 'react-icons/lu';
|
|
4
|
+
|
|
5
|
+
import { cn } from '../../utils/components';
|
|
6
|
+
|
|
7
|
+
export type LinkListProps = ComponentProps<'ul'>;
|
|
8
|
+
|
|
9
|
+
export const LinkList = ({ className, ...props }: LinkListProps) => (
|
|
10
|
+
<ul data-slot="link-list" className={cn('cn-link-list', className)} {...props} />
|
|
11
|
+
);
|
|
12
|
+
|
|
13
|
+
export type LinkListItemProps = ComponentProps<'li'>;
|
|
14
|
+
|
|
15
|
+
export const LinkListItem = ({ className, children, ...props }: LinkListItemProps) => (
|
|
16
|
+
<li data-slot="link-list-item" className={cn('cn-link-list-item', className)} {...props}>
|
|
17
|
+
<span className="cn-link-list-item-icon" aria-hidden>
|
|
18
|
+
<LuArrowRight />
|
|
19
|
+
</span>
|
|
20
|
+
|
|
21
|
+
{children}
|
|
22
|
+
</li>
|
|
23
|
+
);
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react-vite';
|
|
2
|
+
|
|
3
|
+
import { Li } from './Li';
|
|
4
|
+
import { OrderedList } from './OrderedList';
|
|
5
|
+
|
|
6
|
+
const meta: Meta<typeof OrderedList> = {
|
|
7
|
+
title: 'Components/Ol',
|
|
8
|
+
component: OrderedList,
|
|
9
|
+
tags: ['autodocs'],
|
|
10
|
+
parameters: {
|
|
11
|
+
docs: {
|
|
12
|
+
description: {
|
|
13
|
+
component:
|
|
14
|
+
'Use lists to make blocks of text easier to read, and to break information into manageable chunks.',
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
argTypes: {},
|
|
19
|
+
args: {},
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export default meta;
|
|
23
|
+
|
|
24
|
+
type Story = StoryObj<typeof OrderedList>;
|
|
25
|
+
|
|
26
|
+
export const Default: Story = {
|
|
27
|
+
render: () => (
|
|
28
|
+
<OrderedList>
|
|
29
|
+
<Li>Task 1</Li>
|
|
30
|
+
|
|
31
|
+
<Li>Task 2</Li>
|
|
32
|
+
|
|
33
|
+
<Li>Task 3</Li>
|
|
34
|
+
</OrderedList>
|
|
35
|
+
),
|
|
36
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { ComponentProps } from 'react';
|
|
2
|
+
|
|
3
|
+
import { cn } from '../../utils';
|
|
4
|
+
|
|
5
|
+
export type OrderedListProps = ComponentProps<'ol'>;
|
|
6
|
+
|
|
7
|
+
export const OrderedList = ({ className, ...props }: OrderedListProps) => {
|
|
8
|
+
return <ol className={cn('cn-ol', className)} {...props} />;
|
|
9
|
+
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react-vite';
|
|
2
|
+
|
|
3
|
+
import { Li } from './Li';
|
|
4
|
+
import { UnorderedList } from './UnorderedList';
|
|
5
|
+
|
|
6
|
+
const meta: Meta<typeof UnorderedList> = {
|
|
7
|
+
title: 'Components/Ul',
|
|
8
|
+
component: UnorderedList,
|
|
9
|
+
tags: ['autodocs'],
|
|
10
|
+
parameters: {
|
|
11
|
+
docs: {
|
|
12
|
+
description: {
|
|
13
|
+
component:
|
|
14
|
+
'Use lists to make blocks of text easier to read, and to break information into manageable chunks.',
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
argTypes: {},
|
|
19
|
+
args: {},
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export default meta;
|
|
23
|
+
|
|
24
|
+
type Story = StoryObj<typeof UnorderedList>;
|
|
25
|
+
|
|
26
|
+
export const Default: Story = {
|
|
27
|
+
render: () => (
|
|
28
|
+
<UnorderedList>
|
|
29
|
+
<Li>Task 1</Li>
|
|
30
|
+
|
|
31
|
+
<Li>Task 2</Li>
|
|
32
|
+
|
|
33
|
+
<Li>Task 3</Li>
|
|
34
|
+
</UnorderedList>
|
|
35
|
+
),
|
|
36
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { ComponentProps } from 'react';
|
|
2
|
+
|
|
3
|
+
import { cn } from '../../utils';
|
|
4
|
+
|
|
5
|
+
export type UnorderedListProps = ComponentProps<'ul'>;
|
|
6
|
+
|
|
7
|
+
export const UnorderedList = ({ className, ...props }: UnorderedListProps) => {
|
|
8
|
+
return <ul className={cn('cn-ul', className)} {...props} />;
|
|
9
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
@layer components {
|
|
2
|
+
/* MARK: LoadingBox
|
|
3
|
+
relative establishes the containing block the overlay positions
|
|
4
|
+
against. */
|
|
5
|
+
.cn-loading-box {
|
|
6
|
+
@apply relative;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
/* Always mounted (see LoadingBox.tsx), faded and set inert when not
|
|
10
|
+
loading rather than mounted/unmounted, so a single opacity transition
|
|
11
|
+
covers fading in and out without a timer to unmount after the
|
|
12
|
+
animation ends. cn-z-top (not cn-z-overlay) since this only needs to
|
|
13
|
+
sit above its own local content, not above every other overlay on the
|
|
14
|
+
page. */
|
|
15
|
+
.cn-loading-box-overlay {
|
|
16
|
+
@apply absolute inset-0 flex items-center justify-center bg-panel/85 opacity-0
|
|
17
|
+
pointer-events-none transition-opacity duration-300 cn-z-top;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
.cn-loading-box-overlay[data-loading] {
|
|
21
|
+
@apply opacity-100 pointer-events-auto;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
.cn-loading-box-spinner {
|
|
25
|
+
@apply h-12 w-12 text-body;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { useState } from 'react';
|
|
4
|
+
|
|
5
|
+
import type { Meta, StoryObj } from '@storybook/react-vite';
|
|
6
|
+
|
|
7
|
+
import { LoadingBox } from './LoadingBox';
|
|
8
|
+
import { Button } from '../Button/Button';
|
|
9
|
+
import { Paragraph } from '../Paragraph/Paragraph';
|
|
10
|
+
|
|
11
|
+
const meta: Meta<typeof LoadingBox> = {
|
|
12
|
+
title: 'Components/LoadingBox',
|
|
13
|
+
component: LoadingBox,
|
|
14
|
+
tags: ['autodocs'],
|
|
15
|
+
parameters: {
|
|
16
|
+
docs: {
|
|
17
|
+
description: {
|
|
18
|
+
component:
|
|
19
|
+
"Wraps content that loads asynchronously. When loading is true, a spinner fades in over a translucent overlay; the overlay is always mounted (just faded and set inert when off) rather than mounted/unmounted, so it never needs a timer to remove itself after the fade finishes. The children are inert while loading, so content that's about to be replaced can't be focused or clicked through the overlay.",
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export default meta;
|
|
26
|
+
|
|
27
|
+
type Story = StoryObj<typeof LoadingBox>;
|
|
28
|
+
|
|
29
|
+
export const Default: Story = {
|
|
30
|
+
args: {
|
|
31
|
+
loading: true,
|
|
32
|
+
children: (
|
|
33
|
+
<Paragraph>
|
|
34
|
+
This content sits behind the loading overlay. Toggle the `loading` control to see it fade.
|
|
35
|
+
</Paragraph>
|
|
36
|
+
),
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
const ToggleExample = () => {
|
|
41
|
+
const [loading, setLoading] = useState(false);
|
|
42
|
+
|
|
43
|
+
return (
|
|
44
|
+
<div className="flex flex-col gap-gds-4">
|
|
45
|
+
<Button
|
|
46
|
+
onClick={() => {
|
|
47
|
+
setLoading(true);
|
|
48
|
+
setTimeout(() => setLoading(false), 2000);
|
|
49
|
+
}}
|
|
50
|
+
>
|
|
51
|
+
Simulate loading
|
|
52
|
+
</Button>
|
|
53
|
+
|
|
54
|
+
<LoadingBox loading={loading}>
|
|
55
|
+
<Paragraph>
|
|
56
|
+
Some asynchronously loaded content lives here. Click the button above to see the overlay
|
|
57
|
+
fade in, then back out after two seconds.
|
|
58
|
+
</Paragraph>
|
|
59
|
+
</LoadingBox>
|
|
60
|
+
</div>
|
|
61
|
+
);
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
export const Toggle: Story = {
|
|
65
|
+
render: () => <ToggleExample />,
|
|
66
|
+
};
|