@panneau/editor 0.0.0-stage → 5.0.0-alpha.11
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/README.md +129 -2
- package/dist/LinkDialog.d.ts +18 -0
- package/dist/LinkDialog.d.ts.map +1 -0
- package/dist/LinkDialog.js +220 -0
- package/dist/LinkDialog.js.map +1 -0
- package/dist/RichTextField.css +257 -0
- package/dist/RichTextField.d.ts +43 -0
- package/dist/RichTextField.d.ts.map +1 -0
- package/dist/RichTextField.js +361 -0
- package/dist/RichTextField.js.map +1 -0
- package/dist/RichTextField.module.js +28 -0
- package/dist/RichTextField.module.js.map +1 -0
- package/dist/Toolbar.d.ts +20 -0
- package/dist/Toolbar.d.ts.map +1 -0
- package/dist/Toolbar.js +203 -0
- package/dist/Toolbar.js.map +1 -0
- package/dist/buttons.d.ts +23 -0
- package/dist/buttons.d.ts.map +1 -0
- package/dist/buttons.js +117 -0
- package/dist/buttons.js.map +1 -0
- package/dist/extensions/attributes.d.ts +44 -0
- package/dist/extensions/attributes.d.ts.map +1 -0
- package/dist/extensions/attributes.js +138 -0
- package/dist/extensions/attributes.js.map +1 -0
- package/dist/extensions/index.d.ts +19 -0
- package/dist/extensions/index.d.ts.map +1 -0
- package/dist/extensions/index.js +96 -0
- package/dist/extensions/index.js.map +1 -0
- package/dist/extensions/marks.d.ts +4 -0
- package/dist/extensions/marks.d.ts.map +1 -0
- package/dist/extensions/marks.js +62 -0
- package/dist/extensions/marks.js.map +1 -0
- package/dist/extensions/paste.d.ts +32 -0
- package/dist/extensions/paste.d.ts.map +1 -0
- package/dist/extensions/paste.js +131 -0
- package/dist/extensions/paste.js.map +1 -0
- package/dist/extensions/raw.d.ts +23 -0
- package/dist/extensions/raw.d.ts.map +1 -0
- package/dist/extensions/raw.js +269 -0
- package/dist/extensions/raw.js.map +1 -0
- package/dist/html.d.ts +21 -0
- package/dist/html.d.ts.map +1 -0
- package/dist/html.js +51 -0
- package/dist/html.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +7 -0
- package/dist/plugin.d.ts +26 -0
- package/dist/plugin.d.ts.map +1 -0
- package/dist/plugin.js +46 -0
- package/dist/plugin.js.map +1 -0
- package/dist/settings.d.ts +22 -0
- package/dist/settings.d.ts.map +1 -0
- package/dist/settings.js +45 -0
- package/dist/settings.js.map +1 -0
- package/dist/styles.d.ts +16 -0
- package/dist/styles.d.ts.map +1 -0
- package/dist/styles.js +86 -0
- package/dist/styles.js.map +1 -0
- package/package.json +71 -5
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { HtmlAttributes } from "./attributes.js";
|
|
2
|
+
import { markExtensions } from "./marks.js";
|
|
3
|
+
import { HtmlBlock, HtmlInline, HtmlMark } from "./raw.js";
|
|
4
|
+
import { Paste } from "./paste.js";
|
|
5
|
+
import { Link } from "@tiptap/extension-link";
|
|
6
|
+
import { Blockquote } from "@tiptap/extension-blockquote";
|
|
7
|
+
import { Document } from "@tiptap/extension-document";
|
|
8
|
+
import { HardBreak } from "@tiptap/extension-hard-break";
|
|
9
|
+
import { Heading } from "@tiptap/extension-heading";
|
|
10
|
+
import { HorizontalRule } from "@tiptap/extension-horizontal-rule";
|
|
11
|
+
import { BulletList, ListItem, ListKeymap, OrderedList } from "@tiptap/extension-list";
|
|
12
|
+
import { Paragraph } from "@tiptap/extension-paragraph";
|
|
13
|
+
import { Text } from "@tiptap/extension-text";
|
|
14
|
+
import { Dropcursor, Gapcursor, Placeholder, UndoRedo } from "@tiptap/extensions";
|
|
15
|
+
//#region src/extensions/index.ts
|
|
16
|
+
/**
|
|
17
|
+
* Links with their attributes in the order they were written in (CKEditor 5 writes `target` and
|
|
18
|
+
* `rel` before `href`), and new links with `href` first.
|
|
19
|
+
*/
|
|
20
|
+
var KeptLink = Link.extend({
|
|
21
|
+
addAttributes() {
|
|
22
|
+
return {
|
|
23
|
+
...this.parent?.(),
|
|
24
|
+
order: {
|
|
25
|
+
default: null,
|
|
26
|
+
rendered: false,
|
|
27
|
+
parseHTML: (element) => element.getAttributeNames().join(" ") || null
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
},
|
|
31
|
+
renderHTML(props) {
|
|
32
|
+
const [tag, attributes] = this.parent?.(props);
|
|
33
|
+
const order = typeof props.mark.attrs.order === "string" ? props.mark.attrs.order : "href";
|
|
34
|
+
return [
|
|
35
|
+
tag,
|
|
36
|
+
{
|
|
37
|
+
...Object.fromEntries(order.split(" ").filter((name) => attributes[name] !== void 0 && attributes[name] !== null).map((name) => [name, attributes[name]])),
|
|
38
|
+
...attributes
|
|
39
|
+
},
|
|
40
|
+
0
|
|
41
|
+
];
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
/**
|
|
45
|
+
* The TipTap extensions of the rich text field. Their schema reads everything the field may hold,
|
|
46
|
+
* whatever its toolbar offers: every heading level, the marks, attributes, and HTML it doesn't
|
|
47
|
+
* edit, kept as it was written.
|
|
48
|
+
*/
|
|
49
|
+
function createRichTextExtensions({ extensions = [], placeholder, html = {} } = {}) {
|
|
50
|
+
const builtIn = [
|
|
51
|
+
Document,
|
|
52
|
+
Paragraph,
|
|
53
|
+
Text,
|
|
54
|
+
Heading.configure({ levels: [
|
|
55
|
+
1,
|
|
56
|
+
2,
|
|
57
|
+
3,
|
|
58
|
+
4,
|
|
59
|
+
5,
|
|
60
|
+
6
|
|
61
|
+
] }),
|
|
62
|
+
Blockquote,
|
|
63
|
+
BulletList,
|
|
64
|
+
OrderedList,
|
|
65
|
+
ListItem,
|
|
66
|
+
ListKeymap,
|
|
67
|
+
HardBreak,
|
|
68
|
+
HorizontalRule,
|
|
69
|
+
...markExtensions,
|
|
70
|
+
KeptLink.configure({
|
|
71
|
+
autolink: false,
|
|
72
|
+
linkOnPaste: false,
|
|
73
|
+
openOnClick: false,
|
|
74
|
+
HTMLAttributes: {
|
|
75
|
+
target: null,
|
|
76
|
+
rel: null,
|
|
77
|
+
class: null
|
|
78
|
+
}
|
|
79
|
+
}),
|
|
80
|
+
HtmlAttributes,
|
|
81
|
+
HtmlBlock.configure(html),
|
|
82
|
+
HtmlInline.configure(html),
|
|
83
|
+
HtmlMark,
|
|
84
|
+
Paste,
|
|
85
|
+
UndoRedo,
|
|
86
|
+
Dropcursor,
|
|
87
|
+
Gapcursor,
|
|
88
|
+
...placeholder !== void 0 && placeholder !== "" ? [Placeholder.configure({ placeholder })] : []
|
|
89
|
+
];
|
|
90
|
+
const replaced = new Set(extensions.map((extension) => extension.name));
|
|
91
|
+
return [...builtIn.filter((extension) => !replaced.has(extension.name)), ...extensions];
|
|
92
|
+
}
|
|
93
|
+
//#endregion
|
|
94
|
+
export { HtmlAttributes, HtmlBlock, HtmlInline, HtmlMark, createRichTextExtensions };
|
|
95
|
+
|
|
96
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":["AnyExtension","Blockquote","Document","HardBreak","Heading","HorizontalRule","Link","BulletList","ListItem","ListKeymap","OrderedList","Paragraph","Text","Dropcursor","Gapcursor","Placeholder","UndoRedo","HtmlAttributes","markExtensions","Paste","HtmlBlock","HtmlInline","HtmlMark","HtmlNodeOptions","KeptLink","extend","addAttributes","parent","order","default","rendered","parseHTML","element","HTMLElement","getAttributeNames","join","renderHTML","props","tag","attributes","Record","mark","attrs","ordered","Object","fromEntries","split","filter","name","undefined","map","RichTextExtensionsOptions","extensions","placeholder","html","Partial","createRichTextExtensions","builtIn","configure","levels","autolink","linkOnPaste","openOnClick","HTMLAttributes","target","rel","class","replaced","Set","extension","has"],"sources":["../../src/extensions/index.ts"],"sourcesContent":["import type { AnyExtension } from '@tiptap/core';\nimport { Blockquote } from '@tiptap/extension-blockquote';\nimport { Document } from '@tiptap/extension-document';\nimport { HardBreak } from '@tiptap/extension-hard-break';\nimport { Heading } from '@tiptap/extension-heading';\nimport { HorizontalRule } from '@tiptap/extension-horizontal-rule';\nimport { Link } from '@tiptap/extension-link';\nimport { BulletList, ListItem, ListKeymap, OrderedList } from '@tiptap/extension-list';\nimport { Paragraph } from '@tiptap/extension-paragraph';\nimport { Text } from '@tiptap/extension-text';\nimport { Dropcursor, Gapcursor, Placeholder, UndoRedo } from '@tiptap/extensions';\n\nimport { HtmlAttributes } from './attributes';\nimport { markExtensions } from './marks';\nimport { Paste } from './paste';\nimport { HtmlBlock, HtmlInline, HtmlMark, type HtmlNodeOptions } from './raw';\n\n/**\n * Links with their attributes in the order they were written in (CKEditor 5 writes `target` and\n * `rel` before `href`), and new links with `href` first.\n */\nconst KeptLink = Link.extend({\n addAttributes() {\n return {\n ...this.parent?.(),\n order: {\n default: null,\n rendered: false,\n parseHTML: (element: HTMLElement) => element.getAttributeNames().join(' ') || null,\n },\n };\n },\n renderHTML(props) {\n const [tag, attributes] = this.parent?.(props) as [string, Record<string, unknown>, 0];\n const order = typeof props.mark.attrs.order === 'string' ? props.mark.attrs.order : 'href';\n const ordered = Object.fromEntries(\n order\n .split(' ')\n .filter((name) => attributes[name] !== undefined && attributes[name] !== null)\n .map((name) => [name, attributes[name]]),\n );\n return [tag, { ...ordered, ...attributes }, 0];\n },\n});\n\nexport interface RichTextExtensionsOptions {\n /** TipTap extensions of the project. One with the name of a built-in extension replaces it. */\n extensions?: readonly AnyExtension[];\n /** Text shown in the empty editor. */\n placeholder?: string;\n /** How kept HTML shows in the editor. */\n html?: Partial<HtmlNodeOptions>;\n}\n\n/**\n * The TipTap extensions of the rich text field. Their schema reads everything the field may hold,\n * whatever its toolbar offers: every heading level, the marks, attributes, and HTML it doesn't\n * edit, kept as it was written.\n */\nexport function createRichTextExtensions({\n extensions = [],\n placeholder,\n html = {},\n}: RichTextExtensionsOptions = {}): AnyExtension[] {\n const builtIn: AnyExtension[] = [\n Document,\n Paragraph,\n Text,\n Heading.configure({ levels: [1, 2, 3, 4, 5, 6] }),\n Blockquote,\n BulletList,\n OrderedList,\n ListItem,\n ListKeymap,\n HardBreak,\n HorizontalRule,\n ...markExtensions,\n KeptLink.configure({\n // Links are added through the toolbar: typing or pasting a URL keeps it as text.\n autolink: false,\n linkOnPaste: false,\n openOnClick: false,\n // No `target` or `rel` on every link: they are set per link.\n HTMLAttributes: { target: null, rel: null, class: null },\n }),\n HtmlAttributes,\n HtmlBlock.configure(html),\n HtmlInline.configure(html),\n HtmlMark,\n Paste,\n UndoRedo,\n Dropcursor,\n Gapcursor,\n ...(placeholder !== undefined && placeholder !== ''\n ? [Placeholder.configure({ placeholder })]\n : []),\n ];\n const replaced = new Set(extensions.map((extension) => extension.name));\n return [...builtIn.filter((extension) => !replaced.has(extension.name)), ...extensions];\n}\n\nexport { HtmlAttributes, HtmlBlock, HtmlInline, HtmlMark };\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAqBA,IAAMwB,WAAWlB,KAAKmB,OAAO;CACzBC,gBAAgB;EACZ,OAAO;GACH,GAAG,KAAKC,SAAS;GACjBC,OAAO;IACHC,SAAS;IACTC,UAAU;IACVC,YAAYC,YAAyBA,QAAQE,kBAAkB,CAAC,CAACC,KAAK,GAAG,KAAK;GAClF;EACJ;CACJ;CACAC,WAAWC,OAAO;EACd,MAAM,CAACC,KAAKC,cAAc,KAAKZ,SAASU,KAAK;EAC7C,MAAMT,QAAQ,OAAOS,MAAMI,KAAKC,MAAMd,UAAU,WAAWS,MAAMI,KAAKC,MAAMd,QAAQ;EAOpF,OAAO;GAACU;GAAK;IAAE,GANCM,OAAOC,YACnBjB,MACKkB,MAAM,GAAG,CAAC,CACVC,QAAQC,SAAST,WAAWS,UAAUC,KAAAA,KAAaV,WAAWS,UAAU,IAAI,CAAC,CAC7EE,KAAKF,SAAS,CAACA,MAAMT,WAAWS,KAAK,CAAC,CAE7BL;IAAS,GAAGJ;GAAW;GAAG;EAAC;CACjD;AACJ,CAAC;;;;;;AAgBD,SAAgBiB,yBAAyB,EACrCJ,aAAa,CAAA,GACbC,aACAC,OAAO,CAAC,MACmB,CAAC,GAAmB;CAC/C,MAAMG,UAA0B;EAC5BvD;EACAS;EACAC;EACAR,QAAQsD,UAAU,EAAEC,QAAQ;GAAC;GAAG;GAAG;GAAG;GAAG;GAAG;EAAC,EAAE,CAAC;EAChD1D;EACAM;EACAG;EACAF;EACAC;EACAN;EACAE;EACA,GAAGa;EACHM,SAASkC,UAAU;GAEfE,UAAU;GACVC,aAAa;GACbC,aAAa;GAEbC,gBAAgB;IAAEC,QAAQ;IAAMC,KAAK;IAAMC,OAAO;GAAK;EAC3D,CAAC;EACDjD;EACAG,UAAUsC,UAAUJ,IAAI;EACxBjC,WAAWqC,UAAUJ,IAAI;EACzBhC;EACAH;EACAH;EACAH;EACAC;EACA,GAAIuC,gBAAgBJ,KAAAA,KAAaI,gBAAgB,KAC3C,CAACtC,YAAY2C,UAAU,EAAEL,YAAY,CAAC,CAAC,IACvC,CAAA;CAAG;CAEb,MAAMc,WAAW,IAAIC,IAAIhB,WAAWF,KAAKmB,cAAcA,UAAUrB,IAAI,CAAC;CACtE,OAAO,CAAC,GAAGS,QAAQV,QAAQsB,cAAc,CAACF,SAASG,IAAID,UAAUrB,IAAI,CAAC,GAAG,GAAGI,UAAU;AAC1F"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { type Mark } from '@tiptap/core';
|
|
2
|
+
/** The marks of the field: bold, italic, underline, strikethrough, code, subscript, superscript. */
|
|
3
|
+
export declare const markExtensions: Mark<import("@tiptap/extension-bold").BoldOptions, any>[];
|
|
4
|
+
//# sourceMappingURL=marks.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"marks.d.ts","sourceRoot":"","sources":["../../src/extensions/marks.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,IAAI,EAAmB,MAAM,cAAc,CAAC;AA4C1D,oGAAoG;AACpG,eAAO,MAAM,cAAc,2DAY1B,CAAC"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { mergeAttributes } from "@tiptap/core";
|
|
2
|
+
import { Bold } from "@tiptap/extension-bold";
|
|
3
|
+
import { Code } from "@tiptap/extension-code";
|
|
4
|
+
import { Italic } from "@tiptap/extension-italic";
|
|
5
|
+
import { Strike } from "@tiptap/extension-strike";
|
|
6
|
+
import { Subscript } from "@tiptap/extension-subscript";
|
|
7
|
+
import { Superscript } from "@tiptap/extension-superscript";
|
|
8
|
+
import { Underline } from "@tiptap/extension-underline";
|
|
9
|
+
//#region src/extensions/marks.ts
|
|
10
|
+
/**
|
|
11
|
+
* A mark that is written with the element it was read from: `<b>` stays `<b>` and `<i>` stays
|
|
12
|
+
* `<i>` (CKEditor 5 writes italics as `<i>`), and new marks use `tag`. Only elements are read:
|
|
13
|
+
* styles (`font-weight: bold` on a `<span>`) stay on their element.
|
|
14
|
+
*/
|
|
15
|
+
function keepTag(mark, tag, rules) {
|
|
16
|
+
return mark.extend({
|
|
17
|
+
addAttributes() {
|
|
18
|
+
return {
|
|
19
|
+
...this.parent?.(),
|
|
20
|
+
tag: {
|
|
21
|
+
default: null,
|
|
22
|
+
rendered: false,
|
|
23
|
+
parseHTML: (element) => {
|
|
24
|
+
const name = element.tagName.toLowerCase();
|
|
25
|
+
return name === tag ? null : name;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
},
|
|
30
|
+
parseHTML() {
|
|
31
|
+
return [...rules];
|
|
32
|
+
},
|
|
33
|
+
renderHTML({ mark: node, HTMLAttributes }) {
|
|
34
|
+
return [
|
|
35
|
+
typeof node.attrs.tag === "string" ? node.attrs.tag : tag,
|
|
36
|
+
mergeAttributes(this.options.HTMLAttributes, HTMLAttributes),
|
|
37
|
+
0
|
|
38
|
+
];
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
/** The marks of the field: bold, italic, underline, strikethrough, code, subscript, superscript. */
|
|
43
|
+
var markExtensions = [
|
|
44
|
+
keepTag(Bold, "strong", [{ tag: "strong" }, {
|
|
45
|
+
tag: "b",
|
|
46
|
+
getAttrs: (node) => node.style.fontWeight !== "normal" && null
|
|
47
|
+
}]),
|
|
48
|
+
keepTag(Italic, "em", [{ tag: "em" }, { tag: "i" }]),
|
|
49
|
+
keepTag(Underline, "u", [{ tag: "u" }]),
|
|
50
|
+
keepTag(Strike, "s", [
|
|
51
|
+
{ tag: "s" },
|
|
52
|
+
{ tag: "del" },
|
|
53
|
+
{ tag: "strike" }
|
|
54
|
+
]),
|
|
55
|
+
keepTag(Code, "code", [{ tag: "code" }]),
|
|
56
|
+
keepTag(Subscript, "sub", [{ tag: "sub" }]),
|
|
57
|
+
keepTag(Superscript, "sup", [{ tag: "sup" }])
|
|
58
|
+
];
|
|
59
|
+
//#endregion
|
|
60
|
+
export { markExtensions };
|
|
61
|
+
|
|
62
|
+
//# sourceMappingURL=marks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"marks.js","names":["Mark","mergeAttributes","Bold","Code","Italic","Strike","Subscript","Superscript","Underline","TagParseRule","keepTag","HTMLAttributes","Record","mark","Options","tag","rules","extend","addAttributes","parent","default","rendered","parseHTML","element","HTMLElement","name","tagName","toLowerCase","renderHTML","node","attrs","options","markExtensions","getAttrs","style","fontWeight"],"sources":["../../src/extensions/marks.ts"],"sourcesContent":["import { type Mark, mergeAttributes } from '@tiptap/core';\nimport { Bold } from '@tiptap/extension-bold';\nimport { Code } from '@tiptap/extension-code';\nimport { Italic } from '@tiptap/extension-italic';\nimport { Strike } from '@tiptap/extension-strike';\nimport { Subscript } from '@tiptap/extension-subscript';\nimport { Superscript } from '@tiptap/extension-superscript';\nimport { Underline } from '@tiptap/extension-underline';\nimport type { TagParseRule } from '@tiptap/pm/model';\n\n/**\n * A mark that is written with the element it was read from: `<b>` stays `<b>` and `<i>` stays\n * `<i>` (CKEditor 5 writes italics as `<i>`), and new marks use `tag`. Only elements are read:\n * styles (`font-weight: bold` on a `<span>`) stay on their element.\n */\nfunction keepTag<Options extends { HTMLAttributes: Record<string, unknown> }>(\n mark: Mark<Options>,\n tag: string,\n rules: readonly TagParseRule[],\n): Mark<Options> {\n return mark.extend({\n addAttributes() {\n return {\n ...this.parent?.(),\n tag: {\n default: null,\n rendered: false,\n parseHTML: (element: HTMLElement) => {\n const name = element.tagName.toLowerCase();\n return name === tag ? null : name;\n },\n },\n };\n },\n parseHTML() {\n return [...rules];\n },\n renderHTML({ mark: node, HTMLAttributes }) {\n const name = typeof node.attrs.tag === 'string' ? node.attrs.tag : tag;\n return [name, mergeAttributes(this.options.HTMLAttributes, HTMLAttributes), 0];\n },\n });\n}\n\n/** The marks of the field: bold, italic, underline, strikethrough, code, subscript, superscript. */\nexport const markExtensions = [\n keepTag(Bold, 'strong', [\n { tag: 'strong' },\n // Google Docs wraps pasted content in `<b style=\"font-weight: normal\">`.\n { tag: 'b', getAttrs: (node) => node.style.fontWeight !== 'normal' && null },\n ]),\n keepTag(Italic, 'em', [{ tag: 'em' }, { tag: 'i' }]),\n keepTag(Underline, 'u', [{ tag: 'u' }]),\n keepTag(Strike, 's', [{ tag: 's' }, { tag: 'del' }, { tag: 'strike' }]),\n keepTag(Code, 'code', [{ tag: 'code' }]),\n keepTag(Subscript, 'sub', [{ tag: 'sub' }]),\n keepTag(Superscript, 'sup', [{ tag: 'sup' }]),\n];\n"],"mappings":";;;;;;;;;;;;;;AAeA,SAASU,QACLG,MACAE,KACAC,OACa;CACb,OAAOH,KAAKI,OAAO;EACfC,gBAAgB;GACZ,OAAO;IACH,GAAG,KAAKC,SAAS;IACjBJ,KAAK;KACDK,SAAS;KACTC,UAAU;KACVC,YAAYC,YAAyB;MACjC,MAAME,OAAOF,QAAQG,QAAQC,YAAY;MACzC,OAAOF,SAASV,MAAM,OAAOU;KACjC;IACJ;GACJ;EACJ;EACAH,YAAY;GACR,OAAO,CAAC,GAAGN,KAAK;EACpB;EACAY,WAAW,EAAEf,MAAMgB,MAAMlB,kBAAkB;GAEvC,OAAO;IADM,OAAOkB,KAAKC,MAAMf,QAAQ,WAAWc,KAAKC,MAAMf,MAAMA;IACrDd,gBAAgB,KAAK8B,QAAQpB,gBAAgBA,cAAc;IAAG;GAAC;EACjF;CACJ,CAAC;AACL;;AAGA,IAAaqB,iBAAiB;CAC1BtB,QAAQR,MAAM,UAAU,CACpB,EAAEa,KAAK,SAAS,GAEhB;EAAEA,KAAK;EAAKkB,WAAWJ,SAASA,KAAKK,MAAMC,eAAe,YAAY;CAAK,CAAC,CAC/E;CACDzB,QAAQN,QAAQ,MAAM,CAAC,EAAEW,KAAK,KAAK,GAAG,EAAEA,KAAK,IAAI,CAAC,CAAC;CACnDL,QAAQF,WAAW,KAAK,CAAC,EAAEO,KAAK,IAAI,CAAC,CAAC;CACtCL,QAAQL,QAAQ,KAAK;EAAC,EAAEU,KAAK,IAAI;EAAG,EAAEA,KAAK,MAAM;EAAG,EAAEA,KAAK,SAAS;CAAC,CAAC;CACtEL,QAAQP,MAAM,QAAQ,CAAC,EAAEY,KAAK,OAAO,CAAC,CAAC;CACvCL,QAAQJ,WAAW,OAAO,CAAC,EAAES,KAAK,MAAM,CAAC,CAAC;CAC1CL,QAAQH,aAAa,OAAO,CAAC,EAAEQ,KAAK,MAAM,CAAC,CAAC;AAAC"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { Extension } from '@tiptap/core';
|
|
2
|
+
import { DOMParser, DOMSerializer, type Schema } from '@tiptap/pm/model';
|
|
3
|
+
/**
|
|
4
|
+
* The token that the rich text fields of this page put on what they copy: random, so that no
|
|
5
|
+
* other page or document can claim to come from them.
|
|
6
|
+
*/
|
|
7
|
+
export declare function getCopyToken(): string;
|
|
8
|
+
/** The serializer of copied content: `getCopyToken()` on its elements. */
|
|
9
|
+
export declare function createCopySerializer(schema: Schema): DOMSerializer;
|
|
10
|
+
/**
|
|
11
|
+
* The parser of pasted content: what the toolbar can make, without the attributes and the HTML
|
|
12
|
+
* that loaded content keeps, so that a page or a document pasted brings its text, its structure
|
|
13
|
+
* and its marks, not its styles (`<span style="font-size: 11pt">` of Google Docs). Bold and
|
|
14
|
+
* italic written as styles become marks. Content copied from a rich text field of this page
|
|
15
|
+
* (`getCopyToken()`), and only that, is read in full: kept HTML can't be brought in from
|
|
16
|
+
* elsewhere, even by HTML that claims to come from a ProseMirror editor (`data-pm-slice`).
|
|
17
|
+
* Attributes that would run a script are dropped in both cases.
|
|
18
|
+
*/
|
|
19
|
+
export declare function createPasteParser(schema: Schema): DOMParser;
|
|
20
|
+
/**
|
|
21
|
+
* Pasted HTML that wasn't copied from a rich text field of this page, without the slice data of
|
|
22
|
+
* ProseMirror (`data-pm-slice`): its context is JSON that ProseMirror makes nodes of after the
|
|
23
|
+
* parser, attributes included, so any page could write it.
|
|
24
|
+
*/
|
|
25
|
+
export declare function withoutForeignSlice(html: string): string;
|
|
26
|
+
/**
|
|
27
|
+
* Pasted content brings what the toolbar can make, not the styles of its page
|
|
28
|
+
* (`createPasteParser()`), and only content copied from a rich text field of this page brings
|
|
29
|
+
* its context (`withoutForeignSlice()`).
|
|
30
|
+
*/
|
|
31
|
+
export declare const Paste: Extension<any, any>;
|
|
32
|
+
//# sourceMappingURL=paste.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paste.d.ts","sourceRoot":"","sources":["../../src/extensions/paste.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,EACH,SAAS,EACT,aAAa,EAIb,KAAK,MAAM,EAGd,MAAM,kBAAkB,CAAC;AAQ1B;;;GAGG;AACH,wBAAgB,YAAY,IAAI,MAAM,CAMrC;AAgCD,0EAA0E;AAC1E,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,GAAG,aAAa,CAGlE;AA8CD;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAuB3D;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAaxD;AAED;;;;GAIG;AACH,eAAO,MAAM,KAAK,qBAehB,CAAC"}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { CLIPBOARD_SLICE, COPIED_FROM } from "./attributes.js";
|
|
2
|
+
import { restoreKeptHtml } from "./raw.js";
|
|
3
|
+
import { Extension } from "@tiptap/core";
|
|
4
|
+
import { DOMParser, DOMSerializer } from "@tiptap/pm/model";
|
|
5
|
+
import { Plugin, PluginKey } from "@tiptap/pm/state";
|
|
6
|
+
//#region src/extensions/paste.ts
|
|
7
|
+
var copyToken = null;
|
|
8
|
+
/**
|
|
9
|
+
* The token that the rich text fields of this page put on what they copy: random, so that no
|
|
10
|
+
* other page or document can claim to come from them.
|
|
11
|
+
*/
|
|
12
|
+
function getCopyToken() {
|
|
13
|
+
copyToken ??= Array.from(crypto.getRandomValues(/* @__PURE__ */ new Uint8Array(16)), (byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
14
|
+
return copyToken;
|
|
15
|
+
}
|
|
16
|
+
/** Whether pasted content was copied from a rich text field of this page. */
|
|
17
|
+
function isCopiedHere(dom) {
|
|
18
|
+
if (!(dom instanceof Element)) return false;
|
|
19
|
+
const selector = `[${COPIED_FROM}="${getCopyToken()}"]`;
|
|
20
|
+
return dom.matches(selector) || dom.querySelector(selector) !== null;
|
|
21
|
+
}
|
|
22
|
+
/** Writes copied content as the field does, with the token of this page on its elements. */
|
|
23
|
+
var CopySerializer = class extends DOMSerializer {
|
|
24
|
+
serializeFragment(fragment, options = {}, target) {
|
|
25
|
+
const result = super.serializeFragment(fragment, options, target);
|
|
26
|
+
if (target === void 0) {
|
|
27
|
+
restoreKeptHtml(result);
|
|
28
|
+
result.childNodes.forEach((child) => {
|
|
29
|
+
if (child.nodeType === 1) child.setAttribute(COPIED_FROM, getCopyToken());
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
return result;
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
/** The serializer of copied content: `getCopyToken()` on its elements. */
|
|
36
|
+
function createCopySerializer(schema) {
|
|
37
|
+
const { nodes, marks } = DOMSerializer.fromSchema(schema);
|
|
38
|
+
return new CopySerializer(nodes, marks);
|
|
39
|
+
}
|
|
40
|
+
/** What the field keeps as it was written, which pasted content doesn't bring. */
|
|
41
|
+
var KEPT_AS_WRITTEN = /* @__PURE__ */ new Set([
|
|
42
|
+
"htmlBlock",
|
|
43
|
+
"htmlInline",
|
|
44
|
+
"htmlMark"
|
|
45
|
+
]);
|
|
46
|
+
/** The attributes of a rule's result, without the attributes kept from the HTML. */
|
|
47
|
+
function withoutHtmlAttributes(rule) {
|
|
48
|
+
if (!("tag" in rule)) return rule;
|
|
49
|
+
const tagRule = rule;
|
|
50
|
+
const { getAttrs } = tagRule;
|
|
51
|
+
if (getAttrs === void 0) return rule;
|
|
52
|
+
return {
|
|
53
|
+
...tagRule,
|
|
54
|
+
getAttrs: (node) => {
|
|
55
|
+
const attrs = getAttrs(node);
|
|
56
|
+
if (attrs === null || attrs === false) return attrs;
|
|
57
|
+
const { htmlAttributes: _htmlAttributes, ...others } = attrs;
|
|
58
|
+
return others;
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
/** Pasted content copied from a rich text field of this page is read in full. */
|
|
63
|
+
var PasteParser = class extends DOMParser {
|
|
64
|
+
full;
|
|
65
|
+
constructor(schema, rules, full) {
|
|
66
|
+
super(schema, rules);
|
|
67
|
+
this.full = full;
|
|
68
|
+
}
|
|
69
|
+
parseSlice(dom, options) {
|
|
70
|
+
return isCopiedHere(dom) ? this.full.parseSlice(dom, options) : super.parseSlice(dom, options);
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
/**
|
|
74
|
+
* The parser of pasted content: what the toolbar can make, without the attributes and the HTML
|
|
75
|
+
* that loaded content keeps, so that a page or a document pasted brings its text, its structure
|
|
76
|
+
* and its marks, not its styles (`<span style="font-size: 11pt">` of Google Docs). Bold and
|
|
77
|
+
* italic written as styles become marks. Content copied from a rich text field of this page
|
|
78
|
+
* (`getCopyToken()`), and only that, is read in full: kept HTML can't be brought in from
|
|
79
|
+
* elsewhere, even by HTML that claims to come from a ProseMirror editor (`data-pm-slice`).
|
|
80
|
+
* Attributes that would run a script are dropped in both cases.
|
|
81
|
+
*/
|
|
82
|
+
function createPasteParser(schema) {
|
|
83
|
+
const full = DOMParser.fromSchema(schema);
|
|
84
|
+
const rules = full.rules.filter((rule) => !KEPT_AS_WRITTEN.has(("node" in rule ? rule.node : void 0) ?? rule.mark ?? "")).map(withoutHtmlAttributes);
|
|
85
|
+
const styles = [...schema.marks.bold !== void 0 ? [{
|
|
86
|
+
style: "font-weight",
|
|
87
|
+
mark: "bold",
|
|
88
|
+
getAttrs: (value) => /^(bold(er)?|[5-9]\d{2,})$/.test(value) && null
|
|
89
|
+
}] : [], ...schema.marks.italic !== void 0 ? [{
|
|
90
|
+
style: "font-style=italic",
|
|
91
|
+
mark: "italic"
|
|
92
|
+
}] : []];
|
|
93
|
+
return new PasteParser(schema, [...rules, ...styles], full);
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Pasted HTML that wasn't copied from a rich text field of this page, without the slice data of
|
|
97
|
+
* ProseMirror (`data-pm-slice`): its context is JSON that ProseMirror makes nodes of after the
|
|
98
|
+
* parser, attributes included, so any page could write it.
|
|
99
|
+
*/
|
|
100
|
+
function withoutForeignSlice(html) {
|
|
101
|
+
const template = document.createElement("template");
|
|
102
|
+
template.innerHTML = html;
|
|
103
|
+
const { content } = template;
|
|
104
|
+
if (content.querySelector(`[data-panneau-copy="${getCopyToken()}"]`) !== null) return html;
|
|
105
|
+
const slices = content.querySelectorAll(`[${CLIPBOARD_SLICE}]`);
|
|
106
|
+
if (slices.length === 0) return html;
|
|
107
|
+
slices.forEach((element) => element.removeAttribute(CLIPBOARD_SLICE));
|
|
108
|
+
return template.innerHTML;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Pasted content brings what the toolbar can make, not the styles of its page
|
|
112
|
+
* (`createPasteParser()`), and only content copied from a rich text field of this page brings
|
|
113
|
+
* its context (`withoutForeignSlice()`).
|
|
114
|
+
*/
|
|
115
|
+
var Paste = Extension.create({
|
|
116
|
+
name: "panneauPaste",
|
|
117
|
+
addProseMirrorPlugins() {
|
|
118
|
+
return [new Plugin({
|
|
119
|
+
key: new PluginKey("panneauPaste"),
|
|
120
|
+
props: {
|
|
121
|
+
transformPastedHTML: withoutForeignSlice,
|
|
122
|
+
clipboardParser: createPasteParser(this.editor.schema),
|
|
123
|
+
clipboardSerializer: createCopySerializer(this.editor.schema)
|
|
124
|
+
}
|
|
125
|
+
})];
|
|
126
|
+
}
|
|
127
|
+
});
|
|
128
|
+
//#endregion
|
|
129
|
+
export { Paste, createCopySerializer, createPasteParser, getCopyToken, withoutForeignSlice };
|
|
130
|
+
|
|
131
|
+
//# sourceMappingURL=paste.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paste.js","names":["Extension","DOMParser","DOMSerializer","Fragment","ParseOptions","ParseRule","Schema","Slice","TagParseRule","Plugin","PluginKey","CLIPBOARD_SLICE","COPIED_FROM","restoreKeptHtml","copyToken","getCopyToken","Array","from","crypto","getRandomValues","Uint8Array","byte","toString","padStart","join","isCopiedHere","dom","globalThis","Node","Element","selector","matches","querySelector","CopySerializer","serializeFragment","fragment","options","document","Document","target","HTMLElement","DocumentFragment","result","undefined","childNodes","forEach","child","nodeType","setAttribute","createCopySerializer","schema","nodes","marks","fromSchema","KEPT_AS_WRITTEN","Set","withoutHtmlAttributes","rule","tagRule","getAttrs","next","node","attrs","htmlAttributes","_htmlAttributes","others","PasteParser","constructor","rules","full","parseSlice","createPasteParser","filter","has","mark","map","styles","bold","style","value","test","italic","withoutForeignSlice","html","template","createElement","innerHTML","content","slices","querySelectorAll","length","element","removeAttribute","Paste","create","name","addProseMirrorPlugins","key","props","transformPastedHTML","clipboardParser","editor","clipboardSerializer"],"sources":["../../src/extensions/paste.ts"],"sourcesContent":["import { Extension } from '@tiptap/core';\nimport {\n DOMParser,\n DOMSerializer,\n type Fragment,\n type ParseOptions,\n type ParseRule,\n type Schema,\n type Slice,\n type TagParseRule,\n} from '@tiptap/pm/model';\nimport { Plugin, PluginKey } from '@tiptap/pm/state';\n\nimport { CLIPBOARD_SLICE, COPIED_FROM } from './attributes';\nimport { restoreKeptHtml } from './raw';\n\nlet copyToken: string | null = null;\n\n/**\n * The token that the rich text fields of this page put on what they copy: random, so that no\n * other page or document can claim to come from them.\n */\nexport function getCopyToken(): string {\n // `randomUUID()` only exists in secure contexts: an admin can be served over plain HTTP\n copyToken ??= Array.from(crypto.getRandomValues(new Uint8Array(16)), (byte) =>\n byte.toString(16).padStart(2, '0'),\n ).join('');\n return copyToken;\n}\n\n/** Whether pasted content was copied from a rich text field of this page. */\nfunction isCopiedHere(dom: globalThis.Node): boolean {\n if (!(dom instanceof Element)) {\n return false;\n }\n const selector = `[${COPIED_FROM}=\"${getCopyToken()}\"]`;\n return dom.matches(selector) || dom.querySelector(selector) !== null;\n}\n\n/** Writes copied content as the field does, with the token of this page on its elements. */\nclass CopySerializer extends DOMSerializer {\n override serializeFragment(\n fragment: Fragment,\n options: { document?: Document } = {},\n target?: HTMLElement | DocumentFragment,\n ): HTMLElement | DocumentFragment {\n const result = super.serializeFragment(fragment, options, target);\n if (target === undefined) {\n // ProseMirror writes the clipboard in an inert document\n restoreKeptHtml(result);\n result.childNodes.forEach((child) => {\n if (child.nodeType === 1) {\n (child as Element).setAttribute(COPIED_FROM, getCopyToken());\n }\n });\n }\n return result;\n }\n}\n\n/** The serializer of copied content: `getCopyToken()` on its elements. */\nexport function createCopySerializer(schema: Schema): DOMSerializer {\n const { nodes, marks } = DOMSerializer.fromSchema(schema);\n return new CopySerializer(nodes, marks);\n}\n\n/** What the field keeps as it was written, which pasted content doesn't bring. */\nconst KEPT_AS_WRITTEN = new Set(['htmlBlock', 'htmlInline', 'htmlMark']);\n\n/** The attributes of a rule's result, without the attributes kept from the HTML. */\nfunction withoutHtmlAttributes(rule: ParseRule): ParseRule {\n if (!('tag' in rule)) {\n return rule;\n }\n const tagRule = rule as TagParseRule;\n const { getAttrs } = tagRule;\n if (getAttrs === undefined) {\n return rule;\n }\n const next: TagParseRule = {\n ...tagRule,\n getAttrs: (node: HTMLElement) => {\n const attrs = getAttrs(node);\n if (attrs === null || attrs === false) {\n return attrs;\n }\n const { htmlAttributes: _htmlAttributes, ...others } = attrs;\n return others;\n },\n };\n return next;\n}\n\n/** Pasted content copied from a rich text field of this page is read in full. */\nclass PasteParser extends DOMParser {\n constructor(\n schema: Schema,\n rules: readonly ParseRule[],\n private readonly full: DOMParser,\n ) {\n super(schema, rules);\n }\n\n override parseSlice(dom: globalThis.Node, options?: ParseOptions): Slice {\n return isCopiedHere(dom)\n ? this.full.parseSlice(dom, options)\n : super.parseSlice(dom, options);\n }\n}\n\n/**\n * The parser of pasted content: what the toolbar can make, without the attributes and the HTML\n * that loaded content keeps, so that a page or a document pasted brings its text, its structure\n * and its marks, not its styles (`<span style=\"font-size: 11pt\">` of Google Docs). Bold and\n * italic written as styles become marks. Content copied from a rich text field of this page\n * (`getCopyToken()`), and only that, is read in full: kept HTML can't be brought in from\n * elsewhere, even by HTML that claims to come from a ProseMirror editor (`data-pm-slice`).\n * Attributes that would run a script are dropped in both cases.\n */\nexport function createPasteParser(schema: Schema): DOMParser {\n const full = DOMParser.fromSchema(schema);\n const rules = full.rules\n .filter(\n (rule) =>\n !KEPT_AS_WRITTEN.has(('node' in rule ? rule.node : undefined) ?? rule.mark ?? ''),\n )\n .map(withoutHtmlAttributes);\n const styles: ParseRule[] = [\n ...(schema.marks.bold !== undefined\n ? [\n {\n style: 'font-weight',\n mark: 'bold',\n getAttrs: (value: string) => /^(bold(er)?|[5-9]\\d{2,})$/.test(value) && null,\n },\n ]\n : []),\n ...(schema.marks.italic !== undefined\n ? [{ style: 'font-style=italic', mark: 'italic' }]\n : []),\n ];\n return new PasteParser(schema, [...rules, ...styles], full);\n}\n\n/**\n * Pasted HTML that wasn't copied from a rich text field of this page, without the slice data of\n * ProseMirror (`data-pm-slice`): its context is JSON that ProseMirror makes nodes of after the\n * parser, attributes included, so any page could write it.\n */\nexport function withoutForeignSlice(html: string): string {\n const template = document.createElement('template');\n template.innerHTML = html;\n const { content } = template;\n if (content.querySelector(`[${COPIED_FROM}=\"${getCopyToken()}\"]`) !== null) {\n return html;\n }\n const slices = content.querySelectorAll(`[${CLIPBOARD_SLICE}]`);\n if (slices.length === 0) {\n return html;\n }\n slices.forEach((element) => element.removeAttribute(CLIPBOARD_SLICE));\n return template.innerHTML;\n}\n\n/**\n * Pasted content brings what the toolbar can make, not the styles of its page\n * (`createPasteParser()`), and only content copied from a rich text field of this page brings\n * its context (`withoutForeignSlice()`).\n */\nexport const Paste = Extension.create({\n // TipTap's core has an extension named `paste`\n name: 'panneauPaste',\n addProseMirrorPlugins() {\n return [\n new Plugin({\n key: new PluginKey('panneauPaste'),\n props: {\n transformPastedHTML: withoutForeignSlice,\n clipboardParser: createPasteParser(this.editor.schema),\n clipboardSerializer: createCopySerializer(this.editor.schema),\n },\n }),\n ];\n },\n});\n"],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { Mark, Node } from '@tiptap/core';
|
|
2
|
+
export interface HtmlNodeOptions {
|
|
3
|
+
/** Names kept HTML in the editor, for assistive technologies: "HTML". */
|
|
4
|
+
label: string;
|
|
5
|
+
/** Class name of the element that stands for kept HTML in the editor. */
|
|
6
|
+
className: string;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Replaces the placeholders of kept HTML with the HTML they hold, in content written outside the
|
|
10
|
+
* page: an inert document, or a fragment of one.
|
|
11
|
+
*/
|
|
12
|
+
export declare function restoreKeptHtml(root: ParentNode): void;
|
|
13
|
+
/** A block of HTML that the field keeps as it was written. */
|
|
14
|
+
export declare const HtmlBlock: Node<HtmlNodeOptions, any>;
|
|
15
|
+
/** An element of HTML in the text that the field keeps as it was written: an image, an iframe. */
|
|
16
|
+
export declare const HtmlInline: Node<HtmlNodeOptions, any>;
|
|
17
|
+
/**
|
|
18
|
+
* An element around text that the field keeps with its attributes: `<span style="…">`, `<abbr
|
|
19
|
+
* title="…">`, an anchor without `href`. A `<span>` without attributes is dropped, as browsers
|
|
20
|
+
* render it the same.
|
|
21
|
+
*/
|
|
22
|
+
export declare const HtmlMark: Mark<any, any>;
|
|
23
|
+
//# sourceMappingURL=raw.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"raw.d.ts","sourceRoot":"","sources":["../../src/extensions/raw.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AA4F1C,MAAM,WAAW,eAAe;IAC5B,yEAAyE;IACzE,KAAK,EAAE,MAAM,CAAC;IACd,yEAAyE;IACzE,SAAS,EAAE,MAAM,CAAC;CACrB;AAYD;;;GAGG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI,CAOtD;AA4ED,8DAA8D;AAC9D,eAAO,MAAM,SAAS,4BAiCpB,CAAC;AAEH,kGAAkG;AAClG,eAAO,MAAM,UAAU,4BA8BrB,CAAC;AAEH;;;;GAIG;AACH,eAAO,MAAM,QAAQ,gBAwCnB,CAAC"}
|