@transferwise/components 0.0.0-experimental-e9426b6 → 0.0.0-experimental-0397551

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 (182) hide show
  1. package/build/dateInput/DateInput.js +3 -6
  2. package/build/dateInput/DateInput.js.map +1 -1
  3. package/build/dateInput/DateInput.mjs +2 -5
  4. package/build/dateInput/DateInput.mjs.map +1 -1
  5. package/build/expressiveMoneyInput/currencySelector/CurrencySelector.js +3 -5
  6. package/build/expressiveMoneyInput/currencySelector/CurrencySelector.js.map +1 -1
  7. package/build/expressiveMoneyInput/currencySelector/CurrencySelector.mjs +1 -3
  8. package/build/expressiveMoneyInput/currencySelector/CurrencySelector.mjs.map +1 -1
  9. package/build/index.js +3 -5
  10. package/build/index.js.map +1 -1
  11. package/build/index.mjs +1 -3
  12. package/build/index.mjs.map +1 -1
  13. package/build/inputs/SelectInput.js +821 -0
  14. package/build/inputs/SelectInput.js.map +1 -0
  15. package/build/inputs/SelectInput.messages.js.map +1 -0
  16. package/build/inputs/SelectInput.messages.mjs.map +1 -0
  17. package/build/inputs/SelectInput.mjs +813 -0
  18. package/build/inputs/SelectInput.mjs.map +1 -0
  19. package/build/main.css +47 -47
  20. package/build/moneyInput/MoneyInput.js +2 -5
  21. package/build/moneyInput/MoneyInput.js.map +1 -1
  22. package/build/moneyInput/MoneyInput.mjs +1 -4
  23. package/build/moneyInput/MoneyInput.mjs.map +1 -1
  24. package/build/phoneNumberInput/PhoneNumberInput.js +2 -5
  25. package/build/phoneNumberInput/PhoneNumberInput.js.map +1 -1
  26. package/build/phoneNumberInput/PhoneNumberInput.mjs +1 -4
  27. package/build/phoneNumberInput/PhoneNumberInput.mjs.map +1 -1
  28. package/build/styles/main.css +47 -47
  29. package/build/types/inputs/{SelectInput/SelectInput.types.d.ts → SelectInput.d.ts} +7 -4
  30. package/build/types/inputs/SelectInput.d.ts.map +1 -0
  31. package/build/types/inputs/SelectInput.messages.d.ts.map +1 -0
  32. package/package.json +1 -1
  33. package/src/actionButton/ActionButton.story.tsx +3 -0
  34. package/src/checkbox/Checkbox.story.tsx +3 -0
  35. package/src/circularButton/CircularButton.story.tsx +3 -0
  36. package/src/common/bottomSheet/BottomSheet.story.tsx +12 -0
  37. package/src/common/circle/Circle.story.tsx +3 -0
  38. package/src/criticalBanner/CriticalCommsBanner.story.tsx +3 -0
  39. package/src/dateInput/DateInput.test.story.tsx +6 -0
  40. package/src/dateLookup/DateLookup.story.tsx +3 -0
  41. package/src/info/Info.story.tsx +6 -0
  42. package/src/inputs/{SelectInput/SelectInput.docs.mdx → SelectInput.docs.mdx} +1 -0
  43. package/src/inputs/SelectInput.less +219 -0
  44. package/src/inputs/{SelectInput/SelectInput.story.tsx → SelectInput.story.tsx} +7 -7
  45. package/src/inputs/SelectInput.tsx +1190 -0
  46. package/src/main.css +47 -47
  47. package/src/main.less +1 -1
  48. package/src/modal/Modal.story.tsx +15 -0
  49. package/src/snackbar/Snackbar.test.story.tsx +9 -0
  50. package/build/inputs/SelectInput/SelectInput.helpers.js +0 -115
  51. package/build/inputs/SelectInput/SelectInput.helpers.js.map +0 -1
  52. package/build/inputs/SelectInput/SelectInput.helpers.mjs +0 -109
  53. package/build/inputs/SelectInput/SelectInput.helpers.mjs.map +0 -1
  54. package/build/inputs/SelectInput/SelectInput.js +0 -216
  55. package/build/inputs/SelectInput/SelectInput.js.map +0 -1
  56. package/build/inputs/SelectInput/SelectInput.messages.js.map +0 -1
  57. package/build/inputs/SelectInput/SelectInput.messages.mjs.map +0 -1
  58. package/build/inputs/SelectInput/SelectInput.mjs +0 -210
  59. package/build/inputs/SelectInput/SelectInput.mjs.map +0 -1
  60. package/build/inputs/SelectInput/components/SelectInputClearButton/SelectInputClearButton.js +0 -26
  61. package/build/inputs/SelectInput/components/SelectInputClearButton/SelectInputClearButton.js.map +0 -1
  62. package/build/inputs/SelectInput/components/SelectInputClearButton/SelectInputClearButton.mjs +0 -24
  63. package/build/inputs/SelectInput/components/SelectInputClearButton/SelectInputClearButton.mjs.map +0 -1
  64. package/build/inputs/SelectInput/components/SelectInputDefaultTrigger/SelectInputDefaultTrigger.js +0 -54
  65. package/build/inputs/SelectInput/components/SelectInputDefaultTrigger/SelectInputDefaultTrigger.js.map +0 -1
  66. package/build/inputs/SelectInput/components/SelectInputDefaultTrigger/SelectInputDefaultTrigger.mjs +0 -52
  67. package/build/inputs/SelectInput/components/SelectInputDefaultTrigger/SelectInputDefaultTrigger.mjs.map +0 -1
  68. package/build/inputs/SelectInput/components/SelectInputGroupItemView/SelectInputGroupItemView.js +0 -50
  69. package/build/inputs/SelectInput/components/SelectInputGroupItemView/SelectInputGroupItemView.js.map +0 -1
  70. package/build/inputs/SelectInput/components/SelectInputGroupItemView/SelectInputGroupItemView.mjs +0 -48
  71. package/build/inputs/SelectInput/components/SelectInputGroupItemView/SelectInputGroupItemView.mjs.map +0 -1
  72. package/build/inputs/SelectInput/components/SelectInputItemView/SelectInputItemView.js +0 -47
  73. package/build/inputs/SelectInput/components/SelectInputItemView/SelectInputItemView.js.map +0 -1
  74. package/build/inputs/SelectInput/components/SelectInputItemView/SelectInputItemView.mjs +0 -45
  75. package/build/inputs/SelectInput/components/SelectInputItemView/SelectInputItemView.mjs.map +0 -1
  76. package/build/inputs/SelectInput/components/SelectInputOption/SelectInputOption.js +0 -45
  77. package/build/inputs/SelectInput/components/SelectInputOption/SelectInputOption.js.map +0 -1
  78. package/build/inputs/SelectInput/components/SelectInputOption/SelectInputOption.mjs +0 -41
  79. package/build/inputs/SelectInput/components/SelectInputOption/SelectInputOption.mjs.map +0 -1
  80. package/build/inputs/SelectInput/components/SelectInputOptionContent/SelectInputOptionContent.js +0 -41
  81. package/build/inputs/SelectInput/components/SelectInputOptionContent/SelectInputOptionContent.js.map +0 -1
  82. package/build/inputs/SelectInput/components/SelectInputOptionContent/SelectInputOptionContent.mjs +0 -38
  83. package/build/inputs/SelectInput/components/SelectInputOptionContent/SelectInputOptionContent.mjs.map +0 -1
  84. package/build/inputs/SelectInput/components/SelectInputOptions/SelectInputOptions.js +0 -270
  85. package/build/inputs/SelectInput/components/SelectInputOptions/SelectInputOptions.js.map +0 -1
  86. package/build/inputs/SelectInput/components/SelectInputOptions/SelectInputOptions.mjs +0 -268
  87. package/build/inputs/SelectInput/components/SelectInputOptions/SelectInputOptions.mjs.map +0 -1
  88. package/build/inputs/SelectInput/components/SelectInputOptionsContainer/SelectInputOptionsContainer.js +0 -48
  89. package/build/inputs/SelectInput/components/SelectInputOptionsContainer/SelectInputOptionsContainer.js.map +0 -1
  90. package/build/inputs/SelectInput/components/SelectInputOptionsContainer/SelectInputOptionsContainer.mjs +0 -46
  91. package/build/inputs/SelectInput/components/SelectInputOptionsContainer/SelectInputOptionsContainer.mjs.map +0 -1
  92. package/build/inputs/SelectInput/components/SelectInputTriggerButton/SelectInputTriggerButton.js +0 -41
  93. package/build/inputs/SelectInput/components/SelectInputTriggerButton/SelectInputTriggerButton.js.map +0 -1
  94. package/build/inputs/SelectInput/components/SelectInputTriggerButton/SelectInputTriggerButton.mjs +0 -34
  95. package/build/inputs/SelectInput/components/SelectInputTriggerButton/SelectInputTriggerButton.mjs.map +0 -1
  96. package/build/styles/inputs/SelectInput/components/SelectInputDefaultTrigger/SelectInputDefaultTrigger.css +0 -17
  97. package/build/styles/inputs/SelectInput/components/SelectInputItemView/SelectInputItemView.css +0 -16
  98. package/build/styles/inputs/SelectInput/components/SelectInputOption/SelectInputOption.css +0 -33
  99. package/build/styles/inputs/SelectInput/components/SelectInputOptionContent/SelectInputOptionContent.css +0 -37
  100. package/build/types/inputs/SelectInput/SelectInput.d.ts +0 -3
  101. package/build/types/inputs/SelectInput/SelectInput.d.ts.map +0 -1
  102. package/build/types/inputs/SelectInput/SelectInput.helpers.d.ts +0 -28
  103. package/build/types/inputs/SelectInput/SelectInput.helpers.d.ts.map +0 -1
  104. package/build/types/inputs/SelectInput/SelectInput.messages.d.ts.map +0 -1
  105. package/build/types/inputs/SelectInput/SelectInput.types.d.ts.map +0 -1
  106. package/build/types/inputs/SelectInput/components/SelectInputClearButton/SelectInputClearButton.d.ts +0 -5
  107. package/build/types/inputs/SelectInput/components/SelectInputClearButton/SelectInputClearButton.d.ts.map +0 -1
  108. package/build/types/inputs/SelectInput/components/SelectInputClearButton/index.d.ts +0 -2
  109. package/build/types/inputs/SelectInput/components/SelectInputClearButton/index.d.ts.map +0 -1
  110. package/build/types/inputs/SelectInput/components/SelectInputDefaultTrigger/SelectInputDefaultTrigger.d.ts +0 -9
  111. package/build/types/inputs/SelectInput/components/SelectInputDefaultTrigger/SelectInputDefaultTrigger.d.ts.map +0 -1
  112. package/build/types/inputs/SelectInput/components/SelectInputDefaultTrigger/index.d.ts +0 -2
  113. package/build/types/inputs/SelectInput/components/SelectInputDefaultTrigger/index.d.ts.map +0 -1
  114. package/build/types/inputs/SelectInput/components/SelectInputGroupItemView/SelectInputGroupItemView.d.ts +0 -9
  115. package/build/types/inputs/SelectInput/components/SelectInputGroupItemView/SelectInputGroupItemView.d.ts.map +0 -1
  116. package/build/types/inputs/SelectInput/components/SelectInputGroupItemView/index.d.ts +0 -2
  117. package/build/types/inputs/SelectInput/components/SelectInputGroupItemView/index.d.ts.map +0 -1
  118. package/build/types/inputs/SelectInput/components/SelectInputItemView/SelectInputItemView.d.ts +0 -8
  119. package/build/types/inputs/SelectInput/components/SelectInputItemView/SelectInputItemView.d.ts.map +0 -1
  120. package/build/types/inputs/SelectInput/components/SelectInputItemView/index.d.ts +0 -2
  121. package/build/types/inputs/SelectInput/components/SelectInputItemView/index.d.ts.map +0 -1
  122. package/build/types/inputs/SelectInput/components/SelectInputOption/SelectInputOption.d.ts +0 -10
  123. package/build/types/inputs/SelectInput/components/SelectInputOption/SelectInputOption.d.ts.map +0 -1
  124. package/build/types/inputs/SelectInput/components/SelectInputOption/index.d.ts +0 -2
  125. package/build/types/inputs/SelectInput/components/SelectInputOption/index.d.ts.map +0 -1
  126. package/build/types/inputs/SelectInput/components/SelectInputOptionContent/SelectInputOptionContent.d.ts +0 -9
  127. package/build/types/inputs/SelectInput/components/SelectInputOptionContent/SelectInputOptionContent.d.ts.map +0 -1
  128. package/build/types/inputs/SelectInput/components/SelectInputOptionContent/index.d.ts +0 -3
  129. package/build/types/inputs/SelectInput/components/SelectInputOptionContent/index.d.ts.map +0 -1
  130. package/build/types/inputs/SelectInput/components/SelectInputOptions/SelectInputOptions.d.ts +0 -15
  131. package/build/types/inputs/SelectInput/components/SelectInputOptions/SelectInputOptions.d.ts.map +0 -1
  132. package/build/types/inputs/SelectInput/components/SelectInputOptions/index.d.ts +0 -2
  133. package/build/types/inputs/SelectInput/components/SelectInputOptions/index.d.ts.map +0 -1
  134. package/build/types/inputs/SelectInput/components/SelectInputOptionsContainer/SelectInputOptionsContainer.d.ts +0 -6
  135. package/build/types/inputs/SelectInput/components/SelectInputOptionsContainer/SelectInputOptionsContainer.d.ts.map +0 -1
  136. package/build/types/inputs/SelectInput/components/SelectInputOptionsContainer/index.d.ts +0 -2
  137. package/build/types/inputs/SelectInput/components/SelectInputOptionsContainer/index.d.ts.map +0 -1
  138. package/build/types/inputs/SelectInput/components/SelectInputTriggerButton/SelectInputTriggerButton.d.ts +0 -15
  139. package/build/types/inputs/SelectInput/components/SelectInputTriggerButton/SelectInputTriggerButton.d.ts.map +0 -1
  140. package/build/types/inputs/SelectInput/components/SelectInputTriggerButton/index.d.ts +0 -3
  141. package/build/types/inputs/SelectInput/components/SelectInputTriggerButton/index.d.ts.map +0 -1
  142. package/build/types/inputs/SelectInput/index.d.ts +0 -5
  143. package/build/types/inputs/SelectInput/index.d.ts.map +0 -1
  144. package/src/inputs/SelectInput/SelectInput.helpers.ts +0 -152
  145. package/src/inputs/SelectInput/SelectInput.less +0 -42
  146. package/src/inputs/SelectInput/SelectInput.test.tsx +0 -606
  147. package/src/inputs/SelectInput/SelectInput.tsx +0 -247
  148. package/src/inputs/SelectInput/SelectInput.types.ts +0 -114
  149. package/src/inputs/SelectInput/components/SelectInputClearButton/SelectInputClearButton.tsx +0 -25
  150. package/src/inputs/SelectInput/components/SelectInputClearButton/index.ts +0 -1
  151. package/src/inputs/SelectInput/components/SelectInputDefaultTrigger/SelectInputDefaultTrigger.css +0 -17
  152. package/src/inputs/SelectInput/components/SelectInputDefaultTrigger/SelectInputDefaultTrigger.less +0 -15
  153. package/src/inputs/SelectInput/components/SelectInputDefaultTrigger/SelectInputDefaultTrigger.tsx +0 -56
  154. package/src/inputs/SelectInput/components/SelectInputDefaultTrigger/index.ts +0 -1
  155. package/src/inputs/SelectInput/components/SelectInputGroupItemView/SelectInputGroupItemView.tsx +0 -64
  156. package/src/inputs/SelectInput/components/SelectInputGroupItemView/index.ts +0 -1
  157. package/src/inputs/SelectInput/components/SelectInputItemView/SelectInputItemView.css +0 -16
  158. package/src/inputs/SelectInput/components/SelectInputItemView/SelectInputItemView.less +0 -17
  159. package/src/inputs/SelectInput/components/SelectInputItemView/SelectInputItemView.tsx +0 -55
  160. package/src/inputs/SelectInput/components/SelectInputItemView/index.ts +0 -1
  161. package/src/inputs/SelectInput/components/SelectInputOption/SelectInputOption.css +0 -33
  162. package/src/inputs/SelectInput/components/SelectInputOption/SelectInputOption.less +0 -32
  163. package/src/inputs/SelectInput/components/SelectInputOption/SelectInputOption.tsx +0 -51
  164. package/src/inputs/SelectInput/components/SelectInputOption/index.ts +0 -5
  165. package/src/inputs/SelectInput/components/SelectInputOptionContent/SelectInputOptionContent.css +0 -37
  166. package/src/inputs/SelectInput/components/SelectInputOptionContent/SelectInputOptionContent.less +0 -38
  167. package/src/inputs/SelectInput/components/SelectInputOptionContent/SelectInputOptionContent.tsx +0 -67
  168. package/src/inputs/SelectInput/components/SelectInputOptionContent/index.ts +0 -5
  169. package/src/inputs/SelectInput/components/SelectInputOptions/SelectInputOptions.less +0 -75
  170. package/src/inputs/SelectInput/components/SelectInputOptions/SelectInputOptions.tsx +0 -369
  171. package/src/inputs/SelectInput/components/SelectInputOptions/index.ts +0 -1
  172. package/src/inputs/SelectInput/components/SelectInputOptionsContainer/SelectInputOptionsContainer.tsx +0 -56
  173. package/src/inputs/SelectInput/components/SelectInputOptionsContainer/index.ts +0 -1
  174. package/src/inputs/SelectInput/components/SelectInputTriggerButton/SelectInputTriggerButton.tsx +0 -39
  175. package/src/inputs/SelectInput/components/SelectInputTriggerButton/index.ts +0 -5
  176. package/src/inputs/SelectInput/index.ts +0 -13
  177. package/build/inputs/{SelectInput/SelectInput.messages.js → SelectInput.messages.js} +0 -0
  178. package/build/inputs/{SelectInput/SelectInput.messages.mjs → SelectInput.messages.mjs} +0 -0
  179. package/{src/inputs/SelectInput → build/styles/inputs}/SelectInput.css +47 -47
  180. package/build/types/inputs/{SelectInput/SelectInput.messages.d.ts → SelectInput.messages.d.ts} +0 -0
  181. package/{build/styles/inputs/SelectInput → src/inputs}/SelectInput.css +47 -47
  182. /package/src/inputs/{SelectInput/SelectInput.messages.ts → SelectInput.messages.ts} +0 -0
@@ -1,247 +0,0 @@
1
- import { Listbox as ListboxBase } from '@headlessui/react';
2
- import mergeProps from 'merge-props';
3
- import { useDeferredValue, useEffect, useRef, useState } from 'react';
4
-
5
- import { useEffectEvent } from '../../common/hooks/useEffectEvent';
6
- import { useScreenSize } from '../../common/hooks/useScreenSize';
7
- import { Breakpoint } from '../../common/propsValues/breakpoint';
8
-
9
- import { BottomSheet } from '../_BottomSheet';
10
- import { Popover } from '../_Popover';
11
- import { useInputAttributes } from '../contexts';
12
- import { searchableString } from './SelectInput.helpers';
13
- import { SelectInputProps } from './SelectInput.types';
14
- import { SelectInputTriggerButtonPropsContext } from './components/SelectInputTriggerButton';
15
- import { SelectInputOptions } from './components/SelectInputOptions';
16
- import { SelectInputOptionContentWithinTriggerContext } from './components/SelectInputOptionContent';
17
- import { SelectInputDefaultTrigger } from './components/SelectInputDefaultTrigger';
18
-
19
- const noop = () => {};
20
-
21
- export function SelectInput<T = string, M extends boolean = false>({
22
- id: idProp,
23
- parentId,
24
- name,
25
- multiple,
26
- placeholder,
27
- autocomplete,
28
- items,
29
- defaultValue,
30
- value: controlledValue,
31
- compareValues,
32
- renderValue = String,
33
- renderFooter,
34
- renderTrigger = SelectInputDefaultTrigger,
35
- filterable,
36
- filterPlaceholder,
37
- sortFilteredOptions,
38
- disabled,
39
- size = 'md',
40
- className,
41
- UNSAFE_triggerButtonProps,
42
- triggerRef: externalTriggerRef,
43
- onFilterChange = noop,
44
- onChange,
45
- onOpen,
46
- onClose,
47
- onClear,
48
- }: SelectInputProps<T, M>) {
49
- const inputAttributes = useInputAttributes({ nonLabelable: true });
50
- const id = idProp ?? inputAttributes.id;
51
-
52
- const [open, setOpen] = useState(false);
53
- const initialized = useRef(false);
54
- const handleClose = useEffectEvent(onClose ?? (() => {}));
55
- const handleOpen = useEffectEvent(onOpen ?? (() => {}));
56
-
57
- useEffect(() => {
58
- if (initialized.current) {
59
- if (open) {
60
- handleOpen?.();
61
- } else {
62
- handleClose?.();
63
- }
64
- } else {
65
- initialized.current = true;
66
- }
67
- }, [handleClose, handleOpen, open]);
68
-
69
- const [filterQuery, _setFilterQuery] = useState('');
70
- const deferredFilterQuery = useDeferredValue(filterQuery);
71
- const setFilterQuery = useEffectEvent((query: string) => {
72
- _setFilterQuery(query);
73
- if (query !== filterQuery) {
74
- onFilterChange({
75
- query,
76
- queryNormalized: query ? searchableString(query) : null,
77
- });
78
- }
79
- });
80
-
81
- const internalTriggerRef = useRef<HTMLButtonElement | null>(null);
82
-
83
- const screenSm = useScreenSize(Breakpoint.SMALL);
84
- const OptionsOverlay = screenSm ? Popover : BottomSheet;
85
-
86
- const searchInputRef = useRef<HTMLInputElement>(null);
87
- const listboxRef = useRef<HTMLDivElement>(null);
88
- const controllerRef = filterable ? searchInputRef : listboxRef;
89
-
90
- /**
91
- * Attempts to resolve the `listbox` label
92
- * @see https://storybook.wise.design/?path=/docs/forms-selectinput-accessibility--docs#labelling
93
- */
94
- const getListBoxLabelProps = (): {
95
- listBoxLabel?: string;
96
- listBoxLabelledBy?: string;
97
- } => {
98
- if (UNSAFE_triggerButtonProps?.['aria-label']) {
99
- return {
100
- listBoxLabel: UNSAFE_triggerButtonProps['aria-label'],
101
- };
102
- }
103
-
104
- if (UNSAFE_triggerButtonProps?.['aria-labelledby']) {
105
- return {
106
- listBoxLabelledBy: UNSAFE_triggerButtonProps['aria-labelledby'],
107
- };
108
- }
109
-
110
- if (inputAttributes['aria-labelledby']) {
111
- return {
112
- listBoxLabelledBy: inputAttributes['aria-labelledby'],
113
- };
114
- }
115
-
116
- return {};
117
- };
118
-
119
- return (
120
- <ListboxBase
121
- name={name}
122
- multiple={multiple}
123
- defaultValue={defaultValue as M extends true ? T[] : T}
124
- value={controlledValue as M extends true ? T[] : T}
125
- by={compareValues}
126
- disabled={disabled}
127
- onChange={
128
- ((value) => {
129
- if (!multiple) {
130
- setOpen(false);
131
- }
132
- onChange?.(value);
133
- }) satisfies SelectInputProps<T, M>['onChange']
134
- }
135
- >
136
- {({ disabled: uiDisabled, value }) => {
137
- const placeholderShown =
138
- multiple && Array.isArray(value) ? value.length === 0 : value == null;
139
- return (
140
- <OptionsOverlay
141
- placement="bottom-start"
142
- open={open}
143
- renderTrigger={({ ref, getInteractionProps }) => (
144
- <SelectInputTriggerButtonPropsContext.Provider
145
- // eslint-disable-next-line react/jsx-no-constructed-context-values
146
- value={{
147
- ref: (node) => {
148
- ref(node);
149
- if (externalTriggerRef) {
150
- // eslint-disable-next-line no-param-reassign
151
- externalTriggerRef.current = node;
152
- } else {
153
- internalTriggerRef.current = node;
154
- }
155
- },
156
- ...inputAttributes,
157
- ...UNSAFE_triggerButtonProps,
158
- id,
159
- ...mergeProps(
160
- {
161
- onClick: () => {
162
- setOpen((prev) => !prev);
163
- },
164
- onKeyDown: (event: React.KeyboardEvent) => {
165
- if (
166
- event.key === ' ' ||
167
- event.key === 'Enter' ||
168
- event.key === 'ArrowDown' ||
169
- event.key === 'ArrowUp'
170
- ) {
171
- setOpen((prev) => !prev);
172
- }
173
- },
174
- },
175
- getInteractionProps(),
176
- ),
177
- }}
178
- >
179
- {renderTrigger({
180
- content: !placeholderShown ? (
181
- <SelectInputOptionContentWithinTriggerContext.Provider value>
182
- {multiple && Array.isArray(value)
183
- ? (value as readonly NonNullable<T>[])
184
- .map((option) => renderValue(option, true))
185
- .filter((node) => node != null)
186
- .join(', ')
187
- : renderValue(value as NonNullable<T>, true)}
188
- </SelectInputOptionContentWithinTriggerContext.Provider>
189
- ) : (
190
- placeholder
191
- ),
192
- placeholderShown,
193
- clear:
194
- onClear != null
195
- ? () => {
196
- onClear();
197
- (externalTriggerRef?.current ?? internalTriggerRef.current)?.focus({
198
- preventScroll: true,
199
- });
200
- }
201
- : undefined,
202
- disabled: uiDisabled,
203
- size,
204
- className,
205
- })}
206
- </SelectInputTriggerButtonPropsContext.Provider>
207
- )}
208
- initialFocusRef={controllerRef}
209
- size={filterable ? 'lg' : 'md'}
210
- padding="none"
211
- onClose={() => {
212
- setOpen(false);
213
- }}
214
- onCloseEnd={() => {
215
- setFilterQuery('');
216
- }}
217
- >
218
- <SelectInputOptions
219
- id={id ? `${id}Search` : undefined}
220
- parentId={parentId}
221
- items={items}
222
- compareValues={compareValues}
223
- renderValue={renderValue}
224
- renderFooter={renderFooter}
225
- filterable={filterable}
226
- filterPlaceholder={filterPlaceholder}
227
- sortFilteredOptions={sortFilteredOptions}
228
- searchInputRef={searchInputRef}
229
- listboxRef={listboxRef}
230
- filterQuery={deferredFilterQuery}
231
- autocomplete={autocomplete}
232
- name={name}
233
- onFilterChange={setFilterQuery}
234
- onAutocompleteSelect={(matchedValue) => {
235
- onChange?.(matchedValue as M extends true ? T[] : T);
236
- if (!multiple) {
237
- setOpen(false);
238
- }
239
- }}
240
- {...getListBoxLabelProps()}
241
- />
242
- </OptionsOverlay>
243
- );
244
- }}
245
- </ListboxBase>
246
- );
247
- }
@@ -1,114 +0,0 @@
1
- import { ReactNode } from 'react';
2
-
3
- import { Merge } from '../../utils';
4
- import { ButtonProps } from '../../button/Button.types';
5
- import { WithInputAttributesProps } from '../contexts';
6
-
7
- export interface SelectInputOptionItem<T = string> {
8
- type: 'option';
9
- value: T;
10
- filterMatchers?: readonly string[];
11
- disabled?: boolean;
12
- }
13
-
14
- export interface SelectInputGroupItem<T = string> {
15
- type: 'group';
16
- label: ReactNode;
17
- options: readonly SelectInputOptionItem<T>[];
18
- action?: {
19
- label: string;
20
- onClick: ButtonProps['onClick'];
21
- };
22
- }
23
-
24
- export interface SelectInputSeparatorItem {
25
- type: 'separator';
26
- }
27
-
28
- export type SelectInputItem<T = string> =
29
- | SelectInputOptionItem<T>
30
- | SelectInputGroupItem<T>
31
- | SelectInputSeparatorItem;
32
-
33
- export interface SelectInputProps<T = string, M extends boolean = false> {
34
- id?: string;
35
- /**
36
- * Sets the `data-wds-parent` attribute on the listbox container, which is needed for complex components like DateInput to correctly manage event handling.
37
- * @internal
38
- */
39
- parentId?: string;
40
- name?: string;
41
- multiple?: M;
42
- placeholder?: string;
43
- items: readonly SelectInputItem<NonNullable<T>>[];
44
- /**
45
- * Enables browser autocomplete integration through the search input.
46
- * Accepts standard HTML autocomplete values (e.g., "country-name", "address-level1").
47
- *
48
- * Requires `filterable={true}` to enable the search input.
49
- *
50
- * @example
51
- * <SelectInput
52
- * name="country"
53
- * autocomplete="country-name"
54
- * filterable={true}
55
- * items={[{
56
- * type: 'option',
57
- * value: 'GB',
58
- * filterMatchers: ['United Kingdom', 'UK']
59
- * }]}
60
- * />
61
- */
62
- autocomplete?: string;
63
- defaultValue?: M extends true ? readonly T[] : T;
64
- value?: M extends true ? readonly T[] : T;
65
- compareValues?:
66
- | (keyof NonNullable<T> & string)
67
- | ((a: T | undefined, b: T | undefined) => boolean);
68
- renderValue?: (value: NonNullable<T>, withinTrigger: boolean) => React.ReactNode;
69
- renderFooter?: (args: {
70
- resultsEmpty: boolean;
71
- queryNormalized: string | null | undefined;
72
- }) => React.ReactNode;
73
- renderTrigger?: (args: {
74
- content: React.ReactNode;
75
- placeholderShown: boolean;
76
- clear: (() => void) | undefined;
77
- disabled: boolean;
78
- size: 'sm' | 'md' | 'lg';
79
- className: string | undefined;
80
- }) => React.ReactNode;
81
- filterable?: boolean;
82
- filterPlaceholder?: string;
83
- sortFilteredOptions?: (
84
- a: SelectInputOptionItem<NonNullable<T>>,
85
- b: SelectInputOptionItem<NonNullable<T>>,
86
- searchQuery: string,
87
- ) => number;
88
- disabled?: boolean;
89
- size?: 'sm' | 'md' | 'lg';
90
- className?: string;
91
- UNSAFE_triggerButtonProps?: WithInputAttributesProps['inputAttributes'] & {
92
- 'aria-label'?: string;
93
- };
94
- /** Ref to the select trigger button element. */
95
- triggerRef?: React.MutableRefObject<HTMLButtonElement | null>;
96
- onFilterChange?: (args: { query: string; queryNormalized: string | null }) => void;
97
- onChange?: (value: M extends true ? T[] : T) => void;
98
- onOpen?: () => void;
99
- onClose?: () => void;
100
- onClear?: () => void;
101
- }
102
-
103
- type SelectInputTriggerButtonElementType = 'button' | React.ComponentType;
104
-
105
- export type SelectInputTriggerButtonProps<
106
- T extends SelectInputTriggerButtonElementType = 'button',
107
- > = Merge<React.ComponentPropsWithoutRef<T>, { as?: T }>;
108
-
109
- export interface SelectInputOptionContentProps {
110
- title: string;
111
- note?: string;
112
- description?: string;
113
- icon?: React.ReactNode;
114
- }
@@ -1,25 +0,0 @@
1
- import { Cross } from '@transferwise/icons';
2
- import { clsx } from 'clsx';
3
- import { useIntl } from 'react-intl';
4
-
5
- import dateTriggerMessages from '../../../../dateLookup/dateTrigger/DateTrigger.messages';
6
-
7
- interface SelectInputClearButtonProps extends Pick<
8
- React.ComponentPropsWithoutRef<'button'>,
9
- 'className' | 'onClick'
10
- > {}
11
-
12
- export function SelectInputClearButton({ className, onClick }: SelectInputClearButtonProps) {
13
- const intl = useIntl();
14
-
15
- return (
16
- <button
17
- type="button"
18
- aria-label={intl.formatMessage(dateTriggerMessages.ariaLabel)}
19
- className={clsx(className, 'np-select-input-addon np-select-input-addon--interactive')}
20
- onClick={onClick}
21
- >
22
- <Cross size={16} />
23
- </button>
24
- );
25
- }
@@ -1 +0,0 @@
1
- export { SelectInputClearButton } from './SelectInputClearButton';
@@ -1,17 +0,0 @@
1
- .np-select-input-addon-container {
2
- pointer-events: none;
3
- margin-inline-start: 4px;
4
- margin-inline-start: var(--size-4);
5
- display: inline-flex;
6
- align-items: center;
7
- }
8
- .np-select-input-addon-container > :not([hidden]) ~ :not([hidden]) {
9
- margin-inline-start: 4px;
10
- margin-inline-start: var(--size-4);
11
- }
12
- .np-select-input-addon-separator {
13
- height: 24px;
14
- height: var(--size-24);
15
- border-inline-start: 1px solid rgba(0,0,0,0.10196);
16
- border-inline-start: 1px solid var(--color-border-neutral);
17
- }
@@ -1,15 +0,0 @@
1
- .np-select-input-addon-container {
2
- pointer-events: none;
3
- margin-inline-start: var(--size-4);
4
- display: inline-flex;
5
- align-items: center;
6
-
7
- & > :not([hidden]) ~ :not([hidden]) {
8
- margin-inline-start: var(--size-4);
9
- }
10
- }
11
-
12
- .np-select-input-addon-separator {
13
- height: var(--size-24);
14
- border-inline-start: 1px solid var(--color-border-neutral);
15
- }
@@ -1,56 +0,0 @@
1
- import { ChevronDown } from '@transferwise/icons';
2
- import { clsx } from 'clsx';
3
-
4
- import { ButtonInput } from '../../../_ButtonInput';
5
- import { InputGroup } from '../../../InputGroup';
6
- import { SelectInputClearButton } from '../SelectInputClearButton';
7
- import { SelectInputTriggerButton } from '../SelectInputTriggerButton';
8
- import type { SelectInputProps } from '../../SelectInput.types';
9
-
10
- export const SelectInputDefaultTrigger = (({
11
- content,
12
- placeholderShown,
13
- clear,
14
- disabled,
15
- size,
16
- className,
17
- }) => (
18
- <InputGroup
19
- addonEnd={{
20
- content: (
21
- <span className={clsx('np-select-input-addon-container', disabled && 'disabled')}>
22
- {clear != null && !placeholderShown ? (
23
- <>
24
- <SelectInputClearButton
25
- onClick={(event) => {
26
- event.preventDefault();
27
- clear();
28
- }}
29
- />
30
- <span className="np-select-input-addon-separator" />
31
- </>
32
- ) : null}
33
-
34
- <span className="np-select-input-addon">
35
- <ChevronDown size={16} />
36
- </span>
37
- </span>
38
- ),
39
- initialContentWidth: 24 + 4,
40
- padding: 'sm',
41
- }}
42
- disabled={disabled}
43
- className={className}
44
- >
45
- <SelectInputTriggerButton as={ButtonInput} size={size}>
46
- <span
47
- className={clsx(
48
- 'np-select-input-content',
49
- placeholderShown && 'np-select-input-placeholder',
50
- )}
51
- >
52
- {content}
53
- </span>
54
- </SelectInputTriggerButton>
55
- </InputGroup>
56
- )) satisfies SelectInputProps['renderTrigger'];
@@ -1 +0,0 @@
1
- export { SelectInputDefaultTrigger } from './SelectInputDefaultTrigger';
@@ -1,64 +0,0 @@
1
- import { clsx } from 'clsx';
2
- import { useId } from 'react';
3
-
4
- import Header from '../../../../header';
5
- import Section from '../../../../section';
6
- import type {
7
- SelectInputGroupItem,
8
- SelectInputProps,
9
- } from '../../SelectInput.types';
10
-
11
- import { SelectInputItemView } from '../SelectInputItemView';
12
-
13
- interface SelectInputGroupItemViewProps<T = string> {
14
- item: SelectInputGroupItem<T | undefined>;
15
- renderValue: Required<Pick<SelectInputProps<T>, 'renderValue'>>['renderValue'];
16
- needle: string | null | undefined;
17
- }
18
-
19
- export function SelectInputGroupItemView<T = string>({
20
- item,
21
- renderValue,
22
- needle,
23
- }: SelectInputGroupItemViewProps<T>) {
24
- const headerId = useId();
25
-
26
- const header = (
27
- <Header
28
- as="header"
29
- role="none"
30
- id={headerId}
31
- title={item.label}
32
- // @ts-expect-error when we migrate ActionButton to new Button this should be sorted
33
- action={
34
- item.action && {
35
- text: item.action.label,
36
- onClick: item.action.onClick,
37
- }
38
- }
39
- className="np-select-input-group-item-header p-x-1"
40
- />
41
- );
42
-
43
- return (
44
- // An empty container may be rendered when no options match `needle`
45
- // However, pre-filtering would result in worse performance overall
46
- <Section
47
- as="section"
48
- role="group"
49
- aria-labelledby={headerId}
50
- className={clsx('m-y-0', needle === null && 'np-select-input-group-item--without-needle')}
51
- >
52
- {needle == null ? header : null}
53
- {item.options.map((option, index) => (
54
- <SelectInputItemView
55
- // eslint-disable-next-line react/no-array-index-key
56
- key={index}
57
- item={option}
58
- renderValue={renderValue}
59
- needle={needle}
60
- />
61
- ))}
62
- </Section>
63
- );
64
- }
@@ -1 +0,0 @@
1
- export { SelectInputGroupItemView } from './SelectInputGroupItemView';
@@ -1,16 +0,0 @@
1
- .np-select-input-separator-item {
2
- margin: 8px;
3
- margin: var(--size-8);
4
- border-top-width: 1px;
5
- }
6
- .np-select-input-group-item--without-needle:first-child {
7
- margin-top: calc(-1 * 8px);
8
- margin-top: calc(-1 * var(--size-8));
9
- }
10
- .np-select-input-group-item-header {
11
- position: sticky;
12
- top: 0px;
13
- z-index: 10;
14
- background-color: #ffffff;
15
- background-color: var(--color-background-elevated);
16
- }
@@ -1,17 +0,0 @@
1
- .np-select-input-separator-item {
2
- margin: var(--size-8);
3
- border-top-width: 1px;
4
- }
5
-
6
- .np-select-input-group-item {
7
- &--without-needle:first-child {
8
- margin-top: calc(-1 * var(--size-8));
9
- }
10
-
11
- &-header {
12
- position: sticky;
13
- top: 0px;
14
- z-index: 10;
15
- background-color: var(--color-background-elevated);
16
- }
17
- }
@@ -1,55 +0,0 @@
1
- import { clsx } from 'clsx';
2
- import { useId } from 'react';
3
-
4
- import Header from '../../../../header';
5
- import Section from '../../../../section';
6
- import { selectInputOptionItemIncludesNeedle } from '../../SelectInput.helpers';
7
- import type {
8
- SelectInputGroupItem,
9
- SelectInputProps,
10
- SelectInputItem,
11
- } from '../../SelectInput.types';
12
- import { SelectInputOption } from '../SelectInputOption';
13
-
14
- import { SelectInputGroupItemView } from '../SelectInputGroupItemView';
15
-
16
- interface SelectInputItemViewProps<
17
- T = string,
18
- I extends SelectInputItem<T | undefined> = SelectInputItem<T | undefined>,
19
- > extends Required<Pick<SelectInputProps<T>, 'renderValue'>> {
20
- item: I;
21
- needle: string | null | undefined;
22
- }
23
-
24
- export function SelectInputItemView<T = string>({
25
- item,
26
- renderValue,
27
- needle,
28
- }: SelectInputItemViewProps<T>) {
29
- switch (item.type) {
30
- case 'option': {
31
- if (
32
- item.value != null &&
33
- (needle == null || selectInputOptionItemIncludesNeedle(item, needle))
34
- ) {
35
- return (
36
- <SelectInputOption value={item.value} disabled={item.disabled}>
37
- {renderValue(item.value, false)}
38
- </SelectInputOption>
39
- );
40
- }
41
- break;
42
- }
43
- case 'group': {
44
- return <SelectInputGroupItemView item={item} renderValue={renderValue} needle={needle} />;
45
- }
46
- case 'separator': {
47
- if (needle == null) {
48
- return <hr className="np-select-input-separator-item" />;
49
- }
50
- break;
51
- }
52
- }
53
- return null;
54
- }
55
-
@@ -1 +0,0 @@
1
- export { SelectInputItemView } from './SelectInputItemView';
@@ -1,33 +0,0 @@
1
- .np-select-input-option-container {
2
- display: flex;
3
- cursor: default;
4
- -webkit-user-select: none;
5
- -moz-user-select: none;
6
- user-select: none;
7
- align-items: center;
8
- -moz-column-gap: 8px;
9
- column-gap: 8px;
10
- -moz-column-gap: var(--size-8);
11
- column-gap: var(--size-8);
12
- border-radius: 10px;
13
- border-radius: var(--radius-small);
14
- padding: 12px 16px;
15
- padding: var(--size-12) var(--size-16);
16
- color: var(--color-interactive-primary);
17
- }
18
- .np-select-input-option-container:focus {
19
- outline: none;
20
- }
21
- .np-select-input-option-container--active {
22
- box-shadow: inset 0 0 0 1px #c9cbce;
23
- box-shadow: inset 0 0 0 1px var(--color-interactive-secondary);
24
- }
25
- .np-select-input-option-container--disabled {
26
- opacity: 0.45;
27
- }
28
- .np-select-input-option {
29
- flex: 1;
30
- }
31
- .np-select-input-option-check--not-selected {
32
- visibility: hidden;
33
- }