@astryxdesign/core 0.7.3 → 0.7.4-canary.1a552f2

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 (143) hide show
  1. package/dist/BottomSheet/BottomSheet.d.ts +18 -6
  2. package/dist/BottomSheet/BottomSheet.d.ts.map +1 -1
  3. package/dist/BottomSheet/BottomSheet.js +268 -58
  4. package/dist/BottomSheet/BottomSheetSwitcher.d.ts +41 -12
  5. package/dist/BottomSheet/BottomSheetSwitcher.d.ts.map +1 -1
  6. package/dist/BottomSheet/BottomSheetSwitcher.js +294 -165
  7. package/dist/BottomSheet/BottomSheetSwitcherContext.d.ts +51 -1
  8. package/dist/BottomSheet/BottomSheetSwitcherContext.d.ts.map +1 -1
  9. package/dist/BottomSheet/BottomSheetSwitcherContext.js +13 -1
  10. package/dist/Carousel/Carousel.d.ts.map +1 -1
  11. package/dist/Carousel/Carousel.js +7 -11
  12. package/dist/Chat/ChatMessageList.d.ts.map +1 -1
  13. package/dist/Chat/ChatMessageList.js +8 -1
  14. package/dist/Chat/useTriggerMenu.d.ts.map +1 -1
  15. package/dist/Chat/useTriggerMenu.js +46 -7
  16. package/dist/CheckboxInput/CheckboxInput.d.ts.map +1 -1
  17. package/dist/CheckboxInput/CheckboxInput.js +6 -0
  18. package/dist/CommandPalette/CommandPalette.d.ts.map +1 -1
  19. package/dist/CommandPalette/CommandPalette.js +6 -11
  20. package/dist/CommandPalette/CommandPaletteInput.d.ts.map +1 -1
  21. package/dist/CommandPalette/CommandPaletteInput.js +7 -1
  22. package/dist/ComplexSelector/ComplexSelector.d.ts.map +1 -1
  23. package/dist/ComplexSelector/ComplexSelector.js +6 -1
  24. package/dist/ContextMenu/ContextMenu.d.ts.map +1 -1
  25. package/dist/ContextMenu/ContextMenu.js +12 -0
  26. package/dist/DateInput/DateInput.d.ts.map +1 -1
  27. package/dist/DateInput/DateInput.js +6 -1
  28. package/dist/DateInput/NativeDateField.d.ts.map +1 -1
  29. package/dist/DateInput/NativeDateField.js +6 -1
  30. package/dist/DateInput/TouchDateField.d.ts.map +1 -1
  31. package/dist/DateInput/TouchDateField.js +9 -1
  32. package/dist/DateRangeInput/DateRangeInput.d.ts.map +1 -1
  33. package/dist/DateRangeInput/DateRangeInput.js +6 -1
  34. package/dist/DateTimeInput/DateTimeInput.d.ts.map +1 -1
  35. package/dist/DateTimeInput/DateTimeInput.js +6 -1
  36. package/dist/DateTimeInput/TouchDateTimeField.d.ts.map +1 -1
  37. package/dist/DateTimeInput/TouchDateTimeField.js +9 -1
  38. package/dist/DropdownMenu/DropdownMenuSubMenu.d.ts.map +1 -1
  39. package/dist/DropdownMenu/DropdownMenuSubMenu.js +7 -1
  40. package/dist/FileInput/FileInput.d.ts.map +1 -1
  41. package/dist/FileInput/FileInput.js +16 -2
  42. package/dist/MultiSelector/MultiSelector.d.ts.map +1 -1
  43. package/dist/MultiSelector/MultiSelector.js +6 -1
  44. package/dist/Selector/Selector.d.ts.map +1 -1
  45. package/dist/Selector/Selector.js +6 -1
  46. package/dist/TextArea/TextArea.d.ts.map +1 -1
  47. package/dist/TextArea/TextArea.js +6 -1
  48. package/dist/TextInput/TextInput.d.ts.map +1 -1
  49. package/dist/TextInput/TextInput.js +6 -1
  50. package/dist/Thumbnail/Thumbnail.d.ts.map +1 -1
  51. package/dist/Thumbnail/Thumbnail.js +9 -2
  52. package/dist/TimeInput/TimeInput.d.ts.map +1 -1
  53. package/dist/TimeInput/TimeInput.js +6 -1
  54. package/dist/TimeInput/TouchTimeField.d.ts.map +1 -1
  55. package/dist/TimeInput/TouchTimeField.js +9 -1
  56. package/dist/Tokenizer/Tokenizer.d.ts.map +1 -1
  57. package/dist/Tokenizer/Tokenizer.js +9 -1
  58. package/dist/Typeahead/BaseTypeahead.d.ts.map +1 -1
  59. package/dist/Typeahead/BaseTypeahead.js +7 -1
  60. package/dist/Typeahead/Typeahead.d.ts.map +1 -1
  61. package/dist/Typeahead/Typeahead.js +9 -1
  62. package/dist/astryx.css +2 -0
  63. package/dist/hooks/useBusyAnnouncement.d.ts +22 -0
  64. package/dist/hooks/useBusyAnnouncement.d.ts.map +1 -0
  65. package/dist/hooks/useBusyAnnouncement.js +87 -0
  66. package/dist/hooks/useMenuPress.d.ts +2 -2
  67. package/dist/hooks/useMenuPress.d.ts.map +1 -1
  68. package/dist/hooks/useMenuPress.js +5 -1
  69. package/dist/hooks/useTypeahead.d.ts.map +1 -1
  70. package/dist/hooks/useTypeahead.js +7 -2
  71. package/dist/i18n/generated-locales/en.generated.d.ts.map +1 -1
  72. package/dist/i18n/generated-locales/en.generated.js +1 -0
  73. package/dist/i18n/generated-locales/pseudo.generated.d.ts.map +1 -1
  74. package/dist/i18n/generated-locales/pseudo.generated.js +1 -0
  75. package/locales/en.json +6 -2
  76. package/locales/pseudo.json +3 -0
  77. package/package.json +4 -4
  78. package/src/BottomSheet/BottomSheet.doc.mjs +2 -2
  79. package/src/BottomSheet/BottomSheet.spec.md +3 -5
  80. package/src/BottomSheet/BottomSheet.tsx +260 -47
  81. package/src/BottomSheet/BottomSheetEdgeTint.test.tsx +29 -4
  82. package/src/BottomSheet/BottomSheetSwitcher.doc.mjs +11 -10
  83. package/src/BottomSheet/BottomSheetSwitcher.spec.md +35 -41
  84. package/src/BottomSheet/BottomSheetSwitcher.test.tsx +1051 -49
  85. package/src/BottomSheet/BottomSheetSwitcher.tsx +396 -215
  86. package/src/BottomSheet/BottomSheetSwitcherContext.ts +57 -2
  87. package/src/BottomSheet/__tests__/BottomSheetNativeModal.a11y.browser.spec.ts +461 -0
  88. package/src/Carousel/Carousel.test.tsx +8 -12
  89. package/src/Carousel/Carousel.tsx +6 -13
  90. package/src/Chat/ChatComposerInput.test.tsx +167 -1
  91. package/src/Chat/ChatMessageList.test.tsx +6 -2
  92. package/src/Chat/ChatMessageList.tsx +7 -1
  93. package/src/Chat/__tests__/ChatMessageList.a11y.chromium.spec.ts +20 -12
  94. package/src/Chat/useTriggerMenu.tsx +55 -6
  95. package/src/CheckboxInput/CheckboxInput.tsx +6 -0
  96. package/src/CommandPalette/CommandPalette.test.tsx +4 -2
  97. package/src/CommandPalette/CommandPalette.tsx +6 -11
  98. package/src/CommandPalette/CommandPaletteInput.test.tsx +3 -1
  99. package/src/CommandPalette/CommandPaletteInput.tsx +10 -1
  100. package/src/ComplexSelector/ComplexSelector.tsx +5 -1
  101. package/src/ContextMenu/ContextMenu.test.tsx +34 -0
  102. package/src/ContextMenu/ContextMenu.tsx +13 -1
  103. package/src/DateInput/DateInput.tsx +5 -1
  104. package/src/DateInput/DateInputTouch.test.tsx +45 -0
  105. package/src/DateInput/NativeDateField.test.tsx +10 -2
  106. package/src/DateInput/NativeDateField.tsx +5 -1
  107. package/src/DateInput/TouchDateField.tsx +14 -2
  108. package/src/DateRangeInput/DateRangeInput.tsx +5 -1
  109. package/src/DateTimeInput/DateTimeInput.tsx +5 -1
  110. package/src/DateTimeInput/TouchDateTimeField.tsx +14 -2
  111. package/src/DropdownMenu/DropdownMenuSubMenu.tsx +10 -1
  112. package/src/FileInput/FileInput.tsx +18 -2
  113. package/src/MultiSelector/MultiSelector.test.tsx +18 -4
  114. package/src/MultiSelector/MultiSelector.tsx +5 -1
  115. package/src/ProgressBar/ProgressBar.test.tsx +4 -21
  116. package/src/ProgressBar/__tests__/ProgressBar.a11y.chromium.spec.ts +114 -0
  117. package/src/ProgressBar/__tests__/ProgressBar.a11y.known-failures.ts +12 -0
  118. package/src/ProgressBar/__tests__/ProgressBar.a11y.renders.tsx +38 -0
  119. package/src/ProgressBar/__tests__/ProgressBar.a11y.states.ts +123 -0
  120. package/src/ProgressBar/__tests__/ProgressBar.a11y.test.tsx +107 -0
  121. package/src/Selector/Selector.test.tsx +22 -5
  122. package/src/Selector/Selector.tsx +5 -1
  123. package/src/TextArea/TextArea.test.tsx +9 -1
  124. package/src/TextArea/TextArea.tsx +5 -1
  125. package/src/TextInput/TextInput.tsx +5 -1
  126. package/src/Thumbnail/Thumbnail.test.tsx +6 -1
  127. package/src/Thumbnail/Thumbnail.tsx +12 -3
  128. package/src/TimeInput/TimeInput.tsx +5 -1
  129. package/src/TimeInput/TouchTimeField.tsx +12 -2
  130. package/src/Tokenizer/Tokenizer.test.tsx +17 -12
  131. package/src/Tokenizer/Tokenizer.tsx +10 -1
  132. package/src/Typeahead/BaseTypeahead.tsx +14 -1
  133. package/src/Typeahead/Typeahead.test.tsx +32 -41
  134. package/src/Typeahead/Typeahead.tsx +10 -1
  135. package/src/__tests__/BusyOwnerAnnouncement.test.tsx +792 -0
  136. package/src/hooks/__tests__/MenuPressShadowRoot.a11y.chromium.spec.ts +50 -0
  137. package/src/hooks/useBusyAnnouncement.ts +100 -0
  138. package/src/hooks/useMenuPress.test.tsx +27 -1
  139. package/src/hooks/useMenuPress.ts +12 -3
  140. package/src/hooks/useTypeahead.test.tsx +42 -1
  141. package/src/hooks/useTypeahead.ts +7 -2
  142. package/src/i18n/generated-locales/en.generated.ts +1 -0
  143. package/src/i18n/generated-locales/pseudo.generated.ts +1 -0
@@ -62,6 +62,7 @@ import {themeProps} from '../utils/themeProps';
62
62
  import {useTranslator} from '../i18n';
63
63
 
64
64
  import {useMergedRefs} from '../hooks/useMergedRefs';
65
+ import {useBusyAnnouncement} from '../hooks/useBusyAnnouncement';
65
66
  import {layerViewportInset} from '../Layer/layerViewportInset.stylex';
66
67
  import {clampInlineSize} from '../Layer/clampInlineSize';
67
68
  // =============================================================================
@@ -561,6 +562,14 @@ export const BaseTypeahead = function BaseTypeahead<T extends SearchableItem>({
561
562
  // A wrapper that owns the inline-end lane subscribes through context; see
562
563
  // busyIndicatorLane.tsx for why this is not a prop.
563
564
  const busyLane = useBusyIndicatorLane();
565
+ // Without a wrapper that took the indicator over, this input announces each
566
+ // search's busy start (spec:AST-086 FR8); its Spinner stays named but is not
567
+ // a live region (family:input-fields FR7).
568
+ useBusyAnnouncement(
569
+ isLoading && busyLane == null,
570
+ t('@astryx.typeahead.loading'),
571
+ inputRef,
572
+ );
564
573
  const onLoadingChangeRef = useRef(busyLane?.onBusyChange);
565
574
  useIsomorphicLayoutEffect(() => {
566
575
  onLoadingChangeRef.current = busyLane?.onBusyChange;
@@ -1218,7 +1227,11 @@ export const BaseTypeahead = function BaseTypeahead<T extends SearchableItem>({
1218
1227
  />
1219
1228
  {isLoading && busyLane == null && (
1220
1229
  <span {...stylex.props(styles.loadingStatus)}>
1221
- <Spinner size="sm" aria-label={t('@astryx.typeahead.loading')} />
1230
+ <Spinner
1231
+ size="sm"
1232
+ aria-label={t('@astryx.typeahead.loading')}
1233
+ role="img"
1234
+ />
1222
1235
  </span>
1223
1236
  )}
1224
1237
  {popover.render(
@@ -99,6 +99,17 @@ const fruitSource: SearchSource = {
99
99
  bootstrap: () => fruits.slice(0, 3),
100
100
  };
101
101
 
102
+ /**
103
+ * The search Spinner: named but not live (family:input-fields FR7,
104
+ * spec:AST-086 FR8), so it is found as an image named "Loading".
105
+ */
106
+ function queryBusySpinner(): Element | null {
107
+ return screen.queryByRole('img', {name: 'Loading'});
108
+ }
109
+ function getBusySpinner(): Element {
110
+ return screen.getByRole('img', {name: 'Loading'});
111
+ }
112
+
102
113
  describe('BaseTypeahead', () => {
103
114
  it('renders input with combobox role', () => {
104
115
  render(
@@ -929,14 +940,12 @@ describe('BaseTypeahead hasEntriesOnFocus', () => {
929
940
 
930
941
  fireEvent.change(input, {target: {value: 'a'}});
931
942
  await waitFor(() => {
932
- expect(screen.getByRole('status', {name: 'Loading'})).toBeInTheDocument();
943
+ expect(getBusySpinner()).toBeInTheDocument();
933
944
  });
934
945
 
935
946
  fireEvent.change(input, {target: {value: ''}});
936
947
  await waitFor(() => {
937
- expect(
938
- screen.queryByRole('status', {name: 'Loading'}),
939
- ).not.toBeInTheDocument();
948
+ expect(queryBusySpinner()).not.toBeInTheDocument();
940
949
  });
941
950
 
942
951
  await act(async () => {
@@ -966,16 +975,14 @@ describe('BaseTypeahead hasEntriesOnFocus', () => {
966
975
 
967
976
  fireEvent.focus(input);
968
977
  await waitFor(() => {
969
- expect(screen.getByRole('status', {name: 'Loading'})).toBeInTheDocument();
978
+ expect(getBusySpinner()).toBeInTheDocument();
970
979
  });
971
980
 
972
981
  await act(async () => {
973
982
  settle([]);
974
983
  await Promise.resolve();
975
984
  });
976
- expect(
977
- screen.queryByRole('status', {name: 'Loading'}),
978
- ).not.toBeInTheDocument();
985
+ expect(queryBusySpinner()).not.toBeInTheDocument();
979
986
  });
980
987
 
981
988
  it('clears the loading state when the search source is replaced during an in-flight load', async () => {
@@ -1004,7 +1011,7 @@ describe('BaseTypeahead hasEntriesOnFocus', () => {
1004
1011
 
1005
1012
  fireEvent.focus(input);
1006
1013
  await waitFor(() => {
1007
- expect(screen.getByRole('status', {name: 'Loading'})).toBeInTheDocument();
1014
+ expect(getBusySpinner()).toBeInTheDocument();
1008
1015
  });
1009
1016
 
1010
1017
  rerender(
@@ -1017,18 +1024,14 @@ describe('BaseTypeahead hasEntriesOnFocus', () => {
1017
1024
  );
1018
1025
 
1019
1026
  await waitFor(() => {
1020
- expect(
1021
- screen.queryByRole('status', {name: 'Loading'}),
1022
- ).not.toBeInTheDocument();
1027
+ expect(queryBusySpinner()).not.toBeInTheDocument();
1023
1028
  });
1024
1029
 
1025
1030
  await act(async () => {
1026
1031
  settle([]);
1027
1032
  await Promise.resolve();
1028
1033
  });
1029
- expect(
1030
- screen.queryByRole('status', {name: 'Loading'}),
1031
- ).not.toBeInTheDocument();
1034
+ expect(queryBusySpinner()).not.toBeInTheDocument();
1032
1035
  });
1033
1036
 
1034
1037
  it('keeps the loading state under StrictMode for a pending autofocus bootstrap', async () => {
@@ -1052,15 +1055,13 @@ describe('BaseTypeahead hasEntriesOnFocus', () => {
1052
1055
  </StrictMode>,
1053
1056
  );
1054
1057
 
1055
- expect(screen.getByRole('status', {name: 'Loading'})).toBeInTheDocument();
1058
+ expect(getBusySpinner()).toBeInTheDocument();
1056
1059
 
1057
1060
  await act(async () => {
1058
1061
  settle([]);
1059
1062
  await Promise.resolve();
1060
1063
  });
1061
- expect(
1062
- screen.queryByRole('status', {name: 'Loading'}),
1063
- ).not.toBeInTheDocument();
1064
+ expect(queryBusySpinner()).not.toBeInTheDocument();
1064
1065
  });
1065
1066
 
1066
1067
  let settlePendingTransitionA: (items: SearchableItem[]) => void = () => {};
@@ -1125,7 +1126,7 @@ describe('BaseTypeahead hasEntriesOnFocus', () => {
1125
1126
  await waitFor(() => {
1126
1127
  expect(input).toHaveAttribute('aria-busy', 'true');
1127
1128
  });
1128
- expect(screen.getByRole('status', {name: 'Loading'})).toBeInTheDocument();
1129
+ expect(getBusySpinner()).toBeInTheDocument();
1129
1130
 
1130
1131
  // Create the pending promise for suspension
1131
1132
  isSuspended = true;
@@ -1160,9 +1161,7 @@ describe('BaseTypeahead hasEntriesOnFocus', () => {
1160
1161
 
1161
1162
  // The combobox must not keep aria-busy and the spinner must be gone
1162
1163
  expect(input).not.toHaveAttribute('aria-busy');
1163
- expect(
1164
- screen.queryByRole('status', {name: 'Loading'}),
1165
- ).not.toBeInTheDocument();
1164
+ expect(queryBusySpinner()).not.toBeInTheDocument();
1166
1165
  });
1167
1166
 
1168
1167
  it('shows bootstrap results on mouse click', async () => {
@@ -1443,7 +1442,7 @@ describe('BaseTypeahead minQueryLength', () => {
1443
1442
 
1444
1443
  fireEvent.change(input, {target: {value: 'App'}});
1445
1444
  await waitFor(() => {
1446
- expect(screen.getByRole('status', {name: 'Loading'})).toBeInTheDocument();
1445
+ expect(getBusySpinner()).toBeInTheDocument();
1447
1446
  });
1448
1447
  expect(input).toHaveAttribute('aria-busy', 'true');
1449
1448
 
@@ -1453,9 +1452,7 @@ describe('BaseTypeahead minQueryLength', () => {
1453
1452
  await Promise.resolve();
1454
1453
  });
1455
1454
 
1456
- expect(
1457
- screen.queryByRole('status', {name: 'Loading'}),
1458
- ).not.toBeInTheDocument();
1455
+ expect(queryBusySpinner()).not.toBeInTheDocument();
1459
1456
  expect(input).not.toHaveAttribute('aria-busy');
1460
1457
  expect(input).toHaveAttribute('aria-expanded', 'false');
1461
1458
  });
@@ -2185,12 +2182,12 @@ describe('busy indicator ownership', () => {
2185
2182
  };
2186
2183
  };
2187
2184
 
2188
- it('renders its own named status for a direct caller', async () => {
2185
+ it('renders its own indicator for a direct caller', async () => {
2189
2186
  // BaseTypeaheadProps is re-exported from the package entry point, so the
2190
2187
  // base has direct callers this repo cannot see. They painted no indicator
2191
- // of their own — the base did it for them — so it keeps doing it, and the
2192
- // status stays a named one rather than a bare aria-busy that only reaches
2193
- // assistive tech.
2188
+ // of their own — the base did it for them — so it keeps doing it. The
2189
+ // Spinner is decorative and the base announces the search's busy start
2190
+ // through the shared channel (spec:AST-086 FR8).
2194
2191
  const {source, settle} = pendingSource();
2195
2192
  render(
2196
2193
  <BaseTypeahead
@@ -2204,22 +2201,18 @@ describe('busy indicator ownership', () => {
2204
2201
 
2205
2202
  fireEvent.change(input, {target: {value: 'App'}});
2206
2203
  await waitFor(() => {
2207
- expect(screen.getByRole('status', {name: 'Loading'})).toBeInTheDocument();
2204
+ expect(getBusySpinner()).toBeInTheDocument();
2208
2205
  });
2209
2206
  // A Spinner, not the static clock glyph this used to render: `clock`
2210
2207
  // means *time* everywhere else in core, and nothing about it moved while
2211
2208
  // a search was out.
2212
- expect(
2213
- screen.getByRole('status', {name: 'Loading'}).querySelector('svg'),
2214
- ).toBeInTheDocument();
2209
+ expect(getBusySpinner().querySelector('svg')).toBeInTheDocument();
2215
2210
 
2216
2211
  await act(async () => {
2217
2212
  settle();
2218
2213
  await Promise.resolve();
2219
2214
  });
2220
- expect(
2221
- screen.queryByRole('status', {name: 'Loading'}),
2222
- ).not.toBeInTheDocument();
2215
+ expect(queryBusySpinner()).not.toBeInTheDocument();
2223
2216
  });
2224
2217
 
2225
2218
  it('hands the indicator over to a field that takes it, and renders none itself', async () => {
@@ -2250,9 +2243,7 @@ describe('busy indicator ownership', () => {
2250
2243
  });
2251
2244
  // Scoped by name: the announcer for result counts is a role="status"
2252
2245
  // live region too, and it is not the indicator.
2253
- expect(
2254
- screen.queryByRole('status', {name: 'Loading'}),
2255
- ).not.toBeInTheDocument();
2246
+ expect(queryBusySpinner()).not.toBeInTheDocument();
2256
2247
  expect(onLoadingChange).toHaveBeenLastCalledWith(true);
2257
2248
 
2258
2249
  await act(async () => {
@@ -25,6 +25,7 @@ import React, {
25
25
  useMemo,
26
26
  useState,
27
27
  type ReactNode,
28
+ type RefObject,
28
29
  } from 'react';
29
30
  import * as stylex from '@stylexjs/stylex';
30
31
  import {
@@ -70,6 +71,7 @@ import {themeProps} from '../utils/themeProps';
70
71
  import {useTranslator} from '../i18n';
71
72
 
72
73
  import {useMergedRefs} from '../hooks/useMergedRefs';
74
+ import {useBusyAnnouncement} from '../hooks/useBusyAnnouncement';
73
75
  export type {
74
76
  InputStatus as TypeaheadStatus,
75
77
  InputStatusType as TypeaheadStatusType,
@@ -349,19 +351,25 @@ const wrapperSizeStyles = stylex.create({
349
351
  function EndLane({
350
352
  lane,
351
353
  loadingLabel,
354
+ anchorRef,
352
355
  clear,
353
356
  }: {
354
357
  lane: BusyIndicatorLane;
355
358
  loadingLabel: string;
359
+ anchorRef: RefObject<Element | null>;
356
360
  clear: ReactNode;
357
361
  }) {
358
362
  const isBusy = useIsBusy(lane);
363
+ // The search Spinner stays named (family:input-fields FR7) but is not a
364
+ // live region; the field announces each search's busy start instead
365
+ // (spec:AST-086 FR8).
366
+ useBusyAnnouncement(isBusy, loadingLabel, anchorRef);
359
367
  if (!isBusy && clear == null) {
360
368
  return null;
361
369
  }
362
370
  return (
363
371
  <div {...stylex.props(styles.endLane)}>
364
- {isBusy && <Spinner size="sm" aria-label={loadingLabel} />}
372
+ {isBusy && <Spinner size="sm" aria-label={loadingLabel} role="img" />}
365
373
  {clear}
366
374
  </div>
367
375
  );
@@ -679,6 +687,7 @@ export function Typeahead<T extends SearchableItem>({
679
687
  <EndLane
680
688
  lane={busyLane}
681
689
  loadingLabel={t('@astryx.typeahead.loading')}
690
+ anchorRef={wrapperRef}
682
691
  clear={
683
692
  hasClear && value && !isDisabled ? (
684
693
  <InputClearButton