@boostdev/design-system-components 1.0.3 → 1.1.1
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/AGENTS.md +51 -10
- package/dist/client.cjs +350 -174
- package/dist/client.css +751 -647
- package/dist/client.d.cts +62 -97
- package/dist/client.d.ts +62 -97
- package/dist/client.js +377 -211
- package/dist/index.cjs +350 -174
- package/dist/index.css +751 -647
- package/dist/index.d.cts +62 -97
- package/dist/index.d.ts +62 -97
- package/dist/index.js +377 -211
- package/dist/native/index.cjs +991 -0
- package/dist/native/index.d.cts +208 -0
- package/dist/native/index.d.ts +208 -0
- package/dist/native/index.js +968 -0
- package/dist/web-components.d.ts +304 -0
- package/dist/web-components.js +1978 -0
- package/package.json +27 -5
- package/src/components/interaction/Button/Button.module.css +11 -8
- package/src/components/interaction/Button/Button.native.mdx +72 -0
- package/src/components/interaction/Button/Button.native.spec.tsx +35 -0
- package/src/components/interaction/Button/Button.native.stories.tsx +42 -0
- package/src/components/interaction/Button/Button.native.tsx +95 -0
- package/src/components/interaction/Button/Button.stories.tsx +1 -1
- package/src/components/interaction/Button/Button.tsx +2 -2
- package/src/components/interaction/Command/Command.mdx +16 -0
- package/src/components/interaction/Command/Command.module.css +7 -7
- package/src/components/interaction/Command/Command.spec.tsx +37 -0
- package/src/components/interaction/Command/Command.stories.tsx +1 -1
- package/src/components/interaction/Command/Command.tsx +39 -4
- package/src/components/interaction/Dialog/Dialog.module.css +10 -13
- package/src/components/interaction/Dialog/Dialog.spec.tsx +53 -1
- package/src/components/interaction/Dialog/Dialog.stories.tsx +18 -1
- package/src/components/interaction/Dialog/Dialog.tsx +52 -18
- package/src/components/interaction/Drawer/Drawer.mdx +14 -0
- package/src/components/interaction/Drawer/Drawer.module.css +11 -11
- package/src/components/interaction/Drawer/Drawer.spec.tsx +48 -1
- package/src/components/interaction/Drawer/Drawer.stories.tsx +1 -1
- package/src/components/interaction/Drawer/Drawer.tsx +40 -6
- package/src/components/interaction/DropdownMenu/DropdownMenu.module.css +6 -6
- package/src/components/interaction/DropdownMenu/DropdownMenu.stories.tsx +1 -1
- package/src/components/interaction/DropdownMenu/DropdownMenu.tsx +2 -2
- package/src/components/interaction/Popover/Popover.mdx +17 -0
- package/src/components/interaction/Popover/Popover.module.css +132 -16
- package/src/components/interaction/Popover/Popover.spec.tsx +119 -20
- package/src/components/interaction/Popover/Popover.stories.tsx +1 -1
- package/src/components/interaction/Popover/Popover.tsx +69 -29
- package/src/components/interaction/Rating/Rating.stories.tsx +1 -1
- package/src/components/interaction/Rating/Rating.tsx +2 -2
- package/src/components/interaction/Toast/Toast.module.css +13 -8
- package/src/components/interaction/Toast/Toast.spec.tsx +21 -0
- package/src/components/interaction/Toast/Toast.stories.tsx +1 -1
- package/src/components/interaction/Toast/Toast.tsx +22 -2
- package/src/components/interaction/form/Checkbox/Checkbox.mdx +2 -2
- package/src/components/interaction/form/Checkbox/Checkbox.module.css +9 -9
- package/src/components/interaction/form/Checkbox/Checkbox.native.mdx +74 -0
- package/src/components/interaction/form/Checkbox/Checkbox.native.spec.tsx +42 -0
- package/src/components/interaction/form/Checkbox/Checkbox.native.stories.tsx +36 -0
- package/src/components/interaction/form/Checkbox/Checkbox.native.tsx +80 -0
- package/src/components/interaction/form/Checkbox/Checkbox.stories.tsx +1 -1
- package/src/components/interaction/form/Checkbox/Checkbox.tsx +2 -2
- package/src/components/interaction/form/CheckboxGroup/CheckboxGroup.mdx +44 -0
- package/src/components/interaction/form/CheckboxGroup/CheckboxGroup.stories.tsx +1 -1
- package/src/components/interaction/form/CheckboxGroup/CheckboxGroup.tsx +2 -2
- package/src/components/interaction/form/Combobox/Combobox.mdx +21 -0
- package/src/components/interaction/form/Combobox/Combobox.module.css +8 -9
- package/src/components/interaction/form/Combobox/Combobox.stories.tsx +1 -1
- package/src/components/interaction/form/Combobox/Combobox.tsx +2 -2
- package/src/components/interaction/form/FileInput/FileInput.mdx +14 -0
- package/src/components/interaction/form/FileInput/FileInput.module.css +5 -5
- package/src/components/interaction/form/FileInput/FileInput.stories.tsx +1 -1
- package/src/components/interaction/form/FileInput/FileInput.tsx +2 -2
- package/src/components/interaction/form/FormInput/FormInput.stories.tsx +1 -1
- package/src/components/interaction/form/FormInput/FormInput.tsx +2 -2
- package/src/components/interaction/form/NumberInput/NumberInput.mdx +16 -0
- package/src/components/interaction/form/NumberInput/NumberInput.module.css +1 -1
- package/src/components/interaction/form/NumberInput/NumberInput.stories.tsx +1 -1
- package/src/components/interaction/form/NumberInput/NumberInput.tsx +2 -2
- package/src/components/interaction/form/Radio/Radio.mdx +3 -3
- package/src/components/interaction/form/Radio/Radio.module.css +9 -9
- package/src/components/interaction/form/Radio/Radio.native.stories.tsx +46 -0
- package/src/components/interaction/form/Radio/Radio.native.tsx +79 -0
- package/src/components/interaction/form/Radio/Radio.stories.tsx +1 -1
- package/src/components/interaction/form/Radio/Radio.tsx +2 -2
- package/src/components/interaction/form/RadioGroup/RadioGroup.mdx +45 -0
- package/src/components/interaction/form/RadioGroup/RadioGroup.stories.tsx +1 -1
- package/src/components/interaction/form/RadioGroup/RadioGroup.tsx +2 -2
- package/src/components/interaction/form/SegmentedControl/SegmentedControl.module.css +5 -6
- package/src/components/interaction/form/SegmentedControl/SegmentedControl.stories.tsx +1 -1
- package/src/components/interaction/form/SegmentedControl/SegmentedControl.tsx +2 -2
- package/src/components/interaction/form/Select/Select.module.css +3 -3
- package/src/components/interaction/form/Select/Select.stories.tsx +1 -1
- package/src/components/interaction/form/Select/Select.tsx +2 -2
- package/src/components/interaction/form/Slider/Slider.mdx +1 -1
- package/src/components/interaction/form/Slider/Slider.module.css +10 -10
- package/src/components/interaction/form/Slider/Slider.stories.tsx +1 -1
- package/src/components/interaction/form/Slider/Slider.tsx +2 -2
- package/src/components/interaction/form/Switch/Switch.mdx +4 -4
- package/src/components/interaction/form/Switch/Switch.module.css +11 -11
- package/src/components/interaction/form/Switch/Switch.native.spec.tsx +60 -0
- package/src/components/interaction/form/Switch/Switch.native.stories.tsx +35 -0
- package/src/components/interaction/form/Switch/Switch.native.tsx +59 -0
- package/src/components/interaction/form/Switch/Switch.stories.tsx +1 -1
- package/src/components/interaction/form/Switch/Switch.tsx +2 -2
- package/src/components/interaction/form/Textarea/Textarea.mdx +17 -0
- package/src/components/interaction/form/Textarea/Textarea.module.css +1 -1
- package/src/components/interaction/form/Textarea/Textarea.stories.tsx +1 -1
- package/src/components/interaction/form/Textarea/Textarea.tsx +2 -2
- package/src/components/interaction/form/atoms/InputContainer.tsx +2 -1
- package/src/components/interaction/form/atoms/Label.native.stories.tsx +18 -0
- package/src/components/interaction/form/atoms/Label.native.tsx +29 -0
- package/src/components/interaction/form/atoms/Label.tsx +5 -3
- package/src/components/interaction/form/atoms/Message.native.spec.tsx +30 -0
- package/src/components/interaction/form/atoms/Message.native.stories.tsx +22 -0
- package/src/components/interaction/form/atoms/Message.native.tsx +34 -0
- package/src/components/interaction/form/atoms/Message.tsx +5 -3
- package/src/components/layout/ButtonGroup/ButtonGroup.native.stories.tsx +50 -0
- package/src/components/layout/ButtonGroup/ButtonGroup.native.tsx +34 -0
- package/src/components/layout/ButtonGroup/ButtonGroup.stories.tsx +1 -1
- package/src/components/layout/ButtonGroup/ButtonGroup.tsx +2 -2
- package/src/components/layout/Card/Card.native.stories.tsx +53 -0
- package/src/components/layout/Card/Card.native.tsx +89 -0
- package/src/components/layout/Card/Card.stories.tsx +1 -1
- package/src/components/layout/Card/Card.tsx +2 -2
- package/src/components/layout/IconWrapper/IconWrapper.mdx +2 -2
- package/src/components/layout/IconWrapper/IconWrapper.module.css +2 -2
- package/src/components/layout/IconWrapper/IconWrapper.native.spec.tsx +39 -0
- package/src/components/layout/IconWrapper/IconWrapper.native.stories.tsx +41 -0
- package/src/components/layout/IconWrapper/IconWrapper.native.tsx +20 -0
- package/src/components/layout/IconWrapper/IconWrapper.stories.tsx +1 -1
- package/src/components/layout/IconWrapper/IconWrapper.tsx +2 -2
- package/src/components/layout/SectionHeader/SectionHeader.mdx +13 -0
- package/src/components/layout/SectionHeader/SectionHeader.native.stories.tsx +38 -0
- package/src/components/layout/SectionHeader/SectionHeader.native.tsx +79 -0
- package/src/components/layout/SectionHeader/SectionHeader.stories.tsx +1 -1
- package/src/components/layout/SectionHeader/SectionHeader.tsx +2 -2
- package/src/components/ui/Accordion/Accordion.mdx +14 -0
- package/src/components/ui/Accordion/Accordion.module.css +5 -5
- package/src/components/ui/Accordion/Accordion.stories.tsx +1 -1
- package/src/components/ui/Accordion/Accordion.tsx +2 -2
- package/src/components/ui/Alert/Alert.native.mdx +62 -0
- package/src/components/ui/Alert/Alert.native.stories.tsx +43 -0
- package/src/components/ui/Alert/Alert.native.tsx +94 -0
- package/src/components/ui/Alert/Alert.stories.tsx +1 -1
- package/src/components/ui/Alert/Alert.tsx +2 -2
- package/src/components/ui/Avatar/Avatar.native.mdx +50 -0
- package/src/components/ui/Avatar/Avatar.native.spec.tsx +47 -0
- package/src/components/ui/Avatar/Avatar.native.stories.tsx +34 -0
- package/src/components/ui/Avatar/Avatar.native.tsx +85 -0
- package/src/components/ui/Avatar/Avatar.stories.tsx +1 -1
- package/src/components/ui/Avatar/Avatar.tsx +2 -2
- package/src/components/ui/Badge/Badge.mdx +2 -2
- package/src/components/ui/Badge/Badge.native.mdx +54 -0
- package/src/components/ui/Badge/Badge.native.stories.tsx +36 -0
- package/src/components/ui/Badge/Badge.native.tsx +50 -0
- package/src/components/ui/Badge/Badge.stories.tsx +1 -1
- package/src/components/ui/Badge/Badge.tsx +2 -2
- package/src/components/ui/Breadcrumb/Breadcrumb.stories.tsx +1 -1
- package/src/components/ui/Breadcrumb/Breadcrumb.tsx +2 -2
- package/src/components/ui/Calendar/Calendar.mdx +16 -0
- package/src/components/ui/Calendar/Calendar.module.css +7 -7
- package/src/components/ui/Calendar/Calendar.stories.tsx +1 -1
- package/src/components/ui/Calendar/Calendar.tsx +2 -2
- package/src/components/ui/Carousel/Carousel.module.css +5 -5
- package/src/components/ui/Carousel/Carousel.stories.tsx +1 -1
- package/src/components/ui/Carousel/Carousel.tsx +2 -2
- package/src/components/ui/Collapsible/Collapsible.module.css +4 -4
- package/src/components/ui/Collapsible/Collapsible.stories.tsx +1 -1
- package/src/components/ui/Collapsible/Collapsible.tsx +2 -2
- package/src/components/ui/DescriptionList/DescriptionList.stories.tsx +1 -1
- package/src/components/ui/DescriptionList/DescriptionList.tsx +2 -2
- package/src/components/ui/Link/Link.mdx +14 -0
- package/src/components/ui/Link/Link.module.css +2 -2
- package/src/components/ui/Link/Link.stories.tsx +1 -1
- package/src/components/ui/Link/Link.tsx +2 -2
- package/src/components/ui/Loading/Loading.module.css +7 -7
- package/src/components/ui/Loading/Loading.native.spec.tsx +24 -0
- package/src/components/ui/Loading/Loading.native.stories.tsx +33 -0
- package/src/components/ui/Loading/Loading.native.tsx +29 -0
- package/src/components/ui/Loading/Loading.stories.tsx +1 -1
- package/src/components/ui/Loading/Loading.tsx +2 -2
- package/src/components/ui/NotificationBanner/NotificationBanner.module.css +3 -3
- package/src/components/ui/NotificationBanner/NotificationBanner.native.stories.tsx +39 -0
- package/src/components/ui/NotificationBanner/NotificationBanner.native.tsx +76 -0
- package/src/components/ui/NotificationBanner/NotificationBanner.stories.tsx +1 -1
- package/src/components/ui/NotificationBanner/NotificationBanner.tsx +2 -2
- package/src/components/ui/Pagination/Pagination.module.css +7 -7
- package/src/components/ui/Pagination/Pagination.stories.tsx +1 -1
- package/src/components/ui/Pagination/Pagination.tsx +2 -2
- package/src/components/ui/Progress/Progress.mdx +1 -1
- package/src/components/ui/Progress/Progress.module.css +6 -6
- package/src/components/ui/Progress/Progress.native.stories.tsx +34 -0
- package/src/components/ui/Progress/Progress.native.tsx +84 -0
- package/src/components/ui/Progress/Progress.stories.tsx +1 -1
- package/src/components/ui/Progress/Progress.tsx +2 -2
- package/src/components/ui/ProgressCircle/ProgressCircle.module.css +1 -1
- package/src/components/ui/ProgressCircle/ProgressCircle.stories.tsx +1 -1
- package/src/components/ui/ProgressCircle/ProgressCircle.tsx +2 -2
- package/src/components/ui/Separator/Separator.mdx +14 -0
- package/src/components/ui/Separator/Separator.module.css +3 -3
- package/src/components/ui/Separator/Separator.native.stories.tsx +42 -0
- package/src/components/ui/Separator/Separator.native.tsx +32 -0
- package/src/components/ui/Separator/Separator.stories.tsx +1 -1
- package/src/components/ui/Separator/Separator.tsx +2 -2
- package/src/components/ui/Skeleton/Skeleton.module.css +1 -1
- package/src/components/ui/Skeleton/Skeleton.native.stories.tsx +33 -0
- package/src/components/ui/Skeleton/Skeleton.native.tsx +41 -0
- package/src/components/ui/Skeleton/Skeleton.stories.tsx +1 -1
- package/src/components/ui/Skeleton/Skeleton.tsx +2 -3
- package/src/components/ui/SkipLink/SkipLink.stories.tsx +1 -1
- package/src/components/ui/SkipLink/SkipLink.tsx +5 -3
- package/src/components/ui/Table/Table.mdx +14 -0
- package/src/components/ui/Table/Table.module.css +9 -9
- package/src/components/ui/Table/Table.stories.tsx +1 -1
- package/src/components/ui/Table/Table.tsx +2 -2
- package/src/components/ui/Tabs/Tabs.module.css +3 -3
- package/src/components/ui/Tabs/Tabs.stories.tsx +1 -1
- package/src/components/ui/Tabs/Tabs.tsx +2 -2
- package/src/components/ui/Tooltip/Tooltip.mdx +14 -0
- package/src/components/ui/Tooltip/Tooltip.module.css +8 -8
- package/src/components/ui/Tooltip/Tooltip.stories.tsx +1 -1
- package/src/components/ui/Tooltip/Tooltip.tsx +2 -2
- package/src/components/ui/Typography/Typography.mdx +13 -0
- package/src/components/ui/Typography/Typography.native.mdx +56 -0
- package/src/components/ui/Typography/Typography.native.stories.tsx +38 -0
- package/src/components/ui/Typography/Typography.native.tsx +65 -0
- package/src/components/ui/Typography/Typography.stories.tsx +1 -1
- package/src/components/ui/Typography/Typography.tsx +2 -2
- package/src/css/bdc.css +8 -0
- package/src/index.ts +1 -0
- package/src/native/ThemeContext.tsx +28 -0
- package/src/native/tokens.ts +13 -0
- package/src/native.ts +39 -0
- package/src/polyfill-invoker-commands.ts +68 -0
- package/src/react-augment.d.ts +32 -0
- package/src/stories/DesignSystem/DarkMode.mdx +130 -0
- package/src/stories/ReactNative.mdx +121 -0
- package/src/types.ts +2 -0
- package/src/typings.d.ts +3 -0
- package/src/web-components/globals.ts +61 -0
- package/src/web-components/index.ts +12 -0
- package/src/web-components/interaction/BdsButton.mdx +106 -0
- package/src/web-components/interaction/BdsButton.stories.tsx +60 -0
- package/src/web-components/interaction/BdsPopover.mdx +120 -0
- package/src/web-components/interaction/BdsPopover.stories.tsx +70 -0
- package/src/web-components/interaction/BdsToastProvider.mdx +94 -0
- package/src/web-components/interaction/BdsToastProvider.stories.tsx +73 -0
- package/src/web-components/interaction/bds-button.spec.ts +95 -0
- package/src/web-components/interaction/bds-button.ts +293 -0
- package/src/web-components/interaction/bds-popover.spec.ts +174 -0
- package/src/web-components/interaction/bds-popover.ts +229 -0
- package/src/web-components/interaction/bds-toast-provider.spec.ts +122 -0
- package/src/web-components/interaction/bds-toast-provider.ts +211 -0
- package/src/web-components/test/helpers.ts +22 -0
- package/src/web-components/ui/BdsAlert.mdx +90 -0
- package/src/web-components/ui/BdsAlert.stories.tsx +60 -0
- package/src/web-components/ui/BdsBadge.mdx +74 -0
- package/src/web-components/ui/BdsBadge.stories.tsx +37 -0
- package/src/web-components/ui/bds-alert.spec.ts +109 -0
- package/src/web-components/ui/bds-alert.ts +209 -0
- package/src/web-components/ui/bds-badge.spec.ts +51 -0
- package/src/web-components/ui/bds-badge.ts +88 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useState, useEffect, createContext, useContext, ReactNode, useCallback, useMemo } from 'react';
|
|
1
|
+
import { useState, useEffect, createContext, useContext, ReactNode, useCallback, useMemo, useRef } from 'react';
|
|
2
2
|
import css from './Toast.module.css';
|
|
3
3
|
import { cn } from '@boostdev/design-system-foundation';
|
|
4
4
|
|
|
@@ -18,6 +18,7 @@ const ToastContext = createContext<ToastContextType | undefined>(undefined);
|
|
|
18
18
|
|
|
19
19
|
export function ToastProvider({ children }: { children: ReactNode }) {
|
|
20
20
|
const [toasts, setToasts] = useState<Toast[]>([]);
|
|
21
|
+
const containerRef = useRef<HTMLDivElement>(null);
|
|
21
22
|
|
|
22
23
|
const showToast = useCallback((message: string, variant: ToastVariant) => {
|
|
23
24
|
const id = Math.random().toString(36).substring(2, 9);
|
|
@@ -28,12 +29,31 @@ export function ToastProvider({ children }: { children: ReactNode }) {
|
|
|
28
29
|
setToasts(prev => prev.filter(toast => toast.id !== id));
|
|
29
30
|
}, []);
|
|
30
31
|
|
|
32
|
+
// Sync the popover's top-layer visibility with the toast queue.
|
|
33
|
+
// showPopover() is a no-op when already open (safe to call multiple times).
|
|
34
|
+
// hidePopover() throws InvalidStateError when already hidden, so catch silently.
|
|
35
|
+
useEffect(() => {
|
|
36
|
+
const container = containerRef.current;
|
|
37
|
+
if (!container) return;
|
|
38
|
+
if (toasts.length > 0) {
|
|
39
|
+
container.showPopover?.();
|
|
40
|
+
} else {
|
|
41
|
+
try { container.hidePopover?.(); } catch { /* already hidden on initial mount */ }
|
|
42
|
+
}
|
|
43
|
+
}, [toasts.length]);
|
|
44
|
+
|
|
31
45
|
const value = useMemo(() => ({ showToast }), [showToast]);
|
|
32
46
|
|
|
33
47
|
return (
|
|
34
48
|
<ToastContext.Provider value={value}>
|
|
35
49
|
{children}
|
|
36
|
-
<div
|
|
50
|
+
<div
|
|
51
|
+
ref={containerRef}
|
|
52
|
+
popover="manual"
|
|
53
|
+
role="region"
|
|
54
|
+
aria-label="Notifications"
|
|
55
|
+
className={css.toastContainer}
|
|
56
|
+
>
|
|
37
57
|
{toasts.map(toast => (
|
|
38
58
|
<ToastItem
|
|
39
59
|
key={toast.id}
|
|
@@ -44,8 +44,8 @@ Binary toggle for opt-in/opt-out choices. Renders a styled native `<input type="
|
|
|
44
44
|
<tr><th>Variable</th><th>Default</th><th>Description</th></tr>
|
|
45
45
|
</thead>
|
|
46
46
|
<tbody>
|
|
47
|
-
<tr><td>`--checkbox_color-active`</td><td>`var(--
|
|
48
|
-
<tr><td>`--checkbox_color-on-active`</td><td>`var(--
|
|
47
|
+
<tr><td>`--checkbox_color-active`</td><td>`var(--bdc-color_active)`</td><td>Checked background</td></tr>
|
|
48
|
+
<tr><td>`--checkbox_color-on-active`</td><td>`var(--bdc-color_on-active)`</td><td>Checkmark colour</td></tr>
|
|
49
49
|
</tbody>
|
|
50
50
|
</table>
|
|
51
51
|
|
|
@@ -14,8 +14,8 @@
|
|
|
14
14
|
|
|
15
15
|
.checkbox {
|
|
16
16
|
margin-block-start: 0.25em;
|
|
17
|
-
|
|
18
|
-
|
|
17
|
+
inline-size: var(--inputSize);
|
|
18
|
+
block-size: var(--inputSize);
|
|
19
19
|
color: var(--checkbox_color, var(--bds-color_on-bg));
|
|
20
20
|
border: var(--checkbox_border, none);
|
|
21
21
|
--bdc_color: currentcolor;
|
|
@@ -33,18 +33,18 @@
|
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
.checkbox:checked {
|
|
36
|
-
background-color: var(--checkbox_color-active, var(--
|
|
37
|
-
--bdc_color: var(--checkbox_color-active, var(--
|
|
36
|
+
background-color: var(--checkbox_color-active, var(--bdc-color_active));
|
|
37
|
+
--bdc_color: var(--checkbox_color-active, var(--bdc-color_active));
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
.checkbox:checked::after {
|
|
41
41
|
content: '';
|
|
42
42
|
position: absolute;
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
border: solid var(--checkbox_color-on-active, var(--
|
|
43
|
+
inset-inline-start: 0.6em;
|
|
44
|
+
inset-block-start: 0.2em;
|
|
45
|
+
inline-size: 0.5em;
|
|
46
|
+
block-size: 1em;
|
|
47
|
+
border: solid var(--checkbox_color-on-active, var(--bdc-color_on-active));
|
|
48
48
|
border-width: 0 2px 2px 0;
|
|
49
49
|
transform: rotate(45deg);
|
|
50
50
|
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { Meta, Canvas, ArgTypes } from '@storybook/blocks';
|
|
2
|
+
import * as Stories from './Checkbox.native.stories';
|
|
3
|
+
|
|
4
|
+
<Meta of={Stories} />
|
|
5
|
+
|
|
6
|
+
# Checkbox (React Native)
|
|
7
|
+
|
|
8
|
+
React Native checkbox component with label, optional hint, and error state. Fully controlled — manage checked state via `checked` + `onChange`.
|
|
9
|
+
|
|
10
|
+
> **Status: alpha** — API may change before stable release.
|
|
11
|
+
|
|
12
|
+
## Usage
|
|
13
|
+
|
|
14
|
+
```tsx
|
|
15
|
+
import { Checkbox } from '@boostdev/components';
|
|
16
|
+
import { useState } from 'react';
|
|
17
|
+
|
|
18
|
+
function Example() {
|
|
19
|
+
const [checked, setChecked] = useState(false);
|
|
20
|
+
return (
|
|
21
|
+
<Checkbox
|
|
22
|
+
name="terms"
|
|
23
|
+
label="Accept terms and conditions"
|
|
24
|
+
checked={checked}
|
|
25
|
+
onChange={setChecked}
|
|
26
|
+
/>
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Examples
|
|
32
|
+
|
|
33
|
+
### Interactive
|
|
34
|
+
<Canvas of={Stories.Interactive} />
|
|
35
|
+
|
|
36
|
+
### Unchecked
|
|
37
|
+
<Canvas of={Stories.Unchecked} />
|
|
38
|
+
|
|
39
|
+
### Checked
|
|
40
|
+
<Canvas of={Stories.Checked} />
|
|
41
|
+
|
|
42
|
+
### With hint
|
|
43
|
+
<Canvas of={Stories.WithHint} />
|
|
44
|
+
|
|
45
|
+
### With error
|
|
46
|
+
<Canvas of={Stories.WithError} />
|
|
47
|
+
|
|
48
|
+
### Disabled
|
|
49
|
+
<Canvas of={Stories.Disabled} />
|
|
50
|
+
|
|
51
|
+
### Disabled + checked
|
|
52
|
+
<Canvas of={Stories.DisabledChecked} />
|
|
53
|
+
|
|
54
|
+
## Props
|
|
55
|
+
|
|
56
|
+
<ArgTypes of={Stories} />
|
|
57
|
+
|
|
58
|
+
## Props reference
|
|
59
|
+
|
|
60
|
+
| Prop | Type | Default | Description |
|
|
61
|
+
|------|------|---------|-------------|
|
|
62
|
+
| `name` | string | — | Field name (used for accessibility grouping) |
|
|
63
|
+
| `label` | string | — | Visible label text |
|
|
64
|
+
| `checked` | boolean | `false` | Controlled checked state |
|
|
65
|
+
| `onChange` | `(checked: boolean) => void` | — | Called with the new value on press |
|
|
66
|
+
| `disabled` | boolean | `false` | Prevents interaction, reduces opacity |
|
|
67
|
+
| `hint` | string | — | Helper text below the label |
|
|
68
|
+
| `error` | string | — | Error message; shown instead of hint when set |
|
|
69
|
+
|
|
70
|
+
## Accessibility
|
|
71
|
+
|
|
72
|
+
- The label, hint, and error are announced together by screen readers
|
|
73
|
+
- `disabled` communicates the disabled state via `accessibilityState`
|
|
74
|
+
- Group related checkboxes using a wrapping `View` with `accessibilityRole="radiogroup"` or a labelled `fieldset` equivalent
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { render, screen } from '@testing-library/react';
|
|
2
|
+
import { ThemeProvider } from '../../../../native/ThemeContext';
|
|
3
|
+
import { Checkbox } from './Checkbox.native';
|
|
4
|
+
|
|
5
|
+
function renderWithTheme(ui: React.ReactElement) {
|
|
6
|
+
return render(<ThemeProvider>{ui}</ThemeProvider>);
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
describe('Checkbox (native)', () => {
|
|
10
|
+
it('has checkbox role with label', () => {
|
|
11
|
+
renderWithTheme(<Checkbox label="Accept terms" name="terms" />);
|
|
12
|
+
expect(screen.getByRole('checkbox', { name: 'Accept terms' })).toBeInTheDocument();
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
it('shows the checkmark when checked', () => {
|
|
16
|
+
renderWithTheme(<Checkbox label="Accept terms" name="terms" checked={true} />);
|
|
17
|
+
expect(screen.getByText('✓')).toBeInTheDocument();
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it('hides the checkmark when unchecked', () => {
|
|
21
|
+
renderWithTheme(<Checkbox label="Accept terms" name="terms" checked={false} />);
|
|
22
|
+
expect(screen.queryByText('✓')).not.toBeInTheDocument();
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it('checkmark uses theme color (contrast regression: was hardcoded #fff)', () => {
|
|
26
|
+
// Previously the checkmark had color: '#fff' hardcoded in the StyleSheet.
|
|
27
|
+
// Now it uses colors.colorOnInteractive from the theme, which is #000 in dark
|
|
28
|
+
// mode — fixing the 2.52:1 contrast failure on the dark interactive blue.
|
|
29
|
+
renderWithTheme(<Checkbox label="Accept terms" name="terms" checked={true} />);
|
|
30
|
+
const checkmark = screen.getByText('✓');
|
|
31
|
+
// The color must be applied as an inline style (overrides StyleSheet), not absent.
|
|
32
|
+
// In light mode colorOnInteractive=#fff; in dark mode it is #000.
|
|
33
|
+
expect(checkmark.style.color).toBeTruthy();
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it('renders with error message', () => {
|
|
37
|
+
renderWithTheme(
|
|
38
|
+
<Checkbox label="Accept terms" name="terms" error="You must accept." />,
|
|
39
|
+
);
|
|
40
|
+
expect(screen.getByRole('alert')).toHaveTextContent('You must accept.');
|
|
41
|
+
});
|
|
42
|
+
});
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import React, { useState } from 'react';
|
|
2
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
3
|
+
import { ThemeProvider } from '../../../../native/ThemeContext';
|
|
4
|
+
import { Checkbox } from './Checkbox.native';
|
|
5
|
+
|
|
6
|
+
const meta = {
|
|
7
|
+
tags: ['!stable', 'alpha'],
|
|
8
|
+
title: 'React Native/Form/Checkbox',
|
|
9
|
+
component: Checkbox,
|
|
10
|
+
decorators: [(Story) => <ThemeProvider><Story /></ThemeProvider>],
|
|
11
|
+
parameters: { layout: 'padded' },
|
|
12
|
+
} satisfies Meta<typeof Checkbox>;
|
|
13
|
+
|
|
14
|
+
export default meta;
|
|
15
|
+
type Story = StoryObj<typeof meta>;
|
|
16
|
+
|
|
17
|
+
export const Unchecked: Story = { args: { label: 'Accept terms', name: 'terms', checked: false } };
|
|
18
|
+
export const Checked: Story = { args: { label: 'Accept terms', name: 'terms', checked: true } };
|
|
19
|
+
export const Disabled: Story = { args: { label: 'Accept terms', name: 'terms', disabled: true } };
|
|
20
|
+
export const DisabledChecked: Story = { args: { label: 'Accept terms', name: 'terms', checked: true, disabled: true } };
|
|
21
|
+
export const WithError: Story = {
|
|
22
|
+
args: { label: 'Accept terms', name: 'terms', error: 'You must accept the terms.' },
|
|
23
|
+
};
|
|
24
|
+
export const WithHint: Story = {
|
|
25
|
+
args: { label: 'Subscribe to newsletter', name: 'newsletter', hint: 'Max one email per week.' },
|
|
26
|
+
};
|
|
27
|
+
export const Interactive: Story = {
|
|
28
|
+
render: () => {
|
|
29
|
+
const [checked, setChecked] = useState(false);
|
|
30
|
+
return (
|
|
31
|
+
<ThemeProvider>
|
|
32
|
+
<Checkbox label="Accept terms and conditions" name="terms" checked={checked} onChange={setChecked} />
|
|
33
|
+
</ThemeProvider>
|
|
34
|
+
);
|
|
35
|
+
},
|
|
36
|
+
};
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
import { StyleSheet, View, Pressable, StyleProp, ViewStyle } from 'react-native';
|
|
3
|
+
import { spacing, border } from '../../../../native/tokens';
|
|
4
|
+
import { useTheme } from '../../../../native/ThemeContext';
|
|
5
|
+
import { Label } from '../atoms/Label.native';
|
|
6
|
+
import { Message } from '../atoms/Message.native';
|
|
7
|
+
|
|
8
|
+
interface CheckboxProps {
|
|
9
|
+
label: ReactNode;
|
|
10
|
+
name: string;
|
|
11
|
+
checked?: boolean;
|
|
12
|
+
onChange?: (checked: boolean) => void;
|
|
13
|
+
disabled?: boolean;
|
|
14
|
+
error?: string;
|
|
15
|
+
hint?: string;
|
|
16
|
+
style?: StyleProp<ViewStyle>;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const BOX = 22;
|
|
20
|
+
|
|
21
|
+
const styles = StyleSheet.create({
|
|
22
|
+
container: {
|
|
23
|
+
gap: spacing.xxs,
|
|
24
|
+
},
|
|
25
|
+
row: {
|
|
26
|
+
flexDirection: 'row',
|
|
27
|
+
alignItems: 'center',
|
|
28
|
+
gap: spacing.xs,
|
|
29
|
+
minHeight: 44,
|
|
30
|
+
},
|
|
31
|
+
box: {
|
|
32
|
+
width: BOX,
|
|
33
|
+
height: BOX,
|
|
34
|
+
borderRadius: border.radius.xs,
|
|
35
|
+
borderWidth: 2,
|
|
36
|
+
alignItems: 'center',
|
|
37
|
+
justifyContent: 'center',
|
|
38
|
+
},
|
|
39
|
+
checkmark: {
|
|
40
|
+
fontSize: 14,
|
|
41
|
+
fontWeight: '700',
|
|
42
|
+
lineHeight: 16,
|
|
43
|
+
},
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
export function Checkbox({
|
|
47
|
+
label,
|
|
48
|
+
name,
|
|
49
|
+
checked = false,
|
|
50
|
+
onChange,
|
|
51
|
+
disabled = false,
|
|
52
|
+
error,
|
|
53
|
+
hint,
|
|
54
|
+
style,
|
|
55
|
+
}: CheckboxProps) {
|
|
56
|
+
const { colors } = useTheme();
|
|
57
|
+
|
|
58
|
+
const borderColor = error ? colors.colorError : checked ? colors.colorInteractive : colors.colorBgSubtle;
|
|
59
|
+
const bgColor = checked ? colors.colorInteractive : 'transparent';
|
|
60
|
+
|
|
61
|
+
return (
|
|
62
|
+
<View style={[styles.container, style]}>
|
|
63
|
+
<Pressable
|
|
64
|
+
onPress={() => !disabled && onChange?.(!checked)}
|
|
65
|
+
accessibilityRole="checkbox"
|
|
66
|
+
accessibilityLabel={typeof label === 'string' ? label : name}
|
|
67
|
+
accessibilityState={{ checked, disabled }}
|
|
68
|
+
disabled={disabled}
|
|
69
|
+
style={({ pressed }) => [styles.row, pressed && { opacity: 0.7 }, disabled && { opacity: 0.4 }]}
|
|
70
|
+
>
|
|
71
|
+
<View style={[styles.box, { borderColor, backgroundColor: bgColor }]}>
|
|
72
|
+
{checked && <Label label="✓" style={[styles.checkmark, { color: colors.colorOnInteractive }]} />}
|
|
73
|
+
</View>
|
|
74
|
+
<Label label={label} />
|
|
75
|
+
</Pressable>
|
|
76
|
+
<Message type="error" message={error} />
|
|
77
|
+
<Message type="hint" message={hint} />
|
|
78
|
+
</View>
|
|
79
|
+
);
|
|
80
|
+
}
|
|
@@ -4,13 +4,13 @@ import { Message } from '../atoms/Message';
|
|
|
4
4
|
import { Label } from '../atoms/Label';
|
|
5
5
|
import { cn } from '@boostdev/design-system-foundation';
|
|
6
6
|
import { InputContainer } from '../atoms/InputContainer';
|
|
7
|
+
import type { WithClassName } from '../../../../types';
|
|
7
8
|
|
|
8
|
-
interface CheckboxProps extends Omit<InputHTMLAttributes<HTMLInputElement>, 'type'> {
|
|
9
|
+
interface CheckboxProps extends WithClassName, Omit<InputHTMLAttributes<HTMLInputElement>, 'type'> {
|
|
9
10
|
label: ReactNode;
|
|
10
11
|
name: string;
|
|
11
12
|
error?: string;
|
|
12
13
|
hint?: string;
|
|
13
|
-
className?: string;
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
export function Checkbox({ label, name, error, hint, className, ...props }: CheckboxProps) {
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { Meta, Canvas, ArgTypes } from '@storybook/blocks';
|
|
2
|
+
import * as Stories from './CheckboxGroup.stories';
|
|
3
|
+
|
|
4
|
+
<Meta of={Stories} />
|
|
5
|
+
|
|
6
|
+
# CheckboxGroup
|
|
7
|
+
|
|
8
|
+
Groups multiple `Checkbox` inputs under a shared label. Renders a `<fieldset>` with a `<legend>` for accessible grouping.
|
|
9
|
+
|
|
10
|
+
## When to use
|
|
11
|
+
- Multi-select option sets where several choices can be active simultaneously
|
|
12
|
+
- Any time two or more checkboxes share a common label or question
|
|
13
|
+
|
|
14
|
+
## When not to use
|
|
15
|
+
- A single independent toggle — use `Checkbox` on its own
|
|
16
|
+
- Mutually exclusive choices — use `RadioGroup`
|
|
17
|
+
|
|
18
|
+
## Examples
|
|
19
|
+
|
|
20
|
+
### Default
|
|
21
|
+
<Canvas of={Stories.Default} />
|
|
22
|
+
|
|
23
|
+
### With error
|
|
24
|
+
<Canvas of={Stories.WithError} />
|
|
25
|
+
|
|
26
|
+
### With hint
|
|
27
|
+
<Canvas of={Stories.WithHint} />
|
|
28
|
+
|
|
29
|
+
### Required
|
|
30
|
+
<Canvas of={Stories.Required} />
|
|
31
|
+
|
|
32
|
+
### Disabled
|
|
33
|
+
<Canvas of={Stories.Disabled} />
|
|
34
|
+
|
|
35
|
+
## Props
|
|
36
|
+
|
|
37
|
+
<ArgTypes of={Stories} />
|
|
38
|
+
|
|
39
|
+
## Accessibility
|
|
40
|
+
|
|
41
|
+
- Wraps checkboxes in a `<fieldset>` with a `<legend>` — screen readers announce the group label before each option
|
|
42
|
+
- `disabled` on the group sets the HTML `disabled` attribute on the `<fieldset>`, which disables all child inputs
|
|
43
|
+
- `aria-required` is set on the `<fieldset>` when `required` is true
|
|
44
|
+
- Error and hint messages are linked via `aria-describedby`
|
|
@@ -2,15 +2,15 @@ import { ReactNode, useId } from 'react';
|
|
|
2
2
|
import css from './CheckboxGroup.module.css';
|
|
3
3
|
import { Message } from '../atoms/Message';
|
|
4
4
|
import { cn } from '@boostdev/design-system-foundation';
|
|
5
|
+
import type { WithClassName } from '../../../../types';
|
|
5
6
|
|
|
6
|
-
export interface CheckboxGroupProps {
|
|
7
|
+
export interface CheckboxGroupProps extends WithClassName {
|
|
7
8
|
legend: string;
|
|
8
9
|
children: ReactNode;
|
|
9
10
|
error?: string;
|
|
10
11
|
hint?: string;
|
|
11
12
|
required?: boolean;
|
|
12
13
|
disabled?: boolean;
|
|
13
|
-
className?: string;
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
export function CheckboxGroup({
|
|
@@ -29,6 +29,27 @@ Searchable select with type-ahead filtering. Combines a text input with a dropdo
|
|
|
29
29
|
|
|
30
30
|
<ArgTypes of={Stories} />
|
|
31
31
|
|
|
32
|
+
## CSS variables
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
<table>
|
|
36
|
+
<thead>
|
|
37
|
+
<tr><th>Variable</th><th>Default</th><th>Description</th></tr>
|
|
38
|
+
</thead>
|
|
39
|
+
<tbody>
|
|
40
|
+
<tr><td>`--combobox_color_bg`</td><td>`var(--bds-color_bg)`</td><td>Input background colour</td></tr>
|
|
41
|
+
<tr><td>`--combobox_color`</td><td>`var(--bds-color_on-bg)`</td><td>Input text colour</td></tr>
|
|
42
|
+
<tr><td>`--combobox_border`</td><td>`none`</td><td>Input border</td></tr>
|
|
43
|
+
<tr><td>`--combobox_radius`</td><td>`var(--bdc-outline_radius)`</td><td>Input corner radius</td></tr>
|
|
44
|
+
<tr><td>`--combobox_shadow`</td><td>`var(--bdc-outline_shadow)`</td><td>Input box shadow</td></tr>
|
|
45
|
+
<tr><td>`--combobox_on-color`</td><td>`var(--bds-color_on-bg)`</td><td>Dropdown list text colour</td></tr>
|
|
46
|
+
<tr><td>`--combobox_listbox-border`</td><td>`none`</td><td>Dropdown list border</td></tr>
|
|
47
|
+
<tr><td>`--combobox_listbox-radius`</td><td>`var(--bdc-outline_radius)`</td><td>Dropdown list corner radius</td></tr>
|
|
48
|
+
<tr><td>`--combobox_listbox-shadow`</td><td>`var(--bds-shadow_m)`</td><td>Dropdown list box shadow</td></tr>
|
|
49
|
+
</tbody>
|
|
50
|
+
</table>
|
|
51
|
+
|
|
52
|
+
|
|
32
53
|
## Accessibility
|
|
33
54
|
|
|
34
55
|
- Input uses `role="combobox"` with `aria-autocomplete="list"` and `aria-controls`
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
|
|
13
13
|
.input {
|
|
14
14
|
appearance: none;
|
|
15
|
-
|
|
15
|
+
inline-size: 100%;
|
|
16
16
|
font-family: var(--bds-font_family--body);
|
|
17
17
|
font-size: var(--bds-font_size--body);
|
|
18
18
|
padding: var(--bds-space_s);
|
|
@@ -59,18 +59,17 @@
|
|
|
59
59
|
}
|
|
60
60
|
|
|
61
61
|
.chevron svg {
|
|
62
|
-
|
|
63
|
-
|
|
62
|
+
inline-size: 1rem;
|
|
63
|
+
block-size: 1rem;
|
|
64
64
|
}
|
|
65
65
|
|
|
66
66
|
.listbox {
|
|
67
67
|
position: absolute;
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
right: 0;
|
|
68
|
+
inset-block-start: calc(100% + var(--bds-space_xxs));
|
|
69
|
+
inset-inline: 0;
|
|
71
70
|
z-index: var(--bds-z-index_dropdown);
|
|
72
|
-
max-
|
|
73
|
-
overflow-
|
|
71
|
+
max-block-size: 15rem;
|
|
72
|
+
overflow-block: auto;
|
|
74
73
|
list-style: none;
|
|
75
74
|
margin: 0;
|
|
76
75
|
padding: var(--bds-space_xxs) 0;
|
|
@@ -98,7 +97,7 @@
|
|
|
98
97
|
|
|
99
98
|
.option.--highlighted {
|
|
100
99
|
background-color: var(--bds-color_bg--subtle);
|
|
101
|
-
color: var(--bds-
|
|
100
|
+
color: var(--bds-color_interactive_on-bg);
|
|
102
101
|
}
|
|
103
102
|
|
|
104
103
|
.option.--selected {
|
|
@@ -13,6 +13,7 @@ import { cn } from '@boostdev/design-system-foundation';
|
|
|
13
13
|
import { InputContainer } from '../atoms/InputContainer';
|
|
14
14
|
import { Label } from '../atoms/Label';
|
|
15
15
|
import { Message } from '../atoms/Message';
|
|
16
|
+
import type { WithClassName } from '../../../../types';
|
|
16
17
|
|
|
17
18
|
export interface ComboboxOption {
|
|
18
19
|
value: string;
|
|
@@ -20,7 +21,7 @@ export interface ComboboxOption {
|
|
|
20
21
|
disabled?: boolean;
|
|
21
22
|
}
|
|
22
23
|
|
|
23
|
-
interface ComboboxProps {
|
|
24
|
+
interface ComboboxProps extends WithClassName {
|
|
24
25
|
label: ReactNode;
|
|
25
26
|
name: string;
|
|
26
27
|
options: ComboboxOption[];
|
|
@@ -30,7 +31,6 @@ interface ComboboxProps {
|
|
|
30
31
|
disabled?: boolean;
|
|
31
32
|
error?: string;
|
|
32
33
|
hint?: string;
|
|
33
|
-
className?: string;
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
export function Combobox({
|
|
@@ -31,6 +31,20 @@ File upload input with styled trigger button, hint, and error support.
|
|
|
31
31
|
|
|
32
32
|
<ArgTypes of={Stories} />
|
|
33
33
|
|
|
34
|
+
## CSS variables
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
<table>
|
|
38
|
+
<thead>
|
|
39
|
+
<tr><th>Variable</th><th>Default</th><th>Description</th></tr>
|
|
40
|
+
</thead>
|
|
41
|
+
<tbody>
|
|
42
|
+
<tr><td>`--fileInput_color`</td><td>`var(--bds-color_on-bg)`</td><td>Text colour</td></tr>
|
|
43
|
+
<tr><td>`--fileInput_border-color`</td><td>`currentcolor`</td><td>Drop zone border colour</td></tr>
|
|
44
|
+
</tbody>
|
|
45
|
+
</table>
|
|
46
|
+
|
|
47
|
+
|
|
34
48
|
## Accessibility
|
|
35
49
|
|
|
36
50
|
- Native `<input type="file">` — opens the OS file picker
|
|
@@ -48,8 +48,8 @@
|
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
.icon {
|
|
51
|
-
|
|
52
|
-
|
|
51
|
+
inline-size: 2rem;
|
|
52
|
+
block-size: 2rem;
|
|
53
53
|
flex-shrink: 0;
|
|
54
54
|
}
|
|
55
55
|
|
|
@@ -59,7 +59,7 @@
|
|
|
59
59
|
}
|
|
60
60
|
|
|
61
61
|
.prompt strong {
|
|
62
|
-
color: var(--bds-
|
|
62
|
+
color: var(--bds-color_interactive_on-bg);
|
|
63
63
|
font-weight: var(--bds-font_weight--semibold);
|
|
64
64
|
}
|
|
65
65
|
|
|
@@ -70,8 +70,8 @@
|
|
|
70
70
|
|
|
71
71
|
.hiddenInput {
|
|
72
72
|
position: absolute;
|
|
73
|
-
|
|
74
|
-
|
|
73
|
+
inline-size: 1px;
|
|
74
|
+
block-size: 1px;
|
|
75
75
|
overflow: hidden;
|
|
76
76
|
clip: rect(0, 0, 0, 0);
|
|
77
77
|
white-space: nowrap;
|
|
@@ -3,8 +3,9 @@ import css from './FileInput.module.css';
|
|
|
3
3
|
import { Message } from '../atoms/Message';
|
|
4
4
|
import { InputContainer } from '../atoms/InputContainer';
|
|
5
5
|
import { cn } from '@boostdev/design-system-foundation';
|
|
6
|
+
import type { WithClassName } from '../../../../types';
|
|
6
7
|
|
|
7
|
-
interface FileInputProps {
|
|
8
|
+
interface FileInputProps extends WithClassName {
|
|
8
9
|
label: string;
|
|
9
10
|
name: string;
|
|
10
11
|
accept?: string;
|
|
@@ -14,7 +15,6 @@ interface FileInputProps {
|
|
|
14
15
|
error?: string;
|
|
15
16
|
hint?: string;
|
|
16
17
|
onChange?: (files: FileList | null) => void;
|
|
17
|
-
className?: string;
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
export function FileInput({
|
|
@@ -4,15 +4,15 @@ import { Label } from '../atoms/Label';
|
|
|
4
4
|
import { Message } from '../atoms/Message';
|
|
5
5
|
import { cn } from '@boostdev/design-system-foundation';
|
|
6
6
|
import { InputContainer } from '../atoms/InputContainer';
|
|
7
|
+
import type { WithClassName } from '../../../../types';
|
|
7
8
|
|
|
8
|
-
interface FormInputProps extends Omit<InputHTMLAttributes<HTMLInputElement>, 'type'> {
|
|
9
|
+
interface FormInputProps extends WithClassName, Omit<InputHTMLAttributes<HTMLInputElement>, 'type'> {
|
|
9
10
|
label: ReactNode;
|
|
10
11
|
name: string;
|
|
11
12
|
type?: Exclude<HTMLInputTypeAttribute, 'checkbox' | 'radio' | 'file'>;
|
|
12
13
|
ariaLabel?: string;
|
|
13
14
|
error?: string;
|
|
14
15
|
hint?: string;
|
|
15
|
-
className?: string;
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
export function FormInput({
|