@aicayzer/inkkit 0.0.18 → 0.1.1
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/NOTICE +4 -2
- package/README.md +11 -7
- package/dist/THIRD-PARTY-NOTICES.txt +2742 -0
- package/dist/chunks/core-CYp5ONPO.js +56519 -0
- package/dist/chunks/highlight-BW9W8PtS.js +14122 -0
- package/dist/core.d.ts +2 -5
- package/dist/core.js +2 -2
- package/dist/editor.d.ts +229 -47
- package/dist/index.js +5 -3
- package/dist/style.css +231 -202
- package/dist/types.d.ts +143 -18
- package/package.json +16 -13
- package/dist/autolink.d.ts +0 -1
- package/dist/autolink.js +0 -18
- package/dist/callouts.d.ts +0 -25
- package/dist/callouts.js +0 -288
- package/dist/clipboard.d.ts +0 -11
- package/dist/clipboard.js +0 -261
- package/dist/code-fences.d.ts +0 -8
- package/dist/code-fences.js +0 -171
- package/dist/comments.d.ts +0 -76
- package/dist/comments.js +0 -545
- package/dist/cursor.d.ts +0 -2
- package/dist/cursor.js +0 -40
- package/dist/decorations.d.ts +0 -2
- package/dist/decorations.js +0 -67
- package/dist/dialect.d.ts +0 -9
- package/dist/dialect.js +0 -446
- package/dist/drop-placement.d.ts +0 -19
- package/dist/drop-placement.js +0 -47
- package/dist/editor.js +0 -2673
- package/dist/files.d.ts +0 -40
- package/dist/files.js +0 -133
- package/dist/highlight.d.ts +0 -1
- package/dist/highlight.js +0 -136
- package/dist/html-import.d.ts +0 -13
- package/dist/html-import.js +0 -477
- package/dist/image-blocks.d.ts +0 -86
- package/dist/image-blocks.js +0 -329
- package/dist/images.d.ts +0 -51
- package/dist/images.js +0 -398
- package/dist/inline-highlight.d.ts +0 -6
- package/dist/inline-highlight.js +0 -112
- package/dist/labels.d.ts +0 -36
- package/dist/labels.js +0 -34
- package/dist/link-safety.d.ts +0 -17
- package/dist/link-safety.js +0 -29
- package/dist/linked-syntax.d.ts +0 -48
- package/dist/linked-syntax.js +0 -320
- package/dist/literals.d.ts +0 -20
- package/dist/literals.js +0 -216
- package/dist/mermaid.d.ts +0 -28
- package/dist/mermaid.js +0 -404
- package/dist/outline.d.ts +0 -22
- package/dist/outline.js +0 -79
- package/dist/paste-html.d.ts +0 -31
- package/dist/paste-html.js +0 -462
- package/dist/paste.d.ts +0 -33
- package/dist/paste.js +0 -591
- package/dist/portable-files.d.ts +0 -10
- package/dist/portable-files.js +0 -36
- package/dist/preserve.d.ts +0 -38
- package/dist/preserve.js +0 -1396
- package/dist/print.d.ts +0 -7
- package/dist/print.js +0 -406
- package/dist/reference-clipboard.d.ts +0 -8
- package/dist/reference-clipboard.js +0 -201
- package/dist/references.d.ts +0 -16
- package/dist/references.js +0 -418
- package/dist/scroll.d.ts +0 -15
- package/dist/scroll.js +0 -27
- package/dist/search.d.ts +0 -15
- package/dist/search.js +0 -202
- package/dist/selection.d.ts +0 -1
- package/dist/selection.js +0 -59
- package/dist/source.d.ts +0 -16
- package/dist/source.js +0 -57
- package/dist/spreadsheet.d.ts +0 -8
- package/dist/spreadsheet.js +0 -289
- package/dist/table-alignment.d.ts +0 -2
- package/dist/table-alignment.js +0 -46
- package/dist/tables.d.ts +0 -27
- package/dist/tables.js +0 -344
- package/dist/tasks.d.ts +0 -3
- package/dist/tasks.js +0 -51
- package/dist/text-ranges.d.ts +0 -29
- package/dist/text-ranges.js +0 -256
- package/dist/types.js +0 -8
- package/dist/wiki-view.d.ts +0 -21
- package/dist/wiki-view.js +0 -78
package/dist/selection.js
DELETED
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
import { Plugin, PluginKey } from '@milkdown/kit/prose/state';
|
|
2
|
-
import { $prose } from '@milkdown/kit/utils';
|
|
3
|
-
/** The stylesheet paints the selection under this name. */
|
|
4
|
-
const name = 'inkkit-selection';
|
|
5
|
-
const ranges = new Map();
|
|
6
|
-
/** The selected text within each block. */
|
|
7
|
-
function covered(state) {
|
|
8
|
-
const { from, to, empty, visible } = state.selection;
|
|
9
|
-
if (empty || !visible)
|
|
10
|
-
return null;
|
|
11
|
-
const text = [];
|
|
12
|
-
state.doc.nodesBetween(from, to, (node, pos) => {
|
|
13
|
-
if (!node.isTextblock)
|
|
14
|
-
return true;
|
|
15
|
-
const start = Math.max(from, pos + 1);
|
|
16
|
-
const end = Math.min(to, pos + node.nodeSize - 1);
|
|
17
|
-
if (end > start)
|
|
18
|
-
text.push({ from: start, to: end });
|
|
19
|
-
return false;
|
|
20
|
-
});
|
|
21
|
-
return text;
|
|
22
|
-
}
|
|
23
|
-
function domRange(view, span) {
|
|
24
|
-
const start = view.domAtPos(span.from);
|
|
25
|
-
const end = view.domAtPos(span.to);
|
|
26
|
-
const range = document.createRange();
|
|
27
|
-
range.setStart(start.node, start.offset);
|
|
28
|
-
range.setEnd(end.node, end.offset);
|
|
29
|
-
return range;
|
|
30
|
-
}
|
|
31
|
-
function paint(view) {
|
|
32
|
-
ranges.set(view, (covered(view.state) ?? []).map((span) => domRange(view, span)));
|
|
33
|
-
refresh();
|
|
34
|
-
}
|
|
35
|
-
function refresh() {
|
|
36
|
-
if (ranges.size === 0) {
|
|
37
|
-
CSS.highlights.delete(name);
|
|
38
|
-
return;
|
|
39
|
-
}
|
|
40
|
-
const highlight = new Highlight();
|
|
41
|
-
for (const selection of ranges.values())
|
|
42
|
-
for (const range of selection)
|
|
43
|
-
highlight.add(range);
|
|
44
|
-
CSS.highlights.set(name, highlight);
|
|
45
|
-
}
|
|
46
|
-
// Paint only selected text, without WebKit filling the surrounding margins.
|
|
47
|
-
export const selectionPlugin = $prose(() => new Plugin({
|
|
48
|
-
key: new PluginKey('selection'),
|
|
49
|
-
view(view) {
|
|
50
|
-
paint(view);
|
|
51
|
-
return {
|
|
52
|
-
update: (view) => paint(view),
|
|
53
|
-
destroy: () => {
|
|
54
|
-
ranges.delete(view);
|
|
55
|
-
refresh();
|
|
56
|
-
},
|
|
57
|
-
};
|
|
58
|
-
},
|
|
59
|
-
}));
|
package/dist/source.d.ts
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import type { Node as ProseNode } from '@milkdown/kit/prose/model';
|
|
2
|
-
export declare const sourceAttribute = "inkkitSource";
|
|
3
|
-
export interface SourceProvenance {
|
|
4
|
-
readonly text: string;
|
|
5
|
-
readonly format: 'md' | 'txt';
|
|
6
|
-
readonly from: number;
|
|
7
|
-
readonly to: number;
|
|
8
|
-
}
|
|
9
|
-
export declare function cleanSourceDoc(doc: ProseNode): ProseNode;
|
|
10
|
-
export declare function rawOffset(source: string, normalized: number): number;
|
|
11
|
-
export declare function normalizedOffset(source: string, raw: number): number;
|
|
12
|
-
export declare function editedPlainSource(previous: string, value: string): string;
|
|
13
|
-
export declare function sourceSelection(source: string, start: number, end: number): {
|
|
14
|
-
markdown: string;
|
|
15
|
-
shareable: string;
|
|
16
|
-
};
|
package/dist/source.js
DELETED
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
import { literalCommentSpans } from './comments.js';
|
|
2
|
-
export const sourceAttribute = 'inkkitSource';
|
|
3
|
-
export function cleanSourceDoc(doc) {
|
|
4
|
-
return doc.attrs[sourceAttribute] == null
|
|
5
|
-
? doc
|
|
6
|
-
: doc.type.create({ ...doc.attrs, [sourceAttribute]: null }, doc.content);
|
|
7
|
-
}
|
|
8
|
-
export function rawOffset(source, normalized) {
|
|
9
|
-
let position = 0, count = 0;
|
|
10
|
-
while (position < source.length && count < normalized) {
|
|
11
|
-
if (source[position] === '\r' && source[position + 1] === '\n')
|
|
12
|
-
position++;
|
|
13
|
-
position++;
|
|
14
|
-
count++;
|
|
15
|
-
}
|
|
16
|
-
return position;
|
|
17
|
-
}
|
|
18
|
-
export function normalizedOffset(source, raw) {
|
|
19
|
-
return source.slice(0, raw).replace(/\r\n?/g, '\n').length;
|
|
20
|
-
}
|
|
21
|
-
export function editedPlainSource(previous, value) {
|
|
22
|
-
const normalized = previous.replace(/\r\n?/g, '\n');
|
|
23
|
-
if (normalized === value)
|
|
24
|
-
return previous;
|
|
25
|
-
let prefix = 0, suffix = 0;
|
|
26
|
-
while (prefix < normalized.length &&
|
|
27
|
-
prefix < value.length &&
|
|
28
|
-
normalized[prefix] === value[prefix])
|
|
29
|
-
prefix++;
|
|
30
|
-
while (suffix < normalized.length - prefix &&
|
|
31
|
-
suffix < value.length - prefix &&
|
|
32
|
-
normalized[normalized.length - suffix - 1] ===
|
|
33
|
-
value[value.length - suffix - 1])
|
|
34
|
-
suffix++;
|
|
35
|
-
const ending = /\r\n|\r|\n/.exec(previous)?.[0] ?? '\n';
|
|
36
|
-
return (previous.slice(0, rawOffset(previous, prefix)) +
|
|
37
|
-
value
|
|
38
|
-
.slice(prefix, value.length - suffix)
|
|
39
|
-
.replace(/\r\n?/g, '\n')
|
|
40
|
-
.replaceAll('\n', ending) +
|
|
41
|
-
previous.slice(rawOffset(previous, normalized.length - suffix)));
|
|
42
|
-
}
|
|
43
|
-
export function sourceSelection(source, start, end) {
|
|
44
|
-
const from = rawOffset(source, start), to = rawOffset(source, end);
|
|
45
|
-
let shareable = '', cursor = from;
|
|
46
|
-
const bom = source.startsWith('\uFEFF') ? 1 : 0;
|
|
47
|
-
for (const parsed of literalCommentSpans(source.slice(bom))) {
|
|
48
|
-
const span = { start: parsed.start + bom, end: parsed.end + bom };
|
|
49
|
-
if (span.end <= from || span.start >= to)
|
|
50
|
-
continue;
|
|
51
|
-
if (span.start > cursor)
|
|
52
|
-
shareable += source.slice(cursor, Math.min(span.start, to));
|
|
53
|
-
cursor = Math.max(cursor, Math.min(span.end, to));
|
|
54
|
-
}
|
|
55
|
-
shareable += source.slice(cursor, to);
|
|
56
|
-
return { markdown: source.slice(from, to), shareable };
|
|
57
|
-
}
|
package/dist/spreadsheet.d.ts
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import type { Ctx } from '@milkdown/kit/ctx';
|
|
2
|
-
import { type ClipboardInput } from './types.js';
|
|
3
|
-
/** Pastes a spreadsheet at the selection, or at `at` for a drop, which
|
|
4
|
-
* always lands outside a table. */
|
|
5
|
-
export declare function pasteSpreadsheet(ctx: Ctx, input: ClipboardInput, at?: {
|
|
6
|
-
from: number;
|
|
7
|
-
to: number;
|
|
8
|
-
}): boolean;
|
package/dist/spreadsheet.js
DELETED
|
@@ -1,289 +0,0 @@
|
|
|
1
|
-
import { editorViewCtx } from '@milkdown/kit/core';
|
|
2
|
-
import { DOMParser as ProseParser, Fragment, Slice, } from '@milkdown/kit/prose/model';
|
|
3
|
-
import { isInTable, selectedRect } from '@milkdown/kit/prose/tables';
|
|
4
|
-
import { InkKitError } from './types.js';
|
|
5
|
-
import { literalCommentSpans } from './comments.js';
|
|
6
|
-
import { restoreConvertedSpaces } from './paste-html.js';
|
|
7
|
-
import { importableSlice } from './html-import.js';
|
|
8
|
-
import { caretAfter } from './drop-placement.js';
|
|
9
|
-
import { normalizeTableAlignment } from './table-alignment.js';
|
|
10
|
-
import { dispatchTableOperation, editableTable, selectTableRectangle, } from './tables.js';
|
|
11
|
-
/** Pastes a spreadsheet at the selection, or at `at` for a drop, which
|
|
12
|
-
* always lands outside a table. */
|
|
13
|
-
export function pasteSpreadsheet(ctx, input, at) {
|
|
14
|
-
const view = ctx.get(editorViewCtx);
|
|
15
|
-
if (input.plainText || input.markdown != null)
|
|
16
|
-
return false;
|
|
17
|
-
const inTable = !at && isInTable(view.state);
|
|
18
|
-
if (input.html &&
|
|
19
|
-
/data-inkkit-(?:markdown|reference|footnote|comment)/i.test(input.html)) {
|
|
20
|
-
if (inTable && /<table[\s>]/i.test(input.html))
|
|
21
|
-
reject();
|
|
22
|
-
return false;
|
|
23
|
-
}
|
|
24
|
-
if (input.images?.length || (input.html && /<img[\s>]/i.test(input.html))) {
|
|
25
|
-
if (!input.html || !/<table[\s>]/i.test(input.html))
|
|
26
|
-
return false;
|
|
27
|
-
const template = document.createElement('template');
|
|
28
|
-
template.innerHTML = input.html;
|
|
29
|
-
for (const image of template.content.querySelectorAll('img'))
|
|
30
|
-
image.replaceWith(document.createTextNode(image.getAttribute('alt') ?? 'Image'));
|
|
31
|
-
try {
|
|
32
|
-
htmlGrid(view.state.schema, template.innerHTML);
|
|
33
|
-
return false;
|
|
34
|
-
}
|
|
35
|
-
catch {
|
|
36
|
-
if (!inTable && !standaloneTable(input.html))
|
|
37
|
-
return false;
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
let grid;
|
|
41
|
-
try {
|
|
42
|
-
grid = input.html?.match(/<table[\s>]/i)
|
|
43
|
-
? htmlGrid(view.state.schema, input.html)
|
|
44
|
-
: input.text.includes('\t')
|
|
45
|
-
? textGrid(view.state.schema, input.text)
|
|
46
|
-
: undefined;
|
|
47
|
-
}
|
|
48
|
-
catch (error) {
|
|
49
|
-
if (inTable || !input.html)
|
|
50
|
-
throw error;
|
|
51
|
-
if (!standaloneTable(input.html))
|
|
52
|
-
return false;
|
|
53
|
-
const schema = view.state.schema;
|
|
54
|
-
const children = [];
|
|
55
|
-
let cursor = 0;
|
|
56
|
-
for (const span of literalCommentSpans(input.html)) {
|
|
57
|
-
if (span.start > cursor)
|
|
58
|
-
children.push(schema.text(input.html.slice(cursor, span.start)));
|
|
59
|
-
children.push(schema.nodes.comment_inline.create({ syntax: span.syntax, block: Boolean(span.block) }, span.value ? schema.text(span.value) : null));
|
|
60
|
-
cursor = span.end;
|
|
61
|
-
}
|
|
62
|
-
if (cursor < input.html.length)
|
|
63
|
-
children.push(schema.text(input.html.slice(cursor)));
|
|
64
|
-
// The source is kept only where it reads back as one literal block.
|
|
65
|
-
const content = importableSlice(ctx, new Slice(Fragment.from(schema.nodes.literal_markdown.create(null, children)), 0, 0)).content;
|
|
66
|
-
const selection = view.state.selection;
|
|
67
|
-
const tr = at
|
|
68
|
-
? view.state.tr.replaceWith(at.from, at.to, content)
|
|
69
|
-
: selection.$from.parent.type.name === 'paragraph' &&
|
|
70
|
-
selection.empty &&
|
|
71
|
-
selection.$from.parent.content.size === 0
|
|
72
|
-
? view.state.tr.replaceWith(selection.$from.before(), selection.$from.after(), content)
|
|
73
|
-
: content.childCount === 1
|
|
74
|
-
? view.state.tr.replaceSelectionWith(content.firstChild)
|
|
75
|
-
: view.state.tr.replaceSelection(new Slice(content, 0, 0));
|
|
76
|
-
dispatchTableOperation(view, tr);
|
|
77
|
-
return true;
|
|
78
|
-
}
|
|
79
|
-
if (!grid)
|
|
80
|
-
return false;
|
|
81
|
-
if (!inTable) {
|
|
82
|
-
const schema = view.state.schema;
|
|
83
|
-
const rows = grid.cells.map((row, index) => schema.nodes[index ? 'table_row' : 'table_header_row'].create(null, row.map((content, column) => schema.nodes[index ? 'table_cell' : 'table_header'].create({ alignment: grid.alignment?.[column] ?? 'left' }, schema.nodes.paragraph.create(null, content)))));
|
|
84
|
-
const table = schema.nodes.table.create(null, rows);
|
|
85
|
-
const selection = view.state.selection;
|
|
86
|
-
const tr = at
|
|
87
|
-
? view.state.tr.replaceWith(at.from, at.to, table)
|
|
88
|
-
: selection.$from.parent.type.name === 'paragraph' &&
|
|
89
|
-
selection.empty &&
|
|
90
|
-
selection.$from.parent.content.size === 0
|
|
91
|
-
? view.state.tr.replaceWith(selection.$from.before(), selection.$from.after(), table)
|
|
92
|
-
: view.state.tr.replaceSelectionWith(table);
|
|
93
|
-
let tableStart = -1;
|
|
94
|
-
tr.doc.descendants((node, pos) => {
|
|
95
|
-
if (node === table)
|
|
96
|
-
tableStart = pos + 1;
|
|
97
|
-
});
|
|
98
|
-
if (tableStart < 0)
|
|
99
|
-
reject();
|
|
100
|
-
// Selecting the new table would let the next keystroke replace it.
|
|
101
|
-
tr.setSelection(caretAfter(tr.doc, tableStart - 1 + table.nodeSize));
|
|
102
|
-
dispatchTableOperation(view, tr);
|
|
103
|
-
return true;
|
|
104
|
-
}
|
|
105
|
-
const rect = selectedRect(view.state);
|
|
106
|
-
if (!editableTable(rect.table))
|
|
107
|
-
reject();
|
|
108
|
-
const width = Math.max(rect.map.width, rect.left + grid.width);
|
|
109
|
-
const height = Math.max(rect.map.height, rect.top + grid.cells.length);
|
|
110
|
-
if (width > 100 || height > 100)
|
|
111
|
-
reject();
|
|
112
|
-
const schema = view.state.schema;
|
|
113
|
-
const alignment = Array.from({ length: width }, (_, column) => column < rect.map.width
|
|
114
|
-
? rect.table.firstChild.child(column).attrs.alignment
|
|
115
|
-
: 'left');
|
|
116
|
-
const rows = [];
|
|
117
|
-
for (let row = 0; row < height; row++) {
|
|
118
|
-
const cells = [];
|
|
119
|
-
for (let column = 0; column < width; column++) {
|
|
120
|
-
const existing = row < rect.map.height && column < rect.map.width
|
|
121
|
-
? rect.table.child(row).child(column)
|
|
122
|
-
: undefined;
|
|
123
|
-
const incoming = grid.cells[row - rect.top]?.[column - rect.left];
|
|
124
|
-
const cleared = row >= rect.top &&
|
|
125
|
-
row < rect.bottom &&
|
|
126
|
-
column >= rect.left &&
|
|
127
|
-
column < rect.right;
|
|
128
|
-
if (existing && !incoming && !cleared)
|
|
129
|
-
cells.push(existing);
|
|
130
|
-
else {
|
|
131
|
-
const type = schema.nodes[row ? 'table_cell' : 'table_header'];
|
|
132
|
-
cells.push(type.create({ ...(existing?.attrs ?? {}), alignment: alignment[column] }, schema.nodes.paragraph.create(null, incoming)));
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
rows.push(schema.nodes[row ? 'table_row' : 'table_header_row'].create(rect.table.maybeChild(row)?.attrs, cells));
|
|
136
|
-
}
|
|
137
|
-
const table = rect.table.copy(Fragment.fromArray(rows));
|
|
138
|
-
const tr = view.state.tr.replaceWith(rect.tableStart - 1, rect.tableStart - 1 + rect.table.nodeSize, table);
|
|
139
|
-
selectTableRectangle(tr, rect.tableStart, table, rect.top, rect.left, rect.top + grid.cells.length, rect.left + grid.width);
|
|
140
|
-
dispatchTableOperation(view, tr);
|
|
141
|
-
return true;
|
|
142
|
-
}
|
|
143
|
-
function standaloneTable(html) {
|
|
144
|
-
const template = document.createElement('template');
|
|
145
|
-
template.innerHTML = html;
|
|
146
|
-
for (const metadata of template.content.querySelectorAll('meta[charset]'))
|
|
147
|
-
metadata.remove();
|
|
148
|
-
const elements = [...template.content.childNodes].filter((node) => node.nodeType !== 3 || node.textContent?.trim());
|
|
149
|
-
return elements.length === 1 && elements[0] instanceof HTMLTableElement;
|
|
150
|
-
}
|
|
151
|
-
function reject() {
|
|
152
|
-
throw new InkKitError('preservation', 'This spreadsheet cannot be represented safely in a Markdown table. Paste as plain text outside the table to retain its source.');
|
|
153
|
-
}
|
|
154
|
-
function textGrid(schema, input) {
|
|
155
|
-
const text = input.replace(/\r\n?/g, '\n').replace(/\n$/, '');
|
|
156
|
-
const rows = [[]];
|
|
157
|
-
let value = '', quoted = false, closed = false, start = true;
|
|
158
|
-
for (let index = 0; index <= text.length; index++) {
|
|
159
|
-
const character = text[index];
|
|
160
|
-
if (quoted) {
|
|
161
|
-
if (character == null)
|
|
162
|
-
reject();
|
|
163
|
-
if (character === '"') {
|
|
164
|
-
if (text[index + 1] === '"') {
|
|
165
|
-
value += '"';
|
|
166
|
-
index++;
|
|
167
|
-
}
|
|
168
|
-
else {
|
|
169
|
-
quoted = false;
|
|
170
|
-
closed = true;
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
else
|
|
174
|
-
value += character;
|
|
175
|
-
continue;
|
|
176
|
-
}
|
|
177
|
-
if (character === '"' && start) {
|
|
178
|
-
quoted = true;
|
|
179
|
-
start = false;
|
|
180
|
-
}
|
|
181
|
-
else if (character === '\t' || character === '\n' || character == null) {
|
|
182
|
-
rows.at(-1).push(value);
|
|
183
|
-
value = '';
|
|
184
|
-
start = true;
|
|
185
|
-
closed = false;
|
|
186
|
-
if (character === '\n')
|
|
187
|
-
rows.push([]);
|
|
188
|
-
}
|
|
189
|
-
else {
|
|
190
|
-
if (closed)
|
|
191
|
-
reject();
|
|
192
|
-
value += character;
|
|
193
|
-
start = false;
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
const width = Math.max(...rows.map((row) => row.length));
|
|
197
|
-
if (width > 100 || rows.length > 100)
|
|
198
|
-
reject();
|
|
199
|
-
if (rows.some((row) => row.some((value) => /[\n\t]/.test(value))))
|
|
200
|
-
reject();
|
|
201
|
-
return {
|
|
202
|
-
width,
|
|
203
|
-
cells: rows.map((row) => Array.from({ length: width }, (_, column) => {
|
|
204
|
-
const value = row[column] ?? '';
|
|
205
|
-
return value ? Fragment.from(schema.text(value)) : Fragment.empty;
|
|
206
|
-
})),
|
|
207
|
-
};
|
|
208
|
-
}
|
|
209
|
-
function htmlGrid(schema, html) {
|
|
210
|
-
const template = document.createElement('template');
|
|
211
|
-
template.innerHTML = html;
|
|
212
|
-
const fragment = template.content;
|
|
213
|
-
for (const metadata of fragment.querySelectorAll('meta[charset]'))
|
|
214
|
-
metadata.remove();
|
|
215
|
-
const table = fragment.querySelector('table');
|
|
216
|
-
if (!table || fragment.querySelectorAll('table').length !== 1)
|
|
217
|
-
reject();
|
|
218
|
-
const wrapper = table.parentElement;
|
|
219
|
-
if (wrapper && wrapper.tagName !== 'BODY')
|
|
220
|
-
reject();
|
|
221
|
-
for (const sibling of fragment.childNodes)
|
|
222
|
-
if (sibling !== table &&
|
|
223
|
-
(sibling.textContent?.trim() || sibling.nodeType !== 3))
|
|
224
|
-
reject();
|
|
225
|
-
const rows = [...table.querySelectorAll('tr')];
|
|
226
|
-
if (document.createTreeWalker(table, NodeFilter.SHOW_COMMENT).nextNode())
|
|
227
|
-
reject();
|
|
228
|
-
for (const element of table.children) {
|
|
229
|
-
if (!['TR', 'THEAD', 'TBODY', 'TFOOT'].includes(element.tagName))
|
|
230
|
-
reject();
|
|
231
|
-
if (element.tagName !== 'TR')
|
|
232
|
-
for (const row of element.children)
|
|
233
|
-
if (row.tagName !== 'TR')
|
|
234
|
-
reject();
|
|
235
|
-
}
|
|
236
|
-
const width = rows[0]?.children.length ?? 0;
|
|
237
|
-
if (!width || width > 100 || !rows.length || rows.length > 100)
|
|
238
|
-
reject();
|
|
239
|
-
const parser = ProseParser.fromSchema(schema);
|
|
240
|
-
const inline = new Set([
|
|
241
|
-
'STRONG',
|
|
242
|
-
'B',
|
|
243
|
-
'EM',
|
|
244
|
-
'I',
|
|
245
|
-
'S',
|
|
246
|
-
'DEL',
|
|
247
|
-
'STRIKE',
|
|
248
|
-
'CODE',
|
|
249
|
-
'A',
|
|
250
|
-
'MARK',
|
|
251
|
-
'SPAN',
|
|
252
|
-
]);
|
|
253
|
-
const cells = rows.map((row) => {
|
|
254
|
-
if (row.children.length !== width)
|
|
255
|
-
reject();
|
|
256
|
-
return [...row.children].map((cell) => {
|
|
257
|
-
if (!['TH', 'TD'].includes(cell.tagName))
|
|
258
|
-
reject();
|
|
259
|
-
if ((cell.hasAttribute('rowspan') &&
|
|
260
|
-
cell.getAttribute('rowspan') !== '1') ||
|
|
261
|
-
(cell.hasAttribute('colspan') && cell.getAttribute('colspan') !== '1'))
|
|
262
|
-
reject();
|
|
263
|
-
for (const element of cell.querySelectorAll('*'))
|
|
264
|
-
if (!inline.has(element.tagName) &&
|
|
265
|
-
!(element.tagName === 'P' &&
|
|
266
|
-
element.parentElement === cell &&
|
|
267
|
-
cell.children.length === 1))
|
|
268
|
-
reject();
|
|
269
|
-
const walker = document.createTreeWalker(cell, NodeFilter.SHOW_COMMENT);
|
|
270
|
-
if (walker.nextNode())
|
|
271
|
-
reject();
|
|
272
|
-
if (/[\n\r\t]/.test(cell.textContent ?? ''))
|
|
273
|
-
reject();
|
|
274
|
-
for (const link of cell.querySelectorAll('a'))
|
|
275
|
-
if (!link.hasAttribute('href'))
|
|
276
|
-
reject();
|
|
277
|
-
restoreConvertedSpaces(cell);
|
|
278
|
-
const parsed = parser.parse(cell, { preserveWhitespace: true });
|
|
279
|
-
if (parsed.childCount === 0)
|
|
280
|
-
return Fragment.empty;
|
|
281
|
-
if (parsed.childCount !== 1 ||
|
|
282
|
-
parsed.firstChild.type.name !== 'paragraph')
|
|
283
|
-
reject();
|
|
284
|
-
return parsed.firstChild.content;
|
|
285
|
-
});
|
|
286
|
-
});
|
|
287
|
-
const alignment = [...rows[0].children].map((cell) => normalizeTableAlignment(cell) ?? 'left');
|
|
288
|
-
return { width, cells, alignment };
|
|
289
|
-
}
|
package/dist/table-alignment.js
DELETED
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
export function normalizeTableAlignment(element) {
|
|
2
|
-
const alignment = (element.style.textAlign ||
|
|
3
|
-
element.getAttribute('align') ||
|
|
4
|
-
'')
|
|
5
|
-
.trim()
|
|
6
|
-
.toLowerCase();
|
|
7
|
-
if (alignment === 'left' || alignment === 'center' || alignment === 'right')
|
|
8
|
-
return alignment;
|
|
9
|
-
if (alignment !== 'start' && alignment !== 'end')
|
|
10
|
-
return null;
|
|
11
|
-
let direction = 'ltr';
|
|
12
|
-
for (let current = element; current; current = current.parentElement) {
|
|
13
|
-
const value = (current.style.direction || current.getAttribute('dir') || '')
|
|
14
|
-
.trim()
|
|
15
|
-
.toLowerCase();
|
|
16
|
-
if (value === 'ltr' || value === 'rtl') {
|
|
17
|
-
direction = value;
|
|
18
|
-
break;
|
|
19
|
-
}
|
|
20
|
-
if (value === 'auto') {
|
|
21
|
-
const first = [...(current.textContent ?? '')].find((character) => /[\u061c\u200e\u200f]|\p{Letter}/u.test(character));
|
|
22
|
-
if (first) {
|
|
23
|
-
direction =
|
|
24
|
-
/[\u0590-\u08ff\u200f\ufb1d-\ufdff\ufe70-\ufeff\u{10800}-\u{10fff}\u{1e800}-\u{1edff}\u{1e900}-\u{1e95f}]/u.test(first)
|
|
25
|
-
? 'rtl'
|
|
26
|
-
: 'ltr';
|
|
27
|
-
break;
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
return alignment === 'start'
|
|
32
|
-
? direction === 'rtl'
|
|
33
|
-
? 'right'
|
|
34
|
-
: 'left'
|
|
35
|
-
: direction === 'rtl'
|
|
36
|
-
? 'left'
|
|
37
|
-
: 'right';
|
|
38
|
-
}
|
|
39
|
-
export function normalizeTableColumnAlignment(element) {
|
|
40
|
-
if (!(element instanceof HTMLTableCellElement))
|
|
41
|
-
return normalizeTableAlignment(element);
|
|
42
|
-
const table = element.closest('table');
|
|
43
|
-
const header = table?.rows[0]?.cells[element.cellIndex];
|
|
44
|
-
// GFM represents alignment once per column, independently of cell direction.
|
|
45
|
-
return normalizeTableAlignment(header ?? element);
|
|
46
|
-
}
|
package/dist/tables.d.ts
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import type { Ctx } from '@milkdown/kit/ctx';
|
|
2
|
-
import { type Node as ProseNode } from '@milkdown/kit/prose/model';
|
|
3
|
-
import type { EditorView } from '@milkdown/kit/prose/view';
|
|
4
|
-
import type { EditorState, Transaction } from '@milkdown/kit/prose/state';
|
|
5
|
-
export type TableCommand = 'insert' | 'addRowBefore' | 'addRowAfter' | 'addColumnBefore' | 'addColumnAfter' | 'deleteRow' | 'deleteColumn' | 'deleteTable' | 'alignLeft' | 'alignCenter' | 'alignRight' | 'moveRowUp' | 'moveRowDown' | 'moveColumnLeft' | 'moveColumnRight' | 'sortRows' | 'exit';
|
|
6
|
-
export declare const tableCommands: readonly TableCommand[];
|
|
7
|
-
export declare function tableContext(state: EditorState): {
|
|
8
|
-
row: number;
|
|
9
|
-
column: number;
|
|
10
|
-
rows: number;
|
|
11
|
-
columns: number;
|
|
12
|
-
} | undefined;
|
|
13
|
-
/** Checks the same default operations without dispatching a transaction. */
|
|
14
|
-
export declare function tableAvailability(ctx: Ctx): Record<TableCommand, boolean>;
|
|
15
|
-
export interface TableOptions {
|
|
16
|
-
rows?: number;
|
|
17
|
-
columns?: number;
|
|
18
|
-
column?: number;
|
|
19
|
-
order?: 'ascending' | 'descending';
|
|
20
|
-
comparison?: 'text' | 'number';
|
|
21
|
-
}
|
|
22
|
-
export declare const tablePlugins: (((ctx: Ctx) => () => void) | import("@milkdown/kit/ctx").MilkdownPlugin)[];
|
|
23
|
-
export declare function tableCommand(ctx: Ctx, command: TableCommand, options?: TableOptions): boolean;
|
|
24
|
-
export declare function dispatchTableOperation(view: EditorView, tr: Transaction): void;
|
|
25
|
-
export declare function configureTableMovement(ctx: Ctx, canEdit: () => boolean): void;
|
|
26
|
-
export declare function editableTable(table: ProseNode): boolean;
|
|
27
|
-
export declare function selectTableRectangle(tr: Transaction, tableStart: number, table: ProseNode, top: number, left: number, bottom: number, right: number): void;
|