@boostdev/design-system-components 2.6.0 → 2.7.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.
- package/AGENTS.md +102 -2
- package/dist/client.cjs +257 -219
- package/dist/client.css +587 -539
- package/dist/client.d.cts +27 -1
- package/dist/client.d.ts +27 -1
- package/dist/client.js +220 -183
- package/dist/index.cjs +257 -219
- package/dist/index.css +587 -539
- package/dist/index.d.cts +27 -1
- package/dist/index.d.ts +27 -1
- package/dist/index.js +220 -183
- package/dist/web-components/{chunk-T6AETZRP.js → chunk-3GFWLSLS.js} +1 -1
- package/dist/web-components/{chunk-N6IMUOY4.js → chunk-65JXQOBA.js} +3 -3
- package/dist/web-components/{chunk-ZTC6GRP7.js → chunk-BKIHQYJR.js} +1 -0
- package/dist/web-components/{chunk-X3FKVHLK.js → chunk-CM3KYZ6Z.js} +1 -1
- package/dist/web-components/{chunk-QLZ2362S.js → chunk-CZBIVR4V.js} +1 -1
- package/dist/web-components/{chunk-GER5UJOF.js → chunk-F5E3IT7G.js} +1 -3
- package/dist/web-components/{chunk-UFFCKVZE.js → chunk-FXURM6D5.js} +1 -1
- package/dist/web-components/{chunk-HHHRF2PS.js → chunk-IYGF6CD5.js} +1 -1
- package/dist/web-components/{chunk-OCODKRVZ.js → chunk-KUI55GFB.js} +2 -2
- package/dist/web-components/{chunk-ZNKEZIYE.js → chunk-NCPQ7AF3.js} +3 -2
- package/dist/web-components/{chunk-RTOS7LLG.js → chunk-PC3IOQAH.js} +3 -8
- package/dist/web-components/{chunk-JUKB3BUP.js → chunk-PXZWYO6Z.js} +1 -1
- package/dist/web-components/{chunk-EBJM3VD4.js → chunk-QBB6ZX4R.js} +1 -1
- package/dist/web-components/{chunk-ECW3HHWA.js → chunk-TQ7IQ4GZ.js} +7 -2
- package/dist/web-components/{chunk-AJSXNDAP.js → chunk-X46KL5BK.js} +19 -18
- package/dist/web-components/{chunk-XNA6WTXG.js → chunk-Y3POAKGS.js} +1 -1
- package/dist/web-components/{chunk-HGBNDR22.js → chunk-Y7V7LM6R.js} +1 -1
- package/dist/web-components/index.d.ts +56 -1
- package/dist/web-components/index.js +140 -19
- package/dist/web-components/interaction/bds-accordion-item.js +1 -1
- package/dist/web-components/interaction/bds-accordion.js +1 -1
- 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/bds-popover.js +1 -1
- package/dist/web-components/interaction/bds-tooltip.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-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.d.ts +3 -9
- package/dist/web-components/ui/bds-card.js +1 -1
- package/dist/web-components/ui/bds-notification-banner.js +1 -1
- package/package.json +4 -2
- package/src/components/interaction/form/FieldGroup/FieldGroup.mdx +113 -0
- package/src/components/interaction/form/FieldGroup/FieldGroup.module.css +96 -0
- package/src/components/interaction/form/FieldGroup/FieldGroup.spec.tsx +196 -0
- package/src/components/interaction/form/FieldGroup/FieldGroup.stories.tsx +99 -0
- package/src/components/interaction/form/FieldGroup/FieldGroup.tsx +64 -0
- package/src/components/interaction/form/FieldGroup/index.ts +2 -0
- package/src/components/interaction/form/atoms/Message.module.css +4 -0
- package/src/components/layout/IconWrapper/IconWrapper.module.css +2 -2
- package/src/index.ts +2 -0
- package/src/test/token-contract.spec.ts +86 -0
- package/src/web-components/index.ts +2 -0
- package/src/web-components/interaction/bds-accordion-item.ts +1 -1
- package/src/web-components/interaction/bds-accordion.ts +1 -0
- package/src/web-components/interaction/bds-button.ts +1 -3
- package/src/web-components/interaction/bds-dialog.ts +3 -3
- package/src/web-components/interaction/bds-drawer.ts +2 -2
- package/src/web-components/interaction/bds-popover.ts +7 -2
- package/src/web-components/interaction/bds-tooltip.ts +1 -1
- package/src/web-components/interaction/form/BdsFieldGroup.mdx +67 -0
- package/src/web-components/interaction/form/BdsFieldGroup.stories.tsx +110 -0
- package/src/web-components/interaction/form/bds-checkbox-group.ts +1 -0
- package/src/web-components/interaction/form/bds-checkbox.ts +1 -1
- package/src/web-components/interaction/form/bds-combobox.ts +1 -1
- package/src/web-components/interaction/form/bds-field-group.spec.ts +64 -0
- package/src/web-components/interaction/form/bds-field-group.ts +157 -0
- package/src/web-components/interaction/form/bds-form-input.ts +2 -1
- package/src/web-components/interaction/form/bds-number-input.ts +1 -1
- package/src/web-components/interaction/form/bds-radio-group.ts +1 -0
- package/src/web-components/interaction/form/bds-radio.ts +1 -1
- package/src/web-components/interaction/form/bds-select.ts +1 -1
- package/src/web-components/interaction/form/bds-switch.ts +1 -1
- package/src/web-components/interaction/form/bds-textarea.ts +1 -1
- package/src/web-components/ui/BdsCard.mdx +4 -3
- package/src/web-components/ui/BdsCard.stories.tsx +7 -11
- package/src/web-components/ui/BdsSkeleton.stories.tsx +4 -4
- package/src/web-components/ui/bds-alert.ts +3 -2
- package/src/web-components/ui/bds-card.spec.ts +3 -5
- package/src/web-components/ui/bds-card.ts +5 -12
- package/src/web-components/ui/bds-notification-banner.ts +19 -18
- package/src/web-components/ui/bds-pagination.ts +1 -1
- package/src/web-components/ui/bds-table.ts +4 -0
|
@@ -1,39 +1,39 @@
|
|
|
1
1
|
import {
|
|
2
2
|
BdsSwitch
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-Y3POAKGS.js";
|
|
4
4
|
import {
|
|
5
5
|
BdsTextarea
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-QBB6ZX4R.js";
|
|
7
7
|
import {
|
|
8
8
|
BdsCheckbox
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-3GFWLSLS.js";
|
|
10
10
|
import {
|
|
11
11
|
BdsCombobox
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-CZBIVR4V.js";
|
|
13
13
|
import {
|
|
14
14
|
BdsFileInput
|
|
15
15
|
} from "./chunk-PY62FTRW.js";
|
|
16
16
|
import {
|
|
17
17
|
BdsNumberInput
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-PXZWYO6Z.js";
|
|
19
19
|
import {
|
|
20
20
|
BdsRadio
|
|
21
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-IYGF6CD5.js";
|
|
22
22
|
import {
|
|
23
23
|
BdsSegmentedControl
|
|
24
24
|
} from "./chunk-2FGATTGT.js";
|
|
25
25
|
import {
|
|
26
26
|
BdsSelect
|
|
27
|
-
} from "./chunk-
|
|
27
|
+
} from "./chunk-CM3KYZ6Z.js";
|
|
28
28
|
import {
|
|
29
29
|
BdsSlider
|
|
30
30
|
} from "./chunk-7FMR53BW.js";
|
|
31
31
|
import {
|
|
32
32
|
BdsDrawer
|
|
33
|
-
} from "./chunk-
|
|
33
|
+
} from "./chunk-KUI55GFB.js";
|
|
34
34
|
import {
|
|
35
35
|
BdsPopover
|
|
36
|
-
} from "./chunk-
|
|
36
|
+
} from "./chunk-TQ7IQ4GZ.js";
|
|
37
37
|
import {
|
|
38
38
|
BdsSkipLink
|
|
39
39
|
} from "./chunk-BQLZ7I4G.js";
|
|
@@ -51,7 +51,7 @@ import {
|
|
|
51
51
|
} from "./chunk-YLVTEY23.js";
|
|
52
52
|
import {
|
|
53
53
|
BdsTooltip
|
|
54
|
-
} from "./chunk-
|
|
54
|
+
} from "./chunk-Y7V7LM6R.js";
|
|
55
55
|
import {
|
|
56
56
|
BdsSeparator
|
|
57
57
|
} from "./chunk-VMMVWLXL.js";
|
|
@@ -63,19 +63,19 @@ import {
|
|
|
63
63
|
} from "./chunk-SOQQ7RVJ.js";
|
|
64
64
|
import {
|
|
65
65
|
BdsAccordion
|
|
66
|
-
} from "./chunk-
|
|
66
|
+
} from "./chunk-BKIHQYJR.js";
|
|
67
67
|
import {
|
|
68
68
|
BdsAccordionItem
|
|
69
|
-
} from "./chunk-
|
|
69
|
+
} from "./chunk-FXURM6D5.js";
|
|
70
70
|
import {
|
|
71
71
|
BdsButton
|
|
72
|
-
} from "./chunk-
|
|
72
|
+
} from "./chunk-F5E3IT7G.js";
|
|
73
73
|
import {
|
|
74
74
|
BdsCollapsible
|
|
75
75
|
} from "./chunk-6I2DBFQ7.js";
|
|
76
76
|
import {
|
|
77
77
|
BdsDialog
|
|
78
|
-
} from "./chunk-
|
|
78
|
+
} from "./chunk-65JXQOBA.js";
|
|
79
79
|
import {
|
|
80
80
|
BdsIconWrapper
|
|
81
81
|
} from "./chunk-5TFWOPLH.js";
|
|
@@ -87,7 +87,7 @@ import {
|
|
|
87
87
|
} from "./chunk-5R6IFELV.js";
|
|
88
88
|
import {
|
|
89
89
|
BdsNotificationBanner
|
|
90
|
-
} from "./chunk-
|
|
90
|
+
} from "./chunk-X46KL5BK.js";
|
|
91
91
|
import {
|
|
92
92
|
BdsProgress
|
|
93
93
|
} from "./chunk-ITHLKR7Q.js";
|
|
@@ -104,7 +104,7 @@ import "./chunk-QPOKHLMQ.js";
|
|
|
104
104
|
import "./chunk-3S42DZ7W.js";
|
|
105
105
|
import {
|
|
106
106
|
BdsAlert
|
|
107
|
-
} from "./chunk-
|
|
107
|
+
} from "./chunk-NCPQ7AF3.js";
|
|
108
108
|
import {
|
|
109
109
|
BdsAvatar
|
|
110
110
|
} from "./chunk-57TRNCWQ.js";
|
|
@@ -116,11 +116,12 @@ import {
|
|
|
116
116
|
} from "./chunk-Q4T5BJT6.js";
|
|
117
117
|
import {
|
|
118
118
|
BdsCard
|
|
119
|
-
} from "./chunk-
|
|
119
|
+
} from "./chunk-PC3IOQAH.js";
|
|
120
120
|
import {
|
|
121
121
|
BdsDescriptionList
|
|
122
122
|
} from "./chunk-AGKJTMJI.js";
|
|
123
123
|
import {
|
|
124
|
+
A,
|
|
124
125
|
T,
|
|
125
126
|
i,
|
|
126
127
|
i2
|
|
@@ -621,6 +622,10 @@ var BdsTable = class extends i2 {
|
|
|
621
622
|
.wrapper {
|
|
622
623
|
overflow-inline: auto;
|
|
623
624
|
-webkit-overflow-scrolling: touch;
|
|
625
|
+
border: var(--table_border, none);
|
|
626
|
+
border-radius: var(--table_radius, var(--bds-border_radius--s));
|
|
627
|
+
--bdc_color: var(--bds-color_bg--subtle);
|
|
628
|
+
box-shadow: inset 0 0 0 var(--bdc-outline_width) var(--bdc_color);
|
|
624
629
|
}
|
|
625
630
|
|
|
626
631
|
::slotted(table) {
|
|
@@ -723,7 +728,7 @@ var BdsPagination = class extends i2 {
|
|
|
723
728
|
cursor: pointer;
|
|
724
729
|
color: var(--bds-color_on-bg);
|
|
725
730
|
transition: var(--bds-animation_transition);
|
|
726
|
-
--bdc_color: transparent;
|
|
731
|
+
--bdc_color: var(--pagination_border-color, transparent);
|
|
727
732
|
--bdc-outline_radius: var(--bds-border_radius--xs);
|
|
728
733
|
box-shadow: inset 0 0 0 var(--bdc-outline_width) var(--bdc_color), var(--bdc-outline_shadow);
|
|
729
734
|
}
|
|
@@ -881,6 +886,7 @@ var BdsCheckboxGroup = class extends i2 {
|
|
|
881
886
|
|
|
882
887
|
.message--hint {
|
|
883
888
|
color: var(--bds-color_on-bg--subtle);
|
|
889
|
+
font-style: italic;
|
|
884
890
|
}
|
|
885
891
|
`;
|
|
886
892
|
static properties = {
|
|
@@ -957,6 +963,7 @@ var BdsRadioGroup = class extends i2 {
|
|
|
957
963
|
|
|
958
964
|
.message--hint {
|
|
959
965
|
color: var(--bds-color_on-bg--subtle);
|
|
966
|
+
font-style: italic;
|
|
960
967
|
}
|
|
961
968
|
`;
|
|
962
969
|
static properties = {
|
|
@@ -1007,6 +1014,118 @@ var BdsRadioGroup = class extends i2 {
|
|
|
1007
1014
|
};
|
|
1008
1015
|
customElements.define("bds-radio-group", BdsRadioGroup);
|
|
1009
1016
|
|
|
1017
|
+
// src/web-components/interaction/form/bds-field-group.ts
|
|
1018
|
+
var BdsFieldGroup = class extends i2 {
|
|
1019
|
+
static styles = i`
|
|
1020
|
+
:host {
|
|
1021
|
+
display: block;
|
|
1022
|
+
|
|
1023
|
+
/* Establish an inline-size containment context so the @container rule
|
|
1024
|
+
queries the host's own width — independent of the viewport. */
|
|
1025
|
+
container-type: inline-size;
|
|
1026
|
+
container-name: field-group;
|
|
1027
|
+
|
|
1028
|
+
/* Auto-derived collapse threshold (mirror of the React component).
|
|
1029
|
+
--fieldGroup_field-count is set inline by _onSlotChange; the other
|
|
1030
|
+
tokens use foundation-default fallbacks so the calc rebuilds when
|
|
1031
|
+
a consumer overrides --fieldGroup_min-field-width or _gap. */
|
|
1032
|
+
--fieldGroup_collapse-threshold:
|
|
1033
|
+
calc(
|
|
1034
|
+
var(--fieldGroup_field-count, 1)
|
|
1035
|
+
* var(--fieldGroup_min-field-width, 12rem)
|
|
1036
|
+
+ (var(--fieldGroup_field-count, 1) - 1)
|
|
1037
|
+
* var(--fieldGroup_gap, var(--bds-space_m))
|
|
1038
|
+
);
|
|
1039
|
+
}
|
|
1040
|
+
|
|
1041
|
+
fieldset {
|
|
1042
|
+
border: 0;
|
|
1043
|
+
margin: 0;
|
|
1044
|
+
padding: 0;
|
|
1045
|
+
min-inline-size: 0;
|
|
1046
|
+
}
|
|
1047
|
+
|
|
1048
|
+
.legend {
|
|
1049
|
+
inline-size: 100%;
|
|
1050
|
+
padding-inline: 0;
|
|
1051
|
+
|
|
1052
|
+
padding-block:
|
|
1053
|
+
var(--fieldGroup_legend-padding-block, var(--bds-space_xs));
|
|
1054
|
+
margin-block-end:
|
|
1055
|
+
var(--fieldGroup_legend-gap, var(--bds-space_m));
|
|
1056
|
+
border-block-end:
|
|
1057
|
+
var(--fieldGroup_legend-border-block-end, 1px solid var(--bds-color_bg--subtle));
|
|
1058
|
+
|
|
1059
|
+
color:
|
|
1060
|
+
var(--fieldGroup_legend-color, var(--bds-color_on-bg));
|
|
1061
|
+
font-family: var(--bds-font_family--body);
|
|
1062
|
+
font-size:
|
|
1063
|
+
var(--fieldGroup_legend-font-size, var(--bds-font_size--heading-3));
|
|
1064
|
+
font-weight:
|
|
1065
|
+
var(--fieldGroup_legend-font-weight, var(--bds-font_weight--semibold));
|
|
1066
|
+
line-height:
|
|
1067
|
+
var(--fieldGroup_legend-line-height, var(--bds-font_line-height--heading));
|
|
1068
|
+
}
|
|
1069
|
+
|
|
1070
|
+
.fields {
|
|
1071
|
+
display: flex;
|
|
1072
|
+
flex-direction: column;
|
|
1073
|
+
gap: var(--fieldGroup_gap, var(--bds-space_m));
|
|
1074
|
+
}
|
|
1075
|
+
|
|
1076
|
+
:host([variant='horizontal']) .fields {
|
|
1077
|
+
flex-flow: row wrap;
|
|
1078
|
+
}
|
|
1079
|
+
|
|
1080
|
+
:host([variant='horizontal']) .fields ::slotted(*) {
|
|
1081
|
+
flex: 1 1 var(--fieldGroup_min-field-width, 12rem);
|
|
1082
|
+
min-inline-size: 0;
|
|
1083
|
+
}
|
|
1084
|
+
|
|
1085
|
+
/* Auto-collapse: when the host's inline-size can't fit a complete
|
|
1086
|
+
horizontal row, switch to a single-column stack. Threshold scales
|
|
1087
|
+
with the actual slotted-element count (see :host calc above). */
|
|
1088
|
+
@container field-group (max-inline-size: var(--fieldGroup_collapse-threshold)) {
|
|
1089
|
+
:host([variant='horizontal']) .fields {
|
|
1090
|
+
flex-direction: column;
|
|
1091
|
+
}
|
|
1092
|
+
|
|
1093
|
+
:host([variant='horizontal']) .fields ::slotted(*) {
|
|
1094
|
+
flex: 1 1 auto;
|
|
1095
|
+
}
|
|
1096
|
+
}
|
|
1097
|
+
`;
|
|
1098
|
+
static properties = {
|
|
1099
|
+
variant: { type: String, reflect: true },
|
|
1100
|
+
legend: { type: String },
|
|
1101
|
+
disabled: { type: Boolean, reflect: true }
|
|
1102
|
+
};
|
|
1103
|
+
constructor() {
|
|
1104
|
+
super();
|
|
1105
|
+
this.variant = "horizontal";
|
|
1106
|
+
this.legend = "";
|
|
1107
|
+
this.disabled = false;
|
|
1108
|
+
}
|
|
1109
|
+
// Arrow-bound for stable identity (unused here but matches the
|
|
1110
|
+
// bds-popover / bds-button conventions for handlers attached in render).
|
|
1111
|
+
_onSlotChange = (e) => {
|
|
1112
|
+
const slot = e.target;
|
|
1113
|
+
const count = slot.assignedElements().length;
|
|
1114
|
+
this.style.setProperty("--fieldGroup_field-count", String(count));
|
|
1115
|
+
};
|
|
1116
|
+
render() {
|
|
1117
|
+
return T`
|
|
1118
|
+
<fieldset ?disabled=${this.disabled}>
|
|
1119
|
+
${this.legend ? T`<legend class="legend">${this.legend}</legend>` : A}
|
|
1120
|
+
<div class="fields">
|
|
1121
|
+
<slot @slotchange=${this._onSlotChange}></slot>
|
|
1122
|
+
</div>
|
|
1123
|
+
</fieldset>
|
|
1124
|
+
`;
|
|
1125
|
+
}
|
|
1126
|
+
};
|
|
1127
|
+
customElements.define("bds-field-group", BdsFieldGroup);
|
|
1128
|
+
|
|
1010
1129
|
// src/web-components/interaction/form/bds-form-input.ts
|
|
1011
1130
|
var BdsFormInput = class extends i2 {
|
|
1012
1131
|
static formAssociated = true;
|
|
@@ -1038,7 +1157,7 @@ var BdsFormInput = class extends i2 {
|
|
|
1038
1157
|
position: relative;
|
|
1039
1158
|
display: flex;
|
|
1040
1159
|
align-items: center;
|
|
1041
|
-
--bdc_color: currentcolor;
|
|
1160
|
+
--bdc_color: var(--formInput_border-color, currentcolor);
|
|
1042
1161
|
--bdc-outline_radius: var(--bds-border_radius--xs);
|
|
1043
1162
|
|
|
1044
1163
|
border-radius: var(--formInput_radius, var(--bdc-outline_radius));
|
|
@@ -1118,6 +1237,7 @@ var BdsFormInput = class extends i2 {
|
|
|
1118
1237
|
|
|
1119
1238
|
.message--hint {
|
|
1120
1239
|
color: var(--bds-color_on-bg--subtle);
|
|
1240
|
+
font-style: italic;
|
|
1121
1241
|
}
|
|
1122
1242
|
`;
|
|
1123
1243
|
static properties = {
|
|
@@ -2068,6 +2188,7 @@ export {
|
|
|
2068
2188
|
BdsDrawer,
|
|
2069
2189
|
BdsDropdownMenu,
|
|
2070
2190
|
BdsDropdownMenuItem,
|
|
2191
|
+
BdsFieldGroup,
|
|
2071
2192
|
BdsFileInput,
|
|
2072
2193
|
BdsFormInput,
|
|
2073
2194
|
BdsGrid,
|
|
@@ -2,14 +2,13 @@ import * as lit from 'lit';
|
|
|
2
2
|
import { LitElement } from 'lit';
|
|
3
3
|
|
|
4
4
|
type CardVariant = 'default' | 'elevated' | 'outlined';
|
|
5
|
-
type CardPadding = 'none' | 'small' | 'medium' | 'large';
|
|
6
5
|
type CardTextAlign = 'start' | 'center' | 'end';
|
|
7
6
|
/**
|
|
8
7
|
* `<bds-card>` — framework-agnostic Card layout custom element.
|
|
9
8
|
*
|
|
10
9
|
* Attributes:
|
|
11
10
|
* variant — "default" (default) | "elevated" | "outlined"
|
|
12
|
-
*
|
|
11
|
+
* --card_padding — CSS custom property to override padding (default: var(--bds-space_m))
|
|
13
12
|
* text-align — "start" (default) | "center" | "end"
|
|
14
13
|
* clickable — boolean; renders as a <button> with hover/active effects
|
|
15
14
|
* aria-label — accessible label (useful when clickable)
|
|
@@ -21,7 +20,7 @@ type CardTextAlign = 'start' | 'center' | 'end';
|
|
|
21
20
|
* bds-click — fired (bubbles, composed) when the card button is clicked
|
|
22
21
|
*
|
|
23
22
|
* @example
|
|
24
|
-
* <bds-card variant="elevated"
|
|
23
|
+
* <bds-card variant="elevated" style="--card_padding: var(--bds-space_l)">
|
|
25
24
|
* <p>Card content</p>
|
|
26
25
|
* </bds-card>
|
|
27
26
|
*
|
|
@@ -36,10 +35,6 @@ declare class BdsCard extends LitElement {
|
|
|
36
35
|
type: StringConstructor;
|
|
37
36
|
reflect: boolean;
|
|
38
37
|
};
|
|
39
|
-
padding: {
|
|
40
|
-
type: StringConstructor;
|
|
41
|
-
reflect: boolean;
|
|
42
|
-
};
|
|
43
38
|
textAlign: {
|
|
44
39
|
type: StringConstructor;
|
|
45
40
|
attribute: string;
|
|
@@ -55,7 +50,6 @@ declare class BdsCard extends LitElement {
|
|
|
55
50
|
};
|
|
56
51
|
};
|
|
57
52
|
variant: CardVariant;
|
|
58
|
-
padding: CardPadding;
|
|
59
53
|
textAlign: CardTextAlign;
|
|
60
54
|
clickable: boolean;
|
|
61
55
|
ariaLabel: string;
|
|
@@ -69,4 +63,4 @@ declare global {
|
|
|
69
63
|
}
|
|
70
64
|
}
|
|
71
65
|
|
|
72
|
-
export { BdsCard, type
|
|
66
|
+
export { BdsCard, type CardTextAlign, type CardVariant };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@boostdev/design-system-components",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.7.1",
|
|
4
4
|
"description": "BoostDev React component library: accessible, token-driven components built on @boostdev/design-system-foundation",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"React",
|
|
@@ -306,6 +306,7 @@
|
|
|
306
306
|
"storybook-addon-tag-badges": "^1.4.0",
|
|
307
307
|
"stylelint": "^16",
|
|
308
308
|
"stylelint-config-standard": "^37",
|
|
309
|
+
"stylelint-declaration-strict-value": "^1.11.1",
|
|
309
310
|
"tsup": "^8",
|
|
310
311
|
"tsx": "^4",
|
|
311
312
|
"typescript": "^5.8",
|
|
@@ -335,5 +336,6 @@
|
|
|
335
336
|
],
|
|
336
337
|
"dependencies": {
|
|
337
338
|
"@oddbird/css-anchor-positioning": "^0.9.0"
|
|
338
|
-
}
|
|
339
|
+
},
|
|
340
|
+
"packageManager": "pnpm@11.0.8"
|
|
339
341
|
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { Meta, Canvas, ArgTypes } from '@storybook/blocks';
|
|
2
|
+
import * as Stories from './FieldGroup.stories';
|
|
3
|
+
|
|
4
|
+
<Meta of={Stories} />
|
|
5
|
+
|
|
6
|
+
# FieldGroup
|
|
7
|
+
|
|
8
|
+
Semantically groups related form fields under a single `<fieldset>` and lays them out either horizontally (with a CSS container query that collapses to a vertical stack when the FieldGroup itself is too narrow) or vertically.
|
|
9
|
+
|
|
10
|
+
Use this any time multiple fields belong to the same conceptual section — contact details, address, search filters, registration step — and you want them grouped for screen readers AND visually arranged on a single row when there's room.
|
|
11
|
+
|
|
12
|
+
## When to use
|
|
13
|
+
|
|
14
|
+
- Two or more related form fields that should sit side by side on wide screens.
|
|
15
|
+
- Sections inside a longer form that need a visual + semantic boundary.
|
|
16
|
+
- A fieldset whose layout should adapt to its **container's** width, not the viewport's (e.g. a form rendered inside a sidebar or dialog).
|
|
17
|
+
|
|
18
|
+
## When **not** to use
|
|
19
|
+
|
|
20
|
+
- A group of related checkboxes — use `CheckboxGroup` instead (it manages legend + error/hint slots specifically for the boolean-list case).
|
|
21
|
+
- A group of related radio inputs — use `RadioGroup`.
|
|
22
|
+
- A single field — wrap nothing; just render the field.
|
|
23
|
+
|
|
24
|
+
## Variants
|
|
25
|
+
|
|
26
|
+
- **`horizontal`** (default) — fields flow into a row; each claims at least `--fieldGroup_min-field-width`. When the FieldGroup's own inline-size drops below the **auto-derived** threshold (`N × min-field-width + (N − 1) × gap`, where `N` is the actual number of children), the layout collapses to a single column via a CSS container query. A 2-field group collapses earlier than a 5-field group; you don't have to tune anything per call site.
|
|
27
|
+
- **`vertical`** — fields always stack one per row.
|
|
28
|
+
|
|
29
|
+
<Canvas of={Stories.Horizontal} />
|
|
30
|
+
<Canvas of={Stories.Vertical} />
|
|
31
|
+
|
|
32
|
+
### Container query in action
|
|
33
|
+
|
|
34
|
+
The collapse-to-vertical threshold measures the **FieldGroup itself**, not the viewport. The FieldGroup below sits inside a 20 rem wrapper, so the same horizontal variant collapses cleanly to a single column even though the page is wide.
|
|
35
|
+
|
|
36
|
+
<Canvas of={Stories.HorizontalCollapsesInNarrowContainer} />
|
|
37
|
+
|
|
38
|
+
### Mixed inputs
|
|
39
|
+
|
|
40
|
+
Any form input works as a child — `FormInput`, `Select`, `Combobox`, `NumberInput`, `Textarea`, `Switch`, etc.
|
|
41
|
+
|
|
42
|
+
<Canvas of={Stories.WithSelectAndInputs} />
|
|
43
|
+
|
|
44
|
+
### Without a legend
|
|
45
|
+
|
|
46
|
+
Omit `legend` and provide an `aria-label` (or `aria-labelledby`) on the fieldset directly when the surrounding context already names the group.
|
|
47
|
+
|
|
48
|
+
<Canvas of={Stories.WithoutLegend} />
|
|
49
|
+
|
|
50
|
+
### Disabled
|
|
51
|
+
|
|
52
|
+
The native `disabled` attribute on the fieldset disables every form control inside it without per-field wiring.
|
|
53
|
+
|
|
54
|
+
<Canvas of={Stories.Disabled} />
|
|
55
|
+
|
|
56
|
+
## Props
|
|
57
|
+
|
|
58
|
+
<ArgTypes of={Stories} />
|
|
59
|
+
|
|
60
|
+
## HTML attribute forwarding
|
|
61
|
+
|
|
62
|
+
Extends `FieldsetHTMLAttributes<HTMLFieldSetElement>`; spreads all unrecognised props onto the root `<fieldset>` (`id`, `name`, `form`, `disabled`, `aria-*`, `data-*`, every DOM event handler, etc.). The consumer-provided `className` is merged with the internal classes via `cn()`.
|
|
63
|
+
|
|
64
|
+
## CSS variables
|
|
65
|
+
|
|
66
|
+
All public override tokens. Set on the FieldGroup or any ancestor; they cascade.
|
|
67
|
+
|
|
68
|
+
### Layout
|
|
69
|
+
|
|
70
|
+
| Variable | Default | Description |
|
|
71
|
+
|----------|---------|-------------|
|
|
72
|
+
| `--fieldGroup_gap` | `var(--bds-space_m)` | Gap between fields. |
|
|
73
|
+
| `--fieldGroup_min-field-width` | `12rem` | Minimum width each field claims in horizontal mode before wrapping. |
|
|
74
|
+
|
|
75
|
+
### Legend
|
|
76
|
+
|
|
77
|
+
| Variable | Default | Description |
|
|
78
|
+
|----------|---------|-------------|
|
|
79
|
+
| `--fieldGroup_legend-color` | `var(--bds-color_on-bg)` | Legend text colour. |
|
|
80
|
+
| `--fieldGroup_legend-font-size` | `var(--bds-font_size--heading-3)` | Legend font size. |
|
|
81
|
+
| `--fieldGroup_legend-font-weight` | `var(--bds-font_weight--semibold)` | Legend font weight. |
|
|
82
|
+
| `--fieldGroup_legend-line-height` | `var(--bds-font_line-height--heading)` | Legend line height. |
|
|
83
|
+
| `--fieldGroup_legend-padding-block` | `var(--bds-space_xs)` | Legend block padding. |
|
|
84
|
+
| `--fieldGroup_legend-gap` | `var(--bds-space_m)` | Space below the legend before the fields. |
|
|
85
|
+
| `--fieldGroup_legend-border-block-end` | `1px solid var(--bds-color_bg--subtle)` | Subtle separator under the legend. Set to `none` to remove. |
|
|
86
|
+
|
|
87
|
+
## Accessibility
|
|
88
|
+
|
|
89
|
+
- Renders as `<fieldset>` so assistive tech announces the legend before each field, and the native `disabled` attribute cascades to all descendants.
|
|
90
|
+
- When `legend` is omitted, you must provide `aria-label` or `aria-labelledby` on the FieldGroup so the group still has an accessible name.
|
|
91
|
+
- The container query is a layout-only change — DOM order stays in source order, so the tab/reading order is unaffected by the horizontal-to-vertical switch.
|
|
92
|
+
|
|
93
|
+
## How the responsive layout works
|
|
94
|
+
|
|
95
|
+
The horizontal variant uses `display: flex; flex-flow: row wrap;` with each child claiming at least `--fieldGroup_min-field-width`. This handles natural wrapping across multiple rows.
|
|
96
|
+
|
|
97
|
+
Layered on top, a CSS [`@container`](https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/At-rules/@container) query forces a clean single-column layout when the FieldGroup itself is narrower than the **auto-derived** collapse threshold:
|
|
98
|
+
|
|
99
|
+
```css
|
|
100
|
+
--fieldGroup_collapse-threshold:
|
|
101
|
+
calc(
|
|
102
|
+
var(--fieldGroup_field-count) * var(--fieldGroup_min-field-width)
|
|
103
|
+
+ (var(--fieldGroup_field-count) - 1) * var(--fieldGroup_gap)
|
|
104
|
+
);
|
|
105
|
+
|
|
106
|
+
@container field-group (max-inline-size: var(--fieldGroup_collapse-threshold)) {
|
|
107
|
+
.fieldGroup.--variant_horizontal .fields { flex-direction: column; }
|
|
108
|
+
}
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
`--fieldGroup_field-count` is set by the React component as an inline `style` custom property derived from `Children.count(children)`, so the threshold scales with the actual content. A 2-field group collapses around `2 × 12rem + 1 × gap`; a 5-field group collapses around `5 × 12rem + 4 × gap`. No magic numbers per call site.
|
|
112
|
+
|
|
113
|
+
Because the query is bound to the FieldGroup's own inline-size (via `container-type: inline-size`), the same FieldGroup behaves correctly whether you place it in a sidebar, a modal, a 2-up grid cell, or a full-width page — with zero media-query wiring at the call site.
|