infinity-ui-elements 1.8.26 → 1.8.28

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
@@ -3222,8 +3222,21 @@ const defaultFilter = (item, query) => {
3222
3222
  return (item.label?.toLowerCase()?.includes(searchQuery) ||
3223
3223
  (item.description?.toLowerCase()?.includes(searchQuery) ?? false));
3224
3224
  };
3225
- const SearchableDropdown = React__namespace.forwardRef(({ className, items = [], sectionHeading, isLoading = false, emptyTitle = "No Search Results Found", emptyDescription = "Add description of what the user can search for here.", emptyLinkText = "Link to support site", onEmptyLinkClick, primaryButtonText, secondaryButtonText, onPrimaryClick, onSecondaryClick, dropdownWidth = "full", showChevron = false, emptyIcon, disableFooter = false, footerLayout = "horizontal", onSearchChange, onItemSelect, filterFunction = defaultFilter, searchValue: controlledSearchValue, defaultSearchValue = "", dropdownClassName, minSearchLength = 0, showOnFocus = true, showAddNew = false, showAddNewIfDoesNotMatch = true, onAddNew, containerClassName, ...textFieldProps }, ref) => {
3226
- const [uncontrolledSearchValue, setUncontrolledSearchValue] = React__namespace.useState(defaultSearchValue);
3225
+ const SearchableDropdown = React__namespace.forwardRef(({ className, items = [], sectionHeading, isLoading = false, emptyTitle = "No Search Results Found", emptyDescription = "Add description of what the user can search for here.", emptyLinkText = "Link to support site", onEmptyLinkClick, primaryButtonText, secondaryButtonText, onPrimaryClick, onSecondaryClick, dropdownWidth = "full", showChevron = false, emptyIcon, disableFooter = false, footerLayout = "horizontal", onSearchChange, onItemSelect, filterFunction = defaultFilter, searchValue: controlledSearchValue, defaultSearchValue = "", dropdownClassName, minSearchLength = 0, showOnFocus = true, showAddNew = false, showAddNewIfDoesNotMatch = true, onAddNew, containerClassName, value: controlledValue, defaultValue, onChange, ...textFieldProps }, ref) => {
3226
+ // Find the selected item based on value/defaultValue
3227
+ const findSelectedItem = React__namespace.useCallback((val) => {
3228
+ if (val === undefined || val === "")
3229
+ return undefined;
3230
+ return items.find((item) => item.value === val);
3231
+ }, [items]);
3232
+ // Initialize uncontrolled value state
3233
+ const initialValue = controlledValue !== undefined ? controlledValue : defaultValue;
3234
+ const initialSelectedItem = findSelectedItem(initialValue);
3235
+ const initialSearchValue = initialSelectedItem
3236
+ ? initialSelectedItem.label
3237
+ : defaultSearchValue;
3238
+ const [uncontrolledSearchValue, setUncontrolledSearchValue] = React__namespace.useState(initialSearchValue);
3239
+ const [uncontrolledValue, setUncontrolledValue] = React__namespace.useState(defaultValue);
3227
3240
  const [isOpen, setIsOpen] = React__namespace.useState(false);
3228
3241
  const [focusedIndex, setFocusedIndex] = React__namespace.useState(-1);
3229
3242
  const [isInsideModal, setIsInsideModal] = React__namespace.useState(false);
@@ -3236,6 +3249,33 @@ const SearchableDropdown = React__namespace.forwardRef(({ className, items = [],
3236
3249
  width: 0,
3237
3250
  });
3238
3251
  React__namespace.useImperativeHandle(ref, () => inputRef.current);
3252
+ // Determine current value (controlled or uncontrolled)
3253
+ const value = controlledValue !== undefined ? controlledValue : uncontrolledValue;
3254
+ // Sync search value when value prop changes
3255
+ React__namespace.useEffect(() => {
3256
+ const selectedItem = findSelectedItem(value);
3257
+ if (selectedItem) {
3258
+ const newSearchValue = selectedItem.label;
3259
+ if (controlledSearchValue === undefined) {
3260
+ setUncontrolledSearchValue(newSearchValue);
3261
+ }
3262
+ // If controlled, we still need to call onSearchChange to notify parent
3263
+ // but only if the search value is different
3264
+ if (controlledSearchValue !== undefined &&
3265
+ controlledSearchValue !== newSearchValue) {
3266
+ onSearchChange?.(newSearchValue);
3267
+ }
3268
+ }
3269
+ else if (value === undefined || value === "") {
3270
+ // If value is cleared, clear search value too
3271
+ if (controlledSearchValue === undefined) {
3272
+ setUncontrolledSearchValue("");
3273
+ }
3274
+ else {
3275
+ onSearchChange?.("");
3276
+ }
3277
+ }
3278
+ }, [value, findSelectedItem, controlledSearchValue, onSearchChange]);
3239
3279
  // Check if dropdown is inside a modal
3240
3280
  React__namespace.useEffect(() => {
3241
3281
  if (isOpen && dropdownRef.current) {
@@ -3277,6 +3317,15 @@ const SearchableDropdown = React__namespace.forwardRef(({ className, items = [],
3277
3317
  setUncontrolledSearchValue(newValue);
3278
3318
  }
3279
3319
  onSearchChange?.(newValue);
3320
+ // If user is typing and the search value no longer matches the selected item's label,
3321
+ // clear the value to indicate no item is selected
3322
+ const selectedItem = findSelectedItem(value);
3323
+ if (selectedItem && selectedItem.label !== newValue) {
3324
+ if (controlledValue === undefined) {
3325
+ setUncontrolledValue(undefined);
3326
+ }
3327
+ onChange?.(undefined, undefined);
3328
+ }
3280
3329
  // Show dropdown if minimum search length is met
3281
3330
  if (newValue.length >= minSearchLength) {
3282
3331
  setIsOpen(true);
@@ -3292,9 +3341,19 @@ const SearchableDropdown = React__namespace.forwardRef(({ className, items = [],
3292
3341
  };
3293
3342
  const handleItemSelect = (item) => {
3294
3343
  onItemSelect?.(item);
3344
+ // Update search value
3295
3345
  if (controlledSearchValue === undefined) {
3296
3346
  setUncontrolledSearchValue(item.label);
3297
3347
  }
3348
+ else {
3349
+ onSearchChange?.(item.label);
3350
+ }
3351
+ // Update value (controlled or uncontrolled)
3352
+ if (controlledValue === undefined) {
3353
+ setUncontrolledValue(item.value);
3354
+ }
3355
+ // Call onChange callback
3356
+ onChange?.(item.value, item);
3298
3357
  setIsOpen(false);
3299
3358
  inputRef.current?.focus();
3300
3359
  };
@@ -3991,6 +4050,7 @@ function TableComponent({ className, wrapperClassName, containerClassName, varia
3991
4050
  maxHeight: typeof maxHeight === "number" ? `${maxHeight}px` : maxHeight,
3992
4051
  };
3993
4052
  }, [maxHeight]);
4053
+ // Resolve loading state: prefer 'loading' prop, fallback to 'isLoading' for backward compatibility
3994
4054
  const resolvedLoading = typeof loading === "boolean" ? loading : Boolean(isLoading);
3995
4055
  const skeletonRowCount = loadingSkeletonRows ?? 5;
3996
4056
  const sizeKey = size || "medium";
@@ -4041,6 +4101,7 @@ function TableComponent({ className, wrapperClassName, containerClassName, varia
4041
4101
  onRowClick(row);
4042
4102
  }
4043
4103
  }, [onRowClick]);
4104
+ // ==================== Render Helpers ====================
4044
4105
  const renderEmptyState = () => {
4045
4106
  if (emptyComponent)
4046
4107
  return emptyComponent;