@sesionario/blocks 1.8.0 → 1.10.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 +758 -43
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +92 -3
- package/dist/index.d.ts +92 -3
- package/dist/index.js +758 -45
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -521,6 +521,9 @@ function ExpandableText({
|
|
|
521
521
|
var MIN_SCALE = 1;
|
|
522
522
|
var MAX_SCALE = 4;
|
|
523
523
|
var DOUBLE_TAP_MS = 300;
|
|
524
|
+
var SWIPE_LOCK_PX = 8;
|
|
525
|
+
var SWIPE_COMMIT_PX = 56;
|
|
526
|
+
var SWIPE_SNAP_MS = 180;
|
|
524
527
|
var IDENTITY = { scale: 1, tx: 0, ty: 0 };
|
|
525
528
|
function clamp(value, min, max) {
|
|
526
529
|
return Math.min(max, Math.max(min, value));
|
|
@@ -538,6 +541,10 @@ function zoomToward(prev, nextScale, originX, originY) {
|
|
|
538
541
|
function pointerDistance(a, b) {
|
|
539
542
|
return Math.hypot(b.x - a.x, b.y - a.y);
|
|
540
543
|
}
|
|
544
|
+
function prefersReducedMotion() {
|
|
545
|
+
if (typeof window === "undefined" || !window.matchMedia) return false;
|
|
546
|
+
return window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
547
|
+
}
|
|
541
548
|
function ImageLightbox({
|
|
542
549
|
images,
|
|
543
550
|
index,
|
|
@@ -553,15 +560,24 @@ function ImageLightbox({
|
|
|
553
560
|
const [transform, setTransform] = React6.useState(IDENTITY);
|
|
554
561
|
const transformRef = React6.useRef(transform);
|
|
555
562
|
transformRef.current = transform;
|
|
563
|
+
const [isSwipeDragging, setIsSwipeDragging] = React6.useState(false);
|
|
564
|
+
const [snapBack, setSnapBack] = React6.useState(false);
|
|
556
565
|
const stageRef = React6.useRef(null);
|
|
557
566
|
const pointersRef = React6.useRef(/* @__PURE__ */ new Map());
|
|
558
567
|
const pinchStartRef = React6.useRef(null);
|
|
559
568
|
const panRef = React6.useRef(null);
|
|
569
|
+
const swipeRef = React6.useRef(null);
|
|
560
570
|
const lastTapRef = React6.useRef(
|
|
561
571
|
null
|
|
562
572
|
);
|
|
573
|
+
const indexRef = React6.useRef(index);
|
|
574
|
+
indexRef.current = index;
|
|
575
|
+
const imagesLengthRef = React6.useRef(images.length);
|
|
576
|
+
imagesLengthRef.current = images.length;
|
|
563
577
|
const resetZoom = React6.useCallback(() => {
|
|
564
578
|
setTransform(IDENTITY);
|
|
579
|
+
setIsSwipeDragging(false);
|
|
580
|
+
setSnapBack(false);
|
|
565
581
|
}, []);
|
|
566
582
|
React6.useEffect(() => {
|
|
567
583
|
resetZoom();
|
|
@@ -618,6 +634,10 @@ function ImageLightbox({
|
|
|
618
634
|
stage.addEventListener("wheel", handleWheel, { passive: false });
|
|
619
635
|
return () => stage.removeEventListener("wheel", handleWheel);
|
|
620
636
|
}, [stageOrigin]);
|
|
637
|
+
function clearSwipe() {
|
|
638
|
+
swipeRef.current = null;
|
|
639
|
+
setIsSwipeDragging(false);
|
|
640
|
+
}
|
|
621
641
|
function beginPinch() {
|
|
622
642
|
const pts = [...pointersRef.current.values()];
|
|
623
643
|
const [a, b] = pts;
|
|
@@ -632,13 +652,18 @@ function ImageLightbox({
|
|
|
632
652
|
transform: { ...transformRef.current }
|
|
633
653
|
};
|
|
634
654
|
panRef.current = null;
|
|
655
|
+
clearSwipe();
|
|
656
|
+
setSnapBack(false);
|
|
635
657
|
}
|
|
636
658
|
function onPointerDown(e) {
|
|
637
659
|
e.stopPropagation();
|
|
638
660
|
const stage = stageRef.current;
|
|
639
661
|
if (!stage) return;
|
|
640
|
-
stage.setPointerCapture
|
|
662
|
+
if (typeof stage.setPointerCapture === "function") {
|
|
663
|
+
stage.setPointerCapture(e.pointerId);
|
|
664
|
+
}
|
|
641
665
|
pointersRef.current.set(e.pointerId, { x: e.clientX, y: e.clientY });
|
|
666
|
+
setSnapBack(false);
|
|
642
667
|
if (pointersRef.current.size === 2) {
|
|
643
668
|
beginPinch();
|
|
644
669
|
return;
|
|
@@ -652,6 +677,17 @@ function ImageLightbox({
|
|
|
652
677
|
originTy: transformRef.current.ty,
|
|
653
678
|
moved: false
|
|
654
679
|
};
|
|
680
|
+
return;
|
|
681
|
+
}
|
|
682
|
+
if (hasMultiple) {
|
|
683
|
+
swipeRef.current = {
|
|
684
|
+
pointerId: e.pointerId,
|
|
685
|
+
startX: e.clientX,
|
|
686
|
+
startY: e.clientY,
|
|
687
|
+
moved: false,
|
|
688
|
+
axis: null
|
|
689
|
+
};
|
|
690
|
+
setIsSwipeDragging(true);
|
|
655
691
|
}
|
|
656
692
|
}
|
|
657
693
|
function onPointerMove(e) {
|
|
@@ -676,19 +712,62 @@ function ImageLightbox({
|
|
|
676
712
|
}
|
|
677
713
|
const pan = panRef.current;
|
|
678
714
|
if (pan && pan.pointerId === e.pointerId) {
|
|
679
|
-
const
|
|
680
|
-
const
|
|
681
|
-
if (Math.abs(
|
|
715
|
+
const dx2 = e.clientX - pan.startX;
|
|
716
|
+
const dy2 = e.clientY - pan.startY;
|
|
717
|
+
if (Math.abs(dx2) > 2 || Math.abs(dy2) > 2) pan.moved = true;
|
|
682
718
|
setTransform((prev) => ({
|
|
683
719
|
...prev,
|
|
684
|
-
tx: pan.originTx +
|
|
685
|
-
ty: pan.originTy +
|
|
720
|
+
tx: pan.originTx + dx2,
|
|
721
|
+
ty: pan.originTy + dy2
|
|
686
722
|
}));
|
|
723
|
+
return;
|
|
724
|
+
}
|
|
725
|
+
const swipe = swipeRef.current;
|
|
726
|
+
if (!swipe || swipe.pointerId !== e.pointerId) return;
|
|
727
|
+
const dx = e.clientX - swipe.startX;
|
|
728
|
+
const dy = e.clientY - swipe.startY;
|
|
729
|
+
if (Math.abs(dx) > 2 || Math.abs(dy) > 2) swipe.moved = true;
|
|
730
|
+
if (swipe.axis === null) {
|
|
731
|
+
const absX = Math.abs(dx);
|
|
732
|
+
const absY = Math.abs(dy);
|
|
733
|
+
if (absX < SWIPE_LOCK_PX && absY < SWIPE_LOCK_PX) return;
|
|
734
|
+
swipe.axis = absX >= absY ? "x" : "y";
|
|
735
|
+
if (swipe.axis === "y") {
|
|
736
|
+
clearSwipe();
|
|
737
|
+
setTransform(IDENTITY);
|
|
738
|
+
return;
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
if (swipe.axis === "x") {
|
|
742
|
+
setTransform({ scale: MIN_SCALE, tx: dx, ty: 0 });
|
|
743
|
+
}
|
|
744
|
+
}
|
|
745
|
+
function finishSwipe(e) {
|
|
746
|
+
const swipe = swipeRef.current;
|
|
747
|
+
if (!swipe || swipe.pointerId !== e.pointerId) return false;
|
|
748
|
+
const dx = e.clientX - swipe.startX;
|
|
749
|
+
const wasMoved = swipe.moved;
|
|
750
|
+
const axis = swipe.axis;
|
|
751
|
+
clearSwipe();
|
|
752
|
+
if (axis === "x" && Math.abs(dx) >= SWIPE_COMMIT_PX) {
|
|
753
|
+
const length = imagesLengthRef.current;
|
|
754
|
+
const current = indexRef.current;
|
|
755
|
+
if (dx < 0) {
|
|
756
|
+
onIndexChange((current + 1) % length);
|
|
757
|
+
} else {
|
|
758
|
+
onIndexChange((current - 1 + length) % length);
|
|
759
|
+
}
|
|
760
|
+
return true;
|
|
687
761
|
}
|
|
762
|
+
if (wasMoved || transformRef.current.tx !== 0) {
|
|
763
|
+
if (!prefersReducedMotion()) setSnapBack(true);
|
|
764
|
+
setTransform(IDENTITY);
|
|
765
|
+
}
|
|
766
|
+
return wasMoved;
|
|
688
767
|
}
|
|
689
768
|
function onPointerUp(e) {
|
|
690
769
|
const stage = stageRef.current;
|
|
691
|
-
if (stage
|
|
770
|
+
if (stage && typeof stage.hasPointerCapture === "function" && stage.hasPointerCapture(e.pointerId) && typeof stage.releasePointerCapture === "function") {
|
|
692
771
|
stage.releasePointerCapture(e.pointerId);
|
|
693
772
|
}
|
|
694
773
|
pointersRef.current.delete(e.pointerId);
|
|
@@ -709,6 +788,8 @@ function ImageLightbox({
|
|
|
709
788
|
};
|
|
710
789
|
}
|
|
711
790
|
}
|
|
791
|
+
const swipeHandled = finishSwipe(e);
|
|
792
|
+
if (swipeHandled) return;
|
|
712
793
|
const pan = panRef.current;
|
|
713
794
|
if (pan && pan.pointerId === e.pointerId) {
|
|
714
795
|
const wasMoved = pan.moved;
|
|
@@ -730,6 +811,7 @@ function ImageLightbox({
|
|
|
730
811
|
e.stopPropagation();
|
|
731
812
|
}
|
|
732
813
|
const { scale, tx, ty } = transform;
|
|
814
|
+
const transition = snapBack && !isSwipeDragging && !prefersReducedMotion() ? `transform ${SWIPE_SNAP_MS}ms ease-out` : void 0;
|
|
733
815
|
return reactDom.createPortal(
|
|
734
816
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
735
817
|
"div",
|
|
@@ -769,6 +851,7 @@ function ImageLightbox({
|
|
|
769
851
|
ref: stageRef,
|
|
770
852
|
className: "relative flex max-h-full max-w-full touch-none items-center justify-center",
|
|
771
853
|
"data-scale": scale,
|
|
854
|
+
"data-swipe-dragging": isSwipeDragging ? "true" : "false",
|
|
772
855
|
onClick: stopDialogClose,
|
|
773
856
|
onPointerDown,
|
|
774
857
|
onPointerMove,
|
|
@@ -783,8 +866,10 @@ function ImageLightbox({
|
|
|
783
866
|
className: "max-h-[calc(100dvh-2rem)] max-w-full select-none rounded-lg object-contain",
|
|
784
867
|
style: {
|
|
785
868
|
transform: `translate(${tx}px, ${ty}px) scale(${scale})`,
|
|
869
|
+
transition,
|
|
786
870
|
cursor: scale > MIN_SCALE ? "grab" : "default"
|
|
787
|
-
}
|
|
871
|
+
},
|
|
872
|
+
onTransitionEnd: () => setSnapBack(false)
|
|
788
873
|
}
|
|
789
874
|
)
|
|
790
875
|
}
|
|
@@ -1411,7 +1496,7 @@ function LanguageSwitcher({
|
|
|
1411
1496
|
const sizes = sizeClasses2[size];
|
|
1412
1497
|
const shapeClass = shapeClasses2[shape];
|
|
1413
1498
|
const reduceMotion = framerMotion.useReducedMotion();
|
|
1414
|
-
const
|
|
1499
|
+
const defaultLabels5 = {
|
|
1415
1500
|
language: labels.language ?? "Language"
|
|
1416
1501
|
};
|
|
1417
1502
|
if (variant === "mini") {
|
|
@@ -1421,7 +1506,7 @@ function LanguageSwitcher({
|
|
|
1421
1506
|
{
|
|
1422
1507
|
variant: "ghost",
|
|
1423
1508
|
size: "icon",
|
|
1424
|
-
"aria-label":
|
|
1509
|
+
"aria-label": defaultLabels5.language,
|
|
1425
1510
|
className: cn(sizes.buttonMini, shapeClass, className),
|
|
1426
1511
|
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Languages, { className: sizes.iconMini })
|
|
1427
1512
|
}
|
|
@@ -3710,6 +3795,19 @@ var PLAYBACK_RATES = [0.75, 1, 1.25, 1.5, 2];
|
|
|
3710
3795
|
var CONTROLS_HIDE_MS = 3e3;
|
|
3711
3796
|
var LIVE_EDGE_THRESHOLD_S = 8;
|
|
3712
3797
|
var SEEK_STEP_S = 5;
|
|
3798
|
+
function asWebkitVideo(video) {
|
|
3799
|
+
return video;
|
|
3800
|
+
}
|
|
3801
|
+
function hasWebkitVideoFullscreen(video) {
|
|
3802
|
+
const webkit = asWebkitVideo(video);
|
|
3803
|
+
return typeof webkit?.webkitEnterFullscreen === "function";
|
|
3804
|
+
}
|
|
3805
|
+
function hasStandardFullscreen() {
|
|
3806
|
+
if (typeof document === "undefined") return false;
|
|
3807
|
+
if (document.fullscreenEnabled) return true;
|
|
3808
|
+
const doc = document;
|
|
3809
|
+
return !!doc.webkitFullscreenEnabled;
|
|
3810
|
+
}
|
|
3713
3811
|
function formatTime(seconds) {
|
|
3714
3812
|
if (!Number.isFinite(seconds) || seconds < 0) return "0:00";
|
|
3715
3813
|
const total = Math.floor(seconds);
|
|
@@ -3783,10 +3881,10 @@ function VideoPlayer({
|
|
|
3783
3881
|
null
|
|
3784
3882
|
);
|
|
3785
3883
|
const [behindLive, setBehindLive] = React6__namespace.useState(false);
|
|
3884
|
+
const [webkitFullscreenSupported, setWebkitFullscreenSupported] = React6__namespace.useState(false);
|
|
3786
3885
|
const hideTimerRef = React6__namespace.useRef(null);
|
|
3787
3886
|
const pipSupported = typeof document !== "undefined" && "pictureInPictureEnabled" in document && document.pictureInPictureEnabled;
|
|
3788
|
-
const fullscreenSupported =
|
|
3789
|
-
"webkitFullscreenEnabled" in document);
|
|
3887
|
+
const fullscreenSupported = hasStandardFullscreen() || webkitFullscreenSupported;
|
|
3790
3888
|
React6__namespace.useEffect(() => {
|
|
3791
3889
|
const video = videoRef.current;
|
|
3792
3890
|
if (!video || !active) return;
|
|
@@ -3820,11 +3918,26 @@ function VideoPlayer({
|
|
|
3820
3918
|
video.removeEventListener("ratechange", onRate);
|
|
3821
3919
|
};
|
|
3822
3920
|
}, [videoRef, active, mode]);
|
|
3921
|
+
React6__namespace.useEffect(() => {
|
|
3922
|
+
setWebkitFullscreenSupported(hasWebkitVideoFullscreen(videoRef.current));
|
|
3923
|
+
}, [videoRef, active]);
|
|
3823
3924
|
React6__namespace.useEffect(() => {
|
|
3824
3925
|
const onFsChange = () => setIsFullscreen(document.fullscreenElement === containerRef.current);
|
|
3825
3926
|
document.addEventListener("fullscreenchange", onFsChange);
|
|
3826
3927
|
return () => document.removeEventListener("fullscreenchange", onFsChange);
|
|
3827
3928
|
}, []);
|
|
3929
|
+
React6__namespace.useEffect(() => {
|
|
3930
|
+
const video = asWebkitVideo(videoRef.current);
|
|
3931
|
+
if (!video) return;
|
|
3932
|
+
const onBegin = () => setIsFullscreen(true);
|
|
3933
|
+
const onEnd = () => setIsFullscreen(false);
|
|
3934
|
+
video.addEventListener("webkitbeginfullscreen", onBegin);
|
|
3935
|
+
video.addEventListener("webkitendfullscreen", onEnd);
|
|
3936
|
+
return () => {
|
|
3937
|
+
video.removeEventListener("webkitbeginfullscreen", onBegin);
|
|
3938
|
+
video.removeEventListener("webkitendfullscreen", onEnd);
|
|
3939
|
+
};
|
|
3940
|
+
}, [videoRef, active]);
|
|
3828
3941
|
React6__namespace.useEffect(() => {
|
|
3829
3942
|
const video = videoRef.current;
|
|
3830
3943
|
if (!video) return;
|
|
@@ -3889,11 +4002,21 @@ function VideoPlayer({
|
|
|
3889
4002
|
}
|
|
3890
4003
|
function toggleFullscreen() {
|
|
3891
4004
|
const el = containerRef.current;
|
|
3892
|
-
|
|
3893
|
-
if (document.fullscreenElement === el) {
|
|
4005
|
+
const video = asWebkitVideo(videoRef.current);
|
|
4006
|
+
if (el && document.fullscreenElement === el) {
|
|
3894
4007
|
void document.exitFullscreen();
|
|
3895
|
-
|
|
3896
|
-
|
|
4008
|
+
return;
|
|
4009
|
+
}
|
|
4010
|
+
if (video?.webkitDisplayingFullscreen && video.webkitExitFullscreen) {
|
|
4011
|
+
video.webkitExitFullscreen();
|
|
4012
|
+
return;
|
|
4013
|
+
}
|
|
4014
|
+
if (el && hasStandardFullscreen() && typeof el.requestFullscreen === "function") {
|
|
4015
|
+
void el.requestFullscreen();
|
|
4016
|
+
return;
|
|
4017
|
+
}
|
|
4018
|
+
if (video && typeof video.webkitEnterFullscreen === "function") {
|
|
4019
|
+
video.webkitEnterFullscreen();
|
|
3897
4020
|
}
|
|
3898
4021
|
}
|
|
3899
4022
|
function togglePip() {
|
|
@@ -4348,6 +4471,18 @@ function useDebouncedValueStrict(value, delayMs) {
|
|
|
4348
4471
|
}, [value, delayMs]);
|
|
4349
4472
|
return debounced;
|
|
4350
4473
|
}
|
|
4474
|
+
function useMediaQuery2(query) {
|
|
4475
|
+
const [matches, setMatches] = React6.useState(false);
|
|
4476
|
+
React6.useEffect(() => {
|
|
4477
|
+
if (typeof window === "undefined" || !window.matchMedia) return;
|
|
4478
|
+
const mql = window.matchMedia(query);
|
|
4479
|
+
const onChange = () => setMatches(mql.matches);
|
|
4480
|
+
onChange();
|
|
4481
|
+
mql.addEventListener("change", onChange);
|
|
4482
|
+
return () => mql.removeEventListener("change", onChange);
|
|
4483
|
+
}, [query]);
|
|
4484
|
+
return matches;
|
|
4485
|
+
}
|
|
4351
4486
|
function useSearchHotkey(options = {}) {
|
|
4352
4487
|
const { defaultOpen = false, disabled = false } = options;
|
|
4353
4488
|
const [open, setOpen] = React6.useState(defaultOpen);
|
|
@@ -4365,6 +4500,22 @@ function useSearchHotkey(options = {}) {
|
|
|
4365
4500
|
}, [disabled]);
|
|
4366
4501
|
return { open, setOpen, toggle };
|
|
4367
4502
|
}
|
|
4503
|
+
|
|
4504
|
+
// src/components/search/fuzzy.ts
|
|
4505
|
+
function normalize(value) {
|
|
4506
|
+
return value.toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "");
|
|
4507
|
+
}
|
|
4508
|
+
function fuzzyMatch(query, target) {
|
|
4509
|
+
const q = normalize(query.trim());
|
|
4510
|
+
if (!q) return true;
|
|
4511
|
+
const t = normalize(target);
|
|
4512
|
+
if (t.includes(q)) return true;
|
|
4513
|
+
let qi = 0;
|
|
4514
|
+
for (let ti = 0; ti < t.length && qi < q.length; ti++) {
|
|
4515
|
+
if (t[ti] === q[qi]) qi++;
|
|
4516
|
+
}
|
|
4517
|
+
return qi === q.length;
|
|
4518
|
+
}
|
|
4368
4519
|
function Command({
|
|
4369
4520
|
className,
|
|
4370
4521
|
...props
|
|
@@ -4482,6 +4633,19 @@ function CommandGroup({
|
|
|
4482
4633
|
}
|
|
4483
4634
|
);
|
|
4484
4635
|
}
|
|
4636
|
+
function CommandSeparator({
|
|
4637
|
+
className,
|
|
4638
|
+
...props
|
|
4639
|
+
}) {
|
|
4640
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
4641
|
+
cmdk.Command.Separator,
|
|
4642
|
+
{
|
|
4643
|
+
"data-slot": "command-separator",
|
|
4644
|
+
className: cn("-mx-1 h-px bg-border", className),
|
|
4645
|
+
...props
|
|
4646
|
+
}
|
|
4647
|
+
);
|
|
4648
|
+
}
|
|
4485
4649
|
function CommandItem({
|
|
4486
4650
|
className,
|
|
4487
4651
|
...props
|
|
@@ -4498,23 +4662,584 @@ function CommandItem({
|
|
|
4498
4662
|
}
|
|
4499
4663
|
);
|
|
4500
4664
|
}
|
|
4501
|
-
|
|
4502
|
-
|
|
4503
|
-
|
|
4504
|
-
|
|
4665
|
+
function OptionRow({
|
|
4666
|
+
entry,
|
|
4667
|
+
selected,
|
|
4668
|
+
onSelect,
|
|
4669
|
+
renderOption
|
|
4670
|
+
}) {
|
|
4671
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
4672
|
+
CommandItem,
|
|
4673
|
+
{
|
|
4674
|
+
value: entry.value,
|
|
4675
|
+
keywords: [entry.label],
|
|
4676
|
+
onSelect,
|
|
4677
|
+
"data-checked": selected || void 0,
|
|
4678
|
+
children: [
|
|
4679
|
+
renderOption ? renderOption(entry.item, { selected }) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 flex-1 truncate", children: entry.label }),
|
|
4680
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4681
|
+
lucideReact.CheckIcon,
|
|
4682
|
+
{
|
|
4683
|
+
className: cn(
|
|
4684
|
+
"ml-auto size-4 shrink-0",
|
|
4685
|
+
selected ? "opacity-100" : "opacity-0"
|
|
4686
|
+
)
|
|
4687
|
+
}
|
|
4688
|
+
)
|
|
4689
|
+
]
|
|
4690
|
+
},
|
|
4691
|
+
entry.value
|
|
4692
|
+
);
|
|
4505
4693
|
}
|
|
4506
|
-
function
|
|
4507
|
-
|
|
4508
|
-
|
|
4509
|
-
|
|
4510
|
-
|
|
4511
|
-
|
|
4512
|
-
|
|
4513
|
-
|
|
4514
|
-
|
|
4515
|
-
|
|
4694
|
+
function SearchablePickerList({
|
|
4695
|
+
query,
|
|
4696
|
+
onQueryChange,
|
|
4697
|
+
labels,
|
|
4698
|
+
isLoading,
|
|
4699
|
+
hasError,
|
|
4700
|
+
recommended,
|
|
4701
|
+
recent,
|
|
4702
|
+
results,
|
|
4703
|
+
selectedValues,
|
|
4704
|
+
mode,
|
|
4705
|
+
allowEmpty,
|
|
4706
|
+
emptyLabel,
|
|
4707
|
+
onSelectEmpty,
|
|
4708
|
+
onSelectItem,
|
|
4709
|
+
renderOption,
|
|
4710
|
+
createOption,
|
|
4711
|
+
onLoadMore,
|
|
4712
|
+
hasMore,
|
|
4713
|
+
isLoadingMore,
|
|
4714
|
+
listClassName
|
|
4715
|
+
}) {
|
|
4716
|
+
const hasPinned = recommended.length > 0 || recent.length > 0;
|
|
4717
|
+
const hasResults = results.length > 0;
|
|
4718
|
+
const showEmpty = !isLoading && !hasError && !hasPinned && !hasResults && !(allowEmpty && mode === "single");
|
|
4719
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(Command, { shouldFilter: false, className: "flex h-full min-h-0 flex-col", children: [
|
|
4720
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4721
|
+
CommandInput,
|
|
4722
|
+
{
|
|
4723
|
+
placeholder: labels.searchPlaceholder,
|
|
4724
|
+
value: query,
|
|
4725
|
+
onValueChange: onQueryChange
|
|
4726
|
+
}
|
|
4727
|
+
),
|
|
4728
|
+
/* @__PURE__ */ jsxRuntime.jsxs(CommandList, { className: cn("min-h-0 flex-1", listClassName), children: [
|
|
4729
|
+
isLoading ? /* @__PURE__ */ jsxRuntime.jsxs(
|
|
4730
|
+
"div",
|
|
4731
|
+
{
|
|
4732
|
+
className: "flex items-center justify-center gap-2 py-6 text-sm text-muted-foreground",
|
|
4733
|
+
role: "status",
|
|
4734
|
+
children: [
|
|
4735
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "size-4 animate-spin", "aria-hidden": true }),
|
|
4736
|
+
labels.loading
|
|
4737
|
+
]
|
|
4738
|
+
}
|
|
4739
|
+
) : null,
|
|
4740
|
+
hasError && !isLoading ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
4741
|
+
"div",
|
|
4742
|
+
{
|
|
4743
|
+
className: "py-6 text-center text-sm text-destructive",
|
|
4744
|
+
role: "alert",
|
|
4745
|
+
children: labels.error
|
|
4746
|
+
}
|
|
4747
|
+
) : null,
|
|
4748
|
+
showEmpty ? /* @__PURE__ */ jsxRuntime.jsx(CommandEmpty, { children: labels.empty }) : null,
|
|
4749
|
+
allowEmpty && mode === "single" && !query.trim() ? /* @__PURE__ */ jsxRuntime.jsx(CommandGroup, { children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
4750
|
+
CommandItem,
|
|
4751
|
+
{
|
|
4752
|
+
value: "__empty__",
|
|
4753
|
+
onSelect: () => onSelectEmpty?.(),
|
|
4754
|
+
"data-checked": !selectedValues.size || void 0,
|
|
4755
|
+
children: [
|
|
4756
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 flex-1 truncate text-muted-foreground", children: emptyLabel }),
|
|
4757
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4758
|
+
lucideReact.CheckIcon,
|
|
4759
|
+
{
|
|
4760
|
+
className: cn(
|
|
4761
|
+
"ml-auto size-4 shrink-0",
|
|
4762
|
+
selectedValues.size === 0 ? "opacity-100" : "opacity-0"
|
|
4763
|
+
)
|
|
4764
|
+
}
|
|
4765
|
+
)
|
|
4766
|
+
]
|
|
4767
|
+
}
|
|
4768
|
+
) }) : null,
|
|
4769
|
+
recommended.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(CommandGroup, { heading: labels.recommended, children: recommended.map((entry) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
4770
|
+
OptionRow,
|
|
4771
|
+
{
|
|
4772
|
+
entry,
|
|
4773
|
+
selected: selectedValues.has(entry.value),
|
|
4774
|
+
onSelect: () => onSelectItem(entry.value),
|
|
4775
|
+
renderOption
|
|
4776
|
+
},
|
|
4777
|
+
`rec-${entry.value}`
|
|
4778
|
+
)) }) : null,
|
|
4779
|
+
recent.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(CommandGroup, { heading: labels.recent, children: recent.map((entry) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
4780
|
+
OptionRow,
|
|
4781
|
+
{
|
|
4782
|
+
entry,
|
|
4783
|
+
selected: selectedValues.has(entry.value),
|
|
4784
|
+
onSelect: () => onSelectItem(entry.value),
|
|
4785
|
+
renderOption
|
|
4786
|
+
},
|
|
4787
|
+
`recent-${entry.value}`
|
|
4788
|
+
)) }) : null,
|
|
4789
|
+
hasPinned && hasResults ? /* @__PURE__ */ jsxRuntime.jsx(CommandSeparator, {}) : null,
|
|
4790
|
+
hasResults ? /* @__PURE__ */ jsxRuntime.jsx(CommandGroup, { heading: hasPinned ? labels.results : void 0, children: results.map((entry) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
4791
|
+
OptionRow,
|
|
4792
|
+
{
|
|
4793
|
+
entry,
|
|
4794
|
+
selected: selectedValues.has(entry.value),
|
|
4795
|
+
onSelect: () => onSelectItem(entry.value),
|
|
4796
|
+
renderOption
|
|
4797
|
+
},
|
|
4798
|
+
`res-${entry.value}`
|
|
4799
|
+
)) }) : null,
|
|
4800
|
+
hasMore && onLoadMore ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-2", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
4801
|
+
Button,
|
|
4802
|
+
{
|
|
4803
|
+
type: "button",
|
|
4804
|
+
variant: "ghost",
|
|
4805
|
+
size: "sm",
|
|
4806
|
+
className: "w-full",
|
|
4807
|
+
disabled: isLoadingMore,
|
|
4808
|
+
onClick: () => void onLoadMore(),
|
|
4809
|
+
children: isLoadingMore ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
4810
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "size-4 animate-spin", "aria-hidden": true }),
|
|
4811
|
+
labels.loading
|
|
4812
|
+
] }) : labels.loadMore
|
|
4813
|
+
}
|
|
4814
|
+
) }) : null,
|
|
4815
|
+
createOption ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
4816
|
+
/* @__PURE__ */ jsxRuntime.jsx(CommandSeparator, {}),
|
|
4817
|
+
/* @__PURE__ */ jsxRuntime.jsx(CommandGroup, { children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
4818
|
+
CommandItem,
|
|
4819
|
+
{
|
|
4820
|
+
value: "__create__",
|
|
4821
|
+
onSelect: () => createOption.onSelect(),
|
|
4822
|
+
children: createOption.label
|
|
4823
|
+
}
|
|
4824
|
+
) })
|
|
4825
|
+
] }) : null
|
|
4826
|
+
] })
|
|
4827
|
+
] });
|
|
4516
4828
|
}
|
|
4517
4829
|
var defaultLabels3 = {
|
|
4830
|
+
placeholder: "Seleccionar\u2026",
|
|
4831
|
+
searchPlaceholder: "Buscar\u2026",
|
|
4832
|
+
empty: "No se encontraron resultados",
|
|
4833
|
+
loading: "Cargando\u2026",
|
|
4834
|
+
error: "No se pudo cargar la lista",
|
|
4835
|
+
recommended: "Recomendados",
|
|
4836
|
+
recent: "Recientes",
|
|
4837
|
+
results: "Resultados",
|
|
4838
|
+
done: "Listo",
|
|
4839
|
+
cancel: "Cancelar",
|
|
4840
|
+
clear: "Limpiar",
|
|
4841
|
+
selectedCount: (count) => count === 1 ? "1 seleccionado" : `${count} seleccionados`,
|
|
4842
|
+
emptyOption: "Ninguno",
|
|
4843
|
+
loadMore: "Cargar m\xE1s",
|
|
4844
|
+
dialogTitle: "Seleccionar"
|
|
4845
|
+
};
|
|
4846
|
+
function toListItems(items, getOptionValue, getOptionLabel) {
|
|
4847
|
+
if (!items?.length) return [];
|
|
4848
|
+
return items.map((item) => ({
|
|
4849
|
+
item,
|
|
4850
|
+
value: getOptionValue(item),
|
|
4851
|
+
label: getOptionLabel(item)
|
|
4852
|
+
}));
|
|
4853
|
+
}
|
|
4854
|
+
function dedupeByValue(items, exclude = /* @__PURE__ */ new Set()) {
|
|
4855
|
+
const seen = new Set(exclude);
|
|
4856
|
+
const out = [];
|
|
4857
|
+
for (const entry of items) {
|
|
4858
|
+
if (seen.has(entry.value)) continue;
|
|
4859
|
+
seen.add(entry.value);
|
|
4860
|
+
out.push(entry);
|
|
4861
|
+
}
|
|
4862
|
+
return out;
|
|
4863
|
+
}
|
|
4864
|
+
function matchesQuery(entry, query, getOptionKeywords) {
|
|
4865
|
+
if (!query.trim()) return true;
|
|
4866
|
+
if (fuzzyMatch(query, entry.label)) return true;
|
|
4867
|
+
return getOptionKeywords?.(entry.item)?.some(
|
|
4868
|
+
(keyword) => fuzzyMatch(query, keyword)
|
|
4869
|
+
) ?? false;
|
|
4870
|
+
}
|
|
4871
|
+
function SearchablePicker(props) {
|
|
4872
|
+
const {
|
|
4873
|
+
options,
|
|
4874
|
+
fetchOptions,
|
|
4875
|
+
getOptionValue,
|
|
4876
|
+
getOptionLabel,
|
|
4877
|
+
getOptionKeywords,
|
|
4878
|
+
renderOption,
|
|
4879
|
+
renderValue,
|
|
4880
|
+
pinned,
|
|
4881
|
+
labels: userLabels,
|
|
4882
|
+
minQueryLength = 0,
|
|
4883
|
+
debounceMs = 200,
|
|
4884
|
+
disabled,
|
|
4885
|
+
open: openProp,
|
|
4886
|
+
onOpenChange,
|
|
4887
|
+
clearable,
|
|
4888
|
+
allowEmpty,
|
|
4889
|
+
emptyLabel,
|
|
4890
|
+
keepOpenOnSelect,
|
|
4891
|
+
maxSelected,
|
|
4892
|
+
createOption,
|
|
4893
|
+
onLoadMore,
|
|
4894
|
+
hasMore,
|
|
4895
|
+
className,
|
|
4896
|
+
triggerClassName: triggerClassName2,
|
|
4897
|
+
id,
|
|
4898
|
+
"aria-labelledby": ariaLabelledBy,
|
|
4899
|
+
"aria-label": ariaLabel
|
|
4900
|
+
} = props;
|
|
4901
|
+
const mode = props.mode ?? "single";
|
|
4902
|
+
const labels = { ...defaultLabels3, ...userLabels };
|
|
4903
|
+
const resolvedEmptyLabel = emptyLabel ?? labels.emptyOption;
|
|
4904
|
+
const isMobile = useMediaQuery2("(max-width: 767px)");
|
|
4905
|
+
const generatedId = React6.useId();
|
|
4906
|
+
const triggerId = id ?? generatedId;
|
|
4907
|
+
const [uncontrolledOpen, setUncontrolledOpen] = React6.useState(false);
|
|
4908
|
+
const open = openProp ?? uncontrolledOpen;
|
|
4909
|
+
const setOpen = React6.useCallback(
|
|
4910
|
+
(next) => {
|
|
4911
|
+
onOpenChange?.(next);
|
|
4912
|
+
if (openProp === void 0) setUncontrolledOpen(next);
|
|
4913
|
+
},
|
|
4914
|
+
[onOpenChange, openProp]
|
|
4915
|
+
);
|
|
4916
|
+
const [query, setQuery] = React6.useState("");
|
|
4917
|
+
const [remoteItems, setRemoteItems] = React6.useState([]);
|
|
4918
|
+
const [isLoading, setIsLoading] = React6.useState(false);
|
|
4919
|
+
const [hasError, setHasError] = React6.useState(false);
|
|
4920
|
+
const [isLoadingMore, setIsLoadingMore] = React6.useState(false);
|
|
4921
|
+
const debouncedQuery = useDebouncedValue(query, debounceMs);
|
|
4922
|
+
const requestIdRef = React6.useRef(0);
|
|
4923
|
+
const knownItemsRef = React6.useRef(/* @__PURE__ */ new Map());
|
|
4924
|
+
const rememberItems = React6.useCallback(
|
|
4925
|
+
(items) => {
|
|
4926
|
+
for (const item of items) {
|
|
4927
|
+
knownItemsRef.current.set(getOptionValue(item), item);
|
|
4928
|
+
}
|
|
4929
|
+
},
|
|
4930
|
+
[getOptionValue]
|
|
4931
|
+
);
|
|
4932
|
+
React6.useEffect(() => {
|
|
4933
|
+
if (options) rememberItems(options);
|
|
4934
|
+
if (pinned?.recommended) rememberItems(pinned.recommended);
|
|
4935
|
+
if (pinned?.recent) rememberItems(pinned.recent);
|
|
4936
|
+
}, [options, pinned, rememberItems]);
|
|
4937
|
+
React6.useEffect(() => {
|
|
4938
|
+
if (!open) {
|
|
4939
|
+
setQuery("");
|
|
4940
|
+
setRemoteItems([]);
|
|
4941
|
+
setHasError(false);
|
|
4942
|
+
setIsLoading(false);
|
|
4943
|
+
}
|
|
4944
|
+
}, [open]);
|
|
4945
|
+
const trimmedDebounced = debouncedQuery.trim();
|
|
4946
|
+
const shouldFetch = Boolean(fetchOptions) && open && trimmedDebounced.length >= minQueryLength && (trimmedDebounced.length > 0 || !options);
|
|
4947
|
+
React6.useEffect(() => {
|
|
4948
|
+
if (!shouldFetch || !fetchOptions) {
|
|
4949
|
+
if (!trimmedDebounced) {
|
|
4950
|
+
setRemoteItems([]);
|
|
4951
|
+
setHasError(false);
|
|
4952
|
+
setIsLoading(false);
|
|
4953
|
+
}
|
|
4954
|
+
return;
|
|
4955
|
+
}
|
|
4956
|
+
const requestId = ++requestIdRef.current;
|
|
4957
|
+
setIsLoading(true);
|
|
4958
|
+
setHasError(false);
|
|
4959
|
+
fetchOptions(trimmedDebounced).then((result) => {
|
|
4960
|
+
if (requestIdRef.current !== requestId) return;
|
|
4961
|
+
setRemoteItems(result);
|
|
4962
|
+
rememberItems(result);
|
|
4963
|
+
}).catch(() => {
|
|
4964
|
+
if (requestIdRef.current !== requestId) return;
|
|
4965
|
+
setRemoteItems([]);
|
|
4966
|
+
setHasError(true);
|
|
4967
|
+
}).finally(() => {
|
|
4968
|
+
if (requestIdRef.current !== requestId) return;
|
|
4969
|
+
setIsLoading(false);
|
|
4970
|
+
});
|
|
4971
|
+
}, [shouldFetch, fetchOptions, trimmedDebounced, rememberItems]);
|
|
4972
|
+
const selectedValues = React6.useMemo(() => {
|
|
4973
|
+
if (mode === "multiple") {
|
|
4974
|
+
const multiValue = props.value ?? [];
|
|
4975
|
+
return new Set(multiValue);
|
|
4976
|
+
}
|
|
4977
|
+
const singleValue = props.value;
|
|
4978
|
+
return singleValue ? /* @__PURE__ */ new Set([singleValue]) : /* @__PURE__ */ new Set();
|
|
4979
|
+
}, [mode, props]);
|
|
4980
|
+
const selectedValueKey = mode === "multiple" ? (props.value ?? []).join("\0") : props.value ?? "";
|
|
4981
|
+
const selectedItems = React6.useMemo(() => {
|
|
4982
|
+
const values = mode === "multiple" ? selectedValueKey ? selectedValueKey.split("\0") : [] : selectedValueKey ? [selectedValueKey] : [];
|
|
4983
|
+
return values.map((value) => knownItemsRef.current.get(value)).filter((item) => item !== void 0);
|
|
4984
|
+
}, [mode, selectedValueKey, options, pinned, remoteItems]);
|
|
4985
|
+
const queryForFilter = query.trim();
|
|
4986
|
+
const recommended = React6.useMemo(() => {
|
|
4987
|
+
if (queryForFilter) return [];
|
|
4988
|
+
const pinnedValues = /* @__PURE__ */ new Set();
|
|
4989
|
+
const items = dedupeByValue(
|
|
4990
|
+
toListItems(pinned?.recommended, getOptionValue, getOptionLabel)
|
|
4991
|
+
);
|
|
4992
|
+
for (const entry of items) pinnedValues.add(entry.value);
|
|
4993
|
+
return items;
|
|
4994
|
+
}, [queryForFilter, pinned?.recommended, getOptionValue, getOptionLabel]);
|
|
4995
|
+
const recent = React6.useMemo(() => {
|
|
4996
|
+
if (queryForFilter) return [];
|
|
4997
|
+
const exclude = new Set(recommended.map((e) => e.value));
|
|
4998
|
+
return dedupeByValue(
|
|
4999
|
+
toListItems(pinned?.recent, getOptionValue, getOptionLabel),
|
|
5000
|
+
exclude
|
|
5001
|
+
);
|
|
5002
|
+
}, [
|
|
5003
|
+
queryForFilter,
|
|
5004
|
+
pinned?.recent,
|
|
5005
|
+
recommended,
|
|
5006
|
+
getOptionValue,
|
|
5007
|
+
getOptionLabel
|
|
5008
|
+
]);
|
|
5009
|
+
const pinnedValueSet = React6.useMemo(() => {
|
|
5010
|
+
const set = /* @__PURE__ */ new Set();
|
|
5011
|
+
for (const entry of recommended) set.add(entry.value);
|
|
5012
|
+
for (const entry of recent) set.add(entry.value);
|
|
5013
|
+
return set;
|
|
5014
|
+
}, [recommended, recent]);
|
|
5015
|
+
const results = React6.useMemo(() => {
|
|
5016
|
+
const usingRemote = Boolean(fetchOptions) && trimmedDebounced.length >= minQueryLength && (trimmedDebounced.length > 0 || !options);
|
|
5017
|
+
if (usingRemote) {
|
|
5018
|
+
return dedupeByValue(
|
|
5019
|
+
toListItems(remoteItems, getOptionValue, getOptionLabel),
|
|
5020
|
+
queryForFilter ? /* @__PURE__ */ new Set() : pinnedValueSet
|
|
5021
|
+
);
|
|
5022
|
+
}
|
|
5023
|
+
const staticItems = toListItems(options, getOptionValue, getOptionLabel);
|
|
5024
|
+
const filtered = staticItems.filter(
|
|
5025
|
+
(entry) => matchesQuery(entry, queryForFilter, getOptionKeywords)
|
|
5026
|
+
);
|
|
5027
|
+
return dedupeByValue(filtered, queryForFilter ? /* @__PURE__ */ new Set() : pinnedValueSet);
|
|
5028
|
+
}, [
|
|
5029
|
+
fetchOptions,
|
|
5030
|
+
trimmedDebounced,
|
|
5031
|
+
minQueryLength,
|
|
5032
|
+
options,
|
|
5033
|
+
remoteItems,
|
|
5034
|
+
getOptionValue,
|
|
5035
|
+
getOptionLabel,
|
|
5036
|
+
getOptionKeywords,
|
|
5037
|
+
queryForFilter,
|
|
5038
|
+
pinnedValueSet
|
|
5039
|
+
]);
|
|
5040
|
+
const closeOnSelect = keepOpenOnSelect !== void 0 ? !keepOpenOnSelect : mode === "single";
|
|
5041
|
+
const handleSelectEmpty = React6.useCallback(() => {
|
|
5042
|
+
if (mode === "single") {
|
|
5043
|
+
props.onValueChange?.(
|
|
5044
|
+
null
|
|
5045
|
+
);
|
|
5046
|
+
}
|
|
5047
|
+
if (closeOnSelect) setOpen(false);
|
|
5048
|
+
}, [mode, props, closeOnSelect, setOpen]);
|
|
5049
|
+
const handleSelectItem = React6.useCallback(
|
|
5050
|
+
(value) => {
|
|
5051
|
+
if (mode === "multiple") {
|
|
5052
|
+
const current = props.value ?? [];
|
|
5053
|
+
const onChange = props.onValueChange;
|
|
5054
|
+
const exists = current.includes(value);
|
|
5055
|
+
if (exists) {
|
|
5056
|
+
onChange?.(current.filter((v) => v !== value));
|
|
5057
|
+
} else if (maxSelected !== void 0 && current.length >= maxSelected) {
|
|
5058
|
+
return;
|
|
5059
|
+
} else {
|
|
5060
|
+
onChange?.([...current, value]);
|
|
5061
|
+
}
|
|
5062
|
+
if (closeOnSelect) setOpen(false);
|
|
5063
|
+
return;
|
|
5064
|
+
}
|
|
5065
|
+
props.onValueChange?.(
|
|
5066
|
+
value
|
|
5067
|
+
);
|
|
5068
|
+
if (closeOnSelect) setOpen(false);
|
|
5069
|
+
},
|
|
5070
|
+
[mode, props, maxSelected, closeOnSelect, setOpen]
|
|
5071
|
+
);
|
|
5072
|
+
const handleClear = React6.useCallback(
|
|
5073
|
+
(event) => {
|
|
5074
|
+
event.preventDefault();
|
|
5075
|
+
event.stopPropagation();
|
|
5076
|
+
if (mode === "multiple") {
|
|
5077
|
+
props.onValueChange?.(
|
|
5078
|
+
[]
|
|
5079
|
+
);
|
|
5080
|
+
} else {
|
|
5081
|
+
props.onValueChange?.(null);
|
|
5082
|
+
}
|
|
5083
|
+
},
|
|
5084
|
+
[mode, props]
|
|
5085
|
+
);
|
|
5086
|
+
const handleLoadMore = React6.useCallback(async () => {
|
|
5087
|
+
if (!onLoadMore || isLoadingMore) return;
|
|
5088
|
+
setIsLoadingMore(true);
|
|
5089
|
+
try {
|
|
5090
|
+
await onLoadMore();
|
|
5091
|
+
} finally {
|
|
5092
|
+
setIsLoadingMore(false);
|
|
5093
|
+
}
|
|
5094
|
+
}, [onLoadMore, isLoadingMore]);
|
|
5095
|
+
const triggerLabel = React6.useMemo(() => {
|
|
5096
|
+
if (renderValue) {
|
|
5097
|
+
if (mode === "multiple") {
|
|
5098
|
+
return renderValue(selectedItems);
|
|
5099
|
+
}
|
|
5100
|
+
return renderValue(selectedItems[0] ?? null);
|
|
5101
|
+
}
|
|
5102
|
+
if (mode === "multiple") {
|
|
5103
|
+
const count = selectedValues.size;
|
|
5104
|
+
if (count === 0) {
|
|
5105
|
+
return /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: labels.placeholder });
|
|
5106
|
+
}
|
|
5107
|
+
if (selectedItems.length === 1) {
|
|
5108
|
+
return getOptionLabel(selectedItems[0]);
|
|
5109
|
+
}
|
|
5110
|
+
return labels.selectedCount(count);
|
|
5111
|
+
}
|
|
5112
|
+
if (selectedValues.size === 0) {
|
|
5113
|
+
return /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: allowEmpty ? resolvedEmptyLabel : labels.placeholder });
|
|
5114
|
+
}
|
|
5115
|
+
if (selectedItems[0]) {
|
|
5116
|
+
return getOptionLabel(selectedItems[0]);
|
|
5117
|
+
}
|
|
5118
|
+
const only = [...selectedValues][0];
|
|
5119
|
+
return only ?? labels.placeholder;
|
|
5120
|
+
}, [
|
|
5121
|
+
renderValue,
|
|
5122
|
+
mode,
|
|
5123
|
+
selectedItems,
|
|
5124
|
+
selectedValues,
|
|
5125
|
+
labels,
|
|
5126
|
+
getOptionLabel,
|
|
5127
|
+
allowEmpty,
|
|
5128
|
+
resolvedEmptyLabel
|
|
5129
|
+
]);
|
|
5130
|
+
const showClear = clearable && !disabled && (mode === "multiple" ? selectedValues.size > 0 : selectedValues.size > 0);
|
|
5131
|
+
const list = /* @__PURE__ */ jsxRuntime.jsx(
|
|
5132
|
+
SearchablePickerList,
|
|
5133
|
+
{
|
|
5134
|
+
query,
|
|
5135
|
+
onQueryChange: setQuery,
|
|
5136
|
+
labels,
|
|
5137
|
+
isLoading,
|
|
5138
|
+
hasError,
|
|
5139
|
+
recommended,
|
|
5140
|
+
recent,
|
|
5141
|
+
results,
|
|
5142
|
+
selectedValues,
|
|
5143
|
+
mode,
|
|
5144
|
+
allowEmpty,
|
|
5145
|
+
emptyLabel: resolvedEmptyLabel,
|
|
5146
|
+
onSelectEmpty: handleSelectEmpty,
|
|
5147
|
+
onSelectItem: handleSelectItem,
|
|
5148
|
+
renderOption,
|
|
5149
|
+
createOption,
|
|
5150
|
+
onLoadMore: onLoadMore ? handleLoadMore : void 0,
|
|
5151
|
+
hasMore,
|
|
5152
|
+
isLoadingMore,
|
|
5153
|
+
listClassName: isMobile ? "max-h-[min(50vh,360px)]" : "max-h-72"
|
|
5154
|
+
}
|
|
5155
|
+
);
|
|
5156
|
+
const triggerButton = /* @__PURE__ */ jsxRuntime.jsxs(
|
|
5157
|
+
Button,
|
|
5158
|
+
{
|
|
5159
|
+
type: "button",
|
|
5160
|
+
variant: "outline",
|
|
5161
|
+
role: "combobox",
|
|
5162
|
+
id: triggerId,
|
|
5163
|
+
"aria-expanded": open,
|
|
5164
|
+
"aria-labelledby": ariaLabelledBy,
|
|
5165
|
+
"aria-label": ariaLabel ?? labels.placeholder,
|
|
5166
|
+
disabled,
|
|
5167
|
+
className: cn("w-full justify-between font-normal", triggerClassName2),
|
|
5168
|
+
children: [
|
|
5169
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 flex-1 truncate text-left", children: triggerLabel }),
|
|
5170
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronsUpDown, { className: "ml-2 size-4 shrink-0 opacity-50", "aria-hidden": true })
|
|
5171
|
+
]
|
|
5172
|
+
}
|
|
5173
|
+
);
|
|
5174
|
+
const clearButton = showClear ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
5175
|
+
Button,
|
|
5176
|
+
{
|
|
5177
|
+
type: "button",
|
|
5178
|
+
variant: "ghost",
|
|
5179
|
+
size: "icon-sm",
|
|
5180
|
+
"aria-label": labels.clear,
|
|
5181
|
+
disabled,
|
|
5182
|
+
className: "shrink-0",
|
|
5183
|
+
onClick: handleClear,
|
|
5184
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "size-4" })
|
|
5185
|
+
}
|
|
5186
|
+
) : null;
|
|
5187
|
+
if (isMobile) {
|
|
5188
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex w-full items-center gap-1", className), children: [
|
|
5189
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5190
|
+
"div",
|
|
5191
|
+
{
|
|
5192
|
+
className: "min-w-0 flex-1",
|
|
5193
|
+
onClick: () => {
|
|
5194
|
+
if (!disabled) setOpen(true);
|
|
5195
|
+
},
|
|
5196
|
+
children: triggerButton
|
|
5197
|
+
}
|
|
5198
|
+
),
|
|
5199
|
+
clearButton,
|
|
5200
|
+
/* @__PURE__ */ jsxRuntime.jsx(Drawer, { open, onOpenChange: setOpen, children: /* @__PURE__ */ jsxRuntime.jsxs(DrawerContent, { className: "max-h-[90vh]", children: [
|
|
5201
|
+
/* @__PURE__ */ jsxRuntime.jsx(DrawerHeader, { className: "text-left", children: /* @__PURE__ */ jsxRuntime.jsx(DrawerTitle, { children: labels.dialogTitle }) }),
|
|
5202
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "min-h-0 flex-1 overflow-hidden px-2 pb-2", children: list }),
|
|
5203
|
+
mode === "multiple" ? /* @__PURE__ */ jsxRuntime.jsxs(DrawerFooter, { className: "flex-row gap-2", children: [
|
|
5204
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5205
|
+
Button,
|
|
5206
|
+
{
|
|
5207
|
+
type: "button",
|
|
5208
|
+
variant: "outline",
|
|
5209
|
+
className: "flex-1",
|
|
5210
|
+
onClick: () => setOpen(false),
|
|
5211
|
+
children: labels.cancel
|
|
5212
|
+
}
|
|
5213
|
+
),
|
|
5214
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5215
|
+
Button,
|
|
5216
|
+
{
|
|
5217
|
+
type: "button",
|
|
5218
|
+
className: "flex-1",
|
|
5219
|
+
onClick: () => setOpen(false),
|
|
5220
|
+
children: labels.done
|
|
5221
|
+
}
|
|
5222
|
+
)
|
|
5223
|
+
] }) : null
|
|
5224
|
+
] }) })
|
|
5225
|
+
] });
|
|
5226
|
+
}
|
|
5227
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex w-full items-center gap-1", className), children: [
|
|
5228
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "min-w-0 flex-1", children: /* @__PURE__ */ jsxRuntime.jsxs(Popover, { open, onOpenChange: setOpen, modal: true, children: [
|
|
5229
|
+
/* @__PURE__ */ jsxRuntime.jsx(PopoverTrigger, { asChild: true, children: triggerButton }),
|
|
5230
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5231
|
+
PopoverContent,
|
|
5232
|
+
{
|
|
5233
|
+
className: "w-[var(--radix-popover-trigger-width)] min-w-[240px] p-0",
|
|
5234
|
+
align: "start",
|
|
5235
|
+
children: list
|
|
5236
|
+
}
|
|
5237
|
+
)
|
|
5238
|
+
] }) }),
|
|
5239
|
+
clearButton
|
|
5240
|
+
] });
|
|
5241
|
+
}
|
|
5242
|
+
var defaultLabels4 = {
|
|
4518
5243
|
placeholder: "Buscar en toda la plataforma\u2026",
|
|
4519
5244
|
dialogTitle: "Buscar",
|
|
4520
5245
|
dialogDescription: "Busca funcionalidades, eventos, documentos y m\xE1s",
|
|
@@ -4548,7 +5273,7 @@ function SearchCommand({
|
|
|
4548
5273
|
debounceMs = 200,
|
|
4549
5274
|
className
|
|
4550
5275
|
}) {
|
|
4551
|
-
const labels = { ...
|
|
5276
|
+
const labels = { ...defaultLabels4, ...userLabels };
|
|
4552
5277
|
const [query, setQuery] = React6.useState("");
|
|
4553
5278
|
const [hits, setHits] = React6.useState([]);
|
|
4554
5279
|
const [isLoading, setIsLoading] = React6.useState(false);
|
|
@@ -5429,18 +6154,6 @@ function ChatMessageList({
|
|
|
5429
6154
|
/* @__PURE__ */ jsxRuntime.jsx(MessageScrollerButton, {})
|
|
5430
6155
|
] }) });
|
|
5431
6156
|
}
|
|
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
6157
|
var RECONNECT_DELAY_MS = 2e3;
|
|
5445
6158
|
function useSupportConversation({
|
|
5446
6159
|
client,
|
|
@@ -6117,6 +6830,7 @@ exports.MexicoMap = MexicoMap;
|
|
|
6117
6830
|
exports.OrgSwitcher = OrgSwitcher;
|
|
6118
6831
|
exports.PhoneInput = PhoneInput;
|
|
6119
6832
|
exports.SearchCommand = SearchCommand;
|
|
6833
|
+
exports.SearchablePicker = SearchablePicker;
|
|
6120
6834
|
exports.SupportMessengerProvider = SupportMessengerProvider;
|
|
6121
6835
|
exports.ThemeSwitcher = ThemeSwitcher;
|
|
6122
6836
|
exports.VerifiedProfessionalBadge = VerifiedProfessionalBadge;
|
|
@@ -6140,6 +6854,7 @@ exports.useDebouncedValue = useDebouncedValue;
|
|
|
6140
6854
|
exports.useDebouncedValueStrict = useDebouncedValueStrict;
|
|
6141
6855
|
exports.useHlsPlayback = useHlsPlayback;
|
|
6142
6856
|
exports.useLanguageContext = useLanguageContext;
|
|
6857
|
+
exports.useMediaQuery = useMediaQuery2;
|
|
6143
6858
|
exports.usePlaybackStats = usePlaybackStats;
|
|
6144
6859
|
exports.useSearchHotkey = useSearchHotkey;
|
|
6145
6860
|
exports.useSupportConversation = useSupportConversation;
|