@tpzdsp/next-toolkit 2.5.1 → 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 +21 -12
- 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
|
@@ -1,171 +1,44 @@
|
|
|
1
|
-
|
|
1
|
+
import type { ComponentProps, ReactNode } from 'react';
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { LuInfo } from 'react-icons/lu';
|
|
4
4
|
|
|
5
|
-
import {
|
|
5
|
+
import { cn } from '../../utils/components';
|
|
6
|
+
import { Popover, PopoverContent, PopoverTrigger } from '../Popover/Popover';
|
|
6
7
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
flip,
|
|
12
|
-
shift,
|
|
13
|
-
arrow,
|
|
14
|
-
useClick,
|
|
15
|
-
useDismiss,
|
|
16
|
-
useRole,
|
|
17
|
-
useInteractions,
|
|
18
|
-
FloatingArrow,
|
|
19
|
-
FloatingFocusManager,
|
|
20
|
-
FloatingPortal,
|
|
21
|
-
type Placement,
|
|
22
|
-
} from '@floating-ui/react';
|
|
23
|
-
|
|
24
|
-
import type { ExtendProps } from '../../types';
|
|
25
|
-
import { cn } from '../../utils';
|
|
26
|
-
|
|
27
|
-
type Props = {
|
|
28
|
-
/** Optional title displayed at the top of the info box content */
|
|
29
|
-
title?: string;
|
|
30
|
-
/** Content to display inside the info box */
|
|
8
|
+
export type InfoBoxProps = Pick<
|
|
9
|
+
ComponentProps<typeof PopoverContent>,
|
|
10
|
+
'side' | 'align' | 'sideOffset' | 'className'
|
|
11
|
+
> & {
|
|
31
12
|
children: ReactNode;
|
|
32
|
-
|
|
33
|
-
defaultOpen?: boolean;
|
|
34
|
-
/** Callback when the info box opens or closes */
|
|
35
|
-
onOpenChange?: (isOpen: boolean) => void;
|
|
36
|
-
/** Maximum width of the info box (default: '320px') */
|
|
37
|
-
maxWidth?: string;
|
|
38
|
-
/** Custom aria-label for the trigger button (default: 'Show information') */
|
|
39
|
-
triggerLabel?: string;
|
|
40
|
-
/** Preferred placement (Floating UI will auto-adjust if needed) */
|
|
41
|
-
placement?: Placement;
|
|
42
|
-
/** Custom icon component to replace the default FaInfoCircle */
|
|
43
|
-
icon?: ComponentType<{ className?: string }>;
|
|
13
|
+
label?: string;
|
|
44
14
|
};
|
|
45
15
|
|
|
46
|
-
export type InfoBoxProps = ExtendProps<'div', Props>;
|
|
47
|
-
|
|
48
16
|
export const InfoBox = ({
|
|
49
|
-
title,
|
|
50
17
|
children,
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
placement = 'bottom-start',
|
|
56
|
-
icon: Icon = FaInfoCircle,
|
|
18
|
+
label = 'More information',
|
|
19
|
+
side,
|
|
20
|
+
align,
|
|
21
|
+
sideOffset,
|
|
57
22
|
className,
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
const arrowRef = useRef(null);
|
|
62
|
-
|
|
63
|
-
const { refs, floatingStyles, context } = useFloating({
|
|
64
|
-
open: isOpen,
|
|
65
|
-
onOpenChange: (open) => {
|
|
66
|
-
setIsOpen(open);
|
|
67
|
-
onOpenChange?.(open);
|
|
68
|
-
},
|
|
69
|
-
placement,
|
|
70
|
-
middleware: [
|
|
71
|
-
offset(12), // Distance from trigger
|
|
72
|
-
flip(), // Flip to opposite side if not enough space
|
|
73
|
-
shift({ padding: 8 }), // Shift along the axis to stay in viewport
|
|
74
|
-
arrow({ element: arrowRef }), // Arrow pointing to trigger
|
|
75
|
-
],
|
|
76
|
-
whileElementsMounted: autoUpdate, // Update position on scroll/resize
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
const click = useClick(context);
|
|
80
|
-
const dismiss = useDismiss(context);
|
|
81
|
-
const role = useRole(context);
|
|
82
|
-
|
|
83
|
-
const { getReferenceProps, getFloatingProps } = useInteractions([click, dismiss, role]);
|
|
84
|
-
|
|
85
|
-
const triggerId = useId();
|
|
86
|
-
const contentId = useId();
|
|
87
|
-
const titleId = useId();
|
|
88
|
-
|
|
89
|
-
const triggerClasses = cn(
|
|
90
|
-
// Base styles - button structure only
|
|
91
|
-
'inline-flex items-center justify-center',
|
|
92
|
-
'w-6 h-6 rounded-full',
|
|
93
|
-
'bg-transparent border-none',
|
|
94
|
-
// Focus outline only
|
|
95
|
-
'focus:outline focus:outline-[3px] focus:outline-focus',
|
|
96
|
-
);
|
|
97
|
-
|
|
98
|
-
const iconClasses = cn(
|
|
99
|
-
// Icon size
|
|
100
|
-
'w-5 h-5',
|
|
101
|
-
// Icon color - yellow when open, auto when closed
|
|
102
|
-
isOpen ? 'text-focus' : '',
|
|
103
|
-
// Hover state - yellow
|
|
104
|
-
'hover:text-focus',
|
|
105
|
-
// Focus state - yellow
|
|
106
|
-
'focus:text-focus',
|
|
107
|
-
// Transition
|
|
108
|
-
'transition-colors duration-150',
|
|
109
|
-
);
|
|
110
|
-
|
|
111
|
-
const contentClasses = cn(
|
|
112
|
-
// Base styles
|
|
113
|
-
'bg-white rounded-lg shadow-lg border border-gray-200',
|
|
114
|
-
'p-4',
|
|
115
|
-
// Width constraints
|
|
116
|
-
'min-w-[280px]',
|
|
117
|
-
// Z-index
|
|
118
|
-
'z-50',
|
|
119
|
-
);
|
|
120
|
-
|
|
121
|
-
return (
|
|
122
|
-
<div className={cn('relative inline-flex', className)} {...props}>
|
|
23
|
+
}: InfoBoxProps) => (
|
|
24
|
+
<Popover>
|
|
25
|
+
<PopoverTrigger asChild>
|
|
123
26
|
<button
|
|
124
|
-
ref={refs.setReference}
|
|
125
|
-
id={triggerId}
|
|
126
27
|
type="button"
|
|
127
|
-
aria-
|
|
128
|
-
|
|
129
|
-
aria-haspopup="dialog"
|
|
130
|
-
aria-label={triggerLabel}
|
|
131
|
-
className={triggerClasses}
|
|
132
|
-
{...getReferenceProps()}
|
|
28
|
+
aria-label={label}
|
|
29
|
+
className="cn-button cn-button-appearance-ghost cn-info-box-trigger"
|
|
133
30
|
>
|
|
134
|
-
<
|
|
31
|
+
<LuInfo aria-hidden className="cn-info-box-icon" />
|
|
135
32
|
</button>
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
}}
|
|
149
|
-
className={contentClasses}
|
|
150
|
-
{...getFloatingProps()}
|
|
151
|
-
>
|
|
152
|
-
<FloatingArrow ref={arrowRef} context={context} className="fill-white" />
|
|
153
|
-
|
|
154
|
-
{title ? (
|
|
155
|
-
<h2 id={titleId} className="text-sm font-semibold text-gray-900 mb-2">
|
|
156
|
-
{title}
|
|
157
|
-
</h2>
|
|
158
|
-
) : null}
|
|
159
|
-
<div
|
|
160
|
-
className="text-sm text-gray-700 max-h-[min(24rem,calc(100vh-200px))]
|
|
161
|
-
overflow-y-auto"
|
|
162
|
-
>
|
|
163
|
-
{children}
|
|
164
|
-
</div>
|
|
165
|
-
</div>
|
|
166
|
-
</FloatingFocusManager>
|
|
167
|
-
</FloatingPortal>
|
|
168
|
-
) : null}
|
|
169
|
-
</div>
|
|
170
|
-
);
|
|
171
|
-
};
|
|
33
|
+
</PopoverTrigger>
|
|
34
|
+
|
|
35
|
+
<PopoverContent
|
|
36
|
+
side={side}
|
|
37
|
+
align={align}
|
|
38
|
+
sideOffset={sideOffset}
|
|
39
|
+
className={cn('max-w-xs', className)}
|
|
40
|
+
>
|
|
41
|
+
{children}
|
|
42
|
+
</PopoverContent>
|
|
43
|
+
</Popover>
|
|
44
|
+
);
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
@layer components {
|
|
2
|
+
/* MARK: Input
|
|
3
|
+
GDS text input: 40px fixed height, 5px padding, 2px border via cn-form-border.
|
|
4
|
+
Focus uses the GDS focused-form-input pattern: yellow outline + inset black shadow. */
|
|
5
|
+
.cn-input {
|
|
6
|
+
@apply cn-form-border w-full h-10 p-gds-1 text-base box-border appearance-none bg-panel
|
|
7
|
+
text-body;
|
|
8
|
+
|
|
9
|
+
&:focus {
|
|
10
|
+
@apply outline-focus;
|
|
11
|
+
box-shadow: inset 0 0 0 var(--border-width-form) var(--color-divider-input);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
&[aria-invalid='true'],
|
|
15
|
+
&:user-invalid {
|
|
16
|
+
@apply border-error;
|
|
17
|
+
|
|
18
|
+
&:focus {
|
|
19
|
+
@apply border-divider-input;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
&:disabled,
|
|
24
|
+
&[aria-disabled='true'] {
|
|
25
|
+
@apply opacity-50 cursor-not-allowed;
|
|
26
|
+
color: inherit;
|
|
27
|
+
-webkit-user-select: none;
|
|
28
|
+
user-select: none;
|
|
29
|
+
|
|
30
|
+
&::placeholder {
|
|
31
|
+
-webkit-user-select: none;
|
|
32
|
+
user-select: none;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/* Remove browser-native number spinners */
|
|
38
|
+
.cn-input[type='number'] {
|
|
39
|
+
-moz-appearance: textfield;
|
|
40
|
+
appearance: textfield;
|
|
41
|
+
|
|
42
|
+
&::-webkit-outer-spin-button,
|
|
43
|
+
&::-webkit-inner-spin-button {
|
|
44
|
+
-webkit-appearance: none;
|
|
45
|
+
margin: 0;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/* MARK: Sizes
|
|
50
|
+
em-based max-widths constrain the input to its expected content length.
|
|
51
|
+
Based on GDS character-width classes. */
|
|
52
|
+
.cn-input-size-date-part {
|
|
53
|
+
max-width: 2.75em;
|
|
54
|
+
}
|
|
55
|
+
.cn-input-size-year {
|
|
56
|
+
max-width: 4.5em;
|
|
57
|
+
}
|
|
58
|
+
.cn-input-size-postcode {
|
|
59
|
+
max-width: 5.5em;
|
|
60
|
+
}
|
|
61
|
+
.cn-input-size-short {
|
|
62
|
+
max-width: 11.5em;
|
|
63
|
+
}
|
|
64
|
+
.cn-input-size-medium {
|
|
65
|
+
max-width: 20.5em;
|
|
66
|
+
}
|
|
67
|
+
.cn-input-size-long {
|
|
68
|
+
max-width: 29.5em;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/* MARK: Appearances */
|
|
72
|
+
|
|
73
|
+
.cn-input-appearance-code {
|
|
74
|
+
font-variant-numeric: tabular-nums;
|
|
75
|
+
letter-spacing: 0.05em;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react-vite';
|
|
2
|
+
|
|
3
|
+
import { Input } from './Input';
|
|
4
|
+
import { ErrorText } from '../ErrorText/ErrorText';
|
|
5
|
+
import { FormGroup } from '../Form/FormGroup';
|
|
6
|
+
import { Label } from '../Label/Label';
|
|
7
|
+
|
|
8
|
+
const meta: Meta<typeof Input> = {
|
|
9
|
+
title: 'Components/Input',
|
|
10
|
+
component: Input,
|
|
11
|
+
tags: ['autodocs'],
|
|
12
|
+
parameters: {
|
|
13
|
+
docs: {
|
|
14
|
+
description: {
|
|
15
|
+
component:
|
|
16
|
+
'GDS-style text input. Use `size` to constrain the field to its expected content length. Compose with `InputGroup`, `InputPrefix`, `InputSuffix`, and `InputSwatch` for addon labels.',
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
argTypes: {
|
|
21
|
+
size: {
|
|
22
|
+
control: { type: 'select' },
|
|
23
|
+
options: ['base', 'date-part', 'year', 'postcode', 'short', 'medium', 'long'],
|
|
24
|
+
},
|
|
25
|
+
appearance: {
|
|
26
|
+
control: { type: 'radio' },
|
|
27
|
+
options: ['default', 'code'],
|
|
28
|
+
},
|
|
29
|
+
disabled: { control: 'boolean' },
|
|
30
|
+
placeholder: { control: 'text' },
|
|
31
|
+
},
|
|
32
|
+
args: {
|
|
33
|
+
size: 'base',
|
|
34
|
+
appearance: 'default',
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
export default meta;
|
|
39
|
+
|
|
40
|
+
type Story = StoryObj<typeof Input>;
|
|
41
|
+
|
|
42
|
+
export const Default: Story = {};
|
|
43
|
+
|
|
44
|
+
export const Sizes: Story = {
|
|
45
|
+
parameters: {
|
|
46
|
+
docs: {
|
|
47
|
+
description: {
|
|
48
|
+
story: 'Character-width constraints based on expected content length.',
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
render: () => (
|
|
53
|
+
<div className="flex flex-col gap-gds-3">
|
|
54
|
+
<div>
|
|
55
|
+
<Label htmlFor="size-date-part">date-part</Label>
|
|
56
|
+
|
|
57
|
+
<Input id="size-date-part" size="date-part" placeholder="DD" />
|
|
58
|
+
</div>
|
|
59
|
+
|
|
60
|
+
<div>
|
|
61
|
+
<Label htmlFor="size-year">year</Label>
|
|
62
|
+
|
|
63
|
+
<Input id="size-year" size="year" placeholder="YYYY" />
|
|
64
|
+
</div>
|
|
65
|
+
|
|
66
|
+
<div>
|
|
67
|
+
<Label htmlFor="size-postcode">postcode</Label>
|
|
68
|
+
|
|
69
|
+
<Input id="size-postcode" size="postcode" placeholder="SW1A 1AA" />
|
|
70
|
+
</div>
|
|
71
|
+
|
|
72
|
+
<div>
|
|
73
|
+
<Label htmlFor="size-short">short</Label>
|
|
74
|
+
|
|
75
|
+
<Input id="size-short" size="short" placeholder="07700 900000" />
|
|
76
|
+
</div>
|
|
77
|
+
|
|
78
|
+
<div>
|
|
79
|
+
<Label htmlFor="size-medium">medium</Label>
|
|
80
|
+
|
|
81
|
+
<Input id="size-medium" size="medium" />
|
|
82
|
+
</div>
|
|
83
|
+
|
|
84
|
+
<div>
|
|
85
|
+
<Label htmlFor="size-long">long</Label>
|
|
86
|
+
|
|
87
|
+
<Input id="size-long" size="long" />
|
|
88
|
+
</div>
|
|
89
|
+
</div>
|
|
90
|
+
),
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
export const Code: Story = {
|
|
94
|
+
parameters: {
|
|
95
|
+
docs: {
|
|
96
|
+
description: {
|
|
97
|
+
story:
|
|
98
|
+
'Tabular monospaced characters. Use for MFA codes, reference numbers, or any fixed-format string where character alignment matters.',
|
|
99
|
+
},
|
|
100
|
+
},
|
|
101
|
+
},
|
|
102
|
+
args: {
|
|
103
|
+
appearance: 'code',
|
|
104
|
+
size: 'short',
|
|
105
|
+
placeholder: 'ABCD 1234',
|
|
106
|
+
},
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
export const Invalid: Story = {
|
|
110
|
+
render: (args) => (
|
|
111
|
+
<FormGroup invalid>
|
|
112
|
+
<Label htmlFor="invalid-input">National Insurance number</Label>
|
|
113
|
+
|
|
114
|
+
<ErrorText id="ni-error">Enter a National Insurance number in the correct format</ErrorText>
|
|
115
|
+
|
|
116
|
+
<Input id="invalid-input" size="short" aria-invalid aria-describedby="ni-error" {...args} />
|
|
117
|
+
</FormGroup>
|
|
118
|
+
),
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
export const Disabled: Story = {
|
|
122
|
+
args: { disabled: true, value: 'Cannot be changed' },
|
|
123
|
+
};
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import type { ComponentProps } from 'react';
|
|
2
|
+
|
|
3
|
+
import { cn } from '../../utils/components';
|
|
4
|
+
|
|
5
|
+
const INPUT_APPEARANCES = {
|
|
6
|
+
default: 'cn-input-appearance-default',
|
|
7
|
+
code: 'cn-input-appearance-code',
|
|
8
|
+
} as const;
|
|
9
|
+
|
|
10
|
+
const INPUT_SIZES = {
|
|
11
|
+
base: 'cn-input-size-base',
|
|
12
|
+
'date-part': 'cn-input-size-date-part',
|
|
13
|
+
year: 'cn-input-size-year',
|
|
14
|
+
postcode: 'cn-input-size-postcode',
|
|
15
|
+
short: 'cn-input-size-short',
|
|
16
|
+
medium: 'cn-input-size-medium',
|
|
17
|
+
long: 'cn-input-size-long',
|
|
18
|
+
} as const;
|
|
19
|
+
|
|
20
|
+
export type InputSize = keyof typeof INPUT_SIZES;
|
|
21
|
+
export type InputAppearance = keyof typeof INPUT_APPEARANCES;
|
|
22
|
+
|
|
23
|
+
// React's own HTMLInputTypeAttribute ends in `| (string & {})`, an
|
|
24
|
+
// autocomplete-with-escape-hatch trick that also defeats Exclude<>, any
|
|
25
|
+
// string (including "number") is still assignable to it. Listed by hand
|
|
26
|
+
// instead, dropping "number" for real: GDS advises against it, it silently
|
|
27
|
+
// strips non-numeric characters instead of validating them, adds browser
|
|
28
|
+
// spinner UI GDS doesn't want, and behaves inconsistently across
|
|
29
|
+
// locales/screen readers. Use the default type="text" with
|
|
30
|
+
// inputMode="numeric" instead.
|
|
31
|
+
export type InputType =
|
|
32
|
+
| 'button'
|
|
33
|
+
| 'checkbox'
|
|
34
|
+
| 'color'
|
|
35
|
+
| 'date'
|
|
36
|
+
| 'datetime-local'
|
|
37
|
+
| 'email'
|
|
38
|
+
| 'file'
|
|
39
|
+
| 'hidden'
|
|
40
|
+
| 'image'
|
|
41
|
+
| 'month'
|
|
42
|
+
| 'password'
|
|
43
|
+
| 'radio'
|
|
44
|
+
| 'range'
|
|
45
|
+
| 'reset'
|
|
46
|
+
| 'search'
|
|
47
|
+
| 'submit'
|
|
48
|
+
| 'tel'
|
|
49
|
+
| 'text'
|
|
50
|
+
| 'time'
|
|
51
|
+
| 'url'
|
|
52
|
+
| 'week';
|
|
53
|
+
|
|
54
|
+
export type InputProps = Omit<ComponentProps<'input'>, 'size' | 'type'> & {
|
|
55
|
+
size?: InputSize;
|
|
56
|
+
appearance?: InputAppearance;
|
|
57
|
+
type?: InputType;
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
export const Input = ({
|
|
61
|
+
className,
|
|
62
|
+
size = 'base',
|
|
63
|
+
appearance = 'default',
|
|
64
|
+
type = 'text',
|
|
65
|
+
...props
|
|
66
|
+
}: InputProps) => (
|
|
67
|
+
<input
|
|
68
|
+
type={type}
|
|
69
|
+
data-slot="input"
|
|
70
|
+
className={cn('cn-input', INPUT_SIZES[size], INPUT_APPEARANCES[appearance], className)}
|
|
71
|
+
draggable="false"
|
|
72
|
+
{...props}
|
|
73
|
+
/>
|
|
74
|
+
);
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
@layer components {
|
|
2
|
+
/* MARK: Group
|
|
3
|
+
Pure flex wrapper. Stacks vertically on mobile, horizontal on sm+.
|
|
4
|
+
direction="vertical" forces flex-col at all breakpoints, used to stack a
|
|
5
|
+
toolbar or count message above/below an input or textarea. */
|
|
6
|
+
.cn-input-group {
|
|
7
|
+
@apply flex flex-col sm:flex-row w-full;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
.cn-input-group[data-direction='vertical'] {
|
|
11
|
+
@apply flex-col;
|
|
12
|
+
|
|
13
|
+
> * + * {
|
|
14
|
+
margin-top: var(--spacing-gds-1);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/* Toolbar border-bottom acts as the divider, no gap needed after it */
|
|
18
|
+
> .cn-input-toolbar + * {
|
|
19
|
+
margin-top: 0;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/* An icon-only Button addon (PasswordInput's show/hide toggle, SearchBox's
|
|
24
|
+
submit) is small enough to always fit next to the input, unlike a
|
|
25
|
+
toolbar or other arbitrary content, so a group containing one never
|
|
26
|
+
needs to drop it onto its own row on mobile. */
|
|
27
|
+
.cn-input-group:has(> .cn-input-prefix > .cn-button),
|
|
28
|
+
.cn-input-group:has(> .cn-input-suffix > .cn-button) {
|
|
29
|
+
@apply flex-row;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/* MARK: Toolbar
|
|
33
|
+
Sits above (or below) an input/textarea inside a vertical InputGroup.
|
|
34
|
+
Full cn-form-border except bottom, the adjacent field's top border
|
|
35
|
+
acts as the visual separator, creating one unified bordered region. */
|
|
36
|
+
.cn-input-toolbar {
|
|
37
|
+
@apply cn-form-border flex items-center gap-gds-1 px-gds-1 py-1 bg-wash justify-end;
|
|
38
|
+
border-bottom: none;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/* MARK: Prefix and Suffix
|
|
42
|
+
Pure positioning containers with no visual styling of their own.
|
|
43
|
+
Gap from the input is the default, swatch and select content remove it
|
|
44
|
+
via :has() and merge borders instead. items-center matters for content
|
|
45
|
+
that isn't already full-height and self-centering (InputSwatch and a
|
|
46
|
+
Select's control both are), e.g. a bare icon used as a decorative
|
|
47
|
+
addon, which would otherwise sit at the cross-start edge. self-start
|
|
48
|
+
stops this element itself stretching to fill cn-input-group's cross
|
|
49
|
+
axis, which is width once the group stacks to a column on mobile, that
|
|
50
|
+
stretch is otherwise invisible (this element has no background/border
|
|
51
|
+
of its own) but pushes a below-input row of content wide regardless of
|
|
52
|
+
what it actually contains. */
|
|
53
|
+
.cn-input-prefix,
|
|
54
|
+
.cn-input-suffix {
|
|
55
|
+
@apply flex flex-none items-center self-start;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.cn-input-suffix {
|
|
59
|
+
@apply mt-gds-1 sm:mt-0 sm:ml-gds-1;
|
|
60
|
+
}
|
|
61
|
+
.cn-input-prefix {
|
|
62
|
+
@apply mb-gds-1 sm:mb-0 sm:mr-gds-1;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/* Connected: swatch or select removes gap and merges borders. */
|
|
66
|
+
.cn-input-suffix:has(.cn-input-swatch),
|
|
67
|
+
.cn-input-suffix:has(.cn-select-container) {
|
|
68
|
+
@apply mt-0 ml-0;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
.cn-input-prefix:has(.cn-input-swatch),
|
|
72
|
+
.cn-input-prefix:has(.cn-select-container) {
|
|
73
|
+
@apply mb-0 mr-0;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/* A Button addon keeps the group in a row at every size (see above), so
|
|
77
|
+
its own margin needs to be the row gap unconditionally too, rather than
|
|
78
|
+
mt-gds-1's mobile stacking gap (which would otherwise both add an
|
|
79
|
+
unwanted top offset and leave no horizontal gap from the input, below
|
|
80
|
+
sm where sm:ml-gds-1 isn't active yet). */
|
|
81
|
+
.cn-input-suffix:has(> .cn-button) {
|
|
82
|
+
@apply mt-0 ml-gds-1;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
.cn-input-prefix:has(> .cn-button) {
|
|
86
|
+
@apply mb-0 mr-gds-1;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/* Select: auto width since select defaults to w-full. */
|
|
90
|
+
.cn-input-prefix > .cn-select-container,
|
|
91
|
+
.cn-input-suffix > .cn-select-container {
|
|
92
|
+
@apply w-auto;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
.cn-input-prefix > .cn-select-container .cn-select-control {
|
|
96
|
+
@apply border-b-0 sm:border-b-form sm:border-r-0;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
.cn-input-suffix > .cn-select-container .cn-select-control {
|
|
100
|
+
@apply border-t-0 sm:border-t-form sm:border-l-0;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/* MARK: Swatch
|
|
104
|
+
Decorative GDS-style addon (currency symbol, unit label).
|
|
105
|
+
Always aria-hidden, use a Button or Select for interactive addons. */
|
|
106
|
+
.cn-input-swatch {
|
|
107
|
+
@apply cn-form-swatch flex-none justify-center min-w-10 p-gds-1 text-body-secondary
|
|
108
|
+
whitespace-nowrap cursor-default;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/* An icon inside a swatch fills its padded box the same way cn-button's
|
|
112
|
+
icon variant does (see Button.css's cn-button-variant-icon), rather than
|
|
113
|
+
an arbitrary fixed size, so an icon swatch (e.g. Geocoder's search icon)
|
|
114
|
+
reads at the same proportions as an icon button instead of looking
|
|
115
|
+
smaller/inconsistent next to one. */
|
|
116
|
+
.cn-input-swatch svg {
|
|
117
|
+
@apply w-full h-full;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
.cn-input-prefix > .cn-input-swatch {
|
|
121
|
+
@apply border-b-0 sm:border-b-form sm:border-r-0;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
.cn-input-suffix > .cn-input-swatch {
|
|
125
|
+
@apply border-t-0 sm:border-t-form sm:border-l-0;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/* MARK: Button
|
|
129
|
+
A Button (e.g. PasswordInput's show/hide toggle, SearchBox's submit)
|
|
130
|
+
manages its own vertical footprint via height + box-shadow compensation
|
|
131
|
+
(see Button.css's --cn-button-shadow-size comments), sized specifically
|
|
132
|
+
assuming flex-start alignment: items-center above would otherwise leave
|
|
133
|
+
it sitting a pixel or two lower than the adjacent input, the shadow
|
|
134
|
+
compensating for the wrong gap. width: auto is the same safeguard
|
|
135
|
+
against stretch-to-fill as the Select rule above. */
|
|
136
|
+
.cn-input-prefix > .cn-button,
|
|
137
|
+
.cn-input-suffix > .cn-button {
|
|
138
|
+
@apply w-auto self-start;
|
|
139
|
+
}
|
|
140
|
+
}
|