@quillmark/wasm 0.110.0 → 0.112.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/CHANGELOG.md +322 -0
- package/README.md +2 -2
- package/backends/pdfform/wasm.d.ts +75 -23
- package/backends/pdfform/wasm.js +60 -7
- package/backends/pdfform/wasm_bg.wasm +0 -0
- package/backends/pdfform/wasm_bg.wasm.d.ts +3 -2
- package/backends/typst/wasm.d.ts +75 -23
- package/backends/typst/wasm.js +60 -7
- package/backends/typst/wasm_bg.wasm +0 -0
- package/backends/typst/wasm_bg.wasm.d.ts +3 -2
- package/core/wasm.d.ts +54 -12
- package/core/wasm.js +41 -0
- package/core/wasm_bg.wasm +0 -0
- package/core/wasm_bg.wasm.d.ts +1 -0
- package/package.json +1 -1
- package/runtime/runtime.d.ts +28 -16
- package/runtime/runtime.js +27 -23
package/core/wasm.js
CHANGED
|
@@ -279,6 +279,10 @@ export class Document {
|
|
|
279
279
|
* Throws on an out-of-range card, a field that is not richtext, a malformed
|
|
280
280
|
* bundle, or an op that applies out of bounds; the value is unchanged on a
|
|
281
281
|
* failed apply.
|
|
282
|
+
*
|
|
283
|
+
* Each text-moving channel rebases the marks already in the field, by the
|
|
284
|
+
* rule on `ChangeBundle`; `mapMarks` answers where they land, so a caller
|
|
285
|
+
* building `markOps` need not predict it.
|
|
282
286
|
* @param {Addr | string} addr
|
|
283
287
|
* @param {ChangeBundle} bundle
|
|
284
288
|
*/
|
|
@@ -1749,11 +1753,48 @@ export function importMarkdown(markdown) {
|
|
|
1749
1753
|
}
|
|
1750
1754
|
}
|
|
1751
1755
|
|
|
1756
|
+
/**
|
|
1757
|
+
* Where `bundle`'s text-moving channels (`delta`, then `islandOps`, then
|
|
1758
|
+
* `lineOps`) leave `content`'s marks: the final-text coordinates the bundle's
|
|
1759
|
+
* `markOps` are written in, under the rebase rule stated on `ChangeBundle`.
|
|
1760
|
+
* The document-free read an editor diffs against to decide which `markOps` to
|
|
1761
|
+
* emit, rather than reproducing that rule in its own language.
|
|
1762
|
+
*
|
|
1763
|
+
* `bundle.markOps` are ignored. The answer is normalized, as the store's is:
|
|
1764
|
+
* marks a text move drops (out of range, zero-width formatting) are absent,
|
|
1765
|
+
* and same-kind runs a move left adjacent arrive already unioned, so a bundle
|
|
1766
|
+
* carrying no `markOps` names the marks the field will hold.
|
|
1767
|
+
* Throws on a non-content `content`, a malformed bundle, or an op that applies
|
|
1768
|
+
* out of bounds: `applyChange`'s errors on the same ops.
|
|
1769
|
+
* @param {Content} content
|
|
1770
|
+
* @param {ChangeBundle} bundle
|
|
1771
|
+
* @returns {ContentMark[]}
|
|
1772
|
+
*/
|
|
1773
|
+
export function mapMarks(content, bundle) {
|
|
1774
|
+
try {
|
|
1775
|
+
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
|
|
1776
|
+
wasm.mapMarks(retptr, addHeapObject(content), addHeapObject(bundle));
|
|
1777
|
+
var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
|
|
1778
|
+
var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
|
|
1779
|
+
var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true);
|
|
1780
|
+
if (r2) {
|
|
1781
|
+
throw takeObject(r1);
|
|
1782
|
+
}
|
|
1783
|
+
return takeObject(r0);
|
|
1784
|
+
} finally {
|
|
1785
|
+
wasm.__wbindgen_add_to_stack_pointer(16);
|
|
1786
|
+
}
|
|
1787
|
+
}
|
|
1788
|
+
|
|
1752
1789
|
/**
|
|
1753
1790
|
* Map a base content position (a USV index into `Content.text`, not a UTF-16
|
|
1754
1791
|
* offset) through a `delta` to its new position, holding a caret stable across
|
|
1755
1792
|
* a `revise`. `assoc` decides the side of a same-position insertion (`"after"`
|
|
1756
1793
|
* moves past it). Throws on a malformed `delta`.
|
|
1794
|
+
*
|
|
1795
|
+
* This maps a position the *caller* holds. For the marks already in a field,
|
|
1796
|
+
* `mapMarks` applies the store's own assoc rule across every channel of a
|
|
1797
|
+
* `ChangeBundle`.
|
|
1757
1798
|
* @param {Delta} delta
|
|
1758
1799
|
* @param {number} pos
|
|
1759
1800
|
* @param {Assoc} assoc
|
package/core/wasm_bg.wasm
CHANGED
|
Binary file
|
package/core/wasm_bg.wasm.d.ts
CHANGED
|
@@ -61,6 +61,7 @@ export const document_warnings: (a: number, b: number) => void;
|
|
|
61
61
|
export const exportMarkdown: (a: number, b: number) => void;
|
|
62
62
|
export const formatDocPath: (a: number, b: number) => void;
|
|
63
63
|
export const importMarkdown: (a: number, b: number, c: number) => void;
|
|
64
|
+
export const mapMarks: (a: number, b: number, c: number) => void;
|
|
64
65
|
export const mapPos: (a: number, b: number, c: number, d: number) => void;
|
|
65
66
|
export const parseDocPath: (a: number, b: number, c: number) => void;
|
|
66
67
|
export const quill_backendId: (a: number, b: number) => void;
|
package/package.json
CHANGED
package/runtime/runtime.d.ts
CHANGED
|
@@ -24,6 +24,7 @@ import type {
|
|
|
24
24
|
exportMarkdown,
|
|
25
25
|
rebase,
|
|
26
26
|
mapPos,
|
|
27
|
+
mapMarks,
|
|
27
28
|
parseDocPath,
|
|
28
29
|
formatDocPath
|
|
29
30
|
} from '../core/wasm.js';
|
|
@@ -42,6 +43,7 @@ export interface CoreSurface {
|
|
|
42
43
|
exportMarkdown: typeof exportMarkdown;
|
|
43
44
|
rebase: typeof rebase;
|
|
44
45
|
mapPos: typeof mapPos;
|
|
46
|
+
mapMarks: typeof mapMarks;
|
|
45
47
|
parseDocPath: typeof parseDocPath;
|
|
46
48
|
formatDocPath: typeof formatDocPath;
|
|
47
49
|
}
|
|
@@ -217,34 +219,32 @@ export declare function isImageIsland(
|
|
|
217
219
|
island: ContentIsland
|
|
218
220
|
): island is ContentIsland & { type: 'image'; props: ImageProps };
|
|
219
221
|
|
|
220
|
-
/** Narrow a {@link ContentMark} to the `link` arm (carries `url`). */
|
|
222
|
+
/** Narrow a {@link ContentMark} to the `link` arm (carries `attrs.url`). */
|
|
221
223
|
export declare function isLinkMark(
|
|
222
224
|
mark: ContentMark
|
|
223
|
-
): mark is ContentMark & { type: 'link'; url: string };
|
|
225
|
+
): mark is ContentMark & { type: 'link'; attrs: { url: string } };
|
|
224
226
|
|
|
225
|
-
/** Narrow a {@link ContentMark} to the `anchor` arm (carries `id`). */
|
|
227
|
+
/** Narrow a {@link ContentMark} to the `anchor` arm (carries `attrs.id`). */
|
|
226
228
|
export declare function isAnchorMark(
|
|
227
229
|
mark: ContentMark
|
|
228
|
-
): mark is ContentMark & { type: 'anchor'; id: string };
|
|
230
|
+
): mark is ContentMark & { type: 'anchor'; attrs: { id: string } };
|
|
229
231
|
|
|
230
|
-
/** Narrow a {@link ContentLine} to the `heading` arm (carries `level`). */
|
|
232
|
+
/** Narrow a {@link ContentLine} to the `heading` arm (carries `attrs.level`). */
|
|
231
233
|
export declare function isHeadingLine(
|
|
232
234
|
line: ContentLine
|
|
233
|
-
): line is ContentLine & { kind: 'heading'; level: number };
|
|
235
|
+
): line is ContentLine & { kind: 'heading'; attrs: { level: number } };
|
|
234
236
|
|
|
235
|
-
/** Narrow a {@link ContentLine} to the `code` arm (carries `lang`). */
|
|
237
|
+
/** Narrow a {@link ContentLine} to the `code` arm (carries `attrs.lang`). */
|
|
236
238
|
export declare function isCodeLine(
|
|
237
239
|
line: ContentLine
|
|
238
|
-
): line is ContentLine & { kind: 'code'; lang?: string };
|
|
240
|
+
): line is ContentLine & { kind: 'code'; attrs?: { lang?: string } };
|
|
239
241
|
|
|
240
242
|
/** Narrow a {@link ContentContainer} to the `list_item` arm (carries its shape). */
|
|
241
243
|
export declare function isListItemContainer(
|
|
242
244
|
container: ContentContainer
|
|
243
245
|
): container is ContentContainer & {
|
|
244
246
|
container: 'list_item';
|
|
245
|
-
ordered: boolean;
|
|
246
|
-
start: number;
|
|
247
|
-
ordinal: number;
|
|
247
|
+
attrs: { ordered: boolean; start: number; ordinal: number };
|
|
248
248
|
instance: number;
|
|
249
249
|
};
|
|
250
250
|
|
|
@@ -255,8 +255,9 @@ export declare function isListItemContainer(
|
|
|
255
255
|
// built-in names by hand re-couples to a closed set.
|
|
256
256
|
//
|
|
257
257
|
// They classify unknown TAGS, not unknown payloads on known tags: a future
|
|
258
|
-
// `kind: "footnote"` carrying
|
|
259
|
-
// predates it, with or without these.
|
|
258
|
+
// `kind: "footnote"` carrying an `attrs.ref` loses `ref` at any consumer that
|
|
259
|
+
// predates it, with or without these. The spelling needs no classifying: a
|
|
260
|
+
// payload rides `attrs` whether or not this build knows the name.
|
|
260
261
|
|
|
261
262
|
/** True when this build does not know `line.kind`: the open arm, carrying opaque `attrs`. */
|
|
262
263
|
export declare function isUnknownLine(
|
|
@@ -610,13 +611,24 @@ export declare class LiveSession {
|
|
|
610
611
|
* transform documented there: `x = clickPx.x / renderScale`,
|
|
611
612
|
* `y = pageHeightPt - clickPx.y / renderScale`. Unlike {@link regions},
|
|
612
613
|
* *every* placement answers, not just the first.
|
|
614
|
+
*
|
|
615
|
+
* `tolPt` is how far off the ink a click still counts, in the same points,
|
|
616
|
+
* and defaults to `0` — exact. It is pointer slack, so derive it from the
|
|
617
|
+
* scale the page was drawn at (`slackPx / renderScale`) rather than fixing a
|
|
618
|
+
* value in points, which shrinks under the cursor as the page zooms out. The
|
|
619
|
+
* nearest placement answers and containment is distance zero, so raising
|
|
620
|
+
* `tolPt` only ever fills a miss.
|
|
613
621
|
*/
|
|
614
|
-
fieldAt(page: number, x: number, y: number): string | undefined;
|
|
622
|
+
fieldAt(page: number, x: number, y: number, tolPt?: number): string | undefined;
|
|
615
623
|
/**
|
|
616
624
|
* Fine-grained click → content position (caret placement). Same PDF-point
|
|
617
|
-
* space as {@link fieldAt}; `undefined`
|
|
625
|
+
* space as {@link fieldAt}; `undefined` past `tolPt` from all content ink.
|
|
626
|
+
*
|
|
627
|
+
* `tolPt` buys the most here: the leading between two lines lies inside a
|
|
628
|
+
* paragraph and on no glyph, and under `tolPt` a point there takes the line
|
|
629
|
+
* it is nearer.
|
|
618
630
|
*/
|
|
619
|
-
positionAt(page: number, x: number, y: number): ContentHit | undefined;
|
|
631
|
+
positionAt(page: number, x: number, y: number, tolPt?: number): ContentHit | undefined;
|
|
620
632
|
/**
|
|
621
633
|
* Content position → caret rect: reverse of {@link positionAt}. `field` is a
|
|
622
634
|
* canonical `DocPath` address (`parseDocPath`-routable), as {@link regions} keys.
|
package/runtime/runtime.js
CHANGED
|
@@ -40,7 +40,7 @@ import initCore, { Quill, Document } from '../core/wasm.js';
|
|
|
40
40
|
// itself), a `node:fs` read under Node, whose `fetch` rejects `file:` URLs.
|
|
41
41
|
// Resolution-time, so `node:fs` never enters a browser graph.
|
|
42
42
|
import { toModuleSource } from '#quillmark-env';
|
|
43
|
-
import { importMarkdown, exportMarkdown, rebase, mapPos } from '../core/wasm.js';
|
|
43
|
+
import { importMarkdown, exportMarkdown, rebase, mapPos, mapMarks } from '../core/wasm.js';
|
|
44
44
|
import { parseDocPath, formatDocPath } from '../core/wasm.js';
|
|
45
45
|
|
|
46
46
|
// ── Initialization ──────────────────────────────────────────────────────────
|
|
@@ -90,6 +90,7 @@ const CORE_SURFACE = Object.freeze({
|
|
|
90
90
|
exportMarkdown,
|
|
91
91
|
rebase,
|
|
92
92
|
mapPos,
|
|
93
|
+
mapMarks,
|
|
93
94
|
parseDocPath,
|
|
94
95
|
formatDocPath
|
|
95
96
|
});
|
|
@@ -397,12 +398,12 @@ for (const name of /** @type {const} */ (['validate', 'resolve', 'conform'])) {
|
|
|
397
398
|
// leaving `props` / the mark payload / `level` opaque at every consumer. These
|
|
398
399
|
// are the checked narrowing path: on the true branch the payload's pinned shape
|
|
399
400
|
// is asserted. Only the payload-carrying arms get a guard: an island always
|
|
400
|
-
// carries `props`, a `link` mark
|
|
401
|
-
// `
|
|
402
|
-
//
|
|
403
|
-
// `
|
|
404
|
-
//
|
|
405
|
-
//
|
|
401
|
+
// carries `props`, and a `link`/`anchor` mark, a `heading`/`code` line and a
|
|
402
|
+
// `list_item` container each carry their payload in `attrs`; the payload-free
|
|
403
|
+
// arms (`strong`/`emph`/`underline`/`strike`/`code` marks, `para`/`island`/
|
|
404
|
+
// `rule` lines, `quote`) omit `attrs` and narrow to nothing. An unrecognized
|
|
405
|
+
// discriminant fails every guard and carries the same `attrs` a known one
|
|
406
|
+
// would.
|
|
406
407
|
|
|
407
408
|
/**
|
|
408
409
|
* @param {import('../core/wasm.js').ContentIsland} island
|
|
@@ -422,7 +423,7 @@ export function isImageIsland(island) {
|
|
|
422
423
|
|
|
423
424
|
/**
|
|
424
425
|
* @param {import('../core/wasm.js').ContentMark} mark
|
|
425
|
-
* @returns {mark is import('../core/wasm.js').ContentMark & { type: 'link'; url: string }}
|
|
426
|
+
* @returns {mark is import('../core/wasm.js').ContentMark & { type: 'link'; attrs: { url: string } }}
|
|
426
427
|
*/
|
|
427
428
|
export function isLinkMark(mark) {
|
|
428
429
|
return mark.type === 'link';
|
|
@@ -430,7 +431,7 @@ export function isLinkMark(mark) {
|
|
|
430
431
|
|
|
431
432
|
/**
|
|
432
433
|
* @param {import('../core/wasm.js').ContentMark} mark
|
|
433
|
-
* @returns {mark is import('../core/wasm.js').ContentMark & { type: 'anchor'; id: string }}
|
|
434
|
+
* @returns {mark is import('../core/wasm.js').ContentMark & { type: 'anchor'; attrs: { id: string } }}
|
|
434
435
|
*/
|
|
435
436
|
export function isAnchorMark(mark) {
|
|
436
437
|
return mark.type === 'anchor';
|
|
@@ -438,7 +439,7 @@ export function isAnchorMark(mark) {
|
|
|
438
439
|
|
|
439
440
|
/**
|
|
440
441
|
* @param {import('../core/wasm.js').ContentLine} line
|
|
441
|
-
* @returns {line is import('../core/wasm.js').ContentLine & { kind: 'heading'; level: number }}
|
|
442
|
+
* @returns {line is import('../core/wasm.js').ContentLine & { kind: 'heading'; attrs: { level: number } }}
|
|
442
443
|
*/
|
|
443
444
|
export function isHeadingLine(line) {
|
|
444
445
|
return line.kind === 'heading';
|
|
@@ -446,7 +447,7 @@ export function isHeadingLine(line) {
|
|
|
446
447
|
|
|
447
448
|
/**
|
|
448
449
|
* @param {import('../core/wasm.js').ContentLine} line
|
|
449
|
-
* @returns {line is import('../core/wasm.js').ContentLine & { kind: 'code'; lang?: string }}
|
|
450
|
+
* @returns {line is import('../core/wasm.js').ContentLine & { kind: 'code'; attrs?: { lang?: string } }}
|
|
450
451
|
*/
|
|
451
452
|
export function isCodeLine(line) {
|
|
452
453
|
return line.kind === 'code';
|
|
@@ -454,7 +455,7 @@ export function isCodeLine(line) {
|
|
|
454
455
|
|
|
455
456
|
/**
|
|
456
457
|
* @param {import('../core/wasm.js').ContentContainer} container
|
|
457
|
-
* @returns {container is import('../core/wasm.js').ContentContainer & { container: 'list_item'; ordered: boolean; start: number; ordinal: number; instance?: number }}
|
|
458
|
+
* @returns {container is import('../core/wasm.js').ContentContainer & { container: 'list_item'; attrs: { ordered: boolean; start: number; ordinal: number }; instance?: number }}
|
|
458
459
|
*/
|
|
459
460
|
export function isListItemContainer(container) {
|
|
460
461
|
return container.container === 'list_item';
|
|
@@ -516,12 +517,13 @@ export function isUnknownIsland(island) {
|
|
|
516
517
|
// form cannot tell a list ending beside another from one list of two items, so
|
|
517
518
|
// an omitted discriminator welds them and nothing reports it.
|
|
518
519
|
//
|
|
519
|
-
// WELD_KEYS is the rule `Container::same_weld` owns upstream: which
|
|
520
|
-
// adjacent runs must share for the markdown projection to read them
|
|
521
|
-
// therefore for the canonical form to have to spend a
|
|
522
|
-
// not among them, since CommonMark reads only a
|
|
523
|
-
//
|
|
524
|
-
//
|
|
520
|
+
// WELD_KEYS is the rule `Container::same_weld` owns upstream: which `attrs`
|
|
521
|
+
// entries two adjacent runs must share for the markdown projection to read them
|
|
522
|
+
// as one, and therefore for the canonical form to have to spend a
|
|
523
|
+
// discriminator. `start` is not among them, since CommonMark reads only a
|
|
524
|
+
// list's first number — a subset, which is why a built-in needs an entry rather
|
|
525
|
+
// than the unknown branch's whole-bag compare. A table rather than a switch, so
|
|
526
|
+
// `tests/known_names_drift.rs` can pin it against the Rust predicate.
|
|
525
527
|
|
|
526
528
|
const WELD_KEYS = { list_item: ['ordered'], quote: [] };
|
|
527
529
|
|
|
@@ -548,7 +550,7 @@ function weldsWith(a, b) {
|
|
|
548
550
|
// `hasOwn`, so a tag colliding with an `Object.prototype` member reaches the
|
|
549
551
|
// unknown branch rather than a function.
|
|
550
552
|
if (!Object.hasOwn(WELD_KEYS, a.container)) return sameJson(a.attrs, b.attrs);
|
|
551
|
-
return WELD_KEYS[a.container].every((k) => a[k] === b[k]);
|
|
553
|
+
return WELD_KEYS[a.container].every((k) => a.attrs?.[k] === b.attrs?.[k]);
|
|
552
554
|
}
|
|
553
555
|
|
|
554
556
|
/**
|
|
@@ -961,20 +963,22 @@ export class LiveSession {
|
|
|
961
963
|
* @param {number} page
|
|
962
964
|
* @param {number} x
|
|
963
965
|
* @param {number} y
|
|
966
|
+
* @param {number} [tolPt]
|
|
964
967
|
* @returns {string | undefined}
|
|
965
968
|
*/
|
|
966
|
-
fieldAt(page, x, y) {
|
|
967
|
-
return this.#inner.fieldAt(page, x, y);
|
|
969
|
+
fieldAt(page, x, y, tolPt) {
|
|
970
|
+
return this.#inner.fieldAt(page, x, y, tolPt);
|
|
968
971
|
}
|
|
969
972
|
|
|
970
973
|
/**
|
|
971
974
|
* @param {number} page
|
|
972
975
|
* @param {number} x
|
|
973
976
|
* @param {number} y
|
|
977
|
+
* @param {number} [tolPt]
|
|
974
978
|
* @returns {import('./runtime.d.ts').ContentHit | undefined}
|
|
975
979
|
*/
|
|
976
|
-
positionAt(page, x, y) {
|
|
977
|
-
return this.#inner.positionAt(page, x, y);
|
|
980
|
+
positionAt(page, x, y, tolPt) {
|
|
981
|
+
return this.#inner.positionAt(page, x, y, tolPt);
|
|
978
982
|
}
|
|
979
983
|
|
|
980
984
|
/**
|