@haklex/rich-editor 0.0.42 → 0.0.43
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.
|
@@ -26,6 +26,7 @@ import { ListNode, ListItemNode } from "@lexical/list";
|
|
|
26
26
|
import { HeadingNode, QuoteNode, $isQuoteNode, DRAG_DROP_PASTE, $createQuoteNode } from "@lexical/rich-text";
|
|
27
27
|
import { TableNode, TableCellNode, TableRowNode } from "@lexical/table";
|
|
28
28
|
import { useLexicalNodeSelection } from "@lexical/react/useLexicalNodeSelection";
|
|
29
|
+
import { nanoid } from "nanoid";
|
|
29
30
|
import { Dialog, DialogPopup, DialogTitle, SegmentedControl } from "@haklex/rich-editor-ui";
|
|
30
31
|
import { b as clsx, g as getVariantClass } from "./utils-fpeaZV1R.js";
|
|
31
32
|
import { MarkdownShortcutPlugin } from "@lexical/react/LexicalMarkdownShortcutPlugin";
|
|
@@ -1330,42 +1331,104 @@ const blockIdState = createState("blockId", {
|
|
|
1330
1331
|
parse: (v) => typeof v === "string" ? v : ""
|
|
1331
1332
|
});
|
|
1332
1333
|
const NORMALIZATION_TAG = "block-id-normalization";
|
|
1334
|
+
function buildPreviousIdIndex(editorState) {
|
|
1335
|
+
return editorState.read(() => {
|
|
1336
|
+
const map = /* @__PURE__ */ new Map();
|
|
1337
|
+
for (const child of $getRoot().getChildren()) {
|
|
1338
|
+
const id = $getState(child, blockIdState);
|
|
1339
|
+
if (!id) continue;
|
|
1340
|
+
const set = map.get(id) ?? /* @__PURE__ */ new Set();
|
|
1341
|
+
set.add(child.getKey());
|
|
1342
|
+
map.set(id, set);
|
|
1343
|
+
}
|
|
1344
|
+
return map;
|
|
1345
|
+
});
|
|
1346
|
+
}
|
|
1347
|
+
function collectRootChildren(editorState) {
|
|
1348
|
+
return editorState.read(
|
|
1349
|
+
() => $getRoot().getChildren().map((child) => $getState(child, blockIdState))
|
|
1350
|
+
);
|
|
1351
|
+
}
|
|
1352
|
+
function hasDuplicateOrMissingId(children) {
|
|
1353
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1354
|
+
for (const id of children) {
|
|
1355
|
+
if (!id || seen.has(id)) {
|
|
1356
|
+
return true;
|
|
1357
|
+
}
|
|
1358
|
+
seen.add(id);
|
|
1359
|
+
}
|
|
1360
|
+
return false;
|
|
1361
|
+
}
|
|
1362
|
+
function generateBlockId(used) {
|
|
1363
|
+
let id = "";
|
|
1364
|
+
do {
|
|
1365
|
+
id = nanoid(8);
|
|
1366
|
+
} while (used.has(id));
|
|
1367
|
+
return id;
|
|
1368
|
+
}
|
|
1369
|
+
function pickKeeperKey(nodes, previousKeys) {
|
|
1370
|
+
if (!nodes.length) return null;
|
|
1371
|
+
if (previousKeys?.size) {
|
|
1372
|
+
for (const node of nodes) {
|
|
1373
|
+
if (previousKeys.has(node.getKey())) {
|
|
1374
|
+
return node.getKey();
|
|
1375
|
+
}
|
|
1376
|
+
}
|
|
1377
|
+
}
|
|
1378
|
+
return nodes[0]?.getKey() ?? null;
|
|
1379
|
+
}
|
|
1380
|
+
function normalizeRootBlockIds(editor, previousIdIndex) {
|
|
1381
|
+
editor.update(
|
|
1382
|
+
() => {
|
|
1383
|
+
$addUpdateTag("history-merge");
|
|
1384
|
+
const children = $getRoot().getChildren();
|
|
1385
|
+
const groupedById = /* @__PURE__ */ new Map();
|
|
1386
|
+
for (const child of children) {
|
|
1387
|
+
const id = $getState(child, blockIdState);
|
|
1388
|
+
if (!id) continue;
|
|
1389
|
+
const bucket = groupedById.get(id) ?? [];
|
|
1390
|
+
bucket.push(child);
|
|
1391
|
+
groupedById.set(id, bucket);
|
|
1392
|
+
}
|
|
1393
|
+
const keeperById = /* @__PURE__ */ new Map();
|
|
1394
|
+
for (const [id, nodes] of groupedById) {
|
|
1395
|
+
if (nodes.length <= 1) continue;
|
|
1396
|
+
const keeperKey = pickKeeperKey(nodes, previousIdIndex.get(id));
|
|
1397
|
+
if (keeperKey) {
|
|
1398
|
+
keeperById.set(id, keeperKey);
|
|
1399
|
+
}
|
|
1400
|
+
}
|
|
1401
|
+
const used = /* @__PURE__ */ new Set();
|
|
1402
|
+
for (const child of children) {
|
|
1403
|
+
let id = $getState(child, blockIdState);
|
|
1404
|
+
const keeperKey = id ? keeperById.get(id) : null;
|
|
1405
|
+
const shouldRegenerate = !id || used.has(id) || keeperKey !== void 0 && child.getKey() !== keeperKey;
|
|
1406
|
+
if (shouldRegenerate) {
|
|
1407
|
+
id = generateBlockId(used);
|
|
1408
|
+
$setState(child, blockIdState, id);
|
|
1409
|
+
}
|
|
1410
|
+
used.add(id);
|
|
1411
|
+
}
|
|
1412
|
+
},
|
|
1413
|
+
{ tag: NORMALIZATION_TAG }
|
|
1414
|
+
);
|
|
1415
|
+
}
|
|
1333
1416
|
function BlockIdPlugin() {
|
|
1334
1417
|
const [editor] = useLexicalComposerContext();
|
|
1335
1418
|
useEffect(() => {
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
editor
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
}
|
|
1350
|
-
if (!needsUpdate) return;
|
|
1351
|
-
editor.update(
|
|
1352
|
-
() => {
|
|
1353
|
-
$addUpdateTag("history-merge");
|
|
1354
|
-
const children2 = $getRoot().getChildren();
|
|
1355
|
-
const seen2 = /* @__PURE__ */ new Set();
|
|
1356
|
-
for (const child of children2) {
|
|
1357
|
-
let id = $getState(child, blockIdState);
|
|
1358
|
-
if (id === "" || seen2.has(id)) {
|
|
1359
|
-
id = crypto.randomUUID();
|
|
1360
|
-
$setState(child, blockIdState, id);
|
|
1361
|
-
}
|
|
1362
|
-
seen2.add(id);
|
|
1363
|
-
}
|
|
1364
|
-
},
|
|
1365
|
-
{ tag: NORMALIZATION_TAG }
|
|
1366
|
-
);
|
|
1367
|
-
});
|
|
1368
|
-
});
|
|
1419
|
+
const initialChildren = collectRootChildren(editor.getEditorState());
|
|
1420
|
+
if (hasDuplicateOrMissingId(initialChildren)) {
|
|
1421
|
+
normalizeRootBlockIds(editor, /* @__PURE__ */ new Map());
|
|
1422
|
+
}
|
|
1423
|
+
return editor.registerUpdateListener(
|
|
1424
|
+
({ tags, editorState, prevEditorState }) => {
|
|
1425
|
+
if (tags.has(NORMALIZATION_TAG)) return;
|
|
1426
|
+
const children = collectRootChildren(editorState);
|
|
1427
|
+
if (!hasDuplicateOrMissingId(children)) return;
|
|
1428
|
+
const previousIdIndex = buildPreviousIdIndex(prevEditorState);
|
|
1429
|
+
normalizeRootBlockIds(editor, previousIdIndex);
|
|
1430
|
+
}
|
|
1431
|
+
);
|
|
1369
1432
|
}, [editor]);
|
|
1370
1433
|
return null;
|
|
1371
1434
|
}
|
|
@@ -2446,6 +2509,7 @@ function RichEditor({
|
|
|
2446
2509
|
className: clsx("rich-editor", variantClass, className),
|
|
2447
2510
|
style,
|
|
2448
2511
|
"data-theme": theme,
|
|
2512
|
+
suppressHydrationWarning: true,
|
|
2449
2513
|
children: [
|
|
2450
2514
|
/* @__PURE__ */ jsx(
|
|
2451
2515
|
RichTextPlugin,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RichEditor.d.ts","sourceRoot":"","sources":["../../src/components/RichEditor.tsx"],"names":[],"mappings":"AAmCA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,UAAU,CAAA;AAI/C,wBAAgB,UAAU,CAAC,EACzB,YAAY,EACZ,QAAQ,EACR,OAAmB,EACnB,KAAe,EACf,WAAkC,EAClC,QAAQ,EACR,SAAiB,EACjB,SAAS,EACT,gBAAgB,EAChB,KAAK,EACL,OAAO,EACP,aAAa,EACb,UAAU,EACV,cAAc,EACd,WAAW,EACX,UAAU,EACV,QAAQ,GACT,EAAE,eAAe,+
|
|
1
|
+
{"version":3,"file":"RichEditor.d.ts","sourceRoot":"","sources":["../../src/components/RichEditor.tsx"],"names":[],"mappings":"AAmCA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,UAAU,CAAA;AAI/C,wBAAgB,UAAU,CAAC,EACzB,YAAY,EACZ,QAAQ,EACR,OAAmB,EACnB,KAAe,EACf,WAAkC,EAClC,QAAQ,EACR,SAAiB,EACjB,SAAS,EACT,gBAAgB,EAChB,KAAK,EACL,OAAO,EACP,aAAa,EACb,UAAU,EACV,cAAc,EACd,WAAW,EACX,UAAU,EACV,QAAQ,GACT,EAAE,eAAe,+BA2EjB"}
|
package/dist/editor.mjs
CHANGED
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { b as blockIdState } from "./RichEditor-
|
|
2
|
-
import { A, F, d, I, e, f, h, i, N, R, a, c, j, g, s, u } from "./RichEditor-
|
|
1
|
+
import { b as blockIdState } from "./RichEditor-Cv399wxR.js";
|
|
2
|
+
import { A, F, d, I, e, f, h, i, N, R, a, c, j, g, s, u } from "./RichEditor-Cv399wxR.js";
|
|
3
3
|
import { h as useFootnoteContent, j as useFootnoteDisplayNumber } from "./theme-gVNBI_ET.js";
|
|
4
4
|
import { $, o, p, q, r, s as s2, t, v, w, x, y, z, A as A2, B, D, E, G, H, C, F as F2, I as I2, J, K, L, M, O, P, Q, S, T, U, N as N2, V, a as a2, b, W, e as e2, c as c2, X, f as f2, g as g2, u as u2, i as i2, k, l, m, n } from "./theme-gVNBI_ET.js";
|
|
5
5
|
import { a as a3, c as c3, g as g3, n as n2 } from "./utils-fpeaZV1R.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BlockIdPlugin.d.ts","sourceRoot":"","sources":["../../src/plugins/BlockIdPlugin.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"BlockIdPlugin.d.ts","sourceRoot":"","sources":["../../src/plugins/BlockIdPlugin.tsx"],"names":[],"mappings":"AAaA,eAAO,MAAM,YAAY,kDAEvB,CAAA;AA8GF,wBAAgB,aAAa,SAwB5B"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@haklex/rich-editor",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.43",
|
|
4
4
|
"description": "Core rich text editor based on Lexical",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -28,10 +28,11 @@
|
|
|
28
28
|
"dist"
|
|
29
29
|
],
|
|
30
30
|
"dependencies": {
|
|
31
|
+
"nanoid": "^5.1.6",
|
|
31
32
|
"thumbhash": "^0.1.1",
|
|
32
|
-
"@haklex/rich-editor-ui": "0.0.
|
|
33
|
-
"@haklex/rich-
|
|
34
|
-
"@haklex/rich-
|
|
33
|
+
"@haklex/rich-editor-ui": "0.0.43",
|
|
34
|
+
"@haklex/rich-style-token": "0.0.43",
|
|
35
|
+
"@haklex/rich-headless": "0.0.43"
|
|
35
36
|
},
|
|
36
37
|
"devDependencies": {
|
|
37
38
|
"@base-ui/react": "^1.2.0",
|