@boostdev/design-system-components 1.0.3 → 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 (225) hide show
  1. package/AGENTS.md +5 -5
  2. package/dist/client.cjs +236 -153
  3. package/dist/client.css +547 -483
  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 +547 -483
  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 +27 -5
  19. package/src/components/interaction/Button/Button.module.css +10 -7
  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.stories.tsx +1 -1
  27. package/src/components/interaction/Command/Command.tsx +2 -2
  28. package/src/components/interaction/Dialog/Dialog.stories.tsx +1 -1
  29. package/src/components/interaction/Dialog/Dialog.tsx +2 -2
  30. package/src/components/interaction/Drawer/Drawer.mdx +14 -0
  31. package/src/components/interaction/Drawer/Drawer.stories.tsx +1 -1
  32. package/src/components/interaction/Drawer/Drawer.tsx +2 -2
  33. package/src/components/interaction/DropdownMenu/DropdownMenu.stories.tsx +1 -1
  34. package/src/components/interaction/DropdownMenu/DropdownMenu.tsx +2 -2
  35. package/src/components/interaction/Popover/Popover.mdx +17 -0
  36. package/src/components/interaction/Popover/Popover.module.css +70 -13
  37. package/src/components/interaction/Popover/Popover.spec.tsx +68 -4
  38. package/src/components/interaction/Popover/Popover.stories.tsx +1 -1
  39. package/src/components/interaction/Popover/Popover.tsx +76 -20
  40. package/src/components/interaction/Rating/Rating.stories.tsx +1 -1
  41. package/src/components/interaction/Rating/Rating.tsx +2 -2
  42. package/src/components/interaction/Toast/Toast.module.css +6 -1
  43. package/src/components/interaction/Toast/Toast.spec.tsx +21 -0
  44. package/src/components/interaction/Toast/Toast.stories.tsx +1 -1
  45. package/src/components/interaction/Toast/Toast.tsx +22 -2
  46. package/src/components/interaction/form/Checkbox/Checkbox.mdx +2 -2
  47. package/src/components/interaction/form/Checkbox/Checkbox.module.css +3 -3
  48. package/src/components/interaction/form/Checkbox/Checkbox.native.spec.tsx +42 -0
  49. package/src/components/interaction/form/Checkbox/Checkbox.native.stories.tsx +36 -0
  50. package/src/components/interaction/form/Checkbox/Checkbox.native.tsx +80 -0
  51. package/src/components/interaction/form/Checkbox/Checkbox.stories.tsx +1 -1
  52. package/src/components/interaction/form/Checkbox/Checkbox.tsx +2 -2
  53. package/src/components/interaction/form/CheckboxGroup/CheckboxGroup.mdx +44 -0
  54. package/src/components/interaction/form/CheckboxGroup/CheckboxGroup.stories.tsx +1 -1
  55. package/src/components/interaction/form/CheckboxGroup/CheckboxGroup.tsx +2 -2
  56. package/src/components/interaction/form/Combobox/Combobox.mdx +21 -0
  57. package/src/components/interaction/form/Combobox/Combobox.module.css +1 -1
  58. package/src/components/interaction/form/Combobox/Combobox.stories.tsx +1 -1
  59. package/src/components/interaction/form/Combobox/Combobox.tsx +2 -2
  60. package/src/components/interaction/form/FileInput/FileInput.mdx +14 -0
  61. package/src/components/interaction/form/FileInput/FileInput.module.css +1 -1
  62. package/src/components/interaction/form/FileInput/FileInput.stories.tsx +1 -1
  63. package/src/components/interaction/form/FileInput/FileInput.tsx +2 -2
  64. package/src/components/interaction/form/FormInput/FormInput.stories.tsx +1 -1
  65. package/src/components/interaction/form/FormInput/FormInput.tsx +2 -2
  66. package/src/components/interaction/form/NumberInput/NumberInput.mdx +16 -0
  67. package/src/components/interaction/form/NumberInput/NumberInput.stories.tsx +1 -1
  68. package/src/components/interaction/form/NumberInput/NumberInput.tsx +2 -2
  69. package/src/components/interaction/form/Radio/Radio.mdx +3 -3
  70. package/src/components/interaction/form/Radio/Radio.module.css +3 -3
  71. package/src/components/interaction/form/Radio/Radio.native.stories.tsx +46 -0
  72. package/src/components/interaction/form/Radio/Radio.native.tsx +79 -0
  73. package/src/components/interaction/form/Radio/Radio.stories.tsx +1 -1
  74. package/src/components/interaction/form/Radio/Radio.tsx +2 -2
  75. package/src/components/interaction/form/RadioGroup/RadioGroup.mdx +45 -0
  76. package/src/components/interaction/form/RadioGroup/RadioGroup.stories.tsx +1 -1
  77. package/src/components/interaction/form/RadioGroup/RadioGroup.tsx +2 -2
  78. package/src/components/interaction/form/SegmentedControl/SegmentedControl.stories.tsx +1 -1
  79. package/src/components/interaction/form/SegmentedControl/SegmentedControl.tsx +2 -2
  80. package/src/components/interaction/form/Select/Select.stories.tsx +1 -1
  81. package/src/components/interaction/form/Select/Select.tsx +2 -2
  82. package/src/components/interaction/form/Slider/Slider.mdx +1 -1
  83. package/src/components/interaction/form/Slider/Slider.module.css +4 -4
  84. package/src/components/interaction/form/Slider/Slider.stories.tsx +1 -1
  85. package/src/components/interaction/form/Slider/Slider.tsx +2 -2
  86. package/src/components/interaction/form/Switch/Switch.mdx +4 -4
  87. package/src/components/interaction/form/Switch/Switch.module.css +3 -3
  88. package/src/components/interaction/form/Switch/Switch.native.spec.tsx +60 -0
  89. package/src/components/interaction/form/Switch/Switch.native.stories.tsx +35 -0
  90. package/src/components/interaction/form/Switch/Switch.native.tsx +59 -0
  91. package/src/components/interaction/form/Switch/Switch.stories.tsx +1 -1
  92. package/src/components/interaction/form/Switch/Switch.tsx +2 -2
  93. package/src/components/interaction/form/Textarea/Textarea.mdx +17 -0
  94. package/src/components/interaction/form/Textarea/Textarea.stories.tsx +1 -1
  95. package/src/components/interaction/form/Textarea/Textarea.tsx +2 -2
  96. package/src/components/interaction/form/atoms/InputContainer.tsx +2 -1
  97. package/src/components/interaction/form/atoms/Label.native.stories.tsx +18 -0
  98. package/src/components/interaction/form/atoms/Label.native.tsx +29 -0
  99. package/src/components/interaction/form/atoms/Label.tsx +5 -3
  100. package/src/components/interaction/form/atoms/Message.native.spec.tsx +30 -0
  101. package/src/components/interaction/form/atoms/Message.native.stories.tsx +22 -0
  102. package/src/components/interaction/form/atoms/Message.native.tsx +34 -0
  103. package/src/components/interaction/form/atoms/Message.tsx +5 -3
  104. package/src/components/layout/ButtonGroup/ButtonGroup.native.stories.tsx +50 -0
  105. package/src/components/layout/ButtonGroup/ButtonGroup.native.tsx +34 -0
  106. package/src/components/layout/ButtonGroup/ButtonGroup.stories.tsx +1 -1
  107. package/src/components/layout/ButtonGroup/ButtonGroup.tsx +2 -2
  108. package/src/components/layout/Card/Card.native.stories.tsx +53 -0
  109. package/src/components/layout/Card/Card.native.tsx +89 -0
  110. package/src/components/layout/Card/Card.stories.tsx +1 -1
  111. package/src/components/layout/Card/Card.tsx +2 -2
  112. package/src/components/layout/IconWrapper/IconWrapper.mdx +2 -2
  113. package/src/components/layout/IconWrapper/IconWrapper.native.spec.tsx +39 -0
  114. package/src/components/layout/IconWrapper/IconWrapper.native.stories.tsx +41 -0
  115. package/src/components/layout/IconWrapper/IconWrapper.native.tsx +20 -0
  116. package/src/components/layout/IconWrapper/IconWrapper.stories.tsx +1 -1
  117. package/src/components/layout/IconWrapper/IconWrapper.tsx +2 -2
  118. package/src/components/layout/SectionHeader/SectionHeader.mdx +13 -0
  119. package/src/components/layout/SectionHeader/SectionHeader.native.stories.tsx +38 -0
  120. package/src/components/layout/SectionHeader/SectionHeader.native.tsx +79 -0
  121. package/src/components/layout/SectionHeader/SectionHeader.stories.tsx +1 -1
  122. package/src/components/layout/SectionHeader/SectionHeader.tsx +2 -2
  123. package/src/components/ui/Accordion/Accordion.mdx +14 -0
  124. package/src/components/ui/Accordion/Accordion.stories.tsx +1 -1
  125. package/src/components/ui/Accordion/Accordion.tsx +2 -2
  126. package/src/components/ui/Alert/Alert.native.stories.tsx +43 -0
  127. package/src/components/ui/Alert/Alert.native.tsx +94 -0
  128. package/src/components/ui/Alert/Alert.stories.tsx +1 -1
  129. package/src/components/ui/Alert/Alert.tsx +2 -2
  130. package/src/components/ui/Avatar/Avatar.native.spec.tsx +47 -0
  131. package/src/components/ui/Avatar/Avatar.native.stories.tsx +34 -0
  132. package/src/components/ui/Avatar/Avatar.native.tsx +85 -0
  133. package/src/components/ui/Avatar/Avatar.stories.tsx +1 -1
  134. package/src/components/ui/Avatar/Avatar.tsx +2 -2
  135. package/src/components/ui/Badge/Badge.mdx +2 -2
  136. package/src/components/ui/Badge/Badge.native.stories.tsx +36 -0
  137. package/src/components/ui/Badge/Badge.native.tsx +50 -0
  138. package/src/components/ui/Badge/Badge.stories.tsx +1 -1
  139. package/src/components/ui/Badge/Badge.tsx +2 -2
  140. package/src/components/ui/Breadcrumb/Breadcrumb.stories.tsx +1 -1
  141. package/src/components/ui/Breadcrumb/Breadcrumb.tsx +2 -2
  142. package/src/components/ui/Calendar/Calendar.mdx +16 -0
  143. package/src/components/ui/Calendar/Calendar.stories.tsx +1 -1
  144. package/src/components/ui/Calendar/Calendar.tsx +2 -2
  145. package/src/components/ui/Carousel/Carousel.stories.tsx +1 -1
  146. package/src/components/ui/Carousel/Carousel.tsx +2 -2
  147. package/src/components/ui/Collapsible/Collapsible.stories.tsx +1 -1
  148. package/src/components/ui/Collapsible/Collapsible.tsx +2 -2
  149. package/src/components/ui/DescriptionList/DescriptionList.stories.tsx +1 -1
  150. package/src/components/ui/DescriptionList/DescriptionList.tsx +2 -2
  151. package/src/components/ui/Link/Link.mdx +14 -0
  152. package/src/components/ui/Link/Link.stories.tsx +1 -1
  153. package/src/components/ui/Link/Link.tsx +2 -2
  154. package/src/components/ui/Loading/Loading.native.spec.tsx +24 -0
  155. package/src/components/ui/Loading/Loading.native.stories.tsx +33 -0
  156. package/src/components/ui/Loading/Loading.native.tsx +29 -0
  157. package/src/components/ui/Loading/Loading.stories.tsx +1 -1
  158. package/src/components/ui/Loading/Loading.tsx +2 -2
  159. package/src/components/ui/NotificationBanner/NotificationBanner.native.stories.tsx +39 -0
  160. package/src/components/ui/NotificationBanner/NotificationBanner.native.tsx +76 -0
  161. package/src/components/ui/NotificationBanner/NotificationBanner.stories.tsx +1 -1
  162. package/src/components/ui/NotificationBanner/NotificationBanner.tsx +2 -2
  163. package/src/components/ui/Pagination/Pagination.module.css +1 -1
  164. package/src/components/ui/Pagination/Pagination.stories.tsx +1 -1
  165. package/src/components/ui/Pagination/Pagination.tsx +2 -2
  166. package/src/components/ui/Progress/Progress.mdx +1 -1
  167. package/src/components/ui/Progress/Progress.module.css +1 -1
  168. package/src/components/ui/Progress/Progress.native.stories.tsx +34 -0
  169. package/src/components/ui/Progress/Progress.native.tsx +84 -0
  170. package/src/components/ui/Progress/Progress.stories.tsx +1 -1
  171. package/src/components/ui/Progress/Progress.tsx +2 -2
  172. package/src/components/ui/ProgressCircle/ProgressCircle.module.css +1 -1
  173. package/src/components/ui/ProgressCircle/ProgressCircle.stories.tsx +1 -1
  174. package/src/components/ui/ProgressCircle/ProgressCircle.tsx +2 -2
  175. package/src/components/ui/Separator/Separator.mdx +14 -0
  176. package/src/components/ui/Separator/Separator.native.stories.tsx +42 -0
  177. package/src/components/ui/Separator/Separator.native.tsx +32 -0
  178. package/src/components/ui/Separator/Separator.stories.tsx +1 -1
  179. package/src/components/ui/Separator/Separator.tsx +2 -2
  180. package/src/components/ui/Skeleton/Skeleton.native.stories.tsx +33 -0
  181. package/src/components/ui/Skeleton/Skeleton.native.tsx +41 -0
  182. package/src/components/ui/Skeleton/Skeleton.stories.tsx +1 -1
  183. package/src/components/ui/Skeleton/Skeleton.tsx +2 -3
  184. package/src/components/ui/SkipLink/SkipLink.stories.tsx +1 -1
  185. package/src/components/ui/SkipLink/SkipLink.tsx +5 -3
  186. package/src/components/ui/Table/Table.mdx +14 -0
  187. package/src/components/ui/Table/Table.stories.tsx +1 -1
  188. package/src/components/ui/Table/Table.tsx +2 -2
  189. package/src/components/ui/Tabs/Tabs.stories.tsx +1 -1
  190. package/src/components/ui/Tabs/Tabs.tsx +2 -2
  191. package/src/components/ui/Tooltip/Tooltip.mdx +14 -0
  192. package/src/components/ui/Tooltip/Tooltip.stories.tsx +1 -1
  193. package/src/components/ui/Tooltip/Tooltip.tsx +2 -2
  194. package/src/components/ui/Typography/Typography.mdx +13 -0
  195. package/src/components/ui/Typography/Typography.native.stories.tsx +38 -0
  196. package/src/components/ui/Typography/Typography.native.tsx +65 -0
  197. package/src/components/ui/Typography/Typography.stories.tsx +1 -1
  198. package/src/components/ui/Typography/Typography.tsx +2 -2
  199. package/src/css/bdc.css +8 -0
  200. package/src/index.ts +1 -0
  201. package/src/native/ThemeContext.tsx +28 -0
  202. package/src/native/tokens.ts +13 -0
  203. package/src/native.ts +39 -0
  204. package/src/react-augment.d.ts +13 -0
  205. package/src/stories/DesignSystem/DarkMode.mdx +130 -0
  206. package/src/types.ts +2 -0
  207. package/src/typings.d.ts +3 -0
  208. package/src/web-components/globals.ts +61 -0
  209. package/src/web-components/index.ts +12 -0
  210. package/src/web-components/interaction/BdsButton.stories.tsx +60 -0
  211. package/src/web-components/interaction/BdsPopover.stories.tsx +70 -0
  212. package/src/web-components/interaction/BdsToastProvider.stories.tsx +73 -0
  213. package/src/web-components/interaction/bds-button.spec.ts +95 -0
  214. package/src/web-components/interaction/bds-button.ts +293 -0
  215. package/src/web-components/interaction/bds-popover.spec.ts +126 -0
  216. package/src/web-components/interaction/bds-popover.ts +217 -0
  217. package/src/web-components/interaction/bds-toast-provider.spec.ts +122 -0
  218. package/src/web-components/interaction/bds-toast-provider.ts +211 -0
  219. package/src/web-components/test/helpers.ts +14 -0
  220. package/src/web-components/ui/BdsAlert.stories.tsx +60 -0
  221. package/src/web-components/ui/BdsBadge.stories.tsx +37 -0
  222. package/src/web-components/ui/bds-alert.spec.ts +109 -0
  223. package/src/web-components/ui/bds-alert.ts +209 -0
  224. package/src/web-components/ui/bds-badge.spec.ts +51 -0
  225. package/src/web-components/ui/bds-badge.ts +88 -0
@@ -0,0 +1,39 @@
1
+ import React from 'react';
2
+ import type { Meta, StoryObj } from '@storybook/react';
3
+ import { ThemeProvider } from '../../../native/ThemeContext';
4
+ import { NotificationBanner } from './NotificationBanner.native';
5
+
6
+ const meta = {
7
+ tags: ['!stable', 'alpha'],
8
+ title: 'React Native/UI/NotificationBanner',
9
+ component: NotificationBanner,
10
+ decorators: [(Story) => <ThemeProvider><Story /></ThemeProvider>],
11
+ parameters: { layout: 'padded' },
12
+ argTypes: {
13
+ variant: { control: 'select', options: ['info', 'success', 'warning', 'error'] },
14
+ },
15
+ } satisfies Meta<typeof NotificationBanner>;
16
+
17
+ export default meta;
18
+ type Story = StoryObj<typeof meta>;
19
+
20
+ export const Info: Story = { args: { children: 'New update available.', variant: 'info' } };
21
+ export const Success: Story = { args: { children: 'Changes saved successfully.', variant: 'success' } };
22
+ export const Warning: Story = { args: { children: 'Your session will expire soon.', variant: 'warning' } };
23
+ export const Error: Story = { args: { children: 'Failed to load data. Please retry.', variant: 'error' } };
24
+ export const Dismissible: Story = {
25
+ args: { children: 'You can dismiss this notification.', variant: 'info', onDismiss: () => {} },
26
+ };
27
+ export const AllVariants: Story = {
28
+ render: () => (
29
+ <ThemeProvider>
30
+ <div style={{ display: 'flex', flexDirection: 'column', gap: '8px' }}>
31
+ {(['info', 'success', 'warning', 'error'] as const).map(v => (
32
+ <NotificationBanner key={v} variant={v}>
33
+ {v.charAt(0).toUpperCase() + v.slice(1)} notification
34
+ </NotificationBanner>
35
+ ))}
36
+ </div>
37
+ </ThemeProvider>
38
+ ),
39
+ };
@@ -0,0 +1,76 @@
1
+ import { ReactNode } from 'react';
2
+ import { StyleSheet, View, Text, Pressable, StyleProp, ViewStyle } from 'react-native';
3
+ import { spacing, font, lineHeight } from '../../../native/tokens';
4
+ import { useTheme } from '../../../native/ThemeContext';
5
+
6
+ type BannerVariant = 'info' | 'success' | 'warning' | 'error';
7
+
8
+ interface NotificationBannerProps {
9
+ variant?: BannerVariant;
10
+ children: ReactNode;
11
+ action?: ReactNode;
12
+ onDismiss?: () => void;
13
+ style?: StyleProp<ViewStyle>;
14
+ }
15
+
16
+ const styles = StyleSheet.create({
17
+ banner: {
18
+ flexDirection: 'row',
19
+ alignItems: 'center',
20
+ paddingVertical: spacing.s,
21
+ paddingHorizontal: spacing.m,
22
+ gap: spacing.xs,
23
+ },
24
+ content: {
25
+ flex: 1,
26
+ fontSize: font.size.bodyS,
27
+ fontFamily: font.family.body,
28
+ lineHeight: lineHeight.bodyS,
29
+ },
30
+ dismiss: {
31
+ padding: spacing.xxs,
32
+ flexShrink: 0,
33
+ },
34
+ });
35
+
36
+ export function NotificationBanner({
37
+ variant = 'info',
38
+ children,
39
+ action,
40
+ onDismiss,
41
+ style,
42
+ }: Readonly<NotificationBannerProps>) {
43
+ const { colors } = useTheme();
44
+ const isUrgent = variant === 'error' || variant === 'warning';
45
+
46
+ const variantColors: Record<BannerVariant, { bg: string; text: string }> = {
47
+ info: { bg: colors.colorBlueSubtle, text: colors.colorOnBlueSubtle },
48
+ success: { bg: colors.colorSuccessSubtle, text: colors.colorOnSuccessSubtle },
49
+ warning: { bg: colors.colorOrangeSubtle, text: colors.colorOnOrangeSubtle },
50
+ error: { bg: colors.colorRedSubtle, text: colors.colorOnRedSubtle },
51
+ };
52
+
53
+ const { bg, text } = variantColors[variant];
54
+
55
+ return (
56
+ <View
57
+ accessibilityRole={isUrgent ? 'alert' : 'none'}
58
+ accessibilityLiveRegion={isUrgent ? 'assertive' : 'polite'}
59
+ style={[styles.banner, { backgroundColor: bg }, style]}
60
+ >
61
+ <Text style={[styles.content, { color: text }]}>{children}</Text>
62
+ {action}
63
+ {onDismiss && (
64
+ <Pressable
65
+ onPress={onDismiss}
66
+ style={styles.dismiss}
67
+ accessibilityLabel="Dismiss notification"
68
+ accessibilityRole="button"
69
+ hitSlop={8}
70
+ >
71
+ <Text style={{ color: text, fontSize: 16 }}>✕</Text>
72
+ </Pressable>
73
+ )}
74
+ </View>
75
+ );
76
+ }
@@ -3,7 +3,7 @@ import { NotificationBanner } from './NotificationBanner';
3
3
  import { Button } from '../../interaction/Button/Button';
4
4
 
5
5
  const meta = {
6
- title: 'UI/NotificationBanner',
6
+ title: 'React/UI/NotificationBanner',
7
7
  component: NotificationBanner,
8
8
  } satisfies Meta<typeof NotificationBanner>;
9
9
 
@@ -1,13 +1,13 @@
1
1
  import { ReactNode } from 'react';
2
2
  import css from './NotificationBanner.module.css';
3
3
  import { cn } from '@boostdev/design-system-foundation';
4
+ import type { WithClassName } from '../../../types';
4
5
 
5
- interface NotificationBannerProps {
6
+ interface NotificationBannerProps extends WithClassName {
6
7
  variant?: 'info' | 'success' | 'warning' | 'error';
7
8
  children: ReactNode;
8
9
  action?: ReactNode;
9
10
  onDismiss?: () => void;
10
- className?: string;
11
11
  }
12
12
 
13
13
  export function NotificationBanner({
@@ -51,7 +51,7 @@
51
51
  @media (hover: hover) and (pointer: fine) {
52
52
  .button:not(:disabled, .--active):hover {
53
53
  --btn_bg: var(--bds-color_bg--subtle);
54
- --btn_color: var(--bds-color_interactive);
54
+ --btn_color: var(--bds-color_interactive_on-bg);
55
55
  }
56
56
  }
57
57
 
@@ -3,7 +3,7 @@ import { useState } from 'react';
3
3
  import { Pagination } from './Pagination';
4
4
 
5
5
  const meta = {
6
- title: 'UI/Pagination',
6
+ title: 'React/UI/Pagination',
7
7
  component: Pagination,
8
8
  } satisfies Meta<typeof Pagination>;
9
9
 
@@ -1,11 +1,11 @@
1
1
  import css from './Pagination.module.css';
2
2
  import { cn } from '@boostdev/design-system-foundation';
3
+ import type { WithClassName } from '../../../types';
3
4
 
4
- interface PaginationProps {
5
+ interface PaginationProps extends WithClassName {
5
6
  currentPage: number;
6
7
  totalPages: number;
7
8
  onPageChange: (page: number) => void;
8
- className?: string;
9
9
  }
10
10
 
11
11
  function getPageRange(current: number, total: number): (number | '...')[] {
@@ -40,7 +40,7 @@ Horizontal progress bar communicating completion towards a goal.
40
40
  <tr><th>Variable</th><th>Description</th></tr>
41
41
  </thead>
42
42
  <tbody>
43
- <tr><td>`--progress_color-active`</td><td>Filled track colour (defaults to `var(--bds-active)`)</td></tr>
43
+ <tr><td>`--progress_color-active`</td><td>Filled track colour (defaults to `var(--bdc-color_active)`)</td></tr>
44
44
  <tr><td>`--progress_color-track`</td><td>Empty track colour</td></tr>
45
45
  </tbody>
46
46
  </table>
@@ -32,7 +32,7 @@
32
32
 
33
33
  .fill {
34
34
  height: 100%;
35
- background-color: var(--progress_color-active, var(--bds-color_green));
35
+ background-color: var(--progress_color-active, var(--bdc-color_active));
36
36
  border-radius: 999px;
37
37
  transition: width var(--bds-animation_transition-duration) var(--bds-animation_easing);
38
38
  }
@@ -0,0 +1,34 @@
1
+ import React from 'react';
2
+ import type { Meta, StoryObj } from '@storybook/react';
3
+ import { ThemeProvider } from '../../../native/ThemeContext';
4
+ import { Progress } from './Progress.native';
5
+
6
+ const meta = {
7
+ tags: ['!stable', 'alpha'],
8
+ title: 'React Native/UI/Progress',
9
+ component: Progress,
10
+ decorators: [
11
+ (Story) => (
12
+ <ThemeProvider>
13
+ <div style={{ width: 300 }}>
14
+ <Story />
15
+ </div>
16
+ </ThemeProvider>
17
+ ),
18
+ ],
19
+ parameters: { layout: 'padded' },
20
+ argTypes: {
21
+ size: { control: 'select', options: ['small', 'medium', 'large'] },
22
+ value: { control: { type: 'range', min: 0, max: 100, step: 1 } },
23
+ },
24
+ } satisfies Meta<typeof Progress>;
25
+
26
+ export default meta;
27
+ type Story = StoryObj<typeof meta>;
28
+
29
+ export const Default: Story = { args: { value: 60, label: 'Progress' } };
30
+ export const WithLabel: Story = { args: { value: 40, label: 'Loading', showLabel: true } };
31
+ export const Small: Story = { args: { value: 70, label: 'Small progress', size: 'small' } };
32
+ export const Large: Story = { args: { value: 50, label: 'Large progress', size: 'large', showLabel: true } };
33
+ export const Complete: Story = { args: { value: 100, label: 'Complete', showLabel: true } };
34
+ export const Empty: Story = { args: { value: 0, label: 'Not started', showLabel: true } };
@@ -0,0 +1,84 @@
1
+ import { StyleSheet, View, Text, StyleProp, ViewStyle } from 'react-native';
2
+ import { spacing, font, border, lineHeight } from '../../../native/tokens';
3
+ import { useTheme } from '../../../native/ThemeContext';
4
+
5
+ type ProgressSize = 'small' | 'medium' | 'large';
6
+
7
+ interface ProgressProps {
8
+ value: number;
9
+ max?: number;
10
+ label: string;
11
+ showLabel?: boolean;
12
+ size?: ProgressSize;
13
+ style?: StyleProp<ViewStyle>;
14
+ }
15
+
16
+ const trackHeight: Record<ProgressSize, number> = {
17
+ small: 4,
18
+ medium: 8,
19
+ large: 12,
20
+ };
21
+
22
+ const styles = StyleSheet.create({
23
+ container: {
24
+ width: '100%',
25
+ },
26
+ labelRow: {
27
+ flexDirection: 'row',
28
+ justifyContent: 'space-between',
29
+ marginBottom: spacing.xxs,
30
+ },
31
+ labelText: {
32
+ fontSize: font.size.bodyS,
33
+ fontFamily: font.family.body,
34
+ lineHeight: lineHeight.bodyS,
35
+ },
36
+ track: {
37
+ width: '100%',
38
+ borderRadius: border.radius.xs,
39
+ overflow: 'hidden',
40
+ },
41
+ fill: {
42
+ height: '100%',
43
+ borderRadius: border.radius.xs,
44
+ },
45
+ });
46
+
47
+ export function Progress({
48
+ value,
49
+ max = 100,
50
+ label,
51
+ showLabel = false,
52
+ size = 'medium',
53
+ style,
54
+ }: Readonly<ProgressProps>) {
55
+ const { colors } = useTheme();
56
+ const percentage = Math.min(100, Math.max(0, (value / max) * 100));
57
+ const height = trackHeight[size];
58
+
59
+ return (
60
+ <View style={[styles.container, style]}>
61
+ {showLabel && (
62
+ <View style={styles.labelRow}>
63
+ <Text style={[styles.labelText, { color: colors.colorOnBg }]}>{label}</Text>
64
+ <Text style={[styles.labelText, { color: colors.colorOnBgSubtle }]}>
65
+ {Math.round(percentage)}%
66
+ </Text>
67
+ </View>
68
+ )}
69
+ <View
70
+ style={[styles.track, { height, backgroundColor: colors.colorBgSubtle }]}
71
+ accessibilityRole="progressbar"
72
+ accessibilityLabel={label}
73
+ accessibilityValue={{ min: 0, max, now: value }}
74
+ >
75
+ <View
76
+ style={[
77
+ styles.fill,
78
+ { width: `${percentage}%`, backgroundColor: colors.colorInteractive },
79
+ ]}
80
+ />
81
+ </View>
82
+ </View>
83
+ );
84
+ }
@@ -2,7 +2,7 @@ import type { Meta, StoryObj } from '@storybook/react';
2
2
  import { Progress } from './Progress';
3
3
 
4
4
  const meta = {
5
- title: 'UI/Progress',
5
+ title: 'React/UI/Progress',
6
6
  component: Progress,
7
7
  argTypes: {
8
8
  size: { control: 'radio', options: ['small', 'medium', 'large'] },
@@ -1,13 +1,13 @@
1
1
  import css from './Progress.module.css';
2
2
  import { cn } from '@boostdev/design-system-foundation';
3
+ import type { WithClassName } from '../../../types';
3
4
 
4
- interface ProgressProps {
5
+ interface ProgressProps extends WithClassName {
5
6
  value: number;
6
7
  max?: number;
7
8
  label: string;
8
9
  showLabel?: boolean;
9
10
  size?: 'small' | 'medium' | 'large';
10
- className?: string;
11
11
  }
12
12
 
13
13
  export function Progress({
@@ -15,7 +15,7 @@
15
15
  }
16
16
 
17
17
  .fill {
18
- stroke: var(--progressCircle_color-active, var(--bds-color_green));
18
+ stroke: var(--progressCircle_color-active, var(--bdc-color_active));
19
19
  transition: stroke-dashoffset var(--bds-animation_transition-duration) var(--bds-animation_easing);
20
20
  }
21
21
 
@@ -2,7 +2,7 @@ import type { Meta, StoryObj } from '@storybook/react';
2
2
  import { ProgressCircle } from './ProgressCircle';
3
3
 
4
4
  const meta = {
5
- title: 'UI/ProgressCircle',
5
+ title: 'React/UI/ProgressCircle',
6
6
  component: ProgressCircle,
7
7
  } satisfies Meta<typeof ProgressCircle>;
8
8
 
@@ -1,13 +1,13 @@
1
1
  import css from './ProgressCircle.module.css';
2
2
  import { cn } from '@boostdev/design-system-foundation';
3
+ import type { WithClassName } from '../../../types';
3
4
 
4
- interface ProgressCircleProps {
5
+ interface ProgressCircleProps extends WithClassName {
5
6
  value: number;
6
7
  max?: number;
7
8
  label: string;
8
9
  showValue?: boolean;
9
10
  size?: 'small' | 'medium' | 'large';
10
- className?: string;
11
11
  }
12
12
 
13
13
  const SIZE_PX = { small: 40, medium: 64, large: 96 };
@@ -23,6 +23,20 @@ Visual divider between content sections. Renders a semantic `<hr>` (horizontal)
23
23
 
24
24
  <ArgTypes of={Stories} />
25
25
 
26
+ ## CSS variables
27
+
28
+
29
+ <table>
30
+ <thead>
31
+ <tr><th>Variable</th><th>Default</th><th>Description</th></tr>
32
+ </thead>
33
+ <tbody>
34
+ <tr><td>`--separator_color`</td><td>`var(--bds-color_on-bg)`</td><td>Line colour</td></tr>
35
+ <tr><td>`--separator_thickness`</td><td>`1px`</td><td>Line thickness (height for horizontal, width for vertical)</td></tr>
36
+ </tbody>
37
+ </table>
38
+
39
+
26
40
  ## Accessibility
27
41
 
28
42
  - Horizontal variant uses `<hr>` — natively announces a thematic break to screen readers
@@ -0,0 +1,42 @@
1
+ import React from 'react';
2
+ import type { Meta, StoryObj } from '@storybook/react';
3
+ import { ThemeProvider } from '../../../native/ThemeContext';
4
+ import { Separator } from './Separator.native';
5
+
6
+ const meta = {
7
+ tags: ['!stable', 'alpha'],
8
+ title: 'React Native/UI/Separator',
9
+ component: Separator,
10
+ decorators: [(Story) => <ThemeProvider><Story /></ThemeProvider>],
11
+ parameters: { layout: 'padded' },
12
+ argTypes: {
13
+ orientation: { control: 'select', options: ['horizontal', 'vertical'] },
14
+ },
15
+ } satisfies Meta<typeof Separator>;
16
+
17
+ export default meta;
18
+ type Story = StoryObj<typeof meta>;
19
+
20
+ export const Horizontal: Story = {
21
+ render: (args) => (
22
+ <ThemeProvider>
23
+ <div style={{ width: 300 }}>
24
+ <Separator {...args} orientation="horizontal" />
25
+ </div>
26
+ </ThemeProvider>
27
+ ),
28
+ };
29
+
30
+ export const Vertical: Story = {
31
+ render: (args) => (
32
+ <ThemeProvider>
33
+ <div style={{ display: 'flex', height: 60, alignItems: 'stretch' }}>
34
+ <span>Left</span>
35
+ <div style={{ display: 'flex', margin: '0 8px' }}>
36
+ <Separator {...args} orientation="vertical" />
37
+ </div>
38
+ <span>Right</span>
39
+ </div>
40
+ </ThemeProvider>
41
+ ),
42
+ };
@@ -0,0 +1,32 @@
1
+ import { StyleSheet, View, StyleProp, ViewStyle } from 'react-native';
2
+ import { useTheme } from '../../../native/ThemeContext';
3
+
4
+ interface SeparatorProps {
5
+ orientation?: 'horizontal' | 'vertical';
6
+ style?: StyleProp<ViewStyle>;
7
+ }
8
+
9
+ const styles = StyleSheet.create({
10
+ horizontal: {
11
+ height: StyleSheet.hairlineWidth,
12
+ width: '100%',
13
+ },
14
+ vertical: {
15
+ width: StyleSheet.hairlineWidth,
16
+ alignSelf: 'stretch',
17
+ },
18
+ });
19
+
20
+ export function Separator({ orientation = 'horizontal', style }: Readonly<SeparatorProps>) {
21
+ const { colors } = useTheme();
22
+ return (
23
+ <View
24
+ accessibilityRole="none"
25
+ style={[
26
+ orientation === 'vertical' ? styles.vertical : styles.horizontal,
27
+ { backgroundColor: colors.colorBgSubtle },
28
+ style,
29
+ ]}
30
+ />
31
+ );
32
+ }
@@ -2,7 +2,7 @@ import type { Meta, StoryObj } from '@storybook/react';
2
2
  import { Separator } from './Separator';
3
3
 
4
4
  const meta = {
5
- title: 'UI/Separator',
5
+ title: 'React/UI/Separator',
6
6
  component: Separator,
7
7
  argTypes: {
8
8
  orientation: { control: 'radio', options: ['horizontal', 'vertical'] },
@@ -1,9 +1,9 @@
1
1
  import css from './Separator.module.css';
2
2
  import { cn } from '@boostdev/design-system-foundation';
3
+ import type { WithClassName } from '../../../types';
3
4
 
4
- interface SeparatorProps {
5
+ interface SeparatorProps extends WithClassName {
5
6
  orientation?: 'horizontal' | 'vertical';
6
- className?: string;
7
7
  }
8
8
 
9
9
  export function Separator({ orientation = 'horizontal', className }: Readonly<SeparatorProps>) {
@@ -0,0 +1,33 @@
1
+ import React from 'react';
2
+ import type { Meta, StoryObj } from '@storybook/react';
3
+ import { ThemeProvider } from '../../../native/ThemeContext';
4
+ import { Skeleton } from './Skeleton.native';
5
+
6
+ const meta = {
7
+ tags: ['!stable', 'alpha'],
8
+ title: 'React Native/UI/Skeleton',
9
+ component: Skeleton,
10
+ decorators: [(Story) => <ThemeProvider><Story /></ThemeProvider>],
11
+ parameters: { layout: 'padded' },
12
+ } satisfies Meta<typeof Skeleton>;
13
+
14
+ export default meta;
15
+ type Story = StoryObj<typeof meta>;
16
+
17
+ export const Text: Story = {
18
+ render: (args) => <Skeleton {...args} style={{ width: 200, height: 16 }} />,
19
+ };
20
+ export const Avatar: Story = {
21
+ render: (args) => <Skeleton {...args} style={{ width: 48, height: 48, borderRadius: 999 }} />,
22
+ };
23
+ export const Card: Story = {
24
+ render: () => (
25
+ <ThemeProvider>
26
+ <div style={{ display: 'flex', flexDirection: 'column', gap: '8px', width: 280 }}>
27
+ <Skeleton style={{ width: 280, height: 160 }} />
28
+ <Skeleton style={{ width: 200, height: 16 }} />
29
+ <Skeleton style={{ width: 140, height: 14 }} />
30
+ </div>
31
+ </ThemeProvider>
32
+ ),
33
+ };
@@ -0,0 +1,41 @@
1
+ import { useEffect, useRef } from 'react';
2
+ import { Animated, StyleSheet, StyleProp, ViewStyle } from 'react-native';
3
+ import { useTheme } from '../../../native/ThemeContext';
4
+
5
+ interface SkeletonProps {
6
+ style?: StyleProp<ViewStyle>;
7
+ }
8
+
9
+ const styles = StyleSheet.create({
10
+ skeleton: {
11
+ borderRadius: 4,
12
+ overflow: 'hidden',
13
+ },
14
+ });
15
+
16
+ export function Skeleton({ style }: SkeletonProps) {
17
+ const { colors } = useTheme();
18
+ const opacity = useRef(new Animated.Value(1)).current;
19
+
20
+ useEffect(() => {
21
+ const anim = Animated.loop(
22
+ Animated.sequence([
23
+ Animated.timing(opacity, { toValue: 0.4, duration: 700, useNativeDriver: true }),
24
+ Animated.timing(opacity, { toValue: 1, duration: 700, useNativeDriver: true }),
25
+ ]),
26
+ );
27
+ anim.start();
28
+ return () => anim.stop();
29
+ }, [opacity]);
30
+
31
+ return (
32
+ <Animated.View
33
+ importantForAccessibility="no-hide-descendants"
34
+ style={[
35
+ styles.skeleton,
36
+ { backgroundColor: colors.colorBgSubtle, opacity },
37
+ style,
38
+ ]}
39
+ />
40
+ );
41
+ }
@@ -2,7 +2,7 @@ import type { Meta, StoryObj } from '@storybook/react';
2
2
  import { Skeleton } from './Skeleton';
3
3
 
4
4
  const meta = {
5
- title: 'UI/Skeleton',
5
+ title: 'React/UI/Skeleton',
6
6
  component: Skeleton,
7
7
  } satisfies Meta<typeof Skeleton>;
8
8
 
@@ -1,9 +1,8 @@
1
1
  import { cn } from '@boostdev/design-system-foundation';
2
2
  import css from './Skeleton.module.css';
3
+ import type { WithClassName } from '../../../types';
3
4
 
4
- interface SkeletonProps {
5
- className?: string;
6
- }
5
+ type SkeletonProps = WithClassName;
7
6
 
8
7
  export function Skeleton({ className }: SkeletonProps) {
9
8
  return (
@@ -2,7 +2,7 @@ import type { Meta, StoryObj } from '@storybook/react';
2
2
  import { SkipLink } from './SkipLink';
3
3
 
4
4
  const meta = {
5
- title: 'UI/SkipLink',
5
+ title: 'React/UI/SkipLink',
6
6
  component: SkipLink,
7
7
  decorators: [
8
8
  Story => (
@@ -1,13 +1,15 @@
1
1
  import css from './SkipLink.module.css';
2
+ import { cn } from '@boostdev/design-system-foundation';
3
+ import type { WithClassName } from '../../../types';
2
4
 
3
- interface SkipLinkProps {
5
+ interface SkipLinkProps extends WithClassName {
4
6
  href?: string;
5
7
  children?: string;
6
8
  }
7
9
 
8
- export function SkipLink({ href = '#main', children = 'Skip to main content' }: SkipLinkProps) {
10
+ export function SkipLink({ href = '#main', children = 'Skip to main content', className }: SkipLinkProps) {
9
11
  return (
10
- <a href={href} className={css.skipLink}>
12
+ <a href={href} className={cn(css.skipLink, className)}>
11
13
  {children}
12
14
  </a>
13
15
  );
@@ -30,6 +30,20 @@ Data table with optional sortable columns and caption.
30
30
 
31
31
  <ArgTypes of={Stories} />
32
32
 
33
+ ## CSS variables
34
+
35
+
36
+ <table>
37
+ <thead>
38
+ <tr><th>Variable</th><th>Default</th><th>Description</th></tr>
39
+ </thead>
40
+ <tbody>
41
+ <tr><td>`--table_border`</td><td>`none`</td><td>Container border</td></tr>
42
+ <tr><td>`--table_radius`</td><td>`var(--bdc-outline_radius)`</td><td>Container corner radius</td></tr>
43
+ </tbody>
44
+ </table>
45
+
46
+
33
47
  ## Accessibility
34
48
 
35
49
  - Wraps in `<table>` with `<thead>` and `<tbody>`
@@ -5,7 +5,7 @@ import { Table } from './Table';
5
5
  type User = { name: string; role: string; status: string; joined: string };
6
6
 
7
7
  const meta = {
8
- title: 'UI/Table',
8
+ title: 'React/UI/Table',
9
9
  component: Table,
10
10
  } satisfies Meta<typeof Table<User>>;
11
11