@cloud-ru/uikit-product-mobile-fields 0.11.24

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 (65) hide show
  1. package/CHANGELOG.md +1300 -0
  2. package/LICENSE +201 -0
  3. package/README.md +8 -0
  4. package/package.json +66 -0
  5. package/src/components/AdaptiveField/AdaptiveField.tsx +88 -0
  6. package/src/components/AdaptiveField/index.ts +1 -0
  7. package/src/components/MobileFieldDate/MobileFieldDate.tsx +375 -0
  8. package/src/components/MobileFieldDate/constants.ts +33 -0
  9. package/src/components/MobileFieldDate/index.ts +2 -0
  10. package/src/components/MobileFieldDate/styles.module.scss +75 -0
  11. package/src/components/MobileFieldDate/types.ts +6 -0
  12. package/src/components/MobileFieldDate/utils.ts +49 -0
  13. package/src/components/MobileFieldSelect/MobileFieldSelect.tsx +18 -0
  14. package/src/components/MobileFieldSelect/MobileFieldSelectMultiple.tsx +331 -0
  15. package/src/components/MobileFieldSelect/MobileFieldSelectSingle.tsx +300 -0
  16. package/src/components/MobileFieldSelect/hooks.tsx +195 -0
  17. package/src/components/MobileFieldSelect/index.ts +13 -0
  18. package/src/components/MobileFieldSelect/legacy/components/Items/hooks.tsx +53 -0
  19. package/src/components/MobileFieldSelect/legacy/components/index.ts +1 -0
  20. package/src/components/MobileFieldSelect/legacy/hooks.ts +38 -0
  21. package/src/components/MobileFieldSelect/legacy/index.ts +3 -0
  22. package/src/components/MobileFieldSelect/legacy/utils.ts +176 -0
  23. package/src/components/MobileFieldSelect/styles.module.scss +176 -0
  24. package/src/components/MobileFieldSelect/types.ts +156 -0
  25. package/src/components/MobileFieldSelect/utils/extractFieldDecoratorProps.ts +35 -0
  26. package/src/components/MobileFieldSelect/utils/extractListProps.ts +30 -0
  27. package/src/components/MobileFieldSelect/utils/getArrowIcon.ts +15 -0
  28. package/src/components/MobileFieldSelect/utils/index.ts +6 -0
  29. package/src/components/MobileFieldSelect/utils/options.tsx +88 -0
  30. package/src/components/MobileFieldSelect/utils/typeGuards.ts +38 -0
  31. package/src/components/MobileFieldSelect/utils/updateItems.ts +121 -0
  32. package/src/components/index.ts +3 -0
  33. package/src/constants/allFields.ts +11 -0
  34. package/src/constants/dateFields.ts +127 -0
  35. package/src/constants/index.ts +2 -0
  36. package/src/helperComponents/ButtonCopyValue/ButtonCopyValue.tsx +79 -0
  37. package/src/helperComponents/ButtonCopyValue/helpers.tsx +19 -0
  38. package/src/helperComponents/ButtonCopyValue/index.ts +1 -0
  39. package/src/helperComponents/ButtonCopyValue/styles.module.scss +5 -0
  40. package/src/helperComponents/FieldContainerPrivate/FieldContainerPrivate.tsx +79 -0
  41. package/src/helperComponents/FieldContainerPrivate/index.ts +1 -0
  42. package/src/helperComponents/FieldContainerPrivate/styles.module.scss +131 -0
  43. package/src/helperComponents/ItemContent/ItemContent.tsx +37 -0
  44. package/src/helperComponents/ItemContent/index.ts +1 -0
  45. package/src/helperComponents/ItemContent/styles.module.scss +80 -0
  46. package/src/helperComponents/index.ts +3 -0
  47. package/src/hooks/dateHandlers/index.ts +3 -0
  48. package/src/hooks/dateHandlers/useDateField.ts +275 -0
  49. package/src/hooks/dateHandlers/useDateFieldHelpersForMode.ts +145 -0
  50. package/src/hooks/dateHandlers/useFocusHandlers.ts +46 -0
  51. package/src/hooks/dateHandlers/useHandlers.ts +15 -0
  52. package/src/hooks/index.ts +5 -0
  53. package/src/hooks/styles.module.scss +17 -0
  54. package/src/hooks/useCopyButton.tsx +47 -0
  55. package/src/hooks/usePostfix.tsx +21 -0
  56. package/src/hooks/usePrefix.tsx +21 -0
  57. package/src/hooks/useValueControl.ts +15 -0
  58. package/src/index.ts +3 -0
  59. package/src/styles.module.scss +55 -0
  60. package/src/types/allFields.ts +9 -0
  61. package/src/types/dateFields.ts +14 -0
  62. package/src/types/index.ts +2 -0
  63. package/src/utils/adaptiveField.tsx +19 -0
  64. package/src/utils/dateFields.ts +75 -0
  65. package/src/utils/getValidationState.ts +6 -0
@@ -0,0 +1,375 @@
1
+ import cn from 'classnames';
2
+ import mergeRefs from 'merge-refs';
3
+ import { FocusEvent, forwardRef, KeyboardEvent, MouseEvent, useCallback, useEffect, useMemo, useRef } from 'react';
4
+ import { useUncontrolledProp } from 'uncontrollable';
5
+
6
+ import { CalendarSVG } from '@cloud-ru/uikit-product-icons';
7
+ import { MobileDropdown } from '@cloud-ru/uikit-product-mobile-dropdown';
8
+ import { Calendar, CalendarProps } from '@snack-uikit/calendar';
9
+ import { FieldDecorator, FieldDecoratorProps } from '@snack-uikit/fields';
10
+ import {
11
+ ButtonProps,
12
+ ICON_SIZE,
13
+ InputPrivate,
14
+ InputPrivateProps,
15
+ runAfterRerender,
16
+ SIZE,
17
+ useButtonNavigation,
18
+ useClearButton,
19
+ } from '@snack-uikit/input-private';
20
+ import { Scroll } from '@snack-uikit/scroll';
21
+ import { extractSupportProps, WithSupportProps } from '@snack-uikit/utils';
22
+
23
+ import { CONTAINER_VARIANT, DEFAULT_LOCALE, MODES, SlotKey, VALIDATION_STATE } from '../../constants';
24
+ import { FieldContainerPrivate } from '../../helperComponents';
25
+ import { useCopyButton, useDateField, useFocusHandlers, useHandlers } from '../../hooks';
26
+ import { getValidationState } from '../../utils/getValidationState';
27
+ import styles from './styles.module.scss';
28
+
29
+ type InputProps = Pick<InputPrivateProps, 'id' | 'name' | 'disabled' | 'readonly' | 'onFocus' | 'onBlur' | 'autoFocus'>;
30
+
31
+ type WrapperProps = Pick<
32
+ FieldDecoratorProps,
33
+ | 'className'
34
+ | 'label'
35
+ | 'labelTooltip'
36
+ | 'required'
37
+ | 'caption'
38
+ | 'hint'
39
+ | 'showHintIcon'
40
+ | 'size'
41
+ | 'validationState'
42
+ | 'labelTooltipPlacement'
43
+ | 'error'
44
+ >;
45
+
46
+ type FieldDateWithSeconds = {
47
+ mode: typeof MODES.DateTime;
48
+ showSeconds?: boolean;
49
+ };
50
+
51
+ type FieldDateOwnProps = {
52
+ /** Открыт date-picker */
53
+ open?: boolean;
54
+ /** Колбек открытия пикера */
55
+ onOpenChange?(value: boolean): void;
56
+ /** Значение поля */
57
+ value?: Date;
58
+ /** Колбек смены значения */
59
+ onChange?(value: Date | undefined): void;
60
+ /** Отображение кнопки копирования */
61
+ showCopyButton?: boolean;
62
+ /**
63
+ * Отображение кнопки Очистки поля
64
+ * @default true
65
+ */
66
+ showClearButton?: boolean;
67
+ } & Pick<CalendarProps, 'buildCellProps'> &
68
+ (
69
+ | {
70
+ mode: typeof MODES.Date;
71
+ }
72
+ | FieldDateWithSeconds
73
+ );
74
+
75
+ export type MobileFieldDateProps = WithSupportProps<FieldDateOwnProps & InputProps & WrapperProps>;
76
+
77
+ export const MobileFieldDate = forwardRef<HTMLInputElement, MobileFieldDateProps>(
78
+ (
79
+ {
80
+ id,
81
+ name,
82
+ value: valueProp,
83
+ disabled = false,
84
+ readonly = false,
85
+ showCopyButton: showCopyButtonProp = true,
86
+ showClearButton: showClearButtonProp = true,
87
+ open,
88
+ onOpenChange,
89
+ onChange,
90
+ onFocus,
91
+ onBlur: onBlurProp,
92
+ className,
93
+ label,
94
+ labelTooltip,
95
+ labelTooltipPlacement,
96
+ required = false,
97
+ caption,
98
+ hint,
99
+ showHintIcon,
100
+ size = SIZE.S,
101
+ validationState = VALIDATION_STATE.Default,
102
+ buildCellProps,
103
+ error,
104
+ mode,
105
+ autoFocus,
106
+ ...rest
107
+ },
108
+ ref,
109
+ ) => {
110
+ const [isOpen, setIsOpen] = useUncontrolledProp(open, false, onOpenChange);
111
+
112
+ const localRef = useRef<HTMLInputElement>(null);
113
+ const clearButtonRef = useRef<HTMLButtonElement>(null);
114
+ const copyButtonRef = useRef<HTMLButtonElement>(null);
115
+ const calendarIconSize = size === SIZE.S ? ICON_SIZE.Xs : ICON_SIZE.S;
116
+ const showDropList = isOpen && !readonly && !disabled;
117
+ const showAdditionalButton = Boolean(valueProp && !disabled);
118
+ const showClearButton = showClearButtonProp && showAdditionalButton && !readonly;
119
+ const showCopyButton = showCopyButtonProp && showAdditionalButton && readonly;
120
+ const showSeconds = mode === 'date-time' ? ((rest as FieldDateWithSeconds).showSeconds ?? true) : undefined;
121
+ const fieldValidationState = getValidationState({ validationState, error });
122
+
123
+ const navigationStartRef: CalendarProps['navigationStartRef'] = useRef(null);
124
+
125
+ const checkForLeavingFocus = useCallback(
126
+ <T extends HTMLInputElement | HTMLButtonElement>(event: KeyboardEvent<T>) => {
127
+ if (event.key === 'ArrowDown') {
128
+ setIsOpen(true);
129
+ setTimeout(() => navigationStartRef.current?.focus(), 0);
130
+ }
131
+ },
132
+ [setIsOpen],
133
+ );
134
+
135
+ const handleClear = useCallback(() => {
136
+ onChange && onChange(undefined);
137
+ if (localRef.current?.value) {
138
+ localRef.current.value = '';
139
+ }
140
+
141
+ if (required) {
142
+ localRef.current?.focus();
143
+ setIsOpen(true);
144
+ } else {
145
+ localRef.current?.blur();
146
+ setIsOpen(false);
147
+ }
148
+ }, [onChange, required, setIsOpen]);
149
+
150
+ const getStringDateValue = useCallback(
151
+ (date: Date | undefined) => {
152
+ if (!date) return '';
153
+
154
+ if (mode === 'date') {
155
+ return date.toLocaleDateString(DEFAULT_LOCALE);
156
+ }
157
+
158
+ return date.toLocaleString(DEFAULT_LOCALE, {
159
+ year: 'numeric',
160
+ month: 'numeric',
161
+ day: 'numeric',
162
+ hour: '2-digit',
163
+ minute: '2-digit',
164
+ second: showSeconds ? '2-digit' : undefined,
165
+ });
166
+ },
167
+ [mode, showSeconds],
168
+ );
169
+
170
+ const valueToCopy = getStringDateValue(valueProp);
171
+ const clearButtonSettings = useClearButton({ clearButtonRef, showClearButton, size, onClear: handleClear });
172
+ const copyButtonSettings = useCopyButton({ copyButtonRef, showCopyButton, size, valueToCopy });
173
+ const calendarIcon: ButtonProps = useMemo(
174
+ () => ({
175
+ active: false,
176
+ show: true,
177
+ id: 'calendarIcon',
178
+ render: props => (
179
+ <CalendarSVG {...props} size={calendarIconSize} className={styles.calendarIcon} data-size={size} />
180
+ ),
181
+ }),
182
+ [calendarIconSize, size],
183
+ );
184
+
185
+ const memorizedButtons = useMemo(
186
+ () => [clearButtonSettings, copyButtonSettings, calendarIcon],
187
+ [clearButtonSettings, copyButtonSettings, calendarIcon],
188
+ );
189
+
190
+ const {
191
+ value,
192
+ handleChange,
193
+ handleClick: dateInputClickHandler,
194
+ handleKeyDown: dateInputKeyDownHandler,
195
+ handleBlur: dateInputBlurHandler,
196
+ mask,
197
+ setInputFocus,
198
+ } = useDateField({
199
+ inputRef: localRef,
200
+ onChange,
201
+ readonly,
202
+ locale: DEFAULT_LOCALE,
203
+ setIsOpen,
204
+ mode,
205
+ showSeconds,
206
+ });
207
+
208
+ const setInputFocusFromButtons = useCallback(
209
+ () => setInputFocus(mode === 'date' ? SlotKey.Year : SlotKey.Seconds),
210
+ [mode, setInputFocus],
211
+ );
212
+
213
+ const {
214
+ postfixButtons,
215
+ inputTabIndex,
216
+ onInputKeyDown: navigationInputKeyDownHandler,
217
+ setInitialTabIndices,
218
+ } = useButtonNavigation({
219
+ setInputFocus: setInputFocusFromButtons,
220
+ inputRef: localRef,
221
+ postfixButtons: memorizedButtons,
222
+ onButtonKeyDown: checkForLeavingFocus,
223
+ readonly,
224
+ submitKeys: ['Enter', 'Space', 'Tab'],
225
+ });
226
+
227
+ const handleSelectDate = (date: Date) => {
228
+ onChange && onChange(date);
229
+ localRef.current?.focus();
230
+ setIsOpen(false);
231
+
232
+ if (localRef.current) {
233
+ localRef.current.value = getStringDateValue(date);
234
+ }
235
+ };
236
+
237
+ const handleCalendarFocusLeave: CalendarProps['onFocusLeave'] = () => {
238
+ setInitialTabIndices();
239
+ // TODO: find out why it works not as expected (focus is moved to the next element instead of the focused one)
240
+ // maybe floating-ui causes the problem
241
+ runAfterRerender(() => {
242
+ setInputFocus(SlotKey.Day);
243
+ setIsOpen(false);
244
+ });
245
+ };
246
+
247
+ const handleInputKeyDown = useHandlers<KeyboardEvent<HTMLInputElement>>([
248
+ checkForLeavingFocus,
249
+ dateInputKeyDownHandler,
250
+ navigationInputKeyDownHandler,
251
+ ]);
252
+
253
+ useEffect(() => {
254
+ if (open) {
255
+ localRef.current?.focus();
256
+ }
257
+ }, [open]);
258
+
259
+ useEffect(() => {
260
+ if (localRef.current && document.activeElement !== localRef.current) {
261
+ localRef.current.value = getStringDateValue(valueProp);
262
+ }
263
+ }, [getStringDateValue, valueProp]);
264
+
265
+ const onFocusByKeyboard = useCallback(
266
+ (e: FocusEvent<HTMLInputElement>) => {
267
+ setInputFocus();
268
+ onFocus?.(e);
269
+ },
270
+ [onFocus, setInputFocus],
271
+ );
272
+
273
+ const inputHandlers = useFocusHandlers({
274
+ onFocusByClick: onFocus,
275
+ onFocusByKeyboard,
276
+ });
277
+
278
+ const onBlur = useHandlers([dateInputBlurHandler, inputHandlers.onBlur, onBlurProp]);
279
+
280
+ const onClick = useCallback(
281
+ (e: MouseEvent<HTMLInputElement>) => {
282
+ dateInputClickHandler();
283
+ if (isOpen) {
284
+ // stop the event because want picker to stay opened
285
+ e.stopPropagation();
286
+ }
287
+ },
288
+ [dateInputClickHandler, isOpen],
289
+ );
290
+
291
+ return (
292
+ <FieldDecorator
293
+ className={className}
294
+ label={label}
295
+ labelTooltip={labelTooltip}
296
+ labelTooltipPlacement={labelTooltipPlacement}
297
+ labelFor={id}
298
+ required={required}
299
+ caption={caption}
300
+ hint={hint}
301
+ disabled={disabled}
302
+ readonly={readonly}
303
+ showHintIcon={showHintIcon}
304
+ size={size}
305
+ error={error}
306
+ validationState={fieldValidationState}
307
+ {...extractSupportProps(rest)}
308
+ >
309
+ <MobileDropdown
310
+ {...(readonly || disabled
311
+ ? { open: false }
312
+ : {
313
+ open: showDropList,
314
+ onOpenChange: setIsOpen,
315
+ })}
316
+ content={
317
+ <Scroll
318
+ className={cn(styles.calendarWrapper, mode === 'date-time' ? styles.dateTimeWrapper : styles.dateWrapper)}
319
+ data-size={size}
320
+ barHideStrategy='never'
321
+ >
322
+ <Calendar
323
+ mode={mode}
324
+ size='l'
325
+ value={valueProp}
326
+ showSeconds={showSeconds}
327
+ onChangeValue={handleSelectDate}
328
+ buildCellProps={buildCellProps}
329
+ navigationStartRef={navigationStartRef}
330
+ onFocusLeave={handleCalendarFocusLeave}
331
+ locale={DEFAULT_LOCALE}
332
+ data-test-id='field-date__calendar'
333
+ />
334
+ </Scroll>
335
+ }
336
+ >
337
+ <FieldContainerPrivate
338
+ className={styles.container}
339
+ size={size}
340
+ validationState={fieldValidationState}
341
+ disabled={disabled}
342
+ readonly={readonly}
343
+ variant={CONTAINER_VARIANT.SingleLine}
344
+ focused={showDropList}
345
+ inputRef={localRef}
346
+ postfix={postfixButtons}
347
+ >
348
+ <InputPrivate
349
+ ref={mergeRefs(ref, localRef)}
350
+ data-size={size}
351
+ value={value || ''}
352
+ placeholder={mask}
353
+ onChange={handleChange}
354
+ onFocus={inputHandlers.onFocus}
355
+ onMouseDown={inputHandlers.onMouseDown}
356
+ onBlur={onBlur}
357
+ onKeyDown={handleInputKeyDown}
358
+ onClick={onClick}
359
+ disabled={disabled}
360
+ readonly={readonly}
361
+ tabIndex={inputTabIndex}
362
+ type='text'
363
+ inputMode='numeric'
364
+ className={styles.readonlyCursor}
365
+ id={id}
366
+ name={name}
367
+ autoFocus={autoFocus}
368
+ data-test-id='field-date__input'
369
+ />
370
+ </FieldContainerPrivate>
371
+ </MobileDropdown>
372
+ </FieldDecorator>
373
+ );
374
+ },
375
+ );
@@ -0,0 +1,33 @@
1
+ import { Slot } from './types';
2
+
3
+ export enum SlotKey {
4
+ Day = 'D',
5
+ Month = 'M',
6
+ Year = 'Y',
7
+ }
8
+
9
+ export const MASK: Record<string, string> = {
10
+ 'ru-RU': 'ДД.ММ.ГГГГ',
11
+ 'en-US': 'DD.MM.YYYY',
12
+ };
13
+
14
+ export const DEFAULT_LOCALE = new Intl.Locale('ru-RU');
15
+
16
+ export const SLOTS: Record<SlotKey | string, Slot> = {
17
+ [SlotKey.Day]: { start: 0, end: 2, max: 31, min: 1 },
18
+ [SlotKey.Month]: { start: 3, end: 5, max: 12, min: 1 },
19
+ [SlotKey.Year]: { start: 6, end: 10, max: 2100, min: 1900 },
20
+ } as const;
21
+
22
+ export const SLOTS_PLACEHOLDER: Record<string, Record<string, string>> = {
23
+ 'ru-RU': {
24
+ [SlotKey.Day]: 'ДД',
25
+ [SlotKey.Month]: 'ММ',
26
+ [SlotKey.Year]: 'ГГГГ',
27
+ },
28
+ 'en-US': {
29
+ [SlotKey.Day]: 'DD',
30
+ [SlotKey.Month]: 'MM',
31
+ [SlotKey.Year]: 'YYYY',
32
+ },
33
+ };
@@ -0,0 +1,2 @@
1
+ export * from './MobileFieldDate';
2
+ export { parseDate } from './utils';
@@ -0,0 +1,75 @@
1
+ @use '@sbercloud/figma-tokens-cloud-platform/build/scss/components/styles-tokens-element';
2
+ @use '@sbercloud/figma-tokens-cloud-platform/build/scss/components/styles-tokens-fields';
3
+
4
+ $sizes: 's', 'm', 'l';
5
+ $icons-sizes: (
6
+ 's': styles-tokens-element.$icon-xs,
7
+ 'm': styles-tokens-element.$icon-s,
8
+ 'l': styles-tokens-element.$icon-s,
9
+ );
10
+
11
+ .triggerClassName {
12
+ --offset: #{styles-tokens-fields.$space-drop-list-drop-offset};
13
+
14
+ display: block;
15
+ width: 100%;
16
+ }
17
+
18
+ .dateWrapper {
19
+ height: 384px;
20
+ }
21
+
22
+ .dateTimeWrapper {
23
+ height: 458px;
24
+ padding-bottom: 8px;
25
+ }
26
+
27
+ input.readonlyCursor {
28
+ cursor: pointer;
29
+ caret-color: transparent;
30
+ }
31
+
32
+ .calendarWrapper {
33
+ width: 100%;
34
+
35
+ &[data-size='s'] {
36
+ min-width: 240px;
37
+ min-height: 256px;
38
+ }
39
+ &[data-size='m'] {
40
+ min-width: 280px;
41
+ min-height: 308px;
42
+ }
43
+ &[data-size='l'] {
44
+ min-width: 304px;
45
+ min-height: 328px;
46
+ }
47
+ }
48
+
49
+ .container {
50
+ .calendarIcon {
51
+ color: styles-tokens-fields.$sys-neutral-text-light;
52
+
53
+ @each $size in $sizes {
54
+ &[data-size='#{$size}'] {
55
+ width: styles-tokens-fields.simple-var($icons-sizes, $size) !important; /* stylelint-disable-line declaration-no-important */
56
+ height: styles-tokens-fields.simple-var($icons-sizes, $size) !important; /* stylelint-disable-line declaration-no-important */
57
+ }
58
+ }
59
+ }
60
+
61
+ &:hover,
62
+ &:focus-within,
63
+ &[data-focused] {
64
+ .calendarIcon {
65
+ color: styles-tokens-fields.$sys-neutral-text-support;
66
+ }
67
+ }
68
+
69
+ &[data-disabled],
70
+ &[data-readonly] {
71
+ .calendarIcon {
72
+ color: styles-tokens-fields.$sys-neutral-text-disabled;
73
+ }
74
+ }
75
+ }
@@ -0,0 +1,6 @@
1
+ export type Slot = {
2
+ start: number;
3
+ end: number;
4
+ max: number;
5
+ min: number;
6
+ };
@@ -0,0 +1,49 @@
1
+ import { SlotKey, SLOTS } from './constants';
2
+
3
+ export function getSlotKey(index: number | null) {
4
+ if (index !== null) {
5
+ for (const key in SLOTS) {
6
+ if (index >= SLOTS[key].start && index <= SLOTS[key].end) {
7
+ return key;
8
+ }
9
+ }
10
+ }
11
+
12
+ return null;
13
+ }
14
+
15
+ export function getNextSlotKey(slotKey: string | null) {
16
+ switch (slotKey) {
17
+ case SlotKey.Day: {
18
+ return SlotKey.Month;
19
+ }
20
+ case SlotKey.Month:
21
+ case SlotKey.Year:
22
+ default: {
23
+ return SlotKey.Year;
24
+ }
25
+ }
26
+ }
27
+
28
+ export function getPrevSlotKey(slotKey: string | null) {
29
+ switch (slotKey) {
30
+ case SlotKey.Year: {
31
+ return SlotKey.Month;
32
+ }
33
+ case SlotKey.Month:
34
+ case SlotKey.Day:
35
+ default: {
36
+ return SlotKey.Day;
37
+ }
38
+ }
39
+ }
40
+
41
+ /**
42
+ * Преобразует строковое значение поля FieldDate в тип Date
43
+ * @function helper
44
+ */
45
+
46
+ export function parseDate(date: string) {
47
+ const values = date.split('.');
48
+ return new Date(Number(values[2]), Number(values[1]) - 1, Number(values[0]));
49
+ }
@@ -0,0 +1,18 @@
1
+ import { forwardRef } from 'react';
2
+
3
+ import { MobileFieldSelectMultiple } from './MobileFieldSelectMultiple';
4
+ import { MobileFieldSelectSingle } from './MobileFieldSelectSingle';
5
+ import { MobileFieldSelectProps } from './types';
6
+ import { isFieldSelectMultipleProps, isFieldSelectSingleProps } from './utils';
7
+
8
+ export const MobileFieldSelect = forwardRef<HTMLInputElement, MobileFieldSelectProps>((props, ref) => {
9
+ if (isFieldSelectMultipleProps(props)) {
10
+ return <MobileFieldSelectMultiple {...props} ref={ref} />;
11
+ }
12
+
13
+ if (isFieldSelectSingleProps(props)) {
14
+ return <MobileFieldSelectSingle {...props} ref={ref} />;
15
+ }
16
+
17
+ return null;
18
+ });