@rathkit/rte-core 0.1.0-alpha.4 → 0.2.0-beta.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/README.md +1 -1
- package/dist/autoformat/autoformat.js +18 -3
- package/dist/base64.js +5 -1
- package/dist/dom/index.d.ts +1 -1
- package/dist/dom/render.js +4 -4
- package/dist/dom/view.d.ts +56 -3
- package/dist/dom/view.js +174 -25
- package/dist/edit.d.ts +6 -0
- package/dist/edit.js +96 -9
- package/dist/engine.d.ts +19 -3
- package/dist/engine.js +96 -22
- package/dist/export.js +1 -1
- package/dist/html/parse.d.ts +8 -2
- package/dist/html/parse.js +6 -2
- package/dist/images/plugin.js +2 -1
- package/dist/images/view.d.ts +1 -1
- package/dist/images/view.js +4 -4
- package/dist/import.d.ts +18 -2
- package/dist/import.js +35 -27
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -1
- package/dist/lists/lists.js +14 -4
- package/dist/markdown/export.js +1 -1
- package/dist/markdown/inline.d.ts +7 -0
- package/dist/markdown/inline.js +29 -20
- package/dist/markdown/parse.js +1 -1
- package/dist/markdown/plugin.js +5 -1
- package/dist/model.d.ts +5 -0
- package/dist/paste.js +9 -2
- package/dist/path.d.ts +7 -0
- package/dist/path.js +20 -7
- package/dist/plugin.d.ts +1 -1
- package/dist/policy.d.ts +41 -0
- package/dist/policy.js +40 -0
- package/dist/standard/index.d.ts +0 -1
- package/dist/standard/index.js +0 -1
- package/dist/stats.js +1 -1
- package/dist/svg/svg.js +9 -1
- package/dist/tables/cells.d.ts +1 -1
- package/dist/tables/cells.js +3 -3
- package/dist/tables/grips.js +2 -2
- package/dist/warning.d.ts +16 -0
- package/dist/warning.js +5 -0
- package/package.json +1 -1
package/dist/policy.js
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
export const DROPPED_ELEMENTS = new Set([
|
|
2
|
+
"script", "style", "link", "meta", "base", "object", "embed", "iframe", "frame", "frameset", "noscript", "template",
|
|
3
|
+
"head", "textarea", "input", "select", "option", "button", "canvas", "audio", "video", "applet", "xml",
|
|
4
|
+
]);
|
|
5
|
+
export const GROUPING_ELEMENTS = new Set([
|
|
6
|
+
"div", "section", "article", "header", "footer", "aside", "nav", "figure", "figcaption", "address", "main", "form",
|
|
7
|
+
"body", "html", "center", "details", "summary", "dd", "dt", "fieldset", "hgroup",
|
|
8
|
+
]);
|
|
9
|
+
export const DEFAULT_LINK_SCHEMES = ["http", "https", "mailto", "tel"];
|
|
10
|
+
export const IMAGE_SCHEMES = ["http", "https"];
|
|
11
|
+
export const DATA_IMAGE_SIGNATURES = [
|
|
12
|
+
["image/png", "iVBORw0KGgo"], ["image/jpeg", "/9j/"], ["image/gif", "R0lGOD"], ["image/webp", "UklGR"], ["image/bmp", "Qk"],
|
|
13
|
+
];
|
|
14
|
+
export const CONTENT_PROFILES = {
|
|
15
|
+
strict: { pasteRelativeImages: false, linkSchemes: ["http", "https", "mailto"], styles: "semantic", maxDataImageLength: 0, maxDepth: 32, maxInputLength: 1_000_000 },
|
|
16
|
+
standard: { pasteRelativeImages: false, linkSchemes: DEFAULT_LINK_SCHEMES, styles: "allowlist", maxDataImageLength: 12_000_000, maxDepth: 100, maxInputLength: 50_000_000 },
|
|
17
|
+
loose: { pasteRelativeImages: false, linkSchemes: ["http", "https", "mailto", "tel", "sms", "ftp", "ftps"], styles: "allowlist", maxDataImageLength: 25_000_000, maxDepth: 200, maxInputLength: 200_000_000 },
|
|
18
|
+
};
|
|
19
|
+
export function contentPolicy(options = {}, complain = () => undefined) {
|
|
20
|
+
const { profile = "standard", ...rest } = options;
|
|
21
|
+
if (!Object.hasOwn(CONTENT_PROFILES, profile))
|
|
22
|
+
complain(`content.profile "${String(profile)}" is not a profile: using standard (strict, standard or loose).`);
|
|
23
|
+
const base = Object.hasOwn(CONTENT_PROFILES, profile) ? CONTENT_PROFILES[profile] : CONTENT_PROFILES.standard;
|
|
24
|
+
const given = {};
|
|
25
|
+
for (const [key, value] of Object.entries(rest)) {
|
|
26
|
+
if (value === undefined)
|
|
27
|
+
continue;
|
|
28
|
+
const ok = key === "linkSchemes" ? Array.isArray(value) && value.every((v) => typeof v === "string" && /^[a-z][a-z0-9+.-]*$/i.test(v))
|
|
29
|
+
: key === "styles" ? value === "semantic" || value === "allowlist"
|
|
30
|
+
: key === "pasteRelativeImages" ? typeof value === "boolean"
|
|
31
|
+
: key === "maxDepth" ? Number.isInteger(value) && value >= 1
|
|
32
|
+
: (key === "maxInputLength" || key === "maxDataImageLength") ? Number.isInteger(value) && value >= 0
|
|
33
|
+
: false;
|
|
34
|
+
if (ok)
|
|
35
|
+
given[key] = value;
|
|
36
|
+
else
|
|
37
|
+
complain(`content.${key} cannot be ${JSON.stringify(value)}: using the ${profile in CONTENT_PROFILES ? profile : "standard"} profile's value.`);
|
|
38
|
+
}
|
|
39
|
+
return { ...base, ...given };
|
|
40
|
+
}
|
package/dist/standard/index.d.ts
CHANGED
|
@@ -25,4 +25,3 @@ export interface StandardOptions extends Omit<EditorOptions, "plugins">, Standar
|
|
|
25
25
|
/** The standard plugins, for hosts that build their own editor but want the usual parts. */
|
|
26
26
|
export declare function standardPlugins(options?: StandardPluginOptions): Plugin[];
|
|
27
27
|
export declare function createEditor(options: StandardOptions): Editor;
|
|
28
|
-
export { Editor, type EditorOptions };
|
package/dist/standard/index.js
CHANGED
package/dist/stats.js
CHANGED
|
@@ -4,7 +4,7 @@ import { selectedText } from "./edit.js";
|
|
|
4
4
|
const WORD = /[\p{L}\p{M}\p{N}]+(?:['’\-‑][\p{L}\p{M}\p{N}]+)*/gu;
|
|
5
5
|
export function countText(text) {
|
|
6
6
|
const clean = text.replace(//g, "").replace(/\n/g, " ");
|
|
7
|
-
return { words: (clean.match(WORD) ?? []).length, characters: [...clean.
|
|
7
|
+
return { words: (clean.match(WORD) ?? []).length, characters: [...clean.trim()].length };
|
|
8
8
|
}
|
|
9
9
|
export function countDocument(doc) {
|
|
10
10
|
let words = 0;
|
package/dist/svg/svg.js
CHANGED
|
@@ -44,7 +44,15 @@ const decodeXml = (value) => value.replace(ENTITY, (_, dec, hex, name) => {
|
|
|
44
44
|
function parseXml(source, limits) {
|
|
45
45
|
if (/<!ENTITY|<!ATTLIST|<!NOTATION/i.test(source) || /<!\[CDATA\[/i.test(source))
|
|
46
46
|
return undefined;
|
|
47
|
-
|
|
47
|
+
let stripped = source.replace(/^/, "").replace(/<\?xml[^>]*\?>/i, "").replace(/<!DOCTYPE[^>[]*(?:\[[^\]]*\])?[^>]*>/gi, "");
|
|
48
|
+
for (let pass = 0; pass < 4; pass++) {
|
|
49
|
+
const next = stripped.replace(/<!--[\s\S]*?-->/g, "");
|
|
50
|
+
if (next === stripped)
|
|
51
|
+
break;
|
|
52
|
+
stripped = next;
|
|
53
|
+
}
|
|
54
|
+
if (stripped.includes("<!--"))
|
|
55
|
+
return undefined;
|
|
48
56
|
const stack = [];
|
|
49
57
|
let root;
|
|
50
58
|
let count = 0;
|
package/dist/tables/cells.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ViewHost } from "../plugin.ts";
|
|
2
2
|
/** The attribute on a cell that a selection covers, for styling. */
|
|
3
|
-
export declare const SELECTED_CELL = "data-
|
|
3
|
+
export declare const SELECTED_CELL = "data-rte-cell-selected";
|
|
4
4
|
/**
|
|
5
5
|
* Marks the cells of the rectangle a selection runs across (when it starts and ends in different cells of one table). The marks are
|
|
6
6
|
* attributes on the drawn cells, not part of the model, and they are put on again after every change.
|
package/dist/tables/cells.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { pathKey } from "../path.js";
|
|
2
2
|
import { inRow, locateCell, selectedCells } from "../tablegrid.js";
|
|
3
|
-
export const SELECTED_CELL = "data-
|
|
3
|
+
export const SELECTED_CELL = "data-rte-cell-selected";
|
|
4
4
|
const GRAB = 5;
|
|
5
5
|
const MIN_WIDTH = 24;
|
|
6
6
|
const MIN_HEIGHT = 16;
|
|
@@ -96,7 +96,7 @@ export function installColumnResize(host) {
|
|
|
96
96
|
const rowBox = row.getBoundingClientRect();
|
|
97
97
|
const rowTable = rowCell.closest("table")?.getBoundingClientRect() ?? rowBox;
|
|
98
98
|
const rowLine = document.createElement("div");
|
|
99
|
-
rowLine.setAttribute("data-
|
|
99
|
+
rowLine.setAttribute("data-rte-resize-line", "");
|
|
100
100
|
rowLine.style.cssText = `position:fixed;z-index:2147483647;pointer-events:none;height:2px;background:#17408b;top:${rowBox.bottom - 1}px;left:${rowTable.left}px;width:${rowTable.width}px`;
|
|
101
101
|
document.body.appendChild(rowLine);
|
|
102
102
|
rowDrag = { path: rowPath, startY: event.clientY, startHeight: rowBox.height, top: rowBox.top, line: rowLine, height: rowBox.height };
|
|
@@ -106,7 +106,7 @@ export function installColumnResize(host) {
|
|
|
106
106
|
const box = cell.getBoundingClientRect();
|
|
107
107
|
const table = cell.closest("table")?.getBoundingClientRect() ?? box;
|
|
108
108
|
const line = document.createElement("div");
|
|
109
|
-
line.setAttribute("data-
|
|
109
|
+
line.setAttribute("data-rte-resize-line", "");
|
|
110
110
|
line.style.cssText = `position:fixed;z-index:2147483647;pointer-events:none;width:2px;background:#17408b;left:${box.right - 1}px;top:${table.top}px;height:${table.height}px`;
|
|
111
111
|
document.body.appendChild(line);
|
|
112
112
|
drag = { cell, path, startX: event.clientX, startWidth: box.width, line, width: box.width };
|
package/dist/tables/grips.js
CHANGED
|
@@ -82,7 +82,7 @@ export class TableGrips {
|
|
|
82
82
|
}
|
|
83
83
|
make(kind) {
|
|
84
84
|
const el = document.createElement("div");
|
|
85
|
-
el.setAttribute("data-
|
|
85
|
+
el.setAttribute("data-rte-grip", kind);
|
|
86
86
|
el.setAttribute("role", "presentation");
|
|
87
87
|
const cursor = kind === "row" ? "ns-resize" : kind === "column" ? "ew-resize" : kind === "width" ? "col-resize" : "row-resize";
|
|
88
88
|
el.style.cssText = `position:fixed;z-index:2147483646;width:${SIZE}px;height:${SIZE}px;box-sizing:border-box;background:${COLOR};border:2px solid #fff;border-radius:${kind === "row" || kind === "column" ? "4px" : "50%"};cursor:${cursor};touch-action:none;opacity:0.9`;
|
|
@@ -120,7 +120,7 @@ export class TableGrips {
|
|
|
120
120
|
const t = table.getBoundingClientRect();
|
|
121
121
|
const horizontal = kind === "column" || kind === "width";
|
|
122
122
|
const line = document.createElement("div");
|
|
123
|
-
line.setAttribute("data-
|
|
123
|
+
line.setAttribute("data-rte-resize-line", "");
|
|
124
124
|
line.style.cssText = `position:fixed;z-index:2147483645;pointer-events:none;background:${COLOR};${horizontal ? `width:2px;top:${t.top}px;height:${t.height}px` : `height:2px;left:${t.left}px;width:${t.width}px`}`;
|
|
125
125
|
document.body.appendChild(line);
|
|
126
126
|
this.guide = line;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/** Why a warning was made. The codes are stable: a host can switch on them. */
|
|
2
|
+
export declare const WARNING_CODES: readonly ["plugin-failed", "plugin-rejected", "plugin-message", "key-conflict", "content-too-long", "content-unreadable", "copy-failed", "upload-failed", "bad-option", "missing-label", "late-options", "listener-failed"];
|
|
3
|
+
/** One of the codes in `WARNING_CODES`. */
|
|
4
|
+
export type WarningCode = (typeof WARNING_CODES)[number];
|
|
5
|
+
/** A problem the editor carried on from, reported to `onWarning`. Never thrown. */
|
|
6
|
+
export interface Warning {
|
|
7
|
+
readonly code: WarningCode;
|
|
8
|
+
/** For a person: what happened and what was done about it. */
|
|
9
|
+
readonly message: string;
|
|
10
|
+
/** The plugin it concerns, when there is one. */
|
|
11
|
+
readonly plugin?: string;
|
|
12
|
+
/** The error that was caught, when one was. */
|
|
13
|
+
readonly error?: unknown;
|
|
14
|
+
}
|
|
15
|
+
/** What an error says, whatever was thrown. */
|
|
16
|
+
export declare const describeError: (error: unknown) => string;
|
package/dist/warning.js
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export const WARNING_CODES = [
|
|
2
|
+
"plugin-failed", "plugin-rejected", "plugin-message", "key-conflict", "content-too-long", "content-unreadable",
|
|
3
|
+
"copy-failed", "upload-failed", "bad-option", "missing-label", "late-options", "listener-failed",
|
|
4
|
+
];
|
|
5
|
+
export const describeError = (error) => (error instanceof Error ? error.message : String(error));
|