lecom-ui 5.4.45 → 5.4.47
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/components/Combobox/Combobox.js +115 -56
- package/dist/components/CustomTagInput/CustomTagInput.js +5 -1
- package/dist/components/Dialog/Dialog.js +2 -2
- package/dist/components/MultiSelect/MultiSelect.js +16 -13
- package/dist/components/Tooltip/Tooltip.js +3 -3
- package/dist/hooks/useDynamicMaxHeight.js +92 -22
- package/dist/index.d.ts +5 -2
- package/dist/style.min.css +1 -1
- package/package.json +134 -134
|
@@ -57,7 +57,7 @@ const getFontVariant = (size) => {
|
|
|
57
57
|
return sizeMap[size ?? "medium"];
|
|
58
58
|
};
|
|
59
59
|
const comboboxItemVariants = cva(
|
|
60
|
-
"text-grey-800 flex items-center justify-start gap-2 hover:bg-grey-50 hover:cursor-pointer py-1 w-full",
|
|
60
|
+
"text-grey-800 flex items-center justify-start gap-2 hover:bg-grey-50 hover:cursor-pointer py-1 w-full min-w-0",
|
|
61
61
|
{
|
|
62
62
|
variants: {
|
|
63
63
|
size: {
|
|
@@ -140,7 +140,7 @@ const ComboboxItemContent = ({
|
|
|
140
140
|
variant: fontVariant,
|
|
141
141
|
className: cn(
|
|
142
142
|
textColor,
|
|
143
|
-
"whitespace-normal
|
|
143
|
+
"whitespace-normal min-w-0 break-words"
|
|
144
144
|
)
|
|
145
145
|
},
|
|
146
146
|
option.label
|
|
@@ -394,6 +394,84 @@ const ComboboxTriggerButton = React.forwardRef(
|
|
|
394
394
|
}
|
|
395
395
|
);
|
|
396
396
|
ComboboxTriggerButton.displayName = "ComboboxTriggerButton";
|
|
397
|
+
function ComboboxPopoverContent({
|
|
398
|
+
dynamicHeightRef,
|
|
399
|
+
dynamicHeightStyle,
|
|
400
|
+
contentClassName,
|
|
401
|
+
side,
|
|
402
|
+
preferredSide,
|
|
403
|
+
dynamicHeight,
|
|
404
|
+
showSearch,
|
|
405
|
+
searchTerm,
|
|
406
|
+
t,
|
|
407
|
+
size,
|
|
408
|
+
search,
|
|
409
|
+
setSearch,
|
|
410
|
+
commandListRef,
|
|
411
|
+
showCreateOption,
|
|
412
|
+
onCreateOption,
|
|
413
|
+
handleClose,
|
|
414
|
+
notFoundContent,
|
|
415
|
+
filteredOptions,
|
|
416
|
+
value,
|
|
417
|
+
onChange,
|
|
418
|
+
itemsClassName,
|
|
419
|
+
matchTriggerWidth
|
|
420
|
+
}) {
|
|
421
|
+
return /* @__PURE__ */ React.createElement(
|
|
422
|
+
PopoverContent,
|
|
423
|
+
{
|
|
424
|
+
ref: dynamicHeightRef,
|
|
425
|
+
style: dynamicHeightStyle,
|
|
426
|
+
className: cn(
|
|
427
|
+
" pt-0 px-1 pb-1 flex flex-col",
|
|
428
|
+
matchTriggerWidth && "w-[var(--radix-popover-trigger-width)]",
|
|
429
|
+
contentClassName
|
|
430
|
+
),
|
|
431
|
+
side: side ?? (dynamicHeight ? preferredSide : "bottom"),
|
|
432
|
+
avoidCollisions: true,
|
|
433
|
+
onWheel: (e) => e.stopPropagation()
|
|
434
|
+
},
|
|
435
|
+
/* @__PURE__ */ React.createElement(Command, { shouldFilter: false, className: cn(SEARCH_INPUT_CLASSES[size], "max-h-full flex flex-col") }, showSearch && /* @__PURE__ */ React.createElement(
|
|
436
|
+
CommandInput,
|
|
437
|
+
{
|
|
438
|
+
placeholder: searchTerm || t("multiSelect.search"),
|
|
439
|
+
value: search,
|
|
440
|
+
onValueChange: setSearch
|
|
441
|
+
}
|
|
442
|
+
), /* @__PURE__ */ React.createElement(
|
|
443
|
+
CommandList,
|
|
444
|
+
{
|
|
445
|
+
ref: commandListRef,
|
|
446
|
+
key: search,
|
|
447
|
+
className: cn(
|
|
448
|
+
"flex-1 overflow-y-auto overflow-x-hidden",
|
|
449
|
+
"[&::-webkit-scrollbar]:w-1.5",
|
|
450
|
+
"[&::-webkit-scrollbar-track]:bg-transparent",
|
|
451
|
+
"[&::-webkit-scrollbar-thumb]:bg-grey-300",
|
|
452
|
+
"[&::-webkit-scrollbar-thumb]:rounded-full",
|
|
453
|
+
"[&::-webkit-scrollbar-thumb]:hover:bg-grey-400",
|
|
454
|
+
dynamicHeight ? "max-h-none" : "max-h-44"
|
|
455
|
+
)
|
|
456
|
+
},
|
|
457
|
+
/* @__PURE__ */ React.createElement(
|
|
458
|
+
ComboboxContent,
|
|
459
|
+
{
|
|
460
|
+
showCreateOption,
|
|
461
|
+
search,
|
|
462
|
+
onCreateOption,
|
|
463
|
+
onClose: handleClose,
|
|
464
|
+
size,
|
|
465
|
+
notFoundContent,
|
|
466
|
+
filteredOptions,
|
|
467
|
+
value,
|
|
468
|
+
onChange,
|
|
469
|
+
itemsClassName
|
|
470
|
+
}
|
|
471
|
+
)
|
|
472
|
+
))
|
|
473
|
+
);
|
|
474
|
+
}
|
|
397
475
|
function Combobox({
|
|
398
476
|
options,
|
|
399
477
|
value,
|
|
@@ -411,18 +489,23 @@ function Combobox({
|
|
|
411
489
|
size = "medium",
|
|
412
490
|
allowCreate = false,
|
|
413
491
|
onCreateOption,
|
|
492
|
+
matchTriggerWidth = true,
|
|
493
|
+
modalPopover = false,
|
|
494
|
+
side,
|
|
414
495
|
dynamicHeight = true,
|
|
415
|
-
dynamicHeightBottomPadding
|
|
416
|
-
dynamicHeightMinHeight
|
|
496
|
+
dynamicHeightBottomPadding,
|
|
497
|
+
dynamicHeightMinHeight
|
|
417
498
|
}) {
|
|
418
499
|
const { t } = useTranslation();
|
|
419
500
|
const [open, setOpen] = React.useState(false);
|
|
420
501
|
const [search, setSearch] = React.useState("");
|
|
421
502
|
const commandListRef = React.useRef(null);
|
|
422
|
-
const
|
|
503
|
+
const triggerRef = React.useRef(null);
|
|
504
|
+
const { ref: dynamicHeightRef, style: dynamicHeightStyle, preferredSide } = useDynamicMaxHeight({
|
|
423
505
|
enabled: open && dynamicHeight,
|
|
424
506
|
bottomPadding: dynamicHeightBottomPadding,
|
|
425
|
-
minHeight: dynamicHeightMinHeight
|
|
507
|
+
minHeight: dynamicHeightMinHeight,
|
|
508
|
+
triggerRef
|
|
426
509
|
});
|
|
427
510
|
const lastOpenOptionsRef = React.useRef(options);
|
|
428
511
|
React.useEffect(() => {
|
|
@@ -451,9 +534,10 @@ function Combobox({
|
|
|
451
534
|
}
|
|
452
535
|
}, []);
|
|
453
536
|
useComboboxScrollToSelected(open, value, commandListRef);
|
|
454
|
-
return /* @__PURE__ */ React.createElement(Popover, { open, onOpenChange: handleOpenChange }, /* @__PURE__ */ React.createElement(PopoverTrigger, { asChild: true }, /* @__PURE__ */ React.createElement(
|
|
537
|
+
return /* @__PURE__ */ React.createElement(Popover, { open, onOpenChange: handleOpenChange, modal: modalPopover }, /* @__PURE__ */ React.createElement(PopoverTrigger, { asChild: true }, /* @__PURE__ */ React.createElement(
|
|
455
538
|
ComboboxTriggerButton,
|
|
456
539
|
{
|
|
540
|
+
ref: triggerRef,
|
|
457
541
|
open,
|
|
458
542
|
disabled,
|
|
459
543
|
value,
|
|
@@ -465,56 +549,31 @@ function Combobox({
|
|
|
465
549
|
size
|
|
466
550
|
}
|
|
467
551
|
)), /* @__PURE__ */ React.createElement(
|
|
468
|
-
|
|
552
|
+
ComboboxPopoverContent,
|
|
469
553
|
{
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
"overflow-y-auto overflow-x-hidden",
|
|
494
|
-
"[&::-webkit-scrollbar]:w-1.5",
|
|
495
|
-
"[&::-webkit-scrollbar-track]:bg-transparent",
|
|
496
|
-
"[&::-webkit-scrollbar-thumb]:bg-grey-300",
|
|
497
|
-
"[&::-webkit-scrollbar-thumb]:rounded-full",
|
|
498
|
-
"[&::-webkit-scrollbar-thumb]:hover:bg-grey-400",
|
|
499
|
-
contentClassName
|
|
500
|
-
)
|
|
501
|
-
},
|
|
502
|
-
/* @__PURE__ */ React.createElement(CommandList, { className: "overflow-visible" }, /* @__PURE__ */ React.createElement(
|
|
503
|
-
ComboboxContent,
|
|
504
|
-
{
|
|
505
|
-
showCreateOption,
|
|
506
|
-
search,
|
|
507
|
-
onCreateOption,
|
|
508
|
-
onClose: handleClose,
|
|
509
|
-
size,
|
|
510
|
-
notFoundContent,
|
|
511
|
-
filteredOptions,
|
|
512
|
-
value,
|
|
513
|
-
onChange,
|
|
514
|
-
itemsClassName
|
|
515
|
-
}
|
|
516
|
-
))
|
|
517
|
-
))
|
|
554
|
+
dynamicHeightRef,
|
|
555
|
+
dynamicHeightStyle,
|
|
556
|
+
contentClassName,
|
|
557
|
+
side,
|
|
558
|
+
preferredSide,
|
|
559
|
+
dynamicHeight,
|
|
560
|
+
showSearch,
|
|
561
|
+
searchTerm,
|
|
562
|
+
t,
|
|
563
|
+
size,
|
|
564
|
+
search,
|
|
565
|
+
setSearch,
|
|
566
|
+
commandListRef,
|
|
567
|
+
showCreateOption,
|
|
568
|
+
onCreateOption,
|
|
569
|
+
handleClose,
|
|
570
|
+
notFoundContent,
|
|
571
|
+
filteredOptions,
|
|
572
|
+
value,
|
|
573
|
+
onChange,
|
|
574
|
+
itemsClassName,
|
|
575
|
+
matchTriggerWidth
|
|
576
|
+
}
|
|
518
577
|
));
|
|
519
578
|
}
|
|
520
579
|
|
|
@@ -54,6 +54,10 @@ const CustomTagItemComponent = React.memo(function CustomTagItemComponent2({
|
|
|
54
54
|
}, [editValue, item.id, item.label, onEdit]);
|
|
55
55
|
const handleKeyDown = React.useCallback(
|
|
56
56
|
(e) => {
|
|
57
|
+
if (e.key === ";") {
|
|
58
|
+
e.preventDefault();
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
57
61
|
if (e.key === "Enter") {
|
|
58
62
|
e.preventDefault();
|
|
59
63
|
handleSave();
|
|
@@ -90,7 +94,7 @@ const CustomTagItemComponent = React.memo(function CustomTagItemComponent2({
|
|
|
90
94
|
type: "text",
|
|
91
95
|
value: editValue,
|
|
92
96
|
onChange: (e) => {
|
|
93
|
-
let newValue = e.target.value;
|
|
97
|
+
let newValue = e.target.value.replace(/;/g, "");
|
|
94
98
|
if (maxEditLength !== void 0 && newValue.length > maxEditLength) {
|
|
95
99
|
newValue = newValue.slice(0, maxEditLength);
|
|
96
100
|
}
|
|
@@ -13,7 +13,7 @@ const DialogOverlay = React.forwardRef(({ className, ...props }, ref) => /* @__P
|
|
|
13
13
|
{
|
|
14
14
|
ref,
|
|
15
15
|
className: cn(
|
|
16
|
-
"fixed inset-0 z-
|
|
16
|
+
"fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
|
|
17
17
|
className
|
|
18
18
|
),
|
|
19
19
|
...props
|
|
@@ -25,7 +25,7 @@ const DialogContent = React.forwardRef(({ className, children, noClose, ...props
|
|
|
25
25
|
{
|
|
26
26
|
ref,
|
|
27
27
|
className: cn(
|
|
28
|
-
"fixed left-[50%] top-[50%] z-
|
|
28
|
+
"fixed left-[50%] top-[50%] z-50 flex flex-col w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-6 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg max-sm:h-full",
|
|
29
29
|
className
|
|
30
30
|
),
|
|
31
31
|
...props
|
|
@@ -47,7 +47,7 @@ const MultiSelect = React.forwardRef(
|
|
|
47
47
|
maxCount,
|
|
48
48
|
modalPopover = false,
|
|
49
49
|
className,
|
|
50
|
-
side
|
|
50
|
+
side,
|
|
51
51
|
treeOptions,
|
|
52
52
|
treeSelectionStrategy = "leaf",
|
|
53
53
|
selectAllLabel,
|
|
@@ -66,8 +66,8 @@ const MultiSelect = React.forwardRef(
|
|
|
66
66
|
readOnly = false,
|
|
67
67
|
status = "default",
|
|
68
68
|
dynamicHeight = true,
|
|
69
|
-
dynamicHeightBottomPadding
|
|
70
|
-
dynamicHeightMinHeight
|
|
69
|
+
dynamicHeightBottomPadding,
|
|
70
|
+
dynamicHeightMinHeight
|
|
71
71
|
}, ref) => {
|
|
72
72
|
const { t } = useTranslation();
|
|
73
73
|
const [selectedValues, setSelectedValues] = React.useState(value);
|
|
@@ -77,10 +77,11 @@ const MultiSelect = React.forwardRef(
|
|
|
77
77
|
selectedValues.length || 1
|
|
78
78
|
);
|
|
79
79
|
const buttonRef = React.useRef(null);
|
|
80
|
-
const { ref: dynamicHeightRef, style: dynamicHeightStyle } = useDynamicMaxHeight({
|
|
80
|
+
const { ref: dynamicHeightRef, style: dynamicHeightStyle, preferredSide } = useDynamicMaxHeight({
|
|
81
81
|
enabled: dynamicHeight && isPopoverOpen,
|
|
82
82
|
bottomPadding: dynamicHeightBottomPadding,
|
|
83
|
-
minHeight: dynamicHeightMinHeight
|
|
83
|
+
minHeight: dynamicHeightMinHeight,
|
|
84
|
+
triggerRef: buttonRef
|
|
84
85
|
});
|
|
85
86
|
React.useEffect(() => {
|
|
86
87
|
const shallowEqual = (a, b) => {
|
|
@@ -638,19 +639,21 @@ const MultiSelect = React.forwardRef(
|
|
|
638
639
|
ref: dynamicHeightRef,
|
|
639
640
|
style: dynamicHeightStyle,
|
|
640
641
|
className: cn(
|
|
641
|
-
"p-0 flex flex-col",
|
|
642
|
+
"p-0 flex flex-col overflow-hidden",
|
|
642
643
|
matchTriggerWidth && "w-[var(--radix-popover-trigger-width)]",
|
|
644
|
+
!dynamicHeight && "max-h-80",
|
|
643
645
|
classNameContent
|
|
644
646
|
),
|
|
645
|
-
side,
|
|
647
|
+
side: side ?? (dynamicHeight ? preferredSide : "bottom"),
|
|
646
648
|
align: "start",
|
|
649
|
+
avoidCollisions: true,
|
|
647
650
|
onEscapeKeyDown: () => setIsPopoverOpen(false)
|
|
648
651
|
},
|
|
649
652
|
!isTree && /* @__PURE__ */ React.createElement(
|
|
650
653
|
Command,
|
|
651
654
|
{
|
|
652
655
|
shouldFilter: false,
|
|
653
|
-
className: SEARCH_INPUT_CLASSES[size]
|
|
656
|
+
className: cn("max-h-full flex flex-col", SEARCH_INPUT_CLASSES[size])
|
|
654
657
|
},
|
|
655
658
|
/* @__PURE__ */ React.createElement(
|
|
656
659
|
CommandInput,
|
|
@@ -665,7 +668,7 @@ const MultiSelect = React.forwardRef(
|
|
|
665
668
|
/* @__PURE__ */ React.createElement(
|
|
666
669
|
CommandList,
|
|
667
670
|
{
|
|
668
|
-
className: "[&::-webkit-scrollbar]:w-1.5 [&::-webkit-scrollbar-track]:bg-transparent [&::-webkit-scrollbar-thumb]:bg-grey-300 [&::-webkit-scrollbar-thumb]:rounded-full [&::-webkit-scrollbar-thumb:hover]:bg-grey-400"
|
|
671
|
+
className: cn("flex-1 [&::-webkit-scrollbar]:w-1.5 [&::-webkit-scrollbar-track]:bg-transparent [&::-webkit-scrollbar-thumb]:bg-grey-300 [&::-webkit-scrollbar-thumb]:rounded-full [&::-webkit-scrollbar-thumb:hover]:bg-grey-400", dynamicHeight && "max-h-none")
|
|
669
672
|
},
|
|
670
673
|
/* @__PURE__ */ React.createElement(CommandGroup, null, (effectiveOptions.length === 0 || query && filteredOptions.length === 0) && /* @__PURE__ */ React.createElement(
|
|
671
674
|
CommandEmpty,
|
|
@@ -756,11 +759,11 @@ const MultiSelect = React.forwardRef(
|
|
|
756
759
|
}
|
|
757
760
|
)
|
|
758
761
|
),
|
|
759
|
-
/* @__PURE__ */ React.createElement("div", { className: "flex items-center gap-2
|
|
762
|
+
/* @__PURE__ */ React.createElement("div", { className: "flex items-center gap-2 min-w-0" }, option.prefix && /* @__PURE__ */ React.createElement(Typography, { className: "flex items-center flex-shrink-0" }, option.prefix), /* @__PURE__ */ React.createElement(
|
|
760
763
|
Typography,
|
|
761
764
|
{
|
|
762
765
|
variant: getFontVariant(size),
|
|
763
|
-
className: "text-grey-800 break-words"
|
|
766
|
+
className: "text-grey-800 whitespace-normal min-w-0 break-words"
|
|
764
767
|
},
|
|
765
768
|
highlight(option.label, query)
|
|
766
769
|
))
|
|
@@ -801,7 +804,7 @@ const MultiSelect = React.forwardRef(
|
|
|
801
804
|
Typography,
|
|
802
805
|
{
|
|
803
806
|
variant: getFontVariant(size),
|
|
804
|
-
className: "text-grey-800 break-words"
|
|
807
|
+
className: "text-grey-800 whitespace-normal min-w-0 break-words"
|
|
805
808
|
},
|
|
806
809
|
highlight(option.label, query)
|
|
807
810
|
))
|
|
@@ -809,7 +812,7 @@ const MultiSelect = React.forwardRef(
|
|
|
809
812
|
}))
|
|
810
813
|
)
|
|
811
814
|
),
|
|
812
|
-
isTree && /* @__PURE__ */ React.createElement("div", { className: "min-w-[260px] overflow-hidden flex flex-col" }, treeSearch && /* @__PURE__ */ React.createElement("div", { className: "px-1 pt-2 pb-0 border-b border-grey-300 flex-shrink-0" }, /* @__PURE__ */ React.createElement("div", { className: "relative" }, /* @__PURE__ */ React.createElement(
|
|
815
|
+
isTree && /* @__PURE__ */ React.createElement("div", { className: cn("min-w-[260px] overflow-hidden flex flex-col flex-1", dynamicHeight ? "max-h-full" : "max-h-80") }, treeSearch && /* @__PURE__ */ React.createElement("div", { className: "px-1 pt-2 pb-0 border-b border-grey-300 flex-shrink-0" }, /* @__PURE__ */ React.createElement("div", { className: "relative" }, /* @__PURE__ */ React.createElement(
|
|
813
816
|
"svg",
|
|
814
817
|
{
|
|
815
818
|
className: "absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground",
|
|
@@ -9,7 +9,7 @@ const TooltipTrigger = TooltipPrimitive.Trigger;
|
|
|
9
9
|
const TooltipArrow = TooltipPrimitive.Arrow;
|
|
10
10
|
const TooltipPortal = TooltipPrimitive.Portal;
|
|
11
11
|
const tooltipContentVariants = cva(
|
|
12
|
-
"z-
|
|
12
|
+
"z-[100] overflow-hidden rounded-lg px-3 py-2 max-w-80 body-small-500 shadow-md animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
|
|
13
13
|
{
|
|
14
14
|
variants: {
|
|
15
15
|
color: {
|
|
@@ -45,7 +45,7 @@ const TooltipContent = React.forwardRef(
|
|
|
45
45
|
className,
|
|
46
46
|
children,
|
|
47
47
|
...props
|
|
48
|
-
}, ref) => /* @__PURE__ */ React.createElement(
|
|
48
|
+
}, ref) => /* @__PURE__ */ React.createElement(TooltipPortal, null, /* @__PURE__ */ React.createElement(
|
|
49
49
|
TooltipPrimitive.Content,
|
|
50
50
|
{
|
|
51
51
|
ref,
|
|
@@ -58,7 +58,7 @@ const TooltipContent = React.forwardRef(
|
|
|
58
58
|
},
|
|
59
59
|
children,
|
|
60
60
|
arrow && /* @__PURE__ */ React.createElement(TooltipArrow, { className: "tooltip-arrow", width: 12, height: 6 })
|
|
61
|
-
)
|
|
61
|
+
))
|
|
62
62
|
);
|
|
63
63
|
TooltipContent.displayName = TooltipPrimitive.Content.displayName;
|
|
64
64
|
|
|
@@ -1,49 +1,119 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
|
|
3
|
-
const DEFAULT_BOTTOM_PADDING =
|
|
3
|
+
const DEFAULT_BOTTOM_PADDING = 25;
|
|
4
4
|
const DEFAULT_MIN_HEIGHT = 120;
|
|
5
|
+
function findDialogContainer(element) {
|
|
6
|
+
if (!element) return null;
|
|
7
|
+
let current = element;
|
|
8
|
+
while (current) {
|
|
9
|
+
if (current.hasAttribute("data-radix-dialog-content")) {
|
|
10
|
+
return current;
|
|
11
|
+
}
|
|
12
|
+
if (current.getAttribute("role") === "dialog") {
|
|
13
|
+
const isInsidePopover = current.closest("[data-radix-popper-content-wrapper]");
|
|
14
|
+
if (!isInsidePopover) {
|
|
15
|
+
return current;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
if (current.classList.contains("dialog-content") || current.classList.contains("modal-content")) {
|
|
19
|
+
return current;
|
|
20
|
+
}
|
|
21
|
+
current = current.parentElement;
|
|
22
|
+
}
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
5
25
|
function useDynamicMaxHeight(options = {}) {
|
|
6
26
|
const {
|
|
7
27
|
enabled = false,
|
|
8
28
|
bottomPadding = DEFAULT_BOTTOM_PADDING,
|
|
9
|
-
minHeight = DEFAULT_MIN_HEIGHT
|
|
29
|
+
minHeight = DEFAULT_MIN_HEIGHT,
|
|
30
|
+
triggerRef,
|
|
31
|
+
detectDialogContainer = true
|
|
10
32
|
} = options;
|
|
33
|
+
const minHeightToFlip = minHeight ?? DEFAULT_MIN_HEIGHT;
|
|
11
34
|
const ref = React.useRef(null);
|
|
12
35
|
const [maxHeight, setMaxHeight] = React.useState(
|
|
13
36
|
void 0
|
|
14
37
|
);
|
|
38
|
+
const [preferredSide, setPreferredSide] = React.useState("bottom");
|
|
39
|
+
const [isInsideDialog, setIsInsideDialog] = React.useState(false);
|
|
15
40
|
const lastCalculatedHeight = React.useRef(void 0);
|
|
16
|
-
React.
|
|
17
|
-
|
|
18
|
-
|
|
41
|
+
const cachedDialogRef = React.useRef(null);
|
|
42
|
+
const initialHeightRef = React.useRef(void 0);
|
|
43
|
+
const calculateHeight = React.useCallback(() => {
|
|
44
|
+
const triggerElement = triggerRef?.current;
|
|
45
|
+
if (!triggerElement) return;
|
|
46
|
+
let dialogElement = null;
|
|
47
|
+
if (detectDialogContainer) {
|
|
48
|
+
if (!cachedDialogRef.current) {
|
|
49
|
+
cachedDialogRef.current = findDialogContainer(triggerElement);
|
|
50
|
+
}
|
|
51
|
+
dialogElement = cachedDialogRef.current;
|
|
52
|
+
}
|
|
53
|
+
const triggerRect = triggerElement.getBoundingClientRect();
|
|
54
|
+
let boundaryTop;
|
|
55
|
+
let boundaryBottom;
|
|
56
|
+
let boundaryHeight;
|
|
57
|
+
if (dialogElement) {
|
|
58
|
+
const containerRect = dialogElement.getBoundingClientRect();
|
|
59
|
+
const dialogPadding = 24;
|
|
60
|
+
boundaryTop = containerRect.top + dialogPadding;
|
|
61
|
+
boundaryBottom = containerRect.bottom - dialogPadding;
|
|
62
|
+
boundaryHeight = boundaryBottom - boundaryTop;
|
|
63
|
+
} else {
|
|
64
|
+
boundaryTop = 0;
|
|
65
|
+
boundaryBottom = window.innerHeight;
|
|
66
|
+
boundaryHeight = window.innerHeight;
|
|
19
67
|
}
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
68
|
+
const triggerBottom = triggerRect.bottom;
|
|
69
|
+
const triggerTop = triggerRect.top;
|
|
70
|
+
const insideDialog = !!dialogElement;
|
|
71
|
+
setIsInsideDialog(insideDialog);
|
|
72
|
+
const effectiveBottomPadding = insideDialog ? 0 : bottomPadding;
|
|
73
|
+
const adjustedBottomPadding = boundaryHeight < 500 ? 10 : effectiveBottomPadding;
|
|
74
|
+
const adjustedMinBeforeFlip = insideDialog ? 0 : minHeightToFlip;
|
|
75
|
+
const spaceBelow = boundaryBottom - triggerBottom;
|
|
76
|
+
const spaceAbove = triggerTop - boundaryTop;
|
|
77
|
+
let finalHeight;
|
|
78
|
+
if (spaceBelow >= adjustedMinBeforeFlip + adjustedBottomPadding) {
|
|
79
|
+
setPreferredSide("bottom");
|
|
80
|
+
const availableHeight = spaceBelow - adjustedBottomPadding;
|
|
81
|
+
finalHeight = Math.max(availableHeight, minHeight);
|
|
82
|
+
} else {
|
|
83
|
+
setPreferredSide("top");
|
|
84
|
+
const availableHeight = spaceAbove - adjustedBottomPadding;
|
|
85
|
+
finalHeight = Math.max(availableHeight, minHeight);
|
|
86
|
+
}
|
|
87
|
+
if (initialHeightRef.current === void 0) {
|
|
88
|
+
initialHeightRef.current = finalHeight;
|
|
27
89
|
lastCalculatedHeight.current = finalHeight;
|
|
28
90
|
setMaxHeight(finalHeight);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
|
|
91
|
+
}
|
|
92
|
+
}, [triggerRef, detectDialogContainer, bottomPadding, minHeight, minHeightToFlip]);
|
|
93
|
+
React.useLayoutEffect(() => {
|
|
94
|
+
if (!enabled) {
|
|
95
|
+
cachedDialogRef.current = null;
|
|
96
|
+
initialHeightRef.current = void 0;
|
|
97
|
+
setMaxHeight(void 0);
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
cachedDialogRef.current = null;
|
|
101
|
+
initialHeightRef.current = void 0;
|
|
102
|
+
calculateHeight();
|
|
103
|
+
const rafId = requestAnimationFrame(() => {
|
|
104
|
+
if (initialHeightRef.current === void 0) {
|
|
32
105
|
calculateHeight();
|
|
33
|
-
}
|
|
106
|
+
}
|
|
34
107
|
});
|
|
35
|
-
window.addEventListener("resize", calculateHeight);
|
|
36
|
-
window.addEventListener("scroll", calculateHeight, true);
|
|
37
108
|
return () => {
|
|
38
|
-
|
|
39
|
-
window.removeEventListener("scroll", calculateHeight, true);
|
|
109
|
+
cancelAnimationFrame(rafId);
|
|
40
110
|
};
|
|
41
|
-
}, [enabled,
|
|
111
|
+
}, [enabled, calculateHeight]);
|
|
42
112
|
const style = React.useMemo(() => {
|
|
43
113
|
if (maxHeight === void 0) return {};
|
|
44
114
|
return { maxHeight: `${maxHeight}px` };
|
|
45
115
|
}, [maxHeight]);
|
|
46
|
-
return { ref, maxHeight, style };
|
|
116
|
+
return { ref, maxHeight, style, preferredSide, isInsideDialog };
|
|
47
117
|
}
|
|
48
118
|
|
|
49
119
|
export { useDynamicMaxHeight };
|
package/dist/index.d.ts
CHANGED
|
@@ -1010,7 +1010,7 @@ declare const RadioGroup: React$1.ForwardRefExoticComponent<Omit<RadioGroupPrimi
|
|
|
1010
1010
|
declare const RadioGroupItem: React$1.ForwardRefExoticComponent<Omit<RadioGroupPrimitive.RadioGroupItemProps & React$1.RefAttributes<HTMLButtonElement>, "ref"> & React$1.RefAttributes<HTMLButtonElement>>;
|
|
1011
1011
|
|
|
1012
1012
|
declare const ResizablePanelGroup: ({ className, ...props }: React$1.ComponentProps<typeof ResizablePrimitive.PanelGroup>) => React$1.JSX.Element;
|
|
1013
|
-
declare const ResizablePanel: React$1.ForwardRefExoticComponent<Omit<React$1.HTMLAttributes<HTMLDivElement | HTMLElement | HTMLButtonElement | HTMLOListElement | HTMLLIElement | HTMLAnchorElement | HTMLSpanElement |
|
|
1013
|
+
declare const ResizablePanel: React$1.ForwardRefExoticComponent<Omit<React$1.HTMLAttributes<HTMLDivElement | HTMLElement | HTMLButtonElement | HTMLOListElement | HTMLLIElement | HTMLAnchorElement | HTMLSpanElement | HTMLLabelElement | HTMLParagraphElement | HTMLHeadingElement | HTMLInputElement | HTMLObjectElement | HTMLAreaElement | HTMLAudioElement | HTMLBaseElement | HTMLQuoteElement | HTMLBodyElement | HTMLBRElement | HTMLCanvasElement | HTMLTableCaptionElement | HTMLTableColElement | HTMLDataElement | HTMLDataListElement | HTMLModElement | HTMLDetailsElement | HTMLDialogElement | HTMLDListElement | HTMLEmbedElement | HTMLFieldSetElement | HTMLFormElement | HTMLHeadElement | HTMLHRElement | HTMLHtmlElement | HTMLIFrameElement | HTMLImageElement | HTMLLegendElement | HTMLLinkElement | HTMLMapElement | HTMLMenuElement | HTMLMetaElement | HTMLMeterElement | HTMLOptGroupElement | HTMLOptionElement | HTMLOutputElement | HTMLPictureElement | HTMLPreElement | HTMLProgressElement | HTMLScriptElement | HTMLSelectElement | HTMLSlotElement | HTMLSourceElement | HTMLStyleElement | HTMLTableElement | HTMLTableSectionElement | HTMLTableCellElement | HTMLTemplateElement | HTMLTextAreaElement | HTMLTimeElement | HTMLTitleElement | HTMLTableRowElement | HTMLTrackElement | HTMLUListElement | HTMLVideoElement>, "id" | "onResize"> & {
|
|
1014
1014
|
className?: string;
|
|
1015
1015
|
collapsedSize?: number | undefined;
|
|
1016
1016
|
collapsible?: boolean | undefined;
|
|
@@ -1251,11 +1251,14 @@ type ComboboxProps = {
|
|
|
1251
1251
|
size?: ComboboxSize;
|
|
1252
1252
|
allowCreate?: boolean;
|
|
1253
1253
|
onCreateOption?: (inputValue: string) => void;
|
|
1254
|
+
matchTriggerWidth?: boolean;
|
|
1255
|
+
modalPopover?: boolean;
|
|
1256
|
+
side?: 'top' | 'right' | 'bottom' | 'left';
|
|
1254
1257
|
dynamicHeight?: boolean;
|
|
1255
1258
|
dynamicHeightBottomPadding?: number;
|
|
1256
1259
|
dynamicHeightMinHeight?: number;
|
|
1257
1260
|
};
|
|
1258
|
-
declare function Combobox({ options, value, onChange, placeholder, disabled, notFoundContent, status, searchTerm, triggerClassName, contentClassName, itemsClassName, rounded, showSearch, size, allowCreate, onCreateOption, dynamicHeight, dynamicHeightBottomPadding, dynamicHeightMinHeight, }: ComboboxProps): React$1.JSX.Element;
|
|
1261
|
+
declare function Combobox({ options, value, onChange, placeholder, disabled, notFoundContent, status, searchTerm, triggerClassName, contentClassName, itemsClassName, rounded, showSearch, size, allowCreate, onCreateOption, matchTriggerWidth, modalPopover, side, dynamicHeight, dynamicHeightBottomPadding, dynamicHeightMinHeight, }: ComboboxProps): React$1.JSX.Element;
|
|
1259
1262
|
|
|
1260
1263
|
interface TagItem {
|
|
1261
1264
|
label: string;
|