@aicayzer/inkkit 0.1.7 → 0.2.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 +13 -37
- package/dist/chunks/{core-DkL-wDqy.js → core-C612uj1Q.js} +132 -61
- package/dist/chunks/{highlight-TSUdUlMi.js → highlight-AI86evan.js} +1 -1
- package/dist/core.d.ts +1 -1
- package/dist/core.js +1 -1
- package/dist/editor.d.ts +3 -1
- package/dist/index.js +1 -1
- package/dist/style.css +7 -1
- package/dist/types.d.ts +5 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,48 +1,32 @@
|
|
|
1
1
|
# Inkkit
|
|
2
2
|
|
|
3
|
-
A Markdown editor for
|
|
3
|
+
A Markdown editor for web pages and for apps that host a web view. People edit formatted text, and your app saves the Markdown as it was written: an unedited document is saved unchanged, and an edit rewrites only the blocks it touches.
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
- Mermaid diagram previews, offline
|
|
8
|
-
- Copy as readable text or HTML, or copy the Markdown itself
|
|
9
|
-
- Images and files through your own storage adapter
|
|
10
|
-
- Your app owns the toolbar, menus, files and appearance
|
|
11
|
-
|
|
12
|
-
## How it works
|
|
5
|
+
<details>
|
|
6
|
+
<summary>How Inkkit preserves Markdown</summary>
|
|
13
7
|
|
|
14
8
|
<picture>
|
|
15
|
-
<source media="(prefers-color-scheme: dark)" srcset="
|
|
16
|
-
<img src="
|
|
9
|
+
<source media="(prefers-color-scheme: dark)" srcset="docs/images/how-inkkit-works-dark.svg">
|
|
10
|
+
<img src="docs/images/how-inkkit-works.svg" alt="Inkkit keeps unchanged source and checks edited blocks before your app saves them.">
|
|
17
11
|
</picture>
|
|
18
12
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
For the exact guarantees, see [Preservation](https://github.com/aicayzer/inkkit/blob/main/docs/preservation.md).
|
|
13
|
+
</details>
|
|
22
14
|
|
|
23
|
-
##
|
|
15
|
+
## Get started
|
|
24
16
|
|
|
25
17
|
```sh
|
|
26
18
|
npm install @aicayzer/inkkit
|
|
27
19
|
```
|
|
28
20
|
|
|
29
|
-
An app that does not render diagrams can import from `@aicayzer/inkkit/core` instead. That entry leaves Mermaid out of the app's bundle and keeps diagrams as editable source. See [Builds without diagrams](https://github.com/aicayzer/inkkit/blob/main/docs/api.md#builds-without-diagrams).
|
|
30
|
-
|
|
31
|
-
## Supported engines
|
|
32
|
-
|
|
33
|
-
Inkkit supports Safari and `WKWebView` 17.5 or later (iOS 17.5, macOS 14.5), Chrome and Edge 123 or later, and Firefox 125 or later. The host page must declare UTF-8. See [Supported engines](https://github.com/aicayzer/inkkit/blob/main/docs/integration.md#supported-engines) for the APIs behind these versions.
|
|
34
|
-
|
|
35
|
-
## Use
|
|
36
|
-
|
|
37
21
|
```ts
|
|
38
22
|
import { InkKitEditor } from '@aicayzer/inkkit'
|
|
39
23
|
import '@aicayzer/inkkit/style.css'
|
|
40
24
|
|
|
41
25
|
const editor = await InkKitEditor.mount(document.getElementById('editor')!, {
|
|
42
|
-
changed(
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
26
|
+
changed() {},
|
|
27
|
+
error(error) {
|
|
28
|
+
console.error(error.code, error.message)
|
|
29
|
+
},
|
|
46
30
|
})
|
|
47
31
|
|
|
48
32
|
editor.loadDocument({
|
|
@@ -55,17 +39,9 @@ editor.loadDocument({
|
|
|
55
39
|
const { text } = editor.snapshot(1)
|
|
56
40
|
```
|
|
57
41
|
|
|
58
|
-
##
|
|
59
|
-
|
|
60
|
-
- [Memos](https://github.com/aicayzer/memos): a small Mac app for memos, in one floating window
|
|
61
|
-
- [PadPad](https://github.com/aicayzer/padpad): a small Mac app for quick text and files
|
|
62
|
-
|
|
63
|
-
## Learn more
|
|
42
|
+
## Documentation
|
|
64
43
|
|
|
65
|
-
|
|
66
|
-
- [Integration guide](https://github.com/aicayzer/inkkit/blob/main/docs/integration.md)
|
|
67
|
-
- [API reference](https://github.com/aicayzer/inkkit/blob/main/docs/api.md)
|
|
68
|
-
- [All documentation](https://github.com/aicayzer/inkkit/blob/main/docs/README.md)
|
|
44
|
+
[inkkit.cyzr.me](https://inkkit.cyzr.me) covers how Inkkit works, compatibility, integration guides and the API reference.
|
|
69
45
|
|
|
70
46
|
## License
|
|
71
47
|
|
|
@@ -35008,7 +35008,7 @@ var associationAttrs = {
|
|
|
35008
35008
|
identifier: { default: "" }
|
|
35009
35009
|
};
|
|
35010
35010
|
/** Whether an element reads as `text`, with whitespace collapsed as shown. */
|
|
35011
|
-
function showsText
|
|
35011
|
+
function showsText(dom, text) {
|
|
35012
35012
|
const shown = (value) => value.replace(/\s+/g, " ").trim();
|
|
35013
35013
|
return shown(dom.textContent ?? "") === shown(text);
|
|
35014
35014
|
}
|
|
@@ -35033,7 +35033,7 @@ var references = [
|
|
|
35033
35033
|
const url = dom.getAttribute("data-inkkit-url") ?? "";
|
|
35034
35034
|
const label = dom.getAttribute("data-inkkit-label") ?? "";
|
|
35035
35035
|
const title = dom.getAttribute("data-inkkit-title");
|
|
35036
|
-
if (!isSafeLinkTarget(url) || !showsText
|
|
35036
|
+
if (!isSafeLinkTarget(url) || !showsText(dom, definitionText(label, url, title))) return false;
|
|
35037
35037
|
return {
|
|
35038
35038
|
label,
|
|
35039
35039
|
identifier: dom.getAttribute("data-inkkit-reference-definition") ?? "",
|
|
@@ -35085,7 +35085,7 @@ var references = [
|
|
|
35085
35085
|
tag: "sup[data-inkkit-footnote-reference]",
|
|
35086
35086
|
getAttrs: (dom) => {
|
|
35087
35087
|
const label = dom.getAttribute("data-inkkit-label") ?? "";
|
|
35088
|
-
return showsText
|
|
35088
|
+
return showsText(dom, label) ? {
|
|
35089
35089
|
label,
|
|
35090
35090
|
identifier: dom.getAttribute("data-inkkit-footnote-reference") ?? ""
|
|
35091
35091
|
} : false;
|
|
@@ -35529,7 +35529,7 @@ var wikiLinkSchema = $node("inkkit_wiki_link", () => ({
|
|
|
35529
35529
|
tag: "span[data-inkkit-wiki]",
|
|
35530
35530
|
getAttrs(dom) {
|
|
35531
35531
|
const parsed = parseLinkedSyntax(dom.getAttribute("data-inkkit-wiki-raw") ?? "", dom.getAttribute("data-inkkit-wiki-table") === "true");
|
|
35532
|
-
return parsed && !parsed.embed && showsWikiTarget(parsed) && showsText
|
|
35532
|
+
return parsed && !parsed.embed && showsWikiTarget(parsed) && showsText(dom, parsed.label) ? {
|
|
35533
35533
|
raw: parsed.raw,
|
|
35534
35534
|
target: parsed.target,
|
|
35535
35535
|
fragment: parsed.fragment,
|
|
@@ -43736,6 +43736,7 @@ function commentNode(inline) {
|
|
|
43736
43736
|
marks: "",
|
|
43737
43737
|
code: true,
|
|
43738
43738
|
defining: true,
|
|
43739
|
+
createGapCursor: !inline,
|
|
43739
43740
|
attrs: {
|
|
43740
43741
|
syntax: { default: "html" },
|
|
43741
43742
|
block: { default: !inline }
|
|
@@ -44924,50 +44925,63 @@ function blockDropRange(view, x, y) {
|
|
|
44924
44925
|
* callout, where typing would change text the reader can't see or didn't
|
|
44925
44926
|
* choose.
|
|
44926
44927
|
*/
|
|
44927
|
-
function caretAfter(doc, pos) {
|
|
44928
|
+
function caretAfter(doc, pos, folds = /* @__PURE__ */ new Map()) {
|
|
44929
|
+
const hides = (node) => isComment(node) || node.type.name === "inkkit_callout" && (folds.get(node) ?? node.attrs.fold === "-");
|
|
44930
|
+
const concealedDepth = ($pos) => {
|
|
44931
|
+
for (let depth = 1; depth <= $pos.depth; depth++) if (hides($pos.node(depth))) return depth;
|
|
44932
|
+
return -1;
|
|
44933
|
+
};
|
|
44934
|
+
const concealed = ($pos) => concealedDepth($pos) >= 0;
|
|
44928
44935
|
const $pos = doc.resolve(pos);
|
|
44929
44936
|
const before = $pos.nodeBefore;
|
|
44930
44937
|
if (before?.isTextblock && !concealed(doc.resolve(pos - 1))) return TextSelection.create(doc, pos - 1);
|
|
44931
|
-
|
|
44938
|
+
const gap = GapCursor;
|
|
44939
|
+
const forward = before && !showsText(before) ? shownText(doc, pos, 1) : null;
|
|
44940
|
+
if (forward) return forward;
|
|
44941
|
+
if (gap.valid($pos)) return new GapCursor($pos);
|
|
44932
44942
|
const [first, second] = before && !showsText(before) ? [1, -1] : [-1, 1];
|
|
44933
44943
|
return shownText(doc, pos, first) ?? shownText(doc, pos, second) ?? Selection.near($pos);
|
|
44934
|
-
|
|
44935
|
-
|
|
44936
|
-
|
|
44937
|
-
|
|
44938
|
-
|
|
44939
|
-
|
|
44940
|
-
|
|
44941
|
-
|
|
44942
|
-
|
|
44943
|
-
|
|
44944
|
-
}
|
|
44945
|
-
function showsText(node) {
|
|
44946
|
-
if (hides(node)) return false;
|
|
44947
|
-
if (node.isTextblock) return true;
|
|
44948
|
-
let found = false;
|
|
44949
|
-
node.descendants((child) => {
|
|
44950
|
-
if (found || hides(child)) return false;
|
|
44951
|
-
if (child.isTextblock) found = true;
|
|
44952
|
-
return !found;
|
|
44953
|
-
});
|
|
44954
|
-
return found;
|
|
44955
|
-
}
|
|
44956
|
-
function shownText(doc, pos, dir) {
|
|
44957
|
-
let $from = doc.resolve(pos);
|
|
44958
|
-
for (;;) {
|
|
44959
|
-
const found = TextSelection.findFrom($from, dir, true);
|
|
44960
|
-
if (!found) return null;
|
|
44961
|
-
const depth = concealedDepth(found.$head);
|
|
44962
|
-
if (depth < 0) return found;
|
|
44963
|
-
$from = doc.resolve(dir > 0 ? found.$head.after(depth) : found.$head.before(depth));
|
|
44944
|
+
function showsText(node) {
|
|
44945
|
+
if (hides(node)) return false;
|
|
44946
|
+
if (node.isTextblock) return true;
|
|
44947
|
+
let found = false;
|
|
44948
|
+
node.descendants((child) => {
|
|
44949
|
+
if (found || hides(child)) return false;
|
|
44950
|
+
if (child.isTextblock) found = true;
|
|
44951
|
+
return !found;
|
|
44952
|
+
});
|
|
44953
|
+
return found;
|
|
44964
44954
|
}
|
|
44955
|
+
function shownText(doc, pos, dir) {
|
|
44956
|
+
let $from = doc.resolve(pos);
|
|
44957
|
+
for (;;) {
|
|
44958
|
+
const found = TextSelection.findFrom($from, dir, true);
|
|
44959
|
+
if (!found) return null;
|
|
44960
|
+
const depth = concealedDepth(found.$head);
|
|
44961
|
+
if (depth < 0) return found;
|
|
44962
|
+
$from = doc.resolve(dir > 0 ? found.$head.after(depth) : found.$head.before(depth));
|
|
44963
|
+
}
|
|
44964
|
+
}
|
|
44965
|
+
}
|
|
44966
|
+
/** Capture reader folding before dispatch, then map it to the new document. */
|
|
44967
|
+
function calloutFolds(view, tr) {
|
|
44968
|
+
const folds = /* @__PURE__ */ new Map();
|
|
44969
|
+
view.state.doc.descendants((node, pos) => {
|
|
44970
|
+
if (node.type.name !== "inkkit_callout") return;
|
|
44971
|
+
const dom = view.nodeDOM(pos);
|
|
44972
|
+
if (!(dom instanceof HTMLElement)) return;
|
|
44973
|
+
const mapped = tr.mapping.mapResult(pos, 1);
|
|
44974
|
+
if (mapped.deleted) return;
|
|
44975
|
+
const next = tr.doc.nodeAt(mapped.pos);
|
|
44976
|
+
if (next?.type === node.type) folds.set(next, dom.getAttribute("data-inkkit-folded") === "true");
|
|
44977
|
+
});
|
|
44978
|
+
return folds;
|
|
44965
44979
|
}
|
|
44966
44980
|
/**
|
|
44967
44981
|
* Puts the caret just after what the transaction's last step inserted, so
|
|
44968
44982
|
* typing continues after pasted or dropped content instead of replacing it.
|
|
44969
44983
|
*/
|
|
44970
|
-
function caretAfterInsertion(tr) {
|
|
44984
|
+
function caretAfterInsertion(tr, view) {
|
|
44971
44985
|
const map = tr.mapping.maps[tr.mapping.maps.length - 1];
|
|
44972
44986
|
let end;
|
|
44973
44987
|
map?.forEach((_from, _to, _newFrom, newTo) => {
|
|
@@ -44975,7 +44989,7 @@ function caretAfterInsertion(tr) {
|
|
|
44975
44989
|
});
|
|
44976
44990
|
if (end == null) return tr;
|
|
44977
44991
|
const $end = tr.doc.resolve(end);
|
|
44978
|
-
return tr.setSelection($end.parent.inlineContent ? TextSelection.create(tr.doc, end) : caretAfter(tr.doc, end));
|
|
44992
|
+
return tr.setSelection($end.parent.inlineContent ? TextSelection.create(tr.doc, end) : caretAfter(tr.doc, end, view && calloutFolds(view, tr)));
|
|
44979
44993
|
}
|
|
44980
44994
|
//#endregion
|
|
44981
44995
|
//#region src/code-fences.ts
|
|
@@ -48200,6 +48214,7 @@ var calloutSchema = $node("inkkit_callout", (ctx) => ({
|
|
|
48200
48214
|
group: "block",
|
|
48201
48215
|
content: "block+",
|
|
48202
48216
|
defining: true,
|
|
48217
|
+
createGapCursor: true,
|
|
48203
48218
|
attrs: {
|
|
48204
48219
|
kind: { default: "NOTE" },
|
|
48205
48220
|
marker: { default: "[!NOTE]" },
|
|
@@ -53851,7 +53866,7 @@ function pasteSpreadsheet(ctx, input, at) {
|
|
|
53851
53866
|
}
|
|
53852
53867
|
let grid;
|
|
53853
53868
|
try {
|
|
53854
|
-
grid = input.html?.match(/<table[\s>]/i) ? htmlGrid(view.state.schema, input.html) : input.text.includes(" ") ? textGrid(view.state.schema, input.text) : void 0;
|
|
53869
|
+
grid = input.html?.match(/<table[\s>]/i) ? htmlGrid(view.state.schema, input.html) : !input.html && input.text.includes(" ") && (inTable || looksLikeGrid(input.text)) ? textGrid(view.state.schema, input.text) : void 0;
|
|
53855
53870
|
} catch (error) {
|
|
53856
53871
|
if (inTable || !input.html) throw error;
|
|
53857
53872
|
if (!standaloneTable(input.html)) return false;
|
|
@@ -53869,7 +53884,7 @@ function pasteSpreadsheet(ctx, input, at) {
|
|
|
53869
53884
|
if (cursor < input.html.length) children.push(schema.text(input.html.slice(cursor)));
|
|
53870
53885
|
const content = importableSlice(ctx, new Slice(Fragment.from(schema.nodes.literal_markdown.create(null, children)), 0, 0)).content;
|
|
53871
53886
|
const selection = view.state.selection;
|
|
53872
|
-
dispatchTableOperation(view, at ? caretAfterInsertion(view.state.tr.replaceWith(at.from, at.to, content)) : selection.$from.parent.type.name === "paragraph" && selection.empty && selection.$from.parent.content.size === 0 ? view.state.tr.replaceWith(selection.$from.before(), selection.$from.after(), content) : content.childCount === 1 ? view.state.tr.replaceSelectionWith(content.firstChild) : view.state.tr.replaceSelection(new Slice(content, 0, 0)));
|
|
53887
|
+
dispatchTableOperation(view, at ? caretAfterInsertion(view.state.tr.replaceWith(at.from, at.to, content), view) : selection.$from.parent.type.name === "paragraph" && selection.empty && selection.$from.parent.content.size === 0 ? view.state.tr.replaceWith(selection.$from.before(), selection.$from.after(), content) : content.childCount === 1 ? view.state.tr.replaceSelectionWith(content.firstChild) : view.state.tr.replaceSelection(new Slice(content, 0, 0)));
|
|
53873
53888
|
return true;
|
|
53874
53889
|
}
|
|
53875
53890
|
if (!grid) return false;
|
|
@@ -53884,7 +53899,7 @@ function pasteSpreadsheet(ctx, input, at) {
|
|
|
53884
53899
|
if (node === table) tableStart = pos + 1;
|
|
53885
53900
|
});
|
|
53886
53901
|
if (tableStart < 0) reject();
|
|
53887
|
-
tr.setSelection(caretAfter(tr.doc, tableStart - 1 + table.nodeSize));
|
|
53902
|
+
tr.setSelection(caretAfter(tr.doc, tableStart - 1 + table.nodeSize, calloutFolds(view, tr)));
|
|
53888
53903
|
dispatchTableOperation(view, tr);
|
|
53889
53904
|
return true;
|
|
53890
53905
|
}
|
|
@@ -53929,6 +53944,12 @@ function standaloneTable(html) {
|
|
|
53929
53944
|
function reject() {
|
|
53930
53945
|
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.");
|
|
53931
53946
|
}
|
|
53947
|
+
function looksLikeGrid(input) {
|
|
53948
|
+
const rows = input.replace(/\r\n?/g, "\n").replace(/\n$/, "").split("\n");
|
|
53949
|
+
if (rows.length < 2) return false;
|
|
53950
|
+
const widths = rows.map((row) => row.split(" ").length);
|
|
53951
|
+
return widths[0] > 1 && widths.every((width) => width === widths[0]) && rows.some((row) => row.split(" ")[0].trim().length > 0);
|
|
53952
|
+
}
|
|
53932
53953
|
function textGrid(schema, input) {
|
|
53933
53954
|
const text = input.replace(/\r\n?/g, "\n").replace(/\n$/, "");
|
|
53934
53955
|
const rows = [[]];
|
|
@@ -54119,7 +54140,10 @@ var PasteController = class {
|
|
|
54119
54140
|
return mapped?.operation === operation ? mapped : operation;
|
|
54120
54141
|
}
|
|
54121
54142
|
cancelPending() {
|
|
54143
|
+
const operation = this.active;
|
|
54144
|
+
if (!operation) return;
|
|
54122
54145
|
this.active = void 0;
|
|
54146
|
+
operation.controller.abort();
|
|
54123
54147
|
this.options.onPendingChanged?.();
|
|
54124
54148
|
}
|
|
54125
54149
|
destroy() {
|
|
@@ -54131,6 +54155,26 @@ var PasteController = class {
|
|
|
54131
54155
|
const current = this.options.context();
|
|
54132
54156
|
if (this.active !== operation || current.documentId !== context.documentId || current.generation !== context.generation) throw new InkKitError("stale-document", "The document changed while images were importing.");
|
|
54133
54157
|
}
|
|
54158
|
+
async importImage(image, context, operation) {
|
|
54159
|
+
this.assertContext(context, operation);
|
|
54160
|
+
const signal = operation.controller.signal;
|
|
54161
|
+
let abort;
|
|
54162
|
+
const cancelled = new Promise((_, reject) => {
|
|
54163
|
+
abort = () => reject(new InkKitError(this.dead ? "destroyed" : "stale-document", "The image import was cancelled."));
|
|
54164
|
+
signal.addEventListener("abort", abort, { once: true });
|
|
54165
|
+
});
|
|
54166
|
+
try {
|
|
54167
|
+
return await Promise.race([new Promise((resolve) => {
|
|
54168
|
+
resolve(this.options.adapter.importImage(image, {
|
|
54169
|
+
...context,
|
|
54170
|
+
signal
|
|
54171
|
+
}));
|
|
54172
|
+
}), cancelled]);
|
|
54173
|
+
} finally {
|
|
54174
|
+
signal.removeEventListener("abort", abort);
|
|
54175
|
+
this.assertContext(context, operation);
|
|
54176
|
+
}
|
|
54177
|
+
}
|
|
54134
54178
|
commit(apply) {
|
|
54135
54179
|
return this.options.commit ? this.options.commit(apply) : apply();
|
|
54136
54180
|
}
|
|
@@ -54145,7 +54189,7 @@ var PasteController = class {
|
|
|
54145
54189
|
const blocks = Fragment.fromArray(topLevel(view.state.schema, slice.content));
|
|
54146
54190
|
const tr = view.state.tr.replaceWith(range.from, range.to, blocks);
|
|
54147
54191
|
const end = tr.mapping.map(range.to);
|
|
54148
|
-
this.dispatch(view, tr.setSelection(caretAfter(tr.doc, end)).scrollIntoView());
|
|
54192
|
+
this.dispatch(view, tr.setSelection(caretAfter(tr.doc, end, calloutFolds(view, tr))).scrollIntoView());
|
|
54149
54193
|
}
|
|
54150
54194
|
/** Imports the input at the selection, or in place of `target`. */
|
|
54151
54195
|
async run(input, files = [], target) {
|
|
@@ -54162,9 +54206,12 @@ var PasteController = class {
|
|
|
54162
54206
|
from: exit,
|
|
54163
54207
|
to: exit
|
|
54164
54208
|
};
|
|
54165
|
-
const operation =
|
|
54166
|
-
|
|
54167
|
-
|
|
54209
|
+
const operation = {
|
|
54210
|
+
...target ?? {
|
|
54211
|
+
from: view.state.selection.from,
|
|
54212
|
+
to: view.state.selection.to
|
|
54213
|
+
},
|
|
54214
|
+
controller: new AbortController()
|
|
54168
54215
|
};
|
|
54169
54216
|
const inCode = () => view.state.doc.resolve(this.anchor(operation).from).parent.type.spec.code;
|
|
54170
54217
|
this.active = operation;
|
|
@@ -54213,14 +54260,14 @@ var PasteController = class {
|
|
|
54213
54260
|
if (!reference) {
|
|
54214
54261
|
const captured = images.find((image) => image.source === source) ?? dataImage(source) ?? positional[index++];
|
|
54215
54262
|
if (!captured || !this.options.adapter) throw new Error("The pasted image is unavailable.");
|
|
54216
|
-
reference = (await this.
|
|
54263
|
+
reference = (await this.importImage(captured, context, operation)).reference;
|
|
54217
54264
|
this.assertContext(context, operation);
|
|
54218
54265
|
imported.set(source, reference);
|
|
54219
54266
|
}
|
|
54220
54267
|
element.setAttribute("src", reference);
|
|
54221
54268
|
element.removeAttribute("srcset");
|
|
54222
54269
|
} catch (error) {
|
|
54223
|
-
if (error instanceof InkKitError) throw error;
|
|
54270
|
+
if (error instanceof InkKitError && error.code !== "image-unavailable") throw error;
|
|
54224
54271
|
element.replaceWith(document.createTextNode(`[${alt}: image unavailable]`));
|
|
54225
54272
|
this.options.onError?.(coded(error, "image-unavailable", error instanceof Error ? error.message : "The pasted image is unavailable."));
|
|
54226
54273
|
}
|
|
@@ -54265,7 +54312,7 @@ var PasteController = class {
|
|
|
54265
54312
|
if (input.text) nodes.push(schema.nodes.paragraph.create(null, schema.text(input.text)));
|
|
54266
54313
|
for (const image of images) try {
|
|
54267
54314
|
if (!this.options.adapter) throw new InkKitError("image-unavailable", "No image adapter is configured.");
|
|
54268
|
-
const imported = await this.
|
|
54315
|
+
const imported = await this.importImage(image, context, operation);
|
|
54269
54316
|
this.assertContext(context, operation);
|
|
54270
54317
|
const imageNode = schema.nodes.image?.create({
|
|
54271
54318
|
src: imported.reference,
|
|
@@ -54312,8 +54359,8 @@ var PasteController = class {
|
|
|
54312
54359
|
});
|
|
54313
54360
|
return;
|
|
54314
54361
|
}
|
|
54315
|
-
if (anchor.from === anchor.to && insertion.parent.type.name === "paragraph" && insertion.parent.content.size === 0 && slice.content.firstChild?.isBlock && slice.content.firstChild.type.spec.isolating) this.dispatch(view, caretAfterInsertion(view.state.tr.replaceRange(insertion.before(), insertion.after(), new Slice(slice.content, 0, 0))).scrollIntoView());
|
|
54316
|
-
else this.dispatch(view, caretAfterInsertion(view.state.tr.replaceRange(anchor.from, anchor.to, source == null ? slice : withEdgeSpaces(slice, source, view.state.doc.resolve(anchor.from), view.state.doc.resolve(anchor.to)))).scrollIntoView());
|
|
54362
|
+
if (anchor.from === anchor.to && insertion.parent.type.name === "paragraph" && insertion.parent.content.size === 0 && slice.content.firstChild?.isBlock && slice.content.firstChild.type.spec.isolating) this.dispatch(view, caretAfterInsertion(view.state.tr.replaceRange(insertion.before(), insertion.after(), new Slice(slice.content, 0, 0)), view).scrollIntoView());
|
|
54363
|
+
else this.dispatch(view, caretAfterInsertion(view.state.tr.replaceRange(anchor.from, anchor.to, source == null ? slice : withEdgeSpaces(slice, source, view.state.doc.resolve(anchor.from), view.state.doc.resolve(anchor.to))), view).scrollIntoView());
|
|
54317
54364
|
} finally {
|
|
54318
54365
|
if (this.active === operation) {
|
|
54319
54366
|
this.active = void 0;
|
|
@@ -55315,17 +55362,35 @@ function navigateFormattedHeading(view, requested, context) {
|
|
|
55315
55362
|
}
|
|
55316
55363
|
//#endregion
|
|
55317
55364
|
//#region src/tasks.ts
|
|
55365
|
+
function onTaskMarker(event) {
|
|
55366
|
+
const target = event.target;
|
|
55367
|
+
if (!(target instanceof HTMLElement) || !target.matches("li[data-item-type=\"task\"]")) return false;
|
|
55368
|
+
const marker = getComputedStyle(target, "::before");
|
|
55369
|
+
const rect = target.getBoundingClientRect();
|
|
55370
|
+
const left = rect.left + parseFloat(marker.left);
|
|
55371
|
+
const top = rect.top + parseFloat(marker.top);
|
|
55372
|
+
return event.clientX >= left && event.clientX <= left + parseFloat(marker.width) && event.clientY >= top && event.clientY <= top + parseFloat(marker.height);
|
|
55373
|
+
}
|
|
55318
55374
|
var taskListPlugin = $prose(() => new Plugin({
|
|
55319
55375
|
key: new PluginKey("taskToggle"),
|
|
55320
|
-
props: {
|
|
55321
|
-
|
|
55322
|
-
|
|
55323
|
-
|
|
55324
|
-
|
|
55325
|
-
|
|
55326
|
-
|
|
55327
|
-
|
|
55328
|
-
|
|
55376
|
+
props: { handleDOMEvents: {
|
|
55377
|
+
mousedown(view, event) {
|
|
55378
|
+
if (!view.editable || event.button !== 0 || !onTaskMarker(event)) return false;
|
|
55379
|
+
event.preventDefault();
|
|
55380
|
+
return true;
|
|
55381
|
+
},
|
|
55382
|
+
click(view, event) {
|
|
55383
|
+
if (!view.editable || event.button !== 0 || !onTaskMarker(event)) return false;
|
|
55384
|
+
const nodePos = view.posAtDOM(event.target, 0) - 1;
|
|
55385
|
+
const node = view.state.doc.nodeAt(nodePos);
|
|
55386
|
+
if (node?.type.name !== "list_item" || node.attrs.checked == null) return false;
|
|
55387
|
+
event.preventDefault();
|
|
55388
|
+
view.dispatch(view.state.tr.setNodeMarkup(nodePos, void 0, {
|
|
55389
|
+
...node.attrs,
|
|
55390
|
+
checked: !node.attrs.checked
|
|
55391
|
+
}));
|
|
55392
|
+
return true;
|
|
55393
|
+
}
|
|
55329
55394
|
} }
|
|
55330
55395
|
}));
|
|
55331
55396
|
function listItemsInSelection(view) {
|
|
@@ -56219,7 +56284,7 @@ var sourceGroupDelay = 500;
|
|
|
56219
56284
|
var sourceStepLimit = 100;
|
|
56220
56285
|
/**
|
|
56221
56286
|
* The editor. Create it with `InkKitEditor.mount`, load a document, and read it back with
|
|
56222
|
-
* `snapshot`. The reference is https://
|
|
56287
|
+
* `snapshot`. The reference is https://inkkit.cyzr.me/reference/editor.
|
|
56223
56288
|
*/
|
|
56224
56289
|
var InkKitEditor = class InkKitEditor {
|
|
56225
56290
|
options;
|
|
@@ -57157,6 +57222,11 @@ var InkKitEditor = class InkKitEditor {
|
|
|
57157
57222
|
...result
|
|
57158
57223
|
};
|
|
57159
57224
|
}
|
|
57225
|
+
/** Cancels the pending image paste without changing the document or editability. */
|
|
57226
|
+
cancelPendingImports(expectedGeneration) {
|
|
57227
|
+
this.assertReady(expectedGeneration);
|
|
57228
|
+
this.pasteController.cancelPending();
|
|
57229
|
+
}
|
|
57160
57230
|
/** Pastes content the host read from the native clipboard. Capture it once; don't read the
|
|
57161
57231
|
* clipboard again while this runs. */
|
|
57162
57232
|
async paste(input, expectedGeneration) {
|
|
@@ -57440,7 +57510,7 @@ var InkKitEditor = class InkKitEditor {
|
|
|
57440
57510
|
return true;
|
|
57441
57511
|
}
|
|
57442
57512
|
}));
|
|
57443
|
-
}).use(labelsCtx).use(instance.pasteController.plugin).use(visibleClipboard).use($prose(() => instance.suggestions.plugin())).use(instance.keymapPlugin).use(createDialect(Boolean(options.images || options.files), Boolean(options.wikiLinks), Boolean(options.files))).use(codeControlCtx).use(codeControlsPlugin(() => instance.viewport().rect)).use(tablePlugins).use(tableBlock).use(instance.changePlugin).use(instance.historyInputPlugin).use(history).use(clipboard).use(cursor).use(taskListPlugin).use(quoteBackspace).use(calloutEnter).use(literalEnter).use(literalReread).use(listItemBackspace).use(listItemShiftTab).use(nestedItemEnter).use(rejoinLists).use(movedListItems).use(textInputPolicy).use(events.copy ? codeCopyPlugin((text) => events.copy?.(text)) : []).use(placeholderPlugin).use(options.rendering?.codeHighlighting === false ? [] : (await import("./highlight-
|
|
57513
|
+
}).use(labelsCtx).use(instance.pasteController.plugin).use(visibleClipboard).use($prose(() => instance.suggestions.plugin())).use(instance.keymapPlugin).use(createDialect(Boolean(options.images || options.files), Boolean(options.wikiLinks), Boolean(options.files))).use(codeControlCtx).use(codeControlsPlugin(() => instance.viewport().rect)).use(tablePlugins).use(tableBlock).use(instance.changePlugin).use(instance.historyInputPlugin).use(history).use(clipboard).use(cursor).use(taskListPlugin).use(quoteBackspace).use(calloutEnter).use(literalEnter).use(literalReread).use(listItemBackspace).use(listItemShiftTab).use(nestedItemEnter).use(rejoinLists).use(movedListItems).use(textInputPolicy).use(events.copy ? codeCopyPlugin((text) => events.copy?.(text)) : []).use(placeholderPlugin).use(options.rendering?.codeHighlighting === false ? [] : (await import("./highlight-AI86evan.js")).highlightPlugin).use(options.rendering?.diagramPreview === false || !diagramsAvailable() ? [] : mermaidPreview((error) => instance.report(error))).use(selectionPlugin).use($prose(() => search())).use(instance.policyPlugin).use(options.wikiLinks ? wikiLinkView(options.wikiLinks, {
|
|
57444
57514
|
capture: () => instance.adapterCapture(),
|
|
57445
57515
|
active: () => instance.ready && !instance.destroyed && !instance.literalSurface,
|
|
57446
57516
|
labels: {
|
|
@@ -58786,6 +58856,7 @@ var InkKitEditor = class InkKitEditor {
|
|
|
58786
58856
|
"printableSnapshot",
|
|
58787
58857
|
"clipboardSnapshot",
|
|
58788
58858
|
"paste",
|
|
58859
|
+
"cancelPendingImports",
|
|
58789
58860
|
"pasteAsPlainText",
|
|
58790
58861
|
"commandState",
|
|
58791
58862
|
"setEditable",
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as Decoration, c as PluginKey, d as __toESM, i as $prose, o as DecorationSet, s as Plugin, u as __commonJSMin } from "./core-
|
|
1
|
+
import { a as Decoration, c as PluginKey, d as __toESM, i as $prose, o as DecorationSet, s as Plugin, u as __commonJSMin } from "./core-C612uj1Q.js";
|
|
2
2
|
//#region node_modules/.pnpm/highlight.js@11.11.2/node_modules/highlight.js/es/languages/arduino.js
|
|
3
3
|
/** @type LanguageFn */
|
|
4
4
|
function cPlusPlus(hljs) {
|
package/dist/core.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { InkKitEditor } from './editor.js';
|
|
2
2
|
export type { EditorEvents, EditorOptions, TextInputPreferences, CommandState, EditingMode, CaretState, Mark, Block, FormatCommand, FormatOptions, KeyInput, ImageInsertion, ShortcutName, Keymap, } from './editor.js';
|
|
3
3
|
export { InkKitError } from './types.js';
|
|
4
|
-
export type { DocumentFormat, EditorLabels, Heading, TableCommand, TableOptions, BlockMoveDirection, DocumentContext, DocumentInput, DocumentSnapshot, DocumentVersion, EditorErrorCode, ImageAdapter, WikiLinkReference, WikiLinkAdapter, FileReference, ClientPoint, FileContext, FilePresentation, FileAdapter, CapturedImage, PortableImage, ClipboardInput, ClipboardOutput, ClipboardScope, ClipboardImage, ClipboardDiagram, PrintableDocument, PrintableWarning, TextRange, ReadableTextSnapshot, TextRect, ViewportInsets, ViewportOptions, ViewportSnapshot, } from './types.js';
|
|
4
|
+
export type { DocumentFormat, EditorLabels, Heading, TableCommand, TableOptions, BlockMoveDirection, DocumentContext, DocumentInput, DocumentSnapshot, DocumentVersion, EditorErrorCode, ImageAdapter, ImageImportContext, WikiLinkReference, WikiLinkAdapter, FileReference, ClientPoint, FileContext, FilePresentation, FileAdapter, CapturedImage, PortableImage, ClipboardInput, ClipboardOutput, ClipboardScope, ClipboardImage, ClipboardDiagram, PrintableDocument, PrintableWarning, TextRange, ReadableTextSnapshot, TextRect, ViewportInsets, ViewportOptions, ViewportSnapshot, } from './types.js';
|
|
5
5
|
export type { SlashMenuOptions, SlashCommandName, SlashCommand } from './types.js';
|
package/dist/core.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { r as InkKitError, t as InkKitEditor } from "./chunks/core-
|
|
1
|
+
import { r as InkKitError, t as InkKitEditor } from "./chunks/core-C612uj1Q.js";
|
|
2
2
|
export { InkKitEditor, InkKitError };
|
package/dist/editor.d.ts
CHANGED
|
@@ -143,7 +143,7 @@ export interface EditorEvents {
|
|
|
143
143
|
export declare const editorEvents: readonly ["changed", "commandStateChanged", "openLink", "copy", "error", "clipboard"];
|
|
144
144
|
/**
|
|
145
145
|
* The editor. Create it with `InkKitEditor.mount`, load a document, and read it back with
|
|
146
|
-
* `snapshot`. The reference is https://
|
|
146
|
+
* `snapshot`. The reference is https://inkkit.cyzr.me/reference/editor.
|
|
147
147
|
*/
|
|
148
148
|
export declare class InkKitEditor {
|
|
149
149
|
private readonly options;
|
|
@@ -321,6 +321,8 @@ export declare class InkKitEditor {
|
|
|
321
321
|
/** Prepares the document or the selection for the native clipboard. Rejects with `stale-document`
|
|
322
322
|
* if the document changes first. */
|
|
323
323
|
clipboardSnapshot(scope?: ClipboardScope, expectedGeneration?: number): Promise<ClipboardOutput>;
|
|
324
|
+
/** Cancels the pending image paste without changing the document or editability. */
|
|
325
|
+
cancelPendingImports(expectedGeneration?: number): void;
|
|
324
326
|
/** Pastes content the host read from the native clipboard. Capture it once; don't read the
|
|
325
327
|
* clipboard again while this runs. */
|
|
326
328
|
paste(input: ClipboardInput, expectedGeneration?: number): Promise<void>;
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as registerMermaid, r as InkKitError, t as InkKitEditor } from "./chunks/core-
|
|
1
|
+
import { n as registerMermaid, r as InkKitError, t as InkKitEditor } from "./chunks/core-C612uj1Q.js";
|
|
2
2
|
//#region src/index.ts
|
|
3
3
|
registerMermaid(async () => (await import("mermaid")).default);
|
|
4
4
|
//#endregion
|
package/dist/style.css
CHANGED
|
@@ -154,9 +154,11 @@
|
|
|
154
154
|
transform: translate(-50%, -50%);
|
|
155
155
|
border-radius: 4px;
|
|
156
156
|
box-shadow: 0 0 0 1px var(--_inkkit-rule);
|
|
157
|
-
cursor: grab;
|
|
158
157
|
touch-action: none;
|
|
159
158
|
}
|
|
159
|
+
.inkkit-root .inkkit-table-controls .inkkit-table-grip:not(:disabled) {
|
|
160
|
+
cursor: grab;
|
|
161
|
+
}
|
|
160
162
|
.inkkit-root .inkkit-table-grip[data-inkkit-axis='column'] {
|
|
161
163
|
width: 24px;
|
|
162
164
|
height: 14px;
|
|
@@ -252,6 +254,10 @@
|
|
|
252
254
|
outline-offset: 2px;
|
|
253
255
|
border-radius: 6px;
|
|
254
256
|
}
|
|
257
|
+
/* A gap or node selection draws its own indicator, not a native text caret. */
|
|
258
|
+
.inkkit-root .ProseMirror.ProseMirror-hideselection {
|
|
259
|
+
caret-color: transparent;
|
|
260
|
+
}
|
|
255
261
|
.inkkit-root .ProseMirror-gapcursor {
|
|
256
262
|
display: none;
|
|
257
263
|
pointer-events: none;
|
package/dist/types.d.ts
CHANGED
|
@@ -51,6 +51,10 @@ export interface PortableImage {
|
|
|
51
51
|
mimeType: string;
|
|
52
52
|
filename?: string;
|
|
53
53
|
}
|
|
54
|
+
/** The document and cancellation signal for one image import. */
|
|
55
|
+
export interface ImageImportContext extends DocumentContext {
|
|
56
|
+
signal: AbortSignal;
|
|
57
|
+
}
|
|
54
58
|
/** Stores, shows and exports the images a host owns. References stay opaque to the editor. */
|
|
55
59
|
export interface ImageAdapter {
|
|
56
60
|
/** The display URL for `reference`, or `undefined` when the image is unavailable. */
|
|
@@ -58,7 +62,7 @@ export interface ImageAdapter {
|
|
|
58
62
|
url: string;
|
|
59
63
|
} | undefined;
|
|
60
64
|
/** Stores the bytes and returns the reference to write into the Markdown. */
|
|
61
|
-
importImage(input: CapturedImage, context:
|
|
65
|
+
importImage(input: CapturedImage, context: ImageImportContext): Promise<{
|
|
62
66
|
reference: string;
|
|
63
67
|
}>;
|
|
64
68
|
/** The stored bytes and type of `reference`, for portable clipboard and print output. */
|