@itcase/forms 1.1.24 → 1.1.27

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,21 +1,16 @@
1
1
  import { isPossiblePhoneNumber } from 'libphonenumber-js';
2
- import React$1, { useMemo, useEffect, useCallback, useState } from 'react';
2
+ import React$1, { useMemo, useEffect, useState, useCallback } from 'react';
3
3
  import { setIn, FORM_ERROR, getIn } from 'final-form';
4
4
  import { useForm, Field, Form, FormSpy } from 'react-final-form';
5
5
  export { Field, useForm, useFormState } from 'react-final-form';
6
6
  import clsx from 'clsx';
7
- import { Checkbox } from '@itcase/ui/components/Checkbox';
7
+ import { useDevicePropsGenerator } from '@itcase/ui/hooks/useDevicePropsGenerator';
8
+ import camelCase from 'lodash/camelCase';
9
+ import snakeCase from 'lodash/snakeCase';
8
10
  import { Divider } from '@itcase/ui/components/Divider';
9
11
  import { Text } from '@itcase/ui/components/Text';
10
12
  import { useDeviceTargetClass } from '@itcase/ui/hooks/useDeviceTargetClass';
11
13
  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
14
  import axios from 'axios';
20
15
  import { fromEvent } from 'file-selector';
21
16
  import castArray from 'lodash/castArray';
@@ -24,15 +19,21 @@ import { createFileFromDataURL } from '@itcase/common';
24
19
  import { Button } from '@itcase/ui/components/Button';
25
20
  import { Loader } from '@itcase/ui/components/Loader';
26
21
  import { Title } from '@itcase/ui/components/Title';
22
+ import { Checkbox } from '@itcase/ui/components/Checkbox';
23
+ import { ChipsGroup, Chips } from '@itcase/ui/components/Chips';
24
+ import { Choice } from '@itcase/ui/components/Choice';
25
+ import { Code } from '@itcase/ui/components/Code';
26
+ import { Icon } from '@itcase/ui/components/Icon';
27
+ import { DatePickerInput } from '@itcase/ui/components/DatePicker';
27
28
  import { Input } from '@itcase/ui/components/Input';
28
- import { Radio } from '@itcase/ui/components/Radio';
29
+ import { icons24 } from '@itcase/icons/default';
29
30
  import { Segmented } from '@itcase/ui/components/Segmented';
30
31
  import { Select } from '@itcase/ui/components/Select';
31
32
  import { Switch } from '@itcase/ui/components/Switch';
32
33
  import { Textarea } from '@itcase/ui/components/Textarea';
33
34
  import { useIMask } from 'react-imask';
34
- import { ChipsGroup, Chips } from '@itcase/ui/components/Chips';
35
- import { Group as Group$1 } from '@itcase/ui/components/Group';
35
+ import { Radio } from '@itcase/ui/components/Radio';
36
+ import { Group } from '@itcase/ui/components/Group';
36
37
  import { Notification } from '@itcase/ui/components/Notification';
37
38
  import createDecorator from 'final-form-focus';
38
39
 
@@ -116,29 +117,149 @@ function useYupValidationSchema(schema, language) {
116
117
  return validate;
117
118
  }
118
119
 
120
+ // Whether to display an error message based on "fieldProps" and meta-objects
121
+ function useFieldValidationState(props) {
122
+ const {
123
+ fieldProps = {},
124
+ meta = {},
125
+ input = {}
126
+ } = props;
127
+ // Determines if there's a submission error that hasn't been rectified since the last submission.
128
+ const submitError = !meta.modifiedSinceLastSubmit && meta.submitError;
129
+
130
+ // Determines a key for the error, defaulting to 'error' if no specific key is found.
131
+ const errorKey = meta.error?.key || 'error';
132
+ const successKey = 'success';
133
+
134
+ // Determines if the field is in an error state based on various conditions.
135
+ const isErrorState = useMemo(() => {
136
+ if (fieldProps.showErrorsOnSubmit) {
137
+ return Boolean(meta.submitFailed && meta.touched && (meta.error || submitError));
138
+ } else {
139
+ return Boolean(meta.touched && (meta.error || submitError));
140
+ }
141
+ }, [fieldProps.showErrorsOnSubmit, meta.submitFailed, meta.touched, meta.error, submitError]);
142
+
143
+ // Determines if the field's input state is valid
144
+ const isValidState = useMemo(() => {
145
+ const hasValue = Array.isArray(input?.value) ? input?.value.length : input?.value;
146
+ const isModifiedAfterSubmit = meta.modifiedSinceLastSubmit && !meta.error && submitError;
147
+ return Boolean(hasValue && (meta.valid || isModifiedAfterSubmit));
148
+ }, [input?.value, meta.valid, meta.error, submitError, meta.modifiedSinceLastSubmit]);
149
+ const errorMessage = useMemo(() => {
150
+ // If final-form field has error in "meta" render-property.
151
+ // If field not modified after last form submit - use submit error
152
+ const error = meta.error || submitError || false;
153
+ if (error) {
154
+ // And error in "meta" is string
155
+ if (typeof error === 'string') {
156
+ // Return error as message
157
+ return error;
158
+ }
159
+ // Or if error in "meta" has "message" property(is object of error)
160
+ if (error.message) {
161
+ // Return message from error
162
+ return error.message;
163
+ }
164
+ }
165
+
166
+ // Field doesn't have error message
167
+ return '';
168
+ }, [meta.error, submitError]);
169
+ return {
170
+ errorKey,
171
+ successKey,
172
+ isErrorState,
173
+ isValidState,
174
+ errorMessage
175
+ };
176
+ }
177
+
178
+ // This hook changes the props of the child component depending on the type of error,
179
+ // looks at what props were in initialProps, if they are there then changes
180
+ function useValidationAppearanceInputProps(props) {
181
+ const {
182
+ validationStateKey,
183
+ inputProps
184
+ } = props;
185
+
186
+ // TODO: need to add props that can change during errors in this field
187
+ const validationAppearanceInputProps = useMemo(() => {
188
+ // const resultAppearanceProps = {
189
+ // messageTextColor: props.errorMessageTextColor,
190
+ // messageTextSize: props.errorMessageTextSize,
191
+ // messageTextWeight: props.errorMessageTextWeight,
192
+ // // Override appearance(styled) props for child input
193
+ // inputProps: {},
194
+ // }
195
+ const updatedInputProps = {};
196
+ if (validationStateKey) {
197
+ Object.entries(inputProps).forEach(([propKey, propValue]) => {
198
+ // Convert the input property key to "snake_case" format.
199
+ // e.g. "requiredBorderColor" -> "required_border_color".
200
+ const propKeySnake = snakeCase(propKey);
201
+ // Check if this property is for appearance.
202
+ // Key maybe starts with: "error", "required", "success", etc from validation config.
203
+ const isPropForValidationState = propKeySnake.startsWith(`${validationStateKey}_`);
204
+
205
+ // If property is for appearance
206
+ if (isPropForValidationState) {
207
+ // Remove validation state part from begin of property key, to make clean appearance property.
208
+ // e.g. "required_border_color" -> "border_color".
209
+ const stateTargetKeySnake = propKeySnake.replace(`${validationStateKey}_`, '');
210
+ // Convert clean appearance property key to "camelCase" format.
211
+ // e.g. "border_color" -> "borderColor"
212
+ const stateTargetKey = camelCase(stateTargetKeySnake);
213
+ // And save the value with a new clean property key
214
+ updatedInputProps[stateTargetKey] = propValue;
215
+ // Else if not already added earlier
216
+ } else if (!updatedInputProps[propKey]) {
217
+ // Just save original property
218
+ updatedInputProps[propKey] = propValue;
219
+ }
220
+ });
221
+ }
222
+ return updatedInputProps;
223
+ }, [validationStateKey, inputProps]);
224
+ return validationAppearanceInputProps;
225
+ }
226
+
119
227
  const defaultFieldProps = {
120
228
  width: 'fill',
121
229
  direction: 'vertical',
122
- size: 'm',
123
230
  labelTextColor: 'surfaceTextPrimary',
124
- labelTextSize: 's',
125
231
  messageTextColor: 'surfaceTextSecondary',
126
- messageTextSize: 's',
127
232
  errorMessageTextColor: 'errorTextSecondary',
128
- errorMessageTextSize: 's',
129
233
  dividerFill: 'errorPrimary',
130
234
  helpTextColor: 'surfaceTextQuaternary',
131
- helpTextSize: 's',
132
235
  requiredMessageTextColor: 'warningTextSecondary',
133
- requiredMessageTextSize: 's',
134
236
  showMessage: true
135
237
  };
238
+ const defaultFieldSizeM = {
239
+ size: 'm',
240
+ labelTextSize: 's',
241
+ messageTextSize: 's',
242
+ errorMessageTextSize: 's',
243
+ helpTextSize: 's',
244
+ requiredMessageTextSize: 's',
245
+ ...defaultFieldProps
246
+ };
247
+ const defaultFieldSizeXL = {
248
+ size: 'xl',
249
+ labelTextSize: 's',
250
+ messageTextSize: 's',
251
+ errorMessageTextSize: 's',
252
+ helpTextSize: 's',
253
+ requiredMessageTextSize: 's',
254
+ ...defaultFieldProps
255
+ };
136
256
 
137
257
  function FieldWrapperBase(props) {
138
258
  const {
139
259
  id,
260
+ dataTour,
140
261
  className,
141
- type = 'normal',
262
+ type,
142
263
  label,
143
264
  labelHidden,
144
265
  labelTextColor,
@@ -146,6 +267,7 @@ function FieldWrapperBase(props) {
146
267
  labelTextSizeMobile,
147
268
  labelTextSizeTablet,
148
269
  labelTextWeight,
270
+ messageTextSize,
149
271
  desc,
150
272
  descTextColor,
151
273
  descTextSize,
@@ -158,7 +280,6 @@ function FieldWrapperBase(props) {
158
280
  isDisabled,
159
281
  afterItem,
160
282
  beforeItem,
161
- dataTour,
162
283
  dividerDirection,
163
284
  dividerFill,
164
285
  dividerSize,
@@ -171,7 +292,6 @@ function FieldWrapperBase(props) {
171
292
  helpTextWeight,
172
293
  inputName,
173
294
  inputValue,
174
- messageTextSize,
175
295
  metaActive,
176
296
  showDivider,
177
297
  showMessage,
@@ -220,13 +340,13 @@ function FieldWrapperBase(props) {
220
340
  const errorTextColor = props[`${errorKey}MessageTextColor`];
221
341
  const errorTextWeight = props[`${errorKey}MessageTextWeight`];
222
342
  return /*#__PURE__*/React$1.createElement(Tag, {
343
+ dataTestId: `${inputName}Field`,
344
+ dataTour: dataTour,
223
345
  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),
224
- "data-test-id": `${inputName}Field`,
225
- "data-tour": dataTour,
226
346
  style: formFieldStyles
227
347
  }, before, (label || labelHidden) && /*#__PURE__*/React$1.createElement("div", {
348
+ dataTestId: `${inputName}FieldLabel`,
228
349
  className: clsx('form-field__label'),
229
- "data-test-id": `${inputName}FieldLabel`,
230
350
  htmlFor: id
231
351
  }, /*#__PURE__*/React$1.createElement(Text, {
232
352
  size: labelTextSize,
@@ -236,7 +356,7 @@ function FieldWrapperBase(props) {
236
356
  sizeTablet: labelTextSizeTablet
237
357
  }, label, labelHidden && '\u00A0')), desc && /*#__PURE__*/React$1.createElement("div", {
238
358
  className: "form-field__desc",
239
- "data-test-id": `${inputName}FieldDesc`
359
+ dataTestId: `${inputName}FieldDesc`
240
360
  }, /*#__PURE__*/React$1.createElement(Text, {
241
361
  size: descTextSize,
242
362
  textColor: descTextColor,
@@ -252,26 +372,26 @@ function FieldWrapperBase(props) {
252
372
  size: dividerSize,
253
373
  fill: dividerFill
254
374
  })), showMessage && /*#__PURE__*/React$1.createElement("div", {
255
- className: "form-field__message",
256
- "data-test-id": `${inputName}FieldMessage`
375
+ dataTestId: `${inputName}FieldMessage`,
376
+ className: "form-field__message"
257
377
  }, isErrorState && errorMessage && /*#__PURE__*/React$1.createElement(Text, {
258
378
  id: `${inputName}-error`,
379
+ dataTestId: `${inputName}FieldMessageError`,
259
380
  className: "form-field__message-item form-field__message-item_type-error",
260
381
  size: errorTextSize,
261
382
  textColor: errorTextColor,
262
- textWeight: errorTextWeight,
263
- dataTestId: `${inputName}FieldMessageError`
383
+ textWeight: errorTextWeight
264
384
  }, errorMessage), Boolean(helpText) && (!isErrorState || !errorMessage) && /*#__PURE__*/React$1.createElement(Text, {
385
+ dataTestId: `${inputName}FieldMessageHelpText`,
265
386
  className: "form-field__message-item form-field__message-item_type_help-text",
266
387
  size: helpTextSize,
267
388
  textColor: isValidState ? helpTextColorSuccess : helpTextColor,
268
389
  textWeight: helpTextWeight,
269
- dataTestId: `${inputName}FieldMessageHelpText`,
270
390
  sizeMobile: helpTextSizeMobile
271
391
  }, helpText), (!isErrorState && !helpText || isErrorState && !helpText && !errorMessage) && /*#__PURE__*/React$1.createElement(Text, {
392
+ dataTestId: `${inputName}FieldMessageHelpText`,
272
393
  className: "form-field__message-item form-field__message-item_type_help-text",
273
- size: messageTextSize,
274
- dataTestId: `${inputName}FieldMessageHelpText`
394
+ size: messageTextSize
275
395
  }, '\u00A0')), after);
276
396
  }
277
397
  function FieldWrapper(props) {
@@ -290,242 +410,425 @@ function FieldWrapper(props) {
290
410
  return /*#__PURE__*/React$1.createElement(FieldWrapperBase, props);
291
411
  }
292
412
 
293
- // Whether to display an error message based on "fieldProps" and meta-objects
294
- function useFieldValidationState(props) {
413
+ const defaultDropzoneProps = {
414
+ fill: 'surfacePrimary',
415
+ borderColor: 'surfaceBorderTertiary',
416
+ borderColorHover: 'surfaceBorderQuaternary',
417
+ hintTitle: 'Перетащите изображение или выберите файл с компьютера',
418
+ hintTitleTextColor: 'surfaceTextPrimary',
419
+ hintTitleTextSize: 'm',
420
+ removeThumbText: 'удалить',
421
+ removeThumbTextColor: 'errorTextPrimary',
422
+ removeThumbTextHoverColor: 'errorTextPrimaryHover',
423
+ removeThumbTextSize: 's',
424
+ shape: 'rounded',
425
+ showFilename: true,
426
+ thumbBorderColor: 'surfaceBorderTertiary',
427
+ thumbBorderColorHover: 'surfaceBorderQuaternary',
428
+ thumbBorderWidth: 1,
429
+ thumbNameTextColor: 'surfaceTextPrimary',
430
+ thumbNameTextSize: 's',
431
+ isPreviews: true
432
+ };
433
+
434
+ const FileInputDropzone = /*#__PURE__*/React$1.memo(function FileInputDropzone(props) {
295
435
  const {
296
- fieldProps = {},
297
- meta = {},
298
- input = {}
436
+ className,
437
+ maxFiles,
438
+ maxSize,
439
+ size,
440
+ fileErrorText,
441
+ dropzoneProps = {},
442
+ hintDescription,
443
+ hintTitle,
444
+ inputName,
445
+ inputValue,
446
+ showFilename,
447
+ thumbColumn,
448
+ isPreviews,
449
+ onAddFiles,
450
+ onDeleteFile
299
451
  } = props;
300
- // Determines if there's a submission error that hasn't been rectified since the last submission.
301
- const submitError = !meta.modifiedSinceLastSubmit && meta.submitError;
302
452
 
303
- // Determines a key for the error, defaulting to 'error' if no specific key is found.
304
- const errorKey = meta.error?.key || 'error';
305
- const successKey = 'success';
453
+ // TODO: delete react-final-form things out of here?
454
+ const {
455
+ change
456
+ } = useForm();
457
+ const [fileError, setFileError] = useState('');
458
+ const [fileIsLoading, setFileIsLoading] = useState(false);
459
+ const filesList = useMemo(() => inputValue ? castArray(inputValue) : [], [inputValue]);
460
+ const changeFormState = useCallback(newFiles => {
461
+ // If max files in dropzone is 1 - return file as it self, else as array of files
462
+ // ps: for old projects compatibility
463
+ const toSave = dropzoneProps.maxFiles == 1 ? newFiles[0] : newFiles;
464
+ change(inputName, toSave);
465
+ return toSave;
466
+ },
467
+ // If "inputName" will be changes, then it should be a different field
468
+ // eslint-disable-next-line react-hooks/exhaustive-deps
469
+ [dropzoneProps, change]);
306
470
 
307
- // Determines if the field is in an error state based on various conditions.
308
- const isErrorState = useMemo(() => {
309
- if (fieldProps.showErrorsOnSubmit) {
310
- return Boolean(meta.submitFailed && meta.touched && (meta.error || submitError));
311
- } else {
312
- return Boolean(meta.touched && (meta.error || submitError));
471
+ //
472
+ const convertFiledValueAndSaveAsFiles = useCallback(async currentFilesList => {
473
+ setFileIsLoading(true);
474
+ const newFiles = [];
475
+ for (const fileItem of currentFilesList) {
476
+ if (typeof fileItem === 'string') {
477
+ const newFile = await convertToFile(fileItem, isPreviews);
478
+ if (newFile) {
479
+ newFiles.push(newFile);
480
+ }
481
+ } else {
482
+ newFiles.push(fileItem);
483
+ }
313
484
  }
314
- }, [fieldProps.showErrorsOnSubmit, meta.submitFailed, meta.touched, meta.error, submitError]);
485
+ changeFormState(newFiles);
486
+ setFileIsLoading(false);
487
+ }, [isPreviews, changeFormState]);
315
488
 
316
- // Determines if the field's input state is valid
317
- const isValidState = useMemo(() => {
318
- const hasValue = Array.isArray(input?.value) ? input?.value.length : input?.value;
319
- const isModifiedAfterSubmit = meta.modifiedSinceLastSubmit && !meta.error && submitError;
320
- return Boolean(hasValue && (meta.valid || isModifiedAfterSubmit));
321
- }, [input?.value, meta.valid, meta.error, submitError, meta.modifiedSinceLastSubmit]);
322
- const errorMessage = useMemo(() => {
323
- // If final-form field has error in "meta" render-property.
324
- // If field not modified after last form submit - use submit error
325
- const error = meta.error || submitError || false;
326
- if (error) {
327
- // And error in "meta" is string
328
- if (typeof error === 'string') {
329
- // Return error as message
330
- return error;
331
- }
332
- // Or if error in "meta" has "message" property(is object of error)
333
- if (error.message) {
334
- // Return message from error
335
- return error.message;
336
- }
489
+ // Delete file from dropzone
490
+ const removeFile = useCallback((event, index) => {
491
+ event.stopPropagation();
492
+ event.preventDefault();
493
+ const newFiles = [...filesList];
494
+ newFiles.splice(index, 1);
495
+ if (onDeleteFile) {
496
+ onDeleteFile(filesList[index], inputName);
337
497
  }
498
+ changeFormState(newFiles);
499
+ },
500
+ // If "inputName" will be changes, then it should be a different field
501
+ // eslint-disable-next-line react-hooks/exhaustive-deps
502
+ [filesList, changeFormState, onDeleteFile]);
338
503
 
339
- // Field doesn't have error message
340
- return '';
341
- }, [meta.error, submitError]);
342
- return {
343
- errorKey,
344
- successKey,
345
- isErrorState,
346
- isValidState,
347
- errorMessage
348
- };
349
- }
350
-
351
- // This hook changes the props of the child component depending on the type of error,
352
- // looks at what props were in initialProps, if they are there then changes
353
- function useValidationAppearanceInputProps(props) {
504
+ // Create dropzone options
354
505
  const {
355
- validationStateKey,
356
- inputProps
357
- } = props;
358
-
359
- // TODO: need to add props that can change during errors in this field
360
- const validationAppearanceInputProps = useMemo(() => {
361
- // const resultAppearanceProps = {
362
- // messageTextColor: props.errorMessageTextColor,
363
- // messageTextSize: props.errorMessageTextSize,
364
- // messageTextWeight: props.errorMessageTextWeight,
365
- // // Override appearance(styled) props for child input
366
- // inputProps: {},
367
- // }
368
- const updatedInputProps = {};
369
- if (validationStateKey) {
370
- Object.entries(inputProps).forEach(([propKey, propValue]) => {
371
- // Convert the input property key to "snake_case" format.
372
- // e.g. "requiredBorderColor" -> "required_border_color".
373
- const propKeySnake = snakeCase(propKey);
374
- // Check if this property is for appearance.
375
- // Key maybe starts with: "error", "required", "success", etc from validation config.
376
- const isPropForValidationState = propKeySnake.startsWith(`${validationStateKey}_`);
506
+ getInputProps,
507
+ getRootProps
508
+ } = useDropzone({
509
+ maxFiles: maxFiles || 5,
510
+ maxSize: maxSize || 10485760,
511
+ // 10mb
512
+ // accept: { 'image/*': [] },
513
+ ...dropzoneProps,
514
+ getFilesFromEvent: async event => {
515
+ const result = await fromEvent(event);
516
+ const newFiles = result.filter(item => item instanceof File);
517
+ // Add exists and new files to accepted(or rejected)
518
+ return [...filesList, ...newFiles];
519
+ },
520
+ onDropAccepted: acceptedFiles => {
521
+ // If dropped files has accepted and we need a previews
522
+ if (isPreviews) {
523
+ // Add preview to every file
524
+ acceptedFiles.forEach(file => {
525
+ if (!file.error) {
526
+ file.preview = URL.createObjectURL(file);
527
+ }
528
+ });
529
+ }
530
+ // Save to form data (including empty when files are not valid)
531
+ const filesToSave = changeFormState(acceptedFiles);
532
+ setFileError('');
377
533
 
378
- // If property is for appearance
379
- if (isPropForValidationState) {
380
- // Remove validation state part from begin of property key, to make clean appearance property.
381
- // e.g. "required_border_color" -> "border_color".
382
- const stateTargetKeySnake = propKeySnake.replace(`${validationStateKey}_`, '');
383
- // Convert clean appearance property key to "camelCase" format.
384
- // e.g. "border_color" -> "borderColor"
385
- const stateTargetKey = camelCase(stateTargetKeySnake);
386
- // And save the value with a new clean property key
387
- updatedInputProps[stateTargetKey] = propValue;
388
- // Else if not already added earlier
389
- } else if (!updatedInputProps[propKey]) {
390
- // Just save original property
391
- updatedInputProps[propKey] = propValue;
534
+ // Save DataURL for all files
535
+ const readerPromisesList = acceptedFiles.map(file => {
536
+ return new Promise(resolve => setFileDataURL(file, resolve));
537
+ });
538
+ // Save files to form values
539
+ Promise.all(readerPromisesList).then(() => {
540
+ if (onAddFiles) {
541
+ onAddFiles(filesToSave, inputName);
392
542
  }
393
543
  });
394
- }
395
- return updatedInputProps;
396
- }, [validationStateKey, inputProps]);
397
- return validationAppearanceInputProps;
398
- }
399
-
400
- const defaultCheckboxProps = {
401
- appearance: 'defaultPrimary',
402
- width: 'fill',
403
- errorBorderColor: 'errorBorderSecondary',
404
- requiredBorderColor: 'warningBorderSecondary'
405
- };
406
-
407
- const CheckboxField = /*#__PURE__*/React$1.memo(function CheckboxField(props) {
408
- const {
409
- name,
410
- initialValue,
411
- isDisabled,
412
- classNameGroupItem,
413
- fieldProps = {},
414
- inputProps = {},
415
- showMessage,
416
- isRequired,
417
- onChange
418
- } = props;
419
- return /*#__PURE__*/React$1.createElement(Field, {
420
- type: "checkbox",
421
- name: name,
422
- initialValue: initialValue
423
- }, function Render({
424
- input,
425
- meta
426
- }) {
427
- /** Note:
428
- * Create "Render" function by "eslint-react-hooks/rules-of-hooks":
429
- * React Hooks cannot be called inside a callback.
430
- * React Hooks must be called in a React function component or a
431
- * custom React Hook function.
432
- */
433
-
434
- const onChangeField = useCallback(event => {
435
- input.onChange(event);
436
- if (onChange) {
437
- onChange(event.target.checked, input.name);
544
+ },
545
+ onDropRejected: rejectedFiles => {
546
+ // If dropped files has rejected
547
+ if (rejectedFiles.length) {
548
+ let fileErrorMessage = 'Ошибка при добавлении файла';
549
+ const firstFileErrorItem = rejectedFiles[0].errors[0];
550
+ if (firstFileErrorItem) {
551
+ if (firstFileErrorItem.code === ErrorCode.TooManyFiles) {
552
+ fileErrorMessage = `Максимальное количество файлов: ${maxFiles}`;
553
+ } else {
554
+ fileErrorMessage = firstFileErrorItem.message;
555
+ }
556
+ }
557
+ // Show error
558
+ setFileError(fileErrorMessage);
559
+ } else {
560
+ // Else clean error
561
+ setFileError('');
438
562
  }
439
- }, [onChange, input.onChange]);
440
- const {
441
- errorKey,
442
- errorMessage,
443
- isErrorState,
444
- isValidState
445
- } = useFieldValidationState({
446
- fieldProps: fieldProps,
447
- input: input,
448
- meta: meta
449
- });
450
- const updatedInputProps = useValidationAppearanceInputProps({
451
- inputProps: inputProps,
452
- validationStateKey: isErrorState ? errorKey : 'success'
453
- });
454
- return /*#__PURE__*/React$1.createElement(FieldWrapper, Object.assign({
455
- className: clsx('form-field_type_checkbox', 'form__item_type_checkbox', classNameGroupItem),
456
- errorKey: errorKey,
457
- errorMessage: errorMessage,
458
- isErrorState: isErrorState,
459
- metaError: meta.error,
460
- isDisabled: isDisabled,
461
- fieldClassName: "form-checkbox",
462
- inputName: input.name,
463
- inputValue: input.checked,
464
- metaActive: meta.active,
465
- showMessage: showMessage,
466
- tag: "label",
467
- isRequired: isRequired,
468
- isValidState: isValidState
469
- }, fieldProps), /*#__PURE__*/React$1.createElement(Checkbox, Object.assign({
470
- type: "checkbox",
471
- name: input.name,
472
- isDisabled: isDisabled,
473
- autoComplete: "nope",
474
- checked: input.checked,
475
- onBlur: input.onBlur,
476
- onChange: onChangeField,
477
- onFocus: input.onFocus
478
- }, updatedInputProps)));
563
+ }
479
564
  });
480
- });
481
-
482
- const defaultChoiceProps = {
483
- width: 'fill',
484
- borderColor: 'surfaceBorderTertiary',
485
- // error
486
- errorBorderColor: 'errorBorderPrimary',
487
- fill: 'surfaceSecondary',
488
- fillActive: 'accentPrimary',
489
- fillActiveDisabled: 'surfaceTertiary',
490
- fillHover: 'surfacePrimaryHover',
491
- indicatorFill: 'accentPrimary',
492
- labelTextActiveColor: 'accentTextPrimary',
493
- labelTextActiveColorDisabled: 'surfaceTextDisabled',
494
- labelTextColor: 'surfaceTextPrimary',
495
- labelTextColorDisabled: 'surfaceTextDisabled',
496
- labelTextSize: 'm',
497
- requiredBorderColor: 'warningBorderPrimary',
498
- shape: 'rounded'
499
- };
565
+ useEffect(() => {
566
+ const currentFilesList = castArray(inputValue);
567
+ const isNeedToConvert = currentFilesList.some(fileItem => typeof fileItem === 'string');
568
+ if (isNeedToConvert) {
569
+ // First time convert value to Files and save to local and form state
570
+ convertFiledValueAndSaveAsFiles(currentFilesList);
571
+ }
500
572
 
501
- const ChoiceField = /*#__PURE__*/React$1.memo(function ChoiceField(props) {
502
- const {
503
- name,
504
- initialValue,
505
- label,
506
- isDisabled,
507
- classNameGroupItem,
508
- fieldProps,
509
- inputProps,
510
- messageType,
511
- options,
512
- placeholder,
513
- showMessage,
514
- isCheckbox,
515
- isRequired,
516
- onChange
517
- } = props;
573
+ // Make sure to revoke the data uris to avoid memory leaks, will run on unmount
574
+ return () => {
575
+ filesList.forEach(file => {
576
+ if (file?.preview) {
577
+ URL.revokeObjectURL(file.preview);
578
+ }
579
+ });
580
+ };
581
+ // eslint-disable-next-line react-hooks/exhaustive-deps
582
+ }, [inputValue]);
583
+ const propsGenerator = useDevicePropsGenerator(props);
518
584
  const {
519
- change
520
- } = useForm();
521
- const setActiveSegment = useCallback((option, isChecked) => {
522
- change(name, isChecked && option.value);
523
- if (onChange) {
524
- onChange(option.value, name, isChecked);
585
+ fillClass,
586
+ fillHoverClass,
587
+ borderColorClass,
588
+ borderColorHoverClass,
589
+ borderTypeClass,
590
+ borderWidthClass,
591
+ errorMessageTextColor,
592
+ errorMessageTextSize,
593
+ errorMessageTextWeight,
594
+ hintDescriptionTextColor,
595
+ hintDescriptionTextSize,
596
+ hintDescriptionTextWeight,
597
+ hintDescriptionTextWrap,
598
+ hintTitleTextColor,
599
+ hintTitleTextSize,
600
+ hintTitleTextWeight,
601
+ hintTitleTextWrap,
602
+ removeThumbAppearance,
603
+ removeThumbShape,
604
+ removeThumbText,
605
+ removeThumbTextWeight,
606
+ shapeClass,
607
+ thumbBorderColorClass,
608
+ thumbBorderColorHoverClass,
609
+ thumbBorderTypeClass,
610
+ thumbBorderWidthClass,
611
+ thumbDirectionClass,
612
+ thumbNameTextColor,
613
+ thumbNameTextSize,
614
+ thumbNameTextWeight,
615
+ thumbNameTextWrap
616
+ } = propsGenerator;
617
+ return /*#__PURE__*/React$1.createElement(React$1.Fragment, null, /*#__PURE__*/React$1.createElement("div", getRootProps({
618
+ className: `form-dropzone__dropzone dropzone ${className} form-dropzone__dropzone_size_${size} ${shapeClass}`
619
+ }), /*#__PURE__*/React$1.createElement("input", Object.assign({}, getInputProps(), {
620
+ name: inputName
621
+ })), /*#__PURE__*/React$1.createElement("div", {
622
+ className: clsx('form-dropzone__dropzone-wrapper', thumbColumn && `form-dropzone__dropzone-wrapper_column_${thumbColumn}`, fillClass, fillHoverClass, borderWidthClass, borderColorClass, borderColorHoverClass, borderTypeClass)
623
+ }, filesList.map((file, index) => /*#__PURE__*/React$1.createElement("aside", {
624
+ className: clsx('form-dropzone__thumb', fillClass, thumbDirectionClass, thumbBorderWidthClass, thumbBorderColorClass, thumbBorderColorHoverClass, thumbBorderTypeClass),
625
+ key: file.id || `${file.name}_${index}`
626
+ }, isPreviews && !file.error && /*#__PURE__*/React$1.createElement("div", {
627
+ className: "form-dropzone__thumb-image"
628
+ }, /*#__PURE__*/React$1.createElement("img", {
629
+ className: "form-dropzone__thumb-image-inner",
630
+ src: file.preview || file.image,
631
+ onLoad: () => {
632
+ // Revoke data uri after image is loaded
633
+ URL.revokeObjectURL(file.preview);
525
634
  }
526
- }, [change, onChange]);
635
+ })), file.error && /*#__PURE__*/React$1.createElement("div", null, /*#__PURE__*/React$1.createElement(Text, {
636
+ size: thumbNameTextSize,
637
+ textColor: thumbNameTextColor,
638
+ textWeight: thumbNameTextWeight,
639
+ textWrap: thumbNameTextWrap
640
+ }, fileErrorText || file.error)), showFilename && /*#__PURE__*/React$1.createElement("div", {
641
+ className: "form-dropzone__thumb-name"
642
+ }, /*#__PURE__*/React$1.createElement(Text, {
643
+ className: "form-dropzone__thumb-name-inner",
644
+ size: thumbNameTextSize,
645
+ textColor: thumbNameTextColor,
646
+ textWeight: thumbNameTextWeight,
647
+ textWrap: thumbNameTextWrap
648
+ }, file.name)), fileIsLoading && /*#__PURE__*/React$1.createElement("div", {
649
+ className: "form-dropzone__thumb-loader"
650
+ }, /*#__PURE__*/React$1.createElement(Loader, {
651
+ width: "fill",
652
+ height: "fill",
653
+ fill: "surfacePrimary",
654
+ itemFill: "surfaceItemAccent",
655
+ set: "simple"
656
+ })), /*#__PURE__*/React$1.createElement("div", {
657
+ className: clsx('form-dropzone__thumb-remove')
658
+ }, /*#__PURE__*/React$1.createElement(Button, {
659
+ className: "form-dropzone__thumb-remove-text",
660
+ appearance: removeThumbAppearance,
661
+ label: removeThumbText || 'Удалить',
662
+ labelTextWeight: removeThumbTextWeight,
663
+ shape: removeThumbShape,
664
+ onClick: event => removeFile(event, index)
665
+ })))), !filesList.length ? /*#__PURE__*/React$1.createElement("div", {
666
+ className: "form-dropzone__hint"
667
+ }, /*#__PURE__*/React$1.createElement(Text, {
668
+ className: "form-dropzone__hint-title",
669
+ size: hintTitleTextSize,
670
+ textColor: hintTitleTextColor,
671
+ textWeight: hintTitleTextWeight,
672
+ textWrap: hintTitleTextWrap
673
+ }, hintTitle || 'Select a file or drag in form'), hintDescription && /*#__PURE__*/React$1.createElement(Text, {
674
+ className: "form-dropzone__hint-text",
675
+ size: hintDescriptionTextSize,
676
+ textColor: hintDescriptionTextColor,
677
+ textWeight: hintDescriptionTextWeight,
678
+ textWrap: hintDescriptionTextWrap
679
+ }, hintDescription)) : /*#__PURE__*/React$1.createElement("div", {
680
+ className: "form-dropzone__hint form-dropzone__hint_type_add-more"
681
+ }, /*#__PURE__*/React$1.createElement(Text, {
682
+ className: "form-dropzone__hint-title",
683
+ size: hintTitleTextSize,
684
+ textColor: hintTitleTextColor,
685
+ textWeight: hintTitleTextWeight,
686
+ textWrap: hintTitleTextWrap
687
+ }, hintTitle || 'Select a file or drag in form'), hintDescription && /*#__PURE__*/React$1.createElement(Text, {
688
+ className: "form-dropzone__hint-text",
689
+ size: hintDescriptionTextSize,
690
+ textColor: hintDescriptionTextColor,
691
+ textWeight: hintDescriptionTextWeight,
692
+ textWrap: hintDescriptionTextWrap
693
+ }, hintDescription)))), fileError && /*#__PURE__*/React$1.createElement("div", {
694
+ className: "form-field__message"
695
+ }, /*#__PURE__*/React$1.createElement(Text, {
696
+ className: "form-field__message-item form-field__message-item_type_message",
697
+ size: errorMessageTextSize,
698
+ textColor: errorMessageTextColor,
699
+ textWeight: errorMessageTextWeight
700
+ }, fileError)));
701
+ });
702
+ async function getFileByURL(url) {
703
+ try {
704
+ const response = await axios({
705
+ url: url,
706
+ responseType: 'blob'
707
+ });
708
+ const blobObject = response.data;
709
+ const dirtyFilename = response.headers['content-disposition']?.split('filename=')[1];
710
+ // Remove double quotes
711
+ let filename = dirtyFilename?.substring(1).slice(0, -1);
712
+ if (!filename) {
713
+ filename = url.split('/').at(-1);
714
+ // const typeParts = blobObject.type.split('/')
715
+ // const fileType = typeParts[typeParts.length - 1]
716
+ // filename = `${new Date().getTime()}.${fileType}`
717
+ }
718
+ return new File([blobObject], filename, {
719
+ type: blobObject.type
720
+ });
721
+ } catch (error) {
722
+ console.log('error: ', error);
723
+ return null;
724
+ }
725
+ }
726
+ async function convertToFile(inputValue, isPreviews) {
727
+ let newFile = null;
728
+
729
+ // Download image by url and save as File instance
730
+ const isURL = typeof inputValue === 'string' && inputValue.includes('/');
731
+ if (inputValue.image || isURL) {
732
+ newFile = await getFileByURL(inputValue.image || inputValue);
733
+ if (newFile) {
734
+ setFileDataURL(newFile);
735
+ }
736
+ }
737
+
738
+ // Convert dataURL to File instance
739
+ if (inputValue.dataURL) {
740
+ newFile = createFileFromDataURL(inputValue.name || inputValue.path, inputValue.dataURL);
741
+ newFile.dataURL = inputValue.dataURL;
742
+ }
743
+
744
+ // Save new File to state
745
+ if (newFile) {
746
+ newFile.id = inputValue.id;
747
+ if (isPreviews) {
748
+ newFile.preview = URL.createObjectURL(newFile);
749
+ }
750
+ }
751
+ return newFile;
752
+ }
753
+ function setFileDataURL(file, resolve) {
754
+ resolve = resolve || (() => {});
755
+ // Init reader and save his file
756
+ const reader = new FileReader();
757
+ reader._readedFile = file;
758
+
759
+ // Set handlers
760
+ reader.onabort = () => resolve();
761
+ reader.onerror = () => resolve();
762
+ reader.onload = event => {
763
+ event.target._readedFile.dataURL = reader.result;
764
+ resolve();
765
+ };
766
+ // Run reader
767
+ if (file instanceof File) {
768
+ reader.readAsDataURL(file);
769
+ } else {
770
+ resolve();
771
+ }
772
+ }
773
+
774
+ const FileInput = /*#__PURE__*/React$1.memo(function FileInput(props) {
775
+ const {
776
+ className,
777
+ name,
778
+ width,
779
+ maxFiles,
780
+ maxSize,
781
+ label,
782
+ fileErrorText,
783
+ classNameGroupItem,
784
+ dropzoneProps,
785
+ fieldProps,
786
+ hintDescription,
787
+ hintTitle,
788
+ showFilename,
789
+ showMessage,
790
+ isPreviews,
791
+ isRequired,
792
+ onAddFiles,
793
+ onDeleteFile
794
+ } = props;
795
+ const propsGenerator = useDevicePropsGenerator(props);
796
+ const {
797
+ size,
798
+ fill,
799
+ fillHover,
800
+ labelTextColor,
801
+ borderColorHover,
802
+ borderType,
803
+ borderWidth,
804
+ errorMessageTextColor,
805
+ errorMessageTextSize,
806
+ errorMessageTextWeight,
807
+ hintDescriptionTextColor,
808
+ hintDescriptionTextSize,
809
+ hintDescriptionTextWeight,
810
+ hintDescriptionTextWrap,
811
+ hintTitleTextColor,
812
+ hintTitleTextSize,
813
+ hintTitleTextWeight,
814
+ hintTitleTextWrap,
815
+ removeThumbAppearance,
816
+ removeThumbText,
817
+ removeThumbTextWeight,
818
+ removeThumbShape,
819
+ shape,
820
+ thumbBorderColor,
821
+ thumbBorderColorHover,
822
+ thumbBorderType,
823
+ thumbBorderWidth,
824
+ thumbColumn = 1,
825
+ thumbDirection = 'vertical',
826
+ thumbNameTextColor,
827
+ thumbNameTextSize,
828
+ thumbNameTextWeight,
829
+ thumbNameTextWrap
830
+ } = propsGenerator;
527
831
  return /*#__PURE__*/React$1.createElement(Field, {
528
- initialValue: initialValue,
529
832
  name: name
530
833
  }, function Render({
531
834
  input,
@@ -537,81 +840,127 @@ const ChoiceField = /*#__PURE__*/React$1.memo(function ChoiceField(props) {
537
840
  * React Hooks must be called in a React function component or a
538
841
  * custom React Hook function.
539
842
  */
540
- const activeOption = useMemo(() => {
541
- const emptyOption = {
542
- value: null,
543
- label: null
544
- };
545
- if (input.value) {
546
- const currentOption = options.find(option => option.value === input.value);
547
- return currentOption || emptyOption;
548
- }
549
- return emptyOption;
550
- }, [input.value]);
843
+
551
844
  const {
552
- isErrorState,
553
- isValidState,
554
845
  errorKey,
555
- errorMessage
846
+ errorMessage,
847
+ isErrorState,
848
+ isValidState
556
849
  } = useFieldValidationState({
557
850
  fieldProps: fieldProps,
558
851
  input: input,
559
852
  meta: meta
560
853
  });
561
854
  const updatedInputProps = useValidationAppearanceInputProps({
562
- inputProps: inputProps,
855
+ inputProps: props,
563
856
  validationStateKey: isErrorState ? errorKey : 'success'
564
857
  });
858
+
859
+ /** TODO:
860
+ * REFACTOR PROPERTIES
861
+ */
565
862
  return /*#__PURE__*/React$1.createElement(FieldWrapper, Object.assign({
566
- className: clsx('form-field_type_choice', 'form__item_type_choice', classNameGroupItem),
863
+ className: clsx('form-field_type_dropzone', 'form__item_type_dropzone', classNameGroupItem),
864
+ width: width,
567
865
  label: label,
866
+ labelTextColor: labelTextColor,
568
867
  errorKey: errorKey,
569
868
  errorMessage: errorMessage,
570
869
  isErrorState: isErrorState,
571
870
  metaError: meta.error,
572
- isDisabled: isDisabled,
573
- fieldClassName: "form-choice",
871
+ fieldClassName: "form-dropzone",
574
872
  inputName: input.name,
575
- inputValue: input.value || [],
576
- messageType: messageType,
873
+ inputValue: input.value,
577
874
  metaActive: meta.active,
875
+ metaTouched: meta.touched,
578
876
  showMessage: showMessage,
579
877
  isRequired: isRequired,
580
878
  isValidState: isValidState
581
- }, fieldProps), /*#__PURE__*/React$1.createElement(Choice, Object.assign({
582
- className: clsx(meta.active && 'form-choice_state_focus', meta.error && meta.touched && `form-choice_state_${errorKey}`),
583
- name: input.name,
584
- isDisabled: isDisabled,
585
- active: activeOption,
586
- inputValue: input.value || [],
587
- options: options,
588
- placeholder: placeholder,
589
- isCheckbox: isCheckbox,
590
- isRequired: isRequired,
591
- setActiveSegment: setActiveSegment
592
- }, updatedInputProps)));
879
+ }, fieldProps), /*#__PURE__*/React$1.createElement(FileInputDropzone, {
880
+ className: className,
881
+ maxFiles: maxFiles,
882
+ maxSize: maxSize,
883
+ size: size,
884
+ fill: fill,
885
+ fillHover: fillHover,
886
+ borderColor: updatedInputProps.borderColor,
887
+ borderColorHover: borderColorHover,
888
+ borderType: borderType,
889
+ borderWidth: borderWidth,
890
+ errorMessageTextColor: errorMessageTextColor,
891
+ errorMessageTextSize: errorMessageTextSize,
892
+ errorMessageWeight: errorMessageTextWeight,
893
+ fileErrorText: fileErrorText,
894
+ metaError: meta.error,
895
+ dropzoneProps: dropzoneProps,
896
+ hintDescription: hintDescription,
897
+ hintDescriptionTextColor: hintDescriptionTextColor,
898
+ hintDescriptionTextSize: hintDescriptionTextSize,
899
+ hintDescriptionTextWeight: hintDescriptionTextWeight,
900
+ hintDescriptionTextWrap: hintDescriptionTextWrap,
901
+ hintTitle: hintTitle,
902
+ hintTitleTextColor: hintTitleTextColor,
903
+ hintTitleTextSize: hintTitleTextSize,
904
+ hintTitleTextWeight: hintTitleTextWeight,
905
+ hintTitleTextWrap: hintTitleTextWrap,
906
+ inputName: input.name,
907
+ inputValue: input.value,
908
+ metaTouched: meta.touched,
909
+ removeThumbAppearance: removeThumbAppearance,
910
+ removeThumbText: removeThumbText,
911
+ removeThumbTextWeight: removeThumbTextWeight,
912
+ removeThumbShape: removeThumbShape,
913
+ shape: shape,
914
+ showFilename: showFilename,
915
+ thumbBorderColor: thumbBorderColor,
916
+ thumbBorderColorHover: thumbBorderColorHover,
917
+ thumbBorderType: thumbBorderType,
918
+ thumbBorderWidth: thumbBorderWidth,
919
+ thumbColumn: thumbColumn,
920
+ thumbDirection: thumbDirection,
921
+ thumbNameTextColor: thumbNameTextColor,
922
+ thumbNameTextSize: thumbNameTextSize,
923
+ thumbNameTextWeight: thumbNameTextWeight,
924
+ thumbNameTextWrap: thumbNameTextWrap,
925
+ isPreviews: isPreviews,
926
+ onAddFiles: onAddFiles,
927
+ onDeleteFile: onDeleteFile
928
+ }));
593
929
  });
594
930
  });
595
931
 
596
- const CustomField = /*#__PURE__*/React$1.memo(function CustomField(props) {
932
+ const defaultGroupProps = {
933
+ width: 'fill',
934
+ labelTextColor: 'surfaceTextPrimary',
935
+ labelTextSize: 'h5',
936
+ labelTextWeight: 500
937
+ };
938
+
939
+ const FormBlockGroup = /*#__PURE__*/React$1.memo(function Group(props) {
597
940
  const {
598
- Component,
599
- isDisabled,
600
- isRequired,
941
+ className,
601
942
  name,
602
- initialValue,
603
- fieldProps = {},
604
- classNameGroupItem,
605
- showMessage,
606
- clearIcon,
607
- clearIconFill,
608
- clearIconFillHover,
609
- clearIconShape,
610
- clearIconSize,
611
- onClickClearIcon
943
+ label,
944
+ labelTextColor,
945
+ labelTextSize,
946
+ labelTextWeight,
947
+ message,
948
+ column,
949
+ dataTour,
950
+ title,
951
+ titleTextSize,
952
+ titleTextColor,
953
+ titleTextWeight,
954
+ messageTextColor = 'surfaceTextTertiary',
955
+ messageTextSize = 's',
956
+ messageTextWeight,
957
+ showGroupMessage,
958
+ before,
959
+ after,
960
+ isHidden,
961
+ children
612
962
  } = props;
613
963
  return /*#__PURE__*/React$1.createElement(Field, {
614
- initialValue: initialValue,
615
964
  name: name
616
965
  }, function Render({
617
966
  input,
@@ -623,84 +972,70 @@ const CustomField = /*#__PURE__*/React$1.memo(function CustomField(props) {
623
972
  * React Hooks must be called in a React function component or a
624
973
  * custom React Hook function.
625
974
  */
626
-
627
975
  const {
628
976
  isErrorState,
629
- isValidState,
630
977
  errorKey,
631
978
  errorMessage
632
979
  } = useFieldValidationState({
633
- fieldProps: fieldProps,
980
+ fieldProps: props,
981
+ // or fieldProps?
634
982
  input: input,
635
983
  meta: meta
636
984
  });
637
- const updatedInputProps = useValidationAppearanceInputProps({
638
- validationStateKey: isErrorState ? errorKey : 'success',
639
- // For "Custom" field we pass all props. Can contain some special props, we don't known.
640
- inputProps: props
985
+ const updatedProps = useValidationAppearanceInputProps({
986
+ inputProps: props,
987
+ validationStateKey: isErrorState ? errorKey : 'success'
641
988
  });
642
- return /*#__PURE__*/React$1.createElement(FieldWrapper, Object.assign({
643
- className: clsx('form-field_type_custom', 'form__item_type_custom', classNameGroupItem),
644
- errorKey: errorKey,
645
- errorMessage: errorMessage,
646
- fieldClassName: 'form-custom',
647
- inputName: input.name,
648
- inputValue: input.value,
649
- isDisabled: isDisabled,
650
- isErrorState: isErrorState,
651
- isRequired: isRequired,
652
- isValidState: isValidState,
653
- metaActive: meta.active,
654
- metaError: meta.error,
655
- showMessage: showMessage
656
- }, fieldProps), /*#__PURE__*/React$1.createElement(Component, Object.assign({}, updatedInputProps, {
657
- input: input,
658
- isDisabled: isDisabled,
659
- meta: meta
660
- })), clearIcon && /*#__PURE__*/React$1.createElement(Icon, {
661
- className: "form-field__icon",
662
- iconFill: clearIconFill,
663
- iconFillHover: clearIconFillHover,
664
- imageSrc: clearIcon,
665
- shape: clearIconShape,
666
- size: clearIconSize,
667
- SvgImage: clearIcon,
668
- onClick: onClickClearIcon
669
- }));
989
+ return /*#__PURE__*/React$1.createElement("div", {
990
+ className: clsx('form__group', className, isHidden && 'form__group_hidden', column && `form__group_column_${column}`),
991
+ "data-tour": dataTour
992
+ }, /*#__PURE__*/React$1.createElement("div", {
993
+ className: "form__group-wrapper"
994
+ }, before, title && /*#__PURE__*/React$1.createElement("div", {
995
+ className: "form__group-title"
996
+ }, /*#__PURE__*/React$1.createElement(Title, {
997
+ size: titleTextSize,
998
+ textColor: titleTextColor,
999
+ textWeight: titleTextWeight
1000
+ }, title)), label && /*#__PURE__*/React$1.createElement("div", {
1001
+ className: "form__group-label"
1002
+ }, /*#__PURE__*/React$1.createElement(Text, {
1003
+ size: labelTextSize,
1004
+ textColor: labelTextColor,
1005
+ textWeight: labelTextWeight
1006
+ }, label)), /*#__PURE__*/React$1.createElement("div", {
1007
+ className: "form__group-items"
1008
+ }, children), after), showGroupMessage && /*#__PURE__*/React$1.createElement(React$1.Fragment, null, isErrorState && errorMessage && /*#__PURE__*/React$1.createElement(Text, {
1009
+ className: `form__group-message form__group-message_type-${errorKey}`,
1010
+ id: `${name}-error`,
1011
+ size: updatedProps.messageTextSize,
1012
+ textColor: updatedProps.messageTextColor,
1013
+ textWeight: updatedProps.messageTextWeight
1014
+ }, errorMessage), Boolean(message) && (!isErrorState || !errorMessage) && /*#__PURE__*/React$1.createElement(Text, {
1015
+ className: "form__group-message",
1016
+ size: messageTextSize,
1017
+ textColor: messageTextColor,
1018
+ textWeight: messageTextWeight
1019
+ }, message), !isErrorState && !message && /*#__PURE__*/React$1.createElement(Text, {
1020
+ className: "form__group-message",
1021
+ size: messageTextSize
1022
+ }, '\u00A0')));
670
1023
  });
671
1024
  });
672
1025
 
673
- const defaultCodeProps = {
674
- fieldProps: {
675
- size: 'l',
676
- labelTextColor: 'surfaceTextPrimary',
677
- labelTextSize: 's',
678
- labelTextWeight: 'normal',
679
- helpText: 'Supporting text',
680
- helpTextColor: 'surfaceTextPrimary',
681
- helpTextSize: 's',
682
- helpTextWeight: 'normal',
683
- showMessage: true
684
- },
685
- inputProps: {
686
- width: 'fill',
687
- size: 'l',
688
- fill: 'surfaceSecondary',
689
- inputBorderColor: 'surfaceBorderTertiary',
690
- inputBorderColorHover: 'surfaceBorderQuaternary',
691
- inputBorderFocusColor: 'surfaceBorderAccent',
692
- inputCaretColor: 'surfaceItemAccent',
693
- inputFill: 'surfacePrimary',
694
- inputFillHover: 'surfaceSecondary',
695
- inputPlaceholderTextColor: 'surfaceSecondary',
696
- inputSize: 'l',
697
- inputTextColor: 'surfaceSecondary',
698
- inputTextSize: 'xxl',
699
- inputTextWeight: 'normal'
700
- }
1026
+ const defaultCheckboxProps = {
1027
+ appearance: 'defaultPrimary',
1028
+ width: 'fill',
1029
+ size: 'm',
1030
+ labelTextColor: 'surfaceTextPrimary',
1031
+ labelTextColorDisabled: 'surfaceTextDisabled',
1032
+ labelTextSize: 's',
1033
+ descTextSize: 's',
1034
+ errorBorderColor: 'errorBorderSecondary',
1035
+ requiredBorderColor: 'warningBorderSecondary'
701
1036
  };
702
1037
 
703
- const CodeField = /*#__PURE__*/React$1.memo(function CodeField(props) {
1038
+ const FormFieldCheckbox = /*#__PURE__*/React$1.memo(function FormFieldCheckbox(props) {
704
1039
  const {
705
1040
  name,
706
1041
  initialValue,
@@ -709,9 +1044,11 @@ const CodeField = /*#__PURE__*/React$1.memo(function CodeField(props) {
709
1044
  fieldProps = {},
710
1045
  inputProps = {},
711
1046
  showMessage,
712
- isRequired
1047
+ isRequired,
1048
+ onChange
713
1049
  } = props;
714
1050
  return /*#__PURE__*/React$1.createElement(Field, {
1051
+ type: "checkbox",
715
1052
  name: name,
716
1053
  initialValue: initialValue
717
1054
  }, function Render({
@@ -725,553 +1062,192 @@ const CodeField = /*#__PURE__*/React$1.memo(function CodeField(props) {
725
1062
  * custom React Hook function.
726
1063
  */
727
1064
 
1065
+ const onChangeField = useCallback(event => {
1066
+ input.onChange(event);
1067
+ if (onChange) {
1068
+ onChange(event.target.checked, input.name);
1069
+ }
1070
+ }, [onChange, input.onChange]);
728
1071
  const {
729
- isErrorState,
730
- isValidState,
731
- errorKey} = useFieldValidationState({
732
- fieldProps: fieldProps,
733
- input: input,
734
- meta: meta
735
- });
736
- const updatedInputProps = useValidationAppearanceInputProps({
737
- inputProps: inputProps,
738
- validationStateKey: isErrorState ? errorKey : 'success'
739
- });
740
- return /*#__PURE__*/React$1.createElement(FieldWrapper, Object.assign({
741
- className: clsx('form-field_type_code', 'form__item_type_code', classNameGroupItem),
742
- fieldClassName: 'form-code',
743
- inputName: input.name,
744
- inputValue: input.value,
745
- metaActive: meta.active,
746
- showMessage: showMessage,
747
- isRequired: isRequired,
748
- isValidState: isValidState
749
- }, fieldProps), /*#__PURE__*/React$1.createElement(Code, Object.assign({
750
- name: input.name,
751
- isDisabled: isDisabled,
752
- autoComplete: "nope",
753
- value: input.value,
754
- onBlur: input.onBlur,
755
- onChange: input.onChange,
756
- onFocus: input.onFocus
757
- }, updatedInputProps)));
758
- });
759
- });
760
-
761
- const defaultDatepickerProps = {
762
- dateFormat: 'dd/MM/yyyy - HH:mm',
763
- readOnly: false,
764
- selectsRange: false,
765
- showTimeSelect: true,
766
- timeCaption: 'Время',
767
- timeFormat: 'p',
768
- timeIntervals: 60,
769
- isClearable: true,
770
- isStartDefaultNull: true
771
- };
772
-
773
- function DatePickerField(props) {
774
- const {
775
- name,
776
- isDisabled,
777
- classNameGroupItem,
778
- datePickerProps,
779
- fieldProps = {},
780
- inputProps = {},
781
- showMessage,
782
- isRequired,
783
- onChange
784
- } = props;
785
- return /*#__PURE__*/React$1.createElement(Field, {
786
- name: name
787
- }, function Render({
788
- input,
789
- meta
790
- }) {
791
- /** Note:
792
- * Create "Render" function by "eslint-react-hooks/rules-of-hooks":
793
- * React Hooks cannot be called inside a callback.
794
- * React Hooks must be called in a React function component or a
795
- * custom React Hook function.
796
- */
797
-
798
- const onChangeField = useCallback((startDate, endDate) => {
799
- if (!datePickerProps.selectsRange) {
800
- // When we need to save single date, value is date
801
- // TODO: make object with one date? need to check all forms with DatePickerField
802
- input.onChange(startDate);
803
- } else {
804
- // When we need to save range, value is object with two date
805
- input.onChange({
806
- endDate,
807
- startDate
808
- });
809
- }
810
- if (onChange) {
811
- onChange(startDate, endDate);
812
- }
813
- }, [input.onChange, onChange]);
814
- const {
815
- errorKey,
816
- errorMessage,
1072
+ errorKey,
1073
+ errorMessage,
817
1074
  isErrorState,
818
1075
  isValidState
819
1076
  } = useFieldValidationState({
820
- fieldProps: fieldProps,
821
- input: input,
822
- meta: meta
823
- });
824
- const updatedInputProps = useValidationAppearanceInputProps({
825
- inputProps: inputProps,
826
- validationStateKey: isErrorState ? errorKey : 'success'
827
- });
828
- return /*#__PURE__*/React$1.createElement(FieldWrapper, Object.assign({
829
- className: clsx('form-field_type_datepicker', 'form__item_type_datepicker', classNameGroupItem),
830
- errorKey: errorKey,
831
- errorMessage: errorMessage,
832
- isErrorState: isErrorState,
833
- metaError: meta.error,
834
- isDisabled: isDisabled,
835
- fieldClassName: "form-datepicker",
836
- inputName: input.name,
837
- inputValue: input.value || '',
838
- metaActive: meta.active,
839
- showMessage: showMessage,
840
- isRequired: isRequired,
841
- isValidState: isValidState
842
- }, fieldProps), /*#__PURE__*/React$1.createElement(DatePickerInput, {
843
- name: input.name,
844
- isDisabled: isDisabled,
845
- datePickerProps: datePickerProps,
846
- endValue: datePickerProps.selectsRange ? input.value.endDate : null,
847
- inputProps: updatedInputProps,
848
- value: datePickerProps.selectsRange ? input.value.startDate : input.value,
849
- onBlur: input.onBlur,
850
- onChange: onChangeField,
851
- onFocus: input.onFocus
852
- }));
853
- });
854
- }
855
-
856
- const defaultDropzoneProps = {
857
- fill: 'surfacePrimary',
858
- borderColor: 'surfaceBorderTertiary',
859
- borderColorHover: 'surfaceBorderQuaternary',
860
- hintTitle: 'Перетащите изображение или выберите файл с компьютера',
861
- hintTitleTextColor: 'surfaceTextPrimary',
862
- hintTitleTextSize: 'm',
863
- removeThumbText: 'удалить',
864
- removeThumbTextColor: 'errorTextPrimary',
865
- removeThumbTextHoverColor: 'errorTextPrimaryHover',
866
- removeThumbTextSize: 's',
867
- shape: 'rounded',
868
- showFilename: true,
869
- thumbBorderColor: 'surfaceBorderTertiary',
870
- thumbBorderColorHover: 'surfaceBorderQuaternary',
871
- thumbBorderWidth: 1,
872
- thumbNameTextColor: 'surfaceTextPrimary',
873
- thumbNameTextSize: 's',
874
- isPreviews: true
875
- };
876
-
877
- const FileInputDropzone = /*#__PURE__*/React$1.memo(function FileInputDropzone(props) {
878
- const {
879
- className,
880
- maxFiles,
881
- maxSize,
882
- size,
883
- fileErrorText,
884
- dropzoneProps = {},
885
- hintDescription,
886
- hintTitle,
887
- inputName,
888
- inputValue,
889
- showFilename,
890
- thumbColumn,
891
- isPreviews,
892
- onAddFiles,
893
- onDeleteFile
894
- } = props;
895
-
896
- // TODO: delete react-final-form things out of here?
897
- const {
898
- change
899
- } = useForm();
900
- const [fileError, setFileError] = useState('');
901
- const [fileIsLoading, setFileIsLoading] = useState(false);
902
- const filesList = useMemo(() => inputValue ? castArray(inputValue) : [], [inputValue]);
903
- const changeFormState = useCallback(newFiles => {
904
- // If max files in dropzone is 1 - return file as it self, else as array of files
905
- // ps: for old projects compatibility
906
- const toSave = dropzoneProps.maxFiles == 1 ? newFiles[0] : newFiles;
907
- change(inputName, toSave);
908
- return toSave;
909
- },
910
- // If "inputName" will be changes, then it should be a different field
911
- // eslint-disable-next-line react-hooks/exhaustive-deps
912
- [dropzoneProps, change]);
913
-
914
- //
915
- const convertFiledValueAndSaveAsFiles = useCallback(async currentFilesList => {
916
- setFileIsLoading(true);
917
- const newFiles = [];
918
- for (const fileItem of currentFilesList) {
919
- if (typeof fileItem === 'string') {
920
- const newFile = await convertToFile(fileItem, isPreviews);
921
- if (newFile) {
922
- newFiles.push(newFile);
923
- }
924
- } else {
925
- newFiles.push(fileItem);
926
- }
927
- }
928
- changeFormState(newFiles);
929
- setFileIsLoading(false);
930
- }, [isPreviews, changeFormState]);
931
-
932
- // Delete file from dropzone
933
- const removeFile = useCallback((event, index) => {
934
- event.stopPropagation();
935
- event.preventDefault();
936
- const newFiles = [...filesList];
937
- newFiles.splice(index, 1);
938
- if (onDeleteFile) {
939
- onDeleteFile(filesList[index], inputName);
940
- }
941
- changeFormState(newFiles);
942
- },
943
- // If "inputName" will be changes, then it should be a different field
944
- // eslint-disable-next-line react-hooks/exhaustive-deps
945
- [filesList, changeFormState, onDeleteFile]);
946
-
947
- // Create dropzone options
948
- const {
949
- getInputProps,
950
- getRootProps
951
- } = useDropzone({
952
- maxFiles: maxFiles || 5,
953
- maxSize: maxSize || 10485760,
954
- // 10mb
955
- // accept: { 'image/*': [] },
956
- ...dropzoneProps,
957
- getFilesFromEvent: async event => {
958
- const result = await fromEvent(event);
959
- const newFiles = result.filter(item => item instanceof File);
960
- // Add exists and new files to accepted(or rejected)
961
- return [...filesList, ...newFiles];
962
- },
963
- onDropAccepted: acceptedFiles => {
964
- // If dropped files has accepted and we need a previews
965
- if (isPreviews) {
966
- // Add preview to every file
967
- acceptedFiles.forEach(file => {
968
- if (!file.error) {
969
- file.preview = URL.createObjectURL(file);
970
- }
971
- });
972
- }
973
- // Save to form data (including empty when files are not valid)
974
- const filesToSave = changeFormState(acceptedFiles);
975
- setFileError('');
976
-
977
- // Save DataURL for all files
978
- const readerPromisesList = acceptedFiles.map(file => {
979
- return new Promise(resolve => setFileDataURL(file, resolve));
980
- });
981
- // Save files to form values
982
- Promise.all(readerPromisesList).then(() => {
983
- if (onAddFiles) {
984
- onAddFiles(filesToSave, inputName);
985
- }
986
- });
987
- },
988
- onDropRejected: rejectedFiles => {
989
- // If dropped files has rejected
990
- if (rejectedFiles.length) {
991
- let fileErrorMessage = 'Ошибка при добавлении файла';
992
- const firstFileErrorItem = rejectedFiles[0].errors[0];
993
- if (firstFileErrorItem) {
994
- if (firstFileErrorItem.code === ErrorCode.TooManyFiles) {
995
- fileErrorMessage = `Максимальное количество файлов: ${maxFiles}`;
996
- } else {
997
- fileErrorMessage = firstFileErrorItem.message;
998
- }
999
- }
1000
- // Show error
1001
- setFileError(fileErrorMessage);
1002
- } else {
1003
- // Else clean error
1004
- setFileError('');
1005
- }
1006
- }
1007
- });
1008
- useEffect(() => {
1009
- const currentFilesList = castArray(inputValue);
1010
- const isNeedToConvert = currentFilesList.some(fileItem => typeof fileItem === 'string');
1011
- if (isNeedToConvert) {
1012
- // First time convert value to Files and save to local and form state
1013
- convertFiledValueAndSaveAsFiles(currentFilesList);
1014
- }
1015
-
1016
- // Make sure to revoke the data uris to avoid memory leaks, will run on unmount
1017
- return () => {
1018
- filesList.forEach(file => {
1019
- if (file?.preview) {
1020
- URL.revokeObjectURL(file.preview);
1021
- }
1022
- });
1023
- };
1024
- // eslint-disable-next-line react-hooks/exhaustive-deps
1025
- }, [inputValue]);
1026
- const propsGenerator = useDevicePropsGenerator(props);
1027
- const {
1028
- fillClass,
1029
- fillHoverClass,
1030
- borderColorClass,
1031
- borderColorHoverClass,
1032
- borderTypeClass,
1033
- borderWidthClass,
1034
- errorMessageTextColor,
1035
- errorMessageTextSize,
1036
- errorMessageTextWeight,
1037
- hintDescriptionTextColor,
1038
- hintDescriptionTextSize,
1039
- hintDescriptionTextWeight,
1040
- hintDescriptionTextWrap,
1041
- hintTitleTextColor,
1042
- hintTitleTextSize,
1043
- hintTitleTextWeight,
1044
- hintTitleTextWrap,
1045
- removeThumbAppearance,
1046
- removeThumbShape,
1047
- removeThumbText,
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} 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: clsx('form-dropzone__thumb-remove')
1101
- }, /*#__PURE__*/React$1.createElement(Button, {
1102
- className: "form-dropzone__thumb-remove-text",
1103
- appearance: removeThumbAppearance,
1104
- label: removeThumbText || 'Удалить',
1105
- labelTextWeight: removeThumbTextWeight,
1106
- shape: removeThumbShape,
1107
- onClick: event => removeFile(event, index)
1108
- })))), !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'), hintDescription && /*#__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'), hintDescription && /*#__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'
1077
+ fieldProps: fieldProps,
1078
+ input: input,
1079
+ meta: meta
1150
1080
  });
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
1081
+ const updatedInputProps = useValidationAppearanceInputProps({
1082
+ inputProps: inputProps,
1083
+ validationStateKey: isErrorState ? errorKey : 'success'
1163
1084
  });
1164
- } catch (error) {
1165
- console.log('error: ', error);
1166
- return null;
1167
- }
1168
- }
1169
- async function convertToFile(inputValue, isPreviews) {
1170
- let newFile = null;
1085
+ return /*#__PURE__*/React$1.createElement(FieldWrapper, Object.assign({
1086
+ className: clsx('form-field_type_checkbox', 'form__item_type_checkbox', classNameGroupItem),
1087
+ errorKey: errorKey,
1088
+ errorMessage: errorMessage,
1089
+ isErrorState: isErrorState,
1090
+ metaError: meta.error,
1091
+ isDisabled: isDisabled,
1092
+ fieldClassName: "form-checkbox",
1093
+ inputName: input.name,
1094
+ inputValue: input.checked,
1095
+ metaActive: meta.active,
1096
+ showMessage: showMessage,
1097
+ tag: "label",
1098
+ isRequired: isRequired,
1099
+ isValidState: isValidState
1100
+ }, fieldProps), /*#__PURE__*/React$1.createElement(Checkbox, Object.assign({
1101
+ type: "checkbox",
1102
+ name: input.name,
1103
+ isDisabled: isDisabled,
1104
+ autoComplete: "nope",
1105
+ checked: input.checked,
1106
+ onBlur: input.onBlur,
1107
+ onChange: onChangeField,
1108
+ onFocus: input.onFocus
1109
+ }, updatedInputProps)));
1110
+ });
1111
+ });
1171
1112
 
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
- }
1113
+ const defaultChipsProps = {
1114
+ appearance: 'surfacePrimary sizeM rounded',
1115
+ width: 'fill',
1116
+ errorBorderColor: 'errorBorderSecondary',
1117
+ requiredBorderColor: 'warningBorderSecondary'
1118
+ };
1180
1119
 
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
- }
1120
+ function FormFieldChips(props) {
1121
+ const {
1122
+ name,
1123
+ initialValue,
1124
+ isDisabled,
1125
+ classNameGroupItem,
1126
+ emptyMessage,
1127
+ emptyMessageTextColor,
1128
+ emptyMessageTextSize,
1129
+ fieldProps,
1130
+ inputProps,
1131
+ options,
1132
+ showMessage,
1133
+ isRequired,
1134
+ onChange
1135
+ } = props;
1136
+ const {
1137
+ change
1138
+ } = useForm();
1186
1139
 
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;
1140
+ // Callback for value changes
1141
+ const onChangeSomeInput = useCallback((inputValue, newOptionValue) => {
1142
+ const updatedValues = inputValue.includes(newOptionValue) ? inputValue.filter(selectedValue => selectedValue !== newOptionValue) : [...inputValue, newOptionValue];
1143
+ change(name, updatedValues);
1144
+ onChange && onChange(updatedValues);
1145
+ }, [change, name, onChange]);
1146
+ useEffect(() => {
1147
+ initialValue && change(name, initialValue);
1148
+ // update the form value only when the initialValue changes, so use disable eslint to ignore the warning
1149
+ // eslint-disable-next-line react-hooks/exhaustive-deps
1150
+ }, [initialValue]);
1151
+ return /*#__PURE__*/React$1.createElement(Field, {
1152
+ name: name,
1153
+ initialValue: initialValue
1154
+ }, function Render({
1155
+ input,
1156
+ meta
1157
+ }) {
1158
+ const {
1159
+ errorKey,
1160
+ errorMessage,
1161
+ isErrorState,
1162
+ isValidState
1163
+ } = useFieldValidationState({
1164
+ fieldProps: fieldProps,
1165
+ input: input,
1166
+ meta: meta
1167
+ });
1168
+ const updatedInputProps = useValidationAppearanceInputProps({
1169
+ inputProps: inputProps,
1170
+ validationStateKey: isErrorState ? errorKey : 'success'
1171
+ });
1172
+ const activeOptionsList = useMemo(() => {
1173
+ const emptyOptionsList = [{
1174
+ label: null,
1175
+ value: null
1176
+ }];
1177
+ if (input?.value) {
1178
+ const currentOptions = options.filter(option => input.value?.includes(option.value));
1179
+ return currentOptions || emptyOptionsList;
1180
+ }
1181
+ return emptyOptionsList;
1182
+ }, [input.value]);
1183
+ return /*#__PURE__*/React$1.createElement(FieldWrapper, Object.assign({
1184
+ className: clsx('form-field_type_chips', 'form__item_type_chips', classNameGroupItem),
1185
+ errorKey: errorKey,
1186
+ errorMessage: errorMessage,
1187
+ isErrorState: isErrorState,
1188
+ metaError: meta.error,
1189
+ isDisabled: isDisabled,
1190
+ fieldClassName: "form-chips",
1191
+ inputName: input.name,
1192
+ inputValue: input.value,
1193
+ metaActive: meta.active,
1194
+ showMessage: showMessage,
1195
+ isRequired: isRequired,
1196
+ isValidState: isValidState
1197
+ }, fieldProps), options.length ? /*#__PURE__*/React$1.createElement(ChipsGroup, {
1198
+ direction: "horizontal",
1199
+ gap: "1m",
1200
+ wrap: "wrap"
1201
+ }, options.map(option => /*#__PURE__*/React$1.createElement(Chips, Object.assign({
1202
+ className: clsx(meta.active && 'form-chips_state_focus', meta.error && meta.touched && `form-chips_state_${errorKey}`),
1203
+ key: option.value,
1204
+ label: option.label,
1205
+ isDisabled: option.isDisabled,
1206
+ value: option.value,
1207
+ isActive: activeOptionsList.some(activeOption => activeOption.value === option.value),
1208
+ onClick: () => onChangeSomeInput(input.value, option.value)
1209
+ }, updatedInputProps)))) : /*#__PURE__*/React$1.createElement(Text, {
1210
+ size: emptyMessageTextSize,
1211
+ textColor: emptyMessageTextColor
1212
+ }, emptyMessage));
1213
+ });
1195
1214
  }
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
1215
 
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
+ const defaultChoiceProps = {
1217
+ appearance: 'defaultPrimary sizeM solid rounded',
1218
+ width: 'fill',
1219
+ errorBorderColor: 'errorBorderPrimary',
1220
+ requiredBorderColor: 'warningBorderPrimary'
1221
+ };
1216
1222
 
1217
- const FileInput = /*#__PURE__*/React$1.memo(function FileInput(props) {
1223
+ const FormFieldChoice = /*#__PURE__*/React$1.memo(function FormFieldChoice(props) {
1218
1224
  const {
1219
- className,
1220
1225
  name,
1221
- width,
1222
- maxFiles,
1223
- maxSize,
1226
+ initialValue,
1224
1227
  label,
1225
- fileErrorText,
1228
+ isDisabled,
1226
1229
  classNameGroupItem,
1227
- dropzoneProps,
1228
1230
  fieldProps,
1229
- hintDescription,
1230
- hintTitle,
1231
- showFilename,
1231
+ inputProps,
1232
+ messageType,
1233
+ options,
1234
+ placeholder,
1232
1235
  showMessage,
1233
- isPreviews,
1236
+ isCheckbox,
1234
1237
  isRequired,
1235
- onAddFiles,
1236
- onDeleteFile
1238
+ onChange
1237
1239
  } = props;
1238
- const propsGenerator = useDevicePropsGenerator(props);
1239
1240
  const {
1240
- size,
1241
- fill,
1242
- fillHover,
1243
- labelTextColor,
1244
- borderColorHover,
1245
- borderType,
1246
- borderWidth,
1247
- errorMessageTextColor,
1248
- errorMessageTextSize,
1249
- errorMessageTextWeight,
1250
- hintDescriptionTextColor,
1251
- hintDescriptionTextSize,
1252
- hintDescriptionTextWeight,
1253
- hintDescriptionTextWrap,
1254
- hintTitleTextColor,
1255
- hintTitleTextSize,
1256
- hintTitleTextWeight,
1257
- hintTitleTextWrap,
1258
- removeThumbAppearance,
1259
- removeThumbText,
1260
- removeThumbTextWeight,
1261
- removeThumbShape,
1262
- shape,
1263
- thumbBorderColor,
1264
- thumbBorderColorHover,
1265
- thumbBorderType,
1266
- thumbBorderWidth,
1267
- thumbColumn = 1,
1268
- thumbDirection = 'vertical',
1269
- thumbNameTextColor,
1270
- thumbNameTextSize,
1271
- thumbNameTextWeight,
1272
- thumbNameTextWrap
1273
- } = propsGenerator;
1241
+ change
1242
+ } = useForm();
1243
+ const setActiveSegment = useCallback((option, isChecked) => {
1244
+ change(name, isChecked && option.value);
1245
+ if (onChange) {
1246
+ onChange(option.value, name, isChecked);
1247
+ }
1248
+ }, [change, onChange]);
1274
1249
  return /*#__PURE__*/React$1.createElement(Field, {
1250
+ initialValue: initialValue,
1275
1251
  name: name
1276
1252
  }, function Render({
1277
1253
  input,
@@ -1283,125 +1259,225 @@ const FileInput = /*#__PURE__*/React$1.memo(function FileInput(props) {
1283
1259
  * React Hooks must be called in a React function component or a
1284
1260
  * custom React Hook function.
1285
1261
  */
1286
-
1262
+ const activeOption = useMemo(() => {
1263
+ const emptyOption = {
1264
+ value: null,
1265
+ label: null
1266
+ };
1267
+ if (input.value) {
1268
+ const currentOption = options.find(option => option.value === input.value);
1269
+ return currentOption || emptyOption;
1270
+ }
1271
+ return emptyOption;
1272
+ }, [input.value]);
1287
1273
  const {
1288
- errorKey,
1289
- errorMessage,
1290
1274
  isErrorState,
1291
- isValidState
1275
+ isValidState,
1276
+ errorKey,
1277
+ errorMessage
1292
1278
  } = useFieldValidationState({
1293
1279
  fieldProps: fieldProps,
1294
1280
  input: input,
1295
1281
  meta: meta
1296
1282
  });
1297
1283
  const updatedInputProps = useValidationAppearanceInputProps({
1298
- inputProps: props,
1284
+ inputProps: inputProps,
1299
1285
  validationStateKey: isErrorState ? errorKey : 'success'
1300
1286
  });
1301
-
1302
- /** TODO:
1303
- * REFACTOR PROPERTIES
1304
- */
1305
1287
  return /*#__PURE__*/React$1.createElement(FieldWrapper, Object.assign({
1306
- className: clsx('form-field_type_dropzone', 'form__item_type_dropzone', classNameGroupItem),
1307
- width: width,
1288
+ className: clsx('form-field_type_choice', 'form__item_type_choice', classNameGroupItem),
1308
1289
  label: label,
1309
- labelTextColor: labelTextColor,
1310
1290
  errorKey: errorKey,
1311
1291
  errorMessage: errorMessage,
1312
1292
  isErrorState: isErrorState,
1313
1293
  metaError: meta.error,
1314
- fieldClassName: "form-dropzone",
1294
+ isDisabled: isDisabled,
1295
+ fieldClassName: "form-choice",
1315
1296
  inputName: input.name,
1316
- inputValue: input.value,
1297
+ inputValue: input.value || [],
1298
+ messageType: messageType,
1317
1299
  metaActive: meta.active,
1318
- metaTouched: meta.touched,
1319
1300
  showMessage: showMessage,
1320
1301
  isRequired: isRequired,
1321
1302
  isValidState: isValidState
1322
- }, fieldProps), /*#__PURE__*/React$1.createElement(FileInputDropzone, {
1323
- className: className,
1324
- maxFiles: maxFiles,
1325
- maxSize: maxSize,
1326
- size: size,
1327
- fill: fill,
1328
- fillHover: fillHover,
1329
- borderColor: updatedInputProps.borderColor,
1330
- borderColorHover: borderColorHover,
1331
- borderType: borderType,
1332
- borderWidth: borderWidth,
1333
- errorMessageTextColor: errorMessageTextColor,
1334
- errorMessageTextSize: errorMessageTextSize,
1335
- errorMessageWeight: errorMessageTextWeight,
1336
- fileErrorText: fileErrorText,
1337
- metaError: meta.error,
1338
- dropzoneProps: dropzoneProps,
1339
- hintDescription: hintDescription,
1340
- hintDescriptionTextColor: hintDescriptionTextColor,
1341
- hintDescriptionTextSize: hintDescriptionTextSize,
1342
- hintDescriptionTextWeight: hintDescriptionTextWeight,
1343
- hintDescriptionTextWrap: hintDescriptionTextWrap,
1344
- hintTitle: hintTitle,
1345
- hintTitleTextColor: hintTitleTextColor,
1346
- hintTitleTextSize: hintTitleTextSize,
1347
- hintTitleTextWeight: hintTitleTextWeight,
1348
- hintTitleTextWrap: hintTitleTextWrap,
1349
- inputName: input.name,
1350
- inputValue: input.value,
1351
- metaTouched: meta.touched,
1352
- removeThumbAppearance: removeThumbAppearance,
1353
- removeThumbText: removeThumbText,
1354
- removeThumbTextWeight: removeThumbTextWeight,
1355
- removeThumbShape: removeThumbShape,
1356
- shape: shape,
1357
- showFilename: showFilename,
1358
- thumbBorderColor: thumbBorderColor,
1359
- thumbBorderColorHover: thumbBorderColorHover,
1360
- thumbBorderType: thumbBorderType,
1361
- thumbBorderWidth: thumbBorderWidth,
1362
- thumbColumn: thumbColumn,
1363
- thumbDirection: thumbDirection,
1364
- thumbNameTextColor: thumbNameTextColor,
1365
- thumbNameTextSize: thumbNameTextSize,
1366
- thumbNameTextWeight: thumbNameTextWeight,
1367
- thumbNameTextWrap: thumbNameTextWrap,
1368
- isPreviews: isPreviews,
1369
- onAddFiles: onAddFiles,
1370
- onDeleteFile: onDeleteFile
1371
- }));
1303
+ }, fieldProps), /*#__PURE__*/React$1.createElement(Choice, Object.assign({
1304
+ className: clsx(meta.active && 'form-choice_state_focus', meta.error && meta.touched && `form-choice_state_${errorKey}`),
1305
+ name: input.name,
1306
+ isDisabled: isDisabled,
1307
+ active: activeOption,
1308
+ inputValue: input.value || [],
1309
+ options: options,
1310
+ placeholder: placeholder,
1311
+ isCheckbox: isCheckbox,
1312
+ isRequired: isRequired,
1313
+ setActiveSegment: setActiveSegment
1314
+ }, updatedInputProps)));
1372
1315
  });
1373
1316
  });
1374
1317
 
1375
- const defaultGroupProps = {
1376
- width: 'fill',
1377
- labelTextColor: 'surfaceTextPrimary',
1378
- labelTextSize: 'h5',
1379
- labelTextWeight: 500
1318
+ const defaultCodeProps = {
1319
+ appearance: 'defaultPrimary sizeL solid rounded'
1380
1320
  };
1381
1321
 
1382
- const Group = /*#__PURE__*/React$1.memo(function Group(props) {
1322
+ const FormFieldCode = /*#__PURE__*/React$1.memo(function FormFieldCode(props) {
1383
1323
  const {
1384
- className,
1385
1324
  name,
1386
- label,
1387
- labelTextColor,
1388
- labelTextSize,
1389
- labelTextWeight,
1390
- message,
1391
- column,
1392
- dataTour,
1393
- title,
1394
- titleTextSize,
1395
- titleTextColor,
1396
- titleTextWeight,
1397
- messageTextColor = 'surfaceTextTertiary',
1398
- messageTextSize = 's',
1399
- messageTextWeight,
1400
- showGroupMessage,
1401
- before,
1402
- after,
1403
- isHidden,
1404
- children
1325
+ initialValue,
1326
+ isDisabled,
1327
+ classNameGroupItem,
1328
+ fieldProps = {},
1329
+ inputProps = {},
1330
+ showMessage,
1331
+ isRequired
1332
+ } = props;
1333
+ return /*#__PURE__*/React$1.createElement(Field, {
1334
+ name: name,
1335
+ initialValue: initialValue
1336
+ }, function Render({
1337
+ input,
1338
+ meta
1339
+ }) {
1340
+ /** Note:
1341
+ * Create "Render" function by "eslint-react-hooks/rules-of-hooks":
1342
+ * React Hooks cannot be called inside a callback.
1343
+ * React Hooks must be called in a React function component or a
1344
+ * custom React Hook function.
1345
+ */
1346
+
1347
+ const {
1348
+ isErrorState,
1349
+ isValidState,
1350
+ errorKey} = useFieldValidationState({
1351
+ fieldProps: fieldProps,
1352
+ input: input,
1353
+ meta: meta
1354
+ });
1355
+ const updatedInputProps = useValidationAppearanceInputProps({
1356
+ inputProps: inputProps,
1357
+ validationStateKey: isErrorState ? errorKey : 'success'
1358
+ });
1359
+ return /*#__PURE__*/React$1.createElement(FieldWrapper, Object.assign({
1360
+ className: clsx('form-field_type_code', 'form__item_type_code', classNameGroupItem),
1361
+ fieldClassName: 'form-code',
1362
+ inputName: input.name,
1363
+ inputValue: input.value,
1364
+ metaActive: meta.active,
1365
+ showMessage: showMessage,
1366
+ isRequired: isRequired,
1367
+ isValidState: isValidState
1368
+ }, fieldProps), /*#__PURE__*/React$1.createElement(Code, Object.assign({
1369
+ name: input.name,
1370
+ isDisabled: isDisabled,
1371
+ autoComplete: "nope",
1372
+ value: input.value,
1373
+ onBlur: input.onBlur,
1374
+ onChange: input.onChange,
1375
+ onFocus: input.onFocus
1376
+ }, updatedInputProps)));
1377
+ });
1378
+ });
1379
+
1380
+ const FormFieldCustom = /*#__PURE__*/React$1.memo(function FormFieldCustom(props) {
1381
+ const {
1382
+ Component,
1383
+ isDisabled,
1384
+ isRequired,
1385
+ name,
1386
+ initialValue,
1387
+ fieldProps = {},
1388
+ classNameGroupItem,
1389
+ showMessage,
1390
+ clearIcon,
1391
+ clearIconFill,
1392
+ clearIconFillHover,
1393
+ clearIconShape,
1394
+ clearIconSize,
1395
+ onClickClearIcon
1396
+ } = props;
1397
+ return /*#__PURE__*/React$1.createElement(Field, {
1398
+ initialValue: initialValue,
1399
+ name: name
1400
+ }, function Render({
1401
+ input,
1402
+ meta
1403
+ }) {
1404
+ /** Note:
1405
+ * Create "Render" function by "eslint-react-hooks/rules-of-hooks":
1406
+ * React Hooks cannot be called inside a callback.
1407
+ * React Hooks must be called in a React function component or a
1408
+ * custom React Hook function.
1409
+ */
1410
+
1411
+ const {
1412
+ isErrorState,
1413
+ isValidState,
1414
+ errorKey,
1415
+ errorMessage
1416
+ } = useFieldValidationState({
1417
+ fieldProps: fieldProps,
1418
+ input: input,
1419
+ meta: meta
1420
+ });
1421
+ const updatedInputProps = useValidationAppearanceInputProps({
1422
+ validationStateKey: isErrorState ? errorKey : 'success',
1423
+ // For "Custom" field we pass all props. Can contain some special props, we don't known.
1424
+ inputProps: props
1425
+ });
1426
+ return /*#__PURE__*/React$1.createElement(FieldWrapper, Object.assign({
1427
+ className: clsx('form-field_type_custom', 'form__item_type_custom', classNameGroupItem),
1428
+ errorKey: errorKey,
1429
+ errorMessage: errorMessage,
1430
+ fieldClassName: 'form-custom',
1431
+ inputName: input.name,
1432
+ inputValue: input.value,
1433
+ isDisabled: isDisabled,
1434
+ isErrorState: isErrorState,
1435
+ isRequired: isRequired,
1436
+ isValidState: isValidState,
1437
+ metaActive: meta.active,
1438
+ metaError: meta.error,
1439
+ showMessage: showMessage
1440
+ }, fieldProps), /*#__PURE__*/React$1.createElement(Component, Object.assign({}, updatedInputProps, {
1441
+ input: input,
1442
+ isDisabled: isDisabled,
1443
+ meta: meta
1444
+ })), clearIcon && /*#__PURE__*/React$1.createElement(Icon, {
1445
+ className: "form-field__icon",
1446
+ iconFill: clearIconFill,
1447
+ iconFillHover: clearIconFillHover,
1448
+ imageSrc: clearIcon,
1449
+ shape: clearIconShape,
1450
+ size: clearIconSize,
1451
+ SvgImage: clearIcon,
1452
+ onClick: onClickClearIcon
1453
+ }));
1454
+ });
1455
+ });
1456
+
1457
+ const defaultDatepickerProps = {
1458
+ appearance: 'surfacePrimary sizeS',
1459
+ dateFormat: 'dd/MM/yyyy - HH:mm',
1460
+ readOnly: false,
1461
+ selectsRange: false,
1462
+ showTimeSelect: true,
1463
+ timeCaption: 'Время',
1464
+ timeFormat: 'p',
1465
+ timeIntervals: 60,
1466
+ isClearable: true,
1467
+ isStartDefaultNull: true
1468
+ };
1469
+
1470
+ function FormFieldDatePicker(props) {
1471
+ const {
1472
+ name,
1473
+ isDisabled,
1474
+ classNameGroupItem,
1475
+ datePickerProps,
1476
+ fieldProps = {},
1477
+ inputProps = {},
1478
+ showMessage,
1479
+ isRequired,
1480
+ onChange
1405
1481
  } = props;
1406
1482
  return /*#__PURE__*/React$1.createElement(Field, {
1407
1483
  name: name
@@ -1415,66 +1491,73 @@ const Group = /*#__PURE__*/React$1.memo(function Group(props) {
1415
1491
  * React Hooks must be called in a React function component or a
1416
1492
  * custom React Hook function.
1417
1493
  */
1494
+
1495
+ const onChangeField = useCallback((startDate, endDate) => {
1496
+ if (!datePickerProps.selectsRange) {
1497
+ // When we need to save single date, value is date
1498
+ // TODO: make object with one date? need to check all forms with FormFieldDatePicker
1499
+ input.onChange(startDate);
1500
+ } else {
1501
+ // When we need to save range, value is object with two date
1502
+ input.onChange({
1503
+ endDate,
1504
+ startDate
1505
+ });
1506
+ }
1507
+ if (onChange) {
1508
+ onChange(startDate, endDate);
1509
+ }
1510
+ }, [input.onChange, onChange]);
1418
1511
  const {
1419
- isErrorState,
1420
1512
  errorKey,
1421
- errorMessage
1513
+ errorMessage,
1514
+ isErrorState,
1515
+ isValidState
1422
1516
  } = useFieldValidationState({
1423
- fieldProps: props,
1424
- // or fieldProps?
1517
+ fieldProps: fieldProps,
1425
1518
  input: input,
1426
1519
  meta: meta
1427
1520
  });
1428
- const updatedProps = useValidationAppearanceInputProps({
1429
- inputProps: props,
1521
+ const updatedInputProps = useValidationAppearanceInputProps({
1522
+ inputProps: inputProps,
1430
1523
  validationStateKey: isErrorState ? errorKey : 'success'
1431
1524
  });
1432
- return /*#__PURE__*/React$1.createElement("div", {
1433
- className: clsx('form__group', className, isHidden && 'form__group_hidden', column && `form__group_column_${column}`),
1434
- "data-tour": dataTour
1435
- }, /*#__PURE__*/React$1.createElement("div", {
1436
- className: "form__group-wrapper"
1437
- }, before, title && /*#__PURE__*/React$1.createElement("div", {
1438
- className: "form__group-title"
1439
- }, /*#__PURE__*/React$1.createElement(Title, {
1440
- size: titleTextSize,
1441
- textColor: titleTextColor,
1442
- textWeight: titleTextWeight
1443
- }, title)), label && /*#__PURE__*/React$1.createElement("div", {
1444
- className: "form__group-label"
1445
- }, /*#__PURE__*/React$1.createElement(Text, {
1446
- size: labelTextSize,
1447
- textColor: labelTextColor,
1448
- textWeight: labelTextWeight
1449
- }, label)), /*#__PURE__*/React$1.createElement("div", {
1450
- className: "form__group-items"
1451
- }, children), after), showGroupMessage && /*#__PURE__*/React$1.createElement(React$1.Fragment, null, isErrorState && errorMessage && /*#__PURE__*/React$1.createElement(Text, {
1452
- className: `form__group-message form__group-message_type-${errorKey}`,
1453
- id: `${name}-error`,
1454
- size: updatedProps.messageTextSize,
1455
- textColor: updatedProps.messageTextColor,
1456
- textWeight: updatedProps.messageTextWeight
1457
- }, errorMessage), Boolean(message) && (!isErrorState || !errorMessage) && /*#__PURE__*/React$1.createElement(Text, {
1458
- className: "form__group-message",
1459
- size: messageTextSize,
1460
- textColor: messageTextColor,
1461
- textWeight: messageTextWeight
1462
- }, message), !isErrorState && !message && /*#__PURE__*/React$1.createElement(Text, {
1463
- className: "form__group-message",
1464
- size: messageTextSize
1465
- }, '\u00A0')));
1525
+ return /*#__PURE__*/React$1.createElement(FieldWrapper, Object.assign({
1526
+ className: clsx('form-field_type_datepicker', 'form__item_type_datepicker', classNameGroupItem),
1527
+ errorKey: errorKey,
1528
+ errorMessage: errorMessage,
1529
+ isErrorState: isErrorState,
1530
+ metaError: meta.error,
1531
+ isDisabled: isDisabled,
1532
+ fieldClassName: "form-datepicker",
1533
+ inputName: input.name,
1534
+ inputValue: input.value || '',
1535
+ metaActive: meta.active,
1536
+ showMessage: showMessage,
1537
+ isRequired: isRequired,
1538
+ isValidState: isValidState
1539
+ }, fieldProps), /*#__PURE__*/React$1.createElement(DatePickerInput, {
1540
+ name: input.name,
1541
+ isDisabled: isDisabled,
1542
+ datePickerProps: datePickerProps,
1543
+ endValue: datePickerProps.selectsRange ? input.value.endDate : null,
1544
+ inputProps: updatedInputProps,
1545
+ value: datePickerProps.selectsRange ? input.value.startDate : input.value,
1546
+ onBlur: input.onBlur,
1547
+ onChange: onChangeField,
1548
+ onFocus: input.onFocus
1549
+ }));
1466
1550
  });
1467
- });
1551
+ }
1468
1552
 
1469
1553
  const defaultInputProps = {
1470
- appearance: 'sizeM defaultSecondary',
1554
+ appearance: 'sizeM defaultSecondary solid rounded',
1471
1555
  width: 'fill',
1472
1556
  errorBorderColor: 'errorBorderSecondary',
1473
- requiredBorderColor: 'warningBorderSecondary',
1474
- shape: 'rounded'
1557
+ requiredBorderColor: 'warningBorderSecondary'
1475
1558
  };
1476
1559
 
1477
- const InputField = /*#__PURE__*/React$1.memo(function InputField(props) {
1560
+ const FormFieldInput = /*#__PURE__*/React$1.memo(function FormFieldInput(props) {
1478
1561
  const {
1479
1562
  name,
1480
1563
  initialValue,
@@ -1489,33 +1572,13 @@ const InputField = /*#__PURE__*/React$1.memo(function InputField(props) {
1489
1572
  clearIconShape,
1490
1573
  clearIconSize,
1491
1574
  fieldProps = {},
1492
- iconFill,
1493
- iconFillHover,
1494
- iconRevealableHide,
1495
- iconRevealableShow,
1496
- iconShape,
1497
- iconSize,
1498
1575
  inputProps = {},
1499
1576
  parse,
1500
1577
  showMessage,
1501
- isPassword,
1502
1578
  isRequired,
1503
- isRevealable,
1504
1579
  onChange,
1505
1580
  onClickClearIcon
1506
1581
  } = props;
1507
- const [isRevealed, setIsRevealed] = useState(false);
1508
- const inputType = useMemo(() => {
1509
- if (isPassword) {
1510
- return isRevealed ? 'text' : 'password';
1511
- } else {
1512
- return 'text';
1513
- }
1514
- }, [isRevealed, isPassword]);
1515
- const onClickIconReveal = useCallback(event => {
1516
- event.preventDefault();
1517
- setIsRevealed(prev => !prev);
1518
- }, []);
1519
1582
  return /*#__PURE__*/React$1.createElement(Field, {
1520
1583
  name: name,
1521
1584
  initialValue: initialValue,
@@ -1551,7 +1614,6 @@ const InputField = /*#__PURE__*/React$1.memo(function InputField(props) {
1551
1614
  inputProps: inputProps,
1552
1615
  validationStateKey: isErrorState ? errorKey : 'success'
1553
1616
  });
1554
- const isIconRevealableString = typeof iconRevealableHide === 'string' && typeof iconRevealableShow === 'string';
1555
1617
  return /*#__PURE__*/React$1.createElement(FieldWrapper, Object.assign({
1556
1618
  className: clsx('form-field_type_input', 'form__item_type_input', classNameGroupItem),
1557
1619
  errorKey: errorKey,
@@ -1559,7 +1621,7 @@ const InputField = /*#__PURE__*/React$1.memo(function InputField(props) {
1559
1621
  isErrorState: isErrorState,
1560
1622
  metaError: meta.error,
1561
1623
  isDisabled: isDisabled,
1562
- fieldClassName: isRevealable ? 'form-password' : 'form-input',
1624
+ fieldClassName: "form-input",
1563
1625
  inputName: input.name,
1564
1626
  inputValue: input.value || '',
1565
1627
  metaActive: meta.active,
@@ -1567,26 +1629,17 @@ const InputField = /*#__PURE__*/React$1.memo(function InputField(props) {
1567
1629
  isRequired: isRequired,
1568
1630
  isValidState: isValidState
1569
1631
  }, fieldProps), /*#__PURE__*/React$1.createElement(Input, Object.assign({
1632
+ dataTestId: `${input.name}FieldInput`,
1570
1633
  className: clsx(meta.active && 'input_state_focus', meta.error && meta.touched && `input_state_${errorKey}`),
1571
- type: inputType,
1634
+ type: "text",
1572
1635
  name: input.name,
1573
1636
  isDisabled: isDisabled,
1574
1637
  autoComplete: "nope",
1575
- dataTestId: `${input.name}FieldInput`,
1576
1638
  value: input.value || '',
1577
1639
  onBlur: input.onBlur,
1578
1640
  onChange: onChangeField,
1579
1641
  onFocus: input.onFocus
1580
- }, updatedInputProps)), isRevealable && /*#__PURE__*/React$1.createElement(Icon, {
1581
- className: "form-field__icon",
1582
- size: iconSize,
1583
- iconFill: iconFill,
1584
- iconFillHover: iconFillHover,
1585
- imageSrc: isRevealed && isIconRevealableString ? iconRevealableHide : iconRevealableShow,
1586
- shape: iconShape,
1587
- SvgImage: isRevealed && !isIconRevealableString ? iconRevealableHide : iconRevealableShow,
1588
- onClick: onClickIconReveal
1589
- }), clearIcon && /*#__PURE__*/React$1.createElement(Icon, {
1642
+ }, updatedInputProps)), clearIcon && /*#__PURE__*/React$1.createElement(Icon, {
1590
1643
  className: "form-field__icon",
1591
1644
  size: clearIconSize,
1592
1645
  iconFill: clearIconFill,
@@ -1599,152 +1652,44 @@ const InputField = /*#__PURE__*/React$1.memo(function InputField(props) {
1599
1652
  });
1600
1653
  });
1601
1654
 
1602
- const defaultRadioProps = {
1603
- fieldProps: {
1604
- width: 'fill',
1605
- size: 'm',
1606
- labelTextColor: 'surfaceTextPrimary',
1607
- labelTextSize: 's',
1608
- labelTextWeight: 'normal',
1609
- textColor: 'surfaceTextPrimary',
1610
- helpText: 'Supporting text',
1611
- helpTextColor: 'surfaceTextPrimary',
1612
- helpTextSize: 's',
1613
- helpTextWeight: 'normal',
1614
- showMessage: true
1615
- },
1616
- inputProps: {
1617
- width: 'fill',
1618
- size: 'm',
1619
- labelTextColor: 'surfaceTextPrimary',
1620
- labelTextSize: 's',
1621
- descTextColor: 'surfaceTextPrimary',
1622
- descTextSize: 's'
1623
- }
1655
+ const defaultPasswordProps = {
1656
+ appearance: 'sizeM defaultSecondary solid rounded',
1657
+ iconRevealableHide: icons24.View.HideValue,
1658
+ iconRevealableShow: icons24.View.ShowValue,
1659
+ iconFill: 'surfaceItemQuaternary'
1624
1660
  };
1625
1661
 
1626
- function RadioGroupInput(props) {
1627
- const {
1628
- input,
1629
- value,
1630
- onChange
1631
- } = props;
1632
- const onChangeField = useCallback(event => onChange(event.target.value), [onChange]);
1633
- return /*#__PURE__*/React.createElement(Input, Object.assign({
1634
- name: input.name,
1635
- autoComplete: "nope",
1636
- value: value,
1637
- onBlur: input.onBlur,
1638
- onChange: onChangeField,
1639
- onFocus: input.onFocus
1640
- }, props));
1641
- }
1642
-
1643
- function RadioGroupItem(props) {
1644
- const {
1645
- input,
1646
- inputProps,
1647
- option,
1648
- onChange
1649
- } = props;
1650
- const onChangeField = useCallback(event => {
1651
- if (event.target.checked) {
1652
- onChange(option.value);
1653
- }
1654
- }, [onChange]);
1655
- return /*#__PURE__*/React.createElement(Radio, Object.assign({
1656
- className: "form-radio__item",
1657
- type: "radio",
1658
- name: input.name,
1659
- label: option.label,
1660
- checked: option.value === input.value,
1661
- value: option.value,
1662
- onBlur: input.onBlur,
1663
- onChange: onChangeField,
1664
- onFocus: input.onFocus
1665
- }, inputProps));
1666
- }
1667
-
1668
- function RadioGroupList(props) {
1669
- const {
1670
- editableProps,
1671
- input,
1672
- inputProps,
1673
- options,
1674
- onChange
1675
- } = props;
1676
- const [editableValue, setEditableValue] = useState(() => {
1677
- const isRadioValue = options.find(option => option.value === input.value);
1678
- if (!isRadioValue) {
1679
- return input.value;
1680
- }
1681
- return '';
1682
- });
1683
- useEffect(() => {
1684
- // When a new value from outside enters the form
1685
- if (input.value) {
1686
- // Check value for radio type
1687
- const isRadioValue = options.find(option => option.value === input.value && !option.editable);
1688
- // If new value not in radio list - set to editable input
1689
- setEditableValue(isRadioValue ? '' : input.value);
1690
- } else {
1691
- // If new value is empty - clear editable input
1692
- setEditableValue('');
1693
- }
1694
- }, [input.value]);
1695
-
1696
- // Callback for value changes
1697
- const onChangeSomeInput = useCallback(value => {
1698
- // Save to form values
1699
- input.onChange(value);
1700
- if (onChange) {
1701
- // Pass to custom event
1702
- onChange(value, input.name);
1703
- }
1704
- }, [input, onChange]);
1705
-
1706
- // Handle for radio inputs
1707
- const onChangeRadio = useCallback(value => {
1708
- setEditableValue('');
1709
- onChangeSomeInput(value);
1710
- }, [onChangeSomeInput]);
1711
-
1712
- // Handle for text input
1713
- const onChangeEditable = useCallback(value => {
1714
- setEditableValue(value);
1715
- onChangeSomeInput(value);
1716
- }, [onChangeSomeInput]);
1717
- return /*#__PURE__*/React$1.createElement(React$1.Fragment, null, options.map(option => option.editable ? /*#__PURE__*/React$1.createElement(RadioGroupInput, {
1718
- key: option.label,
1719
- editableProps: editableProps,
1720
- input: input,
1721
- inputProps: inputProps,
1722
- option: option,
1723
- value: editableValue,
1724
- onChange: onChangeEditable
1725
- }) : /*#__PURE__*/React$1.createElement(RadioGroupItem, {
1726
- key: option.value,
1727
- input: input,
1728
- inputProps: inputProps,
1729
- option: option,
1730
- onChange: onChangeRadio
1731
- })));
1732
- }
1733
-
1734
- const RadioGroup = /*#__PURE__*/React$1.memo(function RadioGroup(props) {
1662
+ const FormFieldPassword = /*#__PURE__*/React$1.memo(function FormFieldPassword(props) {
1735
1663
  const {
1736
1664
  name,
1665
+ initialValue,
1737
1666
  isDisabled,
1738
- editableProps = {},
1739
- fieldProps = {},
1740
- inputProps = {},
1741
- options = [],
1667
+ classNameGroupItem,
1668
+ fieldProps,
1669
+ iconFill,
1670
+ iconFillHover,
1671
+ iconRevealableHide,
1672
+ iconRevealableShow,
1673
+ iconShape,
1674
+ iconSize,
1675
+ inputProps,
1676
+ parse,
1742
1677
  showMessage,
1743
1678
  isRequired,
1744
1679
  onChange
1745
1680
  } = props;
1681
+ const [isRevealed, setIsRevealed] = useState(false);
1682
+ const inputType = useMemo(() => {
1683
+ return isRevealed ? 'text' : 'password';
1684
+ }, [isRevealed]);
1685
+ const onClickIconReveal = useCallback(event => {
1686
+ event.preventDefault();
1687
+ setIsRevealed(prev => !prev);
1688
+ }, []);
1746
1689
  return /*#__PURE__*/React$1.createElement(Field, {
1747
- name: name
1690
+ name: name,
1691
+ initialValue: initialValue,
1692
+ parse: parse
1748
1693
  }, function Render({
1749
1694
  input,
1750
1695
  meta
@@ -1756,11 +1701,17 @@ const RadioGroup = /*#__PURE__*/React$1.memo(function RadioGroup(props) {
1756
1701
  * custom React Hook function.
1757
1702
  */
1758
1703
 
1704
+ const onChangeField = useCallback(event => {
1705
+ input.onChange(event);
1706
+ if (onChange) {
1707
+ onChange(event.target.value, input.name);
1708
+ }
1709
+ }, [onChange, input.onChange]);
1759
1710
  const {
1760
- errorKey,
1761
- errorMessage,
1762
1711
  isErrorState,
1763
- isValidState
1712
+ isValidState,
1713
+ errorKey,
1714
+ errorMessage
1764
1715
  } = useFieldValidationState({
1765
1716
  fieldProps: fieldProps,
1766
1717
  input: input,
@@ -1771,39 +1722,48 @@ const RadioGroup = /*#__PURE__*/React$1.memo(function RadioGroup(props) {
1771
1722
  validationStateKey: isErrorState ? errorKey : 'success'
1772
1723
  });
1773
1724
  return /*#__PURE__*/React$1.createElement(FieldWrapper, Object.assign({
1774
- className: clsx('form-field_type_radio', 'form__item_type_radio"', classNameGroupItem),
1725
+ className: clsx('form-field_type_input', 'form__item_type_input', classNameGroupItem),
1775
1726
  errorKey: errorKey,
1776
1727
  errorMessage: errorMessage,
1777
1728
  isErrorState: isErrorState,
1778
1729
  metaError: meta.error,
1779
1730
  isDisabled: isDisabled,
1780
- fieldClassName: 'form-radio',
1731
+ fieldClassName: "form-password",
1781
1732
  inputName: input.name,
1782
1733
  inputValue: input.value || '',
1783
1734
  metaActive: meta.active,
1784
1735
  showMessage: showMessage,
1785
1736
  isRequired: isRequired,
1786
1737
  isValidState: isValidState
1787
- }, fieldProps), /*#__PURE__*/React$1.createElement(RadioGroupList, {
1738
+ }, fieldProps), /*#__PURE__*/React$1.createElement(Input, Object.assign({
1739
+ dataTestId: `${input.name}FieldInputPassword`,
1740
+ className: clsx(meta.active && 'input_state_focus', meta.error && meta.touched && `input_state_${errorKey}`),
1741
+ type: inputType,
1742
+ name: input.name,
1788
1743
  isDisabled: isDisabled,
1789
- editableProps: editableProps,
1790
- input: input,
1791
- inputProps: updatedInputProps,
1792
- options: options,
1793
- onChange: onChange
1744
+ autoComplete: "nope",
1745
+ value: input.value || '',
1746
+ onBlur: input.onBlur,
1747
+ onChange: onChangeField,
1748
+ onFocus: input.onFocus
1749
+ }, updatedInputProps)), /*#__PURE__*/React$1.createElement(Icon, {
1750
+ className: "form-field__icon",
1751
+ size: inputProps.iconSize,
1752
+ iconFill: inputProps.iconFill,
1753
+ SvgImage: isRevealed ? inputProps.iconRevealableHide : inputProps.iconRevealableShow,
1754
+ onClick: onClickIconReveal
1794
1755
  }));
1795
1756
  });
1796
1757
  });
1797
1758
 
1798
1759
  const defaultSegmentedProps = {
1799
- appearance: 'sizeM surfacePrimary',
1760
+ appearance: 'defaultPrimary sizeM solid rounded',
1800
1761
  width: 'fill',
1801
1762
  errorLabelTextColor: 'errorTextPrimary',
1802
- requiredLabelTextColor: 'warningTextPrimary',
1803
- shape: 'rounded'
1763
+ requiredLabelTextColor: 'warningTextPrimary'
1804
1764
  };
1805
1765
 
1806
- function SegmentedField(props) {
1766
+ function FormFieldSegmented(props) {
1807
1767
  const {
1808
1768
  name,
1809
1769
  isDisabled,
@@ -1881,36 +1841,7 @@ function SegmentedField(props) {
1881
1841
  }
1882
1842
 
1883
1843
  const defaultSelectProps = {
1884
- elevation: 8,
1885
- isClearable: true,
1886
- isSearchable: true,
1887
- badgeAppearance: 'accent',
1888
- badgeSize: 'm',
1889
- badgeTextSize: 'm',
1890
- // clearIcon: icon24.Clear,
1891
- clearIconFill: 'surfaceItemPrimary',
1892
- closeMenuOnSelect: true,
1893
- // optionSelected: <Icon iconFill="surfaceItemAccent" SvgImage={icon24.Check} />,
1894
-
1895
- dividerDirection: 'horizontal',
1896
- dividerFill: 'surfaceTertiary',
1897
- dividerSize: 'xxs',
1898
- // dropdownIcon: icon24.ChevronDownSmall,
1899
- dropdownIconFill: 'surfaceItemPrimary',
1900
- // error
1901
- errorInputBorderColor: 'errorBorderPrimary',
1902
- headingFill: 'surfaceSecondary',
1903
- loadingMessage: /*#__PURE__*/React$1.createElement(Loader, {
1904
- width: "fill",
1905
- height: "fill",
1906
- fill: "surfacePrimary",
1907
- position: "absolute",
1908
- left: "0px",
1909
- right: "0px",
1910
- zIndex: "1",
1911
- itemFill: "surfaceItemAccent",
1912
- set: "simple"
1913
- })
1844
+ appearance: 'defaultPrimary sizeM'
1914
1845
  };
1915
1846
 
1916
1847
  function getDefaultValue(options, selectValue) {
@@ -1931,7 +1862,7 @@ function getDefaultValue(options, selectValue) {
1931
1862
  });
1932
1863
  return result;
1933
1864
  }
1934
- const SelectField = /*#__PURE__*/React$1.memo(function SelectField(props) {
1865
+ const FormFieldSelect = /*#__PURE__*/React$1.memo(function FormFieldSelect(props) {
1935
1866
  const {
1936
1867
  isDisabled,
1937
1868
  isRequired,
@@ -2014,10 +1945,10 @@ const SelectField = /*#__PURE__*/React$1.memo(function SelectField(props) {
2014
1945
  isValidState: isValidState
2015
1946
  }, fieldProps), /*#__PURE__*/React$1.createElement(Select, Object.assign({
2016
1947
  className: "form-select-item",
1948
+ ref: selectRef,
2017
1949
  isDisabled: isDisabled,
2018
1950
  instanceId: `id_${input.name}`,
2019
1951
  options: options,
2020
- ref: selectRef,
2021
1952
  value: selectedOptions,
2022
1953
  onChange: onChangeValue,
2023
1954
  onInputChange: onInputChange
@@ -2026,32 +1957,10 @@ const SelectField = /*#__PURE__*/React$1.memo(function SelectField(props) {
2026
1957
  });
2027
1958
 
2028
1959
  const defaultSwitchProps = {
2029
- fieldProps: {
2030
- width: 'fill',
2031
- size: 'xl',
2032
- labelTextColor: 'surfaceTextPrimary',
2033
- labelTextSize: 's',
2034
- labelTextWeight: 'normal',
2035
- textColor: 'surfaceTextPrimary',
2036
- helpText: 'Supporting text',
2037
- helpTextColor: 'surfaceTextPrimary',
2038
- helpTextSize: 's',
2039
- helpTextWeight: 'normal',
2040
- showMessage: true
2041
- },
2042
- inputProps: {
2043
- size: 'm',
2044
- fill: 'surfaceSecondary',
2045
- title: 'Switch',
2046
- titleTextColor: 'surfaceTextPrimary',
2047
- titleTextSize: 's',
2048
- desc: 'Description',
2049
- descTextColor: 'surfaceTextPrimary',
2050
- descTextSize: 'xs'
2051
- }
1960
+ appearance: 'defaultPrimary sizeL solid rounded'
2052
1961
  };
2053
1962
 
2054
- const SwitchField = /*#__PURE__*/React$1.memo(function SwitchField(props) {
1963
+ const FormFieldSwitch = /*#__PURE__*/React$1.memo(function FormFieldSwitch(props) {
2055
1964
  const {
2056
1965
  name,
2057
1966
  isDisabled,
@@ -2125,14 +2034,12 @@ const SwitchField = /*#__PURE__*/React$1.memo(function SwitchField(props) {
2125
2034
  });
2126
2035
 
2127
2036
  const defaultTextareaProps = {
2128
- appearance: 'sizeM defaultSecondary',
2129
- width: 'fill',
2037
+ appearance: 'defaultPrimary sizeM solid rounded',
2130
2038
  errorBorderColor: 'errorBorderSecondary',
2131
- requiredBorderColor: 'warningBorderSecondary',
2132
- shape: 'rounded'
2039
+ requiredBorderColor: 'warningBorderSecondary'
2133
2040
  };
2134
2041
 
2135
- const TextareaField = /*#__PURE__*/React$1.memo(function TextareaField(props) {
2042
+ const FormFieldTextarea = /*#__PURE__*/React$1.memo(function FormFieldTextarea(props) {
2136
2043
  const {
2137
2044
  name,
2138
2045
  isDisabled,
@@ -2184,10 +2091,12 @@ const TextareaField = /*#__PURE__*/React$1.memo(function TextareaField(props) {
2184
2091
  isRequired: isRequired,
2185
2092
  isValidState: isValidState
2186
2093
  }, fieldProps), /*#__PURE__*/React$1.createElement(Textarea, Object.assign({
2094
+ dataTestId: `${input.name}FieldTextarea`,
2095
+ className: clsx(meta.active && 'textarea_state_focus', meta.error && meta.touched && `textarea_state_${errorKey}`),
2187
2096
  name: input.name,
2188
2097
  isDisabled: isDisabled,
2189
2098
  autoComplete: "nope",
2190
- value: input.value,
2099
+ value: input.value || '',
2191
2100
  onBlur: input.onBlur,
2192
2101
  onChange: input.onChange,
2193
2102
  onFocus: input.onFocus
@@ -2195,7 +2104,7 @@ const TextareaField = /*#__PURE__*/React$1.memo(function TextareaField(props) {
2195
2104
  });
2196
2105
  });
2197
2106
 
2198
- const MaskedInputField = /*#__PURE__*/React$1.memo(function MaskedInputField(props) {
2107
+ const FormFieldMaskedInput = /*#__PURE__*/React$1.memo(function FormFieldMaskedInput(props) {
2199
2108
  const {
2200
2109
  name,
2201
2110
  initialValue,
@@ -2292,51 +2201,144 @@ const MaskedInputField = /*#__PURE__*/React$1.memo(function MaskedInputField(pro
2292
2201
  });
2293
2202
  });
2294
2203
 
2295
- const defaultChipsProps = {
2296
- appearance: 'surfacePrimary',
2297
- width: 'fill',
2298
- errorBorderColor: 'errorBorderSecondary',
2299
- requiredBorderColor: 'warningBorderSecondary'
2204
+ const defaultRadioProps = {
2205
+ appearance: 'defaultPrimary sizeM solid circular'
2300
2206
  };
2301
2207
 
2302
- function ChipsField(props) {
2208
+ function RadioGroupInput(props) {
2209
+ const {
2210
+ input,
2211
+ value,
2212
+ onChange
2213
+ } = props;
2214
+ const onChangeField = useCallback(event => onChange(event.target.value), [onChange]);
2215
+ return /*#__PURE__*/React.createElement(Input, Object.assign({
2216
+ name: input.name,
2217
+ autoComplete: "nope",
2218
+ value: value,
2219
+ onBlur: input.onBlur,
2220
+ onChange: onChangeField,
2221
+ onFocus: input.onFocus
2222
+ }, props));
2223
+ }
2224
+
2225
+ function RadioGroupItem(props) {
2226
+ const {
2227
+ input,
2228
+ inputProps,
2229
+ option,
2230
+ onChange
2231
+ } = props;
2232
+ const onChangeField = useCallback(event => {
2233
+ if (event.target.checked) {
2234
+ onChange(option.value);
2235
+ }
2236
+ }, [onChange]);
2237
+ return /*#__PURE__*/React.createElement(Radio, Object.assign({
2238
+ className: "form-radio__item",
2239
+ type: "radio",
2240
+ name: input.name,
2241
+ label: option.label,
2242
+ checked: option.value === input.value,
2243
+ value: option.value,
2244
+ onBlur: input.onBlur,
2245
+ onChange: onChangeField,
2246
+ onFocus: input.onFocus
2247
+ }, inputProps));
2248
+ }
2249
+
2250
+ function RadioGroupList(props) {
2251
+ const {
2252
+ editableProps,
2253
+ input,
2254
+ inputProps,
2255
+ options,
2256
+ onChange
2257
+ } = props;
2258
+ const [editableValue, setEditableValue] = useState(() => {
2259
+ const isRadioValue = options.find(option => option.value === input.value);
2260
+ if (!isRadioValue) {
2261
+ return input.value;
2262
+ }
2263
+ return '';
2264
+ });
2265
+ useEffect(() => {
2266
+ // When a new value from outside enters the form
2267
+ if (input.value) {
2268
+ // Check value for radio type
2269
+ const isRadioValue = options.find(option => option.value === input.value && !option.editable);
2270
+ // If new value not in radio list - set to editable input
2271
+ setEditableValue(isRadioValue ? '' : input.value);
2272
+ } else {
2273
+ // If new value is empty - clear editable input
2274
+ setEditableValue('');
2275
+ }
2276
+ }, [input.value]);
2277
+
2278
+ // Callback for value changes
2279
+ const onChangeSomeInput = useCallback(value => {
2280
+ // Save to form values
2281
+ input.onChange(value);
2282
+ if (onChange) {
2283
+ // Pass to custom event
2284
+ onChange(value, input.name);
2285
+ }
2286
+ }, [input, onChange]);
2287
+
2288
+ // Handle for radio inputs
2289
+ const onChangeRadio = useCallback(value => {
2290
+ setEditableValue('');
2291
+ onChangeSomeInput(value);
2292
+ }, [onChangeSomeInput]);
2293
+
2294
+ // Handle for text input
2295
+ const onChangeEditable = useCallback(value => {
2296
+ setEditableValue(value);
2297
+ onChangeSomeInput(value);
2298
+ }, [onChangeSomeInput]);
2299
+ return /*#__PURE__*/React$1.createElement(React$1.Fragment, null, options.map(option => option.editable ? /*#__PURE__*/React$1.createElement(RadioGroupInput, {
2300
+ key: option.label,
2301
+ editableProps: editableProps,
2302
+ input: input,
2303
+ inputProps: inputProps,
2304
+ option: option,
2305
+ value: editableValue,
2306
+ onChange: onChangeEditable
2307
+ }) : /*#__PURE__*/React$1.createElement(RadioGroupItem, {
2308
+ key: option.value,
2309
+ input: input,
2310
+ inputProps: inputProps,
2311
+ option: option,
2312
+ onChange: onChangeRadio
2313
+ })));
2314
+ }
2315
+
2316
+ const RadioGroup = /*#__PURE__*/React$1.memo(function RadioGroup(props) {
2303
2317
  const {
2304
2318
  name,
2305
- initialValue,
2306
2319
  isDisabled,
2320
+ editableProps = {},
2321
+ fieldProps = {},
2322
+ inputProps = {},
2323
+ options = [],
2307
2324
  classNameGroupItem,
2308
- emptyMessage,
2309
- emptyMessageTextColor,
2310
- emptyMessageTextSize,
2311
- fieldProps,
2312
- inputProps,
2313
- options,
2314
2325
  showMessage,
2315
2326
  isRequired,
2316
2327
  onChange
2317
2328
  } = props;
2318
- const {
2319
- change
2320
- } = useForm();
2321
-
2322
- // Callback for value changes
2323
- const onChangeSomeInput = useCallback((inputValue, newOptionValue) => {
2324
- const updatedValues = inputValue.includes(newOptionValue) ? inputValue.filter(selectedValue => selectedValue !== newOptionValue) : [...inputValue, newOptionValue];
2325
- change(name, updatedValues);
2326
- onChange && onChange(updatedValues);
2327
- }, [change, name, onChange]);
2328
- useEffect(() => {
2329
- initialValue && change(name, initialValue);
2330
- // update the form value only when the initialValue changes, so use disable eslint to ignore the warning
2331
- // eslint-disable-next-line react-hooks/exhaustive-deps
2332
- }, [initialValue]);
2333
2329
  return /*#__PURE__*/React$1.createElement(Field, {
2334
- name: name,
2335
- initialValue: initialValue
2330
+ name: name
2336
2331
  }, function Render({
2337
2332
  input,
2338
2333
  meta
2339
2334
  }) {
2335
+ /** Note:
2336
+ * Create "Render" function by "eslint-react-hooks/rules-of-hooks":
2337
+ * React Hooks cannot be called inside a callback.
2338
+ * React Hooks must be called in a React function component or a
2339
+ * custom React Hook function.
2340
+ */
2341
+
2340
2342
  const {
2341
2343
  errorKey,
2342
2344
  errorMessage,
@@ -2351,49 +2353,30 @@ function ChipsField(props) {
2351
2353
  inputProps: inputProps,
2352
2354
  validationStateKey: isErrorState ? errorKey : 'success'
2353
2355
  });
2354
- const activeOptionsList = useMemo(() => {
2355
- const emptyOptionsList = [{
2356
- label: null,
2357
- value: null
2358
- }];
2359
- if (input?.value) {
2360
- const currentOptions = options.filter(option => input.value?.includes(option.value));
2361
- return currentOptions || emptyOptionsList;
2362
- }
2363
- return emptyOptionsList;
2364
- }, [input.value]);
2365
2356
  return /*#__PURE__*/React$1.createElement(FieldWrapper, Object.assign({
2366
- className: clsx('form-field_type_chips', 'form__item_type_chips', classNameGroupItem),
2357
+ className: clsx('form-field_type_radio', 'form__item_type_radio"', classNameGroupItem),
2367
2358
  errorKey: errorKey,
2368
2359
  errorMessage: errorMessage,
2369
2360
  isErrorState: isErrorState,
2370
2361
  metaError: meta.error,
2371
2362
  isDisabled: isDisabled,
2372
- fieldClassName: "form-chips",
2363
+ fieldClassName: 'form-radio',
2373
2364
  inputName: input.name,
2374
- inputValue: input.value,
2365
+ inputValue: input.value || '',
2375
2366
  metaActive: meta.active,
2376
2367
  showMessage: showMessage,
2377
2368
  isRequired: isRequired,
2378
2369
  isValidState: isValidState
2379
- }, fieldProps), options.length ? /*#__PURE__*/React$1.createElement(ChipsGroup, {
2380
- direction: "horizontal",
2381
- gap: "1m",
2382
- wrap: "wrap"
2383
- }, options.map(option => /*#__PURE__*/React$1.createElement(Chips, Object.assign({
2384
- className: clsx(meta.active && 'form-chips_state_focus', meta.error && meta.touched && `form-chips_state_${errorKey}`),
2385
- key: option.value,
2386
- label: option.label,
2387
- isDisabled: option.isDisabled,
2388
- value: option.value,
2389
- isActive: activeOptionsList.some(activeOption => activeOption.value === option.value),
2390
- onClick: () => onChangeSomeInput(input.value, option.value)
2391
- }, updatedInputProps)))) : /*#__PURE__*/React$1.createElement(Text, {
2392
- size: emptyMessageTextSize,
2393
- textColor: emptyMessageTextColor
2394
- }, emptyMessage));
2370
+ }, fieldProps), /*#__PURE__*/React$1.createElement(RadioGroupList, {
2371
+ isDisabled: isDisabled,
2372
+ editableProps: editableProps,
2373
+ input: input,
2374
+ inputProps: updatedInputProps,
2375
+ options: options,
2376
+ onChange: onChange
2377
+ }));
2395
2378
  });
2396
- }
2379
+ });
2397
2380
 
2398
2381
  const formTypes = {
2399
2382
  code: 'code',
@@ -2417,43 +2400,43 @@ function generateField(field, config, props) {
2417
2400
  switch (field.type) {
2418
2401
  case formTypes.checkbox:
2419
2402
  {
2420
- return /*#__PURE__*/React$1.createElement(CheckboxField, Object.assign({
2403
+ return /*#__PURE__*/React$1.createElement(FormFieldCheckbox, Object.assign({
2421
2404
  key: config.key
2422
2405
  }, field, props));
2423
2406
  }
2424
2407
  case formTypes.choice:
2425
2408
  {
2426
- return /*#__PURE__*/React$1.createElement(ChoiceField, Object.assign({
2409
+ return /*#__PURE__*/React$1.createElement(FormFieldChoice, Object.assign({
2427
2410
  key: config.key
2428
2411
  }, field, props));
2429
2412
  }
2430
2413
  case formTypes.chips:
2431
2414
  {
2432
- return /*#__PURE__*/React$1.createElement(ChipsField, Object.assign({
2415
+ return /*#__PURE__*/React$1.createElement(FormFieldChips, Object.assign({
2433
2416
  key: config.key
2434
2417
  }, field, props));
2435
2418
  }
2436
2419
  case formTypes.code:
2437
2420
  {
2438
- return /*#__PURE__*/React$1.createElement(CodeField, Object.assign({
2421
+ return /*#__PURE__*/React$1.createElement(FormFieldCode, Object.assign({
2439
2422
  key: config.key
2440
2423
  }, field, props));
2441
2424
  }
2442
2425
  case formTypes.switch:
2443
2426
  {
2444
- return /*#__PURE__*/React$1.createElement(SwitchField, Object.assign({
2427
+ return /*#__PURE__*/React$1.createElement(FormFieldSwitch, Object.assign({
2445
2428
  key: config.key
2446
2429
  }, field, props));
2447
2430
  }
2448
2431
  case formTypes.segmented:
2449
2432
  {
2450
- return /*#__PURE__*/React$1.createElement(SegmentedField, Object.assign({
2433
+ return /*#__PURE__*/React$1.createElement(FormFieldSegmented, Object.assign({
2451
2434
  key: config.key
2452
2435
  }, field, props));
2453
2436
  }
2454
2437
  case formTypes.datePicker:
2455
2438
  {
2456
- return /*#__PURE__*/React$1.createElement(DatePickerField, Object.assign({
2439
+ return /*#__PURE__*/React$1.createElement(FormFieldDatePicker, Object.assign({
2457
2440
  key: config.key
2458
2441
  }, field, props));
2459
2442
  }
@@ -2471,37 +2454,43 @@ function generateField(field, config, props) {
2471
2454
  }
2472
2455
  case formTypes.select:
2473
2456
  {
2474
- return /*#__PURE__*/React$1.createElement(SelectField, Object.assign({
2457
+ return /*#__PURE__*/React$1.createElement(FormFieldSelect, Object.assign({
2475
2458
  key: config.key
2476
2459
  }, field, props));
2477
2460
  }
2478
2461
  case formTypes.text:
2479
2462
  {
2480
- return /*#__PURE__*/React$1.createElement(InputField, Object.assign({
2463
+ return /*#__PURE__*/React$1.createElement(FormFieldInput, Object.assign({
2464
+ key: config.key
2465
+ }, field, props));
2466
+ }
2467
+ case formTypes.password:
2468
+ {
2469
+ return /*#__PURE__*/React$1.createElement(FormFieldPassword, Object.assign({
2481
2470
  key: config.key
2482
2471
  }, field, props));
2483
2472
  }
2484
2473
  case formTypes.textarea:
2485
2474
  {
2486
- return /*#__PURE__*/React$1.createElement(TextareaField, Object.assign({
2475
+ return /*#__PURE__*/React$1.createElement(FormFieldTextarea, Object.assign({
2487
2476
  key: config.key
2488
2477
  }, field, props));
2489
2478
  }
2490
2479
  case formTypes.maskedInput:
2491
2480
  {
2492
- return /*#__PURE__*/React$1.createElement(MaskedInputField, Object.assign({
2481
+ return /*#__PURE__*/React$1.createElement(FormFieldMaskedInput, Object.assign({
2493
2482
  key: config.key
2494
2483
  }, field, props));
2495
2484
  }
2496
2485
  case formTypes.custom:
2497
2486
  {
2498
- return /*#__PURE__*/React$1.createElement(CustomField, Object.assign({
2487
+ return /*#__PURE__*/React$1.createElement(FormFieldCustom, Object.assign({
2499
2488
  key: config.key
2500
2489
  }, field, props));
2501
2490
  }
2502
2491
  case formTypes.group:
2503
2492
  {
2504
- return /*#__PURE__*/React$1.createElement(Group, Object.assign({
2493
+ return /*#__PURE__*/React$1.createElement(FormBlockGroup, Object.assign({
2505
2494
  key: config.key
2506
2495
  }, field, props), Object.entries(field.group).map(([key, value]) => {
2507
2496
  const groupProps = {
@@ -2781,7 +2770,7 @@ const FinalForm = /*#__PURE__*/React$1.forwardRef(function FinalForm(props, ref)
2781
2770
  values: true
2782
2771
  },
2783
2772
  onChange: onChangeFormValues
2784
- }), Boolean(Object.keys(config).length) && /*#__PURE__*/React$1.createElement(React$1.Fragment, null, renderFieldsWrapper(/*#__PURE__*/React$1.createElement(Group$1, {
2773
+ }), Boolean(Object.keys(config).length) && /*#__PURE__*/React$1.createElement(React$1.Fragment, null, renderFieldsWrapper(/*#__PURE__*/React$1.createElement(Group, {
2785
2774
  className: "form__wrapper",
2786
2775
  direction: "vertical",
2787
2776
  gap: fieldsGap || groupGap,
@@ -2797,7 +2786,7 @@ const FinalForm = /*#__PURE__*/React$1.forwardRef(function FinalForm(props, ref)
2797
2786
  text: loaderText,
2798
2787
  itemFill: loaderItemFill,
2799
2788
  shape: loaderShape
2800
- }))))), (primaryButtonLabel || primaryButton || secondaryButtonLabel || secondaryButton || tertiaryButton || tertiaryButtonLabel) && /*#__PURE__*/React$1.createElement(Group$1, {
2789
+ }))))), (primaryButtonLabel || primaryButton || secondaryButtonLabel || secondaryButton || tertiaryButton || tertiaryButtonLabel) && /*#__PURE__*/React$1.createElement(Group, {
2801
2790
  className: "form__button",
2802
2791
  direction: buttonDirection,
2803
2792
  justifyContent: buttonJustifyContent,
@@ -3078,4 +3067,4 @@ const getErrorsForFinalForm = error => {
3078
3067
  return formErrors;
3079
3068
  };
3080
3069
 
3081
- 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, defaultGroupProps, defaultInputProps, defaultRadioProps, defaultSegmentedProps, defaultSelectProps, defaultSwitchProps, defaultTextareaProps, emailValidation, focusOnError, focusOnErrorDecorator, formTypes, generateField, getErrorsForFinalForm, parseNumericField, phoneValidation, sendFormDataToServer, setErrorsMutator, useYupValidationSchema };
3070
+ export { DEFAULT_MESSAGES_FIELDS, FieldWrapper, FieldWrapperBase, FileInput, FinalForm, FormBlockGroup, FormFieldCheckbox, FormFieldChips, FormFieldChoice, FormFieldCode, FormFieldCustom, FormFieldDatePicker, FormFieldInput, FormFieldMaskedInput, FormFieldPassword, FormFieldSegmented, FormFieldSelect, FormFieldSwitch, FormFieldTextarea, RadioGroup, addRequiredFieldsParamToSchema, dateValidation, defaultCheckboxProps, defaultChipsProps, defaultChoiceProps, defaultCodeProps, defaultDatepickerProps, defaultDropzoneProps, defaultFieldProps, defaultFieldSizeM, defaultFieldSizeXL, defaultGroupProps, defaultInputProps, defaultPasswordProps, defaultRadioProps, defaultSegmentedProps, defaultSelectProps, defaultSwitchProps, defaultTextareaProps, emailValidation, focusOnError, focusOnErrorDecorator, formTypes, generateField, getErrorsForFinalForm, parseNumericField, phoneValidation, sendFormDataToServer, setErrorsMutator, useYupValidationSchema };