@crewlethq/ui 0.29.0 → 0.31.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 +28 -3
- package/dist/ArtifactBar/ArtifactBar.d.ts +13 -1
- package/dist/ArtifactBar/index.js +1 -1
- package/dist/{ArtifactBar-IBWB5POL.css → ArtifactBar-MLMJHWY6.css} +7 -0
- package/dist/ArtifactCover/index.js +2 -2
- package/dist/CommentThread/index.js +2 -2
- package/dist/DataView/index.js +2 -2
- package/dist/Document/Document.d.ts +8 -1
- package/dist/Document/index.js +1 -1
- package/dist/{Document-PQGXJHB7.css → Document-G3YTZIUL.css} +71 -0
- package/dist/EditingStatus/EditingStatus.d.ts +25 -0
- package/dist/EditingStatus/index.d.ts +3 -0
- package/dist/EditingStatus/index.js +2 -0
- package/dist/EditingStatus-NFADEPSX.css +53 -0
- package/dist/Editor-YZ7KG2RD.js +2099 -0
- package/dist/Markdown/grammar.d.ts +170 -0
- package/dist/Markdown/index.d.ts +2 -0
- package/dist/Markdown/index.js +1 -0
- package/dist/RichEditor/Editor.d.ts +17 -0
- package/dist/RichEditor/RichEditor.d.ts +26 -0
- package/dist/RichEditor/codec.d.ts +78 -0
- package/dist/RichEditor/commands.d.ts +89 -0
- package/dist/RichEditor/index.d.ts +4 -0
- package/dist/RichEditor/index.js +8 -0
- package/dist/RichEditor/keys.d.ts +16 -0
- package/dist/RichEditor/nodeviews.d.ts +60 -0
- package/dist/RichEditor/paste.d.ts +47 -0
- package/dist/RichEditor/plugins.d.ts +49 -0
- package/dist/RichEditor/roundtrip.d.ts +14 -0
- package/dist/RichEditor/schema.d.ts +23 -0
- package/dist/RichEditor/types.d.ts +140 -0
- package/dist/RichEditor-NPD2KAPS.css +419 -0
- package/dist/RichEditorMarkdown/index.d.ts +1 -0
- package/dist/RichEditorMarkdown/index.js +3 -0
- package/dist/chunk-3DPIU2Q7.js +28 -0
- package/dist/{chunk-XALUCIG5.js → chunk-6AH2XJ3Q.js} +1 -1
- package/dist/chunk-A4E5YLXO.js +85 -0
- package/dist/{chunk-FKULOLKG.js → chunk-GR55WT4R.js} +1 -1
- package/dist/chunk-IDBHX5SR.js +12 -0
- package/dist/{chunk-WI6K5M5X.js → chunk-M3LUNN7F.js} +1 -1
- package/dist/{chunk-QMBP23BL.js → chunk-P4BOXB6E.js} +17 -1
- package/dist/chunk-SKOYC2CF.js +288 -0
- package/dist/chunk-VOX3YRFO.js +76 -0
- package/dist/chunk-YFW4MTK4.js +749 -0
- package/dist/generated/index.d.ts +4 -0
- package/dist/generated/index.js +50 -44
- package/dist/index.js +50 -44
- package/dist/styles.css +558 -2
- package/package.json +13 -3
- package/dist/{chunk-IFNQKWUO.js → chunk-OC46246T.js} +0 -0
- package/dist/{chunk-RODMM35O.js → chunk-UVJ5FF5V.js} +1 -1
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Markdown grammar every Crewlet surface reads and writes: a CommonMark
|
|
3
|
+
* subset, parsed into blocks and inline matches and never into markup.
|
|
4
|
+
*
|
|
5
|
+
* ONE GRAMMAR FOR READING AND EDITING. An application renders these blocks
|
|
6
|
+
* with its own renderer (which elements, which link schemes, where a picture
|
|
7
|
+
* is fetched from are decisions about its own content), and `RichEditor`
|
|
8
|
+
* builds its document from the same blocks. A page that reads one way and
|
|
9
|
+
* edits another is a page whose author cannot trust what they see, and two
|
|
10
|
+
* copies of a grammar drift the first time somebody fixes one of them.
|
|
11
|
+
*
|
|
12
|
+
* NOTHING HERE PRODUCES MARKUP. The parser answers plain objects and strings,
|
|
13
|
+
* so a renderer that builds elements from them never parses HTML, which is
|
|
14
|
+
* what lets a consumer enforce Trusted Types with no policy at all.
|
|
15
|
+
*
|
|
16
|
+
* WHAT IT READS: ATX headings, paragraphs, emphasis and strong, strikethrough,
|
|
17
|
+
* inline code, fenced code, links, images, autolinks, backslash escapes,
|
|
18
|
+
* bullet and ordered lists (nested), task list items, block quotes, callouts
|
|
19
|
+
* (`> [!NOTE]`, GitHub's alert syntax), tables, thematic breaks and hard line
|
|
20
|
+
* breaks.
|
|
21
|
+
*
|
|
22
|
+
* WHAT IT DELIBERATELY DOES NOT: raw HTML (read as its own text, never
|
|
23
|
+
* parsed), reference links, footnotes, bare autolink literals, setext
|
|
24
|
+
* headings and indented code. Each is a shape these documents do not use, and
|
|
25
|
+
* every one of them is a place a parser grows a branch nobody exercises.
|
|
26
|
+
*/
|
|
27
|
+
export type MarkdownAlign = 'left' | 'center' | 'right';
|
|
28
|
+
/**
|
|
29
|
+
* A callout's tone, by GitHub's alert names: `> [!NOTE]`, `> [!TIP]`,
|
|
30
|
+
* `> [!IMPORTANT]`, `> [!WARNING]` and `> [!CAUTION]`. The syntax is
|
|
31
|
+
* GitHub's so a page reads as a callout on GitHub too, and anywhere else it
|
|
32
|
+
* degrades to a quote whose first line names its tone.
|
|
33
|
+
*/
|
|
34
|
+
export type MarkdownCalloutTone = 'note' | 'tip' | 'important' | 'warning' | 'caution';
|
|
35
|
+
export declare const MARKDOWN_CALLOUT_TONES: readonly MarkdownCalloutTone[];
|
|
36
|
+
/**
|
|
37
|
+
* Each tone's name as a reader sees it, on the callout's own label line: the
|
|
38
|
+
* one set of words a renderer and the editor both draw.
|
|
39
|
+
*/
|
|
40
|
+
export declare const MARKDOWN_CALLOUT_NAMES: Readonly<Record<MarkdownCalloutTone, string>>;
|
|
41
|
+
/** One parsed block. */
|
|
42
|
+
export type MarkdownBlock = {
|
|
43
|
+
kind: 'heading';
|
|
44
|
+
level: number;
|
|
45
|
+
text: string;
|
|
46
|
+
} | {
|
|
47
|
+
kind: 'paragraph';
|
|
48
|
+
text: string;
|
|
49
|
+
} | {
|
|
50
|
+
kind: 'code';
|
|
51
|
+
lang: string;
|
|
52
|
+
text: string;
|
|
53
|
+
fence: MarkdownFence;
|
|
54
|
+
} | {
|
|
55
|
+
kind: 'quote';
|
|
56
|
+
blocks: MarkdownBlock[];
|
|
57
|
+
} | {
|
|
58
|
+
kind: 'callout';
|
|
59
|
+
tone: MarkdownCalloutTone;
|
|
60
|
+
blocks: MarkdownBlock[];
|
|
61
|
+
} | {
|
|
62
|
+
kind: 'list';
|
|
63
|
+
ordered: boolean;
|
|
64
|
+
start: number;
|
|
65
|
+
/** The bullet character (`-`, `*`, `+`) or the ordered delimiter (`.`, `)`). */
|
|
66
|
+
marker: string;
|
|
67
|
+
/** Whether a blank line separates any two of its items. */
|
|
68
|
+
loose: boolean;
|
|
69
|
+
items: MarkdownListItem[];
|
|
70
|
+
} | {
|
|
71
|
+
kind: 'table';
|
|
72
|
+
head: string[];
|
|
73
|
+
align: MarkdownAlign[];
|
|
74
|
+
rows: string[][];
|
|
75
|
+
} | {
|
|
76
|
+
kind: 'rule';
|
|
77
|
+
};
|
|
78
|
+
export type MarkdownFence = '```' | '~~~';
|
|
79
|
+
export interface MarkdownListItem {
|
|
80
|
+
/** null when the item is not a task item, which is not "unticked". */
|
|
81
|
+
checked: boolean | null;
|
|
82
|
+
blocks: MarkdownBlock[];
|
|
83
|
+
}
|
|
84
|
+
/** A top-level block and the source lines it was read from, `[start, end)`. */
|
|
85
|
+
export interface MarkdownSpan {
|
|
86
|
+
block: MarkdownBlock;
|
|
87
|
+
start: number;
|
|
88
|
+
end: number;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Whether a href may be followed at all, and in what form: `http:`, `https:`,
|
|
92
|
+
* `mailto:` and an application's own `#/` routes. Anything else is null.
|
|
93
|
+
*
|
|
94
|
+
* In-app routes (`#/work/ENG-1`) are allowed because they are how a page
|
|
95
|
+
* points at the company's own objects and they cannot leave the application.
|
|
96
|
+
* Everything else must carry an allowed scheme, including, deliberately, a
|
|
97
|
+
* bare `/path` or `guide.html`, which would resolve against whatever origin
|
|
98
|
+
* serves the page and mean nothing to a reader.
|
|
99
|
+
*/
|
|
100
|
+
export declare function safeHref(raw: string): string | null;
|
|
101
|
+
/** Whether `line` closes a fence opened with `marker`. */
|
|
102
|
+
export declare function markdownClosesFence(line: string, marker: MarkdownFence): boolean;
|
|
103
|
+
/** The fence `line` opens, with its info string, or null when it opens none. */
|
|
104
|
+
export declare function markdownFenceOf(line: string): {
|
|
105
|
+
marker: MarkdownFence;
|
|
106
|
+
lang: string;
|
|
107
|
+
} | null;
|
|
108
|
+
/** The ATX heading `line` is, or null. Closing hashes are decoration, not content. */
|
|
109
|
+
export declare function markdownHeadingOf(line: string): {
|
|
110
|
+
level: number;
|
|
111
|
+
title: string;
|
|
112
|
+
} | null;
|
|
113
|
+
/** A document's lines, every line ending normalised to `\n`. */
|
|
114
|
+
export declare function markdownLines(source: string): string[];
|
|
115
|
+
/** Split a document into blocks. Pure, and the only thing that reads lines. */
|
|
116
|
+
export declare function parseMarkdown(source: string): MarkdownBlock[];
|
|
117
|
+
/**
|
|
118
|
+
* Split a document into its top-level blocks AND the lines each was read
|
|
119
|
+
* from, for an editor that keeps the source of every block it did not change.
|
|
120
|
+
*/
|
|
121
|
+
export declare function parseMarkdownSpans(source: string): {
|
|
122
|
+
lines: string[];
|
|
123
|
+
spans: MarkdownSpan[];
|
|
124
|
+
};
|
|
125
|
+
/** What one inline construct captured, by name. */
|
|
126
|
+
export interface MarkdownInlineGroups {
|
|
127
|
+
/** An escaped ASCII punctuation character, without its backslash. */
|
|
128
|
+
esc?: string;
|
|
129
|
+
tick?: string;
|
|
130
|
+
code?: string;
|
|
131
|
+
alt?: string;
|
|
132
|
+
src?: string;
|
|
133
|
+
srcTitle?: string;
|
|
134
|
+
label?: string;
|
|
135
|
+
href?: string;
|
|
136
|
+
hrefTitle?: string;
|
|
137
|
+
auto?: string;
|
|
138
|
+
strong?: string;
|
|
139
|
+
strongUnder?: string;
|
|
140
|
+
em?: string;
|
|
141
|
+
emUnder?: string;
|
|
142
|
+
del?: string;
|
|
143
|
+
}
|
|
144
|
+
/** One inline construct: where it starts and ends in the text, and what it captured. */
|
|
145
|
+
export interface MarkdownInlineMatch {
|
|
146
|
+
index: number;
|
|
147
|
+
end: number;
|
|
148
|
+
groups: MarkdownInlineGroups;
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Every inline construct of `text`, in order: THE ONE WALK every reader of
|
|
152
|
+
* inline Markdown takes, so a renderer, a text flattener and an editor can
|
|
153
|
+
* never disagree about where a construct begins.
|
|
154
|
+
*
|
|
155
|
+
* A fresh pattern per walk: the walk is re-entered for a construct's own
|
|
156
|
+
* content before the outer one has finished, and a shared `g` pattern carries
|
|
157
|
+
* its position in `lastIndex`.
|
|
158
|
+
*/
|
|
159
|
+
export declare function markdownInline(text: string): Generator<MarkdownInlineMatch>;
|
|
160
|
+
/**
|
|
161
|
+
* A code span's content as it reads: ONE leading and one trailing space go,
|
|
162
|
+
* which is how CommonMark lets a span start with a backtick of its own.
|
|
163
|
+
*/
|
|
164
|
+
export declare function markdownCodeText(code: string): string;
|
|
165
|
+
/**
|
|
166
|
+
* The splits a run of text breaks at: two trailing spaces or a backslash
|
|
167
|
+
* before a newline is a HARD break; every other newline is soft. With
|
|
168
|
+
* `hard`, every newline is a break and the two markers are consumed with it.
|
|
169
|
+
*/
|
|
170
|
+
export declare function markdownBreaks(text: string, hard?: boolean): string[];
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export { MARKDOWN_CALLOUT_NAMES, MARKDOWN_CALLOUT_TONES, markdownBreaks, markdownClosesFence, markdownCodeText, markdownFenceOf, markdownHeadingOf, markdownInline, markdownLines, parseMarkdown, parseMarkdownSpans, safeHref, } from './grammar.js';
|
|
2
|
+
export type { MarkdownAlign, MarkdownBlock, MarkdownCalloutTone, MarkdownFence, MarkdownInlineGroups, MarkdownInlineMatch, MarkdownListItem, MarkdownSpan, } from './grammar.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { MARKDOWN_CALLOUT_NAMES, MARKDOWN_CALLOUT_TONES, markdownBreaks, markdownClosesFence, markdownCodeText, markdownFenceOf, markdownHeadingOf, markdownInline, markdownLines, parseMarkdown, parseMarkdownSpans, safeHref } from '../chunk-SKOYC2CF.js';
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The editor itself: ProseMirror, drawn as the document it edits, with the
|
|
3
|
+
* slash menu, the selection toolbar, the link and picture panels and the
|
|
4
|
+
* table bar around it. Loaded lazily by `RichEditor`, so nothing here is
|
|
5
|
+
* fetched until somebody edits.
|
|
6
|
+
*/
|
|
7
|
+
import { EditorView } from 'prosemirror-view';
|
|
8
|
+
import { type RichEditorHandle, type RichEditorProps } from './types.js';
|
|
9
|
+
/**
|
|
10
|
+
* The engine's handle: the public one, and the view itself for this
|
|
11
|
+
* package's own suites, which drive ProseMirror where jsdom has no layout to
|
|
12
|
+
* drive a browser's input through.
|
|
13
|
+
*/
|
|
14
|
+
export interface EditorHandle extends RichEditorHandle {
|
|
15
|
+
view(): EditorView | null;
|
|
16
|
+
}
|
|
17
|
+
export declare const Editor: import("react").ForwardRefExoticComponent<RichEditorProps & import("react").RefAttributes<EditorHandle>>;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `RichEditor`: Markdown edited in place, as the document it reads as.
|
|
3
|
+
*
|
|
4
|
+
* # Loaded when somebody edits
|
|
5
|
+
*
|
|
6
|
+
* The editor is ProseMirror and everything around it, which is more than a
|
|
7
|
+
* reader of a page needs, so this component is a SHELL: it fetches the engine
|
|
8
|
+
* (`Editor.tsx`) with `import()` the first time one is drawn, and a bundler
|
|
9
|
+
* splits that into a chunk of its own. While the chunk loads the shell draws
|
|
10
|
+
* the caller's `fallback` (the body as it reads, so nothing moves) or a
|
|
11
|
+
* skeleton.
|
|
12
|
+
*
|
|
13
|
+
* A LOAD THAT FAILED IS FORGOTTEN, so the next attempt asks the server again
|
|
14
|
+
* rather than replaying the failure for the life of the page: the usual
|
|
15
|
+
* cause is a deploy that renamed the chunk while the page was open, and the
|
|
16
|
+
* other is one dropped request, which a retry fixes.
|
|
17
|
+
*/
|
|
18
|
+
import { type RefAttributes } from 'react';
|
|
19
|
+
import { type RichEditorHandle, type RichEditorProps } from './types.js';
|
|
20
|
+
/**
|
|
21
|
+
* Fetch the editor's code ahead of the first edit, on a press that is about
|
|
22
|
+
* to open one. It settles once the code is there, or once fetching it has
|
|
23
|
+
* failed, which the editor itself then says where it is drawn.
|
|
24
|
+
*/
|
|
25
|
+
export declare function preloadRichEditor(): Promise<void>;
|
|
26
|
+
export declare const RichEditor: import("react").ForwardRefExoticComponent<RichEditorProps & RefAttributes<RichEditorHandle>>;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Markdown in, Markdown out: the editor's document read from a body, and the
|
|
3
|
+
* body written back from the document.
|
|
4
|
+
*
|
|
5
|
+
* # A save with no edit changes nothing, by construction
|
|
6
|
+
*
|
|
7
|
+
* Storage is Markdown, and the bytes are the record: a Knowledge page is
|
|
8
|
+
* merged line by line against somebody else's save, and a doc's version is a
|
|
9
|
+
* patch of the lines that moved. An editor that wrote every body back in its
|
|
10
|
+
* own canonical spelling would turn opening a page and pressing Save into a
|
|
11
|
+
* rewrite of every line, and every concurrent save into a conflict.
|
|
12
|
+
*
|
|
13
|
+
* So the document REMEMBERS THE SOURCE OF EVERY TOP-LEVEL BLOCK it read
|
|
14
|
+
* ([LoadedMarkdown]). ProseMirror shares every node a transaction did not
|
|
15
|
+
* touch, so a block nobody edited is the very node that was read, and it is
|
|
16
|
+
* written back as the lines it came from, with the blank lines that stood
|
|
17
|
+
* between it and its neighbour. A block an edit replaced is looked up by
|
|
18
|
+
* value too, so a change that was undone writes back its original lines.
|
|
19
|
+
* Only a block that really changed is written in the canonical spelling
|
|
20
|
+
* below, and it keeps the markers it was read with.
|
|
21
|
+
*
|
|
22
|
+
* # A changed block is checked before it is written
|
|
23
|
+
*
|
|
24
|
+
* The canonical spelling is read back through the same grammar and compared
|
|
25
|
+
* with what the writer sees ([signature]); a spelling that would read
|
|
26
|
+
* differently (an asterisk that would open emphasis, a `_` inside a word that
|
|
27
|
+
* cannot close one) is written again with plainer markers and then with every
|
|
28
|
+
* punctuation character escaped. What the editor shows is what the next
|
|
29
|
+
* reader sees.
|
|
30
|
+
*/
|
|
31
|
+
import { type Node as PMNode } from 'prosemirror-model';
|
|
32
|
+
/** One top-level block as it was read: its lines, and what stood before it. */
|
|
33
|
+
interface SourceBlock {
|
|
34
|
+
index: number;
|
|
35
|
+
node: PMNode;
|
|
36
|
+
text: string;
|
|
37
|
+
/** The text between the previous block's last line and this block's first. */
|
|
38
|
+
sep: string;
|
|
39
|
+
}
|
|
40
|
+
/** A document and the source it was read from. */
|
|
41
|
+
export interface LoadedMarkdown {
|
|
42
|
+
doc: PMNode;
|
|
43
|
+
source: MarkdownSource;
|
|
44
|
+
}
|
|
45
|
+
/** What a document remembers of the body it was read from. */
|
|
46
|
+
export interface MarkdownSource {
|
|
47
|
+
original: string;
|
|
48
|
+
doc: PMNode;
|
|
49
|
+
lead: string;
|
|
50
|
+
trail: string;
|
|
51
|
+
blocks: SourceBlock[];
|
|
52
|
+
byNode: WeakMap<PMNode, SourceBlock>;
|
|
53
|
+
/** Whether every line of the original ends in CRLF, which a changed body keeps. */
|
|
54
|
+
crlf: boolean;
|
|
55
|
+
}
|
|
56
|
+
/** Read a Markdown body into the editor's document. */
|
|
57
|
+
export declare function readMarkdown(markdown: string): LoadedMarkdown;
|
|
58
|
+
/**
|
|
59
|
+
* The body a document is saved as.
|
|
60
|
+
*
|
|
61
|
+
* With the source it was read from, every block nobody changed is written as
|
|
62
|
+
* the lines it was read from; a document nobody changed at all is the source,
|
|
63
|
+
* byte for byte, line endings included.
|
|
64
|
+
*/
|
|
65
|
+
export declare function writeMarkdown(doc: PMNode, source?: MarkdownSource): string;
|
|
66
|
+
/**
|
|
67
|
+
* One block in the canonical spelling, checked: the first spelling that reads
|
|
68
|
+
* back as what the writer sees, or the plainest when none does.
|
|
69
|
+
*/
|
|
70
|
+
export declare function writeBlock(node: PMNode): string;
|
|
71
|
+
/**
|
|
72
|
+
* What a block SAYS: its structure and the attributes a reader sees, and its
|
|
73
|
+
* text character by character with the marks each carries. The spelling (a
|
|
74
|
+
* `*` or a `_`, a fence's marker, whether a space sat inside the strong or
|
|
75
|
+
* after it) is not part of it, because the reader cannot see it either.
|
|
76
|
+
*/
|
|
77
|
+
export declare function signature(node: PMNode): string;
|
|
78
|
+
export {};
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What the editor can do to a document, as ProseMirror commands: each takes a
|
|
3
|
+
* state and, given a dispatch, applies itself, and without one answers
|
|
4
|
+
* whether it could. The slash menu, the selection toolbar, the shortcuts and
|
|
5
|
+
* the table bar all call these, so a block is made one way whichever of them
|
|
6
|
+
* made it.
|
|
7
|
+
*/
|
|
8
|
+
import { type Mark, type MarkType, type Node as PMNode } from 'prosemirror-model';
|
|
9
|
+
import { type Command, type EditorState } from 'prosemirror-state';
|
|
10
|
+
import type { MarkdownAlign, MarkdownCalloutTone } from '../Markdown/index.js';
|
|
11
|
+
/** Whether a mark is on across the selection, or stored for the next keystroke. */
|
|
12
|
+
export declare function markActive(state: EditorState, type: MarkType): boolean;
|
|
13
|
+
/** The heading level the selection sits in, or 0 for any other block. */
|
|
14
|
+
export declare function headingLevel(state: EditorState): number;
|
|
15
|
+
/** Whether the selection is inside a code block, where no formatting applies. */
|
|
16
|
+
export declare function inCode(state: EditorState): boolean;
|
|
17
|
+
export declare const toggleStrong: Command;
|
|
18
|
+
export declare const toggleEm: Command;
|
|
19
|
+
export declare const toggleStrike: Command;
|
|
20
|
+
export declare const toggleCode: Command;
|
|
21
|
+
/** The link the selection is on: its whole range, and the mark. */
|
|
22
|
+
export declare function linkAt(state: EditorState): {
|
|
23
|
+
from: number;
|
|
24
|
+
to: number;
|
|
25
|
+
mark: Mark;
|
|
26
|
+
} | null;
|
|
27
|
+
/**
|
|
28
|
+
* Link the selection to `href`, or the link the caret is on; with nothing
|
|
29
|
+
* selected and no link under the caret, insert `text` linked.
|
|
30
|
+
*/
|
|
31
|
+
export declare function setLink(href: string, text?: string): Command;
|
|
32
|
+
/** Remove the link under the caret or across the selection. */
|
|
33
|
+
export declare const removeLink: Command;
|
|
34
|
+
/** A heading of `level`, or back to a paragraph when the block already is one. */
|
|
35
|
+
export declare function toggleHeading(level: number): Command;
|
|
36
|
+
export declare const setParagraph: Command;
|
|
37
|
+
export declare function setCodeBlock(lang?: string): Command;
|
|
38
|
+
export declare const wrapQuote: Command;
|
|
39
|
+
export declare function wrapCallout(tone?: MarkdownCalloutTone): Command;
|
|
40
|
+
export type ListKind = 'bullet' | 'ordered' | 'task';
|
|
41
|
+
/**
|
|
42
|
+
* Make the selection a list of `kind`. In a list of that kind already, the
|
|
43
|
+
* items come out of it; in a list of another kind, the list changes kind.
|
|
44
|
+
*/
|
|
45
|
+
export declare function setList(kind: ListKind): Command;
|
|
46
|
+
/** Enter in a list item: a new item, a task when this one is a task. */
|
|
47
|
+
export declare const splitItem: Command;
|
|
48
|
+
/** Tick or untick the task item at `pos`. */
|
|
49
|
+
export declare function toggleTask(pos: number): Command;
|
|
50
|
+
export declare const insertRule: Command;
|
|
51
|
+
export declare function insertImage(src: string, alt: string): Command;
|
|
52
|
+
/** The table the caret is in, and the cell. */
|
|
53
|
+
export interface TableAt {
|
|
54
|
+
table: PMNode;
|
|
55
|
+
pos: number;
|
|
56
|
+
row: number;
|
|
57
|
+
col: number;
|
|
58
|
+
}
|
|
59
|
+
export declare function tableAt(state: EditorState): TableAt | null;
|
|
60
|
+
/** A table of `rows` by `cols`, header included, with the caret in its first cell. */
|
|
61
|
+
export declare function insertTable(rows?: number, cols?: number): Command;
|
|
62
|
+
export declare const addRowBefore: Command;
|
|
63
|
+
export declare const addRowAfter: Command;
|
|
64
|
+
export declare const addColumnBefore: Command;
|
|
65
|
+
export declare const addColumnAfter: Command;
|
|
66
|
+
export declare const deleteRow: Command;
|
|
67
|
+
export declare const deleteColumn: Command;
|
|
68
|
+
export declare const deleteTable: Command;
|
|
69
|
+
export declare function alignColumn(align: MarkdownAlign): Command;
|
|
70
|
+
/** The alignment of the column the caret is in. */
|
|
71
|
+
export declare function columnAlign(state: EditorState): MarkdownAlign | null;
|
|
72
|
+
/**
|
|
73
|
+
* Tab and Shift-Tab between cells, and Enter to the cell below: past the last
|
|
74
|
+
* cell (or the last row, for Enter) a row is added, as a spreadsheet does.
|
|
75
|
+
*/
|
|
76
|
+
export declare function moveCell(direction: 'next' | 'previous' | 'down'): Command;
|
|
77
|
+
/**
|
|
78
|
+
* Enter on the third blank line at the end of a code block leaves it: the
|
|
79
|
+
* two blank lines go, and a paragraph opens after the block.
|
|
80
|
+
*/
|
|
81
|
+
export declare const exitCodeOnBlankLines: Command;
|
|
82
|
+
/** Enter after ```` ```lang ```` in a paragraph opens a code block in that language. */
|
|
83
|
+
export declare const fenceToCode: Command;
|
|
84
|
+
/** Select a whole node: an image the writer clicked, a rule. */
|
|
85
|
+
export declare function selectNode(pos: number): Command;
|
|
86
|
+
export declare function setCalloutTone(pos: number, tone: MarkdownCalloutTone): Command;
|
|
87
|
+
export declare function setCodeLanguage(pos: number, lang: string): Command;
|
|
88
|
+
/** Take the callout or quote at `pos` away, keeping what it holds. */
|
|
89
|
+
export declare function unwrapAt(pos: number): Command;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import './RichEditor.css';
|
|
2
|
+
export { RichEditor, preloadRichEditor } from './RichEditor.js';
|
|
3
|
+
export { RICH_EDITOR_LABELS, richEditorLabels } from './types.js';
|
|
4
|
+
export type { RichEditorBlock, RichEditorCommand, RichEditorHandle, RichEditorLabelOverrides, RichEditorLabels, RichEditorPanelApi, RichEditorProps, } from './types.js';
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { RichEditor, preloadRichEditor } from '../chunk-VOX3YRFO.js';
|
|
2
|
+
export { RICH_EDITOR_LABELS, richEditorLabels } from '../chunk-A4E5YLXO.js';
|
|
3
|
+
import '../chunk-W5J7R5EB.js';
|
|
4
|
+
import '../chunk-SKOYC2CF.js';
|
|
5
|
+
import '../chunk-SVSCLHHI.js';
|
|
6
|
+
import '../chunk-OG6CL3EB.js';
|
|
7
|
+
import '../chunk-BZFWDIV6.js';
|
|
8
|
+
import '../chunk-ODEQTPFM.js';
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The keyboard: Markdown typed as Markdown becomes the block or the format it
|
|
3
|
+
* spells (`# `, `- `, `1. `, `[ ] `, `> `, ```` ``` ````, `---`, `**bold**`),
|
|
4
|
+
* and the shortcuts every editor shares.
|
|
5
|
+
*
|
|
6
|
+
* AN INPUT RULE IS UNDONE BY BACKSPACE: a writer who meant a literal `# ` or
|
|
7
|
+
* `**` presses it once right after, and has the characters they typed.
|
|
8
|
+
*/
|
|
9
|
+
import { type Plugin } from 'prosemirror-state';
|
|
10
|
+
export declare function buildInputRules(): Plugin;
|
|
11
|
+
export interface KeyHooks {
|
|
12
|
+
submit: () => boolean;
|
|
13
|
+
link: () => boolean;
|
|
14
|
+
toolbar: () => boolean;
|
|
15
|
+
}
|
|
16
|
+
export declare function buildKeymap(hooks: KeyHooks): Plugin[];
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The blocks that draw more than their element while they are edited: a code
|
|
3
|
+
* block's language, a callout's tone, a task's box, a picture's file, a
|
|
4
|
+
* table's scroller.
|
|
5
|
+
*
|
|
6
|
+
* Each is the element shape the reader's renderer emits, so `Document` sets it
|
|
7
|
+
* the same way, plus a CONTROL SLOT that is not part of the content
|
|
8
|
+
* (`contenteditable="false"`). The editor draws its React controls into those
|
|
9
|
+
* slots through portals ([SlotStore]), so a code block's language field is a
|
|
10
|
+
* design system field rather than markup built here.
|
|
11
|
+
*/
|
|
12
|
+
import type { Node as PMNode } from 'prosemirror-model';
|
|
13
|
+
import type { EditorView, NodeView } from 'prosemirror-view';
|
|
14
|
+
/** A control slot a node view opened, for the editor to draw into. */
|
|
15
|
+
export interface Slot {
|
|
16
|
+
kind: 'code' | 'callout';
|
|
17
|
+
element: HTMLElement;
|
|
18
|
+
node: PMNode;
|
|
19
|
+
getPos: () => number | undefined;
|
|
20
|
+
}
|
|
21
|
+
/** The open slots, which the editor subscribes to and draws portals into. */
|
|
22
|
+
export declare class SlotStore {
|
|
23
|
+
private slots;
|
|
24
|
+
private listeners;
|
|
25
|
+
private snapshot;
|
|
26
|
+
add(slot: Slot): void;
|
|
27
|
+
remove(slot: Slot): void;
|
|
28
|
+
changed(): void;
|
|
29
|
+
subscribe: (listener: () => void) => (() => void);
|
|
30
|
+
get: () => Slot[];
|
|
31
|
+
private emit;
|
|
32
|
+
}
|
|
33
|
+
export declare function codeBlockView(store: SlotStore): (node: PMNode, _view: EditorView, getPos: () => number | undefined) => NodeView;
|
|
34
|
+
export declare function calloutView(store: SlotStore): (node: PMNode, _view: EditorView, getPos: () => number | undefined) => NodeView;
|
|
35
|
+
/**
|
|
36
|
+
* A list item, and a task item's box. The box is the same native checkbox
|
|
37
|
+
* the reader's renderer draws, and here it can be pressed: a press ticks the
|
|
38
|
+
* task without moving the caret.
|
|
39
|
+
*/
|
|
40
|
+
export declare function listItemView(labels: () => {
|
|
41
|
+
done: string;
|
|
42
|
+
notDone: string;
|
|
43
|
+
}): (node: PMNode, view: EditorView, getPos: () => number | undefined) => NodeView;
|
|
44
|
+
/** A table inside the scroller the reader's renderer wraps it in. */
|
|
45
|
+
export declare function tableView(node: PMNode): NodeView;
|
|
46
|
+
/** How a picture's address is shown: a doc's are files of its version. */
|
|
47
|
+
export type ImageResolver = (src: string) => string | null;
|
|
48
|
+
/**
|
|
49
|
+
* A picture, shown from where the application says (a doc's file, through an
|
|
50
|
+
* object URL) or, without a resolver, from an address a reader may follow.
|
|
51
|
+
* One it cannot show reads as its alt text, as it does to a reader.
|
|
52
|
+
*/
|
|
53
|
+
export declare class ImageViews {
|
|
54
|
+
private resolve;
|
|
55
|
+
private views;
|
|
56
|
+
constructor(resolve: () => ImageResolver | undefined);
|
|
57
|
+
/** Paint every picture again, when what the resolver can answer has changed. */
|
|
58
|
+
refresh(): void;
|
|
59
|
+
view: (node: PMNode) => NodeView;
|
|
60
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What a paste or a drop becomes: Markdown, HTML or plain text, read into the
|
|
3
|
+
* editor's document WITHOUT EVER PARSING MARKUP THROUGH A SINK.
|
|
4
|
+
*
|
|
5
|
+
* # Why HTML is tokenized here
|
|
6
|
+
*
|
|
7
|
+
* ProseMirror reads pasted HTML by assigning it to `innerHTML` on a detached
|
|
8
|
+
* document, behind a pass-through Trusted Types policy it creates for itself.
|
|
9
|
+
* A page that enforces Trusted Types with `trusted-types 'none'` allows no
|
|
10
|
+
* policy at all, so that path throws; and a pass-through policy, where one is
|
|
11
|
+
* allowed, is exactly the hole Trusted Types exists to close. So the editor
|
|
12
|
+
* takes the paste and the drop itself (`handleDOMEvents`), and reads HTML
|
|
13
|
+
* with the small tokenizer below, which builds elements one by one in an
|
|
14
|
+
* inert document (`createElement`, `setAttribute` and `createTextNode`, none
|
|
15
|
+
* of them a sink), keeping only the elements and attributes the editor has a
|
|
16
|
+
* meaning for. ProseMirror's own `DOMParser` then reads that tree, so every
|
|
17
|
+
* rule about what an element becomes is the schema's.
|
|
18
|
+
*
|
|
19
|
+
* NOTHING IN THE TREE LOADS ANYTHING: it lives in a document with no browsing
|
|
20
|
+
* context, a picture's address is kept in `data-src` rather than `src`, and a
|
|
21
|
+
* link whose scheme is not allowed is dropped to its text.
|
|
22
|
+
*/
|
|
23
|
+
import { Slice, type ResolvedPos } from 'prosemirror-model';
|
|
24
|
+
/**
|
|
25
|
+
* The paste as an element tree in an inert document, kept to what the
|
|
26
|
+
* editor understands. Unclosed `p`, `li`, `tr`, `td` and `th` close where a
|
|
27
|
+
* browser would close them, which is how real clipboard HTML is written.
|
|
28
|
+
*/
|
|
29
|
+
export declare function htmlTree(html: string, doc?: Document): HTMLElement;
|
|
30
|
+
/** A slice of the editor's document from pasted HTML. */
|
|
31
|
+
export declare function htmlSlice(html: string, $context: ResolvedPos): Slice;
|
|
32
|
+
/**
|
|
33
|
+
* Whether plain text is written in Markdown: a block's syntax at a line's
|
|
34
|
+
* start, or a span's (strong, a link, a code span) anywhere. Text with
|
|
35
|
+
* neither is pasted line by line, as it was written.
|
|
36
|
+
*/
|
|
37
|
+
export declare function looksLikeMarkdown(text: string): boolean;
|
|
38
|
+
/** A slice from Markdown text. */
|
|
39
|
+
export declare function markdownSlice(text: string): Slice;
|
|
40
|
+
/** A slice from plain text: one paragraph per line. */
|
|
41
|
+
export declare function textSlice(text: string): Slice;
|
|
42
|
+
/**
|
|
43
|
+
* Whether clipboard HTML carries structure worth keeping. A code editor puts
|
|
44
|
+
* its text on the clipboard as HTML too, every line a styled `div`, and
|
|
45
|
+
* reading that as HTML would lose the Markdown the text was written in.
|
|
46
|
+
*/
|
|
47
|
+
export declare function richHtml(html: string, types: readonly string[]): boolean;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The editor's plugins: the slash trigger, the placeholder, and the clipboard.
|
|
3
|
+
*/
|
|
4
|
+
import { Slice, type Node as PMNode } from 'prosemirror-model';
|
|
5
|
+
import { Plugin, PluginKey } from 'prosemirror-state';
|
|
6
|
+
/** Where the slash the writer typed is, and what they have typed after it. */
|
|
7
|
+
export interface SlashState {
|
|
8
|
+
open: boolean;
|
|
9
|
+
/** The position of the `/`. */
|
|
10
|
+
from: number;
|
|
11
|
+
query: string;
|
|
12
|
+
}
|
|
13
|
+
export declare const slashKey: PluginKey<SlashState>;
|
|
14
|
+
/**
|
|
15
|
+
* The slash trigger: a `/` typed at the start of a line or after a space
|
|
16
|
+
* opens the block menu, and the menu follows what is typed after it until
|
|
17
|
+
* the caret leaves, a space ends the word, or Escape closes it.
|
|
18
|
+
*
|
|
19
|
+
* ONLY A TYPED SLASH OPENS IT. A caret moved into an address that holds one
|
|
20
|
+
* (`https://…`) is not asking for a block.
|
|
21
|
+
*/
|
|
22
|
+
export declare function slashPlugin(keys: {
|
|
23
|
+
current: ((event: KeyboardEvent) => boolean) | null;
|
|
24
|
+
}): Plugin<SlashState>;
|
|
25
|
+
export declare const focusKey: PluginKey<boolean>;
|
|
26
|
+
/** Whether the editor has focus, kept as state so a decoration can follow it. */
|
|
27
|
+
export declare const focusPlugin: Plugin<boolean>;
|
|
28
|
+
/**
|
|
29
|
+
* The words an empty editor shows, and the hint an empty line shows while the
|
|
30
|
+
* caret is on it. Both are a decoration's attribute drawn by the stylesheet,
|
|
31
|
+
* never text in the document, so neither can be saved.
|
|
32
|
+
*/
|
|
33
|
+
export declare function placeholderPlugin(text: () => {
|
|
34
|
+
empty: string;
|
|
35
|
+
line: string;
|
|
36
|
+
}): Plugin;
|
|
37
|
+
/** A slice's content as Markdown, for a paste into anything that reads text. */
|
|
38
|
+
export declare function sliceMarkdown(slice: Slice): string;
|
|
39
|
+
/**
|
|
40
|
+
* The clipboard, taken whole: copy writes Markdown as the text a plain field
|
|
41
|
+
* receives, and paste and drop read Markdown, HTML and text through
|
|
42
|
+
* `paste.ts` rather than through ProseMirror's own HTML path, which assigns
|
|
43
|
+
* markup to `innerHTML` and cannot run under Trusted Types.
|
|
44
|
+
*/
|
|
45
|
+
export declare function clipboardPlugin(shift: {
|
|
46
|
+
current: boolean;
|
|
47
|
+
}): Plugin;
|
|
48
|
+
/** Whether a document is the single empty paragraph an empty body reads as. */
|
|
49
|
+
export declare function isEmptyDoc(doc: PMNode): boolean;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The editor's Markdown round trip, as plain functions: what a load and a
|
|
3
|
+
* save with no edit write, and the spelling a changed block is written in.
|
|
4
|
+
* An application holds its own bodies to them (a Knowledge page's fixtures, a
|
|
5
|
+
* doc's), so a body the editor would rewrite is found by a test rather than
|
|
6
|
+
* by somebody's diff.
|
|
7
|
+
*
|
|
8
|
+
* Importing these brings the document model with them; the editor's shell
|
|
9
|
+
* does not, so a screen that only draws `RichEditor` pays for neither.
|
|
10
|
+
*/
|
|
11
|
+
/** The body a load and a save with no edit write: the body itself, byte for byte. */
|
|
12
|
+
export declare function roundTripMarkdown(markdown: string): string;
|
|
13
|
+
/** The body as the editor writes it when every block has changed. */
|
|
14
|
+
export declare function canonicalMarkdown(markdown: string): string;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The document model `RichEditor` edits: exactly what the Markdown grammar
|
|
3
|
+
* (`../Markdown`) reads, and nothing it cannot write back.
|
|
4
|
+
*
|
|
5
|
+
* EVERY NODE DRAWS WHAT THE READER SEES. The editor's DOM is the element shape
|
|
6
|
+
* an application's renderer emits for the same block (an `h2` for a `#`
|
|
7
|
+
* heading, a list item whose first child is a checkbox, a table inside a
|
|
8
|
+
* scrolling wrapper), inside `Document`, so the page looks the same while it
|
|
9
|
+
* is edited as when it is read, and one stylesheet sets both.
|
|
10
|
+
*
|
|
11
|
+
* A NODE CARRIES THE SPELLING IT WAS READ WITH (a bullet's character, a
|
|
12
|
+
* fence's marker, emphasis by `*` or `_`), so a block somebody edits is
|
|
13
|
+
* written back in the hand it was written in rather than in the editor's.
|
|
14
|
+
*
|
|
15
|
+
* NO STYLE ATTRIBUTE IS EVER WRITTEN. A strict Content-Security-Policy refuses
|
|
16
|
+
* `style-src 'unsafe-inline'`, which covers a `style` attribute set through
|
|
17
|
+
* `setAttribute`, so a cell's alignment is a data attribute the stylesheet
|
|
18
|
+
* reads.
|
|
19
|
+
*/
|
|
20
|
+
import { Schema } from 'prosemirror-model';
|
|
21
|
+
/** A heading's element: a body's `#` is an `h2`, because the page's title is its `h1`. */
|
|
22
|
+
export declare function headingTag(level: number): string;
|
|
23
|
+
export declare const schema: Schema<"blockquote" | "table" | "image" | "text" | "heading" | "doc" | "paragraph" | "callout" | "code_block" | "horizontal_rule" | "bullet_list" | "ordered_list" | "list_item" | "table_row" | "table_header" | "table_cell" | "hard_break", "code" | "em" | "link" | "strong" | "strike">;
|