@sesionario/blocks 1.8.0 → 1.9.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/index.cjs +621 -29
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +90 -1
- package/dist/index.d.ts +90 -1
- package/dist/index.js +621 -31
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1411,7 +1411,7 @@ function LanguageSwitcher({
|
|
|
1411
1411
|
const sizes = sizeClasses2[size];
|
|
1412
1412
|
const shapeClass = shapeClasses2[shape];
|
|
1413
1413
|
const reduceMotion = framerMotion.useReducedMotion();
|
|
1414
|
-
const
|
|
1414
|
+
const defaultLabels5 = {
|
|
1415
1415
|
language: labels.language ?? "Language"
|
|
1416
1416
|
};
|
|
1417
1417
|
if (variant === "mini") {
|
|
@@ -1421,7 +1421,7 @@ function LanguageSwitcher({
|
|
|
1421
1421
|
{
|
|
1422
1422
|
variant: "ghost",
|
|
1423
1423
|
size: "icon",
|
|
1424
|
-
"aria-label":
|
|
1424
|
+
"aria-label": defaultLabels5.language,
|
|
1425
1425
|
className: cn(sizes.buttonMini, shapeClass, className),
|
|
1426
1426
|
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Languages, { className: sizes.iconMini })
|
|
1427
1427
|
}
|
|
@@ -4348,6 +4348,18 @@ function useDebouncedValueStrict(value, delayMs) {
|
|
|
4348
4348
|
}, [value, delayMs]);
|
|
4349
4349
|
return debounced;
|
|
4350
4350
|
}
|
|
4351
|
+
function useMediaQuery2(query) {
|
|
4352
|
+
const [matches, setMatches] = React6.useState(false);
|
|
4353
|
+
React6.useEffect(() => {
|
|
4354
|
+
if (typeof window === "undefined" || !window.matchMedia) return;
|
|
4355
|
+
const mql = window.matchMedia(query);
|
|
4356
|
+
const onChange = () => setMatches(mql.matches);
|
|
4357
|
+
onChange();
|
|
4358
|
+
mql.addEventListener("change", onChange);
|
|
4359
|
+
return () => mql.removeEventListener("change", onChange);
|
|
4360
|
+
}, [query]);
|
|
4361
|
+
return matches;
|
|
4362
|
+
}
|
|
4351
4363
|
function useSearchHotkey(options = {}) {
|
|
4352
4364
|
const { defaultOpen = false, disabled = false } = options;
|
|
4353
4365
|
const [open, setOpen] = React6.useState(defaultOpen);
|
|
@@ -4365,6 +4377,22 @@ function useSearchHotkey(options = {}) {
|
|
|
4365
4377
|
}, [disabled]);
|
|
4366
4378
|
return { open, setOpen, toggle };
|
|
4367
4379
|
}
|
|
4380
|
+
|
|
4381
|
+
// src/components/search/fuzzy.ts
|
|
4382
|
+
function normalize(value) {
|
|
4383
|
+
return value.toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "");
|
|
4384
|
+
}
|
|
4385
|
+
function fuzzyMatch(query, target) {
|
|
4386
|
+
const q = normalize(query.trim());
|
|
4387
|
+
if (!q) return true;
|
|
4388
|
+
const t = normalize(target);
|
|
4389
|
+
if (t.includes(q)) return true;
|
|
4390
|
+
let qi = 0;
|
|
4391
|
+
for (let ti = 0; ti < t.length && qi < q.length; ti++) {
|
|
4392
|
+
if (t[ti] === q[qi]) qi++;
|
|
4393
|
+
}
|
|
4394
|
+
return qi === q.length;
|
|
4395
|
+
}
|
|
4368
4396
|
function Command({
|
|
4369
4397
|
className,
|
|
4370
4398
|
...props
|
|
@@ -4482,6 +4510,19 @@ function CommandGroup({
|
|
|
4482
4510
|
}
|
|
4483
4511
|
);
|
|
4484
4512
|
}
|
|
4513
|
+
function CommandSeparator({
|
|
4514
|
+
className,
|
|
4515
|
+
...props
|
|
4516
|
+
}) {
|
|
4517
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
4518
|
+
cmdk.Command.Separator,
|
|
4519
|
+
{
|
|
4520
|
+
"data-slot": "command-separator",
|
|
4521
|
+
className: cn("-mx-1 h-px bg-border", className),
|
|
4522
|
+
...props
|
|
4523
|
+
}
|
|
4524
|
+
);
|
|
4525
|
+
}
|
|
4485
4526
|
function CommandItem({
|
|
4486
4527
|
className,
|
|
4487
4528
|
...props
|
|
@@ -4498,23 +4539,584 @@ function CommandItem({
|
|
|
4498
4539
|
}
|
|
4499
4540
|
);
|
|
4500
4541
|
}
|
|
4501
|
-
|
|
4502
|
-
|
|
4503
|
-
|
|
4504
|
-
|
|
4542
|
+
function OptionRow({
|
|
4543
|
+
entry,
|
|
4544
|
+
selected,
|
|
4545
|
+
onSelect,
|
|
4546
|
+
renderOption
|
|
4547
|
+
}) {
|
|
4548
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
4549
|
+
CommandItem,
|
|
4550
|
+
{
|
|
4551
|
+
value: entry.value,
|
|
4552
|
+
keywords: [entry.label],
|
|
4553
|
+
onSelect,
|
|
4554
|
+
"data-checked": selected || void 0,
|
|
4555
|
+
children: [
|
|
4556
|
+
renderOption ? renderOption(entry.item, { selected }) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 flex-1 truncate", children: entry.label }),
|
|
4557
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4558
|
+
lucideReact.CheckIcon,
|
|
4559
|
+
{
|
|
4560
|
+
className: cn(
|
|
4561
|
+
"ml-auto size-4 shrink-0",
|
|
4562
|
+
selected ? "opacity-100" : "opacity-0"
|
|
4563
|
+
)
|
|
4564
|
+
}
|
|
4565
|
+
)
|
|
4566
|
+
]
|
|
4567
|
+
},
|
|
4568
|
+
entry.value
|
|
4569
|
+
);
|
|
4505
4570
|
}
|
|
4506
|
-
function
|
|
4507
|
-
|
|
4508
|
-
|
|
4509
|
-
|
|
4510
|
-
|
|
4511
|
-
|
|
4512
|
-
|
|
4513
|
-
|
|
4514
|
-
|
|
4515
|
-
|
|
4571
|
+
function SearchablePickerList({
|
|
4572
|
+
query,
|
|
4573
|
+
onQueryChange,
|
|
4574
|
+
labels,
|
|
4575
|
+
isLoading,
|
|
4576
|
+
hasError,
|
|
4577
|
+
recommended,
|
|
4578
|
+
recent,
|
|
4579
|
+
results,
|
|
4580
|
+
selectedValues,
|
|
4581
|
+
mode,
|
|
4582
|
+
allowEmpty,
|
|
4583
|
+
emptyLabel,
|
|
4584
|
+
onSelectEmpty,
|
|
4585
|
+
onSelectItem,
|
|
4586
|
+
renderOption,
|
|
4587
|
+
createOption,
|
|
4588
|
+
onLoadMore,
|
|
4589
|
+
hasMore,
|
|
4590
|
+
isLoadingMore,
|
|
4591
|
+
listClassName
|
|
4592
|
+
}) {
|
|
4593
|
+
const hasPinned = recommended.length > 0 || recent.length > 0;
|
|
4594
|
+
const hasResults = results.length > 0;
|
|
4595
|
+
const showEmpty = !isLoading && !hasError && !hasPinned && !hasResults && !(allowEmpty && mode === "single");
|
|
4596
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(Command, { shouldFilter: false, className: "flex h-full min-h-0 flex-col", children: [
|
|
4597
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4598
|
+
CommandInput,
|
|
4599
|
+
{
|
|
4600
|
+
placeholder: labels.searchPlaceholder,
|
|
4601
|
+
value: query,
|
|
4602
|
+
onValueChange: onQueryChange
|
|
4603
|
+
}
|
|
4604
|
+
),
|
|
4605
|
+
/* @__PURE__ */ jsxRuntime.jsxs(CommandList, { className: cn("min-h-0 flex-1", listClassName), children: [
|
|
4606
|
+
isLoading ? /* @__PURE__ */ jsxRuntime.jsxs(
|
|
4607
|
+
"div",
|
|
4608
|
+
{
|
|
4609
|
+
className: "flex items-center justify-center gap-2 py-6 text-sm text-muted-foreground",
|
|
4610
|
+
role: "status",
|
|
4611
|
+
children: [
|
|
4612
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "size-4 animate-spin", "aria-hidden": true }),
|
|
4613
|
+
labels.loading
|
|
4614
|
+
]
|
|
4615
|
+
}
|
|
4616
|
+
) : null,
|
|
4617
|
+
hasError && !isLoading ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
4618
|
+
"div",
|
|
4619
|
+
{
|
|
4620
|
+
className: "py-6 text-center text-sm text-destructive",
|
|
4621
|
+
role: "alert",
|
|
4622
|
+
children: labels.error
|
|
4623
|
+
}
|
|
4624
|
+
) : null,
|
|
4625
|
+
showEmpty ? /* @__PURE__ */ jsxRuntime.jsx(CommandEmpty, { children: labels.empty }) : null,
|
|
4626
|
+
allowEmpty && mode === "single" && !query.trim() ? /* @__PURE__ */ jsxRuntime.jsx(CommandGroup, { children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
4627
|
+
CommandItem,
|
|
4628
|
+
{
|
|
4629
|
+
value: "__empty__",
|
|
4630
|
+
onSelect: () => onSelectEmpty?.(),
|
|
4631
|
+
"data-checked": !selectedValues.size || void 0,
|
|
4632
|
+
children: [
|
|
4633
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 flex-1 truncate text-muted-foreground", children: emptyLabel }),
|
|
4634
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4635
|
+
lucideReact.CheckIcon,
|
|
4636
|
+
{
|
|
4637
|
+
className: cn(
|
|
4638
|
+
"ml-auto size-4 shrink-0",
|
|
4639
|
+
selectedValues.size === 0 ? "opacity-100" : "opacity-0"
|
|
4640
|
+
)
|
|
4641
|
+
}
|
|
4642
|
+
)
|
|
4643
|
+
]
|
|
4644
|
+
}
|
|
4645
|
+
) }) : null,
|
|
4646
|
+
recommended.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(CommandGroup, { heading: labels.recommended, children: recommended.map((entry) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
4647
|
+
OptionRow,
|
|
4648
|
+
{
|
|
4649
|
+
entry,
|
|
4650
|
+
selected: selectedValues.has(entry.value),
|
|
4651
|
+
onSelect: () => onSelectItem(entry.value),
|
|
4652
|
+
renderOption
|
|
4653
|
+
},
|
|
4654
|
+
`rec-${entry.value}`
|
|
4655
|
+
)) }) : null,
|
|
4656
|
+
recent.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(CommandGroup, { heading: labels.recent, children: recent.map((entry) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
4657
|
+
OptionRow,
|
|
4658
|
+
{
|
|
4659
|
+
entry,
|
|
4660
|
+
selected: selectedValues.has(entry.value),
|
|
4661
|
+
onSelect: () => onSelectItem(entry.value),
|
|
4662
|
+
renderOption
|
|
4663
|
+
},
|
|
4664
|
+
`recent-${entry.value}`
|
|
4665
|
+
)) }) : null,
|
|
4666
|
+
hasPinned && hasResults ? /* @__PURE__ */ jsxRuntime.jsx(CommandSeparator, {}) : null,
|
|
4667
|
+
hasResults ? /* @__PURE__ */ jsxRuntime.jsx(CommandGroup, { heading: hasPinned ? labels.results : void 0, children: results.map((entry) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
4668
|
+
OptionRow,
|
|
4669
|
+
{
|
|
4670
|
+
entry,
|
|
4671
|
+
selected: selectedValues.has(entry.value),
|
|
4672
|
+
onSelect: () => onSelectItem(entry.value),
|
|
4673
|
+
renderOption
|
|
4674
|
+
},
|
|
4675
|
+
`res-${entry.value}`
|
|
4676
|
+
)) }) : null,
|
|
4677
|
+
hasMore && onLoadMore ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-2", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
4678
|
+
Button,
|
|
4679
|
+
{
|
|
4680
|
+
type: "button",
|
|
4681
|
+
variant: "ghost",
|
|
4682
|
+
size: "sm",
|
|
4683
|
+
className: "w-full",
|
|
4684
|
+
disabled: isLoadingMore,
|
|
4685
|
+
onClick: () => void onLoadMore(),
|
|
4686
|
+
children: isLoadingMore ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
4687
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "size-4 animate-spin", "aria-hidden": true }),
|
|
4688
|
+
labels.loading
|
|
4689
|
+
] }) : labels.loadMore
|
|
4690
|
+
}
|
|
4691
|
+
) }) : null,
|
|
4692
|
+
createOption ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
4693
|
+
/* @__PURE__ */ jsxRuntime.jsx(CommandSeparator, {}),
|
|
4694
|
+
/* @__PURE__ */ jsxRuntime.jsx(CommandGroup, { children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
4695
|
+
CommandItem,
|
|
4696
|
+
{
|
|
4697
|
+
value: "__create__",
|
|
4698
|
+
onSelect: () => createOption.onSelect(),
|
|
4699
|
+
children: createOption.label
|
|
4700
|
+
}
|
|
4701
|
+
) })
|
|
4702
|
+
] }) : null
|
|
4703
|
+
] })
|
|
4704
|
+
] });
|
|
4516
4705
|
}
|
|
4517
4706
|
var defaultLabels3 = {
|
|
4707
|
+
placeholder: "Seleccionar\u2026",
|
|
4708
|
+
searchPlaceholder: "Buscar\u2026",
|
|
4709
|
+
empty: "No se encontraron resultados",
|
|
4710
|
+
loading: "Cargando\u2026",
|
|
4711
|
+
error: "No se pudo cargar la lista",
|
|
4712
|
+
recommended: "Recomendados",
|
|
4713
|
+
recent: "Recientes",
|
|
4714
|
+
results: "Resultados",
|
|
4715
|
+
done: "Listo",
|
|
4716
|
+
cancel: "Cancelar",
|
|
4717
|
+
clear: "Limpiar",
|
|
4718
|
+
selectedCount: (count) => count === 1 ? "1 seleccionado" : `${count} seleccionados`,
|
|
4719
|
+
emptyOption: "Ninguno",
|
|
4720
|
+
loadMore: "Cargar m\xE1s",
|
|
4721
|
+
dialogTitle: "Seleccionar"
|
|
4722
|
+
};
|
|
4723
|
+
function toListItems(items, getOptionValue, getOptionLabel) {
|
|
4724
|
+
if (!items?.length) return [];
|
|
4725
|
+
return items.map((item) => ({
|
|
4726
|
+
item,
|
|
4727
|
+
value: getOptionValue(item),
|
|
4728
|
+
label: getOptionLabel(item)
|
|
4729
|
+
}));
|
|
4730
|
+
}
|
|
4731
|
+
function dedupeByValue(items, exclude = /* @__PURE__ */ new Set()) {
|
|
4732
|
+
const seen = new Set(exclude);
|
|
4733
|
+
const out = [];
|
|
4734
|
+
for (const entry of items) {
|
|
4735
|
+
if (seen.has(entry.value)) continue;
|
|
4736
|
+
seen.add(entry.value);
|
|
4737
|
+
out.push(entry);
|
|
4738
|
+
}
|
|
4739
|
+
return out;
|
|
4740
|
+
}
|
|
4741
|
+
function matchesQuery(entry, query, getOptionKeywords) {
|
|
4742
|
+
if (!query.trim()) return true;
|
|
4743
|
+
if (fuzzyMatch(query, entry.label)) return true;
|
|
4744
|
+
return getOptionKeywords?.(entry.item)?.some(
|
|
4745
|
+
(keyword) => fuzzyMatch(query, keyword)
|
|
4746
|
+
) ?? false;
|
|
4747
|
+
}
|
|
4748
|
+
function SearchablePicker(props) {
|
|
4749
|
+
const {
|
|
4750
|
+
options,
|
|
4751
|
+
fetchOptions,
|
|
4752
|
+
getOptionValue,
|
|
4753
|
+
getOptionLabel,
|
|
4754
|
+
getOptionKeywords,
|
|
4755
|
+
renderOption,
|
|
4756
|
+
renderValue,
|
|
4757
|
+
pinned,
|
|
4758
|
+
labels: userLabels,
|
|
4759
|
+
minQueryLength = 0,
|
|
4760
|
+
debounceMs = 200,
|
|
4761
|
+
disabled,
|
|
4762
|
+
open: openProp,
|
|
4763
|
+
onOpenChange,
|
|
4764
|
+
clearable,
|
|
4765
|
+
allowEmpty,
|
|
4766
|
+
emptyLabel,
|
|
4767
|
+
keepOpenOnSelect,
|
|
4768
|
+
maxSelected,
|
|
4769
|
+
createOption,
|
|
4770
|
+
onLoadMore,
|
|
4771
|
+
hasMore,
|
|
4772
|
+
className,
|
|
4773
|
+
triggerClassName: triggerClassName2,
|
|
4774
|
+
id,
|
|
4775
|
+
"aria-labelledby": ariaLabelledBy,
|
|
4776
|
+
"aria-label": ariaLabel
|
|
4777
|
+
} = props;
|
|
4778
|
+
const mode = props.mode ?? "single";
|
|
4779
|
+
const labels = { ...defaultLabels3, ...userLabels };
|
|
4780
|
+
const resolvedEmptyLabel = emptyLabel ?? labels.emptyOption;
|
|
4781
|
+
const isMobile = useMediaQuery2("(max-width: 767px)");
|
|
4782
|
+
const generatedId = React6.useId();
|
|
4783
|
+
const triggerId = id ?? generatedId;
|
|
4784
|
+
const [uncontrolledOpen, setUncontrolledOpen] = React6.useState(false);
|
|
4785
|
+
const open = openProp ?? uncontrolledOpen;
|
|
4786
|
+
const setOpen = React6.useCallback(
|
|
4787
|
+
(next) => {
|
|
4788
|
+
onOpenChange?.(next);
|
|
4789
|
+
if (openProp === void 0) setUncontrolledOpen(next);
|
|
4790
|
+
},
|
|
4791
|
+
[onOpenChange, openProp]
|
|
4792
|
+
);
|
|
4793
|
+
const [query, setQuery] = React6.useState("");
|
|
4794
|
+
const [remoteItems, setRemoteItems] = React6.useState([]);
|
|
4795
|
+
const [isLoading, setIsLoading] = React6.useState(false);
|
|
4796
|
+
const [hasError, setHasError] = React6.useState(false);
|
|
4797
|
+
const [isLoadingMore, setIsLoadingMore] = React6.useState(false);
|
|
4798
|
+
const debouncedQuery = useDebouncedValue(query, debounceMs);
|
|
4799
|
+
const requestIdRef = React6.useRef(0);
|
|
4800
|
+
const knownItemsRef = React6.useRef(/* @__PURE__ */ new Map());
|
|
4801
|
+
const rememberItems = React6.useCallback(
|
|
4802
|
+
(items) => {
|
|
4803
|
+
for (const item of items) {
|
|
4804
|
+
knownItemsRef.current.set(getOptionValue(item), item);
|
|
4805
|
+
}
|
|
4806
|
+
},
|
|
4807
|
+
[getOptionValue]
|
|
4808
|
+
);
|
|
4809
|
+
React6.useEffect(() => {
|
|
4810
|
+
if (options) rememberItems(options);
|
|
4811
|
+
if (pinned?.recommended) rememberItems(pinned.recommended);
|
|
4812
|
+
if (pinned?.recent) rememberItems(pinned.recent);
|
|
4813
|
+
}, [options, pinned, rememberItems]);
|
|
4814
|
+
React6.useEffect(() => {
|
|
4815
|
+
if (!open) {
|
|
4816
|
+
setQuery("");
|
|
4817
|
+
setRemoteItems([]);
|
|
4818
|
+
setHasError(false);
|
|
4819
|
+
setIsLoading(false);
|
|
4820
|
+
}
|
|
4821
|
+
}, [open]);
|
|
4822
|
+
const trimmedDebounced = debouncedQuery.trim();
|
|
4823
|
+
const shouldFetch = Boolean(fetchOptions) && open && trimmedDebounced.length >= minQueryLength && (trimmedDebounced.length > 0 || !options);
|
|
4824
|
+
React6.useEffect(() => {
|
|
4825
|
+
if (!shouldFetch || !fetchOptions) {
|
|
4826
|
+
if (!trimmedDebounced) {
|
|
4827
|
+
setRemoteItems([]);
|
|
4828
|
+
setHasError(false);
|
|
4829
|
+
setIsLoading(false);
|
|
4830
|
+
}
|
|
4831
|
+
return;
|
|
4832
|
+
}
|
|
4833
|
+
const requestId = ++requestIdRef.current;
|
|
4834
|
+
setIsLoading(true);
|
|
4835
|
+
setHasError(false);
|
|
4836
|
+
fetchOptions(trimmedDebounced).then((result) => {
|
|
4837
|
+
if (requestIdRef.current !== requestId) return;
|
|
4838
|
+
setRemoteItems(result);
|
|
4839
|
+
rememberItems(result);
|
|
4840
|
+
}).catch(() => {
|
|
4841
|
+
if (requestIdRef.current !== requestId) return;
|
|
4842
|
+
setRemoteItems([]);
|
|
4843
|
+
setHasError(true);
|
|
4844
|
+
}).finally(() => {
|
|
4845
|
+
if (requestIdRef.current !== requestId) return;
|
|
4846
|
+
setIsLoading(false);
|
|
4847
|
+
});
|
|
4848
|
+
}, [shouldFetch, fetchOptions, trimmedDebounced, rememberItems]);
|
|
4849
|
+
const selectedValues = React6.useMemo(() => {
|
|
4850
|
+
if (mode === "multiple") {
|
|
4851
|
+
const multiValue = props.value ?? [];
|
|
4852
|
+
return new Set(multiValue);
|
|
4853
|
+
}
|
|
4854
|
+
const singleValue = props.value;
|
|
4855
|
+
return singleValue ? /* @__PURE__ */ new Set([singleValue]) : /* @__PURE__ */ new Set();
|
|
4856
|
+
}, [mode, props]);
|
|
4857
|
+
const selectedValueKey = mode === "multiple" ? (props.value ?? []).join("\0") : props.value ?? "";
|
|
4858
|
+
const selectedItems = React6.useMemo(() => {
|
|
4859
|
+
const values = mode === "multiple" ? selectedValueKey ? selectedValueKey.split("\0") : [] : selectedValueKey ? [selectedValueKey] : [];
|
|
4860
|
+
return values.map((value) => knownItemsRef.current.get(value)).filter((item) => item !== void 0);
|
|
4861
|
+
}, [mode, selectedValueKey, options, pinned, remoteItems]);
|
|
4862
|
+
const queryForFilter = query.trim();
|
|
4863
|
+
const recommended = React6.useMemo(() => {
|
|
4864
|
+
if (queryForFilter) return [];
|
|
4865
|
+
const pinnedValues = /* @__PURE__ */ new Set();
|
|
4866
|
+
const items = dedupeByValue(
|
|
4867
|
+
toListItems(pinned?.recommended, getOptionValue, getOptionLabel)
|
|
4868
|
+
);
|
|
4869
|
+
for (const entry of items) pinnedValues.add(entry.value);
|
|
4870
|
+
return items;
|
|
4871
|
+
}, [queryForFilter, pinned?.recommended, getOptionValue, getOptionLabel]);
|
|
4872
|
+
const recent = React6.useMemo(() => {
|
|
4873
|
+
if (queryForFilter) return [];
|
|
4874
|
+
const exclude = new Set(recommended.map((e) => e.value));
|
|
4875
|
+
return dedupeByValue(
|
|
4876
|
+
toListItems(pinned?.recent, getOptionValue, getOptionLabel),
|
|
4877
|
+
exclude
|
|
4878
|
+
);
|
|
4879
|
+
}, [
|
|
4880
|
+
queryForFilter,
|
|
4881
|
+
pinned?.recent,
|
|
4882
|
+
recommended,
|
|
4883
|
+
getOptionValue,
|
|
4884
|
+
getOptionLabel
|
|
4885
|
+
]);
|
|
4886
|
+
const pinnedValueSet = React6.useMemo(() => {
|
|
4887
|
+
const set = /* @__PURE__ */ new Set();
|
|
4888
|
+
for (const entry of recommended) set.add(entry.value);
|
|
4889
|
+
for (const entry of recent) set.add(entry.value);
|
|
4890
|
+
return set;
|
|
4891
|
+
}, [recommended, recent]);
|
|
4892
|
+
const results = React6.useMemo(() => {
|
|
4893
|
+
const usingRemote = Boolean(fetchOptions) && trimmedDebounced.length >= minQueryLength && (trimmedDebounced.length > 0 || !options);
|
|
4894
|
+
if (usingRemote) {
|
|
4895
|
+
return dedupeByValue(
|
|
4896
|
+
toListItems(remoteItems, getOptionValue, getOptionLabel),
|
|
4897
|
+
queryForFilter ? /* @__PURE__ */ new Set() : pinnedValueSet
|
|
4898
|
+
);
|
|
4899
|
+
}
|
|
4900
|
+
const staticItems = toListItems(options, getOptionValue, getOptionLabel);
|
|
4901
|
+
const filtered = staticItems.filter(
|
|
4902
|
+
(entry) => matchesQuery(entry, queryForFilter, getOptionKeywords)
|
|
4903
|
+
);
|
|
4904
|
+
return dedupeByValue(filtered, queryForFilter ? /* @__PURE__ */ new Set() : pinnedValueSet);
|
|
4905
|
+
}, [
|
|
4906
|
+
fetchOptions,
|
|
4907
|
+
trimmedDebounced,
|
|
4908
|
+
minQueryLength,
|
|
4909
|
+
options,
|
|
4910
|
+
remoteItems,
|
|
4911
|
+
getOptionValue,
|
|
4912
|
+
getOptionLabel,
|
|
4913
|
+
getOptionKeywords,
|
|
4914
|
+
queryForFilter,
|
|
4915
|
+
pinnedValueSet
|
|
4916
|
+
]);
|
|
4917
|
+
const closeOnSelect = keepOpenOnSelect !== void 0 ? !keepOpenOnSelect : mode === "single";
|
|
4918
|
+
const handleSelectEmpty = React6.useCallback(() => {
|
|
4919
|
+
if (mode === "single") {
|
|
4920
|
+
props.onValueChange?.(
|
|
4921
|
+
null
|
|
4922
|
+
);
|
|
4923
|
+
}
|
|
4924
|
+
if (closeOnSelect) setOpen(false);
|
|
4925
|
+
}, [mode, props, closeOnSelect, setOpen]);
|
|
4926
|
+
const handleSelectItem = React6.useCallback(
|
|
4927
|
+
(value) => {
|
|
4928
|
+
if (mode === "multiple") {
|
|
4929
|
+
const current = props.value ?? [];
|
|
4930
|
+
const onChange = props.onValueChange;
|
|
4931
|
+
const exists = current.includes(value);
|
|
4932
|
+
if (exists) {
|
|
4933
|
+
onChange?.(current.filter((v) => v !== value));
|
|
4934
|
+
} else if (maxSelected !== void 0 && current.length >= maxSelected) {
|
|
4935
|
+
return;
|
|
4936
|
+
} else {
|
|
4937
|
+
onChange?.([...current, value]);
|
|
4938
|
+
}
|
|
4939
|
+
if (closeOnSelect) setOpen(false);
|
|
4940
|
+
return;
|
|
4941
|
+
}
|
|
4942
|
+
props.onValueChange?.(
|
|
4943
|
+
value
|
|
4944
|
+
);
|
|
4945
|
+
if (closeOnSelect) setOpen(false);
|
|
4946
|
+
},
|
|
4947
|
+
[mode, props, maxSelected, closeOnSelect, setOpen]
|
|
4948
|
+
);
|
|
4949
|
+
const handleClear = React6.useCallback(
|
|
4950
|
+
(event) => {
|
|
4951
|
+
event.preventDefault();
|
|
4952
|
+
event.stopPropagation();
|
|
4953
|
+
if (mode === "multiple") {
|
|
4954
|
+
props.onValueChange?.(
|
|
4955
|
+
[]
|
|
4956
|
+
);
|
|
4957
|
+
} else {
|
|
4958
|
+
props.onValueChange?.(null);
|
|
4959
|
+
}
|
|
4960
|
+
},
|
|
4961
|
+
[mode, props]
|
|
4962
|
+
);
|
|
4963
|
+
const handleLoadMore = React6.useCallback(async () => {
|
|
4964
|
+
if (!onLoadMore || isLoadingMore) return;
|
|
4965
|
+
setIsLoadingMore(true);
|
|
4966
|
+
try {
|
|
4967
|
+
await onLoadMore();
|
|
4968
|
+
} finally {
|
|
4969
|
+
setIsLoadingMore(false);
|
|
4970
|
+
}
|
|
4971
|
+
}, [onLoadMore, isLoadingMore]);
|
|
4972
|
+
const triggerLabel = React6.useMemo(() => {
|
|
4973
|
+
if (renderValue) {
|
|
4974
|
+
if (mode === "multiple") {
|
|
4975
|
+
return renderValue(selectedItems);
|
|
4976
|
+
}
|
|
4977
|
+
return renderValue(selectedItems[0] ?? null);
|
|
4978
|
+
}
|
|
4979
|
+
if (mode === "multiple") {
|
|
4980
|
+
const count = selectedValues.size;
|
|
4981
|
+
if (count === 0) {
|
|
4982
|
+
return /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: labels.placeholder });
|
|
4983
|
+
}
|
|
4984
|
+
if (selectedItems.length === 1) {
|
|
4985
|
+
return getOptionLabel(selectedItems[0]);
|
|
4986
|
+
}
|
|
4987
|
+
return labels.selectedCount(count);
|
|
4988
|
+
}
|
|
4989
|
+
if (selectedValues.size === 0) {
|
|
4990
|
+
return /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: allowEmpty ? resolvedEmptyLabel : labels.placeholder });
|
|
4991
|
+
}
|
|
4992
|
+
if (selectedItems[0]) {
|
|
4993
|
+
return getOptionLabel(selectedItems[0]);
|
|
4994
|
+
}
|
|
4995
|
+
const only = [...selectedValues][0];
|
|
4996
|
+
return only ?? labels.placeholder;
|
|
4997
|
+
}, [
|
|
4998
|
+
renderValue,
|
|
4999
|
+
mode,
|
|
5000
|
+
selectedItems,
|
|
5001
|
+
selectedValues,
|
|
5002
|
+
labels,
|
|
5003
|
+
getOptionLabel,
|
|
5004
|
+
allowEmpty,
|
|
5005
|
+
resolvedEmptyLabel
|
|
5006
|
+
]);
|
|
5007
|
+
const showClear = clearable && !disabled && (mode === "multiple" ? selectedValues.size > 0 : selectedValues.size > 0);
|
|
5008
|
+
const list = /* @__PURE__ */ jsxRuntime.jsx(
|
|
5009
|
+
SearchablePickerList,
|
|
5010
|
+
{
|
|
5011
|
+
query,
|
|
5012
|
+
onQueryChange: setQuery,
|
|
5013
|
+
labels,
|
|
5014
|
+
isLoading,
|
|
5015
|
+
hasError,
|
|
5016
|
+
recommended,
|
|
5017
|
+
recent,
|
|
5018
|
+
results,
|
|
5019
|
+
selectedValues,
|
|
5020
|
+
mode,
|
|
5021
|
+
allowEmpty,
|
|
5022
|
+
emptyLabel: resolvedEmptyLabel,
|
|
5023
|
+
onSelectEmpty: handleSelectEmpty,
|
|
5024
|
+
onSelectItem: handleSelectItem,
|
|
5025
|
+
renderOption,
|
|
5026
|
+
createOption,
|
|
5027
|
+
onLoadMore: onLoadMore ? handleLoadMore : void 0,
|
|
5028
|
+
hasMore,
|
|
5029
|
+
isLoadingMore,
|
|
5030
|
+
listClassName: isMobile ? "max-h-[min(50vh,360px)]" : "max-h-72"
|
|
5031
|
+
}
|
|
5032
|
+
);
|
|
5033
|
+
const triggerButton = /* @__PURE__ */ jsxRuntime.jsxs(
|
|
5034
|
+
Button,
|
|
5035
|
+
{
|
|
5036
|
+
type: "button",
|
|
5037
|
+
variant: "outline",
|
|
5038
|
+
role: "combobox",
|
|
5039
|
+
id: triggerId,
|
|
5040
|
+
"aria-expanded": open,
|
|
5041
|
+
"aria-labelledby": ariaLabelledBy,
|
|
5042
|
+
"aria-label": ariaLabel ?? labels.placeholder,
|
|
5043
|
+
disabled,
|
|
5044
|
+
className: cn("w-full justify-between font-normal", triggerClassName2),
|
|
5045
|
+
children: [
|
|
5046
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 flex-1 truncate text-left", children: triggerLabel }),
|
|
5047
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronsUpDown, { className: "ml-2 size-4 shrink-0 opacity-50", "aria-hidden": true })
|
|
5048
|
+
]
|
|
5049
|
+
}
|
|
5050
|
+
);
|
|
5051
|
+
const clearButton = showClear ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
5052
|
+
Button,
|
|
5053
|
+
{
|
|
5054
|
+
type: "button",
|
|
5055
|
+
variant: "ghost",
|
|
5056
|
+
size: "icon-sm",
|
|
5057
|
+
"aria-label": labels.clear,
|
|
5058
|
+
disabled,
|
|
5059
|
+
className: "shrink-0",
|
|
5060
|
+
onClick: handleClear,
|
|
5061
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "size-4" })
|
|
5062
|
+
}
|
|
5063
|
+
) : null;
|
|
5064
|
+
if (isMobile) {
|
|
5065
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex w-full items-center gap-1", className), children: [
|
|
5066
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5067
|
+
"div",
|
|
5068
|
+
{
|
|
5069
|
+
className: "min-w-0 flex-1",
|
|
5070
|
+
onClick: () => {
|
|
5071
|
+
if (!disabled) setOpen(true);
|
|
5072
|
+
},
|
|
5073
|
+
children: triggerButton
|
|
5074
|
+
}
|
|
5075
|
+
),
|
|
5076
|
+
clearButton,
|
|
5077
|
+
/* @__PURE__ */ jsxRuntime.jsx(Drawer, { open, onOpenChange: setOpen, children: /* @__PURE__ */ jsxRuntime.jsxs(DrawerContent, { className: "max-h-[90vh]", children: [
|
|
5078
|
+
/* @__PURE__ */ jsxRuntime.jsx(DrawerHeader, { className: "text-left", children: /* @__PURE__ */ jsxRuntime.jsx(DrawerTitle, { children: labels.dialogTitle }) }),
|
|
5079
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "min-h-0 flex-1 overflow-hidden px-2 pb-2", children: list }),
|
|
5080
|
+
mode === "multiple" ? /* @__PURE__ */ jsxRuntime.jsxs(DrawerFooter, { className: "flex-row gap-2", children: [
|
|
5081
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5082
|
+
Button,
|
|
5083
|
+
{
|
|
5084
|
+
type: "button",
|
|
5085
|
+
variant: "outline",
|
|
5086
|
+
className: "flex-1",
|
|
5087
|
+
onClick: () => setOpen(false),
|
|
5088
|
+
children: labels.cancel
|
|
5089
|
+
}
|
|
5090
|
+
),
|
|
5091
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5092
|
+
Button,
|
|
5093
|
+
{
|
|
5094
|
+
type: "button",
|
|
5095
|
+
className: "flex-1",
|
|
5096
|
+
onClick: () => setOpen(false),
|
|
5097
|
+
children: labels.done
|
|
5098
|
+
}
|
|
5099
|
+
)
|
|
5100
|
+
] }) : null
|
|
5101
|
+
] }) })
|
|
5102
|
+
] });
|
|
5103
|
+
}
|
|
5104
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex w-full items-center gap-1", className), children: [
|
|
5105
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "min-w-0 flex-1", children: /* @__PURE__ */ jsxRuntime.jsxs(Popover, { open, onOpenChange: setOpen, modal: true, children: [
|
|
5106
|
+
/* @__PURE__ */ jsxRuntime.jsx(PopoverTrigger, { asChild: true, children: triggerButton }),
|
|
5107
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5108
|
+
PopoverContent,
|
|
5109
|
+
{
|
|
5110
|
+
className: "w-[var(--radix-popover-trigger-width)] min-w-[240px] p-0",
|
|
5111
|
+
align: "start",
|
|
5112
|
+
children: list
|
|
5113
|
+
}
|
|
5114
|
+
)
|
|
5115
|
+
] }) }),
|
|
5116
|
+
clearButton
|
|
5117
|
+
] });
|
|
5118
|
+
}
|
|
5119
|
+
var defaultLabels4 = {
|
|
4518
5120
|
placeholder: "Buscar en toda la plataforma\u2026",
|
|
4519
5121
|
dialogTitle: "Buscar",
|
|
4520
5122
|
dialogDescription: "Busca funcionalidades, eventos, documentos y m\xE1s",
|
|
@@ -4548,7 +5150,7 @@ function SearchCommand({
|
|
|
4548
5150
|
debounceMs = 200,
|
|
4549
5151
|
className
|
|
4550
5152
|
}) {
|
|
4551
|
-
const labels = { ...
|
|
5153
|
+
const labels = { ...defaultLabels4, ...userLabels };
|
|
4552
5154
|
const [query, setQuery] = React6.useState("");
|
|
4553
5155
|
const [hits, setHits] = React6.useState([]);
|
|
4554
5156
|
const [isLoading, setIsLoading] = React6.useState(false);
|
|
@@ -5429,18 +6031,6 @@ function ChatMessageList({
|
|
|
5429
6031
|
/* @__PURE__ */ jsxRuntime.jsx(MessageScrollerButton, {})
|
|
5430
6032
|
] }) });
|
|
5431
6033
|
}
|
|
5432
|
-
function useMediaQuery2(query) {
|
|
5433
|
-
const [matches, setMatches] = React6.useState(false);
|
|
5434
|
-
React6.useEffect(() => {
|
|
5435
|
-
if (typeof window === "undefined" || !window.matchMedia) return;
|
|
5436
|
-
const mql = window.matchMedia(query);
|
|
5437
|
-
const onChange = () => setMatches(mql.matches);
|
|
5438
|
-
onChange();
|
|
5439
|
-
mql.addEventListener("change", onChange);
|
|
5440
|
-
return () => mql.removeEventListener("change", onChange);
|
|
5441
|
-
}, [query]);
|
|
5442
|
-
return matches;
|
|
5443
|
-
}
|
|
5444
6034
|
var RECONNECT_DELAY_MS = 2e3;
|
|
5445
6035
|
function useSupportConversation({
|
|
5446
6036
|
client,
|
|
@@ -6117,6 +6707,7 @@ exports.MexicoMap = MexicoMap;
|
|
|
6117
6707
|
exports.OrgSwitcher = OrgSwitcher;
|
|
6118
6708
|
exports.PhoneInput = PhoneInput;
|
|
6119
6709
|
exports.SearchCommand = SearchCommand;
|
|
6710
|
+
exports.SearchablePicker = SearchablePicker;
|
|
6120
6711
|
exports.SupportMessengerProvider = SupportMessengerProvider;
|
|
6121
6712
|
exports.ThemeSwitcher = ThemeSwitcher;
|
|
6122
6713
|
exports.VerifiedProfessionalBadge = VerifiedProfessionalBadge;
|
|
@@ -6140,6 +6731,7 @@ exports.useDebouncedValue = useDebouncedValue;
|
|
|
6140
6731
|
exports.useDebouncedValueStrict = useDebouncedValueStrict;
|
|
6141
6732
|
exports.useHlsPlayback = useHlsPlayback;
|
|
6142
6733
|
exports.useLanguageContext = useLanguageContext;
|
|
6734
|
+
exports.useMediaQuery = useMediaQuery2;
|
|
6143
6735
|
exports.usePlaybackStats = usePlaybackStats;
|
|
6144
6736
|
exports.useSearchHotkey = useSearchHotkey;
|
|
6145
6737
|
exports.useSupportConversation = useSupportConversation;
|