@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
|
@@ -1,3 +1,76 @@
|
|
|
1
|
+
/** Splits a CSS style string into declarations, ignoring semicolons inside quotes/parentheses. */
|
|
2
|
+
function splitStyleDeclarations(styles: string): string[] {
|
|
3
|
+
const result: string[] = []
|
|
4
|
+
|
|
5
|
+
let current = ''
|
|
6
|
+
let inSingleQuote = false
|
|
7
|
+
let inDoubleQuote = false
|
|
8
|
+
let parenDepth = 0
|
|
9
|
+
|
|
10
|
+
const length = styles.length
|
|
11
|
+
for (let i = 0; i < length; i += 1) {
|
|
12
|
+
const char = styles[i]
|
|
13
|
+
if (char === "'" && !inDoubleQuote) {
|
|
14
|
+
inSingleQuote = !inSingleQuote
|
|
15
|
+
current += char
|
|
16
|
+
continue
|
|
17
|
+
}
|
|
18
|
+
if (char === '"' && !inSingleQuote) {
|
|
19
|
+
inDoubleQuote = !inDoubleQuote
|
|
20
|
+
current += char
|
|
21
|
+
continue
|
|
22
|
+
}
|
|
23
|
+
if (!inSingleQuote && !inDoubleQuote) {
|
|
24
|
+
if (char === '(') {
|
|
25
|
+
parenDepth += 1
|
|
26
|
+
current += char
|
|
27
|
+
continue
|
|
28
|
+
}
|
|
29
|
+
if (char === ')' && parenDepth > 0) {
|
|
30
|
+
parenDepth -= 1
|
|
31
|
+
current += char
|
|
32
|
+
continue
|
|
33
|
+
}
|
|
34
|
+
if (char === ';' && parenDepth === 0) {
|
|
35
|
+
result.push(current)
|
|
36
|
+
current = ''
|
|
37
|
+
continue
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
current += char
|
|
41
|
+
}
|
|
42
|
+
if (current) {
|
|
43
|
+
result.push(current)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return result
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** Yields property/value pairs from a style string. */
|
|
50
|
+
function parseStyleEntries(styles: string | undefined): [property: string, value: string][] {
|
|
51
|
+
const pairs: [string, string][] = []
|
|
52
|
+
|
|
53
|
+
const declarations = splitStyleDeclarations(styles || '')
|
|
54
|
+
const numDeclarations = declarations.length
|
|
55
|
+
|
|
56
|
+
for (let i = 0; i < numDeclarations; i += 1) {
|
|
57
|
+
const declaration = declarations[i]
|
|
58
|
+
|
|
59
|
+
const firstColonIndex = declaration.indexOf(':')
|
|
60
|
+
if (firstColonIndex === -1) {
|
|
61
|
+
continue
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const property = declaration.slice(0, firstColonIndex).trim()
|
|
65
|
+
const value = declaration.slice(firstColonIndex + 1).trim()
|
|
66
|
+
if (property && value) {
|
|
67
|
+
pairs.push([property, value])
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return pairs
|
|
72
|
+
}
|
|
73
|
+
|
|
1
74
|
export function mergeAttributes(...objects: Record<string, any>[]): Record<string, any> {
|
|
2
75
|
return objects
|
|
3
76
|
.filter(item => !!item)
|
|
@@ -21,32 +94,7 @@ export function mergeAttributes(...objects: Record<string, any>[]): Record<strin
|
|
|
21
94
|
|
|
22
95
|
mergedAttributes[key] = [...existingClasses, ...insertClasses].join(' ')
|
|
23
96
|
} else if (key === 'style') {
|
|
24
|
-
const
|
|
25
|
-
? value
|
|
26
|
-
.split(';')
|
|
27
|
-
.map((style: string) => style.trim())
|
|
28
|
-
.filter(Boolean)
|
|
29
|
-
: []
|
|
30
|
-
const existingStyles: string[] = mergedAttributes[key]
|
|
31
|
-
? mergedAttributes[key]
|
|
32
|
-
.split(';')
|
|
33
|
-
.map((style: string) => style.trim())
|
|
34
|
-
.filter(Boolean)
|
|
35
|
-
: []
|
|
36
|
-
|
|
37
|
-
const styleMap = new Map<string, string>()
|
|
38
|
-
|
|
39
|
-
existingStyles.forEach(style => {
|
|
40
|
-
const [property, val] = style.split(':').map(part => part.trim())
|
|
41
|
-
|
|
42
|
-
styleMap.set(property, val)
|
|
43
|
-
})
|
|
44
|
-
|
|
45
|
-
newStyles.forEach(style => {
|
|
46
|
-
const [property, val] = style.split(':').map(part => part.trim())
|
|
47
|
-
|
|
48
|
-
styleMap.set(property, val)
|
|
49
|
-
})
|
|
97
|
+
const styleMap = new Map([...parseStyleEntries(mergedAttributes[key]), ...parseStyleEntries(value)])
|
|
50
98
|
|
|
51
99
|
mergedAttributes[key] = Array.from(styleMap.entries())
|
|
52
100
|
.map(([property, val]) => `${property}: ${val}`)
|