@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
|
@@ -3943,8 +3943,10 @@ var import_react19 = __toESM(require("react"), 1);
|
|
|
3943
3943
|
var useAutoPosition = (triggerRef, popRef, enabled = true) => {
|
|
3944
3944
|
const [position, setPosition] = import_react19.default.useState({
|
|
3945
3945
|
position: {},
|
|
3946
|
-
direction: "bottom"
|
|
3946
|
+
direction: "bottom",
|
|
3947
|
+
repositioning: false
|
|
3947
3948
|
});
|
|
3949
|
+
const placedRef = import_react19.default.useRef(false);
|
|
3948
3950
|
const calculatePosition = import_react19.default.useCallback(() => {
|
|
3949
3951
|
if (!triggerRef.current || !popRef.current) return;
|
|
3950
3952
|
const triggerRect = triggerRef.current.getBoundingClientRect();
|
|
@@ -3969,11 +3971,16 @@ var useAutoPosition = (triggerRef, popRef, enabled = true) => {
|
|
|
3969
3971
|
if (left < 8) left = 8;
|
|
3970
3972
|
setPosition({
|
|
3971
3973
|
position: { top, left },
|
|
3972
|
-
direction
|
|
3974
|
+
direction,
|
|
3975
|
+
repositioning: placedRef.current
|
|
3973
3976
|
});
|
|
3977
|
+
placedRef.current = true;
|
|
3974
3978
|
}, [triggerRef, popRef]);
|
|
3975
3979
|
import_react19.default.useLayoutEffect(() => {
|
|
3976
|
-
if (!enabled)
|
|
3980
|
+
if (!enabled) {
|
|
3981
|
+
placedRef.current = false;
|
|
3982
|
+
return;
|
|
3983
|
+
}
|
|
3977
3984
|
calculatePosition();
|
|
3978
3985
|
const raf = requestAnimationFrame(calculatePosition);
|
|
3979
3986
|
return () => cancelAnimationFrame(raf);
|
|
@@ -3988,11 +3995,17 @@ var useAutoPosition = (triggerRef, popRef, enabled = true) => {
|
|
|
3988
3995
|
}, [calculatePosition, enabled, popRef]);
|
|
3989
3996
|
import_react19.default.useEffect(() => {
|
|
3990
3997
|
if (!enabled) return;
|
|
3991
|
-
|
|
3992
|
-
|
|
3998
|
+
let raf = 0;
|
|
3999
|
+
const onScrollOrResize = () => {
|
|
4000
|
+
cancelAnimationFrame(raf);
|
|
4001
|
+
raf = requestAnimationFrame(calculatePosition);
|
|
4002
|
+
};
|
|
4003
|
+
window.addEventListener("resize", onScrollOrResize, { passive: true });
|
|
4004
|
+
window.addEventListener("scroll", onScrollOrResize, { passive: true, capture: true });
|
|
3993
4005
|
return () => {
|
|
3994
|
-
|
|
3995
|
-
window.removeEventListener("
|
|
4006
|
+
cancelAnimationFrame(raf);
|
|
4007
|
+
window.removeEventListener("resize", onScrollOrResize);
|
|
4008
|
+
window.removeEventListener("scroll", onScrollOrResize, true);
|
|
3996
4009
|
};
|
|
3997
4010
|
}, [calculatePosition, enabled]);
|
|
3998
4011
|
return position;
|
|
@@ -4033,7 +4046,7 @@ var Dropdown = (props) => {
|
|
|
4033
4046
|
const [visible, setVisible] = import_react21.default.useState(false);
|
|
4034
4047
|
const triggerRef = import_react21.default.useRef(null);
|
|
4035
4048
|
const menuRef = import_react21.default.useRef(null);
|
|
4036
|
-
const { position, direction } = useAutoPosition_default(triggerRef, menuRef, mounted);
|
|
4049
|
+
const { position, direction, repositioning } = useAutoPosition_default(triggerRef, menuRef, mounted);
|
|
4037
4050
|
useClickOutside_default([triggerRef, menuRef], () => setIsOpen(false), isOpen);
|
|
4038
4051
|
useEscapeKey(isOpen, () => {
|
|
4039
4052
|
setIsOpen(false);
|
|
@@ -4068,7 +4081,7 @@ var Dropdown = (props) => {
|
|
|
4068
4081
|
"div",
|
|
4069
4082
|
{
|
|
4070
4083
|
ref: menuRef,
|
|
4071
|
-
className: clsx_default("lib-xplat-dropdown-menu", direction, { visible }),
|
|
4084
|
+
className: clsx_default("lib-xplat-dropdown-menu", direction, { visible }, repositioning && "repositioning"),
|
|
4072
4085
|
style: { top: position.top, left: position.left },
|
|
4073
4086
|
role: "menu",
|
|
4074
4087
|
children: items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime322.jsx)(
|
|
@@ -4094,6 +4107,111 @@ var Dropdown_default = Dropdown;
|
|
|
4094
4107
|
|
|
4095
4108
|
// src/components/Editor/Editor.tsx
|
|
4096
4109
|
var import_react22 = __toESM(require("react"), 1);
|
|
4110
|
+
|
|
4111
|
+
// src/components/Editor/highlight.ts
|
|
4112
|
+
var CODE_LANGUAGES = [
|
|
4113
|
+
{ value: "plain", label: "\uC5C6\uC74C" },
|
|
4114
|
+
{ value: "javascript", label: "JavaScript" },
|
|
4115
|
+
{ value: "typescript", label: "TypeScript" },
|
|
4116
|
+
{ value: "json", label: "JSON" },
|
|
4117
|
+
{ value: "html", label: "HTML" },
|
|
4118
|
+
{ value: "css", label: "CSS" },
|
|
4119
|
+
{ value: "python", label: "Python" },
|
|
4120
|
+
{ value: "sql", label: "SQL" },
|
|
4121
|
+
{ value: "bash", label: "Bash" }
|
|
4122
|
+
];
|
|
4123
|
+
var KEYWORDS = {
|
|
4124
|
+
plain: [],
|
|
4125
|
+
javascript: "const let var function return if else for while class new this import export from default async await try catch throw typeof instanceof null undefined true false break continue switch case do delete in of yield".split(" "),
|
|
4126
|
+
typescript: "const let var function return if else for while class new this import export from default async await try catch throw typeof instanceof null undefined true false break continue switch case do delete in of yield interface type enum implements extends public private protected readonly as satisfies keyof infer never unknown any".split(" "),
|
|
4127
|
+
json: ["true", "false", "null"],
|
|
4128
|
+
html: [],
|
|
4129
|
+
css: [],
|
|
4130
|
+
python: "def class return if elif else for while import from as try except finally raise with lambda None True False and or not in is pass break continue global nonlocal yield async await".split(" "),
|
|
4131
|
+
sql: "SELECT FROM WHERE INSERT INTO VALUES UPDATE SET DELETE CREATE TABLE ALTER DROP JOIN LEFT RIGHT INNER OUTER ON GROUP BY ORDER HAVING LIMIT OFFSET AS AND OR NOT NULL DISTINCT UNION INDEX PRIMARY KEY FOREIGN REFERENCES DEFAULT".split(" "),
|
|
4132
|
+
bash: "if then else fi for while do done case esac function return export local echo cd ls rm cp mv mkdir sudo source set unset exit".split(" ")
|
|
4133
|
+
};
|
|
4134
|
+
var LINE_COMMENT = {
|
|
4135
|
+
javascript: "//",
|
|
4136
|
+
typescript: "//",
|
|
4137
|
+
css: "",
|
|
4138
|
+
python: "#",
|
|
4139
|
+
sql: "--",
|
|
4140
|
+
bash: "#"
|
|
4141
|
+
};
|
|
4142
|
+
var escape = (s) => s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
4143
|
+
var wrap = (cls, text) => `<span class="tok-${cls}">${escape(text)}</span>`;
|
|
4144
|
+
var highlight = (code, lang) => {
|
|
4145
|
+
if (lang === "plain" || !code) return escape(code);
|
|
4146
|
+
const keywords = new Set(KEYWORDS[lang]);
|
|
4147
|
+
const lineComment = LINE_COMMENT[lang];
|
|
4148
|
+
const caseInsensitive = lang === "sql";
|
|
4149
|
+
let out = "";
|
|
4150
|
+
let i = 0;
|
|
4151
|
+
while (i < code.length) {
|
|
4152
|
+
const rest = code.slice(i);
|
|
4153
|
+
if ((lang === "javascript" || lang === "typescript" || lang === "css") && rest.startsWith("/*")) {
|
|
4154
|
+
const end = code.indexOf("*/", i + 2);
|
|
4155
|
+
const stop = end === -1 ? code.length : end + 2;
|
|
4156
|
+
out += wrap("comment", code.slice(i, stop));
|
|
4157
|
+
i = stop;
|
|
4158
|
+
continue;
|
|
4159
|
+
}
|
|
4160
|
+
if (lineComment && rest.startsWith(lineComment)) {
|
|
4161
|
+
const nl = code.indexOf("\n", i);
|
|
4162
|
+
const stop = nl === -1 ? code.length : nl;
|
|
4163
|
+
out += wrap("comment", code.slice(i, stop));
|
|
4164
|
+
i = stop;
|
|
4165
|
+
continue;
|
|
4166
|
+
}
|
|
4167
|
+
const q = rest[0];
|
|
4168
|
+
if (q === '"' || q === "'" || q === "`") {
|
|
4169
|
+
let j = 1;
|
|
4170
|
+
while (j < rest.length) {
|
|
4171
|
+
if (rest[j] === "\\") {
|
|
4172
|
+
j += 2;
|
|
4173
|
+
continue;
|
|
4174
|
+
}
|
|
4175
|
+
if (rest[j] === q) {
|
|
4176
|
+
j += 1;
|
|
4177
|
+
break;
|
|
4178
|
+
}
|
|
4179
|
+
if (rest[j] === "\n" && q !== "`") break;
|
|
4180
|
+
j += 1;
|
|
4181
|
+
}
|
|
4182
|
+
out += wrap("string", rest.slice(0, j));
|
|
4183
|
+
i += j;
|
|
4184
|
+
continue;
|
|
4185
|
+
}
|
|
4186
|
+
const num = /^\d+(\.\d+)?/.exec(rest);
|
|
4187
|
+
if (num && !/[\w$]/.test(code[i - 1] ?? "")) {
|
|
4188
|
+
out += wrap("number", num[0]);
|
|
4189
|
+
i += num[0].length;
|
|
4190
|
+
continue;
|
|
4191
|
+
}
|
|
4192
|
+
const word = /^[A-Za-z_$][\w$]*/.exec(rest);
|
|
4193
|
+
if (word) {
|
|
4194
|
+
const w = word[0];
|
|
4195
|
+
const hit = caseInsensitive ? keywords.has(w.toUpperCase()) : keywords.has(w);
|
|
4196
|
+
out += hit ? wrap("keyword", w) : escape(w);
|
|
4197
|
+
i += w.length;
|
|
4198
|
+
continue;
|
|
4199
|
+
}
|
|
4200
|
+
if (lang === "html" && rest.startsWith("<")) {
|
|
4201
|
+
const tag = /^<\/?[A-Za-z][\w-]*/.exec(rest);
|
|
4202
|
+
if (tag) {
|
|
4203
|
+
out += wrap("keyword", tag[0]);
|
|
4204
|
+
i += tag[0].length;
|
|
4205
|
+
continue;
|
|
4206
|
+
}
|
|
4207
|
+
}
|
|
4208
|
+
out += escape(code[i]);
|
|
4209
|
+
i += 1;
|
|
4210
|
+
}
|
|
4211
|
+
return out;
|
|
4212
|
+
};
|
|
4213
|
+
|
|
4214
|
+
// src/components/Editor/Editor.tsx
|
|
4097
4215
|
var import_jsx_runtime323 = require("react/jsx-runtime");
|
|
4098
4216
|
var DEFAULT_TOOLBAR = [
|
|
4099
4217
|
"bold",
|
|
@@ -4101,14 +4219,27 @@ var DEFAULT_TOOLBAR = [
|
|
|
4101
4219
|
"underline",
|
|
4102
4220
|
"strikethrough",
|
|
4103
4221
|
"code",
|
|
4104
|
-
"heading",
|
|
4222
|
+
"heading-1",
|
|
4223
|
+
"heading-2",
|
|
4224
|
+
"heading-3",
|
|
4105
4225
|
"list",
|
|
4106
4226
|
"ordered-list",
|
|
4107
4227
|
"blockquote",
|
|
4108
4228
|
"code-block",
|
|
4109
4229
|
"link",
|
|
4110
4230
|
"image",
|
|
4111
|
-
"divider"
|
|
4231
|
+
"divider",
|
|
4232
|
+
"checklist",
|
|
4233
|
+
"table",
|
|
4234
|
+
"align-left",
|
|
4235
|
+
"align-center",
|
|
4236
|
+
"align-right",
|
|
4237
|
+
"highlight",
|
|
4238
|
+
"superscript",
|
|
4239
|
+
"subscript",
|
|
4240
|
+
"clear-format",
|
|
4241
|
+
"undo",
|
|
4242
|
+
"redo"
|
|
4112
4243
|
];
|
|
4113
4244
|
var ALLOWED_TAGS = /* @__PURE__ */ new Set([
|
|
4114
4245
|
"p",
|
|
@@ -4137,11 +4268,41 @@ var ALLOWED_TAGS = /* @__PURE__ */ new Set([
|
|
|
4137
4268
|
"img",
|
|
4138
4269
|
"hr",
|
|
4139
4270
|
"span",
|
|
4140
|
-
"div"
|
|
4271
|
+
"div",
|
|
4272
|
+
"sub",
|
|
4273
|
+
"sup",
|
|
4274
|
+
"mark",
|
|
4275
|
+
"table",
|
|
4276
|
+
"thead",
|
|
4277
|
+
"tbody",
|
|
4278
|
+
"tr",
|
|
4279
|
+
"th",
|
|
4280
|
+
"td"
|
|
4141
4281
|
]);
|
|
4142
4282
|
var ALLOWED_ATTRS = {
|
|
4143
4283
|
a: ["href", "target", "rel"],
|
|
4144
|
-
img: ["src", "alt"]
|
|
4284
|
+
img: ["src", "alt", "width"],
|
|
4285
|
+
// 정렬·체크리스트는 클래스로만 표현한다. style 을 열면 붙여넣기로 아무 CSS 나 들어온다
|
|
4286
|
+
p: ["class"],
|
|
4287
|
+
h1: ["class"],
|
|
4288
|
+
h2: ["class"],
|
|
4289
|
+
h3: ["class"],
|
|
4290
|
+
h4: ["class"],
|
|
4291
|
+
h5: ["class"],
|
|
4292
|
+
h6: ["class"],
|
|
4293
|
+
ul: ["class"],
|
|
4294
|
+
ol: ["class"],
|
|
4295
|
+
li: ["class", "data-checked"],
|
|
4296
|
+
blockquote: ["class"],
|
|
4297
|
+
div: ["class"],
|
|
4298
|
+
span: ["class"],
|
|
4299
|
+
pre: ["class"],
|
|
4300
|
+
code: ["class"],
|
|
4301
|
+
mark: ["class"],
|
|
4302
|
+
table: ["class"],
|
|
4303
|
+
td: ["class"],
|
|
4304
|
+
th: ["class"],
|
|
4305
|
+
tr: ["class"]
|
|
4145
4306
|
};
|
|
4146
4307
|
var DROP_WITH_CONTENT = /* @__PURE__ */ new Set([
|
|
4147
4308
|
"script",
|
|
@@ -4194,7 +4355,9 @@ var escapeHtml = (text) => {
|
|
|
4194
4355
|
};
|
|
4195
4356
|
var SLASH_ITEMS = [
|
|
4196
4357
|
{ key: "paragraph", label: "\uB2E8\uB77D", hint: "\uAE30\uBCF8 \uD14D\uC2A4\uD2B8" },
|
|
4197
|
-
{ key: "heading", label: "\uC81C\uBAA9 1", hint: "\uD070 \uC81C\uBAA9" },
|
|
4358
|
+
{ key: "heading-1", label: "\uC81C\uBAA9 1", hint: "\uAC00\uC7A5 \uD070 \uC81C\uBAA9" },
|
|
4359
|
+
{ key: "heading-2", label: "\uC81C\uBAA9 2", hint: "" },
|
|
4360
|
+
{ key: "heading-3", label: "\uC81C\uBAA9 3", hint: "" },
|
|
4198
4361
|
{ key: "list", label: "\uAE00\uBA38\uB9AC \uAE30\uD638 \uBAA9\uB85D", hint: "\u2022 \uD56D\uBAA9" },
|
|
4199
4362
|
{ key: "ordered-list", label: "\uBC88\uD638 \uB9E4\uAE30\uAE30 \uBAA9\uB85D", hint: "1. \uD56D\uBAA9" },
|
|
4200
4363
|
{ key: "blockquote", label: "\uC778\uC6A9", hint: "" },
|
|
@@ -4237,6 +4400,8 @@ var Editor = (props) => {
|
|
|
4237
4400
|
el.innerHTML = sanitizeHtml(value || "");
|
|
4238
4401
|
if (!el.firstChild) el.innerHTML = "<p><br></p>";
|
|
4239
4402
|
lastEmittedRef.current = null;
|
|
4403
|
+
historyRef.current = [{ html: el.innerHTML, caret: 0 }];
|
|
4404
|
+
historyIdxRef.current = 0;
|
|
4240
4405
|
updateEmpty();
|
|
4241
4406
|
}, [value]);
|
|
4242
4407
|
const updateEmpty = () => {
|
|
@@ -4281,6 +4446,17 @@ var Editor = (props) => {
|
|
|
4281
4446
|
if (document.queryCommandState("insertOrderedList")) next.add("ordered-list");
|
|
4282
4447
|
const block = String(document.queryCommandValue("formatBlock") || "").toLowerCase();
|
|
4283
4448
|
if (block) next.add(`block:${block}`);
|
|
4449
|
+
if (document.queryCommandState("superscript")) next.add("superscript");
|
|
4450
|
+
if (document.queryCommandState("subscript")) next.add("subscript");
|
|
4451
|
+
} catch {
|
|
4452
|
+
}
|
|
4453
|
+
try {
|
|
4454
|
+
const blockEl = currentBlock();
|
|
4455
|
+
if (blockEl?.classList.contains("align-center")) next.add("align:center");
|
|
4456
|
+
else if (blockEl?.classList.contains("align-right")) next.add("align:right");
|
|
4457
|
+
else if (blockEl) next.add("align:left");
|
|
4458
|
+
if (blockEl?.closest("mark")) next.add("highlight");
|
|
4459
|
+
if (blockEl?.closest("ul.checklist")) next.add("checklist");
|
|
4284
4460
|
} catch {
|
|
4285
4461
|
}
|
|
4286
4462
|
setActiveFormats(next);
|
|
@@ -4294,6 +4470,122 @@ var Editor = (props) => {
|
|
|
4294
4470
|
const setBlock = (tag) => {
|
|
4295
4471
|
exec("formatBlock", tag);
|
|
4296
4472
|
};
|
|
4473
|
+
const toggleBlock = (tag) => {
|
|
4474
|
+
const current = String(document.queryCommandValue("formatBlock") || "").toLowerCase();
|
|
4475
|
+
setBlock(current === tag ? "p" : tag);
|
|
4476
|
+
};
|
|
4477
|
+
const historyRef = import_react22.default.useRef([]);
|
|
4478
|
+
const historyIdxRef = import_react22.default.useRef(-1);
|
|
4479
|
+
const lastPushAtRef = import_react22.default.useRef(0);
|
|
4480
|
+
const isRestoringRef = import_react22.default.useRef(false);
|
|
4481
|
+
const caretOffset = (rootEl) => {
|
|
4482
|
+
const el = rootEl ?? editorRef.current;
|
|
4483
|
+
const sel = window.getSelection();
|
|
4484
|
+
if (!el || !sel || sel.rangeCount === 0 || !el.contains(sel.anchorNode)) return 0;
|
|
4485
|
+
const range = sel.getRangeAt(0).cloneRange();
|
|
4486
|
+
range.selectNodeContents(el);
|
|
4487
|
+
range.setEnd(sel.getRangeAt(0).endContainer, sel.getRangeAt(0).endOffset);
|
|
4488
|
+
return range.toString().length;
|
|
4489
|
+
};
|
|
4490
|
+
const setCaretOffset = (offset, rootEl) => {
|
|
4491
|
+
const el = rootEl ?? editorRef.current;
|
|
4492
|
+
if (!el) return;
|
|
4493
|
+
const walker = document.createTreeWalker(el, NodeFilter.SHOW_TEXT);
|
|
4494
|
+
let remaining = offset;
|
|
4495
|
+
let node = null;
|
|
4496
|
+
while (node = walker.nextNode()) {
|
|
4497
|
+
const len = node.textContent?.length ?? 0;
|
|
4498
|
+
if (remaining <= len) {
|
|
4499
|
+
const range = document.createRange();
|
|
4500
|
+
range.setStart(node, remaining);
|
|
4501
|
+
range.collapse(true);
|
|
4502
|
+
const sel = window.getSelection();
|
|
4503
|
+
sel?.removeAllRanges();
|
|
4504
|
+
sel?.addRange(range);
|
|
4505
|
+
return;
|
|
4506
|
+
}
|
|
4507
|
+
remaining -= len;
|
|
4508
|
+
}
|
|
4509
|
+
placeCaretAtEnd(el);
|
|
4510
|
+
};
|
|
4511
|
+
const pushHistory = (force = false) => {
|
|
4512
|
+
const el = editorRef.current;
|
|
4513
|
+
if (!el || isRestoringRef.current) return;
|
|
4514
|
+
const html = el.innerHTML;
|
|
4515
|
+
const hist = historyRef.current;
|
|
4516
|
+
const cur = hist[historyIdxRef.current];
|
|
4517
|
+
if (cur && cur.html === html) return;
|
|
4518
|
+
const now = Date.now();
|
|
4519
|
+
const coalesce = !force && cur && now - lastPushAtRef.current < 500;
|
|
4520
|
+
lastPushAtRef.current = now;
|
|
4521
|
+
if (coalesce) {
|
|
4522
|
+
hist[historyIdxRef.current] = { html, caret: caretOffset() };
|
|
4523
|
+
return;
|
|
4524
|
+
}
|
|
4525
|
+
hist.length = historyIdxRef.current + 1;
|
|
4526
|
+
hist.push({ html, caret: caretOffset() });
|
|
4527
|
+
if (hist.length > 200) hist.shift();
|
|
4528
|
+
historyIdxRef.current = hist.length - 1;
|
|
4529
|
+
};
|
|
4530
|
+
const applySnapshot = (snap) => {
|
|
4531
|
+
const el = editorRef.current;
|
|
4532
|
+
if (!el) return;
|
|
4533
|
+
isRestoringRef.current = true;
|
|
4534
|
+
el.innerHTML = snap.html;
|
|
4535
|
+
setCaretOffset(snap.caret);
|
|
4536
|
+
isRestoringRef.current = false;
|
|
4537
|
+
lastEmittedRef.current = el.innerHTML;
|
|
4538
|
+
onChange?.(el.innerHTML);
|
|
4539
|
+
updateEmpty();
|
|
4540
|
+
updateActiveFormats();
|
|
4541
|
+
};
|
|
4542
|
+
const undo = () => {
|
|
4543
|
+
pushHistory(true);
|
|
4544
|
+
if (historyIdxRef.current <= 0) return;
|
|
4545
|
+
historyIdxRef.current -= 1;
|
|
4546
|
+
applySnapshot(historyRef.current[historyIdxRef.current]);
|
|
4547
|
+
};
|
|
4548
|
+
const redo = () => {
|
|
4549
|
+
if (historyIdxRef.current >= historyRef.current.length - 1) return;
|
|
4550
|
+
historyIdxRef.current += 1;
|
|
4551
|
+
applySnapshot(historyRef.current[historyIdxRef.current]);
|
|
4552
|
+
};
|
|
4553
|
+
const langOf = (pre) => {
|
|
4554
|
+
const cls = Array.from(pre.classList).find((c) => c.startsWith("lang-"));
|
|
4555
|
+
return cls?.slice(5) ?? "plain";
|
|
4556
|
+
};
|
|
4557
|
+
const [codeLang, setCodeLang] = import_react22.default.useState("plain");
|
|
4558
|
+
const highlightRafRef = import_react22.default.useRef(0);
|
|
4559
|
+
const rehighlight = (pre) => {
|
|
4560
|
+
if (composingRef.current) return;
|
|
4561
|
+
const code = pre.querySelector("code");
|
|
4562
|
+
if (!code) return;
|
|
4563
|
+
const lang = langOf(pre);
|
|
4564
|
+
const text = code.textContent || "";
|
|
4565
|
+
const next = highlight(text, lang);
|
|
4566
|
+
if (code.innerHTML === next) return;
|
|
4567
|
+
const caret = caretOffset(code);
|
|
4568
|
+
isRestoringRef.current = true;
|
|
4569
|
+
code.innerHTML = next;
|
|
4570
|
+
setCaretOffset(caret, code);
|
|
4571
|
+
isRestoringRef.current = false;
|
|
4572
|
+
};
|
|
4573
|
+
const scheduleHighlight = () => {
|
|
4574
|
+
const pre = closestPre();
|
|
4575
|
+
if (!pre) return;
|
|
4576
|
+
cancelAnimationFrame(highlightRafRef.current);
|
|
4577
|
+
highlightRafRef.current = requestAnimationFrame(() => rehighlight(pre));
|
|
4578
|
+
};
|
|
4579
|
+
const changeCodeLang = (lang) => {
|
|
4580
|
+
const pre = closestPre();
|
|
4581
|
+
if (!pre) return;
|
|
4582
|
+
pushHistory(true);
|
|
4583
|
+
Array.from(pre.classList).filter((c) => c.startsWith("lang-")).forEach((c) => pre.classList.remove(c));
|
|
4584
|
+
if (lang !== "plain") pre.classList.add(`lang-${lang}`);
|
|
4585
|
+
setCodeLang(lang);
|
|
4586
|
+
rehighlight(pre);
|
|
4587
|
+
handleInput();
|
|
4588
|
+
};
|
|
4297
4589
|
const closestPre = () => {
|
|
4298
4590
|
const sel = window.getSelection();
|
|
4299
4591
|
const node = sel?.anchorNode;
|
|
@@ -4302,6 +4594,7 @@ var Editor = (props) => {
|
|
|
4302
4594
|
return el?.closest("pre") ?? null;
|
|
4303
4595
|
};
|
|
4304
4596
|
const insertCodeBlock = () => {
|
|
4597
|
+
pushHistory(true);
|
|
4305
4598
|
const el = editorRef.current;
|
|
4306
4599
|
const sel = window.getSelection();
|
|
4307
4600
|
if (!el || !sel || sel.rangeCount === 0) return;
|
|
@@ -4384,7 +4677,167 @@ var Editor = (props) => {
|
|
|
4384
4677
|
sel.addRange(r2);
|
|
4385
4678
|
editorRef.current?.focus();
|
|
4386
4679
|
};
|
|
4680
|
+
const clearFormat = () => {
|
|
4681
|
+
exec("removeFormat");
|
|
4682
|
+
exec("unlink");
|
|
4683
|
+
setBlock("p");
|
|
4684
|
+
};
|
|
4685
|
+
const indentList = (outdent) => {
|
|
4686
|
+
exec(outdent ? "outdent" : "indent");
|
|
4687
|
+
};
|
|
4688
|
+
const inListItem = () => {
|
|
4689
|
+
const sel = window.getSelection();
|
|
4690
|
+
const node = sel?.anchorNode;
|
|
4691
|
+
if (!node || !editorRef.current?.contains(node)) return false;
|
|
4692
|
+
const el = node.nodeType === Node.ELEMENT_NODE ? node : node.parentElement;
|
|
4693
|
+
return !!el?.closest("li");
|
|
4694
|
+
};
|
|
4695
|
+
const currentBlock = () => {
|
|
4696
|
+
const sel = window.getSelection();
|
|
4697
|
+
const node = sel?.anchorNode;
|
|
4698
|
+
const root = editorRef.current;
|
|
4699
|
+
if (!node || !root?.contains(node)) return null;
|
|
4700
|
+
let el = node.nodeType === Node.ELEMENT_NODE ? node : node.parentElement;
|
|
4701
|
+
while (el && el !== root && !/^(P|H[1-6]|LI|BLOCKQUOTE|PRE|DIV|TD|TH)$/.test(el.tagName)) {
|
|
4702
|
+
el = el.parentElement;
|
|
4703
|
+
}
|
|
4704
|
+
return el && el !== root ? el : null;
|
|
4705
|
+
};
|
|
4706
|
+
const setAlign = (align) => {
|
|
4707
|
+
const block = currentBlock();
|
|
4708
|
+
if (!block) return;
|
|
4709
|
+
pushHistory(true);
|
|
4710
|
+
block.classList.remove("align-left", "align-center", "align-right");
|
|
4711
|
+
if (align !== "left") block.classList.add(`align-${align}`);
|
|
4712
|
+
handleInput();
|
|
4713
|
+
};
|
|
4714
|
+
const toggleChecklist = () => {
|
|
4715
|
+
pushHistory(true);
|
|
4716
|
+
const block = currentBlock();
|
|
4717
|
+
const list = block?.closest("ul");
|
|
4718
|
+
if (list?.classList.contains("checklist")) {
|
|
4719
|
+
list.classList.remove("checklist");
|
|
4720
|
+
list.querySelectorAll("li").forEach((li) => li.removeAttribute("data-checked"));
|
|
4721
|
+
handleInput();
|
|
4722
|
+
return;
|
|
4723
|
+
}
|
|
4724
|
+
if (list) {
|
|
4725
|
+
list.classList.add("checklist");
|
|
4726
|
+
list.querySelectorAll("li").forEach((li) => li.setAttribute("data-checked", "false"));
|
|
4727
|
+
handleInput();
|
|
4728
|
+
return;
|
|
4729
|
+
}
|
|
4730
|
+
exec("insertUnorderedList");
|
|
4731
|
+
const made = currentBlock()?.closest("ul");
|
|
4732
|
+
if (made) {
|
|
4733
|
+
made.classList.add("checklist");
|
|
4734
|
+
made.querySelectorAll("li").forEach((li) => li.setAttribute("data-checked", "false"));
|
|
4735
|
+
}
|
|
4736
|
+
handleInput();
|
|
4737
|
+
};
|
|
4738
|
+
const handleEditorClick = (e) => {
|
|
4739
|
+
if (readOnly) return;
|
|
4740
|
+
const target = e.target;
|
|
4741
|
+
const li = target.closest?.("li");
|
|
4742
|
+
if (!li || !li.closest("ul.checklist")) return;
|
|
4743
|
+
const rect = li.getBoundingClientRect();
|
|
4744
|
+
if (e.clientX - rect.left > 20) return;
|
|
4745
|
+
e.preventDefault();
|
|
4746
|
+
pushHistory(true);
|
|
4747
|
+
li.setAttribute("data-checked", li.getAttribute("data-checked") === "true" ? "false" : "true");
|
|
4748
|
+
handleInput();
|
|
4749
|
+
};
|
|
4750
|
+
const toggleHighlight = () => {
|
|
4751
|
+
const sel = window.getSelection();
|
|
4752
|
+
if (!sel || sel.rangeCount === 0 || sel.isCollapsed) return;
|
|
4753
|
+
pushHistory(true);
|
|
4754
|
+
const range = sel.getRangeAt(0);
|
|
4755
|
+
const node = sel.anchorNode;
|
|
4756
|
+
const el = node?.nodeType === Node.ELEMENT_NODE ? node : node?.parentElement;
|
|
4757
|
+
const existing = el?.closest("mark");
|
|
4758
|
+
if (existing) {
|
|
4759
|
+
const parent = existing.parentNode;
|
|
4760
|
+
while (existing.firstChild) parent?.insertBefore(existing.firstChild, existing);
|
|
4761
|
+
parent?.removeChild(existing);
|
|
4762
|
+
handleInput();
|
|
4763
|
+
return;
|
|
4764
|
+
}
|
|
4765
|
+
const mark = document.createElement("mark");
|
|
4766
|
+
try {
|
|
4767
|
+
range.surroundContents(mark);
|
|
4768
|
+
} catch {
|
|
4769
|
+
const frag = range.extractContents();
|
|
4770
|
+
mark.appendChild(frag);
|
|
4771
|
+
range.insertNode(mark);
|
|
4772
|
+
}
|
|
4773
|
+
handleInput();
|
|
4774
|
+
};
|
|
4775
|
+
const insertTable = (cols = 3, rows = 2) => {
|
|
4776
|
+
const sel = window.getSelection();
|
|
4777
|
+
if (!sel || sel.rangeCount === 0) return;
|
|
4778
|
+
pushHistory(true);
|
|
4779
|
+
const table = document.createElement("table");
|
|
4780
|
+
const thead = document.createElement("thead");
|
|
4781
|
+
const headRow = document.createElement("tr");
|
|
4782
|
+
for (let c = 0; c < cols; c++) {
|
|
4783
|
+
const th = document.createElement("th");
|
|
4784
|
+
th.innerHTML = "<br>";
|
|
4785
|
+
headRow.appendChild(th);
|
|
4786
|
+
}
|
|
4787
|
+
thead.appendChild(headRow);
|
|
4788
|
+
table.appendChild(thead);
|
|
4789
|
+
const tbody = document.createElement("tbody");
|
|
4790
|
+
for (let r2 = 0; r2 < rows; r2++) {
|
|
4791
|
+
const tr = document.createElement("tr");
|
|
4792
|
+
for (let c = 0; c < cols; c++) {
|
|
4793
|
+
const td = document.createElement("td");
|
|
4794
|
+
td.innerHTML = "<br>";
|
|
4795
|
+
tr.appendChild(td);
|
|
4796
|
+
}
|
|
4797
|
+
tbody.appendChild(tr);
|
|
4798
|
+
}
|
|
4799
|
+
table.appendChild(tbody);
|
|
4800
|
+
const range = sel.getRangeAt(0);
|
|
4801
|
+
range.deleteContents();
|
|
4802
|
+
range.insertNode(table);
|
|
4803
|
+
ensureParagraphAfter(table);
|
|
4804
|
+
const first = table.querySelector("th");
|
|
4805
|
+
if (first) placeCaretAtEnd(first);
|
|
4806
|
+
handleInput();
|
|
4807
|
+
};
|
|
4808
|
+
const moveTableCell = (backwards) => {
|
|
4809
|
+
const block = currentBlock();
|
|
4810
|
+
const cell = block?.closest("td, th");
|
|
4811
|
+
if (!cell) return false;
|
|
4812
|
+
const table = cell.closest("table");
|
|
4813
|
+
if (!table) return false;
|
|
4814
|
+
const cells = Array.from(table.querySelectorAll("td, th"));
|
|
4815
|
+
const i = cells.indexOf(cell);
|
|
4816
|
+
const next = cells[i + (backwards ? -1 : 1)];
|
|
4817
|
+
if (next) {
|
|
4818
|
+
placeCaretAtEnd(next);
|
|
4819
|
+
return true;
|
|
4820
|
+
}
|
|
4821
|
+
if (!backwards) {
|
|
4822
|
+
pushHistory(true);
|
|
4823
|
+
const lastRow = table.querySelector("tbody")?.lastElementChild;
|
|
4824
|
+
if (lastRow) {
|
|
4825
|
+
const tr = document.createElement("tr");
|
|
4826
|
+
for (let c = 0; c < lastRow.children.length; c++) {
|
|
4827
|
+
const td = document.createElement("td");
|
|
4828
|
+
td.innerHTML = "<br>";
|
|
4829
|
+
tr.appendChild(td);
|
|
4830
|
+
}
|
|
4831
|
+
lastRow.after(tr);
|
|
4832
|
+
placeCaretAtEnd(tr.firstElementChild);
|
|
4833
|
+
handleInput();
|
|
4834
|
+
return true;
|
|
4835
|
+
}
|
|
4836
|
+
}
|
|
4837
|
+
return false;
|
|
4838
|
+
};
|
|
4387
4839
|
const insertDivider = () => {
|
|
4840
|
+
pushHistory(true);
|
|
4388
4841
|
exec("insertHorizontalRule");
|
|
4389
4842
|
const el = editorRef.current;
|
|
4390
4843
|
if (el && el.lastElementChild?.tagName === "HR") {
|
|
@@ -4477,8 +4930,14 @@ var Editor = (props) => {
|
|
|
4477
4930
|
case "paragraph":
|
|
4478
4931
|
setBlock("p");
|
|
4479
4932
|
break;
|
|
4480
|
-
case "heading":
|
|
4481
|
-
|
|
4933
|
+
case "heading-1":
|
|
4934
|
+
toggleBlock("h1");
|
|
4935
|
+
break;
|
|
4936
|
+
case "heading-2":
|
|
4937
|
+
toggleBlock("h2");
|
|
4938
|
+
break;
|
|
4939
|
+
case "heading-3":
|
|
4940
|
+
toggleBlock("h3");
|
|
4482
4941
|
break;
|
|
4483
4942
|
case "list":
|
|
4484
4943
|
exec("insertUnorderedList");
|
|
@@ -4571,6 +5030,8 @@ var Editor = (props) => {
|
|
|
4571
5030
|
if (!el) return;
|
|
4572
5031
|
const html = el.innerHTML;
|
|
4573
5032
|
lastEmittedRef.current = html;
|
|
5033
|
+
pushHistory();
|
|
5034
|
+
scheduleHighlight();
|
|
4574
5035
|
onChange?.(html);
|
|
4575
5036
|
updateEmpty();
|
|
4576
5037
|
updateActiveFormats();
|
|
@@ -4624,6 +5085,15 @@ var Editor = (props) => {
|
|
|
4624
5085
|
return;
|
|
4625
5086
|
}
|
|
4626
5087
|
}
|
|
5088
|
+
if (e.key === "Tab" && moveTableCell(e.shiftKey)) {
|
|
5089
|
+
e.preventDefault();
|
|
5090
|
+
return;
|
|
5091
|
+
}
|
|
5092
|
+
if (e.key === "Tab" && inListItem()) {
|
|
5093
|
+
e.preventDefault();
|
|
5094
|
+
indentList(e.shiftKey);
|
|
5095
|
+
return;
|
|
5096
|
+
}
|
|
4627
5097
|
if (slashOpen) {
|
|
4628
5098
|
if (e.key === "ArrowDown") {
|
|
4629
5099
|
e.preventDefault();
|
|
@@ -4647,6 +5117,21 @@ var Editor = (props) => {
|
|
|
4647
5117
|
return;
|
|
4648
5118
|
}
|
|
4649
5119
|
}
|
|
5120
|
+
if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === "z") {
|
|
5121
|
+
e.preventDefault();
|
|
5122
|
+
if (e.shiftKey) redo();
|
|
5123
|
+
else undo();
|
|
5124
|
+
return;
|
|
5125
|
+
}
|
|
5126
|
+
if ((e.metaKey || e.ctrlKey) && e.shiftKey && e.key.toLowerCase() === "v") {
|
|
5127
|
+
plainPasteRef.current = true;
|
|
5128
|
+
return;
|
|
5129
|
+
}
|
|
5130
|
+
if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === "y") {
|
|
5131
|
+
e.preventDefault();
|
|
5132
|
+
redo();
|
|
5133
|
+
return;
|
|
5134
|
+
}
|
|
4650
5135
|
if ((e.metaKey || e.ctrlKey) && !e.shiftKey && !e.altKey) {
|
|
4651
5136
|
const k = e.key.toLowerCase();
|
|
4652
5137
|
if (k === "b") {
|
|
@@ -4680,10 +5165,16 @@ var Editor = (props) => {
|
|
|
4680
5165
|
}
|
|
4681
5166
|
}
|
|
4682
5167
|
};
|
|
5168
|
+
const plainPasteRef = import_react22.default.useRef(false);
|
|
4683
5169
|
const handlePaste = (e) => {
|
|
4684
5170
|
if (readOnly) return;
|
|
4685
5171
|
e.preventDefault();
|
|
4686
5172
|
const text = e.clipboardData.getData("text/plain");
|
|
5173
|
+
if (plainPasteRef.current) {
|
|
5174
|
+
plainPasteRef.current = false;
|
|
5175
|
+
insertTextAtCaret(text);
|
|
5176
|
+
return;
|
|
5177
|
+
}
|
|
4687
5178
|
if (closestPre()) {
|
|
4688
5179
|
insertTextAtCaret(text);
|
|
4689
5180
|
return;
|
|
@@ -4710,9 +5201,11 @@ var Editor = (props) => {
|
|
|
4710
5201
|
};
|
|
4711
5202
|
const handleSelectionUpdate = () => {
|
|
4712
5203
|
updateActiveFormats();
|
|
5204
|
+
const pre = closestPre();
|
|
5205
|
+
setCodeLang(pre ? langOf(pre) : "plain");
|
|
4713
5206
|
};
|
|
4714
5207
|
const onToolbarAction = (item) => {
|
|
4715
|
-
if (closestPre() &&
|
|
5208
|
+
if (closestPre() && !["code-block", "undo", "redo"].includes(item)) return;
|
|
4716
5209
|
switch (item) {
|
|
4717
5210
|
case "bold":
|
|
4718
5211
|
exec("bold");
|
|
@@ -4741,8 +5234,14 @@ var Editor = (props) => {
|
|
|
4741
5234
|
handleInput();
|
|
4742
5235
|
break;
|
|
4743
5236
|
}
|
|
4744
|
-
case "heading":
|
|
4745
|
-
|
|
5237
|
+
case "heading-1":
|
|
5238
|
+
toggleBlock("h1");
|
|
5239
|
+
break;
|
|
5240
|
+
case "heading-2":
|
|
5241
|
+
toggleBlock("h2");
|
|
5242
|
+
break;
|
|
5243
|
+
case "heading-3":
|
|
5244
|
+
toggleBlock("h3");
|
|
4746
5245
|
break;
|
|
4747
5246
|
case "list":
|
|
4748
5247
|
exec("insertUnorderedList");
|
|
@@ -4765,6 +5264,39 @@ var Editor = (props) => {
|
|
|
4765
5264
|
case "divider":
|
|
4766
5265
|
insertDivider();
|
|
4767
5266
|
break;
|
|
5267
|
+
case "checklist":
|
|
5268
|
+
toggleChecklist();
|
|
5269
|
+
break;
|
|
5270
|
+
case "align-left":
|
|
5271
|
+
setAlign("left");
|
|
5272
|
+
break;
|
|
5273
|
+
case "align-center":
|
|
5274
|
+
setAlign("center");
|
|
5275
|
+
break;
|
|
5276
|
+
case "align-right":
|
|
5277
|
+
setAlign("right");
|
|
5278
|
+
break;
|
|
5279
|
+
case "highlight":
|
|
5280
|
+
toggleHighlight();
|
|
5281
|
+
break;
|
|
5282
|
+
case "superscript":
|
|
5283
|
+
exec("superscript");
|
|
5284
|
+
break;
|
|
5285
|
+
case "subscript":
|
|
5286
|
+
exec("subscript");
|
|
5287
|
+
break;
|
|
5288
|
+
case "table":
|
|
5289
|
+
insertTable();
|
|
5290
|
+
break;
|
|
5291
|
+
case "clear-format":
|
|
5292
|
+
clearFormat();
|
|
5293
|
+
break;
|
|
5294
|
+
case "undo":
|
|
5295
|
+
undo();
|
|
5296
|
+
break;
|
|
5297
|
+
case "redo":
|
|
5298
|
+
redo();
|
|
5299
|
+
break;
|
|
4768
5300
|
}
|
|
4769
5301
|
};
|
|
4770
5302
|
return /* @__PURE__ */ (0, import_jsx_runtime323.jsxs)("div", { className: clsx_default("lib-xplat-editor", isFocused && "focused", readOnly && "readonly"), children: [
|
|
@@ -4773,7 +5305,10 @@ var Editor = (props) => {
|
|
|
4773
5305
|
{
|
|
4774
5306
|
items: toolbar,
|
|
4775
5307
|
active: activeFormats,
|
|
4776
|
-
onAction: onToolbarAction
|
|
5308
|
+
onAction: onToolbarAction,
|
|
5309
|
+
codeLang,
|
|
5310
|
+
inCodeBlock: activeFormats.has("block:pre"),
|
|
5311
|
+
onCodeLangChange: changeCodeLang
|
|
4777
5312
|
}
|
|
4778
5313
|
),
|
|
4779
5314
|
/* @__PURE__ */ (0, import_jsx_runtime323.jsxs)("div", { className: "lib-xplat-editor__content", style: { minHeight }, children: [
|
|
@@ -4791,6 +5326,7 @@ var Editor = (props) => {
|
|
|
4791
5326
|
className: "lib-xplat-editor__editable",
|
|
4792
5327
|
onInput: handleInput,
|
|
4793
5328
|
onKeyDown: handleKeyDown,
|
|
5329
|
+
onClick: handleEditorClick,
|
|
4794
5330
|
onKeyUp: handleSelectionUpdate,
|
|
4795
5331
|
onMouseUp: handleSelectionUpdate,
|
|
4796
5332
|
onPaste: handlePaste,
|
|
@@ -4832,14 +5368,27 @@ var TOOLBAR_LABEL = {
|
|
|
4832
5368
|
underline: "U",
|
|
4833
5369
|
strikethrough: "S",
|
|
4834
5370
|
code: "<>",
|
|
4835
|
-
heading: "
|
|
5371
|
+
"heading-1": "H1",
|
|
5372
|
+
"heading-2": "H2",
|
|
5373
|
+
"heading-3": "H3",
|
|
4836
5374
|
list: "\u2022",
|
|
4837
5375
|
"ordered-list": "1.",
|
|
4838
5376
|
blockquote: "\u275D",
|
|
4839
5377
|
"code-block": "[ ]",
|
|
4840
5378
|
link: "\u{1F517}",
|
|
4841
5379
|
image: "\u{1F5BC}",
|
|
4842
|
-
divider: "\u2014"
|
|
5380
|
+
divider: "\u2014",
|
|
5381
|
+
checklist: "\u2611",
|
|
5382
|
+
"align-left": "\u21E4",
|
|
5383
|
+
"align-center": "\u2194",
|
|
5384
|
+
"align-right": "\u21E5",
|
|
5385
|
+
highlight: "\u{1F58D}",
|
|
5386
|
+
superscript: "x\xB2",
|
|
5387
|
+
subscript: "x\u2082",
|
|
5388
|
+
table: "\u25A6",
|
|
5389
|
+
"clear-format": "\u232B",
|
|
5390
|
+
undo: "\u21B6",
|
|
5391
|
+
redo: "\u21B7"
|
|
4843
5392
|
};
|
|
4844
5393
|
var TOOLBAR_TITLE = {
|
|
4845
5394
|
bold: "\uAD75\uAC8C (\u2318B)",
|
|
@@ -4847,36 +5396,74 @@ var TOOLBAR_TITLE = {
|
|
|
4847
5396
|
underline: "\uBC11\uC904 (\u2318U)",
|
|
4848
5397
|
strikethrough: "\uCDE8\uC18C\uC120",
|
|
4849
5398
|
code: "\uC778\uB77C\uC778 \uCF54\uB4DC",
|
|
4850
|
-
heading: "\uC81C\uBAA9",
|
|
5399
|
+
"heading-1": "\uC81C\uBAA9 1",
|
|
5400
|
+
"heading-2": "\uC81C\uBAA9 2",
|
|
5401
|
+
"heading-3": "\uC81C\uBAA9 3",
|
|
4851
5402
|
list: "\uAE00\uBA38\uB9AC \uAE30\uD638 \uBAA9\uB85D",
|
|
4852
5403
|
"ordered-list": "\uBC88\uD638 \uB9E4\uAE30\uAE30 \uBAA9\uB85D",
|
|
4853
5404
|
blockquote: "\uC778\uC6A9",
|
|
4854
5405
|
"code-block": "\uCF54\uB4DC \uBE14\uB85D",
|
|
4855
5406
|
link: "\uB9C1\uD06C (\u2318K)",
|
|
4856
5407
|
image: "\uC774\uBBF8\uC9C0",
|
|
4857
|
-
divider: "\uAD6C\uBD84\uC120"
|
|
5408
|
+
divider: "\uAD6C\uBD84\uC120",
|
|
5409
|
+
checklist: "\uCCB4\uD06C\uB9AC\uC2A4\uD2B8",
|
|
5410
|
+
"align-left": "\uC67C\uCABD \uC815\uB82C",
|
|
5411
|
+
"align-center": "\uAC00\uC6B4\uB370 \uC815\uB82C",
|
|
5412
|
+
"align-right": "\uC624\uB978\uCABD \uC815\uB82C",
|
|
5413
|
+
highlight: "\uD615\uAD11\uD39C",
|
|
5414
|
+
superscript: "\uC704 \uCCA8\uC790",
|
|
5415
|
+
subscript: "\uC544\uB798 \uCCA8\uC790",
|
|
5416
|
+
table: "\uD45C \uC0BD\uC785",
|
|
5417
|
+
"clear-format": "\uC11C\uC2DD \uC9C0\uC6B0\uAE30",
|
|
5418
|
+
undo: "\uB418\uB3CC\uB9AC\uAE30 (\u2318Z)",
|
|
5419
|
+
redo: "\uB2E4\uC2DC\uD558\uAE30 (\u2318\u21E7Z)"
|
|
4858
5420
|
};
|
|
4859
5421
|
var isActive = (item, active) => {
|
|
4860
|
-
if (item === "heading") return active.has("block:h1")
|
|
5422
|
+
if (item === "heading-1") return active.has("block:h1");
|
|
5423
|
+
if (item === "heading-2") return active.has("block:h2");
|
|
5424
|
+
if (item === "heading-3") return active.has("block:h3");
|
|
4861
5425
|
if (item === "blockquote") return active.has("block:blockquote");
|
|
4862
5426
|
if (item === "code-block") return active.has("block:pre");
|
|
5427
|
+
if (item === "align-left") return active.has("align:left");
|
|
5428
|
+
if (item === "align-center") return active.has("align:center");
|
|
5429
|
+
if (item === "align-right") return active.has("align:right");
|
|
4863
5430
|
return active.has(item);
|
|
4864
5431
|
};
|
|
4865
|
-
var EditorToolbar = ({
|
|
4866
|
-
|
|
4867
|
-
|
|
4868
|
-
|
|
4869
|
-
|
|
4870
|
-
|
|
4871
|
-
|
|
4872
|
-
|
|
4873
|
-
|
|
4874
|
-
|
|
5432
|
+
var EditorToolbar = ({
|
|
5433
|
+
items,
|
|
5434
|
+
active,
|
|
5435
|
+
onAction,
|
|
5436
|
+
codeLang,
|
|
5437
|
+
inCodeBlock,
|
|
5438
|
+
onCodeLangChange
|
|
5439
|
+
}) => {
|
|
5440
|
+
return /* @__PURE__ */ (0, import_jsx_runtime323.jsxs)("div", { className: "lib-xplat-editor__toolbar", children: [
|
|
5441
|
+
items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime323.jsx)(
|
|
5442
|
+
"button",
|
|
5443
|
+
{
|
|
5444
|
+
type: "button",
|
|
5445
|
+
className: clsx_default("lib-xplat-editor__toolbar-btn", isActive(item, active) && "active"),
|
|
5446
|
+
title: TOOLBAR_TITLE[item],
|
|
5447
|
+
onMouseDown: (e) => {
|
|
5448
|
+
e.preventDefault();
|
|
5449
|
+
onAction(item);
|
|
5450
|
+
},
|
|
5451
|
+
children: TOOLBAR_LABEL[item]
|
|
4875
5452
|
},
|
|
4876
|
-
|
|
4877
|
-
|
|
4878
|
-
|
|
4879
|
-
|
|
5453
|
+
item
|
|
5454
|
+
)),
|
|
5455
|
+
inCodeBlock && /* @__PURE__ */ (0, import_jsx_runtime323.jsx)(
|
|
5456
|
+
"select",
|
|
5457
|
+
{
|
|
5458
|
+
className: "lib-xplat-editor__lang",
|
|
5459
|
+
value: codeLang,
|
|
5460
|
+
"aria-label": "\uCF54\uB4DC \uC5B8\uC5B4",
|
|
5461
|
+
onMouseDown: (e) => e.stopPropagation(),
|
|
5462
|
+
onChange: (e) => onCodeLangChange(e.target.value),
|
|
5463
|
+
children: CODE_LANGUAGES.map((l) => /* @__PURE__ */ (0, import_jsx_runtime323.jsx)("option", { value: l.value, children: l.label }, l.value))
|
|
5464
|
+
}
|
|
5465
|
+
)
|
|
5466
|
+
] });
|
|
4880
5467
|
};
|
|
4881
5468
|
var SlashMenu = ({ position, items, activeIndex, onSelect, onClose }) => {
|
|
4882
5469
|
import_react22.default.useEffect(() => {
|
|
@@ -5421,6 +6008,7 @@ var PopOver = (props) => {
|
|
|
5421
6008
|
className: clsx_default(
|
|
5422
6009
|
"lib-xplat-pop-over-content",
|
|
5423
6010
|
position.direction,
|
|
6011
|
+
position.repositioning && "repositioning",
|
|
5424
6012
|
eventTrigger && "visible"
|
|
5425
6013
|
),
|
|
5426
6014
|
ref: popRef,
|
|
@@ -5767,7 +6355,7 @@ var SelectRoot = (props) => {
|
|
|
5767
6355
|
mounted && /* @__PURE__ */ (0, import_jsx_runtime337.jsx)(Portal_default, { children: /* @__PURE__ */ (0, import_jsx_runtime337.jsxs)(
|
|
5768
6356
|
"div",
|
|
5769
6357
|
{
|
|
5770
|
-
className: clsx_default("lib-xplat-select-content", size, position.direction, stateClass),
|
|
6358
|
+
className: clsx_default("lib-xplat-select-content", size, position.direction, stateClass, position.repositioning && "repositioning"),
|
|
5771
6359
|
ref: contentRef,
|
|
5772
6360
|
style: { ...position.position, width: triggerRef.current?.offsetWidth },
|
|
5773
6361
|
role: "listbox",
|
|
@@ -6660,7 +7248,7 @@ var TimePicker = (props) => {
|
|
|
6660
7248
|
"div",
|
|
6661
7249
|
{
|
|
6662
7250
|
ref: contentRef,
|
|
6663
|
-
className: clsx_default("lib-xplat-time-picker-content", size, visible ? "enter" : "exit"),
|
|
7251
|
+
className: clsx_default("lib-xplat-time-picker-content", size, visible ? "enter" : "exit", position.repositioning && "repositioning"),
|
|
6664
7252
|
style: { ...position.position, width: triggerRef.current?.offsetWidth },
|
|
6665
7253
|
role: "listbox",
|
|
6666
7254
|
children: options.map((t) => /* @__PURE__ */ (0, import_jsx_runtime351.jsx)(
|