@boostdev/design-system-components 1.0.2 → 1.1.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.
Files changed (268) hide show
  1. package/AGENTS.md +20 -18
  2. package/dist/client.cjs +236 -153
  3. package/dist/client.css +785 -702
  4. package/dist/client.d.cts +53 -94
  5. package/dist/client.d.ts +53 -94
  6. package/dist/client.js +237 -163
  7. package/dist/index.cjs +236 -153
  8. package/dist/index.css +785 -702
  9. package/dist/index.d.cts +53 -94
  10. package/dist/index.d.ts +53 -94
  11. package/dist/index.js +237 -163
  12. package/dist/native/index.cjs +991 -0
  13. package/dist/native/index.d.cts +208 -0
  14. package/dist/native/index.d.ts +208 -0
  15. package/dist/native/index.js +968 -0
  16. package/dist/web-components.d.ts +303 -0
  17. package/dist/web-components.js +1968 -0
  18. package/package.json +29 -7
  19. package/src/components/interaction/Button/Button.module.css +14 -11
  20. package/src/components/interaction/Button/Button.native.spec.tsx +35 -0
  21. package/src/components/interaction/Button/Button.native.stories.tsx +42 -0
  22. package/src/components/interaction/Button/Button.native.tsx +95 -0
  23. package/src/components/interaction/Button/Button.stories.tsx +1 -1
  24. package/src/components/interaction/Button/Button.tsx +2 -2
  25. package/src/components/interaction/Command/Command.mdx +16 -0
  26. package/src/components/interaction/Command/Command.module.css +12 -12
  27. package/src/components/interaction/Command/Command.stories.tsx +1 -1
  28. package/src/components/interaction/Command/Command.tsx +2 -2
  29. package/src/components/interaction/Dialog/Dialog.module.css +3 -3
  30. package/src/components/interaction/Dialog/Dialog.stories.tsx +1 -1
  31. package/src/components/interaction/Dialog/Dialog.tsx +2 -2
  32. package/src/components/interaction/Drawer/Drawer.mdx +14 -0
  33. package/src/components/interaction/Drawer/Drawer.module.css +3 -3
  34. package/src/components/interaction/Drawer/Drawer.stories.tsx +1 -1
  35. package/src/components/interaction/Drawer/Drawer.tsx +2 -2
  36. package/src/components/interaction/DropdownMenu/DropdownMenu.module.css +3 -3
  37. package/src/components/interaction/DropdownMenu/DropdownMenu.stories.tsx +1 -1
  38. package/src/components/interaction/DropdownMenu/DropdownMenu.tsx +2 -2
  39. package/src/components/interaction/Popover/Popover.mdx +17 -0
  40. package/src/components/interaction/Popover/Popover.module.css +72 -15
  41. package/src/components/interaction/Popover/Popover.spec.tsx +68 -4
  42. package/src/components/interaction/Popover/Popover.stories.tsx +1 -1
  43. package/src/components/interaction/Popover/Popover.tsx +76 -20
  44. package/src/components/interaction/Rating/Rating.module.css +2 -2
  45. package/src/components/interaction/Rating/Rating.stories.tsx +1 -1
  46. package/src/components/interaction/Rating/Rating.tsx +2 -2
  47. package/src/components/interaction/Toast/Toast.module.css +16 -11
  48. package/src/components/interaction/Toast/Toast.spec.tsx +21 -0
  49. package/src/components/interaction/Toast/Toast.stories.tsx +1 -1
  50. package/src/components/interaction/Toast/Toast.tsx +22 -2
  51. package/src/components/interaction/form/Checkbox/Checkbox.mdx +2 -2
  52. package/src/components/interaction/form/Checkbox/Checkbox.module.css +5 -5
  53. package/src/components/interaction/form/Checkbox/Checkbox.native.spec.tsx +42 -0
  54. package/src/components/interaction/form/Checkbox/Checkbox.native.stories.tsx +36 -0
  55. package/src/components/interaction/form/Checkbox/Checkbox.native.tsx +80 -0
  56. package/src/components/interaction/form/Checkbox/Checkbox.stories.tsx +1 -1
  57. package/src/components/interaction/form/Checkbox/Checkbox.tsx +2 -2
  58. package/src/components/interaction/form/CheckboxGroup/CheckboxGroup.mdx +44 -0
  59. package/src/components/interaction/form/CheckboxGroup/CheckboxGroup.module.css +2 -2
  60. package/src/components/interaction/form/CheckboxGroup/CheckboxGroup.stories.tsx +1 -1
  61. package/src/components/interaction/form/CheckboxGroup/CheckboxGroup.tsx +2 -2
  62. package/src/components/interaction/form/Combobox/Combobox.mdx +21 -0
  63. package/src/components/interaction/form/Combobox/Combobox.module.css +8 -8
  64. package/src/components/interaction/form/Combobox/Combobox.stories.tsx +1 -1
  65. package/src/components/interaction/form/Combobox/Combobox.tsx +2 -2
  66. package/src/components/interaction/form/FileInput/FileInput.mdx +14 -0
  67. package/src/components/interaction/form/FileInput/FileInput.module.css +8 -8
  68. package/src/components/interaction/form/FileInput/FileInput.stories.tsx +1 -1
  69. package/src/components/interaction/form/FileInput/FileInput.tsx +2 -2
  70. package/src/components/interaction/form/FormInput/FormInput.module.css +2 -2
  71. package/src/components/interaction/form/FormInput/FormInput.stories.tsx +1 -1
  72. package/src/components/interaction/form/FormInput/FormInput.tsx +2 -2
  73. package/src/components/interaction/form/NumberInput/NumberInput.mdx +16 -0
  74. package/src/components/interaction/form/NumberInput/NumberInput.module.css +4 -4
  75. package/src/components/interaction/form/NumberInput/NumberInput.stories.tsx +1 -1
  76. package/src/components/interaction/form/NumberInput/NumberInput.tsx +2 -2
  77. package/src/components/interaction/form/Radio/Radio.mdx +3 -3
  78. package/src/components/interaction/form/Radio/Radio.module.css +6 -6
  79. package/src/components/interaction/form/Radio/Radio.native.stories.tsx +46 -0
  80. package/src/components/interaction/form/Radio/Radio.native.tsx +79 -0
  81. package/src/components/interaction/form/Radio/Radio.stories.tsx +1 -1
  82. package/src/components/interaction/form/Radio/Radio.tsx +2 -2
  83. package/src/components/interaction/form/RadioGroup/RadioGroup.mdx +45 -0
  84. package/src/components/interaction/form/RadioGroup/RadioGroup.module.css +2 -2
  85. package/src/components/interaction/form/RadioGroup/RadioGroup.stories.tsx +1 -1
  86. package/src/components/interaction/form/RadioGroup/RadioGroup.tsx +2 -2
  87. package/src/components/interaction/form/SegmentedControl/SegmentedControl.module.css +5 -5
  88. package/src/components/interaction/form/SegmentedControl/SegmentedControl.stories.tsx +1 -1
  89. package/src/components/interaction/form/SegmentedControl/SegmentedControl.tsx +2 -2
  90. package/src/components/interaction/form/Select/Select.module.css +3 -3
  91. package/src/components/interaction/form/Select/Select.stories.tsx +1 -1
  92. package/src/components/interaction/form/Select/Select.tsx +2 -2
  93. package/src/components/interaction/form/Slider/Slider.mdx +1 -1
  94. package/src/components/interaction/form/Slider/Slider.module.css +14 -14
  95. package/src/components/interaction/form/Slider/Slider.stories.tsx +1 -1
  96. package/src/components/interaction/form/Slider/Slider.tsx +2 -2
  97. package/src/components/interaction/form/Switch/Switch.mdx +4 -4
  98. package/src/components/interaction/form/Switch/Switch.module.css +8 -8
  99. package/src/components/interaction/form/Switch/Switch.native.spec.tsx +60 -0
  100. package/src/components/interaction/form/Switch/Switch.native.stories.tsx +35 -0
  101. package/src/components/interaction/form/Switch/Switch.native.tsx +59 -0
  102. package/src/components/interaction/form/Switch/Switch.stories.tsx +1 -1
  103. package/src/components/interaction/form/Switch/Switch.tsx +2 -2
  104. package/src/components/interaction/form/Textarea/Textarea.mdx +17 -0
  105. package/src/components/interaction/form/Textarea/Textarea.module.css +2 -2
  106. package/src/components/interaction/form/Textarea/Textarea.stories.tsx +1 -1
  107. package/src/components/interaction/form/Textarea/Textarea.tsx +2 -2
  108. package/src/components/interaction/form/atoms/InputContainer.tsx +2 -1
  109. package/src/components/interaction/form/atoms/Label.module.css +1 -1
  110. package/src/components/interaction/form/atoms/Label.native.stories.tsx +18 -0
  111. package/src/components/interaction/form/atoms/Label.native.tsx +29 -0
  112. package/src/components/interaction/form/atoms/Label.tsx +5 -3
  113. package/src/components/interaction/form/atoms/Message.native.spec.tsx +30 -0
  114. package/src/components/interaction/form/atoms/Message.native.stories.tsx +22 -0
  115. package/src/components/interaction/form/atoms/Message.native.tsx +34 -0
  116. package/src/components/interaction/form/atoms/Message.tsx +5 -3
  117. package/src/components/layout/ButtonGroup/ButtonGroup.native.stories.tsx +50 -0
  118. package/src/components/layout/ButtonGroup/ButtonGroup.native.tsx +34 -0
  119. package/src/components/layout/ButtonGroup/ButtonGroup.stories.tsx +1 -1
  120. package/src/components/layout/ButtonGroup/ButtonGroup.tsx +2 -2
  121. package/src/components/layout/Card/Card.module.css +2 -2
  122. package/src/components/layout/Card/Card.native.stories.tsx +53 -0
  123. package/src/components/layout/Card/Card.native.tsx +89 -0
  124. package/src/components/layout/Card/Card.stories.tsx +1 -1
  125. package/src/components/layout/Card/Card.tsx +2 -2
  126. package/src/components/layout/IconWrapper/IconWrapper.mdx +2 -2
  127. package/src/components/layout/IconWrapper/IconWrapper.module.css +3 -3
  128. package/src/components/layout/IconWrapper/IconWrapper.native.spec.tsx +39 -0
  129. package/src/components/layout/IconWrapper/IconWrapper.native.stories.tsx +41 -0
  130. package/src/components/layout/IconWrapper/IconWrapper.native.tsx +20 -0
  131. package/src/components/layout/IconWrapper/IconWrapper.stories.tsx +1 -1
  132. package/src/components/layout/IconWrapper/IconWrapper.tsx +2 -2
  133. package/src/components/layout/SectionHeader/SectionHeader.mdx +13 -0
  134. package/src/components/layout/SectionHeader/SectionHeader.module.css +2 -2
  135. package/src/components/layout/SectionHeader/SectionHeader.native.stories.tsx +38 -0
  136. package/src/components/layout/SectionHeader/SectionHeader.native.tsx +79 -0
  137. package/src/components/layout/SectionHeader/SectionHeader.stories.tsx +1 -1
  138. package/src/components/layout/SectionHeader/SectionHeader.tsx +2 -2
  139. package/src/components/ui/Accordion/Accordion.mdx +14 -0
  140. package/src/components/ui/Accordion/Accordion.module.css +5 -5
  141. package/src/components/ui/Accordion/Accordion.stories.tsx +1 -1
  142. package/src/components/ui/Accordion/Accordion.tsx +2 -2
  143. package/src/components/ui/Alert/Alert.module.css +15 -15
  144. package/src/components/ui/Alert/Alert.native.stories.tsx +43 -0
  145. package/src/components/ui/Alert/Alert.native.tsx +94 -0
  146. package/src/components/ui/Alert/Alert.stories.tsx +1 -1
  147. package/src/components/ui/Alert/Alert.tsx +2 -2
  148. package/src/components/ui/Avatar/Avatar.module.css +2 -2
  149. package/src/components/ui/Avatar/Avatar.native.spec.tsx +47 -0
  150. package/src/components/ui/Avatar/Avatar.native.stories.tsx +34 -0
  151. package/src/components/ui/Avatar/Avatar.native.tsx +85 -0
  152. package/src/components/ui/Avatar/Avatar.stories.tsx +1 -1
  153. package/src/components/ui/Avatar/Avatar.tsx +2 -2
  154. package/src/components/ui/Badge/Badge.mdx +2 -2
  155. package/src/components/ui/Badge/Badge.module.css +12 -12
  156. package/src/components/ui/Badge/Badge.native.stories.tsx +36 -0
  157. package/src/components/ui/Badge/Badge.native.tsx +50 -0
  158. package/src/components/ui/Badge/Badge.stories.tsx +1 -1
  159. package/src/components/ui/Badge/Badge.tsx +2 -2
  160. package/src/components/ui/Breadcrumb/Breadcrumb.module.css +2 -2
  161. package/src/components/ui/Breadcrumb/Breadcrumb.stories.tsx +1 -1
  162. package/src/components/ui/Breadcrumb/Breadcrumb.tsx +2 -2
  163. package/src/components/ui/Calendar/Calendar.mdx +16 -0
  164. package/src/components/ui/Calendar/Calendar.module.css +11 -11
  165. package/src/components/ui/Calendar/Calendar.stories.tsx +1 -1
  166. package/src/components/ui/Calendar/Calendar.tsx +2 -2
  167. package/src/components/ui/Carousel/Carousel.module.css +4 -4
  168. package/src/components/ui/Carousel/Carousel.stories.tsx +1 -1
  169. package/src/components/ui/Carousel/Carousel.tsx +2 -2
  170. package/src/components/ui/Collapsible/Collapsible.module.css +6 -6
  171. package/src/components/ui/Collapsible/Collapsible.stories.tsx +1 -1
  172. package/src/components/ui/Collapsible/Collapsible.tsx +2 -2
  173. package/src/components/ui/DescriptionList/DescriptionList.module.css +3 -3
  174. package/src/components/ui/DescriptionList/DescriptionList.stories.tsx +1 -1
  175. package/src/components/ui/DescriptionList/DescriptionList.tsx +2 -2
  176. package/src/components/ui/Link/Link.mdx +14 -0
  177. package/src/components/ui/Link/Link.module.css +4 -4
  178. package/src/components/ui/Link/Link.stories.tsx +1 -1
  179. package/src/components/ui/Link/Link.tsx +2 -2
  180. package/src/components/ui/Loading/Loading.module.css +2 -2
  181. package/src/components/ui/Loading/Loading.native.spec.tsx +24 -0
  182. package/src/components/ui/Loading/Loading.native.stories.tsx +33 -0
  183. package/src/components/ui/Loading/Loading.native.tsx +29 -0
  184. package/src/components/ui/Loading/Loading.stories.tsx +1 -1
  185. package/src/components/ui/Loading/Loading.tsx +2 -2
  186. package/src/components/ui/NotificationBanner/NotificationBanner.module.css +15 -15
  187. package/src/components/ui/NotificationBanner/NotificationBanner.native.stories.tsx +39 -0
  188. package/src/components/ui/NotificationBanner/NotificationBanner.native.tsx +76 -0
  189. package/src/components/ui/NotificationBanner/NotificationBanner.stories.tsx +1 -1
  190. package/src/components/ui/NotificationBanner/NotificationBanner.tsx +2 -2
  191. package/src/components/ui/Pagination/Pagination.module.css +8 -8
  192. package/src/components/ui/Pagination/Pagination.stories.tsx +1 -1
  193. package/src/components/ui/Pagination/Pagination.tsx +2 -2
  194. package/src/components/ui/Progress/Progress.mdx +1 -1
  195. package/src/components/ui/Progress/Progress.module.css +3 -3
  196. package/src/components/ui/Progress/Progress.native.stories.tsx +34 -0
  197. package/src/components/ui/Progress/Progress.native.tsx +84 -0
  198. package/src/components/ui/Progress/Progress.stories.tsx +1 -1
  199. package/src/components/ui/Progress/Progress.tsx +2 -2
  200. package/src/components/ui/ProgressCircle/ProgressCircle.module.css +3 -3
  201. package/src/components/ui/ProgressCircle/ProgressCircle.stories.tsx +1 -1
  202. package/src/components/ui/ProgressCircle/ProgressCircle.tsx +2 -2
  203. package/src/components/ui/Separator/Separator.mdx +14 -0
  204. package/src/components/ui/Separator/Separator.module.css +1 -1
  205. package/src/components/ui/Separator/Separator.native.stories.tsx +42 -0
  206. package/src/components/ui/Separator/Separator.native.tsx +32 -0
  207. package/src/components/ui/Separator/Separator.stories.tsx +1 -1
  208. package/src/components/ui/Separator/Separator.tsx +2 -2
  209. package/src/components/ui/Skeleton/Skeleton.module.css +3 -3
  210. package/src/components/ui/Skeleton/Skeleton.native.stories.tsx +33 -0
  211. package/src/components/ui/Skeleton/Skeleton.native.tsx +41 -0
  212. package/src/components/ui/Skeleton/Skeleton.stories.tsx +1 -1
  213. package/src/components/ui/Skeleton/Skeleton.tsx +2 -3
  214. package/src/components/ui/SkipLink/SkipLink.module.css +3 -3
  215. package/src/components/ui/SkipLink/SkipLink.stories.tsx +1 -1
  216. package/src/components/ui/SkipLink/SkipLink.tsx +5 -3
  217. package/src/components/ui/Table/Table.mdx +14 -0
  218. package/src/components/ui/Table/Table.module.css +11 -11
  219. package/src/components/ui/Table/Table.stories.tsx +1 -1
  220. package/src/components/ui/Table/Table.tsx +2 -2
  221. package/src/components/ui/Tabs/Tabs.module.css +3 -3
  222. package/src/components/ui/Tabs/Tabs.stories.tsx +1 -1
  223. package/src/components/ui/Tabs/Tabs.tsx +2 -2
  224. package/src/components/ui/Tooltip/Tooltip.mdx +14 -0
  225. package/src/components/ui/Tooltip/Tooltip.module.css +2 -2
  226. package/src/components/ui/Tooltip/Tooltip.stories.tsx +1 -1
  227. package/src/components/ui/Tooltip/Tooltip.tsx +2 -2
  228. package/src/components/ui/Typography/Typography.mdx +13 -0
  229. package/src/components/ui/Typography/Typography.module.css +1 -1
  230. package/src/components/ui/Typography/Typography.native.stories.tsx +38 -0
  231. package/src/components/ui/Typography/Typography.native.tsx +65 -0
  232. package/src/components/ui/Typography/Typography.stories.tsx +1 -1
  233. package/src/components/ui/Typography/Typography.tsx +2 -2
  234. package/src/css/bdc.css +10 -2
  235. package/src/index.ts +3 -0
  236. package/src/native/ThemeContext.tsx +28 -0
  237. package/src/native/tokens.ts +13 -0
  238. package/src/native.ts +39 -0
  239. package/src/react-augment.d.ts +13 -0
  240. package/src/stories/DesignSystem/Borders.mdx +7 -7
  241. package/src/stories/DesignSystem/Colors.mdx +28 -29
  242. package/src/stories/DesignSystem/DarkMode.mdx +130 -0
  243. package/src/stories/DesignSystem/Elevation.mdx +4 -4
  244. package/src/stories/DesignSystem/Grid.mdx +5 -5
  245. package/src/stories/DesignSystem/Motion.mdx +2 -2
  246. package/src/stories/DesignSystem/Overview.mdx +1 -1
  247. package/src/stories/DesignSystem/Spacing.mdx +3 -3
  248. package/src/stories/DesignSystem/Typography.mdx +6 -6
  249. package/src/types.ts +2 -0
  250. package/src/typings.d.ts +3 -0
  251. package/src/web-components/globals.ts +61 -0
  252. package/src/web-components/index.ts +12 -0
  253. package/src/web-components/interaction/BdsButton.stories.tsx +60 -0
  254. package/src/web-components/interaction/BdsPopover.stories.tsx +70 -0
  255. package/src/web-components/interaction/BdsToastProvider.stories.tsx +73 -0
  256. package/src/web-components/interaction/bds-button.spec.ts +95 -0
  257. package/src/web-components/interaction/bds-button.ts +293 -0
  258. package/src/web-components/interaction/bds-popover.spec.ts +126 -0
  259. package/src/web-components/interaction/bds-popover.ts +217 -0
  260. package/src/web-components/interaction/bds-toast-provider.spec.ts +122 -0
  261. package/src/web-components/interaction/bds-toast-provider.ts +211 -0
  262. package/src/web-components/test/helpers.ts +14 -0
  263. package/src/web-components/ui/BdsAlert.stories.tsx +60 -0
  264. package/src/web-components/ui/BdsBadge.stories.tsx +37 -0
  265. package/src/web-components/ui/bds-alert.spec.ts +109 -0
  266. package/src/web-components/ui/bds-alert.ts +209 -0
  267. package/src/web-components/ui/bds-badge.spec.ts +51 -0
  268. package/src/web-components/ui/bds-badge.ts +88 -0
@@ -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
+ }
@@ -2,7 +2,7 @@ import type { Meta, StoryObj } from '@storybook/react';
2
2
  import { Checkbox } from './Checkbox';
3
3
 
4
4
  const meta = {
5
- title: 'Form/Checkbox',
5
+ title: 'React/Form/Checkbox',
6
6
  component: Checkbox,
7
7
  } satisfies Meta<typeof Checkbox>;
8
8
 
@@ -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`
@@ -12,13 +12,13 @@
12
12
  font-family: var(--bds-font_family--body);
13
13
  font-size: var(--bds-font_size--body--s);
14
14
  font-weight: var(--bds-font_weight--medium);
15
- color: var(--bds-on-bg);
15
+ color: var(--bds-color_on-bg);
16
16
  padding: 0;
17
17
  margin-block-end: var(--bds-space_xs);
18
18
  }
19
19
 
20
20
  .required {
21
- color: var(--bds-error);
21
+ color: var(--bds-color_error);
22
22
  }
23
23
 
24
24
  .items {
@@ -3,7 +3,7 @@ import { Checkbox } from '../Checkbox';
3
3
  import { CheckboxGroup } from './CheckboxGroup';
4
4
 
5
5
  const meta = {
6
- title: 'Form/CheckboxGroup',
6
+ title: 'React/Form/CheckboxGroup',
7
7
  component: CheckboxGroup,
8
8
  } satisfies Meta<typeof CheckboxGroup>;
9
9
 
@@ -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`
@@ -25,8 +25,8 @@
25
25
  outline-offset: var(--bdc-outline_offset);
26
26
  border-radius: var(--combobox_radius, var(--bdc-outline_radius));
27
27
  box-shadow: var(--combobox_shadow, var(--bdc-outline_shadow));
28
- background-color: var(--combobox_color_bg, var(--bds-bg));
29
- color: var(--combobox_color, var(--bds-on-bg));
28
+ background-color: var(--combobox_color_bg, var(--bds-color_bg));
29
+ color: var(--combobox_color, var(--bds-color_on-bg));
30
30
  transition: --bdc_color var(--bds-animation_transition-duration) var(--bds-animation_easing),
31
31
  background-color var(--bds-animation_transition-duration) var(--bds-animation_easing);
32
32
  }
@@ -55,7 +55,7 @@
55
55
  display: flex;
56
56
  align-items: center;
57
57
  pointer-events: none;
58
- color: var(--combobox_color, var(--bds-on-bg));
58
+ color: var(--combobox_color, var(--bds-color_on-bg));
59
59
  }
60
60
 
61
61
  .chevron svg {
@@ -81,8 +81,8 @@
81
81
  outline: var(--bdc-outline_width) solid var(--bdc_color);
82
82
  outline-offset: var(--bdc-outline_offset);
83
83
  border-radius: var(--combobox_listbox-radius, var(--bdc-outline_radius));
84
- background-color: var(--combobox_color, var(--bds-bg));
85
- color: var(--combobox_on-color, var(--bds-on-bg));
84
+ background-color: var(--combobox_color, var(--bds-color_bg));
85
+ color: var(--combobox_on-color, var(--bds-color_on-bg));
86
86
  box-shadow: var(--combobox_listbox-shadow, var(--bds-shadow_m));
87
87
  }
88
88
 
@@ -91,14 +91,14 @@
91
91
  align-items: center;
92
92
  padding: var(--bds-space_xs) var(--bds-space_m);
93
93
  font-size: var(--bds-font_size--body);
94
- color: var(--combobox_color, var(--bds-on-bg));
94
+ color: var(--combobox_color, var(--bds-color_on-bg));
95
95
  cursor: pointer;
96
96
  transition: var(--bds-animation_transition);
97
97
  }
98
98
 
99
99
  .option.--highlighted {
100
- background-color: var(--bds-bg--subtle);
101
- color: var(--bds-interactive);
100
+ background-color: var(--bds-color_bg--subtle);
101
+ color: var(--bds-color_interactive_on-bg);
102
102
  }
103
103
 
104
104
  .option.--selected {
@@ -12,7 +12,7 @@ const options = [
12
12
  ];
13
13
 
14
14
  const meta = {
15
- title: 'Form/Combobox',
15
+ title: 'React/Form/Combobox',
16
16
  component: Combobox,
17
17
  } satisfies Meta<typeof Combobox>;
18
18
 
@@ -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
@@ -8,7 +8,7 @@
8
8
  display: flex;
9
9
  align-items: center;
10
10
  font-family: var(--bds-font_family--body);
11
- color: var(--bds-on-bg);
11
+ color: var(--bds-color_on-bg);
12
12
  margin-block-end: var(--bds-space_xs);
13
13
  }
14
14
 
@@ -21,7 +21,7 @@
21
21
  padding: var(--bds-space_l) var(--bds-space_m);
22
22
  border: 2px dashed currentcolor;
23
23
  border-radius: var(--bds-border_radius--s);
24
- color: var(--fileInput_color, var(--bds-on-bg));
24
+ color: var(--fileInput_color, var(--bds-color_on-bg));
25
25
  cursor: pointer;
26
26
  text-align: center;
27
27
  transition: var(--bds-animation_transition);
@@ -39,7 +39,7 @@
39
39
  }
40
40
 
41
41
  .hasError {
42
- border-color: var(--bds-error);
42
+ border-color: var(--bds-color_error);
43
43
  }
44
44
 
45
45
  .isDisabled {
@@ -55,17 +55,17 @@
55
55
 
56
56
  .prompt {
57
57
  font-size: var(--bds-font_size--body);
58
- color: var(--bds-on-bg);
58
+ color: var(--bds-color_on-bg);
59
59
  }
60
60
 
61
61
  .prompt strong {
62
- color: var(--bds-interactive);
62
+ color: var(--bds-color_interactive_on-bg);
63
63
  font-weight: var(--bds-font_weight--semibold);
64
64
  }
65
65
 
66
66
  .acceptHint {
67
67
  font-size: var(--bds-font_size--body--s);
68
- color: var(--bds-on-bg);
68
+ color: var(--bds-color_on-bg);
69
69
  }
70
70
 
71
71
  .hiddenInput {
@@ -80,8 +80,8 @@
80
80
 
81
81
  @media (hover: hover) and (pointer: fine) {
82
82
  .dropZone:not(.isDisabled):hover {
83
- border-color: var(--bds-interactive);
84
- background-color: rgb(from var(--bds-interactive) r g b / 4%);
83
+ border-color: var(--bds-color_interactive);
84
+ background-color: rgb(from var(--bds-color_interactive) r g b / 4%);
85
85
  }
86
86
  }
87
87
  }
@@ -2,7 +2,7 @@ import type { Meta, StoryObj } from '@storybook/react';
2
2
  import { FileInput } from './FileInput';
3
3
 
4
4
  const meta = {
5
- title: 'Form/FileInput',
5
+ title: 'React/Form/FileInput',
6
6
  component: FileInput,
7
7
  } satisfies Meta<typeof FileInput>;
8
8
 
@@ -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({
@@ -18,8 +18,8 @@
18
18
  outline-offset: var(--bdc-outline_offset);
19
19
  border-radius: var(--input_radius, var(--bdc-outline_radius));
20
20
  box-shadow: var(--input_shadow, var(--bdc-outline_shadow));
21
- color: var(--input_color, var(--bds-on-bg));
22
- background-color: var(--input_color_bg, var(--bds-bg));
21
+ color: var(--input_color, var(--bds-color_on-bg));
22
+ background-color: var(--input_color_bg, var(--bds-color_bg));
23
23
  transition: --bdc_color var(--bds-animation_transition-duration) var(--bds-animation_easing),
24
24
  background-color var(--bds-animation_transition-duration) var(--bds-animation_easing);
25
25
  }
@@ -2,7 +2,7 @@ import type { Meta, StoryObj } from '@storybook/react';
2
2
  import { FormInput } from './FormInput';
3
3
 
4
4
  const meta = {
5
- title: 'Form/FormInput',
5
+ title: 'React/Form/FormInput',
6
6
  component: FormInput,
7
7
  } satisfies Meta<typeof FormInput>;
8
8
 
@@ -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({
@@ -31,6 +31,22 @@ Numeric text input with increment/decrement stepper buttons. Enforces `min`, `ma
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>`--numberInput_color`</td><td>`var(--bds-color_on-bg)`</td><td>Text colour</td></tr>
43
+ <tr><td>`--numberInput_border`</td><td>`none`</td><td>Border</td></tr>
44
+ <tr><td>`--numberInput_radius`</td><td>`var(--bdc-outline_radius)`</td><td>Corner radius</td></tr>
45
+ <tr><td>`--numberInput_shadow`</td><td>`var(--bdc-outline_shadow)`</td><td>Box shadow</td></tr>
46
+ </tbody>
47
+ </table>
48
+
49
+
34
50
  ## Accessibility
35
51
 
36
52
  - Renders `<input type="number">` — browser-native spinner support
@@ -37,7 +37,7 @@
37
37
  text-align: center;
38
38
  padding: var(--bds-space_s);
39
39
  background: transparent;
40
- color: var(--numberInput_color, var(--bds-on-bg));
40
+ color: var(--numberInput_color, var(--bds-color_on-bg));
41
41
  min-width: 0;
42
42
  appearance: textfield;
43
43
  }
@@ -57,8 +57,8 @@
57
57
  align-items: center;
58
58
  justify-content: center;
59
59
  padding: var(--bds-space_xs);
60
- background-color: var(--bds-bg--subtle);
61
- color: var(--numberInput_color, var(--bds-on-bg));
60
+ background-color: var(--bds-color_bg--subtle);
61
+ color: var(--numberInput_color, var(--bds-color_on-bg));
62
62
  cursor: pointer;
63
63
  transition: var(--bds-animation_transition);
64
64
  flex-shrink: 0;
@@ -76,7 +76,7 @@
76
76
 
77
77
  @media (hover: hover) and (pointer: fine) {
78
78
  .stepper:not(:disabled):hover {
79
- background-color: var(--bds-bg--subtle);
79
+ background-color: var(--bds-color_bg--subtle);
80
80
  opacity: 0.7;
81
81
  }
82
82
  }
@@ -2,7 +2,7 @@ import type { Meta, StoryObj } from '@storybook/react';
2
2
  import { NumberInput } from './NumberInput';
3
3
 
4
4
  const meta = {
5
- title: 'Form/NumberInput',
5
+ title: 'React/Form/NumberInput',
6
6
  component: NumberInput,
7
7
  } satisfies Meta<typeof NumberInput>;
8
8
 
@@ -4,8 +4,9 @@ import {Label} from '../atoms/Label';
4
4
  import {Message} from '../atoms/Message';
5
5
  import {InputContainer} from '../atoms/InputContainer';
6
6
  import {cn} from '@boostdev/design-system-foundation';
7
+ import type { WithClassName } from '../../../../types';
7
8
 
8
- interface NumberInputProps {
9
+ interface NumberInputProps extends WithClassName {
9
10
  label: string;
10
11
  name: string;
11
12
  value?: number;
@@ -17,7 +18,6 @@ interface NumberInputProps {
17
18
  error?: string;
18
19
  hint?: string;
19
20
  onChange?: (value: number) => void;
20
- className?: string;
21
21
  }
22
22
 
23
23
  export function NumberInput({
@@ -46,9 +46,9 @@ Single-select option within a group. Renders a styled native `<input type="radio
46
46
  <tr><th>Variable</th><th>Default</th><th>Description</th></tr>
47
47
  </thead>
48
48
  <tbody>
49
- <tr><td>`--radio_color-active`</td><td>`var(--bds-active)`</td><td>Selected fill and border colour</td></tr>
50
- <tr><td>`--radio_color-on-active`</td><td>`var(--bds-on-active)`</td><td>Inner dot colour</td></tr>
51
- <tr><td>`--radio_description-color`</td><td>`var(--bds-on-bg--subtle)`</td><td>Description text colour</td></tr>
49
+ <tr><td>`--radio_color-active`</td><td>`var(--bdc-color_active)`</td><td>Selected fill and border colour</td></tr>
50
+ <tr><td>`--radio_color-on-active`</td><td>`var(--bdc-color_on-active)`</td><td>Inner dot colour</td></tr>
51
+ <tr><td>`--radio_description-color`</td><td>`var(--bds-color_on-bg--subtle)`</td><td>Description text colour</td></tr>
52
52
  </tbody>
53
53
  </table>
54
54