@react-x11/components 0.8.0 → 0.9.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 +95 -34
- package/dist/charts/node.d.ts +1 -1
- package/dist/charts/node.d.ts.map +1 -1
- package/dist/charts/node.js +6 -2
- package/dist/charts/node.js.map +1 -1
- package/dist/embed/client.d.ts +48 -3
- package/dist/embed/client.d.ts.map +1 -1
- package/dist/embed/client.js +79 -5
- package/dist/embed/client.js.map +1 -1
- package/dist/embed/index.d.ts +1 -1
- package/dist/embed/index.d.ts.map +1 -1
- package/dist/embed/index.js +1 -1
- package/dist/embed/index.js.map +1 -1
- package/dist/html/node.d.ts +3 -1
- package/dist/html/node.d.ts.map +1 -1
- package/dist/html/node.js +7 -5
- package/dist/html/node.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/{markdown → internal/markdown}/ast.d.ts +12 -0
- package/dist/internal/markdown/ast.d.ts.map +1 -0
- package/dist/internal/markdown/ast.js +22 -0
- package/dist/internal/markdown/ast.js.map +1 -0
- package/dist/internal/markdown/parse.d.ts.map +1 -0
- package/dist/{markdown → internal/markdown}/parse.js +112 -22
- package/dist/internal/markdown/parse.js.map +1 -0
- package/dist/internal/markdown/stringify.d.ts +4 -0
- package/dist/internal/markdown/stringify.d.ts.map +1 -0
- package/dist/internal/markdown/stringify.js +684 -0
- package/dist/internal/markdown/stringify.js.map +1 -0
- package/dist/internal/markdown/tags.d.ts.map +1 -0
- package/dist/internal/markdown/tags.js.map +1 -0
- package/dist/internal/scroll.d.ts +3 -2
- package/dist/internal/scroll.d.ts.map +1 -1
- package/dist/internal/scroll.js +1 -0
- package/dist/internal/scroll.js.map +1 -1
- package/dist/maps/anchors.d.ts +98 -0
- package/dist/maps/anchors.d.ts.map +1 -0
- package/dist/maps/anchors.js +531 -0
- package/dist/maps/anchors.js.map +1 -0
- package/dist/maps/controller.d.ts +283 -0
- package/dist/maps/controller.d.ts.map +1 -0
- package/dist/maps/controller.js +743 -0
- package/dist/maps/controller.js.map +1 -0
- package/dist/maps/gl/buckets.d.ts +95 -0
- package/dist/maps/gl/buckets.d.ts.map +1 -0
- package/dist/maps/gl/buckets.js +362 -0
- package/dist/maps/gl/buckets.js.map +1 -0
- package/dist/maps/gl/build-worker.d.ts +13 -0
- package/dist/maps/gl/build-worker.d.ts.map +1 -0
- package/dist/maps/gl/build-worker.js +44 -0
- package/dist/maps/gl/build-worker.js.map +1 -0
- package/dist/maps/gl/color.d.ts +8 -0
- package/dist/maps/gl/color.d.ts.map +1 -0
- package/dist/maps/gl/color.js +57 -0
- package/dist/maps/gl/color.js.map +1 -0
- package/dist/maps/gl/cover.d.ts +51 -0
- package/dist/maps/gl/cover.d.ts.map +1 -0
- package/dist/maps/gl/cover.js +124 -0
- package/dist/maps/gl/cover.js.map +1 -0
- package/dist/maps/gl/index.d.ts +3 -0
- package/dist/maps/gl/index.d.ts.map +1 -0
- package/dist/maps/gl/index.js +20 -0
- package/dist/maps/gl/index.js.map +1 -0
- package/dist/maps/gl/markers.d.ts +28 -0
- package/dist/maps/gl/markers.d.ts.map +1 -0
- package/dist/maps/gl/markers.js +60 -0
- package/dist/maps/gl/markers.js.map +1 -0
- package/dist/maps/gl/overlays.d.ts +68 -0
- package/dist/maps/gl/overlays.d.ts.map +1 -0
- package/dist/maps/gl/overlays.js +300 -0
- package/dist/maps/gl/overlays.js.map +1 -0
- package/dist/maps/gl/pane.d.ts +12 -0
- package/dist/maps/gl/pane.d.ts.map +1 -0
- package/dist/maps/gl/pane.js +37 -0
- package/dist/maps/gl/pane.js.map +1 -0
- package/dist/maps/gl/placement.d.ts +111 -0
- package/dist/maps/gl/placement.d.ts.map +1 -0
- package/dist/maps/gl/placement.js +567 -0
- package/dist/maps/gl/placement.js.map +1 -0
- package/dist/maps/gl/renderer.d.ts +352 -0
- package/dist/maps/gl/renderer.d.ts.map +1 -0
- package/dist/maps/gl/renderer.js +1127 -0
- package/dist/maps/gl/renderer.js.map +1 -0
- package/dist/maps/gl/shaders.d.ts +120 -0
- package/dist/maps/gl/shaders.d.ts.map +1 -0
- package/dist/maps/gl/shaders.js +451 -0
- package/dist/maps/gl/shaders.js.map +1 -0
- package/dist/maps/gl/store.d.ts +115 -0
- package/dist/maps/gl/store.d.ts.map +1 -0
- package/dist/maps/gl/store.js +469 -0
- package/dist/maps/gl/store.js.map +1 -0
- package/dist/maps/gl/text.d.ts +154 -0
- package/dist/maps/gl/text.d.ts.map +1 -0
- package/dist/maps/gl/text.js +382 -0
- package/dist/maps/gl/text.js.map +1 -0
- package/dist/maps/gl/view.d.ts +54 -0
- package/dist/maps/gl/view.d.ts.map +1 -0
- package/dist/maps/gl/view.js +974 -0
- package/dist/maps/gl/view.js.map +1 -0
- package/dist/maps/index.d.ts +1 -1
- package/dist/maps/index.d.ts.map +1 -1
- package/dist/maps/index.js +216 -52
- package/dist/maps/index.js.map +1 -1
- package/dist/maps/labels.d.ts +37 -16
- package/dist/maps/labels.d.ts.map +1 -1
- package/dist/maps/labels.js +188 -119
- package/dist/maps/labels.js.map +1 -1
- package/dist/maps/node.d.ts +162 -56
- package/dist/maps/node.d.ts.map +1 -1
- package/dist/maps/node.js +607 -515
- package/dist/maps/node.js.map +1 -1
- package/dist/maps/overlay.d.ts +72 -9
- package/dist/maps/overlay.d.ts.map +1 -1
- package/dist/maps/overlay.js +108 -28
- package/dist/maps/overlay.js.map +1 -1
- package/dist/maps/paint.d.ts +3 -0
- package/dist/maps/paint.d.ts.map +1 -1
- package/dist/maps/paint.js.map +1 -1
- package/dist/maps/proj.d.ts +14 -0
- package/dist/maps/proj.d.ts.map +1 -1
- package/dist/maps/proj.js +28 -0
- package/dist/maps/proj.js.map +1 -1
- package/dist/maps/renderer.d.ts +69 -0
- package/dist/maps/renderer.d.ts.map +1 -0
- package/dist/maps/renderer.js +66 -0
- package/dist/maps/renderer.js.map +1 -0
- package/dist/maps/sources.d.ts +25 -3
- package/dist/maps/sources.d.ts.map +1 -1
- package/dist/maps/sources.js +17 -0
- package/dist/maps/sources.js.map +1 -1
- package/dist/maps/theme.d.ts +19 -0
- package/dist/maps/theme.d.ts.map +1 -0
- package/dist/maps/theme.js +44 -0
- package/dist/maps/theme.js.map +1 -0
- package/dist/maps/tiles.d.ts +117 -17
- package/dist/maps/tiles.d.ts.map +1 -1
- package/dist/maps/tiles.js +163 -30
- package/dist/maps/tiles.js.map +1 -1
- package/dist/maps/types.d.ts +188 -20
- package/dist/maps/types.d.ts.map +1 -1
- package/dist/markdown/expressions.d.ts +1 -1
- package/dist/markdown/expressions.d.ts.map +1 -1
- package/dist/markdown/expressions.js.map +1 -1
- package/dist/markdown/index.d.ts +7 -6
- package/dist/markdown/index.d.ts.map +1 -1
- package/dist/markdown/index.js +9 -7
- package/dist/markdown/index.js.map +1 -1
- package/dist/markdown/spans.d.ts +1 -1
- package/dist/markdown/spans.d.ts.map +1 -1
- package/dist/media-player/index.d.ts +11 -3
- package/dist/media-player/index.d.ts.map +1 -1
- package/dist/media-player/index.js +13 -2
- package/dist/media-player/index.js.map +1 -1
- package/dist/rich-text-editor/clipboard.d.ts +23 -0
- package/dist/rich-text-editor/clipboard.d.ts.map +1 -0
- package/dist/rich-text-editor/clipboard.js +307 -0
- package/dist/rich-text-editor/clipboard.js.map +1 -0
- package/dist/rich-text-editor/collab.d.ts +32 -0
- package/dist/rich-text-editor/collab.d.ts.map +1 -0
- package/dist/rich-text-editor/collab.js +55 -0
- package/dist/rich-text-editor/collab.js.map +1 -0
- package/dist/rich-text-editor/commands.d.ts +50 -0
- package/dist/rich-text-editor/commands.d.ts.map +1 -0
- package/dist/rich-text-editor/commands.js +376 -0
- package/dist/rich-text-editor/commands.js.map +1 -0
- package/dist/rich-text-editor/drag.d.ts +68 -0
- package/dist/rich-text-editor/drag.d.ts.map +1 -0
- package/dist/rich-text-editor/drag.js +148 -0
- package/dist/rich-text-editor/drag.js.map +1 -0
- package/dist/rich-text-editor/html.d.ts +145 -0
- package/dist/rich-text-editor/html.d.ts.map +1 -0
- package/dist/rich-text-editor/html.js +516 -0
- package/dist/rich-text-editor/html.js.map +1 -0
- package/dist/rich-text-editor/index.d.ts +263 -0
- package/dist/rich-text-editor/index.d.ts.map +1 -0
- package/dist/rich-text-editor/index.js +822 -0
- package/dist/rich-text-editor/index.js.map +1 -0
- package/dist/rich-text-editor/inline.d.ts +94 -0
- package/dist/rich-text-editor/inline.d.ts.map +1 -0
- package/dist/rich-text-editor/inline.js +252 -0
- package/dist/rich-text-editor/inline.js.map +1 -0
- package/dist/rich-text-editor/keymap.d.ts +71 -0
- package/dist/rich-text-editor/keymap.d.ts.map +1 -0
- package/dist/rich-text-editor/keymap.js +393 -0
- package/dist/rich-text-editor/keymap.js.map +1 -0
- package/dist/rich-text-editor/keys.d.ts +29 -0
- package/dist/rich-text-editor/keys.d.ts.map +1 -0
- package/dist/rich-text-editor/keys.js +93 -0
- package/dist/rich-text-editor/keys.js.map +1 -0
- package/dist/rich-text-editor/look.d.ts +71 -0
- package/dist/rich-text-editor/look.d.ts.map +1 -0
- package/dist/rich-text-editor/look.js +342 -0
- package/dist/rich-text-editor/look.js.map +1 -0
- package/dist/rich-text-editor/markdown.d.ts +18 -0
- package/dist/rich-text-editor/markdown.d.ts.map +1 -0
- package/dist/rich-text-editor/markdown.js +496 -0
- package/dist/rich-text-editor/markdown.js.map +1 -0
- package/dist/rich-text-editor/nodes.d.ts +135 -0
- package/dist/rich-text-editor/nodes.d.ts.map +1 -0
- package/dist/rich-text-editor/nodes.js +397 -0
- package/dist/rich-text-editor/nodes.js.map +1 -0
- package/dist/rich-text-editor/render.d.ts +68 -0
- package/dist/rich-text-editor/render.d.ts.map +1 -0
- package/dist/rich-text-editor/render.js +500 -0
- package/dist/rich-text-editor/render.js.map +1 -0
- package/dist/rich-text-editor/schema.d.ts +16 -0
- package/dist/rich-text-editor/schema.d.ts.map +1 -0
- package/dist/rich-text-editor/schema.js +386 -0
- package/dist/rich-text-editor/schema.js.map +1 -0
- package/dist/rich-text-editor/store.d.ts +11 -0
- package/dist/rich-text-editor/store.d.ts.map +1 -0
- package/dist/rich-text-editor/store.js +43 -0
- package/dist/rich-text-editor/store.js.map +1 -0
- package/dist/rich-text-editor/suggest.d.ts +127 -0
- package/dist/rich-text-editor/suggest.d.ts.map +1 -0
- package/dist/rich-text-editor/suggest.js +0 -0
- package/dist/rich-text-editor/suggest.js.map +1 -0
- package/dist/rich-text-editor/tables.d.ts +41 -0
- package/dist/rich-text-editor/tables.d.ts.map +1 -0
- package/dist/rich-text-editor/tables.js +204 -0
- package/dist/rich-text-editor/tables.js.map +1 -0
- package/dist/rich-text-editor/toolbar.d.ts +58 -0
- package/dist/rich-text-editor/toolbar.d.ts.map +1 -0
- package/dist/rich-text-editor/toolbar.js +548 -0
- package/dist/rich-text-editor/toolbar.js.map +1 -0
- package/dist/rich-text-editor/view.d.ts +368 -0
- package/dist/rich-text-editor/view.d.ts.map +1 -0
- package/dist/rich-text-editor/view.js +1968 -0
- package/dist/rich-text-editor/view.js.map +1 -0
- package/dist/rich-text-editor/virtual.d.ts +54 -0
- package/dist/rich-text-editor/virtual.d.ts.map +1 -0
- package/dist/rich-text-editor/virtual.js +262 -0
- package/dist/rich-text-editor/virtual.js.map +1 -0
- package/dist/richtext/node.d.ts +25 -2
- package/dist/richtext/node.d.ts.map +1 -1
- package/dist/richtext/node.js +46 -24
- package/dist/richtext/node.js.map +1 -1
- package/dist/terminal/backends.d.ts +4 -1
- package/dist/terminal/backends.d.ts.map +1 -1
- package/dist/terminal/backends.js.map +1 -1
- package/dist/terminal/index.d.ts +18 -7
- package/dist/terminal/index.d.ts.map +1 -1
- package/dist/terminal/index.js +28 -11
- package/dist/terminal/index.js.map +1 -1
- package/package.json +23 -4
- package/src/charts/node.ts +6 -2
- package/src/embed/client.ts +102 -8
- package/src/embed/index.ts +2 -0
- package/src/html/node.ts +7 -5
- package/src/index.ts +2 -0
- package/src/{markdown → internal/markdown}/ast.ts +24 -7
- package/src/{markdown → internal/markdown}/parse.ts +134 -24
- package/src/internal/markdown/stringify.ts +772 -0
- package/src/internal/scroll.ts +5 -3
- package/src/maps/anchors.ts +607 -0
- package/src/maps/controller.ts +999 -0
- package/src/maps/gl/buckets.ts +457 -0
- package/src/maps/gl/build-worker.ts +55 -0
- package/src/maps/gl/color.ts +62 -0
- package/src/maps/gl/cover.ts +170 -0
- package/src/maps/gl/index.ts +23 -0
- package/src/maps/gl/markers.ts +83 -0
- package/src/maps/gl/overlays.ts +379 -0
- package/src/maps/gl/pane.ts +42 -0
- package/src/maps/gl/placement.ts +816 -0
- package/src/maps/gl/renderer.ts +1576 -0
- package/src/maps/gl/shaders.ts +486 -0
- package/src/maps/gl/store.ts +566 -0
- package/src/maps/gl/text.ts +495 -0
- package/src/maps/gl/view.ts +1224 -0
- package/src/maps/index.ts +270 -81
- package/src/maps/labels.ts +214 -121
- package/src/maps/node.ts +763 -629
- package/src/maps/overlay.ts +148 -43
- package/src/maps/paint.ts +3 -0
- package/src/maps/proj.ts +31 -0
- package/src/maps/renderer.ts +155 -0
- package/src/maps/sources.ts +38 -3
- package/src/maps/theme.ts +51 -0
- package/src/maps/tiles.ts +191 -33
- package/src/maps/types.ts +188 -20
- package/src/markdown/expressions.ts +5 -1
- package/src/markdown/index.ts +14 -11
- package/src/markdown/spans.ts +1 -1
- package/src/media-player/index.ts +18 -4
- package/src/rich-text-editor/clipboard.ts +439 -0
- package/src/rich-text-editor/collab.ts +91 -0
- package/src/rich-text-editor/commands.ts +448 -0
- package/src/rich-text-editor/dom-globals.d.ts +23 -0
- package/src/rich-text-editor/drag.ts +211 -0
- package/src/rich-text-editor/html.ts +619 -0
- package/src/rich-text-editor/index.ts +1331 -0
- package/src/rich-text-editor/inline.ts +345 -0
- package/src/rich-text-editor/keymap.ts +510 -0
- package/src/rich-text-editor/keys.ts +119 -0
- package/src/rich-text-editor/look.ts +427 -0
- package/src/rich-text-editor/markdown.ts +653 -0
- package/src/rich-text-editor/nodes.ts +497 -0
- package/src/rich-text-editor/render.ts +800 -0
- package/src/rich-text-editor/schema.ts +431 -0
- package/src/rich-text-editor/store.ts +39 -0
- package/src/rich-text-editor/suggest.ts +597 -0
- package/src/rich-text-editor/tables.ts +272 -0
- package/src/rich-text-editor/toolbar.ts +724 -0
- package/src/rich-text-editor/view.ts +2287 -0
- package/src/rich-text-editor/virtual.ts +347 -0
- package/src/richtext/node.ts +59 -30
- package/src/terminal/backends.ts +4 -1
- package/src/terminal/index.ts +43 -15
- package/dist/markdown/ast.d.ts.map +0 -1
- package/dist/markdown/ast.js +0 -17
- package/dist/markdown/ast.js.map +0 -1
- package/dist/markdown/parse.d.ts.map +0 -1
- package/dist/markdown/parse.js.map +0 -1
- package/dist/markdown/tags.d.ts.map +0 -1
- package/dist/markdown/tags.js.map +0 -1
- /package/dist/{markdown → internal/markdown}/parse.d.ts +0 -0
- /package/dist/{markdown → internal/markdown}/tags.d.ts +0 -0
- /package/dist/{markdown → internal/markdown}/tags.js +0 -0
- /package/src/{markdown → internal/markdown}/tags.ts +0 -0
|
@@ -0,0 +1,431 @@
|
|
|
1
|
+
// The document the editor edits when the app does not bring one: GitHub-
|
|
2
|
+
// flavoured markdown, written in ProseMirror's reference vocabulary.
|
|
3
|
+
//
|
|
4
|
+
// The node and mark names are prosemirror-schema-basic's and
|
|
5
|
+
// prosemirror-schema-list's, with prosemirror-markdown's attributes (`order`,
|
|
6
|
+
// `tight`, `params`) — so a command, an input rule or a plugin written
|
|
7
|
+
// against the reference schema works on this one unchanged. What GFM adds is
|
|
8
|
+
// named the way the ecosystem already names it: `strike`, a `checked`
|
|
9
|
+
// attribute on `list_item` for task items, and table nodes whose `tableRole`s
|
|
10
|
+
// and cell attributes are prosemirror-tables' own, so that package's commands
|
|
11
|
+
// can be pointed at a document of this schema.
|
|
12
|
+
//
|
|
13
|
+
// `parseDOM`/`toDOM` are not decoration either. They are how HTML comes in
|
|
14
|
+
// (a paste from a browser, `format="html"`) and goes out (a copy another
|
|
15
|
+
// application can read, `format="html"`), through ProseMirror's own
|
|
16
|
+
// DOMParser and DOMSerializer over the DOM-shaped shim in `./html.ts`. The
|
|
17
|
+
// editor does not *draw* from them — `./render.ts` does that — except for a
|
|
18
|
+
// node or mark of an app's schema that nothing more specific describes,
|
|
19
|
+
// where `toDOM`'s tag is read as a statement of what the node is.
|
|
20
|
+
import { Schema } from 'prosemirror-model';
|
|
21
|
+
import type {
|
|
22
|
+
Attrs,
|
|
23
|
+
DOMOutputSpec,
|
|
24
|
+
MarkSpec,
|
|
25
|
+
Node as PMNode,
|
|
26
|
+
NodeSpec,
|
|
27
|
+
} from 'prosemirror-model';
|
|
28
|
+
|
|
29
|
+
/** The DOM surface `getAttrs` reads, whether it is a browser's element or
|
|
30
|
+
* the shim's — named here so the rules below say what they need. */
|
|
31
|
+
interface ElementLike {
|
|
32
|
+
getAttribute(name: string): string | null;
|
|
33
|
+
hasAttribute(name: string): boolean;
|
|
34
|
+
readonly childNodes: ArrayLike<ElementLike>;
|
|
35
|
+
readonly nodeName: string;
|
|
36
|
+
readonly style?: { textAlign?: string; fontWeight?: string };
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function el(dom: unknown): ElementLike {
|
|
40
|
+
return dom as ElementLike;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** `language-js` on a `<pre>` or the `<code>` in it: how every HTML
|
|
44
|
+
* highlighter marks a block's language. */
|
|
45
|
+
function fenceParams(dom: ElementLike): string {
|
|
46
|
+
const own = dom.getAttribute('data-params');
|
|
47
|
+
if (own != null) return own;
|
|
48
|
+
const classes = [dom.getAttribute('class') ?? ''];
|
|
49
|
+
for (const child of Array.from(dom.childNodes)) {
|
|
50
|
+
if (child.nodeName === 'CODE')
|
|
51
|
+
classes.push(child.getAttribute('class') ?? '');
|
|
52
|
+
}
|
|
53
|
+
for (const cls of classes) {
|
|
54
|
+
const m = /(?:^|\s)(?:language|lang)-(\S+)/.exec(cls);
|
|
55
|
+
if (m) return m[1];
|
|
56
|
+
}
|
|
57
|
+
return '';
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* A GFM task item's state, from the HTML GitHub renders one as: a disabled
|
|
62
|
+
* checkbox as the item's first content, directly or inside its first
|
|
63
|
+
* paragraph. `data-checked` is what this schema writes itself. Only the item's
|
|
64
|
+
* own box counts — a nested list's checkboxes are its items' business.
|
|
65
|
+
*/
|
|
66
|
+
function taskState(dom: ElementLike): boolean | null {
|
|
67
|
+
const flag = dom.getAttribute('data-checked');
|
|
68
|
+
if (flag === 'true') return true;
|
|
69
|
+
if (flag === 'false') return false;
|
|
70
|
+
const kids = Array.from(dom.childNodes);
|
|
71
|
+
const first = kids.find((k) => k.nodeName !== '#text') ?? null;
|
|
72
|
+
const candidates = first
|
|
73
|
+
? [first, ...(first.nodeName === 'P' ? Array.from(first.childNodes) : [])]
|
|
74
|
+
: [];
|
|
75
|
+
for (const node of candidates) {
|
|
76
|
+
if (
|
|
77
|
+
node.nodeName === 'INPUT' &&
|
|
78
|
+
(node.getAttribute('type') ?? '').toLowerCase() === 'checkbox'
|
|
79
|
+
) {
|
|
80
|
+
return node.hasAttribute('checked');
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
type Align = 'left' | 'center' | 'right' | null;
|
|
87
|
+
|
|
88
|
+
function alignOf(value: string | null | undefined): Align {
|
|
89
|
+
const v = (value ?? '').trim().toLowerCase();
|
|
90
|
+
return v === 'left' || v === 'center' || v === 'right' ? v : null;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/** prosemirror-tables' cell attributes, plus GFM's column alignment. */
|
|
94
|
+
const cellAttrs = {
|
|
95
|
+
colspan: { default: 1 },
|
|
96
|
+
rowspan: { default: 1 },
|
|
97
|
+
colwidth: { default: null },
|
|
98
|
+
align: { default: null },
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
function getCellAttrs(dom: unknown): Attrs {
|
|
102
|
+
const e = el(dom);
|
|
103
|
+
const widthAttr = e.getAttribute('data-colwidth');
|
|
104
|
+
const colspan = Number(e.getAttribute('colspan') || 1);
|
|
105
|
+
const widths =
|
|
106
|
+
widthAttr && /^\d+(,\d+)*$/.test(widthAttr)
|
|
107
|
+
? widthAttr.split(',').map(Number)
|
|
108
|
+
: null;
|
|
109
|
+
return {
|
|
110
|
+
colspan,
|
|
111
|
+
rowspan: Number(e.getAttribute('rowspan') || 1),
|
|
112
|
+
colwidth: widths && widths.length === colspan ? widths : null,
|
|
113
|
+
align: alignOf(e.getAttribute('align') ?? e.style?.textAlign),
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function setCellAttrs(node: PMNode): Record<string, string> {
|
|
118
|
+
const attrs: Record<string, string> = {};
|
|
119
|
+
if (node.attrs.colspan !== 1) attrs.colspan = String(node.attrs.colspan);
|
|
120
|
+
if (node.attrs.rowspan !== 1) attrs.rowspan = String(node.attrs.rowspan);
|
|
121
|
+
if (node.attrs.colwidth) {
|
|
122
|
+
attrs['data-colwidth'] = (node.attrs.colwidth as number[]).join(',');
|
|
123
|
+
}
|
|
124
|
+
if (node.attrs.align) attrs.style = `text-align: ${node.attrs.align}`;
|
|
125
|
+
return attrs;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/** The node specs, in the order the schema ranks them. Exported so an app
|
|
129
|
+
* can build on them — `new Schema({ nodes: schema.spec.nodes.addBefore(…),
|
|
130
|
+
* marks: schema.spec.marks })` is ProseMirror's own idiom for that. */
|
|
131
|
+
export const nodes: Record<string, NodeSpec> = {
|
|
132
|
+
doc: { content: 'block+' },
|
|
133
|
+
|
|
134
|
+
paragraph: {
|
|
135
|
+
content: 'inline*',
|
|
136
|
+
group: 'block',
|
|
137
|
+
parseDOM: [{ tag: 'p' }],
|
|
138
|
+
toDOM: (): DOMOutputSpec => ['p', 0],
|
|
139
|
+
},
|
|
140
|
+
|
|
141
|
+
blockquote: {
|
|
142
|
+
content: 'block+',
|
|
143
|
+
group: 'block',
|
|
144
|
+
defining: true,
|
|
145
|
+
parseDOM: [{ tag: 'blockquote' }],
|
|
146
|
+
toDOM: (): DOMOutputSpec => ['blockquote', 0],
|
|
147
|
+
},
|
|
148
|
+
|
|
149
|
+
horizontal_rule: {
|
|
150
|
+
group: 'block',
|
|
151
|
+
parseDOM: [{ tag: 'hr' }],
|
|
152
|
+
toDOM: (): DOMOutputSpec => ['hr'],
|
|
153
|
+
},
|
|
154
|
+
|
|
155
|
+
heading: {
|
|
156
|
+
attrs: { level: { default: 1, validate: 'number' } },
|
|
157
|
+
content: 'inline*',
|
|
158
|
+
group: 'block',
|
|
159
|
+
defining: true,
|
|
160
|
+
parseDOM: [1, 2, 3, 4, 5, 6].map((level) => ({
|
|
161
|
+
tag: `h${level}`,
|
|
162
|
+
attrs: { level },
|
|
163
|
+
})),
|
|
164
|
+
toDOM: (node): DOMOutputSpec => [`h${node.attrs.level}`, 0],
|
|
165
|
+
},
|
|
166
|
+
|
|
167
|
+
code_block: {
|
|
168
|
+
// the whole info string, as prosemirror-markdown keeps it; the language
|
|
169
|
+
// is its first word
|
|
170
|
+
attrs: { params: { default: '', validate: 'string' } },
|
|
171
|
+
content: 'text*',
|
|
172
|
+
marks: '',
|
|
173
|
+
group: 'block',
|
|
174
|
+
code: true,
|
|
175
|
+
defining: true,
|
|
176
|
+
parseDOM: [
|
|
177
|
+
{
|
|
178
|
+
tag: 'pre',
|
|
179
|
+
preserveWhitespace: 'full',
|
|
180
|
+
getAttrs: (dom) => ({ params: fenceParams(el(dom)) }),
|
|
181
|
+
},
|
|
182
|
+
],
|
|
183
|
+
toDOM: (node): DOMOutputSpec => {
|
|
184
|
+
const params = String(node.attrs.params ?? '');
|
|
185
|
+
const lang = params.split(/\s/, 1)[0];
|
|
186
|
+
return [
|
|
187
|
+
'pre',
|
|
188
|
+
params ? { 'data-params': params } : {},
|
|
189
|
+
['code', lang ? { class: `language-${lang}` } : {}, 0],
|
|
190
|
+
];
|
|
191
|
+
},
|
|
192
|
+
},
|
|
193
|
+
|
|
194
|
+
ordered_list: {
|
|
195
|
+
attrs: {
|
|
196
|
+
order: { default: 1, validate: 'number' },
|
|
197
|
+
tight: { default: true },
|
|
198
|
+
},
|
|
199
|
+
content: 'list_item+',
|
|
200
|
+
group: 'block',
|
|
201
|
+
parseDOM: [
|
|
202
|
+
{
|
|
203
|
+
tag: 'ol',
|
|
204
|
+
getAttrs: (dom) => {
|
|
205
|
+
const e = el(dom);
|
|
206
|
+
return {
|
|
207
|
+
order: e.hasAttribute('start')
|
|
208
|
+
? Number(e.getAttribute('start'))
|
|
209
|
+
: 1,
|
|
210
|
+
tight: e.getAttribute('data-tight') !== 'false',
|
|
211
|
+
};
|
|
212
|
+
},
|
|
213
|
+
},
|
|
214
|
+
],
|
|
215
|
+
toDOM: (node): DOMOutputSpec => [
|
|
216
|
+
'ol',
|
|
217
|
+
{
|
|
218
|
+
start: node.attrs.order === 1 ? null : String(node.attrs.order),
|
|
219
|
+
'data-tight': node.attrs.tight ? null : 'false',
|
|
220
|
+
},
|
|
221
|
+
0,
|
|
222
|
+
],
|
|
223
|
+
},
|
|
224
|
+
|
|
225
|
+
bullet_list: {
|
|
226
|
+
attrs: { tight: { default: true } },
|
|
227
|
+
content: 'list_item+',
|
|
228
|
+
group: 'block',
|
|
229
|
+
parseDOM: [
|
|
230
|
+
{
|
|
231
|
+
tag: 'ul',
|
|
232
|
+
getAttrs: (dom) => ({
|
|
233
|
+
tight: el(dom).getAttribute('data-tight') !== 'false',
|
|
234
|
+
}),
|
|
235
|
+
},
|
|
236
|
+
],
|
|
237
|
+
toDOM: (node): DOMOutputSpec => [
|
|
238
|
+
'ul',
|
|
239
|
+
{ 'data-tight': node.attrs.tight ? null : 'false' },
|
|
240
|
+
0,
|
|
241
|
+
],
|
|
242
|
+
},
|
|
243
|
+
|
|
244
|
+
list_item: {
|
|
245
|
+
// `null` for a plain item; `true`/`false` is a GFM task item
|
|
246
|
+
attrs: { checked: { default: null } },
|
|
247
|
+
content: 'paragraph block*',
|
|
248
|
+
defining: true,
|
|
249
|
+
parseDOM: [
|
|
250
|
+
{ tag: 'li', getAttrs: (dom) => ({ checked: taskState(el(dom)) }) },
|
|
251
|
+
],
|
|
252
|
+
toDOM: (node): DOMOutputSpec =>
|
|
253
|
+
node.attrs.checked == null
|
|
254
|
+
? ['li', 0]
|
|
255
|
+
: [
|
|
256
|
+
'li',
|
|
257
|
+
{
|
|
258
|
+
class: 'task-list-item',
|
|
259
|
+
'data-checked': String(node.attrs.checked),
|
|
260
|
+
},
|
|
261
|
+
[
|
|
262
|
+
'input',
|
|
263
|
+
{
|
|
264
|
+
type: 'checkbox',
|
|
265
|
+
disabled: '',
|
|
266
|
+
checked: node.attrs.checked ? '' : null,
|
|
267
|
+
},
|
|
268
|
+
],
|
|
269
|
+
['div', 0],
|
|
270
|
+
],
|
|
271
|
+
},
|
|
272
|
+
|
|
273
|
+
table: {
|
|
274
|
+
content: 'table_row+',
|
|
275
|
+
tableRole: 'table',
|
|
276
|
+
isolating: true,
|
|
277
|
+
group: 'block',
|
|
278
|
+
parseDOM: [{ tag: 'table' }],
|
|
279
|
+
toDOM: (): DOMOutputSpec => ['table', ['tbody', 0]],
|
|
280
|
+
},
|
|
281
|
+
|
|
282
|
+
table_row: {
|
|
283
|
+
content: '(table_cell | table_header)*',
|
|
284
|
+
tableRole: 'row',
|
|
285
|
+
parseDOM: [{ tag: 'tr' }],
|
|
286
|
+
toDOM: (): DOMOutputSpec => ['tr', 0],
|
|
287
|
+
},
|
|
288
|
+
|
|
289
|
+
table_cell: {
|
|
290
|
+
// GFM cells hold a line of inline content, not blocks: each cell is a
|
|
291
|
+
// textblock, which is what makes a table typable with nothing special
|
|
292
|
+
content: 'inline*',
|
|
293
|
+
attrs: cellAttrs,
|
|
294
|
+
tableRole: 'cell',
|
|
295
|
+
isolating: true,
|
|
296
|
+
parseDOM: [{ tag: 'td', getAttrs: getCellAttrs }],
|
|
297
|
+
toDOM: (node): DOMOutputSpec => ['td', setCellAttrs(node), 0],
|
|
298
|
+
},
|
|
299
|
+
|
|
300
|
+
table_header: {
|
|
301
|
+
content: 'inline*',
|
|
302
|
+
attrs: cellAttrs,
|
|
303
|
+
tableRole: 'header_cell',
|
|
304
|
+
isolating: true,
|
|
305
|
+
parseDOM: [{ tag: 'th', getAttrs: getCellAttrs }],
|
|
306
|
+
toDOM: (node): DOMOutputSpec => ['th', setCellAttrs(node), 0],
|
|
307
|
+
},
|
|
308
|
+
|
|
309
|
+
text: { group: 'inline' },
|
|
310
|
+
|
|
311
|
+
image: {
|
|
312
|
+
inline: true,
|
|
313
|
+
attrs: {
|
|
314
|
+
src: { validate: 'string' },
|
|
315
|
+
alt: { default: null },
|
|
316
|
+
title: { default: null },
|
|
317
|
+
},
|
|
318
|
+
group: 'inline',
|
|
319
|
+
draggable: true,
|
|
320
|
+
parseDOM: [
|
|
321
|
+
{
|
|
322
|
+
tag: 'img[src]',
|
|
323
|
+
getAttrs: (dom) => {
|
|
324
|
+
const e = el(dom);
|
|
325
|
+
return {
|
|
326
|
+
src: e.getAttribute('src'),
|
|
327
|
+
title: e.getAttribute('title'),
|
|
328
|
+
alt: e.getAttribute('alt'),
|
|
329
|
+
};
|
|
330
|
+
},
|
|
331
|
+
},
|
|
332
|
+
],
|
|
333
|
+
toDOM: (node): DOMOutputSpec => {
|
|
334
|
+
const { src, alt, title } = node.attrs;
|
|
335
|
+
return ['img', { src, alt, title }];
|
|
336
|
+
},
|
|
337
|
+
},
|
|
338
|
+
|
|
339
|
+
hard_break: {
|
|
340
|
+
inline: true,
|
|
341
|
+
group: 'inline',
|
|
342
|
+
selectable: false,
|
|
343
|
+
parseDOM: [{ tag: 'br' }],
|
|
344
|
+
toDOM: (): DOMOutputSpec => ['br'],
|
|
345
|
+
},
|
|
346
|
+
};
|
|
347
|
+
|
|
348
|
+
/** The mark specs. Order is rank: a mark earlier here wraps a later one when
|
|
349
|
+
* both cover the same text, which is what puts `code` innermost. */
|
|
350
|
+
export const marks: Record<string, MarkSpec> = {
|
|
351
|
+
link: {
|
|
352
|
+
attrs: {
|
|
353
|
+
href: { validate: 'string' },
|
|
354
|
+
title: { default: null },
|
|
355
|
+
},
|
|
356
|
+
// typing at the end of a link continues the text, not the link
|
|
357
|
+
inclusive: false,
|
|
358
|
+
parseDOM: [
|
|
359
|
+
{
|
|
360
|
+
tag: 'a[href]',
|
|
361
|
+
getAttrs: (dom) => {
|
|
362
|
+
const e = el(dom);
|
|
363
|
+
return {
|
|
364
|
+
href: e.getAttribute('href'),
|
|
365
|
+
title: e.getAttribute('title'),
|
|
366
|
+
};
|
|
367
|
+
},
|
|
368
|
+
},
|
|
369
|
+
],
|
|
370
|
+
toDOM: (mark): DOMOutputSpec => [
|
|
371
|
+
'a',
|
|
372
|
+
{ href: mark.attrs.href, title: mark.attrs.title },
|
|
373
|
+
0,
|
|
374
|
+
],
|
|
375
|
+
},
|
|
376
|
+
|
|
377
|
+
em: {
|
|
378
|
+
parseDOM: [
|
|
379
|
+
{ tag: 'i' },
|
|
380
|
+
{ tag: 'em' },
|
|
381
|
+
{ style: 'font-style=italic' },
|
|
382
|
+
{ style: 'font-style=normal', clearMark: (m) => m.type.name === 'em' },
|
|
383
|
+
],
|
|
384
|
+
toDOM: (): DOMOutputSpec => ['em', 0],
|
|
385
|
+
},
|
|
386
|
+
|
|
387
|
+
strong: {
|
|
388
|
+
parseDOM: [
|
|
389
|
+
{ tag: 'strong' },
|
|
390
|
+
// Google Docs wraps a whole paste in `<b style="font-weight: normal">`
|
|
391
|
+
{
|
|
392
|
+
tag: 'b',
|
|
393
|
+
getAttrs: (dom) => el(dom).style?.fontWeight !== 'normal' && null,
|
|
394
|
+
},
|
|
395
|
+
{
|
|
396
|
+
style: 'font-weight=400',
|
|
397
|
+
clearMark: (m) => m.type.name === 'strong',
|
|
398
|
+
},
|
|
399
|
+
{
|
|
400
|
+
style: 'font-weight',
|
|
401
|
+
getAttrs: (value) =>
|
|
402
|
+
/^(bold(er)?|[5-9]\d{2,})$/.test(value as string) && null,
|
|
403
|
+
},
|
|
404
|
+
],
|
|
405
|
+
toDOM: (): DOMOutputSpec => ['strong', 0],
|
|
406
|
+
},
|
|
407
|
+
|
|
408
|
+
strike: {
|
|
409
|
+
parseDOM: [
|
|
410
|
+
{ tag: 's' },
|
|
411
|
+
{ tag: 'del' },
|
|
412
|
+
{ tag: 'strike' },
|
|
413
|
+
{ style: 'text-decoration=line-through' },
|
|
414
|
+
{ style: 'text-decoration-line=line-through' },
|
|
415
|
+
],
|
|
416
|
+
toDOM: (): DOMOutputSpec => ['s', 0],
|
|
417
|
+
},
|
|
418
|
+
|
|
419
|
+
code: {
|
|
420
|
+
code: true,
|
|
421
|
+
parseDOM: [{ tag: 'code' }],
|
|
422
|
+
toDOM: (): DOMOutputSpec => ['code', 0],
|
|
423
|
+
},
|
|
424
|
+
};
|
|
425
|
+
|
|
426
|
+
/**
|
|
427
|
+
* The default schema: GFM — paragraphs, six heading levels, quotes, fenced
|
|
428
|
+
* code, rules, bullet/ordered/task lists, tables, images, hard breaks; bold,
|
|
429
|
+
* italic, strikethrough, inline code and links.
|
|
430
|
+
*/
|
|
431
|
+
export const schema = new Schema({ nodes, marks });
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
// A value per block, with a subscription per block.
|
|
2
|
+
//
|
|
3
|
+
// What lets a decoration, or a node selection, repaint the one block it is
|
|
4
|
+
// on: the block's component subscribes to its own key (React's
|
|
5
|
+
// `useSyncExternalStore`), so a plugin lighting up a search match re-renders
|
|
6
|
+
// that paragraph — not the document, and not the chain of memoized blocks
|
|
7
|
+
// between the document and the paragraph, which would each have to be told.
|
|
8
|
+
export class KeyedStore<T> {
|
|
9
|
+
private values = new Map<string, T>();
|
|
10
|
+
private listeners = new Map<string, Set<() => void>>();
|
|
11
|
+
|
|
12
|
+
get(key: string): T | undefined {
|
|
13
|
+
return this.values.get(key);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/** Set, or with `undefined` clear, one key's value. Identical values are
|
|
17
|
+
* not news: nothing is told. */
|
|
18
|
+
set(key: string, value: T | undefined): void {
|
|
19
|
+
if (Object.is(this.values.get(key), value)) return;
|
|
20
|
+
if (value === undefined) this.values.delete(key);
|
|
21
|
+
else this.values.set(key, value);
|
|
22
|
+
const set = this.listeners.get(key);
|
|
23
|
+
if (set) for (const fn of [...set]) fn();
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
keys(): IterableIterator<string> {
|
|
27
|
+
return this.values.keys();
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
subscribe(key: string, fn: () => void): () => void {
|
|
31
|
+
let set = this.listeners.get(key);
|
|
32
|
+
if (!set) this.listeners.set(key, (set = new Set()));
|
|
33
|
+
set.add(fn);
|
|
34
|
+
return () => {
|
|
35
|
+
set.delete(fn);
|
|
36
|
+
if (set.size === 0) this.listeners.delete(key);
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
}
|