infinity-ui-elements 1.8.12 → 1.8.13

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.js CHANGED
@@ -3442,6 +3442,208 @@ const Skeleton = React__namespace.forwardRef(({ className, containerClassName, c
3442
3442
  });
3443
3443
  Skeleton.displayName = "Skeleton";
3444
3444
 
3445
+ const selectTriggerVariants = classVarianceAuthority.cva("flex items-center gap-1 transition-all font-display font-size-100 leading-100", {
3446
+ variants: {
3447
+ size: {
3448
+ small: "px-2 text-xs",
3449
+ medium: "px-2 text-sm",
3450
+ large: "px-3 text-base",
3451
+ },
3452
+ validationState: {
3453
+ none: "",
3454
+ positive: "",
3455
+ negative: "",
3456
+ },
3457
+ isDisabled: {
3458
+ true: "opacity-60 cursor-not-allowed",
3459
+ false: "cursor-pointer hover:opacity-80",
3460
+ },
3461
+ },
3462
+ defaultVariants: {
3463
+ size: "medium",
3464
+ validationState: "none",
3465
+ isDisabled: false,
3466
+ },
3467
+ });
3468
+ const SelectTextField = React__namespace.forwardRef(({ textValue: controlledTextValue, defaultTextValue, onTextChange, selectOptions = [], selectValue: controlledSelectValue, defaultSelectValue, onSelectChange, selectPlaceholder = "Select", selectTriggerClassName, selectMenuClassName, selectMenuWidth = "auto", selectSectionHeading, selectEmptyTitle = "No options available", selectEmptyDescription = "There are no options to select from.", selectEmptyIcon, label, helperText, errorText, successText, validationState = "none", isDisabled = false, isRequired = false, isOptional = false, size = "medium", containerClassName, labelClassName, inputClassName, className, ...textFieldProps }, ref) => {
3469
+ const [uncontrolledTextValue, setUncontrolledTextValue] = React__namespace.useState(defaultTextValue || "");
3470
+ const [uncontrolledSelectValue, setUncontrolledSelectValue] = React__namespace.useState(defaultSelectValue);
3471
+ const [isSelectOpen, setIsSelectOpen] = React__namespace.useState(false);
3472
+ const [dropdownPlacement, setDropdownPlacement] = React__namespace.useState("bottom");
3473
+ const selectRef = React__namespace.useRef(null);
3474
+ const dropdownContainerRef = React__namespace.useRef(null);
3475
+ const componentRef = React__namespace.useRef(null);
3476
+ const textValue = controlledTextValue !== undefined
3477
+ ? controlledTextValue
3478
+ : uncontrolledTextValue;
3479
+ const selectValue = controlledSelectValue !== undefined
3480
+ ? controlledSelectValue
3481
+ : uncontrolledSelectValue;
3482
+ // Find the selected option
3483
+ const selectedOption = selectOptions.find((opt) => opt.value === selectValue);
3484
+ // Determine which helper text to show
3485
+ const displayHelperText = errorText || successText || helperText;
3486
+ const currentValidationState = errorText
3487
+ ? "negative"
3488
+ : successText
3489
+ ? "positive"
3490
+ : validationState;
3491
+ const handleTextChange = (e) => {
3492
+ const newValue = e.target.value;
3493
+ if (onTextChange) {
3494
+ onTextChange(newValue);
3495
+ }
3496
+ else {
3497
+ setUncontrolledTextValue(newValue);
3498
+ }
3499
+ };
3500
+ const handleSelectOpenChange = (newOpen) => {
3501
+ if (!isDisabled) {
3502
+ setIsSelectOpen(newOpen);
3503
+ }
3504
+ };
3505
+ const toggleSelectOpen = () => {
3506
+ handleSelectOpenChange(!isSelectOpen);
3507
+ };
3508
+ const handleSelect = (option) => {
3509
+ if (controlledSelectValue === undefined) {
3510
+ setUncontrolledSelectValue(option.value);
3511
+ }
3512
+ onSelectChange?.(option.value, option);
3513
+ setIsSelectOpen(false);
3514
+ };
3515
+ const updateDropdownPlacement = React__namespace.useCallback(() => {
3516
+ if (typeof window === "undefined")
3517
+ return;
3518
+ const trigger = selectRef.current;
3519
+ if (!trigger)
3520
+ return;
3521
+ const triggerRect = trigger.getBoundingClientRect();
3522
+ const spaceBelow = window.innerHeight - triggerRect.bottom;
3523
+ const spaceAbove = triggerRect.top;
3524
+ const dropdownHeight = dropdownContainerRef.current
3525
+ ? dropdownContainerRef.current.offsetHeight
3526
+ : 0;
3527
+ if (dropdownHeight === 0) {
3528
+ setDropdownPlacement(spaceBelow >= spaceAbove ? "bottom" : "top");
3529
+ return;
3530
+ }
3531
+ if (spaceBelow >= dropdownHeight || spaceBelow >= spaceAbove) {
3532
+ setDropdownPlacement("bottom");
3533
+ }
3534
+ else {
3535
+ setDropdownPlacement("top");
3536
+ }
3537
+ }, []);
3538
+ const attachDropdownListeners = React__namespace.useCallback(() => {
3539
+ if (!isSelectOpen)
3540
+ return;
3541
+ if (typeof window === "undefined")
3542
+ return;
3543
+ let rafId = requestAnimationFrame(updateDropdownPlacement);
3544
+ const handleUpdate = () => updateDropdownPlacement();
3545
+ window.addEventListener("resize", handleUpdate);
3546
+ window.addEventListener("scroll", handleUpdate, true);
3547
+ return () => {
3548
+ cancelAnimationFrame(rafId);
3549
+ window.removeEventListener("resize", handleUpdate);
3550
+ window.removeEventListener("scroll", handleUpdate, true);
3551
+ };
3552
+ }, [isSelectOpen, updateDropdownPlacement]);
3553
+ React__namespace.useEffect(() => {
3554
+ const detach = attachDropdownListeners();
3555
+ return () => {
3556
+ detach?.();
3557
+ };
3558
+ }, [attachDropdownListeners]);
3559
+ React__namespace.useEffect(() => {
3560
+ if (isSelectOpen) {
3561
+ updateDropdownPlacement();
3562
+ }
3563
+ }, [isSelectOpen, selectOptions.length, updateDropdownPlacement]);
3564
+ // Close dropdown when clicking outside
3565
+ React__namespace.useEffect(() => {
3566
+ const handleClickOutside = (event) => {
3567
+ const target = event.target;
3568
+ if (selectRef.current &&
3569
+ !selectRef.current.contains(target) &&
3570
+ dropdownContainerRef.current &&
3571
+ !dropdownContainerRef.current.contains(target)) {
3572
+ handleSelectOpenChange(false);
3573
+ }
3574
+ };
3575
+ if (isSelectOpen) {
3576
+ document.addEventListener("mousedown", handleClickOutside);
3577
+ return () => {
3578
+ document.removeEventListener("mousedown", handleClickOutside);
3579
+ };
3580
+ }
3581
+ }, [isSelectOpen]);
3582
+ // Close on escape key
3583
+ React__namespace.useEffect(() => {
3584
+ const handleEscape = (event) => {
3585
+ if (event.key === "Escape") {
3586
+ handleSelectOpenChange(false);
3587
+ }
3588
+ };
3589
+ if (isSelectOpen) {
3590
+ document.addEventListener("keydown", handleEscape);
3591
+ return () => {
3592
+ document.removeEventListener("keydown", handleEscape);
3593
+ };
3594
+ }
3595
+ }, [isSelectOpen]);
3596
+ // Transform options to dropdown menu items
3597
+ const menuItems = selectOptions.map((option) => ({
3598
+ value: option.value,
3599
+ label: option.label ?? String(option.value),
3600
+ description: option.description,
3601
+ leadingIcon: option.leadingIcon,
3602
+ trailingIcon: option.trailingIcon,
3603
+ isDisabled: option.isDisabled,
3604
+ variant: option.variant,
3605
+ onClick: () => handleSelect(option),
3606
+ }));
3607
+ const widthStyle = selectMenuWidth === "full"
3608
+ ? "100%"
3609
+ : selectMenuWidth === "auto"
3610
+ ? "auto"
3611
+ : selectMenuWidth;
3612
+ const sizeConfig = {
3613
+ small: {
3614
+ gap: "gap-2",
3615
+ },
3616
+ medium: {
3617
+ gap: "gap-2",
3618
+ },
3619
+ large: {
3620
+ gap: "gap-3",
3621
+ },
3622
+ };
3623
+ // Create the select suffix component
3624
+ const selectSuffix = (jsxRuntime.jsxs("div", { className: "relative flex items-center h-full", children: [jsxRuntime.jsxs("div", { ref: selectRef, className: cn(selectTriggerVariants({
3625
+ size,
3626
+ validationState: currentValidationState,
3627
+ isDisabled,
3628
+ }), "border-l border-action-outline-neutral-faded pl-2 ml-2 h-full flex items-center", selectTriggerClassName), onClick: !isDisabled ? toggleSelectOpen : undefined, role: "combobox", "aria-haspopup": "listbox", "aria-expanded": isSelectOpen, "aria-disabled": isDisabled, children: [jsxRuntime.jsx("span", { className: cn("text-left truncate max-w-[120px] whitespace-nowrap", !selectedOption && "text-surface-ink-neutral-muted", isDisabled && "text-surface-ink-neutral-disabled"), children: selectedOption?.label || selectPlaceholder }), jsxRuntime.jsx(lucideReact.ChevronDown, { className: cn("shrink-0 transition-transform", size === "small"
3629
+ ? "w-3 h-3"
3630
+ : size === "medium"
3631
+ ? "w-3.5 h-3.5"
3632
+ : "w-4 h-4", isDisabled
3633
+ ? "text-surface-ink-neutral-disabled"
3634
+ : currentValidationState === "positive"
3635
+ ? "text-feedback-ink-positive-intense"
3636
+ : currentValidationState === "negative"
3637
+ ? "text-feedback-ink-negative-subtle"
3638
+ : "text-surface-ink-neutral-muted", isSelectOpen && "transform rotate-180") })] }), isSelectOpen && !isDisabled && (jsxRuntime.jsx("div", { ref: dropdownContainerRef, className: cn("absolute z-50 right-0", dropdownPlacement === "bottom"
3639
+ ? "top-full mt-1"
3640
+ : "bottom-full mb-1"), children: jsxRuntime.jsx(DropdownMenu, { items: menuItems, sectionHeading: selectSectionHeading, isEmpty: selectOptions.length === 0, emptyTitle: selectEmptyTitle, emptyDescription: selectEmptyDescription, emptyIcon: selectEmptyIcon, disableFooter: true, onClose: () => handleSelectOpenChange(false), className: selectMenuClassName, width: widthStyle }) }))] }));
3641
+ return (jsxRuntime.jsxs("div", { ref: componentRef, className: cn("w-full flex flex-col", sizeConfig[size].gap, containerClassName), children: [label && (jsxRuntime.jsx(FormHeader, { label: label, size: size, isRequired: isRequired, isOptional: isOptional, infoHeading: textFieldProps.infoHeading, infoDescription: textFieldProps.infoDescription, LinkComponent: textFieldProps.LinkComponent, linkText: textFieldProps.linkText, linkHref: textFieldProps.linkHref, onLinkClick: textFieldProps.onLinkClick, htmlFor: textFieldProps.id, className: "mb-2", labelClassName: labelClassName })), jsxRuntime.jsx(TextField, { ref: ref, value: textValue, onChange: handleTextChange, suffix: selectSuffix, size: size, validationState: currentValidationState, isDisabled: isDisabled, isRequired: isRequired, isOptional: isOptional, containerClassName: "gap-0", className: className, inputClassName: inputClassName, ...textFieldProps }), jsxRuntime.jsx(FormFooter, { helperText: displayHelperText, validationState: currentValidationState === "none"
3642
+ ? "default"
3643
+ : currentValidationState, size: size, isDisabled: isDisabled, className: "mt-1" })] }));
3644
+ });
3645
+ SelectTextField.displayName = "SelectTextField";
3646
+
3445
3647
  const switchVariants = classVarianceAuthority.cva("relative inline-flex items-center shrink-0 cursor-pointer rounded-full transition-all duration-200", {
3446
3648
  variants: {
3447
3649
  size: {
@@ -4060,6 +4262,7 @@ exports.Pagination = Pagination;
4060
4262
  exports.Radio = Radio;
4061
4263
  exports.SearchableDropdown = SearchableDropdown;
4062
4264
  exports.Select = Select;
4265
+ exports.SelectTextField = SelectTextField;
4063
4266
  exports.Skeleton = Skeleton;
4064
4267
  exports.SlotCell = SlotCell;
4065
4268
  exports.SpacerCell = SpacerCell;
@@ -4090,6 +4293,7 @@ exports.linkVariants = linkVariants;
4090
4293
  exports.listItemVariants = listItemVariants;
4091
4294
  exports.paginationVariants = paginationVariants;
4092
4295
  exports.radioVariants = radioVariants;
4296
+ exports.selectTriggerVariants = selectTriggerVariants;
4093
4297
  exports.selectVariants = selectVariants;
4094
4298
  exports.switchVariants = switchVariants;
4095
4299
  exports.tableCellVariants = tableCellVariants;