@boostdev/design-system-components 1.0.3 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +5 -5
- package/dist/client.cjs +236 -153
- package/dist/client.css +547 -483
- package/dist/client.d.cts +53 -94
- package/dist/client.d.ts +53 -94
- package/dist/client.js +237 -163
- package/dist/index.cjs +236 -153
- package/dist/index.css +547 -483
- package/dist/index.d.cts +53 -94
- package/dist/index.d.ts +53 -94
- package/dist/index.js +237 -163
- package/dist/native/index.cjs +991 -0
- package/dist/native/index.d.cts +208 -0
- package/dist/native/index.d.ts +208 -0
- package/dist/native/index.js +968 -0
- package/dist/web-components.d.ts +303 -0
- package/dist/web-components.js +1968 -0
- package/package.json +27 -5
- package/src/components/interaction/Button/Button.module.css +10 -7
- package/src/components/interaction/Button/Button.native.spec.tsx +35 -0
- package/src/components/interaction/Button/Button.native.stories.tsx +42 -0
- package/src/components/interaction/Button/Button.native.tsx +95 -0
- package/src/components/interaction/Button/Button.stories.tsx +1 -1
- package/src/components/interaction/Button/Button.tsx +2 -2
- package/src/components/interaction/Command/Command.mdx +16 -0
- package/src/components/interaction/Command/Command.stories.tsx +1 -1
- package/src/components/interaction/Command/Command.tsx +2 -2
- package/src/components/interaction/Dialog/Dialog.stories.tsx +1 -1
- package/src/components/interaction/Dialog/Dialog.tsx +2 -2
- package/src/components/interaction/Drawer/Drawer.mdx +14 -0
- package/src/components/interaction/Drawer/Drawer.stories.tsx +1 -1
- package/src/components/interaction/Drawer/Drawer.tsx +2 -2
- package/src/components/interaction/DropdownMenu/DropdownMenu.stories.tsx +1 -1
- package/src/components/interaction/DropdownMenu/DropdownMenu.tsx +2 -2
- package/src/components/interaction/Popover/Popover.mdx +17 -0
- package/src/components/interaction/Popover/Popover.module.css +70 -13
- package/src/components/interaction/Popover/Popover.spec.tsx +68 -4
- package/src/components/interaction/Popover/Popover.stories.tsx +1 -1
- package/src/components/interaction/Popover/Popover.tsx +76 -20
- package/src/components/interaction/Rating/Rating.stories.tsx +1 -1
- package/src/components/interaction/Rating/Rating.tsx +2 -2
- package/src/components/interaction/Toast/Toast.module.css +6 -1
- package/src/components/interaction/Toast/Toast.spec.tsx +21 -0
- package/src/components/interaction/Toast/Toast.stories.tsx +1 -1
- package/src/components/interaction/Toast/Toast.tsx +22 -2
- package/src/components/interaction/form/Checkbox/Checkbox.mdx +2 -2
- package/src/components/interaction/form/Checkbox/Checkbox.module.css +3 -3
- package/src/components/interaction/form/Checkbox/Checkbox.native.spec.tsx +42 -0
- package/src/components/interaction/form/Checkbox/Checkbox.native.stories.tsx +36 -0
- package/src/components/interaction/form/Checkbox/Checkbox.native.tsx +80 -0
- package/src/components/interaction/form/Checkbox/Checkbox.stories.tsx +1 -1
- package/src/components/interaction/form/Checkbox/Checkbox.tsx +2 -2
- package/src/components/interaction/form/CheckboxGroup/CheckboxGroup.mdx +44 -0
- package/src/components/interaction/form/CheckboxGroup/CheckboxGroup.stories.tsx +1 -1
- package/src/components/interaction/form/CheckboxGroup/CheckboxGroup.tsx +2 -2
- package/src/components/interaction/form/Combobox/Combobox.mdx +21 -0
- package/src/components/interaction/form/Combobox/Combobox.module.css +1 -1
- package/src/components/interaction/form/Combobox/Combobox.stories.tsx +1 -1
- package/src/components/interaction/form/Combobox/Combobox.tsx +2 -2
- package/src/components/interaction/form/FileInput/FileInput.mdx +14 -0
- package/src/components/interaction/form/FileInput/FileInput.module.css +1 -1
- package/src/components/interaction/form/FileInput/FileInput.stories.tsx +1 -1
- package/src/components/interaction/form/FileInput/FileInput.tsx +2 -2
- package/src/components/interaction/form/FormInput/FormInput.stories.tsx +1 -1
- package/src/components/interaction/form/FormInput/FormInput.tsx +2 -2
- package/src/components/interaction/form/NumberInput/NumberInput.mdx +16 -0
- package/src/components/interaction/form/NumberInput/NumberInput.stories.tsx +1 -1
- package/src/components/interaction/form/NumberInput/NumberInput.tsx +2 -2
- package/src/components/interaction/form/Radio/Radio.mdx +3 -3
- package/src/components/interaction/form/Radio/Radio.module.css +3 -3
- package/src/components/interaction/form/Radio/Radio.native.stories.tsx +46 -0
- package/src/components/interaction/form/Radio/Radio.native.tsx +79 -0
- package/src/components/interaction/form/Radio/Radio.stories.tsx +1 -1
- package/src/components/interaction/form/Radio/Radio.tsx +2 -2
- package/src/components/interaction/form/RadioGroup/RadioGroup.mdx +45 -0
- package/src/components/interaction/form/RadioGroup/RadioGroup.stories.tsx +1 -1
- package/src/components/interaction/form/RadioGroup/RadioGroup.tsx +2 -2
- package/src/components/interaction/form/SegmentedControl/SegmentedControl.stories.tsx +1 -1
- package/src/components/interaction/form/SegmentedControl/SegmentedControl.tsx +2 -2
- package/src/components/interaction/form/Select/Select.stories.tsx +1 -1
- package/src/components/interaction/form/Select/Select.tsx +2 -2
- package/src/components/interaction/form/Slider/Slider.mdx +1 -1
- package/src/components/interaction/form/Slider/Slider.module.css +4 -4
- package/src/components/interaction/form/Slider/Slider.stories.tsx +1 -1
- package/src/components/interaction/form/Slider/Slider.tsx +2 -2
- package/src/components/interaction/form/Switch/Switch.mdx +4 -4
- package/src/components/interaction/form/Switch/Switch.module.css +3 -3
- package/src/components/interaction/form/Switch/Switch.native.spec.tsx +60 -0
- package/src/components/interaction/form/Switch/Switch.native.stories.tsx +35 -0
- package/src/components/interaction/form/Switch/Switch.native.tsx +59 -0
- package/src/components/interaction/form/Switch/Switch.stories.tsx +1 -1
- package/src/components/interaction/form/Switch/Switch.tsx +2 -2
- package/src/components/interaction/form/Textarea/Textarea.mdx +17 -0
- package/src/components/interaction/form/Textarea/Textarea.stories.tsx +1 -1
- package/src/components/interaction/form/Textarea/Textarea.tsx +2 -2
- package/src/components/interaction/form/atoms/InputContainer.tsx +2 -1
- package/src/components/interaction/form/atoms/Label.native.stories.tsx +18 -0
- package/src/components/interaction/form/atoms/Label.native.tsx +29 -0
- package/src/components/interaction/form/atoms/Label.tsx +5 -3
- package/src/components/interaction/form/atoms/Message.native.spec.tsx +30 -0
- package/src/components/interaction/form/atoms/Message.native.stories.tsx +22 -0
- package/src/components/interaction/form/atoms/Message.native.tsx +34 -0
- package/src/components/interaction/form/atoms/Message.tsx +5 -3
- package/src/components/layout/ButtonGroup/ButtonGroup.native.stories.tsx +50 -0
- package/src/components/layout/ButtonGroup/ButtonGroup.native.tsx +34 -0
- package/src/components/layout/ButtonGroup/ButtonGroup.stories.tsx +1 -1
- package/src/components/layout/ButtonGroup/ButtonGroup.tsx +2 -2
- package/src/components/layout/Card/Card.native.stories.tsx +53 -0
- package/src/components/layout/Card/Card.native.tsx +89 -0
- package/src/components/layout/Card/Card.stories.tsx +1 -1
- package/src/components/layout/Card/Card.tsx +2 -2
- package/src/components/layout/IconWrapper/IconWrapper.mdx +2 -2
- package/src/components/layout/IconWrapper/IconWrapper.native.spec.tsx +39 -0
- package/src/components/layout/IconWrapper/IconWrapper.native.stories.tsx +41 -0
- package/src/components/layout/IconWrapper/IconWrapper.native.tsx +20 -0
- package/src/components/layout/IconWrapper/IconWrapper.stories.tsx +1 -1
- package/src/components/layout/IconWrapper/IconWrapper.tsx +2 -2
- package/src/components/layout/SectionHeader/SectionHeader.mdx +13 -0
- package/src/components/layout/SectionHeader/SectionHeader.native.stories.tsx +38 -0
- package/src/components/layout/SectionHeader/SectionHeader.native.tsx +79 -0
- package/src/components/layout/SectionHeader/SectionHeader.stories.tsx +1 -1
- package/src/components/layout/SectionHeader/SectionHeader.tsx +2 -2
- package/src/components/ui/Accordion/Accordion.mdx +14 -0
- package/src/components/ui/Accordion/Accordion.stories.tsx +1 -1
- package/src/components/ui/Accordion/Accordion.tsx +2 -2
- package/src/components/ui/Alert/Alert.native.stories.tsx +43 -0
- package/src/components/ui/Alert/Alert.native.tsx +94 -0
- package/src/components/ui/Alert/Alert.stories.tsx +1 -1
- package/src/components/ui/Alert/Alert.tsx +2 -2
- package/src/components/ui/Avatar/Avatar.native.spec.tsx +47 -0
- package/src/components/ui/Avatar/Avatar.native.stories.tsx +34 -0
- package/src/components/ui/Avatar/Avatar.native.tsx +85 -0
- package/src/components/ui/Avatar/Avatar.stories.tsx +1 -1
- package/src/components/ui/Avatar/Avatar.tsx +2 -2
- package/src/components/ui/Badge/Badge.mdx +2 -2
- package/src/components/ui/Badge/Badge.native.stories.tsx +36 -0
- package/src/components/ui/Badge/Badge.native.tsx +50 -0
- package/src/components/ui/Badge/Badge.stories.tsx +1 -1
- package/src/components/ui/Badge/Badge.tsx +2 -2
- package/src/components/ui/Breadcrumb/Breadcrumb.stories.tsx +1 -1
- package/src/components/ui/Breadcrumb/Breadcrumb.tsx +2 -2
- package/src/components/ui/Calendar/Calendar.mdx +16 -0
- package/src/components/ui/Calendar/Calendar.stories.tsx +1 -1
- package/src/components/ui/Calendar/Calendar.tsx +2 -2
- package/src/components/ui/Carousel/Carousel.stories.tsx +1 -1
- package/src/components/ui/Carousel/Carousel.tsx +2 -2
- package/src/components/ui/Collapsible/Collapsible.stories.tsx +1 -1
- package/src/components/ui/Collapsible/Collapsible.tsx +2 -2
- package/src/components/ui/DescriptionList/DescriptionList.stories.tsx +1 -1
- package/src/components/ui/DescriptionList/DescriptionList.tsx +2 -2
- package/src/components/ui/Link/Link.mdx +14 -0
- package/src/components/ui/Link/Link.stories.tsx +1 -1
- package/src/components/ui/Link/Link.tsx +2 -2
- package/src/components/ui/Loading/Loading.native.spec.tsx +24 -0
- package/src/components/ui/Loading/Loading.native.stories.tsx +33 -0
- package/src/components/ui/Loading/Loading.native.tsx +29 -0
- package/src/components/ui/Loading/Loading.stories.tsx +1 -1
- package/src/components/ui/Loading/Loading.tsx +2 -2
- package/src/components/ui/NotificationBanner/NotificationBanner.native.stories.tsx +39 -0
- package/src/components/ui/NotificationBanner/NotificationBanner.native.tsx +76 -0
- package/src/components/ui/NotificationBanner/NotificationBanner.stories.tsx +1 -1
- package/src/components/ui/NotificationBanner/NotificationBanner.tsx +2 -2
- package/src/components/ui/Pagination/Pagination.module.css +1 -1
- package/src/components/ui/Pagination/Pagination.stories.tsx +1 -1
- package/src/components/ui/Pagination/Pagination.tsx +2 -2
- package/src/components/ui/Progress/Progress.mdx +1 -1
- package/src/components/ui/Progress/Progress.module.css +1 -1
- package/src/components/ui/Progress/Progress.native.stories.tsx +34 -0
- package/src/components/ui/Progress/Progress.native.tsx +84 -0
- package/src/components/ui/Progress/Progress.stories.tsx +1 -1
- package/src/components/ui/Progress/Progress.tsx +2 -2
- package/src/components/ui/ProgressCircle/ProgressCircle.module.css +1 -1
- package/src/components/ui/ProgressCircle/ProgressCircle.stories.tsx +1 -1
- package/src/components/ui/ProgressCircle/ProgressCircle.tsx +2 -2
- package/src/components/ui/Separator/Separator.mdx +14 -0
- package/src/components/ui/Separator/Separator.native.stories.tsx +42 -0
- package/src/components/ui/Separator/Separator.native.tsx +32 -0
- package/src/components/ui/Separator/Separator.stories.tsx +1 -1
- package/src/components/ui/Separator/Separator.tsx +2 -2
- package/src/components/ui/Skeleton/Skeleton.native.stories.tsx +33 -0
- package/src/components/ui/Skeleton/Skeleton.native.tsx +41 -0
- package/src/components/ui/Skeleton/Skeleton.stories.tsx +1 -1
- package/src/components/ui/Skeleton/Skeleton.tsx +2 -3
- package/src/components/ui/SkipLink/SkipLink.stories.tsx +1 -1
- package/src/components/ui/SkipLink/SkipLink.tsx +5 -3
- package/src/components/ui/Table/Table.mdx +14 -0
- package/src/components/ui/Table/Table.stories.tsx +1 -1
- package/src/components/ui/Table/Table.tsx +2 -2
- package/src/components/ui/Tabs/Tabs.stories.tsx +1 -1
- package/src/components/ui/Tabs/Tabs.tsx +2 -2
- package/src/components/ui/Tooltip/Tooltip.mdx +14 -0
- package/src/components/ui/Tooltip/Tooltip.stories.tsx +1 -1
- package/src/components/ui/Tooltip/Tooltip.tsx +2 -2
- package/src/components/ui/Typography/Typography.mdx +13 -0
- package/src/components/ui/Typography/Typography.native.stories.tsx +38 -0
- package/src/components/ui/Typography/Typography.native.tsx +65 -0
- package/src/components/ui/Typography/Typography.stories.tsx +1 -1
- package/src/components/ui/Typography/Typography.tsx +2 -2
- package/src/css/bdc.css +8 -0
- package/src/index.ts +1 -0
- package/src/native/ThemeContext.tsx +28 -0
- package/src/native/tokens.ts +13 -0
- package/src/native.ts +39 -0
- package/src/react-augment.d.ts +13 -0
- package/src/stories/DesignSystem/DarkMode.mdx +130 -0
- package/src/types.ts +2 -0
- package/src/typings.d.ts +3 -0
- package/src/web-components/globals.ts +61 -0
- package/src/web-components/index.ts +12 -0
- package/src/web-components/interaction/BdsButton.stories.tsx +60 -0
- package/src/web-components/interaction/BdsPopover.stories.tsx +70 -0
- package/src/web-components/interaction/BdsToastProvider.stories.tsx +73 -0
- package/src/web-components/interaction/bds-button.spec.ts +95 -0
- package/src/web-components/interaction/bds-button.ts +293 -0
- package/src/web-components/interaction/bds-popover.spec.ts +126 -0
- package/src/web-components/interaction/bds-popover.ts +217 -0
- package/src/web-components/interaction/bds-toast-provider.spec.ts +122 -0
- package/src/web-components/interaction/bds-toast-provider.ts +211 -0
- package/src/web-components/test/helpers.ts +14 -0
- package/src/web-components/ui/BdsAlert.stories.tsx +60 -0
- package/src/web-components/ui/BdsBadge.stories.tsx +37 -0
- package/src/web-components/ui/bds-alert.spec.ts +109 -0
- package/src/web-components/ui/bds-alert.ts +209 -0
- package/src/web-components/ui/bds-badge.spec.ts +51 -0
- package/src/web-components/ui/bds-badge.ts +88 -0
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { ReactNode } from 'react';
|
|
2
2
|
import css from './Table.module.css';
|
|
3
3
|
import { cn } from '@boostdev/design-system-foundation';
|
|
4
|
+
import type { WithClassName } from '../../../types';
|
|
4
5
|
|
|
5
6
|
export interface TableColumn<Row> {
|
|
6
7
|
key: string;
|
|
@@ -9,14 +10,13 @@ export interface TableColumn<Row> {
|
|
|
9
10
|
render?: (row: Row) => ReactNode;
|
|
10
11
|
}
|
|
11
12
|
|
|
12
|
-
interface TableProps<Row extends Record<string, unknown>> {
|
|
13
|
+
interface TableProps<Row extends Record<string, unknown>> extends WithClassName {
|
|
13
14
|
columns: TableColumn<Row>[];
|
|
14
15
|
rows: Row[];
|
|
15
16
|
caption?: string;
|
|
16
17
|
sortKey?: string;
|
|
17
18
|
sortDirection?: 'asc' | 'desc';
|
|
18
19
|
onSort?: (key: string, direction: 'asc' | 'desc') => void;
|
|
19
|
-
className?: string;
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
export function Table<Row extends Record<string, unknown>>({
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { KeyboardEvent, ReactNode, useId, useRef, useState } from 'react';
|
|
2
2
|
import css from './Tabs.module.css';
|
|
3
3
|
import { cn } from '@boostdev/design-system-foundation';
|
|
4
|
+
import type { WithClassName } from '../../../types';
|
|
4
5
|
|
|
5
6
|
export interface TabItem {
|
|
6
7
|
id: string;
|
|
@@ -9,10 +10,9 @@ export interface TabItem {
|
|
|
9
10
|
disabled?: boolean;
|
|
10
11
|
}
|
|
11
12
|
|
|
12
|
-
interface TabsProps {
|
|
13
|
+
interface TabsProps extends WithClassName {
|
|
13
14
|
tabs: TabItem[];
|
|
14
15
|
defaultTab?: string;
|
|
15
|
-
className?: string;
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
export function Tabs({ tabs, defaultTab, className }: Readonly<TabsProps>) {
|
|
@@ -36,6 +36,20 @@ Short contextual label that appears on hover or focus. Use to supplement icon bu
|
|
|
36
36
|
|
|
37
37
|
<ArgTypes of={Stories} />
|
|
38
38
|
|
|
39
|
+
## CSS variables
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
<table>
|
|
43
|
+
<thead>
|
|
44
|
+
<tr><th>Variable</th><th>Default</th><th>Description</th></tr>
|
|
45
|
+
</thead>
|
|
46
|
+
<tbody>
|
|
47
|
+
<tr><td>`--tooltip_bg`</td><td>`var(--bds-color_on-bg)`</td><td>Tooltip background colour</td></tr>
|
|
48
|
+
<tr><td>`--tooltip_text`</td><td>`var(--bds-color_bg)`</td><td>Tooltip text colour</td></tr>
|
|
49
|
+
</tbody>
|
|
50
|
+
</table>
|
|
51
|
+
|
|
52
|
+
|
|
39
53
|
## Accessibility
|
|
40
54
|
|
|
41
55
|
- Tooltip content is linked via `aria-describedby` on the trigger element
|
|
@@ -3,7 +3,7 @@ import { Tooltip } from './Tooltip';
|
|
|
3
3
|
import { Button } from '../../interaction/Button/Button';
|
|
4
4
|
|
|
5
5
|
const meta = {
|
|
6
|
-
title: 'UI/Tooltip',
|
|
6
|
+
title: 'React/UI/Tooltip',
|
|
7
7
|
component: Tooltip,
|
|
8
8
|
argTypes: {
|
|
9
9
|
placement: { control: 'radio', options: ['top', 'bottom', 'left', 'right'] },
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { ReactElement, ReactNode, cloneElement, isValidElement, useId, useState } from 'react';
|
|
2
2
|
import css from './Tooltip.module.css';
|
|
3
3
|
import { cn } from '@boostdev/design-system-foundation';
|
|
4
|
+
import type { WithClassName } from '../../../types';
|
|
4
5
|
|
|
5
|
-
interface TooltipProps {
|
|
6
|
+
interface TooltipProps extends WithClassName {
|
|
6
7
|
content: ReactNode;
|
|
7
8
|
placement?: 'top' | 'bottom' | 'left' | 'right';
|
|
8
9
|
children: ReactElement;
|
|
9
|
-
className?: string;
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
export function Tooltip({
|
|
@@ -35,6 +35,19 @@ Renders a text element with a design-system variant. Decouples visual style from
|
|
|
35
35
|
|
|
36
36
|
<ArgTypes of={Stories} />
|
|
37
37
|
|
|
38
|
+
## CSS variables
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
<table>
|
|
42
|
+
<thead>
|
|
43
|
+
<tr><th>Variable</th><th>Default</th><th>Description</th></tr>
|
|
44
|
+
</thead>
|
|
45
|
+
<tbody>
|
|
46
|
+
<tr><td>`--typography_color`</td><td>`var(--bds-color_on-bg)`</td><td>Text colour override</td></tr>
|
|
47
|
+
</tbody>
|
|
48
|
+
</table>
|
|
49
|
+
|
|
50
|
+
|
|
38
51
|
## Accessibility
|
|
39
52
|
|
|
40
53
|
- Defaults to the semantically correct element for each variant (`h1`–`h3`, `p`)
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
3
|
+
import { ThemeProvider } from '../../../native/ThemeContext';
|
|
4
|
+
import { Typography } from './Typography.native';
|
|
5
|
+
|
|
6
|
+
const meta = {
|
|
7
|
+
tags: ['!stable', 'alpha'],
|
|
8
|
+
title: 'React Native/UI/Typography',
|
|
9
|
+
component: Typography,
|
|
10
|
+
decorators: [(Story) => <ThemeProvider><Story /></ThemeProvider>],
|
|
11
|
+
parameters: { layout: 'padded' },
|
|
12
|
+
argTypes: {
|
|
13
|
+
variant: { control: 'select', options: ['h1', 'h2', 'h3', 'body', 'body_s'] },
|
|
14
|
+
},
|
|
15
|
+
} satisfies Meta<typeof Typography>;
|
|
16
|
+
|
|
17
|
+
export default meta;
|
|
18
|
+
type Story = StoryObj<typeof meta>;
|
|
19
|
+
|
|
20
|
+
export const Heading1: Story = { args: { children: 'Heading 1', variant: 'h1' } };
|
|
21
|
+
export const Heading2: Story = { args: { children: 'Heading 2', variant: 'h2' } };
|
|
22
|
+
export const Heading3: Story = { args: { children: 'Heading 3', variant: 'h3' } };
|
|
23
|
+
export const Body: Story = { args: { children: 'The quick brown fox jumps over the lazy dog.', variant: 'body' } };
|
|
24
|
+
export const BodySmall: Story = { args: { children: 'The quick brown fox jumps over the lazy dog.', variant: 'body_s' } };
|
|
25
|
+
export const AllVariants: Story = {
|
|
26
|
+
args: { children: '' },
|
|
27
|
+
render: () => (
|
|
28
|
+
<ThemeProvider>
|
|
29
|
+
<div style={{ display: 'flex', flexDirection: 'column', gap: '12px' }}>
|
|
30
|
+
<Typography variant="h1">Heading 1</Typography>
|
|
31
|
+
<Typography variant="h2">Heading 2</Typography>
|
|
32
|
+
<Typography variant="h3">Heading 3</Typography>
|
|
33
|
+
<Typography variant="body">Body — The quick brown fox jumps over the lazy dog.</Typography>
|
|
34
|
+
<Typography variant="body_s">Body Small — The quick brown fox jumps over the lazy dog.</Typography>
|
|
35
|
+
</div>
|
|
36
|
+
</ThemeProvider>
|
|
37
|
+
),
|
|
38
|
+
};
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
import { StyleSheet, Text, StyleProp, TextStyle } from 'react-native';
|
|
3
|
+
import { font, lineHeight } from '../../../native/tokens';
|
|
4
|
+
import { useTheme } from '../../../native/ThemeContext';
|
|
5
|
+
|
|
6
|
+
type TypographyVariant = 'h1' | 'h2' | 'h3' | 'body' | 'body_s';
|
|
7
|
+
|
|
8
|
+
interface TypographyProps {
|
|
9
|
+
variant?: TypographyVariant;
|
|
10
|
+
children: ReactNode;
|
|
11
|
+
style?: StyleProp<TextStyle>;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const styles = StyleSheet.create({
|
|
15
|
+
base: {
|
|
16
|
+
fontFamily: font.family.body,
|
|
17
|
+
fontWeight: font.weight.body,
|
|
18
|
+
},
|
|
19
|
+
h1: {
|
|
20
|
+
fontSize: font.size.heading1,
|
|
21
|
+
fontFamily: font.family.heading,
|
|
22
|
+
fontWeight: font.weight.heading,
|
|
23
|
+
lineHeight: lineHeight.heading1,
|
|
24
|
+
},
|
|
25
|
+
h2: {
|
|
26
|
+
fontSize: font.size.heading2,
|
|
27
|
+
fontFamily: font.family.heading,
|
|
28
|
+
fontWeight: font.weight.heading,
|
|
29
|
+
lineHeight: lineHeight.heading2,
|
|
30
|
+
},
|
|
31
|
+
h3: {
|
|
32
|
+
fontSize: font.size.heading3,
|
|
33
|
+
fontFamily: font.family.heading,
|
|
34
|
+
fontWeight: font.weight.heading,
|
|
35
|
+
lineHeight: lineHeight.heading3,
|
|
36
|
+
},
|
|
37
|
+
body: {
|
|
38
|
+
fontSize: font.size.body,
|
|
39
|
+
lineHeight: lineHeight.body,
|
|
40
|
+
},
|
|
41
|
+
body_s: {
|
|
42
|
+
fontSize: font.size.bodyS,
|
|
43
|
+
lineHeight: lineHeight.bodyS,
|
|
44
|
+
},
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
const accessibilityRoles: Record<TypographyVariant, 'header' | 'text'> = {
|
|
48
|
+
h1: 'header',
|
|
49
|
+
h2: 'header',
|
|
50
|
+
h3: 'header',
|
|
51
|
+
body: 'text',
|
|
52
|
+
body_s: 'text',
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
export function Typography({ variant = 'body', children, style }: TypographyProps) {
|
|
56
|
+
const { colors } = useTheme();
|
|
57
|
+
return (
|
|
58
|
+
<Text
|
|
59
|
+
accessibilityRole={accessibilityRoles[variant]}
|
|
60
|
+
style={[styles.base, styles[variant], { color: colors.colorOnBg }, style]}
|
|
61
|
+
>
|
|
62
|
+
{children}
|
|
63
|
+
</Text>
|
|
64
|
+
);
|
|
65
|
+
}
|
|
@@ -2,7 +2,7 @@ import type { Meta, StoryObj } from '@storybook/react';
|
|
|
2
2
|
import { Typography } from './Typography';
|
|
3
3
|
|
|
4
4
|
const meta = {
|
|
5
|
-
title: 'UI/Typography',
|
|
5
|
+
title: 'React/UI/Typography',
|
|
6
6
|
component: Typography,
|
|
7
7
|
argTypes: {
|
|
8
8
|
variant: { control: 'select', options: ['h1', 'h2', 'h3', 'body', 'body_s'] },
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { ReactNode, ElementType } from 'react';
|
|
2
2
|
import css from './Typography.module.css';
|
|
3
3
|
import { cn } from '@boostdev/design-system-foundation';
|
|
4
|
+
import type { WithClassName } from '../../../types';
|
|
4
5
|
|
|
5
6
|
type TypographyVariant = 'h1' | 'h2' | 'h3' | 'body' | 'body_s';
|
|
6
7
|
|
|
7
|
-
interface TypographyProps {
|
|
8
|
+
interface TypographyProps extends WithClassName {
|
|
8
9
|
variant?: TypographyVariant;
|
|
9
10
|
component?: ElementType;
|
|
10
11
|
children: ReactNode;
|
|
11
|
-
className?: string;
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
const variantToElement: Record<TypographyVariant, ElementType> = {
|
package/src/css/bdc.css
CHANGED
|
@@ -55,6 +55,14 @@
|
|
|
55
55
|
--bdc_color--focus: var(--bds-color_interactive);
|
|
56
56
|
--bdc_color--error: var(--bds-color_error);
|
|
57
57
|
|
|
58
|
+
/* Active / selected state colours — override these to theme all filled form controls globally */
|
|
59
|
+
--bdc-color_active: var(--bds-color_green);
|
|
60
|
+
--bdc-color_on-active: var(--bds-color_on-green);
|
|
61
|
+
--bdc-color_active--subtle: var(--bds-color_green--subtle);
|
|
62
|
+
--bdc-color_on-active--subtle: var(--bds-color_on-green--subtle);
|
|
63
|
+
--bdc-color_active--strong: var(--bds-color_green--strong);
|
|
64
|
+
--bdc-color_on-active--strong: var(--bds-color_on-green--strong);
|
|
65
|
+
|
|
58
66
|
/* Outline geometry */
|
|
59
67
|
--bdc-outline_width: 1px;
|
|
60
68
|
--bdc-outline_offset: -1px; /* inset — appears inside the element like a traditional border */
|
package/src/index.ts
CHANGED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { createContext, ReactNode, useContext, useMemo } from 'react';
|
|
2
|
+
import { useColorScheme } from 'react-native';
|
|
3
|
+
import { colors } from './tokens';
|
|
4
|
+
|
|
5
|
+
type ThemeColors = typeof colors.light | typeof colors.dark;
|
|
6
|
+
|
|
7
|
+
interface ThemeContextValue {
|
|
8
|
+
colors: ThemeColors;
|
|
9
|
+
isDark: boolean;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const ThemeContext = createContext<ThemeContextValue | null>(null);
|
|
13
|
+
|
|
14
|
+
export function ThemeProvider({ children }: { children: ReactNode }) {
|
|
15
|
+
const scheme = useColorScheme();
|
|
16
|
+
const isDark = scheme === 'dark';
|
|
17
|
+
const value = useMemo<ThemeContextValue>(
|
|
18
|
+
() => ({ colors: isDark ? colors.dark : colors.light, isDark }),
|
|
19
|
+
[isDark],
|
|
20
|
+
);
|
|
21
|
+
return <ThemeContext.Provider value={value}>{children}</ThemeContext.Provider>;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function useTheme(): ThemeContextValue {
|
|
25
|
+
const ctx = useContext(ThemeContext);
|
|
26
|
+
if (!ctx) throw new Error('useTheme must be used within ThemeProvider');
|
|
27
|
+
return ctx;
|
|
28
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { colors, spacing, font, border, zIndex, animation } from '@boostdev/design-system-foundation/native';
|
|
2
|
+
|
|
3
|
+
export { colors, spacing, font, border, zIndex, animation };
|
|
4
|
+
|
|
5
|
+
/** Absolute lineHeight values for React Native (ratio × fontSize). */
|
|
6
|
+
export const lineHeight = {
|
|
7
|
+
display: Math.round(font.size.display * font.lineHeight.display),
|
|
8
|
+
heading1: Math.round(font.size.heading1 * font.lineHeight.heading),
|
|
9
|
+
heading2: Math.round(font.size.heading2 * font.lineHeight.heading),
|
|
10
|
+
heading3: Math.round(font.size.heading3 * font.lineHeight.heading),
|
|
11
|
+
body: Math.round(font.size.body * font.lineHeight.body),
|
|
12
|
+
bodyS: Math.round(font.size.bodyS * font.lineHeight.body),
|
|
13
|
+
} as const;
|
package/src/native.ts
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
// React Native component barrel
|
|
2
|
+
// Explicitly imports *.native.tsx variants so tsup compiles them into dist/native/index.js.
|
|
3
|
+
// Metro resolves this via the "react-native" export condition in package.json.
|
|
4
|
+
|
|
5
|
+
// Infrastructure
|
|
6
|
+
export { ThemeProvider, useTheme } from './native/ThemeContext';
|
|
7
|
+
|
|
8
|
+
// UI
|
|
9
|
+
export { Typography } from './components/ui/Typography/Typography.native';
|
|
10
|
+
export { Badge } from './components/ui/Badge/Badge.native';
|
|
11
|
+
export { Avatar } from './components/ui/Avatar/Avatar.native';
|
|
12
|
+
export { Separator } from './components/ui/Separator/Separator.native';
|
|
13
|
+
export { Loading } from './components/ui/Loading/Loading.native';
|
|
14
|
+
export { Progress } from './components/ui/Progress/Progress.native';
|
|
15
|
+
export { Skeleton } from './components/ui/Skeleton/Skeleton.native';
|
|
16
|
+
export { Alert } from './components/ui/Alert/Alert.native';
|
|
17
|
+
export { NotificationBanner } from './components/ui/NotificationBanner/NotificationBanner.native';
|
|
18
|
+
|
|
19
|
+
// Layout
|
|
20
|
+
export { Card } from './components/layout/Card/Card.native';
|
|
21
|
+
export { SectionHeader } from './components/layout/SectionHeader/SectionHeader.native';
|
|
22
|
+
export { IconWrapper } from './components/layout/IconWrapper/IconWrapper.native';
|
|
23
|
+
export type { IconWrapperProps } from './components/layout/IconWrapper/IconWrapper.native';
|
|
24
|
+
export { ButtonGroup } from './components/layout/ButtonGroup/ButtonGroup.native';
|
|
25
|
+
export type { ButtonGroupProps } from './components/layout/ButtonGroup/ButtonGroup.native';
|
|
26
|
+
|
|
27
|
+
// Interaction
|
|
28
|
+
export { Button } from './components/interaction/Button/Button.native';
|
|
29
|
+
export type { ButtonProps } from './components/interaction/Button/Button.native';
|
|
30
|
+
export { Switch } from './components/interaction/form/Switch/Switch.native';
|
|
31
|
+
export { Checkbox } from './components/interaction/form/Checkbox/Checkbox.native';
|
|
32
|
+
export { Radio } from './components/interaction/form/Radio/Radio.native';
|
|
33
|
+
|
|
34
|
+
// Atoms
|
|
35
|
+
export { Label } from './components/interaction/form/atoms/Label.native';
|
|
36
|
+
export { Message } from './components/interaction/form/atoms/Message.native';
|
|
37
|
+
|
|
38
|
+
// Tokens (re-exported for convenience)
|
|
39
|
+
export { colors, spacing, font, border, zIndex, animation, lineHeight } from './native/tokens';
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// This file MUST be a module (not a global script) so that `declare module 'react'`
|
|
2
|
+
// is treated as an augmentation that merges with @types/react rather than as an
|
|
3
|
+
// ambient module declaration that would shadow @types/react entirely.
|
|
4
|
+
// The `export {}` below is what makes TypeScript treat this as a module.
|
|
5
|
+
export {};
|
|
6
|
+
|
|
7
|
+
// CSS Anchor Positioning properties — not yet in React's CSSProperties types.
|
|
8
|
+
declare module 'react' {
|
|
9
|
+
interface CSSProperties {
|
|
10
|
+
anchorName?: string;
|
|
11
|
+
positionAnchor?: string;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { Meta } from '@storybook/blocks';
|
|
2
|
+
|
|
3
|
+
<Meta title="Design System/Dark Mode" />
|
|
4
|
+
|
|
5
|
+
# Dark Mode
|
|
6
|
+
|
|
7
|
+
All components adapt to dark mode automatically. No extra CSS imports or component changes are needed — switching the theme updates every token at once.
|
|
8
|
+
|
|
9
|
+
## How it works
|
|
10
|
+
|
|
11
|
+
The design system foundation ships two sets of semantic tokens: one for light mode and one for dark mode. When dark mode is active, the `--bds-color_*` tokens remap to their dark counterparts. Because every component is built on these tokens, the entire UI responds in a single cascade update.
|
|
12
|
+
|
|
13
|
+
## Enabling dark mode
|
|
14
|
+
|
|
15
|
+
### Via `data-theme` attribute (recommended)
|
|
16
|
+
|
|
17
|
+
Set `data-theme="dark"` on a container element — typically `<html>` for a global switch, or any wrapper for a scoped one.
|
|
18
|
+
|
|
19
|
+
```html
|
|
20
|
+
<!-- global dark mode -->
|
|
21
|
+
<html data-theme="dark">
|
|
22
|
+
|
|
23
|
+
<!-- scoped dark mode (only this subtree) -->
|
|
24
|
+
<div data-theme="dark">
|
|
25
|
+
<Button>Dark button</Button>
|
|
26
|
+
</div>
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Remove the attribute (or set `data-theme="light"`) to return to light mode.
|
|
30
|
+
|
|
31
|
+
### Via `prefers-color-scheme` (automatic)
|
|
32
|
+
|
|
33
|
+
No attribute needed. When a user has dark mode enabled at the OS level, the design system tokens switch automatically:
|
|
34
|
+
|
|
35
|
+
```css
|
|
36
|
+
/* this is built into @boostdev/design-system-foundation — nothing to add */
|
|
37
|
+
@media (prefers-color-scheme: dark) {
|
|
38
|
+
:root { /* dark token values */ }
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
`data-theme` always takes precedence over `prefers-color-scheme`, so you can override the system preference.
|
|
43
|
+
|
|
44
|
+
## Building a theme toggle
|
|
45
|
+
|
|
46
|
+
A minimal React hook that syncs with the system preference and lets the user override it:
|
|
47
|
+
|
|
48
|
+
```tsx
|
|
49
|
+
import { useEffect, useState } from 'react';
|
|
50
|
+
|
|
51
|
+
type Theme = 'light' | 'dark';
|
|
52
|
+
|
|
53
|
+
function getSystemTheme(): Theme {
|
|
54
|
+
return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function useTheme() {
|
|
58
|
+
const [theme, setTheme] = useState<Theme>(
|
|
59
|
+
() => (localStorage.getItem('theme') as Theme) ?? getSystemTheme()
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
useEffect(() => {
|
|
63
|
+
document.documentElement.setAttribute('data-theme', theme);
|
|
64
|
+
localStorage.setItem('theme', theme);
|
|
65
|
+
}, [theme]);
|
|
66
|
+
|
|
67
|
+
const toggle = () => setTheme(t => (t === 'dark' ? 'light' : 'dark'));
|
|
68
|
+
|
|
69
|
+
return { theme, toggle };
|
|
70
|
+
}
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Usage:
|
|
74
|
+
|
|
75
|
+
```tsx
|
|
76
|
+
function ThemeToggle() {
|
|
77
|
+
const { theme, toggle } = useTheme();
|
|
78
|
+
return (
|
|
79
|
+
<Button onClick={toggle}>
|
|
80
|
+
{theme === 'dark' ? 'Switch to light' : 'Switch to dark'}
|
|
81
|
+
</Button>
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## Customising tokens in dark mode
|
|
87
|
+
|
|
88
|
+
Override any token in `@layer tokens.override` — the rule applies regardless of the active theme unless you scope it:
|
|
89
|
+
|
|
90
|
+
```css
|
|
91
|
+
@import "@boostdev/design-system-foundation/css";
|
|
92
|
+
|
|
93
|
+
/* override for all themes */
|
|
94
|
+
@layer tokens.override {
|
|
95
|
+
:root {
|
|
96
|
+
--bds-color_green: oklch(60% 0.15 145);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/* override for dark mode only */
|
|
101
|
+
@layer tokens.override {
|
|
102
|
+
[data-theme="dark"],
|
|
103
|
+
@media (prefers-color-scheme: dark) {
|
|
104
|
+
:root:not([data-theme="light"]) {
|
|
105
|
+
--bds-color_green: oklch(75% 0.15 145);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## Component-level dark mode overrides
|
|
112
|
+
|
|
113
|
+
Use component CSS variables to restyle a specific component in dark mode without touching global tokens:
|
|
114
|
+
|
|
115
|
+
```css
|
|
116
|
+
/* make all Tooltips use a high-contrast dark style in both themes */
|
|
117
|
+
.my-app {
|
|
118
|
+
--tooltip_bg: #1a1a1a;
|
|
119
|
+
--tooltip_text: #f5f5f5;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/* only override in dark mode */
|
|
123
|
+
[data-theme="dark"] .my-card {
|
|
124
|
+
--card_color: #1e1e1e;
|
|
125
|
+
}
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
## Testing dark mode in Storybook
|
|
129
|
+
|
|
130
|
+
Use the **Theme** toolbar toggle in the top bar to switch between light and dark mode while browsing stories. This sets `data-theme` on the story canvas root.
|
package/src/types.ts
ADDED
package/src/typings.d.ts
CHANGED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Injects the bdc border-decoration @property rules into the document's adopted stylesheets.
|
|
3
|
+
*
|
|
4
|
+
* @property declarations must live at the document level — they cannot be scoped to a Shadow DOM.
|
|
5
|
+
* This module is imported once by src/web-components/index.ts and runs as a side effect.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const bdcCss = `
|
|
9
|
+
@property --bdc_color {
|
|
10
|
+
syntax: '<color>';
|
|
11
|
+
inherits: false;
|
|
12
|
+
initial-value: currentcolor;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
@property --bdc-outline_width {
|
|
16
|
+
syntax: '<length>';
|
|
17
|
+
inherits: false;
|
|
18
|
+
initial-value: 1px;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
@property --bdc-outline_offset {
|
|
22
|
+
syntax: '<length>';
|
|
23
|
+
inherits: false;
|
|
24
|
+
initial-value: -1px;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
@property --bdc-outline_radius {
|
|
28
|
+
syntax: '<length-percentage>';
|
|
29
|
+
inherits: false;
|
|
30
|
+
initial-value: 0;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
@property --bdc-outline_shadow {
|
|
34
|
+
syntax: '*';
|
|
35
|
+
inherits: false;
|
|
36
|
+
initial-value: none;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
@layer component {
|
|
40
|
+
:root {
|
|
41
|
+
--bdc-outline_border: none;
|
|
42
|
+
|
|
43
|
+
--bdc_color: currentcolor;
|
|
44
|
+
--bdc_color--focus: var(--bds-color_interactive);
|
|
45
|
+
--bdc_color--error: var(--bds-color_error);
|
|
46
|
+
|
|
47
|
+
--bdc-outline_width: 1px;
|
|
48
|
+
--bdc-outline_offset: -1px;
|
|
49
|
+
--bdc-outline_radius: var(--bds-border_radius--xs);
|
|
50
|
+
--bdc-outline_shadow: none;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
`;
|
|
54
|
+
|
|
55
|
+
// Guard against double-injection during hot-reload or test re-evaluation.
|
|
56
|
+
if (!('__bdcInjected' in document)) {
|
|
57
|
+
Object.defineProperty(document, '__bdcInjected', { value: true });
|
|
58
|
+
const sheet = new CSSStyleSheet();
|
|
59
|
+
sheet.replaceSync(bdcCss);
|
|
60
|
+
document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet];
|
|
61
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// Inject global bdc @property declarations into the document.
|
|
2
|
+
// Must run before any component that uses --bdc_color / --bdc-outline_* tokens.
|
|
3
|
+
import './globals';
|
|
4
|
+
|
|
5
|
+
// Phase 1 — proof of concept components
|
|
6
|
+
export { BdsBadge } from './ui/bds-badge';
|
|
7
|
+
export { BdsButton } from './interaction/bds-button';
|
|
8
|
+
export { BdsAlert } from './ui/bds-alert';
|
|
9
|
+
|
|
10
|
+
// Phase 2 — layout-driven components
|
|
11
|
+
export { BdsPopover } from './interaction/bds-popover';
|
|
12
|
+
export { BdsToastProvider } from './interaction/bds-toast-provider';
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
3
|
+
import type { ButtonVariant, ButtonSize } from './bds-button';
|
|
4
|
+
import '../index'; // auto-registers all custom elements
|
|
5
|
+
|
|
6
|
+
// Thin React wrapper so Storybook controls work with the custom element's props
|
|
7
|
+
function BdsButton({
|
|
8
|
+
variant = 'default',
|
|
9
|
+
size = 'medium',
|
|
10
|
+
disabled,
|
|
11
|
+
href,
|
|
12
|
+
hasPulse,
|
|
13
|
+
children,
|
|
14
|
+
}: {
|
|
15
|
+
variant?: ButtonVariant;
|
|
16
|
+
size?: ButtonSize;
|
|
17
|
+
disabled?: boolean;
|
|
18
|
+
href?: string;
|
|
19
|
+
hasPulse?: boolean;
|
|
20
|
+
children?: React.ReactNode;
|
|
21
|
+
}) {
|
|
22
|
+
return React.createElement(
|
|
23
|
+
'bds-button',
|
|
24
|
+
{ variant, size, disabled: disabled || undefined, href, 'has-pulse': hasPulse || undefined },
|
|
25
|
+
children,
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const meta = {
|
|
30
|
+
title: 'Web Components/Interaction/Button',
|
|
31
|
+
component: BdsButton,
|
|
32
|
+
tags: ['!stable', 'experimental'],
|
|
33
|
+
parameters: { layout: 'centered' },
|
|
34
|
+
argTypes: {
|
|
35
|
+
variant: { control: 'select', options: ['default', 'ghost'] },
|
|
36
|
+
size: { control: 'select', options: ['small', 'medium', 'large'] },
|
|
37
|
+
},
|
|
38
|
+
} satisfies Meta<typeof BdsButton>;
|
|
39
|
+
|
|
40
|
+
export default meta;
|
|
41
|
+
type Story = StoryObj<typeof meta>;
|
|
42
|
+
|
|
43
|
+
export const Default: Story = { args: { children: 'Default', variant: 'default' } };
|
|
44
|
+
export const Ghost: Story = { args: { children: 'Ghost', variant: 'ghost' } };
|
|
45
|
+
export const Small: Story = { args: { children: 'Small', size: 'small' } };
|
|
46
|
+
export const Medium: Story = { args: { children: 'Medium', size: 'medium' } };
|
|
47
|
+
export const Large: Story = { args: { children: 'Large', size: 'large' } };
|
|
48
|
+
export const WithPulse: Story = { args: { children: 'Pulsing', hasPulse: true } };
|
|
49
|
+
export const Disabled: Story = { args: { children: 'Disabled', disabled: true } };
|
|
50
|
+
export const AllVariants: Story = {
|
|
51
|
+
render: () => (
|
|
52
|
+
<div style={{ display: 'flex', gap: '12px', flexWrap: 'wrap', alignItems: 'center' }}>
|
|
53
|
+
{(['default', 'ghost'] as const).flatMap(v =>
|
|
54
|
+
(['small', 'medium', 'large'] as const).map(s => (
|
|
55
|
+
<BdsButton key={`${v}-${s}`} variant={v} size={s}>{v} {s}</BdsButton>
|
|
56
|
+
)),
|
|
57
|
+
)}
|
|
58
|
+
</div>
|
|
59
|
+
),
|
|
60
|
+
};
|