@acusti/css-value-input 0.25.0 → 1.0.0-rc.1
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/dist/CSSValueInput.js +11 -3
- package/dist/CSSValueInput.js.map +1 -1
- package/package.json +9 -3
- package/src/CSSValueInput.test.tsx +115 -0
- package/src/CSSValueInput.tsx +12 -4
package/dist/CSSValueInput.js
CHANGED
|
@@ -2,12 +2,15 @@ import { DEFAULT_CSS_VALUE_TYPE, DEFAULT_UNIT_BY_CSS_VALUE_TYPE, getCSSValueAsNu
|
|
|
2
2
|
import InputText from '@acusti/input-text';
|
|
3
3
|
import clsx from 'clsx';
|
|
4
4
|
import * as React from 'react';
|
|
5
|
-
const { useCallback, useImperativeHandle, useRef } = React;
|
|
5
|
+
const { useCallback, useEffect, useImperativeHandle, useRef } = React;
|
|
6
6
|
const ROOT_CLASS_NAME = 'cssvalueinput';
|
|
7
7
|
const CSSValueInput = React.forwardRef(({ allowEmpty = true, className, cssValueType = DEFAULT_CSS_VALUE_TYPE, disabled, getValueAsNumber = getCSSValueAsNumber, icon, label, max, min, name, onBlur, onChange, onFocus, onKeyDown, onKeyUp, onSubmitValue, placeholder, step = 1, tabIndex, title, unit = DEFAULT_UNIT_BY_CSS_VALUE_TYPE[cssValueType], validator, value, }, ref) => {
|
|
8
8
|
const inputRef = useRef(null);
|
|
9
9
|
useImperativeHandle(ref, () => inputRef.current);
|
|
10
10
|
const submittedValueRef = useRef(value || '');
|
|
11
|
+
useEffect(() => {
|
|
12
|
+
submittedValueRef.current = value || '';
|
|
13
|
+
}, [value]);
|
|
11
14
|
const handleSubmitValue = useCallback((event) => {
|
|
12
15
|
const currentValue = event.currentTarget.value;
|
|
13
16
|
// Store last submittedValue (used to reset value on invalid input)
|
|
@@ -27,6 +30,11 @@ const CSSValueInput = React.forwardRef(({ allowEmpty = true, className, cssValue
|
|
|
27
30
|
}
|
|
28
31
|
const currentValueAsNumber = getValueAsNumber(currentValue);
|
|
29
32
|
const isCurrentValueFinite = Number.isFinite(currentValueAsNumber);
|
|
33
|
+
const defaultUnit = getUnitFromCSSValue({
|
|
34
|
+
cssValueType,
|
|
35
|
+
defaultUnit: unit,
|
|
36
|
+
value: submittedValueRef.current,
|
|
37
|
+
});
|
|
30
38
|
if (!isCurrentValueFinite) {
|
|
31
39
|
let isValid = false;
|
|
32
40
|
if (validator instanceof RegExp) {
|
|
@@ -60,7 +68,7 @@ const CSSValueInput = React.forwardRef(({ allowEmpty = true, className, cssValue
|
|
|
60
68
|
if (normalizedValueAsNumber !== currentValueAsNumber) {
|
|
61
69
|
const currentUnit = getUnitFromCSSValue({
|
|
62
70
|
cssValueType,
|
|
63
|
-
defaultUnit
|
|
71
|
+
defaultUnit,
|
|
64
72
|
value: currentValue,
|
|
65
73
|
});
|
|
66
74
|
input.value = normalizedValueAsNumber + currentUnit;
|
|
@@ -68,7 +76,7 @@ const CSSValueInput = React.forwardRef(({ allowEmpty = true, className, cssValue
|
|
|
68
76
|
else {
|
|
69
77
|
input.value = getCSSValueWithUnit({
|
|
70
78
|
cssValueType,
|
|
71
|
-
defaultUnit
|
|
79
|
+
defaultUnit,
|
|
72
80
|
value: currentValue,
|
|
73
81
|
});
|
|
74
82
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CSSValueInput.js","sourceRoot":"","sources":["../src/CSSValueInput.tsx"],"names":[],"mappings":"AAAA,OAAO,EACH,sBAAsB,EACtB,8BAA8B,EAC9B,mBAAmB,EACnB,mBAAmB,EACnB,mBAAmB,EACnB,gBAAgB,GACnB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,SAAS,MAAM,oBAAoB,CAAC;AAC3C,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAkC/B,MAAM,EAAE,WAAW,EAAE,mBAAmB,EAAE,MAAM,EAAE,GAAG,KAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"CSSValueInput.js","sourceRoot":"","sources":["../src/CSSValueInput.tsx"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@acusti/css-value-input",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.0-rc.1",
|
|
4
4
|
"description": "React component that renders a text input that can take and update a CSS value of a particular type with a default unit",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"react",
|
|
@@ -36,11 +36,17 @@
|
|
|
36
36
|
},
|
|
37
37
|
"homepage": "https://github.com/acusti/uikit/tree/main/packages/css-value-input#readme",
|
|
38
38
|
"devDependencies": {
|
|
39
|
+
"@testing-library/dom": "^9.3.1",
|
|
40
|
+
"@testing-library/react": "^14.0.0",
|
|
41
|
+
"@testing-library/user-event": "^14.4.3",
|
|
39
42
|
"@types/react": "^18.0.25",
|
|
40
|
-
"
|
|
43
|
+
"jsdom": "^22.1.0",
|
|
44
|
+
"react": "^18",
|
|
45
|
+
"react-dom": "^18",
|
|
46
|
+
"typescript": "^5.1.6"
|
|
41
47
|
},
|
|
42
48
|
"dependencies": {
|
|
43
|
-
"@acusti/css-values": "^0.
|
|
49
|
+
"@acusti/css-values": "^1.0.0",
|
|
44
50
|
"@acusti/input-text": "^1.2.0",
|
|
45
51
|
"clsx": "^1.2.1"
|
|
46
52
|
},
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
// @vitest-environment jsdom
|
|
2
|
+
import { cleanup, render } from '@testing-library/react';
|
|
3
|
+
import userEvent from '@testing-library/user-event';
|
|
4
|
+
import React from 'react';
|
|
5
|
+
import { afterEach, describe, expect, it } from 'vitest';
|
|
6
|
+
|
|
7
|
+
import CSSValueInput from './CSSValueInput.js';
|
|
8
|
+
|
|
9
|
+
const noop = () => {};
|
|
10
|
+
|
|
11
|
+
afterEach(cleanup);
|
|
12
|
+
|
|
13
|
+
describe('CSSValueInput.tsx', async () => {
|
|
14
|
+
it('renders a text input with the given props.value', async () => {
|
|
15
|
+
const { getByRole } = render(<CSSValueInput onSubmitValue={noop} value="24px" />);
|
|
16
|
+
expect(getByRole('textbox').value).toBe('24px');
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it('handles ↑/↓ keys to increment/decrement by 1 and ⇧↑/⇧↓ to increment/decrement by 10 (preserving the CSS unit)', async () => {
|
|
20
|
+
const user = userEvent.setup();
|
|
21
|
+
const { getByRole } = render(<CSSValueInput onSubmitValue={noop} value="75%" />);
|
|
22
|
+
const input = getByRole('textbox');
|
|
23
|
+
expect(input.value).toBe('75%');
|
|
24
|
+
await user.type(input, '{ArrowUp}');
|
|
25
|
+
expect(input.value).toBe('76%');
|
|
26
|
+
await user.type(input, '{Shift>}{ArrowUp}{/Shift}');
|
|
27
|
+
expect(input.value).toBe('86%');
|
|
28
|
+
await user.type(input, '{Shift>}{ArrowUp}{/Shift}');
|
|
29
|
+
expect(input.value).toBe('96%');
|
|
30
|
+
await user.type(input, '{ArrowUp}');
|
|
31
|
+
expect(input.value).toBe('97%');
|
|
32
|
+
await user.type(input, '{Shift>}{ArrowDown}{/Shift}');
|
|
33
|
+
expect(input.value).toBe('87%');
|
|
34
|
+
await user.type(input, '{Shift>}{ArrowDown}{/Shift}');
|
|
35
|
+
expect(input.value).toBe('77%');
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it('supports custom props.step for ↑/↓ key handling', async () => {
|
|
39
|
+
const user = userEvent.setup();
|
|
40
|
+
const { getByRole } = render(
|
|
41
|
+
<CSSValueInput onSubmitValue={noop} step={0.1} value="2rem" />,
|
|
42
|
+
);
|
|
43
|
+
const input = getByRole('textbox');
|
|
44
|
+
expect(input.value).toBe('2rem');
|
|
45
|
+
await user.type(input, '{ArrowUp}');
|
|
46
|
+
expect(input.value).toBe('2.1rem');
|
|
47
|
+
await user.type(input, '{Shift>}{ArrowUp}{/Shift}');
|
|
48
|
+
expect(input.value).toBe('3.1rem');
|
|
49
|
+
await user.type(input, '{Shift>}{ArrowUp}{/Shift}');
|
|
50
|
+
expect(input.value).toBe('4.1rem');
|
|
51
|
+
await user.type(input, '{ArrowUp}');
|
|
52
|
+
expect(input.value).toBe('4.2rem');
|
|
53
|
+
await user.type(input, '{Shift>}{ArrowDown}{/Shift}');
|
|
54
|
+
expect(input.value).toBe('3.2rem');
|
|
55
|
+
await user.type(input, '{Shift>}{ArrowDown}{/Shift}');
|
|
56
|
+
expect(input.value).toBe('2.2rem');
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it('uses props.unit as default unit when unit is missing', async () => {
|
|
60
|
+
const user = userEvent.setup();
|
|
61
|
+
const { getByRole } = render(
|
|
62
|
+
<CSSValueInput allowEmpty onSubmitValue={noop} unit="px" value="" />,
|
|
63
|
+
);
|
|
64
|
+
const input = getByRole('textbox');
|
|
65
|
+
expect(input.value).toBe('');
|
|
66
|
+
await user.type(input, '14{Enter}');
|
|
67
|
+
expect(input.value).toBe('14px');
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it('preserves last entered unit if different from props.unit when unit is missing', async () => {
|
|
71
|
+
const user = userEvent.setup();
|
|
72
|
+
const { getByRole } = render(
|
|
73
|
+
<CSSValueInput allowEmpty onSubmitValue={noop} unit="px" value="" />,
|
|
74
|
+
);
|
|
75
|
+
const input = getByRole('textbox');
|
|
76
|
+
expect(input.value).toBe('');
|
|
77
|
+
await user.type(input, '25vw{Enter}');
|
|
78
|
+
expect(input.value).toBe('25vw');
|
|
79
|
+
await user.type(input, '50{Enter}');
|
|
80
|
+
expect(input.value).toBe('50vw');
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it('treats value as numeric if props.unit is an empty string', async () => {
|
|
84
|
+
const user = userEvent.setup();
|
|
85
|
+
const { getByRole } = render(
|
|
86
|
+
<CSSValueInput allowEmpty onSubmitValue={noop} unit="" value="100" />,
|
|
87
|
+
);
|
|
88
|
+
const input = getByRole('textbox');
|
|
89
|
+
expect(input.value).toBe('100');
|
|
90
|
+
await user.type(input, '1{Enter}');
|
|
91
|
+
expect(input.value).toBe('1');
|
|
92
|
+
await user.type(input, '{Shift>}{ArrowUp}{/Shift}');
|
|
93
|
+
expect(input.value).toBe('11');
|
|
94
|
+
await user.clear(input);
|
|
95
|
+
expect(input.value).toBe('');
|
|
96
|
+
await user.type(input, '200{Enter}');
|
|
97
|
+
expect(input.value).toBe('200');
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
it('updates default unit as props.unit and props.value changes', async () => {
|
|
101
|
+
const user = userEvent.setup();
|
|
102
|
+
const { getByRole, rerender } = render(
|
|
103
|
+
<CSSValueInput onSubmitValue={noop} unit="px" value="12px" />,
|
|
104
|
+
);
|
|
105
|
+
const input = getByRole('textbox');
|
|
106
|
+
rerender(<CSSValueInput onSubmitValue={noop} unit="" value="4" />);
|
|
107
|
+
expect(input.value).toBe('4');
|
|
108
|
+
await user.type(input, '25{Enter}');
|
|
109
|
+
expect(input.value).toBe('25');
|
|
110
|
+
rerender(<CSSValueInput onSubmitValue={noop} unit="rad" value="3rad" />);
|
|
111
|
+
expect(input.value).toBe('3rad');
|
|
112
|
+
await user.type(input, '-4.1{Enter}');
|
|
113
|
+
expect(input.value).toBe('-4.1rad');
|
|
114
|
+
});
|
|
115
|
+
});
|
package/src/CSSValueInput.tsx
CHANGED
|
@@ -42,7 +42,7 @@ export type Props = {
|
|
|
42
42
|
|
|
43
43
|
type InputRef = HTMLInputElement | null;
|
|
44
44
|
|
|
45
|
-
const { useCallback, useImperativeHandle, useRef } = React;
|
|
45
|
+
const { useCallback, useEffect, useImperativeHandle, useRef } = React;
|
|
46
46
|
|
|
47
47
|
const ROOT_CLASS_NAME = 'cssvalueinput';
|
|
48
48
|
|
|
@@ -77,9 +77,12 @@ const CSSValueInput: React.FC<Props> = React.forwardRef<HTMLInputElement, Props>
|
|
|
77
77
|
) => {
|
|
78
78
|
const inputRef = useRef<InputRef>(null);
|
|
79
79
|
useImperativeHandle<InputRef, InputRef>(ref, () => inputRef.current);
|
|
80
|
-
|
|
81
80
|
const submittedValueRef = useRef<string>(value || '');
|
|
82
81
|
|
|
82
|
+
useEffect(() => {
|
|
83
|
+
submittedValueRef.current = value || '';
|
|
84
|
+
}, [value]);
|
|
85
|
+
|
|
83
86
|
const handleSubmitValue = useCallback(
|
|
84
87
|
(event: React.SyntheticEvent<HTMLInputElement>) => {
|
|
85
88
|
const currentValue = event.currentTarget.value;
|
|
@@ -106,6 +109,11 @@ const CSSValueInput: React.FC<Props> = React.forwardRef<HTMLInputElement, Props>
|
|
|
106
109
|
|
|
107
110
|
const currentValueAsNumber = getValueAsNumber(currentValue);
|
|
108
111
|
const isCurrentValueFinite = Number.isFinite(currentValueAsNumber);
|
|
112
|
+
const defaultUnit = getUnitFromCSSValue({
|
|
113
|
+
cssValueType,
|
|
114
|
+
defaultUnit: unit,
|
|
115
|
+
value: submittedValueRef.current,
|
|
116
|
+
});
|
|
109
117
|
|
|
110
118
|
if (!isCurrentValueFinite) {
|
|
111
119
|
let isValid = false;
|
|
@@ -141,14 +149,14 @@ const CSSValueInput: React.FC<Props> = React.forwardRef<HTMLInputElement, Props>
|
|
|
141
149
|
if (normalizedValueAsNumber !== currentValueAsNumber) {
|
|
142
150
|
const currentUnit = getUnitFromCSSValue({
|
|
143
151
|
cssValueType,
|
|
144
|
-
defaultUnit
|
|
152
|
+
defaultUnit,
|
|
145
153
|
value: currentValue,
|
|
146
154
|
});
|
|
147
155
|
input.value = normalizedValueAsNumber + currentUnit;
|
|
148
156
|
} else {
|
|
149
157
|
input.value = getCSSValueWithUnit({
|
|
150
158
|
cssValueType,
|
|
151
|
-
defaultUnit
|
|
159
|
+
defaultUnit,
|
|
152
160
|
value: currentValue,
|
|
153
161
|
});
|
|
154
162
|
}
|