@boostdev/design-system-components 2.14.1 → 2.15.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 +1 -1
- package/dist/client.cjs +52 -52
- package/dist/client.css +600 -599
- package/dist/client.js +52 -52
- package/dist/index.cjs +52 -52
- package/dist/index.css +600 -599
- package/dist/index.js +52 -52
- package/dist/web-components/{chunk-XIZWAWMJ.js → chunk-XTPUKUN5.js} +16 -6
- package/dist/web-components/index.js +1 -1
- package/dist/web-components/interaction/bds-button.js +1 -1
- package/package.json +1 -1
- package/src/components/interaction/Button/Button.mdx +7 -0
- package/src/components/interaction/Button/Button.module.css +17 -9
- package/src/components/interaction/Button/Button.stories.tsx +28 -0
- package/src/web-components/interaction/BdsButton.mdx +8 -0
- package/src/web-components/interaction/BdsButton.stories.tsx +41 -0
- package/src/web-components/interaction/bds-button.ts +16 -6
|
@@ -55,6 +55,12 @@ Pass any `ReactNode` to `iconStart` or `iconEnd`. Icons inherit the button's `cu
|
|
|
55
55
|
<Canvas of={Stories.WithIconEnd} />
|
|
56
56
|
<Canvas of={Stories.WithBothIcons} />
|
|
57
57
|
|
|
58
|
+
### Icon offset across sizes
|
|
59
|
+
|
|
60
|
+
The gap between an icon and the button edge (`--button_icon-offset`) is half the size's inline padding by default, so it scales automatically with `size` and with the responsive space tokens at wider viewports.
|
|
61
|
+
|
|
62
|
+
<Canvas of={Stories.IconOffsetMatrix} />
|
|
63
|
+
|
|
58
64
|
### Icon-only (1:1 aspect ratio)
|
|
59
65
|
|
|
60
66
|
Set `isIconOnly` to render a square button with equal `xs` padding on both axes — composable with any `variant`. The icon sits centred; the button's height (from `size`) determines both width and height. Always pair with `aria-label` — there's no visible text for assistive tech to read.
|
|
@@ -143,6 +149,7 @@ Every public token below can be set on the button or any ancestor — the consum
|
|
|
143
149
|
<tr><td>`--button_radius`</td><td>`var(--bds-border_radius--full)`</td><td>Button border radius.</td></tr>
|
|
144
150
|
<tr><td>`--button_height`</td><td>`3em` (medium)</td><td>Button height. Also drives the width when `isIconOnly` is set.</td></tr>
|
|
145
151
|
<tr><td>`--button_font-size`</td><td>`inherit` (medium)</td><td>Button font size.</td></tr>
|
|
152
|
+
<tr><td>`--button_icon-offset`</td><td>Half of the inline padding for the current size</td><td>How far `iconStart`/`iconEnd` pull into the padding (optical correction). Scales with `size` and with the responsive space tokens by default — override to pin a fixed offset instead.</td></tr>
|
|
146
153
|
</tbody>
|
|
147
154
|
</table>
|
|
148
155
|
|
|
@@ -33,7 +33,9 @@
|
|
|
33
33
|
all: unset;
|
|
34
34
|
position: relative;
|
|
35
35
|
font: inherit;
|
|
36
|
-
|
|
36
|
+
--button_padding-inline--size: var(--bds-space_l);
|
|
37
|
+
|
|
38
|
+
padding-inline: var(--button_padding-inline--size);
|
|
37
39
|
display: inline-flex;
|
|
38
40
|
gap: var(--bds-space_xs);
|
|
39
41
|
border-radius: var(--button_radius, var(--bds-border_radius--full));
|
|
@@ -82,20 +84,17 @@
|
|
|
82
84
|
.button.--size_small {
|
|
83
85
|
--button_height: 2.25em;
|
|
84
86
|
--button_font-size: var(--bds-font_size--body--s);
|
|
85
|
-
|
|
86
|
-
padding-inline: var(--bds-space_m);
|
|
87
|
+
--button_padding-inline--size: var(--bds-space_m);
|
|
87
88
|
}
|
|
88
89
|
|
|
89
90
|
.button.--size_medium {
|
|
90
91
|
--button_height: 3em;
|
|
91
|
-
|
|
92
|
-
padding-inline: var(--bds-space_l);
|
|
92
|
+
--button_padding-inline--size: var(--bds-space_l);
|
|
93
93
|
}
|
|
94
94
|
|
|
95
95
|
.button.--size_large {
|
|
96
96
|
--button_font-size: var(--bds-font_size--heading-3);
|
|
97
|
-
|
|
98
|
-
padding-inline: var(--bds-space_xl);
|
|
97
|
+
--button_padding-inline--size: var(--bds-space_xl);
|
|
99
98
|
}
|
|
100
99
|
|
|
101
100
|
.button.--hasPulse {
|
|
@@ -133,17 +132,26 @@
|
|
|
133
132
|
flex-shrink: 0;
|
|
134
133
|
}
|
|
135
134
|
|
|
135
|
+
/* Icon offset — pulls the icon into the padding so the optical gap between
|
|
136
|
+
icon and edge matches the gap between label and edge. Defaults to half
|
|
137
|
+
the size's inline padding (--button_padding-inline--size, set above per
|
|
138
|
+
--size_*), so it scales automatically with size and with the responsive
|
|
139
|
+
space tokens (space_l/space_xl grow at wider viewports). --button_icon-offset
|
|
140
|
+
is the public override; like the identity tokens above it is intentionally
|
|
141
|
+
read only as a var() fallback here, never declared on .button, so an
|
|
142
|
+
ancestor-set value inherits through instead of being shadowed by a
|
|
143
|
+
same-element declaration. */
|
|
136
144
|
.iconStart {
|
|
137
145
|
display: flex;
|
|
138
146
|
align-items: center;
|
|
139
|
-
margin-inline-start: calc(var(--
|
|
147
|
+
margin-inline-start: calc(var(--button_icon-offset, calc(var(--button_padding-inline--size) / 2)) * -1);
|
|
140
148
|
transition: var(--bds-animation_transition);
|
|
141
149
|
}
|
|
142
150
|
|
|
143
151
|
.iconEnd {
|
|
144
152
|
display: flex;
|
|
145
153
|
align-items: center;
|
|
146
|
-
margin-inline-end: calc(var(--
|
|
154
|
+
margin-inline-end: calc(var(--button_icon-offset, calc(var(--button_padding-inline--size) / 2)) * -1);
|
|
147
155
|
transition: var(--bds-animation_transition);
|
|
148
156
|
}
|
|
149
157
|
|
|
@@ -158,3 +158,31 @@ export const AllIconOnly: Story = {
|
|
|
158
158
|
</div>
|
|
159
159
|
),
|
|
160
160
|
};
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Every size × icon position × variant combination in one grid, so the
|
|
164
|
+
* icon-to-edge offset (which now scales with the size's inline padding —
|
|
165
|
+
* see `--button_icon-offset` in the CSS variables docs) can be eyeballed
|
|
166
|
+
* and measured across viewports. Each button's label states its own
|
|
167
|
+
* variant/size/position so a verification script can find the right
|
|
168
|
+
* `.iconStart`/`.iconEnd` span via the button's accessible name and read
|
|
169
|
+
* `getComputedStyle(span).marginInlineStart` / `marginInlineEnd`.
|
|
170
|
+
*/
|
|
171
|
+
export const IconOffsetMatrix: Story = {
|
|
172
|
+
render: () => (
|
|
173
|
+
<div style={{ display: 'flex', flexDirection: 'column', gap: '16px' }}>
|
|
174
|
+
{(['small', 'medium', 'large'] as const).map(s => (
|
|
175
|
+
<div key={s} style={{ display: 'flex', gap: '12px', flexWrap: 'wrap', alignItems: 'center' }}>
|
|
176
|
+
{(['default', 'outline'] as const).flatMap(v => [
|
|
177
|
+
<Button key={`${v}-${s}-start`} variant={v} size={s} iconStart={CheckIcon}>
|
|
178
|
+
{v} {s} start
|
|
179
|
+
</Button>,
|
|
180
|
+
<Button key={`${v}-${s}-end`} variant={v} size={s} iconEnd={CheckIcon}>
|
|
181
|
+
{v} {s} end
|
|
182
|
+
</Button>,
|
|
183
|
+
])}
|
|
184
|
+
</div>
|
|
185
|
+
))}
|
|
186
|
+
</div>
|
|
187
|
+
),
|
|
188
|
+
};
|
|
@@ -54,6 +54,13 @@ Slot an SVG (or any element) into `icon-start` or `icon-end`:
|
|
|
54
54
|
<Canvas of={Stories.WithIconStart} />
|
|
55
55
|
<Canvas of={Stories.WithIconEnd} />
|
|
56
56
|
|
|
57
|
+
### Icon offset across sizes
|
|
58
|
+
|
|
59
|
+
The gap between an icon and the button edge (`--button_icon-offset`) is half the size's inline padding by default, so it scales automatically with `size` and with the responsive space tokens at wider viewports. Set `--button_icon-offset` on the host or an ancestor to override it — it inherits across the shadow boundary.
|
|
60
|
+
|
|
61
|
+
<Canvas of={Stories.IconOffsetMatrix} />
|
|
62
|
+
<Canvas of={Stories.IconOffsetOverride} />
|
|
63
|
+
|
|
57
64
|
### Icon-only (1:1 aspect ratio)
|
|
58
65
|
|
|
59
66
|
Set the `is-icon-only` attribute to render a square button with equal `var(--bds-space_xxs)` padding on both axes. Composable with any `variant`. Always pair with `aria-label` — there's no visible label text for assistive tech to read.
|
|
@@ -107,6 +114,7 @@ Set the `is-icon-only` attribute to render a square button with equal `var(--bds
|
|
|
107
114
|
|----------|-------------|
|
|
108
115
|
| `--button_color` | Identity colour — fills the default variant, outlines the outline variant |
|
|
109
116
|
| `--button_on-color` | Text/icon colour on the button surface. Pair with `--button_color` |
|
|
117
|
+
| `--button_icon-offset` | How far the icon slots pull into the padding (optical correction). Defaults to half the inline padding for the current `size`, so it scales with `size` and the responsive space tokens. Inherits across the shadow boundary — set it on the host or an ancestor. |
|
|
110
118
|
|
|
111
119
|
## Form participation
|
|
112
120
|
|
|
@@ -210,3 +210,44 @@ export const AllIconOnly: Story = {
|
|
|
210
210
|
</div>
|
|
211
211
|
),
|
|
212
212
|
};
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Every size × icon position × variant combination, mirroring the React
|
|
216
|
+
* `IconOffsetMatrix` story. The icon-to-edge offset (`--button_icon-offset`,
|
|
217
|
+
* defaulting to half the size's inline padding) is set inside the shadow DOM,
|
|
218
|
+
* so this also confirms React and the web component stay pixel-identical.
|
|
219
|
+
*/
|
|
220
|
+
export const IconOffsetMatrix: Story = {
|
|
221
|
+
render: () => (
|
|
222
|
+
<div style={{ display: 'flex', flexDirection: 'column', gap: '16px' }}>
|
|
223
|
+
{(['small', 'medium', 'large'] as const).map(s => (
|
|
224
|
+
<div key={s} style={{ display: 'flex', gap: '12px', flexWrap: 'wrap', alignItems: 'center' }}>
|
|
225
|
+
{(['default', 'outline'] as const).flatMap(v => [
|
|
226
|
+
<BdsButton key={`${v}-${s}-start`} variant={v} size={s} iconStart={CheckIcon}>
|
|
227
|
+
{v} {s} start
|
|
228
|
+
</BdsButton>,
|
|
229
|
+
<BdsButton key={`${v}-${s}-end`} variant={v} size={s} iconEnd={ArrowRightEnd}>
|
|
230
|
+
{v} {s} end
|
|
231
|
+
</BdsButton>,
|
|
232
|
+
])}
|
|
233
|
+
</div>
|
|
234
|
+
))}
|
|
235
|
+
</div>
|
|
236
|
+
),
|
|
237
|
+
};
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* `--button_icon-offset` set on a plain wrapper `<div>` (light DOM, an
|
|
241
|
+
* ancestor of the `<bds-button>` host) inherits across the shadow boundary
|
|
242
|
+
* and overrides the default half-padding calculation inside the shadow tree —
|
|
243
|
+
* confirming the token is a real public override point for the web component.
|
|
244
|
+
*/
|
|
245
|
+
export const IconOffsetOverride: Story = {
|
|
246
|
+
render: () => (
|
|
247
|
+
<div style={{ '--button_icon-offset': '4px' } as React.CSSProperties}>
|
|
248
|
+
<BdsButton size="large" iconStart={CheckIcon}>
|
|
249
|
+
Fixed 4px offset
|
|
250
|
+
</BdsButton>
|
|
251
|
+
</div>
|
|
252
|
+
),
|
|
253
|
+
};
|
|
@@ -70,7 +70,9 @@ export class BdsButton extends LitElement {
|
|
|
70
70
|
all: unset;
|
|
71
71
|
position: relative;
|
|
72
72
|
font: inherit;
|
|
73
|
-
|
|
73
|
+
--button_padding-inline--size: var(--bds-space_l);
|
|
74
|
+
|
|
75
|
+
padding-inline: var(--button_padding-inline--size);
|
|
74
76
|
display: inline-flex;
|
|
75
77
|
gap: var(--bds-space_xs);
|
|
76
78
|
border-radius: var(--button_radius, var(--bds-border_radius--full));
|
|
@@ -120,17 +122,17 @@ export class BdsButton extends LitElement {
|
|
|
120
122
|
.button.small {
|
|
121
123
|
--button_height: 2.25em;
|
|
122
124
|
--button_font-size: var(--bds-font_size--body--s);
|
|
123
|
-
|
|
125
|
+
--button_padding-inline--size: var(--bds-space_m);
|
|
124
126
|
}
|
|
125
127
|
|
|
126
128
|
.button.medium {
|
|
127
129
|
--button_height: 3em;
|
|
128
|
-
|
|
130
|
+
--button_padding-inline--size: var(--bds-space_l);
|
|
129
131
|
}
|
|
130
132
|
|
|
131
133
|
.button.large {
|
|
132
134
|
--button_font-size: var(--bds-font_size--heading-3);
|
|
133
|
-
|
|
135
|
+
--button_padding-inline--size: var(--bds-space_xl);
|
|
134
136
|
}
|
|
135
137
|
|
|
136
138
|
/* Pulse */
|
|
@@ -173,15 +175,23 @@ export class BdsButton extends LitElement {
|
|
|
173
175
|
align-items: center;
|
|
174
176
|
}
|
|
175
177
|
|
|
178
|
+
/* Icon offset — pulls the icon into the padding so the optical gap between
|
|
179
|
+
icon and edge matches the gap between label and edge. Defaults to half
|
|
180
|
+
the size's inline padding (--button_padding-inline--size, set above per
|
|
181
|
+
size), so it scales automatically with size and with the responsive
|
|
182
|
+
space tokens. --button_icon-offset is the public override; it is read
|
|
183
|
+
only as a var() fallback here, never declared on .button, so a value
|
|
184
|
+
set on the host or an ancestor inherits through the shadow boundary
|
|
185
|
+
instead of being shadowed by a same-element declaration. */
|
|
176
186
|
.icon-start.has-content {
|
|
177
187
|
display: flex;
|
|
178
|
-
margin-inline-start: calc(var(--
|
|
188
|
+
margin-inline-start: calc(var(--button_icon-offset, calc(var(--button_padding-inline--size) / 2)) * -1);
|
|
179
189
|
transition: var(--bds-animation_transition);
|
|
180
190
|
}
|
|
181
191
|
|
|
182
192
|
.icon-end.has-content {
|
|
183
193
|
display: flex;
|
|
184
|
-
margin-inline-end: calc(var(--
|
|
194
|
+
margin-inline-end: calc(var(--button_icon-offset, calc(var(--button_padding-inline--size) / 2)) * -1);
|
|
185
195
|
transition: var(--bds-animation_transition);
|
|
186
196
|
}
|
|
187
197
|
|