@boostdev/design-system-components 1.1.2 → 1.2.0

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 (169) hide show
  1. package/AGENTS.md +13 -10
  2. package/dist/client.cjs +77 -99
  3. package/dist/client.css +611 -580
  4. package/dist/client.d.cts +13 -16
  5. package/dist/client.d.ts +13 -16
  6. package/dist/client.js +87 -109
  7. package/dist/index.cjs +77 -99
  8. package/dist/index.css +611 -580
  9. package/dist/index.d.cts +13 -16
  10. package/dist/index.d.ts +13 -16
  11. package/dist/index.js +87 -109
  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-O4UFI2RX.js → chunk-3REOIRDW.js} +13 -11
  17. package/dist/web-components/{chunk-K5CE6HSB.js → chunk-6MH5UWUD.js} +74 -17
  18. package/dist/web-components/{chunk-VM3YHGQ2.js → chunk-AJSXNDAP.js} +1 -2
  19. package/dist/web-components/{chunk-LSC4N56Q.js → chunk-BX3IPVOB.js} +1 -2
  20. package/dist/web-components/{chunk-CJ5ZOO42.js → chunk-DI46Q2EA.js} +50 -1
  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-QDRH46TF.js → chunk-QLZ2362S.js} +1 -3
  27. package/dist/web-components/{chunk-IK3PTFZ4.js → chunk-T6AETZRP.js} +1 -3
  28. package/dist/web-components/{chunk-4BX6AWXX.js → chunk-X3FKVHLK.js} +2 -4
  29. package/dist/web-components/{chunk-A67LCT7C.js → chunk-XNA6WTXG.js} +3 -4
  30. package/dist/web-components/{chunk-XIENXR7H.js → chunk-YRXCVKHV.js} +1 -3
  31. package/dist/web-components/{chunk-6T3RKUKG.js → chunk-ZTC6GRP7.js} +1 -2
  32. package/dist/web-components/globals.js +1 -1
  33. package/dist/web-components/index.js +16 -16
  34. package/dist/web-components/interaction/bds-accordion.js +1 -1
  35. package/dist/web-components/interaction/bds-button.d.ts +2 -2
  36. package/dist/web-components/interaction/bds-button.js +1 -1
  37. package/dist/web-components/interaction/bds-dialog.js +1 -1
  38. package/dist/web-components/interaction/bds-drawer.js +1 -1
  39. package/dist/web-components/interaction/form/bds-checkbox.js +1 -1
  40. package/dist/web-components/interaction/form/bds-combobox.js +1 -1
  41. package/dist/web-components/interaction/form/bds-number-input.js +1 -1
  42. package/dist/web-components/interaction/form/bds-radio.js +1 -1
  43. package/dist/web-components/interaction/form/bds-segmented-control.d.ts +20 -3
  44. package/dist/web-components/interaction/form/bds-segmented-control.js +1 -1
  45. package/dist/web-components/interaction/form/bds-select.js +1 -1
  46. package/dist/web-components/interaction/form/bds-switch.js +1 -1
  47. package/dist/web-components/interaction/form/bds-textarea.js +1 -1
  48. package/dist/web-components/ui/bds-alert.js +1 -1
  49. package/dist/web-components/ui/bds-card.js +1 -1
  50. package/dist/web-components/ui/bds-notification-banner.js +1 -1
  51. package/package.json +2 -2
  52. package/src/components/interaction/Button/Button.module.css +12 -11
  53. package/src/components/interaction/Button/Button.native.tsx +10 -9
  54. package/src/components/interaction/Button/Button.tsx +1 -1
  55. package/src/components/interaction/Command/Command.module.css +3 -7
  56. package/src/components/interaction/Dialog/Dialog.module.css +7 -5
  57. package/src/components/interaction/Drawer/Drawer.module.css +49 -1
  58. package/src/components/interaction/DropdownMenu/DropdownMenu.module.css +1 -3
  59. package/src/components/interaction/Popover/Popover.module.css +1 -3
  60. package/src/components/interaction/form/Checkbox/Checkbox.module.css +1 -3
  61. package/src/components/interaction/form/Combobox/Combobox.module.css +2 -6
  62. package/src/components/interaction/form/FormInput/FormInput.module.css +1 -3
  63. package/src/components/interaction/form/NumberInput/NumberInput.module.css +16 -4
  64. package/src/components/interaction/form/Radio/Radio.module.css +6 -16
  65. package/src/components/interaction/form/SegmentedControl/SegmentedControl.mdx +70 -25
  66. package/src/components/interaction/form/SegmentedControl/SegmentedControl.module.css +55 -33
  67. package/src/components/interaction/form/SegmentedControl/SegmentedControl.spec.tsx +127 -56
  68. package/src/components/interaction/form/SegmentedControl/SegmentedControl.stories.tsx +89 -72
  69. package/src/components/interaction/form/SegmentedControl/SegmentedControl.tsx +40 -62
  70. package/src/components/interaction/form/SegmentedControl/index.ts +1 -1
  71. package/src/components/interaction/form/Select/Select.module.css +2 -4
  72. package/src/components/interaction/form/Switch/Switch.module.css +5 -7
  73. package/src/components/interaction/form/Switch/Switch.native.spec.tsx +9 -9
  74. package/src/components/interaction/form/Switch/Switch.native.tsx +2 -2
  75. package/src/components/interaction/form/Textarea/Textarea.module.css +1 -3
  76. package/src/components/interaction/form/atoms/InputContainer.stories.tsx +64 -0
  77. package/src/components/interaction/form/atoms/Label.stories.tsx +33 -0
  78. package/src/components/interaction/form/atoms/Message.stories.tsx +33 -0
  79. package/src/components/layout/Card/Card.module.css +1 -3
  80. package/src/components/ui/Accordion/Accordion.module.css +1 -2
  81. package/src/components/ui/Alert/Alert.module.css +1 -2
  82. package/src/components/ui/Calendar/Calendar.module.css +2 -5
  83. package/src/components/ui/Carousel/Carousel.module.css +1 -3
  84. package/src/components/ui/NotificationBanner/NotificationBanner.module.css +1 -2
  85. package/src/components/ui/Pagination/Pagination.module.css +1 -2
  86. package/src/components/ui/SkipLink/SkipLink.module.css +1 -2
  87. package/src/components/ui/Table/Table.module.css +1 -2
  88. package/src/css/bdc.css +16 -11
  89. package/src/index.ts +1 -1
  90. package/src/web-components/globals.ts +3 -3
  91. package/src/web-components/interaction/BdsAccordion.mdx +51 -0
  92. package/src/web-components/interaction/BdsAccordion.stories.tsx +85 -0
  93. package/src/web-components/interaction/BdsCollapsible.mdx +46 -0
  94. package/src/web-components/interaction/BdsCollapsible.stories.tsx +87 -0
  95. package/src/web-components/interaction/BdsDialog.mdx +49 -0
  96. package/src/web-components/interaction/BdsDialog.stories.tsx +75 -0
  97. package/src/web-components/interaction/BdsDrawer.mdx +50 -0
  98. package/src/web-components/interaction/BdsDrawer.stories.tsx +66 -0
  99. package/src/web-components/interaction/BdsSkipLink.mdx +34 -0
  100. package/src/web-components/interaction/BdsSkipLink.stories.tsx +55 -0
  101. package/src/web-components/interaction/BdsTabs.mdx +47 -0
  102. package/src/web-components/interaction/BdsTabs.stories.tsx +80 -0
  103. package/src/web-components/interaction/BdsTooltip.mdx +38 -0
  104. package/src/web-components/interaction/BdsTooltip.stories.tsx +68 -0
  105. package/src/web-components/interaction/bds-accordion.ts +1 -2
  106. package/src/web-components/interaction/bds-button.ts +15 -13
  107. package/src/web-components/interaction/bds-dialog.ts +2 -5
  108. package/src/web-components/interaction/bds-drawer.ts +50 -1
  109. package/src/web-components/interaction/form/BdsCheckbox.mdx +39 -0
  110. package/src/web-components/interaction/form/BdsCheckbox.stories.tsx +73 -0
  111. package/src/web-components/interaction/form/BdsCombobox.mdx +52 -0
  112. package/src/web-components/interaction/form/BdsCombobox.stories.tsx +91 -0
  113. package/src/web-components/interaction/form/BdsFileInput.mdx +44 -0
  114. package/src/web-components/interaction/form/BdsFileInput.stories.tsx +84 -0
  115. package/src/web-components/interaction/form/BdsNumberInput.mdx +41 -0
  116. package/src/web-components/interaction/form/BdsNumberInput.stories.tsx +90 -0
  117. package/src/web-components/interaction/form/BdsRadio.mdx +41 -0
  118. package/src/web-components/interaction/form/BdsRadio.stories.tsx +90 -0
  119. package/src/web-components/interaction/form/BdsSegmentedControl.mdx +42 -0
  120. package/src/web-components/interaction/form/BdsSegmentedControl.stories.tsx +92 -0
  121. package/src/web-components/interaction/form/BdsSelect.mdx +38 -0
  122. package/src/web-components/interaction/form/BdsSelect.stories.tsx +93 -0
  123. package/src/web-components/interaction/form/BdsSlider.mdx +49 -0
  124. package/src/web-components/interaction/form/BdsSlider.stories.tsx +89 -0
  125. package/src/web-components/interaction/form/BdsSwitch.mdx +39 -0
  126. package/src/web-components/interaction/form/BdsSwitch.stories.tsx +73 -0
  127. package/src/web-components/interaction/form/BdsTextarea.mdx +41 -0
  128. package/src/web-components/interaction/form/BdsTextarea.stories.tsx +79 -0
  129. package/src/web-components/interaction/form/bds-checkbox.ts +1 -3
  130. package/src/web-components/interaction/form/bds-combobox.ts +1 -3
  131. package/src/web-components/interaction/form/bds-number-input.ts +3 -4
  132. package/src/web-components/interaction/form/bds-radio.ts +6 -12
  133. package/src/web-components/interaction/form/bds-segmented-control.ts +91 -20
  134. package/src/web-components/interaction/form/bds-select.ts +2 -4
  135. package/src/web-components/interaction/form/bds-switch.ts +3 -4
  136. package/src/web-components/interaction/form/bds-textarea.ts +1 -3
  137. package/src/web-components/ui/BdsAvatar.mdx +67 -0
  138. package/src/web-components/ui/BdsAvatar.stories.tsx +62 -0
  139. package/src/web-components/ui/BdsBreadcrumb.mdx +63 -0
  140. package/src/web-components/ui/BdsBreadcrumb.stories.tsx +59 -0
  141. package/src/web-components/ui/BdsCard.mdx +83 -0
  142. package/src/web-components/ui/BdsCard.stories.tsx +90 -0
  143. package/src/web-components/ui/BdsDescriptionList.mdx +67 -0
  144. package/src/web-components/ui/BdsDescriptionList.stories.tsx +79 -0
  145. package/src/web-components/ui/BdsIconWrapper.mdx +70 -0
  146. package/src/web-components/ui/BdsIconWrapper.stories.tsx +76 -0
  147. package/src/web-components/ui/BdsLink.mdx +75 -0
  148. package/src/web-components/ui/BdsLink.stories.tsx +64 -0
  149. package/src/web-components/ui/BdsLoading.mdx +62 -0
  150. package/src/web-components/ui/BdsLoading.stories.tsx +37 -0
  151. package/src/web-components/ui/BdsNotificationBanner.mdx +90 -0
  152. package/src/web-components/ui/BdsNotificationBanner.stories.tsx +93 -0
  153. package/src/web-components/ui/BdsProgress.mdx +63 -0
  154. package/src/web-components/ui/BdsProgress.stories.tsx +70 -0
  155. package/src/web-components/ui/BdsProgressCircle.mdx +64 -0
  156. package/src/web-components/ui/BdsProgressCircle.stories.tsx +69 -0
  157. package/src/web-components/ui/BdsRating.mdx +61 -0
  158. package/src/web-components/ui/BdsRating.stories.tsx +39 -0
  159. package/src/web-components/ui/BdsSectionHeader.mdx +69 -0
  160. package/src/web-components/ui/BdsSectionHeader.stories.tsx +56 -0
  161. package/src/web-components/ui/BdsSeparator.mdx +63 -0
  162. package/src/web-components/ui/BdsSeparator.stories.tsx +47 -0
  163. package/src/web-components/ui/BdsSkeleton.mdx +67 -0
  164. package/src/web-components/ui/BdsSkeleton.stories.tsx +50 -0
  165. package/src/web-components/ui/BdsTypography.mdx +83 -0
  166. package/src/web-components/ui/BdsTypography.stories.tsx +51 -0
  167. package/src/web-components/ui/bds-alert.ts +1 -2
  168. package/src/web-components/ui/bds-card.ts +1 -3
  169. package/src/web-components/ui/bds-notification-banner.ts +1 -2
@@ -0,0 +1,52 @@
1
+ import { Meta, Canvas, ArgTypes } from '@storybook/blocks';
2
+ import * as Stories from './BdsCombobox.stories';
3
+
4
+ <Meta of={Stories} />
5
+
6
+ # Combobox
7
+
8
+ `<bds-combobox>` is a form-associated autocomplete input. The user types to filter options and selects with Enter or mouse click. Keyboard navigation: ArrowDown/ArrowUp to move focus, Enter to select, Escape to close.
9
+
10
+ ## Usage
11
+
12
+ ```html
13
+ <bds-combobox
14
+ name="country"
15
+ placeholder="Search…"
16
+ options='[{"value":"nl","label":"Netherlands"},{"value":"be","label":"Belgium"}]'
17
+ ></bds-combobox>
18
+ ```
19
+
20
+ ## Attributes
21
+
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` | `""` | Input placeholder text |
28
+ | `disabled` | `boolean` | `false` | Disables the combobox |
29
+
30
+ ## Events
31
+
32
+ | Event | Detail | Description |
33
+ |--------------|----------------------------|----------------------------------|
34
+ | `bds-change` | `{ value, label }` | Fired when an option is selected |
35
+
36
+ ## Keyboard Navigation
37
+
38
+ | Key | Action |
39
+ |-------------|-------------------------|
40
+ | `ArrowDown` | Move to next option |
41
+ | `ArrowUp` | Move to previous option |
42
+ | `Enter` | Select focused option |
43
+ | `Escape` | Close the listbox |
44
+
45
+ ## Stories
46
+
47
+ <Canvas of={Stories.Default} />
48
+ <Canvas of={Stories.AllVariants} />
49
+
50
+ ## Controls
51
+
52
+ <ArgTypes of={Stories} />
@@ -0,0 +1,91 @@
1
+ import React from 'react';
2
+ import type { Meta, StoryObj } from '@storybook/react';
3
+ import type { ComboboxOption } from './bds-combobox';
4
+ import '../../index';
5
+
6
+ const COUNTRIES: ComboboxOption[] = [
7
+ { value: 'nl', label: 'Netherlands' },
8
+ { value: 'be', label: 'Belgium' },
9
+ { value: 'de', label: 'Germany' },
10
+ { value: 'fr', label: 'France' },
11
+ { value: 'es', label: 'Spain' },
12
+ { value: 'it', label: 'Italy' },
13
+ { value: 'gb', label: 'United Kingdom', disabled: true },
14
+ ];
15
+
16
+ function BdsCombobox({
17
+ placeholder = 'Search…',
18
+ disabled,
19
+ }: {
20
+ placeholder?: string;
21
+ disabled?: boolean;
22
+ }) {
23
+ return React.createElement('bds-combobox', {
24
+ options: JSON.stringify(COUNTRIES),
25
+ placeholder,
26
+ disabled: disabled || undefined,
27
+ style: { display: 'block', maxInlineSize: '280px' },
28
+ });
29
+ }
30
+
31
+ const meta = {
32
+ title: 'Web Components/Interaction/Form/Combobox',
33
+ component: BdsCombobox,
34
+ tags: ['!stable', 'experimental'],
35
+ parameters: { layout: 'padded' },
36
+ argTypes: {
37
+ disabled: { control: 'boolean' },
38
+ },
39
+ } satisfies Meta<typeof BdsCombobox>;
40
+
41
+ export default meta;
42
+ type Story = StoryObj<typeof meta>;
43
+
44
+ export const Default: Story = { args: { placeholder: 'Select a country…' } };
45
+ export const Disabled: Story = { args: { placeholder: 'Select a country…', disabled: true } };
46
+ export const WithValue: Story = {
47
+ render: () =>
48
+ React.createElement('bds-combobox', {
49
+ options: JSON.stringify(COUNTRIES),
50
+ value: 'nl',
51
+ placeholder: 'Search…',
52
+ style: { display: 'block', maxInlineSize: '280px' },
53
+ }),
54
+ };
55
+
56
+ export const AllVariants: Story = {
57
+ render: () => (
58
+ <div style={{ display: 'flex', flexDirection: 'column', gap: '16px', maxInlineSize: '280px' }}>
59
+ <div>
60
+ <p style={{ margin: '0 0 4px', fontSize: '0.75rem', color: '#888' }}>Default</p>
61
+ {React.createElement('bds-combobox', { options: JSON.stringify(COUNTRIES), placeholder: 'Search…' })}
62
+ </div>
63
+ <div>
64
+ <p style={{ margin: '0 0 4px', fontSize: '0.75rem', color: '#888' }}>With pre-selected value</p>
65
+ {React.createElement('bds-combobox', { options: JSON.stringify(COUNTRIES), value: 'be', placeholder: 'Search…' })}
66
+ </div>
67
+ <div>
68
+ <p style={{ margin: '0 0 4px', fontSize: '0.75rem', color: '#888' }}>Disabled</p>
69
+ {React.createElement('bds-combobox', { options: JSON.stringify(COUNTRIES), placeholder: 'Search…', disabled: true })}
70
+ </div>
71
+ </div>
72
+ ),
73
+ };
74
+
75
+ export const Interactive: Story = {
76
+ render: () => {
77
+ const [selected, setSelected] = React.useState<{ value: string; label: string } | null>(null);
78
+ return (
79
+ <div style={{ display: 'flex', flexDirection: 'column', gap: '8px', maxInlineSize: '280px' }}>
80
+ <p style={{ margin: '0 0 8px', fontSize: '0.875rem' }}>
81
+ Selected: {selected ? `${selected.label} (${selected.value})` : '(none)'}
82
+ </p>
83
+ {React.createElement('bds-combobox', {
84
+ options: JSON.stringify(COUNTRIES),
85
+ placeholder: 'Type to filter…',
86
+ 'onbds-change': (e: CustomEvent<{ value: string; label: string }>) => setSelected(e.detail),
87
+ })}
88
+ </div>
89
+ );
90
+ },
91
+ };
@@ -0,0 +1,44 @@
1
+ import { Meta, Canvas, ArgTypes } from '@storybook/blocks';
2
+ import * as Stories from './BdsFileInput.stories';
3
+
4
+ <Meta of={Stories} />
5
+
6
+ # File Input
7
+
8
+ `<bds-file-input>` is a form-associated file upload zone with drag-and-drop support. The slot content customises the zone label text.
9
+
10
+ ## Usage
11
+
12
+ ```html
13
+ <bds-file-input name="avatar" accept="image/*">Upload your photo</bds-file-input>
14
+ ```
15
+
16
+ ## Attributes
17
+
18
+ | Attribute | Type | Default | Description |
19
+ |------------|-----------|---------|------------------------------------------|
20
+ | `name` | `string` | `""` | Form field name |
21
+ | `accept` | `string` | `""` | File types to accept (e.g. `"image/*"`) |
22
+ | `multiple` | `boolean` | `false` | Allow selecting multiple files |
23
+ | `disabled` | `boolean` | `false` | Disables the drop zone |
24
+
25
+ ## Events
26
+
27
+ | Event | Detail | Description |
28
+ |--------------|-------------|------------------------------------------|
29
+ | `bds-change` | `FileList` | Fired when files are selected or dropped |
30
+
31
+ ## Slots
32
+
33
+ | Slot | Description |
34
+ |-----------|--------------------------------|
35
+ | (default) | Custom label text for the zone |
36
+
37
+ ## Stories
38
+
39
+ <Canvas of={Stories.Default} />
40
+ <Canvas of={Stories.AllVariants} />
41
+
42
+ ## Controls
43
+
44
+ <ArgTypes of={Stories} />
@@ -0,0 +1,84 @@
1
+ import React from 'react';
2
+ import type { Meta, StoryObj } from '@storybook/react';
3
+ import '../../index';
4
+
5
+ function BdsFileInput({
6
+ accept,
7
+ multiple,
8
+ disabled,
9
+ }: {
10
+ accept?: string;
11
+ multiple?: boolean;
12
+ disabled?: boolean;
13
+ }) {
14
+ return React.createElement('bds-file-input', {
15
+ accept,
16
+ multiple: multiple || undefined,
17
+ disabled: disabled || undefined,
18
+ style: { display: 'block', maxInlineSize: '480px' },
19
+ });
20
+ }
21
+
22
+ const meta = {
23
+ title: 'Web Components/Interaction/Form/FileInput',
24
+ component: BdsFileInput,
25
+ tags: ['!stable', 'experimental'],
26
+ parameters: { layout: 'padded' },
27
+ argTypes: {
28
+ multiple: { control: 'boolean' },
29
+ disabled: { control: 'boolean' },
30
+ },
31
+ } satisfies Meta<typeof BdsFileInput>;
32
+
33
+ export default meta;
34
+ type Story = StoryObj<typeof meta>;
35
+
36
+ export const Default: Story = { args: {} };
37
+ export const ImagesOnly: Story = { args: { accept: 'image/*' } };
38
+ export const Multiple: Story = { args: { multiple: true } };
39
+ export const Disabled: Story = { args: { disabled: true } };
40
+
41
+ export const AllVariants: Story = {
42
+ render: () => (
43
+ <div style={{ display: 'flex', flexDirection: 'column', gap: '24px', maxInlineSize: '480px' }}>
44
+ <div>
45
+ <p style={{ margin: '0 0 8px', fontSize: '0.75rem', color: '#888' }}>Any file type</p>
46
+ {React.createElement('bds-file-input', { style: { display: 'block' } })}
47
+ </div>
48
+ <div>
49
+ <p style={{ margin: '0 0 8px', fontSize: '0.75rem', color: '#888' }}>Images only</p>
50
+ {React.createElement('bds-file-input', { accept: 'image/*', style: { display: 'block' } })}
51
+ </div>
52
+ <div>
53
+ <p style={{ margin: '0 0 8px', fontSize: '0.75rem', color: '#888' }}>Multiple files</p>
54
+ {React.createElement('bds-file-input', { multiple: true, style: { display: 'block' } })}
55
+ </div>
56
+ <div>
57
+ <p style={{ margin: '0 0 8px', fontSize: '0.75rem', color: '#888' }}>Disabled</p>
58
+ {React.createElement('bds-file-input', { disabled: true, style: { display: 'block' } })}
59
+ </div>
60
+ </div>
61
+ ),
62
+ };
63
+
64
+ export const Interactive: Story = {
65
+ render: () => {
66
+ const [files, setFiles] = React.useState<string[]>([]);
67
+ return (
68
+ <div style={{ display: 'flex', flexDirection: 'column', gap: '12px', maxInlineSize: '480px' }}>
69
+ {React.createElement('bds-file-input', {
70
+ multiple: true,
71
+ style: { display: 'block' },
72
+ 'onbds-change': (e: CustomEvent<FileList>) => {
73
+ setFiles(Array.from(e.detail).map(f => f.name));
74
+ },
75
+ })}
76
+ {files.length > 0 && (
77
+ <ul style={{ margin: 0, padding: '0 0 0 16px', fontSize: '0.875rem' }}>
78
+ {files.map(name => <li key={name}>{name}</li>)}
79
+ </ul>
80
+ )}
81
+ </div>
82
+ );
83
+ },
84
+ };
@@ -0,0 +1,41 @@
1
+ import { Meta, Canvas, ArgTypes } from '@storybook/blocks';
2
+ import * as Stories from './BdsNumberInput.stories';
3
+
4
+ <Meta of={Stories} />
5
+
6
+ # Number Input
7
+
8
+ `<bds-number-input>` is a form-associated number input with decrement/increment stepper buttons. The native browser spin buttons are hidden in favour of the custom steppers.
9
+
10
+ ## Usage
11
+
12
+ ```html
13
+ <bds-number-input name="qty" value="1" min="0" max="99" step="1"></bds-number-input>
14
+ ```
15
+
16
+ ## Attributes
17
+
18
+ | Attribute | Type | Default | Description |
19
+ |------------|-----------|-------------|------------------------------------|
20
+ | `name` | `string` | `""` | Form field name |
21
+ | `value` | `number` | `0` | Current numeric value |
22
+ | `min` | `number` | `undefined` | Minimum allowed value |
23
+ | `max` | `number` | `undefined` | Maximum allowed value |
24
+ | `step` | `number` | `1` | Increment/decrement step |
25
+ | `disabled` | `boolean` | `false` | Disables all interaction |
26
+
27
+ ## Events
28
+
29
+ | Event | Description |
30
+ |----------|--------------------------------------------|
31
+ | `input` | Fired on stepper click and native input |
32
+ | `change` | Native change event |
33
+
34
+ ## Stories
35
+
36
+ <Canvas of={Stories.Default} />
37
+ <Canvas of={Stories.AllVariants} />
38
+
39
+ ## Controls
40
+
41
+ <ArgTypes of={Stories} />
@@ -0,0 +1,90 @@
1
+ import React from 'react';
2
+ import type { Meta, StoryObj } from '@storybook/react';
3
+ import '../../index';
4
+
5
+ function BdsNumberInput({
6
+ value,
7
+ min,
8
+ max,
9
+ step,
10
+ disabled,
11
+ }: {
12
+ value?: number;
13
+ min?: number;
14
+ max?: number;
15
+ step?: number;
16
+ disabled?: boolean;
17
+ }) {
18
+ return React.createElement('bds-number-input', {
19
+ value,
20
+ min,
21
+ max,
22
+ step,
23
+ disabled: disabled || undefined,
24
+ style: { display: 'block', maxInlineSize: '160px' },
25
+ });
26
+ }
27
+
28
+ const meta = {
29
+ title: 'Web Components/Interaction/Form/NumberInput',
30
+ component: BdsNumberInput,
31
+ tags: ['!stable', 'experimental'],
32
+ parameters: { layout: 'padded' },
33
+ argTypes: {
34
+ value: { control: 'number' },
35
+ min: { control: 'number' },
36
+ max: { control: 'number' },
37
+ step: { control: 'number' },
38
+ disabled: { control: 'boolean' },
39
+ },
40
+ } satisfies Meta<typeof BdsNumberInput>;
41
+
42
+ export default meta;
43
+ type Story = StoryObj<typeof meta>;
44
+
45
+ export const Default: Story = { args: { value: 0 } };
46
+ export const WithBounds: Story = { args: { value: 5, min: 0, max: 10 } };
47
+ export const WithStep: Story = { args: { value: 0, min: 0, max: 100, step: 5 } };
48
+ export const Disabled: Story = { args: { value: 42, disabled: true } };
49
+
50
+ export const AllVariants: Story = {
51
+ render: () => (
52
+ <div style={{ display: 'flex', flexDirection: 'column', gap: '16px' }}>
53
+ <div>
54
+ <p style={{ margin: '0 0 4px', fontSize: '0.75rem', color: '#888' }}>Default</p>
55
+ {React.createElement('bds-number-input', { value: 0, style: { display: 'block', maxInlineSize: '160px' } })}
56
+ </div>
57
+ <div>
58
+ <p style={{ margin: '0 0 4px', fontSize: '0.75rem', color: '#888' }}>Bounded (0–10)</p>
59
+ {React.createElement('bds-number-input', { value: 5, min: 0, max: 10, style: { display: 'block', maxInlineSize: '160px' } })}
60
+ </div>
61
+ <div>
62
+ <p style={{ margin: '0 0 4px', fontSize: '0.75rem', color: '#888' }}>Step 5</p>
63
+ {React.createElement('bds-number-input', { value: 50, min: 0, max: 100, step: 5, style: { display: 'block', maxInlineSize: '160px' } })}
64
+ </div>
65
+ <div>
66
+ <p style={{ margin: '0 0 4px', fontSize: '0.75rem', color: '#888' }}>Disabled</p>
67
+ {React.createElement('bds-number-input', { value: 7, disabled: true, style: { display: 'block', maxInlineSize: '160px' } })}
68
+ </div>
69
+ </div>
70
+ ),
71
+ };
72
+
73
+ export const Interactive: Story = {
74
+ render: () => {
75
+ const [qty, setQty] = React.useState(1);
76
+ return (
77
+ <div style={{ display: 'flex', flexDirection: 'column', gap: '8px' }}>
78
+ <p style={{ margin: '0 0 4px', fontSize: '0.875rem' }}>Quantity: {qty}</p>
79
+ {React.createElement('bds-number-input', {
80
+ value: qty,
81
+ min: 1,
82
+ max: 99,
83
+ step: 1,
84
+ style: { display: 'block', maxInlineSize: '160px' },
85
+ onInput: (e: Event) => setQty(parseInt((e.target as HTMLInputElement).value, 10) || 1),
86
+ })}
87
+ </div>
88
+ );
89
+ },
90
+ };
@@ -0,0 +1,41 @@
1
+ import { Meta, Canvas, ArgTypes } from '@storybook/blocks';
2
+ import * as Stories from './BdsRadio.stories';
3
+
4
+ <Meta of={Stories} />
5
+
6
+ # Radio
7
+
8
+ `<bds-radio>` is a form-associated radio button custom element. Use multiple elements with the same `name` to create a radio group where only one option can be selected.
9
+
10
+ ## Usage
11
+
12
+ ```html
13
+ <bds-radio name="size" value="s">Small</bds-radio>
14
+ <bds-radio name="size" value="m" checked>Medium</bds-radio>
15
+ <bds-radio name="size" value="l">Large</bds-radio>
16
+ ```
17
+
18
+ ## Attributes
19
+
20
+ | Attribute | Type | Default | Description |
21
+ |------------|-----------|---------|-------------------------------------|
22
+ | `name` | `string` | `""` | Groups radio buttons together |
23
+ | `value` | `string` | `""` | Submitted value when selected |
24
+ | `checked` | `boolean` | `false` | Whether this option is selected |
25
+ | `required` | `boolean` | `false` | Marks the field as required |
26
+ | `disabled` | `boolean` | `false` | Disables this option |
27
+
28
+ ## Slots
29
+
30
+ | Slot | Description |
31
+ |-----------|---------------|
32
+ | (default) | Label text |
33
+
34
+ ## Stories
35
+
36
+ <Canvas of={Stories.Group} />
37
+ <Canvas of={Stories.AllVariants} />
38
+
39
+ ## Controls
40
+
41
+ <ArgTypes of={Stories} />
@@ -0,0 +1,90 @@
1
+ import React from 'react';
2
+ import type { Meta, StoryObj } from '@storybook/react';
3
+ import '../../index';
4
+
5
+ function BdsRadio({
6
+ label = 'Option',
7
+ value = 'option',
8
+ checked,
9
+ disabled,
10
+ }: {
11
+ label?: string;
12
+ value?: string;
13
+ checked?: boolean;
14
+ disabled?: boolean;
15
+ }) {
16
+ return React.createElement(
17
+ 'bds-radio',
18
+ {
19
+ name: 'demo',
20
+ value,
21
+ checked: checked || undefined,
22
+ disabled: disabled || undefined,
23
+ },
24
+ label,
25
+ );
26
+ }
27
+
28
+ const meta = {
29
+ title: 'Web Components/Interaction/Form/Radio',
30
+ component: BdsRadio,
31
+ tags: ['!stable', 'experimental'],
32
+ parameters: { layout: 'padded' },
33
+ argTypes: {
34
+ checked: { control: 'boolean' },
35
+ disabled: { control: 'boolean' },
36
+ },
37
+ } satisfies Meta<typeof BdsRadio>;
38
+
39
+ export default meta;
40
+ type Story = StoryObj<typeof meta>;
41
+
42
+ export const Default: Story = { args: { label: 'Option A', value: 'a' } };
43
+ export const Checked: Story = { args: { label: 'Pre-selected', value: 'b', checked: true } };
44
+ export const Disabled: Story = { args: { label: 'Disabled option', value: 'c', disabled: true } };
45
+
46
+ export const Group: Story = {
47
+ render: () => (
48
+ <div style={{ display: 'flex', flexDirection: 'column', gap: '8px' }}>
49
+ {React.createElement('bds-radio', { name: 'size', value: 's' }, 'Small')}
50
+ {React.createElement('bds-radio', { name: 'size', value: 'm', checked: true }, 'Medium')}
51
+ {React.createElement('bds-radio', { name: 'size', value: 'l' }, 'Large')}
52
+ {React.createElement('bds-radio', { name: 'size', value: 'xl', disabled: true }, 'Extra Large (unavailable)')}
53
+ </div>
54
+ ),
55
+ };
56
+
57
+ export const AllVariants: Story = {
58
+ render: () => (
59
+ <div style={{ display: 'flex', flexDirection: 'column', gap: '12px' }}>
60
+ {React.createElement('bds-radio', { name: 'v', value: 'a' }, 'Unselected')}
61
+ {React.createElement('bds-radio', { name: 'v', value: 'b', checked: true }, 'Selected')}
62
+ {React.createElement('bds-radio', { name: 'v', value: 'c', disabled: true }, 'Disabled')}
63
+ {React.createElement('bds-radio', { name: 'v', value: 'd', checked: true, disabled: true }, 'Disabled selected')}
64
+ </div>
65
+ ),
66
+ };
67
+
68
+ export const Interactive: Story = {
69
+ render: () => {
70
+ const [value, setValue] = React.useState('m');
71
+ return (
72
+ <div style={{ display: 'flex', flexDirection: 'column', gap: '8px' }}>
73
+ <p style={{ margin: '0 0 8px', fontSize: '0.875rem' }}>Selected: {value}</p>
74
+ {(['s', 'm', 'l'] as const).map(v =>
75
+ React.createElement(
76
+ 'bds-radio',
77
+ {
78
+ key: v,
79
+ name: 'ctrl',
80
+ value: v,
81
+ checked: value === v || undefined,
82
+ onChange: () => setValue(v),
83
+ },
84
+ v === 's' ? 'Small' : v === 'm' ? 'Medium' : 'Large',
85
+ ),
86
+ )}
87
+ </div>
88
+ );
89
+ },
90
+ };
@@ -0,0 +1,42 @@
1
+ import { Meta, Canvas, ArgTypes } from '@storybook/blocks';
2
+ import * as Stories from './BdsSegmentedControl.stories';
3
+
4
+ <Meta of={Stories} />
5
+
6
+ # Segmented Control
7
+
8
+ `<bds-segmented-control>` renders a group of radio buttons styled as a unified segmented control with an animated sliding thumb. Uses a JSON `options` attribute.
9
+
10
+ ## Usage
11
+
12
+ ```html
13
+ <bds-segmented-control
14
+ name="view"
15
+ value="list"
16
+ options='[{"value":"list","label":"List"},{"value":"grid","label":"Grid"}]'
17
+ ></bds-segmented-control>
18
+ ```
19
+
20
+ ## Attributes
21
+
22
+ | Attribute | Type | Default | Description |
23
+ |------------|-----------|---------|-----------------------------------------------------|
24
+ | `name` | `string` | `""` | Form field name (also used for radio group) |
25
+ | `value` | `string` | `""` | Currently selected value |
26
+ | `options` | `string` | `"[]"` | JSON array of `{ value, label, disabled? }` objects |
27
+ | `disabled` | `boolean` | `false` | Disables all options |
28
+
29
+ ## Events
30
+
31
+ | Event | Description |
32
+ |----------|--------------------------------------|
33
+ | `change` | Fired when a new segment is selected |
34
+
35
+ ## Stories
36
+
37
+ <Canvas of={Stories.Default} />
38
+ <Canvas of={Stories.AllVariants} />
39
+
40
+ ## Controls
41
+
42
+ <ArgTypes of={Stories} />
@@ -0,0 +1,92 @@
1
+ import React from 'react';
2
+ import type { Meta, StoryObj } from '@storybook/react';
3
+ import type { SegmentedOption } from './bds-segmented-control';
4
+ import '../../index';
5
+
6
+ const VIEW_OPTIONS: SegmentedOption[] = [
7
+ { value: 'list', label: 'List' },
8
+ { value: 'grid', label: 'Grid' },
9
+ { value: 'table', label: 'Table' },
10
+ ];
11
+
12
+ const PERIOD_OPTIONS: SegmentedOption[] = [
13
+ { value: 'day', label: 'Day' },
14
+ { value: 'week', label: 'Week' },
15
+ { value: 'month', label: 'Month' },
16
+ { value: 'year', label: 'Year', disabled: true },
17
+ ];
18
+
19
+ function BdsSegmentedControl({
20
+ value = 'list',
21
+ disabled,
22
+ }: {
23
+ value?: string;
24
+ disabled?: boolean;
25
+ }) {
26
+ return React.createElement('bds-segmented-control', {
27
+ name: 'view',
28
+ value,
29
+ options: JSON.stringify(VIEW_OPTIONS),
30
+ disabled: disabled || undefined,
31
+ });
32
+ }
33
+
34
+ const meta = {
35
+ title: 'Web Components/Interaction/Form/SegmentedControl',
36
+ component: BdsSegmentedControl,
37
+ tags: ['!stable', 'experimental'],
38
+ parameters: { layout: 'padded' },
39
+ argTypes: {
40
+ disabled: { control: 'boolean' },
41
+ },
42
+ } satisfies Meta<typeof BdsSegmentedControl>;
43
+
44
+ export default meta;
45
+ type Story = StoryObj<typeof meta>;
46
+
47
+ export const Default: Story = { args: { value: 'list' } };
48
+ export const Disabled: Story = { args: { value: 'grid', disabled: true } };
49
+ export const WithDisabledOption: Story = {
50
+ render: () =>
51
+ React.createElement('bds-segmented-control', {
52
+ name: 'period',
53
+ value: 'week',
54
+ options: JSON.stringify(PERIOD_OPTIONS),
55
+ }),
56
+ };
57
+
58
+ export const AllVariants: Story = {
59
+ render: () => (
60
+ <div style={{ display: 'flex', flexDirection: 'column', gap: '24px' }}>
61
+ <div>
62
+ <p style={{ margin: '0 0 8px', fontSize: '0.75rem', color: '#888' }}>View mode</p>
63
+ {React.createElement('bds-segmented-control', { name: 'view1', value: 'grid', options: JSON.stringify(VIEW_OPTIONS) })}
64
+ </div>
65
+ <div>
66
+ <p style={{ margin: '0 0 8px', fontSize: '0.75rem', color: '#888' }}>Time period (year disabled)</p>
67
+ {React.createElement('bds-segmented-control', { name: 'period1', value: 'week', options: JSON.stringify(PERIOD_OPTIONS) })}
68
+ </div>
69
+ <div>
70
+ <p style={{ margin: '0 0 8px', fontSize: '0.75rem', color: '#888' }}>Disabled</p>
71
+ {React.createElement('bds-segmented-control', { name: 'view2', value: 'list', options: JSON.stringify(VIEW_OPTIONS), disabled: true })}
72
+ </div>
73
+ </div>
74
+ ),
75
+ };
76
+
77
+ export const Interactive: Story = {
78
+ render: () => {
79
+ const [view, setView] = React.useState('list');
80
+ return (
81
+ <div style={{ display: 'flex', flexDirection: 'column', gap: '12px' }}>
82
+ <p style={{ margin: 0, fontSize: '0.875rem' }}>Active view: {view}</p>
83
+ {React.createElement('bds-segmented-control', {
84
+ name: 'view-ctrl',
85
+ value: view,
86
+ options: JSON.stringify(VIEW_OPTIONS),
87
+ onChange: (e: Event) => setView((e.target as HTMLInputElement).value),
88
+ })}
89
+ </div>
90
+ );
91
+ },
92
+ };