@boostdev/design-system-components 2.4.2 → 2.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (201) hide show
  1. package/AGENTS.md +4 -20
  2. package/README.md +3 -23
  3. package/dist/client.cjs +115 -61
  4. package/dist/client.css +537 -537
  5. package/dist/client.d.cts +11 -1
  6. package/dist/client.d.ts +11 -1
  7. package/dist/client.js +115 -61
  8. package/dist/index.cjs +115 -61
  9. package/dist/index.css +537 -537
  10. package/dist/index.d.cts +11 -1
  11. package/dist/index.d.ts +11 -1
  12. package/dist/index.js +115 -61
  13. package/dist/web-components/index.js +23 -3
  14. package/package.json +2 -10
  15. package/src/components/layout/Grid/Grid.mdx +20 -2
  16. package/src/components/layout/Grid/Grid.spec.tsx +194 -4
  17. package/src/components/layout/Grid/Grid.tsx +15 -1
  18. package/src/components/layout/Grid/masonry.ts +127 -9
  19. package/dist/native/index.cjs +0 -4337
  20. package/dist/native/index.d.cts +0 -574
  21. package/dist/native/index.d.ts +0 -574
  22. package/dist/native/index.js +0 -4421
  23. package/src/components/interaction/Button/Button.native.mdx +0 -91
  24. package/src/components/interaction/Button/Button.native.spec.tsx +0 -55
  25. package/src/components/interaction/Button/Button.native.stories.tsx +0 -141
  26. package/src/components/interaction/Button/Button.native.tsx +0 -105
  27. package/src/components/interaction/Dialog/Dialog.native.mdx +0 -61
  28. package/src/components/interaction/Dialog/Dialog.native.spec.tsx +0 -73
  29. package/src/components/interaction/Dialog/Dialog.native.stories.tsx +0 -53
  30. package/src/components/interaction/Dialog/Dialog.native.tsx +0 -128
  31. package/src/components/interaction/Drawer/Drawer.native.mdx +0 -58
  32. package/src/components/interaction/Drawer/Drawer.native.spec.tsx +0 -81
  33. package/src/components/interaction/Drawer/Drawer.native.stories.tsx +0 -33
  34. package/src/components/interaction/Drawer/Drawer.native.tsx +0 -175
  35. package/src/components/interaction/DropdownMenu/DropdownMenu.native.mdx +0 -74
  36. package/src/components/interaction/DropdownMenu/DropdownMenu.native.spec.tsx +0 -78
  37. package/src/components/interaction/DropdownMenu/DropdownMenu.native.stories.tsx +0 -51
  38. package/src/components/interaction/DropdownMenu/DropdownMenu.native.tsx +0 -254
  39. package/src/components/interaction/Popover/Popover.native.mdx +0 -61
  40. package/src/components/interaction/Popover/Popover.native.spec.tsx +0 -73
  41. package/src/components/interaction/Popover/Popover.native.stories.tsx +0 -44
  42. package/src/components/interaction/Popover/Popover.native.tsx +0 -87
  43. package/src/components/interaction/Rating/Rating.native.mdx +0 -55
  44. package/src/components/interaction/Rating/Rating.native.spec.tsx +0 -38
  45. package/src/components/interaction/Rating/Rating.native.stories.tsx +0 -37
  46. package/src/components/interaction/Rating/Rating.native.tsx +0 -50
  47. package/src/components/interaction/Toast/Toast.native.mdx +0 -81
  48. package/src/components/interaction/Toast/Toast.native.spec.tsx +0 -80
  49. package/src/components/interaction/Toast/Toast.native.stories.tsx +0 -47
  50. package/src/components/interaction/Toast/Toast.native.tsx +0 -202
  51. package/src/components/interaction/form/Checkbox/Checkbox.native.mdx +0 -74
  52. package/src/components/interaction/form/Checkbox/Checkbox.native.spec.tsx +0 -42
  53. package/src/components/interaction/form/Checkbox/Checkbox.native.stories.tsx +0 -34
  54. package/src/components/interaction/form/Checkbox/Checkbox.native.tsx +0 -80
  55. package/src/components/interaction/form/CheckboxGroup/CheckboxGroup.native.mdx +0 -78
  56. package/src/components/interaction/form/CheckboxGroup/CheckboxGroup.native.spec.tsx +0 -57
  57. package/src/components/interaction/form/CheckboxGroup/CheckboxGroup.native.stories.tsx +0 -96
  58. package/src/components/interaction/form/CheckboxGroup/CheckboxGroup.native.tsx +0 -61
  59. package/src/components/interaction/form/Combobox/Combobox.native.mdx +0 -86
  60. package/src/components/interaction/form/Combobox/Combobox.native.spec.tsx +0 -60
  61. package/src/components/interaction/form/Combobox/Combobox.native.stories.tsx +0 -99
  62. package/src/components/interaction/form/Combobox/Combobox.native.tsx +0 -211
  63. package/src/components/interaction/form/FileInput/FileInput.native.mdx +0 -86
  64. package/src/components/interaction/form/FileInput/FileInput.native.spec.tsx +0 -73
  65. package/src/components/interaction/form/FileInput/FileInput.native.stories.tsx +0 -69
  66. package/src/components/interaction/form/FileInput/FileInput.native.tsx +0 -129
  67. package/src/components/interaction/form/FormInput/FormInput.native.mdx +0 -81
  68. package/src/components/interaction/form/FormInput/FormInput.native.spec.tsx +0 -51
  69. package/src/components/interaction/form/FormInput/FormInput.native.stories.tsx +0 -54
  70. package/src/components/interaction/form/FormInput/FormInput.native.tsx +0 -122
  71. package/src/components/interaction/form/NumberInput/NumberInput.native.mdx +0 -87
  72. package/src/components/interaction/form/NumberInput/NumberInput.native.spec.tsx +0 -63
  73. package/src/components/interaction/form/NumberInput/NumberInput.native.stories.tsx +0 -63
  74. package/src/components/interaction/form/NumberInput/NumberInput.native.tsx +0 -198
  75. package/src/components/interaction/form/Radio/Radio.native.spec.tsx +0 -79
  76. package/src/components/interaction/form/Radio/Radio.native.stories.tsx +0 -44
  77. package/src/components/interaction/form/Radio/Radio.native.tsx +0 -79
  78. package/src/components/interaction/form/RadioGroup/RadioGroup.native.mdx +0 -79
  79. package/src/components/interaction/form/RadioGroup/RadioGroup.native.spec.tsx +0 -66
  80. package/src/components/interaction/form/RadioGroup/RadioGroup.native.stories.tsx +0 -96
  81. package/src/components/interaction/form/RadioGroup/RadioGroup.native.tsx +0 -61
  82. package/src/components/interaction/form/SegmentedControl/SegmentedControl.native.mdx +0 -78
  83. package/src/components/interaction/form/SegmentedControl/SegmentedControl.native.spec.tsx +0 -82
  84. package/src/components/interaction/form/SegmentedControl/SegmentedControl.native.stories.tsx +0 -99
  85. package/src/components/interaction/form/SegmentedControl/SegmentedControl.native.tsx +0 -121
  86. package/src/components/interaction/form/Select/Select.native.mdx +0 -85
  87. package/src/components/interaction/form/Select/Select.native.spec.tsx +0 -64
  88. package/src/components/interaction/form/Select/Select.native.stories.tsx +0 -75
  89. package/src/components/interaction/form/Select/Select.native.tsx +0 -252
  90. package/src/components/interaction/form/Slider/Slider.native.mdx +0 -83
  91. package/src/components/interaction/form/Slider/Slider.native.spec.tsx +0 -51
  92. package/src/components/interaction/form/Slider/Slider.native.stories.tsx +0 -58
  93. package/src/components/interaction/form/Slider/Slider.native.tsx +0 -188
  94. package/src/components/interaction/form/Switch/Switch.native.spec.tsx +0 -60
  95. package/src/components/interaction/form/Switch/Switch.native.stories.tsx +0 -33
  96. package/src/components/interaction/form/Switch/Switch.native.tsx +0 -59
  97. package/src/components/interaction/form/Textarea/Textarea.native.mdx +0 -76
  98. package/src/components/interaction/form/Textarea/Textarea.native.spec.tsx +0 -50
  99. package/src/components/interaction/form/Textarea/Textarea.native.stories.tsx +0 -50
  100. package/src/components/interaction/form/Textarea/Textarea.native.tsx +0 -108
  101. package/src/components/interaction/form/atoms/Label.native.spec.tsx +0 -39
  102. package/src/components/interaction/form/atoms/Label.native.stories.tsx +0 -18
  103. package/src/components/interaction/form/atoms/Label.native.tsx +0 -29
  104. package/src/components/interaction/form/atoms/Message.native.spec.tsx +0 -30
  105. package/src/components/interaction/form/atoms/Message.native.stories.tsx +0 -22
  106. package/src/components/interaction/form/atoms/Message.native.tsx +0 -34
  107. package/src/components/layout/ButtonGroup/ButtonGroup.native.spec.tsx +0 -83
  108. package/src/components/layout/ButtonGroup/ButtonGroup.native.stories.tsx +0 -44
  109. package/src/components/layout/ButtonGroup/ButtonGroup.native.tsx +0 -44
  110. package/src/components/layout/Card/Card.native.spec.tsx +0 -102
  111. package/src/components/layout/Card/Card.native.stories.tsx +0 -51
  112. package/src/components/layout/Card/Card.native.tsx +0 -89
  113. package/src/components/layout/IconWrapper/IconWrapper.native.spec.tsx +0 -39
  114. package/src/components/layout/IconWrapper/IconWrapper.native.stories.tsx +0 -37
  115. package/src/components/layout/IconWrapper/IconWrapper.native.tsx +0 -20
  116. package/src/components/layout/SectionHeader/SectionHeader.native.spec.tsx +0 -51
  117. package/src/components/layout/SectionHeader/SectionHeader.native.stories.tsx +0 -36
  118. package/src/components/layout/SectionHeader/SectionHeader.native.tsx +0 -79
  119. package/src/components/ui/Accordion/Accordion.native.mdx +0 -65
  120. package/src/components/ui/Accordion/Accordion.native.spec.tsx +0 -69
  121. package/src/components/ui/Accordion/Accordion.native.stories.tsx +0 -52
  122. package/src/components/ui/Accordion/Accordion.native.tsx +0 -141
  123. package/src/components/ui/Alert/Alert.native.mdx +0 -62
  124. package/src/components/ui/Alert/Alert.native.spec.tsx +0 -76
  125. package/src/components/ui/Alert/Alert.native.stories.tsx +0 -41
  126. package/src/components/ui/Alert/Alert.native.tsx +0 -94
  127. package/src/components/ui/Avatar/Avatar.native.mdx +0 -50
  128. package/src/components/ui/Avatar/Avatar.native.spec.tsx +0 -47
  129. package/src/components/ui/Avatar/Avatar.native.stories.tsx +0 -32
  130. package/src/components/ui/Avatar/Avatar.native.tsx +0 -85
  131. package/src/components/ui/Badge/Badge.native.mdx +0 -54
  132. package/src/components/ui/Badge/Badge.native.spec.tsx +0 -45
  133. package/src/components/ui/Badge/Badge.native.stories.tsx +0 -34
  134. package/src/components/ui/Badge/Badge.native.tsx +0 -50
  135. package/src/components/ui/Breadcrumb/Breadcrumb.native.mdx +0 -52
  136. package/src/components/ui/Breadcrumb/Breadcrumb.native.spec.tsx +0 -49
  137. package/src/components/ui/Breadcrumb/Breadcrumb.native.stories.tsx +0 -46
  138. package/src/components/ui/Breadcrumb/Breadcrumb.native.tsx +0 -83
  139. package/src/components/ui/Calendar/Calendar.native.mdx +0 -58
  140. package/src/components/ui/Calendar/Calendar.native.spec.tsx +0 -92
  141. package/src/components/ui/Calendar/Calendar.native.stories.tsx +0 -45
  142. package/src/components/ui/Calendar/Calendar.native.tsx +0 -294
  143. package/src/components/ui/Carousel/Carousel.native.mdx +0 -55
  144. package/src/components/ui/Carousel/Carousel.native.spec.tsx +0 -55
  145. package/src/components/ui/Carousel/Carousel.native.stories.tsx +0 -59
  146. package/src/components/ui/Carousel/Carousel.native.tsx +0 -184
  147. package/src/components/ui/Collapsible/Collapsible.native.mdx +0 -53
  148. package/src/components/ui/Collapsible/Collapsible.native.spec.tsx +0 -68
  149. package/src/components/ui/Collapsible/Collapsible.native.stories.tsx +0 -48
  150. package/src/components/ui/Collapsible/Collapsible.native.tsx +0 -139
  151. package/src/components/ui/DescriptionList/DescriptionList.native.mdx +0 -50
  152. package/src/components/ui/DescriptionList/DescriptionList.native.spec.tsx +0 -37
  153. package/src/components/ui/DescriptionList/DescriptionList.native.stories.tsx +0 -48
  154. package/src/components/ui/DescriptionList/DescriptionList.native.tsx +0 -54
  155. package/src/components/ui/Link/Link.native.mdx +0 -53
  156. package/src/components/ui/Link/Link.native.spec.tsx +0 -35
  157. package/src/components/ui/Link/Link.native.stories.tsx +0 -46
  158. package/src/components/ui/Link/Link.native.tsx +0 -48
  159. package/src/components/ui/Loading/Loading.native.spec.tsx +0 -24
  160. package/src/components/ui/Loading/Loading.native.stories.tsx +0 -31
  161. package/src/components/ui/Loading/Loading.native.tsx +0 -29
  162. package/src/components/ui/NotificationBanner/NotificationBanner.native.spec.tsx +0 -85
  163. package/src/components/ui/NotificationBanner/NotificationBanner.native.stories.tsx +0 -37
  164. package/src/components/ui/NotificationBanner/NotificationBanner.native.tsx +0 -76
  165. package/src/components/ui/Pagination/Pagination.native.mdx +0 -62
  166. package/src/components/ui/Pagination/Pagination.native.spec.tsx +0 -86
  167. package/src/components/ui/Pagination/Pagination.native.stories.tsx +0 -47
  168. package/src/components/ui/Pagination/Pagination.native.tsx +0 -157
  169. package/src/components/ui/Progress/Progress.native.spec.tsx +0 -56
  170. package/src/components/ui/Progress/Progress.native.stories.tsx +0 -34
  171. package/src/components/ui/Progress/Progress.native.tsx +0 -84
  172. package/src/components/ui/ProgressCircle/ProgressCircle.native.mdx +0 -63
  173. package/src/components/ui/ProgressCircle/ProgressCircle.native.spec.tsx +0 -39
  174. package/src/components/ui/ProgressCircle/ProgressCircle.native.stories.tsx +0 -36
  175. package/src/components/ui/ProgressCircle/ProgressCircle.native.tsx +0 -176
  176. package/src/components/ui/Separator/Separator.native.spec.tsx +0 -39
  177. package/src/components/ui/Separator/Separator.native.stories.tsx +0 -38
  178. package/src/components/ui/Separator/Separator.native.tsx +0 -32
  179. package/src/components/ui/Skeleton/Skeleton.native.spec.tsx +0 -39
  180. package/src/components/ui/Skeleton/Skeleton.native.stories.tsx +0 -31
  181. package/src/components/ui/Skeleton/Skeleton.native.tsx +0 -42
  182. package/src/components/ui/Table/Table.native.mdx +0 -72
  183. package/src/components/ui/Table/Table.native.spec.tsx +0 -83
  184. package/src/components/ui/Table/Table.native.stories.tsx +0 -55
  185. package/src/components/ui/Table/Table.native.tsx +0 -196
  186. package/src/components/ui/Tabs/Tabs.native.mdx +0 -65
  187. package/src/components/ui/Tabs/Tabs.native.spec.tsx +0 -65
  188. package/src/components/ui/Tabs/Tabs.native.stories.tsx +0 -57
  189. package/src/components/ui/Tabs/Tabs.native.tsx +0 -133
  190. package/src/components/ui/Tooltip/Tooltip.native.mdx +0 -47
  191. package/src/components/ui/Tooltip/Tooltip.native.spec.tsx +0 -37
  192. package/src/components/ui/Tooltip/Tooltip.native.stories.tsx +0 -38
  193. package/src/components/ui/Tooltip/Tooltip.native.tsx +0 -57
  194. package/src/components/ui/Typography/Typography.native.mdx +0 -56
  195. package/src/components/ui/Typography/Typography.native.spec.tsx +0 -49
  196. package/src/components/ui/Typography/Typography.native.stories.tsx +0 -36
  197. package/src/components/ui/Typography/Typography.native.tsx +0 -65
  198. package/src/native/ThemeContext.tsx +0 -28
  199. package/src/native/tokens.ts +0 -13
  200. package/src/native.ts +0 -76
  201. package/src/stories/ReactNative.mdx +0 -156
@@ -1,68 +0,0 @@
1
- import { render, screen, fireEvent } from '@testing-library/react';
2
- import { ThemeProvider } from '../../../native/ThemeContext';
3
- import { Collapsible } from './Collapsible.native';
4
-
5
- function renderWithTheme(ui: React.ReactElement) {
6
- return render(<ThemeProvider>{ui}</ThemeProvider>);
7
- }
8
-
9
- describe('Collapsible (native)', () => {
10
- it('renders the summary text', () => {
11
- renderWithTheme(
12
- <Collapsible summary="Details">
13
- <span>Content</span>
14
- </Collapsible>,
15
- );
16
- expect(screen.getByText('Details')).toBeInTheDocument();
17
- });
18
-
19
- it('hides content by default', () => {
20
- renderWithTheme(
21
- <Collapsible summary="Details">
22
- <span>Hidden content</span>
23
- </Collapsible>,
24
- );
25
- expect(screen.queryByText('Hidden content')).not.toBeInTheDocument();
26
- });
27
-
28
- it('shows content when defaultOpen is true', () => {
29
- renderWithTheme(
30
- <Collapsible summary="Details" defaultOpen>
31
- <span>Visible content</span>
32
- </Collapsible>,
33
- );
34
- expect(screen.getByText('Visible content')).toBeInTheDocument();
35
- });
36
-
37
- it('toggles content on press', () => {
38
- renderWithTheme(
39
- <Collapsible summary="Toggle me">
40
- <span>Toggled content</span>
41
- </Collapsible>,
42
- );
43
- expect(screen.queryByText('Toggled content')).not.toBeInTheDocument();
44
- fireEvent.click(screen.getByRole('button', { name: 'Toggle me' }));
45
- expect(screen.getByText('Toggled content')).toBeInTheDocument();
46
- });
47
-
48
- it('shows content when defaultOpen is set and has button role', () => {
49
- renderWithTheme(
50
- <Collapsible summary="Expandable" defaultOpen>
51
- <span>Content</span>
52
- </Collapsible>,
53
- );
54
- expect(screen.getByRole('button', { name: 'Expandable' })).toBeInTheDocument();
55
- expect(screen.getByText('Content')).toBeInTheDocument();
56
- });
57
-
58
- it('calls onToggle with the new open state', () => {
59
- const onToggle = vi.fn();
60
- renderWithTheme(
61
- <Collapsible summary="Toggle" onToggle={onToggle}>
62
- <span>Content</span>
63
- </Collapsible>,
64
- );
65
- fireEvent.click(screen.getByRole('button', { name: 'Toggle' }));
66
- expect(onToggle).toHaveBeenCalledWith(true);
67
- });
68
- });
@@ -1,48 +0,0 @@
1
- import React from 'react';
2
- import { Text } from 'react-native';
3
- import type { Meta, StoryObj } from '@storybook/react';
4
- import { ThemeProvider } from '../../../native/ThemeContext';
5
- import { Collapsible } from './Collapsible.native';
6
-
7
- const meta = {
8
- tags: ['!stable', 'alpha'],
9
- title: 'React Native/UI/Collapsible',
10
- component: Collapsible,
11
- decorators: [(Story) => <ThemeProvider colorScheme="light"><Story /></ThemeProvider>],
12
- parameters: { layout: 'padded' },
13
- } satisfies Meta<typeof Collapsible>;
14
-
15
- export default meta;
16
- type Story = StoryObj<typeof meta>;
17
-
18
- export const Default: Story = {
19
- args: {
20
- summary: 'Click to expand',
21
- children: <Text>This is the collapsible content that is revealed when expanded.</Text>,
22
- },
23
- };
24
-
25
- export const DefaultOpen: Story = {
26
- args: {
27
- summary: 'Already open',
28
- defaultOpen: true,
29
- children: <Text>This content is visible by default.</Text>,
30
- },
31
- };
32
-
33
- export const Multiple: Story = {
34
- args: { summary: '', children: null },
35
- render: () => (
36
- <>
37
- <Collapsible summary="Section 1">
38
- <Text>Content for section 1.</Text>
39
- </Collapsible>
40
- <Collapsible summary="Section 2">
41
- <Text>Content for section 2.</Text>
42
- </Collapsible>
43
- <Collapsible summary="Section 3" defaultOpen>
44
- <Text>Content for section 3 (open by default).</Text>
45
- </Collapsible>
46
- </>
47
- ),
48
- };
@@ -1,139 +0,0 @@
1
- import { ReactNode, useCallback, useRef, useState } from 'react';
2
- import {
3
- StyleSheet,
4
- View,
5
- Text,
6
- Pressable,
7
- Animated,
8
- LayoutAnimation,
9
- Platform,
10
- UIManager,
11
- StyleProp,
12
- ViewStyle,
13
- } from 'react-native';
14
- import { spacing, font, border, lineHeight } from '../../../native/tokens';
15
- import { useTheme } from '../../../native/ThemeContext';
16
-
17
- if (
18
- Platform.OS === 'android' &&
19
- UIManager.setLayoutAnimationEnabledExperimental
20
- ) {
21
- UIManager.setLayoutAnimationEnabledExperimental(true);
22
- }
23
-
24
- export interface CollapsibleProps {
25
- /** The trigger label -- always visible */
26
- summary: string;
27
- /** The content revealed when expanded */
28
- children: ReactNode;
29
- /** Controlled open state */
30
- open?: boolean;
31
- /** Uncontrolled initial open state */
32
- defaultOpen?: boolean;
33
- /** Called after each toggle with the new open state */
34
- onToggle?: (open: boolean) => void;
35
- /** Grouping name (informational in native) */
36
- name?: string;
37
- style?: StyleProp<ViewStyle>;
38
- }
39
-
40
- const styles = StyleSheet.create({
41
- container: {
42
- borderRadius: border.radius.m,
43
- overflow: 'hidden',
44
- },
45
- header: {
46
- flexDirection: 'row',
47
- alignItems: 'center',
48
- justifyContent: 'space-between',
49
- minHeight: 44,
50
- paddingVertical: spacing.s,
51
- paddingHorizontal: spacing.m,
52
- },
53
- summaryText: {
54
- flex: 1,
55
- fontSize: font.size.body,
56
- fontFamily: font.family.body,
57
- fontWeight: font.weight.semibold,
58
- lineHeight: lineHeight.body,
59
- },
60
- chevron: {
61
- fontSize: font.size.body,
62
- marginStart: spacing.xs,
63
- },
64
- content: {
65
- paddingHorizontal: spacing.m,
66
- paddingBottom: spacing.m,
67
- },
68
- pressed: {
69
- opacity: 0.75,
70
- },
71
- });
72
-
73
- export function Collapsible({
74
- summary,
75
- children,
76
- open: controlledOpen,
77
- defaultOpen = false,
78
- onToggle,
79
- name: _name, // eslint-disable-line @typescript-eslint/no-unused-vars
80
- style,
81
- }: Readonly<CollapsibleProps>) {
82
- const { colors } = useTheme();
83
- const [internalOpen, setInternalOpen] = useState(defaultOpen);
84
- const isControlled = controlledOpen !== undefined;
85
- const isOpen = isControlled ? controlledOpen : internalOpen;
86
-
87
- const rotation = useRef(new Animated.Value(isOpen ? 1 : 0)).current;
88
-
89
- const toggle = useCallback(() => {
90
- const next = !isOpen;
91
-
92
- LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut);
93
-
94
- Animated.timing(rotation, {
95
- toValue: next ? 1 : 0,
96
- duration: 200,
97
- useNativeDriver: true,
98
- }).start();
99
-
100
- if (!isControlled) {
101
- setInternalOpen(next);
102
- }
103
- onToggle?.(next);
104
- }, [isOpen, isControlled, onToggle, rotation]);
105
-
106
- const rotateZ = rotation.interpolate({
107
- inputRange: [0, 1],
108
- outputRange: ['0deg', '90deg'],
109
- });
110
-
111
- return (
112
- <View
113
- style={[styles.container, { borderBottomWidth: 1, borderBottomColor: colors.colorBgSubtle }, style]}
114
- accessibilityRole="summary"
115
- >
116
- <Pressable
117
- onPress={toggle}
118
- accessibilityRole="button"
119
- accessibilityLabel={summary}
120
- accessibilityState={{ expanded: isOpen }}
121
- style={({ pressed }) => [styles.header, pressed && styles.pressed]}
122
- >
123
- <Text style={[styles.summaryText, { color: colors.colorOnBg }]}>{summary}</Text>
124
- <Animated.Text
125
- style={[styles.chevron, { color: colors.colorOnBgSubtle, transform: [{ rotateZ }] }]}
126
- importantForAccessibility="no"
127
- accessibilityElementsHidden={true}
128
- >
129
-
130
- </Animated.Text>
131
- </Pressable>
132
- {isOpen && (
133
- <View style={styles.content}>
134
- {children}
135
- </View>
136
- )}
137
- </View>
138
- );
139
- }
@@ -1,50 +0,0 @@
1
- import { Meta, Canvas, ArgTypes } from '@storybook/blocks';
2
- import * as Stories from './DescriptionList.native.stories';
3
-
4
- <Meta of={Stories} />
5
-
6
- # DescriptionList (React Native)
7
-
8
- React Native description list for displaying key-value pairs. Each item has a bold term and a description.
9
-
10
- > **Status: alpha** — API may change before stable release.
11
-
12
- ## Usage
13
-
14
- ```tsx
15
- import { DescriptionList } from '@boostdev/design-system-components';
16
-
17
- <DescriptionList
18
- items={[
19
- { term: 'Name', description: 'Jane Doe' },
20
- { term: 'Email', description: 'jane@example.com' },
21
- ]}
22
- />
23
- ```
24
-
25
- ## Examples
26
-
27
- ### Default
28
- <Canvas of={Stories.Default} />
29
-
30
- ### Two items
31
- <Canvas of={Stories.TwoItems} />
32
-
33
- ### Single item
34
- <Canvas of={Stories.SingleItem} />
35
-
36
- ## Props
37
-
38
- <ArgTypes of={Stories} />
39
-
40
- ## Props reference
41
-
42
- | Prop | Type | Default | Description |
43
- |------|------|---------|-------------|
44
- | `items` | `Array<{ term: string, description: ReactNode }>` | — | List of term-description pairs |
45
- | `style` | `StyleProp<ViewStyle>` | — | Override container styles |
46
-
47
- ## Accessibility
48
-
49
- - Container uses `accessibilityRole="list"`, each group uses `accessibilityRole="listitem"`
50
- - Terms render as bold text for visual distinction
@@ -1,37 +0,0 @@
1
- import { render, screen } from '@testing-library/react';
2
- import { ThemeProvider } from '../../../native/ThemeContext';
3
- import { DescriptionList } from './DescriptionList.native';
4
-
5
- function renderWithTheme(ui: React.ReactElement) {
6
- return render(<ThemeProvider>{ui}</ThemeProvider>);
7
- }
8
-
9
- describe('DescriptionList (native)', () => {
10
- const items = [
11
- { term: 'Name', description: 'Jane Doe' },
12
- { term: 'Email', description: 'jane@example.com' },
13
- ];
14
-
15
- it('renders all term texts', () => {
16
- renderWithTheme(<DescriptionList items={items} />);
17
- expect(screen.getByText('Name')).toBeInTheDocument();
18
- expect(screen.getByText('Email')).toBeInTheDocument();
19
- });
20
-
21
- it('renders all description texts', () => {
22
- renderWithTheme(<DescriptionList items={items} />);
23
- expect(screen.getByText('Jane Doe')).toBeInTheDocument();
24
- expect(screen.getByText('jane@example.com')).toBeInTheDocument();
25
- });
26
-
27
- it('has list role on the container', () => {
28
- renderWithTheme(<DescriptionList items={items} />);
29
- expect(screen.getByRole('list')).toBeInTheDocument();
30
- });
31
-
32
- it('renders a single item', () => {
33
- renderWithTheme(<DescriptionList items={[{ term: 'Version', description: '1.0' }]} />);
34
- expect(screen.getByText('Version')).toBeInTheDocument();
35
- expect(screen.getByText('1.0')).toBeInTheDocument();
36
- });
37
- });
@@ -1,48 +0,0 @@
1
- import React from 'react';
2
- import type { Meta, StoryObj } from '@storybook/react';
3
- import { ThemeProvider } from '../../../native/ThemeContext';
4
- import { DescriptionList } from './DescriptionList.native';
5
-
6
- const meta = {
7
- tags: ['!stable', 'alpha'],
8
- title: 'React Native/UI/DescriptionList',
9
- component: DescriptionList,
10
- decorators: [
11
- (Story) => (
12
- <ThemeProvider colorScheme="light">
13
- <div style={{ width: 300 }}>
14
- <Story />
15
- </div>
16
- </ThemeProvider>
17
- ),
18
- ],
19
- parameters: { layout: 'padded' },
20
- } satisfies Meta<typeof DescriptionList>;
21
-
22
- export default meta;
23
- type Story = StoryObj<typeof meta>;
24
-
25
- export const Default: Story = {
26
- args: {
27
- items: [
28
- { term: 'Name', description: 'Jane Doe' },
29
- { term: 'Email', description: 'jane@example.com' },
30
- { term: 'Role', description: 'Administrator' },
31
- ],
32
- },
33
- };
34
-
35
- export const TwoItems: Story = {
36
- args: {
37
- items: [
38
- { term: 'Status', description: 'Active' },
39
- { term: 'Plan', description: 'Enterprise' },
40
- ],
41
- },
42
- };
43
-
44
- export const SingleItem: Story = {
45
- args: {
46
- items: [{ term: 'Version', description: '1.0.0' }],
47
- },
48
- };
@@ -1,54 +0,0 @@
1
- import { ReactNode } from 'react';
2
- import { AccessibilityRole, StyleSheet, View, Text, StyleProp, ViewStyle } from 'react-native';
3
- import { spacing, font, lineHeight } from '../../../native/tokens';
4
- import { useTheme } from '../../../native/ThemeContext';
5
-
6
- export interface DescriptionItem {
7
- term: string;
8
- description: ReactNode;
9
- }
10
-
11
- interface DescriptionListProps {
12
- items: DescriptionItem[];
13
- style?: StyleProp<ViewStyle>;
14
- }
15
-
16
- const styles = StyleSheet.create({
17
- list: {
18
- gap: spacing.m,
19
- },
20
- group: {
21
- gap: spacing.xxs,
22
- },
23
- term: {
24
- fontSize: font.size.bodyS,
25
- fontFamily: font.family.body,
26
- fontWeight: font.weight.semibold,
27
- lineHeight: lineHeight.bodyS,
28
- },
29
- description: {
30
- fontSize: font.size.body,
31
- fontFamily: font.family.body,
32
- fontWeight: font.weight.body,
33
- lineHeight: lineHeight.body,
34
- },
35
- });
36
-
37
- export function DescriptionList({ items, style }: Readonly<DescriptionListProps>) {
38
- const { colors } = useTheme();
39
-
40
- return (
41
- <View style={[styles.list, style]} accessibilityRole="list">
42
- {items.map((item, i) => (
43
- <View key={i} style={styles.group} accessibilityRole={'listitem' as AccessibilityRole}>
44
- <Text style={[styles.term, { color: colors.colorOnBgSubtle }]}>{item.term}</Text>
45
- {typeof item.description === 'string' ? (
46
- <Text style={[styles.description, { color: colors.colorOnBg }]}>{item.description}</Text>
47
- ) : (
48
- <View>{item.description}</View>
49
- )}
50
- </View>
51
- ))}
52
- </View>
53
- );
54
- }
@@ -1,53 +0,0 @@
1
- import { Meta, Canvas, ArgTypes } from '@storybook/blocks';
2
- import * as Stories from './Link.native.stories';
3
-
4
- <Meta of={Stories} />
5
-
6
- # Link (React Native)
7
-
8
- React Native link component using `Pressable` + `Text`. Opens URLs via `Linking.openURL` or calls a custom `onPress` handler.
9
-
10
- > **Status: alpha** — API may change before stable release.
11
-
12
- ## Usage
13
-
14
- ```tsx
15
- import { Link } from '@boostdev/design-system-components';
16
-
17
- <Link href="https://example.com">Visit website</Link>
18
- <Link onPress={() => navigation.navigate('Settings')}>Settings</Link>
19
- ```
20
-
21
- ## Examples
22
-
23
- ### Default
24
- <Canvas of={Stories.Default} />
25
-
26
- ### With onPress callback
27
- <Canvas of={Stories.WithOnPress} />
28
-
29
- ### With accessibility label
30
- <Canvas of={Stories.WithAccessibilityLabel} />
31
-
32
- ### All variants
33
- <Canvas of={Stories.AllVariants} />
34
-
35
- ## Props
36
-
37
- <ArgTypes of={Stories} />
38
-
39
- ## Props reference
40
-
41
- | Prop | Type | Default | Description |
42
- |------|------|---------|-------------|
43
- | `href` | `string` | — | URL to open via `Linking.openURL` |
44
- | `children` | `ReactNode` | — | Link label |
45
- | `onPress` | `() => void` | — | Custom press handler (used when `href` is not provided) |
46
- | `accessibilityLabel` | `string` | — | Screen reader label |
47
- | `style` | `StyleProp<TextStyle>` | — | Override text styles |
48
-
49
- ## Accessibility
50
-
51
- - Uses `accessibilityRole="link"` for assistive technologies
52
- - Provide `accessibilityLabel` when the visible text is not self-descriptive
53
- - Pressed state reduces opacity for visual feedback
@@ -1,35 +0,0 @@
1
- import { render, screen, fireEvent } from '@testing-library/react';
2
- import { ThemeProvider } from '../../../native/ThemeContext';
3
- import { Link } from './Link.native';
4
-
5
- function renderWithTheme(ui: React.ReactElement) {
6
- return render(<ThemeProvider>{ui}</ThemeProvider>);
7
- }
8
-
9
- describe('Link (native)', () => {
10
- it('renders children text', () => {
11
- renderWithTheme(<Link href="https://example.com">Visit</Link>);
12
- expect(screen.getByText('Visit')).toBeInTheDocument();
13
- });
14
-
15
- it('has link role', () => {
16
- renderWithTheme(<Link href="https://example.com">Visit</Link>);
17
- expect(screen.getByRole('link')).toBeInTheDocument();
18
- });
19
-
20
- it('calls onPress when provided without href', () => {
21
- const onPress = vi.fn();
22
- renderWithTheme(<Link onPress={onPress}>Navigate</Link>);
23
- fireEvent.click(screen.getByRole('link'));
24
- expect(onPress).toHaveBeenCalledTimes(1);
25
- });
26
-
27
- it('uses accessibilityLabel when provided', () => {
28
- renderWithTheme(
29
- <Link href="https://example.com" accessibilityLabel="Read more about products">
30
- Read more
31
- </Link>,
32
- );
33
- expect(screen.getByLabelText('Read more about products')).toBeInTheDocument();
34
- });
35
- });
@@ -1,46 +0,0 @@
1
- import React from 'react';
2
- import type { Meta, StoryObj } from '@storybook/react';
3
- import { ThemeProvider } from '../../../native/ThemeContext';
4
- import { Link } from './Link.native';
5
-
6
- const meta = {
7
- tags: ['!stable', 'alpha'],
8
- title: 'React Native/UI/Link',
9
- component: Link,
10
- decorators: [(Story) => <ThemeProvider colorScheme="light"><Story /></ThemeProvider>],
11
- parameters: { layout: 'centered' },
12
- argTypes: {
13
- onPress: { action: 'pressed' },
14
- },
15
- } satisfies Meta<typeof Link>;
16
-
17
- export default meta;
18
- type Story = StoryObj<typeof meta>;
19
-
20
- export const Default: Story = {
21
- args: { children: 'Visit website', href: 'https://example.com' },
22
- };
23
-
24
- export const WithOnPress: Story = {
25
- args: { children: 'Navigate', onPress: () => {} },
26
- };
27
-
28
- export const WithAccessibilityLabel: Story = {
29
- args: {
30
- children: 'Read more',
31
- href: 'https://example.com',
32
- accessibilityLabel: 'Read more about our products',
33
- },
34
- };
35
-
36
- export const AllVariants: Story = {
37
- render: () => (
38
- <div style={{ display: 'flex', flexDirection: 'column', gap: '12px' }}>
39
- <Link href="https://example.com">Default link</Link>
40
- <Link onPress={() => {}}>Callback link</Link>
41
- <Link href="https://example.com" accessibilityLabel="Accessible link">
42
- With accessibility label
43
- </Link>
44
- </div>
45
- ),
46
- };
@@ -1,48 +0,0 @@
1
- import { ReactNode } from 'react';
2
- import { StyleSheet, Text, Pressable, Linking, StyleProp, TextStyle } from 'react-native';
3
- import { font } from '../../../native/tokens';
4
- import { useTheme } from '../../../native/ThemeContext';
5
-
6
- interface LinkProps {
7
- href?: string;
8
- children: ReactNode;
9
- accessibilityLabel?: string;
10
- style?: StyleProp<TextStyle>;
11
- onPress?: () => void;
12
- }
13
-
14
- const styles = StyleSheet.create({
15
- text: {
16
- fontSize: font.size.body,
17
- fontFamily: font.family.body,
18
- textDecorationLine: 'underline',
19
- },
20
- pressed: {
21
- opacity: 0.75,
22
- },
23
- });
24
-
25
- export function Link({ href, children, accessibilityLabel, style, onPress }: Readonly<LinkProps>) {
26
- const { colors } = useTheme();
27
-
28
- const handlePress = () => {
29
- if (onPress) {
30
- onPress();
31
- } else if (href) {
32
- Linking.openURL(href);
33
- }
34
- };
35
-
36
- return (
37
- <Pressable
38
- onPress={handlePress}
39
- accessibilityRole="link"
40
- accessibilityLabel={accessibilityLabel}
41
- style={({ pressed }) => pressed && styles.pressed}
42
- >
43
- <Text style={[styles.text, { color: colors.colorInteractiveOnBg }, style]}>
44
- {children}
45
- </Text>
46
- </Pressable>
47
- );
48
- }
@@ -1,24 +0,0 @@
1
- import { render, screen } from '@testing-library/react';
2
- import { ThemeProvider } from '../../../native/ThemeContext';
3
- import { Loading } from './Loading.native';
4
-
5
- function renderWithTheme(ui: React.ReactElement) {
6
- return render(<ThemeProvider>{ui}</ThemeProvider>);
7
- }
8
-
9
- describe('Loading (native)', () => {
10
- it('has progressbar role', () => {
11
- renderWithTheme(<Loading />);
12
- expect(screen.getByRole('progressbar')).toBeInTheDocument();
13
- });
14
-
15
- it('has default accessible label "Loading"', () => {
16
- renderWithTheme(<Loading />);
17
- expect(screen.getByRole('progressbar', { name: 'Loading' })).toBeInTheDocument();
18
- });
19
-
20
- it('accepts a custom accessibilityLabel', () => {
21
- renderWithTheme(<Loading accessibilityLabel="Laden…" />);
22
- expect(screen.getByRole('progressbar', { name: 'Laden…' })).toBeInTheDocument();
23
- });
24
- });
@@ -1,31 +0,0 @@
1
- import React from 'react';
2
- import type { Meta, StoryObj } from '@storybook/react';
3
- import { ThemeProvider } from '../../../native/ThemeContext';
4
- import { Loading } from './Loading.native';
5
-
6
- const meta = {
7
- tags: ['!stable', 'alpha'],
8
- title: 'React Native/UI/Loading',
9
- component: Loading,
10
- decorators: [(Story) => <ThemeProvider colorScheme="light"><Story /></ThemeProvider>],
11
- parameters: { layout: 'centered' },
12
- argTypes: {
13
- size: { control: 'select', options: ['small', 'medium', 'large'] },
14
- },
15
- } satisfies Meta<typeof Loading>;
16
-
17
- export default meta;
18
- type Story = StoryObj<typeof meta>;
19
-
20
- export const Small: Story = { args: { size: 'small' } };
21
- export const Medium: Story = { args: { size: 'medium' } };
22
- export const Large: Story = { args: { size: 'large' } };
23
- export const AllSizes: Story = {
24
- render: () => (
25
- <div style={{ display: 'flex', gap: '24px', alignItems: 'center' }}>
26
- <Loading size="small" />
27
- <Loading size="medium" />
28
- <Loading size="large" />
29
- </div>
30
- ),
31
- };