smartrte-react 0.3.0 → 0.3.1
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/CHANGELOG.md +5 -0
- package/dist/components/ClassicEditor.js +106 -44
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.3.1
|
|
4
|
+
|
|
5
|
+
- Make caret-based superscript and subscript toggling deterministic in controlled React applications.
|
|
6
|
+
- Preserve normal text before and after script spans and prevent nested superscript/subscript markup.
|
|
7
|
+
|
|
3
8
|
## 0.3.0
|
|
4
9
|
|
|
5
10
|
- Rebuild list selection and conversion behavior for checklists, bullets, numbers, alphabetic lists, and Roman numerals.
|
|
@@ -254,12 +254,8 @@ export function ClassicEditor({ value, onChange, placeholder = "Type here…", m
|
|
|
254
254
|
italic: queryState("italic"),
|
|
255
255
|
underline: queryState("underline"),
|
|
256
256
|
strikeThrough: queryState("strikeThrough"),
|
|
257
|
-
subscript: overrideApplies
|
|
258
|
-
|
|
259
|
-
: subscriptActive,
|
|
260
|
-
superscript: overrideApplies && scriptOverride?.command === "superscript"
|
|
261
|
-
? false
|
|
262
|
-
: superscriptActive,
|
|
257
|
+
subscript: overrideApplies ? scriptOverride?.command === "subscript" : subscriptActive,
|
|
258
|
+
superscript: overrideApplies ? scriptOverride?.command === "superscript" : superscriptActive,
|
|
263
259
|
checklist: Boolean(element?.closest('[data-srte-checklist="true"]')),
|
|
264
260
|
unorderedList: Boolean(element?.closest("ul:not([data-srte-checklist=\"true\"])")),
|
|
265
261
|
orderedList: Boolean(element?.closest("ol")),
|
|
@@ -398,55 +394,121 @@ export function ClassicEditor({ value, onChange, placeholder = "Type here…", m
|
|
|
398
394
|
const range = getSelectionRangeInEditor();
|
|
399
395
|
if (!editor || !range)
|
|
400
396
|
return;
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
? {
|
|
411
|
-
command,
|
|
412
|
-
container: currentRange.startContainer,
|
|
413
|
-
offset: currentRange.startOffset,
|
|
414
|
-
}
|
|
415
|
-
: null;
|
|
416
|
-
setActiveState((current) => ({
|
|
417
|
-
...current,
|
|
418
|
-
subscript: command === "subscript" ? false : current.subscript,
|
|
419
|
-
superscript: command === "superscript" ? false : current.superscript,
|
|
420
|
-
}));
|
|
421
|
-
handleInput();
|
|
422
|
-
requestAnimationFrame(updateActiveState);
|
|
423
|
-
return;
|
|
424
|
-
}
|
|
425
|
-
if (script) {
|
|
426
|
-
const nextRange = document.createRange();
|
|
427
|
-
nextRange.setStartAfter(script);
|
|
428
|
-
nextRange.collapse(true);
|
|
429
|
-
safeSelectRange(nextRange);
|
|
430
|
-
savedRangeRef.current = nextRange.cloneRange();
|
|
397
|
+
if (range.collapsed) {
|
|
398
|
+
const tagName = command === "subscript" ? "sub" : "sup";
|
|
399
|
+
const pending = inlineScriptCaretOverrideRef.current;
|
|
400
|
+
const pendingApplies = pending &&
|
|
401
|
+
pending.container === range.startContainer && pending.offset === range.startOffset;
|
|
402
|
+
const active = pendingApplies
|
|
403
|
+
? pending.command === command
|
|
404
|
+
: Boolean(getScriptAncestor(range.startContainer, tagName));
|
|
405
|
+
const nextCommand = active ? "normal" : command;
|
|
431
406
|
inlineScriptCaretOverrideRef.current = {
|
|
432
|
-
command,
|
|
433
|
-
container:
|
|
434
|
-
offset:
|
|
407
|
+
command: nextCommand,
|
|
408
|
+
container: range.startContainer,
|
|
409
|
+
offset: range.startOffset,
|
|
435
410
|
};
|
|
436
411
|
setActiveState((current) => ({
|
|
437
412
|
...current,
|
|
438
|
-
subscript:
|
|
439
|
-
superscript:
|
|
413
|
+
subscript: nextCommand === "subscript",
|
|
414
|
+
superscript: nextCommand === "superscript",
|
|
440
415
|
}));
|
|
441
|
-
|
|
416
|
+
savedRangeRef.current = range.cloneRange();
|
|
442
417
|
return;
|
|
443
418
|
}
|
|
444
419
|
inlineScriptCaretOverrideRef.current = null;
|
|
445
|
-
|
|
420
|
+
pushEditorHistory();
|
|
421
|
+
const result = getCoreInlineMarkResult(editor, command);
|
|
422
|
+
if (result) {
|
|
423
|
+
editor.innerHTML = result.html;
|
|
424
|
+
ensureTableWrappers(editor);
|
|
425
|
+
addTableResizeHandles();
|
|
426
|
+
restoreSelectionToDom(editor, result.selectionAfter);
|
|
427
|
+
handleInput();
|
|
428
|
+
}
|
|
429
|
+
else {
|
|
430
|
+
exec(command);
|
|
431
|
+
}
|
|
446
432
|
requestAnimationFrame(updateActiveState);
|
|
447
433
|
}
|
|
448
434
|
catch { }
|
|
449
435
|
};
|
|
436
|
+
useEffect(() => {
|
|
437
|
+
const editor = editableRef.current;
|
|
438
|
+
if (!editor)
|
|
439
|
+
return;
|
|
440
|
+
const splitScriptAtRange = (script, range) => {
|
|
441
|
+
const rightRange = document.createRange();
|
|
442
|
+
rightRange.selectNodeContents(script);
|
|
443
|
+
rightRange.setStart(range.startContainer, range.startOffset);
|
|
444
|
+
const rightContent = rightRange.extractContents();
|
|
445
|
+
const rightScript = script.cloneNode(false);
|
|
446
|
+
rightScript.appendChild(rightContent);
|
|
447
|
+
script.parentNode?.insertBefore(rightScript, script.nextSibling);
|
|
448
|
+
const insertion = document.createRange();
|
|
449
|
+
insertion.setStartAfter(script);
|
|
450
|
+
insertion.collapse(true);
|
|
451
|
+
if (!script.textContent)
|
|
452
|
+
script.remove();
|
|
453
|
+
if (!rightScript.textContent)
|
|
454
|
+
rightScript.remove();
|
|
455
|
+
return insertion;
|
|
456
|
+
};
|
|
457
|
+
const applyPendingInlineScript = (event) => {
|
|
458
|
+
const pending = inlineScriptCaretOverrideRef.current;
|
|
459
|
+
if (!pending || event.inputType !== "insertText" || !event.data)
|
|
460
|
+
return;
|
|
461
|
+
const range = getSelectionRangeInEditor();
|
|
462
|
+
if (!range?.collapsed || range.startContainer !== pending.container || range.startOffset !== pending.offset)
|
|
463
|
+
return;
|
|
464
|
+
event.preventDefault();
|
|
465
|
+
event.stopImmediatePropagation();
|
|
466
|
+
pushEditorHistory();
|
|
467
|
+
const currentScript = getScriptAncestor(range.startContainer, "sub") ||
|
|
468
|
+
getScriptAncestor(range.startContainer, "sup");
|
|
469
|
+
const desiredTag = pending.command === "normal"
|
|
470
|
+
? null
|
|
471
|
+
: pending.command === "subscript" ? "sub" : "sup";
|
|
472
|
+
let insertion = range;
|
|
473
|
+
if (currentScript && currentScript.tagName.toLowerCase() !== desiredTag) {
|
|
474
|
+
insertion = splitScriptAtRange(currentScript, range);
|
|
475
|
+
}
|
|
476
|
+
const text = document.createTextNode(event.data);
|
|
477
|
+
let inserted = text;
|
|
478
|
+
if (desiredTag && currentScript?.tagName.toLowerCase() !== desiredTag) {
|
|
479
|
+
const script = document.createElement(desiredTag);
|
|
480
|
+
script.appendChild(text);
|
|
481
|
+
inserted = script;
|
|
482
|
+
}
|
|
483
|
+
const pendingSize = pendingFontSizeRef.current;
|
|
484
|
+
if (pendingSize) {
|
|
485
|
+
const span = document.createElement("span");
|
|
486
|
+
span.style.fontSize = `${pendingSize.valuePx}px`;
|
|
487
|
+
span.appendChild(inserted);
|
|
488
|
+
inserted = span;
|
|
489
|
+
}
|
|
490
|
+
insertion.insertNode(inserted);
|
|
491
|
+
const nextRange = document.createRange();
|
|
492
|
+
nextRange.setStartAfter(text);
|
|
493
|
+
nextRange.collapse(true);
|
|
494
|
+
safeSelectRange(nextRange);
|
|
495
|
+
inlineScriptCaretOverrideRef.current = {
|
|
496
|
+
command: pending.command,
|
|
497
|
+
container: nextRange.startContainer,
|
|
498
|
+
offset: nextRange.startOffset,
|
|
499
|
+
};
|
|
500
|
+
if (pendingSize)
|
|
501
|
+
pendingFontSizeRef.current = {
|
|
502
|
+
valuePx: pendingSize.valuePx,
|
|
503
|
+
container: nextRange.startContainer,
|
|
504
|
+
offset: nextRange.startOffset,
|
|
505
|
+
};
|
|
506
|
+
savedRangeRef.current = nextRange.cloneRange();
|
|
507
|
+
handleInput();
|
|
508
|
+
};
|
|
509
|
+
editor.addEventListener("beforeinput", applyPendingInlineScript);
|
|
510
|
+
return () => editor.removeEventListener("beforeinput", applyPendingInlineScript);
|
|
511
|
+
}, []);
|
|
450
512
|
const applyFormatBlock = (blockName) => {
|
|
451
513
|
try {
|
|
452
514
|
if (!restoreSavedSelection()) {
|
|
@@ -4967,7 +5029,7 @@ export function ClassicEditor({ value, onChange, placeholder = "Type here…", m
|
|
|
4967
5029
|
borderRadius: 6,
|
|
4968
5030
|
background: "var(--srte-input-bg)",
|
|
4969
5031
|
color: "var(--srte-input-text)",
|
|
4970
|
-
}, children: _jsx("span", { style: { fontWeight: 700, padding: "1px 4px", background: "var(--srte-accent-bg)", borderRadius: 3 }, children: "A" }) }), _jsxs("button", { title: "Subscript", onClick: () => toggleInlineScript("subscript"), "aria-pressed": activeState.subscript, style: activeButtonStyle(activeState.subscript), children: ["X", _jsx("sub", { children: "2" })] }), _jsxs("button", { title: "Superscript", onClick: () => toggleInlineScript("superscript"), "aria-pressed": activeState.superscript, style: activeButtonStyle(activeState.superscript), children: ["X", _jsx("sup", { children: "2" })] }), [
|
|
5032
|
+
}, children: _jsx("span", { style: { fontWeight: 700, padding: "1px 4px", background: "var(--srte-accent-bg)", borderRadius: 3 }, children: "A" }) }), _jsxs("button", { title: "Subscript", onMouseDown: preserveEditorSelection, onClick: () => toggleInlineScript("subscript"), "aria-pressed": activeState.subscript, style: activeButtonStyle(activeState.subscript), children: ["X", _jsx("sub", { children: "2" })] }), _jsxs("button", { title: "Superscript", onMouseDown: preserveEditorSelection, onClick: () => toggleInlineScript("superscript"), "aria-pressed": activeState.superscript, style: activeButtonStyle(activeState.superscript), children: ["X", _jsx("sup", { children: "2" })] }), [
|
|
4971
5033
|
{
|
|
4972
5034
|
key: "check",
|
|
4973
5035
|
label: "☐",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "smartrte-react",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"description": "A powerful, feature-rich Rich Text Editor for React with support for tables, mathematical formulas (LaTeX/KaTeX), and media management",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -79,6 +79,6 @@
|
|
|
79
79
|
"jszip": "^3.10.1",
|
|
80
80
|
"mammoth": "^1.11.0",
|
|
81
81
|
"pdfjs-dist": "^5.4.530",
|
|
82
|
-
"smartrte-core": "^0.2.
|
|
82
|
+
"smartrte-core": "^0.2.1"
|
|
83
83
|
}
|
|
84
84
|
}
|