Skip to content

Releases: liminisapp/liminis-editor

v0.7.0

Choose a tag to compare

@verveguy verveguy released this 05 Oct 11:13
c794846

A breaking release. It moves to Lexical 0.52 and Mermaid 12, and fixes a data-loss bug that affects fresh installs of 0.6.0.

Breaking

  • Lexical 0.52. All twelve Lexical peer ranges move from ^0.49.0 to ^0.52.0. The ranges don't overlap, so you must upgrade your whole Lexical family to 0.52 before taking this release.
    • If your own code uses Lexical directly, Lexical 0.50–0.52 have breaking changes of their own. The ones most likely to affect an editor host:
      • SELECTION_CHANGE_COMMAND now runs before DOM reconciliation (0.52).
      • Packages are ESM-only (0.51).
      • LexicalNode.getCommonAncestor was removed (0.52).
    • The editor adapts to the selection-timing change internally. It also keeps one copy/paste behaviour from 0.6.0: pasted text never brings annotation marks with it, which from Lexical 0.50 it otherwise would.
  • Mermaid 12 raises the browser floor to ES2024 / Safari 17.4+. Diagrams look exactly as before: the editor pins mermaid's previous dagre layout and classic look, so existing documents don't re-lay out or restyle.

Fixed

  • Data loss on save with newer mdast-util-to-markdown. mdast-util-to-markdown is pinned to exactly 2.1.2.
    • From 2.1.3, an underscore typed next to a backslash escape preserved from the source was saved unescaped, and the document re-opened with that text as emphasis.
    • 0.6.0 declared ^2.1.2, so a fresh install of 0.6.0 today resolves 2.2.0 and is affected. Upgrade to 0.7.0.
    • Lifting the pin is tracked in #157.

Changed

  • Runtime dependency floors raised: lucide-react ^1.49.0, yaml ^2.9.1, zod ^4.6.5.
  • @liminis/diagrams ^0.1.6 (metadata only).
  • The documentation site now runs on Astro 7 / Starlight 0.42.

Known gaps

  • IME composition wasn't manually validated against Lexical 0.52 for this release (#162). The rest of the hands-on pass found no regressions against 0.6.0.
  • Two existing quirks were found during that pass, neither new in 0.7.0: #160 and #161.

Full notes: CHANGELOG.md.

v0.6.0 — block anchors render as badges

Choose a tag to compare

@verveguy verveguy released this 11 Sep 03:04
40c24f2

Writing ^id at the end of a line marks that block with an anchor, and the editor now renders it as a badge rather than raw text. This is the definition site for the block-scoped links and transclusion added in 0.5.0 — [[file#^id]] and ![[file#^id]] address exactly these anchors.

Issues: #122, #124, #126, #127.

The id is an opaque token

ULIDs, raw-decimal snowflakes, NanoIDs (including _ and -), UUID-shaped ids, base62 and short alphanumeric ids (^a1b2c3) all badge. There is no length or charset rule to satisfy.

Position is the disambiguator, not the id's shape: the caret must start a token (line start, or preceded by whitespace) and the id must run to end of line. Ordinary prose is left alone — 2^10, 10^100, mc^2 and a ^ b are never badged, mid-line or at a line's end. Carets inside inline code, fenced blocks and MathJax are untouched by construction, not by special-casing.

An anchor may be wrapped in symmetric emphasis — **^id**, __^id__, *^id*, _^id_ — badging the id without the wrapper characters.

A reference written mid-sentence (![[file#^id]]) is a wiki-link and has always resolved independently of position. Unchanged.

Requires a matching host resolver

This is half a change. For ![[file#^id]] to resolve an anchor this editor badges, the embedding application's resolveTransclusion() must use an agreeing anchor rule. The Liminis app's resolver was widened in step (shadoworg/liminis-notes#1114). Other hosts should match:

/(?:^|\s)(?:(\*\*|__|\*|_)\^([^\s\]#*]+?)\1|\^([^\s\]#*]+))\s*$/

Both sides are pinned against a shared case table (src/markdown/__tests__/blockAnchorCases.ts) so they cannot drift silently. A host on an older resolver will show badges it cannot resolve.

Known limitations

  • A bare number alone at end of line preceded by whitespace (^100), or wrapped in emphasis (*^2*), is badged. Accepted rather than filtered: any minimum-length rule excluding it would also exclude legitimate short ids like ^a1b2c3. Real mathematics is written in MathJax ($x^2$) and excluded structurally.
  • Asymmetric wrappers (**^id_) and non-emphasis wrappers (~~…~~, backticks, parentheses) are not recognised.

Why 0.6.0 and not 0.5.1

Nothing here has ever been published — 0.5.0's dist contains no blockAnchor at all — so nothing can break. The minor is deliberate: every feature release in this repo has been one, and more importantly ^0.5.0 would let a routine lockfile refresh adopt this without anyone choosing to. Editor and resolver need to move together.

v0.5.0 — block-scoped links and transclusion

Choose a tag to compare

@verveguy verveguy released this 09 Sep 16:20
ea893a7

Adds Obsidian-style block references, and live transclusion of the block they point at. Purely additive — existing wiki-links are untouched.

[[file#^id]] — link to a block, not a file

A wiki-link can now target one specific block inside a file rather than the file as a whole, using the Obsidian block-reference form. [[notes#^01ABC]] opens notes scoped to that block; [[notes#^01ABC|see this]] does the same with an alias.

![[file#^id]] — transclude it

The ! form renders that block's live, current content inline at the reference site, so edits to the source show up on the next render rather than being copied once.

This needs one new optional host service:

resolveTransclusion(file: string, blockId: string): Promise<string | null>

See docs/editor-api.md. If you inject nothing, or your resolver can't find the reference, the editor renders a clearly marked "unresolved" placeholder — it does not throw. A transclusion cycle is detected and rendered as a "circular transclusion" indicator rather than hanging, and nesting is bounded to a depth of 8.

See ADR-119 for the design, including why the ! marker is detected by sentinel substitution ahead of the wiki-link extension, and how fenced and inline code spans are protected from it.

One known limitation, recorded rather than hidden

[[notes.md#^01ABC]] — a block reference whose target carries an explicit .md extension — round-trips to [[notes#^01ABC|notes.md]], moving the extension into an alias. The content survives and the link still resolves; the source text changes shape once. It is pinned by a known-defects round-trip fixture, so a future fix will show up as a fixture change rather than a surprise.

Nothing else changed for consumers

The export surface is identical. TransclusionNode is registered in editorNodes, and ./nodes exports that array, so a headless consumer building its own editor picks it up with no code change.

scripts/check-lockfile-drift.mjs also landed since 0.4.1 — a weekly check that fails when this repo's lockfile pins a first-party dependency behind what its range already allows. It ships nothing and changes nothing for consumers; it exists because that gap silently withheld three separate fixes in one week.

Upgrading

pnpm add @liminis/editor@^0.5.0

Nothing to change. Implement resolveTransclusion only if you want ![[file#^id]] to render live content.

v0.4.1 — @liminis/diagrams 0.1.5

Choose a tag to compare

@verveguy verveguy released this 26 Aug 19:09
cb43f70

A patch release. No API change; one dependency bump with effects you can see.

C4 diagram SVG is now deterministic across platforms

@liminis/diagrams moves to ^0.1.5, and 0.1.2 is the reason to take it: renderC4DiagramToSVG produced different bytes on macOS and on Linux for the same input and the same version.

This package re-exports that function from @liminis/diagrams/server, so the inconsistency was passed straight through to anyone rendering diagrams server-side. If you snapshot or hash rendered SVG, output may differ once from your stored value, and be stable after that.

0.1.3 also fixes diagrams rendering clipped — an auto-layout viewBox that did not contain the diagram when an element outside a System_Boundary related to something inside it — and adds zoom controls.

Why this had not already reached you: the declared range was ^0.1.1, which admits these releases, but the lockfile pinned 0.1.1. The range now states the minimum so a stale lockfile cannot quietly drift back. (#116)

0.1.4 and 0.1.5 add /playground and /remark subpaths, which this package does not use — they arrive as unused surface, not as behaviour.

Not in this release

Five of the six merges since 0.4.0 built an Astro documentation site with live C4 embedding. It lives in site/ and is not part of the published tarball — verified by packing: 378K here against 0.4.0's 372K.

Upgrading

pnpm add @liminis/editor@^0.4.1

Nothing to change.

v0.4.0 — token inversion, C4 extracted to @liminis/diagrams

Choose a tag to compare

@verveguy verveguy released this 23 Aug 20:30
9843b80

One breaking change, plus an extraction and a fix that ride along.

Breaking: setting a legacy token name no longer themes the editor

0.3.0 defined --liminis-editor-* names, but as aliases pointing at the legacy names — the real values still lived on --vscode-* / --slashmd-* / --color-* / --checkbox-*.

That is now inverted. --liminis-editor-* carries the values; the legacy names are read-only shims.

  • Reading a legacy name still works — var(--vscode-foreground) resolves as before.
  • Setting one no longer has any effect. A host that themes the editor by declaring --vscode-foreground must declare --liminis-editor-foreground instead.

That second point is the breaking part, and it fails silently — an unresolved custom property drops its declaration rather than erroring, so a host on legacy overrides sees subtly wrong colours with a green build. Check your theming after upgrading. This completes the deprecation announced in 0.2.0.

--slashmd-* is removed entirely (no consumer read it). --liminis-editor-primary now carries a real value rather than forwarding a token this package never defined. See ADR-98.

The C4 subsystem now comes from @liminis/diagrams

src/app/editor/c4/ is gone; the parser, layout engine and renderer are consumed from the published package, so the same code no longer exists in two places.

The exported API is unchanged — verified by diffing all six subpaths against 0.3.0: 129 exports, 0 added, 0 removed. index.ts and headless.ts re-export the same names from the package instead of local files.

@liminis/diagrams is a new runtime dependency. Your install grows a package even though nothing you import changes. (#100)

Fixed: C4 diagrams can be dragged on touch devices

The dependency is ^0.1.1, which replaces a mouse-only drag path with pointer events. Under 0.1.0 a C4 node could not be dragged on iPad at all — the browser claimed the gesture as a scroll and the page panned instead. (#109)

Also

The editor's history before 2026-08-03 is now reachable from this repository. It was extracted from verveguy/liminis by copying the tree, so seven months of provenance sat only in the other repo; a merge brings it in without rewriting anything, so every prior tag and its attestations remain valid. Note git blame still stops at the extraction — see CLAUDE.md. (#103)

Upgrading

pnpm add @liminis/editor@^0.4.0

If you override editor tokens, move those declarations from the legacy names to --liminis-editor-*. If you only read them, nothing to do.

v0.3.0 — Lexical 0.49, defined --liminis-editor-* aliases

Choose a tag to compare

@verveguy verveguy released this 21 Aug 19:22
4714f88

One breaking change, one addition, one fix — bundled deliberately so consumers take a single coordinated upgrade.

Breaking: Lexical peer range is now ^0.49.0

lexical and all eleven @lexical/* packages move from ^0.44.0 to ^0.49.0. The ranges do not overlap — a host on Lexical 0.44–0.48 must move its own Lexical family to 0.49 to install this version.

Lexical is a 0.x package, so ^0.44.0 resolved to >=0.44.0 <0.45.0 and excluded every 0.45+ release regardless of whether it was actually breaking. That pinned every host five minors behind with no published path forward.

The devDependencies move with the peers, so the version CI tests and the version the package promises are now the same thing. Whether to widen this into a band was considered and rejected: a 0.x range claiming six minors would assert compatibility nothing tests. The policy — bump the peer range with each adopted Lexical minor — is recorded in ADR-92. (#92)

Added: --liminis-editor-* names are now defined

Previously the package consumed --liminis-editor-* but defined only the legacy --vscode-* / --slashmd-* / --color-* / --checkbox-* names, so a host could override the new vocabulary but could not read it.

All 65 are now declared as aliases of their legacy counterparts:

:root { --liminis-editor-foreground: var(--vscode-foreground); }

Declaring them with literal values instead would have silently disabled the fallback layer from ADR-087 — every consumption chain would resolve at its first arm and stop honouring hosts that supply legacy names. Aliasing avoids that: hosts on legacy names keep working, hosts setting the new names win, and hosts reading the new names now get a value.

One documented limitation: because aliases are declared at the document root, a legacy override applied to a descendant element is not reflected through them. Both behaviours are pinned by e2e tests. See ADR-93. (#93)

Fixed: the editor no longer steals focus on every reload

CursorRestorePlugin called rootElement.focus() unconditionally on any contentVersion bump, so a reload the user did not initiate — an agent writing the file underneath them, for instance — pulled the caret into the editor. Focus is now restored only if the editor already had it. (#96)

Upgrading

pnpm add @liminis/editor@^0.3.0
pnpm add lexical@^0.49.0 @lexical/react@^0.49.0   # …and the rest of the family

Theming needs no change. If you want to migrate reads onto --liminis-editor-*, that is now possible for the first time.

v0.2.2 — markdown-derived outline, defined-token guard

Choose a tag to compare

@verveguy verveguy released this 20 Aug 11:51
a31e350

A patch release. Additive and documentation only — no behaviour is removed.

DocumentOutline works without a Lexical editor

deriveOutlineFromMarkdown(markdown) and resolveActiveOutlineIndex(entries, line) are now exported, and entries carry a 1-based source line.

0.2.0 derived outline entries from live Lexical state, which meant an outline was only possible where an editor was mounted — a host with a raw markdown mode had no data source at all. Deriving from markdown serves both, and the line numbers let a raw view track the active heading by line. The existing Lexical path is unchanged. (#84, ADR-091)

The tokens this package defines are public API

Hosts read them — not just override them — so renaming or removing a definition is a breaking change, distinct from renaming a consumption site. This is now stated in the README and guarded by a checked-in baseline (scripts/lib/theming-defined-tokens-baseline.json), so a removed or renamed declaration fails CI instead of silently dropping a downstream consumer's palette.

The guard catches a same-count rename masked by an unchanged total, and a token declared outside :root. (#79, ADR-092)

The 0.2.0 record, corrected

getMarkRects shipped under "Added" in 0.2.0. It is additive at runtime, but as a required member of AnnotationEditorHandle it is a compile-time break for anything that implements, constructs or type-checks against that interface. The 0.2.0 entry now says so, with the one-line fix. (#78)

Also

  • CLAUDE.md records this repository's conventions, including ADR naming (adr-<issue>-<slug>.md) after two parallel issues independently produced the same ADR number.

Upgrading

pnpm add @liminis/editor@^0.2.2

Nothing to change. ^0.2.0 already admits this release.

v0.2.1 — App forwards documentOutlineHandle

Choose a tag to compare

@verveguy verveguy released this 19 Aug 22:09
84fb5e2

A patch release, additive only.

<App> now forwards documentOutlineHandle to its inner <Editor>

0.2.0 added documentOutlineHandle to EditorProps but not to AppProps. Since <App> rather than <Editor> is what most consumers embed, the document outline was effectively unreachable for them. Pass documentOutlineHandle to <App> exactly as you would to <Editor> — see the Document Outline section of docs/editor-api.md. (#80, ADR-090)

The prop is optional; nothing changes for consumers that don't use it.

Why 0.2.1 and not 0.3.0

The change is additive, and in 0.x semver the minor is the breaking slot: ^0.2.0 matches 0.2.1 but not 0.3.0. Releasing this as a minor would have forced every consumer to raise their range in order to receive a fix that takes nothing away from them. As a patch, pnpm update is enough.

Upgrading

pnpm add @liminis/editor@^0.2.1

No action required beyond the install.

v0.2.0 — no Tailwind requirement, package-owned theming vocabulary, mark geometry

Choose a tag to compare

@verveguy verveguy released this 19 Aug 12:56
8e948a8

Two breaking changes and one addition, held together deliberately so consumers absorb one breaking upgrade instead of three.

Breaking: the Tailwind requirement is gone

Previously a host had to run Tailwind v4 and add an @source directive pointing into node_modules — a documented footgun whose failure mode was silent, unstyled chrome. The handful of utility classes the package emitted now ship as semantic classes in styles.css (.editor-container, .editor-loading, .editor-error-banner, .editor-app-root).

Hosts no longer need Tailwind installed, configured, or scanning this package at all. If you added an @source for @liminis/editor, it now generates nothing and can be removed. See ADR-086. (#49)

Breaking: theming tokens renamed to --liminis-editor-*

All 59 CSS custom properties are now under one package-owned prefix, replacing four inconsistent ones (--slashmd-* 30, --vscode-* 24, --color-* 4, --checkbox-* 1). See ADR-087. (#51)

Nothing loses its theme on upgrade. Every property resolves through a fallback chain — --liminis-editor-x, then that property's specific previous name, then its existing default — so a host still supplying old-prefix overrides keeps working untouched. Both known consumers do exactly that today and are unaffected.

The old names are deprecated and will be removed in a future major. README.md's "Migrating from the old names" section has the full mapping.

Added: getMarkRects() — breaking if you implement AnnotationEditorHandle

AnnotationEditorHandle gains getMarkRects(annotationIds?), returning Map<string, DOMRect[]> — the on-screen geometry of existing annotation marks, so a host can align UI to annotated text.

Previously the only public rect was the one-shot AnnotationCreateEvent.rect at creation time, and marks carry no id in the DOM, so there was no way for a host to attribute a rectangle to an annotation. DOMRect[] because one annotation can span several sibling mark nodes. (#73)

This is a required interface member, so it's breaking for anything that implements, constructs, or mocks AnnotationEditorHandle — a test double, an alternative host, a wrapper — which will fail to compile (TS2741: Property 'getMarkRects' is missing). It is not breaking for code that only calls methods on a handle instance the package itself supplies, e.g. via annotationEditorHandleRef — that continues to work unchanged. The fix is one line: add a getMarkRects implementation to any hand-built object satisfying AnnotationEditorHandle.

Also in this release

  • Table delimiters no longer minimise to | - | on round-trip; conventional | --- | is preserved and padded forms normalise to it once (#60)
  • The theming contract is documented, generated from source, and CI-enforced — the token reference cannot drift from the code (#50)
  • The toolbar link input referenced a --vscode-text token that never existed (#52)
  • Every workflow runs Node 24; Node 20 reached end of life on 24 March 2026
  • engines.node: ">=22" is now declared
  • Every CI job caps its runtime, so a hung job fails in minutes rather than six hours

Upgrading

pnpm add @liminis/editor@^0.2.0

Three things to check:

  1. Remove any @source directive pointing at this package — it now generates nothing.
  2. If you assert byte-identical markdown round-trips, regenerate fixtures containing tables: | - | becomes | --- | once, then stays stable.
  3. If you implement, construct, or mock AnnotationEditorHandle (a test double, an alternative host, a wrapper), add a getMarkRects implementation or you'll hit TS2741: Property 'getMarkRects' is missing.

Theming needs no immediate change; migrate to --liminis-editor-* at your convenience.

v0.1.1 — fixes a broken 0.1.0

Choose a tag to compare

@verveguy verveguy released this 17 Aug 03:38
5e358d9

0.1.0 could not be imported. Use 0.1.1.

0.1.0's published manifest pointed main, types and all six exports subpaths at ./src/*.ts, while the tarball shipped only dist/ — 191 dist/ files and zero src/ files. Every entry point resolved to a file that was not in the package, so import '@liminis/editor' failed outright.

Cause

publishConfig manifest-field overrides (main/types/exports) are a pnpm and yarn feature. npm honours publishConfig only for config values — access, registry, tag — and ignores field overrides. The release workflow publishes with npm publish, so the intended swap to dist/ never happened.

Fix

Entry points now live in the checked-in manifest as dist/ paths, with no pack-time rewriting. What is written is what is published.

The verification script was the deeper defect: it asserted the right things but packed with pnpm while the release packed with npm, so it validated a tarball no consumer would receive. It now packs with the same client that publishes, and additionally asserts the packed entry points are byte-identical to the checked-in ones.

Breaking

An in-workspace consumer resolving @liminis/editor no longer lands on raw TypeScript. Anything naming the package's src/ tree directly — a Tailwind @source directive, a bundler externalization exclusion — must name the installed package instead.

Also in this release

Every CI workflow moves to Node 24 (Node 20 reached end of life on 24 March 2026), and several code comments whose reasoning had gone stale are corrected.