shadcn-ui-react 0.7.10 → 0.7.12

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
@@ -6271,7 +6271,7 @@ import { cva as cva5 } from "class-variance-authority";
6271
6271
  import * as React42 from "react";
6272
6272
  import { jsx as jsx18 } from "react/jsx-runtime";
6273
6273
  var labelVariants = cva5(
6274
- "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70 text-label"
6274
+ "text-sm font-medium leading-none text-label peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
6275
6275
  );
6276
6276
  var Label3 = React42.forwardRef((_a, ref) => {
6277
6277
  var _b = _a, { className } = _b, props = __objRest(_b, ["className"]);
@@ -6594,7 +6594,7 @@ import {
6594
6594
  // src/components/input.tsx
6595
6595
  import * as React45 from "react";
6596
6596
 
6597
- // src/components/Form/utils/form-utils.ts
6597
+ // src/utils/form-utils.ts
6598
6598
  var formInputVariants = {
6599
6599
  outline: "rounded-md border border-input bg-input backdrop-blur-sm shadow-sm hover:border-primary/60 focus:border-primary focus:ring-2 focus:ring-primary/20",
6600
6600
  soft: "rounded-md border border-transparent bg-muted/60 shadow-sm hover:bg-muted focus:bg-input/80 focus:ring-2 focus:ring-primary/20",
@@ -6604,6 +6604,15 @@ var formInputVariants = {
6604
6604
  unstyled: "border-0 shadow-none focus:ring-0",
6605
6605
  link: "h-auto border-0 bg-transparent p-0 text-primary shadow-none underline-offset-4 focus:underline focus:ring-0"
6606
6606
  };
6607
+ var formCompositeVariants = {
6608
+ outline: "rounded-md border border-input bg-input backdrop-blur-sm shadow-sm hover:border-primary/60 focus-within:border-primary focus-within:ring-2 focus-within:ring-primary/20",
6609
+ soft: "rounded-md border border-transparent bg-muted/60 shadow-sm hover:bg-muted focus-within:bg-input/80 focus-within:ring-2 focus-within:ring-primary/20",
6610
+ ghost: "rounded-md border border-transparent bg-transparent hover:bg-muted/50 focus-within:ring-2 focus-within:ring-ring",
6611
+ filled: "rounded-md border border-input bg-muted/70 shadow-inner hover:bg-muted focus-within:bg-input/70 focus-within:ring-2 focus-within:ring-primary/20",
6612
+ flushed: "rounded-none border-0 border-b border-input px-0 shadow-none focus-within:border-b-2 focus-within:border-primary focus-within:ring-0",
6613
+ unstyled: "border-0 shadow-none focus-within:ring-0",
6614
+ link: "h-auto border-0 bg-transparent p-0 text-primary shadow-none underline-offset-4 focus-within:underline focus-within:ring-0"
6615
+ };
6607
6616
  var variants = formInputVariants;
6608
6617
  var formSizeVariants = {
6609
6618
  "2xs": {
@@ -6684,9 +6693,18 @@ var formSizeVariants = {
6684
6693
  message: "text-base"
6685
6694
  }
6686
6695
  };
6696
+ var formControlBase = "relative inline-flex w-full items-center justify-between gap-2 text-foreground outline-none transition data-[placeholder]:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50";
6697
+ var formCompositeControlBase = "relative flex w-full items-center gap-2 text-foreground outline-none transition";
6698
+ var formControlErrorClass = "border-destructive focus:border-destructive focus:ring-destructive/20";
6699
+ var formCompositeControlErrorClass = "border-destructive focus-within:border-destructive focus-within:ring-destructive/20";
6687
6700
  function getFormSizeClasses(size = "md", customSize) {
6688
6701
  return __spreadValues(__spreadValues({}, formSizeVariants[size]), customSize);
6689
6702
  }
6703
+ function getFormControlSizeClass(variant, sizeClasses) {
6704
+ if (variant === "flushed") return sizeClasses.flushedControl;
6705
+ if (variant === "link") return sizeClasses.linkControl;
6706
+ return sizeClasses.control;
6707
+ }
6690
6708
 
6691
6709
  // src/components/input.tsx
6692
6710
  import { jsx as jsx22, jsxs as jsxs12 } from "react/jsx-runtime";
@@ -6898,213 +6916,852 @@ import {
6898
6916
  } from "react-hook-form";
6899
6917
 
6900
6918
  // src/components/select.tsx
6901
- import {
6902
- CaretSortIcon,
6903
- CheckIcon as CheckIcon4,
6904
- ChevronDownIcon as ChevronDownIcon2,
6905
- ChevronUpIcon
6906
- } from "@radix-ui/react-icons";
6907
- import * as SelectPrimitive from "@radix-ui/react-select";
6919
+ import { CaretSortIcon, CheckIcon as CheckIcon4 } from "@radix-ui/react-icons";
6908
6920
  import * as React46 from "react";
6909
- import { Fragment, jsx as jsx24, jsxs as jsxs14 } from "react/jsx-runtime";
6910
- var Select2 = SelectPrimitive.Root;
6911
- var SelectGroup = SelectPrimitive.Group;
6912
- var SelectValue = SelectPrimitive.Value;
6913
- var BODY_UNLOCK_ATTR = "data-select-scroll-unlocked";
6914
- var BODY_UNLOCK_STYLE_ID = "radix-select-scroll-unlock-style";
6915
- var useSafeLayoutEffect = typeof window !== "undefined" ? React46.useLayoutEffect : React46.useEffect;
6916
- function SelectBodyScrollUnlock() {
6917
- useSafeLayoutEffect(() => {
6918
- var _a;
6919
- if (typeof document === "undefined") return;
6920
- if (!document.getElementById(BODY_UNLOCK_STYLE_ID)) {
6921
- const style = document.createElement("style");
6922
- style.id = BODY_UNLOCK_STYLE_ID;
6923
- style.textContent = `
6924
- body[${BODY_UNLOCK_ATTR}][data-scroll-locked] {
6925
- overflow: auto !important;
6926
- margin-right: 0 !important;
6927
- padding-right: 0 !important;
6928
- }
6929
- `;
6930
- document.head.appendChild(style);
6931
- }
6932
- const body = document.body;
6933
- const currentCount = Number((_a = body.getAttribute(BODY_UNLOCK_ATTR)) != null ? _a : "0");
6934
- body.setAttribute(BODY_UNLOCK_ATTR, String(currentCount + 1));
6935
- return () => {
6936
- var _a2;
6937
- const nextCount = Number((_a2 = body.getAttribute(BODY_UNLOCK_ATTR)) != null ? _a2 : "1") - 1;
6938
- if (nextCount <= 0) {
6939
- body.removeAttribute(BODY_UNLOCK_ATTR);
6940
- } else {
6941
- body.setAttribute(BODY_UNLOCK_ATTR, String(nextCount));
6921
+ import { createPortal } from "react-dom";
6922
+ import { jsx as jsx24, jsxs as jsxs14 } from "react/jsx-runtime";
6923
+ var SelectContext = React46.createContext(null);
6924
+ function useSelectContext(componentName) {
6925
+ const context = React46.useContext(SelectContext);
6926
+ if (!context) {
6927
+ throw new Error(
6928
+ `${componentName} must be used within <Select />. Aseg\xFArate de importar Select, SelectTrigger, SelectContent, SelectValue y SelectItem desde el mismo archivo "../select", sin mezclar Radix ni otra versi\xF3n del componente.`
6929
+ );
6930
+ }
6931
+ return context;
6932
+ }
6933
+ function useControllableState({
6934
+ value,
6935
+ defaultValue,
6936
+ onChange
6937
+ }) {
6938
+ const [internalValue, setInternalValue] = React46.useState(defaultValue);
6939
+ const isControlled = value !== void 0;
6940
+ const currentValue = isControlled ? value : internalValue;
6941
+ const setValue = React46.useCallback(
6942
+ (nextValue) => {
6943
+ if (!isControlled) {
6944
+ setInternalValue(
6945
+ (previousValue) => Object.is(previousValue, nextValue) ? previousValue : nextValue
6946
+ );
6942
6947
  }
6943
- };
6944
- }, []);
6945
- return null;
6948
+ if (!Object.is(currentValue, nextValue)) {
6949
+ onChange == null ? void 0 : onChange(nextValue);
6950
+ }
6951
+ },
6952
+ [currentValue, isControlled, onChange]
6953
+ );
6954
+ return [currentValue, setValue];
6946
6955
  }
6947
- var SelectTrigger = React46.forwardRef((_a, ref) => {
6948
- var _b = _a, { className, children } = _b, props = __objRest(_b, ["className", "children"]);
6949
- return /* @__PURE__ */ jsxs14(
6950
- SelectPrimitive.Trigger,
6951
- __spreadProps(__spreadValues({
6952
- ref,
6953
- className: cn(
6954
- "flex h-9 w-full items-center justify-between gap-2 whitespace-nowrap rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-sm ring-offset-background transition-colors placeholder:text-muted-foreground focus:outline-none focus:ring-1 focus:ring-ring disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1",
6955
- className
6956
- )
6957
- }, props), {
6958
- children: [
6959
- children,
6960
- /* @__PURE__ */ jsx24(SelectPrimitive.Icon, { asChild: true, children: /* @__PURE__ */ jsx24(CaretSortIcon, { className: "h-4 w-4 shrink-0 opacity-50" }) })
6961
- ]
6962
- })
6956
+ function composeRefs(...refs) {
6957
+ return (node) => {
6958
+ refs.forEach((ref) => {
6959
+ if (!ref) return;
6960
+ if (typeof ref === "function") {
6961
+ ref(node);
6962
+ return;
6963
+ }
6964
+ ref.current = node;
6965
+ });
6966
+ };
6967
+ }
6968
+ function getNodeText(node) {
6969
+ if (node === null || node === void 0 || typeof node === "boolean") {
6970
+ return "";
6971
+ }
6972
+ if (typeof node === "string" || typeof node === "number") {
6973
+ return String(node);
6974
+ }
6975
+ if (Array.isArray(node)) {
6976
+ return node.map(getNodeText).join("");
6977
+ }
6978
+ if (React46.isValidElement(node)) {
6979
+ return getNodeText(node.props.children);
6980
+ }
6981
+ return "";
6982
+ }
6983
+ function getEnabledItems(items) {
6984
+ return items.filter((item) => !item.disabled);
6985
+ }
6986
+ function getNextItemValue(items, currentValue, direction) {
6987
+ var _a, _b, _c;
6988
+ const enabledItems = getEnabledItems(items);
6989
+ if (!enabledItems.length) return void 0;
6990
+ const currentIndex = enabledItems.findIndex(
6991
+ (item) => item.value === currentValue
6992
+ );
6993
+ if (currentIndex === -1) {
6994
+ return direction === "next" ? (_a = enabledItems[0]) == null ? void 0 : _a.value : (_b = enabledItems[enabledItems.length - 1]) == null ? void 0 : _b.value;
6995
+ }
6996
+ const nextIndex = direction === "next" ? (currentIndex + 1) % enabledItems.length : (currentIndex - 1 + enabledItems.length) % enabledItems.length;
6997
+ return (_c = enabledItems[nextIndex]) == null ? void 0 : _c.value;
6998
+ }
6999
+ function areRegisteredItemsEqual(previous, next) {
7000
+ return Boolean(
7001
+ previous && previous.id === next.id && previous.value === next.value && previous.textValue === next.textValue && previous.disabled === next.disabled && previous.label === next.label
7002
+ );
7003
+ }
7004
+ function areStylesEqual(previous, next) {
7005
+ if (!previous) return false;
7006
+ return previous.position === next.position && previous.zIndex === next.zIndex && previous.width === next.width && previous.minWidth === next.minWidth && previous.maxWidth === next.maxWidth && previous.maxHeight === next.maxHeight && previous.left === next.left && previous.right === next.right && previous.top === next.top && previous.bottom === next.bottom && previous.transform === next.transform;
7007
+ }
7008
+ function scrollItemIntoView(container, item) {
7009
+ if (!container || !item) return;
7010
+ const containerRect = container.getBoundingClientRect();
7011
+ const itemRect = item.getBoundingClientRect();
7012
+ const itemTop = itemRect.top - containerRect.top + container.scrollTop;
7013
+ const itemBottom = itemTop + itemRect.height;
7014
+ const visibleTop = container.scrollTop;
7015
+ const visibleBottom = visibleTop + container.clientHeight;
7016
+ if (itemTop < visibleTop) {
7017
+ container.scrollTop = itemTop;
7018
+ return;
7019
+ }
7020
+ if (itemBottom > visibleBottom) {
7021
+ container.scrollTop = itemBottom - container.clientHeight;
7022
+ }
7023
+ }
7024
+ function Select2({
7025
+ value,
7026
+ defaultValue = "",
7027
+ onValueChange,
7028
+ open,
7029
+ defaultOpen = false,
7030
+ onOpenChange,
7031
+ disabled = false,
7032
+ name,
7033
+ required,
7034
+ variant = "outline",
7035
+ size = "sm",
7036
+ customSize,
7037
+ invalid = false,
7038
+ children
7039
+ }) {
7040
+ const triggerRef = React46.useRef(null);
7041
+ const contentRef = React46.useRef(null);
7042
+ const [currentValue, setCurrentValue] = useControllableState({
7043
+ value,
7044
+ defaultValue,
7045
+ onChange: onValueChange
7046
+ });
7047
+ const [isOpen, setIsOpen] = useControllableState({
7048
+ value: open,
7049
+ defaultValue: defaultOpen,
7050
+ onChange: onOpenChange
7051
+ });
7052
+ const itemsRef = React46.useRef(/* @__PURE__ */ new Map());
7053
+ const [itemsVersion, forceItemsUpdate] = React46.useReducer(
7054
+ (version) => version + 1,
7055
+ 0
7056
+ );
7057
+ const [activeValue, setActiveValue] = React46.useState();
7058
+ const items = React46.useMemo(
7059
+ () => Array.from(itemsRef.current.values()),
7060
+ [itemsVersion]
7061
+ );
7062
+ const selectedItem = React46.useMemo(
7063
+ () => items.find((item) => item.value === currentValue),
7064
+ [currentValue, items]
7065
+ );
7066
+ const registerItem = React46.useCallback((item) => {
7067
+ const previousItem = itemsRef.current.get(item.value);
7068
+ if (previousItem && previousItem.id === item.id) {
7069
+ previousItem.label = item.label;
7070
+ previousItem.textValue = item.textValue;
7071
+ previousItem.disabled = item.disabled;
7072
+ if (!areRegisteredItemsEqual(previousItem, item)) {
7073
+ forceItemsUpdate();
7074
+ }
7075
+ return;
7076
+ }
7077
+ itemsRef.current.set(item.value, item);
7078
+ forceItemsUpdate();
7079
+ }, []);
7080
+ const unregisterItem = React46.useCallback((value2, id) => {
7081
+ const currentItem = itemsRef.current.get(value2);
7082
+ if (!currentItem || currentItem.id !== id) return;
7083
+ itemsRef.current.delete(value2);
7084
+ forceItemsUpdate();
7085
+ }, []);
7086
+ const updateItemRef = React46.useCallback(
7087
+ (value2, id, node) => {
7088
+ const currentItem = itemsRef.current.get(value2);
7089
+ if (!currentItem || currentItem.id !== id) return;
7090
+ if (currentItem.ref === node) return;
7091
+ currentItem.ref = node;
7092
+ },
7093
+ []
6963
7094
  );
6964
- });
6965
- SelectTrigger.displayName = SelectPrimitive.Trigger.displayName;
6966
- var SelectScrollUpButton = React46.forwardRef((_a, ref) => {
6967
- var _b = _a, { className } = _b, props = __objRest(_b, ["className"]);
6968
- return /* @__PURE__ */ jsx24(
6969
- SelectPrimitive.ScrollUpButton,
6970
- __spreadProps(__spreadValues({
6971
- ref,
6972
- className: cn(
6973
- "flex cursor-default items-center justify-center py-1",
6974
- className
6975
- )
6976
- }, props), {
6977
- children: /* @__PURE__ */ jsx24(ChevronUpIcon, { className: "h-4 w-4" })
6978
- })
7095
+ const handleOpenChange = React46.useCallback(
7096
+ (nextOpen) => {
7097
+ if (disabled) return;
7098
+ setIsOpen(nextOpen);
7099
+ },
7100
+ [disabled, setIsOpen]
6979
7101
  );
6980
- });
6981
- SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName;
6982
- var SelectScrollDownButton = React46.forwardRef((_a, ref) => {
6983
- var _b = _a, { className } = _b, props = __objRest(_b, ["className"]);
6984
- return /* @__PURE__ */ jsx24(
6985
- SelectPrimitive.ScrollDownButton,
6986
- __spreadProps(__spreadValues({
6987
- ref,
6988
- className: cn(
6989
- "flex cursor-default items-center justify-center py-1",
6990
- className
6991
- )
6992
- }, props), {
6993
- children: /* @__PURE__ */ jsx24(ChevronDownIcon2, { className: "h-4 w-4" })
6994
- })
7102
+ const handleValueChange = React46.useCallback(
7103
+ (nextValue) => {
7104
+ if (disabled) return;
7105
+ setCurrentValue(nextValue);
7106
+ setIsOpen(false);
7107
+ requestAnimationFrame(() => {
7108
+ var _a;
7109
+ (_a = triggerRef.current) == null ? void 0 : _a.focus({ preventScroll: true });
7110
+ });
7111
+ },
7112
+ [disabled, setCurrentValue, setIsOpen]
6995
7113
  );
6996
- });
6997
- SelectScrollDownButton.displayName = SelectPrimitive.ScrollDownButton.displayName;
7114
+ React46.useEffect(() => {
7115
+ var _a;
7116
+ if (!isOpen) return;
7117
+ const selectedEnabledItem = items.find(
7118
+ (item) => item.value === currentValue && !item.disabled
7119
+ );
7120
+ const firstEnabledItem = getEnabledItems(items)[0];
7121
+ const nextActiveValue = (_a = selectedEnabledItem == null ? void 0 : selectedEnabledItem.value) != null ? _a : firstEnabledItem == null ? void 0 : firstEnabledItem.value;
7122
+ setActiveValue(
7123
+ (previousValue) => previousValue === nextActiveValue ? previousValue : nextActiveValue
7124
+ );
7125
+ }, [currentValue, isOpen, items]);
7126
+ React46.useEffect(() => {
7127
+ if (!isOpen) return;
7128
+ const handlePointerDown = (event) => {
7129
+ var _a, _b;
7130
+ const target = event.target;
7131
+ if (target && (((_a = triggerRef.current) == null ? void 0 : _a.contains(target)) || ((_b = contentRef.current) == null ? void 0 : _b.contains(target)))) {
7132
+ return;
7133
+ }
7134
+ setIsOpen(false);
7135
+ };
7136
+ document.addEventListener("pointerdown", handlePointerDown, true);
7137
+ return () => {
7138
+ document.removeEventListener("pointerdown", handlePointerDown, true);
7139
+ };
7140
+ }, [isOpen, setIsOpen]);
7141
+ const contextValue = React46.useMemo(
7142
+ () => ({
7143
+ value: currentValue,
7144
+ open: isOpen,
7145
+ disabled,
7146
+ invalid,
7147
+ variant,
7148
+ size,
7149
+ customSize,
7150
+ selectedItem,
7151
+ activeValue,
7152
+ items,
7153
+ triggerRef,
7154
+ contentRef,
7155
+ setOpen: handleOpenChange,
7156
+ setValue: handleValueChange,
7157
+ setActiveValue,
7158
+ registerItem,
7159
+ unregisterItem,
7160
+ updateItemRef
7161
+ }),
7162
+ [
7163
+ currentValue,
7164
+ isOpen,
7165
+ disabled,
7166
+ invalid,
7167
+ variant,
7168
+ size,
7169
+ customSize,
7170
+ selectedItem,
7171
+ activeValue,
7172
+ items,
7173
+ handleOpenChange,
7174
+ handleValueChange,
7175
+ registerItem,
7176
+ unregisterItem,
7177
+ updateItemRef
7178
+ ]
7179
+ );
7180
+ return /* @__PURE__ */ jsxs14(SelectContext.Provider, { value: contextValue, children: [
7181
+ children,
7182
+ name ? /* @__PURE__ */ jsx24(
7183
+ "input",
7184
+ {
7185
+ type: "hidden",
7186
+ name,
7187
+ value: currentValue,
7188
+ required,
7189
+ disabled
7190
+ }
7191
+ ) : null
7192
+ ] });
7193
+ }
7194
+ var SelectTrigger = React46.forwardRef(
7195
+ (_a, ref) => {
7196
+ var _b = _a, {
7197
+ className,
7198
+ children,
7199
+ variant,
7200
+ size,
7201
+ customSize,
7202
+ invalid,
7203
+ disabled,
7204
+ onClick,
7205
+ onKeyDown,
7206
+ onPointerDown
7207
+ } = _b, props = __objRest(_b, [
7208
+ "className",
7209
+ "children",
7210
+ "variant",
7211
+ "size",
7212
+ "customSize",
7213
+ "invalid",
7214
+ "disabled",
7215
+ "onClick",
7216
+ "onKeyDown",
7217
+ "onPointerDown"
7218
+ ]);
7219
+ const context = useSelectContext("SelectTrigger");
7220
+ const resolvedVariant = variant != null ? variant : context.variant;
7221
+ const resolvedSize = size != null ? size : context.size;
7222
+ const resolvedCustomSize = customSize != null ? customSize : context.customSize;
7223
+ const resolvedInvalid = invalid != null ? invalid : context.invalid;
7224
+ const resolvedDisabled = disabled != null ? disabled : context.disabled;
7225
+ const sizeClasses = getFormSizeClasses(resolvedSize, resolvedCustomSize);
7226
+ const controlSizeClass = getFormControlSizeClass(
7227
+ resolvedVariant,
7228
+ sizeClasses
7229
+ );
7230
+ const typeaheadRef = React46.useRef("");
7231
+ const typeaheadTimeoutRef = React46.useRef(null);
7232
+ const moveActiveItem = React46.useCallback(
7233
+ (direction) => {
7234
+ var _a2;
7235
+ const nextValue = getNextItemValue(
7236
+ context.items,
7237
+ (_a2 = context.activeValue) != null ? _a2 : context.value,
7238
+ direction
7239
+ );
7240
+ if (nextValue) {
7241
+ context.setActiveValue(nextValue);
7242
+ }
7243
+ },
7244
+ [context]
7245
+ );
7246
+ const handleTypeahead = React46.useCallback(
7247
+ (key) => {
7248
+ typeaheadRef.current += key.toLowerCase();
7249
+ if (typeaheadTimeoutRef.current) {
7250
+ window.clearTimeout(typeaheadTimeoutRef.current);
7251
+ }
7252
+ typeaheadTimeoutRef.current = window.setTimeout(() => {
7253
+ typeaheadRef.current = "";
7254
+ }, 500);
7255
+ const enabledItems = getEnabledItems(context.items);
7256
+ const match2 = enabledItems.find(
7257
+ (item) => item.textValue.toLowerCase().startsWith(typeaheadRef.current)
7258
+ );
7259
+ if (!match2) return;
7260
+ if (!context.open) {
7261
+ context.setOpen(true);
7262
+ }
7263
+ context.setActiveValue(match2.value);
7264
+ },
7265
+ [context]
7266
+ );
7267
+ React46.useEffect(() => {
7268
+ return () => {
7269
+ if (typeaheadTimeoutRef.current) {
7270
+ window.clearTimeout(typeaheadTimeoutRef.current);
7271
+ }
7272
+ };
7273
+ }, []);
7274
+ const handleKeyDown = (event) => {
7275
+ onKeyDown == null ? void 0 : onKeyDown(event);
7276
+ if (event.defaultPrevented || resolvedDisabled) return;
7277
+ if (event.key === "ArrowDown") {
7278
+ event.preventDefault();
7279
+ if (!context.open) {
7280
+ context.setOpen(true);
7281
+ return;
7282
+ }
7283
+ moveActiveItem("next");
7284
+ return;
7285
+ }
7286
+ if (event.key === "ArrowUp") {
7287
+ event.preventDefault();
7288
+ if (!context.open) {
7289
+ context.setOpen(true);
7290
+ return;
7291
+ }
7292
+ moveActiveItem("previous");
7293
+ return;
7294
+ }
7295
+ if (event.key === "Enter" || event.key === " ") {
7296
+ event.preventDefault();
7297
+ if (!context.open) {
7298
+ context.setOpen(true);
7299
+ return;
7300
+ }
7301
+ if (context.activeValue) {
7302
+ context.setValue(context.activeValue);
7303
+ }
7304
+ return;
7305
+ }
7306
+ if (event.key === "Escape") {
7307
+ event.preventDefault();
7308
+ context.setOpen(false);
7309
+ return;
7310
+ }
7311
+ if (event.key === "Home") {
7312
+ event.preventDefault();
7313
+ const firstEnabledItem = getEnabledItems(context.items)[0];
7314
+ if (firstEnabledItem) {
7315
+ context.setActiveValue(firstEnabledItem.value);
7316
+ }
7317
+ return;
7318
+ }
7319
+ if (event.key === "End") {
7320
+ event.preventDefault();
7321
+ const enabledItems = getEnabledItems(context.items);
7322
+ const lastEnabledItem = enabledItems[enabledItems.length - 1];
7323
+ if (lastEnabledItem) {
7324
+ context.setActiveValue(lastEnabledItem.value);
7325
+ }
7326
+ return;
7327
+ }
7328
+ if (event.key.length === 1 && !event.ctrlKey && !event.metaKey && !event.altKey) {
7329
+ handleTypeahead(event.key);
7330
+ }
7331
+ };
7332
+ return /* @__PURE__ */ jsxs14(
7333
+ "button",
7334
+ __spreadProps(__spreadValues({
7335
+ ref: composeRefs(ref, context.triggerRef),
7336
+ type: "button",
7337
+ "aria-haspopup": "listbox",
7338
+ "aria-expanded": context.open,
7339
+ "data-placeholder": !context.value ? "" : void 0,
7340
+ disabled: resolvedDisabled,
7341
+ className: cn(
7342
+ formControlBase,
7343
+ "relative flex w-full items-center justify-between gap-2 overflow-hidden whitespace-nowrap ring-offset-background",
7344
+ formInputVariants[resolvedVariant],
7345
+ controlSizeClass,
7346
+ resolvedInvalid && formControlErrorClass,
7347
+ className
7348
+ ),
7349
+ onPointerDown: (event) => {
7350
+ onPointerDown == null ? void 0 : onPointerDown(event);
7351
+ if (event.defaultPrevented || resolvedDisabled || event.button !== 0 || event.ctrlKey) {
7352
+ return;
7353
+ }
7354
+ event.preventDefault();
7355
+ },
7356
+ onClick: (event) => {
7357
+ onClick == null ? void 0 : onClick(event);
7358
+ if (!event.defaultPrevented && !resolvedDisabled) {
7359
+ context.setOpen(!context.open);
7360
+ requestAnimationFrame(() => {
7361
+ var _a2;
7362
+ (_a2 = context.triggerRef.current) == null ? void 0 : _a2.focus({ preventScroll: true });
7363
+ });
7364
+ }
7365
+ },
7366
+ onKeyDown: handleKeyDown
7367
+ }, props), {
7368
+ children: [
7369
+ children,
7370
+ /* @__PURE__ */ jsx24(CaretSortIcon, { className: "h-4 w-4 shrink-0 opacity-50" })
7371
+ ]
7372
+ })
7373
+ );
7374
+ }
7375
+ );
7376
+ SelectTrigger.displayName = "SelectTrigger";
7377
+ var SelectValue = React46.forwardRef(
7378
+ (_a, ref) => {
7379
+ var _b = _a, { className, placeholder = "Select an option", children } = _b, props = __objRest(_b, ["className", "placeholder", "children"]);
7380
+ var _a2;
7381
+ const context = useSelectContext("SelectValue");
7382
+ const hasValue = Boolean(context.selectedItem) || children !== void 0;
7383
+ return /* @__PURE__ */ jsx24(
7384
+ "span",
7385
+ __spreadProps(__spreadValues({
7386
+ ref,
7387
+ className: cn(
7388
+ "min-w-0 flex-1 truncate text-left",
7389
+ !hasValue && "text-muted-foreground",
7390
+ className
7391
+ )
7392
+ }, props), {
7393
+ children: hasValue ? children != null ? children : (_a2 = context.selectedItem) == null ? void 0 : _a2.label : placeholder
7394
+ })
7395
+ );
7396
+ }
7397
+ );
6998
7398
  var SelectContent = React46.forwardRef(
6999
7399
  (_a, ref) => {
7000
7400
  var _b = _a, {
7001
7401
  className,
7002
7402
  children,
7003
- position = "popper",
7004
7403
  sideOffset = 4,
7005
- align = "start"
7404
+ align = "start",
7405
+ position: _position,
7406
+ style
7006
7407
  } = _b, props = __objRest(_b, [
7007
7408
  "className",
7008
7409
  "children",
7009
- "position",
7010
7410
  "sideOffset",
7011
- "align"
7411
+ "align",
7412
+ "position",
7413
+ "style"
7012
7414
  ]);
7013
- return /* @__PURE__ */ jsxs14(Fragment, { children: [
7014
- /* @__PURE__ */ jsx24(SelectBodyScrollUnlock, {}),
7015
- /* @__PURE__ */ jsx24(SelectPrimitive.Portal, { children: /* @__PURE__ */ jsxs14(
7016
- SelectPrimitive.Content,
7017
- __spreadProps(__spreadValues({
7018
- ref,
7019
- position,
7020
- sideOffset,
7021
- align,
7415
+ const context = useSelectContext("SelectContent");
7416
+ const scrollRef = React46.useRef(null);
7417
+ const rafRef = React46.useRef(null);
7418
+ const lockedSideRef = React46.useRef(null);
7419
+ const [mounted, setMounted] = React46.useState(false);
7420
+ const [side, setSide] = React46.useState("bottom");
7421
+ const [contentStyle, setContentStyle] = React46.useState();
7422
+ React46.useLayoutEffect(() => {
7423
+ setMounted(true);
7424
+ }, []);
7425
+ React46.useLayoutEffect(() => {
7426
+ if (!context.open) {
7427
+ lockedSideRef.current = null;
7428
+ setContentStyle(void 0);
7429
+ }
7430
+ }, [context.open]);
7431
+ const updatePosition = React46.useCallback(() => {
7432
+ const trigger = context.triggerRef.current;
7433
+ if (!trigger) return;
7434
+ const rect = trigger.getBoundingClientRect();
7435
+ const viewportPadding = 8;
7436
+ const preferredMaxHeight = 288;
7437
+ const minUsefulHeight = 140;
7438
+ const availableBelow = window.innerHeight - rect.bottom - viewportPadding - sideOffset;
7439
+ const availableAbove = rect.top - viewportPadding - sideOffset;
7440
+ const calculatedSide = availableBelow >= Math.min(preferredMaxHeight, minUsefulHeight) || availableBelow >= availableAbove ? "bottom" : "top";
7441
+ if (!lockedSideRef.current) {
7442
+ lockedSideRef.current = calculatedSide;
7443
+ }
7444
+ const nextSide = lockedSideRef.current;
7445
+ const availableHeight = nextSide === "bottom" ? availableBelow : availableAbove;
7446
+ const contentMaxHeight = Math.max(
7447
+ 80,
7448
+ Math.min(preferredMaxHeight, availableHeight)
7449
+ );
7450
+ const baseStyle = {
7451
+ position: "fixed",
7452
+ zIndex: 9999,
7453
+ width: rect.width,
7454
+ minWidth: rect.width,
7455
+ maxWidth: "calc(100vw - 16px)",
7456
+ maxHeight: contentMaxHeight
7457
+ };
7458
+ if (align === "start") {
7459
+ baseStyle.left = rect.left;
7460
+ baseStyle.right = void 0;
7461
+ baseStyle.transform = void 0;
7462
+ }
7463
+ if (align === "center") {
7464
+ baseStyle.left = rect.left + rect.width / 2;
7465
+ baseStyle.right = void 0;
7466
+ baseStyle.transform = "translateX(-50%)";
7467
+ }
7468
+ if (align === "end") {
7469
+ baseStyle.left = rect.right;
7470
+ baseStyle.right = void 0;
7471
+ baseStyle.transform = "translateX(-100%)";
7472
+ }
7473
+ if (nextSide === "bottom") {
7474
+ baseStyle.top = rect.bottom + sideOffset;
7475
+ baseStyle.bottom = void 0;
7476
+ } else {
7477
+ baseStyle.bottom = window.innerHeight - rect.top + sideOffset;
7478
+ baseStyle.top = void 0;
7479
+ }
7480
+ setSide(
7481
+ (previousSide) => previousSide === nextSide ? previousSide : nextSide
7482
+ );
7483
+ setContentStyle(
7484
+ (previousStyle) => areStylesEqual(previousStyle, baseStyle) ? previousStyle : baseStyle
7485
+ );
7486
+ }, [align, context.triggerRef, sideOffset]);
7487
+ const scheduleUpdatePosition = React46.useCallback(() => {
7488
+ if (rafRef.current) {
7489
+ cancelAnimationFrame(rafRef.current);
7490
+ }
7491
+ rafRef.current = requestAnimationFrame(() => {
7492
+ rafRef.current = null;
7493
+ updatePosition();
7494
+ });
7495
+ }, [updatePosition]);
7496
+ React46.useLayoutEffect(() => {
7497
+ var _a2, _b2;
7498
+ if (!context.open) return;
7499
+ updatePosition();
7500
+ scheduleUpdatePosition();
7501
+ const handleResize = () => {
7502
+ scheduleUpdatePosition();
7503
+ };
7504
+ const handlePageScroll = (event) => {
7505
+ var _a3;
7506
+ const target = event.target;
7507
+ if (target && ((_a3 = scrollRef.current) == null ? void 0 : _a3.contains(target))) {
7508
+ return;
7509
+ }
7510
+ scheduleUpdatePosition();
7511
+ };
7512
+ window.addEventListener("resize", handleResize);
7513
+ window.addEventListener("scroll", handlePageScroll, true);
7514
+ (_a2 = window.visualViewport) == null ? void 0 : _a2.addEventListener("resize", handleResize);
7515
+ (_b2 = window.visualViewport) == null ? void 0 : _b2.addEventListener("scroll", handleResize);
7516
+ return () => {
7517
+ var _a3, _b3;
7518
+ window.removeEventListener("resize", handleResize);
7519
+ window.removeEventListener("scroll", handlePageScroll, true);
7520
+ (_a3 = window.visualViewport) == null ? void 0 : _a3.removeEventListener("resize", handleResize);
7521
+ (_b3 = window.visualViewport) == null ? void 0 : _b3.removeEventListener("scroll", handleResize);
7522
+ if (rafRef.current) {
7523
+ cancelAnimationFrame(rafRef.current);
7524
+ rafRef.current = null;
7525
+ }
7526
+ };
7527
+ }, [context.open, scheduleUpdatePosition, updatePosition]);
7528
+ React46.useLayoutEffect(() => {
7529
+ if (!context.open) return;
7530
+ const frame = requestAnimationFrame(() => {
7531
+ const activeItem = context.items.find(
7532
+ (item) => item.value === context.activeValue
7533
+ );
7534
+ scrollItemIntoView(scrollRef.current, activeItem == null ? void 0 : activeItem.ref);
7535
+ });
7536
+ return () => {
7537
+ cancelAnimationFrame(frame);
7538
+ };
7539
+ }, [context.activeValue, context.items, context.open]);
7540
+ if (!context.open) {
7541
+ return /* @__PURE__ */ jsx24("div", { hidden: true, "aria-hidden": "true", style: { display: "none" }, children });
7542
+ }
7543
+ if (!mounted || !contentStyle) return null;
7544
+ return createPortal(
7545
+ /* @__PURE__ */ jsx24(
7546
+ "div",
7547
+ __spreadProps(__spreadValues({}, props), {
7548
+ ref: composeRefs(ref, context.contentRef),
7549
+ role: "listbox",
7550
+ "data-side": side,
7022
7551
  className: cn(
7023
- "relative z-50 min-w-32 overflow-hidden rounded-md border border-border bg-popover text-popover-foreground shadow-md",
7024
- "data-[state=open]:animate-in data-[state=closed]:animate-out",
7025
- "data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
7026
- "data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95",
7027
- "data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2",
7028
- "data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
7029
- position === "popper" && "data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
7552
+ "min-w-32 overflow-hidden rounded-md border border-border bg-popover text-popover-foreground shadow-md",
7030
7553
  className
7554
+ ),
7555
+ style: __spreadValues(__spreadValues({}, contentStyle), style),
7556
+ children: /* @__PURE__ */ jsx24(
7557
+ "div",
7558
+ {
7559
+ ref: scrollRef,
7560
+ "data-select-scroll-content": true,
7561
+ className: cn(
7562
+ "max-h-full overflow-x-hidden overflow-y-auto overscroll-contain px-1 py-1",
7563
+ "scrollbar-gutter-stable"
7564
+ ),
7565
+ style: {
7566
+ maxHeight: contentStyle.maxHeight,
7567
+ overflowX: "hidden",
7568
+ overflowY: "auto",
7569
+ overscrollBehavior: "contain",
7570
+ scrollbarGutter: "stable",
7571
+ WebkitOverflowScrolling: "touch"
7572
+ },
7573
+ onWheel: (event) => {
7574
+ event.stopPropagation();
7575
+ },
7576
+ onTouchMove: (event) => {
7577
+ event.stopPropagation();
7578
+ },
7579
+ children
7580
+ }
7031
7581
  )
7032
- }, props), {
7033
- children: [
7034
- /* @__PURE__ */ jsx24(SelectScrollUpButton, {}),
7035
- /* @__PURE__ */ jsx24(
7036
- SelectPrimitive.Viewport,
7037
- {
7038
- className: cn(
7039
- "max-h-[min(20rem,var(--radix-select-content-available-height))] overflow-y-auto p-1",
7040
- position === "popper" && "w-full min-w-(--radix-select-trigger-width)"
7041
- ),
7042
- children
7043
- }
7044
- ),
7045
- /* @__PURE__ */ jsx24(SelectScrollDownButton, {})
7046
- ]
7047
7582
  })
7048
- ) })
7049
- ] });
7583
+ ),
7584
+ document.body
7585
+ );
7050
7586
  }
7051
7587
  );
7052
- SelectContent.displayName = SelectPrimitive.Content.displayName;
7053
- var SelectLabel = React46.forwardRef((_a, ref) => {
7054
- var _b = _a, { className } = _b, props = __objRest(_b, ["className"]);
7055
- return /* @__PURE__ */ jsx24(
7056
- SelectPrimitive.Label,
7057
- __spreadValues({
7058
- ref,
7059
- className: cn("px-2 py-1.5 text-sm font-semibold", className)
7060
- }, props)
7061
- );
7062
- });
7063
- SelectLabel.displayName = SelectPrimitive.Label.displayName;
7064
- var SelectItem = React46.forwardRef((_a, ref) => {
7065
- var _b = _a, { className, children } = _b, props = __objRest(_b, ["className", "children"]);
7066
- return /* @__PURE__ */ jsxs14(
7067
- SelectPrimitive.Item,
7068
- __spreadProps(__spreadValues({
7069
- ref,
7070
- className: cn(
7071
- "relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-2 pr-8 text-sm outline-none transition-colors",
7072
- "focus:bg-accent focus:text-accent-foreground",
7073
- "data-disabled:pointer-events-none data-disabled:opacity-50",
7074
- className
7075
- )
7076
- }, props), {
7077
- children: [
7078
- /* @__PURE__ */ jsx24("span", { className: "absolute right-2 flex h-3.5 w-3.5 items-center justify-center", children: /* @__PURE__ */ jsx24(SelectPrimitive.ItemIndicator, { children: /* @__PURE__ */ jsx24(CheckIcon4, { className: "h-4 w-4" }) }) }),
7079
- /* @__PURE__ */ jsx24(SelectPrimitive.ItemText, { children })
7080
- ]
7081
- })
7082
- );
7083
- });
7084
- SelectItem.displayName = SelectPrimitive.Item.displayName;
7085
- var SelectSeparator = React46.forwardRef((_a, ref) => {
7086
- var _b = _a, { className } = _b, props = __objRest(_b, ["className"]);
7087
- return /* @__PURE__ */ jsx24(
7088
- SelectPrimitive.Separator,
7089
- __spreadValues({
7090
- ref,
7091
- className: cn("-mx-1 my-1 h-px bg-muted", className)
7092
- }, props)
7093
- );
7094
- });
7095
- SelectSeparator.displayName = SelectPrimitive.Separator.displayName;
7588
+ SelectContent.displayName = "SelectContent";
7589
+ var SelectGroup = React46.forwardRef(
7590
+ (_a, ref) => {
7591
+ var _b = _a, { className } = _b, props = __objRest(_b, ["className"]);
7592
+ return /* @__PURE__ */ jsx24("div", __spreadValues({ ref, role: "group", className }, props));
7593
+ }
7594
+ );
7595
+ SelectGroup.displayName = "SelectGroup";
7596
+ var SelectLabel = React46.forwardRef(
7597
+ (_a, ref) => {
7598
+ var _b = _a, { className } = _b, props = __objRest(_b, ["className"]);
7599
+ return /* @__PURE__ */ jsx24(
7600
+ "div",
7601
+ __spreadValues({
7602
+ ref,
7603
+ className: cn("px-2 py-1.5 text-sm font-semibold", className)
7604
+ }, props)
7605
+ );
7606
+ }
7607
+ );
7608
+ SelectLabel.displayName = "SelectLabel";
7609
+ var SelectItem = React46.forwardRef(
7610
+ (_a, ref) => {
7611
+ var _b = _a, {
7612
+ className,
7613
+ children,
7614
+ value,
7615
+ disabled = false,
7616
+ textValue,
7617
+ size,
7618
+ customSize,
7619
+ onClick,
7620
+ onMouseMove,
7621
+ onMouseDown
7622
+ } = _b, props = __objRest(_b, [
7623
+ "className",
7624
+ "children",
7625
+ "value",
7626
+ "disabled",
7627
+ "textValue",
7628
+ "size",
7629
+ "customSize",
7630
+ "onClick",
7631
+ "onMouseMove",
7632
+ "onMouseDown"
7633
+ ]);
7634
+ const context = useSelectContext("SelectItem");
7635
+ const {
7636
+ registerItem,
7637
+ unregisterItem,
7638
+ updateItemRef,
7639
+ setActiveValue,
7640
+ setValue,
7641
+ value: selectedValue,
7642
+ activeValue,
7643
+ size: contextSize,
7644
+ customSize: contextCustomSize
7645
+ } = context;
7646
+ const itemId = React46.useId();
7647
+ const localRef = React46.useRef(null);
7648
+ const resolvedSize = size != null ? size : contextSize;
7649
+ const resolvedCustomSize = customSize != null ? customSize : contextCustomSize;
7650
+ const sizeClasses = getFormSizeClasses(resolvedSize, resolvedCustomSize);
7651
+ const labelText = textValue != null ? textValue : getNodeText(children);
7652
+ const isSelected = selectedValue === value;
7653
+ const isActive = activeValue === value;
7654
+ React46.useLayoutEffect(() => {
7655
+ registerItem({
7656
+ id: itemId,
7657
+ value,
7658
+ label: children,
7659
+ textValue: labelText,
7660
+ disabled,
7661
+ ref: localRef.current
7662
+ });
7663
+ return () => {
7664
+ unregisterItem(value, itemId);
7665
+ };
7666
+ }, [
7667
+ registerItem,
7668
+ unregisterItem,
7669
+ itemId,
7670
+ value,
7671
+ labelText,
7672
+ disabled,
7673
+ children
7674
+ ]);
7675
+ const handleItemRef = React46.useCallback(
7676
+ (node) => {
7677
+ localRef.current = node;
7678
+ updateItemRef(value, itemId, node);
7679
+ },
7680
+ [updateItemRef, value, itemId]
7681
+ );
7682
+ const setRefs = React46.useMemo(
7683
+ () => composeRefs(ref, handleItemRef),
7684
+ [ref, handleItemRef]
7685
+ );
7686
+ return /* @__PURE__ */ jsxs14(
7687
+ "div",
7688
+ __spreadProps(__spreadValues({
7689
+ ref: setRefs,
7690
+ id: itemId,
7691
+ role: "option",
7692
+ "aria-selected": isSelected,
7693
+ "aria-disabled": disabled,
7694
+ "data-highlighted": isActive ? "" : void 0,
7695
+ "data-disabled": disabled ? "" : void 0,
7696
+ className: cn(
7697
+ "relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-2 pr-8 outline-none transition-colors",
7698
+ sizeClasses.selectItem,
7699
+ !disabled && "data-highlighted:bg-accent data-highlighted:text-accent-foreground",
7700
+ disabled && "pointer-events-none opacity-50",
7701
+ className
7702
+ ),
7703
+ onMouseDown: (event) => {
7704
+ event.preventDefault();
7705
+ onMouseDown == null ? void 0 : onMouseDown(event);
7706
+ },
7707
+ onMouseMove: (event) => {
7708
+ onMouseMove == null ? void 0 : onMouseMove(event);
7709
+ if (!disabled) {
7710
+ setActiveValue(value);
7711
+ }
7712
+ },
7713
+ onClick: (event) => {
7714
+ onClick == null ? void 0 : onClick(event);
7715
+ if (!event.defaultPrevented && !disabled) {
7716
+ setValue(value);
7717
+ }
7718
+ }
7719
+ }, props), {
7720
+ children: [
7721
+ /* @__PURE__ */ jsx24("span", { className: "absolute right-2 flex h-3.5 w-3.5 items-center justify-center", children: isSelected ? /* @__PURE__ */ jsx24(CheckIcon4, { className: "h-4 w-4" }) : null }),
7722
+ /* @__PURE__ */ jsx24("span", { className: "truncate", children })
7723
+ ]
7724
+ })
7725
+ );
7726
+ }
7727
+ );
7728
+ SelectItem.displayName = "SelectItem";
7729
+ var SelectSeparator = React46.forwardRef(
7730
+ (_a, ref) => {
7731
+ var _b = _a, { className } = _b, props = __objRest(_b, ["className"]);
7732
+ return /* @__PURE__ */ jsx24(
7733
+ "div",
7734
+ __spreadValues({
7735
+ ref,
7736
+ role: "separator",
7737
+ className: cn("-mx-1 my-1 h-px bg-muted", className)
7738
+ }, props)
7739
+ );
7740
+ }
7741
+ );
7742
+ SelectSeparator.displayName = "SelectSeparator";
7096
7743
 
7097
7744
  // src/components/searchable-select.tsx
7098
7745
  import * as React47 from "react";
7746
+ import { createPortal as createPortal2 } from "react-dom";
7099
7747
  import { CaretSortIcon as CaretSortIcon2, CheckIcon as CheckIcon5, Cross2Icon as Cross2Icon2 } from "@radix-ui/react-icons";
7100
7748
  import { jsx as jsx25, jsxs as jsxs15 } from "react/jsx-runtime";
7101
7749
  function normalizeText(value) {
7102
7750
  return String(value != null ? value : "").normalize("NFD").replace(new RegExp("\\p{Diacritic}", "gu"), "").toLowerCase().trim();
7103
7751
  }
7104
7752
  function getLabelText(value) {
7753
+ if (value === null || value === void 0 || typeof value === "boolean") {
7754
+ return "";
7755
+ }
7105
7756
  if (typeof value === "string" || typeof value === "number") {
7106
7757
  return String(value);
7107
7758
  }
7759
+ if (Array.isArray(value)) {
7760
+ return value.map(getLabelText).join("");
7761
+ }
7762
+ if (React47.isValidElement(value)) {
7763
+ return getLabelText(value.props.children);
7764
+ }
7108
7765
  return "";
7109
7766
  }
7110
7767
  function getOptionText(item) {
@@ -7123,6 +7780,10 @@ function getNextEnabledIndex2(items, currentIndex, direction) {
7123
7780
  }
7124
7781
  return -1;
7125
7782
  }
7783
+ function areStylesEqual2(previous, next) {
7784
+ if (!previous) return false;
7785
+ return previous.position === next.position && previous.zIndex === next.zIndex && previous.width === next.width && previous.minWidth === next.minWidth && previous.maxWidth === next.maxWidth && previous.maxHeight === next.maxHeight && previous.left === next.left && previous.right === next.right && previous.top === next.top && previous.bottom === next.bottom && previous.transform === next.transform;
7786
+ }
7126
7787
  function SearchableSelectBase({
7127
7788
  items,
7128
7789
  value,
@@ -7134,6 +7795,11 @@ function SearchableSelectBase({
7134
7795
  disabled,
7135
7796
  name,
7136
7797
  required,
7798
+ invalid = false,
7799
+ size = "md",
7800
+ customSize,
7801
+ variant = "outline",
7802
+ classNameDefault = true,
7137
7803
  triggerClassName,
7138
7804
  contentClassName,
7139
7805
  itemClassName,
@@ -7141,7 +7807,11 @@ function SearchableSelectBase({
7141
7807
  }) {
7142
7808
  const rootRef = React47.useRef(null);
7143
7809
  const inputRef = React47.useRef(null);
7810
+ const contentRef = React47.useRef(null);
7811
+ const rafRef = React47.useRef(null);
7144
7812
  const listboxId = React47.useId();
7813
+ const sizeClasses = getFormSizeClasses(size, customSize);
7814
+ const triggerSizeClass = getFormControlSizeClass(variant, sizeClasses);
7145
7815
  const isControlled = value !== void 0;
7146
7816
  const [internalValue, setInternalValue] = React47.useState(defaultValue != null ? defaultValue : "");
7147
7817
  const currentValue = isControlled ? value != null ? value : "" : internalValue;
@@ -7151,9 +7821,14 @@ function SearchableSelectBase({
7151
7821
  const selectedText = React47.useMemo(() => {
7152
7822
  return getOptionText(selectedItem);
7153
7823
  }, [selectedItem]);
7824
+ const [mounted, setMounted] = React47.useState(false);
7154
7825
  const [open, setOpen] = React47.useState(false);
7155
7826
  const [inputValue, setInputValue] = React47.useState(selectedText);
7156
7827
  const [activeIndex, setActiveIndex] = React47.useState(-1);
7828
+ const [contentStyle, setContentStyle] = React47.useState();
7829
+ React47.useLayoutEffect(() => {
7830
+ setMounted(true);
7831
+ }, []);
7157
7832
  React47.useEffect(() => {
7158
7833
  if (!open) {
7159
7834
  setInputValue(selectedText);
@@ -7170,17 +7845,110 @@ function SearchableSelectBase({
7170
7845
  return haystack.includes(query);
7171
7846
  });
7172
7847
  }, [inputValue, items]);
7848
+ const updatePosition = React47.useCallback(() => {
7849
+ const root = rootRef.current;
7850
+ if (!root) return;
7851
+ const rect = root.getBoundingClientRect();
7852
+ const viewportPadding = 8;
7853
+ const sideOffset = 6;
7854
+ const preferredMaxHeight = 288;
7855
+ const minUsefulHeight = 140;
7856
+ const availableBelow = window.innerHeight - rect.bottom - viewportPadding - sideOffset;
7857
+ const availableAbove = rect.top - viewportPadding - sideOffset;
7858
+ const shouldOpenBelow = availableBelow >= Math.min(preferredMaxHeight, minUsefulHeight) || availableBelow >= availableAbove;
7859
+ const availableHeight = shouldOpenBelow ? availableBelow : availableAbove;
7860
+ const contentMaxHeight = Math.max(
7861
+ 96,
7862
+ Math.min(preferredMaxHeight, availableHeight)
7863
+ );
7864
+ const nextStyle = {
7865
+ position: "fixed",
7866
+ zIndex: 9999,
7867
+ left: Math.max(viewportPadding, rect.left),
7868
+ width: rect.width,
7869
+ minWidth: rect.width,
7870
+ maxWidth: `calc(100vw - ${viewportPadding * 2}px)`,
7871
+ maxHeight: contentMaxHeight
7872
+ };
7873
+ if (shouldOpenBelow) {
7874
+ nextStyle.top = rect.bottom + sideOffset;
7875
+ nextStyle.bottom = void 0;
7876
+ } else {
7877
+ nextStyle.bottom = window.innerHeight - rect.top + sideOffset;
7878
+ nextStyle.top = void 0;
7879
+ }
7880
+ setContentStyle(
7881
+ (previousStyle) => areStylesEqual2(previousStyle, nextStyle) ? previousStyle : nextStyle
7882
+ );
7883
+ }, []);
7884
+ const scheduleUpdatePosition = React47.useCallback(() => {
7885
+ if (rafRef.current) {
7886
+ cancelAnimationFrame(rafRef.current);
7887
+ }
7888
+ rafRef.current = requestAnimationFrame(() => {
7889
+ rafRef.current = null;
7890
+ updatePosition();
7891
+ });
7892
+ }, [updatePosition]);
7893
+ const openDropdown = React47.useCallback(() => {
7894
+ if (disabled) return;
7895
+ if (!open) {
7896
+ setInputValue("");
7897
+ setOpen(true);
7898
+ }
7899
+ requestAnimationFrame(() => {
7900
+ var _a;
7901
+ (_a = inputRef.current) == null ? void 0 : _a.focus({ preventScroll: true });
7902
+ });
7903
+ }, [disabled, open]);
7904
+ React47.useLayoutEffect(() => {
7905
+ if (!open) {
7906
+ setContentStyle(void 0);
7907
+ }
7908
+ }, [open]);
7909
+ React47.useLayoutEffect(() => {
7910
+ var _a, _b;
7911
+ if (!open) return;
7912
+ updatePosition();
7913
+ scheduleUpdatePosition();
7914
+ const handleResizeOrScroll = () => {
7915
+ scheduleUpdatePosition();
7916
+ };
7917
+ window.addEventListener("resize", handleResizeOrScroll);
7918
+ window.addEventListener("scroll", handleResizeOrScroll, true);
7919
+ (_a = window.visualViewport) == null ? void 0 : _a.addEventListener("resize", handleResizeOrScroll);
7920
+ (_b = window.visualViewport) == null ? void 0 : _b.addEventListener("scroll", handleResizeOrScroll);
7921
+ return () => {
7922
+ var _a2, _b2;
7923
+ window.removeEventListener("resize", handleResizeOrScroll);
7924
+ window.removeEventListener("scroll", handleResizeOrScroll, true);
7925
+ (_a2 = window.visualViewport) == null ? void 0 : _a2.removeEventListener(
7926
+ "resize",
7927
+ handleResizeOrScroll
7928
+ );
7929
+ (_b2 = window.visualViewport) == null ? void 0 : _b2.removeEventListener(
7930
+ "scroll",
7931
+ handleResizeOrScroll
7932
+ );
7933
+ if (rafRef.current) {
7934
+ cancelAnimationFrame(rafRef.current);
7935
+ rafRef.current = null;
7936
+ }
7937
+ };
7938
+ }, [open, scheduleUpdatePosition, updatePosition]);
7173
7939
  React47.useEffect(() => {
7174
7940
  if (!open) return;
7175
7941
  const firstEnabledIndex = filteredItems.findIndex((item) => !item.disabled);
7176
- setActiveIndex(firstEnabledIndex);
7942
+ setActiveIndex(
7943
+ (previousIndex) => previousIndex === firstEnabledIndex ? previousIndex : firstEnabledIndex
7944
+ );
7177
7945
  }, [filteredItems, open]);
7178
7946
  React47.useEffect(() => {
7179
7947
  if (!open) return;
7180
7948
  const handlePointerDown = (event) => {
7181
- var _a;
7949
+ var _a, _b;
7182
7950
  const target = event.target;
7183
- if (target && ((_a = rootRef.current) == null ? void 0 : _a.contains(target))) {
7951
+ if (target && (((_a = rootRef.current) == null ? void 0 : _a.contains(target)) || ((_b = contentRef.current) == null ? void 0 : _b.contains(target)))) {
7184
7952
  return;
7185
7953
  }
7186
7954
  setOpen(false);
@@ -7206,6 +7974,99 @@ function SearchableSelectBase({
7206
7974
  },
7207
7975
  [isControlled, onValueChange]
7208
7976
  );
7977
+ const dropdown = open && mounted && contentStyle ? createPortal2(
7978
+ /* @__PURE__ */ jsx25(
7979
+ "div",
7980
+ {
7981
+ ref: contentRef,
7982
+ className: cn(
7983
+ "overflow-hidden rounded-xl border border-border bg-popover text-popover-foreground shadow-xl",
7984
+ contentClassName
7985
+ ),
7986
+ style: __spreadProps(__spreadValues({}, contentStyle), {
7987
+ maxHeight: contentStyle.maxHeight
7988
+ }),
7989
+ children: /* @__PURE__ */ jsx25(
7990
+ "div",
7991
+ {
7992
+ id: listboxId,
7993
+ role: "listbox",
7994
+ className: "max-h-full overflow-x-hidden overflow-y-auto overscroll-contain p-1 scrollbar-gutter-stable",
7995
+ style: {
7996
+ maxHeight: contentStyle.maxHeight,
7997
+ overflowX: "hidden",
7998
+ overflowY: "auto",
7999
+ overscrollBehavior: "contain",
8000
+ scrollbarGutter: "stable",
8001
+ WebkitOverflowScrolling: "touch"
8002
+ },
8003
+ onWheel: (event) => {
8004
+ event.stopPropagation();
8005
+ },
8006
+ onTouchMove: (event) => {
8007
+ event.stopPropagation();
8008
+ },
8009
+ children: filteredItems.length === 0 ? /* @__PURE__ */ jsx25(
8010
+ "div",
8011
+ {
8012
+ className: cn(
8013
+ "px-3 py-6 text-center text-muted-foreground",
8014
+ sizeClasses.message
8015
+ ),
8016
+ children: emptyText
8017
+ }
8018
+ ) : filteredItems.map((item, index) => {
8019
+ const isSelected = item.value === currentValue;
8020
+ const isActive = index === activeIndex;
8021
+ return /* @__PURE__ */ jsxs15(
8022
+ "div",
8023
+ {
8024
+ id: `${listboxId}-option-${index}`,
8025
+ role: "option",
8026
+ "aria-selected": isSelected,
8027
+ "aria-disabled": item.disabled,
8028
+ tabIndex: -1,
8029
+ onMouseMove: () => {
8030
+ if (!item.disabled) {
8031
+ setActiveIndex(index);
8032
+ }
8033
+ },
8034
+ onPointerDown: (event) => {
8035
+ event.preventDefault();
8036
+ event.stopPropagation();
8037
+ if (!item.disabled) {
8038
+ selectItem(item);
8039
+ }
8040
+ },
8041
+ className: cn(
8042
+ "relative flex w-full select-none items-center gap-2 rounded-lg px-3 text-left outline-none transition",
8043
+ sizeClasses.selectItem,
8044
+ item.disabled ? "pointer-events-none opacity-50" : "cursor-pointer",
8045
+ isActive && !item.disabled && "bg-accent text-accent-foreground",
8046
+ !isActive && !item.disabled && "hover:bg-accent/70 hover:text-accent-foreground",
8047
+ isSelected && "font-medium",
8048
+ itemClassName
8049
+ ),
8050
+ children: [
8051
+ /* @__PURE__ */ jsx25("span", { className: "min-w-0 flex-1 truncate", children: item.label }),
8052
+ isSelected ? /* @__PURE__ */ jsx25(
8053
+ CheckIcon5,
8054
+ {
8055
+ "aria-hidden": "true",
8056
+ className: "h-4 w-4 shrink-0 text-primary"
8057
+ }
8058
+ ) : null
8059
+ ]
8060
+ },
8061
+ item.value
8062
+ );
8063
+ })
8064
+ }
8065
+ )
8066
+ }
8067
+ ),
8068
+ document.body
8069
+ ) : null;
7209
8070
  return /* @__PURE__ */ jsxs15("div", { ref: rootRef, className: "relative w-full", children: [
7210
8071
  name ? /* @__PURE__ */ jsx25(
7211
8072
  "input",
@@ -7220,19 +8081,18 @@ function SearchableSelectBase({
7220
8081
  /* @__PURE__ */ jsxs15(
7221
8082
  "div",
7222
8083
  {
7223
- className: cn(
7224
- "relative flex h-9 w-full items-center gap-2 rounded-md border border-input bg-background px-3 text-sm shadow-sm transition",
7225
- "focus-within:border-primary/60 focus-within:ring-2 focus-within:ring-primary/20",
8084
+ className: classNameDefault ? cn(
8085
+ formCompositeControlBase,
8086
+ formCompositeVariants[variant],
8087
+ triggerSizeClass,
8088
+ invalid && formCompositeControlErrorClass,
7226
8089
  disabled && "cursor-not-allowed opacity-50",
7227
8090
  triggerClassName
7228
- ),
7229
- onPointerDown: () => {
7230
- if (disabled) return;
7231
- setOpen(true);
7232
- requestAnimationFrame(() => {
7233
- var _a;
7234
- (_a = inputRef.current) == null ? void 0 : _a.focus({ preventScroll: true });
7235
- });
8091
+ ) : triggerClassName,
8092
+ onPointerDown: (event) => {
8093
+ if (disabled || event.button !== 0 || event.ctrlKey) return;
8094
+ event.preventDefault();
8095
+ openDropdown();
7236
8096
  },
7237
8097
  children: [
7238
8098
  /* @__PURE__ */ jsx25(
@@ -7244,17 +8104,14 @@ function SearchableSelectBase({
7244
8104
  "aria-autocomplete": "list",
7245
8105
  "aria-expanded": open,
7246
8106
  "aria-controls": listboxId,
8107
+ "aria-invalid": invalid || void 0,
7247
8108
  "aria-activedescendant": activeIndex >= 0 ? `${listboxId}-option-${activeIndex}` : void 0,
7248
8109
  placeholder: open ? searchPlaceholder : placeholder,
7249
8110
  autoComplete: "off",
7250
8111
  spellCheck: false,
7251
8112
  disabled,
7252
8113
  onFocus: () => {
7253
- setOpen(true);
7254
- requestAnimationFrame(() => {
7255
- var _a;
7256
- (_a = inputRef.current) == null ? void 0 : _a.select();
7257
- });
8114
+ openDropdown();
7258
8115
  },
7259
8116
  onChange: (event) => {
7260
8117
  setInputValue(event.target.value);
@@ -7295,7 +8152,7 @@ function SearchableSelectBase({
7295
8152
  }
7296
8153
  },
7297
8154
  className: cn(
7298
- "h-full min-w-0 flex-1 border-0 bg-transparent p-0 text-sm outline-none",
8155
+ "h-full min-w-0 flex-1 border-0 bg-transparent p-0 outline-none",
7299
8156
  "placeholder:text-muted-foreground disabled:cursor-not-allowed",
7300
8157
  searchInputClassName
7301
8158
  )
@@ -7337,76 +8194,7 @@ function SearchableSelectBase({
7337
8194
  ]
7338
8195
  }
7339
8196
  ),
7340
- /* @__PURE__ */ jsx25(
7341
- "div",
7342
- {
7343
- className: cn(
7344
- "absolute left-0 top-full z-50 mt-1 w-full overflow-hidden rounded-xl border border-border bg-popover text-popover-foreground shadow-xl transition",
7345
- !open && "pointer-events-none invisible opacity-0",
7346
- open && "visible opacity-100",
7347
- contentClassName
7348
- ),
7349
- children: /* @__PURE__ */ jsx25(
7350
- "div",
7351
- {
7352
- id: listboxId,
7353
- role: "listbox",
7354
- className: "max-h-72 overflow-y-auto overscroll-contain p-1 [scrollbar-gutter:stable]",
7355
- onWheelCapture: (event) => {
7356
- event.stopPropagation();
7357
- },
7358
- onTouchMoveCapture: (event) => {
7359
- event.stopPropagation();
7360
- },
7361
- children: filteredItems.length === 0 ? /* @__PURE__ */ jsx25("div", { className: "px-3 py-6 text-center text-sm text-muted-foreground", children: emptyText }) : filteredItems.map((item, index) => {
7362
- const isSelected = item.value === currentValue;
7363
- const isActive = index === activeIndex;
7364
- return /* @__PURE__ */ jsxs15(
7365
- "div",
7366
- {
7367
- id: `${listboxId}-option-${index}`,
7368
- role: "option",
7369
- "aria-selected": isSelected,
7370
- "aria-disabled": item.disabled,
7371
- tabIndex: -1,
7372
- onMouseMove: () => {
7373
- if (!item.disabled) {
7374
- setActiveIndex(index);
7375
- }
7376
- },
7377
- onPointerDown: (event) => {
7378
- event.preventDefault();
7379
- event.stopPropagation();
7380
- if (!item.disabled) {
7381
- selectItem(item);
7382
- }
7383
- },
7384
- className: cn(
7385
- "relative flex w-full select-none items-center gap-2 rounded-lg px-3 py-2 text-left text-sm outline-none transition",
7386
- item.disabled ? "pointer-events-none opacity-50" : "cursor-pointer",
7387
- isActive && !item.disabled && "bg-accent text-accent-foreground",
7388
- !isActive && !item.disabled && "hover:bg-accent/70 hover:text-accent-foreground",
7389
- isSelected && "font-medium",
7390
- itemClassName
7391
- ),
7392
- children: [
7393
- /* @__PURE__ */ jsx25("span", { className: "min-w-0 flex-1 truncate", children: item.label }),
7394
- isSelected ? /* @__PURE__ */ jsx25(
7395
- CheckIcon5,
7396
- {
7397
- "aria-hidden": "true",
7398
- className: "h-4 w-4 shrink-0 text-primary"
7399
- }
7400
- ) : null
7401
- ]
7402
- },
7403
- item.value
7404
- );
7405
- })
7406
- }
7407
- )
7408
- }
7409
- )
8197
+ dropdown
7410
8198
  ] });
7411
8199
  }
7412
8200
  var SearchableSelect = React47.memo(
@@ -7421,7 +8209,7 @@ var FormSelect = ({
7421
8209
  rules,
7422
8210
  shouldUnregister,
7423
8211
  defaultValue,
7424
- placeholder = "Seleccionar opci\xF3n",
8212
+ placeholder = "Select an option",
7425
8213
  label,
7426
8214
  requiredLabel,
7427
8215
  className,
@@ -7437,7 +8225,6 @@ var FormSelect = ({
7437
8225
  getOptionLabel = getDefaultOptionLabel,
7438
8226
  getOptionDisabled,
7439
8227
  getOptionData,
7440
- children,
7441
8228
  onChange,
7442
8229
  onChangeItem,
7443
8230
  disabled,
@@ -7446,17 +8233,14 @@ var FormSelect = ({
7446
8233
  variant = "outline",
7447
8234
  invalid,
7448
8235
  searchable = false,
7449
- searchPlaceholder = "Buscar\u2026",
7450
- emptyText = "No hay resultados",
7451
- position = "popper"
8236
+ searchPlaceholder = "Search\u2026",
8237
+ emptyText = "No results",
8238
+ classNameDefault = true
7452
8239
  }) => {
7453
8240
  const form = useFormContext4();
7454
8241
  const controllerControl = control != null ? control : form == null ? void 0 : form.control;
7455
8242
  const sizeClasses = getFormSizeClasses(size, customSize);
7456
- const triggerBase = "relative inline-flex w-full items-center justify-between gap-2 text-foreground outline-none ring-offset-background transition placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50";
7457
- const triggerSizeClass = variant === "flushed" ? sizeClasses.flushedControl : variant === "link" ? sizeClasses.linkControl : sizeClasses.control;
7458
- const contentBase = "z-50 rounded-xl border border-border bg-popover text-popover-foreground shadow-xl outline-none";
7459
- const contentViewport = "[&_[data-radix-select-viewport]]:max-h-72 [&_[data-radix-select-viewport]]:overflow-y-auto [&_[data-radix-select-viewport]]:overscroll-contain [&_[data-radix-select-viewport]]:[scrollbar-gutter:stable]";
8243
+ const triggerSizeClass = getFormControlSizeClass(variant, sizeClasses);
7460
8244
  const normalizedOptions = React48.useMemo(() => {
7461
8245
  if (options) return options;
7462
8246
  return (items != null ? items : []).map((item) => {
@@ -7497,15 +8281,11 @@ var FormSelect = ({
7497
8281
  onChange == null ? void 0 : onChange(value);
7498
8282
  onChangeItem == null ? void 0 : onChangeItem((_a2 = nextOption == null ? void 0 : nextOption.data) != null ? _a2 : null);
7499
8283
  };
7500
- return /* @__PURE__ */ jsxs16(FormItem, { children: [
8284
+ return /* @__PURE__ */ jsxs16(FormItem, { className: itemClassName, children: [
7501
8285
  label ? /* @__PURE__ */ jsxs16(
7502
8286
  FormLabel,
7503
8287
  {
7504
- className: cn(
7505
- "flex items-center gap-0.5",
7506
- sizeClasses.label,
7507
- labelClassName
7508
- ),
8288
+ className: cn("flex items-center gap-0.5", labelClassName),
7509
8289
  children: [
7510
8290
  /* @__PURE__ */ jsx26("span", { children: label }),
7511
8291
  requiredLabel ? /* @__PURE__ */ jsx26(
@@ -7521,7 +8301,7 @@ var FormSelect = ({
7521
8301
  ]
7522
8302
  }
7523
8303
  ) : null,
7524
- searchable ? /* @__PURE__ */ jsx26(
8304
+ searchable ? /* @__PURE__ */ jsx26(FormControl, { children: /* @__PURE__ */ jsx26(
7525
8305
  SearchableSelect,
7526
8306
  {
7527
8307
  items: normalizedOptions,
@@ -7531,93 +8311,47 @@ var FormSelect = ({
7531
8311
  searchPlaceholder,
7532
8312
  emptyText,
7533
8313
  disabled,
7534
- triggerClassName: cn(
7535
- "min-h-10 w-full rounded-xl border border-input bg-input px-3 text-sm shadow-sm",
7536
- "focus-within:border-primary focus-within:ring-2 focus-within:ring-primary/20",
7537
- hasError && "border-destructive ring-destructive/20",
7538
- className
7539
- ),
7540
- contentClassName: cn(
7541
- "z-50 mt-1 max-h-72 w-full overflow-hidden rounded-xl border border-border bg-popover shadow-xl",
7542
- contentClassName
7543
- ),
7544
- itemClassName: cn(sizeClasses.selectItem, itemClassName),
7545
- searchInputClassName: cn(
7546
- "h-full w-full min-w-0 bg-transparent outline-none placeholder:text-muted-foreground",
7547
- searchInputClassName
7548
- ),
8314
+ invalid: hasError,
8315
+ size,
8316
+ customSize,
8317
+ variant,
8318
+ classNameDefault,
8319
+ triggerClassName: className,
8320
+ contentClassName,
8321
+ itemClassName,
8322
+ searchInputClassName,
7549
8323
  onValueChange: (value, option) => {
7550
8324
  var _a2;
7551
8325
  field.onChange(value);
7552
8326
  onChange == null ? void 0 : onChange(value);
7553
- onChangeItem == null ? void 0 : onChangeItem((_a2 = option == null ? void 0 : option.data) != null ? _a2 : null);
8327
+ onChangeItem == null ? void 0 : onChangeItem(
8328
+ (_a2 = option == null ? void 0 : option.data) != null ? _a2 : null
8329
+ );
7554
8330
  field.onBlur();
7555
8331
  }
7556
8332
  }
7557
- ) : /* @__PURE__ */ jsxs16(
8333
+ ) }) : /* @__PURE__ */ jsx26(
7558
8334
  Select2,
7559
8335
  {
7560
8336
  value: (_b = field.value) != null ? _b : "",
7561
8337
  onValueChange: handleValueChange,
7562
8338
  onOpenChange: (nextOpen) => {
7563
- if (!nextOpen) {
7564
- field.onBlur();
7565
- }
8339
+ if (!nextOpen) field.onBlur();
7566
8340
  },
7567
8341
  disabled,
7568
- children: [
7569
- /* @__PURE__ */ jsx26(FormControl, { children: /* @__PURE__ */ jsx26(
7570
- SelectTrigger,
7571
- {
7572
- className: cn(
7573
- triggerBase,
7574
- variants[variant],
7575
- triggerSizeClass,
7576
- hasError && "border-destructive ring-destructive focus:ring-destructive/40",
7577
- className
7578
- ),
7579
- children: /* @__PURE__ */ jsx26(SelectValue, { placeholder })
7580
- }
7581
- ) }),
7582
- /* @__PURE__ */ jsx26(
7583
- SelectContent,
7584
- {
7585
- position,
7586
- sideOffset: 6,
7587
- className: cn(
7588
- contentBase,
7589
- contentViewport,
7590
- "w-(--radix-select-trigger-width) min-w-(--radix-select-trigger-width) overflow-hidden!",
7591
- contentClassName
7592
- ),
7593
- onWheelCapture: (event) => {
7594
- event.stopPropagation();
7595
- },
7596
- onTouchMoveCapture: (event) => {
7597
- event.stopPropagation();
7598
- },
7599
- children: children ? children : normalizedOptions.length > 0 ? normalizedOptions.map((option) => /* @__PURE__ */ jsx26(
7600
- SelectItem,
7601
- {
7602
- value: option.value,
7603
- disabled: option.disabled,
7604
- className: cn(sizeClasses.selectItem, itemClassName),
7605
- children: option.label
7606
- },
7607
- option.value
7608
- )) : /* @__PURE__ */ jsx26(
7609
- "div",
7610
- {
7611
- className: cn(
7612
- "px-3 py-2 text-muted-foreground",
7613
- sizeClasses.message
7614
- ),
7615
- children: emptyText
7616
- }
7617
- )
7618
- }
7619
- )
7620
- ]
8342
+ children: /* @__PURE__ */ jsx26(FormControl, { children: /* @__PURE__ */ jsx26(
8343
+ SelectTrigger,
8344
+ {
8345
+ className: classNameDefault ? cn(
8346
+ formControlBase,
8347
+ formInputVariants[variant],
8348
+ triggerSizeClass,
8349
+ hasError && formControlErrorClass,
8350
+ className
8351
+ ) : className,
8352
+ children: /* @__PURE__ */ jsx26(SelectValue, { placeholder })
8353
+ }
8354
+ ) })
7621
8355
  }
7622
8356
  ),
7623
8357
  fieldError ? /* @__PURE__ */ jsx26(
@@ -7990,7 +8724,7 @@ var Modal = ({
7990
8724
  };
7991
8725
 
7992
8726
  // src/components/navigation-menu.tsx
7993
- import { ChevronDownIcon as ChevronDownIcon3 } from "@radix-ui/react-icons";
8727
+ import { ChevronDownIcon as ChevronDownIcon2 } from "@radix-ui/react-icons";
7994
8728
  import * as NavigationMenuPrimitive from "@radix-ui/react-navigation-menu";
7995
8729
  import { cva as cva6 } from "class-variance-authority";
7996
8730
  import * as React52 from "react";
@@ -8044,7 +8778,7 @@ var NavigationMenuTrigger = React52.forwardRef((_a, ref) => {
8044
8778
  children,
8045
8779
  " ",
8046
8780
  /* @__PURE__ */ jsx31(
8047
- ChevronDownIcon3,
8781
+ ChevronDownIcon2,
8048
8782
  {
8049
8783
  className: "relative top-[1px] ml-1 h-3 w-3 transition duration-300 group-data-[state=open]:rotate-180",
8050
8784
  "aria-hidden": "true"
@@ -8563,7 +9297,7 @@ SearchInput.displayName = "SearchInput";
8563
9297
  import * as SeparatorPrimitive from "@radix-ui/react-separator";
8564
9298
  import * as React59 from "react";
8565
9299
  import { jsx as jsx39 } from "react/jsx-runtime";
8566
- var Separator6 = React59.forwardRef(
9300
+ var Separator5 = React59.forwardRef(
8567
9301
  (_a, ref) => {
8568
9302
  var _b = _a, { className, orientation = "horizontal", decorative = true } = _b, props = __objRest(_b, ["className", "orientation", "decorative"]);
8569
9303
  return /* @__PURE__ */ jsx39(
@@ -8581,7 +9315,7 @@ var Separator6 = React59.forwardRef(
8581
9315
  );
8582
9316
  }
8583
9317
  );
8584
- Separator6.displayName = SeparatorPrimitive.Root.displayName;
9318
+ Separator5.displayName = SeparatorPrimitive.Root.displayName;
8585
9319
 
8586
9320
  // src/components/sheet.tsx
8587
9321
  import * as SheetPrimitive from "@radix-ui/react-dialog";
@@ -9382,24 +10116,10 @@ UiInput.displayName = "UiInput";
9382
10116
  // src/components/ui/select.tsx
9383
10117
  import * as React72 from "react";
9384
10118
  import { Asterisk as Asterisk5 } from "lucide-react";
9385
-
9386
- // src/types/select.ts
9387
- var selectVariants = {
9388
- outline: "rounded-md border border-input bg-input backdrop-blur-sm shadow-sm hover:border-primary/60 focus:border-primary focus:ring-2 focus:ring-primary/20",
9389
- soft: "rounded-md border border-transparent bg-muted/60 shadow-sm hover:bg-muted focus:bg-input/80 focus:ring-2 focus:ring-primary/20",
9390
- ghost: "rounded-md border border-transparent bg-transparent hover:bg-muted/50 focus:ring-2 focus:ring-ring",
9391
- filled: "rounded-md border border-input bg-muted/70 shadow-inner hover:bg-muted focus:bg-input/70 focus:ring-2 focus:ring-primary/20",
9392
- flushed: "rounded-none border-0 border-b border-input px-0 shadow-none focus:border-b-2 focus:border-primary focus:ring-0",
9393
- unstyled: "border-0 shadow-none focus:ring-0",
9394
- link: "h-auto border-0 bg-transparent p-0 text-primary shadow-none underline-offset-4 focus:underline focus:ring-0"
9395
- };
9396
- var variants2 = selectVariants;
9397
-
9398
- // src/components/ui/select.tsx
9399
10119
  import { jsx as jsx54, jsxs as jsxs27 } from "react/jsx-runtime";
9400
10120
  function UiSelect({
9401
10121
  label,
9402
- placeholder,
10122
+ placeholder = "Select an option",
9403
10123
  value,
9404
10124
  defaultValue,
9405
10125
  onChange,
@@ -9415,37 +10135,27 @@ function UiSelect({
9415
10135
  messageClassName,
9416
10136
  requiredLabelClassName,
9417
10137
  size = "md",
10138
+ customSize,
9418
10139
  variant = "outline",
9419
10140
  errorMessage,
9420
- htmlFormItemId
10141
+ htmlFormItemId,
10142
+ position
9421
10143
  }) {
9422
10144
  const generatedId = React72.useId();
9423
10145
  const triggerId = htmlFormItemId != null ? htmlFormItemId : generatedId;
9424
10146
  const messageId = `${triggerId}-message`;
9425
10147
  const hasError = Boolean(errorMessage);
9426
- const triggerBase = "relative inline-flex w-full items-center justify-between text-foreground outline-none ring-offset-background transition placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50";
9427
- const sizeTrigger = {
9428
- sm: "h-9 px-3 text-sm",
9429
- md: "h-10 px-3.5 text-sm",
9430
- lg: "h-11 px-4 text-base"
9431
- };
9432
- const itemSize = {
9433
- sm: "h-8 text-sm",
9434
- md: "h-9 text-sm",
9435
- lg: "h-10 text-base"
9436
- };
9437
- const specialFlushed = variant === "flushed" ? size === "sm" ? "h-9 text-sm" : size === "lg" ? "h-11 text-base" : "h-10 text-sm" : "";
9438
- const specialLink = variant === "link" ? "text-sm" : "";
9439
- return /* @__PURE__ */ jsxs27("div", { className: cn("w-full space-y-1.5", selectClassName), children: [
10148
+ const sizeClasses = getFormSizeClasses(size, customSize);
10149
+ return /* @__PURE__ */ jsxs27("div", { className: cn("w-full space-y-0.5", selectClassName), children: [
9440
10150
  label ? /* @__PURE__ */ jsxs27(
9441
10151
  Label3,
9442
10152
  {
10153
+ htmlFor: triggerId,
9443
10154
  className: cn(
9444
- "inline-flex items-start gap-0.5 text-sm font-medium",
10155
+ "flex items-center gap-0.5 text-sm font-medium -mt-0.75 -pt-1.5",
9445
10156
  hasError && "text-destructive",
9446
10157
  labelClassName
9447
10158
  ),
9448
- htmlFor: triggerId,
9449
10159
  children: [
9450
10160
  /* @__PURE__ */ jsx54("span", { children: label }),
9451
10161
  requiredLabel ? /* @__PURE__ */ jsx54(
@@ -9453,7 +10163,7 @@ function UiSelect({
9453
10163
  {
9454
10164
  "aria-hidden": "true",
9455
10165
  className: cn(
9456
- "mt-0.5 h-3 w-3 shrink-0 text-red-500",
10166
+ "h-3 w-3 shrink-0 text-red-500",
9457
10167
  requiredLabelClassName
9458
10168
  )
9459
10169
  }
@@ -9468,6 +10178,10 @@ function UiSelect({
9468
10178
  defaultValue,
9469
10179
  onValueChange: onChange,
9470
10180
  disabled,
10181
+ size,
10182
+ customSize,
10183
+ variant,
10184
+ invalid: hasError,
9471
10185
  children: [
9472
10186
  /* @__PURE__ */ jsx54(
9473
10187
  SelectTrigger,
@@ -9475,26 +10189,33 @@ function UiSelect({
9475
10189
  id: triggerId,
9476
10190
  "aria-invalid": hasError || void 0,
9477
10191
  "aria-describedby": errorMessage ? messageId : void 0,
9478
- className: cn(
9479
- triggerBase,
9480
- variants2[variant],
9481
- variant === "flushed" ? specialFlushed : variant === "link" ? specialLink : sizeTrigger[size],
9482
- hasError && "border-destructive ring-destructive focus:ring-destructive/40",
9483
- className
9484
- ),
10192
+ className,
9485
10193
  children: /* @__PURE__ */ jsx54(SelectValue, { placeholder })
9486
10194
  }
9487
10195
  ),
9488
- /* @__PURE__ */ jsx54(SelectContent, { className: contentClassName, children: children != null ? children : items == null ? void 0 : items.map((item) => /* @__PURE__ */ jsx54(
9489
- SelectItem,
10196
+ /* @__PURE__ */ jsx54(
10197
+ SelectContent,
9490
10198
  {
9491
- value: item.value,
9492
- disabled: item.disabled,
9493
- className: cn(itemSize[size], itemClassName),
9494
- children: item.label
9495
- },
9496
- item.value
9497
- )) })
10199
+ position,
10200
+ sideOffset: 6,
10201
+ className: cn(
10202
+ "z-50 overflow-hidden rounded-xl border border-border bg-popover text-popover-foreground shadow-xl outline-none",
10203
+ contentClassName
10204
+ ),
10205
+ onWheelCapture: (event) => event.stopPropagation(),
10206
+ onTouchMoveCapture: (event) => event.stopPropagation(),
10207
+ children: children != null ? children : items == null ? void 0 : items.map((item) => /* @__PURE__ */ jsx54(
10208
+ SelectItem,
10209
+ {
10210
+ value: item.value,
10211
+ disabled: item.disabled,
10212
+ className: cn(sizeClasses.selectItem, itemClassName),
10213
+ children: item.label
10214
+ },
10215
+ item.value
10216
+ ))
10217
+ }
10218
+ )
9498
10219
  ]
9499
10220
  }
9500
10221
  ),
@@ -9502,7 +10223,11 @@ function UiSelect({
9502
10223
  "p",
9503
10224
  {
9504
10225
  id: messageId,
9505
- className: cn("text-sm font-medium text-destructive", messageClassName),
10226
+ className: cn(
10227
+ "font-medium text-destructive",
10228
+ sizeClasses.message,
10229
+ messageClassName
10230
+ ),
9506
10231
  children: errorMessage
9507
10232
  }
9508
10233
  ) : null
@@ -9618,18 +10343,18 @@ var UiCheckbox = React73.forwardRef(
9618
10343
  UiCheckbox.displayName = "UiCheckbox";
9619
10344
 
9620
10345
  // src/hooks/use-sidebar.tsx
9621
- import { createContext as createContext5, useContext as useContext6, useState as useState7 } from "react";
10346
+ import { createContext as createContext6, useContext as useContext7, useState as useState8 } from "react";
9622
10347
  import { jsx as jsx56 } from "react/jsx-runtime";
9623
- var SidebarContext = createContext5({
10348
+ var SidebarContext = createContext6({
9624
10349
  isMinimized: false,
9625
10350
  toggle: () => {
9626
10351
  }
9627
10352
  });
9628
- var useSidebar = () => useContext6(SidebarContext);
10353
+ var useSidebar = () => useContext7(SidebarContext);
9629
10354
  var SidebarProvider = ({
9630
10355
  children
9631
10356
  }) => {
9632
- const [isMinimized, setIsMinimized] = useState7(false);
10357
+ const [isMinimized, setIsMinimized] = useState8(false);
9633
10358
  const toggle = () => {
9634
10359
  setIsMinimized(!isMinimized);
9635
10360
  };
@@ -9677,7 +10402,7 @@ var AlertModal = ({
9677
10402
 
9678
10403
  // src/shared/breadcrumbs.tsx
9679
10404
  import { Slash } from "lucide-react";
9680
- import { Fragment as Fragment2 } from "react";
10405
+ import { Fragment } from "react";
9681
10406
  import { jsx as jsx58, jsxs as jsxs30 } from "react/jsx-runtime";
9682
10407
  function Breadcrumbs({
9683
10408
  items,
@@ -9688,7 +10413,7 @@ function Breadcrumbs({
9688
10413
  return /* @__PURE__ */ jsx58(Breadcrumb, { className, children: /* @__PURE__ */ jsx58(BreadcrumbList, { className: classNameList, children: items.map((item, index) => {
9689
10414
  var _a;
9690
10415
  const isLast = index === items.length - 1;
9691
- return /* @__PURE__ */ jsxs30(Fragment2, { children: [
10416
+ return /* @__PURE__ */ jsxs30(Fragment, { children: [
9692
10417
  !isLast ? /* @__PURE__ */ jsx58(BreadcrumbItem, { className: item.className, children: /* @__PURE__ */ jsx58(BreadcrumbLink, { href: (_a = item.link) != null ? _a : "#", children: item.title }) }) : /* @__PURE__ */ jsx58(BreadcrumbItem, { className: item.className, children: /* @__PURE__ */ jsx58(BreadcrumbPage, { children: item.title }) }),
9693
10418
  !isLast ? /* @__PURE__ */ jsx58(BreadcrumbSeparator, { children: separator }) : null
9694
10419
  ] }, `${item.title}-${index}`);
@@ -9696,7 +10421,7 @@ function Breadcrumbs({
9696
10421
  }
9697
10422
 
9698
10423
  // src/shared/data-table.tsx
9699
- import { useMemo as useMemo5 } from "react";
10424
+ import { useMemo as useMemo6 } from "react";
9700
10425
  import { AnimatePresence, motion } from "framer-motion";
9701
10426
  import {
9702
10427
  DoubleArrowLeftIcon,
@@ -9946,7 +10671,7 @@ function DataTable({
9946
10671
  const safePageCount = Math.max(pageCount != null ? pageCount : 1, 1);
9947
10672
  const pageIndex = Math.min(Math.max(page - 1, 0), safePageCount - 1);
9948
10673
  const pageSize = Math.max(perPage, 1);
9949
- const paginationState = useMemo5(
10674
+ const paginationState = useMemo6(
9950
10675
  () => ({ pageIndex, pageSize }),
9951
10676
  [pageIndex, pageSize]
9952
10677
  );
@@ -9963,7 +10688,7 @@ function DataTable({
9963
10688
  autoResetPageIndex: false
9964
10689
  });
9965
10690
  const clickable = !!onClick;
9966
- const pageKey = useMemo5(
10691
+ const pageKey = useMemo6(
9967
10692
  () => `${pageIndex}-${pageSize}-${data.length}`,
9968
10693
  [pageIndex, pageSize, data.length]
9969
10694
  );
@@ -9978,7 +10703,7 @@ function DataTable({
9978
10703
  onPageSizeChange == null ? void 0 : onPageSizeChange(size);
9979
10704
  onPageChange == null ? void 0 : onPageChange(1);
9980
10705
  };
9981
- const ui = useMemo5(() => {
10706
+ const ui = useMemo6(() => {
9982
10707
  var _a;
9983
10708
  const builtIn = (_a = DATA_TABLE_TEMPLATES[template]) != null ? _a : DATA_TABLE_TEMPLATES.neo;
9984
10709
  return mergeSlots(DATA_TABLE_TEMPLATES.neo, builtIn, classNames);
@@ -10111,7 +10836,7 @@ function DataTable({
10111
10836
  children: /* @__PURE__ */ jsx59(SelectValue, { placeholder: `${pageSize}` })
10112
10837
  }
10113
10838
  ),
10114
- /* @__PURE__ */ jsx59(SelectContent, { side: "top", children: pageSizeOptions.map((size) => /* @__PURE__ */ jsx59(SelectItem, { value: `${size}`, children: size }, size)) })
10839
+ /* @__PURE__ */ jsx59(SelectContent, { children: pageSizeOptions.map((size) => /* @__PURE__ */ jsx59(SelectItem, { value: `${size}`, children: size }, size)) })
10115
10840
  ]
10116
10841
  }
10117
10842
  )
@@ -10282,7 +11007,7 @@ function Dropzone({
10282
11007
  // src/shared/fileupload.tsx
10283
11008
  import { AvatarIcon } from "@radix-ui/react-icons";
10284
11009
  import { CameraIcon } from "lucide-react";
10285
- import { useEffect as useEffect7, useState as useState8 } from "react";
11010
+ import { useEffect as useEffect7, useState as useState9 } from "react";
10286
11011
  import { useDropzone as useDropzone2 } from "react-dropzone";
10287
11012
  import { jsx as jsx62, jsxs as jsxs34 } from "react/jsx-runtime";
10288
11013
  function FileUpload({
@@ -10319,7 +11044,7 @@ function FileUpload({
10319
11044
  ) });
10320
11045
  }
10321
11046
  function ImagePreview({ file }) {
10322
- const [objectUrl, setObjectUrl] = useState8(null);
11047
+ const [objectUrl, setObjectUrl] = useState9(null);
10323
11048
  useEffect7(() => {
10324
11049
  const url = URL.createObjectURL(file);
10325
11050
  setObjectUrl(url);
@@ -10635,12 +11360,10 @@ export {
10635
11360
  SelectGroup,
10636
11361
  SelectItem,
10637
11362
  SelectLabel,
10638
- SelectScrollDownButton,
10639
- SelectScrollUpButton,
10640
11363
  SelectSeparator,
10641
11364
  SelectTrigger,
10642
11365
  SelectValue,
10643
- Separator6 as Separator,
11366
+ Separator5 as Separator,
10644
11367
  Sheet,
10645
11368
  SheetClose,
10646
11369
  SheetContent,
@@ -10691,9 +11414,18 @@ export {
10691
11414
  badgeVariants,
10692
11415
  buttonVariants,
10693
11416
  cn,
11417
+ formCompositeControlBase,
11418
+ formCompositeControlErrorClass,
11419
+ formCompositeVariants,
11420
+ formControlBase,
11421
+ formControlErrorClass,
11422
+ formInputVariants,
11423
+ formSizeVariants,
10694
11424
  getDefaultOptionLabel,
10695
11425
  getDefaultOptionValue,
10696
11426
  getErrorMessage,
11427
+ getFormControlSizeClass,
11428
+ getFormSizeClasses,
10697
11429
  getNextEnabledIndex,
10698
11430
  iconButtonVariants,
10699
11431
  navigationMenuTriggerStyle,
@@ -10703,5 +11435,6 @@ export {
10703
11435
  toggleVariants,
10704
11436
  useFormField,
10705
11437
  useSidebar,
10706
- useToast
11438
+ useToast,
11439
+ variants
10707
11440
  };