@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.
- package/AGENTS.md +13 -10
- package/dist/client.cjs +77 -99
- package/dist/client.css +611 -580
- package/dist/client.d.cts +13 -16
- package/dist/client.d.ts +13 -16
- package/dist/client.js +87 -109
- package/dist/index.cjs +77 -99
- package/dist/index.css +611 -580
- package/dist/index.d.cts +13 -16
- package/dist/index.d.ts +13 -16
- package/dist/index.js +87 -109
- package/dist/native/index.cjs +9 -8
- package/dist/native/index.d.cts +1 -1
- package/dist/native/index.d.ts +1 -1
- package/dist/native/index.js +9 -8
- package/dist/web-components/{chunk-O4UFI2RX.js → chunk-3REOIRDW.js} +13 -11
- package/dist/web-components/{chunk-K5CE6HSB.js → chunk-6MH5UWUD.js} +74 -17
- package/dist/web-components/{chunk-VM3YHGQ2.js → chunk-AJSXNDAP.js} +1 -2
- package/dist/web-components/{chunk-LSC4N56Q.js → chunk-BX3IPVOB.js} +1 -2
- package/dist/web-components/{chunk-CJ5ZOO42.js → chunk-DI46Q2EA.js} +50 -1
- package/dist/web-components/{chunk-CAPI25CU.js → chunk-DZRSJGPB.js} +3 -3
- package/dist/web-components/{chunk-VSS5ITNE.js → chunk-EBJM3VD4.js} +1 -3
- package/dist/web-components/{chunk-O7I63SQX.js → chunk-HHHRF2PS.js} +6 -12
- package/dist/web-components/{chunk-OTX4COSV.js → chunk-JUKB3BUP.js} +3 -4
- package/dist/web-components/{chunk-IQGLIQSO.js → chunk-N6IMUOY4.js} +2 -5
- package/dist/web-components/{chunk-QDRH46TF.js → chunk-QLZ2362S.js} +1 -3
- package/dist/web-components/{chunk-IK3PTFZ4.js → chunk-T6AETZRP.js} +1 -3
- package/dist/web-components/{chunk-4BX6AWXX.js → chunk-X3FKVHLK.js} +2 -4
- package/dist/web-components/{chunk-A67LCT7C.js → chunk-XNA6WTXG.js} +3 -4
- package/dist/web-components/{chunk-XIENXR7H.js → chunk-YRXCVKHV.js} +1 -3
- package/dist/web-components/{chunk-6T3RKUKG.js → chunk-ZTC6GRP7.js} +1 -2
- package/dist/web-components/globals.js +1 -1
- package/dist/web-components/index.js +16 -16
- package/dist/web-components/interaction/bds-accordion.js +1 -1
- package/dist/web-components/interaction/bds-button.d.ts +2 -2
- package/dist/web-components/interaction/bds-button.js +1 -1
- package/dist/web-components/interaction/bds-dialog.js +1 -1
- package/dist/web-components/interaction/bds-drawer.js +1 -1
- package/dist/web-components/interaction/form/bds-checkbox.js +1 -1
- package/dist/web-components/interaction/form/bds-combobox.js +1 -1
- package/dist/web-components/interaction/form/bds-number-input.js +1 -1
- package/dist/web-components/interaction/form/bds-radio.js +1 -1
- package/dist/web-components/interaction/form/bds-segmented-control.d.ts +20 -3
- package/dist/web-components/interaction/form/bds-segmented-control.js +1 -1
- package/dist/web-components/interaction/form/bds-select.js +1 -1
- package/dist/web-components/interaction/form/bds-switch.js +1 -1
- package/dist/web-components/interaction/form/bds-textarea.js +1 -1
- package/dist/web-components/ui/bds-alert.js +1 -1
- package/dist/web-components/ui/bds-card.js +1 -1
- package/dist/web-components/ui/bds-notification-banner.js +1 -1
- package/package.json +2 -2
- package/src/components/interaction/Button/Button.module.css +12 -11
- package/src/components/interaction/Button/Button.native.tsx +10 -9
- package/src/components/interaction/Button/Button.tsx +1 -1
- package/src/components/interaction/Command/Command.module.css +3 -7
- package/src/components/interaction/Dialog/Dialog.module.css +7 -5
- package/src/components/interaction/Drawer/Drawer.module.css +49 -1
- package/src/components/interaction/DropdownMenu/DropdownMenu.module.css +1 -3
- package/src/components/interaction/Popover/Popover.module.css +1 -3
- package/src/components/interaction/form/Checkbox/Checkbox.module.css +1 -3
- package/src/components/interaction/form/Combobox/Combobox.module.css +2 -6
- package/src/components/interaction/form/FormInput/FormInput.module.css +1 -3
- package/src/components/interaction/form/NumberInput/NumberInput.module.css +16 -4
- package/src/components/interaction/form/Radio/Radio.module.css +6 -16
- package/src/components/interaction/form/SegmentedControl/SegmentedControl.mdx +70 -25
- package/src/components/interaction/form/SegmentedControl/SegmentedControl.module.css +55 -33
- package/src/components/interaction/form/SegmentedControl/SegmentedControl.spec.tsx +127 -56
- package/src/components/interaction/form/SegmentedControl/SegmentedControl.stories.tsx +89 -72
- package/src/components/interaction/form/SegmentedControl/SegmentedControl.tsx +40 -62
- package/src/components/interaction/form/SegmentedControl/index.ts +1 -1
- package/src/components/interaction/form/Select/Select.module.css +2 -4
- package/src/components/interaction/form/Switch/Switch.module.css +5 -7
- package/src/components/interaction/form/Switch/Switch.native.spec.tsx +9 -9
- package/src/components/interaction/form/Switch/Switch.native.tsx +2 -2
- package/src/components/interaction/form/Textarea/Textarea.module.css +1 -3
- package/src/components/interaction/form/atoms/InputContainer.stories.tsx +64 -0
- package/src/components/interaction/form/atoms/Label.stories.tsx +33 -0
- package/src/components/interaction/form/atoms/Message.stories.tsx +33 -0
- package/src/components/layout/Card/Card.module.css +1 -3
- package/src/components/ui/Accordion/Accordion.module.css +1 -2
- package/src/components/ui/Alert/Alert.module.css +1 -2
- package/src/components/ui/Calendar/Calendar.module.css +2 -5
- package/src/components/ui/Carousel/Carousel.module.css +1 -3
- package/src/components/ui/NotificationBanner/NotificationBanner.module.css +1 -2
- package/src/components/ui/Pagination/Pagination.module.css +1 -2
- package/src/components/ui/SkipLink/SkipLink.module.css +1 -2
- package/src/components/ui/Table/Table.module.css +1 -2
- package/src/css/bdc.css +16 -11
- package/src/index.ts +1 -1
- package/src/web-components/globals.ts +3 -3
- package/src/web-components/interaction/BdsAccordion.mdx +51 -0
- package/src/web-components/interaction/BdsAccordion.stories.tsx +85 -0
- package/src/web-components/interaction/BdsCollapsible.mdx +46 -0
- package/src/web-components/interaction/BdsCollapsible.stories.tsx +87 -0
- package/src/web-components/interaction/BdsDialog.mdx +49 -0
- package/src/web-components/interaction/BdsDialog.stories.tsx +75 -0
- package/src/web-components/interaction/BdsDrawer.mdx +50 -0
- package/src/web-components/interaction/BdsDrawer.stories.tsx +66 -0
- package/src/web-components/interaction/BdsSkipLink.mdx +34 -0
- package/src/web-components/interaction/BdsSkipLink.stories.tsx +55 -0
- package/src/web-components/interaction/BdsTabs.mdx +47 -0
- package/src/web-components/interaction/BdsTabs.stories.tsx +80 -0
- package/src/web-components/interaction/BdsTooltip.mdx +38 -0
- package/src/web-components/interaction/BdsTooltip.stories.tsx +68 -0
- package/src/web-components/interaction/bds-accordion.ts +1 -2
- package/src/web-components/interaction/bds-button.ts +15 -13
- package/src/web-components/interaction/bds-dialog.ts +2 -5
- package/src/web-components/interaction/bds-drawer.ts +50 -1
- package/src/web-components/interaction/form/BdsCheckbox.mdx +39 -0
- package/src/web-components/interaction/form/BdsCheckbox.stories.tsx +73 -0
- package/src/web-components/interaction/form/BdsCombobox.mdx +52 -0
- package/src/web-components/interaction/form/BdsCombobox.stories.tsx +91 -0
- package/src/web-components/interaction/form/BdsFileInput.mdx +44 -0
- package/src/web-components/interaction/form/BdsFileInput.stories.tsx +84 -0
- package/src/web-components/interaction/form/BdsNumberInput.mdx +41 -0
- package/src/web-components/interaction/form/BdsNumberInput.stories.tsx +90 -0
- package/src/web-components/interaction/form/BdsRadio.mdx +41 -0
- package/src/web-components/interaction/form/BdsRadio.stories.tsx +90 -0
- package/src/web-components/interaction/form/BdsSegmentedControl.mdx +42 -0
- package/src/web-components/interaction/form/BdsSegmentedControl.stories.tsx +92 -0
- package/src/web-components/interaction/form/BdsSelect.mdx +38 -0
- package/src/web-components/interaction/form/BdsSelect.stories.tsx +93 -0
- package/src/web-components/interaction/form/BdsSlider.mdx +49 -0
- package/src/web-components/interaction/form/BdsSlider.stories.tsx +89 -0
- package/src/web-components/interaction/form/BdsSwitch.mdx +39 -0
- package/src/web-components/interaction/form/BdsSwitch.stories.tsx +73 -0
- package/src/web-components/interaction/form/BdsTextarea.mdx +41 -0
- package/src/web-components/interaction/form/BdsTextarea.stories.tsx +79 -0
- package/src/web-components/interaction/form/bds-checkbox.ts +1 -3
- package/src/web-components/interaction/form/bds-combobox.ts +1 -3
- package/src/web-components/interaction/form/bds-number-input.ts +3 -4
- package/src/web-components/interaction/form/bds-radio.ts +6 -12
- package/src/web-components/interaction/form/bds-segmented-control.ts +91 -20
- package/src/web-components/interaction/form/bds-select.ts +2 -4
- package/src/web-components/interaction/form/bds-switch.ts +3 -4
- package/src/web-components/interaction/form/bds-textarea.ts +1 -3
- package/src/web-components/ui/BdsAvatar.mdx +67 -0
- package/src/web-components/ui/BdsAvatar.stories.tsx +62 -0
- package/src/web-components/ui/BdsBreadcrumb.mdx +63 -0
- package/src/web-components/ui/BdsBreadcrumb.stories.tsx +59 -0
- package/src/web-components/ui/BdsCard.mdx +83 -0
- package/src/web-components/ui/BdsCard.stories.tsx +90 -0
- package/src/web-components/ui/BdsDescriptionList.mdx +67 -0
- package/src/web-components/ui/BdsDescriptionList.stories.tsx +79 -0
- package/src/web-components/ui/BdsIconWrapper.mdx +70 -0
- package/src/web-components/ui/BdsIconWrapper.stories.tsx +76 -0
- package/src/web-components/ui/BdsLink.mdx +75 -0
- package/src/web-components/ui/BdsLink.stories.tsx +64 -0
- package/src/web-components/ui/BdsLoading.mdx +62 -0
- package/src/web-components/ui/BdsLoading.stories.tsx +37 -0
- package/src/web-components/ui/BdsNotificationBanner.mdx +90 -0
- package/src/web-components/ui/BdsNotificationBanner.stories.tsx +93 -0
- package/src/web-components/ui/BdsProgress.mdx +63 -0
- package/src/web-components/ui/BdsProgress.stories.tsx +70 -0
- package/src/web-components/ui/BdsProgressCircle.mdx +64 -0
- package/src/web-components/ui/BdsProgressCircle.stories.tsx +69 -0
- package/src/web-components/ui/BdsRating.mdx +61 -0
- package/src/web-components/ui/BdsRating.stories.tsx +39 -0
- package/src/web-components/ui/BdsSectionHeader.mdx +69 -0
- package/src/web-components/ui/BdsSectionHeader.stories.tsx +56 -0
- package/src/web-components/ui/BdsSeparator.mdx +63 -0
- package/src/web-components/ui/BdsSeparator.stories.tsx +47 -0
- package/src/web-components/ui/BdsSkeleton.mdx +67 -0
- package/src/web-components/ui/BdsSkeleton.stories.tsx +50 -0
- package/src/web-components/ui/BdsTypography.mdx +83 -0
- package/src/web-components/ui/BdsTypography.stories.tsx +51 -0
- package/src/web-components/ui/bds-alert.ts +1 -2
- package/src/web-components/ui/bds-card.ts +1 -3
- package/src/web-components/ui/bds-notification-banner.ts +1 -2
|
@@ -1,26 +1,29 @@
|
|
|
1
|
-
import { LitElement, css, html } from 'lit';
|
|
1
|
+
import { LitElement, css, html, nothing } from 'lit';
|
|
2
2
|
|
|
3
3
|
export interface SegmentedOption {
|
|
4
4
|
value: string;
|
|
5
5
|
label: string;
|
|
6
6
|
disabled?: boolean;
|
|
7
|
+
/** When set, renders the option as an <a> link instead of a radio button */
|
|
8
|
+
href?: string;
|
|
7
9
|
}
|
|
8
10
|
|
|
9
11
|
/**
|
|
10
12
|
* `<bds-segmented-control>` — form-associated Segmented Control custom element.
|
|
11
13
|
*
|
|
12
|
-
* Renders a group of radio buttons styled as a unified segmented control.
|
|
14
|
+
* Renders a group of radio buttons (or links) styled as a unified segmented control.
|
|
13
15
|
* Passes a JSON `options` attribute because reactive slot content can't be
|
|
14
16
|
* easily converted to radio groups.
|
|
15
17
|
*
|
|
16
18
|
* Attributes:
|
|
17
19
|
* name — form field name (also used for the internal radio group)
|
|
18
20
|
* value — currently selected value
|
|
19
|
-
* options — JSON array of `{ value, label, disabled? }` option objects
|
|
21
|
+
* options — JSON array of `{ value, label, disabled?, href? }` option objects
|
|
20
22
|
* disabled — boolean; disables all options
|
|
23
|
+
* variant — "outline" (inset border on active item, default) | "filled" (sliding thumb)
|
|
21
24
|
*
|
|
22
25
|
* Events:
|
|
23
|
-
* change — fired when a new segment is selected
|
|
26
|
+
* change — fired when a new segment is selected (radio mode only)
|
|
24
27
|
*
|
|
25
28
|
* @example
|
|
26
29
|
* <bds-segmented-control
|
|
@@ -28,6 +31,13 @@ export interface SegmentedOption {
|
|
|
28
31
|
* value="list"
|
|
29
32
|
* options='[{"value":"list","label":"List"},{"value":"grid","label":"Grid"}]'
|
|
30
33
|
* ></bds-segmented-control>
|
|
34
|
+
*
|
|
35
|
+
* @example Outline variant with links
|
|
36
|
+
* <bds-segmented-control
|
|
37
|
+
* variant="outline"
|
|
38
|
+
* value="home"
|
|
39
|
+
* options='[{"value":"home","label":"Home","href":"/"},{"value":"about","label":"About","href":"/about"}]'
|
|
40
|
+
* ></bds-segmented-control>
|
|
31
41
|
*/
|
|
32
42
|
export class BdsSegmentedControl extends LitElement {
|
|
33
43
|
static formAssociated = true;
|
|
@@ -56,7 +66,7 @@ export class BdsSegmentedControl extends LitElement {
|
|
|
56
66
|
position: absolute;
|
|
57
67
|
inset-block: 0.25rem;
|
|
58
68
|
border-radius: calc(var(--bds-border_radius--s) - 2px);
|
|
59
|
-
background-color: var(--segmented_thumb-color, var(--bds-
|
|
69
|
+
background-color: var(--segmented_thumb-color, var(--bds-color_interactive));
|
|
60
70
|
box-shadow: var(--bds-shadow_m);
|
|
61
71
|
transition: inset-inline-start var(--bds-animation_transition-duration) var(--bds-animation_easing),
|
|
62
72
|
inline-size var(--bds-animation_transition-duration) var(--bds-animation_easing);
|
|
@@ -87,10 +97,11 @@ export class BdsSegmentedControl extends LitElement {
|
|
|
87
97
|
transition: color var(--bds-animation_transition-duration) var(--bds-animation_easing);
|
|
88
98
|
user-select: none;
|
|
89
99
|
white-space: nowrap;
|
|
100
|
+
text-decoration: none;
|
|
90
101
|
}
|
|
91
102
|
|
|
92
103
|
.item.--active {
|
|
93
|
-
color: var(--segmented_color--active, var(--bds-
|
|
104
|
+
color: var(--segmented_color--active, var(--bds-color_on-interactive));
|
|
94
105
|
}
|
|
95
106
|
|
|
96
107
|
.item.--disabled {
|
|
@@ -102,6 +113,39 @@ export class BdsSegmentedControl extends LitElement {
|
|
|
102
113
|
outline: var(--bds-outline_default);
|
|
103
114
|
outline-offset: var(--bds-outline_offset);
|
|
104
115
|
}
|
|
116
|
+
|
|
117
|
+
/* Outline variant: sliding inset-border indicator (positioned via JS like .thumb) */
|
|
118
|
+
.indicator {
|
|
119
|
+
position: absolute;
|
|
120
|
+
inset-block: 0.25rem;
|
|
121
|
+
border-radius: calc(var(--bds-border_radius--s) - 2px);
|
|
122
|
+
pointer-events: none;
|
|
123
|
+
z-index: 2;
|
|
124
|
+
display: none;
|
|
125
|
+
transition: inset-inline-start var(--bds-animation_transition-duration) var(--bds-animation_easing),
|
|
126
|
+
inline-size var(--bds-animation_transition-duration) var(--bds-animation_easing);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/* Outline variant — no thumb, sliding inset-border indicator, interactive active color */
|
|
130
|
+
:host([variant='outline']) .thumb {
|
|
131
|
+
display: none;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
:host([variant='outline']) .item.--active {
|
|
135
|
+
color: var(--segmented_color--active, var(--bds-color_interactive));
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
:host([variant='outline']) .indicator {
|
|
139
|
+
display: block;
|
|
140
|
+
box-shadow: inset 0 0 0 2px var(--bds-color_interactive);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
@media (prefers-reduced-motion: reduce) {
|
|
144
|
+
.thumb,
|
|
145
|
+
.indicator {
|
|
146
|
+
transition: none;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
105
149
|
`;
|
|
106
150
|
|
|
107
151
|
static properties = {
|
|
@@ -109,12 +153,14 @@ export class BdsSegmentedControl extends LitElement {
|
|
|
109
153
|
value: { type: String },
|
|
110
154
|
options: { type: String },
|
|
111
155
|
disabled: { type: Boolean, reflect: true },
|
|
156
|
+
variant: { type: String, reflect: true },
|
|
112
157
|
};
|
|
113
158
|
|
|
114
159
|
declare name: string;
|
|
115
160
|
declare value: string;
|
|
116
161
|
declare options: string;
|
|
117
162
|
declare disabled: boolean;
|
|
163
|
+
declare variant: 'outline' | 'filled';
|
|
118
164
|
|
|
119
165
|
private _internals!: ElementInternals;
|
|
120
166
|
private readonly _uid = Math.random().toString(36).slice(2, 8);
|
|
@@ -126,6 +172,7 @@ export class BdsSegmentedControl extends LitElement {
|
|
|
126
172
|
this.value = '';
|
|
127
173
|
this.options = '[]';
|
|
128
174
|
this.disabled = false;
|
|
175
|
+
this.variant = 'outline';
|
|
129
176
|
}
|
|
130
177
|
|
|
131
178
|
private get _options(): SegmentedOption[] {
|
|
@@ -140,22 +187,35 @@ export class BdsSegmentedControl extends LitElement {
|
|
|
140
187
|
super.updated(changed);
|
|
141
188
|
if (changed.has('value') || changed.has('options')) {
|
|
142
189
|
this._internals.setFormValue?.(this.value || null);
|
|
143
|
-
this._updateThumb();
|
|
190
|
+
if (this.variant === 'filled') this._updateThumb();
|
|
191
|
+
if (this.variant === 'outline') this._updateIndicator();
|
|
192
|
+
}
|
|
193
|
+
if (changed.has('variant')) {
|
|
194
|
+
if (this.variant === 'filled') this._updateThumb();
|
|
195
|
+
if (this.variant === 'outline') this._updateIndicator();
|
|
144
196
|
}
|
|
145
197
|
}
|
|
146
198
|
|
|
147
|
-
private
|
|
148
|
-
|
|
149
|
-
const selectedIndex = Math.max(0, opts.findIndex(o => o.value === this.value));
|
|
150
|
-
const items = this.shadowRoot?.querySelectorAll<HTMLElement>('.item');
|
|
151
|
-
const thumb = this.shadowRoot?.querySelector<HTMLElement>('.thumb');
|
|
152
|
-
if (!items || !thumb || items.length === 0) return;
|
|
199
|
+
private _positionSlider(el: HTMLElement | null | undefined, items: NodeListOf<HTMLElement>, selectedIndex: number) {
|
|
200
|
+
if (!el || items.length === 0) return;
|
|
153
201
|
const item = items[selectedIndex];
|
|
154
202
|
if (!item) return;
|
|
155
203
|
const controlRect = (item.parentElement as HTMLElement).getBoundingClientRect();
|
|
156
204
|
const itemRect = item.getBoundingClientRect();
|
|
157
|
-
|
|
158
|
-
|
|
205
|
+
el.style.insetInlineStart = `${itemRect.left - controlRect.left}px`;
|
|
206
|
+
el.style.inlineSize = `${itemRect.width}px`;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
private _updateThumb() {
|
|
210
|
+
const selectedIndex = Math.max(0, this._options.findIndex(o => o.value === this.value));
|
|
211
|
+
const items = this.shadowRoot?.querySelectorAll<HTMLElement>('.item');
|
|
212
|
+
this._positionSlider(this.shadowRoot?.querySelector<HTMLElement>('.thumb'), items!, selectedIndex);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
private _updateIndicator() {
|
|
216
|
+
const selectedIndex = Math.max(0, this._options.findIndex(o => o.value === this.value));
|
|
217
|
+
const items = this.shadowRoot?.querySelectorAll<HTMLElement>('.item');
|
|
218
|
+
this._positionSlider(this.shadowRoot?.querySelector<HTMLElement>('.indicator'), items!, selectedIndex);
|
|
159
219
|
}
|
|
160
220
|
|
|
161
221
|
formResetCallback() {
|
|
@@ -174,15 +234,26 @@ export class BdsSegmentedControl extends LitElement {
|
|
|
174
234
|
return html`
|
|
175
235
|
<div class="control" role="group">
|
|
176
236
|
<span class="thumb" aria-hidden="true"></span>
|
|
237
|
+
<span class="indicator" aria-hidden="true"></span>
|
|
177
238
|
${opts.map((opt, i) => {
|
|
178
|
-
const id = `bds-seg-${this._uid}-${i}`;
|
|
179
239
|
const isActive = opt.value === this.value;
|
|
180
240
|
const isDisabled = this.disabled || opt.disabled;
|
|
241
|
+
const itemClass = `item ${isActive ? '--active' : ''} ${isDisabled ? '--disabled' : ''}`.trim();
|
|
242
|
+
|
|
243
|
+
if (opt.href) {
|
|
244
|
+
return html`
|
|
245
|
+
<a
|
|
246
|
+
class=${itemClass}
|
|
247
|
+
href=${isDisabled ? nothing : opt.href}
|
|
248
|
+
aria-current=${isActive ? 'page' : nothing}
|
|
249
|
+
?aria-disabled=${isDisabled}
|
|
250
|
+
>${opt.label}</a>
|
|
251
|
+
`;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
const id = `bds-seg-${this._uid}-${i}`;
|
|
181
255
|
return html`
|
|
182
|
-
<label
|
|
183
|
-
class="item ${isActive ? '--active' : ''} ${isDisabled ? '--disabled' : ''}"
|
|
184
|
-
for=${id}
|
|
185
|
-
>
|
|
256
|
+
<label class=${itemClass} for=${id}>
|
|
186
257
|
<input
|
|
187
258
|
id=${id}
|
|
188
259
|
type="radio"
|
|
@@ -58,10 +58,8 @@ export class BdsSelect extends LitElement {
|
|
|
58
58
|
--bdc_color: currentcolor;
|
|
59
59
|
--bdc-outline_radius: var(--bds-border_radius--xs);
|
|
60
60
|
|
|
61
|
-
outline: var(--bdc-outline_width) solid var(--bdc_color);
|
|
62
|
-
outline-offset: var(--bdc-outline_offset);
|
|
63
61
|
border-radius: var(--select_radius, var(--bdc-outline_radius));
|
|
64
|
-
box-shadow: var(--select_shadow, var(--bdc-outline_shadow));
|
|
62
|
+
box-shadow: inset 0 0 0 var(--bdc-outline_width) var(--bdc_color), var(--select_shadow, var(--bdc-outline_shadow));
|
|
65
63
|
background-color: var(--select_color_bg, var(--bds-color_bg));
|
|
66
64
|
color: var(--select_color, var(--bds-color_on-bg));
|
|
67
65
|
appearance: none;
|
|
@@ -86,7 +84,7 @@ export class BdsSelect extends LitElement {
|
|
|
86
84
|
pointer-events: none;
|
|
87
85
|
inline-size: 1rem;
|
|
88
86
|
block-size: 1rem;
|
|
89
|
-
color:
|
|
87
|
+
color: var(--select_chevron-color, var(--bds-color_interactive));
|
|
90
88
|
}
|
|
91
89
|
|
|
92
90
|
.chevron svg {
|
|
@@ -48,8 +48,7 @@ export class BdsSwitch extends LitElement {
|
|
|
48
48
|
background-color: var(--switch_color_bg, var(--bds-color_bg--subtle));
|
|
49
49
|
--bdc_color: currentcolor;
|
|
50
50
|
|
|
51
|
-
|
|
52
|
-
outline-offset: var(--bdc-outline_offset);
|
|
51
|
+
box-shadow: inset 0 0 0 var(--bdc-outline_width) var(--bdc_color);
|
|
53
52
|
transition: background-color 0.2s ease;
|
|
54
53
|
flex-shrink: 0;
|
|
55
54
|
}
|
|
@@ -61,7 +60,7 @@ export class BdsSwitch extends LitElement {
|
|
|
61
60
|
inline-size: 1.1rem;
|
|
62
61
|
block-size: 1.1rem;
|
|
63
62
|
border-radius: 50%;
|
|
64
|
-
background-color: var(--switch_thumb_color, var(--bds-
|
|
63
|
+
background-color: var(--switch_thumb_color, var(--bds-color_interactive));
|
|
65
64
|
transition: inset-inline-start 0.2s ease;
|
|
66
65
|
}
|
|
67
66
|
|
|
@@ -74,7 +73,7 @@ export class BdsSwitch extends LitElement {
|
|
|
74
73
|
}
|
|
75
74
|
|
|
76
75
|
.input:checked + .track {
|
|
77
|
-
background-color: var(--switch_color-active, var(--bdc-color_active));
|
|
76
|
+
background-color: var(--switch_color-active, var(--bdc-color_active--subtle));
|
|
78
77
|
}
|
|
79
78
|
|
|
80
79
|
.input:checked + .track .thumb {
|
|
@@ -44,10 +44,8 @@ export class BdsTextarea extends LitElement {
|
|
|
44
44
|
--bdc_color: currentcolor;
|
|
45
45
|
--bdc-outline_radius: var(--bds-border_radius--xs);
|
|
46
46
|
|
|
47
|
-
outline: var(--bdc-outline_width) solid var(--bdc_color);
|
|
48
|
-
outline-offset: var(--bdc-outline_offset);
|
|
49
47
|
border-radius: var(--textarea_radius, var(--bdc-outline_radius));
|
|
50
|
-
box-shadow: var(--textarea_shadow, var(--bdc-outline_shadow));
|
|
48
|
+
box-shadow: inset 0 0 0 var(--bdc-outline_width) var(--bdc_color), var(--textarea_shadow, var(--bdc-outline_shadow));
|
|
51
49
|
background-color: var(--textarea_color_bg, var(--bds-color_bg));
|
|
52
50
|
color: var(--textarea_color, var(--bds-color_on-bg));
|
|
53
51
|
resize: vertical;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { Meta, Canvas, ArgTypes } from '@storybook/blocks';
|
|
2
|
+
import * as Stories from './BdsAvatar.stories';
|
|
3
|
+
|
|
4
|
+
<Meta of={Stories} />
|
|
5
|
+
|
|
6
|
+
# <bds-avatar>
|
|
7
|
+
|
|
8
|
+
Framework-agnostic Avatar custom element. Displays a profile image when `src` is set; falls back to initials derived from the `name` attribute.
|
|
9
|
+
|
|
10
|
+
> **Status: experimental** — API may change before stable release.
|
|
11
|
+
|
|
12
|
+
## Installation
|
|
13
|
+
|
|
14
|
+
```js
|
|
15
|
+
import '@boostdev/components/web-components';
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Examples
|
|
19
|
+
|
|
20
|
+
### All sizes
|
|
21
|
+
<Canvas of={Stories.AllSizes} />
|
|
22
|
+
|
|
23
|
+
### With initials
|
|
24
|
+
<Canvas of={Stories.Default} />
|
|
25
|
+
|
|
26
|
+
### All variants
|
|
27
|
+
<Canvas of={Stories.AllVariants} />
|
|
28
|
+
|
|
29
|
+
## Props
|
|
30
|
+
|
|
31
|
+
<ArgTypes of={Stories} />
|
|
32
|
+
|
|
33
|
+
## Attributes
|
|
34
|
+
|
|
35
|
+
| Attribute | Type | Default | Description |
|
|
36
|
+
|-----------|------|---------|-------------|
|
|
37
|
+
| `name` | string | — | Full name; used to compute initials and as `aria-label` fallback |
|
|
38
|
+
| `src` | string | — | Image URL; when set, shows the image instead of initials |
|
|
39
|
+
| `alt` | string | — | Alt text for the image (defaults to `name`) |
|
|
40
|
+
| `size` | `"small" \| "medium" \| "large"` | `"medium"` | Avatar diameter (`2em` / `3em` / `4.5em`) |
|
|
41
|
+
|
|
42
|
+
## CSS Custom Properties
|
|
43
|
+
|
|
44
|
+
| Property | Description |
|
|
45
|
+
|----------|-------------|
|
|
46
|
+
| `--avatar_size` | Override the diameter directly |
|
|
47
|
+
| `--avatar_bg` | Fallback background colour (defaults to `--bds-color_blue`) |
|
|
48
|
+
| `--avatar_text` | Initials text colour (defaults to `--bds-color_on-blue`) |
|
|
49
|
+
|
|
50
|
+
## Usage in plain HTML
|
|
51
|
+
|
|
52
|
+
```html
|
|
53
|
+
<!-- Initials fallback -->
|
|
54
|
+
<bds-avatar name="Jane Doe"></bds-avatar>
|
|
55
|
+
|
|
56
|
+
<!-- With image -->
|
|
57
|
+
<bds-avatar src="/path/to/photo.jpg" name="Jane Doe" alt="Jane Doe's avatar"></bds-avatar>
|
|
58
|
+
|
|
59
|
+
<!-- Large size -->
|
|
60
|
+
<bds-avatar name="John Smith" size="large"></bds-avatar>
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Accessibility
|
|
64
|
+
|
|
65
|
+
- When showing initials: renders `role="img"` with `aria-label` set to the `name` value
|
|
66
|
+
- When showing an image: renders a standard `<img>` with `alt` text
|
|
67
|
+
- Initials are hidden from assistive technology (`aria-hidden="true"`) — the label is on the container
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
3
|
+
import '../index';
|
|
4
|
+
|
|
5
|
+
function BdsAvatar({
|
|
6
|
+
name,
|
|
7
|
+
src,
|
|
8
|
+
alt,
|
|
9
|
+
size,
|
|
10
|
+
}: {
|
|
11
|
+
name?: string;
|
|
12
|
+
src?: string;
|
|
13
|
+
alt?: string;
|
|
14
|
+
size?: 'small' | 'medium' | 'large';
|
|
15
|
+
}) {
|
|
16
|
+
return React.createElement('bds-avatar', { name, src, alt, size });
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const meta = {
|
|
20
|
+
title: 'Web Components/UI/Avatar',
|
|
21
|
+
component: BdsAvatar,
|
|
22
|
+
tags: ['!stable', 'experimental'],
|
|
23
|
+
parameters: { layout: 'centered' },
|
|
24
|
+
argTypes: {
|
|
25
|
+
size: { control: 'select', options: ['small', 'medium', 'large'] },
|
|
26
|
+
},
|
|
27
|
+
} satisfies Meta<typeof BdsAvatar>;
|
|
28
|
+
|
|
29
|
+
export default meta;
|
|
30
|
+
type Story = StoryObj<typeof meta>;
|
|
31
|
+
|
|
32
|
+
export const Default: Story = { args: { name: 'Jane Doe' } };
|
|
33
|
+
export const SingleInitial: Story = { args: { name: 'Jane' } };
|
|
34
|
+
export const Small: Story = { args: { name: 'Jane Doe', size: 'small' } };
|
|
35
|
+
export const Medium: Story = { args: { name: 'Jane Doe', size: 'medium' } };
|
|
36
|
+
export const Large: Story = { args: { name: 'Jane Doe', size: 'large' } };
|
|
37
|
+
|
|
38
|
+
export const AllSizes: Story = {
|
|
39
|
+
render: () => (
|
|
40
|
+
<div style={{ display: 'flex', alignItems: 'center', gap: '24px' }}>
|
|
41
|
+
{(['small', 'medium', 'large'] as const).map(s => (
|
|
42
|
+
<div key={s} style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: '8px' }}>
|
|
43
|
+
<BdsAvatar name="Jane Doe" size={s} />
|
|
44
|
+
<span style={{ fontSize: '0.75rem', color: '#888' }}>{s}</span>
|
|
45
|
+
</div>
|
|
46
|
+
))}
|
|
47
|
+
</div>
|
|
48
|
+
),
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
export const AllVariants: Story = {
|
|
52
|
+
render: () => (
|
|
53
|
+
<div style={{ display: 'flex', alignItems: 'center', gap: '16px', flexWrap: 'wrap' }}>
|
|
54
|
+
<BdsAvatar name="Jane Doe" />
|
|
55
|
+
<BdsAvatar name="John Smith" />
|
|
56
|
+
<BdsAvatar name="Alice" />
|
|
57
|
+
<BdsAvatar name="Bob" />
|
|
58
|
+
<BdsAvatar name="Jane Doe" size="small" />
|
|
59
|
+
<BdsAvatar name="Jane Doe" size="large" />
|
|
60
|
+
</div>
|
|
61
|
+
),
|
|
62
|
+
};
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { Meta, Canvas, ArgTypes } from '@storybook/blocks';
|
|
2
|
+
import * as Stories from './BdsBreadcrumb.stories';
|
|
3
|
+
|
|
4
|
+
<Meta of={Stories} />
|
|
5
|
+
|
|
6
|
+
# <bds-breadcrumb>
|
|
7
|
+
|
|
8
|
+
Framework-agnostic Breadcrumb navigation custom element. Renders an ordered list of links showing the user's location in the site hierarchy.
|
|
9
|
+
|
|
10
|
+
> **Status: experimental** — API may change before stable release.
|
|
11
|
+
|
|
12
|
+
## Installation
|
|
13
|
+
|
|
14
|
+
```js
|
|
15
|
+
import '@boostdev/components/web-components';
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Examples
|
|
19
|
+
|
|
20
|
+
### Default (3 levels)
|
|
21
|
+
<Canvas of={Stories.Default} />
|
|
22
|
+
|
|
23
|
+
### Deep nested
|
|
24
|
+
<Canvas of={Stories.DeepNested} />
|
|
25
|
+
|
|
26
|
+
### All variants
|
|
27
|
+
<Canvas of={Stories.AllVariants} />
|
|
28
|
+
|
|
29
|
+
## Props
|
|
30
|
+
|
|
31
|
+
<ArgTypes of={Stories} />
|
|
32
|
+
|
|
33
|
+
## Attributes
|
|
34
|
+
|
|
35
|
+
| Attribute | Type | Default | Description |
|
|
36
|
+
|-----------|------|---------|-------------|
|
|
37
|
+
| `items` | JSON string | `"[]"` | Array of `{ label: string, href?: string }` objects. The last item is the current page (no link). |
|
|
38
|
+
|
|
39
|
+
## Usage in plain HTML
|
|
40
|
+
|
|
41
|
+
```html
|
|
42
|
+
<bds-breadcrumb items='[
|
|
43
|
+
{"label":"Home","href":"/"},
|
|
44
|
+
{"label":"Products","href":"/products"},
|
|
45
|
+
{"label":"Detail"}
|
|
46
|
+
]'></bds-breadcrumb>
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
In JavaScript:
|
|
50
|
+
```js
|
|
51
|
+
const crumb = document.querySelector('bds-breadcrumb');
|
|
52
|
+
crumb.items = [
|
|
53
|
+
{ label: 'Home', href: '/' },
|
|
54
|
+
{ label: 'Products', href: '/products' },
|
|
55
|
+
{ label: 'Detail' },
|
|
56
|
+
];
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Accessibility
|
|
60
|
+
|
|
61
|
+
- Renders as `<nav aria-label="Breadcrumb">` with an `<ol>` list
|
|
62
|
+
- The last item gets `aria-current="page"` — it is not a link
|
|
63
|
+
- Separators (`›`) are hidden from screen readers with `aria-hidden="true"`
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
3
|
+
import type { BreadcrumbItem } from './bds-breadcrumb';
|
|
4
|
+
import '../index';
|
|
5
|
+
|
|
6
|
+
function BdsBreadcrumb({ items = [] }: { items?: BreadcrumbItem[] }) {
|
|
7
|
+
return React.createElement('bds-breadcrumb', { items: JSON.stringify(items) });
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const meta = {
|
|
11
|
+
title: 'Web Components/UI/Breadcrumb',
|
|
12
|
+
component: BdsBreadcrumb,
|
|
13
|
+
tags: ['!stable', 'experimental'],
|
|
14
|
+
parameters: { layout: 'padded' },
|
|
15
|
+
} satisfies Meta<typeof BdsBreadcrumb>;
|
|
16
|
+
|
|
17
|
+
export default meta;
|
|
18
|
+
type Story = StoryObj<typeof meta>;
|
|
19
|
+
|
|
20
|
+
export const Default: Story = {
|
|
21
|
+
args: {
|
|
22
|
+
items: [
|
|
23
|
+
{ label: 'Home', href: '/' },
|
|
24
|
+
{ label: 'Products', href: '/products' },
|
|
25
|
+
{ label: 'Current page' },
|
|
26
|
+
],
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export const TwoLevels: Story = {
|
|
31
|
+
args: {
|
|
32
|
+
items: [
|
|
33
|
+
{ label: 'Home', href: '/' },
|
|
34
|
+
{ label: 'Current page' },
|
|
35
|
+
],
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export const DeepNested: Story = {
|
|
40
|
+
args: {
|
|
41
|
+
items: [
|
|
42
|
+
{ label: 'Home', href: '/' },
|
|
43
|
+
{ label: 'Category', href: '/category' },
|
|
44
|
+
{ label: 'Subcategory', href: '/category/sub' },
|
|
45
|
+
{ label: 'Section', href: '/category/sub/section' },
|
|
46
|
+
{ label: 'Current page' },
|
|
47
|
+
],
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
export const AllVariants: Story = {
|
|
52
|
+
render: () => (
|
|
53
|
+
<div style={{ display: 'flex', flexDirection: 'column', gap: '16px' }}>
|
|
54
|
+
<BdsBreadcrumb items={[{ label: 'Home', href: '/' }, { label: 'Current' }]} />
|
|
55
|
+
<BdsBreadcrumb items={[{ label: 'Home', href: '/' }, { label: 'Products', href: '/products' }, { label: 'Detail' }]} />
|
|
56
|
+
<BdsBreadcrumb items={[{ label: 'Home', href: '/' }, { label: 'A', href: '/a' }, { label: 'B', href: '/a/b' }, { label: 'C', href: '/a/b/c' }, { label: 'Current' }]} />
|
|
57
|
+
</div>
|
|
58
|
+
),
|
|
59
|
+
};
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { Meta, Canvas, ArgTypes } from '@storybook/blocks';
|
|
2
|
+
import * as Stories from './BdsCard.stories';
|
|
3
|
+
|
|
4
|
+
<Meta of={Stories} />
|
|
5
|
+
|
|
6
|
+
# <bds-card>
|
|
7
|
+
|
|
8
|
+
Framework-agnostic Card layout element. Groups related content in a contained surface with optional elevation or outline. Can be made clickable.
|
|
9
|
+
|
|
10
|
+
> **Status: experimental** — API may change before stable release.
|
|
11
|
+
|
|
12
|
+
## Installation
|
|
13
|
+
|
|
14
|
+
```js
|
|
15
|
+
import '@boostdev/components/web-components';
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Examples
|
|
19
|
+
|
|
20
|
+
### All variants
|
|
21
|
+
<Canvas of={Stories.AllVariants} />
|
|
22
|
+
|
|
23
|
+
### Clickable
|
|
24
|
+
<Canvas of={Stories.Interactive} />
|
|
25
|
+
|
|
26
|
+
## Props
|
|
27
|
+
|
|
28
|
+
<ArgTypes of={Stories} />
|
|
29
|
+
|
|
30
|
+
## Attributes
|
|
31
|
+
|
|
32
|
+
| Attribute | Type | Default | Description |
|
|
33
|
+
|-----------|------|---------|-------------|
|
|
34
|
+
| `variant` | `"default" \| "elevated" \| "outlined"` | `"default"` | Visual style |
|
|
35
|
+
| `padding` | `"none" \| "small" \| "medium" \| "large"` | `"medium"` | Internal spacing |
|
|
36
|
+
| `text-align` | `"start" \| "center" \| "end"` | `"start"` | Content alignment |
|
|
37
|
+
| `clickable` | boolean | `false` | Renders as `<button>`, adds hover/active effects |
|
|
38
|
+
| `aria-label` | string | — | Accessible label (required when `clickable` and the card content is not descriptive enough) |
|
|
39
|
+
|
|
40
|
+
## Slots
|
|
41
|
+
|
|
42
|
+
| Slot | Description |
|
|
43
|
+
|------|-------------|
|
|
44
|
+
| `(default)` | Card content |
|
|
45
|
+
|
|
46
|
+
## Events
|
|
47
|
+
|
|
48
|
+
| Event | Detail | Bubbles | Composed | Description |
|
|
49
|
+
|-------|--------|---------|----------|-------------|
|
|
50
|
+
| `bds-click` | — | Yes | Yes | Fired when a clickable card is activated |
|
|
51
|
+
|
|
52
|
+
## CSS Custom Properties
|
|
53
|
+
|
|
54
|
+
| Property | Description |
|
|
55
|
+
|----------|-------------|
|
|
56
|
+
| `--card_color` | Card background colour |
|
|
57
|
+
| `--card_on-color` | Card text colour |
|
|
58
|
+
|
|
59
|
+
## Usage in plain HTML
|
|
60
|
+
|
|
61
|
+
```html
|
|
62
|
+
<bds-card variant="elevated" padding="large">
|
|
63
|
+
<h3>Card title</h3>
|
|
64
|
+
<p>Card body text.</p>
|
|
65
|
+
</bds-card>
|
|
66
|
+
|
|
67
|
+
<bds-card clickable aria-label="View product details">
|
|
68
|
+
<strong>Clickable card</strong>
|
|
69
|
+
</bds-card>
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Listen for click:
|
|
73
|
+
```js
|
|
74
|
+
document.querySelector('bds-card[clickable]').addEventListener('bds-click', () => {
|
|
75
|
+
console.log('card clicked');
|
|
76
|
+
});
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Accessibility
|
|
80
|
+
|
|
81
|
+
- Non-clickable cards are `<div>` elements — they have no interactive role
|
|
82
|
+
- Clickable cards render as `<button>` with keyboard and pointer support
|
|
83
|
+
- Always provide `aria-label` on clickable cards when the text content alone is not descriptive
|