@snack-uikit/fields 0.51.11 → 0.51.12
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 +8 -0
- package/README.md +1 -0
- package/dist/cjs/components/FieldText/FieldText.d.ts +2 -0
- package/dist/cjs/components/FieldText/FieldText.js +30 -7
- package/dist/esm/components/FieldText/FieldText.d.ts +2 -0
- package/dist/esm/components/FieldText/FieldText.js +32 -5
- package/package.json +6 -6
- package/src/components/FieldText/FieldText.tsx +44 -5
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,14 @@
|
|
|
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
|
+
## <small>0.51.12 (2025-12-01)</small>
|
|
7
|
+
|
|
8
|
+
* feat(PDS-3204): added onClearButtonClick in FieldText ([2a0526b](https://github.com/cloud-ru-tech/snack-uikit/commit/2a0526b))
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
6
14
|
## <small>0.51.11 (2025-11-28)</small>
|
|
7
15
|
|
|
8
16
|
### Only dependencies have been changed
|
package/README.md
CHANGED
|
@@ -473,6 +473,7 @@ FieldStepper в основном предназначен для работы с
|
|
|
473
473
|
| showCopyButton | `boolean` | - | Отображение кнопки Копировать для поля (актуально только для `readonly = true`) |
|
|
474
474
|
| onCopyButtonClick | `() => void` | - | Колбек клика по кнопке Копировать для поля |
|
|
475
475
|
| showClearButton | `boolean` | true | Отображение кнопки очистки поля |
|
|
476
|
+
| onClearButtonClick | `() => void` | - | Колбек клика по кнопке очистки поля |
|
|
476
477
|
| allowMoreThanMaxLength | `boolean` | - | Можно ли вводить больше разрешённого кол-ва символов |
|
|
477
478
|
| prefixIcon | `ReactElement<any, string \| JSXElementConstructor<any>>` | - | Иконка-префикс для поля |
|
|
478
479
|
| prefix | `ReactNode` | - | Произвольный префикс для поля |
|
|
@@ -15,6 +15,8 @@ type FieldTextOwnProps = {
|
|
|
15
15
|
* @default true
|
|
16
16
|
*/
|
|
17
17
|
showClearButton?: boolean;
|
|
18
|
+
/** Колбек клика по кнопке очистки поля */
|
|
19
|
+
onClearButtonClick?(): void;
|
|
18
20
|
/** Можно ли вводить больше разрешённого кол-ва символов */
|
|
19
21
|
allowMoreThanMaxLength?: boolean;
|
|
20
22
|
/** Иконка-префикс для поля */
|
|
@@ -44,6 +44,7 @@ exports.FieldText = (0, react_1.forwardRef)((_a, ref) => {
|
|
|
44
44
|
onFocus,
|
|
45
45
|
onBlur,
|
|
46
46
|
onCopyButtonClick,
|
|
47
|
+
onClearButtonClick,
|
|
47
48
|
className,
|
|
48
49
|
label,
|
|
49
50
|
labelTooltip,
|
|
@@ -67,7 +68,7 @@ exports.FieldText = (0, react_1.forwardRef)((_a, ref) => {
|
|
|
67
68
|
inputMode,
|
|
68
69
|
spellCheck
|
|
69
70
|
} = _a,
|
|
70
|
-
rest = __rest(_a, ["id", "name", "value", "placeholder", "maxLength", "disabled", "readonly", "showCopyButton", "showClearButton", "allowMoreThanMaxLength", "onChange", "onFocus", "onBlur", "onCopyButtonClick", "className", "label", "labelTooltip", "labelTooltipPlacement", "required", "caption", "hint", "showHintIcon", "size", "validationState", "error", "autoComplete", "autoFocus", "prefixIcon", "prefix", "postfix", "button", "onPaste", "onKeyDown", "type", "inputMode", "spellCheck"]);
|
|
71
|
+
rest = __rest(_a, ["id", "name", "value", "placeholder", "maxLength", "disabled", "readonly", "showCopyButton", "showClearButton", "allowMoreThanMaxLength", "onChange", "onFocus", "onBlur", "onCopyButtonClick", "onClearButtonClick", "className", "label", "labelTooltip", "labelTooltipPlacement", "required", "caption", "hint", "showHintIcon", "size", "validationState", "error", "autoComplete", "autoFocus", "prefixIcon", "prefix", "postfix", "button", "onPaste", "onKeyDown", "type", "inputMode", "spellCheck"]);
|
|
71
72
|
const [value = '', onChange] = (0, hooks_1.useValueControl)({
|
|
72
73
|
value: valueProp,
|
|
73
74
|
defaultValue: '',
|
|
@@ -98,18 +99,26 @@ exports.FieldText = (0, react_1.forwardRef)((_a, ref) => {
|
|
|
98
99
|
const containerVariant = (0, helpers_1.getContainerVariant)({
|
|
99
100
|
button
|
|
100
101
|
});
|
|
101
|
-
const
|
|
102
|
+
const [isFieldFocused, setIsFieldFocused] = (0, react_1.useState)(false);
|
|
103
|
+
const focusedRef = (0, react_1.useRef)(false);
|
|
104
|
+
const onClear = e => {
|
|
102
105
|
var _a;
|
|
106
|
+
e.preventDefault();
|
|
103
107
|
onChange('');
|
|
104
|
-
|
|
108
|
+
onClearButtonClick === null || onClearButtonClick === void 0 ? void 0 : onClearButtonClick();
|
|
109
|
+
if (focusedRef.current) {
|
|
105
110
|
(_a = localRef.current) === null || _a === void 0 ? void 0 : _a.focus();
|
|
106
111
|
}
|
|
107
112
|
};
|
|
113
|
+
const handleClearClickDown = () => {
|
|
114
|
+
focusedRef.current = isFieldFocused;
|
|
115
|
+
};
|
|
108
116
|
const clearButtonSettings = (0, input_private_1.useClearButton)({
|
|
109
117
|
clearButtonRef,
|
|
110
118
|
showClearButton,
|
|
111
|
-
|
|
112
|
-
|
|
119
|
+
onClear,
|
|
120
|
+
onDown: handleClearClickDown,
|
|
121
|
+
size
|
|
113
122
|
});
|
|
114
123
|
const copyButtonSettings = (0, hooks_1.useCopyButton)({
|
|
115
124
|
copyButtonRef,
|
|
@@ -164,6 +173,20 @@ exports.FieldText = (0, react_1.forwardRef)((_a, ref) => {
|
|
|
164
173
|
onInputKeyDown(event);
|
|
165
174
|
onKeyDown === null || onKeyDown === void 0 ? void 0 : onKeyDown(event);
|
|
166
175
|
};
|
|
176
|
+
const handleBlur = event => {
|
|
177
|
+
const nextTarget = event.relatedTarget;
|
|
178
|
+
// если фокус ушёл на кнопку очистки — игнорируем внешний onBlur
|
|
179
|
+
if (nextTarget && nextTarget === clearButtonRef.current) {
|
|
180
|
+
setIsFieldFocused(false);
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
onBlur === null || onBlur === void 0 ? void 0 : onBlur(event);
|
|
184
|
+
setIsFieldFocused(false);
|
|
185
|
+
};
|
|
186
|
+
const handleFocus = event => {
|
|
187
|
+
onFocus === null || onFocus === void 0 ? void 0 : onFocus(event);
|
|
188
|
+
setIsFieldFocused(true);
|
|
189
|
+
};
|
|
167
190
|
return (0, jsx_runtime_1.jsx)(FieldDecorator_1.FieldDecorator, Object.assign({
|
|
168
191
|
className: className,
|
|
169
192
|
label: label,
|
|
@@ -199,8 +222,8 @@ exports.FieldText = (0, react_1.forwardRef)((_a, ref) => {
|
|
|
199
222
|
"data-size": size,
|
|
200
223
|
value: value,
|
|
201
224
|
onChange: onChange,
|
|
202
|
-
onFocus:
|
|
203
|
-
onBlur:
|
|
225
|
+
onFocus: handleFocus,
|
|
226
|
+
onBlur: handleBlur,
|
|
204
227
|
tabIndex: inputTabIndex,
|
|
205
228
|
onKeyDown: handleKeyDown,
|
|
206
229
|
onPaste: onPaste,
|
|
@@ -15,6 +15,8 @@ type FieldTextOwnProps = {
|
|
|
15
15
|
* @default true
|
|
16
16
|
*/
|
|
17
17
|
showClearButton?: boolean;
|
|
18
|
+
/** Колбек клика по кнопке очистки поля */
|
|
19
|
+
onClearButtonClick?(): void;
|
|
18
20
|
/** Можно ли вводить больше разрешённого кол-ва символов */
|
|
19
21
|
allowMoreThanMaxLength?: boolean;
|
|
20
22
|
/** Иконка-префикс для поля */
|
|
@@ -21,7 +21,7 @@ import { getValidationState } from '../../utils/getValidationState';
|
|
|
21
21
|
import { FieldDecorator } from '../FieldDecorator';
|
|
22
22
|
import { getContainerVariant } from './helpers';
|
|
23
23
|
export const FieldText = forwardRef((_a, ref) => {
|
|
24
|
-
var { id, name, value: valueProp, placeholder, maxLength, disabled = false, readonly = false, showCopyButton: showCopyButtonProp = true, showClearButton: showClearButtonProp = true, allowMoreThanMaxLength = false, onChange: onChangeProp, onFocus, onBlur, onCopyButtonClick, className, label, labelTooltip, labelTooltipPlacement, required = false, caption, hint, showHintIcon, size = SIZE.S, validationState = VALIDATION_STATE.Default, error, autoComplete, autoFocus, prefixIcon, prefix, postfix, button: buttonProp, onPaste, onKeyDown, type = 'text', inputMode, spellCheck } = _a, rest = __rest(_a, ["id", "name", "value", "placeholder", "maxLength", "disabled", "readonly", "showCopyButton", "showClearButton", "allowMoreThanMaxLength", "onChange", "onFocus", "onBlur", "onCopyButtonClick", "className", "label", "labelTooltip", "labelTooltipPlacement", "required", "caption", "hint", "showHintIcon", "size", "validationState", "error", "autoComplete", "autoFocus", "prefixIcon", "prefix", "postfix", "button", "onPaste", "onKeyDown", "type", "inputMode", "spellCheck"]);
|
|
24
|
+
var { id, name, value: valueProp, placeholder, maxLength, disabled = false, readonly = false, showCopyButton: showCopyButtonProp = true, showClearButton: showClearButtonProp = true, allowMoreThanMaxLength = false, onChange: onChangeProp, onFocus, onBlur, onCopyButtonClick, onClearButtonClick, className, label, labelTooltip, labelTooltipPlacement, required = false, caption, hint, showHintIcon, size = SIZE.S, validationState = VALIDATION_STATE.Default, error, autoComplete, autoFocus, prefixIcon, prefix, postfix, button: buttonProp, onPaste, onKeyDown, type = 'text', inputMode, spellCheck } = _a, rest = __rest(_a, ["id", "name", "value", "placeholder", "maxLength", "disabled", "readonly", "showCopyButton", "showClearButton", "allowMoreThanMaxLength", "onChange", "onFocus", "onBlur", "onCopyButtonClick", "onClearButtonClick", "className", "label", "labelTooltip", "labelTooltipPlacement", "required", "caption", "hint", "showHintIcon", "size", "validationState", "error", "autoComplete", "autoFocus", "prefixIcon", "prefix", "postfix", "button", "onPaste", "onKeyDown", "type", "inputMode", "spellCheck"]);
|
|
25
25
|
const [value = '', onChange] = useValueControl({
|
|
26
26
|
value: valueProp,
|
|
27
27
|
defaultValue: '',
|
|
@@ -41,14 +41,27 @@ export const FieldText = forwardRef((_a, ref) => {
|
|
|
41
41
|
setTimeout(() => { var _a; return (_a = localRef.current) === null || _a === void 0 ? void 0 : _a.focus(); }, 0);
|
|
42
42
|
} }) }) : undefined, [buttonProp]);
|
|
43
43
|
const containerVariant = getContainerVariant({ button });
|
|
44
|
-
const
|
|
44
|
+
const [isFieldFocused, setIsFieldFocused] = useState(false);
|
|
45
|
+
const focusedRef = useRef(false);
|
|
46
|
+
const onClear = e => {
|
|
45
47
|
var _a;
|
|
48
|
+
e.preventDefault();
|
|
46
49
|
onChange('');
|
|
47
|
-
|
|
50
|
+
onClearButtonClick === null || onClearButtonClick === void 0 ? void 0 : onClearButtonClick();
|
|
51
|
+
if (focusedRef.current) {
|
|
48
52
|
(_a = localRef.current) === null || _a === void 0 ? void 0 : _a.focus();
|
|
49
53
|
}
|
|
50
54
|
};
|
|
51
|
-
const
|
|
55
|
+
const handleClearClickDown = () => {
|
|
56
|
+
focusedRef.current = isFieldFocused;
|
|
57
|
+
};
|
|
58
|
+
const clearButtonSettings = useClearButton({
|
|
59
|
+
clearButtonRef,
|
|
60
|
+
showClearButton,
|
|
61
|
+
onClear,
|
|
62
|
+
onDown: handleClearClickDown,
|
|
63
|
+
size,
|
|
64
|
+
});
|
|
52
65
|
const copyButtonSettings = useCopyButton({
|
|
53
66
|
copyButtonRef,
|
|
54
67
|
showCopyButton,
|
|
@@ -91,5 +104,19 @@ export const FieldText = forwardRef((_a, ref) => {
|
|
|
91
104
|
onInputKeyDown(event);
|
|
92
105
|
onKeyDown === null || onKeyDown === void 0 ? void 0 : onKeyDown(event);
|
|
93
106
|
};
|
|
94
|
-
|
|
107
|
+
const handleBlur = event => {
|
|
108
|
+
const nextTarget = event.relatedTarget;
|
|
109
|
+
// если фокус ушёл на кнопку очистки — игнорируем внешний onBlur
|
|
110
|
+
if (nextTarget && nextTarget === clearButtonRef.current) {
|
|
111
|
+
setIsFieldFocused(false);
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
onBlur === null || onBlur === void 0 ? void 0 : onBlur(event);
|
|
115
|
+
setIsFieldFocused(false);
|
|
116
|
+
};
|
|
117
|
+
const handleFocus = event => {
|
|
118
|
+
onFocus === null || onFocus === void 0 ? void 0 : onFocus(event);
|
|
119
|
+
setIsFieldFocused(true);
|
|
120
|
+
};
|
|
121
|
+
return (_jsx(FieldDecorator, Object.assign({ className: className, label: label, labelTooltip: labelTooltip, labelTooltipPlacement: labelTooltipPlacement, labelFor: id, required: required, caption: caption, length: maxLength ? { max: maxLength, current: value.length } : undefined, hint: hint, disabled: disabled, readonly: readonly, showHintIcon: showHintIcon, size: size, validationState: fieldValidationState, error: error }, extractSupportProps(rest), { children: _jsx(FieldContainerPrivate, { size: size, validationState: fieldValidationState, disabled: disabled, readonly: readonly, variant: containerVariant, inputRef: localRef, prefix: prefixButtons, postfix: postfixButtons, disableFocus: isButtonFocused, children: _jsx(InputPrivate, { ref: mergeRefs(ref, localRef), "data-size": size, value: value, onChange: onChange, onFocus: handleFocus, onBlur: handleBlur, tabIndex: inputTabIndex, onKeyDown: handleKeyDown, onPaste: onPaste, placeholder: placeholder, disabled: disabled, readonly: readonly, type: type, inputMode: inputMode, maxLength: allowMoreThanMaxLength ? undefined : maxLength || undefined, id: id, name: name, autoComplete: autoComplete, autoFocus: autoFocus, spellCheck: spellCheck, "data-test-id": 'field-text__input' }) }) })));
|
|
95
122
|
});
|
package/package.json
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
6
|
"title": "Fields",
|
|
7
|
-
"version": "0.51.
|
|
7
|
+
"version": "0.51.12",
|
|
8
8
|
"sideEffects": [
|
|
9
9
|
"*.css",
|
|
10
10
|
"*.woff",
|
|
@@ -37,13 +37,13 @@
|
|
|
37
37
|
"scripts": {},
|
|
38
38
|
"dependencies": {
|
|
39
39
|
"@snack-uikit/button": "0.19.16",
|
|
40
|
-
"@snack-uikit/calendar": "0.13.
|
|
41
|
-
"@snack-uikit/color-picker": "0.3.
|
|
40
|
+
"@snack-uikit/calendar": "0.13.11",
|
|
41
|
+
"@snack-uikit/color-picker": "0.3.50",
|
|
42
42
|
"@snack-uikit/divider": "3.2.10",
|
|
43
43
|
"@snack-uikit/dropdown": "0.5.3",
|
|
44
44
|
"@snack-uikit/icons": "0.27.4",
|
|
45
|
-
"@snack-uikit/input-private": "4.8.
|
|
46
|
-
"@snack-uikit/list": "0.32.
|
|
45
|
+
"@snack-uikit/input-private": "4.8.5",
|
|
46
|
+
"@snack-uikit/list": "0.32.10",
|
|
47
47
|
"@snack-uikit/scroll": "0.10.5",
|
|
48
48
|
"@snack-uikit/skeleton": "0.6.9",
|
|
49
49
|
"@snack-uikit/slider": "0.3.30",
|
|
@@ -66,5 +66,5 @@
|
|
|
66
66
|
"peerDependencies": {
|
|
67
67
|
"@snack-uikit/locale": "*"
|
|
68
68
|
},
|
|
69
|
-
"gitHead": "
|
|
69
|
+
"gitHead": "e1b3bee4ec326c0c7e9c87b2714634a8ff113ded"
|
|
70
70
|
}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import mergeRefs from 'merge-refs';
|
|
2
2
|
import {
|
|
3
|
+
FocusEventHandler,
|
|
3
4
|
forwardRef,
|
|
4
5
|
KeyboardEventHandler,
|
|
6
|
+
MouseEventHandler,
|
|
5
7
|
ReactElement,
|
|
6
8
|
ReactNode,
|
|
7
9
|
useCallback,
|
|
@@ -66,6 +68,8 @@ type FieldTextOwnProps = {
|
|
|
66
68
|
* @default true
|
|
67
69
|
*/
|
|
68
70
|
showClearButton?: boolean;
|
|
71
|
+
/** Колбек клика по кнопке очистки поля */
|
|
72
|
+
onClearButtonClick?(): void;
|
|
69
73
|
/** Можно ли вводить больше разрешённого кол-ва символов */
|
|
70
74
|
allowMoreThanMaxLength?: boolean;
|
|
71
75
|
/** Иконка-префикс для поля */
|
|
@@ -100,6 +104,7 @@ export const FieldText = forwardRef<HTMLInputElement, FieldTextProps>(
|
|
|
100
104
|
onFocus,
|
|
101
105
|
onBlur,
|
|
102
106
|
onCopyButtonClick,
|
|
107
|
+
onClearButtonClick,
|
|
103
108
|
className,
|
|
104
109
|
label,
|
|
105
110
|
labelTooltip,
|
|
@@ -158,15 +163,31 @@ export const FieldText = forwardRef<HTMLInputElement, FieldTextProps>(
|
|
|
158
163
|
|
|
159
164
|
const containerVariant = getContainerVariant({ button });
|
|
160
165
|
|
|
161
|
-
const
|
|
166
|
+
const [isFieldFocused, setIsFieldFocused] = useState(false);
|
|
167
|
+
const focusedRef = useRef(false);
|
|
168
|
+
|
|
169
|
+
const onClear: MouseEventHandler<HTMLButtonElement> = e => {
|
|
170
|
+
e.preventDefault();
|
|
162
171
|
onChange('');
|
|
172
|
+
onClearButtonClick?.();
|
|
163
173
|
|
|
164
|
-
if (
|
|
174
|
+
if (focusedRef.current) {
|
|
165
175
|
localRef.current?.focus();
|
|
166
176
|
}
|
|
167
177
|
};
|
|
168
178
|
|
|
169
|
-
const
|
|
179
|
+
const handleClearClickDown = () => {
|
|
180
|
+
focusedRef.current = isFieldFocused;
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
const clearButtonSettings = useClearButton({
|
|
184
|
+
clearButtonRef,
|
|
185
|
+
showClearButton,
|
|
186
|
+
onClear,
|
|
187
|
+
onDown: handleClearClickDown,
|
|
188
|
+
size,
|
|
189
|
+
});
|
|
190
|
+
|
|
170
191
|
const copyButtonSettings = useCopyButton({
|
|
171
192
|
copyButtonRef,
|
|
172
193
|
showCopyButton,
|
|
@@ -218,6 +239,24 @@ export const FieldText = forwardRef<HTMLInputElement, FieldTextProps>(
|
|
|
218
239
|
onKeyDown?.(event);
|
|
219
240
|
};
|
|
220
241
|
|
|
242
|
+
const handleBlur: FocusEventHandler<HTMLInputElement> = event => {
|
|
243
|
+
const nextTarget = event.relatedTarget as HTMLElement | null;
|
|
244
|
+
|
|
245
|
+
// если фокус ушёл на кнопку очистки — игнорируем внешний onBlur
|
|
246
|
+
if (nextTarget && nextTarget === clearButtonRef.current) {
|
|
247
|
+
setIsFieldFocused(false);
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
onBlur?.(event);
|
|
252
|
+
setIsFieldFocused(false);
|
|
253
|
+
};
|
|
254
|
+
|
|
255
|
+
const handleFocus: FocusEventHandler<HTMLInputElement> = event => {
|
|
256
|
+
onFocus?.(event);
|
|
257
|
+
setIsFieldFocused(true);
|
|
258
|
+
};
|
|
259
|
+
|
|
221
260
|
return (
|
|
222
261
|
<FieldDecorator
|
|
223
262
|
className={className}
|
|
@@ -253,8 +292,8 @@ export const FieldText = forwardRef<HTMLInputElement, FieldTextProps>(
|
|
|
253
292
|
data-size={size}
|
|
254
293
|
value={value}
|
|
255
294
|
onChange={onChange}
|
|
256
|
-
onFocus={
|
|
257
|
-
onBlur={
|
|
295
|
+
onFocus={handleFocus}
|
|
296
|
+
onBlur={handleBlur}
|
|
258
297
|
tabIndex={inputTabIndex}
|
|
259
298
|
onKeyDown={handleKeyDown}
|
|
260
299
|
onPaste={onPaste}
|