@x-plat/design-system 0.11.0 → 0.13.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/dist/components/AutoResizeTextArea/index.cjs +2 -2
- package/dist/components/AutoResizeTextArea/index.js +2 -2
- package/dist/components/ChatInput/index.cjs +2 -2
- package/dist/components/ChatInput/index.js +2 -2
- package/dist/components/CheckBox/index.cjs +2 -2
- package/dist/components/CheckBox/index.js +2 -2
- package/dist/components/DatePicker/index.cjs +109 -75
- package/dist/components/DatePicker/index.d.cts +19 -0
- package/dist/components/DatePicker/index.d.ts +19 -0
- package/dist/components/DatePicker/index.js +109 -75
- package/dist/components/Dropdown/index.cjs +22 -9
- package/dist/components/Dropdown/index.css +3 -0
- package/dist/components/Dropdown/index.js +22 -9
- package/dist/components/Editor/index.cjs +602 -30
- package/dist/components/Editor/index.css +103 -0
- package/dist/components/Editor/index.d.cts +1 -1
- package/dist/components/Editor/index.d.ts +1 -1
- package/dist/components/Editor/index.js +602 -30
- package/dist/components/FieldMessage/index.cjs +2 -2
- package/dist/components/FieldMessage/index.d.cts +8 -0
- package/dist/components/FieldMessage/index.d.ts +8 -0
- package/dist/components/FieldMessage/index.js +2 -2
- package/dist/components/FileUpload/index.cjs +10 -6
- package/dist/components/FileUpload/index.d.cts +15 -2
- package/dist/components/FileUpload/index.d.ts +15 -2
- package/dist/components/FileUpload/index.js +10 -6
- package/dist/components/ImageSelector/index.cjs +7 -6
- package/dist/components/ImageSelector/index.d.cts +15 -2
- package/dist/components/ImageSelector/index.d.ts +15 -2
- package/dist/components/ImageSelector/index.js +7 -6
- package/dist/components/Input/index.cjs +2 -2
- package/dist/components/Input/index.d.cts +4 -0
- package/dist/components/Input/index.d.ts +4 -0
- package/dist/components/Input/index.js +2 -2
- package/dist/components/PopOver/index.cjs +21 -7
- package/dist/components/PopOver/index.css +3 -0
- package/dist/components/PopOver/index.js +21 -7
- package/dist/components/Radio/index.cjs +2 -2
- package/dist/components/Radio/index.js +2 -2
- package/dist/components/Select/index.cjs +23 -10
- package/dist/components/Select/index.css +3 -0
- package/dist/components/Select/index.d.cts +1 -2
- package/dist/components/Select/index.d.ts +1 -2
- package/dist/components/Select/index.js +23 -10
- package/dist/components/Switch/index.cjs +2 -2
- package/dist/components/Switch/index.js +2 -2
- package/dist/components/TextArea/index.cjs +2 -2
- package/dist/components/TextArea/index.js +2 -2
- package/dist/components/TimePicker/index.cjs +23 -10
- package/dist/components/TimePicker/index.css +3 -0
- package/dist/components/TimePicker/index.js +23 -10
- package/dist/components/index.cjs +751 -124
- package/dist/components/index.css +113 -0
- package/dist/components/index.js +751 -124
- package/dist/index.cjs +751 -124
- package/dist/index.css +113 -0
- package/dist/index.js +751 -124
- package/guidelines/Guidelines.md +12 -0
- package/guidelines/MIGRATION.md +270 -0
- package/guidelines/components/datepicker.md +26 -0
- package/guidelines/components/editor.md +58 -3
- package/guidelines/components/file-media.md +21 -4
- package/package.json +1 -1
|
@@ -166,11 +166,11 @@ var FieldMessage = (props) => {
|
|
|
166
166
|
FieldMessage.displayName = "FieldMessage";
|
|
167
167
|
var FieldMessage_default = FieldMessage;
|
|
168
168
|
var Field = (props) => {
|
|
169
|
-
const { label, required = false, htmlFor, validations, children } = props;
|
|
169
|
+
const { label, required = false, htmlFor, labelId, validations, children } = props;
|
|
170
170
|
const hasMessages = !!validations && validations.length > 0;
|
|
171
171
|
if (!label && !hasMessages) return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_jsx_runtime4.Fragment, { children });
|
|
172
172
|
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "lib-xplat-field", children: [
|
|
173
|
-
label && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("label", { className: "lib-xplat-field-label", htmlFor, children: [
|
|
173
|
+
label && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("label", { className: "lib-xplat-field-label", id: labelId, htmlFor, children: [
|
|
174
174
|
label,
|
|
175
175
|
required && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "required", "aria-hidden": "true", children: "*" })
|
|
176
176
|
] }),
|
|
@@ -31,6 +31,14 @@ interface FieldProps {
|
|
|
31
31
|
required?: boolean;
|
|
32
32
|
/** 라벨의 htmlFor 와 컨트롤의 id 를 잇는 값 */
|
|
33
33
|
htmlFor?: string;
|
|
34
|
+
/**
|
|
35
|
+
* 라벨 자체에 붙일 id.
|
|
36
|
+
*
|
|
37
|
+
* `htmlFor` 로 이을 수 없는 컨트롤 — 달력처럼 포커스 대상이 여럿이라
|
|
38
|
+
* 하나를 고를 수 없는 것 — 이 `role="group"` + `aria-labelledby` 로
|
|
39
|
+
* 라벨을 가리킬 때 쓴다.
|
|
40
|
+
*/
|
|
41
|
+
labelId?: string;
|
|
34
42
|
validations?: Validation[];
|
|
35
43
|
children: React.ReactNode;
|
|
36
44
|
}
|
|
@@ -31,6 +31,14 @@ interface FieldProps {
|
|
|
31
31
|
required?: boolean;
|
|
32
32
|
/** 라벨의 htmlFor 와 컨트롤의 id 를 잇는 값 */
|
|
33
33
|
htmlFor?: string;
|
|
34
|
+
/**
|
|
35
|
+
* 라벨 자체에 붙일 id.
|
|
36
|
+
*
|
|
37
|
+
* `htmlFor` 로 이을 수 없는 컨트롤 — 달력처럼 포커스 대상이 여럿이라
|
|
38
|
+
* 하나를 고를 수 없는 것 — 이 `role="group"` + `aria-labelledby` 로
|
|
39
|
+
* 라벨을 가리킬 때 쓴다.
|
|
40
|
+
*/
|
|
41
|
+
labelId?: string;
|
|
34
42
|
validations?: Validation[];
|
|
35
43
|
children: React.ReactNode;
|
|
36
44
|
}
|
|
@@ -138,11 +138,11 @@ var FieldMessage = (props) => {
|
|
|
138
138
|
FieldMessage.displayName = "FieldMessage";
|
|
139
139
|
var FieldMessage_default = FieldMessage;
|
|
140
140
|
var Field = (props) => {
|
|
141
|
-
const { label, required = false, htmlFor, validations, children } = props;
|
|
141
|
+
const { label, required = false, htmlFor, labelId, validations, children } = props;
|
|
142
142
|
const hasMessages = !!validations && validations.length > 0;
|
|
143
143
|
if (!label && !hasMessages) return /* @__PURE__ */ jsx4(Fragment, { children });
|
|
144
144
|
return /* @__PURE__ */ jsxs3("div", { className: "lib-xplat-field", children: [
|
|
145
|
-
label && /* @__PURE__ */ jsxs3("label", { className: "lib-xplat-field-label", htmlFor, children: [
|
|
145
|
+
label && /* @__PURE__ */ jsxs3("label", { className: "lib-xplat-field-label", id: labelId, htmlFor, children: [
|
|
146
146
|
label,
|
|
147
147
|
required && /* @__PURE__ */ jsx4("span", { className: "required", "aria-hidden": "true", children: "*" })
|
|
148
148
|
] }),
|
|
@@ -1076,11 +1076,11 @@ var FieldMessage = (props) => {
|
|
|
1076
1076
|
};
|
|
1077
1077
|
FieldMessage.displayName = "FieldMessage";
|
|
1078
1078
|
var Field = (props) => {
|
|
1079
|
-
const { label, required = false, htmlFor, validations, children } = props;
|
|
1079
|
+
const { label, required = false, htmlFor, labelId, validations, children } = props;
|
|
1080
1080
|
const hasMessages = !!validations && validations.length > 0;
|
|
1081
1081
|
if (!label && !hasMessages) return /* @__PURE__ */ (0, import_jsx_runtime295.jsx)(import_jsx_runtime295.Fragment, { children });
|
|
1082
1082
|
return /* @__PURE__ */ (0, import_jsx_runtime295.jsxs)("div", { className: "lib-xplat-field", children: [
|
|
1083
|
-
label && /* @__PURE__ */ (0, import_jsx_runtime295.jsxs)("label", { className: "lib-xplat-field-label", htmlFor, children: [
|
|
1083
|
+
label && /* @__PURE__ */ (0, import_jsx_runtime295.jsxs)("label", { className: "lib-xplat-field-label", id: labelId, htmlFor, children: [
|
|
1084
1084
|
label,
|
|
1085
1085
|
required && /* @__PURE__ */ (0, import_jsx_runtime295.jsx)("span", { className: "required", "aria-hidden": "true", children: "*" })
|
|
1086
1086
|
] }),
|
|
@@ -1099,10 +1099,13 @@ var FileUpload = (props) => {
|
|
|
1099
1099
|
multiple = false,
|
|
1100
1100
|
maxSize,
|
|
1101
1101
|
onChange,
|
|
1102
|
-
|
|
1102
|
+
placeholder = "\uD30C\uC77C\uC744 \uB4DC\uB798\uADF8\uD558\uAC70\uB098 \uD074\uB9AD\uD558\uC5EC \uC5C5\uB85C\uB4DC",
|
|
1103
1103
|
description,
|
|
1104
|
-
validations
|
|
1104
|
+
validations,
|
|
1105
|
+
label,
|
|
1106
|
+
required
|
|
1105
1107
|
} = props;
|
|
1108
|
+
const fieldId = import_react.default.useId();
|
|
1106
1109
|
const [isDragOver, setIsDragOver] = import_react.default.useState(false);
|
|
1107
1110
|
const inputRef = import_react.default.useRef(null);
|
|
1108
1111
|
const handleFiles = (fileList) => {
|
|
@@ -1147,6 +1150,7 @@ var FileUpload = (props) => {
|
|
|
1147
1150
|
"input",
|
|
1148
1151
|
{
|
|
1149
1152
|
ref: inputRef,
|
|
1153
|
+
id: fieldId,
|
|
1150
1154
|
type: "file",
|
|
1151
1155
|
accept,
|
|
1152
1156
|
multiple,
|
|
@@ -1155,12 +1159,12 @@ var FileUpload = (props) => {
|
|
|
1155
1159
|
}
|
|
1156
1160
|
),
|
|
1157
1161
|
/* @__PURE__ */ (0, import_jsx_runtime296.jsx)("div", { className: "upload-icon", children: /* @__PURE__ */ (0, import_jsx_runtime296.jsx)(UploadIcon_default, {}) }),
|
|
1158
|
-
/* @__PURE__ */ (0, import_jsx_runtime296.jsx)("p", { className: "upload-label", children:
|
|
1162
|
+
/* @__PURE__ */ (0, import_jsx_runtime296.jsx)("p", { className: "upload-label", children: placeholder }),
|
|
1159
1163
|
description && /* @__PURE__ */ (0, import_jsx_runtime296.jsx)("p", { className: "upload-description", children: description })
|
|
1160
1164
|
]
|
|
1161
1165
|
}
|
|
1162
1166
|
);
|
|
1163
|
-
return /* @__PURE__ */ (0, import_jsx_runtime296.jsx)(Field, { validations, children: control });
|
|
1167
|
+
return /* @__PURE__ */ (0, import_jsx_runtime296.jsx)(Field, { label, required, htmlFor: fieldId, validations, children: control });
|
|
1164
1168
|
};
|
|
1165
1169
|
FileUpload.displayName = "FileUpload";
|
|
1166
1170
|
var FileUpload_default = FileUpload;
|
|
@@ -12,10 +12,23 @@ interface FileUploadProps {
|
|
|
12
12
|
maxSize?: number;
|
|
13
13
|
/** 고른 파일 목록을 준다. maxSize 로 걸러진 것은 빠져 있다 */
|
|
14
14
|
onChange?: (files: File[]) => void;
|
|
15
|
-
/**
|
|
16
|
-
|
|
15
|
+
/**
|
|
16
|
+
* 상자 안 큰 글자.
|
|
17
|
+
*
|
|
18
|
+
* **0.13.0 에서 `label` 이 필드 라벨로 바뀌면서 이 이름으로 옮겨졌다.**
|
|
19
|
+
* DS 전체에서 `placeholder` 는 "빈 컨트롤 안에 보이는 글자" 를 뜻한다.
|
|
20
|
+
*/
|
|
21
|
+
placeholder?: string;
|
|
17
22
|
/** 상자 안 작은 설명 */
|
|
18
23
|
description?: string;
|
|
24
|
+
/**
|
|
25
|
+
* 상자 **위에** 붙는 필드 라벨. 클릭하면 파일 선택창이 열린다.
|
|
26
|
+
*
|
|
27
|
+
* **0.13.0 이전에는 상자 안 글자를 뜻했다.** 그 용도는 `placeholder` 로 옮겼다.
|
|
28
|
+
*/
|
|
29
|
+
label?: React.ReactNode;
|
|
30
|
+
/** 라벨 뒤에 필수 표시(*)를 붙인다 */
|
|
31
|
+
required?: boolean;
|
|
19
32
|
}
|
|
20
33
|
declare const FileUpload: React.FC<FileUploadProps>;
|
|
21
34
|
|
|
@@ -12,10 +12,23 @@ interface FileUploadProps {
|
|
|
12
12
|
maxSize?: number;
|
|
13
13
|
/** 고른 파일 목록을 준다. maxSize 로 걸러진 것은 빠져 있다 */
|
|
14
14
|
onChange?: (files: File[]) => void;
|
|
15
|
-
/**
|
|
16
|
-
|
|
15
|
+
/**
|
|
16
|
+
* 상자 안 큰 글자.
|
|
17
|
+
*
|
|
18
|
+
* **0.13.0 에서 `label` 이 필드 라벨로 바뀌면서 이 이름으로 옮겨졌다.**
|
|
19
|
+
* DS 전체에서 `placeholder` 는 "빈 컨트롤 안에 보이는 글자" 를 뜻한다.
|
|
20
|
+
*/
|
|
21
|
+
placeholder?: string;
|
|
17
22
|
/** 상자 안 작은 설명 */
|
|
18
23
|
description?: string;
|
|
24
|
+
/**
|
|
25
|
+
* 상자 **위에** 붙는 필드 라벨. 클릭하면 파일 선택창이 열린다.
|
|
26
|
+
*
|
|
27
|
+
* **0.13.0 이전에는 상자 안 글자를 뜻했다.** 그 용도는 `placeholder` 로 옮겼다.
|
|
28
|
+
*/
|
|
29
|
+
label?: React.ReactNode;
|
|
30
|
+
/** 라벨 뒤에 필수 표시(*)를 붙인다 */
|
|
31
|
+
required?: boolean;
|
|
19
32
|
}
|
|
20
33
|
declare const FileUpload: React.FC<FileUploadProps>;
|
|
21
34
|
|
|
@@ -1040,11 +1040,11 @@ var FieldMessage = (props) => {
|
|
|
1040
1040
|
};
|
|
1041
1041
|
FieldMessage.displayName = "FieldMessage";
|
|
1042
1042
|
var Field = (props) => {
|
|
1043
|
-
const { label, required = false, htmlFor, validations, children } = props;
|
|
1043
|
+
const { label, required = false, htmlFor, labelId, validations, children } = props;
|
|
1044
1044
|
const hasMessages = !!validations && validations.length > 0;
|
|
1045
1045
|
if (!label && !hasMessages) return /* @__PURE__ */ jsx295(Fragment, { children });
|
|
1046
1046
|
return /* @__PURE__ */ jsxs189("div", { className: "lib-xplat-field", children: [
|
|
1047
|
-
label && /* @__PURE__ */ jsxs189("label", { className: "lib-xplat-field-label", htmlFor, children: [
|
|
1047
|
+
label && /* @__PURE__ */ jsxs189("label", { className: "lib-xplat-field-label", id: labelId, htmlFor, children: [
|
|
1048
1048
|
label,
|
|
1049
1049
|
required && /* @__PURE__ */ jsx295("span", { className: "required", "aria-hidden": "true", children: "*" })
|
|
1050
1050
|
] }),
|
|
@@ -1063,10 +1063,13 @@ var FileUpload = (props) => {
|
|
|
1063
1063
|
multiple = false,
|
|
1064
1064
|
maxSize,
|
|
1065
1065
|
onChange,
|
|
1066
|
-
|
|
1066
|
+
placeholder = "\uD30C\uC77C\uC744 \uB4DC\uB798\uADF8\uD558\uAC70\uB098 \uD074\uB9AD\uD558\uC5EC \uC5C5\uB85C\uB4DC",
|
|
1067
1067
|
description,
|
|
1068
|
-
validations
|
|
1068
|
+
validations,
|
|
1069
|
+
label,
|
|
1070
|
+
required
|
|
1069
1071
|
} = props;
|
|
1072
|
+
const fieldId = React.useId();
|
|
1070
1073
|
const [isDragOver, setIsDragOver] = React.useState(false);
|
|
1071
1074
|
const inputRef = React.useRef(null);
|
|
1072
1075
|
const handleFiles = (fileList) => {
|
|
@@ -1111,6 +1114,7 @@ var FileUpload = (props) => {
|
|
|
1111
1114
|
"input",
|
|
1112
1115
|
{
|
|
1113
1116
|
ref: inputRef,
|
|
1117
|
+
id: fieldId,
|
|
1114
1118
|
type: "file",
|
|
1115
1119
|
accept,
|
|
1116
1120
|
multiple,
|
|
@@ -1119,12 +1123,12 @@ var FileUpload = (props) => {
|
|
|
1119
1123
|
}
|
|
1120
1124
|
),
|
|
1121
1125
|
/* @__PURE__ */ jsx296("div", { className: "upload-icon", children: /* @__PURE__ */ jsx296(UploadIcon_default, {}) }),
|
|
1122
|
-
/* @__PURE__ */ jsx296("p", { className: "upload-label", children:
|
|
1126
|
+
/* @__PURE__ */ jsx296("p", { className: "upload-label", children: placeholder }),
|
|
1123
1127
|
description && /* @__PURE__ */ jsx296("p", { className: "upload-description", children: description })
|
|
1124
1128
|
]
|
|
1125
1129
|
}
|
|
1126
1130
|
);
|
|
1127
|
-
return /* @__PURE__ */ jsx296(Field, { validations, children: control });
|
|
1131
|
+
return /* @__PURE__ */ jsx296(Field, { label, required, htmlFor: fieldId, validations, children: control });
|
|
1128
1132
|
};
|
|
1129
1133
|
FileUpload.displayName = "FileUpload";
|
|
1130
1134
|
var FileUpload_default = FileUpload;
|
|
@@ -1143,11 +1143,11 @@ var FieldMessage = (props) => {
|
|
|
1143
1143
|
};
|
|
1144
1144
|
FieldMessage.displayName = "FieldMessage";
|
|
1145
1145
|
var Field = (props) => {
|
|
1146
|
-
const { label, required = false, htmlFor, validations, children } = props;
|
|
1146
|
+
const { label, required = false, htmlFor, labelId, validations, children } = props;
|
|
1147
1147
|
const hasMessages = !!validations && validations.length > 0;
|
|
1148
1148
|
if (!label && !hasMessages) return /* @__PURE__ */ (0, import_jsx_runtime295.jsx)(import_jsx_runtime295.Fragment, { children });
|
|
1149
1149
|
return /* @__PURE__ */ (0, import_jsx_runtime295.jsxs)("div", { className: "lib-xplat-field", children: [
|
|
1150
|
-
label && /* @__PURE__ */ (0, import_jsx_runtime295.jsxs)("label", { className: "lib-xplat-field-label", htmlFor, children: [
|
|
1150
|
+
label && /* @__PURE__ */ (0, import_jsx_runtime295.jsxs)("label", { className: "lib-xplat-field-label", id: labelId, htmlFor, children: [
|
|
1151
1151
|
label,
|
|
1152
1152
|
required && /* @__PURE__ */ (0, import_jsx_runtime295.jsx)("span", { className: "required", "aria-hidden": "true", children: "*" })
|
|
1153
1153
|
] }),
|
|
@@ -1161,7 +1161,8 @@ var hasError = (validations) => !!validations?.some((v) => v.status === "error")
|
|
|
1161
1161
|
// src/components/ImageSelector/ImageSelector.tsx
|
|
1162
1162
|
var import_jsx_runtime296 = require("react/jsx-runtime");
|
|
1163
1163
|
var ImageSelector = (props) => {
|
|
1164
|
-
const { value,
|
|
1164
|
+
const { value, placeholder, onChange, validations, label, required } = props;
|
|
1165
|
+
const fieldId = import_react.default.useId();
|
|
1165
1166
|
const [previewUrl, setPreviewUrl] = import_react.default.useState();
|
|
1166
1167
|
import_react.default.useEffect(() => {
|
|
1167
1168
|
if (!value) {
|
|
@@ -1191,7 +1192,7 @@ var ImageSelector = (props) => {
|
|
|
1191
1192
|
{
|
|
1192
1193
|
type: "file",
|
|
1193
1194
|
accept: "image/*",
|
|
1194
|
-
id:
|
|
1195
|
+
id: fieldId,
|
|
1195
1196
|
onChange: handleFileChange,
|
|
1196
1197
|
ref: inputRef,
|
|
1197
1198
|
"aria-invalid": hasError(validations) || void 0
|
|
@@ -1203,10 +1204,10 @@ var ImageSelector = (props) => {
|
|
|
1203
1204
|
] }),
|
|
1204
1205
|
/* @__PURE__ */ (0, import_jsx_runtime296.jsx)("div", { className: "content", children: previewUrl ? /* @__PURE__ */ (0, import_jsx_runtime296.jsx)("img", { src: previewUrl, alt: "preview" }) : /* @__PURE__ */ (0, import_jsx_runtime296.jsxs)("div", { className: "skeleton", onClick: handleOpenFileDialog, children: [
|
|
1205
1206
|
/* @__PURE__ */ (0, import_jsx_runtime296.jsx)("div", { className: "icon-wrapper", children: /* @__PURE__ */ (0, import_jsx_runtime296.jsx)(ImageIcon_default, {}) }),
|
|
1206
|
-
/* @__PURE__ */ (0, import_jsx_runtime296.jsx)("div", { className: "label", children:
|
|
1207
|
+
/* @__PURE__ */ (0, import_jsx_runtime296.jsx)("div", { className: "label", children: placeholder || "\uC774\uBBF8\uC9C0 \uCD94\uAC00\uD558\uAE30" })
|
|
1207
1208
|
] }) })
|
|
1208
1209
|
] });
|
|
1209
|
-
return /* @__PURE__ */ (0, import_jsx_runtime296.jsx)(Field, { validations, children: control });
|
|
1210
|
+
return /* @__PURE__ */ (0, import_jsx_runtime296.jsx)(Field, { label, required, htmlFor: fieldId, validations, children: control });
|
|
1210
1211
|
};
|
|
1211
1212
|
ImageSelector.displayName = "ImageSelector";
|
|
1212
1213
|
var ImageSelector_default = ImageSelector;
|
|
@@ -6,8 +6,21 @@ interface ImageSelectorProps {
|
|
|
6
6
|
value?: File;
|
|
7
7
|
/** 컨트롤 아래에 표시할 검증 메시지. DS 폼 컴포넌트 공통 */
|
|
8
8
|
validations?: Validation[];
|
|
9
|
-
/**
|
|
10
|
-
|
|
9
|
+
/**
|
|
10
|
+
* 비어 있을 때 상자 안에 표시할 안내 글자.
|
|
11
|
+
*
|
|
12
|
+
* **0.13.0 에서 `label` 이 필드 라벨로 바뀌면서 이 이름으로 옮겨졌다.**
|
|
13
|
+
* DS 전체에서 `placeholder` 는 "빈 컨트롤 안에 보이는 글자" 를 뜻한다.
|
|
14
|
+
*/
|
|
15
|
+
placeholder?: string;
|
|
16
|
+
/**
|
|
17
|
+
* 상자 **위에** 붙는 필드 라벨. 클릭하면 파일 선택창이 열린다.
|
|
18
|
+
*
|
|
19
|
+
* **0.13.0 이전에는 상자 안 글자를 뜻했다.** 그 용도는 `placeholder` 로 옮겼다.
|
|
20
|
+
*/
|
|
21
|
+
label?: React.ReactNode;
|
|
22
|
+
/** 라벨 뒤에 필수 표시(*)를 붙인다 */
|
|
23
|
+
required?: boolean;
|
|
11
24
|
/** 이미지를 고르거나 지우면 호출된다. 지우면 undefined 가 온다 */
|
|
12
25
|
onChange?: (value: File | undefined) => void;
|
|
13
26
|
}
|
|
@@ -6,8 +6,21 @@ interface ImageSelectorProps {
|
|
|
6
6
|
value?: File;
|
|
7
7
|
/** 컨트롤 아래에 표시할 검증 메시지. DS 폼 컴포넌트 공통 */
|
|
8
8
|
validations?: Validation[];
|
|
9
|
-
/**
|
|
10
|
-
|
|
9
|
+
/**
|
|
10
|
+
* 비어 있을 때 상자 안에 표시할 안내 글자.
|
|
11
|
+
*
|
|
12
|
+
* **0.13.0 에서 `label` 이 필드 라벨로 바뀌면서 이 이름으로 옮겨졌다.**
|
|
13
|
+
* DS 전체에서 `placeholder` 는 "빈 컨트롤 안에 보이는 글자" 를 뜻한다.
|
|
14
|
+
*/
|
|
15
|
+
placeholder?: string;
|
|
16
|
+
/**
|
|
17
|
+
* 상자 **위에** 붙는 필드 라벨. 클릭하면 파일 선택창이 열린다.
|
|
18
|
+
*
|
|
19
|
+
* **0.13.0 이전에는 상자 안 글자를 뜻했다.** 그 용도는 `placeholder` 로 옮겼다.
|
|
20
|
+
*/
|
|
21
|
+
label?: React.ReactNode;
|
|
22
|
+
/** 라벨 뒤에 필수 표시(*)를 붙인다 */
|
|
23
|
+
required?: boolean;
|
|
11
24
|
/** 이미지를 고르거나 지우면 호출된다. 지우면 undefined 가 온다 */
|
|
12
25
|
onChange?: (value: File | undefined) => void;
|
|
13
26
|
}
|
|
@@ -1107,11 +1107,11 @@ var FieldMessage = (props) => {
|
|
|
1107
1107
|
};
|
|
1108
1108
|
FieldMessage.displayName = "FieldMessage";
|
|
1109
1109
|
var Field = (props) => {
|
|
1110
|
-
const { label, required = false, htmlFor, validations, children } = props;
|
|
1110
|
+
const { label, required = false, htmlFor, labelId, validations, children } = props;
|
|
1111
1111
|
const hasMessages = !!validations && validations.length > 0;
|
|
1112
1112
|
if (!label && !hasMessages) return /* @__PURE__ */ jsx295(Fragment, { children });
|
|
1113
1113
|
return /* @__PURE__ */ jsxs189("div", { className: "lib-xplat-field", children: [
|
|
1114
|
-
label && /* @__PURE__ */ jsxs189("label", { className: "lib-xplat-field-label", htmlFor, children: [
|
|
1114
|
+
label && /* @__PURE__ */ jsxs189("label", { className: "lib-xplat-field-label", id: labelId, htmlFor, children: [
|
|
1115
1115
|
label,
|
|
1116
1116
|
required && /* @__PURE__ */ jsx295("span", { className: "required", "aria-hidden": "true", children: "*" })
|
|
1117
1117
|
] }),
|
|
@@ -1125,7 +1125,8 @@ var hasError = (validations) => !!validations?.some((v) => v.status === "error")
|
|
|
1125
1125
|
// src/components/ImageSelector/ImageSelector.tsx
|
|
1126
1126
|
import { jsx as jsx296, jsxs as jsxs190 } from "react/jsx-runtime";
|
|
1127
1127
|
var ImageSelector = (props) => {
|
|
1128
|
-
const { value,
|
|
1128
|
+
const { value, placeholder, onChange, validations, label, required } = props;
|
|
1129
|
+
const fieldId = React.useId();
|
|
1129
1130
|
const [previewUrl, setPreviewUrl] = React.useState();
|
|
1130
1131
|
React.useEffect(() => {
|
|
1131
1132
|
if (!value) {
|
|
@@ -1155,7 +1156,7 @@ var ImageSelector = (props) => {
|
|
|
1155
1156
|
{
|
|
1156
1157
|
type: "file",
|
|
1157
1158
|
accept: "image/*",
|
|
1158
|
-
id:
|
|
1159
|
+
id: fieldId,
|
|
1159
1160
|
onChange: handleFileChange,
|
|
1160
1161
|
ref: inputRef,
|
|
1161
1162
|
"aria-invalid": hasError(validations) || void 0
|
|
@@ -1167,10 +1168,10 @@ var ImageSelector = (props) => {
|
|
|
1167
1168
|
] }),
|
|
1168
1169
|
/* @__PURE__ */ jsx296("div", { className: "content", children: previewUrl ? /* @__PURE__ */ jsx296("img", { src: previewUrl, alt: "preview" }) : /* @__PURE__ */ jsxs190("div", { className: "skeleton", onClick: handleOpenFileDialog, children: [
|
|
1169
1170
|
/* @__PURE__ */ jsx296("div", { className: "icon-wrapper", children: /* @__PURE__ */ jsx296(ImageIcon_default, {}) }),
|
|
1170
|
-
/* @__PURE__ */ jsx296("div", { className: "label", children:
|
|
1171
|
+
/* @__PURE__ */ jsx296("div", { className: "label", children: placeholder || "\uC774\uBBF8\uC9C0 \uCD94\uAC00\uD558\uAE30" })
|
|
1171
1172
|
] }) })
|
|
1172
1173
|
] });
|
|
1173
|
-
return /* @__PURE__ */ jsx296(Field, { validations, children: control });
|
|
1174
|
+
return /* @__PURE__ */ jsx296(Field, { label, required, htmlFor: fieldId, validations, children: control });
|
|
1174
1175
|
};
|
|
1175
1176
|
ImageSelector.displayName = "ImageSelector";
|
|
1176
1177
|
var ImageSelector_default = ImageSelector;
|
|
@@ -178,11 +178,11 @@ var FieldMessage = (props) => {
|
|
|
178
178
|
FieldMessage.displayName = "FieldMessage";
|
|
179
179
|
var FieldMessage_default = FieldMessage;
|
|
180
180
|
var Field = (props) => {
|
|
181
|
-
const { label, required = false, htmlFor, validations, children } = props;
|
|
181
|
+
const { label, required = false, htmlFor, labelId, validations, children } = props;
|
|
182
182
|
const hasMessages = !!validations && validations.length > 0;
|
|
183
183
|
if (!label && !hasMessages) return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_jsx_runtime4.Fragment, { children });
|
|
184
184
|
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "lib-xplat-field", children: [
|
|
185
|
-
label && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("label", { className: "lib-xplat-field-label", htmlFor, children: [
|
|
185
|
+
label && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("label", { className: "lib-xplat-field-label", id: labelId, htmlFor, children: [
|
|
186
186
|
label,
|
|
187
187
|
required && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "required", "aria-hidden": "true", children: "*" })
|
|
188
188
|
] }),
|
|
@@ -23,6 +23,10 @@ interface PasswordInputProps extends Omit<InputAttributes, "size"> {
|
|
|
23
23
|
validations?: Validation[];
|
|
24
24
|
/** 높이와 글자 크기 */
|
|
25
25
|
size?: InputSize;
|
|
26
|
+
/** 컨트롤 위에 붙는 라벨. 클릭하면 입력칸에 포커스가 간다 */
|
|
27
|
+
label?: React.ReactNode;
|
|
28
|
+
/** 라벨 뒤에 필수 표시(*)를 붙인다 */
|
|
29
|
+
required?: boolean;
|
|
26
30
|
reg?: RegExp;
|
|
27
31
|
}
|
|
28
32
|
declare const PasswordInput: React.ForwardRefExoticComponent<PasswordInputProps & React.RefAttributes<HTMLInputElement>>;
|
|
@@ -23,6 +23,10 @@ interface PasswordInputProps extends Omit<InputAttributes, "size"> {
|
|
|
23
23
|
validations?: Validation[];
|
|
24
24
|
/** 높이와 글자 크기 */
|
|
25
25
|
size?: InputSize;
|
|
26
|
+
/** 컨트롤 위에 붙는 라벨. 클릭하면 입력칸에 포커스가 간다 */
|
|
27
|
+
label?: React.ReactNode;
|
|
28
|
+
/** 라벨 뒤에 필수 표시(*)를 붙인다 */
|
|
29
|
+
required?: boolean;
|
|
26
30
|
reg?: RegExp;
|
|
27
31
|
}
|
|
28
32
|
declare const PasswordInput: React.ForwardRefExoticComponent<PasswordInputProps & React.RefAttributes<HTMLInputElement>>;
|
|
@@ -141,11 +141,11 @@ var FieldMessage = (props) => {
|
|
|
141
141
|
FieldMessage.displayName = "FieldMessage";
|
|
142
142
|
var FieldMessage_default = FieldMessage;
|
|
143
143
|
var Field = (props) => {
|
|
144
|
-
const { label, required = false, htmlFor, validations, children } = props;
|
|
144
|
+
const { label, required = false, htmlFor, labelId, validations, children } = props;
|
|
145
145
|
const hasMessages = !!validations && validations.length > 0;
|
|
146
146
|
if (!label && !hasMessages) return /* @__PURE__ */ jsx4(Fragment, { children });
|
|
147
147
|
return /* @__PURE__ */ jsxs3("div", { className: "lib-xplat-field", children: [
|
|
148
|
-
label && /* @__PURE__ */ jsxs3("label", { className: "lib-xplat-field-label", htmlFor, children: [
|
|
148
|
+
label && /* @__PURE__ */ jsxs3("label", { className: "lib-xplat-field-label", id: labelId, htmlFor, children: [
|
|
149
149
|
label,
|
|
150
150
|
required && /* @__PURE__ */ jsx4("span", { className: "required", "aria-hidden": "true", children: "*" })
|
|
151
151
|
] }),
|
|
@@ -51,8 +51,10 @@ var import_react = __toESM(require("react"), 1);
|
|
|
51
51
|
var useAutoPosition = (triggerRef, popRef, enabled = true) => {
|
|
52
52
|
const [position, setPosition] = import_react.default.useState({
|
|
53
53
|
position: {},
|
|
54
|
-
direction: "bottom"
|
|
54
|
+
direction: "bottom",
|
|
55
|
+
repositioning: false
|
|
55
56
|
});
|
|
57
|
+
const placedRef = import_react.default.useRef(false);
|
|
56
58
|
const calculatePosition = import_react.default.useCallback(() => {
|
|
57
59
|
if (!triggerRef.current || !popRef.current) return;
|
|
58
60
|
const triggerRect = triggerRef.current.getBoundingClientRect();
|
|
@@ -77,11 +79,16 @@ var useAutoPosition = (triggerRef, popRef, enabled = true) => {
|
|
|
77
79
|
if (left < 8) left = 8;
|
|
78
80
|
setPosition({
|
|
79
81
|
position: { top, left },
|
|
80
|
-
direction
|
|
82
|
+
direction,
|
|
83
|
+
repositioning: placedRef.current
|
|
81
84
|
});
|
|
85
|
+
placedRef.current = true;
|
|
82
86
|
}, [triggerRef, popRef]);
|
|
83
87
|
import_react.default.useLayoutEffect(() => {
|
|
84
|
-
if (!enabled)
|
|
88
|
+
if (!enabled) {
|
|
89
|
+
placedRef.current = false;
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
85
92
|
calculatePosition();
|
|
86
93
|
const raf = requestAnimationFrame(calculatePosition);
|
|
87
94
|
return () => cancelAnimationFrame(raf);
|
|
@@ -96,11 +103,17 @@ var useAutoPosition = (triggerRef, popRef, enabled = true) => {
|
|
|
96
103
|
}, [calculatePosition, enabled, popRef]);
|
|
97
104
|
import_react.default.useEffect(() => {
|
|
98
105
|
if (!enabled) return;
|
|
99
|
-
|
|
100
|
-
|
|
106
|
+
let raf = 0;
|
|
107
|
+
const onScrollOrResize = () => {
|
|
108
|
+
cancelAnimationFrame(raf);
|
|
109
|
+
raf = requestAnimationFrame(calculatePosition);
|
|
110
|
+
};
|
|
111
|
+
window.addEventListener("resize", onScrollOrResize, { passive: true });
|
|
112
|
+
window.addEventListener("scroll", onScrollOrResize, { passive: true, capture: true });
|
|
101
113
|
return () => {
|
|
102
|
-
|
|
103
|
-
window.removeEventListener("
|
|
114
|
+
cancelAnimationFrame(raf);
|
|
115
|
+
window.removeEventListener("resize", onScrollOrResize);
|
|
116
|
+
window.removeEventListener("scroll", onScrollOrResize, true);
|
|
104
117
|
};
|
|
105
118
|
}, [calculatePosition, enabled]);
|
|
106
119
|
return position;
|
|
@@ -215,6 +228,7 @@ var PopOver = (props) => {
|
|
|
215
228
|
className: clsx_default(
|
|
216
229
|
"lib-xplat-pop-over-content",
|
|
217
230
|
position.direction,
|
|
231
|
+
position.repositioning && "repositioning",
|
|
218
232
|
eventTrigger && "visible"
|
|
219
233
|
),
|
|
220
234
|
ref: popRef,
|
|
@@ -15,8 +15,10 @@ import React from "react";
|
|
|
15
15
|
var useAutoPosition = (triggerRef, popRef, enabled = true) => {
|
|
16
16
|
const [position, setPosition] = React.useState({
|
|
17
17
|
position: {},
|
|
18
|
-
direction: "bottom"
|
|
18
|
+
direction: "bottom",
|
|
19
|
+
repositioning: false
|
|
19
20
|
});
|
|
21
|
+
const placedRef = React.useRef(false);
|
|
20
22
|
const calculatePosition = React.useCallback(() => {
|
|
21
23
|
if (!triggerRef.current || !popRef.current) return;
|
|
22
24
|
const triggerRect = triggerRef.current.getBoundingClientRect();
|
|
@@ -41,11 +43,16 @@ var useAutoPosition = (triggerRef, popRef, enabled = true) => {
|
|
|
41
43
|
if (left < 8) left = 8;
|
|
42
44
|
setPosition({
|
|
43
45
|
position: { top, left },
|
|
44
|
-
direction
|
|
46
|
+
direction,
|
|
47
|
+
repositioning: placedRef.current
|
|
45
48
|
});
|
|
49
|
+
placedRef.current = true;
|
|
46
50
|
}, [triggerRef, popRef]);
|
|
47
51
|
React.useLayoutEffect(() => {
|
|
48
|
-
if (!enabled)
|
|
52
|
+
if (!enabled) {
|
|
53
|
+
placedRef.current = false;
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
49
56
|
calculatePosition();
|
|
50
57
|
const raf = requestAnimationFrame(calculatePosition);
|
|
51
58
|
return () => cancelAnimationFrame(raf);
|
|
@@ -60,11 +67,17 @@ var useAutoPosition = (triggerRef, popRef, enabled = true) => {
|
|
|
60
67
|
}, [calculatePosition, enabled, popRef]);
|
|
61
68
|
React.useEffect(() => {
|
|
62
69
|
if (!enabled) return;
|
|
63
|
-
|
|
64
|
-
|
|
70
|
+
let raf = 0;
|
|
71
|
+
const onScrollOrResize = () => {
|
|
72
|
+
cancelAnimationFrame(raf);
|
|
73
|
+
raf = requestAnimationFrame(calculatePosition);
|
|
74
|
+
};
|
|
75
|
+
window.addEventListener("resize", onScrollOrResize, { passive: true });
|
|
76
|
+
window.addEventListener("scroll", onScrollOrResize, { passive: true, capture: true });
|
|
65
77
|
return () => {
|
|
66
|
-
|
|
67
|
-
window.removeEventListener("
|
|
78
|
+
cancelAnimationFrame(raf);
|
|
79
|
+
window.removeEventListener("resize", onScrollOrResize);
|
|
80
|
+
window.removeEventListener("scroll", onScrollOrResize, true);
|
|
68
81
|
};
|
|
69
82
|
}, [calculatePosition, enabled]);
|
|
70
83
|
return position;
|
|
@@ -179,6 +192,7 @@ var PopOver = (props) => {
|
|
|
179
192
|
className: clsx_default(
|
|
180
193
|
"lib-xplat-pop-over-content",
|
|
181
194
|
position.direction,
|
|
195
|
+
position.repositioning && "repositioning",
|
|
182
196
|
eventTrigger && "visible"
|
|
183
197
|
),
|
|
184
198
|
ref: popRef,
|
|
@@ -177,11 +177,11 @@ var FieldMessage = (props) => {
|
|
|
177
177
|
};
|
|
178
178
|
FieldMessage.displayName = "FieldMessage";
|
|
179
179
|
var Field = (props) => {
|
|
180
|
-
const { label, required = false, htmlFor, validations, children } = props;
|
|
180
|
+
const { label, required = false, htmlFor, labelId, validations, children } = props;
|
|
181
181
|
const hasMessages = !!validations && validations.length > 0;
|
|
182
182
|
if (!label && !hasMessages) return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_jsx_runtime4.Fragment, { children });
|
|
183
183
|
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "lib-xplat-field", children: [
|
|
184
|
-
label && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("label", { className: "lib-xplat-field-label", htmlFor, children: [
|
|
184
|
+
label && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("label", { className: "lib-xplat-field-label", id: labelId, htmlFor, children: [
|
|
185
185
|
label,
|
|
186
186
|
required && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "required", "aria-hidden": "true", children: "*" })
|
|
187
187
|
] }),
|
|
@@ -140,11 +140,11 @@ var FieldMessage = (props) => {
|
|
|
140
140
|
};
|
|
141
141
|
FieldMessage.displayName = "FieldMessage";
|
|
142
142
|
var Field = (props) => {
|
|
143
|
-
const { label, required = false, htmlFor, validations, children } = props;
|
|
143
|
+
const { label, required = false, htmlFor, labelId, validations, children } = props;
|
|
144
144
|
const hasMessages = !!validations && validations.length > 0;
|
|
145
145
|
if (!label && !hasMessages) return /* @__PURE__ */ jsx4(Fragment, { children });
|
|
146
146
|
return /* @__PURE__ */ jsxs3("div", { className: "lib-xplat-field", children: [
|
|
147
|
-
label && /* @__PURE__ */ jsxs3("label", { className: "lib-xplat-field-label", htmlFor, children: [
|
|
147
|
+
label && /* @__PURE__ */ jsxs3("label", { className: "lib-xplat-field-label", id: labelId, htmlFor, children: [
|
|
148
148
|
label,
|
|
149
149
|
required && /* @__PURE__ */ jsx4("span", { className: "required", "aria-hidden": "true", children: "*" })
|
|
150
150
|
] }),
|