@snack-uikit/fields 0.19.3-preview-34ffedb5.0 → 0.20.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 +16 -0
- package/README.md +1 -1
- package/dist/components/FieldSecure/FieldSecure.d.ts +1 -1
- package/dist/components/FieldSecure/FieldSecure.js +18 -10
- package/dist/components/FieldSelect/FieldSelectMultiple.js +1 -1
- package/dist/helperComponents/ButtonCopyValue/ButtonCopyValue.d.ts +2 -1
- package/dist/helperComponents/ButtonCopyValue/ButtonCopyValue.js +14 -14
- package/dist/hooks/useCopyButton.d.ts +3 -2
- package/dist/hooks/useCopyButton.js +3 -3
- package/dist/types.d.ts +4 -0
- package/package.json +2 -2
- package/src/components/FieldSecure/FieldSecure.tsx +28 -11
- package/src/components/FieldSelect/FieldSelectMultiple.tsx +1 -1
- package/src/helperComponents/ButtonCopyValue/ButtonCopyValue.tsx +24 -17
- package/src/hooks/useCopyButton.tsx +5 -4
- package/src/types.ts +2 -0
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,22 @@
|
|
|
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.20.0 (2024-04-26)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Bug Fixes
|
|
10
|
+
|
|
11
|
+
* **FF-4714:** remove nonexistent classname ([e45ee61](https://github.com/cloud-ru-tech/snack-uikit/commit/e45ee611a4c0ed5038dc4d7e0058c7719232d747))
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
### Features
|
|
15
|
+
|
|
16
|
+
* **FF-4714:** add asyncValueGetter property ([2267477](https://github.com/cloud-ru-tech/snack-uikit/commit/22674774d3845c3cc77369b153afb3c9e13e5e0d))
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
|
|
6
22
|
## 0.19.2 (2024-04-25)
|
|
7
23
|
|
|
8
24
|
|
package/README.md
CHANGED
|
@@ -252,7 +252,7 @@ const [isOpen, setIsOpen] = useState(false);
|
|
|
252
252
|
| showCopyButton | `boolean` | - | Отображение кнопки копирования |
|
|
253
253
|
| allowMoreThanMaxLength | `boolean` | - | Можно ли вводить больше разрешённого кол-ва символов |
|
|
254
254
|
| prefixIcon | `ReactElement<any, string \| JSXElementConstructor<any>>` | - | Иконка-префикс для поля |
|
|
255
|
-
|
|
|
255
|
+
| asyncValueGetter | `() => Promise<string>` | - | Свойство позволяет грузить данные в поле по требованию |
|
|
256
256
|
| value | `string` | - | Значение input |
|
|
257
257
|
| onChange | `(value: string, e?: ChangeEvent<HTMLInputElement>) => void` | - | Колбек смены значения |
|
|
258
258
|
| disabled | `boolean` | - | Является ли поле деактивированным |
|
|
@@ -16,7 +16,7 @@ type FieldSecureOwnProps = {
|
|
|
16
16
|
/** Иконка-префикс для поля */
|
|
17
17
|
prefixIcon?: ReactElement;
|
|
18
18
|
/** Свойство позволяет грузить данные в поле по требованию */
|
|
19
|
-
|
|
19
|
+
asyncValueGetter?(): Promise<string>;
|
|
20
20
|
};
|
|
21
21
|
export type FieldSecureProps = WithSupportProps<FieldSecureOwnProps & InputProps & WrapperProps>;
|
|
22
22
|
export declare const FieldSecure: import("react").ForwardRefExoticComponent<{
|
|
@@ -30,7 +30,7 @@ import { useCopyButton, useHideButton, useValueControl } from '../../hooks';
|
|
|
30
30
|
import { getValidationState } from '../../utils/getValidationState';
|
|
31
31
|
import { FieldDecorator } from '../FieldDecorator';
|
|
32
32
|
export const FieldSecure = forwardRef((_a, ref) => {
|
|
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,
|
|
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, asyncValueGetter } = _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", "asyncValueGetter"]);
|
|
34
34
|
const localRef = useRef(null);
|
|
35
35
|
const copyButtonRef = useRef(null);
|
|
36
36
|
const hideButtonRef = useRef(null);
|
|
@@ -49,26 +49,34 @@ export const FieldSecure = forwardRef((_a, ref) => {
|
|
|
49
49
|
const showCopyButton = showCopyButtonProp && Boolean(value) && readonly && !disabled;
|
|
50
50
|
const showHideButton = !(readonly && !value);
|
|
51
51
|
const fieldValidationState = getValidationState({ validationState, error });
|
|
52
|
-
const
|
|
53
|
-
if (!isDataRequested &&
|
|
52
|
+
const getAsyncValue = () => __awaiter(void 0, void 0, void 0, function* () {
|
|
53
|
+
if (!isDataRequested && asyncValueGetter) {
|
|
54
54
|
setIsLoading(true);
|
|
55
55
|
try {
|
|
56
|
-
yield
|
|
56
|
+
const asyncValue = yield asyncValueGetter();
|
|
57
57
|
setIsDataRequested(true);
|
|
58
|
-
|
|
58
|
+
onChange(asyncValue);
|
|
59
|
+
return {
|
|
60
|
+
success: true,
|
|
61
|
+
value: asyncValue,
|
|
62
|
+
};
|
|
59
63
|
}
|
|
60
64
|
catch (e) {
|
|
61
|
-
return
|
|
65
|
+
return {
|
|
66
|
+
success: false,
|
|
67
|
+
};
|
|
62
68
|
}
|
|
63
69
|
finally {
|
|
64
70
|
setIsLoading(false);
|
|
65
71
|
}
|
|
66
72
|
}
|
|
67
|
-
return
|
|
73
|
+
return {
|
|
74
|
+
success: true,
|
|
75
|
+
};
|
|
68
76
|
});
|
|
69
77
|
const toggleHidden = () => {
|
|
70
|
-
|
|
71
|
-
if (
|
|
78
|
+
getAsyncValue().then(({ success }) => {
|
|
79
|
+
if (success) {
|
|
72
80
|
setHidden(!hidden);
|
|
73
81
|
if (!readonly) {
|
|
74
82
|
runAfterRerender(() => {
|
|
@@ -85,7 +93,7 @@ export const FieldSecure = forwardRef((_a, ref) => {
|
|
|
85
93
|
showCopyButton,
|
|
86
94
|
size,
|
|
87
95
|
valueToCopy: value,
|
|
88
|
-
|
|
96
|
+
onValueRequest: getAsyncValue,
|
|
89
97
|
disabled: isLoading,
|
|
90
98
|
});
|
|
91
99
|
const hideButtonSettings = useHideButton({
|
|
@@ -134,7 +134,7 @@ export const FieldSelectMultiple = forwardRef((_a, ref) => {
|
|
|
134
134
|
minWidth: value
|
|
135
135
|
? Math.min((_b = (_a = contentRef.current) === null || _a === void 0 ? void 0 : _a.clientWidth) !== null && _b !== void 0 ? _b : BASE_MIN_WIDTH, (_d = (_c = inputPlugRef.current) === null || _c === void 0 ? void 0 : _c.clientWidth) !== null && _d !== void 0 ? _d : BASE_MIN_WIDTH)
|
|
136
136
|
: '100%',
|
|
137
|
-
}, children: _jsx(InputPrivate, { id: id, name: name, type: 'text', disabled: disabled, placeholder: !selectedItems || !selectedItems.length ? placeholder : undefined, ref: mergeRefs(ref, localRef), onChange: searchable ? setInputValue : undefined, value: searchable ? inputValue : '', readonly: !searchable || readonly, "data-test-id": 'field-select__input', onKeyDown: handleOnKeyDown(onKeyDown), onBlur: handleBlur, className: cn(
|
|
137
|
+
}, children: _jsx(InputPrivate, { id: id, name: name, type: 'text', disabled: disabled, placeholder: !selectedItems || !selectedItems.length ? placeholder : undefined, ref: mergeRefs(ref, localRef), onChange: searchable ? setInputValue : undefined, value: searchable ? inputValue : '', readonly: !searchable || readonly, "data-test-id": 'field-select__input', onKeyDown: handleOnKeyDown(onKeyDown), onBlur: handleBlur, className: cn({
|
|
138
138
|
[styles.readonlyCursor]: !searchable,
|
|
139
139
|
}) }) })] }), _jsxs("div", { className: styles.postfix, children: [buttons, _jsx(ArrowIcon, { size: arrowIconSize, className: styles.arrowIcon })] }), _jsx("span", { ref: inputPlugRef, className: styles.inputPlug, children: inputValue })] }) }));
|
|
140
140
|
} })) })));
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { KeyboardEventHandler, MouseEventHandler } from 'react';
|
|
2
2
|
import { ButtonSize } from '@snack-uikit/input-private';
|
|
3
|
+
import { AsyncValueRequest } from '../../types';
|
|
3
4
|
type ButtonCopyValueProps = {
|
|
4
5
|
size: ButtonSize;
|
|
5
6
|
valueToCopy?: string;
|
|
6
7
|
onKeyDown?: KeyboardEventHandler<HTMLButtonElement>;
|
|
7
8
|
onClick?: MouseEventHandler<HTMLButtonElement>;
|
|
8
9
|
tabIndex?: number;
|
|
9
|
-
|
|
10
|
+
onValueRequest?(): AsyncValueRequest;
|
|
10
11
|
disabled?: boolean;
|
|
11
12
|
};
|
|
12
13
|
export declare const ButtonCopyValue: import("react").ForwardRefExoticComponent<ButtonCopyValueProps & import("react").RefAttributes<HTMLButtonElement>>;
|
|
@@ -3,29 +3,29 @@ 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,
|
|
6
|
+
export const ButtonCopyValue = forwardRef(({ size, valueToCopy, tabIndex = -1, onKeyDown, onClick, onValueRequest, disabled }, ref) => {
|
|
7
7
|
const [isChecked, setIsChecked] = useState(false);
|
|
8
8
|
const timerId = useRef();
|
|
9
|
-
const openTooltip = () => setIsChecked(true);
|
|
10
9
|
const closeTooltip = () => setIsChecked(false);
|
|
10
|
+
const handleCopy = (event, asyncValue) => {
|
|
11
|
+
const value = asyncValue || valueToCopy;
|
|
12
|
+
value && copyToClipboard(value, { format: 'text/plain' });
|
|
13
|
+
setIsChecked(true);
|
|
14
|
+
clearTimeout(timerId.current);
|
|
15
|
+
timerId.current = setTimeout(closeTooltip, 2000);
|
|
16
|
+
onClick === null || onClick === void 0 ? void 0 : onClick(event);
|
|
17
|
+
};
|
|
11
18
|
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
|
-
};
|
|
19
19
|
event.stopPropagation();
|
|
20
|
-
if (
|
|
21
|
-
|
|
22
|
-
if (
|
|
23
|
-
handleCopy();
|
|
20
|
+
if (onValueRequest) {
|
|
21
|
+
onValueRequest().then(({ success, value }) => {
|
|
22
|
+
if (success) {
|
|
23
|
+
handleCopy(event, value);
|
|
24
24
|
}
|
|
25
25
|
});
|
|
26
26
|
}
|
|
27
27
|
else {
|
|
28
|
-
handleCopy();
|
|
28
|
+
handleCopy(event);
|
|
29
29
|
}
|
|
30
30
|
};
|
|
31
31
|
useEffect(() => () => {
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { RefObject } from 'react';
|
|
2
2
|
import { ButtonProps, Size } from '@snack-uikit/input-private';
|
|
3
|
+
import { AsyncValueRequest } from '../types';
|
|
3
4
|
type UseCopyButtonProps = {
|
|
4
5
|
copyButtonRef: RefObject<HTMLButtonElement>;
|
|
5
6
|
showCopyButton: boolean;
|
|
6
7
|
valueToCopy: string;
|
|
7
8
|
size: Size;
|
|
8
|
-
|
|
9
|
+
onValueRequest?(): AsyncValueRequest;
|
|
9
10
|
disabled?: boolean;
|
|
10
11
|
};
|
|
11
|
-
export declare function useCopyButton({ copyButtonRef, showCopyButton, size, valueToCopy,
|
|
12
|
+
export declare function useCopyButton({ copyButtonRef, showCopyButton, size, valueToCopy, onValueRequest, disabled, }: UseCopyButtonProps): ButtonProps;
|
|
12
13
|
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, onValueRequest, 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, disabled,
|
|
10
|
+
render: props => (_jsx(ButtonCopyValue, Object.assign({}, props, { size: BUTTON_SIZE_MAP[size], valueToCopy: valueToCopy, onValueRequest: onValueRequest, disabled: disabled }))),
|
|
11
|
+
}), [copyButtonRef, disabled, onValueRequest, showCopyButton, size, valueToCopy]);
|
|
12
12
|
}
|
package/dist/types.d.ts
CHANGED
|
@@ -2,3 +2,7 @@ import { ValueOf } from '@snack-uikit/utils';
|
|
|
2
2
|
import { CONTAINER_VARIANT, VALIDATION_STATE } from './constants';
|
|
3
3
|
export type ValidationState = ValueOf<typeof VALIDATION_STATE>;
|
|
4
4
|
export type ContainerVariant = ValueOf<typeof CONTAINER_VARIANT>;
|
|
5
|
+
export type AsyncValueRequest = Promise<{
|
|
6
|
+
success: boolean;
|
|
7
|
+
value?: string;
|
|
8
|
+
}>;
|
package/package.json
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
6
|
"title": "Fields",
|
|
7
|
-
"version": "0.
|
|
7
|
+
"version": "0.20.0",
|
|
8
8
|
"sideEffects": [
|
|
9
9
|
"*.css",
|
|
10
10
|
"*.woff",
|
|
@@ -59,5 +59,5 @@
|
|
|
59
59
|
"peerDependencies": {
|
|
60
60
|
"@snack-uikit/locale": "*"
|
|
61
61
|
},
|
|
62
|
-
"gitHead": "
|
|
62
|
+
"gitHead": "b6f9b6606011158a035e9e49ef8df194e74bf070"
|
|
63
63
|
}
|
|
@@ -15,6 +15,7 @@ import { extractSupportProps, WithSupportProps } from '@snack-uikit/utils';
|
|
|
15
15
|
import { CONTAINER_VARIANT, VALIDATION_STATE } from '../../constants';
|
|
16
16
|
import { FieldContainerPrivate } from '../../helperComponents';
|
|
17
17
|
import { useCopyButton, useHideButton, useValueControl } from '../../hooks';
|
|
18
|
+
import { AsyncValueRequest } from '../../types';
|
|
18
19
|
import { getValidationState } from '../../utils/getValidationState';
|
|
19
20
|
import { FieldDecorator, FieldDecoratorProps } from '../FieldDecorator';
|
|
20
21
|
|
|
@@ -47,7 +48,7 @@ type FieldSecureOwnProps = {
|
|
|
47
48
|
/** Иконка-префикс для поля */
|
|
48
49
|
prefixIcon?: ReactElement;
|
|
49
50
|
/** Свойство позволяет грузить данные в поле по требованию */
|
|
50
|
-
|
|
51
|
+
asyncValueGetter?(): Promise<string>;
|
|
51
52
|
};
|
|
52
53
|
|
|
53
54
|
export type FieldSecureProps = WithSupportProps<FieldSecureOwnProps & InputProps & WrapperProps>;
|
|
@@ -80,7 +81,7 @@ export const FieldSecure = forwardRef<HTMLInputElement, FieldSecureProps>(
|
|
|
80
81
|
validationState = VALIDATION_STATE.Default,
|
|
81
82
|
prefixIcon,
|
|
82
83
|
error,
|
|
83
|
-
|
|
84
|
+
asyncValueGetter,
|
|
84
85
|
...rest
|
|
85
86
|
},
|
|
86
87
|
ref,
|
|
@@ -88,44 +89,58 @@ export const FieldSecure = forwardRef<HTMLInputElement, FieldSecureProps>(
|
|
|
88
89
|
const localRef = useRef<HTMLInputElement>(null);
|
|
89
90
|
const copyButtonRef = useRef<HTMLButtonElement>(null);
|
|
90
91
|
const hideButtonRef = useRef<HTMLButtonElement>(null);
|
|
92
|
+
|
|
91
93
|
const [isDataRequested, setIsDataRequested] = useState(false);
|
|
92
94
|
const [isLoading, setIsLoading] = useState(false);
|
|
95
|
+
|
|
93
96
|
const [value = '', onChange] = useValueControl<string>({
|
|
94
97
|
value: valueProp,
|
|
95
98
|
defaultValue: '',
|
|
96
99
|
onChange: onChangeProp,
|
|
97
100
|
});
|
|
101
|
+
|
|
98
102
|
const [hidden = true, setHidden] = useValueControl<boolean>({
|
|
99
103
|
value: hiddenProp,
|
|
100
104
|
defaultValue: true,
|
|
101
105
|
onChange: onHiddenChange,
|
|
102
106
|
});
|
|
107
|
+
|
|
103
108
|
const showCopyButton = showCopyButtonProp && Boolean(value) && readonly && !disabled;
|
|
104
109
|
const showHideButton = !(readonly && !value);
|
|
105
110
|
|
|
106
111
|
const fieldValidationState = getValidationState({ validationState, error });
|
|
107
112
|
|
|
108
|
-
const
|
|
109
|
-
if (!isDataRequested &&
|
|
113
|
+
const getAsyncValue = async (): AsyncValueRequest => {
|
|
114
|
+
if (!isDataRequested && asyncValueGetter) {
|
|
110
115
|
setIsLoading(true);
|
|
111
116
|
|
|
112
117
|
try {
|
|
113
|
-
await
|
|
118
|
+
const asyncValue = await asyncValueGetter();
|
|
119
|
+
|
|
114
120
|
setIsDataRequested(true);
|
|
115
|
-
|
|
121
|
+
onChange(asyncValue);
|
|
122
|
+
|
|
123
|
+
return {
|
|
124
|
+
success: true,
|
|
125
|
+
value: asyncValue,
|
|
126
|
+
};
|
|
116
127
|
} catch (e) {
|
|
117
|
-
return
|
|
128
|
+
return {
|
|
129
|
+
success: false,
|
|
130
|
+
};
|
|
118
131
|
} finally {
|
|
119
132
|
setIsLoading(false);
|
|
120
133
|
}
|
|
121
134
|
}
|
|
122
135
|
|
|
123
|
-
return
|
|
136
|
+
return {
|
|
137
|
+
success: true,
|
|
138
|
+
};
|
|
124
139
|
};
|
|
125
140
|
|
|
126
141
|
const toggleHidden = () => {
|
|
127
|
-
|
|
128
|
-
if (
|
|
142
|
+
getAsyncValue().then(({ success }) => {
|
|
143
|
+
if (success) {
|
|
129
144
|
setHidden(!hidden);
|
|
130
145
|
|
|
131
146
|
if (!readonly) {
|
|
@@ -143,9 +158,10 @@ export const FieldSecure = forwardRef<HTMLInputElement, FieldSecureProps>(
|
|
|
143
158
|
showCopyButton,
|
|
144
159
|
size,
|
|
145
160
|
valueToCopy: value,
|
|
146
|
-
|
|
161
|
+
onValueRequest: getAsyncValue,
|
|
147
162
|
disabled: isLoading,
|
|
148
163
|
});
|
|
164
|
+
|
|
149
165
|
const hideButtonSettings = useHideButton({
|
|
150
166
|
hideButtonRef,
|
|
151
167
|
showHideButton,
|
|
@@ -154,6 +170,7 @@ export const FieldSecure = forwardRef<HTMLInputElement, FieldSecureProps>(
|
|
|
154
170
|
hidden,
|
|
155
171
|
disabled: disabled || isLoading,
|
|
156
172
|
});
|
|
173
|
+
|
|
157
174
|
const { buttons, inputTabIndex, onInputKeyDown } = useButtonNavigation({
|
|
158
175
|
inputRef: localRef,
|
|
159
176
|
buttons: useMemo(() => [copyButtonSettings, hideButtonSettings], [copyButtonSettings, hideButtonSettings]),
|
|
@@ -242,7 +242,7 @@ export const FieldSelectMultiple = forwardRef<HTMLInputElement, FieldSelectMulti
|
|
|
242
242
|
data-test-id='field-select__input'
|
|
243
243
|
onKeyDown={handleOnKeyDown(onKeyDown)}
|
|
244
244
|
onBlur={handleBlur}
|
|
245
|
-
className={cn(
|
|
245
|
+
className={cn({
|
|
246
246
|
[styles.readonlyCursor]: !searchable,
|
|
247
247
|
})}
|
|
248
248
|
/>
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import copyToClipboard from 'copy-to-clipboard';
|
|
2
|
-
import { forwardRef, KeyboardEventHandler, MouseEventHandler, useEffect, useRef, useState } from 'react';
|
|
2
|
+
import { forwardRef, KeyboardEventHandler, MouseEvent, MouseEventHandler, useEffect, useRef, useState } from 'react';
|
|
3
3
|
|
|
4
4
|
import { ButtonSize } from '@snack-uikit/input-private';
|
|
5
5
|
|
|
6
|
+
import { AsyncValueRequest } from '../../types';
|
|
6
7
|
import { getIcon } from './helpers';
|
|
7
8
|
import styles from './styles.module.scss';
|
|
8
9
|
|
|
@@ -12,35 +13,41 @@ type ButtonCopyValueProps = {
|
|
|
12
13
|
onKeyDown?: KeyboardEventHandler<HTMLButtonElement>;
|
|
13
14
|
onClick?: MouseEventHandler<HTMLButtonElement>;
|
|
14
15
|
tabIndex?: number;
|
|
15
|
-
|
|
16
|
+
onValueRequest?(): AsyncValueRequest;
|
|
16
17
|
disabled?: boolean;
|
|
17
18
|
};
|
|
19
|
+
|
|
18
20
|
export const ButtonCopyValue = forwardRef<HTMLButtonElement, ButtonCopyValueProps>(
|
|
19
|
-
({ size, valueToCopy, tabIndex = -1, onKeyDown, onClick,
|
|
21
|
+
({ size, valueToCopy, tabIndex = -1, onKeyDown, onClick, onValueRequest, disabled }, ref) => {
|
|
20
22
|
const [isChecked, setIsChecked] = useState(false);
|
|
21
23
|
const timerId = useRef<ReturnType<typeof setTimeout>>();
|
|
22
|
-
|
|
24
|
+
|
|
23
25
|
const closeTooltip = () => setIsChecked(false);
|
|
24
26
|
|
|
25
|
-
const
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
clearTimeout(timerId.current);
|
|
30
|
-
timerId.current = setTimeout(closeTooltip, 2000);
|
|
31
|
-
onClick?.(event);
|
|
32
|
-
};
|
|
27
|
+
const handleCopy = (event: MouseEvent<HTMLButtonElement>, asyncValue?: string) => {
|
|
28
|
+
const value = asyncValue || valueToCopy;
|
|
29
|
+
|
|
30
|
+
value && copyToClipboard(value, { format: 'text/plain' });
|
|
33
31
|
|
|
32
|
+
setIsChecked(true);
|
|
33
|
+
|
|
34
|
+
clearTimeout(timerId.current);
|
|
35
|
+
timerId.current = setTimeout(closeTooltip, 2000);
|
|
36
|
+
|
|
37
|
+
onClick?.(event);
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
const handleClick: MouseEventHandler<HTMLButtonElement> = event => {
|
|
34
41
|
event.stopPropagation();
|
|
35
42
|
|
|
36
|
-
if (
|
|
37
|
-
|
|
38
|
-
if (
|
|
39
|
-
handleCopy();
|
|
43
|
+
if (onValueRequest) {
|
|
44
|
+
onValueRequest().then(({ success, value }) => {
|
|
45
|
+
if (success) {
|
|
46
|
+
handleCopy(event, value);
|
|
40
47
|
}
|
|
41
48
|
});
|
|
42
49
|
} else {
|
|
43
|
-
handleCopy();
|
|
50
|
+
handleCopy(event);
|
|
44
51
|
}
|
|
45
52
|
};
|
|
46
53
|
|
|
@@ -3,13 +3,14 @@ import { RefObject, useMemo } from 'react';
|
|
|
3
3
|
import { BUTTON_SIZE_MAP, ButtonProps, Size } from '@snack-uikit/input-private';
|
|
4
4
|
|
|
5
5
|
import { ButtonCopyValue } from '../helperComponents';
|
|
6
|
+
import { AsyncValueRequest } from '../types';
|
|
6
7
|
|
|
7
8
|
type UseCopyButtonProps = {
|
|
8
9
|
copyButtonRef: RefObject<HTMLButtonElement>;
|
|
9
10
|
showCopyButton: boolean;
|
|
10
11
|
valueToCopy: string;
|
|
11
12
|
size: Size;
|
|
12
|
-
|
|
13
|
+
onValueRequest?(): AsyncValueRequest;
|
|
13
14
|
disabled?: boolean;
|
|
14
15
|
};
|
|
15
16
|
|
|
@@ -18,7 +19,7 @@ export function useCopyButton({
|
|
|
18
19
|
showCopyButton,
|
|
19
20
|
size,
|
|
20
21
|
valueToCopy,
|
|
21
|
-
|
|
22
|
+
onValueRequest,
|
|
22
23
|
disabled,
|
|
23
24
|
}: UseCopyButtonProps): ButtonProps {
|
|
24
25
|
return useMemo(
|
|
@@ -31,11 +32,11 @@ export function useCopyButton({
|
|
|
31
32
|
{...props}
|
|
32
33
|
size={BUTTON_SIZE_MAP[size]}
|
|
33
34
|
valueToCopy={valueToCopy}
|
|
34
|
-
|
|
35
|
+
onValueRequest={onValueRequest}
|
|
35
36
|
disabled={disabled}
|
|
36
37
|
/>
|
|
37
38
|
),
|
|
38
39
|
}),
|
|
39
|
-
[copyButtonRef, disabled,
|
|
40
|
+
[copyButtonRef, disabled, onValueRequest, showCopyButton, size, valueToCopy],
|
|
40
41
|
);
|
|
41
42
|
}
|
package/src/types.ts
CHANGED
|
@@ -5,3 +5,5 @@ import { CONTAINER_VARIANT, VALIDATION_STATE } from './constants';
|
|
|
5
5
|
export type ValidationState = ValueOf<typeof VALIDATION_STATE>;
|
|
6
6
|
|
|
7
7
|
export type ContainerVariant = ValueOf<typeof CONTAINER_VARIANT>;
|
|
8
|
+
|
|
9
|
+
export type AsyncValueRequest = Promise<{ success: boolean; value?: string }>;
|