infinity-ui-elements 1.8.32 → 1.8.40

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
@@ -8,9 +8,9 @@ var reactSpinners = require('react-spinners');
8
8
  var clsx = require('clsx');
9
9
  var tailwindMerge = require('tailwind-merge');
10
10
  var lucideReact = require('lucide-react');
11
+ var reactDom = require('react-dom');
11
12
  var Calendar = require('react-calendar');
12
13
  require('react-calendar/dist/Calendar.css');
13
- var reactDom = require('react-dom');
14
14
  var reactTable = require('@tanstack/react-table');
15
15
 
16
16
  function _interopNamespaceDefault(e) {
@@ -2098,16 +2098,95 @@ const formatDateDefault = (date) => {
2098
2098
  day: "numeric",
2099
2099
  });
2100
2100
  };
2101
- const DatePicker = React__namespace.forwardRef(({ className, value: controlledValue, defaultValue, onChange, placeholder = "Select a date", label, helperText, errorText, successText, validationState = "none", isDisabled = false, isRequired = false, isOptional = false, size = "medium", showClearButton = true, onClear, containerClassName, labelClassName, triggerClassName, calendarClassName, minDate, maxDate, formatDate = formatDateDefault, infoHeading, infoDescription, LinkComponent, linkText, linkHref, onLinkClick, ...props }, ref) => {
2101
+ // Helper function to format date based on format string
2102
+ const formatDateByPattern = (date, format) => {
2103
+ const day = date.getDate();
2104
+ const month = date.getMonth() + 1; // getMonth() returns 0-11
2105
+ const year = date.getFullYear();
2106
+ const monthNames = [
2107
+ "Jan",
2108
+ "Feb",
2109
+ "Mar",
2110
+ "Apr",
2111
+ "May",
2112
+ "Jun",
2113
+ "Jul",
2114
+ "Aug",
2115
+ "Sep",
2116
+ "Oct",
2117
+ "Nov",
2118
+ "Dec",
2119
+ ];
2120
+ const monthNamesFull = [
2121
+ "January",
2122
+ "February",
2123
+ "March",
2124
+ "April",
2125
+ "May",
2126
+ "June",
2127
+ "July",
2128
+ "August",
2129
+ "September",
2130
+ "October",
2131
+ "November",
2132
+ "December",
2133
+ ];
2134
+ const dayNames = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
2135
+ const dayNamesFull = [
2136
+ "Sunday",
2137
+ "Monday",
2138
+ "Tuesday",
2139
+ "Wednesday",
2140
+ "Thursday",
2141
+ "Friday",
2142
+ "Saturday",
2143
+ ];
2144
+ // Pad numbers with leading zeros
2145
+ const pad = (n, length = 2) => {
2146
+ const str = n.toString();
2147
+ if (str.length >= length)
2148
+ return str;
2149
+ return "0".repeat(length - str.length) + str;
2150
+ };
2151
+ let formatted = format;
2152
+ // Replace format patterns
2153
+ formatted = formatted.replace(/YYYY/g, year.toString());
2154
+ formatted = formatted.replace(/YY/g, year.toString().slice(-2));
2155
+ formatted = formatted.replace(/MMMM/g, monthNamesFull[month - 1]);
2156
+ formatted = formatted.replace(/MMM/g, monthNames[month - 1]);
2157
+ formatted = formatted.replace(/MM/g, pad(month));
2158
+ formatted = formatted.replace(/M/g, month.toString());
2159
+ formatted = formatted.replace(/DDDD/g, dayNamesFull[date.getDay()]);
2160
+ formatted = formatted.replace(/DDD/g, dayNames[date.getDay()]);
2161
+ formatted = formatted.replace(/DD/g, pad(day));
2162
+ formatted = formatted.replace(/D/g, day.toString());
2163
+ return formatted;
2164
+ };
2165
+ const DatePicker = React__namespace.forwardRef(({ className, value: controlledValue, defaultValue, onChange, placeholder = "Select a date", label, helperText, errorText, successText, validationState = "none", isDisabled = false, isRequired = false, isOptional = false, size = "medium", showClearButton = true, onClear, containerClassName, labelClassName, triggerClassName, calendarClassName, minDate, maxDate, formatDate = formatDateDefault, format, infoHeading, infoDescription, LinkComponent, linkText, linkHref, onLinkClick, ...props }, ref) => {
2102
2166
  const [uncontrolledValue, setUncontrolledValue] = React__namespace.useState(parseDate(defaultValue));
2103
2167
  const [isOpen, setIsOpen] = React__namespace.useState(false);
2104
2168
  const datePickerRef = React__namespace.useRef(null);
2105
2169
  const calendarRef = React__namespace.useRef(null);
2106
2170
  const [dropdownPlacement, setDropdownPlacement] = React__namespace.useState("bottom");
2171
+ const [isInsideModal, setIsInsideModal] = React__namespace.useState(false);
2172
+ const [position, setPosition] = React__namespace.useState({
2173
+ top: 0,
2174
+ left: 0,
2175
+ width: 0,
2176
+ bottom: 0,
2177
+ });
2178
+ const [calendarHeight, setCalendarHeight] = React__namespace.useState(300); // Default height estimate
2107
2179
  const value = controlledValue !== undefined
2108
2180
  ? parseDate(controlledValue)
2109
2181
  : uncontrolledValue;
2110
2182
  const hasValue = value !== null;
2183
+ // Create a formatter function that uses format prop if provided, otherwise formatDate
2184
+ const formatDateValue = React__namespace.useCallback((date) => {
2185
+ if (format) {
2186
+ return formatDateByPattern(date, format);
2187
+ }
2188
+ return formatDate(date);
2189
+ }, [format, formatDate]);
2111
2190
  // Determine which helper text to show
2112
2191
  const displayHelperText = errorText || successText || helperText;
2113
2192
  const currentValidationState = errorText
@@ -2179,13 +2258,74 @@ const DatePicker = React__namespace.forwardRef(({ className, value: controlledVa
2179
2258
  setDropdownPlacement("top");
2180
2259
  }
2181
2260
  }, []);
2261
+ // Check if date picker is inside a modal
2262
+ React__namespace.useEffect(() => {
2263
+ if (isOpen && datePickerRef.current) {
2264
+ let element = datePickerRef.current;
2265
+ let foundModal = false;
2266
+ while (element && !foundModal) {
2267
+ const styles = window.getComputedStyle(element);
2268
+ const zIndex = parseInt(styles.zIndex, 10);
2269
+ // Check if element has modal z-index (10000) or is a modal container
2270
+ if (zIndex === 10000 || element.getAttribute("role") === "dialog") {
2271
+ foundModal = true;
2272
+ setIsInsideModal(true);
2273
+ break;
2274
+ }
2275
+ element = element.parentElement;
2276
+ }
2277
+ if (!foundModal) {
2278
+ setIsInsideModal(false);
2279
+ }
2280
+ }
2281
+ }, [isOpen]);
2282
+ // Update position when calendar opens or window resizes
2283
+ React__namespace.useEffect(() => {
2284
+ if (isOpen && datePickerRef.current) {
2285
+ const updatePosition = () => {
2286
+ const rect = datePickerRef.current?.getBoundingClientRect();
2287
+ if (rect) {
2288
+ setPosition({
2289
+ top: rect.top,
2290
+ left: rect.left,
2291
+ width: rect.width,
2292
+ bottom: rect.bottom,
2293
+ });
2294
+ // Update dropdown placement based on available space
2295
+ updateDropdownPlacement();
2296
+ }
2297
+ };
2298
+ updatePosition();
2299
+ window.addEventListener("resize", updatePosition);
2300
+ window.addEventListener("scroll", updatePosition, true);
2301
+ return () => {
2302
+ window.removeEventListener("resize", updatePosition);
2303
+ window.removeEventListener("scroll", updatePosition, true);
2304
+ };
2305
+ }
2306
+ }, [isOpen, updateDropdownPlacement]);
2182
2307
  React__namespace.useEffect(() => {
2183
2308
  if (!isOpen)
2184
2309
  return;
2185
2310
  if (typeof window === "undefined")
2186
2311
  return;
2187
- let rafId = requestAnimationFrame(updateDropdownPlacement);
2188
- const handleUpdate = () => updateDropdownPlacement();
2312
+ // Use requestAnimationFrame to ensure calendar is rendered before calculating placement
2313
+ let rafId = requestAnimationFrame(() => {
2314
+ updateDropdownPlacement();
2315
+ });
2316
+ const handleUpdate = () => {
2317
+ updateDropdownPlacement();
2318
+ // Also update position when scrolling/resizing
2319
+ if (datePickerRef.current) {
2320
+ const rect = datePickerRef.current.getBoundingClientRect();
2321
+ setPosition({
2322
+ top: rect.top,
2323
+ left: rect.left,
2324
+ width: rect.width,
2325
+ bottom: rect.bottom,
2326
+ });
2327
+ }
2328
+ };
2189
2329
  window.addEventListener("resize", handleUpdate);
2190
2330
  window.addEventListener("scroll", handleUpdate, true);
2191
2331
  return () => {
@@ -2196,14 +2336,44 @@ const DatePicker = React__namespace.forwardRef(({ className, value: controlledVa
2196
2336
  }, [isOpen, updateDropdownPlacement]);
2197
2337
  React__namespace.useEffect(() => {
2198
2338
  if (isOpen) {
2199
- updateDropdownPlacement();
2339
+ // Delay to ensure calendar is rendered
2340
+ const timer = setTimeout(() => {
2341
+ updateDropdownPlacement();
2342
+ }, 0);
2343
+ return () => clearTimeout(timer);
2200
2344
  }
2201
2345
  }, [isOpen, updateDropdownPlacement]);
2346
+ // Measure calendar height and adjust position after render
2347
+ React__namespace.useLayoutEffect(() => {
2348
+ if (isOpen && calendarRef.current && datePickerRef.current) {
2349
+ const measuredHeight = calendarRef.current.offsetHeight;
2350
+ setCalendarHeight(measuredHeight);
2351
+ const rect = datePickerRef.current.getBoundingClientRect();
2352
+ // Recalculate placement if needed based on actual calendar height
2353
+ const spaceBelow = window.innerHeight - rect.bottom;
2354
+ const spaceAbove = rect.top;
2355
+ if (measuredHeight > spaceBelow && spaceAbove > spaceBelow) {
2356
+ setDropdownPlacement("top");
2357
+ }
2358
+ else {
2359
+ setDropdownPlacement("bottom");
2360
+ }
2361
+ // Update position
2362
+ setPosition({
2363
+ top: rect.top,
2364
+ left: rect.left,
2365
+ width: rect.width,
2366
+ bottom: rect.bottom,
2367
+ });
2368
+ }
2369
+ }, [isOpen]);
2202
2370
  // Close calendar when clicking outside
2203
2371
  React__namespace.useEffect(() => {
2204
2372
  const handleClickOutside = (event) => {
2205
2373
  if (datePickerRef.current &&
2206
- !datePickerRef.current.contains(event.target)) {
2374
+ !datePickerRef.current.contains(event.target) &&
2375
+ calendarRef.current &&
2376
+ !calendarRef.current.contains(event.target)) {
2207
2377
  handleOpenChange(false);
2208
2378
  }
2209
2379
  };
@@ -2251,9 +2421,23 @@ const DatePicker = React__namespace.forwardRef(({ className, value: controlledVa
2251
2421
  ? "text-feedback-ink-positive-intense"
2252
2422
  : currentValidationState === "negative"
2253
2423
  ? "text-feedback-ink-negative-subtle"
2254
- : "text-surface-ink-neutral-muted") }), jsxRuntime.jsx("span", { className: cn("flex-1 text-left truncate", !hasValue && "text-surface-ink-neutral-muted", isDisabled && "text-surface-ink-neutral-disabled"), children: hasValue && value ? formatDate(value) : placeholder }), showClearButton && hasValue && !isDisabled && (jsxRuntime.jsx("button", { type: "button", onClick: handleClear, className: "shrink-0 flex items-center justify-center text-surface-ink-neutral-muted hover:text-surface-ink-neutral-normal transition-colors", tabIndex: -1, "aria-label": "Clear date", children: jsxRuntime.jsx(lucideReact.X, { className: "w-4 h-4" }) })), isOpen && !isDisabled && (jsxRuntime.jsx("div", { ref: calendarRef, className: cn("absolute z-50 left-0 bg-surface-fill-neutral-intense rounded-large shadow-lg p-4", dropdownPlacement === "bottom"
2255
- ? "top-full mt-1"
2256
- : "bottom-full mb-1", calendarClassName), onClick: (e) => e.stopPropagation(), children: jsxRuntime.jsx("div", { className: "react-calendar-wrapper w-fit", children: jsxRuntime.jsx(Calendar, { onChange: handleCalendarChange, value: value ?? null, minDate: minDateParsed ?? undefined, maxDate: maxDateParsed ?? undefined, locale: "en-US", formatShortWeekday: (locale, date) => {
2424
+ : "text-surface-ink-neutral-muted") }), jsxRuntime.jsx("span", { className: cn("flex-1 text-left truncate", !hasValue && "text-surface-ink-neutral-muted", isDisabled && "text-surface-ink-neutral-disabled"), children: hasValue && value ? formatDateValue(value) : placeholder }), showClearButton && hasValue && !isDisabled && (jsxRuntime.jsx("button", { type: "button", onClick: handleClear, className: "shrink-0 flex items-center justify-center text-surface-ink-neutral-muted hover:text-surface-ink-neutral-normal transition-colors", tabIndex: -1, "aria-label": "Clear date", children: jsxRuntime.jsx(lucideReact.X, { className: "w-4 h-4" }) }))] }), jsxRuntime.jsx(FormFooter, { helperText: displayHelperText, validationState: currentValidationState === "none"
2425
+ ? "default"
2426
+ : currentValidationState, size: size, isDisabled: isDisabled, className: "mt-1" }), typeof document !== "undefined" &&
2427
+ isOpen &&
2428
+ !isDisabled &&
2429
+ (() => {
2430
+ // Calculate calendar position using fixed positioning (viewport-relative)
2431
+ const gap = 4; // 4px gap between trigger and calendar
2432
+ const calendarTop = dropdownPlacement === "bottom"
2433
+ ? position.bottom + gap
2434
+ : position.top - calendarHeight - gap;
2435
+ const calendarPopup = (jsxRuntime.jsx("div", { ref: calendarRef, style: {
2436
+ position: "fixed",
2437
+ top: `${calendarTop}px`,
2438
+ left: `${position.left}px`,
2439
+ zIndex: isInsideModal ? 10001 : 9999,
2440
+ }, className: cn("bg-surface-fill-neutral-intense rounded-large shadow-lg p-4 w-fit", calendarClassName), onClick: (e) => e.stopPropagation(), children: jsxRuntime.jsx("div", { className: "react-calendar-wrapper w-fit", children: jsxRuntime.jsx(Calendar, { onChange: handleCalendarChange, value: value ?? null, minDate: minDateParsed ?? undefined, maxDate: maxDateParsed ?? undefined, locale: "en-US", formatShortWeekday: (locale, date) => {
2257
2441
  const weekdayNames = [
2258
2442
  "Su",
2259
2443
  "Mo",
@@ -2264,9 +2448,9 @@ const DatePicker = React__namespace.forwardRef(({ className, value: controlledVa
2264
2448
  "Sa",
2265
2449
  ];
2266
2450
  return weekdayNames[date.getDay()];
2267
- } }) }) }))] }), jsxRuntime.jsx(FormFooter, { helperText: displayHelperText, validationState: currentValidationState === "none"
2268
- ? "default"
2269
- : currentValidationState, size: size, isDisabled: isDisabled, className: "mt-1" })] }));
2451
+ } }) }) }));
2452
+ return reactDom.createPortal(calendarPopup, document.body);
2453
+ })()] }));
2270
2454
  });
2271
2455
  DatePicker.displayName = "DatePicker";
2272
2456
 
@@ -3718,7 +3902,7 @@ const selectTriggerVariants = classVarianceAuthority.cva("flex items-center gap-
3718
3902
  isDisabled: false,
3719
3903
  },
3720
3904
  });
3721
- 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) => {
3905
+ 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, position = "suffix", label, helperText, errorText, successText, validationState = "none", isDisabled = false, isRequired = false, isOptional = false, size = "medium", containerClassName, labelClassName, inputClassName, className, ...textFieldProps }, ref) => {
3722
3906
  const [uncontrolledTextValue, setUncontrolledTextValue] = React__namespace.useState(defaultTextValue || "");
3723
3907
  const [uncontrolledSelectValue, setUncontrolledSelectValue] = React__namespace.useState(defaultSelectValue);
3724
3908
  const [isSelectOpen, setIsSelectOpen] = React__namespace.useState(false);
@@ -3873,12 +4057,14 @@ const SelectTextField = React__namespace.forwardRef(({ textValue: controlledText
3873
4057
  gap: "gap-3",
3874
4058
  },
3875
4059
  };
3876
- // Create the select suffix component
3877
- const selectSuffix = (jsxRuntime.jsxs("div", { className: "relative flex items-center h-full", children: [jsxRuntime.jsxs("div", { ref: selectRef, className: cn(selectTriggerVariants({
4060
+ // Create the select component (prefix or suffix)
4061
+ const selectComponent = (jsxRuntime.jsxs("div", { className: cn("relative flex items-stretch h-full"), children: [jsxRuntime.jsxs("div", { ref: selectRef, className: cn(selectTriggerVariants({
3878
4062
  size,
3879
4063
  validationState: currentValidationState,
3880
4064
  isDisabled,
3881
- }), "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"
4065
+ }), "h-full flex items-center self-stretch", position === "prefix"
4066
+ ? "border-r border-action-outline-neutral-faded"
4067
+ : "border-l border-action-outline-neutral-faded", selectTriggerClassName, position === "prefix" ? "pr-4" : "pl-4"), 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"
3882
4068
  ? "w-3 h-3"
3883
4069
  : size === "medium"
3884
4070
  ? "w-3.5 h-3.5"
@@ -3888,10 +4074,12 @@ const SelectTextField = React__namespace.forwardRef(({ textValue: controlledText
3888
4074
  ? "text-feedback-ink-positive-intense"
3889
4075
  : currentValidationState === "negative"
3890
4076
  ? "text-feedback-ink-negative-subtle"
3891
- : "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"
3892
- ? "top-full mt-1"
4077
+ : "text-surface-ink-neutral-muted", isSelectOpen && "transform rotate-180") })] }), isSelectOpen && !isDisabled && (jsxRuntime.jsx("div", { ref: dropdownContainerRef, className: cn("absolute z-50", position === "prefix" ? "left-[-12px]" : "right-[-12px]", dropdownPlacement === "bottom"
4078
+ ? "top-[30px] mt-1"
3893
4079
  : "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 }) }))] }));
3894
- 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"
4080
+ 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, ...(position === "prefix"
4081
+ ? { prefix: selectComponent }
4082
+ : { suffix: selectComponent }), 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"
3895
4083
  ? "default"
3896
4084
  : currentValidationState, size: size, isDisabled: isDisabled, className: "mt-1" })] }));
3897
4085
  });