@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.
- package/dist/components/AutoResizeTextArea/index.cjs +14 -5
- package/dist/components/AutoResizeTextArea/index.css +15 -0
- package/dist/components/AutoResizeTextArea/index.d.cts +4 -0
- package/dist/components/AutoResizeTextArea/index.d.ts +4 -0
- package/dist/components/AutoResizeTextArea/index.js +14 -5
- package/dist/components/Badge/index.d.cts +1 -1
- package/dist/components/Badge/index.d.ts +1 -1
- package/dist/components/ChatInput/index.cjs +20 -7
- package/dist/components/ChatInput/index.css +15 -0
- package/dist/components/ChatInput/index.d.cts +4 -0
- package/dist/components/ChatInput/index.d.ts +4 -0
- package/dist/components/ChatInput/index.js +20 -7
- package/dist/components/CheckBox/index.cjs +8 -3
- package/dist/components/CheckBox/index.css +15 -0
- package/dist/components/CheckBox/index.d.cts +1 -1
- package/dist/components/CheckBox/index.d.ts +1 -1
- package/dist/components/CheckBox/index.js +8 -3
- package/dist/components/DatePicker/index.cjs +179 -64
- package/dist/components/DatePicker/index.css +19 -0
- package/dist/components/DatePicker/index.js +179 -64
- package/dist/components/Drawer/index.cjs +83 -4
- package/dist/components/Drawer/index.js +83 -4
- package/dist/components/Dropdown/index.cjs +57 -16
- package/dist/components/Dropdown/index.css +3 -0
- package/dist/components/Dropdown/index.js +57 -16
- package/dist/components/Editor/index.cjs +779 -50
- package/dist/components/Editor/index.css +100 -0
- package/dist/components/Editor/index.d.cts +1 -1
- package/dist/components/Editor/index.d.ts +1 -1
- package/dist/components/Editor/index.js +779 -50
- package/dist/components/FieldMessage/index.cjs +8 -3
- package/dist/components/FieldMessage/index.css +15 -0
- package/dist/components/FieldMessage/index.d.cts +11 -4
- package/dist/components/FieldMessage/index.d.ts +11 -4
- package/dist/components/FieldMessage/index.js +8 -3
- package/dist/components/FileUpload/index.cjs +8 -3
- package/dist/components/FileUpload/index.css +15 -0
- package/dist/components/FileUpload/index.js +8 -3
- package/dist/components/ImageSelector/index.cjs +8 -3
- package/dist/components/ImageSelector/index.css +15 -0
- package/dist/components/ImageSelector/index.js +8 -3
- package/dist/components/Input/index.cjs +15 -5
- package/dist/components/Input/index.css +15 -0
- package/dist/components/Input/index.d.cts +4 -0
- package/dist/components/Input/index.d.ts +4 -0
- package/dist/components/Input/index.js +15 -5
- package/dist/components/Modal/index.cjs +84 -5
- package/dist/components/Modal/index.js +84 -5
- package/dist/components/NotificationBadge/index.d.cts +1 -1
- package/dist/components/NotificationBadge/index.d.ts +1 -1
- package/dist/components/Pagination/index.d.cts +1 -1
- package/dist/components/Pagination/index.d.ts +1 -1
- package/dist/components/PopOver/index.cjs +55 -13
- package/dist/components/PopOver/index.css +3 -0
- package/dist/components/PopOver/index.js +55 -13
- package/dist/components/Progress/index.d.cts +1 -1
- package/dist/components/Progress/index.d.ts +1 -1
- package/dist/components/Radio/index.cjs +8 -3
- package/dist/components/Radio/index.css +15 -0
- package/dist/components/Radio/index.d.cts +1 -1
- package/dist/components/Radio/index.d.ts +1 -1
- package/dist/components/Radio/index.js +8 -3
- package/dist/components/Select/index.cjs +120 -39
- package/dist/components/Select/index.css +57 -0
- package/dist/components/Select/index.d.cts +11 -0
- package/dist/components/Select/index.d.ts +11 -0
- package/dist/components/Select/index.js +120 -39
- package/dist/components/Spinner/index.d.cts +1 -1
- package/dist/components/Spinner/index.d.ts +1 -1
- package/dist/components/Stat/index.cjs +84 -0
- package/dist/components/Stat/index.css +96 -0
- package/dist/components/Stat/index.d.cts +37 -0
- package/dist/components/Stat/index.d.ts +37 -0
- package/dist/components/Stat/index.js +57 -0
- package/dist/components/Steps/index.d.cts +1 -1
- package/dist/components/Steps/index.d.ts +1 -1
- package/dist/components/Switch/index.cjs +14 -5
- package/dist/components/Switch/index.css +15 -0
- package/dist/components/Switch/index.d.cts +6 -1
- package/dist/components/Switch/index.d.ts +6 -1
- package/dist/components/Switch/index.js +14 -5
- package/dist/components/Tab/index.cjs +49 -25
- package/dist/components/Tab/index.css +4 -0
- package/dist/components/Tab/index.js +49 -25
- package/dist/components/TextArea/index.cjs +14 -4
- package/dist/components/TextArea/index.css +15 -0
- package/dist/components/TextArea/index.d.cts +4 -0
- package/dist/components/TextArea/index.d.ts +4 -0
- package/dist/components/TextArea/index.js +14 -4
- package/dist/components/TimePicker/index.cjs +461 -0
- package/dist/components/TimePicker/index.css +175 -0
- package/dist/components/TimePicker/index.d.cts +42 -0
- package/dist/components/TimePicker/index.d.ts +42 -0
- package/dist/components/TimePicker/index.js +424 -0
- package/dist/components/index.cjs +1500 -398
- package/dist/components/index.css +385 -0
- package/dist/components/index.d.cts +3 -1
- package/dist/components/index.d.ts +3 -1
- package/dist/components/index.js +1498 -398
- package/dist/index.cjs +1524 -422
- package/dist/index.css +385 -0
- package/dist/index.d.cts +3 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.js +1522 -422
- package/dist/status-njWqQWFV.d.cts +20 -0
- package/dist/status-njWqQWFV.d.ts +20 -0
- package/guidelines/AGENT_PROMPT.md +3 -3
- package/guidelines/Guidelines.md +3 -0
- package/guidelines/components/editor.md +141 -0
- package/guidelines/components/form.md +19 -0
- package/guidelines/components/stat.md +31 -0
- package/guidelines/components/time-picker.md +49 -0
- package/package.json +1 -1
- package/dist/status-g_KP3qT6.d.cts +0 -8
- package/dist/status-g_KP3qT6.d.ts +0 -8
package/dist/index.cjs
CHANGED
|
@@ -320,6 +320,7 @@ __export(index_exports, {
|
|
|
320
320
|
Spinner: () => Spinner_default,
|
|
321
321
|
SquareIcon: () => SquareIcon_default,
|
|
322
322
|
StarIcon: () => StarIcon_default,
|
|
323
|
+
Stat: () => Stat_default,
|
|
323
324
|
Steps: () => Steps_default,
|
|
324
325
|
StopCircleIcon: () => StopCircleIcon_default,
|
|
325
326
|
SuccessIcon: () => SuccessIcon_default,
|
|
@@ -344,6 +345,7 @@ __export(index_exports, {
|
|
|
344
345
|
ThermometerIcon: () => ThermometerIcon_default,
|
|
345
346
|
ThumbsDownIcon: () => ThumbsDownIcon_default,
|
|
346
347
|
ThumbsUpIcon: () => ThumbsUpIcon_default,
|
|
348
|
+
TimePicker: () => TimePicker_default,
|
|
347
349
|
ToastProvider: () => ToastProvider,
|
|
348
350
|
ToggleLeftIcon: () => ToggleLeftIcon_default,
|
|
349
351
|
ToggleRightIcon: () => ToggleRightIcon_default,
|
|
@@ -6029,11 +6031,16 @@ var FieldMessage = (props) => {
|
|
|
6029
6031
|
FieldMessage.displayName = "FieldMessage";
|
|
6030
6032
|
var FieldMessage_default = FieldMessage;
|
|
6031
6033
|
var Field = (props) => {
|
|
6032
|
-
const { validations, children } = props;
|
|
6033
|
-
|
|
6034
|
+
const { label, required = false, htmlFor, validations, children } = props;
|
|
6035
|
+
const hasMessages = !!validations && validations.length > 0;
|
|
6036
|
+
if (!label && !hasMessages) return /* @__PURE__ */ (0, import_jsx_runtime297.jsx)(import_jsx_runtime297.Fragment, { children });
|
|
6034
6037
|
return /* @__PURE__ */ (0, import_jsx_runtime297.jsxs)("div", { className: "lib-xplat-field", children: [
|
|
6038
|
+
label && /* @__PURE__ */ (0, import_jsx_runtime297.jsxs)("label", { className: "lib-xplat-field-label", htmlFor, children: [
|
|
6039
|
+
label,
|
|
6040
|
+
required && /* @__PURE__ */ (0, import_jsx_runtime297.jsx)("span", { className: "required", "aria-hidden": "true", children: "*" })
|
|
6041
|
+
] }),
|
|
6035
6042
|
children,
|
|
6036
|
-
/* @__PURE__ */ (0, import_jsx_runtime297.jsx)(FieldMessage, { validations })
|
|
6043
|
+
hasMessages && /* @__PURE__ */ (0, import_jsx_runtime297.jsx)(FieldMessage, { validations })
|
|
6037
6044
|
] });
|
|
6038
6045
|
};
|
|
6039
6046
|
Field.displayName = "Field";
|
|
@@ -6044,7 +6051,9 @@ var import_jsx_runtime298 = require("react/jsx-runtime");
|
|
|
6044
6051
|
var MAX_HEIGHT = 400;
|
|
6045
6052
|
var AutoResizeTextArea = import_react2.default.forwardRef(
|
|
6046
6053
|
(props, ref) => {
|
|
6047
|
-
const { value, className, onChange, disabled, bare = false, validations, ...textareaProps } = props;
|
|
6054
|
+
const { value, className, onChange, disabled, bare = false, validations, label, required, ...textareaProps } = props;
|
|
6055
|
+
const autoId = import_react2.default.useId();
|
|
6056
|
+
const fieldId = props.id ?? autoId;
|
|
6048
6057
|
const localRef = import_react2.default.useRef(null);
|
|
6049
6058
|
const setRefs = (el) => {
|
|
6050
6059
|
localRef.current = el;
|
|
@@ -6078,6 +6087,7 @@ var AutoResizeTextArea = import_react2.default.forwardRef(
|
|
|
6078
6087
|
"aria-invalid": hasError(validations) || void 0,
|
|
6079
6088
|
...textareaProps,
|
|
6080
6089
|
ref: setRefs,
|
|
6090
|
+
id: fieldId,
|
|
6081
6091
|
className,
|
|
6082
6092
|
disabled,
|
|
6083
6093
|
value,
|
|
@@ -6091,12 +6101,13 @@ var AutoResizeTextArea = import_react2.default.forwardRef(
|
|
|
6091
6101
|
"aria-invalid": hasError(validations) || void 0,
|
|
6092
6102
|
...textareaProps,
|
|
6093
6103
|
ref: setRefs,
|
|
6104
|
+
id: fieldId,
|
|
6094
6105
|
disabled,
|
|
6095
6106
|
value,
|
|
6096
6107
|
onChange: handleChange
|
|
6097
6108
|
}
|
|
6098
6109
|
) }) });
|
|
6099
|
-
return /* @__PURE__ */ (0, import_jsx_runtime298.jsx)(Field, { validations, children: control });
|
|
6110
|
+
return /* @__PURE__ */ (0, import_jsx_runtime298.jsx)(Field, { validations, label, required, htmlFor: fieldId, children: control });
|
|
6100
6111
|
}
|
|
6101
6112
|
);
|
|
6102
6113
|
AutoResizeTextArea.displayName = "AutoResizeTextArea";
|
|
@@ -7314,8 +7325,11 @@ var ChatInput = import_react7.default.forwardRef(
|
|
|
7314
7325
|
buttonType = "primary",
|
|
7315
7326
|
onSubmit,
|
|
7316
7327
|
onChange,
|
|
7317
|
-
validations
|
|
7328
|
+
validations,
|
|
7329
|
+
label,
|
|
7330
|
+
required
|
|
7318
7331
|
} = props;
|
|
7332
|
+
const fieldId = import_react7.default.useId();
|
|
7319
7333
|
const isControlled = valueProp !== void 0;
|
|
7320
7334
|
const [internalValue, setInternalValue] = import_react7.default.useState("");
|
|
7321
7335
|
const value = isControlled ? valueProp : internalValue;
|
|
@@ -7340,6 +7354,7 @@ var ChatInput = import_react7.default.forwardRef(
|
|
|
7340
7354
|
/* @__PURE__ */ (0, import_jsx_runtime308.jsx)(
|
|
7341
7355
|
AutoResizeTextArea_default,
|
|
7342
7356
|
{
|
|
7357
|
+
id: fieldId,
|
|
7343
7358
|
ref,
|
|
7344
7359
|
bare: true,
|
|
7345
7360
|
className: "chat-input-textarea",
|
|
@@ -7364,7 +7379,7 @@ var ChatInput = import_react7.default.forwardRef(
|
|
|
7364
7379
|
}
|
|
7365
7380
|
)
|
|
7366
7381
|
] });
|
|
7367
|
-
return /* @__PURE__ */ (0, import_jsx_runtime308.jsx)(Field, { validations, children: control });
|
|
7382
|
+
return /* @__PURE__ */ (0, import_jsx_runtime308.jsx)(Field, { validations, label, required, htmlFor: fieldId, children: control });
|
|
7368
7383
|
}
|
|
7369
7384
|
);
|
|
7370
7385
|
ChatInput.displayName = "ChatInput";
|
|
@@ -7448,7 +7463,7 @@ Chip.displayName = "Chip";
|
|
|
7448
7463
|
var Chip_default = Chip;
|
|
7449
7464
|
|
|
7450
7465
|
// src/components/DatePicker/InputDatePicker/index.tsx
|
|
7451
|
-
var
|
|
7466
|
+
var import_react13 = __toESM(require("react"), 1);
|
|
7452
7467
|
|
|
7453
7468
|
// src/components/Input/Input.tsx
|
|
7454
7469
|
var import_react8 = __toESM(require("react"), 1);
|
|
@@ -7546,8 +7561,12 @@ var Input = import_react8.default.forwardRef((props, ref) => {
|
|
|
7546
7561
|
suffix,
|
|
7547
7562
|
disabled,
|
|
7548
7563
|
validations,
|
|
7564
|
+
label,
|
|
7565
|
+
required,
|
|
7549
7566
|
...inputProps
|
|
7550
7567
|
} = props;
|
|
7568
|
+
const autoId = import_react8.default.useId();
|
|
7569
|
+
const fieldId = inputProps.id ?? autoId;
|
|
7551
7570
|
const localValue = formatValue(type, value);
|
|
7552
7571
|
const handleChange = (e) => {
|
|
7553
7572
|
let val = e.target.value;
|
|
@@ -7563,7 +7582,7 @@ var Input = import_react8.default.forwardRef((props, ref) => {
|
|
|
7563
7582
|
onChange(event);
|
|
7564
7583
|
}
|
|
7565
7584
|
};
|
|
7566
|
-
return /* @__PURE__ */ (0, import_jsx_runtime311.jsxs)("div", { className: clsx_default("lib-xplat-input-wrap", className), children: [
|
|
7585
|
+
return /* @__PURE__ */ (0, import_jsx_runtime311.jsx)(Field, { label, required, htmlFor: fieldId, children: /* @__PURE__ */ (0, import_jsx_runtime311.jsxs)("div", { className: clsx_default("lib-xplat-input-wrap", className), children: [
|
|
7567
7586
|
/* @__PURE__ */ (0, import_jsx_runtime311.jsxs)(
|
|
7568
7587
|
"div",
|
|
7569
7588
|
{
|
|
@@ -7574,6 +7593,7 @@ var Input = import_react8.default.forwardRef((props, ref) => {
|
|
|
7574
7593
|
{
|
|
7575
7594
|
...inputProps,
|
|
7576
7595
|
ref,
|
|
7596
|
+
id: fieldId,
|
|
7577
7597
|
disabled,
|
|
7578
7598
|
type: type === "number" ? "text" : type,
|
|
7579
7599
|
value: localValue,
|
|
@@ -7586,7 +7606,7 @@ var Input = import_react8.default.forwardRef((props, ref) => {
|
|
|
7586
7606
|
}
|
|
7587
7607
|
),
|
|
7588
7608
|
/* @__PURE__ */ (0, import_jsx_runtime311.jsx)(FieldMessage_default, { validations })
|
|
7589
|
-
] });
|
|
7609
|
+
] }) });
|
|
7590
7610
|
});
|
|
7591
7611
|
Input.displayName = "Input";
|
|
7592
7612
|
var Input_default = Input;
|
|
@@ -7616,16 +7636,96 @@ PasswordInput.displayName = "PasswordInput";
|
|
|
7616
7636
|
var PasswordInput_default = PasswordInput;
|
|
7617
7637
|
|
|
7618
7638
|
// src/components/Modal/Modal.tsx
|
|
7619
|
-
var
|
|
7639
|
+
var import_react11 = __toESM(require("react"), 1);
|
|
7620
7640
|
var import_react_dom = require("react-dom");
|
|
7641
|
+
|
|
7642
|
+
// src/tokens/hooks/useOverlayKeyboard.ts
|
|
7643
|
+
var import_react10 = __toESM(require("react"), 1);
|
|
7644
|
+
var FOCUSABLE = [
|
|
7645
|
+
"a[href]",
|
|
7646
|
+
"button:not([disabled])",
|
|
7647
|
+
"input:not([disabled]):not([type='hidden'])",
|
|
7648
|
+
"select:not([disabled])",
|
|
7649
|
+
"textarea:not([disabled])",
|
|
7650
|
+
"[tabindex]:not([tabindex='-1'])"
|
|
7651
|
+
].join(",");
|
|
7652
|
+
var focusableIn = (el) => Array.from(el.querySelectorAll(FOCUSABLE)).filter(
|
|
7653
|
+
// 화면에 없는 것은 제외 (display:none 등)
|
|
7654
|
+
(n) => n.offsetWidth > 0 || n.offsetHeight > 0 || n === document.activeElement
|
|
7655
|
+
);
|
|
7656
|
+
var useEscapeKey = (enabled, onEscape) => {
|
|
7657
|
+
import_react10.default.useEffect(() => {
|
|
7658
|
+
if (!enabled) return;
|
|
7659
|
+
const onKey = (e) => {
|
|
7660
|
+
if (e.key !== "Escape") return;
|
|
7661
|
+
if (e.defaultPrevented) return;
|
|
7662
|
+
e.preventDefault();
|
|
7663
|
+
onEscape();
|
|
7664
|
+
};
|
|
7665
|
+
document.addEventListener("keydown", onKey);
|
|
7666
|
+
return () => document.removeEventListener("keydown", onKey);
|
|
7667
|
+
}, [enabled, onEscape]);
|
|
7668
|
+
};
|
|
7669
|
+
var useFocusTrap = (containerRef, enabled, options = {}) => {
|
|
7670
|
+
const { trap = false, initialFocus } = options;
|
|
7671
|
+
const restoreRef = import_react10.default.useRef(null);
|
|
7672
|
+
import_react10.default.useEffect(() => {
|
|
7673
|
+
if (!enabled) return;
|
|
7674
|
+
restoreRef.current = document.activeElement;
|
|
7675
|
+
const raf = requestAnimationFrame(() => {
|
|
7676
|
+
const el = containerRef.current;
|
|
7677
|
+
if (!el) return;
|
|
7678
|
+
const target = initialFocus?.current ?? focusableIn(el)[0] ?? el;
|
|
7679
|
+
if (!target.hasAttribute("tabindex") && !focusableIn(el).includes(target)) {
|
|
7680
|
+
target.setAttribute("tabindex", "-1");
|
|
7681
|
+
}
|
|
7682
|
+
target.focus({ preventScroll: true });
|
|
7683
|
+
});
|
|
7684
|
+
return () => {
|
|
7685
|
+
cancelAnimationFrame(raf);
|
|
7686
|
+
const prev = restoreRef.current;
|
|
7687
|
+
if (prev && document.contains(prev)) prev.focus({ preventScroll: true });
|
|
7688
|
+
};
|
|
7689
|
+
}, [enabled, containerRef, initialFocus]);
|
|
7690
|
+
import_react10.default.useEffect(() => {
|
|
7691
|
+
if (!enabled || !trap) return;
|
|
7692
|
+
const onKey = (e) => {
|
|
7693
|
+
if (e.key !== "Tab") return;
|
|
7694
|
+
const el = containerRef.current;
|
|
7695
|
+
if (!el) return;
|
|
7696
|
+
const items = focusableIn(el);
|
|
7697
|
+
if (items.length === 0) {
|
|
7698
|
+
e.preventDefault();
|
|
7699
|
+
return;
|
|
7700
|
+
}
|
|
7701
|
+
const first = items[0];
|
|
7702
|
+
const last = items[items.length - 1];
|
|
7703
|
+
const active = document.activeElement;
|
|
7704
|
+
if (e.shiftKey && (active === first || !el.contains(active))) {
|
|
7705
|
+
e.preventDefault();
|
|
7706
|
+
last.focus();
|
|
7707
|
+
} else if (!e.shiftKey && (active === last || !el.contains(active))) {
|
|
7708
|
+
e.preventDefault();
|
|
7709
|
+
first.focus();
|
|
7710
|
+
}
|
|
7711
|
+
};
|
|
7712
|
+
document.addEventListener("keydown", onKey);
|
|
7713
|
+
return () => document.removeEventListener("keydown", onKey);
|
|
7714
|
+
}, [enabled, trap, containerRef]);
|
|
7715
|
+
};
|
|
7716
|
+
|
|
7717
|
+
// src/components/Modal/Modal.tsx
|
|
7621
7718
|
var import_jsx_runtime313 = require("react/jsx-runtime");
|
|
7622
7719
|
var ANIMATION_DURATION_MS = 200;
|
|
7623
7720
|
var Modal = (props) => {
|
|
7624
7721
|
const { isOpen, onClose, children } = props;
|
|
7625
|
-
const [mounted, setMounted] =
|
|
7626
|
-
const [visible, setVisible] =
|
|
7627
|
-
const [settled, setSettled] =
|
|
7628
|
-
|
|
7722
|
+
const [mounted, setMounted] = import_react11.default.useState(false);
|
|
7723
|
+
const [visible, setVisible] = import_react11.default.useState(false);
|
|
7724
|
+
const [settled, setSettled] = import_react11.default.useState(false);
|
|
7725
|
+
const boxRef = import_react11.default.useRef(null);
|
|
7726
|
+
useEscapeKey(isOpen, onClose);
|
|
7727
|
+
useFocusTrap(boxRef, isOpen && mounted, { trap: true });
|
|
7728
|
+
import_react11.default.useEffect(() => {
|
|
7629
7729
|
if (isOpen) {
|
|
7630
7730
|
setMounted(true);
|
|
7631
7731
|
const show = setTimeout(() => setVisible(true), 1);
|
|
@@ -7652,6 +7752,7 @@ var Modal = (props) => {
|
|
|
7652
7752
|
children: /* @__PURE__ */ (0, import_jsx_runtime313.jsx)(
|
|
7653
7753
|
"div",
|
|
7654
7754
|
{
|
|
7755
|
+
ref: boxRef,
|
|
7655
7756
|
className: clsx_default("lib-xplat-modal", "modal-box", stateClass, settled && "settled"),
|
|
7656
7757
|
role: "dialog",
|
|
7657
7758
|
"aria-modal": "true",
|
|
@@ -7668,9 +7769,9 @@ Modal.displayName = "Modal";
|
|
|
7668
7769
|
var Modal_default = Modal;
|
|
7669
7770
|
|
|
7670
7771
|
// src/components/DatePicker/SingleDatePicker/index.tsx
|
|
7671
|
-
var
|
|
7772
|
+
var import_react12 = __toESM(require("react"), 1);
|
|
7672
7773
|
var import_jsx_runtime314 = require("react/jsx-runtime");
|
|
7673
|
-
var DayCell2 =
|
|
7774
|
+
var DayCell2 = import_react12.default.memo(
|
|
7674
7775
|
({
|
|
7675
7776
|
day,
|
|
7676
7777
|
disabled,
|
|
@@ -7722,26 +7823,26 @@ var SingleDatePicker = (props) => {
|
|
|
7722
7823
|
initialYear,
|
|
7723
7824
|
initialMonth
|
|
7724
7825
|
);
|
|
7725
|
-
const [pickerMode, setPickerMode] =
|
|
7726
|
-
const [yearRangeStart, setYearRangeStart] =
|
|
7826
|
+
const [pickerMode, setPickerMode] = import_react12.default.useState("days");
|
|
7827
|
+
const [yearRangeStart, setYearRangeStart] = import_react12.default.useState(
|
|
7727
7828
|
Math.floor((initialYear ?? (/* @__PURE__ */ new Date()).getFullYear()) / 12) * 12
|
|
7728
7829
|
);
|
|
7729
|
-
const minTime =
|
|
7830
|
+
const minTime = import_react12.default.useMemo(
|
|
7730
7831
|
() => minDate ? new Date(minDate.getFullYear(), minDate.getMonth(), minDate.getDate()).getTime() : -Infinity,
|
|
7731
7832
|
[minDate]
|
|
7732
7833
|
);
|
|
7733
|
-
const maxTime =
|
|
7834
|
+
const maxTime = import_react12.default.useMemo(
|
|
7734
7835
|
() => maxDate ? new Date(maxDate.getFullYear(), maxDate.getMonth(), maxDate.getDate()).getTime() : Infinity,
|
|
7735
7836
|
[maxDate]
|
|
7736
7837
|
);
|
|
7737
|
-
const highlightSet =
|
|
7838
|
+
const highlightSet = import_react12.default.useMemo(() => {
|
|
7738
7839
|
const set = /* @__PURE__ */ new Set();
|
|
7739
7840
|
for (const h of highlightDates) {
|
|
7740
7841
|
set.add(`${h.getFullYear()}-${h.getMonth()}-${h.getDate()}`);
|
|
7741
7842
|
}
|
|
7742
7843
|
return set;
|
|
7743
7844
|
}, [highlightDates]);
|
|
7744
|
-
const handleSelect =
|
|
7845
|
+
const handleSelect = import_react12.default.useCallback(
|
|
7745
7846
|
(date) => {
|
|
7746
7847
|
onChange?.(date);
|
|
7747
7848
|
},
|
|
@@ -7870,8 +7971,8 @@ var formatDate = (date) => {
|
|
|
7870
7971
|
};
|
|
7871
7972
|
var InputDatePicker = (props) => {
|
|
7872
7973
|
const { value, onChange, minDate, maxDate, disabled, locale = "ko", placeholder } = props;
|
|
7873
|
-
const [isOpen, setIsOpen] =
|
|
7874
|
-
const [tempDate, setTempDate] =
|
|
7974
|
+
const [isOpen, setIsOpen] = import_react13.default.useState(false);
|
|
7975
|
+
const [tempDate, setTempDate] = import_react13.default.useState(value ?? /* @__PURE__ */ new Date());
|
|
7875
7976
|
const handleOpen = () => {
|
|
7876
7977
|
if (disabled) return;
|
|
7877
7978
|
setTempDate(value ?? /* @__PURE__ */ new Date());
|
|
@@ -7920,23 +8021,27 @@ InputDatePicker.displayName = "InputDatePicker";
|
|
|
7920
8021
|
var InputDatePicker_default = InputDatePicker;
|
|
7921
8022
|
|
|
7922
8023
|
// src/components/DatePicker/PopupPicker/index.tsx
|
|
7923
|
-
var
|
|
8024
|
+
var import_react17 = __toESM(require("react"), 1);
|
|
7924
8025
|
|
|
7925
8026
|
// src/components/DatePicker/RangePicker/index.tsx
|
|
7926
|
-
var
|
|
8027
|
+
var import_react16 = __toESM(require("react"), 1);
|
|
7927
8028
|
|
|
7928
8029
|
// src/components/Tab/Tab.tsx
|
|
7929
|
-
var
|
|
8030
|
+
var import_react15 = __toESM(require("react"), 1);
|
|
7930
8031
|
|
|
7931
8032
|
// src/components/Tab/TabItem.tsx
|
|
7932
|
-
var
|
|
8033
|
+
var import_react14 = __toESM(require("react"), 1);
|
|
7933
8034
|
var import_jsx_runtime316 = require("react/jsx-runtime");
|
|
7934
|
-
var TabItem =
|
|
8035
|
+
var TabItem = import_react14.default.forwardRef((props, ref) => {
|
|
7935
8036
|
const { isActive: isActive2, title, onClick } = props;
|
|
7936
8037
|
return /* @__PURE__ */ (0, import_jsx_runtime316.jsx)(
|
|
7937
|
-
"
|
|
8038
|
+
"button",
|
|
7938
8039
|
{
|
|
7939
8040
|
ref,
|
|
8041
|
+
type: "button",
|
|
8042
|
+
role: "tab",
|
|
8043
|
+
"aria-selected": isActive2,
|
|
8044
|
+
tabIndex: isActive2 ? 0 : -1,
|
|
7940
8045
|
className: clsx_default("tab-item", isActive2 ? "active" : null),
|
|
7941
8046
|
onClick,
|
|
7942
8047
|
children: title
|
|
@@ -7951,44 +8056,64 @@ var import_jsx_runtime317 = require("react/jsx-runtime");
|
|
|
7951
8056
|
var Tab = (props) => {
|
|
7952
8057
|
const { activeIndex, onChange, tabs, variant, type, size = "md" } = props;
|
|
7953
8058
|
const shape = variant ?? type ?? "default";
|
|
7954
|
-
const [underlineStyle, setUnderlineStyle] =
|
|
8059
|
+
const [underlineStyle, setUnderlineStyle] = import_react15.default.useState({
|
|
7955
8060
|
left: 0,
|
|
7956
8061
|
width: 0
|
|
7957
8062
|
});
|
|
7958
|
-
const itemRefs =
|
|
8063
|
+
const itemRefs = import_react15.default.useRef([]);
|
|
8064
|
+
const handleKeyDown = (e) => {
|
|
8065
|
+
const last = tabs.length - 1;
|
|
8066
|
+
let next = null;
|
|
8067
|
+
if (e.key === "ArrowRight") next = activeIndex >= last ? 0 : activeIndex + 1;
|
|
8068
|
+
else if (e.key === "ArrowLeft") next = activeIndex <= 0 ? last : activeIndex - 1;
|
|
8069
|
+
else if (e.key === "Home") next = 0;
|
|
8070
|
+
else if (e.key === "End") next = last;
|
|
8071
|
+
if (next === null) return;
|
|
8072
|
+
e.preventDefault();
|
|
8073
|
+
onChange(tabs[next], next);
|
|
8074
|
+
itemRefs.current[next]?.focus();
|
|
8075
|
+
};
|
|
7959
8076
|
const handleChangeActiveTab = (tabItem, tabIdx) => {
|
|
7960
8077
|
onChange(tabItem, tabIdx);
|
|
7961
8078
|
};
|
|
7962
|
-
|
|
8079
|
+
import_react15.default.useEffect(() => {
|
|
7963
8080
|
const el = itemRefs.current[activeIndex];
|
|
7964
8081
|
if (el) {
|
|
7965
8082
|
setUnderlineStyle({ left: el.offsetLeft, width: el.offsetWidth });
|
|
7966
8083
|
}
|
|
7967
8084
|
}, [activeIndex, tabs.length]);
|
|
7968
|
-
return /* @__PURE__ */ (0, import_jsx_runtime317.jsxs)(
|
|
7969
|
-
|
|
7970
|
-
|
|
7971
|
-
{
|
|
7972
|
-
|
|
7973
|
-
|
|
7974
|
-
|
|
7975
|
-
|
|
7976
|
-
|
|
7977
|
-
|
|
7978
|
-
|
|
7979
|
-
|
|
7980
|
-
|
|
7981
|
-
|
|
7982
|
-
|
|
7983
|
-
|
|
7984
|
-
|
|
7985
|
-
|
|
7986
|
-
|
|
7987
|
-
|
|
7988
|
-
|
|
7989
|
-
|
|
7990
|
-
|
|
7991
|
-
|
|
8085
|
+
return /* @__PURE__ */ (0, import_jsx_runtime317.jsxs)(
|
|
8086
|
+
"div",
|
|
8087
|
+
{
|
|
8088
|
+
className: clsx_default("lib-xplat-tab", `type-${shape}`, size),
|
|
8089
|
+
role: "tablist",
|
|
8090
|
+
onKeyDown: handleKeyDown,
|
|
8091
|
+
children: [
|
|
8092
|
+
tabs.map((tab, idx) => /* @__PURE__ */ (0, import_jsx_runtime317.jsx)(
|
|
8093
|
+
TabItem_default,
|
|
8094
|
+
{
|
|
8095
|
+
onClick: () => handleChangeActiveTab(tab, idx),
|
|
8096
|
+
isActive: activeIndex === idx,
|
|
8097
|
+
ref: (el) => {
|
|
8098
|
+
itemRefs.current[idx] = el;
|
|
8099
|
+
},
|
|
8100
|
+
title: tab.title
|
|
8101
|
+
},
|
|
8102
|
+
`${tab.value}_${idx}`
|
|
8103
|
+
)),
|
|
8104
|
+
shape === "toggle" && /* @__PURE__ */ (0, import_jsx_runtime317.jsx)(
|
|
8105
|
+
"div",
|
|
8106
|
+
{
|
|
8107
|
+
className: "tab-toggle-underline",
|
|
8108
|
+
style: {
|
|
8109
|
+
left: underlineStyle.left,
|
|
8110
|
+
width: underlineStyle.width
|
|
8111
|
+
}
|
|
8112
|
+
}
|
|
8113
|
+
)
|
|
8114
|
+
]
|
|
8115
|
+
}
|
|
8116
|
+
);
|
|
7992
8117
|
};
|
|
7993
8118
|
Tab.displayName = "Tab";
|
|
7994
8119
|
var Tab_default = Tab;
|
|
@@ -8004,7 +8129,7 @@ var RangePicker = (props) => {
|
|
|
8004
8129
|
maxDate,
|
|
8005
8130
|
locale = "ko"
|
|
8006
8131
|
} = props;
|
|
8007
|
-
const [activeTab, setActiveTab] =
|
|
8132
|
+
const [activeTab, setActiveTab] = import_react16.default.useState("start");
|
|
8008
8133
|
const handleStartChange = (date) => {
|
|
8009
8134
|
if (!date) return;
|
|
8010
8135
|
const newStart = date > endDate ? endDate : date;
|
|
@@ -8089,7 +8214,7 @@ var RangePicker_default = RangePicker;
|
|
|
8089
8214
|
var import_jsx_runtime319 = require("react/jsx-runtime");
|
|
8090
8215
|
var PopupPicker = (props) => {
|
|
8091
8216
|
const { component, type, locale } = props;
|
|
8092
|
-
const [isOpen, setIsOpen] =
|
|
8217
|
+
const [isOpen, setIsOpen] = import_react17.default.useState(false);
|
|
8093
8218
|
const handleClick = () => setIsOpen(true);
|
|
8094
8219
|
const handleClose = () => setIsOpen(false);
|
|
8095
8220
|
const handleSingleChange = (date) => {
|
|
@@ -8098,7 +8223,7 @@ var PopupPicker = (props) => {
|
|
|
8098
8223
|
handleClose();
|
|
8099
8224
|
};
|
|
8100
8225
|
return /* @__PURE__ */ (0, import_jsx_runtime319.jsxs)("div", { className: "lib-xplat-popup-datepicker", children: [
|
|
8101
|
-
|
|
8226
|
+
import_react17.default.cloneElement(component, { onClick: handleClick }),
|
|
8102
8227
|
/* @__PURE__ */ (0, import_jsx_runtime319.jsx)(Modal_default, { isOpen, onClose: handleClose, children: /* @__PURE__ */ (0, import_jsx_runtime319.jsxs)("div", { className: clsx_default("lib-xplat-popup-datepicker-card", type === "range" && "range-mode"), children: [
|
|
8103
8228
|
/* @__PURE__ */ (0, import_jsx_runtime319.jsxs)("div", { className: "popup-datepicker-content", children: [
|
|
8104
8229
|
type === "single" && /* @__PURE__ */ (0, import_jsx_runtime319.jsx)(
|
|
@@ -8157,15 +8282,18 @@ Divider.displayName = "Divider";
|
|
|
8157
8282
|
var Divider_default = Divider;
|
|
8158
8283
|
|
|
8159
8284
|
// src/components/Drawer/Drawer.tsx
|
|
8160
|
-
var
|
|
8285
|
+
var import_react18 = __toESM(require("react"), 1);
|
|
8161
8286
|
var import_react_dom2 = require("react-dom");
|
|
8162
8287
|
var import_jsx_runtime321 = require("react/jsx-runtime");
|
|
8163
8288
|
var ANIMATION_DURATION_MS2 = 250;
|
|
8164
8289
|
var Drawer = (props) => {
|
|
8165
8290
|
const { isOpen, onClose, placement = "right", size = "md", title, children } = props;
|
|
8166
|
-
const [mounted, setMounted] =
|
|
8167
|
-
const [visible, setVisible] =
|
|
8168
|
-
|
|
8291
|
+
const [mounted, setMounted] = import_react18.default.useState(false);
|
|
8292
|
+
const [visible, setVisible] = import_react18.default.useState(false);
|
|
8293
|
+
const panelRef = import_react18.default.useRef(null);
|
|
8294
|
+
useEscapeKey(isOpen, onClose);
|
|
8295
|
+
useFocusTrap(panelRef, isOpen && mounted, { trap: true });
|
|
8296
|
+
import_react18.default.useEffect(() => {
|
|
8169
8297
|
if (isOpen) {
|
|
8170
8298
|
setMounted(true);
|
|
8171
8299
|
const t2 = setTimeout(() => setVisible(true), 1);
|
|
@@ -8187,6 +8315,7 @@ var Drawer = (props) => {
|
|
|
8187
8315
|
children: /* @__PURE__ */ (0, import_jsx_runtime321.jsxs)(
|
|
8188
8316
|
"div",
|
|
8189
8317
|
{
|
|
8318
|
+
ref: panelRef,
|
|
8190
8319
|
className: clsx_default("lib-xplat-drawer", placement, size, stateClass),
|
|
8191
8320
|
role: "dialog",
|
|
8192
8321
|
"aria-modal": "true",
|
|
@@ -8209,7 +8338,7 @@ Drawer.displayName = "Drawer";
|
|
|
8209
8338
|
var Drawer_default = Drawer;
|
|
8210
8339
|
|
|
8211
8340
|
// src/components/Dropdown/Dropdown.tsx
|
|
8212
|
-
var
|
|
8341
|
+
var import_react21 = __toESM(require("react"), 1);
|
|
8213
8342
|
|
|
8214
8343
|
// src/tokens/hooks/Portal.tsx
|
|
8215
8344
|
var import_react_dom3 = __toESM(require("react-dom"), 1);
|
|
@@ -8221,13 +8350,15 @@ Portal.displayName = "Portal";
|
|
|
8221
8350
|
var Portal_default = Portal;
|
|
8222
8351
|
|
|
8223
8352
|
// src/tokens/hooks/useAutoPosition.ts
|
|
8224
|
-
var
|
|
8353
|
+
var import_react19 = __toESM(require("react"), 1);
|
|
8225
8354
|
var useAutoPosition = (triggerRef, popRef, enabled = true) => {
|
|
8226
|
-
const [position, setPosition] =
|
|
8355
|
+
const [position, setPosition] = import_react19.default.useState({
|
|
8227
8356
|
position: {},
|
|
8228
|
-
direction: "bottom"
|
|
8357
|
+
direction: "bottom",
|
|
8358
|
+
repositioning: false
|
|
8229
8359
|
});
|
|
8230
|
-
const
|
|
8360
|
+
const placedRef = import_react19.default.useRef(false);
|
|
8361
|
+
const calculatePosition = import_react19.default.useCallback(() => {
|
|
8231
8362
|
if (!triggerRef.current || !popRef.current) return;
|
|
8232
8363
|
const triggerRect = triggerRef.current.getBoundingClientRect();
|
|
8233
8364
|
const popW = popRef.current.offsetWidth;
|
|
@@ -8251,16 +8382,21 @@ var useAutoPosition = (triggerRef, popRef, enabled = true) => {
|
|
|
8251
8382
|
if (left < 8) left = 8;
|
|
8252
8383
|
setPosition({
|
|
8253
8384
|
position: { top, left },
|
|
8254
|
-
direction
|
|
8385
|
+
direction,
|
|
8386
|
+
repositioning: placedRef.current
|
|
8255
8387
|
});
|
|
8388
|
+
placedRef.current = true;
|
|
8256
8389
|
}, [triggerRef, popRef]);
|
|
8257
|
-
|
|
8258
|
-
if (!enabled)
|
|
8390
|
+
import_react19.default.useLayoutEffect(() => {
|
|
8391
|
+
if (!enabled) {
|
|
8392
|
+
placedRef.current = false;
|
|
8393
|
+
return;
|
|
8394
|
+
}
|
|
8259
8395
|
calculatePosition();
|
|
8260
8396
|
const raf = requestAnimationFrame(calculatePosition);
|
|
8261
8397
|
return () => cancelAnimationFrame(raf);
|
|
8262
8398
|
}, [calculatePosition, enabled]);
|
|
8263
|
-
|
|
8399
|
+
import_react19.default.useEffect(() => {
|
|
8264
8400
|
if (!enabled || !popRef.current) return;
|
|
8265
8401
|
const observer = new ResizeObserver(() => {
|
|
8266
8402
|
calculatePosition();
|
|
@@ -8268,13 +8404,19 @@ var useAutoPosition = (triggerRef, popRef, enabled = true) => {
|
|
|
8268
8404
|
observer.observe(popRef.current);
|
|
8269
8405
|
return () => observer.disconnect();
|
|
8270
8406
|
}, [calculatePosition, enabled, popRef]);
|
|
8271
|
-
|
|
8407
|
+
import_react19.default.useEffect(() => {
|
|
8272
8408
|
if (!enabled) return;
|
|
8273
|
-
|
|
8274
|
-
|
|
8409
|
+
let raf = 0;
|
|
8410
|
+
const onScrollOrResize = () => {
|
|
8411
|
+
cancelAnimationFrame(raf);
|
|
8412
|
+
raf = requestAnimationFrame(calculatePosition);
|
|
8413
|
+
};
|
|
8414
|
+
window.addEventListener("resize", onScrollOrResize, { passive: true });
|
|
8415
|
+
window.addEventListener("scroll", onScrollOrResize, { passive: true, capture: true });
|
|
8275
8416
|
return () => {
|
|
8276
|
-
|
|
8277
|
-
window.removeEventListener("
|
|
8417
|
+
cancelAnimationFrame(raf);
|
|
8418
|
+
window.removeEventListener("resize", onScrollOrResize);
|
|
8419
|
+
window.removeEventListener("scroll", onScrollOrResize, true);
|
|
8278
8420
|
};
|
|
8279
8421
|
}, [calculatePosition, enabled]);
|
|
8280
8422
|
return position;
|
|
@@ -8282,9 +8424,9 @@ var useAutoPosition = (triggerRef, popRef, enabled = true) => {
|
|
|
8282
8424
|
var useAutoPosition_default = useAutoPosition;
|
|
8283
8425
|
|
|
8284
8426
|
// src/tokens/hooks/useClickOutside.ts
|
|
8285
|
-
var
|
|
8427
|
+
var import_react20 = __toESM(require("react"), 1);
|
|
8286
8428
|
var useClickOutside = (refs, handler, enabled = true) => {
|
|
8287
|
-
|
|
8429
|
+
import_react20.default.useEffect(() => {
|
|
8288
8430
|
if (!enabled) return;
|
|
8289
8431
|
const refArray = Array.isArray(refs) ? refs : [refs];
|
|
8290
8432
|
const listener = (event) => {
|
|
@@ -8310,14 +8452,18 @@ var useClickOutside_default = useClickOutside;
|
|
|
8310
8452
|
var import_jsx_runtime322 = require("react/jsx-runtime");
|
|
8311
8453
|
var Dropdown = (props) => {
|
|
8312
8454
|
const { items, children } = props;
|
|
8313
|
-
const [isOpen, setIsOpen] =
|
|
8314
|
-
const [mounted, setMounted] =
|
|
8315
|
-
const [visible, setVisible] =
|
|
8316
|
-
const triggerRef =
|
|
8317
|
-
const menuRef =
|
|
8318
|
-
const { position, direction } = useAutoPosition_default(triggerRef, menuRef, mounted);
|
|
8455
|
+
const [isOpen, setIsOpen] = import_react21.default.useState(false);
|
|
8456
|
+
const [mounted, setMounted] = import_react21.default.useState(false);
|
|
8457
|
+
const [visible, setVisible] = import_react21.default.useState(false);
|
|
8458
|
+
const triggerRef = import_react21.default.useRef(null);
|
|
8459
|
+
const menuRef = import_react21.default.useRef(null);
|
|
8460
|
+
const { position, direction, repositioning } = useAutoPosition_default(triggerRef, menuRef, mounted);
|
|
8319
8461
|
useClickOutside_default([triggerRef, menuRef], () => setIsOpen(false), isOpen);
|
|
8320
|
-
|
|
8462
|
+
useEscapeKey(isOpen, () => {
|
|
8463
|
+
setIsOpen(false);
|
|
8464
|
+
triggerRef.current?.focus({ preventScroll: true });
|
|
8465
|
+
});
|
|
8466
|
+
import_react21.default.useEffect(() => {
|
|
8321
8467
|
if (isOpen) {
|
|
8322
8468
|
setMounted(true);
|
|
8323
8469
|
const t2 = setTimeout(() => setVisible(true), 1);
|
|
@@ -8346,7 +8492,7 @@ var Dropdown = (props) => {
|
|
|
8346
8492
|
"div",
|
|
8347
8493
|
{
|
|
8348
8494
|
ref: menuRef,
|
|
8349
|
-
className: clsx_default("lib-xplat-dropdown-menu", direction, { visible }),
|
|
8495
|
+
className: clsx_default("lib-xplat-dropdown-menu", direction, { visible }, repositioning && "repositioning"),
|
|
8350
8496
|
style: { top: position.top, left: position.left },
|
|
8351
8497
|
role: "menu",
|
|
8352
8498
|
children: items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime322.jsx)(
|
|
@@ -8371,7 +8517,112 @@ Dropdown.displayName = "Dropdown";
|
|
|
8371
8517
|
var Dropdown_default = Dropdown;
|
|
8372
8518
|
|
|
8373
8519
|
// src/components/Editor/Editor.tsx
|
|
8374
|
-
var
|
|
8520
|
+
var import_react22 = __toESM(require("react"), 1);
|
|
8521
|
+
|
|
8522
|
+
// src/components/Editor/highlight.ts
|
|
8523
|
+
var CODE_LANGUAGES = [
|
|
8524
|
+
{ value: "plain", label: "\uC5C6\uC74C" },
|
|
8525
|
+
{ value: "javascript", label: "JavaScript" },
|
|
8526
|
+
{ value: "typescript", label: "TypeScript" },
|
|
8527
|
+
{ value: "json", label: "JSON" },
|
|
8528
|
+
{ value: "html", label: "HTML" },
|
|
8529
|
+
{ value: "css", label: "CSS" },
|
|
8530
|
+
{ value: "python", label: "Python" },
|
|
8531
|
+
{ value: "sql", label: "SQL" },
|
|
8532
|
+
{ value: "bash", label: "Bash" }
|
|
8533
|
+
];
|
|
8534
|
+
var KEYWORDS = {
|
|
8535
|
+
plain: [],
|
|
8536
|
+
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(" "),
|
|
8537
|
+
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(" "),
|
|
8538
|
+
json: ["true", "false", "null"],
|
|
8539
|
+
html: [],
|
|
8540
|
+
css: [],
|
|
8541
|
+
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(" "),
|
|
8542
|
+
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(" "),
|
|
8543
|
+
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(" ")
|
|
8544
|
+
};
|
|
8545
|
+
var LINE_COMMENT = {
|
|
8546
|
+
javascript: "//",
|
|
8547
|
+
typescript: "//",
|
|
8548
|
+
css: "",
|
|
8549
|
+
python: "#",
|
|
8550
|
+
sql: "--",
|
|
8551
|
+
bash: "#"
|
|
8552
|
+
};
|
|
8553
|
+
var escape = (s) => s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
8554
|
+
var wrap = (cls, text) => `<span class="tok-${cls}">${escape(text)}</span>`;
|
|
8555
|
+
var highlight = (code, lang) => {
|
|
8556
|
+
if (lang === "plain" || !code) return escape(code);
|
|
8557
|
+
const keywords = new Set(KEYWORDS[lang]);
|
|
8558
|
+
const lineComment = LINE_COMMENT[lang];
|
|
8559
|
+
const caseInsensitive = lang === "sql";
|
|
8560
|
+
let out = "";
|
|
8561
|
+
let i = 0;
|
|
8562
|
+
while (i < code.length) {
|
|
8563
|
+
const rest = code.slice(i);
|
|
8564
|
+
if ((lang === "javascript" || lang === "typescript" || lang === "css") && rest.startsWith("/*")) {
|
|
8565
|
+
const end = code.indexOf("*/", i + 2);
|
|
8566
|
+
const stop = end === -1 ? code.length : end + 2;
|
|
8567
|
+
out += wrap("comment", code.slice(i, stop));
|
|
8568
|
+
i = stop;
|
|
8569
|
+
continue;
|
|
8570
|
+
}
|
|
8571
|
+
if (lineComment && rest.startsWith(lineComment)) {
|
|
8572
|
+
const nl = code.indexOf("\n", i);
|
|
8573
|
+
const stop = nl === -1 ? code.length : nl;
|
|
8574
|
+
out += wrap("comment", code.slice(i, stop));
|
|
8575
|
+
i = stop;
|
|
8576
|
+
continue;
|
|
8577
|
+
}
|
|
8578
|
+
const q = rest[0];
|
|
8579
|
+
if (q === '"' || q === "'" || q === "`") {
|
|
8580
|
+
let j = 1;
|
|
8581
|
+
while (j < rest.length) {
|
|
8582
|
+
if (rest[j] === "\\") {
|
|
8583
|
+
j += 2;
|
|
8584
|
+
continue;
|
|
8585
|
+
}
|
|
8586
|
+
if (rest[j] === q) {
|
|
8587
|
+
j += 1;
|
|
8588
|
+
break;
|
|
8589
|
+
}
|
|
8590
|
+
if (rest[j] === "\n" && q !== "`") break;
|
|
8591
|
+
j += 1;
|
|
8592
|
+
}
|
|
8593
|
+
out += wrap("string", rest.slice(0, j));
|
|
8594
|
+
i += j;
|
|
8595
|
+
continue;
|
|
8596
|
+
}
|
|
8597
|
+
const num = /^\d+(\.\d+)?/.exec(rest);
|
|
8598
|
+
if (num && !/[\w$]/.test(code[i - 1] ?? "")) {
|
|
8599
|
+
out += wrap("number", num[0]);
|
|
8600
|
+
i += num[0].length;
|
|
8601
|
+
continue;
|
|
8602
|
+
}
|
|
8603
|
+
const word = /^[A-Za-z_$][\w$]*/.exec(rest);
|
|
8604
|
+
if (word) {
|
|
8605
|
+
const w = word[0];
|
|
8606
|
+
const hit = caseInsensitive ? keywords.has(w.toUpperCase()) : keywords.has(w);
|
|
8607
|
+
out += hit ? wrap("keyword", w) : escape(w);
|
|
8608
|
+
i += w.length;
|
|
8609
|
+
continue;
|
|
8610
|
+
}
|
|
8611
|
+
if (lang === "html" && rest.startsWith("<")) {
|
|
8612
|
+
const tag = /^<\/?[A-Za-z][\w-]*/.exec(rest);
|
|
8613
|
+
if (tag) {
|
|
8614
|
+
out += wrap("keyword", tag[0]);
|
|
8615
|
+
i += tag[0].length;
|
|
8616
|
+
continue;
|
|
8617
|
+
}
|
|
8618
|
+
}
|
|
8619
|
+
out += escape(code[i]);
|
|
8620
|
+
i += 1;
|
|
8621
|
+
}
|
|
8622
|
+
return out;
|
|
8623
|
+
};
|
|
8624
|
+
|
|
8625
|
+
// src/components/Editor/Editor.tsx
|
|
8375
8626
|
var import_jsx_runtime323 = require("react/jsx-runtime");
|
|
8376
8627
|
var DEFAULT_TOOLBAR = [
|
|
8377
8628
|
"bold",
|
|
@@ -8379,14 +8630,27 @@ var DEFAULT_TOOLBAR = [
|
|
|
8379
8630
|
"underline",
|
|
8380
8631
|
"strikethrough",
|
|
8381
8632
|
"code",
|
|
8382
|
-
"heading",
|
|
8633
|
+
"heading-1",
|
|
8634
|
+
"heading-2",
|
|
8635
|
+
"heading-3",
|
|
8383
8636
|
"list",
|
|
8384
8637
|
"ordered-list",
|
|
8385
8638
|
"blockquote",
|
|
8386
8639
|
"code-block",
|
|
8387
8640
|
"link",
|
|
8388
8641
|
"image",
|
|
8389
|
-
"divider"
|
|
8642
|
+
"divider",
|
|
8643
|
+
"checklist",
|
|
8644
|
+
"table",
|
|
8645
|
+
"align-left",
|
|
8646
|
+
"align-center",
|
|
8647
|
+
"align-right",
|
|
8648
|
+
"highlight",
|
|
8649
|
+
"superscript",
|
|
8650
|
+
"subscript",
|
|
8651
|
+
"clear-format",
|
|
8652
|
+
"undo",
|
|
8653
|
+
"redo"
|
|
8390
8654
|
];
|
|
8391
8655
|
var ALLOWED_TAGS = /* @__PURE__ */ new Set([
|
|
8392
8656
|
"p",
|
|
@@ -8415,12 +8679,51 @@ var ALLOWED_TAGS = /* @__PURE__ */ new Set([
|
|
|
8415
8679
|
"img",
|
|
8416
8680
|
"hr",
|
|
8417
8681
|
"span",
|
|
8418
|
-
"div"
|
|
8682
|
+
"div",
|
|
8683
|
+
"sub",
|
|
8684
|
+
"sup",
|
|
8685
|
+
"mark",
|
|
8686
|
+
"table",
|
|
8687
|
+
"thead",
|
|
8688
|
+
"tbody",
|
|
8689
|
+
"tr",
|
|
8690
|
+
"th",
|
|
8691
|
+
"td"
|
|
8419
8692
|
]);
|
|
8420
8693
|
var ALLOWED_ATTRS = {
|
|
8421
8694
|
a: ["href", "target", "rel"],
|
|
8422
|
-
img: ["src", "alt"]
|
|
8695
|
+
img: ["src", "alt", "width"],
|
|
8696
|
+
// 정렬·체크리스트는 클래스로만 표현한다. style 을 열면 붙여넣기로 아무 CSS 나 들어온다
|
|
8697
|
+
p: ["class"],
|
|
8698
|
+
h1: ["class"],
|
|
8699
|
+
h2: ["class"],
|
|
8700
|
+
h3: ["class"],
|
|
8701
|
+
h4: ["class"],
|
|
8702
|
+
h5: ["class"],
|
|
8703
|
+
h6: ["class"],
|
|
8704
|
+
ul: ["class"],
|
|
8705
|
+
ol: ["class"],
|
|
8706
|
+
li: ["class", "data-checked"],
|
|
8707
|
+
blockquote: ["class"],
|
|
8708
|
+
div: ["class"],
|
|
8709
|
+
span: ["class"],
|
|
8710
|
+
pre: ["class"],
|
|
8711
|
+
code: ["class"],
|
|
8712
|
+
mark: ["class"],
|
|
8713
|
+
table: ["class"],
|
|
8714
|
+
td: ["class"],
|
|
8715
|
+
th: ["class"],
|
|
8716
|
+
tr: ["class"]
|
|
8423
8717
|
};
|
|
8718
|
+
var DROP_WITH_CONTENT = /* @__PURE__ */ new Set([
|
|
8719
|
+
"script",
|
|
8720
|
+
"style",
|
|
8721
|
+
"noscript",
|
|
8722
|
+
"iframe",
|
|
8723
|
+
"object",
|
|
8724
|
+
"embed",
|
|
8725
|
+
"template"
|
|
8726
|
+
]);
|
|
8424
8727
|
var sanitizeHtml = (input) => {
|
|
8425
8728
|
const doc = new DOMParser().parseFromString(`<div>${input}</div>`, "text/html");
|
|
8426
8729
|
const root = doc.body.firstElementChild;
|
|
@@ -8429,6 +8732,10 @@ var sanitizeHtml = (input) => {
|
|
|
8429
8732
|
const children = Array.from(node.children);
|
|
8430
8733
|
for (const child of children) {
|
|
8431
8734
|
const tag = child.tagName.toLowerCase();
|
|
8735
|
+
if (DROP_WITH_CONTENT.has(tag)) {
|
|
8736
|
+
node.removeChild(child);
|
|
8737
|
+
continue;
|
|
8738
|
+
}
|
|
8432
8739
|
if (!ALLOWED_TAGS.has(tag)) {
|
|
8433
8740
|
while (child.firstChild) node.insertBefore(child.firstChild, child);
|
|
8434
8741
|
node.removeChild(child);
|
|
@@ -8459,7 +8766,9 @@ var escapeHtml = (text) => {
|
|
|
8459
8766
|
};
|
|
8460
8767
|
var SLASH_ITEMS = [
|
|
8461
8768
|
{ key: "paragraph", label: "\uB2E8\uB77D", hint: "\uAE30\uBCF8 \uD14D\uC2A4\uD2B8" },
|
|
8462
|
-
{ key: "heading", label: "\uC81C\uBAA9 1", hint: "\uD070 \uC81C\uBAA9" },
|
|
8769
|
+
{ key: "heading-1", label: "\uC81C\uBAA9 1", hint: "\uAC00\uC7A5 \uD070 \uC81C\uBAA9" },
|
|
8770
|
+
{ key: "heading-2", label: "\uC81C\uBAA9 2", hint: "" },
|
|
8771
|
+
{ key: "heading-3", label: "\uC81C\uBAA9 3", hint: "" },
|
|
8463
8772
|
{ key: "list", label: "\uAE00\uBA38\uB9AC \uAE30\uD638 \uBAA9\uB85D", hint: "\u2022 \uD56D\uBAA9" },
|
|
8464
8773
|
{ key: "ordered-list", label: "\uBC88\uD638 \uB9E4\uAE30\uAE30 \uBAA9\uB85D", hint: "1. \uD56D\uBAA9" },
|
|
8465
8774
|
{ key: "blockquote", label: "\uC778\uC6A9", hint: "" },
|
|
@@ -8479,26 +8788,32 @@ var Editor = (props) => {
|
|
|
8479
8788
|
onImageUpload,
|
|
8480
8789
|
minHeight = 200
|
|
8481
8790
|
} = props;
|
|
8482
|
-
const editorRef =
|
|
8483
|
-
const lastRangeRef =
|
|
8484
|
-
const composingRef =
|
|
8485
|
-
const [isFocused, setIsFocused] =
|
|
8486
|
-
const [isEmpty, setIsEmpty] =
|
|
8487
|
-
const [activeFormats, setActiveFormats] =
|
|
8488
|
-
const [slashOpen, setSlashOpen] =
|
|
8489
|
-
const [slashFilter, setSlashFilter] =
|
|
8490
|
-
const [slashIdx, setSlashIdx] =
|
|
8491
|
-
const [slashPos, setSlashPos] =
|
|
8492
|
-
const slashStartRangeRef =
|
|
8493
|
-
const [linkOpen, setLinkOpen] =
|
|
8494
|
-
const [linkValue, setLinkValue] =
|
|
8495
|
-
const [linkPos, setLinkPos] =
|
|
8496
|
-
|
|
8497
|
-
|
|
8498
|
-
|
|
8499
|
-
|
|
8500
|
-
|
|
8501
|
-
|
|
8791
|
+
const editorRef = import_react22.default.useRef(null);
|
|
8792
|
+
const lastRangeRef = import_react22.default.useRef(null);
|
|
8793
|
+
const composingRef = import_react22.default.useRef(false);
|
|
8794
|
+
const [isFocused, setIsFocused] = import_react22.default.useState(false);
|
|
8795
|
+
const [isEmpty, setIsEmpty] = import_react22.default.useState(!value);
|
|
8796
|
+
const [activeFormats, setActiveFormats] = import_react22.default.useState(/* @__PURE__ */ new Set());
|
|
8797
|
+
const [slashOpen, setSlashOpen] = import_react22.default.useState(false);
|
|
8798
|
+
const [slashFilter, setSlashFilter] = import_react22.default.useState("");
|
|
8799
|
+
const [slashIdx, setSlashIdx] = import_react22.default.useState(0);
|
|
8800
|
+
const [slashPos, setSlashPos] = import_react22.default.useState({ top: 0, left: 0 });
|
|
8801
|
+
const slashStartRangeRef = import_react22.default.useRef(null);
|
|
8802
|
+
const [linkOpen, setLinkOpen] = import_react22.default.useState(false);
|
|
8803
|
+
const [linkValue, setLinkValue] = import_react22.default.useState("");
|
|
8804
|
+
const [linkPos, setLinkPos] = import_react22.default.useState({ top: 0, left: 0 });
|
|
8805
|
+
const lastEmittedRef = import_react22.default.useRef(null);
|
|
8806
|
+
import_react22.default.useEffect(() => {
|
|
8807
|
+
const el = editorRef.current;
|
|
8808
|
+
if (!el) return;
|
|
8809
|
+
if (value === lastEmittedRef.current) return;
|
|
8810
|
+
if (el.innerHTML === value) return;
|
|
8811
|
+
el.innerHTML = sanitizeHtml(value || "");
|
|
8812
|
+
if (!el.firstChild) el.innerHTML = "<p><br></p>";
|
|
8813
|
+
lastEmittedRef.current = null;
|
|
8814
|
+
historyRef.current = [{ html: el.innerHTML, caret: 0 }];
|
|
8815
|
+
historyIdxRef.current = 0;
|
|
8816
|
+
updateEmpty();
|
|
8502
8817
|
}, [value]);
|
|
8503
8818
|
const updateEmpty = () => {
|
|
8504
8819
|
const el = editorRef.current;
|
|
@@ -8514,10 +8829,19 @@ var Editor = (props) => {
|
|
|
8514
8829
|
}
|
|
8515
8830
|
};
|
|
8516
8831
|
const restoreSelection = () => {
|
|
8517
|
-
|
|
8832
|
+
const range = lastRangeRef.current;
|
|
8833
|
+
if (!range) return;
|
|
8834
|
+
if (!editorRef.current?.contains(range.startContainer)) {
|
|
8835
|
+
lastRangeRef.current = null;
|
|
8836
|
+
return;
|
|
8837
|
+
}
|
|
8518
8838
|
const sel = window.getSelection();
|
|
8519
|
-
|
|
8520
|
-
|
|
8839
|
+
try {
|
|
8840
|
+
sel?.removeAllRanges();
|
|
8841
|
+
sel?.addRange(range);
|
|
8842
|
+
} catch {
|
|
8843
|
+
lastRangeRef.current = null;
|
|
8844
|
+
}
|
|
8521
8845
|
};
|
|
8522
8846
|
const updateActiveFormats = () => {
|
|
8523
8847
|
if (!editorRef.current) return;
|
|
@@ -8533,6 +8857,17 @@ var Editor = (props) => {
|
|
|
8533
8857
|
if (document.queryCommandState("insertOrderedList")) next.add("ordered-list");
|
|
8534
8858
|
const block = String(document.queryCommandValue("formatBlock") || "").toLowerCase();
|
|
8535
8859
|
if (block) next.add(`block:${block}`);
|
|
8860
|
+
if (document.queryCommandState("superscript")) next.add("superscript");
|
|
8861
|
+
if (document.queryCommandState("subscript")) next.add("subscript");
|
|
8862
|
+
} catch {
|
|
8863
|
+
}
|
|
8864
|
+
try {
|
|
8865
|
+
const blockEl = currentBlock();
|
|
8866
|
+
if (blockEl?.classList.contains("align-center")) next.add("align:center");
|
|
8867
|
+
else if (blockEl?.classList.contains("align-right")) next.add("align:right");
|
|
8868
|
+
else if (blockEl) next.add("align:left");
|
|
8869
|
+
if (blockEl?.closest("mark")) next.add("highlight");
|
|
8870
|
+
if (blockEl?.closest("ul.checklist")) next.add("checklist");
|
|
8536
8871
|
} catch {
|
|
8537
8872
|
}
|
|
8538
8873
|
setActiveFormats(next);
|
|
@@ -8546,7 +8881,374 @@ var Editor = (props) => {
|
|
|
8546
8881
|
const setBlock = (tag) => {
|
|
8547
8882
|
exec("formatBlock", tag);
|
|
8548
8883
|
};
|
|
8884
|
+
const toggleBlock = (tag) => {
|
|
8885
|
+
const current = String(document.queryCommandValue("formatBlock") || "").toLowerCase();
|
|
8886
|
+
setBlock(current === tag ? "p" : tag);
|
|
8887
|
+
};
|
|
8888
|
+
const historyRef = import_react22.default.useRef([]);
|
|
8889
|
+
const historyIdxRef = import_react22.default.useRef(-1);
|
|
8890
|
+
const lastPushAtRef = import_react22.default.useRef(0);
|
|
8891
|
+
const isRestoringRef = import_react22.default.useRef(false);
|
|
8892
|
+
const caretOffset = (rootEl) => {
|
|
8893
|
+
const el = rootEl ?? editorRef.current;
|
|
8894
|
+
const sel = window.getSelection();
|
|
8895
|
+
if (!el || !sel || sel.rangeCount === 0 || !el.contains(sel.anchorNode)) return 0;
|
|
8896
|
+
const range = sel.getRangeAt(0).cloneRange();
|
|
8897
|
+
range.selectNodeContents(el);
|
|
8898
|
+
range.setEnd(sel.getRangeAt(0).endContainer, sel.getRangeAt(0).endOffset);
|
|
8899
|
+
return range.toString().length;
|
|
8900
|
+
};
|
|
8901
|
+
const setCaretOffset = (offset, rootEl) => {
|
|
8902
|
+
const el = rootEl ?? editorRef.current;
|
|
8903
|
+
if (!el) return;
|
|
8904
|
+
const walker = document.createTreeWalker(el, NodeFilter.SHOW_TEXT);
|
|
8905
|
+
let remaining = offset;
|
|
8906
|
+
let node = null;
|
|
8907
|
+
while (node = walker.nextNode()) {
|
|
8908
|
+
const len = node.textContent?.length ?? 0;
|
|
8909
|
+
if (remaining <= len) {
|
|
8910
|
+
const range = document.createRange();
|
|
8911
|
+
range.setStart(node, remaining);
|
|
8912
|
+
range.collapse(true);
|
|
8913
|
+
const sel = window.getSelection();
|
|
8914
|
+
sel?.removeAllRanges();
|
|
8915
|
+
sel?.addRange(range);
|
|
8916
|
+
return;
|
|
8917
|
+
}
|
|
8918
|
+
remaining -= len;
|
|
8919
|
+
}
|
|
8920
|
+
placeCaretAtEnd(el);
|
|
8921
|
+
};
|
|
8922
|
+
const pushHistory = (force = false) => {
|
|
8923
|
+
const el = editorRef.current;
|
|
8924
|
+
if (!el || isRestoringRef.current) return;
|
|
8925
|
+
const html = el.innerHTML;
|
|
8926
|
+
const hist = historyRef.current;
|
|
8927
|
+
const cur = hist[historyIdxRef.current];
|
|
8928
|
+
if (cur && cur.html === html) return;
|
|
8929
|
+
const now = Date.now();
|
|
8930
|
+
const coalesce = !force && cur && now - lastPushAtRef.current < 500;
|
|
8931
|
+
lastPushAtRef.current = now;
|
|
8932
|
+
if (coalesce) {
|
|
8933
|
+
hist[historyIdxRef.current] = { html, caret: caretOffset() };
|
|
8934
|
+
return;
|
|
8935
|
+
}
|
|
8936
|
+
hist.length = historyIdxRef.current + 1;
|
|
8937
|
+
hist.push({ html, caret: caretOffset() });
|
|
8938
|
+
if (hist.length > 200) hist.shift();
|
|
8939
|
+
historyIdxRef.current = hist.length - 1;
|
|
8940
|
+
};
|
|
8941
|
+
const applySnapshot = (snap) => {
|
|
8942
|
+
const el = editorRef.current;
|
|
8943
|
+
if (!el) return;
|
|
8944
|
+
isRestoringRef.current = true;
|
|
8945
|
+
el.innerHTML = snap.html;
|
|
8946
|
+
setCaretOffset(snap.caret);
|
|
8947
|
+
isRestoringRef.current = false;
|
|
8948
|
+
lastEmittedRef.current = el.innerHTML;
|
|
8949
|
+
onChange?.(el.innerHTML);
|
|
8950
|
+
updateEmpty();
|
|
8951
|
+
updateActiveFormats();
|
|
8952
|
+
};
|
|
8953
|
+
const undo = () => {
|
|
8954
|
+
pushHistory(true);
|
|
8955
|
+
if (historyIdxRef.current <= 0) return;
|
|
8956
|
+
historyIdxRef.current -= 1;
|
|
8957
|
+
applySnapshot(historyRef.current[historyIdxRef.current]);
|
|
8958
|
+
};
|
|
8959
|
+
const redo = () => {
|
|
8960
|
+
if (historyIdxRef.current >= historyRef.current.length - 1) return;
|
|
8961
|
+
historyIdxRef.current += 1;
|
|
8962
|
+
applySnapshot(historyRef.current[historyIdxRef.current]);
|
|
8963
|
+
};
|
|
8964
|
+
const langOf = (pre) => {
|
|
8965
|
+
const cls = Array.from(pre.classList).find((c) => c.startsWith("lang-"));
|
|
8966
|
+
return cls?.slice(5) ?? "plain";
|
|
8967
|
+
};
|
|
8968
|
+
const [codeLang, setCodeLang] = import_react22.default.useState("plain");
|
|
8969
|
+
const highlightRafRef = import_react22.default.useRef(0);
|
|
8970
|
+
const rehighlight = (pre) => {
|
|
8971
|
+
if (composingRef.current) return;
|
|
8972
|
+
const code = pre.querySelector("code");
|
|
8973
|
+
if (!code) return;
|
|
8974
|
+
const lang = langOf(pre);
|
|
8975
|
+
const text = code.textContent || "";
|
|
8976
|
+
const next = highlight(text, lang);
|
|
8977
|
+
if (code.innerHTML === next) return;
|
|
8978
|
+
const caret = caretOffset(code);
|
|
8979
|
+
isRestoringRef.current = true;
|
|
8980
|
+
code.innerHTML = next;
|
|
8981
|
+
setCaretOffset(caret, code);
|
|
8982
|
+
isRestoringRef.current = false;
|
|
8983
|
+
};
|
|
8984
|
+
const scheduleHighlight = () => {
|
|
8985
|
+
const pre = closestPre();
|
|
8986
|
+
if (!pre) return;
|
|
8987
|
+
cancelAnimationFrame(highlightRafRef.current);
|
|
8988
|
+
highlightRafRef.current = requestAnimationFrame(() => rehighlight(pre));
|
|
8989
|
+
};
|
|
8990
|
+
const changeCodeLang = (lang) => {
|
|
8991
|
+
const pre = closestPre();
|
|
8992
|
+
if (!pre) return;
|
|
8993
|
+
pushHistory(true);
|
|
8994
|
+
Array.from(pre.classList).filter((c) => c.startsWith("lang-")).forEach((c) => pre.classList.remove(c));
|
|
8995
|
+
if (lang !== "plain") pre.classList.add(`lang-${lang}`);
|
|
8996
|
+
setCodeLang(lang);
|
|
8997
|
+
rehighlight(pre);
|
|
8998
|
+
handleInput();
|
|
8999
|
+
};
|
|
9000
|
+
const closestPre = () => {
|
|
9001
|
+
const sel = window.getSelection();
|
|
9002
|
+
const node = sel?.anchorNode;
|
|
9003
|
+
if (!node || !editorRef.current?.contains(node)) return null;
|
|
9004
|
+
const el = node.nodeType === Node.ELEMENT_NODE ? node : node.parentElement;
|
|
9005
|
+
return el?.closest("pre") ?? null;
|
|
9006
|
+
};
|
|
9007
|
+
const insertCodeBlock = () => {
|
|
9008
|
+
pushHistory(true);
|
|
9009
|
+
const el = editorRef.current;
|
|
9010
|
+
const sel = window.getSelection();
|
|
9011
|
+
if (!el || !sel || sel.rangeCount === 0) return;
|
|
9012
|
+
const existing = closestPre();
|
|
9013
|
+
if (existing) {
|
|
9014
|
+
const p = document.createElement("p");
|
|
9015
|
+
p.textContent = existing.textContent || "";
|
|
9016
|
+
if (!p.textContent) p.innerHTML = "<br>";
|
|
9017
|
+
existing.replaceWith(p);
|
|
9018
|
+
placeCaretAtEnd(p);
|
|
9019
|
+
handleInput();
|
|
9020
|
+
return;
|
|
9021
|
+
}
|
|
9022
|
+
const range = sel.getRangeAt(0);
|
|
9023
|
+
const frag = range.cloneContents();
|
|
9024
|
+
const holder = document.createElement("div");
|
|
9025
|
+
holder.appendChild(frag);
|
|
9026
|
+
const BLOCK = /^(p|div|h[1-6]|li|blockquote|pre|tr)$/i;
|
|
9027
|
+
const linesOf = (node) => {
|
|
9028
|
+
const out = [];
|
|
9029
|
+
let cur = "";
|
|
9030
|
+
for (const child of Array.from(node.childNodes)) {
|
|
9031
|
+
if (child.nodeType === Node.TEXT_NODE) {
|
|
9032
|
+
cur += child.textContent || "";
|
|
9033
|
+
} else if (child.nodeName === "BR") {
|
|
9034
|
+
out.push(cur);
|
|
9035
|
+
cur = "";
|
|
9036
|
+
} else if (BLOCK.test(child.nodeName)) {
|
|
9037
|
+
if (cur) {
|
|
9038
|
+
out.push(cur);
|
|
9039
|
+
cur = "";
|
|
9040
|
+
}
|
|
9041
|
+
const sub = linesOf(child);
|
|
9042
|
+
out.push(...sub.length > 0 ? sub : [""]);
|
|
9043
|
+
} else {
|
|
9044
|
+
cur += linesOf(child).join("\n");
|
|
9045
|
+
}
|
|
9046
|
+
}
|
|
9047
|
+
if (cur) out.push(cur);
|
|
9048
|
+
return out;
|
|
9049
|
+
};
|
|
9050
|
+
const text = linesOf(holder).join("\n").replace(/\n+$/, "");
|
|
9051
|
+
const pre = document.createElement("pre");
|
|
9052
|
+
const code = document.createElement("code");
|
|
9053
|
+
code.textContent = text || "";
|
|
9054
|
+
pre.appendChild(code);
|
|
9055
|
+
range.deleteContents();
|
|
9056
|
+
range.insertNode(pre);
|
|
9057
|
+
ensureParagraphAfter(pre);
|
|
9058
|
+
placeCaretAtEnd(code);
|
|
9059
|
+
handleInput();
|
|
9060
|
+
};
|
|
9061
|
+
const insertTextAtCaret = (text) => {
|
|
9062
|
+
const sel = window.getSelection();
|
|
9063
|
+
if (!sel || sel.rangeCount === 0) return;
|
|
9064
|
+
const range = sel.getRangeAt(0);
|
|
9065
|
+
range.deleteContents();
|
|
9066
|
+
const node = document.createTextNode(text);
|
|
9067
|
+
range.insertNode(node);
|
|
9068
|
+
range.setStartAfter(node);
|
|
9069
|
+
range.collapse(true);
|
|
9070
|
+
sel.removeAllRanges();
|
|
9071
|
+
sel.addRange(range);
|
|
9072
|
+
handleInput();
|
|
9073
|
+
};
|
|
9074
|
+
const ensureParagraphAfter = (node) => {
|
|
9075
|
+
const next = node.nextElementSibling;
|
|
9076
|
+
if (next && next.tagName === "P") return;
|
|
9077
|
+
const p = document.createElement("p");
|
|
9078
|
+
p.innerHTML = "<br>";
|
|
9079
|
+
node.after(p);
|
|
9080
|
+
};
|
|
9081
|
+
const placeCaretAtEnd = (node) => {
|
|
9082
|
+
const sel = window.getSelection();
|
|
9083
|
+
if (!sel) return;
|
|
9084
|
+
const r2 = document.createRange();
|
|
9085
|
+
r2.selectNodeContents(node);
|
|
9086
|
+
r2.collapse(false);
|
|
9087
|
+
sel.removeAllRanges();
|
|
9088
|
+
sel.addRange(r2);
|
|
9089
|
+
editorRef.current?.focus();
|
|
9090
|
+
};
|
|
9091
|
+
const clearFormat = () => {
|
|
9092
|
+
exec("removeFormat");
|
|
9093
|
+
exec("unlink");
|
|
9094
|
+
setBlock("p");
|
|
9095
|
+
};
|
|
9096
|
+
const indentList = (outdent) => {
|
|
9097
|
+
exec(outdent ? "outdent" : "indent");
|
|
9098
|
+
};
|
|
9099
|
+
const inListItem = () => {
|
|
9100
|
+
const sel = window.getSelection();
|
|
9101
|
+
const node = sel?.anchorNode;
|
|
9102
|
+
if (!node || !editorRef.current?.contains(node)) return false;
|
|
9103
|
+
const el = node.nodeType === Node.ELEMENT_NODE ? node : node.parentElement;
|
|
9104
|
+
return !!el?.closest("li");
|
|
9105
|
+
};
|
|
9106
|
+
const currentBlock = () => {
|
|
9107
|
+
const sel = window.getSelection();
|
|
9108
|
+
const node = sel?.anchorNode;
|
|
9109
|
+
const root = editorRef.current;
|
|
9110
|
+
if (!node || !root?.contains(node)) return null;
|
|
9111
|
+
let el = node.nodeType === Node.ELEMENT_NODE ? node : node.parentElement;
|
|
9112
|
+
while (el && el !== root && !/^(P|H[1-6]|LI|BLOCKQUOTE|PRE|DIV|TD|TH)$/.test(el.tagName)) {
|
|
9113
|
+
el = el.parentElement;
|
|
9114
|
+
}
|
|
9115
|
+
return el && el !== root ? el : null;
|
|
9116
|
+
};
|
|
9117
|
+
const setAlign = (align) => {
|
|
9118
|
+
const block = currentBlock();
|
|
9119
|
+
if (!block) return;
|
|
9120
|
+
pushHistory(true);
|
|
9121
|
+
block.classList.remove("align-left", "align-center", "align-right");
|
|
9122
|
+
if (align !== "left") block.classList.add(`align-${align}`);
|
|
9123
|
+
handleInput();
|
|
9124
|
+
};
|
|
9125
|
+
const toggleChecklist = () => {
|
|
9126
|
+
pushHistory(true);
|
|
9127
|
+
const block = currentBlock();
|
|
9128
|
+
const list = block?.closest("ul");
|
|
9129
|
+
if (list?.classList.contains("checklist")) {
|
|
9130
|
+
list.classList.remove("checklist");
|
|
9131
|
+
list.querySelectorAll("li").forEach((li) => li.removeAttribute("data-checked"));
|
|
9132
|
+
handleInput();
|
|
9133
|
+
return;
|
|
9134
|
+
}
|
|
9135
|
+
if (list) {
|
|
9136
|
+
list.classList.add("checklist");
|
|
9137
|
+
list.querySelectorAll("li").forEach((li) => li.setAttribute("data-checked", "false"));
|
|
9138
|
+
handleInput();
|
|
9139
|
+
return;
|
|
9140
|
+
}
|
|
9141
|
+
exec("insertUnorderedList");
|
|
9142
|
+
const made = currentBlock()?.closest("ul");
|
|
9143
|
+
if (made) {
|
|
9144
|
+
made.classList.add("checklist");
|
|
9145
|
+
made.querySelectorAll("li").forEach((li) => li.setAttribute("data-checked", "false"));
|
|
9146
|
+
}
|
|
9147
|
+
handleInput();
|
|
9148
|
+
};
|
|
9149
|
+
const handleEditorClick = (e) => {
|
|
9150
|
+
if (readOnly) return;
|
|
9151
|
+
const target = e.target;
|
|
9152
|
+
const li = target.closest?.("li");
|
|
9153
|
+
if (!li || !li.closest("ul.checklist")) return;
|
|
9154
|
+
const rect = li.getBoundingClientRect();
|
|
9155
|
+
if (e.clientX - rect.left > 20) return;
|
|
9156
|
+
e.preventDefault();
|
|
9157
|
+
pushHistory(true);
|
|
9158
|
+
li.setAttribute("data-checked", li.getAttribute("data-checked") === "true" ? "false" : "true");
|
|
9159
|
+
handleInput();
|
|
9160
|
+
};
|
|
9161
|
+
const toggleHighlight = () => {
|
|
9162
|
+
const sel = window.getSelection();
|
|
9163
|
+
if (!sel || sel.rangeCount === 0 || sel.isCollapsed) return;
|
|
9164
|
+
pushHistory(true);
|
|
9165
|
+
const range = sel.getRangeAt(0);
|
|
9166
|
+
const node = sel.anchorNode;
|
|
9167
|
+
const el = node?.nodeType === Node.ELEMENT_NODE ? node : node?.parentElement;
|
|
9168
|
+
const existing = el?.closest("mark");
|
|
9169
|
+
if (existing) {
|
|
9170
|
+
const parent = existing.parentNode;
|
|
9171
|
+
while (existing.firstChild) parent?.insertBefore(existing.firstChild, existing);
|
|
9172
|
+
parent?.removeChild(existing);
|
|
9173
|
+
handleInput();
|
|
9174
|
+
return;
|
|
9175
|
+
}
|
|
9176
|
+
const mark = document.createElement("mark");
|
|
9177
|
+
try {
|
|
9178
|
+
range.surroundContents(mark);
|
|
9179
|
+
} catch {
|
|
9180
|
+
const frag = range.extractContents();
|
|
9181
|
+
mark.appendChild(frag);
|
|
9182
|
+
range.insertNode(mark);
|
|
9183
|
+
}
|
|
9184
|
+
handleInput();
|
|
9185
|
+
};
|
|
9186
|
+
const insertTable = (cols = 3, rows = 2) => {
|
|
9187
|
+
const sel = window.getSelection();
|
|
9188
|
+
if (!sel || sel.rangeCount === 0) return;
|
|
9189
|
+
pushHistory(true);
|
|
9190
|
+
const table = document.createElement("table");
|
|
9191
|
+
const thead = document.createElement("thead");
|
|
9192
|
+
const headRow = document.createElement("tr");
|
|
9193
|
+
for (let c = 0; c < cols; c++) {
|
|
9194
|
+
const th = document.createElement("th");
|
|
9195
|
+
th.innerHTML = "<br>";
|
|
9196
|
+
headRow.appendChild(th);
|
|
9197
|
+
}
|
|
9198
|
+
thead.appendChild(headRow);
|
|
9199
|
+
table.appendChild(thead);
|
|
9200
|
+
const tbody = document.createElement("tbody");
|
|
9201
|
+
for (let r2 = 0; r2 < rows; r2++) {
|
|
9202
|
+
const tr = document.createElement("tr");
|
|
9203
|
+
for (let c = 0; c < cols; c++) {
|
|
9204
|
+
const td = document.createElement("td");
|
|
9205
|
+
td.innerHTML = "<br>";
|
|
9206
|
+
tr.appendChild(td);
|
|
9207
|
+
}
|
|
9208
|
+
tbody.appendChild(tr);
|
|
9209
|
+
}
|
|
9210
|
+
table.appendChild(tbody);
|
|
9211
|
+
const range = sel.getRangeAt(0);
|
|
9212
|
+
range.deleteContents();
|
|
9213
|
+
range.insertNode(table);
|
|
9214
|
+
ensureParagraphAfter(table);
|
|
9215
|
+
const first = table.querySelector("th");
|
|
9216
|
+
if (first) placeCaretAtEnd(first);
|
|
9217
|
+
handleInput();
|
|
9218
|
+
};
|
|
9219
|
+
const moveTableCell = (backwards) => {
|
|
9220
|
+
const block = currentBlock();
|
|
9221
|
+
const cell = block?.closest("td, th");
|
|
9222
|
+
if (!cell) return false;
|
|
9223
|
+
const table = cell.closest("table");
|
|
9224
|
+
if (!table) return false;
|
|
9225
|
+
const cells = Array.from(table.querySelectorAll("td, th"));
|
|
9226
|
+
const i = cells.indexOf(cell);
|
|
9227
|
+
const next = cells[i + (backwards ? -1 : 1)];
|
|
9228
|
+
if (next) {
|
|
9229
|
+
placeCaretAtEnd(next);
|
|
9230
|
+
return true;
|
|
9231
|
+
}
|
|
9232
|
+
if (!backwards) {
|
|
9233
|
+
pushHistory(true);
|
|
9234
|
+
const lastRow = table.querySelector("tbody")?.lastElementChild;
|
|
9235
|
+
if (lastRow) {
|
|
9236
|
+
const tr = document.createElement("tr");
|
|
9237
|
+
for (let c = 0; c < lastRow.children.length; c++) {
|
|
9238
|
+
const td = document.createElement("td");
|
|
9239
|
+
td.innerHTML = "<br>";
|
|
9240
|
+
tr.appendChild(td);
|
|
9241
|
+
}
|
|
9242
|
+
lastRow.after(tr);
|
|
9243
|
+
placeCaretAtEnd(tr.firstElementChild);
|
|
9244
|
+
handleInput();
|
|
9245
|
+
return true;
|
|
9246
|
+
}
|
|
9247
|
+
}
|
|
9248
|
+
return false;
|
|
9249
|
+
};
|
|
8549
9250
|
const insertDivider = () => {
|
|
9251
|
+
pushHistory(true);
|
|
8550
9252
|
exec("insertHorizontalRule");
|
|
8551
9253
|
const el = editorRef.current;
|
|
8552
9254
|
if (el && el.lastElementChild?.tagName === "HR") {
|
|
@@ -8592,7 +9294,9 @@ var Editor = (props) => {
|
|
|
8592
9294
|
const range = sel.getRangeAt(0);
|
|
8593
9295
|
slashStartRangeRef.current = range.cloneRange();
|
|
8594
9296
|
const rect = range.getBoundingClientRect();
|
|
8595
|
-
const
|
|
9297
|
+
const editorEl = editorRef.current;
|
|
9298
|
+
if (!editorEl) return;
|
|
9299
|
+
const editorRect = editorEl.getBoundingClientRect();
|
|
8596
9300
|
setSlashPos({
|
|
8597
9301
|
top: rect.bottom - editorRect.top + 4,
|
|
8598
9302
|
left: rect.left - editorRect.left
|
|
@@ -8607,7 +9311,7 @@ var Editor = (props) => {
|
|
|
8607
9311
|
setSlashIdx(0);
|
|
8608
9312
|
slashStartRangeRef.current = null;
|
|
8609
9313
|
};
|
|
8610
|
-
const filteredSlashItems =
|
|
9314
|
+
const filteredSlashItems = import_react22.default.useMemo(() => {
|
|
8611
9315
|
if (!slashFilter) return SLASH_ITEMS;
|
|
8612
9316
|
const f = slashFilter.toLowerCase();
|
|
8613
9317
|
return SLASH_ITEMS.filter((it) => it.label.toLowerCase().includes(f) || it.key.includes(f));
|
|
@@ -8637,8 +9341,14 @@ var Editor = (props) => {
|
|
|
8637
9341
|
case "paragraph":
|
|
8638
9342
|
setBlock("p");
|
|
8639
9343
|
break;
|
|
8640
|
-
case "heading":
|
|
8641
|
-
|
|
9344
|
+
case "heading-1":
|
|
9345
|
+
toggleBlock("h1");
|
|
9346
|
+
break;
|
|
9347
|
+
case "heading-2":
|
|
9348
|
+
toggleBlock("h2");
|
|
9349
|
+
break;
|
|
9350
|
+
case "heading-3":
|
|
9351
|
+
toggleBlock("h3");
|
|
8642
9352
|
break;
|
|
8643
9353
|
case "list":
|
|
8644
9354
|
exec("insertUnorderedList");
|
|
@@ -8650,7 +9360,7 @@ var Editor = (props) => {
|
|
|
8650
9360
|
setBlock("blockquote");
|
|
8651
9361
|
break;
|
|
8652
9362
|
case "code-block":
|
|
8653
|
-
|
|
9363
|
+
insertCodeBlock();
|
|
8654
9364
|
break;
|
|
8655
9365
|
case "divider":
|
|
8656
9366
|
insertDivider();
|
|
@@ -8668,7 +9378,9 @@ var Editor = (props) => {
|
|
|
8668
9378
|
if (!sel || sel.rangeCount === 0) return;
|
|
8669
9379
|
const range = sel.getRangeAt(0);
|
|
8670
9380
|
const rect = range.getBoundingClientRect();
|
|
8671
|
-
const
|
|
9381
|
+
const editorEl2 = editorRef.current;
|
|
9382
|
+
if (!editorEl2) return;
|
|
9383
|
+
const editorRect = editorEl2.getBoundingClientRect();
|
|
8672
9384
|
setLinkPos({
|
|
8673
9385
|
top: rect.bottom - editorRect.top + 4,
|
|
8674
9386
|
left: rect.left - editorRect.left
|
|
@@ -8701,13 +9413,13 @@ var Editor = (props) => {
|
|
|
8701
9413
|
if (node.nodeType !== Node.TEXT_NODE) return false;
|
|
8702
9414
|
const text = (node.textContent || "").slice(0, range.startOffset);
|
|
8703
9415
|
const patterns = [
|
|
8704
|
-
[
|
|
8705
|
-
[
|
|
8706
|
-
[
|
|
8707
|
-
[
|
|
8708
|
-
[
|
|
8709
|
-
[/^1
|
|
8710
|
-
[
|
|
9416
|
+
[/^###$/, () => setBlock("h3")],
|
|
9417
|
+
[/^##$/, () => setBlock("h2")],
|
|
9418
|
+
[/^#$/, () => setBlock("h1")],
|
|
9419
|
+
[/^-$/, () => exec("insertUnorderedList")],
|
|
9420
|
+
[/^\*$/, () => exec("insertUnorderedList")],
|
|
9421
|
+
[/^1\.$/, () => exec("insertOrderedList")],
|
|
9422
|
+
[/^>$/, () => setBlock("blockquote")]
|
|
8711
9423
|
];
|
|
8712
9424
|
for (const [re, fn] of patterns) {
|
|
8713
9425
|
if (re.test(text)) {
|
|
@@ -8727,7 +9439,11 @@ var Editor = (props) => {
|
|
|
8727
9439
|
if (composingRef.current) return;
|
|
8728
9440
|
const el = editorRef.current;
|
|
8729
9441
|
if (!el) return;
|
|
8730
|
-
|
|
9442
|
+
const html = el.innerHTML;
|
|
9443
|
+
lastEmittedRef.current = html;
|
|
9444
|
+
pushHistory();
|
|
9445
|
+
scheduleHighlight();
|
|
9446
|
+
onChange?.(html);
|
|
8731
9447
|
updateEmpty();
|
|
8732
9448
|
updateActiveFormats();
|
|
8733
9449
|
if (slashOpen) {
|
|
@@ -8755,6 +9471,40 @@ var Editor = (props) => {
|
|
|
8755
9471
|
};
|
|
8756
9472
|
const handleKeyDown = (e) => {
|
|
8757
9473
|
if (readOnly) return;
|
|
9474
|
+
if (composingRef.current || e.nativeEvent.isComposing || e.keyCode === 229) return;
|
|
9475
|
+
const pre = closestPre();
|
|
9476
|
+
if (pre && !slashOpen) {
|
|
9477
|
+
if (e.key === "Enter" && !e.shiftKey) {
|
|
9478
|
+
const text = pre.textContent || "";
|
|
9479
|
+
if (text.endsWith("\n\n")) {
|
|
9480
|
+
e.preventDefault();
|
|
9481
|
+
const code = pre.querySelector("code") ?? pre;
|
|
9482
|
+
code.textContent = text.replace(/\n\n$/, "");
|
|
9483
|
+
ensureParagraphAfter(pre);
|
|
9484
|
+
const next = pre.nextElementSibling;
|
|
9485
|
+
if (next) placeCaretAtEnd(next);
|
|
9486
|
+
handleInput();
|
|
9487
|
+
return;
|
|
9488
|
+
}
|
|
9489
|
+
e.preventDefault();
|
|
9490
|
+
insertTextAtCaret("\n");
|
|
9491
|
+
return;
|
|
9492
|
+
}
|
|
9493
|
+
if (e.key === "Tab") {
|
|
9494
|
+
e.preventDefault();
|
|
9495
|
+
insertTextAtCaret(" ");
|
|
9496
|
+
return;
|
|
9497
|
+
}
|
|
9498
|
+
}
|
|
9499
|
+
if (e.key === "Tab" && moveTableCell(e.shiftKey)) {
|
|
9500
|
+
e.preventDefault();
|
|
9501
|
+
return;
|
|
9502
|
+
}
|
|
9503
|
+
if (e.key === "Tab" && inListItem()) {
|
|
9504
|
+
e.preventDefault();
|
|
9505
|
+
indentList(e.shiftKey);
|
|
9506
|
+
return;
|
|
9507
|
+
}
|
|
8758
9508
|
if (slashOpen) {
|
|
8759
9509
|
if (e.key === "ArrowDown") {
|
|
8760
9510
|
e.preventDefault();
|
|
@@ -8778,6 +9528,21 @@ var Editor = (props) => {
|
|
|
8778
9528
|
return;
|
|
8779
9529
|
}
|
|
8780
9530
|
}
|
|
9531
|
+
if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === "z") {
|
|
9532
|
+
e.preventDefault();
|
|
9533
|
+
if (e.shiftKey) redo();
|
|
9534
|
+
else undo();
|
|
9535
|
+
return;
|
|
9536
|
+
}
|
|
9537
|
+
if ((e.metaKey || e.ctrlKey) && e.shiftKey && e.key.toLowerCase() === "v") {
|
|
9538
|
+
plainPasteRef.current = true;
|
|
9539
|
+
return;
|
|
9540
|
+
}
|
|
9541
|
+
if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === "y") {
|
|
9542
|
+
e.preventDefault();
|
|
9543
|
+
redo();
|
|
9544
|
+
return;
|
|
9545
|
+
}
|
|
8781
9546
|
if ((e.metaKey || e.ctrlKey) && !e.shiftKey && !e.altKey) {
|
|
8782
9547
|
const k = e.key.toLowerCase();
|
|
8783
9548
|
if (k === "b") {
|
|
@@ -8801,6 +9566,7 @@ var Editor = (props) => {
|
|
|
8801
9566
|
return;
|
|
8802
9567
|
}
|
|
8803
9568
|
}
|
|
9569
|
+
if (pre) return;
|
|
8804
9570
|
if (enableSlashCommand && e.key === "/") {
|
|
8805
9571
|
setTimeout(openSlashMenu, 0);
|
|
8806
9572
|
}
|
|
@@ -8810,11 +9576,21 @@ var Editor = (props) => {
|
|
|
8810
9576
|
}
|
|
8811
9577
|
}
|
|
8812
9578
|
};
|
|
9579
|
+
const plainPasteRef = import_react22.default.useRef(false);
|
|
8813
9580
|
const handlePaste = (e) => {
|
|
8814
9581
|
if (readOnly) return;
|
|
8815
9582
|
e.preventDefault();
|
|
8816
|
-
const html = e.clipboardData.getData("text/html");
|
|
8817
9583
|
const text = e.clipboardData.getData("text/plain");
|
|
9584
|
+
if (plainPasteRef.current) {
|
|
9585
|
+
plainPasteRef.current = false;
|
|
9586
|
+
insertTextAtCaret(text);
|
|
9587
|
+
return;
|
|
9588
|
+
}
|
|
9589
|
+
if (closestPre()) {
|
|
9590
|
+
insertTextAtCaret(text);
|
|
9591
|
+
return;
|
|
9592
|
+
}
|
|
9593
|
+
const html = e.clipboardData.getData("text/html");
|
|
8818
9594
|
const clean = html ? sanitizeHtml(html) : escapeHtml(text);
|
|
8819
9595
|
document.execCommand("insertHTML", false, clean);
|
|
8820
9596
|
handleInput();
|
|
@@ -8836,8 +9612,11 @@ var Editor = (props) => {
|
|
|
8836
9612
|
};
|
|
8837
9613
|
const handleSelectionUpdate = () => {
|
|
8838
9614
|
updateActiveFormats();
|
|
9615
|
+
const pre = closestPre();
|
|
9616
|
+
setCodeLang(pre ? langOf(pre) : "plain");
|
|
8839
9617
|
};
|
|
8840
9618
|
const onToolbarAction = (item) => {
|
|
9619
|
+
if (closestPre() && !["code-block", "undo", "redo"].includes(item)) return;
|
|
8841
9620
|
switch (item) {
|
|
8842
9621
|
case "bold":
|
|
8843
9622
|
exec("bold");
|
|
@@ -8866,8 +9645,14 @@ var Editor = (props) => {
|
|
|
8866
9645
|
handleInput();
|
|
8867
9646
|
break;
|
|
8868
9647
|
}
|
|
8869
|
-
case "heading":
|
|
8870
|
-
|
|
9648
|
+
case "heading-1":
|
|
9649
|
+
toggleBlock("h1");
|
|
9650
|
+
break;
|
|
9651
|
+
case "heading-2":
|
|
9652
|
+
toggleBlock("h2");
|
|
9653
|
+
break;
|
|
9654
|
+
case "heading-3":
|
|
9655
|
+
toggleBlock("h3");
|
|
8871
9656
|
break;
|
|
8872
9657
|
case "list":
|
|
8873
9658
|
exec("insertUnorderedList");
|
|
@@ -8879,7 +9664,7 @@ var Editor = (props) => {
|
|
|
8879
9664
|
setBlock("blockquote");
|
|
8880
9665
|
break;
|
|
8881
9666
|
case "code-block":
|
|
8882
|
-
|
|
9667
|
+
insertCodeBlock();
|
|
8883
9668
|
break;
|
|
8884
9669
|
case "link":
|
|
8885
9670
|
openLinkEditor();
|
|
@@ -8890,6 +9675,39 @@ var Editor = (props) => {
|
|
|
8890
9675
|
case "divider":
|
|
8891
9676
|
insertDivider();
|
|
8892
9677
|
break;
|
|
9678
|
+
case "checklist":
|
|
9679
|
+
toggleChecklist();
|
|
9680
|
+
break;
|
|
9681
|
+
case "align-left":
|
|
9682
|
+
setAlign("left");
|
|
9683
|
+
break;
|
|
9684
|
+
case "align-center":
|
|
9685
|
+
setAlign("center");
|
|
9686
|
+
break;
|
|
9687
|
+
case "align-right":
|
|
9688
|
+
setAlign("right");
|
|
9689
|
+
break;
|
|
9690
|
+
case "highlight":
|
|
9691
|
+
toggleHighlight();
|
|
9692
|
+
break;
|
|
9693
|
+
case "superscript":
|
|
9694
|
+
exec("superscript");
|
|
9695
|
+
break;
|
|
9696
|
+
case "subscript":
|
|
9697
|
+
exec("subscript");
|
|
9698
|
+
break;
|
|
9699
|
+
case "table":
|
|
9700
|
+
insertTable();
|
|
9701
|
+
break;
|
|
9702
|
+
case "clear-format":
|
|
9703
|
+
clearFormat();
|
|
9704
|
+
break;
|
|
9705
|
+
case "undo":
|
|
9706
|
+
undo();
|
|
9707
|
+
break;
|
|
9708
|
+
case "redo":
|
|
9709
|
+
redo();
|
|
9710
|
+
break;
|
|
8893
9711
|
}
|
|
8894
9712
|
};
|
|
8895
9713
|
return /* @__PURE__ */ (0, import_jsx_runtime323.jsxs)("div", { className: clsx_default("lib-xplat-editor", isFocused && "focused", readOnly && "readonly"), children: [
|
|
@@ -8898,7 +9716,10 @@ var Editor = (props) => {
|
|
|
8898
9716
|
{
|
|
8899
9717
|
items: toolbar,
|
|
8900
9718
|
active: activeFormats,
|
|
8901
|
-
onAction: onToolbarAction
|
|
9719
|
+
onAction: onToolbarAction,
|
|
9720
|
+
codeLang,
|
|
9721
|
+
inCodeBlock: activeFormats.has("block:pre"),
|
|
9722
|
+
onCodeLangChange: changeCodeLang
|
|
8902
9723
|
}
|
|
8903
9724
|
),
|
|
8904
9725
|
/* @__PURE__ */ (0, import_jsx_runtime323.jsxs)("div", { className: "lib-xplat-editor__content", style: { minHeight }, children: [
|
|
@@ -8909,9 +9730,14 @@ var Editor = (props) => {
|
|
|
8909
9730
|
ref: editorRef,
|
|
8910
9731
|
contentEditable: !readOnly,
|
|
8911
9732
|
suppressContentEditableWarning: true,
|
|
9733
|
+
role: "textbox",
|
|
9734
|
+
"aria-multiline": "true",
|
|
9735
|
+
"aria-readonly": readOnly || void 0,
|
|
9736
|
+
"aria-label": placeholder,
|
|
8912
9737
|
className: "lib-xplat-editor__editable",
|
|
8913
9738
|
onInput: handleInput,
|
|
8914
9739
|
onKeyDown: handleKeyDown,
|
|
9740
|
+
onClick: handleEditorClick,
|
|
8915
9741
|
onKeyUp: handleSelectionUpdate,
|
|
8916
9742
|
onMouseUp: handleSelectionUpdate,
|
|
8917
9743
|
onPaste: handlePaste,
|
|
@@ -8953,14 +9779,27 @@ var TOOLBAR_LABEL = {
|
|
|
8953
9779
|
underline: "U",
|
|
8954
9780
|
strikethrough: "S",
|
|
8955
9781
|
code: "<>",
|
|
8956
|
-
heading: "
|
|
9782
|
+
"heading-1": "H1",
|
|
9783
|
+
"heading-2": "H2",
|
|
9784
|
+
"heading-3": "H3",
|
|
8957
9785
|
list: "\u2022",
|
|
8958
9786
|
"ordered-list": "1.",
|
|
8959
9787
|
blockquote: "\u275D",
|
|
8960
9788
|
"code-block": "[ ]",
|
|
8961
9789
|
link: "\u{1F517}",
|
|
8962
9790
|
image: "\u{1F5BC}",
|
|
8963
|
-
divider: "\u2014"
|
|
9791
|
+
divider: "\u2014",
|
|
9792
|
+
checklist: "\u2611",
|
|
9793
|
+
"align-left": "\u21E4",
|
|
9794
|
+
"align-center": "\u2194",
|
|
9795
|
+
"align-right": "\u21E5",
|
|
9796
|
+
highlight: "\u{1F58D}",
|
|
9797
|
+
superscript: "x\xB2",
|
|
9798
|
+
subscript: "x\u2082",
|
|
9799
|
+
table: "\u25A6",
|
|
9800
|
+
"clear-format": "\u232B",
|
|
9801
|
+
undo: "\u21B6",
|
|
9802
|
+
redo: "\u21B7"
|
|
8964
9803
|
};
|
|
8965
9804
|
var TOOLBAR_TITLE = {
|
|
8966
9805
|
bold: "\uAD75\uAC8C (\u2318B)",
|
|
@@ -8968,39 +9807,77 @@ var TOOLBAR_TITLE = {
|
|
|
8968
9807
|
underline: "\uBC11\uC904 (\u2318U)",
|
|
8969
9808
|
strikethrough: "\uCDE8\uC18C\uC120",
|
|
8970
9809
|
code: "\uC778\uB77C\uC778 \uCF54\uB4DC",
|
|
8971
|
-
heading: "\uC81C\uBAA9",
|
|
9810
|
+
"heading-1": "\uC81C\uBAA9 1",
|
|
9811
|
+
"heading-2": "\uC81C\uBAA9 2",
|
|
9812
|
+
"heading-3": "\uC81C\uBAA9 3",
|
|
8972
9813
|
list: "\uAE00\uBA38\uB9AC \uAE30\uD638 \uBAA9\uB85D",
|
|
8973
9814
|
"ordered-list": "\uBC88\uD638 \uB9E4\uAE30\uAE30 \uBAA9\uB85D",
|
|
8974
9815
|
blockquote: "\uC778\uC6A9",
|
|
8975
9816
|
"code-block": "\uCF54\uB4DC \uBE14\uB85D",
|
|
8976
9817
|
link: "\uB9C1\uD06C (\u2318K)",
|
|
8977
9818
|
image: "\uC774\uBBF8\uC9C0",
|
|
8978
|
-
divider: "\uAD6C\uBD84\uC120"
|
|
9819
|
+
divider: "\uAD6C\uBD84\uC120",
|
|
9820
|
+
checklist: "\uCCB4\uD06C\uB9AC\uC2A4\uD2B8",
|
|
9821
|
+
"align-left": "\uC67C\uCABD \uC815\uB82C",
|
|
9822
|
+
"align-center": "\uAC00\uC6B4\uB370 \uC815\uB82C",
|
|
9823
|
+
"align-right": "\uC624\uB978\uCABD \uC815\uB82C",
|
|
9824
|
+
highlight: "\uD615\uAD11\uD39C",
|
|
9825
|
+
superscript: "\uC704 \uCCA8\uC790",
|
|
9826
|
+
subscript: "\uC544\uB798 \uCCA8\uC790",
|
|
9827
|
+
table: "\uD45C \uC0BD\uC785",
|
|
9828
|
+
"clear-format": "\uC11C\uC2DD \uC9C0\uC6B0\uAE30",
|
|
9829
|
+
undo: "\uB418\uB3CC\uB9AC\uAE30 (\u2318Z)",
|
|
9830
|
+
redo: "\uB2E4\uC2DC\uD558\uAE30 (\u2318\u21E7Z)"
|
|
8979
9831
|
};
|
|
8980
9832
|
var isActive = (item, active) => {
|
|
8981
|
-
if (item === "heading") return active.has("block:h1")
|
|
9833
|
+
if (item === "heading-1") return active.has("block:h1");
|
|
9834
|
+
if (item === "heading-2") return active.has("block:h2");
|
|
9835
|
+
if (item === "heading-3") return active.has("block:h3");
|
|
8982
9836
|
if (item === "blockquote") return active.has("block:blockquote");
|
|
8983
9837
|
if (item === "code-block") return active.has("block:pre");
|
|
9838
|
+
if (item === "align-left") return active.has("align:left");
|
|
9839
|
+
if (item === "align-center") return active.has("align:center");
|
|
9840
|
+
if (item === "align-right") return active.has("align:right");
|
|
8984
9841
|
return active.has(item);
|
|
8985
9842
|
};
|
|
8986
|
-
var EditorToolbar = ({
|
|
8987
|
-
|
|
8988
|
-
|
|
8989
|
-
|
|
8990
|
-
|
|
8991
|
-
|
|
8992
|
-
|
|
8993
|
-
|
|
8994
|
-
|
|
8995
|
-
|
|
9843
|
+
var EditorToolbar = ({
|
|
9844
|
+
items,
|
|
9845
|
+
active,
|
|
9846
|
+
onAction,
|
|
9847
|
+
codeLang,
|
|
9848
|
+
inCodeBlock,
|
|
9849
|
+
onCodeLangChange
|
|
9850
|
+
}) => {
|
|
9851
|
+
return /* @__PURE__ */ (0, import_jsx_runtime323.jsxs)("div", { className: "lib-xplat-editor__toolbar", children: [
|
|
9852
|
+
items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime323.jsx)(
|
|
9853
|
+
"button",
|
|
9854
|
+
{
|
|
9855
|
+
type: "button",
|
|
9856
|
+
className: clsx_default("lib-xplat-editor__toolbar-btn", isActive(item, active) && "active"),
|
|
9857
|
+
title: TOOLBAR_TITLE[item],
|
|
9858
|
+
onMouseDown: (e) => {
|
|
9859
|
+
e.preventDefault();
|
|
9860
|
+
onAction(item);
|
|
9861
|
+
},
|
|
9862
|
+
children: TOOLBAR_LABEL[item]
|
|
8996
9863
|
},
|
|
8997
|
-
|
|
8998
|
-
|
|
8999
|
-
|
|
9000
|
-
|
|
9864
|
+
item
|
|
9865
|
+
)),
|
|
9866
|
+
inCodeBlock && /* @__PURE__ */ (0, import_jsx_runtime323.jsx)(
|
|
9867
|
+
"select",
|
|
9868
|
+
{
|
|
9869
|
+
className: "lib-xplat-editor__lang",
|
|
9870
|
+
value: codeLang,
|
|
9871
|
+
"aria-label": "\uCF54\uB4DC \uC5B8\uC5B4",
|
|
9872
|
+
onMouseDown: (e) => e.stopPropagation(),
|
|
9873
|
+
onChange: (e) => onCodeLangChange(e.target.value),
|
|
9874
|
+
children: CODE_LANGUAGES.map((l) => /* @__PURE__ */ (0, import_jsx_runtime323.jsx)("option", { value: l.value, children: l.label }, l.value))
|
|
9875
|
+
}
|
|
9876
|
+
)
|
|
9877
|
+
] });
|
|
9001
9878
|
};
|
|
9002
9879
|
var SlashMenu = ({ position, items, activeIndex, onSelect, onClose }) => {
|
|
9003
|
-
|
|
9880
|
+
import_react22.default.useEffect(() => {
|
|
9004
9881
|
const handleClickOutside = (e) => {
|
|
9005
9882
|
const target = e.target;
|
|
9006
9883
|
const menu = document.querySelector(".lib-xplat-editor__slash-menu");
|
|
@@ -9034,8 +9911,8 @@ var SlashMenu = ({ position, items, activeIndex, onSelect, onClose }) => {
|
|
|
9034
9911
|
);
|
|
9035
9912
|
};
|
|
9036
9913
|
var LinkPopover = ({ position, value, onChange, onConfirm, onClose }) => {
|
|
9037
|
-
const inputRef =
|
|
9038
|
-
|
|
9914
|
+
const inputRef = import_react22.default.useRef(null);
|
|
9915
|
+
import_react22.default.useEffect(() => {
|
|
9039
9916
|
inputRef.current?.focus();
|
|
9040
9917
|
}, []);
|
|
9041
9918
|
return /* @__PURE__ */ (0, import_jsx_runtime323.jsxs)(
|
|
@@ -9093,7 +9970,7 @@ EmptyState.displayName = "EmptyState";
|
|
|
9093
9970
|
var EmptyState_default = EmptyState;
|
|
9094
9971
|
|
|
9095
9972
|
// src/components/FileUpload/FileUpload.tsx
|
|
9096
|
-
var
|
|
9973
|
+
var import_react23 = __toESM(require("react"), 1);
|
|
9097
9974
|
var import_jsx_runtime325 = require("react/jsx-runtime");
|
|
9098
9975
|
var FileUpload = (props) => {
|
|
9099
9976
|
const {
|
|
@@ -9105,8 +9982,8 @@ var FileUpload = (props) => {
|
|
|
9105
9982
|
description,
|
|
9106
9983
|
validations
|
|
9107
9984
|
} = props;
|
|
9108
|
-
const [isDragOver, setIsDragOver] =
|
|
9109
|
-
const inputRef =
|
|
9985
|
+
const [isDragOver, setIsDragOver] = import_react23.default.useState(false);
|
|
9986
|
+
const inputRef = import_react23.default.useRef(null);
|
|
9110
9987
|
const handleFiles = (fileList) => {
|
|
9111
9988
|
let files = Array.from(fileList);
|
|
9112
9989
|
if (maxSize) {
|
|
@@ -9168,10 +10045,10 @@ FileUpload.displayName = "FileUpload";
|
|
|
9168
10045
|
var FileUpload_default = FileUpload;
|
|
9169
10046
|
|
|
9170
10047
|
// src/components/HtmlTypeWriter/HtmlTypeWriter.tsx
|
|
9171
|
-
var
|
|
10048
|
+
var import_react25 = __toESM(require("react"), 1);
|
|
9172
10049
|
|
|
9173
10050
|
// src/components/HtmlTypeWriter/utils.ts
|
|
9174
|
-
var
|
|
10051
|
+
var import_react24 = __toESM(require("react"), 1);
|
|
9175
10052
|
var voidTags = /* @__PURE__ */ new Set([
|
|
9176
10053
|
"br",
|
|
9177
10054
|
"img",
|
|
@@ -9239,15 +10116,15 @@ var convertNodeToReactWithRange = (node, typedLen, rangeMap) => {
|
|
|
9239
10116
|
props[attr.name] = attr.value;
|
|
9240
10117
|
});
|
|
9241
10118
|
if (voidTags.has(tag)) {
|
|
9242
|
-
return
|
|
10119
|
+
return import_react24.default.createElement(tag, props);
|
|
9243
10120
|
}
|
|
9244
10121
|
const children = Array.from(element.childNodes).map((child) => convertNodeToReactWithRange(child, typedLen, rangeMap)).filter((n) => n != null);
|
|
9245
|
-
return
|
|
10122
|
+
return import_react24.default.createElement(tag, props, ...children);
|
|
9246
10123
|
};
|
|
9247
10124
|
var htmlToReactProgressive = (root, typedLen, rangeMap) => {
|
|
9248
10125
|
const nodes = Array.from(root.childNodes).map((child, idx) => {
|
|
9249
10126
|
const node = convertNodeToReactWithRange(child, typedLen, rangeMap);
|
|
9250
|
-
return node == null ? null :
|
|
10127
|
+
return node == null ? null : import_react24.default.createElement(import_react24.default.Fragment, { key: idx }, node);
|
|
9251
10128
|
}).filter(Boolean);
|
|
9252
10129
|
return nodes.length === 0 ? null : nodes;
|
|
9253
10130
|
};
|
|
@@ -9260,20 +10137,20 @@ var HtmlTypeWriter = ({
|
|
|
9260
10137
|
onDone,
|
|
9261
10138
|
onChange
|
|
9262
10139
|
}) => {
|
|
9263
|
-
const [typedLen, setTypedLen] =
|
|
9264
|
-
const doneCalledRef =
|
|
9265
|
-
const { doc, rangeMap, totalLength } =
|
|
10140
|
+
const [typedLen, setTypedLen] = import_react25.default.useState(0);
|
|
10141
|
+
const doneCalledRef = import_react25.default.useRef(false);
|
|
10142
|
+
const { doc, rangeMap, totalLength } = import_react25.default.useMemo(() => {
|
|
9266
10143
|
if (typeof window === "undefined") return { doc: null, rangeMap: /* @__PURE__ */ new Map(), totalLength: 0 };
|
|
9267
10144
|
const decoded = decodeHtmlEntities(html);
|
|
9268
10145
|
const doc2 = new DOMParser().parseFromString(decoded, "text/html");
|
|
9269
10146
|
const { rangeMap: rangeMap2, totalLength: totalLength2 } = buildRangeMap(doc2.body);
|
|
9270
10147
|
return { doc: doc2, rangeMap: rangeMap2, totalLength: totalLength2 };
|
|
9271
10148
|
}, [html]);
|
|
9272
|
-
|
|
10149
|
+
import_react25.default.useEffect(() => {
|
|
9273
10150
|
setTypedLen(0);
|
|
9274
10151
|
doneCalledRef.current = false;
|
|
9275
10152
|
}, [html]);
|
|
9276
|
-
|
|
10153
|
+
import_react25.default.useEffect(() => {
|
|
9277
10154
|
if (!totalLength) return;
|
|
9278
10155
|
if (typedLen >= totalLength) return;
|
|
9279
10156
|
const timer = window.setInterval(() => {
|
|
@@ -9281,18 +10158,18 @@ var HtmlTypeWriter = ({
|
|
|
9281
10158
|
}, duration);
|
|
9282
10159
|
return () => window.clearInterval(timer);
|
|
9283
10160
|
}, [typedLen, totalLength, duration]);
|
|
9284
|
-
|
|
10161
|
+
import_react25.default.useEffect(() => {
|
|
9285
10162
|
if (typedLen > 0 && typedLen < totalLength) {
|
|
9286
10163
|
onChange?.();
|
|
9287
10164
|
}
|
|
9288
10165
|
}, [typedLen, totalLength, onChange]);
|
|
9289
|
-
|
|
10166
|
+
import_react25.default.useEffect(() => {
|
|
9290
10167
|
if (typedLen === totalLength && totalLength > 0 && !doneCalledRef.current) {
|
|
9291
10168
|
doneCalledRef.current = true;
|
|
9292
10169
|
onDone?.();
|
|
9293
10170
|
}
|
|
9294
10171
|
}, [typedLen, totalLength, onDone]);
|
|
9295
|
-
const parsed =
|
|
10172
|
+
const parsed = import_react25.default.useMemo(
|
|
9296
10173
|
() => doc ? htmlToReactProgressive(doc.body, typedLen, rangeMap) : null,
|
|
9297
10174
|
[doc, typedLen, rangeMap]
|
|
9298
10175
|
);
|
|
@@ -9302,12 +10179,12 @@ HtmlTypeWriter.displayName = "HtmlTypeWriter";
|
|
|
9302
10179
|
var HtmlTypeWriter_default = HtmlTypeWriter;
|
|
9303
10180
|
|
|
9304
10181
|
// src/components/ImageSelector/ImageSelector.tsx
|
|
9305
|
-
var
|
|
10182
|
+
var import_react26 = __toESM(require("react"), 1);
|
|
9306
10183
|
var import_jsx_runtime327 = require("react/jsx-runtime");
|
|
9307
10184
|
var ImageSelector = (props) => {
|
|
9308
10185
|
const { value, label, onChange, validations } = props;
|
|
9309
|
-
const [previewUrl, setPreviewUrl] =
|
|
9310
|
-
|
|
10186
|
+
const [previewUrl, setPreviewUrl] = import_react26.default.useState();
|
|
10187
|
+
import_react26.default.useEffect(() => {
|
|
9311
10188
|
if (!value) {
|
|
9312
10189
|
setPreviewUrl(void 0);
|
|
9313
10190
|
return;
|
|
@@ -9316,7 +10193,7 @@ var ImageSelector = (props) => {
|
|
|
9316
10193
|
setPreviewUrl(url);
|
|
9317
10194
|
return () => URL.revokeObjectURL(url);
|
|
9318
10195
|
}, [value]);
|
|
9319
|
-
const inputRef =
|
|
10196
|
+
const inputRef = import_react26.default.useRef(null);
|
|
9320
10197
|
const handleFileChange = (e) => {
|
|
9321
10198
|
const selectedFile = e.target.files?.[0];
|
|
9322
10199
|
if (selectedFile) {
|
|
@@ -9499,17 +10376,21 @@ Pagination.displayName = "Pagination";
|
|
|
9499
10376
|
var Pagination_default = Pagination;
|
|
9500
10377
|
|
|
9501
10378
|
// src/components/PopOver/PopOver.tsx
|
|
9502
|
-
var
|
|
10379
|
+
var import_react27 = __toESM(require("react"), 1);
|
|
9503
10380
|
var import_jsx_runtime332 = require("react/jsx-runtime");
|
|
9504
10381
|
var PopOver = (props) => {
|
|
9505
10382
|
const { children, isOpen, onClose, PopOverEl } = props;
|
|
9506
|
-
const popRef =
|
|
9507
|
-
const triggerRef =
|
|
9508
|
-
const [localOpen, setLocalOpen] =
|
|
9509
|
-
const [eventTrigger, setEventTrigger] =
|
|
10383
|
+
const popRef = import_react27.default.useRef(null);
|
|
10384
|
+
const triggerRef = import_react27.default.useRef(null);
|
|
10385
|
+
const [localOpen, setLocalOpen] = import_react27.default.useState(false);
|
|
10386
|
+
const [eventTrigger, setEventTrigger] = import_react27.default.useState(false);
|
|
9510
10387
|
useClickOutside_default([popRef, triggerRef], onClose, isOpen);
|
|
10388
|
+
useEscapeKey(isOpen, () => {
|
|
10389
|
+
onClose();
|
|
10390
|
+
triggerRef.current?.focus({ preventScroll: true });
|
|
10391
|
+
});
|
|
9511
10392
|
const position = useAutoPosition_default(triggerRef, popRef, localOpen);
|
|
9512
|
-
|
|
10393
|
+
import_react27.default.useEffect(() => {
|
|
9513
10394
|
if (isOpen) {
|
|
9514
10395
|
setLocalOpen(isOpen);
|
|
9515
10396
|
setTimeout(() => {
|
|
@@ -9538,6 +10419,7 @@ var PopOver = (props) => {
|
|
|
9538
10419
|
className: clsx_default(
|
|
9539
10420
|
"lib-xplat-pop-over-content",
|
|
9540
10421
|
position.direction,
|
|
10422
|
+
position.repositioning && "repositioning",
|
|
9541
10423
|
eventTrigger && "visible"
|
|
9542
10424
|
),
|
|
9543
10425
|
ref: popRef,
|
|
@@ -9594,12 +10476,12 @@ Progress.displayName = "Progress";
|
|
|
9594
10476
|
var Progress_default = Progress;
|
|
9595
10477
|
|
|
9596
10478
|
// src/components/Radio/RadioGroupContext.tsx
|
|
9597
|
-
var
|
|
9598
|
-
var RadioGroupContext =
|
|
10479
|
+
var import_react28 = __toESM(require("react"), 1);
|
|
10480
|
+
var RadioGroupContext = import_react28.default.createContext(
|
|
9599
10481
|
null
|
|
9600
10482
|
);
|
|
9601
10483
|
var useRadioGroupContext = () => {
|
|
9602
|
-
return
|
|
10484
|
+
return import_react28.default.useContext(RadioGroupContext);
|
|
9603
10485
|
};
|
|
9604
10486
|
var RadioGroupContext_default = RadioGroupContext;
|
|
9605
10487
|
|
|
@@ -9675,19 +10557,19 @@ RadioGroup.displayName = "RadioGroup";
|
|
|
9675
10557
|
var RadioGroup_default = RadioGroup;
|
|
9676
10558
|
|
|
9677
10559
|
// src/components/Select/Select.tsx
|
|
9678
|
-
var
|
|
10560
|
+
var import_react31 = __toESM(require("react"), 1);
|
|
9679
10561
|
|
|
9680
10562
|
// src/components/Select/context.ts
|
|
9681
|
-
var
|
|
9682
|
-
var SelectContext =
|
|
10563
|
+
var import_react29 = __toESM(require("react"), 1);
|
|
10564
|
+
var SelectContext = import_react29.default.createContext(null);
|
|
9683
10565
|
var context_default = SelectContext;
|
|
9684
10566
|
|
|
9685
10567
|
// src/components/Select/SelectItem.tsx
|
|
9686
|
-
var
|
|
10568
|
+
var import_react30 = __toESM(require("react"), 1);
|
|
9687
10569
|
var import_jsx_runtime336 = require("react/jsx-runtime");
|
|
9688
10570
|
var SelectItem = (props) => {
|
|
9689
10571
|
const { children, value, onClick, disabled = false } = props;
|
|
9690
|
-
const ctx =
|
|
10572
|
+
const ctx = import_react30.default.useContext(context_default);
|
|
9691
10573
|
const handleClick = (e) => {
|
|
9692
10574
|
e.preventDefault();
|
|
9693
10575
|
e.stopPropagation();
|
|
@@ -9727,32 +10609,37 @@ var SelectRoot = (props) => {
|
|
|
9727
10609
|
onChange,
|
|
9728
10610
|
children,
|
|
9729
10611
|
disabled = false,
|
|
10612
|
+
searchable = false,
|
|
10613
|
+
searchPlaceholder = "\uAC80\uC0C9",
|
|
9730
10614
|
error = false,
|
|
9731
10615
|
validations,
|
|
10616
|
+
label,
|
|
10617
|
+
required,
|
|
9732
10618
|
size = "md"
|
|
9733
10619
|
} = props;
|
|
9734
|
-
const
|
|
9735
|
-
|
|
10620
|
+
const fieldId = import_react31.default.useId();
|
|
10621
|
+
const itemChildren = import_react31.default.Children.toArray(children).filter(
|
|
10622
|
+
(child) => import_react31.default.isValidElement(child) && child.type === SelectItem_default
|
|
9736
10623
|
);
|
|
9737
10624
|
const isControlled = valueProp !== void 0;
|
|
9738
|
-
const [isOpen, setOpen] =
|
|
9739
|
-
const [uncontrolledLabel, setUncontrolledLabel] =
|
|
9740
|
-
const [uncontrolledValue, setUncontrolledValue] =
|
|
9741
|
-
const controlledLabel =
|
|
10625
|
+
const [isOpen, setOpen] = import_react31.default.useState(false);
|
|
10626
|
+
const [uncontrolledLabel, setUncontrolledLabel] = import_react31.default.useState(null);
|
|
10627
|
+
const [uncontrolledValue, setUncontrolledValue] = import_react31.default.useState(void 0);
|
|
10628
|
+
const controlledLabel = import_react31.default.useMemo(() => {
|
|
9742
10629
|
if (!isControlled) return null;
|
|
9743
10630
|
const match = itemChildren.find((child) => child.props.value === valueProp);
|
|
9744
10631
|
return match ? match.props.children : null;
|
|
9745
10632
|
}, [isControlled, valueProp, itemChildren]);
|
|
9746
10633
|
const selectedLabel = isControlled ? controlledLabel : uncontrolledLabel;
|
|
9747
10634
|
const selectedValue = isControlled ? valueProp : uncontrolledValue;
|
|
9748
|
-
const triggerRef =
|
|
9749
|
-
const contentRef =
|
|
9750
|
-
const [mounted, setMounted] =
|
|
9751
|
-
const [visible, setVisible] =
|
|
9752
|
-
|
|
10635
|
+
const triggerRef = import_react31.default.useRef(null);
|
|
10636
|
+
const contentRef = import_react31.default.useRef(null);
|
|
10637
|
+
const [mounted, setMounted] = import_react31.default.useState(false);
|
|
10638
|
+
const [visible, setVisible] = import_react31.default.useState(false);
|
|
10639
|
+
import_react31.default.useEffect(() => {
|
|
9753
10640
|
if (disabled && isOpen) setOpen(false);
|
|
9754
10641
|
}, [disabled, isOpen]);
|
|
9755
|
-
|
|
10642
|
+
import_react31.default.useEffect(() => {
|
|
9756
10643
|
if (isOpen) {
|
|
9757
10644
|
setMounted(true);
|
|
9758
10645
|
const t2 = setTimeout(() => setVisible(true), 1);
|
|
@@ -9762,22 +10649,42 @@ var SelectRoot = (props) => {
|
|
|
9762
10649
|
const t = setTimeout(() => setMounted(false), ANIMATION_DURATION_MS3);
|
|
9763
10650
|
return () => clearTimeout(t);
|
|
9764
10651
|
}, [isOpen]);
|
|
9765
|
-
const
|
|
9766
|
-
const
|
|
9767
|
-
|
|
10652
|
+
const [query, setQuery] = import_react31.default.useState("");
|
|
10653
|
+
const textOf = (node) => {
|
|
10654
|
+
if (node === null || node === void 0 || typeof node === "boolean") return "";
|
|
10655
|
+
if (typeof node === "string" || typeof node === "number") return String(node);
|
|
10656
|
+
if (Array.isArray(node)) return node.map(textOf).join("");
|
|
10657
|
+
if (import_react31.default.isValidElement(node)) return textOf(node.props.children);
|
|
10658
|
+
return "";
|
|
10659
|
+
};
|
|
10660
|
+
const visibleItems = import_react31.default.useMemo(() => {
|
|
10661
|
+
if (!searchable || !query.trim()) return itemChildren;
|
|
10662
|
+
const q = query.trim().toLowerCase();
|
|
10663
|
+
return itemChildren.filter((c) => textOf(c.props.children).toLowerCase().includes(q));
|
|
10664
|
+
}, [searchable, query, itemChildren]);
|
|
10665
|
+
const open = import_react31.default.useCallback(() => setOpen(true), []);
|
|
10666
|
+
const close = import_react31.default.useCallback(() => {
|
|
10667
|
+
setOpen(false);
|
|
10668
|
+
setQuery("");
|
|
10669
|
+
}, []);
|
|
10670
|
+
const toggle = import_react31.default.useCallback(() => setOpen((prev) => !prev), []);
|
|
9768
10671
|
useClickOutside_default([contentRef, triggerRef], close, isOpen);
|
|
10672
|
+
useEscapeKey(isOpen, () => {
|
|
10673
|
+
close();
|
|
10674
|
+
triggerRef.current?.focus({ preventScroll: true });
|
|
10675
|
+
});
|
|
9769
10676
|
const position = useAutoPosition_default(triggerRef, contentRef, mounted);
|
|
9770
|
-
const setSelected =
|
|
9771
|
-
(
|
|
10677
|
+
const setSelected = import_react31.default.useCallback(
|
|
10678
|
+
(label2, itemValue) => {
|
|
9772
10679
|
if (!isControlled) {
|
|
9773
|
-
setUncontrolledLabel(
|
|
10680
|
+
setUncontrolledLabel(label2);
|
|
9774
10681
|
setUncontrolledValue(itemValue);
|
|
9775
10682
|
}
|
|
9776
|
-
onChange?.(itemValue,
|
|
10683
|
+
onChange?.(itemValue, label2);
|
|
9777
10684
|
},
|
|
9778
10685
|
[isControlled, onChange]
|
|
9779
10686
|
);
|
|
9780
|
-
const ctxValue =
|
|
10687
|
+
const ctxValue = import_react31.default.useMemo(
|
|
9781
10688
|
() => ({
|
|
9782
10689
|
isOpen,
|
|
9783
10690
|
mounted,
|
|
@@ -9813,6 +10720,7 @@ var SelectRoot = (props) => {
|
|
|
9813
10720
|
/* @__PURE__ */ (0, import_jsx_runtime337.jsxs)(
|
|
9814
10721
|
"div",
|
|
9815
10722
|
{
|
|
10723
|
+
id: fieldId,
|
|
9816
10724
|
ref: triggerRef,
|
|
9817
10725
|
className: clsx_default(
|
|
9818
10726
|
"select-trigger",
|
|
@@ -9855,20 +10763,33 @@ var SelectRoot = (props) => {
|
|
|
9855
10763
|
]
|
|
9856
10764
|
}
|
|
9857
10765
|
),
|
|
9858
|
-
mounted && /* @__PURE__ */ (0, import_jsx_runtime337.jsx)(Portal_default, { children: /* @__PURE__ */ (0, import_jsx_runtime337.
|
|
10766
|
+
mounted && /* @__PURE__ */ (0, import_jsx_runtime337.jsx)(Portal_default, { children: /* @__PURE__ */ (0, import_jsx_runtime337.jsxs)(
|
|
9859
10767
|
"div",
|
|
9860
10768
|
{
|
|
9861
|
-
className: clsx_default("lib-xplat-select-content", size, position.direction, stateClass),
|
|
10769
|
+
className: clsx_default("lib-xplat-select-content", size, position.direction, stateClass, position.repositioning && "repositioning"),
|
|
9862
10770
|
ref: contentRef,
|
|
9863
10771
|
style: { ...position.position, width: triggerRef.current?.offsetWidth },
|
|
9864
10772
|
role: "listbox",
|
|
9865
|
-
children:
|
|
10773
|
+
children: [
|
|
10774
|
+
searchable && /* @__PURE__ */ (0, import_jsx_runtime337.jsx)("div", { className: "select-search", children: /* @__PURE__ */ (0, import_jsx_runtime337.jsx)(
|
|
10775
|
+
"input",
|
|
10776
|
+
{
|
|
10777
|
+
type: "text",
|
|
10778
|
+
value: query,
|
|
10779
|
+
placeholder: searchPlaceholder,
|
|
10780
|
+
onChange: (e) => setQuery(e.target.value),
|
|
10781
|
+
autoFocus: true,
|
|
10782
|
+
"aria-label": searchPlaceholder
|
|
10783
|
+
}
|
|
10784
|
+
) }),
|
|
10785
|
+
/* @__PURE__ */ (0, import_jsx_runtime337.jsx)(context_default.Provider, { value: ctxValue, children: visibleItems.length > 0 ? visibleItems : /* @__PURE__ */ (0, import_jsx_runtime337.jsx)("div", { className: "select-empty", children: "\uACB0\uACFC\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4" }) })
|
|
10786
|
+
]
|
|
9866
10787
|
}
|
|
9867
10788
|
) })
|
|
9868
10789
|
]
|
|
9869
10790
|
}
|
|
9870
10791
|
) });
|
|
9871
|
-
return /* @__PURE__ */ (0, import_jsx_runtime337.jsx)(Field, { validations, children: control });
|
|
10792
|
+
return /* @__PURE__ */ (0, import_jsx_runtime337.jsx)(Field, { validations, label, required, htmlFor: fieldId, children: control });
|
|
9872
10793
|
};
|
|
9873
10794
|
SelectRoot.displayName = "Select";
|
|
9874
10795
|
var Select = Object.assign(SelectRoot, {
|
|
@@ -9948,8 +10869,44 @@ var Spinner = (props) => {
|
|
|
9948
10869
|
Spinner.displayName = "Spinner";
|
|
9949
10870
|
var Spinner_default = Spinner;
|
|
9950
10871
|
|
|
9951
|
-
// src/components/
|
|
10872
|
+
// src/components/Stat/Stat.tsx
|
|
9952
10873
|
var import_jsx_runtime340 = require("react/jsx-runtime");
|
|
10874
|
+
var ARROW = {
|
|
10875
|
+
up: "\u25B2",
|
|
10876
|
+
down: "\u25BC",
|
|
10877
|
+
flat: "\u2014"
|
|
10878
|
+
};
|
|
10879
|
+
var Stat = (props) => {
|
|
10880
|
+
const {
|
|
10881
|
+
label,
|
|
10882
|
+
value,
|
|
10883
|
+
unit,
|
|
10884
|
+
description,
|
|
10885
|
+
trend,
|
|
10886
|
+
icon,
|
|
10887
|
+
size = "md",
|
|
10888
|
+
type = "primary"
|
|
10889
|
+
} = props;
|
|
10890
|
+
const statusType = normalizeStatus(type);
|
|
10891
|
+
return /* @__PURE__ */ (0, import_jsx_runtime340.jsxs)("div", { className: clsx_default("lib-xplat-stat", size, statusType), children: [
|
|
10892
|
+
/* @__PURE__ */ (0, import_jsx_runtime340.jsx)("div", { className: "stat-label", children: label }),
|
|
10893
|
+
/* @__PURE__ */ (0, import_jsx_runtime340.jsxs)("div", { className: "stat-value-row", children: [
|
|
10894
|
+
icon && /* @__PURE__ */ (0, import_jsx_runtime340.jsx)("span", { className: "stat-icon", children: icon }),
|
|
10895
|
+
/* @__PURE__ */ (0, import_jsx_runtime340.jsx)("span", { className: "stat-value", children: value }),
|
|
10896
|
+
unit && /* @__PURE__ */ (0, import_jsx_runtime340.jsx)("span", { className: "stat-unit", children: unit }),
|
|
10897
|
+
trend && /* @__PURE__ */ (0, import_jsx_runtime340.jsxs)("span", { className: clsx_default("stat-trend", trend.direction), children: [
|
|
10898
|
+
/* @__PURE__ */ (0, import_jsx_runtime340.jsx)("span", { "aria-hidden": "true", children: ARROW[trend.direction] }),
|
|
10899
|
+
trend.value
|
|
10900
|
+
] })
|
|
10901
|
+
] }),
|
|
10902
|
+
description && /* @__PURE__ */ (0, import_jsx_runtime340.jsx)("div", { className: "stat-description", children: description })
|
|
10903
|
+
] });
|
|
10904
|
+
};
|
|
10905
|
+
Stat.displayName = "Stat";
|
|
10906
|
+
var Stat_default = Stat;
|
|
10907
|
+
|
|
10908
|
+
// src/components/Steps/Steps.tsx
|
|
10909
|
+
var import_jsx_runtime341 = require("react/jsx-runtime");
|
|
9953
10910
|
var Steps = (props) => {
|
|
9954
10911
|
const {
|
|
9955
10912
|
items,
|
|
@@ -9957,13 +10914,13 @@ var Steps = (props) => {
|
|
|
9957
10914
|
type = "primary"
|
|
9958
10915
|
} = props;
|
|
9959
10916
|
const statusType = normalizeStatus(type);
|
|
9960
|
-
return /* @__PURE__ */ (0,
|
|
10917
|
+
return /* @__PURE__ */ (0, import_jsx_runtime341.jsx)("div", { className: clsx_default("lib-xplat-steps", statusType), children: items.map((item, index) => {
|
|
9961
10918
|
const status = index < current ? "completed" : index === current ? "active" : "pending";
|
|
9962
|
-
return /* @__PURE__ */ (0,
|
|
9963
|
-
/* @__PURE__ */ (0,
|
|
9964
|
-
/* @__PURE__ */ (0,
|
|
9965
|
-
/* @__PURE__ */ (0,
|
|
9966
|
-
item.description && /* @__PURE__ */ (0,
|
|
10919
|
+
return /* @__PURE__ */ (0, import_jsx_runtime341.jsxs)("div", { className: clsx_default("step-item", status), children: [
|
|
10920
|
+
/* @__PURE__ */ (0, import_jsx_runtime341.jsx)("div", { className: "step-circle", children: status === "completed" ? /* @__PURE__ */ (0, import_jsx_runtime341.jsx)(CheckIcon_default, {}) : /* @__PURE__ */ (0, import_jsx_runtime341.jsx)("span", { children: index + 1 }) }),
|
|
10921
|
+
/* @__PURE__ */ (0, import_jsx_runtime341.jsxs)("div", { className: "step-content", children: [
|
|
10922
|
+
/* @__PURE__ */ (0, import_jsx_runtime341.jsx)("span", { className: "step-title", children: item.title }),
|
|
10923
|
+
item.description && /* @__PURE__ */ (0, import_jsx_runtime341.jsx)("span", { className: "step-description", children: item.description })
|
|
9967
10924
|
] })
|
|
9968
10925
|
] }, index);
|
|
9969
10926
|
}) });
|
|
@@ -9972,8 +10929,8 @@ Steps.displayName = "Steps";
|
|
|
9972
10929
|
var Steps_default = Steps;
|
|
9973
10930
|
|
|
9974
10931
|
// src/components/Swiper/Swiper.tsx
|
|
9975
|
-
var
|
|
9976
|
-
var
|
|
10932
|
+
var import_react32 = __toESM(require("react"), 1);
|
|
10933
|
+
var import_jsx_runtime342 = require("react/jsx-runtime");
|
|
9977
10934
|
var Swiper = (props) => {
|
|
9978
10935
|
const {
|
|
9979
10936
|
auto = false,
|
|
@@ -9997,26 +10954,26 @@ var Swiper = (props) => {
|
|
|
9997
10954
|
const maxIndex = Math.max(0, totalSlides - viewItemCount);
|
|
9998
10955
|
const useLoop = loop && canSlide;
|
|
9999
10956
|
const cloneCount = useLoop ? totalSlides : 0;
|
|
10000
|
-
const extendedItems =
|
|
10957
|
+
const extendedItems = import_react32.default.useMemo(() => {
|
|
10001
10958
|
if (!useLoop) return items;
|
|
10002
10959
|
return [...items, ...items, ...items];
|
|
10003
10960
|
}, [items, useLoop]);
|
|
10004
10961
|
const initialIdx = Math.max(0, Math.min(indexProp ?? 0, maxIndex));
|
|
10005
|
-
const [innerIndex, setInnerIndex] =
|
|
10962
|
+
const [innerIndex, setInnerIndex] = import_react32.default.useState(
|
|
10006
10963
|
useLoop ? cloneCount + initialIdx : initialIdx
|
|
10007
10964
|
);
|
|
10008
|
-
const [isDragging, setIsDragging] =
|
|
10009
|
-
const [dragOffset, setDragOffset] =
|
|
10010
|
-
const [animated, setAnimated] =
|
|
10011
|
-
const [containerWidth, setContainerWidth] =
|
|
10012
|
-
const containerRef =
|
|
10013
|
-
const startXRef =
|
|
10014
|
-
const startTimeRef =
|
|
10015
|
-
const autoplayTimerRef =
|
|
10016
|
-
const resumeTimeoutRef =
|
|
10017
|
-
const [paused, setPaused] =
|
|
10018
|
-
const initializedRef =
|
|
10019
|
-
|
|
10965
|
+
const [isDragging, setIsDragging] = import_react32.default.useState(false);
|
|
10966
|
+
const [dragOffset, setDragOffset] = import_react32.default.useState(0);
|
|
10967
|
+
const [animated, setAnimated] = import_react32.default.useState(false);
|
|
10968
|
+
const [containerWidth, setContainerWidth] = import_react32.default.useState(0);
|
|
10969
|
+
const containerRef = import_react32.default.useRef(null);
|
|
10970
|
+
const startXRef = import_react32.default.useRef(0);
|
|
10971
|
+
const startTimeRef = import_react32.default.useRef(0);
|
|
10972
|
+
const autoplayTimerRef = import_react32.default.useRef(null);
|
|
10973
|
+
const resumeTimeoutRef = import_react32.default.useRef(null);
|
|
10974
|
+
const [paused, setPaused] = import_react32.default.useState(false);
|
|
10975
|
+
const initializedRef = import_react32.default.useRef(false);
|
|
10976
|
+
import_react32.default.useEffect(() => {
|
|
10020
10977
|
const el = containerRef.current;
|
|
10021
10978
|
if (!el) return;
|
|
10022
10979
|
const ro = new ResizeObserver((entries) => {
|
|
@@ -10039,7 +10996,7 @@ var Swiper = (props) => {
|
|
|
10039
10996
|
return ((inner - cloneCount) % totalSlides + totalSlides) % totalSlides;
|
|
10040
10997
|
};
|
|
10041
10998
|
const realIndex = getRealIndex(innerIndex);
|
|
10042
|
-
const moveToInner =
|
|
10999
|
+
const moveToInner = import_react32.default.useCallback(
|
|
10043
11000
|
(idx, withAnim = true) => {
|
|
10044
11001
|
if (!useLoop) {
|
|
10045
11002
|
setAnimated(withAnim);
|
|
@@ -10067,7 +11024,7 @@ var Swiper = (props) => {
|
|
|
10067
11024
|
},
|
|
10068
11025
|
[useLoop, cloneCount, totalSlides]
|
|
10069
11026
|
);
|
|
10070
|
-
const handleTransitionEnd =
|
|
11027
|
+
const handleTransitionEnd = import_react32.default.useCallback(() => {
|
|
10071
11028
|
if (!useLoop) return;
|
|
10072
11029
|
const real = getRealIndex(innerIndex);
|
|
10073
11030
|
const canonical = cloneCount + real;
|
|
@@ -10077,7 +11034,7 @@ var Swiper = (props) => {
|
|
|
10077
11034
|
}
|
|
10078
11035
|
onChange?.(Math.min(real, maxIndex));
|
|
10079
11036
|
}, [useLoop, innerIndex, cloneCount, totalSlides, maxIndex, onChange]);
|
|
10080
|
-
const slideTo =
|
|
11037
|
+
const slideTo = import_react32.default.useCallback(
|
|
10081
11038
|
(logicalIndex) => {
|
|
10082
11039
|
if (!canSlide) return;
|
|
10083
11040
|
const clamped = useLoop ? logicalIndex : Math.max(0, Math.min(logicalIndex, maxIndex));
|
|
@@ -10087,7 +11044,7 @@ var Swiper = (props) => {
|
|
|
10087
11044
|
},
|
|
10088
11045
|
[canSlide, useLoop, cloneCount, maxIndex, onChange, moveToInner]
|
|
10089
11046
|
);
|
|
10090
|
-
const slideNext =
|
|
11047
|
+
const slideNext = import_react32.default.useCallback(() => {
|
|
10091
11048
|
if (!canSlide) return;
|
|
10092
11049
|
const nextInner = innerIndex + slideBy;
|
|
10093
11050
|
if (useLoop) {
|
|
@@ -10096,7 +11053,7 @@ var Swiper = (props) => {
|
|
|
10096
11053
|
moveToInner(Math.min(nextInner, maxIndex), true);
|
|
10097
11054
|
}
|
|
10098
11055
|
}, [canSlide, useLoop, innerIndex, slideBy, maxIndex, moveToInner]);
|
|
10099
|
-
const slidePrev =
|
|
11056
|
+
const slidePrev = import_react32.default.useCallback(() => {
|
|
10100
11057
|
if (!canSlide) return;
|
|
10101
11058
|
const prevInner = innerIndex - slideBy;
|
|
10102
11059
|
if (useLoop) {
|
|
@@ -10105,7 +11062,7 @@ var Swiper = (props) => {
|
|
|
10105
11062
|
moveToInner(Math.max(prevInner, 0), true);
|
|
10106
11063
|
}
|
|
10107
11064
|
}, [canSlide, useLoop, innerIndex, slideBy, moveToInner]);
|
|
10108
|
-
|
|
11065
|
+
import_react32.default.useEffect(() => {
|
|
10109
11066
|
if (indexProp === void 0) return;
|
|
10110
11067
|
const clamped = Math.max(0, Math.min(indexProp, maxIndex));
|
|
10111
11068
|
const target = useLoop ? cloneCount + clamped : clamped;
|
|
@@ -10113,12 +11070,12 @@ var Swiper = (props) => {
|
|
|
10113
11070
|
moveToInner(target, true);
|
|
10114
11071
|
}
|
|
10115
11072
|
}, [indexProp]);
|
|
10116
|
-
|
|
11073
|
+
import_react32.default.useImperativeHandle(swiperRef, () => ({
|
|
10117
11074
|
slidePrev,
|
|
10118
11075
|
slideNext,
|
|
10119
11076
|
slideTo
|
|
10120
11077
|
}));
|
|
10121
|
-
|
|
11078
|
+
import_react32.default.useEffect(() => {
|
|
10122
11079
|
if (!auto || !canSlide || paused) return;
|
|
10123
11080
|
autoplayTimerRef.current = setInterval(slideNext, autoplayDelay);
|
|
10124
11081
|
return () => {
|
|
@@ -10144,7 +11101,7 @@ var Swiper = (props) => {
|
|
|
10144
11101
|
resumeTimeoutRef.current = null;
|
|
10145
11102
|
}, pauseOnInteraction);
|
|
10146
11103
|
};
|
|
10147
|
-
|
|
11104
|
+
import_react32.default.useEffect(() => {
|
|
10148
11105
|
return () => {
|
|
10149
11106
|
if (resumeTimeoutRef.current) clearTimeout(resumeTimeoutRef.current);
|
|
10150
11107
|
};
|
|
@@ -10162,7 +11119,7 @@ var Swiper = (props) => {
|
|
|
10162
11119
|
startXRef.current = getClientX(e);
|
|
10163
11120
|
startTimeRef.current = Date.now();
|
|
10164
11121
|
};
|
|
10165
|
-
|
|
11122
|
+
import_react32.default.useEffect(() => {
|
|
10166
11123
|
if (!isDragging) return;
|
|
10167
11124
|
const handleMove = (e) => {
|
|
10168
11125
|
setDragOffset(getClientX(e) - startXRef.current);
|
|
@@ -10201,8 +11158,8 @@ var Swiper = (props) => {
|
|
|
10201
11158
|
}, [isDragging, dragOffset, innerIndex, useLoop, maxIndex, slideStep, moveToInner]);
|
|
10202
11159
|
const slideWidthPercent = 100 / viewItemCount;
|
|
10203
11160
|
const gapAdjust = spaceBetween * (viewItemCount - 1) / viewItemCount;
|
|
10204
|
-
const slideElements =
|
|
10205
|
-
() => extendedItems.map((item, idx) => /* @__PURE__ */ (0,
|
|
11161
|
+
const slideElements = import_react32.default.useMemo(
|
|
11162
|
+
() => extendedItems.map((item, idx) => /* @__PURE__ */ (0, import_jsx_runtime342.jsx)(
|
|
10206
11163
|
"div",
|
|
10207
11164
|
{
|
|
10208
11165
|
className: "lib-xplat-swiper__slide",
|
|
@@ -10221,15 +11178,15 @@ var Swiper = (props) => {
|
|
|
10221
11178
|
Math.floor(realIndex / slideBy),
|
|
10222
11179
|
totalSteps - 1
|
|
10223
11180
|
);
|
|
10224
|
-
return /* @__PURE__ */ (0,
|
|
10225
|
-
/* @__PURE__ */ (0,
|
|
11181
|
+
return /* @__PURE__ */ (0, import_jsx_runtime342.jsxs)("div", { className: "lib-xplat-swiper", ref: containerRef, children: [
|
|
11182
|
+
/* @__PURE__ */ (0, import_jsx_runtime342.jsx)(
|
|
10226
11183
|
"div",
|
|
10227
11184
|
{
|
|
10228
11185
|
className: "lib-xplat-swiper__viewport",
|
|
10229
11186
|
onMouseDown: handleDragStart,
|
|
10230
11187
|
onTouchStart: handleDragStart,
|
|
10231
11188
|
onDragStart: (e) => e.preventDefault(),
|
|
10232
|
-
children: /* @__PURE__ */ (0,
|
|
11189
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime342.jsx)(
|
|
10233
11190
|
"div",
|
|
10234
11191
|
{
|
|
10235
11192
|
className: clsx_default(
|
|
@@ -10247,7 +11204,7 @@ var Swiper = (props) => {
|
|
|
10247
11204
|
)
|
|
10248
11205
|
}
|
|
10249
11206
|
),
|
|
10250
|
-
showProgress && canSlide && /* @__PURE__ */ (0,
|
|
11207
|
+
showProgress && canSlide && /* @__PURE__ */ (0, import_jsx_runtime342.jsx)("div", { className: "lib-xplat-swiper__progress", children: /* @__PURE__ */ (0, import_jsx_runtime342.jsx)("div", { className: "lib-xplat-swiper__progress-track", children: /* @__PURE__ */ (0, import_jsx_runtime342.jsx)(
|
|
10251
11208
|
"span",
|
|
10252
11209
|
{
|
|
10253
11210
|
className: "lib-xplat-swiper__progress-fill",
|
|
@@ -10257,7 +11214,7 @@ var Swiper = (props) => {
|
|
|
10257
11214
|
}
|
|
10258
11215
|
}
|
|
10259
11216
|
) }) }),
|
|
10260
|
-
canSlide && /* @__PURE__ */ (0,
|
|
11217
|
+
canSlide && /* @__PURE__ */ (0, import_jsx_runtime342.jsx)("div", { className: "lib-xplat-swiper__dots", children: Array.from({ length: totalSteps }, (_, i) => /* @__PURE__ */ (0, import_jsx_runtime342.jsx)(
|
|
10261
11218
|
"button",
|
|
10262
11219
|
{
|
|
10263
11220
|
className: clsx_default(
|
|
@@ -10275,8 +11232,8 @@ Swiper.displayName = "Swiper";
|
|
|
10275
11232
|
var Swiper_default = Swiper;
|
|
10276
11233
|
|
|
10277
11234
|
// src/components/Switch/Switch.tsx
|
|
10278
|
-
var
|
|
10279
|
-
var
|
|
11235
|
+
var import_react33 = __toESM(require("react"), 1);
|
|
11236
|
+
var import_jsx_runtime343 = require("react/jsx-runtime");
|
|
10280
11237
|
var KNOB_TRANSITION_MS = 250;
|
|
10281
11238
|
var Switch = (props) => {
|
|
10282
11239
|
const {
|
|
@@ -10285,12 +11242,15 @@ var Switch = (props) => {
|
|
|
10285
11242
|
type = "primary",
|
|
10286
11243
|
disabled,
|
|
10287
11244
|
onChange,
|
|
10288
|
-
validations
|
|
11245
|
+
validations,
|
|
11246
|
+
label,
|
|
11247
|
+
required
|
|
10289
11248
|
} = props;
|
|
11249
|
+
const fieldId = import_react33.default.useId();
|
|
10290
11250
|
const statusType = normalizeStatus(type);
|
|
10291
|
-
const [isAnimating, setIsAnimating] =
|
|
10292
|
-
const timeoutRef =
|
|
10293
|
-
|
|
11251
|
+
const [isAnimating, setIsAnimating] = import_react33.default.useState(false);
|
|
11252
|
+
const timeoutRef = import_react33.default.useRef(null);
|
|
11253
|
+
import_react33.default.useEffect(() => {
|
|
10294
11254
|
return () => {
|
|
10295
11255
|
if (timeoutRef.current) clearTimeout(timeoutRef.current);
|
|
10296
11256
|
};
|
|
@@ -10305,9 +11265,10 @@ var Switch = (props) => {
|
|
|
10305
11265
|
timeoutRef.current = null;
|
|
10306
11266
|
}, KNOB_TRANSITION_MS);
|
|
10307
11267
|
};
|
|
10308
|
-
const control = /* @__PURE__ */ (0,
|
|
11268
|
+
const control = /* @__PURE__ */ (0, import_jsx_runtime343.jsx)(
|
|
10309
11269
|
"div",
|
|
10310
11270
|
{
|
|
11271
|
+
id: fieldId,
|
|
10311
11272
|
className: clsx_default(
|
|
10312
11273
|
"lib-xplat-switch",
|
|
10313
11274
|
size,
|
|
@@ -10319,26 +11280,26 @@ var Switch = (props) => {
|
|
|
10319
11280
|
onClick: handleClick,
|
|
10320
11281
|
"aria-invalid": hasError(validations) || void 0,
|
|
10321
11282
|
"aria-disabled": disabled || isAnimating,
|
|
10322
|
-
children: /* @__PURE__ */ (0,
|
|
11283
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime343.jsx)("div", { className: clsx_default("knob", value ? "checked" : void 0) })
|
|
10323
11284
|
}
|
|
10324
11285
|
);
|
|
10325
|
-
return /* @__PURE__ */ (0,
|
|
11286
|
+
return /* @__PURE__ */ (0, import_jsx_runtime343.jsx)(Field, { validations, label, required, htmlFor: fieldId, children: control });
|
|
10326
11287
|
};
|
|
10327
11288
|
Switch.displayName = "Switch";
|
|
10328
11289
|
var Switch_default = Switch;
|
|
10329
11290
|
|
|
10330
11291
|
// src/components/Table/TableContext.tsx
|
|
10331
|
-
var
|
|
10332
|
-
var TableContext =
|
|
11292
|
+
var import_react34 = __toESM(require("react"), 1);
|
|
11293
|
+
var TableContext = import_react34.default.createContext(null);
|
|
10333
11294
|
var useTableContext = () => {
|
|
10334
|
-
const ctx =
|
|
11295
|
+
const ctx = import_react34.default.useContext(TableContext);
|
|
10335
11296
|
if (!ctx) throw new Error("Table components must be used inside <Table>");
|
|
10336
11297
|
return ctx;
|
|
10337
11298
|
};
|
|
10338
11299
|
var TableContext_default = TableContext;
|
|
10339
11300
|
|
|
10340
11301
|
// src/components/Table/Table.tsx
|
|
10341
|
-
var
|
|
11302
|
+
var import_jsx_runtime344 = require("react/jsx-runtime");
|
|
10342
11303
|
var Table = (props) => {
|
|
10343
11304
|
const {
|
|
10344
11305
|
children,
|
|
@@ -10348,7 +11309,7 @@ var Table = (props) => {
|
|
|
10348
11309
|
headerSticky = false,
|
|
10349
11310
|
stickyShadow = true
|
|
10350
11311
|
} = props;
|
|
10351
|
-
return /* @__PURE__ */ (0,
|
|
11312
|
+
return /* @__PURE__ */ (0, import_jsx_runtime344.jsx)("div", { className: `lib-xplat-table-wrapper ${size}`, children: /* @__PURE__ */ (0, import_jsx_runtime344.jsx)(
|
|
10352
11313
|
TableContext_default.Provider,
|
|
10353
11314
|
{
|
|
10354
11315
|
value: {
|
|
@@ -10357,7 +11318,7 @@ var Table = (props) => {
|
|
|
10357
11318
|
headerSticky,
|
|
10358
11319
|
stickyShadow
|
|
10359
11320
|
},
|
|
10360
|
-
children: /* @__PURE__ */ (0,
|
|
11321
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime344.jsx)("table", { className: "lib-xplat-table", children })
|
|
10361
11322
|
}
|
|
10362
11323
|
) });
|
|
10363
11324
|
};
|
|
@@ -10365,41 +11326,41 @@ Table.displayName = "Table";
|
|
|
10365
11326
|
var Table_default = Table;
|
|
10366
11327
|
|
|
10367
11328
|
// src/components/Table/TableBody.tsx
|
|
10368
|
-
var
|
|
11329
|
+
var import_jsx_runtime345 = require("react/jsx-runtime");
|
|
10369
11330
|
var TableBody = (props) => {
|
|
10370
11331
|
const { children } = props;
|
|
10371
|
-
return /* @__PURE__ */ (0,
|
|
11332
|
+
return /* @__PURE__ */ (0, import_jsx_runtime345.jsx)("tbody", { children });
|
|
10372
11333
|
};
|
|
10373
11334
|
TableBody.displayName = "TableBody";
|
|
10374
11335
|
var TableBody_default = TableBody;
|
|
10375
11336
|
|
|
10376
11337
|
// src/components/Table/TableCell.tsx
|
|
10377
|
-
var
|
|
11338
|
+
var import_react37 = __toESM(require("react"), 1);
|
|
10378
11339
|
|
|
10379
11340
|
// src/components/Table/TableHeadContext.tsx
|
|
10380
|
-
var
|
|
10381
|
-
var TableHeadContext =
|
|
11341
|
+
var import_react35 = __toESM(require("react"), 1);
|
|
11342
|
+
var TableHeadContext = import_react35.default.createContext(
|
|
10382
11343
|
null
|
|
10383
11344
|
);
|
|
10384
11345
|
var useTableHeadContext = () => {
|
|
10385
|
-
const ctx =
|
|
11346
|
+
const ctx = import_react35.default.useContext(TableHeadContext);
|
|
10386
11347
|
return ctx;
|
|
10387
11348
|
};
|
|
10388
11349
|
var TableHeadContext_default = TableHeadContext;
|
|
10389
11350
|
|
|
10390
11351
|
// src/components/Table/TableRowContext.tsx
|
|
10391
|
-
var
|
|
10392
|
-
var TableRowContext =
|
|
11352
|
+
var import_react36 = __toESM(require("react"), 1);
|
|
11353
|
+
var TableRowContext = import_react36.default.createContext(null);
|
|
10393
11354
|
var useTableRowContext = () => {
|
|
10394
|
-
const ctx =
|
|
11355
|
+
const ctx = import_react36.default.useContext(TableRowContext);
|
|
10395
11356
|
if (!ctx) throw new Error("Table components must be used inside <Table>");
|
|
10396
11357
|
return ctx;
|
|
10397
11358
|
};
|
|
10398
11359
|
var TableRowContext_default = TableRowContext;
|
|
10399
11360
|
|
|
10400
11361
|
// src/components/Table/TableCell.tsx
|
|
10401
|
-
var
|
|
10402
|
-
var TableCell =
|
|
11362
|
+
var import_jsx_runtime346 = require("react/jsx-runtime");
|
|
11363
|
+
var TableCell = import_react37.default.memo((props) => {
|
|
10403
11364
|
const {
|
|
10404
11365
|
children,
|
|
10405
11366
|
align = "center",
|
|
@@ -10413,9 +11374,9 @@ var TableCell = import_react36.default.memo((props) => {
|
|
|
10413
11374
|
const { registerStickyCell, stickyCells } = useTableRowContext();
|
|
10414
11375
|
const { stickyShadow } = useTableContext();
|
|
10415
11376
|
const headContext = useTableHeadContext();
|
|
10416
|
-
const [left, setLeft] =
|
|
10417
|
-
const cellRef =
|
|
10418
|
-
const calculateLeft =
|
|
11377
|
+
const [left, setLeft] = import_react37.default.useState(0);
|
|
11378
|
+
const cellRef = import_react37.default.useRef(null);
|
|
11379
|
+
const calculateLeft = import_react37.default.useCallback(() => {
|
|
10419
11380
|
if (!cellRef.current) return 0;
|
|
10420
11381
|
let totalLeft = 0;
|
|
10421
11382
|
for (const ref of stickyCells) {
|
|
@@ -10424,7 +11385,7 @@ var TableCell = import_react36.default.memo((props) => {
|
|
|
10424
11385
|
}
|
|
10425
11386
|
return totalLeft;
|
|
10426
11387
|
}, [stickyCells]);
|
|
10427
|
-
|
|
11388
|
+
import_react37.default.useEffect(() => {
|
|
10428
11389
|
if (!isSticky || !cellRef.current) return;
|
|
10429
11390
|
registerStickyCell(cellRef);
|
|
10430
11391
|
setLeft(calculateLeft());
|
|
@@ -10443,7 +11404,7 @@ var TableCell = import_react36.default.memo((props) => {
|
|
|
10443
11404
|
const CellTag = isHeaderCell ? "th" : "td";
|
|
10444
11405
|
const isLastSticky = isSticky && stickyCells[stickyCells.length - 1] === cellRef;
|
|
10445
11406
|
const enableHover = headContext && headContext.cellHover;
|
|
10446
|
-
return /* @__PURE__ */ (0,
|
|
11407
|
+
return /* @__PURE__ */ (0, import_jsx_runtime346.jsx)(
|
|
10447
11408
|
CellTag,
|
|
10448
11409
|
{
|
|
10449
11410
|
ref: cellRef,
|
|
@@ -10470,21 +11431,21 @@ TableCell.displayName = "TableCell";
|
|
|
10470
11431
|
var TableCell_default = TableCell;
|
|
10471
11432
|
|
|
10472
11433
|
// src/components/Table/TableHead.tsx
|
|
10473
|
-
var
|
|
11434
|
+
var import_jsx_runtime347 = require("react/jsx-runtime");
|
|
10474
11435
|
var TableHead = ({
|
|
10475
11436
|
children,
|
|
10476
11437
|
cellHover = false
|
|
10477
11438
|
}) => {
|
|
10478
11439
|
const { headerSticky } = useTableContext();
|
|
10479
|
-
return /* @__PURE__ */ (0,
|
|
11440
|
+
return /* @__PURE__ */ (0, import_jsx_runtime347.jsx)(TableHeadContext_default.Provider, { value: { cellHover }, children: /* @__PURE__ */ (0, import_jsx_runtime347.jsx)("thead", { className: clsx_default(headerSticky ? "table-sticky" : null), children }) });
|
|
10480
11441
|
};
|
|
10481
11442
|
TableHead.displayName = "TableHead";
|
|
10482
11443
|
var TableHead_default = TableHead;
|
|
10483
11444
|
|
|
10484
11445
|
// src/components/Table/TableRow.tsx
|
|
10485
|
-
var
|
|
10486
|
-
var
|
|
10487
|
-
var TableRow =
|
|
11446
|
+
var import_react38 = __toESM(require("react"), 1);
|
|
11447
|
+
var import_jsx_runtime348 = require("react/jsx-runtime");
|
|
11448
|
+
var TableRow = import_react38.default.memo((props) => {
|
|
10488
11449
|
const {
|
|
10489
11450
|
children,
|
|
10490
11451
|
type = "secondary",
|
|
@@ -10493,14 +11454,14 @@ var TableRow = import_react37.default.memo((props) => {
|
|
|
10493
11454
|
onClick
|
|
10494
11455
|
} = props;
|
|
10495
11456
|
const { rowBorderUse } = useTableContext();
|
|
10496
|
-
const [stickyCells, setStickyCells] =
|
|
11457
|
+
const [stickyCells, setStickyCells] = import_react38.default.useState([]);
|
|
10497
11458
|
const registerStickyCell = (ref) => {
|
|
10498
11459
|
setStickyCells((prev) => {
|
|
10499
11460
|
if (prev.includes(ref)) return prev;
|
|
10500
11461
|
return [...prev, ref];
|
|
10501
11462
|
});
|
|
10502
11463
|
};
|
|
10503
|
-
return /* @__PURE__ */ (0,
|
|
11464
|
+
return /* @__PURE__ */ (0, import_jsx_runtime348.jsx)(TableRowContext_default.Provider, { value: { stickyCells, registerStickyCell }, children: /* @__PURE__ */ (0, import_jsx_runtime348.jsx)(
|
|
10504
11465
|
"tr",
|
|
10505
11466
|
{
|
|
10506
11467
|
className: clsx_default(
|
|
@@ -10524,7 +11485,7 @@ TableRow.displayName = "TableRow";
|
|
|
10524
11485
|
var TableRow_default = TableRow;
|
|
10525
11486
|
|
|
10526
11487
|
// src/components/Tag/Tag.tsx
|
|
10527
|
-
var
|
|
11488
|
+
var import_jsx_runtime349 = require("react/jsx-runtime");
|
|
10528
11489
|
var Tag = (props) => {
|
|
10529
11490
|
const {
|
|
10530
11491
|
children,
|
|
@@ -10536,7 +11497,7 @@ var Tag = (props) => {
|
|
|
10536
11497
|
colorIndex
|
|
10537
11498
|
} = props;
|
|
10538
11499
|
const shape = variant ?? type ?? "neutral";
|
|
10539
|
-
return /* @__PURE__ */ (0,
|
|
11500
|
+
return /* @__PURE__ */ (0, import_jsx_runtime349.jsxs)(
|
|
10540
11501
|
"span",
|
|
10541
11502
|
{
|
|
10542
11503
|
className: clsx_default(
|
|
@@ -10547,8 +11508,8 @@ var Tag = (props) => {
|
|
|
10547
11508
|
disabled && "disabled"
|
|
10548
11509
|
),
|
|
10549
11510
|
children: [
|
|
10550
|
-
/* @__PURE__ */ (0,
|
|
10551
|
-
onClose && /* @__PURE__ */ (0,
|
|
11511
|
+
/* @__PURE__ */ (0, import_jsx_runtime349.jsx)("span", { className: "tag-label", children }),
|
|
11512
|
+
onClose && /* @__PURE__ */ (0, import_jsx_runtime349.jsx)("button", { className: "tag-close", onClick: onClose, "aria-label": "\uC0AD\uC81C", disabled, children: /* @__PURE__ */ (0, import_jsx_runtime349.jsx)(XIcon_default, {}) })
|
|
10552
11513
|
]
|
|
10553
11514
|
}
|
|
10554
11515
|
);
|
|
@@ -10557,24 +11518,29 @@ Tag.displayName = "Tag";
|
|
|
10557
11518
|
var Tag_default = Tag;
|
|
10558
11519
|
|
|
10559
11520
|
// src/components/TextArea/TextArea.tsx
|
|
10560
|
-
var
|
|
10561
|
-
var
|
|
10562
|
-
var TextArea =
|
|
11521
|
+
var import_react39 = __toESM(require("react"), 1);
|
|
11522
|
+
var import_jsx_runtime350 = require("react/jsx-runtime");
|
|
11523
|
+
var TextArea = import_react39.default.forwardRef(
|
|
10563
11524
|
(props, ref) => {
|
|
10564
11525
|
const {
|
|
10565
11526
|
className,
|
|
10566
11527
|
size = "md",
|
|
10567
11528
|
validations,
|
|
11529
|
+
label,
|
|
11530
|
+
required,
|
|
10568
11531
|
resize = "vertical",
|
|
10569
11532
|
rows = 3,
|
|
10570
11533
|
disabled,
|
|
10571
11534
|
...textareaProps
|
|
10572
11535
|
} = props;
|
|
10573
|
-
const
|
|
11536
|
+
const autoId = import_react39.default.useId();
|
|
11537
|
+
const fieldId = props.id ?? autoId;
|
|
11538
|
+
const control = /* @__PURE__ */ (0, import_jsx_runtime350.jsx)("div", { className: clsx_default("lib-xplat-textarea-wrap", className), children: /* @__PURE__ */ (0, import_jsx_runtime350.jsx)(
|
|
10574
11539
|
"textarea",
|
|
10575
11540
|
{
|
|
10576
11541
|
...textareaProps,
|
|
10577
11542
|
ref,
|
|
11543
|
+
id: fieldId,
|
|
10578
11544
|
rows,
|
|
10579
11545
|
disabled,
|
|
10580
11546
|
"aria-invalid": hasError(validations) || void 0,
|
|
@@ -10582,32 +11548,166 @@ var TextArea = import_react38.default.forwardRef(
|
|
|
10582
11548
|
style: { resize }
|
|
10583
11549
|
}
|
|
10584
11550
|
) });
|
|
10585
|
-
return /* @__PURE__ */ (0,
|
|
11551
|
+
return /* @__PURE__ */ (0, import_jsx_runtime350.jsx)(Field, { validations, label, required, htmlFor: fieldId, children: control });
|
|
10586
11552
|
}
|
|
10587
11553
|
);
|
|
10588
11554
|
TextArea.displayName = "TextArea";
|
|
10589
11555
|
var TextArea_default = TextArea;
|
|
10590
11556
|
|
|
11557
|
+
// src/components/TimePicker/TimePicker.tsx
|
|
11558
|
+
var import_react40 = __toESM(require("react"), 1);
|
|
11559
|
+
var import_jsx_runtime351 = require("react/jsx-runtime");
|
|
11560
|
+
var ANIMATION_DURATION_MS4 = 200;
|
|
11561
|
+
var toMinutes = (hhmm) => {
|
|
11562
|
+
if (!hhmm) return null;
|
|
11563
|
+
const m = /^(\d{1,2}):(\d{2})$/.exec(hhmm.trim());
|
|
11564
|
+
if (!m) return null;
|
|
11565
|
+
const h = Number(m[1]);
|
|
11566
|
+
const min = Number(m[2]);
|
|
11567
|
+
if (h > 23 || min > 59) return null;
|
|
11568
|
+
return h * 60 + min;
|
|
11569
|
+
};
|
|
11570
|
+
var toHHmm = (minutes) => `${String(Math.floor(minutes / 60)).padStart(2, "0")}:${String(minutes % 60).padStart(2, "0")}`;
|
|
11571
|
+
var display = (hhmm, use12Hours) => {
|
|
11572
|
+
if (!use12Hours) return hhmm;
|
|
11573
|
+
const total = toMinutes(hhmm);
|
|
11574
|
+
if (total === null) return hhmm;
|
|
11575
|
+
const h24 = Math.floor(total / 60);
|
|
11576
|
+
const mm = String(total % 60).padStart(2, "0");
|
|
11577
|
+
const period = h24 < 12 ? "\uC624\uC804" : "\uC624\uD6C4";
|
|
11578
|
+
const h12 = h24 % 12 === 0 ? 12 : h24 % 12;
|
|
11579
|
+
return `${period} ${h12}:${mm}`;
|
|
11580
|
+
};
|
|
11581
|
+
var TimePicker = (props) => {
|
|
11582
|
+
const {
|
|
11583
|
+
value,
|
|
11584
|
+
onChange,
|
|
11585
|
+
step = 30,
|
|
11586
|
+
min,
|
|
11587
|
+
max,
|
|
11588
|
+
use12Hours = false,
|
|
11589
|
+
placeholder = "\uC2DC\uAC01 \uC120\uD0DD",
|
|
11590
|
+
disabled = false,
|
|
11591
|
+
size = "md",
|
|
11592
|
+
label,
|
|
11593
|
+
required,
|
|
11594
|
+
validations
|
|
11595
|
+
} = props;
|
|
11596
|
+
const fieldId = import_react40.default.useId();
|
|
11597
|
+
const triggerRef = import_react40.default.useRef(null);
|
|
11598
|
+
const contentRef = import_react40.default.useRef(null);
|
|
11599
|
+
const [isOpen, setOpen] = import_react40.default.useState(false);
|
|
11600
|
+
const [mounted, setMounted] = import_react40.default.useState(false);
|
|
11601
|
+
const [visible, setVisible] = import_react40.default.useState(false);
|
|
11602
|
+
const options = import_react40.default.useMemo(() => {
|
|
11603
|
+
const safeStep = step > 0 && step <= 720 ? step : 30;
|
|
11604
|
+
const lo = toMinutes(min) ?? 0;
|
|
11605
|
+
const hi = toMinutes(max) ?? 24 * 60 - 1;
|
|
11606
|
+
const out = [];
|
|
11607
|
+
for (let t = lo; t <= hi; t += safeStep) out.push(toHHmm(t));
|
|
11608
|
+
return out;
|
|
11609
|
+
}, [step, min, max]);
|
|
11610
|
+
const close = import_react40.default.useCallback(() => setOpen(false), []);
|
|
11611
|
+
useClickOutside_default([triggerRef, contentRef], close, isOpen);
|
|
11612
|
+
useEscapeKey(isOpen, () => {
|
|
11613
|
+
close();
|
|
11614
|
+
triggerRef.current?.focus({ preventScroll: true });
|
|
11615
|
+
});
|
|
11616
|
+
const position = useAutoPosition_default(triggerRef, contentRef, mounted);
|
|
11617
|
+
import_react40.default.useEffect(() => {
|
|
11618
|
+
if (disabled && isOpen) setOpen(false);
|
|
11619
|
+
}, [disabled, isOpen]);
|
|
11620
|
+
import_react40.default.useEffect(() => {
|
|
11621
|
+
if (isOpen) {
|
|
11622
|
+
setMounted(true);
|
|
11623
|
+
const t2 = setTimeout(() => setVisible(true), 1);
|
|
11624
|
+
return () => clearTimeout(t2);
|
|
11625
|
+
}
|
|
11626
|
+
setVisible(false);
|
|
11627
|
+
const t = setTimeout(() => setMounted(false), ANIMATION_DURATION_MS4);
|
|
11628
|
+
return () => clearTimeout(t);
|
|
11629
|
+
}, [isOpen]);
|
|
11630
|
+
const pick = (hhmm) => {
|
|
11631
|
+
onChange?.(hhmm);
|
|
11632
|
+
close();
|
|
11633
|
+
triggerRef.current?.focus({ preventScroll: true });
|
|
11634
|
+
};
|
|
11635
|
+
const control = /* @__PURE__ */ (0, import_jsx_runtime351.jsxs)("div", { className: clsx_default("lib-xplat-time-picker", size, disabled && "disabled"), children: [
|
|
11636
|
+
/* @__PURE__ */ (0, import_jsx_runtime351.jsx)(
|
|
11637
|
+
"div",
|
|
11638
|
+
{
|
|
11639
|
+
id: fieldId,
|
|
11640
|
+
ref: triggerRef,
|
|
11641
|
+
className: clsx_default("time-picker-trigger", hasError(validations) && "error"),
|
|
11642
|
+
role: "combobox",
|
|
11643
|
+
"aria-expanded": isOpen,
|
|
11644
|
+
"aria-haspopup": "listbox",
|
|
11645
|
+
"aria-invalid": hasError(validations) || void 0,
|
|
11646
|
+
tabIndex: disabled ? void 0 : 0,
|
|
11647
|
+
onClick: () => !disabled && setOpen((p) => !p),
|
|
11648
|
+
onKeyDown: (e) => {
|
|
11649
|
+
if (disabled) return;
|
|
11650
|
+
if (e.key === "Enter" || e.key === " " || e.key === "ArrowDown") {
|
|
11651
|
+
e.preventDefault();
|
|
11652
|
+
setOpen(true);
|
|
11653
|
+
}
|
|
11654
|
+
},
|
|
11655
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime351.jsx)("span", { className: clsx_default("time-picker-value", !value && "placeholder"), children: value ? display(value, use12Hours) : placeholder })
|
|
11656
|
+
}
|
|
11657
|
+
),
|
|
11658
|
+
mounted && /* @__PURE__ */ (0, import_jsx_runtime351.jsx)(Portal_default, { children: /* @__PURE__ */ (0, import_jsx_runtime351.jsx)(
|
|
11659
|
+
"div",
|
|
11660
|
+
{
|
|
11661
|
+
ref: contentRef,
|
|
11662
|
+
className: clsx_default("lib-xplat-time-picker-content", size, visible ? "enter" : "exit", position.repositioning && "repositioning"),
|
|
11663
|
+
style: { ...position.position, width: triggerRef.current?.offsetWidth },
|
|
11664
|
+
role: "listbox",
|
|
11665
|
+
children: options.map((t) => /* @__PURE__ */ (0, import_jsx_runtime351.jsx)(
|
|
11666
|
+
"div",
|
|
11667
|
+
{
|
|
11668
|
+
className: clsx_default("time-picker-item", t === value && "is-selected"),
|
|
11669
|
+
role: "option",
|
|
11670
|
+
"aria-selected": t === value,
|
|
11671
|
+
tabIndex: 0,
|
|
11672
|
+
onClick: () => pick(t),
|
|
11673
|
+
onKeyDown: (e) => {
|
|
11674
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
11675
|
+
e.preventDefault();
|
|
11676
|
+
pick(t);
|
|
11677
|
+
}
|
|
11678
|
+
},
|
|
11679
|
+
children: display(t, use12Hours)
|
|
11680
|
+
},
|
|
11681
|
+
t
|
|
11682
|
+
))
|
|
11683
|
+
}
|
|
11684
|
+
) })
|
|
11685
|
+
] });
|
|
11686
|
+
return /* @__PURE__ */ (0, import_jsx_runtime351.jsx)(Field, { validations, label, required, htmlFor: fieldId, children: control });
|
|
11687
|
+
};
|
|
11688
|
+
TimePicker.displayName = "TimePicker";
|
|
11689
|
+
var TimePicker_default = TimePicker;
|
|
11690
|
+
|
|
10591
11691
|
// src/components/Toast/Toast.tsx
|
|
10592
|
-
var
|
|
11692
|
+
var import_react41 = __toESM(require("react"), 1);
|
|
10593
11693
|
var import_react_dom4 = require("react-dom");
|
|
10594
|
-
var
|
|
10595
|
-
var ToastContext =
|
|
11694
|
+
var import_jsx_runtime352 = require("react/jsx-runtime");
|
|
11695
|
+
var ToastContext = import_react41.default.createContext(null);
|
|
10596
11696
|
var useToast = () => {
|
|
10597
|
-
const ctx =
|
|
11697
|
+
const ctx = import_react41.default.useContext(ToastContext);
|
|
10598
11698
|
if (!ctx) throw new Error("useToast must be used within ToastProvider");
|
|
10599
11699
|
return ctx;
|
|
10600
11700
|
};
|
|
10601
11701
|
var EXIT_DURATION = 300;
|
|
10602
11702
|
var ToastItemComponent = ({ item, isExiting, onClose }) => {
|
|
10603
|
-
const ref =
|
|
10604
|
-
const [height, setHeight] =
|
|
10605
|
-
|
|
11703
|
+
const ref = import_react41.default.useRef(null);
|
|
11704
|
+
const [height, setHeight] = import_react41.default.useState(void 0);
|
|
11705
|
+
import_react41.default.useEffect(() => {
|
|
10606
11706
|
if (ref.current && !isExiting) {
|
|
10607
11707
|
setHeight(ref.current.offsetHeight);
|
|
10608
11708
|
}
|
|
10609
11709
|
}, [isExiting]);
|
|
10610
|
-
return /* @__PURE__ */ (0,
|
|
11710
|
+
return /* @__PURE__ */ (0, import_jsx_runtime352.jsx)(
|
|
10611
11711
|
"div",
|
|
10612
11712
|
{
|
|
10613
11713
|
className: clsx_default("lib-xplat-toast-wrapper", { exit: isExiting }),
|
|
@@ -10615,15 +11715,15 @@ var ToastItemComponent = ({ item, isExiting, onClose }) => {
|
|
|
10615
11715
|
maxHeight: isExiting ? 0 : height ?? "none",
|
|
10616
11716
|
marginBottom: isExiting ? 0 : void 0
|
|
10617
11717
|
},
|
|
10618
|
-
children: /* @__PURE__ */ (0,
|
|
11718
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime352.jsxs)(
|
|
10619
11719
|
"div",
|
|
10620
11720
|
{
|
|
10621
11721
|
ref,
|
|
10622
11722
|
className: clsx_default("lib-xplat-toast", item.type, { exit: isExiting }),
|
|
10623
11723
|
role: "alert",
|
|
10624
11724
|
children: [
|
|
10625
|
-
/* @__PURE__ */ (0,
|
|
10626
|
-
/* @__PURE__ */ (0,
|
|
11725
|
+
/* @__PURE__ */ (0, import_jsx_runtime352.jsx)("span", { className: "message", children: item.message }),
|
|
11726
|
+
/* @__PURE__ */ (0, import_jsx_runtime352.jsx)("button", { className: "close-btn", onClick: onClose, "aria-label": "\uB2EB\uAE30", children: "\xD7" })
|
|
10627
11727
|
]
|
|
10628
11728
|
}
|
|
10629
11729
|
)
|
|
@@ -10634,13 +11734,13 @@ var ToastProvider = ({
|
|
|
10634
11734
|
children,
|
|
10635
11735
|
position = "top-right"
|
|
10636
11736
|
}) => {
|
|
10637
|
-
const [toasts, setToasts] =
|
|
10638
|
-
const [removing, setRemoving] =
|
|
10639
|
-
const [mounted, setMounted] =
|
|
10640
|
-
|
|
11737
|
+
const [toasts, setToasts] = import_react41.default.useState([]);
|
|
11738
|
+
const [removing, setRemoving] = import_react41.default.useState(/* @__PURE__ */ new Set());
|
|
11739
|
+
const [mounted, setMounted] = import_react41.default.useState(false);
|
|
11740
|
+
import_react41.default.useEffect(() => {
|
|
10641
11741
|
setMounted(true);
|
|
10642
11742
|
}, []);
|
|
10643
|
-
const remove =
|
|
11743
|
+
const remove = import_react41.default.useCallback((id) => {
|
|
10644
11744
|
setRemoving((prev) => new Set(prev).add(id));
|
|
10645
11745
|
setTimeout(() => {
|
|
10646
11746
|
setToasts((prev) => prev.filter((t) => t.id !== id));
|
|
@@ -10651,7 +11751,7 @@ var ToastProvider = ({
|
|
|
10651
11751
|
});
|
|
10652
11752
|
}, EXIT_DURATION);
|
|
10653
11753
|
}, []);
|
|
10654
|
-
const toast =
|
|
11754
|
+
const toast = import_react41.default.useCallback(
|
|
10655
11755
|
(type, message, duration = 3e3) => {
|
|
10656
11756
|
const id = `${Date.now()}-${Math.random()}`;
|
|
10657
11757
|
setToasts((prev) => [...prev, { id, type, message }]);
|
|
@@ -10661,10 +11761,10 @@ var ToastProvider = ({
|
|
|
10661
11761
|
},
|
|
10662
11762
|
[remove]
|
|
10663
11763
|
);
|
|
10664
|
-
return /* @__PURE__ */ (0,
|
|
11764
|
+
return /* @__PURE__ */ (0, import_jsx_runtime352.jsxs)(ToastContext.Provider, { value: { toast }, children: [
|
|
10665
11765
|
children,
|
|
10666
11766
|
mounted && (0, import_react_dom4.createPortal)(
|
|
10667
|
-
/* @__PURE__ */ (0,
|
|
11767
|
+
/* @__PURE__ */ (0, import_jsx_runtime352.jsx)("div", { className: clsx_default("lib-xplat-toast-container", position), children: toasts.map((t) => /* @__PURE__ */ (0, import_jsx_runtime352.jsx)(
|
|
10668
11768
|
ToastItemComponent,
|
|
10669
11769
|
{
|
|
10670
11770
|
item: t,
|
|
@@ -10680,8 +11780,8 @@ var ToastProvider = ({
|
|
|
10680
11780
|
ToastProvider.displayName = "ToastProvider";
|
|
10681
11781
|
|
|
10682
11782
|
// src/components/Tooltip/Tooltip.tsx
|
|
10683
|
-
var
|
|
10684
|
-
var
|
|
11783
|
+
var import_react42 = __toESM(require("react"), 1);
|
|
11784
|
+
var import_jsx_runtime353 = require("react/jsx-runtime");
|
|
10685
11785
|
var OFFSET = 12;
|
|
10686
11786
|
var GAP = 8;
|
|
10687
11787
|
var SHOW_DELAY = 300;
|
|
@@ -10696,14 +11796,14 @@ var Tooltip = (props) => {
|
|
|
10696
11796
|
disabled = false
|
|
10697
11797
|
} = props;
|
|
10698
11798
|
const shape = variant ?? type ?? "dark";
|
|
10699
|
-
const triggerRef =
|
|
10700
|
-
const tooltipRef =
|
|
10701
|
-
const [visible, setVisible] =
|
|
10702
|
-
const [pos, setPos] =
|
|
10703
|
-
const delayTimer =
|
|
10704
|
-
const rafRef =
|
|
10705
|
-
const cursor =
|
|
10706
|
-
const clamp =
|
|
11799
|
+
const triggerRef = import_react42.default.useRef(null);
|
|
11800
|
+
const tooltipRef = import_react42.default.useRef(null);
|
|
11801
|
+
const [visible, setVisible] = import_react42.default.useState(false);
|
|
11802
|
+
const [pos, setPos] = import_react42.default.useState({ left: 0, top: 0 });
|
|
11803
|
+
const delayTimer = import_react42.default.useRef(0);
|
|
11804
|
+
const rafRef = import_react42.default.useRef(0);
|
|
11805
|
+
const cursor = import_react42.default.useRef(null);
|
|
11806
|
+
const clamp = import_react42.default.useCallback((left, top, w, h) => {
|
|
10707
11807
|
const vw = window.innerWidth;
|
|
10708
11808
|
const vh = window.innerHeight;
|
|
10709
11809
|
return {
|
|
@@ -10711,7 +11811,7 @@ var Tooltip = (props) => {
|
|
|
10711
11811
|
top: Math.min(Math.max(GAP, top), Math.max(GAP, vh - h - GAP))
|
|
10712
11812
|
};
|
|
10713
11813
|
}, []);
|
|
10714
|
-
const placeAtCursor =
|
|
11814
|
+
const placeAtCursor = import_react42.default.useCallback((x, y) => {
|
|
10715
11815
|
const el = tooltipRef.current;
|
|
10716
11816
|
if (!el) return;
|
|
10717
11817
|
const w = el.offsetWidth;
|
|
@@ -10722,7 +11822,7 @@ var Tooltip = (props) => {
|
|
|
10722
11822
|
if (top < GAP) top = y + OFFSET;
|
|
10723
11823
|
setPos(clamp(left, top, w, h));
|
|
10724
11824
|
}, [clamp]);
|
|
10725
|
-
const placeAtTrigger =
|
|
11825
|
+
const placeAtTrigger = import_react42.default.useCallback(() => {
|
|
10726
11826
|
const el = tooltipRef.current;
|
|
10727
11827
|
const trigger = triggerRef.current;
|
|
10728
11828
|
if (!el || !trigger) return;
|
|
@@ -10734,19 +11834,19 @@ var Tooltip = (props) => {
|
|
|
10734
11834
|
const left = rect.left + rect.width / 2 - w / 2;
|
|
10735
11835
|
setPos(clamp(left, top, w, h));
|
|
10736
11836
|
}, [clamp]);
|
|
10737
|
-
const reposition =
|
|
11837
|
+
const reposition = import_react42.default.useCallback(() => {
|
|
10738
11838
|
if (follow && cursor.current) {
|
|
10739
11839
|
placeAtCursor(cursor.current.x, cursor.current.y);
|
|
10740
11840
|
} else {
|
|
10741
11841
|
placeAtTrigger();
|
|
10742
11842
|
}
|
|
10743
11843
|
}, [follow, placeAtCursor, placeAtTrigger]);
|
|
10744
|
-
const handleMouseEnter =
|
|
11844
|
+
const handleMouseEnter = import_react42.default.useCallback((e) => {
|
|
10745
11845
|
if (disabled) return;
|
|
10746
11846
|
cursor.current = { x: e.clientX, y: e.clientY };
|
|
10747
11847
|
delayTimer.current = window.setTimeout(() => setVisible(true), SHOW_DELAY);
|
|
10748
11848
|
}, [disabled]);
|
|
10749
|
-
const handleMouseMove =
|
|
11849
|
+
const handleMouseMove = import_react42.default.useCallback((e) => {
|
|
10750
11850
|
cursor.current = { x: e.clientX, y: e.clientY };
|
|
10751
11851
|
if (!visible || !follow) return;
|
|
10752
11852
|
cancelAnimationFrame(rafRef.current);
|
|
@@ -10754,25 +11854,25 @@ var Tooltip = (props) => {
|
|
|
10754
11854
|
if (cursor.current) placeAtCursor(cursor.current.x, cursor.current.y);
|
|
10755
11855
|
});
|
|
10756
11856
|
}, [visible, follow, placeAtCursor]);
|
|
10757
|
-
const close =
|
|
11857
|
+
const close = import_react42.default.useCallback(() => {
|
|
10758
11858
|
window.clearTimeout(delayTimer.current);
|
|
10759
11859
|
cancelAnimationFrame(rafRef.current);
|
|
10760
11860
|
setVisible(false);
|
|
10761
11861
|
}, []);
|
|
10762
|
-
const handleMouseLeave =
|
|
11862
|
+
const handleMouseLeave = import_react42.default.useCallback(() => {
|
|
10763
11863
|
cursor.current = null;
|
|
10764
11864
|
close();
|
|
10765
11865
|
}, [close]);
|
|
10766
|
-
const handleFocus =
|
|
11866
|
+
const handleFocus = import_react42.default.useCallback(() => {
|
|
10767
11867
|
if (disabled) return;
|
|
10768
11868
|
cursor.current = null;
|
|
10769
11869
|
setVisible(true);
|
|
10770
11870
|
}, [disabled]);
|
|
10771
|
-
|
|
11871
|
+
import_react42.default.useLayoutEffect(() => {
|
|
10772
11872
|
if (!visible) return;
|
|
10773
11873
|
reposition();
|
|
10774
11874
|
}, [visible, reposition]);
|
|
10775
|
-
|
|
11875
|
+
import_react42.default.useEffect(() => {
|
|
10776
11876
|
if (!visible || follow) return;
|
|
10777
11877
|
const onChange = () => placeAtTrigger();
|
|
10778
11878
|
window.addEventListener("scroll", onChange, true);
|
|
@@ -10782,12 +11882,12 @@ var Tooltip = (props) => {
|
|
|
10782
11882
|
window.removeEventListener("resize", onChange);
|
|
10783
11883
|
};
|
|
10784
11884
|
}, [visible, follow, placeAtTrigger]);
|
|
10785
|
-
|
|
11885
|
+
import_react42.default.useEffect(() => () => {
|
|
10786
11886
|
window.clearTimeout(delayTimer.current);
|
|
10787
11887
|
cancelAnimationFrame(rafRef.current);
|
|
10788
11888
|
}, []);
|
|
10789
|
-
if (!title && !description) return /* @__PURE__ */ (0,
|
|
10790
|
-
return /* @__PURE__ */ (0,
|
|
11889
|
+
if (!title && !description) return /* @__PURE__ */ (0, import_jsx_runtime353.jsx)(import_jsx_runtime353.Fragment, { children });
|
|
11890
|
+
return /* @__PURE__ */ (0, import_jsx_runtime353.jsxs)(
|
|
10791
11891
|
"div",
|
|
10792
11892
|
{
|
|
10793
11893
|
ref: triggerRef,
|
|
@@ -10800,7 +11900,7 @@ var Tooltip = (props) => {
|
|
|
10800
11900
|
onBlur: close,
|
|
10801
11901
|
children: [
|
|
10802
11902
|
children,
|
|
10803
|
-
visible && /* @__PURE__ */ (0,
|
|
11903
|
+
visible && /* @__PURE__ */ (0, import_jsx_runtime353.jsx)(Portal_default, { children: /* @__PURE__ */ (0, import_jsx_runtime353.jsxs)(
|
|
10804
11904
|
"div",
|
|
10805
11905
|
{
|
|
10806
11906
|
ref: tooltipRef,
|
|
@@ -10808,8 +11908,8 @@ var Tooltip = (props) => {
|
|
|
10808
11908
|
className: clsx_default("lib-xplat-tooltip", shape),
|
|
10809
11909
|
style: { position: "fixed", left: pos.left, top: pos.top },
|
|
10810
11910
|
children: [
|
|
10811
|
-
title && /* @__PURE__ */ (0,
|
|
10812
|
-
description && /* @__PURE__ */ (0,
|
|
11911
|
+
title && /* @__PURE__ */ (0, import_jsx_runtime353.jsx)("div", { className: "tooltip-title", children: title }),
|
|
11912
|
+
description && /* @__PURE__ */ (0, import_jsx_runtime353.jsx)("div", { className: "tooltip-desc", children: description })
|
|
10813
11913
|
]
|
|
10814
11914
|
}
|
|
10815
11915
|
) })
|
|
@@ -10821,11 +11921,11 @@ Tooltip.displayName = "Tooltip";
|
|
|
10821
11921
|
var Tooltip_default = Tooltip;
|
|
10822
11922
|
|
|
10823
11923
|
// src/components/Video/Video.tsx
|
|
10824
|
-
var
|
|
10825
|
-
var
|
|
10826
|
-
var PipIcon = () => /* @__PURE__ */ (0,
|
|
10827
|
-
/* @__PURE__ */ (0,
|
|
10828
|
-
/* @__PURE__ */ (0,
|
|
11924
|
+
var import_react43 = __toESM(require("react"), 1);
|
|
11925
|
+
var import_jsx_runtime354 = require("react/jsx-runtime");
|
|
11926
|
+
var PipIcon = () => /* @__PURE__ */ (0, import_jsx_runtime354.jsxs)("svg", { viewBox: "0 0 24 24", width: "1em", height: "1em", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [
|
|
11927
|
+
/* @__PURE__ */ (0, import_jsx_runtime354.jsx)("rect", { x: "3", y: "5", width: "18", height: "14", rx: "2" }),
|
|
11928
|
+
/* @__PURE__ */ (0, import_jsx_runtime354.jsx)("rect", { x: "12", y: "11", width: "7", height: "6", rx: "1", fill: "currentColor" })
|
|
10829
11929
|
] });
|
|
10830
11930
|
var formatTime = (sec) => {
|
|
10831
11931
|
if (!Number.isFinite(sec) || sec < 0) return "0:00";
|
|
@@ -10833,7 +11933,7 @@ var formatTime = (sec) => {
|
|
|
10833
11933
|
const s = Math.floor(sec % 60);
|
|
10834
11934
|
return `${m}:${s.toString().padStart(2, "0")}`;
|
|
10835
11935
|
};
|
|
10836
|
-
var Video =
|
|
11936
|
+
var Video = import_react43.default.forwardRef((props, ref) => {
|
|
10837
11937
|
const {
|
|
10838
11938
|
src,
|
|
10839
11939
|
poster,
|
|
@@ -10857,21 +11957,21 @@ var Video = import_react41.default.forwardRef((props, ref) => {
|
|
|
10857
11957
|
children,
|
|
10858
11958
|
...rest
|
|
10859
11959
|
} = props;
|
|
10860
|
-
const containerRef =
|
|
10861
|
-
const videoRef =
|
|
10862
|
-
const [isPlaying, setIsPlaying] =
|
|
10863
|
-
const [isLoaded, setIsLoaded] =
|
|
10864
|
-
const [currentTime, setCurrentTime] =
|
|
10865
|
-
const [duration, setDuration] =
|
|
10866
|
-
const [buffered, setBuffered] =
|
|
10867
|
-
const [volume, setVolume] =
|
|
10868
|
-
const [isMuted, setIsMuted] =
|
|
10869
|
-
const [isFullscreen, setIsFullscreen] =
|
|
10870
|
-
const [playbackRate, setPlaybackRate] =
|
|
10871
|
-
const [rateMenuOpen, setRateMenuOpen] =
|
|
10872
|
-
const [captionsOn, setCaptionsOn] =
|
|
10873
|
-
const [isPip, setIsPip] =
|
|
10874
|
-
const setRefs =
|
|
11960
|
+
const containerRef = import_react43.default.useRef(null);
|
|
11961
|
+
const videoRef = import_react43.default.useRef(null);
|
|
11962
|
+
const [isPlaying, setIsPlaying] = import_react43.default.useState(Boolean(autoPlay));
|
|
11963
|
+
const [isLoaded, setIsLoaded] = import_react43.default.useState(false);
|
|
11964
|
+
const [currentTime, setCurrentTime] = import_react43.default.useState(0);
|
|
11965
|
+
const [duration, setDuration] = import_react43.default.useState(0);
|
|
11966
|
+
const [buffered, setBuffered] = import_react43.default.useState(0);
|
|
11967
|
+
const [volume, setVolume] = import_react43.default.useState(1);
|
|
11968
|
+
const [isMuted, setIsMuted] = import_react43.default.useState(Boolean(muted));
|
|
11969
|
+
const [isFullscreen, setIsFullscreen] = import_react43.default.useState(false);
|
|
11970
|
+
const [playbackRate, setPlaybackRate] = import_react43.default.useState(1);
|
|
11971
|
+
const [rateMenuOpen, setRateMenuOpen] = import_react43.default.useState(false);
|
|
11972
|
+
const [captionsOn, setCaptionsOn] = import_react43.default.useState(false);
|
|
11973
|
+
const [isPip, setIsPip] = import_react43.default.useState(false);
|
|
11974
|
+
const setRefs = import_react43.default.useCallback(
|
|
10875
11975
|
(el) => {
|
|
10876
11976
|
videoRef.current = el;
|
|
10877
11977
|
if (typeof ref === "function") ref(el);
|
|
@@ -10879,14 +11979,14 @@ var Video = import_react41.default.forwardRef((props, ref) => {
|
|
|
10879
11979
|
},
|
|
10880
11980
|
[ref]
|
|
10881
11981
|
);
|
|
10882
|
-
|
|
11982
|
+
import_react43.default.useEffect(() => {
|
|
10883
11983
|
const onFsChange = () => {
|
|
10884
11984
|
setIsFullscreen(document.fullscreenElement === containerRef.current);
|
|
10885
11985
|
};
|
|
10886
11986
|
document.addEventListener("fullscreenchange", onFsChange);
|
|
10887
11987
|
return () => document.removeEventListener("fullscreenchange", onFsChange);
|
|
10888
11988
|
}, []);
|
|
10889
|
-
|
|
11989
|
+
import_react43.default.useEffect(() => {
|
|
10890
11990
|
const v = videoRef.current;
|
|
10891
11991
|
if (!v) return;
|
|
10892
11992
|
const onEnter = () => setIsPip(true);
|
|
@@ -11000,13 +12100,13 @@ var Video = import_react41.default.forwardRef((props, ref) => {
|
|
|
11000
12100
|
const volumePct = (isMuted ? 0 : volume) * 100;
|
|
11001
12101
|
const VolumeGlyph = isMuted || volume === 0 ? VolumeXIcon_default : volume < 0.5 ? VolumeIcon_default : Volume2Icon_default;
|
|
11002
12102
|
const pipSupported = typeof document !== "undefined" && "pictureInPictureEnabled" in document && document.pictureInPictureEnabled;
|
|
11003
|
-
return /* @__PURE__ */ (0,
|
|
12103
|
+
return /* @__PURE__ */ (0, import_jsx_runtime354.jsxs)(
|
|
11004
12104
|
"div",
|
|
11005
12105
|
{
|
|
11006
12106
|
ref: containerRef,
|
|
11007
12107
|
className: clsx_default("lib-xplat-video", showControls && "has-controls"),
|
|
11008
12108
|
children: [
|
|
11009
|
-
/* @__PURE__ */ (0,
|
|
12109
|
+
/* @__PURE__ */ (0, import_jsx_runtime354.jsx)(
|
|
11010
12110
|
"video",
|
|
11011
12111
|
{
|
|
11012
12112
|
ref: setRefs,
|
|
@@ -11027,7 +12127,7 @@ var Video = import_react41.default.forwardRef((props, ref) => {
|
|
|
11027
12127
|
children
|
|
11028
12128
|
}
|
|
11029
12129
|
),
|
|
11030
|
-
showCenterPlay && /* @__PURE__ */ (0,
|
|
12130
|
+
showCenterPlay && /* @__PURE__ */ (0, import_jsx_runtime354.jsx)(
|
|
11031
12131
|
"button",
|
|
11032
12132
|
{
|
|
11033
12133
|
type: "button",
|
|
@@ -11039,11 +12139,11 @@ var Video = import_react41.default.forwardRef((props, ref) => {
|
|
|
11039
12139
|
onClick: togglePlay,
|
|
11040
12140
|
"aria-label": isPlaying ? "\uC77C\uC2DC\uC815\uC9C0" : "\uC7AC\uC0DD",
|
|
11041
12141
|
tabIndex: -1,
|
|
11042
|
-
children: /* @__PURE__ */ (0,
|
|
12142
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime354.jsx)("span", { className: "center-play-icon", children: /* @__PURE__ */ (0, import_jsx_runtime354.jsx)(PlayCircleIcon_default, {}) })
|
|
11043
12143
|
}
|
|
11044
12144
|
),
|
|
11045
|
-
showControls && /* @__PURE__ */ (0,
|
|
11046
|
-
/* @__PURE__ */ (0,
|
|
12145
|
+
showControls && /* @__PURE__ */ (0, import_jsx_runtime354.jsxs)("div", { className: "controls", onClick: (e) => e.stopPropagation(), children: [
|
|
12146
|
+
/* @__PURE__ */ (0, import_jsx_runtime354.jsx)(
|
|
11047
12147
|
"input",
|
|
11048
12148
|
{
|
|
11049
12149
|
type: "range",
|
|
@@ -11060,29 +12160,29 @@ var Video = import_react41.default.forwardRef((props, ref) => {
|
|
|
11060
12160
|
}
|
|
11061
12161
|
}
|
|
11062
12162
|
),
|
|
11063
|
-
/* @__PURE__ */ (0,
|
|
11064
|
-
/* @__PURE__ */ (0,
|
|
12163
|
+
/* @__PURE__ */ (0, import_jsx_runtime354.jsxs)("div", { className: "controls-row", children: [
|
|
12164
|
+
/* @__PURE__ */ (0, import_jsx_runtime354.jsx)(
|
|
11065
12165
|
"button",
|
|
11066
12166
|
{
|
|
11067
12167
|
type: "button",
|
|
11068
12168
|
className: "control-btn",
|
|
11069
12169
|
onClick: togglePlay,
|
|
11070
12170
|
"aria-label": isPlaying ? "\uC77C\uC2DC\uC815\uC9C0" : "\uC7AC\uC0DD",
|
|
11071
|
-
children: isPlaying ? /* @__PURE__ */ (0,
|
|
12171
|
+
children: isPlaying ? /* @__PURE__ */ (0, import_jsx_runtime354.jsx)(PauseIcon_default, {}) : /* @__PURE__ */ (0, import_jsx_runtime354.jsx)(PlayIcon_default, {})
|
|
11072
12172
|
}
|
|
11073
12173
|
),
|
|
11074
|
-
/* @__PURE__ */ (0,
|
|
11075
|
-
/* @__PURE__ */ (0,
|
|
12174
|
+
/* @__PURE__ */ (0, import_jsx_runtime354.jsxs)("div", { className: "volume-group", children: [
|
|
12175
|
+
/* @__PURE__ */ (0, import_jsx_runtime354.jsx)(
|
|
11076
12176
|
"button",
|
|
11077
12177
|
{
|
|
11078
12178
|
type: "button",
|
|
11079
12179
|
className: "control-btn",
|
|
11080
12180
|
onClick: toggleMute,
|
|
11081
12181
|
"aria-label": isMuted ? "\uC74C\uC18C\uAC70 \uD574\uC81C" : "\uC74C\uC18C\uAC70",
|
|
11082
|
-
children: /* @__PURE__ */ (0,
|
|
12182
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime354.jsx)(VolumeGlyph, {})
|
|
11083
12183
|
}
|
|
11084
12184
|
),
|
|
11085
|
-
/* @__PURE__ */ (0,
|
|
12185
|
+
/* @__PURE__ */ (0, import_jsx_runtime354.jsx)(
|
|
11086
12186
|
"input",
|
|
11087
12187
|
{
|
|
11088
12188
|
type: "range",
|
|
@@ -11097,14 +12197,14 @@ var Video = import_react41.default.forwardRef((props, ref) => {
|
|
|
11097
12197
|
}
|
|
11098
12198
|
)
|
|
11099
12199
|
] }),
|
|
11100
|
-
/* @__PURE__ */ (0,
|
|
12200
|
+
/* @__PURE__ */ (0, import_jsx_runtime354.jsxs)("span", { className: "time", children: [
|
|
11101
12201
|
formatTime(currentTime),
|
|
11102
12202
|
" / ",
|
|
11103
12203
|
formatTime(duration)
|
|
11104
12204
|
] }),
|
|
11105
|
-
/* @__PURE__ */ (0,
|
|
11106
|
-
playbackRates && playbackRates.length > 0 && /* @__PURE__ */ (0,
|
|
11107
|
-
/* @__PURE__ */ (0,
|
|
12205
|
+
/* @__PURE__ */ (0, import_jsx_runtime354.jsx)("div", { className: "controls-spacer" }),
|
|
12206
|
+
playbackRates && playbackRates.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime354.jsxs)("div", { className: clsx_default("rate-group", rateMenuOpen && "is-open"), children: [
|
|
12207
|
+
/* @__PURE__ */ (0, import_jsx_runtime354.jsxs)(
|
|
11108
12208
|
"button",
|
|
11109
12209
|
{
|
|
11110
12210
|
type: "button",
|
|
@@ -11118,7 +12218,7 @@ var Video = import_react41.default.forwardRef((props, ref) => {
|
|
|
11118
12218
|
]
|
|
11119
12219
|
}
|
|
11120
12220
|
),
|
|
11121
|
-
rateMenuOpen && /* @__PURE__ */ (0,
|
|
12221
|
+
rateMenuOpen && /* @__PURE__ */ (0, import_jsx_runtime354.jsx)("ul", { className: "rate-menu", role: "menu", children: playbackRates.map((r2) => /* @__PURE__ */ (0, import_jsx_runtime354.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime354.jsxs)(
|
|
11122
12222
|
"button",
|
|
11123
12223
|
{
|
|
11124
12224
|
type: "button",
|
|
@@ -11132,7 +12232,7 @@ var Video = import_react41.default.forwardRef((props, ref) => {
|
|
|
11132
12232
|
}
|
|
11133
12233
|
) }, r2)) })
|
|
11134
12234
|
] }),
|
|
11135
|
-
showCaptions && /* @__PURE__ */ (0,
|
|
12235
|
+
showCaptions && /* @__PURE__ */ (0, import_jsx_runtime354.jsx)(
|
|
11136
12236
|
"button",
|
|
11137
12237
|
{
|
|
11138
12238
|
type: "button",
|
|
@@ -11140,37 +12240,37 @@ var Video = import_react41.default.forwardRef((props, ref) => {
|
|
|
11140
12240
|
onClick: toggleCaptions,
|
|
11141
12241
|
"aria-label": captionsOn ? "\uC790\uB9C9 \uB044\uAE30" : "\uC790\uB9C9 \uCF1C\uAE30",
|
|
11142
12242
|
"aria-pressed": captionsOn,
|
|
11143
|
-
children: /* @__PURE__ */ (0,
|
|
12243
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime354.jsx)(TypeIcon_default, {})
|
|
11144
12244
|
}
|
|
11145
12245
|
),
|
|
11146
|
-
showPip && pipSupported && /* @__PURE__ */ (0,
|
|
12246
|
+
showPip && pipSupported && /* @__PURE__ */ (0, import_jsx_runtime354.jsx)(
|
|
11147
12247
|
"button",
|
|
11148
12248
|
{
|
|
11149
12249
|
type: "button",
|
|
11150
12250
|
className: clsx_default("control-btn", isPip && "is-active"),
|
|
11151
12251
|
onClick: togglePip,
|
|
11152
12252
|
"aria-label": isPip ? "PIP \uC885\uB8CC" : "PIP",
|
|
11153
|
-
children: /* @__PURE__ */ (0,
|
|
12253
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime354.jsx)(PipIcon, {})
|
|
11154
12254
|
}
|
|
11155
12255
|
),
|
|
11156
|
-
showDownload && /* @__PURE__ */ (0,
|
|
12256
|
+
showDownload && /* @__PURE__ */ (0, import_jsx_runtime354.jsx)(
|
|
11157
12257
|
"a",
|
|
11158
12258
|
{
|
|
11159
12259
|
className: "control-btn",
|
|
11160
12260
|
href: src,
|
|
11161
12261
|
download: downloadFileName ?? true,
|
|
11162
12262
|
"aria-label": "\uB2E4\uC6B4\uB85C\uB4DC",
|
|
11163
|
-
children: /* @__PURE__ */ (0,
|
|
12263
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime354.jsx)(DownloadIcon_default, {})
|
|
11164
12264
|
}
|
|
11165
12265
|
),
|
|
11166
|
-
/* @__PURE__ */ (0,
|
|
12266
|
+
/* @__PURE__ */ (0, import_jsx_runtime354.jsx)(
|
|
11167
12267
|
"button",
|
|
11168
12268
|
{
|
|
11169
12269
|
type: "button",
|
|
11170
12270
|
className: "control-btn",
|
|
11171
12271
|
onClick: toggleFullscreen,
|
|
11172
12272
|
"aria-label": isFullscreen ? "\uC804\uCCB4\uD654\uBA74 \uC885\uB8CC" : "\uC804\uCCB4\uD654\uBA74",
|
|
11173
|
-
children: isFullscreen ? /* @__PURE__ */ (0,
|
|
12273
|
+
children: isFullscreen ? /* @__PURE__ */ (0, import_jsx_runtime354.jsx)(MinimizeIcon_default, {}) : /* @__PURE__ */ (0, import_jsx_runtime354.jsx)(MaximizeIcon_default, {})
|
|
11174
12274
|
}
|
|
11175
12275
|
)
|
|
11176
12276
|
] })
|
|
@@ -11183,7 +12283,7 @@ Video.displayName = "Video";
|
|
|
11183
12283
|
var Video_default = Video;
|
|
11184
12284
|
|
|
11185
12285
|
// src/layout/Grid/FullGrid/FullGrid.tsx
|
|
11186
|
-
var
|
|
12286
|
+
var import_jsx_runtime355 = require("react/jsx-runtime");
|
|
11187
12287
|
var GAP_MAP = {
|
|
11188
12288
|
none: "var(--spacing-space-none)",
|
|
11189
12289
|
xs: "var(--spacing-space-1)",
|
|
@@ -11196,13 +12296,13 @@ var GAP_MAP = {
|
|
|
11196
12296
|
var FullGrid = (props) => {
|
|
11197
12297
|
const { children, gap } = props;
|
|
11198
12298
|
const style = gap != null ? { gap: GAP_MAP[gap] } : void 0;
|
|
11199
|
-
return /* @__PURE__ */ (0,
|
|
12299
|
+
return /* @__PURE__ */ (0, import_jsx_runtime355.jsx)("div", { className: "lib-xplat-full-grid", style, children });
|
|
11200
12300
|
};
|
|
11201
12301
|
FullGrid.displayName = "FullGrid";
|
|
11202
12302
|
var FullGrid_default = FullGrid;
|
|
11203
12303
|
|
|
11204
12304
|
// src/layout/Grid/FullScreen/FullScreen.tsx
|
|
11205
|
-
var
|
|
12305
|
+
var import_jsx_runtime356 = require("react/jsx-runtime");
|
|
11206
12306
|
var GAP_MAP2 = {
|
|
11207
12307
|
none: "var(--spacing-space-none)",
|
|
11208
12308
|
xs: "var(--spacing-space-1)",
|
|
@@ -11215,13 +12315,13 @@ var GAP_MAP2 = {
|
|
|
11215
12315
|
var FullScreen = (props) => {
|
|
11216
12316
|
const { children, gap } = props;
|
|
11217
12317
|
const style = gap != null ? { gap: GAP_MAP2[gap] } : void 0;
|
|
11218
|
-
return /* @__PURE__ */ (0,
|
|
12318
|
+
return /* @__PURE__ */ (0, import_jsx_runtime356.jsx)("div", { className: "lib-xplat-full-screen", style, children });
|
|
11219
12319
|
};
|
|
11220
12320
|
FullScreen.displayName = "FullScreen";
|
|
11221
12321
|
var FullScreen_default = FullScreen;
|
|
11222
12322
|
|
|
11223
12323
|
// src/layout/Grid/Item/Item.tsx
|
|
11224
|
-
var
|
|
12324
|
+
var import_jsx_runtime357 = require("react/jsx-runtime");
|
|
11225
12325
|
var calculateSpans = (column) => {
|
|
11226
12326
|
const spans = {};
|
|
11227
12327
|
let inherited = column.default;
|
|
@@ -11238,35 +12338,35 @@ var GridItem = ({ column, children, className }) => {
|
|
|
11238
12338
|
Object.entries(spans).forEach(([key, value]) => {
|
|
11239
12339
|
style[`--column-${key}`] = value;
|
|
11240
12340
|
});
|
|
11241
|
-
return /* @__PURE__ */ (0,
|
|
12341
|
+
return /* @__PURE__ */ (0, import_jsx_runtime357.jsx)("div", { className: clsx_default("lib-xplat-grid-item", className), style, children });
|
|
11242
12342
|
};
|
|
11243
12343
|
GridItem.displayName = "GridItem";
|
|
11244
12344
|
var Item_default = GridItem;
|
|
11245
12345
|
|
|
11246
12346
|
// src/layout/Header/Header.tsx
|
|
11247
|
-
var
|
|
12347
|
+
var import_jsx_runtime358 = require("react/jsx-runtime");
|
|
11248
12348
|
var Header = ({
|
|
11249
12349
|
logo,
|
|
11250
12350
|
centerContent,
|
|
11251
12351
|
rightContent
|
|
11252
12352
|
}) => {
|
|
11253
|
-
return /* @__PURE__ */ (0,
|
|
11254
|
-
/* @__PURE__ */ (0,
|
|
11255
|
-
/* @__PURE__ */ (0,
|
|
11256
|
-
/* @__PURE__ */ (0,
|
|
12353
|
+
return /* @__PURE__ */ (0, import_jsx_runtime358.jsxs)("div", { className: "lib-xplat-layout-header", children: [
|
|
12354
|
+
/* @__PURE__ */ (0, import_jsx_runtime358.jsx)("div", { children: logo }),
|
|
12355
|
+
/* @__PURE__ */ (0, import_jsx_runtime358.jsx)("div", { children: centerContent }),
|
|
12356
|
+
/* @__PURE__ */ (0, import_jsx_runtime358.jsx)("div", { children: rightContent })
|
|
11257
12357
|
] });
|
|
11258
12358
|
};
|
|
11259
12359
|
Header.displayName = "Header";
|
|
11260
12360
|
var Header_default = Header;
|
|
11261
12361
|
|
|
11262
12362
|
// src/layout/Layout/Layout.tsx
|
|
11263
|
-
var
|
|
12363
|
+
var import_jsx_runtime359 = require("react/jsx-runtime");
|
|
11264
12364
|
var Layout = (props) => {
|
|
11265
12365
|
const { header, sideBar, children } = props;
|
|
11266
|
-
return /* @__PURE__ */ (0,
|
|
11267
|
-
sideBar && /* @__PURE__ */ (0,
|
|
11268
|
-
/* @__PURE__ */ (0,
|
|
11269
|
-
header && /* @__PURE__ */ (0,
|
|
12366
|
+
return /* @__PURE__ */ (0, import_jsx_runtime359.jsx)("div", { className: "lib-xplat-layout", children: /* @__PURE__ */ (0, import_jsx_runtime359.jsxs)("div", { className: "lib-xplat-layout-content-wrapper", children: [
|
|
12367
|
+
sideBar && /* @__PURE__ */ (0, import_jsx_runtime359.jsx)(import_jsx_runtime359.Fragment, { children: sideBar }),
|
|
12368
|
+
/* @__PURE__ */ (0, import_jsx_runtime359.jsxs)("div", { className: "lib-xplat-layout-content", children: [
|
|
12369
|
+
header && /* @__PURE__ */ (0, import_jsx_runtime359.jsx)("div", { className: "lib-xplat-layout-conent-header", children: header }),
|
|
11270
12370
|
children
|
|
11271
12371
|
] })
|
|
11272
12372
|
] }) });
|
|
@@ -11275,31 +12375,31 @@ Layout.displayName = "Layout";
|
|
|
11275
12375
|
var Layout_default = Layout;
|
|
11276
12376
|
|
|
11277
12377
|
// src/layout/SideBar/SideBar.tsx
|
|
11278
|
-
var
|
|
12378
|
+
var import_react45 = __toESM(require("react"), 1);
|
|
11279
12379
|
|
|
11280
12380
|
// src/layout/SideBar/SideBarContext.tsx
|
|
11281
|
-
var
|
|
11282
|
-
var SideBarContext =
|
|
12381
|
+
var import_react44 = __toESM(require("react"), 1);
|
|
12382
|
+
var SideBarContext = import_react44.default.createContext(null);
|
|
11283
12383
|
var useSideBarContext = () => {
|
|
11284
|
-
const ctx =
|
|
12384
|
+
const ctx = import_react44.default.useContext(SideBarContext);
|
|
11285
12385
|
if (!ctx) throw new Error("Error");
|
|
11286
12386
|
return ctx;
|
|
11287
12387
|
};
|
|
11288
12388
|
var SideBarContext_default = SideBarContext;
|
|
11289
12389
|
|
|
11290
12390
|
// src/layout/SideBar/SideBar.tsx
|
|
11291
|
-
var
|
|
12391
|
+
var import_jsx_runtime360 = require("react/jsx-runtime");
|
|
11292
12392
|
var SideBar = (props) => {
|
|
11293
12393
|
const { children, className } = props;
|
|
11294
|
-
const [isOpen, setIsOpen] =
|
|
12394
|
+
const [isOpen, setIsOpen] = import_react45.default.useState(true);
|
|
11295
12395
|
const handleSwitchSideBar = () => {
|
|
11296
12396
|
setIsOpen((prev) => !prev);
|
|
11297
12397
|
};
|
|
11298
|
-
return /* @__PURE__ */ (0,
|
|
12398
|
+
return /* @__PURE__ */ (0, import_jsx_runtime360.jsx)(
|
|
11299
12399
|
SideBarContext_default.Provider,
|
|
11300
12400
|
{
|
|
11301
12401
|
value: { isSidebarOpen: isOpen, handleSwitchSideBar },
|
|
11302
|
-
children: /* @__PURE__ */ (0,
|
|
12402
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime360.jsx)(
|
|
11303
12403
|
"div",
|
|
11304
12404
|
{
|
|
11305
12405
|
className: clsx_default(
|
|
@@ -11607,6 +12707,7 @@ var SideBar_default = SideBar;
|
|
|
11607
12707
|
Spinner,
|
|
11608
12708
|
SquareIcon,
|
|
11609
12709
|
StarIcon,
|
|
12710
|
+
Stat,
|
|
11610
12711
|
Steps,
|
|
11611
12712
|
StopCircleIcon,
|
|
11612
12713
|
SuccessIcon,
|
|
@@ -11631,6 +12732,7 @@ var SideBar_default = SideBar;
|
|
|
11631
12732
|
ThermometerIcon,
|
|
11632
12733
|
ThumbsDownIcon,
|
|
11633
12734
|
ThumbsUpIcon,
|
|
12735
|
+
TimePicker,
|
|
11634
12736
|
ToastProvider,
|
|
11635
12737
|
ToggleLeftIcon,
|
|
11636
12738
|
ToggleRightIcon,
|