@boostdev/design-system-components 2.4.1 → 2.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +4 -20
- package/README.md +3 -23
- package/dist/client.cjs +128 -62
- package/dist/client.css +537 -537
- package/dist/client.d.cts +11 -1
- package/dist/client.d.ts +11 -1
- package/dist/client.js +128 -62
- package/dist/index.cjs +128 -62
- package/dist/index.css +537 -537
- package/dist/index.d.cts +11 -1
- package/dist/index.d.ts +11 -1
- package/dist/index.js +128 -62
- package/dist/web-components/index.js +36 -4
- package/package.json +2 -10
- package/src/components/layout/Grid/Grid.mdx +20 -2
- package/src/components/layout/Grid/Grid.spec.tsx +206 -4
- package/src/components/layout/Grid/Grid.tsx +15 -1
- package/src/components/layout/Grid/masonry.ts +148 -10
- package/dist/native/index.cjs +0 -4337
- package/dist/native/index.d.cts +0 -574
- package/dist/native/index.d.ts +0 -574
- package/dist/native/index.js +0 -4421
- package/src/components/interaction/Button/Button.native.mdx +0 -91
- package/src/components/interaction/Button/Button.native.spec.tsx +0 -55
- package/src/components/interaction/Button/Button.native.stories.tsx +0 -141
- package/src/components/interaction/Button/Button.native.tsx +0 -105
- package/src/components/interaction/Dialog/Dialog.native.mdx +0 -61
- package/src/components/interaction/Dialog/Dialog.native.spec.tsx +0 -73
- package/src/components/interaction/Dialog/Dialog.native.stories.tsx +0 -53
- package/src/components/interaction/Dialog/Dialog.native.tsx +0 -128
- package/src/components/interaction/Drawer/Drawer.native.mdx +0 -58
- package/src/components/interaction/Drawer/Drawer.native.spec.tsx +0 -81
- package/src/components/interaction/Drawer/Drawer.native.stories.tsx +0 -33
- package/src/components/interaction/Drawer/Drawer.native.tsx +0 -175
- package/src/components/interaction/DropdownMenu/DropdownMenu.native.mdx +0 -74
- package/src/components/interaction/DropdownMenu/DropdownMenu.native.spec.tsx +0 -78
- package/src/components/interaction/DropdownMenu/DropdownMenu.native.stories.tsx +0 -51
- package/src/components/interaction/DropdownMenu/DropdownMenu.native.tsx +0 -254
- package/src/components/interaction/Popover/Popover.native.mdx +0 -61
- package/src/components/interaction/Popover/Popover.native.spec.tsx +0 -73
- package/src/components/interaction/Popover/Popover.native.stories.tsx +0 -44
- package/src/components/interaction/Popover/Popover.native.tsx +0 -87
- package/src/components/interaction/Rating/Rating.native.mdx +0 -55
- package/src/components/interaction/Rating/Rating.native.spec.tsx +0 -38
- package/src/components/interaction/Rating/Rating.native.stories.tsx +0 -37
- package/src/components/interaction/Rating/Rating.native.tsx +0 -50
- package/src/components/interaction/Toast/Toast.native.mdx +0 -81
- package/src/components/interaction/Toast/Toast.native.spec.tsx +0 -80
- package/src/components/interaction/Toast/Toast.native.stories.tsx +0 -47
- package/src/components/interaction/Toast/Toast.native.tsx +0 -202
- package/src/components/interaction/form/Checkbox/Checkbox.native.mdx +0 -74
- package/src/components/interaction/form/Checkbox/Checkbox.native.spec.tsx +0 -42
- package/src/components/interaction/form/Checkbox/Checkbox.native.stories.tsx +0 -34
- package/src/components/interaction/form/Checkbox/Checkbox.native.tsx +0 -80
- package/src/components/interaction/form/CheckboxGroup/CheckboxGroup.native.mdx +0 -78
- package/src/components/interaction/form/CheckboxGroup/CheckboxGroup.native.spec.tsx +0 -57
- package/src/components/interaction/form/CheckboxGroup/CheckboxGroup.native.stories.tsx +0 -96
- package/src/components/interaction/form/CheckboxGroup/CheckboxGroup.native.tsx +0 -61
- package/src/components/interaction/form/Combobox/Combobox.native.mdx +0 -86
- package/src/components/interaction/form/Combobox/Combobox.native.spec.tsx +0 -60
- package/src/components/interaction/form/Combobox/Combobox.native.stories.tsx +0 -99
- package/src/components/interaction/form/Combobox/Combobox.native.tsx +0 -211
- package/src/components/interaction/form/FileInput/FileInput.native.mdx +0 -86
- package/src/components/interaction/form/FileInput/FileInput.native.spec.tsx +0 -73
- package/src/components/interaction/form/FileInput/FileInput.native.stories.tsx +0 -69
- package/src/components/interaction/form/FileInput/FileInput.native.tsx +0 -129
- package/src/components/interaction/form/FormInput/FormInput.native.mdx +0 -81
- package/src/components/interaction/form/FormInput/FormInput.native.spec.tsx +0 -51
- package/src/components/interaction/form/FormInput/FormInput.native.stories.tsx +0 -54
- package/src/components/interaction/form/FormInput/FormInput.native.tsx +0 -122
- package/src/components/interaction/form/NumberInput/NumberInput.native.mdx +0 -87
- package/src/components/interaction/form/NumberInput/NumberInput.native.spec.tsx +0 -63
- package/src/components/interaction/form/NumberInput/NumberInput.native.stories.tsx +0 -63
- package/src/components/interaction/form/NumberInput/NumberInput.native.tsx +0 -198
- package/src/components/interaction/form/Radio/Radio.native.spec.tsx +0 -79
- package/src/components/interaction/form/Radio/Radio.native.stories.tsx +0 -44
- package/src/components/interaction/form/Radio/Radio.native.tsx +0 -79
- package/src/components/interaction/form/RadioGroup/RadioGroup.native.mdx +0 -79
- package/src/components/interaction/form/RadioGroup/RadioGroup.native.spec.tsx +0 -66
- package/src/components/interaction/form/RadioGroup/RadioGroup.native.stories.tsx +0 -96
- package/src/components/interaction/form/RadioGroup/RadioGroup.native.tsx +0 -61
- package/src/components/interaction/form/SegmentedControl/SegmentedControl.native.mdx +0 -78
- package/src/components/interaction/form/SegmentedControl/SegmentedControl.native.spec.tsx +0 -82
- package/src/components/interaction/form/SegmentedControl/SegmentedControl.native.stories.tsx +0 -99
- package/src/components/interaction/form/SegmentedControl/SegmentedControl.native.tsx +0 -121
- package/src/components/interaction/form/Select/Select.native.mdx +0 -85
- package/src/components/interaction/form/Select/Select.native.spec.tsx +0 -64
- package/src/components/interaction/form/Select/Select.native.stories.tsx +0 -75
- package/src/components/interaction/form/Select/Select.native.tsx +0 -252
- package/src/components/interaction/form/Slider/Slider.native.mdx +0 -83
- package/src/components/interaction/form/Slider/Slider.native.spec.tsx +0 -51
- package/src/components/interaction/form/Slider/Slider.native.stories.tsx +0 -58
- package/src/components/interaction/form/Slider/Slider.native.tsx +0 -188
- package/src/components/interaction/form/Switch/Switch.native.spec.tsx +0 -60
- package/src/components/interaction/form/Switch/Switch.native.stories.tsx +0 -33
- package/src/components/interaction/form/Switch/Switch.native.tsx +0 -59
- package/src/components/interaction/form/Textarea/Textarea.native.mdx +0 -76
- package/src/components/interaction/form/Textarea/Textarea.native.spec.tsx +0 -50
- package/src/components/interaction/form/Textarea/Textarea.native.stories.tsx +0 -50
- package/src/components/interaction/form/Textarea/Textarea.native.tsx +0 -108
- package/src/components/interaction/form/atoms/Label.native.spec.tsx +0 -39
- package/src/components/interaction/form/atoms/Label.native.stories.tsx +0 -18
- package/src/components/interaction/form/atoms/Label.native.tsx +0 -29
- package/src/components/interaction/form/atoms/Message.native.spec.tsx +0 -30
- package/src/components/interaction/form/atoms/Message.native.stories.tsx +0 -22
- package/src/components/interaction/form/atoms/Message.native.tsx +0 -34
- package/src/components/layout/ButtonGroup/ButtonGroup.native.spec.tsx +0 -83
- package/src/components/layout/ButtonGroup/ButtonGroup.native.stories.tsx +0 -44
- package/src/components/layout/ButtonGroup/ButtonGroup.native.tsx +0 -44
- package/src/components/layout/Card/Card.native.spec.tsx +0 -102
- package/src/components/layout/Card/Card.native.stories.tsx +0 -51
- package/src/components/layout/Card/Card.native.tsx +0 -89
- package/src/components/layout/IconWrapper/IconWrapper.native.spec.tsx +0 -39
- package/src/components/layout/IconWrapper/IconWrapper.native.stories.tsx +0 -37
- package/src/components/layout/IconWrapper/IconWrapper.native.tsx +0 -20
- package/src/components/layout/SectionHeader/SectionHeader.native.spec.tsx +0 -51
- package/src/components/layout/SectionHeader/SectionHeader.native.stories.tsx +0 -36
- package/src/components/layout/SectionHeader/SectionHeader.native.tsx +0 -79
- package/src/components/ui/Accordion/Accordion.native.mdx +0 -65
- package/src/components/ui/Accordion/Accordion.native.spec.tsx +0 -69
- package/src/components/ui/Accordion/Accordion.native.stories.tsx +0 -52
- package/src/components/ui/Accordion/Accordion.native.tsx +0 -141
- package/src/components/ui/Alert/Alert.native.mdx +0 -62
- package/src/components/ui/Alert/Alert.native.spec.tsx +0 -76
- package/src/components/ui/Alert/Alert.native.stories.tsx +0 -41
- package/src/components/ui/Alert/Alert.native.tsx +0 -94
- package/src/components/ui/Avatar/Avatar.native.mdx +0 -50
- package/src/components/ui/Avatar/Avatar.native.spec.tsx +0 -47
- package/src/components/ui/Avatar/Avatar.native.stories.tsx +0 -32
- package/src/components/ui/Avatar/Avatar.native.tsx +0 -85
- package/src/components/ui/Badge/Badge.native.mdx +0 -54
- package/src/components/ui/Badge/Badge.native.spec.tsx +0 -45
- package/src/components/ui/Badge/Badge.native.stories.tsx +0 -34
- package/src/components/ui/Badge/Badge.native.tsx +0 -50
- package/src/components/ui/Breadcrumb/Breadcrumb.native.mdx +0 -52
- package/src/components/ui/Breadcrumb/Breadcrumb.native.spec.tsx +0 -49
- package/src/components/ui/Breadcrumb/Breadcrumb.native.stories.tsx +0 -46
- package/src/components/ui/Breadcrumb/Breadcrumb.native.tsx +0 -83
- package/src/components/ui/Calendar/Calendar.native.mdx +0 -58
- package/src/components/ui/Calendar/Calendar.native.spec.tsx +0 -92
- package/src/components/ui/Calendar/Calendar.native.stories.tsx +0 -45
- package/src/components/ui/Calendar/Calendar.native.tsx +0 -294
- package/src/components/ui/Carousel/Carousel.native.mdx +0 -55
- package/src/components/ui/Carousel/Carousel.native.spec.tsx +0 -55
- package/src/components/ui/Carousel/Carousel.native.stories.tsx +0 -59
- package/src/components/ui/Carousel/Carousel.native.tsx +0 -184
- package/src/components/ui/Collapsible/Collapsible.native.mdx +0 -53
- package/src/components/ui/Collapsible/Collapsible.native.spec.tsx +0 -68
- package/src/components/ui/Collapsible/Collapsible.native.stories.tsx +0 -48
- package/src/components/ui/Collapsible/Collapsible.native.tsx +0 -139
- package/src/components/ui/DescriptionList/DescriptionList.native.mdx +0 -50
- package/src/components/ui/DescriptionList/DescriptionList.native.spec.tsx +0 -37
- package/src/components/ui/DescriptionList/DescriptionList.native.stories.tsx +0 -48
- package/src/components/ui/DescriptionList/DescriptionList.native.tsx +0 -54
- package/src/components/ui/Link/Link.native.mdx +0 -53
- package/src/components/ui/Link/Link.native.spec.tsx +0 -35
- package/src/components/ui/Link/Link.native.stories.tsx +0 -46
- package/src/components/ui/Link/Link.native.tsx +0 -48
- package/src/components/ui/Loading/Loading.native.spec.tsx +0 -24
- package/src/components/ui/Loading/Loading.native.stories.tsx +0 -31
- package/src/components/ui/Loading/Loading.native.tsx +0 -29
- package/src/components/ui/NotificationBanner/NotificationBanner.native.spec.tsx +0 -85
- package/src/components/ui/NotificationBanner/NotificationBanner.native.stories.tsx +0 -37
- package/src/components/ui/NotificationBanner/NotificationBanner.native.tsx +0 -76
- package/src/components/ui/Pagination/Pagination.native.mdx +0 -62
- package/src/components/ui/Pagination/Pagination.native.spec.tsx +0 -86
- package/src/components/ui/Pagination/Pagination.native.stories.tsx +0 -47
- package/src/components/ui/Pagination/Pagination.native.tsx +0 -157
- package/src/components/ui/Progress/Progress.native.spec.tsx +0 -56
- package/src/components/ui/Progress/Progress.native.stories.tsx +0 -34
- package/src/components/ui/Progress/Progress.native.tsx +0 -84
- package/src/components/ui/ProgressCircle/ProgressCircle.native.mdx +0 -63
- package/src/components/ui/ProgressCircle/ProgressCircle.native.spec.tsx +0 -39
- package/src/components/ui/ProgressCircle/ProgressCircle.native.stories.tsx +0 -36
- package/src/components/ui/ProgressCircle/ProgressCircle.native.tsx +0 -176
- package/src/components/ui/Separator/Separator.native.spec.tsx +0 -39
- package/src/components/ui/Separator/Separator.native.stories.tsx +0 -38
- package/src/components/ui/Separator/Separator.native.tsx +0 -32
- package/src/components/ui/Skeleton/Skeleton.native.spec.tsx +0 -39
- package/src/components/ui/Skeleton/Skeleton.native.stories.tsx +0 -31
- package/src/components/ui/Skeleton/Skeleton.native.tsx +0 -42
- package/src/components/ui/Table/Table.native.mdx +0 -72
- package/src/components/ui/Table/Table.native.spec.tsx +0 -83
- package/src/components/ui/Table/Table.native.stories.tsx +0 -55
- package/src/components/ui/Table/Table.native.tsx +0 -196
- package/src/components/ui/Tabs/Tabs.native.mdx +0 -65
- package/src/components/ui/Tabs/Tabs.native.spec.tsx +0 -65
- package/src/components/ui/Tabs/Tabs.native.stories.tsx +0 -57
- package/src/components/ui/Tabs/Tabs.native.tsx +0 -133
- package/src/components/ui/Tooltip/Tooltip.native.mdx +0 -47
- package/src/components/ui/Tooltip/Tooltip.native.spec.tsx +0 -37
- package/src/components/ui/Tooltip/Tooltip.native.stories.tsx +0 -38
- package/src/components/ui/Tooltip/Tooltip.native.tsx +0 -57
- package/src/components/ui/Typography/Typography.native.mdx +0 -56
- package/src/components/ui/Typography/Typography.native.spec.tsx +0 -49
- package/src/components/ui/Typography/Typography.native.stories.tsx +0 -36
- package/src/components/ui/Typography/Typography.native.tsx +0 -65
- package/src/native/ThemeContext.tsx +0 -28
- package/src/native/tokens.ts +0 -13
- package/src/native.ts +0 -76
- package/src/stories/ReactNative.mdx +0 -156
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
import { Meta, Canvas, ArgTypes } from '@storybook/blocks';
|
|
2
|
-
import * as Stories from './Breadcrumb.native.stories';
|
|
3
|
-
|
|
4
|
-
<Meta of={Stories} />
|
|
5
|
-
|
|
6
|
-
# Breadcrumb (React Native)
|
|
7
|
-
|
|
8
|
-
React Native breadcrumb navigation showing the user's location within a hierarchy. Items are separated by "/" and the last item is non-interactive (current page).
|
|
9
|
-
|
|
10
|
-
> **Status: alpha** — API may change before stable release.
|
|
11
|
-
|
|
12
|
-
## Usage
|
|
13
|
-
|
|
14
|
-
```tsx
|
|
15
|
-
import { Breadcrumb } from '@boostdev/design-system-components';
|
|
16
|
-
|
|
17
|
-
<Breadcrumb
|
|
18
|
-
items={[
|
|
19
|
-
{ label: 'Home', onPress: () => navigation.navigate('Home') },
|
|
20
|
-
{ label: 'Products', onPress: () => navigation.navigate('Products') },
|
|
21
|
-
{ label: 'Shoes' },
|
|
22
|
-
]}
|
|
23
|
-
/>
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
## Examples
|
|
27
|
-
|
|
28
|
-
### Default
|
|
29
|
-
<Canvas of={Stories.Default} />
|
|
30
|
-
|
|
31
|
-
### Two items
|
|
32
|
-
<Canvas of={Stories.TwoItems} />
|
|
33
|
-
|
|
34
|
-
### Many items
|
|
35
|
-
<Canvas of={Stories.ManyItems} />
|
|
36
|
-
|
|
37
|
-
## Props
|
|
38
|
-
|
|
39
|
-
<ArgTypes of={Stories} />
|
|
40
|
-
|
|
41
|
-
## Props reference
|
|
42
|
-
|
|
43
|
-
| Prop | Type | Default | Description |
|
|
44
|
-
|------|------|---------|-------------|
|
|
45
|
-
| `items` | `Array<{ label: string, onPress?: () => void }>` | — | Breadcrumb items; last item is current page |
|
|
46
|
-
| `style` | `StyleProp<ViewStyle>` | — | Override container styles |
|
|
47
|
-
|
|
48
|
-
## Accessibility
|
|
49
|
-
|
|
50
|
-
- Container uses `accessibilityRole="navigation"` with `accessibilityLabel="Breadcrumb"`
|
|
51
|
-
- Interactive items use `accessibilityRole="link"`
|
|
52
|
-
- Separator characters are hidden from assistive technologies
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
import { render, screen, fireEvent } from '@testing-library/react';
|
|
2
|
-
import { ThemeProvider } from '../../../native/ThemeContext';
|
|
3
|
-
import { Breadcrumb } from './Breadcrumb.native';
|
|
4
|
-
|
|
5
|
-
function renderWithTheme(ui: React.ReactElement) {
|
|
6
|
-
return render(<ThemeProvider>{ui}</ThemeProvider>);
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
describe('Breadcrumb (native)', () => {
|
|
10
|
-
const items = [
|
|
11
|
-
{ label: 'Home', onPress: vi.fn() },
|
|
12
|
-
{ label: 'Products', onPress: vi.fn() },
|
|
13
|
-
{ label: 'Shoes' },
|
|
14
|
-
];
|
|
15
|
-
|
|
16
|
-
it('has navigation role with Breadcrumb label', () => {
|
|
17
|
-
renderWithTheme(<Breadcrumb items={items} />);
|
|
18
|
-
expect(screen.getByRole('navigation', { name: 'Breadcrumb' })).toBeInTheDocument();
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
it('renders all item labels', () => {
|
|
22
|
-
renderWithTheme(<Breadcrumb items={items} />);
|
|
23
|
-
expect(screen.getByText('Home')).toBeInTheDocument();
|
|
24
|
-
expect(screen.getByText('Products')).toBeInTheDocument();
|
|
25
|
-
expect(screen.getByText('Shoes')).toBeInTheDocument();
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
it('renders separator characters between items', () => {
|
|
29
|
-
renderWithTheme(<Breadcrumb items={items} />);
|
|
30
|
-
const separators = screen.getAllByText('/');
|
|
31
|
-
expect(separators).toHaveLength(2);
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
it('calls onPress when an interactive item is pressed', () => {
|
|
35
|
-
const onPress = vi.fn();
|
|
36
|
-
renderWithTheme(
|
|
37
|
-
<Breadcrumb items={[{ label: 'Home', onPress }, { label: 'Current' }]} />,
|
|
38
|
-
);
|
|
39
|
-
fireEvent.click(screen.getByRole('link'));
|
|
40
|
-
expect(onPress).toHaveBeenCalledTimes(1);
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
it('renders last item as non-interactive text', () => {
|
|
44
|
-
renderWithTheme(<Breadcrumb items={items} />);
|
|
45
|
-
const links = screen.getAllByRole('link');
|
|
46
|
-
const linkTexts = links.map(l => l.textContent);
|
|
47
|
-
expect(linkTexts).not.toContain('Shoes');
|
|
48
|
-
});
|
|
49
|
-
});
|
|
@@ -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 { Breadcrumb } from './Breadcrumb.native';
|
|
5
|
-
|
|
6
|
-
const meta = {
|
|
7
|
-
tags: ['!stable', 'alpha'],
|
|
8
|
-
title: 'React Native/UI/Breadcrumb',
|
|
9
|
-
component: Breadcrumb,
|
|
10
|
-
decorators: [(Story) => <ThemeProvider colorScheme="light"><Story /></ThemeProvider>],
|
|
11
|
-
parameters: { layout: 'padded' },
|
|
12
|
-
} satisfies Meta<typeof Breadcrumb>;
|
|
13
|
-
|
|
14
|
-
export default meta;
|
|
15
|
-
type Story = StoryObj<typeof meta>;
|
|
16
|
-
|
|
17
|
-
export const Default: Story = {
|
|
18
|
-
args: {
|
|
19
|
-
items: [
|
|
20
|
-
{ label: 'Home', onPress: () => {} },
|
|
21
|
-
{ label: 'Products', onPress: () => {} },
|
|
22
|
-
{ label: 'Shoes' },
|
|
23
|
-
],
|
|
24
|
-
},
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
export const TwoItems: Story = {
|
|
28
|
-
args: {
|
|
29
|
-
items: [
|
|
30
|
-
{ label: 'Home', onPress: () => {} },
|
|
31
|
-
{ label: 'Settings' },
|
|
32
|
-
],
|
|
33
|
-
},
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
export const ManyItems: Story = {
|
|
37
|
-
args: {
|
|
38
|
-
items: [
|
|
39
|
-
{ label: 'Home', onPress: () => {} },
|
|
40
|
-
{ label: 'Category', onPress: () => {} },
|
|
41
|
-
{ label: 'Subcategory', onPress: () => {} },
|
|
42
|
-
{ label: 'Product', onPress: () => {} },
|
|
43
|
-
{ label: 'Details' },
|
|
44
|
-
],
|
|
45
|
-
},
|
|
46
|
-
};
|
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
import { AccessibilityRole, StyleSheet, View, Text, Pressable, StyleProp, ViewStyle } from 'react-native';
|
|
2
|
-
import { spacing, font, lineHeight } from '../../../native/tokens';
|
|
3
|
-
import { useTheme } from '../../../native/ThemeContext';
|
|
4
|
-
|
|
5
|
-
export interface BreadcrumbItem {
|
|
6
|
-
label: string;
|
|
7
|
-
onPress?: () => void;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
interface BreadcrumbProps {
|
|
11
|
-
items: BreadcrumbItem[];
|
|
12
|
-
style?: StyleProp<ViewStyle>;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
const styles = StyleSheet.create({
|
|
16
|
-
container: {
|
|
17
|
-
flexDirection: 'row',
|
|
18
|
-
flexWrap: 'wrap',
|
|
19
|
-
alignItems: 'center',
|
|
20
|
-
},
|
|
21
|
-
separator: {
|
|
22
|
-
marginHorizontal: spacing.xs,
|
|
23
|
-
fontSize: font.size.body,
|
|
24
|
-
fontFamily: font.family.body,
|
|
25
|
-
lineHeight: lineHeight.body,
|
|
26
|
-
},
|
|
27
|
-
itemText: {
|
|
28
|
-
fontSize: font.size.body,
|
|
29
|
-
fontFamily: font.family.body,
|
|
30
|
-
lineHeight: lineHeight.body,
|
|
31
|
-
},
|
|
32
|
-
pressed: {
|
|
33
|
-
opacity: 0.75,
|
|
34
|
-
},
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
export function Breadcrumb({ items, style }: Readonly<BreadcrumbProps>) {
|
|
38
|
-
const { colors } = useTheme();
|
|
39
|
-
|
|
40
|
-
return (
|
|
41
|
-
<View
|
|
42
|
-
style={[styles.container, style]}
|
|
43
|
-
accessibilityRole={'navigation' as AccessibilityRole}
|
|
44
|
-
accessibilityLabel="Breadcrumb"
|
|
45
|
-
>
|
|
46
|
-
{items.map((item, index) => {
|
|
47
|
-
const isLast = index === items.length - 1;
|
|
48
|
-
|
|
49
|
-
return (
|
|
50
|
-
<View key={index} style={{ flexDirection: 'row', alignItems: 'center', minHeight: 44 }}>
|
|
51
|
-
{isLast ? (
|
|
52
|
-
<Text
|
|
53
|
-
style={[styles.itemText, { color: colors.colorOnBg }]}
|
|
54
|
-
accessibilityRole="text"
|
|
55
|
-
>
|
|
56
|
-
{item.label}
|
|
57
|
-
</Text>
|
|
58
|
-
) : (
|
|
59
|
-
<>
|
|
60
|
-
<Pressable
|
|
61
|
-
onPress={item.onPress}
|
|
62
|
-
accessibilityRole="link"
|
|
63
|
-
style={({ pressed }) => pressed && styles.pressed}
|
|
64
|
-
>
|
|
65
|
-
<Text style={[styles.itemText, { color: colors.colorInteractiveOnBg }]}>
|
|
66
|
-
{item.label}
|
|
67
|
-
</Text>
|
|
68
|
-
</Pressable>
|
|
69
|
-
<Text
|
|
70
|
-
style={[styles.separator, { color: colors.colorOnBgSubtle }]}
|
|
71
|
-
importantForAccessibility="no"
|
|
72
|
-
accessibilityElementsHidden={true}
|
|
73
|
-
>
|
|
74
|
-
/
|
|
75
|
-
</Text>
|
|
76
|
-
</>
|
|
77
|
-
)}
|
|
78
|
-
</View>
|
|
79
|
-
);
|
|
80
|
-
})}
|
|
81
|
-
</View>
|
|
82
|
-
);
|
|
83
|
-
}
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
import { Meta, Canvas, ArgTypes } from '@storybook/blocks';
|
|
2
|
-
import * as Stories from './Calendar.native.stories';
|
|
3
|
-
|
|
4
|
-
<Meta of={Stories} />
|
|
5
|
-
|
|
6
|
-
# Calendar (React Native)
|
|
7
|
-
|
|
8
|
-
React Native calendar component for date selection. Renders a month grid with Previous/Next navigation, day-of-week headers, and a 6x7 day grid. Supports controlled and uncontrolled modes, and optional min/max date constraints.
|
|
9
|
-
|
|
10
|
-
> **Status: alpha** -- API may change before stable release.
|
|
11
|
-
|
|
12
|
-
## Usage
|
|
13
|
-
|
|
14
|
-
```tsx
|
|
15
|
-
import { Calendar } from '@boostdev/design-system-components';
|
|
16
|
-
|
|
17
|
-
<Calendar
|
|
18
|
-
defaultValue={new Date(2026, 3, 15)}
|
|
19
|
-
onChange={(date) => console.log(date)}
|
|
20
|
-
/>
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
## Examples
|
|
24
|
-
|
|
25
|
-
### Default
|
|
26
|
-
<Canvas of={Stories.Default} />
|
|
27
|
-
|
|
28
|
-
### With default value
|
|
29
|
-
<Canvas of={Stories.WithDefaultValue} />
|
|
30
|
-
|
|
31
|
-
### With min/max range
|
|
32
|
-
<Canvas of={Stories.WithMinMax} />
|
|
33
|
-
|
|
34
|
-
### Controlled
|
|
35
|
-
<Canvas of={Stories.Controlled} />
|
|
36
|
-
|
|
37
|
-
## Props
|
|
38
|
-
|
|
39
|
-
<ArgTypes of={Stories} />
|
|
40
|
-
|
|
41
|
-
## Props reference
|
|
42
|
-
|
|
43
|
-
| Prop | Type | Default | Description |
|
|
44
|
-
|------|------|---------|-------------|
|
|
45
|
-
| `value` | `Date` | -- | Controlled selected date |
|
|
46
|
-
| `defaultValue` | `Date` | -- | Uncontrolled initial selected date |
|
|
47
|
-
| `min` | `Date` | -- | Earliest selectable date |
|
|
48
|
-
| `max` | `Date` | -- | Latest selectable date |
|
|
49
|
-
| `onChange` | `(date: Date) => void` | -- | Called when a date is selected |
|
|
50
|
-
| `style` | `StyleProp<ViewStyle>` | -- | Custom style for the container |
|
|
51
|
-
|
|
52
|
-
## Accessibility
|
|
53
|
-
|
|
54
|
-
- Month/year header uses `polite` live region to announce month changes
|
|
55
|
-
- Each day button has a descriptive label (e.g. "April 15, 2026")
|
|
56
|
-
- Selected and disabled states are exposed via accessibility state
|
|
57
|
-
- Today's date is visually distinguished with a border
|
|
58
|
-
- Disabled (out-of-range) dates have reduced opacity
|
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
import { render, screen, fireEvent } from '@testing-library/react';
|
|
2
|
-
import { ThemeProvider } from '../../../native/ThemeContext';
|
|
3
|
-
import { Calendar } from './Calendar.native';
|
|
4
|
-
|
|
5
|
-
function renderWithTheme(ui: React.ReactElement) {
|
|
6
|
-
return render(<ThemeProvider>{ui}</ThemeProvider>);
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
describe('Calendar (native)', () => {
|
|
10
|
-
it('renders the month and year header', () => {
|
|
11
|
-
renderWithTheme(<Calendar defaultValue={new Date(2026, 3, 15)} />);
|
|
12
|
-
expect(screen.getByText('April 2026')).toBeInTheDocument();
|
|
13
|
-
});
|
|
14
|
-
|
|
15
|
-
it('renders day-of-week headers', () => {
|
|
16
|
-
renderWithTheme(<Calendar />);
|
|
17
|
-
expect(screen.getByText('Su')).toBeInTheDocument();
|
|
18
|
-
expect(screen.getByText('Mo')).toBeInTheDocument();
|
|
19
|
-
expect(screen.getByText('Fr')).toBeInTheDocument();
|
|
20
|
-
expect(screen.getByText('Sa')).toBeInTheDocument();
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
it('renders day numbers for the current month', () => {
|
|
24
|
-
renderWithTheme(<Calendar defaultValue={new Date(2026, 3, 1)} />);
|
|
25
|
-
expect(screen.getByText('1')).toBeInTheDocument();
|
|
26
|
-
expect(screen.getByText('15')).toBeInTheDocument();
|
|
27
|
-
expect(screen.getByText('30')).toBeInTheDocument();
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
it('renders the selected date button', () => {
|
|
31
|
-
renderWithTheme(<Calendar defaultValue={new Date(2026, 3, 10)} />);
|
|
32
|
-
expect(
|
|
33
|
-
screen.getByRole('button', { name: 'April 10, 2026' }),
|
|
34
|
-
).toBeInTheDocument();
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
it('calls onChange when a date is pressed', () => {
|
|
38
|
-
const onChange = vi.fn();
|
|
39
|
-
renderWithTheme(
|
|
40
|
-
<Calendar defaultValue={new Date(2026, 3, 1)} onChange={onChange} />,
|
|
41
|
-
);
|
|
42
|
-
fireEvent.click(screen.getByRole('button', { name: 'April 15, 2026' }));
|
|
43
|
-
expect(onChange).toHaveBeenCalledTimes(1);
|
|
44
|
-
const selectedDate = onChange.mock.calls[0][0] as Date;
|
|
45
|
-
expect(selectedDate.getDate()).toBe(15);
|
|
46
|
-
expect(selectedDate.getMonth()).toBe(3);
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
it('navigates to the previous month', () => {
|
|
50
|
-
renderWithTheme(<Calendar defaultValue={new Date(2026, 3, 15)} />);
|
|
51
|
-
fireEvent.click(screen.getByRole('button', { name: 'Previous month' }));
|
|
52
|
-
expect(screen.getByText('March 2026')).toBeInTheDocument();
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
it('navigates to the next month', () => {
|
|
56
|
-
renderWithTheme(<Calendar defaultValue={new Date(2026, 3, 15)} />);
|
|
57
|
-
fireEvent.click(screen.getByRole('button', { name: 'Next month' }));
|
|
58
|
-
expect(screen.getByText('May 2026')).toBeInTheDocument();
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
it('disables dates outside min/max range', () => {
|
|
62
|
-
renderWithTheme(
|
|
63
|
-
<Calendar
|
|
64
|
-
defaultValue={new Date(2026, 3, 10)}
|
|
65
|
-
min={new Date(2026, 3, 5)}
|
|
66
|
-
max={new Date(2026, 3, 20)}
|
|
67
|
-
/>,
|
|
68
|
-
);
|
|
69
|
-
expect(
|
|
70
|
-
screen.getByRole('button', { name: 'April 3, 2026' }),
|
|
71
|
-
).toHaveAttribute('aria-disabled', 'true');
|
|
72
|
-
expect(
|
|
73
|
-
screen.getByRole('button', { name: 'April 25, 2026' }),
|
|
74
|
-
).toHaveAttribute('aria-disabled', 'true');
|
|
75
|
-
expect(
|
|
76
|
-
screen.getByRole('button', { name: 'April 10, 2026' }),
|
|
77
|
-
).not.toHaveAttribute('aria-disabled', 'true');
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
it('does not call onChange for disabled dates', () => {
|
|
81
|
-
const onChange = vi.fn();
|
|
82
|
-
renderWithTheme(
|
|
83
|
-
<Calendar
|
|
84
|
-
defaultValue={new Date(2026, 3, 10)}
|
|
85
|
-
min={new Date(2026, 3, 5)}
|
|
86
|
-
onChange={onChange}
|
|
87
|
-
/>,
|
|
88
|
-
);
|
|
89
|
-
fireEvent.click(screen.getByRole('button', { name: 'April 3, 2026' }));
|
|
90
|
-
expect(onChange).not.toHaveBeenCalled();
|
|
91
|
-
});
|
|
92
|
-
});
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
import React, { useState } from 'react';
|
|
2
|
-
import type { Meta, StoryObj } from '@storybook/react';
|
|
3
|
-
import { ThemeProvider } from '../../../native/ThemeContext';
|
|
4
|
-
import { Calendar } from './Calendar.native';
|
|
5
|
-
|
|
6
|
-
const meta = {
|
|
7
|
-
tags: ['!stable', 'alpha'],
|
|
8
|
-
title: 'React Native/UI/Calendar',
|
|
9
|
-
component: Calendar,
|
|
10
|
-
decorators: [(Story) => <ThemeProvider colorScheme="light"><Story /></ThemeProvider>],
|
|
11
|
-
parameters: { layout: 'padded' },
|
|
12
|
-
} satisfies Meta<typeof Calendar>;
|
|
13
|
-
|
|
14
|
-
export default meta;
|
|
15
|
-
type Story = StoryObj<typeof meta>;
|
|
16
|
-
|
|
17
|
-
export const Default: Story = {
|
|
18
|
-
args: {},
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
export const WithDefaultValue: Story = {
|
|
22
|
-
args: {
|
|
23
|
-
defaultValue: new Date(2026, 3, 15),
|
|
24
|
-
},
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
export const WithMinMax: Story = {
|
|
28
|
-
args: {
|
|
29
|
-
defaultValue: new Date(2026, 3, 10),
|
|
30
|
-
min: new Date(2026, 3, 5),
|
|
31
|
-
max: new Date(2026, 3, 25),
|
|
32
|
-
},
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
function ControlledDemo() {
|
|
36
|
-
const [date, setDate] = useState(new Date(2026, 3, 6));
|
|
37
|
-
return (
|
|
38
|
-
<Calendar value={date} onChange={setDate} />
|
|
39
|
-
);
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
export const Controlled: Story = {
|
|
43
|
-
args: {},
|
|
44
|
-
render: () => <ControlledDemo />,
|
|
45
|
-
};
|