@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.
- package/AGENTS.md +4 -20
- package/README.md +3 -23
- package/dist/client.cjs +115 -61
- package/dist/client.css +537 -537
- package/dist/client.d.cts +11 -1
- package/dist/client.d.ts +11 -1
- package/dist/client.js +115 -61
- package/dist/index.cjs +115 -61
- package/dist/index.css +537 -537
- package/dist/index.d.cts +11 -1
- package/dist/index.d.ts +11 -1
- package/dist/index.js +115 -61
- package/dist/web-components/index.js +23 -3
- package/package.json +2 -10
- package/src/components/layout/Grid/Grid.mdx +20 -2
- package/src/components/layout/Grid/Grid.spec.tsx +194 -4
- package/src/components/layout/Grid/Grid.tsx +15 -1
- package/src/components/layout/Grid/masonry.ts +127 -9
- 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,29 +0,0 @@
|
|
|
1
|
-
import { ActivityIndicator, StyleProp, ViewStyle } from 'react-native';
|
|
2
|
-
import { useTheme } from '../../../native/ThemeContext';
|
|
3
|
-
|
|
4
|
-
type LoadingSize = 'small' | 'medium' | 'large';
|
|
5
|
-
|
|
6
|
-
interface LoadingProps {
|
|
7
|
-
size?: LoadingSize;
|
|
8
|
-
accessibilityLabel?: string;
|
|
9
|
-
style?: StyleProp<ViewStyle>;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
const rnSize: Record<LoadingSize, 'small' | 'large'> = {
|
|
13
|
-
small: 'small',
|
|
14
|
-
medium: 'large',
|
|
15
|
-
large: 'large',
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
export function Loading({ size = 'medium', accessibilityLabel = 'Loading', style }: LoadingProps) {
|
|
19
|
-
const { colors } = useTheme();
|
|
20
|
-
return (
|
|
21
|
-
<ActivityIndicator
|
|
22
|
-
size={rnSize[size]}
|
|
23
|
-
color={colors.colorInteractive}
|
|
24
|
-
style={style}
|
|
25
|
-
accessibilityRole="progressbar"
|
|
26
|
-
accessibilityLabel={accessibilityLabel}
|
|
27
|
-
/>
|
|
28
|
-
);
|
|
29
|
-
}
|
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
import { render, screen, fireEvent } from '@testing-library/react';
|
|
2
|
-
import { Text } from 'react-native';
|
|
3
|
-
import { ThemeProvider } from '../../../native/ThemeContext';
|
|
4
|
-
import { NotificationBanner } from './NotificationBanner.native';
|
|
5
|
-
|
|
6
|
-
function renderWithTheme(ui: React.ReactElement) {
|
|
7
|
-
return render(<ThemeProvider>{ui}</ThemeProvider>);
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
describe('NotificationBanner (native)', () => {
|
|
11
|
-
it('renders children text', () => {
|
|
12
|
-
renderWithTheme(<NotificationBanner>Update available</NotificationBanner>);
|
|
13
|
-
expect(screen.getByText('Update available')).toBeInTheDocument();
|
|
14
|
-
});
|
|
15
|
-
|
|
16
|
-
it('has alert role for error variant', () => {
|
|
17
|
-
renderWithTheme(
|
|
18
|
-
<NotificationBanner variant="error">Something went wrong</NotificationBanner>,
|
|
19
|
-
);
|
|
20
|
-
expect(screen.getByRole('alert')).toBeInTheDocument();
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
it('has alert role for warning variant', () => {
|
|
24
|
-
renderWithTheme(
|
|
25
|
-
<NotificationBanner variant="warning">Attention needed</NotificationBanner>,
|
|
26
|
-
);
|
|
27
|
-
expect(screen.getByRole('alert')).toBeInTheDocument();
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
it('does not have alert role for info variant', () => {
|
|
31
|
-
renderWithTheme(
|
|
32
|
-
<NotificationBanner variant="info">FYI</NotificationBanner>,
|
|
33
|
-
);
|
|
34
|
-
expect(screen.queryByRole('alert')).not.toBeInTheDocument();
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
it('does not have alert role for success variant', () => {
|
|
38
|
-
renderWithTheme(
|
|
39
|
-
<NotificationBanner variant="success">All good</NotificationBanner>,
|
|
40
|
-
);
|
|
41
|
-
expect(screen.queryByRole('alert')).not.toBeInTheDocument();
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
it('renders an action element when provided', () => {
|
|
45
|
-
renderWithTheme(
|
|
46
|
-
<NotificationBanner action={<Text>Retry</Text>}>
|
|
47
|
-
Failed to save
|
|
48
|
-
</NotificationBanner>,
|
|
49
|
-
);
|
|
50
|
-
expect(screen.getByText('Retry')).toBeInTheDocument();
|
|
51
|
-
expect(screen.getByText('Failed to save')).toBeInTheDocument();
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
it('renders a dismiss button when onDismiss is provided', () => {
|
|
55
|
-
renderWithTheme(
|
|
56
|
-
<NotificationBanner onDismiss={() => {}}>Dismissable</NotificationBanner>,
|
|
57
|
-
);
|
|
58
|
-
expect(
|
|
59
|
-
screen.getByRole('button', { name: 'Dismiss notification' }),
|
|
60
|
-
).toBeInTheDocument();
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
it('calls onDismiss when dismiss button is pressed', () => {
|
|
64
|
-
const onDismiss = vi.fn();
|
|
65
|
-
renderWithTheme(
|
|
66
|
-
<NotificationBanner onDismiss={onDismiss}>Dismissable</NotificationBanner>,
|
|
67
|
-
);
|
|
68
|
-
fireEvent.click(screen.getByRole('button', { name: 'Dismiss notification' }));
|
|
69
|
-
expect(onDismiss).toHaveBeenCalledTimes(1);
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
it('does not render a dismiss button when onDismiss is omitted', () => {
|
|
73
|
-
renderWithTheme(<NotificationBanner>No dismiss</NotificationBanner>);
|
|
74
|
-
expect(
|
|
75
|
-
screen.queryByRole('button', { name: 'Dismiss notification' }),
|
|
76
|
-
).not.toBeInTheDocument();
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
it('accepts custom style', () => {
|
|
80
|
-
renderWithTheme(
|
|
81
|
-
<NotificationBanner style={{ marginTop: 10 }}>Styled</NotificationBanner>,
|
|
82
|
-
);
|
|
83
|
-
expect(screen.getByText('Styled')).toBeInTheDocument();
|
|
84
|
-
});
|
|
85
|
-
});
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import type { Meta, StoryObj } from '@storybook/react';
|
|
3
|
-
import { ThemeProvider } from '../../../native/ThemeContext';
|
|
4
|
-
import { NotificationBanner } from './NotificationBanner.native';
|
|
5
|
-
|
|
6
|
-
const meta = {
|
|
7
|
-
tags: ['!stable', 'alpha'],
|
|
8
|
-
title: 'React Native/UI/NotificationBanner',
|
|
9
|
-
component: NotificationBanner,
|
|
10
|
-
decorators: [(Story) => <ThemeProvider colorScheme="light"><Story /></ThemeProvider>],
|
|
11
|
-
parameters: { layout: 'padded' },
|
|
12
|
-
argTypes: {
|
|
13
|
-
variant: { control: 'select', options: ['info', 'success', 'warning', 'error'] },
|
|
14
|
-
},
|
|
15
|
-
} satisfies Meta<typeof NotificationBanner>;
|
|
16
|
-
|
|
17
|
-
export default meta;
|
|
18
|
-
type Story = StoryObj<typeof meta>;
|
|
19
|
-
|
|
20
|
-
export const Info: Story = { args: { children: 'New update available.', variant: 'info' } };
|
|
21
|
-
export const Success: Story = { args: { children: 'Changes saved successfully.', variant: 'success' } };
|
|
22
|
-
export const Warning: Story = { args: { children: 'Your session will expire soon.', variant: 'warning' } };
|
|
23
|
-
export const Error: Story = { args: { children: 'Failed to load data. Please retry.', variant: 'error' } };
|
|
24
|
-
export const Dismissible: Story = {
|
|
25
|
-
args: { children: 'You can dismiss this notification.', variant: 'info', onDismiss: () => {} },
|
|
26
|
-
};
|
|
27
|
-
export const AllVariants: Story = {
|
|
28
|
-
render: () => (
|
|
29
|
-
<div style={{ display: 'flex', flexDirection: 'column', gap: '8px' }}>
|
|
30
|
-
{(['info', 'success', 'warning', 'error'] as const).map(v => (
|
|
31
|
-
<NotificationBanner key={v} variant={v}>
|
|
32
|
-
{v.charAt(0).toUpperCase() + v.slice(1)} notification
|
|
33
|
-
</NotificationBanner>
|
|
34
|
-
))}
|
|
35
|
-
</div>
|
|
36
|
-
),
|
|
37
|
-
};
|
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
import { ReactNode } from 'react';
|
|
2
|
-
import { StyleSheet, View, Text, Pressable, StyleProp, ViewStyle } from 'react-native';
|
|
3
|
-
import { spacing, font, lineHeight } from '../../../native/tokens';
|
|
4
|
-
import { useTheme } from '../../../native/ThemeContext';
|
|
5
|
-
|
|
6
|
-
type BannerVariant = 'info' | 'success' | 'warning' | 'error';
|
|
7
|
-
|
|
8
|
-
interface NotificationBannerProps {
|
|
9
|
-
variant?: BannerVariant;
|
|
10
|
-
children: ReactNode;
|
|
11
|
-
action?: ReactNode;
|
|
12
|
-
onDismiss?: () => void;
|
|
13
|
-
style?: StyleProp<ViewStyle>;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
const styles = StyleSheet.create({
|
|
17
|
-
banner: {
|
|
18
|
-
flexDirection: 'row',
|
|
19
|
-
alignItems: 'center',
|
|
20
|
-
paddingVertical: spacing.s,
|
|
21
|
-
paddingHorizontal: spacing.m,
|
|
22
|
-
gap: spacing.xs,
|
|
23
|
-
},
|
|
24
|
-
content: {
|
|
25
|
-
flex: 1,
|
|
26
|
-
fontSize: font.size.bodyS,
|
|
27
|
-
fontFamily: font.family.body,
|
|
28
|
-
lineHeight: lineHeight.bodyS,
|
|
29
|
-
},
|
|
30
|
-
dismiss: {
|
|
31
|
-
padding: spacing.xxs,
|
|
32
|
-
flexShrink: 0,
|
|
33
|
-
},
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
export function NotificationBanner({
|
|
37
|
-
variant = 'info',
|
|
38
|
-
children,
|
|
39
|
-
action,
|
|
40
|
-
onDismiss,
|
|
41
|
-
style,
|
|
42
|
-
}: Readonly<NotificationBannerProps>) {
|
|
43
|
-
const { colors } = useTheme();
|
|
44
|
-
const isUrgent = variant === 'error' || variant === 'warning';
|
|
45
|
-
|
|
46
|
-
const variantColors: Record<BannerVariant, { bg: string; text: string; border: string }> = {
|
|
47
|
-
info: { bg: colors.colorBlueSubtle, text: colors.colorOnBlueSubtle, border: colors.colorBlue },
|
|
48
|
-
success: { bg: colors.colorSuccessSubtle, text: colors.colorOnSuccessSubtle, border: colors.colorSuccess },
|
|
49
|
-
warning: { bg: colors.colorOrangeSubtle, text: colors.colorOnOrangeSubtle, border: colors.colorWarning },
|
|
50
|
-
error: { bg: colors.colorRedSubtle, text: colors.colorOnBg, border: colors.colorError },
|
|
51
|
-
};
|
|
52
|
-
|
|
53
|
-
const { bg, text, border: borderColor } = variantColors[variant];
|
|
54
|
-
|
|
55
|
-
return (
|
|
56
|
-
<View
|
|
57
|
-
accessibilityRole={isUrgent ? 'alert' : 'none'}
|
|
58
|
-
accessibilityLiveRegion={isUrgent ? 'assertive' : 'polite'}
|
|
59
|
-
style={[styles.banner, { backgroundColor: bg, borderBottomWidth: 3, borderBottomColor: borderColor }, style]}
|
|
60
|
-
>
|
|
61
|
-
<Text style={[styles.content, { color: text }]}>{children}</Text>
|
|
62
|
-
{action}
|
|
63
|
-
{onDismiss && (
|
|
64
|
-
<Pressable
|
|
65
|
-
onPress={onDismiss}
|
|
66
|
-
style={styles.dismiss}
|
|
67
|
-
accessibilityLabel="Dismiss notification"
|
|
68
|
-
accessibilityRole="button"
|
|
69
|
-
hitSlop={8}
|
|
70
|
-
>
|
|
71
|
-
<Text style={{ color: text, fontSize: 16 }}>✕</Text>
|
|
72
|
-
</Pressable>
|
|
73
|
-
)}
|
|
74
|
-
</View>
|
|
75
|
-
);
|
|
76
|
-
}
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
import { Meta, Canvas, ArgTypes } from '@storybook/blocks';
|
|
2
|
-
import * as Stories from './Pagination.native.stories';
|
|
3
|
-
|
|
4
|
-
<Meta of={Stories} />
|
|
5
|
-
|
|
6
|
-
# Pagination (React Native)
|
|
7
|
-
|
|
8
|
-
React Native pagination component for navigating between pages of content. Shows page numbers with ellipsis for large ranges, with Previous/Next navigation buttons.
|
|
9
|
-
|
|
10
|
-
> **Status: alpha** -- API may change before stable release.
|
|
11
|
-
|
|
12
|
-
## Usage
|
|
13
|
-
|
|
14
|
-
```tsx
|
|
15
|
-
import { Pagination } from '@boostdev/design-system-components';
|
|
16
|
-
|
|
17
|
-
<Pagination
|
|
18
|
-
currentPage={3}
|
|
19
|
-
totalPages={10}
|
|
20
|
-
onPageChange={(page) => setPage(page)}
|
|
21
|
-
/>
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
## Examples
|
|
25
|
-
|
|
26
|
-
### Default (first page)
|
|
27
|
-
<Canvas of={Stories.Default} />
|
|
28
|
-
|
|
29
|
-
### Middle page
|
|
30
|
-
<Canvas of={Stories.MiddlePage} />
|
|
31
|
-
|
|
32
|
-
### Last page
|
|
33
|
-
<Canvas of={Stories.LastPage} />
|
|
34
|
-
|
|
35
|
-
### Many pages (with ellipsis)
|
|
36
|
-
<Canvas of={Stories.ManyPages} />
|
|
37
|
-
|
|
38
|
-
### Single page
|
|
39
|
-
<Canvas of={Stories.SinglePage} />
|
|
40
|
-
|
|
41
|
-
### Interactive
|
|
42
|
-
<Canvas of={Stories.Interactive} />
|
|
43
|
-
|
|
44
|
-
## Props
|
|
45
|
-
|
|
46
|
-
<ArgTypes of={Stories} />
|
|
47
|
-
|
|
48
|
-
## Props reference
|
|
49
|
-
|
|
50
|
-
| Prop | Type | Default | Description |
|
|
51
|
-
|------|------|---------|-------------|
|
|
52
|
-
| `currentPage` | `number` | -- | The currently active page (1-based) |
|
|
53
|
-
| `totalPages` | `number` | -- | Total number of pages |
|
|
54
|
-
| `onPageChange` | `(page: number) => void` | -- | Called when a page button is pressed |
|
|
55
|
-
| `style` | `StyleProp<ViewStyle>` | -- | Custom style for the container |
|
|
56
|
-
|
|
57
|
-
## Accessibility
|
|
58
|
-
|
|
59
|
-
- Container has `navigation` role with "Pagination" label
|
|
60
|
-
- Previous/Next buttons are disabled at bounds
|
|
61
|
-
- Active page is indicated with `selected` accessibility state
|
|
62
|
-
- Each page button has a descriptive label (e.g. "Page 3")
|
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
import { render, screen, fireEvent } from '@testing-library/react';
|
|
2
|
-
import { ThemeProvider } from '../../../native/ThemeContext';
|
|
3
|
-
import { Pagination } from './Pagination.native';
|
|
4
|
-
|
|
5
|
-
function renderWithTheme(ui: React.ReactElement) {
|
|
6
|
-
return render(<ThemeProvider>{ui}</ThemeProvider>);
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
describe('Pagination (native)', () => {
|
|
10
|
-
it('renders the navigation container', () => {
|
|
11
|
-
renderWithTheme(
|
|
12
|
-
<Pagination currentPage={1} totalPages={5} onPageChange={() => {}} />,
|
|
13
|
-
);
|
|
14
|
-
expect(screen.getByRole('navigation', { name: 'Pagination' })).toBeInTheDocument();
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
it('renders page buttons', () => {
|
|
18
|
-
renderWithTheme(
|
|
19
|
-
<Pagination currentPage={1} totalPages={3} onPageChange={() => {}} />,
|
|
20
|
-
);
|
|
21
|
-
expect(screen.getByRole('button', { name: 'Page 1' })).toBeInTheDocument();
|
|
22
|
-
expect(screen.getByRole('button', { name: 'Page 2' })).toBeInTheDocument();
|
|
23
|
-
expect(screen.getByRole('button', { name: 'Page 3' })).toBeInTheDocument();
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
it('renders the current page button', () => {
|
|
27
|
-
renderWithTheme(
|
|
28
|
-
<Pagination currentPage={2} totalPages={3} onPageChange={() => {}} />,
|
|
29
|
-
);
|
|
30
|
-
expect(screen.getByRole('button', { name: 'Page 2' })).toBeInTheDocument();
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
it('disables Previous on first page', () => {
|
|
34
|
-
renderWithTheme(
|
|
35
|
-
<Pagination currentPage={1} totalPages={5} onPageChange={() => {}} />,
|
|
36
|
-
);
|
|
37
|
-
expect(screen.getByRole('button', { name: 'Previous page' })).toHaveAttribute(
|
|
38
|
-
'aria-disabled',
|
|
39
|
-
'true',
|
|
40
|
-
);
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
it('disables Next on last page', () => {
|
|
44
|
-
renderWithTheme(
|
|
45
|
-
<Pagination currentPage={5} totalPages={5} onPageChange={() => {}} />,
|
|
46
|
-
);
|
|
47
|
-
expect(screen.getByRole('button', { name: 'Next page' })).toHaveAttribute(
|
|
48
|
-
'aria-disabled',
|
|
49
|
-
'true',
|
|
50
|
-
);
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
it('calls onPageChange with the next page when Next is pressed', () => {
|
|
54
|
-
const onPageChange = vi.fn();
|
|
55
|
-
renderWithTheme(
|
|
56
|
-
<Pagination currentPage={2} totalPages={5} onPageChange={onPageChange} />,
|
|
57
|
-
);
|
|
58
|
-
fireEvent.click(screen.getByRole('button', { name: 'Next page' }));
|
|
59
|
-
expect(onPageChange).toHaveBeenCalledWith(3);
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
it('calls onPageChange with the previous page when Previous is pressed', () => {
|
|
63
|
-
const onPageChange = vi.fn();
|
|
64
|
-
renderWithTheme(
|
|
65
|
-
<Pagination currentPage={3} totalPages={5} onPageChange={onPageChange} />,
|
|
66
|
-
);
|
|
67
|
-
fireEvent.click(screen.getByRole('button', { name: 'Previous page' }));
|
|
68
|
-
expect(onPageChange).toHaveBeenCalledWith(2);
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
it('calls onPageChange when a page number is pressed', () => {
|
|
72
|
-
const onPageChange = vi.fn();
|
|
73
|
-
renderWithTheme(
|
|
74
|
-
<Pagination currentPage={1} totalPages={5} onPageChange={onPageChange} />,
|
|
75
|
-
);
|
|
76
|
-
fireEvent.click(screen.getByRole('button', { name: 'Page 2' }));
|
|
77
|
-
expect(onPageChange).toHaveBeenCalledWith(2);
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
it('shows ellipsis for large page ranges', () => {
|
|
81
|
-
renderWithTheme(
|
|
82
|
-
<Pagination currentPage={5} totalPages={20} onPageChange={() => {}} />,
|
|
83
|
-
);
|
|
84
|
-
expect(screen.getAllByText('...').length).toBeGreaterThanOrEqual(1);
|
|
85
|
-
});
|
|
86
|
-
});
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
import React, { useState } from 'react';
|
|
2
|
-
import type { Meta, StoryObj } from '@storybook/react';
|
|
3
|
-
import { ThemeProvider } from '../../../native/ThemeContext';
|
|
4
|
-
import { Pagination } from './Pagination.native';
|
|
5
|
-
|
|
6
|
-
const meta = {
|
|
7
|
-
tags: ['!stable', 'alpha'],
|
|
8
|
-
title: 'React Native/UI/Pagination',
|
|
9
|
-
component: Pagination,
|
|
10
|
-
decorators: [(Story) => <ThemeProvider colorScheme="light"><Story /></ThemeProvider>],
|
|
11
|
-
parameters: { layout: 'padded' },
|
|
12
|
-
} satisfies Meta<typeof Pagination>;
|
|
13
|
-
|
|
14
|
-
export default meta;
|
|
15
|
-
type Story = StoryObj<typeof meta>;
|
|
16
|
-
|
|
17
|
-
export const Default: Story = {
|
|
18
|
-
args: { currentPage: 1, totalPages: 5 },
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
export const MiddlePage: Story = {
|
|
22
|
-
args: { currentPage: 3, totalPages: 5 },
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
export const LastPage: Story = {
|
|
26
|
-
args: { currentPage: 5, totalPages: 5 },
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
export const ManyPages: Story = {
|
|
30
|
-
args: { currentPage: 5, totalPages: 20 },
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
export const SinglePage: Story = {
|
|
34
|
-
args: { currentPage: 1, totalPages: 1 },
|
|
35
|
-
};
|
|
36
|
-
|
|
37
|
-
function InteractiveDemo() {
|
|
38
|
-
const [page, setPage] = useState(1);
|
|
39
|
-
return (
|
|
40
|
-
<Pagination currentPage={page} totalPages={10} onPageChange={setPage} />
|
|
41
|
-
);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
export const Interactive: Story = {
|
|
45
|
-
args: { currentPage: 1, totalPages: 10 },
|
|
46
|
-
render: () => <InteractiveDemo />,
|
|
47
|
-
};
|
|
@@ -1,157 +0,0 @@
|
|
|
1
|
-
import { AccessibilityRole, StyleSheet, View, Text, Pressable, StyleProp, ViewStyle } from 'react-native';
|
|
2
|
-
import { spacing, font, border, lineHeight } from '../../../native/tokens';
|
|
3
|
-
import { useTheme } from '../../../native/ThemeContext';
|
|
4
|
-
|
|
5
|
-
interface PaginationProps {
|
|
6
|
-
currentPage: number;
|
|
7
|
-
totalPages: number;
|
|
8
|
-
onPageChange: (page: number) => void;
|
|
9
|
-
style?: StyleProp<ViewStyle>;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
function getPageRange(current: number, total: number): (number | '...')[] {
|
|
13
|
-
const delta = 1;
|
|
14
|
-
const range: (number | '...')[] = [];
|
|
15
|
-
|
|
16
|
-
for (let i = 1; i <= total; i++) {
|
|
17
|
-
if (i === 1 || i === total || (i >= current - delta && i <= current + delta)) {
|
|
18
|
-
range.push(i);
|
|
19
|
-
} else if (range[range.length - 1] !== '...') {
|
|
20
|
-
range.push('...');
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
return range;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
const styles = StyleSheet.create({
|
|
28
|
-
container: {
|
|
29
|
-
flexDirection: 'row',
|
|
30
|
-
alignItems: 'center',
|
|
31
|
-
gap: spacing.xxs,
|
|
32
|
-
},
|
|
33
|
-
button: {
|
|
34
|
-
minWidth: 44,
|
|
35
|
-
minHeight: 44,
|
|
36
|
-
alignItems: 'center',
|
|
37
|
-
justifyContent: 'center',
|
|
38
|
-
borderRadius: border.radius.full,
|
|
39
|
-
paddingHorizontal: spacing.xs,
|
|
40
|
-
paddingVertical: spacing.xxs,
|
|
41
|
-
},
|
|
42
|
-
buttonText: {
|
|
43
|
-
fontSize: font.size.body,
|
|
44
|
-
fontFamily: font.family.body,
|
|
45
|
-
lineHeight: lineHeight.body,
|
|
46
|
-
fontWeight: font.weight.body,
|
|
47
|
-
},
|
|
48
|
-
navText: {
|
|
49
|
-
fontSize: font.size.body,
|
|
50
|
-
fontFamily: font.family.body,
|
|
51
|
-
lineHeight: lineHeight.body,
|
|
52
|
-
fontWeight: font.weight.semibold,
|
|
53
|
-
},
|
|
54
|
-
ellipsis: {
|
|
55
|
-
fontSize: font.size.body,
|
|
56
|
-
fontFamily: font.family.body,
|
|
57
|
-
lineHeight: lineHeight.body,
|
|
58
|
-
minWidth: 44,
|
|
59
|
-
minHeight: 44,
|
|
60
|
-
textAlign: 'center',
|
|
61
|
-
textAlignVertical: 'center',
|
|
62
|
-
},
|
|
63
|
-
pressed: {
|
|
64
|
-
opacity: 0.75,
|
|
65
|
-
},
|
|
66
|
-
disabled: {
|
|
67
|
-
opacity: 0.4,
|
|
68
|
-
},
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
export function Pagination({
|
|
72
|
-
currentPage,
|
|
73
|
-
totalPages,
|
|
74
|
-
onPageChange,
|
|
75
|
-
style,
|
|
76
|
-
}: Readonly<PaginationProps>) {
|
|
77
|
-
const { colors } = useTheme();
|
|
78
|
-
const pages = getPageRange(currentPage, totalPages);
|
|
79
|
-
|
|
80
|
-
return (
|
|
81
|
-
<View
|
|
82
|
-
style={[styles.container, style]}
|
|
83
|
-
accessibilityRole={'navigation' as AccessibilityRole}
|
|
84
|
-
accessibilityLabel="Pagination"
|
|
85
|
-
>
|
|
86
|
-
<Pressable
|
|
87
|
-
onPress={() => onPageChange(currentPage - 1)}
|
|
88
|
-
disabled={currentPage <= 1}
|
|
89
|
-
accessibilityRole="button"
|
|
90
|
-
accessibilityLabel="Previous page"
|
|
91
|
-
accessibilityState={{ disabled: currentPage <= 1 }}
|
|
92
|
-
style={({ pressed }) => [
|
|
93
|
-
styles.button,
|
|
94
|
-
currentPage <= 1 && styles.disabled,
|
|
95
|
-
pressed && !currentPage && styles.pressed,
|
|
96
|
-
]}
|
|
97
|
-
>
|
|
98
|
-
<Text style={[styles.navText, { color: colors.colorOnBg }]}>‹</Text>
|
|
99
|
-
</Pressable>
|
|
100
|
-
|
|
101
|
-
{pages.map((page, index) =>
|
|
102
|
-
page === '...' ? (
|
|
103
|
-
<Text
|
|
104
|
-
key={`ellipsis-${index}`}
|
|
105
|
-
style={[styles.ellipsis, { color: colors.colorOnBgSubtle }]}
|
|
106
|
-
importantForAccessibility="no"
|
|
107
|
-
accessibilityElementsHidden={true}
|
|
108
|
-
>
|
|
109
|
-
...
|
|
110
|
-
</Text>
|
|
111
|
-
) : (
|
|
112
|
-
<Pressable
|
|
113
|
-
key={page}
|
|
114
|
-
onPress={() => onPageChange(page)}
|
|
115
|
-
accessibilityRole="button"
|
|
116
|
-
accessibilityLabel={`Page ${page}`}
|
|
117
|
-
accessibilityState={{ selected: currentPage === page }}
|
|
118
|
-
style={({ pressed }) => [
|
|
119
|
-
styles.button,
|
|
120
|
-
currentPage === page && { backgroundColor: colors.colorInteractive },
|
|
121
|
-
pressed && styles.pressed,
|
|
122
|
-
]}
|
|
123
|
-
>
|
|
124
|
-
<Text
|
|
125
|
-
style={[
|
|
126
|
-
styles.buttonText,
|
|
127
|
-
{
|
|
128
|
-
color: currentPage === page
|
|
129
|
-
? colors.colorOnInteractive
|
|
130
|
-
: colors.colorOnBg,
|
|
131
|
-
},
|
|
132
|
-
currentPage === page && { fontWeight: font.weight.semibold },
|
|
133
|
-
]}
|
|
134
|
-
>
|
|
135
|
-
{page}
|
|
136
|
-
</Text>
|
|
137
|
-
</Pressable>
|
|
138
|
-
),
|
|
139
|
-
)}
|
|
140
|
-
|
|
141
|
-
<Pressable
|
|
142
|
-
onPress={() => onPageChange(currentPage + 1)}
|
|
143
|
-
disabled={currentPage >= totalPages}
|
|
144
|
-
accessibilityRole="button"
|
|
145
|
-
accessibilityLabel="Next page"
|
|
146
|
-
accessibilityState={{ disabled: currentPage >= totalPages }}
|
|
147
|
-
style={({ pressed }) => [
|
|
148
|
-
styles.button,
|
|
149
|
-
currentPage >= totalPages && styles.disabled,
|
|
150
|
-
pressed && styles.pressed,
|
|
151
|
-
]}
|
|
152
|
-
>
|
|
153
|
-
<Text style={[styles.navText, { color: colors.colorOnBg }]}>›</Text>
|
|
154
|
-
</Pressable>
|
|
155
|
-
</View>
|
|
156
|
-
);
|
|
157
|
-
}
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
import { render, screen } from '@testing-library/react';
|
|
2
|
-
import { ThemeProvider } from '../../../native/ThemeContext';
|
|
3
|
-
import { Progress } from './Progress.native';
|
|
4
|
-
|
|
5
|
-
function renderWithTheme(ui: React.ReactElement) {
|
|
6
|
-
return render(<ThemeProvider>{ui}</ThemeProvider>);
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
describe('Progress (native)', () => {
|
|
10
|
-
it('has progressbar role with accessible label', () => {
|
|
11
|
-
renderWithTheme(<Progress value={50} label="Upload progress" />);
|
|
12
|
-
expect(screen.getByRole('progressbar', { name: 'Upload progress' })).toBeInTheDocument();
|
|
13
|
-
});
|
|
14
|
-
|
|
15
|
-
it('renders progressbar for various values', () => {
|
|
16
|
-
renderWithTheme(<Progress value={30} max={100} label="Loading" />);
|
|
17
|
-
expect(screen.getByRole('progressbar', { name: 'Loading' })).toBeInTheDocument();
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
it('respects a custom max value in percentage display', () => {
|
|
21
|
-
renderWithTheme(<Progress value={5} max={10} label="Steps" showLabel />);
|
|
22
|
-
expect(screen.getByText('50%')).toBeInTheDocument();
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
it('does not show label by default', () => {
|
|
26
|
-
renderWithTheme(<Progress value={60} label="Progress" />);
|
|
27
|
-
expect(screen.queryByText('Progress')).not.toBeInTheDocument();
|
|
28
|
-
expect(screen.queryByText('60%')).not.toBeInTheDocument();
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
it('shows label text and percentage when showLabel is true', () => {
|
|
32
|
-
renderWithTheme(<Progress value={60} label="Progress" showLabel />);
|
|
33
|
-
expect(screen.getByText('Progress')).toBeInTheDocument();
|
|
34
|
-
expect(screen.getByText('60%')).toBeInTheDocument();
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
it('clamps percentage display at 100%', () => {
|
|
38
|
-
renderWithTheme(<Progress value={150} max={100} label="Overflow" showLabel />);
|
|
39
|
-
expect(screen.getByText('100%')).toBeInTheDocument();
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
it('clamps percentage display at 0%', () => {
|
|
43
|
-
renderWithTheme(<Progress value={-10} max={100} label="Underflow" showLabel />);
|
|
44
|
-
expect(screen.getByText('0%')).toBeInTheDocument();
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
it('rounds the percentage to the nearest integer', () => {
|
|
48
|
-
renderWithTheme(<Progress value={33} max={100} label="Loading" showLabel />);
|
|
49
|
-
expect(screen.getByText('33%')).toBeInTheDocument();
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
it('defaults to medium size', () => {
|
|
53
|
-
renderWithTheme(<Progress value={50} label="Loading" />);
|
|
54
|
-
expect(screen.getByRole('progressbar')).toBeInTheDocument();
|
|
55
|
-
});
|
|
56
|
-
});
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import type { Meta, StoryObj } from '@storybook/react';
|
|
3
|
-
import { ThemeProvider } from '../../../native/ThemeContext';
|
|
4
|
-
import { Progress } from './Progress.native';
|
|
5
|
-
|
|
6
|
-
const meta = {
|
|
7
|
-
tags: ['!stable', 'alpha'],
|
|
8
|
-
title: 'React Native/UI/Progress',
|
|
9
|
-
component: Progress,
|
|
10
|
-
decorators: [
|
|
11
|
-
(Story) => (
|
|
12
|
-
<ThemeProvider colorScheme="light">
|
|
13
|
-
<div style={{ width: 300 }}>
|
|
14
|
-
<Story />
|
|
15
|
-
</div>
|
|
16
|
-
</ThemeProvider>
|
|
17
|
-
),
|
|
18
|
-
],
|
|
19
|
-
parameters: { layout: 'padded' },
|
|
20
|
-
argTypes: {
|
|
21
|
-
size: { control: 'select', options: ['small', 'medium', 'large'] },
|
|
22
|
-
value: { control: { type: 'range', min: 0, max: 100, step: 1 } },
|
|
23
|
-
},
|
|
24
|
-
} satisfies Meta<typeof Progress>;
|
|
25
|
-
|
|
26
|
-
export default meta;
|
|
27
|
-
type Story = StoryObj<typeof meta>;
|
|
28
|
-
|
|
29
|
-
export const Default: Story = { args: { value: 60, label: 'Progress' } };
|
|
30
|
-
export const WithLabel: Story = { args: { value: 40, label: 'Loading', showLabel: true } };
|
|
31
|
-
export const Small: Story = { args: { value: 70, label: 'Small progress', size: 'small' } };
|
|
32
|
-
export const Large: Story = { args: { value: 50, label: 'Large progress', size: 'large', showLabel: true } };
|
|
33
|
-
export const Complete: Story = { args: { value: 100, label: 'Complete', showLabel: true } };
|
|
34
|
-
export const Empty: Story = { args: { value: 0, label: 'Not started', showLabel: true } };
|