@x-plat/design-system 0.10.0 → 0.12.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 (115) 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 +57 -16
  24. package/dist/components/Dropdown/index.css +3 -0
  25. package/dist/components/Dropdown/index.js +57 -16
  26. package/dist/components/Editor/index.cjs +779 -50
  27. package/dist/components/Editor/index.css +100 -0
  28. package/dist/components/Editor/index.d.cts +1 -1
  29. package/dist/components/Editor/index.d.ts +1 -1
  30. package/dist/components/Editor/index.js +779 -50
  31. package/dist/components/FieldMessage/index.cjs +8 -3
  32. package/dist/components/FieldMessage/index.css +15 -0
  33. package/dist/components/FieldMessage/index.d.cts +11 -4
  34. package/dist/components/FieldMessage/index.d.ts +11 -4
  35. package/dist/components/FieldMessage/index.js +8 -3
  36. package/dist/components/FileUpload/index.cjs +8 -3
  37. package/dist/components/FileUpload/index.css +15 -0
  38. package/dist/components/FileUpload/index.js +8 -3
  39. package/dist/components/ImageSelector/index.cjs +8 -3
  40. package/dist/components/ImageSelector/index.css +15 -0
  41. package/dist/components/ImageSelector/index.js +8 -3
  42. package/dist/components/Input/index.cjs +15 -5
  43. package/dist/components/Input/index.css +15 -0
  44. package/dist/components/Input/index.d.cts +4 -0
  45. package/dist/components/Input/index.d.ts +4 -0
  46. package/dist/components/Input/index.js +15 -5
  47. package/dist/components/Modal/index.cjs +84 -5
  48. package/dist/components/Modal/index.js +84 -5
  49. package/dist/components/NotificationBadge/index.d.cts +1 -1
  50. package/dist/components/NotificationBadge/index.d.ts +1 -1
  51. package/dist/components/Pagination/index.d.cts +1 -1
  52. package/dist/components/Pagination/index.d.ts +1 -1
  53. package/dist/components/PopOver/index.cjs +55 -13
  54. package/dist/components/PopOver/index.css +3 -0
  55. package/dist/components/PopOver/index.js +55 -13
  56. package/dist/components/Progress/index.d.cts +1 -1
  57. package/dist/components/Progress/index.d.ts +1 -1
  58. package/dist/components/Radio/index.cjs +8 -3
  59. package/dist/components/Radio/index.css +15 -0
  60. package/dist/components/Radio/index.d.cts +1 -1
  61. package/dist/components/Radio/index.d.ts +1 -1
  62. package/dist/components/Radio/index.js +8 -3
  63. package/dist/components/Select/index.cjs +120 -39
  64. package/dist/components/Select/index.css +57 -0
  65. package/dist/components/Select/index.d.cts +11 -0
  66. package/dist/components/Select/index.d.ts +11 -0
  67. package/dist/components/Select/index.js +120 -39
  68. package/dist/components/Spinner/index.d.cts +1 -1
  69. package/dist/components/Spinner/index.d.ts +1 -1
  70. package/dist/components/Stat/index.cjs +84 -0
  71. package/dist/components/Stat/index.css +96 -0
  72. package/dist/components/Stat/index.d.cts +37 -0
  73. package/dist/components/Stat/index.d.ts +37 -0
  74. package/dist/components/Stat/index.js +57 -0
  75. package/dist/components/Steps/index.d.cts +1 -1
  76. package/dist/components/Steps/index.d.ts +1 -1
  77. package/dist/components/Switch/index.cjs +14 -5
  78. package/dist/components/Switch/index.css +15 -0
  79. package/dist/components/Switch/index.d.cts +6 -1
  80. package/dist/components/Switch/index.d.ts +6 -1
  81. package/dist/components/Switch/index.js +14 -5
  82. package/dist/components/Tab/index.cjs +49 -25
  83. package/dist/components/Tab/index.css +4 -0
  84. package/dist/components/Tab/index.js +49 -25
  85. package/dist/components/TextArea/index.cjs +14 -4
  86. package/dist/components/TextArea/index.css +15 -0
  87. package/dist/components/TextArea/index.d.cts +4 -0
  88. package/dist/components/TextArea/index.d.ts +4 -0
  89. package/dist/components/TextArea/index.js +14 -4
  90. package/dist/components/TimePicker/index.cjs +461 -0
  91. package/dist/components/TimePicker/index.css +175 -0
  92. package/dist/components/TimePicker/index.d.cts +42 -0
  93. package/dist/components/TimePicker/index.d.ts +42 -0
  94. package/dist/components/TimePicker/index.js +424 -0
  95. package/dist/components/index.cjs +1500 -398
  96. package/dist/components/index.css +385 -0
  97. package/dist/components/index.d.cts +3 -1
  98. package/dist/components/index.d.ts +3 -1
  99. package/dist/components/index.js +1498 -398
  100. package/dist/index.cjs +1524 -422
  101. package/dist/index.css +385 -0
  102. package/dist/index.d.cts +3 -1
  103. package/dist/index.d.ts +3 -1
  104. package/dist/index.js +1522 -422
  105. package/dist/status-njWqQWFV.d.cts +20 -0
  106. package/dist/status-njWqQWFV.d.ts +20 -0
  107. package/guidelines/AGENT_PROMPT.md +3 -3
  108. package/guidelines/Guidelines.md +3 -0
  109. package/guidelines/components/editor.md +141 -0
  110. package/guidelines/components/form.md +19 -0
  111. package/guidelines/components/stat.md +31 -0
  112. package/guidelines/components/time-picker.md +49 -0
  113. package/package.json +1 -1
  114. package/dist/status-g_KP3qT6.d.cts +0 -8
  115. package/dist/status-g_KP3qT6.d.ts +0 -8
package/dist/index.js CHANGED
@@ -5622,11 +5622,16 @@ var FieldMessage = (props) => {
5622
5622
  FieldMessage.displayName = "FieldMessage";
5623
5623
  var FieldMessage_default = FieldMessage;
5624
5624
  var Field = (props) => {
5625
- const { validations, children } = props;
5626
- if (!validations || validations.length === 0) return /* @__PURE__ */ jsx297(Fragment, { children });
5625
+ const { label, required = false, htmlFor, validations, children } = props;
5626
+ const hasMessages = !!validations && validations.length > 0;
5627
+ if (!label && !hasMessages) return /* @__PURE__ */ jsx297(Fragment, { children });
5627
5628
  return /* @__PURE__ */ jsxs191("div", { className: "lib-xplat-field", children: [
5629
+ label && /* @__PURE__ */ jsxs191("label", { className: "lib-xplat-field-label", htmlFor, children: [
5630
+ label,
5631
+ required && /* @__PURE__ */ jsx297("span", { className: "required", "aria-hidden": "true", children: "*" })
5632
+ ] }),
5628
5633
  children,
5629
- /* @__PURE__ */ jsx297(FieldMessage, { validations })
5634
+ hasMessages && /* @__PURE__ */ jsx297(FieldMessage, { validations })
5630
5635
  ] });
5631
5636
  };
5632
5637
  Field.displayName = "Field";
@@ -5637,7 +5642,9 @@ import { jsx as jsx298 } from "react/jsx-runtime";
5637
5642
  var MAX_HEIGHT = 400;
5638
5643
  var AutoResizeTextArea = React2.forwardRef(
5639
5644
  (props, ref) => {
5640
- const { value, className, onChange, disabled, bare = false, validations, ...textareaProps } = props;
5645
+ const { value, className, onChange, disabled, bare = false, validations, label, required, ...textareaProps } = props;
5646
+ const autoId = React2.useId();
5647
+ const fieldId = props.id ?? autoId;
5641
5648
  const localRef = React2.useRef(null);
5642
5649
  const setRefs = (el) => {
5643
5650
  localRef.current = el;
@@ -5671,6 +5678,7 @@ var AutoResizeTextArea = React2.forwardRef(
5671
5678
  "aria-invalid": hasError(validations) || void 0,
5672
5679
  ...textareaProps,
5673
5680
  ref: setRefs,
5681
+ id: fieldId,
5674
5682
  className,
5675
5683
  disabled,
5676
5684
  value,
@@ -5684,12 +5692,13 @@ var AutoResizeTextArea = React2.forwardRef(
5684
5692
  "aria-invalid": hasError(validations) || void 0,
5685
5693
  ...textareaProps,
5686
5694
  ref: setRefs,
5695
+ id: fieldId,
5687
5696
  disabled,
5688
5697
  value,
5689
5698
  onChange: handleChange
5690
5699
  }
5691
5700
  ) }) });
5692
- return /* @__PURE__ */ jsx298(Field, { validations, children: control });
5701
+ return /* @__PURE__ */ jsx298(Field, { validations, label, required, htmlFor: fieldId, children: control });
5693
5702
  }
5694
5703
  );
5695
5704
  AutoResizeTextArea.displayName = "AutoResizeTextArea";
@@ -6907,8 +6916,11 @@ var ChatInput = React7.forwardRef(
6907
6916
  buttonType = "primary",
6908
6917
  onSubmit,
6909
6918
  onChange,
6910
- validations
6919
+ validations,
6920
+ label,
6921
+ required
6911
6922
  } = props;
6923
+ const fieldId = React7.useId();
6912
6924
  const isControlled = valueProp !== void 0;
6913
6925
  const [internalValue, setInternalValue] = React7.useState("");
6914
6926
  const value = isControlled ? valueProp : internalValue;
@@ -6933,6 +6945,7 @@ var ChatInput = React7.forwardRef(
6933
6945
  /* @__PURE__ */ jsx308(
6934
6946
  AutoResizeTextArea_default,
6935
6947
  {
6948
+ id: fieldId,
6936
6949
  ref,
6937
6950
  bare: true,
6938
6951
  className: "chat-input-textarea",
@@ -6957,7 +6970,7 @@ var ChatInput = React7.forwardRef(
6957
6970
  }
6958
6971
  )
6959
6972
  ] });
6960
- return /* @__PURE__ */ jsx308(Field, { validations, children: control });
6973
+ return /* @__PURE__ */ jsx308(Field, { validations, label, required, htmlFor: fieldId, children: control });
6961
6974
  }
6962
6975
  );
6963
6976
  ChatInput.displayName = "ChatInput";
@@ -7041,7 +7054,7 @@ Chip.displayName = "Chip";
7041
7054
  var Chip_default = Chip;
7042
7055
 
7043
7056
  // src/components/DatePicker/InputDatePicker/index.tsx
7044
- import React12 from "react";
7057
+ import React13 from "react";
7045
7058
 
7046
7059
  // src/components/Input/Input.tsx
7047
7060
  import React8 from "react";
@@ -7139,8 +7152,12 @@ var Input = React8.forwardRef((props, ref) => {
7139
7152
  suffix,
7140
7153
  disabled,
7141
7154
  validations,
7155
+ label,
7156
+ required,
7142
7157
  ...inputProps
7143
7158
  } = props;
7159
+ const autoId = React8.useId();
7160
+ const fieldId = inputProps.id ?? autoId;
7144
7161
  const localValue = formatValue(type, value);
7145
7162
  const handleChange = (e) => {
7146
7163
  let val = e.target.value;
@@ -7156,7 +7173,7 @@ var Input = React8.forwardRef((props, ref) => {
7156
7173
  onChange(event);
7157
7174
  }
7158
7175
  };
7159
- return /* @__PURE__ */ jsxs199("div", { className: clsx_default("lib-xplat-input-wrap", className), children: [
7176
+ return /* @__PURE__ */ jsx311(Field, { label, required, htmlFor: fieldId, children: /* @__PURE__ */ jsxs199("div", { className: clsx_default("lib-xplat-input-wrap", className), children: [
7160
7177
  /* @__PURE__ */ jsxs199(
7161
7178
  "div",
7162
7179
  {
@@ -7167,6 +7184,7 @@ var Input = React8.forwardRef((props, ref) => {
7167
7184
  {
7168
7185
  ...inputProps,
7169
7186
  ref,
7187
+ id: fieldId,
7170
7188
  disabled,
7171
7189
  type: type === "number" ? "text" : type,
7172
7190
  value: localValue,
@@ -7179,7 +7197,7 @@ var Input = React8.forwardRef((props, ref) => {
7179
7197
  }
7180
7198
  ),
7181
7199
  /* @__PURE__ */ jsx311(FieldMessage_default, { validations })
7182
- ] });
7200
+ ] }) });
7183
7201
  });
7184
7202
  Input.displayName = "Input";
7185
7203
  var Input_default = Input;
@@ -7209,16 +7227,96 @@ PasswordInput.displayName = "PasswordInput";
7209
7227
  var PasswordInput_default = PasswordInput;
7210
7228
 
7211
7229
  // src/components/Modal/Modal.tsx
7212
- import React10 from "react";
7230
+ import React11 from "react";
7213
7231
  import { createPortal } from "react-dom";
7232
+
7233
+ // src/tokens/hooks/useOverlayKeyboard.ts
7234
+ import React10 from "react";
7235
+ var FOCUSABLE = [
7236
+ "a[href]",
7237
+ "button:not([disabled])",
7238
+ "input:not([disabled]):not([type='hidden'])",
7239
+ "select:not([disabled])",
7240
+ "textarea:not([disabled])",
7241
+ "[tabindex]:not([tabindex='-1'])"
7242
+ ].join(",");
7243
+ var focusableIn = (el) => Array.from(el.querySelectorAll(FOCUSABLE)).filter(
7244
+ // 화면에 없는 것은 제외 (display:none 등)
7245
+ (n) => n.offsetWidth > 0 || n.offsetHeight > 0 || n === document.activeElement
7246
+ );
7247
+ var useEscapeKey = (enabled, onEscape) => {
7248
+ React10.useEffect(() => {
7249
+ if (!enabled) return;
7250
+ const onKey = (e) => {
7251
+ if (e.key !== "Escape") return;
7252
+ if (e.defaultPrevented) return;
7253
+ e.preventDefault();
7254
+ onEscape();
7255
+ };
7256
+ document.addEventListener("keydown", onKey);
7257
+ return () => document.removeEventListener("keydown", onKey);
7258
+ }, [enabled, onEscape]);
7259
+ };
7260
+ var useFocusTrap = (containerRef, enabled, options = {}) => {
7261
+ const { trap = false, initialFocus } = options;
7262
+ const restoreRef = React10.useRef(null);
7263
+ React10.useEffect(() => {
7264
+ if (!enabled) return;
7265
+ restoreRef.current = document.activeElement;
7266
+ const raf = requestAnimationFrame(() => {
7267
+ const el = containerRef.current;
7268
+ if (!el) return;
7269
+ const target = initialFocus?.current ?? focusableIn(el)[0] ?? el;
7270
+ if (!target.hasAttribute("tabindex") && !focusableIn(el).includes(target)) {
7271
+ target.setAttribute("tabindex", "-1");
7272
+ }
7273
+ target.focus({ preventScroll: true });
7274
+ });
7275
+ return () => {
7276
+ cancelAnimationFrame(raf);
7277
+ const prev = restoreRef.current;
7278
+ if (prev && document.contains(prev)) prev.focus({ preventScroll: true });
7279
+ };
7280
+ }, [enabled, containerRef, initialFocus]);
7281
+ React10.useEffect(() => {
7282
+ if (!enabled || !trap) return;
7283
+ const onKey = (e) => {
7284
+ if (e.key !== "Tab") return;
7285
+ const el = containerRef.current;
7286
+ if (!el) return;
7287
+ const items = focusableIn(el);
7288
+ if (items.length === 0) {
7289
+ e.preventDefault();
7290
+ return;
7291
+ }
7292
+ const first = items[0];
7293
+ const last = items[items.length - 1];
7294
+ const active = document.activeElement;
7295
+ if (e.shiftKey && (active === first || !el.contains(active))) {
7296
+ e.preventDefault();
7297
+ last.focus();
7298
+ } else if (!e.shiftKey && (active === last || !el.contains(active))) {
7299
+ e.preventDefault();
7300
+ first.focus();
7301
+ }
7302
+ };
7303
+ document.addEventListener("keydown", onKey);
7304
+ return () => document.removeEventListener("keydown", onKey);
7305
+ }, [enabled, trap, containerRef]);
7306
+ };
7307
+
7308
+ // src/components/Modal/Modal.tsx
7214
7309
  import { jsx as jsx313 } from "react/jsx-runtime";
7215
7310
  var ANIMATION_DURATION_MS = 200;
7216
7311
  var Modal = (props) => {
7217
7312
  const { isOpen, onClose, children } = props;
7218
- const [mounted, setMounted] = React10.useState(false);
7219
- const [visible, setVisible] = React10.useState(false);
7220
- const [settled, setSettled] = React10.useState(false);
7221
- React10.useEffect(() => {
7313
+ const [mounted, setMounted] = React11.useState(false);
7314
+ const [visible, setVisible] = React11.useState(false);
7315
+ const [settled, setSettled] = React11.useState(false);
7316
+ const boxRef = React11.useRef(null);
7317
+ useEscapeKey(isOpen, onClose);
7318
+ useFocusTrap(boxRef, isOpen && mounted, { trap: true });
7319
+ React11.useEffect(() => {
7222
7320
  if (isOpen) {
7223
7321
  setMounted(true);
7224
7322
  const show = setTimeout(() => setVisible(true), 1);
@@ -7245,6 +7343,7 @@ var Modal = (props) => {
7245
7343
  children: /* @__PURE__ */ jsx313(
7246
7344
  "div",
7247
7345
  {
7346
+ ref: boxRef,
7248
7347
  className: clsx_default("lib-xplat-modal", "modal-box", stateClass, settled && "settled"),
7249
7348
  role: "dialog",
7250
7349
  "aria-modal": "true",
@@ -7261,9 +7360,9 @@ Modal.displayName = "Modal";
7261
7360
  var Modal_default = Modal;
7262
7361
 
7263
7362
  // src/components/DatePicker/SingleDatePicker/index.tsx
7264
- import React11 from "react";
7363
+ import React12 from "react";
7265
7364
  import { Fragment as Fragment4, jsx as jsx314, jsxs as jsxs200 } from "react/jsx-runtime";
7266
- var DayCell2 = React11.memo(
7365
+ var DayCell2 = React12.memo(
7267
7366
  ({
7268
7367
  day,
7269
7368
  disabled,
@@ -7315,26 +7414,26 @@ var SingleDatePicker = (props) => {
7315
7414
  initialYear,
7316
7415
  initialMonth
7317
7416
  );
7318
- const [pickerMode, setPickerMode] = React11.useState("days");
7319
- const [yearRangeStart, setYearRangeStart] = React11.useState(
7417
+ const [pickerMode, setPickerMode] = React12.useState("days");
7418
+ const [yearRangeStart, setYearRangeStart] = React12.useState(
7320
7419
  Math.floor((initialYear ?? (/* @__PURE__ */ new Date()).getFullYear()) / 12) * 12
7321
7420
  );
7322
- const minTime = React11.useMemo(
7421
+ const minTime = React12.useMemo(
7323
7422
  () => minDate ? new Date(minDate.getFullYear(), minDate.getMonth(), minDate.getDate()).getTime() : -Infinity,
7324
7423
  [minDate]
7325
7424
  );
7326
- const maxTime = React11.useMemo(
7425
+ const maxTime = React12.useMemo(
7327
7426
  () => maxDate ? new Date(maxDate.getFullYear(), maxDate.getMonth(), maxDate.getDate()).getTime() : Infinity,
7328
7427
  [maxDate]
7329
7428
  );
7330
- const highlightSet = React11.useMemo(() => {
7429
+ const highlightSet = React12.useMemo(() => {
7331
7430
  const set = /* @__PURE__ */ new Set();
7332
7431
  for (const h of highlightDates) {
7333
7432
  set.add(`${h.getFullYear()}-${h.getMonth()}-${h.getDate()}`);
7334
7433
  }
7335
7434
  return set;
7336
7435
  }, [highlightDates]);
7337
- const handleSelect = React11.useCallback(
7436
+ const handleSelect = React12.useCallback(
7338
7437
  (date) => {
7339
7438
  onChange?.(date);
7340
7439
  },
@@ -7463,8 +7562,8 @@ var formatDate = (date) => {
7463
7562
  };
7464
7563
  var InputDatePicker = (props) => {
7465
7564
  const { value, onChange, minDate, maxDate, disabled, locale = "ko", placeholder } = props;
7466
- const [isOpen, setIsOpen] = React12.useState(false);
7467
- const [tempDate, setTempDate] = React12.useState(value ?? /* @__PURE__ */ new Date());
7565
+ const [isOpen, setIsOpen] = React13.useState(false);
7566
+ const [tempDate, setTempDate] = React13.useState(value ?? /* @__PURE__ */ new Date());
7468
7567
  const handleOpen = () => {
7469
7568
  if (disabled) return;
7470
7569
  setTempDate(value ?? /* @__PURE__ */ new Date());
@@ -7513,23 +7612,27 @@ InputDatePicker.displayName = "InputDatePicker";
7513
7612
  var InputDatePicker_default = InputDatePicker;
7514
7613
 
7515
7614
  // src/components/DatePicker/PopupPicker/index.tsx
7516
- import React16 from "react";
7615
+ import React17 from "react";
7517
7616
 
7518
7617
  // src/components/DatePicker/RangePicker/index.tsx
7519
- import React15 from "react";
7618
+ import React16 from "react";
7520
7619
 
7521
7620
  // src/components/Tab/Tab.tsx
7522
- import React14 from "react";
7621
+ import React15 from "react";
7523
7622
 
7524
7623
  // src/components/Tab/TabItem.tsx
7525
- import React13 from "react";
7624
+ import React14 from "react";
7526
7625
  import { jsx as jsx316 } from "react/jsx-runtime";
7527
- var TabItem = React13.forwardRef((props, ref) => {
7626
+ var TabItem = React14.forwardRef((props, ref) => {
7528
7627
  const { isActive: isActive2, title, onClick } = props;
7529
7628
  return /* @__PURE__ */ jsx316(
7530
- "div",
7629
+ "button",
7531
7630
  {
7532
7631
  ref,
7632
+ type: "button",
7633
+ role: "tab",
7634
+ "aria-selected": isActive2,
7635
+ tabIndex: isActive2 ? 0 : -1,
7533
7636
  className: clsx_default("tab-item", isActive2 ? "active" : null),
7534
7637
  onClick,
7535
7638
  children: title
@@ -7544,44 +7647,64 @@ import { jsx as jsx317, jsxs as jsxs202 } from "react/jsx-runtime";
7544
7647
  var Tab = (props) => {
7545
7648
  const { activeIndex, onChange, tabs, variant, type, size = "md" } = props;
7546
7649
  const shape = variant ?? type ?? "default";
7547
- const [underlineStyle, setUnderlineStyle] = React14.useState({
7650
+ const [underlineStyle, setUnderlineStyle] = React15.useState({
7548
7651
  left: 0,
7549
7652
  width: 0
7550
7653
  });
7551
- const itemRefs = React14.useRef([]);
7654
+ const itemRefs = React15.useRef([]);
7655
+ const handleKeyDown = (e) => {
7656
+ const last = tabs.length - 1;
7657
+ let next = null;
7658
+ if (e.key === "ArrowRight") next = activeIndex >= last ? 0 : activeIndex + 1;
7659
+ else if (e.key === "ArrowLeft") next = activeIndex <= 0 ? last : activeIndex - 1;
7660
+ else if (e.key === "Home") next = 0;
7661
+ else if (e.key === "End") next = last;
7662
+ if (next === null) return;
7663
+ e.preventDefault();
7664
+ onChange(tabs[next], next);
7665
+ itemRefs.current[next]?.focus();
7666
+ };
7552
7667
  const handleChangeActiveTab = (tabItem, tabIdx) => {
7553
7668
  onChange(tabItem, tabIdx);
7554
7669
  };
7555
- React14.useEffect(() => {
7670
+ React15.useEffect(() => {
7556
7671
  const el = itemRefs.current[activeIndex];
7557
7672
  if (el) {
7558
7673
  setUnderlineStyle({ left: el.offsetLeft, width: el.offsetWidth });
7559
7674
  }
7560
7675
  }, [activeIndex, tabs.length]);
7561
- return /* @__PURE__ */ jsxs202("div", { className: clsx_default("lib-xplat-tab", `type-${shape}`, size), children: [
7562
- tabs.map((tab, idx) => /* @__PURE__ */ jsx317(
7563
- TabItem_default,
7564
- {
7565
- onClick: () => handleChangeActiveTab(tab, idx),
7566
- isActive: activeIndex === idx,
7567
- ref: (el) => {
7568
- itemRefs.current[idx] = el;
7569
- },
7570
- title: tab.title
7571
- },
7572
- `${tab.value}_${idx}`
7573
- )),
7574
- shape === "toggle" && /* @__PURE__ */ jsx317(
7575
- "div",
7576
- {
7577
- className: "tab-toggle-underline",
7578
- style: {
7579
- left: underlineStyle.left,
7580
- width: underlineStyle.width
7581
- }
7582
- }
7583
- )
7584
- ] });
7676
+ return /* @__PURE__ */ jsxs202(
7677
+ "div",
7678
+ {
7679
+ className: clsx_default("lib-xplat-tab", `type-${shape}`, size),
7680
+ role: "tablist",
7681
+ onKeyDown: handleKeyDown,
7682
+ children: [
7683
+ tabs.map((tab, idx) => /* @__PURE__ */ jsx317(
7684
+ TabItem_default,
7685
+ {
7686
+ onClick: () => handleChangeActiveTab(tab, idx),
7687
+ isActive: activeIndex === idx,
7688
+ ref: (el) => {
7689
+ itemRefs.current[idx] = el;
7690
+ },
7691
+ title: tab.title
7692
+ },
7693
+ `${tab.value}_${idx}`
7694
+ )),
7695
+ shape === "toggle" && /* @__PURE__ */ jsx317(
7696
+ "div",
7697
+ {
7698
+ className: "tab-toggle-underline",
7699
+ style: {
7700
+ left: underlineStyle.left,
7701
+ width: underlineStyle.width
7702
+ }
7703
+ }
7704
+ )
7705
+ ]
7706
+ }
7707
+ );
7585
7708
  };
7586
7709
  Tab.displayName = "Tab";
7587
7710
  var Tab_default = Tab;
@@ -7597,7 +7720,7 @@ var RangePicker = (props) => {
7597
7720
  maxDate,
7598
7721
  locale = "ko"
7599
7722
  } = props;
7600
- const [activeTab, setActiveTab] = React15.useState("start");
7723
+ const [activeTab, setActiveTab] = React16.useState("start");
7601
7724
  const handleStartChange = (date) => {
7602
7725
  if (!date) return;
7603
7726
  const newStart = date > endDate ? endDate : date;
@@ -7682,7 +7805,7 @@ var RangePicker_default = RangePicker;
7682
7805
  import { jsx as jsx319, jsxs as jsxs204 } from "react/jsx-runtime";
7683
7806
  var PopupPicker = (props) => {
7684
7807
  const { component, type, locale } = props;
7685
- const [isOpen, setIsOpen] = React16.useState(false);
7808
+ const [isOpen, setIsOpen] = React17.useState(false);
7686
7809
  const handleClick = () => setIsOpen(true);
7687
7810
  const handleClose = () => setIsOpen(false);
7688
7811
  const handleSingleChange = (date) => {
@@ -7691,7 +7814,7 @@ var PopupPicker = (props) => {
7691
7814
  handleClose();
7692
7815
  };
7693
7816
  return /* @__PURE__ */ jsxs204("div", { className: "lib-xplat-popup-datepicker", children: [
7694
- React16.cloneElement(component, { onClick: handleClick }),
7817
+ React17.cloneElement(component, { onClick: handleClick }),
7695
7818
  /* @__PURE__ */ jsx319(Modal_default, { isOpen, onClose: handleClose, children: /* @__PURE__ */ jsxs204("div", { className: clsx_default("lib-xplat-popup-datepicker-card", type === "range" && "range-mode"), children: [
7696
7819
  /* @__PURE__ */ jsxs204("div", { className: "popup-datepicker-content", children: [
7697
7820
  type === "single" && /* @__PURE__ */ jsx319(
@@ -7750,15 +7873,18 @@ Divider.displayName = "Divider";
7750
7873
  var Divider_default = Divider;
7751
7874
 
7752
7875
  // src/components/Drawer/Drawer.tsx
7753
- import React17 from "react";
7876
+ import React18 from "react";
7754
7877
  import { createPortal as createPortal2 } from "react-dom";
7755
7878
  import { jsx as jsx321, jsxs as jsxs205 } from "react/jsx-runtime";
7756
7879
  var ANIMATION_DURATION_MS2 = 250;
7757
7880
  var Drawer = (props) => {
7758
7881
  const { isOpen, onClose, placement = "right", size = "md", title, children } = props;
7759
- const [mounted, setMounted] = React17.useState(false);
7760
- const [visible, setVisible] = React17.useState(false);
7761
- React17.useEffect(() => {
7882
+ const [mounted, setMounted] = React18.useState(false);
7883
+ const [visible, setVisible] = React18.useState(false);
7884
+ const panelRef = React18.useRef(null);
7885
+ useEscapeKey(isOpen, onClose);
7886
+ useFocusTrap(panelRef, isOpen && mounted, { trap: true });
7887
+ React18.useEffect(() => {
7762
7888
  if (isOpen) {
7763
7889
  setMounted(true);
7764
7890
  const t2 = setTimeout(() => setVisible(true), 1);
@@ -7780,6 +7906,7 @@ var Drawer = (props) => {
7780
7906
  children: /* @__PURE__ */ jsxs205(
7781
7907
  "div",
7782
7908
  {
7909
+ ref: panelRef,
7783
7910
  className: clsx_default("lib-xplat-drawer", placement, size, stateClass),
7784
7911
  role: "dialog",
7785
7912
  "aria-modal": "true",
@@ -7802,7 +7929,7 @@ Drawer.displayName = "Drawer";
7802
7929
  var Drawer_default = Drawer;
7803
7930
 
7804
7931
  // src/components/Dropdown/Dropdown.tsx
7805
- import React20 from "react";
7932
+ import React21 from "react";
7806
7933
 
7807
7934
  // src/tokens/hooks/Portal.tsx
7808
7935
  import ReactDOM from "react-dom";
@@ -7814,13 +7941,15 @@ Portal.displayName = "Portal";
7814
7941
  var Portal_default = Portal;
7815
7942
 
7816
7943
  // src/tokens/hooks/useAutoPosition.ts
7817
- import React18 from "react";
7944
+ import React19 from "react";
7818
7945
  var useAutoPosition = (triggerRef, popRef, enabled = true) => {
7819
- const [position, setPosition] = React18.useState({
7946
+ const [position, setPosition] = React19.useState({
7820
7947
  position: {},
7821
- direction: "bottom"
7948
+ direction: "bottom",
7949
+ repositioning: false
7822
7950
  });
7823
- const calculatePosition = React18.useCallback(() => {
7951
+ const placedRef = React19.useRef(false);
7952
+ const calculatePosition = React19.useCallback(() => {
7824
7953
  if (!triggerRef.current || !popRef.current) return;
7825
7954
  const triggerRect = triggerRef.current.getBoundingClientRect();
7826
7955
  const popW = popRef.current.offsetWidth;
@@ -7844,16 +7973,21 @@ var useAutoPosition = (triggerRef, popRef, enabled = true) => {
7844
7973
  if (left < 8) left = 8;
7845
7974
  setPosition({
7846
7975
  position: { top, left },
7847
- direction
7976
+ direction,
7977
+ repositioning: placedRef.current
7848
7978
  });
7979
+ placedRef.current = true;
7849
7980
  }, [triggerRef, popRef]);
7850
- React18.useLayoutEffect(() => {
7851
- if (!enabled) return;
7981
+ React19.useLayoutEffect(() => {
7982
+ if (!enabled) {
7983
+ placedRef.current = false;
7984
+ return;
7985
+ }
7852
7986
  calculatePosition();
7853
7987
  const raf = requestAnimationFrame(calculatePosition);
7854
7988
  return () => cancelAnimationFrame(raf);
7855
7989
  }, [calculatePosition, enabled]);
7856
- React18.useEffect(() => {
7990
+ React19.useEffect(() => {
7857
7991
  if (!enabled || !popRef.current) return;
7858
7992
  const observer = new ResizeObserver(() => {
7859
7993
  calculatePosition();
@@ -7861,13 +7995,19 @@ var useAutoPosition = (triggerRef, popRef, enabled = true) => {
7861
7995
  observer.observe(popRef.current);
7862
7996
  return () => observer.disconnect();
7863
7997
  }, [calculatePosition, enabled, popRef]);
7864
- React18.useEffect(() => {
7998
+ React19.useEffect(() => {
7865
7999
  if (!enabled) return;
7866
- window.addEventListener("resize", calculatePosition);
7867
- window.addEventListener("scroll", calculatePosition, true);
8000
+ let raf = 0;
8001
+ const onScrollOrResize = () => {
8002
+ cancelAnimationFrame(raf);
8003
+ raf = requestAnimationFrame(calculatePosition);
8004
+ };
8005
+ window.addEventListener("resize", onScrollOrResize, { passive: true });
8006
+ window.addEventListener("scroll", onScrollOrResize, { passive: true, capture: true });
7868
8007
  return () => {
7869
- window.removeEventListener("resize", calculatePosition);
7870
- window.removeEventListener("scroll", calculatePosition, true);
8008
+ cancelAnimationFrame(raf);
8009
+ window.removeEventListener("resize", onScrollOrResize);
8010
+ window.removeEventListener("scroll", onScrollOrResize, true);
7871
8011
  };
7872
8012
  }, [calculatePosition, enabled]);
7873
8013
  return position;
@@ -7875,9 +8015,9 @@ var useAutoPosition = (triggerRef, popRef, enabled = true) => {
7875
8015
  var useAutoPosition_default = useAutoPosition;
7876
8016
 
7877
8017
  // src/tokens/hooks/useClickOutside.ts
7878
- import React19 from "react";
8018
+ import React20 from "react";
7879
8019
  var useClickOutside = (refs, handler, enabled = true) => {
7880
- React19.useEffect(() => {
8020
+ React20.useEffect(() => {
7881
8021
  if (!enabled) return;
7882
8022
  const refArray = Array.isArray(refs) ? refs : [refs];
7883
8023
  const listener = (event) => {
@@ -7903,14 +8043,18 @@ var useClickOutside_default = useClickOutside;
7903
8043
  import { jsx as jsx322, jsxs as jsxs206 } from "react/jsx-runtime";
7904
8044
  var Dropdown = (props) => {
7905
8045
  const { items, children } = props;
7906
- const [isOpen, setIsOpen] = React20.useState(false);
7907
- const [mounted, setMounted] = React20.useState(false);
7908
- const [visible, setVisible] = React20.useState(false);
7909
- const triggerRef = React20.useRef(null);
7910
- const menuRef = React20.useRef(null);
7911
- const { position, direction } = useAutoPosition_default(triggerRef, menuRef, mounted);
8046
+ const [isOpen, setIsOpen] = React21.useState(false);
8047
+ const [mounted, setMounted] = React21.useState(false);
8048
+ const [visible, setVisible] = React21.useState(false);
8049
+ const triggerRef = React21.useRef(null);
8050
+ const menuRef = React21.useRef(null);
8051
+ const { position, direction, repositioning } = useAutoPosition_default(triggerRef, menuRef, mounted);
7912
8052
  useClickOutside_default([triggerRef, menuRef], () => setIsOpen(false), isOpen);
7913
- React20.useEffect(() => {
8053
+ useEscapeKey(isOpen, () => {
8054
+ setIsOpen(false);
8055
+ triggerRef.current?.focus({ preventScroll: true });
8056
+ });
8057
+ React21.useEffect(() => {
7914
8058
  if (isOpen) {
7915
8059
  setMounted(true);
7916
8060
  const t2 = setTimeout(() => setVisible(true), 1);
@@ -7939,7 +8083,7 @@ var Dropdown = (props) => {
7939
8083
  "div",
7940
8084
  {
7941
8085
  ref: menuRef,
7942
- className: clsx_default("lib-xplat-dropdown-menu", direction, { visible }),
8086
+ className: clsx_default("lib-xplat-dropdown-menu", direction, { visible }, repositioning && "repositioning"),
7943
8087
  style: { top: position.top, left: position.left },
7944
8088
  role: "menu",
7945
8089
  children: items.map((item) => /* @__PURE__ */ jsx322(
@@ -7964,7 +8108,112 @@ Dropdown.displayName = "Dropdown";
7964
8108
  var Dropdown_default = Dropdown;
7965
8109
 
7966
8110
  // src/components/Editor/Editor.tsx
7967
- import React21 from "react";
8111
+ import React22 from "react";
8112
+
8113
+ // src/components/Editor/highlight.ts
8114
+ var CODE_LANGUAGES = [
8115
+ { value: "plain", label: "\uC5C6\uC74C" },
8116
+ { value: "javascript", label: "JavaScript" },
8117
+ { value: "typescript", label: "TypeScript" },
8118
+ { value: "json", label: "JSON" },
8119
+ { value: "html", label: "HTML" },
8120
+ { value: "css", label: "CSS" },
8121
+ { value: "python", label: "Python" },
8122
+ { value: "sql", label: "SQL" },
8123
+ { value: "bash", label: "Bash" }
8124
+ ];
8125
+ var KEYWORDS = {
8126
+ plain: [],
8127
+ javascript: "const let var function return if else for while class new this import export from default async await try catch throw typeof instanceof null undefined true false break continue switch case do delete in of yield".split(" "),
8128
+ typescript: "const let var function return if else for while class new this import export from default async await try catch throw typeof instanceof null undefined true false break continue switch case do delete in of yield interface type enum implements extends public private protected readonly as satisfies keyof infer never unknown any".split(" "),
8129
+ json: ["true", "false", "null"],
8130
+ html: [],
8131
+ css: [],
8132
+ python: "def class return if elif else for while import from as try except finally raise with lambda None True False and or not in is pass break continue global nonlocal yield async await".split(" "),
8133
+ sql: "SELECT FROM WHERE INSERT INTO VALUES UPDATE SET DELETE CREATE TABLE ALTER DROP JOIN LEFT RIGHT INNER OUTER ON GROUP BY ORDER HAVING LIMIT OFFSET AS AND OR NOT NULL DISTINCT UNION INDEX PRIMARY KEY FOREIGN REFERENCES DEFAULT".split(" "),
8134
+ bash: "if then else fi for while do done case esac function return export local echo cd ls rm cp mv mkdir sudo source set unset exit".split(" ")
8135
+ };
8136
+ var LINE_COMMENT = {
8137
+ javascript: "//",
8138
+ typescript: "//",
8139
+ css: "",
8140
+ python: "#",
8141
+ sql: "--",
8142
+ bash: "#"
8143
+ };
8144
+ var escape = (s) => s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
8145
+ var wrap = (cls, text) => `<span class="tok-${cls}">${escape(text)}</span>`;
8146
+ var highlight = (code, lang) => {
8147
+ if (lang === "plain" || !code) return escape(code);
8148
+ const keywords = new Set(KEYWORDS[lang]);
8149
+ const lineComment = LINE_COMMENT[lang];
8150
+ const caseInsensitive = lang === "sql";
8151
+ let out = "";
8152
+ let i = 0;
8153
+ while (i < code.length) {
8154
+ const rest = code.slice(i);
8155
+ if ((lang === "javascript" || lang === "typescript" || lang === "css") && rest.startsWith("/*")) {
8156
+ const end = code.indexOf("*/", i + 2);
8157
+ const stop = end === -1 ? code.length : end + 2;
8158
+ out += wrap("comment", code.slice(i, stop));
8159
+ i = stop;
8160
+ continue;
8161
+ }
8162
+ if (lineComment && rest.startsWith(lineComment)) {
8163
+ const nl = code.indexOf("\n", i);
8164
+ const stop = nl === -1 ? code.length : nl;
8165
+ out += wrap("comment", code.slice(i, stop));
8166
+ i = stop;
8167
+ continue;
8168
+ }
8169
+ const q = rest[0];
8170
+ if (q === '"' || q === "'" || q === "`") {
8171
+ let j = 1;
8172
+ while (j < rest.length) {
8173
+ if (rest[j] === "\\") {
8174
+ j += 2;
8175
+ continue;
8176
+ }
8177
+ if (rest[j] === q) {
8178
+ j += 1;
8179
+ break;
8180
+ }
8181
+ if (rest[j] === "\n" && q !== "`") break;
8182
+ j += 1;
8183
+ }
8184
+ out += wrap("string", rest.slice(0, j));
8185
+ i += j;
8186
+ continue;
8187
+ }
8188
+ const num = /^\d+(\.\d+)?/.exec(rest);
8189
+ if (num && !/[\w$]/.test(code[i - 1] ?? "")) {
8190
+ out += wrap("number", num[0]);
8191
+ i += num[0].length;
8192
+ continue;
8193
+ }
8194
+ const word = /^[A-Za-z_$][\w$]*/.exec(rest);
8195
+ if (word) {
8196
+ const w = word[0];
8197
+ const hit = caseInsensitive ? keywords.has(w.toUpperCase()) : keywords.has(w);
8198
+ out += hit ? wrap("keyword", w) : escape(w);
8199
+ i += w.length;
8200
+ continue;
8201
+ }
8202
+ if (lang === "html" && rest.startsWith("<")) {
8203
+ const tag = /^<\/?[A-Za-z][\w-]*/.exec(rest);
8204
+ if (tag) {
8205
+ out += wrap("keyword", tag[0]);
8206
+ i += tag[0].length;
8207
+ continue;
8208
+ }
8209
+ }
8210
+ out += escape(code[i]);
8211
+ i += 1;
8212
+ }
8213
+ return out;
8214
+ };
8215
+
8216
+ // src/components/Editor/Editor.tsx
7968
8217
  import { jsx as jsx323, jsxs as jsxs207 } from "react/jsx-runtime";
7969
8218
  var DEFAULT_TOOLBAR = [
7970
8219
  "bold",
@@ -7972,14 +8221,27 @@ var DEFAULT_TOOLBAR = [
7972
8221
  "underline",
7973
8222
  "strikethrough",
7974
8223
  "code",
7975
- "heading",
8224
+ "heading-1",
8225
+ "heading-2",
8226
+ "heading-3",
7976
8227
  "list",
7977
8228
  "ordered-list",
7978
8229
  "blockquote",
7979
8230
  "code-block",
7980
8231
  "link",
7981
8232
  "image",
7982
- "divider"
8233
+ "divider",
8234
+ "checklist",
8235
+ "table",
8236
+ "align-left",
8237
+ "align-center",
8238
+ "align-right",
8239
+ "highlight",
8240
+ "superscript",
8241
+ "subscript",
8242
+ "clear-format",
8243
+ "undo",
8244
+ "redo"
7983
8245
  ];
7984
8246
  var ALLOWED_TAGS = /* @__PURE__ */ new Set([
7985
8247
  "p",
@@ -8008,12 +8270,51 @@ var ALLOWED_TAGS = /* @__PURE__ */ new Set([
8008
8270
  "img",
8009
8271
  "hr",
8010
8272
  "span",
8011
- "div"
8273
+ "div",
8274
+ "sub",
8275
+ "sup",
8276
+ "mark",
8277
+ "table",
8278
+ "thead",
8279
+ "tbody",
8280
+ "tr",
8281
+ "th",
8282
+ "td"
8012
8283
  ]);
8013
8284
  var ALLOWED_ATTRS = {
8014
8285
  a: ["href", "target", "rel"],
8015
- img: ["src", "alt"]
8286
+ img: ["src", "alt", "width"],
8287
+ // 정렬·체크리스트는 클래스로만 표현한다. style 을 열면 붙여넣기로 아무 CSS 나 들어온다
8288
+ p: ["class"],
8289
+ h1: ["class"],
8290
+ h2: ["class"],
8291
+ h3: ["class"],
8292
+ h4: ["class"],
8293
+ h5: ["class"],
8294
+ h6: ["class"],
8295
+ ul: ["class"],
8296
+ ol: ["class"],
8297
+ li: ["class", "data-checked"],
8298
+ blockquote: ["class"],
8299
+ div: ["class"],
8300
+ span: ["class"],
8301
+ pre: ["class"],
8302
+ code: ["class"],
8303
+ mark: ["class"],
8304
+ table: ["class"],
8305
+ td: ["class"],
8306
+ th: ["class"],
8307
+ tr: ["class"]
8016
8308
  };
8309
+ var DROP_WITH_CONTENT = /* @__PURE__ */ new Set([
8310
+ "script",
8311
+ "style",
8312
+ "noscript",
8313
+ "iframe",
8314
+ "object",
8315
+ "embed",
8316
+ "template"
8317
+ ]);
8017
8318
  var sanitizeHtml = (input) => {
8018
8319
  const doc = new DOMParser().parseFromString(`<div>${input}</div>`, "text/html");
8019
8320
  const root = doc.body.firstElementChild;
@@ -8022,6 +8323,10 @@ var sanitizeHtml = (input) => {
8022
8323
  const children = Array.from(node.children);
8023
8324
  for (const child of children) {
8024
8325
  const tag = child.tagName.toLowerCase();
8326
+ if (DROP_WITH_CONTENT.has(tag)) {
8327
+ node.removeChild(child);
8328
+ continue;
8329
+ }
8025
8330
  if (!ALLOWED_TAGS.has(tag)) {
8026
8331
  while (child.firstChild) node.insertBefore(child.firstChild, child);
8027
8332
  node.removeChild(child);
@@ -8052,7 +8357,9 @@ var escapeHtml = (text) => {
8052
8357
  };
8053
8358
  var SLASH_ITEMS = [
8054
8359
  { key: "paragraph", label: "\uB2E8\uB77D", hint: "\uAE30\uBCF8 \uD14D\uC2A4\uD2B8" },
8055
- { key: "heading", label: "\uC81C\uBAA9 1", hint: "\uD070 \uC81C\uBAA9" },
8360
+ { key: "heading-1", label: "\uC81C\uBAA9 1", hint: "\uAC00\uC7A5 \uD070 \uC81C\uBAA9" },
8361
+ { key: "heading-2", label: "\uC81C\uBAA9 2", hint: "" },
8362
+ { key: "heading-3", label: "\uC81C\uBAA9 3", hint: "" },
8056
8363
  { key: "list", label: "\uAE00\uBA38\uB9AC \uAE30\uD638 \uBAA9\uB85D", hint: "\u2022 \uD56D\uBAA9" },
8057
8364
  { key: "ordered-list", label: "\uBC88\uD638 \uB9E4\uAE30\uAE30 \uBAA9\uB85D", hint: "1. \uD56D\uBAA9" },
8058
8365
  { key: "blockquote", label: "\uC778\uC6A9", hint: "" },
@@ -8072,26 +8379,32 @@ var Editor = (props) => {
8072
8379
  onImageUpload,
8073
8380
  minHeight = 200
8074
8381
  } = props;
8075
- const editorRef = React21.useRef(null);
8076
- const lastRangeRef = React21.useRef(null);
8077
- const composingRef = React21.useRef(false);
8078
- const [isFocused, setIsFocused] = React21.useState(false);
8079
- const [isEmpty, setIsEmpty] = React21.useState(!value);
8080
- const [activeFormats, setActiveFormats] = React21.useState(/* @__PURE__ */ new Set());
8081
- const [slashOpen, setSlashOpen] = React21.useState(false);
8082
- const [slashFilter, setSlashFilter] = React21.useState("");
8083
- const [slashIdx, setSlashIdx] = React21.useState(0);
8084
- const [slashPos, setSlashPos] = React21.useState({ top: 0, left: 0 });
8085
- const slashStartRangeRef = React21.useRef(null);
8086
- const [linkOpen, setLinkOpen] = React21.useState(false);
8087
- const [linkValue, setLinkValue] = React21.useState("");
8088
- const [linkPos, setLinkPos] = React21.useState({ top: 0, left: 0 });
8089
- React21.useEffect(() => {
8090
- if (!editorRef.current) return;
8091
- if (editorRef.current.innerHTML !== value) {
8092
- editorRef.current.innerHTML = sanitizeHtml(value || "");
8093
- updateEmpty();
8094
- }
8382
+ const editorRef = React22.useRef(null);
8383
+ const lastRangeRef = React22.useRef(null);
8384
+ const composingRef = React22.useRef(false);
8385
+ const [isFocused, setIsFocused] = React22.useState(false);
8386
+ const [isEmpty, setIsEmpty] = React22.useState(!value);
8387
+ const [activeFormats, setActiveFormats] = React22.useState(/* @__PURE__ */ new Set());
8388
+ const [slashOpen, setSlashOpen] = React22.useState(false);
8389
+ const [slashFilter, setSlashFilter] = React22.useState("");
8390
+ const [slashIdx, setSlashIdx] = React22.useState(0);
8391
+ const [slashPos, setSlashPos] = React22.useState({ top: 0, left: 0 });
8392
+ const slashStartRangeRef = React22.useRef(null);
8393
+ const [linkOpen, setLinkOpen] = React22.useState(false);
8394
+ const [linkValue, setLinkValue] = React22.useState("");
8395
+ const [linkPos, setLinkPos] = React22.useState({ top: 0, left: 0 });
8396
+ const lastEmittedRef = React22.useRef(null);
8397
+ React22.useEffect(() => {
8398
+ const el = editorRef.current;
8399
+ if (!el) return;
8400
+ if (value === lastEmittedRef.current) return;
8401
+ if (el.innerHTML === value) return;
8402
+ el.innerHTML = sanitizeHtml(value || "");
8403
+ if (!el.firstChild) el.innerHTML = "<p><br></p>";
8404
+ lastEmittedRef.current = null;
8405
+ historyRef.current = [{ html: el.innerHTML, caret: 0 }];
8406
+ historyIdxRef.current = 0;
8407
+ updateEmpty();
8095
8408
  }, [value]);
8096
8409
  const updateEmpty = () => {
8097
8410
  const el = editorRef.current;
@@ -8107,10 +8420,19 @@ var Editor = (props) => {
8107
8420
  }
8108
8421
  };
8109
8422
  const restoreSelection = () => {
8110
- if (!lastRangeRef.current) return;
8423
+ const range = lastRangeRef.current;
8424
+ if (!range) return;
8425
+ if (!editorRef.current?.contains(range.startContainer)) {
8426
+ lastRangeRef.current = null;
8427
+ return;
8428
+ }
8111
8429
  const sel = window.getSelection();
8112
- sel?.removeAllRanges();
8113
- sel?.addRange(lastRangeRef.current);
8430
+ try {
8431
+ sel?.removeAllRanges();
8432
+ sel?.addRange(range);
8433
+ } catch {
8434
+ lastRangeRef.current = null;
8435
+ }
8114
8436
  };
8115
8437
  const updateActiveFormats = () => {
8116
8438
  if (!editorRef.current) return;
@@ -8126,6 +8448,17 @@ var Editor = (props) => {
8126
8448
  if (document.queryCommandState("insertOrderedList")) next.add("ordered-list");
8127
8449
  const block = String(document.queryCommandValue("formatBlock") || "").toLowerCase();
8128
8450
  if (block) next.add(`block:${block}`);
8451
+ if (document.queryCommandState("superscript")) next.add("superscript");
8452
+ if (document.queryCommandState("subscript")) next.add("subscript");
8453
+ } catch {
8454
+ }
8455
+ try {
8456
+ const blockEl = currentBlock();
8457
+ if (blockEl?.classList.contains("align-center")) next.add("align:center");
8458
+ else if (blockEl?.classList.contains("align-right")) next.add("align:right");
8459
+ else if (blockEl) next.add("align:left");
8460
+ if (blockEl?.closest("mark")) next.add("highlight");
8461
+ if (blockEl?.closest("ul.checklist")) next.add("checklist");
8129
8462
  } catch {
8130
8463
  }
8131
8464
  setActiveFormats(next);
@@ -8139,7 +8472,374 @@ var Editor = (props) => {
8139
8472
  const setBlock = (tag) => {
8140
8473
  exec("formatBlock", tag);
8141
8474
  };
8475
+ const toggleBlock = (tag) => {
8476
+ const current = String(document.queryCommandValue("formatBlock") || "").toLowerCase();
8477
+ setBlock(current === tag ? "p" : tag);
8478
+ };
8479
+ const historyRef = React22.useRef([]);
8480
+ const historyIdxRef = React22.useRef(-1);
8481
+ const lastPushAtRef = React22.useRef(0);
8482
+ const isRestoringRef = React22.useRef(false);
8483
+ const caretOffset = (rootEl) => {
8484
+ const el = rootEl ?? editorRef.current;
8485
+ const sel = window.getSelection();
8486
+ if (!el || !sel || sel.rangeCount === 0 || !el.contains(sel.anchorNode)) return 0;
8487
+ const range = sel.getRangeAt(0).cloneRange();
8488
+ range.selectNodeContents(el);
8489
+ range.setEnd(sel.getRangeAt(0).endContainer, sel.getRangeAt(0).endOffset);
8490
+ return range.toString().length;
8491
+ };
8492
+ const setCaretOffset = (offset, rootEl) => {
8493
+ const el = rootEl ?? editorRef.current;
8494
+ if (!el) return;
8495
+ const walker = document.createTreeWalker(el, NodeFilter.SHOW_TEXT);
8496
+ let remaining = offset;
8497
+ let node = null;
8498
+ while (node = walker.nextNode()) {
8499
+ const len = node.textContent?.length ?? 0;
8500
+ if (remaining <= len) {
8501
+ const range = document.createRange();
8502
+ range.setStart(node, remaining);
8503
+ range.collapse(true);
8504
+ const sel = window.getSelection();
8505
+ sel?.removeAllRanges();
8506
+ sel?.addRange(range);
8507
+ return;
8508
+ }
8509
+ remaining -= len;
8510
+ }
8511
+ placeCaretAtEnd(el);
8512
+ };
8513
+ const pushHistory = (force = false) => {
8514
+ const el = editorRef.current;
8515
+ if (!el || isRestoringRef.current) return;
8516
+ const html = el.innerHTML;
8517
+ const hist = historyRef.current;
8518
+ const cur = hist[historyIdxRef.current];
8519
+ if (cur && cur.html === html) return;
8520
+ const now = Date.now();
8521
+ const coalesce = !force && cur && now - lastPushAtRef.current < 500;
8522
+ lastPushAtRef.current = now;
8523
+ if (coalesce) {
8524
+ hist[historyIdxRef.current] = { html, caret: caretOffset() };
8525
+ return;
8526
+ }
8527
+ hist.length = historyIdxRef.current + 1;
8528
+ hist.push({ html, caret: caretOffset() });
8529
+ if (hist.length > 200) hist.shift();
8530
+ historyIdxRef.current = hist.length - 1;
8531
+ };
8532
+ const applySnapshot = (snap) => {
8533
+ const el = editorRef.current;
8534
+ if (!el) return;
8535
+ isRestoringRef.current = true;
8536
+ el.innerHTML = snap.html;
8537
+ setCaretOffset(snap.caret);
8538
+ isRestoringRef.current = false;
8539
+ lastEmittedRef.current = el.innerHTML;
8540
+ onChange?.(el.innerHTML);
8541
+ updateEmpty();
8542
+ updateActiveFormats();
8543
+ };
8544
+ const undo = () => {
8545
+ pushHistory(true);
8546
+ if (historyIdxRef.current <= 0) return;
8547
+ historyIdxRef.current -= 1;
8548
+ applySnapshot(historyRef.current[historyIdxRef.current]);
8549
+ };
8550
+ const redo = () => {
8551
+ if (historyIdxRef.current >= historyRef.current.length - 1) return;
8552
+ historyIdxRef.current += 1;
8553
+ applySnapshot(historyRef.current[historyIdxRef.current]);
8554
+ };
8555
+ const langOf = (pre) => {
8556
+ const cls = Array.from(pre.classList).find((c) => c.startsWith("lang-"));
8557
+ return cls?.slice(5) ?? "plain";
8558
+ };
8559
+ const [codeLang, setCodeLang] = React22.useState("plain");
8560
+ const highlightRafRef = React22.useRef(0);
8561
+ const rehighlight = (pre) => {
8562
+ if (composingRef.current) return;
8563
+ const code = pre.querySelector("code");
8564
+ if (!code) return;
8565
+ const lang = langOf(pre);
8566
+ const text = code.textContent || "";
8567
+ const next = highlight(text, lang);
8568
+ if (code.innerHTML === next) return;
8569
+ const caret = caretOffset(code);
8570
+ isRestoringRef.current = true;
8571
+ code.innerHTML = next;
8572
+ setCaretOffset(caret, code);
8573
+ isRestoringRef.current = false;
8574
+ };
8575
+ const scheduleHighlight = () => {
8576
+ const pre = closestPre();
8577
+ if (!pre) return;
8578
+ cancelAnimationFrame(highlightRafRef.current);
8579
+ highlightRafRef.current = requestAnimationFrame(() => rehighlight(pre));
8580
+ };
8581
+ const changeCodeLang = (lang) => {
8582
+ const pre = closestPre();
8583
+ if (!pre) return;
8584
+ pushHistory(true);
8585
+ Array.from(pre.classList).filter((c) => c.startsWith("lang-")).forEach((c) => pre.classList.remove(c));
8586
+ if (lang !== "plain") pre.classList.add(`lang-${lang}`);
8587
+ setCodeLang(lang);
8588
+ rehighlight(pre);
8589
+ handleInput();
8590
+ };
8591
+ const closestPre = () => {
8592
+ const sel = window.getSelection();
8593
+ const node = sel?.anchorNode;
8594
+ if (!node || !editorRef.current?.contains(node)) return null;
8595
+ const el = node.nodeType === Node.ELEMENT_NODE ? node : node.parentElement;
8596
+ return el?.closest("pre") ?? null;
8597
+ };
8598
+ const insertCodeBlock = () => {
8599
+ pushHistory(true);
8600
+ const el = editorRef.current;
8601
+ const sel = window.getSelection();
8602
+ if (!el || !sel || sel.rangeCount === 0) return;
8603
+ const existing = closestPre();
8604
+ if (existing) {
8605
+ const p = document.createElement("p");
8606
+ p.textContent = existing.textContent || "";
8607
+ if (!p.textContent) p.innerHTML = "<br>";
8608
+ existing.replaceWith(p);
8609
+ placeCaretAtEnd(p);
8610
+ handleInput();
8611
+ return;
8612
+ }
8613
+ const range = sel.getRangeAt(0);
8614
+ const frag = range.cloneContents();
8615
+ const holder = document.createElement("div");
8616
+ holder.appendChild(frag);
8617
+ const BLOCK = /^(p|div|h[1-6]|li|blockquote|pre|tr)$/i;
8618
+ const linesOf = (node) => {
8619
+ const out = [];
8620
+ let cur = "";
8621
+ for (const child of Array.from(node.childNodes)) {
8622
+ if (child.nodeType === Node.TEXT_NODE) {
8623
+ cur += child.textContent || "";
8624
+ } else if (child.nodeName === "BR") {
8625
+ out.push(cur);
8626
+ cur = "";
8627
+ } else if (BLOCK.test(child.nodeName)) {
8628
+ if (cur) {
8629
+ out.push(cur);
8630
+ cur = "";
8631
+ }
8632
+ const sub = linesOf(child);
8633
+ out.push(...sub.length > 0 ? sub : [""]);
8634
+ } else {
8635
+ cur += linesOf(child).join("\n");
8636
+ }
8637
+ }
8638
+ if (cur) out.push(cur);
8639
+ return out;
8640
+ };
8641
+ const text = linesOf(holder).join("\n").replace(/\n+$/, "");
8642
+ const pre = document.createElement("pre");
8643
+ const code = document.createElement("code");
8644
+ code.textContent = text || "";
8645
+ pre.appendChild(code);
8646
+ range.deleteContents();
8647
+ range.insertNode(pre);
8648
+ ensureParagraphAfter(pre);
8649
+ placeCaretAtEnd(code);
8650
+ handleInput();
8651
+ };
8652
+ const insertTextAtCaret = (text) => {
8653
+ const sel = window.getSelection();
8654
+ if (!sel || sel.rangeCount === 0) return;
8655
+ const range = sel.getRangeAt(0);
8656
+ range.deleteContents();
8657
+ const node = document.createTextNode(text);
8658
+ range.insertNode(node);
8659
+ range.setStartAfter(node);
8660
+ range.collapse(true);
8661
+ sel.removeAllRanges();
8662
+ sel.addRange(range);
8663
+ handleInput();
8664
+ };
8665
+ const ensureParagraphAfter = (node) => {
8666
+ const next = node.nextElementSibling;
8667
+ if (next && next.tagName === "P") return;
8668
+ const p = document.createElement("p");
8669
+ p.innerHTML = "<br>";
8670
+ node.after(p);
8671
+ };
8672
+ const placeCaretAtEnd = (node) => {
8673
+ const sel = window.getSelection();
8674
+ if (!sel) return;
8675
+ const r2 = document.createRange();
8676
+ r2.selectNodeContents(node);
8677
+ r2.collapse(false);
8678
+ sel.removeAllRanges();
8679
+ sel.addRange(r2);
8680
+ editorRef.current?.focus();
8681
+ };
8682
+ const clearFormat = () => {
8683
+ exec("removeFormat");
8684
+ exec("unlink");
8685
+ setBlock("p");
8686
+ };
8687
+ const indentList = (outdent) => {
8688
+ exec(outdent ? "outdent" : "indent");
8689
+ };
8690
+ const inListItem = () => {
8691
+ const sel = window.getSelection();
8692
+ const node = sel?.anchorNode;
8693
+ if (!node || !editorRef.current?.contains(node)) return false;
8694
+ const el = node.nodeType === Node.ELEMENT_NODE ? node : node.parentElement;
8695
+ return !!el?.closest("li");
8696
+ };
8697
+ const currentBlock = () => {
8698
+ const sel = window.getSelection();
8699
+ const node = sel?.anchorNode;
8700
+ const root = editorRef.current;
8701
+ if (!node || !root?.contains(node)) return null;
8702
+ let el = node.nodeType === Node.ELEMENT_NODE ? node : node.parentElement;
8703
+ while (el && el !== root && !/^(P|H[1-6]|LI|BLOCKQUOTE|PRE|DIV|TD|TH)$/.test(el.tagName)) {
8704
+ el = el.parentElement;
8705
+ }
8706
+ return el && el !== root ? el : null;
8707
+ };
8708
+ const setAlign = (align) => {
8709
+ const block = currentBlock();
8710
+ if (!block) return;
8711
+ pushHistory(true);
8712
+ block.classList.remove("align-left", "align-center", "align-right");
8713
+ if (align !== "left") block.classList.add(`align-${align}`);
8714
+ handleInput();
8715
+ };
8716
+ const toggleChecklist = () => {
8717
+ pushHistory(true);
8718
+ const block = currentBlock();
8719
+ const list = block?.closest("ul");
8720
+ if (list?.classList.contains("checklist")) {
8721
+ list.classList.remove("checklist");
8722
+ list.querySelectorAll("li").forEach((li) => li.removeAttribute("data-checked"));
8723
+ handleInput();
8724
+ return;
8725
+ }
8726
+ if (list) {
8727
+ list.classList.add("checklist");
8728
+ list.querySelectorAll("li").forEach((li) => li.setAttribute("data-checked", "false"));
8729
+ handleInput();
8730
+ return;
8731
+ }
8732
+ exec("insertUnorderedList");
8733
+ const made = currentBlock()?.closest("ul");
8734
+ if (made) {
8735
+ made.classList.add("checklist");
8736
+ made.querySelectorAll("li").forEach((li) => li.setAttribute("data-checked", "false"));
8737
+ }
8738
+ handleInput();
8739
+ };
8740
+ const handleEditorClick = (e) => {
8741
+ if (readOnly) return;
8742
+ const target = e.target;
8743
+ const li = target.closest?.("li");
8744
+ if (!li || !li.closest("ul.checklist")) return;
8745
+ const rect = li.getBoundingClientRect();
8746
+ if (e.clientX - rect.left > 20) return;
8747
+ e.preventDefault();
8748
+ pushHistory(true);
8749
+ li.setAttribute("data-checked", li.getAttribute("data-checked") === "true" ? "false" : "true");
8750
+ handleInput();
8751
+ };
8752
+ const toggleHighlight = () => {
8753
+ const sel = window.getSelection();
8754
+ if (!sel || sel.rangeCount === 0 || sel.isCollapsed) return;
8755
+ pushHistory(true);
8756
+ const range = sel.getRangeAt(0);
8757
+ const node = sel.anchorNode;
8758
+ const el = node?.nodeType === Node.ELEMENT_NODE ? node : node?.parentElement;
8759
+ const existing = el?.closest("mark");
8760
+ if (existing) {
8761
+ const parent = existing.parentNode;
8762
+ while (existing.firstChild) parent?.insertBefore(existing.firstChild, existing);
8763
+ parent?.removeChild(existing);
8764
+ handleInput();
8765
+ return;
8766
+ }
8767
+ const mark = document.createElement("mark");
8768
+ try {
8769
+ range.surroundContents(mark);
8770
+ } catch {
8771
+ const frag = range.extractContents();
8772
+ mark.appendChild(frag);
8773
+ range.insertNode(mark);
8774
+ }
8775
+ handleInput();
8776
+ };
8777
+ const insertTable = (cols = 3, rows = 2) => {
8778
+ const sel = window.getSelection();
8779
+ if (!sel || sel.rangeCount === 0) return;
8780
+ pushHistory(true);
8781
+ const table = document.createElement("table");
8782
+ const thead = document.createElement("thead");
8783
+ const headRow = document.createElement("tr");
8784
+ for (let c = 0; c < cols; c++) {
8785
+ const th = document.createElement("th");
8786
+ th.innerHTML = "<br>";
8787
+ headRow.appendChild(th);
8788
+ }
8789
+ thead.appendChild(headRow);
8790
+ table.appendChild(thead);
8791
+ const tbody = document.createElement("tbody");
8792
+ for (let r2 = 0; r2 < rows; r2++) {
8793
+ const tr = document.createElement("tr");
8794
+ for (let c = 0; c < cols; c++) {
8795
+ const td = document.createElement("td");
8796
+ td.innerHTML = "<br>";
8797
+ tr.appendChild(td);
8798
+ }
8799
+ tbody.appendChild(tr);
8800
+ }
8801
+ table.appendChild(tbody);
8802
+ const range = sel.getRangeAt(0);
8803
+ range.deleteContents();
8804
+ range.insertNode(table);
8805
+ ensureParagraphAfter(table);
8806
+ const first = table.querySelector("th");
8807
+ if (first) placeCaretAtEnd(first);
8808
+ handleInput();
8809
+ };
8810
+ const moveTableCell = (backwards) => {
8811
+ const block = currentBlock();
8812
+ const cell = block?.closest("td, th");
8813
+ if (!cell) return false;
8814
+ const table = cell.closest("table");
8815
+ if (!table) return false;
8816
+ const cells = Array.from(table.querySelectorAll("td, th"));
8817
+ const i = cells.indexOf(cell);
8818
+ const next = cells[i + (backwards ? -1 : 1)];
8819
+ if (next) {
8820
+ placeCaretAtEnd(next);
8821
+ return true;
8822
+ }
8823
+ if (!backwards) {
8824
+ pushHistory(true);
8825
+ const lastRow = table.querySelector("tbody")?.lastElementChild;
8826
+ if (lastRow) {
8827
+ const tr = document.createElement("tr");
8828
+ for (let c = 0; c < lastRow.children.length; c++) {
8829
+ const td = document.createElement("td");
8830
+ td.innerHTML = "<br>";
8831
+ tr.appendChild(td);
8832
+ }
8833
+ lastRow.after(tr);
8834
+ placeCaretAtEnd(tr.firstElementChild);
8835
+ handleInput();
8836
+ return true;
8837
+ }
8838
+ }
8839
+ return false;
8840
+ };
8142
8841
  const insertDivider = () => {
8842
+ pushHistory(true);
8143
8843
  exec("insertHorizontalRule");
8144
8844
  const el = editorRef.current;
8145
8845
  if (el && el.lastElementChild?.tagName === "HR") {
@@ -8185,7 +8885,9 @@ var Editor = (props) => {
8185
8885
  const range = sel.getRangeAt(0);
8186
8886
  slashStartRangeRef.current = range.cloneRange();
8187
8887
  const rect = range.getBoundingClientRect();
8188
- const editorRect = editorRef.current.getBoundingClientRect();
8888
+ const editorEl = editorRef.current;
8889
+ if (!editorEl) return;
8890
+ const editorRect = editorEl.getBoundingClientRect();
8189
8891
  setSlashPos({
8190
8892
  top: rect.bottom - editorRect.top + 4,
8191
8893
  left: rect.left - editorRect.left
@@ -8200,7 +8902,7 @@ var Editor = (props) => {
8200
8902
  setSlashIdx(0);
8201
8903
  slashStartRangeRef.current = null;
8202
8904
  };
8203
- const filteredSlashItems = React21.useMemo(() => {
8905
+ const filteredSlashItems = React22.useMemo(() => {
8204
8906
  if (!slashFilter) return SLASH_ITEMS;
8205
8907
  const f = slashFilter.toLowerCase();
8206
8908
  return SLASH_ITEMS.filter((it) => it.label.toLowerCase().includes(f) || it.key.includes(f));
@@ -8230,8 +8932,14 @@ var Editor = (props) => {
8230
8932
  case "paragraph":
8231
8933
  setBlock("p");
8232
8934
  break;
8233
- case "heading":
8234
- setBlock("h2");
8935
+ case "heading-1":
8936
+ toggleBlock("h1");
8937
+ break;
8938
+ case "heading-2":
8939
+ toggleBlock("h2");
8940
+ break;
8941
+ case "heading-3":
8942
+ toggleBlock("h3");
8235
8943
  break;
8236
8944
  case "list":
8237
8945
  exec("insertUnorderedList");
@@ -8243,7 +8951,7 @@ var Editor = (props) => {
8243
8951
  setBlock("blockquote");
8244
8952
  break;
8245
8953
  case "code-block":
8246
- setBlock("pre");
8954
+ insertCodeBlock();
8247
8955
  break;
8248
8956
  case "divider":
8249
8957
  insertDivider();
@@ -8261,7 +8969,9 @@ var Editor = (props) => {
8261
8969
  if (!sel || sel.rangeCount === 0) return;
8262
8970
  const range = sel.getRangeAt(0);
8263
8971
  const rect = range.getBoundingClientRect();
8264
- const editorRect = editorRef.current.getBoundingClientRect();
8972
+ const editorEl2 = editorRef.current;
8973
+ if (!editorEl2) return;
8974
+ const editorRect = editorEl2.getBoundingClientRect();
8265
8975
  setLinkPos({
8266
8976
  top: rect.bottom - editorRect.top + 4,
8267
8977
  left: rect.left - editorRect.left
@@ -8294,13 +9004,13 @@ var Editor = (props) => {
8294
9004
  if (node.nodeType !== Node.TEXT_NODE) return false;
8295
9005
  const text = (node.textContent || "").slice(0, range.startOffset);
8296
9006
  const patterns = [
8297
- [/^###\s$/, () => setBlock("h3")],
8298
- [/^##\s$/, () => setBlock("h2")],
8299
- [/^#\s$/, () => setBlock("h1")],
8300
- [/^-\s$/, () => exec("insertUnorderedList")],
8301
- [/^\*\s$/, () => exec("insertUnorderedList")],
8302
- [/^1\.\s$/, () => exec("insertOrderedList")],
8303
- [/^>\s$/, () => setBlock("blockquote")]
9007
+ [/^###$/, () => setBlock("h3")],
9008
+ [/^##$/, () => setBlock("h2")],
9009
+ [/^#$/, () => setBlock("h1")],
9010
+ [/^-$/, () => exec("insertUnorderedList")],
9011
+ [/^\*$/, () => exec("insertUnorderedList")],
9012
+ [/^1\.$/, () => exec("insertOrderedList")],
9013
+ [/^>$/, () => setBlock("blockquote")]
8304
9014
  ];
8305
9015
  for (const [re, fn] of patterns) {
8306
9016
  if (re.test(text)) {
@@ -8320,7 +9030,11 @@ var Editor = (props) => {
8320
9030
  if (composingRef.current) return;
8321
9031
  const el = editorRef.current;
8322
9032
  if (!el) return;
8323
- onChange?.(el.innerHTML);
9033
+ const html = el.innerHTML;
9034
+ lastEmittedRef.current = html;
9035
+ pushHistory();
9036
+ scheduleHighlight();
9037
+ onChange?.(html);
8324
9038
  updateEmpty();
8325
9039
  updateActiveFormats();
8326
9040
  if (slashOpen) {
@@ -8348,6 +9062,40 @@ var Editor = (props) => {
8348
9062
  };
8349
9063
  const handleKeyDown = (e) => {
8350
9064
  if (readOnly) return;
9065
+ if (composingRef.current || e.nativeEvent.isComposing || e.keyCode === 229) return;
9066
+ const pre = closestPre();
9067
+ if (pre && !slashOpen) {
9068
+ if (e.key === "Enter" && !e.shiftKey) {
9069
+ const text = pre.textContent || "";
9070
+ if (text.endsWith("\n\n")) {
9071
+ e.preventDefault();
9072
+ const code = pre.querySelector("code") ?? pre;
9073
+ code.textContent = text.replace(/\n\n$/, "");
9074
+ ensureParagraphAfter(pre);
9075
+ const next = pre.nextElementSibling;
9076
+ if (next) placeCaretAtEnd(next);
9077
+ handleInput();
9078
+ return;
9079
+ }
9080
+ e.preventDefault();
9081
+ insertTextAtCaret("\n");
9082
+ return;
9083
+ }
9084
+ if (e.key === "Tab") {
9085
+ e.preventDefault();
9086
+ insertTextAtCaret(" ");
9087
+ return;
9088
+ }
9089
+ }
9090
+ if (e.key === "Tab" && moveTableCell(e.shiftKey)) {
9091
+ e.preventDefault();
9092
+ return;
9093
+ }
9094
+ if (e.key === "Tab" && inListItem()) {
9095
+ e.preventDefault();
9096
+ indentList(e.shiftKey);
9097
+ return;
9098
+ }
8351
9099
  if (slashOpen) {
8352
9100
  if (e.key === "ArrowDown") {
8353
9101
  e.preventDefault();
@@ -8371,6 +9119,21 @@ var Editor = (props) => {
8371
9119
  return;
8372
9120
  }
8373
9121
  }
9122
+ if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === "z") {
9123
+ e.preventDefault();
9124
+ if (e.shiftKey) redo();
9125
+ else undo();
9126
+ return;
9127
+ }
9128
+ if ((e.metaKey || e.ctrlKey) && e.shiftKey && e.key.toLowerCase() === "v") {
9129
+ plainPasteRef.current = true;
9130
+ return;
9131
+ }
9132
+ if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === "y") {
9133
+ e.preventDefault();
9134
+ redo();
9135
+ return;
9136
+ }
8374
9137
  if ((e.metaKey || e.ctrlKey) && !e.shiftKey && !e.altKey) {
8375
9138
  const k = e.key.toLowerCase();
8376
9139
  if (k === "b") {
@@ -8394,6 +9157,7 @@ var Editor = (props) => {
8394
9157
  return;
8395
9158
  }
8396
9159
  }
9160
+ if (pre) return;
8397
9161
  if (enableSlashCommand && e.key === "/") {
8398
9162
  setTimeout(openSlashMenu, 0);
8399
9163
  }
@@ -8403,11 +9167,21 @@ var Editor = (props) => {
8403
9167
  }
8404
9168
  }
8405
9169
  };
9170
+ const plainPasteRef = React22.useRef(false);
8406
9171
  const handlePaste = (e) => {
8407
9172
  if (readOnly) return;
8408
9173
  e.preventDefault();
8409
- const html = e.clipboardData.getData("text/html");
8410
9174
  const text = e.clipboardData.getData("text/plain");
9175
+ if (plainPasteRef.current) {
9176
+ plainPasteRef.current = false;
9177
+ insertTextAtCaret(text);
9178
+ return;
9179
+ }
9180
+ if (closestPre()) {
9181
+ insertTextAtCaret(text);
9182
+ return;
9183
+ }
9184
+ const html = e.clipboardData.getData("text/html");
8411
9185
  const clean = html ? sanitizeHtml(html) : escapeHtml(text);
8412
9186
  document.execCommand("insertHTML", false, clean);
8413
9187
  handleInput();
@@ -8429,8 +9203,11 @@ var Editor = (props) => {
8429
9203
  };
8430
9204
  const handleSelectionUpdate = () => {
8431
9205
  updateActiveFormats();
9206
+ const pre = closestPre();
9207
+ setCodeLang(pre ? langOf(pre) : "plain");
8432
9208
  };
8433
9209
  const onToolbarAction = (item) => {
9210
+ if (closestPre() && !["code-block", "undo", "redo"].includes(item)) return;
8434
9211
  switch (item) {
8435
9212
  case "bold":
8436
9213
  exec("bold");
@@ -8459,8 +9236,14 @@ var Editor = (props) => {
8459
9236
  handleInput();
8460
9237
  break;
8461
9238
  }
8462
- case "heading":
8463
- setBlock("h2");
9239
+ case "heading-1":
9240
+ toggleBlock("h1");
9241
+ break;
9242
+ case "heading-2":
9243
+ toggleBlock("h2");
9244
+ break;
9245
+ case "heading-3":
9246
+ toggleBlock("h3");
8464
9247
  break;
8465
9248
  case "list":
8466
9249
  exec("insertUnorderedList");
@@ -8472,7 +9255,7 @@ var Editor = (props) => {
8472
9255
  setBlock("blockquote");
8473
9256
  break;
8474
9257
  case "code-block":
8475
- setBlock("pre");
9258
+ insertCodeBlock();
8476
9259
  break;
8477
9260
  case "link":
8478
9261
  openLinkEditor();
@@ -8483,6 +9266,39 @@ var Editor = (props) => {
8483
9266
  case "divider":
8484
9267
  insertDivider();
8485
9268
  break;
9269
+ case "checklist":
9270
+ toggleChecklist();
9271
+ break;
9272
+ case "align-left":
9273
+ setAlign("left");
9274
+ break;
9275
+ case "align-center":
9276
+ setAlign("center");
9277
+ break;
9278
+ case "align-right":
9279
+ setAlign("right");
9280
+ break;
9281
+ case "highlight":
9282
+ toggleHighlight();
9283
+ break;
9284
+ case "superscript":
9285
+ exec("superscript");
9286
+ break;
9287
+ case "subscript":
9288
+ exec("subscript");
9289
+ break;
9290
+ case "table":
9291
+ insertTable();
9292
+ break;
9293
+ case "clear-format":
9294
+ clearFormat();
9295
+ break;
9296
+ case "undo":
9297
+ undo();
9298
+ break;
9299
+ case "redo":
9300
+ redo();
9301
+ break;
8486
9302
  }
8487
9303
  };
8488
9304
  return /* @__PURE__ */ jsxs207("div", { className: clsx_default("lib-xplat-editor", isFocused && "focused", readOnly && "readonly"), children: [
@@ -8491,7 +9307,10 @@ var Editor = (props) => {
8491
9307
  {
8492
9308
  items: toolbar,
8493
9309
  active: activeFormats,
8494
- onAction: onToolbarAction
9310
+ onAction: onToolbarAction,
9311
+ codeLang,
9312
+ inCodeBlock: activeFormats.has("block:pre"),
9313
+ onCodeLangChange: changeCodeLang
8495
9314
  }
8496
9315
  ),
8497
9316
  /* @__PURE__ */ jsxs207("div", { className: "lib-xplat-editor__content", style: { minHeight }, children: [
@@ -8502,9 +9321,14 @@ var Editor = (props) => {
8502
9321
  ref: editorRef,
8503
9322
  contentEditable: !readOnly,
8504
9323
  suppressContentEditableWarning: true,
9324
+ role: "textbox",
9325
+ "aria-multiline": "true",
9326
+ "aria-readonly": readOnly || void 0,
9327
+ "aria-label": placeholder,
8505
9328
  className: "lib-xplat-editor__editable",
8506
9329
  onInput: handleInput,
8507
9330
  onKeyDown: handleKeyDown,
9331
+ onClick: handleEditorClick,
8508
9332
  onKeyUp: handleSelectionUpdate,
8509
9333
  onMouseUp: handleSelectionUpdate,
8510
9334
  onPaste: handlePaste,
@@ -8546,14 +9370,27 @@ var TOOLBAR_LABEL = {
8546
9370
  underline: "U",
8547
9371
  strikethrough: "S",
8548
9372
  code: "<>",
8549
- heading: "H",
9373
+ "heading-1": "H1",
9374
+ "heading-2": "H2",
9375
+ "heading-3": "H3",
8550
9376
  list: "\u2022",
8551
9377
  "ordered-list": "1.",
8552
9378
  blockquote: "\u275D",
8553
9379
  "code-block": "[ ]",
8554
9380
  link: "\u{1F517}",
8555
9381
  image: "\u{1F5BC}",
8556
- divider: "\u2014"
9382
+ divider: "\u2014",
9383
+ checklist: "\u2611",
9384
+ "align-left": "\u21E4",
9385
+ "align-center": "\u2194",
9386
+ "align-right": "\u21E5",
9387
+ highlight: "\u{1F58D}",
9388
+ superscript: "x\xB2",
9389
+ subscript: "x\u2082",
9390
+ table: "\u25A6",
9391
+ "clear-format": "\u232B",
9392
+ undo: "\u21B6",
9393
+ redo: "\u21B7"
8557
9394
  };
8558
9395
  var TOOLBAR_TITLE = {
8559
9396
  bold: "\uAD75\uAC8C (\u2318B)",
@@ -8561,39 +9398,77 @@ var TOOLBAR_TITLE = {
8561
9398
  underline: "\uBC11\uC904 (\u2318U)",
8562
9399
  strikethrough: "\uCDE8\uC18C\uC120",
8563
9400
  code: "\uC778\uB77C\uC778 \uCF54\uB4DC",
8564
- heading: "\uC81C\uBAA9",
9401
+ "heading-1": "\uC81C\uBAA9 1",
9402
+ "heading-2": "\uC81C\uBAA9 2",
9403
+ "heading-3": "\uC81C\uBAA9 3",
8565
9404
  list: "\uAE00\uBA38\uB9AC \uAE30\uD638 \uBAA9\uB85D",
8566
9405
  "ordered-list": "\uBC88\uD638 \uB9E4\uAE30\uAE30 \uBAA9\uB85D",
8567
9406
  blockquote: "\uC778\uC6A9",
8568
9407
  "code-block": "\uCF54\uB4DC \uBE14\uB85D",
8569
9408
  link: "\uB9C1\uD06C (\u2318K)",
8570
9409
  image: "\uC774\uBBF8\uC9C0",
8571
- divider: "\uAD6C\uBD84\uC120"
9410
+ divider: "\uAD6C\uBD84\uC120",
9411
+ checklist: "\uCCB4\uD06C\uB9AC\uC2A4\uD2B8",
9412
+ "align-left": "\uC67C\uCABD \uC815\uB82C",
9413
+ "align-center": "\uAC00\uC6B4\uB370 \uC815\uB82C",
9414
+ "align-right": "\uC624\uB978\uCABD \uC815\uB82C",
9415
+ highlight: "\uD615\uAD11\uD39C",
9416
+ superscript: "\uC704 \uCCA8\uC790",
9417
+ subscript: "\uC544\uB798 \uCCA8\uC790",
9418
+ table: "\uD45C \uC0BD\uC785",
9419
+ "clear-format": "\uC11C\uC2DD \uC9C0\uC6B0\uAE30",
9420
+ undo: "\uB418\uB3CC\uB9AC\uAE30 (\u2318Z)",
9421
+ redo: "\uB2E4\uC2DC\uD558\uAE30 (\u2318\u21E7Z)"
8572
9422
  };
8573
9423
  var isActive = (item, active) => {
8574
- if (item === "heading") return active.has("block:h1") || active.has("block:h2") || active.has("block:h3");
9424
+ if (item === "heading-1") return active.has("block:h1");
9425
+ if (item === "heading-2") return active.has("block:h2");
9426
+ if (item === "heading-3") return active.has("block:h3");
8575
9427
  if (item === "blockquote") return active.has("block:blockquote");
8576
9428
  if (item === "code-block") return active.has("block:pre");
9429
+ if (item === "align-left") return active.has("align:left");
9430
+ if (item === "align-center") return active.has("align:center");
9431
+ if (item === "align-right") return active.has("align:right");
8577
9432
  return active.has(item);
8578
9433
  };
8579
- var EditorToolbar = ({ items, active, onAction }) => {
8580
- return /* @__PURE__ */ jsx323("div", { className: "lib-xplat-editor__toolbar", children: items.map((item) => /* @__PURE__ */ jsx323(
8581
- "button",
8582
- {
8583
- type: "button",
8584
- className: clsx_default("lib-xplat-editor__toolbar-btn", isActive(item, active) && "active"),
8585
- title: TOOLBAR_TITLE[item],
8586
- onMouseDown: (e) => {
8587
- e.preventDefault();
8588
- onAction(item);
9434
+ var EditorToolbar = ({
9435
+ items,
9436
+ active,
9437
+ onAction,
9438
+ codeLang,
9439
+ inCodeBlock,
9440
+ onCodeLangChange
9441
+ }) => {
9442
+ return /* @__PURE__ */ jsxs207("div", { className: "lib-xplat-editor__toolbar", children: [
9443
+ items.map((item) => /* @__PURE__ */ jsx323(
9444
+ "button",
9445
+ {
9446
+ type: "button",
9447
+ className: clsx_default("lib-xplat-editor__toolbar-btn", isActive(item, active) && "active"),
9448
+ title: TOOLBAR_TITLE[item],
9449
+ onMouseDown: (e) => {
9450
+ e.preventDefault();
9451
+ onAction(item);
9452
+ },
9453
+ children: TOOLBAR_LABEL[item]
8589
9454
  },
8590
- children: TOOLBAR_LABEL[item]
8591
- },
8592
- item
8593
- )) });
9455
+ item
9456
+ )),
9457
+ inCodeBlock && /* @__PURE__ */ jsx323(
9458
+ "select",
9459
+ {
9460
+ className: "lib-xplat-editor__lang",
9461
+ value: codeLang,
9462
+ "aria-label": "\uCF54\uB4DC \uC5B8\uC5B4",
9463
+ onMouseDown: (e) => e.stopPropagation(),
9464
+ onChange: (e) => onCodeLangChange(e.target.value),
9465
+ children: CODE_LANGUAGES.map((l) => /* @__PURE__ */ jsx323("option", { value: l.value, children: l.label }, l.value))
9466
+ }
9467
+ )
9468
+ ] });
8594
9469
  };
8595
9470
  var SlashMenu = ({ position, items, activeIndex, onSelect, onClose }) => {
8596
- React21.useEffect(() => {
9471
+ React22.useEffect(() => {
8597
9472
  const handleClickOutside = (e) => {
8598
9473
  const target = e.target;
8599
9474
  const menu = document.querySelector(".lib-xplat-editor__slash-menu");
@@ -8627,8 +9502,8 @@ var SlashMenu = ({ position, items, activeIndex, onSelect, onClose }) => {
8627
9502
  );
8628
9503
  };
8629
9504
  var LinkPopover = ({ position, value, onChange, onConfirm, onClose }) => {
8630
- const inputRef = React21.useRef(null);
8631
- React21.useEffect(() => {
9505
+ const inputRef = React22.useRef(null);
9506
+ React22.useEffect(() => {
8632
9507
  inputRef.current?.focus();
8633
9508
  }, []);
8634
9509
  return /* @__PURE__ */ jsxs207(
@@ -8686,7 +9561,7 @@ EmptyState.displayName = "EmptyState";
8686
9561
  var EmptyState_default = EmptyState;
8687
9562
 
8688
9563
  // src/components/FileUpload/FileUpload.tsx
8689
- import React22 from "react";
9564
+ import React23 from "react";
8690
9565
  import { jsx as jsx325, jsxs as jsxs209 } from "react/jsx-runtime";
8691
9566
  var FileUpload = (props) => {
8692
9567
  const {
@@ -8698,8 +9573,8 @@ var FileUpload = (props) => {
8698
9573
  description,
8699
9574
  validations
8700
9575
  } = props;
8701
- const [isDragOver, setIsDragOver] = React22.useState(false);
8702
- const inputRef = React22.useRef(null);
9576
+ const [isDragOver, setIsDragOver] = React23.useState(false);
9577
+ const inputRef = React23.useRef(null);
8703
9578
  const handleFiles = (fileList) => {
8704
9579
  let files = Array.from(fileList);
8705
9580
  if (maxSize) {
@@ -8761,10 +9636,10 @@ FileUpload.displayName = "FileUpload";
8761
9636
  var FileUpload_default = FileUpload;
8762
9637
 
8763
9638
  // src/components/HtmlTypeWriter/HtmlTypeWriter.tsx
8764
- import React24 from "react";
9639
+ import React25 from "react";
8765
9640
 
8766
9641
  // src/components/HtmlTypeWriter/utils.ts
8767
- import React23 from "react";
9642
+ import React24 from "react";
8768
9643
  var voidTags = /* @__PURE__ */ new Set([
8769
9644
  "br",
8770
9645
  "img",
@@ -8832,15 +9707,15 @@ var convertNodeToReactWithRange = (node, typedLen, rangeMap) => {
8832
9707
  props[attr.name] = attr.value;
8833
9708
  });
8834
9709
  if (voidTags.has(tag)) {
8835
- return React23.createElement(tag, props);
9710
+ return React24.createElement(tag, props);
8836
9711
  }
8837
9712
  const children = Array.from(element.childNodes).map((child) => convertNodeToReactWithRange(child, typedLen, rangeMap)).filter((n) => n != null);
8838
- return React23.createElement(tag, props, ...children);
9713
+ return React24.createElement(tag, props, ...children);
8839
9714
  };
8840
9715
  var htmlToReactProgressive = (root, typedLen, rangeMap) => {
8841
9716
  const nodes = Array.from(root.childNodes).map((child, idx) => {
8842
9717
  const node = convertNodeToReactWithRange(child, typedLen, rangeMap);
8843
- return node == null ? null : React23.createElement(React23.Fragment, { key: idx }, node);
9718
+ return node == null ? null : React24.createElement(React24.Fragment, { key: idx }, node);
8844
9719
  }).filter(Boolean);
8845
9720
  return nodes.length === 0 ? null : nodes;
8846
9721
  };
@@ -8853,20 +9728,20 @@ var HtmlTypeWriter = ({
8853
9728
  onDone,
8854
9729
  onChange
8855
9730
  }) => {
8856
- const [typedLen, setTypedLen] = React24.useState(0);
8857
- const doneCalledRef = React24.useRef(false);
8858
- const { doc, rangeMap, totalLength } = React24.useMemo(() => {
9731
+ const [typedLen, setTypedLen] = React25.useState(0);
9732
+ const doneCalledRef = React25.useRef(false);
9733
+ const { doc, rangeMap, totalLength } = React25.useMemo(() => {
8859
9734
  if (typeof window === "undefined") return { doc: null, rangeMap: /* @__PURE__ */ new Map(), totalLength: 0 };
8860
9735
  const decoded = decodeHtmlEntities(html);
8861
9736
  const doc2 = new DOMParser().parseFromString(decoded, "text/html");
8862
9737
  const { rangeMap: rangeMap2, totalLength: totalLength2 } = buildRangeMap(doc2.body);
8863
9738
  return { doc: doc2, rangeMap: rangeMap2, totalLength: totalLength2 };
8864
9739
  }, [html]);
8865
- React24.useEffect(() => {
9740
+ React25.useEffect(() => {
8866
9741
  setTypedLen(0);
8867
9742
  doneCalledRef.current = false;
8868
9743
  }, [html]);
8869
- React24.useEffect(() => {
9744
+ React25.useEffect(() => {
8870
9745
  if (!totalLength) return;
8871
9746
  if (typedLen >= totalLength) return;
8872
9747
  const timer = window.setInterval(() => {
@@ -8874,18 +9749,18 @@ var HtmlTypeWriter = ({
8874
9749
  }, duration);
8875
9750
  return () => window.clearInterval(timer);
8876
9751
  }, [typedLen, totalLength, duration]);
8877
- React24.useEffect(() => {
9752
+ React25.useEffect(() => {
8878
9753
  if (typedLen > 0 && typedLen < totalLength) {
8879
9754
  onChange?.();
8880
9755
  }
8881
9756
  }, [typedLen, totalLength, onChange]);
8882
- React24.useEffect(() => {
9757
+ React25.useEffect(() => {
8883
9758
  if (typedLen === totalLength && totalLength > 0 && !doneCalledRef.current) {
8884
9759
  doneCalledRef.current = true;
8885
9760
  onDone?.();
8886
9761
  }
8887
9762
  }, [typedLen, totalLength, onDone]);
8888
- const parsed = React24.useMemo(
9763
+ const parsed = React25.useMemo(
8889
9764
  () => doc ? htmlToReactProgressive(doc.body, typedLen, rangeMap) : null,
8890
9765
  [doc, typedLen, rangeMap]
8891
9766
  );
@@ -8895,12 +9770,12 @@ HtmlTypeWriter.displayName = "HtmlTypeWriter";
8895
9770
  var HtmlTypeWriter_default = HtmlTypeWriter;
8896
9771
 
8897
9772
  // src/components/ImageSelector/ImageSelector.tsx
8898
- import React25 from "react";
9773
+ import React26 from "react";
8899
9774
  import { jsx as jsx327, jsxs as jsxs210 } from "react/jsx-runtime";
8900
9775
  var ImageSelector = (props) => {
8901
9776
  const { value, label, onChange, validations } = props;
8902
- const [previewUrl, setPreviewUrl] = React25.useState();
8903
- React25.useEffect(() => {
9777
+ const [previewUrl, setPreviewUrl] = React26.useState();
9778
+ React26.useEffect(() => {
8904
9779
  if (!value) {
8905
9780
  setPreviewUrl(void 0);
8906
9781
  return;
@@ -8909,7 +9784,7 @@ var ImageSelector = (props) => {
8909
9784
  setPreviewUrl(url);
8910
9785
  return () => URL.revokeObjectURL(url);
8911
9786
  }, [value]);
8912
- const inputRef = React25.useRef(null);
9787
+ const inputRef = React26.useRef(null);
8913
9788
  const handleFileChange = (e) => {
8914
9789
  const selectedFile = e.target.files?.[0];
8915
9790
  if (selectedFile) {
@@ -9092,17 +9967,21 @@ Pagination.displayName = "Pagination";
9092
9967
  var Pagination_default = Pagination;
9093
9968
 
9094
9969
  // src/components/PopOver/PopOver.tsx
9095
- import React26 from "react";
9970
+ import React27 from "react";
9096
9971
  import { jsx as jsx332, jsxs as jsxs213 } from "react/jsx-runtime";
9097
9972
  var PopOver = (props) => {
9098
9973
  const { children, isOpen, onClose, PopOverEl } = props;
9099
- const popRef = React26.useRef(null);
9100
- const triggerRef = React26.useRef(null);
9101
- const [localOpen, setLocalOpen] = React26.useState(false);
9102
- const [eventTrigger, setEventTrigger] = React26.useState(false);
9974
+ const popRef = React27.useRef(null);
9975
+ const triggerRef = React27.useRef(null);
9976
+ const [localOpen, setLocalOpen] = React27.useState(false);
9977
+ const [eventTrigger, setEventTrigger] = React27.useState(false);
9103
9978
  useClickOutside_default([popRef, triggerRef], onClose, isOpen);
9979
+ useEscapeKey(isOpen, () => {
9980
+ onClose();
9981
+ triggerRef.current?.focus({ preventScroll: true });
9982
+ });
9104
9983
  const position = useAutoPosition_default(triggerRef, popRef, localOpen);
9105
- React26.useEffect(() => {
9984
+ React27.useEffect(() => {
9106
9985
  if (isOpen) {
9107
9986
  setLocalOpen(isOpen);
9108
9987
  setTimeout(() => {
@@ -9131,6 +10010,7 @@ var PopOver = (props) => {
9131
10010
  className: clsx_default(
9132
10011
  "lib-xplat-pop-over-content",
9133
10012
  position.direction,
10013
+ position.repositioning && "repositioning",
9134
10014
  eventTrigger && "visible"
9135
10015
  ),
9136
10016
  ref: popRef,
@@ -9187,12 +10067,12 @@ Progress.displayName = "Progress";
9187
10067
  var Progress_default = Progress;
9188
10068
 
9189
10069
  // src/components/Radio/RadioGroupContext.tsx
9190
- import React27 from "react";
9191
- var RadioGroupContext = React27.createContext(
10070
+ import React28 from "react";
10071
+ var RadioGroupContext = React28.createContext(
9192
10072
  null
9193
10073
  );
9194
10074
  var useRadioGroupContext = () => {
9195
- return React27.useContext(RadioGroupContext);
10075
+ return React28.useContext(RadioGroupContext);
9196
10076
  };
9197
10077
  var RadioGroupContext_default = RadioGroupContext;
9198
10078
 
@@ -9268,19 +10148,19 @@ RadioGroup.displayName = "RadioGroup";
9268
10148
  var RadioGroup_default = RadioGroup;
9269
10149
 
9270
10150
  // src/components/Select/Select.tsx
9271
- import React30 from "react";
10151
+ import React31 from "react";
9272
10152
 
9273
10153
  // src/components/Select/context.ts
9274
- import React28 from "react";
9275
- var SelectContext = React28.createContext(null);
10154
+ import React29 from "react";
10155
+ var SelectContext = React29.createContext(null);
9276
10156
  var context_default = SelectContext;
9277
10157
 
9278
10158
  // src/components/Select/SelectItem.tsx
9279
- import React29 from "react";
10159
+ import React30 from "react";
9280
10160
  import { jsx as jsx336 } from "react/jsx-runtime";
9281
10161
  var SelectItem = (props) => {
9282
10162
  const { children, value, onClick, disabled = false } = props;
9283
- const ctx = React29.useContext(context_default);
10163
+ const ctx = React30.useContext(context_default);
9284
10164
  const handleClick = (e) => {
9285
10165
  e.preventDefault();
9286
10166
  e.stopPropagation();
@@ -9320,32 +10200,37 @@ var SelectRoot = (props) => {
9320
10200
  onChange,
9321
10201
  children,
9322
10202
  disabled = false,
10203
+ searchable = false,
10204
+ searchPlaceholder = "\uAC80\uC0C9",
9323
10205
  error = false,
9324
10206
  validations,
10207
+ label,
10208
+ required,
9325
10209
  size = "md"
9326
10210
  } = props;
9327
- const itemChildren = React30.Children.toArray(children).filter(
9328
- (child) => React30.isValidElement(child) && child.type === SelectItem_default
10211
+ const fieldId = React31.useId();
10212
+ const itemChildren = React31.Children.toArray(children).filter(
10213
+ (child) => React31.isValidElement(child) && child.type === SelectItem_default
9329
10214
  );
9330
10215
  const isControlled = valueProp !== void 0;
9331
- const [isOpen, setOpen] = React30.useState(false);
9332
- const [uncontrolledLabel, setUncontrolledLabel] = React30.useState(null);
9333
- const [uncontrolledValue, setUncontrolledValue] = React30.useState(void 0);
9334
- const controlledLabel = React30.useMemo(() => {
10216
+ const [isOpen, setOpen] = React31.useState(false);
10217
+ const [uncontrolledLabel, setUncontrolledLabel] = React31.useState(null);
10218
+ const [uncontrolledValue, setUncontrolledValue] = React31.useState(void 0);
10219
+ const controlledLabel = React31.useMemo(() => {
9335
10220
  if (!isControlled) return null;
9336
10221
  const match = itemChildren.find((child) => child.props.value === valueProp);
9337
10222
  return match ? match.props.children : null;
9338
10223
  }, [isControlled, valueProp, itemChildren]);
9339
10224
  const selectedLabel = isControlled ? controlledLabel : uncontrolledLabel;
9340
10225
  const selectedValue = isControlled ? valueProp : uncontrolledValue;
9341
- const triggerRef = React30.useRef(null);
9342
- const contentRef = React30.useRef(null);
9343
- const [mounted, setMounted] = React30.useState(false);
9344
- const [visible, setVisible] = React30.useState(false);
9345
- React30.useEffect(() => {
10226
+ const triggerRef = React31.useRef(null);
10227
+ const contentRef = React31.useRef(null);
10228
+ const [mounted, setMounted] = React31.useState(false);
10229
+ const [visible, setVisible] = React31.useState(false);
10230
+ React31.useEffect(() => {
9346
10231
  if (disabled && isOpen) setOpen(false);
9347
10232
  }, [disabled, isOpen]);
9348
- React30.useEffect(() => {
10233
+ React31.useEffect(() => {
9349
10234
  if (isOpen) {
9350
10235
  setMounted(true);
9351
10236
  const t2 = setTimeout(() => setVisible(true), 1);
@@ -9355,22 +10240,42 @@ var SelectRoot = (props) => {
9355
10240
  const t = setTimeout(() => setMounted(false), ANIMATION_DURATION_MS3);
9356
10241
  return () => clearTimeout(t);
9357
10242
  }, [isOpen]);
9358
- const open = React30.useCallback(() => setOpen(true), []);
9359
- const close = React30.useCallback(() => setOpen(false), []);
9360
- const toggle = React30.useCallback(() => setOpen((prev) => !prev), []);
10243
+ const [query, setQuery] = React31.useState("");
10244
+ const textOf = (node) => {
10245
+ if (node === null || node === void 0 || typeof node === "boolean") return "";
10246
+ if (typeof node === "string" || typeof node === "number") return String(node);
10247
+ if (Array.isArray(node)) return node.map(textOf).join("");
10248
+ if (React31.isValidElement(node)) return textOf(node.props.children);
10249
+ return "";
10250
+ };
10251
+ const visibleItems = React31.useMemo(() => {
10252
+ if (!searchable || !query.trim()) return itemChildren;
10253
+ const q = query.trim().toLowerCase();
10254
+ return itemChildren.filter((c) => textOf(c.props.children).toLowerCase().includes(q));
10255
+ }, [searchable, query, itemChildren]);
10256
+ const open = React31.useCallback(() => setOpen(true), []);
10257
+ const close = React31.useCallback(() => {
10258
+ setOpen(false);
10259
+ setQuery("");
10260
+ }, []);
10261
+ const toggle = React31.useCallback(() => setOpen((prev) => !prev), []);
9361
10262
  useClickOutside_default([contentRef, triggerRef], close, isOpen);
10263
+ useEscapeKey(isOpen, () => {
10264
+ close();
10265
+ triggerRef.current?.focus({ preventScroll: true });
10266
+ });
9362
10267
  const position = useAutoPosition_default(triggerRef, contentRef, mounted);
9363
- const setSelected = React30.useCallback(
9364
- (label, itemValue) => {
10268
+ const setSelected = React31.useCallback(
10269
+ (label2, itemValue) => {
9365
10270
  if (!isControlled) {
9366
- setUncontrolledLabel(label);
10271
+ setUncontrolledLabel(label2);
9367
10272
  setUncontrolledValue(itemValue);
9368
10273
  }
9369
- onChange?.(itemValue, label);
10274
+ onChange?.(itemValue, label2);
9370
10275
  },
9371
10276
  [isControlled, onChange]
9372
10277
  );
9373
- const ctxValue = React30.useMemo(
10278
+ const ctxValue = React31.useMemo(
9374
10279
  () => ({
9375
10280
  isOpen,
9376
10281
  mounted,
@@ -9406,6 +10311,7 @@ var SelectRoot = (props) => {
9406
10311
  /* @__PURE__ */ jsxs216(
9407
10312
  "div",
9408
10313
  {
10314
+ id: fieldId,
9409
10315
  ref: triggerRef,
9410
10316
  className: clsx_default(
9411
10317
  "select-trigger",
@@ -9448,20 +10354,33 @@ var SelectRoot = (props) => {
9448
10354
  ]
9449
10355
  }
9450
10356
  ),
9451
- mounted && /* @__PURE__ */ jsx337(Portal_default, { children: /* @__PURE__ */ jsx337(
10357
+ mounted && /* @__PURE__ */ jsx337(Portal_default, { children: /* @__PURE__ */ jsxs216(
9452
10358
  "div",
9453
10359
  {
9454
- className: clsx_default("lib-xplat-select-content", size, position.direction, stateClass),
10360
+ className: clsx_default("lib-xplat-select-content", size, position.direction, stateClass, position.repositioning && "repositioning"),
9455
10361
  ref: contentRef,
9456
10362
  style: { ...position.position, width: triggerRef.current?.offsetWidth },
9457
10363
  role: "listbox",
9458
- children: /* @__PURE__ */ jsx337(context_default.Provider, { value: ctxValue, children: itemChildren })
10364
+ children: [
10365
+ searchable && /* @__PURE__ */ jsx337("div", { className: "select-search", children: /* @__PURE__ */ jsx337(
10366
+ "input",
10367
+ {
10368
+ type: "text",
10369
+ value: query,
10370
+ placeholder: searchPlaceholder,
10371
+ onChange: (e) => setQuery(e.target.value),
10372
+ autoFocus: true,
10373
+ "aria-label": searchPlaceholder
10374
+ }
10375
+ ) }),
10376
+ /* @__PURE__ */ jsx337(context_default.Provider, { value: ctxValue, children: visibleItems.length > 0 ? visibleItems : /* @__PURE__ */ jsx337("div", { className: "select-empty", children: "\uACB0\uACFC\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4" }) })
10377
+ ]
9459
10378
  }
9460
10379
  ) })
9461
10380
  ]
9462
10381
  }
9463
10382
  ) });
9464
- return /* @__PURE__ */ jsx337(Field, { validations, children: control });
10383
+ return /* @__PURE__ */ jsx337(Field, { validations, label, required, htmlFor: fieldId, children: control });
9465
10384
  };
9466
10385
  SelectRoot.displayName = "Select";
9467
10386
  var Select = Object.assign(SelectRoot, {
@@ -9541,8 +10460,44 @@ var Spinner = (props) => {
9541
10460
  Spinner.displayName = "Spinner";
9542
10461
  var Spinner_default = Spinner;
9543
10462
 
9544
- // src/components/Steps/Steps.tsx
10463
+ // src/components/Stat/Stat.tsx
9545
10464
  import { jsx as jsx340, jsxs as jsxs218 } from "react/jsx-runtime";
10465
+ var ARROW = {
10466
+ up: "\u25B2",
10467
+ down: "\u25BC",
10468
+ flat: "\u2014"
10469
+ };
10470
+ var Stat = (props) => {
10471
+ const {
10472
+ label,
10473
+ value,
10474
+ unit,
10475
+ description,
10476
+ trend,
10477
+ icon,
10478
+ size = "md",
10479
+ type = "primary"
10480
+ } = props;
10481
+ const statusType = normalizeStatus(type);
10482
+ return /* @__PURE__ */ jsxs218("div", { className: clsx_default("lib-xplat-stat", size, statusType), children: [
10483
+ /* @__PURE__ */ jsx340("div", { className: "stat-label", children: label }),
10484
+ /* @__PURE__ */ jsxs218("div", { className: "stat-value-row", children: [
10485
+ icon && /* @__PURE__ */ jsx340("span", { className: "stat-icon", children: icon }),
10486
+ /* @__PURE__ */ jsx340("span", { className: "stat-value", children: value }),
10487
+ unit && /* @__PURE__ */ jsx340("span", { className: "stat-unit", children: unit }),
10488
+ trend && /* @__PURE__ */ jsxs218("span", { className: clsx_default("stat-trend", trend.direction), children: [
10489
+ /* @__PURE__ */ jsx340("span", { "aria-hidden": "true", children: ARROW[trend.direction] }),
10490
+ trend.value
10491
+ ] })
10492
+ ] }),
10493
+ description && /* @__PURE__ */ jsx340("div", { className: "stat-description", children: description })
10494
+ ] });
10495
+ };
10496
+ Stat.displayName = "Stat";
10497
+ var Stat_default = Stat;
10498
+
10499
+ // src/components/Steps/Steps.tsx
10500
+ import { jsx as jsx341, jsxs as jsxs219 } from "react/jsx-runtime";
9546
10501
  var Steps = (props) => {
9547
10502
  const {
9548
10503
  items,
@@ -9550,13 +10505,13 @@ var Steps = (props) => {
9550
10505
  type = "primary"
9551
10506
  } = props;
9552
10507
  const statusType = normalizeStatus(type);
9553
- return /* @__PURE__ */ jsx340("div", { className: clsx_default("lib-xplat-steps", statusType), children: items.map((item, index) => {
10508
+ return /* @__PURE__ */ jsx341("div", { className: clsx_default("lib-xplat-steps", statusType), children: items.map((item, index) => {
9554
10509
  const status = index < current ? "completed" : index === current ? "active" : "pending";
9555
- return /* @__PURE__ */ jsxs218("div", { className: clsx_default("step-item", status), children: [
9556
- /* @__PURE__ */ jsx340("div", { className: "step-circle", children: status === "completed" ? /* @__PURE__ */ jsx340(CheckIcon_default, {}) : /* @__PURE__ */ jsx340("span", { children: index + 1 }) }),
9557
- /* @__PURE__ */ jsxs218("div", { className: "step-content", children: [
9558
- /* @__PURE__ */ jsx340("span", { className: "step-title", children: item.title }),
9559
- item.description && /* @__PURE__ */ jsx340("span", { className: "step-description", children: item.description })
10510
+ return /* @__PURE__ */ jsxs219("div", { className: clsx_default("step-item", status), children: [
10511
+ /* @__PURE__ */ jsx341("div", { className: "step-circle", children: status === "completed" ? /* @__PURE__ */ jsx341(CheckIcon_default, {}) : /* @__PURE__ */ jsx341("span", { children: index + 1 }) }),
10512
+ /* @__PURE__ */ jsxs219("div", { className: "step-content", children: [
10513
+ /* @__PURE__ */ jsx341("span", { className: "step-title", children: item.title }),
10514
+ item.description && /* @__PURE__ */ jsx341("span", { className: "step-description", children: item.description })
9560
10515
  ] })
9561
10516
  ] }, index);
9562
10517
  }) });
@@ -9565,8 +10520,8 @@ Steps.displayName = "Steps";
9565
10520
  var Steps_default = Steps;
9566
10521
 
9567
10522
  // src/components/Swiper/Swiper.tsx
9568
- import React31 from "react";
9569
- import { jsx as jsx341, jsxs as jsxs219 } from "react/jsx-runtime";
10523
+ import React32 from "react";
10524
+ import { jsx as jsx342, jsxs as jsxs220 } from "react/jsx-runtime";
9570
10525
  var Swiper = (props) => {
9571
10526
  const {
9572
10527
  auto = false,
@@ -9590,26 +10545,26 @@ var Swiper = (props) => {
9590
10545
  const maxIndex = Math.max(0, totalSlides - viewItemCount);
9591
10546
  const useLoop = loop && canSlide;
9592
10547
  const cloneCount = useLoop ? totalSlides : 0;
9593
- const extendedItems = React31.useMemo(() => {
10548
+ const extendedItems = React32.useMemo(() => {
9594
10549
  if (!useLoop) return items;
9595
10550
  return [...items, ...items, ...items];
9596
10551
  }, [items, useLoop]);
9597
10552
  const initialIdx = Math.max(0, Math.min(indexProp ?? 0, maxIndex));
9598
- const [innerIndex, setInnerIndex] = React31.useState(
10553
+ const [innerIndex, setInnerIndex] = React32.useState(
9599
10554
  useLoop ? cloneCount + initialIdx : initialIdx
9600
10555
  );
9601
- const [isDragging, setIsDragging] = React31.useState(false);
9602
- const [dragOffset, setDragOffset] = React31.useState(0);
9603
- const [animated, setAnimated] = React31.useState(false);
9604
- const [containerWidth, setContainerWidth] = React31.useState(0);
9605
- const containerRef = React31.useRef(null);
9606
- const startXRef = React31.useRef(0);
9607
- const startTimeRef = React31.useRef(0);
9608
- const autoplayTimerRef = React31.useRef(null);
9609
- const resumeTimeoutRef = React31.useRef(null);
9610
- const [paused, setPaused] = React31.useState(false);
9611
- const initializedRef = React31.useRef(false);
9612
- React31.useEffect(() => {
10556
+ const [isDragging, setIsDragging] = React32.useState(false);
10557
+ const [dragOffset, setDragOffset] = React32.useState(0);
10558
+ const [animated, setAnimated] = React32.useState(false);
10559
+ const [containerWidth, setContainerWidth] = React32.useState(0);
10560
+ const containerRef = React32.useRef(null);
10561
+ const startXRef = React32.useRef(0);
10562
+ const startTimeRef = React32.useRef(0);
10563
+ const autoplayTimerRef = React32.useRef(null);
10564
+ const resumeTimeoutRef = React32.useRef(null);
10565
+ const [paused, setPaused] = React32.useState(false);
10566
+ const initializedRef = React32.useRef(false);
10567
+ React32.useEffect(() => {
9613
10568
  const el = containerRef.current;
9614
10569
  if (!el) return;
9615
10570
  const ro = new ResizeObserver((entries) => {
@@ -9632,7 +10587,7 @@ var Swiper = (props) => {
9632
10587
  return ((inner - cloneCount) % totalSlides + totalSlides) % totalSlides;
9633
10588
  };
9634
10589
  const realIndex = getRealIndex(innerIndex);
9635
- const moveToInner = React31.useCallback(
10590
+ const moveToInner = React32.useCallback(
9636
10591
  (idx, withAnim = true) => {
9637
10592
  if (!useLoop) {
9638
10593
  setAnimated(withAnim);
@@ -9660,7 +10615,7 @@ var Swiper = (props) => {
9660
10615
  },
9661
10616
  [useLoop, cloneCount, totalSlides]
9662
10617
  );
9663
- const handleTransitionEnd = React31.useCallback(() => {
10618
+ const handleTransitionEnd = React32.useCallback(() => {
9664
10619
  if (!useLoop) return;
9665
10620
  const real = getRealIndex(innerIndex);
9666
10621
  const canonical = cloneCount + real;
@@ -9670,7 +10625,7 @@ var Swiper = (props) => {
9670
10625
  }
9671
10626
  onChange?.(Math.min(real, maxIndex));
9672
10627
  }, [useLoop, innerIndex, cloneCount, totalSlides, maxIndex, onChange]);
9673
- const slideTo = React31.useCallback(
10628
+ const slideTo = React32.useCallback(
9674
10629
  (logicalIndex) => {
9675
10630
  if (!canSlide) return;
9676
10631
  const clamped = useLoop ? logicalIndex : Math.max(0, Math.min(logicalIndex, maxIndex));
@@ -9680,7 +10635,7 @@ var Swiper = (props) => {
9680
10635
  },
9681
10636
  [canSlide, useLoop, cloneCount, maxIndex, onChange, moveToInner]
9682
10637
  );
9683
- const slideNext = React31.useCallback(() => {
10638
+ const slideNext = React32.useCallback(() => {
9684
10639
  if (!canSlide) return;
9685
10640
  const nextInner = innerIndex + slideBy;
9686
10641
  if (useLoop) {
@@ -9689,7 +10644,7 @@ var Swiper = (props) => {
9689
10644
  moveToInner(Math.min(nextInner, maxIndex), true);
9690
10645
  }
9691
10646
  }, [canSlide, useLoop, innerIndex, slideBy, maxIndex, moveToInner]);
9692
- const slidePrev = React31.useCallback(() => {
10647
+ const slidePrev = React32.useCallback(() => {
9693
10648
  if (!canSlide) return;
9694
10649
  const prevInner = innerIndex - slideBy;
9695
10650
  if (useLoop) {
@@ -9698,7 +10653,7 @@ var Swiper = (props) => {
9698
10653
  moveToInner(Math.max(prevInner, 0), true);
9699
10654
  }
9700
10655
  }, [canSlide, useLoop, innerIndex, slideBy, moveToInner]);
9701
- React31.useEffect(() => {
10656
+ React32.useEffect(() => {
9702
10657
  if (indexProp === void 0) return;
9703
10658
  const clamped = Math.max(0, Math.min(indexProp, maxIndex));
9704
10659
  const target = useLoop ? cloneCount + clamped : clamped;
@@ -9706,12 +10661,12 @@ var Swiper = (props) => {
9706
10661
  moveToInner(target, true);
9707
10662
  }
9708
10663
  }, [indexProp]);
9709
- React31.useImperativeHandle(swiperRef, () => ({
10664
+ React32.useImperativeHandle(swiperRef, () => ({
9710
10665
  slidePrev,
9711
10666
  slideNext,
9712
10667
  slideTo
9713
10668
  }));
9714
- React31.useEffect(() => {
10669
+ React32.useEffect(() => {
9715
10670
  if (!auto || !canSlide || paused) return;
9716
10671
  autoplayTimerRef.current = setInterval(slideNext, autoplayDelay);
9717
10672
  return () => {
@@ -9737,7 +10692,7 @@ var Swiper = (props) => {
9737
10692
  resumeTimeoutRef.current = null;
9738
10693
  }, pauseOnInteraction);
9739
10694
  };
9740
- React31.useEffect(() => {
10695
+ React32.useEffect(() => {
9741
10696
  return () => {
9742
10697
  if (resumeTimeoutRef.current) clearTimeout(resumeTimeoutRef.current);
9743
10698
  };
@@ -9755,7 +10710,7 @@ var Swiper = (props) => {
9755
10710
  startXRef.current = getClientX(e);
9756
10711
  startTimeRef.current = Date.now();
9757
10712
  };
9758
- React31.useEffect(() => {
10713
+ React32.useEffect(() => {
9759
10714
  if (!isDragging) return;
9760
10715
  const handleMove = (e) => {
9761
10716
  setDragOffset(getClientX(e) - startXRef.current);
@@ -9794,8 +10749,8 @@ var Swiper = (props) => {
9794
10749
  }, [isDragging, dragOffset, innerIndex, useLoop, maxIndex, slideStep, moveToInner]);
9795
10750
  const slideWidthPercent = 100 / viewItemCount;
9796
10751
  const gapAdjust = spaceBetween * (viewItemCount - 1) / viewItemCount;
9797
- const slideElements = React31.useMemo(
9798
- () => extendedItems.map((item, idx) => /* @__PURE__ */ jsx341(
10752
+ const slideElements = React32.useMemo(
10753
+ () => extendedItems.map((item, idx) => /* @__PURE__ */ jsx342(
9799
10754
  "div",
9800
10755
  {
9801
10756
  className: "lib-xplat-swiper__slide",
@@ -9814,15 +10769,15 @@ var Swiper = (props) => {
9814
10769
  Math.floor(realIndex / slideBy),
9815
10770
  totalSteps - 1
9816
10771
  );
9817
- return /* @__PURE__ */ jsxs219("div", { className: "lib-xplat-swiper", ref: containerRef, children: [
9818
- /* @__PURE__ */ jsx341(
10772
+ return /* @__PURE__ */ jsxs220("div", { className: "lib-xplat-swiper", ref: containerRef, children: [
10773
+ /* @__PURE__ */ jsx342(
9819
10774
  "div",
9820
10775
  {
9821
10776
  className: "lib-xplat-swiper__viewport",
9822
10777
  onMouseDown: handleDragStart,
9823
10778
  onTouchStart: handleDragStart,
9824
10779
  onDragStart: (e) => e.preventDefault(),
9825
- children: /* @__PURE__ */ jsx341(
10780
+ children: /* @__PURE__ */ jsx342(
9826
10781
  "div",
9827
10782
  {
9828
10783
  className: clsx_default(
@@ -9840,7 +10795,7 @@ var Swiper = (props) => {
9840
10795
  )
9841
10796
  }
9842
10797
  ),
9843
- showProgress && canSlide && /* @__PURE__ */ jsx341("div", { className: "lib-xplat-swiper__progress", children: /* @__PURE__ */ jsx341("div", { className: "lib-xplat-swiper__progress-track", children: /* @__PURE__ */ jsx341(
10798
+ showProgress && canSlide && /* @__PURE__ */ jsx342("div", { className: "lib-xplat-swiper__progress", children: /* @__PURE__ */ jsx342("div", { className: "lib-xplat-swiper__progress-track", children: /* @__PURE__ */ jsx342(
9844
10799
  "span",
9845
10800
  {
9846
10801
  className: "lib-xplat-swiper__progress-fill",
@@ -9850,7 +10805,7 @@ var Swiper = (props) => {
9850
10805
  }
9851
10806
  }
9852
10807
  ) }) }),
9853
- canSlide && /* @__PURE__ */ jsx341("div", { className: "lib-xplat-swiper__dots", children: Array.from({ length: totalSteps }, (_, i) => /* @__PURE__ */ jsx341(
10808
+ canSlide && /* @__PURE__ */ jsx342("div", { className: "lib-xplat-swiper__dots", children: Array.from({ length: totalSteps }, (_, i) => /* @__PURE__ */ jsx342(
9854
10809
  "button",
9855
10810
  {
9856
10811
  className: clsx_default(
@@ -9868,8 +10823,8 @@ Swiper.displayName = "Swiper";
9868
10823
  var Swiper_default = Swiper;
9869
10824
 
9870
10825
  // src/components/Switch/Switch.tsx
9871
- import React32 from "react";
9872
- import { jsx as jsx342 } from "react/jsx-runtime";
10826
+ import React33 from "react";
10827
+ import { jsx as jsx343 } from "react/jsx-runtime";
9873
10828
  var KNOB_TRANSITION_MS = 250;
9874
10829
  var Switch = (props) => {
9875
10830
  const {
@@ -9878,12 +10833,15 @@ var Switch = (props) => {
9878
10833
  type = "primary",
9879
10834
  disabled,
9880
10835
  onChange,
9881
- validations
10836
+ validations,
10837
+ label,
10838
+ required
9882
10839
  } = props;
10840
+ const fieldId = React33.useId();
9883
10841
  const statusType = normalizeStatus(type);
9884
- const [isAnimating, setIsAnimating] = React32.useState(false);
9885
- const timeoutRef = React32.useRef(null);
9886
- React32.useEffect(() => {
10842
+ const [isAnimating, setIsAnimating] = React33.useState(false);
10843
+ const timeoutRef = React33.useRef(null);
10844
+ React33.useEffect(() => {
9887
10845
  return () => {
9888
10846
  if (timeoutRef.current) clearTimeout(timeoutRef.current);
9889
10847
  };
@@ -9898,9 +10856,10 @@ var Switch = (props) => {
9898
10856
  timeoutRef.current = null;
9899
10857
  }, KNOB_TRANSITION_MS);
9900
10858
  };
9901
- const control = /* @__PURE__ */ jsx342(
10859
+ const control = /* @__PURE__ */ jsx343(
9902
10860
  "div",
9903
10861
  {
10862
+ id: fieldId,
9904
10863
  className: clsx_default(
9905
10864
  "lib-xplat-switch",
9906
10865
  size,
@@ -9912,26 +10871,26 @@ var Switch = (props) => {
9912
10871
  onClick: handleClick,
9913
10872
  "aria-invalid": hasError(validations) || void 0,
9914
10873
  "aria-disabled": disabled || isAnimating,
9915
- children: /* @__PURE__ */ jsx342("div", { className: clsx_default("knob", value ? "checked" : void 0) })
10874
+ children: /* @__PURE__ */ jsx343("div", { className: clsx_default("knob", value ? "checked" : void 0) })
9916
10875
  }
9917
10876
  );
9918
- return /* @__PURE__ */ jsx342(Field, { validations, children: control });
10877
+ return /* @__PURE__ */ jsx343(Field, { validations, label, required, htmlFor: fieldId, children: control });
9919
10878
  };
9920
10879
  Switch.displayName = "Switch";
9921
10880
  var Switch_default = Switch;
9922
10881
 
9923
10882
  // src/components/Table/TableContext.tsx
9924
- import React33 from "react";
9925
- var TableContext = React33.createContext(null);
10883
+ import React34 from "react";
10884
+ var TableContext = React34.createContext(null);
9926
10885
  var useTableContext = () => {
9927
- const ctx = React33.useContext(TableContext);
10886
+ const ctx = React34.useContext(TableContext);
9928
10887
  if (!ctx) throw new Error("Table components must be used inside <Table>");
9929
10888
  return ctx;
9930
10889
  };
9931
10890
  var TableContext_default = TableContext;
9932
10891
 
9933
10892
  // src/components/Table/Table.tsx
9934
- import { jsx as jsx343 } from "react/jsx-runtime";
10893
+ import { jsx as jsx344 } from "react/jsx-runtime";
9935
10894
  var Table = (props) => {
9936
10895
  const {
9937
10896
  children,
@@ -9941,7 +10900,7 @@ var Table = (props) => {
9941
10900
  headerSticky = false,
9942
10901
  stickyShadow = true
9943
10902
  } = props;
9944
- return /* @__PURE__ */ jsx343("div", { className: `lib-xplat-table-wrapper ${size}`, children: /* @__PURE__ */ jsx343(
10903
+ return /* @__PURE__ */ jsx344("div", { className: `lib-xplat-table-wrapper ${size}`, children: /* @__PURE__ */ jsx344(
9945
10904
  TableContext_default.Provider,
9946
10905
  {
9947
10906
  value: {
@@ -9950,7 +10909,7 @@ var Table = (props) => {
9950
10909
  headerSticky,
9951
10910
  stickyShadow
9952
10911
  },
9953
- children: /* @__PURE__ */ jsx343("table", { className: "lib-xplat-table", children })
10912
+ children: /* @__PURE__ */ jsx344("table", { className: "lib-xplat-table", children })
9954
10913
  }
9955
10914
  ) });
9956
10915
  };
@@ -9958,41 +10917,41 @@ Table.displayName = "Table";
9958
10917
  var Table_default = Table;
9959
10918
 
9960
10919
  // src/components/Table/TableBody.tsx
9961
- import { jsx as jsx344 } from "react/jsx-runtime";
10920
+ import { jsx as jsx345 } from "react/jsx-runtime";
9962
10921
  var TableBody = (props) => {
9963
10922
  const { children } = props;
9964
- return /* @__PURE__ */ jsx344("tbody", { children });
10923
+ return /* @__PURE__ */ jsx345("tbody", { children });
9965
10924
  };
9966
10925
  TableBody.displayName = "TableBody";
9967
10926
  var TableBody_default = TableBody;
9968
10927
 
9969
10928
  // src/components/Table/TableCell.tsx
9970
- import React36 from "react";
10929
+ import React37 from "react";
9971
10930
 
9972
10931
  // src/components/Table/TableHeadContext.tsx
9973
- import React34 from "react";
9974
- var TableHeadContext = React34.createContext(
10932
+ import React35 from "react";
10933
+ var TableHeadContext = React35.createContext(
9975
10934
  null
9976
10935
  );
9977
10936
  var useTableHeadContext = () => {
9978
- const ctx = React34.useContext(TableHeadContext);
10937
+ const ctx = React35.useContext(TableHeadContext);
9979
10938
  return ctx;
9980
10939
  };
9981
10940
  var TableHeadContext_default = TableHeadContext;
9982
10941
 
9983
10942
  // src/components/Table/TableRowContext.tsx
9984
- import React35 from "react";
9985
- var TableRowContext = React35.createContext(null);
10943
+ import React36 from "react";
10944
+ var TableRowContext = React36.createContext(null);
9986
10945
  var useTableRowContext = () => {
9987
- const ctx = React35.useContext(TableRowContext);
10946
+ const ctx = React36.useContext(TableRowContext);
9988
10947
  if (!ctx) throw new Error("Table components must be used inside <Table>");
9989
10948
  return ctx;
9990
10949
  };
9991
10950
  var TableRowContext_default = TableRowContext;
9992
10951
 
9993
10952
  // src/components/Table/TableCell.tsx
9994
- import { jsx as jsx345 } from "react/jsx-runtime";
9995
- var TableCell = React36.memo((props) => {
10953
+ import { jsx as jsx346 } from "react/jsx-runtime";
10954
+ var TableCell = React37.memo((props) => {
9996
10955
  const {
9997
10956
  children,
9998
10957
  align = "center",
@@ -10006,9 +10965,9 @@ var TableCell = React36.memo((props) => {
10006
10965
  const { registerStickyCell, stickyCells } = useTableRowContext();
10007
10966
  const { stickyShadow } = useTableContext();
10008
10967
  const headContext = useTableHeadContext();
10009
- const [left, setLeft] = React36.useState(0);
10010
- const cellRef = React36.useRef(null);
10011
- const calculateLeft = React36.useCallback(() => {
10968
+ const [left, setLeft] = React37.useState(0);
10969
+ const cellRef = React37.useRef(null);
10970
+ const calculateLeft = React37.useCallback(() => {
10012
10971
  if (!cellRef.current) return 0;
10013
10972
  let totalLeft = 0;
10014
10973
  for (const ref of stickyCells) {
@@ -10017,7 +10976,7 @@ var TableCell = React36.memo((props) => {
10017
10976
  }
10018
10977
  return totalLeft;
10019
10978
  }, [stickyCells]);
10020
- React36.useEffect(() => {
10979
+ React37.useEffect(() => {
10021
10980
  if (!isSticky || !cellRef.current) return;
10022
10981
  registerStickyCell(cellRef);
10023
10982
  setLeft(calculateLeft());
@@ -10036,7 +10995,7 @@ var TableCell = React36.memo((props) => {
10036
10995
  const CellTag = isHeaderCell ? "th" : "td";
10037
10996
  const isLastSticky = isSticky && stickyCells[stickyCells.length - 1] === cellRef;
10038
10997
  const enableHover = headContext && headContext.cellHover;
10039
- return /* @__PURE__ */ jsx345(
10998
+ return /* @__PURE__ */ jsx346(
10040
10999
  CellTag,
10041
11000
  {
10042
11001
  ref: cellRef,
@@ -10063,21 +11022,21 @@ TableCell.displayName = "TableCell";
10063
11022
  var TableCell_default = TableCell;
10064
11023
 
10065
11024
  // src/components/Table/TableHead.tsx
10066
- import { jsx as jsx346 } from "react/jsx-runtime";
11025
+ import { jsx as jsx347 } from "react/jsx-runtime";
10067
11026
  var TableHead = ({
10068
11027
  children,
10069
11028
  cellHover = false
10070
11029
  }) => {
10071
11030
  const { headerSticky } = useTableContext();
10072
- return /* @__PURE__ */ jsx346(TableHeadContext_default.Provider, { value: { cellHover }, children: /* @__PURE__ */ jsx346("thead", { className: clsx_default(headerSticky ? "table-sticky" : null), children }) });
11031
+ return /* @__PURE__ */ jsx347(TableHeadContext_default.Provider, { value: { cellHover }, children: /* @__PURE__ */ jsx347("thead", { className: clsx_default(headerSticky ? "table-sticky" : null), children }) });
10073
11032
  };
10074
11033
  TableHead.displayName = "TableHead";
10075
11034
  var TableHead_default = TableHead;
10076
11035
 
10077
11036
  // src/components/Table/TableRow.tsx
10078
- import React37 from "react";
10079
- import { jsx as jsx347 } from "react/jsx-runtime";
10080
- var TableRow = React37.memo((props) => {
11037
+ import React38 from "react";
11038
+ import { jsx as jsx348 } from "react/jsx-runtime";
11039
+ var TableRow = React38.memo((props) => {
10081
11040
  const {
10082
11041
  children,
10083
11042
  type = "secondary",
@@ -10086,14 +11045,14 @@ var TableRow = React37.memo((props) => {
10086
11045
  onClick
10087
11046
  } = props;
10088
11047
  const { rowBorderUse } = useTableContext();
10089
- const [stickyCells, setStickyCells] = React37.useState([]);
11048
+ const [stickyCells, setStickyCells] = React38.useState([]);
10090
11049
  const registerStickyCell = (ref) => {
10091
11050
  setStickyCells((prev) => {
10092
11051
  if (prev.includes(ref)) return prev;
10093
11052
  return [...prev, ref];
10094
11053
  });
10095
11054
  };
10096
- return /* @__PURE__ */ jsx347(TableRowContext_default.Provider, { value: { stickyCells, registerStickyCell }, children: /* @__PURE__ */ jsx347(
11055
+ return /* @__PURE__ */ jsx348(TableRowContext_default.Provider, { value: { stickyCells, registerStickyCell }, children: /* @__PURE__ */ jsx348(
10097
11056
  "tr",
10098
11057
  {
10099
11058
  className: clsx_default(
@@ -10117,7 +11076,7 @@ TableRow.displayName = "TableRow";
10117
11076
  var TableRow_default = TableRow;
10118
11077
 
10119
11078
  // src/components/Tag/Tag.tsx
10120
- import { jsx as jsx348, jsxs as jsxs220 } from "react/jsx-runtime";
11079
+ import { jsx as jsx349, jsxs as jsxs221 } from "react/jsx-runtime";
10121
11080
  var Tag = (props) => {
10122
11081
  const {
10123
11082
  children,
@@ -10129,7 +11088,7 @@ var Tag = (props) => {
10129
11088
  colorIndex
10130
11089
  } = props;
10131
11090
  const shape = variant ?? type ?? "neutral";
10132
- return /* @__PURE__ */ jsxs220(
11091
+ return /* @__PURE__ */ jsxs221(
10133
11092
  "span",
10134
11093
  {
10135
11094
  className: clsx_default(
@@ -10140,8 +11099,8 @@ var Tag = (props) => {
10140
11099
  disabled && "disabled"
10141
11100
  ),
10142
11101
  children: [
10143
- /* @__PURE__ */ jsx348("span", { className: "tag-label", children }),
10144
- onClose && /* @__PURE__ */ jsx348("button", { className: "tag-close", onClick: onClose, "aria-label": "\uC0AD\uC81C", disabled, children: /* @__PURE__ */ jsx348(XIcon_default, {}) })
11102
+ /* @__PURE__ */ jsx349("span", { className: "tag-label", children }),
11103
+ onClose && /* @__PURE__ */ jsx349("button", { className: "tag-close", onClick: onClose, "aria-label": "\uC0AD\uC81C", disabled, children: /* @__PURE__ */ jsx349(XIcon_default, {}) })
10145
11104
  ]
10146
11105
  }
10147
11106
  );
@@ -10150,24 +11109,29 @@ Tag.displayName = "Tag";
10150
11109
  var Tag_default = Tag;
10151
11110
 
10152
11111
  // src/components/TextArea/TextArea.tsx
10153
- import React38 from "react";
10154
- import { jsx as jsx349 } from "react/jsx-runtime";
10155
- var TextArea = React38.forwardRef(
11112
+ import React39 from "react";
11113
+ import { jsx as jsx350 } from "react/jsx-runtime";
11114
+ var TextArea = React39.forwardRef(
10156
11115
  (props, ref) => {
10157
11116
  const {
10158
11117
  className,
10159
11118
  size = "md",
10160
11119
  validations,
11120
+ label,
11121
+ required,
10161
11122
  resize = "vertical",
10162
11123
  rows = 3,
10163
11124
  disabled,
10164
11125
  ...textareaProps
10165
11126
  } = props;
10166
- const control = /* @__PURE__ */ jsx349("div", { className: clsx_default("lib-xplat-textarea-wrap", className), children: /* @__PURE__ */ jsx349(
11127
+ const autoId = React39.useId();
11128
+ const fieldId = props.id ?? autoId;
11129
+ const control = /* @__PURE__ */ jsx350("div", { className: clsx_default("lib-xplat-textarea-wrap", className), children: /* @__PURE__ */ jsx350(
10167
11130
  "textarea",
10168
11131
  {
10169
11132
  ...textareaProps,
10170
11133
  ref,
11134
+ id: fieldId,
10171
11135
  rows,
10172
11136
  disabled,
10173
11137
  "aria-invalid": hasError(validations) || void 0,
@@ -10175,32 +11139,166 @@ var TextArea = React38.forwardRef(
10175
11139
  style: { resize }
10176
11140
  }
10177
11141
  ) });
10178
- return /* @__PURE__ */ jsx349(Field, { validations, children: control });
11142
+ return /* @__PURE__ */ jsx350(Field, { validations, label, required, htmlFor: fieldId, children: control });
10179
11143
  }
10180
11144
  );
10181
11145
  TextArea.displayName = "TextArea";
10182
11146
  var TextArea_default = TextArea;
10183
11147
 
11148
+ // src/components/TimePicker/TimePicker.tsx
11149
+ import React40 from "react";
11150
+ import { jsx as jsx351, jsxs as jsxs222 } from "react/jsx-runtime";
11151
+ var ANIMATION_DURATION_MS4 = 200;
11152
+ var toMinutes = (hhmm) => {
11153
+ if (!hhmm) return null;
11154
+ const m = /^(\d{1,2}):(\d{2})$/.exec(hhmm.trim());
11155
+ if (!m) return null;
11156
+ const h = Number(m[1]);
11157
+ const min = Number(m[2]);
11158
+ if (h > 23 || min > 59) return null;
11159
+ return h * 60 + min;
11160
+ };
11161
+ var toHHmm = (minutes) => `${String(Math.floor(minutes / 60)).padStart(2, "0")}:${String(minutes % 60).padStart(2, "0")}`;
11162
+ var display = (hhmm, use12Hours) => {
11163
+ if (!use12Hours) return hhmm;
11164
+ const total = toMinutes(hhmm);
11165
+ if (total === null) return hhmm;
11166
+ const h24 = Math.floor(total / 60);
11167
+ const mm = String(total % 60).padStart(2, "0");
11168
+ const period = h24 < 12 ? "\uC624\uC804" : "\uC624\uD6C4";
11169
+ const h12 = h24 % 12 === 0 ? 12 : h24 % 12;
11170
+ return `${period} ${h12}:${mm}`;
11171
+ };
11172
+ var TimePicker = (props) => {
11173
+ const {
11174
+ value,
11175
+ onChange,
11176
+ step = 30,
11177
+ min,
11178
+ max,
11179
+ use12Hours = false,
11180
+ placeholder = "\uC2DC\uAC01 \uC120\uD0DD",
11181
+ disabled = false,
11182
+ size = "md",
11183
+ label,
11184
+ required,
11185
+ validations
11186
+ } = props;
11187
+ const fieldId = React40.useId();
11188
+ const triggerRef = React40.useRef(null);
11189
+ const contentRef = React40.useRef(null);
11190
+ const [isOpen, setOpen] = React40.useState(false);
11191
+ const [mounted, setMounted] = React40.useState(false);
11192
+ const [visible, setVisible] = React40.useState(false);
11193
+ const options = React40.useMemo(() => {
11194
+ const safeStep = step > 0 && step <= 720 ? step : 30;
11195
+ const lo = toMinutes(min) ?? 0;
11196
+ const hi = toMinutes(max) ?? 24 * 60 - 1;
11197
+ const out = [];
11198
+ for (let t = lo; t <= hi; t += safeStep) out.push(toHHmm(t));
11199
+ return out;
11200
+ }, [step, min, max]);
11201
+ const close = React40.useCallback(() => setOpen(false), []);
11202
+ useClickOutside_default([triggerRef, contentRef], close, isOpen);
11203
+ useEscapeKey(isOpen, () => {
11204
+ close();
11205
+ triggerRef.current?.focus({ preventScroll: true });
11206
+ });
11207
+ const position = useAutoPosition_default(triggerRef, contentRef, mounted);
11208
+ React40.useEffect(() => {
11209
+ if (disabled && isOpen) setOpen(false);
11210
+ }, [disabled, isOpen]);
11211
+ React40.useEffect(() => {
11212
+ if (isOpen) {
11213
+ setMounted(true);
11214
+ const t2 = setTimeout(() => setVisible(true), 1);
11215
+ return () => clearTimeout(t2);
11216
+ }
11217
+ setVisible(false);
11218
+ const t = setTimeout(() => setMounted(false), ANIMATION_DURATION_MS4);
11219
+ return () => clearTimeout(t);
11220
+ }, [isOpen]);
11221
+ const pick = (hhmm) => {
11222
+ onChange?.(hhmm);
11223
+ close();
11224
+ triggerRef.current?.focus({ preventScroll: true });
11225
+ };
11226
+ const control = /* @__PURE__ */ jsxs222("div", { className: clsx_default("lib-xplat-time-picker", size, disabled && "disabled"), children: [
11227
+ /* @__PURE__ */ jsx351(
11228
+ "div",
11229
+ {
11230
+ id: fieldId,
11231
+ ref: triggerRef,
11232
+ className: clsx_default("time-picker-trigger", hasError(validations) && "error"),
11233
+ role: "combobox",
11234
+ "aria-expanded": isOpen,
11235
+ "aria-haspopup": "listbox",
11236
+ "aria-invalid": hasError(validations) || void 0,
11237
+ tabIndex: disabled ? void 0 : 0,
11238
+ onClick: () => !disabled && setOpen((p) => !p),
11239
+ onKeyDown: (e) => {
11240
+ if (disabled) return;
11241
+ if (e.key === "Enter" || e.key === " " || e.key === "ArrowDown") {
11242
+ e.preventDefault();
11243
+ setOpen(true);
11244
+ }
11245
+ },
11246
+ children: /* @__PURE__ */ jsx351("span", { className: clsx_default("time-picker-value", !value && "placeholder"), children: value ? display(value, use12Hours) : placeholder })
11247
+ }
11248
+ ),
11249
+ mounted && /* @__PURE__ */ jsx351(Portal_default, { children: /* @__PURE__ */ jsx351(
11250
+ "div",
11251
+ {
11252
+ ref: contentRef,
11253
+ className: clsx_default("lib-xplat-time-picker-content", size, visible ? "enter" : "exit", position.repositioning && "repositioning"),
11254
+ style: { ...position.position, width: triggerRef.current?.offsetWidth },
11255
+ role: "listbox",
11256
+ children: options.map((t) => /* @__PURE__ */ jsx351(
11257
+ "div",
11258
+ {
11259
+ className: clsx_default("time-picker-item", t === value && "is-selected"),
11260
+ role: "option",
11261
+ "aria-selected": t === value,
11262
+ tabIndex: 0,
11263
+ onClick: () => pick(t),
11264
+ onKeyDown: (e) => {
11265
+ if (e.key === "Enter" || e.key === " ") {
11266
+ e.preventDefault();
11267
+ pick(t);
11268
+ }
11269
+ },
11270
+ children: display(t, use12Hours)
11271
+ },
11272
+ t
11273
+ ))
11274
+ }
11275
+ ) })
11276
+ ] });
11277
+ return /* @__PURE__ */ jsx351(Field, { validations, label, required, htmlFor: fieldId, children: control });
11278
+ };
11279
+ TimePicker.displayName = "TimePicker";
11280
+ var TimePicker_default = TimePicker;
11281
+
10184
11282
  // src/components/Toast/Toast.tsx
10185
- import React39 from "react";
11283
+ import React41 from "react";
10186
11284
  import { createPortal as createPortal3 } from "react-dom";
10187
- import { jsx as jsx350, jsxs as jsxs221 } from "react/jsx-runtime";
10188
- var ToastContext = React39.createContext(null);
11285
+ import { jsx as jsx352, jsxs as jsxs223 } from "react/jsx-runtime";
11286
+ var ToastContext = React41.createContext(null);
10189
11287
  var useToast = () => {
10190
- const ctx = React39.useContext(ToastContext);
11288
+ const ctx = React41.useContext(ToastContext);
10191
11289
  if (!ctx) throw new Error("useToast must be used within ToastProvider");
10192
11290
  return ctx;
10193
11291
  };
10194
11292
  var EXIT_DURATION = 300;
10195
11293
  var ToastItemComponent = ({ item, isExiting, onClose }) => {
10196
- const ref = React39.useRef(null);
10197
- const [height, setHeight] = React39.useState(void 0);
10198
- React39.useEffect(() => {
11294
+ const ref = React41.useRef(null);
11295
+ const [height, setHeight] = React41.useState(void 0);
11296
+ React41.useEffect(() => {
10199
11297
  if (ref.current && !isExiting) {
10200
11298
  setHeight(ref.current.offsetHeight);
10201
11299
  }
10202
11300
  }, [isExiting]);
10203
- return /* @__PURE__ */ jsx350(
11301
+ return /* @__PURE__ */ jsx352(
10204
11302
  "div",
10205
11303
  {
10206
11304
  className: clsx_default("lib-xplat-toast-wrapper", { exit: isExiting }),
@@ -10208,15 +11306,15 @@ var ToastItemComponent = ({ item, isExiting, onClose }) => {
10208
11306
  maxHeight: isExiting ? 0 : height ?? "none",
10209
11307
  marginBottom: isExiting ? 0 : void 0
10210
11308
  },
10211
- children: /* @__PURE__ */ jsxs221(
11309
+ children: /* @__PURE__ */ jsxs223(
10212
11310
  "div",
10213
11311
  {
10214
11312
  ref,
10215
11313
  className: clsx_default("lib-xplat-toast", item.type, { exit: isExiting }),
10216
11314
  role: "alert",
10217
11315
  children: [
10218
- /* @__PURE__ */ jsx350("span", { className: "message", children: item.message }),
10219
- /* @__PURE__ */ jsx350("button", { className: "close-btn", onClick: onClose, "aria-label": "\uB2EB\uAE30", children: "\xD7" })
11316
+ /* @__PURE__ */ jsx352("span", { className: "message", children: item.message }),
11317
+ /* @__PURE__ */ jsx352("button", { className: "close-btn", onClick: onClose, "aria-label": "\uB2EB\uAE30", children: "\xD7" })
10220
11318
  ]
10221
11319
  }
10222
11320
  )
@@ -10227,13 +11325,13 @@ var ToastProvider = ({
10227
11325
  children,
10228
11326
  position = "top-right"
10229
11327
  }) => {
10230
- const [toasts, setToasts] = React39.useState([]);
10231
- const [removing, setRemoving] = React39.useState(/* @__PURE__ */ new Set());
10232
- const [mounted, setMounted] = React39.useState(false);
10233
- React39.useEffect(() => {
11328
+ const [toasts, setToasts] = React41.useState([]);
11329
+ const [removing, setRemoving] = React41.useState(/* @__PURE__ */ new Set());
11330
+ const [mounted, setMounted] = React41.useState(false);
11331
+ React41.useEffect(() => {
10234
11332
  setMounted(true);
10235
11333
  }, []);
10236
- const remove = React39.useCallback((id) => {
11334
+ const remove = React41.useCallback((id) => {
10237
11335
  setRemoving((prev) => new Set(prev).add(id));
10238
11336
  setTimeout(() => {
10239
11337
  setToasts((prev) => prev.filter((t) => t.id !== id));
@@ -10244,7 +11342,7 @@ var ToastProvider = ({
10244
11342
  });
10245
11343
  }, EXIT_DURATION);
10246
11344
  }, []);
10247
- const toast = React39.useCallback(
11345
+ const toast = React41.useCallback(
10248
11346
  (type, message, duration = 3e3) => {
10249
11347
  const id = `${Date.now()}-${Math.random()}`;
10250
11348
  setToasts((prev) => [...prev, { id, type, message }]);
@@ -10254,10 +11352,10 @@ var ToastProvider = ({
10254
11352
  },
10255
11353
  [remove]
10256
11354
  );
10257
- return /* @__PURE__ */ jsxs221(ToastContext.Provider, { value: { toast }, children: [
11355
+ return /* @__PURE__ */ jsxs223(ToastContext.Provider, { value: { toast }, children: [
10258
11356
  children,
10259
11357
  mounted && createPortal3(
10260
- /* @__PURE__ */ jsx350("div", { className: clsx_default("lib-xplat-toast-container", position), children: toasts.map((t) => /* @__PURE__ */ jsx350(
11358
+ /* @__PURE__ */ jsx352("div", { className: clsx_default("lib-xplat-toast-container", position), children: toasts.map((t) => /* @__PURE__ */ jsx352(
10261
11359
  ToastItemComponent,
10262
11360
  {
10263
11361
  item: t,
@@ -10273,8 +11371,8 @@ var ToastProvider = ({
10273
11371
  ToastProvider.displayName = "ToastProvider";
10274
11372
 
10275
11373
  // src/components/Tooltip/Tooltip.tsx
10276
- import React40 from "react";
10277
- import { Fragment as Fragment6, jsx as jsx351, jsxs as jsxs222 } from "react/jsx-runtime";
11374
+ import React42 from "react";
11375
+ import { Fragment as Fragment6, jsx as jsx353, jsxs as jsxs224 } from "react/jsx-runtime";
10278
11376
  var OFFSET = 12;
10279
11377
  var GAP = 8;
10280
11378
  var SHOW_DELAY = 300;
@@ -10289,14 +11387,14 @@ var Tooltip = (props) => {
10289
11387
  disabled = false
10290
11388
  } = props;
10291
11389
  const shape = variant ?? type ?? "dark";
10292
- const triggerRef = React40.useRef(null);
10293
- const tooltipRef = React40.useRef(null);
10294
- const [visible, setVisible] = React40.useState(false);
10295
- const [pos, setPos] = React40.useState({ left: 0, top: 0 });
10296
- const delayTimer = React40.useRef(0);
10297
- const rafRef = React40.useRef(0);
10298
- const cursor = React40.useRef(null);
10299
- const clamp = React40.useCallback((left, top, w, h) => {
11390
+ const triggerRef = React42.useRef(null);
11391
+ const tooltipRef = React42.useRef(null);
11392
+ const [visible, setVisible] = React42.useState(false);
11393
+ const [pos, setPos] = React42.useState({ left: 0, top: 0 });
11394
+ const delayTimer = React42.useRef(0);
11395
+ const rafRef = React42.useRef(0);
11396
+ const cursor = React42.useRef(null);
11397
+ const clamp = React42.useCallback((left, top, w, h) => {
10300
11398
  const vw = window.innerWidth;
10301
11399
  const vh = window.innerHeight;
10302
11400
  return {
@@ -10304,7 +11402,7 @@ var Tooltip = (props) => {
10304
11402
  top: Math.min(Math.max(GAP, top), Math.max(GAP, vh - h - GAP))
10305
11403
  };
10306
11404
  }, []);
10307
- const placeAtCursor = React40.useCallback((x, y) => {
11405
+ const placeAtCursor = React42.useCallback((x, y) => {
10308
11406
  const el = tooltipRef.current;
10309
11407
  if (!el) return;
10310
11408
  const w = el.offsetWidth;
@@ -10315,7 +11413,7 @@ var Tooltip = (props) => {
10315
11413
  if (top < GAP) top = y + OFFSET;
10316
11414
  setPos(clamp(left, top, w, h));
10317
11415
  }, [clamp]);
10318
- const placeAtTrigger = React40.useCallback(() => {
11416
+ const placeAtTrigger = React42.useCallback(() => {
10319
11417
  const el = tooltipRef.current;
10320
11418
  const trigger = triggerRef.current;
10321
11419
  if (!el || !trigger) return;
@@ -10327,19 +11425,19 @@ var Tooltip = (props) => {
10327
11425
  const left = rect.left + rect.width / 2 - w / 2;
10328
11426
  setPos(clamp(left, top, w, h));
10329
11427
  }, [clamp]);
10330
- const reposition = React40.useCallback(() => {
11428
+ const reposition = React42.useCallback(() => {
10331
11429
  if (follow && cursor.current) {
10332
11430
  placeAtCursor(cursor.current.x, cursor.current.y);
10333
11431
  } else {
10334
11432
  placeAtTrigger();
10335
11433
  }
10336
11434
  }, [follow, placeAtCursor, placeAtTrigger]);
10337
- const handleMouseEnter = React40.useCallback((e) => {
11435
+ const handleMouseEnter = React42.useCallback((e) => {
10338
11436
  if (disabled) return;
10339
11437
  cursor.current = { x: e.clientX, y: e.clientY };
10340
11438
  delayTimer.current = window.setTimeout(() => setVisible(true), SHOW_DELAY);
10341
11439
  }, [disabled]);
10342
- const handleMouseMove = React40.useCallback((e) => {
11440
+ const handleMouseMove = React42.useCallback((e) => {
10343
11441
  cursor.current = { x: e.clientX, y: e.clientY };
10344
11442
  if (!visible || !follow) return;
10345
11443
  cancelAnimationFrame(rafRef.current);
@@ -10347,25 +11445,25 @@ var Tooltip = (props) => {
10347
11445
  if (cursor.current) placeAtCursor(cursor.current.x, cursor.current.y);
10348
11446
  });
10349
11447
  }, [visible, follow, placeAtCursor]);
10350
- const close = React40.useCallback(() => {
11448
+ const close = React42.useCallback(() => {
10351
11449
  window.clearTimeout(delayTimer.current);
10352
11450
  cancelAnimationFrame(rafRef.current);
10353
11451
  setVisible(false);
10354
11452
  }, []);
10355
- const handleMouseLeave = React40.useCallback(() => {
11453
+ const handleMouseLeave = React42.useCallback(() => {
10356
11454
  cursor.current = null;
10357
11455
  close();
10358
11456
  }, [close]);
10359
- const handleFocus = React40.useCallback(() => {
11457
+ const handleFocus = React42.useCallback(() => {
10360
11458
  if (disabled) return;
10361
11459
  cursor.current = null;
10362
11460
  setVisible(true);
10363
11461
  }, [disabled]);
10364
- React40.useLayoutEffect(() => {
11462
+ React42.useLayoutEffect(() => {
10365
11463
  if (!visible) return;
10366
11464
  reposition();
10367
11465
  }, [visible, reposition]);
10368
- React40.useEffect(() => {
11466
+ React42.useEffect(() => {
10369
11467
  if (!visible || follow) return;
10370
11468
  const onChange = () => placeAtTrigger();
10371
11469
  window.addEventListener("scroll", onChange, true);
@@ -10375,12 +11473,12 @@ var Tooltip = (props) => {
10375
11473
  window.removeEventListener("resize", onChange);
10376
11474
  };
10377
11475
  }, [visible, follow, placeAtTrigger]);
10378
- React40.useEffect(() => () => {
11476
+ React42.useEffect(() => () => {
10379
11477
  window.clearTimeout(delayTimer.current);
10380
11478
  cancelAnimationFrame(rafRef.current);
10381
11479
  }, []);
10382
- if (!title && !description) return /* @__PURE__ */ jsx351(Fragment6, { children });
10383
- return /* @__PURE__ */ jsxs222(
11480
+ if (!title && !description) return /* @__PURE__ */ jsx353(Fragment6, { children });
11481
+ return /* @__PURE__ */ jsxs224(
10384
11482
  "div",
10385
11483
  {
10386
11484
  ref: triggerRef,
@@ -10393,7 +11491,7 @@ var Tooltip = (props) => {
10393
11491
  onBlur: close,
10394
11492
  children: [
10395
11493
  children,
10396
- visible && /* @__PURE__ */ jsx351(Portal_default, { children: /* @__PURE__ */ jsxs222(
11494
+ visible && /* @__PURE__ */ jsx353(Portal_default, { children: /* @__PURE__ */ jsxs224(
10397
11495
  "div",
10398
11496
  {
10399
11497
  ref: tooltipRef,
@@ -10401,8 +11499,8 @@ var Tooltip = (props) => {
10401
11499
  className: clsx_default("lib-xplat-tooltip", shape),
10402
11500
  style: { position: "fixed", left: pos.left, top: pos.top },
10403
11501
  children: [
10404
- title && /* @__PURE__ */ jsx351("div", { className: "tooltip-title", children: title }),
10405
- description && /* @__PURE__ */ jsx351("div", { className: "tooltip-desc", children: description })
11502
+ title && /* @__PURE__ */ jsx353("div", { className: "tooltip-title", children: title }),
11503
+ description && /* @__PURE__ */ jsx353("div", { className: "tooltip-desc", children: description })
10406
11504
  ]
10407
11505
  }
10408
11506
  ) })
@@ -10414,11 +11512,11 @@ Tooltip.displayName = "Tooltip";
10414
11512
  var Tooltip_default = Tooltip;
10415
11513
 
10416
11514
  // src/components/Video/Video.tsx
10417
- import React41 from "react";
10418
- import { jsx as jsx352, jsxs as jsxs223 } from "react/jsx-runtime";
10419
- var PipIcon = () => /* @__PURE__ */ jsxs223("svg", { viewBox: "0 0 24 24", width: "1em", height: "1em", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [
10420
- /* @__PURE__ */ jsx352("rect", { x: "3", y: "5", width: "18", height: "14", rx: "2" }),
10421
- /* @__PURE__ */ jsx352("rect", { x: "12", y: "11", width: "7", height: "6", rx: "1", fill: "currentColor" })
11515
+ import React43 from "react";
11516
+ import { jsx as jsx354, jsxs as jsxs225 } from "react/jsx-runtime";
11517
+ var PipIcon = () => /* @__PURE__ */ jsxs225("svg", { viewBox: "0 0 24 24", width: "1em", height: "1em", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [
11518
+ /* @__PURE__ */ jsx354("rect", { x: "3", y: "5", width: "18", height: "14", rx: "2" }),
11519
+ /* @__PURE__ */ jsx354("rect", { x: "12", y: "11", width: "7", height: "6", rx: "1", fill: "currentColor" })
10422
11520
  ] });
10423
11521
  var formatTime = (sec) => {
10424
11522
  if (!Number.isFinite(sec) || sec < 0) return "0:00";
@@ -10426,7 +11524,7 @@ var formatTime = (sec) => {
10426
11524
  const s = Math.floor(sec % 60);
10427
11525
  return `${m}:${s.toString().padStart(2, "0")}`;
10428
11526
  };
10429
- var Video = React41.forwardRef((props, ref) => {
11527
+ var Video = React43.forwardRef((props, ref) => {
10430
11528
  const {
10431
11529
  src,
10432
11530
  poster,
@@ -10450,21 +11548,21 @@ var Video = React41.forwardRef((props, ref) => {
10450
11548
  children,
10451
11549
  ...rest
10452
11550
  } = props;
10453
- const containerRef = React41.useRef(null);
10454
- const videoRef = React41.useRef(null);
10455
- const [isPlaying, setIsPlaying] = React41.useState(Boolean(autoPlay));
10456
- const [isLoaded, setIsLoaded] = React41.useState(false);
10457
- const [currentTime, setCurrentTime] = React41.useState(0);
10458
- const [duration, setDuration] = React41.useState(0);
10459
- const [buffered, setBuffered] = React41.useState(0);
10460
- const [volume, setVolume] = React41.useState(1);
10461
- const [isMuted, setIsMuted] = React41.useState(Boolean(muted));
10462
- const [isFullscreen, setIsFullscreen] = React41.useState(false);
10463
- const [playbackRate, setPlaybackRate] = React41.useState(1);
10464
- const [rateMenuOpen, setRateMenuOpen] = React41.useState(false);
10465
- const [captionsOn, setCaptionsOn] = React41.useState(false);
10466
- const [isPip, setIsPip] = React41.useState(false);
10467
- const setRefs = React41.useCallback(
11551
+ const containerRef = React43.useRef(null);
11552
+ const videoRef = React43.useRef(null);
11553
+ const [isPlaying, setIsPlaying] = React43.useState(Boolean(autoPlay));
11554
+ const [isLoaded, setIsLoaded] = React43.useState(false);
11555
+ const [currentTime, setCurrentTime] = React43.useState(0);
11556
+ const [duration, setDuration] = React43.useState(0);
11557
+ const [buffered, setBuffered] = React43.useState(0);
11558
+ const [volume, setVolume] = React43.useState(1);
11559
+ const [isMuted, setIsMuted] = React43.useState(Boolean(muted));
11560
+ const [isFullscreen, setIsFullscreen] = React43.useState(false);
11561
+ const [playbackRate, setPlaybackRate] = React43.useState(1);
11562
+ const [rateMenuOpen, setRateMenuOpen] = React43.useState(false);
11563
+ const [captionsOn, setCaptionsOn] = React43.useState(false);
11564
+ const [isPip, setIsPip] = React43.useState(false);
11565
+ const setRefs = React43.useCallback(
10468
11566
  (el) => {
10469
11567
  videoRef.current = el;
10470
11568
  if (typeof ref === "function") ref(el);
@@ -10472,14 +11570,14 @@ var Video = React41.forwardRef((props, ref) => {
10472
11570
  },
10473
11571
  [ref]
10474
11572
  );
10475
- React41.useEffect(() => {
11573
+ React43.useEffect(() => {
10476
11574
  const onFsChange = () => {
10477
11575
  setIsFullscreen(document.fullscreenElement === containerRef.current);
10478
11576
  };
10479
11577
  document.addEventListener("fullscreenchange", onFsChange);
10480
11578
  return () => document.removeEventListener("fullscreenchange", onFsChange);
10481
11579
  }, []);
10482
- React41.useEffect(() => {
11580
+ React43.useEffect(() => {
10483
11581
  const v = videoRef.current;
10484
11582
  if (!v) return;
10485
11583
  const onEnter = () => setIsPip(true);
@@ -10593,13 +11691,13 @@ var Video = React41.forwardRef((props, ref) => {
10593
11691
  const volumePct = (isMuted ? 0 : volume) * 100;
10594
11692
  const VolumeGlyph = isMuted || volume === 0 ? VolumeXIcon_default : volume < 0.5 ? VolumeIcon_default : Volume2Icon_default;
10595
11693
  const pipSupported = typeof document !== "undefined" && "pictureInPictureEnabled" in document && document.pictureInPictureEnabled;
10596
- return /* @__PURE__ */ jsxs223(
11694
+ return /* @__PURE__ */ jsxs225(
10597
11695
  "div",
10598
11696
  {
10599
11697
  ref: containerRef,
10600
11698
  className: clsx_default("lib-xplat-video", showControls && "has-controls"),
10601
11699
  children: [
10602
- /* @__PURE__ */ jsx352(
11700
+ /* @__PURE__ */ jsx354(
10603
11701
  "video",
10604
11702
  {
10605
11703
  ref: setRefs,
@@ -10620,7 +11718,7 @@ var Video = React41.forwardRef((props, ref) => {
10620
11718
  children
10621
11719
  }
10622
11720
  ),
10623
- showCenterPlay && /* @__PURE__ */ jsx352(
11721
+ showCenterPlay && /* @__PURE__ */ jsx354(
10624
11722
  "button",
10625
11723
  {
10626
11724
  type: "button",
@@ -10632,11 +11730,11 @@ var Video = React41.forwardRef((props, ref) => {
10632
11730
  onClick: togglePlay,
10633
11731
  "aria-label": isPlaying ? "\uC77C\uC2DC\uC815\uC9C0" : "\uC7AC\uC0DD",
10634
11732
  tabIndex: -1,
10635
- children: /* @__PURE__ */ jsx352("span", { className: "center-play-icon", children: /* @__PURE__ */ jsx352(PlayCircleIcon_default, {}) })
11733
+ children: /* @__PURE__ */ jsx354("span", { className: "center-play-icon", children: /* @__PURE__ */ jsx354(PlayCircleIcon_default, {}) })
10636
11734
  }
10637
11735
  ),
10638
- showControls && /* @__PURE__ */ jsxs223("div", { className: "controls", onClick: (e) => e.stopPropagation(), children: [
10639
- /* @__PURE__ */ jsx352(
11736
+ showControls && /* @__PURE__ */ jsxs225("div", { className: "controls", onClick: (e) => e.stopPropagation(), children: [
11737
+ /* @__PURE__ */ jsx354(
10640
11738
  "input",
10641
11739
  {
10642
11740
  type: "range",
@@ -10653,29 +11751,29 @@ var Video = React41.forwardRef((props, ref) => {
10653
11751
  }
10654
11752
  }
10655
11753
  ),
10656
- /* @__PURE__ */ jsxs223("div", { className: "controls-row", children: [
10657
- /* @__PURE__ */ jsx352(
11754
+ /* @__PURE__ */ jsxs225("div", { className: "controls-row", children: [
11755
+ /* @__PURE__ */ jsx354(
10658
11756
  "button",
10659
11757
  {
10660
11758
  type: "button",
10661
11759
  className: "control-btn",
10662
11760
  onClick: togglePlay,
10663
11761
  "aria-label": isPlaying ? "\uC77C\uC2DC\uC815\uC9C0" : "\uC7AC\uC0DD",
10664
- children: isPlaying ? /* @__PURE__ */ jsx352(PauseIcon_default, {}) : /* @__PURE__ */ jsx352(PlayIcon_default, {})
11762
+ children: isPlaying ? /* @__PURE__ */ jsx354(PauseIcon_default, {}) : /* @__PURE__ */ jsx354(PlayIcon_default, {})
10665
11763
  }
10666
11764
  ),
10667
- /* @__PURE__ */ jsxs223("div", { className: "volume-group", children: [
10668
- /* @__PURE__ */ jsx352(
11765
+ /* @__PURE__ */ jsxs225("div", { className: "volume-group", children: [
11766
+ /* @__PURE__ */ jsx354(
10669
11767
  "button",
10670
11768
  {
10671
11769
  type: "button",
10672
11770
  className: "control-btn",
10673
11771
  onClick: toggleMute,
10674
11772
  "aria-label": isMuted ? "\uC74C\uC18C\uAC70 \uD574\uC81C" : "\uC74C\uC18C\uAC70",
10675
- children: /* @__PURE__ */ jsx352(VolumeGlyph, {})
11773
+ children: /* @__PURE__ */ jsx354(VolumeGlyph, {})
10676
11774
  }
10677
11775
  ),
10678
- /* @__PURE__ */ jsx352(
11776
+ /* @__PURE__ */ jsx354(
10679
11777
  "input",
10680
11778
  {
10681
11779
  type: "range",
@@ -10690,14 +11788,14 @@ var Video = React41.forwardRef((props, ref) => {
10690
11788
  }
10691
11789
  )
10692
11790
  ] }),
10693
- /* @__PURE__ */ jsxs223("span", { className: "time", children: [
11791
+ /* @__PURE__ */ jsxs225("span", { className: "time", children: [
10694
11792
  formatTime(currentTime),
10695
11793
  " / ",
10696
11794
  formatTime(duration)
10697
11795
  ] }),
10698
- /* @__PURE__ */ jsx352("div", { className: "controls-spacer" }),
10699
- playbackRates && playbackRates.length > 0 && /* @__PURE__ */ jsxs223("div", { className: clsx_default("rate-group", rateMenuOpen && "is-open"), children: [
10700
- /* @__PURE__ */ jsxs223(
11796
+ /* @__PURE__ */ jsx354("div", { className: "controls-spacer" }),
11797
+ playbackRates && playbackRates.length > 0 && /* @__PURE__ */ jsxs225("div", { className: clsx_default("rate-group", rateMenuOpen && "is-open"), children: [
11798
+ /* @__PURE__ */ jsxs225(
10701
11799
  "button",
10702
11800
  {
10703
11801
  type: "button",
@@ -10711,7 +11809,7 @@ var Video = React41.forwardRef((props, ref) => {
10711
11809
  ]
10712
11810
  }
10713
11811
  ),
10714
- rateMenuOpen && /* @__PURE__ */ jsx352("ul", { className: "rate-menu", role: "menu", children: playbackRates.map((r2) => /* @__PURE__ */ jsx352("li", { children: /* @__PURE__ */ jsxs223(
11812
+ rateMenuOpen && /* @__PURE__ */ jsx354("ul", { className: "rate-menu", role: "menu", children: playbackRates.map((r2) => /* @__PURE__ */ jsx354("li", { children: /* @__PURE__ */ jsxs225(
10715
11813
  "button",
10716
11814
  {
10717
11815
  type: "button",
@@ -10725,7 +11823,7 @@ var Video = React41.forwardRef((props, ref) => {
10725
11823
  }
10726
11824
  ) }, r2)) })
10727
11825
  ] }),
10728
- showCaptions && /* @__PURE__ */ jsx352(
11826
+ showCaptions && /* @__PURE__ */ jsx354(
10729
11827
  "button",
10730
11828
  {
10731
11829
  type: "button",
@@ -10733,37 +11831,37 @@ var Video = React41.forwardRef((props, ref) => {
10733
11831
  onClick: toggleCaptions,
10734
11832
  "aria-label": captionsOn ? "\uC790\uB9C9 \uB044\uAE30" : "\uC790\uB9C9 \uCF1C\uAE30",
10735
11833
  "aria-pressed": captionsOn,
10736
- children: /* @__PURE__ */ jsx352(TypeIcon_default, {})
11834
+ children: /* @__PURE__ */ jsx354(TypeIcon_default, {})
10737
11835
  }
10738
11836
  ),
10739
- showPip && pipSupported && /* @__PURE__ */ jsx352(
11837
+ showPip && pipSupported && /* @__PURE__ */ jsx354(
10740
11838
  "button",
10741
11839
  {
10742
11840
  type: "button",
10743
11841
  className: clsx_default("control-btn", isPip && "is-active"),
10744
11842
  onClick: togglePip,
10745
11843
  "aria-label": isPip ? "PIP \uC885\uB8CC" : "PIP",
10746
- children: /* @__PURE__ */ jsx352(PipIcon, {})
11844
+ children: /* @__PURE__ */ jsx354(PipIcon, {})
10747
11845
  }
10748
11846
  ),
10749
- showDownload && /* @__PURE__ */ jsx352(
11847
+ showDownload && /* @__PURE__ */ jsx354(
10750
11848
  "a",
10751
11849
  {
10752
11850
  className: "control-btn",
10753
11851
  href: src,
10754
11852
  download: downloadFileName ?? true,
10755
11853
  "aria-label": "\uB2E4\uC6B4\uB85C\uB4DC",
10756
- children: /* @__PURE__ */ jsx352(DownloadIcon_default, {})
11854
+ children: /* @__PURE__ */ jsx354(DownloadIcon_default, {})
10757
11855
  }
10758
11856
  ),
10759
- /* @__PURE__ */ jsx352(
11857
+ /* @__PURE__ */ jsx354(
10760
11858
  "button",
10761
11859
  {
10762
11860
  type: "button",
10763
11861
  className: "control-btn",
10764
11862
  onClick: toggleFullscreen,
10765
11863
  "aria-label": isFullscreen ? "\uC804\uCCB4\uD654\uBA74 \uC885\uB8CC" : "\uC804\uCCB4\uD654\uBA74",
10766
- children: isFullscreen ? /* @__PURE__ */ jsx352(MinimizeIcon_default, {}) : /* @__PURE__ */ jsx352(MaximizeIcon_default, {})
11864
+ children: isFullscreen ? /* @__PURE__ */ jsx354(MinimizeIcon_default, {}) : /* @__PURE__ */ jsx354(MaximizeIcon_default, {})
10767
11865
  }
10768
11866
  )
10769
11867
  ] })
@@ -10776,7 +11874,7 @@ Video.displayName = "Video";
10776
11874
  var Video_default = Video;
10777
11875
 
10778
11876
  // src/layout/Grid/FullGrid/FullGrid.tsx
10779
- import { jsx as jsx353 } from "react/jsx-runtime";
11877
+ import { jsx as jsx355 } from "react/jsx-runtime";
10780
11878
  var GAP_MAP = {
10781
11879
  none: "var(--spacing-space-none)",
10782
11880
  xs: "var(--spacing-space-1)",
@@ -10789,13 +11887,13 @@ var GAP_MAP = {
10789
11887
  var FullGrid = (props) => {
10790
11888
  const { children, gap } = props;
10791
11889
  const style = gap != null ? { gap: GAP_MAP[gap] } : void 0;
10792
- return /* @__PURE__ */ jsx353("div", { className: "lib-xplat-full-grid", style, children });
11890
+ return /* @__PURE__ */ jsx355("div", { className: "lib-xplat-full-grid", style, children });
10793
11891
  };
10794
11892
  FullGrid.displayName = "FullGrid";
10795
11893
  var FullGrid_default = FullGrid;
10796
11894
 
10797
11895
  // src/layout/Grid/FullScreen/FullScreen.tsx
10798
- import { jsx as jsx354 } from "react/jsx-runtime";
11896
+ import { jsx as jsx356 } from "react/jsx-runtime";
10799
11897
  var GAP_MAP2 = {
10800
11898
  none: "var(--spacing-space-none)",
10801
11899
  xs: "var(--spacing-space-1)",
@@ -10808,13 +11906,13 @@ var GAP_MAP2 = {
10808
11906
  var FullScreen = (props) => {
10809
11907
  const { children, gap } = props;
10810
11908
  const style = gap != null ? { gap: GAP_MAP2[gap] } : void 0;
10811
- return /* @__PURE__ */ jsx354("div", { className: "lib-xplat-full-screen", style, children });
11909
+ return /* @__PURE__ */ jsx356("div", { className: "lib-xplat-full-screen", style, children });
10812
11910
  };
10813
11911
  FullScreen.displayName = "FullScreen";
10814
11912
  var FullScreen_default = FullScreen;
10815
11913
 
10816
11914
  // src/layout/Grid/Item/Item.tsx
10817
- import { jsx as jsx355 } from "react/jsx-runtime";
11915
+ import { jsx as jsx357 } from "react/jsx-runtime";
10818
11916
  var calculateSpans = (column) => {
10819
11917
  const spans = {};
10820
11918
  let inherited = column.default;
@@ -10831,35 +11929,35 @@ var GridItem = ({ column, children, className }) => {
10831
11929
  Object.entries(spans).forEach(([key, value]) => {
10832
11930
  style[`--column-${key}`] = value;
10833
11931
  });
10834
- return /* @__PURE__ */ jsx355("div", { className: clsx_default("lib-xplat-grid-item", className), style, children });
11932
+ return /* @__PURE__ */ jsx357("div", { className: clsx_default("lib-xplat-grid-item", className), style, children });
10835
11933
  };
10836
11934
  GridItem.displayName = "GridItem";
10837
11935
  var Item_default = GridItem;
10838
11936
 
10839
11937
  // src/layout/Header/Header.tsx
10840
- import { jsx as jsx356, jsxs as jsxs224 } from "react/jsx-runtime";
11938
+ import { jsx as jsx358, jsxs as jsxs226 } from "react/jsx-runtime";
10841
11939
  var Header = ({
10842
11940
  logo,
10843
11941
  centerContent,
10844
11942
  rightContent
10845
11943
  }) => {
10846
- return /* @__PURE__ */ jsxs224("div", { className: "lib-xplat-layout-header", children: [
10847
- /* @__PURE__ */ jsx356("div", { children: logo }),
10848
- /* @__PURE__ */ jsx356("div", { children: centerContent }),
10849
- /* @__PURE__ */ jsx356("div", { children: rightContent })
11944
+ return /* @__PURE__ */ jsxs226("div", { className: "lib-xplat-layout-header", children: [
11945
+ /* @__PURE__ */ jsx358("div", { children: logo }),
11946
+ /* @__PURE__ */ jsx358("div", { children: centerContent }),
11947
+ /* @__PURE__ */ jsx358("div", { children: rightContent })
10850
11948
  ] });
10851
11949
  };
10852
11950
  Header.displayName = "Header";
10853
11951
  var Header_default = Header;
10854
11952
 
10855
11953
  // src/layout/Layout/Layout.tsx
10856
- import { Fragment as Fragment7, jsx as jsx357, jsxs as jsxs225 } from "react/jsx-runtime";
11954
+ import { Fragment as Fragment7, jsx as jsx359, jsxs as jsxs227 } from "react/jsx-runtime";
10857
11955
  var Layout = (props) => {
10858
11956
  const { header, sideBar, children } = props;
10859
- return /* @__PURE__ */ jsx357("div", { className: "lib-xplat-layout", children: /* @__PURE__ */ jsxs225("div", { className: "lib-xplat-layout-content-wrapper", children: [
10860
- sideBar && /* @__PURE__ */ jsx357(Fragment7, { children: sideBar }),
10861
- /* @__PURE__ */ jsxs225("div", { className: "lib-xplat-layout-content", children: [
10862
- header && /* @__PURE__ */ jsx357("div", { className: "lib-xplat-layout-conent-header", children: header }),
11957
+ return /* @__PURE__ */ jsx359("div", { className: "lib-xplat-layout", children: /* @__PURE__ */ jsxs227("div", { className: "lib-xplat-layout-content-wrapper", children: [
11958
+ sideBar && /* @__PURE__ */ jsx359(Fragment7, { children: sideBar }),
11959
+ /* @__PURE__ */ jsxs227("div", { className: "lib-xplat-layout-content", children: [
11960
+ header && /* @__PURE__ */ jsx359("div", { className: "lib-xplat-layout-conent-header", children: header }),
10863
11961
  children
10864
11962
  ] })
10865
11963
  ] }) });
@@ -10868,31 +11966,31 @@ Layout.displayName = "Layout";
10868
11966
  var Layout_default = Layout;
10869
11967
 
10870
11968
  // src/layout/SideBar/SideBar.tsx
10871
- import React43 from "react";
11969
+ import React45 from "react";
10872
11970
 
10873
11971
  // src/layout/SideBar/SideBarContext.tsx
10874
- import React42 from "react";
10875
- var SideBarContext = React42.createContext(null);
11972
+ import React44 from "react";
11973
+ var SideBarContext = React44.createContext(null);
10876
11974
  var useSideBarContext = () => {
10877
- const ctx = React42.useContext(SideBarContext);
11975
+ const ctx = React44.useContext(SideBarContext);
10878
11976
  if (!ctx) throw new Error("Error");
10879
11977
  return ctx;
10880
11978
  };
10881
11979
  var SideBarContext_default = SideBarContext;
10882
11980
 
10883
11981
  // src/layout/SideBar/SideBar.tsx
10884
- import { jsx as jsx358 } from "react/jsx-runtime";
11982
+ import { jsx as jsx360 } from "react/jsx-runtime";
10885
11983
  var SideBar = (props) => {
10886
11984
  const { children, className } = props;
10887
- const [isOpen, setIsOpen] = React43.useState(true);
11985
+ const [isOpen, setIsOpen] = React45.useState(true);
10888
11986
  const handleSwitchSideBar = () => {
10889
11987
  setIsOpen((prev) => !prev);
10890
11988
  };
10891
- return /* @__PURE__ */ jsx358(
11989
+ return /* @__PURE__ */ jsx360(
10892
11990
  SideBarContext_default.Provider,
10893
11991
  {
10894
11992
  value: { isSidebarOpen: isOpen, handleSwitchSideBar },
10895
- children: /* @__PURE__ */ jsx358(
11993
+ children: /* @__PURE__ */ jsx360(
10896
11994
  "div",
10897
11995
  {
10898
11996
  className: clsx_default(
@@ -11199,6 +12297,7 @@ export {
11199
12297
  Spinner_default as Spinner,
11200
12298
  SquareIcon_default as SquareIcon,
11201
12299
  StarIcon_default as StarIcon,
12300
+ Stat_default as Stat,
11202
12301
  Steps_default as Steps,
11203
12302
  StopCircleIcon_default as StopCircleIcon,
11204
12303
  SuccessIcon_default as SuccessIcon,
@@ -11223,6 +12322,7 @@ export {
11223
12322
  ThermometerIcon_default as ThermometerIcon,
11224
12323
  ThumbsDownIcon_default as ThumbsDownIcon,
11225
12324
  ThumbsUpIcon_default as ThumbsUpIcon,
12325
+ TimePicker_default as TimePicker,
11226
12326
  ToastProvider,
11227
12327
  ToggleLeftIcon_default as ToggleLeftIcon,
11228
12328
  ToggleRightIcon_default as ToggleRightIcon,