@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/index.js
CHANGED
|
@@ -7945,8 +7945,10 @@ import React19 from "react";
|
|
|
7945
7945
|
var useAutoPosition = (triggerRef, popRef, enabled = true) => {
|
|
7946
7946
|
const [position, setPosition] = React19.useState({
|
|
7947
7947
|
position: {},
|
|
7948
|
-
direction: "bottom"
|
|
7948
|
+
direction: "bottom",
|
|
7949
|
+
repositioning: false
|
|
7949
7950
|
});
|
|
7951
|
+
const placedRef = React19.useRef(false);
|
|
7950
7952
|
const calculatePosition = React19.useCallback(() => {
|
|
7951
7953
|
if (!triggerRef.current || !popRef.current) return;
|
|
7952
7954
|
const triggerRect = triggerRef.current.getBoundingClientRect();
|
|
@@ -7971,11 +7973,16 @@ var useAutoPosition = (triggerRef, popRef, enabled = true) => {
|
|
|
7971
7973
|
if (left < 8) left = 8;
|
|
7972
7974
|
setPosition({
|
|
7973
7975
|
position: { top, left },
|
|
7974
|
-
direction
|
|
7976
|
+
direction,
|
|
7977
|
+
repositioning: placedRef.current
|
|
7975
7978
|
});
|
|
7979
|
+
placedRef.current = true;
|
|
7976
7980
|
}, [triggerRef, popRef]);
|
|
7977
7981
|
React19.useLayoutEffect(() => {
|
|
7978
|
-
if (!enabled)
|
|
7982
|
+
if (!enabled) {
|
|
7983
|
+
placedRef.current = false;
|
|
7984
|
+
return;
|
|
7985
|
+
}
|
|
7979
7986
|
calculatePosition();
|
|
7980
7987
|
const raf = requestAnimationFrame(calculatePosition);
|
|
7981
7988
|
return () => cancelAnimationFrame(raf);
|
|
@@ -7990,11 +7997,17 @@ var useAutoPosition = (triggerRef, popRef, enabled = true) => {
|
|
|
7990
7997
|
}, [calculatePosition, enabled, popRef]);
|
|
7991
7998
|
React19.useEffect(() => {
|
|
7992
7999
|
if (!enabled) return;
|
|
7993
|
-
|
|
7994
|
-
|
|
8000
|
+
let raf = 0;
|
|
8001
|
+
const onScrollOrResize = () => {
|
|
8002
|
+
cancelAnimationFrame(raf);
|
|
8003
|
+
raf = requestAnimationFrame(calculatePosition);
|
|
8004
|
+
};
|
|
8005
|
+
window.addEventListener("resize", onScrollOrResize, { passive: true });
|
|
8006
|
+
window.addEventListener("scroll", onScrollOrResize, { passive: true, capture: true });
|
|
7995
8007
|
return () => {
|
|
7996
|
-
|
|
7997
|
-
window.removeEventListener("
|
|
8008
|
+
cancelAnimationFrame(raf);
|
|
8009
|
+
window.removeEventListener("resize", onScrollOrResize);
|
|
8010
|
+
window.removeEventListener("scroll", onScrollOrResize, true);
|
|
7998
8011
|
};
|
|
7999
8012
|
}, [calculatePosition, enabled]);
|
|
8000
8013
|
return position;
|
|
@@ -8035,7 +8048,7 @@ var Dropdown = (props) => {
|
|
|
8035
8048
|
const [visible, setVisible] = React21.useState(false);
|
|
8036
8049
|
const triggerRef = React21.useRef(null);
|
|
8037
8050
|
const menuRef = React21.useRef(null);
|
|
8038
|
-
const { position, direction } = useAutoPosition_default(triggerRef, menuRef, mounted);
|
|
8051
|
+
const { position, direction, repositioning } = useAutoPosition_default(triggerRef, menuRef, mounted);
|
|
8039
8052
|
useClickOutside_default([triggerRef, menuRef], () => setIsOpen(false), isOpen);
|
|
8040
8053
|
useEscapeKey(isOpen, () => {
|
|
8041
8054
|
setIsOpen(false);
|
|
@@ -8070,7 +8083,7 @@ var Dropdown = (props) => {
|
|
|
8070
8083
|
"div",
|
|
8071
8084
|
{
|
|
8072
8085
|
ref: menuRef,
|
|
8073
|
-
className: clsx_default("lib-xplat-dropdown-menu", direction, { visible }),
|
|
8086
|
+
className: clsx_default("lib-xplat-dropdown-menu", direction, { visible }, repositioning && "repositioning"),
|
|
8074
8087
|
style: { top: position.top, left: position.left },
|
|
8075
8088
|
role: "menu",
|
|
8076
8089
|
children: items.map((item) => /* @__PURE__ */ jsx322(
|
|
@@ -8096,6 +8109,111 @@ var Dropdown_default = Dropdown;
|
|
|
8096
8109
|
|
|
8097
8110
|
// src/components/Editor/Editor.tsx
|
|
8098
8111
|
import React22 from "react";
|
|
8112
|
+
|
|
8113
|
+
// src/components/Editor/highlight.ts
|
|
8114
|
+
var CODE_LANGUAGES = [
|
|
8115
|
+
{ value: "plain", label: "\uC5C6\uC74C" },
|
|
8116
|
+
{ value: "javascript", label: "JavaScript" },
|
|
8117
|
+
{ value: "typescript", label: "TypeScript" },
|
|
8118
|
+
{ value: "json", label: "JSON" },
|
|
8119
|
+
{ value: "html", label: "HTML" },
|
|
8120
|
+
{ value: "css", label: "CSS" },
|
|
8121
|
+
{ value: "python", label: "Python" },
|
|
8122
|
+
{ value: "sql", label: "SQL" },
|
|
8123
|
+
{ value: "bash", label: "Bash" }
|
|
8124
|
+
];
|
|
8125
|
+
var KEYWORDS = {
|
|
8126
|
+
plain: [],
|
|
8127
|
+
javascript: "const let var function return if else for while class new this import export from default async await try catch throw typeof instanceof null undefined true false break continue switch case do delete in of yield".split(" "),
|
|
8128
|
+
typescript: "const let var function return if else for while class new this import export from default async await try catch throw typeof instanceof null undefined true false break continue switch case do delete in of yield interface type enum implements extends public private protected readonly as satisfies keyof infer never unknown any".split(" "),
|
|
8129
|
+
json: ["true", "false", "null"],
|
|
8130
|
+
html: [],
|
|
8131
|
+
css: [],
|
|
8132
|
+
python: "def class return if elif else for while import from as try except finally raise with lambda None True False and or not in is pass break continue global nonlocal yield async await".split(" "),
|
|
8133
|
+
sql: "SELECT FROM WHERE INSERT INTO VALUES UPDATE SET DELETE CREATE TABLE ALTER DROP JOIN LEFT RIGHT INNER OUTER ON GROUP BY ORDER HAVING LIMIT OFFSET AS AND OR NOT NULL DISTINCT UNION INDEX PRIMARY KEY FOREIGN REFERENCES DEFAULT".split(" "),
|
|
8134
|
+
bash: "if then else fi for while do done case esac function return export local echo cd ls rm cp mv mkdir sudo source set unset exit".split(" ")
|
|
8135
|
+
};
|
|
8136
|
+
var LINE_COMMENT = {
|
|
8137
|
+
javascript: "//",
|
|
8138
|
+
typescript: "//",
|
|
8139
|
+
css: "",
|
|
8140
|
+
python: "#",
|
|
8141
|
+
sql: "--",
|
|
8142
|
+
bash: "#"
|
|
8143
|
+
};
|
|
8144
|
+
var escape = (s) => s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
8145
|
+
var wrap = (cls, text) => `<span class="tok-${cls}">${escape(text)}</span>`;
|
|
8146
|
+
var highlight = (code, lang) => {
|
|
8147
|
+
if (lang === "plain" || !code) return escape(code);
|
|
8148
|
+
const keywords = new Set(KEYWORDS[lang]);
|
|
8149
|
+
const lineComment = LINE_COMMENT[lang];
|
|
8150
|
+
const caseInsensitive = lang === "sql";
|
|
8151
|
+
let out = "";
|
|
8152
|
+
let i = 0;
|
|
8153
|
+
while (i < code.length) {
|
|
8154
|
+
const rest = code.slice(i);
|
|
8155
|
+
if ((lang === "javascript" || lang === "typescript" || lang === "css") && rest.startsWith("/*")) {
|
|
8156
|
+
const end = code.indexOf("*/", i + 2);
|
|
8157
|
+
const stop = end === -1 ? code.length : end + 2;
|
|
8158
|
+
out += wrap("comment", code.slice(i, stop));
|
|
8159
|
+
i = stop;
|
|
8160
|
+
continue;
|
|
8161
|
+
}
|
|
8162
|
+
if (lineComment && rest.startsWith(lineComment)) {
|
|
8163
|
+
const nl = code.indexOf("\n", i);
|
|
8164
|
+
const stop = nl === -1 ? code.length : nl;
|
|
8165
|
+
out += wrap("comment", code.slice(i, stop));
|
|
8166
|
+
i = stop;
|
|
8167
|
+
continue;
|
|
8168
|
+
}
|
|
8169
|
+
const q = rest[0];
|
|
8170
|
+
if (q === '"' || q === "'" || q === "`") {
|
|
8171
|
+
let j = 1;
|
|
8172
|
+
while (j < rest.length) {
|
|
8173
|
+
if (rest[j] === "\\") {
|
|
8174
|
+
j += 2;
|
|
8175
|
+
continue;
|
|
8176
|
+
}
|
|
8177
|
+
if (rest[j] === q) {
|
|
8178
|
+
j += 1;
|
|
8179
|
+
break;
|
|
8180
|
+
}
|
|
8181
|
+
if (rest[j] === "\n" && q !== "`") break;
|
|
8182
|
+
j += 1;
|
|
8183
|
+
}
|
|
8184
|
+
out += wrap("string", rest.slice(0, j));
|
|
8185
|
+
i += j;
|
|
8186
|
+
continue;
|
|
8187
|
+
}
|
|
8188
|
+
const num = /^\d+(\.\d+)?/.exec(rest);
|
|
8189
|
+
if (num && !/[\w$]/.test(code[i - 1] ?? "")) {
|
|
8190
|
+
out += wrap("number", num[0]);
|
|
8191
|
+
i += num[0].length;
|
|
8192
|
+
continue;
|
|
8193
|
+
}
|
|
8194
|
+
const word = /^[A-Za-z_$][\w$]*/.exec(rest);
|
|
8195
|
+
if (word) {
|
|
8196
|
+
const w = word[0];
|
|
8197
|
+
const hit = caseInsensitive ? keywords.has(w.toUpperCase()) : keywords.has(w);
|
|
8198
|
+
out += hit ? wrap("keyword", w) : escape(w);
|
|
8199
|
+
i += w.length;
|
|
8200
|
+
continue;
|
|
8201
|
+
}
|
|
8202
|
+
if (lang === "html" && rest.startsWith("<")) {
|
|
8203
|
+
const tag = /^<\/?[A-Za-z][\w-]*/.exec(rest);
|
|
8204
|
+
if (tag) {
|
|
8205
|
+
out += wrap("keyword", tag[0]);
|
|
8206
|
+
i += tag[0].length;
|
|
8207
|
+
continue;
|
|
8208
|
+
}
|
|
8209
|
+
}
|
|
8210
|
+
out += escape(code[i]);
|
|
8211
|
+
i += 1;
|
|
8212
|
+
}
|
|
8213
|
+
return out;
|
|
8214
|
+
};
|
|
8215
|
+
|
|
8216
|
+
// src/components/Editor/Editor.tsx
|
|
8099
8217
|
import { jsx as jsx323, jsxs as jsxs207 } from "react/jsx-runtime";
|
|
8100
8218
|
var DEFAULT_TOOLBAR = [
|
|
8101
8219
|
"bold",
|
|
@@ -8103,14 +8221,27 @@ var DEFAULT_TOOLBAR = [
|
|
|
8103
8221
|
"underline",
|
|
8104
8222
|
"strikethrough",
|
|
8105
8223
|
"code",
|
|
8106
|
-
"heading",
|
|
8224
|
+
"heading-1",
|
|
8225
|
+
"heading-2",
|
|
8226
|
+
"heading-3",
|
|
8107
8227
|
"list",
|
|
8108
8228
|
"ordered-list",
|
|
8109
8229
|
"blockquote",
|
|
8110
8230
|
"code-block",
|
|
8111
8231
|
"link",
|
|
8112
8232
|
"image",
|
|
8113
|
-
"divider"
|
|
8233
|
+
"divider",
|
|
8234
|
+
"checklist",
|
|
8235
|
+
"table",
|
|
8236
|
+
"align-left",
|
|
8237
|
+
"align-center",
|
|
8238
|
+
"align-right",
|
|
8239
|
+
"highlight",
|
|
8240
|
+
"superscript",
|
|
8241
|
+
"subscript",
|
|
8242
|
+
"clear-format",
|
|
8243
|
+
"undo",
|
|
8244
|
+
"redo"
|
|
8114
8245
|
];
|
|
8115
8246
|
var ALLOWED_TAGS = /* @__PURE__ */ new Set([
|
|
8116
8247
|
"p",
|
|
@@ -8139,11 +8270,41 @@ var ALLOWED_TAGS = /* @__PURE__ */ new Set([
|
|
|
8139
8270
|
"img",
|
|
8140
8271
|
"hr",
|
|
8141
8272
|
"span",
|
|
8142
|
-
"div"
|
|
8273
|
+
"div",
|
|
8274
|
+
"sub",
|
|
8275
|
+
"sup",
|
|
8276
|
+
"mark",
|
|
8277
|
+
"table",
|
|
8278
|
+
"thead",
|
|
8279
|
+
"tbody",
|
|
8280
|
+
"tr",
|
|
8281
|
+
"th",
|
|
8282
|
+
"td"
|
|
8143
8283
|
]);
|
|
8144
8284
|
var ALLOWED_ATTRS = {
|
|
8145
8285
|
a: ["href", "target", "rel"],
|
|
8146
|
-
img: ["src", "alt"]
|
|
8286
|
+
img: ["src", "alt", "width"],
|
|
8287
|
+
// 정렬·체크리스트는 클래스로만 표현한다. style 을 열면 붙여넣기로 아무 CSS 나 들어온다
|
|
8288
|
+
p: ["class"],
|
|
8289
|
+
h1: ["class"],
|
|
8290
|
+
h2: ["class"],
|
|
8291
|
+
h3: ["class"],
|
|
8292
|
+
h4: ["class"],
|
|
8293
|
+
h5: ["class"],
|
|
8294
|
+
h6: ["class"],
|
|
8295
|
+
ul: ["class"],
|
|
8296
|
+
ol: ["class"],
|
|
8297
|
+
li: ["class", "data-checked"],
|
|
8298
|
+
blockquote: ["class"],
|
|
8299
|
+
div: ["class"],
|
|
8300
|
+
span: ["class"],
|
|
8301
|
+
pre: ["class"],
|
|
8302
|
+
code: ["class"],
|
|
8303
|
+
mark: ["class"],
|
|
8304
|
+
table: ["class"],
|
|
8305
|
+
td: ["class"],
|
|
8306
|
+
th: ["class"],
|
|
8307
|
+
tr: ["class"]
|
|
8147
8308
|
};
|
|
8148
8309
|
var DROP_WITH_CONTENT = /* @__PURE__ */ new Set([
|
|
8149
8310
|
"script",
|
|
@@ -8196,7 +8357,9 @@ var escapeHtml = (text) => {
|
|
|
8196
8357
|
};
|
|
8197
8358
|
var SLASH_ITEMS = [
|
|
8198
8359
|
{ key: "paragraph", label: "\uB2E8\uB77D", hint: "\uAE30\uBCF8 \uD14D\uC2A4\uD2B8" },
|
|
8199
|
-
{ key: "heading", label: "\uC81C\uBAA9 1", hint: "\uD070 \uC81C\uBAA9" },
|
|
8360
|
+
{ key: "heading-1", label: "\uC81C\uBAA9 1", hint: "\uAC00\uC7A5 \uD070 \uC81C\uBAA9" },
|
|
8361
|
+
{ key: "heading-2", label: "\uC81C\uBAA9 2", hint: "" },
|
|
8362
|
+
{ key: "heading-3", label: "\uC81C\uBAA9 3", hint: "" },
|
|
8200
8363
|
{ key: "list", label: "\uAE00\uBA38\uB9AC \uAE30\uD638 \uBAA9\uB85D", hint: "\u2022 \uD56D\uBAA9" },
|
|
8201
8364
|
{ key: "ordered-list", label: "\uBC88\uD638 \uB9E4\uAE30\uAE30 \uBAA9\uB85D", hint: "1. \uD56D\uBAA9" },
|
|
8202
8365
|
{ key: "blockquote", label: "\uC778\uC6A9", hint: "" },
|
|
@@ -8239,6 +8402,8 @@ var Editor = (props) => {
|
|
|
8239
8402
|
el.innerHTML = sanitizeHtml(value || "");
|
|
8240
8403
|
if (!el.firstChild) el.innerHTML = "<p><br></p>";
|
|
8241
8404
|
lastEmittedRef.current = null;
|
|
8405
|
+
historyRef.current = [{ html: el.innerHTML, caret: 0 }];
|
|
8406
|
+
historyIdxRef.current = 0;
|
|
8242
8407
|
updateEmpty();
|
|
8243
8408
|
}, [value]);
|
|
8244
8409
|
const updateEmpty = () => {
|
|
@@ -8283,6 +8448,17 @@ var Editor = (props) => {
|
|
|
8283
8448
|
if (document.queryCommandState("insertOrderedList")) next.add("ordered-list");
|
|
8284
8449
|
const block = String(document.queryCommandValue("formatBlock") || "").toLowerCase();
|
|
8285
8450
|
if (block) next.add(`block:${block}`);
|
|
8451
|
+
if (document.queryCommandState("superscript")) next.add("superscript");
|
|
8452
|
+
if (document.queryCommandState("subscript")) next.add("subscript");
|
|
8453
|
+
} catch {
|
|
8454
|
+
}
|
|
8455
|
+
try {
|
|
8456
|
+
const blockEl = currentBlock();
|
|
8457
|
+
if (blockEl?.classList.contains("align-center")) next.add("align:center");
|
|
8458
|
+
else if (blockEl?.classList.contains("align-right")) next.add("align:right");
|
|
8459
|
+
else if (blockEl) next.add("align:left");
|
|
8460
|
+
if (blockEl?.closest("mark")) next.add("highlight");
|
|
8461
|
+
if (blockEl?.closest("ul.checklist")) next.add("checklist");
|
|
8286
8462
|
} catch {
|
|
8287
8463
|
}
|
|
8288
8464
|
setActiveFormats(next);
|
|
@@ -8296,6 +8472,122 @@ var Editor = (props) => {
|
|
|
8296
8472
|
const setBlock = (tag) => {
|
|
8297
8473
|
exec("formatBlock", tag);
|
|
8298
8474
|
};
|
|
8475
|
+
const toggleBlock = (tag) => {
|
|
8476
|
+
const current = String(document.queryCommandValue("formatBlock") || "").toLowerCase();
|
|
8477
|
+
setBlock(current === tag ? "p" : tag);
|
|
8478
|
+
};
|
|
8479
|
+
const historyRef = React22.useRef([]);
|
|
8480
|
+
const historyIdxRef = React22.useRef(-1);
|
|
8481
|
+
const lastPushAtRef = React22.useRef(0);
|
|
8482
|
+
const isRestoringRef = React22.useRef(false);
|
|
8483
|
+
const caretOffset = (rootEl) => {
|
|
8484
|
+
const el = rootEl ?? editorRef.current;
|
|
8485
|
+
const sel = window.getSelection();
|
|
8486
|
+
if (!el || !sel || sel.rangeCount === 0 || !el.contains(sel.anchorNode)) return 0;
|
|
8487
|
+
const range = sel.getRangeAt(0).cloneRange();
|
|
8488
|
+
range.selectNodeContents(el);
|
|
8489
|
+
range.setEnd(sel.getRangeAt(0).endContainer, sel.getRangeAt(0).endOffset);
|
|
8490
|
+
return range.toString().length;
|
|
8491
|
+
};
|
|
8492
|
+
const setCaretOffset = (offset, rootEl) => {
|
|
8493
|
+
const el = rootEl ?? editorRef.current;
|
|
8494
|
+
if (!el) return;
|
|
8495
|
+
const walker = document.createTreeWalker(el, NodeFilter.SHOW_TEXT);
|
|
8496
|
+
let remaining = offset;
|
|
8497
|
+
let node = null;
|
|
8498
|
+
while (node = walker.nextNode()) {
|
|
8499
|
+
const len = node.textContent?.length ?? 0;
|
|
8500
|
+
if (remaining <= len) {
|
|
8501
|
+
const range = document.createRange();
|
|
8502
|
+
range.setStart(node, remaining);
|
|
8503
|
+
range.collapse(true);
|
|
8504
|
+
const sel = window.getSelection();
|
|
8505
|
+
sel?.removeAllRanges();
|
|
8506
|
+
sel?.addRange(range);
|
|
8507
|
+
return;
|
|
8508
|
+
}
|
|
8509
|
+
remaining -= len;
|
|
8510
|
+
}
|
|
8511
|
+
placeCaretAtEnd(el);
|
|
8512
|
+
};
|
|
8513
|
+
const pushHistory = (force = false) => {
|
|
8514
|
+
const el = editorRef.current;
|
|
8515
|
+
if (!el || isRestoringRef.current) return;
|
|
8516
|
+
const html = el.innerHTML;
|
|
8517
|
+
const hist = historyRef.current;
|
|
8518
|
+
const cur = hist[historyIdxRef.current];
|
|
8519
|
+
if (cur && cur.html === html) return;
|
|
8520
|
+
const now = Date.now();
|
|
8521
|
+
const coalesce = !force && cur && now - lastPushAtRef.current < 500;
|
|
8522
|
+
lastPushAtRef.current = now;
|
|
8523
|
+
if (coalesce) {
|
|
8524
|
+
hist[historyIdxRef.current] = { html, caret: caretOffset() };
|
|
8525
|
+
return;
|
|
8526
|
+
}
|
|
8527
|
+
hist.length = historyIdxRef.current + 1;
|
|
8528
|
+
hist.push({ html, caret: caretOffset() });
|
|
8529
|
+
if (hist.length > 200) hist.shift();
|
|
8530
|
+
historyIdxRef.current = hist.length - 1;
|
|
8531
|
+
};
|
|
8532
|
+
const applySnapshot = (snap) => {
|
|
8533
|
+
const el = editorRef.current;
|
|
8534
|
+
if (!el) return;
|
|
8535
|
+
isRestoringRef.current = true;
|
|
8536
|
+
el.innerHTML = snap.html;
|
|
8537
|
+
setCaretOffset(snap.caret);
|
|
8538
|
+
isRestoringRef.current = false;
|
|
8539
|
+
lastEmittedRef.current = el.innerHTML;
|
|
8540
|
+
onChange?.(el.innerHTML);
|
|
8541
|
+
updateEmpty();
|
|
8542
|
+
updateActiveFormats();
|
|
8543
|
+
};
|
|
8544
|
+
const undo = () => {
|
|
8545
|
+
pushHistory(true);
|
|
8546
|
+
if (historyIdxRef.current <= 0) return;
|
|
8547
|
+
historyIdxRef.current -= 1;
|
|
8548
|
+
applySnapshot(historyRef.current[historyIdxRef.current]);
|
|
8549
|
+
};
|
|
8550
|
+
const redo = () => {
|
|
8551
|
+
if (historyIdxRef.current >= historyRef.current.length - 1) return;
|
|
8552
|
+
historyIdxRef.current += 1;
|
|
8553
|
+
applySnapshot(historyRef.current[historyIdxRef.current]);
|
|
8554
|
+
};
|
|
8555
|
+
const langOf = (pre) => {
|
|
8556
|
+
const cls = Array.from(pre.classList).find((c) => c.startsWith("lang-"));
|
|
8557
|
+
return cls?.slice(5) ?? "plain";
|
|
8558
|
+
};
|
|
8559
|
+
const [codeLang, setCodeLang] = React22.useState("plain");
|
|
8560
|
+
const highlightRafRef = React22.useRef(0);
|
|
8561
|
+
const rehighlight = (pre) => {
|
|
8562
|
+
if (composingRef.current) return;
|
|
8563
|
+
const code = pre.querySelector("code");
|
|
8564
|
+
if (!code) return;
|
|
8565
|
+
const lang = langOf(pre);
|
|
8566
|
+
const text = code.textContent || "";
|
|
8567
|
+
const next = highlight(text, lang);
|
|
8568
|
+
if (code.innerHTML === next) return;
|
|
8569
|
+
const caret = caretOffset(code);
|
|
8570
|
+
isRestoringRef.current = true;
|
|
8571
|
+
code.innerHTML = next;
|
|
8572
|
+
setCaretOffset(caret, code);
|
|
8573
|
+
isRestoringRef.current = false;
|
|
8574
|
+
};
|
|
8575
|
+
const scheduleHighlight = () => {
|
|
8576
|
+
const pre = closestPre();
|
|
8577
|
+
if (!pre) return;
|
|
8578
|
+
cancelAnimationFrame(highlightRafRef.current);
|
|
8579
|
+
highlightRafRef.current = requestAnimationFrame(() => rehighlight(pre));
|
|
8580
|
+
};
|
|
8581
|
+
const changeCodeLang = (lang) => {
|
|
8582
|
+
const pre = closestPre();
|
|
8583
|
+
if (!pre) return;
|
|
8584
|
+
pushHistory(true);
|
|
8585
|
+
Array.from(pre.classList).filter((c) => c.startsWith("lang-")).forEach((c) => pre.classList.remove(c));
|
|
8586
|
+
if (lang !== "plain") pre.classList.add(`lang-${lang}`);
|
|
8587
|
+
setCodeLang(lang);
|
|
8588
|
+
rehighlight(pre);
|
|
8589
|
+
handleInput();
|
|
8590
|
+
};
|
|
8299
8591
|
const closestPre = () => {
|
|
8300
8592
|
const sel = window.getSelection();
|
|
8301
8593
|
const node = sel?.anchorNode;
|
|
@@ -8304,6 +8596,7 @@ var Editor = (props) => {
|
|
|
8304
8596
|
return el?.closest("pre") ?? null;
|
|
8305
8597
|
};
|
|
8306
8598
|
const insertCodeBlock = () => {
|
|
8599
|
+
pushHistory(true);
|
|
8307
8600
|
const el = editorRef.current;
|
|
8308
8601
|
const sel = window.getSelection();
|
|
8309
8602
|
if (!el || !sel || sel.rangeCount === 0) return;
|
|
@@ -8386,7 +8679,167 @@ var Editor = (props) => {
|
|
|
8386
8679
|
sel.addRange(r2);
|
|
8387
8680
|
editorRef.current?.focus();
|
|
8388
8681
|
};
|
|
8682
|
+
const clearFormat = () => {
|
|
8683
|
+
exec("removeFormat");
|
|
8684
|
+
exec("unlink");
|
|
8685
|
+
setBlock("p");
|
|
8686
|
+
};
|
|
8687
|
+
const indentList = (outdent) => {
|
|
8688
|
+
exec(outdent ? "outdent" : "indent");
|
|
8689
|
+
};
|
|
8690
|
+
const inListItem = () => {
|
|
8691
|
+
const sel = window.getSelection();
|
|
8692
|
+
const node = sel?.anchorNode;
|
|
8693
|
+
if (!node || !editorRef.current?.contains(node)) return false;
|
|
8694
|
+
const el = node.nodeType === Node.ELEMENT_NODE ? node : node.parentElement;
|
|
8695
|
+
return !!el?.closest("li");
|
|
8696
|
+
};
|
|
8697
|
+
const currentBlock = () => {
|
|
8698
|
+
const sel = window.getSelection();
|
|
8699
|
+
const node = sel?.anchorNode;
|
|
8700
|
+
const root = editorRef.current;
|
|
8701
|
+
if (!node || !root?.contains(node)) return null;
|
|
8702
|
+
let el = node.nodeType === Node.ELEMENT_NODE ? node : node.parentElement;
|
|
8703
|
+
while (el && el !== root && !/^(P|H[1-6]|LI|BLOCKQUOTE|PRE|DIV|TD|TH)$/.test(el.tagName)) {
|
|
8704
|
+
el = el.parentElement;
|
|
8705
|
+
}
|
|
8706
|
+
return el && el !== root ? el : null;
|
|
8707
|
+
};
|
|
8708
|
+
const setAlign = (align) => {
|
|
8709
|
+
const block = currentBlock();
|
|
8710
|
+
if (!block) return;
|
|
8711
|
+
pushHistory(true);
|
|
8712
|
+
block.classList.remove("align-left", "align-center", "align-right");
|
|
8713
|
+
if (align !== "left") block.classList.add(`align-${align}`);
|
|
8714
|
+
handleInput();
|
|
8715
|
+
};
|
|
8716
|
+
const toggleChecklist = () => {
|
|
8717
|
+
pushHistory(true);
|
|
8718
|
+
const block = currentBlock();
|
|
8719
|
+
const list = block?.closest("ul");
|
|
8720
|
+
if (list?.classList.contains("checklist")) {
|
|
8721
|
+
list.classList.remove("checklist");
|
|
8722
|
+
list.querySelectorAll("li").forEach((li) => li.removeAttribute("data-checked"));
|
|
8723
|
+
handleInput();
|
|
8724
|
+
return;
|
|
8725
|
+
}
|
|
8726
|
+
if (list) {
|
|
8727
|
+
list.classList.add("checklist");
|
|
8728
|
+
list.querySelectorAll("li").forEach((li) => li.setAttribute("data-checked", "false"));
|
|
8729
|
+
handleInput();
|
|
8730
|
+
return;
|
|
8731
|
+
}
|
|
8732
|
+
exec("insertUnorderedList");
|
|
8733
|
+
const made = currentBlock()?.closest("ul");
|
|
8734
|
+
if (made) {
|
|
8735
|
+
made.classList.add("checklist");
|
|
8736
|
+
made.querySelectorAll("li").forEach((li) => li.setAttribute("data-checked", "false"));
|
|
8737
|
+
}
|
|
8738
|
+
handleInput();
|
|
8739
|
+
};
|
|
8740
|
+
const handleEditorClick = (e) => {
|
|
8741
|
+
if (readOnly) return;
|
|
8742
|
+
const target = e.target;
|
|
8743
|
+
const li = target.closest?.("li");
|
|
8744
|
+
if (!li || !li.closest("ul.checklist")) return;
|
|
8745
|
+
const rect = li.getBoundingClientRect();
|
|
8746
|
+
if (e.clientX - rect.left > 20) return;
|
|
8747
|
+
e.preventDefault();
|
|
8748
|
+
pushHistory(true);
|
|
8749
|
+
li.setAttribute("data-checked", li.getAttribute("data-checked") === "true" ? "false" : "true");
|
|
8750
|
+
handleInput();
|
|
8751
|
+
};
|
|
8752
|
+
const toggleHighlight = () => {
|
|
8753
|
+
const sel = window.getSelection();
|
|
8754
|
+
if (!sel || sel.rangeCount === 0 || sel.isCollapsed) return;
|
|
8755
|
+
pushHistory(true);
|
|
8756
|
+
const range = sel.getRangeAt(0);
|
|
8757
|
+
const node = sel.anchorNode;
|
|
8758
|
+
const el = node?.nodeType === Node.ELEMENT_NODE ? node : node?.parentElement;
|
|
8759
|
+
const existing = el?.closest("mark");
|
|
8760
|
+
if (existing) {
|
|
8761
|
+
const parent = existing.parentNode;
|
|
8762
|
+
while (existing.firstChild) parent?.insertBefore(existing.firstChild, existing);
|
|
8763
|
+
parent?.removeChild(existing);
|
|
8764
|
+
handleInput();
|
|
8765
|
+
return;
|
|
8766
|
+
}
|
|
8767
|
+
const mark = document.createElement("mark");
|
|
8768
|
+
try {
|
|
8769
|
+
range.surroundContents(mark);
|
|
8770
|
+
} catch {
|
|
8771
|
+
const frag = range.extractContents();
|
|
8772
|
+
mark.appendChild(frag);
|
|
8773
|
+
range.insertNode(mark);
|
|
8774
|
+
}
|
|
8775
|
+
handleInput();
|
|
8776
|
+
};
|
|
8777
|
+
const insertTable = (cols = 3, rows = 2) => {
|
|
8778
|
+
const sel = window.getSelection();
|
|
8779
|
+
if (!sel || sel.rangeCount === 0) return;
|
|
8780
|
+
pushHistory(true);
|
|
8781
|
+
const table = document.createElement("table");
|
|
8782
|
+
const thead = document.createElement("thead");
|
|
8783
|
+
const headRow = document.createElement("tr");
|
|
8784
|
+
for (let c = 0; c < cols; c++) {
|
|
8785
|
+
const th = document.createElement("th");
|
|
8786
|
+
th.innerHTML = "<br>";
|
|
8787
|
+
headRow.appendChild(th);
|
|
8788
|
+
}
|
|
8789
|
+
thead.appendChild(headRow);
|
|
8790
|
+
table.appendChild(thead);
|
|
8791
|
+
const tbody = document.createElement("tbody");
|
|
8792
|
+
for (let r2 = 0; r2 < rows; r2++) {
|
|
8793
|
+
const tr = document.createElement("tr");
|
|
8794
|
+
for (let c = 0; c < cols; c++) {
|
|
8795
|
+
const td = document.createElement("td");
|
|
8796
|
+
td.innerHTML = "<br>";
|
|
8797
|
+
tr.appendChild(td);
|
|
8798
|
+
}
|
|
8799
|
+
tbody.appendChild(tr);
|
|
8800
|
+
}
|
|
8801
|
+
table.appendChild(tbody);
|
|
8802
|
+
const range = sel.getRangeAt(0);
|
|
8803
|
+
range.deleteContents();
|
|
8804
|
+
range.insertNode(table);
|
|
8805
|
+
ensureParagraphAfter(table);
|
|
8806
|
+
const first = table.querySelector("th");
|
|
8807
|
+
if (first) placeCaretAtEnd(first);
|
|
8808
|
+
handleInput();
|
|
8809
|
+
};
|
|
8810
|
+
const moveTableCell = (backwards) => {
|
|
8811
|
+
const block = currentBlock();
|
|
8812
|
+
const cell = block?.closest("td, th");
|
|
8813
|
+
if (!cell) return false;
|
|
8814
|
+
const table = cell.closest("table");
|
|
8815
|
+
if (!table) return false;
|
|
8816
|
+
const cells = Array.from(table.querySelectorAll("td, th"));
|
|
8817
|
+
const i = cells.indexOf(cell);
|
|
8818
|
+
const next = cells[i + (backwards ? -1 : 1)];
|
|
8819
|
+
if (next) {
|
|
8820
|
+
placeCaretAtEnd(next);
|
|
8821
|
+
return true;
|
|
8822
|
+
}
|
|
8823
|
+
if (!backwards) {
|
|
8824
|
+
pushHistory(true);
|
|
8825
|
+
const lastRow = table.querySelector("tbody")?.lastElementChild;
|
|
8826
|
+
if (lastRow) {
|
|
8827
|
+
const tr = document.createElement("tr");
|
|
8828
|
+
for (let c = 0; c < lastRow.children.length; c++) {
|
|
8829
|
+
const td = document.createElement("td");
|
|
8830
|
+
td.innerHTML = "<br>";
|
|
8831
|
+
tr.appendChild(td);
|
|
8832
|
+
}
|
|
8833
|
+
lastRow.after(tr);
|
|
8834
|
+
placeCaretAtEnd(tr.firstElementChild);
|
|
8835
|
+
handleInput();
|
|
8836
|
+
return true;
|
|
8837
|
+
}
|
|
8838
|
+
}
|
|
8839
|
+
return false;
|
|
8840
|
+
};
|
|
8389
8841
|
const insertDivider = () => {
|
|
8842
|
+
pushHistory(true);
|
|
8390
8843
|
exec("insertHorizontalRule");
|
|
8391
8844
|
const el = editorRef.current;
|
|
8392
8845
|
if (el && el.lastElementChild?.tagName === "HR") {
|
|
@@ -8479,8 +8932,14 @@ var Editor = (props) => {
|
|
|
8479
8932
|
case "paragraph":
|
|
8480
8933
|
setBlock("p");
|
|
8481
8934
|
break;
|
|
8482
|
-
case "heading":
|
|
8483
|
-
|
|
8935
|
+
case "heading-1":
|
|
8936
|
+
toggleBlock("h1");
|
|
8937
|
+
break;
|
|
8938
|
+
case "heading-2":
|
|
8939
|
+
toggleBlock("h2");
|
|
8940
|
+
break;
|
|
8941
|
+
case "heading-3":
|
|
8942
|
+
toggleBlock("h3");
|
|
8484
8943
|
break;
|
|
8485
8944
|
case "list":
|
|
8486
8945
|
exec("insertUnorderedList");
|
|
@@ -8573,6 +9032,8 @@ var Editor = (props) => {
|
|
|
8573
9032
|
if (!el) return;
|
|
8574
9033
|
const html = el.innerHTML;
|
|
8575
9034
|
lastEmittedRef.current = html;
|
|
9035
|
+
pushHistory();
|
|
9036
|
+
scheduleHighlight();
|
|
8576
9037
|
onChange?.(html);
|
|
8577
9038
|
updateEmpty();
|
|
8578
9039
|
updateActiveFormats();
|
|
@@ -8626,6 +9087,15 @@ var Editor = (props) => {
|
|
|
8626
9087
|
return;
|
|
8627
9088
|
}
|
|
8628
9089
|
}
|
|
9090
|
+
if (e.key === "Tab" && moveTableCell(e.shiftKey)) {
|
|
9091
|
+
e.preventDefault();
|
|
9092
|
+
return;
|
|
9093
|
+
}
|
|
9094
|
+
if (e.key === "Tab" && inListItem()) {
|
|
9095
|
+
e.preventDefault();
|
|
9096
|
+
indentList(e.shiftKey);
|
|
9097
|
+
return;
|
|
9098
|
+
}
|
|
8629
9099
|
if (slashOpen) {
|
|
8630
9100
|
if (e.key === "ArrowDown") {
|
|
8631
9101
|
e.preventDefault();
|
|
@@ -8649,6 +9119,21 @@ var Editor = (props) => {
|
|
|
8649
9119
|
return;
|
|
8650
9120
|
}
|
|
8651
9121
|
}
|
|
9122
|
+
if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === "z") {
|
|
9123
|
+
e.preventDefault();
|
|
9124
|
+
if (e.shiftKey) redo();
|
|
9125
|
+
else undo();
|
|
9126
|
+
return;
|
|
9127
|
+
}
|
|
9128
|
+
if ((e.metaKey || e.ctrlKey) && e.shiftKey && e.key.toLowerCase() === "v") {
|
|
9129
|
+
plainPasteRef.current = true;
|
|
9130
|
+
return;
|
|
9131
|
+
}
|
|
9132
|
+
if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === "y") {
|
|
9133
|
+
e.preventDefault();
|
|
9134
|
+
redo();
|
|
9135
|
+
return;
|
|
9136
|
+
}
|
|
8652
9137
|
if ((e.metaKey || e.ctrlKey) && !e.shiftKey && !e.altKey) {
|
|
8653
9138
|
const k = e.key.toLowerCase();
|
|
8654
9139
|
if (k === "b") {
|
|
@@ -8682,10 +9167,16 @@ var Editor = (props) => {
|
|
|
8682
9167
|
}
|
|
8683
9168
|
}
|
|
8684
9169
|
};
|
|
9170
|
+
const plainPasteRef = React22.useRef(false);
|
|
8685
9171
|
const handlePaste = (e) => {
|
|
8686
9172
|
if (readOnly) return;
|
|
8687
9173
|
e.preventDefault();
|
|
8688
9174
|
const text = e.clipboardData.getData("text/plain");
|
|
9175
|
+
if (plainPasteRef.current) {
|
|
9176
|
+
plainPasteRef.current = false;
|
|
9177
|
+
insertTextAtCaret(text);
|
|
9178
|
+
return;
|
|
9179
|
+
}
|
|
8689
9180
|
if (closestPre()) {
|
|
8690
9181
|
insertTextAtCaret(text);
|
|
8691
9182
|
return;
|
|
@@ -8712,9 +9203,11 @@ var Editor = (props) => {
|
|
|
8712
9203
|
};
|
|
8713
9204
|
const handleSelectionUpdate = () => {
|
|
8714
9205
|
updateActiveFormats();
|
|
9206
|
+
const pre = closestPre();
|
|
9207
|
+
setCodeLang(pre ? langOf(pre) : "plain");
|
|
8715
9208
|
};
|
|
8716
9209
|
const onToolbarAction = (item) => {
|
|
8717
|
-
if (closestPre() &&
|
|
9210
|
+
if (closestPre() && !["code-block", "undo", "redo"].includes(item)) return;
|
|
8718
9211
|
switch (item) {
|
|
8719
9212
|
case "bold":
|
|
8720
9213
|
exec("bold");
|
|
@@ -8743,8 +9236,14 @@ var Editor = (props) => {
|
|
|
8743
9236
|
handleInput();
|
|
8744
9237
|
break;
|
|
8745
9238
|
}
|
|
8746
|
-
case "heading":
|
|
8747
|
-
|
|
9239
|
+
case "heading-1":
|
|
9240
|
+
toggleBlock("h1");
|
|
9241
|
+
break;
|
|
9242
|
+
case "heading-2":
|
|
9243
|
+
toggleBlock("h2");
|
|
9244
|
+
break;
|
|
9245
|
+
case "heading-3":
|
|
9246
|
+
toggleBlock("h3");
|
|
8748
9247
|
break;
|
|
8749
9248
|
case "list":
|
|
8750
9249
|
exec("insertUnorderedList");
|
|
@@ -8767,6 +9266,39 @@ var Editor = (props) => {
|
|
|
8767
9266
|
case "divider":
|
|
8768
9267
|
insertDivider();
|
|
8769
9268
|
break;
|
|
9269
|
+
case "checklist":
|
|
9270
|
+
toggleChecklist();
|
|
9271
|
+
break;
|
|
9272
|
+
case "align-left":
|
|
9273
|
+
setAlign("left");
|
|
9274
|
+
break;
|
|
9275
|
+
case "align-center":
|
|
9276
|
+
setAlign("center");
|
|
9277
|
+
break;
|
|
9278
|
+
case "align-right":
|
|
9279
|
+
setAlign("right");
|
|
9280
|
+
break;
|
|
9281
|
+
case "highlight":
|
|
9282
|
+
toggleHighlight();
|
|
9283
|
+
break;
|
|
9284
|
+
case "superscript":
|
|
9285
|
+
exec("superscript");
|
|
9286
|
+
break;
|
|
9287
|
+
case "subscript":
|
|
9288
|
+
exec("subscript");
|
|
9289
|
+
break;
|
|
9290
|
+
case "table":
|
|
9291
|
+
insertTable();
|
|
9292
|
+
break;
|
|
9293
|
+
case "clear-format":
|
|
9294
|
+
clearFormat();
|
|
9295
|
+
break;
|
|
9296
|
+
case "undo":
|
|
9297
|
+
undo();
|
|
9298
|
+
break;
|
|
9299
|
+
case "redo":
|
|
9300
|
+
redo();
|
|
9301
|
+
break;
|
|
8770
9302
|
}
|
|
8771
9303
|
};
|
|
8772
9304
|
return /* @__PURE__ */ jsxs207("div", { className: clsx_default("lib-xplat-editor", isFocused && "focused", readOnly && "readonly"), children: [
|
|
@@ -8775,7 +9307,10 @@ var Editor = (props) => {
|
|
|
8775
9307
|
{
|
|
8776
9308
|
items: toolbar,
|
|
8777
9309
|
active: activeFormats,
|
|
8778
|
-
onAction: onToolbarAction
|
|
9310
|
+
onAction: onToolbarAction,
|
|
9311
|
+
codeLang,
|
|
9312
|
+
inCodeBlock: activeFormats.has("block:pre"),
|
|
9313
|
+
onCodeLangChange: changeCodeLang
|
|
8779
9314
|
}
|
|
8780
9315
|
),
|
|
8781
9316
|
/* @__PURE__ */ jsxs207("div", { className: "lib-xplat-editor__content", style: { minHeight }, children: [
|
|
@@ -8793,6 +9328,7 @@ var Editor = (props) => {
|
|
|
8793
9328
|
className: "lib-xplat-editor__editable",
|
|
8794
9329
|
onInput: handleInput,
|
|
8795
9330
|
onKeyDown: handleKeyDown,
|
|
9331
|
+
onClick: handleEditorClick,
|
|
8796
9332
|
onKeyUp: handleSelectionUpdate,
|
|
8797
9333
|
onMouseUp: handleSelectionUpdate,
|
|
8798
9334
|
onPaste: handlePaste,
|
|
@@ -8834,14 +9370,27 @@ var TOOLBAR_LABEL = {
|
|
|
8834
9370
|
underline: "U",
|
|
8835
9371
|
strikethrough: "S",
|
|
8836
9372
|
code: "<>",
|
|
8837
|
-
heading: "
|
|
9373
|
+
"heading-1": "H1",
|
|
9374
|
+
"heading-2": "H2",
|
|
9375
|
+
"heading-3": "H3",
|
|
8838
9376
|
list: "\u2022",
|
|
8839
9377
|
"ordered-list": "1.",
|
|
8840
9378
|
blockquote: "\u275D",
|
|
8841
9379
|
"code-block": "[ ]",
|
|
8842
9380
|
link: "\u{1F517}",
|
|
8843
9381
|
image: "\u{1F5BC}",
|
|
8844
|
-
divider: "\u2014"
|
|
9382
|
+
divider: "\u2014",
|
|
9383
|
+
checklist: "\u2611",
|
|
9384
|
+
"align-left": "\u21E4",
|
|
9385
|
+
"align-center": "\u2194",
|
|
9386
|
+
"align-right": "\u21E5",
|
|
9387
|
+
highlight: "\u{1F58D}",
|
|
9388
|
+
superscript: "x\xB2",
|
|
9389
|
+
subscript: "x\u2082",
|
|
9390
|
+
table: "\u25A6",
|
|
9391
|
+
"clear-format": "\u232B",
|
|
9392
|
+
undo: "\u21B6",
|
|
9393
|
+
redo: "\u21B7"
|
|
8845
9394
|
};
|
|
8846
9395
|
var TOOLBAR_TITLE = {
|
|
8847
9396
|
bold: "\uAD75\uAC8C (\u2318B)",
|
|
@@ -8849,36 +9398,74 @@ var TOOLBAR_TITLE = {
|
|
|
8849
9398
|
underline: "\uBC11\uC904 (\u2318U)",
|
|
8850
9399
|
strikethrough: "\uCDE8\uC18C\uC120",
|
|
8851
9400
|
code: "\uC778\uB77C\uC778 \uCF54\uB4DC",
|
|
8852
|
-
heading: "\uC81C\uBAA9",
|
|
9401
|
+
"heading-1": "\uC81C\uBAA9 1",
|
|
9402
|
+
"heading-2": "\uC81C\uBAA9 2",
|
|
9403
|
+
"heading-3": "\uC81C\uBAA9 3",
|
|
8853
9404
|
list: "\uAE00\uBA38\uB9AC \uAE30\uD638 \uBAA9\uB85D",
|
|
8854
9405
|
"ordered-list": "\uBC88\uD638 \uB9E4\uAE30\uAE30 \uBAA9\uB85D",
|
|
8855
9406
|
blockquote: "\uC778\uC6A9",
|
|
8856
9407
|
"code-block": "\uCF54\uB4DC \uBE14\uB85D",
|
|
8857
9408
|
link: "\uB9C1\uD06C (\u2318K)",
|
|
8858
9409
|
image: "\uC774\uBBF8\uC9C0",
|
|
8859
|
-
divider: "\uAD6C\uBD84\uC120"
|
|
9410
|
+
divider: "\uAD6C\uBD84\uC120",
|
|
9411
|
+
checklist: "\uCCB4\uD06C\uB9AC\uC2A4\uD2B8",
|
|
9412
|
+
"align-left": "\uC67C\uCABD \uC815\uB82C",
|
|
9413
|
+
"align-center": "\uAC00\uC6B4\uB370 \uC815\uB82C",
|
|
9414
|
+
"align-right": "\uC624\uB978\uCABD \uC815\uB82C",
|
|
9415
|
+
highlight: "\uD615\uAD11\uD39C",
|
|
9416
|
+
superscript: "\uC704 \uCCA8\uC790",
|
|
9417
|
+
subscript: "\uC544\uB798 \uCCA8\uC790",
|
|
9418
|
+
table: "\uD45C \uC0BD\uC785",
|
|
9419
|
+
"clear-format": "\uC11C\uC2DD \uC9C0\uC6B0\uAE30",
|
|
9420
|
+
undo: "\uB418\uB3CC\uB9AC\uAE30 (\u2318Z)",
|
|
9421
|
+
redo: "\uB2E4\uC2DC\uD558\uAE30 (\u2318\u21E7Z)"
|
|
8860
9422
|
};
|
|
8861
9423
|
var isActive = (item, active) => {
|
|
8862
|
-
if (item === "heading") return active.has("block:h1")
|
|
9424
|
+
if (item === "heading-1") return active.has("block:h1");
|
|
9425
|
+
if (item === "heading-2") return active.has("block:h2");
|
|
9426
|
+
if (item === "heading-3") return active.has("block:h3");
|
|
8863
9427
|
if (item === "blockquote") return active.has("block:blockquote");
|
|
8864
9428
|
if (item === "code-block") return active.has("block:pre");
|
|
9429
|
+
if (item === "align-left") return active.has("align:left");
|
|
9430
|
+
if (item === "align-center") return active.has("align:center");
|
|
9431
|
+
if (item === "align-right") return active.has("align:right");
|
|
8865
9432
|
return active.has(item);
|
|
8866
9433
|
};
|
|
8867
|
-
var EditorToolbar = ({
|
|
8868
|
-
|
|
8869
|
-
|
|
8870
|
-
|
|
8871
|
-
|
|
8872
|
-
|
|
8873
|
-
|
|
8874
|
-
|
|
8875
|
-
|
|
8876
|
-
|
|
9434
|
+
var EditorToolbar = ({
|
|
9435
|
+
items,
|
|
9436
|
+
active,
|
|
9437
|
+
onAction,
|
|
9438
|
+
codeLang,
|
|
9439
|
+
inCodeBlock,
|
|
9440
|
+
onCodeLangChange
|
|
9441
|
+
}) => {
|
|
9442
|
+
return /* @__PURE__ */ jsxs207("div", { className: "lib-xplat-editor__toolbar", children: [
|
|
9443
|
+
items.map((item) => /* @__PURE__ */ jsx323(
|
|
9444
|
+
"button",
|
|
9445
|
+
{
|
|
9446
|
+
type: "button",
|
|
9447
|
+
className: clsx_default("lib-xplat-editor__toolbar-btn", isActive(item, active) && "active"),
|
|
9448
|
+
title: TOOLBAR_TITLE[item],
|
|
9449
|
+
onMouseDown: (e) => {
|
|
9450
|
+
e.preventDefault();
|
|
9451
|
+
onAction(item);
|
|
9452
|
+
},
|
|
9453
|
+
children: TOOLBAR_LABEL[item]
|
|
8877
9454
|
},
|
|
8878
|
-
|
|
8879
|
-
|
|
8880
|
-
|
|
8881
|
-
|
|
9455
|
+
item
|
|
9456
|
+
)),
|
|
9457
|
+
inCodeBlock && /* @__PURE__ */ jsx323(
|
|
9458
|
+
"select",
|
|
9459
|
+
{
|
|
9460
|
+
className: "lib-xplat-editor__lang",
|
|
9461
|
+
value: codeLang,
|
|
9462
|
+
"aria-label": "\uCF54\uB4DC \uC5B8\uC5B4",
|
|
9463
|
+
onMouseDown: (e) => e.stopPropagation(),
|
|
9464
|
+
onChange: (e) => onCodeLangChange(e.target.value),
|
|
9465
|
+
children: CODE_LANGUAGES.map((l) => /* @__PURE__ */ jsx323("option", { value: l.value, children: l.label }, l.value))
|
|
9466
|
+
}
|
|
9467
|
+
)
|
|
9468
|
+
] });
|
|
8882
9469
|
};
|
|
8883
9470
|
var SlashMenu = ({ position, items, activeIndex, onSelect, onClose }) => {
|
|
8884
9471
|
React22.useEffect(() => {
|
|
@@ -9423,6 +10010,7 @@ var PopOver = (props) => {
|
|
|
9423
10010
|
className: clsx_default(
|
|
9424
10011
|
"lib-xplat-pop-over-content",
|
|
9425
10012
|
position.direction,
|
|
10013
|
+
position.repositioning && "repositioning",
|
|
9426
10014
|
eventTrigger && "visible"
|
|
9427
10015
|
),
|
|
9428
10016
|
ref: popRef,
|
|
@@ -9769,7 +10357,7 @@ var SelectRoot = (props) => {
|
|
|
9769
10357
|
mounted && /* @__PURE__ */ jsx337(Portal_default, { children: /* @__PURE__ */ jsxs216(
|
|
9770
10358
|
"div",
|
|
9771
10359
|
{
|
|
9772
|
-
className: clsx_default("lib-xplat-select-content", size, position.direction, stateClass),
|
|
10360
|
+
className: clsx_default("lib-xplat-select-content", size, position.direction, stateClass, position.repositioning && "repositioning"),
|
|
9773
10361
|
ref: contentRef,
|
|
9774
10362
|
style: { ...position.position, width: triggerRef.current?.offsetWidth },
|
|
9775
10363
|
role: "listbox",
|
|
@@ -10662,7 +11250,7 @@ var TimePicker = (props) => {
|
|
|
10662
11250
|
"div",
|
|
10663
11251
|
{
|
|
10664
11252
|
ref: contentRef,
|
|
10665
|
-
className: clsx_default("lib-xplat-time-picker-content", size, visible ? "enter" : "exit"),
|
|
11253
|
+
className: clsx_default("lib-xplat-time-picker-content", size, visible ? "enter" : "exit", position.repositioning && "repositioning"),
|
|
10666
11254
|
style: { ...position.position, width: triggerRef.current?.offsetWidth },
|
|
10667
11255
|
role: "listbox",
|
|
10668
11256
|
children: options.map((t) => /* @__PURE__ */ jsx351(
|