@aicayzer/inkkit 0.3.1 → 0.3.2

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.
@@ -7916,7 +7916,7 @@ function postprocess(events) {
7916
7916
  * @returns {Array<Chunk>}
7917
7917
  * Chunks.
7918
7918
  */
7919
- var search$1 = /[\0\t\n\r]/g;
7919
+ var search$2 = /[\0\t\n\r]/g;
7920
7920
  /**
7921
7921
  * @returns {Preprocessor}
7922
7922
  * Preprocess a value.
@@ -7941,8 +7941,8 @@ function preprocess() {
7941
7941
  start = void 0;
7942
7942
  }
7943
7943
  while (startPosition < value.length) {
7944
- search$1.lastIndex = startPosition;
7945
- const match = search$1.exec(value);
7944
+ search$2.lastIndex = startPosition;
7945
+ const match = search$2.exec(value);
7946
7946
  const endPosition = match && match.index !== void 0 ? match.index : value.length;
7947
7947
  const code = value.charCodeAt(endPosition);
7948
7948
  if (!match) {
@@ -22734,7 +22734,7 @@ var SerializerState = class extends Stack {
22734
22734
  #closeMark;
22735
22735
  };
22736
22736
  //#endregion
22737
- //#region node_modules/.pnpm/prosemirror-view@1.42.6_patch_hash=808819d35255b79fc131ebc4873ab2fbcd47cd8f5bc05cd11e8caab02ecee548/node_modules/prosemirror-view/dist/index.js
22737
+ //#region node_modules/.pnpm/prosemirror-view@1.42.6_patch_hash=f2853b430244e6a0ce28d0ee793854c199c3f40279a807cb6690af21fae2d25e/node_modules/prosemirror-view/dist/index.js
22738
22738
  var domIndex = function(node) {
22739
22739
  for (var index = 0;; index++) {
22740
22740
  node = node.previousSibling;
@@ -23907,7 +23907,7 @@ var NodeViewDesc = class NodeViewDesc extends ViewDesc {
23907
23907
  this.children = replaceNodes(this.children, pos, pos + text.length, view, desc);
23908
23908
  }
23909
23909
  update(node, outerDeco, innerDeco, view) {
23910
- if (this.dirty == NODE_DIRTY || !node.sameMarkup(this.node)) return false;
23910
+ if (this.dirty == NODE_DIRTY || (this.parent ? !node.sameMarkup(this.node) : node.type != this.node.type)) return false;
23911
23911
  this.updateInner(node, outerDeco, innerDeco, view);
23912
23912
  return true;
23913
23913
  }
@@ -44149,14 +44149,16 @@ function samePresentation(a, b) {
44149
44149
  var FileResolution = class {
44150
44150
  runtime;
44151
44151
  changed;
44152
+ cache;
44152
44153
  state = { status: "idle" };
44153
44154
  reference;
44154
44155
  key = "";
44155
44156
  request;
44156
44157
  dead = false;
44157
- constructor(runtime, changed) {
44158
+ constructor(runtime, changed, cache) {
44158
44159
  this.runtime = runtime;
44159
44160
  this.changed = changed;
44161
+ this.cache = cache;
44160
44162
  }
44161
44163
  update(reference) {
44162
44164
  const key = JSON.stringify([
@@ -44167,11 +44169,29 @@ var FileResolution = class {
44167
44169
  ]);
44168
44170
  this.reference = Object.freeze({ ...reference });
44169
44171
  if (this.key === key && this.request?.isCurrent()) return;
44172
+ if (this.key !== key) this.cache?.release(this, this.key);
44170
44173
  this.key = key;
44174
+ this.cache?.retain(this, key);
44175
+ const cached = this.cache?.get(key);
44176
+ if (cached) {
44177
+ if (this.request?.pending) this.request.controller.abort();
44178
+ this.request = {
44179
+ controller: cached.controller,
44180
+ pending: false,
44181
+ isCurrent: cached.isCurrent
44182
+ };
44183
+ this.state = {
44184
+ status: "resolved",
44185
+ presentation: cached.presentation
44186
+ };
44187
+ this.changed();
44188
+ return;
44189
+ }
44171
44190
  this.retry();
44172
44191
  }
44173
44192
  /** Resolves again from a blank loading card. */
44174
44193
  retry() {
44194
+ this.cache?.delete(this.key);
44175
44195
  this.cancel();
44176
44196
  this.start(true);
44177
44197
  }
@@ -44180,17 +44200,19 @@ var FileResolution = class {
44180
44200
  * the host's change doesn't affect neither blanks nor moves.
44181
44201
  */
44182
44202
  refresh() {
44203
+ this.cache?.delete(this.key);
44183
44204
  if (this.dead || !this.runtime.active()) return;
44184
44205
  if (this.state.status === "idle") this.retry();
44185
44206
  else this.start(false);
44186
44207
  }
44187
44208
  start(blank) {
44188
- this.request?.controller.abort();
44209
+ if (!this.cache || this.request?.pending) this.request?.controller.abort();
44189
44210
  this.request = void 0;
44190
44211
  if (this.dead || !this.reference || !this.runtime.active()) return;
44191
44212
  const captured = this.runtime.capture();
44192
44213
  const request = {
44193
44214
  controller: new AbortController(),
44215
+ pending: true,
44194
44216
  isCurrent: captured.isCurrent
44195
44217
  };
44196
44218
  this.request = request;
@@ -44204,10 +44226,16 @@ var FileResolution = class {
44204
44226
  }).then((presentation) => {
44205
44227
  if (!this.current(request)) return;
44206
44228
  const before = this.state;
44229
+ request.pending = false;
44207
44230
  this.state = {
44208
44231
  status: "resolved",
44209
44232
  presentation
44210
44233
  };
44234
+ this.cache?.set(this.key, {
44235
+ presentation,
44236
+ isCurrent: request.isCurrent,
44237
+ controller: request.controller
44238
+ });
44211
44239
  if (before.status !== "resolved" || !samePresentation(before.presentation, presentation)) this.changed();
44212
44240
  }, (failure) => {
44213
44241
  if (!this.current(request)) return;
@@ -44228,9 +44256,63 @@ var FileResolution = class {
44228
44256
  this.request = void 0;
44229
44257
  this.state = { status: "idle" };
44230
44258
  }
44259
+ /** Hidden views keep an answer for this document, but never accept a late answer. */
44260
+ suspend() {
44261
+ if (this.request?.pending || this.state.status === "idle") this.cancel();
44262
+ }
44263
+ invalidate() {
44264
+ this.cache?.delete(this.key);
44265
+ this.cancel();
44266
+ }
44231
44267
  destroy() {
44232
44268
  this.dead = true;
44233
- this.cancel();
44269
+ this.cache?.release(this, this.key);
44270
+ if (!this.cache || this.request?.pending || this.state.status !== "resolved") this.cancel();
44271
+ }
44272
+ };
44273
+ /** A source commit may replace a node view without changing its authored reference. */
44274
+ var FilePresentationCache = class {
44275
+ entries = /* @__PURE__ */ new Map();
44276
+ retain(owner, key) {
44277
+ let entry = this.entries.get(key);
44278
+ if (!entry) this.entries.set(key, entry = {
44279
+ owners: /* @__PURE__ */ new Set(),
44280
+ controllers: /* @__PURE__ */ new Set()
44281
+ });
44282
+ entry.owners.add(owner);
44283
+ }
44284
+ release(owner, key) {
44285
+ const entry = this.entries.get(key);
44286
+ if (!entry) return;
44287
+ entry.owners.delete(owner);
44288
+ queueMicrotask(() => {
44289
+ if (this.entries.get(key) === entry && !entry.owners.size) {
44290
+ for (const controller of entry.controllers) controller.abort();
44291
+ this.entries.delete(key);
44292
+ }
44293
+ });
44294
+ }
44295
+ get(key) {
44296
+ const value = this.entries.get(key)?.value;
44297
+ if (value && !value.isCurrent()) {
44298
+ this.delete(key);
44299
+ return;
44300
+ }
44301
+ return value;
44302
+ }
44303
+ set(key, value) {
44304
+ const entry = this.entries.get(key);
44305
+ if (!entry) return;
44306
+ entry.value = value;
44307
+ entry.controllers.add(value.controller);
44308
+ }
44309
+ delete(key) {
44310
+ const entry = this.entries.get(key);
44311
+ if (entry) {
44312
+ for (const controller of entry.controllers) controller.abort();
44313
+ entry.controllers.clear();
44314
+ entry.value = void 0;
44315
+ }
44234
44316
  }
44235
44317
  };
44236
44318
  //#endregion
@@ -45319,6 +45401,81 @@ function caretAfterInsertion(tr, view) {
45319
45401
  return tr.setSelection($end.parent.inlineContent ? TextSelection.create(tr.doc, end) : caretAfter(tr.doc, end, view && calloutFolds(view, tr)));
45320
45402
  }
45321
45403
  //#endregion
45404
+ //#region src/parser.ts
45405
+ /**
45406
+ * Milkdown's parser state, except that it throws where Milkdown would drop content. Milkdown
45407
+ * catches the failure to build a node (`createNodeInParserFail`), logs it and carries on without
45408
+ * the node and everything inside it, so the document it returns can silently lack part of its
45409
+ * source.
45410
+ */
45411
+ var CheckedParserState = class extends ParserState {
45412
+ constructor(schema) {
45413
+ super(schema);
45414
+ const closeNode = this.closeNode;
45415
+ const addNode = this.addNode;
45416
+ const unbuildable = (type, attrs, content) => {
45417
+ try {
45418
+ return !type.createAndFill(attrs, content);
45419
+ } catch {
45420
+ return true;
45421
+ }
45422
+ };
45423
+ this.closeNode = () => {
45424
+ const element = this.top();
45425
+ if (!element || this.size() < 2 || unbuildable(element.type, element.attrs, element.content)) throw new Error(`Cannot build ${element?.type.name ?? "a node"}`);
45426
+ return closeNode();
45427
+ };
45428
+ this.addNode = (type, attrs, content) => {
45429
+ if (!this.top() || unbuildable(type, attrs, content)) throw new Error(`Cannot build ${type.name}`);
45430
+ return addNode(type, attrs, content);
45431
+ };
45432
+ }
45433
+ };
45434
+ /** The document, or undefined when Milkdown cannot build all of it. */
45435
+ function build(schema, tree) {
45436
+ try {
45437
+ return new CheckedParserState(schema).next(tree).toDoc();
45438
+ } catch {
45439
+ return;
45440
+ }
45441
+ }
45442
+ /**
45443
+ * Parses Markdown as Milkdown does, but never returns a document that lacks part of its source.
45444
+ * A top-level block that cannot be built is kept as its literal source, as unsupported syntax is,
45445
+ * so the rest of the document stays editable; when that is not enough, it throws `preservation`.
45446
+ */
45447
+ function parseMarkdown(schema, remark, markdown, parsedTree) {
45448
+ const tree = parsedTree ?? remark.runSync(remark.parse(markdown), markdown);
45449
+ const doc = build(schema, tree);
45450
+ if (doc) return doc;
45451
+ const source = markdown.replace(/^\uFEFF/, "");
45452
+ tree.children = tree.children.map((node) => {
45453
+ if (build(schema, {
45454
+ type: "root",
45455
+ children: [node]
45456
+ })) return node;
45457
+ const start = node.position?.start.offset;
45458
+ const end = node.position?.end.offset;
45459
+ if (start == null || end == null) return node;
45460
+ const value = source.slice(start, end);
45461
+ return {
45462
+ type: "inkkitLiteral",
45463
+ value,
45464
+ comments: literalCommentSpans(value),
45465
+ position: node.position
45466
+ };
45467
+ });
45468
+ const kept = build(schema, tree);
45469
+ if (kept) return kept;
45470
+ throw new InkKitError("preservation", "The Markdown cannot be shown without losing part of it");
45471
+ }
45472
+ /** Replaces Milkdown's parser with `parseMarkdown`, for every caller of `parserCtx`. */
45473
+ var checkedParser = (ctx) => async () => {
45474
+ await ctx.wait(ParserReady);
45475
+ const schema = ctx.get(schemaCtx);
45476
+ ctx.set(parserCtx, (markdown) => parseMarkdown(schema, ctx.get(remarkCtx), markdown));
45477
+ };
45478
+ //#endregion
45322
45479
  //#region src/gutter.ts
45323
45480
  var listMarker = /(?:[-*+]|\d{1,9}[.)])(?=[ \t])/g;
45324
45481
  /**
@@ -46974,6 +47131,18 @@ var nothingCarried = {
46974
47131
  var Preservation = class Preservation {
46975
47132
  ctx;
46976
47133
  source;
47134
+ static recent = /* @__PURE__ */ new WeakMap();
47135
+ processor;
47136
+ rawTree;
47137
+ sourceTree;
47138
+ static read(ctx, source) {
47139
+ const cached = this.recent.get(ctx);
47140
+ const previous = cached?.processor === ctx.get(remarkCtx) ? cached : void 0;
47141
+ if (previous?.source === source) return previous;
47142
+ const next = new Preservation(ctx, source, previous);
47143
+ this.recent.set(ctx, next);
47144
+ return next;
47145
+ }
46977
47146
  /** The document as loaded from `source`. */
46978
47147
  baseline;
46979
47148
  blocks = [];
@@ -46991,18 +47160,22 @@ var Preservation = class Preservation {
46991
47160
  nestedLiterals = /* @__PURE__ */ new Set();
46992
47161
  literalsRead = /* @__PURE__ */ new WeakSet();
46993
47162
  definitionSources;
46994
- constructor(ctx, source) {
47163
+ constructor(ctx, source, previous) {
46995
47164
  this.ctx = ctx;
46996
47165
  this.source = source;
46997
47166
  try {
46998
47167
  const parse = (text) => parseDoc(ctx, text);
46999
- this.baseline = parse(source);
47000
47168
  this.lineEnding = !source.includes("\n") ? source.includes("\r") ? "\r" : "\n" : source.includes("\r\n") && !source.replaceAll("\r\n", "").includes("\n") ? "\r\n" : "\n";
47001
- const processor = ctx.get(remarkCtx);
47169
+ const processor = this.processor = ctx.get(remarkCtx);
47002
47170
  const offset = source.startsWith("") ? 1 : 0;
47003
47171
  const body = source.slice(offset);
47004
- const rawTree = parseTree(ctx, source);
47005
- const tree = processor.runSync(structuredClone(rawTree), { value: body });
47172
+ const incremental = previous?.readEditedSource(source);
47173
+ const rawTree = incremental?.raw ?? parseTree(ctx, source);
47174
+ const tree = incremental?.tree ?? processor.runSync(structuredClone(rawTree), { value: body });
47175
+ this.rawTree = rawTree;
47176
+ this.sourceTree = tree;
47177
+ this.baseline = incremental?.doc ?? parseMarkdown(ctx.get(schemaCtx), processor, source, structuredClone(tree));
47178
+ const positions = new Map(rawTree.children.map((node) => [`${node.position?.start.offset}:${node.position?.end.offset}`, node]));
47006
47179
  for (const [index, node] of tree.children.entries()) {
47007
47180
  let start = node.position?.start.offset;
47008
47181
  const end = node.position?.end.offset;
@@ -47014,9 +47187,9 @@ var Preservation = class Preservation {
47014
47187
  const text = source.slice(start, sourceEnd);
47015
47188
  const own = this.baseline.childCount === tree.children.length;
47016
47189
  const parsed = own ? this.baseline.type.create(null, [this.baseline.child(index)]) : parse(text);
47017
- const blockText = parsed.childCount === 1 ? blockForm(ctx, parsed.firstChild) : form(write(ctx, parsed));
47190
+ const blockText = previous?.forms.get(parsed.firstChild) ?? (parsed.childCount === 1 ? blockForm(ctx, parsed.firstChild) : form(write(ctx, parsed)));
47018
47191
  if (own) this.forms.set(this.baseline.child(index), blockText);
47019
- const ast = positionalNode(rawTree, node);
47192
+ const ast = positions.get(`${node.position?.start.offset}:${node.position?.end.offset}`) ?? node;
47020
47193
  if (parsed.childCount === 1 && parsed.firstChild.type.name === "literal_markdown") literalForms.set(ast, blockText);
47021
47194
  this.blocks.push({
47022
47195
  start,
@@ -47053,6 +47226,66 @@ var Preservation = class Preservation {
47053
47226
  throw new PreservationError("Cannot read Markdown for preservation", { cause });
47054
47227
  }
47055
47228
  }
47229
+ readEditedSource(source) {
47230
+ if (this.source.startsWith("") || source.startsWith("") || /[\[\]<>%]/.test(this.source) || /[\[\]<>%]/.test(source) || this.blocks.length !== this.baseline.childCount || this.blocks.some((_, index) => !["paragraph", "heading"].includes(this.baseline.child(index).type.name))) return;
47231
+ let prefix = 0, suffix = 0;
47232
+ while (prefix < source.length && prefix < this.source.length && source[prefix] === this.source[prefix]) prefix++;
47233
+ while (suffix < source.length - prefix && suffix < this.source.length - prefix && source[source.length - suffix - 1] === this.source[this.source.length - suffix - 1]) suffix++;
47234
+ const first = Math.max(0, this.blocks.findIndex((block) => block.end >= prefix) - 1);
47235
+ let last = this.blocks.findIndex((block) => block.start > this.source.length - suffix);
47236
+ if (last < 0) last = this.blocks.length - 1;
47237
+ else last = Math.min(this.blocks.length - 1, last + 1);
47238
+ if (!this.blocks[first] || !this.blocks[last]) return;
47239
+ const start = this.blocks[first].start;
47240
+ const end = this.blocks[last].end;
47241
+ const delta = source.length - this.source.length;
47242
+ const nextEnd = end + delta;
47243
+ if (nextEnd < start || prefix < start || this.source.length - suffix > end) return;
47244
+ const part = new Preservation(this.ctx, source.slice(start, nextEnd));
47245
+ if (part.blocks.length !== part.baseline.childCount || part.blocks.some((_, index) => !["paragraph", "heading"].includes(part.baseline.child(index).type.name))) return;
47246
+ const lines = [0];
47247
+ for (const match of source.matchAll(/\r\n|\r|\n/g)) lines.push(match.index + match[0].length);
47248
+ const point = (offset) => {
47249
+ let low = 0, high = lines.length;
47250
+ while (low + 1 < high) {
47251
+ const middle = low + high >> 1;
47252
+ if (lines[middle] <= offset) low = middle;
47253
+ else high = middle;
47254
+ }
47255
+ return {
47256
+ offset,
47257
+ line: low + 1,
47258
+ column: offset - lines[low] + 1
47259
+ };
47260
+ };
47261
+ const shifted = (node, amount) => {
47262
+ const visit = (value) => {
47263
+ if (Array.isArray(value)) return value.map(visit);
47264
+ if (!value || typeof value !== "object") return value;
47265
+ if ("offset" in value && typeof value.offset === "number") return point(value.offset + amount);
47266
+ return Object.fromEntries(Object.entries(value).map(([key, child]) => [key, visit(child)]));
47267
+ };
47268
+ return visit(node);
47269
+ };
47270
+ const splice = (old, fresh) => ({
47271
+ type: "root",
47272
+ children: [
47273
+ ...old.children.slice(0, first),
47274
+ ...fresh.children.map((node) => shifted(node, start)),
47275
+ ...old.children.slice(last + 1).map((node) => shifted(node, delta))
47276
+ ]
47277
+ });
47278
+ const children = [];
47279
+ this.baseline.forEach((node, _offset, index) => {
47280
+ if (index === first) part.baseline.forEach((child) => children.push(child));
47281
+ if (index < first || index > last) children.push(node);
47282
+ });
47283
+ return {
47284
+ raw: splice(this.rawTree, part.rawTree),
47285
+ tree: splice(this.sourceTree, part.sourceTree),
47286
+ doc: this.baseline.copy(Fragment.fromArray(children))
47287
+ };
47288
+ }
47056
47289
  retainBlock(block, after, canonical, joined = [], reorder) {
47057
47290
  const offset = this.source.startsWith("") ? 1 : 0;
47058
47291
  const start = block.ast.position?.start.offset;
@@ -47189,7 +47422,7 @@ var Preservation = class Preservation {
47189
47422
  static plainInline(node) {
47190
47423
  let plain = true;
47191
47424
  node.descendants((child) => {
47192
- if (child.isInline && !child.isText && child.type.name !== "hardbreak") plain = false;
47425
+ if (child.isInline && !child.isText && !["hardbreak", "footnote_reference"].includes(child.type.name)) plain = false;
47193
47426
  return plain;
47194
47427
  });
47195
47428
  return plain;
@@ -47473,6 +47706,12 @@ var Preservation = class Preservation {
47473
47706
  const block = position == null ? void 0 : this.blocks[position];
47474
47707
  if (index === 0) return position === 0 && block ? this.source.slice(0, block.start) : this.source.startsWith("") ? "" : "";
47475
47708
  const previous = positions[index - 1];
47709
+ if (previous === this.blocks.length - 1 && position == null) {
47710
+ const ending = this.source.slice(this.blocks[previous].end);
47711
+ const lines = ending.replace(/\r\n?/g, "\n");
47712
+ if (/\n[ \t]*\n/.test(lines)) return ending + (lines.endsWith("\n") ? "" : this.lineEnding);
47713
+ return ending + this.lineEnding.repeat(lines.endsWith("\n") ? 1 : 2);
47714
+ }
47476
47715
  return previous != null && position === previous + 1 && block ? this.source.slice(this.blocks[previous].end, block.start) : this.lineEnding.repeat(2);
47477
47716
  }
47478
47717
  build(doc, positions, current, carried, from, to, canonical, tree) {
@@ -48505,81 +48744,6 @@ function normalizeTableColumnAlignment(element) {
48505
48744
  return normalizeTableAlignment(header ?? element);
48506
48745
  }
48507
48746
  //#endregion
48508
- //#region src/parser.ts
48509
- /**
48510
- * Milkdown's parser state, except that it throws where Milkdown would drop content. Milkdown
48511
- * catches the failure to build a node (`createNodeInParserFail`), logs it and carries on without
48512
- * the node and everything inside it, so the document it returns can silently lack part of its
48513
- * source.
48514
- */
48515
- var CheckedParserState = class extends ParserState {
48516
- constructor(schema) {
48517
- super(schema);
48518
- const closeNode = this.closeNode;
48519
- const addNode = this.addNode;
48520
- const unbuildable = (type, attrs, content) => {
48521
- try {
48522
- return !type.createAndFill(attrs, content);
48523
- } catch {
48524
- return true;
48525
- }
48526
- };
48527
- this.closeNode = () => {
48528
- const element = this.top();
48529
- if (!element || this.size() < 2 || unbuildable(element.type, element.attrs, element.content)) throw new Error(`Cannot build ${element?.type.name ?? "a node"}`);
48530
- return closeNode();
48531
- };
48532
- this.addNode = (type, attrs, content) => {
48533
- if (!this.top() || unbuildable(type, attrs, content)) throw new Error(`Cannot build ${type.name}`);
48534
- return addNode(type, attrs, content);
48535
- };
48536
- }
48537
- };
48538
- /** The document, or undefined when Milkdown cannot build all of it. */
48539
- function build(schema, tree) {
48540
- try {
48541
- return new CheckedParserState(schema).next(tree).toDoc();
48542
- } catch {
48543
- return;
48544
- }
48545
- }
48546
- /**
48547
- * Parses Markdown as Milkdown does, but never returns a document that lacks part of its source.
48548
- * A top-level block that cannot be built is kept as its literal source, as unsupported syntax is,
48549
- * so the rest of the document stays editable; when that is not enough, it throws `preservation`.
48550
- */
48551
- function parseMarkdown(schema, remark, markdown) {
48552
- const tree = remark.runSync(remark.parse(markdown), markdown);
48553
- const doc = build(schema, tree);
48554
- if (doc) return doc;
48555
- const source = markdown.replace(/^\uFEFF/, "");
48556
- tree.children = tree.children.map((node) => {
48557
- if (build(schema, {
48558
- type: "root",
48559
- children: [node]
48560
- })) return node;
48561
- const start = node.position?.start.offset;
48562
- const end = node.position?.end.offset;
48563
- if (start == null || end == null) return node;
48564
- const value = source.slice(start, end);
48565
- return {
48566
- type: "inkkitLiteral",
48567
- value,
48568
- comments: literalCommentSpans(value),
48569
- position: node.position
48570
- };
48571
- });
48572
- const kept = build(schema, tree);
48573
- if (kept) return kept;
48574
- throw new InkKitError("preservation", "The Markdown cannot be shown without losing part of it");
48575
- }
48576
- /** Replaces Milkdown's parser with `parseMarkdown`, for every caller of `parserCtx`. */
48577
- var checkedParser = (ctx) => async () => {
48578
- await ctx.wait(ParserReady);
48579
- const schema = ctx.get(schemaCtx);
48580
- ctx.set(parserCtx, (markdown) => parseMarkdown(schema, ctx.get(remarkCtx), markdown));
48581
- };
48582
- //#endregion
48583
48747
  //#region src/callouts.ts
48584
48748
  var kinds = /* @__PURE__ */ new Set([
48585
48749
  "NOTE",
@@ -51648,8 +51812,7 @@ function modeSelectionMap(ctx, source, doc) {
51648
51812
  if (at >= 0) append(value, Array.from({ length: value.length + 1 }, (_, index) => start + bom + at + index));
51649
51813
  }
51650
51814
  };
51651
- const processor = ctx.get(remarkCtx);
51652
- processor.runSync(processor.parse(source), { value: source }).children.forEach((node) => visit(node));
51815
+ Preservation.read(ctx, source).sourceTree.children.forEach((node) => visit(node));
51653
51816
  let cursor = 0;
51654
51817
  doc.descendants((node, position) => {
51655
51818
  if ([
@@ -51869,9 +52032,10 @@ var ImageView = class {
51869
52032
  stopResize;
51870
52033
  resolution;
51871
52034
  previewFailed = false;
52035
+ suspended = false;
51872
52036
  /** Present when the host sets `files`, which then shows every image. */
51873
52037
  runtime;
51874
- constructor(node, view, getPos, adapter, host, files, canMutate = () => true) {
52038
+ constructor(node, view, getPos, adapter, host, files, cache, canMutate = () => true) {
51875
52039
  this.node = node;
51876
52040
  this.view = view;
51877
52041
  this.getPos = getPos;
@@ -51900,7 +52064,7 @@ var ImageView = class {
51900
52064
  }, () => {
51901
52065
  this.previewFailed = false;
51902
52066
  this.render();
51903
- });
52067
+ }, cache);
51904
52068
  this.resolution.update(this.reference());
51905
52069
  }
51906
52070
  this.render();
@@ -51933,18 +52097,33 @@ var ImageView = class {
51933
52097
  if (!this.runtime) return;
51934
52098
  const refresh = refreshOf(event);
51935
52099
  if (refresh) {
51936
- if (!this.active() || !refreshes(refresh, this.reference().target)) return;
52100
+ if (!refreshes(refresh, this.reference().target)) return;
52101
+ if (!this.active()) {
52102
+ this.resolution?.invalidate();
52103
+ return;
52104
+ }
51937
52105
  if (this.previewFailed) this.resolution?.retry();
51938
52106
  else this.resolution?.refresh();
51939
52107
  return;
51940
52108
  }
51941
52109
  if (!this.active()) {
52110
+ if (this.suspended) return;
52111
+ this.suspended = true;
51942
52112
  this.stopResize?.();
51943
52113
  this.stopResize = void 0;
51944
- this.resolution?.cancel();
51945
- this.releaseMedia();
51946
- this.render();
51947
- } else this.resolution?.update(this.reference());
52114
+ this.resolution?.suspend();
52115
+ if (this.media || this.pdf) this.render();
52116
+ } else {
52117
+ const suspended = this.suspended;
52118
+ this.suspended = false;
52119
+ this.resolution?.update(this.reference());
52120
+ const state = this.resolution?.state;
52121
+ if (suspended && state?.status === "resolved" && [
52122
+ "audio",
52123
+ "video",
52124
+ "pdf"
52125
+ ].includes(state.presentation.kind)) this.render();
52126
+ }
51948
52127
  };
51949
52128
  cancelResize = () => {
51950
52129
  if (!this.stopResize) return;
@@ -52092,6 +52271,14 @@ var ImageView = class {
52092
52271
  return;
52093
52272
  }
52094
52273
  const presentation = state.presentation;
52274
+ if (!this.active() && [
52275
+ "audio",
52276
+ "video",
52277
+ "pdf"
52278
+ ].includes(presentation.kind)) {
52279
+ this.card(label);
52280
+ return;
52281
+ }
52095
52282
  if (presentation.kind === "missing") this.card(label, this.runtime.labels.fileMissing, true);
52096
52283
  else if (presentation.kind === "error") this.card(label, presentation.message || this.runtime.labels.fileError, true);
52097
52284
  else if (presentation.kind === "image") {
@@ -52222,7 +52409,8 @@ function openArrow() {
52222
52409
  return icon;
52223
52410
  }
52224
52411
  function imageView(adapter, host, files, canMutate = () => true) {
52225
- const view = (schema) => $view(schema.node, () => (node, view, getPos) => new ImageView(node, view, getPos, adapter, host, files, canMutate));
52412
+ const cache = new FilePresentationCache();
52413
+ const view = (schema) => $view(schema.node, () => (node, view, getPos) => new ImageView(node, view, getPos, adapter, host, files, cache, canMutate));
52226
52414
  return [view(imageSchema), view(imageBlockSchema)];
52227
52415
  }
52228
52416
  //#endregion
@@ -55420,18 +55608,92 @@ function covered(state) {
55420
55608
  const { from, to, empty, visible } = state.selection;
55421
55609
  if (empty || !visible) return [];
55422
55610
  const text = [];
55423
- state.doc.nodesBetween(from, to, (node, pos) => {
55611
+ let index = 0;
55612
+ state.doc.descendants((node, pos) => {
55424
55613
  if (!node.isTextblock) return true;
55425
55614
  const start = Math.max(from, pos + 1);
55426
55615
  const end = Math.min(to, pos + node.nodeSize - 1);
55427
55616
  if (end > start) text.push({
55428
55617
  from: start,
55429
- to: end
55618
+ to: end,
55619
+ start: pos + 1,
55620
+ end: pos + node.nodeSize - 1,
55621
+ index
55430
55622
  });
55623
+ index++;
55431
55624
  return false;
55432
55625
  });
55433
55626
  return text;
55434
55627
  }
55628
+ function blockContents(view) {
55629
+ return Array.from(view.dom.querySelectorAll("p,h1,h2,h3,h4,h5,h6,pre,.inkkit-comment-block")).filter((element) => {
55630
+ const excluded = element.closest(".ProseMirror-widget,[contenteditable=\"false\"]");
55631
+ return !excluded || excluded === view.dom;
55632
+ }).map((element) => element.tagName === "PRE" && !element.classList.contains("inkkit-literal-markdown") ? element.querySelector(":scope > code") ?? element : element);
55633
+ }
55634
+ function matchesBlock(node, content) {
55635
+ if (!content) return false;
55636
+ switch (node.type.name) {
55637
+ case "paragraph": return content.tagName === "P";
55638
+ case "heading": return content.tagName === `H${node.attrs.level}`;
55639
+ case "code_block": return content.tagName === "CODE" && content.parentElement?.tagName === "PRE";
55640
+ case "literal_markdown": return content.classList.contains("inkkit-literal-markdown");
55641
+ case "comment_block": return content.classList.contains("inkkit-comment-block");
55642
+ default: return false;
55643
+ }
55644
+ }
55645
+ function blockRange(view, span, content) {
55646
+ const range = view.dom.ownerDocument.createRange();
55647
+ range.selectNodeContents(content);
55648
+ const children = Array.from(content.childNodes);
55649
+ const decoration = (node) => node instanceof Element && (node.classList.contains("ProseMirror-widget") || node.classList.contains("ProseMirror-trailingBreak"));
55650
+ const first = children.find((node) => !decoration(node));
55651
+ const last = [...children].reverse().find((node) => !decoration(node));
55652
+ if (first) range.setStartBefore(first);
55653
+ if (last) range.setEndAfter(last);
55654
+ if (span.from !== span.start) {
55655
+ const start = view.domAtPos(span.from);
55656
+ range.setStart(start.node, start.offset);
55657
+ }
55658
+ if (span.to !== span.end) {
55659
+ const end = view.domAtPos(span.to);
55660
+ range.setEnd(end.node, end.offset);
55661
+ }
55662
+ return range;
55663
+ }
55664
+ function addBlockRanges(highlight, view, spans, contents) {
55665
+ let first;
55666
+ let last;
55667
+ const flush = () => {
55668
+ if (!first || !last) return;
55669
+ const range = view.dom.ownerDocument.createRange();
55670
+ range.setStart(first.content.firstChild, first.span.from - first.span.start);
55671
+ range.setEnd(last.content.firstChild, last.span.to - last.span.start);
55672
+ highlight.add(range);
55673
+ first = last = void 0;
55674
+ };
55675
+ for (const span of spans) {
55676
+ const content = contents[span.index];
55677
+ if (!(/^(P|H[1-6])$/.test(content.tagName) && content.childNodes.length === 1 && content.firstChild?.nodeType === Node.TEXT_NODE)) {
55678
+ flush();
55679
+ highlight.add(blockRange(view, span, content));
55680
+ continue;
55681
+ }
55682
+ if (last && last.content.nextSibling !== content) flush();
55683
+ first ??= {
55684
+ span,
55685
+ content
55686
+ };
55687
+ last = {
55688
+ span,
55689
+ content
55690
+ };
55691
+ }
55692
+ flush();
55693
+ }
55694
+ function setSelectionHostActive(view, active) {
55695
+ Painter.of(view.dom.ownerDocument).hostActive(view, active);
55696
+ }
55435
55697
  function domRange(view, span) {
55436
55698
  const start = view.domAtPos(span.from);
55437
55699
  const end = view.domAtPos(span.to);
@@ -55473,6 +55735,13 @@ var Painter = class Painter {
55473
55735
  custom = paintable();
55474
55736
  owner = null;
55475
55737
  windowFocused;
55738
+ hostActivation = /* @__PURE__ */ new WeakMap();
55739
+ painted;
55740
+ hostActive(view, active) {
55741
+ if (active === null) this.hostActivation.delete(view);
55742
+ else this.hostActivation.set(view, active);
55743
+ this.sync();
55744
+ }
55476
55745
  static of(doc) {
55477
55746
  let painter = Painter.all.get(doc);
55478
55747
  if (!painter) Painter.all.set(doc, painter = new Painter(doc));
@@ -55534,17 +55803,34 @@ var Painter = class Painter {
55534
55803
  this.win[method]("blur", this.onWindow);
55535
55804
  }
55536
55805
  sync() {
55537
- for (const [view, root] of this.views) root.classList.toggle(activeClass, this.windowFocused && focused(view));
55806
+ for (const [view, root] of this.views) root.classList.toggle(activeClass, (this.hostActivation.get(view) ?? this.windowFocused) && focused(view));
55538
55807
  if (!this.custom) return;
55539
55808
  const { owner } = this;
55809
+ if (owner && this.painted?.owner === owner && this.painted.doc === owner.state.doc && this.painted.selection.eq(owner.state.selection)) return;
55540
55810
  const spans = owner ? covered(owner.state) : [];
55541
55811
  if (!owner || !spans.length) {
55542
55812
  CSS.highlights.delete(name);
55813
+ this.painted = void 0;
55543
55814
  return;
55544
55815
  }
55545
55816
  const highlight = new Highlight();
55546
- for (const span of spans) highlight.add(domRange(owner, span));
55817
+ const contents = blockContents(owner);
55818
+ let blocks = 0;
55819
+ let mapped = true;
55820
+ owner.state.doc.descendants((node) => {
55821
+ if (!node.isTextblock) return true;
55822
+ if (!matchesBlock(node, contents[blocks])) mapped = false;
55823
+ blocks++;
55824
+ return false;
55825
+ });
55826
+ if (mapped && contents.length === blocks) addBlockRanges(highlight, owner, spans, contents);
55827
+ else for (const span of spans) highlight.add(domRange(owner, span));
55547
55828
  CSS.highlights.set(name, highlight);
55829
+ this.painted = {
55830
+ owner,
55831
+ doc: owner.state.doc,
55832
+ selection: owner.state.selection
55833
+ };
55548
55834
  }
55549
55835
  };
55550
55836
  var selectionPlugin = $prose(() => {
@@ -55866,7 +56152,7 @@ var searchKey = new PluginKey("search");
55866
56152
  Returns a plugin that stores a current search query and searched
55867
56153
  range, and highlights matches of the query.
55868
56154
  */
55869
- function search(options = {}) {
56155
+ function search$1(options = {}) {
55870
56156
  return new Plugin({
55871
56157
  key: searchKey,
55872
56158
  state: {
@@ -55915,6 +56201,56 @@ function setSearchState(tr, query, range = null) {
55915
56201
  }
55916
56202
  //#endregion
55917
56203
  //#region src/search.ts
56204
+ function search() {
56205
+ const original = search$1();
56206
+ return new Plugin({
56207
+ ...original.spec,
56208
+ state: {
56209
+ init: original.spec.state.init,
56210
+ apply(tr, current, oldState, state) {
56211
+ if (tr.getMeta(original) || current.range) return original.spec.state.apply.call(this, tr, current, oldState, state);
56212
+ if (!current.query.valid || !tr.docChanged && !tr.selectionSet) return current;
56213
+ let deco = tr.docChanged ? current.deco.map(tr.mapping, tr.doc) : current.deco;
56214
+ let from = tr.doc.content.size, to = 0;
56215
+ if (tr.docChanged) {
56216
+ tr.mapping.maps.forEach((map, index) => map.forEach((_a, _b, start, end) => {
56217
+ const rest = tr.mapping.slice(index + 1);
56218
+ from = Math.min(from, rest.map(start, -1));
56219
+ to = Math.max(to, rest.map(end, 1));
56220
+ }));
56221
+ if (from <= to) {
56222
+ const left = tr.doc.resolve(Math.max(0, from - 1));
56223
+ const right = tr.doc.resolve(Math.min(tr.doc.content.size, to + 1));
56224
+ from = left.depth ? left.before(1) : left.pos;
56225
+ to = right.depth ? right.after(1) : right.pos;
56226
+ deco = deco.remove(deco.find(from, to));
56227
+ const added = [];
56228
+ for (let position = from; position < to;) {
56229
+ const match = current.query.findNext(state, position, to);
56230
+ if (!match) break;
56231
+ added.push(Decoration.inline(match.from, match.to, { class: "ProseMirror-search-match" }));
56232
+ position = Math.max(match.to, position + 1);
56233
+ }
56234
+ deco = deco.add(state.doc, added);
56235
+ }
56236
+ }
56237
+ const previous = {
56238
+ from: tr.mapping.map(oldState.selection.from),
56239
+ to: tr.mapping.map(oldState.selection.to)
56240
+ };
56241
+ for (const [selection, active] of [[previous, false], [state.selection, true]]) {
56242
+ const matches = deco.find(selection.from, selection.to).filter((item) => item.from === selection.from && item.to === selection.to);
56243
+ const replacements = matches.map((item) => Decoration.inline(item.from, item.to, { class: active ? "ProseMirror-active-search-match" : "ProseMirror-search-match" }));
56244
+ deco = deco.remove(matches).add(state.doc, replacements);
56245
+ }
56246
+ return {
56247
+ ...current,
56248
+ deco
56249
+ };
56250
+ }
56251
+ }
56252
+ });
56253
+ }
55918
56254
  function escapedPattern(text) {
55919
56255
  return text.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
55920
56256
  }
@@ -56076,8 +56412,10 @@ function formattedLocations(doc) {
56076
56412
  return headings;
56077
56413
  }
56078
56414
  function sourceLocations(ctx, source) {
56079
- const processor = ctx.get(remarkCtx);
56080
- const tree = processor.runSync(processor.parse(source), { value: source });
56415
+ const cached = sourceOutlines.get(ctx);
56416
+ if (cached?.source === source) return cached.headings;
56417
+ const preservation = Preservation.read(ctx, source);
56418
+ const tree = preservation.sourceTree;
56081
56419
  const positions = [];
56082
56420
  const bom = source.startsWith("") ? 1 : 0;
56083
56421
  const visit = (node) => {
@@ -56088,13 +56426,19 @@ function sourceLocations(ctx, source) {
56088
56426
  node.children?.forEach(visit);
56089
56427
  };
56090
56428
  visit(tree);
56091
- const parsed = formattedLocations(ctx.get(parserCtx)(source));
56429
+ const parsed = formattedLocations(preservation.baseline);
56092
56430
  if (positions.length !== parsed.length || positions.some((item, index) => item.level !== parsed[index].node.attrs.level)) throw new InkKitError("preservation", "The current Markdown headings cannot be located safely");
56093
- return parsed.map((heading, index) => ({
56431
+ const headings = parsed.map((heading, index) => ({
56094
56432
  ...heading,
56095
56433
  position: positions[index].position
56096
56434
  }));
56435
+ sourceOutlines.set(ctx, {
56436
+ source,
56437
+ headings
56438
+ });
56439
+ return headings;
56097
56440
  }
56441
+ var sourceOutlines = /* @__PURE__ */ new WeakMap();
56098
56442
  function entry(heading, context) {
56099
56443
  return Object.freeze({
56100
56444
  id: `heading:${context.key}:${heading.position}`,
@@ -57191,7 +57535,7 @@ var InkKitEditor = class InkKitEditor {
57191
57535
  const anchor = view.state.doc.attrs[sourceAttribute];
57192
57536
  const from = anchor?.from ?? this.plain.selectionStart;
57193
57537
  const to = anchor?.to ?? this.plain.selectionEnd;
57194
- if (!this.plainComposing) this.plain.value = markdown;
57538
+ if (!this.plainComposing) this.setSourceValue(markdown);
57195
57539
  if (!this.plainComposing) {
57196
57540
  this.plain.setSelectionRange(Math.min(from, this.plain.value.length), Math.min(to, this.plain.value.length));
57197
57541
  this.revealLiteralSelection();
@@ -57440,6 +57784,12 @@ var InkKitEditor = class InkKitEditor {
57440
57784
  }
57441
57785
  this.publishCommandState();
57442
57786
  }
57787
+ /** Supplies native host activation for selection presentation. Null restores browser detection. */
57788
+ setHostActive(active) {
57789
+ this.assertAlive();
57790
+ if (active !== null) expectBoolean(active, "active");
57791
+ setSelectionHostActive(this.editor.ctx.get(editorViewCtx), active);
57792
+ }
57443
57793
  /** Replaces the input preferences. A field left out takes its default. Throws `composition`
57444
57794
  * during text composition. */
57445
57795
  setTextInputPreferences(preferences) {
@@ -57458,11 +57808,13 @@ var InkKitEditor = class InkKitEditor {
57458
57808
  }
57459
57809
  applyInputPolicy() {
57460
57810
  const view = this.editor.ctx.get(editorViewCtx);
57461
- const attributes = typeof view.props.attributes === "function" ? view.props.attributes(view.state) : view.props.attributes;
57811
+ const inputAttributes = { ...typeof view.props.attributes === "function" ? view.props.attributes(view.state) : view.props.attributes };
57812
+ delete inputAttributes["aria-readonly"];
57813
+ if (!this.writable) inputAttributes["aria-readonly"] = "true";
57462
57814
  view.setProps({
57463
57815
  editable: () => this.writable && !this.literalSurface,
57464
57816
  attributes: {
57465
- ...attributes,
57817
+ ...inputAttributes,
57466
57818
  role: "textbox",
57467
57819
  "aria-multiline": "true",
57468
57820
  "aria-label": this.options.labels?.formattedEditor ?? defaultLabels.formattedEditor
@@ -57627,7 +57979,7 @@ var InkKitEditor = class InkKitEditor {
57627
57979
  if (provenance) {
57628
57980
  preservation = this.sourcePreservations.get(provenance);
57629
57981
  if (!preservation) {
57630
- preservation = new Preservation(this.editor.ctx, provenance.text);
57982
+ preservation = Preservation.read(this.editor.ctx, provenance.text);
57631
57983
  this.sourcePreservations.set(provenance, preservation);
57632
57984
  }
57633
57985
  }
@@ -57669,7 +58021,7 @@ var InkKitEditor = class InkKitEditor {
57669
58021
  this.plainSearch = "";
57670
58022
  this.literalMatch = void 0;
57671
58023
  if (mode === "source") {
57672
- this.plain.value = text;
58024
+ this.setSourceValue(text);
57673
58025
  this.plain.setSelectionRange(Math.min(anchor, head), Math.max(anchor, head), anchor > head ? "backward" : "forward");
57674
58026
  } else view.dispatch(view.state.tr.setSelection(TextSelection.between(view.state.doc.resolve(Math.min(anchor, view.state.doc.content.size)), view.state.doc.resolve(Math.min(head, view.state.doc.content.size)))).setMeta("addToHistory", false));
57675
58027
  const suppressed = this.reportingSuppressed;
@@ -57754,10 +58106,27 @@ var InkKitEditor = class InkKitEditor {
57754
58106
  if (this.typedSteps.length > sourceStepLimit) this.typedSteps.shift();
57755
58107
  }
57756
58108
  showTypedSource(text, from, to) {
57757
- this.plain.value = text;
58109
+ this.setSourceValue(text);
57758
58110
  this.plain.setSelectionRange(Math.min(from, this.plain.value.length), Math.min(to, this.plain.value.length));
57759
58111
  this.revealLiteralSelection();
57760
58112
  }
58113
+ setSourceValue(text) {
58114
+ const plain = this.plain;
58115
+ if (text.length < 65536 || !plain.isConnected || this.plainComposing) {
58116
+ plain.value = text;
58117
+ return;
58118
+ }
58119
+ const focused = plain.ownerDocument.activeElement === plain;
58120
+ const { selectionStart, selectionEnd, selectionDirection, scrollTop, scrollLeft } = plain;
58121
+ const marker = plain.ownerDocument.createComment("source");
58122
+ plain.replaceWith(marker);
58123
+ plain.value = text;
58124
+ marker.replaceWith(plain);
58125
+ plain.setSelectionRange(selectionStart, selectionEnd, selectionDirection);
58126
+ if (focused) plain.focus({ preventScroll: true });
58127
+ plain.scrollTop = scrollTop;
58128
+ plain.scrollLeft = scrollLeft;
58129
+ }
57761
58130
  /**
57762
58131
  * Undoes or redoes typed source that the formatted document has not taken
57763
58132
  * in, on the text alone. Returns whether there was a step to take.
@@ -57829,7 +58198,7 @@ var InkKitEditor = class InkKitEditor {
57829
58198
  try {
57830
58199
  if (this.formatType === "txt") parsed = view.state.schema.topNodeType.create(null, view.state.schema.nodes.paragraph.create(null, text ? view.state.schema.text(text) : void 0));
57831
58200
  else {
57832
- const preservation = new Preservation(this.editor.ctx, text);
58201
+ const preservation = Preservation.read(this.editor.ctx, text);
57833
58202
  this.sourcePreservations.set(provenance, preservation);
57834
58203
  parsed = preservation.baseline;
57835
58204
  }
@@ -57993,7 +58362,7 @@ var InkKitEditor = class InkKitEditor {
57993
58362
  const valid = content.firstChild?.isInline ? Fragment.from(schema.nodes.paragraph.create(null, content)) : content;
57994
58363
  let markdown;
57995
58364
  try {
57996
- markdown = selectedSource ? selectedSource.markdown : all ? snapshot.text : completeDiagrams.size ? new Preservation(this.editor.ctx, snapshot.text).serialize(doc.type.create(null, selectionContent(doc, valid))) : selectionMarkdown(this.editor.ctx, doc, valid);
58365
+ markdown = selectedSource ? selectedSource.markdown : all ? snapshot.text : completeDiagrams.size ? Preservation.read(this.editor.ctx, snapshot.text).serialize(doc.type.create(null, selectionContent(doc, valid))) : selectionMarkdown(this.editor.ctx, doc, valid);
57997
58366
  } catch (error) {
57998
58367
  throw coded(error, "preservation");
57999
58368
  }
@@ -58308,7 +58677,7 @@ var InkKitEditor = class InkKitEditor {
58308
58677
  return true;
58309
58678
  }
58310
58679
  }));
58311
- }).use(labelsCtx).use(linkSchemesCtx).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(undoTypedRule).use(quoteBackspace).use(calloutEnter).use(literalEnter).use(literalReread).use(listItemBackspace).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-GlZZ_7st.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, {
58680
+ }).use(labelsCtx).use(linkSchemesCtx).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(undoTypedRule).use(quoteBackspace).use(calloutEnter).use(literalEnter).use(literalReread).use(listItemBackspace).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-LB7Mkd5W.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, {
58312
58681
  capture: () => instance.adapterCapture(),
58313
58682
  active: () => instance.ready && !instance.destroyed && !instance.literalSurface,
58314
58683
  labels: {
@@ -58358,7 +58727,7 @@ var InkKitEditor = class InkKitEditor {
58358
58727
  instance.plain.addEventListener("input", () => {
58359
58728
  if (!instance.ready || !instance.literalSurface) return;
58360
58729
  if (!instance.writable) {
58361
- instance.plain.value = instance.currentText();
58730
+ instance.setSourceValue(instance.currentText());
58362
58731
  return;
58363
58732
  }
58364
58733
  try {
@@ -58509,7 +58878,7 @@ var InkKitEditor = class InkKitEditor {
58509
58878
  const markdown = input.format === "txt" ? "" : input.text;
58510
58879
  let preservation;
58511
58880
  try {
58512
- preservation = new Preservation(this.editor.ctx, markdown);
58881
+ preservation = Preservation.read(this.editor.ctx, markdown);
58513
58882
  } catch (error) {
58514
58883
  throw new InkKitError("preservation", "The document was not loaded because its Markdown could not be shown without losing part of it", { cause: error });
58515
58884
  }
@@ -58534,7 +58903,7 @@ var InkKitEditor = class InkKitEditor {
58534
58903
  this.plainSearch = "";
58535
58904
  this.literalMatch = void 0;
58536
58905
  this.formatType = input.format;
58537
- this.plain.value = input.text;
58906
+ this.setSourceValue(input.text);
58538
58907
  this.plain.setSelectionRange(this.plain.value.length, this.plain.value.length);
58539
58908
  this.load(markdown, preservation);
58540
58909
  this.originalSource = input.text;
@@ -59115,7 +59484,7 @@ var InkKitEditor = class InkKitEditor {
59115
59484
  * Resolves wiki links and file embeds again, all of them or those whose `target` is named, after
59116
59485
  * something they point to changed. A file keeps its card until the new answer differs. Changes no
59117
59486
  * document state, so it works in a read-only editor and during composition. Source and TXT modes
59118
- * draw no references, and they resolve afresh when formatted mode returns.
59487
+ * draw no references; named file answers are invalidated and resolved when formatted mode returns.
59119
59488
  */
59120
59489
  refreshReferences(targets, expectedGeneration) {
59121
59490
  this.assertAlive();
@@ -59236,7 +59605,7 @@ var InkKitEditor = class InkKitEditor {
59236
59605
  const view = this.editor.ctx.get(editorViewCtx);
59237
59606
  const { doc, tr } = view.state;
59238
59607
  const blocks = this.imageBlocks(images);
59239
- if (doc.childCount === 1 && doc.firstChild.content.size === 0) tr.replaceWith(0, doc.content.size, blocks);
59608
+ if (doc.childCount === 1 && doc.firstChild.type.name === "paragraph" && doc.firstChild.content.size === 0 && this.currentText().trim() === "") tr.replaceWith(0, doc.content.size, blocks);
59240
59609
  else tr.insert(doc.content.size, blocks);
59241
59610
  view.dispatch(closeHistory(tr));
59242
59611
  view.dispatch(closeHistory(view.state.tr).setMeta("addToHistory", false));
@@ -59704,6 +60073,7 @@ var InkKitEditor = class InkKitEditor {
59704
60073
  "pasteAsPlainText",
59705
60074
  "commandState",
59706
60075
  "setEditable",
60076
+ "setHostActive",
59707
60077
  "setTextInputPreferences",
59708
60078
  "setEditingMode",
59709
60079
  "replaceSource",
@@ -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-Dx4gTiUo.js";
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-DTew7k7c.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.js CHANGED
@@ -1,2 +1,2 @@
1
- import { r as InkKitError, t as InkKitEditor } from "./chunks/core-Dx4gTiUo.js";
1
+ import { r as InkKitError, t as InkKitEditor } from "./chunks/core-DTew7k7c.js";
2
2
  export { InkKitEditor, InkKitError };
package/dist/editor.d.ts CHANGED
@@ -267,6 +267,8 @@ export declare class InkKitEditor {
267
267
  get editable(): boolean;
268
268
  /** Turns editing on or off for both surfaces. Throws `composition` during text composition. */
269
269
  setEditable(editable: boolean): void;
270
+ /** Supplies native host activation for selection presentation. Null restores browser detection. */
271
+ setHostActive(active: boolean | null): void;
270
272
  /** Replaces the input preferences. A field left out takes its default. Throws `composition`
271
273
  * during text composition. */
272
274
  setTextInputPreferences(preferences: TextInputPreferences): void;
@@ -299,6 +301,7 @@ export declare class InkKitEditor {
299
301
  private deferSource;
300
302
  private rememberTypedStep;
301
303
  private showTypedSource;
304
+ private setSourceValue;
302
305
  /**
303
306
  * Undoes or redoes typed source that the formatted document has not taken
304
307
  * in, on the text alone. Returns whether there was a step to take.
@@ -426,7 +429,7 @@ export declare class InkKitEditor {
426
429
  * Resolves wiki links and file embeds again, all of them or those whose `target` is named, after
427
430
  * something they point to changed. A file keeps its card until the new answer differs. Changes no
428
431
  * document state, so it works in a read-only editor and during composition. Source and TXT modes
429
- * draw no references, and they resolve afresh when formatted mode returns.
432
+ * draw no references; named file answers are invalidated and resolved when formatted mode returns.
430
433
  */
431
434
  refreshReferences(targets?: readonly string[], expectedGeneration?: number): void;
432
435
  /** Replaces every binding. Keys are in ProseMirror's notation. A key given to two shortcuts goes
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { n as registerMermaid, r as InkKitError, t as InkKitEditor } from "./chunks/core-Dx4gTiUo.js";
1
+ import { n as registerMermaid, r as InkKitError, t as InkKitEditor } from "./chunks/core-DTew7k7c.js";
2
2
  //#region src/index.ts
3
3
  registerMermaid(async () => (await import("mermaid")).default);
4
4
  //#endregion
package/dist/style.css CHANGED
@@ -1,4 +1,5 @@
1
1
  .inkkit-root {
2
+ --_inkkit-font-size: var(--inkkit-font-size, 15px);
2
3
  box-sizing: border-box;
3
4
  color-scheme: var(--inkkit-color-scheme, light dark);
4
5
  color: var(--inkkit-text-color, CanvasText);
@@ -9,7 +10,7 @@
9
10
  system-ui,
10
11
  sans-serif
11
12
  );
12
- font-size: var(--inkkit-font-size, 15px);
13
+ font-size: var(--_inkkit-font-size);
13
14
  line-height: var(--inkkit-line-height, normal);
14
15
  -webkit-font-smoothing: antialiased;
15
16
  -webkit-text-size-adjust: none;
@@ -60,7 +61,7 @@
60
61
  var(--inkkit-padding-bottom, 48px);
61
62
  background: transparent;
62
63
  color: var(--_inkkit-text);
63
- font: calc(var(--inkkit-font-size, 15px) * 1)/var(--inkkit-line-height, 1.5)
64
+ font: calc(var(--_inkkit-font-size) * 1)/var(--inkkit-line-height, 1.5)
64
65
  var(--_inkkit-mono);
65
66
  }
66
67
 
@@ -75,7 +76,7 @@
75
76
  .inkkit-root .inkkit-table-block {
76
77
  position: relative;
77
78
  margin: 0 0
78
- var(--inkkit-paragraph-spacing, calc(var(--inkkit-font-size, 15px) * 0.667));
79
+ var(--inkkit-paragraph-spacing, calc(var(--_inkkit-font-size) * 0.667));
79
80
  }
80
81
  .inkkit-root .inkkit-table-scroll {
81
82
  overflow-x: auto;
@@ -91,9 +92,9 @@
91
92
  .inkkit-root .ProseMirror th {
92
93
  position: relative;
93
94
  box-sizing: border-box;
94
- min-width: calc(var(--inkkit-font-size, 15px) * 4);
95
- padding: calc(var(--inkkit-font-size, 15px) * 0.4)
96
- calc(var(--inkkit-font-size, 15px) * 0.6);
95
+ min-width: calc(var(--_inkkit-font-size) * 4);
96
+ padding: calc(var(--_inkkit-font-size) * 0.4)
97
+ calc(var(--_inkkit-font-size) * 0.6);
97
98
  border: 0 solid var(--_inkkit-rule);
98
99
  border-width: 0 1px 1px 0;
99
100
  vertical-align: top;
@@ -263,7 +264,7 @@
263
264
  .inkkit-root .ProseMirror .inkkit-image-block {
264
265
  display: block;
265
266
  margin: 0 0
266
- var(--inkkit-paragraph-spacing, calc(var(--inkkit-font-size, 15px) * 0.667));
267
+ var(--inkkit-paragraph-spacing, calc(var(--_inkkit-font-size) * 0.667));
267
268
  line-height: 0;
268
269
  }
269
270
  .inkkit-root .ProseMirror .inkkit-image-block > .inkkit-image {
@@ -526,7 +527,7 @@
526
527
 
527
528
  .inkkit-root .ProseMirror p {
528
529
  margin: 0 0
529
- var(--inkkit-paragraph-spacing, calc(var(--inkkit-font-size, 15px) * 0.667));
530
+ var(--inkkit-paragraph-spacing, calc(var(--_inkkit-font-size) * 0.667));
530
531
  }
531
532
 
532
533
  .inkkit-root .ProseMirror h1,
@@ -534,32 +535,32 @@
534
535
  .inkkit-root .ProseMirror h3 {
535
536
  line-height: 1.25;
536
537
  letter-spacing: -0.01em;
537
- margin: calc(var(--inkkit-font-size, 15px) * 1.867) 0
538
- calc(var(--inkkit-font-size, 15px) * 0.533);
538
+ margin: calc(var(--_inkkit-font-size) * 1.867) 0
539
+ calc(var(--_inkkit-font-size) * 0.533);
539
540
  }
540
541
 
541
542
  .inkkit-root .ProseMirror h1 {
542
- font-size: calc(var(--inkkit-font-size, 15px) * 1.733);
543
+ font-size: calc(var(--_inkkit-font-size) * 1.733);
543
544
  font-weight: 700;
544
545
  }
545
546
 
546
547
  .inkkit-root .ProseMirror h2 {
547
- font-size: calc(var(--inkkit-font-size, 15px) * 1.4);
548
+ font-size: calc(var(--_inkkit-font-size) * 1.4);
548
549
  font-weight: 700;
549
550
  }
550
551
 
551
552
  .inkkit-root .ProseMirror h3 {
552
- font-size: calc(var(--inkkit-font-size, 15px) * 1.133);
553
+ font-size: calc(var(--_inkkit-font-size) * 1.133);
553
554
  font-weight: 600;
554
555
  }
555
556
 
556
557
  .inkkit-root .ProseMirror h4,
557
558
  .inkkit-root .ProseMirror h5,
558
559
  .inkkit-root .ProseMirror h6 {
559
- font-size: calc(var(--inkkit-font-size, 15px) * 1);
560
+ font-size: calc(var(--_inkkit-font-size) * 1);
560
561
  font-weight: 600;
561
- margin: calc(var(--inkkit-font-size, 15px) * 1.333) 0
562
- calc(var(--inkkit-font-size, 15px) * 0.4);
562
+ margin: calc(var(--_inkkit-font-size) * 1.333) 0
563
+ calc(var(--_inkkit-font-size) * 0.4);
563
564
  }
564
565
 
565
566
  .inkkit-root .ProseMirror strong {
@@ -600,25 +601,25 @@
600
601
  font-size: 0.88em;
601
602
  background: var(--_inkkit-code-bg);
602
603
  border-radius: 5px;
603
- padding: calc(var(--inkkit-font-size, 15px) * 0.067)
604
- calc(var(--inkkit-font-size, 15px) * 0.333);
604
+ padding: calc(var(--_inkkit-font-size) * 0.067)
605
+ calc(var(--_inkkit-font-size) * 0.333);
605
606
  }
606
607
 
607
608
  .inkkit-root .ProseMirror pre {
608
609
  position: relative;
609
610
  font-family: var(--_inkkit-mono);
610
- font-size: calc(var(--inkkit-font-size, 15px) * 0.867);
611
+ font-size: calc(var(--_inkkit-font-size) * 0.867);
611
612
  line-height: 1.5;
612
613
  background: var(--_inkkit-code-bg);
613
614
  border-radius: 8px;
614
- padding: calc(var(--inkkit-font-size, 15px) * 0.8)
615
- calc(var(--inkkit-font-size, 15px) * 0.933);
616
- margin: 0 0 calc(var(--inkkit-font-size, 15px) * 0.8);
615
+ padding: calc(var(--_inkkit-font-size) * 0.8)
616
+ calc(var(--_inkkit-font-size) * 0.933);
617
+ margin: 0 0 calc(var(--_inkkit-font-size) * 0.8);
617
618
  overflow-x: auto;
618
619
  }
619
620
 
620
621
  .inkkit-root .ProseMirror pre[data-language] {
621
- padding-top: max(calc(var(--inkkit-font-size, 15px) * 2), 30px);
622
+ padding-top: max(calc(var(--_inkkit-font-size) * 2), 30px);
622
623
  }
623
624
 
624
625
  .inkkit-root .ProseMirror pre .inkkit-copy {
@@ -661,8 +662,8 @@
661
662
  }
662
663
 
663
664
  .inkkit-root .ProseMirror blockquote {
664
- margin: 0 0 calc(var(--inkkit-font-size, 15px) * 0.8);
665
- padding: 2px 0 2px calc(var(--inkkit-font-size, 15px) * 0.8);
665
+ margin: 0 0 calc(var(--_inkkit-font-size) * 0.8);
666
+ padding: 2px 0 2px calc(var(--_inkkit-font-size) * 0.8);
666
667
  border-left: 2px solid var(--_inkkit-accent);
667
668
  }
668
669
 
@@ -677,18 +678,18 @@
677
678
  .inkkit-root .ProseMirror hr {
678
679
  border: 0;
679
680
  border-top: 1px solid var(--_inkkit-rule);
680
- margin: calc(var(--inkkit-font-size, 15px) * 1.333) 0;
681
+ margin: calc(var(--_inkkit-font-size) * 1.333) 0;
681
682
  }
682
683
 
683
684
  .inkkit-root .ProseMirror ul,
684
685
  .inkkit-root .ProseMirror ol {
685
686
  margin: 0 0
686
- var(--inkkit-paragraph-spacing, calc(var(--inkkit-font-size, 15px) * 0.667));
687
- padding-left: calc(var(--inkkit-font-size, 15px) * 1.733);
687
+ var(--inkkit-paragraph-spacing, calc(var(--_inkkit-font-size) * 0.667));
688
+ padding-left: calc(var(--_inkkit-font-size) * 1.733);
688
689
  }
689
690
 
690
691
  .inkkit-root .ProseMirror li {
691
- margin: 0 0 calc(var(--inkkit-font-size, 15px) * 0.267);
692
+ margin: 0 0 calc(var(--_inkkit-font-size) * 0.267);
692
693
  }
693
694
 
694
695
  .inkkit-root .ProseMirror li > p {
@@ -697,7 +698,7 @@
697
698
 
698
699
  .inkkit-root .ProseMirror li ul,
699
700
  .inkkit-root .ProseMirror li ol {
700
- margin-top: calc(var(--inkkit-font-size, 15px) * 0.267);
701
+ margin-top: calc(var(--_inkkit-font-size) * 0.267);
701
702
  margin-bottom: 0;
702
703
  }
703
704
 
@@ -712,7 +713,7 @@
712
713
  /* The box is centered on the first line: 1lh is the line height the item's
713
714
  text uses, including when it is normal, and --inkkit-checkbox-offset
714
715
  moves the box down for a font whose lines look off-center. */
715
- --_inkkit-task-size: calc(var(--inkkit-font-size, 15px) * 0.933);
716
+ --_inkkit-task-size: calc(var(--_inkkit-font-size) * 0.933);
716
717
  --_inkkit-task-top: calc(
717
718
  (1lh - var(--_inkkit-task-size)) / 2 + var(--inkkit-checkbox-offset, 0px)
718
719
  );
@@ -721,7 +722,7 @@
721
722
  .inkkit-root .ProseMirror li[data-item-type='task']::before {
722
723
  content: '';
723
724
  position: absolute;
724
- left: calc(var(--inkkit-font-size, 15px) * -1.667);
725
+ left: calc(var(--_inkkit-font-size) * -1.667);
725
726
  top: var(--_inkkit-task-top);
726
727
  width: var(--_inkkit-task-size);
727
728
  height: var(--_inkkit-task-size);
@@ -747,10 +748,10 @@
747
748
  li[data-item-type='task'][data-checked='true']::after {
748
749
  content: '';
749
750
  position: absolute;
750
- left: calc(var(--inkkit-font-size, 15px) * -1.333);
751
- top: calc(var(--_inkkit-task-top) + var(--inkkit-font-size, 15px) * 0.133);
752
- width: calc(var(--inkkit-font-size, 15px) * 0.2);
753
- height: calc(var(--inkkit-font-size, 15px) * 0.467);
751
+ left: calc(var(--_inkkit-font-size) * -1.333);
752
+ top: calc(var(--_inkkit-task-top) + var(--_inkkit-font-size) * 0.133);
753
+ width: calc(var(--_inkkit-font-size) * 0.2);
754
+ height: calc(var(--_inkkit-font-size) * 0.467);
754
755
  border: solid Canvas;
755
756
  border-width: 0 1.5px 1.5px 0;
756
757
  transform: rotate(45deg);
@@ -853,28 +854,28 @@
853
854
  .inkkit-root .ProseMirror .inkkit-literal-markdown {
854
855
  white-space: pre-wrap;
855
856
  font-family: var(--_inkkit-mono);
856
- font-size: calc(var(--inkkit-font-size, 15px) * 0.9);
857
+ font-size: calc(var(--_inkkit-font-size) * 0.9);
857
858
  }
858
859
 
859
860
  .inkkit-root .inkkit-footnote-reference {
860
861
  cursor: pointer;
861
862
  color: var(--_inkkit-accent, currentColor);
862
- font-size: calc(var(--inkkit-font-size, 15px) * 0.75);
863
+ font-size: calc(var(--_inkkit-font-size) * 0.75);
863
864
  }
864
865
 
865
866
  .inkkit-root .inkkit-footnote-definition {
866
867
  border-inline-start: 2px solid var(--_inkkit-muted, currentColor);
867
- padding-inline-start: calc(var(--inkkit-font-size, 15px) * 1);
868
+ padding-inline-start: calc(var(--_inkkit-font-size) * 1);
868
869
  }
869
870
 
870
871
  .inkkit-root .inkkit-footnote-definition::before {
871
872
  content: '[' attr(data-inkkit-label) ']';
872
- font-size: calc(var(--inkkit-font-size, 15px) * 0.8);
873
+ font-size: calc(var(--_inkkit-font-size) * 0.8);
873
874
  }
874
875
 
875
876
  .inkkit-root .inkkit-reference-definition {
876
877
  font-family: var(--_inkkit-mono);
877
- font-size: calc(var(--inkkit-font-size, 15px) * 0.8);
878
+ font-size: calc(var(--_inkkit-font-size) * 0.8);
878
879
  opacity: 0.7;
879
880
  }
880
881
 
@@ -886,8 +887,8 @@
886
887
  .inkkit-root .ProseMirror .inkkit-callout {
887
888
  --_inkkit-callout-color: var(--_inkkit-accent);
888
889
  border-inline-start: 3px solid var(--_inkkit-callout-color);
889
- padding: calc(var(--inkkit-font-size, 15px) * 0.65)
890
- calc(var(--inkkit-font-size, 15px) * 1);
890
+ padding: calc(var(--_inkkit-font-size) * 0.65)
891
+ calc(var(--_inkkit-font-size) * 1);
891
892
  background: color-mix(in srgb, var(--_inkkit-callout-color) 7%, transparent);
892
893
  }
893
894
 
@@ -907,14 +908,14 @@
907
908
  .inkkit-root .inkkit-callout-header {
908
909
  display: flex;
909
910
  align-items: baseline;
910
- gap: calc(var(--inkkit-font-size, 15px) * 0.75);
911
+ gap: calc(var(--_inkkit-font-size) * 0.75);
911
912
  }
912
913
 
913
914
  .inkkit-root [data-inkkit-callout-toggle] {
914
915
  color: var(--_inkkit-muted);
915
916
  background: transparent;
916
917
  border: 0;
917
- padding: calc(var(--inkkit-font-size, 15px) * 0.25);
918
+ padding: calc(var(--_inkkit-font-size) * 0.25);
918
919
  cursor: pointer;
919
920
  }
920
921
 
@@ -936,7 +937,7 @@
936
937
 
937
938
  .inkkit-root [data-inkkit-comments-visible='true'] .inkkit-comment-block {
938
939
  display: block;
939
- padding: calc(var(--inkkit-font-size, 15px) * 0.5);
940
+ padding: calc(var(--_inkkit-font-size) * 0.5);
940
941
  }
941
942
 
942
943
  @media print {
@@ -980,7 +981,7 @@
980
981
  }
981
982
  .inkkit-root .inkkit-mermaid-preview[data-state='error'] {
982
983
  color: var(--inkkit-diagram-error-color, #9b2424);
983
- font-size: calc(var(--inkkit-font-size, 15px) * 0.9);
984
+ font-size: calc(var(--_inkkit-font-size) * 0.9);
984
985
  }
985
986
 
986
987
  /* One ring for every control InkKit draws; the editing surfaces can be set apart. */
@@ -1028,8 +1029,8 @@
1028
1029
  background: var(--inkkit-menu-background, light-dark(#fff, #252529));
1029
1030
  color: var(--inkkit-menu-text, CanvasText);
1030
1031
  box-shadow: var(--inkkit-menu-shadow, 0 4px 18px #0003);
1031
- font: calc(var(--inkkit-font-size, 15px) * 14 / 15) /
1032
- calc(var(--inkkit-font-size, 15px) * 1.6)
1032
+ font: calc(var(--_inkkit-font-size) * 14 / 15) /
1033
+ calc(var(--_inkkit-font-size) * 1.6)
1033
1034
  var(--inkkit-font-family, system-ui, sans-serif);
1034
1035
  }
1035
1036
  .inkkit-root .inkkit-suggestions [role='option'] {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aicayzer/inkkit",
3
- "version": "0.3.1",
3
+ "version": "0.3.2",
4
4
  "description": "A preserving Markdown editor for offline web views and the web",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -38,7 +38,7 @@
38
38
  },
39
39
  "packageManager": "pnpm@11.0.9",
40
40
  "engines": {
41
- "node": ">=22.14"
41
+ "node": ">=26"
42
42
  },
43
43
  "scripts": {
44
44
  "build": "node scripts/clean-build.mjs && tsc -p tsconfig.build.json && vite build --config vite.package.config.ts && node scripts/finish-build.mjs",