@boostdev/design-system-components 1.0.3 → 1.1.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 +51 -10
- package/dist/client.cjs +350 -174
- package/dist/client.css +751 -647
- package/dist/client.d.cts +62 -97
- package/dist/client.d.ts +62 -97
- package/dist/client.js +377 -211
- package/dist/index.cjs +350 -174
- package/dist/index.css +751 -647
- package/dist/index.d.cts +62 -97
- package/dist/index.d.ts +62 -97
- package/dist/index.js +377 -211
- 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 +304 -0
- package/dist/web-components.js +1978 -0
- package/package.json +27 -5
- package/src/components/interaction/Button/Button.module.css +11 -8
- package/src/components/interaction/Button/Button.native.mdx +72 -0
- 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.module.css +7 -7
- package/src/components/interaction/Command/Command.spec.tsx +37 -0
- package/src/components/interaction/Command/Command.stories.tsx +1 -1
- package/src/components/interaction/Command/Command.tsx +39 -4
- package/src/components/interaction/Dialog/Dialog.module.css +10 -13
- package/src/components/interaction/Dialog/Dialog.spec.tsx +53 -1
- package/src/components/interaction/Dialog/Dialog.stories.tsx +18 -1
- package/src/components/interaction/Dialog/Dialog.tsx +52 -18
- package/src/components/interaction/Drawer/Drawer.mdx +14 -0
- package/src/components/interaction/Drawer/Drawer.module.css +11 -11
- package/src/components/interaction/Drawer/Drawer.spec.tsx +48 -1
- package/src/components/interaction/Drawer/Drawer.stories.tsx +1 -1
- package/src/components/interaction/Drawer/Drawer.tsx +40 -6
- package/src/components/interaction/DropdownMenu/DropdownMenu.module.css +6 -6
- 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 +132 -16
- package/src/components/interaction/Popover/Popover.spec.tsx +119 -20
- package/src/components/interaction/Popover/Popover.stories.tsx +1 -1
- package/src/components/interaction/Popover/Popover.tsx +69 -29
- 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 +13 -8
- 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 +9 -9
- package/src/components/interaction/form/Checkbox/Checkbox.native.mdx +74 -0
- 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 +8 -9
- 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 +5 -5
- 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.module.css +1 -1
- 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 +9 -9
- 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.module.css +5 -6
- 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.module.css +3 -3
- 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 +10 -10
- 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 +11 -11
- 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.module.css +1 -1
- 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.module.css +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.module.css +5 -5
- 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.mdx +62 -0
- 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.mdx +50 -0
- 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.mdx +54 -0
- 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.module.css +7 -7
- 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.module.css +5 -5
- 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.module.css +4 -4
- 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.module.css +2 -2
- 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.module.css +7 -7
- 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.module.css +3 -3
- 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 +7 -7
- 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 +6 -6
- 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.module.css +3 -3
- 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.module.css +1 -1
- 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.module.css +9 -9
- 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.module.css +3 -3
- 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.module.css +8 -8
- 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.mdx +56 -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/polyfill-invoker-commands.ts +68 -0
- package/src/react-augment.d.ts +32 -0
- package/src/stories/DesignSystem/DarkMode.mdx +130 -0
- package/src/stories/ReactNative.mdx +121 -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.mdx +106 -0
- package/src/web-components/interaction/BdsButton.stories.tsx +60 -0
- package/src/web-components/interaction/BdsPopover.mdx +120 -0
- package/src/web-components/interaction/BdsPopover.stories.tsx +70 -0
- package/src/web-components/interaction/BdsToastProvider.mdx +94 -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 +174 -0
- package/src/web-components/interaction/bds-popover.ts +229 -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 +22 -0
- package/src/web-components/ui/BdsAlert.mdx +90 -0
- package/src/web-components/ui/BdsAlert.stories.tsx +60 -0
- package/src/web-components/ui/BdsBadge.mdx +74 -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
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { Meta } from '@storybook/blocks';
|
|
2
|
+
|
|
3
|
+
<Meta title="React Native/Overview" />
|
|
4
|
+
|
|
5
|
+
# React Native
|
|
6
|
+
|
|
7
|
+
> **Status: alpha** — components and APIs may change before stable release.
|
|
8
|
+
|
|
9
|
+
`@boostdev/components` ships native implementations for 19 components. These use React Native primitives (`View`, `Text`, `Pressable`, `StyleSheet`) rather than HTML elements, and consume a dedicated token layer instead of CSS custom properties.
|
|
10
|
+
|
|
11
|
+
## Installation
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npm install @boostdev/components
|
|
15
|
+
# or
|
|
16
|
+
pnpm add @boostdev/components
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Metro automatically resolves the native entry point via the `"react-native"` export condition in `package.json` — no extra configuration needed.
|
|
20
|
+
|
|
21
|
+
```ts
|
|
22
|
+
// Import is identical to the web version:
|
|
23
|
+
import { Button, Alert, Badge, Avatar, Typography } from '@boostdev/components';
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Setup — ThemeProvider
|
|
27
|
+
|
|
28
|
+
Wrap your app (or the relevant subtree) in `ThemeProvider` to give native components access to the design token context:
|
|
29
|
+
|
|
30
|
+
```tsx
|
|
31
|
+
import { ThemeProvider } from '@boostdev/components/native/ThemeContext';
|
|
32
|
+
|
|
33
|
+
export default function App() {
|
|
34
|
+
return (
|
|
35
|
+
<ThemeProvider>
|
|
36
|
+
{/* your app */}
|
|
37
|
+
</ThemeProvider>
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
`ThemeProvider` reads the current colour scheme via `useColorScheme()` and applies the corresponding dark/light token set automatically.
|
|
43
|
+
|
|
44
|
+
## Design Tokens
|
|
45
|
+
|
|
46
|
+
Native components consume tokens from `src/native/tokens.ts` — a JS object mirroring the CSS custom properties from `@boostdev/design-system-foundation`. Token categories:
|
|
47
|
+
|
|
48
|
+
| Category | Example |
|
|
49
|
+
|----------|---------|
|
|
50
|
+
| `colors` | `tokens.colors.bg`, `tokens.colors.interactive` |
|
|
51
|
+
| `spacing` | `tokens.spacing.xs`, `tokens.spacing.m` |
|
|
52
|
+
| `font` | `tokens.font.sizeBody`, `tokens.font.weightBold` |
|
|
53
|
+
| `border` | `tokens.border.radiusS`, `tokens.border.radiusM` |
|
|
54
|
+
| `zIndex` | `tokens.zIndex.modal` |
|
|
55
|
+
| `animation` | `tokens.animation.duration` |
|
|
56
|
+
|
|
57
|
+
Tokens are accessed inside components via `useTheme()`:
|
|
58
|
+
|
|
59
|
+
```tsx
|
|
60
|
+
import { useTheme } from '@boostdev/components/native/ThemeContext';
|
|
61
|
+
|
|
62
|
+
function MyComponent() {
|
|
63
|
+
const { tokens } = useTheme();
|
|
64
|
+
return <View style={{ backgroundColor: tokens.colors.bg }} />;
|
|
65
|
+
}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Available Components
|
|
69
|
+
|
|
70
|
+
### UI
|
|
71
|
+
|
|
72
|
+
| Component | Description |
|
|
73
|
+
|-----------|-------------|
|
|
74
|
+
| `Typography` | Text with semantic variants: `h1`, `h2`, `h3`, `body`, `body_s` |
|
|
75
|
+
| `Badge` | Short status label with 5 semantic variants |
|
|
76
|
+
| `Avatar` | Initials-based avatar with 3 sizes |
|
|
77
|
+
| `Alert` | Inline status message with optional title and dismiss |
|
|
78
|
+
| `NotificationBanner` | Full-width banner notification |
|
|
79
|
+
| `Progress` | Linear progress bar |
|
|
80
|
+
| `Skeleton` | Loading placeholder |
|
|
81
|
+
| `Loading` | Animated loading spinner |
|
|
82
|
+
| `Separator` | Visual divider |
|
|
83
|
+
|
|
84
|
+
### Layout
|
|
85
|
+
|
|
86
|
+
| Component | Description |
|
|
87
|
+
|-----------|-------------|
|
|
88
|
+
| `Card` | Elevated content container |
|
|
89
|
+
| `SectionHeader` | Section heading with optional action |
|
|
90
|
+
| `ButtonGroup` | Horizontal or vertical button row |
|
|
91
|
+
| `IconWrapper` | Consistent icon sizing wrapper |
|
|
92
|
+
|
|
93
|
+
### Interaction
|
|
94
|
+
|
|
95
|
+
| Component | Description |
|
|
96
|
+
|-----------|-------------|
|
|
97
|
+
| `Button` | Primary action element with `onPress` |
|
|
98
|
+
|
|
99
|
+
### Form
|
|
100
|
+
|
|
101
|
+
| Component | Description |
|
|
102
|
+
|-----------|-------------|
|
|
103
|
+
| `Checkbox` | Controlled checkbox with label, hint, and error |
|
|
104
|
+
| `Radio` | Controlled radio button |
|
|
105
|
+
| `Switch` | Toggle switch |
|
|
106
|
+
| `Label` | Form field label atom |
|
|
107
|
+
| `Message` | Form field hint/error atom |
|
|
108
|
+
|
|
109
|
+
## Key differences from the web components
|
|
110
|
+
|
|
111
|
+
| Web | React Native |
|
|
112
|
+
|-----|-------------|
|
|
113
|
+
| `onClick` | `onPress` |
|
|
114
|
+
| `aria-label` | `accessibilityLabel` |
|
|
115
|
+
| CSS `className` | `StyleSheet` / `style` prop |
|
|
116
|
+
| `children` as string/HTML | `children` must be `<Text>` nodes (RN restriction) |
|
|
117
|
+
| Design tokens via CSS custom properties | Design tokens via `useTheme()` JS object |
|
|
118
|
+
|
|
119
|
+
## Dark mode
|
|
120
|
+
|
|
121
|
+
`ThemeProvider` subscribes to `useColorScheme()` automatically. No extra work is needed — components adapt their colours when the device switches between light and dark mode.
|
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,106 @@
|
|
|
1
|
+
import { Meta, Canvas, ArgTypes } from '@storybook/blocks';
|
|
2
|
+
import * as Stories from './BdsButton.stories';
|
|
3
|
+
|
|
4
|
+
<Meta of={Stories} />
|
|
5
|
+
|
|
6
|
+
# <bds-button>
|
|
7
|
+
|
|
8
|
+
Framework-agnostic button custom element. Renders as `<button>` or `<a>` depending on whether `href` is set. Matches the React `Button` component in variants, sizes, and theming.
|
|
9
|
+
|
|
10
|
+
> **Status: experimental** — API may change before stable release.
|
|
11
|
+
|
|
12
|
+
## Installation
|
|
13
|
+
|
|
14
|
+
```js
|
|
15
|
+
// Register all web components at once
|
|
16
|
+
import '@boostdev/components/web-components';
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Or in HTML without a bundler:
|
|
20
|
+
|
|
21
|
+
```html
|
|
22
|
+
<script type="module">
|
|
23
|
+
import '@boostdev/components/web-components';
|
|
24
|
+
</script>
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Examples
|
|
28
|
+
|
|
29
|
+
### All variants & sizes
|
|
30
|
+
<Canvas of={Stories.AllVariants} />
|
|
31
|
+
|
|
32
|
+
### Default
|
|
33
|
+
<Canvas of={Stories.Default} />
|
|
34
|
+
|
|
35
|
+
### Ghost
|
|
36
|
+
<Canvas of={Stories.Ghost} />
|
|
37
|
+
|
|
38
|
+
### Sizes
|
|
39
|
+
<Canvas of={Stories.Small} />
|
|
40
|
+
<Canvas of={Stories.Medium} />
|
|
41
|
+
<Canvas of={Stories.Large} />
|
|
42
|
+
|
|
43
|
+
### Pulse (CTA emphasis)
|
|
44
|
+
<Canvas of={Stories.WithPulse} />
|
|
45
|
+
|
|
46
|
+
### Disabled
|
|
47
|
+
<Canvas of={Stories.Disabled} />
|
|
48
|
+
|
|
49
|
+
## Props
|
|
50
|
+
|
|
51
|
+
<ArgTypes of={Stories} />
|
|
52
|
+
|
|
53
|
+
## Attributes
|
|
54
|
+
|
|
55
|
+
| Attribute | Type | Default | Description |
|
|
56
|
+
|-----------|------|---------|-------------|
|
|
57
|
+
| `variant` | `"default" \| "ghost"` | `"default"` | Visual style — filled or transparent outlined |
|
|
58
|
+
| `size` | `"small" \| "medium" \| "large"` | `"medium"` | Height and padding scale |
|
|
59
|
+
| `disabled` | boolean | `false` | Prevents interaction, sets `aria-disabled` |
|
|
60
|
+
| `href` | string | — | Renders as `<a>` when set |
|
|
61
|
+
| `target` | string | — | Forwarded to `<a>` when `href` is set |
|
|
62
|
+
| `rel` | string | — | Forwarded to `<a>` when `href` is set |
|
|
63
|
+
| `type` | `"button" \| "submit" \| "reset"` | `"button"` | Native button type |
|
|
64
|
+
| `has-pulse` | boolean | `false` | Adds animated ring for CTA emphasis |
|
|
65
|
+
| `aria-label` | string | — | Accessible label (required for icon-only buttons) |
|
|
66
|
+
|
|
67
|
+
## Slots
|
|
68
|
+
|
|
69
|
+
| Slot | Description |
|
|
70
|
+
|------|-------------|
|
|
71
|
+
| `(default)` | Button label text |
|
|
72
|
+
| `icon-start` | Icon placed before the label |
|
|
73
|
+
| `icon-end` | Icon placed after the label |
|
|
74
|
+
|
|
75
|
+
## CSS Custom Properties
|
|
76
|
+
|
|
77
|
+
| Property | Description |
|
|
78
|
+
|----------|-------------|
|
|
79
|
+
| `--button_color` | Identity colour — fills the default variant, outlines the ghost variant |
|
|
80
|
+
| `--button_on-color` | Text/icon colour on the button surface. Pair with `--button_color` |
|
|
81
|
+
|
|
82
|
+
## Invoker Commands API
|
|
83
|
+
|
|
84
|
+
`<bds-button>` can control a `<bds-popover>` declaratively using `commandfor` and `command`:
|
|
85
|
+
|
|
86
|
+
```html
|
|
87
|
+
<bds-button commandfor="my-popover" command="--toggle">Open popover</bds-button>
|
|
88
|
+
<bds-popover id="my-popover">
|
|
89
|
+
<p>Popover content</p>
|
|
90
|
+
</bds-popover>
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## Usage in plain HTML
|
|
94
|
+
|
|
95
|
+
```html
|
|
96
|
+
<bds-button variant="default" size="medium">Save</bds-button>
|
|
97
|
+
<bds-button variant="ghost">Cancel</bds-button>
|
|
98
|
+
<bds-button href="/dashboard">Go to dashboard</bds-button>
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## Accessibility
|
|
102
|
+
|
|
103
|
+
- Always provide a label via slot content or `aria-label` (required for icon-only buttons)
|
|
104
|
+
- `disabled` sets `aria-disabled="true"` and prevents click events
|
|
105
|
+
- When rendered as `<a>`, `href` must point to a valid destination
|
|
106
|
+
- `has-pulse` animation respects `prefers-reduced-motion`
|
|
@@ -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
|
+
};
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { Meta, Canvas, ArgTypes } from '@storybook/blocks';
|
|
2
|
+
import * as Stories from './BdsPopover.stories';
|
|
3
|
+
|
|
4
|
+
<Meta of={Stories} />
|
|
5
|
+
|
|
6
|
+
# <bds-popover>
|
|
7
|
+
|
|
8
|
+
Framework-agnostic popover custom element. A non-modal floating panel anchored to a trigger element. Uses CSS Anchor Positioning for automatic repositioning when near viewport edges.
|
|
9
|
+
|
|
10
|
+
> **Status: experimental** — API may change before stable release.
|
|
11
|
+
|
|
12
|
+
## Installation
|
|
13
|
+
|
|
14
|
+
```js
|
|
15
|
+
import '@boostdev/components/web-components';
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Examples
|
|
19
|
+
|
|
20
|
+
### Default (bottom)
|
|
21
|
+
<Canvas of={Stories.Default} />
|
|
22
|
+
|
|
23
|
+
### Top
|
|
24
|
+
<Canvas of={Stories.Top} />
|
|
25
|
+
|
|
26
|
+
### Right
|
|
27
|
+
<Canvas of={Stories.Right} />
|
|
28
|
+
|
|
29
|
+
### Left
|
|
30
|
+
<Canvas of={Stories.Left} />
|
|
31
|
+
|
|
32
|
+
### With rich content
|
|
33
|
+
<Canvas of={Stories.WithRichContent} />
|
|
34
|
+
|
|
35
|
+
### All placements
|
|
36
|
+
<Canvas of={Stories.AllPlacements} />
|
|
37
|
+
|
|
38
|
+
## Props
|
|
39
|
+
|
|
40
|
+
<ArgTypes of={Stories} />
|
|
41
|
+
|
|
42
|
+
## Attributes
|
|
43
|
+
|
|
44
|
+
| Attribute | Type | Default | Description |
|
|
45
|
+
|-----------|------|---------|-------------|
|
|
46
|
+
| `placement` | `"bottom" \| "top" \| "left" \| "right"` | `"bottom"` | Preferred panel position relative to the trigger |
|
|
47
|
+
| `open` | boolean | `false` | Controls panel visibility; reflects on the element |
|
|
48
|
+
|
|
49
|
+
## Slots
|
|
50
|
+
|
|
51
|
+
| Slot | Description |
|
|
52
|
+
|------|-------------|
|
|
53
|
+
| `trigger` | Element that opens and closes the panel on click |
|
|
54
|
+
| `(default)` | Panel content |
|
|
55
|
+
|
|
56
|
+
## Events
|
|
57
|
+
|
|
58
|
+
| Event | Detail | Bubbles | Composed | Description |
|
|
59
|
+
|-------|--------|---------|----------|-------------|
|
|
60
|
+
| `bds-open` | — | Yes | Yes | Fired when the panel opens |
|
|
61
|
+
| `bds-close` | — | Yes | Yes | Fired when the panel closes |
|
|
62
|
+
|
|
63
|
+
## Behaviour
|
|
64
|
+
|
|
65
|
+
- Clicking the trigger toggles the panel open/closed
|
|
66
|
+
- Pressing `Escape` closes an open panel
|
|
67
|
+
- Clicking outside the element closes the panel
|
|
68
|
+
- CSS Anchor Positioning automatically tries fallback placements (`@position-try`) when the preferred placement would overflow the viewport
|
|
69
|
+
- Each instance gets a unique CSS anchor name — multiple popovers on the same page don't interfere
|
|
70
|
+
|
|
71
|
+
## Invoker Commands API
|
|
72
|
+
|
|
73
|
+
Control the popover declaratively from any `<button>` using `commandfor` and `command` — no JavaScript required:
|
|
74
|
+
|
|
75
|
+
```html
|
|
76
|
+
<button commandfor="my-popover" command="--toggle">Open</button>
|
|
77
|
+
<button commandfor="my-popover" command="--open">Open only</button>
|
|
78
|
+
<button commandfor="my-popover" command="--close">Close only</button>
|
|
79
|
+
|
|
80
|
+
<bds-popover id="my-popover">
|
|
81
|
+
<p>Panel content</p>
|
|
82
|
+
</bds-popover>
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## Usage in plain HTML
|
|
86
|
+
|
|
87
|
+
```html
|
|
88
|
+
<bds-popover placement="bottom">
|
|
89
|
+
<button slot="trigger">Open menu</button>
|
|
90
|
+
<nav>
|
|
91
|
+
<a href="/profile">Profile</a>
|
|
92
|
+
<a href="/settings">Settings</a>
|
|
93
|
+
<a href="/logout">Log out</a>
|
|
94
|
+
</nav>
|
|
95
|
+
</bds-popover>
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Listen for open/close events:
|
|
99
|
+
|
|
100
|
+
```js
|
|
101
|
+
const popover = document.querySelector('bds-popover');
|
|
102
|
+
popover.addEventListener('bds-open', () => console.log('opened'));
|
|
103
|
+
popover.addEventListener('bds-close', () => console.log('closed'));
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## CSS Custom Properties
|
|
107
|
+
|
|
108
|
+
| Property | Default | Description |
|
|
109
|
+
|----------|---------|-------------|
|
|
110
|
+
| `--popover_color` | `--bds-color_bg` | Panel background |
|
|
111
|
+
| `--popover_on-color` | `--bds-color_on-bg` | Panel text colour |
|
|
112
|
+
| `--popover_shadow` | `--bds-shadow_m` | Panel drop shadow |
|
|
113
|
+
| `--popover_z-index` | `100` | Stacking order |
|
|
114
|
+
|
|
115
|
+
## Accessibility
|
|
116
|
+
|
|
117
|
+
- The panel has `role="region"` and `aria-label="Popover"`
|
|
118
|
+
- The trigger element retains its own role (e.g. `<button>`) — no ARIA is added by the component
|
|
119
|
+
- For menus, use a `<nav>` or `role="menu"` inside the default slot as appropriate
|
|
120
|
+
- The component does not trap focus — use `<bds-dialog>` for modal, focus-trapped overlays
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
3
|
+
import type { PopoverPlacement } from './bds-popover';
|
|
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 BdsPopover({
|
|
8
|
+
placement = 'bottom',
|
|
9
|
+
children,
|
|
10
|
+
trigger,
|
|
11
|
+
}: {
|
|
12
|
+
placement?: PopoverPlacement;
|
|
13
|
+
children?: React.ReactNode;
|
|
14
|
+
trigger?: React.ReactNode;
|
|
15
|
+
}) {
|
|
16
|
+
return React.createElement(
|
|
17
|
+
'bds-popover',
|
|
18
|
+
{ placement },
|
|
19
|
+
trigger ?? React.createElement('button', { slot: 'trigger' }, 'Open popover'),
|
|
20
|
+
children ?? React.createElement('p', { style: { margin: 0 } }, 'Popover content'),
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const meta = {
|
|
25
|
+
title: 'Web Components/Interaction/Popover',
|
|
26
|
+
component: BdsPopover,
|
|
27
|
+
tags: ['!stable', 'experimental'],
|
|
28
|
+
parameters: { layout: 'centered' },
|
|
29
|
+
argTypes: {
|
|
30
|
+
placement: { control: 'select', options: ['bottom', 'top', 'left', 'right'] },
|
|
31
|
+
},
|
|
32
|
+
} satisfies Meta<typeof BdsPopover>;
|
|
33
|
+
|
|
34
|
+
export default meta;
|
|
35
|
+
type Story = StoryObj<typeof meta>;
|
|
36
|
+
|
|
37
|
+
export const Default: Story = { args: { placement: 'bottom' } };
|
|
38
|
+
export const Top: Story = { args: { placement: 'top' } };
|
|
39
|
+
export const Right: Story = { args: { placement: 'right' } };
|
|
40
|
+
export const Left: Story = { args: { placement: 'left' } };
|
|
41
|
+
|
|
42
|
+
export const WithRichContent: Story = {
|
|
43
|
+
args: { placement: 'bottom' },
|
|
44
|
+
render: (args) => (
|
|
45
|
+
<BdsPopover {...args}>
|
|
46
|
+
{React.createElement(
|
|
47
|
+
'div',
|
|
48
|
+
{ style: { display: 'flex', flexDirection: 'column', gap: '0.5rem' } },
|
|
49
|
+
React.createElement('strong', null, 'Actions'),
|
|
50
|
+
React.createElement('button', null, 'Edit'),
|
|
51
|
+
React.createElement('button', null, 'Duplicate'),
|
|
52
|
+
React.createElement('button', null, 'Delete'),
|
|
53
|
+
)}
|
|
54
|
+
</BdsPopover>
|
|
55
|
+
),
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
export const AllPlacements: Story = {
|
|
59
|
+
render: () => (
|
|
60
|
+
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(2, auto)', gap: '3rem', padding: '4rem' }}>
|
|
61
|
+
{(['bottom', 'top', 'right', 'left'] as const).map(p => (
|
|
62
|
+
<div key={p} style={{ display: 'flex', justifyContent: 'center' }}>
|
|
63
|
+
<BdsPopover placement={p}>
|
|
64
|
+
{React.createElement('p', { style: { margin: 0 } }, `Placed ${p}`)}
|
|
65
|
+
</BdsPopover>
|
|
66
|
+
</div>
|
|
67
|
+
))}
|
|
68
|
+
</div>
|
|
69
|
+
),
|
|
70
|
+
};
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { Meta, Canvas, ArgTypes } from '@storybook/blocks';
|
|
2
|
+
import * as Stories from './BdsToastProvider.stories';
|
|
3
|
+
|
|
4
|
+
<Meta of={Stories} />
|
|
5
|
+
|
|
6
|
+
# <bds-toast-provider>
|
|
7
|
+
|
|
8
|
+
Framework-agnostic toast notification provider. Wrap your page content in `<bds-toast-provider>` to enable toast notifications that render in the browser top layer (above fixed/sticky elements). Auto-dismisses after 5 seconds.
|
|
9
|
+
|
|
10
|
+
> **Status: experimental** — API may change before stable release.
|
|
11
|
+
|
|
12
|
+
## Installation
|
|
13
|
+
|
|
14
|
+
```js
|
|
15
|
+
import '@boostdev/components/web-components';
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Examples
|
|
19
|
+
|
|
20
|
+
### Static API
|
|
21
|
+
<Canvas of={Stories.Default} />
|
|
22
|
+
|
|
23
|
+
### Event API (no import required)
|
|
24
|
+
<Canvas of={Stories.EventAPI} />
|
|
25
|
+
|
|
26
|
+
## Slots
|
|
27
|
+
|
|
28
|
+
| Slot | Description |
|
|
29
|
+
|------|-------------|
|
|
30
|
+
| `(default)` | Page content. `<bds-toast-provider>` renders as `display: contents` so it is invisible in the layout |
|
|
31
|
+
|
|
32
|
+
## Three ways to show a toast
|
|
33
|
+
|
|
34
|
+
### 1. Static method (import required)
|
|
35
|
+
|
|
36
|
+
```js
|
|
37
|
+
import { BdsToastProvider } from '@boostdev/components/web-components';
|
|
38
|
+
|
|
39
|
+
BdsToastProvider.show('File saved', 'success');
|
|
40
|
+
BdsToastProvider.show('Something went wrong', 'error');
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### 2. Instance method
|
|
44
|
+
|
|
45
|
+
```js
|
|
46
|
+
const provider = document.querySelector('bds-toast-provider');
|
|
47
|
+
provider.showToast('Settings updated', 'info');
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### 3. Document event (no import required)
|
|
51
|
+
|
|
52
|
+
Useful in frameworks or contexts where importing the class is inconvenient:
|
|
53
|
+
|
|
54
|
+
```js
|
|
55
|
+
document.dispatchEvent(new CustomEvent('bds-show-toast', {
|
|
56
|
+
detail: { message: 'Copied to clipboard', variant: 'success' },
|
|
57
|
+
}));
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Toast variants
|
|
61
|
+
|
|
62
|
+
| Variant | Use for |
|
|
63
|
+
|---------|---------|
|
|
64
|
+
| `info` | Neutral status updates |
|
|
65
|
+
| `success` | Completed actions |
|
|
66
|
+
| `warning` | Potential issues the user should know about |
|
|
67
|
+
| `error` | Failures requiring attention |
|
|
68
|
+
|
|
69
|
+
## Setup in plain HTML
|
|
70
|
+
|
|
71
|
+
```html
|
|
72
|
+
<bds-toast-provider>
|
|
73
|
+
<!-- all your page content goes here -->
|
|
74
|
+
<main>…</main>
|
|
75
|
+
</bds-toast-provider>
|
|
76
|
+
|
|
77
|
+
<script type="module">
|
|
78
|
+
import '@boostdev/components/web-components';
|
|
79
|
+
// or use the document event API — no import needed
|
|
80
|
+
</script>
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## Behaviour
|
|
84
|
+
|
|
85
|
+
- Toasts render in the browser top layer via the Popover API (`popover="manual"`) — they appear above `position: fixed` elements and `z-index` stacking
|
|
86
|
+
- Each toast auto-dismisses after **5000 ms**
|
|
87
|
+
- Multiple toasts stack vertically and each has its own dismissal timer
|
|
88
|
+
- A visible dismiss (×) button is always present on each toast
|
|
89
|
+
|
|
90
|
+
## Accessibility
|
|
91
|
+
|
|
92
|
+
- Each toast renders with `role="status"` + `aria-live="polite"` by default so screen readers announce it without interrupting the user
|
|
93
|
+
- `error` toasts use `role="alert"` + `aria-live="assertive"` for immediate announcement
|
|
94
|
+
- The dismiss button has an accessible label
|