@boostdev/design-system-components 1.2.0 → 1.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (126) hide show
  1. package/AGENTS.md +25 -4
  2. package/dist/client.cjs +58 -54
  3. package/dist/client.css +503 -525
  4. package/dist/client.js +58 -54
  5. package/dist/index.cjs +58 -54
  6. package/dist/index.css +503 -525
  7. package/dist/index.js +58 -54
  8. package/dist/web-components/{chunk-6MH5UWUD.js → chunk-2FGATTGT.js} +5 -0
  9. package/dist/web-components/{chunk-5IPHEONG.js → chunk-6I2DBFQ7.js} +1 -0
  10. package/dist/web-components/{chunk-DI46Q2EA.js → chunk-OCODKRVZ.js} +57 -82
  11. package/dist/web-components/index.d.ts +571 -1
  12. package/dist/web-components/index.js +1501 -4
  13. package/dist/web-components/interaction/bds-collapsible.js +1 -1
  14. package/dist/web-components/interaction/bds-drawer.js +1 -1
  15. package/dist/web-components/interaction/form/bds-segmented-control.js +1 -1
  16. package/package.json +1 -1
  17. package/src/components/interaction/Drawer/Drawer.module.css +37 -62
  18. package/src/components/interaction/Drawer/Drawer.tsx +21 -17
  19. package/src/components/interaction/form/SegmentedControl/SegmentedControl.mdx +8 -4
  20. package/src/components/interaction/form/SegmentedControl/SegmentedControl.module.css +13 -6
  21. package/src/stories/Introduction.mdx +2 -1
  22. package/src/web-components/index.ts +12 -0
  23. package/src/web-components/interaction/BdsAccordion.mdx +80 -28
  24. package/src/web-components/interaction/BdsAccordion.stories.tsx +67 -58
  25. package/src/web-components/interaction/BdsCollapsible.mdx +93 -23
  26. package/src/web-components/interaction/BdsCollapsible.stories.tsx +29 -48
  27. package/src/web-components/interaction/BdsDialog.mdx +88 -27
  28. package/src/web-components/interaction/BdsDialog.stories.tsx +129 -47
  29. package/src/web-components/interaction/BdsDrawer.mdx +85 -27
  30. package/src/web-components/interaction/BdsDrawer.stories.tsx +161 -31
  31. package/src/web-components/interaction/BdsDropdownMenu.mdx +108 -0
  32. package/src/web-components/interaction/BdsDropdownMenu.stories.tsx +91 -0
  33. package/src/web-components/interaction/BdsSkipLink.mdx +72 -16
  34. package/src/web-components/interaction/BdsSkipLink.stories.tsx +47 -34
  35. package/src/web-components/interaction/BdsTabs.mdx +97 -27
  36. package/src/web-components/interaction/BdsTabs.stories.tsx +69 -55
  37. package/src/web-components/interaction/BdsTooltip.mdx +84 -18
  38. package/src/web-components/interaction/BdsTooltip.stories.tsx +49 -30
  39. package/src/web-components/interaction/bds-collapsible.ts +1 -0
  40. package/src/web-components/interaction/bds-drawer.ts +59 -82
  41. package/src/web-components/interaction/bds-dropdown-menu-item.ts +124 -0
  42. package/src/web-components/interaction/bds-dropdown-menu.spec.ts +102 -0
  43. package/src/web-components/interaction/bds-dropdown-menu.ts +200 -0
  44. package/src/web-components/interaction/form/BdsCheckbox.mdx +57 -20
  45. package/src/web-components/interaction/form/BdsCheckbox.stories.tsx +35 -36
  46. package/src/web-components/interaction/form/BdsCheckboxGroup.mdx +70 -0
  47. package/src/web-components/interaction/form/BdsCheckboxGroup.stories.tsx +81 -0
  48. package/src/web-components/interaction/form/BdsCombobox.mdx +52 -33
  49. package/src/web-components/interaction/form/BdsCombobox.stories.tsx +55 -53
  50. package/src/web-components/interaction/form/BdsFileInput.mdx +59 -24
  51. package/src/web-components/interaction/form/BdsFileInput.stories.tsx +38 -53
  52. package/src/web-components/interaction/form/BdsFormInput.mdx +98 -0
  53. package/src/web-components/interaction/form/BdsFormInput.stories.tsx +139 -0
  54. package/src/web-components/interaction/form/BdsNumberInput.mdx +51 -22
  55. package/src/web-components/interaction/form/BdsNumberInput.stories.tsx +24 -46
  56. package/src/web-components/interaction/form/BdsRadio.mdx +53 -22
  57. package/src/web-components/interaction/form/BdsRadio.stories.tsx +19 -51
  58. package/src/web-components/interaction/form/BdsRadioGroup.mdx +73 -0
  59. package/src/web-components/interaction/form/BdsRadioGroup.stories.tsx +88 -0
  60. package/src/web-components/interaction/form/BdsSegmentedControl.mdx +76 -23
  61. package/src/web-components/interaction/form/BdsSegmentedControl.stories.tsx +64 -54
  62. package/src/web-components/interaction/form/BdsSelect.mdx +59 -21
  63. package/src/web-components/interaction/form/BdsSelect.stories.tsx +47 -56
  64. package/src/web-components/interaction/form/BdsSlider.mdx +55 -27
  65. package/src/web-components/interaction/form/BdsSlider.stories.tsx +23 -44
  66. package/src/web-components/interaction/form/BdsSwitch.mdx +53 -20
  67. package/src/web-components/interaction/form/BdsSwitch.stories.tsx +22 -37
  68. package/src/web-components/interaction/form/BdsTextarea.mdx +54 -22
  69. package/src/web-components/interaction/form/BdsTextarea.stories.tsx +35 -44
  70. package/src/web-components/interaction/form/bds-checkbox-group.spec.ts +55 -0
  71. package/src/web-components/interaction/form/bds-checkbox-group.ts +117 -0
  72. package/src/web-components/interaction/form/bds-form-input.spec.ts +83 -0
  73. package/src/web-components/interaction/form/bds-form-input.ts +268 -0
  74. package/src/web-components/interaction/form/bds-radio-group.spec.ts +62 -0
  75. package/src/web-components/interaction/form/bds-radio-group.ts +142 -0
  76. package/src/web-components/interaction/form/bds-segmented-control.ts +5 -0
  77. package/src/web-components/ui/BdsAvatar.mdx +29 -20
  78. package/src/web-components/ui/BdsAvatar.stories.tsx +14 -28
  79. package/src/web-components/ui/BdsBreadcrumb.mdx +22 -19
  80. package/src/web-components/ui/BdsBreadcrumb.stories.tsx +11 -21
  81. package/src/web-components/ui/BdsButtonGroup.mdx +69 -0
  82. package/src/web-components/ui/BdsButtonGroup.stories.tsx +66 -0
  83. package/src/web-components/ui/BdsCalendar.mdx +93 -0
  84. package/src/web-components/ui/BdsCalendar.stories.tsx +63 -0
  85. package/src/web-components/ui/BdsCard.mdx +30 -25
  86. package/src/web-components/ui/BdsCard.stories.tsx +19 -42
  87. package/src/web-components/ui/BdsCarousel.mdx +83 -0
  88. package/src/web-components/ui/BdsCarousel.stories.tsx +96 -0
  89. package/src/web-components/ui/BdsDescriptionList.mdx +13 -16
  90. package/src/web-components/ui/BdsDescriptionList.stories.tsx +34 -49
  91. package/src/web-components/ui/BdsIconWrapper.mdx +20 -20
  92. package/src/web-components/ui/BdsIconWrapper.stories.tsx +46 -41
  93. package/src/web-components/ui/BdsLink.mdx +21 -17
  94. package/src/web-components/ui/BdsLink.stories.tsx +19 -20
  95. package/src/web-components/ui/BdsLoading.mdx +9 -13
  96. package/src/web-components/ui/BdsLoading.stories.tsx +8 -10
  97. package/src/web-components/ui/BdsNotificationBanner.mdx +32 -37
  98. package/src/web-components/ui/BdsNotificationBanner.stories.tsx +38 -47
  99. package/src/web-components/ui/BdsPagination.mdx +74 -0
  100. package/src/web-components/ui/BdsPagination.stories.tsx +36 -0
  101. package/src/web-components/ui/BdsProgress.mdx +24 -17
  102. package/src/web-components/ui/BdsProgress.stories.tsx +55 -29
  103. package/src/web-components/ui/BdsProgressCircle.mdx +24 -18
  104. package/src/web-components/ui/BdsProgressCircle.stories.tsx +17 -29
  105. package/src/web-components/ui/BdsRating.mdx +22 -22
  106. package/src/web-components/ui/BdsRating.stories.tsx +19 -13
  107. package/src/web-components/ui/BdsSectionHeader.mdx +31 -28
  108. package/src/web-components/ui/BdsSectionHeader.stories.tsx +21 -23
  109. package/src/web-components/ui/BdsSeparator.mdx +22 -8
  110. package/src/web-components/ui/BdsSeparator.stories.tsx +27 -19
  111. package/src/web-components/ui/BdsSkeleton.mdx +20 -26
  112. package/src/web-components/ui/BdsSkeleton.stories.tsx +23 -23
  113. package/src/web-components/ui/BdsTable.mdx +81 -0
  114. package/src/web-components/ui/BdsTable.stories.tsx +83 -0
  115. package/src/web-components/ui/BdsTypography.mdx +20 -29
  116. package/src/web-components/ui/BdsTypography.stories.tsx +19 -18
  117. package/src/web-components/ui/bds-button-group.spec.ts +40 -0
  118. package/src/web-components/ui/bds-button-group.ts +78 -0
  119. package/src/web-components/ui/bds-calendar.spec.ts +91 -0
  120. package/src/web-components/ui/bds-calendar.ts +427 -0
  121. package/src/web-components/ui/bds-carousel.spec.ts +64 -0
  122. package/src/web-components/ui/bds-carousel.ts +296 -0
  123. package/src/web-components/ui/bds-pagination.spec.ts +67 -0
  124. package/src/web-components/ui/bds-pagination.ts +197 -0
  125. package/src/web-components/ui/bds-table.spec.ts +45 -0
  126. package/src/web-components/ui/bds-table.ts +96 -0
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  BdsCollapsible
3
- } from "../chunk-5IPHEONG.js";
3
+ } from "../chunk-6I2DBFQ7.js";
4
4
  import "../chunk-LGEZYFUU.js";
5
5
  export {
6
6
  BdsCollapsible
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  BdsDrawer
3
- } from "../chunk-DI46Q2EA.js";
3
+ } from "../chunk-OCODKRVZ.js";
4
4
  import "../chunk-LGEZYFUU.js";
5
5
  export {
6
6
  BdsDrawer
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  BdsSegmentedControl
3
- } from "../../chunk-6MH5UWUD.js";
3
+ } from "../../chunk-2FGATTGT.js";
4
4
  import "../../chunk-LGEZYFUU.js";
5
5
  export {
6
6
  BdsSegmentedControl
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@boostdev/design-system-components",
3
- "version": "1.2.0",
3
+ "version": "1.2.1",
4
4
  "description": "BoostDev React component library: accessible, token-driven components built on @boostdev/design-system-foundation",
5
5
  "keywords": [
6
6
  "React",
@@ -1,84 +1,65 @@
1
1
  @layer component {
2
2
  .drawer {
3
3
  position: fixed;
4
- inset: 0;
4
+ inset-block: 0;
5
+ inset-inline: auto 0;
6
+ inline-size: min(28rem, 90vw);
7
+ max-inline-size: 100vw;
8
+ block-size: 100dvh;
9
+ max-block-size: 100dvh;
5
10
  margin: 0;
6
11
  padding: 0;
7
- inline-size: 100%;
8
- max-inline-size: 100%;
9
- block-size: 100%;
10
- max-block-size: 100%;
11
- border: none;
12
- background: transparent;
13
- overflow: hidden;
14
- transition:
15
- display var(--bds-animation_transition-duration) allow-discrete,
16
- overlay var(--bds-animation_transition-duration) allow-discrete;
17
- }
18
-
19
- .drawer::backdrop {
20
- background-color: var(--color_backdrop, rgb(0 0 0 / 50%));
21
- backdrop-filter: blur(3px);
22
- transition:
23
- display var(--bds-animation_transition-duration) allow-discrete,
24
- overlay var(--bds-animation_transition-duration) allow-discrete,
25
- background-color var(--bds-animation_transition-duration) var(--bds-animation_easing),
26
- backdrop-filter var(--bds-animation_transition-duration) var(--bds-animation_easing);
27
- }
28
-
29
- @starting-style {
30
- .drawer[open]::backdrop {
31
- background-color: transparent;
32
- backdrop-filter: blur(0);
33
- }
34
- }
35
-
36
- .panel {
37
- position: absolute;
38
- inset-block: 0;
39
- inset-inline: auto;
40
12
  display: flex;
41
13
  flex-direction: column;
42
- inline-size: min(28rem, 90vw);
43
- block-size: 100%;
44
14
  background-color: var(--drawer_color, var(--bds-color_bg));
45
15
  color: var(--drawer_on-color, var(--bds-color_on-bg));
16
+ border: none;
46
17
  box-shadow: var(--bds-shadow_xl);
47
18
  overflow: hidden;
48
19
  translate: 100% 0;
49
- transition: translate var(--bds-animation_transition-duration) var(--bds-animation_easing);
50
- }
51
-
52
- .--side_right .panel {
53
- inset-inline-end: 0;
54
- translate: 100% 0;
20
+ transition:
21
+ translate var(--bds-animation_transition-duration) var(--bds-animation_easing),
22
+ display var(--bds-animation_transition-duration) var(--bds-animation_easing) allow-discrete,
23
+ overlay var(--bds-animation_transition-duration) var(--bds-animation_easing) allow-discrete;
55
24
  }
56
25
 
57
- .--side_left .panel {
58
- inset-inline-start: 0;
26
+ .--side_left.drawer {
27
+ inset-inline: 0 auto;
59
28
  translate: -100% 0;
60
29
  }
61
30
 
62
- .drawer[open] .panel {
31
+ .drawer[open] {
63
32
  translate: 0 0;
64
33
  }
65
34
 
66
- .drawer[open].--side_right .panel {
67
- animation: bdc-drawer-slide-right var(--bds-animation_transition-duration) var(--bds-animation_easing) both;
35
+ @starting-style {
36
+ .drawer[open] {
37
+ translate: 100% 0;
38
+ }
39
+
40
+ .--side_left.drawer[open] {
41
+ translate: -100% 0;
42
+ }
68
43
  }
69
44
 
70
- .drawer[open].--side_left .panel {
71
- animation: bdc-drawer-slide-left var(--bds-animation_transition-duration) var(--bds-animation_easing) both;
45
+ .drawer::backdrop {
46
+ background-color: var(--color_backdrop, rgb(0 0 0 / 50%));
47
+ backdrop-filter: blur(3px);
48
+ opacity: 0;
49
+ transition:
50
+ opacity var(--bds-animation_transition-duration) var(--bds-animation_easing),
51
+ display var(--bds-animation_transition-duration) var(--bds-animation_easing) allow-discrete,
52
+ overlay var(--bds-animation_transition-duration) var(--bds-animation_easing) allow-discrete;
72
53
  }
73
54
 
74
- @keyframes bdc-drawer-slide-right {
75
- from { translate: 100% 0; }
76
- to { translate: 0 0; }
55
+ .drawer[open]::backdrop {
56
+ opacity: 1;
77
57
  }
78
58
 
79
- @keyframes bdc-drawer-slide-left {
80
- from { translate: -100% 0; }
81
- to { translate: 0 0; }
59
+ @starting-style {
60
+ .drawer[open]::backdrop {
61
+ opacity: 0;
62
+ }
82
63
  }
83
64
 
84
65
  .header {
@@ -128,14 +109,8 @@
128
109
 
129
110
  @media (prefers-reduced-motion: reduce) {
130
111
  .drawer,
131
- .drawer::backdrop,
132
- .panel {
112
+ .drawer::backdrop {
133
113
  transition: none;
134
114
  }
135
-
136
- .drawer[open].--side_right .panel,
137
- .drawer[open].--side_left .panel {
138
- animation: none;
139
- }
140
115
  }
141
116
  }
@@ -75,7 +75,13 @@ export function Drawer({
75
75
 
76
76
  // Close on backdrop click
77
77
  const handleClick = (e: React.MouseEvent<HTMLDialogElement>) => {
78
- if (e.target === dialogRef.current) onClose();
78
+ const dialog = dialogRef.current;
79
+ if (!dialog) return;
80
+ const rect = dialog.getBoundingClientRect();
81
+ const outside =
82
+ e.clientX < rect.left || e.clientX > rect.right ||
83
+ e.clientY < rect.top || e.clientY > rect.bottom;
84
+ if (outside) onClose();
79
85
  };
80
86
 
81
87
  // Close on Escape (dialog handles it natively, but we sync state)
@@ -94,23 +100,21 @@ export function Drawer({
94
100
  onClick={handleClick}
95
101
  onCancel={handleCancel}
96
102
  >
97
- <div className={css.panel}>
98
- <div className={css.header}>
99
- {!!title && title}
100
- <button
101
- type="button"
102
- className={css.closeButton}
103
- commandfor={id}
104
- command="close"
105
- aria-label="Close drawer"
106
- >
107
- <svg aria-hidden="true" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
108
- <path strokeLinecap="round" strokeLinejoin="round" d="M18 6L6 18M6 6l12 12" />
109
- </svg>
110
- </button>
111
- </div>
112
- <div className={css.body}>{children}</div>
103
+ <div className={css.header}>
104
+ {!!title && title}
105
+ <button
106
+ type="button"
107
+ className={css.closeButton}
108
+ commandfor={id}
109
+ command="close"
110
+ aria-label="Close drawer"
111
+ >
112
+ <svg aria-hidden="true" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
113
+ <path strokeLinecap="round" strokeLinejoin="round" d="M18 6L6 18M6 6l12 12" />
114
+ </svg>
115
+ </button>
113
116
  </div>
117
+ <div className={css.body}>{children}</div>
114
118
  </dialog>
115
119
  );
116
120
  }
@@ -87,15 +87,19 @@ When `selectedIndex` is omitted, the component auto-detects the active item from
87
87
 
88
88
  | Variant | Description |
89
89
  |---------|-------------|
90
- | `outline` (default) | Transparent track, inset-border indicator slides to the active item |
91
- | `filled` | Coloured track, filled thumb slides behind the active item |
90
+ | `outline` (default) | Subtle track background; active item has a `bg` background with inset-border indicator; inactive items are transparent |
91
+ | `filled` | Subtle track background; coloured filled thumb slides behind the active item |
92
92
 
93
93
  ## CSS variables
94
94
 
95
95
  | Variable | Default | Description |
96
96
  |----------|---------|-------------|
97
- | `--control_track-bg` | `var(--bds-color_bg--subtle)` (filled) / `transparent` (outline) | Track background |
98
- | `--control_thumb-bg` | `var(--bds-color_interactive)` | Filled thumb colour |
97
+ | `--control_track-bg` | `var(--bds-color_bg--subtle)` | Track background colour (both variants) |
98
+ | `--control_item-bg` | `transparent` | Inactive item background (outline variant) |
99
+ | `--control_item-bg--active` | `var(--bds-color_bg)` | Active item background (outline variant) |
100
+ | `--control_radius` | `var(--bds-border_radius--m)` | Border radius of the outer track |
101
+ | `--control_thumb-bg` | `var(--bds-color_interactive)` | Filled thumb colour (filled variant) |
102
+ | `--control_thumb-radius` | `var(--bds-border_radius--s)` | Border radius of the thumb, indicator, and item focus ring |
99
103
  | `--control_label-color` | `var(--bds-color_on-bg--subtle)` | Inactive item text colour |
100
104
  | `--control_label-color--active` | `var(--bds-color_on-interactive)` (filled) / `var(--bds-color_interactive)` (outline) | Active item text colour |
101
105
  | `--control_label-color--hover` | `var(--bds-color_on-bg)` | Hovered inactive item text colour |
@@ -6,7 +6,7 @@
6
6
  grid-auto-columns: 1fr;
7
7
  padding: var(--bds-space_xxxs);
8
8
  background-color: var(--control_track-bg, var(--bds-color_bg--subtle));
9
- border-radius: var(--bds-border_radius--m);
9
+ border-radius: var(--control_radius, var(--bds-border_radius--m));
10
10
  gap: 0;
11
11
  }
12
12
 
@@ -16,7 +16,7 @@
16
16
  inset-block: var(--bds-space_xxxs);
17
17
  inset-inline-start: var(--bds-space_xxxs);
18
18
  inline-size: calc((100% - 2 * var(--bds-space_xxxs)) / var(--control_count, 1));
19
- border-radius: var(--bds-border_radius--s);
19
+ border-radius: var(--control_thumb-radius, var(--bds-border_radius--s));
20
20
  background-color: var(--control_thumb-bg, var(--bds-color_interactive));
21
21
  box-shadow: var(--bds-shadow_s);
22
22
  pointer-events: none;
@@ -30,7 +30,7 @@
30
30
  inset-block: var(--bds-space_xxxs);
31
31
  inset-inline-start: var(--bds-space_xxxs);
32
32
  inline-size: calc((100% - 2 * var(--bds-space_xxxs)) / var(--control_count, 1));
33
- border-radius: var(--bds-border_radius--s);
33
+ border-radius: var(--control_thumb-radius, var(--bds-border_radius--s));
34
34
  pointer-events: none;
35
35
  z-index: 2;
36
36
  display: none;
@@ -46,7 +46,7 @@
46
46
  align-items: center;
47
47
  justify-content: center;
48
48
  cursor: pointer;
49
- border-radius: var(--bds-border_radius--s);
49
+ border-radius: var(--control_thumb-radius, var(--bds-border_radius--s));
50
50
  padding: var(--bds-space_xs) var(--bds-space_m);
51
51
  font-size: var(--bds-font_size--body);
52
52
  font-family: var(--bds-font_family--body);
@@ -66,7 +66,7 @@
66
66
  .item:focus-visible {
67
67
  outline: var(--bds-outline_default);
68
68
  outline-offset: calc(var(--bds-outline_offset) * -1);
69
- border-radius: var(--bds-border_radius--s);
69
+ border-radius: var(--control_thumb-radius, var(--bds-border_radius--s));
70
70
  }
71
71
 
72
72
  .item.--active {
@@ -92,7 +92,6 @@
92
92
 
93
93
  /* Outline variant — no thumb, sliding inset-border indicator, interactive active color */
94
94
  .control.--variant_outline {
95
- background-color: var(--control_track-bg, transparent);
96
95
  --control_label-color--active: var(--bds-color_interactive);
97
96
  }
98
97
 
@@ -100,6 +99,14 @@
100
99
  display: none;
101
100
  }
102
101
 
102
+ .control.--variant_outline .item {
103
+ background-color: var(--control_item-bg, transparent);
104
+ }
105
+
106
+ .control.--variant_outline .item.--active {
107
+ background-color: var(--control_item-bg--active, var(--bds-color_bg));
108
+ }
109
+
103
110
  .control.--variant_outline .indicator {
104
111
  display: block;
105
112
  box-shadow: inset 0 0 0 2px var(--bds-color_interactive);
@@ -5,6 +5,7 @@ import foundationPackageJson from '../../node_modules/@boostdev/design-system-fo
5
5
  import './Introduction.css';
6
6
  import {ButtonGroup} from "../components/layout/ButtonGroup/index.ts";
7
7
  import {Card} from "../components/layout/Card/index.ts";
8
+ import logo from '../static/logo.svg';
8
9
 
9
10
  <Meta title="Introduction"/>
10
11
 
@@ -12,7 +13,7 @@ import {Card} from "../components/layout/Card/index.ts";
12
13
 
13
14
  <div>
14
15
  <div>
15
- <img src="../../src/static/logo.svg" alt="BoostDev logo" width={200}/>
16
+ <img src={logo} alt="BoostDev logo" width={200}/>
16
17
  <div className="title">Design System Foundation {foundationPackageJson.version} &<br/> Components {componentsPackageJson.version}</div>
17
18
  </div>
18
19
  <div className="main-description">
@@ -57,3 +57,15 @@ export { BdsIconWrapper } from './ui/bds-icon-wrapper';
57
57
  export { BdsDescriptionList } from './ui/bds-description-list';
58
58
  export { BdsBreadcrumb } from './ui/bds-breadcrumb';
59
59
  export { BdsLink } from './ui/bds-link';
60
+
61
+ // Phase 8 — complete parity with React library
62
+ export { BdsButtonGroup } from './ui/bds-button-group';
63
+ export { BdsTable } from './ui/bds-table';
64
+ export { BdsPagination } from './ui/bds-pagination';
65
+ export { BdsCheckboxGroup } from './interaction/form/bds-checkbox-group';
66
+ export { BdsRadioGroup } from './interaction/form/bds-radio-group';
67
+ export { BdsFormInput } from './interaction/form/bds-form-input';
68
+ export { BdsCarousel } from './ui/bds-carousel';
69
+ export { BdsCalendar } from './ui/bds-calendar';
70
+ export { BdsDropdownMenu } from './interaction/bds-dropdown-menu';
71
+ export { BdsDropdownMenuItem } from './interaction/bds-dropdown-menu-item';
@@ -3,49 +3,101 @@ import * as Stories from './BdsAccordion.stories';
3
3
 
4
4
  <Meta of={Stories} />
5
5
 
6
- # Accordion
6
+ # &lt;bds-accordion&gt;
7
7
 
8
- `<bds-accordion>` is a container for one or more `<bds-accordion-item>` elements. Each item shows a header and reveals its body on click. By default only one item can be open at a time; set `allow-multiple` to allow several.
8
+ Framework-agnostic Accordion custom element. Coordinates open/closed state across `<bds-accordion-item>` children; by default only one item is open at a time.
9
9
 
10
- ## Usage
10
+ > **Status: experimental** — API may change before stable release.
11
+
12
+ ## Installation
13
+
14
+ ```js
15
+ import '@boostdev/components/web-components';
16
+ ```
17
+
18
+ Or in HTML without a bundler:
11
19
 
12
20
  ```html
13
- <bds-accordion>
14
- <bds-accordion-item>
15
- <span slot="header">Section 1</span>
16
- <p>Content for section 1.</p>
17
- </bds-accordion-item>
18
- <bds-accordion-item>
19
- <span slot="header">Section 2</span>
20
- <p>Content for section 2.</p>
21
- </bds-accordion-item>
22
- </bds-accordion>
21
+ <script type="module">
22
+ import '@boostdev/components/web-components';
23
+ </script>
23
24
  ```
24
25
 
26
+ ## When to use
27
+
28
+ - Displaying a list of questions and answers (FAQ)
29
+ - Grouping related settings or options to reduce visual clutter
30
+ - Progressive disclosure of content sections on a page
31
+
32
+ ## When not to use
33
+
34
+ - When all sections should be visible at once — use a regular list or `<bds-collapsible>` per section instead
35
+ - For navigation — use a menu or sidebar
36
+
37
+ ## Examples
38
+
39
+ ### Default (single open)
40
+ <Canvas of={Stories.Default} />
41
+
42
+ ### Allow multiple open
43
+ <Canvas of={Stories.AllowMultiple} />
44
+
45
+ ### With disabled item
46
+ <Canvas of={Stories.WithDisabledItem} />
47
+
48
+ ## Props
49
+
50
+ <ArgTypes of={Stories} />
51
+
25
52
  ## Attributes — `<bds-accordion>`
26
53
 
27
- | Attribute | Type | Default | Description |
28
- |------------------|-----------|---------|-----------------------------------------|
29
- | `allow-multiple` | `boolean` | `false` | Allow more than one item open at a time |
54
+ | Attribute | Type | Default | Description |
55
+ |-----------|------|---------|-------------|
56
+ | `allow-multiple` | boolean | `false` | When set, multiple items can be open simultaneously |
30
57
 
31
58
  ## Attributes — `<bds-accordion-item>`
32
59
 
33
- | Attribute | Type | Default | Description |
34
- |------------|-----------|---------|-----------------------------------|
35
- | `disabled` | `boolean` | `false` | Prevents this item from toggling |
60
+ | Attribute | Type | Default | Description |
61
+ |-----------|------|---------|-------------|
62
+ | `open` | boolean | `false` | Whether this panel is currently expanded |
63
+ | `disabled` | boolean | `false` | Prevents the user from toggling this item |
36
64
 
37
65
  ## Slots — `<bds-accordion-item>`
38
66
 
39
- | Slot | Description |
40
- |-----------|--------------------------|
41
- | `header` | The clickable header text |
42
- | (default) | The collapsible body content |
67
+ | Slot | Description |
68
+ |------|-------------|
69
+ | `header` | The always-visible trigger label |
70
+ | `(default)` | The content revealed when the item is open |
43
71
 
44
- ## Stories
72
+ ## Events
45
73
 
46
- <Canvas of={Stories.Default} />
47
- <Canvas of={Stories.AllVariants} />
74
+ | Event | Bubbles | Description |
75
+ |-------|---------|-------------|
76
+ | `bds-accordion-item-toggle` | Yes | Fired by `<bds-accordion-item>` when the trigger is clicked; the parent accordion handles state |
48
77
 
49
- ## Controls
78
+ ## Usage in plain HTML
50
79
 
51
- <ArgTypes of={Stories} />
80
+ ```html
81
+ <bds-accordion>
82
+ <bds-accordion-item open>
83
+ <span slot="header">What is Boost Components?</span>
84
+ <p>A framework-agnostic component library built on web standards.</p>
85
+ </bds-accordion-item>
86
+ <bds-accordion-item>
87
+ <span slot="header">How do I install it?</span>
88
+ <p>Run npm install @boostdev/components.</p>
89
+ </bds-accordion-item>
90
+ </bds-accordion>
91
+
92
+ <!-- Allow multiple panels open at once -->
93
+ <bds-accordion allow-multiple>
94
+ <!-- ... -->
95
+ </bds-accordion>
96
+ ```
97
+
98
+ ## Accessibility
99
+
100
+ - Each trigger is a `<button>` inside an `<h3>` heading with `aria-expanded` and `aria-controls` wired to the corresponding panel
101
+ - Panels use `role="region"` and `aria-labelledby` pointing back to the trigger
102
+ - `disabled` prevents toggle and conveys state via the native `disabled` attribute on the button
103
+ - Chevron icon is `aria-hidden="true"`
@@ -1,85 +1,94 @@
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
- function BdsAccordion({ allowMultiple }: { allowMultiple?: boolean }) {
5
+ // Thin wrapper for bds-accordion-item
6
+ function BdsAccordionItem({
7
+ open,
8
+ disabled,
9
+ header,
10
+ children,
11
+ }: {
12
+ open?: boolean;
13
+ disabled?: boolean;
14
+ header?: string;
15
+ children?: React.ReactNode;
16
+ }) {
17
+ return React.createElement(
18
+ 'bds-accordion-item',
19
+ { open: open || undefined, disabled: disabled || undefined },
20
+ React.createElement('span', { slot: 'header' }, header ?? 'Accordion item'),
21
+ children ?? React.createElement('p', { style: { margin: 0 } }, 'Accordion panel content.'),
22
+ );
23
+ }
24
+
25
+ // Thin wrapper for bds-accordion
26
+ function BdsAccordion({
27
+ allowMultiple,
28
+ children,
29
+ }: {
30
+ allowMultiple?: boolean;
31
+ children?: React.ReactNode;
32
+ }) {
6
33
  return React.createElement(
7
34
  'bds-accordion',
8
35
  { 'allow-multiple': allowMultiple || undefined },
9
- React.createElement(
10
- 'bds-accordion-item',
11
- null,
12
- React.createElement('span', { slot: 'header' }, 'What is a web component?'),
13
- React.createElement('p', { style: { margin: 0 } }, 'A web component is a reusable custom element built with native web platform APIs — no framework required.'),
14
- ),
15
- React.createElement(
16
- 'bds-accordion-item',
17
- null,
18
- React.createElement('span', { slot: 'header' }, 'How do I use it?'),
19
- React.createElement('p', { style: { margin: 0 } }, 'Import the package and add the custom element tag to your HTML. Works in any framework.'),
20
- ),
21
- React.createElement(
22
- 'bds-accordion-item',
23
- null,
24
- React.createElement('span', { slot: 'header' }, 'Is it accessible?'),
25
- React.createElement('p', { style: { margin: 0 } }, 'Yes. Each item uses proper ARIA attributes: aria-expanded, aria-controls, and aria-labelledby.'),
26
- ),
36
+ children,
37
+ );
38
+ }
39
+
40
+ // Top-level wrapper used by Storybook controls
41
+ function BdsAccordionStory({
42
+ allowMultiple = false,
43
+ }: {
44
+ allowMultiple?: boolean;
45
+ }) {
46
+ return (
47
+ <BdsAccordion allowMultiple={allowMultiple}>
48
+ <BdsAccordionItem header="What is Boost Components?" open>
49
+ {React.createElement('p', { style: { margin: 0 } }, 'A framework-agnostic component library built on web standards.')}
50
+ </BdsAccordionItem>
51
+ <BdsAccordionItem header="How do I install it?">
52
+ {React.createElement('p', { style: { margin: 0 } }, 'Run npm install @boostdev/components and import the web components entry point.')}
53
+ </BdsAccordionItem>
54
+ <BdsAccordionItem header="Does it support dark mode?">
55
+ {React.createElement('p', { style: { margin: 0 } }, 'Yes — all design tokens respond to [data-theme="dark"] and prefers-color-scheme: dark.')}
56
+ </BdsAccordionItem>
57
+ </BdsAccordion>
27
58
  );
28
59
  }
29
60
 
30
61
  const meta = {
31
62
  title: 'Web Components/Interaction/Accordion',
32
- component: BdsAccordion,
63
+ component: BdsAccordionStory,
33
64
  tags: ['!stable', 'experimental'],
34
65
  parameters: { layout: 'padded' },
35
66
  argTypes: {
36
67
  allowMultiple: { control: 'boolean' },
37
68
  },
38
- } satisfies Meta<typeof BdsAccordion>;
69
+ } satisfies Meta<typeof BdsAccordionStory>;
39
70
 
40
71
  export default meta;
41
72
  type Story = StoryObj<typeof meta>;
42
73
 
43
74
  export const Default: Story = { args: { allowMultiple: false } };
44
- export const AllowMultiple: Story = { args: { allowMultiple: true } };
45
75
 
46
- export const WithDisabledItem: Story = {
47
- render: () =>
48
- React.createElement(
49
- 'bds-accordion',
50
- null,
51
- React.createElement(
52
- 'bds-accordion-item',
53
- null,
54
- React.createElement('span', { slot: 'header' }, 'Available item'),
55
- React.createElement('p', { style: { margin: 0 } }, 'This item can be opened and closed.'),
56
- ),
57
- React.createElement(
58
- 'bds-accordion-item',
59
- { disabled: true },
60
- React.createElement('span', { slot: 'header' }, 'Disabled item'),
61
- React.createElement('p', { style: { margin: 0 } }, 'This item cannot be toggled.'),
62
- ),
63
- React.createElement(
64
- 'bds-accordion-item',
65
- null,
66
- React.createElement('span', { slot: 'header' }, 'Another available item'),
67
- React.createElement('p', { style: { margin: 0 } }, 'This item can also be opened.'),
68
- ),
69
- ),
76
+ export const AllowMultiple: Story = {
77
+ args: { allowMultiple: true },
70
78
  };
71
79
 
72
- export const AllVariants: Story = {
80
+ export const WithDisabledItem: Story = {
73
81
  render: () => (
74
- <div style={{ display: 'flex', flexDirection: 'column', gap: '24px' }}>
75
- <div>
76
- <p style={{ margin: '0 0 8px', fontSize: '0.75rem', color: '#888', fontWeight: 600 }}>Single open (default)</p>
77
- <BdsAccordion />
78
- </div>
79
- <div>
80
- <p style={{ margin: '0 0 8px', fontSize: '0.75rem', color: '#888', fontWeight: 600 }}>Multiple open</p>
81
- <BdsAccordion allowMultiple />
82
- </div>
83
- </div>
82
+ <BdsAccordion>
83
+ <BdsAccordionItem header="Available item" open>
84
+ {React.createElement('p', { style: { margin: 0 } }, 'This item can be toggled.')}
85
+ </BdsAccordionItem>
86
+ <BdsAccordionItem header="Disabled item" disabled>
87
+ {React.createElement('p', { style: { margin: 0 } }, 'This content is inaccessible because the item is disabled.')}
88
+ </BdsAccordionItem>
89
+ <BdsAccordionItem header="Another available item">
90
+ {React.createElement('p', { style: { margin: 0 } }, 'This item can also be toggled.')}
91
+ </BdsAccordionItem>
92
+ </BdsAccordion>
84
93
  ),
85
94
  };