@aicayzer/inkkit 0.7.1 → 0.7.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.
@@ -22786,7 +22786,7 @@ function nodeSize(node) {
22786
22786
  function isElt(node) {
22787
22787
  return node.nodeType == 1;
22788
22788
  }
22789
- function isText$1(node) {
22789
+ function isText$2(node) {
22790
22790
  return node.nodeType == 3;
22791
22791
  }
22792
22792
  function contains(parent, child) {
@@ -22794,7 +22794,7 @@ function contains(parent, child) {
22794
22794
  }
22795
22795
  function textNodeBefore$1(node, offset) {
22796
22796
  for (;;) {
22797
- if (isText$1(node) && offset) return node;
22797
+ if (isText$2(node) && offset) return node;
22798
22798
  if (isElt(node) && offset > 0) {
22799
22799
  if (node.contentEditable == "false") return null;
22800
22800
  node = node.childNodes[offset - 1];
@@ -22807,7 +22807,7 @@ function textNodeBefore$1(node, offset) {
22807
22807
  }
22808
22808
  function textNodeAfter$1(node, offset) {
22809
22809
  for (;;) {
22810
- if (isText$1(node) && offset < node.nodeValue.length) return node;
22810
+ if (isText$2(node) && offset < node.nodeValue.length) return node;
22811
22811
  if (isElt(node) && offset < node.childNodes.length) {
22812
22812
  if (node.contentEditable == "false") return null;
22813
22813
  node = node.childNodes[offset];
@@ -23014,7 +23014,7 @@ function findOffsetInNode(node, coords) {
23014
23014
  for (let child = node.firstChild, childIndex = 0; child; child = child.nextSibling, childIndex++) {
23015
23015
  let rects;
23016
23016
  if (isElt(child)) rects = child.getClientRects();
23017
- else if (isText$1(child)) rects = textRange$1(child).getClientRects();
23017
+ else if (isText$2(child)) rects = textRange$1(child).getClientRects();
23018
23018
  else continue;
23019
23019
  for (let i = 0; i < rects.length; i++) {
23020
23020
  let rect = rects[i];
@@ -23025,7 +23025,7 @@ function findOffsetInNode(node, coords) {
23025
23025
  if (dx < dxClosest) {
23026
23026
  closest = child;
23027
23027
  dxClosest = dx;
23028
- coordsClosest = dx && isText$1(closest) ? {
23028
+ coordsClosest = dx && isText$2(closest) ? {
23029
23029
  left: rect.right < coords.left ? rect.right : rect.left,
23030
23030
  top: coords.top
23031
23031
  } : coords;
@@ -23047,7 +23047,7 @@ function findOffsetInNode(node, coords) {
23047
23047
  coordsClosest = coordsBelow;
23048
23048
  dxClosest = 0;
23049
23049
  }
23050
- if (closest && isText$1(closest)) return findOffsetInText(closest, coordsClosest);
23050
+ if (closest && isText$2(closest)) return findOffsetInText(closest, coordsClosest);
23051
23051
  if (!closest || dxClosest) return {
23052
23052
  node,
23053
23053
  offset
@@ -23176,7 +23176,7 @@ var BIDI = /[\u0590-\u05f4\u0600-\u06ff\u0700-\u08ac]/;
23176
23176
  function coordsAtPos(view, pos, side) {
23177
23177
  let { node, offset, atom } = view.docView.domFromPos(pos, side < 0 ? -1 : 1);
23178
23178
  let supportEmptyRange = webkit || gecko;
23179
- if (isText$1(node)) {
23179
+ if (isText$2(node)) {
23180
23180
  if (supportEmptyRange && (BIDI.test(node.nodeValue) || (side < 0 ? !offset : offset == node.nodeValue.length))) {
23181
23181
  let rect = singleRect(textRange$1(node, offset, offset), side);
23182
23182
  if (gecko && offset && /\s/.test(node.nodeValue[offset - 1]) && offset < node.nodeValue.length) {
@@ -23213,16 +23213,16 @@ function coordsAtPos(view, pos, side) {
23213
23213
  }
23214
23214
  if (atom == null && offset && (side < 0 || offset == nodeSize(node))) {
23215
23215
  let before = node.childNodes[offset - 1];
23216
- let target = isText$1(before) ? textRange$1(before, nodeSize(before) - (supportEmptyRange ? 0 : 1)) : isElt(before) && (before.nodeName != "BR" || !before.nextSibling) ? before : null;
23216
+ let target = isText$2(before) ? textRange$1(before, nodeSize(before) - (supportEmptyRange ? 0 : 1)) : isElt(before) && (before.nodeName != "BR" || !before.nextSibling) ? before : null;
23217
23217
  if (target) return flattenV(singleRect(target, 1), false);
23218
23218
  }
23219
23219
  if (atom == null && offset < nodeSize(node)) {
23220
23220
  let after = node.childNodes[offset];
23221
23221
  while (after.pmViewDesc && after.pmViewDesc.ignoreForCoords) after = after.nextSibling;
23222
- let target = !after ? null : isText$1(after) ? textRange$1(after, 0, supportEmptyRange ? 0 : 1) : isElt(after) ? after : null;
23222
+ let target = !after ? null : isText$2(after) ? textRange$1(after, 0, supportEmptyRange ? 0 : 1) : isElt(after) ? after : null;
23223
23223
  if (target) return flattenV(singleRect(target, -1), true);
23224
23224
  }
23225
- return flattenV(singleRect(isText$1(node) ? textRange$1(node) : node, -side), side >= 0);
23225
+ return flattenV(singleRect(isText$2(node) ? textRange$1(node) : node, -side), side >= 0);
23226
23226
  }
23227
23227
  function flattenV(rect, left) {
23228
23228
  if (rect.width == 0) return rect;
@@ -23273,7 +23273,7 @@ function endOfTextblockVertical(view, state, dir) {
23273
23273
  for (let child = dom.firstChild; child; child = child.nextSibling) {
23274
23274
  let boxes;
23275
23275
  if (isElt(child)) boxes = child.getClientRects();
23276
- else if (isText$1(child)) boxes = textRange$1(child, 0, child.nodeValue.length).getClientRects();
23276
+ else if (isText$2(child)) boxes = textRange$1(child, 0, child.nodeValue.length).getClientRects();
23277
23277
  else continue;
23278
23278
  for (let i = 0; i < boxes.length; i++) {
23279
23279
  let box = boxes[i];
@@ -23574,7 +23574,7 @@ var ViewDesc = class {
23574
23574
  let brKludge = false;
23575
23575
  if ((gecko || safari$1) && anchor == head) {
23576
23576
  let { node, offset } = anchorDOM;
23577
- if (isText$1(node)) {
23577
+ if (isText$2(node)) {
23578
23578
  brKludge = !!(offset && node.nodeValue[offset - 1] == "\n");
23579
23579
  if (brKludge && offset == node.nodeValue.length) for (let scan = node, after; scan; scan = scan.parentNode) {
23580
23580
  if (after = scan.nextSibling) {
@@ -23794,7 +23794,7 @@ var NodeViewDesc = class NodeViewDesc extends ViewDesc {
23794
23794
  let dom = spec && spec.dom, contentDOM = spec && spec.contentDOM;
23795
23795
  if (node.isText) {
23796
23796
  if (!dom) dom = document.createTextNode(node.text);
23797
- else if (!isText$1(dom)) throw new RangeError("Text must be rendered as a DOM text node");
23797
+ else if (!isText$2(dom)) throw new RangeError("Text must be rendered as a DOM text node");
23798
23798
  } else if (!dom) {
23799
23799
  let spec = DOMSerializer.renderSpec(document, node.type.spec.toDOM(node), null, node.attrs);
23800
23800
  ({dom, contentDOM} = spec);
@@ -24698,7 +24698,7 @@ function skipIgnoredNodesBefore(view) {
24698
24698
  if (isIgnorable(before, -1)) {
24699
24699
  moveNode = node;
24700
24700
  moveOffset = --offset;
24701
- } else if (isText$1(before)) {
24701
+ } else if (isText$2(before)) {
24702
24702
  node = before;
24703
24703
  offset = node.nodeValue.length;
24704
24704
  } else break;
@@ -24766,7 +24766,7 @@ function textNodeAfter(node, offset) {
24766
24766
  }
24767
24767
  while (node && offset < node.childNodes.length) {
24768
24768
  let next = node.childNodes[offset];
24769
- if (isText$1(next)) return next;
24769
+ if (isText$2(next)) return next;
24770
24770
  if (isElt(next) && next.contentEditable == "false") break;
24771
24771
  node = next;
24772
24772
  offset = 0;
@@ -24779,14 +24779,14 @@ function textNodeBefore(node, offset) {
24779
24779
  }
24780
24780
  while (node && offset) {
24781
24781
  let next = node.childNodes[offset - 1];
24782
- if (isText$1(next)) return next;
24782
+ if (isText$2(next)) return next;
24783
24783
  if (isElt(next) && next.contentEditable == "false") break;
24784
24784
  node = next;
24785
24785
  offset = node.childNodes.length;
24786
24786
  }
24787
24787
  }
24788
24788
  function setSelFocus(view, node, offset) {
24789
- if (!isText$1(node)) {
24789
+ if (!isText$2(node)) {
24790
24790
  let before, after;
24791
24791
  if (after = textNodeAfter(node, offset)) {
24792
24792
  node = after;
@@ -25534,7 +25534,7 @@ editHandlers.compositionstart = editHandlers.compositionupdate = (view) => {
25534
25534
  for (let node = sel.focusNode, offset = sel.focusOffset; node && isElt(node) && offset != 0;) {
25535
25535
  let before = offset < 0 ? node.lastChild : node.childNodes[offset - 1];
25536
25536
  if (!before) break;
25537
- if (isText$1(before)) {
25537
+ if (isText$2(before)) {
25538
25538
  let sel = view.domSelection();
25539
25539
  if (sel) sel.collapse(before, before.nodeValue.length);
25540
25540
  break;
@@ -26485,7 +26485,7 @@ var DOMObserver = class {
26485
26485
  let desc = container && this.view.docView.nearestDesc(container);
26486
26486
  if (desc && desc.ignoreMutation({
26487
26487
  type: "selection",
26488
- target: isText$1(container) ? container.parentNode : container
26488
+ target: isText$2(container) ? container.parentNode : container
26489
26489
  })) {
26490
26490
  this.setCurSelection();
26491
26491
  return true;
@@ -26566,7 +26566,7 @@ var DOMObserver = class {
26566
26566
  for (let i = 0; i < mut.addedNodes.length; i++) {
26567
26567
  let node = mut.addedNodes[i];
26568
26568
  added.push(node);
26569
- if (isText$1(node)) this.lastChangedTextNode = node;
26569
+ if (isText$2(node)) this.lastChangedTextNode = node;
26570
26570
  }
26571
26571
  if (desc.contentDOM && desc.contentDOM != desc.dom && !desc.contentDOM.contains(mut.target)) return {
26572
26572
  from: desc.posBefore,
@@ -27863,7 +27863,7 @@ function prepareViewDom(dom) {
27863
27863
  dom.classList.add("editor");
27864
27864
  dom.setAttribute("role", "textbox");
27865
27865
  }
27866
- var key$3 = new PluginKey("MILKDOWN_VIEW_CLEAR");
27866
+ var key$4 = new PluginKey("MILKDOWN_VIEW_CLEAR");
27867
27867
  var editorView = (ctx) => {
27868
27868
  ctx.inject(rootCtx, document.body).inject(editorViewCtx, {}).inject(editorViewOptionsCtx, {}).inject(rootDOMCtx, null).inject(rootAttrsCtx, {}).inject(editorViewTimerCtx, [EditorStateReady, PasteRulesReady]).record(EditorViewReady);
27869
27869
  return async () => {
@@ -27871,7 +27871,7 @@ var editorView = (ctx) => {
27871
27871
  const root = ctx.get(rootCtx) || document.body;
27872
27872
  const el = typeof root === "string" ? document.querySelector(root) : root;
27873
27873
  ctx.update(prosePluginsCtx, (xs) => [new Plugin({
27874
- key: key$3,
27874
+ key: key$4,
27875
27875
  view: (editorView) => {
27876
27876
  const container = el ? createViewContainer(el, ctx) : void 0;
27877
27877
  const handleDOM = () => {
@@ -28375,6 +28375,7 @@ var defaultLabels = {
28375
28375
  copyCode: "Copy",
28376
28376
  codeLanguage: "Code language",
28377
28377
  codeLanguageSearch: "Search languages",
28378
+ codeWrap: "Wrap code",
28378
28379
  codeAuto: "Auto",
28379
28380
  codePlainText: "Plain text",
28380
28381
  expandCallout: "Expand",
@@ -35804,10 +35805,10 @@ var ie_edge = /Edge\/(\d+)/.exec(agent);
35804
35805
  var ie_upto10 = /MSIE \d/.exec(agent);
35805
35806
  var ie_11up = /Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(agent);
35806
35807
  var safari = !!!(ie_upto10 || ie_11up || ie_edge) && !!nav && /Apple Computer/.test(nav.vendor);
35807
- var key$2 = new PluginKey("safari-ime-span");
35808
+ var key$3 = new PluginKey("safari-ime-span");
35808
35809
  var isComposing = false;
35809
35810
  var spec = {
35810
- key: key$2,
35811
+ key: key$3,
35811
35812
  props: {
35812
35813
  decorations: createDecorations,
35813
35814
  handleDOMEvents: {
@@ -35835,7 +35836,7 @@ function createSpan(view) {
35835
35836
  span.className = "ProseMirror-safari-ime-span";
35836
35837
  return span;
35837
35838
  }
35838
- var imeSpan = new Plugin(safari ? spec : { key: key$2 });
35839
+ var imeSpan = new Plugin(safari ? spec : { key: key$3 });
35839
35840
  //#endregion
35840
35841
  //#region node_modules/.pnpm/ccount@2.0.1/node_modules/ccount/index.js
35841
35842
  /**
@@ -39989,8 +39990,8 @@ var plugins = [
39989
39990
  var authoredSourcesCtx = $ctx(null, "inkkitAuthoredSources");
39990
39991
  /** The block types a conversion changes. Comment and literal blocks also hold code, but keep their own syntax. */
39991
39992
  var isCode$1 = (type) => type.name === "code_block";
39992
- var isText = (type) => type.name === "paragraph" || type.name === "heading";
39993
- var convertible = (type) => isCode$1(type) || isText(type);
39993
+ var isText$1 = (type) => type.name === "paragraph" || type.name === "heading";
39994
+ var convertible = (type) => isCode$1(type) || isText$1(type);
39994
39995
  var keepsSyntax = (type) => type.name === "comment_block" || type.name === "literal_markdown";
39995
39996
  /** The Markdown of a textblock's inline content, as InkKit writes it. */
39996
39997
  function writtenInlineSource(ctx, node) {
@@ -40141,7 +40142,7 @@ function joinKeepingSource(ctx, dir) {
40141
40142
  const pair = [neighbour.type, $edge.parent.type];
40142
40143
  if (!neighbour.isTextblock || !neighbour.content.size || !$edge.parent.content.size || dir < 0 && undoInputRule(state) || dir < 0 && $edge.parent.type.name === "heading") return false;
40143
40144
  if (neighbour.type !== $edge.parent.type && pair.some(keepsSyntax)) return true;
40144
- if (!pair.some(isCode$1) || !pair.some(isText)) return false;
40145
+ if (!pair.some(isCode$1) || !pair.some(isText$1)) return false;
40145
40146
  const before = dir < 0 ? neighbour : $edge.parent;
40146
40147
  const cut = dir < 0 ? $edge.before() : $edge.after();
40147
40148
  if (!dispatch) return true;
@@ -40553,6 +40554,7 @@ function parseLinkedSyntax(raw, inTable = false) {
40553
40554
  const prefix = embed ? "![[" : "[[";
40554
40555
  if (!source.startsWith(prefix) || !source.endsWith("]]")) return void 0;
40555
40556
  const content = source.slice(prefix.length, -2);
40557
+ if (!embed) return wikiLinkParts(raw, content, inTable);
40556
40558
  const parts = {
40557
40559
  target: "",
40558
40560
  fragment: "",
@@ -40561,7 +40563,7 @@ function parseLinkedSyntax(raw, inTable = false) {
40561
40563
  let section = "target", hasFragment = false, hasAlias = false;
40562
40564
  for (let index = 0; index < content.length; index++) {
40563
40565
  const character = content[index];
40564
- if (character === "\\" && embed) {
40566
+ if (character === "\\") {
40565
40567
  const escaped = content[++index];
40566
40568
  if (!escaped || !"[]|#\\".includes(escaped)) return void 0;
40567
40569
  parts[section] += escaped;
@@ -40593,9 +40595,82 @@ function parseLinkedSyntax(raw, inTable = false) {
40593
40595
  inTable
40594
40596
  };
40595
40597
  }
40598
+ /**
40599
+ * A wiki link's parts, read as Marfa reads them (`device/link-parts-split`): the name is the text
40600
+ * before the first `|` or `#`; a `#` before any `|` starts the heading, which runs to the next
40601
+ * `|`; the alias is everything after that `|`, so it can hold `|`, `#` and brackets. An empty
40602
+ * heading or alias counts as none. A backslash is text (`device/link-backslash`).
40603
+ */
40604
+ function wikiLinkParts(raw, content, inTable) {
40605
+ if (content.includes("[[") || content.includes("]]") || content.endsWith("]")) return void 0;
40606
+ for (const character of content) if (character.charCodeAt(0) < 32 && character !== " " || character === "") return void 0;
40607
+ let target = content;
40608
+ let fragment = null;
40609
+ let alias = null;
40610
+ const at = content.search(/[|#]/);
40611
+ if (at >= 0) {
40612
+ target = content.slice(0, at);
40613
+ if (content[at] === "|") alias = content.slice(at + 1);
40614
+ else {
40615
+ const rest = content.slice(at + 1);
40616
+ const bar = rest.indexOf("|");
40617
+ fragment = bar >= 0 ? rest.slice(0, bar) : rest;
40618
+ if (bar >= 0) alias = rest.slice(bar + 1);
40619
+ }
40620
+ }
40621
+ if (fragment != null && !fragment.trim()) fragment = null;
40622
+ if (alias != null && !alias.trim()) alias = null;
40623
+ if (!target.trim() && fragment == null || target.trimStart().startsWith("^") || fragment?.trimStart().startsWith("^")) return void 0;
40624
+ return {
40625
+ raw,
40626
+ target,
40627
+ fragment,
40628
+ label: alias ?? target + (fragment != null ? `#${fragment}` : ""),
40629
+ width: null,
40630
+ embed: false,
40631
+ inTable
40632
+ };
40633
+ }
40634
+ /**
40635
+ * The `[[`…`]]` spans of a line-separated text, bounded as Marfa bounds them: `[` characters pair
40636
+ * from the start of each run, the last opening pair before a `]]` on the same line opens the
40637
+ * span, and a `[[` with no `]]` after it on its line opens nothing (`device/link-bounds`,
40638
+ * `device/link-bounds-pairs`). A span preceded by `!` is an embed. Code and comments should be
40639
+ * blanked by the caller, so a `]]` inside them closes nothing.
40640
+ */
40641
+ function linkedSpans(text) {
40642
+ const found = [];
40643
+ let open = null;
40644
+ for (let at = 0; at < text.length;) {
40645
+ const character = text[at];
40646
+ if (character === "[" && text[at + 1] === "[") {
40647
+ open = at;
40648
+ at += 2;
40649
+ } else if (character === "]" && text[at + 1] === "]" && open != null) {
40650
+ const embed = open > 0 && text[open - 1] === "!";
40651
+ found.push({
40652
+ from: embed ? open - 1 : open,
40653
+ to: at + 2,
40654
+ embed
40655
+ });
40656
+ open = null;
40657
+ at += 2;
40658
+ } else {
40659
+ if (character === "\n" || character === "\r") open = null;
40660
+ at++;
40661
+ }
40662
+ }
40663
+ return found;
40664
+ }
40665
+ /**
40666
+ * The run of `[` each parse is in: where it began and the last offset tried, so openings pair
40667
+ * from the start of the run.
40668
+ */
40669
+ var bracketRuns = /* @__PURE__ */ new WeakMap();
40596
40670
  function linkedTokenizer(embed) {
40597
40671
  return function(effects, ok, nok) {
40598
40672
  const prefix = embed ? "![[" : "[[";
40673
+ const context = this;
40599
40674
  let index = 0, raw = "";
40600
40675
  return opening;
40601
40676
  function consume(code) {
@@ -40604,24 +40679,43 @@ function linkedTokenizer(embed) {
40604
40679
  }
40605
40680
  function opening(code) {
40606
40681
  if (code !== prefix.charCodeAt(index)) return nok(code);
40682
+ if (!index && !embed) {
40683
+ const offset = context.now().offset;
40684
+ const run = bracketRuns.get(context.parser);
40685
+ if (context.previous === 91 && run?.last === offset - 1) {
40686
+ run.last = offset;
40687
+ if ((offset - run.start) % 2) return nok(code);
40688
+ } else {
40689
+ bracketRuns.set(context.parser, {
40690
+ start: offset,
40691
+ last: offset
40692
+ });
40693
+ if (context.previous === 33) return nok(code);
40694
+ }
40695
+ }
40607
40696
  if (!index) effects.enter("inkkitLinkedSyntax");
40608
40697
  consume(code);
40609
40698
  index++;
40610
40699
  return index === prefix.length ? body : opening;
40611
40700
  }
40612
40701
  function body(code) {
40613
- if (code === null || code < 32 && code !== -2 && code !== -1 && code !== 9 || code === 91) return nok(code);
40702
+ if (code === null || code < 32 && code !== -2 && code !== -1 && code !== 9 || code === 91 && embed) return nok(code);
40614
40703
  consume(code);
40615
40704
  if (code === 92 && embed) return escaped;
40705
+ if (code === 91) return bracket;
40616
40706
  return code === 93 ? closing : body;
40617
40707
  }
40708
+ function bracket(code) {
40709
+ if (code === 91) return nok(code);
40710
+ return body(code);
40711
+ }
40618
40712
  function escaped(code) {
40619
40713
  if (code === null || code < 32) return nok(code);
40620
40714
  consume(code);
40621
40715
  return body;
40622
40716
  }
40623
40717
  function closing(code) {
40624
- if (code !== 93) return nok(code);
40718
+ if (code !== 93) return embed ? nok(code) : body(code);
40625
40719
  consume(code);
40626
40720
  if (!parseLinkedSyntax(raw) && !parseLinkedSyntax(raw, true)) return nok(code);
40627
40721
  effects.exit("inkkitLinkedSyntax");
@@ -40946,8 +41040,7 @@ function linkedSyntax(wikiLinks, files) {
40946
41040
  const syntax = { text: {} };
40947
41041
  if (wikiLinks) syntax.text[91] = {
40948
41042
  name: "inkkitWikiLink",
40949
- tokenize: linkedTokenizer(false),
40950
- previous: (code) => code !== 33 && code !== 91
41043
+ tokenize: linkedTokenizer(false)
40951
41044
  };
40952
41045
  if (wikiLinks) syntax.text[92] = backslashBeforeWikiLink;
40953
41046
  if (files) syntax.text[33] = {
@@ -43115,6 +43208,7 @@ function containsUnsupportedLinked(node, source) {
43115
43208
  const start = node.position?.start.offset, end = node.position?.end.offset;
43116
43209
  if (start == null || end == null || node.type === "definition") return false;
43117
43210
  const supported = [];
43211
+ const text = source.slice(start, end).split("");
43118
43212
  const visit = (child) => {
43119
43213
  if ([
43120
43214
  "inkkitWikiLink",
@@ -43126,21 +43220,31 @@ function containsUnsupportedLinked(node, source) {
43126
43220
  "inkkitCommentBlock"
43127
43221
  ].includes(child.type)) {
43128
43222
  const from = child.position?.start.offset, to = child.position?.end.offset;
43129
- if (from != null && to != null) supported.push({
43130
- from,
43131
- to
43132
- });
43223
+ if (from != null && to != null) {
43224
+ supported.push({
43225
+ from,
43226
+ to
43227
+ });
43228
+ if (![
43229
+ "inkkitWikiLink",
43230
+ "image",
43231
+ "link"
43232
+ ].includes(child.type)) {
43233
+ for (let at = Math.max(from, start); at < Math.min(to, end); at++) if (text[at - start] !== "\n" && text[at - start] !== "\r") text[at - start] = " ";
43234
+ }
43235
+ }
43133
43236
  return;
43134
43237
  }
43135
43238
  if ("children" in child) child.children.forEach(visit);
43136
43239
  };
43137
43240
  visit(node);
43138
- for (const match of source.slice(start, end).matchAll(/!?\[\[[^\r\n]*?\]\]/g)) {
43139
- const from = start + match.index, to = from + match[0].length;
43241
+ for (const span of linkedSpans(text.join(""))) {
43242
+ const from = start + span.from, to = start + span.to;
43140
43243
  let escapes = 0;
43141
43244
  while (from - escapes > 0 && source[from - escapes - 1] === "\\") escapes++;
43142
43245
  if (escapes % 2) continue;
43143
- if (!supported.some((span) => span.from <= from && span.to >= to)) return true;
43246
+ if (!supported.some((covered) => covered.from <= from && covered.to >= to)) return true;
43247
+ if (!span.embed && source[from - 1] === "[") return true;
43144
43248
  }
43145
43249
  return false;
43146
43250
  }
@@ -47521,7 +47625,7 @@ async function portableClipboard(content, schema, markdown, adapter, context, co
47521
47625
  }
47522
47626
  //#endregion
47523
47627
  //#region src/reference-clipboard.ts
47524
- function key$1(node) {
47628
+ function key$2(node) {
47525
47629
  if (node.type.name === "reference_definition") return `link:${node.attrs.identifier}`;
47526
47630
  if (node.type.name === "footnote_definition") return `footnote:${node.attrs.identifier}`;
47527
47631
  }
@@ -47536,7 +47640,7 @@ function used(content) {
47536
47640
  function selectionContent(doc, content) {
47537
47641
  const definitions = /* @__PURE__ */ new Map();
47538
47642
  doc.descendants((node) => {
47539
- const id = key$1(node);
47643
+ const id = key$2(node);
47540
47644
  if (id && !definitions.has(id)) definitions.set(id, node);
47541
47645
  });
47542
47646
  const required = used(content);
@@ -47545,7 +47649,7 @@ function selectionContent(doc, content) {
47545
47649
  if (definition) for (const dependency of used(definition.content)) required.add(dependency);
47546
47650
  }
47547
47651
  const complete = (node) => {
47548
- const id = key$1(node);
47652
+ const id = key$2(node);
47549
47653
  if (id && required.has(id) && definitions.has(id)) return definitions.get(id);
47550
47654
  if (node.isText) return node;
47551
47655
  const children = [];
@@ -47557,7 +47661,7 @@ function selectionContent(doc, content) {
47557
47661
  content = Fragment.fromArray(selected);
47558
47662
  const included = /* @__PURE__ */ new Set();
47559
47663
  content.descendants((node) => {
47560
- const id = key$1(node);
47664
+ const id = key$2(node);
47561
47665
  if (id) included.add(id);
47562
47666
  });
47563
47667
  const extra = [];
@@ -47579,7 +47683,7 @@ function referenceMetadata(ctx, doc, content) {
47579
47683
  content = shareableFragment(content);
47580
47684
  let references = false, index = 0;
47581
47685
  const rewrite = (node) => {
47582
- if (key$1(node) || node.type.name === "footnote_reference" || node.marks.some((mark) => mark.type.name === "link" && mark.attrs.identifier)) references = true;
47686
+ if (key$2(node) || node.type.name === "footnote_reference" || node.marks.some((mark) => mark.type.name === "link" && mark.attrs.identifier)) references = true;
47583
47687
  if (node.type.name === "image") return node.type.create({
47584
47688
  ...node.attrs,
47585
47689
  src: `inkkit-clipboard-image:${index++}`
@@ -47597,7 +47701,7 @@ function allLabels(doc) {
47597
47701
  const labels = /* @__PURE__ */ new Map([["link", /* @__PURE__ */ new Set()], ["footnote", /* @__PURE__ */ new Set()]]);
47598
47702
  doc.descendants((node) => {
47599
47703
  if (isCode(node)) return false;
47600
- const id = key$1(node);
47704
+ const id = key$2(node);
47601
47705
  if (id) {
47602
47706
  const separator = id.indexOf(":");
47603
47707
  labels.get(id.slice(0, separator)).add(id.slice(separator + 1));
@@ -56789,14 +56893,37 @@ var codeLanguages = [
56789
56893
  ];
56790
56894
  //#endregion
56791
56895
  //#region src/code-controls.ts
56896
+ var codeControlKey = new PluginKey("codeControls");
56792
56897
  var codeControlCtx = $ctx((operation) => operation(), "inkkitCodeControl");
56793
56898
  function codeControlsPlugin(visibleRect) {
56794
56899
  return $prose((ctx) => new Plugin({
56795
- key: new PluginKey("codeControls"),
56900
+ key: codeControlKey,
56901
+ state: {
56902
+ init: () => DecorationSet.empty,
56903
+ apply(transaction, wrapped) {
56904
+ let next = transaction.docChanged ? DecorationSet.create(transaction.doc, wrapped.find().flatMap((decoration) => {
56905
+ const mapped = transaction.mapping.mapResult(decoration.from + 1, -1);
56906
+ if (mapped.deletedAcross) return [];
56907
+ const inside = mapped.pos;
56908
+ const node = inside > 0 ? transaction.doc.nodeAt(inside - 1) : null;
56909
+ return node?.type.name === "code_block" ? [Decoration.node(inside - 1, inside - 1 + node.nodeSize, { class: "inkkit-code-wrapped" })] : [];
56910
+ })) : wrapped;
56911
+ const toggle = transaction.getMeta(codeControlKey);
56912
+ if (toggle) {
56913
+ const node = transaction.doc.nodeAt(toggle.position);
56914
+ if (node?.type.name === "code_block") {
56915
+ next = next.remove(next.find(toggle.position, toggle.position + node.nodeSize).filter((decoration) => decoration.from === toggle.position));
56916
+ if (toggle.wrapped) next = next.add(transaction.doc, [Decoration.node(toggle.position, toggle.position + node.nodeSize, { class: "inkkit-code-wrapped" })]);
56917
+ }
56918
+ }
56919
+ return next;
56920
+ }
56921
+ },
56796
56922
  props: { decorations(state) {
56797
- const widgets = [];
56923
+ const widgets = [...codeControlKey.getState(state)?.find() ?? []];
56798
56924
  state.doc.descendants((node, pos) => {
56799
56925
  if (node.type.name !== "code_block") return true;
56926
+ if (state.selection.$head.pos > pos && state.selection.$head.pos < pos + node.nodeSize) widgets.push(Decoration.node(pos, pos + node.nodeSize, { "data-inkkit-code-active": "" }));
56800
56927
  const language = String(node.attrs.language ?? "");
56801
56928
  widgets.push(Decoration.widget(pos + 1, (view, getPos) => {
56802
56929
  const labels = editorLabels(ctx);
@@ -56848,7 +56975,32 @@ function codeControlsPlugin(visibleRect) {
56848
56975
  search.setAttribute("aria-label", labels.codeLanguageSearch);
56849
56976
  const list = document.createElement("span");
56850
56977
  list.className = "inkkit-code-language-list";
56851
- popup.append(search, list);
56978
+ const searchRow = document.createElement("span");
56979
+ searchRow.className = "inkkit-code-language-search";
56980
+ const wrap = document.createElement("button");
56981
+ wrap.type = "button";
56982
+ wrap.tabIndex = 0;
56983
+ wrap.className = "inkkit-code-wrap";
56984
+ wrap.setAttribute("aria-label", labels.codeWrap);
56985
+ wrap.title = labels.codeWrap;
56986
+ wrap.innerHTML = "<svg viewBox=\"0 0 24 24\" aria-hidden=\"true\" focusable=\"false\"><path d=\"M3 6h18M3 12h15a3 3 0 0 1 0 6h-4m2-2-2 2 2 2M3 18h4\"/></svg>";
56987
+ const isWrapped = () => {
56988
+ const at = getPos();
56989
+ return at != null && Boolean(codeControlKey.getState(view.state)?.find(at - 1, at).some((decoration) => decoration.from === at - 1));
56990
+ };
56991
+ wrap.setAttribute("aria-pressed", String(isWrapped()));
56992
+ wrap.addEventListener("click", () => {
56993
+ if (view.composing || view.state.doc !== captured) return;
56994
+ const at = getPos();
56995
+ if (at == null) return;
56996
+ view.dispatch(view.state.tr.setMeta(codeControlKey, {
56997
+ position: at - 1,
56998
+ wrapped: !isWrapped()
56999
+ }).setMeta("addToHistory", false));
57000
+ wrap.setAttribute("aria-pressed", String(isWrapped()));
57001
+ });
57002
+ searchRow.append(search, wrap);
57003
+ popup.append(searchRow, list);
56852
57004
  const choices = [
56853
57005
  ["", labels.codeAuto],
56854
57006
  ["text", labels.codePlainText],
@@ -56858,7 +57010,7 @@ function codeControlsPlugin(visibleRect) {
56858
57010
  const render = () => {
56859
57011
  list.replaceChildren();
56860
57012
  for (const [value, name] of choices) {
56861
- if (!`${value} ${name}`.toLowerCase().includes(search.value.toLowerCase())) continue;
57013
+ if (!`${value} ${name}`.toLowerCase().includes(search.value.trim().toLowerCase())) continue;
56862
57014
  const option = document.createElement("button");
56863
57015
  option.type = "button";
56864
57016
  option.textContent = name;
@@ -56927,10 +57079,10 @@ function codeControlsPlugin(visibleRect) {
56927
57079
  const bottom = Math.min(window.innerHeight - 8, safe.bottom - 4);
56928
57080
  const below = Math.max(0, bottom - bounds.bottom - 4);
56929
57081
  const above = Math.max(0, bounds.top - top - 4);
56930
- const height = Math.min(320, Math.max(below, above));
56931
- popup.style.width = `${Math.max(0, Math.min(220, right - left))}px`;
57082
+ const height = Math.min(264, Math.max(below, above));
57083
+ popup.style.width = `${Math.max(0, Math.min(200, right - left))}px`;
56932
57084
  popup.style.maxHeight = `${height}px`;
56933
- popup.style.left = `${Math.max(left, Math.min(bounds.right - 220, right - 220))}px`;
57085
+ popup.style.left = `${Math.max(left, Math.min(bounds.right - 200, right - 200))}px`;
56934
57086
  const menuHeight = Math.min(height, popup.getBoundingClientRect().height);
56935
57087
  popup.style.top = `${Math.max(top, Math.min(below >= menuHeight ? bounds.bottom + 4 : bounds.top - menuHeight - 4, bottom - menuHeight))}px`;
56936
57088
  const outside = (event) => {
@@ -57860,9 +58012,9 @@ var dropIndicatorConfig = $ctx({
57860
58012
  class: "milkdown-drop-indicator"
57861
58013
  }, "dropIndicatorConfig");
57862
58014
  withMeta(dropIndicatorConfig, { displayName: "Ctx<dropIndicatorConfig>" });
57863
- var key = new PluginKey("MILKDOWN_DROP_INDICATOR_DOM");
58015
+ var key$1 = new PluginKey("MILKDOWN_DROP_INDICATOR_DOM");
57864
58016
  var dropIndicatorDOMPlugin = $prose((ctx) => new Plugin({
57865
- key,
58017
+ key: key$1,
57866
58018
  view: (view) => {
57867
58019
  const config = ctx.get(dropIndicatorConfig.key);
57868
58020
  const dom = document.createElement("div");
@@ -58186,6 +58338,197 @@ var placeholderPlugin = $prose((ctx) => new Plugin({
58186
58338
  } }
58187
58339
  }));
58188
58340
  //#endregion
58341
+ //#region src/drawn-selection.ts
58342
+ var hostClass$1 = "inkkit-overlay-host";
58343
+ var layerClass = "inkkit-selection-layer";
58344
+ /** Every text node a range covers, clipped to the range. */
58345
+ function* textPieces(range) {
58346
+ const root = range.commonAncestorContainer;
58347
+ const doc = root.ownerDocument ?? root;
58348
+ if (root.nodeType === Node.TEXT_NODE) {
58349
+ yield range;
58350
+ return;
58351
+ }
58352
+ const walker = doc.createTreeWalker(root, NodeFilter.SHOW_TEXT);
58353
+ let node = walker.nextNode();
58354
+ while (node) {
58355
+ if (range.intersectsNode(node)) {
58356
+ const piece = doc.createRange();
58357
+ piece.setStart(node, node === range.startContainer ? range.startOffset : 0);
58358
+ piece.setEnd(node, node === range.endContainer ? range.endOffset : node.length);
58359
+ if (!piece.collapsed) yield piece;
58360
+ } else if (range.comparePoint(node, 0) > 0) return;
58361
+ node = walker.nextNode();
58362
+ }
58363
+ }
58364
+ /** Groups pieces by visual line within a block and gives each line one height. */
58365
+ function bars(pieces) {
58366
+ const lines = [];
58367
+ for (const piece of pieces) {
58368
+ const line = lines.find((candidate) => candidate.block === piece.block && piece.textTop < candidate.textBottom && piece.textBottom > candidate.textTop);
58369
+ if (line) {
58370
+ line.top = Math.min(line.top, piece.top);
58371
+ line.bottom = Math.max(line.bottom, piece.bottom);
58372
+ line.textTop = Math.min(line.textTop, piece.textTop);
58373
+ line.textBottom = Math.max(line.textBottom, piece.textBottom);
58374
+ line.pieces.push(piece);
58375
+ } else lines.push({
58376
+ block: piece.block,
58377
+ top: piece.top,
58378
+ bottom: piece.bottom,
58379
+ textTop: piece.textTop,
58380
+ textBottom: piece.textBottom,
58381
+ pieces: [piece]
58382
+ });
58383
+ }
58384
+ const out = [];
58385
+ for (const line of lines) {
58386
+ line.pieces.sort((a, b) => a.left - b.left);
58387
+ let current;
58388
+ for (const piece of line.pieces) if (current && piece.left <= current.right + 1) current.right = Math.max(current.right, piece.right);
58389
+ else {
58390
+ current = {
58391
+ left: piece.left,
58392
+ right: piece.right,
58393
+ top: line.top,
58394
+ bottom: line.bottom
58395
+ };
58396
+ out.push(current);
58397
+ }
58398
+ }
58399
+ return out;
58400
+ }
58401
+ /** Draws one view's selection, and redraws it as the view scrolls or resizes. */
58402
+ var SelectionLayer = class {
58403
+ view;
58404
+ layer;
58405
+ ranges = [];
58406
+ frame = 0;
58407
+ resize;
58408
+ doc;
58409
+ constructor(view) {
58410
+ this.view = view;
58411
+ this.doc = view.dom.ownerDocument;
58412
+ this.layer = this.doc.createElement("div");
58413
+ this.layer.className = layerClass;
58414
+ this.layer.setAttribute("aria-hidden", "true");
58415
+ const host = view.dom.parentElement;
58416
+ host?.classList.add(hostClass$1);
58417
+ host?.insertBefore(this.layer, host.firstChild);
58418
+ const win = this.doc.defaultView;
58419
+ this.resize = win?.ResizeObserver ? new win.ResizeObserver(() => this.schedule()) : void 0;
58420
+ this.resize?.observe(view.dom);
58421
+ this.doc.addEventListener("scroll", this.schedule, true);
58422
+ }
58423
+ schedule = () => {
58424
+ if (this.frame || !this.ranges.length) return;
58425
+ const win = this.doc.defaultView;
58426
+ if (!win) return;
58427
+ this.frame = win.requestAnimationFrame(() => {
58428
+ this.frame = 0;
58429
+ this.render();
58430
+ });
58431
+ };
58432
+ /**
58433
+ * Draws the ranges. Text inside an element with an opaque background would hide a bar
58434
+ * drawn behind it, so those pieces are returned for the caller to paint another way.
58435
+ */
58436
+ draw(ranges) {
58437
+ this.ranges = ranges;
58438
+ return this.render();
58439
+ }
58440
+ clear() {
58441
+ this.ranges = [];
58442
+ this.layer.replaceChildren();
58443
+ }
58444
+ render() {
58445
+ const host = this.layer.parentElement;
58446
+ const win = this.doc.defaultView;
58447
+ if (!host || !win || this.view.isDestroyed) return [];
58448
+ const origin = host.getBoundingClientRect();
58449
+ const margin = win.innerHeight;
58450
+ const visibleTop = -margin;
58451
+ const visibleBottom = win.innerHeight + margin;
58452
+ const styles = /* @__PURE__ */ new Map();
58453
+ const style = (element) => {
58454
+ let found = styles.get(element);
58455
+ if (!found) styles.set(element, found = win.getComputedStyle(element));
58456
+ return found;
58457
+ };
58458
+ const opaque = /* @__PURE__ */ new Map();
58459
+ const behindOpaque = (element) => {
58460
+ const known = opaque.get(element);
58461
+ if (known !== void 0) return known;
58462
+ let result = false;
58463
+ if (element !== this.view.dom && element.parentElement) result = backgroundAlpha(style(element).backgroundColor) >= .99 || behindOpaque(element.parentElement);
58464
+ opaque.set(element, result);
58465
+ return result;
58466
+ };
58467
+ const blockRects = /* @__PURE__ */ new Map();
58468
+ const pieces = [];
58469
+ const fallback = [];
58470
+ for (const range of this.ranges) for (const piece of textPieces(range)) {
58471
+ const parent = piece.startContainer.parentElement;
58472
+ if (!parent) continue;
58473
+ if (parent.closest(".ProseMirror-widget")) continue;
58474
+ if (parent.closest("[contenteditable]")?.getAttribute("contenteditable") === "false") continue;
58475
+ const block = parent.closest("p,h1,h2,h3,h4,h5,h6,pre,li,td,th") ?? this.view.dom;
58476
+ let blockRect = blockRects.get(block);
58477
+ if (!blockRect) blockRects.set(block, blockRect = block.getBoundingClientRect());
58478
+ if (blockRect.bottom < visibleTop || blockRect.top > visibleBottom) continue;
58479
+ if (behindOpaque(parent)) {
58480
+ fallback.push(piece);
58481
+ continue;
58482
+ }
58483
+ const lineHeight = Number.parseFloat(style(parent).lineHeight);
58484
+ for (const rect of piece.getClientRects()) {
58485
+ if (!rect.width) continue;
58486
+ const spare = Number.isFinite(lineHeight) && lineHeight > rect.height ? (lineHeight - rect.height) / 2 : 0;
58487
+ pieces.push({
58488
+ block,
58489
+ left: rect.left,
58490
+ right: rect.right,
58491
+ top: rect.top - spare,
58492
+ bottom: rect.bottom + spare,
58493
+ textTop: rect.top,
58494
+ textBottom: rect.bottom
58495
+ });
58496
+ }
58497
+ }
58498
+ const drawn = bars(pieces);
58499
+ const children = this.layer.children;
58500
+ for (let i = 0; i < drawn.length; i++) {
58501
+ const bar = drawn[i];
58502
+ let element = children[i];
58503
+ if (!element) {
58504
+ element = this.doc.createElement("div");
58505
+ this.layer.append(element);
58506
+ }
58507
+ element.style.left = `${bar.left - origin.left}px`;
58508
+ element.style.top = `${bar.top - origin.top}px`;
58509
+ element.style.width = `${bar.right - bar.left}px`;
58510
+ element.style.height = `${bar.bottom - bar.top}px`;
58511
+ }
58512
+ while (children.length > drawn.length) children[children.length - 1].remove();
58513
+ return fallback;
58514
+ }
58515
+ destroy() {
58516
+ if (this.frame) this.doc.defaultView?.cancelAnimationFrame(this.frame);
58517
+ this.resize?.disconnect();
58518
+ this.doc.removeEventListener("scroll", this.schedule, true);
58519
+ this.layer.remove();
58520
+ }
58521
+ };
58522
+ function backgroundAlpha(color) {
58523
+ if (!color || color === "transparent") return 0;
58524
+ const match = /rgba?\(([^)]+)\)/.exec(color);
58525
+ if (!match) return 1;
58526
+ const parts = match[1].split(/[\s,/]+/).filter(Boolean);
58527
+ if (parts.length < 4) return 1;
58528
+ const alpha = parts[3];
58529
+ return alpha.endsWith("%") ? Number.parseFloat(alpha) / 100 : Number(alpha);
58530
+ }
58531
+ //#endregion
58189
58532
  //#region src/selection.ts
58190
58533
  /** The stylesheet paints the selection under this name. */
58191
58534
  var name = "inkkit-selection";
@@ -58324,6 +58667,7 @@ var Painter = class Painter {
58324
58667
  windowFocused;
58325
58668
  hostActivation = /* @__PURE__ */ new WeakMap();
58326
58669
  painted;
58670
+ layers = /* @__PURE__ */ new Map();
58327
58671
  hostActive(view, active) {
58328
58672
  if (active === null) this.hostActivation.delete(view);
58329
58673
  else this.hostActivation.set(view, active);
@@ -58339,14 +58683,17 @@ var Painter = class Painter {
58339
58683
  this.win = doc.defaultView;
58340
58684
  this.windowFocused = doc.hasFocus();
58341
58685
  }
58342
- add(view) {
58686
+ add(view, drawn) {
58343
58687
  if (!this.views.size) this.listen("add");
58344
58688
  this.views.set(view, rootOf(view));
58689
+ if (drawn) this.layers.set(view, new SelectionLayer(view));
58345
58690
  this.sync();
58346
58691
  }
58347
58692
  remove(view) {
58348
58693
  this.views.get(view)?.classList.remove(activeClass);
58349
58694
  this.views.delete(view);
58695
+ this.layers.get(view)?.destroy();
58696
+ this.layers.delete(view);
58350
58697
  if (this.owner === view) this.owner = null;
58351
58698
  this.sync();
58352
58699
  if (!this.views.size) {
@@ -58391,16 +58738,19 @@ var Painter = class Painter {
58391
58738
  }
58392
58739
  sync() {
58393
58740
  for (const [view, root] of this.views) root.classList.toggle(activeClass, (this.hostActivation.get(view) ?? this.windowFocused) && focused(view));
58394
- if (!this.custom) return;
58741
+ if (!this.custom && !this.layers.size) return;
58395
58742
  const { owner } = this;
58396
58743
  if (owner && this.painted?.owner === owner && this.painted.doc === owner.state.doc && this.painted.selection.eq(owner.state.selection)) return;
58744
+ for (const [view, layer] of this.layers) if (view !== owner) layer.clear();
58397
58745
  const spans = owner ? covered(owner.state) : [];
58398
58746
  if (!owner || !spans.length) {
58399
- CSS.highlights.delete(name);
58747
+ if (this.custom) CSS.highlights.delete(name);
58748
+ if (owner) this.layers.get(owner)?.clear();
58400
58749
  this.painted = void 0;
58401
58750
  return;
58402
58751
  }
58403
- const highlight = new Highlight();
58752
+ const ranges = [];
58753
+ const highlight = { add: (range) => ranges.push(range) };
58404
58754
  const contents = blockContents(owner);
58405
58755
  let blocks = 0;
58406
58756
  let mapped = true;
@@ -58412,7 +58762,15 @@ var Painter = class Painter {
58412
58762
  });
58413
58763
  if (mapped && contents.length === blocks) addBlockRanges(highlight, owner, spans, contents);
58414
58764
  else for (const span of spans) highlight.add(domRange(owner, span));
58415
- CSS.highlights.set(name, highlight);
58765
+ const layer = this.layers.get(owner);
58766
+ const painted = layer ? layer.draw(ranges) : ranges;
58767
+ if (this.custom) {
58768
+ if (painted.length) {
58769
+ const highlight = new Highlight();
58770
+ for (const range of painted) highlight.add(range);
58771
+ CSS.highlights.set(name, highlight);
58772
+ } else CSS.highlights.delete(name);
58773
+ }
58416
58774
  this.painted = {
58417
58775
  owner,
58418
58776
  doc: owner.state.doc,
@@ -58420,7 +58778,11 @@ var Painter = class Painter {
58420
58778
  };
58421
58779
  }
58422
58780
  };
58423
- var selectionPlugin = $prose(() => {
58781
+ /**
58782
+ * Paints the selection. With `drawn`, a layer draws it centred on each line of text, and only
58783
+ * text it can't draw behind falls back to a custom highlight.
58784
+ */
58785
+ var selectionPlugin = (drawn) => $prose(() => {
58424
58786
  const key = new PluginKey("selection");
58425
58787
  return new Plugin({
58426
58788
  key,
@@ -58428,10 +58790,10 @@ var selectionPlugin = $prose(() => {
58428
58790
  init: () => 0,
58429
58791
  apply: (tr, count) => tr.selectionSet ? count + 1 : count
58430
58792
  },
58431
- props: paintable() ? { attributes: { class: "inkkit-painted-selection" } } : {},
58793
+ props: drawn || paintable() ? { attributes: { class: "inkkit-painted-selection" } } : {},
58432
58794
  view(view) {
58433
58795
  const painter = Painter.of(view.dom.ownerDocument);
58434
- painter.add(view);
58796
+ painter.add(view, drawn);
58435
58797
  return {
58436
58798
  update(view, previous) {
58437
58799
  if (key.getState(view.state) !== key.getState(previous)) painter.take(view);
@@ -58443,6 +58805,238 @@ var selectionPlugin = $prose(() => {
58443
58805
  });
58444
58806
  });
58445
58807
  //#endregion
58808
+ //#region src/drawn-caret.ts
58809
+ /** Set on the editable surface while the drawn bar replaces the native caret. */
58810
+ var drawnClass = "inkkit-drawn-caret";
58811
+ var barClass = "inkkit-caret";
58812
+ var hostClass = "inkkit-overlay-host";
58813
+ var lineEndKeys = /* @__PURE__ */ new Set(["End"]);
58814
+ var lineStartKeys = /* @__PURE__ */ new Set(["Home"]);
58815
+ function keyIntent(event, caretY) {
58816
+ if (event.shiftKey || event.altKey) return null;
58817
+ const { key, metaKey, ctrlKey } = event;
58818
+ if (lineEndKeys.has(key) || metaKey && key === "ArrowRight") return { kind: "line-end" };
58819
+ if (lineStartKeys.has(key) || metaKey && key === "ArrowLeft") return { kind: "line-start" };
58820
+ if (ctrlKey && !metaKey && key === "e") return { kind: "line-end" };
58821
+ if (ctrlKey && !metaKey && key === "a") return { kind: "line-start" };
58822
+ if (!metaKey && !ctrlKey && (key === "ArrowUp" || key === "ArrowDown") && caretY !== null) return {
58823
+ kind: "vertical",
58824
+ y: caretY,
58825
+ down: key === "ArrowDown"
58826
+ };
58827
+ return null;
58828
+ }
58829
+ var isText = (node) => !!node?.isText;
58830
+ var DrawnCaret = class {
58831
+ view;
58832
+ bar;
58833
+ intent = null;
58834
+ frame = 0;
58835
+ blink = false;
58836
+ drawn = null;
58837
+ resize;
58838
+ doc;
58839
+ constructor(view) {
58840
+ this.view = view;
58841
+ this.doc = view.dom.ownerDocument;
58842
+ this.bar = this.doc.createElement("div");
58843
+ this.bar.className = barClass;
58844
+ this.bar.setAttribute("aria-hidden", "true");
58845
+ view.dom.parentElement?.classList.add(hostClass);
58846
+ view.dom.parentElement?.appendChild(this.bar);
58847
+ const win = this.doc.defaultView;
58848
+ this.resize = win?.ResizeObserver ? new win.ResizeObserver(() => this.schedule()) : void 0;
58849
+ this.resize?.observe(view.dom);
58850
+ this.doc.addEventListener("selectionchange", this.schedule);
58851
+ this.doc.addEventListener("scroll", this.schedule, true);
58852
+ this.doc.fonts?.ready.then(this.schedule);
58853
+ this.update();
58854
+ }
58855
+ schedule = () => {
58856
+ if (this.frame || this.view.isDestroyed) return;
58857
+ const win = this.doc.defaultView;
58858
+ if (!win) return;
58859
+ this.frame = win.requestAnimationFrame(() => {
58860
+ this.frame = 0;
58861
+ this.update();
58862
+ });
58863
+ };
58864
+ keyDown(event) {
58865
+ this.intent = keyIntent(event, this.drawn ? (this.drawn.top + this.drawn.bottom) / 2 : null);
58866
+ }
58867
+ pointerDown(event) {
58868
+ this.intent = {
58869
+ kind: "point",
58870
+ y: event.clientY
58871
+ };
58872
+ }
58873
+ /** Places the bar, or hands the caret back to the engine where the bar can't stand in. */
58874
+ update() {
58875
+ const { view } = this;
58876
+ if (view.isDestroyed) return;
58877
+ const rect = this.measure();
58878
+ view.dom.classList.toggle(drawnClass, rect !== null);
58879
+ if (!rect) {
58880
+ this.drawn = null;
58881
+ this.bar.style.display = "none";
58882
+ return;
58883
+ }
58884
+ const container = this.bar.parentElement;
58885
+ if (!container) return;
58886
+ const origin = container.getBoundingClientRect();
58887
+ const moved = !this.drawn || this.drawn.left !== rect.left || this.drawn.top !== rect.top || this.drawn.bottom !== rect.bottom;
58888
+ this.drawn = rect;
58889
+ const style = this.bar.style;
58890
+ style.display = "";
58891
+ style.left = `${rect.left - origin.left + container.scrollLeft}px`;
58892
+ style.top = `${rect.top - origin.top + container.scrollTop}px`;
58893
+ style.height = `${rect.bottom - rect.top}px`;
58894
+ if (moved) {
58895
+ this.blink = !this.blink;
58896
+ this.bar.dataset.blink = this.blink ? "a" : "b";
58897
+ }
58898
+ }
58899
+ /** The caret's text rectangle in the viewport, or null where the native caret applies. */
58900
+ measure() {
58901
+ const { view } = this;
58902
+ const { selection } = view.state;
58903
+ if (!view.editable || view.composing || !view.hasFocus() || !(selection instanceof TextSelection) || !selection.empty || !selection.$head.parent.inlineContent) return null;
58904
+ const $head = selection.$head;
58905
+ const before = isText($head.nodeBefore);
58906
+ const after = isText($head.nodeAfter);
58907
+ if (!before && !after) return null;
58908
+ let rect;
58909
+ try {
58910
+ rect = this.coords($head.pos, before, after);
58911
+ } catch {
58912
+ return null;
58913
+ }
58914
+ if (!Number.isFinite(rect.top) || !Number.isFinite(rect.left) || !(rect.bottom > rect.top)) return null;
58915
+ return this.visible($head.pos, rect) ? rect : null;
58916
+ }
58917
+ coords(pos, before, after) {
58918
+ const { view } = this;
58919
+ if (!before) return view.coordsAtPos(pos, 1);
58920
+ if (!after) return view.coordsAtPos(pos, -1);
58921
+ const end = view.coordsAtPos(pos, -1);
58922
+ const start = view.coordsAtPos(pos, 1);
58923
+ if (Math.abs(end.top - start.top) < (start.bottom - start.top) / 2) return start;
58924
+ return this.side(end, start) === -1 ? end : start;
58925
+ }
58926
+ side(end, start) {
58927
+ const intent = this.intent;
58928
+ if (!intent) return 1;
58929
+ switch (intent.kind) {
58930
+ case "line-end": return -1;
58931
+ case "line-start": return 1;
58932
+ case "point": {
58933
+ const distance = (rect) => Math.abs((rect.top + rect.bottom) / 2 - intent.y);
58934
+ return distance(end) < distance(start) ? -1 : 1;
58935
+ }
58936
+ case "vertical": {
58937
+ const middle = (rect) => (rect.top + rect.bottom) / 2;
58938
+ const half = (start.bottom - start.top) / 2;
58939
+ if (intent.down) return middle(end) > intent.y + half ? -1 : 1;
58940
+ return middle(start) < intent.y - half ? 1 : -1;
58941
+ }
58942
+ }
58943
+ }
58944
+ /** Whether a scrolled table or code block shows the caret, as it would clip the native one. */
58945
+ visible(pos, rect) {
58946
+ const { view } = this;
58947
+ let node = view.domAtPos(pos).node;
58948
+ const win = this.doc.defaultView;
58949
+ if (!win) return true;
58950
+ while (node && node !== view.dom) {
58951
+ if (node instanceof Element) {
58952
+ const style = win.getComputedStyle(node);
58953
+ if (style.overflowX !== "visible" || style.overflowY !== "visible") {
58954
+ const box = node.getBoundingClientRect();
58955
+ if (rect.left < box.left - 1 || rect.left > box.right + 1 || rect.bottom < box.top || rect.top > box.bottom) return false;
58956
+ }
58957
+ }
58958
+ node = node.parentNode;
58959
+ }
58960
+ return true;
58961
+ }
58962
+ destroy() {
58963
+ if (this.frame) this.doc.defaultView?.cancelAnimationFrame(this.frame);
58964
+ this.resize?.disconnect();
58965
+ this.doc.removeEventListener("selectionchange", this.schedule);
58966
+ this.doc.removeEventListener("scroll", this.schedule, true);
58967
+ this.view.dom.classList.remove(drawnClass);
58968
+ this.bar.parentElement?.classList.remove(hostClass);
58969
+ this.bar.remove();
58970
+ }
58971
+ };
58972
+ var key = new PluginKey("inkkitDrawnCaret");
58973
+ /**
58974
+ * Draws the caret in formatted mode where a fine pointer is the primary input. On touch devices
58975
+ * the system draws the caret and the selection handles, so the native caret stays.
58976
+ */
58977
+ var drawnCaretPlugin = $prose(() => {
58978
+ let caret;
58979
+ return new Plugin({
58980
+ key,
58981
+ view(view) {
58982
+ caret = new DrawnCaret(view);
58983
+ const current = caret;
58984
+ return {
58985
+ update: () => current.update(),
58986
+ destroy: () => {
58987
+ current.destroy();
58988
+ if (caret === current) caret = void 0;
58989
+ }
58990
+ };
58991
+ },
58992
+ props: {
58993
+ handleKeyDown(_view, event) {
58994
+ caret?.keyDown(event);
58995
+ return false;
58996
+ },
58997
+ handleDOMEvents: {
58998
+ mousedown(_view, event) {
58999
+ caret?.pointerDown(event);
59000
+ return false;
59001
+ },
59002
+ mouseup() {
59003
+ caret?.schedule();
59004
+ return false;
59005
+ },
59006
+ keyup() {
59007
+ caret?.schedule();
59008
+ return false;
59009
+ },
59010
+ focus() {
59011
+ caret?.schedule();
59012
+ return false;
59013
+ },
59014
+ blur() {
59015
+ caret?.schedule();
59016
+ return false;
59017
+ },
59018
+ compositionstart() {
59019
+ caret?.schedule();
59020
+ return false;
59021
+ },
59022
+ compositionend() {
59023
+ caret?.schedule();
59024
+ return false;
59025
+ }
59026
+ }
59027
+ }
59028
+ });
59029
+ });
59030
+ /** The bar drawn for this surface while it replaces the native caret. */
59031
+ function drawnCaretBar(surface) {
59032
+ if (!surface.classList.contains(drawnClass)) return null;
59033
+ return surface.parentElement?.querySelector(`:scope > .${barClass}`) ?? null;
59034
+ }
59035
+ /** Whether the primary pointer is fine, so the page, not the system, draws the caret. */
59036
+ function drawsOverlays(win) {
59037
+ return !!win?.matchMedia?.("(pointer: fine)").matches;
59038
+ }
59039
+ //#endregion
58446
59040
  //#region src/wiki-view.ts
58447
59041
  function wikiLinkView(adapter, runtime) {
58448
59042
  return $view(wikiLinkSchema, () => (node, view) => {
@@ -59030,6 +59624,7 @@ function imageView(adapter, host, files, canMutate = () => true) {
59030
59624
  //#region src/editor-milkdown.ts
59031
59625
  /** Assemble plugins in their input and transaction precedence order. The facade owns mutation guards. */
59032
59626
  async function createMilkdownEditor(root, options, runtime) {
59627
+ const drawn = options.rendering?.drawnSelection !== false && drawsOverlays(root.ownerDocument.defaultView);
59033
59628
  return Editor.make().config((ctx) => {
59034
59629
  ctx.set(rootCtx, root);
59035
59630
  ctx.set(authoredSourcesCtx.key, (doc, positions) => runtime.authoredSources(doc, positions));
@@ -59084,7 +59679,7 @@ async function createMilkdownEditor(root, options, runtime) {
59084
59679
  return true;
59085
59680
  }
59086
59681
  }));
59087
- }).use(labelsCtx).use(linkSchemesCtx).use(formatInputCtx).use(richTextGuard).use(runtime.plugins.paste).use(visibleClipboard).use(runtime.plugins.suggestions).use(runtime.plugins.keymap).use(createDialect(Boolean(options.images || options.files), Boolean(options.wikiLinks), Boolean(options.files))).use(codeControlCtx).use(codeControlsPlugin(() => runtime.visibleRect())).use(tablePlugins).use(tableBlock).use(runtime.plugins.change).use(runtime.plugins.historyInput).use(history).use(clipboard).use(cursor).use(taskListPlugin((operation) => runtime.mutate(operation))).use(undoTypedRule).use(quoteBackspace).use(calloutEnter).use(literalEnter).use(literalReread).use(listItemBackspace).use(nestedItemEnter).use(rejoinLists).use(movedListItems).use(textInputPolicy).use(runtime.copy ? codeCopyPlugin((text) => runtime.copy?.(text)) : []).use(placeholderPlugin).use(options.rendering?.codeHighlighting === false ? [] : (await import("./highlight-CVL-YhFo.js")).highlightPlugin).use(options.rendering?.diagramPreview === false || !diagramsAvailable() ? [] : mermaidPreview(runtime.diagrams, (error) => runtime.report(error))).use(selectionPlugin).use($prose(() => search())).use(runtime.plugins.policy).use(options.wikiLinks ? wikiLinkView(options.wikiLinks, {
59682
+ }).use(labelsCtx).use(linkSchemesCtx).use(formatInputCtx).use(richTextGuard).use(runtime.plugins.paste).use(visibleClipboard).use(runtime.plugins.suggestions).use(runtime.plugins.keymap).use(createDialect(Boolean(options.images || options.files), Boolean(options.wikiLinks), Boolean(options.files))).use(codeControlCtx).use(codeControlsPlugin(() => runtime.visibleRect())).use(tablePlugins).use(tableBlock).use(runtime.plugins.change).use(runtime.plugins.historyInput).use(history).use(clipboard).use(cursor).use(taskListPlugin((operation) => runtime.mutate(operation))).use(undoTypedRule).use(quoteBackspace).use(calloutEnter).use(literalEnter).use(literalReread).use(listItemBackspace).use(nestedItemEnter).use(rejoinLists).use(movedListItems).use(textInputPolicy).use(runtime.copy ? codeCopyPlugin((text) => runtime.copy?.(text)) : []).use(placeholderPlugin).use(options.rendering?.codeHighlighting === false ? [] : (await import("./highlight-DlSWR6ji.js")).highlightPlugin).use(options.rendering?.diagramPreview === false || !diagramsAvailable() ? [] : mermaidPreview(runtime.diagrams, (error) => runtime.report(error))).use(selectionPlugin(drawn)).use(drawn ? drawnCaretPlugin : []).use($prose(() => search())).use(runtime.plugins.policy).use(options.wikiLinks ? wikiLinkView(options.wikiLinks, {
59088
59683
  capture: () => runtime.capture(),
59089
59684
  active: () => runtime.active(),
59090
59685
  labels: {
@@ -60069,9 +60664,14 @@ function editorOptions(value) {
60069
60664
  if (!isOmitted(options.textInput)) textInputPreferences(options.textInput, "options.textInput");
60070
60665
  if (!isOmitted(options.keymap)) keymapBindings(options.keymap, "options.keymap");
60071
60666
  const linkSchemes = isOmitted(options.linkSchemes) ? void 0 : extraLinkSchemes(options.linkSchemes, "options.linkSchemes");
60072
- const rendering = optionalRecord(options.rendering, "options.rendering", ["codeHighlighting", "diagramPreview"]);
60667
+ const rendering = optionalRecord(options.rendering, "options.rendering", [
60668
+ "codeHighlighting",
60669
+ "diagramPreview",
60670
+ "drawnSelection"
60671
+ ]);
60073
60672
  optionalBoolean(rendering?.codeHighlighting, "options.rendering.codeHighlighting");
60074
60673
  optionalBoolean(rendering?.diagramPreview, "options.rendering.diagramPreview");
60674
+ optionalBoolean(rendering?.drawnSelection, "options.rendering.drawnSelection");
60075
60675
  const labels = optionalRecord(options.labels, "options.labels", Object.keys(defaultLabels));
60076
60676
  return {
60077
60677
  ...options,
@@ -60622,6 +61222,8 @@ var InkKitEditor = class InkKitEditor {
60622
61222
  const element = dom.nodeType === 1 ? dom : dom.parentElement ?? view.dom;
60623
61223
  const window = this.root.ownerDocument.defaultView;
60624
61224
  const style = window.getComputedStyle(element);
61225
+ const bar = literal ? null : drawnCaretBar(view.dom);
61226
+ const caretColor = bar ? window.getComputedStyle(bar).backgroundColor : style.caretColor;
60625
61227
  const fontFamily = style.fontFamily.slice(0, 160).replace(/[^\p{L}\p{N} ,"'_-]/gu, "");
60626
61228
  const type = selection.$from.parent.type.name;
60627
61229
  const block = literal ? "literal" : type === "paragraph" ? "paragraph" : type === "heading" ? "heading" : type === "code_block" ? "code" : "other";
@@ -60651,7 +61253,7 @@ var InkKitEditor = class InkKitEditor {
60651
61253
  ...style.lineHeight !== "normal" ? { lineHeight: diagnosticNumber(Number.parseFloat(style.lineHeight)) } : {},
60652
61254
  block,
60653
61255
  marks,
60654
- caretColor: /^(?:rgba?\([\d.,% ]+\)|#[\da-f]{3,8}|auto|transparent|currentcolor)$/i.test(style.caretColor) ? style.caretColor.slice(0, 80) : "other",
61256
+ caretColor: /^(?:rgba?\([\d.,% ]+\)|#[\da-f]{3,8}|auto|transparent|currentcolor)$/i.test(caretColor) ? caretColor.slice(0, 80) : "other",
60655
61257
  ...bounds ? { caret: {
60656
61258
  left: diagnosticNumber(bounds.left),
60657
61259
  top: diagnosticNumber(bounds.top),