@tiptap/core 3.19.0 → 3.20.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/dist/index.cjs +118 -13
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +38 -2
- package/dist/index.d.ts +38 -2
- package/dist/index.js +118 -13
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
- package/src/Editor.ts +8 -3
- package/src/Extendable.ts +24 -0
- package/src/ExtensionManager.ts +42 -1
- package/src/__tests__/transformPastedHTML.test.ts +575 -0
- package/src/helpers/getAttributesFromExtensions.ts +20 -1
- package/src/helpers/isMarkActive.ts +5 -0
- package/src/types.ts +11 -1
- package/src/utilities/mergeAttributes.ts +74 -26
package/dist/index.cjs
CHANGED
|
@@ -1481,6 +1481,9 @@ function getAttributesFromExtensions(extensions) {
|
|
|
1481
1481
|
keepOnSplit: true,
|
|
1482
1482
|
isRequired: false
|
|
1483
1483
|
};
|
|
1484
|
+
const nodeExtensionTypes = nodeExtensions.filter((ext) => ext.name !== "text").map((ext) => ext.name);
|
|
1485
|
+
const markExtensionTypes = markExtensions.map((ext) => ext.name);
|
|
1486
|
+
const allExtensionTypes = [...nodeExtensionTypes, ...markExtensionTypes];
|
|
1484
1487
|
extensions.forEach((extension) => {
|
|
1485
1488
|
const context = {
|
|
1486
1489
|
name: extension.name,
|
|
@@ -1498,7 +1501,19 @@ function getAttributesFromExtensions(extensions) {
|
|
|
1498
1501
|
}
|
|
1499
1502
|
const globalAttributes = addGlobalAttributes();
|
|
1500
1503
|
globalAttributes.forEach((globalAttribute) => {
|
|
1501
|
-
|
|
1504
|
+
let resolvedTypes;
|
|
1505
|
+
if (Array.isArray(globalAttribute.types)) {
|
|
1506
|
+
resolvedTypes = globalAttribute.types;
|
|
1507
|
+
} else if (globalAttribute.types === "*") {
|
|
1508
|
+
resolvedTypes = allExtensionTypes;
|
|
1509
|
+
} else if (globalAttribute.types === "nodes") {
|
|
1510
|
+
resolvedTypes = nodeExtensionTypes;
|
|
1511
|
+
} else if (globalAttribute.types === "marks") {
|
|
1512
|
+
resolvedTypes = markExtensionTypes;
|
|
1513
|
+
} else {
|
|
1514
|
+
resolvedTypes = [];
|
|
1515
|
+
}
|
|
1516
|
+
resolvedTypes.forEach((type) => {
|
|
1502
1517
|
Object.entries(globalAttribute.attributes).forEach(([name, attribute]) => {
|
|
1503
1518
|
extensionAttributes.push({
|
|
1504
1519
|
type,
|
|
@@ -1549,6 +1564,67 @@ function getAttributesFromExtensions(extensions) {
|
|
|
1549
1564
|
}
|
|
1550
1565
|
|
|
1551
1566
|
// src/utilities/mergeAttributes.ts
|
|
1567
|
+
function splitStyleDeclarations(styles) {
|
|
1568
|
+
const result = [];
|
|
1569
|
+
let current = "";
|
|
1570
|
+
let inSingleQuote = false;
|
|
1571
|
+
let inDoubleQuote = false;
|
|
1572
|
+
let parenDepth = 0;
|
|
1573
|
+
const length = styles.length;
|
|
1574
|
+
for (let i = 0; i < length; i += 1) {
|
|
1575
|
+
const char = styles[i];
|
|
1576
|
+
if (char === "'" && !inDoubleQuote) {
|
|
1577
|
+
inSingleQuote = !inSingleQuote;
|
|
1578
|
+
current += char;
|
|
1579
|
+
continue;
|
|
1580
|
+
}
|
|
1581
|
+
if (char === '"' && !inSingleQuote) {
|
|
1582
|
+
inDoubleQuote = !inDoubleQuote;
|
|
1583
|
+
current += char;
|
|
1584
|
+
continue;
|
|
1585
|
+
}
|
|
1586
|
+
if (!inSingleQuote && !inDoubleQuote) {
|
|
1587
|
+
if (char === "(") {
|
|
1588
|
+
parenDepth += 1;
|
|
1589
|
+
current += char;
|
|
1590
|
+
continue;
|
|
1591
|
+
}
|
|
1592
|
+
if (char === ")" && parenDepth > 0) {
|
|
1593
|
+
parenDepth -= 1;
|
|
1594
|
+
current += char;
|
|
1595
|
+
continue;
|
|
1596
|
+
}
|
|
1597
|
+
if (char === ";" && parenDepth === 0) {
|
|
1598
|
+
result.push(current);
|
|
1599
|
+
current = "";
|
|
1600
|
+
continue;
|
|
1601
|
+
}
|
|
1602
|
+
}
|
|
1603
|
+
current += char;
|
|
1604
|
+
}
|
|
1605
|
+
if (current) {
|
|
1606
|
+
result.push(current);
|
|
1607
|
+
}
|
|
1608
|
+
return result;
|
|
1609
|
+
}
|
|
1610
|
+
function parseStyleEntries(styles) {
|
|
1611
|
+
const pairs = [];
|
|
1612
|
+
const declarations = splitStyleDeclarations(styles || "");
|
|
1613
|
+
const numDeclarations = declarations.length;
|
|
1614
|
+
for (let i = 0; i < numDeclarations; i += 1) {
|
|
1615
|
+
const declaration = declarations[i];
|
|
1616
|
+
const firstColonIndex = declaration.indexOf(":");
|
|
1617
|
+
if (firstColonIndex === -1) {
|
|
1618
|
+
continue;
|
|
1619
|
+
}
|
|
1620
|
+
const property = declaration.slice(0, firstColonIndex).trim();
|
|
1621
|
+
const value = declaration.slice(firstColonIndex + 1).trim();
|
|
1622
|
+
if (property && value) {
|
|
1623
|
+
pairs.push([property, value]);
|
|
1624
|
+
}
|
|
1625
|
+
}
|
|
1626
|
+
return pairs;
|
|
1627
|
+
}
|
|
1552
1628
|
function mergeAttributes(...objects) {
|
|
1553
1629
|
return objects.filter((item) => !!item).reduce((items, item) => {
|
|
1554
1630
|
const mergedAttributes = { ...items };
|
|
@@ -1564,17 +1640,7 @@ function mergeAttributes(...objects) {
|
|
|
1564
1640
|
const insertClasses = valueClasses.filter((valueClass) => !existingClasses.includes(valueClass));
|
|
1565
1641
|
mergedAttributes[key] = [...existingClasses, ...insertClasses].join(" ");
|
|
1566
1642
|
} else if (key === "style") {
|
|
1567
|
-
const
|
|
1568
|
-
const existingStyles = mergedAttributes[key] ? mergedAttributes[key].split(";").map((style2) => style2.trim()).filter(Boolean) : [];
|
|
1569
|
-
const styleMap = /* @__PURE__ */ new Map();
|
|
1570
|
-
existingStyles.forEach((style2) => {
|
|
1571
|
-
const [property, val] = style2.split(":").map((part) => part.trim());
|
|
1572
|
-
styleMap.set(property, val);
|
|
1573
|
-
});
|
|
1574
|
-
newStyles.forEach((style2) => {
|
|
1575
|
-
const [property, val] = style2.split(":").map((part) => part.trim());
|
|
1576
|
-
styleMap.set(property, val);
|
|
1577
|
-
});
|
|
1643
|
+
const styleMap = new Map([...parseStyleEntries(mergedAttributes[key]), ...parseStyleEntries(value)]);
|
|
1578
1644
|
mergedAttributes[key] = Array.from(styleMap.entries()).map(([property, val]) => `${property}: ${val}`).join("; ");
|
|
1579
1645
|
} else {
|
|
1580
1646
|
mergedAttributes[key] = value;
|
|
@@ -2116,6 +2182,9 @@ function isMarkActive(state, typeOrName, attributes = {}) {
|
|
|
2116
2182
|
const from = $from.pos;
|
|
2117
2183
|
const to = $to.pos;
|
|
2118
2184
|
state.doc.nodesBetween(from, to, (node, pos) => {
|
|
2185
|
+
if (type && node.inlineContent && !node.type.allowsMarkType(type)) {
|
|
2186
|
+
return false;
|
|
2187
|
+
}
|
|
2119
2188
|
if (!node.isText && !node.marks.length) {
|
|
2120
2189
|
return;
|
|
2121
2190
|
}
|
|
@@ -3816,6 +3885,39 @@ var ExtensionManager = class {
|
|
|
3816
3885
|
};
|
|
3817
3886
|
}, baseDispatch);
|
|
3818
3887
|
}
|
|
3888
|
+
/**
|
|
3889
|
+
* Get the composed transformPastedHTML function from all extensions.
|
|
3890
|
+
* @param baseTransform The base transform function (e.g. from the editor props)
|
|
3891
|
+
* @returns A composed transform function that chains all extension transforms
|
|
3892
|
+
*/
|
|
3893
|
+
transformPastedHTML(baseTransform) {
|
|
3894
|
+
const { editor } = this;
|
|
3895
|
+
const extensions = sortExtensions([...this.extensions]);
|
|
3896
|
+
return extensions.reduce(
|
|
3897
|
+
(transform, extension) => {
|
|
3898
|
+
const context = {
|
|
3899
|
+
name: extension.name,
|
|
3900
|
+
options: extension.options,
|
|
3901
|
+
storage: this.editor.extensionStorage[extension.name],
|
|
3902
|
+
editor,
|
|
3903
|
+
type: getSchemaTypeByName(extension.name, this.schema)
|
|
3904
|
+
};
|
|
3905
|
+
const extensionTransform = getExtensionField(
|
|
3906
|
+
extension,
|
|
3907
|
+
"transformPastedHTML",
|
|
3908
|
+
context
|
|
3909
|
+
);
|
|
3910
|
+
if (!extensionTransform) {
|
|
3911
|
+
return transform;
|
|
3912
|
+
}
|
|
3913
|
+
return (html, view) => {
|
|
3914
|
+
const transformedHtml = transform(html, view);
|
|
3915
|
+
return extensionTransform.call(context, transformedHtml);
|
|
3916
|
+
};
|
|
3917
|
+
},
|
|
3918
|
+
baseTransform || ((html) => html)
|
|
3919
|
+
);
|
|
3920
|
+
}
|
|
3819
3921
|
get markViews() {
|
|
3820
3922
|
const { editor } = this;
|
|
3821
3923
|
const { markExtensions } = splitExtensions(this.extensions);
|
|
@@ -4838,7 +4940,7 @@ var Editor = class extends EventEmitter {
|
|
|
4838
4940
|
return this.options.editable && this.view && this.view.editable;
|
|
4839
4941
|
}
|
|
4840
4942
|
/**
|
|
4841
|
-
* Returns the editor
|
|
4943
|
+
* Returns the editor view.
|
|
4842
4944
|
*/
|
|
4843
4945
|
get view() {
|
|
4844
4946
|
if (this.editorView) {
|
|
@@ -5007,6 +5109,8 @@ var Editor = class extends EventEmitter {
|
|
|
5007
5109
|
const { editorProps, enableExtensionDispatchTransaction } = this.options;
|
|
5008
5110
|
const baseDispatch = editorProps.dispatchTransaction || this.dispatchTransaction.bind(this);
|
|
5009
5111
|
const dispatch = enableExtensionDispatchTransaction ? this.extensionManager.dispatchTransaction(baseDispatch) : baseDispatch;
|
|
5112
|
+
const baseTransformPastedHTML = editorProps.transformPastedHTML;
|
|
5113
|
+
const transformPastedHTML = this.extensionManager.transformPastedHTML(baseTransformPastedHTML);
|
|
5010
5114
|
this.editorView = new import_view.EditorView(element, {
|
|
5011
5115
|
...editorProps,
|
|
5012
5116
|
attributes: {
|
|
@@ -5015,6 +5119,7 @@ var Editor = class extends EventEmitter {
|
|
|
5015
5119
|
...editorProps == null ? void 0 : editorProps.attributes
|
|
5016
5120
|
},
|
|
5017
5121
|
dispatchTransaction: dispatch,
|
|
5122
|
+
transformPastedHTML,
|
|
5018
5123
|
state: this.editorState,
|
|
5019
5124
|
markViews: this.extensionManager.markViews,
|
|
5020
5125
|
nodeViews: this.extensionManager.nodeViews
|