@reitwagen/design-components 0.6.1 → 0.6.2
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/components/TextInput/TextInput.d.ts +15 -3
- package/dist/components/TextInput/TextInput.d.ts.map +1 -1
- package/dist/components/TextInput/TextInput.js +48 -3
- package/dist/components/TextInput/TextInput.stories.d.ts +6 -0
- package/dist/components/TextInput/TextInput.stories.d.ts.map +1 -1
- package/dist/components/TextInput/TextInput.stories.js +25 -1
- package/dist/index.css +0 -3
- package/package.json +3 -3
|
@@ -4,11 +4,16 @@ import { inputVariants } from "./TextInput.styles";
|
|
|
4
4
|
export type TextInputProps = ComponentPropsWithRef<"input"> & VariantProps<typeof inputVariants> & {
|
|
5
5
|
/**
|
|
6
6
|
* 클리어 버튼이 표시되는 조건
|
|
7
|
-
* - 'never': 표시 안 함
|
|
8
|
-
* - 'while-editing': 입력값이 있을 때만 표시
|
|
7
|
+
* - 'never': 표시 안 함
|
|
8
|
+
* - 'while-editing': 입력값이 있으면서 포커스가 있을 때만 표시 (기본값)
|
|
9
9
|
* - 'always': 항상 표시
|
|
10
10
|
*/
|
|
11
11
|
clearButtonMode?: "always" | "while-editing" | "never";
|
|
12
|
+
/**
|
|
13
|
+
* 입력값의 단위 (예: "km", "원", "%")
|
|
14
|
+
* 입력 필드 오른쪽에 표시됩니다.
|
|
15
|
+
*/
|
|
16
|
+
unit?: string;
|
|
12
17
|
};
|
|
13
18
|
/**
|
|
14
19
|
* `TextInput`: 텍스트 입력을 위한 기본 컴포넌트입니다. FormControl과 함께 사용하면 label, validation 등의 기능을 자동으로 제공받습니다.
|
|
@@ -27,9 +32,16 @@ export type TextInputProps = ComponentPropsWithRef<"input"> & VariantProps<typeo
|
|
|
27
32
|
* <FormControl.Label>이메일</FormControl.Label>
|
|
28
33
|
* <TextInput type="email" />
|
|
29
34
|
* </FormControl>
|
|
35
|
+
*
|
|
36
|
+
* // 단위와 함께 사용
|
|
37
|
+
* <TextInput
|
|
38
|
+
* type="number"
|
|
39
|
+
* unit="km"
|
|
40
|
+
* placeholder="거리를 입력하세요"
|
|
41
|
+
* />
|
|
30
42
|
* ```
|
|
31
43
|
*/
|
|
32
|
-
export declare function TextInput({ variant, disabled, className, clearButtonMode, value: controlledValue, onChange, ...props }: TextInputProps): import("react/jsx-runtime").JSX.Element;
|
|
44
|
+
export declare function TextInput({ variant, disabled, className, clearButtonMode, unit, value: controlledValue, onChange, ...props }: TextInputProps): import("react/jsx-runtime").JSX.Element;
|
|
33
45
|
export declare namespace TextInput {
|
|
34
46
|
var displayName: string;
|
|
35
47
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TextInput.d.ts","sourceRoot":"","sources":["../../../src/components/TextInput/TextInput.tsx"],"names":[],"mappings":"AAEA,OAAO,
|
|
1
|
+
{"version":3,"file":"TextInput.d.ts","sourceRoot":"","sources":["../../../src/components/TextInput/TextInput.tsx"],"names":[],"mappings":"AAEA,OAAO,EAEL,qBAAqB,EAKtB,MAAM,OAAO,CAAC;AACf,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAExD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAQnD,MAAM,MAAM,cAAc,GAAG,qBAAqB,CAAC,OAAO,CAAC,GACzD,YAAY,CAAC,OAAO,aAAa,CAAC,GAAG;IACnC;;;;;OAKG;IACH,eAAe,CAAC,EAAE,QAAQ,GAAG,eAAe,GAAG,OAAO,CAAC;IACvD;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAAC;AAEJ;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,SAAS,CAAC,EACxB,OAAO,EACP,QAAQ,EACR,SAAS,EACT,eAAiC,EACjC,IAAI,EACJ,KAAK,EAAE,eAAe,EACtB,QAAQ,EACR,GAAG,KAAK,EACT,EAAE,cAAc,2CA6GhB;yBAtHe,SAAS"}
|
|
@@ -7,6 +7,10 @@ const react_1 = require("react");
|
|
|
7
7
|
const style_1 = require("../../utils/style");
|
|
8
8
|
const TextInput_styles_1 = require("./TextInput.styles");
|
|
9
9
|
const Icons_1 = require("../Icons");
|
|
10
|
+
const SPACING = {
|
|
11
|
+
GAP_BETWEEN_ELEMENTS: 12,
|
|
12
|
+
RIGHT_PADDING: 16,
|
|
13
|
+
};
|
|
10
14
|
/**
|
|
11
15
|
* `TextInput`: 텍스트 입력을 위한 기본 컴포넌트입니다. FormControl과 함께 사용하면 label, validation 등의 기능을 자동으로 제공받습니다.
|
|
12
16
|
* @see [RDS Storybook: TextInput](https://main--691ac7d6da1eb0c0acb5f3e2.chromatic.com/?path=/docs/components-textinput--docs)
|
|
@@ -24,14 +28,35 @@ const Icons_1 = require("../Icons");
|
|
|
24
28
|
* <FormControl.Label>이메일</FormControl.Label>
|
|
25
29
|
* <TextInput type="email" />
|
|
26
30
|
* </FormControl>
|
|
31
|
+
*
|
|
32
|
+
* // 단위와 함께 사용
|
|
33
|
+
* <TextInput
|
|
34
|
+
* type="number"
|
|
35
|
+
* unit="km"
|
|
36
|
+
* placeholder="거리를 입력하세요"
|
|
37
|
+
* />
|
|
27
38
|
* ```
|
|
28
39
|
*/
|
|
29
|
-
function TextInput({ variant, disabled, className, clearButtonMode = "
|
|
40
|
+
function TextInput({ variant, disabled, className, clearButtonMode = "while-editing", unit, value: controlledValue, onChange, ...props }) {
|
|
30
41
|
const [internalValue, setInternalValue] = (0, react_1.useState)("");
|
|
42
|
+
const [isFocused, setIsFocused] = (0, react_1.useState)(false);
|
|
43
|
+
const [rightContentWidth, setRightContentWidth] = (0, react_1.useState)(0);
|
|
44
|
+
const unitRef = (0, react_1.useRef)(null);
|
|
45
|
+
const clearButtonRef = (0, react_1.useRef)(null);
|
|
31
46
|
const isControlled = controlledValue !== undefined;
|
|
32
47
|
const value = isControlled ? controlledValue : internalValue;
|
|
33
48
|
const isShowClearButton = clearButtonMode === "always" ||
|
|
34
|
-
(clearButtonMode === "while-editing" &&
|
|
49
|
+
(clearButtonMode === "while-editing" &&
|
|
50
|
+
String(value).length > 0 &&
|
|
51
|
+
isFocused);
|
|
52
|
+
const handleFocus = (e) => {
|
|
53
|
+
setIsFocused(true);
|
|
54
|
+
props.onFocus?.(e);
|
|
55
|
+
};
|
|
56
|
+
const handleBlur = (e) => {
|
|
57
|
+
setIsFocused(false);
|
|
58
|
+
props.onBlur?.(e);
|
|
59
|
+
};
|
|
35
60
|
const handleChange = (e) => {
|
|
36
61
|
if (!isControlled) {
|
|
37
62
|
setInternalValue(e.target.value);
|
|
@@ -48,6 +73,26 @@ function TextInput({ variant, disabled, className, clearButtonMode = "never", va
|
|
|
48
73
|
}
|
|
49
74
|
onChange?.(syntheticEvent);
|
|
50
75
|
};
|
|
51
|
-
|
|
76
|
+
(0, react_1.useEffect)(() => {
|
|
77
|
+
let totalWidth = 0;
|
|
78
|
+
if (unit && unitRef.current) {
|
|
79
|
+
totalWidth += unitRef.current.offsetWidth;
|
|
80
|
+
}
|
|
81
|
+
if (isShowClearButton && clearButtonRef.current) {
|
|
82
|
+
if (totalWidth > 0) {
|
|
83
|
+
totalWidth += SPACING.GAP_BETWEEN_ELEMENTS;
|
|
84
|
+
}
|
|
85
|
+
totalWidth += clearButtonRef.current.offsetWidth;
|
|
86
|
+
}
|
|
87
|
+
if (totalWidth > 0) {
|
|
88
|
+
totalWidth += SPACING.RIGHT_PADDING;
|
|
89
|
+
}
|
|
90
|
+
setRightContentWidth(totalWidth);
|
|
91
|
+
}, [unit, isShowClearButton]);
|
|
92
|
+
return ((0, jsx_runtime_1.jsxs)("div", { className: "ui:relative ui:flex-1 ui:flex ui:items-center", children: [(0, jsx_runtime_1.jsx)("input", { disabled: disabled, value: value, onFocus: handleFocus, onBlur: handleBlur, onChange: handleChange, style: {
|
|
93
|
+
paddingRight: rightContentWidth > 0
|
|
94
|
+
? `${rightContentWidth + SPACING.GAP_BETWEEN_ELEMENTS}px`
|
|
95
|
+
: undefined,
|
|
96
|
+
}, className: (0, style_1.cn)((0, TextInput_styles_1.inputVariants)({ variant, disabled, className })), ...props }), (0, jsx_runtime_1.jsxs)("div", { className: "ui:absolute ui:right-4 ui:top-1/2 ui:-translate-y-1/2 ui:flex ui:items-center ui:gap-3", children: [unit && ((0, jsx_runtime_1.jsx)("span", { ref: unitRef, className: "ui:text-gray-500 ui:text-body4 ui:select-none ui:pointer-events-none", children: unit })), isShowClearButton && ((0, jsx_runtime_1.jsx)("button", { ref: clearButtonRef, type: "button", onClick: handleClear, disabled: disabled, onMouseDown: (e) => e.preventDefault(), className: "ui:cursor-pointer disabled:ui:cursor-not-allowed disabled:ui:opacity-50", "aria-label": "Clear input", children: (0, jsx_runtime_1.jsx)(Icons_1.IconCloseCircle, { className: "ui:text-gray-400" }) }))] })] }));
|
|
52
97
|
}
|
|
53
98
|
TextInput.displayName = "TextInput";
|
|
@@ -31,11 +31,17 @@ declare const meta: {
|
|
|
31
31
|
};
|
|
32
32
|
options: string[];
|
|
33
33
|
};
|
|
34
|
+
unit: {
|
|
35
|
+
control: {
|
|
36
|
+
type: "text";
|
|
37
|
+
};
|
|
38
|
+
};
|
|
34
39
|
};
|
|
35
40
|
};
|
|
36
41
|
export default meta;
|
|
37
42
|
type Story = StoryObj<typeof meta>;
|
|
38
43
|
export declare const Default: Story;
|
|
39
44
|
export declare const Error: Story;
|
|
45
|
+
export declare const Unit: Story;
|
|
40
46
|
export declare const DefaultWithClearButton: Story;
|
|
41
47
|
//# sourceMappingURL=TextInput.stories.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TextInput.stories.d.ts","sourceRoot":"","sources":["../../../src/components/TextInput/TextInput.stories.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAQ,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAExC,QAAA,MAAM,IAAI
|
|
1
|
+
{"version":3,"file":"TextInput.stories.d.ts","sourceRoot":"","sources":["../../../src/components/TextInput/TextInput.stories.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAQ,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAExC,QAAA,MAAM,IAAI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAmCwB,CAAC;AAEnC,eAAe,IAAI,CAAC;AACpB,KAAK,KAAK,GAAG,QAAQ,CAAC,OAAO,IAAI,CAAC,CAAC;AAEnC,eAAO,MAAM,OAAO,EAAE,KA2BrB,CAAC;AAEF,eAAO,MAAM,KAAK,EAAE,KA2BnB,CAAC;AAEF,eAAO,MAAM,IAAI,EAAE,KAyBlB,CAAC;AAEF,eAAO,MAAM,sBAAsB,EAAE,KA+BpC,CAAC"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.DefaultWithClearButton = exports.Error = exports.Default = void 0;
|
|
3
|
+
exports.DefaultWithClearButton = exports.Unit = exports.Error = exports.Default = void 0;
|
|
4
4
|
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
5
5
|
const TextInput_1 = require("./TextInput");
|
|
6
6
|
const meta = {
|
|
@@ -34,6 +34,9 @@ TextInput은 한 줄의 텍스트 값을 설정하는데 사용됩니다.
|
|
|
34
34
|
control: { type: "radio" },
|
|
35
35
|
options: ["never", "always", "while-editing"],
|
|
36
36
|
},
|
|
37
|
+
unit: {
|
|
38
|
+
control: { type: "text" },
|
|
39
|
+
},
|
|
37
40
|
},
|
|
38
41
|
};
|
|
39
42
|
exports.default = meta;
|
|
@@ -83,6 +86,27 @@ exports.Error = {
|
|
|
83
86
|
},
|
|
84
87
|
},
|
|
85
88
|
};
|
|
89
|
+
exports.Unit = {
|
|
90
|
+
parameters: {
|
|
91
|
+
layout: "centered",
|
|
92
|
+
docs: {
|
|
93
|
+
description: {
|
|
94
|
+
story: ``,
|
|
95
|
+
},
|
|
96
|
+
},
|
|
97
|
+
},
|
|
98
|
+
render: (props) => ((0, jsx_runtime_1.jsxs)("div", { className: "ui:flex ui:gap-2", children: [(0, jsx_runtime_1.jsx)(TextInput_1.TextInput, { ...props, unit: "km" }), props.children] })),
|
|
99
|
+
args: {
|
|
100
|
+
placeholder: "주행거리를 입력하세요",
|
|
101
|
+
variant: "default",
|
|
102
|
+
},
|
|
103
|
+
argTypes: {
|
|
104
|
+
disabled: {
|
|
105
|
+
control: { type: "boolean" },
|
|
106
|
+
options: ["true", "false"],
|
|
107
|
+
},
|
|
108
|
+
},
|
|
109
|
+
};
|
|
86
110
|
exports.DefaultWithClearButton = {
|
|
87
111
|
parameters: {
|
|
88
112
|
layout: "centered",
|
package/dist/index.css
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@reitwagen/design-components",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.2",
|
|
4
4
|
"sideEffects": [
|
|
5
5
|
"**/*.css"
|
|
6
6
|
],
|
|
@@ -50,8 +50,8 @@
|
|
|
50
50
|
"ts-node": "^10.9.2",
|
|
51
51
|
"typescript": "5.9.2",
|
|
52
52
|
"@reitwagen/eslint-config": "0.0.0",
|
|
53
|
-
"@reitwagen/
|
|
54
|
-
"@reitwagen/
|
|
53
|
+
"@reitwagen/tailwind-config": "0.0.0",
|
|
54
|
+
"@reitwagen/typescript-config": "0.0.0"
|
|
55
55
|
},
|
|
56
56
|
"dependencies": {
|
|
57
57
|
"axios": "^1.13.2",
|