@crisp-ui-kit/crisp 0.42.0 → 0.43.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/dist/cjs/components/multiselect/multiselect.js +6 -1
- package/dist/cjs/components/multiselect/multiselect.recipe.js +4 -0
- package/dist/cjs/components/select/select.js +6 -1
- package/dist/cjs/components/select/select.recipe.js +4 -0
- package/dist/esm/components/multiselect/multiselect.js +6 -1
- package/dist/esm/components/multiselect/multiselect.recipe.js +4 -0
- package/dist/esm/components/select/select.js +6 -1
- package/dist/esm/components/select/select.recipe.js +4 -0
- package/dist/multiselect.css +4 -0
- package/dist/multiselect.layered.css +4 -0
- package/dist/select.css +4 -0
- package/dist/select.layered.css +4 -0
- package/dist/styles.css +8 -0
- package/dist/styles.layered.css +8 -0
- package/dist/types/components/multiselect/multiselect.d.ts +8 -0
- package/dist/types/components/select/select.d.ts +8 -0
- package/package.json +1 -1
|
@@ -195,7 +195,12 @@ id, placeholder = "Select…", searchable = true, searchPlaceholder = "Search…
|
|
|
195
195
|
setHighlight(0);
|
|
196
196
|
}, onKeyDown: onNavKeys })] })), filtered.length === 0 ? ((0, jsx_runtime_1.jsx)("div", { className: "crisp-multiselect-empty", children: emptyLabel })) : (filtered.map((opt, i) => {
|
|
197
197
|
const sel = selectedSet.has(opt.value);
|
|
198
|
-
|
|
198
|
+
// #343: a header renders once per run of same-`group`
|
|
199
|
+
// options, so consecutive rows sharing a group render one
|
|
200
|
+
// heading, not one each.
|
|
201
|
+
const showGroupLabel = opt.group !== undefined &&
|
|
202
|
+
opt.group !== filtered[i - 1]?.group;
|
|
203
|
+
return ((0, jsx_runtime_1.jsxs)(React.Fragment, { children: [showGroupLabel && ((0, jsx_runtime_1.jsx)("div", { className: "crisp-multiselect-label", children: opt.group })), (0, jsx_runtime_1.jsxs)("button", { type: "button", id: optionId(i), role: "option", "aria-selected": sel, tabIndex: -1, "data-highlighted": i === highlight ? "" : undefined, className: "crisp-multiselect-option", onClick: () => toggle(opt.value), onMouseEnter: () => setHighlight(i), children: [(0, jsx_runtime_1.jsx)("span", { className: "crisp-multiselect-option-chip", children: (0, jsx_runtime_1.jsx)(Chip, { opt: opt }) }), (0, jsx_runtime_1.jsx)("span", { className: "crisp-multiselect-check", children: sel && (0, jsx_runtime_1.jsx)(lucide_react_1.Check, { size: 12, strokeWidth: 3 }) })] })] }, opt.value));
|
|
199
204
|
}))] }) }))] }));
|
|
200
205
|
}
|
|
201
206
|
MultiSelect.displayName = "MultiSelect";
|
|
@@ -58,6 +58,10 @@ const config = (0, core_1.defineRecipe)({
|
|
|
58
58
|
.crisp-multiselect-search svg { flex-shrink: 0; }
|
|
59
59
|
.crisp-multiselect-search input { flex: 1; min-width: 0; border: none; outline: none; background: none; font-family: inherit; font-size: ${tokens_1.contract.text.lg}; color: ${tokens_1.contract.fgPrimary}; }
|
|
60
60
|
.crisp-multiselect-search input::placeholder { color: ${tokens_1.contract.fgMuted}; }
|
|
61
|
+
/* #343: same measured values as Menu's own group heading
|
|
62
|
+
(crisp-menu-label) -- reused rather than re-measured, since it's the
|
|
63
|
+
same "small muted heading above a run of rows" treatment. */
|
|
64
|
+
.crisp-multiselect-label { padding: ${tokens_1.contract.space["1.5"]} ${tokens_1.contract.space["2"]} ${tokens_1.contract.space["0.5"]}; font-size: ${tokens_1.contract.text.sm}; font-weight: ${tokens_1.contract.weight.medium}; color: ${tokens_1.contract.fgMuted}; }
|
|
61
65
|
.crisp-multiselect-option {
|
|
62
66
|
box-sizing: border-box; display: flex; align-items: center; gap: ${tokens_1.contract.space["2"]}; height: ${tokens_1.contract.size.menuRow}; flex-shrink: 0;
|
|
63
67
|
padding: 0 ${tokens_1.contract.space["2"]}; margin: 0; border: none; background: none; border-radius: ${tokens_1.contract.radius.md}; font-family: inherit; cursor: pointer; text-align: start;
|
|
@@ -185,7 +185,12 @@ function Select({ options, value, defaultValue, onValueChange, name, required, p
|
|
|
185
185
|
setHighlight(0);
|
|
186
186
|
}, onKeyDown: onNavKeys })] })), filtered.length === 0 ? ((0, jsx_runtime_1.jsx)("div", { className: "crisp-select-empty", children: emptyLabel })) : (filtered.map((opt, i) => {
|
|
187
187
|
const isSel = opt.value === selected;
|
|
188
|
-
|
|
188
|
+
// #343: a header renders once per run of same-`group`
|
|
189
|
+
// options, so consecutive rows sharing a group render one
|
|
190
|
+
// heading, not one each.
|
|
191
|
+
const showGroupLabel = opt.group !== undefined &&
|
|
192
|
+
opt.group !== filtered[i - 1]?.group;
|
|
193
|
+
return ((0, jsx_runtime_1.jsxs)(React.Fragment, { children: [showGroupLabel && ((0, jsx_runtime_1.jsx)("div", { className: "crisp-select-label", children: opt.group })), (0, jsx_runtime_1.jsxs)("button", { type: "button", id: optionId(i), role: "option", "aria-selected": isSel, tabIndex: -1, disabled: opt.disabled, "data-disabled": opt.disabled ? "" : undefined, "data-highlighted": i === highlight ? "" : undefined, className: "crisp-select-option", onClick: () => pick(opt), onMouseEnter: () => setHighlight(i), children: [opt.color && ((0, jsx_runtime_1.jsx)("span", { className: "crisp-select-option-dot", style: { background: opt.color } })), (0, jsx_runtime_1.jsx)("span", { className: "crisp-select-option-label", children: opt.label }), isSel && ((0, jsx_runtime_1.jsx)(lucide_react_1.Check, { className: "crisp-select-option-check", size: 15, strokeWidth: 2 }))] })] }, opt.value));
|
|
189
194
|
}))] }) }))] }));
|
|
190
195
|
}
|
|
191
196
|
Select.displayName = "Select";
|
|
@@ -59,6 +59,10 @@ const config = (0, core_1.defineRecipe)({
|
|
|
59
59
|
.crisp-select-search input { flex: 1; min-width: 0; border: none; outline: none; background: none; font-family: inherit; font-size: ${tokens_1.contract.text.lg}; color: ${tokens_1.contract.fgPrimary}; }
|
|
60
60
|
.crisp-select-search input::placeholder { color: ${tokens_1.contract.fgMuted}; }
|
|
61
61
|
.crisp-select-empty { padding: ${tokens_1.contract.space["3"]} ${tokens_1.contract.space["2"]}; text-align: center; font-size: ${tokens_1.contract.text.md}; color: ${tokens_1.contract.fgMuted}; }
|
|
62
|
+
/* #343: same measured values as Menu's own group heading
|
|
63
|
+
(crisp-menu-label) -- reused rather than re-measured, since it's the
|
|
64
|
+
same "small muted heading above a run of rows" treatment. */
|
|
65
|
+
.crisp-select-label { padding: ${tokens_1.contract.space["1.5"]} ${tokens_1.contract.space["2"]} ${tokens_1.contract.space["0.5"]}; font-size: ${tokens_1.contract.text.sm}; font-weight: ${tokens_1.contract.weight.medium}; color: ${tokens_1.contract.fgMuted}; }
|
|
62
66
|
.crisp-select-option {
|
|
63
67
|
box-sizing: border-box; display: flex; align-items: center; gap: ${tokens_1.contract.space["2"]}; height: ${tokens_1.contract.size.menuRow}; flex-shrink: 0;
|
|
64
68
|
padding: 0 ${tokens_1.contract.space["2"]}; margin: 0; border: none; background: none; border-radius: ${tokens_1.contract.radius.md};
|
|
@@ -159,7 +159,12 @@ id, placeholder = "Select…", searchable = true, searchPlaceholder = "Search…
|
|
|
159
159
|
setHighlight(0);
|
|
160
160
|
}, onKeyDown: onNavKeys })] })), filtered.length === 0 ? (_jsx("div", { className: "crisp-multiselect-empty", children: emptyLabel })) : (filtered.map((opt, i) => {
|
|
161
161
|
const sel = selectedSet.has(opt.value);
|
|
162
|
-
|
|
162
|
+
// #343: a header renders once per run of same-`group`
|
|
163
|
+
// options, so consecutive rows sharing a group render one
|
|
164
|
+
// heading, not one each.
|
|
165
|
+
const showGroupLabel = opt.group !== undefined &&
|
|
166
|
+
opt.group !== filtered[i - 1]?.group;
|
|
167
|
+
return (_jsxs(React.Fragment, { children: [showGroupLabel && (_jsx("div", { className: "crisp-multiselect-label", children: opt.group })), _jsxs("button", { type: "button", id: optionId(i), role: "option", "aria-selected": sel, tabIndex: -1, "data-highlighted": i === highlight ? "" : undefined, className: "crisp-multiselect-option", onClick: () => toggle(opt.value), onMouseEnter: () => setHighlight(i), children: [_jsx("span", { className: "crisp-multiselect-option-chip", children: _jsx(Chip, { opt: opt }) }), _jsx("span", { className: "crisp-multiselect-check", children: sel && _jsx(Check, { size: 12, strokeWidth: 3 }) })] })] }, opt.value));
|
|
163
168
|
}))] }) }))] }));
|
|
164
169
|
}
|
|
165
170
|
MultiSelect.displayName = "MultiSelect";
|
|
@@ -55,6 +55,10 @@ const config = defineRecipe({
|
|
|
55
55
|
.crisp-multiselect-search svg { flex-shrink: 0; }
|
|
56
56
|
.crisp-multiselect-search input { flex: 1; min-width: 0; border: none; outline: none; background: none; font-family: inherit; font-size: ${c.text.lg}; color: ${c.fgPrimary}; }
|
|
57
57
|
.crisp-multiselect-search input::placeholder { color: ${c.fgMuted}; }
|
|
58
|
+
/* #343: same measured values as Menu's own group heading
|
|
59
|
+
(crisp-menu-label) -- reused rather than re-measured, since it's the
|
|
60
|
+
same "small muted heading above a run of rows" treatment. */
|
|
61
|
+
.crisp-multiselect-label { padding: ${c.space["1.5"]} ${c.space["2"]} ${c.space["0.5"]}; font-size: ${c.text.sm}; font-weight: ${c.weight.medium}; color: ${c.fgMuted}; }
|
|
58
62
|
.crisp-multiselect-option {
|
|
59
63
|
box-sizing: border-box; display: flex; align-items: center; gap: ${c.space["2"]}; height: ${c.size.menuRow}; flex-shrink: 0;
|
|
60
64
|
padding: 0 ${c.space["2"]}; margin: 0; border: none; background: none; border-radius: ${c.radius.md}; font-family: inherit; cursor: pointer; text-align: start;
|
|
@@ -149,7 +149,12 @@ export function Select({ options, value, defaultValue, onValueChange, name, requ
|
|
|
149
149
|
setHighlight(0);
|
|
150
150
|
}, onKeyDown: onNavKeys })] })), filtered.length === 0 ? (_jsx("div", { className: "crisp-select-empty", children: emptyLabel })) : (filtered.map((opt, i) => {
|
|
151
151
|
const isSel = opt.value === selected;
|
|
152
|
-
|
|
152
|
+
// #343: a header renders once per run of same-`group`
|
|
153
|
+
// options, so consecutive rows sharing a group render one
|
|
154
|
+
// heading, not one each.
|
|
155
|
+
const showGroupLabel = opt.group !== undefined &&
|
|
156
|
+
opt.group !== filtered[i - 1]?.group;
|
|
157
|
+
return (_jsxs(React.Fragment, { children: [showGroupLabel && (_jsx("div", { className: "crisp-select-label", children: opt.group })), _jsxs("button", { type: "button", id: optionId(i), role: "option", "aria-selected": isSel, tabIndex: -1, disabled: opt.disabled, "data-disabled": opt.disabled ? "" : undefined, "data-highlighted": i === highlight ? "" : undefined, className: "crisp-select-option", onClick: () => pick(opt), onMouseEnter: () => setHighlight(i), children: [opt.color && (_jsx("span", { className: "crisp-select-option-dot", style: { background: opt.color } })), _jsx("span", { className: "crisp-select-option-label", children: opt.label }), isSel && (_jsx(Check, { className: "crisp-select-option-check", size: 15, strokeWidth: 2 }))] })] }, opt.value));
|
|
153
158
|
}))] }) }))] }));
|
|
154
159
|
}
|
|
155
160
|
Select.displayName = "Select";
|
|
@@ -56,6 +56,10 @@ const config = defineRecipe({
|
|
|
56
56
|
.crisp-select-search input { flex: 1; min-width: 0; border: none; outline: none; background: none; font-family: inherit; font-size: ${c.text.lg}; color: ${c.fgPrimary}; }
|
|
57
57
|
.crisp-select-search input::placeholder { color: ${c.fgMuted}; }
|
|
58
58
|
.crisp-select-empty { padding: ${c.space["3"]} ${c.space["2"]}; text-align: center; font-size: ${c.text.md}; color: ${c.fgMuted}; }
|
|
59
|
+
/* #343: same measured values as Menu's own group heading
|
|
60
|
+
(crisp-menu-label) -- reused rather than re-measured, since it's the
|
|
61
|
+
same "small muted heading above a run of rows" treatment. */
|
|
62
|
+
.crisp-select-label { padding: ${c.space["1.5"]} ${c.space["2"]} ${c.space["0.5"]}; font-size: ${c.text.sm}; font-weight: ${c.weight.medium}; color: ${c.fgMuted}; }
|
|
59
63
|
.crisp-select-option {
|
|
60
64
|
box-sizing: border-box; display: flex; align-items: center; gap: ${c.space["2"]}; height: ${c.size.menuRow}; flex-shrink: 0;
|
|
61
65
|
padding: 0 ${c.space["2"]}; margin: 0; border: none; background: none; border-radius: ${c.radius.md};
|
package/dist/multiselect.css
CHANGED
|
@@ -13,6 +13,10 @@
|
|
|
13
13
|
.crisp-multiselect-search svg { flex-shrink: 0; }
|
|
14
14
|
.crisp-multiselect-search input { flex: 1; min-width: 0; border: none; outline: none; background: none; font-family: inherit; font-size: var(--crisp-text-lg); color: var(--crisp-fg-primary); }
|
|
15
15
|
.crisp-multiselect-search input::placeholder { color: var(--crisp-fg-muted); }
|
|
16
|
+
/* #343: same measured values as Menu's own group heading
|
|
17
|
+
(crisp-menu-label) -- reused rather than re-measured, since it's the
|
|
18
|
+
same "small muted heading above a run of rows" treatment. */
|
|
19
|
+
.crisp-multiselect-label { padding: var(--crisp-space-1-5) var(--crisp-space-2) var(--crisp-space-0-5); font-size: var(--crisp-text-sm); font-weight: var(--crisp-weight-medium); color: var(--crisp-fg-muted); }
|
|
16
20
|
.crisp-multiselect-option {
|
|
17
21
|
box-sizing: border-box; display: flex; align-items: center; gap: var(--crisp-space-2); height: var(--crisp-size-menuRow); flex-shrink: 0;
|
|
18
22
|
padding: 0 var(--crisp-space-2); margin: 0; border: none; background: none; border-radius: var(--crisp-radius-md); font-family: inherit; cursor: pointer; text-align: start;
|
|
@@ -14,6 +14,10 @@
|
|
|
14
14
|
.crisp-multiselect-search svg { flex-shrink: 0; }
|
|
15
15
|
.crisp-multiselect-search input { flex: 1; min-width: 0; border: none; outline: none; background: none; font-family: inherit; font-size: var(--crisp-text-lg); color: var(--crisp-fg-primary); }
|
|
16
16
|
.crisp-multiselect-search input::placeholder { color: var(--crisp-fg-muted); }
|
|
17
|
+
/* #343: same measured values as Menu's own group heading
|
|
18
|
+
(crisp-menu-label) -- reused rather than re-measured, since it's the
|
|
19
|
+
same "small muted heading above a run of rows" treatment. */
|
|
20
|
+
.crisp-multiselect-label { padding: var(--crisp-space-1-5) var(--crisp-space-2) var(--crisp-space-0-5); font-size: var(--crisp-text-sm); font-weight: var(--crisp-weight-medium); color: var(--crisp-fg-muted); }
|
|
17
21
|
.crisp-multiselect-option {
|
|
18
22
|
box-sizing: border-box; display: flex; align-items: center; gap: var(--crisp-space-2); height: var(--crisp-size-menuRow); flex-shrink: 0;
|
|
19
23
|
padding: 0 var(--crisp-space-2); margin: 0; border: none; background: none; border-radius: var(--crisp-radius-md); font-family: inherit; cursor: pointer; text-align: start;
|
package/dist/select.css
CHANGED
|
@@ -14,6 +14,10 @@
|
|
|
14
14
|
.crisp-select-search input { flex: 1; min-width: 0; border: none; outline: none; background: none; font-family: inherit; font-size: var(--crisp-text-lg); color: var(--crisp-fg-primary); }
|
|
15
15
|
.crisp-select-search input::placeholder { color: var(--crisp-fg-muted); }
|
|
16
16
|
.crisp-select-empty { padding: var(--crisp-space-3) var(--crisp-space-2); text-align: center; font-size: var(--crisp-text-md); color: var(--crisp-fg-muted); }
|
|
17
|
+
/* #343: same measured values as Menu's own group heading
|
|
18
|
+
(crisp-menu-label) -- reused rather than re-measured, since it's the
|
|
19
|
+
same "small muted heading above a run of rows" treatment. */
|
|
20
|
+
.crisp-select-label { padding: var(--crisp-space-1-5) var(--crisp-space-2) var(--crisp-space-0-5); font-size: var(--crisp-text-sm); font-weight: var(--crisp-weight-medium); color: var(--crisp-fg-muted); }
|
|
17
21
|
.crisp-select-option {
|
|
18
22
|
box-sizing: border-box; display: flex; align-items: center; gap: var(--crisp-space-2); height: var(--crisp-size-menuRow); flex-shrink: 0;
|
|
19
23
|
padding: 0 var(--crisp-space-2); margin: 0; border: none; background: none; border-radius: var(--crisp-radius-md);
|
package/dist/select.layered.css
CHANGED
|
@@ -15,6 +15,10 @@
|
|
|
15
15
|
.crisp-select-search input { flex: 1; min-width: 0; border: none; outline: none; background: none; font-family: inherit; font-size: var(--crisp-text-lg); color: var(--crisp-fg-primary); }
|
|
16
16
|
.crisp-select-search input::placeholder { color: var(--crisp-fg-muted); }
|
|
17
17
|
.crisp-select-empty { padding: var(--crisp-space-3) var(--crisp-space-2); text-align: center; font-size: var(--crisp-text-md); color: var(--crisp-fg-muted); }
|
|
18
|
+
/* #343: same measured values as Menu's own group heading
|
|
19
|
+
(crisp-menu-label) -- reused rather than re-measured, since it's the
|
|
20
|
+
same "small muted heading above a run of rows" treatment. */
|
|
21
|
+
.crisp-select-label { padding: var(--crisp-space-1-5) var(--crisp-space-2) var(--crisp-space-0-5); font-size: var(--crisp-text-sm); font-weight: var(--crisp-weight-medium); color: var(--crisp-fg-muted); }
|
|
18
22
|
.crisp-select-option {
|
|
19
23
|
box-sizing: border-box; display: flex; align-items: center; gap: var(--crisp-space-2); height: var(--crisp-size-menuRow); flex-shrink: 0;
|
|
20
24
|
padding: 0 var(--crisp-space-2); margin: 0; border: none; background: none; border-radius: var(--crisp-radius-md);
|
package/dist/styles.css
CHANGED
|
@@ -1045,6 +1045,10 @@
|
|
|
1045
1045
|
.crisp-multiselect-search svg { flex-shrink: 0; }
|
|
1046
1046
|
.crisp-multiselect-search input { flex: 1; min-width: 0; border: none; outline: none; background: none; font-family: inherit; font-size: var(--crisp-text-lg); color: var(--crisp-fg-primary); }
|
|
1047
1047
|
.crisp-multiselect-search input::placeholder { color: var(--crisp-fg-muted); }
|
|
1048
|
+
/* #343: same measured values as Menu's own group heading
|
|
1049
|
+
(crisp-menu-label) -- reused rather than re-measured, since it's the
|
|
1050
|
+
same "small muted heading above a run of rows" treatment. */
|
|
1051
|
+
.crisp-multiselect-label { padding: var(--crisp-space-1-5) var(--crisp-space-2) var(--crisp-space-0-5); font-size: var(--crisp-text-sm); font-weight: var(--crisp-weight-medium); color: var(--crisp-fg-muted); }
|
|
1048
1052
|
.crisp-multiselect-option {
|
|
1049
1053
|
box-sizing: border-box; display: flex; align-items: center; gap: var(--crisp-space-2); height: var(--crisp-size-menuRow); flex-shrink: 0;
|
|
1050
1054
|
padding: 0 var(--crisp-space-2); margin: 0; border: none; background: none; border-radius: var(--crisp-radius-md); font-family: inherit; cursor: pointer; text-align: start;
|
|
@@ -1272,6 +1276,10 @@
|
|
|
1272
1276
|
.crisp-select-search input { flex: 1; min-width: 0; border: none; outline: none; background: none; font-family: inherit; font-size: var(--crisp-text-lg); color: var(--crisp-fg-primary); }
|
|
1273
1277
|
.crisp-select-search input::placeholder { color: var(--crisp-fg-muted); }
|
|
1274
1278
|
.crisp-select-empty { padding: var(--crisp-space-3) var(--crisp-space-2); text-align: center; font-size: var(--crisp-text-md); color: var(--crisp-fg-muted); }
|
|
1279
|
+
/* #343: same measured values as Menu's own group heading
|
|
1280
|
+
(crisp-menu-label) -- reused rather than re-measured, since it's the
|
|
1281
|
+
same "small muted heading above a run of rows" treatment. */
|
|
1282
|
+
.crisp-select-label { padding: var(--crisp-space-1-5) var(--crisp-space-2) var(--crisp-space-0-5); font-size: var(--crisp-text-sm); font-weight: var(--crisp-weight-medium); color: var(--crisp-fg-muted); }
|
|
1275
1283
|
.crisp-select-option {
|
|
1276
1284
|
box-sizing: border-box; display: flex; align-items: center; gap: var(--crisp-space-2); height: var(--crisp-size-menuRow); flex-shrink: 0;
|
|
1277
1285
|
padding: 0 var(--crisp-space-2); margin: 0; border: none; background: none; border-radius: var(--crisp-radius-md);
|
package/dist/styles.layered.css
CHANGED
|
@@ -1046,6 +1046,10 @@
|
|
|
1046
1046
|
.crisp-multiselect-search svg { flex-shrink: 0; }
|
|
1047
1047
|
.crisp-multiselect-search input { flex: 1; min-width: 0; border: none; outline: none; background: none; font-family: inherit; font-size: var(--crisp-text-lg); color: var(--crisp-fg-primary); }
|
|
1048
1048
|
.crisp-multiselect-search input::placeholder { color: var(--crisp-fg-muted); }
|
|
1049
|
+
/* #343: same measured values as Menu's own group heading
|
|
1050
|
+
(crisp-menu-label) -- reused rather than re-measured, since it's the
|
|
1051
|
+
same "small muted heading above a run of rows" treatment. */
|
|
1052
|
+
.crisp-multiselect-label { padding: var(--crisp-space-1-5) var(--crisp-space-2) var(--crisp-space-0-5); font-size: var(--crisp-text-sm); font-weight: var(--crisp-weight-medium); color: var(--crisp-fg-muted); }
|
|
1049
1053
|
.crisp-multiselect-option {
|
|
1050
1054
|
box-sizing: border-box; display: flex; align-items: center; gap: var(--crisp-space-2); height: var(--crisp-size-menuRow); flex-shrink: 0;
|
|
1051
1055
|
padding: 0 var(--crisp-space-2); margin: 0; border: none; background: none; border-radius: var(--crisp-radius-md); font-family: inherit; cursor: pointer; text-align: start;
|
|
@@ -1273,6 +1277,10 @@
|
|
|
1273
1277
|
.crisp-select-search input { flex: 1; min-width: 0; border: none; outline: none; background: none; font-family: inherit; font-size: var(--crisp-text-lg); color: var(--crisp-fg-primary); }
|
|
1274
1278
|
.crisp-select-search input::placeholder { color: var(--crisp-fg-muted); }
|
|
1275
1279
|
.crisp-select-empty { padding: var(--crisp-space-3) var(--crisp-space-2); text-align: center; font-size: var(--crisp-text-md); color: var(--crisp-fg-muted); }
|
|
1280
|
+
/* #343: same measured values as Menu's own group heading
|
|
1281
|
+
(crisp-menu-label) -- reused rather than re-measured, since it's the
|
|
1282
|
+
same "small muted heading above a run of rows" treatment. */
|
|
1283
|
+
.crisp-select-label { padding: var(--crisp-space-1-5) var(--crisp-space-2) var(--crisp-space-0-5); font-size: var(--crisp-text-sm); font-weight: var(--crisp-weight-medium); color: var(--crisp-fg-muted); }
|
|
1276
1284
|
.crisp-select-option {
|
|
1277
1285
|
box-sizing: border-box; display: flex; align-items: center; gap: var(--crisp-space-2); height: var(--crisp-size-menuRow); flex-shrink: 0;
|
|
1278
1286
|
padding: 0 var(--crisp-space-2); margin: 0; border: none; background: none; border-radius: var(--crisp-radius-md);
|
|
@@ -4,6 +4,14 @@ export type MultiSelectOption = {
|
|
|
4
4
|
label: string;
|
|
5
5
|
/** Chip colour tone; falls back to a deterministic pastel per value. */
|
|
6
6
|
tone?: string;
|
|
7
|
+
/**
|
|
8
|
+
* Group heading, rendered above this option (#343). A header renders once
|
|
9
|
+
* per run of consecutive options sharing the same `group` — like native
|
|
10
|
+
* `<optgroup>`, grouping is positional: pre-sort `options` so same-group
|
|
11
|
+
* rows are adjacent, or the same label renders more than once. Options
|
|
12
|
+
* with no `group` render exactly as before this existed.
|
|
13
|
+
*/
|
|
14
|
+
group?: string;
|
|
7
15
|
};
|
|
8
16
|
export type MultiSelectProps = Omit<React.ComponentPropsWithoutRef<"div">, "value" | "defaultValue" | "onChange"> & {
|
|
9
17
|
options: MultiSelectOption[];
|
|
@@ -7,6 +7,14 @@ export type SelectOption = {
|
|
|
7
7
|
/** A status colour dot shown before the label (status/select fields). */
|
|
8
8
|
color?: string;
|
|
9
9
|
disabled?: boolean;
|
|
10
|
+
/**
|
|
11
|
+
* Group heading, rendered above this option (#343). A header renders once
|
|
12
|
+
* per run of consecutive options sharing the same `group` — like native
|
|
13
|
+
* `<optgroup>`, grouping is positional: pre-sort `options` so same-group
|
|
14
|
+
* rows are adjacent, or the same label renders more than once. Options
|
|
15
|
+
* with no `group` render exactly as before this existed.
|
|
16
|
+
*/
|
|
17
|
+
group?: string;
|
|
10
18
|
};
|
|
11
19
|
export type SelectProps = Omit<React.ComponentPropsWithoutRef<"div">, "value" | "defaultValue" | "onChange"> & {
|
|
12
20
|
options: SelectOption[];
|