@snack-uikit/fields 0.19.1 → 0.19.3-preview-34ffedb5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -3,6 +3,18 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ ## 0.19.2 (2024-04-25)
7
+
8
+
9
+ ### Bug Fixes
10
+
11
+ * **PDS-0000:** remove required pinTop/pinBottom ([51bbe9f](https://github.com/cloud-ru-tech/snack-uikit/commit/51bbe9f6d79c50bd2aa41128a12b125eb91f625b))
12
+ * **PDS-0000:** set default button type as button ([4ec64de](https://github.com/cloud-ru-tech/snack-uikit/commit/4ec64de508826df4a1e82fd8c75448d9919e563f))
13
+
14
+
15
+
16
+
17
+
6
18
  ## 0.19.1 (2024-04-24)
7
19
 
8
20
 
package/README.md CHANGED
@@ -252,6 +252,7 @@ const [isOpen, setIsOpen] = useState(false);
252
252
  | showCopyButton | `boolean` | - | Отображение кнопки копирования |
253
253
  | allowMoreThanMaxLength | `boolean` | - | Можно ли вводить больше разрешённого кол-ва символов |
254
254
  | prefixIcon | `ReactElement<any, string \| JSXElementConstructor<any>>` | - | Иконка-префикс для поля |
255
+ | onDataRequest | `() => Promise<void>` | - | Свойство позволяет грузить данные в поле по требованию |
255
256
  | value | `string` | - | Значение input |
256
257
  | onChange | `(value: string, e?: ChangeEvent<HTMLInputElement>) => void` | - | Колбек смены значения |
257
258
  | disabled | `boolean` | - | Является ли поле деактивированным |
@@ -312,8 +313,6 @@ const [isOpen, setIsOpen] = useState(false);
312
313
  ### Props
313
314
  | name | type | default value | description |
314
315
  |------|------|---------------|-------------|
315
- | pinBottom* | `OptionProps[]` | - | |
316
- | pinTop* | `OptionProps[]` | - | |
317
316
  | options* | `OptionProps[]` | - | |
318
317
  | disabled | `boolean` | false | Является ли поле деактивированным |
319
318
  | readonly | `boolean` | false false | Является ли поле доступным только для чтения |
@@ -337,6 +336,8 @@ const [isOpen, setIsOpen] = useState(false);
337
336
  | value | `ItemId \| ItemId[]` | - | Controlled состояние |
338
337
  | onChange | `OnChangeHandler<any>` | - | Controlled обработчик измения состояния |
339
338
  | defaultValue | `ItemId \| ItemId[]` | - | Начальное состояние |
339
+ | pinTop | `OptionProps[]` | - | |
340
+ | pinBottom | `OptionProps[]` | - | |
340
341
  | searchable | `boolean` | - | |
341
342
  | showCopyButton | `boolean` | - | Отображение кнопки Копировать для поля (актуально только для `readonly = true`) |
342
343
  | showClearButton | `boolean` | true | Отображение кнопки очистки поля |
@@ -15,6 +15,8 @@ type FieldSecureOwnProps = {
15
15
  allowMoreThanMaxLength?: boolean;
16
16
  /** Иконка-префикс для поля */
17
17
  prefixIcon?: ReactElement;
18
+ /** Свойство позволяет грузить данные в поле по требованию */
19
+ onDataRequest?(): Promise<void>;
18
20
  };
19
21
  export type FieldSecureProps = WithSupportProps<FieldSecureOwnProps & InputProps & WrapperProps>;
20
22
  export declare const FieldSecure: import("react").ForwardRefExoticComponent<{
@@ -1,3 +1,12 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
1
10
  var __rest = (this && this.__rest) || function (s, e) {
2
11
  var t = {};
3
12
  for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
@@ -11,8 +20,9 @@ var __rest = (this && this.__rest) || function (s, e) {
11
20
  };
12
21
  import { jsx as _jsx } from "react/jsx-runtime";
13
22
  import mergeRefs from 'merge-refs';
14
- import { forwardRef, useMemo, useRef } from 'react';
23
+ import { forwardRef, useMemo, useRef, useState } from 'react';
15
24
  import { InputPrivate, moveCursorToEnd, runAfterRerender, SIZE, useButtonNavigation, } from '@snack-uikit/input-private';
25
+ import { Skeleton, WithSkeleton } from '@snack-uikit/skeleton';
16
26
  import { extractSupportProps } from '@snack-uikit/utils';
17
27
  import { CONTAINER_VARIANT, VALIDATION_STATE } from '../../constants';
18
28
  import { FieldContainerPrivate } from '../../helperComponents';
@@ -20,10 +30,12 @@ import { useCopyButton, useHideButton, useValueControl } from '../../hooks';
20
30
  import { getValidationState } from '../../utils/getValidationState';
21
31
  import { FieldDecorator } from '../FieldDecorator';
22
32
  export const FieldSecure = forwardRef((_a, ref) => {
23
- var { id, name, value: valueProp, placeholder, maxLength, disabled = false, readonly = false, showCopyButton: showCopyButtonProp = true, allowMoreThanMaxLength = false, hidden: hiddenProp, onHiddenChange, showHintIcon, onChange: onChangeProp, onFocus, onBlur, className, label, labelTooltip, labelTooltipPlacement, required = false, hint, size = SIZE.S, validationState = VALIDATION_STATE.Default, prefixIcon, error } = _a, rest = __rest(_a, ["id", "name", "value", "placeholder", "maxLength", "disabled", "readonly", "showCopyButton", "allowMoreThanMaxLength", "hidden", "onHiddenChange", "showHintIcon", "onChange", "onFocus", "onBlur", "className", "label", "labelTooltip", "labelTooltipPlacement", "required", "hint", "size", "validationState", "prefixIcon", "error"]);
33
+ var { id, name, value: valueProp, placeholder, maxLength, disabled = false, readonly = false, showCopyButton: showCopyButtonProp = true, allowMoreThanMaxLength = false, hidden: hiddenProp, onHiddenChange, showHintIcon, onChange: onChangeProp, onFocus, onBlur, className, label, labelTooltip, labelTooltipPlacement, required = false, hint, size = SIZE.S, validationState = VALIDATION_STATE.Default, prefixIcon, error, onDataRequest } = _a, rest = __rest(_a, ["id", "name", "value", "placeholder", "maxLength", "disabled", "readonly", "showCopyButton", "allowMoreThanMaxLength", "hidden", "onHiddenChange", "showHintIcon", "onChange", "onFocus", "onBlur", "className", "label", "labelTooltip", "labelTooltipPlacement", "required", "hint", "size", "validationState", "prefixIcon", "error", "onDataRequest"]);
24
34
  const localRef = useRef(null);
25
35
  const copyButtonRef = useRef(null);
26
36
  const hideButtonRef = useRef(null);
37
+ const [isDataRequested, setIsDataRequested] = useState(false);
38
+ const [isLoading, setIsLoading] = useState(false);
27
39
  const [value = '', onChange] = useValueControl({
28
40
  value: valueProp,
29
41
  defaultValue: '',
@@ -37,23 +49,58 @@ export const FieldSecure = forwardRef((_a, ref) => {
37
49
  const showCopyButton = showCopyButtonProp && Boolean(value) && readonly && !disabled;
38
50
  const showHideButton = !(readonly && !value);
39
51
  const fieldValidationState = getValidationState({ validationState, error });
40
- const toggleHidden = () => {
41
- setHidden(!hidden);
42
- if (!readonly) {
43
- runAfterRerender(() => {
44
- var _a;
45
- (_a = localRef.current) === null || _a === void 0 ? void 0 : _a.focus();
46
- moveCursorToEnd(localRef.current);
47
- });
52
+ const handleDataRequest = () => __awaiter(void 0, void 0, void 0, function* () {
53
+ if (!isDataRequested && onDataRequest) {
54
+ setIsLoading(true);
55
+ try {
56
+ yield onDataRequest();
57
+ setIsDataRequested(true);
58
+ return true;
59
+ }
60
+ catch (e) {
61
+ return false;
62
+ }
63
+ finally {
64
+ setIsLoading(false);
65
+ }
48
66
  }
67
+ return true;
68
+ });
69
+ const toggleHidden = () => {
70
+ handleDataRequest().then(isSuccess => {
71
+ if (isSuccess) {
72
+ setHidden(!hidden);
73
+ if (!readonly) {
74
+ runAfterRerender(() => {
75
+ var _a;
76
+ (_a = localRef.current) === null || _a === void 0 ? void 0 : _a.focus();
77
+ moveCursorToEnd(localRef.current);
78
+ });
79
+ }
80
+ }
81
+ });
49
82
  };
50
- const copyButtonSettings = useCopyButton({ copyButtonRef, showCopyButton, size, valueToCopy: value });
51
- const hideButtonSettings = useHideButton({ hideButtonRef, showHideButton, size, toggleHidden, hidden, disabled });
83
+ const copyButtonSettings = useCopyButton({
84
+ copyButtonRef,
85
+ showCopyButton,
86
+ size,
87
+ valueToCopy: value,
88
+ onDataRequest: handleDataRequest,
89
+ disabled: isLoading,
90
+ });
91
+ const hideButtonSettings = useHideButton({
92
+ hideButtonRef,
93
+ showHideButton,
94
+ size,
95
+ toggleHidden,
96
+ hidden,
97
+ disabled: disabled || isLoading,
98
+ });
52
99
  const { buttons, inputTabIndex, onInputKeyDown } = useButtonNavigation({
53
100
  inputRef: localRef,
54
101
  buttons: useMemo(() => [copyButtonSettings, hideButtonSettings], [copyButtonSettings, hideButtonSettings]),
55
102
  readonly,
56
103
  submitKeys: ['Enter', 'Space', 'Tab'],
57
104
  });
58
- return (_jsx(FieldDecorator, Object.assign({ className: className, label: label, labelTooltip: labelTooltip, labelTooltipPlacement: labelTooltipPlacement, labelFor: id, required: required, length: maxLength ? { max: maxLength, current: value.length } : undefined, hint: hint, disabled: disabled, readonly: readonly, showHintIcon: showHintIcon, size: size, error: error, validationState: fieldValidationState }, extractSupportProps(rest), { children: _jsx(FieldContainerPrivate, { size: size, validationState: fieldValidationState, disabled: disabled, readonly: readonly, variant: CONTAINER_VARIANT.SingleLine, inputRef: localRef, prefix: prefixIcon, postfix: buttons, children: _jsx(InputPrivate, { ref: mergeRefs(ref, localRef), "data-size": size, value: value, onChange: onChange, onFocus: onFocus, onBlur: onBlur, onKeyDown: onInputKeyDown, tabIndex: inputTabIndex, placeholder: placeholder, disabled: disabled, readonly: readonly, type: hidden ? 'password' : 'text', maxLength: allowMoreThanMaxLength ? undefined : maxLength || undefined, id: id, name: name, "data-test-id": 'field-secure__input' }) }) })));
105
+ return (_jsx(FieldDecorator, Object.assign({ className: className, label: label, labelTooltip: labelTooltip, labelTooltipPlacement: labelTooltipPlacement, labelFor: id, required: required, length: maxLength ? { max: maxLength, current: value.length } : undefined, hint: hint, disabled: disabled, readonly: readonly, showHintIcon: showHintIcon, size: size, error: error, validationState: fieldValidationState }, extractSupportProps(rest), { children: _jsx(FieldContainerPrivate, { size: size, validationState: fieldValidationState, disabled: disabled, readonly: readonly, variant: CONTAINER_VARIANT.SingleLine, inputRef: localRef, prefix: prefixIcon, postfix: buttons, children: _jsx(WithSkeleton, { skeleton: _jsx(Skeleton, { width: '100%', borderRadius: 2 }), loading: isLoading, children: _jsx(InputPrivate, { ref: mergeRefs(ref, localRef), "data-size": size, value: value, onChange: onChange, onFocus: onFocus, onBlur: onBlur, onKeyDown: onInputKeyDown, tabIndex: inputTabIndex, placeholder: placeholder, disabled: disabled, readonly: readonly, type: hidden ? 'password' : 'text', maxLength: allowMoreThanMaxLength ? undefined : maxLength || undefined, id: id, name: name, "data-test-id": 'field-secure__input' }) }) }) })));
59
106
  });
@@ -9,8 +9,8 @@ export declare const FieldSelectMultiple: import("react").ForwardRefExoticCompon
9
9
  'data-test-id'?: string | undefined;
10
10
  } & import("react").AriaAttributes & {
11
11
  options: import("./types").OptionProps[];
12
- pinTop: import("./types").OptionProps[];
13
- pinBottom: import("./types").OptionProps[];
12
+ pinTop?: import("./types").OptionProps[] | undefined;
13
+ pinBottom?: import("./types").OptionProps[] | undefined;
14
14
  searchable?: boolean | undefined;
15
15
  showCopyButton?: boolean | undefined;
16
16
  showClearButton?: boolean | undefined;
@@ -7,8 +7,8 @@ export declare const FieldSelectSingle: import("react").ForwardRefExoticComponen
7
7
  'data-test-id'?: string | undefined;
8
8
  } & import("react").AriaAttributes & {
9
9
  options: import("./types").OptionProps[];
10
- pinTop: import("./types").OptionProps[];
11
- pinBottom: import("./types").OptionProps[];
10
+ pinTop?: import("./types").OptionProps[] | undefined;
11
+ pinBottom?: import("./types").OptionProps[] | undefined;
12
12
  searchable?: boolean | undefined;
13
13
  showCopyButton?: boolean | undefined;
14
14
  showClearButton?: boolean | undefined;
@@ -37,8 +37,8 @@ export type FieldSelectPrivateProps = InputProps & WrapperProps & {
37
37
  };
38
38
  type FiledSelectCommonProps = WithSupportProps<{
39
39
  options: OptionProps[];
40
- pinTop: OptionProps[];
41
- pinBottom: OptionProps[];
40
+ pinTop?: OptionProps[];
41
+ pinBottom?: OptionProps[];
42
42
  searchable?: boolean;
43
43
  /** Отображение кнопки Копировать для поля (актуально только для `readonly = true`) */
44
44
  showCopyButton?: boolean;
@@ -6,6 +6,8 @@ type ButtonCopyValueProps = {
6
6
  onKeyDown?: KeyboardEventHandler<HTMLButtonElement>;
7
7
  onClick?: MouseEventHandler<HTMLButtonElement>;
8
8
  tabIndex?: number;
9
+ onDataRequest?(): Promise<boolean>;
10
+ disabled?: boolean;
9
11
  };
10
12
  export declare const ButtonCopyValue: import("react").ForwardRefExoticComponent<ButtonCopyValueProps & import("react").RefAttributes<HTMLButtonElement>>;
11
13
  export {};
@@ -3,22 +3,34 @@ import copyToClipboard from 'copy-to-clipboard';
3
3
  import { forwardRef, useEffect, useRef, useState } from 'react';
4
4
  import { getIcon } from './helpers';
5
5
  import styles from './styles.module.css';
6
- export const ButtonCopyValue = forwardRef(({ size, valueToCopy, tabIndex = -1, onKeyDown, onClick }, ref) => {
6
+ export const ButtonCopyValue = forwardRef(({ size, valueToCopy, tabIndex = -1, onKeyDown, onClick, onDataRequest, disabled }, ref) => {
7
7
  const [isChecked, setIsChecked] = useState(false);
8
8
  const timerId = useRef();
9
9
  const openTooltip = () => setIsChecked(true);
10
10
  const closeTooltip = () => setIsChecked(false);
11
11
  const handleClick = event => {
12
+ const handleCopy = () => {
13
+ valueToCopy && copyToClipboard(valueToCopy, { format: 'text/plain' });
14
+ openTooltip();
15
+ clearTimeout(timerId.current);
16
+ timerId.current = setTimeout(closeTooltip, 2000);
17
+ onClick === null || onClick === void 0 ? void 0 : onClick(event);
18
+ };
12
19
  event.stopPropagation();
13
- valueToCopy && copyToClipboard(valueToCopy, { format: 'text/plain' });
14
- openTooltip();
15
- clearTimeout(timerId.current);
16
- timerId.current = setTimeout(closeTooltip, 2000);
17
- onClick === null || onClick === void 0 ? void 0 : onClick(event);
20
+ if (onDataRequest) {
21
+ onDataRequest().then(isSuccess => {
22
+ if (isSuccess) {
23
+ handleCopy();
24
+ }
25
+ });
26
+ }
27
+ else {
28
+ handleCopy();
29
+ }
18
30
  };
19
31
  useEffect(() => () => {
20
32
  closeTooltip();
21
33
  clearTimeout(timerId.current);
22
34
  }, []);
23
- return (_jsx("button", { className: styles.buttonCopyValue, "data-size": size, onClick: handleClick, "data-test-id": 'button-copy-value', ref: ref, onKeyDown: onKeyDown, tabIndex: tabIndex, type: 'button', children: getIcon({ size, isChecked }) }));
35
+ return (_jsx("button", { className: styles.buttonCopyValue, "data-size": size, "data-disabled": disabled || undefined, onClick: handleClick, "data-test-id": 'button-copy-value', ref: ref, onKeyDown: onKeyDown, tabIndex: tabIndex, type: 'button', disabled: disabled, children: getIcon({ size, isChecked }) }));
24
36
  });
@@ -5,6 +5,8 @@ type UseCopyButtonProps = {
5
5
  showCopyButton: boolean;
6
6
  valueToCopy: string;
7
7
  size: Size;
8
+ onDataRequest?(): Promise<boolean>;
9
+ disabled?: boolean;
8
10
  };
9
- export declare function useCopyButton({ copyButtonRef, showCopyButton, size, valueToCopy }: UseCopyButtonProps): ButtonProps;
11
+ export declare function useCopyButton({ copyButtonRef, showCopyButton, size, valueToCopy, onDataRequest, disabled, }: UseCopyButtonProps): ButtonProps;
10
12
  export {};
@@ -2,11 +2,11 @@ import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { useMemo } from 'react';
3
3
  import { BUTTON_SIZE_MAP } from '@snack-uikit/input-private';
4
4
  import { ButtonCopyValue } from '../helperComponents';
5
- export function useCopyButton({ copyButtonRef, showCopyButton, size, valueToCopy }) {
5
+ export function useCopyButton({ copyButtonRef, showCopyButton, size, valueToCopy, onDataRequest, disabled, }) {
6
6
  return useMemo(() => ({
7
7
  id: 'copy',
8
8
  ref: copyButtonRef,
9
9
  show: showCopyButton,
10
- render: props => _jsx(ButtonCopyValue, Object.assign({}, props, { size: BUTTON_SIZE_MAP[size], valueToCopy: valueToCopy })),
11
- }), [copyButtonRef, showCopyButton, size, valueToCopy]);
10
+ render: props => (_jsx(ButtonCopyValue, Object.assign({}, props, { size: BUTTON_SIZE_MAP[size], valueToCopy: valueToCopy, onDataRequest: onDataRequest, disabled: disabled }))),
11
+ }), [copyButtonRef, disabled, onDataRequest, showCopyButton, size, valueToCopy]);
12
12
  }
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "access": "public"
5
5
  },
6
6
  "title": "Fields",
7
- "version": "0.19.1",
7
+ "version": "0.19.3-preview-34ffedb5.0",
8
8
  "sideEffects": [
9
9
  "*.css",
10
10
  "*.woff",
@@ -33,12 +33,13 @@
33
33
  "scripts": {},
34
34
  "dependencies": {
35
35
  "@snack-uikit/button": "0.17.1",
36
- "@snack-uikit/calendar": "0.7.7",
36
+ "@snack-uikit/calendar": "0.7.8",
37
37
  "@snack-uikit/dropdown": "0.2.2",
38
38
  "@snack-uikit/icons": "0.20.1",
39
39
  "@snack-uikit/input-private": "3.1.2",
40
- "@snack-uikit/list": "0.11.1",
40
+ "@snack-uikit/list": "0.11.2",
41
41
  "@snack-uikit/scroll": "0.5.3",
42
+ "@snack-uikit/skeleton": "0.3.4",
42
43
  "@snack-uikit/slider": "0.1.9",
43
44
  "@snack-uikit/tag": "0.9.1",
44
45
  "@snack-uikit/tooltip": "0.13.2",
@@ -58,5 +59,5 @@
58
59
  "peerDependencies": {
59
60
  "@snack-uikit/locale": "*"
60
61
  },
61
- "gitHead": "06a0c7c3a2f092971d66bead5e89f74f4befee4b"
62
+ "gitHead": "7c21433a0f290c78176650374b137e2abafced96"
62
63
  }
@@ -1,5 +1,5 @@
1
1
  import mergeRefs from 'merge-refs';
2
- import { forwardRef, ReactElement, useMemo, useRef } from 'react';
2
+ import { forwardRef, ReactElement, useMemo, useRef, useState } from 'react';
3
3
 
4
4
  import {
5
5
  InputPrivate,
@@ -9,6 +9,7 @@ import {
9
9
  SIZE,
10
10
  useButtonNavigation,
11
11
  } from '@snack-uikit/input-private';
12
+ import { Skeleton, WithSkeleton } from '@snack-uikit/skeleton';
12
13
  import { extractSupportProps, WithSupportProps } from '@snack-uikit/utils';
13
14
 
14
15
  import { CONTAINER_VARIANT, VALIDATION_STATE } from '../../constants';
@@ -45,6 +46,8 @@ type FieldSecureOwnProps = {
45
46
  allowMoreThanMaxLength?: boolean;
46
47
  /** Иконка-префикс для поля */
47
48
  prefixIcon?: ReactElement;
49
+ /** Свойство позволяет грузить данные в поле по требованию */
50
+ onDataRequest?(): Promise<void>;
48
51
  };
49
52
 
50
53
  export type FieldSecureProps = WithSupportProps<FieldSecureOwnProps & InputProps & WrapperProps>;
@@ -77,6 +80,7 @@ export const FieldSecure = forwardRef<HTMLInputElement, FieldSecureProps>(
77
80
  validationState = VALIDATION_STATE.Default,
78
81
  prefixIcon,
79
82
  error,
83
+ onDataRequest,
80
84
  ...rest
81
85
  },
82
86
  ref,
@@ -84,6 +88,8 @@ export const FieldSecure = forwardRef<HTMLInputElement, FieldSecureProps>(
84
88
  const localRef = useRef<HTMLInputElement>(null);
85
89
  const copyButtonRef = useRef<HTMLButtonElement>(null);
86
90
  const hideButtonRef = useRef<HTMLButtonElement>(null);
91
+ const [isDataRequested, setIsDataRequested] = useState(false);
92
+ const [isLoading, setIsLoading] = useState(false);
87
93
  const [value = '', onChange] = useValueControl<string>({
88
94
  value: valueProp,
89
95
  defaultValue: '',
@@ -99,19 +105,55 @@ export const FieldSecure = forwardRef<HTMLInputElement, FieldSecureProps>(
99
105
 
100
106
  const fieldValidationState = getValidationState({ validationState, error });
101
107
 
102
- const toggleHidden = () => {
103
- setHidden(!hidden);
108
+ const handleDataRequest = async (): Promise<boolean> => {
109
+ if (!isDataRequested && onDataRequest) {
110
+ setIsLoading(true);
104
111
 
105
- if (!readonly) {
106
- runAfterRerender(() => {
107
- localRef.current?.focus();
108
- moveCursorToEnd(localRef.current);
109
- });
112
+ try {
113
+ await onDataRequest();
114
+ setIsDataRequested(true);
115
+ return true;
116
+ } catch (e) {
117
+ return false;
118
+ } finally {
119
+ setIsLoading(false);
120
+ }
110
121
  }
122
+
123
+ return true;
124
+ };
125
+
126
+ const toggleHidden = () => {
127
+ handleDataRequest().then(isSuccess => {
128
+ if (isSuccess) {
129
+ setHidden(!hidden);
130
+
131
+ if (!readonly) {
132
+ runAfterRerender(() => {
133
+ localRef.current?.focus();
134
+ moveCursorToEnd(localRef.current);
135
+ });
136
+ }
137
+ }
138
+ });
111
139
  };
112
140
 
113
- const copyButtonSettings = useCopyButton({ copyButtonRef, showCopyButton, size, valueToCopy: value });
114
- const hideButtonSettings = useHideButton({ hideButtonRef, showHideButton, size, toggleHidden, hidden, disabled });
141
+ const copyButtonSettings = useCopyButton({
142
+ copyButtonRef,
143
+ showCopyButton,
144
+ size,
145
+ valueToCopy: value,
146
+ onDataRequest: handleDataRequest,
147
+ disabled: isLoading,
148
+ });
149
+ const hideButtonSettings = useHideButton({
150
+ hideButtonRef,
151
+ showHideButton,
152
+ size,
153
+ toggleHidden,
154
+ hidden,
155
+ disabled: disabled || isLoading,
156
+ });
115
157
  const { buttons, inputTabIndex, onInputKeyDown } = useButtonNavigation({
116
158
  inputRef: localRef,
117
159
  buttons: useMemo(() => [copyButtonSettings, hideButtonSettings], [copyButtonSettings, hideButtonSettings]),
@@ -147,24 +189,26 @@ export const FieldSecure = forwardRef<HTMLInputElement, FieldSecureProps>(
147
189
  prefix={prefixIcon}
148
190
  postfix={buttons}
149
191
  >
150
- <InputPrivate
151
- ref={mergeRefs(ref, localRef)}
152
- data-size={size}
153
- value={value}
154
- onChange={onChange}
155
- onFocus={onFocus}
156
- onBlur={onBlur}
157
- onKeyDown={onInputKeyDown}
158
- tabIndex={inputTabIndex}
159
- placeholder={placeholder}
160
- disabled={disabled}
161
- readonly={readonly}
162
- type={hidden ? 'password' : 'text'}
163
- maxLength={allowMoreThanMaxLength ? undefined : maxLength || undefined}
164
- id={id}
165
- name={name}
166
- data-test-id='field-secure__input'
167
- />
192
+ <WithSkeleton skeleton={<Skeleton width='100%' borderRadius={2} />} loading={isLoading}>
193
+ <InputPrivate
194
+ ref={mergeRefs(ref, localRef)}
195
+ data-size={size}
196
+ value={value}
197
+ onChange={onChange}
198
+ onFocus={onFocus}
199
+ onBlur={onBlur}
200
+ onKeyDown={onInputKeyDown}
201
+ tabIndex={inputTabIndex}
202
+ placeholder={placeholder}
203
+ disabled={disabled}
204
+ readonly={readonly}
205
+ type={hidden ? 'password' : 'text'}
206
+ maxLength={allowMoreThanMaxLength ? undefined : maxLength || undefined}
207
+ id={id}
208
+ name={name}
209
+ data-test-id='field-secure__input'
210
+ />
211
+ </WithSkeleton>
168
212
  </FieldContainerPrivate>
169
213
  </FieldDecorator>
170
214
  );
@@ -83,8 +83,8 @@ export type FieldSelectPrivateProps = InputProps & WrapperProps & { options: Opt
83
83
  type FiledSelectCommonProps = WithSupportProps<{
84
84
  options: OptionProps[];
85
85
 
86
- pinTop: OptionProps[];
87
- pinBottom: OptionProps[];
86
+ pinTop?: OptionProps[];
87
+ pinBottom?: OptionProps[];
88
88
 
89
89
  searchable?: boolean;
90
90
  /** Отображение кнопки Копировать для поля (актуально только для `readonly = true`) */
@@ -12,21 +12,36 @@ type ButtonCopyValueProps = {
12
12
  onKeyDown?: KeyboardEventHandler<HTMLButtonElement>;
13
13
  onClick?: MouseEventHandler<HTMLButtonElement>;
14
14
  tabIndex?: number;
15
+ onDataRequest?(): Promise<boolean>;
16
+ disabled?: boolean;
15
17
  };
16
18
  export const ButtonCopyValue = forwardRef<HTMLButtonElement, ButtonCopyValueProps>(
17
- ({ size, valueToCopy, tabIndex = -1, onKeyDown, onClick }, ref) => {
19
+ ({ size, valueToCopy, tabIndex = -1, onKeyDown, onClick, onDataRequest, disabled }, ref) => {
18
20
  const [isChecked, setIsChecked] = useState(false);
19
21
  const timerId = useRef<ReturnType<typeof setTimeout>>();
20
22
  const openTooltip = () => setIsChecked(true);
21
23
  const closeTooltip = () => setIsChecked(false);
22
24
 
23
25
  const handleClick: MouseEventHandler<HTMLButtonElement> = event => {
26
+ const handleCopy = () => {
27
+ valueToCopy && copyToClipboard(valueToCopy, { format: 'text/plain' });
28
+ openTooltip();
29
+ clearTimeout(timerId.current);
30
+ timerId.current = setTimeout(closeTooltip, 2000);
31
+ onClick?.(event);
32
+ };
33
+
24
34
  event.stopPropagation();
25
- valueToCopy && copyToClipboard(valueToCopy, { format: 'text/plain' });
26
- openTooltip();
27
- clearTimeout(timerId.current);
28
- timerId.current = setTimeout(closeTooltip, 2000);
29
- onClick?.(event);
35
+
36
+ if (onDataRequest) {
37
+ onDataRequest().then(isSuccess => {
38
+ if (isSuccess) {
39
+ handleCopy();
40
+ }
41
+ });
42
+ } else {
43
+ handleCopy();
44
+ }
30
45
  };
31
46
 
32
47
  useEffect(
@@ -41,12 +56,14 @@ export const ButtonCopyValue = forwardRef<HTMLButtonElement, ButtonCopyValueProp
41
56
  <button
42
57
  className={styles.buttonCopyValue}
43
58
  data-size={size}
59
+ data-disabled={disabled || undefined}
44
60
  onClick={handleClick}
45
61
  data-test-id='button-copy-value'
46
62
  ref={ref}
47
63
  onKeyDown={onKeyDown}
48
64
  tabIndex={tabIndex}
49
65
  type='button'
66
+ disabled={disabled}
50
67
  >
51
68
  {getIcon({ size, isChecked })}
52
69
  </button>
@@ -9,16 +9,33 @@ type UseCopyButtonProps = {
9
9
  showCopyButton: boolean;
10
10
  valueToCopy: string;
11
11
  size: Size;
12
+ onDataRequest?(): Promise<boolean>;
13
+ disabled?: boolean;
12
14
  };
13
15
 
14
- export function useCopyButton({ copyButtonRef, showCopyButton, size, valueToCopy }: UseCopyButtonProps): ButtonProps {
16
+ export function useCopyButton({
17
+ copyButtonRef,
18
+ showCopyButton,
19
+ size,
20
+ valueToCopy,
21
+ onDataRequest,
22
+ disabled,
23
+ }: UseCopyButtonProps): ButtonProps {
15
24
  return useMemo(
16
25
  () => ({
17
26
  id: 'copy',
18
27
  ref: copyButtonRef,
19
28
  show: showCopyButton,
20
- render: props => <ButtonCopyValue {...props} size={BUTTON_SIZE_MAP[size]} valueToCopy={valueToCopy} />,
29
+ render: props => (
30
+ <ButtonCopyValue
31
+ {...props}
32
+ size={BUTTON_SIZE_MAP[size]}
33
+ valueToCopy={valueToCopy}
34
+ onDataRequest={onDataRequest}
35
+ disabled={disabled}
36
+ />
37
+ ),
21
38
  }),
22
- [copyButtonRef, showCopyButton, size, valueToCopy],
39
+ [copyButtonRef, disabled, onDataRequest, showCopyButton, size, valueToCopy],
23
40
  );
24
41
  }