@boostdev/design-system-components 1.1.2 → 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.
Files changed (213) hide show
  1. package/AGENTS.md +38 -14
  2. package/dist/client.cjs +85 -103
  3. package/dist/client.css +610 -601
  4. package/dist/client.d.cts +13 -16
  5. package/dist/client.d.ts +13 -16
  6. package/dist/client.js +95 -113
  7. package/dist/index.cjs +85 -103
  8. package/dist/index.css +610 -601
  9. package/dist/index.d.cts +13 -16
  10. package/dist/index.d.ts +13 -16
  11. package/dist/index.js +95 -113
  12. package/dist/native/index.cjs +9 -8
  13. package/dist/native/index.d.cts +1 -1
  14. package/dist/native/index.d.ts +1 -1
  15. package/dist/native/index.js +9 -8
  16. package/dist/web-components/{chunk-K5CE6HSB.js → chunk-2FGATTGT.js} +79 -17
  17. package/dist/web-components/{chunk-O4UFI2RX.js → chunk-3REOIRDW.js} +13 -11
  18. package/dist/web-components/{chunk-5IPHEONG.js → chunk-6I2DBFQ7.js} +1 -0
  19. package/dist/web-components/{chunk-VM3YHGQ2.js → chunk-AJSXNDAP.js} +1 -2
  20. package/dist/web-components/{chunk-LSC4N56Q.js → chunk-BX3IPVOB.js} +1 -2
  21. package/dist/web-components/{chunk-CAPI25CU.js → chunk-DZRSJGPB.js} +3 -3
  22. package/dist/web-components/{chunk-VSS5ITNE.js → chunk-EBJM3VD4.js} +1 -3
  23. package/dist/web-components/{chunk-O7I63SQX.js → chunk-HHHRF2PS.js} +6 -12
  24. package/dist/web-components/{chunk-OTX4COSV.js → chunk-JUKB3BUP.js} +3 -4
  25. package/dist/web-components/{chunk-IQGLIQSO.js → chunk-N6IMUOY4.js} +2 -5
  26. package/dist/web-components/{chunk-CJ5ZOO42.js → chunk-OCODKRVZ.js} +68 -44
  27. package/dist/web-components/{chunk-QDRH46TF.js → chunk-QLZ2362S.js} +1 -3
  28. package/dist/web-components/{chunk-IK3PTFZ4.js → chunk-T6AETZRP.js} +1 -3
  29. package/dist/web-components/{chunk-4BX6AWXX.js → chunk-X3FKVHLK.js} +2 -4
  30. package/dist/web-components/{chunk-A67LCT7C.js → chunk-XNA6WTXG.js} +3 -4
  31. package/dist/web-components/{chunk-XIENXR7H.js → chunk-YRXCVKHV.js} +1 -3
  32. package/dist/web-components/{chunk-6T3RKUKG.js → chunk-ZTC6GRP7.js} +1 -2
  33. package/dist/web-components/globals.js +1 -1
  34. package/dist/web-components/index.d.ts +571 -1
  35. package/dist/web-components/index.js +1515 -18
  36. package/dist/web-components/interaction/bds-accordion.js +1 -1
  37. package/dist/web-components/interaction/bds-button.d.ts +2 -2
  38. package/dist/web-components/interaction/bds-button.js +1 -1
  39. package/dist/web-components/interaction/bds-collapsible.js +1 -1
  40. package/dist/web-components/interaction/bds-dialog.js +1 -1
  41. package/dist/web-components/interaction/bds-drawer.js +1 -1
  42. package/dist/web-components/interaction/form/bds-checkbox.js +1 -1
  43. package/dist/web-components/interaction/form/bds-combobox.js +1 -1
  44. package/dist/web-components/interaction/form/bds-number-input.js +1 -1
  45. package/dist/web-components/interaction/form/bds-radio.js +1 -1
  46. package/dist/web-components/interaction/form/bds-segmented-control.d.ts +20 -3
  47. package/dist/web-components/interaction/form/bds-segmented-control.js +1 -1
  48. package/dist/web-components/interaction/form/bds-select.js +1 -1
  49. package/dist/web-components/interaction/form/bds-switch.js +1 -1
  50. package/dist/web-components/interaction/form/bds-textarea.js +1 -1
  51. package/dist/web-components/ui/bds-alert.js +1 -1
  52. package/dist/web-components/ui/bds-card.js +1 -1
  53. package/dist/web-components/ui/bds-notification-banner.js +1 -1
  54. package/package.json +2 -2
  55. package/src/components/interaction/Button/Button.module.css +12 -11
  56. package/src/components/interaction/Button/Button.native.tsx +10 -9
  57. package/src/components/interaction/Button/Button.tsx +1 -1
  58. package/src/components/interaction/Command/Command.module.css +3 -7
  59. package/src/components/interaction/Dialog/Dialog.module.css +7 -5
  60. package/src/components/interaction/Drawer/Drawer.module.css +48 -25
  61. package/src/components/interaction/Drawer/Drawer.tsx +21 -17
  62. package/src/components/interaction/DropdownMenu/DropdownMenu.module.css +1 -3
  63. package/src/components/interaction/Popover/Popover.module.css +1 -3
  64. package/src/components/interaction/form/Checkbox/Checkbox.module.css +1 -3
  65. package/src/components/interaction/form/Combobox/Combobox.module.css +2 -6
  66. package/src/components/interaction/form/FormInput/FormInput.module.css +1 -3
  67. package/src/components/interaction/form/NumberInput/NumberInput.module.css +16 -4
  68. package/src/components/interaction/form/Radio/Radio.module.css +6 -16
  69. package/src/components/interaction/form/SegmentedControl/SegmentedControl.mdx +74 -25
  70. package/src/components/interaction/form/SegmentedControl/SegmentedControl.module.css +65 -36
  71. package/src/components/interaction/form/SegmentedControl/SegmentedControl.spec.tsx +127 -56
  72. package/src/components/interaction/form/SegmentedControl/SegmentedControl.stories.tsx +89 -72
  73. package/src/components/interaction/form/SegmentedControl/SegmentedControl.tsx +40 -62
  74. package/src/components/interaction/form/SegmentedControl/index.ts +1 -1
  75. package/src/components/interaction/form/Select/Select.module.css +2 -4
  76. package/src/components/interaction/form/Switch/Switch.module.css +5 -7
  77. package/src/components/interaction/form/Switch/Switch.native.spec.tsx +9 -9
  78. package/src/components/interaction/form/Switch/Switch.native.tsx +2 -2
  79. package/src/components/interaction/form/Textarea/Textarea.module.css +1 -3
  80. package/src/components/interaction/form/atoms/InputContainer.stories.tsx +64 -0
  81. package/src/components/interaction/form/atoms/Label.stories.tsx +33 -0
  82. package/src/components/interaction/form/atoms/Message.stories.tsx +33 -0
  83. package/src/components/layout/Card/Card.module.css +1 -3
  84. package/src/components/ui/Accordion/Accordion.module.css +1 -2
  85. package/src/components/ui/Alert/Alert.module.css +1 -2
  86. package/src/components/ui/Calendar/Calendar.module.css +2 -5
  87. package/src/components/ui/Carousel/Carousel.module.css +1 -3
  88. package/src/components/ui/NotificationBanner/NotificationBanner.module.css +1 -2
  89. package/src/components/ui/Pagination/Pagination.module.css +1 -2
  90. package/src/components/ui/SkipLink/SkipLink.module.css +1 -2
  91. package/src/components/ui/Table/Table.module.css +1 -2
  92. package/src/css/bdc.css +16 -11
  93. package/src/index.ts +1 -1
  94. package/src/stories/Introduction.mdx +2 -1
  95. package/src/web-components/globals.ts +3 -3
  96. package/src/web-components/index.ts +12 -0
  97. package/src/web-components/interaction/BdsAccordion.mdx +103 -0
  98. package/src/web-components/interaction/BdsAccordion.stories.tsx +94 -0
  99. package/src/web-components/interaction/BdsCollapsible.mdx +116 -0
  100. package/src/web-components/interaction/BdsCollapsible.stories.tsx +68 -0
  101. package/src/web-components/interaction/BdsDialog.mdx +110 -0
  102. package/src/web-components/interaction/BdsDialog.stories.tsx +157 -0
  103. package/src/web-components/interaction/BdsDrawer.mdx +108 -0
  104. package/src/web-components/interaction/BdsDrawer.stories.tsx +196 -0
  105. package/src/web-components/interaction/BdsDropdownMenu.mdx +108 -0
  106. package/src/web-components/interaction/BdsDropdownMenu.stories.tsx +91 -0
  107. package/src/web-components/interaction/BdsSkipLink.mdx +90 -0
  108. package/src/web-components/interaction/BdsSkipLink.stories.tsx +68 -0
  109. package/src/web-components/interaction/BdsTabs.mdx +117 -0
  110. package/src/web-components/interaction/BdsTabs.stories.tsx +94 -0
  111. package/src/web-components/interaction/BdsTooltip.mdx +104 -0
  112. package/src/web-components/interaction/BdsTooltip.stories.tsx +87 -0
  113. package/src/web-components/interaction/bds-accordion.ts +1 -2
  114. package/src/web-components/interaction/bds-button.ts +15 -13
  115. package/src/web-components/interaction/bds-collapsible.ts +1 -0
  116. package/src/web-components/interaction/bds-dialog.ts +2 -5
  117. package/src/web-components/interaction/bds-drawer.ts +70 -44
  118. package/src/web-components/interaction/bds-dropdown-menu-item.ts +124 -0
  119. package/src/web-components/interaction/bds-dropdown-menu.spec.ts +102 -0
  120. package/src/web-components/interaction/bds-dropdown-menu.ts +200 -0
  121. package/src/web-components/interaction/form/BdsCheckbox.mdx +76 -0
  122. package/src/web-components/interaction/form/BdsCheckbox.stories.tsx +72 -0
  123. package/src/web-components/interaction/form/BdsCheckboxGroup.mdx +70 -0
  124. package/src/web-components/interaction/form/BdsCheckboxGroup.stories.tsx +81 -0
  125. package/src/web-components/interaction/form/BdsCombobox.mdx +71 -0
  126. package/src/web-components/interaction/form/BdsCombobox.stories.tsx +93 -0
  127. package/src/web-components/interaction/form/BdsFileInput.mdx +79 -0
  128. package/src/web-components/interaction/form/BdsFileInput.stories.tsx +69 -0
  129. package/src/web-components/interaction/form/BdsFormInput.mdx +98 -0
  130. package/src/web-components/interaction/form/BdsFormInput.stories.tsx +139 -0
  131. package/src/web-components/interaction/form/BdsNumberInput.mdx +70 -0
  132. package/src/web-components/interaction/form/BdsNumberInput.stories.tsx +68 -0
  133. package/src/web-components/interaction/form/BdsRadio.mdx +72 -0
  134. package/src/web-components/interaction/form/BdsRadio.stories.tsx +58 -0
  135. package/src/web-components/interaction/form/BdsRadioGroup.mdx +73 -0
  136. package/src/web-components/interaction/form/BdsRadioGroup.stories.tsx +88 -0
  137. package/src/web-components/interaction/form/BdsSegmentedControl.mdx +95 -0
  138. package/src/web-components/interaction/form/BdsSegmentedControl.stories.tsx +102 -0
  139. package/src/web-components/interaction/form/BdsSelect.mdx +76 -0
  140. package/src/web-components/interaction/form/BdsSelect.stories.tsx +84 -0
  141. package/src/web-components/interaction/form/BdsSlider.mdx +77 -0
  142. package/src/web-components/interaction/form/BdsSlider.stories.tsx +68 -0
  143. package/src/web-components/interaction/form/BdsSwitch.mdx +72 -0
  144. package/src/web-components/interaction/form/BdsSwitch.stories.tsx +58 -0
  145. package/src/web-components/interaction/form/BdsTextarea.mdx +73 -0
  146. package/src/web-components/interaction/form/BdsTextarea.stories.tsx +70 -0
  147. package/src/web-components/interaction/form/bds-checkbox-group.spec.ts +55 -0
  148. package/src/web-components/interaction/form/bds-checkbox-group.ts +117 -0
  149. package/src/web-components/interaction/form/bds-checkbox.ts +1 -3
  150. package/src/web-components/interaction/form/bds-combobox.ts +1 -3
  151. package/src/web-components/interaction/form/bds-form-input.spec.ts +83 -0
  152. package/src/web-components/interaction/form/bds-form-input.ts +268 -0
  153. package/src/web-components/interaction/form/bds-number-input.ts +3 -4
  154. package/src/web-components/interaction/form/bds-radio-group.spec.ts +62 -0
  155. package/src/web-components/interaction/form/bds-radio-group.ts +142 -0
  156. package/src/web-components/interaction/form/bds-radio.ts +6 -12
  157. package/src/web-components/interaction/form/bds-segmented-control.ts +96 -20
  158. package/src/web-components/interaction/form/bds-select.ts +2 -4
  159. package/src/web-components/interaction/form/bds-switch.ts +3 -4
  160. package/src/web-components/interaction/form/bds-textarea.ts +1 -3
  161. package/src/web-components/ui/BdsAvatar.mdx +76 -0
  162. package/src/web-components/ui/BdsAvatar.stories.tsx +48 -0
  163. package/src/web-components/ui/BdsBreadcrumb.mdx +66 -0
  164. package/src/web-components/ui/BdsBreadcrumb.stories.tsx +49 -0
  165. package/src/web-components/ui/BdsButtonGroup.mdx +69 -0
  166. package/src/web-components/ui/BdsButtonGroup.stories.tsx +66 -0
  167. package/src/web-components/ui/BdsCalendar.mdx +93 -0
  168. package/src/web-components/ui/BdsCalendar.stories.tsx +63 -0
  169. package/src/web-components/ui/BdsCard.mdx +88 -0
  170. package/src/web-components/ui/BdsCard.stories.tsx +67 -0
  171. package/src/web-components/ui/BdsCarousel.mdx +83 -0
  172. package/src/web-components/ui/BdsCarousel.stories.tsx +96 -0
  173. package/src/web-components/ui/BdsDescriptionList.mdx +64 -0
  174. package/src/web-components/ui/BdsDescriptionList.stories.tsx +64 -0
  175. package/src/web-components/ui/BdsIconWrapper.mdx +70 -0
  176. package/src/web-components/ui/BdsIconWrapper.stories.tsx +81 -0
  177. package/src/web-components/ui/BdsLink.mdx +79 -0
  178. package/src/web-components/ui/BdsLink.stories.tsx +63 -0
  179. package/src/web-components/ui/BdsLoading.mdx +58 -0
  180. package/src/web-components/ui/BdsLoading.stories.tsx +35 -0
  181. package/src/web-components/ui/BdsNotificationBanner.mdx +85 -0
  182. package/src/web-components/ui/BdsNotificationBanner.stories.tsx +84 -0
  183. package/src/web-components/ui/BdsPagination.mdx +74 -0
  184. package/src/web-components/ui/BdsPagination.stories.tsx +36 -0
  185. package/src/web-components/ui/BdsProgress.mdx +70 -0
  186. package/src/web-components/ui/BdsProgress.stories.tsx +96 -0
  187. package/src/web-components/ui/BdsProgressCircle.mdx +70 -0
  188. package/src/web-components/ui/BdsProgressCircle.stories.tsx +57 -0
  189. package/src/web-components/ui/BdsRating.mdx +61 -0
  190. package/src/web-components/ui/BdsRating.stories.tsx +45 -0
  191. package/src/web-components/ui/BdsSectionHeader.mdx +72 -0
  192. package/src/web-components/ui/BdsSectionHeader.stories.tsx +54 -0
  193. package/src/web-components/ui/BdsSeparator.mdx +77 -0
  194. package/src/web-components/ui/BdsSeparator.stories.tsx +55 -0
  195. package/src/web-components/ui/BdsSkeleton.mdx +61 -0
  196. package/src/web-components/ui/BdsSkeleton.stories.tsx +50 -0
  197. package/src/web-components/ui/BdsTable.mdx +81 -0
  198. package/src/web-components/ui/BdsTable.stories.tsx +83 -0
  199. package/src/web-components/ui/BdsTypography.mdx +74 -0
  200. package/src/web-components/ui/BdsTypography.stories.tsx +52 -0
  201. package/src/web-components/ui/bds-alert.ts +1 -2
  202. package/src/web-components/ui/bds-button-group.spec.ts +40 -0
  203. package/src/web-components/ui/bds-button-group.ts +78 -0
  204. package/src/web-components/ui/bds-calendar.spec.ts +91 -0
  205. package/src/web-components/ui/bds-calendar.ts +427 -0
  206. package/src/web-components/ui/bds-card.ts +1 -3
  207. package/src/web-components/ui/bds-carousel.spec.ts +64 -0
  208. package/src/web-components/ui/bds-carousel.ts +296 -0
  209. package/src/web-components/ui/bds-notification-banner.ts +1 -2
  210. package/src/web-components/ui/bds-pagination.spec.ts +67 -0
  211. package/src/web-components/ui/bds-pagination.ts +197 -0
  212. package/src/web-components/ui/bds-table.spec.ts +45 -0
  213. package/src/web-components/ui/bds-table.ts +96 -0
@@ -0,0 +1,77 @@
1
+ import { Meta, Canvas, ArgTypes } from '@storybook/blocks';
2
+ import * as Stories from './BdsSeparator.stories';
3
+
4
+ <Meta of={Stories} />
5
+
6
+ # &lt;bds-separator&gt;
7
+
8
+ Framework-agnostic Separator custom element. Renders a thin decorative line to visually divide content. Supports both horizontal and vertical orientations.
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
+ ## When to use
28
+
29
+ - To visually separate groups of related content (e.g. sections in a form or list)
30
+ - As a vertical divider between inline elements such as navigation links
31
+
32
+ ## Examples
33
+
34
+ ### Default (horizontal)
35
+ <Canvas of={Stories.Default} />
36
+
37
+ ### Horizontal
38
+ <Canvas of={Stories.Horizontal} />
39
+
40
+ ### Vertical
41
+ <Canvas of={Stories.Vertical} />
42
+
43
+ ## Props
44
+
45
+ <ArgTypes of={Stories} />
46
+
47
+ ## Attributes
48
+
49
+ | Attribute | Type | Default | Description |
50
+ |-----------|------|---------|-------------|
51
+ | `orientation` | `"horizontal" \| "vertical"` | `"horizontal"` | Direction of the separator line |
52
+
53
+ ## CSS Custom Properties
54
+
55
+ | Property | Description |
56
+ |----------|-------------|
57
+ | `--separator_color` | Line colour (defaults to `--bds-color_on-bg`) |
58
+ | `--separator_thickness` | Line thickness (default: `1px`) |
59
+
60
+ ## Usage in plain HTML
61
+
62
+ ```html
63
+ <p>Above</p>
64
+ <bds-separator></bds-separator>
65
+ <p>Below</p>
66
+
67
+ <!-- Vertical -->
68
+ <div style="display: flex; align-items: center; gap: 8px; height: 40px;">
69
+ <span>Left</span>
70
+ <bds-separator orientation="vertical"></bds-separator>
71
+ <span>Right</span>
72
+ </div>
73
+ ```
74
+
75
+ ## Accessibility
76
+
77
+ - Renders a `<div role="separator">` with `aria-orientation` set automatically
@@ -0,0 +1,55 @@
1
+ import React from 'react';
2
+ import type { Meta, StoryObj } from '@storybook/react';
3
+ import '../index'; // auto-registers all custom elements
4
+
5
+ function BdsSeparator({
6
+ orientation = 'horizontal',
7
+ }: {
8
+ orientation?: 'horizontal' | 'vertical';
9
+ }) {
10
+ return React.createElement('bds-separator', { orientation });
11
+ }
12
+
13
+ const meta = {
14
+ title: 'Web Components/UI/Separator',
15
+ component: BdsSeparator,
16
+ tags: ['!stable', 'experimental'],
17
+ parameters: { layout: 'centered' },
18
+ argTypes: {
19
+ orientation: { control: 'radio', options: ['horizontal', 'vertical'] },
20
+ },
21
+ } satisfies Meta<typeof BdsSeparator>;
22
+
23
+ export default meta;
24
+ type Story = StoryObj<typeof meta>;
25
+
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
+ };
36
+
37
+ export const Horizontal: Story = {
38
+ render: () => (
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>
43
+ </div>
44
+ ),
45
+ };
46
+
47
+ export const Vertical: Story = {
48
+ render: () => (
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>
53
+ </div>
54
+ ),
55
+ };
@@ -0,0 +1,61 @@
1
+ import { Meta, Canvas, ArgTypes } from '@storybook/blocks';
2
+ import * as Stories from './BdsSkeleton.stories';
3
+
4
+ <Meta of={Stories} />
5
+
6
+ # &lt;bds-skeleton&gt;
7
+
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
+
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
+ - 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
+
23
+ ## Examples
24
+
25
+ ### Default
26
+ <Canvas of={Stories.Default} />
27
+
28
+ ### Heading placeholder
29
+ <Canvas of={Stories.Heading} />
30
+
31
+ ### Avatar placeholder
32
+ <Canvas of={Stories.Avatar} />
33
+
34
+ ### Content block
35
+ <Canvas of={Stories.ContentBlock} />
36
+
37
+ ## Props
38
+
39
+ <ArgTypes of={Stories} />
40
+
41
+ ## Attributes
42
+
43
+ `<bds-skeleton>` has no custom attributes. Size is controlled via inline styles or CSS.
44
+
45
+ ## Usage in plain HTML
46
+
47
+ ```html
48
+ <!-- Inline text placeholder -->
49
+ <bds-skeleton style="width: 200px; height: 1rem;"></bds-skeleton>
50
+
51
+ <!-- Heading placeholder -->
52
+ <bds-skeleton style="width: 300px; height: 2rem;"></bds-skeleton>
53
+
54
+ <!-- Avatar placeholder -->
55
+ <bds-skeleton style="width: 48px; height: 48px; border-radius: 50%;"></bds-skeleton>
56
+ ```
57
+
58
+ ## Accessibility
59
+
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
@@ -0,0 +1,50 @@
1
+ import React from 'react';
2
+ import type { Meta, StoryObj } from '@storybook/react';
3
+ import '../index'; // auto-registers all custom elements
4
+
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};` });
8
+ }
9
+
10
+ const meta = {
11
+ title: 'Web Components/UI/Skeleton',
12
+ component: BdsSkeleton,
13
+ tags: ['!stable', 'experimental'],
14
+ parameters: { layout: 'centered' },
15
+ argTypes: {
16
+ width: { control: 'text' },
17
+ height: { control: 'text' },
18
+ },
19
+ } satisfies Meta<typeof BdsSkeleton>;
20
+
21
+ export default meta;
22
+ type Story = StoryObj<typeof meta>;
23
+
24
+ export const Default: Story = {
25
+ args: { width: '200px', height: '1rem' },
26
+ };
27
+
28
+ export const Heading: Story = {
29
+ args: { width: '300px', height: '2rem' },
30
+ };
31
+
32
+ export const Avatar: Story = {
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
+ ),
39
+ };
40
+
41
+ export const ContentBlock: Story = {
42
+ render: () => (
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
+ </div>
49
+ ),
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
+ };
@@ -0,0 +1,74 @@
1
+ import { Meta, Canvas, ArgTypes } from '@storybook/blocks';
2
+ import * as Stories from './BdsTypography.stories';
3
+
4
+ <Meta of={Stories} />
5
+
6
+ # &lt;bds-typography&gt;
7
+
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
+
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
+ - 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
+
23
+ ## Examples
24
+
25
+ ### All variants
26
+ <Canvas of={Stories.AllVariants} />
27
+
28
+ ### Heading 1
29
+ <Canvas of={Stories.H1} />
30
+
31
+ ### Heading 2
32
+ <Canvas of={Stories.H2} />
33
+
34
+ ### Heading 3
35
+ <Canvas of={Stories.H3} />
36
+
37
+ ### Body
38
+ <Canvas of={Stories.Body} />
39
+
40
+ ### Body small
41
+ <Canvas of={Stories.BodySmall} />
42
+
43
+ ### Custom tag
44
+ <Canvas of={Stories.CustomTag} />
45
+
46
+ ## Props
47
+
48
+ <ArgTypes of={Stories} />
49
+
50
+ ## Attributes
51
+
52
+ | Attribute | Type | Default | Description |
53
+ |-----------|------|---------|-------------|
54
+ | `variant` | `"h1" \| "h2" \| "h3" \| "body" \| "body_s"` | `"body"` | Visual style and default semantic tag |
55
+ | `component` | string | — | Override the rendered HTML tag (e.g. `"span"`, `"label"`) |
56
+
57
+ ## Slots
58
+
59
+ | Slot | Description |
60
+ |------|-------------|
61
+ | `(default)` | Text content |
62
+
63
+ ## Usage in plain HTML
64
+
65
+ ```html
66
+ <bds-typography variant="h1">Page title</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>
69
+ ```
70
+
71
+ ## Accessibility
72
+
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
@@ -0,0 +1,52 @@
1
+ import React from 'react';
2
+ import type { Meta, StoryObj } from '@storybook/react';
3
+ import type { TypographyVariant } from './bds-typography';
4
+ import '../index'; // auto-registers all custom elements
5
+
6
+ function BdsTypography({
7
+ variant = 'body',
8
+ component,
9
+ children,
10
+ }: {
11
+ variant?: TypographyVariant;
12
+ component?: string;
13
+ children?: React.ReactNode;
14
+ }) {
15
+ return React.createElement('bds-typography', { variant, component }, children);
16
+ }
17
+
18
+ const meta = {
19
+ title: 'Web Components/UI/Typography',
20
+ component: BdsTypography,
21
+ tags: ['!stable', 'experimental'],
22
+ parameters: { layout: 'centered' },
23
+ argTypes: {
24
+ variant: { control: 'select', options: ['h1', 'h2', 'h3', 'body', 'body_s'] },
25
+ component: { control: 'text' },
26
+ },
27
+ } satisfies Meta<typeof BdsTypography>;
28
+
29
+ export default meta;
30
+ type Story = StoryObj<typeof meta>;
31
+
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
+ };
41
+
42
+ export const AllVariants: Story = {
43
+ render: () => (
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.')}
50
+ </div>
51
+ ),
52
+ };
@@ -110,8 +110,7 @@ export class BdsAlert extends LitElement {
110
110
  transition: var(--bds-animation_transition);
111
111
  border-radius: 50%;
112
112
  --bdc_color: currentcolor;
113
- outline: var(--bdc-outline_width) solid var(--bdc_color);
114
- outline-offset: var(--bdc-outline_offset);
113
+ box-shadow: inset 0 0 0 var(--bdc-outline_width) var(--bdc_color);
115
114
  }
116
115
 
117
116
  .dismiss svg {
@@ -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
+ });
@@ -0,0 +1,78 @@
1
+ import { LitElement, css, html } from 'lit';
2
+
3
+ export type ButtonGroupOrientation = 'horizontal' | 'vertical';
4
+
5
+ /**
6
+ * `<bds-button-group>` — groups related buttons into a flex container.
7
+ *
8
+ * Attributes:
9
+ * orientation — `"horizontal"` (default) | `"vertical"`
10
+ * aria-label — accessible label for the group
11
+ *
12
+ * Slots:
13
+ * (default) — `<bds-button>` elements
14
+ *
15
+ * @example
16
+ * <bds-button-group aria-label="View options">
17
+ * <bds-button>Day</bds-button>
18
+ * <bds-button>Week</bds-button>
19
+ * <bds-button>Month</bds-button>
20
+ * </bds-button-group>
21
+ */
22
+ export class BdsButtonGroup extends LitElement {
23
+ static styles = css`
24
+ :host {
25
+ display: block;
26
+ }
27
+
28
+ .group {
29
+ display: inline-flex;
30
+ flex-direction: row;
31
+ align-items: center;
32
+ gap: 0;
33
+ }
34
+
35
+ :host([orientation='vertical']) .group {
36
+ flex-direction: column;
37
+ align-items: stretch;
38
+ }
39
+
40
+ /* Collapse border radius between adjacent buttons */
41
+ ::slotted(*:not(:first-child)) {
42
+ --button_radius-start: 0;
43
+ }
44
+
45
+ ::slotted(*:not(:last-child)) {
46
+ --button_radius-end: 0;
47
+ }
48
+ `;
49
+
50
+ static properties = {
51
+ orientation: { type: String, reflect: true },
52
+ 'aria-label': { type: String },
53
+ };
54
+
55
+ declare orientation: ButtonGroupOrientation;
56
+ declare ['aria-label']: string | undefined;
57
+
58
+ constructor() {
59
+ super();
60
+ this.orientation = 'horizontal';
61
+ }
62
+
63
+ render() {
64
+ return html`
65
+ <div class="group" role="group" aria-label=${this['aria-label'] ?? ''}>
66
+ <slot></slot>
67
+ </div>
68
+ `;
69
+ }
70
+ }
71
+
72
+ customElements.define('bds-button-group', BdsButtonGroup);
73
+
74
+ declare global {
75
+ interface HTMLElementTagNameMap {
76
+ 'bds-button-group': BdsButtonGroup;
77
+ }
78
+ }