@mezzanine-ui/react 1.0.0-rc.4 → 1.0.0-rc.5

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.
Files changed (60) hide show
  1. package/AutoComplete/AutoComplete.d.ts +14 -0
  2. package/AutoComplete/AutoComplete.js +74 -67
  3. package/AutoComplete/useAutoCompleteCreation.d.ts +5 -2
  4. package/AutoComplete/useAutoCompleteCreation.js +64 -6
  5. package/AutoComplete/useAutoCompleteKeyboard.d.ts +3 -1
  6. package/AutoComplete/useAutoCompleteKeyboard.js +9 -1
  7. package/Calendar/CalendarDays.js +7 -3
  8. package/Calendar/RangeCalendar.js +1 -1
  9. package/Cascader/Cascader.js +46 -12
  10. package/Cascader/CascaderPanel.js +27 -16
  11. package/Checkbox/Checkbox.js +13 -4
  12. package/Checkbox/typings.d.ts +4 -0
  13. package/DatePicker/DatePicker.js +11 -3
  14. package/DatePicker/DatePickerCalendar.d.ts +10 -0
  15. package/DatePicker/DatePickerCalendar.js +2 -2
  16. package/DateRangePicker/DateRangePicker.js +9 -2
  17. package/DateRangePicker/DateRangePickerCalendar.d.ts +5 -0
  18. package/DateRangePicker/DateRangePickerCalendar.js +2 -2
  19. package/DateRangePicker/useDateRangePickerValue.d.ts +3 -0
  20. package/DateRangePicker/useDateRangePickerValue.js +9 -1
  21. package/DateTimePicker/DateTimePicker.js +65 -13
  22. package/Dropdown/DropdownAction.js +1 -1
  23. package/Form/useAutoCompleteValueControl.d.ts +1 -0
  24. package/Form/useAutoCompleteValueControl.js +4 -2
  25. package/Input/Input.d.ts +7 -7
  26. package/Input/Input.js +16 -11
  27. package/Input/index.d.ts +1 -1
  28. package/Picker/FormattedInput.d.ts +5 -0
  29. package/Picker/FormattedInput.js +21 -13
  30. package/Picker/PickerTrigger.d.ts +1 -1
  31. package/Picker/PickerTrigger.js +2 -2
  32. package/Picker/PickerTriggerWithSeparator.d.ts +4 -0
  33. package/Picker/PickerTriggerWithSeparator.js +2 -2
  34. package/Picker/RangePickerTrigger.d.ts +8 -0
  35. package/Picker/RangePickerTrigger.js +2 -2
  36. package/Picker/useDateInputFormatter.d.ts +1 -0
  37. package/Picker/useDateInputFormatter.js +1 -0
  38. package/Select/SelectTriggerTags.js +10 -1
  39. package/Slider/Slider.d.ts +12 -0
  40. package/Slider/Slider.js +69 -4
  41. package/TimePanel/TimePanel.d.ts +8 -0
  42. package/TimePanel/TimePanel.js +12 -31
  43. package/TimePanel/index.d.ts +0 -2
  44. package/TimePanel/index.js +0 -1
  45. package/TimePicker/TimePicker.d.ts +1 -1
  46. package/TimePicker/TimePicker.js +96 -42
  47. package/TimePicker/TimePickerPanel.d.ts +8 -0
  48. package/TimePicker/TimePickerPanel.js +2 -2
  49. package/TimeRangePicker/TimeRangePicker.js +85 -25
  50. package/TimeRangePicker/useTimeRangePickerValue.d.ts +2 -0
  51. package/TimeRangePicker/useTimeRangePickerValue.js +45 -7
  52. package/Tooltip/Tooltip.d.ts +5 -0
  53. package/Tooltip/Tooltip.js +2 -2
  54. package/index.d.ts +3 -3
  55. package/index.js +1 -2
  56. package/package.json +4 -4
  57. package/utils/get-css-variable-value.d.ts +1 -0
  58. package/utils/get-css-variable-value.js +96 -2
  59. package/TimePanel/TimePanelAction.d.ts +0 -12
  60. package/TimePanel/TimePanelAction.js +0 -15
@@ -139,6 +139,13 @@ export interface AutoCompleteBaseProps extends Omit<SelectTriggerProps, 'active'
139
139
  * @default true
140
140
  */
141
141
  trimOnCreate?: boolean;
142
+ /**
143
+ * When true, pasted bulk text is kept in the input and user creates one item at a time
144
+ * (create button shows only the first pending item; after create, input updates to remaining).
145
+ * When false, pasted bulk text creates all items at once (default).
146
+ * @default false
147
+ */
148
+ stepByStepBulkCreate?: boolean;
142
149
  /**
143
150
  * Custom text for the create action button.
144
151
  * @default '建立 "{text}"'
@@ -170,6 +177,13 @@ export interface AutoCompleteBaseProps extends Omit<SelectTriggerProps, 'active'
170
177
  * Only fires when `menuMaxHeight` is set and the list is scrollable.
171
178
  */
172
179
  onLeaveBottom?: () => void;
180
+ /**
181
+ * Called on blur when addable mode has unselected created items.
182
+ * Receives the cleaned options (unselected created items already removed).
183
+ * Use this to update your options state.
184
+ * Only called when `addable` is true and there are unselected created items.
185
+ */
186
+ onRemoveCreated?(cleanedOptions: SelectValue[]): void;
173
187
  }
174
188
  export type AutoCompleteMultipleProps = AutoCompleteBaseProps & {
175
189
  /**
@@ -7,7 +7,7 @@ import { useAutoCompleteValueControl } from '../Form/useAutoCompleteValueControl
7
7
  import { useComposeRefs } from '../hooks/useComposeRefs.js';
8
8
  import { SelectControlContext } from '../Select/SelectControlContext.js';
9
9
  import SelectTrigger from '../Select/SelectTrigger.js';
10
- import { useAutoCompleteCreation } from './useAutoCompleteCreation.js';
10
+ import { useAutoCompleteCreation, getFullParsedList } from './useAutoCompleteCreation.js';
11
11
  import { useAutoCompleteKeyboard } from './useAutoCompleteKeyboard.js';
12
12
  import { useAutoCompleteSearch } from './useAutoCompleteSearch.js';
13
13
  import { useCreationTracker } from './useCreationTracker.js';
@@ -29,18 +29,6 @@ function isMultipleValue(value) {
29
29
  function isSingleValue(value) {
30
30
  return value !== null && value !== undefined && !Array.isArray(value);
31
31
  }
32
- /**
33
- * Check if an option is already selected
34
- */
35
- function isOptionSelected(option, value, isMultiple) {
36
- if (isMultiple && isMultipleValue(value)) {
37
- return value.some((v) => v.id === option.id);
38
- }
39
- if (!isMultiple && isSingleValue(value)) {
40
- return value.id === option.id;
41
- }
42
- return false;
43
- }
44
32
  /**
45
33
  * The AutoComplete component for react. <br />
46
34
  * Note that if you need search for ONLY given options, not included your typings,
@@ -48,7 +36,7 @@ function isOptionSelected(option, value, isMultiple) {
48
36
  */
49
37
  const AutoComplete = forwardRef(function AutoComplete(props, ref) {
50
38
  const { disabled: disabledFromFormControl, fullWidth: fullWidthFromFormControl, required: requiredFromFormControl, severity, } = useContext(FormControlContext) || {};
51
- const { addable = false, asyncData = false, className, clearSearchText = true, createSeparators = [',', '+', '\n'], defaultValue, disabled = disabledFromFormControl || false, disabledOptionsFilter = false, emptyText = '沒有符合的項目', error = severity === 'error' || false, fullWidth = fullWidthFromFormControl || false, id, inputPosition = 'outside', inputProps, inputRef, loading = false, loadingText = '載入中...', loadingPosition = 'bottom', menuMaxHeight, mode = 'single', name, onClear: onClearProp, onChange: onChangeProp, onInsert, onSearch, onSearchTextChange, onVisibilityChange, open: openProp, options: optionsProp, overflowStrategy, placeholder = '', prefix, required = requiredFromFormControl || false, searchDebounceTime = 300, searchTextControlRef, size, trimOnCreate = true, value: valueProp, createActionText, createActionTextTemplate = '建立 "{text}"', dropdownZIndex, globalPortal = true, onReachBottom, onLeaveBottom, } = props;
39
+ const { addable = false, asyncData = false, className, clearSearchText = true, createSeparators = [',', '+', '\n'], defaultValue, disabled = disabledFromFormControl || false, disabledOptionsFilter = false, emptyText = '沒有符合的項目', error = severity === 'error' || false, fullWidth = fullWidthFromFormControl || false, id, inputPosition = 'outside', inputProps, inputRef, loading = false, loadingText = '載入中...', loadingPosition = 'bottom', menuMaxHeight, mode = 'single', name, onClear: onClearProp, onChange: onChangeProp, onInsert, onSearch, onSearchTextChange, onVisibilityChange, open: openProp, options: optionsProp, overflowStrategy, placeholder = '', prefix, required = requiredFromFormControl || false, searchDebounceTime = 300, searchTextControlRef, size, stepByStepBulkCreate = false, trimOnCreate = true, value: valueProp, createActionText, createActionTextTemplate = '建立 "{text}"', dropdownZIndex, globalPortal = true, onReachBottom, onLeaveBottom, onRemoveCreated, } = props;
52
40
  const shouldClearSearchTextOnBlur = clearSearchText;
53
41
  const [uncontrolledOpen, setUncontrolledOpen] = useState(false);
54
42
  const isMultiple = mode === 'multiple';
@@ -68,6 +56,13 @@ const AutoComplete = forwardRef(function AutoComplete(props, ref) {
68
56
  ? defaultValue
69
57
  : undefined,
70
58
  disabledOptionsFilter,
59
+ getOptionsFilterQuery: stepByStepBulkCreate && addable && onInsert
60
+ ? (st) => {
61
+ var _a;
62
+ const full = getFullParsedList(st, createSeparators, trimOnCreate);
63
+ return full.length > 1 ? (_a = full[0]) !== null && _a !== void 0 ? _a : undefined : undefined;
64
+ }
65
+ : undefined,
71
66
  mode: 'multiple',
72
67
  onChange: onChangeProp,
73
68
  onClear: onClearProp,
@@ -106,7 +101,13 @@ const AutoComplete = forwardRef(function AutoComplete(props, ref) {
106
101
  }, [addable, onInsert]);
107
102
  const idSeed = useId();
108
103
  const menuId = useMemo(() => `${MENU_ID_PREFIX}-${idSeed}`, [idSeed]);
109
- const { handleActionCustom, handleBulkCreate, handlePaste, insertText, processBulkCreate, resetCreationInputs, setInsertText, } = useAutoCompleteCreation({
104
+ const inputElementRef = useRef(null);
105
+ const onSetInputDisplay = useCallback((text) => {
106
+ if (inputElementRef.current) {
107
+ inputElementRef.current.value = text;
108
+ }
109
+ }, []);
110
+ const { getPendingCreateList, handleActionCustom: handleActionCustomBase, handleBulkCreate, handlePaste, insertText, processBulkCreate, resetCreationInputs, setInsertText, } = useAutoCompleteCreation({
110
111
  addable: creationEnabled,
111
112
  clearUnselected,
112
113
  createSeparators,
@@ -119,15 +120,23 @@ const AutoComplete = forwardRef(function AutoComplete(props, ref) {
119
120
  onChangeMultiple: isMultiple
120
121
  ? onChangeProp
121
122
  : undefined,
122
- onFocus,
123
123
  onInsert,
124
- options,
124
+ onSetInputDisplay,
125
+ options: optionsProp,
125
126
  setSearchText,
127
+ stepByStepBulkCreate,
126
128
  toggleOpen,
127
129
  trimOnCreate,
128
130
  value,
129
131
  wrappedOnChange: (chooseOption) => wrappedOnChange(chooseOption),
130
132
  });
133
+ const handleActionCustom = useCallback(() => {
134
+ suppressNextCloseRef.current = true;
135
+ handleActionCustomBase();
136
+ window.setTimeout(() => {
137
+ suppressNextCloseRef.current = false;
138
+ }, 0);
139
+ }, [handleActionCustomBase]);
131
140
  const { cancelSearch, isLoading, runSearch } = useAutoCompleteSearch({
132
141
  asyncData,
133
142
  loading,
@@ -161,10 +170,10 @@ const AutoComplete = forwardRef(function AutoComplete(props, ref) {
161
170
  value,
162
171
  ]);
163
172
  const nodeRef = useRef(null);
164
- const inputElementRef = useRef(null);
165
173
  const controlRef = useRef(null);
166
174
  const resetOptionsTimeoutRef = useRef(null);
167
175
  const skipNextMultipleCloseResetRef = useRef(false);
176
+ const suppressNextCloseRef = useRef(false);
168
177
  const composedRef = useComposeRefs([ref, controlRef]);
169
178
  const composedInputRef = useComposeRefs([inputRef, inputElementRef]);
170
179
  const clearPendingOptionsReset = useCallback(() => {
@@ -191,6 +200,15 @@ const AutoComplete = forwardRef(function AutoComplete(props, ref) {
191
200
  resetOptionsTimeoutRef.current = null;
192
201
  }, BLUR_RESET_OPTIONS_DELAY);
193
202
  }, [cancelSearch, clearPendingOptionsReset, resetSearchInputs, runSearch]);
203
+ const cleanupUnselectedCreated = useCallback(() => {
204
+ if (!creationEnabled || typeof onRemoveCreated !== 'function')
205
+ return;
206
+ const cleanedOptions = filterUnselected(optionsProp);
207
+ if (cleanedOptions.length === optionsProp.length)
208
+ return;
209
+ clearUnselected();
210
+ onRemoveCreated(cleanedOptions);
211
+ }, [clearUnselected, creationEnabled, filterUnselected, onRemoveCreated, optionsProp]);
194
212
  useEffect(() => () => {
195
213
  clearPendingOptionsReset();
196
214
  }, [clearPendingOptionsReset]);
@@ -241,8 +259,6 @@ const AutoComplete = forwardRef(function AutoComplete(props, ref) {
241
259
  setSearchText(nextSearch);
242
260
  setInsertText(nextSearch);
243
261
  onSearchTextChange === null || onSearchTextChange === void 0 ? void 0 : onSearchTextChange(nextSearch);
244
- if (autoSelectMatchingOption(nextSearch))
245
- return;
246
262
  if (!nextSearch) {
247
263
  cancelSearch();
248
264
  runSearch(nextSearch, { immediate: true });
@@ -283,6 +299,7 @@ const AutoComplete = forwardRef(function AutoComplete(props, ref) {
283
299
  // Clear search text and insert text when blur clear behavior is enabled
284
300
  if (shouldClearSearchTextOnBlur && !shouldDeferMultipleBlurReset) {
285
301
  resetSearchInputsAndOptions();
302
+ cleanupUnselectedCreated();
286
303
  }
287
304
  (_a = inputProps === null || inputProps === void 0 ? void 0 : inputProps.onBlur) === null || _a === void 0 ? void 0 : _a.call(inputProps, e);
288
305
  return;
@@ -292,6 +309,7 @@ const AutoComplete = forwardRef(function AutoComplete(props, ref) {
292
309
  // Clear search text and insert text when blur clear behavior is enabled
293
310
  if (shouldClearSearchTextOnBlur && !shouldDeferMultipleBlurReset) {
294
311
  resetSearchInputsAndOptions();
312
+ cleanupUnselectedCreated();
295
313
  }
296
314
  (_b = inputProps === null || inputProps === void 0 ? void 0 : inputProps.onBlur) === null || _b === void 0 ? void 0 : _b.call(inputProps, e);
297
315
  return;
@@ -300,25 +318,42 @@ const AutoComplete = forwardRef(function AutoComplete(props, ref) {
300
318
  // Clear search text and insert text when blur clear behavior is enabled
301
319
  if (shouldClearSearchTextOnBlur && !shouldDeferMultipleBlurReset) {
302
320
  resetSearchInputsAndOptions();
321
+ cleanupUnselectedCreated();
303
322
  }
304
323
  (_c = inputProps === null || inputProps === void 0 ? void 0 : inputProps.onBlur) === null || _c === void 0 ? void 0 : _c.call(inputProps, e);
305
324
  };
306
325
  const handleClear = useCallback((e) => {
326
+ if (isSingle && isSingleValue(value)) {
327
+ markUnselected([value.id]);
328
+ }
307
329
  onClear(e);
308
330
  resetSearchInputs();
309
- }, [onClear, resetSearchInputs]);
331
+ }, [isSingle, markUnselected, onClear, resetSearchInputs, value]);
310
332
  const onClickSuffixActionIcon = () => {
311
333
  toggleOpen((prev) => !prev);
312
334
  };
313
- const searchTextExistWithoutOption = !!searchText &&
314
- options.find((option) => option.name === searchText) === undefined;
335
+ const hasStepByStepBulkSeparator = stepByStepBulkCreate &&
336
+ createSeparators.some((sep) => insertText.includes(sep));
337
+ const firstPendingText = hasStepByStepBulkSeparator
338
+ ? getPendingCreateList(insertText)[0]
339
+ : undefined;
340
+ const searchTextExistWithoutOption = !!((firstPendingText
341
+ ? firstPendingText &&
342
+ options.find((option) => option.name === firstPendingText) ===
343
+ undefined
344
+ : searchText &&
345
+ options.find((option) => option.name === searchText) === undefined));
315
346
  const shouldShowCreateAction = !!(searchTextExistWithoutOption &&
316
347
  creationEnabled &&
317
- insertText);
348
+ (firstPendingText !== null && firstPendingText !== void 0 ? firstPendingText : insertText));
349
+ const createActionDisplayText = firstPendingText !== undefined && firstPendingText !== ''
350
+ ? firstPendingText
351
+ : insertText;
318
352
  const context = useMemo(() => ({ onChange: wrappedOnChange, value }), [wrappedOnChange, value]);
319
- // Convert SelectValue[] to DropdownOption[]
353
+ // Convert SelectValue[] to DropdownOption[] (created options first)
320
354
  const dropdownOptions = useMemo(() => {
321
- return options.map((option) => {
355
+ const sortedOptions = [...options].sort((a, b) => (isCreated(b.id) ? 1 : 0) - (isCreated(a.id) ? 1 : 0));
356
+ return sortedOptions.map((option) => {
322
357
  const created = isCreated(option.id);
323
358
  const result = {
324
359
  id: option.id,
@@ -348,7 +383,7 @@ const AutoComplete = forwardRef(function AutoComplete(props, ref) {
348
383
  return isSingleValue(value) ? value.id : undefined;
349
384
  }, [mode, value]);
350
385
  // Disable input when loading
351
- const isInputDisabled = disabled || isLoading;
386
+ const isInputDisabled = disabled || (!asyncData && isLoading);
352
387
  const dropdownStatus = isLoading
353
388
  ? 'loading'
354
389
  : dropdownOptions.length === 0
@@ -424,6 +459,7 @@ const AutoComplete = forwardRef(function AutoComplete(props, ref) {
424
459
  addable: creationEnabled,
425
460
  createSeparators,
426
461
  dropdownOptions,
462
+ handleActionCustom,
427
463
  handleBulkCreate,
428
464
  handleDropdownSelect,
429
465
  inputPropsOnKeyDown: inputProps === null || inputProps === void 0 ? void 0 : inputProps.onKeyDown,
@@ -438,6 +474,7 @@ const AutoComplete = forwardRef(function AutoComplete(props, ref) {
438
474
  setInsertText,
439
475
  setListboxHasVisualFocus,
440
476
  setSearchText,
477
+ stepByStepBulkCreate,
441
478
  toggleOpen,
442
479
  value,
443
480
  wrappedOnChange,
@@ -467,6 +504,11 @@ const AutoComplete = forwardRef(function AutoComplete(props, ref) {
467
504
  // Handle visibility change from Dropdown to prevent flickering
468
505
  const handleVisibilityChange = useCallback((newOpen) => {
469
506
  var _a;
507
+ // Suppress spurious closes triggered immediately after create action
508
+ if (!newOpen && suppressNextCloseRef.current) {
509
+ suppressNextCloseRef.current = false;
510
+ return;
511
+ }
470
512
  // Only update if state actually changed to prevent flickering
471
513
  if (newOpen !== open) {
472
514
  toggleOpen(newOpen);
@@ -486,8 +528,10 @@ const AutoComplete = forwardRef(function AutoComplete(props, ref) {
486
528
  }
487
529
  }
488
530
  resetSearchInputsAndOptions();
531
+ cleanupUnselectedCreated();
489
532
  }
490
533
  }, [
534
+ cleanupUnselectedCreated,
491
535
  isMultiple,
492
536
  menuId,
493
537
  open,
@@ -500,43 +544,6 @@ const AutoComplete = forwardRef(function AutoComplete(props, ref) {
500
544
  handlePaste(e);
501
545
  (_a = inputProps === null || inputProps === void 0 ? void 0 : inputProps.onPaste) === null || _a === void 0 ? void 0 : _a.call(inputProps, e);
502
546
  }, [handlePaste, inputProps]);
503
- const autoSelectMatchingOption = useCallback((keyword) => {
504
- if (!creationEnabled || !keyword.length)
505
- return false;
506
- const matchingOption = options.find((option) => option.name === keyword);
507
- if (!matchingOption)
508
- return false;
509
- if (isSingle) {
510
- if (!value) {
511
- // Update searchText first to prevent showing old value
512
- setSearchText(matchingOption.name);
513
- setInsertText(matchingOption.name);
514
- // Then update value and focus state
515
- wrappedOnChange(matchingOption);
516
- toggleOpen(false);
517
- onFocus(false);
518
- return true;
519
- }
520
- return false;
521
- }
522
- const alreadySelected = isOptionSelected(matchingOption, value, isMultiple);
523
- if (!alreadySelected) {
524
- wrappedOnChange(matchingOption);
525
- return true;
526
- }
527
- return false;
528
- }, [
529
- creationEnabled,
530
- isMultiple,
531
- isSingle,
532
- onFocus,
533
- options,
534
- setSearchText,
535
- setInsertText,
536
- toggleOpen,
537
- value,
538
- wrappedOnChange,
539
- ]);
540
547
  const resolvedInputProps = {
541
548
  ...inputProps,
542
549
  'aria-activedescendant': ariaActivedescendant,
@@ -559,9 +566,9 @@ const AutoComplete = forwardRef(function AutoComplete(props, ref) {
559
566
  [autocompleteClasses.hostMode(mode)]: mode,
560
567
  }), children: jsx(Dropdown, { actionText: shouldShowCreateAction
561
568
  ? createActionText
562
- ? createActionText(insertText)
563
- : createActionTextTemplate.replace('{text}', insertText)
564
- : undefined, activeIndex: activeIndex, disabled: isInputDisabled, emptyText: emptyText, followText: searchText, inputPosition: inputPosition, isMatchInputValue: true, listboxId: menuId, loadingText: loadingText, loadingPosition: loadingPosition, maxHeight: menuMaxHeight, mode: mode, onActionCustom: shouldShowCreateAction ? handleActionCustom : undefined, onItemHover: setActiveIndex, onSelect: handleDropdownSelect, onVisibilityChange: handleVisibilityChange, open: open, options: dropdownOptions, placement: "bottom", sameWidth: true, showDropdownActions: shouldShowCreateAction, showActionShowTopBar: shouldShowCreateAction, status: dropdownStatus, type: "default", value: dropdownValue, zIndex: dropdownZIndex, globalPortal: globalPortal, onReachBottom: onReachBottom, onLeaveBottom: onLeaveBottom, children: jsx(SelectTrigger, { ref: composedRef, active: open, className: className, clearable: true, disabled: isInputDisabled, fullWidth: fullWidth, isForceClearable: shouldForceClearable, inputRef: composedInputRef, mode: mode, onTagClose: wrappedOnChange, onClear: handleClear, overflowStrategy: overflowStrategy, placeholder: getPlaceholder(), prefix: prefix, readOnly: false, required: required, type: error ? 'error' : 'default', inputProps: {
569
+ ? createActionText(createActionDisplayText)
570
+ : createActionTextTemplate.replace('{text}', createActionDisplayText)
571
+ : undefined, activeIndex: activeIndex, disabled: isInputDisabled, emptyText: emptyText, followText: searchText, inputPosition: inputPosition, isMatchInputValue: true, listboxId: menuId, loadingText: loadingText, loadingPosition: loadingPosition, maxHeight: menuMaxHeight, mode: mode, onActionCustom: shouldShowCreateAction ? handleActionCustom : undefined, onItemHover: setActiveIndex, onSelect: handleDropdownSelect, onVisibilityChange: handleVisibilityChange, open: open, options: asyncData && isLoading ? [] : dropdownOptions, placement: "bottom", sameWidth: true, showDropdownActions: shouldShowCreateAction, showActionShowTopBar: shouldShowCreateAction, status: dropdownStatus, type: "default", value: dropdownValue, zIndex: dropdownZIndex, globalPortal: globalPortal, onReachBottom: onReachBottom, onLeaveBottom: onLeaveBottom, children: jsx(SelectTrigger, { ref: composedRef, active: open, className: className, clearable: true, disabled: isInputDisabled, fullWidth: fullWidth, isForceClearable: shouldForceClearable, inputRef: composedInputRef, mode: mode, onTagClose: wrappedOnChange, onClear: handleClear, overflowStrategy: isMultiple ? (overflowStrategy !== null && overflowStrategy !== void 0 ? overflowStrategy : 'wrap') : overflowStrategy, placeholder: getPlaceholder(), prefix: prefix, readOnly: false, required: required, type: error ? 'error' : 'default', inputProps: {
565
572
  ...resolvedInputProps,
566
573
  onClick: (e) => {
567
574
  var _a;
@@ -11,9 +11,10 @@ type UseAutoCompleteCreationParams = {
11
11
  clearNewlyCreated: (ids?: string[]) => void;
12
12
  markUnselected: (ids: string[]) => void;
13
13
  onChangeMultiple?: (newOptions: SelectValue[]) => void;
14
- onFocus: (focus: boolean) => void;
15
14
  onInsert?: (text: string, currentOptions: SelectValue[]) => SelectValue[];
15
+ onSetInputDisplay?: (text: string) => void;
16
16
  options: SelectValue[];
17
+ stepByStepBulkCreate?: boolean;
17
18
  toggleOpen: (newOpen: boolean | ((prev: boolean) => boolean)) => void;
18
19
  trimOnCreate: boolean;
19
20
  value: SelectValue[] | SelectValue | null | undefined;
@@ -21,7 +22,9 @@ type UseAutoCompleteCreationParams = {
21
22
  setSearchText: (value: string) => void;
22
23
  };
23
24
  type ProcessBulkCreate = (text: string) => string[];
24
- export declare function useAutoCompleteCreation({ addable, createSeparators, filterUnselected, clearUnselected, isMultiple, isSingle, markCreated, markUnselected, onChangeMultiple, onFocus, onInsert, options, toggleOpen, trimOnCreate, value, wrappedOnChange, setSearchText, clearNewlyCreated, }: UseAutoCompleteCreationParams): {
25
+ export declare function getFullParsedList(text: string, createSeparators: string[], trimOnCreate: boolean): string[];
26
+ export declare function useAutoCompleteCreation({ addable, createSeparators, filterUnselected, clearUnselected, isMultiple, isSingle, markCreated, markUnselected, onChangeMultiple, onInsert, onSetInputDisplay, options, stepByStepBulkCreate, toggleOpen, trimOnCreate, value, wrappedOnChange, setSearchText, clearNewlyCreated, }: UseAutoCompleteCreationParams): {
27
+ getPendingCreateList: (text: string) => string[];
25
28
  handleActionCustom: () => void;
26
29
  handleBulkCreate: (texts: string[]) => void;
27
30
  handlePaste: (e: ClipboardEvent<HTMLInputElement>) => void;
@@ -1,5 +1,20 @@
1
1
  import { useState, useRef, useEffect, useCallback } from 'react';
2
2
 
3
+ function getFullParsedList(text, createSeparators, trimOnCreate) {
4
+ if (!text)
5
+ return [];
6
+ let parts = [text];
7
+ createSeparators.forEach((separator) => {
8
+ const newParts = [];
9
+ parts.forEach((part) => {
10
+ newParts.push(...part.split(separator));
11
+ });
12
+ parts = newParts;
13
+ });
14
+ return parts
15
+ .map((part) => (trimOnCreate ? part.trim() : part))
16
+ .filter((part) => part.length > 0);
17
+ }
3
18
  function isMultipleValue(value) {
4
19
  return Array.isArray(value);
5
20
  }
@@ -15,7 +30,7 @@ function isOptionSelected(option, value, isMultiple) {
15
30
  }
16
31
  return false;
17
32
  }
18
- function useAutoCompleteCreation({ addable, createSeparators, filterUnselected, clearUnselected, isMultiple, isSingle, markCreated, markUnselected, onChangeMultiple, onFocus, onInsert, options, toggleOpen, trimOnCreate, value, wrappedOnChange, setSearchText, clearNewlyCreated, }) {
33
+ function useAutoCompleteCreation({ addable, createSeparators, filterUnselected, clearUnselected, isMultiple, isSingle, markCreated, markUnselected, onChangeMultiple, onInsert, onSetInputDisplay, options, stepByStepBulkCreate = false, toggleOpen, trimOnCreate, value, wrappedOnChange, setSearchText, clearNewlyCreated, }) {
19
34
  const [insertText, setInsertText] = useState('');
20
35
  const valueRef = useRef(value);
21
36
  useEffect(() => {
@@ -48,6 +63,11 @@ function useAutoCompleteCreation({ addable, createSeparators, filterUnselected,
48
63
  }
49
64
  return processed.filter((part) => !selectedNames.has(part.toLowerCase()));
50
65
  }, [addable, createSeparators, isMultiple, isSingle, onInsert, trimOnCreate]);
66
+ const getPendingCreateList = useCallback((text) => {
67
+ const processed = processBulkCreate(text);
68
+ const optionNames = new Set(options.map((o) => o.name.toLowerCase()));
69
+ return processed.filter((part) => !optionNames.has(part.toLowerCase()));
70
+ }, [options, processBulkCreate]);
51
71
  const handleBulkCreate = useCallback((texts) => {
52
72
  if (!addable || texts.length === 0 || !onInsert)
53
73
  return;
@@ -87,8 +107,6 @@ function useAutoCompleteCreation({ addable, createSeparators, filterUnselected,
87
107
  if (itemsToAdd.length > 0) {
88
108
  if (isSingle && itemsToAdd[0]) {
89
109
  wrappedOnChange(itemsToAdd[0]);
90
- toggleOpen(false);
91
- onFocus(false);
92
110
  newlySelectedIds.add(itemsToAdd[0].id);
93
111
  }
94
112
  else if (isMultiple) {
@@ -126,16 +144,36 @@ function useAutoCompleteCreation({ addable, createSeparators, filterUnselected,
126
144
  markCreated,
127
145
  markUnselected,
128
146
  onChangeMultiple,
129
- onFocus,
130
147
  onInsert,
131
148
  options,
132
- toggleOpen,
133
149
  wrappedOnChange,
134
150
  ]);
135
151
  const handleActionCustom = useCallback(() => {
136
152
  if (!addable || !insertText)
137
153
  return;
138
154
  const hasSeparator = createSeparators.some((sep) => insertText.includes(sep));
155
+ if (stepByStepBulkCreate && hasSeparator && isMultiple) {
156
+ const pending = getPendingCreateList(insertText);
157
+ const firstPending = pending[0];
158
+ if (!firstPending) {
159
+ resetCreationInputs();
160
+ onSetInputDisplay === null || onSetInputDisplay === void 0 ? void 0 : onSetInputDisplay('');
161
+ return;
162
+ }
163
+ handleBulkCreate([firstPending]);
164
+ toggleOpen(true);
165
+ const remaining = pending.slice(1).join(', ');
166
+ if (remaining) {
167
+ setSearchText(remaining);
168
+ setInsertText(remaining);
169
+ onSetInputDisplay === null || onSetInputDisplay === void 0 ? void 0 : onSetInputDisplay(remaining);
170
+ }
171
+ else {
172
+ resetCreationInputs();
173
+ onSetInputDisplay === null || onSetInputDisplay === void 0 ? void 0 : onSetInputDisplay('');
174
+ }
175
+ return;
176
+ }
139
177
  if (hasSeparator && isMultiple) {
140
178
  const textsToCreate = processBulkCreate(insertText);
141
179
  if (textsToCreate.length > 0) {
@@ -152,11 +190,16 @@ function useAutoCompleteCreation({ addable, createSeparators, filterUnselected,
152
190
  }, [
153
191
  addable,
154
192
  createSeparators,
193
+ getPendingCreateList,
155
194
  handleBulkCreate,
156
195
  insertText,
157
196
  isMultiple,
197
+ onSetInputDisplay,
158
198
  processBulkCreate,
159
199
  resetCreationInputs,
200
+ stepByStepBulkCreate,
201
+ setSearchText,
202
+ toggleOpen,
160
203
  ]);
161
204
  const handlePaste = useCallback((e) => {
162
205
  if (!addable || !onInsert) {
@@ -169,6 +212,15 @@ function useAutoCompleteCreation({ addable, createSeparators, filterUnselected,
169
212
  if (isMultiple) {
170
213
  const hasSeparator = createSeparators.some((sep) => pastedText.includes(sep));
171
214
  if (hasSeparator) {
215
+ if (stepByStepBulkCreate) {
216
+ e.preventDefault();
217
+ const pending = getPendingCreateList(pastedText);
218
+ const pendingJoin = pending.join(', ');
219
+ setSearchText(pendingJoin);
220
+ setInsertText(pendingJoin);
221
+ onSetInputDisplay === null || onSetInputDisplay === void 0 ? void 0 : onSetInputDisplay(pendingJoin);
222
+ return;
223
+ }
172
224
  e.preventDefault();
173
225
  const textsToCreate = processBulkCreate(pastedText);
174
226
  if (textsToCreate.length > 0) {
@@ -181,13 +233,19 @@ function useAutoCompleteCreation({ addable, createSeparators, filterUnselected,
181
233
  }, [
182
234
  addable,
183
235
  createSeparators,
236
+ getPendingCreateList,
184
237
  handleBulkCreate,
185
238
  isMultiple,
186
239
  onInsert,
240
+ onSetInputDisplay,
187
241
  processBulkCreate,
188
242
  resetCreationInputs,
243
+ setInsertText,
244
+ setSearchText,
245
+ stepByStepBulkCreate,
189
246
  ]);
190
247
  return {
248
+ getPendingCreateList,
191
249
  handleActionCustom,
192
250
  handleBulkCreate,
193
251
  handlePaste,
@@ -198,4 +256,4 @@ function useAutoCompleteCreation({ addable, createSeparators, filterUnselected,
198
256
  };
199
257
  }
200
258
 
201
- export { useAutoCompleteCreation };
259
+ export { getFullParsedList, useAutoCompleteCreation };
@@ -6,6 +6,7 @@ type UseAutoCompleteKeyboardParams = {
6
6
  addable: boolean;
7
7
  createSeparators: string[];
8
8
  dropdownOptions: DropdownOption[];
9
+ handleActionCustom: () => void;
9
10
  handleBulkCreate: (texts: string[]) => void;
10
11
  handleDropdownSelect: (option: DropdownOption) => void;
11
12
  inputRef?: Ref<HTMLInputElement>;
@@ -21,11 +22,12 @@ type UseAutoCompleteKeyboardParams = {
21
22
  setListboxHasVisualFocus: (focus: boolean) => void;
22
23
  setInsertText: (value: string) => void;
23
24
  setSearchText: (value: string) => void;
25
+ stepByStepBulkCreate?: boolean;
24
26
  toggleOpen: (newOpen: boolean | ((prev: boolean) => boolean)) => void;
25
27
  value: SelectValue[] | SelectValue | null | undefined;
26
28
  wrappedOnChange: (chooseOption: SelectValue | null) => SelectValue[] | SelectValue | null;
27
29
  };
28
- export declare function useAutoCompleteKeyboard({ activeIndex, addable, createSeparators, dropdownOptions, handleBulkCreate, handleDropdownSelect, inputPropsOnKeyDown, inputRef, mode, onFocus, open, processBulkCreate, searchText, searchTextExistWithoutOption, setActiveIndex, setInsertText, setListboxHasVisualFocus, setSearchText, toggleOpen, value, wrappedOnChange, }: UseAutoCompleteKeyboardParams): {
30
+ export declare function useAutoCompleteKeyboard({ activeIndex, addable, createSeparators, dropdownOptions, handleActionCustom, handleBulkCreate, handleDropdownSelect, inputPropsOnKeyDown, inputRef, mode, onFocus, open, processBulkCreate, searchText, searchTextExistWithoutOption, setActiveIndex, setInsertText, setListboxHasVisualFocus, setSearchText, stepByStepBulkCreate, toggleOpen, value, wrappedOnChange, }: UseAutoCompleteKeyboardParams): {
29
31
  handleInputKeyDown: (e: KeyboardEvent<HTMLInputElement>) => void;
30
32
  };
31
33
  export {};
@@ -4,7 +4,7 @@ import { createDropdownKeydownHandler } from '../Dropdown/dropdownKeydownHandler
4
4
  function isMultipleValue(value) {
5
5
  return Array.isArray(value);
6
6
  }
7
- function useAutoCompleteKeyboard({ activeIndex, addable, createSeparators, dropdownOptions, handleBulkCreate, handleDropdownSelect, inputPropsOnKeyDown, inputRef, mode, onFocus, open, processBulkCreate, searchText, searchTextExistWithoutOption, setActiveIndex, setInsertText, setListboxHasVisualFocus, setSearchText, toggleOpen, value, wrappedOnChange, }) {
7
+ function useAutoCompleteKeyboard({ activeIndex, addable, createSeparators, dropdownOptions, handleActionCustom, handleBulkCreate, handleDropdownSelect, inputPropsOnKeyDown, inputRef, mode, onFocus, open, processBulkCreate, searchText, searchTextExistWithoutOption, setActiveIndex, setInsertText, setListboxHasVisualFocus, setSearchText, stepByStepBulkCreate = false, toggleOpen, value, wrappedOnChange, }) {
8
8
  const handleKeyDown = useCallback((e) => createDropdownKeydownHandler({
9
9
  activeIndex,
10
10
  onEnterSelect: (option) => {
@@ -52,6 +52,12 @@ function useAutoCompleteKeyboard({ activeIndex, addable, createSeparators, dropd
52
52
  if (addable && searchText) {
53
53
  const hasSeparator = createSeparators.some((sep) => searchText.includes(sep));
54
54
  if (hasSeparator && mode === 'multiple') {
55
+ if (stepByStepBulkCreate) {
56
+ e.preventDefault();
57
+ e.stopPropagation();
58
+ handleActionCustom();
59
+ return true;
60
+ }
55
61
  e.preventDefault();
56
62
  e.stopPropagation();
57
63
  const textsToCreate = processBulkCreate(searchText);
@@ -94,6 +100,7 @@ function useAutoCompleteKeyboard({ activeIndex, addable, createSeparators, dropd
94
100
  addable,
95
101
  createSeparators,
96
102
  dropdownOptions,
103
+ handleActionCustom,
97
104
  handleBulkCreate,
98
105
  handleDropdownSelect,
99
106
  mode,
@@ -104,6 +111,7 @@ function useAutoCompleteKeyboard({ activeIndex, addable, createSeparators, dropd
104
111
  searchTextExistWithoutOption,
105
112
  setInsertText,
106
113
  setSearchText,
114
+ stepByStepBulkCreate,
107
115
  toggleOpen,
108
116
  ]);
109
117
  const handleInputKeyDown = useCallback((e) => {
@@ -34,8 +34,10 @@ function CalendarDays(props) {
34
34
  false;
35
35
  const inactive = !disabled && (isPrevMonth || isNextMonth);
36
36
  const inRange = !inactive && isDateInRange && isDateInRange(date);
37
- const inRangeStart = inRange && value ? isSameDate(date, value[0]) : false;
38
- const inRangeEnd = inRange && value
37
+ const inRangeStart = !inactive && value && value.length > 0
38
+ ? isSameDate(date, value[0])
39
+ : false;
40
+ const inRangeEnd = !inactive && value && value.length > 0
39
41
  ? isSameDate(date, value[value.length - 1])
40
42
  : false;
41
43
  const active = !disabled && !inactive && value && isDateIncluded(date, value);
@@ -75,7 +77,9 @@ function CalendarDays(props) {
75
77
  ? (() => {
76
78
  var _a, _b;
77
79
  const annotation = renderAnnotations(date);
78
- return (jsx(Typography, { variant: "annotation", color: (_a = annotation === null || annotation === void 0 ? void 0 : annotation.color) !== null && _a !== void 0 ? _a : 'text-neutral', children: (_b = annotation === null || annotation === void 0 ? void 0 : annotation.value) !== null && _b !== void 0 ? _b : '--' }));
80
+ return (jsx(Typography, { variant: "annotation", color: active
81
+ ? 'text-fixed-light'
82
+ : ((_a = annotation === null || annotation === void 0 ? void 0 : annotation.color) !== null && _a !== void 0 ? _a : 'text-neutral'), children: (_b = annotation === null || annotation === void 0 ? void 0 : annotation.value) !== null && _b !== void 0 ? _b : '--' }));
79
83
  })()
80
84
  : null] }) }, `${getMonth(date)}/${getDate(date)}`));
81
85
  }) }, `CALENDAR_DAYS/WEEK_OF/${index}`)))] }) }));
@@ -215,7 +215,7 @@ const RangeCalendar = forwardRef(function RangeCalendar(props, ref) {
215
215
  getTargetValue,
216
216
  handleRangeSelection,
217
217
  ]);
218
- return (jsxs("div", { ...restProps, ref: ref, role: "application", "aria-label": `Range calendar, ${mode} view`, className: cx(calendarClasses.host, className), children: [quickSelect && (jsx(CalendarQuickSelect, { activeId: quickSelect.activeId, options: quickSelect.options })), jsxs("div", { className: calendarClasses.mainWithFooter, children: [jsxs("div", { style: { display: 'inline-flex', flexFlow: 'row' }, children: [jsx(Calendar, { ...calendarProps, renderAnnotations: renderAnnotations, className: cx(calendarClasses.noShadowHost, calendarProps === null || calendarProps === void 0 ? void 0 : calendarProps.className), ref: firstCalendarRef, mode: currentMode, value: value, onChange: onChangeFactory(0), referenceDate: referenceDates[0], onPrev: onFirstPrev, onDoublePrev: onFirstDoublePrev, onMonthControlClick: onMonthControlClick, onYearControlClick: onYearControlClick, disabledFooterControl: true, disabledMonthSwitch: disabledMonthSwitch, disabledYearSwitch: disabledYearSwitch, disableOnPrev: disableOnPrev, disableOnDoublePrev: disableOnDoublePrev, displayMonthLocale: displayMonthLocale, displayWeekDayLocale: displayWeekDayLocale, isDateDisabled: isDateDisabled, isDateInRange: isDateInRange, onDateHover: onDateHover, isMonthDisabled: isMonthDisabled, isMonthInRange: isMonthInRange, onMonthHover: onMonthHover, isWeekDisabled: isWeekDisabled, isWeekInRange: isWeekInRange, onWeekHover: onWeekHover, isYearDisabled: isYearDisabled, isYearInRange: isYearInRange, onYearHover: onYearHover, isQuarterDisabled: isQuarterDisabled, isQuarterInRange: isQuarterInRange, onQuarterHover: onQuarterHover, isHalfYearDisabled: isHalfYearDisabled, isHalfYearInRange: isHalfYearInRange, onHalfYearHover: onHalfYearHover }), jsx(Calendar, { ...calendarProps, renderAnnotations: renderAnnotations, className: cx(calendarClasses.noShadowHost, calendarProps === null || calendarProps === void 0 ? void 0 : calendarProps.className), ref: secondCalendarRef, mode: currentMode, value: value, onChange: onChangeFactory(1), referenceDate: referenceDates[1], onNext: onSecondNext, onDoubleNext: onSecondDoubleNext, onMonthControlClick: onMonthControlClick, onYearControlClick: onYearControlClick, disabledFooterControl: true, disabledMonthSwitch: disabledMonthSwitch, disabledYearSwitch: disabledYearSwitch, disableOnNext: disableOnNext, disableOnDoubleNext: disableOnDoubleNext, displayMonthLocale: displayMonthLocale, displayWeekDayLocale: displayWeekDayLocale, isDateDisabled: isDateDisabled, isDateInRange: isDateInRange, onDateHover: onDateHover, isMonthDisabled: isMonthDisabled, isMonthInRange: isMonthInRange, onMonthHover: onMonthHover, isWeekDisabled: isWeekDisabled, isWeekInRange: isWeekInRange, onWeekHover: onWeekHover, isYearDisabled: isYearDisabled, isYearInRange: isYearInRange, onYearHover: onYearHover, isQuarterDisabled: isQuarterDisabled, isQuarterInRange: isQuarterInRange, onQuarterHover: onQuarterHover, isHalfYearDisabled: isHalfYearDisabled, isHalfYearInRange: isHalfYearInRange, onHalfYearHover: onHalfYearHover })] }), actions && (jsx(CalendarFooterActions, { actions: {
218
+ return (jsxs("div", { ...restProps, ref: ref, role: "application", "aria-label": `Range calendar, ${mode} view`, className: cx(calendarClasses.host, className), children: [quickSelect && (jsx(CalendarQuickSelect, { activeId: quickSelect.activeId, options: quickSelect.options })), jsxs("div", { className: calendarClasses.mainWithFooter, children: [jsxs("div", { className: calendarClasses.mainRangeCalendarWrapper, children: [jsx(Calendar, { ...calendarProps, renderAnnotations: renderAnnotations, className: cx(calendarClasses.noShadowHost, calendarProps === null || calendarProps === void 0 ? void 0 : calendarProps.className), ref: firstCalendarRef, mode: currentMode, value: value, onChange: onChangeFactory(0), referenceDate: referenceDates[0], onPrev: onFirstPrev, onDoublePrev: onFirstDoublePrev, onMonthControlClick: onMonthControlClick, onYearControlClick: onYearControlClick, disabledFooterControl: true, disabledMonthSwitch: disabledMonthSwitch, disabledYearSwitch: disabledYearSwitch, disableOnPrev: disableOnPrev, disableOnDoublePrev: disableOnDoublePrev, displayMonthLocale: displayMonthLocale, displayWeekDayLocale: displayWeekDayLocale, isDateDisabled: isDateDisabled, isDateInRange: isDateInRange, onDateHover: onDateHover, isMonthDisabled: isMonthDisabled, isMonthInRange: isMonthInRange, onMonthHover: onMonthHover, isWeekDisabled: isWeekDisabled, isWeekInRange: isWeekInRange, onWeekHover: onWeekHover, isYearDisabled: isYearDisabled, isYearInRange: isYearInRange, onYearHover: onYearHover, isQuarterDisabled: isQuarterDisabled, isQuarterInRange: isQuarterInRange, onQuarterHover: onQuarterHover, isHalfYearDisabled: isHalfYearDisabled, isHalfYearInRange: isHalfYearInRange, onHalfYearHover: onHalfYearHover }), jsx(Calendar, { ...calendarProps, renderAnnotations: renderAnnotations, className: cx(calendarClasses.noShadowHost, calendarProps === null || calendarProps === void 0 ? void 0 : calendarProps.className), ref: secondCalendarRef, mode: currentMode, value: value, onChange: onChangeFactory(1), referenceDate: referenceDates[1], onNext: onSecondNext, onDoubleNext: onSecondDoubleNext, onMonthControlClick: onMonthControlClick, onYearControlClick: onYearControlClick, disabledFooterControl: true, disabledMonthSwitch: disabledMonthSwitch, disabledYearSwitch: disabledYearSwitch, disableOnNext: disableOnNext, disableOnDoubleNext: disableOnDoubleNext, displayMonthLocale: displayMonthLocale, displayWeekDayLocale: displayWeekDayLocale, isDateDisabled: isDateDisabled, isDateInRange: isDateInRange, onDateHover: onDateHover, isMonthDisabled: isMonthDisabled, isMonthInRange: isMonthInRange, onMonthHover: onMonthHover, isWeekDisabled: isWeekDisabled, isWeekInRange: isWeekInRange, onWeekHover: onWeekHover, isYearDisabled: isYearDisabled, isYearInRange: isYearInRange, onYearHover: onYearHover, isQuarterDisabled: isQuarterDisabled, isQuarterInRange: isQuarterInRange, onQuarterHover: onQuarterHover, isHalfYearDisabled: isHalfYearDisabled, isHalfYearInRange: isHalfYearInRange, onHalfYearHover: onHalfYearHover })] }), actions && (jsx(CalendarFooterActions, { actions: {
219
219
  secondaryButtonProps: {
220
220
  children: 'Cancel',
221
221
  disabled: false,