@aicayzer/inkkit 0.7.2 → 0.7.4

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.
@@ -42330,7 +42330,7 @@ function commentSelectionContent(doc, from, to, content) {
42330
42330
  }
42331
42331
  //#endregion
42332
42332
  //#region src/hidden-comments.ts
42333
- var graphemes$1 = new Intl.Segmenter(void 0, { granularity: "grapheme" });
42333
+ var graphemes$2 = new Intl.Segmenter(void 0, { granularity: "grapheme" });
42334
42334
  function deletion(event) {
42335
42335
  const { altKey: alt, ctrlKey: ctrl, metaKey: meta, key } = event;
42336
42336
  const dir = key === "Backspace" ? -1 : key === "Delete" ? 1 : void 0;
@@ -42373,7 +42373,7 @@ function characterEnd(doc, pos, dir) {
42373
42373
  const node = dir < 0 ? $pos.nodeBefore : $pos.nodeAfter;
42374
42374
  if (!node) return void 0;
42375
42375
  if (!node.isText) return pos + dir * node.nodeSize;
42376
- const segments = [...graphemes$1.segment(node.text)];
42376
+ const segments = [...graphemes$2.segment(node.text)];
42377
42377
  return pos + dir * ((dir < 0 ? segments.at(-1) : segments[0])?.segment.length ?? 1);
42378
42378
  }
42379
42379
  /** Where the browser would end a word or line deletion, measured on the rendered text. */
@@ -53759,7 +53759,7 @@ function modeSelectionMap(ctx, source, doc) {
53759
53759
  function hasImageFile(files) {
53760
53760
  return [...files].some((file) => file.type.startsWith("image/"));
53761
53761
  }
53762
- var graphemes = new Intl.Segmenter(void 0, { granularity: "grapheme" });
53762
+ var graphemes$1 = new Intl.Segmenter(void 0, { granularity: "grapheme" });
53763
53763
  /** Owns the source/TXT textarea and the DOM state of its current input. */
53764
53764
  var SourceSurface = class {
53765
53765
  runtime;
@@ -53900,7 +53900,7 @@ var SourceSurface = class {
53900
53900
  if (key === "Backspace" || key === "Delete") {
53901
53901
  const start = this.element.selectionStart;
53902
53902
  if (start === this.element.selectionEnd) {
53903
- const segment = graphemes.segment(this.element.value).containing(key === "Backspace" ? start - 1 : start);
53903
+ const segment = graphemes$1.segment(this.element.value).containing(key === "Backspace" ? start - 1 : start);
53904
53904
  if (!segment) return false;
53905
53905
  this.element.setSelectionRange(segment.index, segment.index + segment.segment.length);
53906
53906
  }
@@ -59038,6 +59038,42 @@ function drawsOverlays(win) {
59038
59038
  }
59039
59039
  //#endregion
59040
59040
  //#region src/wiki-view.ts
59041
+ /** Whether the style engine reads the text as one color, so a value cannot carry a second
59042
+ * declaration into the property it is written to. */
59043
+ function checkedColor(value, what) {
59044
+ const probe = document.createElement("span");
59045
+ if (typeof value === "string") probe.style.color = value;
59046
+ if (probe.style.color === "") throw new TypeError(`Wiki link ${what} must be a color`);
59047
+ return value;
59048
+ }
59049
+ /** What a link draws beyond its text: an icon, which is decoration drawn as a CSS mask, so a URL
59050
+ * that fetches from the network or runs script is refused, and a tint, a color for a host's look
59051
+ * to fill the link with. Either one that cannot be drawn refuses both. */
59052
+ function drawn(presentation) {
59053
+ const { icon, iconColor, tint } = presentation;
59054
+ const result = {};
59055
+ if (tint !== void 0) result.tint = checkedColor(tint, "tint");
59056
+ if (icon === void 0) return result;
59057
+ if (typeof icon !== "string" || !icon.trim()) throw new TypeError("Wiki link icon needs a URL");
59058
+ const url = new URL(icon, document.baseURI);
59059
+ if ([
59060
+ "http:",
59061
+ "https:",
59062
+ "javascript:",
59063
+ "vbscript:"
59064
+ ].includes(url.protocol)) throw new TypeError("Wiki link icons must load offline");
59065
+ if (url.protocol === "data:" && !/^image\//i.test(url.pathname)) throw new TypeError("Wiki link icon data URL must be an image");
59066
+ result.icon = iconColor === void 0 ? { url: url.href } : {
59067
+ url: url.href,
59068
+ color: checkedColor(iconColor, "icon color")
59069
+ };
59070
+ return result;
59071
+ }
59072
+ /** A quoted CSS url() whose text cannot end the string or the declaration early. */
59073
+ var cssUrl = (url) => `url("${url.replace(/[\\"\n\r\f]/g, (character) => `\\${character.charCodeAt(0).toString(16)} `)}")`;
59074
+ var graphemes = new Intl.Segmenter(void 0, { granularity: "grapheme" });
59075
+ /** The first character a reader sees, so a combining mark stays with its base. */
59076
+ var firstGrapheme = (label) => graphemes.segment(label)[Symbol.iterator]().next().value?.segment ?? "";
59041
59077
  function wikiLinkView(adapter, runtime) {
59042
59078
  return $view(wikiLinkSchema, () => (node, view) => {
59043
59079
  let current = node;
@@ -59045,21 +59081,54 @@ function wikiLinkView(adapter, runtime) {
59045
59081
  dom.className = "inkkit-wiki-link";
59046
59082
  dom.setAttribute("role", "link");
59047
59083
  dom.tabIndex = 0;
59084
+ const text = document.createTextNode("");
59085
+ dom.append(text);
59086
+ let lead;
59087
+ const showLabel = (label, icon) => {
59088
+ if (!icon) {
59089
+ lead?.box.remove();
59090
+ lead = void 0;
59091
+ if (text.data !== label) text.data = label;
59092
+ return;
59093
+ }
59094
+ if (!lead) {
59095
+ const box = document.createElement("span");
59096
+ box.className = "inkkit-wiki-link-lead";
59097
+ const leadText = document.createTextNode("");
59098
+ box.append(leadText);
59099
+ dom.insertBefore(box, text);
59100
+ lead = {
59101
+ box,
59102
+ text: leadText
59103
+ };
59104
+ }
59105
+ const first = firstGrapheme(label);
59106
+ if (lead.text.data !== first) lead.text.data = first;
59107
+ const rest = label.slice(first.length);
59108
+ if (text.data !== rest) text.data = rest;
59109
+ lead.box.style.setProperty("--_inkkit-wiki-icon", cssUrl(icon.url));
59110
+ if (icon.color) lead.box.style.setProperty("--_inkkit-wiki-icon-color", icon.color);
59111
+ else lead.box.style.removeProperty("--_inkkit-wiki-icon-color");
59112
+ };
59048
59113
  const reference = () => wikiReference(current);
59049
59114
  const report = (error) => runtime.error?.(coded(error, "file-unavailable"));
59050
59115
  const render = () => {
59051
59116
  const { label } = reference();
59052
- if (dom.textContent !== label) dom.textContent = label;
59053
59117
  let missing = false;
59118
+ let look = {};
59054
59119
  if (runtime.active()) {
59055
59120
  const captured = runtime.capture();
59056
59121
  try {
59057
59122
  const result = adapter.resolve?.(reference(), captured.context);
59058
59123
  missing = captured.isCurrent() && Boolean(result?.missing);
59124
+ if (result && captured.isCurrent() && !missing) look = drawn(result);
59059
59125
  } catch (error) {
59060
59126
  report(error);
59061
59127
  }
59062
59128
  }
59129
+ showLabel(label, look.icon);
59130
+ if (look.tint) dom.style.setProperty("--_inkkit-wiki-link-tint", look.tint);
59131
+ else dom.style.removeProperty("--_inkkit-wiki-link-tint");
59063
59132
  if (missing) {
59064
59133
  dom.dataset.missing = "true";
59065
59134
  dom.title = runtime.labels.wikiMissing;
@@ -59351,16 +59420,18 @@ var ImageView = class {
59351
59420
  const text = document.createElement("span");
59352
59421
  text.className = "inkkit-file-label";
59353
59422
  text.textContent = label;
59354
- text.title = label;
59355
- name.append(text);
59356
- if (activation && this.runtime?.adapter.open) this.activateCard(label);
59357
- else if (this.runtime?.adapter.open) {
59423
+ if (this.runtime?.adapter.open && !activation) {
59358
59424
  const open = this.button("", this.activate);
59359
59425
  open.classList.add("inkkit-file-open");
59360
- open.setAttribute("aria-label", `${this.runtime.labels.fileOpen} ${label}`);
59361
- open.title = this.runtime.labels.fileOpen;
59362
- open.append(openArrow());
59426
+ const opening = `${this.runtime.labels.fileOpen} ${label}`;
59427
+ open.setAttribute("aria-label", opening);
59428
+ open.title = opening;
59429
+ open.append(text, openArrow());
59363
59430
  name.append(open);
59431
+ } else {
59432
+ text.title = label;
59433
+ name.append(text);
59434
+ if (activation && this.runtime?.adapter.open) this.activateCard(label);
59364
59435
  }
59365
59436
  footer.append(name);
59366
59437
  if (status) {
@@ -59393,6 +59464,7 @@ var ImageView = class {
59393
59464
  this.element.removeEventListener("click", this.cardClick);
59394
59465
  this.element.removeEventListener("keydown", this.cardKey);
59395
59466
  this.element.removeAttribute("tabindex");
59467
+ this.element.removeAttribute("title");
59396
59468
  this.element.removeAttribute("data-inkkit-file-activation");
59397
59469
  this.element.removeAttribute("data-inkkit-file-layout");
59398
59470
  this.cardKeys = false;
@@ -59430,8 +59502,8 @@ var ImageView = class {
59430
59502
  if (presentation.kind === "missing") this.card(label, this.runtime.labels.fileMissing, true);
59431
59503
  else if (presentation.kind === "error") this.card(label, presentation.message || this.runtime.labels.fileError, true);
59432
59504
  else if (presentation.kind === "image") {
59505
+ this.element.title = label;
59433
59506
  this.renderImage(presentation.url, label, width);
59434
- this.card(label);
59435
59507
  } else if (presentation.kind === "audio" || presentation.kind === "video") {
59436
59508
  const media = document.createElement(presentation.kind);
59437
59509
  media.controls = true;
@@ -59679,7 +59751,7 @@ async function createMilkdownEditor(root, options, runtime) {
59679
59751
  return true;
59680
59752
  }
59681
59753
  }));
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, {
59754
+ }).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-9qMrVP06.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, {
59683
59755
  capture: () => runtime.capture(),
59684
59756
  active: () => runtime.active(),
59685
59757
  labels: {
@@ -1,4 +1,4 @@
1
- import { c as DecorationSet, f as __commonJSMin, l as Plugin, o as $prose, p as __toESM, s as Decoration, u as PluginKey } from "./core-BeZFc1qW.js";
1
+ import { c as DecorationSet, f as __commonJSMin, l as Plugin, o as $prose, p as __toESM, s as Decoration, u as PluginKey } from "./core-B9tnDvUW.js";
2
2
  //#region node_modules/.pnpm/highlight.js@11.11.2/node_modules/highlight.js/es/languages/arduino.js
3
3
  /** @type LanguageFn */
4
4
  function cPlusPlus(hljs) {
package/dist/core.d.ts CHANGED
@@ -2,6 +2,6 @@ export { InkKitEditor } from './editor.js';
2
2
  export type { EditorEvents, EditorOptions, TextInputPreferences, CommandState, EditingMode, CaretState, Mark, Block, FormatCommand, FormatOptions, KeyInput, ImageInsertion, ShortcutName, Keymap, } from './editor.js';
3
3
  export { InkKitError } from './types.js';
4
4
  export { normalizeLinkAddress, canOpenLink } from './link-address.js';
5
- export type { DocumentFormat, TextDocumentFormat, TextDocumentInput, RichTextDocumentInput, TextDocumentSnapshot, RichTextDocumentSnapshot, RichTextDocument, RichTextBlock, RichTextListItem, RichTextTableCell, RichTextInline, RichTextMark, FormatLoss, FormatLossCode, ConvertedDocument, FormatPromise, OfferedFormat, EditorLabels, Heading, TableCommand, TableOptions, BlockMoveDirection, DocumentContext, DocumentInput, DocumentSnapshot, DocumentVersion, EditorErrorCode, ImageAdapter, ImageImportContext, WikiLinkReference, WikiLinkAdapter, FileReference, ClientPoint, FileContext, FilePresentation, FileAdapter, CapturedImage, PortableImage, ClipboardInput, ClipboardOutput, ClipboardScope, ClipboardImage, ClipboardDiagram, PrintableDocument, PrintableWarning, TextRange, FindState, FindSession, ReadableTextSnapshot, TextRect, ViewportInsets, ViewportOptions, ViewportSnapshot, } from './types.js';
5
+ export type { DocumentFormat, TextDocumentFormat, TextDocumentInput, RichTextDocumentInput, TextDocumentSnapshot, RichTextDocumentSnapshot, RichTextDocument, RichTextBlock, RichTextListItem, RichTextTableCell, RichTextInline, RichTextMark, FormatLoss, FormatLossCode, ConvertedDocument, FormatPromise, OfferedFormat, EditorLabels, Heading, TableCommand, TableOptions, BlockMoveDirection, DocumentContext, DocumentInput, DocumentSnapshot, DocumentVersion, EditorErrorCode, ImageAdapter, ImageImportContext, WikiLinkPresentation, WikiLinkReference, WikiLinkAdapter, FileReference, ClientPoint, FileContext, FilePresentation, FileAdapter, CapturedImage, PortableImage, ClipboardInput, ClipboardOutput, ClipboardScope, ClipboardImage, ClipboardDiagram, PrintableDocument, PrintableWarning, TextRange, FindState, FindSession, ReadableTextSnapshot, TextRect, ViewportInsets, ViewportOptions, ViewportSnapshot, } from './types.js';
6
6
  export type { SlashMenuOptions, SlashCommandName, SlashCommand } from './types.js';
7
7
  export type { DiagnosticReport, DiagnosticEvent, DiagnosticState, DiagnosticPresentation, } from './diagnostics.js';
package/dist/core.js CHANGED
@@ -1,2 +1,2 @@
1
- import { a as InkKitError, n as normalizeLinkAddress, r as InkKitEditor, t as canOpenLink } from "./chunks/core-BeZFc1qW.js";
1
+ import { a as InkKitError, n as normalizeLinkAddress, r as InkKitEditor, t as canOpenLink } from "./chunks/core-B9tnDvUW.js";
2
2
  export { InkKitEditor, InkKitError, canOpenLink, normalizeLinkAddress };
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { a as InkKitError, i as registerDiagram, n as normalizeLinkAddress, r as InkKitEditor, t as canOpenLink } from "./chunks/core-BeZFc1qW.js";
1
+ import { a as InkKitError, i as registerDiagram, n as normalizeLinkAddress, r as InkKitEditor, t as canOpenLink } from "./chunks/core-B9tnDvUW.js";
2
2
  //#region node_modules/.pnpm/dompurify@3.4.17/node_modules/dompurify/dist/purify.es.mjs
3
3
  /*! @license DOMPurify 3.4.17 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/3.4.17/LICENSE */
4
4
  function _OverloadYield(e, d) {
package/dist/style.css CHANGED
@@ -379,6 +379,14 @@
379
379
  padding: 6px;
380
380
  white-space: normal;
381
381
  }
382
+ /* A picture that loads is drawn bare: no border, padding or caption. Any grey inside it is the
383
+ picture's own. A picture that is loading or has failed keeps its card. */
384
+ .inkkit-root
385
+ .ProseMirror
386
+ .inkkit-file[data-inkkit-file-state='resolved'][data-inkkit-file-kind='image'] {
387
+ border: 0;
388
+ padding: 0;
389
+ }
382
390
 
383
391
  /* A file presentation with `layout: 'fill'` takes the column's width instead of its label's. */
384
392
  .inkkit-root
@@ -408,17 +416,6 @@
408
416
  .inkkit-root .ProseMirror .inkkit-file-footer:not(:first-child) {
409
417
  margin-block-start: 0.25em;
410
418
  }
411
- /* Below a picture, the name takes the picture's width rather than widening the card, so the grip
412
- stays at the picture's edge; a short picture still leaves room for a few characters. */
413
- .inkkit-root .ProseMirror .inkkit-image-preview ~ .inkkit-file-footer {
414
- width: 0;
415
- min-width: 100%;
416
- }
417
- .inkkit-root
418
- .ProseMirror
419
- .inkkit-image.inkkit-file:has(> .inkkit-image-preview) {
420
- min-width: min(100%, 8em);
421
- }
422
419
  /* The name truncates; the open arrow stays visible right after it. */
423
420
  .inkkit-root .ProseMirror .inkkit-file-name {
424
421
  display: flex;
@@ -470,29 +467,42 @@
470
467
  cursor: pointer;
471
468
  }
472
469
  .inkkit-root .ProseMirror .inkkit-file-open {
470
+ /* The name and the arrow are one link: a plain control that the footer's muted text colours. */
473
471
  display: inline-flex;
472
+ flex: 0 1 auto;
474
473
  align-items: center;
475
- justify-content: center;
476
- min-width: 1.5em;
477
- min-height: 1.5em;
474
+ gap: 0.25em;
475
+ min-width: 0;
476
+ max-width: 100%;
478
477
  padding: 0;
479
478
  color: var(--_inkkit-muted);
480
479
  background: transparent;
481
- border-color: transparent;
480
+ border: 0;
481
+ border-radius: 3px;
482
+ text-align: start;
482
483
  }
483
484
  .inkkit-root .ProseMirror .inkkit-file-open:hover {
484
485
  color: var(--_inkkit-text);
485
- background: var(--_inkkit-code-bg);
486
+ }
487
+ .inkkit-root .ProseMirror .inkkit-file-open:hover .inkkit-file-label {
488
+ text-decoration: underline;
486
489
  }
487
490
  .inkkit-root .ProseMirror .inkkit-file-open svg {
491
+ flex: none;
492
+ box-sizing: content-box;
488
493
  width: 0.85em;
489
494
  height: 0.85em;
495
+ padding: 0.2em;
496
+ border-radius: 3px;
490
497
  fill: none;
491
498
  stroke: currentColor;
492
499
  stroke-width: 1.5;
493
500
  stroke-linecap: round;
494
501
  stroke-linejoin: round;
495
502
  }
503
+ .inkkit-root .ProseMirror .inkkit-file-open:hover svg {
504
+ background: var(--_inkkit-code-bg);
505
+ }
496
506
 
497
507
  .inkkit-root .ProseMirror {
498
508
  /* The viewport, not the wrapper Milkdown adds, so a click below the text still places the caret. */
@@ -669,27 +679,90 @@
669
679
  font-weight: 700;
670
680
  }
671
681
 
672
- .inkkit-root .ProseMirror a,
673
- .inkkit-root .inkkit-wiki-link {
682
+ .inkkit-root .ProseMirror a {
674
683
  color: var(--_inkkit-accent);
675
684
  text-decoration: none;
676
685
  text-underline-offset: 2px;
677
686
  }
678
687
 
679
- .inkkit-root .ProseMirror a:hover,
680
- .inkkit-root .inkkit-wiki-link:hover {
688
+ .inkkit-root .ProseMirror a:hover {
681
689
  text-decoration: underline;
682
690
  }
683
691
 
692
+ /* A wiki link reads each part of its look from a variable whose default is the plain look. */
693
+ .inkkit-root .inkkit-wiki-link {
694
+ color: var(--inkkit-wiki-link-color, var(--_inkkit-accent));
695
+ text-decoration-line: var(--inkkit-wiki-link-underline, none);
696
+ text-decoration-style: solid;
697
+ text-decoration-thickness: var(--inkkit-wiki-link-underline-thickness, auto);
698
+ text-decoration-color: var(--inkkit-wiki-link-underline-color, currentcolor);
699
+ text-underline-offset: var(--inkkit-wiki-link-underline-offset, 2px);
700
+ padding: var(--inkkit-wiki-link-padding-block, 0)
701
+ var(--inkkit-wiki-link-padding-inline, 0);
702
+ border-radius: var(--inkkit-wiki-link-radius, 0);
703
+ /* The link's tint, when it has one, mixes into the host's background by the strength the host
704
+ gives it. The host cannot read the tint itself: a variable it sets on the root is read there,
705
+ where the link's own custom property does not exist. */
706
+ background-color: color-mix(
707
+ in srgb,
708
+ var(
709
+ --_inkkit-wiki-link-tint,
710
+ var(--inkkit-wiki-link-background, transparent)
711
+ )
712
+ var(--inkkit-wiki-link-tint-strength, 0%),
713
+ var(--inkkit-wiki-link-background, transparent)
714
+ );
715
+ /* A link that wraps keeps its padding and corners on every line. */
716
+ -webkit-box-decoration-break: clone;
717
+ box-decoration-break: clone;
718
+ }
719
+
720
+ .inkkit-root .inkkit-wiki-link:hover {
721
+ color: var(
722
+ --inkkit-wiki-link-hover-color,
723
+ var(--inkkit-wiki-link-color, var(--_inkkit-accent))
724
+ );
725
+ text-decoration-line: var(--inkkit-wiki-link-hover-underline, underline);
726
+ }
727
+
684
728
  /* A missing target differs by its line, not only its color, which forced colors replace. */
685
729
  .inkkit-root .inkkit-wiki-link[data-missing] {
686
- text-decoration: underline dashed;
730
+ text-decoration-line: underline;
731
+ text-decoration-style: dashed;
732
+ }
733
+
734
+ /* The icon is generated content before the link's first character, so it adds no text, no caret
735
+ position and nothing to copy. It is an inline-block with a size of its own because WebKit
736
+ paints the whole box of an inline element in the mask's color. A line may break either side of
737
+ such a box, so the character it sits before is held with it by no-wrap. */
738
+ .inkkit-root .inkkit-wiki-link-lead {
739
+ white-space: nowrap;
740
+ }
741
+
742
+ .inkkit-root .inkkit-wiki-link-lead::before {
743
+ content: '';
744
+ display: var(--inkkit-wiki-link-icon-display, inline-block);
745
+ width: var(--inkkit-wiki-link-icon-size, 0.9em);
746
+ height: var(--inkkit-wiki-link-icon-size, 0.9em);
747
+ margin-inline-end: var(--inkkit-wiki-link-icon-gap, 0.3em);
748
+ /* Centers the square on the text's height. */
749
+ vertical-align: calc(0.35em - var(--inkkit-wiki-link-icon-size, 0.9em) / 2);
750
+ background-color: var(--_inkkit-wiki-icon-color, currentColor);
751
+ mask-image: var(--_inkkit-wiki-icon);
752
+ mask-repeat: no-repeat;
753
+ mask-position: center;
754
+ mask-size: 100% 100%;
687
755
  }
688
756
 
689
757
  @media (forced-colors: active) {
690
758
  .inkkit-root .inkkit-wiki-link {
691
759
  color: LinkText;
692
760
  }
761
+
762
+ .inkkit-root .inkkit-wiki-link-lead::before {
763
+ forced-color-adjust: none;
764
+ background-color: LinkText;
765
+ }
693
766
  }
694
767
 
695
768
  /* Held Mod opens a link on click; an empty address opens nothing. */
@@ -764,34 +837,6 @@
764
837
  overflow-wrap: anywhere;
765
838
  }
766
839
 
767
- .inkkit-root .ProseMirror pre .inkkit-code-controls,
768
- .inkkit-root .ProseMirror pre .inkkit-copy {
769
- opacity: 0;
770
- pointer-events: none;
771
- transition: opacity 120ms;
772
- }
773
-
774
- .inkkit-root .ProseMirror pre:hover .inkkit-code-controls,
775
- .inkkit-root .ProseMirror pre:hover .inkkit-copy,
776
- .inkkit-root .ProseMirror pre:focus-within .inkkit-code-controls,
777
- .inkkit-root .ProseMirror pre:focus-within .inkkit-copy,
778
- .inkkit-root
779
- .ProseMirror
780
- pre:has(.inkkit-code-language[aria-expanded='true'])
781
- .inkkit-code-controls,
782
- .inkkit-root
783
- .ProseMirror
784
- pre:has(.inkkit-code-language[aria-expanded='true'])
785
- .inkkit-copy,
786
- .inkkit-root
787
- .ProseMirror-focused
788
- pre[data-inkkit-code-active]
789
- .inkkit-code-controls,
790
- .inkkit-root .ProseMirror-focused pre[data-inkkit-code-active] .inkkit-copy {
791
- opacity: 1;
792
- pointer-events: auto;
793
- }
794
-
795
840
  .inkkit-root .ProseMirror blockquote {
796
841
  position: relative;
797
842
  margin: 0 0 calc(var(--_inkkit-font-size) * 0.8);
@@ -1154,6 +1199,7 @@
1154
1199
  }
1155
1200
 
1156
1201
  .inkkit-root .inkkit-comment,
1202
+ .inkkit-root .inkkit-wiki-link-lead::before,
1157
1203
  .inkkit-root [data-inkkit-callout-toggle],
1158
1204
  .inkkit-root .ProseMirror pre .inkkit-copy,
1159
1205
  .inkkit-root .inkkit-table-controls,
package/dist/types.d.ts CHANGED
@@ -174,14 +174,27 @@ export interface WikiLinkReference {
174
174
  /** The text shown: the alias, or the target and fragment. */
175
175
  label: string;
176
176
  }
177
+ /** How a resolved wiki link is drawn, beyond its text. */
178
+ export interface WikiLinkPresentation {
179
+ /** An image drawn as a mask before the link text, such as a data URL of an SVG. It stays with the
180
+ * first character of the link and is decoration only. A `missing` link ignores it. */
181
+ icon?: string;
182
+ /** The icon's CSS color: a color value or a `var()` reference. Without it, or with an undefined
183
+ * variable, the icon takes the link text's color. */
184
+ iconColor?: string;
185
+ /** A CSS color for a host's look to fill the link with, such as the tint of its kind of item. It
186
+ * is a color value or a `var()` reference, and a link without one fills with the host's plain
187
+ * background. A `missing` link ignores it. */
188
+ tint?: string;
189
+ }
177
190
  /** Resolves and opens wiki links. The host owns lookup, permissions and navigation. */
178
191
  export interface WikiLinkAdapter {
179
192
  /** Matches note names for a typed `[[` query. Late answers are ignored. */
180
193
  suggest?(query: string, context: FileContext): Promise<readonly string[]>;
181
- /** Whether the target is missing, for presentation only. */
182
- resolve?(reference: WikiLinkReference, context: DocumentContext): {
194
+ /** Whether the target is missing, and how to draw it if it is not, for presentation only. */
195
+ resolve?(reference: WikiLinkReference, context: DocumentContext): ({
183
196
  missing?: boolean;
184
- } | undefined;
197
+ } & WikiLinkPresentation) | undefined;
185
198
  /** Called by Mod-click, and by Enter or Space on the focused link. */
186
199
  open(reference: WikiLinkReference, context: DocumentContext): void;
187
200
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aicayzer/inkkit",
3
- "version": "0.7.2",
3
+ "version": "0.7.4",
4
4
  "description": "A preserving Markdown editor for offline web views and the web",
5
5
  "license": "MIT",
6
6
  "type": "module",