@boostdev/design-system-components 2.4.2 → 2.5.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/AGENTS.md +4 -20
- package/README.md +3 -23
- package/dist/client.cjs +115 -61
- package/dist/client.css +537 -537
- package/dist/client.d.cts +11 -1
- package/dist/client.d.ts +11 -1
- package/dist/client.js +115 -61
- package/dist/index.cjs +115 -61
- package/dist/index.css +537 -537
- package/dist/index.d.cts +11 -1
- package/dist/index.d.ts +11 -1
- package/dist/index.js +115 -61
- package/dist/web-components/index.js +23 -3
- package/package.json +2 -10
- package/src/components/layout/Grid/Grid.mdx +20 -2
- package/src/components/layout/Grid/Grid.spec.tsx +175 -4
- package/src/components/layout/Grid/Grid.tsx +15 -1
- package/src/components/layout/Grid/masonry.ts +120 -9
- package/dist/native/index.cjs +0 -4337
- package/dist/native/index.d.cts +0 -574
- package/dist/native/index.d.ts +0 -574
- package/dist/native/index.js +0 -4421
- package/src/components/interaction/Button/Button.native.mdx +0 -91
- package/src/components/interaction/Button/Button.native.spec.tsx +0 -55
- package/src/components/interaction/Button/Button.native.stories.tsx +0 -141
- package/src/components/interaction/Button/Button.native.tsx +0 -105
- package/src/components/interaction/Dialog/Dialog.native.mdx +0 -61
- package/src/components/interaction/Dialog/Dialog.native.spec.tsx +0 -73
- package/src/components/interaction/Dialog/Dialog.native.stories.tsx +0 -53
- package/src/components/interaction/Dialog/Dialog.native.tsx +0 -128
- package/src/components/interaction/Drawer/Drawer.native.mdx +0 -58
- package/src/components/interaction/Drawer/Drawer.native.spec.tsx +0 -81
- package/src/components/interaction/Drawer/Drawer.native.stories.tsx +0 -33
- package/src/components/interaction/Drawer/Drawer.native.tsx +0 -175
- package/src/components/interaction/DropdownMenu/DropdownMenu.native.mdx +0 -74
- package/src/components/interaction/DropdownMenu/DropdownMenu.native.spec.tsx +0 -78
- package/src/components/interaction/DropdownMenu/DropdownMenu.native.stories.tsx +0 -51
- package/src/components/interaction/DropdownMenu/DropdownMenu.native.tsx +0 -254
- package/src/components/interaction/Popover/Popover.native.mdx +0 -61
- package/src/components/interaction/Popover/Popover.native.spec.tsx +0 -73
- package/src/components/interaction/Popover/Popover.native.stories.tsx +0 -44
- package/src/components/interaction/Popover/Popover.native.tsx +0 -87
- package/src/components/interaction/Rating/Rating.native.mdx +0 -55
- package/src/components/interaction/Rating/Rating.native.spec.tsx +0 -38
- package/src/components/interaction/Rating/Rating.native.stories.tsx +0 -37
- package/src/components/interaction/Rating/Rating.native.tsx +0 -50
- package/src/components/interaction/Toast/Toast.native.mdx +0 -81
- package/src/components/interaction/Toast/Toast.native.spec.tsx +0 -80
- package/src/components/interaction/Toast/Toast.native.stories.tsx +0 -47
- package/src/components/interaction/Toast/Toast.native.tsx +0 -202
- package/src/components/interaction/form/Checkbox/Checkbox.native.mdx +0 -74
- package/src/components/interaction/form/Checkbox/Checkbox.native.spec.tsx +0 -42
- package/src/components/interaction/form/Checkbox/Checkbox.native.stories.tsx +0 -34
- package/src/components/interaction/form/Checkbox/Checkbox.native.tsx +0 -80
- package/src/components/interaction/form/CheckboxGroup/CheckboxGroup.native.mdx +0 -78
- package/src/components/interaction/form/CheckboxGroup/CheckboxGroup.native.spec.tsx +0 -57
- package/src/components/interaction/form/CheckboxGroup/CheckboxGroup.native.stories.tsx +0 -96
- package/src/components/interaction/form/CheckboxGroup/CheckboxGroup.native.tsx +0 -61
- package/src/components/interaction/form/Combobox/Combobox.native.mdx +0 -86
- package/src/components/interaction/form/Combobox/Combobox.native.spec.tsx +0 -60
- package/src/components/interaction/form/Combobox/Combobox.native.stories.tsx +0 -99
- package/src/components/interaction/form/Combobox/Combobox.native.tsx +0 -211
- package/src/components/interaction/form/FileInput/FileInput.native.mdx +0 -86
- package/src/components/interaction/form/FileInput/FileInput.native.spec.tsx +0 -73
- package/src/components/interaction/form/FileInput/FileInput.native.stories.tsx +0 -69
- package/src/components/interaction/form/FileInput/FileInput.native.tsx +0 -129
- package/src/components/interaction/form/FormInput/FormInput.native.mdx +0 -81
- package/src/components/interaction/form/FormInput/FormInput.native.spec.tsx +0 -51
- package/src/components/interaction/form/FormInput/FormInput.native.stories.tsx +0 -54
- package/src/components/interaction/form/FormInput/FormInput.native.tsx +0 -122
- package/src/components/interaction/form/NumberInput/NumberInput.native.mdx +0 -87
- package/src/components/interaction/form/NumberInput/NumberInput.native.spec.tsx +0 -63
- package/src/components/interaction/form/NumberInput/NumberInput.native.stories.tsx +0 -63
- package/src/components/interaction/form/NumberInput/NumberInput.native.tsx +0 -198
- package/src/components/interaction/form/Radio/Radio.native.spec.tsx +0 -79
- package/src/components/interaction/form/Radio/Radio.native.stories.tsx +0 -44
- package/src/components/interaction/form/Radio/Radio.native.tsx +0 -79
- package/src/components/interaction/form/RadioGroup/RadioGroup.native.mdx +0 -79
- package/src/components/interaction/form/RadioGroup/RadioGroup.native.spec.tsx +0 -66
- package/src/components/interaction/form/RadioGroup/RadioGroup.native.stories.tsx +0 -96
- package/src/components/interaction/form/RadioGroup/RadioGroup.native.tsx +0 -61
- package/src/components/interaction/form/SegmentedControl/SegmentedControl.native.mdx +0 -78
- package/src/components/interaction/form/SegmentedControl/SegmentedControl.native.spec.tsx +0 -82
- package/src/components/interaction/form/SegmentedControl/SegmentedControl.native.stories.tsx +0 -99
- package/src/components/interaction/form/SegmentedControl/SegmentedControl.native.tsx +0 -121
- package/src/components/interaction/form/Select/Select.native.mdx +0 -85
- package/src/components/interaction/form/Select/Select.native.spec.tsx +0 -64
- package/src/components/interaction/form/Select/Select.native.stories.tsx +0 -75
- package/src/components/interaction/form/Select/Select.native.tsx +0 -252
- package/src/components/interaction/form/Slider/Slider.native.mdx +0 -83
- package/src/components/interaction/form/Slider/Slider.native.spec.tsx +0 -51
- package/src/components/interaction/form/Slider/Slider.native.stories.tsx +0 -58
- package/src/components/interaction/form/Slider/Slider.native.tsx +0 -188
- package/src/components/interaction/form/Switch/Switch.native.spec.tsx +0 -60
- package/src/components/interaction/form/Switch/Switch.native.stories.tsx +0 -33
- package/src/components/interaction/form/Switch/Switch.native.tsx +0 -59
- package/src/components/interaction/form/Textarea/Textarea.native.mdx +0 -76
- package/src/components/interaction/form/Textarea/Textarea.native.spec.tsx +0 -50
- package/src/components/interaction/form/Textarea/Textarea.native.stories.tsx +0 -50
- package/src/components/interaction/form/Textarea/Textarea.native.tsx +0 -108
- package/src/components/interaction/form/atoms/Label.native.spec.tsx +0 -39
- package/src/components/interaction/form/atoms/Label.native.stories.tsx +0 -18
- package/src/components/interaction/form/atoms/Label.native.tsx +0 -29
- package/src/components/interaction/form/atoms/Message.native.spec.tsx +0 -30
- package/src/components/interaction/form/atoms/Message.native.stories.tsx +0 -22
- package/src/components/interaction/form/atoms/Message.native.tsx +0 -34
- package/src/components/layout/ButtonGroup/ButtonGroup.native.spec.tsx +0 -83
- package/src/components/layout/ButtonGroup/ButtonGroup.native.stories.tsx +0 -44
- package/src/components/layout/ButtonGroup/ButtonGroup.native.tsx +0 -44
- package/src/components/layout/Card/Card.native.spec.tsx +0 -102
- package/src/components/layout/Card/Card.native.stories.tsx +0 -51
- package/src/components/layout/Card/Card.native.tsx +0 -89
- package/src/components/layout/IconWrapper/IconWrapper.native.spec.tsx +0 -39
- package/src/components/layout/IconWrapper/IconWrapper.native.stories.tsx +0 -37
- package/src/components/layout/IconWrapper/IconWrapper.native.tsx +0 -20
- package/src/components/layout/SectionHeader/SectionHeader.native.spec.tsx +0 -51
- package/src/components/layout/SectionHeader/SectionHeader.native.stories.tsx +0 -36
- package/src/components/layout/SectionHeader/SectionHeader.native.tsx +0 -79
- package/src/components/ui/Accordion/Accordion.native.mdx +0 -65
- package/src/components/ui/Accordion/Accordion.native.spec.tsx +0 -69
- package/src/components/ui/Accordion/Accordion.native.stories.tsx +0 -52
- package/src/components/ui/Accordion/Accordion.native.tsx +0 -141
- package/src/components/ui/Alert/Alert.native.mdx +0 -62
- package/src/components/ui/Alert/Alert.native.spec.tsx +0 -76
- package/src/components/ui/Alert/Alert.native.stories.tsx +0 -41
- package/src/components/ui/Alert/Alert.native.tsx +0 -94
- package/src/components/ui/Avatar/Avatar.native.mdx +0 -50
- package/src/components/ui/Avatar/Avatar.native.spec.tsx +0 -47
- package/src/components/ui/Avatar/Avatar.native.stories.tsx +0 -32
- package/src/components/ui/Avatar/Avatar.native.tsx +0 -85
- package/src/components/ui/Badge/Badge.native.mdx +0 -54
- package/src/components/ui/Badge/Badge.native.spec.tsx +0 -45
- package/src/components/ui/Badge/Badge.native.stories.tsx +0 -34
- package/src/components/ui/Badge/Badge.native.tsx +0 -50
- package/src/components/ui/Breadcrumb/Breadcrumb.native.mdx +0 -52
- package/src/components/ui/Breadcrumb/Breadcrumb.native.spec.tsx +0 -49
- package/src/components/ui/Breadcrumb/Breadcrumb.native.stories.tsx +0 -46
- package/src/components/ui/Breadcrumb/Breadcrumb.native.tsx +0 -83
- package/src/components/ui/Calendar/Calendar.native.mdx +0 -58
- package/src/components/ui/Calendar/Calendar.native.spec.tsx +0 -92
- package/src/components/ui/Calendar/Calendar.native.stories.tsx +0 -45
- package/src/components/ui/Calendar/Calendar.native.tsx +0 -294
- package/src/components/ui/Carousel/Carousel.native.mdx +0 -55
- package/src/components/ui/Carousel/Carousel.native.spec.tsx +0 -55
- package/src/components/ui/Carousel/Carousel.native.stories.tsx +0 -59
- package/src/components/ui/Carousel/Carousel.native.tsx +0 -184
- package/src/components/ui/Collapsible/Collapsible.native.mdx +0 -53
- package/src/components/ui/Collapsible/Collapsible.native.spec.tsx +0 -68
- package/src/components/ui/Collapsible/Collapsible.native.stories.tsx +0 -48
- package/src/components/ui/Collapsible/Collapsible.native.tsx +0 -139
- package/src/components/ui/DescriptionList/DescriptionList.native.mdx +0 -50
- package/src/components/ui/DescriptionList/DescriptionList.native.spec.tsx +0 -37
- package/src/components/ui/DescriptionList/DescriptionList.native.stories.tsx +0 -48
- package/src/components/ui/DescriptionList/DescriptionList.native.tsx +0 -54
- package/src/components/ui/Link/Link.native.mdx +0 -53
- package/src/components/ui/Link/Link.native.spec.tsx +0 -35
- package/src/components/ui/Link/Link.native.stories.tsx +0 -46
- package/src/components/ui/Link/Link.native.tsx +0 -48
- package/src/components/ui/Loading/Loading.native.spec.tsx +0 -24
- package/src/components/ui/Loading/Loading.native.stories.tsx +0 -31
- package/src/components/ui/Loading/Loading.native.tsx +0 -29
- package/src/components/ui/NotificationBanner/NotificationBanner.native.spec.tsx +0 -85
- package/src/components/ui/NotificationBanner/NotificationBanner.native.stories.tsx +0 -37
- package/src/components/ui/NotificationBanner/NotificationBanner.native.tsx +0 -76
- package/src/components/ui/Pagination/Pagination.native.mdx +0 -62
- package/src/components/ui/Pagination/Pagination.native.spec.tsx +0 -86
- package/src/components/ui/Pagination/Pagination.native.stories.tsx +0 -47
- package/src/components/ui/Pagination/Pagination.native.tsx +0 -157
- package/src/components/ui/Progress/Progress.native.spec.tsx +0 -56
- package/src/components/ui/Progress/Progress.native.stories.tsx +0 -34
- package/src/components/ui/Progress/Progress.native.tsx +0 -84
- package/src/components/ui/ProgressCircle/ProgressCircle.native.mdx +0 -63
- package/src/components/ui/ProgressCircle/ProgressCircle.native.spec.tsx +0 -39
- package/src/components/ui/ProgressCircle/ProgressCircle.native.stories.tsx +0 -36
- package/src/components/ui/ProgressCircle/ProgressCircle.native.tsx +0 -176
- package/src/components/ui/Separator/Separator.native.spec.tsx +0 -39
- package/src/components/ui/Separator/Separator.native.stories.tsx +0 -38
- package/src/components/ui/Separator/Separator.native.tsx +0 -32
- package/src/components/ui/Skeleton/Skeleton.native.spec.tsx +0 -39
- package/src/components/ui/Skeleton/Skeleton.native.stories.tsx +0 -31
- package/src/components/ui/Skeleton/Skeleton.native.tsx +0 -42
- package/src/components/ui/Table/Table.native.mdx +0 -72
- package/src/components/ui/Table/Table.native.spec.tsx +0 -83
- package/src/components/ui/Table/Table.native.stories.tsx +0 -55
- package/src/components/ui/Table/Table.native.tsx +0 -196
- package/src/components/ui/Tabs/Tabs.native.mdx +0 -65
- package/src/components/ui/Tabs/Tabs.native.spec.tsx +0 -65
- package/src/components/ui/Tabs/Tabs.native.stories.tsx +0 -57
- package/src/components/ui/Tabs/Tabs.native.tsx +0 -133
- package/src/components/ui/Tooltip/Tooltip.native.mdx +0 -47
- package/src/components/ui/Tooltip/Tooltip.native.spec.tsx +0 -37
- package/src/components/ui/Tooltip/Tooltip.native.stories.tsx +0 -38
- package/src/components/ui/Tooltip/Tooltip.native.tsx +0 -57
- package/src/components/ui/Typography/Typography.native.mdx +0 -56
- package/src/components/ui/Typography/Typography.native.spec.tsx +0 -49
- package/src/components/ui/Typography/Typography.native.stories.tsx +0 -36
- package/src/components/ui/Typography/Typography.native.tsx +0 -65
- package/src/native/ThemeContext.tsx +0 -28
- package/src/native/tokens.ts +0 -13
- package/src/native.ts +0 -76
- package/src/stories/ReactNative.mdx +0 -156
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
import { Meta, Canvas, ArgTypes } from '@storybook/blocks';
|
|
2
|
-
import * as Stories from './CheckboxGroup.native.stories';
|
|
3
|
-
|
|
4
|
-
<Meta of={Stories} />
|
|
5
|
-
|
|
6
|
-
# CheckboxGroup (React Native)
|
|
7
|
-
|
|
8
|
-
Groups related checkboxes under a common legend with optional hint and error messages.
|
|
9
|
-
|
|
10
|
-
> **Status: alpha** -- API may change before stable release.
|
|
11
|
-
|
|
12
|
-
## Usage
|
|
13
|
-
|
|
14
|
-
```tsx
|
|
15
|
-
import { CheckboxGroup, Checkbox } from '@boostdev/design-system-components';
|
|
16
|
-
import { useState } from 'react';
|
|
17
|
-
|
|
18
|
-
function Example() {
|
|
19
|
-
const [checked, setChecked] = useState({ email: false, sms: false });
|
|
20
|
-
|
|
21
|
-
return (
|
|
22
|
-
<CheckboxGroup legend="Notifications">
|
|
23
|
-
<Checkbox
|
|
24
|
-
label="Email"
|
|
25
|
-
name="email"
|
|
26
|
-
checked={checked.email}
|
|
27
|
-
onChange={(v) => setChecked(s => ({ ...s, email: v }))}
|
|
28
|
-
/>
|
|
29
|
-
<Checkbox
|
|
30
|
-
label="SMS"
|
|
31
|
-
name="sms"
|
|
32
|
-
checked={checked.sms}
|
|
33
|
-
onChange={(v) => setChecked(s => ({ ...s, sms: v }))}
|
|
34
|
-
/>
|
|
35
|
-
</CheckboxGroup>
|
|
36
|
-
);
|
|
37
|
-
}
|
|
38
|
-
```
|
|
39
|
-
|
|
40
|
-
## Examples
|
|
41
|
-
|
|
42
|
-
### Default
|
|
43
|
-
<Canvas of={Stories.Default} />
|
|
44
|
-
|
|
45
|
-
### Required
|
|
46
|
-
<Canvas of={Stories.Required} />
|
|
47
|
-
|
|
48
|
-
### With hint
|
|
49
|
-
<Canvas of={Stories.WithHint} />
|
|
50
|
-
|
|
51
|
-
### With error
|
|
52
|
-
<Canvas of={Stories.WithError} />
|
|
53
|
-
|
|
54
|
-
### Disabled
|
|
55
|
-
<Canvas of={Stories.Disabled} />
|
|
56
|
-
|
|
57
|
-
### Interactive
|
|
58
|
-
<Canvas of={Stories.Interactive} />
|
|
59
|
-
|
|
60
|
-
## Props
|
|
61
|
-
|
|
62
|
-
<ArgTypes of={Stories} />
|
|
63
|
-
|
|
64
|
-
## Props reference
|
|
65
|
-
|
|
66
|
-
| Prop | Type | Default | Description |
|
|
67
|
-
|------|------|---------|-------------|
|
|
68
|
-
| `legend` | string | -- | Group label displayed above the checkboxes |
|
|
69
|
-
| `children` | ReactNode | -- | Checkbox components |
|
|
70
|
-
| `error` | string | -- | Error message displayed below the group |
|
|
71
|
-
| `hint` | string | -- | Helper text displayed below the group |
|
|
72
|
-
| `required` | boolean | -- | Appends asterisk to legend |
|
|
73
|
-
| `disabled` | boolean | `false` | Reduces opacity of the entire group |
|
|
74
|
-
|
|
75
|
-
## Accessibility
|
|
76
|
-
|
|
77
|
-
- The group is labelled via `accessibilityLabel` matching the legend text
|
|
78
|
-
- Error messages use `accessibilityRole="alert"` for screen reader announcement
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
import { render, screen } from '@testing-library/react';
|
|
2
|
-
import { ThemeProvider } from '../../../../native/ThemeContext';
|
|
3
|
-
import { CheckboxGroup } from './CheckboxGroup.native';
|
|
4
|
-
import { Checkbox } from '../Checkbox/Checkbox.native';
|
|
5
|
-
|
|
6
|
-
function renderWithTheme(ui: React.ReactElement) {
|
|
7
|
-
return render(<ThemeProvider>{ui}</ThemeProvider>);
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
describe('CheckboxGroup (native)', () => {
|
|
11
|
-
it('renders the legend text', () => {
|
|
12
|
-
renderWithTheme(
|
|
13
|
-
<CheckboxGroup legend="Notifications">
|
|
14
|
-
<Checkbox label="Email" name="email" />
|
|
15
|
-
</CheckboxGroup>,
|
|
16
|
-
);
|
|
17
|
-
expect(screen.getByText('Notifications')).toBeInTheDocument();
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
it('renders children', () => {
|
|
21
|
-
renderWithTheme(
|
|
22
|
-
<CheckboxGroup legend="Preferences">
|
|
23
|
-
<Checkbox label="Option A" name="a" />
|
|
24
|
-
<Checkbox label="Option B" name="b" />
|
|
25
|
-
</CheckboxGroup>,
|
|
26
|
-
);
|
|
27
|
-
expect(screen.getByText('Option A')).toBeInTheDocument();
|
|
28
|
-
expect(screen.getByText('Option B')).toBeInTheDocument();
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
it('appends asterisk when required', () => {
|
|
32
|
-
renderWithTheme(
|
|
33
|
-
<CheckboxGroup legend="Accept" required>
|
|
34
|
-
<Checkbox label="Terms" name="terms" />
|
|
35
|
-
</CheckboxGroup>,
|
|
36
|
-
);
|
|
37
|
-
expect(screen.getByText('*', { exact: false })).toBeInTheDocument();
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
it('renders error message', () => {
|
|
41
|
-
renderWithTheme(
|
|
42
|
-
<CheckboxGroup legend="Options" error="Select at least one.">
|
|
43
|
-
<Checkbox label="A" name="a" />
|
|
44
|
-
</CheckboxGroup>,
|
|
45
|
-
);
|
|
46
|
-
expect(screen.getByRole('alert')).toHaveTextContent('Select at least one.');
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
it('renders hint message', () => {
|
|
50
|
-
renderWithTheme(
|
|
51
|
-
<CheckboxGroup legend="Options" hint="Select all that apply.">
|
|
52
|
-
<Checkbox label="A" name="a" />
|
|
53
|
-
</CheckboxGroup>,
|
|
54
|
-
);
|
|
55
|
-
expect(screen.getByText('Select all that apply.')).toBeInTheDocument();
|
|
56
|
-
});
|
|
57
|
-
});
|
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
import React, { useState } from 'react';
|
|
2
|
-
import type { Meta, StoryObj } from '@storybook/react';
|
|
3
|
-
import { ThemeProvider } from '../../../../native/ThemeContext';
|
|
4
|
-
import { CheckboxGroup } from './CheckboxGroup.native';
|
|
5
|
-
import { Checkbox } from '../Checkbox/Checkbox.native';
|
|
6
|
-
|
|
7
|
-
const meta = {
|
|
8
|
-
tags: ['!stable', 'alpha'],
|
|
9
|
-
title: 'React Native/Form/CheckboxGroup',
|
|
10
|
-
component: CheckboxGroup,
|
|
11
|
-
decorators: [(Story) => <ThemeProvider colorScheme="light"><Story /></ThemeProvider>],
|
|
12
|
-
parameters: { layout: 'padded' },
|
|
13
|
-
} satisfies Meta<typeof CheckboxGroup>;
|
|
14
|
-
|
|
15
|
-
export default meta;
|
|
16
|
-
type Story = StoryObj<typeof meta>;
|
|
17
|
-
|
|
18
|
-
export const Default: Story = {
|
|
19
|
-
args: {
|
|
20
|
-
legend: 'Notifications',
|
|
21
|
-
children: (
|
|
22
|
-
<>
|
|
23
|
-
<Checkbox label="Email" name="email" />
|
|
24
|
-
<Checkbox label="SMS" name="sms" />
|
|
25
|
-
<Checkbox label="Push" name="push" />
|
|
26
|
-
</>
|
|
27
|
-
),
|
|
28
|
-
},
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
export const Required: Story = {
|
|
32
|
-
args: {
|
|
33
|
-
legend: 'Accept terms',
|
|
34
|
-
required: true,
|
|
35
|
-
children: (
|
|
36
|
-
<>
|
|
37
|
-
<Checkbox label="Terms of service" name="tos" />
|
|
38
|
-
<Checkbox label="Privacy policy" name="privacy" />
|
|
39
|
-
</>
|
|
40
|
-
),
|
|
41
|
-
},
|
|
42
|
-
};
|
|
43
|
-
|
|
44
|
-
export const Disabled: Story = {
|
|
45
|
-
args: {
|
|
46
|
-
legend: 'Notifications',
|
|
47
|
-
disabled: true,
|
|
48
|
-
children: (
|
|
49
|
-
<>
|
|
50
|
-
<Checkbox label="Email" name="email" checked disabled />
|
|
51
|
-
<Checkbox label="SMS" name="sms" disabled />
|
|
52
|
-
</>
|
|
53
|
-
),
|
|
54
|
-
},
|
|
55
|
-
};
|
|
56
|
-
|
|
57
|
-
export const WithError: Story = {
|
|
58
|
-
args: {
|
|
59
|
-
legend: 'Select at least one',
|
|
60
|
-
error: 'Please select at least one option.',
|
|
61
|
-
children: (
|
|
62
|
-
<>
|
|
63
|
-
<Checkbox label="Option A" name="a" />
|
|
64
|
-
<Checkbox label="Option B" name="b" />
|
|
65
|
-
</>
|
|
66
|
-
),
|
|
67
|
-
},
|
|
68
|
-
};
|
|
69
|
-
|
|
70
|
-
export const WithHint: Story = {
|
|
71
|
-
args: {
|
|
72
|
-
legend: 'Preferences',
|
|
73
|
-
hint: 'Select all that apply.',
|
|
74
|
-
children: (
|
|
75
|
-
<>
|
|
76
|
-
<Checkbox label="Newsletter" name="newsletter" />
|
|
77
|
-
<Checkbox label="Product updates" name="updates" />
|
|
78
|
-
</>
|
|
79
|
-
),
|
|
80
|
-
},
|
|
81
|
-
};
|
|
82
|
-
|
|
83
|
-
function InteractiveComponent() {
|
|
84
|
-
const [checked, setChecked] = useState({ email: false, sms: false, push: false });
|
|
85
|
-
return (
|
|
86
|
-
<CheckboxGroup legend="Notifications">
|
|
87
|
-
<Checkbox label="Email" name="email" checked={checked.email} onChange={(v) => setChecked(s => ({ ...s, email: v }))} />
|
|
88
|
-
<Checkbox label="SMS" name="sms" checked={checked.sms} onChange={(v) => setChecked(s => ({ ...s, sms: v }))} />
|
|
89
|
-
<Checkbox label="Push" name="push" checked={checked.push} onChange={(v) => setChecked(s => ({ ...s, push: v }))} />
|
|
90
|
-
</CheckboxGroup>
|
|
91
|
-
);
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
export const Interactive: Story = {
|
|
95
|
-
render: () => <InteractiveComponent />,
|
|
96
|
-
};
|
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
import { ReactNode } from 'react';
|
|
2
|
-
import { StyleSheet, View, Text, StyleProp, ViewStyle } from 'react-native';
|
|
3
|
-
import { spacing, font, lineHeight } from '../../../../native/tokens';
|
|
4
|
-
import { useTheme } from '../../../../native/ThemeContext';
|
|
5
|
-
import { Message } from '../atoms/Message.native';
|
|
6
|
-
|
|
7
|
-
interface CheckboxGroupProps {
|
|
8
|
-
legend: string;
|
|
9
|
-
children: ReactNode;
|
|
10
|
-
error?: string;
|
|
11
|
-
hint?: string;
|
|
12
|
-
required?: boolean;
|
|
13
|
-
disabled?: boolean;
|
|
14
|
-
style?: StyleProp<ViewStyle>;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
const styles = StyleSheet.create({
|
|
18
|
-
container: {
|
|
19
|
-
gap: spacing.xs,
|
|
20
|
-
},
|
|
21
|
-
legend: {
|
|
22
|
-
fontFamily: font.family.body,
|
|
23
|
-
fontSize: font.size.body,
|
|
24
|
-
lineHeight: lineHeight.body,
|
|
25
|
-
fontWeight: font.weight.semibold,
|
|
26
|
-
},
|
|
27
|
-
required: {
|
|
28
|
-
fontWeight: font.weight.body,
|
|
29
|
-
},
|
|
30
|
-
items: {
|
|
31
|
-
gap: spacing.xxs,
|
|
32
|
-
},
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
export function CheckboxGroup({
|
|
36
|
-
legend,
|
|
37
|
-
children,
|
|
38
|
-
error,
|
|
39
|
-
hint,
|
|
40
|
-
required,
|
|
41
|
-
disabled = false,
|
|
42
|
-
style,
|
|
43
|
-
}: Readonly<CheckboxGroupProps>) {
|
|
44
|
-
const { colors } = useTheme();
|
|
45
|
-
|
|
46
|
-
return (
|
|
47
|
-
<View
|
|
48
|
-
style={[styles.container, disabled && { opacity: 0.4 }, style]}
|
|
49
|
-
accessibilityRole="none"
|
|
50
|
-
accessibilityLabel={legend}
|
|
51
|
-
>
|
|
52
|
-
<Text style={[styles.legend, { color: colors.colorOnBg }]}>
|
|
53
|
-
{legend}
|
|
54
|
-
{required && <Text style={[styles.required, { color: colors.colorOnBgSubtle }]}> *</Text>}
|
|
55
|
-
</Text>
|
|
56
|
-
<View style={styles.items}>{children}</View>
|
|
57
|
-
<Message type="error" message={error} />
|
|
58
|
-
<Message type="hint" message={hint} />
|
|
59
|
-
</View>
|
|
60
|
-
);
|
|
61
|
-
}
|
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
import { Meta, Canvas, ArgTypes } from '@storybook/blocks';
|
|
2
|
-
import * as Stories from './Combobox.native.stories';
|
|
3
|
-
|
|
4
|
-
<Meta of={Stories} />
|
|
5
|
-
|
|
6
|
-
# Combobox (React Native)
|
|
7
|
-
|
|
8
|
-
A text input with a filterable dropdown list. Type to filter options, tap to select. Supports error and hint messages.
|
|
9
|
-
|
|
10
|
-
> **Status: alpha** -- API may change before stable release.
|
|
11
|
-
|
|
12
|
-
## Usage
|
|
13
|
-
|
|
14
|
-
```tsx
|
|
15
|
-
import { Combobox } from '@boostdev/design-system-components';
|
|
16
|
-
import { useState } from 'react';
|
|
17
|
-
|
|
18
|
-
const options = [
|
|
19
|
-
{ value: 'apple', label: 'Apple' },
|
|
20
|
-
{ value: 'banana', label: 'Banana' },
|
|
21
|
-
{ value: 'cherry', label: 'Cherry' },
|
|
22
|
-
];
|
|
23
|
-
|
|
24
|
-
function Example() {
|
|
25
|
-
const [value, setValue] = useState('');
|
|
26
|
-
|
|
27
|
-
return (
|
|
28
|
-
<Combobox
|
|
29
|
-
label="Fruit"
|
|
30
|
-
name="fruit"
|
|
31
|
-
options={options}
|
|
32
|
-
placeholder="Search fruit..."
|
|
33
|
-
value={value}
|
|
34
|
-
onChange={setValue}
|
|
35
|
-
/>
|
|
36
|
-
);
|
|
37
|
-
}
|
|
38
|
-
```
|
|
39
|
-
|
|
40
|
-
## Examples
|
|
41
|
-
|
|
42
|
-
### Default
|
|
43
|
-
<Canvas of={Stories.Default} />
|
|
44
|
-
|
|
45
|
-
### With value
|
|
46
|
-
<Canvas of={Stories.WithValue} />
|
|
47
|
-
|
|
48
|
-
### With hint
|
|
49
|
-
<Canvas of={Stories.WithHint} />
|
|
50
|
-
|
|
51
|
-
### With error
|
|
52
|
-
<Canvas of={Stories.WithError} />
|
|
53
|
-
|
|
54
|
-
### Disabled
|
|
55
|
-
<Canvas of={Stories.Disabled} />
|
|
56
|
-
|
|
57
|
-
### With disabled option
|
|
58
|
-
<Canvas of={Stories.WithDisabledOption} />
|
|
59
|
-
|
|
60
|
-
### Interactive
|
|
61
|
-
<Canvas of={Stories.Interactive} />
|
|
62
|
-
|
|
63
|
-
## Props
|
|
64
|
-
|
|
65
|
-
<ArgTypes of={Stories} />
|
|
66
|
-
|
|
67
|
-
## Props reference
|
|
68
|
-
|
|
69
|
-
| Prop | Type | Default | Description |
|
|
70
|
-
|------|------|---------|-------------|
|
|
71
|
-
| `label` | string | -- | Visible label text |
|
|
72
|
-
| `name` | string | -- | Field name |
|
|
73
|
-
| `options` | `ComboboxOption[]` | -- | Array of `{ value, label, disabled? }` |
|
|
74
|
-
| `placeholder` | string | -- | Input placeholder text |
|
|
75
|
-
| `value` | string | -- | Currently selected option value |
|
|
76
|
-
| `onChange` | `(value: string) => void` | -- | Called with the selected option value |
|
|
77
|
-
| `disabled` | boolean | `false` | Disables the entire input |
|
|
78
|
-
| `error` | string | -- | Error message displayed below |
|
|
79
|
-
| `hint` | string | -- | Helper text displayed below |
|
|
80
|
-
|
|
81
|
-
## Accessibility
|
|
82
|
-
|
|
83
|
-
- Uses `accessibilityRole="combobox"` on the input
|
|
84
|
-
- Options use `accessibilityRole="menuitem"` with selected/disabled states
|
|
85
|
-
- Selected option is highlighted with `accessibilityState.selected`
|
|
86
|
-
- Disabled options are communicated via `accessibilityState.disabled`
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
import { render, screen } from '@testing-library/react';
|
|
2
|
-
import { ThemeProvider } from '../../../../native/ThemeContext';
|
|
3
|
-
import { Combobox } from './Combobox.native';
|
|
4
|
-
import type { ComboboxOption } from './Combobox.native';
|
|
5
|
-
|
|
6
|
-
function renderWithTheme(ui: React.ReactElement) {
|
|
7
|
-
return render(<ThemeProvider>{ui}</ThemeProvider>);
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
const fruits: ComboboxOption[] = [
|
|
11
|
-
{ value: 'apple', label: 'Apple' },
|
|
12
|
-
{ value: 'banana', label: 'Banana' },
|
|
13
|
-
{ value: 'cherry', label: 'Cherry' },
|
|
14
|
-
];
|
|
15
|
-
|
|
16
|
-
describe('Combobox (native)', () => {
|
|
17
|
-
it('renders with label', () => {
|
|
18
|
-
renderWithTheme(
|
|
19
|
-
<Combobox label="Fruit" name="fruit" options={fruits} />,
|
|
20
|
-
);
|
|
21
|
-
expect(screen.getByText('Fruit')).toBeInTheDocument();
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
it('has combobox role', () => {
|
|
25
|
-
renderWithTheme(
|
|
26
|
-
<Combobox label="Fruit" name="fruit" options={fruits} />,
|
|
27
|
-
);
|
|
28
|
-
expect(screen.getByRole('combobox')).toBeInTheDocument();
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
it('shows placeholder text', () => {
|
|
32
|
-
renderWithTheme(
|
|
33
|
-
<Combobox label="Fruit" name="fruit" options={fruits} placeholder="Search..." />,
|
|
34
|
-
);
|
|
35
|
-
expect(screen.getByPlaceholderText('Search...')).toBeInTheDocument();
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
it('displays the selected option label when value is set', () => {
|
|
39
|
-
renderWithTheme(
|
|
40
|
-
<Combobox label="Fruit" name="fruit" options={fruits} value="cherry" />,
|
|
41
|
-
);
|
|
42
|
-
// react-native-web renders TextInput as <input>, so we can check the DOM value
|
|
43
|
-
const input = screen.getByRole('combobox') as HTMLInputElement;
|
|
44
|
-
expect(input.value).toBe('Cherry');
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
it('renders error message', () => {
|
|
48
|
-
renderWithTheme(
|
|
49
|
-
<Combobox label="Fruit" name="fruit" options={fruits} error="Required." />,
|
|
50
|
-
);
|
|
51
|
-
expect(screen.getByRole('alert')).toHaveTextContent('Required.');
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
it('renders hint message', () => {
|
|
55
|
-
renderWithTheme(
|
|
56
|
-
<Combobox label="Fruit" name="fruit" options={fruits} hint="Type to filter." />,
|
|
57
|
-
);
|
|
58
|
-
expect(screen.getByText('Type to filter.')).toBeInTheDocument();
|
|
59
|
-
});
|
|
60
|
-
});
|
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
import React, { useState } from 'react';
|
|
2
|
-
import type { Meta, StoryObj } from '@storybook/react';
|
|
3
|
-
import { ThemeProvider } from '../../../../native/ThemeContext';
|
|
4
|
-
import { Combobox } from './Combobox.native';
|
|
5
|
-
import type { ComboboxOption } from './Combobox.native';
|
|
6
|
-
|
|
7
|
-
const fruits: ComboboxOption[] = [
|
|
8
|
-
{ value: 'apple', label: 'Apple' },
|
|
9
|
-
{ value: 'banana', label: 'Banana' },
|
|
10
|
-
{ value: 'cherry', label: 'Cherry' },
|
|
11
|
-
{ value: 'date', label: 'Date' },
|
|
12
|
-
{ value: 'elderberry', label: 'Elderberry' },
|
|
13
|
-
];
|
|
14
|
-
|
|
15
|
-
const meta = {
|
|
16
|
-
tags: ['!stable', 'alpha'],
|
|
17
|
-
title: 'React Native/Form/Combobox',
|
|
18
|
-
component: Combobox,
|
|
19
|
-
decorators: [(Story) => <ThemeProvider colorScheme="light"><Story /></ThemeProvider>],
|
|
20
|
-
parameters: { layout: 'padded' },
|
|
21
|
-
} satisfies Meta<typeof Combobox>;
|
|
22
|
-
|
|
23
|
-
export default meta;
|
|
24
|
-
type Story = StoryObj<typeof meta>;
|
|
25
|
-
|
|
26
|
-
export const Default: Story = {
|
|
27
|
-
args: {
|
|
28
|
-
label: 'Fruit',
|
|
29
|
-
name: 'fruit',
|
|
30
|
-
options: fruits,
|
|
31
|
-
placeholder: 'Search fruit...',
|
|
32
|
-
},
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
export const WithValue: Story = {
|
|
36
|
-
args: {
|
|
37
|
-
label: 'Fruit',
|
|
38
|
-
name: 'fruit',
|
|
39
|
-
options: fruits,
|
|
40
|
-
value: 'cherry',
|
|
41
|
-
},
|
|
42
|
-
};
|
|
43
|
-
|
|
44
|
-
export const Disabled: Story = {
|
|
45
|
-
args: {
|
|
46
|
-
label: 'Fruit',
|
|
47
|
-
name: 'fruit',
|
|
48
|
-
options: fruits,
|
|
49
|
-
disabled: true,
|
|
50
|
-
},
|
|
51
|
-
};
|
|
52
|
-
|
|
53
|
-
export const WithError: Story = {
|
|
54
|
-
args: {
|
|
55
|
-
label: 'Fruit',
|
|
56
|
-
name: 'fruit',
|
|
57
|
-
options: fruits,
|
|
58
|
-
error: 'Please select a fruit.',
|
|
59
|
-
},
|
|
60
|
-
};
|
|
61
|
-
|
|
62
|
-
export const WithHint: Story = {
|
|
63
|
-
args: {
|
|
64
|
-
label: 'Fruit',
|
|
65
|
-
name: 'fruit',
|
|
66
|
-
options: fruits,
|
|
67
|
-
hint: 'Type to filter the list.',
|
|
68
|
-
},
|
|
69
|
-
};
|
|
70
|
-
|
|
71
|
-
export const WithDisabledOption: Story = {
|
|
72
|
-
args: {
|
|
73
|
-
label: 'Fruit',
|
|
74
|
-
name: 'fruit',
|
|
75
|
-
options: [
|
|
76
|
-
{ value: 'apple', label: 'Apple' },
|
|
77
|
-
{ value: 'banana', label: 'Banana', disabled: true },
|
|
78
|
-
{ value: 'cherry', label: 'Cherry' },
|
|
79
|
-
],
|
|
80
|
-
},
|
|
81
|
-
};
|
|
82
|
-
|
|
83
|
-
function InteractiveComponent() {
|
|
84
|
-
const [value, setValue] = useState('');
|
|
85
|
-
return (
|
|
86
|
-
<Combobox
|
|
87
|
-
label="Fruit"
|
|
88
|
-
name="fruit"
|
|
89
|
-
options={fruits}
|
|
90
|
-
placeholder="Search fruit..."
|
|
91
|
-
value={value}
|
|
92
|
-
onChange={setValue}
|
|
93
|
-
/>
|
|
94
|
-
);
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
export const Interactive: Story = {
|
|
98
|
-
render: () => <InteractiveComponent />,
|
|
99
|
-
};
|