@gtivr4/a1-design-system-react 0.2.4 → 0.3.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gtivr4/a1-design-system-react",
3
- "version": "0.2.4",
3
+ "version": "0.3.0",
4
4
  "description": "React components for the A1 token-driven design system.",
5
5
  "type": "module",
6
6
  "main": "./src/index.js",
@@ -0,0 +1,205 @@
1
+ import { Fragment, useId, useState } from "react";
2
+ import { useLabel } from "../labels/Labels.jsx";
3
+ import { MessageBadge } from "../message/Message.jsx";
4
+ import { Icon } from "../icon/Icon.jsx";
5
+ import "./choice-group.css";
6
+
7
+ const SIZES = ["compact", "default", "comfortable"];
8
+
9
+ const BP_MIN = { xs: 0, sm: 481, md: 641, lg: 1025, xl: 1441 };
10
+
11
+ export function ChoiceGroup({
12
+ label,
13
+ hint,
14
+ error,
15
+ success,
16
+ size = "default",
17
+ columns,
18
+ multiple = false,
19
+ required = false,
20
+ name,
21
+ options = [],
22
+ sections,
23
+ value,
24
+ defaultValue,
25
+ onChange,
26
+ id: providedId,
27
+ className = "",
28
+ ...props
29
+ }) {
30
+ const autoId = useId();
31
+ const id = providedId ?? autoId;
32
+ const hintId = `${id}-hint`;
33
+ const errorId = `${id}-error`;
34
+ const successId = `${id}-success`;
35
+
36
+ const resolvedSize = SIZES.includes(size) ? size : "default";
37
+
38
+ const defaultVal = defaultValue ?? (multiple ? [] : null);
39
+ const [internalValue, setInternalValue] = useState(defaultVal);
40
+ const currentValue = value !== undefined ? value : internalValue;
41
+
42
+ function handleChange(optionValue, checked) {
43
+ if (multiple) {
44
+ const next = checked
45
+ ? [...(currentValue ?? []), optionValue]
46
+ : (currentValue ?? []).filter(v => v !== optionValue);
47
+ if (value === undefined) setInternalValue(next);
48
+ onChange?.(next);
49
+ } else {
50
+ if (value === undefined) setInternalValue(optionValue);
51
+ onChange?.(optionValue);
52
+ }
53
+ }
54
+
55
+ const isFixedNumber = typeof columns === "number" && columns > 0;
56
+ const isResponsiveObj = columns !== null && typeof columns === "object";
57
+ const isFixedColumns = isFixedNumber || isResponsiveObj;
58
+
59
+ const responsiveClass = isResponsiveObj
60
+ ? `a1-cg-${autoId.replace(/[^a-zA-Z0-9_-]/g, "")}`
61
+ : null;
62
+
63
+ const responsiveStyle = isResponsiveObj
64
+ ? Object.entries(columns)
65
+ .filter(([bp, n]) => bp in BP_MIN && typeof n === "number" && n > 0)
66
+ .sort(([a], [b]) => BP_MIN[a] - BP_MIN[b])
67
+ .map(([bp, n]) => {
68
+ const min = BP_MIN[bp];
69
+ const rule = `.${responsiveClass} { --a1-cg-columns: ${n}; }`;
70
+ return min === 0 ? rule : `@media (min-width: ${min}px) { .${responsiveClass} { --a1-cg-columns: ${n}; } }`;
71
+ })
72
+ .join("\n")
73
+ : null;
74
+
75
+ const classes = [
76
+ "a1-choice-group",
77
+ resolvedSize !== "default" && `a1-choice-group--${resolvedSize}`,
78
+ multiple ? "a1-choice-group--multiple" : "a1-choice-group--single",
79
+ isFixedColumns && "a1-choice-group--fixed-columns",
80
+ responsiveClass,
81
+ error && "a1-choice-group--error",
82
+ success && "a1-choice-group--success",
83
+ required && "a1-choice-group--required",
84
+ className,
85
+ ].filter(Boolean).join(" ");
86
+
87
+ const messageId = error ? errorId : success ? successId : hint ? hintId : null;
88
+ const describedBy = messageId || undefined;
89
+ const requiredText = useLabel("field.required", "Required");
90
+ const groupName = name ?? id;
91
+
92
+ const inlineStyle = isFixedNumber ? { "--a1-cg-columns": columns } : undefined;
93
+
94
+ function renderOption(option) {
95
+ const isDisabled = option.disabled ?? false;
96
+ const isChecked = multiple
97
+ ? (currentValue ?? []).includes(option.value)
98
+ : currentValue === option.value;
99
+ const itemId = `${id}-${option.value}`;
100
+ return (
101
+ <label
102
+ key={option.value}
103
+ htmlFor={itemId}
104
+ className={[
105
+ "a1-choice-item",
106
+ isDisabled && "a1-choice-item--disabled",
107
+ ].filter(Boolean).join(" ")}
108
+ >
109
+ <input
110
+ type={multiple ? "checkbox" : "radio"}
111
+ id={itemId}
112
+ className="a1-choice-item__input"
113
+ name={multiple ? (name ?? id) : groupName}
114
+ value={option.value}
115
+ checked={isChecked}
116
+ disabled={isDisabled}
117
+ onChange={(e) => handleChange(option.value, e.target.checked)}
118
+ />
119
+ {option.icon && (
120
+ <span className="a1-choice-item__icon" aria-hidden="true">
121
+ <Icon name={option.icon} />
122
+ </span>
123
+ )}
124
+ <span className="a1-choice-item__content">
125
+ <span className="a1-choice-item__label">{option.label}</span>
126
+ {option.subtext && (
127
+ <span className="a1-choice-item__subtext">{option.subtext}</span>
128
+ )}
129
+ </span>
130
+ <span className="a1-choice-item__indicator" aria-hidden="true" />
131
+ </label>
132
+ );
133
+ }
134
+
135
+ function renderItems(opts, ariaLabelledBy) {
136
+ return (
137
+ <div
138
+ className="a1-choice-group__items"
139
+ role="group"
140
+ aria-labelledby={ariaLabelledBy}
141
+ >
142
+ {opts.map(renderOption)}
143
+ </div>
144
+ );
145
+ }
146
+
147
+ return (
148
+ <>
149
+ {responsiveStyle && <style>{responsiveStyle}</style>}
150
+ <fieldset
151
+ className={classes}
152
+ aria-describedby={describedBy}
153
+ style={inlineStyle}
154
+ {...props}
155
+ >
156
+ {label && (
157
+ <legend className="a1-choice-group__legend">
158
+ <span className="a1-choice-group__legend-inner">
159
+ {label}
160
+ {required && resolvedSize === "comfortable" ? (
161
+ <MessageBadge status="info" subtle>{requiredText}</MessageBadge>
162
+ ) : required ? (
163
+ <span className="a1-field__asterisk" aria-hidden="true"> *</span>
164
+ ) : null}
165
+ </span>
166
+ </legend>
167
+ )}
168
+ {!error && !success && hint && (
169
+ <p className="a1-choice-group__message a1-choice-group__message--hint" id={hintId}>
170
+ {hint}
171
+ </p>
172
+ )}
173
+ {sections
174
+ ? sections.map((section, i) => (
175
+ <Fragment key={section.label ?? i}>
176
+ {i > 0 && <hr className="a1-choice-group__section-divider" aria-hidden="true" />}
177
+ <div className="a1-choice-group__section">
178
+ {section.label && (
179
+ <p
180
+ className="a1-choice-group__section-label"
181
+ id={`${id}-section-${i}`}
182
+ >
183
+ {section.label}
184
+ </p>
185
+ )}
186
+ {renderItems(section.options, section.label ? `${id}-section-${i}` : undefined)}
187
+ </div>
188
+ </Fragment>
189
+ ))
190
+ : renderItems(options, undefined)
191
+ }
192
+ {error && (
193
+ <p className="a1-choice-group__message a1-choice-group__message--error" id={errorId} role="alert">
194
+ {error}
195
+ </p>
196
+ )}
197
+ {!error && success && (
198
+ <p className="a1-choice-group__message a1-choice-group__message--success" id={successId}>
199
+ {success}
200
+ </p>
201
+ )}
202
+ </fieldset>
203
+ </>
204
+ );
205
+ }
@@ -0,0 +1,332 @@
1
+ /* ─── ChoiceGroup ──────────────────────────────────────────────────────────── */
2
+
3
+ .a1-choice-group {
4
+ border: none;
5
+ margin: 0;
6
+ padding: 0;
7
+ min-width: 0;
8
+
9
+ /* Tile size defaults (default) */
10
+ --a1-cg-padding: var(--component-choice-group-default-padding);
11
+ --a1-cg-icon-size: var(--component-choice-group-default-icon-size);
12
+ --a1-cg-indicator-size: var(--component-choice-group-default-indicator-size);
13
+ --a1-cg-content-gap: var(--component-choice-group-default-content-gap);
14
+ --a1-cg-min-width: var(--component-choice-group-default-min-width);
15
+ --a1-cg-label-size: var(--semantic-font-size-body-md);
16
+ --a1-cg-subtext-size: var(--semantic-font-size-body-sm);
17
+ --a1-cg-legend-size: var(--semantic-font-size-body-sm);
18
+ --a1-cg-section-label-size: var(--semantic-font-size-body-xs);
19
+
20
+ /* Gap between tiles — tracks size */
21
+ --a1-cg-gap: var(--component-choice-group-gap-md);
22
+
23
+ /* Spacing between legend/messages and the items container */
24
+ --a1-cg-group-gap: var(--component-choice-group-default-group-gap);
25
+ --a1-cg-items-top-gap: var(--component-choice-group-default-items-top-gap);
26
+
27
+ display: flex;
28
+ flex-direction: column;
29
+ gap: var(--a1-cg-group-gap);
30
+ }
31
+
32
+ /* ─── Tile sizes — affect only tile padding and child element sizes ─────────── */
33
+
34
+ .a1-choice-group--compact {
35
+ --a1-cg-padding: var(--component-choice-group-compact-padding);
36
+ --a1-cg-icon-size: var(--component-choice-group-compact-icon-size);
37
+ --a1-cg-indicator-size: var(--component-choice-group-compact-indicator-size);
38
+ --a1-cg-content-gap: var(--component-choice-group-compact-content-gap);
39
+ --a1-cg-min-width: var(--component-choice-group-compact-min-width);
40
+ --a1-cg-label-size: var(--semantic-font-size-body-sm);
41
+ --a1-cg-subtext-size: var(--semantic-font-size-body-xs);
42
+ --a1-cg-legend-size: var(--semantic-font-size-body-xs);
43
+ --a1-cg-gap: var(--component-choice-group-gap-sm);
44
+ --a1-cg-group-gap: var(--component-choice-group-compact-group-gap);
45
+ --a1-cg-items-top-gap: var(--component-choice-group-compact-items-top-gap);
46
+ }
47
+
48
+ .a1-choice-group--comfortable {
49
+ --a1-cg-padding: var(--component-choice-group-comfortable-padding);
50
+ --a1-cg-icon-size: var(--component-choice-group-comfortable-icon-size);
51
+ --a1-cg-indicator-size: var(--component-choice-group-comfortable-indicator-size);
52
+ --a1-cg-content-gap: var(--component-choice-group-comfortable-content-gap);
53
+ --a1-cg-min-width: var(--component-choice-group-comfortable-min-width);
54
+ --a1-cg-label-size: var(--semantic-font-size-body-lg);
55
+ --a1-cg-subtext-size: var(--semantic-font-size-body-md);
56
+ --a1-cg-legend-size: var(--semantic-font-size-body-md);
57
+ --a1-cg-section-label-size: var(--semantic-font-size-body-sm);
58
+ --a1-cg-gap: var(--component-choice-group-gap-lg);
59
+ --a1-cg-group-gap: var(--component-choice-group-comfortable-group-gap);
60
+ --a1-cg-items-top-gap: var(--component-choice-group-comfortable-items-top-gap);
61
+ }
62
+
63
+ @media (--bp-md-up) {
64
+ .a1-choice-group--comfortable {
65
+ --a1-cg-legend-size: var(--semantic-font-size-body-lg);
66
+ }
67
+ }
68
+
69
+ /* ─── Legend ────────────────────────────────────────────────────────────────── */
70
+
71
+ .a1-choice-group__legend {
72
+ display: block;
73
+ width: 100%;
74
+ padding: 0;
75
+ font-family: var(--component-paragraph-font-family);
76
+ font-size: var(--a1-cg-legend-size);
77
+ font-weight: var(--component-field-label-font-weight);
78
+ color: var(--semantic-color-text-default);
79
+ line-height: var(--semantic-font-line-height-body);
80
+ }
81
+
82
+ .a1-choice-group__legend-inner {
83
+ display: inline-flex;
84
+ align-items: center;
85
+ gap: var(--base-spacing-6);
86
+ }
87
+
88
+ /* ─── Group messages (hint / error / success) ────────────────────────────────── */
89
+
90
+ .a1-choice-group__message {
91
+ margin: 0;
92
+ font-family: var(--component-paragraph-font-family);
93
+ font-size: var(--a1-cg-legend-size);
94
+ line-height: var(--semantic-font-line-height-body);
95
+ }
96
+
97
+ .a1-choice-group__message--hint { color: var(--semantic-color-text-muted); }
98
+ .a1-choice-group__message--error {
99
+ color: var(--semantic-color-status-error-background);
100
+ font-weight: var(--base-font-weight-medium);
101
+ }
102
+ .a1-choice-group__message--success {
103
+ color: var(--semantic-color-status-success-background);
104
+ font-weight: var(--base-font-weight-medium);
105
+ }
106
+
107
+ /* ─── Sections ───────────────────────────────────────────────────────────────── */
108
+
109
+ .a1-choice-group__section-divider {
110
+ border: none;
111
+ border-top: 1px solid var(--semantic-color-border-subtle);
112
+ margin: var(--a1-cg-gap) 0 0;
113
+ padding: 0;
114
+ }
115
+
116
+ .a1-choice-group__section {
117
+ display: flex;
118
+ flex-direction: column;
119
+ }
120
+
121
+ .a1-choice-group__section-label {
122
+ margin: 0 0 var(--a1-cg-items-top-gap);
123
+ font-family: var(--component-paragraph-font-family);
124
+ font-size: var(--a1-cg-section-label-size);
125
+ font-weight: var(--base-font-weight-semibold);
126
+ color: var(--semantic-color-text-muted);
127
+ line-height: var(--semantic-font-line-height-body);
128
+ }
129
+
130
+ /* Items inside a section — the section label handles the top spacing */
131
+ .a1-choice-group__section .a1-choice-group__items {
132
+ margin-top: 0;
133
+ }
134
+
135
+ /* ─── Items flex layout ─────────────────────────────────────────────────────── */
136
+
137
+ .a1-choice-group__items {
138
+ display: flex;
139
+ flex-wrap: wrap;
140
+ gap: var(--a1-cg-gap);
141
+ margin-top: var(--a1-cg-items-top-gap);
142
+ }
143
+
144
+ /* Fixed column count when --a1-cg-columns is set */
145
+ .a1-choice-group--fixed-columns .a1-choice-group__items > .a1-choice-item {
146
+ flex: 0 0 calc((100% - (var(--a1-cg-columns) - 1) * var(--a1-cg-gap)) / var(--a1-cg-columns));
147
+ }
148
+
149
+ /* ─── Choice item (card tile) ───────────────────────────────────────────────── */
150
+
151
+ .a1-choice-item {
152
+ position: relative;
153
+ display: flex;
154
+ flex-direction: column;
155
+ flex: 1 1 var(--a1-cg-min-width);
156
+ gap: var(--a1-cg-content-gap);
157
+ overflow: hidden;
158
+ /* Start padding offsets all content clear of the indicator in the top-start corner */
159
+ padding-block: var(--a1-cg-padding);
160
+ padding-inline-end: var(--a1-cg-padding);
161
+ padding-inline-start: calc(var(--a1-cg-padding) + var(--a1-cg-indicator-size) + var(--base-spacing-8));
162
+ border: var(--component-choice-group-border-width) solid var(--semantic-color-border-subtle);
163
+ border-radius: var(--component-choice-group-border-radius);
164
+ background-color: var(--semantic-color-surface-page);
165
+ cursor: pointer;
166
+ transition:
167
+ border-color var(--semantic-motion-duration-fast) var(--semantic-motion-easing-standard),
168
+ background-color var(--semantic-motion-duration-fast) var(--semantic-motion-easing-standard),
169
+ box-shadow var(--semantic-motion-duration-fast) var(--semantic-motion-easing-standard);
170
+ }
171
+
172
+ .a1-choice-item--disabled {
173
+ cursor: not-allowed;
174
+ opacity: 0.5;
175
+ background-color: var(--semantic-color-surface-raised);
176
+ }
177
+
178
+ .a1-choice-item--disabled .a1-choice-item__input {
179
+ pointer-events: none;
180
+ }
181
+
182
+ /* Hover (unselected, non-disabled) */
183
+ .a1-choice-item:not(.a1-choice-item--disabled):not(:has(.a1-choice-item__input:checked)):hover {
184
+ border-color: var(--semantic-color-action-border);
185
+ background-color: var(--semantic-color-action-surface);
186
+ }
187
+
188
+ /* Selected */
189
+ .a1-choice-item:not(.a1-choice-item--disabled):has(.a1-choice-item__input:checked) {
190
+ border-color: var(--semantic-color-action-background);
191
+ background-color: var(--semantic-color-action-surface);
192
+ box-shadow: inset 0 0 0 1px var(--semantic-color-action-background);
193
+ }
194
+
195
+ /* Selected hover */
196
+ .a1-choice-item:not(.a1-choice-item--disabled):has(.a1-choice-item__input:checked):hover {
197
+ border-color: var(--semantic-color-action-background-hover);
198
+ box-shadow: inset 0 0 0 1px var(--semantic-color-action-background-hover);
199
+ }
200
+
201
+ /* Focus ring on card when hidden input receives keyboard focus */
202
+ .a1-choice-item:has(.a1-choice-item__input:focus-visible) {
203
+ outline: var(--component-field-focus-ring-width) solid var(--component-field-focus-ring-color);
204
+ outline-offset: 2px;
205
+ }
206
+
207
+ /* ─── Hidden input ──────────────────────────────────────────────────────────── */
208
+
209
+ .a1-choice-item__input {
210
+ position: absolute;
211
+ width: 1px;
212
+ height: 1px;
213
+ padding: 0;
214
+ margin: -1px;
215
+ overflow: hidden;
216
+ clip: rect(0, 0, 0, 0);
217
+ white-space: nowrap;
218
+ border: 0;
219
+ }
220
+
221
+ /* ─── Icon ──────────────────────────────────────────────────────────────────── */
222
+
223
+ .a1-choice-item__icon {
224
+ display: flex;
225
+ align-items: center;
226
+ justify-content: center;
227
+ width: var(--a1-cg-icon-size);
228
+ height: var(--a1-cg-icon-size);
229
+ color: var(--semantic-color-action-background);
230
+ flex-shrink: 0;
231
+ }
232
+
233
+ .a1-choice-item__icon .a1-icon {
234
+ font-size: var(--a1-cg-icon-size);
235
+ }
236
+
237
+ /* ─── Label and subtext ─────────────────────────────────────────────────────── */
238
+
239
+ .a1-choice-item__content {
240
+ display: flex;
241
+ flex-direction: column;
242
+ gap: var(--base-spacing-2);
243
+ flex: 1;
244
+ min-width: 0;
245
+ }
246
+
247
+ .a1-choice-item__label {
248
+ font-family: var(--component-paragraph-font-family);
249
+ font-size: var(--a1-cg-label-size);
250
+ font-weight: var(--base-font-weight-medium);
251
+ color: var(--semantic-color-text-default);
252
+ line-height: var(--semantic-font-line-height-body);
253
+ overflow-wrap: break-word;
254
+ }
255
+
256
+ .a1-choice-item__subtext {
257
+ font-family: var(--component-paragraph-font-family);
258
+ font-size: var(--a1-cg-subtext-size);
259
+ font-weight: var(--base-font-weight-regular);
260
+ color: var(--semantic-color-text-muted);
261
+ line-height: var(--semantic-font-line-height-body);
262
+ overflow-wrap: break-word;
263
+ }
264
+
265
+ /* ─── Selection indicator ───────────────────────────────────────────────────── */
266
+
267
+ .a1-choice-item__indicator {
268
+ position: absolute;
269
+ top: calc(var(--a1-cg-padding) + var(--base-spacing-4));
270
+ inset-inline-start: var(--a1-cg-padding);
271
+ width: var(--a1-cg-indicator-size);
272
+ height: var(--a1-cg-indicator-size);
273
+ border: 1.5px solid var(--semantic-color-border-default);
274
+ background-color: var(--semantic-color-surface-page);
275
+ background-repeat: no-repeat;
276
+ background-position: center;
277
+ transition:
278
+ border-color var(--semantic-motion-duration-fast),
279
+ background-color var(--semantic-motion-duration-fast);
280
+ }
281
+
282
+ /* Single-select (radio) — circle */
283
+ .a1-choice-group--single .a1-choice-item__indicator {
284
+ border-radius: 50%;
285
+ }
286
+
287
+ /* Multi-select (checkbox) — rounded square */
288
+ .a1-choice-group--multiple .a1-choice-item__indicator {
289
+ border-radius: var(--base-radius-sm);
290
+ }
291
+
292
+ /* Hover indicator border (unselected only) */
293
+ .a1-choice-item:not(.a1-choice-item--disabled):not(:has(.a1-choice-item__input:checked)):hover
294
+ .a1-choice-item__indicator {
295
+ border-color: var(--semantic-color-action-background);
296
+ }
297
+
298
+ /* Selected indicator — filled */
299
+ .a1-choice-item:has(.a1-choice-item__input:checked) .a1-choice-item__indicator {
300
+ border-color: var(--semantic-color-action-background);
301
+ background-color: var(--semantic-color-action-background);
302
+ }
303
+
304
+ /* Radio selected: white dot */
305
+ .a1-choice-group--single
306
+ .a1-choice-item:has(.a1-choice-item__input:checked)
307
+ .a1-choice-item__indicator {
308
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 10'%3E%3Ccircle cx='5' cy='5' r='3' fill='%23ffffff'/%3E%3C/svg%3E");
309
+ background-size: 100%;
310
+ }
311
+
312
+ /* Checkbox selected: white checkmark */
313
+ .a1-choice-group--multiple
314
+ .a1-choice-item:has(.a1-choice-item__input:checked)
315
+ .a1-choice-item__indicator {
316
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpolyline points='2,6 5,9.5 10,3' fill='none' stroke='%23ffffff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
317
+ background-size: 80%;
318
+ }
319
+
320
+ /* ─── Error state ───────────────────────────────────────────────────────────── */
321
+
322
+ .a1-choice-group--error
323
+ .a1-choice-item:not(.a1-choice-item--disabled):not(:has(.a1-choice-item__input:checked)) {
324
+ border-color: var(--semantic-color-status-error-border);
325
+ box-shadow: inset 0 0 0 1px var(--semantic-color-status-error-border);
326
+ }
327
+
328
+ .a1-choice-group--error
329
+ .a1-choice-item:not(.a1-choice-item--disabled):not(:has(.a1-choice-item__input:checked))
330
+ .a1-choice-item__indicator {
331
+ border-color: var(--semantic-color-status-error-border);
332
+ }
package/src/index.js CHANGED
@@ -33,6 +33,7 @@ export { NumberField } from "./components/field/NumberField.jsx";
33
33
  export { TimeField } from "./components/field/TimeField.jsx";
34
34
  export { TextareaField } from "./components/field/TextareaField.jsx";
35
35
  export { CheckboxGroup } from "./components/checkbox-group/CheckboxGroup.jsx";
36
+ export { ChoiceGroup } from "./components/choice-group/ChoiceGroup.jsx";
36
37
  export { RadioGroup } from "./components/radio-group/RadioGroup.jsx";
37
38
  export { Switch } from "./components/switch/Switch.jsx";
38
39
  export { MessageBadge, MessageEmptyState } from "./components/message/Message.jsx";
package/src/tokens.css CHANGED
@@ -382,6 +382,32 @@
382
382
  --component-checkbox-group-compact-input-nudge: 3px;
383
383
  --component-checkbox-group-compact-row-padding-block: 2px;
384
384
  --component-checkbox-group-compact-row-padding-inline: 4px;
385
+ --component-choice-group-border-radius: 8px;
386
+ --component-choice-group-border-width: 1px;
387
+ --component-choice-group-gap-sm: 8px;
388
+ --component-choice-group-gap-md: 12px;
389
+ --component-choice-group-gap-lg: 16px;
390
+ --component-choice-group-compact-padding: 8px;
391
+ --component-choice-group-compact-icon-size: 20px;
392
+ --component-choice-group-compact-indicator-size: 12px;
393
+ --component-choice-group-compact-content-gap: 4px;
394
+ --component-choice-group-compact-min-width: 100px;
395
+ --component-choice-group-compact-group-gap: 4px;
396
+ --component-choice-group-compact-items-top-gap: 8px;
397
+ --component-choice-group-default-padding: 12px;
398
+ --component-choice-group-default-icon-size: 24px;
399
+ --component-choice-group-default-indicator-size: 16px;
400
+ --component-choice-group-default-content-gap: 6px;
401
+ --component-choice-group-default-min-width: 140px;
402
+ --component-choice-group-default-group-gap: 8px;
403
+ --component-choice-group-default-items-top-gap: 12px;
404
+ --component-choice-group-comfortable-padding: 16px;
405
+ --component-choice-group-comfortable-icon-size: 32px;
406
+ --component-choice-group-comfortable-indicator-size: 20px;
407
+ --component-choice-group-comfortable-content-gap: 8px;
408
+ --component-choice-group-comfortable-min-width: 200px;
409
+ --component-choice-group-comfortable-group-gap: 8px;
410
+ --component-choice-group-comfortable-items-top-gap: 16px;
385
411
  --component-data-table-border-width: 1px;
386
412
  --component-data-table-header-font-weight: 500;
387
413
  --component-data-table-focus-ring-width: 2px;