@x-plat/design-system 0.12.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.
Files changed (50) hide show
  1. package/dist/components/AutoResizeTextArea/index.cjs +2 -2
  2. package/dist/components/AutoResizeTextArea/index.js +2 -2
  3. package/dist/components/ChatInput/index.cjs +2 -2
  4. package/dist/components/ChatInput/index.js +2 -2
  5. package/dist/components/CheckBox/index.cjs +2 -2
  6. package/dist/components/CheckBox/index.js +2 -2
  7. package/dist/components/DatePicker/index.cjs +109 -75
  8. package/dist/components/DatePicker/index.d.cts +19 -0
  9. package/dist/components/DatePicker/index.d.ts +19 -0
  10. package/dist/components/DatePicker/index.js +109 -75
  11. package/dist/components/Editor/index.css +3 -0
  12. package/dist/components/FieldMessage/index.cjs +2 -2
  13. package/dist/components/FieldMessage/index.d.cts +8 -0
  14. package/dist/components/FieldMessage/index.d.ts +8 -0
  15. package/dist/components/FieldMessage/index.js +2 -2
  16. package/dist/components/FileUpload/index.cjs +10 -6
  17. package/dist/components/FileUpload/index.d.cts +15 -2
  18. package/dist/components/FileUpload/index.d.ts +15 -2
  19. package/dist/components/FileUpload/index.js +10 -6
  20. package/dist/components/ImageSelector/index.cjs +7 -6
  21. package/dist/components/ImageSelector/index.d.cts +15 -2
  22. package/dist/components/ImageSelector/index.d.ts +15 -2
  23. package/dist/components/ImageSelector/index.js +7 -6
  24. package/dist/components/Input/index.cjs +2 -2
  25. package/dist/components/Input/index.d.cts +4 -0
  26. package/dist/components/Input/index.d.ts +4 -0
  27. package/dist/components/Input/index.js +2 -2
  28. package/dist/components/Radio/index.cjs +2 -2
  29. package/dist/components/Radio/index.js +2 -2
  30. package/dist/components/Select/index.cjs +2 -2
  31. package/dist/components/Select/index.d.cts +1 -2
  32. package/dist/components/Select/index.d.ts +1 -2
  33. package/dist/components/Select/index.js +2 -2
  34. package/dist/components/Switch/index.cjs +2 -2
  35. package/dist/components/Switch/index.js +2 -2
  36. package/dist/components/TextArea/index.cjs +2 -2
  37. package/dist/components/TextArea/index.js +2 -2
  38. package/dist/components/TimePicker/index.cjs +2 -2
  39. package/dist/components/TimePicker/index.js +2 -2
  40. package/dist/components/index.cjs +122 -83
  41. package/dist/components/index.css +3 -0
  42. package/dist/components/index.js +122 -83
  43. package/dist/index.cjs +122 -83
  44. package/dist/index.css +3 -0
  45. package/dist/index.js +122 -83
  46. package/guidelines/Guidelines.md +12 -0
  47. package/guidelines/MIGRATION.md +270 -0
  48. package/guidelines/components/datepicker.md +26 -0
  49. package/guidelines/components/file-media.md +21 -4
  50. package/package.json +1 -1
@@ -167,11 +167,11 @@ var FieldMessage = (props) => {
167
167
  FieldMessage.displayName = "FieldMessage";
168
168
  var FieldMessage_default = FieldMessage;
169
169
  var Field = (props) => {
170
- const { label, required = false, htmlFor, validations, children } = props;
170
+ const { label, required = false, htmlFor, labelId, validations, children } = props;
171
171
  const hasMessages = !!validations && validations.length > 0;
172
172
  if (!label && !hasMessages) return /* @__PURE__ */ jsx5(Fragment, { children });
173
173
  return /* @__PURE__ */ jsxs3("div", { className: "lib-xplat-field", children: [
174
- label && /* @__PURE__ */ jsxs3("label", { className: "lib-xplat-field-label", htmlFor, children: [
174
+ label && /* @__PURE__ */ jsxs3("label", { className: "lib-xplat-field-label", id: labelId, htmlFor, children: [
175
175
  label,
176
176
  required && /* @__PURE__ */ jsx5("span", { className: "required", "aria-hidden": "true", children: "*" })
177
177
  ] }),
@@ -1609,8 +1609,12 @@ var SingleDatePicker = (props) => {
1609
1609
  highlightDates = [],
1610
1610
  locale = "ko",
1611
1611
  rangeStart,
1612
- rangeEnd
1612
+ rangeEnd,
1613
+ label,
1614
+ required,
1615
+ validations
1613
1616
  } = props;
1617
+ const labelId = React6.useId();
1614
1618
  const initialYear = value?.getFullYear();
1615
1619
  const initialMonth = value?.getMonth();
1616
1620
  const { year, month, days, goToPrevMonth, goToNextMonth, setYear, setMonth } = useCalendar(
@@ -1673,10 +1677,12 @@ var SingleDatePicker = (props) => {
1673
1677
  const monthLabels = MONTH_LABELS[locale];
1674
1678
  const titleText = pickerMode === "days" ? locale === "ko" ? `${year}\uB144 ${monthLabels[month]}` : `${monthLabels[month]} ${year}` : pickerMode === "months" ? `${year}` : `${yearRangeStart} - ${yearRangeStart + 11}`;
1675
1679
  const hasRange = rangeStart != null && rangeEnd != null;
1676
- return /* @__PURE__ */ jsxs191(
1680
+ const calendar = /* @__PURE__ */ jsxs191(
1677
1681
  "div",
1678
1682
  {
1679
1683
  className: clsx_default("lib-xplat-datepicker", "single"),
1684
+ role: "group",
1685
+ "aria-labelledby": label ? labelId : void 0,
1680
1686
  children: [
1681
1687
  /* @__PURE__ */ jsxs191("div", { className: "datepicker-header", children: [
1682
1688
  /* @__PURE__ */ jsx300("button", { className: "datepicker-nav", onClick: handlePrev, type: "button", children: /* @__PURE__ */ jsx300(ChevronLeftIcon_default, {}) }),
@@ -1697,18 +1703,18 @@ var SingleDatePicker = (props) => {
1697
1703
  y
1698
1704
  );
1699
1705
  }) }),
1700
- pickerMode === "months" && /* @__PURE__ */ jsx300("div", { className: "datepicker-picker-grid", children: monthLabels.map((label, i) => /* @__PURE__ */ jsx300(
1706
+ pickerMode === "months" && /* @__PURE__ */ jsx300("div", { className: "datepicker-picker-grid", children: monthLabels.map((label2, i) => /* @__PURE__ */ jsx300(
1701
1707
  "button",
1702
1708
  {
1703
1709
  type: "button",
1704
1710
  className: clsx_default("datepicker-picker-cell", i === month && "active"),
1705
1711
  onClick: () => handleMonthSelect(i),
1706
- children: label
1712
+ children: label2
1707
1713
  },
1708
1714
  i
1709
1715
  )) }),
1710
1716
  pickerMode === "days" && /* @__PURE__ */ jsxs191(Fragment2, { children: [
1711
- /* @__PURE__ */ jsx300("div", { className: "datepicker-weekdays", children: weekdays.map((label, i) => /* @__PURE__ */ jsx300(
1717
+ /* @__PURE__ */ jsx300("div", { className: "datepicker-weekdays", children: weekdays.map((label2, i) => /* @__PURE__ */ jsx300(
1712
1718
  "div",
1713
1719
  {
1714
1720
  className: clsx_default(
@@ -1716,9 +1722,9 @@ var SingleDatePicker = (props) => {
1716
1722
  i === 0 && "sunday",
1717
1723
  i === 6 && "saturday"
1718
1724
  ),
1719
- children: label
1725
+ children: label2
1720
1726
  },
1721
- label
1727
+ label2
1722
1728
  )) }),
1723
1729
  /* @__PURE__ */ jsx300("div", { className: "datepicker-grid", children: days.map((day, idx) => {
1724
1730
  const t = day.date.getTime();
@@ -1750,6 +1756,7 @@ var SingleDatePicker = (props) => {
1750
1756
  ]
1751
1757
  }
1752
1758
  );
1759
+ return /* @__PURE__ */ jsx300(Field, { label, required, labelId, validations, children: calendar });
1753
1760
  };
1754
1761
  SingleDatePicker.displayName = "SingleDatePicker";
1755
1762
  var SingleDatePicker_default = SingleDatePicker;
@@ -1764,7 +1771,18 @@ var formatDate = (date) => {
1764
1771
  return `${y}/${m}/${d}`;
1765
1772
  };
1766
1773
  var InputDatePicker = (props) => {
1767
- const { value, onChange, minDate, maxDate, disabled, locale = "ko", placeholder } = props;
1774
+ const {
1775
+ value,
1776
+ onChange,
1777
+ minDate,
1778
+ maxDate,
1779
+ disabled,
1780
+ locale = "ko",
1781
+ placeholder,
1782
+ label,
1783
+ required,
1784
+ validations
1785
+ } = props;
1768
1786
  const [isOpen, setIsOpen] = React7.useState(false);
1769
1787
  const [tempDate, setTempDate] = React7.useState(value ?? /* @__PURE__ */ new Date());
1770
1788
  const handleOpen = () => {
@@ -1790,6 +1808,9 @@ var InputDatePicker = (props) => {
1790
1808
  placeholder,
1791
1809
  suffix: /* @__PURE__ */ jsx301(CalenderIcon_default, {}),
1792
1810
  disabled,
1811
+ label,
1812
+ required,
1813
+ validations,
1793
1814
  readOnly: true
1794
1815
  }
1795
1816
  ) }),
@@ -1921,8 +1942,12 @@ var RangePicker = (props) => {
1921
1942
  onChange,
1922
1943
  minDate,
1923
1944
  maxDate,
1924
- locale = "ko"
1945
+ locale = "ko",
1946
+ label,
1947
+ required,
1948
+ validations
1925
1949
  } = props;
1950
+ const labelId = React10.useId();
1926
1951
  const [activeTab, setActiveTab] = React10.useState("start");
1927
1952
  const handleStartChange = (date) => {
1928
1953
  if (!date) return;
@@ -1936,70 +1961,79 @@ var RangePicker = (props) => {
1936
1961
  };
1937
1962
  const startMaxDate = maxDate && endDate < maxDate ? endDate : endDate;
1938
1963
  const endMinDate = minDate && startDate > minDate ? startDate : startDate;
1939
- return /* @__PURE__ */ jsxs194("div", { className: clsx_default("lib-xplat-datepicker", "range"), children: [
1940
- /* @__PURE__ */ jsx304("div", { className: "datepicker-range-tabs", children: /* @__PURE__ */ jsx304(
1941
- Tab_default,
1942
- {
1943
- activeIndex: activeTab === "start" ? 0 : 1,
1944
- tabs: [
1945
- { value: "start", title: locale === "ko" ? "\uC2DC\uC791\uC77C" : "Start" },
1946
- { value: "end", title: locale === "ko" ? "\uC885\uB8CC\uC77C" : "End" }
1947
- ],
1948
- onChange: (tab) => setActiveTab(tab.value),
1949
- type: "toggle",
1950
- size: "sm"
1951
- }
1952
- ) }),
1953
- /* @__PURE__ */ jsxs194("div", { className: "datepicker-range-panels", children: [
1954
- /* @__PURE__ */ jsx304(
1955
- SingleDatePicker_default,
1956
- {
1957
- value: startDate,
1958
- onChange: handleStartChange,
1959
- minDate,
1960
- maxDate: startMaxDate,
1961
- rangeStart: startDate,
1962
- rangeEnd: endDate,
1963
- locale
1964
- }
1965
- ),
1966
- /* @__PURE__ */ jsx304(
1967
- SingleDatePicker_default,
1968
- {
1969
- value: endDate,
1970
- onChange: handleEndChange,
1971
- minDate: endMinDate,
1972
- maxDate,
1973
- rangeStart: startDate,
1974
- rangeEnd: endDate,
1975
- locale
1976
- }
1977
- )
1978
- ] }),
1979
- /* @__PURE__ */ jsx304("div", { className: "datepicker-range-mobile", children: activeTab === "start" ? /* @__PURE__ */ jsx304(
1980
- SingleDatePicker_default,
1981
- {
1982
- value: startDate,
1983
- onChange: handleStartChange,
1984
- minDate,
1985
- maxDate: startMaxDate,
1986
- rangeStart: startDate,
1987
- rangeEnd: endDate,
1988
- locale
1989
- }
1990
- ) : /* @__PURE__ */ jsx304(
1991
- SingleDatePicker_default,
1992
- {
1993
- value: endDate,
1994
- onChange: handleEndChange,
1995
- minDate: endMinDate,
1996
- maxDate,
1997
- rangeStart: startDate,
1998
- rangeEnd: endDate,
1999
- locale
2000
- }
2001
- ) })
2002
- ] });
1964
+ const calendar = /* @__PURE__ */ jsxs194(
1965
+ "div",
1966
+ {
1967
+ className: clsx_default("lib-xplat-datepicker", "range"),
1968
+ role: "group",
1969
+ "aria-labelledby": label ? labelId : void 0,
1970
+ children: [
1971
+ /* @__PURE__ */ jsx304("div", { className: "datepicker-range-tabs", children: /* @__PURE__ */ jsx304(
1972
+ Tab_default,
1973
+ {
1974
+ activeIndex: activeTab === "start" ? 0 : 1,
1975
+ tabs: [
1976
+ { value: "start", title: locale === "ko" ? "\uC2DC\uC791\uC77C" : "Start" },
1977
+ { value: "end", title: locale === "ko" ? "\uC885\uB8CC\uC77C" : "End" }
1978
+ ],
1979
+ onChange: (tab) => setActiveTab(tab.value),
1980
+ type: "toggle",
1981
+ size: "sm"
1982
+ }
1983
+ ) }),
1984
+ /* @__PURE__ */ jsxs194("div", { className: "datepicker-range-panels", children: [
1985
+ /* @__PURE__ */ jsx304(
1986
+ SingleDatePicker_default,
1987
+ {
1988
+ value: startDate,
1989
+ onChange: handleStartChange,
1990
+ minDate,
1991
+ maxDate: startMaxDate,
1992
+ rangeStart: startDate,
1993
+ rangeEnd: endDate,
1994
+ locale
1995
+ }
1996
+ ),
1997
+ /* @__PURE__ */ jsx304(
1998
+ SingleDatePicker_default,
1999
+ {
2000
+ value: endDate,
2001
+ onChange: handleEndChange,
2002
+ minDate: endMinDate,
2003
+ maxDate,
2004
+ rangeStart: startDate,
2005
+ rangeEnd: endDate,
2006
+ locale
2007
+ }
2008
+ )
2009
+ ] }),
2010
+ /* @__PURE__ */ jsx304("div", { className: "datepicker-range-mobile", children: activeTab === "start" ? /* @__PURE__ */ jsx304(
2011
+ SingleDatePicker_default,
2012
+ {
2013
+ value: startDate,
2014
+ onChange: handleStartChange,
2015
+ minDate,
2016
+ maxDate: startMaxDate,
2017
+ rangeStart: startDate,
2018
+ rangeEnd: endDate,
2019
+ locale
2020
+ }
2021
+ ) : /* @__PURE__ */ jsx304(
2022
+ SingleDatePicker_default,
2023
+ {
2024
+ value: endDate,
2025
+ onChange: handleEndChange,
2026
+ minDate: endMinDate,
2027
+ maxDate,
2028
+ rangeStart: startDate,
2029
+ rangeEnd: endDate,
2030
+ locale
2031
+ }
2032
+ ) })
2033
+ ]
2034
+ }
2035
+ );
2036
+ return /* @__PURE__ */ jsx304(Field, { label, required, labelId, validations, children: calendar });
2003
2037
  };
2004
2038
  RangePicker.displayName = "RangePicker";
2005
2039
  var RangePicker_default = RangePicker;
@@ -286,6 +286,9 @@
286
286
  color: var(--semantic-text-inverse);
287
287
  border-color: var(--semantic-surface-brand-default);
288
288
  }
289
+ .lib-xplat-editor.readonly .lib-xplat-editor__editable ul.checklist > li::before {
290
+ cursor: default;
291
+ }
289
292
  .lib-xplat-editor__editable .align-center {
290
293
  text-align: center;
291
294
  }
@@ -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
- label = "\uD30C\uC77C\uC744 \uB4DC\uB798\uADF8\uD558\uAC70\uB098 \uD074\uB9AD\uD558\uC5EC \uC5C5\uB85C\uB4DC",
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: label }),
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
- label?: string;
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
- label?: string;
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
- label = "\uD30C\uC77C\uC744 \uB4DC\uB798\uADF8\uD558\uAC70\uB098 \uD074\uB9AD\uD558\uC5EC \uC5C5\uB85C\uB4DC",
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: label }),
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, label, onChange, validations } = props;
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: "image-input",
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: label || "\uC774\uBBF8\uC9C0 \uCD94\uAC00\uD558\uAE30" })
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
- label?: string;
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
- label?: string;
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, label, onChange, validations } = props;
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: "image-input",
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: label || "\uC774\uBBF8\uC9C0 \uCD94\uAC00\uD558\uAE30" })
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;