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/components/SelectTextField/SelectTextField.d.ts +73 -0
- package/dist/components/SelectTextField/SelectTextField.d.ts.map +1 -0
- package/dist/components/SelectTextField/SelectTextField.stories.d.ts +21 -0
- package/dist/components/SelectTextField/SelectTextField.stories.d.ts.map +1 -0
- package/dist/components/SelectTextField/index.d.ts +3 -0
- package/dist/components/SelectTextField/index.d.ts.map +1 -0
- package/dist/index.css +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.esm.js +203 -1
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +204 -0
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
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;
|