@techsio/ui-kit 0.49.0 → 0.50.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/molecules/combobox.js +204 -50
- package/dist/src/molecules/combobox.d.ts +50 -4
- package/dist/src/molecules/combobox.d.ts.map +1 -1
- package/dist/src/templates/facet-filter-panel.d.ts +96 -0
- package/dist/src/templates/facet-filter-panel.d.ts.map +1 -0
- package/dist/src/templates/search-suggestions.d.ts +23 -0
- package/dist/src/templates/search-suggestions.d.ts.map +1 -0
- package/dist/stories/changelog/changelog.stories.d.ts.map +1 -1
- package/dist/stories/molecules/combobox.stories.d.ts +6 -0
- package/dist/stories/molecules/combobox.stories.d.ts.map +1 -1
- package/dist/stories/templates/facet-filter-panel.stories.d.ts +17 -0
- package/dist/stories/templates/facet-filter-panel.stories.d.ts.map +1 -0
- package/dist/stories/templates/search-suggestions.stories.d.ts +119 -0
- package/dist/stories/templates/search-suggestions.stories.d.ts.map +1 -0
- package/dist/templates/facet-filter-panel.js +310 -0
- package/dist/templates/search-suggestions.js +14 -0
- package/dist/test/combobox.behavior.spec.d.ts +2 -0
- package/dist/test/combobox.behavior.spec.d.ts.map +1 -0
- package/dist/test/facet-filter-panel.spec.d.ts +2 -0
- package/dist/test/facet-filter-panel.spec.d.ts.map +1 -0
- package/dist/test/search-suggestions.spec.d.ts +2 -0
- package/dist/test/search-suggestions.spec.d.ts.map +1 -0
- package/package.json +1 -1
- package/src/tokens/components/components.css +2 -0
- package/src/tokens/components/molecules/_combobox.css +22 -0
- package/src/tokens/components/templates/_facet-filter-panel.css +43 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { createElement, useEffect, useId, useMemo, useState } from "react";
|
|
2
3
|
import { collection as combobox_collection, connect, machine } from "@zag-js/combobox";
|
|
3
4
|
import { Portal, normalizeProps, useMachine } from "@zag-js/react";
|
|
4
|
-
import { useEffect, useId, useState } from "react";
|
|
5
5
|
import { ActionIcon } from "../atoms/action-icon.js";
|
|
6
6
|
import { Button } from "../atoms/button.js";
|
|
7
7
|
import { Icon } from "../atoms/icon.js";
|
|
@@ -53,7 +53,7 @@ const comboboxVariants = tv({
|
|
|
53
53
|
content: [
|
|
54
54
|
"popup-surface-base",
|
|
55
55
|
"w-full",
|
|
56
|
-
"flex flex-col",
|
|
56
|
+
"flex flex-col overflow-hidden",
|
|
57
57
|
"duration-200 ease-out motion-safe:transition-[opacity,display,translate,scale]",
|
|
58
58
|
"transition-discrete",
|
|
59
59
|
"starting:scale-98 starting:opacity-0",
|
|
@@ -62,7 +62,14 @@ const comboboxVariants = tv({
|
|
|
62
62
|
"data-[state=closed]:scale-98 data-[state=closed]:opacity-0"
|
|
63
63
|
],
|
|
64
64
|
list: [
|
|
65
|
-
"m-0 flex list-none flex-col"
|
|
65
|
+
"m-0 flex min-h-0 list-none flex-col overflow-y-auto overscroll-contain"
|
|
66
|
+
],
|
|
67
|
+
groupLabel: [
|
|
68
|
+
"combobox-popup-padding",
|
|
69
|
+
"text-combobox-group-label-size font-combobox-group-label text-combobox-group-fg"
|
|
70
|
+
],
|
|
71
|
+
footer: [
|
|
72
|
+
"combobox-popup-padding shrink-0 border-t border-combobox-footer-border"
|
|
66
73
|
],
|
|
67
74
|
itemText: [
|
|
68
75
|
"min-w-0 flex-grow truncate"
|
|
@@ -83,7 +90,12 @@ const comboboxVariants = tv({
|
|
|
83
90
|
],
|
|
84
91
|
emptyState: [
|
|
85
92
|
"px-(--popup-item-x) py-(--popup-item-y)",
|
|
86
|
-
"text-
|
|
93
|
+
"text-combobox-status-fg"
|
|
94
|
+
],
|
|
95
|
+
status: [
|
|
96
|
+
"combobox-status-gap flex items-center",
|
|
97
|
+
"px-(--popup-item-x) py-(--popup-item-y)",
|
|
98
|
+
"text-combobox-status-fg"
|
|
87
99
|
],
|
|
88
100
|
triggerIndicator: [
|
|
89
101
|
"text-combobox-trigger-fg-base group-hover:text-combobox-trigger-fg-hover",
|
|
@@ -142,65 +154,151 @@ const comboboxVariants = tv({
|
|
|
142
154
|
size: "md"
|
|
143
155
|
}
|
|
144
156
|
});
|
|
145
|
-
function Combobox({ id, name, label, size, placeholder = "Select option", disabled = false, readOnly = false, required = false, items
|
|
157
|
+
function Combobox({ id, name, label, size, placeholder = "Select option", disabled = false, readOnly = false, required = false, items, groups, value, defaultValue, inputValue, multiple = false, validateStatus, helpText, showHelpTextIcon = true, noResultsMessage = 'No results found for "{inputValue}"', clearable = true, selectionBehavior = "replace", closeOnSelect = true, allowCustomValue = false, loopFocus = true, autoFocus = false, open, defaultOpen, triggerIcon = "token-icon-combobox-chevron", triggerIconSize, clearIcon = "token-icon-combobox-clear", inputBehavior = "autocomplete", filterBehavior = "local", loading = false, loadingMessage = "Loading results", error, retryLabel = "Retry", onRetry, renderItem, onChange, onInputValueChange, onOpenChange, mode = "selection", navigate, footer, portalled = true }) {
|
|
146
158
|
const generatedId = useId();
|
|
147
159
|
const uniqueId = id || generatedId;
|
|
148
|
-
const
|
|
160
|
+
const listId = `${uniqueId}-listbox`;
|
|
161
|
+
const helpTextId = `${uniqueId}-help`;
|
|
162
|
+
const navigation = "navigation" === mode;
|
|
163
|
+
const allItems = useMemo(()=>groups ? groups.flatMap((group)=>group.items) : items ?? [], [
|
|
164
|
+
groups,
|
|
165
|
+
items
|
|
166
|
+
]);
|
|
167
|
+
const [options, setOptions] = useState(allItems);
|
|
149
168
|
useEffect(()=>{
|
|
150
|
-
setOptions(
|
|
169
|
+
setOptions(allItems);
|
|
151
170
|
}, [
|
|
152
|
-
|
|
171
|
+
allItems
|
|
153
172
|
]);
|
|
173
|
+
const displayedItems = "external" === filterBehavior ? allItems : options;
|
|
174
|
+
const resultsHidden = loading || Boolean(error);
|
|
154
175
|
const collection = combobox_collection({
|
|
155
|
-
items:
|
|
176
|
+
items: displayedItems,
|
|
156
177
|
itemToString: (item)=>item.label,
|
|
157
178
|
itemToValue: (item)=>item.value,
|
|
158
|
-
isItemDisabled: (item)
|
|
179
|
+
isItemDisabled: (item)=>Boolean(resultsHidden || item.disabled || readOnly || navigation && !item.href)
|
|
159
180
|
});
|
|
160
181
|
const service = useMachine(machine, {
|
|
161
182
|
id: uniqueId,
|
|
162
|
-
name,
|
|
183
|
+
name: navigation ? void 0 : name,
|
|
163
184
|
collection,
|
|
164
185
|
disabled,
|
|
165
186
|
readOnly,
|
|
166
187
|
closeOnSelect,
|
|
167
|
-
selectionBehavior,
|
|
168
|
-
allowCustomValue,
|
|
188
|
+
selectionBehavior: navigation ? "preserve" : selectionBehavior,
|
|
189
|
+
allowCustomValue: !navigation && allowCustomValue,
|
|
169
190
|
autoFocus,
|
|
191
|
+
open,
|
|
192
|
+
defaultOpen,
|
|
170
193
|
inputBehavior,
|
|
171
194
|
loopFocus,
|
|
195
|
+
navigate,
|
|
196
|
+
composite: false,
|
|
197
|
+
positioning: {
|
|
198
|
+
strategy: portalled ? "absolute" : "fixed"
|
|
199
|
+
},
|
|
200
|
+
scrollToIndexFn: ({ getElement })=>{
|
|
201
|
+
getElement()?.scrollIntoView({
|
|
202
|
+
block: "nearest",
|
|
203
|
+
inline: "nearest"
|
|
204
|
+
});
|
|
205
|
+
},
|
|
206
|
+
invalid: "error" === validateStatus,
|
|
172
207
|
ids: {
|
|
173
208
|
label: `${uniqueId}-label`,
|
|
174
209
|
input: `${uniqueId}-input`,
|
|
175
210
|
control: `${uniqueId}-control`
|
|
176
211
|
},
|
|
177
|
-
value: value
|
|
178
|
-
|
|
179
|
-
|
|
212
|
+
value: navigation ? [] : "string" == typeof value ? [
|
|
213
|
+
value
|
|
214
|
+
] : value,
|
|
215
|
+
defaultValue: navigation ? void 0 : "string" == typeof defaultValue ? [
|
|
216
|
+
defaultValue
|
|
217
|
+
] : defaultValue,
|
|
218
|
+
multiple: !navigation && multiple,
|
|
180
219
|
inputValue,
|
|
181
220
|
onValueChange: ({ value: selectedValue })=>{
|
|
182
|
-
onChange?.(selectedValue);
|
|
221
|
+
if (!navigation) onChange?.(selectedValue);
|
|
183
222
|
},
|
|
184
223
|
onInputValueChange: ({ inputValue: newItemInputValue })=>{
|
|
185
|
-
|
|
186
|
-
|
|
224
|
+
if ("local" === filterBehavior) {
|
|
225
|
+
const filtered = allItems.filter((item)=>item.label.toLowerCase().includes(newItemInputValue.toLowerCase()));
|
|
226
|
+
setOptions(filtered);
|
|
227
|
+
}
|
|
187
228
|
onInputValueChange?.(newItemInputValue);
|
|
188
229
|
},
|
|
189
230
|
onOpenChange: ({ open })=>{
|
|
190
|
-
setOptions(
|
|
231
|
+
setOptions(allItems);
|
|
191
232
|
onOpenChange?.(open);
|
|
192
233
|
}
|
|
193
234
|
});
|
|
194
235
|
const api = connect(service, normalizeProps);
|
|
195
|
-
const
|
|
196
|
-
const { ...restInputProps } = inputProps;
|
|
197
|
-
const { root, label: labelStyles, control, input, trigger, positioner, content, list, item: itemSlot, itemText, itemIndicator, emptyState, triggerIndicator } = comboboxVariants({
|
|
236
|
+
const { root, label: labelStyles, control, input, trigger, positioner, content, list, groupLabel, footer: footerSlot, item: itemSlot, itemText, itemIndicator, emptyState, status: statusSlot, triggerIndicator } = comboboxVariants({
|
|
198
237
|
size
|
|
199
238
|
});
|
|
200
239
|
const hasOptions = api.collection.size > 0;
|
|
201
|
-
const showEmptyState = !hasOptions && Boolean(api.inputValue);
|
|
240
|
+
const showEmptyState = !resultsHidden && !hasOptions && Boolean(api.inputValue);
|
|
241
|
+
let state = "idle";
|
|
242
|
+
if (loading) state = "loading";
|
|
243
|
+
else if (error) state = "error";
|
|
244
|
+
else if (hasOptions) state = "results";
|
|
245
|
+
else if (showEmptyState) state = "empty";
|
|
246
|
+
const visibleValues = new Set(collection.items.map((item)=>item.value));
|
|
247
|
+
const renderOption = (item)=>{
|
|
248
|
+
const itemProps = api.getItemProps({
|
|
249
|
+
item
|
|
250
|
+
});
|
|
251
|
+
const itemContent = renderItem ? renderItem(item) : /*#__PURE__*/ jsx("span", {
|
|
252
|
+
className: itemText(),
|
|
253
|
+
children: item.label
|
|
254
|
+
});
|
|
255
|
+
if (navigation) {
|
|
256
|
+
const blocked = disabled || readOnly || item.disabled || !item.href;
|
|
257
|
+
return /*#__PURE__*/ createElement("a", {
|
|
258
|
+
...itemProps,
|
|
259
|
+
"aria-label": item.label,
|
|
260
|
+
className: itemSlot(),
|
|
261
|
+
href: blocked ? void 0 : item.href,
|
|
262
|
+
key: item.value,
|
|
263
|
+
onClick: (event)=>{
|
|
264
|
+
if (blocked) return void event.preventDefault();
|
|
265
|
+
itemProps.onClick?.(event);
|
|
266
|
+
if (navigate && !event.defaultPrevented && 0 === event.button && !event.metaKey && !event.ctrlKey && !event.shiftKey && !event.altKey) {
|
|
267
|
+
event.preventDefault();
|
|
268
|
+
navigate({
|
|
269
|
+
node: event.currentTarget,
|
|
270
|
+
href: event.currentTarget.href,
|
|
271
|
+
value: item.value
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
}, itemContent);
|
|
276
|
+
}
|
|
277
|
+
return /*#__PURE__*/ createElement("div", {
|
|
278
|
+
...itemProps,
|
|
279
|
+
"aria-label": item.label,
|
|
280
|
+
className: itemSlot(),
|
|
281
|
+
key: item.value,
|
|
282
|
+
children: [
|
|
283
|
+
itemContent,
|
|
284
|
+
/*#__PURE__*/ jsx("span", {
|
|
285
|
+
...api.getItemIndicatorProps({
|
|
286
|
+
item
|
|
287
|
+
}),
|
|
288
|
+
className: itemIndicator(),
|
|
289
|
+
children: /*#__PURE__*/ jsx(Icon, {
|
|
290
|
+
icon: "token-icon-check",
|
|
291
|
+
size: "current"
|
|
292
|
+
})
|
|
293
|
+
})
|
|
294
|
+
]
|
|
295
|
+
});
|
|
296
|
+
};
|
|
202
297
|
return /*#__PURE__*/ jsxs("div", {
|
|
298
|
+
...api.getRootProps(),
|
|
203
299
|
className: root(),
|
|
300
|
+
"data-mode": mode,
|
|
301
|
+
"data-status": state,
|
|
204
302
|
children: [
|
|
205
303
|
label && /*#__PURE__*/ jsx(Label, {
|
|
206
304
|
className: labelStyles(),
|
|
@@ -216,20 +314,33 @@ function Combobox({ id, name, label, size, placeholder = "Select option", disabl
|
|
|
216
314
|
children: [
|
|
217
315
|
/*#__PURE__*/ jsx(Input, {
|
|
218
316
|
className: input(),
|
|
219
|
-
...
|
|
220
|
-
|
|
317
|
+
...api.getInputProps(),
|
|
318
|
+
"aria-controls": api.open ? listId : void 0,
|
|
319
|
+
"aria-describedby": helpText ? helpTextId : void 0,
|
|
320
|
+
name: navigation ? void 0 : name,
|
|
221
321
|
placeholder: placeholder,
|
|
222
322
|
required: required,
|
|
223
323
|
size: size
|
|
224
324
|
}),
|
|
225
|
-
clearable && api.value.length > 0 && /*#__PURE__*/ jsx(ActionIcon, {
|
|
325
|
+
clearable && (navigation ? Boolean(api.inputValue) : api.value.length > 0) && /*#__PURE__*/ jsx(ActionIcon, {
|
|
226
326
|
icon: clearIcon,
|
|
227
327
|
size: size ?? "md",
|
|
228
328
|
tone: "neutral",
|
|
229
|
-
...api.getClearTriggerProps()
|
|
329
|
+
...api.getClearTriggerProps(),
|
|
330
|
+
disabled: disabled || readOnly,
|
|
331
|
+
hidden: false,
|
|
332
|
+
onClick: (event)=>{
|
|
333
|
+
if (navigation) {
|
|
334
|
+
if (disabled || readOnly) return;
|
|
335
|
+
api.setInputValue("");
|
|
336
|
+
api.focus();
|
|
337
|
+
} else api.getClearTriggerProps().onClick?.(event);
|
|
338
|
+
}
|
|
230
339
|
}),
|
|
231
340
|
/*#__PURE__*/ jsx(Button, {
|
|
232
341
|
...api.getTriggerProps(),
|
|
342
|
+
"aria-controls": api.open ? listId : void 0,
|
|
343
|
+
"aria-haspopup": "listbox",
|
|
233
344
|
className: trigger(),
|
|
234
345
|
size: "current",
|
|
235
346
|
theme: "unstyled",
|
|
@@ -242,48 +353,91 @@ function Combobox({ id, name, label, size, placeholder = "Select option", disabl
|
|
|
242
353
|
]
|
|
243
354
|
}),
|
|
244
355
|
/*#__PURE__*/ jsx(Portal, {
|
|
356
|
+
disabled: !portalled,
|
|
245
357
|
children: /*#__PURE__*/ jsx("div", {
|
|
246
358
|
...api.getPositionerProps(),
|
|
247
359
|
className: positioner(),
|
|
248
360
|
children: /*#__PURE__*/ jsxs("div", {
|
|
249
361
|
...api.getContentProps(),
|
|
362
|
+
"aria-labelledby": void 0,
|
|
250
363
|
className: content(),
|
|
364
|
+
"data-status": state,
|
|
365
|
+
role: void 0,
|
|
366
|
+
tabIndex: void 0,
|
|
251
367
|
children: [
|
|
252
|
-
|
|
368
|
+
loading ? /*#__PURE__*/ jsxs("div", {
|
|
369
|
+
className: statusSlot(),
|
|
370
|
+
role: "status",
|
|
371
|
+
children: [
|
|
372
|
+
/*#__PURE__*/ jsx(Icon, {
|
|
373
|
+
icon: "token-icon-spinner",
|
|
374
|
+
size: "current"
|
|
375
|
+
}),
|
|
376
|
+
/*#__PURE__*/ jsx("span", {
|
|
377
|
+
children: loadingMessage
|
|
378
|
+
})
|
|
379
|
+
]
|
|
380
|
+
}) : error ? /*#__PURE__*/ jsxs("div", {
|
|
381
|
+
className: statusSlot(),
|
|
382
|
+
role: "alert",
|
|
383
|
+
children: [
|
|
384
|
+
/*#__PURE__*/ jsx("span", {
|
|
385
|
+
className: "min-w-0 flex-1",
|
|
386
|
+
children: error
|
|
387
|
+
}),
|
|
388
|
+
onRetry && /*#__PURE__*/ jsx(Button, {
|
|
389
|
+
disabled: disabled || readOnly,
|
|
390
|
+
onClick: onRetry,
|
|
391
|
+
size: "sm",
|
|
392
|
+
variant: "secondary",
|
|
393
|
+
children: retryLabel
|
|
394
|
+
})
|
|
395
|
+
]
|
|
396
|
+
}) : showEmptyState ? /*#__PURE__*/ jsx("div", {
|
|
397
|
+
className: emptyState(),
|
|
398
|
+
role: "status",
|
|
399
|
+
children: noResultsMessage.replace("{inputValue}", api.inputValue)
|
|
400
|
+
}) : null,
|
|
401
|
+
/*#__PURE__*/ jsx("div", {
|
|
253
402
|
...api.getListProps(),
|
|
403
|
+
"aria-busy": loading || void 0,
|
|
254
404
|
className: list(),
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
405
|
+
id: listId,
|
|
406
|
+
children: !resultsHidden && (groups ? groups.map((group)=>{
|
|
407
|
+
const groupItems = group.items.filter((item)=>visibleValues.has(item.value));
|
|
408
|
+
if (0 === groupItems.length) return null;
|
|
409
|
+
return /*#__PURE__*/ createElement("div", {
|
|
410
|
+
...api.getItemGroupProps({
|
|
411
|
+
id: group.id
|
|
258
412
|
}),
|
|
259
|
-
|
|
413
|
+
"aria-labelledby": group.label ? api.getItemGroupProps({
|
|
414
|
+
id: group.id
|
|
415
|
+
})["aria-labelledby"] : void 0,
|
|
416
|
+
key: group.id,
|
|
260
417
|
children: [
|
|
261
|
-
/*#__PURE__*/ jsx("
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
}),
|
|
265
|
-
/*#__PURE__*/ jsx("span", {
|
|
266
|
-
...api.getItemIndicatorProps({
|
|
267
|
-
item
|
|
418
|
+
group.label && /*#__PURE__*/ jsx("div", {
|
|
419
|
+
...api.getItemGroupLabelProps({
|
|
420
|
+
htmlFor: group.id
|
|
268
421
|
}),
|
|
269
|
-
className:
|
|
270
|
-
children:
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
})
|
|
274
|
-
})
|
|
422
|
+
className: groupLabel(),
|
|
423
|
+
children: group.label
|
|
424
|
+
}),
|
|
425
|
+
groupItems.map(renderOption)
|
|
275
426
|
]
|
|
276
|
-
}
|
|
427
|
+
});
|
|
428
|
+
}) : collection.items.map(renderOption))
|
|
277
429
|
}),
|
|
278
|
-
|
|
279
|
-
className:
|
|
280
|
-
|
|
430
|
+
footer && /*#__PURE__*/ jsx("div", {
|
|
431
|
+
className: footerSlot(),
|
|
432
|
+
"data-part": "footer",
|
|
433
|
+
children: footer
|
|
281
434
|
})
|
|
282
435
|
]
|
|
283
436
|
})
|
|
284
437
|
})
|
|
285
438
|
}),
|
|
286
439
|
helpText && /*#__PURE__*/ jsx(StatusText, {
|
|
440
|
+
id: helpTextId,
|
|
287
441
|
showIcon: showHelpTextIcon,
|
|
288
442
|
size: size,
|
|
289
443
|
status: validateStatus,
|
|
@@ -1,3 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Combobox — @techsio/ui-kit molecule.
|
|
3
|
+
*
|
|
4
|
+
* @component Combobox
|
|
5
|
+
* @componentVersion v1.3.0
|
|
6
|
+
* @skill combobox-usage
|
|
7
|
+
* @changelog libs/ui/stories/changelog/changelog.stories.tsx
|
|
8
|
+
*
|
|
9
|
+
* Versioning is enforced at commit by scripts/check-skill-sync.mjs: @componentVersion must match
|
|
10
|
+
* the combobox-usage skill's component_version and a changelog entry. Bump all three together.
|
|
11
|
+
*/
|
|
12
|
+
import { type Props as ZagComboboxProps } from "@zag-js/combobox";
|
|
13
|
+
import { type ReactNode } from "react";
|
|
1
14
|
import type { VariantProps } from "tailwind-variants";
|
|
2
15
|
import { type IconProps, type IconType } from "../atoms/icon.js";
|
|
3
16
|
declare const comboboxVariants: import("tailwind-variants").TVReturnType<{
|
|
@@ -33,10 +46,13 @@ declare const comboboxVariants: import("tailwind-variants").TVReturnType<{
|
|
|
33
46
|
positioner: string[];
|
|
34
47
|
content: string[];
|
|
35
48
|
list: string[];
|
|
49
|
+
groupLabel: string[];
|
|
50
|
+
footer: string[];
|
|
36
51
|
itemText: string[];
|
|
37
52
|
item: string[];
|
|
38
53
|
itemIndicator: string[];
|
|
39
54
|
emptyState: string[];
|
|
55
|
+
status: string[];
|
|
40
56
|
triggerIndicator: string[];
|
|
41
57
|
helper: string[];
|
|
42
58
|
multiple: never[];
|
|
@@ -73,10 +89,13 @@ declare const comboboxVariants: import("tailwind-variants").TVReturnType<{
|
|
|
73
89
|
positioner: string[];
|
|
74
90
|
content: string[];
|
|
75
91
|
list: string[];
|
|
92
|
+
groupLabel: string[];
|
|
93
|
+
footer: string[];
|
|
76
94
|
itemText: string[];
|
|
77
95
|
item: string[];
|
|
78
96
|
itemIndicator: string[];
|
|
79
97
|
emptyState: string[];
|
|
98
|
+
status: string[];
|
|
80
99
|
triggerIndicator: string[];
|
|
81
100
|
helper: string[];
|
|
82
101
|
multiple: never[];
|
|
@@ -113,10 +132,13 @@ declare const comboboxVariants: import("tailwind-variants").TVReturnType<{
|
|
|
113
132
|
positioner: string[];
|
|
114
133
|
content: string[];
|
|
115
134
|
list: string[];
|
|
135
|
+
groupLabel: string[];
|
|
136
|
+
footer: string[];
|
|
116
137
|
itemText: string[];
|
|
117
138
|
item: string[];
|
|
118
139
|
itemIndicator: string[];
|
|
119
140
|
emptyState: string[];
|
|
141
|
+
status: string[];
|
|
120
142
|
triggerIndicator: string[];
|
|
121
143
|
helper: string[];
|
|
122
144
|
multiple: never[];
|
|
@@ -127,8 +149,20 @@ export type ComboboxItem<T = unknown> = {
|
|
|
127
149
|
value: string;
|
|
128
150
|
disabled?: boolean;
|
|
129
151
|
data?: T;
|
|
152
|
+
href?: string;
|
|
130
153
|
};
|
|
131
|
-
export
|
|
154
|
+
export type ComboboxItemGroup<T = unknown> = {
|
|
155
|
+
id: string;
|
|
156
|
+
label?: string;
|
|
157
|
+
items: ComboboxItem<T>[];
|
|
158
|
+
};
|
|
159
|
+
export type ComboboxProps<T = unknown> = VariantProps<typeof comboboxVariants> & ({
|
|
160
|
+
items: ComboboxItem<T>[];
|
|
161
|
+
groups?: never;
|
|
162
|
+
} | {
|
|
163
|
+
items?: never;
|
|
164
|
+
groups: ComboboxItemGroup<T>[];
|
|
165
|
+
}) & {
|
|
132
166
|
id?: string;
|
|
133
167
|
name?: string;
|
|
134
168
|
label?: string;
|
|
@@ -136,7 +170,6 @@ export interface ComboboxProps<T = unknown> extends VariantProps<typeof combobox
|
|
|
136
170
|
disabled?: boolean;
|
|
137
171
|
readOnly?: boolean;
|
|
138
172
|
required?: boolean;
|
|
139
|
-
items: ComboboxItem<T>[];
|
|
140
173
|
value?: string | string[];
|
|
141
174
|
defaultValue?: string | string[];
|
|
142
175
|
inputValue?: string;
|
|
@@ -151,6 +184,8 @@ export interface ComboboxProps<T = unknown> extends VariantProps<typeof combobox
|
|
|
151
184
|
allowCustomValue?: boolean;
|
|
152
185
|
loopFocus?: boolean;
|
|
153
186
|
autoFocus?: boolean;
|
|
187
|
+
open?: boolean;
|
|
188
|
+
defaultOpen?: boolean;
|
|
154
189
|
triggerIcon?: IconType;
|
|
155
190
|
triggerIconSize?: IconProps["size"];
|
|
156
191
|
clearIcon?: IconType;
|
|
@@ -158,7 +193,18 @@ export interface ComboboxProps<T = unknown> extends VariantProps<typeof combobox
|
|
|
158
193
|
onInputValueChange?: (value: string) => void;
|
|
159
194
|
onOpenChange?: (open: boolean) => void;
|
|
160
195
|
inputBehavior?: "autohighlight" | "autocomplete" | "none";
|
|
161
|
-
|
|
162
|
-
|
|
196
|
+
filterBehavior?: "local" | "external";
|
|
197
|
+
loading?: boolean;
|
|
198
|
+
loadingMessage?: string;
|
|
199
|
+
error?: ReactNode;
|
|
200
|
+
retryLabel?: string;
|
|
201
|
+
onRetry?: () => void;
|
|
202
|
+
renderItem?: (item: ComboboxItem<T>) => ReactNode;
|
|
203
|
+
mode?: "selection" | "navigation";
|
|
204
|
+
navigate?: ZagComboboxProps["navigate"];
|
|
205
|
+
footer?: ReactNode;
|
|
206
|
+
portalled?: boolean;
|
|
207
|
+
};
|
|
208
|
+
export declare function Combobox<T = unknown>({ id, name, label, size, placeholder, disabled, readOnly, required, items, groups, value, defaultValue, inputValue, multiple, validateStatus, helpText, showHelpTextIcon, noResultsMessage, clearable, selectionBehavior, closeOnSelect, allowCustomValue, loopFocus, autoFocus, open, defaultOpen, triggerIcon, triggerIconSize, clearIcon, inputBehavior, filterBehavior, loading, loadingMessage, error, retryLabel, onRetry, renderItem, onChange, onInputValueChange, onOpenChange, mode, navigate, footer, portalled, }: ComboboxProps<T>): import("react/jsx-runtime").JSX.Element;
|
|
163
209
|
export {};
|
|
164
210
|
//# sourceMappingURL=combobox.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"combobox.d.ts","sourceRoot":"","sources":["../../../src/molecules/combobox.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"combobox.d.ts","sourceRoot":"","sources":["../../../src/molecules/combobox.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FacetFilterPanel - @techsio/ui-kit template.
|
|
3
|
+
*
|
|
4
|
+
* @component FacetFilterPanel
|
|
5
|
+
* @componentVersion v1.0.1
|
|
6
|
+
* @skill facet-filter-panel-usage
|
|
7
|
+
* @changelog libs/ui/stories/changelog/changelog.stories.tsx
|
|
8
|
+
*/
|
|
9
|
+
import type { ReactNode } from "react";
|
|
10
|
+
export type FacetFilterOption = {
|
|
11
|
+
value: string;
|
|
12
|
+
label: ReactNode;
|
|
13
|
+
count?: number;
|
|
14
|
+
disabled?: boolean;
|
|
15
|
+
};
|
|
16
|
+
type FacetFilterGroupBase = {
|
|
17
|
+
id: string;
|
|
18
|
+
disabled?: boolean;
|
|
19
|
+
};
|
|
20
|
+
export type FacetFilterOptionsGroup = FacetFilterGroupBase & {
|
|
21
|
+
type: "options";
|
|
22
|
+
label: ReactNode;
|
|
23
|
+
options: readonly FacetFilterOption[];
|
|
24
|
+
collapseAfter?: number;
|
|
25
|
+
emptyLabel?: ReactNode;
|
|
26
|
+
};
|
|
27
|
+
export type FacetFilterRangeGroup = FacetFilterGroupBase & {
|
|
28
|
+
type: "range";
|
|
29
|
+
label: string;
|
|
30
|
+
min: number;
|
|
31
|
+
max: number;
|
|
32
|
+
step?: number;
|
|
33
|
+
minStepsBetweenThumbs?: number;
|
|
34
|
+
value: readonly [number, number];
|
|
35
|
+
formatValue?: (value: number) => string;
|
|
36
|
+
formatRangeText?: (values: number[]) => string;
|
|
37
|
+
};
|
|
38
|
+
export type FacetFilterGroup = FacetFilterOptionsGroup | FacetFilterRangeGroup;
|
|
39
|
+
export type FacetFilterActiveItem = {
|
|
40
|
+
id: string;
|
|
41
|
+
label: ReactNode;
|
|
42
|
+
removeLabel: string;
|
|
43
|
+
};
|
|
44
|
+
export type FacetFilterOptionChangeDetails = {
|
|
45
|
+
groupId: string;
|
|
46
|
+
value: string;
|
|
47
|
+
checked: boolean;
|
|
48
|
+
};
|
|
49
|
+
export type FacetFilterRangeChangeDetails = {
|
|
50
|
+
groupId: string;
|
|
51
|
+
value: [number, number];
|
|
52
|
+
};
|
|
53
|
+
export type FacetFilterPanelProps = {
|
|
54
|
+
title: ReactNode;
|
|
55
|
+
groups: readonly FacetFilterGroup[];
|
|
56
|
+
selectedValues?: Readonly<Record<string, readonly string[]>>;
|
|
57
|
+
activeFilters?: readonly FacetFilterActiveItem[];
|
|
58
|
+
presentation?: "inline" | "drawer";
|
|
59
|
+
disabled?: boolean;
|
|
60
|
+
pending?: boolean;
|
|
61
|
+
pendingLabel?: ReactNode;
|
|
62
|
+
activeFiltersLabel?: ReactNode;
|
|
63
|
+
resetLabel?: ReactNode;
|
|
64
|
+
showMoreLabel?: (hiddenCount: number) => ReactNode;
|
|
65
|
+
showLessLabel?: ReactNode;
|
|
66
|
+
expandedGroups?: string[];
|
|
67
|
+
defaultExpandedGroups?: string[];
|
|
68
|
+
onExpandedGroupsChange?: (groupIds: string[]) => void;
|
|
69
|
+
drawerTriggerLabel?: ReactNode;
|
|
70
|
+
drawerPlacement?: "left" | "right";
|
|
71
|
+
drawerSize?: "xs" | "sm" | "md" | "lg" | "xl" | "full";
|
|
72
|
+
drawerOpen?: boolean;
|
|
73
|
+
defaultDrawerOpen?: boolean;
|
|
74
|
+
onDrawerOpenChange?: (open: boolean) => void;
|
|
75
|
+
className?: string;
|
|
76
|
+
onOptionChange?: (details: FacetFilterOptionChangeDetails) => void;
|
|
77
|
+
onRangeChange?: (details: FacetFilterRangeChangeDetails) => void;
|
|
78
|
+
onRangeChangeEnd?: (details: FacetFilterRangeChangeDetails) => void;
|
|
79
|
+
onRemoveFilter?: (id: string) => void;
|
|
80
|
+
onReset?: () => void;
|
|
81
|
+
};
|
|
82
|
+
export type FacetFilterActiveFiltersProps = {
|
|
83
|
+
items: readonly FacetFilterActiveItem[];
|
|
84
|
+
label?: ReactNode;
|
|
85
|
+
resetLabel?: ReactNode;
|
|
86
|
+
disabled?: boolean;
|
|
87
|
+
className?: string;
|
|
88
|
+
onRemove?: (id: string) => void;
|
|
89
|
+
onReset?: () => void;
|
|
90
|
+
};
|
|
91
|
+
export declare function FacetFilterPanel({ presentation, drawerTriggerLabel, drawerPlacement, drawerSize, drawerOpen, defaultDrawerOpen, onDrawerOpenChange, className, ...props }: FacetFilterPanelProps): import("react/jsx-runtime").JSX.Element;
|
|
92
|
+
export declare namespace FacetFilterPanel {
|
|
93
|
+
var ActiveFilters: ({ items, label, resetLabel, disabled, className, onRemove, onReset, }: FacetFilterActiveFiltersProps) => import("react/jsx-runtime").JSX.Element | null;
|
|
94
|
+
}
|
|
95
|
+
export {};
|
|
96
|
+
//# sourceMappingURL=facet-filter-panel.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"facet-filter-panel.d.ts","sourceRoot":"","sources":["../../../src/templates/facet-filter-panel.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SearchSuggestions - @techsio/ui-kit template.
|
|
3
|
+
*
|
|
4
|
+
* @component SearchSuggestions
|
|
5
|
+
* @componentVersion v1.0.0
|
|
6
|
+
* @skill search-suggestions-usage
|
|
7
|
+
* @changelog libs/ui/stories/changelog/changelog.stories.tsx
|
|
8
|
+
*/
|
|
9
|
+
import type { ReactNode } from "react";
|
|
10
|
+
import { type ComboboxItem, type ComboboxItemGroup, type ComboboxProps } from "../molecules/combobox.js";
|
|
11
|
+
export type SearchSuggestionItem<T = unknown> = ComboboxItem<T> & {
|
|
12
|
+
href: string;
|
|
13
|
+
};
|
|
14
|
+
export type SearchSuggestionGroup<T = unknown> = Omit<ComboboxItemGroup<T>, "items"> & {
|
|
15
|
+
items: SearchSuggestionItem<T>[];
|
|
16
|
+
};
|
|
17
|
+
export type SearchSuggestionsProps<T = unknown> = Omit<ComboboxProps<T>, "items" | "groups" | "renderItem" | "footer" | "mode" | "multiple" | "value" | "defaultValue" | "onChange" | "name" | "selectionBehavior" | "allowCustomValue"> & {
|
|
18
|
+
groups: SearchSuggestionGroup<T>[];
|
|
19
|
+
resultSlot?: ComboboxProps<T>["renderItem"];
|
|
20
|
+
allResultsLink?: ReactNode;
|
|
21
|
+
};
|
|
22
|
+
export declare function SearchSuggestions<T = unknown>({ resultSlot, allResultsLink, filterBehavior, inputBehavior, portalled, ...props }: SearchSuggestionsProps<T>): import("react/jsx-runtime").JSX.Element;
|
|
23
|
+
//# sourceMappingURL=search-suggestions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search-suggestions.d.ts","sourceRoot":"","sources":["../../../src/templates/search-suggestions.tsx"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AACtC,OAAO,EAEL,KAAK,YAAY,EACjB,KAAK,iBAAiB,EACtB,KAAK,aAAa,EACnB,MAAM,uBAAuB,CAAA;AAE9B,MAAM,MAAM,oBAAoB,CAAC,CAAC,GAAG,OAAO,IAAI,YAAY,CAAC,CAAC,CAAC,GAAG;IAChE,IAAI,EAAE,MAAM,CAAA;CACb,CAAA;AAED,MAAM,MAAM,qBAAqB,CAAC,CAAC,GAAG,OAAO,IAAI,IAAI,CACnD,iBAAiB,CAAC,CAAC,CAAC,EACpB,OAAO,CACR,GAAG;IACF,KAAK,EAAE,oBAAoB,CAAC,CAAC,CAAC,EAAE,CAAA;CACjC,CAAA;AAED,MAAM,MAAM,sBAAsB,CAAC,CAAC,GAAG,OAAO,IAAI,IAAI,CACpD,aAAa,CAAC,CAAC,CAAC,EACd,OAAO,GACP,QAAQ,GACR,YAAY,GACZ,QAAQ,GACR,MAAM,GACN,UAAU,GACV,OAAO,GACP,cAAc,GACd,UAAU,GACV,MAAM,GACN,mBAAmB,GACnB,kBAAkB,CACrB,GAAG;IACF,MAAM,EAAE,qBAAqB,CAAC,CAAC,CAAC,EAAE,CAAA;IAClC,UAAU,CAAC,EAAE,aAAa,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAA;IAC3C,cAAc,CAAC,EAAE,SAAS,CAAA;CAC3B,CAAA;AAED,wBAAgB,iBAAiB,CAAC,CAAC,GAAG,OAAO,EAAE,EAC7C,UAAU,EACV,cAAc,EACd,cAA2B,EAC3B,aAAsB,EACtB,SAAiB,EACjB,GAAG,KAAK,EACT,EAAE,sBAAsB,CAAC,CAAC,CAAC,2CAY3B"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"changelog.stories.d.ts","sourceRoot":"","sources":["../../../stories/changelog/changelog.stories.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAA;
|
|
1
|
+
{"version":3,"file":"changelog.stories.d.ts","sourceRoot":"","sources":["../../../stories/changelog/changelog.stories.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAA;AAwRtD,iBAAS,SAAS,4CAUjB;AAED,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,OAAO,SAAS,CAKhC,CAAA;AAED,eAAe,IAAI,CAAA;AAEnB,eAAO,MAAM,UAAU,EAAE,QAAQ,CAAC,OAAO,SAAS,CAAM,CAAA"}
|
|
@@ -8,4 +8,10 @@ export declare const ValidationStates: Story;
|
|
|
8
8
|
export declare const MultipleSelection: Story;
|
|
9
9
|
export declare const Sizes: Story;
|
|
10
10
|
export declare const ComplexStory: Story;
|
|
11
|
+
export declare const Grouped: Story;
|
|
12
|
+
export declare const ExternalFiltering: Story;
|
|
13
|
+
export declare const Loading: Story;
|
|
14
|
+
export declare const LoadingWithSelection: Story;
|
|
15
|
+
export declare const ErrorRetry: Story;
|
|
16
|
+
export declare const RichItem: Story;
|
|
11
17
|
//# sourceMappingURL=combobox.stories.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"combobox.stories.d.ts","sourceRoot":"","sources":["../../../stories/molecules/combobox.stories.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAA;
|
|
1
|
+
{"version":3,"file":"combobox.stories.d.ts","sourceRoot":"","sources":["../../../stories/molecules/combobox.stories.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAA;AAItD,OAAO,EAAE,QAAQ,EAAqB,MAAM,8BAA8B,CAAA;AAiB1E,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,OAAO,QAAQ,CAwE/B,CAAA;AAED,eAAe,IAAI,CAAA;AACnB,KAAK,KAAK,GAAG,QAAQ,CAAC,OAAO,QAAQ,CAAC,CAAA;AAEtC,eAAO,MAAM,UAAU,EAAE,KAiBxB,CAAA;AAED,eAAO,MAAM,gBAAgB,EAAE,KAiC9B,CAAA;AAED,eAAO,MAAM,iBAAiB,EAAE,KAmD/B,CAAA;AAED,eAAO,MAAM,KAAK,EAAE,KA0BnB,CAAA;AAED,eAAO,MAAM,YAAY,EAAE,KAgD1B,CAAA;AAED,eAAO,MAAM,OAAO,EAAE,KAsBrB,CAAA;AAED,eAAO,MAAM,iBAAiB,EAAE,KAE/B,CAAA;AAgCD,eAAO,MAAM,OAAO,EAAE,KAQrB,CAAA;AAED,eAAO,MAAM,oBAAoB,EAAE,KAQlC,CAAA;AAED,eAAO,MAAM,UAAU,EAAE,KAsBxB,CAAA;AAQD,eAAO,MAAM,QAAQ,EAAE,KAiBtB,CAAA"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from "@storybook/react";
|
|
2
|
+
import { FacetFilterPanel } from "../../src/templates/facet-filter-panel.js";
|
|
3
|
+
declare const meta: Meta<typeof FacetFilterPanel>;
|
|
4
|
+
export default meta;
|
|
5
|
+
type Story = StoryObj<typeof FacetFilterPanel>;
|
|
6
|
+
export declare const Playground: Story;
|
|
7
|
+
export declare const Selected: Story;
|
|
8
|
+
export declare const ActiveFilters: Story;
|
|
9
|
+
export declare const EmptyAndOptionAvailability: Story;
|
|
10
|
+
export declare const Disabled: Story;
|
|
11
|
+
export declare const Pending: Story;
|
|
12
|
+
export declare const Overflow: Story;
|
|
13
|
+
export declare const NarrowLayout: Story;
|
|
14
|
+
export declare const AsyncGroups: Story;
|
|
15
|
+
export declare const RejectedDrawerClose: Story;
|
|
16
|
+
export declare const DrawerOpen: Story;
|
|
17
|
+
//# sourceMappingURL=facet-filter-panel.stories.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"facet-filter-panel.stories.d.ts","sourceRoot":"","sources":["../../../stories/templates/facet-filter-panel.stories.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAA;AAItD,OAAO,EACL,gBAAgB,EAOjB,MAAM,wCAAwC,CAAA;AAoP/C,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,OAAO,gBAAgB,CAqDvC,CAAA;AAED,eAAe,IAAI,CAAA;AACnB,KAAK,KAAK,GAAG,QAAQ,CAAC,OAAO,gBAAgB,CAAC,CAAA;AAE9C,eAAO,MAAM,UAAU,EAAE,KAMxB,CAAA;AAED,eAAO,MAAM,QAAQ,EAAE,KAwBtB,CAAA;AAED,eAAO,MAAM,aAAa,EAAE,KAmB3B,CAAA;AAED,eAAO,MAAM,0BAA0B,EAAE,KA0BxC,CAAA;AAED,eAAO,MAAM,QAAQ,EAAE,KAiBtB,CAAA;AAED,eAAO,MAAM,OAAO,EAAE,KAiBrB,CAAA;AAED,eAAO,MAAM,QAAQ,EAAE,KAWtB,CAAA;AAED,eAAO,MAAM,YAAY,EAAE,KAM1B,CAAA;AAeD,eAAO,MAAM,WAAW,EAAE,KAEzB,CAAA;AAyBD,eAAO,MAAM,mBAAmB,EAAE,KAKjC,CAAA;AAED,eAAO,MAAM,UAAU,EAAE,KAcxB,CAAA"}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import type { StoryObj } from "@storybook/react";
|
|
2
|
+
import { type SearchSuggestionGroup, type SearchSuggestionsProps } from "../../src/templates/search-suggestions.js";
|
|
3
|
+
type ProductDetails = {
|
|
4
|
+
image?: string;
|
|
5
|
+
subtitle: string;
|
|
6
|
+
price?: string;
|
|
7
|
+
};
|
|
8
|
+
declare const meta: {
|
|
9
|
+
title: string;
|
|
10
|
+
component: ({ resultSlot, allResultsLink, filterBehavior, inputBehavior, portalled, ...props }: SearchSuggestionsProps<ProductDetails>) => import("react/jsx-runtime").JSX.Element;
|
|
11
|
+
tags: string[];
|
|
12
|
+
parameters: {
|
|
13
|
+
layout: string;
|
|
14
|
+
};
|
|
15
|
+
decorators: ((Story: import("storybook/internal/csf").PartialStoryFn<import("storybook-react-rsbuild").ReactRenderer, {
|
|
16
|
+
id?: string | undefined;
|
|
17
|
+
label?: string | undefined;
|
|
18
|
+
size?: "md" | "sm" | "lg" | undefined;
|
|
19
|
+
open?: boolean | undefined;
|
|
20
|
+
disabled?: boolean | undefined;
|
|
21
|
+
error?: import("react").ReactNode;
|
|
22
|
+
placeholder?: string | undefined;
|
|
23
|
+
readOnly?: boolean | undefined;
|
|
24
|
+
required?: boolean | undefined;
|
|
25
|
+
autoFocus?: boolean | undefined;
|
|
26
|
+
loading?: boolean | undefined;
|
|
27
|
+
loopFocus?: boolean | undefined;
|
|
28
|
+
inputValue?: string | undefined;
|
|
29
|
+
onInputValueChange?: ((value: string) => void) | undefined;
|
|
30
|
+
defaultOpen?: boolean | undefined;
|
|
31
|
+
inputBehavior?: "autohighlight" | "autocomplete" | "none" | undefined;
|
|
32
|
+
onOpenChange?: ((open: boolean) => void) | undefined;
|
|
33
|
+
closeOnSelect?: boolean | undefined;
|
|
34
|
+
navigate?: ((details: import("@zag-js/combobox").NavigateDetails) => void) | null | undefined;
|
|
35
|
+
validateStatus?: "default" | "error" | "success" | "warning" | undefined;
|
|
36
|
+
helpText?: string | undefined;
|
|
37
|
+
showHelpTextIcon?: boolean | undefined;
|
|
38
|
+
noResultsMessage?: string | undefined;
|
|
39
|
+
clearable?: boolean | undefined;
|
|
40
|
+
triggerIcon?: import("../../src/atoms/icon.js").IconType | undefined;
|
|
41
|
+
triggerIconSize?: "md" | "sm" | "lg" | "current" | "xs" | "xl" | "2xl" | undefined;
|
|
42
|
+
clearIcon?: import("../../src/atoms/icon.js").IconType | undefined;
|
|
43
|
+
filterBehavior?: "local" | "external" | undefined;
|
|
44
|
+
loadingMessage?: string | undefined;
|
|
45
|
+
retryLabel?: string | undefined;
|
|
46
|
+
onRetry?: (() => void) | undefined;
|
|
47
|
+
portalled?: boolean | undefined;
|
|
48
|
+
groups: SearchSuggestionGroup<ProductDetails>[];
|
|
49
|
+
resultSlot?: ((item: import("../../src/molecules/combobox.js").ComboboxItem<ProductDetails>) => import("react").ReactNode) | undefined;
|
|
50
|
+
allResultsLink?: import("react").ReactNode;
|
|
51
|
+
}>) => import("react/jsx-runtime").JSX.Element)[];
|
|
52
|
+
argTypes: {
|
|
53
|
+
label: {
|
|
54
|
+
control: "text";
|
|
55
|
+
};
|
|
56
|
+
placeholder: {
|
|
57
|
+
control: "text";
|
|
58
|
+
};
|
|
59
|
+
size: {
|
|
60
|
+
control: "select";
|
|
61
|
+
options: string[];
|
|
62
|
+
};
|
|
63
|
+
disabled: {
|
|
64
|
+
control: "boolean";
|
|
65
|
+
};
|
|
66
|
+
readOnly: {
|
|
67
|
+
control: "boolean";
|
|
68
|
+
};
|
|
69
|
+
clearable: {
|
|
70
|
+
control: "boolean";
|
|
71
|
+
};
|
|
72
|
+
loading: {
|
|
73
|
+
control: "boolean";
|
|
74
|
+
};
|
|
75
|
+
loadingMessage: {
|
|
76
|
+
control: "text";
|
|
77
|
+
};
|
|
78
|
+
noResultsMessage: {
|
|
79
|
+
control: "text";
|
|
80
|
+
};
|
|
81
|
+
retryLabel: {
|
|
82
|
+
control: "text";
|
|
83
|
+
};
|
|
84
|
+
groups: {
|
|
85
|
+
control: false;
|
|
86
|
+
};
|
|
87
|
+
resultSlot: {
|
|
88
|
+
control: false;
|
|
89
|
+
};
|
|
90
|
+
allResultsLink: {
|
|
91
|
+
control: false;
|
|
92
|
+
};
|
|
93
|
+
navigate: {
|
|
94
|
+
control: false;
|
|
95
|
+
};
|
|
96
|
+
};
|
|
97
|
+
args: {
|
|
98
|
+
groups: SearchSuggestionGroup<ProductDetails>[];
|
|
99
|
+
label: string;
|
|
100
|
+
placeholder: string;
|
|
101
|
+
resultSlot: (item: import("../../src/molecules/combobox.js").ComboboxItem<ProductDetails>) => import("react").ReactNode;
|
|
102
|
+
navigate: import("storybook/test").Mock<(...args: any[]) => any>;
|
|
103
|
+
onInputValueChange: import("storybook/test").Mock<(...args: any[]) => any>;
|
|
104
|
+
allResultsLink: import("react/jsx-runtime").JSX.Element;
|
|
105
|
+
};
|
|
106
|
+
};
|
|
107
|
+
export default meta;
|
|
108
|
+
type Story = StoryObj<typeof meta>;
|
|
109
|
+
export declare const Playground: Story;
|
|
110
|
+
export declare const Sizes: Story;
|
|
111
|
+
export declare const States: Story;
|
|
112
|
+
export declare const GroupedResults: Story;
|
|
113
|
+
export declare const WithoutGroupLabels: Story;
|
|
114
|
+
export declare const Loading: Story;
|
|
115
|
+
export declare const Empty: Story;
|
|
116
|
+
export declare const ErrorWithRetry: Story;
|
|
117
|
+
export declare const NarrowLayout: Story;
|
|
118
|
+
export declare const InDialog: Story;
|
|
119
|
+
//# sourceMappingURL=search-suggestions.stories.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search-suggestions.stories.d.ts","sourceRoot":"","sources":["../../../stories/templates/search-suggestions.stories.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAQ,QAAQ,EAAE,MAAM,kBAAkB,CAAA;AAOtD,OAAO,EAEL,KAAK,qBAAqB,EAC1B,KAAK,sBAAsB,EAC5B,MAAM,wCAAwC,CAAA;AAE/C,KAAK,cAAc,GAAG;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAAA;AA2D1E,QAAA,MAAM,IAAI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqCgD,CAAA;AAE1D,eAAe,IAAI,CAAA;AACnB,KAAK,KAAK,GAAG,QAAQ,CAAC,OAAO,IAAI,CAAC,CAAA;AAElC,eAAO,MAAM,UAAU,EAAE,KAAU,CAAA;AAEnC,eAAO,MAAM,KAAK,EAAE,KAUnB,CAAA;AAED,eAAO,MAAM,MAAM,EAAE,KAgBpB,CAAA;AAED,eAAO,MAAM,cAAc,EAAE,KAE5B,CAAA;AAED,eAAO,MAAM,kBAAkB,EAAE,KAYhC,CAAA;AAED,eAAO,MAAM,OAAO,EAAE,KAMrB,CAAA;AAED,eAAO,MAAM,KAAK,EAAE,KAOnB,CAAA;AAED,eAAO,MAAM,cAAc,EAAE,KAgB5B,CAAA;AAED,eAAO,MAAM,YAAY,EAAE,KAO1B,CAAA;AAED,eAAO,MAAM,QAAQ,EAAE,KAMtB,CAAA"}
|
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect, useId, useRef, useState } from "react";
|
|
3
|
+
import { Button } from "../atoms/button.js";
|
|
4
|
+
import { Accordion } from "../molecules/accordion.js";
|
|
5
|
+
import { Dialog } from "../molecules/dialog.js";
|
|
6
|
+
import { FormCheckbox } from "../molecules/form-checkbox.js";
|
|
7
|
+
import { Slider } from "../molecules/slider.js";
|
|
8
|
+
import { tv } from "../utils.js";
|
|
9
|
+
const facetFilterPanelStyles = tv({
|
|
10
|
+
slots: {
|
|
11
|
+
root: [
|
|
12
|
+
"flex w-full min-w-0 flex-col overflow-y-auto",
|
|
13
|
+
"max-h-(--container-facet-filter-panel-max-h) rounded-facet-filter-panel",
|
|
14
|
+
"border-(length:--border-width-facet-filter-panel) border-facet-filter-panel-border",
|
|
15
|
+
"bg-facet-filter-panel-bg text-facet-filter-panel-fg",
|
|
16
|
+
"p-facet-filter-panel"
|
|
17
|
+
],
|
|
18
|
+
content: "flex min-h-0 flex-col gap-facet-filter-panel",
|
|
19
|
+
title: "font-facet-filter-panel-title text-facet-filter-panel-title text-facet-filter-panel-title-fg",
|
|
20
|
+
pending: "text-(length:--text-facet-filter-panel-status) text-facet-filter-panel-muted-fg",
|
|
21
|
+
groups: "min-h-0 gap-facet-filter-panel-group bg-facet-filter-panel-bg",
|
|
22
|
+
rangeGroup: "border-b-(length:--border-width-facet-filter-panel) border-facet-filter-panel-border p-facet-filter-panel-group",
|
|
23
|
+
optionList: "flex flex-col gap-facet-filter-panel-item",
|
|
24
|
+
optionLabel: "flex min-w-0 flex-1 items-center justify-between gap-facet-filter-panel-item",
|
|
25
|
+
optionText: "min-w-0 break-words",
|
|
26
|
+
optionCount: "shrink-0 text-facet-filter-panel-count text-facet-filter-panel-muted-fg",
|
|
27
|
+
empty: "text-(length:--text-facet-filter-panel-status) text-facet-filter-panel-muted-fg",
|
|
28
|
+
overflowAction: "mt-facet-filter-panel-overflow self-start",
|
|
29
|
+
drawerTrigger: "self-start",
|
|
30
|
+
drawerContent: "min-w-0",
|
|
31
|
+
triggerCount: "inline-flex min-w-facet-filter-panel-count items-center justify-center rounded-facet-filter-panel-count bg-facet-filter-panel-count-bg px-facet-filter-panel-count text-facet-filter-panel-count text-facet-filter-panel-count-fg",
|
|
32
|
+
activeRoot: "border-b-(length:--border-width-facet-filter-panel) flex flex-col gap-facet-filter-panel-active border-facet-filter-panel-border pb-facet-filter-panel-active",
|
|
33
|
+
activeHeader: "flex flex-wrap items-center justify-between gap-facet-filter-panel-active",
|
|
34
|
+
activeTitle: "font-facet-filter-panel-active-title text-facet-filter-panel-active-title",
|
|
35
|
+
activeList: "flex flex-wrap gap-facet-filter-panel-active"
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
const toRangeTuple = (values, group)=>[
|
|
39
|
+
values[0] ?? group.min,
|
|
40
|
+
values[1] ?? group.max
|
|
41
|
+
];
|
|
42
|
+
function FacetFilterOptions({ group, selectedValues, disabled, showMoreLabel, showLessLabel, onOptionChange }) {
|
|
43
|
+
const [expanded, setExpanded] = useState(false);
|
|
44
|
+
const styles = facetFilterPanelStyles();
|
|
45
|
+
const collapseAfter = Math.max(0, group.collapseAfter ?? group.options.length);
|
|
46
|
+
const hasOverflow = group.options.length > collapseAfter;
|
|
47
|
+
const visibleOptions = expanded || !hasOverflow ? group.options : group.options.slice(0, collapseAfter);
|
|
48
|
+
if (0 === group.options.length) return group.emptyLabel ? /*#__PURE__*/ jsx("div", {
|
|
49
|
+
className: styles.empty(),
|
|
50
|
+
children: group.emptyLabel
|
|
51
|
+
}) : null;
|
|
52
|
+
return /*#__PURE__*/ jsxs("div", {
|
|
53
|
+
className: "flex flex-col",
|
|
54
|
+
children: [
|
|
55
|
+
/*#__PURE__*/ jsx("ul", {
|
|
56
|
+
className: styles.optionList(),
|
|
57
|
+
children: visibleOptions.map((option)=>/*#__PURE__*/ jsx("li", {
|
|
58
|
+
children: /*#__PURE__*/ jsx(FormCheckbox, {
|
|
59
|
+
checked: selectedValues.includes(option.value),
|
|
60
|
+
disabled: disabled || option.disabled,
|
|
61
|
+
label: /*#__PURE__*/ jsxs("span", {
|
|
62
|
+
className: styles.optionLabel(),
|
|
63
|
+
children: [
|
|
64
|
+
/*#__PURE__*/ jsx("span", {
|
|
65
|
+
className: styles.optionText(),
|
|
66
|
+
children: option.label
|
|
67
|
+
}),
|
|
68
|
+
void 0 !== option.count ? /*#__PURE__*/ jsx("span", {
|
|
69
|
+
className: styles.optionCount(),
|
|
70
|
+
children: option.count
|
|
71
|
+
}) : null
|
|
72
|
+
]
|
|
73
|
+
}),
|
|
74
|
+
name: group.id,
|
|
75
|
+
onCheckedChange: (checked)=>onOptionChange?.({
|
|
76
|
+
groupId: group.id,
|
|
77
|
+
value: option.value,
|
|
78
|
+
checked
|
|
79
|
+
}),
|
|
80
|
+
value: option.value
|
|
81
|
+
})
|
|
82
|
+
}, option.value))
|
|
83
|
+
}),
|
|
84
|
+
hasOverflow ? /*#__PURE__*/ jsx(Button, {
|
|
85
|
+
"aria-expanded": expanded,
|
|
86
|
+
className: styles.overflowAction(),
|
|
87
|
+
disabled: disabled,
|
|
88
|
+
onClick: ()=>setExpanded((current)=>!current),
|
|
89
|
+
size: "sm",
|
|
90
|
+
theme: "borderless",
|
|
91
|
+
type: "button",
|
|
92
|
+
variant: "primary",
|
|
93
|
+
children: expanded ? showLessLabel : showMoreLabel(group.options.length - collapseAfter)
|
|
94
|
+
}) : null
|
|
95
|
+
]
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
function FacetFilterPanelContent({ title, groups, selectedValues = {}, activeFilters = [], disabled = false, pending = false, pendingLabel, activeFiltersLabel = "Active filters", resetLabel = "Clear filters", showMoreLabel = (hiddenCount)=>`Show ${hiddenCount} more`, showLessLabel = "Show less", expandedGroups, defaultExpandedGroups, onExpandedGroupsChange, onOptionChange, onRangeChange, onRangeChangeEnd, onRemoveFilter, onReset, showTitle, titleId }) {
|
|
99
|
+
const styles = facetFilterPanelStyles();
|
|
100
|
+
const interactionDisabled = disabled || pending;
|
|
101
|
+
const optionGroupIds = groups.filter((group)=>"options" === group.type).map((group)=>group.id);
|
|
102
|
+
const [localExpandedGroups, setLocalExpandedGroups] = useState(()=>defaultExpandedGroups ?? optionGroupIds);
|
|
103
|
+
const previousGroupIds = useRef(new Set(optionGroupIds));
|
|
104
|
+
useEffect(()=>{
|
|
105
|
+
const addedGroupIds = optionGroupIds.filter((id)=>!previousGroupIds.current.has(id));
|
|
106
|
+
previousGroupIds.current = new Set(optionGroupIds);
|
|
107
|
+
if (void 0 === expandedGroups && void 0 === defaultExpandedGroups && addedGroupIds.length > 0) setLocalExpandedGroups((current)=>[
|
|
108
|
+
...new Set([
|
|
109
|
+
...current,
|
|
110
|
+
...addedGroupIds
|
|
111
|
+
])
|
|
112
|
+
]);
|
|
113
|
+
}, [
|
|
114
|
+
optionGroupIds,
|
|
115
|
+
expandedGroups,
|
|
116
|
+
defaultExpandedGroups
|
|
117
|
+
]);
|
|
118
|
+
return /*#__PURE__*/ jsxs("div", {
|
|
119
|
+
"aria-busy": pending || void 0,
|
|
120
|
+
className: styles.content(),
|
|
121
|
+
children: [
|
|
122
|
+
showTitle ? /*#__PURE__*/ jsx("h2", {
|
|
123
|
+
className: styles.title(),
|
|
124
|
+
id: titleId,
|
|
125
|
+
children: title
|
|
126
|
+
}) : null,
|
|
127
|
+
pending && pendingLabel ? /*#__PURE__*/ jsx("output", {
|
|
128
|
+
"aria-live": "polite",
|
|
129
|
+
className: styles.pending(),
|
|
130
|
+
children: pendingLabel
|
|
131
|
+
}) : null,
|
|
132
|
+
/*#__PURE__*/ jsx(FacetFilterPanel.ActiveFilters, {
|
|
133
|
+
disabled: interactionDisabled,
|
|
134
|
+
items: activeFilters,
|
|
135
|
+
label: activeFiltersLabel,
|
|
136
|
+
onRemove: onRemoveFilter,
|
|
137
|
+
onReset: onReset,
|
|
138
|
+
resetLabel: resetLabel
|
|
139
|
+
}),
|
|
140
|
+
/*#__PURE__*/ jsx(Accordion, {
|
|
141
|
+
className: styles.groups(),
|
|
142
|
+
disabled: disabled,
|
|
143
|
+
multiple: true,
|
|
144
|
+
onChange: (groupIds)=>{
|
|
145
|
+
if (void 0 === expandedGroups) setLocalExpandedGroups(groupIds);
|
|
146
|
+
onExpandedGroupsChange?.(groupIds);
|
|
147
|
+
},
|
|
148
|
+
value: expandedGroups ?? localExpandedGroups,
|
|
149
|
+
variant: "child",
|
|
150
|
+
children: groups.map((group)=>{
|
|
151
|
+
if ("range" === group.type) return /*#__PURE__*/ jsx("section", {
|
|
152
|
+
className: styles.rangeGroup(),
|
|
153
|
+
children: /*#__PURE__*/ jsx(Slider, {
|
|
154
|
+
disabled: interactionDisabled || group.disabled,
|
|
155
|
+
formatRangeText: group.formatRangeText,
|
|
156
|
+
formatValue: group.formatValue,
|
|
157
|
+
label: group.label,
|
|
158
|
+
max: group.max,
|
|
159
|
+
min: group.min,
|
|
160
|
+
minStepsBetweenThumbs: group.minStepsBetweenThumbs,
|
|
161
|
+
onChange: (value)=>onRangeChange?.({
|
|
162
|
+
groupId: group.id,
|
|
163
|
+
value: toRangeTuple(value, group)
|
|
164
|
+
}),
|
|
165
|
+
onChangeEnd: (value)=>onRangeChangeEnd?.({
|
|
166
|
+
groupId: group.id,
|
|
167
|
+
value: toRangeTuple(value, group)
|
|
168
|
+
}),
|
|
169
|
+
showValueText: true,
|
|
170
|
+
step: group.step,
|
|
171
|
+
value: [
|
|
172
|
+
...group.value
|
|
173
|
+
]
|
|
174
|
+
})
|
|
175
|
+
}, group.id);
|
|
176
|
+
return /*#__PURE__*/ jsxs(Accordion.Item, {
|
|
177
|
+
disabled: group.disabled,
|
|
178
|
+
value: group.id,
|
|
179
|
+
children: [
|
|
180
|
+
/*#__PURE__*/ jsxs(Accordion.Header, {
|
|
181
|
+
children: [
|
|
182
|
+
/*#__PURE__*/ jsx(Accordion.Title, {
|
|
183
|
+
children: group.label
|
|
184
|
+
}),
|
|
185
|
+
/*#__PURE__*/ jsx(Accordion.Indicator, {})
|
|
186
|
+
]
|
|
187
|
+
}),
|
|
188
|
+
/*#__PURE__*/ jsx(Accordion.Content, {
|
|
189
|
+
children: /*#__PURE__*/ jsx(FacetFilterOptions, {
|
|
190
|
+
disabled: interactionDisabled || Boolean(group.disabled),
|
|
191
|
+
group: group,
|
|
192
|
+
onOptionChange: onOptionChange,
|
|
193
|
+
selectedValues: selectedValues[group.id] ?? [],
|
|
194
|
+
showLessLabel: showLessLabel,
|
|
195
|
+
showMoreLabel: showMoreLabel
|
|
196
|
+
})
|
|
197
|
+
})
|
|
198
|
+
]
|
|
199
|
+
}, group.id);
|
|
200
|
+
})
|
|
201
|
+
})
|
|
202
|
+
]
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
function FacetFilterPanel({ presentation = "inline", drawerTriggerLabel, drawerPlacement = "right", drawerSize = "sm", drawerOpen, defaultDrawerOpen = false, onDrawerOpenChange, className, ...props }) {
|
|
206
|
+
const styles = facetFilterPanelStyles();
|
|
207
|
+
const inlineTitleId = useId();
|
|
208
|
+
const drawerTriggerRef = useRef(null);
|
|
209
|
+
const [uncontrolledDrawerOpen, setUncontrolledDrawerOpen] = useState(defaultDrawerOpen);
|
|
210
|
+
const resolvedDrawerOpen = drawerOpen ?? uncontrolledDrawerOpen;
|
|
211
|
+
const activeCount = props.activeFilters?.length ?? 0;
|
|
212
|
+
const setDrawerOpen = (open)=>{
|
|
213
|
+
if (void 0 === drawerOpen) setUncontrolledDrawerOpen(open);
|
|
214
|
+
onDrawerOpenChange?.(open);
|
|
215
|
+
};
|
|
216
|
+
if ("drawer" === presentation) return /*#__PURE__*/ jsxs(Fragment, {
|
|
217
|
+
children: [
|
|
218
|
+
/*#__PURE__*/ jsxs(Button, {
|
|
219
|
+
"aria-expanded": resolvedDrawerOpen,
|
|
220
|
+
"aria-haspopup": "dialog",
|
|
221
|
+
className: styles.drawerTrigger(),
|
|
222
|
+
icon: "token-icon-facet-filter-panel-filter",
|
|
223
|
+
onClick: ()=>setDrawerOpen(true),
|
|
224
|
+
ref: drawerTriggerRef,
|
|
225
|
+
type: "button",
|
|
226
|
+
variant: "primary",
|
|
227
|
+
children: [
|
|
228
|
+
drawerTriggerLabel ?? props.title,
|
|
229
|
+
activeCount > 0 ? /*#__PURE__*/ jsx("span", {
|
|
230
|
+
"aria-hidden": "true",
|
|
231
|
+
className: styles.triggerCount(),
|
|
232
|
+
children: activeCount
|
|
233
|
+
}) : null
|
|
234
|
+
]
|
|
235
|
+
}),
|
|
236
|
+
/*#__PURE__*/ jsx(Dialog, {
|
|
237
|
+
className: styles.drawerContent({
|
|
238
|
+
className
|
|
239
|
+
}),
|
|
240
|
+
customTrigger: true,
|
|
241
|
+
finalFocusEl: ()=>drawerTriggerRef.current,
|
|
242
|
+
onOpenChange: ({ open })=>setDrawerOpen(open),
|
|
243
|
+
open: resolvedDrawerOpen,
|
|
244
|
+
placement: drawerPlacement,
|
|
245
|
+
size: drawerSize,
|
|
246
|
+
title: props.title,
|
|
247
|
+
children: /*#__PURE__*/ jsx(FacetFilterPanelContent, {
|
|
248
|
+
...props,
|
|
249
|
+
showTitle: false
|
|
250
|
+
})
|
|
251
|
+
})
|
|
252
|
+
]
|
|
253
|
+
});
|
|
254
|
+
return /*#__PURE__*/ jsx("aside", {
|
|
255
|
+
"aria-labelledby": inlineTitleId,
|
|
256
|
+
className: styles.root({
|
|
257
|
+
className
|
|
258
|
+
}),
|
|
259
|
+
children: /*#__PURE__*/ jsx(FacetFilterPanelContent, {
|
|
260
|
+
...props,
|
|
261
|
+
showTitle: true,
|
|
262
|
+
titleId: inlineTitleId
|
|
263
|
+
})
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
FacetFilterPanel.ActiveFilters = function({ items, label = "Active filters", resetLabel = "Clear filters", disabled = false, className, onRemove, onReset }) {
|
|
267
|
+
const styles = facetFilterPanelStyles();
|
|
268
|
+
if (0 === items.length) return null;
|
|
269
|
+
return /*#__PURE__*/ jsxs("section", {
|
|
270
|
+
className: styles.activeRoot({
|
|
271
|
+
className
|
|
272
|
+
}),
|
|
273
|
+
children: [
|
|
274
|
+
/*#__PURE__*/ jsxs("div", {
|
|
275
|
+
className: styles.activeHeader(),
|
|
276
|
+
children: [
|
|
277
|
+
/*#__PURE__*/ jsx("h3", {
|
|
278
|
+
className: styles.activeTitle(),
|
|
279
|
+
children: label
|
|
280
|
+
}),
|
|
281
|
+
/*#__PURE__*/ jsx(Button, {
|
|
282
|
+
disabled: disabled,
|
|
283
|
+
onClick: onReset,
|
|
284
|
+
size: "sm",
|
|
285
|
+
theme: "borderless",
|
|
286
|
+
type: "button",
|
|
287
|
+
variant: "primary",
|
|
288
|
+
children: resetLabel
|
|
289
|
+
})
|
|
290
|
+
]
|
|
291
|
+
}),
|
|
292
|
+
/*#__PURE__*/ jsx("div", {
|
|
293
|
+
className: styles.activeList(),
|
|
294
|
+
children: items.map((item)=>/*#__PURE__*/ jsx(Button, {
|
|
295
|
+
"aria-label": item.removeLabel,
|
|
296
|
+
disabled: disabled,
|
|
297
|
+
icon: "token-icon-close",
|
|
298
|
+
iconPosition: "right",
|
|
299
|
+
onClick: ()=>onRemove?.(item.id),
|
|
300
|
+
size: "sm",
|
|
301
|
+
theme: "outlined",
|
|
302
|
+
type: "button",
|
|
303
|
+
variant: "primary",
|
|
304
|
+
children: item.label
|
|
305
|
+
}, item.id))
|
|
306
|
+
})
|
|
307
|
+
]
|
|
308
|
+
});
|
|
309
|
+
};
|
|
310
|
+
export { FacetFilterPanel };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { jsx } from "react/jsx-runtime";
|
|
2
|
+
import { Combobox } from "../molecules/combobox.js";
|
|
3
|
+
function SearchSuggestions({ resultSlot, allResultsLink, filterBehavior = "external", inputBehavior = "none", portalled = false, ...props }) {
|
|
4
|
+
return /*#__PURE__*/ jsx(Combobox, {
|
|
5
|
+
...props,
|
|
6
|
+
filterBehavior: filterBehavior,
|
|
7
|
+
footer: allResultsLink,
|
|
8
|
+
inputBehavior: inputBehavior,
|
|
9
|
+
mode: "navigation",
|
|
10
|
+
portalled: portalled,
|
|
11
|
+
renderItem: resultSlot
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
export { SearchSuggestions };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"combobox.behavior.spec.d.ts","sourceRoot":"","sources":["../../test/combobox.behavior.spec.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"facet-filter-panel.spec.d.ts","sourceRoot":"","sources":["../../test/facet-filter-panel.spec.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search-suggestions.spec.d.ts","sourceRoot":"","sources":["../../test/search-suggestions.spec.ts"],"names":[],"mappings":""}
|
package/package.json
CHANGED
|
@@ -5,14 +5,36 @@
|
|
|
5
5
|
* - `--padding-combobox-input-{size}` semantic aliases (Figma exports
|
|
6
6
|
* the shared per-size spacing axis).
|
|
7
7
|
* - `--padding-combobox-trigger` composite.
|
|
8
|
+
* - Group, footer, and async status aliases over shared popup tokens.
|
|
8
9
|
*/
|
|
9
10
|
|
|
10
11
|
@theme static {
|
|
12
|
+
--color-combobox-status: var(--color-popup-item-fg);
|
|
13
|
+
--color-combobox-group: var(--color-popup-item-fg);
|
|
14
|
+
--color-combobox-divider: var(--color-popup-border);
|
|
15
|
+
|
|
16
|
+
--color-combobox-status-fg: var(--color-combobox-status);
|
|
17
|
+
--color-combobox-group-fg: var(--color-combobox-group);
|
|
18
|
+
--color-combobox-footer-border: var(--color-combobox-divider);
|
|
19
|
+
|
|
11
20
|
--padding-combobox-input-sm: var(--spacing-combobox-sm);
|
|
12
21
|
--padding-combobox-input-md: var(--spacing-combobox-md);
|
|
13
22
|
--padding-combobox-input-lg: var(--spacing-combobox-lg);
|
|
14
23
|
|
|
15
24
|
--padding-combobox-trigger: 0 var(--spacing-100);
|
|
25
|
+
|
|
26
|
+
--text-combobox-group-label-size: var(--text-sm);
|
|
27
|
+
--font-weight-combobox-group-label: var(--font-weight-semibold);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/* Resolve the popup's size scale on each group label, footer, or status. */
|
|
31
|
+
@utility combobox-popup-padding {
|
|
32
|
+
padding: var(--popup-item-y, var(--padding-popup-item-y-md))
|
|
33
|
+
var(--popup-item-x, var(--padding-popup-item-x-md));
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
@utility combobox-status-gap {
|
|
37
|
+
gap: var(--popup-item-gap, var(--spacing-popup-item-md));
|
|
16
38
|
}
|
|
17
39
|
|
|
18
40
|
/* Semantic tokens for combobox icons */
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
@theme static {
|
|
2
|
+
/* Reference layer */
|
|
3
|
+
--color-facet-filter-panel-surface: var(--color-fill-surface);
|
|
4
|
+
--color-facet-filter-panel-text: var(--color-fg-primary);
|
|
5
|
+
--color-facet-filter-panel-muted: var(--color-fg-secondary);
|
|
6
|
+
--color-facet-filter-panel-divider: var(--color-border-primary);
|
|
7
|
+
--color-facet-filter-panel-accent: var(--color-bg-primary-base);
|
|
8
|
+
--color-facet-filter-panel-on-accent: var(--color-fg-on-primary-solid-neo);
|
|
9
|
+
|
|
10
|
+
/* Derived layer */
|
|
11
|
+
--color-facet-filter-panel-bg: var(--color-facet-filter-panel-surface);
|
|
12
|
+
--color-facet-filter-panel-fg: var(--color-facet-filter-panel-text);
|
|
13
|
+
--color-facet-filter-panel-title-fg: var(--color-facet-filter-panel-text);
|
|
14
|
+
--color-facet-filter-panel-muted-fg: var(--color-facet-filter-panel-muted);
|
|
15
|
+
--color-facet-filter-panel-border: var(--color-facet-filter-panel-divider);
|
|
16
|
+
--color-facet-filter-panel-count-bg: var(--color-facet-filter-panel-accent);
|
|
17
|
+
--color-facet-filter-panel-count-fg: var(--color-facet-filter-panel-on-accent);
|
|
18
|
+
|
|
19
|
+
--border-width-facet-filter-panel: var(--border-sm);
|
|
20
|
+
--radius-facet-filter-panel: var(--radius-md);
|
|
21
|
+
--radius-facet-filter-panel-count: var(--radius-sm);
|
|
22
|
+
--container-facet-filter-panel-max-h: calc(100dvh - var(--spacing-400));
|
|
23
|
+
--spacing-facet-filter-panel: var(--spacing-200);
|
|
24
|
+
--spacing-facet-filter-panel-group: var(--spacing-100);
|
|
25
|
+
--spacing-facet-filter-panel-item: var(--spacing-100);
|
|
26
|
+
--spacing-facet-filter-panel-active: var(--spacing-100);
|
|
27
|
+
--spacing-facet-filter-panel-overflow: var(--spacing-100);
|
|
28
|
+
--spacing-facet-filter-panel-count: var(--spacing-400);
|
|
29
|
+
--padding-facet-filter-panel: var(--spacing-200);
|
|
30
|
+
--padding-facet-filter-panel-group: var(--spacing-200);
|
|
31
|
+
--padding-facet-filter-panel-active: var(--spacing-150);
|
|
32
|
+
--padding-facet-filter-panel-count: var(--spacing-100);
|
|
33
|
+
--text-facet-filter-panel-title: var(--text-md);
|
|
34
|
+
--text-facet-filter-panel-active-title: var(--text-sm);
|
|
35
|
+
--text-facet-filter-panel-status: var(--text-sm);
|
|
36
|
+
--text-facet-filter-panel-count: var(--text-xs);
|
|
37
|
+
--font-weight-facet-filter-panel-title: var(--font-weight-semibold);
|
|
38
|
+
--font-weight-facet-filter-panel-active-title: var(--font-weight-medium);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
@utility token-icon-facet-filter-panel-filter {
|
|
42
|
+
@apply icon-[mdi--filter-variant];
|
|
43
|
+
}
|