@boostdev/design-system-components 2.4.2 → 2.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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 +175 -4
  17. package/src/components/layout/Grid/Grid.tsx +15 -1
  18. package/src/components/layout/Grid/masonry.ts +120 -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,108 +0,0 @@
1
- import { ReactNode, useState } from 'react';
2
- import {
3
- StyleSheet,
4
- View,
5
- TextInput,
6
- StyleProp,
7
- ViewStyle,
8
- } from 'react-native';
9
- import { spacing, font, border, lineHeight } from '../../../../native/tokens';
10
- import { useTheme } from '../../../../native/ThemeContext';
11
- import { Label } from '../atoms/Label.native';
12
- import { Message } from '../atoms/Message.native';
13
-
14
- interface TextareaProps {
15
- label: ReactNode;
16
- name: string;
17
- value?: string;
18
- defaultValue?: string;
19
- placeholder?: string;
20
- error?: string;
21
- hint?: string;
22
- disabled?: boolean;
23
- numberOfLines?: number;
24
- onChange?: (value: string) => void;
25
- onBlur?: () => void;
26
- onFocus?: () => void;
27
- style?: StyleProp<ViewStyle>;
28
- }
29
-
30
- const styles = StyleSheet.create({
31
- container: {
32
- gap: spacing.xxs,
33
- },
34
- textarea: {
35
- fontFamily: font.family.body,
36
- fontSize: font.size.body,
37
- lineHeight: lineHeight.body,
38
- paddingHorizontal: spacing.s,
39
- paddingVertical: spacing.xs,
40
- borderWidth: 1,
41
- borderRadius: border.radius.xs,
42
- minHeight: 100,
43
- textAlignVertical: 'top',
44
- },
45
- });
46
-
47
- export function Textarea({
48
- label,
49
- name,
50
- value,
51
- defaultValue,
52
- placeholder,
53
- error,
54
- hint,
55
- disabled = false,
56
- numberOfLines = 4,
57
- onChange,
58
- onBlur,
59
- onFocus,
60
- style,
61
- }: Readonly<TextareaProps>) {
62
- const { colors } = useTheme();
63
- const [focused, setFocused] = useState(false);
64
-
65
- const borderColor = error
66
- ? colors.colorError
67
- : focused
68
- ? colors.colorInteractive
69
- : colors.colorOnBg;
70
-
71
- return (
72
- <View style={[styles.container, style]}>
73
- <Label label={label} />
74
- <TextInput
75
- accessibilityLabel={typeof label === 'string' ? label : name}
76
- accessibilityState={{ disabled }}
77
- accessibilityHint={hint}
78
- multiline
79
- numberOfLines={numberOfLines}
80
- value={value}
81
- defaultValue={defaultValue}
82
- placeholder={placeholder}
83
- placeholderTextColor={colors.colorOnBgSubtle}
84
- editable={!disabled}
85
- onChangeText={onChange}
86
- onFocus={() => {
87
- setFocused(true);
88
- onFocus?.();
89
- }}
90
- onBlur={() => {
91
- setFocused(false);
92
- onBlur?.();
93
- }}
94
- style={[
95
- styles.textarea,
96
- {
97
- borderColor,
98
- color: colors.colorOnBg,
99
- backgroundColor: colors.colorBg,
100
- },
101
- disabled && { opacity: 0.4 },
102
- ]}
103
- />
104
- <Message type="error" message={error} />
105
- <Message type="hint" message={hint} />
106
- </View>
107
- );
108
- }
@@ -1,39 +0,0 @@
1
- import { render, screen } from '@testing-library/react';
2
- import { ThemeProvider } from '../../../../native/ThemeContext';
3
- import { Label } from './Label.native';
4
-
5
- function renderWithTheme(ui: React.ReactElement) {
6
- return render(<ThemeProvider>{ui}</ThemeProvider>);
7
- }
8
-
9
- describe('Label (native)', () => {
10
- it('renders the label text', () => {
11
- renderWithTheme(<Label label="Email address" />);
12
- expect(screen.getByText('Email address')).toBeInTheDocument();
13
- });
14
-
15
- it('renders ReactNode content as label', () => {
16
- renderWithTheme(
17
- <Label
18
- label={
19
- <span data-testid="custom-label">
20
- Custom <strong>label</strong>
21
- </span>
22
- }
23
- />,
24
- );
25
- expect(screen.getByTestId('custom-label')).toBeInTheDocument();
26
- });
27
-
28
- it('applies semibold font weight', () => {
29
- renderWithTheme(<Label label="Name" />);
30
- const label = screen.getByText('Name');
31
- expect(label).toHaveStyle({ fontWeight: expect.stringMatching(/600|bold|semibold/) });
32
- });
33
-
34
- it('applies custom style when provided', () => {
35
- renderWithTheme(<Label label="Name" style={{ marginBottom: 8 }} />);
36
- const label = screen.getByText('Name');
37
- expect(label).toHaveStyle({ marginBottom: 8 });
38
- });
39
- });
@@ -1,18 +0,0 @@
1
- import React from 'react';
2
- import type { Meta, StoryObj } from '@storybook/react';
3
- import { ThemeProvider } from '../../../../native/ThemeContext';
4
- import { Label } from './Label.native';
5
-
6
- const meta = {
7
- tags: ['!stable', 'alpha'],
8
- title: 'React Native/Form/Label',
9
- component: Label,
10
- decorators: [(Story) => <ThemeProvider colorScheme="light"><Story /></ThemeProvider>],
11
- parameters: { layout: 'centered' },
12
- } satisfies Meta<typeof Label>;
13
-
14
- export default meta;
15
- type Story = StoryObj<typeof meta>;
16
-
17
- export const Default: Story = { args: { label: 'Email address' } };
18
- export const LongLabel: Story = { args: { label: 'Please enter your full legal name as it appears on your passport' } };
@@ -1,29 +0,0 @@
1
- import { ReactNode } from 'react';
2
- import { Text, StyleProp, TextStyle } from 'react-native';
3
- import { font, lineHeight } from '../../../../native/tokens';
4
- import { useTheme } from '../../../../native/ThemeContext';
5
-
6
- interface LabelProps {
7
- label: ReactNode;
8
- style?: StyleProp<TextStyle>;
9
- }
10
-
11
- export function Label({ label, style }: LabelProps) {
12
- const { colors } = useTheme();
13
- return (
14
- <Text
15
- style={[
16
- {
17
- fontFamily: font.family.body,
18
- fontSize: font.size.body,
19
- lineHeight: lineHeight.body,
20
- fontWeight: font.weight.semibold,
21
- color: colors.colorOnBg,
22
- },
23
- style,
24
- ]}
25
- >
26
- {label}
27
- </Text>
28
- );
29
- }
@@ -1,30 +0,0 @@
1
- import { render, screen } from '@testing-library/react';
2
- import { ThemeProvider } from '../../../../native/ThemeContext';
3
- import { Message } from './Message.native';
4
-
5
- function renderWithTheme(ui: React.ReactElement) {
6
- return render(<ThemeProvider>{ui}</ThemeProvider>);
7
- }
8
-
9
- describe('Message (native)', () => {
10
- it('renders nothing when message is undefined', () => {
11
- const { container } = renderWithTheme(<Message type="error" message={undefined} />);
12
- expect(container.firstChild).toBeNull();
13
- });
14
-
15
- it('renders error message with alert role', () => {
16
- renderWithTheme(<Message type="error" message="This field is required." />);
17
- expect(screen.getByRole('alert')).toHaveTextContent('This field is required.');
18
- });
19
-
20
- it('announces error messages assertively', () => {
21
- renderWithTheme(<Message type="error" message="This field is required." />);
22
- expect(screen.getByRole('alert')).toHaveAttribute('aria-live', 'assertive');
23
- });
24
-
25
- it('announces hint messages politely', () => {
26
- renderWithTheme(<Message type="hint" message="Use at least 8 characters." />);
27
- const hint = screen.getByText('Use at least 8 characters.');
28
- expect(hint).toHaveAttribute('aria-live', 'polite');
29
- });
30
- });
@@ -1,22 +0,0 @@
1
- import React from 'react';
2
- import type { Meta, StoryObj } from '@storybook/react';
3
- import { ThemeProvider } from '../../../../native/ThemeContext';
4
- import { Message } from './Message.native';
5
-
6
- const meta = {
7
- tags: ['!stable', 'alpha'],
8
- title: 'React Native/Form/Message',
9
- component: Message,
10
- decorators: [(Story) => <ThemeProvider colorScheme="light"><Story /></ThemeProvider>],
11
- parameters: { layout: 'padded' },
12
- argTypes: {
13
- type: { control: 'select', options: ['hint', 'error'] },
14
- },
15
- } satisfies Meta<typeof Message>;
16
-
17
- export default meta;
18
- type Story = StoryObj<typeof meta>;
19
-
20
- export const Hint: Story = { args: { type: 'hint', message: 'Use at least 8 characters.' } };
21
- export const Error: Story = { args: { type: 'error', message: 'This field is required.' } };
22
- export const Empty: Story = { args: { type: 'hint', message: undefined } };
@@ -1,34 +0,0 @@
1
- import { StyleSheet, Text, StyleProp, TextStyle } from 'react-native';
2
- import { font, lineHeight } from '../../../../native/tokens';
3
- import { useTheme } from '../../../../native/ThemeContext';
4
-
5
- interface MessageProps {
6
- type: 'hint' | 'error';
7
- message: string | undefined;
8
- style?: StyleProp<TextStyle>;
9
- }
10
-
11
- const styles = StyleSheet.create({
12
- base: {
13
- fontFamily: font.family.body,
14
- fontSize: font.size.bodyS,
15
- lineHeight: lineHeight.bodyS,
16
- },
17
- });
18
-
19
- export function Message({ message, type, style }: MessageProps) {
20
- const { colors } = useTheme();
21
- if (!message) return null;
22
-
23
- const color = type === 'error' ? colors.colorError : colors.colorOnBgSubtle;
24
-
25
- return (
26
- <Text
27
- accessibilityRole={type === 'error' ? 'alert' : 'none'}
28
- accessibilityLiveRegion={type === 'error' ? 'assertive' : 'polite'}
29
- style={[styles.base, { color }, style]}
30
- >
31
- {message}
32
- </Text>
33
- );
34
- }
@@ -1,83 +0,0 @@
1
- import { render, screen } from '@testing-library/react';
2
- import { ThemeProvider } from '../../../native/ThemeContext';
3
- import { ButtonGroup } from './ButtonGroup.native';
4
-
5
- function renderWithTheme(ui: React.ReactElement) {
6
- return render(<ThemeProvider>{ui}</ThemeProvider>);
7
- }
8
-
9
- describe('ButtonGroup (native)', () => {
10
- it('renders children', () => {
11
- renderWithTheme(
12
- <ButtonGroup>
13
- <span data-testid="child-a">A</span>
14
- <span data-testid="child-b">B</span>
15
- </ButtonGroup>,
16
- );
17
- expect(screen.getByTestId('child-a')).toBeInTheDocument();
18
- expect(screen.getByTestId('child-b')).toBeInTheDocument();
19
- });
20
-
21
- it('applies accessibilityLabel to the container', () => {
22
- const { container } = renderWithTheme(
23
- <ButtonGroup accessibilityLabel="Actions">
24
- <span>OK</span>
25
- </ButtonGroup>,
26
- );
27
- expect(container.firstChild).toHaveAttribute('aria-label', 'Actions');
28
- });
29
-
30
- it('renders without accessibilityLabel when not provided', () => {
31
- const { container } = renderWithTheme(
32
- <ButtonGroup>
33
- <span>OK</span>
34
- </ButtonGroup>,
35
- );
36
- expect(container.firstChild).not.toHaveAttribute('aria-label');
37
- });
38
-
39
- it('renders in row direction by default', () => {
40
- const { container } = renderWithTheme(
41
- <ButtonGroup>
42
- <span>A</span>
43
- </ButtonGroup>,
44
- );
45
- expect(container.firstChild).toHaveStyle({ flexDirection: 'row' });
46
- });
47
-
48
- it('renders in row direction for flow variant', () => {
49
- const { container } = renderWithTheme(
50
- <ButtonGroup variant="flow">
51
- <span>A</span>
52
- </ButtonGroup>,
53
- );
54
- expect(container.firstChild).toHaveStyle({ flexDirection: 'row' });
55
- });
56
-
57
- it('renders in row direction for content variant', () => {
58
- const { container } = renderWithTheme(
59
- <ButtonGroup variant="content">
60
- <span>A</span>
61
- </ButtonGroup>,
62
- );
63
- expect(container.firstChild).toHaveStyle({ flexDirection: 'row' });
64
- });
65
-
66
- it('renders in column direction for card variant', () => {
67
- const { container } = renderWithTheme(
68
- <ButtonGroup variant="card">
69
- <span>A</span>
70
- </ButtonGroup>,
71
- );
72
- expect(container.firstChild).toHaveStyle({ flexDirection: 'column' });
73
- });
74
-
75
- it('renders in column direction for modal variant', () => {
76
- const { container } = renderWithTheme(
77
- <ButtonGroup variant="modal">
78
- <span>A</span>
79
- </ButtonGroup>,
80
- );
81
- expect(container.firstChild).toHaveStyle({ flexDirection: 'column' });
82
- });
83
- });
@@ -1,44 +0,0 @@
1
- import React from 'react';
2
- import type { Meta, StoryObj } from '@storybook/react';
3
- import { ThemeProvider } from '../../../native/ThemeContext';
4
- import { ButtonGroup } from './ButtonGroup.native';
5
- import { Button } from '../../interaction/Button/Button.native';
6
-
7
- const meta = {
8
- tags: ['!stable', 'alpha'],
9
- title: 'React Native/Layout/ButtonGroup',
10
- component: ButtonGroup,
11
- decorators: [(Story) => <ThemeProvider colorScheme="light"><Story /></ThemeProvider>],
12
- parameters: { layout: 'padded' },
13
- argTypes: {
14
- variant: { control: 'select', options: ['flow', 'card', 'modal', 'content'] },
15
- },
16
- } satisfies Meta<typeof ButtonGroup>;
17
-
18
- export default meta;
19
- type Story = StoryObj<typeof meta>;
20
-
21
- export const Flow: Story = {
22
- render: (args) => (
23
- <ButtonGroup {...args} variant="flow">
24
- <Button>Primary</Button>
25
- <Button variant="ghost">Secondary</Button>
26
- </ButtonGroup>
27
- ),
28
- };
29
- export const Card: Story = {
30
- render: (args) => (
31
- <ButtonGroup {...args} variant="card">
32
- <Button>Confirm</Button>
33
- <Button variant="ghost">Cancel</Button>
34
- </ButtonGroup>
35
- ),
36
- };
37
- export const Modal: Story = {
38
- render: (args) => (
39
- <ButtonGroup {...args} variant="modal">
40
- <Button>Save</Button>
41
- <Button variant="ghost">Discard</Button>
42
- </ButtonGroup>
43
- ),
44
- };
@@ -1,44 +0,0 @@
1
- import { ReactNode } from 'react';
2
- import { StyleSheet, View, StyleProp, ViewStyle } from 'react-native';
3
- import { spacing } from '../../../native/tokens';
4
-
5
- export interface ButtonContainerProps {
6
- children: ReactNode;
7
- variant?: 'flow' | 'card' | 'modal' | 'content';
8
- accessibilityLabel?: string;
9
- style?: StyleProp<ViewStyle>;
10
- }
11
-
12
- const styles = StyleSheet.create({
13
- group: {
14
- flexDirection: 'row',
15
- flexWrap: 'wrap',
16
- gap: spacing.xs,
17
- },
18
- column: {
19
- flexDirection: 'column',
20
- gap: spacing.xs,
21
- },
22
- });
23
-
24
- export function ButtonContainer({ children, variant, accessibilityLabel, style }: ButtonContainerProps) {
25
- const isColumn = variant === 'card' || variant === 'modal';
26
- return (
27
- <View
28
- accessibilityLabel={accessibilityLabel}
29
- style={[isColumn ? styles.column : styles.group, style]}
30
- >
31
- {children}
32
- </View>
33
- );
34
- }
35
-
36
- /**
37
- * @deprecated Use `ButtonContainer` instead. `ButtonGroup` will be removed in the next major version.
38
- */
39
- export const ButtonGroup = ButtonContainer;
40
-
41
- /**
42
- * @deprecated Use `ButtonContainerProps` instead. `ButtonGroupProps` will be removed in the next major version.
43
- */
44
- export type ButtonGroupProps = ButtonContainerProps;
@@ -1,102 +0,0 @@
1
- import { render, screen, fireEvent } from '@testing-library/react';
2
- import { ThemeProvider } from '../../../native/ThemeContext';
3
- import { Card } from './Card.native';
4
-
5
- function renderWithTheme(ui: React.ReactElement) {
6
- return render(<ThemeProvider>{ui}</ThemeProvider>);
7
- }
8
-
9
- describe('Card (native)', () => {
10
- it('renders children', () => {
11
- renderWithTheme(
12
- <Card>
13
- <span data-testid="content">Hello</span>
14
- </Card>,
15
- );
16
- expect(screen.getByTestId('content')).toBeInTheDocument();
17
- });
18
-
19
- it('renders as a View when onPress is not provided', () => {
20
- const { container } = renderWithTheme(
21
- <Card>
22
- <span>Content</span>
23
- </Card>,
24
- );
25
- expect(container.firstChild).not.toHaveAttribute('role');
26
- });
27
-
28
- it('renders as a Pressable with button role when onPress is provided', () => {
29
- const handlePress = vi.fn();
30
- renderWithTheme(
31
- <Card onPress={handlePress} accessibilityLabel="Tap me">
32
- <span>Content</span>
33
- </Card>,
34
- );
35
- expect(screen.getByRole('button', { name: 'Tap me' })).toBeInTheDocument();
36
- });
37
-
38
- it('calls onPress when pressed', () => {
39
- const handlePress = vi.fn();
40
- renderWithTheme(
41
- <Card onPress={handlePress} accessibilityLabel="Tap me">
42
- <span>Content</span>
43
- </Card>,
44
- );
45
- fireEvent.click(screen.getByRole('button'));
46
- expect(handlePress).toHaveBeenCalledOnce();
47
- });
48
-
49
- it('applies accessibilityLabel to the pressable card', () => {
50
- renderWithTheme(
51
- <Card onPress={() => {}} accessibilityLabel="Product card">
52
- <span>Content</span>
53
- </Card>,
54
- );
55
- expect(screen.getByRole('button')).toHaveAttribute('aria-label', 'Product card');
56
- });
57
-
58
- it('applies border for outlined variant', () => {
59
- const { container } = renderWithTheme(
60
- <Card variant="outlined">
61
- <span>Content</span>
62
- </Card>,
63
- );
64
- expect(container.firstChild).toHaveStyle({ borderWidth: 1 });
65
- });
66
-
67
- it('renders elevated variant without throwing', () => {
68
- renderWithTheme(
69
- <Card variant="elevated">
70
- <span data-testid="elevated-content">Content</span>
71
- </Card>,
72
- );
73
- expect(screen.getByTestId('elevated-content')).toBeInTheDocument();
74
- });
75
-
76
- it('renders with no padding when padding is none', () => {
77
- const { container } = renderWithTheme(
78
- <Card padding="none">
79
- <span>Content</span>
80
- </Card>,
81
- );
82
- expect(container.firstChild).toHaveStyle({ padding: 0 });
83
- });
84
-
85
- it('centers content when textAlign is center', () => {
86
- const { container } = renderWithTheme(
87
- <Card textAlign="center">
88
- <span>Content</span>
89
- </Card>,
90
- );
91
- expect(container.firstChild).toHaveStyle({ alignItems: 'center' });
92
- });
93
-
94
- it('aligns content to flex-end when textAlign is end', () => {
95
- const { container } = renderWithTheme(
96
- <Card textAlign="end">
97
- <span>Content</span>
98
- </Card>,
99
- );
100
- expect(container.firstChild).toHaveStyle({ alignItems: 'flex-end' });
101
- });
102
- });
@@ -1,51 +0,0 @@
1
- import React from 'react';
2
- import type { Meta, StoryObj } from '@storybook/react';
3
- import { ThemeProvider } from '../../../native/ThemeContext';
4
- import { Card } from './Card.native';
5
- import { Typography } from '../../ui/Typography/Typography.native';
6
-
7
- const meta = {
8
- tags: ['!stable', 'alpha'],
9
- title: 'React Native/Layout/Card',
10
- component: Card,
11
- decorators: [(Story) => <ThemeProvider colorScheme="light"><Story /></ThemeProvider>],
12
- parameters: { layout: 'padded' },
13
- argTypes: {
14
- variant: { control: 'select', options: ['default', 'elevated', 'outlined'] },
15
- padding: { control: 'select', options: ['none', 'small', 'medium', 'large'] },
16
- textAlign: { control: 'select', options: ['start', 'center', 'end'] },
17
- },
18
- } satisfies Meta<typeof Card>;
19
-
20
- export default meta;
21
- type Story = StoryObj<typeof meta>;
22
-
23
- export const Default: Story = {
24
- args: { children: <Typography>Card content goes here.</Typography>, variant: 'default', padding: 'medium' },
25
- };
26
- export const Elevated: Story = {
27
- args: { children: <Typography>Elevated card with shadow.</Typography>, variant: 'elevated', padding: 'medium' },
28
- };
29
- export const Outlined: Story = {
30
- args: { children: <Typography>Outlined card with border.</Typography>, variant: 'outlined', padding: 'medium' },
31
- };
32
- export const Pressable: Story = {
33
- args: {
34
- children: <Typography>Tap me!</Typography>,
35
- variant: 'outlined',
36
- padding: 'medium',
37
- onPress: () => {},
38
- },
39
- };
40
- export const AllVariants: Story = {
41
- render: () => (
42
- <div style={{ display: 'flex', flexDirection: 'column', gap: '12px', maxWidth: 320 }}>
43
- {(['default', 'elevated', 'outlined'] as const).map(v => (
44
- <Card key={v} variant={v} padding="medium">
45
- <Typography variant="h3">{v.charAt(0).toUpperCase() + v.slice(1)}</Typography>
46
- <Typography>Card with {v} variant.</Typography>
47
- </Card>
48
- ))}
49
- </div>
50
- ),
51
- };