@boostdev/design-system-components 1.2.0 → 1.2.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 +25 -4
- package/dist/client.cjs +58 -54
- package/dist/client.css +503 -525
- package/dist/client.js +58 -54
- package/dist/index.cjs +58 -54
- package/dist/index.css +503 -525
- package/dist/index.js +58 -54
- package/dist/web-components/{chunk-6MH5UWUD.js → chunk-2FGATTGT.js} +5 -0
- package/dist/web-components/{chunk-5IPHEONG.js → chunk-6I2DBFQ7.js} +1 -0
- package/dist/web-components/{chunk-DI46Q2EA.js → chunk-OCODKRVZ.js} +57 -82
- package/dist/web-components/index.d.ts +571 -1
- package/dist/web-components/index.js +1501 -4
- package/dist/web-components/interaction/bds-collapsible.js +1 -1
- package/dist/web-components/interaction/bds-drawer.js +1 -1
- package/dist/web-components/interaction/form/bds-segmented-control.js +1 -1
- package/package.json +1 -1
- package/src/components/interaction/Drawer/Drawer.module.css +37 -62
- package/src/components/interaction/Drawer/Drawer.tsx +21 -17
- package/src/components/interaction/form/SegmentedControl/SegmentedControl.mdx +8 -4
- package/src/components/interaction/form/SegmentedControl/SegmentedControl.module.css +13 -6
- package/src/stories/Introduction.mdx +2 -1
- package/src/web-components/index.ts +12 -0
- package/src/web-components/interaction/BdsAccordion.mdx +80 -28
- package/src/web-components/interaction/BdsAccordion.stories.tsx +67 -58
- package/src/web-components/interaction/BdsCollapsible.mdx +93 -23
- package/src/web-components/interaction/BdsCollapsible.stories.tsx +29 -48
- package/src/web-components/interaction/BdsDialog.mdx +88 -27
- package/src/web-components/interaction/BdsDialog.stories.tsx +129 -47
- package/src/web-components/interaction/BdsDrawer.mdx +85 -27
- package/src/web-components/interaction/BdsDrawer.stories.tsx +161 -31
- package/src/web-components/interaction/BdsDropdownMenu.mdx +108 -0
- package/src/web-components/interaction/BdsDropdownMenu.stories.tsx +91 -0
- package/src/web-components/interaction/BdsSkipLink.mdx +72 -16
- package/src/web-components/interaction/BdsSkipLink.stories.tsx +47 -34
- package/src/web-components/interaction/BdsTabs.mdx +97 -27
- package/src/web-components/interaction/BdsTabs.stories.tsx +69 -55
- package/src/web-components/interaction/BdsTooltip.mdx +84 -18
- package/src/web-components/interaction/BdsTooltip.stories.tsx +49 -30
- package/src/web-components/interaction/bds-collapsible.ts +1 -0
- package/src/web-components/interaction/bds-drawer.ts +59 -82
- package/src/web-components/interaction/bds-dropdown-menu-item.ts +124 -0
- package/src/web-components/interaction/bds-dropdown-menu.spec.ts +102 -0
- package/src/web-components/interaction/bds-dropdown-menu.ts +200 -0
- package/src/web-components/interaction/form/BdsCheckbox.mdx +57 -20
- package/src/web-components/interaction/form/BdsCheckbox.stories.tsx +35 -36
- package/src/web-components/interaction/form/BdsCheckboxGroup.mdx +70 -0
- package/src/web-components/interaction/form/BdsCheckboxGroup.stories.tsx +81 -0
- package/src/web-components/interaction/form/BdsCombobox.mdx +52 -33
- package/src/web-components/interaction/form/BdsCombobox.stories.tsx +55 -53
- package/src/web-components/interaction/form/BdsFileInput.mdx +59 -24
- package/src/web-components/interaction/form/BdsFileInput.stories.tsx +38 -53
- package/src/web-components/interaction/form/BdsFormInput.mdx +98 -0
- package/src/web-components/interaction/form/BdsFormInput.stories.tsx +139 -0
- package/src/web-components/interaction/form/BdsNumberInput.mdx +51 -22
- package/src/web-components/interaction/form/BdsNumberInput.stories.tsx +24 -46
- package/src/web-components/interaction/form/BdsRadio.mdx +53 -22
- package/src/web-components/interaction/form/BdsRadio.stories.tsx +19 -51
- package/src/web-components/interaction/form/BdsRadioGroup.mdx +73 -0
- package/src/web-components/interaction/form/BdsRadioGroup.stories.tsx +88 -0
- package/src/web-components/interaction/form/BdsSegmentedControl.mdx +76 -23
- package/src/web-components/interaction/form/BdsSegmentedControl.stories.tsx +64 -54
- package/src/web-components/interaction/form/BdsSelect.mdx +59 -21
- package/src/web-components/interaction/form/BdsSelect.stories.tsx +47 -56
- package/src/web-components/interaction/form/BdsSlider.mdx +55 -27
- package/src/web-components/interaction/form/BdsSlider.stories.tsx +23 -44
- package/src/web-components/interaction/form/BdsSwitch.mdx +53 -20
- package/src/web-components/interaction/form/BdsSwitch.stories.tsx +22 -37
- package/src/web-components/interaction/form/BdsTextarea.mdx +54 -22
- package/src/web-components/interaction/form/BdsTextarea.stories.tsx +35 -44
- package/src/web-components/interaction/form/bds-checkbox-group.spec.ts +55 -0
- package/src/web-components/interaction/form/bds-checkbox-group.ts +117 -0
- package/src/web-components/interaction/form/bds-form-input.spec.ts +83 -0
- package/src/web-components/interaction/form/bds-form-input.ts +268 -0
- package/src/web-components/interaction/form/bds-radio-group.spec.ts +62 -0
- package/src/web-components/interaction/form/bds-radio-group.ts +142 -0
- package/src/web-components/interaction/form/bds-segmented-control.ts +5 -0
- package/src/web-components/ui/BdsAvatar.mdx +29 -20
- package/src/web-components/ui/BdsAvatar.stories.tsx +14 -28
- package/src/web-components/ui/BdsBreadcrumb.mdx +22 -19
- package/src/web-components/ui/BdsBreadcrumb.stories.tsx +11 -21
- package/src/web-components/ui/BdsButtonGroup.mdx +69 -0
- package/src/web-components/ui/BdsButtonGroup.stories.tsx +66 -0
- package/src/web-components/ui/BdsCalendar.mdx +93 -0
- package/src/web-components/ui/BdsCalendar.stories.tsx +63 -0
- package/src/web-components/ui/BdsCard.mdx +30 -25
- package/src/web-components/ui/BdsCard.stories.tsx +19 -42
- package/src/web-components/ui/BdsCarousel.mdx +83 -0
- package/src/web-components/ui/BdsCarousel.stories.tsx +96 -0
- package/src/web-components/ui/BdsDescriptionList.mdx +13 -16
- package/src/web-components/ui/BdsDescriptionList.stories.tsx +34 -49
- package/src/web-components/ui/BdsIconWrapper.mdx +20 -20
- package/src/web-components/ui/BdsIconWrapper.stories.tsx +46 -41
- package/src/web-components/ui/BdsLink.mdx +21 -17
- package/src/web-components/ui/BdsLink.stories.tsx +19 -20
- package/src/web-components/ui/BdsLoading.mdx +9 -13
- package/src/web-components/ui/BdsLoading.stories.tsx +8 -10
- package/src/web-components/ui/BdsNotificationBanner.mdx +32 -37
- package/src/web-components/ui/BdsNotificationBanner.stories.tsx +38 -47
- package/src/web-components/ui/BdsPagination.mdx +74 -0
- package/src/web-components/ui/BdsPagination.stories.tsx +36 -0
- package/src/web-components/ui/BdsProgress.mdx +24 -17
- package/src/web-components/ui/BdsProgress.stories.tsx +55 -29
- package/src/web-components/ui/BdsProgressCircle.mdx +24 -18
- package/src/web-components/ui/BdsProgressCircle.stories.tsx +17 -29
- package/src/web-components/ui/BdsRating.mdx +22 -22
- package/src/web-components/ui/BdsRating.stories.tsx +19 -13
- package/src/web-components/ui/BdsSectionHeader.mdx +31 -28
- package/src/web-components/ui/BdsSectionHeader.stories.tsx +21 -23
- package/src/web-components/ui/BdsSeparator.mdx +22 -8
- package/src/web-components/ui/BdsSeparator.stories.tsx +27 -19
- package/src/web-components/ui/BdsSkeleton.mdx +20 -26
- package/src/web-components/ui/BdsSkeleton.stories.tsx +23 -23
- package/src/web-components/ui/BdsTable.mdx +81 -0
- package/src/web-components/ui/BdsTable.stories.tsx +83 -0
- package/src/web-components/ui/BdsTypography.mdx +20 -29
- package/src/web-components/ui/BdsTypography.stories.tsx +19 -18
- package/src/web-components/ui/bds-button-group.spec.ts +40 -0
- package/src/web-components/ui/bds-button-group.ts +78 -0
- package/src/web-components/ui/bds-calendar.spec.ts +91 -0
- package/src/web-components/ui/bds-calendar.ts +427 -0
- package/src/web-components/ui/bds-carousel.spec.ts +64 -0
- package/src/web-components/ui/bds-carousel.ts +296 -0
- package/src/web-components/ui/bds-pagination.spec.ts +67 -0
- package/src/web-components/ui/bds-pagination.ts +197 -0
- package/src/web-components/ui/bds-table.spec.ts +45 -0
- package/src/web-components/ui/bds-table.ts +96 -0
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import type { Meta, StoryObj } from '@storybook/react';
|
|
3
|
-
import '../index';
|
|
3
|
+
import '../index'; // auto-registers all custom elements
|
|
4
4
|
|
|
5
|
-
function BdsSeparator({
|
|
5
|
+
function BdsSeparator({
|
|
6
|
+
orientation = 'horizontal',
|
|
7
|
+
}: {
|
|
8
|
+
orientation?: 'horizontal' | 'vertical';
|
|
9
|
+
}) {
|
|
6
10
|
return React.createElement('bds-separator', { orientation });
|
|
7
11
|
}
|
|
8
12
|
|
|
@@ -12,36 +16,40 @@ const meta = {
|
|
|
12
16
|
tags: ['!stable', 'experimental'],
|
|
13
17
|
parameters: { layout: 'centered' },
|
|
14
18
|
argTypes: {
|
|
15
|
-
orientation: { control: '
|
|
19
|
+
orientation: { control: 'radio', options: ['horizontal', 'vertical'] },
|
|
16
20
|
},
|
|
17
21
|
} satisfies Meta<typeof BdsSeparator>;
|
|
18
22
|
|
|
19
23
|
export default meta;
|
|
20
24
|
type Story = StoryObj<typeof meta>;
|
|
21
25
|
|
|
22
|
-
export const
|
|
26
|
+
export const Default: Story = {
|
|
27
|
+
args: { orientation: 'horizontal' },
|
|
28
|
+
render: ({ orientation }) => (
|
|
29
|
+
<div style={{ width: 300 }}>
|
|
30
|
+
<p style={{ margin: 0 }}>Above the separator</p>
|
|
31
|
+
{React.createElement('bds-separator', { orientation })}
|
|
32
|
+
<p style={{ margin: 0 }}>Below the separator</p>
|
|
33
|
+
</div>
|
|
34
|
+
),
|
|
35
|
+
};
|
|
23
36
|
|
|
24
|
-
export const
|
|
37
|
+
export const Horizontal: Story = {
|
|
25
38
|
render: () => (
|
|
26
|
-
<div style={{
|
|
27
|
-
<
|
|
28
|
-
|
|
29
|
-
<
|
|
39
|
+
<div style={{ width: 300 }}>
|
|
40
|
+
<p style={{ margin: 0 }}>First section</p>
|
|
41
|
+
{React.createElement('bds-separator', { orientation: 'horizontal' })}
|
|
42
|
+
<p style={{ margin: 0 }}>Second section</p>
|
|
30
43
|
</div>
|
|
31
44
|
),
|
|
32
45
|
};
|
|
33
46
|
|
|
34
|
-
export const
|
|
47
|
+
export const Vertical: Story = {
|
|
35
48
|
render: () => (
|
|
36
|
-
<div style={{ display: 'flex',
|
|
37
|
-
<
|
|
38
|
-
|
|
39
|
-
<
|
|
40
|
-
<div style={{ display: 'flex', alignItems: 'center', gap: '16px', height: '40px' }}>
|
|
41
|
-
<span>Left</span>
|
|
42
|
-
<BdsSeparator orientation="vertical" />
|
|
43
|
-
<span>Right</span>
|
|
44
|
-
</div>
|
|
49
|
+
<div style={{ display: 'flex', alignItems: 'center', gap: 12, height: 40 }}>
|
|
50
|
+
<span>Left</span>
|
|
51
|
+
{React.createElement('bds-separator', { orientation: 'vertical' })}
|
|
52
|
+
<span>Right</span>
|
|
45
53
|
</div>
|
|
46
54
|
),
|
|
47
55
|
};
|
|
@@ -5,7 +5,7 @@ import * as Stories from './BdsSkeleton.stories';
|
|
|
5
5
|
|
|
6
6
|
# <bds-skeleton>
|
|
7
7
|
|
|
8
|
-
Framework-agnostic Skeleton loading placeholder.
|
|
8
|
+
Framework-agnostic Skeleton loading placeholder custom element. Displays an animated shimmer while real content is loading. Size is set via inline styles or CSS on the host element.
|
|
9
9
|
|
|
10
10
|
> **Status: experimental** — API may change before stable release.
|
|
11
11
|
|
|
@@ -15,19 +15,24 @@ Framework-agnostic Skeleton loading placeholder. Shows a shimmer animation while
|
|
|
15
15
|
import '@boostdev/components/web-components';
|
|
16
16
|
```
|
|
17
17
|
|
|
18
|
+
## When to use
|
|
19
|
+
|
|
20
|
+
- While fetching data, replace text, images, and cards with skeleton placeholders to reduce perceived loading time
|
|
21
|
+
- Match the shape of the final content as closely as possible
|
|
22
|
+
|
|
18
23
|
## Examples
|
|
19
24
|
|
|
20
|
-
###
|
|
21
|
-
<Canvas of={Stories.
|
|
25
|
+
### Default
|
|
26
|
+
<Canvas of={Stories.Default} />
|
|
22
27
|
|
|
23
|
-
###
|
|
24
|
-
<Canvas of={Stories.
|
|
28
|
+
### Heading placeholder
|
|
29
|
+
<Canvas of={Stories.Heading} />
|
|
25
30
|
|
|
26
31
|
### Avatar placeholder
|
|
27
32
|
<Canvas of={Stories.Avatar} />
|
|
28
33
|
|
|
29
|
-
###
|
|
30
|
-
<Canvas of={Stories.
|
|
34
|
+
### Content block
|
|
35
|
+
<Canvas of={Stories.ContentBlock} />
|
|
31
36
|
|
|
32
37
|
## Props
|
|
33
38
|
|
|
@@ -35,33 +40,22 @@ import '@boostdev/components/web-components';
|
|
|
35
40
|
|
|
36
41
|
## Attributes
|
|
37
42
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
## CSS Custom Properties
|
|
41
|
-
|
|
42
|
-
The shimmer animation uses design tokens directly:
|
|
43
|
-
|
|
44
|
-
| Token | Description |
|
|
45
|
-
|-------|-------------|
|
|
46
|
-
| `--bds-color_grey--subtle` | Shimmer base colour |
|
|
47
|
-
| `--bds-color_bg` | Shimmer highlight colour |
|
|
48
|
-
| `--bds-border_radius--xs` | Default corner radius |
|
|
43
|
+
`<bds-skeleton>` has no custom attributes. Size is controlled via inline styles or CSS.
|
|
49
44
|
|
|
50
45
|
## Usage in plain HTML
|
|
51
46
|
|
|
52
47
|
```html
|
|
53
|
-
<!--
|
|
48
|
+
<!-- Inline text placeholder -->
|
|
54
49
|
<bds-skeleton style="width: 200px; height: 1rem;"></bds-skeleton>
|
|
55
50
|
|
|
56
|
-
<!--
|
|
57
|
-
<bds-skeleton style="width:
|
|
51
|
+
<!-- Heading placeholder -->
|
|
52
|
+
<bds-skeleton style="width: 300px; height: 2rem;"></bds-skeleton>
|
|
58
53
|
|
|
59
|
-
<!--
|
|
60
|
-
<bds-skeleton style="width:
|
|
54
|
+
<!-- Avatar placeholder -->
|
|
55
|
+
<bds-skeleton style="width: 48px; height: 48px; border-radius: 50%;"></bds-skeleton>
|
|
61
56
|
```
|
|
62
57
|
|
|
63
58
|
## Accessibility
|
|
64
59
|
|
|
65
|
-
-
|
|
66
|
-
-
|
|
67
|
-
- Respects `prefers-reduced-motion`: shimmer animation is disabled for users who prefer reduced motion
|
|
60
|
+
- The inner `<span>` carries `aria-hidden="true"` so screen readers skip the placeholder
|
|
61
|
+
- Replace the skeleton with real content and a meaningful accessible label once loaded
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import type { Meta, StoryObj } from '@storybook/react';
|
|
3
|
-
import '../index';
|
|
3
|
+
import '../index'; // auto-registers all custom elements
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
// bds-skeleton has no attributes — the wrapper just passes inline style
|
|
6
|
+
function BdsSkeleton({ width = '200px', height = '1rem' }: { width?: string; height?: string }) {
|
|
7
|
+
return React.createElement('bds-skeleton', { style: `width: ${width}; height: ${height};` });
|
|
7
8
|
}
|
|
8
9
|
|
|
9
10
|
const meta = {
|
|
@@ -11,40 +12,39 @@ const meta = {
|
|
|
11
12
|
component: BdsSkeleton,
|
|
12
13
|
tags: ['!stable', 'experimental'],
|
|
13
14
|
parameters: { layout: 'centered' },
|
|
15
|
+
argTypes: {
|
|
16
|
+
width: { control: 'text' },
|
|
17
|
+
height: { control: 'text' },
|
|
18
|
+
},
|
|
14
19
|
} satisfies Meta<typeof BdsSkeleton>;
|
|
15
20
|
|
|
16
21
|
export default meta;
|
|
17
22
|
type Story = StoryObj<typeof meta>;
|
|
18
23
|
|
|
19
|
-
export const
|
|
20
|
-
|
|
24
|
+
export const Default: Story = {
|
|
25
|
+
args: { width: '200px', height: '1rem' },
|
|
21
26
|
};
|
|
22
27
|
|
|
23
28
|
export const Heading: Story = {
|
|
24
|
-
|
|
29
|
+
args: { width: '300px', height: '2rem' },
|
|
25
30
|
};
|
|
26
31
|
|
|
27
32
|
export const Avatar: Story = {
|
|
28
|
-
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
+
args: { width: '48px', height: '48px' },
|
|
34
|
+
render: ({ width, height }) => (
|
|
35
|
+
<div style={{ borderRadius: '50%', overflow: 'hidden', display: 'inline-block', width, height }}>
|
|
36
|
+
{React.createElement('bds-skeleton', { style: `width: ${width}; height: ${height};` })}
|
|
37
|
+
</div>
|
|
38
|
+
),
|
|
33
39
|
};
|
|
34
40
|
|
|
35
|
-
export const
|
|
41
|
+
export const ContentBlock: Story = {
|
|
36
42
|
render: () => (
|
|
37
|
-
<div style={{ display: 'flex', flexDirection: 'column', gap:
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
<BdsSkeleton style={{ width: '60%', height: '0.75rem' }} />
|
|
43
|
-
</div>
|
|
44
|
-
</div>
|
|
45
|
-
<BdsSkeleton style={{ width: '100%', height: '120px' }} />
|
|
46
|
-
<BdsSkeleton style={{ width: '80%', height: '0.875rem' }} />
|
|
47
|
-
<BdsSkeleton style={{ width: '60%', height: '0.875rem' }} />
|
|
43
|
+
<div style={{ display: 'flex', flexDirection: 'column', gap: 8, width: 300 }}>
|
|
44
|
+
{React.createElement('bds-skeleton', { style: 'width: 100%; height: 1.5rem;' })}
|
|
45
|
+
{React.createElement('bds-skeleton', { style: 'width: 80%; height: 1rem;' })}
|
|
46
|
+
{React.createElement('bds-skeleton', { style: 'width: 90%; height: 1rem;' })}
|
|
47
|
+
{React.createElement('bds-skeleton', { style: 'width: 60%; height: 1rem;' })}
|
|
48
48
|
</div>
|
|
49
49
|
),
|
|
50
50
|
};
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { Meta, Canvas, ArgTypes } from '@storybook/blocks';
|
|
2
|
+
import * as Stories from './BdsTable.stories';
|
|
3
|
+
|
|
4
|
+
<Meta of={Stories} />
|
|
5
|
+
|
|
6
|
+
# <bds-table>
|
|
7
|
+
|
|
8
|
+
Framework-agnostic scrollable Table wrapper custom element. Apply design-system styles to a standard `<table>` element by nesting it in the default slot.
|
|
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
|
+
## When to use
|
|
19
|
+
|
|
20
|
+
- Displaying tabular data with design-system typography and colour tokens
|
|
21
|
+
- Use `sticky-header` to keep `<thead>` visible when the table overflows vertically inside a fixed-height container
|
|
22
|
+
|
|
23
|
+
## Examples
|
|
24
|
+
|
|
25
|
+
### Default
|
|
26
|
+
<Canvas of={Stories.Default} />
|
|
27
|
+
|
|
28
|
+
### Sticky header
|
|
29
|
+
<Canvas of={Stories.StickyHeader} />
|
|
30
|
+
|
|
31
|
+
## Props
|
|
32
|
+
|
|
33
|
+
<ArgTypes of={Stories} />
|
|
34
|
+
|
|
35
|
+
## Attributes
|
|
36
|
+
|
|
37
|
+
| Attribute | Type | Default | Description |
|
|
38
|
+
|-----------|------|---------|-------------|
|
|
39
|
+
| `sticky-header` | boolean | `false` | Freezes `<thead>` at the top when the table overflows vertically |
|
|
40
|
+
|
|
41
|
+
## Slots
|
|
42
|
+
|
|
43
|
+
| Slot | Description |
|
|
44
|
+
|------|-------------|
|
|
45
|
+
| `(default)` | A standard `<table>` element with `<thead>` and `<tbody>` |
|
|
46
|
+
|
|
47
|
+
## Usage in plain HTML
|
|
48
|
+
|
|
49
|
+
```html
|
|
50
|
+
<bds-table>
|
|
51
|
+
<table>
|
|
52
|
+
<thead>
|
|
53
|
+
<tr>
|
|
54
|
+
<th>Name</th>
|
|
55
|
+
<th>Role</th>
|
|
56
|
+
<th>Status</th>
|
|
57
|
+
</tr>
|
|
58
|
+
</thead>
|
|
59
|
+
<tbody>
|
|
60
|
+
<tr>
|
|
61
|
+
<td>Jane Doe</td>
|
|
62
|
+
<td>Designer</td>
|
|
63
|
+
<td>Active</td>
|
|
64
|
+
</tr>
|
|
65
|
+
</tbody>
|
|
66
|
+
</table>
|
|
67
|
+
</bds-table>
|
|
68
|
+
|
|
69
|
+
<!-- Sticky header in a scrollable container -->
|
|
70
|
+
<div style="max-height: 300px; overflow: auto;">
|
|
71
|
+
<bds-table sticky-header>
|
|
72
|
+
<table>...</table>
|
|
73
|
+
</bds-table>
|
|
74
|
+
</div>
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Accessibility
|
|
78
|
+
|
|
79
|
+
- Use a standard `<table>` with proper `<thead>` / `<tbody>` structure
|
|
80
|
+
- Column headers (`<th>`) are automatically styled; add `scope="col"` for complex tables
|
|
81
|
+
- The wrapper is horizontally scrollable (`overflow-inline: auto`) on small viewports
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
3
|
+
import '../index'; // auto-registers all custom elements
|
|
4
|
+
|
|
5
|
+
function BdsTable({
|
|
6
|
+
stickyHeader,
|
|
7
|
+
children,
|
|
8
|
+
}: {
|
|
9
|
+
stickyHeader?: boolean;
|
|
10
|
+
children?: React.ReactNode;
|
|
11
|
+
}) {
|
|
12
|
+
return React.createElement(
|
|
13
|
+
'bds-table',
|
|
14
|
+
{ 'sticky-header': stickyHeader || undefined },
|
|
15
|
+
children,
|
|
16
|
+
);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const sampleTable = () =>
|
|
20
|
+
React.createElement(
|
|
21
|
+
'table',
|
|
22
|
+
null,
|
|
23
|
+
React.createElement(
|
|
24
|
+
'thead',
|
|
25
|
+
null,
|
|
26
|
+
React.createElement(
|
|
27
|
+
'tr',
|
|
28
|
+
null,
|
|
29
|
+
React.createElement('th', null, 'Name'),
|
|
30
|
+
React.createElement('th', null, 'Role'),
|
|
31
|
+
React.createElement('th', null, 'Department'),
|
|
32
|
+
React.createElement('th', null, 'Status'),
|
|
33
|
+
),
|
|
34
|
+
),
|
|
35
|
+
React.createElement(
|
|
36
|
+
'tbody',
|
|
37
|
+
null,
|
|
38
|
+
...[
|
|
39
|
+
['Alice Brown', 'Designer', 'Product', 'Active'],
|
|
40
|
+
['Bob Smith', 'Engineer', 'Platform', 'Active'],
|
|
41
|
+
['Carol White', 'Manager', 'Operations', 'Away'],
|
|
42
|
+
['Dan Jones', 'Analyst', 'Data', 'Inactive'],
|
|
43
|
+
].map(([name, role, dept, status]) =>
|
|
44
|
+
React.createElement(
|
|
45
|
+
'tr',
|
|
46
|
+
{ key: name },
|
|
47
|
+
React.createElement('td', null, name),
|
|
48
|
+
React.createElement('td', null, role),
|
|
49
|
+
React.createElement('td', null, dept),
|
|
50
|
+
React.createElement('td', null, status),
|
|
51
|
+
),
|
|
52
|
+
),
|
|
53
|
+
),
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
const meta = {
|
|
57
|
+
title: 'Web Components/UI/Table',
|
|
58
|
+
component: BdsTable,
|
|
59
|
+
tags: ['!stable', 'experimental'],
|
|
60
|
+
parameters: { layout: 'fullscreen' },
|
|
61
|
+
argTypes: {
|
|
62
|
+
stickyHeader: { control: 'boolean' },
|
|
63
|
+
},
|
|
64
|
+
} satisfies Meta<typeof BdsTable>;
|
|
65
|
+
|
|
66
|
+
export default meta;
|
|
67
|
+
type Story = StoryObj<typeof meta>;
|
|
68
|
+
|
|
69
|
+
export const Default: Story = {
|
|
70
|
+
render: () => (
|
|
71
|
+
<div style={{ padding: 24 }}>
|
|
72
|
+
{React.createElement('bds-table', {}, sampleTable())}
|
|
73
|
+
</div>
|
|
74
|
+
),
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
export const StickyHeader: Story = {
|
|
78
|
+
render: () => (
|
|
79
|
+
<div style={{ padding: 24, maxHeight: 200, overflow: 'auto' }}>
|
|
80
|
+
{React.createElement('bds-table', { 'sticky-header': true }, sampleTable())}
|
|
81
|
+
</div>
|
|
82
|
+
),
|
|
83
|
+
};
|
|
@@ -5,7 +5,7 @@ import * as Stories from './BdsTypography.stories';
|
|
|
5
5
|
|
|
6
6
|
# <bds-typography>
|
|
7
7
|
|
|
8
|
-
Framework-agnostic Typography custom element. Renders slotted
|
|
8
|
+
Framework-agnostic Typography custom element. Renders slotted text inside the appropriate semantic HTML element (`h1`–`h3`, `p`) based on the `variant` attribute, with optional tag override via `component`.
|
|
9
9
|
|
|
10
10
|
> **Status: experimental** — API may change before stable release.
|
|
11
11
|
|
|
@@ -15,6 +15,11 @@ Framework-agnostic Typography custom element. Renders slotted content inside the
|
|
|
15
15
|
import '@boostdev/components/web-components';
|
|
16
16
|
```
|
|
17
17
|
|
|
18
|
+
## When to use
|
|
19
|
+
|
|
20
|
+
- To apply design-system typography styles in non-React environments
|
|
21
|
+
- When you need to override the rendered HTML tag while keeping the visual style
|
|
22
|
+
|
|
18
23
|
## Examples
|
|
19
24
|
|
|
20
25
|
### All variants
|
|
@@ -23,12 +28,21 @@ import '@boostdev/components/web-components';
|
|
|
23
28
|
### Heading 1
|
|
24
29
|
<Canvas of={Stories.H1} />
|
|
25
30
|
|
|
31
|
+
### Heading 2
|
|
32
|
+
<Canvas of={Stories.H2} />
|
|
33
|
+
|
|
34
|
+
### Heading 3
|
|
35
|
+
<Canvas of={Stories.H3} />
|
|
36
|
+
|
|
26
37
|
### Body
|
|
27
38
|
<Canvas of={Stories.Body} />
|
|
28
39
|
|
|
29
40
|
### Body small
|
|
30
41
|
<Canvas of={Stories.BodySmall} />
|
|
31
42
|
|
|
43
|
+
### Custom tag
|
|
44
|
+
<Canvas of={Stories.CustomTag} />
|
|
45
|
+
|
|
32
46
|
## Props
|
|
33
47
|
|
|
34
48
|
<ArgTypes of={Stories} />
|
|
@@ -37,7 +51,7 @@ import '@boostdev/components/web-components';
|
|
|
37
51
|
|
|
38
52
|
| Attribute | Type | Default | Description |
|
|
39
53
|
|-----------|------|---------|-------------|
|
|
40
|
-
| `variant` | `"h1" \| "h2" \| "h3" \| "body" \| "body_s"` | `"body"` |
|
|
54
|
+
| `variant` | `"h1" \| "h2" \| "h3" \| "body" \| "body_s"` | `"body"` | Visual style and default semantic tag |
|
|
41
55
|
| `component` | string | — | Override the rendered HTML tag (e.g. `"span"`, `"label"`) |
|
|
42
56
|
|
|
43
57
|
## Slots
|
|
@@ -46,38 +60,15 @@ import '@boostdev/components/web-components';
|
|
|
46
60
|
|------|-------------|
|
|
47
61
|
| `(default)` | Text content |
|
|
48
62
|
|
|
49
|
-
## Default tag mapping
|
|
50
|
-
|
|
51
|
-
| Variant | Rendered tag |
|
|
52
|
-
|---------|-------------|
|
|
53
|
-
| `h1` | `<h1>` |
|
|
54
|
-
| `h2` | `<h2>` |
|
|
55
|
-
| `h3` | `<h3>` |
|
|
56
|
-
| `body` | `<p>` |
|
|
57
|
-
| `body_s` | `<p>` |
|
|
58
|
-
|
|
59
|
-
## CSS Custom Properties
|
|
60
|
-
|
|
61
|
-
| Property | Description |
|
|
62
|
-
|----------|-------------|
|
|
63
|
-
| `--typography_color` | Text colour (defaults to `--bds-color_on-bg`) |
|
|
64
|
-
|
|
65
63
|
## Usage in plain HTML
|
|
66
64
|
|
|
67
65
|
```html
|
|
68
66
|
<bds-typography variant="h1">Page title</bds-typography>
|
|
69
|
-
|
|
70
|
-
<bds-typography variant="
|
|
71
|
-
A paragraph of body text.
|
|
72
|
-
</bds-typography>
|
|
73
|
-
|
|
74
|
-
<!-- Override tag while keeping style -->
|
|
75
|
-
<bds-typography variant="body_s" component="span">
|
|
76
|
-
Inline small text
|
|
77
|
-
</bds-typography>
|
|
67
|
+
<bds-typography variant="body">Regular paragraph text.</bds-typography>
|
|
68
|
+
<bds-typography variant="body_s" component="span">Small helper text</bds-typography>
|
|
78
69
|
```
|
|
79
70
|
|
|
80
71
|
## Accessibility
|
|
81
72
|
|
|
82
|
-
- Uses
|
|
83
|
-
-
|
|
73
|
+
- Uses semantic heading elements (`h1`–`h3`) or `<p>` by default
|
|
74
|
+
- Override with `component` only when the semantic meaning differs from the visual style
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import type { Meta, StoryObj } from '@storybook/react';
|
|
3
3
|
import type { TypographyVariant } from './bds-typography';
|
|
4
|
-
import '../index';
|
|
4
|
+
import '../index'; // auto-registers all custom elements
|
|
5
5
|
|
|
6
6
|
function BdsTypography({
|
|
7
|
-
variant,
|
|
7
|
+
variant = 'body',
|
|
8
8
|
component,
|
|
9
9
|
children,
|
|
10
10
|
}: {
|
|
@@ -19,33 +19,34 @@ const meta = {
|
|
|
19
19
|
title: 'Web Components/UI/Typography',
|
|
20
20
|
component: BdsTypography,
|
|
21
21
|
tags: ['!stable', 'experimental'],
|
|
22
|
-
parameters: { layout: '
|
|
22
|
+
parameters: { layout: 'centered' },
|
|
23
23
|
argTypes: {
|
|
24
24
|
variant: { control: 'select', options: ['h1', 'h2', 'h3', 'body', 'body_s'] },
|
|
25
|
+
component: { control: 'text' },
|
|
25
26
|
},
|
|
26
27
|
} satisfies Meta<typeof BdsTypography>;
|
|
27
28
|
|
|
28
29
|
export default meta;
|
|
29
30
|
type Story = StoryObj<typeof meta>;
|
|
30
31
|
|
|
31
|
-
export const
|
|
32
|
-
export const
|
|
33
|
-
export const
|
|
34
|
-
export const
|
|
35
|
-
export const
|
|
32
|
+
export const Default: Story = { args: { children: 'Body text', variant: 'body' } };
|
|
33
|
+
export const H1: Story = { args: { children: 'Heading 1', variant: 'h1' } };
|
|
34
|
+
export const H2: Story = { args: { children: 'Heading 2', variant: 'h2' } };
|
|
35
|
+
export const H3: Story = { args: { children: 'Heading 3', variant: 'h3' } };
|
|
36
|
+
export const Body: Story = { args: { children: 'Regular body text.', variant: 'body' } };
|
|
37
|
+
export const BodySmall: Story = { args: { children: 'Small body text.', variant: 'body_s' } };
|
|
38
|
+
export const CustomTag: Story = {
|
|
39
|
+
args: { children: 'Rendered as a <span>', variant: 'body_s', component: 'span' },
|
|
40
|
+
};
|
|
36
41
|
|
|
37
42
|
export const AllVariants: Story = {
|
|
38
43
|
render: () => (
|
|
39
|
-
<div style={{ display: 'flex', flexDirection: 'column', gap:
|
|
40
|
-
{(
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
{v === 'body' && 'Body text — comfortable reading size for paragraphs.'}
|
|
46
|
-
{v === 'body_s' && 'Small body — captions, labels, and secondary text.'}
|
|
47
|
-
</BdsTypography>
|
|
48
|
-
))}
|
|
44
|
+
<div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
|
|
45
|
+
{React.createElement('bds-typography', { variant: 'h1' }, 'Heading 1')}
|
|
46
|
+
{React.createElement('bds-typography', { variant: 'h2' }, 'Heading 2')}
|
|
47
|
+
{React.createElement('bds-typography', { variant: 'h3' }, 'Heading 3')}
|
|
48
|
+
{React.createElement('bds-typography', { variant: 'body' }, 'Body text — regular paragraph copy.')}
|
|
49
|
+
{React.createElement('bds-typography', { variant: 'body_s' }, 'Body small — captions and helper text.')}
|
|
49
50
|
</div>
|
|
50
51
|
),
|
|
51
52
|
};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { fixture, cleanup } from '../test/helpers';
|
|
2
|
+
import { BdsButtonGroup } from './bds-button-group';
|
|
3
|
+
|
|
4
|
+
describe('bds-button-group', () => {
|
|
5
|
+
it('is registered as a custom element', () => {
|
|
6
|
+
expect(customElements.get('bds-button-group')).toBe(BdsButtonGroup);
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
it('renders a group role element', async () => {
|
|
10
|
+
const el = await fixture('<bds-button-group>content</bds-button-group>');
|
|
11
|
+
expect(el.shadowRoot!.querySelector('[role="group"]')).not.toBeNull();
|
|
12
|
+
cleanup(el);
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
it('defaults to horizontal orientation', async () => {
|
|
16
|
+
const el = await fixture('<bds-button-group>content</bds-button-group>') as BdsButtonGroup;
|
|
17
|
+
expect(el.orientation).toBe('horizontal');
|
|
18
|
+
cleanup(el);
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it('reflects vertical orientation attribute', async () => {
|
|
22
|
+
const el = await fixture('<bds-button-group orientation="vertical">content</bds-button-group>') as BdsButtonGroup;
|
|
23
|
+
expect(el.orientation).toBe('vertical');
|
|
24
|
+
expect(el.getAttribute('orientation')).toBe('vertical');
|
|
25
|
+
cleanup(el);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it('renders a slot', async () => {
|
|
29
|
+
const el = await fixture('<bds-button-group><span>item</span></bds-button-group>');
|
|
30
|
+
expect(el.shadowRoot!.querySelector('slot')).not.toBeNull();
|
|
31
|
+
cleanup(el);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('sets aria-label on the group element', async () => {
|
|
35
|
+
const el = await fixture('<bds-button-group aria-label="View options">content</bds-button-group>');
|
|
36
|
+
const group = el.shadowRoot!.querySelector('[role="group"]')!;
|
|
37
|
+
expect(group.getAttribute('aria-label')).toBe('View options');
|
|
38
|
+
cleanup(el);
|
|
39
|
+
});
|
|
40
|
+
});
|