@boostdev/design-system-components 1.2.4 → 1.2.6

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 (71) hide show
  1. package/AGENTS.md +42 -15
  2. package/README.md +7 -0
  3. package/dist/client.cjs +57 -52
  4. package/dist/client.css +546 -536
  5. package/dist/client.d.cts +1 -1
  6. package/dist/client.d.ts +1 -1
  7. package/dist/client.js +57 -52
  8. package/dist/index.cjs +57 -52
  9. package/dist/index.css +546 -536
  10. package/dist/index.d.cts +1 -1
  11. package/dist/index.d.ts +1 -1
  12. package/dist/index.js +57 -52
  13. package/dist/utils.cjs +30 -0
  14. package/dist/utils.d.cts +8 -0
  15. package/dist/utils.d.ts +8 -0
  16. package/dist/utils.js +5 -0
  17. package/package.json +10 -4
  18. package/src/client.ts +6 -0
  19. package/src/components/interaction/Button/Button.mdx +11 -3
  20. package/src/components/interaction/Button/Button.module.css +5 -5
  21. package/src/components/interaction/Command/Command.mdx +1 -0
  22. package/src/components/interaction/Command/Command.module.css +1 -1
  23. package/src/components/interaction/Drawer/Drawer.mdx +2 -0
  24. package/src/components/interaction/Drawer/Drawer.module.css +1 -1
  25. package/src/components/interaction/DropdownMenu/DropdownMenu.mdx +19 -0
  26. package/src/components/interaction/DropdownMenu/DropdownMenu.module.css +2 -2
  27. package/src/components/interaction/Rating/Rating.mdx +14 -0
  28. package/src/components/interaction/Rating/Rating.module.css +2 -2
  29. package/src/components/interaction/Toast/Toast.mdx +12 -4
  30. package/src/components/interaction/Toast/Toast.spec.tsx +11 -0
  31. package/src/components/interaction/Toast/Toast.tsx +11 -4
  32. package/src/components/interaction/form/Combobox/Combobox.mdx +2 -0
  33. package/src/components/interaction/form/Combobox/Combobox.module.css +3 -3
  34. package/src/components/interaction/form/FileInput/FileInput.mdx +2 -0
  35. package/src/components/interaction/form/FileInput/FileInput.module.css +2 -2
  36. package/src/components/interaction/form/NumberInput/NumberInput.mdx +4 -0
  37. package/src/components/interaction/form/NumberInput/NumberInput.module.css +3 -3
  38. package/src/components/interaction/form/SegmentedControl/SegmentedControl.mdx +1 -0
  39. package/src/components/interaction/form/SegmentedControl/SegmentedControl.module.css +1 -1
  40. package/src/components/interaction/form/Slider/Slider.mdx +4 -0
  41. package/src/components/interaction/form/Slider/Slider.module.css +8 -8
  42. package/src/components/interaction/form/Switch/Switch.mdx +3 -0
  43. package/src/components/interaction/form/Switch/Switch.module.css +1 -1
  44. package/src/components/interaction/form/Textarea/Textarea.mdx +1 -1
  45. package/src/components/interaction/form/Textarea/Textarea.module.css +1 -1
  46. package/src/components/layout/ButtonGroup/ButtonGroup.mdx +2 -0
  47. package/src/components/layout/Card/Card.mdx +8 -5
  48. package/src/components/layout/Card/Card.module.css +4 -4
  49. package/src/components/layout/SectionHeader/SectionHeader.mdx +10 -2
  50. package/src/components/layout/SectionHeader/SectionHeader.module.css +29 -17
  51. package/src/components/layout/SectionHeader/SectionHeader.spec.tsx +5 -0
  52. package/src/components/layout/SectionHeader/SectionHeader.stories.tsx +2 -1
  53. package/src/components/layout/SectionHeader/SectionHeader.tsx +1 -1
  54. package/src/components/ui/Accordion/Accordion.mdx +1 -0
  55. package/src/components/ui/Accordion/Accordion.module.css +1 -1
  56. package/src/components/ui/Alert/Alert.mdx +6 -3
  57. package/src/components/ui/Alert/Alert.module.css +1 -1
  58. package/src/components/ui/Calendar/Calendar.mdx +5 -0
  59. package/src/components/ui/Calendar/Calendar.module.css +5 -5
  60. package/src/components/ui/Carousel/Carousel.mdx +14 -0
  61. package/src/components/ui/Carousel/Carousel.module.css +1 -1
  62. package/src/components/ui/NotificationBanner/NotificationBanner.mdx +18 -0
  63. package/src/components/ui/NotificationBanner/NotificationBanner.module.css +1 -1
  64. package/src/components/ui/Pagination/Pagination.mdx +21 -0
  65. package/src/components/ui/Pagination/Pagination.module.css +5 -5
  66. package/src/components/ui/Table/Table.mdx +2 -0
  67. package/src/components/ui/Table/Table.module.css +2 -2
  68. package/src/components/ui/Tabs/Tabs.mdx +17 -0
  69. package/src/components/ui/Tabs/Tabs.module.css +3 -3
  70. package/src/css/bdc.css +1 -0
  71. package/src/utils.ts +6 -0
package/src/client.ts CHANGED
@@ -1 +1,7 @@
1
+ /**
2
+ * Client entry point — identical exports to the root, but with a 'use client'
3
+ * banner injected by tsup. Use this import path in Next.js App Router:
4
+ *
5
+ * import { Button } from '@boostdev/design-system-components/client';
6
+ */
1
7
  export * from './index';
@@ -12,6 +12,8 @@ Primary interactive element for triggering actions. Renders as `<button>` or `<a
12
12
  - Secondary or ghost actions (`ghost`)
13
13
  - Navigation that should look like an action (`href` → renders as `<a>`)
14
14
 
15
+ > **Form actions:** When using buttons in a form (submit, reset, cancel), always wrap them in a `ButtonGroup` component. This provides consistent spacing, alignment, and responsive layout for form actions. Use `variant="flow"` for step navigation or `variant="card"` for single-form submissions.
16
+
15
17
  ## When not to use
16
18
  - Navigation to another page when it reads naturally as a link — use `Link` instead
17
19
  - When the action is purely icon-based without a label — ensure `aria-label` is set
@@ -53,11 +55,17 @@ Primary interactive element for triggering actions. Renders as `<button>` or `<a
53
55
 
54
56
  <table>
55
57
  <thead>
56
- <tr><th>Variable</th><th>Description</th></tr>
58
+ <tr><th>Variable</th><th>Default</th><th>Description</th></tr>
57
59
  </thead>
58
60
  <tbody>
59
- <tr><td>`--button_color`</td><td>Identity colour — fills default, outlines ghost. Set this to re-theme.</td></tr>
60
- <tr><td>`--button_on-color`</td><td>Text/icon colour on the button. Pair with `--button_color`.</td></tr>
61
+ <tr><td>`--button_color`</td><td>`var(--bds-color_interactive)`</td><td>Identity colour — fills default, outlines outline. Set this to re-theme.</td></tr>
62
+ <tr><td>`--button_on-color`</td><td>`var(--bds-color_on-interactive)`</td><td>Text/icon colour on the button. Pair with `--button_color`.</td></tr>
63
+ <tr><td>`--button_color--on-bg`</td><td>`var(--bds-color_interactive_on-bg)`</td><td>Text-safe variant of `--button_color` for outline variant text/border</td></tr>
64
+ <tr><td>`--button_radius`</td><td>`var(--bds-border_radius--full)`</td><td>Button border radius</td></tr>
65
+ <tr><td>`--button_bg--hover`</td><td>`var(--bds-color_bg)`</td><td>Default variant background on hover</td></tr>
66
+ <tr><td>`--button_text--hover`</td><td>`var(--bds-color_interactive_on-bg)`</td><td>Default variant text colour on hover</td></tr>
67
+ <tr><td>`--button_bg--outline-hover`</td><td>`var(--button_color)`</td><td>Outline variant background on hover</td></tr>
68
+ <tr><td>`--button_text--outline-hover`</td><td>`var(--button_on-color)`</td><td>Outline variant text colour on hover</td></tr>
61
69
  </tbody>
62
70
  </table>
63
71
 
@@ -140,9 +140,9 @@
140
140
  /* Default hover: outline appears, bg becomes page surface */
141
141
  @media (hover: hover) and (pointer: fine) {
142
142
  .button.--default:hover {
143
- --button_bg: var(--bds-color_bg);
144
- --button_text: var(--bds-color_interactive_on-bg);
145
- --button_pulse-color: var(--bds-color_interactive_on-bg);
143
+ --button_bg: var(--button_bg--hover, var(--bds-color_bg));
144
+ --button_text: var(--button_text--hover, var(--bds-color_interactive_on-bg));
145
+ --button_pulse-color: var(--button_pulse-color--hover, var(--bds-color_interactive_on-bg));
146
146
  --bdc_color: currentcolor;
147
147
  }
148
148
  }
@@ -151,8 +151,8 @@
151
151
  @media (hover: hover) and (pointer: fine) {
152
152
  .button.--outline:hover,
153
153
  .button.--ghost:hover {
154
- --button_bg: var(--button_color);
155
- --button_text: var(--button_on-color);
154
+ --button_bg: var(--button_bg--outline-hover, var(--button_color));
155
+ --button_text: var(--button_text--outline-hover, var(--button_on-color));
156
156
  --bdc_color: transparent;
157
157
  }
158
158
  }
@@ -32,6 +32,7 @@ Keyboard-first command palette for searching and executing actions. Commonly tri
32
32
  <tr><td>`--command_on-color`</td><td>`var(--bds-color_on-bg)`</td><td>Text and icon colour</td></tr>
33
33
  <tr><td>`--command_shadow`</td><td>`var(--bds-shadow_xl)`</td><td>Panel box shadow</td></tr>
34
34
  <tr><td>`--command_border`</td><td>`none`</td><td>Panel border</td></tr>
35
+ <tr><td>`--command_item-bg--active`</td><td>`var(--bds-color_bg--subtle)`</td><td>Active/highlighted item background</td></tr>
35
36
  </tbody>
36
37
  </table>
37
38
 
@@ -106,7 +106,7 @@
106
106
  }
107
107
 
108
108
  .itemActive {
109
- background-color: var(--bds-color_bg--subtle);
109
+ background-color: var(--command_item-bg--active, var(--bds-color_bg--subtle));
110
110
  }
111
111
 
112
112
  .itemLabel {
@@ -38,6 +38,8 @@ Slide-in panel from the left or right edge of the viewport. Use for navigation,
38
38
  <tbody>
39
39
  <tr><td>`--drawer_color`</td><td>`var(--bds-color_bg)`</td><td>Panel background colour</td></tr>
40
40
  <tr><td>`--drawer_on-color`</td><td>`var(--bds-color_on-bg)`</td><td>Text colour</td></tr>
41
+ <tr><td>`--drawer_close-radius`</td><td>`var(--bds-border_radius--circle)`</td><td>Close button border radius</td></tr>
42
+ <tr><td>`--drawer_close-bg--hover`</td><td>`var(--bds-color_bg--subtle)`</td><td>Close button background on hover</td></tr>
41
43
  </tbody>
42
44
  </table>
43
45
 
@@ -95,7 +95,7 @@
95
95
 
96
96
  @media (hover: hover) and (pointer: fine) {
97
97
  .closeButton:hover {
98
- background-color: var(--bds-color_bg--subtle);
98
+ background-color: var(--drawer_close-bg--hover, var(--bds-color_bg--subtle));
99
99
  }
100
100
  }
101
101
 
@@ -33,6 +33,25 @@ Floating menu with a list of selectable actions, triggered by a button. Supports
33
33
 
34
34
  <ArgTypes of={Stories} />
35
35
 
36
+ ## CSS variables
37
+
38
+
39
+ <table>
40
+ <thead>
41
+ <tr><th>Variable</th><th>Default</th><th>Description</th></tr>
42
+ </thead>
43
+ <tbody>
44
+ <tr><td>`--dropdown_border`</td><td>`none`</td><td>Menu container border</td></tr>
45
+ <tr><td>`--dropdown_radius`</td><td>`var(--bdc-outline_radius)`</td><td>Menu container corner radius</td></tr>
46
+ <tr><td>`--dropdown_color`</td><td>`var(--bds-color_bg)`</td><td>Menu background colour</td></tr>
47
+ <tr><td>`--dropdown_on-color`</td><td>`var(--bds-color_on-bg)`</td><td>Menu text colour</td></tr>
48
+ <tr><td>`--dropdown_shadow`</td><td>`var(--bds-shadow_m)`</td><td>Menu box shadow</td></tr>
49
+ <tr><td>`--dropdown_item-bg--hover`</td><td>`var(--bds-color_bg--subtle)`</td><td>Menu item background on hover</td></tr>
50
+ <tr><td>`--dropdown_item-color--hover`</td><td>`var(--bds-color_interactive_on-bg)`</td><td>Menu item text colour on hover</td></tr>
51
+ </tbody>
52
+ </table>
53
+
54
+
36
55
  ## Accessibility
37
56
 
38
57
  - Implements ARIA menu pattern: `role="menu"`, `role="menuitem"`
@@ -64,8 +64,8 @@
64
64
 
65
65
  @media (hover: hover) and (pointer: fine) {
66
66
  .item:not(:disabled):hover {
67
- background-color: var(--bds-color_bg--subtle);
68
- color: var(--bds-color_interactive_on-bg);
67
+ background-color: var(--dropdown_item-bg--hover, var(--bds-color_bg--subtle));
68
+ color: var(--dropdown_item-color--hover, var(--bds-color_interactive_on-bg));
69
69
  }
70
70
  }
71
71
 
@@ -32,6 +32,20 @@ Read-only star rating display. Use to show an existing score; for user input, co
32
32
 
33
33
  <ArgTypes of={Stories} />
34
34
 
35
+ ## CSS variables
36
+
37
+
38
+ <table>
39
+ <thead>
40
+ <tr><th>Variable</th><th>Default</th><th>Description</th></tr>
41
+ </thead>
42
+ <tbody>
43
+ <tr><td>`--rating_color`</td><td>`var(--bds-color_bg)`</td><td>Empty star colour</td></tr>
44
+ <tr><td>`--rating_color--filled`</td><td>`var(--bds-color_warning)`</td><td>Filled star colour</td></tr>
45
+ </tbody>
46
+ </table>
47
+
48
+
35
49
  ## Accessibility
36
50
 
37
51
  - Renders as a `<span>` with `role="img"` and `aria-label="X out of Y stars"`
@@ -2,7 +2,7 @@
2
2
  .rating {
3
3
  display: inline-flex;
4
4
  gap: var(--bds-space_xxxs);
5
- color: var(--bds-color_bg);
5
+ color: var(--rating_color, var(--bds-color_bg));
6
6
  }
7
7
 
8
8
  .star {
@@ -11,6 +11,6 @@
11
11
  }
12
12
 
13
13
  .--filled {
14
- color: var(--bds-color_warning);
14
+ color: var(--rating_color--filled, var(--bds-color_warning));
15
15
  }
16
16
  }
@@ -17,20 +17,26 @@ Transient feedback notification that auto-dismisses after 5 seconds. Provided vi
17
17
 
18
18
  ## Setup
19
19
 
20
- Wrap your app (or layout root) once with `ToastProvider`:
20
+ Wrap your app (or layout root) once with `ToastProvider`. Since Toast uses React hooks, it requires a client boundary in Next.js:
21
21
 
22
22
  ```tsx
23
- import { ToastProvider } from '@boostdev/components';
23
+ // Next.js App Router use the /client entry inside a 'use client' boundary:
24
+ import { ToastProvider } from '@boostdev/design-system-components/client';
24
25
 
26
+ // Non-Next.js / bundler apps:
27
+ import { ToastProvider } from '@boostdev/design-system-components';
28
+ ```
29
+
30
+ ```tsx
25
31
  <ToastProvider>
26
32
  <App />
27
33
  </ToastProvider>
28
34
  ```
29
35
 
30
- Then call `showToast` anywhere inside:
36
+ Then call `showToast` anywhere inside a client component:
31
37
 
32
38
  ```tsx
33
- import { useToast } from '@boostdev/components';
39
+ import { useToast } from '@boostdev/design-system-components/client';
34
40
 
35
41
  const { showToast } = useToast();
36
42
 
@@ -39,6 +45,8 @@ showToast('Something went wrong', 'error');
39
45
  showToast('New message received', 'info');
40
46
  ```
41
47
 
48
+ > **Next.js RSC note:** The root entry (`@boostdev/design-system-components`) is safe to import in Server Components for server-safe components like `Typography` or `Badge`. Toast itself is client-only and must be used inside a `'use client'` boundary.
49
+
42
50
  ## Examples
43
51
 
44
52
  ### Success
@@ -59,4 +59,15 @@ describe('Toast', () => {
59
59
  expect(() => render(<Bad />)).toThrow('useToast must be used within a ToastProvider');
60
60
  errorSpy.mockRestore();
61
61
  });
62
+
63
+ it('shares a single lazy-initialised context between provider and consumer (RSC-safe)', () => {
64
+ // The lazy getToastContext() pattern defers createContext() until first render
65
+ // so the module can be safely evaluated in Next.js Server Components.
66
+ // This test verifies provider and consumer share the same context instance.
67
+ let captured: ReturnType<typeof useToast> | undefined;
68
+ const Capture = () => { captured = useToast(); return null; };
69
+ render(<ToastProvider><Capture /></ToastProvider>);
70
+ expect(captured).toBeDefined();
71
+ expect(typeof captured!.showToast).toBe('function');
72
+ });
62
73
  });
@@ -1,4 +1,4 @@
1
- import { useState, useEffect, createContext, useContext, ReactNode, useCallback, useMemo, useRef } from 'react';
1
+ import { useState, useEffect, createContext, useContext, ReactNode, useCallback, useMemo, useRef, Context } from 'react';
2
2
  import css from './Toast.module.css';
3
3
  import { cn } from '@boostdev/design-system-foundation';
4
4
 
@@ -14,9 +14,16 @@ interface ToastContextType {
14
14
  showToast: (message: string, variant: ToastVariant) => void;
15
15
  }
16
16
 
17
- const ToastContext = createContext<ToastContextType | undefined>(undefined);
17
+ // Lazy-initialised so the module can be evaluated in Next.js Server Components
18
+ // without calling `createContext` at import time (which crashes RSC).
19
+ let _ToastContext: Context<ToastContextType | undefined>;
20
+ function getToastContext(): Context<ToastContextType | undefined> {
21
+ _ToastContext ??= createContext<ToastContextType | undefined>(undefined);
22
+ return _ToastContext;
23
+ }
18
24
 
19
25
  export function ToastProvider({ children }: { children: ReactNode }) {
26
+ const ToastContext = getToastContext();
20
27
  const [toasts, setToasts] = useState<Toast[]>([]);
21
28
  const containerRef = useRef<HTMLDivElement>(null);
22
29
 
@@ -84,8 +91,8 @@ function ToastItem({ toast, onRemove }: { toast: Toast; onRemove: () => void })
84
91
  );
85
92
  }
86
93
 
87
- export function useToast() {
88
- const context = useContext(ToastContext);
94
+ export function useToast(): ToastContextType {
95
+ const context = useContext(getToastContext());
89
96
  if (!context) {
90
97
  throw new Error('useToast must be used within a ToastProvider');
91
98
  }
@@ -46,6 +46,8 @@ Searchable select with type-ahead filtering. Combines a text input with a dropdo
46
46
  <tr><td>`--combobox_listbox-border`</td><td>`none`</td><td>Dropdown list border</td></tr>
47
47
  <tr><td>`--combobox_listbox-radius`</td><td>`var(--bdc-outline_radius)`</td><td>Dropdown list corner radius</td></tr>
48
48
  <tr><td>`--combobox_listbox-shadow`</td><td>`var(--bds-shadow_m)`</td><td>Dropdown list box shadow</td></tr>
49
+ <tr><td>`--combobox_option-bg--highlighted`</td><td>`var(--bds-color_bg--subtle)`</td><td>Highlighted option background</td></tr>
50
+ <tr><td>`--combobox_option-color--highlighted`</td><td>`var(--bds-color_interactive_on-bg)`</td><td>Highlighted option text colour</td></tr>
49
51
  </tbody>
50
52
  </table>
51
53
 
@@ -73,7 +73,7 @@
73
73
  padding: var(--bds-space_xxs) 0;
74
74
  border: var(--combobox_listbox-border, none);
75
75
  --bdc_color: currentcolor;
76
- --bdc-outline_radius: var(--bds-border_radius--xs);
76
+ --bdc-outline_radius: var(--bds-border_radius--s);
77
77
 
78
78
  border-radius: var(--combobox_listbox-radius, var(--bdc-outline_radius));
79
79
  background-color: var(--combobox_color, var(--bds-color_bg));
@@ -92,8 +92,8 @@
92
92
  }
93
93
 
94
94
  .option.--highlighted {
95
- background-color: var(--bds-color_bg--subtle);
96
- color: var(--bds-color_interactive_on-bg);
95
+ background-color: var(--combobox_option-bg--highlighted, var(--bds-color_bg--subtle));
96
+ color: var(--combobox_option-color--highlighted, var(--bds-color_interactive_on-bg));
97
97
  }
98
98
 
99
99
  .option.--selected {
@@ -41,6 +41,8 @@ File upload input with styled trigger button, hint, and error support.
41
41
  <tbody>
42
42
  <tr><td>`--fileInput_color`</td><td>`var(--bds-color_on-bg)`</td><td>Text colour</td></tr>
43
43
  <tr><td>`--fileInput_border-color`</td><td>`currentcolor`</td><td>Drop zone border colour</td></tr>
44
+ <tr><td>`--fileInput_border-color--hover`</td><td>`var(--bds-color_interactive)`</td><td>Drop zone border colour on hover</td></tr>
45
+ <tr><td>`--fileInput_bg--hover`</td><td>`rgb(from var(--bds-color_interactive) r g b / 4%)`</td><td>Drop zone background on hover</td></tr>
44
46
  </tbody>
45
47
  </table>
46
48
 
@@ -80,8 +80,8 @@
80
80
 
81
81
  @media (hover: hover) and (pointer: fine) {
82
82
  .dropZone:not(.isDisabled):hover {
83
- border-color: var(--bds-color_interactive);
84
- background-color: rgb(from var(--bds-color_interactive) r g b / 4%);
83
+ border-color: var(--fileInput_border-color--hover, var(--bds-color_interactive));
84
+ background-color: var(--fileInput_bg--hover, rgb(from var(--bds-color_interactive) r g b / 4%));
85
85
  }
86
86
  }
87
87
  }
@@ -43,6 +43,10 @@ Numeric text input with increment/decrement stepper buttons. Enforces `min`, `ma
43
43
  <tr><td>`--numberInput_border`</td><td>`none`</td><td>Border</td></tr>
44
44
  <tr><td>`--numberInput_radius`</td><td>`var(--bdc-outline_radius)`</td><td>Corner radius</td></tr>
45
45
  <tr><td>`--numberInput_shadow`</td><td>`var(--bdc-outline_shadow)`</td><td>Box shadow</td></tr>
46
+ <tr><td>`--numberInput_stepper-color`</td><td>`var(--bds-color_interactive)`</td><td>Stepper button icon colour</td></tr>
47
+ <tr><td>`--numberInput_stepper-bg`</td><td>`var(--bds-color_bg--subtle)`</td><td>Stepper button background</td></tr>
48
+ <tr><td>`--numberInput_stepper-bg--hover`</td><td>`var(--bds-color_bg--subtle)`</td><td>Stepper button background on hover</td></tr>
49
+ <tr><td>`--numberInput_stepper-opacity--hover`</td><td>`0.7`</td><td>Stepper button opacity on hover</td></tr>
46
50
  </tbody>
47
51
  </table>
48
52
 
@@ -58,7 +58,7 @@
58
58
  justify-content: center;
59
59
  padding: var(--bds-space_xs);
60
60
  margin: 1px;
61
- background-color: var(--bds-color_bg--subtle);
61
+ background-color: var(--numberInput_stepper-bg, var(--bds-color_bg--subtle));
62
62
  color: var(--numberInput_color, var(--bds-color_on-bg));
63
63
  cursor: pointer;
64
64
  transition: var(--bds-animation_transition);
@@ -88,8 +88,8 @@
88
88
 
89
89
  @media (hover: hover) and (pointer: fine) {
90
90
  .stepper:not(:disabled):hover {
91
- background-color: var(--bds-color_bg--subtle);
92
- opacity: 0.7;
91
+ background-color: var(--numberInput_stepper-bg--hover, var(--bds-color_bg--subtle));
92
+ opacity: var(--numberInput_stepper-opacity--hover, 0.7);
93
93
  }
94
94
  }
95
95
  }
@@ -103,6 +103,7 @@ When `selectedIndex` is omitted, the component auto-detects the active item from
103
103
  | `--control_label-color` | `var(--bds-color_on-bg--subtle)` | Inactive item text colour |
104
104
  | `--control_label-color--active` | `var(--bds-color_on-interactive)` (filled) / `var(--bds-color_interactive)` (outline) | Active item text colour |
105
105
  | `--control_label-color--hover` | `var(--bds-color_on-bg)` | Hovered inactive item text colour |
106
+ | `--control_indicator-color` | `var(--bds-color_interactive)` | Outline indicator border colour (outline variant) |
106
107
 
107
108
  ## Accessibility
108
109
 
@@ -109,7 +109,7 @@
109
109
 
110
110
  .control.--variant_outline .indicator {
111
111
  display: block;
112
- box-shadow: inset 0 0 0 2px var(--bds-color_interactive);
112
+ box-shadow: inset 0 0 0 2px var(--control_indicator-color, var(--bds-color_interactive));
113
113
  }
114
114
 
115
115
  @media (hover: hover) and (pointer: fine) {
@@ -47,6 +47,10 @@ Range input for selecting a numeric value within a bounded range.
47
47
  </thead>
48
48
  <tbody>
49
49
  <tr><td>`--slider_color-active`</td><td>`var(--bdc-color_active)`</td><td>Filled track and thumb colour</td></tr>
50
+ <tr><td>`--slider_track-bg`</td><td>`var(--bds-color_bg--subtle)`</td><td>Unfilled track background</td></tr>
51
+ <tr><td>`--slider_track-radius`</td><td>`var(--bds-border_radius--full)`</td><td>Track border radius</td></tr>
52
+ <tr><td>`--slider_thumb-radius`</td><td>`var(--bds-border_radius--circle)`</td><td>Thumb border radius</td></tr>
53
+ <tr><td>`--slider_color--error`</td><td>`var(--bds-color_error)`</td><td>Track and thumb colour in error state</td></tr>
50
54
  </tbody>
51
55
  </table>
52
56
 
@@ -31,8 +31,8 @@
31
31
  to right,
32
32
  var(--slider_color-active, var(--bdc-color_active)) 0%,
33
33
  var(--slider_color-active, var(--bdc-color_active)) var(--slider_fill),
34
- var(--bds-color_bg--subtle) var(--slider_fill),
35
- var(--bds-color_bg--subtle) 100%
34
+ var(--slider_track-bg, var(--bds-color_bg--subtle)) var(--slider_fill),
35
+ var(--slider_track-bg, var(--bds-color_bg--subtle)) 100%
36
36
  );
37
37
  cursor: pointer;
38
38
  transition: var(--bds-animation_transition);
@@ -75,19 +75,19 @@
75
75
  .sliderError {
76
76
  background: linear-gradient(
77
77
  to right,
78
- var(--bds-color_error) 0%,
79
- var(--bds-color_error) var(--slider_fill),
80
- var(--bds-color_bg--subtle) var(--slider_fill),
81
- var(--bds-color_bg--subtle) 100%
78
+ var(--slider_color--error, var(--bds-color_error)) 0%,
79
+ var(--slider_color--error, var(--bds-color_error)) var(--slider_fill),
80
+ var(--slider_track-bg, var(--bds-color_bg--subtle)) var(--slider_fill),
81
+ var(--slider_track-bg, var(--bds-color_bg--subtle)) 100%
82
82
  );
83
83
  }
84
84
 
85
85
  .sliderError::-webkit-slider-thumb {
86
- background-color: var(--bds-color_error);
86
+ background-color: var(--slider_color--error, var(--bds-color_error));
87
87
  }
88
88
 
89
89
  .sliderError::-moz-range-thumb {
90
- background-color: var(--bds-color_error);
90
+ background-color: var(--slider_color--error, var(--bds-color_error));
91
91
  }
92
92
 
93
93
  @media (prefers-reduced-motion: reduce) {
@@ -56,6 +56,9 @@ Toggle control for binary settings that take immediate effect — without requir
56
56
  <tr><td>`--switch_thumb-bg`</td><td>`var(--bds-color_grey)`</td><td>Thumb colour when off (also track outline)</td></tr>
57
57
  <tr><td>`--switch_track-bg--active`</td><td>`var(--bdc-color_active--subtle)`</td><td>Track background when on</td></tr>
58
58
  <tr><td>`--switch_thumb-bg--active`</td><td>`var(--bdc-color_active--strong)`</td><td>Thumb colour when on (also track outline)</td></tr>
59
+ <tr><td>`--switch_track-radius`</td><td>`var(--bds-border_radius--full)`</td><td>Track border radius</td></tr>
60
+ <tr><td>`--switch_thumb-radius`</td><td>`var(--bds-border_radius--circle)`</td><td>Thumb border radius</td></tr>
61
+ <tr><td>`--switch_border-color--error`</td><td>`var(--bds-color_error)`</td><td>Track outline colour in error state</td></tr>
59
62
  </tbody>
60
63
  </table>
61
64
 
@@ -78,7 +78,7 @@
78
78
 
79
79
  /* Error state — declared before checked/focus so higher-specificity states can override */
80
80
  .switch.switchError + .track {
81
- --bdc_color: var(--bds-color_error);
81
+ --bdc_color: var(--switch_border-color--error, var(--bds-color_error));
82
82
  }
83
83
 
84
84
  /* Checked state via CSS sibling combinator */
@@ -45,7 +45,7 @@ Multi-line text input with label, hint, and error support.
45
45
  <tr><td>`--textarea_color_bg`</td><td>`var(--bds-color_bg)`</td><td>Background colour</td></tr>
46
46
  <tr><td>`--textarea_color`</td><td>`var(--bds-color_on-bg)`</td><td>Text colour</td></tr>
47
47
  <tr><td>`--textarea_border`</td><td>`none`</td><td>Border</td></tr>
48
- <tr><td>`--textarea_radius`</td><td>`var(--bdc-outline_radius)`</td><td>Corner radius</td></tr>
48
+ <tr><td>`--textarea_radius`</td><td>`var(--bdc-outline_radius--l)` (1.5em)</td><td>Corner radius</td></tr>
49
49
  <tr><td>`--textarea_shadow`</td><td>`var(--bdc-outline_shadow)`</td><td>Box shadow</td></tr>
50
50
  </tbody>
51
51
  </table>
@@ -11,7 +11,7 @@
11
11
  padding: var(--bds-space_s);
12
12
  border: var(--textarea_border, none);
13
13
  --bdc_color: currentcolor;
14
- --bdc-outline_radius: var(--bds-border_radius--xs);
14
+ --bdc-outline_radius: var(--bdc-outline_radius--l);
15
15
 
16
16
  border-radius: var(--textarea_radius, var(--bdc-outline_radius));
17
17
  box-shadow: inset 0 0 0 var(--bdc-outline_width) var(--bdc_color), var(--textarea_shadow, var(--bdc-outline_shadow));
@@ -7,6 +7,8 @@ import * as Stories from './ButtonGroup.stories';
7
7
 
8
8
  Layout wrapper that arranges `Button` children according to a contextual variant. Handles spacing, alignment, and direction.
9
9
 
10
+ > **Recommended:** Always wrap buttons in a `ButtonGroup` when they appear inside a form. This ensures consistent spacing and alignment for form actions like submit, cancel, and navigation.
11
+
10
12
  ## Variants
11
13
 
12
14
 
@@ -40,13 +40,16 @@ Contained surface for grouping related content. Three visual variants provide di
40
40
 
41
41
  <table>
42
42
  <thead>
43
- <tr><th>Variable</th><th>Description</th></tr>
43
+ <tr><th>Variable</th><th>Default</th><th>Description</th></tr>
44
44
  </thead>
45
45
  <tbody>
46
- <tr><td>`--card_bg`</td><td>Card background colour</td></tr>
47
- <tr><td>`--card_on-bg`</td><td>Card text colour</td></tr>
48
- <tr><td>`--card_border-color`</td><td>Border colour (outlined variant)</td></tr>
49
- <tr><td>`--card_shadow`</td><td>Box shadow (elevated variant)</td></tr>
46
+ <tr><td>`--card_color`</td><td>`var(--bds-color_bg)`</td><td>Card background colour</td></tr>
47
+ <tr><td>`--card_on-color`</td><td>`var(--bds-color_on-bg)`</td><td>Card text colour</td></tr>
48
+ <tr><td>`--card_border`</td><td>`none`</td><td>Border (outlined variant)</td></tr>
49
+ <tr><td>`--card_shadow--clickable-hover`</td><td>`var(--bds-shadow_xl)`</td><td>Box shadow on hover for clickable cards</td></tr>
50
+ <tr><td>`--card_shadow--default-hover`</td><td>`var(--bds-shadow_m)`</td><td>Box shadow on hover for default variant</td></tr>
51
+ <tr><td>`--card_shadow--elevated-hover`</td><td>`var(--bds-shadow_2xl)`</td><td>Box shadow on hover for elevated variant</td></tr>
52
+ <tr><td>`--card_shadow--outlined-hover`</td><td>`var(--bds-shadow_s)`</td><td>Box shadow on hover for outlined variant</td></tr>
50
53
  </tbody>
51
54
  </table>
52
55
 
@@ -67,19 +67,19 @@
67
67
  @media (hover: hover) and (pointer: fine) {
68
68
  .card.--clickable:hover {
69
69
  transform: translateY(-2px);
70
- box-shadow: var(--bds-shadow_xl);
70
+ box-shadow: var(--card_shadow--clickable-hover, var(--bds-shadow_xl));
71
71
  }
72
72
 
73
73
  .card.--default:hover {
74
- box-shadow: var(--bds-shadow_m);
74
+ box-shadow: var(--card_shadow--default-hover, var(--bds-shadow_m));
75
75
  }
76
76
 
77
77
  .card.--elevated:hover {
78
- box-shadow: var(--bds-shadow_2xl);
78
+ box-shadow: var(--card_shadow--elevated-hover, var(--bds-shadow_2xl));
79
79
  }
80
80
 
81
81
  .card.--outlined:hover {
82
- box-shadow: var(--bds-shadow_s);
82
+ box-shadow: var(--card_shadow--outlined-hover, var(--bds-shadow_s));
83
83
  }
84
84
  }
85
85
  }
@@ -19,12 +19,15 @@ Heading block with optional subtitle for introducing a content section.
19
19
  ### Without subtitle
20
20
  <Canvas of={Stories.WithoutSubtitle} />
21
21
 
22
- ### Large
23
- <Canvas of={Stories.Large} />
22
+ ### Extra Small
23
+ <Canvas of={Stories.ExtraSmall} />
24
24
 
25
25
  ### Small
26
26
  <Canvas of={Stories.Small} />
27
27
 
28
+ ### Large
29
+ <Canvas of={Stories.Large} />
30
+
28
31
  ### Centered
29
32
  <Canvas of={Stories.Centered} />
30
33
 
@@ -40,7 +43,12 @@ Heading block with optional subtitle for introducing a content section.
40
43
  <tr><th>Variable</th><th>Default</th><th>Description</th></tr>
41
44
  </thead>
42
45
  <tbody>
46
+ <tr><td>`--sectionHeader-title-color`</td><td>`var(--bds-color_on-bg)`</td><td>Title text colour</td></tr>
47
+ <tr><td>`--sectionHeader_title-size`</td><td>varies by `size` prop</td><td>Title font-size (overrides the variant default)</td></tr>
48
+ <tr><td>`--sectionHeader_title-line-height`</td><td>varies by `size` prop</td><td>Title line-height</td></tr>
49
+ <tr><td>`--sectionHeader_title-weight`</td><td>`var(--bds-font_weight--bold)`</td><td>Title font-weight</td></tr>
43
50
  <tr><td>`--sectionHeader_subtitle-color`</td><td>`var(--bds-color_grey--strong)`</td><td>Subtitle text colour</td></tr>
51
+ <tr><td>`--sectionHeader_subtitle-size`</td><td>varies by `size` prop</td><td>Subtitle font-size</td></tr>
44
52
  </tbody>
45
53
  </table>
46
54