@itcase/forms 1.1.9 → 1.1.11

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.
@@ -1,3046 +0,0 @@
1
- import { isPossiblePhoneNumber } from 'libphonenumber-js';
2
- import React$1, { useMemo, useEffect, useCallback, useState } from 'react';
3
- import { setIn, FORM_ERROR, getIn } from 'final-form';
4
- import { useForm, Field, Form, FormSpy } from 'react-final-form';
5
- export { Field, useForm, useFormState } from 'react-final-form';
6
- import clsx from 'clsx';
7
- import { Checkbox } from '@itcase/ui/components/Checkbox';
8
- import { Divider } from '@itcase/ui/components/Divider';
9
- import { Text } from '@itcase/ui/components/Text';
10
- import { useDeviceTargetClass } from '@itcase/ui/hooks/useDeviceTargetClass';
11
- import { useStyles } from '@itcase/ui/hooks/useStyles';
12
- import camelCase from 'lodash/camelCase';
13
- import snakeCase from 'lodash/snakeCase';
14
- import { Choice } from '@itcase/ui/components/Choice';
15
- import { Icon } from '@itcase/ui/components/Icon';
16
- import { Code } from '@itcase/ui/components/Code';
17
- import { DatePickerInput } from '@itcase/ui/components/DatePicker';
18
- import { useDevicePropsGenerator } from '@itcase/ui/hooks/useDevicePropsGenerator';
19
- import axios from 'axios';
20
- import { fromEvent } from 'file-selector';
21
- import castArray from 'lodash/castArray';
22
- import { useDropzone, ErrorCode } from 'react-dropzone';
23
- import { createFileFromDataURL } from '@itcase/common';
24
- import { Loader } from '@itcase/ui/components/Loader';
25
- import { Title } from '@itcase/ui/components/Title';
26
- import { Input } from '@itcase/ui/components/Input';
27
- import { Radio } from '@itcase/ui/components/Radio';
28
- import { Segmented } from '@itcase/ui/components/Segmented';
29
- import { Select } from '@itcase/ui/components/Select';
30
- import { Switch } from '@itcase/ui/components/Switch';
31
- import { Textarea } from '@itcase/ui/components/Textarea';
32
- import { useIMask } from 'react-imask';
33
- import { Chips } from '@itcase/ui/components/Chips';
34
- import { Button } from '@itcase/ui/components/Button';
35
- import { Group as Group$1 } from '@itcase/ui/components/Group';
36
- import { NotificationItem } from '@itcase/ui/components/Notification';
37
- import createDecorator from 'final-form-focus';
38
-
39
- const phoneValidation = value => {
40
- if (!value) {
41
- return true;
42
- }
43
- return isPossiblePhoneNumber(value, 'RU');
44
- };
45
- const emailValidation = value => {
46
- // from https://emailregex.com/
47
- if (!value) {
48
- return true;
49
- }
50
-
51
- // from https://www.regular-expressions.info/email.html
52
- const regexp = /^[a-za-яёЁ0-9_-]+(?:\.[a-za-яёЁ0-9_-]+)*@(?:[a-za-яёЁ0-9](?:[a-za-яёЁ0-9-]*[a-za-яёЁ0-9])?\.)+[a-za-яёЁ0-9]+$/;
53
- return regexp.test(String(value).toLowerCase());
54
- };
55
- const dateValidation = value => {
56
- const valueDate = value instanceof Date ? value : new Date(value);
57
- const isDateValid = !isNaN(valueDate.getTime());
58
- return isDateValid;
59
- };
60
- const addRequiredFieldsParamToSchema = schema => {
61
- const fields = Object.entries(schema.fields);
62
- schema.requiredFields = fields.reduce((list, [fieldName, validationProps]) => {
63
- if (validationProps.exclusiveTests?.required) {
64
- list.push(fieldName);
65
- }
66
- return list;
67
- }, []);
68
- return schema;
69
- };
70
-
71
- /**
72
- * Sets the `innerError.message` in an `errors` object at the key
73
- * defined by `innerError.path`.
74
- * @param {Object} errors The object to set the error in.
75
- * @param {{ path: string, message: string }} innerError A `yup` field error.
76
- * @returns {Object} The result of setting the new error message onto `errors`.
77
- */
78
- const setInError = (errors, innerError) => {
79
- return setIn(errors, innerError.path, innerError.message);
80
- };
81
-
82
- /**
83
- * Empty object map with no prototype. Used as default
84
- * value for reducing the `err.inner` array of errors
85
- * from a `yup~ValidationError`.
86
- */
87
- const emptyObj = Object.create(null);
88
-
89
- /**
90
- * Takes a `yup` validation schema and returns a function that expects
91
- * a map of values to validate. If the validation passes, the function resolves to `undefined`
92
- * (signalling that the values are valid). If the validation doesn't pass, it resolves
93
- * to a map of invalid field names to errors.
94
- * @param {import('yup').ObjectSchema} schema `yup` schema definition.
95
- * @returns {(values: Object) => Promise<?Object>} An async function that expects some `values`
96
- * and resolves to either `undefined` or a map of field names to error messages.
97
- */
98
-
99
- const makeValidate = schema => {
100
- return async function validate(values) {
101
- try {
102
- await schema.validate(values, {
103
- abortEarly: false
104
- });
105
- } catch (error) {
106
- if (error.inner) {
107
- return error.inner.reduce(setInError, emptyObj);
108
- } else {
109
- console.warn('itcase-forms schema.validate error: An error not related to the form occurred during validation. Validation ignored.');
110
- }
111
- }
112
- };
113
- };
114
- function useYupValidationSchema(schema, language) {
115
- const validate = useMemo(() => schema && makeValidate(schema), [schema, language]);
116
- return validate;
117
- }
118
-
119
- const defaultFieldProps = {
120
- width: 'fill',
121
- direction: 'vertical',
122
- labelTextColor: 'surfaceTextPrimary',
123
- labelTextSize: 'm',
124
- errorMessageTextColor: 'errorTextSecondary',
125
- errorMessageTextSize: 's',
126
- dividerFill: 'errorPrimary',
127
- helpTextColor: 'surfaceTextQuaternary',
128
- helpTextSize: 's',
129
- messageTextColor: 'surfaceTextSecondary',
130
- messageTextSize: 's',
131
- requiredMessageTextColor: 'warningTextSecondary',
132
- requiredMessageTextSize: 's',
133
- showMessage: true
134
- };
135
-
136
- function FieldWrapperBase(props) {
137
- const {
138
- id,
139
- className,
140
- type = 'normal',
141
- label,
142
- labelHidden,
143
- labelTextColor,
144
- labelTextSize,
145
- labelTextSizeMobile,
146
- labelTextSizeTablet,
147
- labelTextWeight,
148
- desc,
149
- descTextColor,
150
- descTextSize,
151
- descTextWeight,
152
- errorKey,
153
- errorMessage,
154
- isErrorState,
155
- metaError,
156
- helpTextColorSuccess,
157
- isDisabled,
158
- afterItem,
159
- beforeItem,
160
- dataTour,
161
- dividerDirection,
162
- dividerFill,
163
- dividerSize,
164
- dividerWidth,
165
- fieldClassName,
166
- helpText,
167
- helpTextColor,
168
- helpTextSize,
169
- helpTextSizeMobile,
170
- helpTextWeight,
171
- inputName,
172
- inputValue,
173
- messageTextSize,
174
- metaActive,
175
- showDivider,
176
- showMessage,
177
- tag: Tag = 'div',
178
- before,
179
- after,
180
- isHidden,
181
- isRequired,
182
- isValidState,
183
- children
184
- } = props;
185
- const formFieldClass = useMemo(() => clsx(className, isValidState && 'form__item_state_success', isRequired && 'form__item_state_required', isDisabled && 'form__item_state_disabled', metaActive && 'form__item_state_focus', inputValue && 'form__item_state_filled', isErrorState && `form__item_state_${errorKey}`), [className, isErrorState, isValidState, isRequired, metaActive, inputValue, isDisabled, metaError]);
186
- const fieldClass = useMemo(() => clsx(fieldClassName, isValidState && `${fieldClassName}_state_success`, metaActive && `${fieldClassName}_state_focus`, inputValue && `${fieldClassName}_state_filled`, isDisabled && `${fieldClassName}_state_disabled`, isErrorState && `${fieldClassName}_state_${errorKey}`), [fieldClassName, isErrorState, isValidState, metaActive, inputValue, isDisabled, metaError]);
187
- const sizeClass = useDeviceTargetClass(props, {
188
- prefix: 'form-field_size_',
189
- propsKey: 'size'
190
- });
191
- const fillClass = useDeviceTargetClass(props, {
192
- prefix: 'fill_',
193
- propsKey: 'fill'
194
- });
195
- const inputFillClass = useDeviceTargetClass(props, {
196
- prefix: 'fill_',
197
- propsKey: 'inputFill'
198
- });
199
- const shapeClass = useDeviceTargetClass(props, {
200
- prefix: 'form-field_shape_',
201
- propsKey: 'shape'
202
- });
203
- const inputShapeClass = useDeviceTargetClass(props, {
204
- prefix: 'form-field__item-value_shape_',
205
- propsKey: 'inputShape'
206
- });
207
- const directionClass = useDeviceTargetClass(props, {
208
- prefix: 'direction_',
209
- propsKey: 'direction'
210
- });
211
- const widthClass = useDeviceTargetClass(props, {
212
- prefix: 'width_',
213
- propsKey: 'width'
214
- });
215
- const {
216
- styles: formFieldStyles
217
- } = useStyles(props);
218
- const errorTextSize = props[`${errorKey}MessageTextSize`];
219
- const errorTextColor = props[`${errorKey}MessageTextColor`];
220
- const errorTextWeight = props[`${errorKey}MessageTextWeight`];
221
- return /*#__PURE__*/React$1.createElement(Tag, {
222
- className: clsx(formFieldClass, 'form__item', 'form-field', type && `form-field_type_${type}`, sizeClass, fillClass, shapeClass, isDisabled && `form-field_state_disabled`, isHidden && `form-field_state_hidden`, directionClass, widthClass),
223
- "data-test-id": `${inputName}Field`,
224
- "data-tour": dataTour,
225
- style: formFieldStyles
226
- }, before, (label || labelHidden) && /*#__PURE__*/React$1.createElement("div", {
227
- className: clsx('form-field__label'),
228
- "data-test-id": `${inputName}FieldLabel`,
229
- htmlFor: id
230
- }, /*#__PURE__*/React$1.createElement(Text, {
231
- size: labelTextSize,
232
- textColor: labelTextColor,
233
- textWeight: labelTextWeight,
234
- sizeMobile: labelTextSizeMobile,
235
- sizeTablet: labelTextSizeTablet
236
- }, label, labelHidden && '\u00A0')), desc && /*#__PURE__*/React$1.createElement("div", {
237
- className: "form-field__desc",
238
- "data-test-id": `${inputName}FieldDesc`
239
- }, /*#__PURE__*/React$1.createElement(Text, {
240
- size: descTextSize,
241
- textColor: descTextColor,
242
- textWeight: descTextWeight
243
- }, desc)), /*#__PURE__*/React$1.createElement("div", {
244
- className: clsx('form-field__content', inputFillClass, inputShapeClass)
245
- }, /*#__PURE__*/React$1.createElement("div", {
246
- className: clsx('form-field__content-inner', fieldClass)
247
- }, beforeItem, children, afterItem), showDivider && /*#__PURE__*/React$1.createElement(Divider, {
248
- className: "form-field__item-divider",
249
- width: dividerWidth,
250
- direction: dividerDirection,
251
- size: dividerSize,
252
- fill: dividerFill
253
- })), showMessage && /*#__PURE__*/React$1.createElement("div", {
254
- className: "form-field__message",
255
- "data-test-id": `${inputName}FieldMessage`
256
- }, isErrorState && errorMessage && /*#__PURE__*/React$1.createElement(Text, {
257
- id: `${inputName}-error`,
258
- className: "form-field__message-item form-field__message-item_type-error",
259
- size: errorTextSize,
260
- textColor: errorTextColor,
261
- textWeight: errorTextWeight,
262
- dataTestId: `${inputName}FieldMessageError`
263
- }, errorMessage), Boolean(helpText) && (!isErrorState || !errorMessage) && /*#__PURE__*/React$1.createElement(Text, {
264
- className: "form-field__message-item form-field__message-item_type_help-text",
265
- size: helpTextSize,
266
- textColor: isValidState ? helpTextColorSuccess : helpTextColor,
267
- textWeight: helpTextWeight,
268
- dataTestId: `${inputName}FieldMessageHelpText`,
269
- sizeMobile: helpTextSizeMobile
270
- }, helpText), (!isErrorState && !helpText || isErrorState && !helpText && !errorMessage) && /*#__PURE__*/React$1.createElement(Text, {
271
- className: "form-field__message-item form-field__message-item_type_help-text",
272
- size: messageTextSize,
273
- dataTestId: `${inputName}FieldMessageHelpText`
274
- }, '\u00A0')), after);
275
- }
276
- function FieldWrapper(props) {
277
- const {
278
- inputName
279
- } = props;
280
- const {
281
- change
282
- } = useForm(); // , mutators
283
-
284
- useEffect(() => {
285
- return () => {
286
- change(inputName, undefined);
287
- };
288
- }, []);
289
- return /*#__PURE__*/React$1.createElement(FieldWrapperBase, props);
290
- }
291
-
292
- // Whether to display an error message based on "fieldProps" and meta-objects
293
- function useFieldValidationState(props) {
294
- const {
295
- fieldProps = {},
296
- meta = {},
297
- input = {}
298
- } = props;
299
- // Determines if there's a submission error that hasn't been rectified since the last submission.
300
- const submitError = !meta.modifiedSinceLastSubmit && meta.submitError;
301
-
302
- // Determines a key for the error, defaulting to 'error' if no specific key is found.
303
- const errorKey = meta.error?.key || 'error';
304
- const successKey = 'success';
305
-
306
- // Determines if the field is in an error state based on various conditions.
307
- const isErrorState = useMemo(() => {
308
- if (fieldProps.showErrorsOnSubmit) {
309
- return Boolean(meta.submitFailed && meta.touched && (meta.error || submitError));
310
- } else {
311
- return Boolean(meta.touched && (meta.error || submitError));
312
- }
313
- }, [fieldProps.showErrorsOnSubmit, meta.submitFailed, meta.touched, meta.error, submitError]);
314
-
315
- // Determines if the field's input state is valid
316
- const isValidState = useMemo(() => {
317
- const hasValue = Array.isArray(input?.value) ? input?.value.length : input?.value;
318
- const isModifiedAfterSubmit = meta.modifiedSinceLastSubmit && !meta.error && submitError;
319
- return Boolean(hasValue && (meta.valid || isModifiedAfterSubmit));
320
- }, [input?.value, meta.valid, meta.error, submitError, meta.modifiedSinceLastSubmit]);
321
- const errorMessage = useMemo(() => {
322
- // If final-form field has error in "meta" render-property.
323
- // If field not modified after last form submit - use submit error
324
- const error = meta.error || submitError || false;
325
- if (error) {
326
- // And error in "meta" is string
327
- if (typeof error === 'string') {
328
- // Return error as message
329
- return error;
330
- }
331
- // Or if error in "meta" has "message" property(is object of error)
332
- if (error.message) {
333
- // Return message from error
334
- return error.message;
335
- }
336
- }
337
-
338
- // Field doesn't have error message
339
- return '';
340
- }, [meta.error, submitError]);
341
- return {
342
- errorKey,
343
- successKey,
344
- isErrorState,
345
- isValidState,
346
- errorMessage
347
- };
348
- }
349
-
350
- // This hook changes the props of the child component depending on the type of error,
351
- // looks at what props were in initialProps, if they are there then changes
352
- function useValidationAppearanceInputProps(props) {
353
- const {
354
- validationStateKey,
355
- inputProps
356
- } = props;
357
-
358
- // TODO: need to add props that can change during errors in this field
359
- const validationAppearanceInputProps = useMemo(() => {
360
- // const resultAppearanceProps = {
361
- // messageTextColor: props.errorMessageTextColor,
362
- // messageTextSize: props.errorMessageTextSize,
363
- // messageTextWeight: props.errorMessageTextWeight,
364
- // // Override appearance(styled) props for child input
365
- // inputProps: {},
366
- // }
367
- const updatedInputProps = {};
368
- if (validationStateKey) {
369
- Object.entries(inputProps).forEach(([propKey, propValue]) => {
370
- // Convert the input property key to "snake_case" format.
371
- // e.g. "requiredBorderColor" -> "required_border_color".
372
- const propKeySnake = snakeCase(propKey);
373
- // Check if this property is for appearance.
374
- // Key maybe starts with: "error", "required", "success", etc from validation config.
375
- const isPropForValidationState = propKeySnake.startsWith(`${validationStateKey}_`);
376
-
377
- // If property is for appearance
378
- if (isPropForValidationState) {
379
- // Remove validation state part from begin of property key, to make clean appearance property.
380
- // e.g. "required_border_color" -> "border_color".
381
- const stateTargetKeySnake = propKeySnake.replace(`${validationStateKey}_`, '');
382
- // Convert clean appearance property key to "camelCase" format.
383
- // e.g. "border_color" -> "borderColor"
384
- const stateTargetKey = camelCase(stateTargetKeySnake);
385
- // And save the value with a new clean property key
386
- updatedInputProps[stateTargetKey] = propValue;
387
- // Else if not already added earlier
388
- } else if (!updatedInputProps[propKey]) {
389
- // Just save original property
390
- updatedInputProps[propKey] = propValue;
391
- }
392
- });
393
- }
394
- return updatedInputProps;
395
- }, [validationStateKey, inputProps]);
396
- return validationAppearanceInputProps;
397
- }
398
-
399
- const defaultCheckboxProps = {
400
- appearance: 'defaultPrimary',
401
- width: 'fill',
402
- errorBorderColor: 'errorBorderSecondary',
403
- requiredBorderColor: 'warningBorderSecondary'
404
- };
405
-
406
- const CheckboxField = /*#__PURE__*/React$1.memo(function CheckboxField(props) {
407
- const {
408
- name,
409
- initialValue,
410
- isDisabled,
411
- classNameGroupItem,
412
- fieldProps = {},
413
- inputProps = {},
414
- showMessage,
415
- isRequired,
416
- onChange
417
- } = props;
418
- return /*#__PURE__*/React$1.createElement(Field, {
419
- type: "checkbox",
420
- name: name,
421
- initialValue: initialValue
422
- }, function Render({
423
- input,
424
- meta
425
- }) {
426
- /** Note:
427
- * Create "Render" function by "eslint-react-hooks/rules-of-hooks":
428
- * React Hooks cannot be called inside a callback.
429
- * React Hooks must be called in a React function component or a
430
- * custom React Hook function.
431
- */
432
-
433
- const onChangeField = useCallback(event => {
434
- input.onChange(event);
435
- if (onChange) {
436
- onChange(event.target.checked, input.name);
437
- }
438
- }, [onChange, input.onChange]);
439
- const {
440
- errorKey,
441
- errorMessage,
442
- isErrorState,
443
- isValidState
444
- } = useFieldValidationState({
445
- fieldProps: fieldProps,
446
- input: input,
447
- meta: meta
448
- });
449
- const updatedInputProps = useValidationAppearanceInputProps({
450
- inputProps: inputProps,
451
- validationStateKey: isErrorState ? errorKey : 'success'
452
- });
453
- return /*#__PURE__*/React$1.createElement(FieldWrapper, Object.assign({
454
- className: clsx('form-field_type_checkbox', 'form__item_type_checkbox', classNameGroupItem),
455
- errorKey: errorKey,
456
- errorMessage: errorMessage,
457
- isErrorState: isErrorState,
458
- metaError: meta.error,
459
- isDisabled: isDisabled,
460
- fieldClassName: "form-checkbox",
461
- inputName: input.name,
462
- inputValue: input.checked,
463
- metaActive: meta.active,
464
- showMessage: showMessage,
465
- tag: "label",
466
- isRequired: isRequired,
467
- isValidState: isValidState
468
- }, fieldProps), /*#__PURE__*/React$1.createElement(Checkbox, Object.assign({
469
- type: "checkbox",
470
- name: input.name,
471
- isDisabled: isDisabled,
472
- autoComplete: "nope",
473
- checked: input.checked,
474
- onBlur: input.onBlur,
475
- onChange: onChangeField,
476
- onFocus: input.onFocus
477
- }, updatedInputProps)));
478
- });
479
- });
480
-
481
- const defaultChoiceProps = {
482
- width: 'fill',
483
- borderColor: 'surfaceBorderTertiary',
484
- // error
485
- errorBorderColor: 'errorBorderPrimary',
486
- fill: 'surfaceSecondary',
487
- fillActive: 'accentPrimary',
488
- fillActiveDisabled: 'surfaceTertiary',
489
- fillHover: 'surfacePrimaryHover',
490
- indicatorFill: 'accentPrimary',
491
- labelTextActiveColor: 'accentTextPrimary',
492
- labelTextActiveColorDisabled: 'surfaceTextDisabled',
493
- labelTextColor: 'surfaceTextPrimary',
494
- labelTextColorDisabled: 'surfaceTextDisabled',
495
- labelTextSize: 'm',
496
- requiredBorderColor: 'warningBorderPrimary',
497
- shape: 'rounded'
498
- };
499
-
500
- const ChoiceField = /*#__PURE__*/React$1.memo(function ChoiceField(props) {
501
- const {
502
- name,
503
- initialValue,
504
- label,
505
- isDisabled,
506
- classNameGroupItem,
507
- fieldProps,
508
- inputProps,
509
- messageType,
510
- options,
511
- placeholder,
512
- showMessage,
513
- isCheckbox,
514
- isRequired,
515
- onChange
516
- } = props;
517
- const {
518
- change
519
- } = useForm();
520
- const setActiveSegment = useCallback((option, isChecked) => {
521
- change(name, isChecked && option.value);
522
- if (onChange) {
523
- onChange(option.value, name, isChecked);
524
- }
525
- }, [change, onChange]);
526
- return /*#__PURE__*/React$1.createElement(Field, {
527
- initialValue: initialValue,
528
- name: name
529
- }, function Render({
530
- input,
531
- meta
532
- }) {
533
- /** Note:
534
- * Create "Render" function by "eslint-react-hooks/rules-of-hooks":
535
- * React Hooks cannot be called inside a callback.
536
- * React Hooks must be called in a React function component or a
537
- * custom React Hook function.
538
- */
539
- const activeOption = useMemo(() => {
540
- const emptyOption = {
541
- value: null,
542
- label: null
543
- };
544
- if (input.value) {
545
- const currentOption = options.find(option => option.value === input.value);
546
- return currentOption || emptyOption;
547
- }
548
- return emptyOption;
549
- }, [input.value]);
550
- const {
551
- isErrorState,
552
- isValidState,
553
- errorKey,
554
- errorMessage
555
- } = useFieldValidationState({
556
- fieldProps: fieldProps,
557
- input: input,
558
- meta: meta
559
- });
560
- const updatedInputProps = useValidationAppearanceInputProps({
561
- inputProps: inputProps,
562
- validationStateKey: isErrorState ? errorKey : 'success'
563
- });
564
- return /*#__PURE__*/React$1.createElement(FieldWrapper, Object.assign({
565
- className: clsx('form-field_type_choice', 'form__item_type_choice', classNameGroupItem),
566
- label: label,
567
- errorKey: errorKey,
568
- errorMessage: errorMessage,
569
- isErrorState: isErrorState,
570
- metaError: meta.error,
571
- isDisabled: isDisabled,
572
- fieldClassName: "form-choice",
573
- inputName: input.name,
574
- inputValue: input.value || [],
575
- messageType: messageType,
576
- metaActive: meta.active,
577
- showMessage: showMessage,
578
- isRequired: isRequired,
579
- isValidState: isValidState
580
- }, fieldProps), /*#__PURE__*/React$1.createElement(Choice, Object.assign({
581
- className: clsx(meta.active && 'form-choice_state_focus', meta.error && meta.touched && `form-choice_state_${errorKey}`),
582
- name: input.name,
583
- isDisabled: isDisabled,
584
- active: activeOption,
585
- inputValue: input.value || [],
586
- options: options,
587
- placeholder: placeholder,
588
- isCheckbox: isCheckbox,
589
- isRequired: isRequired,
590
- setActiveSegment: setActiveSegment
591
- }, updatedInputProps)));
592
- });
593
- });
594
-
595
- const CustomField = /*#__PURE__*/React$1.memo(function CustomField(props) {
596
- const {
597
- Component,
598
- isDisabled,
599
- isRequired,
600
- name,
601
- initialValue,
602
- fieldProps = {},
603
- classNameGroupItem,
604
- showMessage,
605
- clearIcon,
606
- clearIconFill,
607
- clearIconFillHover,
608
- clearIconShape,
609
- clearIconSize,
610
- onClickClearIcon
611
- } = props;
612
- return /*#__PURE__*/React$1.createElement(Field, {
613
- initialValue: initialValue,
614
- name: name
615
- }, function Render({
616
- input,
617
- meta
618
- }) {
619
- /** Note:
620
- * Create "Render" function by "eslint-react-hooks/rules-of-hooks":
621
- * React Hooks cannot be called inside a callback.
622
- * React Hooks must be called in a React function component or a
623
- * custom React Hook function.
624
- */
625
-
626
- const {
627
- isErrorState,
628
- isValidState,
629
- errorKey,
630
- errorMessage
631
- } = useFieldValidationState({
632
- fieldProps: fieldProps,
633
- input: input,
634
- meta: meta
635
- });
636
- const updatedInputProps = useValidationAppearanceInputProps({
637
- validationStateKey: isErrorState ? errorKey : 'success',
638
- // For "Custom" field we pass all props. Can contain some special props, we don't known.
639
- inputProps: props
640
- });
641
- return /*#__PURE__*/React$1.createElement(FieldWrapper, Object.assign({
642
- className: clsx('form-field_type_custom', 'form__item_type_custom', classNameGroupItem),
643
- errorKey: errorKey,
644
- errorMessage: errorMessage,
645
- fieldClassName: 'form-custom',
646
- inputName: input.name,
647
- inputValue: input.value,
648
- isDisabled: isDisabled,
649
- isErrorState: isErrorState,
650
- isRequired: isRequired,
651
- isValidState: isValidState,
652
- metaActive: meta.active,
653
- metaError: meta.error,
654
- showMessage: showMessage
655
- }, fieldProps), /*#__PURE__*/React$1.createElement(Component, Object.assign({}, updatedInputProps, {
656
- input: input,
657
- isDisabled: isDisabled,
658
- meta: meta
659
- })), clearIcon && /*#__PURE__*/React$1.createElement(Icon, {
660
- className: "form-field__icon",
661
- iconFill: clearIconFill,
662
- iconFillHover: clearIconFillHover,
663
- imageSrc: clearIcon,
664
- shape: clearIconShape,
665
- size: clearIconSize,
666
- SvgImage: clearIcon,
667
- onClick: onClickClearIcon
668
- }));
669
- });
670
- });
671
-
672
- const defaultCodeProps = {
673
- fieldProps: {
674
- size: 'l',
675
- labelTextColor: 'surfaceTextPrimary',
676
- labelTextSize: 's',
677
- labelTextWeight: 'normal',
678
- helpText: 'Supporting text',
679
- helpTextColor: 'surfaceTextPrimary',
680
- helpTextSize: 's',
681
- helpTextWeight: 'normal',
682
- showMessage: true
683
- },
684
- inputProps: {
685
- width: 'fill',
686
- size: 'l',
687
- fill: 'surfaceSecondary',
688
- inputBorderColor: 'surfaceBorderTertiary',
689
- inputBorderColorHover: 'surfaceBorderQuaternary',
690
- inputBorderFocusColor: 'surfaceBorderAccent',
691
- inputCaretColor: 'surfaceItemAccent',
692
- inputFill: 'surfacePrimary',
693
- inputFillHover: 'surfaceSecondary',
694
- inputPlaceholderTextColor: 'surfaceSecondary',
695
- inputSize: 'l',
696
- inputTextColor: 'surfaceSecondary',
697
- inputTextSize: 'xxl',
698
- inputTextWeight: 'normal'
699
- }
700
- };
701
-
702
- const CodeField = /*#__PURE__*/React$1.memo(function CodeField(props) {
703
- const {
704
- name,
705
- initialValue,
706
- isDisabled,
707
- classNameGroupItem,
708
- fieldProps = {},
709
- inputProps = {},
710
- showMessage,
711
- isRequired
712
- } = props;
713
- return /*#__PURE__*/React$1.createElement(Field, {
714
- name: name,
715
- initialValue: initialValue
716
- }, function Render({
717
- input,
718
- meta
719
- }) {
720
- /** Note:
721
- * Create "Render" function by "eslint-react-hooks/rules-of-hooks":
722
- * React Hooks cannot be called inside a callback.
723
- * React Hooks must be called in a React function component or a
724
- * custom React Hook function.
725
- */
726
-
727
- const {
728
- isErrorState,
729
- isValidState,
730
- errorKey} = useFieldValidationState({
731
- fieldProps: fieldProps,
732
- input: input,
733
- meta: meta
734
- });
735
- const updatedInputProps = useValidationAppearanceInputProps({
736
- inputProps: inputProps,
737
- validationStateKey: isErrorState ? errorKey : 'success'
738
- });
739
- return /*#__PURE__*/React$1.createElement(FieldWrapper, Object.assign({
740
- className: clsx('form-field_type_code', 'form__item_type_code', classNameGroupItem),
741
- fieldClassName: 'form-code',
742
- inputName: input.name,
743
- inputValue: input.value,
744
- metaActive: meta.active,
745
- showMessage: showMessage,
746
- isRequired: isRequired,
747
- isValidState: isValidState
748
- }, fieldProps), /*#__PURE__*/React$1.createElement(Code, Object.assign({
749
- name: input.name,
750
- isDisabled: isDisabled,
751
- autoComplete: "nope",
752
- value: input.value,
753
- onBlur: input.onBlur,
754
- onChange: input.onChange,
755
- onFocus: input.onFocus
756
- }, updatedInputProps)));
757
- });
758
- });
759
-
760
- const defaultDatepickerProps = {
761
- dateFormat: 'dd/MM/yyyy - HH:mm',
762
- readOnly: false,
763
- selectsRange: false,
764
- showTimeSelect: true,
765
- timeCaption: 'Время',
766
- timeFormat: 'p',
767
- timeIntervals: 60,
768
- isClearable: true,
769
- isStartDefaultNull: true
770
- };
771
-
772
- function DatePickerField(props) {
773
- const {
774
- name,
775
- isDisabled,
776
- classNameGroupItem,
777
- datePickerProps,
778
- fieldProps = {},
779
- inputProps = {},
780
- showMessage,
781
- isRequired,
782
- onChange
783
- } = props;
784
- return /*#__PURE__*/React$1.createElement(Field, {
785
- name: name
786
- }, function Render({
787
- input,
788
- meta
789
- }) {
790
- /** Note:
791
- * Create "Render" function by "eslint-react-hooks/rules-of-hooks":
792
- * React Hooks cannot be called inside a callback.
793
- * React Hooks must be called in a React function component or a
794
- * custom React Hook function.
795
- */
796
-
797
- const onChangeField = useCallback((startDate, endDate) => {
798
- if (!datePickerProps.selectsRange) {
799
- // When we need to save single date, value is date
800
- // TODO: make object with one date? need to check all forms with DatePickerField
801
- input.onChange(startDate);
802
- } else {
803
- // When we need to save range, value is object with two date
804
- input.onChange({
805
- endDate,
806
- startDate
807
- });
808
- }
809
- if (onChange) {
810
- onChange(startDate, endDate);
811
- }
812
- }, [input.onChange, onChange]);
813
- const {
814
- errorKey,
815
- errorMessage,
816
- isErrorState,
817
- isValidState
818
- } = useFieldValidationState({
819
- fieldProps: fieldProps,
820
- input: input,
821
- meta: meta
822
- });
823
- const updatedInputProps = useValidationAppearanceInputProps({
824
- inputProps: inputProps,
825
- validationStateKey: isErrorState ? errorKey : 'success'
826
- });
827
- return /*#__PURE__*/React$1.createElement(FieldWrapper, Object.assign({
828
- className: clsx('form-field_type_datepicker', 'form__item_type_datepicker', classNameGroupItem),
829
- errorKey: errorKey,
830
- errorMessage: errorMessage,
831
- isErrorState: isErrorState,
832
- metaError: meta.error,
833
- isDisabled: isDisabled,
834
- fieldClassName: "form-datepicker",
835
- inputName: input.name,
836
- inputValue: input.value || '',
837
- metaActive: meta.active,
838
- showMessage: showMessage,
839
- isRequired: isRequired,
840
- isValidState: isValidState
841
- }, fieldProps), /*#__PURE__*/React$1.createElement(DatePickerInput, {
842
- name: input.name,
843
- isDisabled: isDisabled,
844
- datePickerProps: datePickerProps,
845
- endValue: datePickerProps.selectsRange ? input.value.endDate : null,
846
- inputProps: updatedInputProps,
847
- value: datePickerProps.selectsRange ? input.value.startDate : input.value,
848
- onBlur: input.onBlur,
849
- onChange: onChangeField,
850
- onFocus: input.onFocus
851
- }));
852
- });
853
- }
854
-
855
- const defaultDropzoneProps = {
856
- fill: 'surfacePrimary',
857
- borderColor: 'surfaceBorderTertiary',
858
- borderColorHover: 'surfaceBorderQuaternary',
859
- hintTitle: 'Перетащите изображение или выберите файл с компьютера',
860
- hintTitleTextColor: 'surfaceTextPrimary',
861
- hintTitleTextSize: 'm',
862
- removeThumbText: 'удалить',
863
- removeThumbTextColor: 'errorTextPrimary',
864
- removeThumbTextHoverColor: 'errorTextPrimaryHover',
865
- removeThumbTextSize: 's',
866
- shape: 'rounded',
867
- showFilename: true,
868
- thumbBorderColor: 'surfaceBorderTertiary',
869
- thumbBorderColorHover: 'surfaceBorderQuaternary',
870
- thumbBorderWidth: 1,
871
- thumbNameTextColor: 'surfaceTextPrimary',
872
- thumbNameTextSize: 's',
873
- isPreviews: true
874
- };
875
-
876
- const FileInputDropzone = /*#__PURE__*/React$1.memo(function FileInputDropzone(props) {
877
- const {
878
- className,
879
- maxFiles,
880
- maxSize,
881
- size,
882
- fileErrorText,
883
- dropzoneProps = {},
884
- hintDescription,
885
- hintTitle,
886
- inputName,
887
- inputValue,
888
- showFilename,
889
- thumbColumn,
890
- isPreviews,
891
- onAddFiles,
892
- onDeleteFile
893
- } = props;
894
-
895
- // TODO: delete react-final-form things out of here?
896
- const {
897
- change
898
- } = useForm();
899
- const [fileError, setFileError] = useState('');
900
- const [fileIsLoading, setFileIsLoading] = useState(false);
901
- const filesList = useMemo(() => inputValue ? castArray(inputValue) : [], [inputValue]);
902
- const changeFormState = useCallback(newFiles => {
903
- // If max files in dropzone is 1 - return file as it self, else as array of files
904
- // ps: for old projects compatibility
905
- const toSave = dropzoneProps.maxFiles == 1 ? newFiles[0] : newFiles;
906
- change(inputName, toSave);
907
- return toSave;
908
- },
909
- // If "inputName" will be changes, then it should be a different field
910
- // eslint-disable-next-line react-hooks/exhaustive-deps
911
- [dropzoneProps, change]);
912
-
913
- //
914
- const convertFiledValueAndSaveAsFiles = useCallback(async currentFilesList => {
915
- setFileIsLoading(true);
916
- const newFiles = [];
917
- for (const fileItem of currentFilesList) {
918
- if (typeof fileItem === 'string') {
919
- const newFile = await convertToFile(fileItem, isPreviews);
920
- if (newFile) {
921
- newFiles.push(newFile);
922
- }
923
- } else {
924
- newFiles.push(fileItem);
925
- }
926
- }
927
- changeFormState(newFiles);
928
- setFileIsLoading(false);
929
- }, [isPreviews, changeFormState]);
930
-
931
- // Delete file from dropzone
932
- const removeFile = useCallback((event, index) => {
933
- event.stopPropagation();
934
- event.preventDefault();
935
- const newFiles = [...filesList];
936
- newFiles.splice(index, 1);
937
- if (onDeleteFile) {
938
- onDeleteFile(filesList[index], inputName);
939
- }
940
- changeFormState(newFiles);
941
- },
942
- // If "inputName" will be changes, then it should be a different field
943
- // eslint-disable-next-line react-hooks/exhaustive-deps
944
- [filesList, changeFormState, onDeleteFile]);
945
-
946
- // Create dropzone options
947
- const {
948
- getInputProps,
949
- getRootProps
950
- } = useDropzone({
951
- maxFiles: maxFiles || 5,
952
- maxSize: maxSize || 10485760,
953
- // 10mb
954
- // accept: { 'image/*': [] },
955
- ...dropzoneProps,
956
- getFilesFromEvent: async event => {
957
- const result = await fromEvent(event);
958
- const newFiles = result.filter(item => item instanceof File);
959
- // Add exists and new files to accepted(or rejected)
960
- return [...filesList, ...newFiles];
961
- },
962
- onDropAccepted: acceptedFiles => {
963
- // If dropped files has accepted and we need a previews
964
- if (isPreviews) {
965
- // Add preview to every file
966
- acceptedFiles.forEach(file => {
967
- if (!file.error) {
968
- file.preview = URL.createObjectURL(file);
969
- }
970
- });
971
- }
972
- // Save to form data (including empty when files are not valid)
973
- const filesToSave = changeFormState(acceptedFiles);
974
- setFileError('');
975
-
976
- // Save DataURL for all files
977
- const readerPromisesList = acceptedFiles.map(file => {
978
- return new Promise(resolve => setFileDataURL(file, resolve));
979
- });
980
- // Save files to form values
981
- Promise.all(readerPromisesList).then(() => {
982
- if (onAddFiles) {
983
- onAddFiles(filesToSave, inputName);
984
- }
985
- });
986
- },
987
- onDropRejected: rejectedFiles => {
988
- // If dropped files has rejected
989
- if (rejectedFiles.length) {
990
- let fileErrorMessage = 'Ошибка при добавлении файла';
991
- const firstFileErrorItem = rejectedFiles[0].errors[0];
992
- if (firstFileErrorItem) {
993
- if (firstFileErrorItem.code === ErrorCode.TooManyFiles) {
994
- fileErrorMessage = `Максимальное количество файлов: ${maxFiles}`;
995
- } else {
996
- fileErrorMessage = firstFileErrorItem.message;
997
- }
998
- }
999
- // Show error
1000
- setFileError(fileErrorMessage);
1001
- } else {
1002
- // Else clean error
1003
- setFileError('');
1004
- }
1005
- }
1006
- });
1007
- useEffect(() => {
1008
- const currentFilesList = castArray(inputValue);
1009
- const isNeedToConvert = currentFilesList.some(fileItem => typeof fileItem === 'string');
1010
- if (isNeedToConvert) {
1011
- // First time convert value to Files and save to local and form state
1012
- convertFiledValueAndSaveAsFiles(currentFilesList);
1013
- }
1014
-
1015
- // Make sure to revoke the data uris to avoid memory leaks, will run on unmount
1016
- return () => {
1017
- filesList.forEach(file => {
1018
- if (file?.preview) {
1019
- URL.revokeObjectURL(file.preview);
1020
- }
1021
- });
1022
- };
1023
- // eslint-disable-next-line react-hooks/exhaustive-deps
1024
- }, [inputValue]);
1025
- const propsGenerator = useDevicePropsGenerator(props);
1026
- const {
1027
- fillClass,
1028
- fillHoverClass,
1029
- borderColorClass,
1030
- borderColorHoverClass,
1031
- borderTypeClass,
1032
- borderWidthClass,
1033
- errorMessageTextColor,
1034
- errorMessageTextSize,
1035
- errorMessageTextWeight,
1036
- hintDescriptionTextColor,
1037
- hintDescriptionTextSize,
1038
- hintDescriptionTextWeight,
1039
- hintDescriptionTextWrap,
1040
- hintTitleTextColor,
1041
- hintTitleTextSize,
1042
- hintTitleTextWeight,
1043
- hintTitleTextWrap,
1044
- removeThumbText,
1045
- removeThumbTextColor,
1046
- removeThumbTextHoverColor,
1047
- removeThumbTextSize,
1048
- removeThumbTextWeight,
1049
- shapeClass,
1050
- thumbBorderColorClass,
1051
- thumbBorderColorHoverClass,
1052
- thumbBorderTypeClass,
1053
- thumbBorderWidthClass,
1054
- thumbDirectionClass,
1055
- thumbNameTextColor,
1056
- thumbNameTextSize,
1057
- thumbNameTextWeight,
1058
- thumbNameTextWrap
1059
- } = propsGenerator;
1060
- return /*#__PURE__*/React$1.createElement(React$1.Fragment, null, /*#__PURE__*/React$1.createElement("div", getRootProps({
1061
- className: `form-dropzone__dropzone dropzone ${className} thumbColumn form-dropzone__dropzone_size_${size} ${shapeClass}`
1062
- }), /*#__PURE__*/React$1.createElement("input", Object.assign({}, getInputProps(), {
1063
- name: inputName
1064
- })), /*#__PURE__*/React$1.createElement("div", {
1065
- className: clsx('form-dropzone__dropzone-wrapper', thumbColumn && `form-dropzone__dropzone-wrapper_column_${thumbColumn}`, fillClass, fillHoverClass, borderWidthClass, borderColorClass, borderColorHoverClass, borderTypeClass)
1066
- }, filesList.map((file, index) => /*#__PURE__*/React$1.createElement("aside", {
1067
- className: clsx('form-dropzone__thumb', fillClass, thumbDirectionClass, thumbBorderWidthClass, thumbBorderColorClass, thumbBorderColorHoverClass, thumbBorderTypeClass),
1068
- key: file.id || `${file.name}_${index}`
1069
- }, isPreviews && !file.error && /*#__PURE__*/React$1.createElement("div", {
1070
- className: "form-dropzone__thumb-image"
1071
- }, /*#__PURE__*/React$1.createElement("img", {
1072
- className: "form-dropzone__thumb-image-inner",
1073
- src: file.preview || file.image,
1074
- onLoad: () => {
1075
- // Revoke data uri after image is loaded
1076
- URL.revokeObjectURL(file.preview);
1077
- }
1078
- })), file.error && /*#__PURE__*/React$1.createElement("div", null, /*#__PURE__*/React$1.createElement(Text, {
1079
- size: thumbNameTextSize,
1080
- textColor: thumbNameTextColor,
1081
- textWeight: thumbNameTextWeight,
1082
- textWrap: thumbNameTextWrap
1083
- }, fileErrorText || file.error)), showFilename && /*#__PURE__*/React$1.createElement("div", {
1084
- className: "form-dropzone__thumb-name"
1085
- }, /*#__PURE__*/React$1.createElement(Text, {
1086
- className: "form-dropzone__thumb-name-inner",
1087
- size: thumbNameTextSize,
1088
- textColor: thumbNameTextColor,
1089
- textWeight: thumbNameTextWeight,
1090
- textWrap: thumbNameTextWrap
1091
- }, file.name)), fileIsLoading && /*#__PURE__*/React$1.createElement("div", {
1092
- className: "form-dropzone__thumb-loader"
1093
- }, /*#__PURE__*/React$1.createElement(Loader, {
1094
- width: "fill",
1095
- height: "fill",
1096
- fill: "surfacePrimary",
1097
- itemFill: "surfaceItemAccent",
1098
- set: "simple"
1099
- })), /*#__PURE__*/React$1.createElement("div", {
1100
- className: "form-dropzone__thumb-remove",
1101
- onClick: event => removeFile(event, index)
1102
- }, /*#__PURE__*/React$1.createElement(Text, {
1103
- className: "form-dropzone__thumb-remove-text",
1104
- size: removeThumbTextSize,
1105
- textColor: removeThumbTextColor,
1106
- textColorHover: removeThumbTextHoverColor,
1107
- textWeight: removeThumbTextWeight
1108
- }, removeThumbText || 'Удалить')))), !filesList.length ? /*#__PURE__*/React$1.createElement("div", {
1109
- className: "form-dropzone__hint"
1110
- }, /*#__PURE__*/React$1.createElement(Text, {
1111
- className: "form-dropzone__hint-title",
1112
- size: hintTitleTextSize,
1113
- textColor: hintTitleTextColor,
1114
- textWeight: hintTitleTextWeight,
1115
- textWrap: hintTitleTextWrap
1116
- }, hintTitle || 'Select a file or drag in form'), /*#__PURE__*/React$1.createElement(Text, {
1117
- className: "form-dropzone__hint-text",
1118
- size: hintDescriptionTextSize,
1119
- textColor: hintDescriptionTextColor,
1120
- textWeight: hintDescriptionTextWeight,
1121
- textWrap: hintDescriptionTextWrap
1122
- }, hintDescription)) : /*#__PURE__*/React$1.createElement("div", {
1123
- className: "form-dropzone__hint form-dropzone__hint_type_add-more"
1124
- }, /*#__PURE__*/React$1.createElement(Text, {
1125
- className: "form-dropzone__hint-title",
1126
- size: hintTitleTextSize,
1127
- textColor: hintTitleTextColor,
1128
- textWeight: hintTitleTextWeight,
1129
- textWrap: hintTitleTextWrap
1130
- }, hintTitle || 'Select a file or drag in form'), /*#__PURE__*/React$1.createElement(Text, {
1131
- className: "form-dropzone__hint-text",
1132
- size: hintDescriptionTextSize,
1133
- textColor: hintDescriptionTextColor,
1134
- textWeight: hintDescriptionTextWeight,
1135
- textWrap: hintDescriptionTextWrap
1136
- }, hintDescription)))), fileError && /*#__PURE__*/React$1.createElement("div", {
1137
- className: "form-field__message"
1138
- }, /*#__PURE__*/React$1.createElement(Text, {
1139
- className: "form-field__message-item form-field__message-item_type_message",
1140
- size: errorMessageTextSize,
1141
- textColor: errorMessageTextColor,
1142
- textWeight: errorMessageTextWeight
1143
- }, fileError)));
1144
- });
1145
- async function getFileByURL(url) {
1146
- try {
1147
- const response = await axios({
1148
- url: url,
1149
- responseType: 'blob'
1150
- });
1151
- const blobObject = response.data;
1152
- const dirtyFilename = response.headers['content-disposition']?.split('filename=')[1];
1153
- // Remove double quotes
1154
- let filename = dirtyFilename?.substring(1).slice(0, -1);
1155
- if (!filename) {
1156
- filename = url.split('/').at(-1);
1157
- // const typeParts = blobObject.type.split('/')
1158
- // const fileType = typeParts[typeParts.length - 1]
1159
- // filename = `${new Date().getTime()}.${fileType}`
1160
- }
1161
- return new File([blobObject], filename, {
1162
- type: blobObject.type
1163
- });
1164
- } catch (error) {
1165
- console.log('error: ', error);
1166
- return null;
1167
- }
1168
- }
1169
- async function convertToFile(inputValue, isPreviews) {
1170
- let newFile = null;
1171
-
1172
- // Download image by url and save as File instance
1173
- const isURL = typeof inputValue === 'string' && inputValue.includes('/');
1174
- if (inputValue.image || isURL) {
1175
- newFile = await getFileByURL(inputValue.image || inputValue);
1176
- if (newFile) {
1177
- setFileDataURL(newFile);
1178
- }
1179
- }
1180
-
1181
- // Convert dataURL to File instance
1182
- if (inputValue.dataURL) {
1183
- newFile = createFileFromDataURL(inputValue.name || inputValue.path, inputValue.dataURL);
1184
- newFile.dataURL = inputValue.dataURL;
1185
- }
1186
-
1187
- // Save new File to state
1188
- if (newFile) {
1189
- newFile.id = inputValue.id;
1190
- if (isPreviews) {
1191
- newFile.preview = URL.createObjectURL(newFile);
1192
- }
1193
- }
1194
- return newFile;
1195
- }
1196
- function setFileDataURL(file, resolve) {
1197
- resolve = resolve || (() => {});
1198
- // Init reader and save his file
1199
- const reader = new FileReader();
1200
- reader._readedFile = file;
1201
-
1202
- // Set handlers
1203
- reader.onabort = () => resolve();
1204
- reader.onerror = () => resolve();
1205
- reader.onload = event => {
1206
- event.target._readedFile.dataURL = reader.result;
1207
- resolve();
1208
- };
1209
- // Run reader
1210
- if (file instanceof File) {
1211
- reader.readAsDataURL(file);
1212
- } else {
1213
- resolve();
1214
- }
1215
- }
1216
-
1217
- const FileInput = /*#__PURE__*/React$1.memo(function FileInput(props) {
1218
- const {
1219
- className,
1220
- name,
1221
- width,
1222
- maxFiles,
1223
- maxSize,
1224
- label,
1225
- fileErrorText,
1226
- classNameGroupItem,
1227
- dropzoneProps,
1228
- fieldProps,
1229
- hintDescription,
1230
- hintTitle,
1231
- showFilename,
1232
- showMessage,
1233
- isPreviews,
1234
- isRequired,
1235
- onAddFiles,
1236
- onDeleteFile
1237
- } = props;
1238
- const propsGenerator = useDevicePropsGenerator(props);
1239
- const {
1240
- size,
1241
- fill,
1242
- fillHover,
1243
- labelTextColor,
1244
- borderColorHover,
1245
- borderType,
1246
- borderWidth,
1247
- errorMessageTextColor = 'errorTextPrimary',
1248
- errorMessageTextSize = 's',
1249
- errorMessageTextWeight,
1250
- hintDescriptionTextColor,
1251
- hintDescriptionTextSize,
1252
- hintDescriptionTextWeight,
1253
- hintDescriptionTextWrap,
1254
- hintTitleTextColor,
1255
- hintTitleTextSize,
1256
- hintTitleTextWeight,
1257
- hintTitleTextWrap,
1258
- removeThumbText,
1259
- removeThumbTextColor,
1260
- removeThumbTextHoverColor,
1261
- removeThumbTextSize,
1262
- removeThumbTextWeight,
1263
- shape,
1264
- thumbBorderColor,
1265
- thumbBorderColorHover,
1266
- thumbBorderType,
1267
- thumbBorderWidth,
1268
- thumbColumn = 1,
1269
- thumbDirection = 'vertical',
1270
- thumbNameTextColor,
1271
- thumbNameTextSize,
1272
- thumbNameTextWeight,
1273
- thumbNameTextWrap
1274
- } = propsGenerator;
1275
- return /*#__PURE__*/React$1.createElement(Field, {
1276
- name: name
1277
- }, function Render({
1278
- input,
1279
- meta
1280
- }) {
1281
- /** Note:
1282
- * Create "Render" function by "eslint-react-hooks/rules-of-hooks":
1283
- * React Hooks cannot be called inside a callback.
1284
- * React Hooks must be called in a React function component or a
1285
- * custom React Hook function.
1286
- */
1287
-
1288
- const {
1289
- errorKey,
1290
- errorMessage,
1291
- isErrorState,
1292
- isValidState
1293
- } = useFieldValidationState({
1294
- fieldProps: fieldProps,
1295
- input: input,
1296
- meta: meta
1297
- });
1298
- const updatedInputProps = useValidationAppearanceInputProps({
1299
- inputProps: props,
1300
- validationStateKey: isErrorState ? errorKey : 'success'
1301
- });
1302
-
1303
- /** TODO:
1304
- * REFACTOR PROPERTIES
1305
- */
1306
- return /*#__PURE__*/React$1.createElement(FieldWrapper, Object.assign({
1307
- className: clsx('form-field_type_dropzone', 'form__item_type_dropzone', classNameGroupItem),
1308
- width: width,
1309
- label: label,
1310
- labelTextColor: labelTextColor,
1311
- errorKey: errorKey,
1312
- errorMessage: errorMessage,
1313
- isErrorState: isErrorState,
1314
- metaError: meta.error,
1315
- fieldClassName: "form-dropzone",
1316
- inputName: input.name,
1317
- inputValue: input.value,
1318
- metaActive: meta.active,
1319
- metaTouched: meta.touched,
1320
- showMessage: showMessage,
1321
- isRequired: isRequired,
1322
- isValidState: isValidState
1323
- }, fieldProps), /*#__PURE__*/React$1.createElement(FileInputDropzone, {
1324
- className: className,
1325
- maxFiles: maxFiles,
1326
- maxSize: maxSize,
1327
- size: size,
1328
- fill: fill,
1329
- fillHover: fillHover,
1330
- borderColor: updatedInputProps.borderColor,
1331
- borderColorHover: borderColorHover,
1332
- borderType: borderType,
1333
- borderWidth: borderWidth,
1334
- errorMessageTextColor: errorMessageTextColor,
1335
- errorMessageTextSize: errorMessageTextSize,
1336
- errorMessageWeight: errorMessageTextWeight,
1337
- fileErrorText: fileErrorText,
1338
- metaError: meta.error,
1339
- dropzoneProps: dropzoneProps,
1340
- hintDescription: hintDescription,
1341
- hintDescriptionTextColor: hintDescriptionTextColor,
1342
- hintDescriptionTextSize: hintDescriptionTextSize,
1343
- hintDescriptionTextWeight: hintDescriptionTextWeight,
1344
- hintDescriptionTextWrap: hintDescriptionTextWrap,
1345
- hintTitle: hintTitle,
1346
- hintTitleTextColor: hintTitleTextColor,
1347
- hintTitleTextSize: hintTitleTextSize,
1348
- hintTitleTextWeight: hintTitleTextWeight,
1349
- hintTitleTextWrap: hintTitleTextWrap,
1350
- inputName: input.name,
1351
- inputValue: input.value,
1352
- metaTouched: meta.touched,
1353
- removeThumbText: removeThumbText,
1354
- removeThumbTextColor: removeThumbTextColor,
1355
- removeThumbTextHoverColor: removeThumbTextHoverColor,
1356
- removeThumbTextSize: removeThumbTextSize,
1357
- removeThumbTextWeight: removeThumbTextWeight,
1358
- shape: shape,
1359
- showFilename: showFilename,
1360
- thumbBorderColor: thumbBorderColor,
1361
- thumbBorderColorHover: thumbBorderColorHover,
1362
- thumbBorderType: thumbBorderType,
1363
- thumbBorderWidth: thumbBorderWidth,
1364
- thumbColumn: thumbColumn,
1365
- thumbDirection: thumbDirection,
1366
- thumbNameTextColor: thumbNameTextColor,
1367
- thumbNameTextSize: thumbNameTextSize,
1368
- thumbNameTextWeight: thumbNameTextWeight,
1369
- thumbNameTextWrap: thumbNameTextWrap,
1370
- isPreviews: isPreviews,
1371
- onAddFiles: onAddFiles,
1372
- onDeleteFile: onDeleteFile
1373
- }));
1374
- });
1375
- });
1376
-
1377
- const Group = /*#__PURE__*/React$1.memo(function Group(props) {
1378
- const {
1379
- className,
1380
- name,
1381
- label,
1382
- labelTextColor,
1383
- labelTextSize,
1384
- labelTextWeight,
1385
- message,
1386
- dataTour,
1387
- messageTextColor = 'surfaceTextTertiary',
1388
- messageTextSize = 's',
1389
- messageTextWeight,
1390
- showGroupMessage,
1391
- before,
1392
- after,
1393
- isHidden,
1394
- children
1395
- } = props;
1396
- return /*#__PURE__*/React$1.createElement(Field, {
1397
- name: name
1398
- }, function Render({
1399
- input,
1400
- meta
1401
- }) {
1402
- /** Note:
1403
- * Create "Render" function by "eslint-react-hooks/rules-of-hooks":
1404
- * React Hooks cannot be called inside a callback.
1405
- * React Hooks must be called in a React function component or a
1406
- * custom React Hook function.
1407
- */
1408
- const {
1409
- isErrorState,
1410
- errorKey,
1411
- errorMessage
1412
- } = useFieldValidationState({
1413
- fieldProps: props,
1414
- // or fieldProps?
1415
- input: input,
1416
- meta: meta
1417
- });
1418
- const updatedProps = useValidationAppearanceInputProps({
1419
- inputProps: props,
1420
- validationStateKey: isErrorState ? errorKey : 'success'
1421
- });
1422
- return /*#__PURE__*/React$1.createElement("div", {
1423
- className: clsx('form__group', className, isHidden && 'form__group_hidden'),
1424
- "data-tour": dataTour
1425
- }, /*#__PURE__*/React$1.createElement("div", {
1426
- className: "form__group-wrapper"
1427
- }, before, label && /*#__PURE__*/React$1.createElement("div", {
1428
- className: "form__group-label"
1429
- }, /*#__PURE__*/React$1.createElement(Title, {
1430
- size: labelTextSize,
1431
- textColor: labelTextColor,
1432
- textWeight: labelTextWeight
1433
- }, label)), /*#__PURE__*/React$1.createElement("div", {
1434
- className: "form__group-items"
1435
- }, children), after), showGroupMessage && /*#__PURE__*/React$1.createElement(React$1.Fragment, null, isErrorState && errorMessage && /*#__PURE__*/React$1.createElement(Text, {
1436
- className: `form__group-message form__group-message_type-${errorKey}`,
1437
- id: `${name}-error`,
1438
- size: updatedProps.messageTextSize,
1439
- textColor: updatedProps.messageTextColor,
1440
- textWeight: updatedProps.messageTextWeight
1441
- }, errorMessage), Boolean(message) && (!isErrorState || !errorMessage) && /*#__PURE__*/React$1.createElement(Text, {
1442
- className: "form__group-message",
1443
- size: messageTextSize,
1444
- textColor: messageTextColor,
1445
- textWeight: messageTextWeight
1446
- }, message), !isErrorState && !message && /*#__PURE__*/React$1.createElement(Text, {
1447
- className: "form__group-message",
1448
- size: messageTextSize
1449
- }, '\u00A0')));
1450
- });
1451
- });
1452
-
1453
- const defaultInputProps = {
1454
- appearance: 'sizeM defaultSecondary',
1455
- width: 'fill',
1456
- errorBorderColor: 'errorBorderSecondary',
1457
- requiredBorderColor: 'warningBorderSecondary',
1458
- shape: 'rounded'
1459
- };
1460
-
1461
- const InputField = /*#__PURE__*/React$1.memo(function InputField(props) {
1462
- const {
1463
- name,
1464
- initialValue,
1465
- isDisabled,
1466
- classNameGroupItem,
1467
- // dataTestId,
1468
- // iconBorder,
1469
- // iconBorderHover,
1470
- clearIcon,
1471
- clearIconFill,
1472
- clearIconFillHover,
1473
- clearIconShape,
1474
- clearIconSize,
1475
- fieldProps = {},
1476
- iconFill,
1477
- iconFillHover,
1478
- iconRevealableHide,
1479
- iconRevealableShow,
1480
- iconShape,
1481
- iconSize,
1482
- inputProps = {},
1483
- parse,
1484
- showMessage,
1485
- isPassword,
1486
- isRequired,
1487
- isRevealable,
1488
- onChange,
1489
- onClickClearIcon
1490
- } = props;
1491
- const [isRevealed, setIsRevealed] = useState(false);
1492
- const inputType = useMemo(() => {
1493
- if (isPassword) {
1494
- return isRevealed ? 'text' : 'password';
1495
- } else {
1496
- return 'text';
1497
- }
1498
- }, [isRevealed, isPassword]);
1499
- const onClickIconReveal = useCallback(event => {
1500
- event.preventDefault();
1501
- setIsRevealed(prev => !prev);
1502
- }, []);
1503
- return /*#__PURE__*/React$1.createElement(Field, {
1504
- name: name,
1505
- initialValue: initialValue,
1506
- parse: parse
1507
- }, function Render({
1508
- input,
1509
- meta
1510
- }) {
1511
- /** Note:
1512
- * Create "Render" function by "eslint-react-hooks/rules-of-hooks":
1513
- * React Hooks cannot be called inside a callback.
1514
- * React Hooks must be called in a React function component or a
1515
- * custom React Hook function.
1516
- */
1517
-
1518
- const onChangeField = useCallback(event => {
1519
- input.onChange(event);
1520
- if (onChange) {
1521
- onChange(event.target.value, input.name);
1522
- }
1523
- }, [onChange, input.onChange]);
1524
- const {
1525
- isErrorState,
1526
- isValidState,
1527
- errorKey,
1528
- errorMessage
1529
- } = useFieldValidationState({
1530
- fieldProps: fieldProps,
1531
- input: input,
1532
- meta: meta
1533
- });
1534
- const updatedInputProps = useValidationAppearanceInputProps({
1535
- inputProps: inputProps,
1536
- validationStateKey: isErrorState ? errorKey : 'success'
1537
- });
1538
- return /*#__PURE__*/React$1.createElement(FieldWrapper, Object.assign({
1539
- className: clsx('form-field_type_input', 'form__item_type_input', classNameGroupItem),
1540
- errorKey: errorKey,
1541
- errorMessage: errorMessage,
1542
- isErrorState: isErrorState,
1543
- metaError: meta.error,
1544
- isDisabled: isDisabled,
1545
- fieldClassName: isRevealable ? 'form-password' : 'form-input',
1546
- inputName: input.name,
1547
- inputValue: input.value || '',
1548
- metaActive: meta.active,
1549
- showMessage: showMessage,
1550
- isRequired: isRequired,
1551
- isValidState: isValidState
1552
- }, fieldProps), /*#__PURE__*/React$1.createElement(Input, Object.assign({
1553
- className: clsx(meta.active && 'input_state_focus', meta.error && meta.touched && `input_state_${errorKey}`),
1554
- type: inputType,
1555
- name: input.name,
1556
- isDisabled: isDisabled,
1557
- autoComplete: "nope",
1558
- dataTestId: `${input.name}FieldInput`,
1559
- value: input.value || '',
1560
- onBlur: input.onBlur,
1561
- onChange: onChangeField,
1562
- onFocus: input.onFocus
1563
- }, updatedInputProps)), isRevealable && /*#__PURE__*/React$1.createElement(Icon, {
1564
- className: "form-field__icon",
1565
- size: iconSize,
1566
- iconFill: iconFill,
1567
- iconFillHover: iconFillHover,
1568
- imageSrc: isRevealed ? iconRevealableHide : iconRevealableShow,
1569
- shape: iconShape,
1570
- SvgImage: isRevealed ? iconRevealableHide : iconRevealableShow,
1571
- onClick: onClickIconReveal
1572
- }), clearIcon && /*#__PURE__*/React$1.createElement(Icon, {
1573
- className: "form-field__icon",
1574
- size: clearIconSize,
1575
- iconFill: clearIconFill,
1576
- iconFillHover: clearIconFillHover,
1577
- imageSrc: clearIcon,
1578
- shape: clearIconShape,
1579
- SvgImage: clearIcon,
1580
- onClick: onClickClearIcon
1581
- }));
1582
- });
1583
- });
1584
-
1585
- const defaultRadioProps = {
1586
- fieldProps: {
1587
- width: 'fill',
1588
- size: 'm',
1589
- labelTextColor: 'surfaceTextPrimary',
1590
- labelTextSize: 's',
1591
- labelTextWeight: 'normal',
1592
- textColor: 'surfaceTextPrimary',
1593
- helpText: 'Supporting text',
1594
- helpTextColor: 'surfaceTextPrimary',
1595
- helpTextSize: 's',
1596
- helpTextWeight: 'normal',
1597
- showMessage: true
1598
- },
1599
- inputProps: {
1600
- width: 'fill',
1601
- size: 'm',
1602
- labelTextColor: 'surfaceTextPrimary',
1603
- labelTextSize: 's',
1604
- descTextColor: 'surfaceTextPrimary',
1605
- descTextSize: 's'
1606
- }
1607
- };
1608
-
1609
- function RadioGroupInput(props) {
1610
- const {
1611
- input,
1612
- value,
1613
- onChange
1614
- } = props;
1615
- const onChangeField = useCallback(event => onChange(event.target.value), [onChange]);
1616
- return /*#__PURE__*/React.createElement(Input, Object.assign({
1617
- name: input.name,
1618
- autoComplete: "nope",
1619
- value: value,
1620
- onBlur: input.onBlur,
1621
- onChange: onChangeField,
1622
- onFocus: input.onFocus
1623
- }, props));
1624
- }
1625
-
1626
- function RadioGroupItem(props) {
1627
- const {
1628
- input,
1629
- inputProps,
1630
- option,
1631
- onChange
1632
- } = props;
1633
- const onChangeField = useCallback(event => {
1634
- if (event.target.checked) {
1635
- onChange(option.value);
1636
- }
1637
- }, [onChange]);
1638
- return /*#__PURE__*/React.createElement(Radio, Object.assign({
1639
- className: "form-radio__item",
1640
- type: "radio",
1641
- name: input.name,
1642
- label: option.label,
1643
- checked: option.value === input.value,
1644
- value: option.value,
1645
- onBlur: input.onBlur,
1646
- onChange: onChangeField,
1647
- onFocus: input.onFocus
1648
- }, inputProps));
1649
- }
1650
-
1651
- function RadioGroupList(props) {
1652
- const {
1653
- editableProps,
1654
- input,
1655
- inputProps,
1656
- options,
1657
- onChange
1658
- } = props;
1659
- const [editableValue, setEditableValue] = useState(() => {
1660
- const isRadioValue = options.find(option => option.value === input.value);
1661
- if (!isRadioValue) {
1662
- return input.value;
1663
- }
1664
- return '';
1665
- });
1666
- useEffect(() => {
1667
- // When a new value from outside enters the form
1668
- if (input.value) {
1669
- // Check value for radio type
1670
- const isRadioValue = options.find(option => option.value === input.value && !option.editable);
1671
- // If new value not in radio list - set to editable input
1672
- setEditableValue(isRadioValue ? '' : input.value);
1673
- } else {
1674
- // If new value is empty - clear editable input
1675
- setEditableValue('');
1676
- }
1677
- }, [input.value]);
1678
-
1679
- // Callback for value changes
1680
- const onChangeSomeInput = useCallback(value => {
1681
- // Save to form values
1682
- input.onChange(value);
1683
- if (onChange) {
1684
- // Pass to custom event
1685
- onChange(value, input.name);
1686
- }
1687
- }, [input, onChange]);
1688
-
1689
- // Handle for radio inputs
1690
- const onChangeRadio = useCallback(value => {
1691
- setEditableValue('');
1692
- onChangeSomeInput(value);
1693
- }, [onChangeSomeInput]);
1694
-
1695
- // Handle for text input
1696
- const onChangeEditable = useCallback(value => {
1697
- setEditableValue(value);
1698
- onChangeSomeInput(value);
1699
- }, [onChangeSomeInput]);
1700
- return /*#__PURE__*/React$1.createElement(React$1.Fragment, null, options.map(option => option.editable ? /*#__PURE__*/React$1.createElement(RadioGroupInput, {
1701
- key: option.label,
1702
- editableProps: editableProps,
1703
- input: input,
1704
- inputProps: inputProps,
1705
- option: option,
1706
- value: editableValue,
1707
- onChange: onChangeEditable
1708
- }) : /*#__PURE__*/React$1.createElement(RadioGroupItem, {
1709
- key: option.value,
1710
- input: input,
1711
- inputProps: inputProps,
1712
- option: option,
1713
- onChange: onChangeRadio
1714
- })));
1715
- }
1716
-
1717
- const RadioGroup = /*#__PURE__*/React$1.memo(function RadioGroup(props) {
1718
- const {
1719
- name,
1720
- isDisabled,
1721
- editableProps = {},
1722
- fieldProps = {},
1723
- inputProps = {},
1724
- options = [],
1725
- showMessage,
1726
- isRequired,
1727
- onChange
1728
- } = props;
1729
- return /*#__PURE__*/React$1.createElement(Field, {
1730
- name: name
1731
- }, function Render({
1732
- input,
1733
- meta
1734
- }) {
1735
- /** Note:
1736
- * Create "Render" function by "eslint-react-hooks/rules-of-hooks":
1737
- * React Hooks cannot be called inside a callback.
1738
- * React Hooks must be called in a React function component or a
1739
- * custom React Hook function.
1740
- */
1741
-
1742
- const {
1743
- errorKey,
1744
- errorMessage,
1745
- isErrorState,
1746
- isValidState
1747
- } = useFieldValidationState({
1748
- fieldProps: fieldProps,
1749
- input: input,
1750
- meta: meta
1751
- });
1752
- const updatedInputProps = useValidationAppearanceInputProps({
1753
- inputProps: inputProps,
1754
- validationStateKey: isErrorState ? errorKey : 'success'
1755
- });
1756
- return /*#__PURE__*/React$1.createElement(FieldWrapper, Object.assign({
1757
- className: clsx('form-field_type_radio', 'form__item_type_radio"', classNameGroupItem),
1758
- errorKey: errorKey,
1759
- errorMessage: errorMessage,
1760
- isErrorState: isErrorState,
1761
- metaError: meta.error,
1762
- isDisabled: isDisabled,
1763
- fieldClassName: 'form-radio',
1764
- inputName: input.name,
1765
- inputValue: input.value || '',
1766
- metaActive: meta.active,
1767
- showMessage: showMessage,
1768
- isRequired: isRequired,
1769
- isValidState: isValidState
1770
- }, fieldProps), /*#__PURE__*/React$1.createElement(RadioGroupList, {
1771
- isDisabled: isDisabled,
1772
- editableProps: editableProps,
1773
- input: input,
1774
- inputProps: updatedInputProps,
1775
- options: options,
1776
- onChange: onChange
1777
- }));
1778
- });
1779
- });
1780
-
1781
- const defaultSegmentedProps = {
1782
- appearance: 'sizeM surfacePrimary',
1783
- width: 'fill',
1784
- errorLabelTextColor: 'errorTextPrimary',
1785
- requiredLabelTextColor: 'warningTextPrimary',
1786
- shape: 'rounded'
1787
- };
1788
-
1789
- function SegmentedField(props) {
1790
- const {
1791
- name,
1792
- isDisabled,
1793
- fieldProps,
1794
- inputProps,
1795
- options,
1796
- showMessage,
1797
- isRequired
1798
- } = props;
1799
- const {
1800
- change
1801
- } = useForm();
1802
- const setActiveSegment = useCallback(option => {
1803
- change(name, option.value);
1804
- }, [change]);
1805
- return /*#__PURE__*/React$1.createElement(Field, {
1806
- name: name
1807
- }, function Render({
1808
- input,
1809
- meta
1810
- }) {
1811
- /** Note:
1812
- * Create "Render" function by "eslint-react-hooks/rules-of-hooks":
1813
- * React Hooks cannot be called inside a callback.
1814
- * React Hooks must be called in a React function component or a
1815
- * custom React Hook function.
1816
- */
1817
-
1818
- const activeOption = useMemo(() => {
1819
- const emptyOption = {
1820
- label: null,
1821
- value: null
1822
- };
1823
- if (input.value) {
1824
- const currentOption = options.find(option => option.value === input.value);
1825
- return currentOption || emptyOption;
1826
- }
1827
- return emptyOption;
1828
- }, [input.value]);
1829
- const {
1830
- errorKey,
1831
- errorMessage,
1832
- isErrorState,
1833
- isValidState
1834
- } = useFieldValidationState({
1835
- fieldProps: fieldProps,
1836
- input: input,
1837
- meta: meta
1838
- });
1839
- const updatedInputProps = useValidationAppearanceInputProps({
1840
- inputProps: inputProps,
1841
- validationStateKey: isErrorState ? errorKey : 'success'
1842
- });
1843
- return /*#__PURE__*/React$1.createElement(FieldWrapper, Object.assign({
1844
- className: clsx('form-field_type_segmented', 'form__item_type_segmented'),
1845
- errorKey: errorKey,
1846
- errorMessage: errorMessage,
1847
- isErrorState: isErrorState,
1848
- metaError: meta.error,
1849
- isDisabled: isDisabled,
1850
- fieldClassName: "form-segmented",
1851
- inputName: input.name,
1852
- inputValue: input.value || [],
1853
- metaActive: meta.active,
1854
- showMessage: showMessage,
1855
- isRequired: isRequired,
1856
- isValidState: isValidState
1857
- }, fieldProps), /*#__PURE__*/React$1.createElement(Segmented, Object.assign({
1858
- isDisabled: isDisabled,
1859
- activeSegment: activeOption,
1860
- segments: options,
1861
- setActiveSegment: setActiveSegment
1862
- }, updatedInputProps)));
1863
- });
1864
- }
1865
-
1866
- const defaultSelectProps = {
1867
- elevation: 8,
1868
- isClearable: true,
1869
- isSearchable: true,
1870
- badgeAppearance: 'accent',
1871
- badgeSize: 'm',
1872
- badgeTextSize: 'm',
1873
- // clearIcon: icon24.Clear,
1874
- clearIconFill: 'surfaceItemPrimary',
1875
- closeMenuOnSelect: true,
1876
- // optionSelected: <Icon iconFill="surfaceItemAccent" SvgImage={icon24.Check} />,
1877
-
1878
- dividerDirection: 'horizontal',
1879
- dividerFill: 'surfaceTertiary',
1880
- dividerSize: 'xxs',
1881
- // dropdownIcon: icon24.ChevronDownSmall,
1882
- dropdownIconFill: 'surfaceItemPrimary',
1883
- // error
1884
- errorInputBorderColor: 'errorBorderPrimary',
1885
- headingFill: 'surfaceSecondary',
1886
- loadingMessage: /*#__PURE__*/React$1.createElement(Loader, {
1887
- width: "fill",
1888
- height: "fill",
1889
- fill: "surfacePrimary",
1890
- position: "absolute",
1891
- left: "0px",
1892
- right: "0px",
1893
- zIndex: "1",
1894
- itemFill: "surfaceItemAccent",
1895
- set: "simple"
1896
- })
1897
- };
1898
-
1899
- function getDefaultValue(options, selectValue) {
1900
- const selectValues = Array.isArray(selectValue) ? selectValue : [selectValue];
1901
- let result = [];
1902
- options.forEach(item => {
1903
- const isValue = selectValues.includes(item.value);
1904
- const isLabel = selectValues.includes(item.label);
1905
- let childOptions = [];
1906
- if (item.options) {
1907
- childOptions = getDefaultValue(item.options, selectValue);
1908
- }
1909
- if (isValue || isLabel) {
1910
- result.push(item);
1911
- } else if (childOptions.length) {
1912
- result = result.concat(childOptions);
1913
- }
1914
- });
1915
- return result;
1916
- }
1917
- const SelectField = /*#__PURE__*/React$1.memo(function SelectField(props) {
1918
- const {
1919
- isDisabled,
1920
- isRequired,
1921
- classNameGroupItem,
1922
- fieldProps,
1923
- initialValue,
1924
- name,
1925
- options = [],
1926
- selectProps,
1927
- selectRef,
1928
- showMessage,
1929
- onChange,
1930
- onInputChange
1931
- } = props;
1932
- return /*#__PURE__*/React$1.createElement(Field, {
1933
- name: name,
1934
- initialValue: initialValue
1935
- }, function Render({
1936
- input,
1937
- meta
1938
- }) {
1939
- /** Note:
1940
- * Create "Render" function by "eslint-react-hooks/rules-of-hooks":
1941
- * React Hooks cannot be called inside a callback.
1942
- * React Hooks must be called in a React function component or a
1943
- * custom React Hook function.
1944
- */
1945
- const [selectedOptions, setSelectedOptions] = useState(null);
1946
- const defaultValue = useMemo(() => {
1947
- const optionsValues = getDefaultValue(options, input.value);
1948
- if (!optionsValues.length && input.value?.length) {
1949
- optionsValues.push({
1950
- label: input.value,
1951
- value: input.value
1952
- });
1953
- }
1954
- return optionsValues;
1955
- }, [input.value]);
1956
- const onChangeField = useCallback(value => {
1957
- input.onChange(value);
1958
- if (onChange) {
1959
- onChange(value, input.name);
1960
- }
1961
- }, [onChange, input.onChange]);
1962
- const onChangeValue = useCallback((option, actionMeta) => {
1963
- const value = Array.isArray(option) ? option.map(o => o.value) : option?.value || null;
1964
- setSelectedOptions(option);
1965
- onChangeField(value);
1966
- }, [onChangeField]);
1967
- useEffect(() => {
1968
- setSelectedOptions(defaultValue);
1969
- }, [defaultValue]);
1970
- const {
1971
- isErrorState,
1972
- isValidState,
1973
- errorKey,
1974
- errorMessage
1975
- } = useFieldValidationState({
1976
- fieldProps: fieldProps,
1977
- input: input,
1978
- meta: meta
1979
- });
1980
- const updatedSelectProps = useValidationAppearanceInputProps({
1981
- inputProps: selectProps,
1982
- validationStateKey: isErrorState ? errorKey : 'success'
1983
- });
1984
- return /*#__PURE__*/React$1.createElement(FieldWrapper, Object.assign({
1985
- className: clsx('form-field_type_select', 'form__item_type_select', classNameGroupItem),
1986
- errorKey: errorKey,
1987
- errorMessage: errorMessage,
1988
- isErrorState: isErrorState,
1989
- metaError: meta.error,
1990
- isDisabled: isDisabled,
1991
- fieldClassName: 'form-select',
1992
- inputName: input.name,
1993
- inputValue: input.value,
1994
- metaActive: meta.active,
1995
- showMessage: showMessage,
1996
- isRequired: isRequired,
1997
- isValidState: isValidState
1998
- }, fieldProps), /*#__PURE__*/React$1.createElement(Select, Object.assign({
1999
- className: "form-select-item",
2000
- isDisabled: isDisabled,
2001
- instanceId: `id_${input.name}`,
2002
- options: options,
2003
- ref: selectRef,
2004
- value: selectedOptions,
2005
- onChange: onChangeValue,
2006
- onInputChange: onInputChange
2007
- }, updatedSelectProps)));
2008
- });
2009
- });
2010
-
2011
- const defaultSwitchProps = {
2012
- fieldProps: {
2013
- width: 'fill',
2014
- size: 'xl',
2015
- labelTextColor: 'surfaceTextPrimary',
2016
- labelTextSize: 's',
2017
- labelTextWeight: 'normal',
2018
- textColor: 'surfaceTextPrimary',
2019
- helpText: 'Supporting text',
2020
- helpTextColor: 'surfaceTextPrimary',
2021
- helpTextSize: 's',
2022
- helpTextWeight: 'normal',
2023
- showMessage: true
2024
- },
2025
- inputProps: {
2026
- size: 'm',
2027
- fill: 'surfaceSecondary',
2028
- title: 'Switch',
2029
- titleTextColor: 'surfaceTextPrimary',
2030
- titleTextSize: 's',
2031
- desc: 'Description',
2032
- descTextColor: 'surfaceTextPrimary',
2033
- descTextSize: 'xs'
2034
- }
2035
- };
2036
-
2037
- const SwitchField = /*#__PURE__*/React$1.memo(function SwitchField(props) {
2038
- const {
2039
- name,
2040
- isDisabled,
2041
- classNameGroupItem,
2042
- fieldProps = {},
2043
- inputProps = {},
2044
- showMessage,
2045
- isRequired,
2046
- onChange
2047
- } = props;
2048
- return /*#__PURE__*/React$1.createElement(Field, {
2049
- type: "checkbox",
2050
- name: name
2051
- }, function Render({
2052
- input,
2053
- meta
2054
- }) {
2055
- /** Note:
2056
- * Create "Render" function by "eslint-react-hooks/rules-of-hooks":
2057
- * React Hooks cannot be called inside a callback.
2058
- * React Hooks must be called in a React function component or a
2059
- * custom React Hook function.
2060
- */
2061
-
2062
- const onChangeField = useCallback(event => {
2063
- input.onChange(event);
2064
- if (onChange) {
2065
- onChange(event.target.checked, input.name);
2066
- }
2067
- }, [onChange, input.onChange]);
2068
- const {
2069
- errorKey,
2070
- errorMessage,
2071
- isErrorState,
2072
- isValidState
2073
- } = useFieldValidationState({
2074
- fieldProps: fieldProps,
2075
- input: input,
2076
- meta: meta
2077
- });
2078
- const updatedInputProps = useValidationAppearanceInputProps({
2079
- inputProps: inputProps,
2080
- validationStateKey: isErrorState ? errorKey : 'success'
2081
- });
2082
- return /*#__PURE__*/React$1.createElement(FieldWrapper, Object.assign({
2083
- className: clsx('form-field_type_switch', 'form__item_type_switch', classNameGroupItem),
2084
- errorKey: errorKey,
2085
- errorMessage: errorMessage,
2086
- isErrorState: isErrorState,
2087
- metaError: meta.error,
2088
- isDisabled: isDisabled,
2089
- fieldClassName: "form-switch",
2090
- inputName: input.name,
2091
- inputValue: input.checked,
2092
- metaActive: meta.active,
2093
- showMessage: showMessage,
2094
- tag: "label",
2095
- isRequired: isRequired,
2096
- isValidState: isValidState
2097
- }, fieldProps), /*#__PURE__*/React$1.createElement(Switch, Object.assign({
2098
- type: "checkbox",
2099
- name: input.name,
2100
- isDisabled: isDisabled,
2101
- autoComplete: "nope",
2102
- checked: input.checked,
2103
- onBlur: input.onBlur,
2104
- onChange: onChangeField,
2105
- onFocus: input.onFocus
2106
- }, updatedInputProps)));
2107
- });
2108
- });
2109
-
2110
- const defaultTextareaProps = {
2111
- appearance: 'sizeM defaultSecondary',
2112
- width: 'fill',
2113
- errorBorderColor: 'errorBorderSecondary',
2114
- requiredBorderColor: 'warningBorderSecondary',
2115
- shape: 'rounded'
2116
- };
2117
-
2118
- const TextareaField = /*#__PURE__*/React$1.memo(function TextareaField(props) {
2119
- const {
2120
- name,
2121
- isDisabled,
2122
- classNameGroupItem,
2123
- fieldProps = {},
2124
- inputProps = {},
2125
- showMessage,
2126
- isRequired
2127
- } = props;
2128
- return /*#__PURE__*/React$1.createElement(Field, {
2129
- name: name
2130
- }, function Render({
2131
- input,
2132
- meta
2133
- }) {
2134
- /** Note:
2135
- * Create "Render" function by "eslint-react-hooks/rules-of-hooks":
2136
- * React Hooks cannot be called inside a callback.
2137
- * React Hooks must be called in a React function component or a
2138
- * custom React Hook function.
2139
- */
2140
-
2141
- const {
2142
- errorKey,
2143
- errorMessage,
2144
- isErrorState,
2145
- isValidState
2146
- } = useFieldValidationState({
2147
- fieldProps: fieldProps,
2148
- input: input,
2149
- meta: meta
2150
- });
2151
- const updatedInputProps = useValidationAppearanceInputProps({
2152
- inputProps: inputProps,
2153
- validationStateKey: isErrorState ? errorKey : 'success'
2154
- });
2155
- return /*#__PURE__*/React$1.createElement(FieldWrapper, Object.assign({
2156
- className: clsx('form-field_type_textarea', 'form__item_type_textarea', classNameGroupItem),
2157
- errorKey: errorKey,
2158
- errorMessage: errorMessage,
2159
- isErrorState: isErrorState,
2160
- metaError: meta.error,
2161
- isDisabled: isDisabled,
2162
- fieldClassName: 'form-textarea',
2163
- inputName: input.name,
2164
- inputValue: input.value,
2165
- metaActive: meta.active,
2166
- showMessage: showMessage,
2167
- isRequired: isRequired,
2168
- isValidState: isValidState
2169
- }, fieldProps), /*#__PURE__*/React$1.createElement(Textarea, Object.assign({
2170
- name: input.name,
2171
- isDisabled: isDisabled,
2172
- autoComplete: "nope",
2173
- value: input.value,
2174
- onBlur: input.onBlur,
2175
- onChange: input.onChange,
2176
- onFocus: input.onFocus
2177
- }, updatedInputProps)));
2178
- });
2179
- });
2180
-
2181
- const MaskedInputField = /*#__PURE__*/React$1.memo(function MaskedInputField(props) {
2182
- const {
2183
- name,
2184
- initialValue,
2185
- isDisabled,
2186
- classNameGroupItem,
2187
- clearIcon,
2188
- clearIconFill,
2189
- clearIconFillHover,
2190
- clearIconShape,
2191
- clearIconSize,
2192
- fieldProps = {},
2193
- inputProps = {},
2194
- optionsMask,
2195
- showMessage,
2196
- unmasked,
2197
- isRequired,
2198
- onClickClearIcon
2199
- } = props;
2200
- return /*#__PURE__*/React$1.createElement(Field, {
2201
- name: name,
2202
- initialValue: initialValue
2203
- }, function Render({
2204
- input,
2205
- meta
2206
- }) {
2207
- /** Note:
2208
- * Create "Render" function by "eslint-react-hooks/rules-of-hooks":
2209
- * React Hooks cannot be called inside a callback.
2210
- * React Hooks must be called in a React function component or a
2211
- * custom React Hook function.
2212
- */
2213
-
2214
- const {
2215
- ref,
2216
- unmaskedValue,
2217
- value,
2218
- setUnmaskedValue
2219
- } = useIMask(optionsMask, {
2220
- onAccept: (newValue, event, element) => {
2221
- if (element) {
2222
- input.onChange(event._unmaskedValue);
2223
- }
2224
- }
2225
- });
2226
- useEffect(() => {
2227
- if (input.value !== unmaskedValue) {
2228
- setUnmaskedValue(input.value.replace(unmasked, ''));
2229
- }
2230
- }, [input.value]);
2231
- const {
2232
- errorKey,
2233
- errorMessage,
2234
- isErrorState,
2235
- isValidState
2236
- } = useFieldValidationState({
2237
- fieldProps: fieldProps,
2238
- input: input,
2239
- meta: meta
2240
- });
2241
- const updatedInputProps = useValidationAppearanceInputProps({
2242
- inputProps: inputProps,
2243
- validationStateKey: isErrorState ? errorKey : 'success'
2244
- });
2245
- return /*#__PURE__*/React$1.createElement(FieldWrapper, Object.assign({
2246
- className: clsx('form-field_type_maskedInput', 'form__item_type_maskedInput', classNameGroupItem),
2247
- errorKey: errorKey,
2248
- errorMessage: errorMessage,
2249
- isErrorState: isErrorState,
2250
- metaError: meta.error,
2251
- isDisabled: isDisabled,
2252
- fieldClassName: 'form-maskedInput',
2253
- inputName: input.name,
2254
- inputValue: input.value,
2255
- metaActive: meta.active,
2256
- showMessage: showMessage,
2257
- isRequired: isRequired,
2258
- isValidState: isValidState
2259
- }, fieldProps), /*#__PURE__*/React$1.createElement(Input, Object.assign({
2260
- className: clsx(meta.active && 'input_state_focus', meta.error && meta.touched && `input_state_${errorKey}`),
2261
- ref: ref,
2262
- value: value,
2263
- onBlur: input.onBlur,
2264
- onFocus: input.onFocus
2265
- }, updatedInputProps)), clearIcon && /*#__PURE__*/React$1.createElement(Icon, {
2266
- className: "form-field__icon",
2267
- size: clearIconSize,
2268
- iconFill: clearIconFill,
2269
- iconFillHover: clearIconFillHover,
2270
- imageSrc: clearIcon,
2271
- shape: clearIconShape,
2272
- SvgImage: clearIcon,
2273
- onClick: onClickClearIcon
2274
- }));
2275
- });
2276
- });
2277
-
2278
- const defaultChipsProps = {
2279
- appearance: 'surfacePrimary',
2280
- width: 'fill',
2281
- errorBorderColor: 'errorBorderSecondary',
2282
- requiredBorderColor: 'warningBorderSecondary'
2283
- };
2284
-
2285
- function ChipsField(props) {
2286
- const {
2287
- name,
2288
- initialValue,
2289
- isDisabled,
2290
- classNameGroupItem,
2291
- emptyMessage,
2292
- emptyMessageTextColor,
2293
- emptyMessageTextSize,
2294
- fieldProps,
2295
- inputProps,
2296
- options,
2297
- showMessage,
2298
- isRequired,
2299
- onChange
2300
- } = props;
2301
- const {
2302
- change
2303
- } = useForm();
2304
-
2305
- // Callback for value changes
2306
- const onChangeSomeInput = useCallback((inputValue, newOptionValue) => {
2307
- const updatedValues = inputValue.includes(newOptionValue) ? inputValue.filter(selectedValue => selectedValue !== newOptionValue) : [...inputValue, newOptionValue];
2308
- change(name, updatedValues);
2309
- onChange && onChange(updatedValues);
2310
- }, [change, name, onChange]);
2311
- useEffect(() => {
2312
- initialValue && change(name, initialValue);
2313
- // update the form value only when the initialValue changes, so use disable eslint to ignore the warning
2314
- // eslint-disable-next-line react-hooks/exhaustive-deps
2315
- }, [initialValue]);
2316
- return /*#__PURE__*/React$1.createElement(Field, {
2317
- name: name,
2318
- initialValue: initialValue
2319
- }, function Render({
2320
- input,
2321
- meta
2322
- }) {
2323
- const {
2324
- errorKey,
2325
- errorMessage,
2326
- isErrorState,
2327
- isValidState
2328
- } = useFieldValidationState({
2329
- fieldProps: fieldProps,
2330
- input: input,
2331
- meta: meta
2332
- });
2333
- const updatedInputProps = useValidationAppearanceInputProps({
2334
- inputProps: inputProps,
2335
- validationStateKey: isErrorState ? errorKey : 'success'
2336
- });
2337
- const activeOptionsList = useMemo(() => {
2338
- const emptyOptionsList = [{
2339
- label: null,
2340
- value: null
2341
- }];
2342
- if (input?.value) {
2343
- const currentOptions = options.filter(option => input.value?.includes(option.value));
2344
- return currentOptions || emptyOptionsList;
2345
- }
2346
- return emptyOptionsList;
2347
- }, [input.value]);
2348
- return /*#__PURE__*/React$1.createElement(FieldWrapper, Object.assign({
2349
- className: clsx('form-field_type_chips', 'form__item_type_chips', classNameGroupItem),
2350
- errorKey: errorKey,
2351
- errorMessage: errorMessage,
2352
- isErrorState: isErrorState,
2353
- metaError: meta.error,
2354
- isDisabled: isDisabled,
2355
- fieldClassName: "form-chips",
2356
- inputName: input.name,
2357
- inputValue: input.value,
2358
- metaActive: meta.active,
2359
- showMessage: showMessage,
2360
- isRequired: isRequired,
2361
- isValidState: isValidState
2362
- }, fieldProps), options.length ? options.map(option => /*#__PURE__*/React$1.createElement(Chips, Object.assign({
2363
- className: clsx(meta.active && 'form-chips_state_focus', meta.error && meta.touched && `form-chips_state_${errorKey}`),
2364
- key: option.value,
2365
- label: option.label,
2366
- isDisabled: option.isDisabled,
2367
- value: option.value,
2368
- isActive: activeOptionsList.some(activeOption => activeOption.value === option.value),
2369
- onClick: () => onChangeSomeInput(input.value, option.value)
2370
- }, updatedInputProps))) : /*#__PURE__*/React$1.createElement(Text, {
2371
- size: emptyMessageTextSize,
2372
- textColor: emptyMessageTextColor
2373
- }, emptyMessage));
2374
- });
2375
- }
2376
-
2377
- const formTypes = {
2378
- code: 'code',
2379
- text: 'text',
2380
- textarea: 'textarea',
2381
- custom: 'custom',
2382
- checkbox: 'checkbox',
2383
- chips: 'chips',
2384
- choice: 'choice',
2385
- datePicker: 'datePicker',
2386
- dateRangePicker: 'dateRangePicker',
2387
- fileInput: 'fileInput',
2388
- group: 'group',
2389
- maskedInput: 'maskedInput',
2390
- radioGroup: 'radioGroup',
2391
- segmented: 'segmented',
2392
- select: 'select',
2393
- switch: 'switch'
2394
- };
2395
- function generateField(field, config, props) {
2396
- switch (field.type) {
2397
- case formTypes.checkbox:
2398
- {
2399
- return /*#__PURE__*/React$1.createElement(CheckboxField, Object.assign({
2400
- key: config.key
2401
- }, field, props));
2402
- }
2403
- case formTypes.choice:
2404
- {
2405
- return /*#__PURE__*/React$1.createElement(ChoiceField, Object.assign({
2406
- key: config.key
2407
- }, field, props));
2408
- }
2409
- case formTypes.chips:
2410
- {
2411
- return /*#__PURE__*/React$1.createElement(ChipsField, Object.assign({
2412
- key: config.key
2413
- }, field, props));
2414
- }
2415
- case formTypes.code:
2416
- {
2417
- return /*#__PURE__*/React$1.createElement(CodeField, Object.assign({
2418
- key: config.key
2419
- }, field, props));
2420
- }
2421
- case formTypes.switch:
2422
- {
2423
- return /*#__PURE__*/React$1.createElement(SwitchField, Object.assign({
2424
- key: config.key
2425
- }, field, props));
2426
- }
2427
- case formTypes.segmented:
2428
- {
2429
- return /*#__PURE__*/React$1.createElement(SegmentedField, Object.assign({
2430
- key: config.key
2431
- }, field, props));
2432
- }
2433
- case formTypes.datePicker:
2434
- {
2435
- return /*#__PURE__*/React$1.createElement(DatePickerField, Object.assign({
2436
- key: config.key
2437
- }, field, props));
2438
- }
2439
- case formTypes.fileInput:
2440
- {
2441
- return /*#__PURE__*/React$1.createElement(FileInput, Object.assign({
2442
- key: config.key
2443
- }, field, props));
2444
- }
2445
- case formTypes.radioGroup:
2446
- {
2447
- return /*#__PURE__*/React$1.createElement(RadioGroup, Object.assign({
2448
- key: config.key
2449
- }, field, props));
2450
- }
2451
- case formTypes.select:
2452
- {
2453
- return /*#__PURE__*/React$1.createElement(SelectField, Object.assign({
2454
- key: config.key
2455
- }, field, props));
2456
- }
2457
- case formTypes.text:
2458
- {
2459
- return /*#__PURE__*/React$1.createElement(InputField, Object.assign({
2460
- key: config.key
2461
- }, field, props));
2462
- }
2463
- case formTypes.textarea:
2464
- {
2465
- return /*#__PURE__*/React$1.createElement(TextareaField, Object.assign({
2466
- key: config.key
2467
- }, field, props));
2468
- }
2469
- case formTypes.maskedInput:
2470
- {
2471
- return /*#__PURE__*/React$1.createElement(MaskedInputField, Object.assign({
2472
- key: config.key
2473
- }, field, props));
2474
- }
2475
- case formTypes.custom:
2476
- {
2477
- return /*#__PURE__*/React$1.createElement(CustomField, Object.assign({
2478
- key: config.key
2479
- }, field, props));
2480
- }
2481
- case formTypes.group:
2482
- {
2483
- return /*#__PURE__*/React$1.createElement(Group, Object.assign({
2484
- key: config.key
2485
- }, field, props), Object.entries(field.group).map(([key, value]) => {
2486
- const groupProps = {
2487
- ...value,
2488
- classNameGroupItem: value.classNameGroupItem || 'form__group-item',
2489
- showMessage: field.showMessage
2490
- };
2491
- return generateField(groupProps, {
2492
- key: key + '_form_group'
2493
- }, props);
2494
- }));
2495
- }
2496
- }
2497
- }
2498
-
2499
- const focusOnError = (formElementsList, errors) => {
2500
- const selectsIds = Object.keys(errors).map(fieldName => {
2501
- if (fieldName === FORM_ERROR) {
2502
- // TODO: get from somewhere
2503
- return 'notification__item_status_error';
2504
- }
2505
- return `react-select-id_${fieldName}-input`;
2506
- });
2507
- const errorFieldElement = formElementsList.find(element => {
2508
- if (element.name) {
2509
- return getIn(errors, element.name);
2510
- } else {
2511
- return selectsIds.includes(element.id);
2512
- }
2513
- });
2514
- const errorsList = Object.keys(errors);
2515
- if (!errorFieldElement && errorsList.length) {
2516
- let errorElement;
2517
- try {
2518
- const fieldName = errorsList[0];
2519
- if (fieldName === FORM_ERROR) {
2520
- errorElement = document.querySelector('notification__item_status_error');
2521
- } else {
2522
- errorElement = document.querySelector(`#${fieldName}-error`);
2523
- if (!errorElement) {
2524
- errorElement = document.querySelector(`#id_${fieldName}`);
2525
- }
2526
- }
2527
- } catch (err) {
2528
- console.warn(err);
2529
- }
2530
- if (errorElement) {
2531
- errorElement.scrollIntoView({
2532
- block: 'center'
2533
- }); // , behavior: 'smooth'
2534
- }
2535
- }
2536
-
2537
- // The field is covered by the header because header is "sticky",
2538
- // that's we scroll manually so that the field falls into the center of the visible area
2539
- if (errorFieldElement) {
2540
- errorFieldElement.scrollIntoView({
2541
- block: 'center'
2542
- });
2543
- }
2544
- return null;
2545
- };
2546
- const focusOnErrorDecorator = createDecorator(null, focusOnError);
2547
- const setErrorsMutator = (args, state) => {
2548
- const [fieldName, data] = args;
2549
- const submitError = data.submitError;
2550
- const fieldError = data.error;
2551
- if (fieldName === 'non_field_errors') {
2552
- // state.formState.invalid = true
2553
- // state.formState.valid = false
2554
- state.formState.error = fieldError;
2555
- state.formState.submitError = submitError;
2556
- } else if (fieldName in state.fields) {
2557
- if (fieldError) {
2558
- const errorsState = Object.assign({}, state.formState.errors, {
2559
- [fieldName]: fieldError
2560
- });
2561
- state.fields[fieldName].touched = true;
2562
- state.fields[fieldName].error = fieldError;
2563
- state.formState.errors = errorsState;
2564
- }
2565
- if (submitError) {
2566
- const submitErrorsState = Object.assign({}, state.formState.submitErrors, {
2567
- [fieldName]: submitError
2568
- });
2569
-
2570
- // state.fields[fieldName].submitFailed = true
2571
- // state.fields[fieldName].submitSucceeded = false
2572
- state.fields[fieldName].submitError = submitError;
2573
- state.formState.submitErrors = submitErrorsState;
2574
- state.formState.submitFailed = true;
2575
- state.formState.submitSucceeded = false;
2576
- state.formState.lastSubmittedValues = state.formState.values;
2577
- }
2578
- }
2579
- };
2580
- const sendFormDataToServer = async (url, data) => {
2581
- try {
2582
- const response = await axios({
2583
- url: url,
2584
- method: 'POST',
2585
- data: data
2586
- });
2587
- return {
2588
- success: true,
2589
- response
2590
- };
2591
- } catch (error) {
2592
- const formErrors = {};
2593
- if (typeof error.response?.data === 'string') {
2594
- formErrors[FORM_ERROR] = 'Something went wrong';
2595
- }
2596
- if (typeof error.response?.data === 'object') {
2597
- Object.entries(error.response.data).forEach(([fieldName, errorsList]) => {
2598
- formErrors[fieldName] = errorsList[0];
2599
- });
2600
- }
2601
- return {
2602
- success: false,
2603
- formErrors,
2604
- error
2605
- };
2606
- }
2607
- };
2608
-
2609
- const FinalForm = /*#__PURE__*/React$1.forwardRef(function FinalForm(props, ref) {
2610
- const {
2611
- className,
2612
- type,
2613
- initialValues,
2614
- initialValuesEqual,
2615
- config,
2616
- title,
2617
- titleFill,
2618
- titleTextColor,
2619
- titleTextSize,
2620
- titleTextWeight,
2621
- desc,
2622
- descSize,
2623
- descTextColor,
2624
- descTextWeight,
2625
- primaryButton,
2626
- primaryButtonFill,
2627
- primaryButtonFillHover,
2628
- primaryButtonLabel,
2629
- primaryButtonLabelSize,
2630
- primaryButtonLabelTextColor,
2631
- primaryButtonLabelTextWeight,
2632
- primaryButtonSize,
2633
- secondaryButton,
2634
- secondaryButtonFill,
2635
- secondaryButtonFillHover,
2636
- secondaryButtonLabel,
2637
- secondaryButtonLabelSize,
2638
- secondaryButtonLabelTextColor,
2639
- secondaryButtonLabelTextWeight,
2640
- secondaryButtonSize,
2641
- tertiaryButton,
2642
- tertiaryButtonFill,
2643
- tertiaryButtonFillHover,
2644
- tertiaryButtonLabel,
2645
- tertiaryButtonLabelSize,
2646
- tertiaryButtonLabelTextColor,
2647
- tertiaryButtonLabelTextWeight,
2648
- tertiaryButtonSize,
2649
- dataTestIdPrimaryButton,
2650
- dataTourPrimaryButton,
2651
- dataTestIdSecondaryButton,
2652
- dataTourSecondaryButton,
2653
- onClickSecondaryButton,
2654
- dataTestIdTertiaryButton,
2655
- dataTourTertiaryButton,
2656
- onClickTertiaryButton,
2657
- additionalProps = {},
2658
- buttonDirection = 'vertical',
2659
- buttonFill,
2660
- buttonGap,
2661
- buttonJustifyContent,
2662
- buttonPadding,
2663
- buttonPosition,
2664
- dataTestId,
2665
- dataTestIdButtons,
2666
- dataTour,
2667
- dataTourButtons,
2668
- disableFieldsAutoComplete = false,
2669
- fieldsGap,
2670
- formName,
2671
- groupGap,
2672
- language,
2673
- loader,
2674
- loaderFill,
2675
- loaderItemFill,
2676
- loaderShape,
2677
- loaderSize,
2678
- loaderText,
2679
- loaderType,
2680
- mutators,
2681
- notificationCloseButton,
2682
- notificationType,
2683
- renderFieldsWrapper = wrapperChildren => wrapperChildren,
2684
- validationSchema,
2685
- before,
2686
- after,
2687
- isLoading,
2688
- onChangeFormValues,
2689
- onSubmit
2690
- } = props;
2691
- const validate = useYupValidationSchema(validationSchema, language);
2692
- const onRefFormInstance = useCallback(formInstance => {
2693
- if (ref) {
2694
- ref.current = formInstance;
2695
- }
2696
- }, [ref]);
2697
- const propsGenerator = useDevicePropsGenerator(props);
2698
- const {
2699
- directionClass,
2700
- fillClass,
2701
- elevationClass,
2702
- shapeClass
2703
- } = propsGenerator;
2704
- const {
2705
- styles: formStyles,
2706
- wrapper: wrapperStyles
2707
- } = useStyles(props);
2708
- return /*#__PURE__*/React$1.createElement(Form, {
2709
- initialValues: initialValues,
2710
- initialValuesEqual: initialValuesEqual,
2711
- render: ({
2712
- submitError,
2713
- form,
2714
- handleSubmit,
2715
- modifiedSinceLastSubmit
2716
- }) => {
2717
- return /*#__PURE__*/React$1.createElement("form", {
2718
- className: clsx(className, 'form', type && `form_type_${type}`, buttonPosition && `form_button-position_${buttonPosition}`, directionClass, fillClass, shapeClass, elevationClass),
2719
- name: formName,
2720
- autoCapitalize: disableFieldsAutoComplete ? 'off' : undefined,
2721
- autoComplete: disableFieldsAutoComplete ? 'off' : undefined,
2722
- autoCorrect: disableFieldsAutoComplete ? 'off' : undefined,
2723
- "data-test-id": dataTestId,
2724
- "data-tour": dataTour
2725
- // We no need set reference to html element, we need reference to "final-form" instance
2726
- ,
2727
- ref: () => onRefFormInstance(form),
2728
- spellCheck: disableFieldsAutoComplete ? 'false' : undefined,
2729
- style: formStyles,
2730
- onSubmit: handleSubmit
2731
- }, before, title && /*#__PURE__*/React$1.createElement(Title, {
2732
- className: "form__title",
2733
- size: titleTextSize,
2734
- fill: titleFill,
2735
- textColor: titleTextColor,
2736
- textWeight: titleTextWeight
2737
- }, title), desc && /*#__PURE__*/React$1.createElement(Text, {
2738
- className: "form__desc",
2739
- size: descSize,
2740
- textColor: descTextColor,
2741
- textWeight: descTextWeight
2742
- }, desc), submitError && !modifiedSinceLastSubmit && /*#__PURE__*/React$1.createElement("div", {
2743
- className: clsx('notification', 'form-notification', notificationType ? `form-notification_type_${notificationType}` : 'form-notification_type_global')
2744
- }, /*#__PURE__*/React$1.createElement(NotificationItem, {
2745
- className: "form-notification__item",
2746
- title: form.getState().submitError,
2747
- titleTextSize: "h6",
2748
- status: "error",
2749
- closeButton: notificationCloseButton,
2750
- set: "form"
2751
- })), onChangeFormValues && /*#__PURE__*/React$1.createElement(FormSpy, {
2752
- subscription: {
2753
- values: true
2754
- },
2755
- onChange: onChangeFormValues
2756
- }), Boolean(Object.keys(config).length) && /*#__PURE__*/React$1.createElement(React$1.Fragment, null, renderFieldsWrapper(/*#__PURE__*/React$1.createElement(Group$1, {
2757
- className: "form__wrapper",
2758
- direction: "vertical",
2759
- gap: fieldsGap || groupGap,
2760
- style: wrapperStyles
2761
- }, Object.keys(config).map(key => generateField(config[key], {
2762
- key
2763
- }, additionalProps[config[key].name])), isLoading && (loader || /*#__PURE__*/React$1.createElement(Loader, {
2764
- className: "form__loader",
2765
- type: loaderType,
2766
- size: loaderSize,
2767
- fill: loaderFill,
2768
- text: loaderText,
2769
- itemFill: loaderItemFill,
2770
- shape: loaderShape
2771
- }))))), (primaryButtonLabel || primaryButton || secondaryButtonLabel || secondaryButton || tertiaryButton || tertiaryButtonLabel) && /*#__PURE__*/React$1.createElement(Group$1, {
2772
- className: "form__button",
2773
- direction: buttonDirection,
2774
- justifyContent: buttonJustifyContent,
2775
- fill: buttonFill,
2776
- padding: buttonPadding,
2777
- gap: buttonGap,
2778
- dataTestId: dataTestIdButtons,
2779
- dataTour: dataTourButtons
2780
- }, primaryButtonLabel ? /*#__PURE__*/React$1.createElement(Button, {
2781
- className: "form__button-item",
2782
- width: "fill",
2783
- size: primaryButtonSize,
2784
- fill: primaryButtonFill,
2785
- fillHover: primaryButtonFillHover,
2786
- label: primaryButtonLabel,
2787
- labelTextColor: primaryButtonLabelTextColor,
2788
- labelTextSize: primaryButtonLabelSize,
2789
- labelTextWeight: primaryButtonLabelTextWeight,
2790
- dataTestId: dataTestIdPrimaryButton,
2791
- dataTour: dataTourPrimaryButton
2792
- }) : primaryButton, secondaryButtonLabel ? /*#__PURE__*/React$1.createElement(Button, {
2793
- className: "form__button-item",
2794
- width: "fill",
2795
- size: secondaryButtonSize,
2796
- fill: secondaryButtonFill,
2797
- fillHover: secondaryButtonFillHover,
2798
- label: secondaryButtonLabel,
2799
- labelTextColor: secondaryButtonLabelTextColor,
2800
- labelTextSize: secondaryButtonLabelSize,
2801
- labelTextWeight: secondaryButtonLabelTextWeight,
2802
- dataTestId: dataTestIdSecondaryButton,
2803
- dataTour: dataTourSecondaryButton,
2804
- onClick: onClickSecondaryButton
2805
- }) : secondaryButton, tertiaryButtonLabel ? /*#__PURE__*/React$1.createElement(Button, {
2806
- className: "form__button-item",
2807
- width: "fill",
2808
- size: tertiaryButtonSize,
2809
- fill: tertiaryButtonFill,
2810
- fillHover: tertiaryButtonFillHover,
2811
- label: tertiaryButtonLabel,
2812
- labelTextColor: tertiaryButtonLabelTextColor,
2813
- labelTextSize: tertiaryButtonLabelSize,
2814
- labelTextWeight: tertiaryButtonLabelTextWeight,
2815
- dataTestId: dataTestIdTertiaryButton,
2816
- dataTour: dataTourTertiaryButton,
2817
- onClick: onClickTertiaryButton
2818
- }) : tertiaryButton), after);
2819
- },
2820
- decorators: [focusOnErrorDecorator],
2821
- mutators: mutators,
2822
- subscription: {
2823
- submitError: true,
2824
- modifiedSinceLastSubmit: true,
2825
- pristine: true,
2826
- submitting: true
2827
- },
2828
- validate: validate,
2829
- onSubmit: onSubmit
2830
- });
2831
- });
2832
- FinalForm.defaultProps = {
2833
- direction: 'vertical'
2834
- };
2835
-
2836
- const DEFAULT_MESSAGES_FIELDS = {
2837
- /*
2838
- !!! it also works without props simply based on the class and key as before `input_state_${meta.error.key}`
2839
- the KEY is needed for example for border color
2840
- the name of the key is anything you want, the main thing is that there is a props with the same KEY and color in FieldProps
2841
- ...example
2842
- required - KEY for yellow color
2843
- error - KEY for red color
2844
- custom or blue - KEY blue or other color
2845
- requiredBorderColor: 'warningBorderPrimary',
2846
- errorBorderColor: 'errorBorderPrimary',
2847
- customBorderColor: 'customBorderPrimary',
2848
- blueBorderColor: 'blueBorderPrimary',
2849
- const defaultFieldProps = {
2850
- messageTextSize: 's',
2851
- messageTextColor: 'surfaceTextSecondary',
2852
- requiredMessageTextSize: 's',
2853
- requiredMessageTextColor: 'warningTextPrimary',
2854
- errorMessageTextSize: 's',
2855
- errorMessageTextColor: 'errorTextPrimary',
2856
- }
2857
- // INPUT
2858
- const defaultInputProps = {
2859
- ... other
2860
- stateBorderColor: 'surfaceBorderTertiary',
2861
- requiredStateBorderColor: 'warningBorderPrimary',
2862
- errorStateBorderColor: 'errorBorderPrimary',
2863
- }
2864
- // RADIO
2865
- const defaultRadioProps = {
2866
- ... other
2867
- stateBorderColor: 'surfaceBorderTertiary',
2868
- requiredStateBorderColor: 'warningBorderPrimary',
2869
- errorStateBorderColor: 'errorBorderPrimary',
2870
- }
2871
- // SELECT
2872
- const defaultSelectProps = {
2873
- ... other
2874
- borderColor: 'surfaceBorderTertiary',
2875
- requiredBorderColor: 'warningBorderPrimary',
2876
- errorBorderColor: 'errorBorderPrimary',
2877
- inputBorderColor: 'surfaceBorderTertiary',
2878
- requiredInputBorderColor: 'warningBorderPrimary',
2879
- errorInputBorderColor: 'errorBorderPrimary',
2880
- }
2881
- ... etc
2882
- */
2883
-
2884
- // DEFAULT
2885
- // required - KEY for yellow color
2886
- // error - KEY for red color
2887
-
2888
- // key: 'required'
2889
- required: {
2890
- key: 'required',
2891
- message: 'Обязательное поле'
2892
- },
2893
- phone_required: {
2894
- key: 'required',
2895
- message: 'Укажите номер телефона'
2896
- },
2897
- email_required: {
2898
- key: 'required',
2899
- message: 'Укажите адрес электронной почты'
2900
- },
2901
- password_required: {
2902
- key: 'required',
2903
- message: 'Введите пароль'
2904
- },
2905
- phone_or_email_required: {
2906
- key: 'required',
2907
- message: 'Введите телефон или адрес эл. почты'
2908
- },
2909
- // key: 'error'
2910
- matches: {
2911
- key: 'error',
2912
- message: 'Допускается ввод только цифр от 0 до 9'
2913
- },
2914
- min: {
2915
- key: 'error',
2916
- message: ({
2917
- min
2918
- }) => `Значение должно быть не менее ${min} символов`
2919
- },
2920
- max: {
2921
- key: 'error',
2922
- message: ({
2923
- max
2924
- }) => `Значение должно быть не менее ${max} символов`
2925
- },
2926
- url: {
2927
- key: 'error',
2928
- message: 'Введите корректный URL-адрес'
2929
- },
2930
- invalid_value: {
2931
- key: 'error',
2932
- message: 'Некорректное значение'
2933
- },
2934
- numeric_value: {
2935
- key: 'error',
2936
- message: 'Только числовое значение'
2937
- },
2938
- phone_error: {
2939
- key: 'error',
2940
- message: 'Введите корректный номер телефона'
2941
- },
2942
- email_error: {
2943
- key: 'error',
2944
- message: 'Введите корректный адрес электронной почты'
2945
- }
2946
- };
2947
-
2948
- const parseNumericField = value => {
2949
- const numberValue = value.slice(0, 10).replace(/,/g, '.').replace(/[^\d.]/g, '');
2950
- const parsedValue = parseFloat(numberValue);
2951
- if (parsedValue || parsedValue === 0) {
2952
- if (numberValue.endsWith('.')) {
2953
- if ((numberValue.match(/\./g) || []).length > 1) {
2954
- return numberValue.slice(0, -1);
2955
- }
2956
- return numberValue;
2957
- }
2958
- return numberValue;
2959
- }
2960
- return '';
2961
- };
2962
-
2963
- // const getErrorsForFinalForm = (errorData) => {
2964
- // /*
2965
- // * errorData - its an "axios" error
2966
- // */
2967
-
2968
- // const formErrors = {}
2969
-
2970
- // const responseErrorMessage = errorData.toJSON ? errorData.toJSON().message : errorData.message
2971
-
2972
- // // const status = (errorData.response && errorData.response.status) || null
2973
- // const problemError = getProblemFromError(errorData)
2974
- // // const problemStatus = getProblemFromStatus(status)
2975
-
2976
- // if (problemError === NETWORK_ERROR || problemError === CONNECTION_ERROR) {
2977
- // // Say to "react-final-form" that we have general error
2978
- // formErrors[FORM_ERROR] = 'Проблемы с подключением к сервису'
2979
- // } else if (errorData.response?.data) {
2980
- // // Collect errors for some fields, which in the response from server
2981
- // const serverErrors = errorData.response.data
2982
- // if (typeof serverErrors === 'string') {
2983
- // if (errorData.response.status === 500) {
2984
- // formErrors[FORM_ERROR] =
2985
- // 'Во время обработки запроса произошла ошибка, попробуйте повторить запрос'
2986
- // }
2987
- // // formErrors[FORM_ERROR] = responseErrorMessage
2988
- // } else {
2989
- // if (errorData.response.status === 500) {
2990
- // formErrors[FORM_ERROR] =
2991
- // 'Во время обработки запроса произошла ошибка, попробуйте повторить запрос'
2992
- // }
2993
- // for (const key in serverErrors) {
2994
- // // TODO: what is forms has "detail" field? show as form error is well?
2995
- // const errorFieldKey = key === 'non_field_errors' || key === 'detail' ? FORM_ERROR : key
2996
- // // Say to "react-final-form" that we have some fields errors
2997
- // formErrors[errorFieldKey] = castArray(serverErrors[key])[0]
2998
- // }
2999
- // }
3000
- // } else if (typeof errorData === 'object' && Object.keys(errorData).length) {
3001
- // for (const key in errorData) {
3002
- // const errorFieldKey = key === 'non_field_errors' || key === 'detail' ? FORM_ERROR : key
3003
- // // Say to "react-final-form" that we have some fields errors
3004
- // formErrors[errorFieldKey] = castArray(errorData[key])[0]
3005
- // }
3006
- // } else {
3007
- // // Say to "react-final-form" that we have general error
3008
- // formErrors[FORM_ERROR] = responseErrorMessage || 'Произошла ошибка'
3009
- // }
3010
-
3011
- // return formErrors
3012
- // }
3013
-
3014
- const getErrorsForFinalForm = error => {
3015
- /*
3016
- * error - its an "axios" error in many cases
3017
- */
3018
-
3019
- const formErrors = {};
3020
- const serverErrors = error.response?.data;
3021
- if (serverErrors) {
3022
- // Collect errors for some fields, which in the response from server
3023
- if (typeof serverErrors === 'string') {
3024
- // Server may send an html page as error data
3025
- formErrors[FORM_ERROR] = 'Во время обработки запроса произошла ошибка, попробуйте повторить запрос';
3026
- } else {
3027
- for (const key in serverErrors) {
3028
- // "non_field_errors" and "detail" is special keys in django to mark errors not for fields
3029
- const errorFieldKey = key === 'non_field_errors' || key === 'detail' ? FORM_ERROR : key;
3030
-
3031
- // Say to "react-final-form" that we have some fields errors
3032
- formErrors[errorFieldKey] = castArray(serverErrors[key])[0];
3033
- }
3034
- }
3035
- } else {
3036
- // const responseErrorMessage = error.toJSON
3037
- // ? error.toJSON().message
3038
- // : error.message
3039
-
3040
- // Say to "react-final-form" that we have general error
3041
- formErrors[FORM_ERROR] = error.message || 'Произошла ошибка';
3042
- }
3043
- return formErrors;
3044
- };
3045
-
3046
- export { CheckboxField, ChipsField, ChoiceField, CodeField, CustomField, DEFAULT_MESSAGES_FIELDS, DatePickerField, FieldWrapper, FieldWrapperBase, FileInput, FinalForm, Group, InputField, MaskedInputField, RadioGroup, SegmentedField, SelectField, SwitchField, TextareaField, addRequiredFieldsParamToSchema, dateValidation, defaultCheckboxProps, defaultChipsProps, defaultChoiceProps, defaultCodeProps, defaultDatepickerProps, defaultDropzoneProps, defaultFieldProps, defaultInputProps, defaultRadioProps, defaultSegmentedProps, defaultSelectProps, defaultSwitchProps, defaultTextareaProps, emailValidation, focusOnError, focusOnErrorDecorator, formTypes, generateField, getErrorsForFinalForm, parseNumericField, phoneValidation, sendFormDataToServer, setErrorsMutator, useYupValidationSchema };