@x-plat/design-system 0.11.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/Dropdown/index.cjs +22 -9
- package/dist/components/Dropdown/index.css +3 -0
- package/dist/components/Dropdown/index.js +22 -9
- package/dist/components/Editor/index.cjs +602 -30
- 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 +602 -30
- package/dist/components/PopOver/index.cjs +21 -7
- package/dist/components/PopOver/index.css +3 -0
- package/dist/components/PopOver/index.js +21 -7
- package/dist/components/Select/index.cjs +21 -8
- package/dist/components/Select/index.css +3 -0
- package/dist/components/Select/index.js +21 -8
- package/dist/components/TimePicker/index.cjs +21 -8
- package/dist/components/TimePicker/index.css +3 -0
- package/dist/components/TimePicker/index.js +21 -8
- package/dist/components/index.cjs +629 -41
- package/dist/components/index.css +110 -0
- package/dist/components/index.js +629 -41
- package/dist/index.cjs +629 -41
- package/dist/index.css +110 -0
- package/dist/index.js +629 -41
- package/guidelines/components/editor.md +58 -3
- package/package.json +1 -1
package/dist/components/index.js
CHANGED
|
@@ -3842,8 +3842,10 @@ import React19 from "react";
|
|
|
3842
3842
|
var useAutoPosition = (triggerRef, popRef, enabled = true) => {
|
|
3843
3843
|
const [position, setPosition] = React19.useState({
|
|
3844
3844
|
position: {},
|
|
3845
|
-
direction: "bottom"
|
|
3845
|
+
direction: "bottom",
|
|
3846
|
+
repositioning: false
|
|
3846
3847
|
});
|
|
3848
|
+
const placedRef = React19.useRef(false);
|
|
3847
3849
|
const calculatePosition = React19.useCallback(() => {
|
|
3848
3850
|
if (!triggerRef.current || !popRef.current) return;
|
|
3849
3851
|
const triggerRect = triggerRef.current.getBoundingClientRect();
|
|
@@ -3868,11 +3870,16 @@ var useAutoPosition = (triggerRef, popRef, enabled = true) => {
|
|
|
3868
3870
|
if (left < 8) left = 8;
|
|
3869
3871
|
setPosition({
|
|
3870
3872
|
position: { top, left },
|
|
3871
|
-
direction
|
|
3873
|
+
direction,
|
|
3874
|
+
repositioning: placedRef.current
|
|
3872
3875
|
});
|
|
3876
|
+
placedRef.current = true;
|
|
3873
3877
|
}, [triggerRef, popRef]);
|
|
3874
3878
|
React19.useLayoutEffect(() => {
|
|
3875
|
-
if (!enabled)
|
|
3879
|
+
if (!enabled) {
|
|
3880
|
+
placedRef.current = false;
|
|
3881
|
+
return;
|
|
3882
|
+
}
|
|
3876
3883
|
calculatePosition();
|
|
3877
3884
|
const raf = requestAnimationFrame(calculatePosition);
|
|
3878
3885
|
return () => cancelAnimationFrame(raf);
|
|
@@ -3887,11 +3894,17 @@ var useAutoPosition = (triggerRef, popRef, enabled = true) => {
|
|
|
3887
3894
|
}, [calculatePosition, enabled, popRef]);
|
|
3888
3895
|
React19.useEffect(() => {
|
|
3889
3896
|
if (!enabled) return;
|
|
3890
|
-
|
|
3891
|
-
|
|
3897
|
+
let raf = 0;
|
|
3898
|
+
const onScrollOrResize = () => {
|
|
3899
|
+
cancelAnimationFrame(raf);
|
|
3900
|
+
raf = requestAnimationFrame(calculatePosition);
|
|
3901
|
+
};
|
|
3902
|
+
window.addEventListener("resize", onScrollOrResize, { passive: true });
|
|
3903
|
+
window.addEventListener("scroll", onScrollOrResize, { passive: true, capture: true });
|
|
3892
3904
|
return () => {
|
|
3893
|
-
|
|
3894
|
-
window.removeEventListener("
|
|
3905
|
+
cancelAnimationFrame(raf);
|
|
3906
|
+
window.removeEventListener("resize", onScrollOrResize);
|
|
3907
|
+
window.removeEventListener("scroll", onScrollOrResize, true);
|
|
3895
3908
|
};
|
|
3896
3909
|
}, [calculatePosition, enabled]);
|
|
3897
3910
|
return position;
|
|
@@ -3932,7 +3945,7 @@ var Dropdown = (props) => {
|
|
|
3932
3945
|
const [visible, setVisible] = React21.useState(false);
|
|
3933
3946
|
const triggerRef = React21.useRef(null);
|
|
3934
3947
|
const menuRef = React21.useRef(null);
|
|
3935
|
-
const { position, direction } = useAutoPosition_default(triggerRef, menuRef, mounted);
|
|
3948
|
+
const { position, direction, repositioning } = useAutoPosition_default(triggerRef, menuRef, mounted);
|
|
3936
3949
|
useClickOutside_default([triggerRef, menuRef], () => setIsOpen(false), isOpen);
|
|
3937
3950
|
useEscapeKey(isOpen, () => {
|
|
3938
3951
|
setIsOpen(false);
|
|
@@ -3967,7 +3980,7 @@ var Dropdown = (props) => {
|
|
|
3967
3980
|
"div",
|
|
3968
3981
|
{
|
|
3969
3982
|
ref: menuRef,
|
|
3970
|
-
className: clsx_default("lib-xplat-dropdown-menu", direction, { visible }),
|
|
3983
|
+
className: clsx_default("lib-xplat-dropdown-menu", direction, { visible }, repositioning && "repositioning"),
|
|
3971
3984
|
style: { top: position.top, left: position.left },
|
|
3972
3985
|
role: "menu",
|
|
3973
3986
|
children: items.map((item) => /* @__PURE__ */ jsx322(
|
|
@@ -3993,6 +4006,111 @@ var Dropdown_default = Dropdown;
|
|
|
3993
4006
|
|
|
3994
4007
|
// src/components/Editor/Editor.tsx
|
|
3995
4008
|
import React22 from "react";
|
|
4009
|
+
|
|
4010
|
+
// src/components/Editor/highlight.ts
|
|
4011
|
+
var CODE_LANGUAGES = [
|
|
4012
|
+
{ value: "plain", label: "\uC5C6\uC74C" },
|
|
4013
|
+
{ value: "javascript", label: "JavaScript" },
|
|
4014
|
+
{ value: "typescript", label: "TypeScript" },
|
|
4015
|
+
{ value: "json", label: "JSON" },
|
|
4016
|
+
{ value: "html", label: "HTML" },
|
|
4017
|
+
{ value: "css", label: "CSS" },
|
|
4018
|
+
{ value: "python", label: "Python" },
|
|
4019
|
+
{ value: "sql", label: "SQL" },
|
|
4020
|
+
{ value: "bash", label: "Bash" }
|
|
4021
|
+
];
|
|
4022
|
+
var KEYWORDS = {
|
|
4023
|
+
plain: [],
|
|
4024
|
+
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(" "),
|
|
4025
|
+
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(" "),
|
|
4026
|
+
json: ["true", "false", "null"],
|
|
4027
|
+
html: [],
|
|
4028
|
+
css: [],
|
|
4029
|
+
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(" "),
|
|
4030
|
+
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(" "),
|
|
4031
|
+
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(" ")
|
|
4032
|
+
};
|
|
4033
|
+
var LINE_COMMENT = {
|
|
4034
|
+
javascript: "//",
|
|
4035
|
+
typescript: "//",
|
|
4036
|
+
css: "",
|
|
4037
|
+
python: "#",
|
|
4038
|
+
sql: "--",
|
|
4039
|
+
bash: "#"
|
|
4040
|
+
};
|
|
4041
|
+
var escape = (s) => s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
4042
|
+
var wrap = (cls, text) => `<span class="tok-${cls}">${escape(text)}</span>`;
|
|
4043
|
+
var highlight = (code, lang) => {
|
|
4044
|
+
if (lang === "plain" || !code) return escape(code);
|
|
4045
|
+
const keywords = new Set(KEYWORDS[lang]);
|
|
4046
|
+
const lineComment = LINE_COMMENT[lang];
|
|
4047
|
+
const caseInsensitive = lang === "sql";
|
|
4048
|
+
let out = "";
|
|
4049
|
+
let i = 0;
|
|
4050
|
+
while (i < code.length) {
|
|
4051
|
+
const rest = code.slice(i);
|
|
4052
|
+
if ((lang === "javascript" || lang === "typescript" || lang === "css") && rest.startsWith("/*")) {
|
|
4053
|
+
const end = code.indexOf("*/", i + 2);
|
|
4054
|
+
const stop = end === -1 ? code.length : end + 2;
|
|
4055
|
+
out += wrap("comment", code.slice(i, stop));
|
|
4056
|
+
i = stop;
|
|
4057
|
+
continue;
|
|
4058
|
+
}
|
|
4059
|
+
if (lineComment && rest.startsWith(lineComment)) {
|
|
4060
|
+
const nl = code.indexOf("\n", i);
|
|
4061
|
+
const stop = nl === -1 ? code.length : nl;
|
|
4062
|
+
out += wrap("comment", code.slice(i, stop));
|
|
4063
|
+
i = stop;
|
|
4064
|
+
continue;
|
|
4065
|
+
}
|
|
4066
|
+
const q = rest[0];
|
|
4067
|
+
if (q === '"' || q === "'" || q === "`") {
|
|
4068
|
+
let j = 1;
|
|
4069
|
+
while (j < rest.length) {
|
|
4070
|
+
if (rest[j] === "\\") {
|
|
4071
|
+
j += 2;
|
|
4072
|
+
continue;
|
|
4073
|
+
}
|
|
4074
|
+
if (rest[j] === q) {
|
|
4075
|
+
j += 1;
|
|
4076
|
+
break;
|
|
4077
|
+
}
|
|
4078
|
+
if (rest[j] === "\n" && q !== "`") break;
|
|
4079
|
+
j += 1;
|
|
4080
|
+
}
|
|
4081
|
+
out += wrap("string", rest.slice(0, j));
|
|
4082
|
+
i += j;
|
|
4083
|
+
continue;
|
|
4084
|
+
}
|
|
4085
|
+
const num = /^\d+(\.\d+)?/.exec(rest);
|
|
4086
|
+
if (num && !/[\w$]/.test(code[i - 1] ?? "")) {
|
|
4087
|
+
out += wrap("number", num[0]);
|
|
4088
|
+
i += num[0].length;
|
|
4089
|
+
continue;
|
|
4090
|
+
}
|
|
4091
|
+
const word = /^[A-Za-z_$][\w$]*/.exec(rest);
|
|
4092
|
+
if (word) {
|
|
4093
|
+
const w = word[0];
|
|
4094
|
+
const hit = caseInsensitive ? keywords.has(w.toUpperCase()) : keywords.has(w);
|
|
4095
|
+
out += hit ? wrap("keyword", w) : escape(w);
|
|
4096
|
+
i += w.length;
|
|
4097
|
+
continue;
|
|
4098
|
+
}
|
|
4099
|
+
if (lang === "html" && rest.startsWith("<")) {
|
|
4100
|
+
const tag = /^<\/?[A-Za-z][\w-]*/.exec(rest);
|
|
4101
|
+
if (tag) {
|
|
4102
|
+
out += wrap("keyword", tag[0]);
|
|
4103
|
+
i += tag[0].length;
|
|
4104
|
+
continue;
|
|
4105
|
+
}
|
|
4106
|
+
}
|
|
4107
|
+
out += escape(code[i]);
|
|
4108
|
+
i += 1;
|
|
4109
|
+
}
|
|
4110
|
+
return out;
|
|
4111
|
+
};
|
|
4112
|
+
|
|
4113
|
+
// src/components/Editor/Editor.tsx
|
|
3996
4114
|
import { jsx as jsx323, jsxs as jsxs207 } from "react/jsx-runtime";
|
|
3997
4115
|
var DEFAULT_TOOLBAR = [
|
|
3998
4116
|
"bold",
|
|
@@ -4000,14 +4118,27 @@ var DEFAULT_TOOLBAR = [
|
|
|
4000
4118
|
"underline",
|
|
4001
4119
|
"strikethrough",
|
|
4002
4120
|
"code",
|
|
4003
|
-
"heading",
|
|
4121
|
+
"heading-1",
|
|
4122
|
+
"heading-2",
|
|
4123
|
+
"heading-3",
|
|
4004
4124
|
"list",
|
|
4005
4125
|
"ordered-list",
|
|
4006
4126
|
"blockquote",
|
|
4007
4127
|
"code-block",
|
|
4008
4128
|
"link",
|
|
4009
4129
|
"image",
|
|
4010
|
-
"divider"
|
|
4130
|
+
"divider",
|
|
4131
|
+
"checklist",
|
|
4132
|
+
"table",
|
|
4133
|
+
"align-left",
|
|
4134
|
+
"align-center",
|
|
4135
|
+
"align-right",
|
|
4136
|
+
"highlight",
|
|
4137
|
+
"superscript",
|
|
4138
|
+
"subscript",
|
|
4139
|
+
"clear-format",
|
|
4140
|
+
"undo",
|
|
4141
|
+
"redo"
|
|
4011
4142
|
];
|
|
4012
4143
|
var ALLOWED_TAGS = /* @__PURE__ */ new Set([
|
|
4013
4144
|
"p",
|
|
@@ -4036,11 +4167,41 @@ var ALLOWED_TAGS = /* @__PURE__ */ new Set([
|
|
|
4036
4167
|
"img",
|
|
4037
4168
|
"hr",
|
|
4038
4169
|
"span",
|
|
4039
|
-
"div"
|
|
4170
|
+
"div",
|
|
4171
|
+
"sub",
|
|
4172
|
+
"sup",
|
|
4173
|
+
"mark",
|
|
4174
|
+
"table",
|
|
4175
|
+
"thead",
|
|
4176
|
+
"tbody",
|
|
4177
|
+
"tr",
|
|
4178
|
+
"th",
|
|
4179
|
+
"td"
|
|
4040
4180
|
]);
|
|
4041
4181
|
var ALLOWED_ATTRS = {
|
|
4042
4182
|
a: ["href", "target", "rel"],
|
|
4043
|
-
img: ["src", "alt"]
|
|
4183
|
+
img: ["src", "alt", "width"],
|
|
4184
|
+
// 정렬·체크리스트는 클래스로만 표현한다. style 을 열면 붙여넣기로 아무 CSS 나 들어온다
|
|
4185
|
+
p: ["class"],
|
|
4186
|
+
h1: ["class"],
|
|
4187
|
+
h2: ["class"],
|
|
4188
|
+
h3: ["class"],
|
|
4189
|
+
h4: ["class"],
|
|
4190
|
+
h5: ["class"],
|
|
4191
|
+
h6: ["class"],
|
|
4192
|
+
ul: ["class"],
|
|
4193
|
+
ol: ["class"],
|
|
4194
|
+
li: ["class", "data-checked"],
|
|
4195
|
+
blockquote: ["class"],
|
|
4196
|
+
div: ["class"],
|
|
4197
|
+
span: ["class"],
|
|
4198
|
+
pre: ["class"],
|
|
4199
|
+
code: ["class"],
|
|
4200
|
+
mark: ["class"],
|
|
4201
|
+
table: ["class"],
|
|
4202
|
+
td: ["class"],
|
|
4203
|
+
th: ["class"],
|
|
4204
|
+
tr: ["class"]
|
|
4044
4205
|
};
|
|
4045
4206
|
var DROP_WITH_CONTENT = /* @__PURE__ */ new Set([
|
|
4046
4207
|
"script",
|
|
@@ -4093,7 +4254,9 @@ var escapeHtml = (text) => {
|
|
|
4093
4254
|
};
|
|
4094
4255
|
var SLASH_ITEMS = [
|
|
4095
4256
|
{ key: "paragraph", label: "\uB2E8\uB77D", hint: "\uAE30\uBCF8 \uD14D\uC2A4\uD2B8" },
|
|
4096
|
-
{ key: "heading", label: "\uC81C\uBAA9 1", hint: "\uD070 \uC81C\uBAA9" },
|
|
4257
|
+
{ key: "heading-1", label: "\uC81C\uBAA9 1", hint: "\uAC00\uC7A5 \uD070 \uC81C\uBAA9" },
|
|
4258
|
+
{ key: "heading-2", label: "\uC81C\uBAA9 2", hint: "" },
|
|
4259
|
+
{ key: "heading-3", label: "\uC81C\uBAA9 3", hint: "" },
|
|
4097
4260
|
{ key: "list", label: "\uAE00\uBA38\uB9AC \uAE30\uD638 \uBAA9\uB85D", hint: "\u2022 \uD56D\uBAA9" },
|
|
4098
4261
|
{ key: "ordered-list", label: "\uBC88\uD638 \uB9E4\uAE30\uAE30 \uBAA9\uB85D", hint: "1. \uD56D\uBAA9" },
|
|
4099
4262
|
{ key: "blockquote", label: "\uC778\uC6A9", hint: "" },
|
|
@@ -4136,6 +4299,8 @@ var Editor = (props) => {
|
|
|
4136
4299
|
el.innerHTML = sanitizeHtml(value || "");
|
|
4137
4300
|
if (!el.firstChild) el.innerHTML = "<p><br></p>";
|
|
4138
4301
|
lastEmittedRef.current = null;
|
|
4302
|
+
historyRef.current = [{ html: el.innerHTML, caret: 0 }];
|
|
4303
|
+
historyIdxRef.current = 0;
|
|
4139
4304
|
updateEmpty();
|
|
4140
4305
|
}, [value]);
|
|
4141
4306
|
const updateEmpty = () => {
|
|
@@ -4180,6 +4345,17 @@ var Editor = (props) => {
|
|
|
4180
4345
|
if (document.queryCommandState("insertOrderedList")) next.add("ordered-list");
|
|
4181
4346
|
const block = String(document.queryCommandValue("formatBlock") || "").toLowerCase();
|
|
4182
4347
|
if (block) next.add(`block:${block}`);
|
|
4348
|
+
if (document.queryCommandState("superscript")) next.add("superscript");
|
|
4349
|
+
if (document.queryCommandState("subscript")) next.add("subscript");
|
|
4350
|
+
} catch {
|
|
4351
|
+
}
|
|
4352
|
+
try {
|
|
4353
|
+
const blockEl = currentBlock();
|
|
4354
|
+
if (blockEl?.classList.contains("align-center")) next.add("align:center");
|
|
4355
|
+
else if (blockEl?.classList.contains("align-right")) next.add("align:right");
|
|
4356
|
+
else if (blockEl) next.add("align:left");
|
|
4357
|
+
if (blockEl?.closest("mark")) next.add("highlight");
|
|
4358
|
+
if (blockEl?.closest("ul.checklist")) next.add("checklist");
|
|
4183
4359
|
} catch {
|
|
4184
4360
|
}
|
|
4185
4361
|
setActiveFormats(next);
|
|
@@ -4193,6 +4369,122 @@ var Editor = (props) => {
|
|
|
4193
4369
|
const setBlock = (tag) => {
|
|
4194
4370
|
exec("formatBlock", tag);
|
|
4195
4371
|
};
|
|
4372
|
+
const toggleBlock = (tag) => {
|
|
4373
|
+
const current = String(document.queryCommandValue("formatBlock") || "").toLowerCase();
|
|
4374
|
+
setBlock(current === tag ? "p" : tag);
|
|
4375
|
+
};
|
|
4376
|
+
const historyRef = React22.useRef([]);
|
|
4377
|
+
const historyIdxRef = React22.useRef(-1);
|
|
4378
|
+
const lastPushAtRef = React22.useRef(0);
|
|
4379
|
+
const isRestoringRef = React22.useRef(false);
|
|
4380
|
+
const caretOffset = (rootEl) => {
|
|
4381
|
+
const el = rootEl ?? editorRef.current;
|
|
4382
|
+
const sel = window.getSelection();
|
|
4383
|
+
if (!el || !sel || sel.rangeCount === 0 || !el.contains(sel.anchorNode)) return 0;
|
|
4384
|
+
const range = sel.getRangeAt(0).cloneRange();
|
|
4385
|
+
range.selectNodeContents(el);
|
|
4386
|
+
range.setEnd(sel.getRangeAt(0).endContainer, sel.getRangeAt(0).endOffset);
|
|
4387
|
+
return range.toString().length;
|
|
4388
|
+
};
|
|
4389
|
+
const setCaretOffset = (offset, rootEl) => {
|
|
4390
|
+
const el = rootEl ?? editorRef.current;
|
|
4391
|
+
if (!el) return;
|
|
4392
|
+
const walker = document.createTreeWalker(el, NodeFilter.SHOW_TEXT);
|
|
4393
|
+
let remaining = offset;
|
|
4394
|
+
let node = null;
|
|
4395
|
+
while (node = walker.nextNode()) {
|
|
4396
|
+
const len = node.textContent?.length ?? 0;
|
|
4397
|
+
if (remaining <= len) {
|
|
4398
|
+
const range = document.createRange();
|
|
4399
|
+
range.setStart(node, remaining);
|
|
4400
|
+
range.collapse(true);
|
|
4401
|
+
const sel = window.getSelection();
|
|
4402
|
+
sel?.removeAllRanges();
|
|
4403
|
+
sel?.addRange(range);
|
|
4404
|
+
return;
|
|
4405
|
+
}
|
|
4406
|
+
remaining -= len;
|
|
4407
|
+
}
|
|
4408
|
+
placeCaretAtEnd(el);
|
|
4409
|
+
};
|
|
4410
|
+
const pushHistory = (force = false) => {
|
|
4411
|
+
const el = editorRef.current;
|
|
4412
|
+
if (!el || isRestoringRef.current) return;
|
|
4413
|
+
const html = el.innerHTML;
|
|
4414
|
+
const hist = historyRef.current;
|
|
4415
|
+
const cur = hist[historyIdxRef.current];
|
|
4416
|
+
if (cur && cur.html === html) return;
|
|
4417
|
+
const now = Date.now();
|
|
4418
|
+
const coalesce = !force && cur && now - lastPushAtRef.current < 500;
|
|
4419
|
+
lastPushAtRef.current = now;
|
|
4420
|
+
if (coalesce) {
|
|
4421
|
+
hist[historyIdxRef.current] = { html, caret: caretOffset() };
|
|
4422
|
+
return;
|
|
4423
|
+
}
|
|
4424
|
+
hist.length = historyIdxRef.current + 1;
|
|
4425
|
+
hist.push({ html, caret: caretOffset() });
|
|
4426
|
+
if (hist.length > 200) hist.shift();
|
|
4427
|
+
historyIdxRef.current = hist.length - 1;
|
|
4428
|
+
};
|
|
4429
|
+
const applySnapshot = (snap) => {
|
|
4430
|
+
const el = editorRef.current;
|
|
4431
|
+
if (!el) return;
|
|
4432
|
+
isRestoringRef.current = true;
|
|
4433
|
+
el.innerHTML = snap.html;
|
|
4434
|
+
setCaretOffset(snap.caret);
|
|
4435
|
+
isRestoringRef.current = false;
|
|
4436
|
+
lastEmittedRef.current = el.innerHTML;
|
|
4437
|
+
onChange?.(el.innerHTML);
|
|
4438
|
+
updateEmpty();
|
|
4439
|
+
updateActiveFormats();
|
|
4440
|
+
};
|
|
4441
|
+
const undo = () => {
|
|
4442
|
+
pushHistory(true);
|
|
4443
|
+
if (historyIdxRef.current <= 0) return;
|
|
4444
|
+
historyIdxRef.current -= 1;
|
|
4445
|
+
applySnapshot(historyRef.current[historyIdxRef.current]);
|
|
4446
|
+
};
|
|
4447
|
+
const redo = () => {
|
|
4448
|
+
if (historyIdxRef.current >= historyRef.current.length - 1) return;
|
|
4449
|
+
historyIdxRef.current += 1;
|
|
4450
|
+
applySnapshot(historyRef.current[historyIdxRef.current]);
|
|
4451
|
+
};
|
|
4452
|
+
const langOf = (pre) => {
|
|
4453
|
+
const cls = Array.from(pre.classList).find((c) => c.startsWith("lang-"));
|
|
4454
|
+
return cls?.slice(5) ?? "plain";
|
|
4455
|
+
};
|
|
4456
|
+
const [codeLang, setCodeLang] = React22.useState("plain");
|
|
4457
|
+
const highlightRafRef = React22.useRef(0);
|
|
4458
|
+
const rehighlight = (pre) => {
|
|
4459
|
+
if (composingRef.current) return;
|
|
4460
|
+
const code = pre.querySelector("code");
|
|
4461
|
+
if (!code) return;
|
|
4462
|
+
const lang = langOf(pre);
|
|
4463
|
+
const text = code.textContent || "";
|
|
4464
|
+
const next = highlight(text, lang);
|
|
4465
|
+
if (code.innerHTML === next) return;
|
|
4466
|
+
const caret = caretOffset(code);
|
|
4467
|
+
isRestoringRef.current = true;
|
|
4468
|
+
code.innerHTML = next;
|
|
4469
|
+
setCaretOffset(caret, code);
|
|
4470
|
+
isRestoringRef.current = false;
|
|
4471
|
+
};
|
|
4472
|
+
const scheduleHighlight = () => {
|
|
4473
|
+
const pre = closestPre();
|
|
4474
|
+
if (!pre) return;
|
|
4475
|
+
cancelAnimationFrame(highlightRafRef.current);
|
|
4476
|
+
highlightRafRef.current = requestAnimationFrame(() => rehighlight(pre));
|
|
4477
|
+
};
|
|
4478
|
+
const changeCodeLang = (lang) => {
|
|
4479
|
+
const pre = closestPre();
|
|
4480
|
+
if (!pre) return;
|
|
4481
|
+
pushHistory(true);
|
|
4482
|
+
Array.from(pre.classList).filter((c) => c.startsWith("lang-")).forEach((c) => pre.classList.remove(c));
|
|
4483
|
+
if (lang !== "plain") pre.classList.add(`lang-${lang}`);
|
|
4484
|
+
setCodeLang(lang);
|
|
4485
|
+
rehighlight(pre);
|
|
4486
|
+
handleInput();
|
|
4487
|
+
};
|
|
4196
4488
|
const closestPre = () => {
|
|
4197
4489
|
const sel = window.getSelection();
|
|
4198
4490
|
const node = sel?.anchorNode;
|
|
@@ -4201,6 +4493,7 @@ var Editor = (props) => {
|
|
|
4201
4493
|
return el?.closest("pre") ?? null;
|
|
4202
4494
|
};
|
|
4203
4495
|
const insertCodeBlock = () => {
|
|
4496
|
+
pushHistory(true);
|
|
4204
4497
|
const el = editorRef.current;
|
|
4205
4498
|
const sel = window.getSelection();
|
|
4206
4499
|
if (!el || !sel || sel.rangeCount === 0) return;
|
|
@@ -4283,7 +4576,167 @@ var Editor = (props) => {
|
|
|
4283
4576
|
sel.addRange(r2);
|
|
4284
4577
|
editorRef.current?.focus();
|
|
4285
4578
|
};
|
|
4579
|
+
const clearFormat = () => {
|
|
4580
|
+
exec("removeFormat");
|
|
4581
|
+
exec("unlink");
|
|
4582
|
+
setBlock("p");
|
|
4583
|
+
};
|
|
4584
|
+
const indentList = (outdent) => {
|
|
4585
|
+
exec(outdent ? "outdent" : "indent");
|
|
4586
|
+
};
|
|
4587
|
+
const inListItem = () => {
|
|
4588
|
+
const sel = window.getSelection();
|
|
4589
|
+
const node = sel?.anchorNode;
|
|
4590
|
+
if (!node || !editorRef.current?.contains(node)) return false;
|
|
4591
|
+
const el = node.nodeType === Node.ELEMENT_NODE ? node : node.parentElement;
|
|
4592
|
+
return !!el?.closest("li");
|
|
4593
|
+
};
|
|
4594
|
+
const currentBlock = () => {
|
|
4595
|
+
const sel = window.getSelection();
|
|
4596
|
+
const node = sel?.anchorNode;
|
|
4597
|
+
const root = editorRef.current;
|
|
4598
|
+
if (!node || !root?.contains(node)) return null;
|
|
4599
|
+
let el = node.nodeType === Node.ELEMENT_NODE ? node : node.parentElement;
|
|
4600
|
+
while (el && el !== root && !/^(P|H[1-6]|LI|BLOCKQUOTE|PRE|DIV|TD|TH)$/.test(el.tagName)) {
|
|
4601
|
+
el = el.parentElement;
|
|
4602
|
+
}
|
|
4603
|
+
return el && el !== root ? el : null;
|
|
4604
|
+
};
|
|
4605
|
+
const setAlign = (align) => {
|
|
4606
|
+
const block = currentBlock();
|
|
4607
|
+
if (!block) return;
|
|
4608
|
+
pushHistory(true);
|
|
4609
|
+
block.classList.remove("align-left", "align-center", "align-right");
|
|
4610
|
+
if (align !== "left") block.classList.add(`align-${align}`);
|
|
4611
|
+
handleInput();
|
|
4612
|
+
};
|
|
4613
|
+
const toggleChecklist = () => {
|
|
4614
|
+
pushHistory(true);
|
|
4615
|
+
const block = currentBlock();
|
|
4616
|
+
const list = block?.closest("ul");
|
|
4617
|
+
if (list?.classList.contains("checklist")) {
|
|
4618
|
+
list.classList.remove("checklist");
|
|
4619
|
+
list.querySelectorAll("li").forEach((li) => li.removeAttribute("data-checked"));
|
|
4620
|
+
handleInput();
|
|
4621
|
+
return;
|
|
4622
|
+
}
|
|
4623
|
+
if (list) {
|
|
4624
|
+
list.classList.add("checklist");
|
|
4625
|
+
list.querySelectorAll("li").forEach((li) => li.setAttribute("data-checked", "false"));
|
|
4626
|
+
handleInput();
|
|
4627
|
+
return;
|
|
4628
|
+
}
|
|
4629
|
+
exec("insertUnorderedList");
|
|
4630
|
+
const made = currentBlock()?.closest("ul");
|
|
4631
|
+
if (made) {
|
|
4632
|
+
made.classList.add("checklist");
|
|
4633
|
+
made.querySelectorAll("li").forEach((li) => li.setAttribute("data-checked", "false"));
|
|
4634
|
+
}
|
|
4635
|
+
handleInput();
|
|
4636
|
+
};
|
|
4637
|
+
const handleEditorClick = (e) => {
|
|
4638
|
+
if (readOnly) return;
|
|
4639
|
+
const target = e.target;
|
|
4640
|
+
const li = target.closest?.("li");
|
|
4641
|
+
if (!li || !li.closest("ul.checklist")) return;
|
|
4642
|
+
const rect = li.getBoundingClientRect();
|
|
4643
|
+
if (e.clientX - rect.left > 20) return;
|
|
4644
|
+
e.preventDefault();
|
|
4645
|
+
pushHistory(true);
|
|
4646
|
+
li.setAttribute("data-checked", li.getAttribute("data-checked") === "true" ? "false" : "true");
|
|
4647
|
+
handleInput();
|
|
4648
|
+
};
|
|
4649
|
+
const toggleHighlight = () => {
|
|
4650
|
+
const sel = window.getSelection();
|
|
4651
|
+
if (!sel || sel.rangeCount === 0 || sel.isCollapsed) return;
|
|
4652
|
+
pushHistory(true);
|
|
4653
|
+
const range = sel.getRangeAt(0);
|
|
4654
|
+
const node = sel.anchorNode;
|
|
4655
|
+
const el = node?.nodeType === Node.ELEMENT_NODE ? node : node?.parentElement;
|
|
4656
|
+
const existing = el?.closest("mark");
|
|
4657
|
+
if (existing) {
|
|
4658
|
+
const parent = existing.parentNode;
|
|
4659
|
+
while (existing.firstChild) parent?.insertBefore(existing.firstChild, existing);
|
|
4660
|
+
parent?.removeChild(existing);
|
|
4661
|
+
handleInput();
|
|
4662
|
+
return;
|
|
4663
|
+
}
|
|
4664
|
+
const mark = document.createElement("mark");
|
|
4665
|
+
try {
|
|
4666
|
+
range.surroundContents(mark);
|
|
4667
|
+
} catch {
|
|
4668
|
+
const frag = range.extractContents();
|
|
4669
|
+
mark.appendChild(frag);
|
|
4670
|
+
range.insertNode(mark);
|
|
4671
|
+
}
|
|
4672
|
+
handleInput();
|
|
4673
|
+
};
|
|
4674
|
+
const insertTable = (cols = 3, rows = 2) => {
|
|
4675
|
+
const sel = window.getSelection();
|
|
4676
|
+
if (!sel || sel.rangeCount === 0) return;
|
|
4677
|
+
pushHistory(true);
|
|
4678
|
+
const table = document.createElement("table");
|
|
4679
|
+
const thead = document.createElement("thead");
|
|
4680
|
+
const headRow = document.createElement("tr");
|
|
4681
|
+
for (let c = 0; c < cols; c++) {
|
|
4682
|
+
const th = document.createElement("th");
|
|
4683
|
+
th.innerHTML = "<br>";
|
|
4684
|
+
headRow.appendChild(th);
|
|
4685
|
+
}
|
|
4686
|
+
thead.appendChild(headRow);
|
|
4687
|
+
table.appendChild(thead);
|
|
4688
|
+
const tbody = document.createElement("tbody");
|
|
4689
|
+
for (let r2 = 0; r2 < rows; r2++) {
|
|
4690
|
+
const tr = document.createElement("tr");
|
|
4691
|
+
for (let c = 0; c < cols; c++) {
|
|
4692
|
+
const td = document.createElement("td");
|
|
4693
|
+
td.innerHTML = "<br>";
|
|
4694
|
+
tr.appendChild(td);
|
|
4695
|
+
}
|
|
4696
|
+
tbody.appendChild(tr);
|
|
4697
|
+
}
|
|
4698
|
+
table.appendChild(tbody);
|
|
4699
|
+
const range = sel.getRangeAt(0);
|
|
4700
|
+
range.deleteContents();
|
|
4701
|
+
range.insertNode(table);
|
|
4702
|
+
ensureParagraphAfter(table);
|
|
4703
|
+
const first = table.querySelector("th");
|
|
4704
|
+
if (first) placeCaretAtEnd(first);
|
|
4705
|
+
handleInput();
|
|
4706
|
+
};
|
|
4707
|
+
const moveTableCell = (backwards) => {
|
|
4708
|
+
const block = currentBlock();
|
|
4709
|
+
const cell = block?.closest("td, th");
|
|
4710
|
+
if (!cell) return false;
|
|
4711
|
+
const table = cell.closest("table");
|
|
4712
|
+
if (!table) return false;
|
|
4713
|
+
const cells = Array.from(table.querySelectorAll("td, th"));
|
|
4714
|
+
const i = cells.indexOf(cell);
|
|
4715
|
+
const next = cells[i + (backwards ? -1 : 1)];
|
|
4716
|
+
if (next) {
|
|
4717
|
+
placeCaretAtEnd(next);
|
|
4718
|
+
return true;
|
|
4719
|
+
}
|
|
4720
|
+
if (!backwards) {
|
|
4721
|
+
pushHistory(true);
|
|
4722
|
+
const lastRow = table.querySelector("tbody")?.lastElementChild;
|
|
4723
|
+
if (lastRow) {
|
|
4724
|
+
const tr = document.createElement("tr");
|
|
4725
|
+
for (let c = 0; c < lastRow.children.length; c++) {
|
|
4726
|
+
const td = document.createElement("td");
|
|
4727
|
+
td.innerHTML = "<br>";
|
|
4728
|
+
tr.appendChild(td);
|
|
4729
|
+
}
|
|
4730
|
+
lastRow.after(tr);
|
|
4731
|
+
placeCaretAtEnd(tr.firstElementChild);
|
|
4732
|
+
handleInput();
|
|
4733
|
+
return true;
|
|
4734
|
+
}
|
|
4735
|
+
}
|
|
4736
|
+
return false;
|
|
4737
|
+
};
|
|
4286
4738
|
const insertDivider = () => {
|
|
4739
|
+
pushHistory(true);
|
|
4287
4740
|
exec("insertHorizontalRule");
|
|
4288
4741
|
const el = editorRef.current;
|
|
4289
4742
|
if (el && el.lastElementChild?.tagName === "HR") {
|
|
@@ -4376,8 +4829,14 @@ var Editor = (props) => {
|
|
|
4376
4829
|
case "paragraph":
|
|
4377
4830
|
setBlock("p");
|
|
4378
4831
|
break;
|
|
4379
|
-
case "heading":
|
|
4380
|
-
|
|
4832
|
+
case "heading-1":
|
|
4833
|
+
toggleBlock("h1");
|
|
4834
|
+
break;
|
|
4835
|
+
case "heading-2":
|
|
4836
|
+
toggleBlock("h2");
|
|
4837
|
+
break;
|
|
4838
|
+
case "heading-3":
|
|
4839
|
+
toggleBlock("h3");
|
|
4381
4840
|
break;
|
|
4382
4841
|
case "list":
|
|
4383
4842
|
exec("insertUnorderedList");
|
|
@@ -4470,6 +4929,8 @@ var Editor = (props) => {
|
|
|
4470
4929
|
if (!el) return;
|
|
4471
4930
|
const html = el.innerHTML;
|
|
4472
4931
|
lastEmittedRef.current = html;
|
|
4932
|
+
pushHistory();
|
|
4933
|
+
scheduleHighlight();
|
|
4473
4934
|
onChange?.(html);
|
|
4474
4935
|
updateEmpty();
|
|
4475
4936
|
updateActiveFormats();
|
|
@@ -4523,6 +4984,15 @@ var Editor = (props) => {
|
|
|
4523
4984
|
return;
|
|
4524
4985
|
}
|
|
4525
4986
|
}
|
|
4987
|
+
if (e.key === "Tab" && moveTableCell(e.shiftKey)) {
|
|
4988
|
+
e.preventDefault();
|
|
4989
|
+
return;
|
|
4990
|
+
}
|
|
4991
|
+
if (e.key === "Tab" && inListItem()) {
|
|
4992
|
+
e.preventDefault();
|
|
4993
|
+
indentList(e.shiftKey);
|
|
4994
|
+
return;
|
|
4995
|
+
}
|
|
4526
4996
|
if (slashOpen) {
|
|
4527
4997
|
if (e.key === "ArrowDown") {
|
|
4528
4998
|
e.preventDefault();
|
|
@@ -4546,6 +5016,21 @@ var Editor = (props) => {
|
|
|
4546
5016
|
return;
|
|
4547
5017
|
}
|
|
4548
5018
|
}
|
|
5019
|
+
if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === "z") {
|
|
5020
|
+
e.preventDefault();
|
|
5021
|
+
if (e.shiftKey) redo();
|
|
5022
|
+
else undo();
|
|
5023
|
+
return;
|
|
5024
|
+
}
|
|
5025
|
+
if ((e.metaKey || e.ctrlKey) && e.shiftKey && e.key.toLowerCase() === "v") {
|
|
5026
|
+
plainPasteRef.current = true;
|
|
5027
|
+
return;
|
|
5028
|
+
}
|
|
5029
|
+
if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === "y") {
|
|
5030
|
+
e.preventDefault();
|
|
5031
|
+
redo();
|
|
5032
|
+
return;
|
|
5033
|
+
}
|
|
4549
5034
|
if ((e.metaKey || e.ctrlKey) && !e.shiftKey && !e.altKey) {
|
|
4550
5035
|
const k = e.key.toLowerCase();
|
|
4551
5036
|
if (k === "b") {
|
|
@@ -4579,10 +5064,16 @@ var Editor = (props) => {
|
|
|
4579
5064
|
}
|
|
4580
5065
|
}
|
|
4581
5066
|
};
|
|
5067
|
+
const plainPasteRef = React22.useRef(false);
|
|
4582
5068
|
const handlePaste = (e) => {
|
|
4583
5069
|
if (readOnly) return;
|
|
4584
5070
|
e.preventDefault();
|
|
4585
5071
|
const text = e.clipboardData.getData("text/plain");
|
|
5072
|
+
if (plainPasteRef.current) {
|
|
5073
|
+
plainPasteRef.current = false;
|
|
5074
|
+
insertTextAtCaret(text);
|
|
5075
|
+
return;
|
|
5076
|
+
}
|
|
4586
5077
|
if (closestPre()) {
|
|
4587
5078
|
insertTextAtCaret(text);
|
|
4588
5079
|
return;
|
|
@@ -4609,9 +5100,11 @@ var Editor = (props) => {
|
|
|
4609
5100
|
};
|
|
4610
5101
|
const handleSelectionUpdate = () => {
|
|
4611
5102
|
updateActiveFormats();
|
|
5103
|
+
const pre = closestPre();
|
|
5104
|
+
setCodeLang(pre ? langOf(pre) : "plain");
|
|
4612
5105
|
};
|
|
4613
5106
|
const onToolbarAction = (item) => {
|
|
4614
|
-
if (closestPre() &&
|
|
5107
|
+
if (closestPre() && !["code-block", "undo", "redo"].includes(item)) return;
|
|
4615
5108
|
switch (item) {
|
|
4616
5109
|
case "bold":
|
|
4617
5110
|
exec("bold");
|
|
@@ -4640,8 +5133,14 @@ var Editor = (props) => {
|
|
|
4640
5133
|
handleInput();
|
|
4641
5134
|
break;
|
|
4642
5135
|
}
|
|
4643
|
-
case "heading":
|
|
4644
|
-
|
|
5136
|
+
case "heading-1":
|
|
5137
|
+
toggleBlock("h1");
|
|
5138
|
+
break;
|
|
5139
|
+
case "heading-2":
|
|
5140
|
+
toggleBlock("h2");
|
|
5141
|
+
break;
|
|
5142
|
+
case "heading-3":
|
|
5143
|
+
toggleBlock("h3");
|
|
4645
5144
|
break;
|
|
4646
5145
|
case "list":
|
|
4647
5146
|
exec("insertUnorderedList");
|
|
@@ -4664,6 +5163,39 @@ var Editor = (props) => {
|
|
|
4664
5163
|
case "divider":
|
|
4665
5164
|
insertDivider();
|
|
4666
5165
|
break;
|
|
5166
|
+
case "checklist":
|
|
5167
|
+
toggleChecklist();
|
|
5168
|
+
break;
|
|
5169
|
+
case "align-left":
|
|
5170
|
+
setAlign("left");
|
|
5171
|
+
break;
|
|
5172
|
+
case "align-center":
|
|
5173
|
+
setAlign("center");
|
|
5174
|
+
break;
|
|
5175
|
+
case "align-right":
|
|
5176
|
+
setAlign("right");
|
|
5177
|
+
break;
|
|
5178
|
+
case "highlight":
|
|
5179
|
+
toggleHighlight();
|
|
5180
|
+
break;
|
|
5181
|
+
case "superscript":
|
|
5182
|
+
exec("superscript");
|
|
5183
|
+
break;
|
|
5184
|
+
case "subscript":
|
|
5185
|
+
exec("subscript");
|
|
5186
|
+
break;
|
|
5187
|
+
case "table":
|
|
5188
|
+
insertTable();
|
|
5189
|
+
break;
|
|
5190
|
+
case "clear-format":
|
|
5191
|
+
clearFormat();
|
|
5192
|
+
break;
|
|
5193
|
+
case "undo":
|
|
5194
|
+
undo();
|
|
5195
|
+
break;
|
|
5196
|
+
case "redo":
|
|
5197
|
+
redo();
|
|
5198
|
+
break;
|
|
4667
5199
|
}
|
|
4668
5200
|
};
|
|
4669
5201
|
return /* @__PURE__ */ jsxs207("div", { className: clsx_default("lib-xplat-editor", isFocused && "focused", readOnly && "readonly"), children: [
|
|
@@ -4672,7 +5204,10 @@ var Editor = (props) => {
|
|
|
4672
5204
|
{
|
|
4673
5205
|
items: toolbar,
|
|
4674
5206
|
active: activeFormats,
|
|
4675
|
-
onAction: onToolbarAction
|
|
5207
|
+
onAction: onToolbarAction,
|
|
5208
|
+
codeLang,
|
|
5209
|
+
inCodeBlock: activeFormats.has("block:pre"),
|
|
5210
|
+
onCodeLangChange: changeCodeLang
|
|
4676
5211
|
}
|
|
4677
5212
|
),
|
|
4678
5213
|
/* @__PURE__ */ jsxs207("div", { className: "lib-xplat-editor__content", style: { minHeight }, children: [
|
|
@@ -4690,6 +5225,7 @@ var Editor = (props) => {
|
|
|
4690
5225
|
className: "lib-xplat-editor__editable",
|
|
4691
5226
|
onInput: handleInput,
|
|
4692
5227
|
onKeyDown: handleKeyDown,
|
|
5228
|
+
onClick: handleEditorClick,
|
|
4693
5229
|
onKeyUp: handleSelectionUpdate,
|
|
4694
5230
|
onMouseUp: handleSelectionUpdate,
|
|
4695
5231
|
onPaste: handlePaste,
|
|
@@ -4731,14 +5267,27 @@ var TOOLBAR_LABEL = {
|
|
|
4731
5267
|
underline: "U",
|
|
4732
5268
|
strikethrough: "S",
|
|
4733
5269
|
code: "<>",
|
|
4734
|
-
heading: "
|
|
5270
|
+
"heading-1": "H1",
|
|
5271
|
+
"heading-2": "H2",
|
|
5272
|
+
"heading-3": "H3",
|
|
4735
5273
|
list: "\u2022",
|
|
4736
5274
|
"ordered-list": "1.",
|
|
4737
5275
|
blockquote: "\u275D",
|
|
4738
5276
|
"code-block": "[ ]",
|
|
4739
5277
|
link: "\u{1F517}",
|
|
4740
5278
|
image: "\u{1F5BC}",
|
|
4741
|
-
divider: "\u2014"
|
|
5279
|
+
divider: "\u2014",
|
|
5280
|
+
checklist: "\u2611",
|
|
5281
|
+
"align-left": "\u21E4",
|
|
5282
|
+
"align-center": "\u2194",
|
|
5283
|
+
"align-right": "\u21E5",
|
|
5284
|
+
highlight: "\u{1F58D}",
|
|
5285
|
+
superscript: "x\xB2",
|
|
5286
|
+
subscript: "x\u2082",
|
|
5287
|
+
table: "\u25A6",
|
|
5288
|
+
"clear-format": "\u232B",
|
|
5289
|
+
undo: "\u21B6",
|
|
5290
|
+
redo: "\u21B7"
|
|
4742
5291
|
};
|
|
4743
5292
|
var TOOLBAR_TITLE = {
|
|
4744
5293
|
bold: "\uAD75\uAC8C (\u2318B)",
|
|
@@ -4746,36 +5295,74 @@ var TOOLBAR_TITLE = {
|
|
|
4746
5295
|
underline: "\uBC11\uC904 (\u2318U)",
|
|
4747
5296
|
strikethrough: "\uCDE8\uC18C\uC120",
|
|
4748
5297
|
code: "\uC778\uB77C\uC778 \uCF54\uB4DC",
|
|
4749
|
-
heading: "\uC81C\uBAA9",
|
|
5298
|
+
"heading-1": "\uC81C\uBAA9 1",
|
|
5299
|
+
"heading-2": "\uC81C\uBAA9 2",
|
|
5300
|
+
"heading-3": "\uC81C\uBAA9 3",
|
|
4750
5301
|
list: "\uAE00\uBA38\uB9AC \uAE30\uD638 \uBAA9\uB85D",
|
|
4751
5302
|
"ordered-list": "\uBC88\uD638 \uB9E4\uAE30\uAE30 \uBAA9\uB85D",
|
|
4752
5303
|
blockquote: "\uC778\uC6A9",
|
|
4753
5304
|
"code-block": "\uCF54\uB4DC \uBE14\uB85D",
|
|
4754
5305
|
link: "\uB9C1\uD06C (\u2318K)",
|
|
4755
5306
|
image: "\uC774\uBBF8\uC9C0",
|
|
4756
|
-
divider: "\uAD6C\uBD84\uC120"
|
|
5307
|
+
divider: "\uAD6C\uBD84\uC120",
|
|
5308
|
+
checklist: "\uCCB4\uD06C\uB9AC\uC2A4\uD2B8",
|
|
5309
|
+
"align-left": "\uC67C\uCABD \uC815\uB82C",
|
|
5310
|
+
"align-center": "\uAC00\uC6B4\uB370 \uC815\uB82C",
|
|
5311
|
+
"align-right": "\uC624\uB978\uCABD \uC815\uB82C",
|
|
5312
|
+
highlight: "\uD615\uAD11\uD39C",
|
|
5313
|
+
superscript: "\uC704 \uCCA8\uC790",
|
|
5314
|
+
subscript: "\uC544\uB798 \uCCA8\uC790",
|
|
5315
|
+
table: "\uD45C \uC0BD\uC785",
|
|
5316
|
+
"clear-format": "\uC11C\uC2DD \uC9C0\uC6B0\uAE30",
|
|
5317
|
+
undo: "\uB418\uB3CC\uB9AC\uAE30 (\u2318Z)",
|
|
5318
|
+
redo: "\uB2E4\uC2DC\uD558\uAE30 (\u2318\u21E7Z)"
|
|
4757
5319
|
};
|
|
4758
5320
|
var isActive = (item, active) => {
|
|
4759
|
-
if (item === "heading") return active.has("block:h1")
|
|
5321
|
+
if (item === "heading-1") return active.has("block:h1");
|
|
5322
|
+
if (item === "heading-2") return active.has("block:h2");
|
|
5323
|
+
if (item === "heading-3") return active.has("block:h3");
|
|
4760
5324
|
if (item === "blockquote") return active.has("block:blockquote");
|
|
4761
5325
|
if (item === "code-block") return active.has("block:pre");
|
|
5326
|
+
if (item === "align-left") return active.has("align:left");
|
|
5327
|
+
if (item === "align-center") return active.has("align:center");
|
|
5328
|
+
if (item === "align-right") return active.has("align:right");
|
|
4762
5329
|
return active.has(item);
|
|
4763
5330
|
};
|
|
4764
|
-
var EditorToolbar = ({
|
|
4765
|
-
|
|
4766
|
-
|
|
4767
|
-
|
|
4768
|
-
|
|
4769
|
-
|
|
4770
|
-
|
|
4771
|
-
|
|
4772
|
-
|
|
4773
|
-
|
|
5331
|
+
var EditorToolbar = ({
|
|
5332
|
+
items,
|
|
5333
|
+
active,
|
|
5334
|
+
onAction,
|
|
5335
|
+
codeLang,
|
|
5336
|
+
inCodeBlock,
|
|
5337
|
+
onCodeLangChange
|
|
5338
|
+
}) => {
|
|
5339
|
+
return /* @__PURE__ */ jsxs207("div", { className: "lib-xplat-editor__toolbar", children: [
|
|
5340
|
+
items.map((item) => /* @__PURE__ */ jsx323(
|
|
5341
|
+
"button",
|
|
5342
|
+
{
|
|
5343
|
+
type: "button",
|
|
5344
|
+
className: clsx_default("lib-xplat-editor__toolbar-btn", isActive(item, active) && "active"),
|
|
5345
|
+
title: TOOLBAR_TITLE[item],
|
|
5346
|
+
onMouseDown: (e) => {
|
|
5347
|
+
e.preventDefault();
|
|
5348
|
+
onAction(item);
|
|
5349
|
+
},
|
|
5350
|
+
children: TOOLBAR_LABEL[item]
|
|
4774
5351
|
},
|
|
4775
|
-
|
|
4776
|
-
|
|
4777
|
-
|
|
4778
|
-
|
|
5352
|
+
item
|
|
5353
|
+
)),
|
|
5354
|
+
inCodeBlock && /* @__PURE__ */ jsx323(
|
|
5355
|
+
"select",
|
|
5356
|
+
{
|
|
5357
|
+
className: "lib-xplat-editor__lang",
|
|
5358
|
+
value: codeLang,
|
|
5359
|
+
"aria-label": "\uCF54\uB4DC \uC5B8\uC5B4",
|
|
5360
|
+
onMouseDown: (e) => e.stopPropagation(),
|
|
5361
|
+
onChange: (e) => onCodeLangChange(e.target.value),
|
|
5362
|
+
children: CODE_LANGUAGES.map((l) => /* @__PURE__ */ jsx323("option", { value: l.value, children: l.label }, l.value))
|
|
5363
|
+
}
|
|
5364
|
+
)
|
|
5365
|
+
] });
|
|
4779
5366
|
};
|
|
4780
5367
|
var SlashMenu = ({ position, items, activeIndex, onSelect, onClose }) => {
|
|
4781
5368
|
React22.useEffect(() => {
|
|
@@ -5320,6 +5907,7 @@ var PopOver = (props) => {
|
|
|
5320
5907
|
className: clsx_default(
|
|
5321
5908
|
"lib-xplat-pop-over-content",
|
|
5322
5909
|
position.direction,
|
|
5910
|
+
position.repositioning && "repositioning",
|
|
5323
5911
|
eventTrigger && "visible"
|
|
5324
5912
|
),
|
|
5325
5913
|
ref: popRef,
|
|
@@ -5666,7 +6254,7 @@ var SelectRoot = (props) => {
|
|
|
5666
6254
|
mounted && /* @__PURE__ */ jsx337(Portal_default, { children: /* @__PURE__ */ jsxs216(
|
|
5667
6255
|
"div",
|
|
5668
6256
|
{
|
|
5669
|
-
className: clsx_default("lib-xplat-select-content", size, position.direction, stateClass),
|
|
6257
|
+
className: clsx_default("lib-xplat-select-content", size, position.direction, stateClass, position.repositioning && "repositioning"),
|
|
5670
6258
|
ref: contentRef,
|
|
5671
6259
|
style: { ...position.position, width: triggerRef.current?.offsetWidth },
|
|
5672
6260
|
role: "listbox",
|
|
@@ -6559,7 +7147,7 @@ var TimePicker = (props) => {
|
|
|
6559
7147
|
"div",
|
|
6560
7148
|
{
|
|
6561
7149
|
ref: contentRef,
|
|
6562
|
-
className: clsx_default("lib-xplat-time-picker-content", size, visible ? "enter" : "exit"),
|
|
7150
|
+
className: clsx_default("lib-xplat-time-picker-content", size, visible ? "enter" : "exit", position.repositioning && "repositioning"),
|
|
6563
7151
|
style: { ...position.position, width: triggerRef.current?.offsetWidth },
|
|
6564
7152
|
role: "listbox",
|
|
6565
7153
|
children: options.map((t) => /* @__PURE__ */ jsx351(
|