@damiro/stylo 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +144 -0
- package/dist/InPlaceView-Ba7JCZ2Y.js +2346 -0
- package/dist/InPlaceView-Ba7JCZ2Y.js.map +1 -0
- package/dist/Preview-Dxb9zPVv.js +93 -0
- package/dist/Preview-Dxb9zPVv.js.map +1 -0
- package/dist/SplitView.d.ts +23 -0
- package/dist/SplitView.d.ts.map +1 -0
- package/dist/Stylo.d.ts +15 -0
- package/dist/Stylo.d.ts.map +1 -0
- package/dist/callout-oLE630ZP.js +37 -0
- package/dist/callout-oLE630ZP.js.map +1 -0
- package/dist/callout.d.ts +18 -0
- package/dist/callout.d.ts.map +1 -0
- package/dist/config-DTBxVhtH.js +101 -0
- package/dist/config-DTBxVhtH.js.map +1 -0
- package/dist/editor/SourceView.d.ts +17 -0
- package/dist/editor/SourceView.d.ts.map +1 -0
- package/dist/editor/extensions.d.ts +20 -0
- package/dist/editor/extensions.d.ts.map +1 -0
- package/dist/editor/highlight.d.ts +19 -0
- package/dist/editor/highlight.d.ts.map +1 -0
- package/dist/editor/save.d.ts +12 -0
- package/dist/editor/save.d.ts.map +1 -0
- package/dist/editor/theme.d.ts +3 -0
- package/dist/editor/theme.d.ts.map +1 -0
- package/dist/editor/useCodeMirror.d.ts +26 -0
- package/dist/editor/useCodeMirror.d.ts.map +1 -0
- package/dist/frontmatter.d.ts +21 -0
- package/dist/frontmatter.d.ts.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/inplace/InPlaceView.d.ts +30 -0
- package/dist/inplace/InPlaceView.d.ts.map +1 -0
- package/dist/inplace/autoformat.d.ts +23 -0
- package/dist/inplace/autoformat.d.ts.map +1 -0
- package/dist/inplace/config.d.ts +57 -0
- package/dist/inplace/config.d.ts.map +1 -0
- package/dist/inplace/context-menu-actions.d.ts +53 -0
- package/dist/inplace/context-menu-actions.d.ts.map +1 -0
- package/dist/inplace/context-menu.d.ts +50 -0
- package/dist/inplace/context-menu.d.ts.map +1 -0
- package/dist/inplace/decorate.d.ts +17 -0
- package/dist/inplace/decorate.d.ts.map +1 -0
- package/dist/inplace/edit-boundaries.d.ts +59 -0
- package/dist/inplace/edit-boundaries.d.ts.map +1 -0
- package/dist/inplace/edit-insert-assoc.d.ts +17 -0
- package/dist/inplace/edit-insert-assoc.d.ts.map +1 -0
- package/dist/inplace/edit-line-prefix.d.ts +23 -0
- package/dist/inplace/edit-line-prefix.d.ts.map +1 -0
- package/dist/inplace/extension.d.ts +21 -0
- package/dist/inplace/extension.d.ts.map +1 -0
- package/dist/inplace/frontmatter.d.ts +13 -0
- package/dist/inplace/frontmatter.d.ts.map +1 -0
- package/dist/inplace/inline-md.d.ts +13 -0
- package/dist/inplace/inline-md.d.ts.map +1 -0
- package/dist/inplace/lazyInPlace.d.ts +7 -0
- package/dist/inplace/lazyInPlace.d.ts.map +1 -0
- package/dist/inplace/link-click.d.ts +24 -0
- package/dist/inplace/link-click.d.ts.map +1 -0
- package/dist/inplace/link-hover.d.ts +11 -0
- package/dist/inplace/link-hover.d.ts.map +1 -0
- package/dist/inplace/list-guides.d.ts +16 -0
- package/dist/inplace/list-guides.d.ts.map +1 -0
- package/dist/inplace/long-press.d.ts +39 -0
- package/dist/inplace/long-press.d.ts.map +1 -0
- package/dist/inplace/math.d.ts +16 -0
- package/dist/inplace/math.d.ts.map +1 -0
- package/dist/inplace/menu-plugin.d.ts +30 -0
- package/dist/inplace/menu-plugin.d.ts.map +1 -0
- package/dist/inplace/nodes.d.ts +24 -0
- package/dist/inplace/nodes.d.ts.map +1 -0
- package/dist/inplace/plugin.d.ts +21 -0
- package/dist/inplace/plugin.d.ts.map +1 -0
- package/dist/inplace/reveal.d.ts +8 -0
- package/dist/inplace/reveal.d.ts.map +1 -0
- package/dist/inplace/scan.d.ts +11 -0
- package/dist/inplace/scan.d.ts.map +1 -0
- package/dist/inplace/selection-bar.d.ts +38 -0
- package/dist/inplace/selection-bar.d.ts.map +1 -0
- package/dist/inplace/table-cell-dom.d.ts +30 -0
- package/dist/inplace/table-cell-dom.d.ts.map +1 -0
- package/dist/inplace/table-enter.d.ts +22 -0
- package/dist/inplace/table-enter.d.ts.map +1 -0
- package/dist/inplace/table-gizmos.d.ts +55 -0
- package/dist/inplace/table-gizmos.d.ts.map +1 -0
- package/dist/inplace/table-structure.d.ts +23 -0
- package/dist/inplace/table-structure.d.ts.map +1 -0
- package/dist/inplace/table-widget.d.ts +81 -0
- package/dist/inplace/table-widget.d.ts.map +1 -0
- package/dist/inplace/tables.d.ts +8 -0
- package/dist/inplace/tables.d.ts.map +1 -0
- package/dist/inplace/theme.d.ts +14 -0
- package/dist/inplace/theme.d.ts.map +1 -0
- package/dist/inplace/widgets.d.ts +25 -0
- package/dist/inplace/widgets.d.ts.map +1 -0
- package/dist/inplace/wikilinks.d.ts +10 -0
- package/dist/inplace/wikilinks.d.ts.map +1 -0
- package/dist/katex-BfiLlqfN.js +21979 -0
- package/dist/katex-BfiLlqfN.js.map +1 -0
- package/dist/katex.css +3 -0
- package/dist/markdown-N3lRmU2n.js +8524 -0
- package/dist/markdown-N3lRmU2n.js.map +1 -0
- package/dist/render/Preview.d.ts +10 -0
- package/dist/render/Preview.d.ts.map +1 -0
- package/dist/render/lazyPreview.d.ts +8 -0
- package/dist/render/lazyPreview.d.ts.map +1 -0
- package/dist/render/remark-callout.d.ts +10 -0
- package/dist/render/remark-callout.d.ts.map +1 -0
- package/dist/render/remark-wikilink.d.ts +8 -0
- package/dist/render/remark-wikilink.d.ts.map +1 -0
- package/dist/styles.css +2 -0
- package/dist/stylo.js +293 -0
- package/dist/stylo.js.map +1 -0
- package/dist/toolbar/Toolbar.d.ts +28 -0
- package/dist/toolbar/Toolbar.d.ts.map +1 -0
- package/dist/toolbar/block.d.ts +56 -0
- package/dist/toolbar/block.d.ts.map +1 -0
- package/dist/toolbar/cell-inline.d.ts +16 -0
- package/dist/toolbar/cell-inline.d.ts.map +1 -0
- package/dist/toolbar/commands.d.ts +25 -0
- package/dist/toolbar/commands.d.ts.map +1 -0
- package/dist/toolbar/config.d.ts +21 -0
- package/dist/toolbar/config.d.ts.map +1 -0
- package/dist/toolbar/fence.d.ts +28 -0
- package/dist/toolbar/fence.d.ts.map +1 -0
- package/dist/toolbar/floating-watchdog.d.ts +18 -0
- package/dist/toolbar/floating-watchdog.d.ts.map +1 -0
- package/dist/toolbar/icon-paths.d.ts +10 -0
- package/dist/toolbar/icon-paths.d.ts.map +1 -0
- package/dist/toolbar/icons.d.ts +10 -0
- package/dist/toolbar/icons.d.ts.map +1 -0
- package/dist/toolbar/inline-ops.d.ts +101 -0
- package/dist/toolbar/inline-ops.d.ts.map +1 -0
- package/dist/toolbar/inline.d.ts +38 -0
- package/dist/toolbar/inline.d.ts.map +1 -0
- package/dist/toolbar/keyboard-inset.d.ts +10 -0
- package/dist/toolbar/keyboard-inset.d.ts.map +1 -0
- package/dist/toolbar/keymap.d.ts +8 -0
- package/dist/toolbar/keymap.d.ts.map +1 -0
- package/dist/toolbar/labels.d.ts +16 -0
- package/dist/toolbar/labels.d.ts.map +1 -0
- package/dist/toolbar/table-grid.d.ts +23 -0
- package/dist/toolbar/table-grid.d.ts.map +1 -0
- package/dist/toolbar/table.d.ts +35 -0
- package/dist/toolbar/table.d.ts.map +1 -0
- package/dist/toolbar-settings/SortableRow.d.ts +15 -0
- package/dist/toolbar-settings/SortableRow.d.ts.map +1 -0
- package/dist/toolbar-settings/StyloToolbarSettings.d.ts +29 -0
- package/dist/toolbar-settings/StyloToolbarSettings.d.ts.map +1 -0
- package/dist/toolbar-settings/index.d.ts +3 -0
- package/dist/toolbar-settings/index.d.ts.map +1 -0
- package/dist/toolbar-settings/items.d.ts +24 -0
- package/dist/toolbar-settings/items.d.ts.map +1 -0
- package/dist/toolbar-settings.js +269 -0
- package/dist/toolbar-settings.js.map +1 -0
- package/dist/types.d.ts +264 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/useCodeMirror-YnIFkvKn.js +1361 -0
- package/dist/useCodeMirror-YnIFkvKn.js.map +1 -0
- package/dist/wikilink-BFpTehto.js +42 -0
- package/dist/wikilink-BFpTehto.js.map +1 -0
- package/dist/wikilink.d.ts +11 -0
- package/dist/wikilink.d.ts.map +1 -0
- package/package.json +122 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useCodeMirror-YnIFkvKn.js","names":[],"sources":["../src/editor/save.ts","../src/toolbar/block.ts","../src/toolbar/inline-ops.ts","../src/inplace/table-cell-dom.ts","../src/toolbar/cell-inline.ts","../src/toolbar/fence.ts","../src/toolbar/inline.ts","../src/toolbar/table-grid.ts","../src/toolbar/table.ts","../src/toolbar/commands.ts","../src/toolbar/keymap.ts","../src/editor/highlight.ts","../src/editor/theme.ts","../src/editor/extensions.ts","../src/editor/useCodeMirror.ts"],"sourcesContent":["import { Facet } from \"@codemirror/state\"\nimport type { EditorView } from \"@codemirror/view\"\n\n/**\n * The consumer's `onSave` handler, surfaced into editor state so the `Mod-s`\n * keymap and the toolbar's `save` command share one path. Absent when no\n * `onSave` prop is set — the `save` button then renders disabled and `Mod-s`\n * falls through to the browser.\n */\nexport const saveHandler = Facet.define<(value: string) => void, ((value: string) => void) | null>({\n combine: (values) => values[0] ?? null,\n})\n\n/** Run the registered save handler with the current document. `false` if none. */\nexport function runSave(view: EditorView): boolean {\n const handler = view.state.facet(saveHandler)\n if (!handler) return false\n handler(view.state.doc.toString())\n return true\n}\n","import type { EditorState } from \"@codemirror/state\"\nimport { EditorSelection } from \"@codemirror/state\"\nimport type { EditorView } from \"@codemirror/view\"\nimport { frontmatterRange } from \"../frontmatter\"\n\n/** The 1-based line numbers the primary selection touches. */\nexport function selectedLines(state: EditorState): [number, number] {\n const { from, to } = state.selection.main\n return [state.doc.lineAt(from).number, state.doc.lineAt(to).number]\n}\n\n/**\n * Set, swap, or clear an ATX heading prefix on every line the selection touches.\n * A line already at `level` is cleared; any other level (or none) is set to it.\n */\nexport function toggleHeading(view: EditorView, level: number): boolean {\n const prefix = \"#\".repeat(level) + \" \"\n const s = view.state\n const [first, last] = selectedLines(s)\n const changes = []\n for (let n = first; n <= last; n++) {\n const line = s.doc.line(n)\n const m = /^(#{1,6}) +/.exec(line.text)\n if (m && m[1]!.length === level) {\n changes.push({ from: line.from, to: line.from + m[0].length })\n } else if (m) {\n changes.push({ from: line.from, to: line.from + m[0].length, insert: prefix })\n } else {\n changes.push({ from: line.from, insert: prefix })\n }\n }\n view.dispatch({ changes, scrollIntoView: true })\n view.focus()\n return true\n}\n\n/** Strip any ATX heading prefix from every line the selection touches — the\n * explicit \"back to body text\" that toggling a heading level does obliquely. */\nexport function clearHeading(view: EditorView): boolean {\n const s = view.state\n const [first, last] = selectedLines(s)\n const changes = []\n for (let n = first; n <= last; n++) {\n const line = s.doc.line(n)\n const m = /^#{1,6} +/.exec(line.text)\n if (m) changes.push({ from: line.from, to: line.from + m[0].length })\n }\n if (!changes.length) return false\n view.dispatch({ changes, scrollIntoView: true })\n view.focus()\n return true\n}\n\nexport interface LinePrefixSpec {\n /** Detects this exact prefix; `match[0]` (from line start) is what gets stripped. */\n match: RegExp\n /**\n * Inserted after any indent when the prefix is absent. A function receives the\n * 0-based position among the lines being prefixed — used to number an ordered\n * list `1.`, `2.`, `3.` rather than stamping `1.` on every line.\n */\n insert: string | ((n: number) => string)\n /**\n * When set, an existing *sibling* prefix matched here (another list marker) is\n * overwritten rather than stacked, so the list buttons stay mutually\n * exclusive. `siblings[1]` is the indent, `siblings[0]` the marker to replace.\n */\n siblings?: RegExp\n}\n\n/**\n * Toggle a Markdown line prefix (`> `, `- `, `1. `, `- [ ] `) over the selected\n * lines. If every non-blank line already carries it the block is stripped;\n * otherwise it is added to the lines that lack it — replacing a sibling list\n * marker in place when `spec.siblings` says to.\n */\nexport function toggleLinePrefix(view: EditorView, spec: LinePrefixSpec): boolean {\n const s = view.state\n const [first, last] = selectedLines(s)\n // A lone blank line: start the list / quote on it rather than skipping it.\n const soleBlank = first === last && !s.doc.line(first).text.trim()\n let allHave = !soleBlank\n for (let n = first; n <= last && allHave; n++) {\n const t = s.doc.line(n).text\n if (t.trim() && !spec.match.test(t)) allHave = false\n }\n const changes = []\n let added = 0\n for (let n = first; n <= last; n++) {\n const line = s.doc.line(n)\n if (!line.text.trim() && !soleBlank) continue\n const m = spec.match.exec(line.text)\n if (allHave) {\n if (m) changes.push({ from: line.from, to: line.from + m[0].length })\n continue\n }\n if (m) continue // mixed selection — this line already has the target prefix\n const prefix = typeof spec.insert === \"function\" ? spec.insert(added++) : spec.insert\n const sib = spec.siblings?.exec(line.text)\n if (sib) {\n changes.push({\n from: line.from + (sib[1] ?? \"\").length,\n to: line.from + sib[0].length,\n insert: prefix,\n })\n } else {\n const indent = /^\\s*/.exec(line.text)![0].length\n changes.push({ from: line.from + indent, insert: prefix })\n }\n }\n if (!changes.length) return false\n view.dispatch({ changes, scrollIntoView: true })\n view.focus()\n return true\n}\n\n/** True when the primary caret's line carries the prefix. */\nexport function linePrefixActive(state: EditorState, match: RegExp): boolean {\n return match.test(state.doc.lineAt(state.selection.main.head).text)\n}\n\n/** A CommonMark thematic break: three or more `-`, `*`, or `_`, spaces allowed. */\nconst THEMATIC_BREAK = /^ {0,3}([-*_])[ \\t]*(?:\\1[ \\t]*){2,}$/\n\n/**\n * Insert a `---` thematic break, or remove the one the caret is on. A blank line\n * is inserted before the rule when the current line has content — otherwise\n * CommonMark reads `text` + `---` as a setext H2, not a divider.\n */\nexport function toggleHorizontalRule(view: EditorView): boolean {\n const s = view.state\n const line = s.doc.lineAt(s.selection.main.head)\n\n if (THEMATIC_BREAK.test(line.text)) {\n view.dispatch({\n changes: { from: line.from, to: Math.min(line.to + 1, s.doc.length) },\n scrollIntoView: true,\n })\n } else if (line.text.trim() === \"\") {\n view.dispatch({\n changes: { from: line.from, to: line.to, insert: \"---\" },\n selection: EditorSelection.cursor(line.from + 3),\n scrollIntoView: true,\n })\n } else {\n const insert = \"\\n\\n---\\n\"\n view.dispatch({\n changes: { from: line.to, insert },\n selection: EditorSelection.cursor(line.to + insert.length),\n scrollIntoView: true,\n })\n }\n view.focus()\n return true\n}\n\n/** True when the primary caret's line is a thematic break. */\nexport function horizontalRuleActive(state: EditorState): boolean {\n return THEMATIC_BREAK.test(state.doc.lineAt(state.selection.main.head).text)\n}\n\n/**\n * Toggle the leading `---` YAML block. With none present, the top of the\n * document — line 1 through the last selected line — is wrapped in `---` fences\n * (so the \"type it, select it, click\" flow works). With one present, only the\n * two fence lines are removed; the YAML text stays in the document. Keeping it\n * out of rendered output is the preview pipeline's job, not this toggle's.\n */\nexport function toggleFrontmatter(view: EditorView): boolean {\n const s = view.state\n const range = frontmatterRange(s.doc)\n\n if (range) {\n const open = s.doc.lineAt(range.from)\n const close = s.doc.lineAt(range.to)\n view.dispatch({\n changes: [\n { from: open.from, to: Math.min(open.to + 1, s.doc.length) },\n { from: close.from, to: Math.min(close.to + 1, s.doc.length) },\n ],\n scrollIntoView: true,\n })\n } else {\n const lastLine = s.doc.lineAt(s.selection.main.to).number\n view.dispatch({\n changes: [\n { from: 0, insert: \"---\\n\" },\n { from: s.doc.line(lastLine).to, insert: \"\\n---\" },\n ],\n selection: EditorSelection.cursor(4), // first line inside the block\n scrollIntoView: true,\n })\n }\n view.focus()\n return true\n}\n\n/** True when the document has a leading `---` YAML block. */\nexport function frontmatterActive(state: EditorState): boolean {\n return frontmatterRange(state.doc) !== null\n}\n","import { WIKILINK_PATTERN } from \"../wikilink\"\n\n/** Regex-escape a literal so it can be spliced into a pattern. */\nexport function esc(s: string): string {\n return s.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\")\n}\n\n/** The characters that can stack as inline marks around a span. */\nexport const MARK_CHARS = \"*~`$\"\n\n/** The maximal run of {@link MARK_CHARS} touching `pos` on the given side of `s`. */\nfunction markRun(s: string, pos: number, dir: -1 | 1): { text: string; from: number } {\n let from = pos\n let to = pos\n if (dir < 0) while (from > 0 && MARK_CHARS.includes(s[from - 1]!)) from--\n else while (to < s.length && MARK_CHARS.includes(s[to]!)) to++\n return { text: s.slice(from, dir < 0 ? pos : to), from }\n}\n\n/** Every run of `ch` inside a mark run, in index order. */\nfunction charGroups(run: string, ch: string): { start: number; len: number }[] {\n const out: { start: number; len: number }[] = []\n for (let i = 0; i < run.length;) {\n if (run[i] !== ch) {\n i++\n continue\n }\n let len = 0\n while (run[i + len] === ch) len++\n out.push({ start: i, len })\n i += len\n }\n return out\n}\n\n/**\n * Do `before` / `after` counts of the mark character flanking a range represent\n * an instance of exactly `mark` to strip? A `**`/`~~` needs at least its length;\n * a single `*` needs an *odd* count — so `*x*` and `***x***` unwrap the italic,\n * but `**x**` keeps the bold and the italic nests instead.\n */\nfunction surroundsExactly(before: number, after: number, m: number): boolean {\n if (before < m || after < m) return false\n return m > 1 || (before % 2 === 1 && after % 2 === 1)\n}\n\n/** Non-overlapping edits plus the selection (post-edit coordinates) to follow. */\nexport interface InlineOp {\n changes: { from: number; to: number; insert: string }[]\n from: number\n to: number\n}\n\n/** A rewritten string plus the selection that should follow it. */\nexport interface InlineStr {\n text: string\n from: number\n to: number\n}\n\n/**\n * Toggle an inline wrapping mark (`**`, `*`, `~~`, `` ` ``, `$`) around `[from,\n * to)` of `text`: unwrap a span already wrapped (marks inside or just around the\n * selection), else wrap it; an empty range gets an empty pair. Applying `*` to\n * `**bold**` (or `**` to `*em*`) nests rather than eating a marker.\n */\nexport function wrapOp(text: string, from: number, to: number, mark: string): InlineOp {\n const m = mark.length\n const ch = mark[0]!\n const inner = text.slice(from, to)\n\n // The selection covers the marks: `**bold**` is selected.\n let lead = 0\n while (inner[lead] === ch) lead++\n let tail = 0\n while (inner[inner.length - 1 - tail] === ch) tail++\n if (\n inner.length >= 2 * m &&\n inner.startsWith(mark) &&\n inner.endsWith(mark) &&\n surroundsExactly(lead, tail, m)\n ) {\n return {\n changes: [\n { from, to: from + m, insert: \"\" },\n { from: to - m, to, insert: \"\" },\n ],\n from,\n to: to - 2 * m,\n }\n }\n\n // `mark` is somewhere in the stack of marks flanking the range — possibly with\n // other marks (`~~`, `*`) between it and the text, as in `***~~word~~***` or,\n // when marks were applied in an interleaving order, `**~~*word*~~**`. Line the\n // `ch`-groups up outermost-first on both sides (the left run reads outer→inner\n // already; the right run reads inner→outer, so reverse it) and strip the\n // outermost pair whose widths match `mark`.\n const left = markRun(text, from, -1)\n const right = markRun(text, to, 1)\n const lgs = charGroups(left.text, ch)\n const rgs = charGroups(right.text, ch).reverse()\n for (let k = 0; k < Math.min(lgs.length, rgs.length); k++) {\n const lg = lgs[k]!\n const rg = rgs[k]!\n if (!surroundsExactly(lg.len, rg.len, m)) continue\n const lInner = left.from + lg.start + lg.len // group's edge nearest the text\n const rInner = to + rg.start\n return {\n changes: [\n { from: lInner - m, to: lInner, insert: \"\" },\n { from: rInner, to: rInner + m, insert: \"\" },\n ],\n from: from - m,\n to: to - m,\n }\n }\n\n // Otherwise wrap.\n return {\n changes: [\n { from, to: from, insert: mark },\n { from: to, to: to, insert: mark },\n ],\n from: from + m,\n to: to + m,\n }\n}\n\n/** Apply non-overlapping {@link InlineOp} changes to a string (right to left). */\nexport function applyChanges(\n text: string,\n changes: { from: number; to: number; insert: string }[],\n): string {\n let out = text\n for (const c of [...changes].sort((a, b) => b.from - a.from)) {\n out = out.slice(0, c.from) + c.insert + out.slice(c.to)\n }\n return out\n}\n\n/** {@link wrapOp} resolved against a plain string — for editing one table cell. */\nexport function wrapString(text: string, from: number, to: number, mark: string): InlineStr {\n const op = wrapOp(text, from, to, mark)\n return { text: applyChanges(text, op.changes), from: op.from, to: op.to }\n}\n\n/**\n * The span a right-click in a table cell should select so a Format toggle lands\n * cleanly: the text between the delimiters for an inline mark run\n * (`**bold phrase**`, `*em*`, `~~strike~~`, `` `code` ``), but the *whole*\n * construct for a `[label](url)` link or `[[target|label]]` wikilink — its label\n * is not a Markdown context, so Bold must wrap the link, not sit inside it.\n * Returns `null` when `pos` is not in any run. Mirrors `wrapAt` on the canvas.\n */\nexport function markedContentAt(text: string, pos: number): { from: number; to: number } | null {\n const link = linkAtIn(text, pos)\n if (link) return { from: link.from, to: link.to }\n const wiki = wikiLinkPartsIn(text, pos)\n if (wiki) return { from: wiki.from, to: wiki.to }\n let best: { from: number; to: number } | null = null\n for (const mark of [\"**\", \"~~\", \"*\", \"`\"]) {\n const re = new RegExp(esc(mark) + \"(?!\\\\s)(?:[^]*?\\\\S)??\" + esc(mark), \"g\")\n for (let m: RegExpExecArray | null; (m = re.exec(text));) {\n if (m[0].length <= 2 * mark.length) continue\n const from = m.index + mark.length\n const to = m.index + m[0].length - mark.length\n if (pos >= from && pos <= to && (!best || to - from < best.to - best.from)) {\n best = { from, to }\n }\n }\n }\n return best\n}\n\n/** The `[text](url)` span of `text` covering `head`, or `null`. */\nexport function linkAtIn(\n text: string,\n head: number,\n): { from: number; to: number; label: string } | null {\n const re = /\\[([^\\]]*)\\]\\([^)]*\\)/g\n for (let m: RegExpExecArray | null; (m = re.exec(text));) {\n const from = m.index\n const to = from + m[0].length\n if (head >= from && head <= to) return { from, to, label: m[1] ?? \"\" }\n }\n return null\n}\n\n/**\n * Like {@link linkAtIn} but also breaks out the URL and its `[from, to)` span\n * within `text`, for editing just the `(…)` part in place.\n */\nexport function linkPartsIn(\n text: string,\n head: number,\n): { from: number; to: number; label: string; url: string; urlFrom: number; urlTo: number } | null {\n const re = /\\[([^\\]]*)\\]\\(([^)]*)\\)/g\n for (let m: RegExpExecArray | null; (m = re.exec(text));) {\n const from = m.index\n const to = from + m[0].length\n if (head >= from && head <= to) {\n const label = m[1] ?? \"\"\n const url = m[2] ?? \"\"\n const urlFrom = from + 1 + label.length + 2 // `[` + label + `](`\n return { from, to, label, url, urlFrom, urlTo: urlFrom + url.length }\n }\n }\n return null\n}\n\n/** Toggle `[text](url)` around `[from, to)` of `text` — wrap, or unlink to the label. */\nexport function linkString(text: string, from: number, to: number): InlineStr {\n const hit = linkAtIn(text, from)\n if (hit) {\n return {\n text: text.slice(0, hit.from) + hit.label + text.slice(hit.to),\n from: hit.from,\n to: hit.from + hit.label.length,\n }\n }\n const label = text.slice(from, to) || \"text\"\n const urlAt = from + label.length + 3 // past `[` + label + `](`\n return {\n text: text.slice(0, from) + `[${label}](url)` + text.slice(to),\n from: urlAt,\n to: urlAt + 3,\n }\n}\n\n/** The `<u>…</u>` span of `text` covering `head` (case-insensitive), or `null`. */\nexport function underlineAtIn(\n text: string,\n head: number,\n): { from: number; to: number; inner: string } | null {\n const re = /<u>([\\s\\S]*?)<\\/u>/gi\n for (let m: RegExpExecArray | null; (m = re.exec(text));) {\n const from = m.index\n const to = from + m[0].length\n if (head >= from && head <= to) return { from, to, inner: m[1] ?? \"\" }\n }\n return null\n}\n\n/**\n * Toggle `<u>…</u>` around `[from, to)` of `text`. Markdown has no underline, so\n * this is a raw HTML tag pair — it renders wherever the host renders inline HTML\n * (Obsidian, GitHub). Wrap the slice, or unwrap a span the caret is already in\n * to its inner text.\n */\nexport function underlineString(text: string, from: number, to: number): InlineStr {\n const hit = underlineAtIn(text, from)\n if (hit) {\n return {\n text: text.slice(0, hit.from) + hit.inner + text.slice(hit.to),\n from: hit.from,\n to: hit.from + hit.inner.length,\n }\n }\n const inner = text.slice(from, to) || \"text\"\n return {\n text: text.slice(0, from) + `<u>${inner}</u>` + text.slice(to),\n from: from + 3, // past `<u>`\n to: from + 3 + inner.length,\n }\n}\n\n/** The `[[target|label]]` span of `text` covering `head`, or `null`. */\nexport function wikiLinkAtIn(\n text: string,\n head: number,\n): { from: number; to: number; label: string } | null {\n for (const m of text.matchAll(WIKILINK_PATTERN)) {\n const from = m.index ?? 0\n const to = from + m[0].length\n if (head >= from && head <= to) return { from, to, label: m[2] || m[1] || \"\" }\n }\n return null\n}\n\n/**\n * Like {@link wikiLinkAtIn} but also breaks out the target and its `[from, to)`\n * span within `text`, for editing just the `[[…]]` target in place.\n */\nexport function wikiLinkPartsIn(\n text: string,\n head: number,\n): {\n from: number\n to: number\n target: string\n label: string\n targetFrom: number\n targetTo: number\n} | null {\n for (const m of text.matchAll(WIKILINK_PATTERN)) {\n const from = m.index ?? 0\n const to = from + m[0].length\n if (head < from || head > to) continue\n const target = m[1] ?? \"\"\n const targetFrom = from + 2 // past `[[`\n return {\n from,\n to,\n target,\n label: m[2] ?? \"\",\n targetFrom,\n targetTo: targetFrom + target.length,\n }\n }\n return null\n}\n\n/** Toggle `[[target]]` around `[from, to)` of `text` — wrap, or unwrap to the display text. */\nexport function wikiLinkString(text: string, from: number, to: number): InlineStr {\n const hit = wikiLinkAtIn(text, from)\n if (hit) {\n return {\n text: text.slice(0, hit.from) + hit.label + text.slice(hit.to),\n from: hit.from,\n to: hit.from + hit.label.length,\n }\n }\n const target = text.slice(from, to) || \"target\"\n return {\n text: text.slice(0, from) + `[[${target}]]` + text.slice(to),\n from: from + 2,\n to: from + 2 + target.length,\n }\n}\n","import { markedContentAt } from \"../toolbar/inline-ops\"\nimport type { ParsedTable } from \"./table-widget\"\n\n/** `[head, ...body]` as raw cell strings — the editable widget's source of truth. */\nexport const gridOf = (t: ParsedTable): string[][] => [t.head, ...t.body].map((r) => [...r])\n\nexport const trimGrid = (rows: string[][]): string[][] => rows.map((r) => r.map((s) => s.trim()))\n\n/** A GFM cell escapes a literal pipe as `\\|`; unescape before inline parsing. */\nexport const unescapePipe = (s: string): string => s.replace(/\\\\\\|/g, \"|\")\n\n/** Total length of the text nodes inside `cell` that precede `target`. */\nfunction textBefore(cell: HTMLElement, target: Node): number {\n const walker = cell.ownerDocument.createTreeWalker(cell, NodeFilter.SHOW_TEXT)\n let offset = 0\n for (let n = walker.nextNode(); n; n = walker.nextNode()) {\n if (n === target) return offset\n offset += n.textContent?.length ?? 0\n }\n return offset\n}\n\n/** Char offset of the DOM selection within `cell`'s rendered text. */\nexport function renderedCaretOffset(cell: HTMLElement): number {\n const sel = cell.ownerDocument.getSelection()\n const node = sel?.anchorNode\n if (!node || !cell.contains(node)) return 0\n if (node.nodeType === Node.TEXT_NODE) return textBefore(cell, node) + (sel?.anchorOffset ?? 0)\n return (sel?.anchorOffset ?? 0) > 0 ? (cell.textContent ?? \"\").length : 0\n}\n\n/** `[from, to]` char offsets of the DOM selection within `cell`'s text. */\nexport function selectionOffsets(cell: HTMLElement): { from: number; to: number } {\n const sel = cell.ownerDocument.getSelection()\n const end = (cell.textContent ?? \"\").length\n const at = (node: Node | null | undefined, off: number): number => {\n if (!node || !cell.contains(node)) return end\n if (node.nodeType === Node.TEXT_NODE) return textBefore(cell, node) + off\n return off > 0 ? end : 0\n }\n if (!sel || sel.rangeCount === 0) return { from: end, to: end }\n const a = at(sel.anchorNode, sel.anchorOffset)\n const b = at(sel.focusNode, sel.focusOffset)\n return { from: Math.min(a, b), to: Math.max(a, b) }\n}\n\ntype PointDoc = Document & {\n caretPositionFromPoint?: (x: number, y: number) => { offsetNode: Node; offset: number } | null\n}\n\n/** Char offset within `cell`'s rendered text at a screen point, `0` if unresolved. */\nexport function offsetFromPoint(cell: HTMLElement, x: number, y: number): number {\n const doc = cell.ownerDocument as PointDoc\n let node: Node | null = null\n let nodeOffset = 0\n if (doc.caretPositionFromPoint) {\n const p = doc.caretPositionFromPoint(x, y)\n if (p) [node, nodeOffset] = [p.offsetNode, p.offset]\n } else if (doc.caretRangeFromPoint) {\n const r = doc.caretRangeFromPoint(x, y)\n if (r) [node, nodeOffset] = [r.startContainer, r.startOffset]\n }\n if (!node || !cell.contains(node)) return 0\n return textBefore(cell, node) + (node.nodeType === Node.TEXT_NODE ? nodeOffset : 0)\n}\n\nconst WORD_CHAR = /[\\p{L}\\p{N}_]/u\n\n/**\n * Select the word at a screen point in `cell`'s raw text — the cell equivalent\n * of the canvas's \"right-click selects the word under the pointer\". A point\n * inside a marked run (`**bold phrase**`, `[a link](url)`, …) selects the whole\n * run's text instead, so a Format toggle covers all of it. Returns `false`\n * (leaving any caret / selection untouched) when the point is on whitespace or\n * punctuation, so a menu opened there still has a target.\n */\nexport function selectWordAtPoint(cell: HTMLElement, x: number, y: number): boolean {\n const text = cell.textContent ?? \"\"\n const at = offsetFromPoint(cell, x, y)\n const run = markedContentAt(text, at)\n if (run) {\n placeCaret(cell, run.from, run.to)\n return true\n }\n let from = at\n let to = at\n while (from > 0 && WORD_CHAR.test(text[from - 1]!)) from--\n while (to < text.length && WORD_CHAR.test(text[to]!)) to++\n if (to <= from) return false\n placeCaret(cell, from, to)\n return true\n}\n\n/**\n * Select `cell`'s first text node from char `offset` to char `head` (both\n * clamped). With `head` omitted or equal, the caret is simply parked at `offset`.\n */\nexport function placeCaret(cell: HTMLElement, offset: number, head = offset) {\n cell.focus()\n const doc = cell.ownerDocument\n const range = doc.createRange()\n const text = cell.firstChild\n if (text && text.nodeType === Node.TEXT_NODE) {\n const len = text.textContent?.length ?? 0\n range.setStart(text, Math.min(Math.min(offset, head), len))\n range.setEnd(text, Math.min(Math.max(offset, head), len))\n } else {\n range.selectNodeContents(cell)\n }\n if (offset === head) range.collapse(true)\n const sel = doc.getSelection()\n sel?.removeAllRanges()\n sel?.addRange(range)\n}\n","import type { EditorView } from \"@codemirror/view\"\nimport { placeCaret, selectionOffsets } from \"../inplace/table-cell-dom\"\nimport {\n type InlineStr,\n linkString,\n underlineString,\n wikiLinkString,\n wrapString,\n} from \"./inline-ops\"\n\n/** Rewrites a cell's text + selection given the current text and selection span. */\ntype Build = (text: string, from: number, to: number) => InlineStr\n\n/** The focused in-place table cell within `view`'s DOM, or `null`. */\nexport function activeTableCell(view: EditorView): HTMLElement | null {\n const el = view.dom.ownerDocument.activeElement\n if (!(el instanceof HTMLElement) || !view.dom.contains(el)) return null\n return el.matches(\".cm-inplace-tcell\") ? el : null\n}\n\n/**\n * Rewrite the focused cell's selected text with `build`, restore the selection\n * over the result, and fire `input` so {@link EditableTableWidget} reserialises\n * the table into the document. The cell shows its raw source while focused, so\n * the string offsets map straight onto the Markdown.\n */\nfunction applyToCell(cell: HTMLElement, build: Build): void {\n const { from, to } = selectionOffsets(cell)\n const next = build(cell.textContent ?? \"\", from, to)\n cell.textContent = next.text\n placeCaret(cell, next.from, next.to)\n cell.dispatchEvent(new Event(\"input\", { bubbles: true }))\n}\n\n/** If the caret is in a table cell, apply `build` there and report it handled. */\nexport function runInlineInCell(view: EditorView, build: Build): boolean {\n const cell = activeTableCell(view)\n if (!cell) return false\n applyToCell(cell, build)\n return true\n}\n\n/** Formatting shortcuts, keyed by the normalised (shift-cased) key. */\nconst SHORTCUTS: Record<string, Build> = {\n b: (t, f, u) => wrapString(t, f, u, \"**\"),\n i: (t, f, u) => wrapString(t, f, u, \"*\"),\n u: underlineString,\n k: linkString,\n K: wikiLinkString, // Mod-Shift-k\n}\n\n/**\n * Handle a formatting shortcut (`Mod-b` / `Mod-i` / `Mod-u` / `Mod-k` /\n * `Mod-Shift-k`) typed inside `cell`. The widget calls this because\n * `ignoreEvent()` keeps such keydowns from ever reaching CodeMirror's keymap.\n */\nexport function handleCellShortcut(event: KeyboardEvent, cell: HTMLElement): boolean {\n if (!(event.metaKey || event.ctrlKey) || event.altKey) return false\n const build = SHORTCUTS[event.shiftKey ? event.key.toUpperCase() : event.key.toLowerCase()]\n if (!build) return false\n event.preventDefault()\n applyToCell(cell, build)\n return true\n}\n","import { syntaxTree } from \"@codemirror/language\"\nimport type { EditorState } from \"@codemirror/state\"\nimport type { EditorView } from \"@codemirror/view\"\nimport { selectedLines } from \"./block\"\n\n/** The `{ from, to }` of the fenced code block enclosing `pos`, or `null`. */\nfunction enclosingFence(state: EditorState, pos: number): { from: number; to: number } | null {\n for (let node = syntaxTree(state).resolveInner(pos, 0); node; node = node.parent!) {\n if (node.name === \"FencedCode\") return { from: node.from, to: node.to }\n if (!node.parent) break\n }\n return null\n}\n\n/**\n * Wrap the selected lines in a ```` ``` ```` fence, or unwrap the block when the\n * caret already sits inside one.\n */\nexport function toggleFencedCode(view: EditorView): boolean {\n const s = view.state\n const fence = enclosingFence(s, s.selection.main.head)\n\n if (fence) {\n const open = s.doc.lineAt(fence.from)\n const close = s.doc.lineAt(fence.to)\n const changes = [{ from: open.from, to: Math.min(open.to + 1, s.doc.length) }]\n if (close.number !== open.number) {\n changes.push({ from: Math.max(close.from - 1, 0), to: close.to })\n }\n view.dispatch({ changes, scrollIntoView: true })\n } else {\n const [first, last] = selectedLines(s)\n view.dispatch({\n changes: [\n { from: s.doc.line(first).from, insert: \"```\\n\" },\n { from: s.doc.line(last).to, insert: \"\\n```\" },\n ],\n // Land the caret on the line between the fences, not before the opener.\n selection: { anchor: s.doc.line(first).from + 4 },\n scrollIntoView: true,\n })\n }\n view.focus()\n return true\n}\n\n/** True when the primary caret is inside a fenced code block. */\nexport function fencedCodeActive(state: EditorState): boolean {\n return enclosingFence(state, state.selection.main.head) !== null\n}\n\n/**\n * The info-string (language) span on the opening fence of the block at the\n * caret, plus its current text. `null` when the caret is not in a fence. The\n * opening line may be hidden in the seamless canvas, but its text is still in\n * the document, so this stays editable through the menu.\n */\nexport function fenceInfoAt(state: EditorState): { from: number; to: number; lang: string } | null {\n const fence = enclosingFence(state, state.selection.main.head)\n if (!fence) return null\n const open = state.doc.lineAt(fence.from)\n const m = /^(\\s*(?:`{3,}|~{3,})[ \\t]*)(.*?)[ \\t]*$/.exec(open.text)\n if (!m) return null\n const from = open.from + m[1]!.length\n return { from, to: from + m[2]!.length, lang: m[2]! }\n}\n\n/** A line that is exactly a `$$` math fence. */\nconst MATH_FENCE = /^\\s*\\$\\$\\s*$/\n\n/**\n * The `[openLine, closeLine]` of the `$$` block enclosing `caretLine`, or\n * `null`. Found by pairing `$$` fence lines across the whole document — the\n * Markdown grammar has no math node to walk.\n */\nfunction enclosingMath(state: EditorState, caretLine: number): [number, number] | null {\n let openLine = 0\n let count = 0\n for (let n = 1; n <= state.doc.lines; n++) {\n if (!MATH_FENCE.test(state.doc.line(n).text)) continue\n count++\n if (count % 2 === 1) {\n openLine = n\n // The caret sitting on the opening `$$` still counts as inside the block.\n if (n > caretLine) return null\n } else if (n >= caretLine) {\n return [openLine, n]\n }\n }\n return null\n}\n\n/**\n * Wrap the selected lines in a `$$` … `$$` block, or unwrap the block the caret\n * already sits in.\n */\nexport function toggleMathBlock(view: EditorView): boolean {\n const s = view.state\n const [first, last] = selectedLines(s)\n const pair = enclosingMath(s, s.doc.lineAt(s.selection.main.head).number)\n\n if (pair) {\n const openLine = s.doc.line(pair[0])\n const closeLine = s.doc.line(pair[1])\n view.dispatch({\n changes: [\n { from: openLine.from, to: Math.min(openLine.to + 1, s.doc.length) },\n { from: Math.max(closeLine.from - 1, 0), to: closeLine.to },\n ],\n scrollIntoView: true,\n })\n } else {\n view.dispatch({\n changes: [\n { from: s.doc.line(first).from, insert: \"$$\\n\" },\n { from: s.doc.line(last).to, insert: \"\\n$$\" },\n ],\n // Land the caret on the line between the fences, not before the opener.\n selection: { anchor: s.doc.line(first).from + 3 },\n scrollIntoView: true,\n })\n }\n view.focus()\n return true\n}\n\n/** True when the primary caret is inside a `$$` math block. */\nexport function mathBlockActive(state: EditorState): boolean {\n return enclosingMath(state, state.doc.lineAt(state.selection.main.head).number) !== null\n}\n","import { EditorSelection } from \"@codemirror/state\"\nimport type { EditorState } from \"@codemirror/state\"\nimport type { EditorView } from \"@codemirror/view\"\nimport { esc, linkAtIn, underlineAtIn, wikiLinkAtIn, wrapOp } from \"./inline-ops\"\n\n/**\n * Toggle an inline wrapping mark (`**`, `*`, `~~`, `` ` ``, `$`) around each\n * selection range. A range already wrapped — whether the marks are inside or\n * around the selection — is unwrapped; an empty range gets an empty pair with\n * the caret parked between the marks. Applying `*` to `**bold**` (or `**` to\n * `*em*`) nests rather than eating a marker. The edit logic lives in\n * {@link wrapOp}; this binds it to the view's selection(s).\n */\nexport function toggleWrap(view: EditorView, mark: string): boolean {\n const text = view.state.doc.toString()\n view.dispatch({\n ...view.state.changeByRange((range) => {\n const op = wrapOp(text, range.from, range.to, mark)\n return {\n changes: op.changes,\n range:\n op.from === op.to\n ? EditorSelection.cursor(op.from)\n : EditorSelection.range(op.from, op.to),\n }\n }),\n scrollIntoView: true,\n })\n view.focus()\n return true\n}\n\n/** True when the primary selection sits within a `mark…mark` span on its line. */\nexport function wrapActive(state: EditorState, mark: string): boolean {\n const range = state.selection.main\n const line = state.doc.lineAt(range.head)\n const pattern = new RegExp(esc(mark) + \"(?!\\\\s)(?:[^]*?\\\\S)??\" + esc(mark), \"g\")\n for (let m: RegExpExecArray | null; (m = pattern.exec(line.text));) {\n if (m[0].length <= 2 * mark.length) continue // an empty pair — `$$`, `****`\n // Inline `$…$` must not be read out of a `$$` block-math fence.\n if (\n mark === \"$\" &&\n (line.text[m.index - 1] === \"$\" || line.text[m.index + m[0].length] === \"$\")\n ) {\n continue\n }\n const start = line.from + m.index\n if (range.from >= start && range.to <= start + m[0].length) return true\n }\n return false\n}\n\n/** The `[text](url)` span under the primary caret, in document coordinates. */\nfunction linkAt(state: EditorState): { from: number; to: number; text: string } | null {\n const { head } = state.selection.main\n const line = state.doc.lineAt(head)\n const hit = linkAtIn(line.text, head - line.from)\n return hit ? { from: line.from + hit.from, to: line.from + hit.to, text: hit.label } : null\n}\n\n/**\n * Wrap the selection as `[text](url)` with the `url` placeholder selected — or,\n * when the caret is already in a link, unlink it: the label text stays, the\n * `](url)` wrapper goes.\n */\nexport function toggleLink(view: EditorView): boolean {\n const existing = linkAt(view.state)\n if (existing) {\n view.dispatch({\n changes: { from: existing.from, to: existing.to, insert: existing.text },\n selection: EditorSelection.range(existing.from, existing.from + existing.text.length),\n scrollIntoView: true,\n })\n view.focus()\n return true\n }\n const { from, to } = view.state.selection.main\n const text = view.state.sliceDoc(from, to) || \"text\"\n const urlAt = from + text.length + 3 // past `[` + text + `](`\n view.dispatch({\n changes: { from, to, insert: `[${text}](url)` },\n selection: EditorSelection.range(urlAt, urlAt + 3),\n scrollIntoView: true,\n })\n view.focus()\n return true\n}\n\n/** True when the primary caret sits inside a `[…](…)` span on its line. */\nexport function linkActive(state: EditorState): boolean {\n return linkAt(state) !== null\n}\n\n/** The `[[target|label]]` span under the primary caret, in document coordinates. */\nfunction wikiLinkAt(state: EditorState): { from: number; to: number; text: string } | null {\n const { head } = state.selection.main\n const line = state.doc.lineAt(head)\n const hit = wikiLinkAtIn(line.text, head - line.from)\n return hit ? { from: line.from + hit.from, to: line.from + hit.to, text: hit.label } : null\n}\n\n/**\n * Wrap the selection as `[[target]]` with the target text selected — or, when\n * the caret is already in a wikilink, unwrap it: the display text (the label if\n * there is one, else the target) stays, the `[[ … ]]` and any `|label` go.\n */\nexport function toggleWikiLink(view: EditorView): boolean {\n const existing = wikiLinkAt(view.state)\n if (existing) {\n view.dispatch({\n changes: { from: existing.from, to: existing.to, insert: existing.text },\n selection: EditorSelection.range(existing.from, existing.from + existing.text.length),\n scrollIntoView: true,\n })\n view.focus()\n return true\n }\n const { from, to } = view.state.selection.main\n const text = view.state.sliceDoc(from, to) || \"target\"\n view.dispatch({\n changes: { from, to, insert: `[[${text}]]` },\n selection: EditorSelection.range(from + 2, from + 2 + text.length),\n scrollIntoView: true,\n })\n view.focus()\n return true\n}\n\n/** True when the primary caret sits inside a `[[…]]` span on its line. */\nexport function wikiLinkActive(state: EditorState): boolean {\n return wikiLinkAt(state) !== null\n}\n\n/** The `<u>…</u>` span under the primary caret, in document coordinates. */\nfunction underlineAt(state: EditorState): { from: number; to: number; inner: string } | null {\n const { head } = state.selection.main\n const line = state.doc.lineAt(head)\n const hit = underlineAtIn(line.text, head - line.from)\n return hit ? { from: line.from + hit.from, to: line.from + hit.to, inner: hit.inner } : null\n}\n\n/**\n * Wrap the selection in `<u>…</u>` — a raw HTML tag pair, since Markdown has no\n * underline. With the caret already inside a `<u>` span, unwrap it: the inner\n * text stays, the tags go.\n */\nexport function toggleUnderline(view: EditorView): boolean {\n const existing = underlineAt(view.state)\n if (existing) {\n view.dispatch({\n changes: { from: existing.from, to: existing.to, insert: existing.inner },\n selection: EditorSelection.range(existing.from, existing.from + existing.inner.length),\n scrollIntoView: true,\n })\n view.focus()\n return true\n }\n const { from, to } = view.state.selection.main\n const inner = view.state.sliceDoc(from, to) || \"text\"\n view.dispatch({\n changes: { from, to, insert: `<u>${inner}</u>` },\n selection: EditorSelection.range(from + 3, from + 3 + inner.length),\n scrollIntoView: true,\n })\n view.focus()\n return true\n}\n\n/** True when the primary caret sits inside a `<u>…</u>` span on its line. */\nexport function underlineActive(state: EditorState): boolean {\n return underlineAt(state) !== null\n}\n","export type Align = \"\" | \"left\" | \"center\" | \"right\"\n\nexport interface Grid {\n /** Content rows, header first. The delimiter row is not included. */\n rows: string[][]\n aligns: Align[]\n}\n\n/** A GFM delimiter row: only pipes, dashes, colons, spaces, and at least one dash. */\nexport function isDelimiterLine(line: string): boolean {\n const t = line.trim()\n return t.includes(\"-\") && t.includes(\"|\") && /^[\\s|:-]+$/.test(t)\n}\n\n/** Split a table row on unescaped `|`, dropping one outer pipe each side. */\nexport function splitRow(line: string): string[] {\n let s = line.trim()\n if (s.startsWith(\"|\")) s = s.slice(1)\n if (s.endsWith(\"|\") && !s.endsWith(\"\\\\|\")) s = s.slice(0, -1)\n const cells: string[] = []\n let cur = \"\"\n for (let i = 0; i < s.length; i++) {\n if (s[i] === \"\\\\\" && s[i + 1] === \"|\") {\n cur += \"\\\\|\"\n i++\n } else if (s[i] === \"|\") {\n cells.push(cur.trim())\n cur = \"\"\n } else {\n cur += s[i]\n }\n }\n cells.push(cur.trim())\n return cells\n}\n\nfunction alignFromSpec(spec: string): Align {\n const s = spec.trim()\n const l = s.startsWith(\":\")\n const r = s.endsWith(\":\")\n return l && r ? \"center\" : r ? \"right\" : l ? \"left\" : \"\"\n}\n\n/** Parse the raw lines of a table (delimiter expected at index 1). */\nexport function parseGrid(lines: string[]): Grid | null {\n if (lines.length < 2 || !isDelimiterLine(lines[1]!)) return null\n const aligns = splitRow(lines[1]!).map(alignFromSpec)\n const rows = lines.filter((_, i) => i !== 1).map(splitRow)\n const cols = Math.max(aligns.length, ...rows.map((r) => r.length))\n const norm = rows.map((r) => {\n const c = r.slice(0, cols)\n while (c.length < cols) c.push(\"\")\n return c\n })\n const a = aligns.slice(0, cols)\n while (a.length < cols) a.push(\"\")\n return { rows: norm, aligns: a }\n}\n\n/** Display width of a cell — an escaped pipe counts as one character. */\nfunction cellWidth(cell: string): number {\n return cell.replace(/\\\\\\|/g, \"|\").length\n}\n\nfunction pad(cell: string, width: number, align: Align): string {\n const gap = width - cellWidth(cell)\n if (gap <= 0) return cell\n if (align === \"right\") return \" \".repeat(gap) + cell\n if (align === \"center\") {\n const l = Math.floor(gap / 2)\n return \" \".repeat(l) + cell + \" \".repeat(gap - l)\n }\n return cell + \" \".repeat(gap)\n}\n\nfunction delimiterCell(width: number, align: Align): string {\n const w = Math.max(3, width)\n if (align === \"left\") return \":\" + \"-\".repeat(w - 1)\n if (align === \"right\") return \"-\".repeat(w - 1) + \":\"\n if (align === \"center\") return \":\" + \"-\".repeat(w - 2) + \":\"\n return \"-\".repeat(w)\n}\n\n/** Serialize a grid to an aligned pipe table — deterministic and idempotent. */\nexport function serializeGrid(grid: Grid): string {\n const cols = grid.aligns.length\n const widths: number[] = []\n for (let c = 0; c < cols; c++) {\n let w = 3\n for (const row of grid.rows) w = Math.max(w, cellWidth(row[c] ?? \"\"))\n widths.push(w)\n }\n const rowLine = (cells: string[]) =>\n \"| \" + cells.map((cell, c) => pad(cell ?? \"\", widths[c]!, grid.aligns[c]!)).join(\" | \") + \" |\"\n const out = [rowLine(grid.rows[0] ?? [])]\n out.push(\"| \" + grid.aligns.map((a, c) => delimiterCell(widths[c]!, a)).join(\" | \") + \" |\")\n for (let r = 1; r < grid.rows.length; r++) out.push(rowLine(grid.rows[r]!))\n return out.join(\"\\n\")\n}\n\nexport interface CellSpan {\n start: number\n contentStart: number\n contentEnd: number\n end: number\n}\n\n/** The `|`-delimited cell spans of a line (positions relative to line start). */\nexport function cellBounds(line: string): CellSpan[] {\n const pipes: number[] = []\n for (let i = 0; i < line.length; i++) {\n if (line[i] === \"\\\\\") {\n i++\n continue\n }\n if (line[i] === \"|\") pipes.push(i)\n }\n const out: CellSpan[] = []\n for (let p = 0; p < pipes.length - 1; p++) {\n const start = pipes[p]! + 1\n const end = pipes[p + 1]!\n const seg = line.slice(start, end)\n const lead = seg.length - seg.trimStart().length\n const trail = seg.length - seg.trimEnd().length\n out.push({ start, contentStart: start + lead, contentEnd: end - trail, end })\n }\n return out\n}\n","import {\n ChangeSet,\n EditorSelection,\n EditorState,\n type Extension,\n type Text,\n} from \"@codemirror/state\"\nimport { keymap } from \"@codemirror/view\"\nimport type { EditorView } from \"@codemirror/view\"\nimport { cellBounds, type Grid, parseGrid, serializeGrid } from \"./table-grid\"\n\ninterface Region {\n from: number\n to: number\n lines: string[]\n}\n\n/** The contiguous pipe-table block containing `pos`, if it parses as a table. */\nexport function findTable(doc: Text, pos: number): Region | null {\n const at = doc.lineAt(pos)\n if (!at.text.includes(\"|\")) return null\n let first = at.number\n while (first > 1) {\n const t = doc.line(first - 1).text\n if (!t.includes(\"|\") || !t.trim()) break\n first--\n }\n let last = at.number\n while (last < doc.lines) {\n const t = doc.line(last + 1).text\n if (!t.includes(\"|\") || !t.trim()) break\n last++\n }\n if (last - first < 1) return null\n const lines: string[] = []\n for (let n = first; n <= last; n++) lines.push(doc.line(n).text)\n if (!parseGrid(lines)) return null\n return { from: doc.line(first).from, to: doc.line(last).to, lines }\n}\n\ninterface CellLoc {\n row: number // index into grid.rows (header = 0)\n col: number\n offset: number // char offset within the cell's trimmed content\n onDelimiter: boolean\n}\n\nfunction locate(lines: string[], from: number, caret: number): CellLoc | null {\n let lineStart = from\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i]!\n if (caret <= lineStart + line.length) {\n const x = caret - lineStart\n if (i === 1) {\n let pipes = 0\n for (let k = 0; k < x && k < line.length; k++) if (line[k] === \"|\") pipes++\n return { row: 0, col: Math.max(0, pipes - 1), offset: 0, onDelimiter: true }\n }\n const bounds = cellBounds(line)\n let col = 0\n for (let c = 0; c < bounds.length; c++) {\n col = c\n if (x <= bounds[c]!.end) break\n }\n const b = bounds[col]\n const offset = b ? Math.max(0, Math.min(x, b.contentEnd) - b.contentStart) : 0\n return { row: i === 0 ? 0 : i - 1, col, offset, onDelimiter: false }\n }\n lineStart += line.length + 1\n }\n return null\n}\n\nfunction resolve(text: string, from: number, loc: CellLoc): number {\n const lines = text.split(\"\\n\")\n const idx = loc.onDelimiter ? 1 : loc.row === 0 ? 0 : loc.row + 1\n let pos = from\n for (let i = 0; i < idx; i++) pos += lines[i]!.length + 1\n const bounds = cellBounds(lines[idx]!)\n const b = bounds[Math.min(loc.col, bounds.length - 1)]\n if (!b) return pos\n return pos + b.contentStart + Math.min(loc.offset, b.contentEnd - b.contentStart)\n}\n\n/**\n * Document position of the start of a table cell's content, for the pipe table\n * that contains `tableFrom`. `row` is the content-row index (header = 0, first\n * body row = 1, …); the delimiter row is not counted. Used to land the caret in\n * the clicked cell when a rendered in-place table reveals its source.\n */\nexport function cellSourcePos(\n doc: Text,\n tableFrom: number,\n row: number,\n col: number,\n): number | null {\n const region = findTable(doc, tableFrom)\n if (!region) return null\n return resolve(region.lines.join(\"\\n\"), region.from, { row, col, offset: 0, onDelimiter: false })\n}\n\nconst SKELETON = \"| Column 1 | Column 2 |\\n| -------- | -------- |\\n| | |\"\n\n/**\n * When the in-place canvas renders tables as editable cells\n * (`inPlace.table: \"cells\"`), drop DOM focus into the first cell of the table\n * just inserted near `pos`. A no-op on every other surface — nothing matches the\n * selector — so no config check is needed.\n */\nfunction focusInsertedCell(view: EditorView, pos: number): void {\n requestAnimationFrame(() => {\n const tables = view.dom.querySelectorAll<HTMLElement>(\".cm-inplace-table-edit\")\n if (tables.length === 0) return\n let target = tables[0]!\n let best = Number.POSITIVE_INFINITY\n for (const t of tables) {\n let d = Number.POSITIVE_INFINITY\n try {\n d = Math.abs(view.posAtDOM(t) - pos)\n } catch {\n // still mid-render — leave it to the fallback\n }\n if (d < best) {\n best = d\n target = t\n }\n }\n const cell = target.querySelector<HTMLElement>(\"th, td\")\n if (!cell) return\n const range = document.createRange()\n range.selectNodeContents(cell)\n const sel = cell.ownerDocument.getSelection()\n sel?.removeAllRanges()\n sel?.addRange(range)\n cell.focus()\n })\n}\n\n/** Insert a starter table at the cursor and select the first header cell. */\nexport function insertTable(view: EditorView): boolean {\n const { from, to } = view.state.selection.main\n const line = view.state.doc.lineAt(from)\n const lead = line.text.slice(0, from - line.from).trim() ? \"\\n\\n\" : \"\"\n const cellAt = from + lead.length + 2 // past \"| \"\n view.dispatch({\n changes: { from, to, insert: lead + SKELETON + \"\\n\" },\n selection: EditorSelection.range(cellAt, cellAt + 8), // \"Column 1\"\n scrollIntoView: true,\n })\n view.focus()\n focusInsertedCell(view, cellAt)\n return true\n}\n\n/** True when the primary caret is inside a pipe table. */\nexport function tableActive(state: EditorState): boolean {\n return findTable(state.doc, state.selection.main.head) !== null\n}\n\n/** Rewrite the table to an aligned grid and move the caret to `target` cell. */\nfunction navigate(view: EditorView, target: (grid: Grid, loc: CellLoc) => CellLoc | null): boolean {\n const region = findTable(view.state.doc, view.state.selection.main.head)\n if (!region) return false\n const grid = parseGrid(region.lines)\n const loc = locate(region.lines, region.from, view.state.selection.main.head)\n if (!grid || !loc) return false\n const next = target(grid, loc)\n if (!next) return false\n const aligned = serializeGrid(grid)\n view.dispatch({\n changes: { from: region.from, to: region.to, insert: aligned },\n selection: EditorSelection.cursor(resolve(aligned, region.from, next)),\n scrollIntoView: true,\n })\n view.focus()\n return true\n}\n\nfunction step(grid: Grid, loc: CellLoc, dir: 1 | -1): CellLoc | null {\n const cols = grid.aligns.length\n let { row, col } = loc\n col += dir\n if (col >= cols) {\n row++\n col = 0\n } else if (col < 0) {\n row--\n col = cols - 1\n }\n if (row < 0) return null\n if (row >= grid.rows.length) grid.rows.push(new Array(cols).fill(\"\"))\n return { row, col, offset: 0, onDelimiter: false }\n}\n\nfunction down(grid: Grid, loc: CellLoc): CellLoc | null {\n const row = loc.row + 1\n if (row >= grid.rows.length) grid.rows.push(new Array(grid.aligns.length).fill(\"\"))\n return { row, col: loc.col, offset: 0, onDelimiter: false }\n}\n\n/**\n * Table editing keys, live only when the caret is inside a pipe table:\n * Tab / Shift-Tab walk the cells (Tab past the end adds a row), Enter drops to\n * the cell below (adding a row at the bottom). Every move re-aligns the grid.\n * Outside a table the bindings return false, so normal Tab / Enter are intact.\n */\nexport const tableKeymap: Extension = keymap.of([\n { key: \"Tab\", run: (v) => navigate(v, (g, l) => step(g, l, 1)) },\n { key: \"Shift-Tab\", run: (v) => navigate(v, (g, l) => step(g, l, -1)) },\n { key: \"Enter\", run: (v) => navigate(v, down) },\n])\n\n/**\n * Live pipe alignment. On every typing / deletion transaction whose caret ends\n * up inside a table, the grid is re-serialized and the change composed into the\n * same transaction (one undo step). Idempotent, so it does not re-trigger.\n */\nexport const tableRealign: Extension = EditorState.transactionFilter.of((tr) => {\n if (!tr.docChanged) return tr\n if (!tr.isUserEvent(\"input\") && !tr.isUserEvent(\"delete\")) return tr\n const head = tr.newSelection.main.head\n const region = findTable(tr.newDoc, head)\n if (!region) return tr\n const grid = parseGrid(region.lines)\n if (!grid) return tr\n const aligned = serializeGrid(grid)\n if (aligned === region.lines.join(\"\\n\")) return tr\n const loc = locate(region.lines, region.from, head)\n const align = ChangeSet.of(\n [{ from: region.from, to: region.to, insert: aligned }],\n tr.newDoc.length,\n )\n return {\n changes: tr.changes.compose(align),\n selection: loc ? EditorSelection.cursor(resolve(aligned, region.from, loc)) : tr.newSelection,\n effects: tr.effects,\n scrollIntoView: tr.scrollIntoView,\n }\n})\n","import { redo, undo } from \"@codemirror/commands\"\nimport { openSearchPanel } from \"@codemirror/search\"\nimport type { EditorState } from \"@codemirror/state\"\nimport type { EditorView } from \"@codemirror/view\"\nimport { runSave, saveHandler } from \"../editor/save\"\nimport type { ToolbarCommandId } from \"../types\"\nimport {\n clearHeading,\n frontmatterActive,\n horizontalRuleActive,\n linePrefixActive,\n toggleFrontmatter,\n toggleHeading,\n toggleHorizontalRule,\n toggleLinePrefix,\n type LinePrefixSpec,\n} from \"./block\"\nimport { frontmatterRange } from \"../frontmatter\"\nimport { runInlineInCell } from \"./cell-inline\"\nimport { fencedCodeActive, mathBlockActive, toggleFencedCode, toggleMathBlock } from \"./fence\"\nimport {\n linkActive,\n toggleLink,\n toggleUnderline,\n toggleWikiLink,\n toggleWrap,\n underlineActive,\n wikiLinkActive,\n wrapActive,\n} from \"./inline\"\nimport { linkString, underlineString, wikiLinkString, wrapString } from \"./inline-ops\"\nimport { insertTable, tableActive } from \"./table\"\n\n// --- context predicates: where a command can't sensibly apply ---\n\n/** Caret's line is an ATX heading (`#` … `######`). */\nconst inHeading = (s: EditorState): boolean =>\n /^\\s{0,3}#{1,6}(?:\\s|$)/.test(s.doc.lineAt(s.selection.main.head).text)\n\n/** Caret is inside the leading `---` YAML block. */\nconst inFrontmatter = (s: EditorState): boolean => {\n const r = frontmatterRange(s.doc)\n return r !== null && s.selection.main.head <= r.to\n}\n\n/** Contexts where inline markup is literal or would break the syntax. */\nconst inLiteral = (s: EditorState): boolean =>\n inFrontmatter(s) || fencedCodeActive(s) || mathBlockActive(s)\n\n/**\n * Inside an inline `` `code` `` or `$math$` span, no *other* mark can be added —\n * `` `**x**` `` / `$`x`$` are not valid. The span's own mark stays live so it\n * can be toggled off.\n */\nconst inOtherInlineLiteral =\n (mark: string) =>\n (s: EditorState): boolean =>\n (mark !== \"`\" && wrapActive(s, \"`\")) || (mark !== \"$\" && wrapActive(s, \"$\"))\n\n/**\n * Nothing to wrap — a collapsed caret with no word at it (a blank line, a run\n * of spaces, punctuation). Wrapping there just drops an empty `****` / `` `` ``\n * pair, which shows as literal marks in the seamless canvas.\n */\nconst nothingToWrap = (s: EditorState): boolean =>\n s.selection.main.empty && !s.wordAt(s.selection.main.head)\n\n/** A `disabled` predicate that fires when any of `checks` matches. */\nconst disabledWhen =\n (...checks: ((s: EditorState) => boolean)[]) =>\n (s: EditorState): boolean =>\n checks.some((c) => c(s))\n\nexport interface ToolbarCommand {\n id: ToolbarCommandId\n /** Tooltip and accessible label. */\n title: string\n /** Mutate the document against the live view; returns true when handled. */\n run: (view: EditorView) => boolean\n /** Reflected as the button's pressed state. */\n isActive?: (state: EditorState) => boolean\n /**\n * True when the command can't produce valid Markdown at the current selection\n * — the button is rendered `disabled` and the shortcut is a no-op. Driven by\n * the context predicates above (a table cell, a heading line, a frontmatter /\n * fenced-code / `$$` block).\n */\n disabled?: (state: EditorState) => boolean\n /** Default key bindings in CodeMirror `key` syntax. */\n keys?: string[]\n}\n\n/** Any list marker — bullet, ordered, or task — with `[1]` capturing the indent. */\nconst LIST_MARKER = /^(\\s*)(?:[-*+] \\[[ xX]\\] +|\\d+\\. +|[-*+] +)/\n\nconst QUOTE: LinePrefixSpec = { match: /^ {0,3}> ?/, insert: \"> \" }\nconst BULLET: LinePrefixSpec = {\n match: /^(\\s*)[-*+] +(?!\\[[ xX]\\])/,\n insert: \"- \",\n siblings: LIST_MARKER,\n}\nconst ORDERED: LinePrefixSpec = {\n match: /^(\\s*)\\d+\\. +/,\n insert: (n) => `${n + 1}. `,\n siblings: LIST_MARKER,\n}\nconst TASK: LinePrefixSpec = {\n match: /^(\\s*)[-*+] \\[[ xX]\\] +/,\n insert: \"- [ ] \",\n siblings: LIST_MARKER,\n}\n\nfunction history(id: \"undo\" | \"redo\", title: string, cmd: typeof undo): ToolbarCommand {\n return {\n id,\n title,\n run: (view) => {\n const ok = cmd(view)\n view.focus()\n return ok\n },\n }\n}\n\nfunction wrap(id: ToolbarCommandId, title: string, mark: string, keys?: string[]): ToolbarCommand {\n return {\n id,\n title,\n run: (view) =>\n runInlineInCell(view, (t, f, u) => wrapString(t, f, u, mark)) || toggleWrap(view, mark),\n isActive: (state) => wrapActive(state, mark),\n disabled: disabledWhen(inLiteral, inOtherInlineLiteral(mark), nothingToWrap),\n keys,\n }\n}\n\nfunction heading(level: 1 | 2 | 3): ToolbarCommand {\n const marker = new RegExp(`^#{${level}} `)\n return {\n id: `h${level}` as ToolbarCommandId,\n title: `Heading ${level}`,\n run: (view) => toggleHeading(view, level),\n isActive: (state) => marker.test(state.doc.lineAt(state.selection.main.head).text),\n disabled: disabledWhen(tableActive, inLiteral),\n keys: [`Mod-Alt-${level}`],\n }\n}\n\nfunction prefix(\n id: ToolbarCommandId,\n title: string,\n spec: LinePrefixSpec,\n ...extra: ((s: EditorState) => boolean)[]\n): ToolbarCommand {\n return {\n id,\n title,\n run: (view) => toggleLinePrefix(view, spec),\n isActive: (state) => linePrefixActive(state, spec.match),\n disabled: disabledWhen(tableActive, inLiteral, ...extra),\n }\n}\n\n/** Every built-in command, in a stable order. The toolbar picks from these by id. */\nexport const BUILTIN_COMMANDS: ToolbarCommand[] = [\n history(\"undo\", \"Undo\", undo),\n history(\"redo\", \"Redo\", redo),\n {\n // Calls the `onSave` prop with the document (same path as `Mod-s`).\n // Disabled — and never in the default bar — until a handler is wired.\n id: \"save\",\n title: \"Save\",\n run: (view) => {\n const ok = runSave(view)\n view.focus()\n return ok\n },\n disabled: (state) => state.facet(saveHandler) == null,\n },\n {\n // Opens the find / replace panel (`@codemirror/search`). `Mod-f` is bound on\n // every surface via `keys`, so the panel works without the visible toolbar;\n // the button is opt-in — not in `DEFAULT_TOOLBAR_ITEMS`. Focus moves into\n // the panel's field, so no `view.focus()` here.\n id: \"search\",\n title: \"Find / replace\",\n run: (view) => openSearchPanel(view),\n keys: [\"Mod-f\"],\n },\n heading(1),\n heading(2),\n heading(3),\n {\n // The explicit \"make this a paragraph again\" — clearer than clicking the\n // active heading level to toggle it off.\n id: \"body\" as ToolbarCommandId,\n title: \"Body\",\n run: (view) => {\n if (!clearHeading(view)) view.focus()\n return true\n },\n isActive: (state) => !/^#{1,6} /.test(state.doc.lineAt(state.selection.main.head).text),\n disabled: disabledWhen(tableActive, inLiteral),\n },\n wrap(\"bold\", \"Bold\", \"**\", [\"Mod-b\"]),\n wrap(\"italic\", \"Italic\", \"*\", [\"Mod-i\"]),\n wrap(\"strike\", \"Strikethrough\", \"~~\"),\n {\n // Markdown has no underline. This inserts a raw `<u>…</u>` HTML pair, which\n // renders wherever the host renders inline HTML. Not in the default bar —\n // add `\"underline\"` to `toolbar.items` to show it.\n id: \"underline\" as ToolbarCommandId,\n title: \"Underline\",\n run: (view) => runInlineInCell(view, underlineString) || toggleUnderline(view),\n isActive: underlineActive,\n disabled: disabledWhen(inLiteral, inOtherInlineLiteral(\"u\"), nothingToWrap),\n keys: [\"Mod-u\"],\n },\n wrap(\"code\", \"Inline code\", \"`\"),\n {\n // In a table cell a fenced block has no valid Markdown, so degrade to\n // inline `` `code` `` there. Disabled on a heading / in frontmatter / in a\n // `$$` block; inside a fence it is the unwrap toggle, so stays live.\n id: \"codeBlock\",\n title: \"Code block\",\n run: (view) =>\n runInlineInCell(view, (t, f, u) => wrapString(t, f, u, \"`\")) ||\n (tableActive(view.state) ? toggleWrap(view, \"`\") : toggleFencedCode(view)),\n isActive: (state) => (tableActive(state) ? wrapActive(state, \"`\") : fencedCodeActive(state)),\n disabled: disabledWhen(inFrontmatter, mathBlockActive, inHeading),\n },\n {\n id: \"link\",\n title: \"Link\",\n run: (view) => runInlineInCell(view, linkString) || toggleLink(view),\n isActive: linkActive,\n disabled: inLiteral,\n keys: [\"Mod-k\"],\n },\n {\n id: \"wikilink\",\n title: \"Wikilink\",\n run: (view) => runInlineInCell(view, wikiLinkString) || toggleWikiLink(view),\n isActive: wikiLinkActive,\n disabled: inLiteral,\n keys: [\"Mod-Shift-k\"],\n },\n prefix(\"quote\", \"Blockquote\", QUOTE),\n prefix(\"bulletList\", \"Bulleted list\", BULLET, inHeading),\n prefix(\"orderedList\", \"Numbered list\", ORDERED, inHeading),\n prefix(\"task\", \"Task list\", TASK, inHeading),\n {\n id: \"hr\",\n title: \"Divider\",\n run: toggleHorizontalRule,\n isActive: horizontalRuleActive,\n disabled: disabledWhen(tableActive, inLiteral),\n },\n {\n id: \"frontmatter\",\n title: \"Frontmatter\",\n run: toggleFrontmatter,\n isActive: frontmatterActive,\n // live inside the block itself (to toggle it off), disabled where it makes no sense\n disabled: disabledWhen(tableActive, fencedCodeActive, mathBlockActive, inHeading),\n },\n {\n id: \"table\",\n title: \"Table\",\n run: insertTable,\n isActive: tableActive,\n disabled: disabledWhen(\n tableActive,\n inFrontmatter,\n fencedCodeActive,\n mathBlockActive,\n inHeading,\n ),\n },\n wrap(\"math\", \"Inline math\", \"$\"),\n {\n // In a table cell, degrade the `$$` block to inline `$…$` math. Disabled on\n // a heading / in frontmatter / in a fence; inside `$$` it is the unwrap\n // toggle, so stays live.\n id: \"mathBlock\",\n title: \"Block math\",\n run: (view) =>\n runInlineInCell(view, (t, f, u) => wrapString(t, f, u, \"$\")) ||\n (tableActive(view.state) ? toggleWrap(view, \"$\") : toggleMathBlock(view)),\n isActive: (state) => (tableActive(state) ? wrapActive(state, \"$\") : mathBlockActive(state)),\n disabled: disabledWhen(inFrontmatter, fencedCodeActive, inHeading),\n },\n]\n\nexport const BUILTIN_BY_ID: Record<string, ToolbarCommand> = Object.fromEntries(\n BUILTIN_COMMANDS.map((c) => [c.id, c]),\n)\n","import { Prec } from \"@codemirror/state\"\nimport { type Command, keymap } from \"@codemirror/view\"\nimport { BUILTIN_COMMANDS } from \"./commands\"\n\n/**\n * Formatting shortcuts (ADR-002 §5): `Mod-b` / `Mod-i` bold and italic,\n * `Mod-k` link, `Mod-Alt-1..3` headings. Bound on every CodeMirror surface\n * whether or not the visible toolbar is mounted. Undo/redo stay with\n * `historyKeymap`, so no command that declares no keys is included here.\n */\nexport const markdownKeymap = Prec.high(\n keymap.of(\n BUILTIN_COMMANDS.filter((c) => c.keys && c.keys.length > 0).flatMap((c) =>\n c.keys!.map((key) => ({\n key,\n preventDefault: true,\n run: ((view) => (c.disabled?.(view.state) ? false : c.run(view))) as Command,\n })),\n ),\n ),\n)\n","import { HighlightStyle, syntaxHighlighting } from \"@codemirror/language\"\nimport { tags as t } from \"@lezer/highlight\"\n\n/**\n * Token colours for fenced code and any other embedded-language grammar.\n *\n * Every colour resolves to a `--stylo-syntax-*` custom property, so the host\n * restyles code the same way as the rest of the `--stylo-*` palette; the values\n * in `tokens.css` are the defaults. Both `@codemirror/language` and\n * `@lezer/highlight` are already transitive dependencies of\n * `@codemirror/lang-markdown`, so this adds no package weight.\n *\n * Markdown's own structural tokens (heading marks, emphasis markers, link\n * brackets) are deliberately left undefined: the in-place canvas styles those\n * with decorations, and `source` mode keeps its plain, un-tinted look. Only\n * tokens that come from a real programming-language parser get a colour.\n */\nexport const styloHighlightStyle = HighlightStyle.define([\n {\n tag: [\n t.keyword,\n t.modifier,\n t.controlKeyword,\n t.operatorKeyword,\n t.definitionKeyword,\n t.moduleKeyword,\n ],\n color: \"var(--stylo-syntax-keyword)\",\n },\n {\n tag: [t.string, t.special(t.string), t.regexp, t.attributeValue],\n color: \"var(--stylo-syntax-string)\",\n },\n { tag: [t.escape, t.character], color: \"var(--stylo-syntax-escape)\" },\n {\n tag: [t.comment, t.lineComment, t.blockComment, t.docComment],\n color: \"var(--stylo-syntax-comment)\",\n fontStyle: \"italic\",\n },\n { tag: [t.number, t.integer, t.float], color: \"var(--stylo-syntax-number)\" },\n { tag: [t.bool, t.null, t.atom, t.constant(t.name)], color: \"var(--stylo-syntax-constant)\" },\n {\n tag: [t.function(t.variableName), t.function(t.propertyName), t.macroName],\n color: \"var(--stylo-syntax-function)\",\n },\n { tag: [t.typeName, t.className, t.namespace], color: \"var(--stylo-syntax-type)\" },\n { tag: [t.propertyName, t.attributeName], color: \"var(--stylo-syntax-property)\" },\n { tag: [t.tagName], color: \"var(--stylo-syntax-tag)\" },\n { tag: [t.meta, t.annotation], color: \"var(--stylo-syntax-comment)\" },\n { tag: [t.invalid], color: \"var(--stylo-syntax-invalid)\" },\n])\n\n/** The highlight style wrapped as an editor extension. */\nexport const styloHighlighting = syntaxHighlighting(styloHighlightStyle)\n","import { EditorView } from \"@codemirror/view\"\n\n/** CodeMirror theme wired to the `--stylo-*` tokens so the host controls the palette. */\nexport const styloTheme = EditorView.theme({\n \"&\": {\n color: \"var(--stylo-text)\",\n backgroundColor: \"var(--stylo-bg)\",\n fontSize: \"0.9375rem\",\n },\n \".cm-content\": {\n fontFamily: \"ui-monospace, SFMono-Regular, Menlo, Consolas, monospace\",\n padding: \"0.75rem 0\",\n caretColor: \"var(--stylo-text)\",\n },\n \".cm-line\": {\n padding: \"0 0.75rem\",\n },\n \"&.cm-focused\": {\n outline: \"none\",\n },\n \".cm-cursor, .cm-dropCursor\": {\n borderLeftColor: \"var(--stylo-text)\",\n },\n \"&.cm-focused .cm-selectionBackground, .cm-selectionBackground, .cm-content ::selection\": {\n backgroundColor: \"color-mix(in srgb, var(--stylo-accent) 15%, transparent)\",\n },\n \".cm-placeholder\": {\n color: \"var(--stylo-text-muted)\",\n },\n \".cm-gutters\": {\n display: \"none\",\n },\n\n // --- Find / replace panel (@codemirror/search) ---\n // Overrides the library's default gradient buttons for Stylo's flat,\n // token-driven chrome. Docked at the top (see `extensions.ts`).\n \".cm-panels\": {\n background: \"var(--stylo-surface-floating, #fff)\",\n color: \"var(--stylo-text)\",\n },\n \".cm-panels.cm-panels-top\": {\n borderBottom: \"1px solid var(--stylo-border)\",\n },\n \".cm-panel.cm-search\": {\n padding: \"6px 8px\",\n font: \"inherit\",\n fontSize: \"0.8125rem\",\n },\n \".cm-panel.cm-search label\": {\n fontSize: \"0.75rem\",\n color: \"var(--stylo-text-muted)\",\n },\n \".cm-panel.cm-search .cm-textfield\": {\n padding: \"0.3em 0.5em\",\n border: \"1px solid var(--stylo-border)\",\n borderRadius: \"calc(var(--stylo-radius) - 3px)\",\n background: \"var(--stylo-bg)\",\n color: \"var(--stylo-text)\",\n fontSize: \"0.8125rem\",\n },\n \".cm-panel.cm-search .cm-textfield:focus-visible\": {\n outline: \"2px solid var(--stylo-ring)\",\n outlineOffset: \"-1px\",\n },\n \".cm-panel.cm-search .cm-button\": {\n padding: \"0.3em 0.65em\",\n border: \"1px solid var(--stylo-border)\",\n borderRadius: \"calc(var(--stylo-radius) - 3px)\",\n background: \"var(--stylo-bg)\",\n backgroundImage: \"none\",\n color: \"var(--stylo-text)\",\n fontSize: \"0.75rem\",\n cursor: \"pointer\",\n },\n \".cm-panel.cm-search .cm-button:hover\": {\n background: \"color-mix(in srgb, var(--stylo-border) 45%, transparent)\",\n },\n \".cm-panel.cm-search [name='close']\": {\n color: \"var(--stylo-text-muted)\",\n fontSize: \"1.1rem\",\n },\n \".cm-searchMatch\": {\n backgroundColor: \"color-mix(in srgb, var(--stylo-ring) 35%, transparent)\",\n borderRadius: \"2px\",\n },\n \".cm-searchMatch.cm-searchMatch-selected\": {\n backgroundColor: \"color-mix(in srgb, var(--stylo-ring) 70%, transparent)\",\n outline: \"1px solid var(--stylo-ring)\",\n },\n})\n","import { defaultKeymap, history, historyKeymap } from \"@codemirror/commands\"\nimport { markdown, markdownLanguage } from \"@codemirror/lang-markdown\"\nimport { search, searchKeymap } from \"@codemirror/search\"\nimport { EditorState, type Extension, Prec } from \"@codemirror/state\"\nimport { EditorView, keymap, placeholder as placeholderExt } from \"@codemirror/view\"\nimport { markdownKeymap } from \"../toolbar/keymap\"\nimport { tableKeymap, tableRealign } from \"../toolbar/table\"\nimport type { CodeLanguages } from \"../types\"\nimport { styloHighlighting } from \"./highlight\"\nimport { saveHandler } from \"./save\"\nimport { styloTheme } from \"./theme\"\n\n/**\n * Static extensions — created once with the view.\n *\n * `codeLanguages` is forwarded verbatim to `@codemirror/lang-markdown` for\n * fenced-code sub-highlighting. Stylo bundles none: passing the full\n * `@codemirror/language-data` grammar set emitted ~110 lazy language chunks into\n * the published package — the zero-bloat mandate inverted for a notes editor. A\n * consumer opts in with exactly the set they want. See the 2026-09-01 journal\n * note and the ADR-001 amendment.\n */\nexport function baseExtensions(codeLanguages?: CodeLanguages): Extension {\n return [\n history(),\n keymap.of([...defaultKeymap, ...historyKeymap]),\n Prec.high(tableKeymap),\n markdownKeymap,\n tableRealign,\n // Find / replace. `search` supplies the panel and its state; `searchKeymap`\n // carries in-panel navigation (`Mod-g` next, `Shift-Mod-g` previous,\n // `Mod-Alt-g` replace, `Escape` close). Opening on `Mod-f` also comes from\n // the `search` toolbar command's `keys`, so the panel opens whether or not\n // the visible toolbar is mounted. Panel docks at the top, editor-style.\n search({ top: true }),\n keymap.of(searchKeymap),\n markdown({ base: markdownLanguage, codeLanguages }),\n styloHighlighting,\n EditorView.lineWrapping,\n styloTheme,\n ]\n}\n\n/** Extensions that depend on props and are swapped via a compartment on change. */\nexport function dynamicConfig(opts: {\n readOnly: boolean\n placeholder?: string\n save?: (value: string) => void\n}): Extension {\n return [\n EditorState.readOnly.of(opts.readOnly),\n EditorView.editable.of(!opts.readOnly),\n opts.placeholder ? placeholderExt(opts.placeholder) : [],\n opts.save ? saveHandler.of(opts.save) : [],\n ]\n}\n","import { useEffect, useRef } from \"react\"\nimport { Annotation, Compartment, EditorState, type Extension, Prec } from \"@codemirror/state\"\nimport { EditorView, keymap } from \"@codemirror/view\"\nimport type { CodeLanguages } from \"../types\"\nimport { baseExtensions, dynamicConfig } from \"./extensions\"\nimport { runSave } from \"./save\"\n\n/** Marks doc changes that came from the `value` prop, so they don't echo back through `onChange`. */\nconst External = Annotation.define<boolean>()\n\nexport interface UseCodeMirrorOptions {\n value: string\n onChange: (next: string) => void\n readOnly?: boolean\n placeholder?: string\n /** Called with the doc string on `Mod-s`; suppresses the browser dialog when set. */\n onSave?: (value: string) => void\n /** Called with the `EditorView` once it is created, and with `null` on teardown. */\n onViewChange?: (view: EditorView | null) => void\n /**\n * Extra extensions merged in at construction (e.g. the in-place decoration\n * layer). Captured once — pass a stable, module-level array.\n */\n extensions?: Extension[]\n /** Fenced-code grammars, forwarded to the Markdown language. Read once. */\n codeLanguages?: CodeLanguages\n}\n\n/**\n * Owns a CodeMirror `EditorView` for the lifetime of the host element and keeps\n * it in sync with a controlled Markdown string. Returns a ref for the container.\n */\nexport function useCodeMirror({\n value,\n onChange,\n readOnly = false,\n placeholder,\n onSave,\n onViewChange,\n extensions,\n codeLanguages,\n}: UseCodeMirrorOptions) {\n const parent = useRef<HTMLDivElement | null>(null)\n const viewRef = useRef<EditorView | null>(null)\n const onChangeRef = useRef(onChange)\n onChangeRef.current = onChange\n const onSaveRef = useRef(onSave)\n onSaveRef.current = onSave\n // Stable wrapper: the facet holds this, it reads the latest handler. The\n // compartment only reconfigures when the handler's *presence* flips.\n const saveFn = useRef((value: string) => onSaveRef.current?.(value)).current\n const hasSave = onSave != null\n const onViewChangeRef = useRef(onViewChange)\n onViewChangeRef.current = onViewChange\n const dynamic = useRef(new Compartment())\n\n // Create the view once. `value` / `readOnly` / `placeholder` are reconciled by\n // the effects below; constructing here (not during render) keeps this SSR-safe.\n useEffect(() => {\n const el = parent.current\n if (!el) return\n\n const view = new EditorView({\n parent: el,\n state: EditorState.create({\n doc: value,\n extensions: [\n baseExtensions(codeLanguages),\n dynamic.current.of(\n dynamicConfig({ readOnly, placeholder, save: hasSave ? saveFn : undefined }),\n ),\n Prec.high(keymap.of([{ key: \"Mod-s\", run: runSave }])),\n ...(extensions ?? []),\n EditorView.updateListener.of((update) => {\n if (!update.docChanged) return\n if (update.transactions.some((t) => Boolean(t.annotation(External)))) return\n onChangeRef.current(update.state.doc.toString())\n }),\n ],\n }),\n })\n viewRef.current = view\n onViewChangeRef.current?.(view)\n\n return () => {\n onViewChangeRef.current?.(null)\n view.destroy()\n viewRef.current = null\n }\n }, [])\n\n // Push external `value` changes into the document without triggering `onChange`.\n useEffect(() => {\n const view = viewRef.current\n if (!view) return\n const current = view.state.doc.toString()\n if (current === value) return\n view.dispatch({\n changes: { from: 0, to: current.length, insert: value },\n annotations: External.of(true),\n })\n }, [value])\n\n // Reconfigure prop-driven extensions in place.\n useEffect(() => {\n viewRef.current?.dispatch({\n effects: dynamic.current.reconfigure(\n dynamicConfig({ readOnly, placeholder, save: hasSave ? saveFn : undefined }),\n ),\n })\n }, [readOnly, placeholder, hasSave, saveFn])\n\n return parent\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
var e = {
|
|
2
|
+
root: "_root_18e48_1",
|
|
3
|
+
source: "_source_18e48_42",
|
|
4
|
+
inplace: "_inplace_18e48_57",
|
|
5
|
+
toolbar: "_toolbar_18e48_63",
|
|
6
|
+
toolbarButton: "_toolbarButton_18e48_73",
|
|
7
|
+
toolbarSep: "_toolbarSep_18e48_125",
|
|
8
|
+
toolbarSticky: "_toolbarSticky_18e48_135",
|
|
9
|
+
toolbarStickyBottom: "_toolbarStickyBottom_18e48_135",
|
|
10
|
+
toolbarStickyTop: "_toolbarStickyTop_18e48_135",
|
|
11
|
+
toolbarStickyHidden: "_toolbarStickyHidden_18e48_194",
|
|
12
|
+
stickyToolbarRootBottom: "_stickyToolbarRootBottom_18e48_205",
|
|
13
|
+
stickyToolbarRootTop: "_stickyToolbarRootTop_18e48_210",
|
|
14
|
+
split: "_split_18e48_224",
|
|
15
|
+
splitPane: "_splitPane_18e48_231",
|
|
16
|
+
preview: "_preview_18e48_251"
|
|
17
|
+
};
|
|
18
|
+
//#endregion
|
|
19
|
+
//#region src/frontmatter.ts
|
|
20
|
+
function t(e) {
|
|
21
|
+
if (e.lines < 2 || e.line(1).text.trim() !== "---") return null;
|
|
22
|
+
for (let t = 2; t <= e.lines; t++) if (e.line(t).text.trim() === "---") return {
|
|
23
|
+
from: 0,
|
|
24
|
+
to: e.line(t).to
|
|
25
|
+
};
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
var n = /^---\r?\n(?:([\s\S]*?)\r?\n)?---[ \t]*(?:\r?\n|$)/;
|
|
29
|
+
function r(e) {
|
|
30
|
+
let t = n.exec(e);
|
|
31
|
+
return t ? {
|
|
32
|
+
frontmatter: t[1] ?? "",
|
|
33
|
+
body: e.slice(t[0].length)
|
|
34
|
+
} : null;
|
|
35
|
+
}
|
|
36
|
+
//#endregion
|
|
37
|
+
//#region src/wikilink.ts
|
|
38
|
+
var i = /\[\[([^\]|\n]+?)(?:\|([^\]\n]+?))?\]\]/g;
|
|
39
|
+
//#endregion
|
|
40
|
+
export { e as i, t as n, r, i as t };
|
|
41
|
+
|
|
42
|
+
//# sourceMappingURL=wikilink-BFpTehto.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wikilink-BFpTehto.js","names":[],"sources":["../src/styles/stylo.module.css","../src/frontmatter.ts","../src/wikilink.ts"],"sourcesContent":[".root {\n display: flex;\n flex-direction: column;\n min-height: 0;\n color: var(--stylo-text);\n background: var(--stylo-bg);\n border: 1px solid var(--stylo-border);\n border-radius: var(--stylo-radius);\n overflow: hidden;\n}\n\n/* The editing surface's own scroll container (source, in-place, and the source\n pane of split all resolve to `.cm-scroller`). Thin, token-tinted bars so the\n editor doesn't fall back to a heavier native scrollbar than the app chrome\n around it. A host's own `.cm-scroller` rules load after and win. */\n.root :global(.cm-scroller) {\n scrollbar-width: thin;\n scrollbar-color: color-mix(in srgb, var(--stylo-border) 90%, transparent) transparent;\n}\n\n.root :global(.cm-scroller)::-webkit-scrollbar {\n width: 10px;\n height: 10px;\n}\n\n.root :global(.cm-scroller)::-webkit-scrollbar-thumb {\n border: 3px solid transparent;\n border-radius: 6px;\n background: color-mix(in srgb, var(--stylo-border) 90%, transparent);\n background-clip: padding-box;\n}\n\n.root :global(.cm-scroller)::-webkit-scrollbar-thumb:hover {\n background: color-mix(in srgb, var(--stylo-text-muted) 55%, transparent);\n background-clip: padding-box;\n}\n\n.root :global(.cm-scroller)::-webkit-scrollbar-corner {\n background: transparent;\n}\n\n.source {\n flex: 1 1 auto;\n min-height: 0;\n overflow: auto;\n}\n\n.source :global(.cm-editor) {\n height: 100%;\n}\n\n.source :global(.cm-editor.cm-focused) {\n outline: 2px solid var(--stylo-ring);\n outline-offset: -2px;\n}\n\n.inplace {\n flex: 1 1 auto;\n min-height: 0;\n overflow: auto;\n}\n\n.toolbar {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 2px;\n padding: 4px 6px;\n background: var(--stylo-bg);\n border-bottom: 1px solid var(--stylo-border);\n}\n\n.toolbarButton {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n box-sizing: border-box;\n min-width: 28px;\n height: 28px;\n padding: 0 5px;\n border: 0;\n border-radius: calc(var(--stylo-radius) - 3px);\n background: none;\n color: var(--stylo-text-muted);\n font: inherit;\n font-size: 0.75rem;\n font-weight: 600;\n line-height: 1;\n cursor: pointer;\n}\n\n.toolbarButton:hover:not(:disabled) {\n background: color-mix(in srgb, var(--stylo-border) 45%, transparent);\n color: var(--stylo-text);\n}\n\n.toolbarButton[data-active] {\n background: color-mix(in srgb, var(--stylo-accent) 12%, transparent);\n color: var(--stylo-text);\n}\n\n.toolbarButton:disabled {\n opacity: 0.4;\n cursor: default;\n}\n\n.toolbarButton:focus-visible {\n outline: 2px solid var(--stylo-ring);\n outline-offset: -2px;\n}\n\n.toolbarButton svg {\n display: block;\n width: 16px;\n height: 16px;\n}\n\n/* Text glyphs that stand in for an icon (e.g. `fm`) — monospace to read as syntax. */\n.toolbarButton code {\n font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\n font-size: 0.8125rem;\n font-weight: 500;\n}\n\n.toolbarSep {\n align-self: stretch;\n width: 1px;\n margin: 4px 3px;\n background: var(--stylo-border);\n}\n\n/* `toolbar={{ sticky: \"top\" | \"bottom\" | true }}` — pins the bar to an edge\n instead of wherever `<Stylo>` sits on the page. One row, no wrapping: it\n scrolls horizontally instead, and its buttons grow to a comfortable touch\n size. Shared by both edges; `.toolbarStickyTop` / `.toolbarStickyBottom`\n below pick the positioning mechanism and the edge itself. */\n.toolbarSticky {\n z-index: 50;\n flex-wrap: nowrap;\n overflow-x: auto;\n -webkit-overflow-scrolling: touch;\n scrollbar-width: none;\n transition: opacity 0.15s ease;\n /* The base `.toolbar` deliberately leaves font-family to inherit from\n wherever the host mounts `<Stylo>`. Both sticky edges are\n `position: fixed` against the window, so neither can safely lean on\n that — an explicit stack instead of the browser's serif default. */\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Helvetica, Arial, sans-serif;\n}\n\n.toolbarSticky::-webkit-scrollbar {\n display: none;\n}\n\n.toolbarSticky .toolbarButton {\n min-width: 40px;\n height: 40px;\n flex: 0 0 auto;\n}\n\n/* `\"bottom\"` (or `true`) — has to be `position: fixed`: nothing about a\n mobile keyboard opening is a \"scroll\", so `position: sticky` has nothing to\n react to. Toolbar.tsx nudges it up from `bottom: 0` with\n `transform: translateY()`, tracking `useKeyboardInset`. */\n.toolbarStickyBottom {\n position: fixed;\n left: 0;\n right: 0;\n bottom: 0;\n border-bottom: none;\n border-top: 1px solid var(--stylo-border);\n box-shadow: 0 -2px 8px color-mix(in srgb, var(--stylo-text) 10%, transparent);\n}\n\n/* `\"top\"` — `position: fixed`, always pinned rather than waiting for a scroll\n threshold like `\"bottom\"`. Nothing ever eats into the top of the screen, so\n there's no keyboard to react to and no accessory bar to collide with — the\n two problems `\"bottom\"` has. `Toolbar.tsx`'s `useFloatingWatchdog` (a\n `requestAnimationFrame` loop, not CSS) is what actually keeps it visible on\n iOS Safari: earlier rounds tried a static `translateZ(0)`, then real\n `position: sticky`, and the disappear-on-scroll bug outlived both — a value\n that's set once and never re-touched gives the browser's compositor nothing\n to recompute if it drifts, so the watchdog re-asserts a `transform` every\n frame instead of trusting a one-time fix to hold. */\n.toolbarStickyTop {\n position: fixed;\n left: 0;\n right: 0;\n top: 0;\n box-shadow: 0 2px 8px color-mix(in srgb, var(--stylo-text) 10%, transparent);\n}\n\n/* `stickyVisibility: \"dynamic\"` — faded out while nothing is focused. */\n.toolbarStickyHidden {\n opacity: 0;\n pointer-events: none;\n}\n\n/* `\"bottom\"` is `position: fixed`, out of flow entirely — reserve its resting\n height so it doesn't sit over the document's last line. Static, not\n keyboard-aware: while the keyboard is open the bar rides up to meet it (see\n `useKeyboardInset`), but the browser's own scroll-into-view around the\n caret is what keeps typing visible above both — this padding only covers\n the keyboard-closed resting state. */\n.stickyToolbarRootBottom .source,\n.stickyToolbarRootBottom .inplace {\n padding-bottom: 52px;\n}\n\n.stickyToolbarRootTop .source,\n.stickyToolbarRootTop .inplace {\n padding-top: 52px;\n}\n\n.inplace :global(.cm-editor) {\n height: 100%;\n}\n\n.inplace :global(.cm-editor.cm-focused) {\n outline: 2px solid var(--stylo-ring);\n outline-offset: -2px;\n}\n\n.split {\n display: grid;\n grid-template-columns: 1fr 1fr;\n flex: 1;\n min-height: 0;\n}\n\n.splitPane {\n display: flex;\n flex-direction: column;\n min-height: 0;\n overflow: auto;\n box-sizing: border-box;\n}\n\n.splitPane + .splitPane {\n border-left: 1px solid var(--stylo-border);\n}\n\n.splitPane > .source {\n flex: 1;\n min-height: 0;\n}\n\n/* Vertical rhythm follows Tailwind's `prose` (@tailwindcss/typography) as a\n visual reference — the em-based scale only, no plugin bundled. Consumer CSS\n wins: `.stylo p`, `.stylo h2`, … load after and match our specificity. */\n.preview {\n padding: 0.75rem 1rem;\n font-size: 0.9375rem;\n line-height: 1.75;\n overflow-wrap: break-word;\n}\n\n.preview > :first-child {\n margin-top: 0;\n}\n\n.preview > :last-child {\n margin-bottom: 0;\n}\n\n.preview :is(h1, h2, h3, h4, h5, h6) {\n font-weight: 600;\n}\n\n.preview h1 {\n margin: 0 0 0.8888889em;\n font-size: 2.25em;\n line-height: 1.1111111;\n}\n\n.preview h2 {\n margin: 2em 0 1em;\n font-size: 1.5em;\n line-height: 1.3333333;\n}\n\n.preview h3 {\n margin: 1.6em 0 0.6em;\n font-size: 1.25em;\n line-height: 1.6;\n}\n\n.preview :is(h4, h5, h6) {\n margin: 1.5em 0 0.5em;\n line-height: 1.5;\n}\n\n.preview p {\n margin: 1.25em 0;\n}\n\n.preview :is(ul, ol) {\n margin: 1.25em 0;\n padding-left: 1.625em;\n}\n\n.preview li {\n margin: 0.5em 0;\n}\n\n.preview li > :is(ul, ol) {\n margin: 0.75em 0;\n}\n\n.preview a {\n color: var(--stylo-link);\n text-decoration: none;\n}\n\n.preview code {\n font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\n font-size: 0.9em;\n padding: 0.1em 0.35em;\n border-radius: calc(var(--stylo-radius) - 3px);\n background: color-mix(in srgb, var(--stylo-border) 45%, transparent);\n}\n\n.preview pre {\n margin: 1.7142857em 0;\n padding: 0.75rem 0.9rem;\n border-radius: var(--stylo-radius);\n background: color-mix(in srgb, var(--stylo-border) 35%, transparent);\n overflow-x: auto;\n}\n\n.preview pre code {\n padding: 0;\n font-size: 0.85em;\n background: none;\n}\n\n/* frontmatter=\"code\": the raw `---` block, recessed. `.stylo-frontmatter` is a\n plain (unscoped) class so a consumer's own CSS overrides it at equal\n specificity — restyle the block, or rename / remove the label:\n .stylo-frontmatter::before { content: \"Meta\" }\n .stylo-frontmatter::before { content: none } */\n:global(.stylo-frontmatter) {\n margin: 0 0 1.2em;\n padding: 0.7rem 0.9rem;\n border-left: 3px solid var(--stylo-border);\n border-radius: calc(var(--stylo-radius) - 3px);\n background: color-mix(in srgb, var(--stylo-border) 22%, transparent);\n color: var(--stylo-text-muted);\n font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\n font-size: 0.8125rem;\n line-height: 1.5;\n white-space: pre-wrap;\n overflow-x: auto;\n}\n\n:global(.stylo-frontmatter)::before {\n content: \"Frontmatter\";\n display: block;\n margin-bottom: 0.5em;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Helvetica, Arial, sans-serif;\n font-size: 0.7rem;\n font-weight: 600;\n letter-spacing: 0.04em;\n text-transform: uppercase;\n}\n\n.preview blockquote {\n margin: 1.6em 0;\n padding-left: 1em;\n border-left: 0.25rem solid var(--stylo-border);\n color: var(--stylo-text-muted);\n}\n\n/* Obsidian callouts (`> [!note]`) — mirrors the in-place canvas. `remark-callout`\n adds `stylo-callout stylo-callout-<bucket>` + `data-callout`. Override\n `--stylo-callout-<bucket>` (or `--stylo-callout-accent` per type) to reskin. */\n.preview :global(.stylo-callout) {\n margin: 1.6em 0;\n padding: 0.6em 1em;\n border-left: 0.25rem solid var(--stylo-callout-accent, var(--stylo-border));\n border-radius: var(--stylo-radius);\n background: color-mix(in srgb, var(--stylo-callout-accent, var(--stylo-border)) 10%, transparent);\n color: var(--stylo-text);\n}\n.preview :global(.stylo-callout)::before {\n content: attr(data-callout);\n display: block;\n margin-bottom: 0.2em;\n font-size: 0.8em;\n font-weight: 700;\n letter-spacing: 0.04em;\n text-transform: uppercase;\n color: var(--stylo-callout-accent, var(--stylo-text-muted));\n}\n.preview :global(.stylo-callout-note) {\n --stylo-callout-accent: var(--stylo-callout-note, #3b82f6);\n}\n.preview :global(.stylo-callout-tip) {\n --stylo-callout-accent: var(--stylo-callout-tip, #22c55e);\n}\n.preview :global(.stylo-callout-warn) {\n --stylo-callout-accent: var(--stylo-callout-warn, #f59e0b);\n}\n.preview :global(.stylo-callout-danger) {\n --stylo-callout-accent: var(--stylo-callout-danger, #ef4444);\n}\n.preview :global(.stylo-callout-example) {\n --stylo-callout-accent: var(--stylo-callout-example, #a855f7);\n}\n\n.preview table {\n display: block;\n margin: 2em 0;\n border-collapse: collapse;\n overflow-x: auto;\n}\n\n.preview :is(th, td) {\n padding: 0.35em 0.6em;\n border: 1px solid var(--stylo-table-border);\n text-align: left;\n}\n\n.preview thead th {\n background: var(--stylo-table-header-bg);\n font-weight: 600;\n}\n\n/* Opt-in zebra striping — no-op until the host sets `--stylo-table-stripe-bg`. */\n.preview tbody tr:nth-child(even) td {\n background: var(--stylo-table-stripe-bg);\n}\n\n/* prose sets `hr { margin: 3em 0 }`, which reads as a page break, not a rule.\n GitHub / VS Code render it tight; `1em` each side matches that. */\n.preview hr {\n margin: 1em 0;\n border: none;\n border-top: 1px solid var(--stylo-border);\n}\n\n.preview :global(.katex-display) {\n padding: 0.25em 0;\n overflow-x: auto;\n overflow-y: hidden;\n}\n","import type { Text } from \"@codemirror/state\"\n\n/**\n * The leading `---` … `---` YAML block, if present. The CodeMirror Markdown\n * grammar has no frontmatter node — it parses the fences as two thematic breaks\n * — so the region is located by hand. Shared by the in-place decoration layer\n * and the toolbar's frontmatter command.\n */\nexport function frontmatterRange(doc: Text): { from: number; to: number } | null {\n if (doc.lines < 2 || doc.line(1).text.trim() !== \"---\") return null\n for (let n = 2; n <= doc.lines; n++) {\n if (doc.line(n).text.trim() === \"---\") return { from: 0, to: doc.line(n).to }\n }\n return null\n}\n\nconst FRONTMATTER_BLOCK = /^---\\r?\\n(?:([\\s\\S]*?)\\r?\\n)?---[ \\t]*(?:\\r?\\n|$)/\n\n/**\n * Split a leading `---` … `---` block off a Markdown string. `frontmatter` is\n * the inner text (`\"\"` for an empty block); `body` is everything after the\n * closing fence. Used by `preview` to render the block instead of dropping it.\n */\nexport function splitFrontmatter(md: string): { frontmatter: string; body: string } | null {\n const m = FRONTMATTER_BLOCK.exec(md)\n return m ? { frontmatter: m[1] ?? \"\", body: md.slice(m[0].length) } : null\n}\n","/**\n * `[[target]]` or `[[target|label]]`. Capture group 1 is the target, group 2 the\n * optional display label. The `g` flag is set for `matchAll` / `exec` loops;\n * callers that keep the regex across calls must reset `lastIndex` (or use\n * `matchAll`, which is stateless).\n *\n * Single source of truth for both the render-side plugin (`remark-wikilink`) and\n * the in-place decoration scanner, so the two never drift.\n */\nexport const WIKILINK_PATTERN = /\\[\\[([^\\]|\\n]+?)(?:\\|([^\\]\\n]+?))?\\]\\]/g\n"],"mappings":";;;;;;;;;;;;;;;;;;;ACQA,SAAgB,EAAiB,GAAgD;CAC/E,IAAI,EAAI,QAAQ,KAAK,EAAI,KAAK,CAAC,CAAC,CAAC,KAAK,KAAK,MAAM,OAAO,OAAO;CAC/D,KAAK,IAAI,IAAI,GAAG,KAAK,EAAI,OAAO,KAC9B,IAAI,EAAI,KAAK,CAAC,CAAC,CAAC,KAAK,KAAK,MAAM,OAAO,OAAO;EAAE,MAAM;EAAG,IAAI,EAAI,KAAK,CAAC,CAAC,CAAC;CAAG;CAE9E,OAAO;AACT;AAEA,IAAM,IAAoB;AAO1B,SAAgB,EAAiB,GAA0D;CACzF,IAAM,IAAI,EAAkB,KAAK,CAAE;CACnC,OAAO,IAAI;EAAE,aAAa,EAAE,MAAM;EAAI,MAAM,EAAG,MAAM,EAAE,EAAE,CAAC,MAAM;CAAE,IAAI;AACxE;;;ACjBA,IAAa,IAAmB"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `[[target]]` or `[[target|label]]`. Capture group 1 is the target, group 2 the
|
|
3
|
+
* optional display label. The `g` flag is set for `matchAll` / `exec` loops;
|
|
4
|
+
* callers that keep the regex across calls must reset `lastIndex` (or use
|
|
5
|
+
* `matchAll`, which is stateless).
|
|
6
|
+
*
|
|
7
|
+
* Single source of truth for both the render-side plugin (`remark-wikilink`) and
|
|
8
|
+
* the in-place decoration scanner, so the two never drift.
|
|
9
|
+
*/
|
|
10
|
+
export declare const WIKILINK_PATTERN: RegExp;
|
|
11
|
+
//# sourceMappingURL=wikilink.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wikilink.d.ts","sourceRoot":"","sources":["../src/wikilink.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,eAAO,MAAM,gBAAgB,QAA4C,CAAA"}
|
package/package.json
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@damiro/stylo",
|
|
3
|
+
"version": "0.4.0",
|
|
4
|
+
"description": "A plain-text-first Markdown editor for React, with first-class LaTeX (KaTeX) support.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"author": "damiro",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/studiodamiro/stylo.git"
|
|
11
|
+
},
|
|
12
|
+
"homepage": "https://github.com/studiodamiro/stylo#readme",
|
|
13
|
+
"bugs": "https://github.com/studiodamiro/stylo/issues",
|
|
14
|
+
"keywords": [
|
|
15
|
+
"react",
|
|
16
|
+
"markdown",
|
|
17
|
+
"editor",
|
|
18
|
+
"codemirror",
|
|
19
|
+
"katex",
|
|
20
|
+
"latex",
|
|
21
|
+
"wikilinks",
|
|
22
|
+
"obsidian"
|
|
23
|
+
],
|
|
24
|
+
"sideEffects": [
|
|
25
|
+
"*.css"
|
|
26
|
+
],
|
|
27
|
+
"files": [
|
|
28
|
+
"dist"
|
|
29
|
+
],
|
|
30
|
+
"exports": {
|
|
31
|
+
".": {
|
|
32
|
+
"types": "./dist/index.d.ts",
|
|
33
|
+
"import": "./dist/stylo.js"
|
|
34
|
+
},
|
|
35
|
+
"./toolbar-settings": {
|
|
36
|
+
"types": "./dist/toolbar-settings/index.d.ts",
|
|
37
|
+
"import": "./dist/toolbar-settings.js"
|
|
38
|
+
},
|
|
39
|
+
"./styles.css": "./dist/styles.css",
|
|
40
|
+
"./katex.css": "./dist/katex.css"
|
|
41
|
+
},
|
|
42
|
+
"publishConfig": {
|
|
43
|
+
"access": "public"
|
|
44
|
+
},
|
|
45
|
+
"scripts": {
|
|
46
|
+
"dev": "vite",
|
|
47
|
+
"typecheck": "tsc --noEmit",
|
|
48
|
+
"check:theme": "node scripts/check-theme-tokens.mjs",
|
|
49
|
+
"check:size": "node scripts/check-bundle-size.mjs",
|
|
50
|
+
"test": "vitest run",
|
|
51
|
+
"test:watch": "vitest",
|
|
52
|
+
"build": "vite build && tsc -p tsconfig.build.json && cp katex.css dist/katex.css",
|
|
53
|
+
"prepare": "npm run build",
|
|
54
|
+
"format": "prettier --write .",
|
|
55
|
+
"format:check": "prettier --check ."
|
|
56
|
+
},
|
|
57
|
+
"peerDependencies": {
|
|
58
|
+
"@codemirror/commands": "^6.0.0",
|
|
59
|
+
"@codemirror/lang-markdown": "^6.0.0",
|
|
60
|
+
"@codemirror/language": "^6.0.0",
|
|
61
|
+
"@codemirror/state": "^6.0.0",
|
|
62
|
+
"@codemirror/view": "^6.0.0",
|
|
63
|
+
"@dnd-kit/core": "^6.0.0",
|
|
64
|
+
"@dnd-kit/sortable": "^10.0.0",
|
|
65
|
+
"@dnd-kit/utilities": "^3.2.0",
|
|
66
|
+
"@lezer/common": "^1.0.0",
|
|
67
|
+
"@lezer/highlight": "^1.0.0",
|
|
68
|
+
"react": ">=18",
|
|
69
|
+
"react-dom": ">=18"
|
|
70
|
+
},
|
|
71
|
+
"peerDependenciesMeta": {
|
|
72
|
+
"@dnd-kit/core": {
|
|
73
|
+
"optional": true
|
|
74
|
+
},
|
|
75
|
+
"@dnd-kit/sortable": {
|
|
76
|
+
"optional": true
|
|
77
|
+
},
|
|
78
|
+
"@dnd-kit/utilities": {
|
|
79
|
+
"optional": true
|
|
80
|
+
}
|
|
81
|
+
},
|
|
82
|
+
"engines": {
|
|
83
|
+
"node": ">=18"
|
|
84
|
+
},
|
|
85
|
+
"dependencies": {
|
|
86
|
+
"@codemirror/search": "^6.7.2",
|
|
87
|
+
"katex": "^0.16.47",
|
|
88
|
+
"react-markdown": "^10.1.0",
|
|
89
|
+
"rehype-katex": "^7.0.1",
|
|
90
|
+
"remark-frontmatter": "^5.0.0",
|
|
91
|
+
"remark-gfm": "^4.0.1",
|
|
92
|
+
"remark-math": "^6.0.0",
|
|
93
|
+
"unist-util-visit": "^5.1.0"
|
|
94
|
+
},
|
|
95
|
+
"devDependencies": {
|
|
96
|
+
"@codemirror/commands": "^6.11.0",
|
|
97
|
+
"@codemirror/lang-markdown": "^6.5.2",
|
|
98
|
+
"@codemirror/language": "^6.12.4",
|
|
99
|
+
"@codemirror/language-data": "^6.5.2",
|
|
100
|
+
"@codemirror/state": "^6.7.2",
|
|
101
|
+
"@codemirror/view": "^6.43.10",
|
|
102
|
+
"@dnd-kit/core": "^6.3.1",
|
|
103
|
+
"@dnd-kit/sortable": "^10.0.0",
|
|
104
|
+
"@dnd-kit/utilities": "^3.2.2",
|
|
105
|
+
"@lezer/common": "^1.5.2",
|
|
106
|
+
"@lezer/highlight": "^1.2.3",
|
|
107
|
+
"@testing-library/jest-dom": "^6.9.1",
|
|
108
|
+
"@testing-library/react": "^16.3.3",
|
|
109
|
+
"@types/mdast": "^4.0.4",
|
|
110
|
+
"@types/node": "^26.4.0",
|
|
111
|
+
"@types/react": "^19.2.18",
|
|
112
|
+
"@types/react-dom": "^19.2.5",
|
|
113
|
+
"@vitejs/plugin-react": "^6.1.1",
|
|
114
|
+
"jsdom": "^29.1.1",
|
|
115
|
+
"prettier": "^3.9.6",
|
|
116
|
+
"react": "^19.2.8",
|
|
117
|
+
"react-dom": "^19.2.8",
|
|
118
|
+
"typescript": "^7.0.2",
|
|
119
|
+
"vite": "^8.2.2",
|
|
120
|
+
"vitest": "^4.1.11"
|
|
121
|
+
}
|
|
122
|
+
}
|