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