@mdaemon/html-editor 1.0.13 → 1.1.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/index.d.ts +9 -0
- package/dist/index.js +236 -21
- package/dist/index.mjs +236 -21
- package/dist/styles.css +108 -0
- package/package.json +19 -19
package/dist/index.d.ts
CHANGED
|
@@ -131,6 +131,8 @@ export declare interface EditorConfig {
|
|
|
131
131
|
toolbar?: string;
|
|
132
132
|
toolbar_mode?: 'sliding' | 'floating' | 'wrap';
|
|
133
133
|
toolbar_sticky?: boolean;
|
|
134
|
+
toolbar_narrow_breakpoint?: number;
|
|
135
|
+
toolbar_priority?: Record<string, number>;
|
|
134
136
|
menubar?: boolean;
|
|
135
137
|
contextmenu?: boolean | string;
|
|
136
138
|
quickbars_selection_toolbar?: string;
|
|
@@ -492,6 +494,11 @@ export declare class Toolbar {
|
|
|
492
494
|
private icon;
|
|
493
495
|
private render;
|
|
494
496
|
private observeOverflow;
|
|
497
|
+
private scrollHandler;
|
|
498
|
+
private bindScrollIndicators;
|
|
499
|
+
private unbindScrollIndicators;
|
|
500
|
+
private updateScrollIndicators;
|
|
501
|
+
private getButtonPriority;
|
|
495
502
|
private renderGroups;
|
|
496
503
|
private createToggleButton;
|
|
497
504
|
private toggleOverflow;
|
|
@@ -554,6 +561,8 @@ declare interface ToolbarOptions {
|
|
|
554
561
|
customButtons: Map<string, ToolbarButtonSpec>;
|
|
555
562
|
config: EditorConfig;
|
|
556
563
|
iconSet: IconSet;
|
|
564
|
+
narrowBreakpoint: number;
|
|
565
|
+
priorityOverrides: Record<string, number>;
|
|
557
566
|
}
|
|
558
567
|
|
|
559
568
|
/**
|
package/dist/index.js
CHANGED
|
@@ -14316,9 +14316,9 @@ function createInnerSelectionForWholeDocList(tr2) {
|
|
|
14316
14316
|
if (!list) {
|
|
14317
14317
|
return null;
|
|
14318
14318
|
}
|
|
14319
|
-
const
|
|
14320
|
-
const
|
|
14321
|
-
return TextSelection.
|
|
14319
|
+
const $start = doc2.resolve(1);
|
|
14320
|
+
const $end = doc2.resolve(list.nodeSize - 1);
|
|
14321
|
+
return TextSelection.between($start, $end);
|
|
14322
14322
|
}
|
|
14323
14323
|
var toggleList = (listTypeOrName, itemTypeOrName, keepMarks, attributes = {}) => ({ editor, tr: tr2, state, dispatch, chain, commands, can }) => {
|
|
14324
14324
|
const { extensions, splittableMarks } = editor.extensionManager;
|
|
@@ -14898,6 +14898,7 @@ var Extendable = class {
|
|
|
14898
14898
|
});
|
|
14899
14899
|
extension.name = this.name;
|
|
14900
14900
|
extension.parent = this.parent;
|
|
14901
|
+
this.child = null;
|
|
14901
14902
|
return extension;
|
|
14902
14903
|
}
|
|
14903
14904
|
extend(extendedConfig = {}) {
|
|
@@ -15425,6 +15426,36 @@ var ExtensionManager = class {
|
|
|
15425
15426
|
})
|
|
15426
15427
|
);
|
|
15427
15428
|
}
|
|
15429
|
+
/**
|
|
15430
|
+
* Destroy the extension manager and clean up all extension references
|
|
15431
|
+
* to prevent memory leaks through parent/child extension chains.
|
|
15432
|
+
*
|
|
15433
|
+
* Walks each extension's full parent chain and nulls every forward
|
|
15434
|
+
* `parent.child → current` link where the parent still points to the
|
|
15435
|
+
* current node. This breaks the retention path from module-scope
|
|
15436
|
+
* singleton roots through deep extend() chains.
|
|
15437
|
+
*
|
|
15438
|
+
* Only ancestor `.child` links matching the current chain are cleared.
|
|
15439
|
+
* The `.parent` pointer on ancestors is never touched — extensions
|
|
15440
|
+
* may be shared across live editors, so their own backward references
|
|
15441
|
+
* and non-matching forward links must remain intact.
|
|
15442
|
+
*/
|
|
15443
|
+
destroy() {
|
|
15444
|
+
this.extensions.forEach((extension) => {
|
|
15445
|
+
let current = extension;
|
|
15446
|
+
while (current.parent) {
|
|
15447
|
+
const parent = current.parent;
|
|
15448
|
+
if (parent.child === current) {
|
|
15449
|
+
parent.child = null;
|
|
15450
|
+
}
|
|
15451
|
+
current = parent;
|
|
15452
|
+
}
|
|
15453
|
+
});
|
|
15454
|
+
this.extensions = [];
|
|
15455
|
+
this.baseExtensions = [];
|
|
15456
|
+
this.schema = null;
|
|
15457
|
+
this.editor = null;
|
|
15458
|
+
}
|
|
15428
15459
|
/**
|
|
15429
15460
|
* Go through all extensions, create extension storages & setup marks
|
|
15430
15461
|
* & bind editor event listener.
|
|
@@ -15830,12 +15861,23 @@ var Paste = Extension.create({
|
|
|
15830
15861
|
});
|
|
15831
15862
|
var Tabindex = Extension.create({
|
|
15832
15863
|
name: "tabindex",
|
|
15864
|
+
addOptions() {
|
|
15865
|
+
return {
|
|
15866
|
+
value: void 0
|
|
15867
|
+
};
|
|
15868
|
+
},
|
|
15833
15869
|
addProseMirrorPlugins() {
|
|
15834
15870
|
return [
|
|
15835
15871
|
new Plugin({
|
|
15836
15872
|
key: new PluginKey("tabindex"),
|
|
15837
15873
|
props: {
|
|
15838
|
-
attributes: () =>
|
|
15874
|
+
attributes: () => {
|
|
15875
|
+
var _a;
|
|
15876
|
+
if (!this.editor.isEditable && this.options.value === void 0) {
|
|
15877
|
+
return {};
|
|
15878
|
+
}
|
|
15879
|
+
return { tabindex: (_a = this.options.value) != null ? _a : "0" };
|
|
15880
|
+
}
|
|
15839
15881
|
}
|
|
15840
15882
|
})
|
|
15841
15883
|
];
|
|
@@ -16166,6 +16208,7 @@ var Editor = class extends EventEmitter {
|
|
|
16166
16208
|
this.className = "tiptap";
|
|
16167
16209
|
this.editorView = null;
|
|
16168
16210
|
this.isFocused = false;
|
|
16211
|
+
this.destroyed = false;
|
|
16169
16212
|
this.isInitialized = false;
|
|
16170
16213
|
this.extensionStorage = {};
|
|
16171
16214
|
this.instanceId = Math.random().toString(36).slice(2, 9);
|
|
@@ -16448,7 +16491,7 @@ var Editor = class extends EventEmitter {
|
|
|
16448
16491
|
* Creates an extension manager.
|
|
16449
16492
|
*/
|
|
16450
16493
|
createExtensionManager() {
|
|
16451
|
-
var _a, _b;
|
|
16494
|
+
var _a, _b, _c, _d;
|
|
16452
16495
|
const coreExtensions = this.options.enableCoreExtensions ? [
|
|
16453
16496
|
Editable,
|
|
16454
16497
|
ClipboardTextSerializer.configure({
|
|
@@ -16457,7 +16500,9 @@ var Editor = class extends EventEmitter {
|
|
|
16457
16500
|
Commands,
|
|
16458
16501
|
FocusEvents,
|
|
16459
16502
|
Keymap,
|
|
16460
|
-
Tabindex
|
|
16503
|
+
Tabindex.configure({
|
|
16504
|
+
value: (_d = (_c = this.options.coreExtensionOptions) == null ? void 0 : _c.tabindex) == null ? void 0 : _d.value
|
|
16505
|
+
}),
|
|
16461
16506
|
Drop,
|
|
16462
16507
|
Paste,
|
|
16463
16508
|
Delete,
|
|
@@ -16694,9 +16739,18 @@ var Editor = class extends EventEmitter {
|
|
|
16694
16739
|
* Destroy the editor.
|
|
16695
16740
|
*/
|
|
16696
16741
|
destroy() {
|
|
16742
|
+
if (this.destroyed) {
|
|
16743
|
+
return;
|
|
16744
|
+
}
|
|
16745
|
+
this.destroyed = true;
|
|
16697
16746
|
this.emit("destroy");
|
|
16698
16747
|
this.unmount();
|
|
16699
16748
|
this.removeAllListeners();
|
|
16749
|
+
this.extensionManager.destroy();
|
|
16750
|
+
this.extensionManager = null;
|
|
16751
|
+
this.schema = null;
|
|
16752
|
+
this.commandManager = null;
|
|
16753
|
+
this.extensionStorage = {};
|
|
16700
16754
|
}
|
|
16701
16755
|
/**
|
|
16702
16756
|
* Check if the editor is already destroyed.
|
|
@@ -20461,6 +20515,25 @@ var BulletList = Node3.create({
|
|
|
20461
20515
|
return [inputRule];
|
|
20462
20516
|
}
|
|
20463
20517
|
});
|
|
20518
|
+
function isSameLineOrderedListToken(token) {
|
|
20519
|
+
var _a, _b;
|
|
20520
|
+
const nestedToken = (_a = token.tokens) == null ? void 0 : _a[0];
|
|
20521
|
+
return Boolean(
|
|
20522
|
+
token.text && ((_b = token.tokens) == null ? void 0 : _b.length) === 1 && (nestedToken == null ? void 0 : nestedToken.type) === "list" && nestedToken.ordered && nestedToken.raw === token.text
|
|
20523
|
+
);
|
|
20524
|
+
}
|
|
20525
|
+
function parseSameLineOrderedListText(text, helpers) {
|
|
20526
|
+
if (helpers.tokenizeInline) {
|
|
20527
|
+
return helpers.parseInline(helpers.tokenizeInline(text));
|
|
20528
|
+
}
|
|
20529
|
+
return helpers.parseInline([
|
|
20530
|
+
{
|
|
20531
|
+
type: "text",
|
|
20532
|
+
raw: text,
|
|
20533
|
+
text
|
|
20534
|
+
}
|
|
20535
|
+
]);
|
|
20536
|
+
}
|
|
20464
20537
|
var ListItem = Node3.create({
|
|
20465
20538
|
name: "listItem",
|
|
20466
20539
|
addOptions() {
|
|
@@ -20491,6 +20564,17 @@ var ListItem = Node3.create({
|
|
|
20491
20564
|
const parseBlockChildren = (_a = helpers.parseBlockChildren) != null ? _a : helpers.parseChildren;
|
|
20492
20565
|
let content = [];
|
|
20493
20566
|
if (token.tokens && token.tokens.length > 0) {
|
|
20567
|
+
if (isSameLineOrderedListToken(token)) {
|
|
20568
|
+
return {
|
|
20569
|
+
type: "listItem",
|
|
20570
|
+
content: [
|
|
20571
|
+
{
|
|
20572
|
+
type: "paragraph",
|
|
20573
|
+
content: parseSameLineOrderedListText(token.text || "", helpers)
|
|
20574
|
+
}
|
|
20575
|
+
]
|
|
20576
|
+
};
|
|
20577
|
+
}
|
|
20494
20578
|
const hasParagraphTokens = token.tokens.some((t) => t.type === "paragraph");
|
|
20495
20579
|
if (hasParagraphTokens) {
|
|
20496
20580
|
content = parseBlockChildren(token.tokens);
|
|
@@ -20795,6 +20879,36 @@ var ListKeymap = Extension.create({
|
|
|
20795
20879
|
});
|
|
20796
20880
|
var ORDERED_LIST_ITEM_REGEX = /^(\s*)(\d+)\.\s+(.*)$/;
|
|
20797
20881
|
var INDENTED_LINE_REGEX = /^\s/;
|
|
20882
|
+
function isBlockContentLine(line) {
|
|
20883
|
+
const trimmedLine = line.trimStart();
|
|
20884
|
+
return /^[-+*]\s+/.test(trimmedLine) || /^\d+\.\s+/.test(trimmedLine) || /^>\s?/.test(trimmedLine) || /^```/.test(trimmedLine) || /^~~~/.test(trimmedLine);
|
|
20885
|
+
}
|
|
20886
|
+
function splitItemContent(contentLines) {
|
|
20887
|
+
const paragraphLines = [];
|
|
20888
|
+
const blockLines = [];
|
|
20889
|
+
let reachedBlockBoundary = false;
|
|
20890
|
+
contentLines.forEach((line) => {
|
|
20891
|
+
if (reachedBlockBoundary) {
|
|
20892
|
+
blockLines.push(line);
|
|
20893
|
+
return;
|
|
20894
|
+
}
|
|
20895
|
+
if (line.trim() === "") {
|
|
20896
|
+
reachedBlockBoundary = true;
|
|
20897
|
+
blockLines.push(line);
|
|
20898
|
+
return;
|
|
20899
|
+
}
|
|
20900
|
+
if (paragraphLines.length > 0 && isBlockContentLine(line)) {
|
|
20901
|
+
reachedBlockBoundary = true;
|
|
20902
|
+
blockLines.push(line);
|
|
20903
|
+
return;
|
|
20904
|
+
}
|
|
20905
|
+
paragraphLines.push(line);
|
|
20906
|
+
});
|
|
20907
|
+
return {
|
|
20908
|
+
paragraphLines,
|
|
20909
|
+
blockLines
|
|
20910
|
+
};
|
|
20911
|
+
}
|
|
20798
20912
|
function collectOrderedListItems(lines) {
|
|
20799
20913
|
const listItems = [];
|
|
20800
20914
|
let currentLineIndex = 0;
|
|
@@ -20807,9 +20921,10 @@ function collectOrderedListItems(lines) {
|
|
|
20807
20921
|
}
|
|
20808
20922
|
const [, indent, number, content] = match;
|
|
20809
20923
|
const indentLevel = indent.length;
|
|
20810
|
-
|
|
20924
|
+
const itemContentLines = [content];
|
|
20811
20925
|
let nextLineIndex = currentLineIndex + 1;
|
|
20812
20926
|
const itemLines = [line];
|
|
20927
|
+
let sawBlankLine = false;
|
|
20813
20928
|
while (nextLineIndex < lines.length) {
|
|
20814
20929
|
const nextLine = lines[nextLineIndex];
|
|
20815
20930
|
const nextMatch = nextLine.match(ORDERED_LIST_ITEM_REGEX);
|
|
@@ -20818,21 +20933,27 @@ function collectOrderedListItems(lines) {
|
|
|
20818
20933
|
}
|
|
20819
20934
|
if (nextLine.trim() === "") {
|
|
20820
20935
|
itemLines.push(nextLine);
|
|
20821
|
-
|
|
20936
|
+
itemContentLines.push("");
|
|
20937
|
+
sawBlankLine = true;
|
|
20822
20938
|
nextLineIndex += 1;
|
|
20823
20939
|
} else if (nextLine.match(INDENTED_LINE_REGEX)) {
|
|
20824
20940
|
itemLines.push(nextLine);
|
|
20825
|
-
|
|
20826
|
-
${nextLine.slice(indentLevel + 2)}`;
|
|
20941
|
+
itemContentLines.push(nextLine.slice(indentLevel + 2));
|
|
20827
20942
|
nextLineIndex += 1;
|
|
20828
20943
|
} else {
|
|
20829
|
-
|
|
20944
|
+
if (sawBlankLine) {
|
|
20945
|
+
break;
|
|
20946
|
+
}
|
|
20947
|
+
itemLines.push(nextLine);
|
|
20948
|
+
itemContentLines.push(nextLine);
|
|
20949
|
+
nextLineIndex += 1;
|
|
20830
20950
|
}
|
|
20831
20951
|
}
|
|
20832
20952
|
listItems.push({
|
|
20833
20953
|
indent: indentLevel,
|
|
20834
20954
|
number: parseInt(number, 10),
|
|
20835
|
-
content:
|
|
20955
|
+
content: itemContentLines.join("\n").trim(),
|
|
20956
|
+
contentLines: itemContentLines,
|
|
20836
20957
|
raw: itemLines.join("\n")
|
|
20837
20958
|
});
|
|
20838
20959
|
consumed = nextLineIndex;
|
|
@@ -20841,14 +20962,13 @@ ${nextLine.slice(indentLevel + 2)}`;
|
|
|
20841
20962
|
return [listItems, consumed];
|
|
20842
20963
|
}
|
|
20843
20964
|
function buildNestedStructure(items, baseIndent, lexer) {
|
|
20844
|
-
var _a;
|
|
20845
20965
|
const result = [];
|
|
20846
20966
|
let currentIndex = 0;
|
|
20847
20967
|
while (currentIndex < items.length) {
|
|
20848
20968
|
const item = items[currentIndex];
|
|
20849
20969
|
if (item.indent === baseIndent) {
|
|
20850
|
-
const
|
|
20851
|
-
const mainText = (
|
|
20970
|
+
const { paragraphLines, blockLines } = splitItemContent(item.contentLines);
|
|
20971
|
+
const mainText = paragraphLines.join("\n").trim();
|
|
20852
20972
|
const tokens = [];
|
|
20853
20973
|
if (mainText) {
|
|
20854
20974
|
tokens.push({
|
|
@@ -20857,7 +20977,7 @@ function buildNestedStructure(items, baseIndent, lexer) {
|
|
|
20857
20977
|
tokens: lexer.inlineTokens(mainText)
|
|
20858
20978
|
});
|
|
20859
20979
|
}
|
|
20860
|
-
const additionalContent =
|
|
20980
|
+
const additionalContent = blockLines.join("\n").trim();
|
|
20861
20981
|
if (additionalContent) {
|
|
20862
20982
|
const blockTokens = lexer.blockTokens(additionalContent);
|
|
20863
20983
|
tokens.push(...blockTokens);
|
|
@@ -25857,6 +25977,14 @@ var Table = Node3.create({
|
|
|
25857
25977
|
})
|
|
25858
25978
|
];
|
|
25859
25979
|
},
|
|
25980
|
+
addNodeView() {
|
|
25981
|
+
const isResizable = this.options.resizable && this.editor.isEditable;
|
|
25982
|
+
const View = this.options.View;
|
|
25983
|
+
if (isResizable || !View) {
|
|
25984
|
+
return null;
|
|
25985
|
+
}
|
|
25986
|
+
return ({ node, view }) => new View(node, this.options.cellMinWidth, view);
|
|
25987
|
+
},
|
|
25860
25988
|
extendNodeSchema(extension) {
|
|
25861
25989
|
const context = {
|
|
25862
25990
|
name: extension.name,
|
|
@@ -42742,6 +42870,15 @@ class LinkEditor {
|
|
|
42742
42870
|
}
|
|
42743
42871
|
}
|
|
42744
42872
|
}
|
|
42873
|
+
const DEFAULT_BUTTON_PRIORITY = {
|
|
42874
|
+
bold: 1,
|
|
42875
|
+
italic: 1,
|
|
42876
|
+
underline: 1,
|
|
42877
|
+
undo: 1,
|
|
42878
|
+
redo: 1,
|
|
42879
|
+
link: 1,
|
|
42880
|
+
forecolor: 1
|
|
42881
|
+
};
|
|
42745
42882
|
const DEFAULT_COLORS = [
|
|
42746
42883
|
{ value: "#000000", label: "Black" },
|
|
42747
42884
|
{ value: "#434343", label: "Dark Gray 4" },
|
|
@@ -42806,7 +42943,8 @@ class Toolbar {
|
|
|
42806
42943
|
this.options = options;
|
|
42807
42944
|
this.state = {
|
|
42808
42945
|
isFullscreen: false,
|
|
42809
|
-
showMoreButtons: false
|
|
42946
|
+
showMoreButtons: false,
|
|
42947
|
+
isNarrow: false
|
|
42810
42948
|
};
|
|
42811
42949
|
this.render();
|
|
42812
42950
|
this.bindEvents();
|
|
@@ -42841,12 +42979,79 @@ class Toolbar {
|
|
|
42841
42979
|
if (this.resizeObserver) {
|
|
42842
42980
|
this.resizeObserver.disconnect();
|
|
42843
42981
|
}
|
|
42982
|
+
const editorRoot = this.container.closest(".md-editor");
|
|
42844
42983
|
this.resizeObserver = new ResizeObserver(() => {
|
|
42845
42984
|
if (!this.buttonsEl || !this.toggleBtn) return;
|
|
42846
|
-
|
|
42847
|
-
|
|
42985
|
+
if (editorRoot) {
|
|
42986
|
+
const width = editorRoot.offsetWidth;
|
|
42987
|
+
const breakpoint = this.options.narrowBreakpoint;
|
|
42988
|
+
const wasNarrow = this.state.isNarrow;
|
|
42989
|
+
this.state.isNarrow = width <= breakpoint;
|
|
42990
|
+
editorRoot.classList.toggle("md-editor-narrow", this.state.isNarrow);
|
|
42991
|
+
if (this.state.isNarrow) {
|
|
42992
|
+
this.toggleBtn.style.display = "none";
|
|
42993
|
+
if (this.state.showMoreButtons) {
|
|
42994
|
+
this.state.showMoreButtons = false;
|
|
42995
|
+
this.buttonsEl.classList.remove("md-toolbar-expanded");
|
|
42996
|
+
this.toggleBtn.classList.remove("md-toolbar-btn-active");
|
|
42997
|
+
}
|
|
42998
|
+
this.updateScrollIndicators();
|
|
42999
|
+
if (!wasNarrow) {
|
|
43000
|
+
this.bindScrollIndicators();
|
|
43001
|
+
}
|
|
43002
|
+
} else {
|
|
43003
|
+
if (wasNarrow) {
|
|
43004
|
+
this.unbindScrollIndicators();
|
|
43005
|
+
}
|
|
43006
|
+
const hasOverflow = this.buttonsEl.scrollHeight > this.buttonsEl.clientHeight;
|
|
43007
|
+
this.toggleBtn.style.display = hasOverflow || this.state.showMoreButtons ? "" : "none";
|
|
43008
|
+
}
|
|
43009
|
+
} else {
|
|
43010
|
+
const hasOverflow = this.buttonsEl.scrollHeight > this.buttonsEl.clientHeight;
|
|
43011
|
+
this.toggleBtn.style.display = hasOverflow || this.state.showMoreButtons ? "" : "none";
|
|
43012
|
+
}
|
|
42848
43013
|
});
|
|
42849
43014
|
this.resizeObserver.observe(this.buttonsEl);
|
|
43015
|
+
if (editorRoot) {
|
|
43016
|
+
this.resizeObserver.observe(editorRoot);
|
|
43017
|
+
}
|
|
43018
|
+
}
|
|
43019
|
+
scrollHandler = null;
|
|
43020
|
+
bindScrollIndicators() {
|
|
43021
|
+
if (!this.buttonsEl) return;
|
|
43022
|
+
this.scrollHandler = () => this.updateScrollIndicators();
|
|
43023
|
+
this.buttonsEl.addEventListener("scroll", this.scrollHandler, { passive: true });
|
|
43024
|
+
}
|
|
43025
|
+
unbindScrollIndicators() {
|
|
43026
|
+
if (this.buttonsEl && this.scrollHandler) {
|
|
43027
|
+
this.buttonsEl.removeEventListener("scroll", this.scrollHandler);
|
|
43028
|
+
this.scrollHandler = null;
|
|
43029
|
+
}
|
|
43030
|
+
this.container.classList.remove("md-toolbar-scroll-start", "md-toolbar-scroll-middle", "md-toolbar-scroll-end");
|
|
43031
|
+
}
|
|
43032
|
+
updateScrollIndicators() {
|
|
43033
|
+
if (!this.buttonsEl) return;
|
|
43034
|
+
const { scrollLeft, scrollWidth, clientWidth } = this.buttonsEl;
|
|
43035
|
+
const maxScroll = scrollWidth - clientWidth;
|
|
43036
|
+
if (maxScroll <= 1) {
|
|
43037
|
+
this.container.classList.remove("md-toolbar-scroll-start", "md-toolbar-scroll-middle", "md-toolbar-scroll-end");
|
|
43038
|
+
return;
|
|
43039
|
+
}
|
|
43040
|
+
const atStart = scrollLeft <= 1;
|
|
43041
|
+
const atEnd = scrollLeft >= maxScroll - 1;
|
|
43042
|
+
this.container.classList.remove("md-toolbar-scroll-start", "md-toolbar-scroll-middle", "md-toolbar-scroll-end");
|
|
43043
|
+
if (atStart) {
|
|
43044
|
+
this.container.classList.add("md-toolbar-scroll-start");
|
|
43045
|
+
} else if (atEnd) {
|
|
43046
|
+
this.container.classList.add("md-toolbar-scroll-end");
|
|
43047
|
+
} else {
|
|
43048
|
+
this.container.classList.add("md-toolbar-scroll-middle");
|
|
43049
|
+
}
|
|
43050
|
+
}
|
|
43051
|
+
getButtonPriority(name) {
|
|
43052
|
+
const overrides = this.options.priorityOverrides;
|
|
43053
|
+
if (overrides[name] !== void 0) return overrides[name];
|
|
43054
|
+
return DEFAULT_BUTTON_PRIORITY[name] ?? 2;
|
|
42850
43055
|
}
|
|
42851
43056
|
renderGroups(buttonsStr, parent) {
|
|
42852
43057
|
const groups = buttonsStr.split("|").map((g) => g.trim()).filter(Boolean);
|
|
@@ -42854,13 +43059,18 @@ class Toolbar {
|
|
|
42854
43059
|
const groupEl = document.createElement("div");
|
|
42855
43060
|
groupEl.className = "md-toolbar-group";
|
|
42856
43061
|
const buttons = group.split(" ").filter(Boolean);
|
|
43062
|
+
let groupMinPriority = 2;
|
|
42857
43063
|
buttons.forEach((buttonName) => {
|
|
42858
43064
|
const buttonEl = this.createButton(buttonName);
|
|
42859
43065
|
if (buttonEl) {
|
|
43066
|
+
const priority = this.getButtonPriority(buttonName);
|
|
43067
|
+
buttonEl.setAttribute("data-priority", String(priority));
|
|
43068
|
+
if (priority < groupMinPriority) groupMinPriority = priority;
|
|
42860
43069
|
groupEl.appendChild(buttonEl);
|
|
42861
43070
|
this.buttonElements.set(buttonName, buttonEl);
|
|
42862
43071
|
}
|
|
42863
43072
|
});
|
|
43073
|
+
groupEl.setAttribute("data-priority", String(groupMinPriority));
|
|
42864
43074
|
parent.appendChild(groupEl);
|
|
42865
43075
|
if (index < groups.length - 1) {
|
|
42866
43076
|
const separator = document.createElement("div");
|
|
@@ -43534,6 +43744,7 @@ class Toolbar {
|
|
|
43534
43744
|
this.resizeObserver.disconnect();
|
|
43535
43745
|
this.resizeObserver = null;
|
|
43536
43746
|
}
|
|
43747
|
+
this.unbindScrollIndicators();
|
|
43537
43748
|
this.unbindEvents();
|
|
43538
43749
|
this.charMap?.destroy();
|
|
43539
43750
|
this.emojiPicker?.destroy();
|
|
@@ -46190,7 +46401,9 @@ class HTMLEditor {
|
|
|
46190
46401
|
entity_encoding: config.entity_encoding ?? "raw",
|
|
46191
46402
|
valid_children: config.valid_children,
|
|
46192
46403
|
convert_unsafe_embeds: config.convert_unsafe_embeds ?? true,
|
|
46193
|
-
format_empty_lines: config.format_empty_lines ?? true
|
|
46404
|
+
format_empty_lines: config.format_empty_lines ?? true,
|
|
46405
|
+
toolbar_narrow_breakpoint: config.toolbar_narrow_breakpoint,
|
|
46406
|
+
toolbar_priority: config.toolbar_priority
|
|
46194
46407
|
};
|
|
46195
46408
|
}
|
|
46196
46409
|
createEditor() {
|
|
@@ -46268,7 +46481,9 @@ class HTMLEditor {
|
|
|
46268
46481
|
sticky: this.config.toolbar_sticky ?? true,
|
|
46269
46482
|
customButtons: this.customButtons,
|
|
46270
46483
|
config: this.config,
|
|
46271
|
-
iconSet
|
|
46484
|
+
iconSet,
|
|
46485
|
+
narrowBreakpoint: this.config.toolbar_narrow_breakpoint ?? 768,
|
|
46486
|
+
priorityOverrides: this.config.toolbar_priority ?? {}
|
|
46272
46487
|
});
|
|
46273
46488
|
if (this.config.auto_focus) {
|
|
46274
46489
|
setTimeout(() => this.focus(), 10);
|
package/dist/index.mjs
CHANGED
|
@@ -14314,9 +14314,9 @@ function createInnerSelectionForWholeDocList(tr2) {
|
|
|
14314
14314
|
if (!list) {
|
|
14315
14315
|
return null;
|
|
14316
14316
|
}
|
|
14317
|
-
const
|
|
14318
|
-
const
|
|
14319
|
-
return TextSelection.
|
|
14317
|
+
const $start = doc2.resolve(1);
|
|
14318
|
+
const $end = doc2.resolve(list.nodeSize - 1);
|
|
14319
|
+
return TextSelection.between($start, $end);
|
|
14320
14320
|
}
|
|
14321
14321
|
var toggleList = (listTypeOrName, itemTypeOrName, keepMarks, attributes = {}) => ({ editor, tr: tr2, state, dispatch, chain, commands, can }) => {
|
|
14322
14322
|
const { extensions, splittableMarks } = editor.extensionManager;
|
|
@@ -14896,6 +14896,7 @@ var Extendable = class {
|
|
|
14896
14896
|
});
|
|
14897
14897
|
extension.name = this.name;
|
|
14898
14898
|
extension.parent = this.parent;
|
|
14899
|
+
this.child = null;
|
|
14899
14900
|
return extension;
|
|
14900
14901
|
}
|
|
14901
14902
|
extend(extendedConfig = {}) {
|
|
@@ -15423,6 +15424,36 @@ var ExtensionManager = class {
|
|
|
15423
15424
|
})
|
|
15424
15425
|
);
|
|
15425
15426
|
}
|
|
15427
|
+
/**
|
|
15428
|
+
* Destroy the extension manager and clean up all extension references
|
|
15429
|
+
* to prevent memory leaks through parent/child extension chains.
|
|
15430
|
+
*
|
|
15431
|
+
* Walks each extension's full parent chain and nulls every forward
|
|
15432
|
+
* `parent.child → current` link where the parent still points to the
|
|
15433
|
+
* current node. This breaks the retention path from module-scope
|
|
15434
|
+
* singleton roots through deep extend() chains.
|
|
15435
|
+
*
|
|
15436
|
+
* Only ancestor `.child` links matching the current chain are cleared.
|
|
15437
|
+
* The `.parent` pointer on ancestors is never touched — extensions
|
|
15438
|
+
* may be shared across live editors, so their own backward references
|
|
15439
|
+
* and non-matching forward links must remain intact.
|
|
15440
|
+
*/
|
|
15441
|
+
destroy() {
|
|
15442
|
+
this.extensions.forEach((extension) => {
|
|
15443
|
+
let current = extension;
|
|
15444
|
+
while (current.parent) {
|
|
15445
|
+
const parent = current.parent;
|
|
15446
|
+
if (parent.child === current) {
|
|
15447
|
+
parent.child = null;
|
|
15448
|
+
}
|
|
15449
|
+
current = parent;
|
|
15450
|
+
}
|
|
15451
|
+
});
|
|
15452
|
+
this.extensions = [];
|
|
15453
|
+
this.baseExtensions = [];
|
|
15454
|
+
this.schema = null;
|
|
15455
|
+
this.editor = null;
|
|
15456
|
+
}
|
|
15426
15457
|
/**
|
|
15427
15458
|
* Go through all extensions, create extension storages & setup marks
|
|
15428
15459
|
* & bind editor event listener.
|
|
@@ -15828,12 +15859,23 @@ var Paste = Extension.create({
|
|
|
15828
15859
|
});
|
|
15829
15860
|
var Tabindex = Extension.create({
|
|
15830
15861
|
name: "tabindex",
|
|
15862
|
+
addOptions() {
|
|
15863
|
+
return {
|
|
15864
|
+
value: void 0
|
|
15865
|
+
};
|
|
15866
|
+
},
|
|
15831
15867
|
addProseMirrorPlugins() {
|
|
15832
15868
|
return [
|
|
15833
15869
|
new Plugin({
|
|
15834
15870
|
key: new PluginKey("tabindex"),
|
|
15835
15871
|
props: {
|
|
15836
|
-
attributes: () =>
|
|
15872
|
+
attributes: () => {
|
|
15873
|
+
var _a;
|
|
15874
|
+
if (!this.editor.isEditable && this.options.value === void 0) {
|
|
15875
|
+
return {};
|
|
15876
|
+
}
|
|
15877
|
+
return { tabindex: (_a = this.options.value) != null ? _a : "0" };
|
|
15878
|
+
}
|
|
15837
15879
|
}
|
|
15838
15880
|
})
|
|
15839
15881
|
];
|
|
@@ -16164,6 +16206,7 @@ var Editor = class extends EventEmitter {
|
|
|
16164
16206
|
this.className = "tiptap";
|
|
16165
16207
|
this.editorView = null;
|
|
16166
16208
|
this.isFocused = false;
|
|
16209
|
+
this.destroyed = false;
|
|
16167
16210
|
this.isInitialized = false;
|
|
16168
16211
|
this.extensionStorage = {};
|
|
16169
16212
|
this.instanceId = Math.random().toString(36).slice(2, 9);
|
|
@@ -16446,7 +16489,7 @@ var Editor = class extends EventEmitter {
|
|
|
16446
16489
|
* Creates an extension manager.
|
|
16447
16490
|
*/
|
|
16448
16491
|
createExtensionManager() {
|
|
16449
|
-
var _a, _b;
|
|
16492
|
+
var _a, _b, _c, _d;
|
|
16450
16493
|
const coreExtensions = this.options.enableCoreExtensions ? [
|
|
16451
16494
|
Editable,
|
|
16452
16495
|
ClipboardTextSerializer.configure({
|
|
@@ -16455,7 +16498,9 @@ var Editor = class extends EventEmitter {
|
|
|
16455
16498
|
Commands,
|
|
16456
16499
|
FocusEvents,
|
|
16457
16500
|
Keymap,
|
|
16458
|
-
Tabindex
|
|
16501
|
+
Tabindex.configure({
|
|
16502
|
+
value: (_d = (_c = this.options.coreExtensionOptions) == null ? void 0 : _c.tabindex) == null ? void 0 : _d.value
|
|
16503
|
+
}),
|
|
16459
16504
|
Drop,
|
|
16460
16505
|
Paste,
|
|
16461
16506
|
Delete,
|
|
@@ -16692,9 +16737,18 @@ var Editor = class extends EventEmitter {
|
|
|
16692
16737
|
* Destroy the editor.
|
|
16693
16738
|
*/
|
|
16694
16739
|
destroy() {
|
|
16740
|
+
if (this.destroyed) {
|
|
16741
|
+
return;
|
|
16742
|
+
}
|
|
16743
|
+
this.destroyed = true;
|
|
16695
16744
|
this.emit("destroy");
|
|
16696
16745
|
this.unmount();
|
|
16697
16746
|
this.removeAllListeners();
|
|
16747
|
+
this.extensionManager.destroy();
|
|
16748
|
+
this.extensionManager = null;
|
|
16749
|
+
this.schema = null;
|
|
16750
|
+
this.commandManager = null;
|
|
16751
|
+
this.extensionStorage = {};
|
|
16698
16752
|
}
|
|
16699
16753
|
/**
|
|
16700
16754
|
* Check if the editor is already destroyed.
|
|
@@ -20459,6 +20513,25 @@ var BulletList = Node3.create({
|
|
|
20459
20513
|
return [inputRule];
|
|
20460
20514
|
}
|
|
20461
20515
|
});
|
|
20516
|
+
function isSameLineOrderedListToken(token) {
|
|
20517
|
+
var _a, _b;
|
|
20518
|
+
const nestedToken = (_a = token.tokens) == null ? void 0 : _a[0];
|
|
20519
|
+
return Boolean(
|
|
20520
|
+
token.text && ((_b = token.tokens) == null ? void 0 : _b.length) === 1 && (nestedToken == null ? void 0 : nestedToken.type) === "list" && nestedToken.ordered && nestedToken.raw === token.text
|
|
20521
|
+
);
|
|
20522
|
+
}
|
|
20523
|
+
function parseSameLineOrderedListText(text, helpers) {
|
|
20524
|
+
if (helpers.tokenizeInline) {
|
|
20525
|
+
return helpers.parseInline(helpers.tokenizeInline(text));
|
|
20526
|
+
}
|
|
20527
|
+
return helpers.parseInline([
|
|
20528
|
+
{
|
|
20529
|
+
type: "text",
|
|
20530
|
+
raw: text,
|
|
20531
|
+
text
|
|
20532
|
+
}
|
|
20533
|
+
]);
|
|
20534
|
+
}
|
|
20462
20535
|
var ListItem = Node3.create({
|
|
20463
20536
|
name: "listItem",
|
|
20464
20537
|
addOptions() {
|
|
@@ -20489,6 +20562,17 @@ var ListItem = Node3.create({
|
|
|
20489
20562
|
const parseBlockChildren = (_a = helpers.parseBlockChildren) != null ? _a : helpers.parseChildren;
|
|
20490
20563
|
let content = [];
|
|
20491
20564
|
if (token.tokens && token.tokens.length > 0) {
|
|
20565
|
+
if (isSameLineOrderedListToken(token)) {
|
|
20566
|
+
return {
|
|
20567
|
+
type: "listItem",
|
|
20568
|
+
content: [
|
|
20569
|
+
{
|
|
20570
|
+
type: "paragraph",
|
|
20571
|
+
content: parseSameLineOrderedListText(token.text || "", helpers)
|
|
20572
|
+
}
|
|
20573
|
+
]
|
|
20574
|
+
};
|
|
20575
|
+
}
|
|
20492
20576
|
const hasParagraphTokens = token.tokens.some((t) => t.type === "paragraph");
|
|
20493
20577
|
if (hasParagraphTokens) {
|
|
20494
20578
|
content = parseBlockChildren(token.tokens);
|
|
@@ -20793,6 +20877,36 @@ var ListKeymap = Extension.create({
|
|
|
20793
20877
|
});
|
|
20794
20878
|
var ORDERED_LIST_ITEM_REGEX = /^(\s*)(\d+)\.\s+(.*)$/;
|
|
20795
20879
|
var INDENTED_LINE_REGEX = /^\s/;
|
|
20880
|
+
function isBlockContentLine(line) {
|
|
20881
|
+
const trimmedLine = line.trimStart();
|
|
20882
|
+
return /^[-+*]\s+/.test(trimmedLine) || /^\d+\.\s+/.test(trimmedLine) || /^>\s?/.test(trimmedLine) || /^```/.test(trimmedLine) || /^~~~/.test(trimmedLine);
|
|
20883
|
+
}
|
|
20884
|
+
function splitItemContent(contentLines) {
|
|
20885
|
+
const paragraphLines = [];
|
|
20886
|
+
const blockLines = [];
|
|
20887
|
+
let reachedBlockBoundary = false;
|
|
20888
|
+
contentLines.forEach((line) => {
|
|
20889
|
+
if (reachedBlockBoundary) {
|
|
20890
|
+
blockLines.push(line);
|
|
20891
|
+
return;
|
|
20892
|
+
}
|
|
20893
|
+
if (line.trim() === "") {
|
|
20894
|
+
reachedBlockBoundary = true;
|
|
20895
|
+
blockLines.push(line);
|
|
20896
|
+
return;
|
|
20897
|
+
}
|
|
20898
|
+
if (paragraphLines.length > 0 && isBlockContentLine(line)) {
|
|
20899
|
+
reachedBlockBoundary = true;
|
|
20900
|
+
blockLines.push(line);
|
|
20901
|
+
return;
|
|
20902
|
+
}
|
|
20903
|
+
paragraphLines.push(line);
|
|
20904
|
+
});
|
|
20905
|
+
return {
|
|
20906
|
+
paragraphLines,
|
|
20907
|
+
blockLines
|
|
20908
|
+
};
|
|
20909
|
+
}
|
|
20796
20910
|
function collectOrderedListItems(lines) {
|
|
20797
20911
|
const listItems = [];
|
|
20798
20912
|
let currentLineIndex = 0;
|
|
@@ -20805,9 +20919,10 @@ function collectOrderedListItems(lines) {
|
|
|
20805
20919
|
}
|
|
20806
20920
|
const [, indent, number, content] = match;
|
|
20807
20921
|
const indentLevel = indent.length;
|
|
20808
|
-
|
|
20922
|
+
const itemContentLines = [content];
|
|
20809
20923
|
let nextLineIndex = currentLineIndex + 1;
|
|
20810
20924
|
const itemLines = [line];
|
|
20925
|
+
let sawBlankLine = false;
|
|
20811
20926
|
while (nextLineIndex < lines.length) {
|
|
20812
20927
|
const nextLine = lines[nextLineIndex];
|
|
20813
20928
|
const nextMatch = nextLine.match(ORDERED_LIST_ITEM_REGEX);
|
|
@@ -20816,21 +20931,27 @@ function collectOrderedListItems(lines) {
|
|
|
20816
20931
|
}
|
|
20817
20932
|
if (nextLine.trim() === "") {
|
|
20818
20933
|
itemLines.push(nextLine);
|
|
20819
|
-
|
|
20934
|
+
itemContentLines.push("");
|
|
20935
|
+
sawBlankLine = true;
|
|
20820
20936
|
nextLineIndex += 1;
|
|
20821
20937
|
} else if (nextLine.match(INDENTED_LINE_REGEX)) {
|
|
20822
20938
|
itemLines.push(nextLine);
|
|
20823
|
-
|
|
20824
|
-
${nextLine.slice(indentLevel + 2)}`;
|
|
20939
|
+
itemContentLines.push(nextLine.slice(indentLevel + 2));
|
|
20825
20940
|
nextLineIndex += 1;
|
|
20826
20941
|
} else {
|
|
20827
|
-
|
|
20942
|
+
if (sawBlankLine) {
|
|
20943
|
+
break;
|
|
20944
|
+
}
|
|
20945
|
+
itemLines.push(nextLine);
|
|
20946
|
+
itemContentLines.push(nextLine);
|
|
20947
|
+
nextLineIndex += 1;
|
|
20828
20948
|
}
|
|
20829
20949
|
}
|
|
20830
20950
|
listItems.push({
|
|
20831
20951
|
indent: indentLevel,
|
|
20832
20952
|
number: parseInt(number, 10),
|
|
20833
|
-
content:
|
|
20953
|
+
content: itemContentLines.join("\n").trim(),
|
|
20954
|
+
contentLines: itemContentLines,
|
|
20834
20955
|
raw: itemLines.join("\n")
|
|
20835
20956
|
});
|
|
20836
20957
|
consumed = nextLineIndex;
|
|
@@ -20839,14 +20960,13 @@ ${nextLine.slice(indentLevel + 2)}`;
|
|
|
20839
20960
|
return [listItems, consumed];
|
|
20840
20961
|
}
|
|
20841
20962
|
function buildNestedStructure(items, baseIndent, lexer) {
|
|
20842
|
-
var _a;
|
|
20843
20963
|
const result = [];
|
|
20844
20964
|
let currentIndex = 0;
|
|
20845
20965
|
while (currentIndex < items.length) {
|
|
20846
20966
|
const item = items[currentIndex];
|
|
20847
20967
|
if (item.indent === baseIndent) {
|
|
20848
|
-
const
|
|
20849
|
-
const mainText = (
|
|
20968
|
+
const { paragraphLines, blockLines } = splitItemContent(item.contentLines);
|
|
20969
|
+
const mainText = paragraphLines.join("\n").trim();
|
|
20850
20970
|
const tokens = [];
|
|
20851
20971
|
if (mainText) {
|
|
20852
20972
|
tokens.push({
|
|
@@ -20855,7 +20975,7 @@ function buildNestedStructure(items, baseIndent, lexer) {
|
|
|
20855
20975
|
tokens: lexer.inlineTokens(mainText)
|
|
20856
20976
|
});
|
|
20857
20977
|
}
|
|
20858
|
-
const additionalContent =
|
|
20978
|
+
const additionalContent = blockLines.join("\n").trim();
|
|
20859
20979
|
if (additionalContent) {
|
|
20860
20980
|
const blockTokens = lexer.blockTokens(additionalContent);
|
|
20861
20981
|
tokens.push(...blockTokens);
|
|
@@ -25855,6 +25975,14 @@ var Table = Node3.create({
|
|
|
25855
25975
|
})
|
|
25856
25976
|
];
|
|
25857
25977
|
},
|
|
25978
|
+
addNodeView() {
|
|
25979
|
+
const isResizable = this.options.resizable && this.editor.isEditable;
|
|
25980
|
+
const View = this.options.View;
|
|
25981
|
+
if (isResizable || !View) {
|
|
25982
|
+
return null;
|
|
25983
|
+
}
|
|
25984
|
+
return ({ node, view }) => new View(node, this.options.cellMinWidth, view);
|
|
25985
|
+
},
|
|
25858
25986
|
extendNodeSchema(extension) {
|
|
25859
25987
|
const context = {
|
|
25860
25988
|
name: extension.name,
|
|
@@ -42740,6 +42868,15 @@ class LinkEditor {
|
|
|
42740
42868
|
}
|
|
42741
42869
|
}
|
|
42742
42870
|
}
|
|
42871
|
+
const DEFAULT_BUTTON_PRIORITY = {
|
|
42872
|
+
bold: 1,
|
|
42873
|
+
italic: 1,
|
|
42874
|
+
underline: 1,
|
|
42875
|
+
undo: 1,
|
|
42876
|
+
redo: 1,
|
|
42877
|
+
link: 1,
|
|
42878
|
+
forecolor: 1
|
|
42879
|
+
};
|
|
42743
42880
|
const DEFAULT_COLORS = [
|
|
42744
42881
|
{ value: "#000000", label: "Black" },
|
|
42745
42882
|
{ value: "#434343", label: "Dark Gray 4" },
|
|
@@ -42804,7 +42941,8 @@ class Toolbar {
|
|
|
42804
42941
|
this.options = options;
|
|
42805
42942
|
this.state = {
|
|
42806
42943
|
isFullscreen: false,
|
|
42807
|
-
showMoreButtons: false
|
|
42944
|
+
showMoreButtons: false,
|
|
42945
|
+
isNarrow: false
|
|
42808
42946
|
};
|
|
42809
42947
|
this.render();
|
|
42810
42948
|
this.bindEvents();
|
|
@@ -42839,12 +42977,79 @@ class Toolbar {
|
|
|
42839
42977
|
if (this.resizeObserver) {
|
|
42840
42978
|
this.resizeObserver.disconnect();
|
|
42841
42979
|
}
|
|
42980
|
+
const editorRoot = this.container.closest(".md-editor");
|
|
42842
42981
|
this.resizeObserver = new ResizeObserver(() => {
|
|
42843
42982
|
if (!this.buttonsEl || !this.toggleBtn) return;
|
|
42844
|
-
|
|
42845
|
-
|
|
42983
|
+
if (editorRoot) {
|
|
42984
|
+
const width = editorRoot.offsetWidth;
|
|
42985
|
+
const breakpoint = this.options.narrowBreakpoint;
|
|
42986
|
+
const wasNarrow = this.state.isNarrow;
|
|
42987
|
+
this.state.isNarrow = width <= breakpoint;
|
|
42988
|
+
editorRoot.classList.toggle("md-editor-narrow", this.state.isNarrow);
|
|
42989
|
+
if (this.state.isNarrow) {
|
|
42990
|
+
this.toggleBtn.style.display = "none";
|
|
42991
|
+
if (this.state.showMoreButtons) {
|
|
42992
|
+
this.state.showMoreButtons = false;
|
|
42993
|
+
this.buttonsEl.classList.remove("md-toolbar-expanded");
|
|
42994
|
+
this.toggleBtn.classList.remove("md-toolbar-btn-active");
|
|
42995
|
+
}
|
|
42996
|
+
this.updateScrollIndicators();
|
|
42997
|
+
if (!wasNarrow) {
|
|
42998
|
+
this.bindScrollIndicators();
|
|
42999
|
+
}
|
|
43000
|
+
} else {
|
|
43001
|
+
if (wasNarrow) {
|
|
43002
|
+
this.unbindScrollIndicators();
|
|
43003
|
+
}
|
|
43004
|
+
const hasOverflow = this.buttonsEl.scrollHeight > this.buttonsEl.clientHeight;
|
|
43005
|
+
this.toggleBtn.style.display = hasOverflow || this.state.showMoreButtons ? "" : "none";
|
|
43006
|
+
}
|
|
43007
|
+
} else {
|
|
43008
|
+
const hasOverflow = this.buttonsEl.scrollHeight > this.buttonsEl.clientHeight;
|
|
43009
|
+
this.toggleBtn.style.display = hasOverflow || this.state.showMoreButtons ? "" : "none";
|
|
43010
|
+
}
|
|
42846
43011
|
});
|
|
42847
43012
|
this.resizeObserver.observe(this.buttonsEl);
|
|
43013
|
+
if (editorRoot) {
|
|
43014
|
+
this.resizeObserver.observe(editorRoot);
|
|
43015
|
+
}
|
|
43016
|
+
}
|
|
43017
|
+
scrollHandler = null;
|
|
43018
|
+
bindScrollIndicators() {
|
|
43019
|
+
if (!this.buttonsEl) return;
|
|
43020
|
+
this.scrollHandler = () => this.updateScrollIndicators();
|
|
43021
|
+
this.buttonsEl.addEventListener("scroll", this.scrollHandler, { passive: true });
|
|
43022
|
+
}
|
|
43023
|
+
unbindScrollIndicators() {
|
|
43024
|
+
if (this.buttonsEl && this.scrollHandler) {
|
|
43025
|
+
this.buttonsEl.removeEventListener("scroll", this.scrollHandler);
|
|
43026
|
+
this.scrollHandler = null;
|
|
43027
|
+
}
|
|
43028
|
+
this.container.classList.remove("md-toolbar-scroll-start", "md-toolbar-scroll-middle", "md-toolbar-scroll-end");
|
|
43029
|
+
}
|
|
43030
|
+
updateScrollIndicators() {
|
|
43031
|
+
if (!this.buttonsEl) return;
|
|
43032
|
+
const { scrollLeft, scrollWidth, clientWidth } = this.buttonsEl;
|
|
43033
|
+
const maxScroll = scrollWidth - clientWidth;
|
|
43034
|
+
if (maxScroll <= 1) {
|
|
43035
|
+
this.container.classList.remove("md-toolbar-scroll-start", "md-toolbar-scroll-middle", "md-toolbar-scroll-end");
|
|
43036
|
+
return;
|
|
43037
|
+
}
|
|
43038
|
+
const atStart = scrollLeft <= 1;
|
|
43039
|
+
const atEnd = scrollLeft >= maxScroll - 1;
|
|
43040
|
+
this.container.classList.remove("md-toolbar-scroll-start", "md-toolbar-scroll-middle", "md-toolbar-scroll-end");
|
|
43041
|
+
if (atStart) {
|
|
43042
|
+
this.container.classList.add("md-toolbar-scroll-start");
|
|
43043
|
+
} else if (atEnd) {
|
|
43044
|
+
this.container.classList.add("md-toolbar-scroll-end");
|
|
43045
|
+
} else {
|
|
43046
|
+
this.container.classList.add("md-toolbar-scroll-middle");
|
|
43047
|
+
}
|
|
43048
|
+
}
|
|
43049
|
+
getButtonPriority(name) {
|
|
43050
|
+
const overrides = this.options.priorityOverrides;
|
|
43051
|
+
if (overrides[name] !== void 0) return overrides[name];
|
|
43052
|
+
return DEFAULT_BUTTON_PRIORITY[name] ?? 2;
|
|
42848
43053
|
}
|
|
42849
43054
|
renderGroups(buttonsStr, parent) {
|
|
42850
43055
|
const groups = buttonsStr.split("|").map((g) => g.trim()).filter(Boolean);
|
|
@@ -42852,13 +43057,18 @@ class Toolbar {
|
|
|
42852
43057
|
const groupEl = document.createElement("div");
|
|
42853
43058
|
groupEl.className = "md-toolbar-group";
|
|
42854
43059
|
const buttons = group.split(" ").filter(Boolean);
|
|
43060
|
+
let groupMinPriority = 2;
|
|
42855
43061
|
buttons.forEach((buttonName) => {
|
|
42856
43062
|
const buttonEl = this.createButton(buttonName);
|
|
42857
43063
|
if (buttonEl) {
|
|
43064
|
+
const priority = this.getButtonPriority(buttonName);
|
|
43065
|
+
buttonEl.setAttribute("data-priority", String(priority));
|
|
43066
|
+
if (priority < groupMinPriority) groupMinPriority = priority;
|
|
42858
43067
|
groupEl.appendChild(buttonEl);
|
|
42859
43068
|
this.buttonElements.set(buttonName, buttonEl);
|
|
42860
43069
|
}
|
|
42861
43070
|
});
|
|
43071
|
+
groupEl.setAttribute("data-priority", String(groupMinPriority));
|
|
42862
43072
|
parent.appendChild(groupEl);
|
|
42863
43073
|
if (index < groups.length - 1) {
|
|
42864
43074
|
const separator = document.createElement("div");
|
|
@@ -43532,6 +43742,7 @@ class Toolbar {
|
|
|
43532
43742
|
this.resizeObserver.disconnect();
|
|
43533
43743
|
this.resizeObserver = null;
|
|
43534
43744
|
}
|
|
43745
|
+
this.unbindScrollIndicators();
|
|
43535
43746
|
this.unbindEvents();
|
|
43536
43747
|
this.charMap?.destroy();
|
|
43537
43748
|
this.emojiPicker?.destroy();
|
|
@@ -46188,7 +46399,9 @@ class HTMLEditor {
|
|
|
46188
46399
|
entity_encoding: config.entity_encoding ?? "raw",
|
|
46189
46400
|
valid_children: config.valid_children,
|
|
46190
46401
|
convert_unsafe_embeds: config.convert_unsafe_embeds ?? true,
|
|
46191
|
-
format_empty_lines: config.format_empty_lines ?? true
|
|
46402
|
+
format_empty_lines: config.format_empty_lines ?? true,
|
|
46403
|
+
toolbar_narrow_breakpoint: config.toolbar_narrow_breakpoint,
|
|
46404
|
+
toolbar_priority: config.toolbar_priority
|
|
46192
46405
|
};
|
|
46193
46406
|
}
|
|
46194
46407
|
createEditor() {
|
|
@@ -46266,7 +46479,9 @@ class HTMLEditor {
|
|
|
46266
46479
|
sticky: this.config.toolbar_sticky ?? true,
|
|
46267
46480
|
customButtons: this.customButtons,
|
|
46268
46481
|
config: this.config,
|
|
46269
|
-
iconSet
|
|
46482
|
+
iconSet,
|
|
46483
|
+
narrowBreakpoint: this.config.toolbar_narrow_breakpoint ?? 768,
|
|
46484
|
+
priorityOverrides: this.config.toolbar_priority ?? {}
|
|
46270
46485
|
});
|
|
46271
46486
|
if (this.config.auto_focus) {
|
|
46272
46487
|
setTimeout(() => this.focus(), 10);
|
package/dist/styles.css
CHANGED
|
@@ -48,6 +48,7 @@
|
|
|
48
48
|
align-items: flex-start;
|
|
49
49
|
padding: 4px;
|
|
50
50
|
background: #f0f0f0;
|
|
51
|
+
--md-toolbar-bg: #f0f0f0;
|
|
51
52
|
border-bottom: 1px solid #ccc;
|
|
52
53
|
gap: 2px;
|
|
53
54
|
min-height: 39px;
|
|
@@ -985,6 +986,7 @@
|
|
|
985
986
|
}
|
|
986
987
|
.md-editor-oxide-dark .md-toolbar {
|
|
987
988
|
background: #1a252f;
|
|
989
|
+
--md-toolbar-bg: #1a252f;
|
|
988
990
|
border-color: #364049;
|
|
989
991
|
}
|
|
990
992
|
.md-editor-oxide-dark .md-toolbar-btn {
|
|
@@ -1130,6 +1132,7 @@
|
|
|
1130
1132
|
}
|
|
1131
1133
|
.md-editor-confab .md-toolbar {
|
|
1132
1134
|
background: var(--color-confab-gray-50, #f9fafb);
|
|
1135
|
+
--md-toolbar-bg: var(--color-confab-gray-50, #f9fafb);
|
|
1133
1136
|
border-color: var(--color-confab-gray-200, #e5e7eb);
|
|
1134
1137
|
}
|
|
1135
1138
|
.md-editor-confab .md-toolbar-btn {
|
|
@@ -1293,6 +1296,7 @@
|
|
|
1293
1296
|
}
|
|
1294
1297
|
.md-editor-confab-dark .md-toolbar {
|
|
1295
1298
|
background: var(--color-dark-bg-secondary, #1e1e1e);
|
|
1299
|
+
--md-toolbar-bg: var(--color-dark-bg-secondary, #1e1e1e);
|
|
1296
1300
|
border-color: var(--color-dark-border, #333);
|
|
1297
1301
|
}
|
|
1298
1302
|
.md-editor-confab-dark .md-toolbar-btn {
|
|
@@ -1489,4 +1493,108 @@
|
|
|
1489
1493
|
}
|
|
1490
1494
|
.md-editor-confab-dark .md-link-editor-row label {
|
|
1491
1495
|
color: var(--color-dark-text-muted, #888);
|
|
1496
|
+
}
|
|
1497
|
+
|
|
1498
|
+
.md-editor-narrow .md-toolbar-buttons {
|
|
1499
|
+
flex-wrap: nowrap;
|
|
1500
|
+
overflow-x: auto;
|
|
1501
|
+
overflow-y: hidden;
|
|
1502
|
+
max-height: none;
|
|
1503
|
+
-webkit-overflow-scrolling: touch;
|
|
1504
|
+
scrollbar-width: thin;
|
|
1505
|
+
scrollbar-color: rgba(0, 0, 0, 0.2) transparent;
|
|
1506
|
+
}
|
|
1507
|
+
.md-editor-narrow .md-toolbar-buttons::-webkit-scrollbar {
|
|
1508
|
+
height: 4px;
|
|
1509
|
+
}
|
|
1510
|
+
.md-editor-narrow .md-toolbar-buttons::-webkit-scrollbar-track {
|
|
1511
|
+
background: transparent;
|
|
1512
|
+
}
|
|
1513
|
+
.md-editor-narrow .md-toolbar-buttons::-webkit-scrollbar-thumb {
|
|
1514
|
+
background: rgba(0, 0, 0, 0.2);
|
|
1515
|
+
border-radius: 2px;
|
|
1516
|
+
}
|
|
1517
|
+
.md-editor-narrow .md-toolbar-toggle-btn {
|
|
1518
|
+
display: none !important;
|
|
1519
|
+
}
|
|
1520
|
+
.md-editor-narrow .md-toolbar-group {
|
|
1521
|
+
flex-shrink: 0;
|
|
1522
|
+
}
|
|
1523
|
+
.md-editor-narrow .md-toolbar-separator {
|
|
1524
|
+
flex-shrink: 0;
|
|
1525
|
+
}
|
|
1526
|
+
|
|
1527
|
+
@media (pointer: coarse) {
|
|
1528
|
+
.md-editor-narrow .md-toolbar-buttons {
|
|
1529
|
+
scrollbar-width: none;
|
|
1530
|
+
}
|
|
1531
|
+
.md-editor-narrow .md-toolbar-buttons::-webkit-scrollbar {
|
|
1532
|
+
display: none;
|
|
1533
|
+
}
|
|
1534
|
+
}
|
|
1535
|
+
.md-editor-oxide-dark.md-editor-narrow .md-toolbar-buttons,
|
|
1536
|
+
.md-editor-confab-dark.md-editor-narrow .md-toolbar-buttons {
|
|
1537
|
+
scrollbar-color: rgba(255, 255, 255, 0.25) transparent;
|
|
1538
|
+
}
|
|
1539
|
+
.md-editor-oxide-dark.md-editor-narrow .md-toolbar-buttons::-webkit-scrollbar-thumb,
|
|
1540
|
+
.md-editor-confab-dark.md-editor-narrow .md-toolbar-buttons::-webkit-scrollbar-thumb {
|
|
1541
|
+
background: rgba(255, 255, 255, 0.25);
|
|
1542
|
+
}
|
|
1543
|
+
|
|
1544
|
+
.md-editor-narrow .md-toolbar {
|
|
1545
|
+
position: relative;
|
|
1546
|
+
}
|
|
1547
|
+
.md-editor-narrow .md-toolbar::before, .md-editor-narrow .md-toolbar::after {
|
|
1548
|
+
content: "";
|
|
1549
|
+
position: absolute;
|
|
1550
|
+
top: 0;
|
|
1551
|
+
bottom: 0;
|
|
1552
|
+
width: 20px;
|
|
1553
|
+
pointer-events: none;
|
|
1554
|
+
z-index: 2;
|
|
1555
|
+
opacity: 0;
|
|
1556
|
+
transition: opacity 0.2s ease;
|
|
1557
|
+
}
|
|
1558
|
+
.md-editor-narrow .md-toolbar::before {
|
|
1559
|
+
left: 0;
|
|
1560
|
+
background: linear-gradient(to right, var(--md-toolbar-bg, #f0f0f0), transparent);
|
|
1561
|
+
}
|
|
1562
|
+
.md-editor-narrow .md-toolbar::after {
|
|
1563
|
+
right: 0;
|
|
1564
|
+
background: linear-gradient(to left, var(--md-toolbar-bg, #f0f0f0), transparent);
|
|
1565
|
+
}
|
|
1566
|
+
.md-editor-narrow .md-toolbar.md-toolbar-scroll-start::after {
|
|
1567
|
+
opacity: 1;
|
|
1568
|
+
}
|
|
1569
|
+
.md-editor-narrow .md-toolbar.md-toolbar-scroll-middle::before, .md-editor-narrow .md-toolbar.md-toolbar-scroll-middle::after {
|
|
1570
|
+
opacity: 1;
|
|
1571
|
+
}
|
|
1572
|
+
.md-editor-narrow .md-toolbar.md-toolbar-scroll-end::before {
|
|
1573
|
+
opacity: 1;
|
|
1574
|
+
}
|
|
1575
|
+
|
|
1576
|
+
@media (pointer: coarse) {
|
|
1577
|
+
.md-editor .md-toolbar {
|
|
1578
|
+
min-height: 52px;
|
|
1579
|
+
}
|
|
1580
|
+
.md-editor:not(.md-editor-narrow) .md-editor .md-toolbar-buttons {
|
|
1581
|
+
max-height: 44px;
|
|
1582
|
+
}
|
|
1583
|
+
.md-editor:not(.md-editor-narrow) .md-editor .md-toolbar-buttons.md-toolbar-expanded {
|
|
1584
|
+
max-height: none;
|
|
1585
|
+
}
|
|
1586
|
+
.md-editor .md-toolbar-btn {
|
|
1587
|
+
min-width: 44px;
|
|
1588
|
+
min-height: 44px;
|
|
1589
|
+
}
|
|
1590
|
+
.md-editor .md-toolbar-dropdown-btn {
|
|
1591
|
+
min-height: 44px;
|
|
1592
|
+
}
|
|
1593
|
+
.md-editor .md-toolbar-colorpicker-btn {
|
|
1594
|
+
min-height: 44px;
|
|
1595
|
+
min-width: 44px;
|
|
1596
|
+
}
|
|
1597
|
+
.md-editor .md-toolbar-separator {
|
|
1598
|
+
height: 32px;
|
|
1599
|
+
}
|
|
1492
1600
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mdaemon/html-editor",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "A TinyMCE-compatible HTML editor built on TipTap",
|
|
5
5
|
"homepage": "https://github.com/mdaemon-technologies/MDHTMLEditor",
|
|
6
6
|
"repository": {
|
|
@@ -60,24 +60,24 @@
|
|
|
60
60
|
},
|
|
61
61
|
"license": "LGPL-3.0-or-later",
|
|
62
62
|
"dependencies": {
|
|
63
|
-
"@tiptap/core": "^3.
|
|
64
|
-
"@tiptap/extension-character-count": "^3.
|
|
65
|
-
"@tiptap/extension-code-block-lowlight": "^3.
|
|
66
|
-
"@tiptap/extension-color": "^3.
|
|
67
|
-
"@tiptap/extension-font-family": "^3.
|
|
68
|
-
"@tiptap/extension-highlight": "^3.
|
|
69
|
-
"@tiptap/extension-image": "^3.
|
|
70
|
-
"@tiptap/extension-link": "^3.
|
|
71
|
-
"@tiptap/extension-placeholder": "^3.
|
|
72
|
-
"@tiptap/extension-table": "^3.
|
|
73
|
-
"@tiptap/extension-table-cell": "^3.
|
|
74
|
-
"@tiptap/extension-table-header": "^3.
|
|
75
|
-
"@tiptap/extension-table-row": "^3.
|
|
76
|
-
"@tiptap/extension-text-align": "^3.
|
|
77
|
-
"@tiptap/extension-text-style": "^3.
|
|
78
|
-
"@tiptap/extension-underline": "^3.
|
|
79
|
-
"@tiptap/pm": "^3.
|
|
80
|
-
"@tiptap/starter-kit": "^3.
|
|
63
|
+
"@tiptap/core": "^3.23.1",
|
|
64
|
+
"@tiptap/extension-character-count": "^3.23.1",
|
|
65
|
+
"@tiptap/extension-code-block-lowlight": "^3.23.1",
|
|
66
|
+
"@tiptap/extension-color": "^3.23.1",
|
|
67
|
+
"@tiptap/extension-font-family": "^3.23.1",
|
|
68
|
+
"@tiptap/extension-highlight": "^3.23.1",
|
|
69
|
+
"@tiptap/extension-image": "^3.23.1",
|
|
70
|
+
"@tiptap/extension-link": "^3.23.1",
|
|
71
|
+
"@tiptap/extension-placeholder": "^3.23.1",
|
|
72
|
+
"@tiptap/extension-table": "^3.23.1",
|
|
73
|
+
"@tiptap/extension-table-cell": "^3.23.1",
|
|
74
|
+
"@tiptap/extension-table-header": "^3.23.1",
|
|
75
|
+
"@tiptap/extension-table-row": "^3.23.1",
|
|
76
|
+
"@tiptap/extension-text-align": "^3.23.1",
|
|
77
|
+
"@tiptap/extension-text-style": "^3.23.1",
|
|
78
|
+
"@tiptap/extension-underline": "^3.23.1",
|
|
79
|
+
"@tiptap/pm": "^3.23.1",
|
|
80
|
+
"@tiptap/starter-kit": "^3.23.1",
|
|
81
81
|
"lowlight": "^3.3.0"
|
|
82
82
|
},
|
|
83
83
|
"devDependencies": {
|