@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,90 @@
1
+ import { Meta, Canvas, ArgTypes } from '@storybook/blocks';
2
+ import * as Stories from './BdsSkipLink.stories';
3
+
4
+ <Meta of={Stories} />
5
+
6
+ # &lt;bds-skip-link&gt;
7
+
8
+ Framework-agnostic Skip Navigation Link custom element. Visually hidden until focused, allowing keyboard users to jump directly to the main content area and bypass repeated navigation.
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
+ Or in HTML without a bundler:
19
+
20
+ ```html
21
+ <script type="module">
22
+ import '@boostdev/components/web-components';
23
+ </script>
24
+ ```
25
+
26
+ ## When to use
27
+
28
+ - Place as the very first focusable element on every page that has a navigation region before the main content
29
+ - Required on all pages to comply with WCAG 2.4.1 (Bypass Blocks, Level A)
30
+
31
+ ## When not to use
32
+
33
+ - Do not place it anywhere other than the start of the document flow
34
+ - Do not use it as a general-purpose navigation shortcut — it is specifically for skipping repetitive blocks
35
+
36
+ ## Examples
37
+
38
+ ### Default
39
+ <Canvas of={Stories.Default} />
40
+
41
+ ### With custom label
42
+ <Canvas of={Stories.WithCustomLabel} />
43
+
44
+ ## Props
45
+
46
+ <ArgTypes of={Stories} />
47
+
48
+ ## Attributes
49
+
50
+ | Attribute | Type | Default | Description |
51
+ |-----------|------|---------|-------------|
52
+ | `href` | string | `"#main"` | The target anchor ID to jump to (e.g. `"#main-content"`) |
53
+
54
+ ## Slots
55
+
56
+ | Slot | Description |
57
+ |------|-------------|
58
+ | `(default)` | Link text; defaults to `"Skip to main content"` when no content is provided |
59
+
60
+ ## Usage in plain HTML
61
+
62
+ Place `<bds-skip-link>` as the very first element inside `<body>`:
63
+
64
+ ```html
65
+ <body>
66
+ <bds-skip-link href="#main-content"></bds-skip-link>
67
+
68
+ <header>
69
+ <nav>...</nav>
70
+ </header>
71
+
72
+ <main id="main-content">
73
+ Page content
74
+ </main>
75
+ </body>
76
+ ```
77
+
78
+ With custom label text:
79
+
80
+ ```html
81
+ <bds-skip-link href="#main-content">Skip to main content</bds-skip-link>
82
+ ```
83
+
84
+ ## Accessibility
85
+
86
+ - Visually hidden via `transform: translateY(...)` until focused — avoids `display: none` and `visibility: hidden` which remove the element from the accessibility tree
87
+ - Becomes visible on `:focus-visible`, ensuring it is discoverable by keyboard and switch-access users
88
+ - Uses an `<a>` element so it is announced as a link by screen readers
89
+ - `z-index: 9999` ensures it appears above all other content when focused
90
+ - Satisfies WCAG 2.4.1 Bypass Blocks (Level A)
@@ -0,0 +1,68 @@
1
+ import React from 'react';
2
+ import type { Meta, StoryObj } from '@storybook/react';
3
+ import '../index'; // auto-registers all custom elements
4
+
5
+ // Thin React wrapper so Storybook controls work with the custom element's props
6
+ function BdsSkipLink({
7
+ href = '#main',
8
+ children,
9
+ }: {
10
+ href?: string;
11
+ children?: React.ReactNode;
12
+ }) {
13
+ return React.createElement(
14
+ 'bds-skip-link',
15
+ { href },
16
+ children,
17
+ );
18
+ }
19
+
20
+ const meta = {
21
+ title: 'Web Components/Interaction/SkipLink',
22
+ component: BdsSkipLink,
23
+ tags: ['!stable', 'experimental'],
24
+ parameters: { layout: 'padded' },
25
+ argTypes: {
26
+ href: { control: 'text' },
27
+ },
28
+ } satisfies Meta<typeof BdsSkipLink>;
29
+
30
+ export default meta;
31
+ type Story = StoryObj<typeof meta>;
32
+
33
+ export const Default: Story = {
34
+ args: { href: '#main' },
35
+ // Hint to the viewer that the link is visually hidden until focused
36
+ decorators: [
37
+ (Story) => (
38
+ <div>
39
+ <p style={{ marginBottom: '0.5rem', fontSize: '0.875rem', color: 'var(--bds-color_on-bg, #333)' }}>
40
+ Tab into the preview to see the skip link appear.
41
+ </p>
42
+ <Story />
43
+ <main id="main" style={{ marginTop: '1rem', padding: '1rem', border: '1px dashed currentcolor' }}>
44
+ Main content area
45
+ </main>
46
+ </div>
47
+ ),
48
+ ],
49
+ };
50
+
51
+ export const WithCustomLabel: Story = {
52
+ args: { href: '#content' },
53
+ render: (args) => (
54
+ <div>
55
+ <p style={{ marginBottom: '0.5rem', fontSize: '0.875rem', color: 'var(--bds-color_on-bg, #333)' }}>
56
+ Tab into the preview to see the skip link appear.
57
+ </p>
58
+ {React.createElement(
59
+ 'bds-skip-link',
60
+ { href: args.href },
61
+ 'Skip to main content',
62
+ )}
63
+ <main id="content" style={{ marginTop: '1rem', padding: '1rem', border: '1px dashed currentcolor' }}>
64
+ Main content area
65
+ </main>
66
+ </div>
67
+ ),
68
+ };
@@ -0,0 +1,117 @@
1
+ import { Meta, Canvas, ArgTypes } from '@storybook/blocks';
2
+ import * as Stories from './BdsTabs.stories';
3
+
4
+ <Meta of={Stories} />
5
+
6
+ # &lt;bds-tabs&gt;
7
+
8
+ Framework-agnostic Tabs custom element. Coordinates `<bds-tab>` and `<bds-tab-panel>` children by DOM order, with full keyboard navigation.
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
+ Or in HTML without a bundler:
19
+
20
+ ```html
21
+ <script type="module">
22
+ import '@boostdev/components/web-components';
23
+ </script>
24
+ ```
25
+
26
+ ## When to use
27
+
28
+ - Organising related content into sections when only one section is shown at a time
29
+ - Switching between views at the same level of hierarchy
30
+
31
+ ## When not to use
32
+
33
+ - For navigation between pages — use `<a>` links or a router
34
+ - When all sections should be visible at once — use an accordion or separate sections
35
+
36
+ ## Examples
37
+
38
+ ### Default
39
+ <Canvas of={Stories.Default} />
40
+
41
+ ### With disabled tab
42
+ <Canvas of={Stories.WithDisabledTab} />
43
+
44
+ ### Many tabs
45
+ <Canvas of={Stories.ManyTabs} />
46
+
47
+ ## Props
48
+
49
+ <ArgTypes of={Stories} />
50
+
51
+ ## Attributes — `<bds-tabs>`
52
+
53
+ `<bds-tabs>` has no configurable attributes. Tab state and active index are managed internally.
54
+
55
+ ## Attributes — `<bds-tab>`
56
+
57
+ | Attribute | Type | Default | Description |
58
+ |-----------|------|---------|-------------|
59
+ | `disabled` | boolean | `false` | Prevents the tab from being selected; tab is skipped during keyboard navigation |
60
+ | `selected` | boolean | `false` | Set by the parent `<bds-tabs>`; do not set manually |
61
+
62
+ ## Slots
63
+
64
+ ### `<bds-tabs>`
65
+
66
+ | Slot | Description |
67
+ |------|-------------|
68
+ | `tab` | `<bds-tab>` elements — rendered in the tab list |
69
+ | `panel` | `<bds-tab-panel>` elements — rendered below the tab list |
70
+
71
+ ### `<bds-tab>`
72
+
73
+ | Slot | Description |
74
+ |------|-------------|
75
+ | `(default)` | Tab label text |
76
+
77
+ ### `<bds-tab-panel>`
78
+
79
+ | Slot | Description |
80
+ |------|-------------|
81
+ | `(default)` | Panel content displayed when the corresponding tab is selected |
82
+
83
+ ## Events
84
+
85
+ | Event | Fired by | Bubbles | Description |
86
+ |-------|----------|---------|-------------|
87
+ | `bds-tab-select` | `<bds-tab>` | Yes | Fired when a tab is clicked; handled internally by `<bds-tabs>` |
88
+
89
+ ## Usage in plain HTML
90
+
91
+ Tabs and panels are matched by DOM order (first tab → first panel, etc.):
92
+
93
+ ```html
94
+ <bds-tabs>
95
+ <bds-tab slot="tab">Overview</bds-tab>
96
+ <bds-tab slot="tab">Details</bds-tab>
97
+ <bds-tab slot="tab" disabled>Disabled</bds-tab>
98
+
99
+ <bds-tab-panel slot="panel">
100
+ <p>Overview content</p>
101
+ </bds-tab-panel>
102
+ <bds-tab-panel slot="panel">
103
+ <p>Details content</p>
104
+ </bds-tab-panel>
105
+ <bds-tab-panel slot="panel">
106
+ <p>Disabled tab content (unreachable)</p>
107
+ </bds-tab-panel>
108
+ </bds-tabs>
109
+ ```
110
+
111
+ ## Accessibility
112
+
113
+ - The tab list container has `role="tablist"`
114
+ - Each `<bds-tab>` renders a `<button role="tab">` with `aria-selected` and the correct `tabindex` (0 for active, -1 for others)
115
+ - Each `<bds-tab-panel>` receives `hidden` when not active
116
+ - Keyboard navigation: ArrowRight / ArrowLeft cycles through enabled tabs; Home / End jumps to first / last enabled tab
117
+ - Disabled tabs are excluded from keyboard navigation
@@ -0,0 +1,94 @@
1
+ import React from 'react';
2
+ import type { Meta, StoryObj } from '@storybook/react';
3
+ import '../index'; // auto-registers all custom elements
4
+
5
+ // Thin React wrapper so Storybook controls work with the custom element's props
6
+ function BdsTabs({
7
+ tabs = ['Overview', 'Details', 'Settings'],
8
+ panels = ['Overview content.', 'Details content.', 'Settings content.'],
9
+ }: {
10
+ tabs?: string[];
11
+ panels?: string[];
12
+ }) {
13
+ return React.createElement(
14
+ 'bds-tabs',
15
+ null,
16
+ ...tabs.map(label =>
17
+ React.createElement('bds-tab', { key: label, slot: 'tab' }, label),
18
+ ),
19
+ ...panels.map((content, i) =>
20
+ React.createElement(
21
+ 'bds-tab-panel',
22
+ { key: i, slot: 'panel' },
23
+ React.createElement('p', { style: { margin: 0 } }, content),
24
+ ),
25
+ ),
26
+ );
27
+ }
28
+
29
+ const meta = {
30
+ title: 'Web Components/Interaction/Tabs',
31
+ component: BdsTabs,
32
+ tags: ['!stable', 'experimental'],
33
+ parameters: { layout: 'padded' },
34
+ } satisfies Meta<typeof BdsTabs>;
35
+
36
+ export default meta;
37
+ type Story = StoryObj<typeof meta>;
38
+
39
+ export const Default: Story = {
40
+ args: {
41
+ tabs: ['Overview', 'Details', 'Settings'],
42
+ panels: [
43
+ 'Overview content. Use tabs to divide related content into sections.',
44
+ 'Details content. Each tab maps to a panel by DOM order.',
45
+ 'Settings content. Navigate with ArrowLeft / ArrowRight keys.',
46
+ ],
47
+ },
48
+ };
49
+
50
+ export const WithDisabledTab: Story = {
51
+ render: () =>
52
+ React.createElement(
53
+ 'bds-tabs',
54
+ null,
55
+ React.createElement('bds-tab', { slot: 'tab' }, 'Active'),
56
+ React.createElement('bds-tab', { slot: 'tab', disabled: '' }, 'Disabled'),
57
+ React.createElement('bds-tab', { slot: 'tab' }, 'Another'),
58
+ React.createElement(
59
+ 'bds-tab-panel',
60
+ { slot: 'panel' },
61
+ React.createElement('p', { style: { margin: 0 } }, 'Content for the first tab.'),
62
+ ),
63
+ React.createElement(
64
+ 'bds-tab-panel',
65
+ { slot: 'panel' },
66
+ React.createElement('p', { style: { margin: 0 } }, 'This panel is paired with the disabled tab.'),
67
+ ),
68
+ React.createElement(
69
+ 'bds-tab-panel',
70
+ { slot: 'panel' },
71
+ React.createElement('p', { style: { margin: 0 } }, 'Content for the third tab.'),
72
+ ),
73
+ ),
74
+ };
75
+
76
+ export const ManyTabs: Story = {
77
+ render: () => {
78
+ const labels = ['Dashboard', 'Reports', 'Users', 'Billing', 'Integrations'];
79
+ return React.createElement(
80
+ 'bds-tabs',
81
+ null,
82
+ ...labels.map(label =>
83
+ React.createElement('bds-tab', { key: label, slot: 'tab' }, label),
84
+ ),
85
+ ...labels.map((label, i) =>
86
+ React.createElement(
87
+ 'bds-tab-panel',
88
+ { key: i, slot: 'panel' },
89
+ React.createElement('p', { style: { margin: 0 } }, `${label} content area.`),
90
+ ),
91
+ ),
92
+ );
93
+ },
94
+ };
@@ -0,0 +1,104 @@
1
+ import { Meta, Canvas, ArgTypes } from '@storybook/blocks';
2
+ import * as Stories from './BdsTooltip.stories';
3
+
4
+ <Meta of={Stories} />
5
+
6
+ # &lt;bds-tooltip&gt;
7
+
8
+ Framework-agnostic Tooltip custom element. Displays a small informational label on hover and keyboard focus using CSS-only visibility — no JavaScript positioning required.
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
+ Or in HTML without a bundler:
19
+
20
+ ```html
21
+ <script type="module">
22
+ import '@boostdev/components/web-components';
23
+ </script>
24
+ ```
25
+
26
+ ## When to use
27
+
28
+ - Labelling icon-only buttons that have no visible text
29
+ - Providing supplementary information for a UI element without cluttering the layout
30
+ - Short, non-interactive hints (a single sentence or less)
31
+
32
+ ## When not to use
33
+
34
+ - For interactive content (links, buttons inside the tooltip) — use `<bds-popover>` instead
35
+ - For error messages or validation feedback — use an inline message
36
+ - For content longer than a short phrase — use `<bds-popover>` or a disclosure pattern
37
+
38
+ ## Examples
39
+
40
+ ### Default
41
+ <Canvas of={Stories.Default} />
42
+
43
+ ### On a button
44
+ <Canvas of={Stories.OnButton} />
45
+
46
+ ### Bottom placement
47
+ <Canvas of={Stories.Bottom} />
48
+
49
+ ### Left placement
50
+ <Canvas of={Stories.Left} />
51
+
52
+ ### Right placement
53
+ <Canvas of={Stories.Right} />
54
+
55
+ ### All placements
56
+ <Canvas of={Stories.AllPlacements} />
57
+
58
+ ## Props
59
+
60
+ <ArgTypes of={Stories} />
61
+
62
+ ## Attributes
63
+
64
+ | Attribute | Type | Default | Description |
65
+ |-----------|------|---------|-------------|
66
+ | `content` | string | `""` | Text to display inside the tooltip |
67
+ | `placement` | `"top" \| "bottom" \| "left" \| "right"` | `"top"` | Where the tooltip appears relative to the trigger |
68
+
69
+ ## Slots
70
+
71
+ | Slot | Description |
72
+ |------|-------------|
73
+ | `(default)` | The trigger element (button, icon, etc.) that the tooltip is anchored to |
74
+
75
+ ## CSS Custom Properties
76
+
77
+ | Property | Description |
78
+ |----------|-------------|
79
+ | `--tooltip_bg` | Tooltip background colour (default: `var(--bds-color_on-bg)`) |
80
+ | `--tooltip_text` | Tooltip text colour (default: `var(--bds-color_bg)`) |
81
+
82
+ ## Usage in plain HTML
83
+
84
+ ```html
85
+ <bds-tooltip content="Save your changes" placement="top">
86
+ <button type="button">Save</button>
87
+ </bds-tooltip>
88
+
89
+ <!-- Icon-only button with tooltip label -->
90
+ <bds-tooltip content="Delete item" placement="bottom">
91
+ <button type="button" aria-label="Delete item">
92
+ <!-- icon SVG -->
93
+ </button>
94
+ </bds-tooltip>
95
+ ```
96
+
97
+ ## Accessibility
98
+
99
+ - The tooltip panel has `role="tooltip"`
100
+ - Visibility is controlled by `:hover` and `:focus-within` — no JavaScript required
101
+ - The tooltip is rendered adjacent to the trigger inside the same shadow root, so screen readers can read it via proximity
102
+ - Note: `aria-describedby` cannot cross shadow DOM boundaries; if your project requires explicit ARIA association, use `<bds-popover>` instead
103
+ - `pointer-events: none` on the tooltip prevents it from interfering with mouse events
104
+ - Fade transition respects `prefers-reduced-motion`
@@ -0,0 +1,87 @@
1
+ import React from 'react';
2
+ import type { Meta, StoryObj } from '@storybook/react';
3
+ import type { TooltipPlacement } from './bds-tooltip';
4
+ import '../index'; // auto-registers all custom elements
5
+
6
+ // Thin React wrapper so Storybook controls work with the custom element's props
7
+ function BdsTooltip({
8
+ content = 'Tooltip text',
9
+ placement = 'top',
10
+ children,
11
+ }: {
12
+ content?: string;
13
+ placement?: TooltipPlacement;
14
+ children?: React.ReactNode;
15
+ }) {
16
+ return React.createElement(
17
+ 'bds-tooltip',
18
+ { content, placement },
19
+ children ?? React.createElement('button', { type: 'button' }, 'Hover me'),
20
+ );
21
+ }
22
+
23
+ const meta = {
24
+ title: 'Web Components/Interaction/Tooltip',
25
+ component: BdsTooltip,
26
+ tags: ['!stable', 'experimental'],
27
+ parameters: { layout: 'centered' },
28
+ argTypes: {
29
+ content: { control: 'text' },
30
+ placement: { control: 'select', options: ['top', 'bottom', 'left', 'right'] },
31
+ },
32
+ } satisfies Meta<typeof BdsTooltip>;
33
+
34
+ export default meta;
35
+ type Story = StoryObj<typeof meta>;
36
+
37
+ export const Default: Story = {
38
+ args: { content: 'Tooltip text', placement: 'top' },
39
+ };
40
+
41
+ export const OnButton: Story = {
42
+ args: { content: 'Save your changes', placement: 'top' },
43
+ render: (args) =>
44
+ React.createElement(
45
+ 'bds-tooltip',
46
+ { content: args.content, placement: args.placement },
47
+ React.createElement(
48
+ 'button',
49
+ { type: 'button', style: { padding: '0.5rem 1rem', cursor: 'pointer' } },
50
+ 'Save',
51
+ ),
52
+ ),
53
+ };
54
+
55
+ export const Bottom: Story = {
56
+ args: { content: 'Appears below', placement: 'bottom' },
57
+ };
58
+
59
+ export const Left: Story = {
60
+ args: { content: 'Appears to the left', placement: 'left' },
61
+ };
62
+
63
+ export const Right: Story = {
64
+ args: { content: 'Appears to the right', placement: 'right' },
65
+ };
66
+
67
+ export const AllPlacements: Story = {
68
+ render: () => (
69
+ <div style={{ display: 'grid', gridTemplateColumns: 'repeat(2, auto)', gap: '4rem', padding: '3rem' }}>
70
+ {(['top', 'bottom', 'left', 'right'] as const).map(placement =>
71
+ React.createElement(
72
+ 'div',
73
+ { key: placement, style: { display: 'flex', justifyContent: 'center', alignItems: 'center' } },
74
+ React.createElement(
75
+ 'bds-tooltip',
76
+ { content: `Placement: ${placement}`, placement },
77
+ React.createElement(
78
+ 'button',
79
+ { type: 'button', style: { padding: '0.5rem 1rem', cursor: 'pointer' } },
80
+ placement,
81
+ ),
82
+ ),
83
+ ),
84
+ )}
85
+ </div>
86
+ ),
87
+ };
@@ -28,9 +28,8 @@ export class BdsAccordion extends LitElement {
28
28
  display: block;
29
29
  --bdc_color: var(--bds-color_bg--subtle);
30
30
  --bdc-outline_radius: var(--bds-border_radius--s);
31
- outline: var(--bdc-outline_width) solid var(--bdc_color);
32
- outline-offset: var(--bdc-outline_offset);
33
31
  border-radius: var(--accordion_radius, var(--bdc-outline_radius));
32
+ box-shadow: inset 0 0 0 var(--bdc-outline_width) var(--bdc_color);
34
33
  overflow: hidden;
35
34
  }
36
35
  `;
@@ -1,13 +1,13 @@
1
1
  import { LitElement, css, html, nothing } from 'lit';
2
2
 
3
- export type ButtonVariant = 'default' | 'ghost';
3
+ export type ButtonVariant = 'default' | 'outline' | 'ghost'; // 'ghost' is deprecated, use 'outline'
4
4
  export type ButtonSize = 'small' | 'medium' | 'large';
5
5
 
6
6
  /**
7
7
  * `<bds-button>` — framework-agnostic Button custom element.
8
8
  *
9
9
  * Attributes:
10
- * variant — "default" (filled, default) | "ghost" (transparent + outlined)
10
+ * variant — "default" (filled, default) | "outline" (transparent + outlined) | "ghost" (deprecated alias for "outline")
11
11
  * size — "small" | "medium" (default) | "large"
12
12
  * disabled — boolean
13
13
  * href — renders an <a> tag instead of <button>
@@ -38,9 +38,9 @@ export class BdsButton extends LitElement {
38
38
  }
39
39
 
40
40
  @keyframes pulse {
41
- 0% { transform: scale(1); box-shadow: 0 0 0 0 rgb(from var(--button_pulse-color, var(--button_color, var(--bds-color_green))) r g b / 50%); }
42
- 70% { transform: scale(1.01); box-shadow: 0 0 0 var(--bds-space_m) rgb(from var(--button_pulse-color, var(--button_color, var(--bds-color_green))) r g b / 0%); }
43
- 100% { transform: scale(1); box-shadow: 0 0 0 0 rgb(from var(--button_pulse-color, var(--button_color, var(--bds-color_green))) r g b / 0%); }
41
+ 0% { transform: scale(1); box-shadow: 0 0 0 0 rgb(from var(--button_pulse-color, var(--button_color, var(--bds-color_interactive))) r g b / 50%); }
42
+ 70% { transform: scale(1.01); box-shadow: 0 0 0 var(--bds-space_m) rgb(from var(--button_pulse-color, var(--button_color, var(--bds-color_interactive))) r g b / 0%); }
43
+ 100% { transform: scale(1); box-shadow: 0 0 0 0 rgb(from var(--button_pulse-color, var(--button_color, var(--bds-color_interactive))) r g b / 0%); }
44
44
  }
45
45
 
46
46
  :host {
@@ -64,16 +64,16 @@ export class BdsButton extends LitElement {
64
64
  white-space: nowrap;
65
65
  line-height: 1;
66
66
 
67
- --button_color: var(--bds-color_green);
68
- --button_on-color: var(--bds-color_on-green);
67
+ --button_color: var(--bds-color_interactive);
68
+ --button_on-color: var(--bds-color_on-interactive);
69
+ --button_color--on-bg: var(--bds-color_interactive_on-bg);
69
70
 
70
71
  background-color: var(--button_bg, var(--button_color));
71
72
  color: var(--button_text, var(--button_on-color));
72
73
  border: var(--button_border, none);
73
74
  --bdc_color: transparent;
74
75
 
75
- outline: var(--bdc-outline_width) solid var(--bdc_color);
76
- outline-offset: var(--bdc-outline_offset);
76
+ box-shadow: inset 0 0 0 var(--bdc-outline_width) var(--bdc_color);
77
77
  transition: var(--bds-animation_transition),
78
78
  --bdc_color var(--bds-animation_transition-duration) var(--bds-animation_easing);
79
79
  }
@@ -83,10 +83,11 @@ export class BdsButton extends LitElement {
83
83
  }
84
84
 
85
85
  /* Variants */
86
- .button.ghost {
86
+ .button.outline,
87
+ .button.ghost /* deprecated — use variant="outline" */ {
87
88
  --button_bg: transparent;
88
- --button_text: var(--button_color);
89
- --bdc_color: var(--button_color);
89
+ --button_text: var(--button_color--on-bg);
90
+ --bdc_color: var(--button_color--on-bg);
90
91
  }
91
92
 
92
93
  /* Sizes */
@@ -155,7 +156,8 @@ export class BdsButton extends LitElement {
155
156
  --bdc_color: currentcolor;
156
157
  }
157
158
 
158
- /* Ghost hover */
159
+ /* Outline hover */
160
+ .button.outline:hover,
159
161
  .button.ghost:hover {
160
162
  --button_bg: var(--button_color);
161
163
  --button_text: var(--button_on-color);
@@ -91,6 +91,7 @@ export class BdsCollapsible extends LitElement {
91
91
 
92
92
  .content {
93
93
  padding: var(--bds-space_m);
94
+ background-color: var(--collapsible_content-bg, var(--bds-color_bg));
94
95
  color: var(--collapsible_on-color, var(--bds-color_on-bg));
95
96
  font-size: var(--bds-font_size--body);
96
97
  line-height: var(--bds-font_line-height--body);
@@ -37,10 +37,8 @@ export class BdsDialog extends LitElement {
37
37
  --bdc_color: currentcolor;
38
38
  --bdc-outline_radius: var(--bds-border_radius--m);
39
39
 
40
- outline: var(--bdc-outline_width) solid var(--bdc_color);
41
- outline-offset: var(--bdc-outline_offset);
42
40
  border-radius: var(--dialog_radius, var(--bdc-outline_radius));
43
- box-shadow: var(--dialog_shadow, var(--bdc-outline_shadow));
41
+ box-shadow: inset 0 0 0 var(--bdc-outline_width) var(--bdc_color), var(--dialog_shadow, var(--bdc-outline_shadow));
44
42
  background-color: var(--dialog_color, var(--bds-color_grey--subtle));
45
43
  color: var(--dialog_on-color, var(--bds-color_on-grey--subtle));
46
44
  padding: var(--bds-space_l);
@@ -74,8 +72,7 @@ export class BdsDialog extends LitElement {
74
72
  border: var(--dialog_close-border, none);
75
73
  --bdc_color: currentcolor;
76
74
 
77
- outline: var(--bdc-outline_width) solid var(--bdc_color);
78
- outline-offset: var(--bdc-outline_offset);
75
+ box-shadow: inset 0 0 0 var(--bdc-outline_width) var(--bdc_color);
79
76
  cursor: pointer;
80
77
  }
81
78