@ncds/ui-admin 1.8.19 → 1.8.20
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/cjs/src/components/forms-and-input/input-base/InputBase.js +4 -2
- package/dist/cjs/src/components/forms-and-input/input-base/__tests__/InputBase.test.js +72 -0
- package/dist/esm/src/components/forms-and-input/input-base/InputBase.js +4 -2
- package/dist/esm/src/components/forms-and-input/input-base/__tests__/InputBase.test.js +69 -0
- package/dist/temp/src/components/forms-and-input/input-base/InputBase.js +3 -3
- package/dist/temp/src/components/forms-and-input/input-base/__tests__/InputBase.test.d.ts +1 -0
- package/dist/temp/src/components/forms-and-input/input-base/__tests__/InputBase.test.js +59 -0
- package/dist/types/src/components/forms-and-input/input-base/__tests__/InputBase.test.d.ts +1 -0
- package/package.json +1 -1
|
@@ -35,6 +35,8 @@ const InputBase = exports.InputBase = /*#__PURE__*/(0, _react.forwardRef)((_ref,
|
|
|
35
35
|
showHelpIcon,
|
|
36
36
|
maxLength,
|
|
37
37
|
showTextCount,
|
|
38
|
+
clearText,
|
|
39
|
+
onClearText,
|
|
38
40
|
className,
|
|
39
41
|
...props
|
|
40
42
|
} = _ref;
|
|
@@ -100,11 +102,11 @@ const InputBase = exports.InputBase = /*#__PURE__*/(0, _react.forwardRef)((_ref,
|
|
|
100
102
|
}
|
|
101
103
|
};
|
|
102
104
|
const renderClearButton = () => {
|
|
103
|
-
if (!
|
|
105
|
+
if (!clearText) return null;
|
|
104
106
|
return (0, _jsxRuntime.jsx)("button", {
|
|
105
107
|
type: "button",
|
|
106
108
|
className: (0, _classnames.default)('ncua-input__icon-wrap', 'ncua-input__right-icon', 'ncua-input__clear'),
|
|
107
|
-
onClick:
|
|
109
|
+
onClick: onClearText,
|
|
108
110
|
children: (0, _jsxRuntime.jsx)(_uiAdminIcon.X, {
|
|
109
111
|
className: "ncua-input__clear-icon",
|
|
110
112
|
width: validationSvgSize[size],
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _react = require("react");
|
|
4
|
+
var _client = require("react-dom/client");
|
|
5
|
+
var _testUtils = require("react-dom/test-utils");
|
|
6
|
+
var _vitest = require("vitest");
|
|
7
|
+
var _InputBase = require("../InputBase");
|
|
8
|
+
// @vitest-environment jsdom
|
|
9
|
+
|
|
10
|
+
// React 18에서 act() 사용 시 필요한 플래그 (미설정 시 console.error 경고 발생)
|
|
11
|
+
globalThis.IS_REACT_ACT_ENVIRONMENT = true;
|
|
12
|
+
function mountInputBase() {
|
|
13
|
+
let props = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
14
|
+
const container = document.createElement('div');
|
|
15
|
+
document.body.appendChild(container);
|
|
16
|
+
const root = (0, _client.createRoot)(container);
|
|
17
|
+
(0, _testUtils.act)(() => {
|
|
18
|
+
root.render(/*#__PURE__*/(0, _react.createElement)(_InputBase.InputBase, props));
|
|
19
|
+
});
|
|
20
|
+
const unmount = () => {
|
|
21
|
+
(0, _testUtils.act)(() => {
|
|
22
|
+
root.unmount();
|
|
23
|
+
});
|
|
24
|
+
container.remove();
|
|
25
|
+
};
|
|
26
|
+
return {
|
|
27
|
+
container,
|
|
28
|
+
unmount
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
(0, _vitest.describe)('InputBase — clearText prop DOM 누출', () => {
|
|
32
|
+
(0, _vitest.it)('clearText/onClearText가 DOM input 속성으로 전달되지 않는다', () => {
|
|
33
|
+
// Given: console.error를 감시하는 상태에서
|
|
34
|
+
const consoleErrorSpy = _vitest.vi.spyOn(console, 'error');
|
|
35
|
+
// When: clearText, onClearText를 전달해 렌더하면
|
|
36
|
+
const view = mountInputBase({
|
|
37
|
+
clearText: true,
|
|
38
|
+
onClearText: _vitest.vi.fn()
|
|
39
|
+
});
|
|
40
|
+
// Then: 렌더된 <input>에 cleartext 속성이 없고, unknown prop 경고도 발생하지 않는다
|
|
41
|
+
const input = view.container.querySelector('input');
|
|
42
|
+
(0, _vitest.expect)(input).not.toBeNull();
|
|
43
|
+
(0, _vitest.expect)(input?.hasAttribute('cleartext')).toBe(false);
|
|
44
|
+
(0, _vitest.expect)(consoleErrorSpy).not.toHaveBeenCalled();
|
|
45
|
+
consoleErrorSpy.mockRestore();
|
|
46
|
+
view.unmount();
|
|
47
|
+
});
|
|
48
|
+
(0, _vitest.it)('clearText가 true면 clear 버튼이 렌더되고 클릭 시 onClearText가 호출된다', () => {
|
|
49
|
+
// Given: clearText와 onClearText를 전달해 렌더한 상태에서
|
|
50
|
+
const onClearText = _vitest.vi.fn();
|
|
51
|
+
const view = mountInputBase({
|
|
52
|
+
clearText: true,
|
|
53
|
+
onClearText
|
|
54
|
+
});
|
|
55
|
+
// When: clear 버튼을 찾아 클릭하면
|
|
56
|
+
const clearButton = view.container.querySelector('.ncua-input__clear');
|
|
57
|
+
(0, _vitest.expect)(clearButton).not.toBeNull();
|
|
58
|
+
(0, _testUtils.act)(() => {
|
|
59
|
+
clearButton?.click();
|
|
60
|
+
});
|
|
61
|
+
// Then: onClearText가 호출된다
|
|
62
|
+
(0, _vitest.expect)(onClearText).toHaveBeenCalledTimes(1);
|
|
63
|
+
view.unmount();
|
|
64
|
+
});
|
|
65
|
+
(0, _vitest.it)('clearText를 전달하지 않으면 clear 버튼이 렌더되지 않는다', () => {
|
|
66
|
+
// Given/When: clearText 없이 렌더하면
|
|
67
|
+
const view = mountInputBase();
|
|
68
|
+
// Then: clear 버튼이 존재하지 않는다
|
|
69
|
+
(0, _vitest.expect)(view.container.querySelector('.ncua-input__clear')).toBeNull();
|
|
70
|
+
view.unmount();
|
|
71
|
+
});
|
|
72
|
+
});
|
|
@@ -28,6 +28,8 @@ const InputBase = /*#__PURE__*/forwardRef((_ref, ref) => {
|
|
|
28
28
|
showHelpIcon,
|
|
29
29
|
maxLength,
|
|
30
30
|
showTextCount,
|
|
31
|
+
clearText,
|
|
32
|
+
onClearText,
|
|
31
33
|
className,
|
|
32
34
|
...props
|
|
33
35
|
} = _ref;
|
|
@@ -93,11 +95,11 @@ const InputBase = /*#__PURE__*/forwardRef((_ref, ref) => {
|
|
|
93
95
|
}
|
|
94
96
|
};
|
|
95
97
|
const renderClearButton = () => {
|
|
96
|
-
if (!
|
|
98
|
+
if (!clearText) return null;
|
|
97
99
|
return _jsx("button", {
|
|
98
100
|
type: "button",
|
|
99
101
|
className: classNames('ncua-input__icon-wrap', 'ncua-input__right-icon', 'ncua-input__clear'),
|
|
100
|
-
onClick:
|
|
102
|
+
onClick: onClearText,
|
|
101
103
|
children: _jsx(X, {
|
|
102
104
|
className: "ncua-input__clear-icon",
|
|
103
105
|
width: validationSvgSize[size],
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
// @vitest-environment jsdom
|
|
2
|
+
import { createElement } from 'react';
|
|
3
|
+
import { createRoot } from 'react-dom/client';
|
|
4
|
+
import { act } from 'react-dom/test-utils';
|
|
5
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
6
|
+
import { InputBase } from '../InputBase';
|
|
7
|
+
// React 18에서 act() 사용 시 필요한 플래그 (미설정 시 console.error 경고 발생)
|
|
8
|
+
globalThis.IS_REACT_ACT_ENVIRONMENT = true;
|
|
9
|
+
function mountInputBase() {
|
|
10
|
+
let props = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
11
|
+
const container = document.createElement('div');
|
|
12
|
+
document.body.appendChild(container);
|
|
13
|
+
const root = createRoot(container);
|
|
14
|
+
act(() => {
|
|
15
|
+
root.render(/*#__PURE__*/createElement(InputBase, props));
|
|
16
|
+
});
|
|
17
|
+
const unmount = () => {
|
|
18
|
+
act(() => {
|
|
19
|
+
root.unmount();
|
|
20
|
+
});
|
|
21
|
+
container.remove();
|
|
22
|
+
};
|
|
23
|
+
return {
|
|
24
|
+
container,
|
|
25
|
+
unmount
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
describe('InputBase — clearText prop DOM 누출', () => {
|
|
29
|
+
it('clearText/onClearText가 DOM input 속성으로 전달되지 않는다', () => {
|
|
30
|
+
// Given: console.error를 감시하는 상태에서
|
|
31
|
+
const consoleErrorSpy = vi.spyOn(console, 'error');
|
|
32
|
+
// When: clearText, onClearText를 전달해 렌더하면
|
|
33
|
+
const view = mountInputBase({
|
|
34
|
+
clearText: true,
|
|
35
|
+
onClearText: vi.fn()
|
|
36
|
+
});
|
|
37
|
+
// Then: 렌더된 <input>에 cleartext 속성이 없고, unknown prop 경고도 발생하지 않는다
|
|
38
|
+
const input = view.container.querySelector('input');
|
|
39
|
+
expect(input).not.toBeNull();
|
|
40
|
+
expect(input?.hasAttribute('cleartext')).toBe(false);
|
|
41
|
+
expect(consoleErrorSpy).not.toHaveBeenCalled();
|
|
42
|
+
consoleErrorSpy.mockRestore();
|
|
43
|
+
view.unmount();
|
|
44
|
+
});
|
|
45
|
+
it('clearText가 true면 clear 버튼이 렌더되고 클릭 시 onClearText가 호출된다', () => {
|
|
46
|
+
// Given: clearText와 onClearText를 전달해 렌더한 상태에서
|
|
47
|
+
const onClearText = vi.fn();
|
|
48
|
+
const view = mountInputBase({
|
|
49
|
+
clearText: true,
|
|
50
|
+
onClearText
|
|
51
|
+
});
|
|
52
|
+
// When: clear 버튼을 찾아 클릭하면
|
|
53
|
+
const clearButton = view.container.querySelector('.ncua-input__clear');
|
|
54
|
+
expect(clearButton).not.toBeNull();
|
|
55
|
+
act(() => {
|
|
56
|
+
clearButton?.click();
|
|
57
|
+
});
|
|
58
|
+
// Then: onClearText가 호출된다
|
|
59
|
+
expect(onClearText).toHaveBeenCalledTimes(1);
|
|
60
|
+
view.unmount();
|
|
61
|
+
});
|
|
62
|
+
it('clearText를 전달하지 않으면 clear 버튼이 렌더되지 않는다', () => {
|
|
63
|
+
// Given/When: clearText 없이 렌더하면
|
|
64
|
+
const view = mountInputBase();
|
|
65
|
+
// Then: clear 버튼이 존재하지 않는다
|
|
66
|
+
expect(view.container.querySelector('.ncua-input__clear')).toBeNull();
|
|
67
|
+
view.unmount();
|
|
68
|
+
});
|
|
69
|
+
});
|
|
@@ -13,7 +13,7 @@ const generalSvgSize = {
|
|
|
13
13
|
xs: 14,
|
|
14
14
|
sm: 20,
|
|
15
15
|
};
|
|
16
|
-
const InputBase = forwardRef(({ size = 'xs', required, label, hintText, disabled, fullWidth = false, validation, destructive, leadingElement, trailingElement, showHelpIcon, maxLength, showTextCount, className, ...props }, ref) => {
|
|
16
|
+
const InputBase = forwardRef(({ size = 'xs', required, label, hintText, disabled, fullWidth = false, validation, destructive, leadingElement, trailingElement, showHelpIcon, maxLength, showTextCount, clearText, onClearText, className, ...props }, ref) => {
|
|
17
17
|
const inputRef = useRef(null);
|
|
18
18
|
const [textCount, setTextCount] = useState(0);
|
|
19
19
|
useEffect(() => {
|
|
@@ -59,9 +59,9 @@ const InputBase = forwardRef(({ size = 'xs', required, label, hintText, disabled
|
|
|
59
59
|
}
|
|
60
60
|
};
|
|
61
61
|
const renderClearButton = () => {
|
|
62
|
-
if (!
|
|
62
|
+
if (!clearText)
|
|
63
63
|
return null;
|
|
64
|
-
return (_jsx("button", { type: "button", className: classNames('ncua-input__icon-wrap', 'ncua-input__right-icon', 'ncua-input__clear'), onClick:
|
|
64
|
+
return (_jsx("button", { type: "button", className: classNames('ncua-input__icon-wrap', 'ncua-input__right-icon', 'ncua-input__clear'), onClick: onClearText, children: _jsx(X, { className: "ncua-input__clear-icon", width: validationSvgSize[size], height: validationSvgSize[size] }) }));
|
|
65
65
|
};
|
|
66
66
|
const renderStatusIcon = () => {
|
|
67
67
|
if (destructive) {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
// @vitest-environment jsdom
|
|
2
|
+
import { createElement } from 'react';
|
|
3
|
+
import { createRoot } from 'react-dom/client';
|
|
4
|
+
import { act } from 'react-dom/test-utils';
|
|
5
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
6
|
+
import { InputBase } from '../InputBase';
|
|
7
|
+
// React 18에서 act() 사용 시 필요한 플래그 (미설정 시 console.error 경고 발생)
|
|
8
|
+
globalThis.IS_REACT_ACT_ENVIRONMENT = true;
|
|
9
|
+
function mountInputBase(props = {}) {
|
|
10
|
+
const container = document.createElement('div');
|
|
11
|
+
document.body.appendChild(container);
|
|
12
|
+
const root = createRoot(container);
|
|
13
|
+
act(() => {
|
|
14
|
+
root.render(createElement(InputBase, props));
|
|
15
|
+
});
|
|
16
|
+
const unmount = () => {
|
|
17
|
+
act(() => {
|
|
18
|
+
root.unmount();
|
|
19
|
+
});
|
|
20
|
+
container.remove();
|
|
21
|
+
};
|
|
22
|
+
return { container, unmount };
|
|
23
|
+
}
|
|
24
|
+
describe('InputBase — clearText prop DOM 누출', () => {
|
|
25
|
+
it('clearText/onClearText가 DOM input 속성으로 전달되지 않는다', () => {
|
|
26
|
+
// Given: console.error를 감시하는 상태에서
|
|
27
|
+
const consoleErrorSpy = vi.spyOn(console, 'error');
|
|
28
|
+
// When: clearText, onClearText를 전달해 렌더하면
|
|
29
|
+
const view = mountInputBase({ clearText: true, onClearText: vi.fn() });
|
|
30
|
+
// Then: 렌더된 <input>에 cleartext 속성이 없고, unknown prop 경고도 발생하지 않는다
|
|
31
|
+
const input = view.container.querySelector('input');
|
|
32
|
+
expect(input).not.toBeNull();
|
|
33
|
+
expect(input?.hasAttribute('cleartext')).toBe(false);
|
|
34
|
+
expect(consoleErrorSpy).not.toHaveBeenCalled();
|
|
35
|
+
consoleErrorSpy.mockRestore();
|
|
36
|
+
view.unmount();
|
|
37
|
+
});
|
|
38
|
+
it('clearText가 true면 clear 버튼이 렌더되고 클릭 시 onClearText가 호출된다', () => {
|
|
39
|
+
// Given: clearText와 onClearText를 전달해 렌더한 상태에서
|
|
40
|
+
const onClearText = vi.fn();
|
|
41
|
+
const view = mountInputBase({ clearText: true, onClearText });
|
|
42
|
+
// When: clear 버튼을 찾아 클릭하면
|
|
43
|
+
const clearButton = view.container.querySelector('.ncua-input__clear');
|
|
44
|
+
expect(clearButton).not.toBeNull();
|
|
45
|
+
act(() => {
|
|
46
|
+
clearButton?.click();
|
|
47
|
+
});
|
|
48
|
+
// Then: onClearText가 호출된다
|
|
49
|
+
expect(onClearText).toHaveBeenCalledTimes(1);
|
|
50
|
+
view.unmount();
|
|
51
|
+
});
|
|
52
|
+
it('clearText를 전달하지 않으면 clear 버튼이 렌더되지 않는다', () => {
|
|
53
|
+
// Given/When: clearText 없이 렌더하면
|
|
54
|
+
const view = mountInputBase();
|
|
55
|
+
// Then: clear 버튼이 존재하지 않는다
|
|
56
|
+
expect(view.container.querySelector('.ncua-input__clear')).toBeNull();
|
|
57
|
+
view.unmount();
|
|
58
|
+
});
|
|
59
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|