@x-plat/design-system 0.10.0 → 0.11.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 (110) hide show
  1. package/dist/components/AutoResizeTextArea/index.cjs +14 -5
  2. package/dist/components/AutoResizeTextArea/index.css +15 -0
  3. package/dist/components/AutoResizeTextArea/index.d.cts +4 -0
  4. package/dist/components/AutoResizeTextArea/index.d.ts +4 -0
  5. package/dist/components/AutoResizeTextArea/index.js +14 -5
  6. package/dist/components/Badge/index.d.cts +1 -1
  7. package/dist/components/Badge/index.d.ts +1 -1
  8. package/dist/components/ChatInput/index.cjs +20 -7
  9. package/dist/components/ChatInput/index.css +15 -0
  10. package/dist/components/ChatInput/index.d.cts +4 -0
  11. package/dist/components/ChatInput/index.d.ts +4 -0
  12. package/dist/components/ChatInput/index.js +20 -7
  13. package/dist/components/CheckBox/index.cjs +8 -3
  14. package/dist/components/CheckBox/index.css +15 -0
  15. package/dist/components/CheckBox/index.d.cts +1 -1
  16. package/dist/components/CheckBox/index.d.ts +1 -1
  17. package/dist/components/CheckBox/index.js +8 -3
  18. package/dist/components/DatePicker/index.cjs +179 -64
  19. package/dist/components/DatePicker/index.css +19 -0
  20. package/dist/components/DatePicker/index.js +179 -64
  21. package/dist/components/Drawer/index.cjs +83 -4
  22. package/dist/components/Drawer/index.js +83 -4
  23. package/dist/components/Dropdown/index.cjs +35 -7
  24. package/dist/components/Dropdown/index.js +35 -7
  25. package/dist/components/Editor/index.cjs +178 -21
  26. package/dist/components/Editor/index.js +178 -21
  27. package/dist/components/FieldMessage/index.cjs +8 -3
  28. package/dist/components/FieldMessage/index.css +15 -0
  29. package/dist/components/FieldMessage/index.d.cts +11 -4
  30. package/dist/components/FieldMessage/index.d.ts +11 -4
  31. package/dist/components/FieldMessage/index.js +8 -3
  32. package/dist/components/FileUpload/index.cjs +8 -3
  33. package/dist/components/FileUpload/index.css +15 -0
  34. package/dist/components/FileUpload/index.js +8 -3
  35. package/dist/components/ImageSelector/index.cjs +8 -3
  36. package/dist/components/ImageSelector/index.css +15 -0
  37. package/dist/components/ImageSelector/index.js +8 -3
  38. package/dist/components/Input/index.cjs +15 -5
  39. package/dist/components/Input/index.css +15 -0
  40. package/dist/components/Input/index.d.cts +4 -0
  41. package/dist/components/Input/index.d.ts +4 -0
  42. package/dist/components/Input/index.js +15 -5
  43. package/dist/components/Modal/index.cjs +84 -5
  44. package/dist/components/Modal/index.js +84 -5
  45. package/dist/components/NotificationBadge/index.d.cts +1 -1
  46. package/dist/components/NotificationBadge/index.d.ts +1 -1
  47. package/dist/components/Pagination/index.d.cts +1 -1
  48. package/dist/components/Pagination/index.d.ts +1 -1
  49. package/dist/components/PopOver/index.cjs +34 -6
  50. package/dist/components/PopOver/index.js +34 -6
  51. package/dist/components/Progress/index.d.cts +1 -1
  52. package/dist/components/Progress/index.d.ts +1 -1
  53. package/dist/components/Radio/index.cjs +8 -3
  54. package/dist/components/Radio/index.css +15 -0
  55. package/dist/components/Radio/index.d.cts +1 -1
  56. package/dist/components/Radio/index.d.ts +1 -1
  57. package/dist/components/Radio/index.js +8 -3
  58. package/dist/components/Select/index.cjs +99 -31
  59. package/dist/components/Select/index.css +54 -0
  60. package/dist/components/Select/index.d.cts +11 -0
  61. package/dist/components/Select/index.d.ts +11 -0
  62. package/dist/components/Select/index.js +99 -31
  63. package/dist/components/Spinner/index.d.cts +1 -1
  64. package/dist/components/Spinner/index.d.ts +1 -1
  65. package/dist/components/Stat/index.cjs +84 -0
  66. package/dist/components/Stat/index.css +96 -0
  67. package/dist/components/Stat/index.d.cts +37 -0
  68. package/dist/components/Stat/index.d.ts +37 -0
  69. package/dist/components/Stat/index.js +57 -0
  70. package/dist/components/Steps/index.d.cts +1 -1
  71. package/dist/components/Steps/index.d.ts +1 -1
  72. package/dist/components/Switch/index.cjs +14 -5
  73. package/dist/components/Switch/index.css +15 -0
  74. package/dist/components/Switch/index.d.cts +6 -1
  75. package/dist/components/Switch/index.d.ts +6 -1
  76. package/dist/components/Switch/index.js +14 -5
  77. package/dist/components/Tab/index.cjs +49 -25
  78. package/dist/components/Tab/index.css +4 -0
  79. package/dist/components/Tab/index.js +49 -25
  80. package/dist/components/TextArea/index.cjs +14 -4
  81. package/dist/components/TextArea/index.css +15 -0
  82. package/dist/components/TextArea/index.d.cts +4 -0
  83. package/dist/components/TextArea/index.d.ts +4 -0
  84. package/dist/components/TextArea/index.js +14 -4
  85. package/dist/components/TimePicker/index.cjs +448 -0
  86. package/dist/components/TimePicker/index.css +172 -0
  87. package/dist/components/TimePicker/index.d.cts +42 -0
  88. package/dist/components/TimePicker/index.d.ts +42 -0
  89. package/dist/components/TimePicker/index.js +411 -0
  90. package/dist/components/index.cjs +873 -359
  91. package/dist/components/index.css +275 -0
  92. package/dist/components/index.d.cts +3 -1
  93. package/dist/components/index.d.ts +3 -1
  94. package/dist/components/index.js +871 -359
  95. package/dist/index.cjs +897 -383
  96. package/dist/index.css +275 -0
  97. package/dist/index.d.cts +3 -1
  98. package/dist/index.d.ts +3 -1
  99. package/dist/index.js +895 -383
  100. package/dist/status-njWqQWFV.d.cts +20 -0
  101. package/dist/status-njWqQWFV.d.ts +20 -0
  102. package/guidelines/AGENT_PROMPT.md +3 -3
  103. package/guidelines/Guidelines.md +3 -0
  104. package/guidelines/components/editor.md +86 -0
  105. package/guidelines/components/form.md +19 -0
  106. package/guidelines/components/stat.md +31 -0
  107. package/guidelines/components/time-picker.md +49 -0
  108. package/package.json +1 -1
  109. package/dist/status-g_KP3qT6.d.cts +0 -8
  110. package/dist/status-g_KP3qT6.d.ts +0 -8
@@ -38,7 +38,7 @@ __export(DatePicker_exports, {
38
38
  module.exports = __toCommonJS(DatePicker_exports);
39
39
 
40
40
  // src/components/DatePicker/InputDatePicker/index.tsx
41
- var import_react6 = __toESM(require("react"), 1);
41
+ var import_react7 = __toESM(require("react"), 1);
42
42
 
43
43
  // ../../node_modules/clsx/dist/clsx.mjs
44
44
  function r(e) {
@@ -206,11 +206,16 @@ var FieldMessage = (props) => {
206
206
  FieldMessage.displayName = "FieldMessage";
207
207
  var FieldMessage_default = FieldMessage;
208
208
  var Field = (props) => {
209
- const { validations, children } = props;
210
- if (!validations || validations.length === 0) return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_jsx_runtime5.Fragment, { children });
209
+ const { label, required = false, htmlFor, validations, children } = props;
210
+ const hasMessages = !!validations && validations.length > 0;
211
+ if (!label && !hasMessages) return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_jsx_runtime5.Fragment, { children });
211
212
  return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "lib-xplat-field", children: [
213
+ label && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("label", { className: "lib-xplat-field-label", htmlFor, children: [
214
+ label,
215
+ required && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "required", "aria-hidden": "true", children: "*" })
216
+ ] }),
212
217
  children,
213
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(FieldMessage, { validations })
218
+ hasMessages && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(FieldMessage, { validations })
214
219
  ] });
215
220
  };
216
221
  Field.displayName = "Field";
@@ -309,8 +314,12 @@ var Input = import_react.default.forwardRef((props, ref) => {
309
314
  suffix,
310
315
  disabled,
311
316
  validations,
317
+ label,
318
+ required,
312
319
  ...inputProps
313
320
  } = props;
321
+ const autoId = import_react.default.useId();
322
+ const fieldId = inputProps.id ?? autoId;
314
323
  const localValue = formatValue(type, value);
315
324
  const handleChange = (e) => {
316
325
  let val = e.target.value;
@@ -326,7 +335,7 @@ var Input = import_react.default.forwardRef((props, ref) => {
326
335
  onChange(event);
327
336
  }
328
337
  };
329
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: clsx_default("lib-xplat-input-wrap", className), children: [
338
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Field, { label, required, htmlFor: fieldId, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: clsx_default("lib-xplat-input-wrap", className), children: [
330
339
  /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
331
340
  "div",
332
341
  {
@@ -337,6 +346,7 @@ var Input = import_react.default.forwardRef((props, ref) => {
337
346
  {
338
347
  ...inputProps,
339
348
  ref,
349
+ id: fieldId,
340
350
  disabled,
341
351
  type: type === "number" ? "text" : type,
342
352
  value: localValue,
@@ -349,7 +359,7 @@ var Input = import_react.default.forwardRef((props, ref) => {
349
359
  }
350
360
  ),
351
361
  /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(FieldMessage_default, { validations })
352
- ] });
362
+ ] }) });
353
363
  });
354
364
  Input.displayName = "Input";
355
365
  var Input_default = Input;
@@ -446,16 +456,96 @@ var PasswordInput = import_react2.default.forwardRef(
446
456
  PasswordInput.displayName = "PasswordInput";
447
457
 
448
458
  // src/components/Modal/Modal.tsx
449
- var import_react3 = __toESM(require("react"), 1);
459
+ var import_react4 = __toESM(require("react"), 1);
450
460
  var import_react_dom = require("react-dom");
461
+
462
+ // src/tokens/hooks/useOverlayKeyboard.ts
463
+ var import_react3 = __toESM(require("react"), 1);
464
+ var FOCUSABLE = [
465
+ "a[href]",
466
+ "button:not([disabled])",
467
+ "input:not([disabled]):not([type='hidden'])",
468
+ "select:not([disabled])",
469
+ "textarea:not([disabled])",
470
+ "[tabindex]:not([tabindex='-1'])"
471
+ ].join(",");
472
+ var focusableIn = (el) => Array.from(el.querySelectorAll(FOCUSABLE)).filter(
473
+ // 화면에 없는 것은 제외 (display:none 등)
474
+ (n) => n.offsetWidth > 0 || n.offsetHeight > 0 || n === document.activeElement
475
+ );
476
+ var useEscapeKey = (enabled, onEscape) => {
477
+ import_react3.default.useEffect(() => {
478
+ if (!enabled) return;
479
+ const onKey = (e) => {
480
+ if (e.key !== "Escape") return;
481
+ if (e.defaultPrevented) return;
482
+ e.preventDefault();
483
+ onEscape();
484
+ };
485
+ document.addEventListener("keydown", onKey);
486
+ return () => document.removeEventListener("keydown", onKey);
487
+ }, [enabled, onEscape]);
488
+ };
489
+ var useFocusTrap = (containerRef, enabled, options = {}) => {
490
+ const { trap = false, initialFocus } = options;
491
+ const restoreRef = import_react3.default.useRef(null);
492
+ import_react3.default.useEffect(() => {
493
+ if (!enabled) return;
494
+ restoreRef.current = document.activeElement;
495
+ const raf = requestAnimationFrame(() => {
496
+ const el = containerRef.current;
497
+ if (!el) return;
498
+ const target = initialFocus?.current ?? focusableIn(el)[0] ?? el;
499
+ if (!target.hasAttribute("tabindex") && !focusableIn(el).includes(target)) {
500
+ target.setAttribute("tabindex", "-1");
501
+ }
502
+ target.focus({ preventScroll: true });
503
+ });
504
+ return () => {
505
+ cancelAnimationFrame(raf);
506
+ const prev = restoreRef.current;
507
+ if (prev && document.contains(prev)) prev.focus({ preventScroll: true });
508
+ };
509
+ }, [enabled, containerRef, initialFocus]);
510
+ import_react3.default.useEffect(() => {
511
+ if (!enabled || !trap) return;
512
+ const onKey = (e) => {
513
+ if (e.key !== "Tab") return;
514
+ const el = containerRef.current;
515
+ if (!el) return;
516
+ const items = focusableIn(el);
517
+ if (items.length === 0) {
518
+ e.preventDefault();
519
+ return;
520
+ }
521
+ const first = items[0];
522
+ const last = items[items.length - 1];
523
+ const active = document.activeElement;
524
+ if (e.shiftKey && (active === first || !el.contains(active))) {
525
+ e.preventDefault();
526
+ last.focus();
527
+ } else if (!e.shiftKey && (active === last || !el.contains(active))) {
528
+ e.preventDefault();
529
+ first.focus();
530
+ }
531
+ };
532
+ document.addEventListener("keydown", onKey);
533
+ return () => document.removeEventListener("keydown", onKey);
534
+ }, [enabled, trap, containerRef]);
535
+ };
536
+
537
+ // src/components/Modal/Modal.tsx
451
538
  var import_jsx_runtime10 = require("react/jsx-runtime");
452
539
  var ANIMATION_DURATION_MS = 200;
453
540
  var Modal = (props) => {
454
541
  const { isOpen, onClose, children } = props;
455
- const [mounted, setMounted] = import_react3.default.useState(false);
456
- const [visible, setVisible] = import_react3.default.useState(false);
457
- const [settled, setSettled] = import_react3.default.useState(false);
458
- import_react3.default.useEffect(() => {
542
+ const [mounted, setMounted] = import_react4.default.useState(false);
543
+ const [visible, setVisible] = import_react4.default.useState(false);
544
+ const [settled, setSettled] = import_react4.default.useState(false);
545
+ const boxRef = import_react4.default.useRef(null);
546
+ useEscapeKey(isOpen, onClose);
547
+ useFocusTrap(boxRef, isOpen && mounted, { trap: true });
548
+ import_react4.default.useEffect(() => {
459
549
  if (isOpen) {
460
550
  setMounted(true);
461
551
  const show = setTimeout(() => setVisible(true), 1);
@@ -482,6 +572,7 @@ var Modal = (props) => {
482
572
  children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
483
573
  "div",
484
574
  {
575
+ ref: boxRef,
485
576
  className: clsx_default("lib-xplat-modal", "modal-box", stateClass, settled && "settled"),
486
577
  role: "dialog",
487
578
  "aria-modal": "true",
@@ -1409,15 +1500,15 @@ var import_jsx_runtime298 = require("react/jsx-runtime");
1409
1500
  var import_jsx_runtime299 = require("react/jsx-runtime");
1410
1501
 
1411
1502
  // src/components/DatePicker/SingleDatePicker/index.tsx
1412
- var import_react5 = __toESM(require("react"), 1);
1503
+ var import_react6 = __toESM(require("react"), 1);
1413
1504
 
1414
1505
  // src/components/Calendar/useCalendar.ts
1415
- var import_react4 = __toESM(require("react"), 1);
1506
+ var import_react5 = __toESM(require("react"), 1);
1416
1507
  var useCalendar = (initialYear, initialMonth) => {
1417
1508
  const today = /* @__PURE__ */ new Date();
1418
- const [year, setYear] = import_react4.default.useState(initialYear ?? today.getFullYear());
1419
- const [month, setMonth] = import_react4.default.useState(initialMonth ?? today.getMonth());
1420
- const days = import_react4.default.useMemo(() => {
1509
+ const [year, setYear] = import_react5.default.useState(initialYear ?? today.getFullYear());
1510
+ const [month, setMonth] = import_react5.default.useState(initialMonth ?? today.getMonth());
1511
+ const days = import_react5.default.useMemo(() => {
1421
1512
  const firstDay = new Date(year, month, 1);
1422
1513
  const lastDay = new Date(year, month + 1, 0);
1423
1514
  const startDayOfWeek = firstDay.getDay();
@@ -1460,7 +1551,7 @@ var useCalendar = (initialYear, initialMonth) => {
1460
1551
  }
1461
1552
  return result;
1462
1553
  }, [year, month]);
1463
- const goToPrevMonth = import_react4.default.useCallback(() => {
1554
+ const goToPrevMonth = import_react5.default.useCallback(() => {
1464
1555
  setMonth((prev) => {
1465
1556
  if (prev === 0) {
1466
1557
  setYear((y) => y - 1);
@@ -1469,7 +1560,7 @@ var useCalendar = (initialYear, initialMonth) => {
1469
1560
  return prev - 1;
1470
1561
  });
1471
1562
  }, []);
1472
- const goToNextMonth = import_react4.default.useCallback(() => {
1563
+ const goToNextMonth = import_react5.default.useCallback(() => {
1473
1564
  setMonth((prev) => {
1474
1565
  if (prev === 11) {
1475
1566
  setYear((y) => y + 1);
@@ -1478,7 +1569,7 @@ var useCalendar = (initialYear, initialMonth) => {
1478
1569
  return prev + 1;
1479
1570
  });
1480
1571
  }, []);
1481
- const goToToday = import_react4.default.useCallback(() => {
1572
+ const goToToday = import_react5.default.useCallback(() => {
1482
1573
  setYear(today.getFullYear());
1483
1574
  setMonth(today.getMonth());
1484
1575
  }, []);
@@ -1513,7 +1604,7 @@ var MONTH_LABELS = {
1513
1604
 
1514
1605
  // src/components/DatePicker/SingleDatePicker/index.tsx
1515
1606
  var import_jsx_runtime300 = require("react/jsx-runtime");
1516
- var DayCell = import_react5.default.memo(
1607
+ var DayCell = import_react6.default.memo(
1517
1608
  ({
1518
1609
  day,
1519
1610
  disabled,
@@ -1565,26 +1656,26 @@ var SingleDatePicker = (props) => {
1565
1656
  initialYear,
1566
1657
  initialMonth
1567
1658
  );
1568
- const [pickerMode, setPickerMode] = import_react5.default.useState("days");
1569
- const [yearRangeStart, setYearRangeStart] = import_react5.default.useState(
1659
+ const [pickerMode, setPickerMode] = import_react6.default.useState("days");
1660
+ const [yearRangeStart, setYearRangeStart] = import_react6.default.useState(
1570
1661
  Math.floor((initialYear ?? (/* @__PURE__ */ new Date()).getFullYear()) / 12) * 12
1571
1662
  );
1572
- const minTime = import_react5.default.useMemo(
1663
+ const minTime = import_react6.default.useMemo(
1573
1664
  () => minDate ? new Date(minDate.getFullYear(), minDate.getMonth(), minDate.getDate()).getTime() : -Infinity,
1574
1665
  [minDate]
1575
1666
  );
1576
- const maxTime = import_react5.default.useMemo(
1667
+ const maxTime = import_react6.default.useMemo(
1577
1668
  () => maxDate ? new Date(maxDate.getFullYear(), maxDate.getMonth(), maxDate.getDate()).getTime() : Infinity,
1578
1669
  [maxDate]
1579
1670
  );
1580
- const highlightSet = import_react5.default.useMemo(() => {
1671
+ const highlightSet = import_react6.default.useMemo(() => {
1581
1672
  const set = /* @__PURE__ */ new Set();
1582
1673
  for (const h of highlightDates) {
1583
1674
  set.add(`${h.getFullYear()}-${h.getMonth()}-${h.getDate()}`);
1584
1675
  }
1585
1676
  return set;
1586
1677
  }, [highlightDates]);
1587
- const handleSelect = import_react5.default.useCallback(
1678
+ const handleSelect = import_react6.default.useCallback(
1588
1679
  (date) => {
1589
1680
  onChange?.(date);
1590
1681
  },
@@ -1713,8 +1804,8 @@ var formatDate = (date) => {
1713
1804
  };
1714
1805
  var InputDatePicker = (props) => {
1715
1806
  const { value, onChange, minDate, maxDate, disabled, locale = "ko", placeholder } = props;
1716
- const [isOpen, setIsOpen] = import_react6.default.useState(false);
1717
- const [tempDate, setTempDate] = import_react6.default.useState(value ?? /* @__PURE__ */ new Date());
1807
+ const [isOpen, setIsOpen] = import_react7.default.useState(false);
1808
+ const [tempDate, setTempDate] = import_react7.default.useState(value ?? /* @__PURE__ */ new Date());
1718
1809
  const handleOpen = () => {
1719
1810
  if (disabled) return;
1720
1811
  setTempDate(value ?? /* @__PURE__ */ new Date());
@@ -1763,23 +1854,27 @@ InputDatePicker.displayName = "InputDatePicker";
1763
1854
  var InputDatePicker_default = InputDatePicker;
1764
1855
 
1765
1856
  // src/components/DatePicker/PopupPicker/index.tsx
1766
- var import_react10 = __toESM(require("react"), 1);
1857
+ var import_react11 = __toESM(require("react"), 1);
1767
1858
 
1768
1859
  // src/components/DatePicker/RangePicker/index.tsx
1769
- var import_react9 = __toESM(require("react"), 1);
1860
+ var import_react10 = __toESM(require("react"), 1);
1770
1861
 
1771
1862
  // src/components/Tab/Tab.tsx
1772
- var import_react8 = __toESM(require("react"), 1);
1863
+ var import_react9 = __toESM(require("react"), 1);
1773
1864
 
1774
1865
  // src/components/Tab/TabItem.tsx
1775
- var import_react7 = __toESM(require("react"), 1);
1866
+ var import_react8 = __toESM(require("react"), 1);
1776
1867
  var import_jsx_runtime302 = require("react/jsx-runtime");
1777
- var TabItem = import_react7.default.forwardRef((props, ref) => {
1868
+ var TabItem = import_react8.default.forwardRef((props, ref) => {
1778
1869
  const { isActive, title, onClick } = props;
1779
1870
  return /* @__PURE__ */ (0, import_jsx_runtime302.jsx)(
1780
- "div",
1871
+ "button",
1781
1872
  {
1782
1873
  ref,
1874
+ type: "button",
1875
+ role: "tab",
1876
+ "aria-selected": isActive,
1877
+ tabIndex: isActive ? 0 : -1,
1783
1878
  className: clsx_default("tab-item", isActive ? "active" : null),
1784
1879
  onClick,
1785
1880
  children: title
@@ -1794,44 +1889,64 @@ var import_jsx_runtime303 = require("react/jsx-runtime");
1794
1889
  var Tab = (props) => {
1795
1890
  const { activeIndex, onChange, tabs, variant, type, size = "md" } = props;
1796
1891
  const shape = variant ?? type ?? "default";
1797
- const [underlineStyle, setUnderlineStyle] = import_react8.default.useState({
1892
+ const [underlineStyle, setUnderlineStyle] = import_react9.default.useState({
1798
1893
  left: 0,
1799
1894
  width: 0
1800
1895
  });
1801
- const itemRefs = import_react8.default.useRef([]);
1896
+ const itemRefs = import_react9.default.useRef([]);
1897
+ const handleKeyDown = (e) => {
1898
+ const last = tabs.length - 1;
1899
+ let next = null;
1900
+ if (e.key === "ArrowRight") next = activeIndex >= last ? 0 : activeIndex + 1;
1901
+ else if (e.key === "ArrowLeft") next = activeIndex <= 0 ? last : activeIndex - 1;
1902
+ else if (e.key === "Home") next = 0;
1903
+ else if (e.key === "End") next = last;
1904
+ if (next === null) return;
1905
+ e.preventDefault();
1906
+ onChange(tabs[next], next);
1907
+ itemRefs.current[next]?.focus();
1908
+ };
1802
1909
  const handleChangeActiveTab = (tabItem, tabIdx) => {
1803
1910
  onChange(tabItem, tabIdx);
1804
1911
  };
1805
- import_react8.default.useEffect(() => {
1912
+ import_react9.default.useEffect(() => {
1806
1913
  const el = itemRefs.current[activeIndex];
1807
1914
  if (el) {
1808
1915
  setUnderlineStyle({ left: el.offsetLeft, width: el.offsetWidth });
1809
1916
  }
1810
1917
  }, [activeIndex, tabs.length]);
1811
- return /* @__PURE__ */ (0, import_jsx_runtime303.jsxs)("div", { className: clsx_default("lib-xplat-tab", `type-${shape}`, size), children: [
1812
- tabs.map((tab, idx) => /* @__PURE__ */ (0, import_jsx_runtime303.jsx)(
1813
- TabItem_default,
1814
- {
1815
- onClick: () => handleChangeActiveTab(tab, idx),
1816
- isActive: activeIndex === idx,
1817
- ref: (el) => {
1818
- itemRefs.current[idx] = el;
1819
- },
1820
- title: tab.title
1821
- },
1822
- `${tab.value}_${idx}`
1823
- )),
1824
- shape === "toggle" && /* @__PURE__ */ (0, import_jsx_runtime303.jsx)(
1825
- "div",
1826
- {
1827
- className: "tab-toggle-underline",
1828
- style: {
1829
- left: underlineStyle.left,
1830
- width: underlineStyle.width
1831
- }
1832
- }
1833
- )
1834
- ] });
1918
+ return /* @__PURE__ */ (0, import_jsx_runtime303.jsxs)(
1919
+ "div",
1920
+ {
1921
+ className: clsx_default("lib-xplat-tab", `type-${shape}`, size),
1922
+ role: "tablist",
1923
+ onKeyDown: handleKeyDown,
1924
+ children: [
1925
+ tabs.map((tab, idx) => /* @__PURE__ */ (0, import_jsx_runtime303.jsx)(
1926
+ TabItem_default,
1927
+ {
1928
+ onClick: () => handleChangeActiveTab(tab, idx),
1929
+ isActive: activeIndex === idx,
1930
+ ref: (el) => {
1931
+ itemRefs.current[idx] = el;
1932
+ },
1933
+ title: tab.title
1934
+ },
1935
+ `${tab.value}_${idx}`
1936
+ )),
1937
+ shape === "toggle" && /* @__PURE__ */ (0, import_jsx_runtime303.jsx)(
1938
+ "div",
1939
+ {
1940
+ className: "tab-toggle-underline",
1941
+ style: {
1942
+ left: underlineStyle.left,
1943
+ width: underlineStyle.width
1944
+ }
1945
+ }
1946
+ )
1947
+ ]
1948
+ }
1949
+ );
1835
1950
  };
1836
1951
  Tab.displayName = "Tab";
1837
1952
  var Tab_default = Tab;
@@ -1847,7 +1962,7 @@ var RangePicker = (props) => {
1847
1962
  maxDate,
1848
1963
  locale = "ko"
1849
1964
  } = props;
1850
- const [activeTab, setActiveTab] = import_react9.default.useState("start");
1965
+ const [activeTab, setActiveTab] = import_react10.default.useState("start");
1851
1966
  const handleStartChange = (date) => {
1852
1967
  if (!date) return;
1853
1968
  const newStart = date > endDate ? endDate : date;
@@ -1932,7 +2047,7 @@ var RangePicker_default = RangePicker;
1932
2047
  var import_jsx_runtime305 = require("react/jsx-runtime");
1933
2048
  var PopupPicker = (props) => {
1934
2049
  const { component, type, locale } = props;
1935
- const [isOpen, setIsOpen] = import_react10.default.useState(false);
2050
+ const [isOpen, setIsOpen] = import_react11.default.useState(false);
1936
2051
  const handleClick = () => setIsOpen(true);
1937
2052
  const handleClose = () => setIsOpen(false);
1938
2053
  const handleSingleChange = (date) => {
@@ -1941,7 +2056,7 @@ var PopupPicker = (props) => {
1941
2056
  handleClose();
1942
2057
  };
1943
2058
  return /* @__PURE__ */ (0, import_jsx_runtime305.jsxs)("div", { className: "lib-xplat-popup-datepicker", children: [
1944
- import_react10.default.cloneElement(component, { onClick: handleClick }),
2059
+ import_react11.default.cloneElement(component, { onClick: handleClick }),
1945
2060
  /* @__PURE__ */ (0, import_jsx_runtime305.jsx)(Modal_default, { isOpen, onClose: handleClose, children: /* @__PURE__ */ (0, import_jsx_runtime305.jsxs)("div", { className: clsx_default("lib-xplat-popup-datepicker-card", type === "range" && "range-mode"), children: [
1946
2061
  /* @__PURE__ */ (0, import_jsx_runtime305.jsxs)("div", { className: "popup-datepicker-content", children: [
1947
2062
  type === "single" && /* @__PURE__ */ (0, import_jsx_runtime305.jsx)(
@@ -111,6 +111,21 @@
111
111
  flex-direction: column;
112
112
  gap: var(--spacing-space-2);
113
113
  }
114
+ .lib-xplat-field-label {
115
+ font-family: var(--semantic-typo-label-2-m-font);
116
+ font-size: var(--semantic-typo-label-2-m-size);
117
+ line-height: var(--semantic-typo-label-2-m-lh);
118
+ font-weight: var(--semantic-typo-label-2-m-weight);
119
+ letter-spacing: var(--semantic-typo-label-2-m-ls);
120
+ color: var(--semantic-text-secondary);
121
+ display: inline-flex;
122
+ align-items: center;
123
+ gap: var(--spacing-space-1);
124
+ cursor: pointer;
125
+ }
126
+ .lib-xplat-field-label > .required {
127
+ color: var(--semantic-text-error);
128
+ }
114
129
  .lib-xplat-field-message-wrap {
115
130
  display: flex;
116
131
  gap: var(--spacing-space-2);
@@ -574,6 +589,10 @@
574
589
  border-radius: var(--spacing-radius-md);
575
590
  }
576
591
  .lib-xplat-tab.type-default > .tab-item {
592
+ appearance: none;
593
+ font: inherit;
594
+ border: none;
595
+ background: none;
577
596
  flex: 1;
578
597
  padding: var(--spacing-space-1) var(--spacing-space-6);
579
598
  height: 100%;