@boostdev/design-system-components 1.2.0 → 1.2.2

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.
Files changed (168) hide show
  1. package/AGENTS.md +46 -4
  2. package/README.md +15 -15
  3. package/dist/client.cjs +149 -124
  4. package/dist/client.css +503 -525
  5. package/dist/client.d.cts +71 -96
  6. package/dist/client.d.ts +71 -96
  7. package/dist/client.js +149 -124
  8. package/dist/index.cjs +149 -124
  9. package/dist/index.css +503 -525
  10. package/dist/index.d.cts +71 -96
  11. package/dist/index.d.ts +71 -96
  12. package/dist/index.js +149 -124
  13. package/dist/web-components/{chunk-6MH5UWUD.js → chunk-2FGATTGT.js} +5 -0
  14. package/dist/web-components/{chunk-5IPHEONG.js → chunk-6I2DBFQ7.js} +1 -0
  15. package/dist/web-components/{chunk-DI46Q2EA.js → chunk-OCODKRVZ.js} +57 -82
  16. package/dist/web-components/index.d.ts +571 -1
  17. package/dist/web-components/index.js +1501 -4
  18. package/dist/web-components/interaction/bds-collapsible.js +1 -1
  19. package/dist/web-components/interaction/bds-drawer.js +1 -1
  20. package/dist/web-components/interaction/form/bds-segmented-control.js +1 -1
  21. package/package.json +1 -1
  22. package/src/components/interaction/Command/Command.tsx +4 -3
  23. package/src/components/interaction/Dialog/Dialog.tsx +4 -5
  24. package/src/components/interaction/Drawer/Drawer.module.css +37 -62
  25. package/src/components/interaction/Drawer/Drawer.spec.tsx +3 -3
  26. package/src/components/interaction/Drawer/Drawer.tsx +25 -24
  27. package/src/components/interaction/DropdownMenu/DropdownMenu.tsx +4 -2
  28. package/src/components/interaction/Popover/Popover.tsx +4 -3
  29. package/src/components/interaction/Rating/Rating.tsx +4 -2
  30. package/src/components/interaction/form/CheckboxGroup/CheckboxGroup.tsx +4 -6
  31. package/src/components/interaction/form/Combobox/Combobox.tsx +4 -2
  32. package/src/components/interaction/form/FileInput/FileInput.tsx +4 -3
  33. package/src/components/interaction/form/NumberInput/NumberInput.tsx +4 -3
  34. package/src/components/interaction/form/RadioGroup/RadioGroup.tsx +4 -6
  35. package/src/components/interaction/form/SegmentedControl/SegmentedControl.mdx +8 -4
  36. package/src/components/interaction/form/SegmentedControl/SegmentedControl.module.css +13 -6
  37. package/src/components/interaction/form/SegmentedControl/SegmentedControl.tsx +4 -6
  38. package/src/components/interaction/form/atoms/InputContainer.tsx +2 -2
  39. package/src/components/layout/ButtonGroup/ButtonGroup.tsx +4 -6
  40. package/src/components/layout/Card/Card.tsx +4 -10
  41. package/src/components/layout/IconWrapper/IconWrapper.tsx +4 -5
  42. package/src/components/layout/SectionHeader/SectionHeader.tsx +5 -4
  43. package/src/components/ui/Accordion/Accordion.tsx +4 -3
  44. package/src/components/ui/Alert/Alert.tsx +4 -3
  45. package/src/components/ui/Avatar/Avatar.tsx +5 -3
  46. package/src/components/ui/Badge/Badge.tsx +4 -5
  47. package/src/components/ui/Breadcrumb/Breadcrumb.tsx +4 -3
  48. package/src/components/ui/Calendar/Calendar.tsx +4 -4
  49. package/src/components/ui/Carousel/Carousel.tsx +4 -4
  50. package/src/components/ui/DescriptionList/DescriptionList.tsx +4 -4
  51. package/src/components/ui/Loading/Loading.tsx +4 -3
  52. package/src/components/ui/NotificationBanner/NotificationBanner.tsx +4 -2
  53. package/src/components/ui/Pagination/Pagination.tsx +4 -2
  54. package/src/components/ui/Progress/Progress.tsx +4 -2
  55. package/src/components/ui/ProgressCircle/ProgressCircle.tsx +4 -1
  56. package/src/components/ui/Separator/Separator.tsx +5 -3
  57. package/src/components/ui/Skeleton/Skeleton.tsx +4 -3
  58. package/src/components/ui/SkipLink/SkipLink.tsx +4 -5
  59. package/src/components/ui/Tabs/Tabs.tsx +4 -4
  60. package/src/components/ui/Tooltip/Tooltip.tsx +4 -2
  61. package/src/components/ui/Typography/Typography.tsx +4 -5
  62. package/src/stories/DesignSystem/Grid.mdx +2 -0
  63. package/src/stories/Introduction.mdx +2 -1
  64. package/src/web-components/index.ts +12 -0
  65. package/src/web-components/interaction/BdsAccordion.mdx +80 -28
  66. package/src/web-components/interaction/BdsAccordion.stories.tsx +67 -58
  67. package/src/web-components/interaction/BdsCollapsible.mdx +93 -23
  68. package/src/web-components/interaction/BdsCollapsible.stories.tsx +29 -48
  69. package/src/web-components/interaction/BdsDialog.mdx +88 -27
  70. package/src/web-components/interaction/BdsDialog.stories.tsx +129 -47
  71. package/src/web-components/interaction/BdsDrawer.mdx +85 -27
  72. package/src/web-components/interaction/BdsDrawer.stories.tsx +161 -31
  73. package/src/web-components/interaction/BdsDropdownMenu.mdx +108 -0
  74. package/src/web-components/interaction/BdsDropdownMenu.stories.tsx +91 -0
  75. package/src/web-components/interaction/BdsSkipLink.mdx +72 -16
  76. package/src/web-components/interaction/BdsSkipLink.stories.tsx +47 -34
  77. package/src/web-components/interaction/BdsTabs.mdx +97 -27
  78. package/src/web-components/interaction/BdsTabs.stories.tsx +69 -55
  79. package/src/web-components/interaction/BdsTooltip.mdx +84 -18
  80. package/src/web-components/interaction/BdsTooltip.stories.tsx +49 -30
  81. package/src/web-components/interaction/bds-collapsible.ts +1 -0
  82. package/src/web-components/interaction/bds-drawer.ts +59 -82
  83. package/src/web-components/interaction/bds-dropdown-menu-item.ts +124 -0
  84. package/src/web-components/interaction/bds-dropdown-menu.spec.ts +102 -0
  85. package/src/web-components/interaction/bds-dropdown-menu.ts +200 -0
  86. package/src/web-components/interaction/form/BdsCheckbox.mdx +57 -20
  87. package/src/web-components/interaction/form/BdsCheckbox.stories.tsx +35 -36
  88. package/src/web-components/interaction/form/BdsCheckboxGroup.mdx +70 -0
  89. package/src/web-components/interaction/form/BdsCheckboxGroup.stories.tsx +81 -0
  90. package/src/web-components/interaction/form/BdsCombobox.mdx +52 -33
  91. package/src/web-components/interaction/form/BdsCombobox.stories.tsx +55 -53
  92. package/src/web-components/interaction/form/BdsFileInput.mdx +59 -24
  93. package/src/web-components/interaction/form/BdsFileInput.stories.tsx +38 -53
  94. package/src/web-components/interaction/form/BdsFormInput.mdx +98 -0
  95. package/src/web-components/interaction/form/BdsFormInput.stories.tsx +139 -0
  96. package/src/web-components/interaction/form/BdsNumberInput.mdx +51 -22
  97. package/src/web-components/interaction/form/BdsNumberInput.stories.tsx +24 -46
  98. package/src/web-components/interaction/form/BdsRadio.mdx +53 -22
  99. package/src/web-components/interaction/form/BdsRadio.stories.tsx +19 -51
  100. package/src/web-components/interaction/form/BdsRadioGroup.mdx +73 -0
  101. package/src/web-components/interaction/form/BdsRadioGroup.stories.tsx +88 -0
  102. package/src/web-components/interaction/form/BdsSegmentedControl.mdx +76 -23
  103. package/src/web-components/interaction/form/BdsSegmentedControl.stories.tsx +64 -54
  104. package/src/web-components/interaction/form/BdsSelect.mdx +59 -21
  105. package/src/web-components/interaction/form/BdsSelect.stories.tsx +47 -56
  106. package/src/web-components/interaction/form/BdsSlider.mdx +55 -27
  107. package/src/web-components/interaction/form/BdsSlider.stories.tsx +23 -44
  108. package/src/web-components/interaction/form/BdsSwitch.mdx +53 -20
  109. package/src/web-components/interaction/form/BdsSwitch.stories.tsx +22 -37
  110. package/src/web-components/interaction/form/BdsTextarea.mdx +54 -22
  111. package/src/web-components/interaction/form/BdsTextarea.stories.tsx +35 -44
  112. package/src/web-components/interaction/form/bds-checkbox-group.spec.ts +55 -0
  113. package/src/web-components/interaction/form/bds-checkbox-group.ts +117 -0
  114. package/src/web-components/interaction/form/bds-form-input.spec.ts +83 -0
  115. package/src/web-components/interaction/form/bds-form-input.ts +268 -0
  116. package/src/web-components/interaction/form/bds-radio-group.spec.ts +62 -0
  117. package/src/web-components/interaction/form/bds-radio-group.ts +142 -0
  118. package/src/web-components/interaction/form/bds-segmented-control.ts +5 -0
  119. package/src/web-components/ui/BdsAvatar.mdx +29 -20
  120. package/src/web-components/ui/BdsAvatar.stories.tsx +14 -28
  121. package/src/web-components/ui/BdsBreadcrumb.mdx +22 -19
  122. package/src/web-components/ui/BdsBreadcrumb.stories.tsx +11 -21
  123. package/src/web-components/ui/BdsButtonGroup.mdx +69 -0
  124. package/src/web-components/ui/BdsButtonGroup.stories.tsx +66 -0
  125. package/src/web-components/ui/BdsCalendar.mdx +93 -0
  126. package/src/web-components/ui/BdsCalendar.stories.tsx +63 -0
  127. package/src/web-components/ui/BdsCard.mdx +30 -25
  128. package/src/web-components/ui/BdsCard.stories.tsx +19 -42
  129. package/src/web-components/ui/BdsCarousel.mdx +83 -0
  130. package/src/web-components/ui/BdsCarousel.stories.tsx +96 -0
  131. package/src/web-components/ui/BdsDescriptionList.mdx +13 -16
  132. package/src/web-components/ui/BdsDescriptionList.stories.tsx +34 -49
  133. package/src/web-components/ui/BdsIconWrapper.mdx +20 -20
  134. package/src/web-components/ui/BdsIconWrapper.stories.tsx +46 -41
  135. package/src/web-components/ui/BdsLink.mdx +21 -17
  136. package/src/web-components/ui/BdsLink.stories.tsx +19 -20
  137. package/src/web-components/ui/BdsLoading.mdx +9 -13
  138. package/src/web-components/ui/BdsLoading.stories.tsx +8 -10
  139. package/src/web-components/ui/BdsNotificationBanner.mdx +32 -37
  140. package/src/web-components/ui/BdsNotificationBanner.stories.tsx +38 -47
  141. package/src/web-components/ui/BdsPagination.mdx +74 -0
  142. package/src/web-components/ui/BdsPagination.stories.tsx +36 -0
  143. package/src/web-components/ui/BdsProgress.mdx +24 -17
  144. package/src/web-components/ui/BdsProgress.stories.tsx +55 -29
  145. package/src/web-components/ui/BdsProgressCircle.mdx +24 -18
  146. package/src/web-components/ui/BdsProgressCircle.stories.tsx +17 -29
  147. package/src/web-components/ui/BdsRating.mdx +22 -22
  148. package/src/web-components/ui/BdsRating.stories.tsx +19 -13
  149. package/src/web-components/ui/BdsSectionHeader.mdx +31 -28
  150. package/src/web-components/ui/BdsSectionHeader.stories.tsx +21 -23
  151. package/src/web-components/ui/BdsSeparator.mdx +22 -8
  152. package/src/web-components/ui/BdsSeparator.stories.tsx +27 -19
  153. package/src/web-components/ui/BdsSkeleton.mdx +20 -26
  154. package/src/web-components/ui/BdsSkeleton.stories.tsx +23 -23
  155. package/src/web-components/ui/BdsTable.mdx +81 -0
  156. package/src/web-components/ui/BdsTable.stories.tsx +83 -0
  157. package/src/web-components/ui/BdsTypography.mdx +20 -29
  158. package/src/web-components/ui/BdsTypography.stories.tsx +19 -18
  159. package/src/web-components/ui/bds-button-group.spec.ts +40 -0
  160. package/src/web-components/ui/bds-button-group.ts +78 -0
  161. package/src/web-components/ui/bds-calendar.spec.ts +91 -0
  162. package/src/web-components/ui/bds-calendar.ts +427 -0
  163. package/src/web-components/ui/bds-carousel.spec.ts +64 -0
  164. package/src/web-components/ui/bds-carousel.ts +296 -0
  165. package/src/web-components/ui/bds-pagination.spec.ts +67 -0
  166. package/src/web-components/ui/bds-pagination.ts +197 -0
  167. package/src/web-components/ui/bds-table.spec.ts +45 -0
  168. 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({ orientation }: { orientation?: 'horizontal' | 'vertical' }) {
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: 'select', options: ['horizontal', 'vertical'] },
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 Horizontal: Story = { args: { orientation: 'horizontal' } };
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 Vertical: Story = {
37
+ export const Horizontal: Story = {
25
38
  render: () => (
26
- <div style={{ display: 'flex', alignItems: 'center', gap: '16px', height: '40px' }}>
27
- <span>Left</span>
28
- <BdsSeparator orientation="vertical" />
29
- <span>Right</span>
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 AllVariants: Story = {
47
+ export const Vertical: Story = {
35
48
  render: () => (
36
- <div style={{ display: 'flex', flexDirection: 'column', gap: '16px', width: '300px' }}>
37
- <p style={{ margin: 0 }}>Content above horizontal separator</p>
38
- <BdsSeparator orientation="horizontal" />
39
- <p style={{ margin: 0 }}>Content below</p>
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
  # &lt;bds-skeleton&gt;
7
7
 
8
- Framework-agnostic Skeleton loading placeholder. Shows a shimmer animation while content is loading. Size is set via inline `style` or container CSS the element inherits its dimensions from the surrounding layout.
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
- ### Card layout skeleton
21
- <Canvas of={Stories.AllVariants} />
25
+ ### Default
26
+ <Canvas of={Stories.Default} />
22
27
 
23
- ### Text line
24
- <Canvas of={Stories.TextLine} />
28
+ ### Heading placeholder
29
+ <Canvas of={Stories.Heading} />
25
30
 
26
31
  ### Avatar placeholder
27
32
  <Canvas of={Stories.Avatar} />
28
33
 
29
- ### Card placeholder
30
- <Canvas of={Stories.Card} />
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
- This element has no attributes. Control dimensions via `style` or a CSS class on the host.
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
- <!-- Text line -->
48
+ <!-- Inline text placeholder -->
54
49
  <bds-skeleton style="width: 200px; height: 1rem;"></bds-skeleton>
55
50
 
56
- <!-- Avatar -->
57
- <bds-skeleton style="width: 3rem; height: 3rem; border-radius: 50%;"></bds-skeleton>
51
+ <!-- Heading placeholder -->
52
+ <bds-skeleton style="width: 300px; height: 2rem;"></bds-skeleton>
58
53
 
59
- <!-- Card block -->
60
- <bds-skeleton style="width: 280px; height: 160px;"></bds-skeleton>
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
- - Hidden from assistive technology via `aria-hidden="true"` it is a purely visual placeholder
66
- - Pair with a live region or announce loading state through other means if necessary
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
- function BdsSkeleton({ style }: { style?: React.CSSProperties }) {
6
- return React.createElement('bds-skeleton', { style });
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 TextLine: Story = {
20
- render: () => <BdsSkeleton style={{ width: '200px', height: '1rem' }} />,
24
+ export const Default: Story = {
25
+ args: { width: '200px', height: '1rem' },
21
26
  };
22
27
 
23
28
  export const Heading: Story = {
24
- render: () => <BdsSkeleton style={{ width: '300px', height: '1.75rem' }} />,
29
+ args: { width: '300px', height: '2rem' },
25
30
  };
26
31
 
27
32
  export const Avatar: Story = {
28
- render: () => <BdsSkeleton style={{ width: '3rem', height: '3rem', borderRadius: '50%' }} />,
29
- };
30
-
31
- export const Card: Story = {
32
- render: () => <BdsSkeleton style={{ width: '280px', height: '160px' }} />,
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 AllVariants: Story = {
41
+ export const ContentBlock: Story = {
36
42
  render: () => (
37
- <div style={{ display: 'flex', flexDirection: 'column', gap: '12px', width: '280px' }}>
38
- <div style={{ display: 'flex', alignItems: 'center', gap: '12px' }}>
39
- <BdsSkeleton style={{ width: '3rem', height: '3rem', borderRadius: '50%', flexShrink: 0 }} />
40
- <div style={{ display: 'flex', flexDirection: 'column', gap: '8px', flex: 1 }}>
41
- <BdsSkeleton style={{ width: '100%', height: '1rem' }} />
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
+ # &lt;bds-table&gt;
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
  # &lt;bds-typography&gt;
7
7
 
8
- Framework-agnostic Typography custom element. Renders slotted content inside the appropriate semantic HTML element with the correct typographic styles.
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"` | Typographic style and semantic element |
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="body">
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 the correct semantic HTML element by default — always prefer semantic variants over overriding `component`
83
- - Use `component` only when the semantic element must differ from the visual style (e.g. a `<span>` styled as `body_s` inside a heading)
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: 'padded' },
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 H1: Story = { args: { variant: 'h1', children: 'Heading level 1' } };
32
- export const H2: Story = { args: { variant: 'h2', children: 'Heading level 2' } };
33
- export const H3: Story = { args: { variant: 'h3', children: 'Heading level 3' } };
34
- export const Body: Story = { args: { variant: 'body', children: 'Body text — the default paragraph style for reading comfort.' } };
35
- export const BodySmall: Story = { args: { variant: 'body_s', children: 'Small body text useful for captions and helper text.' } };
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: '16px' }}>
40
- {(['h1', 'h2', 'h3', 'body', 'body_s'] as const).map(v => (
41
- <BdsTypography key={v} variant={v}>
42
- {v === 'h1' && 'Heading level 1'}
43
- {v === 'h2' && 'Heading level 2'}
44
- {v === 'h3' && 'Heading level 3'}
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
+ });