@octanejs/select 0.1.1
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.
- package/LICENSE +21 -0
- package/README.md +43 -0
- package/UPSTREAM.md +66 -0
- package/package.json +89 -0
- package/src/accessibility-types.ts +70 -0
- package/src/animated/component-element.ts +5 -0
- package/src/animated/index.ts +32 -0
- package/src/animated/input.tsrx +24 -0
- package/src/animated/multi-value.tsrx +23 -0
- package/src/animated/placeholder.tsrx +19 -0
- package/src/animated/single-value.tsrx +18 -0
- package/src/animated/transitions.tsrx +90 -0
- package/src/animated/value-container.tsrx +96 -0
- package/src/animated-registry.ts +10 -0
- package/src/async-creatable.tsrx +30 -0
- package/src/async.tsrx +19 -0
- package/src/base.ts +7 -0
- package/src/builtins.ts +13 -0
- package/src/components.tsrx +875 -0
- package/src/creatable.tsrx +26 -0
- package/src/default-styles.ts +445 -0
- package/src/diacritics.ts +245 -0
- package/src/filters.ts +49 -0
- package/src/index.ts +66 -0
- package/src/menu-placement.ts +143 -0
- package/src/scroll-manager.ts +112 -0
- package/src/select.tsrx +1621 -0
- package/src/state-managed-select.tsrx +19 -0
- package/src/style-adapter.d.ts +25 -0
- package/src/style-adapter.mjs +53 -0
- package/src/style-context.tsrx +37 -0
- package/src/styles.ts +53 -0
- package/src/theme.ts +35 -0
- package/src/types.ts +147 -0
- package/src/use-async.tsrx +146 -0
- package/src/use-creatable.tsrx +151 -0
- package/src/use-state-manager.tsrx +90 -0
- package/src/utils.ts +71 -0
|
@@ -0,0 +1,875 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createContext,
|
|
3
|
+
createPortal,
|
|
4
|
+
useCallback,
|
|
5
|
+
useLayoutEffect,
|
|
6
|
+
useMemo,
|
|
7
|
+
useRef,
|
|
8
|
+
useState,
|
|
9
|
+
} from 'octane';
|
|
10
|
+
import type { OctaneNode } from 'octane';
|
|
11
|
+
import type { Octane } from 'octane/jsx-runtime';
|
|
12
|
+
import { autoUpdate } from '@floating-ui/dom';
|
|
13
|
+
|
|
14
|
+
import type { CSSObjectWithLabel, GroupBase, Theme } from './types';
|
|
15
|
+
import { createKeyframes } from './style-adapter';
|
|
16
|
+
import { useStyleResolver } from './style-context.tsrx';
|
|
17
|
+
|
|
18
|
+
export type Ref<T> = ((value: T | null) => void) | { current: T | null } | null;
|
|
19
|
+
export type ClassNamesState = Record<string, boolean>;
|
|
20
|
+
export type CX = (state: ClassNamesState, ...classNames: (string | undefined)[]) => string;
|
|
21
|
+
type DivProps =
|
|
22
|
+
Omit<Octane.JSX.IntrinsicElements['div'], 'ref'> & {
|
|
23
|
+
ref?: Octane.Ref<HTMLDivElement>;
|
|
24
|
+
};
|
|
25
|
+
type InputPropsBase = Omit<Octane.JSX.IntrinsicElements['input'], 'ref'>;
|
|
26
|
+
type SpanProps = Octane.JSX.IntrinsicElements['span'];
|
|
27
|
+
type SvgProps = Octane.JSX.IntrinsicElements['svg'];
|
|
28
|
+
|
|
29
|
+
export interface CommonComponentProps<
|
|
30
|
+
Option = unknown,
|
|
31
|
+
IsMulti extends boolean = boolean,
|
|
32
|
+
Group extends GroupBase<Option> = GroupBase<Option>,
|
|
33
|
+
> {
|
|
34
|
+
[key: string]: unknown;
|
|
35
|
+
className?: string;
|
|
36
|
+
cx: CX;
|
|
37
|
+
getClassNames: (name: string, props: unknown) => string | undefined;
|
|
38
|
+
getStyles: (name: string, props: unknown) => CSSObjectWithLabel;
|
|
39
|
+
hasValue: boolean;
|
|
40
|
+
isMulti: boolean;
|
|
41
|
+
isRtl: boolean;
|
|
42
|
+
selectProps: { controlShouldRenderValue: boolean } & Record<string, unknown>;
|
|
43
|
+
theme: Theme;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function useStyleProps(
|
|
47
|
+
props: CommonComponentProps,
|
|
48
|
+
name: string,
|
|
49
|
+
state: ClassNamesState = {},
|
|
50
|
+
): { className: string; ref?: undefined } {
|
|
51
|
+
const resolveStyle = useStyleResolver();
|
|
52
|
+
const prefixed = props.cx(state, props.getClassNames(name, props), props.className);
|
|
53
|
+
const css = props.getStyles(name, props);
|
|
54
|
+
const implicitLabels: Record<string, string> = {
|
|
55
|
+
indicatorsContainer: 'IndicatorsContainer',
|
|
56
|
+
valueContainer: 'ValueContainer',
|
|
57
|
+
};
|
|
58
|
+
const labeledCSS =
|
|
59
|
+
css.label === undefined && implicitLabels[name] !== undefined
|
|
60
|
+
? { ...css, label: implicitLabels[name] }
|
|
61
|
+
: css;
|
|
62
|
+
return { className: resolveStyle(labeledCSS, prefixed).className };
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const svgCSS: CSSObjectWithLabel = {
|
|
66
|
+
label: 'Svg',
|
|
67
|
+
display: 'inline-block',
|
|
68
|
+
fill: 'currentColor',
|
|
69
|
+
lineHeight: 1,
|
|
70
|
+
stroke: 'currentColor',
|
|
71
|
+
strokeWidth: 0,
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
export type CrossIconProps = SvgProps & { size?: number };
|
|
75
|
+
export function CrossIcon(props: CrossIconProps) @{
|
|
76
|
+
const resolveStyle = useStyleResolver();
|
|
77
|
+
const { size = 20, className, children: _children, ...rest } = props;
|
|
78
|
+
const resolved = resolveStyle(svgCSS, className);
|
|
79
|
+
<svg
|
|
80
|
+
{...rest}
|
|
81
|
+
height={size}
|
|
82
|
+
width={size}
|
|
83
|
+
viewBox="0 0 20 20"
|
|
84
|
+
aria-hidden="true"
|
|
85
|
+
focusable="false"
|
|
86
|
+
className={resolved.className}
|
|
87
|
+
>
|
|
88
|
+
<path
|
|
89
|
+
d="M14.348 14.849c-0.469 0.469-1.229 0.469-1.697 0l-2.651-3.030-2.651 3.029c-0.469 0.469-1.229 0.469-1.697 0-0.469-0.469-0.469-1.229 0-1.697l2.758-3.15-2.759-3.152c-0.469-0.469-0.469-1.228 0-1.697s1.228-0.469 1.697 0l2.652 3.031 2.651-3.031c0.469-0.469 1.228-0.469 1.697 0s0.469 1.229 0 1.697l-2.758 3.152 2.758 3.15c0.469 0.469 0.469 1.229 0 1.698z"
|
|
90
|
+
/>
|
|
91
|
+
</svg>
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export type DownChevronProps = SvgProps & { size?: number };
|
|
95
|
+
export function DownChevron(props: DownChevronProps) @{
|
|
96
|
+
const resolveStyle = useStyleResolver();
|
|
97
|
+
const { size = 20, className, children: _children, ...rest } = props;
|
|
98
|
+
const resolved = resolveStyle(svgCSS, className);
|
|
99
|
+
<svg
|
|
100
|
+
{...rest}
|
|
101
|
+
height={size}
|
|
102
|
+
width={size}
|
|
103
|
+
viewBox="0 0 20 20"
|
|
104
|
+
aria-hidden="true"
|
|
105
|
+
focusable="false"
|
|
106
|
+
className={resolved.className}
|
|
107
|
+
>
|
|
108
|
+
<path
|
|
109
|
+
d="M4.516 7.548c0.436-0.446 1.043-0.481 1.576 0l3.908 3.747 3.908-3.747c0.533-0.481 1.141-0.446 1.574 0 0.436 0.445 0.408 1.197 0 1.615-0.406 0.418-4.695 4.502-4.695 4.502-0.217 0.223-0.502 0.335-0.787 0.335s-0.57-0.112-0.789-0.335c0 0-4.287-4.084-4.695-4.502s-0.436-1.17 0-1.615z"
|
|
110
|
+
/>
|
|
111
|
+
</svg>
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export interface ContainerProps<
|
|
115
|
+
Option = unknown,
|
|
116
|
+
IsMulti extends boolean = boolean,
|
|
117
|
+
Group extends GroupBase<Option> = GroupBase<Option>,
|
|
118
|
+
> extends CommonComponentProps<Option, IsMulti, Group> {
|
|
119
|
+
children?: OctaneNode;
|
|
120
|
+
innerProps: DivProps;
|
|
121
|
+
isDisabled: boolean;
|
|
122
|
+
isFocused: boolean;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
export function SelectContainer(props: ContainerProps) @{
|
|
126
|
+
const { children, innerProps, isDisabled, isRtl } = props;
|
|
127
|
+
<div
|
|
128
|
+
{...useStyleProps(props, 'container', {
|
|
129
|
+
'--is-disabled': isDisabled,
|
|
130
|
+
'--is-rtl': isRtl,
|
|
131
|
+
})}
|
|
132
|
+
{...innerProps}
|
|
133
|
+
>{children}</div>
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
export interface ControlProps<
|
|
137
|
+
Option = unknown,
|
|
138
|
+
IsMulti extends boolean = boolean,
|
|
139
|
+
Group extends GroupBase<Option> = GroupBase<Option>,
|
|
140
|
+
> extends CommonComponentProps<Option, IsMulti, Group> {
|
|
141
|
+
children?: OctaneNode;
|
|
142
|
+
innerRef: Ref<HTMLDivElement>;
|
|
143
|
+
innerProps: DivProps;
|
|
144
|
+
isDisabled: boolean;
|
|
145
|
+
isFocused: boolean;
|
|
146
|
+
menuIsOpen: boolean;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
export function Control(props: ControlProps) @{
|
|
150
|
+
const { children, isDisabled, isFocused, innerRef, innerProps, menuIsOpen } = props;
|
|
151
|
+
<div
|
|
152
|
+
ref={innerRef}
|
|
153
|
+
{...useStyleProps(props, 'control', {
|
|
154
|
+
control: true,
|
|
155
|
+
'control--is-disabled': isDisabled,
|
|
156
|
+
'control--is-focused': isFocused,
|
|
157
|
+
'control--menu-is-open': menuIsOpen,
|
|
158
|
+
})}
|
|
159
|
+
{...innerProps}
|
|
160
|
+
aria-disabled={isDisabled || undefined}
|
|
161
|
+
>{children}</div>
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
export interface ValueContainerProps<
|
|
165
|
+
Option = unknown,
|
|
166
|
+
IsMulti extends boolean = boolean,
|
|
167
|
+
Group extends GroupBase<Option> = GroupBase<Option>,
|
|
168
|
+
> extends CommonComponentProps<Option, IsMulti, Group> {
|
|
169
|
+
children?: OctaneNode;
|
|
170
|
+
innerProps?: DivProps;
|
|
171
|
+
isDisabled: boolean;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
export function ValueContainer(props: ValueContainerProps) @{
|
|
175
|
+
const { children, innerProps, isMulti, hasValue } = props;
|
|
176
|
+
<div
|
|
177
|
+
{...useStyleProps(props, 'valueContainer', {
|
|
178
|
+
'value-container': true,
|
|
179
|
+
'value-container--is-multi': isMulti,
|
|
180
|
+
'value-container--has-value': hasValue,
|
|
181
|
+
})}
|
|
182
|
+
{...innerProps}
|
|
183
|
+
>{children}</div>
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
export interface IndicatorsContainerProps<
|
|
187
|
+
Option = unknown,
|
|
188
|
+
IsMulti extends boolean = boolean,
|
|
189
|
+
Group extends GroupBase<Option> = GroupBase<Option>,
|
|
190
|
+
> extends CommonComponentProps<Option, IsMulti, Group> {
|
|
191
|
+
children?: OctaneNode;
|
|
192
|
+
innerProps?: DivProps;
|
|
193
|
+
isDisabled: boolean;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
export function IndicatorsContainer(props: IndicatorsContainerProps) @{
|
|
197
|
+
<div
|
|
198
|
+
{...useStyleProps(props, 'indicatorsContainer', { indicators: true })}
|
|
199
|
+
{...props.innerProps}
|
|
200
|
+
>{props.children}</div>
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
export interface PlaceholderProps<
|
|
204
|
+
Option = unknown,
|
|
205
|
+
IsMulti extends boolean = boolean,
|
|
206
|
+
Group extends GroupBase<Option> = GroupBase<Option>,
|
|
207
|
+
> extends CommonComponentProps<Option, IsMulti, Group> {
|
|
208
|
+
children?: OctaneNode;
|
|
209
|
+
innerProps?: DivProps;
|
|
210
|
+
isDisabled: boolean;
|
|
211
|
+
isFocused: boolean;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
export function Placeholder(props: PlaceholderProps) @{
|
|
215
|
+
<div
|
|
216
|
+
{...useStyleProps(props, 'placeholder', { placeholder: true })}
|
|
217
|
+
{...props.innerProps}
|
|
218
|
+
>{props.children}</div>
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
export interface SingleValueProps<
|
|
222
|
+
Option = unknown,
|
|
223
|
+
IsMulti extends boolean = boolean,
|
|
224
|
+
Group extends GroupBase<Option> = GroupBase<Option>,
|
|
225
|
+
> extends CommonComponentProps<Option, IsMulti, Group> {
|
|
226
|
+
children?: OctaneNode;
|
|
227
|
+
data: unknown;
|
|
228
|
+
innerProps?: DivProps;
|
|
229
|
+
isDisabled: boolean;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
export function SingleValue(props: SingleValueProps) @{
|
|
233
|
+
<div
|
|
234
|
+
{...useStyleProps(props, 'singleValue', {
|
|
235
|
+
'single-value': true,
|
|
236
|
+
'single-value--is-disabled': props.isDisabled,
|
|
237
|
+
})}
|
|
238
|
+
{...props.innerProps}
|
|
239
|
+
>{props.children}</div>
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
export interface OptionProps<
|
|
243
|
+
Option = unknown,
|
|
244
|
+
IsMulti extends boolean = boolean,
|
|
245
|
+
Group extends GroupBase<Option> = GroupBase<Option>,
|
|
246
|
+
> extends CommonComponentProps<Option, IsMulti, Group> {
|
|
247
|
+
children?: OctaneNode;
|
|
248
|
+
data: unknown;
|
|
249
|
+
innerRef: Ref<HTMLDivElement>;
|
|
250
|
+
innerProps: DivProps;
|
|
251
|
+
label: string;
|
|
252
|
+
type: 'option';
|
|
253
|
+
isDisabled: boolean;
|
|
254
|
+
isFocused: boolean;
|
|
255
|
+
isSelected: boolean;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
export function Option(props: OptionProps) @{
|
|
259
|
+
<div
|
|
260
|
+
{...useStyleProps(props, 'option', {
|
|
261
|
+
option: true,
|
|
262
|
+
'option--is-disabled': props.isDisabled,
|
|
263
|
+
'option--is-focused': props.isFocused,
|
|
264
|
+
'option--is-selected': props.isSelected,
|
|
265
|
+
})}
|
|
266
|
+
ref={props.innerRef}
|
|
267
|
+
aria-disabled={props.isDisabled}
|
|
268
|
+
{...props.innerProps}
|
|
269
|
+
>{props.children}</div>
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
export interface InputProps<
|
|
273
|
+
Option = unknown,
|
|
274
|
+
IsMulti extends boolean = boolean,
|
|
275
|
+
Group extends GroupBase<Option> = GroupBase<Option>,
|
|
276
|
+
> extends CommonComponentProps<Option, IsMulti, Group>, Omit<InputPropsBase, 'className'> {
|
|
277
|
+
innerRef?: Ref<HTMLInputElement>;
|
|
278
|
+
isHidden: boolean;
|
|
279
|
+
isDisabled?: boolean;
|
|
280
|
+
inputClassName?: string;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
const inputSpacingStyle = {
|
|
284
|
+
gridArea: '1 / 2',
|
|
285
|
+
font: 'inherit',
|
|
286
|
+
minWidth: '2px',
|
|
287
|
+
border: 0,
|
|
288
|
+
margin: 0,
|
|
289
|
+
outline: 0,
|
|
290
|
+
padding: 0,
|
|
291
|
+
} as const;
|
|
292
|
+
|
|
293
|
+
function inputStyle(isHidden: boolean) {
|
|
294
|
+
return {
|
|
295
|
+
label: 'input',
|
|
296
|
+
color: 'inherit',
|
|
297
|
+
background: 0,
|
|
298
|
+
opacity: isHidden ? 0 : 1,
|
|
299
|
+
width: '100%',
|
|
300
|
+
...inputSpacingStyle,
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
export function Input(props: InputProps) @{
|
|
305
|
+
const {
|
|
306
|
+
className: _className,
|
|
307
|
+
clearValue: _clearValue,
|
|
308
|
+
cx,
|
|
309
|
+
getStyles: _getStyles,
|
|
310
|
+
getClassNames: _getClassNames,
|
|
311
|
+
getValue: _getValue,
|
|
312
|
+
hasValue: _hasValue,
|
|
313
|
+
isMulti: _isMulti,
|
|
314
|
+
isRtl: _isRtl,
|
|
315
|
+
options: _options,
|
|
316
|
+
selectOption: _selectOption,
|
|
317
|
+
selectProps: _selectProps,
|
|
318
|
+
setValue: _setValue,
|
|
319
|
+
theme: _theme,
|
|
320
|
+
innerRef,
|
|
321
|
+
isDisabled,
|
|
322
|
+
isHidden,
|
|
323
|
+
inputClassName,
|
|
324
|
+
value,
|
|
325
|
+
...innerProps
|
|
326
|
+
} = props;
|
|
327
|
+
<div {...useStyleProps(props, 'input', { 'input-container': true })} data-value={value || ''}>
|
|
328
|
+
<input
|
|
329
|
+
className={cx({ input: true }, inputClassName)}
|
|
330
|
+
ref={innerRef ?? null}
|
|
331
|
+
style={inputStyle(isHidden)}
|
|
332
|
+
disabled={isDisabled}
|
|
333
|
+
value={value}
|
|
334
|
+
{...innerProps}
|
|
335
|
+
/>
|
|
336
|
+
</div>
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
export interface IndicatorProps<
|
|
340
|
+
Option = unknown,
|
|
341
|
+
IsMulti extends boolean = boolean,
|
|
342
|
+
Group extends GroupBase<Option> = GroupBase<Option>,
|
|
343
|
+
> extends CommonComponentProps<Option, IsMulti, Group> {
|
|
344
|
+
children?: OctaneNode;
|
|
345
|
+
innerProps: DivProps;
|
|
346
|
+
isFocused: boolean;
|
|
347
|
+
isDisabled: boolean;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
export function DropdownIndicator(props: IndicatorProps) @{
|
|
351
|
+
<div
|
|
352
|
+
{...useStyleProps(props, 'dropdownIndicator', {
|
|
353
|
+
indicator: true,
|
|
354
|
+
'dropdown-indicator': true,
|
|
355
|
+
})}
|
|
356
|
+
{...props.innerProps}
|
|
357
|
+
>
|
|
358
|
+
{props.children || <DownChevron />}
|
|
359
|
+
</div>
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
export function ClearIndicator(props: IndicatorProps) @{
|
|
363
|
+
<div
|
|
364
|
+
{...useStyleProps(props, 'clearIndicator', {
|
|
365
|
+
indicator: true,
|
|
366
|
+
'clear-indicator': true,
|
|
367
|
+
})}
|
|
368
|
+
{...props.innerProps}
|
|
369
|
+
>
|
|
370
|
+
{props.children || <CrossIcon />}
|
|
371
|
+
</div>
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
export interface IndicatorSeparatorProps<
|
|
375
|
+
Option = unknown,
|
|
376
|
+
IsMulti extends boolean = boolean,
|
|
377
|
+
Group extends GroupBase<Option> = GroupBase<Option>,
|
|
378
|
+
> extends CommonComponentProps<Option, IsMulti, Group> {
|
|
379
|
+
isDisabled: boolean;
|
|
380
|
+
isFocused: boolean;
|
|
381
|
+
innerProps?: SpanProps;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
export function IndicatorSeparator(props: IndicatorSeparatorProps) @{
|
|
385
|
+
<span
|
|
386
|
+
{...props.innerProps}
|
|
387
|
+
{...useStyleProps(props, 'indicatorSeparator', { 'indicator-separator': true })}
|
|
388
|
+
/>
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
export interface MenuProps<
|
|
392
|
+
Option = unknown,
|
|
393
|
+
IsMulti extends boolean = boolean,
|
|
394
|
+
Group extends GroupBase<Option> = GroupBase<Option>,
|
|
395
|
+
> extends CommonComponentProps<Option, IsMulti, Group> {
|
|
396
|
+
children?: OctaneNode;
|
|
397
|
+
innerRef: Ref<HTMLDivElement>;
|
|
398
|
+
innerProps: DivProps;
|
|
399
|
+
isLoading: boolean;
|
|
400
|
+
placement: 'bottom' | 'top';
|
|
401
|
+
minMenuHeight: number;
|
|
402
|
+
maxMenuHeight: number;
|
|
403
|
+
menuPlacement: 'auto' | 'bottom' | 'top';
|
|
404
|
+
menuPosition: 'absolute' | 'fixed';
|
|
405
|
+
menuShouldScrollIntoView: boolean;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
export function Menu(props: MenuProps) @{
|
|
409
|
+
<div
|
|
410
|
+
{...useStyleProps(props, 'menu', { menu: true })}
|
|
411
|
+
ref={props.innerRef}
|
|
412
|
+
{...props.innerProps}
|
|
413
|
+
>{props.children}</div>
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
export interface MenuListProps<
|
|
417
|
+
Option = unknown,
|
|
418
|
+
IsMulti extends boolean = boolean,
|
|
419
|
+
Group extends GroupBase<Option> = GroupBase<Option>,
|
|
420
|
+
> extends CommonComponentProps<Option, IsMulti, Group> {
|
|
421
|
+
children?: OctaneNode;
|
|
422
|
+
innerRef: Ref<HTMLDivElement>;
|
|
423
|
+
innerProps: DivProps;
|
|
424
|
+
maxHeight: number;
|
|
425
|
+
focusedOption: unknown;
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
export function MenuList(props: MenuListProps) @{
|
|
429
|
+
<div
|
|
430
|
+
{...useStyleProps(props, 'menuList', {
|
|
431
|
+
'menu-list': true,
|
|
432
|
+
'menu-list--is-multi': props.isMulti,
|
|
433
|
+
})}
|
|
434
|
+
ref={props.innerRef}
|
|
435
|
+
{...props.innerProps}
|
|
436
|
+
>{props.children}</div>
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
export interface NoticeProps<
|
|
440
|
+
Option = unknown,
|
|
441
|
+
IsMulti extends boolean = boolean,
|
|
442
|
+
Group extends GroupBase<Option> = GroupBase<Option>,
|
|
443
|
+
> extends CommonComponentProps<Option, IsMulti, Group> {
|
|
444
|
+
children?: OctaneNode;
|
|
445
|
+
innerProps?: DivProps;
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
export function NoOptionsMessage(props: NoticeProps) @{
|
|
449
|
+
const children = props.children ?? 'No options';
|
|
450
|
+
<div
|
|
451
|
+
{...useStyleProps(props, 'noOptionsMessage', {
|
|
452
|
+
'menu-notice': true,
|
|
453
|
+
'menu-notice--no-options': true,
|
|
454
|
+
})}
|
|
455
|
+
{...props.innerProps}
|
|
456
|
+
>{children}</div>
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
export function LoadingMessage(props: NoticeProps) @{
|
|
460
|
+
const children = props.children ?? 'Loading...';
|
|
461
|
+
<div
|
|
462
|
+
{...useStyleProps(props, 'loadingMessage', {
|
|
463
|
+
'menu-notice': true,
|
|
464
|
+
'menu-notice--loading': true,
|
|
465
|
+
})}
|
|
466
|
+
{...props.innerProps}
|
|
467
|
+
>{children}</div>
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
type ComponentType<Props> = (props: Props) => Octane.JSX.Element;
|
|
471
|
+
|
|
472
|
+
function cleanCommonProps<Props extends CommonComponentProps>(props: Props) {
|
|
473
|
+
const {
|
|
474
|
+
className: _className,
|
|
475
|
+
cx: _cx,
|
|
476
|
+
getStyles: _getStyles,
|
|
477
|
+
getClassNames: _getClassNames,
|
|
478
|
+
hasValue: _hasValue,
|
|
479
|
+
isMulti: _isMulti,
|
|
480
|
+
isRtl: _isRtl,
|
|
481
|
+
selectProps: _selectProps,
|
|
482
|
+
theme: _theme,
|
|
483
|
+
...innerProps
|
|
484
|
+
} = props;
|
|
485
|
+
return innerProps;
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
export type GroupHeadingProps<
|
|
489
|
+
Option = unknown,
|
|
490
|
+
IsMulti extends boolean = boolean,
|
|
491
|
+
Group extends GroupBase<Option> = GroupBase<Option>,
|
|
492
|
+
> =
|
|
493
|
+
CommonComponentProps<Option, IsMulti, Group> & Omit<DivProps, 'className'> & {
|
|
494
|
+
children?: OctaneNode;
|
|
495
|
+
id: string;
|
|
496
|
+
data: unknown;
|
|
497
|
+
};
|
|
498
|
+
|
|
499
|
+
export function GroupHeading(props: GroupHeadingProps) @{
|
|
500
|
+
const { data: _data, ...innerProps } = cleanCommonProps(props);
|
|
501
|
+
<div {...useStyleProps(props, 'groupHeading', { 'group-heading': true })} {...innerProps} />
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
export interface GroupProps<
|
|
505
|
+
Option = unknown,
|
|
506
|
+
IsMulti extends boolean = boolean,
|
|
507
|
+
GroupType extends GroupBase<Option> = GroupBase<Option>,
|
|
508
|
+
> extends CommonComponentProps<Option, IsMulti, GroupType> {
|
|
509
|
+
children?: OctaneNode;
|
|
510
|
+
Heading: ComponentType<GroupHeadingProps>;
|
|
511
|
+
headingProps: { id: string; data: unknown };
|
|
512
|
+
innerProps?: DivProps;
|
|
513
|
+
label?: OctaneNode;
|
|
514
|
+
data: unknown;
|
|
515
|
+
options: readonly unknown[];
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
export function Group(props: GroupProps) @{
|
|
519
|
+
const Heading = props.Heading;
|
|
520
|
+
<div {...useStyleProps(props, 'group', { group: true })} {...props.innerProps}>
|
|
521
|
+
<Heading
|
|
522
|
+
{...props.headingProps}
|
|
523
|
+
selectProps={props.selectProps}
|
|
524
|
+
theme={props.theme}
|
|
525
|
+
getStyles={props.getStyles}
|
|
526
|
+
getClassNames={props.getClassNames}
|
|
527
|
+
cx={props.cx}
|
|
528
|
+
hasValue={props.hasValue}
|
|
529
|
+
isMulti={props.isMulti}
|
|
530
|
+
isRtl={props.isRtl}
|
|
531
|
+
>{props.label}</Heading>
|
|
532
|
+
<div>{props.children}</div>
|
|
533
|
+
</div>
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
export interface MultiValueGenericProps<
|
|
537
|
+
Option = unknown,
|
|
538
|
+
IsMulti extends boolean = boolean,
|
|
539
|
+
Group extends GroupBase<Option> = GroupBase<Option>,
|
|
540
|
+
> {
|
|
541
|
+
children?: OctaneNode;
|
|
542
|
+
data: unknown;
|
|
543
|
+
innerProps: DivProps;
|
|
544
|
+
selectProps: Record<string, unknown>;
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
export function MultiValueGeneric(props: MultiValueGenericProps) @{
|
|
548
|
+
<div {...props.innerProps}>{props.children}</div>
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
export const MultiValueContainer = MultiValueGeneric;
|
|
552
|
+
export const MultiValueLabel = MultiValueGeneric;
|
|
553
|
+
|
|
554
|
+
export interface MultiValueRemoveProps<
|
|
555
|
+
Option = unknown,
|
|
556
|
+
IsMulti extends boolean = boolean,
|
|
557
|
+
Group extends GroupBase<Option> = GroupBase<Option>,
|
|
558
|
+
> {
|
|
559
|
+
children?: OctaneNode;
|
|
560
|
+
data: unknown;
|
|
561
|
+
innerProps: DivProps;
|
|
562
|
+
selectProps: Record<string, unknown>;
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
export function MultiValueRemove(props: MultiValueRemoveProps) @{
|
|
566
|
+
<div role="button" {...props.innerProps}>{props.children || <CrossIcon size={14} />}</div>
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
export interface MultiValueProps<
|
|
570
|
+
Option = unknown,
|
|
571
|
+
IsMulti extends boolean = boolean,
|
|
572
|
+
Group extends GroupBase<Option> = GroupBase<Option>,
|
|
573
|
+
> extends CommonComponentProps<Option, IsMulti, Group> {
|
|
574
|
+
children?: OctaneNode;
|
|
575
|
+
components: {
|
|
576
|
+
Container: ComponentType<MultiValueGenericProps>;
|
|
577
|
+
Label: ComponentType<MultiValueGenericProps>;
|
|
578
|
+
Remove: ComponentType<MultiValueRemoveProps>;
|
|
579
|
+
};
|
|
580
|
+
cropWithEllipsis?: boolean;
|
|
581
|
+
data: unknown;
|
|
582
|
+
innerProps?: DivProps;
|
|
583
|
+
isFocused: boolean;
|
|
584
|
+
isDisabled: boolean;
|
|
585
|
+
removeProps: DivProps;
|
|
586
|
+
index: number;
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
export function MultiValue(props: MultiValueProps) @{
|
|
590
|
+
const Container = props.components.Container;
|
|
591
|
+
const Label = props.components.Label;
|
|
592
|
+
const Remove = props.components.Remove;
|
|
593
|
+
<Container
|
|
594
|
+
data={props.data}
|
|
595
|
+
innerProps={{
|
|
596
|
+
...useStyleProps(props, 'multiValue', {
|
|
597
|
+
'multi-value': true,
|
|
598
|
+
'multi-value--is-disabled': props.isDisabled,
|
|
599
|
+
}),
|
|
600
|
+
...props.innerProps,
|
|
601
|
+
}}
|
|
602
|
+
selectProps={props.selectProps}
|
|
603
|
+
>
|
|
604
|
+
<Label
|
|
605
|
+
data={props.data}
|
|
606
|
+
innerProps={{
|
|
607
|
+
...useStyleProps(props, 'multiValueLabel', { 'multi-value__label': true }),
|
|
608
|
+
}}
|
|
609
|
+
selectProps={props.selectProps}
|
|
610
|
+
>{props.children}</Label>
|
|
611
|
+
<Remove
|
|
612
|
+
data={props.data}
|
|
613
|
+
innerProps={{
|
|
614
|
+
...useStyleProps(props, 'multiValueRemove', { 'multi-value__remove': true }),
|
|
615
|
+
'aria-label': `Remove ${props.children || 'option'}`,
|
|
616
|
+
...props.removeProps,
|
|
617
|
+
}}
|
|
618
|
+
selectProps={props.selectProps}
|
|
619
|
+
/>
|
|
620
|
+
</Container>
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
const loadingDotAnimations = createKeyframes({
|
|
624
|
+
'0%, 80%, 100%': { opacity: 0 },
|
|
625
|
+
'40%': { opacity: 1 },
|
|
626
|
+
});
|
|
627
|
+
|
|
628
|
+
function LoadingDot(props: { delay: number; offset: boolean }) @{
|
|
629
|
+
const resolveStyle = useStyleResolver();
|
|
630
|
+
const resolved = resolveStyle({
|
|
631
|
+
animation: `${loadingDotAnimations} 1s ease-in-out ${props.delay}ms infinite;`,
|
|
632
|
+
backgroundColor: 'currentColor',
|
|
633
|
+
borderRadius: '1em',
|
|
634
|
+
display: 'inline-block',
|
|
635
|
+
marginLeft: props.offset ? '1em' : undefined,
|
|
636
|
+
height: '1em',
|
|
637
|
+
verticalAlign: 'top',
|
|
638
|
+
width: '1em',
|
|
639
|
+
label: 'LoadingDot',
|
|
640
|
+
});
|
|
641
|
+
<span className={resolved.className} />
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
export interface LoadingIndicatorProps<
|
|
645
|
+
Option = unknown,
|
|
646
|
+
IsMulti extends boolean = boolean,
|
|
647
|
+
Group extends GroupBase<Option> = GroupBase<Option>,
|
|
648
|
+
> extends CommonComponentProps<Option, IsMulti, Group> {
|
|
649
|
+
innerProps: DivProps;
|
|
650
|
+
isFocused: boolean;
|
|
651
|
+
isDisabled: boolean;
|
|
652
|
+
size?: number;
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
export function LoadingIndicator(props: LoadingIndicatorProps) @{
|
|
656
|
+
const size = props.size ?? 4;
|
|
657
|
+
const styleInput = { ...props, size };
|
|
658
|
+
<div
|
|
659
|
+
{...useStyleProps(styleInput, 'loadingIndicator', {
|
|
660
|
+
indicator: true,
|
|
661
|
+
'loading-indicator': true,
|
|
662
|
+
})}
|
|
663
|
+
{...props.innerProps}
|
|
664
|
+
>
|
|
665
|
+
<LoadingDot delay={0} offset={props.isRtl} />
|
|
666
|
+
<LoadingDot delay={160} offset={true} />
|
|
667
|
+
<LoadingDot delay={320} offset={!props.isRtl} />
|
|
668
|
+
</div>
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
type MenuPlacement = 'auto' | 'bottom' | 'top';
|
|
672
|
+
type MenuPosition = 'absolute' | 'fixed';
|
|
673
|
+
const PortalPlacementContext = createContext<
|
|
674
|
+
| {
|
|
675
|
+
setPortalPlacement: (placement: 'bottom' | 'top') => void;
|
|
676
|
+
}
|
|
677
|
+
| null
|
|
678
|
+
>(null);
|
|
679
|
+
|
|
680
|
+
function coercePlacement(placement: MenuPlacement): 'bottom' | 'top' {
|
|
681
|
+
return placement === 'auto' ? 'bottom' : placement;
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
function boundingClientObject(element: HTMLElement) {
|
|
685
|
+
const rect = element.getBoundingClientRect();
|
|
686
|
+
return {
|
|
687
|
+
bottom: rect.bottom,
|
|
688
|
+
height: rect.height,
|
|
689
|
+
left: rect.left,
|
|
690
|
+
right: rect.right,
|
|
691
|
+
top: rect.top,
|
|
692
|
+
width: rect.width,
|
|
693
|
+
};
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
export interface MenuPortalProps<
|
|
697
|
+
Option = unknown,
|
|
698
|
+
IsMulti extends boolean = boolean,
|
|
699
|
+
Group extends GroupBase<Option> = GroupBase<Option>,
|
|
700
|
+
> extends CommonComponentProps<Option, IsMulti, Group> {
|
|
701
|
+
appendTo: HTMLElement | undefined;
|
|
702
|
+
children?: OctaneNode;
|
|
703
|
+
controlElement: HTMLDivElement | null;
|
|
704
|
+
innerProps: DivProps;
|
|
705
|
+
menuPlacement: MenuPlacement;
|
|
706
|
+
menuPosition: MenuPosition;
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
export function MenuPortal(props: MenuPortalProps) @{
|
|
710
|
+
const menuPortalRef = useRef<HTMLDivElement | null>(null);
|
|
711
|
+
const cleanupRef = useRef<(() => void) | null>(null);
|
|
712
|
+
const [placement, setPortalPlacement] = useState<'bottom' | 'top'>(
|
|
713
|
+
coercePlacement(props.menuPlacement),
|
|
714
|
+
);
|
|
715
|
+
const portalPlacementContext = useMemo(() => ({ setPortalPlacement }), []);
|
|
716
|
+
useLayoutEffect(() => {
|
|
717
|
+
setPortalPlacement(coercePlacement(props.menuPlacement));
|
|
718
|
+
}, [props.menuPlacement]);
|
|
719
|
+
const [computedPosition, setComputedPosition] = useState<
|
|
720
|
+
| {
|
|
721
|
+
offset: number;
|
|
722
|
+
rect: { left: number; width: number };
|
|
723
|
+
}
|
|
724
|
+
| null
|
|
725
|
+
>(null);
|
|
726
|
+
|
|
727
|
+
const updateComputedPosition = useCallback(() => {
|
|
728
|
+
if (!props.controlElement) return;
|
|
729
|
+
const rect = boundingClientObject(props.controlElement);
|
|
730
|
+
const scrollDistance =
|
|
731
|
+
props.menuPosition === 'fixed' ? 0 : window.pageYOffset;
|
|
732
|
+
const offset = rect[placement] + scrollDistance;
|
|
733
|
+
if (
|
|
734
|
+
offset !== computedPosition?.offset || rect.left !== computedPosition?.rect.left ||
|
|
735
|
+
rect.width !== computedPosition?.rect.width
|
|
736
|
+
) {
|
|
737
|
+
setComputedPosition({ offset, rect });
|
|
738
|
+
}
|
|
739
|
+
}, [
|
|
740
|
+
props.controlElement,
|
|
741
|
+
props.menuPosition,
|
|
742
|
+
placement,
|
|
743
|
+
computedPosition?.offset,
|
|
744
|
+
computedPosition?.rect.left,
|
|
745
|
+
computedPosition?.rect.width,
|
|
746
|
+
]);
|
|
747
|
+
|
|
748
|
+
useLayoutEffect(() => {
|
|
749
|
+
updateComputedPosition();
|
|
750
|
+
}, [updateComputedPosition]);
|
|
751
|
+
|
|
752
|
+
const runAutoUpdate = useCallback(() => {
|
|
753
|
+
cleanupRef.current?.();
|
|
754
|
+
cleanupRef.current = null;
|
|
755
|
+
if (props.controlElement && menuPortalRef.current) {
|
|
756
|
+
cleanupRef.current = autoUpdate(
|
|
757
|
+
props.controlElement,
|
|
758
|
+
menuPortalRef.current,
|
|
759
|
+
updateComputedPosition,
|
|
760
|
+
{ elementResize: 'ResizeObserver' in window },
|
|
761
|
+
);
|
|
762
|
+
}
|
|
763
|
+
}, [props.controlElement, updateComputedPosition]);
|
|
764
|
+
|
|
765
|
+
useLayoutEffect(() => {
|
|
766
|
+
runAutoUpdate();
|
|
767
|
+
return () => cleanupRef.current?.();
|
|
768
|
+
}, [runAutoUpdate]);
|
|
769
|
+
|
|
770
|
+
const setMenuPortalElement = useCallback((element: HTMLDivElement | null) => {
|
|
771
|
+
menuPortalRef.current = element;
|
|
772
|
+
runAutoUpdate();
|
|
773
|
+
}, [runAutoUpdate]);
|
|
774
|
+
|
|
775
|
+
if (!props.appendTo && props.menuPosition !== 'fixed' || !computedPosition) return null;
|
|
776
|
+
|
|
777
|
+
const menuWrapperProps: DivProps = {
|
|
778
|
+
...useStyleProps(
|
|
779
|
+
{
|
|
780
|
+
...props,
|
|
781
|
+
offset: computedPosition.offset,
|
|
782
|
+
position: props.menuPosition,
|
|
783
|
+
rect: computedPosition.rect,
|
|
784
|
+
},
|
|
785
|
+
'menuPortal',
|
|
786
|
+
{ 'menu-portal': true },
|
|
787
|
+
),
|
|
788
|
+
...props.innerProps,
|
|
789
|
+
ref: [setMenuPortalElement, props.innerProps.ref],
|
|
790
|
+
};
|
|
791
|
+
const menuWrapper = <div {...menuWrapperProps}>{props.children}</div>;
|
|
792
|
+
|
|
793
|
+
<PortalPlacementContext.Provider value={portalPlacementContext}>
|
|
794
|
+
{props.appendTo ? createPortal(menuWrapper, props.appendTo) : menuWrapper}
|
|
795
|
+
</PortalPlacementContext.Provider>
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
export interface SelectComponents<
|
|
799
|
+
Option = unknown,
|
|
800
|
+
IsMulti extends boolean = boolean,
|
|
801
|
+
Group extends GroupBase<Option> = GroupBase<Option>,
|
|
802
|
+
> {
|
|
803
|
+
ClearIndicator: ComponentType<IndicatorProps<Option, IsMulti, Group>>;
|
|
804
|
+
Control: ComponentType<ControlProps<Option, IsMulti, Group>>;
|
|
805
|
+
DropdownIndicator: ComponentType<IndicatorProps<Option, IsMulti, Group>> | null;
|
|
806
|
+
DownChevron: ComponentType<DownChevronProps>;
|
|
807
|
+
CrossIcon: ComponentType<CrossIconProps>;
|
|
808
|
+
Group: ComponentType<GroupProps<Option, IsMulti, Group>>;
|
|
809
|
+
GroupHeading: ComponentType<GroupHeadingProps<Option, IsMulti, Group>>;
|
|
810
|
+
IndicatorsContainer: ComponentType<IndicatorsContainerProps<Option, IsMulti, Group>>;
|
|
811
|
+
IndicatorSeparator: ComponentType<IndicatorSeparatorProps<Option, IsMulti, Group>> | null;
|
|
812
|
+
Input: ComponentType<InputProps<Option, IsMulti, Group>>;
|
|
813
|
+
LoadingIndicator: ComponentType<LoadingIndicatorProps<Option, IsMulti, Group>>;
|
|
814
|
+
Menu: ComponentType<MenuProps<Option, IsMulti, Group>>;
|
|
815
|
+
MenuList: ComponentType<MenuListProps<Option, IsMulti, Group>>;
|
|
816
|
+
MenuPortal: (props: MenuPortalProps<Option, IsMulti, Group>) => Octane.JSX.Element | null;
|
|
817
|
+
LoadingMessage: ComponentType<NoticeProps<Option, IsMulti, Group>>;
|
|
818
|
+
NoOptionsMessage: ComponentType<NoticeProps<Option, IsMulti, Group>>;
|
|
819
|
+
MultiValue: ComponentType<MultiValueProps<Option, IsMulti, Group>>;
|
|
820
|
+
MultiValueContainer: ComponentType<MultiValueGenericProps<Option, IsMulti, Group>>;
|
|
821
|
+
MultiValueLabel: ComponentType<MultiValueGenericProps<Option, IsMulti, Group>>;
|
|
822
|
+
MultiValueRemove: ComponentType<MultiValueRemoveProps<Option, IsMulti, Group>>;
|
|
823
|
+
Option: ComponentType<OptionProps<Option, IsMulti, Group>>;
|
|
824
|
+
Placeholder: ComponentType<PlaceholderProps<Option, IsMulti, Group>>;
|
|
825
|
+
SelectContainer: ComponentType<ContainerProps<Option, IsMulti, Group>>;
|
|
826
|
+
SingleValue: ComponentType<SingleValueProps<Option, IsMulti, Group>>;
|
|
827
|
+
ValueContainer: ComponentType<ValueContainerProps<Option, IsMulti, Group>>;
|
|
828
|
+
}
|
|
829
|
+
|
|
830
|
+
export type SelectComponentsConfig<
|
|
831
|
+
Option = unknown,
|
|
832
|
+
IsMulti extends boolean = boolean,
|
|
833
|
+
Group extends GroupBase<Option> = GroupBase<Option>,
|
|
834
|
+
> =
|
|
835
|
+
Partial<SelectComponents<Option, IsMulti, Group>>;
|
|
836
|
+
|
|
837
|
+
export const components: SelectComponents = {
|
|
838
|
+
ClearIndicator,
|
|
839
|
+
Control,
|
|
840
|
+
DropdownIndicator,
|
|
841
|
+
DownChevron,
|
|
842
|
+
CrossIcon,
|
|
843
|
+
Group,
|
|
844
|
+
GroupHeading,
|
|
845
|
+
IndicatorsContainer,
|
|
846
|
+
IndicatorSeparator,
|
|
847
|
+
Input,
|
|
848
|
+
LoadingIndicator,
|
|
849
|
+
Menu,
|
|
850
|
+
MenuList,
|
|
851
|
+
MenuPortal,
|
|
852
|
+
LoadingMessage,
|
|
853
|
+
NoOptionsMessage,
|
|
854
|
+
MultiValue,
|
|
855
|
+
MultiValueContainer,
|
|
856
|
+
MultiValueLabel,
|
|
857
|
+
MultiValueRemove,
|
|
858
|
+
Option,
|
|
859
|
+
Placeholder,
|
|
860
|
+
SelectContainer,
|
|
861
|
+
SingleValue,
|
|
862
|
+
ValueContainer,
|
|
863
|
+
};
|
|
864
|
+
|
|
865
|
+
export type SelectComponentsGeneric = typeof components;
|
|
866
|
+
|
|
867
|
+
export function defaultComponents<
|
|
868
|
+
Option = unknown,
|
|
869
|
+
IsMulti extends boolean = boolean,
|
|
870
|
+
Group extends GroupBase<Option> = GroupBase<Option>,
|
|
871
|
+
>(props: {
|
|
872
|
+
components: SelectComponentsConfig<Option, IsMulti, Group>;
|
|
873
|
+
}): SelectComponents<Option, IsMulti, Group> {
|
|
874
|
+
return { ...components, ...props.components } as SelectComponents<Option, IsMulti, Group>;
|
|
875
|
+
}
|