@itcase/forms 1.1.40 → 1.1.42

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,16 +1,22 @@
1
1
  import { isPossiblePhoneNumber } from 'libphonenumber-js';
2
- import React, { useMemo, useEffect, useState, useCallback } from 'react';
2
+ import React, { useMemo, useEffect, useCallback, useState } 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 { useDevicePropsGenerator } from '@itcase/ui/hooks/useDevicePropsGenerator';
7
+ import { Checkbox } from '@itcase/ui/components/Checkbox';
8
8
  import camelCase from 'lodash/camelCase';
9
9
  import snakeCase from 'lodash/snakeCase';
10
10
  import { Divider } from '@itcase/ui/components/Divider';
11
11
  import { Text } from '@itcase/ui/components/Text';
12
12
  import { useDeviceTargetClass } from '@itcase/ui/hooks/useDeviceTargetClass';
13
13
  import { useStyles } from '@itcase/ui/hooks/useStyles';
14
+ import { ChipsGroup, Chips } from '@itcase/ui/components/Chips';
15
+ import { Choice } from '@itcase/ui/components/Choice';
16
+ import { Code } from '@itcase/ui/components/Code';
17
+ import { Icon } from '@itcase/ui/components/Icon';
18
+ import { DatePickerInput } from '@itcase/ui/components/DatePicker';
19
+ import { useDevicePropsGenerator } from '@itcase/ui/hooks/useDevicePropsGenerator';
14
20
  import axios from 'axios';
15
21
  import { fromEvent } from 'file-selector';
16
22
  import castArray from 'lodash/castArray';
@@ -19,20 +25,14 @@ import { createFileFromDataURL } from '@itcase/common';
19
25
  import { Button } from '@itcase/ui/components/Button';
20
26
  import { Loader } from '@itcase/ui/components/Loader';
21
27
  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';
28
28
  import { Input } from '@itcase/ui/components/Input';
29
- import { icons24 } from '@itcase/icons/default';
29
+ import { useIMask } from 'react-imask';
30
+ import { InputPassword } from '@itcase/ui/components/InputPassword';
31
+ import { Radio } from '@itcase/ui/components/Radio';
30
32
  import { Segmented } from '@itcase/ui/components/Segmented';
31
33
  import { Select } from '@itcase/ui/components/Select';
32
34
  import { Switch } from '@itcase/ui/components/Switch';
33
35
  import { Textarea } from '@itcase/ui/components/Textarea';
34
- import { useIMask } from 'react-imask';
35
- import { Radio } from '@itcase/ui/components/Radio';
36
36
  import { Group } from '@itcase/ui/components/Group';
37
37
  import { Notification } from '@itcase/ui/components/Notification';
38
38
  import createDecorator from 'final-form-focus';
@@ -117,6 +117,16 @@ function useYupValidationSchema(schema, language) {
117
117
  return validate;
118
118
  }
119
119
 
120
+ const defaultCheckboxProps = {
121
+ appearance: 'defaultPrimary sizeL solid',
122
+ width: 'fill',
123
+ // useValidationAppearanceInputProps
124
+ // Error
125
+ errorAppearance: 'errorPrimary sizeL solid',
126
+ // Required
127
+ requiredAppearance: 'requirePrimary sizeL solid'
128
+ };
129
+
120
130
  // Whether to display an error message based on "fieldProps" and meta-objects
121
131
  function useFieldValidationState(props) {
122
132
  const {
@@ -430,428 +440,477 @@ function FieldWrapper(props) {
430
440
  return /*#__PURE__*/React.createElement(FieldWrapperBase, props);
431
441
  }
432
442
 
433
- const defaultDropzoneProps = {
434
- fill: 'surfaceSecondary',
435
- fillHover: 'surfaceTertiary',
436
- // borderColor: 'surfaceBorderTertiary',
437
- // borderColorHover: 'surfaceBorderQuaternary',
438
- hintTitle: 'Перетащите изображение или выберите файл с компьютера',
439
- hintTitleTextColor: 'surfaceTextPrimary',
440
- hintTitleTextSize: 'm',
441
- removeThumbText: 'удалить',
442
- removeThumbTextColor: 'errorTextPrimary',
443
- removeThumbTextHoverColor: 'errorTextPrimaryHover',
444
- removeThumbTextSize: 's',
445
- shape: 'rounded',
446
- showFilename: true,
447
- thumbBorderColor: 'surfaceBorderTertiary',
448
- thumbBorderColorHover: 'surfaceBorderQuaternary',
449
- thumbBorderWidth: 1,
450
- thumbNameTextColor: 'surfaceTextPrimary',
451
- thumbNameTextSize: 's',
452
- isPreviews: true
443
+ const FormFieldCheckbox = /*#__PURE__*/React.memo(function FormFieldCheckbox(props) {
444
+ const {
445
+ name,
446
+ initialValue,
447
+ isDisabled,
448
+ classNameGroupItem,
449
+ fieldProps = {},
450
+ inputProps = {},
451
+ showMessage,
452
+ isRequired,
453
+ onChange
454
+ } = props;
455
+ return /*#__PURE__*/React.createElement(Field, {
456
+ type: "checkbox",
457
+ name: name,
458
+ initialValue: initialValue
459
+ }, function Render({
460
+ input,
461
+ meta
462
+ }) {
463
+ /** Note:
464
+ * Create "Render" function by "eslint-react-hooks/rules-of-hooks":
465
+ * React Hooks cannot be called inside a callback.
466
+ * React Hooks must be called in a React function component or a
467
+ * custom React Hook function.
468
+ */
469
+
470
+ const onChangeField = useCallback(event => {
471
+ input.onChange(event);
472
+ if (onChange) {
473
+ onChange(event.target.checked, input.name);
474
+ }
475
+ }, [onChange, input.onChange]);
476
+ const {
477
+ errorKey,
478
+ errorMessage,
479
+ isErrorState,
480
+ successKey,
481
+ isValidState
482
+ } = useFieldValidationState({
483
+ fieldProps: fieldProps,
484
+ input: input,
485
+ meta: meta
486
+ });
487
+ const updatedInputProps = useValidationAppearanceInputProps({
488
+ inputProps: inputProps,
489
+ validationStateKey: isErrorState ? errorKey : isValidState ? successKey : null
490
+ });
491
+ return /*#__PURE__*/React.createElement(FieldWrapper, Object.assign({
492
+ className: clsx('form-field-checkbox', 'form__item_checkbox', classNameGroupItem),
493
+ errorKey: errorKey,
494
+ errorMessage: errorMessage,
495
+ isErrorState: isErrorState,
496
+ metaError: meta.error,
497
+ isDisabled: isDisabled,
498
+ fieldClassName: "form-checkbox",
499
+ inputName: input.name,
500
+ inputValue: input.checked,
501
+ metaActive: meta.active,
502
+ showMessage: showMessage,
503
+ tag: "label",
504
+ isRequired: isRequired,
505
+ isValidState: isValidState
506
+ }, fieldProps), /*#__PURE__*/React.createElement(Checkbox, Object.assign({
507
+ type: "checkbox",
508
+ name: input.name,
509
+ isDisabled: isDisabled,
510
+ autoComplete: "nope",
511
+ checked: input.checked,
512
+ isActive: input.checked,
513
+ onBlur: input.onBlur,
514
+ onChange: onChangeField,
515
+ onFocus: input.onFocus
516
+ }, updatedInputProps)));
517
+ });
518
+ });
519
+
520
+ const defaultChipsProps = {
521
+ appearance: 'surfacePrimary sizeM rounded',
522
+ width: 'fill',
523
+ // useValidationAppearanceInputProps
524
+ // Error
525
+ errorAppearance: 'errorPrimary sizeM solid rounded',
526
+ // Required
527
+ requiredAppearance: 'requirePrimary sizeM solid rounded'
528
+ // Success
529
+ // successAppearance: 'successPrimary sizeM solid rounded',
453
530
  };
454
531
 
455
- const FileInputDropzone = /*#__PURE__*/React.memo(function FileInputDropzone(props) {
532
+ function FormFieldChips(props) {
456
533
  const {
457
- className,
458
- maxFiles,
459
- maxSize,
460
- size,
461
- fileErrorText,
462
- dropzoneProps = {},
463
- hintDescription,
464
- hintTitle,
465
- inputName,
466
- inputValue,
467
- showFilename,
468
- thumbColumn,
469
- isPreviews,
470
- onAddFiles,
471
- onClickPreview,
472
- onDeleteFile
534
+ name,
535
+ initialValue,
536
+ isDisabled,
537
+ classNameGroupItem,
538
+ emptyMessage,
539
+ emptyMessageTextColor,
540
+ emptyMessageTextSize,
541
+ fieldProps,
542
+ inputProps,
543
+ options,
544
+ showMessage,
545
+ isRequired,
546
+ onChange
473
547
  } = props;
474
-
475
- // TODO: delete react-final-form things out of here?
476
548
  const {
477
549
  change
478
550
  } = useForm();
479
- const [fileError, setFileError] = useState('');
480
- const [fileIsLoading, setFileIsLoading] = useState(false);
481
- const filesList = useMemo(() => inputValue ? castArray(inputValue) : [], [inputValue]);
482
- const changeFormState = useCallback(newFiles => {
483
- // If max files in dropzone is 1 - return file as it self, else as array of files
484
- // ps: for old projects compatibility
485
- const toSave = dropzoneProps.maxFiles == 1 ? newFiles[0] : newFiles;
486
- change(inputName, toSave);
487
- return toSave;
488
- },
489
- // If "inputName" will be changes, then it should be a different field
490
- // eslint-disable-next-line react-hooks/exhaustive-deps
491
- [dropzoneProps, change]);
492
551
 
493
- //
494
- const convertFiledValueAndSaveAsFiles = useCallback(async currentFilesList => {
495
- setFileIsLoading(true);
496
- const newFiles = [];
497
- for (const fileItem of currentFilesList) {
498
- if (typeof fileItem === 'string') {
499
- const newFile = await convertToFile(fileItem, isPreviews);
500
- if (newFile) {
501
- newFiles.push(newFile);
502
- }
503
- } else {
504
- newFiles.push(fileItem);
552
+ // Callback for value changes
553
+ const onChangeSomeInput = useCallback((inputValue, newOptionValue) => {
554
+ const updatedValues = inputValue.includes(newOptionValue) ? inputValue.filter(selectedValue => selectedValue !== newOptionValue) : [...inputValue, newOptionValue];
555
+ change(name, updatedValues);
556
+ onChange && onChange(updatedValues);
557
+ }, [change, name, onChange]);
558
+ useEffect(() => {
559
+ initialValue && change(name, initialValue);
560
+ // update the form value only when the initialValue changes, so use disable eslint to ignore the warning
561
+ // eslint-disable-next-line react-hooks/exhaustive-deps
562
+ }, [initialValue]);
563
+ return /*#__PURE__*/React.createElement(Field, {
564
+ name: name,
565
+ initialValue: initialValue
566
+ }, function Render({
567
+ input,
568
+ meta
569
+ }) {
570
+ const {
571
+ errorKey,
572
+ errorMessage,
573
+ isErrorState,
574
+ successKey,
575
+ isValidState
576
+ } = useFieldValidationState({
577
+ fieldProps: fieldProps,
578
+ input: input,
579
+ meta: meta
580
+ });
581
+ const updatedInputProps = useValidationAppearanceInputProps({
582
+ inputProps: inputProps,
583
+ validationStateKey: isErrorState ? errorKey : isValidState ? successKey : null
584
+ });
585
+ const activeOptionsList = useMemo(() => {
586
+ const emptyOptionsList = [{
587
+ label: null,
588
+ value: null
589
+ }];
590
+ if (input?.value) {
591
+ const currentOptions = options.filter(option => input.value?.includes(option.value));
592
+ return currentOptions || emptyOptionsList;
505
593
  }
506
- }
507
- changeFormState(newFiles);
508
- setFileIsLoading(false);
509
- }, [isPreviews, changeFormState]);
510
-
511
- // Delete file from dropzone
512
- const removeFile = useCallback((event, index) => {
513
- event.stopPropagation();
514
- event.preventDefault();
515
- const newFiles = [...filesList];
516
- newFiles.splice(index, 1);
517
- if (onDeleteFile) {
518
- onDeleteFile(filesList[index], inputName);
519
- }
520
- changeFormState(newFiles);
521
- },
522
- // If "inputName" will be changes, then it should be a different field
523
- // eslint-disable-next-line react-hooks/exhaustive-deps
524
- [filesList, changeFormState, onDeleteFile]);
525
-
526
- // Create dropzone options
527
- const {
528
- getInputProps,
529
- getRootProps
530
- } = useDropzone({
531
- maxFiles: maxFiles || 5,
532
- maxSize: maxSize || 10485760,
533
- // 10mb
534
- // accept: { 'image/*': [] },
535
- ...dropzoneProps,
536
- getFilesFromEvent: async event => {
537
- const result = await fromEvent(event);
538
- const newFiles = result.filter(item => item instanceof File);
539
- // Add exists and new files to accepted(or rejected)
540
- return [...filesList, ...newFiles];
541
- },
542
- onDropAccepted: acceptedFiles => {
543
- // If dropped files has accepted and we need a previews
544
- if (isPreviews) {
545
- // Add preview to every file
546
- acceptedFiles.forEach(file => {
547
- if (!file.error) {
548
- file.preview = URL.createObjectURL(file);
549
- }
550
- });
551
- }
552
- // Save to form data (including empty when files are not valid)
553
- const filesToSave = changeFormState(acceptedFiles);
554
- setFileError('');
555
-
556
- // Save DataURL for all files
557
- const readerPromisesList = acceptedFiles.map(file => {
558
- return new Promise(resolve => setFileDataURL(file, resolve));
559
- });
560
- // Save files to form values
561
- Promise.all(readerPromisesList).then(() => {
562
- if (onAddFiles) {
563
- onAddFiles(filesToSave, inputName);
564
- }
565
- });
566
- },
567
- onDropRejected: rejectedFiles => {
568
- // If dropped files has rejected
569
- if (rejectedFiles.length) {
570
- let fileErrorMessage = 'Ошибка при добавлении файла';
571
- const firstFileErrorItem = rejectedFiles[0].errors[0];
572
- if (firstFileErrorItem) {
573
- if (firstFileErrorItem.code === ErrorCode.TooManyFiles) {
574
- fileErrorMessage = `Максимальное количество файлов: ${maxFiles}`;
575
- } else {
576
- fileErrorMessage = firstFileErrorItem.message;
577
- }
578
- }
579
- // Show error
580
- setFileError(fileErrorMessage);
581
- } else {
582
- // Else clean error
583
- setFileError('');
584
- }
585
- }
594
+ return emptyOptionsList;
595
+ }, [input.value]);
596
+ return /*#__PURE__*/React.createElement(FieldWrapper, Object.assign({
597
+ className: clsx('form-field_chips', 'form__item_chips', classNameGroupItem),
598
+ errorKey: errorKey,
599
+ errorMessage: errorMessage,
600
+ isErrorState: isErrorState,
601
+ metaError: meta.error,
602
+ isDisabled: isDisabled,
603
+ fieldClassName: "form-chips",
604
+ inputName: input.name,
605
+ inputValue: input.value,
606
+ metaActive: meta.active,
607
+ showMessage: showMessage,
608
+ isRequired: isRequired,
609
+ isValidState: isValidState
610
+ }, fieldProps), options.length ? /*#__PURE__*/React.createElement(ChipsGroup, {
611
+ direction: "horizontal",
612
+ gap: "1m",
613
+ wrap: "wrap"
614
+ }, options.map(option => /*#__PURE__*/React.createElement(Chips, Object.assign({
615
+ className: clsx(meta.active && 'form-chips_state_focus', meta.error && meta.touched && `form-chips_state_${errorKey}`),
616
+ key: option.value,
617
+ label: option.label,
618
+ isDisabled: option.isDisabled,
619
+ value: option.value,
620
+ isActive: activeOptionsList.some(activeOption => activeOption.value === option.value),
621
+ onClick: () => onChangeSomeInput(input.value, option.value)
622
+ }, updatedInputProps)))) : /*#__PURE__*/React.createElement(Text, {
623
+ size: emptyMessageTextSize,
624
+ textColor: emptyMessageTextColor
625
+ }, emptyMessage));
586
626
  });
587
- useEffect(() => {
588
- const currentFilesList = castArray(inputValue);
589
- const isNeedToConvert = currentFilesList.some(fileItem => typeof fileItem === 'string');
590
- if (isNeedToConvert) {
591
- // First time convert value to Files and save to local and form state
592
- convertFiledValueAndSaveAsFiles(currentFilesList);
593
- }
627
+ }
594
628
 
595
- // Make sure to revoke the data uris to avoid memory leaks, will run on unmount
596
- return () => {
597
- filesList.forEach(file => {
598
- if (file?.preview) {
599
- URL.revokeObjectURL(file.preview);
600
- }
601
- });
602
- };
603
- // eslint-disable-next-line react-hooks/exhaustive-deps
604
- }, [inputValue]);
605
- const propsGenerator = useDevicePropsGenerator(props);
629
+ const defaultChoiceProps = {
630
+ appearance: 'defaultPrimary sizeM solid rounded',
631
+ width: 'fill',
632
+ // useValidationAppearanceInputProps
633
+ // Error
634
+ errorAppearance: 'errorPrimary sizeM solid rounded',
635
+ // Required
636
+ requiredAppearance: 'requirePrimary sizeM solid rounded'
637
+ };
638
+
639
+ const FormFieldChoice = /*#__PURE__*/React.memo(function FormFieldChoice(props) {
606
640
  const {
607
- fillClass,
608
- fillHoverClass,
609
- borderColorClass,
610
- borderColorHoverClass,
611
- borderTypeClass,
612
- borderWidthClass,
613
- errorMessageTextColor,
614
- errorMessageTextSize,
615
- errorMessageTextWeight,
616
- hintDescriptionTextColor,
617
- hintDescriptionTextSize,
618
- hintDescriptionTextWeight,
619
- hintDescriptionTextWrap,
620
- hintTitleTextColor,
621
- hintTitleTextSize,
622
- hintTitleTextWeight,
623
- hintTitleTextWrap,
624
- removeThumbAppearance,
625
- removeThumbShape,
626
- removeThumbText,
627
- removeThumbTextWeight,
628
- shapeClass,
629
- thumbBorderColorClass,
630
- thumbBorderColorHoverClass,
631
- thumbBorderTypeClass,
632
- thumbBorderWidthClass,
633
- thumbDirectionClass,
634
- thumbNameTextColor,
635
- thumbNameTextSize,
636
- thumbNameTextWeight,
637
- thumbNameTextWrap
638
- } = propsGenerator;
639
- return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("div", getRootProps({
640
- // className: `form-dropzone__dropzone dropzone ${className} form-dropzone__dropzone_size_${size} ${shapeClass}`,
641
- className: `form-dropzone__dropzone dropzone`
642
- }), /*#__PURE__*/React.createElement("input", Object.assign({}, getInputProps(), {
643
- name: inputName
644
- })), /*#__PURE__*/React.createElement("div", {
645
- className: clsx('form-dropzone__dropzone-wrapper', thumbColumn && `form-dropzone__dropzone-wrapper_column_${thumbColumn}`, fillClass && `fill_${fillClass}`, fillHoverClass && `fill_hover_${fillHoverClass}`, borderWidthClass && `border-width_${borderWidthClass}`, borderColorClass && `border-color_${borderColorClass}`, borderColorHoverClass && `border-color_hover_${borderColorHoverClass}`, borderTypeClass && `border_type_${borderTypeClass}`, shapeClass && `shape_${shapeClass}`)
646
- }, filesList.map((file, index) => /*#__PURE__*/React.createElement("aside", {
647
- className: clsx('form-dropzone__thumb', fillClass, thumbDirectionClass, thumbBorderWidthClass, thumbBorderColorClass, thumbBorderColorHoverClass, thumbBorderTypeClass),
648
- key: file.id || `${file.name}_${index}`
649
- }, isPreviews && !file.error && /*#__PURE__*/React.createElement("div", {
650
- className: "form-dropzone__thumb-image"
651
- }, /*#__PURE__*/React.createElement("img", {
652
- className: "form-dropzone__thumb-image-inner",
653
- src: file.preview || file.image,
654
- onClick: event => {
655
- onClickPreview && onClickPreview(file, event);
656
- },
657
- onLoad: () => {
658
- // Revoke data uri after image is loaded
659
- URL.revokeObjectURL(file.preview);
641
+ name,
642
+ initialValue,
643
+ label,
644
+ messageType,
645
+ isDisabled,
646
+ classNameGroupItem,
647
+ fieldProps,
648
+ inputProps,
649
+ options,
650
+ placeholder,
651
+ showMessage,
652
+ isCheckbox,
653
+ isRequired,
654
+ onChange
655
+ } = props;
656
+ const {
657
+ change
658
+ } = useForm();
659
+ const setActiveSegment = useCallback((option, isChecked) => {
660
+ change(name, isChecked && option.value);
661
+ if (onChange) {
662
+ onChange(option.value, name, isChecked);
660
663
  }
661
- })), file.error && /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement(Text, {
662
- size: thumbNameTextSize,
663
- textColor: thumbNameTextColor,
664
- textWeight: thumbNameTextWeight,
665
- textWrap: thumbNameTextWrap
666
- }, fileErrorText || file.error)), showFilename && /*#__PURE__*/React.createElement("div", {
667
- className: "form-dropzone__thumb-name"
668
- }, /*#__PURE__*/React.createElement(Text, {
669
- className: "form-dropzone__thumb-name-inner",
670
- size: thumbNameTextSize,
671
- textColor: thumbNameTextColor,
672
- textWeight: thumbNameTextWeight,
673
- textWrap: thumbNameTextWrap
674
- }, file.name)), fileIsLoading && /*#__PURE__*/React.createElement("div", {
675
- className: "form-dropzone__thumb-loader"
676
- }, /*#__PURE__*/React.createElement(Loader, {
677
- width: "fill",
678
- height: "fill"
679
- })), /*#__PURE__*/React.createElement("div", {
680
- className: clsx('form-dropzone__thumb-remove')
681
- }, /*#__PURE__*/React.createElement(Button, {
682
- className: "form-dropzone__thumb-remove-text",
683
- appearance: removeThumbAppearance,
684
- label: removeThumbText || 'Удалить',
685
- labelTextWeight: removeThumbTextWeight,
686
- shape: removeThumbShape,
687
- onClick: event => removeFile(event, index)
688
- })))), !filesList.length ? /*#__PURE__*/React.createElement("div", {
689
- className: "form-dropzone__hint"
690
- }, /*#__PURE__*/React.createElement(Text, {
691
- className: "form-dropzone__hint-title",
692
- size: hintTitleTextSize,
693
- textColor: hintTitleTextColor,
694
- textWeight: hintTitleTextWeight,
695
- textWrap: hintTitleTextWrap
696
- }, hintTitle || 'Select a file or drag in form'), hintDescription && /*#__PURE__*/React.createElement(Text, {
697
- className: "form-dropzone__hint-text",
698
- size: hintDescriptionTextSize,
699
- textColor: hintDescriptionTextColor,
700
- textWeight: hintDescriptionTextWeight,
701
- textWrap: hintDescriptionTextWrap
702
- }, hintDescription)) : /*#__PURE__*/React.createElement("div", {
703
- className: "form-dropzone__hint form-dropzone__hint_type_add-more"
704
- }, /*#__PURE__*/React.createElement(Text, {
705
- className: "form-dropzone__hint-title",
706
- size: hintTitleTextSize,
707
- textColor: hintTitleTextColor,
708
- textWeight: hintTitleTextWeight,
709
- textWrap: hintTitleTextWrap
710
- }, hintTitle || 'Select a file or drag in form'), hintDescription && /*#__PURE__*/React.createElement(Text, {
711
- className: "form-dropzone__hint-text",
712
- size: hintDescriptionTextSize,
713
- textColor: hintDescriptionTextColor,
714
- textWeight: hintDescriptionTextWeight,
715
- textWrap: hintDescriptionTextWrap
716
- }, hintDescription)))), fileError && /*#__PURE__*/React.createElement("div", {
717
- className: "form-field__message"
718
- }, /*#__PURE__*/React.createElement(Text, {
719
- className: "form-field__message-item form-field__message-item_type_message",
720
- size: errorMessageTextSize,
721
- textColor: errorMessageTextColor,
722
- textWeight: errorMessageTextWeight
723
- }, fileError)));
664
+ }, [change, onChange]);
665
+ return /*#__PURE__*/React.createElement(Field, {
666
+ initialValue: initialValue,
667
+ name: name
668
+ }, function Render({
669
+ input,
670
+ meta
671
+ }) {
672
+ /** Note:
673
+ * Create "Render" function by "eslint-react-hooks/rules-of-hooks":
674
+ * React Hooks cannot be called inside a callback.
675
+ * React Hooks must be called in a React function component or a
676
+ * custom React Hook function.
677
+ */
678
+ const activeOption = useMemo(() => {
679
+ const emptyOption = {
680
+ value: null,
681
+ label: null
682
+ };
683
+ if (input.value) {
684
+ const currentOption = options.find(option => option.value === input.value);
685
+ return currentOption || emptyOption;
686
+ }
687
+ return emptyOption;
688
+ }, [input.value]);
689
+ const {
690
+ errorKey,
691
+ errorMessage,
692
+ isErrorState,
693
+ successKey,
694
+ isValidState
695
+ } = useFieldValidationState({
696
+ fieldProps: fieldProps,
697
+ input: input,
698
+ meta: meta
699
+ });
700
+ const updatedInputProps = useValidationAppearanceInputProps({
701
+ inputProps: inputProps,
702
+ validationStateKey: isErrorState ? errorKey : isValidState ? successKey : null
703
+ });
704
+ return /*#__PURE__*/React.createElement(FieldWrapper, Object.assign({
705
+ className: clsx('form-field_choice', 'form__item_choice', classNameGroupItem),
706
+ label: label,
707
+ messageType: messageType,
708
+ errorKey: errorKey,
709
+ errorMessage: errorMessage,
710
+ isErrorState: isErrorState,
711
+ metaError: meta.error,
712
+ isDisabled: isDisabled,
713
+ fieldClassName: "form-choice",
714
+ inputName: input.name,
715
+ inputValue: input.value || [],
716
+ metaActive: meta.active,
717
+ showMessage: showMessage,
718
+ isRequired: isRequired,
719
+ isValidState: isValidState
720
+ }, fieldProps), /*#__PURE__*/React.createElement(Choice, Object.assign({
721
+ className: clsx(meta.active && 'form-choice_state_focus', meta.error && meta.touched && `form-choice_state_${errorKey}`),
722
+ name: input.name,
723
+ isDisabled: isDisabled,
724
+ active: activeOption,
725
+ inputValue: input.value || [],
726
+ options: options,
727
+ placeholder: placeholder,
728
+ setActiveSegment: setActiveSegment,
729
+ isCheckbox: isCheckbox,
730
+ isRequired: isRequired
731
+ }, updatedInputProps)));
732
+ });
724
733
  });
725
- async function getFileByURL(url) {
726
- try {
727
- const response = await axios({
728
- url: url,
729
- responseType: 'blob'
734
+
735
+ const defaultCodeProps = {
736
+ appearance: 'defaultPrimary sizeL solid rounded',
737
+ // useValidationAppearanceInputProps
738
+ // Error
739
+ errorAppearance: 'errorPrimary sizeM solid rounded',
740
+ // Required
741
+ requiredAppearance: 'requirePrimary sizeM solid rounded'
742
+ };
743
+
744
+ const FormFieldCode = /*#__PURE__*/React.memo(function FormFieldCode(props) {
745
+ const {
746
+ name,
747
+ initialValue,
748
+ label,
749
+ messageType,
750
+ isDisabled,
751
+ classNameGroupItem,
752
+ fieldProps = {},
753
+ inputProps = {},
754
+ showMessage,
755
+ isRequired
756
+ } = props;
757
+ return /*#__PURE__*/React.createElement(Field, {
758
+ name: name,
759
+ initialValue: initialValue
760
+ }, function Render({
761
+ input,
762
+ meta
763
+ }) {
764
+ /** Note:
765
+ * Create "Render" function by "eslint-react-hooks/rules-of-hooks":
766
+ * React Hooks cannot be called inside a callback.
767
+ * React Hooks must be called in a React function component or a
768
+ * custom React Hook function.
769
+ */
770
+
771
+ const {
772
+ errorKey,
773
+ errorMessage,
774
+ isErrorState,
775
+ successKey,
776
+ isValidState
777
+ } = useFieldValidationState({
778
+ fieldProps: fieldProps,
779
+ input: input,
780
+ meta: meta
730
781
  });
731
- const blobObject = response.data;
732
- const dirtyFilename = response.headers['content-disposition']?.split('filename=')[1];
733
- // Remove double quotes
734
- let filename = dirtyFilename?.substring(1).slice(0, -1);
735
- if (!filename) {
736
- filename = url.split('/').at(-1);
737
- // const typeParts = blobObject.type.split('/')
738
- // const fileType = typeParts[typeParts.length - 1]
739
- // filename = `${new Date().getTime()}.${fileType}`
740
- }
741
- return new File([blobObject], filename, {
742
- type: blobObject.type
782
+ const updatedInputProps = useValidationAppearanceInputProps({
783
+ inputProps: inputProps,
784
+ validationStateKey: isErrorState ? errorKey : isValidState ? successKey : null
743
785
  });
744
- } catch (error) {
745
- console.log('error: ', error);
746
- return null;
747
- }
748
- }
749
- async function convertToFile(inputValue, isPreviews) {
750
- let newFile = null;
751
-
752
- // Download image by url and save as File instance
753
- const isURL = typeof inputValue === 'string' && inputValue.includes('/');
754
- if (inputValue.image || isURL) {
755
- newFile = await getFileByURL(inputValue.image || inputValue);
756
- if (newFile) {
757
- setFileDataURL(newFile);
758
- }
759
- }
786
+ return /*#__PURE__*/React.createElement(FieldWrapper, Object.assign({
787
+ className: clsx('form-field-code', 'form__item_code', classNameGroupItem),
788
+ label: label,
789
+ messageType: messageType,
790
+ errorKey: errorKey,
791
+ errorMessage: errorMessage,
792
+ isErrorState: isErrorState,
793
+ fieldClassName: 'form-code',
794
+ inputName: input.name,
795
+ inputValue: input.value,
796
+ metaActive: meta.active,
797
+ showMessage: showMessage,
798
+ isRequired: isRequired,
799
+ isValidState: isValidState
800
+ }, fieldProps), /*#__PURE__*/React.createElement(Code, Object.assign({
801
+ name: input.name,
802
+ initialValue: input.value,
803
+ isDisabled: isDisabled,
804
+ autoComplete: "nope",
805
+ onBlur: input.onBlur,
806
+ onChange: input.onChange,
807
+ onFocus: input.onFocus
808
+ }, updatedInputProps)));
809
+ });
810
+ });
760
811
 
761
- // Convert dataURL to File instance
762
- if (inputValue.dataURL) {
763
- newFile = createFileFromDataURL(inputValue.name || inputValue.path, inputValue.dataURL);
764
- newFile.dataURL = inputValue.dataURL;
765
- }
812
+ const FormFieldCustom = /*#__PURE__*/React.memo(function FormFieldCustom(props) {
813
+ const {
814
+ Component,
815
+ isDisabled,
816
+ isRequired,
817
+ name,
818
+ initialValue,
819
+ fieldProps = {},
820
+ classNameGroupItem,
821
+ showMessage,
822
+ clearIcon,
823
+ clearIconFill,
824
+ clearIconFillHover,
825
+ clearIconShape,
826
+ clearIconSize,
827
+ onClickClearIcon
828
+ } = props;
829
+ return /*#__PURE__*/React.createElement(Field, {
830
+ initialValue: initialValue,
831
+ name: name
832
+ }, function Render({
833
+ input,
834
+ meta
835
+ }) {
836
+ /** Note:
837
+ * Create "Render" function by "eslint-react-hooks/rules-of-hooks":
838
+ * React Hooks cannot be called inside a callback.
839
+ * React Hooks must be called in a React function component or a
840
+ * custom React Hook function.
841
+ */
766
842
 
767
- // Save new File to state
768
- if (newFile) {
769
- newFile.id = inputValue.id;
770
- if (isPreviews) {
771
- newFile.preview = URL.createObjectURL(newFile);
772
- }
773
- }
774
- return newFile;
775
- }
776
- function setFileDataURL(file, resolve) {
777
- resolve = resolve || (() => {});
778
- // Init reader and save his file
779
- const reader = new FileReader();
780
- reader._readedFile = file;
843
+ const {
844
+ isErrorState,
845
+ isValidState,
846
+ errorKey,
847
+ errorMessage
848
+ } = useFieldValidationState({
849
+ fieldProps: fieldProps,
850
+ input: input,
851
+ meta: meta
852
+ });
853
+ const updatedInputProps = useValidationAppearanceInputProps({
854
+ validationStateKey: isErrorState ? errorKey : 'success',
855
+ // For "Custom" field we pass all props. Can contain some special props, we don't known.
856
+ inputProps: props
857
+ });
858
+ return /*#__PURE__*/React.createElement(FieldWrapper, Object.assign({
859
+ className: clsx('form-field_custom', 'form__item_custom', classNameGroupItem),
860
+ errorKey: errorKey,
861
+ errorMessage: errorMessage,
862
+ fieldClassName: 'form-custom',
863
+ inputName: input.name,
864
+ inputValue: input.value,
865
+ isDisabled: isDisabled,
866
+ isErrorState: isErrorState,
867
+ isRequired: isRequired,
868
+ isValidState: isValidState,
869
+ metaActive: meta.active,
870
+ metaError: meta.error,
871
+ showMessage: showMessage
872
+ }, fieldProps), /*#__PURE__*/React.createElement(Component, Object.assign({}, updatedInputProps, {
873
+ input: input,
874
+ isDisabled: isDisabled,
875
+ meta: meta
876
+ })), clearIcon && /*#__PURE__*/React.createElement(Icon, {
877
+ className: "form-field__icon",
878
+ iconFill: clearIconFill,
879
+ iconFillHover: clearIconFillHover,
880
+ imageSrc: clearIcon,
881
+ shape: clearIconShape,
882
+ size: clearIconSize,
883
+ SvgImage: clearIcon,
884
+ onClick: onClickClearIcon
885
+ }));
886
+ });
887
+ });
781
888
 
782
- // Set handlers
783
- reader.onabort = () => resolve();
784
- reader.onerror = () => resolve();
785
- reader.onload = event => {
786
- event.target._readedFile.dataURL = reader.result;
787
- resolve();
788
- };
789
- // Run reader
790
- if (file instanceof File) {
791
- reader.readAsDataURL(file);
792
- } else {
793
- resolve();
794
- }
795
- }
889
+ const defaultDatepickerProps = {
890
+ appearance: 'surfacePrimary sizeS',
891
+ dateFormat: 'dd/MM/yyyy - HH:mm',
892
+ readOnly: false,
893
+ selectsRange: false,
894
+ showTimeSelect: true,
895
+ timeCaption: 'Время',
896
+ timeFormat: 'p',
897
+ timeIntervals: 60,
898
+ isClearable: true,
899
+ isStartDefaultNull: true
900
+ };
796
901
 
797
- const FileInput = /*#__PURE__*/React.memo(function FileInput(props) {
902
+ function FormFieldDatePicker(props) {
798
903
  const {
799
- className,
800
904
  name,
801
- width,
802
- maxFiles,
803
- maxSize,
804
- label,
805
- fileErrorText,
905
+ isDisabled,
806
906
  classNameGroupItem,
807
- dropzoneProps,
808
- fieldProps,
809
- hintDescription,
810
- hintTitle,
811
- showFilename,
907
+ datePickerProps,
908
+ fieldProps = {},
909
+ inputProps = {},
812
910
  showMessage,
813
- isPreviews,
814
911
  isRequired,
815
- onAddFiles,
816
- onClickPreview,
817
- onDeleteFile
912
+ onChange
818
913
  } = props;
819
- const propsGenerator = useDevicePropsGenerator(props);
820
- const {
821
- size,
822
- fill,
823
- fillHover,
824
- labelTextColor,
825
- borderColorHover,
826
- borderType,
827
- borderWidth,
828
- errorMessageTextColor,
829
- errorMessageTextSize,
830
- errorMessageTextWeight,
831
- hintDescriptionTextColor,
832
- hintDescriptionTextSize,
833
- hintDescriptionTextWeight,
834
- hintDescriptionTextWrap,
835
- hintTitleTextColor,
836
- hintTitleTextSize,
837
- hintTitleTextWeight,
838
- hintTitleTextWrap,
839
- removeThumbAppearance,
840
- removeThumbShape,
841
- removeThumbText,
842
- removeThumbTextWeight,
843
- shape,
844
- thumbBorderColor,
845
- thumbBorderColorHover,
846
- thumbBorderType,
847
- thumbBorderWidth,
848
- thumbColumn = 1,
849
- thumbDirection = 'vertical',
850
- thumbNameTextColor,
851
- thumbNameTextSize,
852
- thumbNameTextWeight,
853
- thumbNameTextWrap
854
- } = propsGenerator;
855
914
  return /*#__PURE__*/React.createElement(Field, {
856
915
  name: name
857
916
  }, function Render({
@@ -865,10 +924,27 @@ const FileInput = /*#__PURE__*/React.memo(function FileInput(props) {
865
924
  * custom React Hook function.
866
925
  */
867
926
 
927
+ const onChangeField = useCallback((startDate, endDate) => {
928
+ if (!datePickerProps.selectsRange) {
929
+ // When we need to save single date, value is date
930
+ // TODO: make object with one date? need to check all forms with FormFieldDatePicker
931
+ input.onChange(startDate);
932
+ } else {
933
+ // When we need to save range, value is object with two date
934
+ input.onChange({
935
+ endDate,
936
+ startDate
937
+ });
938
+ }
939
+ if (onChange) {
940
+ onChange(startDate, endDate);
941
+ }
942
+ }, [input.onChange, onChange]);
868
943
  const {
869
944
  errorKey,
870
945
  errorMessage,
871
946
  isErrorState,
947
+ successKey,
872
948
  isValidState
873
949
  } = useFieldValidationState({
874
950
  fieldProps: fieldProps,
@@ -876,423 +952,460 @@ const FileInput = /*#__PURE__*/React.memo(function FileInput(props) {
876
952
  meta: meta
877
953
  });
878
954
  const updatedInputProps = useValidationAppearanceInputProps({
879
- inputProps: props,
880
- validationStateKey: isErrorState ? errorKey : 'success'
955
+ inputProps: inputProps,
956
+ validationStateKey: isErrorState ? errorKey : isValidState ? successKey : null
881
957
  });
882
-
883
- /** TODO:
884
- * REFACTOR PROPERTIES
885
- */
886
958
  return /*#__PURE__*/React.createElement(FieldWrapper, Object.assign({
887
- className: clsx('form-field_type_dropzone', 'form__item_type_dropzone', classNameGroupItem),
888
- width: width,
889
- label: label,
890
- labelTextColor: labelTextColor,
959
+ className: clsx('form-field_datepicker', 'form__item_datepicker', classNameGroupItem),
891
960
  errorKey: errorKey,
892
961
  errorMessage: errorMessage,
893
962
  isErrorState: isErrorState,
894
963
  metaError: meta.error,
895
- fieldClassName: "form-dropzone",
964
+ isDisabled: isDisabled,
965
+ fieldClassName: "form-datepicker",
896
966
  inputName: input.name,
897
- inputValue: input.value,
967
+ inputValue: input.value || '',
898
968
  metaActive: meta.active,
899
- metaTouched: meta.touched,
900
969
  showMessage: showMessage,
901
970
  isRequired: isRequired,
902
971
  isValidState: isValidState
903
- }, fieldProps), /*#__PURE__*/React.createElement(FileInputDropzone, {
904
- className: className,
905
- maxFiles: maxFiles,
906
- maxSize: maxSize,
907
- size: size,
908
- fill: fill,
909
- fillHover: fillHover,
910
- borderColor: updatedInputProps.borderColor,
911
- borderColorHover: borderColorHover,
912
- borderType: borderType,
913
- borderWidth: borderWidth,
914
- errorMessageTextColor: errorMessageTextColor,
915
- errorMessageTextSize: errorMessageTextSize,
916
- errorMessageWeight: errorMessageTextWeight,
917
- fileErrorText: fileErrorText,
918
- metaError: meta.error,
919
- dropzoneProps: dropzoneProps,
920
- hintDescription: hintDescription,
921
- hintDescriptionTextColor: hintDescriptionTextColor,
922
- hintDescriptionTextSize: hintDescriptionTextSize,
923
- hintDescriptionTextWeight: hintDescriptionTextWeight,
924
- hintDescriptionTextWrap: hintDescriptionTextWrap,
925
- hintTitle: hintTitle,
926
- hintTitleTextColor: hintTitleTextColor,
927
- hintTitleTextSize: hintTitleTextSize,
928
- hintTitleTextWeight: hintTitleTextWeight,
929
- hintTitleTextWrap: hintTitleTextWrap,
930
- inputName: input.name,
931
- inputValue: input.value,
932
- metaTouched: meta.touched,
933
- removeThumbAppearance: removeThumbAppearance,
934
- removeThumbShape: removeThumbShape,
935
- removeThumbText: removeThumbText,
936
- removeThumbTextWeight: removeThumbTextWeight,
937
- shape: shape,
938
- showFilename: showFilename,
939
- thumbBorderColor: thumbBorderColor,
940
- thumbBorderColorHover: thumbBorderColorHover,
941
- thumbBorderType: thumbBorderType,
942
- thumbBorderWidth: thumbBorderWidth,
943
- thumbColumn: thumbColumn,
944
- thumbDirection: thumbDirection,
945
- thumbNameTextColor: thumbNameTextColor,
946
- thumbNameTextSize: thumbNameTextSize,
947
- thumbNameTextWeight: thumbNameTextWeight,
948
- thumbNameTextWrap: thumbNameTextWrap,
949
- isPreviews: isPreviews,
950
- onAddFiles: onAddFiles,
951
- onClickPreview: onClickPreview,
952
- onDeleteFile: onDeleteFile
972
+ }, fieldProps), /*#__PURE__*/React.createElement(DatePickerInput, {
973
+ name: input.name,
974
+ isDisabled: isDisabled,
975
+ datePickerProps: datePickerProps,
976
+ endValue: datePickerProps.selectsRange ? input.value.endDate : null,
977
+ inputProps: updatedInputProps,
978
+ value: datePickerProps.selectsRange ? input.value.startDate : input.value,
979
+ onBlur: input.onBlur,
980
+ onChange: onChangeField,
981
+ onFocus: input.onFocus
953
982
  }));
954
983
  });
955
- });
984
+ }
956
985
 
957
- const defaultGroupProps = {
958
- width: 'fill',
959
- labelTextSize: 's',
960
- messageTextColor: 'surfaceTextPrimary',
961
- messageTextSize: 's',
962
- errorMessageTextSize: 's',
963
- errorMessageTextColor: 'errorTextSecondary',
964
- helpTextSize: 's',
965
- requiredMessageTextColor: 'warningTextSecondary',
966
- requiredMessageTextSize: 's'
986
+ const defaultDropzoneProps = {
987
+ fill: 'surfaceSecondary',
988
+ fillHover: 'surfaceTertiary',
989
+ // borderColor: 'surfaceBorderTertiary',
990
+ // borderColorHover: 'surfaceBorderQuaternary',
991
+ hintTitle: 'Перетащите изображение или выберите файл с компьютера',
992
+ hintTitleTextColor: 'surfaceTextPrimary',
993
+ hintTitleTextSize: 'm',
994
+ removeThumbText: 'удалить',
995
+ removeThumbTextColor: 'errorTextPrimary',
996
+ removeThumbTextHoverColor: 'errorTextPrimaryHover',
997
+ removeThumbTextSize: 's',
998
+ shape: 'rounded',
999
+ showFilename: true,
1000
+ thumbBorderColor: 'surfaceBorderTertiary',
1001
+ thumbBorderColorHover: 'surfaceBorderQuaternary',
1002
+ thumbBorderWidth: 1,
1003
+ thumbNameTextColor: 'surfaceTextPrimary',
1004
+ thumbNameTextSize: 's',
1005
+ isPreviews: true
967
1006
  };
968
1007
 
969
- const FormBlockGroup = /*#__PURE__*/React.memo(function Group(props) {
1008
+ const FileInputDropzone = /*#__PURE__*/React.memo(function FileInputDropzone(props) {
970
1009
  const {
971
- dataTour,
972
1010
  className,
973
- name,
974
- title,
975
- titleTextColor,
976
- titleTextSize,
977
- titleTextWeight,
978
- label,
979
- labelTextColor,
980
- labelTextSize,
981
- labelTextWeight,
982
- message,
983
- messageTextColor,
984
- messageTextSize,
985
- messageTextWeight,
986
- column,
987
- showGroupMessage,
988
- before,
989
- after,
990
- isHidden,
991
- children
1011
+ maxFiles,
1012
+ maxSize,
1013
+ size,
1014
+ fileErrorText,
1015
+ dropzoneProps = {},
1016
+ hintDescription,
1017
+ hintTitle,
1018
+ inputName,
1019
+ inputValue,
1020
+ showFilename,
1021
+ thumbColumn,
1022
+ isPreviews,
1023
+ onAddFiles,
1024
+ onClickPreview,
1025
+ onDeleteFile
992
1026
  } = props;
993
1027
 
994
- // @ts-expect-error
1028
+ // TODO: delete react-final-form things out of here?
995
1029
  const {
996
- styles: styles
997
- } = useStyles(props);
998
- return /*#__PURE__*/React.createElement(Field, {
999
- name: name
1000
- }, function Render({
1001
- input,
1002
- meta
1003
- }) {
1004
- /** Note:
1005
- * Create "Render" function by "eslint-react-hooks/rules-of-hooks":
1006
- * React Hooks cannot be called inside a callback.
1007
- * React Hooks must be called in a React function component or a
1008
- * custom React Hook function.
1009
- */
1010
- const {
1011
- errorKey,
1012
- errorMessage,
1013
- isErrorState
1014
- } = useFieldValidationState({
1015
- fieldProps: props,
1016
- // or fieldProps?
1017
- input: input,
1018
- meta: meta
1019
- });
1020
- const updatedProps = useValidationAppearanceInputProps({
1021
- inputProps: props,
1022
- validationStateKey: isErrorState ? errorKey : 'success'
1023
- });
1024
- return /*#__PURE__*/React.createElement("div", {
1025
- className: clsx('form__group', className, isHidden && 'form__group_hidden', column && `form__group_column_${column}`),
1026
- "data-tour": dataTour,
1027
- style: styles
1028
- }, /*#__PURE__*/React.createElement("div", {
1029
- className: "form__group-wrapper"
1030
- }, before, title && /*#__PURE__*/React.createElement("div", {
1031
- className: "form__group-title"
1032
- }, /*#__PURE__*/React.createElement(Title, {
1033
- size: titleTextSize,
1034
- textColor: titleTextColor,
1035
- textWeight: titleTextWeight
1036
- }, title)), label && /*#__PURE__*/React.createElement("div", {
1037
- className: "form__group-label"
1038
- }, /*#__PURE__*/React.createElement(Text, {
1039
- size: labelTextSize,
1040
- textColor: labelTextColor,
1041
- textWeight: labelTextWeight
1042
- }, label)), /*#__PURE__*/React.createElement("div", {
1043
- className: "form__group-items"
1044
- }, children), after), showGroupMessage && /*#__PURE__*/React.createElement(React.Fragment, null, isErrorState && errorMessage && /*#__PURE__*/React.createElement(Text, {
1045
- id: `${name}-error`,
1046
- className: `form__group-message form__group-message_type-${errorKey}`,
1047
- size: updatedProps.messageTextSize,
1048
- textColor: updatedProps.messageTextColor,
1049
- textWeight: updatedProps.messageTextWeight
1050
- }, errorMessage), Boolean(message) && (!isErrorState || !errorMessage) && /*#__PURE__*/React.createElement(Text, {
1051
- className: "form__group-message",
1052
- size: messageTextSize,
1053
- textColor: messageTextColor,
1054
- textWeight: messageTextWeight
1055
- }, message), !isErrorState && !message && /*#__PURE__*/React.createElement(Text, {
1056
- className: "form__group-message",
1057
- size: messageTextSize
1058
- }, '\u00A0')));
1059
- });
1060
- });
1030
+ change
1031
+ } = useForm();
1032
+ const [fileError, setFileError] = useState('');
1033
+ const [fileIsLoading, setFileIsLoading] = useState(false);
1034
+ const filesList = useMemo(() => inputValue ? castArray(inputValue) : [], [inputValue]);
1035
+ const changeFormState = useCallback(newFiles => {
1036
+ // If max files in dropzone is 1 - return file as it self, else as array of files
1037
+ // ps: for old projects compatibility
1038
+ const toSave = dropzoneProps.maxFiles == 1 ? newFiles[0] : newFiles;
1039
+ change(inputName, toSave);
1040
+ return toSave;
1041
+ },
1042
+ // If "inputName" will be changes, then it should be a different field
1043
+ // eslint-disable-next-line react-hooks/exhaustive-deps
1044
+ [dropzoneProps, change]);
1045
+
1046
+ //
1047
+ const convertFiledValueAndSaveAsFiles = useCallback(async currentFilesList => {
1048
+ setFileIsLoading(true);
1049
+ const newFiles = [];
1050
+ for (const fileItem of currentFilesList) {
1051
+ if (typeof fileItem === 'string') {
1052
+ const newFile = await convertToFile(fileItem, isPreviews);
1053
+ if (newFile) {
1054
+ newFiles.push(newFile);
1055
+ }
1056
+ } else {
1057
+ newFiles.push(fileItem);
1058
+ }
1059
+ }
1060
+ changeFormState(newFiles);
1061
+ setFileIsLoading(false);
1062
+ }, [isPreviews, changeFormState]);
1061
1063
 
1062
- const defaultCheckboxProps = {
1063
- appearance: 'defaultPrimary sizeL solid',
1064
- width: 'fill',
1065
- // useValidationAppearanceInputProps
1066
- // Error
1067
- errorAppearance: 'errorPrimary sizeL solid',
1068
- // Required
1069
- requiredAppearance: 'requirePrimary sizeL solid'
1070
- };
1064
+ // Delete file from dropzone
1065
+ const removeFile = useCallback((event, index) => {
1066
+ event.stopPropagation();
1067
+ event.preventDefault();
1068
+ const newFiles = [...filesList];
1069
+ newFiles.splice(index, 1);
1070
+ if (onDeleteFile) {
1071
+ onDeleteFile(filesList[index], inputName);
1072
+ }
1073
+ changeFormState(newFiles);
1074
+ },
1075
+ // If "inputName" will be changes, then it should be a different field
1076
+ // eslint-disable-next-line react-hooks/exhaustive-deps
1077
+ [filesList, changeFormState, onDeleteFile]);
1071
1078
 
1072
- const FormFieldCheckbox = /*#__PURE__*/React.memo(function FormFieldCheckbox(props) {
1079
+ // Create dropzone options
1073
1080
  const {
1074
- name,
1075
- initialValue,
1076
- isDisabled,
1077
- classNameGroupItem,
1078
- fieldProps = {},
1079
- inputProps = {},
1080
- showMessage,
1081
- isRequired,
1082
- onChange
1083
- } = props;
1084
- return /*#__PURE__*/React.createElement(Field, {
1085
- type: "checkbox",
1086
- name: name,
1087
- initialValue: initialValue
1088
- }, function Render({
1089
- input,
1090
- meta
1091
- }) {
1092
- /** Note:
1093
- * Create "Render" function by "eslint-react-hooks/rules-of-hooks":
1094
- * React Hooks cannot be called inside a callback.
1095
- * React Hooks must be called in a React function component or a
1096
- * custom React Hook function.
1097
- */
1081
+ getInputProps,
1082
+ getRootProps
1083
+ } = useDropzone({
1084
+ maxFiles: maxFiles || 5,
1085
+ maxSize: maxSize || 10485760,
1086
+ // 10mb
1087
+ // accept: { 'image/*': [] },
1088
+ ...dropzoneProps,
1089
+ getFilesFromEvent: async event => {
1090
+ const result = await fromEvent(event);
1091
+ const newFiles = result.filter(item => item instanceof File);
1092
+ // Add exists and new files to accepted(or rejected)
1093
+ return [...filesList, ...newFiles];
1094
+ },
1095
+ onDropAccepted: acceptedFiles => {
1096
+ // If dropped files has accepted and we need a previews
1097
+ if (isPreviews) {
1098
+ // Add preview to every file
1099
+ acceptedFiles.forEach(file => {
1100
+ if (!file.error) {
1101
+ file.preview = URL.createObjectURL(file);
1102
+ }
1103
+ });
1104
+ }
1105
+ // Save to form data (including empty when files are not valid)
1106
+ const filesToSave = changeFormState(acceptedFiles);
1107
+ setFileError('');
1098
1108
 
1099
- const onChangeField = useCallback(event => {
1100
- input.onChange(event);
1101
- if (onChange) {
1102
- onChange(event.target.checked, input.name);
1109
+ // Save DataURL for all files
1110
+ const readerPromisesList = acceptedFiles.map(file => {
1111
+ return new Promise(resolve => setFileDataURL(file, resolve));
1112
+ });
1113
+ // Save files to form values
1114
+ Promise.all(readerPromisesList).then(() => {
1115
+ if (onAddFiles) {
1116
+ onAddFiles(filesToSave, inputName);
1117
+ }
1118
+ });
1119
+ },
1120
+ onDropRejected: rejectedFiles => {
1121
+ // If dropped files has rejected
1122
+ if (rejectedFiles.length) {
1123
+ let fileErrorMessage = 'Ошибка при добавлении файла';
1124
+ const firstFileErrorItem = rejectedFiles[0].errors[0];
1125
+ if (firstFileErrorItem) {
1126
+ if (firstFileErrorItem.code === ErrorCode.TooManyFiles) {
1127
+ fileErrorMessage = `Максимальное количество файлов: ${maxFiles}`;
1128
+ } else {
1129
+ fileErrorMessage = firstFileErrorItem.message;
1130
+ }
1131
+ }
1132
+ // Show error
1133
+ setFileError(fileErrorMessage);
1134
+ } else {
1135
+ // Else clean error
1136
+ setFileError('');
1103
1137
  }
1104
- }, [onChange, input.onChange]);
1105
- const {
1106
- errorKey,
1107
- errorMessage,
1108
- isErrorState,
1109
- successKey,
1110
- isValidState
1111
- } = useFieldValidationState({
1112
- fieldProps: fieldProps,
1113
- input: input,
1114
- meta: meta
1138
+ }
1139
+ });
1140
+ useEffect(() => {
1141
+ const currentFilesList = castArray(inputValue);
1142
+ const isNeedToConvert = currentFilesList.some(fileItem => typeof fileItem === 'string');
1143
+ if (isNeedToConvert) {
1144
+ // First time convert value to Files and save to local and form state
1145
+ convertFiledValueAndSaveAsFiles(currentFilesList);
1146
+ }
1147
+
1148
+ // Make sure to revoke the data uris to avoid memory leaks, will run on unmount
1149
+ return () => {
1150
+ filesList.forEach(file => {
1151
+ if (file?.preview) {
1152
+ URL.revokeObjectURL(file.preview);
1153
+ }
1154
+ });
1155
+ };
1156
+ // eslint-disable-next-line react-hooks/exhaustive-deps
1157
+ }, [inputValue]);
1158
+ const propsGenerator = useDevicePropsGenerator(props);
1159
+ const {
1160
+ fillClass,
1161
+ fillHoverClass,
1162
+ borderColorClass,
1163
+ borderColorHoverClass,
1164
+ borderTypeClass,
1165
+ borderWidthClass,
1166
+ errorMessageTextColor,
1167
+ errorMessageTextSize,
1168
+ errorMessageTextWeight,
1169
+ hintDescriptionTextColor,
1170
+ hintDescriptionTextSize,
1171
+ hintDescriptionTextWeight,
1172
+ hintDescriptionTextWrap,
1173
+ hintTitleTextColor,
1174
+ hintTitleTextSize,
1175
+ hintTitleTextWeight,
1176
+ hintTitleTextWrap,
1177
+ removeThumbAppearance,
1178
+ removeThumbShape,
1179
+ removeThumbText,
1180
+ removeThumbTextWeight,
1181
+ shapeClass,
1182
+ thumbBorderColorClass,
1183
+ thumbBorderColorHoverClass,
1184
+ thumbBorderTypeClass,
1185
+ thumbBorderWidthClass,
1186
+ thumbDirectionClass,
1187
+ thumbNameTextColor,
1188
+ thumbNameTextSize,
1189
+ thumbNameTextWeight,
1190
+ thumbNameTextWrap
1191
+ } = propsGenerator;
1192
+ return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("div", getRootProps({
1193
+ // className: `form-dropzone__dropzone dropzone ${className} form-dropzone__dropzone_size_${size} ${shapeClass}`,
1194
+ className: `form-dropzone__dropzone dropzone`
1195
+ }), /*#__PURE__*/React.createElement("input", Object.assign({}, getInputProps(), {
1196
+ name: inputName
1197
+ })), /*#__PURE__*/React.createElement("div", {
1198
+ className: clsx('form-dropzone__dropzone-wrapper', thumbColumn && `form-dropzone__dropzone-wrapper_column_${thumbColumn}`, fillClass && `fill_${fillClass}`, fillHoverClass && `fill_hover_${fillHoverClass}`, borderWidthClass && `border-width_${borderWidthClass}`, borderColorClass && `border-color_${borderColorClass}`, borderColorHoverClass && `border-color_hover_${borderColorHoverClass}`, borderTypeClass && `border_type_${borderTypeClass}`, shapeClass && `shape_${shapeClass}`)
1199
+ }, filesList.map((file, index) => /*#__PURE__*/React.createElement("aside", {
1200
+ className: clsx('form-dropzone__thumb', fillClass, thumbDirectionClass, thumbBorderWidthClass, thumbBorderColorClass, thumbBorderColorHoverClass, thumbBorderTypeClass),
1201
+ key: file.id || `${file.name}_${index}`
1202
+ }, isPreviews && !file.error && /*#__PURE__*/React.createElement("div", {
1203
+ className: "form-dropzone__thumb-image"
1204
+ }, /*#__PURE__*/React.createElement("img", {
1205
+ className: "form-dropzone__thumb-image-inner",
1206
+ src: file.preview || file.image,
1207
+ onClick: event => {
1208
+ onClickPreview && onClickPreview(file, event);
1209
+ },
1210
+ onLoad: () => {
1211
+ // Revoke data uri after image is loaded
1212
+ URL.revokeObjectURL(file.preview);
1213
+ }
1214
+ })), file.error && /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement(Text, {
1215
+ size: thumbNameTextSize,
1216
+ textColor: thumbNameTextColor,
1217
+ textWeight: thumbNameTextWeight,
1218
+ textWrap: thumbNameTextWrap
1219
+ }, fileErrorText || file.error)), showFilename && /*#__PURE__*/React.createElement("div", {
1220
+ className: "form-dropzone__thumb-name"
1221
+ }, /*#__PURE__*/React.createElement(Text, {
1222
+ className: "form-dropzone__thumb-name-inner",
1223
+ size: thumbNameTextSize,
1224
+ textColor: thumbNameTextColor,
1225
+ textWeight: thumbNameTextWeight,
1226
+ textWrap: thumbNameTextWrap
1227
+ }, file.name)), fileIsLoading && /*#__PURE__*/React.createElement("div", {
1228
+ className: "form-dropzone__thumb-loader"
1229
+ }, /*#__PURE__*/React.createElement(Loader, {
1230
+ width: "fill",
1231
+ height: "fill"
1232
+ })), /*#__PURE__*/React.createElement("div", {
1233
+ className: clsx('form-dropzone__thumb-remove')
1234
+ }, /*#__PURE__*/React.createElement(Button, {
1235
+ className: "form-dropzone__thumb-remove-text",
1236
+ appearance: removeThumbAppearance,
1237
+ label: removeThumbText || 'Удалить',
1238
+ labelTextWeight: removeThumbTextWeight,
1239
+ shape: removeThumbShape,
1240
+ onClick: event => removeFile(event, index)
1241
+ })))), !filesList.length ? /*#__PURE__*/React.createElement("div", {
1242
+ className: "form-dropzone__hint"
1243
+ }, /*#__PURE__*/React.createElement(Text, {
1244
+ className: "form-dropzone__hint-title",
1245
+ size: hintTitleTextSize,
1246
+ textColor: hintTitleTextColor,
1247
+ textWeight: hintTitleTextWeight,
1248
+ textWrap: hintTitleTextWrap
1249
+ }, hintTitle || 'Select a file or drag in form'), hintDescription && /*#__PURE__*/React.createElement(Text, {
1250
+ className: "form-dropzone__hint-text",
1251
+ size: hintDescriptionTextSize,
1252
+ textColor: hintDescriptionTextColor,
1253
+ textWeight: hintDescriptionTextWeight,
1254
+ textWrap: hintDescriptionTextWrap
1255
+ }, hintDescription)) : /*#__PURE__*/React.createElement("div", {
1256
+ className: "form-dropzone__hint form-dropzone__hint_type_add-more"
1257
+ }, /*#__PURE__*/React.createElement(Text, {
1258
+ className: "form-dropzone__hint-title",
1259
+ size: hintTitleTextSize,
1260
+ textColor: hintTitleTextColor,
1261
+ textWeight: hintTitleTextWeight,
1262
+ textWrap: hintTitleTextWrap
1263
+ }, hintTitle || 'Select a file or drag in form'), hintDescription && /*#__PURE__*/React.createElement(Text, {
1264
+ className: "form-dropzone__hint-text",
1265
+ size: hintDescriptionTextSize,
1266
+ textColor: hintDescriptionTextColor,
1267
+ textWeight: hintDescriptionTextWeight,
1268
+ textWrap: hintDescriptionTextWrap
1269
+ }, hintDescription)))), fileError && /*#__PURE__*/React.createElement("div", {
1270
+ className: "form-field__message"
1271
+ }, /*#__PURE__*/React.createElement(Text, {
1272
+ className: "form-field__message-item form-field__message-item_type_message",
1273
+ size: errorMessageTextSize,
1274
+ textColor: errorMessageTextColor,
1275
+ textWeight: errorMessageTextWeight
1276
+ }, fileError)));
1277
+ });
1278
+ async function getFileByURL(url) {
1279
+ try {
1280
+ const response = await axios({
1281
+ url: url,
1282
+ responseType: 'blob'
1115
1283
  });
1116
- const updatedInputProps = useValidationAppearanceInputProps({
1117
- inputProps: inputProps,
1118
- validationStateKey: isErrorState ? errorKey : isValidState ? successKey : null
1284
+ const blobObject = response.data;
1285
+ const dirtyFilename = response.headers['content-disposition']?.split('filename=')[1];
1286
+ // Remove double quotes
1287
+ let filename = dirtyFilename?.substring(1).slice(0, -1);
1288
+ if (!filename) {
1289
+ filename = url.split('/').at(-1);
1290
+ // const typeParts = blobObject.type.split('/')
1291
+ // const fileType = typeParts[typeParts.length - 1]
1292
+ // filename = `${new Date().getTime()}.${fileType}`
1293
+ }
1294
+ return new File([blobObject], filename, {
1295
+ type: blobObject.type
1119
1296
  });
1120
- return /*#__PURE__*/React.createElement(FieldWrapper, Object.assign({
1121
- className: clsx('form-field-checkbox', 'form__item_checkbox', classNameGroupItem),
1122
- errorKey: errorKey,
1123
- errorMessage: errorMessage,
1124
- isErrorState: isErrorState,
1125
- metaError: meta.error,
1126
- isDisabled: isDisabled,
1127
- fieldClassName: "form-checkbox",
1128
- inputName: input.name,
1129
- inputValue: input.checked,
1130
- metaActive: meta.active,
1131
- showMessage: showMessage,
1132
- tag: "label",
1133
- isRequired: isRequired,
1134
- isValidState: isValidState
1135
- }, fieldProps), /*#__PURE__*/React.createElement(Checkbox, Object.assign({
1136
- type: "checkbox",
1137
- name: input.name,
1138
- isDisabled: isDisabled,
1139
- autoComplete: "nope",
1140
- checked: input.checked,
1141
- isActive: input.checked,
1142
- onBlur: input.onBlur,
1143
- onChange: onChangeField,
1144
- onFocus: input.onFocus
1145
- }, updatedInputProps)));
1146
- });
1147
- });
1297
+ } catch (error) {
1298
+ console.log('error: ', error);
1299
+ return null;
1300
+ }
1301
+ }
1302
+ async function convertToFile(inputValue, isPreviews) {
1303
+ let newFile = null;
1148
1304
 
1149
- const defaultChipsProps = {
1150
- appearance: 'surfacePrimary sizeM rounded',
1151
- width: 'fill',
1152
- // useValidationAppearanceInputProps
1153
- // Error
1154
- errorAppearance: 'errorPrimary sizeM solid rounded',
1155
- // Required
1156
- requiredAppearance: 'requirePrimary sizeM solid rounded'
1157
- // Success
1158
- // successAppearance: 'successPrimary sizeM solid rounded',
1159
- };
1305
+ // Download image by url and save as File instance
1306
+ const isURL = typeof inputValue === 'string' && inputValue.includes('/');
1307
+ if (inputValue.image || isURL) {
1308
+ newFile = await getFileByURL(inputValue.image || inputValue);
1309
+ if (newFile) {
1310
+ setFileDataURL(newFile);
1311
+ }
1312
+ }
1160
1313
 
1161
- function FormFieldChips(props) {
1162
- const {
1163
- name,
1164
- initialValue,
1165
- isDisabled,
1166
- classNameGroupItem,
1167
- emptyMessage,
1168
- emptyMessageTextColor,
1169
- emptyMessageTextSize,
1170
- fieldProps,
1171
- inputProps,
1172
- options,
1173
- showMessage,
1174
- isRequired,
1175
- onChange
1176
- } = props;
1177
- const {
1178
- change
1179
- } = useForm();
1314
+ // Convert dataURL to File instance
1315
+ if (inputValue.dataURL) {
1316
+ newFile = createFileFromDataURL(inputValue.name || inputValue.path, inputValue.dataURL);
1317
+ newFile.dataURL = inputValue.dataURL;
1318
+ }
1180
1319
 
1181
- // Callback for value changes
1182
- const onChangeSomeInput = useCallback((inputValue, newOptionValue) => {
1183
- const updatedValues = inputValue.includes(newOptionValue) ? inputValue.filter(selectedValue => selectedValue !== newOptionValue) : [...inputValue, newOptionValue];
1184
- change(name, updatedValues);
1185
- onChange && onChange(updatedValues);
1186
- }, [change, name, onChange]);
1187
- useEffect(() => {
1188
- initialValue && change(name, initialValue);
1189
- // update the form value only when the initialValue changes, so use disable eslint to ignore the warning
1190
- // eslint-disable-next-line react-hooks/exhaustive-deps
1191
- }, [initialValue]);
1192
- return /*#__PURE__*/React.createElement(Field, {
1193
- name: name,
1194
- initialValue: initialValue
1195
- }, function Render({
1196
- input,
1197
- meta
1198
- }) {
1199
- const {
1200
- errorKey,
1201
- errorMessage,
1202
- isErrorState,
1203
- successKey,
1204
- isValidState
1205
- } = useFieldValidationState({
1206
- fieldProps: fieldProps,
1207
- input: input,
1208
- meta: meta
1209
- });
1210
- const updatedInputProps = useValidationAppearanceInputProps({
1211
- inputProps: inputProps,
1212
- validationStateKey: isErrorState ? errorKey : isValidState ? successKey : null
1213
- });
1214
- const activeOptionsList = useMemo(() => {
1215
- const emptyOptionsList = [{
1216
- label: null,
1217
- value: null
1218
- }];
1219
- if (input?.value) {
1220
- const currentOptions = options.filter(option => input.value?.includes(option.value));
1221
- return currentOptions || emptyOptionsList;
1222
- }
1223
- return emptyOptionsList;
1224
- }, [input.value]);
1225
- return /*#__PURE__*/React.createElement(FieldWrapper, Object.assign({
1226
- className: clsx('form-field_chips', 'form__item_chips', classNameGroupItem),
1227
- errorKey: errorKey,
1228
- errorMessage: errorMessage,
1229
- isErrorState: isErrorState,
1230
- metaError: meta.error,
1231
- isDisabled: isDisabled,
1232
- fieldClassName: "form-chips",
1233
- inputName: input.name,
1234
- inputValue: input.value,
1235
- metaActive: meta.active,
1236
- showMessage: showMessage,
1237
- isRequired: isRequired,
1238
- isValidState: isValidState
1239
- }, fieldProps), options.length ? /*#__PURE__*/React.createElement(ChipsGroup, {
1240
- direction: "horizontal",
1241
- gap: "1m",
1242
- wrap: "wrap"
1243
- }, options.map(option => /*#__PURE__*/React.createElement(Chips, Object.assign({
1244
- className: clsx(meta.active && 'form-chips_state_focus', meta.error && meta.touched && `form-chips_state_${errorKey}`),
1245
- key: option.value,
1246
- label: option.label,
1247
- isDisabled: option.isDisabled,
1248
- value: option.value,
1249
- isActive: activeOptionsList.some(activeOption => activeOption.value === option.value),
1250
- onClick: () => onChangeSomeInput(input.value, option.value)
1251
- }, updatedInputProps)))) : /*#__PURE__*/React.createElement(Text, {
1252
- size: emptyMessageTextSize,
1253
- textColor: emptyMessageTextColor
1254
- }, emptyMessage));
1255
- });
1320
+ // Save new File to state
1321
+ if (newFile) {
1322
+ newFile.id = inputValue.id;
1323
+ if (isPreviews) {
1324
+ newFile.preview = URL.createObjectURL(newFile);
1325
+ }
1326
+ }
1327
+ return newFile;
1256
1328
  }
1329
+ function setFileDataURL(file, resolve) {
1330
+ resolve = resolve || (() => {});
1331
+ // Init reader and save his file
1332
+ const reader = new FileReader();
1333
+ reader._readedFile = file;
1257
1334
 
1258
- const defaultChoiceProps = {
1259
- appearance: 'defaultPrimary sizeM solid rounded',
1260
- width: 'fill',
1261
- // useValidationAppearanceInputProps
1262
- // Error
1263
- errorAppearance: 'errorPrimary sizeM solid rounded',
1264
- // Required
1265
- requiredAppearance: 'requirePrimary sizeM solid rounded'
1266
- };
1335
+ // Set handlers
1336
+ reader.onabort = () => resolve();
1337
+ reader.onerror = () => resolve();
1338
+ reader.onload = event => {
1339
+ event.target._readedFile.dataURL = reader.result;
1340
+ resolve();
1341
+ };
1342
+ // Run reader
1343
+ if (file instanceof File) {
1344
+ reader.readAsDataURL(file);
1345
+ } else {
1346
+ resolve();
1347
+ }
1348
+ }
1267
1349
 
1268
- const FormFieldChoice = /*#__PURE__*/React.memo(function FormFieldChoice(props) {
1350
+ const FormFieldFileInput = /*#__PURE__*/React.memo(function FormFieldFileInput(props) {
1269
1351
  const {
1352
+ className,
1270
1353
  name,
1271
- initialValue,
1354
+ width,
1355
+ maxFiles,
1356
+ maxSize,
1272
1357
  label,
1273
- messageType,
1274
- isDisabled,
1358
+ fileErrorText,
1275
1359
  classNameGroupItem,
1360
+ dropzoneProps,
1276
1361
  fieldProps,
1277
- inputProps,
1278
- options,
1279
- placeholder,
1362
+ hintDescription,
1363
+ hintTitle,
1364
+ showFilename,
1280
1365
  showMessage,
1281
- isCheckbox,
1366
+ isPreviews,
1282
1367
  isRequired,
1283
- onChange
1368
+ onAddFiles,
1369
+ onClickPreview,
1370
+ onDeleteFile
1284
1371
  } = props;
1372
+ const propsGenerator = useDevicePropsGenerator(props);
1285
1373
  const {
1286
- change
1287
- } = useForm();
1288
- const setActiveSegment = useCallback((option, isChecked) => {
1289
- change(name, isChecked && option.value);
1290
- if (onChange) {
1291
- onChange(option.value, name, isChecked);
1292
- }
1293
- }, [change, onChange]);
1374
+ size,
1375
+ fill,
1376
+ fillHover,
1377
+ labelTextColor,
1378
+ borderColorHover,
1379
+ borderType,
1380
+ borderWidth,
1381
+ errorMessageTextColor,
1382
+ errorMessageTextSize,
1383
+ errorMessageTextWeight,
1384
+ hintDescriptionTextColor,
1385
+ hintDescriptionTextSize,
1386
+ hintDescriptionTextWeight,
1387
+ hintDescriptionTextWrap,
1388
+ hintTitleTextColor,
1389
+ hintTitleTextSize,
1390
+ hintTitleTextWeight,
1391
+ hintTitleTextWrap,
1392
+ removeThumbAppearance,
1393
+ removeThumbShape,
1394
+ removeThumbText,
1395
+ removeThumbTextWeight,
1396
+ shape,
1397
+ thumbBorderColor,
1398
+ thumbBorderColorHover,
1399
+ thumbBorderType,
1400
+ thumbBorderWidth,
1401
+ thumbColumn = 1,
1402
+ thumbDirection = 'vertical',
1403
+ thumbNameTextColor,
1404
+ thumbNameTextSize,
1405
+ thumbNameTextWeight,
1406
+ thumbNameTextWrap
1407
+ } = propsGenerator;
1294
1408
  return /*#__PURE__*/React.createElement(Field, {
1295
- initialValue: initialValue,
1296
1409
  name: name
1297
1410
  }, function Render({
1298
1411
  input,
@@ -1304,22 +1417,11 @@ const FormFieldChoice = /*#__PURE__*/React.memo(function FormFieldChoice(props)
1304
1417
  * React Hooks must be called in a React function component or a
1305
1418
  * custom React Hook function.
1306
1419
  */
1307
- const activeOption = useMemo(() => {
1308
- const emptyOption = {
1309
- value: null,
1310
- label: null
1311
- };
1312
- if (input.value) {
1313
- const currentOption = options.find(option => option.value === input.value);
1314
- return currentOption || emptyOption;
1315
- }
1316
- return emptyOption;
1317
- }, [input.value]);
1420
+
1318
1421
  const {
1319
1422
  errorKey,
1320
1423
  errorMessage,
1321
1424
  isErrorState,
1322
- successKey,
1323
1425
  isValidState
1324
1426
  } = useFieldValidationState({
1325
1427
  fieldProps: fieldProps,
@@ -1327,65 +1429,127 @@ const FormFieldChoice = /*#__PURE__*/React.memo(function FormFieldChoice(props)
1327
1429
  meta: meta
1328
1430
  });
1329
1431
  const updatedInputProps = useValidationAppearanceInputProps({
1330
- inputProps: inputProps,
1331
- validationStateKey: isErrorState ? errorKey : isValidState ? successKey : null
1432
+ inputProps: props,
1433
+ validationStateKey: isErrorState ? errorKey : 'success'
1332
1434
  });
1435
+
1436
+ /** TODO:
1437
+ * REFACTOR PROPERTIES
1438
+ */
1333
1439
  return /*#__PURE__*/React.createElement(FieldWrapper, Object.assign({
1334
- className: clsx('form-field_choice', 'form__item_choice', classNameGroupItem),
1440
+ className: clsx('form-field_type_dropzone', 'form__item_type_dropzone', classNameGroupItem),
1441
+ width: width,
1335
1442
  label: label,
1336
- messageType: messageType,
1443
+ labelTextColor: labelTextColor,
1337
1444
  errorKey: errorKey,
1338
1445
  errorMessage: errorMessage,
1339
1446
  isErrorState: isErrorState,
1340
1447
  metaError: meta.error,
1341
- isDisabled: isDisabled,
1342
- fieldClassName: "form-choice",
1448
+ fieldClassName: "form-dropzone",
1343
1449
  inputName: input.name,
1344
- inputValue: input.value || [],
1450
+ inputValue: input.value,
1345
1451
  metaActive: meta.active,
1452
+ metaTouched: meta.touched,
1346
1453
  showMessage: showMessage,
1347
1454
  isRequired: isRequired,
1348
1455
  isValidState: isValidState
1349
- }, fieldProps), /*#__PURE__*/React.createElement(Choice, Object.assign({
1350
- className: clsx(meta.active && 'form-choice_state_focus', meta.error && meta.touched && `form-choice_state_${errorKey}`),
1351
- name: input.name,
1352
- isDisabled: isDisabled,
1353
- active: activeOption,
1354
- inputValue: input.value || [],
1355
- options: options,
1356
- placeholder: placeholder,
1357
- setActiveSegment: setActiveSegment,
1358
- isCheckbox: isCheckbox,
1359
- isRequired: isRequired
1360
- }, updatedInputProps)));
1456
+ }, fieldProps), /*#__PURE__*/React.createElement(FileInputDropzone, {
1457
+ className: className,
1458
+ maxFiles: maxFiles,
1459
+ maxSize: maxSize,
1460
+ size: size,
1461
+ fill: fill,
1462
+ fillHover: fillHover,
1463
+ borderColor: updatedInputProps.borderColor,
1464
+ borderColorHover: borderColorHover,
1465
+ borderType: borderType,
1466
+ borderWidth: borderWidth,
1467
+ errorMessageTextColor: errorMessageTextColor,
1468
+ errorMessageTextSize: errorMessageTextSize,
1469
+ errorMessageWeight: errorMessageTextWeight,
1470
+ fileErrorText: fileErrorText,
1471
+ metaError: meta.error,
1472
+ dropzoneProps: dropzoneProps,
1473
+ hintDescription: hintDescription,
1474
+ hintDescriptionTextColor: hintDescriptionTextColor,
1475
+ hintDescriptionTextSize: hintDescriptionTextSize,
1476
+ hintDescriptionTextWeight: hintDescriptionTextWeight,
1477
+ hintDescriptionTextWrap: hintDescriptionTextWrap,
1478
+ hintTitle: hintTitle,
1479
+ hintTitleTextColor: hintTitleTextColor,
1480
+ hintTitleTextSize: hintTitleTextSize,
1481
+ hintTitleTextWeight: hintTitleTextWeight,
1482
+ hintTitleTextWrap: hintTitleTextWrap,
1483
+ inputName: input.name,
1484
+ inputValue: input.value,
1485
+ metaTouched: meta.touched,
1486
+ removeThumbAppearance: removeThumbAppearance,
1487
+ removeThumbShape: removeThumbShape,
1488
+ removeThumbText: removeThumbText,
1489
+ removeThumbTextWeight: removeThumbTextWeight,
1490
+ shape: shape,
1491
+ showFilename: showFilename,
1492
+ thumbBorderColor: thumbBorderColor,
1493
+ thumbBorderColorHover: thumbBorderColorHover,
1494
+ thumbBorderType: thumbBorderType,
1495
+ thumbBorderWidth: thumbBorderWidth,
1496
+ thumbColumn: thumbColumn,
1497
+ thumbDirection: thumbDirection,
1498
+ thumbNameTextColor: thumbNameTextColor,
1499
+ thumbNameTextSize: thumbNameTextSize,
1500
+ thumbNameTextWeight: thumbNameTextWeight,
1501
+ thumbNameTextWrap: thumbNameTextWrap,
1502
+ isPreviews: isPreviews,
1503
+ onAddFiles: onAddFiles,
1504
+ onClickPreview: onClickPreview,
1505
+ onDeleteFile: onDeleteFile
1506
+ }));
1361
1507
  });
1362
1508
  });
1363
1509
 
1364
- const defaultCodeProps = {
1365
- appearance: 'defaultPrimary sizeL solid rounded',
1366
- // useValidationAppearanceInputProps
1367
- // Error
1368
- errorAppearance: 'errorPrimary sizeM solid rounded',
1369
- // Required
1370
- requiredAppearance: 'requirePrimary sizeM solid rounded'
1510
+ const defaultGroupProps = {
1511
+ width: 'fill',
1512
+ labelTextSize: 's',
1513
+ messageTextColor: 'surfaceTextPrimary',
1514
+ messageTextSize: 's',
1515
+ errorMessageTextSize: 's',
1516
+ errorMessageTextColor: 'errorTextSecondary',
1517
+ helpTextSize: 's',
1518
+ requiredMessageTextColor: 'warningTextSecondary',
1519
+ requiredMessageTextSize: 's'
1371
1520
  };
1372
1521
 
1373
- const FormFieldCode = /*#__PURE__*/React.memo(function FormFieldCode(props) {
1522
+ const FormBlockGroup = /*#__PURE__*/React.memo(function Group(props) {
1374
1523
  const {
1524
+ dataTour,
1525
+ className,
1375
1526
  name,
1376
- initialValue,
1527
+ title,
1528
+ titleTextColor,
1529
+ titleTextSize,
1530
+ titleTextWeight,
1377
1531
  label,
1378
- messageType,
1379
- isDisabled,
1380
- classNameGroupItem,
1381
- fieldProps = {},
1382
- inputProps = {},
1383
- showMessage,
1384
- isRequired
1532
+ labelTextColor,
1533
+ labelTextSize,
1534
+ labelTextWeight,
1535
+ message,
1536
+ messageTextColor,
1537
+ messageTextSize,
1538
+ messageTextWeight,
1539
+ column,
1540
+ showGroupMessage,
1541
+ before,
1542
+ after,
1543
+ isHidden,
1544
+ children
1385
1545
  } = props;
1546
+
1547
+ // @ts-expect-error
1548
+ const {
1549
+ styles: styles
1550
+ } = useStyles(props);
1386
1551
  return /*#__PURE__*/React.createElement(Field, {
1387
- name: name,
1388
- initialValue: initialValue
1552
+ name: name
1389
1553
  }, function Render({
1390
1554
  input,
1391
1555
  meta
@@ -1396,68 +1560,93 @@ const FormFieldCode = /*#__PURE__*/React.memo(function FormFieldCode(props) {
1396
1560
  * React Hooks must be called in a React function component or a
1397
1561
  * custom React Hook function.
1398
1562
  */
1399
-
1400
1563
  const {
1401
1564
  errorKey,
1402
1565
  errorMessage,
1403
- isErrorState,
1404
- successKey,
1405
- isValidState
1566
+ isErrorState
1406
1567
  } = useFieldValidationState({
1407
- fieldProps: fieldProps,
1568
+ fieldProps: props,
1569
+ // or fieldProps?
1408
1570
  input: input,
1409
1571
  meta: meta
1410
1572
  });
1411
- const updatedInputProps = useValidationAppearanceInputProps({
1412
- inputProps: inputProps,
1413
- validationStateKey: isErrorState ? errorKey : isValidState ? successKey : null
1573
+ const updatedProps = useValidationAppearanceInputProps({
1574
+ inputProps: props,
1575
+ validationStateKey: isErrorState ? errorKey : 'success'
1414
1576
  });
1415
- return /*#__PURE__*/React.createElement(FieldWrapper, Object.assign({
1416
- className: clsx('form-field-code', 'form__item_code', classNameGroupItem),
1417
- label: label,
1418
- messageType: messageType,
1419
- errorKey: errorKey,
1420
- errorMessage: errorMessage,
1421
- isErrorState: isErrorState,
1422
- fieldClassName: 'form-code',
1423
- inputName: input.name,
1424
- inputValue: input.value,
1425
- metaActive: meta.active,
1426
- showMessage: showMessage,
1427
- isRequired: isRequired,
1428
- isValidState: isValidState
1429
- }, fieldProps), /*#__PURE__*/React.createElement(Code, Object.assign({
1430
- name: input.name,
1431
- initialValue: input.value,
1432
- isDisabled: isDisabled,
1433
- autoComplete: "nope",
1434
- onBlur: input.onBlur,
1435
- onChange: input.onChange,
1436
- onFocus: input.onFocus
1437
- }, updatedInputProps)));
1577
+ return /*#__PURE__*/React.createElement("div", {
1578
+ className: clsx('form__group', className, isHidden && 'form__group_hidden', column && `form__group_column_${column}`),
1579
+ "data-tour": dataTour,
1580
+ style: styles
1581
+ }, /*#__PURE__*/React.createElement("div", {
1582
+ className: "form__group-wrapper"
1583
+ }, before, title && /*#__PURE__*/React.createElement("div", {
1584
+ className: "form__group-title"
1585
+ }, /*#__PURE__*/React.createElement(Title, {
1586
+ size: titleTextSize,
1587
+ textColor: titleTextColor,
1588
+ textWeight: titleTextWeight
1589
+ }, title)), label && /*#__PURE__*/React.createElement("div", {
1590
+ className: "form__group-label"
1591
+ }, /*#__PURE__*/React.createElement(Text, {
1592
+ size: labelTextSize,
1593
+ textColor: labelTextColor,
1594
+ textWeight: labelTextWeight
1595
+ }, label)), /*#__PURE__*/React.createElement("div", {
1596
+ className: "form__group-items"
1597
+ }, children), after), showGroupMessage && /*#__PURE__*/React.createElement(React.Fragment, null, isErrorState && errorMessage && /*#__PURE__*/React.createElement(Text, {
1598
+ id: `${name}-error`,
1599
+ className: `form__group-message form__group-message_type-${errorKey}`,
1600
+ size: updatedProps.messageTextSize,
1601
+ textColor: updatedProps.messageTextColor,
1602
+ textWeight: updatedProps.messageTextWeight
1603
+ }, errorMessage), Boolean(message) && (!isErrorState || !errorMessage) && /*#__PURE__*/React.createElement(Text, {
1604
+ className: "form__group-message",
1605
+ size: messageTextSize,
1606
+ textColor: messageTextColor,
1607
+ textWeight: messageTextWeight
1608
+ }, message), !isErrorState && !message && /*#__PURE__*/React.createElement(Text, {
1609
+ className: "form__group-message",
1610
+ size: messageTextSize
1611
+ }, '\u00A0')));
1438
1612
  });
1439
1613
  });
1440
1614
 
1441
- const FormFieldCustom = /*#__PURE__*/React.memo(function FormFieldCustom(props) {
1615
+ const defaultInputProps = {
1616
+ appearance: 'defaultPrimary sizeM solid rounded',
1617
+ width: 'fill',
1618
+ // useValidationAppearanceInputProps
1619
+ // Error
1620
+ errorAppearance: 'errorPrimary sizeM solid rounded',
1621
+ // Required
1622
+ requiredAppearance: 'requirePrimary sizeM solid rounded',
1623
+ // Success
1624
+ successAppearance: 'successPrimary sizeM solid rounded'
1625
+ };
1626
+
1627
+ const FormFieldInput = /*#__PURE__*/React.memo(function FormFieldInput(props) {
1442
1628
  const {
1443
- Component,
1444
- isDisabled,
1445
- isRequired,
1446
1629
  name,
1447
1630
  initialValue,
1448
- fieldProps = {},
1449
1631
  classNameGroupItem,
1450
- showMessage,
1451
1632
  clearIcon,
1452
1633
  clearIconFill,
1453
1634
  clearIconFillHover,
1454
1635
  clearIconShape,
1455
1636
  clearIconSize,
1456
- onClickClearIcon
1637
+ fieldProps = {},
1638
+ inputProps = {},
1639
+ parse,
1640
+ showMessage,
1641
+ isDisabled,
1642
+ isRequired,
1643
+ onClickClearIcon,
1644
+ onChange
1457
1645
  } = props;
1458
1646
  return /*#__PURE__*/React.createElement(Field, {
1647
+ name: name,
1459
1648
  initialValue: initialValue,
1460
- name: name
1649
+ parse: parse
1461
1650
  }, function Render({
1462
1651
  input,
1463
1652
  meta
@@ -1469,79 +1658,87 @@ const FormFieldCustom = /*#__PURE__*/React.memo(function FormFieldCustom(props)
1469
1658
  * custom React Hook function.
1470
1659
  */
1471
1660
 
1661
+ const onChangeField = useCallback(event => {
1662
+ input.onChange(event);
1663
+ if (onChange) {
1664
+ onChange(event.target.value, input.name);
1665
+ }
1666
+ }, [onChange, input.onChange]);
1472
1667
  const {
1473
- isErrorState,
1474
- isValidState,
1475
1668
  errorKey,
1476
- errorMessage
1669
+ errorMessage,
1670
+ successKey,
1671
+ isErrorState,
1672
+ isValidState
1477
1673
  } = useFieldValidationState({
1478
1674
  fieldProps: fieldProps,
1479
1675
  input: input,
1480
1676
  meta: meta
1481
1677
  });
1482
1678
  const updatedInputProps = useValidationAppearanceInputProps({
1483
- validationStateKey: isErrorState ? errorKey : 'success',
1484
- // For "Custom" field we pass all props. Can contain some special props, we don't known.
1485
- inputProps: props
1679
+ inputProps: inputProps,
1680
+ validationStateKey: isErrorState ? errorKey : isValidState ? successKey : null
1486
1681
  });
1487
1682
  return /*#__PURE__*/React.createElement(FieldWrapper, Object.assign({
1488
- className: clsx('form-field_custom', 'form__item_custom', classNameGroupItem),
1683
+ className: clsx('form-field_input', 'form__item_input', classNameGroupItem),
1489
1684
  errorKey: errorKey,
1490
1685
  errorMessage: errorMessage,
1491
- fieldClassName: 'form-custom',
1686
+ fieldClassName: "form-input",
1492
1687
  inputName: input.name,
1493
- inputValue: input.value,
1688
+ inputValue: input.value || '',
1689
+ metaActive: meta.active,
1690
+ metaError: meta.error,
1691
+ showMessage: showMessage,
1494
1692
  isDisabled: isDisabled,
1495
1693
  isErrorState: isErrorState,
1496
1694
  isRequired: isRequired,
1497
- isValidState: isValidState,
1498
- metaActive: meta.active,
1499
- metaError: meta.error,
1500
- showMessage: showMessage
1501
- }, fieldProps), /*#__PURE__*/React.createElement(Component, Object.assign({}, updatedInputProps, {
1502
- input: input,
1695
+ isValidState: isValidState
1696
+ }, fieldProps), /*#__PURE__*/React.createElement(Input, Object.assign({
1697
+ className: clsx(meta.active && 'input_state_focus', meta.error && meta.touched && `input_state_${errorKey}`),
1698
+ dataTestId: `${input.name}FieldInput`,
1699
+ type: "text",
1700
+ name: input.name,
1701
+ autoComplete: "nope",
1702
+ value: input.value || '',
1503
1703
  isDisabled: isDisabled,
1504
- meta: meta
1505
- })), clearIcon && /*#__PURE__*/React.createElement(Icon, {
1704
+ onBlur: input.onBlur,
1705
+ onChange: onChangeField,
1706
+ onFocus: input.onFocus
1707
+ }, updatedInputProps)), clearIcon && /*#__PURE__*/React.createElement(Icon, {
1506
1708
  className: "form-field__icon",
1709
+ size: clearIconSize,
1507
1710
  iconFill: clearIconFill,
1508
1711
  iconFillHover: clearIconFillHover,
1509
- imageSrc: clearIcon,
1712
+ imageSrc: typeof clearIcon === 'string' && clearIcon,
1510
1713
  shape: clearIconShape,
1511
- size: clearIconSize,
1512
- SvgImage: clearIcon,
1714
+ SvgImage: typeof clearIcon !== 'string' && clearIcon,
1513
1715
  onClick: onClickClearIcon
1514
1716
  }));
1515
1717
  });
1516
1718
  });
1517
1719
 
1518
- const defaultDatepickerProps = {
1519
- appearance: 'surfacePrimary sizeS',
1520
- dateFormat: 'dd/MM/yyyy - HH:mm',
1521
- readOnly: false,
1522
- selectsRange: false,
1523
- showTimeSelect: true,
1524
- timeCaption: 'Время',
1525
- timeFormat: 'p',
1526
- timeIntervals: 60,
1527
- isClearable: true,
1528
- isStartDefaultNull: true
1529
- };
1530
-
1531
- function FormFieldDatePicker(props) {
1720
+ const FormFieldMaskedInput = /*#__PURE__*/React.memo(function FormFieldMaskedInput(props) {
1532
1721
  const {
1533
1722
  name,
1534
- isDisabled,
1723
+ initialValue,
1535
1724
  classNameGroupItem,
1536
- datePickerProps,
1725
+ clearIcon,
1726
+ clearIconFill,
1727
+ clearIconFillHover,
1728
+ clearIconShape,
1729
+ clearIconSize,
1537
1730
  fieldProps = {},
1538
1731
  inputProps = {},
1732
+ optionsMask,
1539
1733
  showMessage,
1734
+ unmasked,
1735
+ isDisabled,
1540
1736
  isRequired,
1541
- onChange
1737
+ onClickClearIcon
1542
1738
  } = props;
1543
1739
  return /*#__PURE__*/React.createElement(Field, {
1544
- name: name
1740
+ name: name,
1741
+ initialValue: initialValue
1545
1742
  }, function Render({
1546
1743
  input,
1547
1744
  meta
@@ -1553,27 +1750,35 @@ function FormFieldDatePicker(props) {
1553
1750
  * custom React Hook function.
1554
1751
  */
1555
1752
 
1556
- const onChangeField = useCallback((startDate, endDate) => {
1557
- if (!datePickerProps.selectsRange) {
1558
- // When we need to save single date, value is date
1559
- // TODO: make object with one date? need to check all forms with FormFieldDatePicker
1560
- input.onChange(startDate);
1561
- } else {
1562
- // When we need to save range, value is object with two date
1563
- input.onChange({
1564
- endDate,
1565
- startDate
1566
- });
1753
+ const {
1754
+ ref,
1755
+ unmaskedValue,
1756
+ value,
1757
+ setUnmaskedValue
1758
+ } = useIMask(optionsMask, {
1759
+ onAccept: (newValue, event, element) => {
1760
+ if (element) {
1761
+ input.onChange(event._unmaskedValue);
1762
+ }
1567
1763
  }
1568
- if (onChange) {
1569
- onChange(startDate, endDate);
1764
+ });
1765
+ useEffect(() => {
1766
+ if (input.value !== unmaskedValue) {
1767
+ setUnmaskedValue(input.value.replace(unmasked, ''));
1570
1768
  }
1571
- }, [input.onChange, onChange]);
1769
+ }, [input.value]);
1770
+
1771
+ // useEffect(() => {
1772
+ // if (unmaskedValue !== input.value) {
1773
+ // input.onChange(unmaskedValue)
1774
+ // }
1775
+ // }, [unmaskedValue])
1776
+
1572
1777
  const {
1573
1778
  errorKey,
1574
1779
  errorMessage,
1575
- isErrorState,
1576
1780
  successKey,
1781
+ isErrorState,
1577
1782
  isValidState
1578
1783
  } = useFieldValidationState({
1579
1784
  fieldProps: fieldProps,
@@ -1585,36 +1790,40 @@ function FormFieldDatePicker(props) {
1585
1790
  validationStateKey: isErrorState ? errorKey : isValidState ? successKey : null
1586
1791
  });
1587
1792
  return /*#__PURE__*/React.createElement(FieldWrapper, Object.assign({
1588
- className: clsx('form-field_datepicker', 'form__item_datepicker', classNameGroupItem),
1793
+ className: clsx('form-field-masked-input', 'form__item_masked-input', classNameGroupItem),
1589
1794
  errorKey: errorKey,
1590
1795
  errorMessage: errorMessage,
1591
- isErrorState: isErrorState,
1592
- metaError: meta.error,
1593
- isDisabled: isDisabled,
1594
- fieldClassName: "form-datepicker",
1796
+ fieldClassName: 'form-maskedInput',
1595
1797
  inputName: input.name,
1596
- inputValue: input.value || '',
1798
+ inputValue: input.value,
1597
1799
  metaActive: meta.active,
1800
+ metaError: meta.error,
1598
1801
  showMessage: showMessage,
1802
+ isDisabled: isDisabled,
1803
+ isErrorState: isErrorState,
1599
1804
  isRequired: isRequired,
1600
1805
  isValidState: isValidState
1601
- }, fieldProps), /*#__PURE__*/React.createElement(DatePickerInput, {
1602
- name: input.name,
1603
- isDisabled: isDisabled,
1604
- datePickerProps: datePickerProps,
1605
- endValue: datePickerProps.selectsRange ? input.value.endDate : null,
1606
- inputProps: updatedInputProps,
1607
- value: datePickerProps.selectsRange ? input.value.startDate : input.value,
1806
+ }, fieldProps), /*#__PURE__*/React.createElement(Input, Object.assign({
1807
+ className: clsx(meta.active && 'input_state_focus', meta.error && meta.touched && `input_state_${errorKey}`),
1808
+ ref: ref,
1809
+ value: value,
1608
1810
  onBlur: input.onBlur,
1609
- onChange: onChangeField,
1610
1811
  onFocus: input.onFocus
1812
+ }, updatedInputProps)), clearIcon && /*#__PURE__*/React.createElement(Icon, {
1813
+ className: "form-field__icon",
1814
+ size: clearIconSize,
1815
+ iconFill: clearIconFill,
1816
+ iconFillHover: clearIconFillHover,
1817
+ imageSrc: clearIcon,
1818
+ shape: clearIconShape,
1819
+ SvgImage: clearIcon,
1820
+ onClick: onClickClearIcon
1611
1821
  }));
1612
1822
  });
1613
- }
1823
+ });
1614
1824
 
1615
- const defaultInputProps = {
1825
+ const defaultPasswordProps = {
1616
1826
  appearance: 'defaultPrimary sizeM solid rounded',
1617
- width: 'fill',
1618
1827
  // useValidationAppearanceInputProps
1619
1828
  // Error
1620
1829
  errorAppearance: 'errorPrimary sizeM solid rounded',
@@ -1624,27 +1833,18 @@ const defaultInputProps = {
1624
1833
  successAppearance: 'successPrimary sizeM solid rounded'
1625
1834
  };
1626
1835
 
1627
- const FormFieldInput = /*#__PURE__*/React.memo(function FormFieldInput(props) {
1836
+ const FormFieldPassword = /*#__PURE__*/React.memo(function FormFieldPassword(props) {
1628
1837
  const {
1629
1838
  name,
1630
1839
  initialValue,
1631
- isDisabled,
1632
1840
  classNameGroupItem,
1633
- // dataTestId,
1634
- // iconBorder,
1635
- // iconBorderHover,
1636
- clearIcon,
1637
- clearIconFill,
1638
- clearIconFillHover,
1639
- clearIconShape,
1640
- clearIconSize,
1641
- fieldProps = {},
1642
- inputProps = {},
1841
+ fieldProps,
1842
+ inputProps,
1643
1843
  parse,
1644
1844
  showMessage,
1845
+ isDisabled,
1645
1846
  isRequired,
1646
- onChange,
1647
- onClickClearIcon
1847
+ onChange
1648
1848
  } = props;
1649
1849
  return /*#__PURE__*/React.createElement(Field, {
1650
1850
  name: name,
@@ -1670,8 +1870,8 @@ const FormFieldInput = /*#__PURE__*/React.memo(function FormFieldInput(props) {
1670
1870
  const {
1671
1871
  errorKey,
1672
1872
  errorMessage,
1673
- isErrorState,
1674
1873
  successKey,
1874
+ isErrorState,
1675
1875
  isValidState
1676
1876
  } = useFieldValidationState({
1677
1877
  fieldProps: fieldProps,
@@ -1683,79 +1883,90 @@ const FormFieldInput = /*#__PURE__*/React.memo(function FormFieldInput(props) {
1683
1883
  validationStateKey: isErrorState ? errorKey : isValidState ? successKey : null
1684
1884
  });
1685
1885
  return /*#__PURE__*/React.createElement(FieldWrapper, Object.assign({
1686
- className: clsx('form-field_input', 'form__item_input', classNameGroupItem),
1886
+ className: clsx('form-field_input-password', 'form__item_input-password', classNameGroupItem),
1687
1887
  errorKey: errorKey,
1688
1888
  errorMessage: errorMessage,
1689
- isErrorState: isErrorState,
1690
- metaError: meta.error,
1691
- isDisabled: isDisabled,
1692
- fieldClassName: "form-input",
1889
+ fieldClassName: "form-password",
1693
1890
  inputName: input.name,
1694
1891
  inputValue: input.value || '',
1695
1892
  metaActive: meta.active,
1893
+ metaError: meta.error,
1696
1894
  showMessage: showMessage,
1895
+ isDisabled: isDisabled,
1896
+ isErrorState: isErrorState,
1697
1897
  isRequired: isRequired,
1698
1898
  isValidState: isValidState
1699
- }, fieldProps), /*#__PURE__*/React.createElement(Input, Object.assign({
1700
- dataTestId: `${input.name}FieldInput`,
1701
- className: clsx(meta.active && 'input_state_focus', meta.error && meta.touched && `input_state_${errorKey}`),
1702
- type: "text",
1899
+ }, fieldProps), /*#__PURE__*/React.createElement(InputPassword, Object.assign({
1900
+ className: clsx(meta.active && 'input-password_state_focus', meta.error && meta.touched && `input-password_state_${errorKey}`),
1901
+ dataTestId: `${input.name}FieldInputPassword`,
1703
1902
  name: input.name,
1704
- isDisabled: isDisabled,
1705
1903
  autoComplete: "nope",
1706
1904
  value: input.value || '',
1905
+ isDisabled: isDisabled,
1707
1906
  onBlur: input.onBlur,
1708
1907
  onChange: onChangeField,
1709
1908
  onFocus: input.onFocus
1710
- }, updatedInputProps)), clearIcon && /*#__PURE__*/React.createElement(Icon, {
1711
- className: "form-field__icon",
1712
- size: clearIconSize,
1713
- iconFill: clearIconFill,
1714
- iconFillHover: clearIconFillHover,
1715
- imageSrc: typeof clearIcon === 'string' && clearIcon,
1716
- shape: clearIconShape,
1717
- SvgImage: typeof clearIcon !== 'string' && clearIcon,
1718
- onClick: onClickClearIcon
1719
- }));
1909
+ }, updatedInputProps)));
1720
1910
  });
1721
1911
  });
1722
1912
 
1723
- const defaultPasswordProps = {
1724
- appearance: 'sizeM defaultSecondary solid rounded',
1725
- // useValidationAppearanceInputProps
1726
- // Error
1727
- errorAppearance: 'errorPrimary sizeM solid rounded',
1728
- // Required
1729
- iconRevealableHide: icons24.View.HideValue,
1730
- iconRevealableShow: icons24.View.ShowValue,
1731
- requiredAppearance: 'requirePrimary sizeM solid rounded'
1913
+ const defaultRadioProps = {
1914
+ appearance: 'defaultPrimary sizeM solid circular'
1732
1915
  };
1733
1916
 
1734
- const FormFieldPassword = /*#__PURE__*/React.memo(function FormFieldPassword(props) {
1917
+ function FormFieldRadioGroupList(props) {
1918
+ const {
1919
+ input,
1920
+ inputProps,
1921
+ options,
1922
+ onChange
1923
+ } = props;
1924
+
1925
+ // Callback for value changes
1926
+ const onChangeSomeInput = useCallback(value => {
1927
+ // Save to form values
1928
+ input.onChange(value);
1929
+ if (onChange) {
1930
+ // Pass to custom event
1931
+ onChange(value, input.name);
1932
+ }
1933
+ }, [input, onChange]);
1934
+
1935
+ // Handle for radio inputs
1936
+ const onChangeRadio = useCallback(event => {
1937
+ if (event.target.checked) {
1938
+ onChangeSomeInput(event.target.value);
1939
+ }
1940
+ }, [onChange]);
1941
+ return /*#__PURE__*/React.createElement(React.Fragment, null, options.map(option => /*#__PURE__*/React.createElement(Radio, Object.assign({
1942
+ className: "form-radio__item",
1943
+ key: option.value,
1944
+ type: "radio",
1945
+ name: input.name,
1946
+ label: option.label,
1947
+ checked: option.value === input.value,
1948
+ value: option.value,
1949
+ onBlur: input.onBlur,
1950
+ onChange: onChangeRadio,
1951
+ onFocus: input.onFocus
1952
+ }, inputProps))));
1953
+ }
1954
+
1955
+ const FormFieldRadioGroup = /*#__PURE__*/React.memo(function FormFieldRadioGroup(props) {
1735
1956
  const {
1736
1957
  name,
1737
- initialValue,
1738
1958
  isDisabled,
1959
+ editableProps = {},
1960
+ fieldProps = {},
1961
+ inputProps = {},
1962
+ options = [],
1739
1963
  classNameGroupItem,
1740
- fieldProps,
1741
- inputProps,
1742
- parse,
1743
1964
  showMessage,
1744
1965
  isRequired,
1745
1966
  onChange
1746
1967
  } = props;
1747
- const [isRevealed, setIsRevealed] = useState(false);
1748
- const inputType = useMemo(() => {
1749
- return isRevealed ? 'text' : 'password';
1750
- }, [isRevealed]);
1751
- const onClickIconReveal = useCallback(event => {
1752
- event.preventDefault();
1753
- setIsRevealed(prev => !prev);
1754
- }, []);
1755
1968
  return /*#__PURE__*/React.createElement(Field, {
1756
- name: name,
1757
- initialValue: initialValue,
1758
- parse: parse
1969
+ name: name
1759
1970
  }, function Render({
1760
1971
  input,
1761
1972
  meta
@@ -1767,17 +1978,10 @@ const FormFieldPassword = /*#__PURE__*/React.memo(function FormFieldPassword(pro
1767
1978
  * custom React Hook function.
1768
1979
  */
1769
1980
 
1770
- const onChangeField = useCallback(event => {
1771
- input.onChange(event);
1772
- if (onChange) {
1773
- onChange(event.target.value, input.name);
1774
- }
1775
- }, [onChange, input.onChange]);
1776
1981
  const {
1777
1982
  errorKey,
1778
1983
  errorMessage,
1779
1984
  isErrorState,
1780
- successKey,
1781
1985
  isValidState
1782
1986
  } = useFieldValidationState({
1783
1987
  fieldProps: fieldProps,
@@ -1786,39 +1990,29 @@ const FormFieldPassword = /*#__PURE__*/React.memo(function FormFieldPassword(pro
1786
1990
  });
1787
1991
  const updatedInputProps = useValidationAppearanceInputProps({
1788
1992
  inputProps: inputProps,
1789
- validationStateKey: isErrorState ? errorKey : isValidState ? successKey : null
1993
+ validationStateKey: isErrorState ? errorKey : 'success'
1790
1994
  });
1791
1995
  return /*#__PURE__*/React.createElement(FieldWrapper, Object.assign({
1792
- className: clsx('form-field_input', 'form__item_input', classNameGroupItem),
1996
+ className: clsx('form-field_radio', 'form__item_radio', classNameGroupItem),
1793
1997
  errorKey: errorKey,
1794
1998
  errorMessage: errorMessage,
1795
1999
  isErrorState: isErrorState,
1796
2000
  metaError: meta.error,
1797
2001
  isDisabled: isDisabled,
1798
- fieldClassName: "form-password",
2002
+ fieldClassName: 'form-radio',
1799
2003
  inputName: input.name,
1800
2004
  inputValue: input.value || '',
1801
2005
  metaActive: meta.active,
1802
2006
  showMessage: showMessage,
1803
2007
  isRequired: isRequired,
1804
2008
  isValidState: isValidState
1805
- }, fieldProps), /*#__PURE__*/React.createElement(Input, Object.assign({
1806
- dataTestId: `${input.name}FieldInputPassword`,
1807
- className: clsx(meta.active && 'input_state_focus', meta.error && meta.touched && `input_state_${errorKey}`),
1808
- type: inputType,
1809
- name: input.name,
2009
+ }, fieldProps), /*#__PURE__*/React.createElement(FormFieldRadioGroupList, {
1810
2010
  isDisabled: isDisabled,
1811
- autoComplete: "nope",
1812
- value: input.value || '',
1813
- onBlur: input.onBlur,
1814
- onChange: onChangeField,
1815
- onFocus: input.onFocus
1816
- }, updatedInputProps)), /*#__PURE__*/React.createElement(Icon, {
1817
- className: "form-field__icon",
1818
- size: inputProps?.iconSize,
1819
- iconFill: inputProps?.iconFill,
1820
- SvgImage: isRevealed ? inputProps?.iconRevealableHide : inputProps?.iconRevealableShow,
1821
- onClick: onClickIconReveal
2011
+ editableProps: editableProps,
2012
+ input: input,
2013
+ inputProps: updatedInputProps,
2014
+ options: options,
2015
+ onChange: onChange
1822
2016
  }));
1823
2017
  });
1824
2018
  });
@@ -2037,12 +2231,8 @@ const FormFieldSelect = /*#__PURE__*/React.memo(function FormFieldSelect(props)
2037
2231
 
2038
2232
  const defaultSwitchProps = {
2039
2233
  appearance: 'defaultPrimary sizeL solid rounded',
2040
- // useValidationAppearanceInputProps
2041
- // Error
2042
2234
  errorAppearance: 'errorPrimary sizeL solid rounded',
2043
- // Success
2044
2235
  successAppearance: 'successPrimary sizeL solid rounded',
2045
- // Required
2046
2236
  requiredAppearance: 'requirePrimary sizeL solid rounded'
2047
2237
  };
2048
2238
 
@@ -2197,216 +2387,6 @@ const FormFieldTextarea = /*#__PURE__*/React.memo(function FormFieldTextarea(pro
2197
2387
  });
2198
2388
  });
2199
2389
 
2200
- const FormFieldMaskedInput = /*#__PURE__*/React.memo(function FormFieldMaskedInput(props) {
2201
- const {
2202
- name,
2203
- initialValue,
2204
- isDisabled,
2205
- classNameGroupItem,
2206
- clearIcon,
2207
- clearIconFill,
2208
- clearIconFillHover,
2209
- clearIconShape,
2210
- clearIconSize,
2211
- fieldProps = {},
2212
- inputProps = {},
2213
- optionsMask,
2214
- showMessage,
2215
- unmasked,
2216
- isRequired,
2217
- onClickClearIcon
2218
- } = props;
2219
- return /*#__PURE__*/React.createElement(Field, {
2220
- name: name,
2221
- initialValue: initialValue
2222
- }, function Render({
2223
- input,
2224
- meta
2225
- }) {
2226
- /** Note:
2227
- * Create "Render" function by "eslint-react-hooks/rules-of-hooks":
2228
- * React Hooks cannot be called inside a callback.
2229
- * React Hooks must be called in a React function component or a
2230
- * custom React Hook function.
2231
- */
2232
-
2233
- const {
2234
- ref,
2235
- setUnmaskedValue,
2236
- unmaskedValue,
2237
- value
2238
- } = useIMask(optionsMask, {
2239
- onAccept: (newValue, event, element) => {
2240
- if (element) {
2241
- input.onChange(event._unmaskedValue);
2242
- }
2243
- }
2244
- });
2245
- useEffect(() => {
2246
- if (input.value !== unmaskedValue) {
2247
- setUnmaskedValue(input.value.replace(unmasked, ''));
2248
- }
2249
- }, [input.value]);
2250
- useEffect(() => {
2251
- if (unmaskedValue !== input.value) {
2252
- input.onChange(unmaskedValue);
2253
- }
2254
- }, [unmaskedValue]);
2255
- const {
2256
- errorKey,
2257
- errorMessage,
2258
- isErrorState,
2259
- successKey,
2260
- isValidState
2261
- } = useFieldValidationState({
2262
- fieldProps: fieldProps,
2263
- input: input,
2264
- meta: meta
2265
- });
2266
- const updatedInputProps = useValidationAppearanceInputProps({
2267
- inputProps: inputProps,
2268
- validationStateKey: isErrorState ? errorKey : isValidState ? successKey : null
2269
- });
2270
- return /*#__PURE__*/React.createElement(FieldWrapper, Object.assign({
2271
- className: clsx('form-field-masked-input', 'form__item_masked-input', classNameGroupItem),
2272
- errorKey: errorKey,
2273
- errorMessage: errorMessage,
2274
- isErrorState: isErrorState,
2275
- metaError: meta.error,
2276
- isDisabled: isDisabled,
2277
- fieldClassName: 'form-maskedInput',
2278
- inputName: input.name,
2279
- inputValue: input.value,
2280
- metaActive: meta.active,
2281
- showMessage: showMessage,
2282
- isRequired: isRequired,
2283
- isValidState: isValidState
2284
- }, fieldProps), /*#__PURE__*/React.createElement(Input, Object.assign({
2285
- className: clsx(meta.active && 'input_state_focus', meta.error && meta.touched && `input_state_${errorKey}`),
2286
- ref: ref,
2287
- value: value,
2288
- onBlur: input.onBlur,
2289
- onFocus: input.onFocus
2290
- }, updatedInputProps)), clearIcon && /*#__PURE__*/React.createElement(Icon, {
2291
- className: "form-field__icon",
2292
- size: clearIconSize,
2293
- iconFill: clearIconFill,
2294
- iconFillHover: clearIconFillHover,
2295
- imageSrc: clearIcon,
2296
- shape: clearIconShape,
2297
- SvgImage: clearIcon,
2298
- onClick: onClickClearIcon
2299
- }));
2300
- });
2301
- });
2302
-
2303
- const defaultRadioProps = {
2304
- appearance: 'defaultPrimary sizeM solid circular'
2305
- };
2306
-
2307
- function RadioGroupList(props) {
2308
- const {
2309
- input,
2310
- inputProps,
2311
- options,
2312
- onChange
2313
- } = props;
2314
-
2315
- // Callback for value changes
2316
- const onChangeSomeInput = useCallback(value => {
2317
- // Save to form values
2318
- input.onChange(value);
2319
- if (onChange) {
2320
- // Pass to custom event
2321
- onChange(value, input.name);
2322
- }
2323
- }, [input, onChange]);
2324
-
2325
- // Handle for radio inputs
2326
- const onChangeRadio = useCallback(event => {
2327
- if (event.target.checked) {
2328
- onChangeSomeInput(event.target.value);
2329
- }
2330
- }, [onChange]);
2331
- return /*#__PURE__*/React.createElement(React.Fragment, null, options.map(option => /*#__PURE__*/React.createElement(Radio, Object.assign({
2332
- className: "form-radio__item",
2333
- key: option.value,
2334
- type: "radio",
2335
- name: input.name,
2336
- label: option.label,
2337
- checked: option.value === input.value,
2338
- value: option.value,
2339
- onBlur: input.onBlur,
2340
- onChange: onChangeRadio,
2341
- onFocus: input.onFocus
2342
- }, inputProps))));
2343
- }
2344
-
2345
- const RadioGroup = /*#__PURE__*/React.memo(function RadioGroup(props) {
2346
- const {
2347
- name,
2348
- isDisabled,
2349
- editableProps = {},
2350
- fieldProps = {},
2351
- inputProps = {},
2352
- options = [],
2353
- classNameGroupItem,
2354
- showMessage,
2355
- isRequired,
2356
- onChange
2357
- } = props;
2358
- return /*#__PURE__*/React.createElement(Field, {
2359
- name: name
2360
- }, function Render({
2361
- input,
2362
- meta
2363
- }) {
2364
- /** Note:
2365
- * Create "Render" function by "eslint-react-hooks/rules-of-hooks":
2366
- * React Hooks cannot be called inside a callback.
2367
- * React Hooks must be called in a React function component or a
2368
- * custom React Hook function.
2369
- */
2370
-
2371
- const {
2372
- errorKey,
2373
- errorMessage,
2374
- isErrorState,
2375
- isValidState
2376
- } = useFieldValidationState({
2377
- fieldProps: fieldProps,
2378
- input: input,
2379
- meta: meta
2380
- });
2381
- const updatedInputProps = useValidationAppearanceInputProps({
2382
- inputProps: inputProps,
2383
- validationStateKey: isErrorState ? errorKey : 'success'
2384
- });
2385
- return /*#__PURE__*/React.createElement(FieldWrapper, Object.assign({
2386
- className: clsx('form-field_radio', 'form__item_radio', classNameGroupItem),
2387
- errorKey: errorKey,
2388
- errorMessage: errorMessage,
2389
- isErrorState: isErrorState,
2390
- metaError: meta.error,
2391
- isDisabled: isDisabled,
2392
- fieldClassName: 'form-radio',
2393
- inputName: input.name,
2394
- inputValue: input.value || '',
2395
- metaActive: meta.active,
2396
- showMessage: showMessage,
2397
- isRequired: isRequired,
2398
- isValidState: isValidState
2399
- }, fieldProps), /*#__PURE__*/React.createElement(RadioGroupList, {
2400
- isDisabled: isDisabled,
2401
- editableProps: editableProps,
2402
- input: input,
2403
- inputProps: updatedInputProps,
2404
- options: options,
2405
- onChange: onChange
2406
- }));
2407
- });
2408
- });
2409
-
2410
2390
  const formTypes = {
2411
2391
  password: 'password',
2412
2392
  code: 'code',
@@ -2478,13 +2458,13 @@ function generateField(field, config, props) {
2478
2458
  }
2479
2459
  case formTypes.fileInput:
2480
2460
  {
2481
- return /*#__PURE__*/React.createElement(FileInput, Object.assign({
2461
+ return /*#__PURE__*/React.createElement(FormFieldFileInput, Object.assign({
2482
2462
  key: config.key
2483
2463
  }, field, props));
2484
2464
  }
2485
2465
  case formTypes.radioGroup:
2486
2466
  {
2487
- return /*#__PURE__*/React.createElement(RadioGroup, Object.assign({
2467
+ return /*#__PURE__*/React.createElement(FormFieldRadioGroup, Object.assign({
2488
2468
  key: config.key
2489
2469
  }, field, props));
2490
2470
  }
@@ -3137,4 +3117,4 @@ const getErrorsForFinalForm = error => {
3137
3117
  return formErrors;
3138
3118
  };
3139
3119
 
3140
- 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, defaultFieldSizeL, defaultFieldSizeM, defaultFieldSizeS, defaultFieldSizeXL, defaultGroupProps, defaultInputProps, defaultPasswordProps, defaultRadioProps, defaultSegmentedProps, defaultSelectProps, defaultSwitchProps, defaultTextareaProps, emailValidation, focusOnError, focusOnErrorDecorator, formTypes, generateField, getErrorsForFinalForm, parseNumericField, phoneValidation, sendFormDataToServer, setErrorsMutator, useYupValidationSchema };
3120
+ export { DEFAULT_MESSAGES_FIELDS, FieldWrapper, FieldWrapperBase, FinalForm, FormBlockGroup, FormFieldCheckbox, FormFieldChips, FormFieldChoice, FormFieldCode, FormFieldCustom, FormFieldDatePicker, FormFieldFileInput, FormFieldInput, FormFieldMaskedInput, FormFieldPassword, FormFieldRadioGroup, FormFieldSegmented, FormFieldSelect, FormFieldSwitch, FormFieldTextarea, addRequiredFieldsParamToSchema, dateValidation, defaultCheckboxProps, defaultChipsProps, defaultChoiceProps, defaultCodeProps, defaultDatepickerProps, defaultDropzoneProps, defaultFieldProps, defaultFieldSizeL, defaultFieldSizeM, defaultFieldSizeS, defaultFieldSizeXL, defaultGroupProps, defaultInputProps, defaultPasswordProps, defaultRadioProps, defaultSegmentedProps, defaultSelectProps, defaultSwitchProps, defaultTextareaProps, emailValidation, focusOnError, focusOnErrorDecorator, formTypes, generateField, getErrorsForFinalForm, parseNumericField, phoneValidation, sendFormDataToServer, setErrorsMutator, useYupValidationSchema };