@latentic/live-markdown 0.4.1 → 0.4.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,23 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.4.2] - 2026-09-10
4
+
5
+ ### Fixed
6
+
7
+ - **Selected text was the least readable text on screen in a dark host.**
8
+ CodeMirror's base theme carries
9
+ `&light.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground`,
10
+ far more specific than the plain `.cm-selectionBackground` this package set —
11
+ and because the editor is themed through CSS custom properties rather than
12
+ registered as `{ dark: true }`, CodeMirror believes it is always `&light` and
13
+ painted its own `#d7d4f0` over the host's `--cds-highlight`. Light text on a
14
+ light band, exactly where a reader had just selected something.
15
+
16
+ The same trap the caret hit, in the one place where getting it wrong hides
17
+ what the reader is looking at. Both focused and unfocused states are now
18
+ stated at CodeMirror's own specificity, and pinned by a browser test that
19
+ reads the computed colour back.
20
+
3
21
  ## [0.4.1] - 2026-09-10
4
22
 
5
23
  ### Changed
@@ -128,7 +128,22 @@ const hideNativeSelection = Prec.highest(
128
128
  }
129
129
  })
130
130
  );
131
- const drawnSelection = [selectionLayer, widgetTintLayer, hideNativeSelection];
131
+ const selectionColor = Prec.highest(
132
+ EditorView.theme({
133
+ "&.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground": {
134
+ background: "var(--cds-highlight, #d0e2ff)"
135
+ },
136
+ "&:not(.cm-focused) > .cm-scroller > .cm-selectionLayer .cm-selectionBackground": {
137
+ background: "var(--cds-layer-accent-01, #e0e0e0)"
138
+ }
139
+ })
140
+ );
141
+ const drawnSelection = [
142
+ selectionLayer,
143
+ widgetTintLayer,
144
+ hideNativeSelection,
145
+ selectionColor
146
+ ];
132
147
  export {
133
148
  drawnSelection
134
149
  };
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/codemirror/selectionLayer.ts"],"sourcesContent":["/**\n * Drawn selection over a virtualized viewport (#166).\n *\n * CodeMirror renders only the visible viewport, and the browser's native\n * `::selection` can only highlight DOM that exists — so with native painting,\n * a Cmd+A or Shift-extended selection shows highlight only on whatever\n * happened to be rendered, and scrolling away and back loses it entirely.\n * This layer paints selection ranges FROM LOGICAL STATE\n * (`state.selection` × the current viewport), so the highlight is correct at\n * every scroll position by construction.\n *\n * Why not CM6's own `drawSelection()`: its wrapped-line handling reverse-maps\n * the editor's far-left/right edge through `posAtCoords` per endpoint, and on\n * lines that start with hidden markers + widgets that probe jitters between\n * before/after the hidden prefix, flashing between one-piece and three-piece\n * painting per drag update (#90). The rects here derive only from FORWARD\n * geometry — `coordsAtPos` of the actual endpoints plus line-block boxes —\n * with no reverse edge probe anywhere:\n *\n * * endpoints in the same visual row → one rect between their coords;\n * * a wrapped or multi-line range → a partial rect for the first row, a\n * partial rect for the last row, and ONE full-width rect for everything\n * between (which also spans block widgets and hidden rows);\n * * a block widget wholly inside a range additionally gets a translucent\n * ABOVE-content tint (`cm-selectionWidgetTint`): widgets paint opaque\n * backgrounds over a below-content layer, so without it a selected\n * table/diagram would show no feedback at all.\n *\n * Known coarseness: partial rows of RTL text paint full-width (bidi span\n * splitting is deliberately not reimplemented here); LTR documents paint\n * glyph-accurately.\n *\n * The native `::selection` stays for the tablev2 cell editors (their own\n * contenteditable islands) and is made transparent everywhere else — the DOM\n * selection itself is untouched, so IME, copy, and focus behavior keep\n * working on the real selection.\n */\n\nimport { Prec, type Extension, type SelectionRange } from \"@codemirror/state\";\nimport {\n BlockType,\n Direction,\n EditorView,\n layer,\n RectangleMarker,\n type BlockInfo,\n} from \"@codemirror/view\";\n\n/** Client-rect → document-space base, mirroring CM6's own layer arithmetic. */\nfunction layerBase(view: EditorView): { left: number; top: number } {\n const rect = view.scrollDOM.getBoundingClientRect();\n const left =\n view.textDirection === Direction.LTR\n ? rect.left\n : rect.right - view.scrollDOM.clientWidth * view.scaleX;\n return {\n left: left - view.scrollDOM.scrollLeft * view.scaleX,\n top: rect.top - view.scrollDOM.scrollTop * view.scaleY,\n };\n}\n\ninterface ContentEdges {\n left: number;\n right: number;\n}\n\n/** The horizontal band text can occupy, in client coordinates. */\nfunction contentEdges(view: EditorView): ContentEdges {\n const rect = view.contentDOM.getBoundingClientRect();\n const line = view.contentDOM.querySelector(\".cm-line\");\n const style = line ? window.getComputedStyle(line) : null;\n const padLeft = style ? parseInt(style.paddingLeft) || 0 : 0;\n const padRight = style ? parseInt(style.paddingRight) || 0 : 0;\n return { left: rect.left + padLeft, right: rect.right - padRight };\n}\n\nfunction isTextBlock(block: BlockInfo): boolean {\n return block.type === BlockType.Text || Array.isArray(block.type);\n}\n\nclass Rect {\n constructor(\n readonly left: number,\n readonly top: number,\n readonly right: number,\n readonly bottom: number,\n ) {}\n}\n\n/**\n * Selection rectangles for one range, clamped to the viewport. Every rect is\n * derived from forward endpoint geometry; positions whose coords are\n * unavailable (jsdom, or an endpoint inside a replaced range) degrade to the\n * enclosing block's box rather than throwing.\n */\nfunction rectsForRange(view: EditorView, range: SelectionRange, edges: ContentEdges): Rect[] {\n if (range.to <= view.viewport.from || range.from >= view.viewport.to) return [];\n const from = Math.max(range.from, view.viewport.from);\n const to = Math.min(range.to, view.viewport.to);\n const startBlock = view.lineBlockAt(from);\n const endBlock = view.lineBlockAt(to);\n const contentTop = view.contentDOM.getBoundingClientRect().top;\n\n // A selection endpoint sitting on a widget block has no glyph coords; its\n // \"row\" is the widget's whole box.\n const startCoords = isTextBlock(startBlock) ? view.coordsAtPos(from, 1) : null;\n const endCoords = isTextBlock(endBlock) ? view.coordsAtPos(to, -1) : null;\n const startTop = startCoords ? startCoords.top : contentTop + startBlock.top;\n const startBottom = startCoords ? startCoords.bottom : contentTop + startBlock.bottom;\n const endTop = endCoords ? endCoords.top : contentTop + endBlock.top;\n const endBottom = endCoords ? endCoords.bottom : contentTop + endBlock.bottom;\n const startLeft = startCoords ? startCoords.left : edges.left;\n const endRight = endCoords ? endCoords.right : edges.right;\n\n // Same visual row: row boxes share their top edge, so the endpoint tops\n // are equal by construction (adjacent rows differ by a full row height).\n if (endTop - startTop < 1) {\n return [new Rect(startLeft, startTop, Math.max(endRight, startLeft), endBottom)];\n }\n\n const rects: Rect[] = [\n // Partial first row: selection start to the row's right edge.\n new Rect(startLeft, startTop, edges.right, startBottom),\n // Everything between the first and last rows — full width. Wrapped rows\n // of the endpoint lines, whole middle lines, and block widgets all fall\n // inside this band, which is what makes the shape probe-free.\n new Rect(edges.left, startBottom, edges.right, endTop),\n // Partial last row: the row's left edge to the selection end.\n new Rect(edges.left, endTop, endRight, endBottom),\n ];\n return rects.filter((r) => r.bottom > r.top || r.right > r.left);\n}\n\nconst selectionLayer = layer({\n above: false,\n class: \"cm-selectionLayer\",\n update: (update) =>\n update.docChanged || update.selectionSet || update.viewportChanged || update.geometryChanged,\n markers(view) {\n const base = layerBase(view);\n const edges = contentEdges(view);\n const markers: RectangleMarker[] = [];\n for (const range of view.state.selection.ranges) {\n if (range.empty) continue;\n for (const rect of rectsForRange(view, range, edges)) {\n markers.push(\n new RectangleMarker(\n \"cm-selectionBackground\",\n rect.left - base.left,\n rect.top - base.top,\n Math.max(0, rect.right - rect.left),\n rect.bottom - rect.top,\n ),\n );\n }\n }\n return markers;\n },\n});\n\n/** Translucent tint ABOVE block widgets wholly covered by a selection — the\n * below-content band is hidden behind their opaque backgrounds. */\nconst widgetTintLayer = layer({\n above: true,\n class: \"cm-selectionWidgetLayer\",\n update: (update) =>\n update.docChanged || update.selectionSet || update.viewportChanged || update.geometryChanged,\n markers(view) {\n const covering = view.state.selection.ranges.filter((r) => !r.empty);\n if (covering.length === 0) return [];\n const base = layerBase(view);\n const edges = contentEdges(view);\n const contentTop = view.contentDOM.getBoundingClientRect().top;\n const markers: RectangleMarker[] = [];\n for (const block of view.viewportLineBlocks) {\n if (isTextBlock(block)) continue;\n if (!covering.some((r) => r.from <= block.from && r.to >= block.to)) continue;\n markers.push(\n new RectangleMarker(\n \"cm-selectionWidgetTint\",\n edges.left - base.left,\n contentTop + block.top - base.top,\n Math.max(0, edges.right - edges.left),\n block.bottom - block.top,\n ),\n );\n }\n return markers;\n },\n});\n\n// The drawn layer replaces the native highlight; the DOM selection itself\n// stays (IME, copy, focus). The tablev2 cell editors are separate\n// contenteditable islands that keep the native paint.\nconst hideNativeSelection = Prec.highest(\n EditorView.theme({\n \".cm-content ::selection, .cm-content::selection\": {\n backgroundColor: \"transparent\",\n },\n '.cm-content [contenteditable=\"plaintext-only\"] ::selection, .cm-content [contenteditable=\"plaintext-only\"]::selection':\n {\n backgroundColor: \"var(--cds-highlight, #d0e2ff)\",\n },\n }),\n);\n\nexport const drawnSelection: Extension = [selectionLayer, widgetTintLayer, hideNativeSelection];\n"],"mappings":";;;AAsCA,SAAS,YAAiD;AAC1D;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAEK;AAGP,SAAS,UAAU,MAAiD;AAClE,QAAM,OAAO,KAAK,UAAU,sBAAsB;AAClD,QAAM,OACJ,KAAK,kBAAkB,UAAU,MAC7B,KAAK,OACL,KAAK,QAAQ,KAAK,UAAU,cAAc,KAAK;AACrD,SAAO;AAAA,IACL,MAAM,OAAO,KAAK,UAAU,aAAa,KAAK;AAAA,IAC9C,KAAK,KAAK,MAAM,KAAK,UAAU,YAAY,KAAK;AAAA,EAClD;AACF;AAQA,SAAS,aAAa,MAAgC;AACpD,QAAM,OAAO,KAAK,WAAW,sBAAsB;AACnD,QAAM,OAAO,KAAK,WAAW,cAAc,UAAU;AACrD,QAAM,QAAQ,OAAO,OAAO,iBAAiB,IAAI,IAAI;AACrD,QAAM,UAAU,QAAQ,SAAS,MAAM,WAAW,KAAK,IAAI;AAC3D,QAAM,WAAW,QAAQ,SAAS,MAAM,YAAY,KAAK,IAAI;AAC7D,SAAO,EAAE,MAAM,KAAK,OAAO,SAAS,OAAO,KAAK,QAAQ,SAAS;AACnE;AAEA,SAAS,YAAY,OAA2B;AAC9C,SAAO,MAAM,SAAS,UAAU,QAAQ,MAAM,QAAQ,MAAM,IAAI;AAClE;AAEA,MAAM,KAAK;AAAA,EACT,YACW,MACA,KACA,OACA,QACT;AAJS;AACA;AACA;AACA;AAAA,EACR;AACL;AAQA,SAAS,cAAc,MAAkB,OAAuB,OAA6B;AAC3F,MAAI,MAAM,MAAM,KAAK,SAAS,QAAQ,MAAM,QAAQ,KAAK,SAAS,GAAI,QAAO,CAAC;AAC9E,QAAM,OAAO,KAAK,IAAI,MAAM,MAAM,KAAK,SAAS,IAAI;AACpD,QAAM,KAAK,KAAK,IAAI,MAAM,IAAI,KAAK,SAAS,EAAE;AAC9C,QAAM,aAAa,KAAK,YAAY,IAAI;AACxC,QAAM,WAAW,KAAK,YAAY,EAAE;AACpC,QAAM,aAAa,KAAK,WAAW,sBAAsB,EAAE;AAI3D,QAAM,cAAc,YAAY,UAAU,IAAI,KAAK,YAAY,MAAM,CAAC,IAAI;AAC1E,QAAM,YAAY,YAAY,QAAQ,IAAI,KAAK,YAAY,IAAI,EAAE,IAAI;AACrE,QAAM,WAAW,cAAc,YAAY,MAAM,aAAa,WAAW;AACzE,QAAM,cAAc,cAAc,YAAY,SAAS,aAAa,WAAW;AAC/E,QAAM,SAAS,YAAY,UAAU,MAAM,aAAa,SAAS;AACjE,QAAM,YAAY,YAAY,UAAU,SAAS,aAAa,SAAS;AACvE,QAAM,YAAY,cAAc,YAAY,OAAO,MAAM;AACzD,QAAM,WAAW,YAAY,UAAU,QAAQ,MAAM;AAIrD,MAAI,SAAS,WAAW,GAAG;AACzB,WAAO,CAAC,IAAI,KAAK,WAAW,UAAU,KAAK,IAAI,UAAU,SAAS,GAAG,SAAS,CAAC;AAAA,EACjF;AAEA,QAAM,QAAgB;AAAA;AAAA,IAEpB,IAAI,KAAK,WAAW,UAAU,MAAM,OAAO,WAAW;AAAA;AAAA;AAAA;AAAA,IAItD,IAAI,KAAK,MAAM,MAAM,aAAa,MAAM,OAAO,MAAM;AAAA;AAAA,IAErD,IAAI,KAAK,MAAM,MAAM,QAAQ,UAAU,SAAS;AAAA,EAClD;AACA,SAAO,MAAM,OAAO,CAAC,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,QAAQ,EAAE,IAAI;AACjE;AAEA,MAAM,iBAAiB,MAAM;AAAA,EAC3B,OAAO;AAAA,EACP,OAAO;AAAA,EACP,QAAQ,CAAC,WACP,OAAO,cAAc,OAAO,gBAAgB,OAAO,mBAAmB,OAAO;AAAA,EAC/E,QAAQ,MAAM;AACZ,UAAM,OAAO,UAAU,IAAI;AAC3B,UAAM,QAAQ,aAAa,IAAI;AAC/B,UAAM,UAA6B,CAAC;AACpC,eAAW,SAAS,KAAK,MAAM,UAAU,QAAQ;AAC/C,UAAI,MAAM,MAAO;AACjB,iBAAW,QAAQ,cAAc,MAAM,OAAO,KAAK,GAAG;AACpD,gBAAQ;AAAA,UACN,IAAI;AAAA,YACF;AAAA,YACA,KAAK,OAAO,KAAK;AAAA,YACjB,KAAK,MAAM,KAAK;AAAA,YAChB,KAAK,IAAI,GAAG,KAAK,QAAQ,KAAK,IAAI;AAAA,YAClC,KAAK,SAAS,KAAK;AAAA,UACrB;AAAA,QACF;AAAA,MACF;AAAA,IACF;AACA,WAAO;AAAA,EACT;AACF,CAAC;AAID,MAAM,kBAAkB,MAAM;AAAA,EAC5B,OAAO;AAAA,EACP,OAAO;AAAA,EACP,QAAQ,CAAC,WACP,OAAO,cAAc,OAAO,gBAAgB,OAAO,mBAAmB,OAAO;AAAA,EAC/E,QAAQ,MAAM;AACZ,UAAM,WAAW,KAAK,MAAM,UAAU,OAAO,OAAO,CAAC,MAAM,CAAC,EAAE,KAAK;AACnE,QAAI,SAAS,WAAW,EAAG,QAAO,CAAC;AACnC,UAAM,OAAO,UAAU,IAAI;AAC3B,UAAM,QAAQ,aAAa,IAAI;AAC/B,UAAM,aAAa,KAAK,WAAW,sBAAsB,EAAE;AAC3D,UAAM,UAA6B,CAAC;AACpC,eAAW,SAAS,KAAK,oBAAoB;AAC3C,UAAI,YAAY,KAAK,EAAG;AACxB,UAAI,CAAC,SAAS,KAAK,CAAC,MAAM,EAAE,QAAQ,MAAM,QAAQ,EAAE,MAAM,MAAM,EAAE,EAAG;AACrE,cAAQ;AAAA,QACN,IAAI;AAAA,UACF;AAAA,UACA,MAAM,OAAO,KAAK;AAAA,UAClB,aAAa,MAAM,MAAM,KAAK;AAAA,UAC9B,KAAK,IAAI,GAAG,MAAM,QAAQ,MAAM,IAAI;AAAA,UACpC,MAAM,SAAS,MAAM;AAAA,QACvB;AAAA,MACF;AAAA,IACF;AACA,WAAO;AAAA,EACT;AACF,CAAC;AAKD,MAAM,sBAAsB,KAAK;AAAA,EAC/B,WAAW,MAAM;AAAA,IACf,mDAAmD;AAAA,MACjD,iBAAiB;AAAA,IACnB;AAAA,IACA,yHACE;AAAA,MACE,iBAAiB;AAAA,IACnB;AAAA,EACJ,CAAC;AACH;AAEO,MAAM,iBAA4B,CAAC,gBAAgB,iBAAiB,mBAAmB;","names":[]}
1
+ {"version":3,"sources":["../../src/codemirror/selectionLayer.ts"],"sourcesContent":["/**\n * Drawn selection over a virtualized viewport (#166).\n *\n * CodeMirror renders only the visible viewport, and the browser's native\n * `::selection` can only highlight DOM that exists — so with native painting,\n * a Cmd+A or Shift-extended selection shows highlight only on whatever\n * happened to be rendered, and scrolling away and back loses it entirely.\n * This layer paints selection ranges FROM LOGICAL STATE\n * (`state.selection` × the current viewport), so the highlight is correct at\n * every scroll position by construction.\n *\n * Why not CM6's own `drawSelection()`: its wrapped-line handling reverse-maps\n * the editor's far-left/right edge through `posAtCoords` per endpoint, and on\n * lines that start with hidden markers + widgets that probe jitters between\n * before/after the hidden prefix, flashing between one-piece and three-piece\n * painting per drag update (#90). The rects here derive only from FORWARD\n * geometry — `coordsAtPos` of the actual endpoints plus line-block boxes —\n * with no reverse edge probe anywhere:\n *\n * * endpoints in the same visual row → one rect between their coords;\n * * a wrapped or multi-line range → a partial rect for the first row, a\n * partial rect for the last row, and ONE full-width rect for everything\n * between (which also spans block widgets and hidden rows);\n * * a block widget wholly inside a range additionally gets a translucent\n * ABOVE-content tint (`cm-selectionWidgetTint`): widgets paint opaque\n * backgrounds over a below-content layer, so without it a selected\n * table/diagram would show no feedback at all.\n *\n * Known coarseness: partial rows of RTL text paint full-width (bidi span\n * splitting is deliberately not reimplemented here); LTR documents paint\n * glyph-accurately.\n *\n * The native `::selection` stays for the tablev2 cell editors (their own\n * contenteditable islands) and is made transparent everywhere else — the DOM\n * selection itself is untouched, so IME, copy, and focus behavior keep\n * working on the real selection.\n */\n\nimport { Prec, type Extension, type SelectionRange } from \"@codemirror/state\";\nimport {\n BlockType,\n Direction,\n EditorView,\n layer,\n RectangleMarker,\n type BlockInfo,\n} from \"@codemirror/view\";\n\n/** Client-rect → document-space base, mirroring CM6's own layer arithmetic. */\nfunction layerBase(view: EditorView): { left: number; top: number } {\n const rect = view.scrollDOM.getBoundingClientRect();\n const left =\n view.textDirection === Direction.LTR\n ? rect.left\n : rect.right - view.scrollDOM.clientWidth * view.scaleX;\n return {\n left: left - view.scrollDOM.scrollLeft * view.scaleX,\n top: rect.top - view.scrollDOM.scrollTop * view.scaleY,\n };\n}\n\ninterface ContentEdges {\n left: number;\n right: number;\n}\n\n/** The horizontal band text can occupy, in client coordinates. */\nfunction contentEdges(view: EditorView): ContentEdges {\n const rect = view.contentDOM.getBoundingClientRect();\n const line = view.contentDOM.querySelector(\".cm-line\");\n const style = line ? window.getComputedStyle(line) : null;\n const padLeft = style ? parseInt(style.paddingLeft) || 0 : 0;\n const padRight = style ? parseInt(style.paddingRight) || 0 : 0;\n return { left: rect.left + padLeft, right: rect.right - padRight };\n}\n\nfunction isTextBlock(block: BlockInfo): boolean {\n return block.type === BlockType.Text || Array.isArray(block.type);\n}\n\nclass Rect {\n constructor(\n readonly left: number,\n readonly top: number,\n readonly right: number,\n readonly bottom: number,\n ) {}\n}\n\n/**\n * Selection rectangles for one range, clamped to the viewport. Every rect is\n * derived from forward endpoint geometry; positions whose coords are\n * unavailable (jsdom, or an endpoint inside a replaced range) degrade to the\n * enclosing block's box rather than throwing.\n */\nfunction rectsForRange(view: EditorView, range: SelectionRange, edges: ContentEdges): Rect[] {\n if (range.to <= view.viewport.from || range.from >= view.viewport.to) return [];\n const from = Math.max(range.from, view.viewport.from);\n const to = Math.min(range.to, view.viewport.to);\n const startBlock = view.lineBlockAt(from);\n const endBlock = view.lineBlockAt(to);\n const contentTop = view.contentDOM.getBoundingClientRect().top;\n\n // A selection endpoint sitting on a widget block has no glyph coords; its\n // \"row\" is the widget's whole box.\n const startCoords = isTextBlock(startBlock) ? view.coordsAtPos(from, 1) : null;\n const endCoords = isTextBlock(endBlock) ? view.coordsAtPos(to, -1) : null;\n const startTop = startCoords ? startCoords.top : contentTop + startBlock.top;\n const startBottom = startCoords ? startCoords.bottom : contentTop + startBlock.bottom;\n const endTop = endCoords ? endCoords.top : contentTop + endBlock.top;\n const endBottom = endCoords ? endCoords.bottom : contentTop + endBlock.bottom;\n const startLeft = startCoords ? startCoords.left : edges.left;\n const endRight = endCoords ? endCoords.right : edges.right;\n\n // Same visual row: row boxes share their top edge, so the endpoint tops\n // are equal by construction (adjacent rows differ by a full row height).\n if (endTop - startTop < 1) {\n return [new Rect(startLeft, startTop, Math.max(endRight, startLeft), endBottom)];\n }\n\n const rects: Rect[] = [\n // Partial first row: selection start to the row's right edge.\n new Rect(startLeft, startTop, edges.right, startBottom),\n // Everything between the first and last rows — full width. Wrapped rows\n // of the endpoint lines, whole middle lines, and block widgets all fall\n // inside this band, which is what makes the shape probe-free.\n new Rect(edges.left, startBottom, edges.right, endTop),\n // Partial last row: the row's left edge to the selection end.\n new Rect(edges.left, endTop, endRight, endBottom),\n ];\n return rects.filter((r) => r.bottom > r.top || r.right > r.left);\n}\n\nconst selectionLayer = layer({\n above: false,\n class: \"cm-selectionLayer\",\n update: (update) =>\n update.docChanged || update.selectionSet || update.viewportChanged || update.geometryChanged,\n markers(view) {\n const base = layerBase(view);\n const edges = contentEdges(view);\n const markers: RectangleMarker[] = [];\n for (const range of view.state.selection.ranges) {\n if (range.empty) continue;\n for (const rect of rectsForRange(view, range, edges)) {\n markers.push(\n new RectangleMarker(\n \"cm-selectionBackground\",\n rect.left - base.left,\n rect.top - base.top,\n Math.max(0, rect.right - rect.left),\n rect.bottom - rect.top,\n ),\n );\n }\n }\n return markers;\n },\n});\n\n/** Translucent tint ABOVE block widgets wholly covered by a selection — the\n * below-content band is hidden behind their opaque backgrounds. */\nconst widgetTintLayer = layer({\n above: true,\n class: \"cm-selectionWidgetLayer\",\n update: (update) =>\n update.docChanged || update.selectionSet || update.viewportChanged || update.geometryChanged,\n markers(view) {\n const covering = view.state.selection.ranges.filter((r) => !r.empty);\n if (covering.length === 0) return [];\n const base = layerBase(view);\n const edges = contentEdges(view);\n const contentTop = view.contentDOM.getBoundingClientRect().top;\n const markers: RectangleMarker[] = [];\n for (const block of view.viewportLineBlocks) {\n if (isTextBlock(block)) continue;\n if (!covering.some((r) => r.from <= block.from && r.to >= block.to)) continue;\n markers.push(\n new RectangleMarker(\n \"cm-selectionWidgetTint\",\n edges.left - base.left,\n contentTop + block.top - base.top,\n Math.max(0, edges.right - edges.left),\n block.bottom - block.top,\n ),\n );\n }\n return markers;\n },\n});\n\n// The drawn layer replaces the native highlight; the DOM selection itself\n// stays (IME, copy, focus). The tablev2 cell editors are separate\n// contenteditable islands that keep the native paint.\nconst hideNativeSelection = Prec.highest(\n EditorView.theme({\n \".cm-content ::selection, .cm-content::selection\": {\n backgroundColor: \"transparent\",\n },\n '.cm-content [contenteditable=\"plaintext-only\"] ::selection, .cm-content [contenteditable=\"plaintext-only\"]::selection':\n {\n backgroundColor: \"var(--cds-highlight, #d0e2ff)\",\n },\n }),\n);\n\n/**\n * The host's highlight token, stated at CodeMirror's own specificity.\n *\n * CM's base theme carries\n * `&light.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground`\n * — far more specific than a plain `.cm-selectionBackground` — and this editor\n * is themed through CSS custom properties rather than registered as\n * `{ dark: true }`, so CM believes it is always `&light` and paints its own\n * `#d7d4f0` over the token. On a dark host that is light-on-light: the selected\n * text becomes the least readable text on screen.\n *\n * The same trap the caret hit (see `editorTheme.ts`), in the one place where\n * getting it wrong hides what the reader just selected. Both focused and\n * unfocused are stated, because CM has a rule for each.\n */\nconst selectionColor = Prec.highest(\n EditorView.theme({\n \"&.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground\": {\n background: \"var(--cds-highlight, #d0e2ff)\",\n },\n \"&:not(.cm-focused) > .cm-scroller > .cm-selectionLayer .cm-selectionBackground\": {\n background: \"var(--cds-layer-accent-01, #e0e0e0)\",\n },\n }),\n);\n\nexport const drawnSelection: Extension = [\n selectionLayer,\n widgetTintLayer,\n hideNativeSelection,\n selectionColor,\n];\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@latentic/live-markdown",
3
- "version": "0.4.1",
3
+ "version": "0.4.2",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "description": "WYSIWYG markdown editor for React, built on CodeMirror 6. Headings, tables, LaTeX math and Mermaid diagrams render inline as you type \u2014 no preview pane and no AST: value in and onChange out is the same markdown string, frontmatter included.",