@panneau/editor 0.0.0-stage → 5.0.0-alpha.10
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
package/dist/styles.js
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { getHtmlAttributes } from "./extensions/attributes.js";
|
|
2
|
+
//#region src/styles.ts
|
|
3
|
+
/** The element a node is written as: `p`, `h2`, `li`. */
|
|
4
|
+
function elementOf(node) {
|
|
5
|
+
switch (node.type.name) {
|
|
6
|
+
case "paragraph": return "p";
|
|
7
|
+
case "heading": return `h${String(node.attrs.level)}`;
|
|
8
|
+
case "blockquote": return "blockquote";
|
|
9
|
+
case "bulletList": return "ul";
|
|
10
|
+
case "orderedList": return "ol";
|
|
11
|
+
case "listItem": return "li";
|
|
12
|
+
default: return null;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
var elementOfStyle = (style) => style.element ?? "p";
|
|
16
|
+
var classesOf = (value) => (value ?? "").split(/\s+/).filter((name) => name !== "");
|
|
17
|
+
/**
|
|
18
|
+
* The nodes a style applies to: the paragraphs and headings of the selection, or the closest
|
|
19
|
+
* quote, list or list item around it.
|
|
20
|
+
*/
|
|
21
|
+
function findTargets(state, element) {
|
|
22
|
+
const { from, to, $from } = state.selection;
|
|
23
|
+
if (element === "p" || /^h[1-6]$/.test(element)) {
|
|
24
|
+
const targets = [];
|
|
25
|
+
state.doc.nodesBetween(from, to, (node, pos) => {
|
|
26
|
+
if (node.isTextblock && elementOf(node) === element) targets.push({
|
|
27
|
+
pos,
|
|
28
|
+
node
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
return targets;
|
|
32
|
+
}
|
|
33
|
+
for (let depth = $from.depth; depth > 0; depth -= 1) {
|
|
34
|
+
const node = $from.node(depth);
|
|
35
|
+
if (elementOf(node) === element) return [{
|
|
36
|
+
pos: $from.before(depth),
|
|
37
|
+
node
|
|
38
|
+
}];
|
|
39
|
+
}
|
|
40
|
+
return [];
|
|
41
|
+
}
|
|
42
|
+
/** Whether a node has the classes of a style. */
|
|
43
|
+
function hasStyle(node, style) {
|
|
44
|
+
const classes = classesOf(getHtmlAttributes(node.attrs).class);
|
|
45
|
+
const wanted = classesOf(style.class);
|
|
46
|
+
return wanted.length > 0 && wanted.every((name) => classes.includes(name));
|
|
47
|
+
}
|
|
48
|
+
/** Whether a style can apply to the selection. */
|
|
49
|
+
function canApplyStyle(state, style) {
|
|
50
|
+
return findTargets(state, elementOfStyle(style)).length > 0;
|
|
51
|
+
}
|
|
52
|
+
/** The style of the selection: the first one that all its targets have. */
|
|
53
|
+
function getActiveStyle(state, styles) {
|
|
54
|
+
return styles.find((style) => {
|
|
55
|
+
const targets = findTargets(state, elementOfStyle(style));
|
|
56
|
+
return targets.length > 0 && targets.every(({ node }) => hasStyle(node, style));
|
|
57
|
+
}) ?? null;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Puts a style on the selection, in place of the other styles of its element, or removes the
|
|
61
|
+
* styles of the paragraphs and headings of the selection with `null`. Other classes stay.
|
|
62
|
+
*/
|
|
63
|
+
function applyStyle(editor, style, styles) {
|
|
64
|
+
const { state } = editor;
|
|
65
|
+
const elements = style !== null ? [elementOfStyle(style)] : [...new Set(styles.map(elementOfStyle))].filter((element) => element === "p" || /^h[1-6]$/.test(element));
|
|
66
|
+
const { tr } = state;
|
|
67
|
+
elements.forEach((element) => {
|
|
68
|
+
const others = styles.filter((candidate) => elementOfStyle(candidate) === element).flatMap((candidate) => classesOf(candidate.class));
|
|
69
|
+
findTargets(state, element).forEach(({ pos, node }) => {
|
|
70
|
+
const attributes = { ...getHtmlAttributes(node.attrs) };
|
|
71
|
+
const classes = [...classesOf(attributes.class).filter((name) => !others.includes(name)), ...style !== null ? classesOf(style.class) : []];
|
|
72
|
+
if (classes.length > 0) attributes.class = classes.join(" ");
|
|
73
|
+
else delete attributes.class;
|
|
74
|
+
tr.setNodeMarkup(pos, void 0, {
|
|
75
|
+
...node.attrs,
|
|
76
|
+
htmlAttributes: Object.keys(attributes).length > 0 ? attributes : null
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
if (tr.docChanged) editor.view.dispatch(tr);
|
|
81
|
+
editor.commands.focus();
|
|
82
|
+
}
|
|
83
|
+
//#endregion
|
|
84
|
+
export { applyStyle, canApplyStyle, elementOf, getActiveStyle };
|
|
85
|
+
|
|
86
|
+
//# sourceMappingURL=styles.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"styles.js","names":["Editor","Node","ProseMirrorNode","EditorState","RichTextStyle","getHtmlAttributes","elementOf","node","type","name","String","attrs","level","elementOfStyle","style","element","classesOf","value","split","filter","Target","pos","findTargets","state","from","to","$from","selection","test","targets","doc","nodesBetween","isTextblock","push","depth","before","hasStyle","classes","class","wanted","length","every","includes","canApplyStyle","getActiveStyle","styles","find","applyStyle","editor","elements","Set","map","tr","forEach","others","candidate","flatMap","attributes","join","setNodeMarkup","undefined","htmlAttributes","Object","keys","docChanged","view","dispatch","commands","focus"],"sources":["../src/styles.ts"],"sourcesContent":["import type { Editor } from '@tiptap/core';\nimport type { Node as ProseMirrorNode } from '@tiptap/pm/model';\nimport type { EditorState } from '@tiptap/pm/state';\n\nimport type { RichTextStyle } from '@panneau/protocol';\n\nimport { getHtmlAttributes } from './extensions/attributes';\n\n/** The element a node is written as: `p`, `h2`, `li`. */\nexport function elementOf(node: ProseMirrorNode): string | null {\n switch (node.type.name) {\n case 'paragraph':\n return 'p';\n case 'heading':\n return `h${String(node.attrs.level)}`;\n case 'blockquote':\n return 'blockquote';\n case 'bulletList':\n return 'ul';\n case 'orderedList':\n return 'ol';\n case 'listItem':\n return 'li';\n default:\n return null;\n }\n}\n\nconst elementOfStyle = (style: RichTextStyle) => style.element ?? 'p';\nconst classesOf = (value: string | undefined) =>\n (value ?? '').split(/\\s+/).filter((name) => name !== '');\n\ninterface Target {\n pos: number;\n node: ProseMirrorNode;\n}\n\n/**\n * The nodes a style applies to: the paragraphs and headings of the selection, or the closest\n * quote, list or list item around it.\n */\nfunction findTargets(state: EditorState, element: string): Target[] {\n const { from, to, $from } = state.selection;\n if (element === 'p' || /^h[1-6]$/.test(element)) {\n const targets: Target[] = [];\n state.doc.nodesBetween(from, to, (node, pos) => {\n if (node.isTextblock && elementOf(node) === element) {\n targets.push({ pos, node });\n }\n });\n return targets;\n }\n for (let depth = $from.depth; depth > 0; depth -= 1) {\n const node = $from.node(depth);\n if (elementOf(node) === element) {\n return [{ pos: $from.before(depth), node }];\n }\n }\n return [];\n}\n\n/** Whether a node has the classes of a style. */\nfunction hasStyle(node: ProseMirrorNode, style: RichTextStyle): boolean {\n const classes = classesOf(getHtmlAttributes(node.attrs).class);\n const wanted = classesOf(style.class);\n return wanted.length > 0 && wanted.every((name) => classes.includes(name));\n}\n\n/** Whether a style can apply to the selection. */\nexport function canApplyStyle(state: EditorState, style: RichTextStyle): boolean {\n return findTargets(state, elementOfStyle(style)).length > 0;\n}\n\n/** The style of the selection: the first one that all its targets have. */\nexport function getActiveStyle(\n state: EditorState,\n styles: readonly RichTextStyle[],\n): RichTextStyle | null {\n return (\n styles.find((style) => {\n const targets = findTargets(state, elementOfStyle(style));\n return targets.length > 0 && targets.every(({ node }) => hasStyle(node, style));\n }) ?? null\n );\n}\n\n/**\n * Puts a style on the selection, in place of the other styles of its element, or removes the\n * styles of the paragraphs and headings of the selection with `null`. Other classes stay.\n */\nexport function applyStyle(\n editor: Editor,\n style: RichTextStyle | null,\n styles: readonly RichTextStyle[],\n): void {\n const { state } = editor;\n const elements =\n style !== null\n ? [elementOfStyle(style)]\n : [...new Set(styles.map(elementOfStyle))].filter(\n (element) => element === 'p' || /^h[1-6]$/.test(element),\n );\n const { tr } = state;\n elements.forEach((element) => {\n const others = styles\n .filter((candidate) => elementOfStyle(candidate) === element)\n .flatMap((candidate) => classesOf(candidate.class));\n findTargets(state, element).forEach(({ pos, node }) => {\n const attributes = { ...getHtmlAttributes(node.attrs) };\n const classes = [\n ...classesOf(attributes.class).filter((name) => !others.includes(name)),\n ...(style !== null ? classesOf(style.class) : []),\n ];\n if (classes.length > 0) {\n attributes.class = classes.join(' ');\n } else {\n delete attributes.class;\n }\n tr.setNodeMarkup(pos, undefined, {\n ...node.attrs,\n htmlAttributes: Object.keys(attributes).length > 0 ? attributes : null,\n });\n });\n });\n if (tr.docChanged) {\n editor.view.dispatch(tr);\n }\n editor.commands.focus();\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,72 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
2
|
+
"name": "@panneau/editor",
|
|
3
|
+
"version": "5.0.0-alpha.10",
|
|
4
|
+
"description": "The rich text field of Panneau, on TipTap 3: HTML storage, a toolbar and block styles set from the definition, and extensions from plugins.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/folkloreinc/panneau-js.git",
|
|
10
|
+
"directory": "packages/editor"
|
|
11
|
+
},
|
|
12
|
+
"sideEffects": [
|
|
13
|
+
"*.css"
|
|
14
|
+
],
|
|
15
|
+
"exports": {
|
|
16
|
+
".": {
|
|
17
|
+
"@panneau/source": "./src/index.ts",
|
|
18
|
+
"types": "./dist/index.d.ts",
|
|
19
|
+
"default": "./dist/index.js"
|
|
20
|
+
},
|
|
21
|
+
"./package.json": "./package.json"
|
|
22
|
+
},
|
|
23
|
+
"files": [
|
|
24
|
+
"dist"
|
|
25
|
+
],
|
|
26
|
+
"scripts": {
|
|
27
|
+
"build": "vite build && node ../../scripts/declarations.js",
|
|
28
|
+
"typecheck": "tsc --noEmit",
|
|
29
|
+
"api": "node ../../scripts/declarations.js && node ../../scripts/api-report.js"
|
|
30
|
+
},
|
|
31
|
+
"publishConfig": {
|
|
32
|
+
"access": "public"
|
|
33
|
+
},
|
|
34
|
+
"peerDependencies": {
|
|
35
|
+
"@tiptap/core": "^3.32.1",
|
|
36
|
+
"@tiptap/pm": "^3.32.1",
|
|
37
|
+
"@tiptap/react": "^3.32.1",
|
|
38
|
+
"react": "^19.2.0",
|
|
39
|
+
"react-aria-components": "^1.22.0",
|
|
40
|
+
"react-dom": "^19.2.0",
|
|
41
|
+
"react-intl": "^12.0.0"
|
|
42
|
+
},
|
|
43
|
+
"dependencies": {
|
|
44
|
+
"@panneau/fields": "5.0.0-alpha.10",
|
|
45
|
+
"@panneau/intl": "5.0.0-alpha.10",
|
|
46
|
+
"@panneau/protocol": "5.0.0-alpha.10",
|
|
47
|
+
"@panneau/ui": "5.0.0-alpha.10",
|
|
48
|
+
"@tiptap/extension-blockquote": "^3.32.1",
|
|
49
|
+
"@tiptap/extension-bold": "^3.32.1",
|
|
50
|
+
"@tiptap/extension-code": "^3.32.1",
|
|
51
|
+
"@tiptap/extension-document": "^3.32.1",
|
|
52
|
+
"@tiptap/extension-hard-break": "^3.32.1",
|
|
53
|
+
"@tiptap/extension-heading": "^3.32.1",
|
|
54
|
+
"@tiptap/extension-horizontal-rule": "^3.32.1",
|
|
55
|
+
"@tiptap/extension-italic": "^3.32.1",
|
|
56
|
+
"@tiptap/extension-link": "^3.32.1",
|
|
57
|
+
"@tiptap/extension-list": "^3.32.1",
|
|
58
|
+
"@tiptap/extension-paragraph": "^3.32.1",
|
|
59
|
+
"@tiptap/extension-strike": "^3.32.1",
|
|
60
|
+
"@tiptap/extension-subscript": "^3.32.1",
|
|
61
|
+
"@tiptap/extension-superscript": "^3.32.1",
|
|
62
|
+
"@tiptap/extension-text": "^3.32.1",
|
|
63
|
+
"@tiptap/extension-underline": "^3.32.1",
|
|
64
|
+
"@tiptap/extensions": "^3.32.1",
|
|
65
|
+
"lucide-react": "^1.57.0"
|
|
66
|
+
},
|
|
67
|
+
"devDependencies": {
|
|
68
|
+
"@tiptap/core": "^3.32.1",
|
|
69
|
+
"@tiptap/pm": "^3.32.1",
|
|
70
|
+
"@tiptap/react": "^3.32.1"
|
|
71
|
+
}
|
|
72
|
+
}
|