@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
@@ -3,36 +3,74 @@ import * as Stories from './BdsSelect.stories';
3
3
 
4
4
  <Meta of={Stories} />
5
5
 
6
- # Select
6
+ # &lt;bds-select&gt;
7
7
 
8
- `<bds-select>` is a form-associated Select custom element. It uses a JSON `options` attribute because slotting `<option>` elements into a shadow DOM `<select>` is not cross-browser supported.
8
+ Form-associated select custom element. Wraps a native `<select>` with consistent styling. Options are passed as a JSON attribute because slotting `<option>` elements into shadow DOM is not supported cross-browser.
9
9
 
10
- ## Usage
10
+ > **Status: experimental** — API may change before stable release.
11
11
 
12
- ```html
13
- <bds-select
14
- name="country"
15
- placeholder="Choose…"
16
- options='[{"value":"nl","label":"Netherlands"},{"value":"be","label":"Belgium"}]'
17
- ></bds-select>
12
+ ## Installation
13
+
14
+ ```js
15
+ import '@boostdev/components/web-components';
18
16
  ```
19
17
 
20
- ## Attributes
18
+ ## When to use
21
19
 
22
- | Attribute | Type | Default | Description |
23
- |---------------|-----------|---------|------------------------------------------------------|
24
- | `name` | `string` | `""` | Form field name |
25
- | `value` | `string` | `""` | Currently selected value |
26
- | `options` | `string` | `"[]"` | JSON array of `{ value, label, disabled? }` objects |
27
- | `placeholder` | `string` | `""` | Placeholder option label (disabled, empty value) |
28
- | `required` | `boolean` | `false` | Marks the field as required |
29
- | `disabled` | `boolean` | `false` | Disables the select |
20
+ Use `<bds-select>` for pick-from-list dropdowns where users cannot type to search. For searchable/filterable lists, use `<bds-combobox>` instead.
30
21
 
31
- ## Stories
22
+ ## Examples
32
23
 
24
+ ### Default (pre-selected value)
33
25
  <Canvas of={Stories.Default} />
34
- <Canvas of={Stories.AllVariants} />
35
26
 
36
- ## Controls
27
+ ### With placeholder
28
+ <Canvas of={Stories.WithPlaceholder} />
29
+
30
+ ### Required
31
+ <Canvas of={Stories.Required} />
32
+
33
+ ### Disabled
34
+ <Canvas of={Stories.Disabled} />
35
+
36
+ ### With a disabled option
37
+ <Canvas of={Stories.WithDisabledOption} />
38
+
39
+ ## Props
37
40
 
38
41
  <ArgTypes of={Stories} />
42
+
43
+ ## Attributes
44
+
45
+ | Attribute | Type | Default | Description |
46
+ |---------------|---------|---------|----------------------------------------------------------------|
47
+ | `name` | string | `""` | Form field name |
48
+ | `value` | string | `""` | Currently selected value |
49
+ | `options` | string | `"[]"` | JSON array of `{ value, label, disabled? }` option objects |
50
+ | `placeholder` | string | `""` | Placeholder option label (disabled, empty value) |
51
+ | `required` | boolean | `false` | Marks the field as required |
52
+ | `disabled` | boolean | `false` | Disables the select |
53
+
54
+ ## Events
55
+
56
+ | Event | Detail | Description |
57
+ |----------|--------|-------------------------------------------------------|
58
+ | `change` | — | Native change event forwarded from the inner `<select>` |
59
+
60
+ ## Usage in plain HTML
61
+
62
+ ```html
63
+ <bds-select
64
+ name="country"
65
+ placeholder="Choose a country…"
66
+ options='[{"value":"nl","label":"Netherlands"},{"value":"be","label":"Belgium"}]'
67
+ ></bds-select>
68
+ ```
69
+
70
+ ## Accessibility
71
+
72
+ - Wraps a native `<select>` which has full browser and assistive technology support
73
+ - The custom chevron icon is `aria-hidden="true"` to avoid duplicate announcements
74
+ - `required` uses the native `<select required>` attribute for browser validation
75
+ - `disabled` uses the native `<select disabled>` attribute
76
+ - Participates in HTML forms via the Form-Associated Custom Elements API
@@ -1,31 +1,44 @@
1
1
  import React from 'react';
2
2
  import type { Meta, StoryObj } from '@storybook/react';
3
- import type { SelectOption } from './bds-select';
4
- import '../../index';
3
+ import '../../index'; // auto-registers all custom elements
5
4
 
6
- const COUNTRIES: SelectOption[] = [
5
+ const COUNTRIES = JSON.stringify([
7
6
  { value: 'nl', label: 'Netherlands' },
8
7
  { value: 'be', label: 'Belgium' },
9
8
  { value: 'de', label: 'Germany' },
10
9
  { value: 'fr', label: 'France' },
11
- { value: 'gb', label: 'United Kingdom', disabled: true },
12
- ];
10
+ { value: 'gb', label: 'United Kingdom' },
11
+ ]);
12
+
13
+ const COUNTRIES_WITH_DISABLED = JSON.stringify([
14
+ { value: 'nl', label: 'Netherlands' },
15
+ { value: 'be', label: 'Belgium' },
16
+ { value: 'de', label: 'Germany', disabled: true },
17
+ { value: 'fr', label: 'France' },
18
+ ]);
13
19
 
14
20
  function BdsSelect({
15
- placeholder = 'Choose an option…',
16
- disabled,
21
+ name,
22
+ value,
23
+ options,
24
+ placeholder,
17
25
  required,
26
+ disabled,
18
27
  }: {
28
+ name?: string;
29
+ value?: string;
30
+ options?: string;
19
31
  placeholder?: string;
20
- disabled?: boolean;
21
32
  required?: boolean;
33
+ disabled?: boolean;
22
34
  }) {
23
35
  return React.createElement('bds-select', {
24
- options: JSON.stringify(COUNTRIES),
36
+ name,
37
+ value,
38
+ options,
25
39
  placeholder,
26
- disabled: disabled || undefined,
27
40
  required: required || undefined,
28
- style: { minInlineSize: '200px', display: 'block' },
41
+ disabled: disabled || undefined,
29
42
  });
30
43
  }
31
44
 
@@ -33,61 +46,39 @@ const meta = {
33
46
  title: 'Web Components/Interaction/Form/Select',
34
47
  component: BdsSelect,
35
48
  tags: ['!stable', 'experimental'],
36
- parameters: { layout: 'padded' },
49
+ parameters: { layout: 'centered' },
37
50
  argTypes: {
38
- disabled: { control: 'boolean' },
39
51
  required: { control: 'boolean' },
52
+ disabled: { control: 'boolean' },
40
53
  },
54
+ decorators: [
55
+ (Story: React.ComponentType) => (
56
+ <div style={{ width: '280px' }}>
57
+ <Story />
58
+ </div>
59
+ ),
60
+ ],
41
61
  } satisfies Meta<typeof BdsSelect>;
42
62
 
43
63
  export default meta;
44
64
  type Story = StoryObj<typeof meta>;
45
65
 
46
- export const Default: Story = { args: { placeholder: 'Select a country…' } };
47
- export const Disabled: Story = { args: { placeholder: 'Select a country', disabled: true } };
48
- export const WithValue: Story = {
49
- render: () =>
50
- React.createElement('bds-select', {
51
- options: JSON.stringify(COUNTRIES),
52
- value: 'nl',
53
- style: { minInlineSize: '200px', display: 'block' },
54
- }),
66
+ export const Default: Story = {
67
+ args: { name: 'country', options: COUNTRIES, value: 'nl' },
55
68
  };
56
69
 
57
- export const AllVariants: Story = {
58
- render: () => (
59
- <div style={{ display: 'flex', flexDirection: 'column', gap: '16px', maxInlineSize: '300px' }}>
60
- <div>
61
- <p style={{ margin: '0 0 4px', fontSize: '0.75rem', color: '#888' }}>Default</p>
62
- {React.createElement('bds-select', { options: JSON.stringify(COUNTRIES), placeholder: 'Choose…' })}
63
- </div>
64
- <div>
65
- <p style={{ margin: '0 0 4px', fontSize: '0.75rem', color: '#888' }}>With value</p>
66
- {React.createElement('bds-select', { options: JSON.stringify(COUNTRIES), value: 'be' })}
67
- </div>
68
- <div>
69
- <p style={{ margin: '0 0 4px', fontSize: '0.75rem', color: '#888' }}>Disabled</p>
70
- {React.createElement('bds-select', { options: JSON.stringify(COUNTRIES), placeholder: 'Choose…', disabled: true })}
71
- </div>
72
- </div>
73
- ),
70
+ export const WithPlaceholder: Story = {
71
+ args: { name: 'country', options: COUNTRIES, placeholder: 'Choose a country…' },
74
72
  };
75
73
 
76
- export const Interactive: Story = {
77
- render: () => {
78
- const [value, setValue] = React.useState('');
79
- return (
80
- <div style={{ display: 'flex', flexDirection: 'column', gap: '8px', maxInlineSize: '300px' }}>
81
- <p style={{ margin: '0 0 8px', fontSize: '0.875rem' }}>
82
- Selected: {value ? COUNTRIES.find(c => c.value === value)?.label : '(none)'}
83
- </p>
84
- {React.createElement('bds-select', {
85
- options: JSON.stringify(COUNTRIES),
86
- placeholder: 'Select a country…',
87
- value,
88
- onChange: (e: Event) => setValue((e.target as HTMLSelectElement).value),
89
- })}
90
- </div>
91
- );
92
- },
74
+ export const Required: Story = {
75
+ args: { name: 'country', options: COUNTRIES, placeholder: 'Choose a country…', required: true },
76
+ };
77
+
78
+ export const Disabled: Story = {
79
+ args: { name: 'country', options: COUNTRIES, value: 'nl', disabled: true },
80
+ };
81
+
82
+ export const WithDisabledOption: Story = {
83
+ args: { name: 'country', options: COUNTRIES_WITH_DISABLED, placeholder: 'Choose a country…' },
93
84
  };
@@ -3,47 +3,75 @@ import * as Stories from './BdsSlider.stories';
3
3
 
4
4
  <Meta of={Stories} />
5
5
 
6
- # Slider
6
+ # &lt;bds-slider&gt;
7
7
 
8
- `<bds-slider>` is a form-associated range input. The fill track is driven by the `--slider_fill` CSS custom property and updates as the user drags.
8
+ Form-associated range slider. Wraps a native `<input type="range">` with a styled fill track driven by the `--slider_fill` CSS custom property.
9
9
 
10
- ## Usage
10
+ > **Status: experimental** — API may change before stable release.
11
11
 
12
- ```html
13
- <bds-slider name="volume" value="50" min="0" max="100" step="5"></bds-slider>
12
+ ## Installation
13
+
14
+ ```js
15
+ import '@boostdev/components/web-components';
14
16
  ```
15
17
 
18
+ ## When to use
19
+
20
+ Use `<bds-slider>` for continuous or stepped numeric ranges — volume controls, price ranges, ratings, or any value that benefits from visual representation of position within a range.
21
+
22
+ ## Examples
23
+
24
+ ### Default (0–100)
25
+ <Canvas of={Stories.Default} />
26
+
27
+ ### With step (25)
28
+ <Canvas of={Stories.WithStep} />
29
+
30
+ ### With custom min/max (1–5)
31
+ <Canvas of={Stories.WithMinMax} />
32
+
33
+ ### Disabled
34
+ <Canvas of={Stories.Disabled} />
35
+
36
+ ## Props
37
+
38
+ <ArgTypes of={Stories} />
39
+
16
40
  ## Attributes
17
41
 
18
- | Attribute | Type | Default | Description |
19
- |------------|-----------|---------|----------------------------------|
20
- | `name` | `string` | `""` | Form field name |
21
- | `value` | `number` | `0` | Current value |
22
- | `min` | `number` | `0` | Minimum value |
23
- | `max` | `number` | `100` | Maximum value |
24
- | `step` | `number` | `1` | Step increment |
25
- | `disabled` | `boolean` | `false` | Disables interaction |
42
+ | Attribute | Type | Default | Description |
43
+ |------------|---------|---------|------------------------------------------|
44
+ | `name` | string | `""` | Form field name |
45
+ | `value` | number | `0` | Current value |
46
+ | `min` | number | `0` | Minimum value |
47
+ | `max` | number | `100` | Maximum value |
48
+ | `step` | number | `1` | Step increment |
49
+ | `disabled` | boolean | `false` | Disables the slider |
26
50
 
27
51
  ## Events
28
52
 
29
- | Event | Description |
30
- |----------|-------------------------------|
31
- | `input` | Fired as the user drags |
32
- | `change` | Fired when the user releases |
53
+ | Event | Detail | Description |
54
+ |----------|--------|--------------------------------------|
55
+ | `input` | — | Fired continuously as the user drags |
56
+ | `change` | — | Fired when the user releases |
33
57
 
34
58
  ## CSS Custom Properties
35
59
 
36
- | Property | Description |
37
- |-----------------------|--------------------------------|
38
- | `--slider_fill-color` | Fill track color (default: `--bds-color_interactive`) |
39
- | `--slider_track-color`| Unfilled track color |
40
- | `--slider_thumb-color`| Thumb color |
60
+ | Property | Description |
61
+ |-------------------------|-----------------------------------------|
62
+ | `--slider_fill-color` | Fill track colour (defaults to `--bds-color_interactive`) |
63
+ | `--slider_track-color` | Unfilled track colour (defaults to `--bds-color_bg--subtle`) |
64
+ | `--slider_thumb-color` | Thumb colour (defaults to `--bds-color_interactive`) |
41
65
 
42
- ## Stories
66
+ ## Usage in plain HTML
43
67
 
44
- <Canvas of={Stories.Default} />
45
- <Canvas of={Stories.AllVariants} />
68
+ ```html
69
+ <bds-slider name="volume" value="50" min="0" max="100" step="5"></bds-slider>
70
+ ```
46
71
 
47
- ## Controls
72
+ ## Accessibility
48
73
 
49
- <ArgTypes of={Stories} />
74
+ - Wraps a native `<input type="range">` which has full browser and assistive technology support
75
+ - Arrow keys adjust the value by `step`
76
+ - `disabled` prevents interaction and reduces opacity
77
+ - Participates in HTML forms via the Form-Associated Custom Elements API
@@ -1,14 +1,16 @@
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
5
  function BdsSlider({
6
+ name,
6
7
  value,
7
8
  min,
8
9
  max,
9
10
  step,
10
11
  disabled,
11
12
  }: {
13
+ name?: string;
12
14
  value?: number;
13
15
  min?: number;
14
16
  max?: number;
@@ -16,12 +18,12 @@ function BdsSlider({
16
18
  disabled?: boolean;
17
19
  }) {
18
20
  return React.createElement('bds-slider', {
21
+ name,
19
22
  value,
20
23
  min,
21
24
  max,
22
25
  step,
23
26
  disabled: disabled || undefined,
24
- style: { display: 'block', maxInlineSize: '320px' },
25
27
  });
26
28
  }
27
29
 
@@ -29,7 +31,7 @@ const meta = {
29
31
  title: 'Web Components/Interaction/Form/Slider',
30
32
  component: BdsSlider,
31
33
  tags: ['!stable', 'experimental'],
32
- parameters: { layout: 'padded' },
34
+ parameters: { layout: 'centered' },
33
35
  argTypes: {
34
36
  value: { control: 'number' },
35
37
  min: { control: 'number' },
@@ -37,53 +39,30 @@ const meta = {
37
39
  step: { control: 'number' },
38
40
  disabled: { control: 'boolean' },
39
41
  },
42
+ decorators: [
43
+ (Story: React.ComponentType) => (
44
+ <div style={{ width: '300px' }}>
45
+ <Story />
46
+ </div>
47
+ ),
48
+ ],
40
49
  } satisfies Meta<typeof BdsSlider>;
41
50
 
42
51
  export default meta;
43
52
  type Story = StoryObj<typeof meta>;
44
53
 
45
- export const Default: Story = { args: { value: 50 } };
46
- export const WithStep: Story = { args: { value: 25, min: 0, max: 100, step: 25 } };
47
- export const Disabled: Story = { args: { value: 60, disabled: true } };
54
+ export const Default: Story = {
55
+ args: { name: 'volume', value: 50 },
56
+ };
48
57
 
49
- export const AllVariants: Story = {
50
- render: () => (
51
- <div style={{ display: 'flex', flexDirection: 'column', gap: '24px', maxInlineSize: '320px' }}>
52
- <div>
53
- <p style={{ margin: '0 0 4px', fontSize: '0.75rem', color: '#888' }}>Default (0%)</p>
54
- {React.createElement('bds-slider', { value: 0, style: { display: 'block' } })}
55
- </div>
56
- <div>
57
- <p style={{ margin: '0 0 4px', fontSize: '0.75rem', color: '#888' }}>Mid (50%)</p>
58
- {React.createElement('bds-slider', { value: 50, style: { display: 'block' } })}
59
- </div>
60
- <div>
61
- <p style={{ margin: '0 0 4px', fontSize: '0.75rem', color: '#888' }}>Full (100%)</p>
62
- {React.createElement('bds-slider', { value: 100, style: { display: 'block' } })}
63
- </div>
64
- <div>
65
- <p style={{ margin: '0 0 4px', fontSize: '0.75rem', color: '#888' }}>Disabled</p>
66
- {React.createElement('bds-slider', { value: 40, disabled: true, style: { display: 'block' } })}
67
- </div>
68
- </div>
69
- ),
58
+ export const WithStep: Story = {
59
+ args: { name: 'volume', value: 25, min: 0, max: 100, step: 25 },
70
60
  };
71
61
 
72
- export const Interactive: Story = {
73
- render: () => {
74
- const [volume, setVolume] = React.useState(50);
75
- return (
76
- <div style={{ display: 'flex', flexDirection: 'column', gap: '8px', maxInlineSize: '320px' }}>
77
- <p style={{ margin: '0 0 4px', fontSize: '0.875rem' }}>Volume: {volume}%</p>
78
- {React.createElement('bds-slider', {
79
- value: volume,
80
- min: 0,
81
- max: 100,
82
- step: 1,
83
- style: { display: 'block' },
84
- onInput: (e: Event) => setVolume(parseFloat((e.target as HTMLInputElement).value)),
85
- })}
86
- </div>
87
- );
88
- },
62
+ export const WithMinMax: Story = {
63
+ args: { name: 'rating', value: 3, min: 1, max: 5 },
64
+ };
65
+
66
+ export const Disabled: Story = {
67
+ args: { name: 'volume', value: 40, disabled: true },
89
68
  };
@@ -3,37 +3,70 @@ import * as Stories from './BdsSwitch.stories';
3
3
 
4
4
  <Meta of={Stories} />
5
5
 
6
- # Switch
6
+ # &lt;bds-switch&gt;
7
7
 
8
- `<bds-switch>` is a visually styled toggle switch. Semantically equivalent to a checkbox (`role="switch"`), it participates in HTML forms via the Form-Associated Custom Elements API.
8
+ Form-associated toggle switch. Visually a sliding toggle but semantically equivalent to a checkbox (`role="switch"`). Participates in HTML forms via the Form-Associated Custom Elements API.
9
9
 
10
- ## Usage
10
+ > **Status: experimental** — API may change before stable release.
11
11
 
12
- ```html
13
- <bds-switch name="notifications" value="enabled">Enable notifications</bds-switch>
12
+ ## Installation
13
+
14
+ ```js
15
+ import '@boostdev/components/web-components';
14
16
  ```
15
17
 
18
+ ## When to use
19
+
20
+ Use `<bds-switch>` for binary on/off settings where the change takes immediate effect, such as enabling or disabling a feature. For settings that require form submission, `<bds-checkbox>` may be more appropriate.
21
+
22
+ ## Examples
23
+
24
+ ### Default (off)
25
+ <Canvas of={Stories.Default} />
26
+
27
+ ### Checked (on)
28
+ <Canvas of={Stories.Checked} />
29
+
30
+ ### Disabled
31
+ <Canvas of={Stories.Disabled} />
32
+
33
+ ## Props
34
+
35
+ <ArgTypes of={Stories} />
36
+
16
37
  ## Attributes
17
38
 
18
- | Attribute | Type | Default | Description |
19
- |------------|-----------|---------|-------------------------------------|
20
- | `name` | `string` | `""` | Form field name |
21
- | `value` | `string` | `"on"` | Submitted value when on |
22
- | `checked` | `boolean` | `false` | Whether the switch is on |
23
- | `required` | `boolean` | `false` | Marks the field as required |
24
- | `disabled` | `boolean` | `false` | Disables interaction |
39
+ | Attribute | Type | Default | Description |
40
+ |------------|---------|---------|--------------------------------------------------|
41
+ | `name` | string | `""` | Form field name |
42
+ | `value` | string | `"on"` | Value submitted when the switch is on |
43
+ | `checked` | boolean | `false` | Whether the switch is on |
44
+ | `required` | boolean | `false` | Marks the field as required |
45
+ | `disabled` | boolean | `false` | Disables the switch |
25
46
 
26
47
  ## Slots
27
48
 
28
- | Slot | Description |
29
- |-----------|---------------|
30
- | (default) | Label text |
49
+ | Slot | Description |
50
+ |-------------|--------------------|
51
+ | `(default)` | Label text content |
31
52
 
32
- ## Stories
53
+ ## Events
33
54
 
34
- <Canvas of={Stories.Default} />
35
- <Canvas of={Stories.AllVariants} />
55
+ | Event | Detail | Description |
56
+ |----------|--------|------------------------------------------------|
57
+ | `change` | — | Fired when the switch state changes |
36
58
 
37
- ## Controls
59
+ ## Usage in plain HTML
38
60
 
39
- <ArgTypes of={Stories} />
61
+ ```html
62
+ <bds-switch name="notifications" value="enabled">Enable notifications</bds-switch>
63
+ <bds-switch name="darkMode" value="on" checked>Dark mode</bds-switch>
64
+ ```
65
+
66
+ ## Accessibility
67
+
68
+ - Uses `role="switch"` on the inner `<input type="checkbox">` for correct screen reader announcement
69
+ - The inner `<input>` is associated with a `<label>` via matching `id`/`for` attributes
70
+ - The visual track and thumb are inside the `<label>` — clicking the label or the track both toggle the switch
71
+ - `disabled` sets `pointer-events: none` and reduces opacity
72
+ - Participates in HTML forms via the Form-Associated Custom Elements API
@@ -1,23 +1,32 @@
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
5
  function BdsSwitch({
6
- label = 'Enable feature',
6
+ name,
7
+ value,
7
8
  checked,
9
+ required,
8
10
  disabled,
11
+ children,
9
12
  }: {
10
- label?: string;
13
+ name?: string;
14
+ value?: string;
11
15
  checked?: boolean;
16
+ required?: boolean;
12
17
  disabled?: boolean;
18
+ children?: React.ReactNode;
13
19
  }) {
14
20
  return React.createElement(
15
21
  'bds-switch',
16
22
  {
23
+ name,
24
+ value,
17
25
  checked: checked || undefined,
26
+ required: required || undefined,
18
27
  disabled: disabled || undefined,
19
28
  },
20
- label,
29
+ children,
21
30
  );
22
31
  }
23
32
 
@@ -25,9 +34,10 @@ const meta = {
25
34
  title: 'Web Components/Interaction/Form/Switch',
26
35
  component: BdsSwitch,
27
36
  tags: ['!stable', 'experimental'],
28
- parameters: { layout: 'padded' },
37
+ parameters: { layout: 'centered' },
29
38
  argTypes: {
30
39
  checked: { control: 'boolean' },
40
+ required: { control: 'boolean' },
31
41
  disabled: { control: 'boolean' },
32
42
  },
33
43
  } satisfies Meta<typeof BdsSwitch>;
@@ -35,39 +45,14 @@ const meta = {
35
45
  export default meta;
36
46
  type Story = StoryObj<typeof meta>;
37
47
 
38
- export const Default: Story = { args: { label: 'Enable notifications' } };
39
- export const On: Story = { args: { label: 'Notifications enabled', checked: true } };
40
- export const Disabled: Story = { args: { label: 'Managed by admin', disabled: true } };
41
- export const DisabledOn: Story = { args: { label: 'Always on (managed)', checked: true, disabled: true } };
48
+ export const Default: Story = {
49
+ args: { name: 'notifications', value: 'enabled', children: 'Enable notifications' },
50
+ };
42
51
 
43
- export const AllVariants: Story = {
44
- render: () => (
45
- <div style={{ display: 'flex', flexDirection: 'column', gap: '16px' }}>
46
- {React.createElement('bds-switch', null, 'Off (default)')}
47
- {React.createElement('bds-switch', { checked: true }, 'On')}
48
- {React.createElement('bds-switch', { disabled: true }, 'Disabled off')}
49
- {React.createElement('bds-switch', { checked: true, disabled: true }, 'Disabled on')}
50
- </div>
51
- ),
52
+ export const Checked: Story = {
53
+ args: { name: 'notifications', value: 'enabled', checked: true, children: 'Notifications enabled' },
52
54
  };
53
55
 
54
- export const Interactive: Story = {
55
- render: () => {
56
- const [enabled, setEnabled] = React.useState(false);
57
- return (
58
- <div style={{ display: 'flex', flexDirection: 'column', gap: '8px' }}>
59
- <p style={{ margin: '0 0 8px', fontSize: '0.875rem' }}>
60
- Dark mode: {enabled ? 'enabled' : 'disabled'}
61
- </p>
62
- {React.createElement(
63
- 'bds-switch',
64
- {
65
- checked: enabled || undefined,
66
- onChange: (e: Event) => setEnabled((e.target as HTMLInputElement).checked),
67
- },
68
- 'Dark mode',
69
- )}
70
- </div>
71
- );
72
- },
56
+ export const Disabled: Story = {
57
+ args: { name: 'notifications', value: 'enabled', disabled: true, children: 'Notifications (disabled)' },
73
58
  };