@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
|
@@ -75,6 +75,7 @@ __export(components_exports, {
|
|
|
75
75
|
SingleDatePicker: () => SingleDatePicker_default,
|
|
76
76
|
Skeleton: () => Skeleton_default,
|
|
77
77
|
Spinner: () => Spinner_default,
|
|
78
|
+
Stat: () => Stat_default,
|
|
78
79
|
Steps: () => Steps_default,
|
|
79
80
|
Swiper: () => Swiper_default,
|
|
80
81
|
Switch: () => Switch_default,
|
|
@@ -86,6 +87,7 @@ __export(components_exports, {
|
|
|
86
87
|
TableRow: () => TableRow_default,
|
|
87
88
|
Tag: () => Tag_default,
|
|
88
89
|
TextArea: () => TextArea_default,
|
|
90
|
+
TimePicker: () => TimePicker_default,
|
|
89
91
|
ToastProvider: () => ToastProvider,
|
|
90
92
|
Tooltip: () => Tooltip_default,
|
|
91
93
|
Video: () => Video_default,
|
|
@@ -1631,11 +1633,16 @@ var FieldMessage = (props) => {
|
|
|
1631
1633
|
FieldMessage.displayName = "FieldMessage";
|
|
1632
1634
|
var FieldMessage_default = FieldMessage;
|
|
1633
1635
|
var Field = (props) => {
|
|
1634
|
-
const { validations, children } = props;
|
|
1635
|
-
|
|
1636
|
+
const { label, required = false, htmlFor, validations, children } = props;
|
|
1637
|
+
const hasMessages = !!validations && validations.length > 0;
|
|
1638
|
+
if (!label && !hasMessages) return /* @__PURE__ */ (0, import_jsx_runtime297.jsx)(import_jsx_runtime297.Fragment, { children });
|
|
1636
1639
|
return /* @__PURE__ */ (0, import_jsx_runtime297.jsxs)("div", { className: "lib-xplat-field", children: [
|
|
1640
|
+
label && /* @__PURE__ */ (0, import_jsx_runtime297.jsxs)("label", { className: "lib-xplat-field-label", htmlFor, children: [
|
|
1641
|
+
label,
|
|
1642
|
+
required && /* @__PURE__ */ (0, import_jsx_runtime297.jsx)("span", { className: "required", "aria-hidden": "true", children: "*" })
|
|
1643
|
+
] }),
|
|
1637
1644
|
children,
|
|
1638
|
-
/* @__PURE__ */ (0, import_jsx_runtime297.jsx)(FieldMessage, { validations })
|
|
1645
|
+
hasMessages && /* @__PURE__ */ (0, import_jsx_runtime297.jsx)(FieldMessage, { validations })
|
|
1639
1646
|
] });
|
|
1640
1647
|
};
|
|
1641
1648
|
Field.displayName = "Field";
|
|
@@ -1646,7 +1653,9 @@ var import_jsx_runtime298 = require("react/jsx-runtime");
|
|
|
1646
1653
|
var MAX_HEIGHT = 400;
|
|
1647
1654
|
var AutoResizeTextArea = import_react2.default.forwardRef(
|
|
1648
1655
|
(props, ref) => {
|
|
1649
|
-
const { value, className, onChange, disabled, bare = false, validations, ...textareaProps } = props;
|
|
1656
|
+
const { value, className, onChange, disabled, bare = false, validations, label, required, ...textareaProps } = props;
|
|
1657
|
+
const autoId = import_react2.default.useId();
|
|
1658
|
+
const fieldId = props.id ?? autoId;
|
|
1650
1659
|
const localRef = import_react2.default.useRef(null);
|
|
1651
1660
|
const setRefs = (el) => {
|
|
1652
1661
|
localRef.current = el;
|
|
@@ -1680,6 +1689,7 @@ var AutoResizeTextArea = import_react2.default.forwardRef(
|
|
|
1680
1689
|
"aria-invalid": hasError(validations) || void 0,
|
|
1681
1690
|
...textareaProps,
|
|
1682
1691
|
ref: setRefs,
|
|
1692
|
+
id: fieldId,
|
|
1683
1693
|
className,
|
|
1684
1694
|
disabled,
|
|
1685
1695
|
value,
|
|
@@ -1693,12 +1703,13 @@ var AutoResizeTextArea = import_react2.default.forwardRef(
|
|
|
1693
1703
|
"aria-invalid": hasError(validations) || void 0,
|
|
1694
1704
|
...textareaProps,
|
|
1695
1705
|
ref: setRefs,
|
|
1706
|
+
id: fieldId,
|
|
1696
1707
|
disabled,
|
|
1697
1708
|
value,
|
|
1698
1709
|
onChange: handleChange
|
|
1699
1710
|
}
|
|
1700
1711
|
) }) });
|
|
1701
|
-
return /* @__PURE__ */ (0, import_jsx_runtime298.jsx)(Field, { validations, children: control });
|
|
1712
|
+
return /* @__PURE__ */ (0, import_jsx_runtime298.jsx)(Field, { validations, label, required, htmlFor: fieldId, children: control });
|
|
1702
1713
|
}
|
|
1703
1714
|
);
|
|
1704
1715
|
AutoResizeTextArea.displayName = "AutoResizeTextArea";
|
|
@@ -2916,8 +2927,11 @@ var ChatInput = import_react7.default.forwardRef(
|
|
|
2916
2927
|
buttonType = "primary",
|
|
2917
2928
|
onSubmit,
|
|
2918
2929
|
onChange,
|
|
2919
|
-
validations
|
|
2930
|
+
validations,
|
|
2931
|
+
label,
|
|
2932
|
+
required
|
|
2920
2933
|
} = props;
|
|
2934
|
+
const fieldId = import_react7.default.useId();
|
|
2921
2935
|
const isControlled = valueProp !== void 0;
|
|
2922
2936
|
const [internalValue, setInternalValue] = import_react7.default.useState("");
|
|
2923
2937
|
const value = isControlled ? valueProp : internalValue;
|
|
@@ -2942,6 +2956,7 @@ var ChatInput = import_react7.default.forwardRef(
|
|
|
2942
2956
|
/* @__PURE__ */ (0, import_jsx_runtime308.jsx)(
|
|
2943
2957
|
AutoResizeTextArea_default,
|
|
2944
2958
|
{
|
|
2959
|
+
id: fieldId,
|
|
2945
2960
|
ref,
|
|
2946
2961
|
bare: true,
|
|
2947
2962
|
className: "chat-input-textarea",
|
|
@@ -2966,7 +2981,7 @@ var ChatInput = import_react7.default.forwardRef(
|
|
|
2966
2981
|
}
|
|
2967
2982
|
)
|
|
2968
2983
|
] });
|
|
2969
|
-
return /* @__PURE__ */ (0, import_jsx_runtime308.jsx)(Field, { validations, children: control });
|
|
2984
|
+
return /* @__PURE__ */ (0, import_jsx_runtime308.jsx)(Field, { validations, label, required, htmlFor: fieldId, children: control });
|
|
2970
2985
|
}
|
|
2971
2986
|
);
|
|
2972
2987
|
ChatInput.displayName = "ChatInput";
|
|
@@ -3037,7 +3052,7 @@ Chip.displayName = "Chip";
|
|
|
3037
3052
|
var Chip_default = Chip;
|
|
3038
3053
|
|
|
3039
3054
|
// src/components/DatePicker/InputDatePicker/index.tsx
|
|
3040
|
-
var
|
|
3055
|
+
var import_react13 = __toESM(require("react"), 1);
|
|
3041
3056
|
|
|
3042
3057
|
// src/components/Input/Input.tsx
|
|
3043
3058
|
var import_react8 = __toESM(require("react"), 1);
|
|
@@ -3135,8 +3150,12 @@ var Input = import_react8.default.forwardRef((props, ref) => {
|
|
|
3135
3150
|
suffix,
|
|
3136
3151
|
disabled,
|
|
3137
3152
|
validations,
|
|
3153
|
+
label,
|
|
3154
|
+
required,
|
|
3138
3155
|
...inputProps
|
|
3139
3156
|
} = props;
|
|
3157
|
+
const autoId = import_react8.default.useId();
|
|
3158
|
+
const fieldId = inputProps.id ?? autoId;
|
|
3140
3159
|
const localValue = formatValue(type, value);
|
|
3141
3160
|
const handleChange = (e) => {
|
|
3142
3161
|
let val = e.target.value;
|
|
@@ -3152,7 +3171,7 @@ var Input = import_react8.default.forwardRef((props, ref) => {
|
|
|
3152
3171
|
onChange(event);
|
|
3153
3172
|
}
|
|
3154
3173
|
};
|
|
3155
|
-
return /* @__PURE__ */ (0, import_jsx_runtime311.jsxs)("div", { className: clsx_default("lib-xplat-input-wrap", className), children: [
|
|
3174
|
+
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: [
|
|
3156
3175
|
/* @__PURE__ */ (0, import_jsx_runtime311.jsxs)(
|
|
3157
3176
|
"div",
|
|
3158
3177
|
{
|
|
@@ -3163,6 +3182,7 @@ var Input = import_react8.default.forwardRef((props, ref) => {
|
|
|
3163
3182
|
{
|
|
3164
3183
|
...inputProps,
|
|
3165
3184
|
ref,
|
|
3185
|
+
id: fieldId,
|
|
3166
3186
|
disabled,
|
|
3167
3187
|
type: type === "number" ? "text" : type,
|
|
3168
3188
|
value: localValue,
|
|
@@ -3175,7 +3195,7 @@ var Input = import_react8.default.forwardRef((props, ref) => {
|
|
|
3175
3195
|
}
|
|
3176
3196
|
),
|
|
3177
3197
|
/* @__PURE__ */ (0, import_jsx_runtime311.jsx)(FieldMessage_default, { validations })
|
|
3178
|
-
] });
|
|
3198
|
+
] }) });
|
|
3179
3199
|
});
|
|
3180
3200
|
Input.displayName = "Input";
|
|
3181
3201
|
var Input_default = Input;
|
|
@@ -3205,16 +3225,96 @@ PasswordInput.displayName = "PasswordInput";
|
|
|
3205
3225
|
var PasswordInput_default = PasswordInput;
|
|
3206
3226
|
|
|
3207
3227
|
// src/components/Modal/Modal.tsx
|
|
3208
|
-
var
|
|
3228
|
+
var import_react11 = __toESM(require("react"), 1);
|
|
3209
3229
|
var import_react_dom = require("react-dom");
|
|
3230
|
+
|
|
3231
|
+
// src/tokens/hooks/useOverlayKeyboard.ts
|
|
3232
|
+
var import_react10 = __toESM(require("react"), 1);
|
|
3233
|
+
var FOCUSABLE = [
|
|
3234
|
+
"a[href]",
|
|
3235
|
+
"button:not([disabled])",
|
|
3236
|
+
"input:not([disabled]):not([type='hidden'])",
|
|
3237
|
+
"select:not([disabled])",
|
|
3238
|
+
"textarea:not([disabled])",
|
|
3239
|
+
"[tabindex]:not([tabindex='-1'])"
|
|
3240
|
+
].join(",");
|
|
3241
|
+
var focusableIn = (el) => Array.from(el.querySelectorAll(FOCUSABLE)).filter(
|
|
3242
|
+
// 화면에 없는 것은 제외 (display:none 등)
|
|
3243
|
+
(n) => n.offsetWidth > 0 || n.offsetHeight > 0 || n === document.activeElement
|
|
3244
|
+
);
|
|
3245
|
+
var useEscapeKey = (enabled, onEscape) => {
|
|
3246
|
+
import_react10.default.useEffect(() => {
|
|
3247
|
+
if (!enabled) return;
|
|
3248
|
+
const onKey = (e) => {
|
|
3249
|
+
if (e.key !== "Escape") return;
|
|
3250
|
+
if (e.defaultPrevented) return;
|
|
3251
|
+
e.preventDefault();
|
|
3252
|
+
onEscape();
|
|
3253
|
+
};
|
|
3254
|
+
document.addEventListener("keydown", onKey);
|
|
3255
|
+
return () => document.removeEventListener("keydown", onKey);
|
|
3256
|
+
}, [enabled, onEscape]);
|
|
3257
|
+
};
|
|
3258
|
+
var useFocusTrap = (containerRef, enabled, options = {}) => {
|
|
3259
|
+
const { trap = false, initialFocus } = options;
|
|
3260
|
+
const restoreRef = import_react10.default.useRef(null);
|
|
3261
|
+
import_react10.default.useEffect(() => {
|
|
3262
|
+
if (!enabled) return;
|
|
3263
|
+
restoreRef.current = document.activeElement;
|
|
3264
|
+
const raf = requestAnimationFrame(() => {
|
|
3265
|
+
const el = containerRef.current;
|
|
3266
|
+
if (!el) return;
|
|
3267
|
+
const target = initialFocus?.current ?? focusableIn(el)[0] ?? el;
|
|
3268
|
+
if (!target.hasAttribute("tabindex") && !focusableIn(el).includes(target)) {
|
|
3269
|
+
target.setAttribute("tabindex", "-1");
|
|
3270
|
+
}
|
|
3271
|
+
target.focus({ preventScroll: true });
|
|
3272
|
+
});
|
|
3273
|
+
return () => {
|
|
3274
|
+
cancelAnimationFrame(raf);
|
|
3275
|
+
const prev = restoreRef.current;
|
|
3276
|
+
if (prev && document.contains(prev)) prev.focus({ preventScroll: true });
|
|
3277
|
+
};
|
|
3278
|
+
}, [enabled, containerRef, initialFocus]);
|
|
3279
|
+
import_react10.default.useEffect(() => {
|
|
3280
|
+
if (!enabled || !trap) return;
|
|
3281
|
+
const onKey = (e) => {
|
|
3282
|
+
if (e.key !== "Tab") return;
|
|
3283
|
+
const el = containerRef.current;
|
|
3284
|
+
if (!el) return;
|
|
3285
|
+
const items = focusableIn(el);
|
|
3286
|
+
if (items.length === 0) {
|
|
3287
|
+
e.preventDefault();
|
|
3288
|
+
return;
|
|
3289
|
+
}
|
|
3290
|
+
const first = items[0];
|
|
3291
|
+
const last = items[items.length - 1];
|
|
3292
|
+
const active = document.activeElement;
|
|
3293
|
+
if (e.shiftKey && (active === first || !el.contains(active))) {
|
|
3294
|
+
e.preventDefault();
|
|
3295
|
+
last.focus();
|
|
3296
|
+
} else if (!e.shiftKey && (active === last || !el.contains(active))) {
|
|
3297
|
+
e.preventDefault();
|
|
3298
|
+
first.focus();
|
|
3299
|
+
}
|
|
3300
|
+
};
|
|
3301
|
+
document.addEventListener("keydown", onKey);
|
|
3302
|
+
return () => document.removeEventListener("keydown", onKey);
|
|
3303
|
+
}, [enabled, trap, containerRef]);
|
|
3304
|
+
};
|
|
3305
|
+
|
|
3306
|
+
// src/components/Modal/Modal.tsx
|
|
3210
3307
|
var import_jsx_runtime313 = require("react/jsx-runtime");
|
|
3211
3308
|
var ANIMATION_DURATION_MS = 200;
|
|
3212
3309
|
var Modal = (props) => {
|
|
3213
3310
|
const { isOpen, onClose, children } = props;
|
|
3214
|
-
const [mounted, setMounted] =
|
|
3215
|
-
const [visible, setVisible] =
|
|
3216
|
-
const [settled, setSettled] =
|
|
3217
|
-
|
|
3311
|
+
const [mounted, setMounted] = import_react11.default.useState(false);
|
|
3312
|
+
const [visible, setVisible] = import_react11.default.useState(false);
|
|
3313
|
+
const [settled, setSettled] = import_react11.default.useState(false);
|
|
3314
|
+
const boxRef = import_react11.default.useRef(null);
|
|
3315
|
+
useEscapeKey(isOpen, onClose);
|
|
3316
|
+
useFocusTrap(boxRef, isOpen && mounted, { trap: true });
|
|
3317
|
+
import_react11.default.useEffect(() => {
|
|
3218
3318
|
if (isOpen) {
|
|
3219
3319
|
setMounted(true);
|
|
3220
3320
|
const show = setTimeout(() => setVisible(true), 1);
|
|
@@ -3241,6 +3341,7 @@ var Modal = (props) => {
|
|
|
3241
3341
|
children: /* @__PURE__ */ (0, import_jsx_runtime313.jsx)(
|
|
3242
3342
|
"div",
|
|
3243
3343
|
{
|
|
3344
|
+
ref: boxRef,
|
|
3244
3345
|
className: clsx_default("lib-xplat-modal", "modal-box", stateClass, settled && "settled"),
|
|
3245
3346
|
role: "dialog",
|
|
3246
3347
|
"aria-modal": "true",
|
|
@@ -3257,9 +3358,9 @@ Modal.displayName = "Modal";
|
|
|
3257
3358
|
var Modal_default = Modal;
|
|
3258
3359
|
|
|
3259
3360
|
// src/components/DatePicker/SingleDatePicker/index.tsx
|
|
3260
|
-
var
|
|
3361
|
+
var import_react12 = __toESM(require("react"), 1);
|
|
3261
3362
|
var import_jsx_runtime314 = require("react/jsx-runtime");
|
|
3262
|
-
var DayCell2 =
|
|
3363
|
+
var DayCell2 = import_react12.default.memo(
|
|
3263
3364
|
({
|
|
3264
3365
|
day,
|
|
3265
3366
|
disabled,
|
|
@@ -3311,26 +3412,26 @@ var SingleDatePicker = (props) => {
|
|
|
3311
3412
|
initialYear,
|
|
3312
3413
|
initialMonth
|
|
3313
3414
|
);
|
|
3314
|
-
const [pickerMode, setPickerMode] =
|
|
3315
|
-
const [yearRangeStart, setYearRangeStart] =
|
|
3415
|
+
const [pickerMode, setPickerMode] = import_react12.default.useState("days");
|
|
3416
|
+
const [yearRangeStart, setYearRangeStart] = import_react12.default.useState(
|
|
3316
3417
|
Math.floor((initialYear ?? (/* @__PURE__ */ new Date()).getFullYear()) / 12) * 12
|
|
3317
3418
|
);
|
|
3318
|
-
const minTime =
|
|
3419
|
+
const minTime = import_react12.default.useMemo(
|
|
3319
3420
|
() => minDate ? new Date(minDate.getFullYear(), minDate.getMonth(), minDate.getDate()).getTime() : -Infinity,
|
|
3320
3421
|
[minDate]
|
|
3321
3422
|
);
|
|
3322
|
-
const maxTime =
|
|
3423
|
+
const maxTime = import_react12.default.useMemo(
|
|
3323
3424
|
() => maxDate ? new Date(maxDate.getFullYear(), maxDate.getMonth(), maxDate.getDate()).getTime() : Infinity,
|
|
3324
3425
|
[maxDate]
|
|
3325
3426
|
);
|
|
3326
|
-
const highlightSet =
|
|
3427
|
+
const highlightSet = import_react12.default.useMemo(() => {
|
|
3327
3428
|
const set = /* @__PURE__ */ new Set();
|
|
3328
3429
|
for (const h of highlightDates) {
|
|
3329
3430
|
set.add(`${h.getFullYear()}-${h.getMonth()}-${h.getDate()}`);
|
|
3330
3431
|
}
|
|
3331
3432
|
return set;
|
|
3332
3433
|
}, [highlightDates]);
|
|
3333
|
-
const handleSelect =
|
|
3434
|
+
const handleSelect = import_react12.default.useCallback(
|
|
3334
3435
|
(date) => {
|
|
3335
3436
|
onChange?.(date);
|
|
3336
3437
|
},
|
|
@@ -3459,8 +3560,8 @@ var formatDate = (date) => {
|
|
|
3459
3560
|
};
|
|
3460
3561
|
var InputDatePicker = (props) => {
|
|
3461
3562
|
const { value, onChange, minDate, maxDate, disabled, locale = "ko", placeholder } = props;
|
|
3462
|
-
const [isOpen, setIsOpen] =
|
|
3463
|
-
const [tempDate, setTempDate] =
|
|
3563
|
+
const [isOpen, setIsOpen] = import_react13.default.useState(false);
|
|
3564
|
+
const [tempDate, setTempDate] = import_react13.default.useState(value ?? /* @__PURE__ */ new Date());
|
|
3464
3565
|
const handleOpen = () => {
|
|
3465
3566
|
if (disabled) return;
|
|
3466
3567
|
setTempDate(value ?? /* @__PURE__ */ new Date());
|
|
@@ -3509,23 +3610,27 @@ InputDatePicker.displayName = "InputDatePicker";
|
|
|
3509
3610
|
var InputDatePicker_default = InputDatePicker;
|
|
3510
3611
|
|
|
3511
3612
|
// src/components/DatePicker/PopupPicker/index.tsx
|
|
3512
|
-
var
|
|
3613
|
+
var import_react17 = __toESM(require("react"), 1);
|
|
3513
3614
|
|
|
3514
3615
|
// src/components/DatePicker/RangePicker/index.tsx
|
|
3515
|
-
var
|
|
3616
|
+
var import_react16 = __toESM(require("react"), 1);
|
|
3516
3617
|
|
|
3517
3618
|
// src/components/Tab/Tab.tsx
|
|
3518
|
-
var
|
|
3619
|
+
var import_react15 = __toESM(require("react"), 1);
|
|
3519
3620
|
|
|
3520
3621
|
// src/components/Tab/TabItem.tsx
|
|
3521
|
-
var
|
|
3622
|
+
var import_react14 = __toESM(require("react"), 1);
|
|
3522
3623
|
var import_jsx_runtime316 = require("react/jsx-runtime");
|
|
3523
|
-
var TabItem =
|
|
3624
|
+
var TabItem = import_react14.default.forwardRef((props, ref) => {
|
|
3524
3625
|
const { isActive: isActive2, title, onClick } = props;
|
|
3525
3626
|
return /* @__PURE__ */ (0, import_jsx_runtime316.jsx)(
|
|
3526
|
-
"
|
|
3627
|
+
"button",
|
|
3527
3628
|
{
|
|
3528
3629
|
ref,
|
|
3630
|
+
type: "button",
|
|
3631
|
+
role: "tab",
|
|
3632
|
+
"aria-selected": isActive2,
|
|
3633
|
+
tabIndex: isActive2 ? 0 : -1,
|
|
3529
3634
|
className: clsx_default("tab-item", isActive2 ? "active" : null),
|
|
3530
3635
|
onClick,
|
|
3531
3636
|
children: title
|
|
@@ -3540,44 +3645,64 @@ var import_jsx_runtime317 = require("react/jsx-runtime");
|
|
|
3540
3645
|
var Tab = (props) => {
|
|
3541
3646
|
const { activeIndex, onChange, tabs, variant, type, size = "md" } = props;
|
|
3542
3647
|
const shape = variant ?? type ?? "default";
|
|
3543
|
-
const [underlineStyle, setUnderlineStyle] =
|
|
3648
|
+
const [underlineStyle, setUnderlineStyle] = import_react15.default.useState({
|
|
3544
3649
|
left: 0,
|
|
3545
3650
|
width: 0
|
|
3546
3651
|
});
|
|
3547
|
-
const itemRefs =
|
|
3652
|
+
const itemRefs = import_react15.default.useRef([]);
|
|
3653
|
+
const handleKeyDown = (e) => {
|
|
3654
|
+
const last = tabs.length - 1;
|
|
3655
|
+
let next = null;
|
|
3656
|
+
if (e.key === "ArrowRight") next = activeIndex >= last ? 0 : activeIndex + 1;
|
|
3657
|
+
else if (e.key === "ArrowLeft") next = activeIndex <= 0 ? last : activeIndex - 1;
|
|
3658
|
+
else if (e.key === "Home") next = 0;
|
|
3659
|
+
else if (e.key === "End") next = last;
|
|
3660
|
+
if (next === null) return;
|
|
3661
|
+
e.preventDefault();
|
|
3662
|
+
onChange(tabs[next], next);
|
|
3663
|
+
itemRefs.current[next]?.focus();
|
|
3664
|
+
};
|
|
3548
3665
|
const handleChangeActiveTab = (tabItem, tabIdx) => {
|
|
3549
3666
|
onChange(tabItem, tabIdx);
|
|
3550
3667
|
};
|
|
3551
|
-
|
|
3668
|
+
import_react15.default.useEffect(() => {
|
|
3552
3669
|
const el = itemRefs.current[activeIndex];
|
|
3553
3670
|
if (el) {
|
|
3554
3671
|
setUnderlineStyle({ left: el.offsetLeft, width: el.offsetWidth });
|
|
3555
3672
|
}
|
|
3556
3673
|
}, [activeIndex, tabs.length]);
|
|
3557
|
-
return /* @__PURE__ */ (0, import_jsx_runtime317.jsxs)(
|
|
3558
|
-
|
|
3559
|
-
|
|
3560
|
-
{
|
|
3561
|
-
|
|
3562
|
-
|
|
3563
|
-
|
|
3564
|
-
|
|
3565
|
-
|
|
3566
|
-
|
|
3567
|
-
|
|
3568
|
-
|
|
3569
|
-
|
|
3570
|
-
|
|
3571
|
-
|
|
3572
|
-
|
|
3573
|
-
|
|
3574
|
-
|
|
3575
|
-
|
|
3576
|
-
|
|
3577
|
-
|
|
3578
|
-
|
|
3579
|
-
|
|
3580
|
-
|
|
3674
|
+
return /* @__PURE__ */ (0, import_jsx_runtime317.jsxs)(
|
|
3675
|
+
"div",
|
|
3676
|
+
{
|
|
3677
|
+
className: clsx_default("lib-xplat-tab", `type-${shape}`, size),
|
|
3678
|
+
role: "tablist",
|
|
3679
|
+
onKeyDown: handleKeyDown,
|
|
3680
|
+
children: [
|
|
3681
|
+
tabs.map((tab, idx) => /* @__PURE__ */ (0, import_jsx_runtime317.jsx)(
|
|
3682
|
+
TabItem_default,
|
|
3683
|
+
{
|
|
3684
|
+
onClick: () => handleChangeActiveTab(tab, idx),
|
|
3685
|
+
isActive: activeIndex === idx,
|
|
3686
|
+
ref: (el) => {
|
|
3687
|
+
itemRefs.current[idx] = el;
|
|
3688
|
+
},
|
|
3689
|
+
title: tab.title
|
|
3690
|
+
},
|
|
3691
|
+
`${tab.value}_${idx}`
|
|
3692
|
+
)),
|
|
3693
|
+
shape === "toggle" && /* @__PURE__ */ (0, import_jsx_runtime317.jsx)(
|
|
3694
|
+
"div",
|
|
3695
|
+
{
|
|
3696
|
+
className: "tab-toggle-underline",
|
|
3697
|
+
style: {
|
|
3698
|
+
left: underlineStyle.left,
|
|
3699
|
+
width: underlineStyle.width
|
|
3700
|
+
}
|
|
3701
|
+
}
|
|
3702
|
+
)
|
|
3703
|
+
]
|
|
3704
|
+
}
|
|
3705
|
+
);
|
|
3581
3706
|
};
|
|
3582
3707
|
Tab.displayName = "Tab";
|
|
3583
3708
|
var Tab_default = Tab;
|
|
@@ -3593,7 +3718,7 @@ var RangePicker = (props) => {
|
|
|
3593
3718
|
maxDate,
|
|
3594
3719
|
locale = "ko"
|
|
3595
3720
|
} = props;
|
|
3596
|
-
const [activeTab, setActiveTab] =
|
|
3721
|
+
const [activeTab, setActiveTab] = import_react16.default.useState("start");
|
|
3597
3722
|
const handleStartChange = (date) => {
|
|
3598
3723
|
if (!date) return;
|
|
3599
3724
|
const newStart = date > endDate ? endDate : date;
|
|
@@ -3678,7 +3803,7 @@ var RangePicker_default = RangePicker;
|
|
|
3678
3803
|
var import_jsx_runtime319 = require("react/jsx-runtime");
|
|
3679
3804
|
var PopupPicker = (props) => {
|
|
3680
3805
|
const { component, type, locale } = props;
|
|
3681
|
-
const [isOpen, setIsOpen] =
|
|
3806
|
+
const [isOpen, setIsOpen] = import_react17.default.useState(false);
|
|
3682
3807
|
const handleClick = () => setIsOpen(true);
|
|
3683
3808
|
const handleClose = () => setIsOpen(false);
|
|
3684
3809
|
const handleSingleChange = (date) => {
|
|
@@ -3687,7 +3812,7 @@ var PopupPicker = (props) => {
|
|
|
3687
3812
|
handleClose();
|
|
3688
3813
|
};
|
|
3689
3814
|
return /* @__PURE__ */ (0, import_jsx_runtime319.jsxs)("div", { className: "lib-xplat-popup-datepicker", children: [
|
|
3690
|
-
|
|
3815
|
+
import_react17.default.cloneElement(component, { onClick: handleClick }),
|
|
3691
3816
|
/* @__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: [
|
|
3692
3817
|
/* @__PURE__ */ (0, import_jsx_runtime319.jsxs)("div", { className: "popup-datepicker-content", children: [
|
|
3693
3818
|
type === "single" && /* @__PURE__ */ (0, import_jsx_runtime319.jsx)(
|
|
@@ -3746,15 +3871,18 @@ Divider.displayName = "Divider";
|
|
|
3746
3871
|
var Divider_default = Divider;
|
|
3747
3872
|
|
|
3748
3873
|
// src/components/Drawer/Drawer.tsx
|
|
3749
|
-
var
|
|
3874
|
+
var import_react18 = __toESM(require("react"), 1);
|
|
3750
3875
|
var import_react_dom2 = require("react-dom");
|
|
3751
3876
|
var import_jsx_runtime321 = require("react/jsx-runtime");
|
|
3752
3877
|
var ANIMATION_DURATION_MS2 = 250;
|
|
3753
3878
|
var Drawer = (props) => {
|
|
3754
3879
|
const { isOpen, onClose, placement = "right", size = "md", title, children } = props;
|
|
3755
|
-
const [mounted, setMounted] =
|
|
3756
|
-
const [visible, setVisible] =
|
|
3757
|
-
|
|
3880
|
+
const [mounted, setMounted] = import_react18.default.useState(false);
|
|
3881
|
+
const [visible, setVisible] = import_react18.default.useState(false);
|
|
3882
|
+
const panelRef = import_react18.default.useRef(null);
|
|
3883
|
+
useEscapeKey(isOpen, onClose);
|
|
3884
|
+
useFocusTrap(panelRef, isOpen && mounted, { trap: true });
|
|
3885
|
+
import_react18.default.useEffect(() => {
|
|
3758
3886
|
if (isOpen) {
|
|
3759
3887
|
setMounted(true);
|
|
3760
3888
|
const t2 = setTimeout(() => setVisible(true), 1);
|
|
@@ -3776,6 +3904,7 @@ var Drawer = (props) => {
|
|
|
3776
3904
|
children: /* @__PURE__ */ (0, import_jsx_runtime321.jsxs)(
|
|
3777
3905
|
"div",
|
|
3778
3906
|
{
|
|
3907
|
+
ref: panelRef,
|
|
3779
3908
|
className: clsx_default("lib-xplat-drawer", placement, size, stateClass),
|
|
3780
3909
|
role: "dialog",
|
|
3781
3910
|
"aria-modal": "true",
|
|
@@ -3798,7 +3927,7 @@ Drawer.displayName = "Drawer";
|
|
|
3798
3927
|
var Drawer_default = Drawer;
|
|
3799
3928
|
|
|
3800
3929
|
// src/components/Dropdown/Dropdown.tsx
|
|
3801
|
-
var
|
|
3930
|
+
var import_react21 = __toESM(require("react"), 1);
|
|
3802
3931
|
|
|
3803
3932
|
// src/tokens/hooks/Portal.tsx
|
|
3804
3933
|
var import_react_dom3 = __toESM(require("react-dom"), 1);
|
|
@@ -3810,13 +3939,15 @@ Portal.displayName = "Portal";
|
|
|
3810
3939
|
var Portal_default = Portal;
|
|
3811
3940
|
|
|
3812
3941
|
// src/tokens/hooks/useAutoPosition.ts
|
|
3813
|
-
var
|
|
3942
|
+
var import_react19 = __toESM(require("react"), 1);
|
|
3814
3943
|
var useAutoPosition = (triggerRef, popRef, enabled = true) => {
|
|
3815
|
-
const [position, setPosition] =
|
|
3944
|
+
const [position, setPosition] = import_react19.default.useState({
|
|
3816
3945
|
position: {},
|
|
3817
|
-
direction: "bottom"
|
|
3946
|
+
direction: "bottom",
|
|
3947
|
+
repositioning: false
|
|
3818
3948
|
});
|
|
3819
|
-
const
|
|
3949
|
+
const placedRef = import_react19.default.useRef(false);
|
|
3950
|
+
const calculatePosition = import_react19.default.useCallback(() => {
|
|
3820
3951
|
if (!triggerRef.current || !popRef.current) return;
|
|
3821
3952
|
const triggerRect = triggerRef.current.getBoundingClientRect();
|
|
3822
3953
|
const popW = popRef.current.offsetWidth;
|
|
@@ -3840,16 +3971,21 @@ var useAutoPosition = (triggerRef, popRef, enabled = true) => {
|
|
|
3840
3971
|
if (left < 8) left = 8;
|
|
3841
3972
|
setPosition({
|
|
3842
3973
|
position: { top, left },
|
|
3843
|
-
direction
|
|
3974
|
+
direction,
|
|
3975
|
+
repositioning: placedRef.current
|
|
3844
3976
|
});
|
|
3977
|
+
placedRef.current = true;
|
|
3845
3978
|
}, [triggerRef, popRef]);
|
|
3846
|
-
|
|
3847
|
-
if (!enabled)
|
|
3979
|
+
import_react19.default.useLayoutEffect(() => {
|
|
3980
|
+
if (!enabled) {
|
|
3981
|
+
placedRef.current = false;
|
|
3982
|
+
return;
|
|
3983
|
+
}
|
|
3848
3984
|
calculatePosition();
|
|
3849
3985
|
const raf = requestAnimationFrame(calculatePosition);
|
|
3850
3986
|
return () => cancelAnimationFrame(raf);
|
|
3851
3987
|
}, [calculatePosition, enabled]);
|
|
3852
|
-
|
|
3988
|
+
import_react19.default.useEffect(() => {
|
|
3853
3989
|
if (!enabled || !popRef.current) return;
|
|
3854
3990
|
const observer = new ResizeObserver(() => {
|
|
3855
3991
|
calculatePosition();
|
|
@@ -3857,13 +3993,19 @@ var useAutoPosition = (triggerRef, popRef, enabled = true) => {
|
|
|
3857
3993
|
observer.observe(popRef.current);
|
|
3858
3994
|
return () => observer.disconnect();
|
|
3859
3995
|
}, [calculatePosition, enabled, popRef]);
|
|
3860
|
-
|
|
3996
|
+
import_react19.default.useEffect(() => {
|
|
3861
3997
|
if (!enabled) return;
|
|
3862
|
-
|
|
3863
|
-
|
|
3998
|
+
let raf = 0;
|
|
3999
|
+
const onScrollOrResize = () => {
|
|
4000
|
+
cancelAnimationFrame(raf);
|
|
4001
|
+
raf = requestAnimationFrame(calculatePosition);
|
|
4002
|
+
};
|
|
4003
|
+
window.addEventListener("resize", onScrollOrResize, { passive: true });
|
|
4004
|
+
window.addEventListener("scroll", onScrollOrResize, { passive: true, capture: true });
|
|
3864
4005
|
return () => {
|
|
3865
|
-
|
|
3866
|
-
window.removeEventListener("
|
|
4006
|
+
cancelAnimationFrame(raf);
|
|
4007
|
+
window.removeEventListener("resize", onScrollOrResize);
|
|
4008
|
+
window.removeEventListener("scroll", onScrollOrResize, true);
|
|
3867
4009
|
};
|
|
3868
4010
|
}, [calculatePosition, enabled]);
|
|
3869
4011
|
return position;
|
|
@@ -3871,9 +4013,9 @@ var useAutoPosition = (triggerRef, popRef, enabled = true) => {
|
|
|
3871
4013
|
var useAutoPosition_default = useAutoPosition;
|
|
3872
4014
|
|
|
3873
4015
|
// src/tokens/hooks/useClickOutside.ts
|
|
3874
|
-
var
|
|
4016
|
+
var import_react20 = __toESM(require("react"), 1);
|
|
3875
4017
|
var useClickOutside = (refs, handler, enabled = true) => {
|
|
3876
|
-
|
|
4018
|
+
import_react20.default.useEffect(() => {
|
|
3877
4019
|
if (!enabled) return;
|
|
3878
4020
|
const refArray = Array.isArray(refs) ? refs : [refs];
|
|
3879
4021
|
const listener = (event) => {
|
|
@@ -3899,14 +4041,18 @@ var useClickOutside_default = useClickOutside;
|
|
|
3899
4041
|
var import_jsx_runtime322 = require("react/jsx-runtime");
|
|
3900
4042
|
var Dropdown = (props) => {
|
|
3901
4043
|
const { items, children } = props;
|
|
3902
|
-
const [isOpen, setIsOpen] =
|
|
3903
|
-
const [mounted, setMounted] =
|
|
3904
|
-
const [visible, setVisible] =
|
|
3905
|
-
const triggerRef =
|
|
3906
|
-
const menuRef =
|
|
3907
|
-
const { position, direction } = useAutoPosition_default(triggerRef, menuRef, mounted);
|
|
4044
|
+
const [isOpen, setIsOpen] = import_react21.default.useState(false);
|
|
4045
|
+
const [mounted, setMounted] = import_react21.default.useState(false);
|
|
4046
|
+
const [visible, setVisible] = import_react21.default.useState(false);
|
|
4047
|
+
const triggerRef = import_react21.default.useRef(null);
|
|
4048
|
+
const menuRef = import_react21.default.useRef(null);
|
|
4049
|
+
const { position, direction, repositioning } = useAutoPosition_default(triggerRef, menuRef, mounted);
|
|
3908
4050
|
useClickOutside_default([triggerRef, menuRef], () => setIsOpen(false), isOpen);
|
|
3909
|
-
|
|
4051
|
+
useEscapeKey(isOpen, () => {
|
|
4052
|
+
setIsOpen(false);
|
|
4053
|
+
triggerRef.current?.focus({ preventScroll: true });
|
|
4054
|
+
});
|
|
4055
|
+
import_react21.default.useEffect(() => {
|
|
3910
4056
|
if (isOpen) {
|
|
3911
4057
|
setMounted(true);
|
|
3912
4058
|
const t2 = setTimeout(() => setVisible(true), 1);
|
|
@@ -3935,7 +4081,7 @@ var Dropdown = (props) => {
|
|
|
3935
4081
|
"div",
|
|
3936
4082
|
{
|
|
3937
4083
|
ref: menuRef,
|
|
3938
|
-
className: clsx_default("lib-xplat-dropdown-menu", direction, { visible }),
|
|
4084
|
+
className: clsx_default("lib-xplat-dropdown-menu", direction, { visible }, repositioning && "repositioning"),
|
|
3939
4085
|
style: { top: position.top, left: position.left },
|
|
3940
4086
|
role: "menu",
|
|
3941
4087
|
children: items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime322.jsx)(
|
|
@@ -3960,7 +4106,112 @@ Dropdown.displayName = "Dropdown";
|
|
|
3960
4106
|
var Dropdown_default = Dropdown;
|
|
3961
4107
|
|
|
3962
4108
|
// src/components/Editor/Editor.tsx
|
|
3963
|
-
var
|
|
4109
|
+
var import_react22 = __toESM(require("react"), 1);
|
|
4110
|
+
|
|
4111
|
+
// src/components/Editor/highlight.ts
|
|
4112
|
+
var CODE_LANGUAGES = [
|
|
4113
|
+
{ value: "plain", label: "\uC5C6\uC74C" },
|
|
4114
|
+
{ value: "javascript", label: "JavaScript" },
|
|
4115
|
+
{ value: "typescript", label: "TypeScript" },
|
|
4116
|
+
{ value: "json", label: "JSON" },
|
|
4117
|
+
{ value: "html", label: "HTML" },
|
|
4118
|
+
{ value: "css", label: "CSS" },
|
|
4119
|
+
{ value: "python", label: "Python" },
|
|
4120
|
+
{ value: "sql", label: "SQL" },
|
|
4121
|
+
{ value: "bash", label: "Bash" }
|
|
4122
|
+
];
|
|
4123
|
+
var KEYWORDS = {
|
|
4124
|
+
plain: [],
|
|
4125
|
+
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(" "),
|
|
4126
|
+
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(" "),
|
|
4127
|
+
json: ["true", "false", "null"],
|
|
4128
|
+
html: [],
|
|
4129
|
+
css: [],
|
|
4130
|
+
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(" "),
|
|
4131
|
+
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(" "),
|
|
4132
|
+
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(" ")
|
|
4133
|
+
};
|
|
4134
|
+
var LINE_COMMENT = {
|
|
4135
|
+
javascript: "//",
|
|
4136
|
+
typescript: "//",
|
|
4137
|
+
css: "",
|
|
4138
|
+
python: "#",
|
|
4139
|
+
sql: "--",
|
|
4140
|
+
bash: "#"
|
|
4141
|
+
};
|
|
4142
|
+
var escape = (s) => s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
4143
|
+
var wrap = (cls, text) => `<span class="tok-${cls}">${escape(text)}</span>`;
|
|
4144
|
+
var highlight = (code, lang) => {
|
|
4145
|
+
if (lang === "plain" || !code) return escape(code);
|
|
4146
|
+
const keywords = new Set(KEYWORDS[lang]);
|
|
4147
|
+
const lineComment = LINE_COMMENT[lang];
|
|
4148
|
+
const caseInsensitive = lang === "sql";
|
|
4149
|
+
let out = "";
|
|
4150
|
+
let i = 0;
|
|
4151
|
+
while (i < code.length) {
|
|
4152
|
+
const rest = code.slice(i);
|
|
4153
|
+
if ((lang === "javascript" || lang === "typescript" || lang === "css") && rest.startsWith("/*")) {
|
|
4154
|
+
const end = code.indexOf("*/", i + 2);
|
|
4155
|
+
const stop = end === -1 ? code.length : end + 2;
|
|
4156
|
+
out += wrap("comment", code.slice(i, stop));
|
|
4157
|
+
i = stop;
|
|
4158
|
+
continue;
|
|
4159
|
+
}
|
|
4160
|
+
if (lineComment && rest.startsWith(lineComment)) {
|
|
4161
|
+
const nl = code.indexOf("\n", i);
|
|
4162
|
+
const stop = nl === -1 ? code.length : nl;
|
|
4163
|
+
out += wrap("comment", code.slice(i, stop));
|
|
4164
|
+
i = stop;
|
|
4165
|
+
continue;
|
|
4166
|
+
}
|
|
4167
|
+
const q = rest[0];
|
|
4168
|
+
if (q === '"' || q === "'" || q === "`") {
|
|
4169
|
+
let j = 1;
|
|
4170
|
+
while (j < rest.length) {
|
|
4171
|
+
if (rest[j] === "\\") {
|
|
4172
|
+
j += 2;
|
|
4173
|
+
continue;
|
|
4174
|
+
}
|
|
4175
|
+
if (rest[j] === q) {
|
|
4176
|
+
j += 1;
|
|
4177
|
+
break;
|
|
4178
|
+
}
|
|
4179
|
+
if (rest[j] === "\n" && q !== "`") break;
|
|
4180
|
+
j += 1;
|
|
4181
|
+
}
|
|
4182
|
+
out += wrap("string", rest.slice(0, j));
|
|
4183
|
+
i += j;
|
|
4184
|
+
continue;
|
|
4185
|
+
}
|
|
4186
|
+
const num = /^\d+(\.\d+)?/.exec(rest);
|
|
4187
|
+
if (num && !/[\w$]/.test(code[i - 1] ?? "")) {
|
|
4188
|
+
out += wrap("number", num[0]);
|
|
4189
|
+
i += num[0].length;
|
|
4190
|
+
continue;
|
|
4191
|
+
}
|
|
4192
|
+
const word = /^[A-Za-z_$][\w$]*/.exec(rest);
|
|
4193
|
+
if (word) {
|
|
4194
|
+
const w = word[0];
|
|
4195
|
+
const hit = caseInsensitive ? keywords.has(w.toUpperCase()) : keywords.has(w);
|
|
4196
|
+
out += hit ? wrap("keyword", w) : escape(w);
|
|
4197
|
+
i += w.length;
|
|
4198
|
+
continue;
|
|
4199
|
+
}
|
|
4200
|
+
if (lang === "html" && rest.startsWith("<")) {
|
|
4201
|
+
const tag = /^<\/?[A-Za-z][\w-]*/.exec(rest);
|
|
4202
|
+
if (tag) {
|
|
4203
|
+
out += wrap("keyword", tag[0]);
|
|
4204
|
+
i += tag[0].length;
|
|
4205
|
+
continue;
|
|
4206
|
+
}
|
|
4207
|
+
}
|
|
4208
|
+
out += escape(code[i]);
|
|
4209
|
+
i += 1;
|
|
4210
|
+
}
|
|
4211
|
+
return out;
|
|
4212
|
+
};
|
|
4213
|
+
|
|
4214
|
+
// src/components/Editor/Editor.tsx
|
|
3964
4215
|
var import_jsx_runtime323 = require("react/jsx-runtime");
|
|
3965
4216
|
var DEFAULT_TOOLBAR = [
|
|
3966
4217
|
"bold",
|
|
@@ -3968,14 +4219,27 @@ var DEFAULT_TOOLBAR = [
|
|
|
3968
4219
|
"underline",
|
|
3969
4220
|
"strikethrough",
|
|
3970
4221
|
"code",
|
|
3971
|
-
"heading",
|
|
4222
|
+
"heading-1",
|
|
4223
|
+
"heading-2",
|
|
4224
|
+
"heading-3",
|
|
3972
4225
|
"list",
|
|
3973
4226
|
"ordered-list",
|
|
3974
4227
|
"blockquote",
|
|
3975
4228
|
"code-block",
|
|
3976
4229
|
"link",
|
|
3977
4230
|
"image",
|
|
3978
|
-
"divider"
|
|
4231
|
+
"divider",
|
|
4232
|
+
"checklist",
|
|
4233
|
+
"table",
|
|
4234
|
+
"align-left",
|
|
4235
|
+
"align-center",
|
|
4236
|
+
"align-right",
|
|
4237
|
+
"highlight",
|
|
4238
|
+
"superscript",
|
|
4239
|
+
"subscript",
|
|
4240
|
+
"clear-format",
|
|
4241
|
+
"undo",
|
|
4242
|
+
"redo"
|
|
3979
4243
|
];
|
|
3980
4244
|
var ALLOWED_TAGS = /* @__PURE__ */ new Set([
|
|
3981
4245
|
"p",
|
|
@@ -4004,12 +4268,51 @@ var ALLOWED_TAGS = /* @__PURE__ */ new Set([
|
|
|
4004
4268
|
"img",
|
|
4005
4269
|
"hr",
|
|
4006
4270
|
"span",
|
|
4007
|
-
"div"
|
|
4271
|
+
"div",
|
|
4272
|
+
"sub",
|
|
4273
|
+
"sup",
|
|
4274
|
+
"mark",
|
|
4275
|
+
"table",
|
|
4276
|
+
"thead",
|
|
4277
|
+
"tbody",
|
|
4278
|
+
"tr",
|
|
4279
|
+
"th",
|
|
4280
|
+
"td"
|
|
4008
4281
|
]);
|
|
4009
4282
|
var ALLOWED_ATTRS = {
|
|
4010
4283
|
a: ["href", "target", "rel"],
|
|
4011
|
-
img: ["src", "alt"]
|
|
4284
|
+
img: ["src", "alt", "width"],
|
|
4285
|
+
// 정렬·체크리스트는 클래스로만 표현한다. style 을 열면 붙여넣기로 아무 CSS 나 들어온다
|
|
4286
|
+
p: ["class"],
|
|
4287
|
+
h1: ["class"],
|
|
4288
|
+
h2: ["class"],
|
|
4289
|
+
h3: ["class"],
|
|
4290
|
+
h4: ["class"],
|
|
4291
|
+
h5: ["class"],
|
|
4292
|
+
h6: ["class"],
|
|
4293
|
+
ul: ["class"],
|
|
4294
|
+
ol: ["class"],
|
|
4295
|
+
li: ["class", "data-checked"],
|
|
4296
|
+
blockquote: ["class"],
|
|
4297
|
+
div: ["class"],
|
|
4298
|
+
span: ["class"],
|
|
4299
|
+
pre: ["class"],
|
|
4300
|
+
code: ["class"],
|
|
4301
|
+
mark: ["class"],
|
|
4302
|
+
table: ["class"],
|
|
4303
|
+
td: ["class"],
|
|
4304
|
+
th: ["class"],
|
|
4305
|
+
tr: ["class"]
|
|
4012
4306
|
};
|
|
4307
|
+
var DROP_WITH_CONTENT = /* @__PURE__ */ new Set([
|
|
4308
|
+
"script",
|
|
4309
|
+
"style",
|
|
4310
|
+
"noscript",
|
|
4311
|
+
"iframe",
|
|
4312
|
+
"object",
|
|
4313
|
+
"embed",
|
|
4314
|
+
"template"
|
|
4315
|
+
]);
|
|
4013
4316
|
var sanitizeHtml = (input) => {
|
|
4014
4317
|
const doc = new DOMParser().parseFromString(`<div>${input}</div>`, "text/html");
|
|
4015
4318
|
const root = doc.body.firstElementChild;
|
|
@@ -4018,6 +4321,10 @@ var sanitizeHtml = (input) => {
|
|
|
4018
4321
|
const children = Array.from(node.children);
|
|
4019
4322
|
for (const child of children) {
|
|
4020
4323
|
const tag = child.tagName.toLowerCase();
|
|
4324
|
+
if (DROP_WITH_CONTENT.has(tag)) {
|
|
4325
|
+
node.removeChild(child);
|
|
4326
|
+
continue;
|
|
4327
|
+
}
|
|
4021
4328
|
if (!ALLOWED_TAGS.has(tag)) {
|
|
4022
4329
|
while (child.firstChild) node.insertBefore(child.firstChild, child);
|
|
4023
4330
|
node.removeChild(child);
|
|
@@ -4048,7 +4355,9 @@ var escapeHtml = (text) => {
|
|
|
4048
4355
|
};
|
|
4049
4356
|
var SLASH_ITEMS = [
|
|
4050
4357
|
{ key: "paragraph", label: "\uB2E8\uB77D", hint: "\uAE30\uBCF8 \uD14D\uC2A4\uD2B8" },
|
|
4051
|
-
{ key: "heading", label: "\uC81C\uBAA9 1", hint: "\uD070 \uC81C\uBAA9" },
|
|
4358
|
+
{ key: "heading-1", label: "\uC81C\uBAA9 1", hint: "\uAC00\uC7A5 \uD070 \uC81C\uBAA9" },
|
|
4359
|
+
{ key: "heading-2", label: "\uC81C\uBAA9 2", hint: "" },
|
|
4360
|
+
{ key: "heading-3", label: "\uC81C\uBAA9 3", hint: "" },
|
|
4052
4361
|
{ key: "list", label: "\uAE00\uBA38\uB9AC \uAE30\uD638 \uBAA9\uB85D", hint: "\u2022 \uD56D\uBAA9" },
|
|
4053
4362
|
{ key: "ordered-list", label: "\uBC88\uD638 \uB9E4\uAE30\uAE30 \uBAA9\uB85D", hint: "1. \uD56D\uBAA9" },
|
|
4054
4363
|
{ key: "blockquote", label: "\uC778\uC6A9", hint: "" },
|
|
@@ -4068,26 +4377,32 @@ var Editor = (props) => {
|
|
|
4068
4377
|
onImageUpload,
|
|
4069
4378
|
minHeight = 200
|
|
4070
4379
|
} = props;
|
|
4071
|
-
const editorRef =
|
|
4072
|
-
const lastRangeRef =
|
|
4073
|
-
const composingRef =
|
|
4074
|
-
const [isFocused, setIsFocused] =
|
|
4075
|
-
const [isEmpty, setIsEmpty] =
|
|
4076
|
-
const [activeFormats, setActiveFormats] =
|
|
4077
|
-
const [slashOpen, setSlashOpen] =
|
|
4078
|
-
const [slashFilter, setSlashFilter] =
|
|
4079
|
-
const [slashIdx, setSlashIdx] =
|
|
4080
|
-
const [slashPos, setSlashPos] =
|
|
4081
|
-
const slashStartRangeRef =
|
|
4082
|
-
const [linkOpen, setLinkOpen] =
|
|
4083
|
-
const [linkValue, setLinkValue] =
|
|
4084
|
-
const [linkPos, setLinkPos] =
|
|
4085
|
-
|
|
4086
|
-
|
|
4087
|
-
|
|
4088
|
-
|
|
4089
|
-
|
|
4090
|
-
|
|
4380
|
+
const editorRef = import_react22.default.useRef(null);
|
|
4381
|
+
const lastRangeRef = import_react22.default.useRef(null);
|
|
4382
|
+
const composingRef = import_react22.default.useRef(false);
|
|
4383
|
+
const [isFocused, setIsFocused] = import_react22.default.useState(false);
|
|
4384
|
+
const [isEmpty, setIsEmpty] = import_react22.default.useState(!value);
|
|
4385
|
+
const [activeFormats, setActiveFormats] = import_react22.default.useState(/* @__PURE__ */ new Set());
|
|
4386
|
+
const [slashOpen, setSlashOpen] = import_react22.default.useState(false);
|
|
4387
|
+
const [slashFilter, setSlashFilter] = import_react22.default.useState("");
|
|
4388
|
+
const [slashIdx, setSlashIdx] = import_react22.default.useState(0);
|
|
4389
|
+
const [slashPos, setSlashPos] = import_react22.default.useState({ top: 0, left: 0 });
|
|
4390
|
+
const slashStartRangeRef = import_react22.default.useRef(null);
|
|
4391
|
+
const [linkOpen, setLinkOpen] = import_react22.default.useState(false);
|
|
4392
|
+
const [linkValue, setLinkValue] = import_react22.default.useState("");
|
|
4393
|
+
const [linkPos, setLinkPos] = import_react22.default.useState({ top: 0, left: 0 });
|
|
4394
|
+
const lastEmittedRef = import_react22.default.useRef(null);
|
|
4395
|
+
import_react22.default.useEffect(() => {
|
|
4396
|
+
const el = editorRef.current;
|
|
4397
|
+
if (!el) return;
|
|
4398
|
+
if (value === lastEmittedRef.current) return;
|
|
4399
|
+
if (el.innerHTML === value) return;
|
|
4400
|
+
el.innerHTML = sanitizeHtml(value || "");
|
|
4401
|
+
if (!el.firstChild) el.innerHTML = "<p><br></p>";
|
|
4402
|
+
lastEmittedRef.current = null;
|
|
4403
|
+
historyRef.current = [{ html: el.innerHTML, caret: 0 }];
|
|
4404
|
+
historyIdxRef.current = 0;
|
|
4405
|
+
updateEmpty();
|
|
4091
4406
|
}, [value]);
|
|
4092
4407
|
const updateEmpty = () => {
|
|
4093
4408
|
const el = editorRef.current;
|
|
@@ -4103,10 +4418,19 @@ var Editor = (props) => {
|
|
|
4103
4418
|
}
|
|
4104
4419
|
};
|
|
4105
4420
|
const restoreSelection = () => {
|
|
4106
|
-
|
|
4421
|
+
const range = lastRangeRef.current;
|
|
4422
|
+
if (!range) return;
|
|
4423
|
+
if (!editorRef.current?.contains(range.startContainer)) {
|
|
4424
|
+
lastRangeRef.current = null;
|
|
4425
|
+
return;
|
|
4426
|
+
}
|
|
4107
4427
|
const sel = window.getSelection();
|
|
4108
|
-
|
|
4109
|
-
|
|
4428
|
+
try {
|
|
4429
|
+
sel?.removeAllRanges();
|
|
4430
|
+
sel?.addRange(range);
|
|
4431
|
+
} catch {
|
|
4432
|
+
lastRangeRef.current = null;
|
|
4433
|
+
}
|
|
4110
4434
|
};
|
|
4111
4435
|
const updateActiveFormats = () => {
|
|
4112
4436
|
if (!editorRef.current) return;
|
|
@@ -4122,6 +4446,17 @@ var Editor = (props) => {
|
|
|
4122
4446
|
if (document.queryCommandState("insertOrderedList")) next.add("ordered-list");
|
|
4123
4447
|
const block = String(document.queryCommandValue("formatBlock") || "").toLowerCase();
|
|
4124
4448
|
if (block) next.add(`block:${block}`);
|
|
4449
|
+
if (document.queryCommandState("superscript")) next.add("superscript");
|
|
4450
|
+
if (document.queryCommandState("subscript")) next.add("subscript");
|
|
4451
|
+
} catch {
|
|
4452
|
+
}
|
|
4453
|
+
try {
|
|
4454
|
+
const blockEl = currentBlock();
|
|
4455
|
+
if (blockEl?.classList.contains("align-center")) next.add("align:center");
|
|
4456
|
+
else if (blockEl?.classList.contains("align-right")) next.add("align:right");
|
|
4457
|
+
else if (blockEl) next.add("align:left");
|
|
4458
|
+
if (blockEl?.closest("mark")) next.add("highlight");
|
|
4459
|
+
if (blockEl?.closest("ul.checklist")) next.add("checklist");
|
|
4125
4460
|
} catch {
|
|
4126
4461
|
}
|
|
4127
4462
|
setActiveFormats(next);
|
|
@@ -4135,7 +4470,374 @@ var Editor = (props) => {
|
|
|
4135
4470
|
const setBlock = (tag) => {
|
|
4136
4471
|
exec("formatBlock", tag);
|
|
4137
4472
|
};
|
|
4473
|
+
const toggleBlock = (tag) => {
|
|
4474
|
+
const current = String(document.queryCommandValue("formatBlock") || "").toLowerCase();
|
|
4475
|
+
setBlock(current === tag ? "p" : tag);
|
|
4476
|
+
};
|
|
4477
|
+
const historyRef = import_react22.default.useRef([]);
|
|
4478
|
+
const historyIdxRef = import_react22.default.useRef(-1);
|
|
4479
|
+
const lastPushAtRef = import_react22.default.useRef(0);
|
|
4480
|
+
const isRestoringRef = import_react22.default.useRef(false);
|
|
4481
|
+
const caretOffset = (rootEl) => {
|
|
4482
|
+
const el = rootEl ?? editorRef.current;
|
|
4483
|
+
const sel = window.getSelection();
|
|
4484
|
+
if (!el || !sel || sel.rangeCount === 0 || !el.contains(sel.anchorNode)) return 0;
|
|
4485
|
+
const range = sel.getRangeAt(0).cloneRange();
|
|
4486
|
+
range.selectNodeContents(el);
|
|
4487
|
+
range.setEnd(sel.getRangeAt(0).endContainer, sel.getRangeAt(0).endOffset);
|
|
4488
|
+
return range.toString().length;
|
|
4489
|
+
};
|
|
4490
|
+
const setCaretOffset = (offset, rootEl) => {
|
|
4491
|
+
const el = rootEl ?? editorRef.current;
|
|
4492
|
+
if (!el) return;
|
|
4493
|
+
const walker = document.createTreeWalker(el, NodeFilter.SHOW_TEXT);
|
|
4494
|
+
let remaining = offset;
|
|
4495
|
+
let node = null;
|
|
4496
|
+
while (node = walker.nextNode()) {
|
|
4497
|
+
const len = node.textContent?.length ?? 0;
|
|
4498
|
+
if (remaining <= len) {
|
|
4499
|
+
const range = document.createRange();
|
|
4500
|
+
range.setStart(node, remaining);
|
|
4501
|
+
range.collapse(true);
|
|
4502
|
+
const sel = window.getSelection();
|
|
4503
|
+
sel?.removeAllRanges();
|
|
4504
|
+
sel?.addRange(range);
|
|
4505
|
+
return;
|
|
4506
|
+
}
|
|
4507
|
+
remaining -= len;
|
|
4508
|
+
}
|
|
4509
|
+
placeCaretAtEnd(el);
|
|
4510
|
+
};
|
|
4511
|
+
const pushHistory = (force = false) => {
|
|
4512
|
+
const el = editorRef.current;
|
|
4513
|
+
if (!el || isRestoringRef.current) return;
|
|
4514
|
+
const html = el.innerHTML;
|
|
4515
|
+
const hist = historyRef.current;
|
|
4516
|
+
const cur = hist[historyIdxRef.current];
|
|
4517
|
+
if (cur && cur.html === html) return;
|
|
4518
|
+
const now = Date.now();
|
|
4519
|
+
const coalesce = !force && cur && now - lastPushAtRef.current < 500;
|
|
4520
|
+
lastPushAtRef.current = now;
|
|
4521
|
+
if (coalesce) {
|
|
4522
|
+
hist[historyIdxRef.current] = { html, caret: caretOffset() };
|
|
4523
|
+
return;
|
|
4524
|
+
}
|
|
4525
|
+
hist.length = historyIdxRef.current + 1;
|
|
4526
|
+
hist.push({ html, caret: caretOffset() });
|
|
4527
|
+
if (hist.length > 200) hist.shift();
|
|
4528
|
+
historyIdxRef.current = hist.length - 1;
|
|
4529
|
+
};
|
|
4530
|
+
const applySnapshot = (snap) => {
|
|
4531
|
+
const el = editorRef.current;
|
|
4532
|
+
if (!el) return;
|
|
4533
|
+
isRestoringRef.current = true;
|
|
4534
|
+
el.innerHTML = snap.html;
|
|
4535
|
+
setCaretOffset(snap.caret);
|
|
4536
|
+
isRestoringRef.current = false;
|
|
4537
|
+
lastEmittedRef.current = el.innerHTML;
|
|
4538
|
+
onChange?.(el.innerHTML);
|
|
4539
|
+
updateEmpty();
|
|
4540
|
+
updateActiveFormats();
|
|
4541
|
+
};
|
|
4542
|
+
const undo = () => {
|
|
4543
|
+
pushHistory(true);
|
|
4544
|
+
if (historyIdxRef.current <= 0) return;
|
|
4545
|
+
historyIdxRef.current -= 1;
|
|
4546
|
+
applySnapshot(historyRef.current[historyIdxRef.current]);
|
|
4547
|
+
};
|
|
4548
|
+
const redo = () => {
|
|
4549
|
+
if (historyIdxRef.current >= historyRef.current.length - 1) return;
|
|
4550
|
+
historyIdxRef.current += 1;
|
|
4551
|
+
applySnapshot(historyRef.current[historyIdxRef.current]);
|
|
4552
|
+
};
|
|
4553
|
+
const langOf = (pre) => {
|
|
4554
|
+
const cls = Array.from(pre.classList).find((c) => c.startsWith("lang-"));
|
|
4555
|
+
return cls?.slice(5) ?? "plain";
|
|
4556
|
+
};
|
|
4557
|
+
const [codeLang, setCodeLang] = import_react22.default.useState("plain");
|
|
4558
|
+
const highlightRafRef = import_react22.default.useRef(0);
|
|
4559
|
+
const rehighlight = (pre) => {
|
|
4560
|
+
if (composingRef.current) return;
|
|
4561
|
+
const code = pre.querySelector("code");
|
|
4562
|
+
if (!code) return;
|
|
4563
|
+
const lang = langOf(pre);
|
|
4564
|
+
const text = code.textContent || "";
|
|
4565
|
+
const next = highlight(text, lang);
|
|
4566
|
+
if (code.innerHTML === next) return;
|
|
4567
|
+
const caret = caretOffset(code);
|
|
4568
|
+
isRestoringRef.current = true;
|
|
4569
|
+
code.innerHTML = next;
|
|
4570
|
+
setCaretOffset(caret, code);
|
|
4571
|
+
isRestoringRef.current = false;
|
|
4572
|
+
};
|
|
4573
|
+
const scheduleHighlight = () => {
|
|
4574
|
+
const pre = closestPre();
|
|
4575
|
+
if (!pre) return;
|
|
4576
|
+
cancelAnimationFrame(highlightRafRef.current);
|
|
4577
|
+
highlightRafRef.current = requestAnimationFrame(() => rehighlight(pre));
|
|
4578
|
+
};
|
|
4579
|
+
const changeCodeLang = (lang) => {
|
|
4580
|
+
const pre = closestPre();
|
|
4581
|
+
if (!pre) return;
|
|
4582
|
+
pushHistory(true);
|
|
4583
|
+
Array.from(pre.classList).filter((c) => c.startsWith("lang-")).forEach((c) => pre.classList.remove(c));
|
|
4584
|
+
if (lang !== "plain") pre.classList.add(`lang-${lang}`);
|
|
4585
|
+
setCodeLang(lang);
|
|
4586
|
+
rehighlight(pre);
|
|
4587
|
+
handleInput();
|
|
4588
|
+
};
|
|
4589
|
+
const closestPre = () => {
|
|
4590
|
+
const sel = window.getSelection();
|
|
4591
|
+
const node = sel?.anchorNode;
|
|
4592
|
+
if (!node || !editorRef.current?.contains(node)) return null;
|
|
4593
|
+
const el = node.nodeType === Node.ELEMENT_NODE ? node : node.parentElement;
|
|
4594
|
+
return el?.closest("pre") ?? null;
|
|
4595
|
+
};
|
|
4596
|
+
const insertCodeBlock = () => {
|
|
4597
|
+
pushHistory(true);
|
|
4598
|
+
const el = editorRef.current;
|
|
4599
|
+
const sel = window.getSelection();
|
|
4600
|
+
if (!el || !sel || sel.rangeCount === 0) return;
|
|
4601
|
+
const existing = closestPre();
|
|
4602
|
+
if (existing) {
|
|
4603
|
+
const p = document.createElement("p");
|
|
4604
|
+
p.textContent = existing.textContent || "";
|
|
4605
|
+
if (!p.textContent) p.innerHTML = "<br>";
|
|
4606
|
+
existing.replaceWith(p);
|
|
4607
|
+
placeCaretAtEnd(p);
|
|
4608
|
+
handleInput();
|
|
4609
|
+
return;
|
|
4610
|
+
}
|
|
4611
|
+
const range = sel.getRangeAt(0);
|
|
4612
|
+
const frag = range.cloneContents();
|
|
4613
|
+
const holder = document.createElement("div");
|
|
4614
|
+
holder.appendChild(frag);
|
|
4615
|
+
const BLOCK = /^(p|div|h[1-6]|li|blockquote|pre|tr)$/i;
|
|
4616
|
+
const linesOf = (node) => {
|
|
4617
|
+
const out = [];
|
|
4618
|
+
let cur = "";
|
|
4619
|
+
for (const child of Array.from(node.childNodes)) {
|
|
4620
|
+
if (child.nodeType === Node.TEXT_NODE) {
|
|
4621
|
+
cur += child.textContent || "";
|
|
4622
|
+
} else if (child.nodeName === "BR") {
|
|
4623
|
+
out.push(cur);
|
|
4624
|
+
cur = "";
|
|
4625
|
+
} else if (BLOCK.test(child.nodeName)) {
|
|
4626
|
+
if (cur) {
|
|
4627
|
+
out.push(cur);
|
|
4628
|
+
cur = "";
|
|
4629
|
+
}
|
|
4630
|
+
const sub = linesOf(child);
|
|
4631
|
+
out.push(...sub.length > 0 ? sub : [""]);
|
|
4632
|
+
} else {
|
|
4633
|
+
cur += linesOf(child).join("\n");
|
|
4634
|
+
}
|
|
4635
|
+
}
|
|
4636
|
+
if (cur) out.push(cur);
|
|
4637
|
+
return out;
|
|
4638
|
+
};
|
|
4639
|
+
const text = linesOf(holder).join("\n").replace(/\n+$/, "");
|
|
4640
|
+
const pre = document.createElement("pre");
|
|
4641
|
+
const code = document.createElement("code");
|
|
4642
|
+
code.textContent = text || "";
|
|
4643
|
+
pre.appendChild(code);
|
|
4644
|
+
range.deleteContents();
|
|
4645
|
+
range.insertNode(pre);
|
|
4646
|
+
ensureParagraphAfter(pre);
|
|
4647
|
+
placeCaretAtEnd(code);
|
|
4648
|
+
handleInput();
|
|
4649
|
+
};
|
|
4650
|
+
const insertTextAtCaret = (text) => {
|
|
4651
|
+
const sel = window.getSelection();
|
|
4652
|
+
if (!sel || sel.rangeCount === 0) return;
|
|
4653
|
+
const range = sel.getRangeAt(0);
|
|
4654
|
+
range.deleteContents();
|
|
4655
|
+
const node = document.createTextNode(text);
|
|
4656
|
+
range.insertNode(node);
|
|
4657
|
+
range.setStartAfter(node);
|
|
4658
|
+
range.collapse(true);
|
|
4659
|
+
sel.removeAllRanges();
|
|
4660
|
+
sel.addRange(range);
|
|
4661
|
+
handleInput();
|
|
4662
|
+
};
|
|
4663
|
+
const ensureParagraphAfter = (node) => {
|
|
4664
|
+
const next = node.nextElementSibling;
|
|
4665
|
+
if (next && next.tagName === "P") return;
|
|
4666
|
+
const p = document.createElement("p");
|
|
4667
|
+
p.innerHTML = "<br>";
|
|
4668
|
+
node.after(p);
|
|
4669
|
+
};
|
|
4670
|
+
const placeCaretAtEnd = (node) => {
|
|
4671
|
+
const sel = window.getSelection();
|
|
4672
|
+
if (!sel) return;
|
|
4673
|
+
const r2 = document.createRange();
|
|
4674
|
+
r2.selectNodeContents(node);
|
|
4675
|
+
r2.collapse(false);
|
|
4676
|
+
sel.removeAllRanges();
|
|
4677
|
+
sel.addRange(r2);
|
|
4678
|
+
editorRef.current?.focus();
|
|
4679
|
+
};
|
|
4680
|
+
const clearFormat = () => {
|
|
4681
|
+
exec("removeFormat");
|
|
4682
|
+
exec("unlink");
|
|
4683
|
+
setBlock("p");
|
|
4684
|
+
};
|
|
4685
|
+
const indentList = (outdent) => {
|
|
4686
|
+
exec(outdent ? "outdent" : "indent");
|
|
4687
|
+
};
|
|
4688
|
+
const inListItem = () => {
|
|
4689
|
+
const sel = window.getSelection();
|
|
4690
|
+
const node = sel?.anchorNode;
|
|
4691
|
+
if (!node || !editorRef.current?.contains(node)) return false;
|
|
4692
|
+
const el = node.nodeType === Node.ELEMENT_NODE ? node : node.parentElement;
|
|
4693
|
+
return !!el?.closest("li");
|
|
4694
|
+
};
|
|
4695
|
+
const currentBlock = () => {
|
|
4696
|
+
const sel = window.getSelection();
|
|
4697
|
+
const node = sel?.anchorNode;
|
|
4698
|
+
const root = editorRef.current;
|
|
4699
|
+
if (!node || !root?.contains(node)) return null;
|
|
4700
|
+
let el = node.nodeType === Node.ELEMENT_NODE ? node : node.parentElement;
|
|
4701
|
+
while (el && el !== root && !/^(P|H[1-6]|LI|BLOCKQUOTE|PRE|DIV|TD|TH)$/.test(el.tagName)) {
|
|
4702
|
+
el = el.parentElement;
|
|
4703
|
+
}
|
|
4704
|
+
return el && el !== root ? el : null;
|
|
4705
|
+
};
|
|
4706
|
+
const setAlign = (align) => {
|
|
4707
|
+
const block = currentBlock();
|
|
4708
|
+
if (!block) return;
|
|
4709
|
+
pushHistory(true);
|
|
4710
|
+
block.classList.remove("align-left", "align-center", "align-right");
|
|
4711
|
+
if (align !== "left") block.classList.add(`align-${align}`);
|
|
4712
|
+
handleInput();
|
|
4713
|
+
};
|
|
4714
|
+
const toggleChecklist = () => {
|
|
4715
|
+
pushHistory(true);
|
|
4716
|
+
const block = currentBlock();
|
|
4717
|
+
const list = block?.closest("ul");
|
|
4718
|
+
if (list?.classList.contains("checklist")) {
|
|
4719
|
+
list.classList.remove("checklist");
|
|
4720
|
+
list.querySelectorAll("li").forEach((li) => li.removeAttribute("data-checked"));
|
|
4721
|
+
handleInput();
|
|
4722
|
+
return;
|
|
4723
|
+
}
|
|
4724
|
+
if (list) {
|
|
4725
|
+
list.classList.add("checklist");
|
|
4726
|
+
list.querySelectorAll("li").forEach((li) => li.setAttribute("data-checked", "false"));
|
|
4727
|
+
handleInput();
|
|
4728
|
+
return;
|
|
4729
|
+
}
|
|
4730
|
+
exec("insertUnorderedList");
|
|
4731
|
+
const made = currentBlock()?.closest("ul");
|
|
4732
|
+
if (made) {
|
|
4733
|
+
made.classList.add("checklist");
|
|
4734
|
+
made.querySelectorAll("li").forEach((li) => li.setAttribute("data-checked", "false"));
|
|
4735
|
+
}
|
|
4736
|
+
handleInput();
|
|
4737
|
+
};
|
|
4738
|
+
const handleEditorClick = (e) => {
|
|
4739
|
+
if (readOnly) return;
|
|
4740
|
+
const target = e.target;
|
|
4741
|
+
const li = target.closest?.("li");
|
|
4742
|
+
if (!li || !li.closest("ul.checklist")) return;
|
|
4743
|
+
const rect = li.getBoundingClientRect();
|
|
4744
|
+
if (e.clientX - rect.left > 20) return;
|
|
4745
|
+
e.preventDefault();
|
|
4746
|
+
pushHistory(true);
|
|
4747
|
+
li.setAttribute("data-checked", li.getAttribute("data-checked") === "true" ? "false" : "true");
|
|
4748
|
+
handleInput();
|
|
4749
|
+
};
|
|
4750
|
+
const toggleHighlight = () => {
|
|
4751
|
+
const sel = window.getSelection();
|
|
4752
|
+
if (!sel || sel.rangeCount === 0 || sel.isCollapsed) return;
|
|
4753
|
+
pushHistory(true);
|
|
4754
|
+
const range = sel.getRangeAt(0);
|
|
4755
|
+
const node = sel.anchorNode;
|
|
4756
|
+
const el = node?.nodeType === Node.ELEMENT_NODE ? node : node?.parentElement;
|
|
4757
|
+
const existing = el?.closest("mark");
|
|
4758
|
+
if (existing) {
|
|
4759
|
+
const parent = existing.parentNode;
|
|
4760
|
+
while (existing.firstChild) parent?.insertBefore(existing.firstChild, existing);
|
|
4761
|
+
parent?.removeChild(existing);
|
|
4762
|
+
handleInput();
|
|
4763
|
+
return;
|
|
4764
|
+
}
|
|
4765
|
+
const mark = document.createElement("mark");
|
|
4766
|
+
try {
|
|
4767
|
+
range.surroundContents(mark);
|
|
4768
|
+
} catch {
|
|
4769
|
+
const frag = range.extractContents();
|
|
4770
|
+
mark.appendChild(frag);
|
|
4771
|
+
range.insertNode(mark);
|
|
4772
|
+
}
|
|
4773
|
+
handleInput();
|
|
4774
|
+
};
|
|
4775
|
+
const insertTable = (cols = 3, rows = 2) => {
|
|
4776
|
+
const sel = window.getSelection();
|
|
4777
|
+
if (!sel || sel.rangeCount === 0) return;
|
|
4778
|
+
pushHistory(true);
|
|
4779
|
+
const table = document.createElement("table");
|
|
4780
|
+
const thead = document.createElement("thead");
|
|
4781
|
+
const headRow = document.createElement("tr");
|
|
4782
|
+
for (let c = 0; c < cols; c++) {
|
|
4783
|
+
const th = document.createElement("th");
|
|
4784
|
+
th.innerHTML = "<br>";
|
|
4785
|
+
headRow.appendChild(th);
|
|
4786
|
+
}
|
|
4787
|
+
thead.appendChild(headRow);
|
|
4788
|
+
table.appendChild(thead);
|
|
4789
|
+
const tbody = document.createElement("tbody");
|
|
4790
|
+
for (let r2 = 0; r2 < rows; r2++) {
|
|
4791
|
+
const tr = document.createElement("tr");
|
|
4792
|
+
for (let c = 0; c < cols; c++) {
|
|
4793
|
+
const td = document.createElement("td");
|
|
4794
|
+
td.innerHTML = "<br>";
|
|
4795
|
+
tr.appendChild(td);
|
|
4796
|
+
}
|
|
4797
|
+
tbody.appendChild(tr);
|
|
4798
|
+
}
|
|
4799
|
+
table.appendChild(tbody);
|
|
4800
|
+
const range = sel.getRangeAt(0);
|
|
4801
|
+
range.deleteContents();
|
|
4802
|
+
range.insertNode(table);
|
|
4803
|
+
ensureParagraphAfter(table);
|
|
4804
|
+
const first = table.querySelector("th");
|
|
4805
|
+
if (first) placeCaretAtEnd(first);
|
|
4806
|
+
handleInput();
|
|
4807
|
+
};
|
|
4808
|
+
const moveTableCell = (backwards) => {
|
|
4809
|
+
const block = currentBlock();
|
|
4810
|
+
const cell = block?.closest("td, th");
|
|
4811
|
+
if (!cell) return false;
|
|
4812
|
+
const table = cell.closest("table");
|
|
4813
|
+
if (!table) return false;
|
|
4814
|
+
const cells = Array.from(table.querySelectorAll("td, th"));
|
|
4815
|
+
const i = cells.indexOf(cell);
|
|
4816
|
+
const next = cells[i + (backwards ? -1 : 1)];
|
|
4817
|
+
if (next) {
|
|
4818
|
+
placeCaretAtEnd(next);
|
|
4819
|
+
return true;
|
|
4820
|
+
}
|
|
4821
|
+
if (!backwards) {
|
|
4822
|
+
pushHistory(true);
|
|
4823
|
+
const lastRow = table.querySelector("tbody")?.lastElementChild;
|
|
4824
|
+
if (lastRow) {
|
|
4825
|
+
const tr = document.createElement("tr");
|
|
4826
|
+
for (let c = 0; c < lastRow.children.length; c++) {
|
|
4827
|
+
const td = document.createElement("td");
|
|
4828
|
+
td.innerHTML = "<br>";
|
|
4829
|
+
tr.appendChild(td);
|
|
4830
|
+
}
|
|
4831
|
+
lastRow.after(tr);
|
|
4832
|
+
placeCaretAtEnd(tr.firstElementChild);
|
|
4833
|
+
handleInput();
|
|
4834
|
+
return true;
|
|
4835
|
+
}
|
|
4836
|
+
}
|
|
4837
|
+
return false;
|
|
4838
|
+
};
|
|
4138
4839
|
const insertDivider = () => {
|
|
4840
|
+
pushHistory(true);
|
|
4139
4841
|
exec("insertHorizontalRule");
|
|
4140
4842
|
const el = editorRef.current;
|
|
4141
4843
|
if (el && el.lastElementChild?.tagName === "HR") {
|
|
@@ -4181,7 +4883,9 @@ var Editor = (props) => {
|
|
|
4181
4883
|
const range = sel.getRangeAt(0);
|
|
4182
4884
|
slashStartRangeRef.current = range.cloneRange();
|
|
4183
4885
|
const rect = range.getBoundingClientRect();
|
|
4184
|
-
const
|
|
4886
|
+
const editorEl = editorRef.current;
|
|
4887
|
+
if (!editorEl) return;
|
|
4888
|
+
const editorRect = editorEl.getBoundingClientRect();
|
|
4185
4889
|
setSlashPos({
|
|
4186
4890
|
top: rect.bottom - editorRect.top + 4,
|
|
4187
4891
|
left: rect.left - editorRect.left
|
|
@@ -4196,7 +4900,7 @@ var Editor = (props) => {
|
|
|
4196
4900
|
setSlashIdx(0);
|
|
4197
4901
|
slashStartRangeRef.current = null;
|
|
4198
4902
|
};
|
|
4199
|
-
const filteredSlashItems =
|
|
4903
|
+
const filteredSlashItems = import_react22.default.useMemo(() => {
|
|
4200
4904
|
if (!slashFilter) return SLASH_ITEMS;
|
|
4201
4905
|
const f = slashFilter.toLowerCase();
|
|
4202
4906
|
return SLASH_ITEMS.filter((it) => it.label.toLowerCase().includes(f) || it.key.includes(f));
|
|
@@ -4226,8 +4930,14 @@ var Editor = (props) => {
|
|
|
4226
4930
|
case "paragraph":
|
|
4227
4931
|
setBlock("p");
|
|
4228
4932
|
break;
|
|
4229
|
-
case "heading":
|
|
4230
|
-
|
|
4933
|
+
case "heading-1":
|
|
4934
|
+
toggleBlock("h1");
|
|
4935
|
+
break;
|
|
4936
|
+
case "heading-2":
|
|
4937
|
+
toggleBlock("h2");
|
|
4938
|
+
break;
|
|
4939
|
+
case "heading-3":
|
|
4940
|
+
toggleBlock("h3");
|
|
4231
4941
|
break;
|
|
4232
4942
|
case "list":
|
|
4233
4943
|
exec("insertUnorderedList");
|
|
@@ -4239,7 +4949,7 @@ var Editor = (props) => {
|
|
|
4239
4949
|
setBlock("blockquote");
|
|
4240
4950
|
break;
|
|
4241
4951
|
case "code-block":
|
|
4242
|
-
|
|
4952
|
+
insertCodeBlock();
|
|
4243
4953
|
break;
|
|
4244
4954
|
case "divider":
|
|
4245
4955
|
insertDivider();
|
|
@@ -4257,7 +4967,9 @@ var Editor = (props) => {
|
|
|
4257
4967
|
if (!sel || sel.rangeCount === 0) return;
|
|
4258
4968
|
const range = sel.getRangeAt(0);
|
|
4259
4969
|
const rect = range.getBoundingClientRect();
|
|
4260
|
-
const
|
|
4970
|
+
const editorEl2 = editorRef.current;
|
|
4971
|
+
if (!editorEl2) return;
|
|
4972
|
+
const editorRect = editorEl2.getBoundingClientRect();
|
|
4261
4973
|
setLinkPos({
|
|
4262
4974
|
top: rect.bottom - editorRect.top + 4,
|
|
4263
4975
|
left: rect.left - editorRect.left
|
|
@@ -4290,13 +5002,13 @@ var Editor = (props) => {
|
|
|
4290
5002
|
if (node.nodeType !== Node.TEXT_NODE) return false;
|
|
4291
5003
|
const text = (node.textContent || "").slice(0, range.startOffset);
|
|
4292
5004
|
const patterns = [
|
|
4293
|
-
[
|
|
4294
|
-
[
|
|
4295
|
-
[
|
|
4296
|
-
[
|
|
4297
|
-
[
|
|
4298
|
-
[/^1
|
|
4299
|
-
[
|
|
5005
|
+
[/^###$/, () => setBlock("h3")],
|
|
5006
|
+
[/^##$/, () => setBlock("h2")],
|
|
5007
|
+
[/^#$/, () => setBlock("h1")],
|
|
5008
|
+
[/^-$/, () => exec("insertUnorderedList")],
|
|
5009
|
+
[/^\*$/, () => exec("insertUnorderedList")],
|
|
5010
|
+
[/^1\.$/, () => exec("insertOrderedList")],
|
|
5011
|
+
[/^>$/, () => setBlock("blockquote")]
|
|
4300
5012
|
];
|
|
4301
5013
|
for (const [re, fn] of patterns) {
|
|
4302
5014
|
if (re.test(text)) {
|
|
@@ -4316,7 +5028,11 @@ var Editor = (props) => {
|
|
|
4316
5028
|
if (composingRef.current) return;
|
|
4317
5029
|
const el = editorRef.current;
|
|
4318
5030
|
if (!el) return;
|
|
4319
|
-
|
|
5031
|
+
const html = el.innerHTML;
|
|
5032
|
+
lastEmittedRef.current = html;
|
|
5033
|
+
pushHistory();
|
|
5034
|
+
scheduleHighlight();
|
|
5035
|
+
onChange?.(html);
|
|
4320
5036
|
updateEmpty();
|
|
4321
5037
|
updateActiveFormats();
|
|
4322
5038
|
if (slashOpen) {
|
|
@@ -4344,6 +5060,40 @@ var Editor = (props) => {
|
|
|
4344
5060
|
};
|
|
4345
5061
|
const handleKeyDown = (e) => {
|
|
4346
5062
|
if (readOnly) return;
|
|
5063
|
+
if (composingRef.current || e.nativeEvent.isComposing || e.keyCode === 229) return;
|
|
5064
|
+
const pre = closestPre();
|
|
5065
|
+
if (pre && !slashOpen) {
|
|
5066
|
+
if (e.key === "Enter" && !e.shiftKey) {
|
|
5067
|
+
const text = pre.textContent || "";
|
|
5068
|
+
if (text.endsWith("\n\n")) {
|
|
5069
|
+
e.preventDefault();
|
|
5070
|
+
const code = pre.querySelector("code") ?? pre;
|
|
5071
|
+
code.textContent = text.replace(/\n\n$/, "");
|
|
5072
|
+
ensureParagraphAfter(pre);
|
|
5073
|
+
const next = pre.nextElementSibling;
|
|
5074
|
+
if (next) placeCaretAtEnd(next);
|
|
5075
|
+
handleInput();
|
|
5076
|
+
return;
|
|
5077
|
+
}
|
|
5078
|
+
e.preventDefault();
|
|
5079
|
+
insertTextAtCaret("\n");
|
|
5080
|
+
return;
|
|
5081
|
+
}
|
|
5082
|
+
if (e.key === "Tab") {
|
|
5083
|
+
e.preventDefault();
|
|
5084
|
+
insertTextAtCaret(" ");
|
|
5085
|
+
return;
|
|
5086
|
+
}
|
|
5087
|
+
}
|
|
5088
|
+
if (e.key === "Tab" && moveTableCell(e.shiftKey)) {
|
|
5089
|
+
e.preventDefault();
|
|
5090
|
+
return;
|
|
5091
|
+
}
|
|
5092
|
+
if (e.key === "Tab" && inListItem()) {
|
|
5093
|
+
e.preventDefault();
|
|
5094
|
+
indentList(e.shiftKey);
|
|
5095
|
+
return;
|
|
5096
|
+
}
|
|
4347
5097
|
if (slashOpen) {
|
|
4348
5098
|
if (e.key === "ArrowDown") {
|
|
4349
5099
|
e.preventDefault();
|
|
@@ -4367,6 +5117,21 @@ var Editor = (props) => {
|
|
|
4367
5117
|
return;
|
|
4368
5118
|
}
|
|
4369
5119
|
}
|
|
5120
|
+
if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === "z") {
|
|
5121
|
+
e.preventDefault();
|
|
5122
|
+
if (e.shiftKey) redo();
|
|
5123
|
+
else undo();
|
|
5124
|
+
return;
|
|
5125
|
+
}
|
|
5126
|
+
if ((e.metaKey || e.ctrlKey) && e.shiftKey && e.key.toLowerCase() === "v") {
|
|
5127
|
+
plainPasteRef.current = true;
|
|
5128
|
+
return;
|
|
5129
|
+
}
|
|
5130
|
+
if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === "y") {
|
|
5131
|
+
e.preventDefault();
|
|
5132
|
+
redo();
|
|
5133
|
+
return;
|
|
5134
|
+
}
|
|
4370
5135
|
if ((e.metaKey || e.ctrlKey) && !e.shiftKey && !e.altKey) {
|
|
4371
5136
|
const k = e.key.toLowerCase();
|
|
4372
5137
|
if (k === "b") {
|
|
@@ -4390,6 +5155,7 @@ var Editor = (props) => {
|
|
|
4390
5155
|
return;
|
|
4391
5156
|
}
|
|
4392
5157
|
}
|
|
5158
|
+
if (pre) return;
|
|
4393
5159
|
if (enableSlashCommand && e.key === "/") {
|
|
4394
5160
|
setTimeout(openSlashMenu, 0);
|
|
4395
5161
|
}
|
|
@@ -4399,11 +5165,21 @@ var Editor = (props) => {
|
|
|
4399
5165
|
}
|
|
4400
5166
|
}
|
|
4401
5167
|
};
|
|
5168
|
+
const plainPasteRef = import_react22.default.useRef(false);
|
|
4402
5169
|
const handlePaste = (e) => {
|
|
4403
5170
|
if (readOnly) return;
|
|
4404
5171
|
e.preventDefault();
|
|
4405
|
-
const html = e.clipboardData.getData("text/html");
|
|
4406
5172
|
const text = e.clipboardData.getData("text/plain");
|
|
5173
|
+
if (plainPasteRef.current) {
|
|
5174
|
+
plainPasteRef.current = false;
|
|
5175
|
+
insertTextAtCaret(text);
|
|
5176
|
+
return;
|
|
5177
|
+
}
|
|
5178
|
+
if (closestPre()) {
|
|
5179
|
+
insertTextAtCaret(text);
|
|
5180
|
+
return;
|
|
5181
|
+
}
|
|
5182
|
+
const html = e.clipboardData.getData("text/html");
|
|
4407
5183
|
const clean = html ? sanitizeHtml(html) : escapeHtml(text);
|
|
4408
5184
|
document.execCommand("insertHTML", false, clean);
|
|
4409
5185
|
handleInput();
|
|
@@ -4425,8 +5201,11 @@ var Editor = (props) => {
|
|
|
4425
5201
|
};
|
|
4426
5202
|
const handleSelectionUpdate = () => {
|
|
4427
5203
|
updateActiveFormats();
|
|
5204
|
+
const pre = closestPre();
|
|
5205
|
+
setCodeLang(pre ? langOf(pre) : "plain");
|
|
4428
5206
|
};
|
|
4429
5207
|
const onToolbarAction = (item) => {
|
|
5208
|
+
if (closestPre() && !["code-block", "undo", "redo"].includes(item)) return;
|
|
4430
5209
|
switch (item) {
|
|
4431
5210
|
case "bold":
|
|
4432
5211
|
exec("bold");
|
|
@@ -4455,8 +5234,14 @@ var Editor = (props) => {
|
|
|
4455
5234
|
handleInput();
|
|
4456
5235
|
break;
|
|
4457
5236
|
}
|
|
4458
|
-
case "heading":
|
|
4459
|
-
|
|
5237
|
+
case "heading-1":
|
|
5238
|
+
toggleBlock("h1");
|
|
5239
|
+
break;
|
|
5240
|
+
case "heading-2":
|
|
5241
|
+
toggleBlock("h2");
|
|
5242
|
+
break;
|
|
5243
|
+
case "heading-3":
|
|
5244
|
+
toggleBlock("h3");
|
|
4460
5245
|
break;
|
|
4461
5246
|
case "list":
|
|
4462
5247
|
exec("insertUnorderedList");
|
|
@@ -4468,7 +5253,7 @@ var Editor = (props) => {
|
|
|
4468
5253
|
setBlock("blockquote");
|
|
4469
5254
|
break;
|
|
4470
5255
|
case "code-block":
|
|
4471
|
-
|
|
5256
|
+
insertCodeBlock();
|
|
4472
5257
|
break;
|
|
4473
5258
|
case "link":
|
|
4474
5259
|
openLinkEditor();
|
|
@@ -4479,6 +5264,39 @@ var Editor = (props) => {
|
|
|
4479
5264
|
case "divider":
|
|
4480
5265
|
insertDivider();
|
|
4481
5266
|
break;
|
|
5267
|
+
case "checklist":
|
|
5268
|
+
toggleChecklist();
|
|
5269
|
+
break;
|
|
5270
|
+
case "align-left":
|
|
5271
|
+
setAlign("left");
|
|
5272
|
+
break;
|
|
5273
|
+
case "align-center":
|
|
5274
|
+
setAlign("center");
|
|
5275
|
+
break;
|
|
5276
|
+
case "align-right":
|
|
5277
|
+
setAlign("right");
|
|
5278
|
+
break;
|
|
5279
|
+
case "highlight":
|
|
5280
|
+
toggleHighlight();
|
|
5281
|
+
break;
|
|
5282
|
+
case "superscript":
|
|
5283
|
+
exec("superscript");
|
|
5284
|
+
break;
|
|
5285
|
+
case "subscript":
|
|
5286
|
+
exec("subscript");
|
|
5287
|
+
break;
|
|
5288
|
+
case "table":
|
|
5289
|
+
insertTable();
|
|
5290
|
+
break;
|
|
5291
|
+
case "clear-format":
|
|
5292
|
+
clearFormat();
|
|
5293
|
+
break;
|
|
5294
|
+
case "undo":
|
|
5295
|
+
undo();
|
|
5296
|
+
break;
|
|
5297
|
+
case "redo":
|
|
5298
|
+
redo();
|
|
5299
|
+
break;
|
|
4482
5300
|
}
|
|
4483
5301
|
};
|
|
4484
5302
|
return /* @__PURE__ */ (0, import_jsx_runtime323.jsxs)("div", { className: clsx_default("lib-xplat-editor", isFocused && "focused", readOnly && "readonly"), children: [
|
|
@@ -4487,7 +5305,10 @@ var Editor = (props) => {
|
|
|
4487
5305
|
{
|
|
4488
5306
|
items: toolbar,
|
|
4489
5307
|
active: activeFormats,
|
|
4490
|
-
onAction: onToolbarAction
|
|
5308
|
+
onAction: onToolbarAction,
|
|
5309
|
+
codeLang,
|
|
5310
|
+
inCodeBlock: activeFormats.has("block:pre"),
|
|
5311
|
+
onCodeLangChange: changeCodeLang
|
|
4491
5312
|
}
|
|
4492
5313
|
),
|
|
4493
5314
|
/* @__PURE__ */ (0, import_jsx_runtime323.jsxs)("div", { className: "lib-xplat-editor__content", style: { minHeight }, children: [
|
|
@@ -4498,9 +5319,14 @@ var Editor = (props) => {
|
|
|
4498
5319
|
ref: editorRef,
|
|
4499
5320
|
contentEditable: !readOnly,
|
|
4500
5321
|
suppressContentEditableWarning: true,
|
|
5322
|
+
role: "textbox",
|
|
5323
|
+
"aria-multiline": "true",
|
|
5324
|
+
"aria-readonly": readOnly || void 0,
|
|
5325
|
+
"aria-label": placeholder,
|
|
4501
5326
|
className: "lib-xplat-editor__editable",
|
|
4502
5327
|
onInput: handleInput,
|
|
4503
5328
|
onKeyDown: handleKeyDown,
|
|
5329
|
+
onClick: handleEditorClick,
|
|
4504
5330
|
onKeyUp: handleSelectionUpdate,
|
|
4505
5331
|
onMouseUp: handleSelectionUpdate,
|
|
4506
5332
|
onPaste: handlePaste,
|
|
@@ -4542,14 +5368,27 @@ var TOOLBAR_LABEL = {
|
|
|
4542
5368
|
underline: "U",
|
|
4543
5369
|
strikethrough: "S",
|
|
4544
5370
|
code: "<>",
|
|
4545
|
-
heading: "
|
|
5371
|
+
"heading-1": "H1",
|
|
5372
|
+
"heading-2": "H2",
|
|
5373
|
+
"heading-3": "H3",
|
|
4546
5374
|
list: "\u2022",
|
|
4547
5375
|
"ordered-list": "1.",
|
|
4548
5376
|
blockquote: "\u275D",
|
|
4549
5377
|
"code-block": "[ ]",
|
|
4550
5378
|
link: "\u{1F517}",
|
|
4551
5379
|
image: "\u{1F5BC}",
|
|
4552
|
-
divider: "\u2014"
|
|
5380
|
+
divider: "\u2014",
|
|
5381
|
+
checklist: "\u2611",
|
|
5382
|
+
"align-left": "\u21E4",
|
|
5383
|
+
"align-center": "\u2194",
|
|
5384
|
+
"align-right": "\u21E5",
|
|
5385
|
+
highlight: "\u{1F58D}",
|
|
5386
|
+
superscript: "x\xB2",
|
|
5387
|
+
subscript: "x\u2082",
|
|
5388
|
+
table: "\u25A6",
|
|
5389
|
+
"clear-format": "\u232B",
|
|
5390
|
+
undo: "\u21B6",
|
|
5391
|
+
redo: "\u21B7"
|
|
4553
5392
|
};
|
|
4554
5393
|
var TOOLBAR_TITLE = {
|
|
4555
5394
|
bold: "\uAD75\uAC8C (\u2318B)",
|
|
@@ -4557,39 +5396,77 @@ var TOOLBAR_TITLE = {
|
|
|
4557
5396
|
underline: "\uBC11\uC904 (\u2318U)",
|
|
4558
5397
|
strikethrough: "\uCDE8\uC18C\uC120",
|
|
4559
5398
|
code: "\uC778\uB77C\uC778 \uCF54\uB4DC",
|
|
4560
|
-
heading: "\uC81C\uBAA9",
|
|
5399
|
+
"heading-1": "\uC81C\uBAA9 1",
|
|
5400
|
+
"heading-2": "\uC81C\uBAA9 2",
|
|
5401
|
+
"heading-3": "\uC81C\uBAA9 3",
|
|
4561
5402
|
list: "\uAE00\uBA38\uB9AC \uAE30\uD638 \uBAA9\uB85D",
|
|
4562
5403
|
"ordered-list": "\uBC88\uD638 \uB9E4\uAE30\uAE30 \uBAA9\uB85D",
|
|
4563
5404
|
blockquote: "\uC778\uC6A9",
|
|
4564
5405
|
"code-block": "\uCF54\uB4DC \uBE14\uB85D",
|
|
4565
5406
|
link: "\uB9C1\uD06C (\u2318K)",
|
|
4566
5407
|
image: "\uC774\uBBF8\uC9C0",
|
|
4567
|
-
divider: "\uAD6C\uBD84\uC120"
|
|
5408
|
+
divider: "\uAD6C\uBD84\uC120",
|
|
5409
|
+
checklist: "\uCCB4\uD06C\uB9AC\uC2A4\uD2B8",
|
|
5410
|
+
"align-left": "\uC67C\uCABD \uC815\uB82C",
|
|
5411
|
+
"align-center": "\uAC00\uC6B4\uB370 \uC815\uB82C",
|
|
5412
|
+
"align-right": "\uC624\uB978\uCABD \uC815\uB82C",
|
|
5413
|
+
highlight: "\uD615\uAD11\uD39C",
|
|
5414
|
+
superscript: "\uC704 \uCCA8\uC790",
|
|
5415
|
+
subscript: "\uC544\uB798 \uCCA8\uC790",
|
|
5416
|
+
table: "\uD45C \uC0BD\uC785",
|
|
5417
|
+
"clear-format": "\uC11C\uC2DD \uC9C0\uC6B0\uAE30",
|
|
5418
|
+
undo: "\uB418\uB3CC\uB9AC\uAE30 (\u2318Z)",
|
|
5419
|
+
redo: "\uB2E4\uC2DC\uD558\uAE30 (\u2318\u21E7Z)"
|
|
4568
5420
|
};
|
|
4569
5421
|
var isActive = (item, active) => {
|
|
4570
|
-
if (item === "heading") return active.has("block:h1")
|
|
5422
|
+
if (item === "heading-1") return active.has("block:h1");
|
|
5423
|
+
if (item === "heading-2") return active.has("block:h2");
|
|
5424
|
+
if (item === "heading-3") return active.has("block:h3");
|
|
4571
5425
|
if (item === "blockquote") return active.has("block:blockquote");
|
|
4572
5426
|
if (item === "code-block") return active.has("block:pre");
|
|
5427
|
+
if (item === "align-left") return active.has("align:left");
|
|
5428
|
+
if (item === "align-center") return active.has("align:center");
|
|
5429
|
+
if (item === "align-right") return active.has("align:right");
|
|
4573
5430
|
return active.has(item);
|
|
4574
5431
|
};
|
|
4575
|
-
var EditorToolbar = ({
|
|
4576
|
-
|
|
4577
|
-
|
|
4578
|
-
|
|
4579
|
-
|
|
4580
|
-
|
|
4581
|
-
|
|
4582
|
-
|
|
4583
|
-
|
|
4584
|
-
|
|
5432
|
+
var EditorToolbar = ({
|
|
5433
|
+
items,
|
|
5434
|
+
active,
|
|
5435
|
+
onAction,
|
|
5436
|
+
codeLang,
|
|
5437
|
+
inCodeBlock,
|
|
5438
|
+
onCodeLangChange
|
|
5439
|
+
}) => {
|
|
5440
|
+
return /* @__PURE__ */ (0, import_jsx_runtime323.jsxs)("div", { className: "lib-xplat-editor__toolbar", children: [
|
|
5441
|
+
items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime323.jsx)(
|
|
5442
|
+
"button",
|
|
5443
|
+
{
|
|
5444
|
+
type: "button",
|
|
5445
|
+
className: clsx_default("lib-xplat-editor__toolbar-btn", isActive(item, active) && "active"),
|
|
5446
|
+
title: TOOLBAR_TITLE[item],
|
|
5447
|
+
onMouseDown: (e) => {
|
|
5448
|
+
e.preventDefault();
|
|
5449
|
+
onAction(item);
|
|
5450
|
+
},
|
|
5451
|
+
children: TOOLBAR_LABEL[item]
|
|
4585
5452
|
},
|
|
4586
|
-
|
|
4587
|
-
|
|
4588
|
-
|
|
4589
|
-
|
|
5453
|
+
item
|
|
5454
|
+
)),
|
|
5455
|
+
inCodeBlock && /* @__PURE__ */ (0, import_jsx_runtime323.jsx)(
|
|
5456
|
+
"select",
|
|
5457
|
+
{
|
|
5458
|
+
className: "lib-xplat-editor__lang",
|
|
5459
|
+
value: codeLang,
|
|
5460
|
+
"aria-label": "\uCF54\uB4DC \uC5B8\uC5B4",
|
|
5461
|
+
onMouseDown: (e) => e.stopPropagation(),
|
|
5462
|
+
onChange: (e) => onCodeLangChange(e.target.value),
|
|
5463
|
+
children: CODE_LANGUAGES.map((l) => /* @__PURE__ */ (0, import_jsx_runtime323.jsx)("option", { value: l.value, children: l.label }, l.value))
|
|
5464
|
+
}
|
|
5465
|
+
)
|
|
5466
|
+
] });
|
|
4590
5467
|
};
|
|
4591
5468
|
var SlashMenu = ({ position, items, activeIndex, onSelect, onClose }) => {
|
|
4592
|
-
|
|
5469
|
+
import_react22.default.useEffect(() => {
|
|
4593
5470
|
const handleClickOutside = (e) => {
|
|
4594
5471
|
const target = e.target;
|
|
4595
5472
|
const menu = document.querySelector(".lib-xplat-editor__slash-menu");
|
|
@@ -4623,8 +5500,8 @@ var SlashMenu = ({ position, items, activeIndex, onSelect, onClose }) => {
|
|
|
4623
5500
|
);
|
|
4624
5501
|
};
|
|
4625
5502
|
var LinkPopover = ({ position, value, onChange, onConfirm, onClose }) => {
|
|
4626
|
-
const inputRef =
|
|
4627
|
-
|
|
5503
|
+
const inputRef = import_react22.default.useRef(null);
|
|
5504
|
+
import_react22.default.useEffect(() => {
|
|
4628
5505
|
inputRef.current?.focus();
|
|
4629
5506
|
}, []);
|
|
4630
5507
|
return /* @__PURE__ */ (0, import_jsx_runtime323.jsxs)(
|
|
@@ -4682,7 +5559,7 @@ EmptyState.displayName = "EmptyState";
|
|
|
4682
5559
|
var EmptyState_default = EmptyState;
|
|
4683
5560
|
|
|
4684
5561
|
// src/components/FileUpload/FileUpload.tsx
|
|
4685
|
-
var
|
|
5562
|
+
var import_react23 = __toESM(require("react"), 1);
|
|
4686
5563
|
var import_jsx_runtime325 = require("react/jsx-runtime");
|
|
4687
5564
|
var FileUpload = (props) => {
|
|
4688
5565
|
const {
|
|
@@ -4694,8 +5571,8 @@ var FileUpload = (props) => {
|
|
|
4694
5571
|
description,
|
|
4695
5572
|
validations
|
|
4696
5573
|
} = props;
|
|
4697
|
-
const [isDragOver, setIsDragOver] =
|
|
4698
|
-
const inputRef =
|
|
5574
|
+
const [isDragOver, setIsDragOver] = import_react23.default.useState(false);
|
|
5575
|
+
const inputRef = import_react23.default.useRef(null);
|
|
4699
5576
|
const handleFiles = (fileList) => {
|
|
4700
5577
|
let files = Array.from(fileList);
|
|
4701
5578
|
if (maxSize) {
|
|
@@ -4757,10 +5634,10 @@ FileUpload.displayName = "FileUpload";
|
|
|
4757
5634
|
var FileUpload_default = FileUpload;
|
|
4758
5635
|
|
|
4759
5636
|
// src/components/HtmlTypeWriter/HtmlTypeWriter.tsx
|
|
4760
|
-
var
|
|
5637
|
+
var import_react25 = __toESM(require("react"), 1);
|
|
4761
5638
|
|
|
4762
5639
|
// src/components/HtmlTypeWriter/utils.ts
|
|
4763
|
-
var
|
|
5640
|
+
var import_react24 = __toESM(require("react"), 1);
|
|
4764
5641
|
var voidTags = /* @__PURE__ */ new Set([
|
|
4765
5642
|
"br",
|
|
4766
5643
|
"img",
|
|
@@ -4828,15 +5705,15 @@ var convertNodeToReactWithRange = (node, typedLen, rangeMap) => {
|
|
|
4828
5705
|
props[attr.name] = attr.value;
|
|
4829
5706
|
});
|
|
4830
5707
|
if (voidTags.has(tag)) {
|
|
4831
|
-
return
|
|
5708
|
+
return import_react24.default.createElement(tag, props);
|
|
4832
5709
|
}
|
|
4833
5710
|
const children = Array.from(element.childNodes).map((child) => convertNodeToReactWithRange(child, typedLen, rangeMap)).filter((n) => n != null);
|
|
4834
|
-
return
|
|
5711
|
+
return import_react24.default.createElement(tag, props, ...children);
|
|
4835
5712
|
};
|
|
4836
5713
|
var htmlToReactProgressive = (root, typedLen, rangeMap) => {
|
|
4837
5714
|
const nodes = Array.from(root.childNodes).map((child, idx) => {
|
|
4838
5715
|
const node = convertNodeToReactWithRange(child, typedLen, rangeMap);
|
|
4839
|
-
return node == null ? null :
|
|
5716
|
+
return node == null ? null : import_react24.default.createElement(import_react24.default.Fragment, { key: idx }, node);
|
|
4840
5717
|
}).filter(Boolean);
|
|
4841
5718
|
return nodes.length === 0 ? null : nodes;
|
|
4842
5719
|
};
|
|
@@ -4849,20 +5726,20 @@ var HtmlTypeWriter = ({
|
|
|
4849
5726
|
onDone,
|
|
4850
5727
|
onChange
|
|
4851
5728
|
}) => {
|
|
4852
|
-
const [typedLen, setTypedLen] =
|
|
4853
|
-
const doneCalledRef =
|
|
4854
|
-
const { doc, rangeMap, totalLength } =
|
|
5729
|
+
const [typedLen, setTypedLen] = import_react25.default.useState(0);
|
|
5730
|
+
const doneCalledRef = import_react25.default.useRef(false);
|
|
5731
|
+
const { doc, rangeMap, totalLength } = import_react25.default.useMemo(() => {
|
|
4855
5732
|
if (typeof window === "undefined") return { doc: null, rangeMap: /* @__PURE__ */ new Map(), totalLength: 0 };
|
|
4856
5733
|
const decoded = decodeHtmlEntities(html);
|
|
4857
5734
|
const doc2 = new DOMParser().parseFromString(decoded, "text/html");
|
|
4858
5735
|
const { rangeMap: rangeMap2, totalLength: totalLength2 } = buildRangeMap(doc2.body);
|
|
4859
5736
|
return { doc: doc2, rangeMap: rangeMap2, totalLength: totalLength2 };
|
|
4860
5737
|
}, [html]);
|
|
4861
|
-
|
|
5738
|
+
import_react25.default.useEffect(() => {
|
|
4862
5739
|
setTypedLen(0);
|
|
4863
5740
|
doneCalledRef.current = false;
|
|
4864
5741
|
}, [html]);
|
|
4865
|
-
|
|
5742
|
+
import_react25.default.useEffect(() => {
|
|
4866
5743
|
if (!totalLength) return;
|
|
4867
5744
|
if (typedLen >= totalLength) return;
|
|
4868
5745
|
const timer = window.setInterval(() => {
|
|
@@ -4870,18 +5747,18 @@ var HtmlTypeWriter = ({
|
|
|
4870
5747
|
}, duration);
|
|
4871
5748
|
return () => window.clearInterval(timer);
|
|
4872
5749
|
}, [typedLen, totalLength, duration]);
|
|
4873
|
-
|
|
5750
|
+
import_react25.default.useEffect(() => {
|
|
4874
5751
|
if (typedLen > 0 && typedLen < totalLength) {
|
|
4875
5752
|
onChange?.();
|
|
4876
5753
|
}
|
|
4877
5754
|
}, [typedLen, totalLength, onChange]);
|
|
4878
|
-
|
|
5755
|
+
import_react25.default.useEffect(() => {
|
|
4879
5756
|
if (typedLen === totalLength && totalLength > 0 && !doneCalledRef.current) {
|
|
4880
5757
|
doneCalledRef.current = true;
|
|
4881
5758
|
onDone?.();
|
|
4882
5759
|
}
|
|
4883
5760
|
}, [typedLen, totalLength, onDone]);
|
|
4884
|
-
const parsed =
|
|
5761
|
+
const parsed = import_react25.default.useMemo(
|
|
4885
5762
|
() => doc ? htmlToReactProgressive(doc.body, typedLen, rangeMap) : null,
|
|
4886
5763
|
[doc, typedLen, rangeMap]
|
|
4887
5764
|
);
|
|
@@ -4891,12 +5768,12 @@ HtmlTypeWriter.displayName = "HtmlTypeWriter";
|
|
|
4891
5768
|
var HtmlTypeWriter_default = HtmlTypeWriter;
|
|
4892
5769
|
|
|
4893
5770
|
// src/components/ImageSelector/ImageSelector.tsx
|
|
4894
|
-
var
|
|
5771
|
+
var import_react26 = __toESM(require("react"), 1);
|
|
4895
5772
|
var import_jsx_runtime327 = require("react/jsx-runtime");
|
|
4896
5773
|
var ImageSelector = (props) => {
|
|
4897
5774
|
const { value, label, onChange, validations } = props;
|
|
4898
|
-
const [previewUrl, setPreviewUrl] =
|
|
4899
|
-
|
|
5775
|
+
const [previewUrl, setPreviewUrl] = import_react26.default.useState();
|
|
5776
|
+
import_react26.default.useEffect(() => {
|
|
4900
5777
|
if (!value) {
|
|
4901
5778
|
setPreviewUrl(void 0);
|
|
4902
5779
|
return;
|
|
@@ -4905,7 +5782,7 @@ var ImageSelector = (props) => {
|
|
|
4905
5782
|
setPreviewUrl(url);
|
|
4906
5783
|
return () => URL.revokeObjectURL(url);
|
|
4907
5784
|
}, [value]);
|
|
4908
|
-
const inputRef =
|
|
5785
|
+
const inputRef = import_react26.default.useRef(null);
|
|
4909
5786
|
const handleFileChange = (e) => {
|
|
4910
5787
|
const selectedFile = e.target.files?.[0];
|
|
4911
5788
|
if (selectedFile) {
|
|
@@ -5088,17 +5965,21 @@ Pagination.displayName = "Pagination";
|
|
|
5088
5965
|
var Pagination_default = Pagination;
|
|
5089
5966
|
|
|
5090
5967
|
// src/components/PopOver/PopOver.tsx
|
|
5091
|
-
var
|
|
5968
|
+
var import_react27 = __toESM(require("react"), 1);
|
|
5092
5969
|
var import_jsx_runtime332 = require("react/jsx-runtime");
|
|
5093
5970
|
var PopOver = (props) => {
|
|
5094
5971
|
const { children, isOpen, onClose, PopOverEl } = props;
|
|
5095
|
-
const popRef =
|
|
5096
|
-
const triggerRef =
|
|
5097
|
-
const [localOpen, setLocalOpen] =
|
|
5098
|
-
const [eventTrigger, setEventTrigger] =
|
|
5972
|
+
const popRef = import_react27.default.useRef(null);
|
|
5973
|
+
const triggerRef = import_react27.default.useRef(null);
|
|
5974
|
+
const [localOpen, setLocalOpen] = import_react27.default.useState(false);
|
|
5975
|
+
const [eventTrigger, setEventTrigger] = import_react27.default.useState(false);
|
|
5099
5976
|
useClickOutside_default([popRef, triggerRef], onClose, isOpen);
|
|
5977
|
+
useEscapeKey(isOpen, () => {
|
|
5978
|
+
onClose();
|
|
5979
|
+
triggerRef.current?.focus({ preventScroll: true });
|
|
5980
|
+
});
|
|
5100
5981
|
const position = useAutoPosition_default(triggerRef, popRef, localOpen);
|
|
5101
|
-
|
|
5982
|
+
import_react27.default.useEffect(() => {
|
|
5102
5983
|
if (isOpen) {
|
|
5103
5984
|
setLocalOpen(isOpen);
|
|
5104
5985
|
setTimeout(() => {
|
|
@@ -5127,6 +6008,7 @@ var PopOver = (props) => {
|
|
|
5127
6008
|
className: clsx_default(
|
|
5128
6009
|
"lib-xplat-pop-over-content",
|
|
5129
6010
|
position.direction,
|
|
6011
|
+
position.repositioning && "repositioning",
|
|
5130
6012
|
eventTrigger && "visible"
|
|
5131
6013
|
),
|
|
5132
6014
|
ref: popRef,
|
|
@@ -5183,12 +6065,12 @@ Progress.displayName = "Progress";
|
|
|
5183
6065
|
var Progress_default = Progress;
|
|
5184
6066
|
|
|
5185
6067
|
// src/components/Radio/RadioGroupContext.tsx
|
|
5186
|
-
var
|
|
5187
|
-
var RadioGroupContext =
|
|
6068
|
+
var import_react28 = __toESM(require("react"), 1);
|
|
6069
|
+
var RadioGroupContext = import_react28.default.createContext(
|
|
5188
6070
|
null
|
|
5189
6071
|
);
|
|
5190
6072
|
var useRadioGroupContext = () => {
|
|
5191
|
-
return
|
|
6073
|
+
return import_react28.default.useContext(RadioGroupContext);
|
|
5192
6074
|
};
|
|
5193
6075
|
var RadioGroupContext_default = RadioGroupContext;
|
|
5194
6076
|
|
|
@@ -5264,19 +6146,19 @@ RadioGroup.displayName = "RadioGroup";
|
|
|
5264
6146
|
var RadioGroup_default = RadioGroup;
|
|
5265
6147
|
|
|
5266
6148
|
// src/components/Select/Select.tsx
|
|
5267
|
-
var
|
|
6149
|
+
var import_react31 = __toESM(require("react"), 1);
|
|
5268
6150
|
|
|
5269
6151
|
// src/components/Select/context.ts
|
|
5270
|
-
var
|
|
5271
|
-
var SelectContext =
|
|
6152
|
+
var import_react29 = __toESM(require("react"), 1);
|
|
6153
|
+
var SelectContext = import_react29.default.createContext(null);
|
|
5272
6154
|
var context_default = SelectContext;
|
|
5273
6155
|
|
|
5274
6156
|
// src/components/Select/SelectItem.tsx
|
|
5275
|
-
var
|
|
6157
|
+
var import_react30 = __toESM(require("react"), 1);
|
|
5276
6158
|
var import_jsx_runtime336 = require("react/jsx-runtime");
|
|
5277
6159
|
var SelectItem = (props) => {
|
|
5278
6160
|
const { children, value, onClick, disabled = false } = props;
|
|
5279
|
-
const ctx =
|
|
6161
|
+
const ctx = import_react30.default.useContext(context_default);
|
|
5280
6162
|
const handleClick = (e) => {
|
|
5281
6163
|
e.preventDefault();
|
|
5282
6164
|
e.stopPropagation();
|
|
@@ -5316,32 +6198,37 @@ var SelectRoot = (props) => {
|
|
|
5316
6198
|
onChange,
|
|
5317
6199
|
children,
|
|
5318
6200
|
disabled = false,
|
|
6201
|
+
searchable = false,
|
|
6202
|
+
searchPlaceholder = "\uAC80\uC0C9",
|
|
5319
6203
|
error = false,
|
|
5320
6204
|
validations,
|
|
6205
|
+
label,
|
|
6206
|
+
required,
|
|
5321
6207
|
size = "md"
|
|
5322
6208
|
} = props;
|
|
5323
|
-
const
|
|
5324
|
-
|
|
6209
|
+
const fieldId = import_react31.default.useId();
|
|
6210
|
+
const itemChildren = import_react31.default.Children.toArray(children).filter(
|
|
6211
|
+
(child) => import_react31.default.isValidElement(child) && child.type === SelectItem_default
|
|
5325
6212
|
);
|
|
5326
6213
|
const isControlled = valueProp !== void 0;
|
|
5327
|
-
const [isOpen, setOpen] =
|
|
5328
|
-
const [uncontrolledLabel, setUncontrolledLabel] =
|
|
5329
|
-
const [uncontrolledValue, setUncontrolledValue] =
|
|
5330
|
-
const controlledLabel =
|
|
6214
|
+
const [isOpen, setOpen] = import_react31.default.useState(false);
|
|
6215
|
+
const [uncontrolledLabel, setUncontrolledLabel] = import_react31.default.useState(null);
|
|
6216
|
+
const [uncontrolledValue, setUncontrolledValue] = import_react31.default.useState(void 0);
|
|
6217
|
+
const controlledLabel = import_react31.default.useMemo(() => {
|
|
5331
6218
|
if (!isControlled) return null;
|
|
5332
6219
|
const match = itemChildren.find((child) => child.props.value === valueProp);
|
|
5333
6220
|
return match ? match.props.children : null;
|
|
5334
6221
|
}, [isControlled, valueProp, itemChildren]);
|
|
5335
6222
|
const selectedLabel = isControlled ? controlledLabel : uncontrolledLabel;
|
|
5336
6223
|
const selectedValue = isControlled ? valueProp : uncontrolledValue;
|
|
5337
|
-
const triggerRef =
|
|
5338
|
-
const contentRef =
|
|
5339
|
-
const [mounted, setMounted] =
|
|
5340
|
-
const [visible, setVisible] =
|
|
5341
|
-
|
|
6224
|
+
const triggerRef = import_react31.default.useRef(null);
|
|
6225
|
+
const contentRef = import_react31.default.useRef(null);
|
|
6226
|
+
const [mounted, setMounted] = import_react31.default.useState(false);
|
|
6227
|
+
const [visible, setVisible] = import_react31.default.useState(false);
|
|
6228
|
+
import_react31.default.useEffect(() => {
|
|
5342
6229
|
if (disabled && isOpen) setOpen(false);
|
|
5343
6230
|
}, [disabled, isOpen]);
|
|
5344
|
-
|
|
6231
|
+
import_react31.default.useEffect(() => {
|
|
5345
6232
|
if (isOpen) {
|
|
5346
6233
|
setMounted(true);
|
|
5347
6234
|
const t2 = setTimeout(() => setVisible(true), 1);
|
|
@@ -5351,22 +6238,42 @@ var SelectRoot = (props) => {
|
|
|
5351
6238
|
const t = setTimeout(() => setMounted(false), ANIMATION_DURATION_MS3);
|
|
5352
6239
|
return () => clearTimeout(t);
|
|
5353
6240
|
}, [isOpen]);
|
|
5354
|
-
const
|
|
5355
|
-
const
|
|
5356
|
-
|
|
6241
|
+
const [query, setQuery] = import_react31.default.useState("");
|
|
6242
|
+
const textOf = (node) => {
|
|
6243
|
+
if (node === null || node === void 0 || typeof node === "boolean") return "";
|
|
6244
|
+
if (typeof node === "string" || typeof node === "number") return String(node);
|
|
6245
|
+
if (Array.isArray(node)) return node.map(textOf).join("");
|
|
6246
|
+
if (import_react31.default.isValidElement(node)) return textOf(node.props.children);
|
|
6247
|
+
return "";
|
|
6248
|
+
};
|
|
6249
|
+
const visibleItems = import_react31.default.useMemo(() => {
|
|
6250
|
+
if (!searchable || !query.trim()) return itemChildren;
|
|
6251
|
+
const q = query.trim().toLowerCase();
|
|
6252
|
+
return itemChildren.filter((c) => textOf(c.props.children).toLowerCase().includes(q));
|
|
6253
|
+
}, [searchable, query, itemChildren]);
|
|
6254
|
+
const open = import_react31.default.useCallback(() => setOpen(true), []);
|
|
6255
|
+
const close = import_react31.default.useCallback(() => {
|
|
6256
|
+
setOpen(false);
|
|
6257
|
+
setQuery("");
|
|
6258
|
+
}, []);
|
|
6259
|
+
const toggle = import_react31.default.useCallback(() => setOpen((prev) => !prev), []);
|
|
5357
6260
|
useClickOutside_default([contentRef, triggerRef], close, isOpen);
|
|
6261
|
+
useEscapeKey(isOpen, () => {
|
|
6262
|
+
close();
|
|
6263
|
+
triggerRef.current?.focus({ preventScroll: true });
|
|
6264
|
+
});
|
|
5358
6265
|
const position = useAutoPosition_default(triggerRef, contentRef, mounted);
|
|
5359
|
-
const setSelected =
|
|
5360
|
-
(
|
|
6266
|
+
const setSelected = import_react31.default.useCallback(
|
|
6267
|
+
(label2, itemValue) => {
|
|
5361
6268
|
if (!isControlled) {
|
|
5362
|
-
setUncontrolledLabel(
|
|
6269
|
+
setUncontrolledLabel(label2);
|
|
5363
6270
|
setUncontrolledValue(itemValue);
|
|
5364
6271
|
}
|
|
5365
|
-
onChange?.(itemValue,
|
|
6272
|
+
onChange?.(itemValue, label2);
|
|
5366
6273
|
},
|
|
5367
6274
|
[isControlled, onChange]
|
|
5368
6275
|
);
|
|
5369
|
-
const ctxValue =
|
|
6276
|
+
const ctxValue = import_react31.default.useMemo(
|
|
5370
6277
|
() => ({
|
|
5371
6278
|
isOpen,
|
|
5372
6279
|
mounted,
|
|
@@ -5402,6 +6309,7 @@ var SelectRoot = (props) => {
|
|
|
5402
6309
|
/* @__PURE__ */ (0, import_jsx_runtime337.jsxs)(
|
|
5403
6310
|
"div",
|
|
5404
6311
|
{
|
|
6312
|
+
id: fieldId,
|
|
5405
6313
|
ref: triggerRef,
|
|
5406
6314
|
className: clsx_default(
|
|
5407
6315
|
"select-trigger",
|
|
@@ -5444,20 +6352,33 @@ var SelectRoot = (props) => {
|
|
|
5444
6352
|
]
|
|
5445
6353
|
}
|
|
5446
6354
|
),
|
|
5447
|
-
mounted && /* @__PURE__ */ (0, import_jsx_runtime337.jsx)(Portal_default, { children: /* @__PURE__ */ (0, import_jsx_runtime337.
|
|
6355
|
+
mounted && /* @__PURE__ */ (0, import_jsx_runtime337.jsx)(Portal_default, { children: /* @__PURE__ */ (0, import_jsx_runtime337.jsxs)(
|
|
5448
6356
|
"div",
|
|
5449
6357
|
{
|
|
5450
|
-
className: clsx_default("lib-xplat-select-content", size, position.direction, stateClass),
|
|
6358
|
+
className: clsx_default("lib-xplat-select-content", size, position.direction, stateClass, position.repositioning && "repositioning"),
|
|
5451
6359
|
ref: contentRef,
|
|
5452
6360
|
style: { ...position.position, width: triggerRef.current?.offsetWidth },
|
|
5453
6361
|
role: "listbox",
|
|
5454
|
-
children:
|
|
6362
|
+
children: [
|
|
6363
|
+
searchable && /* @__PURE__ */ (0, import_jsx_runtime337.jsx)("div", { className: "select-search", children: /* @__PURE__ */ (0, import_jsx_runtime337.jsx)(
|
|
6364
|
+
"input",
|
|
6365
|
+
{
|
|
6366
|
+
type: "text",
|
|
6367
|
+
value: query,
|
|
6368
|
+
placeholder: searchPlaceholder,
|
|
6369
|
+
onChange: (e) => setQuery(e.target.value),
|
|
6370
|
+
autoFocus: true,
|
|
6371
|
+
"aria-label": searchPlaceholder
|
|
6372
|
+
}
|
|
6373
|
+
) }),
|
|
6374
|
+
/* @__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" }) })
|
|
6375
|
+
]
|
|
5455
6376
|
}
|
|
5456
6377
|
) })
|
|
5457
6378
|
]
|
|
5458
6379
|
}
|
|
5459
6380
|
) });
|
|
5460
|
-
return /* @__PURE__ */ (0, import_jsx_runtime337.jsx)(Field, { validations, children: control });
|
|
6381
|
+
return /* @__PURE__ */ (0, import_jsx_runtime337.jsx)(Field, { validations, label, required, htmlFor: fieldId, children: control });
|
|
5461
6382
|
};
|
|
5462
6383
|
SelectRoot.displayName = "Select";
|
|
5463
6384
|
var Select = Object.assign(SelectRoot, {
|
|
@@ -5537,8 +6458,44 @@ var Spinner = (props) => {
|
|
|
5537
6458
|
Spinner.displayName = "Spinner";
|
|
5538
6459
|
var Spinner_default = Spinner;
|
|
5539
6460
|
|
|
5540
|
-
// src/components/
|
|
6461
|
+
// src/components/Stat/Stat.tsx
|
|
5541
6462
|
var import_jsx_runtime340 = require("react/jsx-runtime");
|
|
6463
|
+
var ARROW = {
|
|
6464
|
+
up: "\u25B2",
|
|
6465
|
+
down: "\u25BC",
|
|
6466
|
+
flat: "\u2014"
|
|
6467
|
+
};
|
|
6468
|
+
var Stat = (props) => {
|
|
6469
|
+
const {
|
|
6470
|
+
label,
|
|
6471
|
+
value,
|
|
6472
|
+
unit,
|
|
6473
|
+
description,
|
|
6474
|
+
trend,
|
|
6475
|
+
icon,
|
|
6476
|
+
size = "md",
|
|
6477
|
+
type = "primary"
|
|
6478
|
+
} = props;
|
|
6479
|
+
const statusType = normalizeStatus(type);
|
|
6480
|
+
return /* @__PURE__ */ (0, import_jsx_runtime340.jsxs)("div", { className: clsx_default("lib-xplat-stat", size, statusType), children: [
|
|
6481
|
+
/* @__PURE__ */ (0, import_jsx_runtime340.jsx)("div", { className: "stat-label", children: label }),
|
|
6482
|
+
/* @__PURE__ */ (0, import_jsx_runtime340.jsxs)("div", { className: "stat-value-row", children: [
|
|
6483
|
+
icon && /* @__PURE__ */ (0, import_jsx_runtime340.jsx)("span", { className: "stat-icon", children: icon }),
|
|
6484
|
+
/* @__PURE__ */ (0, import_jsx_runtime340.jsx)("span", { className: "stat-value", children: value }),
|
|
6485
|
+
unit && /* @__PURE__ */ (0, import_jsx_runtime340.jsx)("span", { className: "stat-unit", children: unit }),
|
|
6486
|
+
trend && /* @__PURE__ */ (0, import_jsx_runtime340.jsxs)("span", { className: clsx_default("stat-trend", trend.direction), children: [
|
|
6487
|
+
/* @__PURE__ */ (0, import_jsx_runtime340.jsx)("span", { "aria-hidden": "true", children: ARROW[trend.direction] }),
|
|
6488
|
+
trend.value
|
|
6489
|
+
] })
|
|
6490
|
+
] }),
|
|
6491
|
+
description && /* @__PURE__ */ (0, import_jsx_runtime340.jsx)("div", { className: "stat-description", children: description })
|
|
6492
|
+
] });
|
|
6493
|
+
};
|
|
6494
|
+
Stat.displayName = "Stat";
|
|
6495
|
+
var Stat_default = Stat;
|
|
6496
|
+
|
|
6497
|
+
// src/components/Steps/Steps.tsx
|
|
6498
|
+
var import_jsx_runtime341 = require("react/jsx-runtime");
|
|
5542
6499
|
var Steps = (props) => {
|
|
5543
6500
|
const {
|
|
5544
6501
|
items,
|
|
@@ -5546,13 +6503,13 @@ var Steps = (props) => {
|
|
|
5546
6503
|
type = "primary"
|
|
5547
6504
|
} = props;
|
|
5548
6505
|
const statusType = normalizeStatus(type);
|
|
5549
|
-
return /* @__PURE__ */ (0,
|
|
6506
|
+
return /* @__PURE__ */ (0, import_jsx_runtime341.jsx)("div", { className: clsx_default("lib-xplat-steps", statusType), children: items.map((item, index) => {
|
|
5550
6507
|
const status = index < current ? "completed" : index === current ? "active" : "pending";
|
|
5551
|
-
return /* @__PURE__ */ (0,
|
|
5552
|
-
/* @__PURE__ */ (0,
|
|
5553
|
-
/* @__PURE__ */ (0,
|
|
5554
|
-
/* @__PURE__ */ (0,
|
|
5555
|
-
item.description && /* @__PURE__ */ (0,
|
|
6508
|
+
return /* @__PURE__ */ (0, import_jsx_runtime341.jsxs)("div", { className: clsx_default("step-item", status), children: [
|
|
6509
|
+
/* @__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 }) }),
|
|
6510
|
+
/* @__PURE__ */ (0, import_jsx_runtime341.jsxs)("div", { className: "step-content", children: [
|
|
6511
|
+
/* @__PURE__ */ (0, import_jsx_runtime341.jsx)("span", { className: "step-title", children: item.title }),
|
|
6512
|
+
item.description && /* @__PURE__ */ (0, import_jsx_runtime341.jsx)("span", { className: "step-description", children: item.description })
|
|
5556
6513
|
] })
|
|
5557
6514
|
] }, index);
|
|
5558
6515
|
}) });
|
|
@@ -5561,8 +6518,8 @@ Steps.displayName = "Steps";
|
|
|
5561
6518
|
var Steps_default = Steps;
|
|
5562
6519
|
|
|
5563
6520
|
// src/components/Swiper/Swiper.tsx
|
|
5564
|
-
var
|
|
5565
|
-
var
|
|
6521
|
+
var import_react32 = __toESM(require("react"), 1);
|
|
6522
|
+
var import_jsx_runtime342 = require("react/jsx-runtime");
|
|
5566
6523
|
var Swiper = (props) => {
|
|
5567
6524
|
const {
|
|
5568
6525
|
auto = false,
|
|
@@ -5586,26 +6543,26 @@ var Swiper = (props) => {
|
|
|
5586
6543
|
const maxIndex = Math.max(0, totalSlides - viewItemCount);
|
|
5587
6544
|
const useLoop = loop && canSlide;
|
|
5588
6545
|
const cloneCount = useLoop ? totalSlides : 0;
|
|
5589
|
-
const extendedItems =
|
|
6546
|
+
const extendedItems = import_react32.default.useMemo(() => {
|
|
5590
6547
|
if (!useLoop) return items;
|
|
5591
6548
|
return [...items, ...items, ...items];
|
|
5592
6549
|
}, [items, useLoop]);
|
|
5593
6550
|
const initialIdx = Math.max(0, Math.min(indexProp ?? 0, maxIndex));
|
|
5594
|
-
const [innerIndex, setInnerIndex] =
|
|
6551
|
+
const [innerIndex, setInnerIndex] = import_react32.default.useState(
|
|
5595
6552
|
useLoop ? cloneCount + initialIdx : initialIdx
|
|
5596
6553
|
);
|
|
5597
|
-
const [isDragging, setIsDragging] =
|
|
5598
|
-
const [dragOffset, setDragOffset] =
|
|
5599
|
-
const [animated, setAnimated] =
|
|
5600
|
-
const [containerWidth, setContainerWidth] =
|
|
5601
|
-
const containerRef =
|
|
5602
|
-
const startXRef =
|
|
5603
|
-
const startTimeRef =
|
|
5604
|
-
const autoplayTimerRef =
|
|
5605
|
-
const resumeTimeoutRef =
|
|
5606
|
-
const [paused, setPaused] =
|
|
5607
|
-
const initializedRef =
|
|
5608
|
-
|
|
6554
|
+
const [isDragging, setIsDragging] = import_react32.default.useState(false);
|
|
6555
|
+
const [dragOffset, setDragOffset] = import_react32.default.useState(0);
|
|
6556
|
+
const [animated, setAnimated] = import_react32.default.useState(false);
|
|
6557
|
+
const [containerWidth, setContainerWidth] = import_react32.default.useState(0);
|
|
6558
|
+
const containerRef = import_react32.default.useRef(null);
|
|
6559
|
+
const startXRef = import_react32.default.useRef(0);
|
|
6560
|
+
const startTimeRef = import_react32.default.useRef(0);
|
|
6561
|
+
const autoplayTimerRef = import_react32.default.useRef(null);
|
|
6562
|
+
const resumeTimeoutRef = import_react32.default.useRef(null);
|
|
6563
|
+
const [paused, setPaused] = import_react32.default.useState(false);
|
|
6564
|
+
const initializedRef = import_react32.default.useRef(false);
|
|
6565
|
+
import_react32.default.useEffect(() => {
|
|
5609
6566
|
const el = containerRef.current;
|
|
5610
6567
|
if (!el) return;
|
|
5611
6568
|
const ro = new ResizeObserver((entries) => {
|
|
@@ -5628,7 +6585,7 @@ var Swiper = (props) => {
|
|
|
5628
6585
|
return ((inner - cloneCount) % totalSlides + totalSlides) % totalSlides;
|
|
5629
6586
|
};
|
|
5630
6587
|
const realIndex = getRealIndex(innerIndex);
|
|
5631
|
-
const moveToInner =
|
|
6588
|
+
const moveToInner = import_react32.default.useCallback(
|
|
5632
6589
|
(idx, withAnim = true) => {
|
|
5633
6590
|
if (!useLoop) {
|
|
5634
6591
|
setAnimated(withAnim);
|
|
@@ -5656,7 +6613,7 @@ var Swiper = (props) => {
|
|
|
5656
6613
|
},
|
|
5657
6614
|
[useLoop, cloneCount, totalSlides]
|
|
5658
6615
|
);
|
|
5659
|
-
const handleTransitionEnd =
|
|
6616
|
+
const handleTransitionEnd = import_react32.default.useCallback(() => {
|
|
5660
6617
|
if (!useLoop) return;
|
|
5661
6618
|
const real = getRealIndex(innerIndex);
|
|
5662
6619
|
const canonical = cloneCount + real;
|
|
@@ -5666,7 +6623,7 @@ var Swiper = (props) => {
|
|
|
5666
6623
|
}
|
|
5667
6624
|
onChange?.(Math.min(real, maxIndex));
|
|
5668
6625
|
}, [useLoop, innerIndex, cloneCount, totalSlides, maxIndex, onChange]);
|
|
5669
|
-
const slideTo =
|
|
6626
|
+
const slideTo = import_react32.default.useCallback(
|
|
5670
6627
|
(logicalIndex) => {
|
|
5671
6628
|
if (!canSlide) return;
|
|
5672
6629
|
const clamped = useLoop ? logicalIndex : Math.max(0, Math.min(logicalIndex, maxIndex));
|
|
@@ -5676,7 +6633,7 @@ var Swiper = (props) => {
|
|
|
5676
6633
|
},
|
|
5677
6634
|
[canSlide, useLoop, cloneCount, maxIndex, onChange, moveToInner]
|
|
5678
6635
|
);
|
|
5679
|
-
const slideNext =
|
|
6636
|
+
const slideNext = import_react32.default.useCallback(() => {
|
|
5680
6637
|
if (!canSlide) return;
|
|
5681
6638
|
const nextInner = innerIndex + slideBy;
|
|
5682
6639
|
if (useLoop) {
|
|
@@ -5685,7 +6642,7 @@ var Swiper = (props) => {
|
|
|
5685
6642
|
moveToInner(Math.min(nextInner, maxIndex), true);
|
|
5686
6643
|
}
|
|
5687
6644
|
}, [canSlide, useLoop, innerIndex, slideBy, maxIndex, moveToInner]);
|
|
5688
|
-
const slidePrev =
|
|
6645
|
+
const slidePrev = import_react32.default.useCallback(() => {
|
|
5689
6646
|
if (!canSlide) return;
|
|
5690
6647
|
const prevInner = innerIndex - slideBy;
|
|
5691
6648
|
if (useLoop) {
|
|
@@ -5694,7 +6651,7 @@ var Swiper = (props) => {
|
|
|
5694
6651
|
moveToInner(Math.max(prevInner, 0), true);
|
|
5695
6652
|
}
|
|
5696
6653
|
}, [canSlide, useLoop, innerIndex, slideBy, moveToInner]);
|
|
5697
|
-
|
|
6654
|
+
import_react32.default.useEffect(() => {
|
|
5698
6655
|
if (indexProp === void 0) return;
|
|
5699
6656
|
const clamped = Math.max(0, Math.min(indexProp, maxIndex));
|
|
5700
6657
|
const target = useLoop ? cloneCount + clamped : clamped;
|
|
@@ -5702,12 +6659,12 @@ var Swiper = (props) => {
|
|
|
5702
6659
|
moveToInner(target, true);
|
|
5703
6660
|
}
|
|
5704
6661
|
}, [indexProp]);
|
|
5705
|
-
|
|
6662
|
+
import_react32.default.useImperativeHandle(swiperRef, () => ({
|
|
5706
6663
|
slidePrev,
|
|
5707
6664
|
slideNext,
|
|
5708
6665
|
slideTo
|
|
5709
6666
|
}));
|
|
5710
|
-
|
|
6667
|
+
import_react32.default.useEffect(() => {
|
|
5711
6668
|
if (!auto || !canSlide || paused) return;
|
|
5712
6669
|
autoplayTimerRef.current = setInterval(slideNext, autoplayDelay);
|
|
5713
6670
|
return () => {
|
|
@@ -5733,7 +6690,7 @@ var Swiper = (props) => {
|
|
|
5733
6690
|
resumeTimeoutRef.current = null;
|
|
5734
6691
|
}, pauseOnInteraction);
|
|
5735
6692
|
};
|
|
5736
|
-
|
|
6693
|
+
import_react32.default.useEffect(() => {
|
|
5737
6694
|
return () => {
|
|
5738
6695
|
if (resumeTimeoutRef.current) clearTimeout(resumeTimeoutRef.current);
|
|
5739
6696
|
};
|
|
@@ -5751,7 +6708,7 @@ var Swiper = (props) => {
|
|
|
5751
6708
|
startXRef.current = getClientX(e);
|
|
5752
6709
|
startTimeRef.current = Date.now();
|
|
5753
6710
|
};
|
|
5754
|
-
|
|
6711
|
+
import_react32.default.useEffect(() => {
|
|
5755
6712
|
if (!isDragging) return;
|
|
5756
6713
|
const handleMove = (e) => {
|
|
5757
6714
|
setDragOffset(getClientX(e) - startXRef.current);
|
|
@@ -5790,8 +6747,8 @@ var Swiper = (props) => {
|
|
|
5790
6747
|
}, [isDragging, dragOffset, innerIndex, useLoop, maxIndex, slideStep, moveToInner]);
|
|
5791
6748
|
const slideWidthPercent = 100 / viewItemCount;
|
|
5792
6749
|
const gapAdjust = spaceBetween * (viewItemCount - 1) / viewItemCount;
|
|
5793
|
-
const slideElements =
|
|
5794
|
-
() => extendedItems.map((item, idx) => /* @__PURE__ */ (0,
|
|
6750
|
+
const slideElements = import_react32.default.useMemo(
|
|
6751
|
+
() => extendedItems.map((item, idx) => /* @__PURE__ */ (0, import_jsx_runtime342.jsx)(
|
|
5795
6752
|
"div",
|
|
5796
6753
|
{
|
|
5797
6754
|
className: "lib-xplat-swiper__slide",
|
|
@@ -5810,15 +6767,15 @@ var Swiper = (props) => {
|
|
|
5810
6767
|
Math.floor(realIndex / slideBy),
|
|
5811
6768
|
totalSteps - 1
|
|
5812
6769
|
);
|
|
5813
|
-
return /* @__PURE__ */ (0,
|
|
5814
|
-
/* @__PURE__ */ (0,
|
|
6770
|
+
return /* @__PURE__ */ (0, import_jsx_runtime342.jsxs)("div", { className: "lib-xplat-swiper", ref: containerRef, children: [
|
|
6771
|
+
/* @__PURE__ */ (0, import_jsx_runtime342.jsx)(
|
|
5815
6772
|
"div",
|
|
5816
6773
|
{
|
|
5817
6774
|
className: "lib-xplat-swiper__viewport",
|
|
5818
6775
|
onMouseDown: handleDragStart,
|
|
5819
6776
|
onTouchStart: handleDragStart,
|
|
5820
6777
|
onDragStart: (e) => e.preventDefault(),
|
|
5821
|
-
children: /* @__PURE__ */ (0,
|
|
6778
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime342.jsx)(
|
|
5822
6779
|
"div",
|
|
5823
6780
|
{
|
|
5824
6781
|
className: clsx_default(
|
|
@@ -5836,7 +6793,7 @@ var Swiper = (props) => {
|
|
|
5836
6793
|
)
|
|
5837
6794
|
}
|
|
5838
6795
|
),
|
|
5839
|
-
showProgress && canSlide && /* @__PURE__ */ (0,
|
|
6796
|
+
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)(
|
|
5840
6797
|
"span",
|
|
5841
6798
|
{
|
|
5842
6799
|
className: "lib-xplat-swiper__progress-fill",
|
|
@@ -5846,7 +6803,7 @@ var Swiper = (props) => {
|
|
|
5846
6803
|
}
|
|
5847
6804
|
}
|
|
5848
6805
|
) }) }),
|
|
5849
|
-
canSlide && /* @__PURE__ */ (0,
|
|
6806
|
+
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)(
|
|
5850
6807
|
"button",
|
|
5851
6808
|
{
|
|
5852
6809
|
className: clsx_default(
|
|
@@ -5864,8 +6821,8 @@ Swiper.displayName = "Swiper";
|
|
|
5864
6821
|
var Swiper_default = Swiper;
|
|
5865
6822
|
|
|
5866
6823
|
// src/components/Switch/Switch.tsx
|
|
5867
|
-
var
|
|
5868
|
-
var
|
|
6824
|
+
var import_react33 = __toESM(require("react"), 1);
|
|
6825
|
+
var import_jsx_runtime343 = require("react/jsx-runtime");
|
|
5869
6826
|
var KNOB_TRANSITION_MS = 250;
|
|
5870
6827
|
var Switch = (props) => {
|
|
5871
6828
|
const {
|
|
@@ -5874,12 +6831,15 @@ var Switch = (props) => {
|
|
|
5874
6831
|
type = "primary",
|
|
5875
6832
|
disabled,
|
|
5876
6833
|
onChange,
|
|
5877
|
-
validations
|
|
6834
|
+
validations,
|
|
6835
|
+
label,
|
|
6836
|
+
required
|
|
5878
6837
|
} = props;
|
|
6838
|
+
const fieldId = import_react33.default.useId();
|
|
5879
6839
|
const statusType = normalizeStatus(type);
|
|
5880
|
-
const [isAnimating, setIsAnimating] =
|
|
5881
|
-
const timeoutRef =
|
|
5882
|
-
|
|
6840
|
+
const [isAnimating, setIsAnimating] = import_react33.default.useState(false);
|
|
6841
|
+
const timeoutRef = import_react33.default.useRef(null);
|
|
6842
|
+
import_react33.default.useEffect(() => {
|
|
5883
6843
|
return () => {
|
|
5884
6844
|
if (timeoutRef.current) clearTimeout(timeoutRef.current);
|
|
5885
6845
|
};
|
|
@@ -5894,9 +6854,10 @@ var Switch = (props) => {
|
|
|
5894
6854
|
timeoutRef.current = null;
|
|
5895
6855
|
}, KNOB_TRANSITION_MS);
|
|
5896
6856
|
};
|
|
5897
|
-
const control = /* @__PURE__ */ (0,
|
|
6857
|
+
const control = /* @__PURE__ */ (0, import_jsx_runtime343.jsx)(
|
|
5898
6858
|
"div",
|
|
5899
6859
|
{
|
|
6860
|
+
id: fieldId,
|
|
5900
6861
|
className: clsx_default(
|
|
5901
6862
|
"lib-xplat-switch",
|
|
5902
6863
|
size,
|
|
@@ -5908,26 +6869,26 @@ var Switch = (props) => {
|
|
|
5908
6869
|
onClick: handleClick,
|
|
5909
6870
|
"aria-invalid": hasError(validations) || void 0,
|
|
5910
6871
|
"aria-disabled": disabled || isAnimating,
|
|
5911
|
-
children: /* @__PURE__ */ (0,
|
|
6872
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime343.jsx)("div", { className: clsx_default("knob", value ? "checked" : void 0) })
|
|
5912
6873
|
}
|
|
5913
6874
|
);
|
|
5914
|
-
return /* @__PURE__ */ (0,
|
|
6875
|
+
return /* @__PURE__ */ (0, import_jsx_runtime343.jsx)(Field, { validations, label, required, htmlFor: fieldId, children: control });
|
|
5915
6876
|
};
|
|
5916
6877
|
Switch.displayName = "Switch";
|
|
5917
6878
|
var Switch_default = Switch;
|
|
5918
6879
|
|
|
5919
6880
|
// src/components/Table/TableContext.tsx
|
|
5920
|
-
var
|
|
5921
|
-
var TableContext =
|
|
6881
|
+
var import_react34 = __toESM(require("react"), 1);
|
|
6882
|
+
var TableContext = import_react34.default.createContext(null);
|
|
5922
6883
|
var useTableContext = () => {
|
|
5923
|
-
const ctx =
|
|
6884
|
+
const ctx = import_react34.default.useContext(TableContext);
|
|
5924
6885
|
if (!ctx) throw new Error("Table components must be used inside <Table>");
|
|
5925
6886
|
return ctx;
|
|
5926
6887
|
};
|
|
5927
6888
|
var TableContext_default = TableContext;
|
|
5928
6889
|
|
|
5929
6890
|
// src/components/Table/Table.tsx
|
|
5930
|
-
var
|
|
6891
|
+
var import_jsx_runtime344 = require("react/jsx-runtime");
|
|
5931
6892
|
var Table = (props) => {
|
|
5932
6893
|
const {
|
|
5933
6894
|
children,
|
|
@@ -5937,7 +6898,7 @@ var Table = (props) => {
|
|
|
5937
6898
|
headerSticky = false,
|
|
5938
6899
|
stickyShadow = true
|
|
5939
6900
|
} = props;
|
|
5940
|
-
return /* @__PURE__ */ (0,
|
|
6901
|
+
return /* @__PURE__ */ (0, import_jsx_runtime344.jsx)("div", { className: `lib-xplat-table-wrapper ${size}`, children: /* @__PURE__ */ (0, import_jsx_runtime344.jsx)(
|
|
5941
6902
|
TableContext_default.Provider,
|
|
5942
6903
|
{
|
|
5943
6904
|
value: {
|
|
@@ -5946,7 +6907,7 @@ var Table = (props) => {
|
|
|
5946
6907
|
headerSticky,
|
|
5947
6908
|
stickyShadow
|
|
5948
6909
|
},
|
|
5949
|
-
children: /* @__PURE__ */ (0,
|
|
6910
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime344.jsx)("table", { className: "lib-xplat-table", children })
|
|
5950
6911
|
}
|
|
5951
6912
|
) });
|
|
5952
6913
|
};
|
|
@@ -5954,41 +6915,41 @@ Table.displayName = "Table";
|
|
|
5954
6915
|
var Table_default = Table;
|
|
5955
6916
|
|
|
5956
6917
|
// src/components/Table/TableBody.tsx
|
|
5957
|
-
var
|
|
6918
|
+
var import_jsx_runtime345 = require("react/jsx-runtime");
|
|
5958
6919
|
var TableBody = (props) => {
|
|
5959
6920
|
const { children } = props;
|
|
5960
|
-
return /* @__PURE__ */ (0,
|
|
6921
|
+
return /* @__PURE__ */ (0, import_jsx_runtime345.jsx)("tbody", { children });
|
|
5961
6922
|
};
|
|
5962
6923
|
TableBody.displayName = "TableBody";
|
|
5963
6924
|
var TableBody_default = TableBody;
|
|
5964
6925
|
|
|
5965
6926
|
// src/components/Table/TableCell.tsx
|
|
5966
|
-
var
|
|
6927
|
+
var import_react37 = __toESM(require("react"), 1);
|
|
5967
6928
|
|
|
5968
6929
|
// src/components/Table/TableHeadContext.tsx
|
|
5969
|
-
var
|
|
5970
|
-
var TableHeadContext =
|
|
6930
|
+
var import_react35 = __toESM(require("react"), 1);
|
|
6931
|
+
var TableHeadContext = import_react35.default.createContext(
|
|
5971
6932
|
null
|
|
5972
6933
|
);
|
|
5973
6934
|
var useTableHeadContext = () => {
|
|
5974
|
-
const ctx =
|
|
6935
|
+
const ctx = import_react35.default.useContext(TableHeadContext);
|
|
5975
6936
|
return ctx;
|
|
5976
6937
|
};
|
|
5977
6938
|
var TableHeadContext_default = TableHeadContext;
|
|
5978
6939
|
|
|
5979
6940
|
// src/components/Table/TableRowContext.tsx
|
|
5980
|
-
var
|
|
5981
|
-
var TableRowContext =
|
|
6941
|
+
var import_react36 = __toESM(require("react"), 1);
|
|
6942
|
+
var TableRowContext = import_react36.default.createContext(null);
|
|
5982
6943
|
var useTableRowContext = () => {
|
|
5983
|
-
const ctx =
|
|
6944
|
+
const ctx = import_react36.default.useContext(TableRowContext);
|
|
5984
6945
|
if (!ctx) throw new Error("Table components must be used inside <Table>");
|
|
5985
6946
|
return ctx;
|
|
5986
6947
|
};
|
|
5987
6948
|
var TableRowContext_default = TableRowContext;
|
|
5988
6949
|
|
|
5989
6950
|
// src/components/Table/TableCell.tsx
|
|
5990
|
-
var
|
|
5991
|
-
var TableCell =
|
|
6951
|
+
var import_jsx_runtime346 = require("react/jsx-runtime");
|
|
6952
|
+
var TableCell = import_react37.default.memo((props) => {
|
|
5992
6953
|
const {
|
|
5993
6954
|
children,
|
|
5994
6955
|
align = "center",
|
|
@@ -6002,9 +6963,9 @@ var TableCell = import_react36.default.memo((props) => {
|
|
|
6002
6963
|
const { registerStickyCell, stickyCells } = useTableRowContext();
|
|
6003
6964
|
const { stickyShadow } = useTableContext();
|
|
6004
6965
|
const headContext = useTableHeadContext();
|
|
6005
|
-
const [left, setLeft] =
|
|
6006
|
-
const cellRef =
|
|
6007
|
-
const calculateLeft =
|
|
6966
|
+
const [left, setLeft] = import_react37.default.useState(0);
|
|
6967
|
+
const cellRef = import_react37.default.useRef(null);
|
|
6968
|
+
const calculateLeft = import_react37.default.useCallback(() => {
|
|
6008
6969
|
if (!cellRef.current) return 0;
|
|
6009
6970
|
let totalLeft = 0;
|
|
6010
6971
|
for (const ref of stickyCells) {
|
|
@@ -6013,7 +6974,7 @@ var TableCell = import_react36.default.memo((props) => {
|
|
|
6013
6974
|
}
|
|
6014
6975
|
return totalLeft;
|
|
6015
6976
|
}, [stickyCells]);
|
|
6016
|
-
|
|
6977
|
+
import_react37.default.useEffect(() => {
|
|
6017
6978
|
if (!isSticky || !cellRef.current) return;
|
|
6018
6979
|
registerStickyCell(cellRef);
|
|
6019
6980
|
setLeft(calculateLeft());
|
|
@@ -6032,7 +6993,7 @@ var TableCell = import_react36.default.memo((props) => {
|
|
|
6032
6993
|
const CellTag = isHeaderCell ? "th" : "td";
|
|
6033
6994
|
const isLastSticky = isSticky && stickyCells[stickyCells.length - 1] === cellRef;
|
|
6034
6995
|
const enableHover = headContext && headContext.cellHover;
|
|
6035
|
-
return /* @__PURE__ */ (0,
|
|
6996
|
+
return /* @__PURE__ */ (0, import_jsx_runtime346.jsx)(
|
|
6036
6997
|
CellTag,
|
|
6037
6998
|
{
|
|
6038
6999
|
ref: cellRef,
|
|
@@ -6059,21 +7020,21 @@ TableCell.displayName = "TableCell";
|
|
|
6059
7020
|
var TableCell_default = TableCell;
|
|
6060
7021
|
|
|
6061
7022
|
// src/components/Table/TableHead.tsx
|
|
6062
|
-
var
|
|
7023
|
+
var import_jsx_runtime347 = require("react/jsx-runtime");
|
|
6063
7024
|
var TableHead = ({
|
|
6064
7025
|
children,
|
|
6065
7026
|
cellHover = false
|
|
6066
7027
|
}) => {
|
|
6067
7028
|
const { headerSticky } = useTableContext();
|
|
6068
|
-
return /* @__PURE__ */ (0,
|
|
7029
|
+
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 }) });
|
|
6069
7030
|
};
|
|
6070
7031
|
TableHead.displayName = "TableHead";
|
|
6071
7032
|
var TableHead_default = TableHead;
|
|
6072
7033
|
|
|
6073
7034
|
// src/components/Table/TableRow.tsx
|
|
6074
|
-
var
|
|
6075
|
-
var
|
|
6076
|
-
var TableRow =
|
|
7035
|
+
var import_react38 = __toESM(require("react"), 1);
|
|
7036
|
+
var import_jsx_runtime348 = require("react/jsx-runtime");
|
|
7037
|
+
var TableRow = import_react38.default.memo((props) => {
|
|
6077
7038
|
const {
|
|
6078
7039
|
children,
|
|
6079
7040
|
type = "secondary",
|
|
@@ -6082,14 +7043,14 @@ var TableRow = import_react37.default.memo((props) => {
|
|
|
6082
7043
|
onClick
|
|
6083
7044
|
} = props;
|
|
6084
7045
|
const { rowBorderUse } = useTableContext();
|
|
6085
|
-
const [stickyCells, setStickyCells] =
|
|
7046
|
+
const [stickyCells, setStickyCells] = import_react38.default.useState([]);
|
|
6086
7047
|
const registerStickyCell = (ref) => {
|
|
6087
7048
|
setStickyCells((prev) => {
|
|
6088
7049
|
if (prev.includes(ref)) return prev;
|
|
6089
7050
|
return [...prev, ref];
|
|
6090
7051
|
});
|
|
6091
7052
|
};
|
|
6092
|
-
return /* @__PURE__ */ (0,
|
|
7053
|
+
return /* @__PURE__ */ (0, import_jsx_runtime348.jsx)(TableRowContext_default.Provider, { value: { stickyCells, registerStickyCell }, children: /* @__PURE__ */ (0, import_jsx_runtime348.jsx)(
|
|
6093
7054
|
"tr",
|
|
6094
7055
|
{
|
|
6095
7056
|
className: clsx_default(
|
|
@@ -6113,7 +7074,7 @@ TableRow.displayName = "TableRow";
|
|
|
6113
7074
|
var TableRow_default = TableRow;
|
|
6114
7075
|
|
|
6115
7076
|
// src/components/Tag/Tag.tsx
|
|
6116
|
-
var
|
|
7077
|
+
var import_jsx_runtime349 = require("react/jsx-runtime");
|
|
6117
7078
|
var Tag = (props) => {
|
|
6118
7079
|
const {
|
|
6119
7080
|
children,
|
|
@@ -6125,7 +7086,7 @@ var Tag = (props) => {
|
|
|
6125
7086
|
colorIndex
|
|
6126
7087
|
} = props;
|
|
6127
7088
|
const shape = variant ?? type ?? "neutral";
|
|
6128
|
-
return /* @__PURE__ */ (0,
|
|
7089
|
+
return /* @__PURE__ */ (0, import_jsx_runtime349.jsxs)(
|
|
6129
7090
|
"span",
|
|
6130
7091
|
{
|
|
6131
7092
|
className: clsx_default(
|
|
@@ -6136,8 +7097,8 @@ var Tag = (props) => {
|
|
|
6136
7097
|
disabled && "disabled"
|
|
6137
7098
|
),
|
|
6138
7099
|
children: [
|
|
6139
|
-
/* @__PURE__ */ (0,
|
|
6140
|
-
onClose && /* @__PURE__ */ (0,
|
|
7100
|
+
/* @__PURE__ */ (0, import_jsx_runtime349.jsx)("span", { className: "tag-label", children }),
|
|
7101
|
+
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, {}) })
|
|
6141
7102
|
]
|
|
6142
7103
|
}
|
|
6143
7104
|
);
|
|
@@ -6146,24 +7107,29 @@ Tag.displayName = "Tag";
|
|
|
6146
7107
|
var Tag_default = Tag;
|
|
6147
7108
|
|
|
6148
7109
|
// src/components/TextArea/TextArea.tsx
|
|
6149
|
-
var
|
|
6150
|
-
var
|
|
6151
|
-
var TextArea =
|
|
7110
|
+
var import_react39 = __toESM(require("react"), 1);
|
|
7111
|
+
var import_jsx_runtime350 = require("react/jsx-runtime");
|
|
7112
|
+
var TextArea = import_react39.default.forwardRef(
|
|
6152
7113
|
(props, ref) => {
|
|
6153
7114
|
const {
|
|
6154
7115
|
className,
|
|
6155
7116
|
size = "md",
|
|
6156
7117
|
validations,
|
|
7118
|
+
label,
|
|
7119
|
+
required,
|
|
6157
7120
|
resize = "vertical",
|
|
6158
7121
|
rows = 3,
|
|
6159
7122
|
disabled,
|
|
6160
7123
|
...textareaProps
|
|
6161
7124
|
} = props;
|
|
6162
|
-
const
|
|
7125
|
+
const autoId = import_react39.default.useId();
|
|
7126
|
+
const fieldId = props.id ?? autoId;
|
|
7127
|
+
const control = /* @__PURE__ */ (0, import_jsx_runtime350.jsx)("div", { className: clsx_default("lib-xplat-textarea-wrap", className), children: /* @__PURE__ */ (0, import_jsx_runtime350.jsx)(
|
|
6163
7128
|
"textarea",
|
|
6164
7129
|
{
|
|
6165
7130
|
...textareaProps,
|
|
6166
7131
|
ref,
|
|
7132
|
+
id: fieldId,
|
|
6167
7133
|
rows,
|
|
6168
7134
|
disabled,
|
|
6169
7135
|
"aria-invalid": hasError(validations) || void 0,
|
|
@@ -6171,32 +7137,166 @@ var TextArea = import_react38.default.forwardRef(
|
|
|
6171
7137
|
style: { resize }
|
|
6172
7138
|
}
|
|
6173
7139
|
) });
|
|
6174
|
-
return /* @__PURE__ */ (0,
|
|
7140
|
+
return /* @__PURE__ */ (0, import_jsx_runtime350.jsx)(Field, { validations, label, required, htmlFor: fieldId, children: control });
|
|
6175
7141
|
}
|
|
6176
7142
|
);
|
|
6177
7143
|
TextArea.displayName = "TextArea";
|
|
6178
7144
|
var TextArea_default = TextArea;
|
|
6179
7145
|
|
|
7146
|
+
// src/components/TimePicker/TimePicker.tsx
|
|
7147
|
+
var import_react40 = __toESM(require("react"), 1);
|
|
7148
|
+
var import_jsx_runtime351 = require("react/jsx-runtime");
|
|
7149
|
+
var ANIMATION_DURATION_MS4 = 200;
|
|
7150
|
+
var toMinutes = (hhmm) => {
|
|
7151
|
+
if (!hhmm) return null;
|
|
7152
|
+
const m = /^(\d{1,2}):(\d{2})$/.exec(hhmm.trim());
|
|
7153
|
+
if (!m) return null;
|
|
7154
|
+
const h = Number(m[1]);
|
|
7155
|
+
const min = Number(m[2]);
|
|
7156
|
+
if (h > 23 || min > 59) return null;
|
|
7157
|
+
return h * 60 + min;
|
|
7158
|
+
};
|
|
7159
|
+
var toHHmm = (minutes) => `${String(Math.floor(minutes / 60)).padStart(2, "0")}:${String(minutes % 60).padStart(2, "0")}`;
|
|
7160
|
+
var display = (hhmm, use12Hours) => {
|
|
7161
|
+
if (!use12Hours) return hhmm;
|
|
7162
|
+
const total = toMinutes(hhmm);
|
|
7163
|
+
if (total === null) return hhmm;
|
|
7164
|
+
const h24 = Math.floor(total / 60);
|
|
7165
|
+
const mm = String(total % 60).padStart(2, "0");
|
|
7166
|
+
const period = h24 < 12 ? "\uC624\uC804" : "\uC624\uD6C4";
|
|
7167
|
+
const h12 = h24 % 12 === 0 ? 12 : h24 % 12;
|
|
7168
|
+
return `${period} ${h12}:${mm}`;
|
|
7169
|
+
};
|
|
7170
|
+
var TimePicker = (props) => {
|
|
7171
|
+
const {
|
|
7172
|
+
value,
|
|
7173
|
+
onChange,
|
|
7174
|
+
step = 30,
|
|
7175
|
+
min,
|
|
7176
|
+
max,
|
|
7177
|
+
use12Hours = false,
|
|
7178
|
+
placeholder = "\uC2DC\uAC01 \uC120\uD0DD",
|
|
7179
|
+
disabled = false,
|
|
7180
|
+
size = "md",
|
|
7181
|
+
label,
|
|
7182
|
+
required,
|
|
7183
|
+
validations
|
|
7184
|
+
} = props;
|
|
7185
|
+
const fieldId = import_react40.default.useId();
|
|
7186
|
+
const triggerRef = import_react40.default.useRef(null);
|
|
7187
|
+
const contentRef = import_react40.default.useRef(null);
|
|
7188
|
+
const [isOpen, setOpen] = import_react40.default.useState(false);
|
|
7189
|
+
const [mounted, setMounted] = import_react40.default.useState(false);
|
|
7190
|
+
const [visible, setVisible] = import_react40.default.useState(false);
|
|
7191
|
+
const options = import_react40.default.useMemo(() => {
|
|
7192
|
+
const safeStep = step > 0 && step <= 720 ? step : 30;
|
|
7193
|
+
const lo = toMinutes(min) ?? 0;
|
|
7194
|
+
const hi = toMinutes(max) ?? 24 * 60 - 1;
|
|
7195
|
+
const out = [];
|
|
7196
|
+
for (let t = lo; t <= hi; t += safeStep) out.push(toHHmm(t));
|
|
7197
|
+
return out;
|
|
7198
|
+
}, [step, min, max]);
|
|
7199
|
+
const close = import_react40.default.useCallback(() => setOpen(false), []);
|
|
7200
|
+
useClickOutside_default([triggerRef, contentRef], close, isOpen);
|
|
7201
|
+
useEscapeKey(isOpen, () => {
|
|
7202
|
+
close();
|
|
7203
|
+
triggerRef.current?.focus({ preventScroll: true });
|
|
7204
|
+
});
|
|
7205
|
+
const position = useAutoPosition_default(triggerRef, contentRef, mounted);
|
|
7206
|
+
import_react40.default.useEffect(() => {
|
|
7207
|
+
if (disabled && isOpen) setOpen(false);
|
|
7208
|
+
}, [disabled, isOpen]);
|
|
7209
|
+
import_react40.default.useEffect(() => {
|
|
7210
|
+
if (isOpen) {
|
|
7211
|
+
setMounted(true);
|
|
7212
|
+
const t2 = setTimeout(() => setVisible(true), 1);
|
|
7213
|
+
return () => clearTimeout(t2);
|
|
7214
|
+
}
|
|
7215
|
+
setVisible(false);
|
|
7216
|
+
const t = setTimeout(() => setMounted(false), ANIMATION_DURATION_MS4);
|
|
7217
|
+
return () => clearTimeout(t);
|
|
7218
|
+
}, [isOpen]);
|
|
7219
|
+
const pick = (hhmm) => {
|
|
7220
|
+
onChange?.(hhmm);
|
|
7221
|
+
close();
|
|
7222
|
+
triggerRef.current?.focus({ preventScroll: true });
|
|
7223
|
+
};
|
|
7224
|
+
const control = /* @__PURE__ */ (0, import_jsx_runtime351.jsxs)("div", { className: clsx_default("lib-xplat-time-picker", size, disabled && "disabled"), children: [
|
|
7225
|
+
/* @__PURE__ */ (0, import_jsx_runtime351.jsx)(
|
|
7226
|
+
"div",
|
|
7227
|
+
{
|
|
7228
|
+
id: fieldId,
|
|
7229
|
+
ref: triggerRef,
|
|
7230
|
+
className: clsx_default("time-picker-trigger", hasError(validations) && "error"),
|
|
7231
|
+
role: "combobox",
|
|
7232
|
+
"aria-expanded": isOpen,
|
|
7233
|
+
"aria-haspopup": "listbox",
|
|
7234
|
+
"aria-invalid": hasError(validations) || void 0,
|
|
7235
|
+
tabIndex: disabled ? void 0 : 0,
|
|
7236
|
+
onClick: () => !disabled && setOpen((p) => !p),
|
|
7237
|
+
onKeyDown: (e) => {
|
|
7238
|
+
if (disabled) return;
|
|
7239
|
+
if (e.key === "Enter" || e.key === " " || e.key === "ArrowDown") {
|
|
7240
|
+
e.preventDefault();
|
|
7241
|
+
setOpen(true);
|
|
7242
|
+
}
|
|
7243
|
+
},
|
|
7244
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime351.jsx)("span", { className: clsx_default("time-picker-value", !value && "placeholder"), children: value ? display(value, use12Hours) : placeholder })
|
|
7245
|
+
}
|
|
7246
|
+
),
|
|
7247
|
+
mounted && /* @__PURE__ */ (0, import_jsx_runtime351.jsx)(Portal_default, { children: /* @__PURE__ */ (0, import_jsx_runtime351.jsx)(
|
|
7248
|
+
"div",
|
|
7249
|
+
{
|
|
7250
|
+
ref: contentRef,
|
|
7251
|
+
className: clsx_default("lib-xplat-time-picker-content", size, visible ? "enter" : "exit", position.repositioning && "repositioning"),
|
|
7252
|
+
style: { ...position.position, width: triggerRef.current?.offsetWidth },
|
|
7253
|
+
role: "listbox",
|
|
7254
|
+
children: options.map((t) => /* @__PURE__ */ (0, import_jsx_runtime351.jsx)(
|
|
7255
|
+
"div",
|
|
7256
|
+
{
|
|
7257
|
+
className: clsx_default("time-picker-item", t === value && "is-selected"),
|
|
7258
|
+
role: "option",
|
|
7259
|
+
"aria-selected": t === value,
|
|
7260
|
+
tabIndex: 0,
|
|
7261
|
+
onClick: () => pick(t),
|
|
7262
|
+
onKeyDown: (e) => {
|
|
7263
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
7264
|
+
e.preventDefault();
|
|
7265
|
+
pick(t);
|
|
7266
|
+
}
|
|
7267
|
+
},
|
|
7268
|
+
children: display(t, use12Hours)
|
|
7269
|
+
},
|
|
7270
|
+
t
|
|
7271
|
+
))
|
|
7272
|
+
}
|
|
7273
|
+
) })
|
|
7274
|
+
] });
|
|
7275
|
+
return /* @__PURE__ */ (0, import_jsx_runtime351.jsx)(Field, { validations, label, required, htmlFor: fieldId, children: control });
|
|
7276
|
+
};
|
|
7277
|
+
TimePicker.displayName = "TimePicker";
|
|
7278
|
+
var TimePicker_default = TimePicker;
|
|
7279
|
+
|
|
6180
7280
|
// src/components/Toast/Toast.tsx
|
|
6181
|
-
var
|
|
7281
|
+
var import_react41 = __toESM(require("react"), 1);
|
|
6182
7282
|
var import_react_dom4 = require("react-dom");
|
|
6183
|
-
var
|
|
6184
|
-
var ToastContext =
|
|
7283
|
+
var import_jsx_runtime352 = require("react/jsx-runtime");
|
|
7284
|
+
var ToastContext = import_react41.default.createContext(null);
|
|
6185
7285
|
var useToast = () => {
|
|
6186
|
-
const ctx =
|
|
7286
|
+
const ctx = import_react41.default.useContext(ToastContext);
|
|
6187
7287
|
if (!ctx) throw new Error("useToast must be used within ToastProvider");
|
|
6188
7288
|
return ctx;
|
|
6189
7289
|
};
|
|
6190
7290
|
var EXIT_DURATION = 300;
|
|
6191
7291
|
var ToastItemComponent = ({ item, isExiting, onClose }) => {
|
|
6192
|
-
const ref =
|
|
6193
|
-
const [height, setHeight] =
|
|
6194
|
-
|
|
7292
|
+
const ref = import_react41.default.useRef(null);
|
|
7293
|
+
const [height, setHeight] = import_react41.default.useState(void 0);
|
|
7294
|
+
import_react41.default.useEffect(() => {
|
|
6195
7295
|
if (ref.current && !isExiting) {
|
|
6196
7296
|
setHeight(ref.current.offsetHeight);
|
|
6197
7297
|
}
|
|
6198
7298
|
}, [isExiting]);
|
|
6199
|
-
return /* @__PURE__ */ (0,
|
|
7299
|
+
return /* @__PURE__ */ (0, import_jsx_runtime352.jsx)(
|
|
6200
7300
|
"div",
|
|
6201
7301
|
{
|
|
6202
7302
|
className: clsx_default("lib-xplat-toast-wrapper", { exit: isExiting }),
|
|
@@ -6204,15 +7304,15 @@ var ToastItemComponent = ({ item, isExiting, onClose }) => {
|
|
|
6204
7304
|
maxHeight: isExiting ? 0 : height ?? "none",
|
|
6205
7305
|
marginBottom: isExiting ? 0 : void 0
|
|
6206
7306
|
},
|
|
6207
|
-
children: /* @__PURE__ */ (0,
|
|
7307
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime352.jsxs)(
|
|
6208
7308
|
"div",
|
|
6209
7309
|
{
|
|
6210
7310
|
ref,
|
|
6211
7311
|
className: clsx_default("lib-xplat-toast", item.type, { exit: isExiting }),
|
|
6212
7312
|
role: "alert",
|
|
6213
7313
|
children: [
|
|
6214
|
-
/* @__PURE__ */ (0,
|
|
6215
|
-
/* @__PURE__ */ (0,
|
|
7314
|
+
/* @__PURE__ */ (0, import_jsx_runtime352.jsx)("span", { className: "message", children: item.message }),
|
|
7315
|
+
/* @__PURE__ */ (0, import_jsx_runtime352.jsx)("button", { className: "close-btn", onClick: onClose, "aria-label": "\uB2EB\uAE30", children: "\xD7" })
|
|
6216
7316
|
]
|
|
6217
7317
|
}
|
|
6218
7318
|
)
|
|
@@ -6223,13 +7323,13 @@ var ToastProvider = ({
|
|
|
6223
7323
|
children,
|
|
6224
7324
|
position = "top-right"
|
|
6225
7325
|
}) => {
|
|
6226
|
-
const [toasts, setToasts] =
|
|
6227
|
-
const [removing, setRemoving] =
|
|
6228
|
-
const [mounted, setMounted] =
|
|
6229
|
-
|
|
7326
|
+
const [toasts, setToasts] = import_react41.default.useState([]);
|
|
7327
|
+
const [removing, setRemoving] = import_react41.default.useState(/* @__PURE__ */ new Set());
|
|
7328
|
+
const [mounted, setMounted] = import_react41.default.useState(false);
|
|
7329
|
+
import_react41.default.useEffect(() => {
|
|
6230
7330
|
setMounted(true);
|
|
6231
7331
|
}, []);
|
|
6232
|
-
const remove =
|
|
7332
|
+
const remove = import_react41.default.useCallback((id) => {
|
|
6233
7333
|
setRemoving((prev) => new Set(prev).add(id));
|
|
6234
7334
|
setTimeout(() => {
|
|
6235
7335
|
setToasts((prev) => prev.filter((t) => t.id !== id));
|
|
@@ -6240,7 +7340,7 @@ var ToastProvider = ({
|
|
|
6240
7340
|
});
|
|
6241
7341
|
}, EXIT_DURATION);
|
|
6242
7342
|
}, []);
|
|
6243
|
-
const toast =
|
|
7343
|
+
const toast = import_react41.default.useCallback(
|
|
6244
7344
|
(type, message, duration = 3e3) => {
|
|
6245
7345
|
const id = `${Date.now()}-${Math.random()}`;
|
|
6246
7346
|
setToasts((prev) => [...prev, { id, type, message }]);
|
|
@@ -6250,10 +7350,10 @@ var ToastProvider = ({
|
|
|
6250
7350
|
},
|
|
6251
7351
|
[remove]
|
|
6252
7352
|
);
|
|
6253
|
-
return /* @__PURE__ */ (0,
|
|
7353
|
+
return /* @__PURE__ */ (0, import_jsx_runtime352.jsxs)(ToastContext.Provider, { value: { toast }, children: [
|
|
6254
7354
|
children,
|
|
6255
7355
|
mounted && (0, import_react_dom4.createPortal)(
|
|
6256
|
-
/* @__PURE__ */ (0,
|
|
7356
|
+
/* @__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)(
|
|
6257
7357
|
ToastItemComponent,
|
|
6258
7358
|
{
|
|
6259
7359
|
item: t,
|
|
@@ -6269,8 +7369,8 @@ var ToastProvider = ({
|
|
|
6269
7369
|
ToastProvider.displayName = "ToastProvider";
|
|
6270
7370
|
|
|
6271
7371
|
// src/components/Tooltip/Tooltip.tsx
|
|
6272
|
-
var
|
|
6273
|
-
var
|
|
7372
|
+
var import_react42 = __toESM(require("react"), 1);
|
|
7373
|
+
var import_jsx_runtime353 = require("react/jsx-runtime");
|
|
6274
7374
|
var OFFSET = 12;
|
|
6275
7375
|
var GAP = 8;
|
|
6276
7376
|
var SHOW_DELAY = 300;
|
|
@@ -6285,14 +7385,14 @@ var Tooltip = (props) => {
|
|
|
6285
7385
|
disabled = false
|
|
6286
7386
|
} = props;
|
|
6287
7387
|
const shape = variant ?? type ?? "dark";
|
|
6288
|
-
const triggerRef =
|
|
6289
|
-
const tooltipRef =
|
|
6290
|
-
const [visible, setVisible] =
|
|
6291
|
-
const [pos, setPos] =
|
|
6292
|
-
const delayTimer =
|
|
6293
|
-
const rafRef =
|
|
6294
|
-
const cursor =
|
|
6295
|
-
const clamp =
|
|
7388
|
+
const triggerRef = import_react42.default.useRef(null);
|
|
7389
|
+
const tooltipRef = import_react42.default.useRef(null);
|
|
7390
|
+
const [visible, setVisible] = import_react42.default.useState(false);
|
|
7391
|
+
const [pos, setPos] = import_react42.default.useState({ left: 0, top: 0 });
|
|
7392
|
+
const delayTimer = import_react42.default.useRef(0);
|
|
7393
|
+
const rafRef = import_react42.default.useRef(0);
|
|
7394
|
+
const cursor = import_react42.default.useRef(null);
|
|
7395
|
+
const clamp = import_react42.default.useCallback((left, top, w, h) => {
|
|
6296
7396
|
const vw = window.innerWidth;
|
|
6297
7397
|
const vh = window.innerHeight;
|
|
6298
7398
|
return {
|
|
@@ -6300,7 +7400,7 @@ var Tooltip = (props) => {
|
|
|
6300
7400
|
top: Math.min(Math.max(GAP, top), Math.max(GAP, vh - h - GAP))
|
|
6301
7401
|
};
|
|
6302
7402
|
}, []);
|
|
6303
|
-
const placeAtCursor =
|
|
7403
|
+
const placeAtCursor = import_react42.default.useCallback((x, y) => {
|
|
6304
7404
|
const el = tooltipRef.current;
|
|
6305
7405
|
if (!el) return;
|
|
6306
7406
|
const w = el.offsetWidth;
|
|
@@ -6311,7 +7411,7 @@ var Tooltip = (props) => {
|
|
|
6311
7411
|
if (top < GAP) top = y + OFFSET;
|
|
6312
7412
|
setPos(clamp(left, top, w, h));
|
|
6313
7413
|
}, [clamp]);
|
|
6314
|
-
const placeAtTrigger =
|
|
7414
|
+
const placeAtTrigger = import_react42.default.useCallback(() => {
|
|
6315
7415
|
const el = tooltipRef.current;
|
|
6316
7416
|
const trigger = triggerRef.current;
|
|
6317
7417
|
if (!el || !trigger) return;
|
|
@@ -6323,19 +7423,19 @@ var Tooltip = (props) => {
|
|
|
6323
7423
|
const left = rect.left + rect.width / 2 - w / 2;
|
|
6324
7424
|
setPos(clamp(left, top, w, h));
|
|
6325
7425
|
}, [clamp]);
|
|
6326
|
-
const reposition =
|
|
7426
|
+
const reposition = import_react42.default.useCallback(() => {
|
|
6327
7427
|
if (follow && cursor.current) {
|
|
6328
7428
|
placeAtCursor(cursor.current.x, cursor.current.y);
|
|
6329
7429
|
} else {
|
|
6330
7430
|
placeAtTrigger();
|
|
6331
7431
|
}
|
|
6332
7432
|
}, [follow, placeAtCursor, placeAtTrigger]);
|
|
6333
|
-
const handleMouseEnter =
|
|
7433
|
+
const handleMouseEnter = import_react42.default.useCallback((e) => {
|
|
6334
7434
|
if (disabled) return;
|
|
6335
7435
|
cursor.current = { x: e.clientX, y: e.clientY };
|
|
6336
7436
|
delayTimer.current = window.setTimeout(() => setVisible(true), SHOW_DELAY);
|
|
6337
7437
|
}, [disabled]);
|
|
6338
|
-
const handleMouseMove =
|
|
7438
|
+
const handleMouseMove = import_react42.default.useCallback((e) => {
|
|
6339
7439
|
cursor.current = { x: e.clientX, y: e.clientY };
|
|
6340
7440
|
if (!visible || !follow) return;
|
|
6341
7441
|
cancelAnimationFrame(rafRef.current);
|
|
@@ -6343,25 +7443,25 @@ var Tooltip = (props) => {
|
|
|
6343
7443
|
if (cursor.current) placeAtCursor(cursor.current.x, cursor.current.y);
|
|
6344
7444
|
});
|
|
6345
7445
|
}, [visible, follow, placeAtCursor]);
|
|
6346
|
-
const close =
|
|
7446
|
+
const close = import_react42.default.useCallback(() => {
|
|
6347
7447
|
window.clearTimeout(delayTimer.current);
|
|
6348
7448
|
cancelAnimationFrame(rafRef.current);
|
|
6349
7449
|
setVisible(false);
|
|
6350
7450
|
}, []);
|
|
6351
|
-
const handleMouseLeave =
|
|
7451
|
+
const handleMouseLeave = import_react42.default.useCallback(() => {
|
|
6352
7452
|
cursor.current = null;
|
|
6353
7453
|
close();
|
|
6354
7454
|
}, [close]);
|
|
6355
|
-
const handleFocus =
|
|
7455
|
+
const handleFocus = import_react42.default.useCallback(() => {
|
|
6356
7456
|
if (disabled) return;
|
|
6357
7457
|
cursor.current = null;
|
|
6358
7458
|
setVisible(true);
|
|
6359
7459
|
}, [disabled]);
|
|
6360
|
-
|
|
7460
|
+
import_react42.default.useLayoutEffect(() => {
|
|
6361
7461
|
if (!visible) return;
|
|
6362
7462
|
reposition();
|
|
6363
7463
|
}, [visible, reposition]);
|
|
6364
|
-
|
|
7464
|
+
import_react42.default.useEffect(() => {
|
|
6365
7465
|
if (!visible || follow) return;
|
|
6366
7466
|
const onChange = () => placeAtTrigger();
|
|
6367
7467
|
window.addEventListener("scroll", onChange, true);
|
|
@@ -6371,12 +7471,12 @@ var Tooltip = (props) => {
|
|
|
6371
7471
|
window.removeEventListener("resize", onChange);
|
|
6372
7472
|
};
|
|
6373
7473
|
}, [visible, follow, placeAtTrigger]);
|
|
6374
|
-
|
|
7474
|
+
import_react42.default.useEffect(() => () => {
|
|
6375
7475
|
window.clearTimeout(delayTimer.current);
|
|
6376
7476
|
cancelAnimationFrame(rafRef.current);
|
|
6377
7477
|
}, []);
|
|
6378
|
-
if (!title && !description) return /* @__PURE__ */ (0,
|
|
6379
|
-
return /* @__PURE__ */ (0,
|
|
7478
|
+
if (!title && !description) return /* @__PURE__ */ (0, import_jsx_runtime353.jsx)(import_jsx_runtime353.Fragment, { children });
|
|
7479
|
+
return /* @__PURE__ */ (0, import_jsx_runtime353.jsxs)(
|
|
6380
7480
|
"div",
|
|
6381
7481
|
{
|
|
6382
7482
|
ref: triggerRef,
|
|
@@ -6389,7 +7489,7 @@ var Tooltip = (props) => {
|
|
|
6389
7489
|
onBlur: close,
|
|
6390
7490
|
children: [
|
|
6391
7491
|
children,
|
|
6392
|
-
visible && /* @__PURE__ */ (0,
|
|
7492
|
+
visible && /* @__PURE__ */ (0, import_jsx_runtime353.jsx)(Portal_default, { children: /* @__PURE__ */ (0, import_jsx_runtime353.jsxs)(
|
|
6393
7493
|
"div",
|
|
6394
7494
|
{
|
|
6395
7495
|
ref: tooltipRef,
|
|
@@ -6397,8 +7497,8 @@ var Tooltip = (props) => {
|
|
|
6397
7497
|
className: clsx_default("lib-xplat-tooltip", shape),
|
|
6398
7498
|
style: { position: "fixed", left: pos.left, top: pos.top },
|
|
6399
7499
|
children: [
|
|
6400
|
-
title && /* @__PURE__ */ (0,
|
|
6401
|
-
description && /* @__PURE__ */ (0,
|
|
7500
|
+
title && /* @__PURE__ */ (0, import_jsx_runtime353.jsx)("div", { className: "tooltip-title", children: title }),
|
|
7501
|
+
description && /* @__PURE__ */ (0, import_jsx_runtime353.jsx)("div", { className: "tooltip-desc", children: description })
|
|
6402
7502
|
]
|
|
6403
7503
|
}
|
|
6404
7504
|
) })
|
|
@@ -6410,11 +7510,11 @@ Tooltip.displayName = "Tooltip";
|
|
|
6410
7510
|
var Tooltip_default = Tooltip;
|
|
6411
7511
|
|
|
6412
7512
|
// src/components/Video/Video.tsx
|
|
6413
|
-
var
|
|
6414
|
-
var
|
|
6415
|
-
var PipIcon = () => /* @__PURE__ */ (0,
|
|
6416
|
-
/* @__PURE__ */ (0,
|
|
6417
|
-
/* @__PURE__ */ (0,
|
|
7513
|
+
var import_react43 = __toESM(require("react"), 1);
|
|
7514
|
+
var import_jsx_runtime354 = require("react/jsx-runtime");
|
|
7515
|
+
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: [
|
|
7516
|
+
/* @__PURE__ */ (0, import_jsx_runtime354.jsx)("rect", { x: "3", y: "5", width: "18", height: "14", rx: "2" }),
|
|
7517
|
+
/* @__PURE__ */ (0, import_jsx_runtime354.jsx)("rect", { x: "12", y: "11", width: "7", height: "6", rx: "1", fill: "currentColor" })
|
|
6418
7518
|
] });
|
|
6419
7519
|
var formatTime = (sec) => {
|
|
6420
7520
|
if (!Number.isFinite(sec) || sec < 0) return "0:00";
|
|
@@ -6422,7 +7522,7 @@ var formatTime = (sec) => {
|
|
|
6422
7522
|
const s = Math.floor(sec % 60);
|
|
6423
7523
|
return `${m}:${s.toString().padStart(2, "0")}`;
|
|
6424
7524
|
};
|
|
6425
|
-
var Video =
|
|
7525
|
+
var Video = import_react43.default.forwardRef((props, ref) => {
|
|
6426
7526
|
const {
|
|
6427
7527
|
src,
|
|
6428
7528
|
poster,
|
|
@@ -6446,21 +7546,21 @@ var Video = import_react41.default.forwardRef((props, ref) => {
|
|
|
6446
7546
|
children,
|
|
6447
7547
|
...rest
|
|
6448
7548
|
} = props;
|
|
6449
|
-
const containerRef =
|
|
6450
|
-
const videoRef =
|
|
6451
|
-
const [isPlaying, setIsPlaying] =
|
|
6452
|
-
const [isLoaded, setIsLoaded] =
|
|
6453
|
-
const [currentTime, setCurrentTime] =
|
|
6454
|
-
const [duration, setDuration] =
|
|
6455
|
-
const [buffered, setBuffered] =
|
|
6456
|
-
const [volume, setVolume] =
|
|
6457
|
-
const [isMuted, setIsMuted] =
|
|
6458
|
-
const [isFullscreen, setIsFullscreen] =
|
|
6459
|
-
const [playbackRate, setPlaybackRate] =
|
|
6460
|
-
const [rateMenuOpen, setRateMenuOpen] =
|
|
6461
|
-
const [captionsOn, setCaptionsOn] =
|
|
6462
|
-
const [isPip, setIsPip] =
|
|
6463
|
-
const setRefs =
|
|
7549
|
+
const containerRef = import_react43.default.useRef(null);
|
|
7550
|
+
const videoRef = import_react43.default.useRef(null);
|
|
7551
|
+
const [isPlaying, setIsPlaying] = import_react43.default.useState(Boolean(autoPlay));
|
|
7552
|
+
const [isLoaded, setIsLoaded] = import_react43.default.useState(false);
|
|
7553
|
+
const [currentTime, setCurrentTime] = import_react43.default.useState(0);
|
|
7554
|
+
const [duration, setDuration] = import_react43.default.useState(0);
|
|
7555
|
+
const [buffered, setBuffered] = import_react43.default.useState(0);
|
|
7556
|
+
const [volume, setVolume] = import_react43.default.useState(1);
|
|
7557
|
+
const [isMuted, setIsMuted] = import_react43.default.useState(Boolean(muted));
|
|
7558
|
+
const [isFullscreen, setIsFullscreen] = import_react43.default.useState(false);
|
|
7559
|
+
const [playbackRate, setPlaybackRate] = import_react43.default.useState(1);
|
|
7560
|
+
const [rateMenuOpen, setRateMenuOpen] = import_react43.default.useState(false);
|
|
7561
|
+
const [captionsOn, setCaptionsOn] = import_react43.default.useState(false);
|
|
7562
|
+
const [isPip, setIsPip] = import_react43.default.useState(false);
|
|
7563
|
+
const setRefs = import_react43.default.useCallback(
|
|
6464
7564
|
(el) => {
|
|
6465
7565
|
videoRef.current = el;
|
|
6466
7566
|
if (typeof ref === "function") ref(el);
|
|
@@ -6468,14 +7568,14 @@ var Video = import_react41.default.forwardRef((props, ref) => {
|
|
|
6468
7568
|
},
|
|
6469
7569
|
[ref]
|
|
6470
7570
|
);
|
|
6471
|
-
|
|
7571
|
+
import_react43.default.useEffect(() => {
|
|
6472
7572
|
const onFsChange = () => {
|
|
6473
7573
|
setIsFullscreen(document.fullscreenElement === containerRef.current);
|
|
6474
7574
|
};
|
|
6475
7575
|
document.addEventListener("fullscreenchange", onFsChange);
|
|
6476
7576
|
return () => document.removeEventListener("fullscreenchange", onFsChange);
|
|
6477
7577
|
}, []);
|
|
6478
|
-
|
|
7578
|
+
import_react43.default.useEffect(() => {
|
|
6479
7579
|
const v = videoRef.current;
|
|
6480
7580
|
if (!v) return;
|
|
6481
7581
|
const onEnter = () => setIsPip(true);
|
|
@@ -6589,13 +7689,13 @@ var Video = import_react41.default.forwardRef((props, ref) => {
|
|
|
6589
7689
|
const volumePct = (isMuted ? 0 : volume) * 100;
|
|
6590
7690
|
const VolumeGlyph = isMuted || volume === 0 ? VolumeXIcon_default : volume < 0.5 ? VolumeIcon_default : Volume2Icon_default;
|
|
6591
7691
|
const pipSupported = typeof document !== "undefined" && "pictureInPictureEnabled" in document && document.pictureInPictureEnabled;
|
|
6592
|
-
return /* @__PURE__ */ (0,
|
|
7692
|
+
return /* @__PURE__ */ (0, import_jsx_runtime354.jsxs)(
|
|
6593
7693
|
"div",
|
|
6594
7694
|
{
|
|
6595
7695
|
ref: containerRef,
|
|
6596
7696
|
className: clsx_default("lib-xplat-video", showControls && "has-controls"),
|
|
6597
7697
|
children: [
|
|
6598
|
-
/* @__PURE__ */ (0,
|
|
7698
|
+
/* @__PURE__ */ (0, import_jsx_runtime354.jsx)(
|
|
6599
7699
|
"video",
|
|
6600
7700
|
{
|
|
6601
7701
|
ref: setRefs,
|
|
@@ -6616,7 +7716,7 @@ var Video = import_react41.default.forwardRef((props, ref) => {
|
|
|
6616
7716
|
children
|
|
6617
7717
|
}
|
|
6618
7718
|
),
|
|
6619
|
-
showCenterPlay && /* @__PURE__ */ (0,
|
|
7719
|
+
showCenterPlay && /* @__PURE__ */ (0, import_jsx_runtime354.jsx)(
|
|
6620
7720
|
"button",
|
|
6621
7721
|
{
|
|
6622
7722
|
type: "button",
|
|
@@ -6628,11 +7728,11 @@ var Video = import_react41.default.forwardRef((props, ref) => {
|
|
|
6628
7728
|
onClick: togglePlay,
|
|
6629
7729
|
"aria-label": isPlaying ? "\uC77C\uC2DC\uC815\uC9C0" : "\uC7AC\uC0DD",
|
|
6630
7730
|
tabIndex: -1,
|
|
6631
|
-
children: /* @__PURE__ */ (0,
|
|
7731
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime354.jsx)("span", { className: "center-play-icon", children: /* @__PURE__ */ (0, import_jsx_runtime354.jsx)(PlayCircleIcon_default, {}) })
|
|
6632
7732
|
}
|
|
6633
7733
|
),
|
|
6634
|
-
showControls && /* @__PURE__ */ (0,
|
|
6635
|
-
/* @__PURE__ */ (0,
|
|
7734
|
+
showControls && /* @__PURE__ */ (0, import_jsx_runtime354.jsxs)("div", { className: "controls", onClick: (e) => e.stopPropagation(), children: [
|
|
7735
|
+
/* @__PURE__ */ (0, import_jsx_runtime354.jsx)(
|
|
6636
7736
|
"input",
|
|
6637
7737
|
{
|
|
6638
7738
|
type: "range",
|
|
@@ -6649,29 +7749,29 @@ var Video = import_react41.default.forwardRef((props, ref) => {
|
|
|
6649
7749
|
}
|
|
6650
7750
|
}
|
|
6651
7751
|
),
|
|
6652
|
-
/* @__PURE__ */ (0,
|
|
6653
|
-
/* @__PURE__ */ (0,
|
|
7752
|
+
/* @__PURE__ */ (0, import_jsx_runtime354.jsxs)("div", { className: "controls-row", children: [
|
|
7753
|
+
/* @__PURE__ */ (0, import_jsx_runtime354.jsx)(
|
|
6654
7754
|
"button",
|
|
6655
7755
|
{
|
|
6656
7756
|
type: "button",
|
|
6657
7757
|
className: "control-btn",
|
|
6658
7758
|
onClick: togglePlay,
|
|
6659
7759
|
"aria-label": isPlaying ? "\uC77C\uC2DC\uC815\uC9C0" : "\uC7AC\uC0DD",
|
|
6660
|
-
children: isPlaying ? /* @__PURE__ */ (0,
|
|
7760
|
+
children: isPlaying ? /* @__PURE__ */ (0, import_jsx_runtime354.jsx)(PauseIcon_default, {}) : /* @__PURE__ */ (0, import_jsx_runtime354.jsx)(PlayIcon_default, {})
|
|
6661
7761
|
}
|
|
6662
7762
|
),
|
|
6663
|
-
/* @__PURE__ */ (0,
|
|
6664
|
-
/* @__PURE__ */ (0,
|
|
7763
|
+
/* @__PURE__ */ (0, import_jsx_runtime354.jsxs)("div", { className: "volume-group", children: [
|
|
7764
|
+
/* @__PURE__ */ (0, import_jsx_runtime354.jsx)(
|
|
6665
7765
|
"button",
|
|
6666
7766
|
{
|
|
6667
7767
|
type: "button",
|
|
6668
7768
|
className: "control-btn",
|
|
6669
7769
|
onClick: toggleMute,
|
|
6670
7770
|
"aria-label": isMuted ? "\uC74C\uC18C\uAC70 \uD574\uC81C" : "\uC74C\uC18C\uAC70",
|
|
6671
|
-
children: /* @__PURE__ */ (0,
|
|
7771
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime354.jsx)(VolumeGlyph, {})
|
|
6672
7772
|
}
|
|
6673
7773
|
),
|
|
6674
|
-
/* @__PURE__ */ (0,
|
|
7774
|
+
/* @__PURE__ */ (0, import_jsx_runtime354.jsx)(
|
|
6675
7775
|
"input",
|
|
6676
7776
|
{
|
|
6677
7777
|
type: "range",
|
|
@@ -6686,14 +7786,14 @@ var Video = import_react41.default.forwardRef((props, ref) => {
|
|
|
6686
7786
|
}
|
|
6687
7787
|
)
|
|
6688
7788
|
] }),
|
|
6689
|
-
/* @__PURE__ */ (0,
|
|
7789
|
+
/* @__PURE__ */ (0, import_jsx_runtime354.jsxs)("span", { className: "time", children: [
|
|
6690
7790
|
formatTime(currentTime),
|
|
6691
7791
|
" / ",
|
|
6692
7792
|
formatTime(duration)
|
|
6693
7793
|
] }),
|
|
6694
|
-
/* @__PURE__ */ (0,
|
|
6695
|
-
playbackRates && playbackRates.length > 0 && /* @__PURE__ */ (0,
|
|
6696
|
-
/* @__PURE__ */ (0,
|
|
7794
|
+
/* @__PURE__ */ (0, import_jsx_runtime354.jsx)("div", { className: "controls-spacer" }),
|
|
7795
|
+
playbackRates && playbackRates.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime354.jsxs)("div", { className: clsx_default("rate-group", rateMenuOpen && "is-open"), children: [
|
|
7796
|
+
/* @__PURE__ */ (0, import_jsx_runtime354.jsxs)(
|
|
6697
7797
|
"button",
|
|
6698
7798
|
{
|
|
6699
7799
|
type: "button",
|
|
@@ -6707,7 +7807,7 @@ var Video = import_react41.default.forwardRef((props, ref) => {
|
|
|
6707
7807
|
]
|
|
6708
7808
|
}
|
|
6709
7809
|
),
|
|
6710
|
-
rateMenuOpen && /* @__PURE__ */ (0,
|
|
7810
|
+
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)(
|
|
6711
7811
|
"button",
|
|
6712
7812
|
{
|
|
6713
7813
|
type: "button",
|
|
@@ -6721,7 +7821,7 @@ var Video = import_react41.default.forwardRef((props, ref) => {
|
|
|
6721
7821
|
}
|
|
6722
7822
|
) }, r2)) })
|
|
6723
7823
|
] }),
|
|
6724
|
-
showCaptions && /* @__PURE__ */ (0,
|
|
7824
|
+
showCaptions && /* @__PURE__ */ (0, import_jsx_runtime354.jsx)(
|
|
6725
7825
|
"button",
|
|
6726
7826
|
{
|
|
6727
7827
|
type: "button",
|
|
@@ -6729,37 +7829,37 @@ var Video = import_react41.default.forwardRef((props, ref) => {
|
|
|
6729
7829
|
onClick: toggleCaptions,
|
|
6730
7830
|
"aria-label": captionsOn ? "\uC790\uB9C9 \uB044\uAE30" : "\uC790\uB9C9 \uCF1C\uAE30",
|
|
6731
7831
|
"aria-pressed": captionsOn,
|
|
6732
|
-
children: /* @__PURE__ */ (0,
|
|
7832
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime354.jsx)(TypeIcon_default, {})
|
|
6733
7833
|
}
|
|
6734
7834
|
),
|
|
6735
|
-
showPip && pipSupported && /* @__PURE__ */ (0,
|
|
7835
|
+
showPip && pipSupported && /* @__PURE__ */ (0, import_jsx_runtime354.jsx)(
|
|
6736
7836
|
"button",
|
|
6737
7837
|
{
|
|
6738
7838
|
type: "button",
|
|
6739
7839
|
className: clsx_default("control-btn", isPip && "is-active"),
|
|
6740
7840
|
onClick: togglePip,
|
|
6741
7841
|
"aria-label": isPip ? "PIP \uC885\uB8CC" : "PIP",
|
|
6742
|
-
children: /* @__PURE__ */ (0,
|
|
7842
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime354.jsx)(PipIcon, {})
|
|
6743
7843
|
}
|
|
6744
7844
|
),
|
|
6745
|
-
showDownload && /* @__PURE__ */ (0,
|
|
7845
|
+
showDownload && /* @__PURE__ */ (0, import_jsx_runtime354.jsx)(
|
|
6746
7846
|
"a",
|
|
6747
7847
|
{
|
|
6748
7848
|
className: "control-btn",
|
|
6749
7849
|
href: src,
|
|
6750
7850
|
download: downloadFileName ?? true,
|
|
6751
7851
|
"aria-label": "\uB2E4\uC6B4\uB85C\uB4DC",
|
|
6752
|
-
children: /* @__PURE__ */ (0,
|
|
7852
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime354.jsx)(DownloadIcon_default, {})
|
|
6753
7853
|
}
|
|
6754
7854
|
),
|
|
6755
|
-
/* @__PURE__ */ (0,
|
|
7855
|
+
/* @__PURE__ */ (0, import_jsx_runtime354.jsx)(
|
|
6756
7856
|
"button",
|
|
6757
7857
|
{
|
|
6758
7858
|
type: "button",
|
|
6759
7859
|
className: "control-btn",
|
|
6760
7860
|
onClick: toggleFullscreen,
|
|
6761
7861
|
"aria-label": isFullscreen ? "\uC804\uCCB4\uD654\uBA74 \uC885\uB8CC" : "\uC804\uCCB4\uD654\uBA74",
|
|
6762
|
-
children: isFullscreen ? /* @__PURE__ */ (0,
|
|
7862
|
+
children: isFullscreen ? /* @__PURE__ */ (0, import_jsx_runtime354.jsx)(MinimizeIcon_default, {}) : /* @__PURE__ */ (0, import_jsx_runtime354.jsx)(MaximizeIcon_default, {})
|
|
6763
7863
|
}
|
|
6764
7864
|
)
|
|
6765
7865
|
] })
|
|
@@ -6817,6 +7917,7 @@ var Video_default = Video;
|
|
|
6817
7917
|
SingleDatePicker,
|
|
6818
7918
|
Skeleton,
|
|
6819
7919
|
Spinner,
|
|
7920
|
+
Stat,
|
|
6820
7921
|
Steps,
|
|
6821
7922
|
Swiper,
|
|
6822
7923
|
Switch,
|
|
@@ -6828,6 +7929,7 @@ var Video_default = Video;
|
|
|
6828
7929
|
TableRow,
|
|
6829
7930
|
Tag,
|
|
6830
7931
|
TextArea,
|
|
7932
|
+
TimePicker,
|
|
6831
7933
|
ToastProvider,
|
|
6832
7934
|
Tooltip,
|
|
6833
7935
|
Video,
|