uikit-react-public 0.14.21 → 0.17.4

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 (158) hide show
  1. package/README.md +4 -2
  2. package/dist/components/Accordion/Accordion.Heading.d.ts +4 -4
  3. package/dist/components/Accordion/Accordion.Panel.d.ts +2 -2
  4. package/dist/components/Accordion/Accordion.d.ts +1 -1
  5. package/dist/components/Accordion/Accordion.stories.d.ts +57 -0
  6. package/dist/components/Accordion/index.d.ts +2 -0
  7. package/dist/components/Avatar/Avatar.stories.d.ts +107 -1
  8. package/dist/components/Button/Button.d.ts +1 -0
  9. package/dist/components/Calendar/index.d.ts +1 -1
  10. package/dist/components/Datepicker/Datepicker.d.ts +1 -1
  11. package/dist/components/Datepicker/Datepicker.stories.d.ts +4 -3
  12. package/dist/components/Datepicker/Datepicker.types.d.ts +4 -5
  13. package/dist/components/Datepicker/subcomponents/CustomDatepicker.d.ts +4 -1
  14. package/dist/components/Datepicker/subcomponents/DatepickerInput.d.ts +15 -2
  15. package/dist/components/Datepicker/subcomponents/Panel.d.ts +1 -1
  16. package/dist/components/Datepicker/subcomponents/VisibleField.d.ts +6 -1
  17. package/dist/components/Datepicker/subcomponents/index.d.ts +0 -1
  18. package/dist/components/Datepicker/utils/index.d.ts +0 -1
  19. package/dist/components/Dialog/BaseDialog.d.ts +2 -1
  20. package/dist/components/Dialog/Dialog.d.ts +2 -0
  21. package/dist/components/Header/Header.d.ts +4 -1
  22. package/dist/components/Header/Header.stories.d.ts +40 -0
  23. package/dist/components/Main/Main.d.ts +21 -0
  24. package/dist/components/Main/Main.stories.d.ts +15 -0
  25. package/dist/components/Main/index.d.ts +2 -0
  26. package/dist/components/NativeDatepicker/NativeDatepicker.d.ts +3 -0
  27. package/dist/components/NativeDatepicker/NativeDatepicker.stories.d.ts +36 -0
  28. package/dist/components/NativeDatepicker/NativeDatepicker.types.d.ts +10 -0
  29. package/dist/components/NativeDatepicker/index.d.ts +2 -0
  30. package/dist/components/{Datepicker → NativeDatepicker}/utils/dateToLocaleISOString/dateToLocaleISOString.d.ts +1 -1
  31. package/dist/components/NativeDatepicker/utils/dateToLocaleISOString/dateToLocaleISOString.test.d.ts +1 -0
  32. package/dist/components/NativeDatepicker/utils/index.d.ts +1 -0
  33. package/dist/components/Select/Select.stories.d.ts +154 -2
  34. package/dist/components/Select/Select.types.d.ts +51 -22
  35. package/dist/components/Select/subcomponents/CustomOption.d.ts +1 -1
  36. package/dist/components/Select/subcomponents/CustomSelect.d.ts +3 -2
  37. package/dist/components/Select/subcomponents/FilterInput.d.ts +14 -0
  38. package/dist/components/Select/subcomponents/NativeSelect.d.ts +5 -1
  39. package/dist/components/Select/subcomponents/VisibleField.d.ts +3 -1
  40. package/dist/components/Select/subcomponents/index.d.ts +1 -0
  41. package/dist/components/WeekPicker/WeekPicker.d.ts +2 -2
  42. package/dist/components/WeekPicker/WeekPicker.stories.d.ts +41 -0
  43. package/dist/components/WeekPicker/WeekPicker.types.d.ts +16 -0
  44. package/dist/components/WeekPicker/index.d.ts +1 -0
  45. package/dist/components/WeekPicker/subcomponents/CustomDatepicker.d.ts +1 -1
  46. package/dist/components/index.d.ts +8 -0
  47. package/dist/hooks/useFocusTrap.d.ts +2 -1
  48. package/dist/index.d.ts +1 -0
  49. package/dist/index.js +4366 -3768
  50. package/dist/utils/__tests__/announce.test.d.ts +1 -0
  51. package/dist/utils/announce.d.ts +6 -0
  52. package/dist/utils/index.d.ts +1 -0
  53. package/lib/components/Accordion/Accordion.Heading.tsx +27 -8
  54. package/lib/components/Accordion/Accordion.Panel.tsx +11 -3
  55. package/lib/components/Accordion/Accordion.stories.tsx +139 -0
  56. package/lib/components/Accordion/Accordion.tsx +10 -8
  57. package/lib/components/Accordion/__tests__/__snapshots__/Accordion.test.tsx.snap +7 -7
  58. package/lib/components/Accordion/index.ts +2 -0
  59. package/lib/components/Alert/Alert.stories.tsx +1 -1
  60. package/lib/components/Avatar/Avatar.mdx +117 -0
  61. package/lib/components/Avatar/Avatar.stories.tsx +110 -2
  62. package/lib/components/Blanket/Blanket.stories.tsx +1 -1
  63. package/lib/components/Button/Button.stories.tsx +1 -1
  64. package/lib/components/Button/Button.tsx +1 -0
  65. package/lib/components/Calendar/Calendar.stories.tsx +12 -32
  66. package/lib/components/Calendar/__tests__/Calendar.test.tsx +23 -15
  67. package/lib/components/Calendar/index.ts +1 -5
  68. package/lib/components/Calendar/subcomponents/AcademicWeeks.tsx +2 -1
  69. package/lib/components/Calendar/subcomponents/ColumnHeading.tsx +5 -1
  70. package/lib/components/Calendar/subcomponents/EventDot.tsx +2 -1
  71. package/lib/components/Calendar/subcomponents/index.ts +1 -1
  72. package/lib/components/Calendar/utils/getDatesForCalendarGrid/getDatesForCalendarGrid.ts +43 -11
  73. package/lib/components/Calendar/utils/normaliseMonth/normaliseMonth.test.ts +5 -5
  74. package/lib/components/Datepicker/Datepicker.lld.md +108 -0
  75. package/lib/components/Datepicker/Datepicker.stories.tsx +44 -5
  76. package/lib/components/Datepicker/Datepicker.tsx +14 -36
  77. package/lib/components/Datepicker/Datepicker.types.ts +5 -14
  78. package/lib/components/Datepicker/__tests__/Datepicker.test.tsx +150 -8
  79. package/lib/components/Datepicker/__tests__/__snapshots__/Datepicker.test.tsx.snap +10 -4
  80. package/lib/components/Datepicker/subcomponents/CustomDatepicker.tsx +39 -5
  81. package/lib/components/Datepicker/subcomponents/DatepickerInput.tsx +30 -17
  82. package/lib/components/Datepicker/subcomponents/Panel.tsx +6 -2
  83. package/lib/components/Datepicker/subcomponents/VisibleField.tsx +40 -3
  84. package/lib/components/Datepicker/subcomponents/index.ts +0 -1
  85. package/lib/components/Datepicker/utils/index.ts +0 -1
  86. package/lib/components/Dialog/BaseDialog.tsx +11 -0
  87. package/lib/components/Dialog/Dialog.tsx +8 -1
  88. package/lib/components/Dialog/DialogBody.tsx +5 -1
  89. package/lib/components/Dialog/DialogHeader.tsx +2 -1
  90. package/lib/components/Divider/Divider.stories.tsx +1 -1
  91. package/lib/components/Field/ErrorText.tsx +1 -0
  92. package/lib/components/Field/Field.stories.tsx +1 -1
  93. package/lib/components/Field/__tests__/Field.test.tsx +13 -0
  94. package/lib/components/FileInput/FileInput.stories.tsx +1 -1
  95. package/lib/components/Footer/Footer.stories.tsx +1 -1
  96. package/lib/components/Footer/__tests__/__snapshots__/Footer.test.tsx.snap +3 -3
  97. package/lib/components/Header/Header.mdx +52 -0
  98. package/lib/components/Header/Header.stories.tsx +98 -0
  99. package/lib/components/Header/Header.tsx +51 -6
  100. package/lib/components/Header/__tests__/Header.test.tsx +17 -1
  101. package/lib/components/Heading/Heading.stories.tsx +1 -1
  102. package/lib/components/Icon/Icon.stories.tsx +1 -1
  103. package/lib/components/IconButton/IconButton.stories.tsx +1 -1
  104. package/lib/components/Input/Input.stories.tsx +1 -1
  105. package/lib/components/Label/Label.stories.tsx +1 -1
  106. package/lib/components/Main/Main.stories.tsx +36 -0
  107. package/lib/components/Main/Main.tsx +46 -0
  108. package/lib/components/Main/__tests__/Main.test.tsx +80 -0
  109. package/lib/components/Main/__tests__/__snapshots__/Main.test.tsx.snap +33 -0
  110. package/lib/components/Main/index.ts +2 -0
  111. package/lib/components/NativeDatepicker/NativeDatepicker.stories.tsx +100 -0
  112. package/lib/components/{Datepicker/subcomponents → NativeDatepicker}/NativeDatepicker.tsx +14 -15
  113. package/lib/components/NativeDatepicker/NativeDatepicker.types.ts +19 -0
  114. package/lib/components/NativeDatepicker/index.ts +2 -0
  115. package/lib/components/{Datepicker → NativeDatepicker}/utils/dateToLocaleISOString/dateToLocaleISOString.ts +1 -1
  116. package/lib/components/NativeDatepicker/utils/index.ts +1 -0
  117. package/lib/components/Pagination/PaginationControls.tsx +55 -12
  118. package/lib/components/Pagination/PaginationInfo.tsx +5 -1
  119. package/lib/components/Paragraph/Paragraph.stories.tsx +1 -1
  120. package/lib/components/Search/Search.stories.tsx +1 -1
  121. package/lib/components/Search/Search.tsx +4 -1
  122. package/lib/components/Search/__tests__/Search.test.tsx +19 -1
  123. package/lib/components/Select/Select.mdx +169 -0
  124. package/lib/components/Select/Select.stories.tsx +191 -43
  125. package/lib/components/Select/Select.tsx +36 -12
  126. package/lib/components/Select/Select.types.ts +66 -48
  127. package/lib/components/Select/__tests__/Select.test.tsx +448 -7
  128. package/lib/components/Select/__tests__/__snapshots__/Select.test.tsx.snap +1 -1
  129. package/lib/components/Select/subcomponents/CustomOption.tsx +2 -1
  130. package/lib/components/Select/subcomponents/CustomSelect.tsx +303 -33
  131. package/lib/components/Select/subcomponents/FilterInput.tsx +80 -0
  132. package/lib/components/Select/subcomponents/NativeSelect.tsx +13 -1
  133. package/lib/components/Select/subcomponents/VisibleField.tsx +11 -3
  134. package/lib/components/Select/subcomponents/index.tsx +1 -0
  135. package/lib/components/Snackbar/Snackbar.stories.tsx +1 -1
  136. package/lib/components/Spinner/Spinner.stories.tsx +1 -1
  137. package/lib/components/Textarea/Textarea.stories.tsx +1 -1
  138. package/lib/components/Timepicker/Timepicker.tsx +4 -0
  139. package/lib/components/Timepicker/__tests__/__snapshots__/Timepicker.test.tsx.snap +2 -2
  140. package/lib/components/Toggle/Toggle.stories.tsx +1 -1
  141. package/lib/components/Tooltip/Tooltip.stories.tsx +1 -1
  142. package/lib/components/WeekPicker/WeekPicker.stories.tsx +147 -0
  143. package/lib/components/WeekPicker/WeekPicker.tsx +2 -2
  144. package/lib/components/WeekPicker/WeekPicker.types.ts +21 -0
  145. package/lib/components/WeekPicker/index.ts +1 -0
  146. package/lib/components/WeekPicker/subcomponents/CustomDatepicker.tsx +1 -1
  147. package/lib/components/common/Common.mdx +1 -1
  148. package/lib/components/index.ts +11 -2
  149. package/lib/hooks/useFocusTrap.ts +40 -4
  150. package/lib/index.ts +1 -0
  151. package/lib/utils/__tests__/announce.test.ts +121 -0
  152. package/lib/utils/announce.ts +134 -0
  153. package/lib/utils/index.ts +1 -0
  154. package/package.json +3 -6
  155. package/dist/components/Datepicker/subcomponents/NativeDatepicker.d.ts +0 -6
  156. package/lib/components/Accordion/Accordion.stories.tsx.NOT_READY +0 -93
  157. /package/dist/components/{Datepicker/utils/dateToLocaleISOString/dateToLocaleISOString.test.d.ts → Main/__tests__/Main.test.d.ts} +0 -0
  158. /package/lib/components/{Datepicker → NativeDatepicker}/utils/dateToLocaleISOString/dateToLocaleISOString.test.ts +0 -0
@@ -1,37 +1,128 @@
1
1
  import type { Meta, StoryObj } from '@storybook/react';
2
2
  import { useArgs } from '@storybook/preview-api';
3
3
  import Select from './Select';
4
+ import { css } from '@emotion/css';
5
+
6
+ const select400pxWidthClass = css`
7
+ width: 400px;
8
+ `;
9
+ const storyWrapperStyle: React.CSSProperties = { minHeight: 150, width: 400 };
4
10
 
5
11
  const meta = {
6
- title: 'Components/Ready to use/Select',
12
+ title: 'Components/Select',
7
13
  component: Select,
8
14
  argTypes: {
9
- value: { control: { type: 'text' } },
15
+ selectionBehaviour: {
16
+ description:
17
+ 'Keyboard selection behaviour for custom variant: `focus` commits on arrow keys, `commit` commits on Enter/click',
18
+ control: { type: 'radio' },
19
+ options: ['focus', 'commit'],
20
+ table: { type: { summary: "'focus' | 'commit'" } },
21
+ },
22
+ options: {
23
+ description: 'Array of option objects `{ label, value, optionProps? }`',
24
+ control: { type: 'object' },
25
+ table: { type: { summary: 'OptionData[]' } },
26
+ },
27
+ value: {
28
+ description: 'Selected value (string | number)',
29
+ control: { type: 'text' },
30
+ table: { type: { summary: 'string | number' } },
31
+ },
32
+ onValueChange: {
33
+ description:
34
+ 'Change handler for the custom select variant (value, event)',
35
+ control: false,
36
+ table: {
37
+ type: {
38
+ summary: '(value: string | number, ev: React.UIEvent) => void',
39
+ },
40
+ },
41
+ },
10
42
  native: {
43
+ description: 'Render the native `<select>` variant when true',
11
44
  control: { type: 'boolean' },
45
+ table: { type: { summary: 'boolean' } },
46
+ },
47
+ nativeHtmlAttributes: {
48
+ description: 'Additional props to spread onto the native `<select>`',
49
+ control: false,
50
+ table: {
51
+ type: { summary: 'React.SelectHTMLAttributes<HTMLSelectElement>' },
52
+ },
12
53
  },
13
54
  disabled: {
55
+ description: 'Disable interaction',
14
56
  control: { type: 'boolean' },
57
+ table: { type: { summary: 'boolean' } },
15
58
  },
16
59
  placeholder: {
60
+ description: 'Helper text when no value is selected',
17
61
  control: { type: 'text' },
62
+ table: { type: { summary: 'string' } },
18
63
  },
19
- testId: {
64
+ filterable: {
65
+ description:
66
+ 'Show a filter input to narrow options in the custom variant',
67
+ control: { type: 'boolean' },
68
+ table: { type: { summary: 'boolean' } },
69
+ },
70
+ filterInputProps: {
71
+ description:
72
+ 'Additional props to spread onto the filter input (when filterable)',
73
+ control: { type: 'object' },
74
+ table: {
75
+ type: {
76
+ summary: 'React.InputHTMLAttributes<HTMLInputElement>',
77
+ },
78
+ },
79
+ },
80
+ id: {
81
+ description: 'Standard HTML id forwarded to the combobox/native select',
82
+ control: { type: 'text' },
83
+ table: { type: { summary: 'string' } },
84
+ },
85
+ title: {
86
+ description:
87
+ 'Standard title attribute forwarded to the combobox/native select',
20
88
  control: { type: 'text' },
89
+ table: { type: { summary: 'string' } },
21
90
  },
22
91
  lineBreak: {
92
+ description: 'Wrap long option labels',
23
93
  control: { type: 'boolean' },
94
+ table: { type: { summary: 'boolean' } },
95
+ },
96
+ panelClassName: {
97
+ description: 'Custom className for the options panel',
98
+ control: { type: 'text' },
99
+ table: { type: { summary: 'string' } },
100
+ },
101
+ className: {
102
+ description: 'Custom className for the root element',
103
+ control: { type: 'text' },
104
+ table: { type: { summary: 'string' } },
105
+ },
106
+ testId: {
107
+ description: 'Test id applied to the root element',
108
+ control: { type: 'text' },
109
+ table: { type: { summary: 'string' } },
24
110
  },
25
111
  },
26
112
  args: {
113
+ selectionBehaviour: 'focus',
27
114
  value: undefined,
28
- onChange: () => {},
29
115
  options: [
30
116
  { label: 'Option one', value: '1' },
31
117
  { label: 'Option two', value: '2' },
32
118
  { label: 'Option three', value: '3' },
33
119
  ],
34
120
  },
121
+ parameters: {
122
+ docs: {
123
+ story: { inline: true },
124
+ },
125
+ },
35
126
  } satisfies Meta<typeof Select>;
36
127
 
37
128
  export default meta;
@@ -44,12 +135,15 @@ export const Default: Story = {
44
135
  updateArgs({ value });
45
136
  };
46
137
  return (
47
- <Select
48
- {...args}
49
- options={args.options}
50
- value={args.value}
51
- onValueChange={onValueChange}
52
- />
138
+ <div style={storyWrapperStyle}>
139
+ <Select
140
+ {...args}
141
+ className={select400pxWidthClass}
142
+ options={args.options}
143
+ value={args.value}
144
+ onValueChange={onValueChange}
145
+ />
146
+ </div>
53
147
  );
54
148
  },
55
149
  };
@@ -60,16 +154,18 @@ export const Native: Story = {
60
154
  },
61
155
  render: () => {
62
156
  const [args, updateArgs] = useArgs();
63
- const onValueChange = (value: string | number) => {
64
- updateArgs({ value });
65
- };
157
+ const onNativeChange = (event: React.ChangeEvent<HTMLSelectElement>) =>
158
+ updateArgs({ value: event.target.value });
66
159
  return (
67
- <Select
68
- {...args}
69
- options={args.options}
70
- value={args.value}
71
- onValueChange={onValueChange}
72
- />
160
+ <div style={storyWrapperStyle}>
161
+ <Select
162
+ {...args}
163
+ className={select400pxWidthClass}
164
+ options={args.options}
165
+ value={args.value}
166
+ nativeHtmlAttributes={{ onChange: onNativeChange }}
167
+ />
168
+ </div>
73
169
  );
74
170
  },
75
171
  };
@@ -85,12 +181,15 @@ export const Disabled: Story = {
85
181
  };
86
182
 
87
183
  return (
88
- <Select
89
- {...args}
90
- options={args.options}
91
- value={args.value}
92
- onValueChange={onValueChange}
93
- />
184
+ <div style={storyWrapperStyle}>
185
+ <Select
186
+ {...args}
187
+ className={select400pxWidthClass}
188
+ options={args.options}
189
+ value={args.value}
190
+ onValueChange={onValueChange}
191
+ />
192
+ </div>
94
193
  );
95
194
  },
96
195
  };
@@ -104,12 +203,15 @@ export const WithPlaceholder: Story = {
104
203
  };
105
204
 
106
205
  return (
107
- <Select
108
- {...args}
109
- options={args.options}
110
- value={args.value}
111
- onValueChange={onValueChange}
112
- />
206
+ <div style={storyWrapperStyle}>
207
+ <Select
208
+ {...args}
209
+ className={select400pxWidthClass}
210
+ options={args.options}
211
+ value={args.value}
212
+ onValueChange={onValueChange}
213
+ />
214
+ </div>
113
215
  );
114
216
  },
115
217
  };
@@ -130,12 +232,15 @@ export const SingleLongOption: Story = {
130
232
  };
131
233
 
132
234
  return (
133
- <Select
134
- {...args}
135
- options={args.options}
136
- value={args.value}
137
- onValueChange={onValueChange}
138
- />
235
+ <div style={storyWrapperStyle}>
236
+ <Select
237
+ {...args}
238
+ className={select400pxWidthClass}
239
+ options={args.options}
240
+ value={args.value}
241
+ onValueChange={onValueChange}
242
+ />
243
+ </div>
139
244
  );
140
245
  },
141
246
  };
@@ -167,12 +272,55 @@ export const ManyOptions: Story = {
167
272
  updateArgs({ value });
168
273
  };
169
274
  return (
170
- <Select
171
- {...args}
172
- options={args.options}
173
- value={args.value}
174
- onValueChange={onValueChange}
175
- />
275
+ <div style={storyWrapperStyle}>
276
+ <Select
277
+ {...args}
278
+ className={select400pxWidthClass}
279
+ options={args.options}
280
+ value={args.value}
281
+ onValueChange={onValueChange}
282
+ />
283
+ </div>
284
+ );
285
+ },
286
+ };
287
+
288
+ export const filterable: Story = {
289
+ args: { filterable: true },
290
+ render: () => {
291
+ const [args, updateArgs] = useArgs();
292
+ const onValueChange = (value: string | number) => updateArgs({ value });
293
+ return (
294
+ <div style={storyWrapperStyle}>
295
+ <Select
296
+ {...args}
297
+ className={select400pxWidthClass}
298
+ options={args.options}
299
+ value={args.value}
300
+ onValueChange={onValueChange}
301
+ placeholder='Type to filter...'
302
+ />
303
+ </div>
304
+ );
305
+ },
306
+ };
307
+
308
+ export const SelectionBehaviourCommit: Story = {
309
+ name: 'Selection behaviour: commit',
310
+ args: { selectionBehaviour: 'commit' },
311
+ render: () => {
312
+ const [args, updateArgs] = useArgs();
313
+ const onValueChange = (value: string | number) => updateArgs({ value });
314
+ return (
315
+ <div style={storyWrapperStyle}>
316
+ <Select
317
+ {...args}
318
+ className={select400pxWidthClass}
319
+ options={args.options}
320
+ value={args.value}
321
+ onValueChange={onValueChange}
322
+ />
323
+ </div>
176
324
  );
177
325
  },
178
326
  };
@@ -2,24 +2,48 @@ import { NativeSelect, CustomSelect } from './subcomponents';
2
2
  import { SelectProps } from './Select.types';
3
3
 
4
4
  const Select = <T extends string | number = string>(props: SelectProps<T>) => {
5
- if (props.native) {
6
- const { onChange, value, ...rest } = props;
5
+ const {
6
+ native,
7
+ nativeHtmlAttributes,
8
+ filterable,
9
+ onValueChange,
10
+ ref,
11
+ ...rest
12
+ } = props;
13
+
14
+ if (native) {
15
+ if (filterable) {
16
+ console.warn('filterable is not supported on native Select; ignoring.');
17
+ }
18
+ const { value, ...nativeRest } = rest;
19
+ const {
20
+ value: nativeAttrValue,
21
+ onChange,
22
+ ...nativeAttrs
23
+ } = nativeHtmlAttributes || {};
24
+ const nativeValue: string | number | undefined =
25
+ typeof value === 'string' || typeof value === 'number'
26
+ ? value
27
+ : undefined;
7
28
  return (
8
29
  <NativeSelect
30
+ value={nativeValue ?? (nativeAttrValue as string | number | undefined)}
9
31
  onChange={onChange}
10
- value={value || ''}
11
- {...rest}
12
- />
13
- );
14
- } else {
15
- const { onValueChange, ...rest } = props;
16
- return (
17
- <CustomSelect<T>
18
- onValueChange={onValueChange}
19
- {...rest}
32
+ ref={ref as React.Ref<HTMLSelectElement>}
33
+ {...nativeRest}
34
+ {...nativeAttrs}
20
35
  />
21
36
  );
22
37
  }
38
+
39
+ return (
40
+ <CustomSelect<T>
41
+ onValueChange={onValueChange}
42
+ filterable={filterable}
43
+ ref={ref as React.Ref<HTMLDivElement>}
44
+ {...rest}
45
+ />
46
+ );
23
47
  };
24
48
 
25
49
  export default Select;
@@ -24,9 +24,30 @@ export type OptionData<T> = {
24
24
  };
25
25
 
26
26
  /**
27
- * Top level props that <Select> accepts when implemented
27
+ * Additional props forwarded to the filter input when `filterable` is true
28
28
  */
29
- interface BaseSelectProps<T = string> {
29
+ export type FilterInputProps = Omit<
30
+ React.InputHTMLAttributes<HTMLInputElement>,
31
+ | 'value'
32
+ | 'onChange'
33
+ | 'disabled'
34
+ | 'ref'
35
+ | 'role'
36
+ | 'aria-autocomplete'
37
+ | 'aria-label'
38
+ >;
39
+
40
+ /**
41
+ * Public props for <Select>, used by both custom and native render paths.
42
+ */
43
+ export interface SelectProps<T = string | number>
44
+ extends Omit<React.HTMLAttributes<HTMLElement>, 'onChange'> {
45
+ /**
46
+ * Controls keyboard selection behaviour in the custom select variant.
47
+ * - `focus` (default): arrow keys move focus and commit value immediately.
48
+ * - `commit`: arrow keys only move focus; Enter or click commits value.
49
+ */
50
+ selectionBehaviour?: 'focus' | 'commit';
30
51
  /**
31
52
  * An array of option data, to be rendered either natively or custom
32
53
  */
@@ -51,53 +72,49 @@ interface BaseSelectProps<T = string> {
51
72
  * Native flag determines which implementation to use
52
73
  */
53
74
  native?: boolean;
75
+ /**
76
+ * Adds a text input to filter options in the custom variant; ignored for native
77
+ */
78
+ filterable?: boolean;
79
+ /**
80
+ * Extra props to apply to the filter input when `filterable` is true
81
+ */
82
+ filterInputProps?: FilterInputProps;
83
+ /**
84
+ * Extra attributes forwarded to the native <select> when `native` is true
85
+ */
86
+ nativeHtmlAttributes?: React.SelectHTMLAttributes<HTMLSelectElement>;
87
+ /**
88
+ * Current value (controlled)
89
+ */
90
+ value?: T;
91
+ /**
92
+ * Disable interaction
93
+ */
94
+ disabled?: boolean;
95
+ /**
96
+ * Allow long option labels to wrap instead of truncating
97
+ */
98
+ lineBreak?: boolean;
99
+ /**
100
+ * Custom className for the root element
101
+ */
102
+ className?: string;
103
+ /**
104
+ * Custom className for the options panel
105
+ */
106
+ panelClassName?: string;
107
+ /**
108
+ * Change handler for the custom variant
109
+ */
110
+ onValueChange?: (value: T, ev: React.UIEvent) => void;
111
+ /**
112
+ * Ref forwarded to the rendered element
113
+ * (div for custom, select for native)
114
+ */
115
+ ref?: React.Ref<HTMLDivElement | HTMLSelectElement | null>;
54
116
  }
55
117
 
56
- // export type SelectProps = BaseSelectProps &
57
- // // Discriminated union to determine which implementation to use
58
- // (| ({ native: true; ref?: React.RefObject<HTMLSelectElement | null> } & Omit<
59
- // React.SelectHTMLAttributes<HTMLSelectElement>,
60
- // keyof BaseSelectProps
61
- // >)
62
- // | ({ native?: false; ref?: React.RefObject<HTMLDivElement | null> } & Omit<
63
- // React.HTMLAttributes<HTMLDivElement>,
64
- // keyof BaseSelectProps
65
- // >)
66
- // );
67
-
68
- // Props interface for the two variants are separated.
69
- // We expose SelectProps for developers to use, and handle discrepancies internally.
70
-
71
- /**
72
- * Internal props for the custom implementation, with <div> as root element
73
- * onChange already exists on <div>. We override it.
74
- */
75
- export type CustomSelectProps<T> = Omit<
76
- React.HTMLAttributes<HTMLDivElement>,
77
- 'onChange'
78
- > &
79
- BaseSelectProps<T> & {
80
- native?: false;
81
- value?: T;
82
- disabled?: boolean;
83
- lineBreak?: boolean;
84
- panelClassName?: string;
85
- onValueChange?: (value: T, ev: React.UIEvent) => void;
86
- ref?: React.RefObject<HTMLDivElement | null>;
87
- };
88
-
89
- /**
90
- * Internal props for native implementation, with <select> as root element
91
- * Default props like value and onChange are passed to the <select> element automatically
92
- */
93
- export type NativeSelectProps = React.SelectHTMLAttributes<HTMLSelectElement> &
94
- BaseSelectProps & {
95
- native: true;
96
- ref?: React.RefObject<HTMLSelectElement | null>;
97
- };
98
-
99
- export type SelectProps<T> = NativeSelectProps | CustomSelectProps<T>;
100
-
101
118
  /**
102
119
  * Each option as displayed in the Panel of <CustomSelect>
103
120
  * Roughly equivalent to a custom version of <option>
@@ -105,8 +122,9 @@ export type SelectProps<T> = NativeSelectProps | CustomSelectProps<T>;
105
122
  export interface CustomOptionProps<T>
106
123
  extends Omit<React.HTMLAttributes<HTMLDivElement>, 'onSelect'> {
107
124
  value: T;
125
+ optionIndex?: number;
108
126
  testId?: string;
109
127
  isSelected?: boolean;
110
- onSelect: (event: React.MouseEvent, value: T) => void;
128
+ onSelect: (event: React.MouseEvent, value: T, optionIndex?: number) => void;
111
129
  lineBreak?: boolean;
112
130
  }