@jobber/components 6.112.2 → 6.113.0

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.
@@ -1,5 +1,5 @@
1
1
  import React__default, { useState, useRef, useEffect, useCallback, useMemo, forwardRef } from 'react';
2
- import { u as useFloating, b as autoUpdate, o as offset, f as flip, c as size, t as useClick, e as useListNavigation, d as useDismiss, g as useInteractions, v as useTransitionStyles, F as FloatingPortal, q as FloatingFocusManager } from '../floating-ui.react-es.js';
2
+ import { u as useFloating, b as autoUpdate, o as offset, f as flip, c as size, t as useClick, e as useListNavigation, d as useDismiss, g as useInteractions, F as FloatingPortal, q as FloatingFocusManager, v as useTransitionStyles } from '../floating-ui.react-es.js';
3
3
  import classnames from 'classnames';
4
4
  import { tokens } from '@jobber/design';
5
5
  import { useCallbackRef, useDebounce, useSafeLayoutEffect, useIsMounted, useOnKeyDown } from '@jobber/hooks';
@@ -8,23 +8,27 @@ import { H as Heading } from '../Heading-es.js';
8
8
  import { T as Text } from '../Text-es.js';
9
9
  import { T as Typography } from '../Typography-es.js';
10
10
  import { I as Icon } from '../Icon-es.js';
11
- import { InputText } from '../InputText/index.mjs';
12
11
  import { G as Glimmer } from '../Glimmer-es.js';
13
- import { n as mergeRefs } from '../FormField-es.js';
14
- import { f as filterDataAttributes } from '../filterDataAttributes-es.js';
12
+ import { InputText } from '../InputText/index.mjs';
13
+ import { n as mergeRefs, f as FormFieldWrapper } from '../FormField-es.js';
15
14
  import { _ as __rest, a as __awaiter } from '../tslib.es6-es.js';
15
+ import 'react-hook-form';
16
+ import '../Button-es.js';
17
+ import { f as filterDataAttributes } from '../filterDataAttributes-es.js';
16
18
  import 'react/jsx-runtime';
17
19
  import 'react-dom';
18
- import 'react-hook-form';
20
+ import '../Content-es.js';
19
21
  import 'framer-motion';
20
- import '../Button-es.js';
21
- import 'react-router-dom';
22
22
  import '../useFormFieldFocus-es.js';
23
23
  import '../InputValidation-es.js';
24
24
  import '../Spinner-es.js';
25
- import '../Content-es.js';
25
+ import 'react-router-dom';
26
26
 
27
- var styles$1 = {"list":"_37kZB-nYE08-","loadingList":"ULib3TUQja0-","option":"h5-1Pp0eRyo-","defaultOptionContent":"iBkyj85vd-E-","icon":"I6wAbSJJHNQ-","optionActive":"_4yhnonWAWRY-","actionActive":"oGLMF6n8C74-","action":"LBrwH6TEUYA-","section":"DDOv4DR8bJQ-","emptyStateMessage":"Twgjn26oldE-","stickyTop":"mc1-CEwZtHE-","scrollRegion":"kOR88SFNOn0-","persistentHeader":"_0O-kEf3h9ZI-","persistentFooter":"rQ9ZS7Rb7Z4-","textPersistent":"vxk57ZhP8GU-","spinning":"_0d8hyvaCPAw-"};
27
+ const AUTOCOMPLETE_MAX_HEIGHT$1 = 300;
28
+ /** Stable empty array for cleared/empty selection state. Reuse to avoid reference churn. */
29
+ const EMPTY_SELECTED_VALUES = [];
30
+
31
+ var styles$1 = {"list":"_37kZB-nYE08-","loadingList":"ULib3TUQja0-","option":"h5-1Pp0eRyo-","defaultOptionContent":"iBkyj85vd-E-","icon":"I6wAbSJJHNQ-","optionActive":"_4yhnonWAWRY-","actionActive":"oGLMF6n8C74-","action":"LBrwH6TEUYA-","section":"DDOv4DR8bJQ-","emptyStateMessage":"Twgjn26oldE-","stickyTop":"mc1-CEwZtHE-","scrollRegion":"kOR88SFNOn0-","persistentHeader":"_0O-kEf3h9ZI-","persistentFooter":"rQ9ZS7Rb7Z4-","textPersistent":"vxk57ZhP8GU-","multiSelectField":"AWoK6-P8fFE-","chipArea":"zJm0oR5x4qY-","inlineInput":"Oa26ZaVEi3g-","selectionChip":"IarOrfyYExE-","selectionChipActive":"pmtAk9HEhF4-","selectionChipDisabled":"nmXqlAV-DJo-","chipDismiss":"SmrmwoOlZDo-","limitText":"pqwAJ8VczCU-","spinning":"_0d8hyvaCPAw-"};
28
32
 
29
33
  function flattenMenu(menu) {
30
34
  const optionItems = [];
@@ -126,8 +130,8 @@ function invokeActiveItemOnEnter(event, activeIndex, renderable, onSelect, onAct
126
130
  }
127
131
 
128
132
  const MENU_OFFSET = tokens["space-small"];
129
- const AUTOCOMPLETE_MAX_HEIGHT$1 = 300;
130
- function useAutocompleteListNav({ navigableCount, shouldResetActiveIndexOnClose, onMenuClose, selectedIndex, readOnly = false, }) {
133
+ const AUTOCOMPLETE_MAX_HEIGHT = 300;
134
+ function useAutocompleteListNav({ navigableCount, shouldResetActiveIndexOnClose, onMenuOpen, onMenuClose, selectedIndex, readOnly = false, disabled = false, outsidePressExcludeSelector, }) {
131
135
  const [open, setOpen] = useState(false);
132
136
  const [activeIndex, setActiveIndex] = useState(null);
133
137
  const listRef = useRef([]);
@@ -137,7 +141,10 @@ function useAutocompleteListNav({ navigableCount, shouldResetActiveIndexOnClose,
137
141
  open,
138
142
  onOpenChange: (isOpen, _event, reason) => {
139
143
  setOpen(isOpen);
140
- if (isOpen === false) {
144
+ if (isOpen) {
145
+ onMenuOpen === null || onMenuOpen === void 0 ? void 0 : onMenuOpen();
146
+ }
147
+ else {
141
148
  if (shouldResetActiveIndexOnClose === null || shouldResetActiveIndexOnClose === void 0 ? void 0 : shouldResetActiveIndexOnClose()) {
142
149
  setActiveIndex(null);
143
150
  }
@@ -150,7 +157,7 @@ function useAutocompleteListNav({ navigableCount, shouldResetActiveIndexOnClose,
150
157
  size({
151
158
  apply({ availableHeight, elements }) {
152
159
  const maxHeight = calculateMaxHeight(availableHeight, {
153
- maxHeight: AUTOCOMPLETE_MAX_HEIGHT$1,
160
+ maxHeight: AUTOCOMPLETE_MAX_HEIGHT,
154
161
  });
155
162
  Object.assign(elements.floating.style, {
156
163
  maxHeight: `${maxHeight}px`,
@@ -159,8 +166,9 @@ function useAutocompleteListNav({ navigableCount, shouldResetActiveIndexOnClose,
159
166
  }),
160
167
  ],
161
168
  });
169
+ const enabled = !readOnly && !disabled;
162
170
  const click = useClick(context, {
163
- enabled: !readOnly,
171
+ enabled,
164
172
  toggle: false, // Only open, never close on click
165
173
  });
166
174
  const listNav = useListNavigation(context, {
@@ -180,7 +188,16 @@ function useAutocompleteListNav({ navigableCount, shouldResetActiveIndexOnClose,
180
188
  focusItemOnHover: false,
181
189
  });
182
190
  const dismiss = useDismiss(context, {
183
- outsidePress: true,
191
+ outsidePress: outsidePressExcludeSelector
192
+ ? (event) => {
193
+ var _a, _b, _c, _d;
194
+ const target = event.target;
195
+ const insideRef = (_b = (_a = context.elements.domReference) === null || _a === void 0 ? void 0 : _a.contains(target)) !== null && _b !== void 0 ? _b : false;
196
+ const insideFloating = (_d = (_c = context.elements.floating) === null || _c === void 0 ? void 0 : _c.contains(target)) !== null && _d !== void 0 ? _d : false;
197
+ const insideExclude = event.target.closest(outsidePressExcludeSelector);
198
+ return !(insideRef || insideFloating || insideExclude);
199
+ }
200
+ : true,
184
201
  escapeKey: true,
185
202
  outsidePressEvent: "click",
186
203
  });
@@ -237,8 +254,8 @@ function createInteractionPointerDownHandler(isHandlingMenuInteractionRef) {
237
254
  // Keeping this hook cohesive improves readability by centralizing related
238
255
  // interactions and state transitions.
239
256
  // eslint-disable-next-line max-statements
240
- function useAutocomplete(props) {
241
- const { menu, emptyActions, getOptionLabel: getOptionLabelProp, isOptionEqualToValue, inputValue, onInputChange, value, onChange, multiple, openOnFocus = true, readOnly = false, debounce: debounceMs = 300, } = props;
257
+ function useAutocomplete(props, inputRef) {
258
+ const { menu, emptyActions, getOptionLabel: getOptionLabelProp, isOptionEqualToValue, inputValue, onInputChange, value, onChange, multiple, openOnFocus = true, readOnly = false, disabled = false, debounce: debounceMs = 300, } = props;
242
259
  const isHandlingMenuInteractionRef = useRef(false);
243
260
  // TODO: Clean up the types in these refs by enhancing the type system in useCallbackRef
244
261
  const getOptionLabelPropRef = useCallbackRef((opt) => getOptionLabelProp === null || getOptionLabelProp === void 0 ? void 0 : getOptionLabelProp(opt));
@@ -254,7 +271,7 @@ function useAutocomplete(props) {
254
271
  const isOptionSelected = useCallback((opt) => {
255
272
  var _a;
256
273
  if (multiple) {
257
- const current = (_a = value) !== null && _a !== void 0 ? _a : [];
274
+ const current = (_a = value) !== null && _a !== void 0 ? _a : EMPTY_SELECTED_VALUES;
258
275
  return current.some(v => equals(v, opt));
259
276
  }
260
277
  const current = value;
@@ -285,6 +302,9 @@ function useAutocomplete(props) {
285
302
  // Skip debounce when clearing input for immediate feedback, preventing flickering of last selected item
286
303
  if (debounceMs === 0 || inputValue === "") {
287
304
  setDebouncedInputValue(inputValue);
305
+ // Cancel any pending debounced call so a stale intermediate value
306
+ // (e.g. "P" while deleting "Pipe…") doesn't overwrite the immediate set.
307
+ debouncedSetter.cancel();
288
308
  return;
289
309
  }
290
310
  debouncedSetter(inputValue);
@@ -340,7 +360,7 @@ function useAutocomplete(props) {
340
360
  const hasSelection = useMemo(() => {
341
361
  var _a;
342
362
  if (multiple) {
343
- const current = (_a = value) !== null && _a !== void 0 ? _a : [];
363
+ const current = (_a = value) !== null && _a !== void 0 ? _a : EMPTY_SELECTED_VALUES;
344
364
  return Array.isArray(current) && current.length > 0;
345
365
  }
346
366
  return value != null;
@@ -351,11 +371,13 @@ function useAutocomplete(props) {
351
371
  const totalNavigableCount = headerInteractivePersistents.length +
352
372
  mainNavigableCount +
353
373
  footerInteractivePersistents.length;
354
- // Compute the currently selected index in the global navigable list (header -> middle -> footer)
374
+ // Compute the currently selected index in the global navigable list (header -> middle -> footer).
375
+ // In multiple mode this is always null — there is no single "selected" index, and
376
+ // floating-ui would otherwise jump the highlight whenever the value array changes.
355
377
  const selectedIndex = useMemo(() => {
356
- const selectedValue = multiple
357
- ? value === null || value === void 0 ? void 0 : value[0]
358
- : value;
378
+ if (multiple)
379
+ return null;
380
+ const selectedValue = value;
359
381
  if (!selectedValue)
360
382
  return null;
361
383
  const middleIndex = findNavigableIndexForValue(renderable, equals, selectedValue);
@@ -374,6 +396,23 @@ function useAutocomplete(props) {
374
396
  shouldResetActiveIndexOnClose: () => !hasSelection,
375
397
  selectedIndex,
376
398
  readOnly,
399
+ disabled,
400
+ outsidePressExcludeSelector: multiple
401
+ ? "[data-testid='ATL-AutocompleteRebuilt-chipArea']"
402
+ : undefined,
403
+ onMenuOpen: () => {
404
+ if (multiple)
405
+ return;
406
+ const selectedValue = value;
407
+ if (selectedValue) {
408
+ const selectedNavigableIndex = findNavigableIndexForValue(renderable, equals, selectedValue);
409
+ if (selectedNavigableIndex != null) {
410
+ setActiveIndex(selectedNavigableIndex);
411
+ return;
412
+ }
413
+ }
414
+ setActiveIndex(null);
415
+ },
377
416
  onMenuClose: () => {
378
417
  if (props.allowFreeForm !== true) {
379
418
  const hasText = inputValue.trim().length > 0;
@@ -385,30 +424,30 @@ function useAutocomplete(props) {
385
424
  }
386
425
  },
387
426
  });
388
- // Handles activeIndex reset and, in single-select mode only, clearing selection when input is empty
427
+ const prevOpenRef = useRef(false);
428
+ // TODO: Leverage FloatingUI useFocus, and onArrowKeyDown to manage open state and allow onOpenChange to be the source of truth
429
+ // JOB-154442
389
430
  useEffect(() => {
390
- const hasText = inputValue.trim().length > 0;
391
- if (hasText)
392
- return;
393
- // Always reset highlight when input is empty
394
- setActiveIndex(null);
395
- // In multiple mode, clearing the input should NOT clear the selection
396
- if (multiple)
397
- return;
398
- // For single-select, treat clearing input as clearing the selection
399
- if (hasSelection) {
400
- onChange === null || onChange === void 0 ? void 0 : onChange(undefined);
431
+ var _a, _b;
432
+ if (open && !prevOpenRef.current) {
433
+ (_a = props.onOpen) === null || _a === void 0 ? void 0 : _a.call(props);
401
434
  }
402
- }, [inputValue, multiple, hasSelection, setActiveIndex, onChange, open]);
435
+ else if (!open && prevOpenRef.current) {
436
+ (_b = props.onClose) === null || _b === void 0 ? void 0 : _b.call(props);
437
+ }
438
+ prevOpenRef.current = open;
439
+ }, [open, props.onOpen, props.onClose]);
403
440
  function selectOption(option) {
404
441
  var _a;
405
442
  if (multiple) {
406
- const current = (_a = value) !== null && _a !== void 0 ? _a : [];
443
+ const current = (_a = value) !== null && _a !== void 0 ? _a : EMPTY_SELECTED_VALUES;
407
444
  const exists = current.some(v => equals(v, option));
408
445
  const next = exists
409
446
  ? current.filter(v => !equals(v, option))
410
447
  : [...current, option];
411
- onChange(next);
448
+ onChange((next.length === 0 ? EMPTY_SELECTED_VALUES : next));
449
+ lastInputWasUser.current = false;
450
+ onInputChange === null || onInputChange === void 0 ? void 0 : onInputChange("");
412
451
  }
413
452
  else {
414
453
  onChange(option);
@@ -416,6 +455,14 @@ function useAutocomplete(props) {
416
455
  onInputChange === null || onInputChange === void 0 ? void 0 : onInputChange(getOptionLabel(option));
417
456
  }
418
457
  }
458
+ function reHighlightSelectedItem() {
459
+ const selectedValue = value;
460
+ if (!selectedValue)
461
+ return;
462
+ const idx = findNavigableIndexForValue(renderable, equals, selectedValue);
463
+ if (idx != null)
464
+ setActiveIndex(idx);
465
+ }
419
466
  function tryCommitFreeFormOnEnter() {
420
467
  if (props.allowFreeForm !== true)
421
468
  return false;
@@ -427,77 +474,38 @@ function useAutocomplete(props) {
427
474
  commitFromInputText(inputText);
428
475
  return true;
429
476
  }
430
- // Keep the selected item highlighted when deleting characters from the input
431
- const prevInputLengthRef = useRef(inputValue.length);
432
- useEffect(() => {
433
- const previousLength = prevInputLengthRef.current;
434
- prevInputLengthRef.current = inputValue.length;
435
- if (!open)
436
- return;
437
- if (!lastInputWasUser.current)
438
- return;
439
- if (previousLength <= inputValue.length)
440
- return; // only on deletion
441
- if (!hasSelection)
442
- return;
443
- const selectedValue = multiple
444
- ? value === null || value === void 0 ? void 0 : value[0]
445
- : value;
446
- if (!selectedValue)
447
- return;
448
- const idx = findNavigableIndexForValue(renderable, equals, selectedValue);
449
- if (idx != null)
450
- setActiveIndex(idx);
451
- }, [
452
- inputValue,
453
- renderable,
454
- equals,
455
- value,
456
- open,
457
- hasSelection,
458
- multiple,
459
- setActiveIndex,
460
- ]);
461
- useEffect(() => {
462
- if (!open)
463
- return;
464
- // When opening the menu, initialize the highlight consistently:
465
- // - If there is a current selection, highlight that option
466
- // - Otherwise, leave the highlight unset (null)
467
- const selectedValue = multiple
468
- ? value === null || value === void 0 ? void 0 : value[0]
469
- : value;
470
- if (selectedValue) {
471
- const selectedNavigableIndex = findNavigableIndexForValue(renderable, equals, selectedValue);
472
- if (selectedNavigableIndex != null) {
473
- setActiveIndex(selectedNavigableIndex);
474
- return;
475
- }
476
- }
477
- setActiveIndex(null);
478
- }, [open, multiple, value, renderable, equals, setActiveIndex]);
479
477
  const onSelection = useCallback((option) => {
478
+ var _a;
480
479
  selectOption(option);
481
- // Might not always want to close on selection. Multi for example.
482
- setOpen(false);
483
- if (refs.domReference.current instanceof HTMLElement) {
484
- refs.domReference.current.focus();
480
+ if (!multiple) {
481
+ setOpen(false);
485
482
  }
486
- }, [selectOption, setOpen]);
483
+ (_a = inputRef.current) === null || _a === void 0 ? void 0 : _a.focus();
484
+ }, [selectOption, setOpen, multiple, inputRef]);
487
485
  const onAction = useCallback((action) => {
486
+ var _a;
488
487
  action.run();
489
488
  setActiveIndex(null);
490
489
  if (action.closeOnRun !== false)
491
490
  setOpen(false);
492
- if (refs.domReference.current instanceof HTMLElement) {
493
- refs.domReference.current.focus();
494
- }
495
- }, [setOpen, setActiveIndex]);
491
+ (_a = inputRef.current) === null || _a === void 0 ? void 0 : _a.focus();
492
+ }, [setOpen, setActiveIndex, inputRef]);
496
493
  /**
497
494
  * Handler for mousedown on interactive menu items (options/actions)
498
495
  * Prevents default to avoid blur and sets flag for focus management
499
496
  */
500
497
  const onInteractionPointerDown = useMemo(() => createInteractionPointerDownHandler(isHandlingMenuInteractionRef), []);
498
+ function applyFreeFormValue(freeFormCreated) {
499
+ var _a;
500
+ const nextValue = multiple
501
+ ? [...((_a = value) !== null && _a !== void 0 ? _a : EMPTY_SELECTED_VALUES), freeFormCreated]
502
+ : freeFormCreated;
503
+ props.onChange(nextValue);
504
+ if (multiple) {
505
+ lastInputWasUser.current = false;
506
+ onInputChange === null || onInputChange === void 0 ? void 0 : onInputChange("");
507
+ }
508
+ }
501
509
  function commitFromInputText(inputText) {
502
510
  var _a;
503
511
  if (inputText.length === 0)
@@ -513,15 +521,20 @@ function useAutocomplete(props) {
513
521
  const freeFormCreated = (_a = props.createFreeFormValue) === null || _a === void 0 ? void 0 : _a.call(props, inputText);
514
522
  if (!freeFormCreated)
515
523
  return false;
516
- props.onChange(freeFormCreated);
524
+ applyFreeFormValue(freeFormCreated);
517
525
  return true;
518
526
  }
519
527
  const tryRestoreInputToSelectedLabel = useCallback(() => {
520
528
  if (props.allowFreeForm === true)
521
529
  return;
522
- const selectedValue = multiple
523
- ? value === null || value === void 0 ? void 0 : value[0]
524
- : value;
530
+ if (multiple) {
531
+ if (inputValue.trim().length > 0) {
532
+ lastInputWasUser.current = false;
533
+ onInputChange === null || onInputChange === void 0 ? void 0 : onInputChange("");
534
+ }
535
+ return;
536
+ }
537
+ const selectedValue = value;
525
538
  if (!selectedValue)
526
539
  return;
527
540
  const selectedLabel = getOptionLabel(selectedValue);
@@ -641,8 +654,40 @@ function useAutocomplete(props) {
641
654
  });
642
655
  }
643
656
  }
657
+ const removeLastSelection = useCallback(() => {
658
+ var _a;
659
+ if (!multiple || readOnly)
660
+ return;
661
+ const current = (_a = value) !== null && _a !== void 0 ? _a : EMPTY_SELECTED_VALUES;
662
+ if (current.length > 0) {
663
+ const next = current.slice(0, -1);
664
+ onChange((next.length === 0 ? EMPTY_SELECTED_VALUES : next));
665
+ }
666
+ }, [multiple, readOnly, value, onChange]);
667
+ const removeSelection = useCallback((option) => {
668
+ var _a;
669
+ if (readOnly)
670
+ return;
671
+ if (multiple) {
672
+ const current = (_a = value) !== null && _a !== void 0 ? _a : EMPTY_SELECTED_VALUES;
673
+ const next = current.filter(v => !equals(v, option));
674
+ onChange((next.length === 0
675
+ ? EMPTY_SELECTED_VALUES
676
+ : next));
677
+ }
678
+ else {
679
+ const current = value;
680
+ if (current && equals(current, option)) {
681
+ onChange(undefined);
682
+ }
683
+ }
684
+ }, [readOnly, multiple, value, equals, onChange]);
644
685
  const onInputKeyDown = useCallback((event) => {
645
686
  const key = event.key;
687
+ if (key === "Backspace" && multiple && inputValue === "") {
688
+ removeLastSelection();
689
+ return;
690
+ }
646
691
  if (key !== "ArrowDown" && key !== "ArrowUp" && key !== "Enter")
647
692
  return;
648
693
  if (key === "ArrowDown" || key === "ArrowUp") {
@@ -650,20 +695,27 @@ function useAutocomplete(props) {
650
695
  return;
651
696
  }
652
697
  handleEnterKey(event);
653
- }, [open, onSelection, onAction]);
698
+ }, [open, onSelection, onAction, multiple, inputValue, removeLastSelection]);
654
699
  const onInputChangeFromUser = useCallback((val) => {
655
700
  lastInputWasUser.current = true;
656
- // Reset highlight (activeIndex) on additions to the search term
657
- if (val.length > inputValue.length) {
701
+ const isEmpty = val.trim().length === 0;
702
+ if (isEmpty) {
703
+ setActiveIndex(null);
704
+ if (!multiple && hasSelection) {
705
+ onChange === null || onChange === void 0 ? void 0 : onChange(undefined);
706
+ }
707
+ }
708
+ else if (val.length > inputValue.length) {
658
709
  setActiveIndex(null);
659
710
  }
660
- // Important: update open state before propagating the change so that downstream effects
661
- // don't see an intermediate state where inputValue changed but open was stale
711
+ else if (val.length < inputValue.length &&
712
+ !multiple &&
713
+ open &&
714
+ hasSelection) {
715
+ reHighlightSelectedItem();
716
+ }
662
717
  if (!readOnly) {
663
- const hasText = val.trim().length > 0;
664
- const mustSelectFromOptions = hasText && !props.allowFreeForm;
665
- const keepOpenOnEmpty = openOnFocus;
666
- setOpen(mustSelectFromOptions || keepOpenOnEmpty);
718
+ setOpen((!isEmpty && !props.allowFreeForm) || openOnFocus);
667
719
  }
668
720
  onInputChange === null || onInputChange === void 0 ? void 0 : onInputChange(val);
669
721
  }, [
@@ -674,7 +726,20 @@ function useAutocomplete(props) {
674
726
  props.allowFreeForm,
675
727
  openOnFocus,
676
728
  setOpen,
729
+ multiple,
730
+ hasSelection,
731
+ onChange,
732
+ open,
677
733
  ]);
734
+ const clearAll = useCallback(() => {
735
+ if (multiple) {
736
+ onChange(EMPTY_SELECTED_VALUES);
737
+ }
738
+ else {
739
+ onChange(undefined);
740
+ }
741
+ onInputChangeFromUser("");
742
+ }, [multiple, onChange, onInputChangeFromUser]);
678
743
  return {
679
744
  // rendering data
680
745
  renderable,
@@ -702,6 +767,8 @@ function useAutocomplete(props) {
702
767
  onSelection,
703
768
  onAction,
704
769
  onInteractionPointerDown,
770
+ removeSelection,
771
+ clearAll,
705
772
  // input handlers
706
773
  onInputChangeFromUser,
707
774
  onInputBlur,
@@ -712,6 +779,83 @@ function useAutocomplete(props) {
712
779
  };
713
780
  }
714
781
 
782
+ function useChipNavigation({ selectedValues, inputValue, readOnly, removeSelection, onInputKeyDown, onInputBlur, }) {
783
+ const [rawActiveChipIndex, setRawActiveChipIndex] = useState(null);
784
+ const [previousInputValue, setPreviousInputValue] = useState(inputValue);
785
+ const activeChipIndex = clampActiveIndex(rawActiveChipIndex, selectedValues.length);
786
+ if (previousInputValue !== inputValue) {
787
+ setPreviousInputValue(inputValue);
788
+ if (inputValue !== "" && rawActiveChipIndex !== null) {
789
+ setRawActiveChipIndex(null);
790
+ }
791
+ }
792
+ const handleActiveChipKey = useCallback(
793
+ // eslint-disable-next-line max-statements
794
+ (event) => {
795
+ if (activeChipIndex === null)
796
+ return false;
797
+ const { key } = event;
798
+ if (key === "ArrowLeft") {
799
+ event.preventDefault();
800
+ setRawActiveChipIndex(i => Math.max(0, (i !== null && i !== void 0 ? i : 0) - 1));
801
+ return true;
802
+ }
803
+ if (key === "ArrowRight") {
804
+ event.preventDefault();
805
+ setRawActiveChipIndex(activeChipIndex + 1 >= selectedValues.length
806
+ ? null
807
+ : activeChipIndex + 1);
808
+ return true;
809
+ }
810
+ if (key === "Backspace" || key === "Delete") {
811
+ event.preventDefault();
812
+ const option = selectedValues[activeChipIndex];
813
+ const newLen = selectedValues.length - 1;
814
+ if (newLen === 0) {
815
+ setRawActiveChipIndex(null);
816
+ }
817
+ else if (activeChipIndex >= newLen) {
818
+ setRawActiveChipIndex(newLen - 1);
819
+ }
820
+ removeSelection(option);
821
+ return true;
822
+ }
823
+ if (key === "Escape") {
824
+ setRawActiveChipIndex(null);
825
+ return true;
826
+ }
827
+ setRawActiveChipIndex(null);
828
+ return false;
829
+ }, [activeChipIndex, selectedValues, removeSelection]);
830
+ const onKeyDown = useCallback((event) => {
831
+ if (handleActiveChipKey(event))
832
+ return;
833
+ if (event.key === "ArrowLeft" &&
834
+ !readOnly &&
835
+ inputValue === "" &&
836
+ selectedValues.length > 0) {
837
+ event.preventDefault();
838
+ setRawActiveChipIndex(selectedValues.length - 1);
839
+ return;
840
+ }
841
+ onInputKeyDown(event);
842
+ }, [handleActiveChipKey, selectedValues, inputValue, readOnly, onInputKeyDown]);
843
+ const onBlur = useCallback((event) => {
844
+ setRawActiveChipIndex(null);
845
+ onInputBlur(event);
846
+ }, [onInputBlur]);
847
+ return { activeChipIndex, onKeyDown, onBlur };
848
+ }
849
+ function clampActiveIndex(index, length) {
850
+ if (index === null)
851
+ return null;
852
+ if (length === 0)
853
+ return null;
854
+ if (index >= length)
855
+ return length - 1;
856
+ return index;
857
+ }
858
+
715
859
  function MenuList({ items, activeIndex, indexOffset = 0, getItemProps, listRef, listboxId, customRenderOption, customRenderSection, customRenderAction, getOptionLabel, onSelect, onAction, onInteractionPointerDown, isOptionSelected, slotOverrides, }) {
716
860
  let navigableIndex = -1;
717
861
  function renderItemNode(item) {
@@ -795,7 +939,8 @@ function handleOptionRendering({ option, activeIndex, navigableIndex, getItemPro
795
939
  }
796
940
  function DefaultOptionContent({ isSelected, text, }) {
797
941
  return (React__default.createElement("div", { className: styles$1.defaultOptionContent },
798
- React__default.createElement("div", { className: styles$1.icon }, isSelected && React__default.createElement(Icon, { name: "checkmark", size: "small" })),
942
+ React__default.createElement("div", { className: styles$1.icon, style: isSelected ? undefined : { visibility: "hidden" } },
943
+ React__default.createElement(Icon, { name: "checkmark", size: "small" })),
799
944
  React__default.createElement(Text, null, text)));
800
945
  }
801
946
  function handleActionRendering({ action, activeIndex, navigableIndex, getItemProps, listRef, listboxId, customRenderAction, onAction, onInteractionPointerDown, indexOffset = 0, actionClassName, actionStyle, origin, }) {
@@ -941,12 +1086,50 @@ function DefaultTextPersistentContent({ persistent, }) {
941
1086
  return React__default.createElement("div", { className: styles$1.textPersistent }, persistent.label);
942
1087
  }
943
1088
 
1089
+ function FloatingMenu({ context, getFloatingProps, refs, listboxId, className, floatingStyles, transitionStyles, menuWidth, menuStyle, renderable, persistentsHeaders, persistentsFooters, activeIndex, headerInteractiveCount, middleNavigableCount, getItemProps, listRef, onSelection, onAction, onInteractionPointerDown, getOptionLabel, isOptionSelected, loading, showEmptyStateMessage, emptyStateMessage, customRenderLoading, customRenderOption, customRenderSection, customRenderAction, customRenderHeader, customRenderFooter, slotOverrides, }) {
1090
+ var _a, _b, _c, _d;
1091
+ const activeIndexForMiddle = activeIndex != null ? activeIndex - headerInteractiveCount : null;
1092
+ return (React__default.createElement(FloatingPortal, null,
1093
+ React__default.createElement(FloatingFocusManager, { context: context, modal: false, initialFocus: -1, closeOnFocusOut: true, returnFocus: false },
1094
+ React__default.createElement("div", Object.assign({}, getFloatingProps({
1095
+ ref(node) {
1096
+ if (node)
1097
+ refs.setFloating(node);
1098
+ },
1099
+ id: listboxId,
1100
+ role: "listbox",
1101
+ className,
1102
+ style: Object.assign(Object.assign(Object.assign(Object.assign({}, floatingStyles), transitionStyles), menuStyle), (menuWidth ? { width: menuWidth, maxWidth: menuWidth } : {})),
1103
+ })),
1104
+ React__default.createElement(PersistentRegion, { items: persistentsHeaders, position: "header", activeIndex: activeIndex, indexOffset: 0, listboxId: listboxId, getItemProps: getItemProps, listRef: listRef, customRenderHeader: customRenderHeader, customRenderFooter: customRenderFooter, onAction: onAction, onInteractionPointerDown: onInteractionPointerDown, className: classnames(styles$1.persistentHeader, (_a = slotOverrides === null || slotOverrides === void 0 ? void 0 : slotOverrides.header) === null || _a === void 0 ? void 0 : _a.className), style: (_b = slotOverrides === null || slotOverrides === void 0 ? void 0 : slotOverrides.header) === null || _b === void 0 ? void 0 : _b.style }),
1105
+ React__default.createElement("div", { className: styles$1.scrollRegion }, loading ? (customRenderLoading !== null && customRenderLoading !== void 0 ? customRenderLoading : React__default.createElement(LoadingContent, null)) : (React__default.createElement(React__default.Fragment, null,
1106
+ showEmptyStateMessage && (React__default.createElement(EmptyStateMessage, { emptyState: emptyStateMessage })),
1107
+ renderable.length > 0 && (React__default.createElement(MenuList, { items: renderable, activeIndex: activeIndexForMiddle, indexOffset: headerInteractiveCount, listboxId: listboxId, getItemProps: getItemProps, listRef: listRef, customRenderOption: customRenderOption, customRenderSection: customRenderSection, customRenderAction: customRenderAction, getOptionLabel: getOptionLabel, onSelect: onSelection, onAction: onAction, onInteractionPointerDown: onInteractionPointerDown, isOptionSelected: isOptionSelected, slotOverrides: slotOverrides }))))),
1108
+ React__default.createElement(PersistentRegion, { items: persistentsFooters, position: "footer", activeIndex: activeIndex, indexOffset: headerInteractiveCount + middleNavigableCount, listboxId: listboxId, getItemProps: getItemProps, listRef: listRef, customRenderHeader: customRenderHeader, customRenderFooter: customRenderFooter, onAction: onAction, onInteractionPointerDown: onInteractionPointerDown, className: classnames(styles$1.persistentFooter, (_c = slotOverrides === null || slotOverrides === void 0 ? void 0 : slotOverrides.footer) === null || _c === void 0 ? void 0 : _c.className), style: (_d = slotOverrides === null || slotOverrides === void 0 ? void 0 : slotOverrides.footer) === null || _d === void 0 ? void 0 : _d.style })))));
1109
+ }
1110
+ function LoadingContent() {
1111
+ return (React__default.createElement("div", { className: styles$1.loadingList, onPointerDown: preventDefaultPointerDown },
1112
+ React__default.createElement(Glimmer, { shape: "rectangle", size: "base" }),
1113
+ React__default.createElement(Glimmer, { shape: "rectangle", size: "base" }),
1114
+ React__default.createElement(Glimmer, { shape: "rectangle", size: "base" })));
1115
+ }
1116
+ function EmptyStateMessage({ emptyState, }) {
1117
+ const emptyStateDefault = "No options";
1118
+ const emptyStateContent = emptyState !== null && emptyState !== void 0 ? emptyState : emptyStateDefault;
1119
+ return (React__default.createElement("div", { className: styles$1.emptyStateMessage, onPointerDown: preventDefaultPointerDown }, emptyStateContent));
1120
+ }
1121
+
944
1122
  const AutocompleteRebuilt = forwardRef(AutocompleteRebuiltInternal);
945
1123
  // eslint-disable-next-line max-statements
946
1124
  function AutocompleteRebuiltInternal(props, forwardedRef) {
947
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o;
1125
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q;
948
1126
  const { inputValue, placeholder, disabled, error, invalid, description, size: sizeProp, loading = false, } = props;
949
- const { renderable, optionCount, persistentsHeaders, persistentsFooters, headerInteractiveCount, middleNavigableCount, getOptionLabel, isOptionSelected, refs, floatingStyles, context, getReferenceProps, getFloatingProps, getItemProps, activeIndex, open, listRef, onSelection, onAction, onInteractionPointerDown, onInputChangeFromUser, onInputBlur, onInputFocus, onInputKeyDown, setReferenceElement, } = useAutocomplete(props);
1127
+ const formFieldRef = useRef(null);
1128
+ // Ref for the multi-select input element, where we cannot use refs.domReference
1129
+ // since it is not attached to the literal input element, whereas single + InputText only offers a
1130
+ // ref to the literal input element.
1131
+ const internalInputRef = useRef(null);
1132
+ const { renderable, optionCount, persistentsHeaders, persistentsFooters, headerInteractiveCount, middleNavigableCount, getOptionLabel, isOptionSelected, refs, floatingStyles, context, getReferenceProps, getFloatingProps, getItemProps, activeIndex, open, listRef, onSelection, onAction, onInteractionPointerDown, removeSelection, onInputChangeFromUser, onInputBlur, onInputFocus, onInputKeyDown, setReferenceElement, clearAll, } = useAutocomplete(props, internalInputRef);
950
1133
  const listboxId = React__default.useId();
951
1134
  // Provides mount/unmount-aware transition styles for the floating element
952
1135
  const { isMounted, styles: transitionStyles } = useTransitionStyles(context, {
@@ -957,90 +1140,172 @@ function AutocompleteRebuiltInternal(props, forwardedRef) {
957
1140
  });
958
1141
  const [menuWidth, setMenuWidth] = React__default.useState(undefined);
959
1142
  const [positionRefEl, setPositionRefEl] = React__default.useState(null);
960
- const composedReferenceProps = getReferenceProps({
961
- onKeyDown: onInputKeyDown,
962
- onFocus: onInputFocus,
963
- onBlur: onInputBlur,
1143
+ const inputId = React__default.useId();
1144
+ const descriptionId = `descriptionUUID--${inputId}`;
1145
+ const selectedValues = props.multiple
1146
+ ? ((_a = props.value) !== null && _a !== void 0 ? _a : EMPTY_SELECTED_VALUES)
1147
+ : EMPTY_SELECTED_VALUES;
1148
+ const { activeChipIndex, onKeyDown: chipKeyDown, onBlur: chipBlur, } = useChipNavigation({
1149
+ selectedValues,
1150
+ inputValue,
1151
+ readOnly: props.readOnly,
1152
+ removeSelection,
1153
+ onInputKeyDown,
1154
+ onInputBlur,
964
1155
  });
1156
+ const focusInputOnPointerDown = useCallback((e) => {
1157
+ var _a;
1158
+ const target = e.target;
1159
+ if (target.closest("input, button"))
1160
+ return;
1161
+ e.preventDefault();
1162
+ (_a = internalInputRef.current) === null || _a === void 0 ? void 0 : _a.focus();
1163
+ }, []);
1164
+ const composedReferenceProps = getReferenceProps(Object.assign({ onKeyDown: props.multiple ? chipKeyDown : onInputKeyDown, onFocus: onInputFocus, onBlur: props.multiple ? chipBlur : onInputBlur }, (props.multiple ? { onPointerDown: focusInputOnPointerDown } : {})));
965
1165
  const dataAttrs = filterDataAttributes(props);
966
- const inputProps = Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({ version: 2, value: inputValue, onChange: props.readOnly ? undefined : onInputChangeFromUser }, (props.readOnly ? { onFocus: onInputFocus, onBlur: onInputBlur } : {})), { placeholder,
967
- disabled, readOnly: props.readOnly, error: error !== null && error !== void 0 ? error : undefined, name: props.name, invalid, autoComplete: "off", autoFocus: props.autoFocus, description, size: sizeProp ? sizeProp : undefined, prefix: props.prefix, suffix: props.suffix }), (props.readOnly ? {} : composedReferenceProps)), { role: "combobox", "aria-autocomplete": "list", "aria-expanded": open ? true : false, "aria-controls": listboxId, "aria-activedescendant": open && activeIndex != null
1166
+ const ariaProps = {
1167
+ role: "combobox",
1168
+ "aria-autocomplete": "list",
1169
+ "aria-expanded": open ? true : false,
1170
+ "aria-controls": listboxId,
1171
+ "aria-activedescendant": activeChipIndex === null && open && activeIndex != null
968
1172
  ? `${listboxId}-item-${activeIndex}`
969
- : undefined }), dataAttrs);
1173
+ : undefined,
1174
+ };
1175
+ const inputProps = Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({ version: 2, value: inputValue, onChange: props.readOnly ? undefined : onInputChangeFromUser }, (props.readOnly ? { onFocus: onInputFocus, onBlur: onInputBlur } : {})), { placeholder,
1176
+ disabled, readOnly: props.readOnly, error: error !== null && error !== void 0 ? error : undefined, name: props.name, invalid, clearable: props.clearable, autoComplete: "off", autoFocus: props.autoFocus, description, size: sizeProp ? sizeProp : undefined, prefix: props.prefix, suffix: props.suffix }), (props.readOnly ? {} : composedReferenceProps)), ariaProps), dataAttrs);
1177
+ const chipAreaRef = useCallback((node) => {
1178
+ if (!node)
1179
+ return;
1180
+ // In multiple mode, we use the input as the reference so floating-ui's
1181
+ // useListNavigation treats it as a typeable combobox and allows Space.
1182
+ // Only use chipArea for positioning/sizing.
1183
+ if (!props.multiple) {
1184
+ setReferenceElement(node);
1185
+ }
1186
+ const multiContainer = node.closest("[data-testid='ATL-AutocompleteRebuilt-multiSelectContainer']");
1187
+ if (multiContainer) {
1188
+ setMenuWidth(multiContainer.clientWidth);
1189
+ setPositionRefEl(multiContainer);
1190
+ }
1191
+ }, [setReferenceElement, props.multiple]);
970
1192
  const referenceInputRef = useCallback((node) => {
971
1193
  setReferenceElement(node);
972
- // Workaround to get the width of the visual InputText element, which is not the same as
973
- // the literal input reference element when props like suffix/prefix/clearable are present.
974
- const visualInputTextElement = node === null || node === void 0 ? void 0 : node.closest("[data-testid='Form-Field-Wrapper']");
975
- if (visualInputTextElement) {
976
- setMenuWidth(visualInputTextElement.clientWidth);
977
- setPositionRefEl(visualInputTextElement);
1194
+ if (!props.multiple) {
1195
+ // Workaround to get the width of the visual InputText element, which is not the same as
1196
+ // the literal input reference element.
1197
+ const visualInputTextElement = node === null || node === void 0 ? void 0 : node.closest("[data-testid='Form-Field-Wrapper']");
1198
+ if (visualInputTextElement) {
1199
+ setMenuWidth(visualInputTextElement.clientWidth);
1200
+ setPositionRefEl(visualInputTextElement);
1201
+ }
978
1202
  }
979
- }, [setReferenceElement]);
1203
+ }, [setReferenceElement, props.multiple]);
980
1204
  const mergedInputRef = useMemo(() => mergeRefs([
981
1205
  referenceInputRef,
1206
+ internalInputRef,
982
1207
  forwardedRef,
983
1208
  ]), [referenceInputRef, forwardedRef]);
984
1209
  useEffect(() => {
985
1210
  if (!positionRefEl)
986
1211
  return;
987
- // Set the reference element to the visual InputText element so the menu aligns with the input.
988
1212
  refs.setPositionReference(positionRefEl);
989
1213
  }, [positionRefEl, refs]);
990
- const menuClassName = classnames(styles$1.list, (_a = props.UNSAFE_className) === null || _a === void 0 ? void 0 : _a.menu);
1214
+ const menuClassName = classnames(styles$1.list, (_b = props.UNSAFE_className) === null || _b === void 0 ? void 0 : _b.menu);
991
1215
  const showEmptyStateMessage = optionCount === 0 && props.emptyStateMessage !== false;
992
- const activeIndexForMiddle = activeIndex != null ? activeIndex - headerInteractiveCount : null;
1216
+ const floatingMenu = isMounted && !props.readOnly && !disabled && (React__default.createElement(FloatingMenu, { context: context, getFloatingProps: getFloatingProps, refs: refs, listboxId: listboxId, className: menuClassName, floatingStyles: floatingStyles, transitionStyles: transitionStyles, menuWidth: menuWidth, menuStyle: (_c = props.UNSAFE_styles) === null || _c === void 0 ? void 0 : _c.menu, renderable: renderable, persistentsHeaders: persistentsHeaders, persistentsFooters: persistentsFooters, activeIndex: activeIndex, headerInteractiveCount: headerInteractiveCount, middleNavigableCount: middleNavigableCount, getItemProps: getItemProps, listRef: listRef, onSelection: onSelection, onAction: onAction, onInteractionPointerDown: onInteractionPointerDown, getOptionLabel: getOptionLabel, isOptionSelected: isOptionSelected, loading: loading, showEmptyStateMessage: showEmptyStateMessage, emptyStateMessage: props.emptyStateMessage, customRenderLoading: props.customRenderLoading, customRenderOption: props.customRenderOption, customRenderSection: props.customRenderSection, customRenderAction: props.customRenderAction, customRenderHeader: props.customRenderHeader, customRenderFooter: props.customRenderFooter, slotOverrides: {
1217
+ option: {
1218
+ className: (_d = props.UNSAFE_className) === null || _d === void 0 ? void 0 : _d.option,
1219
+ style: (_e = props.UNSAFE_styles) === null || _e === void 0 ? void 0 : _e.option,
1220
+ },
1221
+ action: {
1222
+ className: (_f = props.UNSAFE_className) === null || _f === void 0 ? void 0 : _f.action,
1223
+ style: (_g = props.UNSAFE_styles) === null || _g === void 0 ? void 0 : _g.action,
1224
+ },
1225
+ section: {
1226
+ className: (_h = props.UNSAFE_className) === null || _h === void 0 ? void 0 : _h.section,
1227
+ style: (_j = props.UNSAFE_styles) === null || _j === void 0 ? void 0 : _j.section,
1228
+ },
1229
+ header: {
1230
+ className: (_k = props.UNSAFE_className) === null || _k === void 0 ? void 0 : _k.header,
1231
+ style: (_l = props.UNSAFE_styles) === null || _l === void 0 ? void 0 : _l.header,
1232
+ },
1233
+ footer: {
1234
+ className: (_m = props.UNSAFE_className) === null || _m === void 0 ? void 0 : _m.footer,
1235
+ style: (_o = props.UNSAFE_styles) === null || _o === void 0 ? void 0 : _o.footer,
1236
+ },
1237
+ } }));
1238
+ if (props.customRenderInput) {
1239
+ return (React__default.createElement("div", { "data-testid": "ATL-AutocompleteRebuilt" },
1240
+ props.customRenderInput({ inputRef: mergedInputRef, inputProps }),
1241
+ floatingMenu));
1242
+ }
1243
+ if (props.multiple) {
1244
+ return (React__default.createElement(MultipleSelectionLayout, { selectedValues: selectedValues, inputValue: inputValue, disabled: disabled, error: error, invalid: invalid, sizeProp: sizeProp, inputId: inputId, descriptionId: descriptionId, description: description, placeholder: placeholder, clearable: props.clearable, prefix: props.prefix, suffix: props.suffix, readOnly: props.readOnly, name: props.name, autoFocus: props.autoFocus, formFieldRef: formFieldRef, chipAreaRef: chipAreaRef, mergedInputRef: mergedInputRef, internalInputRef: internalInputRef, activeChipIndex: activeChipIndex, getOptionLabel: getOptionLabel, customRenderValue: props.customRenderValue, removeSelection: removeSelection, clearAll: clearAll, onInputChangeFromUser: onInputChangeFromUser, chipAreaEventProps: props.readOnly
1245
+ ? { onFocus: onInputFocus, onBlur: chipBlur }
1246
+ : composedReferenceProps, inputAriaProps: ariaProps, inputDataAttrs: dataAttrs, limitVisibleSelections: props.limitVisibleSelections, limitSelectionText: props.limitSelectionText, unsafeClassName: (_p = props.UNSAFE_className) === null || _p === void 0 ? void 0 : _p.selection, unsafeStyle: (_q = props.UNSAFE_styles) === null || _q === void 0 ? void 0 : _q.selection }, floatingMenu));
1247
+ }
993
1248
  return (React__default.createElement("div", { "data-testid": "ATL-AutocompleteRebuilt" },
994
- props.customRenderInput ? (props.customRenderInput({ inputRef: mergedInputRef, inputProps })) : (React__default.createElement(InputText, Object.assign({ ref: mergedInputRef }, inputProps))),
995
- isMounted && !props.readOnly && (React__default.createElement(FloatingPortal, null,
996
- React__default.createElement(FloatingFocusManager, { context: context, modal: false, initialFocus: -1, closeOnFocusOut: true, returnFocus: false },
997
- React__default.createElement("div", Object.assign({}, getFloatingProps({
998
- ref(node) {
999
- if (node)
1000
- refs.setFloating(node);
1001
- },
1002
- id: listboxId,
1003
- role: "listbox",
1004
- className: menuClassName,
1005
- style: Object.assign(Object.assign(Object.assign(Object.assign({}, floatingStyles), transitionStyles), (_b = props.UNSAFE_styles) === null || _b === void 0 ? void 0 : _b.menu), (menuWidth
1006
- ? { width: menuWidth, maxWidth: menuWidth }
1007
- : {})),
1008
- })),
1009
- React__default.createElement(PersistentRegion, { items: persistentsHeaders, position: "header", activeIndex: activeIndex, indexOffset: 0, listboxId: listboxId, getItemProps: getItemProps, listRef: listRef, customRenderHeader: props.customRenderHeader, customRenderFooter: props.customRenderFooter, onAction: onAction, onInteractionPointerDown: onInteractionPointerDown, className: classnames(styles$1.persistentHeader, (_c = props.UNSAFE_className) === null || _c === void 0 ? void 0 : _c.header), style: (_d = props.UNSAFE_styles) === null || _d === void 0 ? void 0 : _d.header }),
1010
- React__default.createElement("div", { className: styles$1.scrollRegion }, loading ? ((_e = props.customRenderLoading) !== null && _e !== void 0 ? _e : React__default.createElement(LoadingContent, null)) : (React__default.createElement(React__default.Fragment, null,
1011
- showEmptyStateMessage && (React__default.createElement(EmptyStateMessage, { emptyState: props.emptyStateMessage })),
1012
- renderable.length > 0 && (React__default.createElement(MenuList, { items: renderable, activeIndex: activeIndexForMiddle, indexOffset: headerInteractiveCount, listboxId: listboxId, getItemProps: getItemProps, listRef: listRef, customRenderOption: props.customRenderOption, customRenderSection: props.customRenderSection, customRenderAction: props.customRenderAction, getOptionLabel: getOptionLabel, onSelect: onSelection, onAction: onAction, onInteractionPointerDown: onInteractionPointerDown, isOptionSelected: isOptionSelected, slotOverrides: {
1013
- option: {
1014
- className: (_f = props.UNSAFE_className) === null || _f === void 0 ? void 0 : _f.option,
1015
- style: (_g = props.UNSAFE_styles) === null || _g === void 0 ? void 0 : _g.option,
1016
- },
1017
- action: {
1018
- className: (_h = props.UNSAFE_className) === null || _h === void 0 ? void 0 : _h.action,
1019
- style: (_j = props.UNSAFE_styles) === null || _j === void 0 ? void 0 : _j.action,
1020
- },
1021
- section: {
1022
- className: (_k = props.UNSAFE_className) === null || _k === void 0 ? void 0 : _k.section,
1023
- style: (_l = props.UNSAFE_styles) === null || _l === void 0 ? void 0 : _l.section,
1024
- },
1025
- } }))))),
1026
- React__default.createElement(PersistentRegion, { items: persistentsFooters, position: "footer", activeIndex: activeIndex, indexOffset: headerInteractiveCount + middleNavigableCount, listboxId: listboxId, getItemProps: getItemProps, listRef: listRef, customRenderHeader: props.customRenderHeader, customRenderFooter: props.customRenderFooter, onAction: onAction, onInteractionPointerDown: onInteractionPointerDown, className: classnames(styles$1.persistentFooter, (_m = props.UNSAFE_className) === null || _m === void 0 ? void 0 : _m.footer), style: (_o = props.UNSAFE_styles) === null || _o === void 0 ? void 0 : _o.footer })))))));
1249
+ React__default.createElement(InputText, Object.assign({ ref: mergedInputRef }, inputProps)),
1250
+ floatingMenu));
1027
1251
  }
1028
- function LoadingContent() {
1029
- return (React__default.createElement("div", { className: styles$1.loadingList, onPointerDown: preventDefaultPointerDown },
1030
- React__default.createElement(Glimmer, { shape: "rectangle", size: "base" }),
1031
- React__default.createElement(Glimmer, { shape: "rectangle", size: "base" }),
1032
- React__default.createElement(Glimmer, { shape: "rectangle", size: "base" })));
1252
+ function SelectionChip({ value, active, disabled, getOptionLabel, customRenderValue, canDismiss, onDismiss, unsafeClassName, unsafeStyle, }) {
1253
+ return (React__default.createElement("span", { "data-selection-disabled": disabled, className: classnames(styles$1.selectionChip, {
1254
+ [styles$1.selectionChipActive]: active,
1255
+ [styles$1.selectionChipDisabled]: disabled,
1256
+ }, unsafeClassName), style: unsafeStyle, "data-testid": "ATL-AutocompleteRebuilt-chip", onPointerDown: preventDefaultPointerDown },
1257
+ customRenderValue ? (customRenderValue({ value, getOptionLabel })) : (React__default.createElement(Typography, { size: "small" }, getOptionLabel(value))),
1258
+ canDismiss && (React__default.createElement("button", { type: "button", disabled: disabled, className: styles$1.chipDismiss, onClick: onDismiss, onPointerDown: preventDefaultPointerDown, "aria-label": `Remove ${getOptionLabel(value)}`, tabIndex: -1 },
1259
+ React__default.createElement(Icon, { size: "small", name: "remove" })))));
1033
1260
  }
1034
- function EmptyStateMessage({ emptyState, }) {
1035
- const emptyStateDefault = "No options";
1036
- const emptyStateContent = emptyState !== null && emptyState !== void 0 ? emptyState : emptyStateDefault;
1037
- return (React__default.createElement("div", { className: styles$1.emptyStateMessage, onPointerDown: preventDefaultPointerDown }, emptyStateContent));
1261
+ function SelectionChipsList({ selectedValues, isFocused, limitVisibleSelections = 6, limitSelectionText = (count) => `+${count}`, activeChipIndex, disabled, getOptionLabel, customRenderValue, canDismiss, removeSelection, unsafeClassName, unsafeStyle, }) {
1262
+ const shouldLimit = !isFocused &&
1263
+ limitVisibleSelections !== -1 &&
1264
+ selectedValues.length > limitVisibleSelections;
1265
+ const visibleValues = shouldLimit
1266
+ ? selectedValues.slice(0, limitVisibleSelections)
1267
+ : selectedValues;
1268
+ const hiddenCount = shouldLimit
1269
+ ? selectedValues.length - limitVisibleSelections
1270
+ : 0;
1271
+ return (React__default.createElement(React__default.Fragment, null,
1272
+ visibleValues.map((v, i) => {
1273
+ var _a;
1274
+ return (React__default.createElement(SelectionChip, { key: (_a = v.key) !== null && _a !== void 0 ? _a : getOptionLabel(v), value: v, active: activeChipIndex === i, disabled: disabled, getOptionLabel: getOptionLabel, customRenderValue: customRenderValue, canDismiss: canDismiss, onDismiss: () => removeSelection(v), unsafeClassName: unsafeClassName, unsafeStyle: unsafeStyle }));
1275
+ }),
1276
+ hiddenCount > 0 && (React__default.createElement("span", { className: styles$1.limitText, "data-testid": "ATL-AutocompleteRebuilt-limitText" },
1277
+ React__default.createElement(Typography, { size: "small", element: "span" }, limitSelectionText(hiddenCount))))));
1278
+ }
1279
+ function MultipleSelectionLayout({ selectedValues, inputValue, disabled, error, invalid, sizeProp, inputId, descriptionId, description, placeholder, clearable, prefix, suffix, readOnly, name, autoFocus, formFieldRef, chipAreaRef, mergedInputRef, internalInputRef, activeChipIndex, getOptionLabel, customRenderValue, removeSelection, clearAll, onInputChangeFromUser, chipAreaEventProps, inputAriaProps, inputDataAttrs, limitVisibleSelections, limitSelectionText, unsafeClassName, unsafeStyle, children, }) {
1280
+ var _a;
1281
+ const [isFocused, setIsFocused] = useState(false);
1282
+ const hasValue = selectedValues.length > 0 || inputValue;
1283
+ const canDismissChip = !disabled && !readOnly;
1284
+ const handleFocusIn = useCallback(() => {
1285
+ setIsFocused(true);
1286
+ }, []);
1287
+ const handleFocusOut = useCallback((e) => {
1288
+ if (!e.currentTarget.contains(e.relatedTarget)) {
1289
+ setIsFocused(false);
1290
+ }
1291
+ }, []);
1292
+ return (React__default.createElement("div", { "data-testid": "ATL-AutocompleteRebuilt", onFocus: handleFocusIn, onBlur: handleFocusOut },
1293
+ React__default.createElement("div", { className: styles$1.multiSelectField, "data-testid": "ATL-AutocompleteRebuilt-multiSelectContainer" },
1294
+ React__default.createElement(FormFieldWrapper, { disabled: disabled, size: sizeProp ? sizeProp : undefined, error: (_a = error) !== null && _a !== void 0 ? _a : "", invalid: Boolean(error || invalid), identifier: inputId, descriptionIdentifier: descriptionId, description: description, clearable: clearable !== null && clearable !== void 0 ? clearable : "never", onClear: () => {
1295
+ var _a;
1296
+ clearAll();
1297
+ (_a = internalInputRef.current) === null || _a === void 0 ? void 0 : _a.focus();
1298
+ }, type: "text", placeholder: placeholder, value: hasValue ? "has-value" : "", prefix: prefix, suffix: suffix, wrapperRef: formFieldRef },
1299
+ React__default.createElement("div", Object.assign({ ref: chipAreaRef, className: styles$1.chipArea, "data-testid": "ATL-AutocompleteRebuilt-chipArea" }, chipAreaEventProps),
1300
+ React__default.createElement(SelectionChipsList, { selectedValues: selectedValues, isFocused: isFocused, limitVisibleSelections: limitVisibleSelections, limitSelectionText: limitSelectionText, activeChipIndex: activeChipIndex, disabled: disabled, getOptionLabel: getOptionLabel, customRenderValue: customRenderValue, canDismiss: canDismissChip, removeSelection: removeSelection, unsafeClassName: unsafeClassName, unsafeStyle: unsafeStyle }),
1301
+ React__default.createElement("input", Object.assign({ ref: mergedInputRef, className: styles$1.inlineInput, id: inputId, value: inputValue, onChange: readOnly
1302
+ ? undefined
1303
+ : e => onInputChangeFromUser(e.target.value), disabled: disabled, readOnly: readOnly, name: name, autoComplete: "off", autoFocus: autoFocus }, inputAriaProps, inputDataAttrs))))),
1304
+ children));
1038
1305
  }
1039
1306
 
1040
1307
  var styles = {"autocomplete":"_7mObJiwfPh4-","options":"dL5JShAJlKM-","heading":"PWZL-94hH7k-","visible":"_2RzcnTdaPyc-","option":"y9zhi8Wr8QA-","active":"_3Xg49dtL1Q8-","separator":"LIeh390F3W8-","icon":"K2phy6IC3TY-","text":"a6-LbUm5WnY-","label":"tQNbuxcE9nU-","details":"qacStG9-XbE-","spinning":"P9cQDL4MZ-s-"};
1041
1308
 
1042
- const AUTOCOMPLETE_MAX_HEIGHT = 300;
1043
-
1044
1309
  function useRepositionMenu(attachTo, visible, cssManagedVisibility) {
1045
1310
  const { refs, floatingStyles, update } = useFloating(Object.assign({ placement: "bottom", middleware: [
1046
1311
  offset(8),
@@ -1048,7 +1313,7 @@ function useRepositionMenu(attachTo, visible, cssManagedVisibility) {
1048
1313
  size({
1049
1314
  apply({ availableHeight, elements }) {
1050
1315
  const maxHeight = calculateMaxHeight(availableHeight, {
1051
- maxHeight: AUTOCOMPLETE_MAX_HEIGHT,
1316
+ maxHeight: AUTOCOMPLETE_MAX_HEIGHT$1,
1052
1317
  });
1053
1318
  Object.assign(elements.floating.style, {
1054
1319
  maxHeight: `${maxHeight}px`,