@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.cjs
CHANGED
|
@@ -8354,8 +8354,10 @@ var import_react19 = __toESM(require("react"), 1);
|
|
|
8354
8354
|
var useAutoPosition = (triggerRef, popRef, enabled = true) => {
|
|
8355
8355
|
const [position, setPosition] = import_react19.default.useState({
|
|
8356
8356
|
position: {},
|
|
8357
|
-
direction: "bottom"
|
|
8357
|
+
direction: "bottom",
|
|
8358
|
+
repositioning: false
|
|
8358
8359
|
});
|
|
8360
|
+
const placedRef = import_react19.default.useRef(false);
|
|
8359
8361
|
const calculatePosition = import_react19.default.useCallback(() => {
|
|
8360
8362
|
if (!triggerRef.current || !popRef.current) return;
|
|
8361
8363
|
const triggerRect = triggerRef.current.getBoundingClientRect();
|
|
@@ -8380,11 +8382,16 @@ var useAutoPosition = (triggerRef, popRef, enabled = true) => {
|
|
|
8380
8382
|
if (left < 8) left = 8;
|
|
8381
8383
|
setPosition({
|
|
8382
8384
|
position: { top, left },
|
|
8383
|
-
direction
|
|
8385
|
+
direction,
|
|
8386
|
+
repositioning: placedRef.current
|
|
8384
8387
|
});
|
|
8388
|
+
placedRef.current = true;
|
|
8385
8389
|
}, [triggerRef, popRef]);
|
|
8386
8390
|
import_react19.default.useLayoutEffect(() => {
|
|
8387
|
-
if (!enabled)
|
|
8391
|
+
if (!enabled) {
|
|
8392
|
+
placedRef.current = false;
|
|
8393
|
+
return;
|
|
8394
|
+
}
|
|
8388
8395
|
calculatePosition();
|
|
8389
8396
|
const raf = requestAnimationFrame(calculatePosition);
|
|
8390
8397
|
return () => cancelAnimationFrame(raf);
|
|
@@ -8399,11 +8406,17 @@ var useAutoPosition = (triggerRef, popRef, enabled = true) => {
|
|
|
8399
8406
|
}, [calculatePosition, enabled, popRef]);
|
|
8400
8407
|
import_react19.default.useEffect(() => {
|
|
8401
8408
|
if (!enabled) return;
|
|
8402
|
-
|
|
8403
|
-
|
|
8409
|
+
let raf = 0;
|
|
8410
|
+
const onScrollOrResize = () => {
|
|
8411
|
+
cancelAnimationFrame(raf);
|
|
8412
|
+
raf = requestAnimationFrame(calculatePosition);
|
|
8413
|
+
};
|
|
8414
|
+
window.addEventListener("resize", onScrollOrResize, { passive: true });
|
|
8415
|
+
window.addEventListener("scroll", onScrollOrResize, { passive: true, capture: true });
|
|
8404
8416
|
return () => {
|
|
8405
|
-
|
|
8406
|
-
window.removeEventListener("
|
|
8417
|
+
cancelAnimationFrame(raf);
|
|
8418
|
+
window.removeEventListener("resize", onScrollOrResize);
|
|
8419
|
+
window.removeEventListener("scroll", onScrollOrResize, true);
|
|
8407
8420
|
};
|
|
8408
8421
|
}, [calculatePosition, enabled]);
|
|
8409
8422
|
return position;
|
|
@@ -8444,7 +8457,7 @@ var Dropdown = (props) => {
|
|
|
8444
8457
|
const [visible, setVisible] = import_react21.default.useState(false);
|
|
8445
8458
|
const triggerRef = import_react21.default.useRef(null);
|
|
8446
8459
|
const menuRef = import_react21.default.useRef(null);
|
|
8447
|
-
const { position, direction } = useAutoPosition_default(triggerRef, menuRef, mounted);
|
|
8460
|
+
const { position, direction, repositioning } = useAutoPosition_default(triggerRef, menuRef, mounted);
|
|
8448
8461
|
useClickOutside_default([triggerRef, menuRef], () => setIsOpen(false), isOpen);
|
|
8449
8462
|
useEscapeKey(isOpen, () => {
|
|
8450
8463
|
setIsOpen(false);
|
|
@@ -8479,7 +8492,7 @@ var Dropdown = (props) => {
|
|
|
8479
8492
|
"div",
|
|
8480
8493
|
{
|
|
8481
8494
|
ref: menuRef,
|
|
8482
|
-
className: clsx_default("lib-xplat-dropdown-menu", direction, { visible }),
|
|
8495
|
+
className: clsx_default("lib-xplat-dropdown-menu", direction, { visible }, repositioning && "repositioning"),
|
|
8483
8496
|
style: { top: position.top, left: position.left },
|
|
8484
8497
|
role: "menu",
|
|
8485
8498
|
children: items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime322.jsx)(
|
|
@@ -8505,6 +8518,111 @@ var Dropdown_default = Dropdown;
|
|
|
8505
8518
|
|
|
8506
8519
|
// src/components/Editor/Editor.tsx
|
|
8507
8520
|
var import_react22 = __toESM(require("react"), 1);
|
|
8521
|
+
|
|
8522
|
+
// src/components/Editor/highlight.ts
|
|
8523
|
+
var CODE_LANGUAGES = [
|
|
8524
|
+
{ value: "plain", label: "\uC5C6\uC74C" },
|
|
8525
|
+
{ value: "javascript", label: "JavaScript" },
|
|
8526
|
+
{ value: "typescript", label: "TypeScript" },
|
|
8527
|
+
{ value: "json", label: "JSON" },
|
|
8528
|
+
{ value: "html", label: "HTML" },
|
|
8529
|
+
{ value: "css", label: "CSS" },
|
|
8530
|
+
{ value: "python", label: "Python" },
|
|
8531
|
+
{ value: "sql", label: "SQL" },
|
|
8532
|
+
{ value: "bash", label: "Bash" }
|
|
8533
|
+
];
|
|
8534
|
+
var KEYWORDS = {
|
|
8535
|
+
plain: [],
|
|
8536
|
+
javascript: "const let var function return if else for while class new this import export from default async await try catch throw typeof instanceof null undefined true false break continue switch case do delete in of yield".split(" "),
|
|
8537
|
+
typescript: "const let var function return if else for while class new this import export from default async await try catch throw typeof instanceof null undefined true false break continue switch case do delete in of yield interface type enum implements extends public private protected readonly as satisfies keyof infer never unknown any".split(" "),
|
|
8538
|
+
json: ["true", "false", "null"],
|
|
8539
|
+
html: [],
|
|
8540
|
+
css: [],
|
|
8541
|
+
python: "def class return if elif else for while import from as try except finally raise with lambda None True False and or not in is pass break continue global nonlocal yield async await".split(" "),
|
|
8542
|
+
sql: "SELECT FROM WHERE INSERT INTO VALUES UPDATE SET DELETE CREATE TABLE ALTER DROP JOIN LEFT RIGHT INNER OUTER ON GROUP BY ORDER HAVING LIMIT OFFSET AS AND OR NOT NULL DISTINCT UNION INDEX PRIMARY KEY FOREIGN REFERENCES DEFAULT".split(" "),
|
|
8543
|
+
bash: "if then else fi for while do done case esac function return export local echo cd ls rm cp mv mkdir sudo source set unset exit".split(" ")
|
|
8544
|
+
};
|
|
8545
|
+
var LINE_COMMENT = {
|
|
8546
|
+
javascript: "//",
|
|
8547
|
+
typescript: "//",
|
|
8548
|
+
css: "",
|
|
8549
|
+
python: "#",
|
|
8550
|
+
sql: "--",
|
|
8551
|
+
bash: "#"
|
|
8552
|
+
};
|
|
8553
|
+
var escape = (s) => s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
8554
|
+
var wrap = (cls, text) => `<span class="tok-${cls}">${escape(text)}</span>`;
|
|
8555
|
+
var highlight = (code, lang) => {
|
|
8556
|
+
if (lang === "plain" || !code) return escape(code);
|
|
8557
|
+
const keywords = new Set(KEYWORDS[lang]);
|
|
8558
|
+
const lineComment = LINE_COMMENT[lang];
|
|
8559
|
+
const caseInsensitive = lang === "sql";
|
|
8560
|
+
let out = "";
|
|
8561
|
+
let i = 0;
|
|
8562
|
+
while (i < code.length) {
|
|
8563
|
+
const rest = code.slice(i);
|
|
8564
|
+
if ((lang === "javascript" || lang === "typescript" || lang === "css") && rest.startsWith("/*")) {
|
|
8565
|
+
const end = code.indexOf("*/", i + 2);
|
|
8566
|
+
const stop = end === -1 ? code.length : end + 2;
|
|
8567
|
+
out += wrap("comment", code.slice(i, stop));
|
|
8568
|
+
i = stop;
|
|
8569
|
+
continue;
|
|
8570
|
+
}
|
|
8571
|
+
if (lineComment && rest.startsWith(lineComment)) {
|
|
8572
|
+
const nl = code.indexOf("\n", i);
|
|
8573
|
+
const stop = nl === -1 ? code.length : nl;
|
|
8574
|
+
out += wrap("comment", code.slice(i, stop));
|
|
8575
|
+
i = stop;
|
|
8576
|
+
continue;
|
|
8577
|
+
}
|
|
8578
|
+
const q = rest[0];
|
|
8579
|
+
if (q === '"' || q === "'" || q === "`") {
|
|
8580
|
+
let j = 1;
|
|
8581
|
+
while (j < rest.length) {
|
|
8582
|
+
if (rest[j] === "\\") {
|
|
8583
|
+
j += 2;
|
|
8584
|
+
continue;
|
|
8585
|
+
}
|
|
8586
|
+
if (rest[j] === q) {
|
|
8587
|
+
j += 1;
|
|
8588
|
+
break;
|
|
8589
|
+
}
|
|
8590
|
+
if (rest[j] === "\n" && q !== "`") break;
|
|
8591
|
+
j += 1;
|
|
8592
|
+
}
|
|
8593
|
+
out += wrap("string", rest.slice(0, j));
|
|
8594
|
+
i += j;
|
|
8595
|
+
continue;
|
|
8596
|
+
}
|
|
8597
|
+
const num = /^\d+(\.\d+)?/.exec(rest);
|
|
8598
|
+
if (num && !/[\w$]/.test(code[i - 1] ?? "")) {
|
|
8599
|
+
out += wrap("number", num[0]);
|
|
8600
|
+
i += num[0].length;
|
|
8601
|
+
continue;
|
|
8602
|
+
}
|
|
8603
|
+
const word = /^[A-Za-z_$][\w$]*/.exec(rest);
|
|
8604
|
+
if (word) {
|
|
8605
|
+
const w = word[0];
|
|
8606
|
+
const hit = caseInsensitive ? keywords.has(w.toUpperCase()) : keywords.has(w);
|
|
8607
|
+
out += hit ? wrap("keyword", w) : escape(w);
|
|
8608
|
+
i += w.length;
|
|
8609
|
+
continue;
|
|
8610
|
+
}
|
|
8611
|
+
if (lang === "html" && rest.startsWith("<")) {
|
|
8612
|
+
const tag = /^<\/?[A-Za-z][\w-]*/.exec(rest);
|
|
8613
|
+
if (tag) {
|
|
8614
|
+
out += wrap("keyword", tag[0]);
|
|
8615
|
+
i += tag[0].length;
|
|
8616
|
+
continue;
|
|
8617
|
+
}
|
|
8618
|
+
}
|
|
8619
|
+
out += escape(code[i]);
|
|
8620
|
+
i += 1;
|
|
8621
|
+
}
|
|
8622
|
+
return out;
|
|
8623
|
+
};
|
|
8624
|
+
|
|
8625
|
+
// src/components/Editor/Editor.tsx
|
|
8508
8626
|
var import_jsx_runtime323 = require("react/jsx-runtime");
|
|
8509
8627
|
var DEFAULT_TOOLBAR = [
|
|
8510
8628
|
"bold",
|
|
@@ -8512,14 +8630,27 @@ var DEFAULT_TOOLBAR = [
|
|
|
8512
8630
|
"underline",
|
|
8513
8631
|
"strikethrough",
|
|
8514
8632
|
"code",
|
|
8515
|
-
"heading",
|
|
8633
|
+
"heading-1",
|
|
8634
|
+
"heading-2",
|
|
8635
|
+
"heading-3",
|
|
8516
8636
|
"list",
|
|
8517
8637
|
"ordered-list",
|
|
8518
8638
|
"blockquote",
|
|
8519
8639
|
"code-block",
|
|
8520
8640
|
"link",
|
|
8521
8641
|
"image",
|
|
8522
|
-
"divider"
|
|
8642
|
+
"divider",
|
|
8643
|
+
"checklist",
|
|
8644
|
+
"table",
|
|
8645
|
+
"align-left",
|
|
8646
|
+
"align-center",
|
|
8647
|
+
"align-right",
|
|
8648
|
+
"highlight",
|
|
8649
|
+
"superscript",
|
|
8650
|
+
"subscript",
|
|
8651
|
+
"clear-format",
|
|
8652
|
+
"undo",
|
|
8653
|
+
"redo"
|
|
8523
8654
|
];
|
|
8524
8655
|
var ALLOWED_TAGS = /* @__PURE__ */ new Set([
|
|
8525
8656
|
"p",
|
|
@@ -8548,11 +8679,41 @@ var ALLOWED_TAGS = /* @__PURE__ */ new Set([
|
|
|
8548
8679
|
"img",
|
|
8549
8680
|
"hr",
|
|
8550
8681
|
"span",
|
|
8551
|
-
"div"
|
|
8682
|
+
"div",
|
|
8683
|
+
"sub",
|
|
8684
|
+
"sup",
|
|
8685
|
+
"mark",
|
|
8686
|
+
"table",
|
|
8687
|
+
"thead",
|
|
8688
|
+
"tbody",
|
|
8689
|
+
"tr",
|
|
8690
|
+
"th",
|
|
8691
|
+
"td"
|
|
8552
8692
|
]);
|
|
8553
8693
|
var ALLOWED_ATTRS = {
|
|
8554
8694
|
a: ["href", "target", "rel"],
|
|
8555
|
-
img: ["src", "alt"]
|
|
8695
|
+
img: ["src", "alt", "width"],
|
|
8696
|
+
// 정렬·체크리스트는 클래스로만 표현한다. style 을 열면 붙여넣기로 아무 CSS 나 들어온다
|
|
8697
|
+
p: ["class"],
|
|
8698
|
+
h1: ["class"],
|
|
8699
|
+
h2: ["class"],
|
|
8700
|
+
h3: ["class"],
|
|
8701
|
+
h4: ["class"],
|
|
8702
|
+
h5: ["class"],
|
|
8703
|
+
h6: ["class"],
|
|
8704
|
+
ul: ["class"],
|
|
8705
|
+
ol: ["class"],
|
|
8706
|
+
li: ["class", "data-checked"],
|
|
8707
|
+
blockquote: ["class"],
|
|
8708
|
+
div: ["class"],
|
|
8709
|
+
span: ["class"],
|
|
8710
|
+
pre: ["class"],
|
|
8711
|
+
code: ["class"],
|
|
8712
|
+
mark: ["class"],
|
|
8713
|
+
table: ["class"],
|
|
8714
|
+
td: ["class"],
|
|
8715
|
+
th: ["class"],
|
|
8716
|
+
tr: ["class"]
|
|
8556
8717
|
};
|
|
8557
8718
|
var DROP_WITH_CONTENT = /* @__PURE__ */ new Set([
|
|
8558
8719
|
"script",
|
|
@@ -8605,7 +8766,9 @@ var escapeHtml = (text) => {
|
|
|
8605
8766
|
};
|
|
8606
8767
|
var SLASH_ITEMS = [
|
|
8607
8768
|
{ key: "paragraph", label: "\uB2E8\uB77D", hint: "\uAE30\uBCF8 \uD14D\uC2A4\uD2B8" },
|
|
8608
|
-
{ key: "heading", label: "\uC81C\uBAA9 1", hint: "\uD070 \uC81C\uBAA9" },
|
|
8769
|
+
{ key: "heading-1", label: "\uC81C\uBAA9 1", hint: "\uAC00\uC7A5 \uD070 \uC81C\uBAA9" },
|
|
8770
|
+
{ key: "heading-2", label: "\uC81C\uBAA9 2", hint: "" },
|
|
8771
|
+
{ key: "heading-3", label: "\uC81C\uBAA9 3", hint: "" },
|
|
8609
8772
|
{ key: "list", label: "\uAE00\uBA38\uB9AC \uAE30\uD638 \uBAA9\uB85D", hint: "\u2022 \uD56D\uBAA9" },
|
|
8610
8773
|
{ key: "ordered-list", label: "\uBC88\uD638 \uB9E4\uAE30\uAE30 \uBAA9\uB85D", hint: "1. \uD56D\uBAA9" },
|
|
8611
8774
|
{ key: "blockquote", label: "\uC778\uC6A9", hint: "" },
|
|
@@ -8648,6 +8811,8 @@ var Editor = (props) => {
|
|
|
8648
8811
|
el.innerHTML = sanitizeHtml(value || "");
|
|
8649
8812
|
if (!el.firstChild) el.innerHTML = "<p><br></p>";
|
|
8650
8813
|
lastEmittedRef.current = null;
|
|
8814
|
+
historyRef.current = [{ html: el.innerHTML, caret: 0 }];
|
|
8815
|
+
historyIdxRef.current = 0;
|
|
8651
8816
|
updateEmpty();
|
|
8652
8817
|
}, [value]);
|
|
8653
8818
|
const updateEmpty = () => {
|
|
@@ -8692,6 +8857,17 @@ var Editor = (props) => {
|
|
|
8692
8857
|
if (document.queryCommandState("insertOrderedList")) next.add("ordered-list");
|
|
8693
8858
|
const block = String(document.queryCommandValue("formatBlock") || "").toLowerCase();
|
|
8694
8859
|
if (block) next.add(`block:${block}`);
|
|
8860
|
+
if (document.queryCommandState("superscript")) next.add("superscript");
|
|
8861
|
+
if (document.queryCommandState("subscript")) next.add("subscript");
|
|
8862
|
+
} catch {
|
|
8863
|
+
}
|
|
8864
|
+
try {
|
|
8865
|
+
const blockEl = currentBlock();
|
|
8866
|
+
if (blockEl?.classList.contains("align-center")) next.add("align:center");
|
|
8867
|
+
else if (blockEl?.classList.contains("align-right")) next.add("align:right");
|
|
8868
|
+
else if (blockEl) next.add("align:left");
|
|
8869
|
+
if (blockEl?.closest("mark")) next.add("highlight");
|
|
8870
|
+
if (blockEl?.closest("ul.checklist")) next.add("checklist");
|
|
8695
8871
|
} catch {
|
|
8696
8872
|
}
|
|
8697
8873
|
setActiveFormats(next);
|
|
@@ -8705,6 +8881,122 @@ var Editor = (props) => {
|
|
|
8705
8881
|
const setBlock = (tag) => {
|
|
8706
8882
|
exec("formatBlock", tag);
|
|
8707
8883
|
};
|
|
8884
|
+
const toggleBlock = (tag) => {
|
|
8885
|
+
const current = String(document.queryCommandValue("formatBlock") || "").toLowerCase();
|
|
8886
|
+
setBlock(current === tag ? "p" : tag);
|
|
8887
|
+
};
|
|
8888
|
+
const historyRef = import_react22.default.useRef([]);
|
|
8889
|
+
const historyIdxRef = import_react22.default.useRef(-1);
|
|
8890
|
+
const lastPushAtRef = import_react22.default.useRef(0);
|
|
8891
|
+
const isRestoringRef = import_react22.default.useRef(false);
|
|
8892
|
+
const caretOffset = (rootEl) => {
|
|
8893
|
+
const el = rootEl ?? editorRef.current;
|
|
8894
|
+
const sel = window.getSelection();
|
|
8895
|
+
if (!el || !sel || sel.rangeCount === 0 || !el.contains(sel.anchorNode)) return 0;
|
|
8896
|
+
const range = sel.getRangeAt(0).cloneRange();
|
|
8897
|
+
range.selectNodeContents(el);
|
|
8898
|
+
range.setEnd(sel.getRangeAt(0).endContainer, sel.getRangeAt(0).endOffset);
|
|
8899
|
+
return range.toString().length;
|
|
8900
|
+
};
|
|
8901
|
+
const setCaretOffset = (offset, rootEl) => {
|
|
8902
|
+
const el = rootEl ?? editorRef.current;
|
|
8903
|
+
if (!el) return;
|
|
8904
|
+
const walker = document.createTreeWalker(el, NodeFilter.SHOW_TEXT);
|
|
8905
|
+
let remaining = offset;
|
|
8906
|
+
let node = null;
|
|
8907
|
+
while (node = walker.nextNode()) {
|
|
8908
|
+
const len = node.textContent?.length ?? 0;
|
|
8909
|
+
if (remaining <= len) {
|
|
8910
|
+
const range = document.createRange();
|
|
8911
|
+
range.setStart(node, remaining);
|
|
8912
|
+
range.collapse(true);
|
|
8913
|
+
const sel = window.getSelection();
|
|
8914
|
+
sel?.removeAllRanges();
|
|
8915
|
+
sel?.addRange(range);
|
|
8916
|
+
return;
|
|
8917
|
+
}
|
|
8918
|
+
remaining -= len;
|
|
8919
|
+
}
|
|
8920
|
+
placeCaretAtEnd(el);
|
|
8921
|
+
};
|
|
8922
|
+
const pushHistory = (force = false) => {
|
|
8923
|
+
const el = editorRef.current;
|
|
8924
|
+
if (!el || isRestoringRef.current) return;
|
|
8925
|
+
const html = el.innerHTML;
|
|
8926
|
+
const hist = historyRef.current;
|
|
8927
|
+
const cur = hist[historyIdxRef.current];
|
|
8928
|
+
if (cur && cur.html === html) return;
|
|
8929
|
+
const now = Date.now();
|
|
8930
|
+
const coalesce = !force && cur && now - lastPushAtRef.current < 500;
|
|
8931
|
+
lastPushAtRef.current = now;
|
|
8932
|
+
if (coalesce) {
|
|
8933
|
+
hist[historyIdxRef.current] = { html, caret: caretOffset() };
|
|
8934
|
+
return;
|
|
8935
|
+
}
|
|
8936
|
+
hist.length = historyIdxRef.current + 1;
|
|
8937
|
+
hist.push({ html, caret: caretOffset() });
|
|
8938
|
+
if (hist.length > 200) hist.shift();
|
|
8939
|
+
historyIdxRef.current = hist.length - 1;
|
|
8940
|
+
};
|
|
8941
|
+
const applySnapshot = (snap) => {
|
|
8942
|
+
const el = editorRef.current;
|
|
8943
|
+
if (!el) return;
|
|
8944
|
+
isRestoringRef.current = true;
|
|
8945
|
+
el.innerHTML = snap.html;
|
|
8946
|
+
setCaretOffset(snap.caret);
|
|
8947
|
+
isRestoringRef.current = false;
|
|
8948
|
+
lastEmittedRef.current = el.innerHTML;
|
|
8949
|
+
onChange?.(el.innerHTML);
|
|
8950
|
+
updateEmpty();
|
|
8951
|
+
updateActiveFormats();
|
|
8952
|
+
};
|
|
8953
|
+
const undo = () => {
|
|
8954
|
+
pushHistory(true);
|
|
8955
|
+
if (historyIdxRef.current <= 0) return;
|
|
8956
|
+
historyIdxRef.current -= 1;
|
|
8957
|
+
applySnapshot(historyRef.current[historyIdxRef.current]);
|
|
8958
|
+
};
|
|
8959
|
+
const redo = () => {
|
|
8960
|
+
if (historyIdxRef.current >= historyRef.current.length - 1) return;
|
|
8961
|
+
historyIdxRef.current += 1;
|
|
8962
|
+
applySnapshot(historyRef.current[historyIdxRef.current]);
|
|
8963
|
+
};
|
|
8964
|
+
const langOf = (pre) => {
|
|
8965
|
+
const cls = Array.from(pre.classList).find((c) => c.startsWith("lang-"));
|
|
8966
|
+
return cls?.slice(5) ?? "plain";
|
|
8967
|
+
};
|
|
8968
|
+
const [codeLang, setCodeLang] = import_react22.default.useState("plain");
|
|
8969
|
+
const highlightRafRef = import_react22.default.useRef(0);
|
|
8970
|
+
const rehighlight = (pre) => {
|
|
8971
|
+
if (composingRef.current) return;
|
|
8972
|
+
const code = pre.querySelector("code");
|
|
8973
|
+
if (!code) return;
|
|
8974
|
+
const lang = langOf(pre);
|
|
8975
|
+
const text = code.textContent || "";
|
|
8976
|
+
const next = highlight(text, lang);
|
|
8977
|
+
if (code.innerHTML === next) return;
|
|
8978
|
+
const caret = caretOffset(code);
|
|
8979
|
+
isRestoringRef.current = true;
|
|
8980
|
+
code.innerHTML = next;
|
|
8981
|
+
setCaretOffset(caret, code);
|
|
8982
|
+
isRestoringRef.current = false;
|
|
8983
|
+
};
|
|
8984
|
+
const scheduleHighlight = () => {
|
|
8985
|
+
const pre = closestPre();
|
|
8986
|
+
if (!pre) return;
|
|
8987
|
+
cancelAnimationFrame(highlightRafRef.current);
|
|
8988
|
+
highlightRafRef.current = requestAnimationFrame(() => rehighlight(pre));
|
|
8989
|
+
};
|
|
8990
|
+
const changeCodeLang = (lang) => {
|
|
8991
|
+
const pre = closestPre();
|
|
8992
|
+
if (!pre) return;
|
|
8993
|
+
pushHistory(true);
|
|
8994
|
+
Array.from(pre.classList).filter((c) => c.startsWith("lang-")).forEach((c) => pre.classList.remove(c));
|
|
8995
|
+
if (lang !== "plain") pre.classList.add(`lang-${lang}`);
|
|
8996
|
+
setCodeLang(lang);
|
|
8997
|
+
rehighlight(pre);
|
|
8998
|
+
handleInput();
|
|
8999
|
+
};
|
|
8708
9000
|
const closestPre = () => {
|
|
8709
9001
|
const sel = window.getSelection();
|
|
8710
9002
|
const node = sel?.anchorNode;
|
|
@@ -8713,6 +9005,7 @@ var Editor = (props) => {
|
|
|
8713
9005
|
return el?.closest("pre") ?? null;
|
|
8714
9006
|
};
|
|
8715
9007
|
const insertCodeBlock = () => {
|
|
9008
|
+
pushHistory(true);
|
|
8716
9009
|
const el = editorRef.current;
|
|
8717
9010
|
const sel = window.getSelection();
|
|
8718
9011
|
if (!el || !sel || sel.rangeCount === 0) return;
|
|
@@ -8795,7 +9088,167 @@ var Editor = (props) => {
|
|
|
8795
9088
|
sel.addRange(r2);
|
|
8796
9089
|
editorRef.current?.focus();
|
|
8797
9090
|
};
|
|
9091
|
+
const clearFormat = () => {
|
|
9092
|
+
exec("removeFormat");
|
|
9093
|
+
exec("unlink");
|
|
9094
|
+
setBlock("p");
|
|
9095
|
+
};
|
|
9096
|
+
const indentList = (outdent) => {
|
|
9097
|
+
exec(outdent ? "outdent" : "indent");
|
|
9098
|
+
};
|
|
9099
|
+
const inListItem = () => {
|
|
9100
|
+
const sel = window.getSelection();
|
|
9101
|
+
const node = sel?.anchorNode;
|
|
9102
|
+
if (!node || !editorRef.current?.contains(node)) return false;
|
|
9103
|
+
const el = node.nodeType === Node.ELEMENT_NODE ? node : node.parentElement;
|
|
9104
|
+
return !!el?.closest("li");
|
|
9105
|
+
};
|
|
9106
|
+
const currentBlock = () => {
|
|
9107
|
+
const sel = window.getSelection();
|
|
9108
|
+
const node = sel?.anchorNode;
|
|
9109
|
+
const root = editorRef.current;
|
|
9110
|
+
if (!node || !root?.contains(node)) return null;
|
|
9111
|
+
let el = node.nodeType === Node.ELEMENT_NODE ? node : node.parentElement;
|
|
9112
|
+
while (el && el !== root && !/^(P|H[1-6]|LI|BLOCKQUOTE|PRE|DIV|TD|TH)$/.test(el.tagName)) {
|
|
9113
|
+
el = el.parentElement;
|
|
9114
|
+
}
|
|
9115
|
+
return el && el !== root ? el : null;
|
|
9116
|
+
};
|
|
9117
|
+
const setAlign = (align) => {
|
|
9118
|
+
const block = currentBlock();
|
|
9119
|
+
if (!block) return;
|
|
9120
|
+
pushHistory(true);
|
|
9121
|
+
block.classList.remove("align-left", "align-center", "align-right");
|
|
9122
|
+
if (align !== "left") block.classList.add(`align-${align}`);
|
|
9123
|
+
handleInput();
|
|
9124
|
+
};
|
|
9125
|
+
const toggleChecklist = () => {
|
|
9126
|
+
pushHistory(true);
|
|
9127
|
+
const block = currentBlock();
|
|
9128
|
+
const list = block?.closest("ul");
|
|
9129
|
+
if (list?.classList.contains("checklist")) {
|
|
9130
|
+
list.classList.remove("checklist");
|
|
9131
|
+
list.querySelectorAll("li").forEach((li) => li.removeAttribute("data-checked"));
|
|
9132
|
+
handleInput();
|
|
9133
|
+
return;
|
|
9134
|
+
}
|
|
9135
|
+
if (list) {
|
|
9136
|
+
list.classList.add("checklist");
|
|
9137
|
+
list.querySelectorAll("li").forEach((li) => li.setAttribute("data-checked", "false"));
|
|
9138
|
+
handleInput();
|
|
9139
|
+
return;
|
|
9140
|
+
}
|
|
9141
|
+
exec("insertUnorderedList");
|
|
9142
|
+
const made = currentBlock()?.closest("ul");
|
|
9143
|
+
if (made) {
|
|
9144
|
+
made.classList.add("checklist");
|
|
9145
|
+
made.querySelectorAll("li").forEach((li) => li.setAttribute("data-checked", "false"));
|
|
9146
|
+
}
|
|
9147
|
+
handleInput();
|
|
9148
|
+
};
|
|
9149
|
+
const handleEditorClick = (e) => {
|
|
9150
|
+
if (readOnly) return;
|
|
9151
|
+
const target = e.target;
|
|
9152
|
+
const li = target.closest?.("li");
|
|
9153
|
+
if (!li || !li.closest("ul.checklist")) return;
|
|
9154
|
+
const rect = li.getBoundingClientRect();
|
|
9155
|
+
if (e.clientX - rect.left > 20) return;
|
|
9156
|
+
e.preventDefault();
|
|
9157
|
+
pushHistory(true);
|
|
9158
|
+
li.setAttribute("data-checked", li.getAttribute("data-checked") === "true" ? "false" : "true");
|
|
9159
|
+
handleInput();
|
|
9160
|
+
};
|
|
9161
|
+
const toggleHighlight = () => {
|
|
9162
|
+
const sel = window.getSelection();
|
|
9163
|
+
if (!sel || sel.rangeCount === 0 || sel.isCollapsed) return;
|
|
9164
|
+
pushHistory(true);
|
|
9165
|
+
const range = sel.getRangeAt(0);
|
|
9166
|
+
const node = sel.anchorNode;
|
|
9167
|
+
const el = node?.nodeType === Node.ELEMENT_NODE ? node : node?.parentElement;
|
|
9168
|
+
const existing = el?.closest("mark");
|
|
9169
|
+
if (existing) {
|
|
9170
|
+
const parent = existing.parentNode;
|
|
9171
|
+
while (existing.firstChild) parent?.insertBefore(existing.firstChild, existing);
|
|
9172
|
+
parent?.removeChild(existing);
|
|
9173
|
+
handleInput();
|
|
9174
|
+
return;
|
|
9175
|
+
}
|
|
9176
|
+
const mark = document.createElement("mark");
|
|
9177
|
+
try {
|
|
9178
|
+
range.surroundContents(mark);
|
|
9179
|
+
} catch {
|
|
9180
|
+
const frag = range.extractContents();
|
|
9181
|
+
mark.appendChild(frag);
|
|
9182
|
+
range.insertNode(mark);
|
|
9183
|
+
}
|
|
9184
|
+
handleInput();
|
|
9185
|
+
};
|
|
9186
|
+
const insertTable = (cols = 3, rows = 2) => {
|
|
9187
|
+
const sel = window.getSelection();
|
|
9188
|
+
if (!sel || sel.rangeCount === 0) return;
|
|
9189
|
+
pushHistory(true);
|
|
9190
|
+
const table = document.createElement("table");
|
|
9191
|
+
const thead = document.createElement("thead");
|
|
9192
|
+
const headRow = document.createElement("tr");
|
|
9193
|
+
for (let c = 0; c < cols; c++) {
|
|
9194
|
+
const th = document.createElement("th");
|
|
9195
|
+
th.innerHTML = "<br>";
|
|
9196
|
+
headRow.appendChild(th);
|
|
9197
|
+
}
|
|
9198
|
+
thead.appendChild(headRow);
|
|
9199
|
+
table.appendChild(thead);
|
|
9200
|
+
const tbody = document.createElement("tbody");
|
|
9201
|
+
for (let r2 = 0; r2 < rows; r2++) {
|
|
9202
|
+
const tr = document.createElement("tr");
|
|
9203
|
+
for (let c = 0; c < cols; c++) {
|
|
9204
|
+
const td = document.createElement("td");
|
|
9205
|
+
td.innerHTML = "<br>";
|
|
9206
|
+
tr.appendChild(td);
|
|
9207
|
+
}
|
|
9208
|
+
tbody.appendChild(tr);
|
|
9209
|
+
}
|
|
9210
|
+
table.appendChild(tbody);
|
|
9211
|
+
const range = sel.getRangeAt(0);
|
|
9212
|
+
range.deleteContents();
|
|
9213
|
+
range.insertNode(table);
|
|
9214
|
+
ensureParagraphAfter(table);
|
|
9215
|
+
const first = table.querySelector("th");
|
|
9216
|
+
if (first) placeCaretAtEnd(first);
|
|
9217
|
+
handleInput();
|
|
9218
|
+
};
|
|
9219
|
+
const moveTableCell = (backwards) => {
|
|
9220
|
+
const block = currentBlock();
|
|
9221
|
+
const cell = block?.closest("td, th");
|
|
9222
|
+
if (!cell) return false;
|
|
9223
|
+
const table = cell.closest("table");
|
|
9224
|
+
if (!table) return false;
|
|
9225
|
+
const cells = Array.from(table.querySelectorAll("td, th"));
|
|
9226
|
+
const i = cells.indexOf(cell);
|
|
9227
|
+
const next = cells[i + (backwards ? -1 : 1)];
|
|
9228
|
+
if (next) {
|
|
9229
|
+
placeCaretAtEnd(next);
|
|
9230
|
+
return true;
|
|
9231
|
+
}
|
|
9232
|
+
if (!backwards) {
|
|
9233
|
+
pushHistory(true);
|
|
9234
|
+
const lastRow = table.querySelector("tbody")?.lastElementChild;
|
|
9235
|
+
if (lastRow) {
|
|
9236
|
+
const tr = document.createElement("tr");
|
|
9237
|
+
for (let c = 0; c < lastRow.children.length; c++) {
|
|
9238
|
+
const td = document.createElement("td");
|
|
9239
|
+
td.innerHTML = "<br>";
|
|
9240
|
+
tr.appendChild(td);
|
|
9241
|
+
}
|
|
9242
|
+
lastRow.after(tr);
|
|
9243
|
+
placeCaretAtEnd(tr.firstElementChild);
|
|
9244
|
+
handleInput();
|
|
9245
|
+
return true;
|
|
9246
|
+
}
|
|
9247
|
+
}
|
|
9248
|
+
return false;
|
|
9249
|
+
};
|
|
8798
9250
|
const insertDivider = () => {
|
|
9251
|
+
pushHistory(true);
|
|
8799
9252
|
exec("insertHorizontalRule");
|
|
8800
9253
|
const el = editorRef.current;
|
|
8801
9254
|
if (el && el.lastElementChild?.tagName === "HR") {
|
|
@@ -8888,8 +9341,14 @@ var Editor = (props) => {
|
|
|
8888
9341
|
case "paragraph":
|
|
8889
9342
|
setBlock("p");
|
|
8890
9343
|
break;
|
|
8891
|
-
case "heading":
|
|
8892
|
-
|
|
9344
|
+
case "heading-1":
|
|
9345
|
+
toggleBlock("h1");
|
|
9346
|
+
break;
|
|
9347
|
+
case "heading-2":
|
|
9348
|
+
toggleBlock("h2");
|
|
9349
|
+
break;
|
|
9350
|
+
case "heading-3":
|
|
9351
|
+
toggleBlock("h3");
|
|
8893
9352
|
break;
|
|
8894
9353
|
case "list":
|
|
8895
9354
|
exec("insertUnorderedList");
|
|
@@ -8982,6 +9441,8 @@ var Editor = (props) => {
|
|
|
8982
9441
|
if (!el) return;
|
|
8983
9442
|
const html = el.innerHTML;
|
|
8984
9443
|
lastEmittedRef.current = html;
|
|
9444
|
+
pushHistory();
|
|
9445
|
+
scheduleHighlight();
|
|
8985
9446
|
onChange?.(html);
|
|
8986
9447
|
updateEmpty();
|
|
8987
9448
|
updateActiveFormats();
|
|
@@ -9035,6 +9496,15 @@ var Editor = (props) => {
|
|
|
9035
9496
|
return;
|
|
9036
9497
|
}
|
|
9037
9498
|
}
|
|
9499
|
+
if (e.key === "Tab" && moveTableCell(e.shiftKey)) {
|
|
9500
|
+
e.preventDefault();
|
|
9501
|
+
return;
|
|
9502
|
+
}
|
|
9503
|
+
if (e.key === "Tab" && inListItem()) {
|
|
9504
|
+
e.preventDefault();
|
|
9505
|
+
indentList(e.shiftKey);
|
|
9506
|
+
return;
|
|
9507
|
+
}
|
|
9038
9508
|
if (slashOpen) {
|
|
9039
9509
|
if (e.key === "ArrowDown") {
|
|
9040
9510
|
e.preventDefault();
|
|
@@ -9058,6 +9528,21 @@ var Editor = (props) => {
|
|
|
9058
9528
|
return;
|
|
9059
9529
|
}
|
|
9060
9530
|
}
|
|
9531
|
+
if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === "z") {
|
|
9532
|
+
e.preventDefault();
|
|
9533
|
+
if (e.shiftKey) redo();
|
|
9534
|
+
else undo();
|
|
9535
|
+
return;
|
|
9536
|
+
}
|
|
9537
|
+
if ((e.metaKey || e.ctrlKey) && e.shiftKey && e.key.toLowerCase() === "v") {
|
|
9538
|
+
plainPasteRef.current = true;
|
|
9539
|
+
return;
|
|
9540
|
+
}
|
|
9541
|
+
if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === "y") {
|
|
9542
|
+
e.preventDefault();
|
|
9543
|
+
redo();
|
|
9544
|
+
return;
|
|
9545
|
+
}
|
|
9061
9546
|
if ((e.metaKey || e.ctrlKey) && !e.shiftKey && !e.altKey) {
|
|
9062
9547
|
const k = e.key.toLowerCase();
|
|
9063
9548
|
if (k === "b") {
|
|
@@ -9091,10 +9576,16 @@ var Editor = (props) => {
|
|
|
9091
9576
|
}
|
|
9092
9577
|
}
|
|
9093
9578
|
};
|
|
9579
|
+
const plainPasteRef = import_react22.default.useRef(false);
|
|
9094
9580
|
const handlePaste = (e) => {
|
|
9095
9581
|
if (readOnly) return;
|
|
9096
9582
|
e.preventDefault();
|
|
9097
9583
|
const text = e.clipboardData.getData("text/plain");
|
|
9584
|
+
if (plainPasteRef.current) {
|
|
9585
|
+
plainPasteRef.current = false;
|
|
9586
|
+
insertTextAtCaret(text);
|
|
9587
|
+
return;
|
|
9588
|
+
}
|
|
9098
9589
|
if (closestPre()) {
|
|
9099
9590
|
insertTextAtCaret(text);
|
|
9100
9591
|
return;
|
|
@@ -9121,9 +9612,11 @@ var Editor = (props) => {
|
|
|
9121
9612
|
};
|
|
9122
9613
|
const handleSelectionUpdate = () => {
|
|
9123
9614
|
updateActiveFormats();
|
|
9615
|
+
const pre = closestPre();
|
|
9616
|
+
setCodeLang(pre ? langOf(pre) : "plain");
|
|
9124
9617
|
};
|
|
9125
9618
|
const onToolbarAction = (item) => {
|
|
9126
|
-
if (closestPre() &&
|
|
9619
|
+
if (closestPre() && !["code-block", "undo", "redo"].includes(item)) return;
|
|
9127
9620
|
switch (item) {
|
|
9128
9621
|
case "bold":
|
|
9129
9622
|
exec("bold");
|
|
@@ -9152,8 +9645,14 @@ var Editor = (props) => {
|
|
|
9152
9645
|
handleInput();
|
|
9153
9646
|
break;
|
|
9154
9647
|
}
|
|
9155
|
-
case "heading":
|
|
9156
|
-
|
|
9648
|
+
case "heading-1":
|
|
9649
|
+
toggleBlock("h1");
|
|
9650
|
+
break;
|
|
9651
|
+
case "heading-2":
|
|
9652
|
+
toggleBlock("h2");
|
|
9653
|
+
break;
|
|
9654
|
+
case "heading-3":
|
|
9655
|
+
toggleBlock("h3");
|
|
9157
9656
|
break;
|
|
9158
9657
|
case "list":
|
|
9159
9658
|
exec("insertUnorderedList");
|
|
@@ -9176,6 +9675,39 @@ var Editor = (props) => {
|
|
|
9176
9675
|
case "divider":
|
|
9177
9676
|
insertDivider();
|
|
9178
9677
|
break;
|
|
9678
|
+
case "checklist":
|
|
9679
|
+
toggleChecklist();
|
|
9680
|
+
break;
|
|
9681
|
+
case "align-left":
|
|
9682
|
+
setAlign("left");
|
|
9683
|
+
break;
|
|
9684
|
+
case "align-center":
|
|
9685
|
+
setAlign("center");
|
|
9686
|
+
break;
|
|
9687
|
+
case "align-right":
|
|
9688
|
+
setAlign("right");
|
|
9689
|
+
break;
|
|
9690
|
+
case "highlight":
|
|
9691
|
+
toggleHighlight();
|
|
9692
|
+
break;
|
|
9693
|
+
case "superscript":
|
|
9694
|
+
exec("superscript");
|
|
9695
|
+
break;
|
|
9696
|
+
case "subscript":
|
|
9697
|
+
exec("subscript");
|
|
9698
|
+
break;
|
|
9699
|
+
case "table":
|
|
9700
|
+
insertTable();
|
|
9701
|
+
break;
|
|
9702
|
+
case "clear-format":
|
|
9703
|
+
clearFormat();
|
|
9704
|
+
break;
|
|
9705
|
+
case "undo":
|
|
9706
|
+
undo();
|
|
9707
|
+
break;
|
|
9708
|
+
case "redo":
|
|
9709
|
+
redo();
|
|
9710
|
+
break;
|
|
9179
9711
|
}
|
|
9180
9712
|
};
|
|
9181
9713
|
return /* @__PURE__ */ (0, import_jsx_runtime323.jsxs)("div", { className: clsx_default("lib-xplat-editor", isFocused && "focused", readOnly && "readonly"), children: [
|
|
@@ -9184,7 +9716,10 @@ var Editor = (props) => {
|
|
|
9184
9716
|
{
|
|
9185
9717
|
items: toolbar,
|
|
9186
9718
|
active: activeFormats,
|
|
9187
|
-
onAction: onToolbarAction
|
|
9719
|
+
onAction: onToolbarAction,
|
|
9720
|
+
codeLang,
|
|
9721
|
+
inCodeBlock: activeFormats.has("block:pre"),
|
|
9722
|
+
onCodeLangChange: changeCodeLang
|
|
9188
9723
|
}
|
|
9189
9724
|
),
|
|
9190
9725
|
/* @__PURE__ */ (0, import_jsx_runtime323.jsxs)("div", { className: "lib-xplat-editor__content", style: { minHeight }, children: [
|
|
@@ -9202,6 +9737,7 @@ var Editor = (props) => {
|
|
|
9202
9737
|
className: "lib-xplat-editor__editable",
|
|
9203
9738
|
onInput: handleInput,
|
|
9204
9739
|
onKeyDown: handleKeyDown,
|
|
9740
|
+
onClick: handleEditorClick,
|
|
9205
9741
|
onKeyUp: handleSelectionUpdate,
|
|
9206
9742
|
onMouseUp: handleSelectionUpdate,
|
|
9207
9743
|
onPaste: handlePaste,
|
|
@@ -9243,14 +9779,27 @@ var TOOLBAR_LABEL = {
|
|
|
9243
9779
|
underline: "U",
|
|
9244
9780
|
strikethrough: "S",
|
|
9245
9781
|
code: "<>",
|
|
9246
|
-
heading: "
|
|
9782
|
+
"heading-1": "H1",
|
|
9783
|
+
"heading-2": "H2",
|
|
9784
|
+
"heading-3": "H3",
|
|
9247
9785
|
list: "\u2022",
|
|
9248
9786
|
"ordered-list": "1.",
|
|
9249
9787
|
blockquote: "\u275D",
|
|
9250
9788
|
"code-block": "[ ]",
|
|
9251
9789
|
link: "\u{1F517}",
|
|
9252
9790
|
image: "\u{1F5BC}",
|
|
9253
|
-
divider: "\u2014"
|
|
9791
|
+
divider: "\u2014",
|
|
9792
|
+
checklist: "\u2611",
|
|
9793
|
+
"align-left": "\u21E4",
|
|
9794
|
+
"align-center": "\u2194",
|
|
9795
|
+
"align-right": "\u21E5",
|
|
9796
|
+
highlight: "\u{1F58D}",
|
|
9797
|
+
superscript: "x\xB2",
|
|
9798
|
+
subscript: "x\u2082",
|
|
9799
|
+
table: "\u25A6",
|
|
9800
|
+
"clear-format": "\u232B",
|
|
9801
|
+
undo: "\u21B6",
|
|
9802
|
+
redo: "\u21B7"
|
|
9254
9803
|
};
|
|
9255
9804
|
var TOOLBAR_TITLE = {
|
|
9256
9805
|
bold: "\uAD75\uAC8C (\u2318B)",
|
|
@@ -9258,36 +9807,74 @@ var TOOLBAR_TITLE = {
|
|
|
9258
9807
|
underline: "\uBC11\uC904 (\u2318U)",
|
|
9259
9808
|
strikethrough: "\uCDE8\uC18C\uC120",
|
|
9260
9809
|
code: "\uC778\uB77C\uC778 \uCF54\uB4DC",
|
|
9261
|
-
heading: "\uC81C\uBAA9",
|
|
9810
|
+
"heading-1": "\uC81C\uBAA9 1",
|
|
9811
|
+
"heading-2": "\uC81C\uBAA9 2",
|
|
9812
|
+
"heading-3": "\uC81C\uBAA9 3",
|
|
9262
9813
|
list: "\uAE00\uBA38\uB9AC \uAE30\uD638 \uBAA9\uB85D",
|
|
9263
9814
|
"ordered-list": "\uBC88\uD638 \uB9E4\uAE30\uAE30 \uBAA9\uB85D",
|
|
9264
9815
|
blockquote: "\uC778\uC6A9",
|
|
9265
9816
|
"code-block": "\uCF54\uB4DC \uBE14\uB85D",
|
|
9266
9817
|
link: "\uB9C1\uD06C (\u2318K)",
|
|
9267
9818
|
image: "\uC774\uBBF8\uC9C0",
|
|
9268
|
-
divider: "\uAD6C\uBD84\uC120"
|
|
9819
|
+
divider: "\uAD6C\uBD84\uC120",
|
|
9820
|
+
checklist: "\uCCB4\uD06C\uB9AC\uC2A4\uD2B8",
|
|
9821
|
+
"align-left": "\uC67C\uCABD \uC815\uB82C",
|
|
9822
|
+
"align-center": "\uAC00\uC6B4\uB370 \uC815\uB82C",
|
|
9823
|
+
"align-right": "\uC624\uB978\uCABD \uC815\uB82C",
|
|
9824
|
+
highlight: "\uD615\uAD11\uD39C",
|
|
9825
|
+
superscript: "\uC704 \uCCA8\uC790",
|
|
9826
|
+
subscript: "\uC544\uB798 \uCCA8\uC790",
|
|
9827
|
+
table: "\uD45C \uC0BD\uC785",
|
|
9828
|
+
"clear-format": "\uC11C\uC2DD \uC9C0\uC6B0\uAE30",
|
|
9829
|
+
undo: "\uB418\uB3CC\uB9AC\uAE30 (\u2318Z)",
|
|
9830
|
+
redo: "\uB2E4\uC2DC\uD558\uAE30 (\u2318\u21E7Z)"
|
|
9269
9831
|
};
|
|
9270
9832
|
var isActive = (item, active) => {
|
|
9271
|
-
if (item === "heading") return active.has("block:h1")
|
|
9833
|
+
if (item === "heading-1") return active.has("block:h1");
|
|
9834
|
+
if (item === "heading-2") return active.has("block:h2");
|
|
9835
|
+
if (item === "heading-3") return active.has("block:h3");
|
|
9272
9836
|
if (item === "blockquote") return active.has("block:blockquote");
|
|
9273
9837
|
if (item === "code-block") return active.has("block:pre");
|
|
9838
|
+
if (item === "align-left") return active.has("align:left");
|
|
9839
|
+
if (item === "align-center") return active.has("align:center");
|
|
9840
|
+
if (item === "align-right") return active.has("align:right");
|
|
9274
9841
|
return active.has(item);
|
|
9275
9842
|
};
|
|
9276
|
-
var EditorToolbar = ({
|
|
9277
|
-
|
|
9278
|
-
|
|
9279
|
-
|
|
9280
|
-
|
|
9281
|
-
|
|
9282
|
-
|
|
9283
|
-
|
|
9284
|
-
|
|
9285
|
-
|
|
9843
|
+
var EditorToolbar = ({
|
|
9844
|
+
items,
|
|
9845
|
+
active,
|
|
9846
|
+
onAction,
|
|
9847
|
+
codeLang,
|
|
9848
|
+
inCodeBlock,
|
|
9849
|
+
onCodeLangChange
|
|
9850
|
+
}) => {
|
|
9851
|
+
return /* @__PURE__ */ (0, import_jsx_runtime323.jsxs)("div", { className: "lib-xplat-editor__toolbar", children: [
|
|
9852
|
+
items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime323.jsx)(
|
|
9853
|
+
"button",
|
|
9854
|
+
{
|
|
9855
|
+
type: "button",
|
|
9856
|
+
className: clsx_default("lib-xplat-editor__toolbar-btn", isActive(item, active) && "active"),
|
|
9857
|
+
title: TOOLBAR_TITLE[item],
|
|
9858
|
+
onMouseDown: (e) => {
|
|
9859
|
+
e.preventDefault();
|
|
9860
|
+
onAction(item);
|
|
9861
|
+
},
|
|
9862
|
+
children: TOOLBAR_LABEL[item]
|
|
9286
9863
|
},
|
|
9287
|
-
|
|
9288
|
-
|
|
9289
|
-
|
|
9290
|
-
|
|
9864
|
+
item
|
|
9865
|
+
)),
|
|
9866
|
+
inCodeBlock && /* @__PURE__ */ (0, import_jsx_runtime323.jsx)(
|
|
9867
|
+
"select",
|
|
9868
|
+
{
|
|
9869
|
+
className: "lib-xplat-editor__lang",
|
|
9870
|
+
value: codeLang,
|
|
9871
|
+
"aria-label": "\uCF54\uB4DC \uC5B8\uC5B4",
|
|
9872
|
+
onMouseDown: (e) => e.stopPropagation(),
|
|
9873
|
+
onChange: (e) => onCodeLangChange(e.target.value),
|
|
9874
|
+
children: CODE_LANGUAGES.map((l) => /* @__PURE__ */ (0, import_jsx_runtime323.jsx)("option", { value: l.value, children: l.label }, l.value))
|
|
9875
|
+
}
|
|
9876
|
+
)
|
|
9877
|
+
] });
|
|
9291
9878
|
};
|
|
9292
9879
|
var SlashMenu = ({ position, items, activeIndex, onSelect, onClose }) => {
|
|
9293
9880
|
import_react22.default.useEffect(() => {
|
|
@@ -9832,6 +10419,7 @@ var PopOver = (props) => {
|
|
|
9832
10419
|
className: clsx_default(
|
|
9833
10420
|
"lib-xplat-pop-over-content",
|
|
9834
10421
|
position.direction,
|
|
10422
|
+
position.repositioning && "repositioning",
|
|
9835
10423
|
eventTrigger && "visible"
|
|
9836
10424
|
),
|
|
9837
10425
|
ref: popRef,
|
|
@@ -10178,7 +10766,7 @@ var SelectRoot = (props) => {
|
|
|
10178
10766
|
mounted && /* @__PURE__ */ (0, import_jsx_runtime337.jsx)(Portal_default, { children: /* @__PURE__ */ (0, import_jsx_runtime337.jsxs)(
|
|
10179
10767
|
"div",
|
|
10180
10768
|
{
|
|
10181
|
-
className: clsx_default("lib-xplat-select-content", size, position.direction, stateClass),
|
|
10769
|
+
className: clsx_default("lib-xplat-select-content", size, position.direction, stateClass, position.repositioning && "repositioning"),
|
|
10182
10770
|
ref: contentRef,
|
|
10183
10771
|
style: { ...position.position, width: triggerRef.current?.offsetWidth },
|
|
10184
10772
|
role: "listbox",
|
|
@@ -11071,7 +11659,7 @@ var TimePicker = (props) => {
|
|
|
11071
11659
|
"div",
|
|
11072
11660
|
{
|
|
11073
11661
|
ref: contentRef,
|
|
11074
|
-
className: clsx_default("lib-xplat-time-picker-content", size, visible ? "enter" : "exit"),
|
|
11662
|
+
className: clsx_default("lib-xplat-time-picker-content", size, visible ? "enter" : "exit", position.repositioning && "repositioning"),
|
|
11075
11663
|
style: { ...position.position, width: triggerRef.current?.offsetWidth },
|
|
11076
11664
|
role: "listbox",
|
|
11077
11665
|
children: options.map((t) => /* @__PURE__ */ (0, import_jsx_runtime351.jsx)(
|