@liminis/editor 0.2.2 → 0.3.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/README.md CHANGED
@@ -43,12 +43,20 @@ produce a broken editor context — peering is what prevents both.
43
43
 
44
44
  ```bash
45
45
  pnpm add react@^19 react-dom@^19 \
46
- lexical@^0.44 @lexical/react@^0.44 @lexical/code@^0.44 \
47
- @lexical/code-prism@^0.44 @lexical/link@^0.44 @lexical/list@^0.44 \
48
- @lexical/mark@^0.44 @lexical/markdown@^0.44 @lexical/rich-text@^0.44 \
49
- @lexical/selection@^0.44 @lexical/table@^0.44 @lexical/utils@^0.44
46
+ lexical@^0.49 @lexical/react@^0.49 @lexical/code@^0.49 \
47
+ @lexical/code-prism@^0.49 @lexical/link@^0.49 @lexical/list@^0.49 \
48
+ @lexical/mark@^0.49 @lexical/markdown@^0.49 @lexical/rich-text@^0.49 \
49
+ @lexical/selection@^0.49 @lexical/table@^0.49 @lexical/utils@^0.49
50
50
  ```
51
51
 
52
+ > **The Lexical peer ranges are single-caret, not a wide band.** Lexical is
53
+ > also `0.x`, where every minor is permitted to break — unlike React's range
54
+ > above, which spans an untested-but-stable range, the Lexical range names
55
+ > exactly the one minor this package is built and tested against. Expect it
56
+ > to move forward (e.g. to `^0.50`) only after this package has adopted and
57
+ > tested that release, not automatically at every upstream release. See
58
+ > `docs/decisions/adr-92-lexical-peer-range-policy.md`.
59
+
52
60
  pnpm v8+ and npm v7+ install peers automatically, so in practice the first
53
61
  command is usually enough.
54
62
 
@@ -201,22 +209,23 @@ properties under a single package-owned vocabulary, `--liminis-editor-*`.
201
209
  Every one of them resolves with no host configuration at all — the table
202
210
  below exists so you can *override* a palette, and also so you can *consume*
203
211
  one: every property this package declares with a value anywhere in
204
- `styles.css` the pre-`0.2.0` names still carrying the real defaults
205
- (`--vscode-*`, `--slashmd-*`, `--checkbox-*`, and a couple of standalone
206
- legacy names) that the `--liminis-editor-*` names below fall back to is
207
- part of this package's public API, readable directly by a host, not only
208
- overridable. (The `--liminis-editor-*` names themselves are never declared
209
- with a value directly see "Has a default" below — nor are legacy names
210
- like `--color-*` that appear only as an inner link in a fallback chain
211
- rather than a `:root`/`.dark` declaration; neither is part of the defined
212
- set this paragraph describes.) Some hosts do exactly that mapping their
213
- own design tokens onto these definitions with `var(--x)` rather than
214
- overriding them. Renaming or removing a definition is therefore a breaking
215
- change, the same as any other change to a supported API surface described
216
- under "Versioning policy" above, and is distinct from renaming a
217
- *consumption* site (covered separately in "Migrating from the old names"
218
- below) this package's CI guards against a definition disappearing
219
- unintentionally (ADR-092).
212
+ `styles.css` is part of this package's public API, readable directly by a
213
+ host, not only overridable. That now includes every `--liminis-editor-*` name
214
+ itself (see "Has a default" below) as well as the pre-`0.2.0` names that still
215
+ carry the real defaults (`--vscode-*`, `--slashmd-*`, `--checkbox-*`, and a
216
+ couple of standalone legacy names) — each `--liminis-editor-*` declaration is
217
+ an alias of its previous name (`--liminis-editor-x: var(--previous-name-x);`),
218
+ so both names resolve to the same value and either can be read directly
219
+ (ADR-93). (Legacy names like `--color-*` that appear only as an inner link in
220
+ a fallback chain, with no `:root`/`.dark` declaration of their own, are not
221
+ part of the defined set this paragraph describes only the property that
222
+ *carries* the value is.) Some hosts read these definitions directly mapping
223
+ their own design tokens onto them with `var(--x)` rather than overriding
224
+ them. Renaming or removing a definition is therefore a breaking change, the
225
+ same as any other change to a supported API surface described under
226
+ "Versioning policy" above, and is distinct from renaming a *consumption* site
227
+ (covered separately in "Migrating from the old names" below) — this package's
228
+ CI guards against a definition disappearing unintentionally (ADR-092).
220
229
 
221
230
  **Previous name** is the pre-`0.2.0` name this property replaced — the exact
222
231
  name to look for if you're migrating a host that still overrides the old
@@ -224,87 +233,92 @@ vocabulary (`—` for a property that was never renamed). **Controls** is a
224
233
  short description of what the token actually affects. **Kind** distinguishes
225
234
  tokens that only affect appearance (`Cosmetic`) from the handful that also
226
235
  affect layout (`Structural` — heading indents and the base font). **Has a
227
- default** marks tokens with a `--liminis-editor-*` `:root`/`.dark`
228
- declaration in `styles.css` directly; every row below reads "No (inline
229
- fallback only)" because each token instead resolves through a fallback chain
230
- `--liminis-editor-x` first, then its previous name (which still carries the
231
- real `:root`/`.dark` default), so a host supplying only the old name keeps
232
- theming unchanged. See "Migrating from the old names" below.
236
+ default** marks tokens declared with a value in `styles.css` directly; every
237
+ row below now reads "Yes" each `--liminis-editor-*` name carries its own
238
+ `:root`/`.dark` declaration, an alias that reads its previous name via `var()`
239
+ (ADR-93), so a host reading `--liminis-editor-x` gets a real value with no
240
+ configuration, and a host overriding only the previous name at
241
+ `:root`/`document.documentElement` still wins, because the alias re-resolves
242
+ through that name's own `.dark`/`@media print` overrides at the point of use
243
+ (ADR-93 documents a scope limitation for an override applied to a descendant
244
+ element instead). See "Migrating from the old names" below.
233
245
 
234
246
  This table is generated from `src/` by `node scripts/generate-theming-docs.mjs`
235
247
  and checked for staleness in CI (`tests/theming-contract.test.ts`) — a `var(--x)`
236
248
  added to the source without regenerating this block fails the build. Do not
237
249
  hand-edit the rows between the markers below. See ADR-085 for how the
238
250
  generation and drift guard work, ADR-087 for the rename and its compatibility
239
- design, and ADR-092 for the separate guard that protects the full *defined*
240
- set — every token declared with a value in `styles.css`, per the checked-in
241
- baseline (`scripts/lib/theming-defined-tokens-baseline.json`), a different
242
- and non-overlapping set of names from this table's rows — against an
243
- unintentional rename or removal run `pnpm docs:theming-baseline` after a
244
- deliberate one.
251
+ design, ADR-092 for the separate guard that protects the full *defined* set —
252
+ every token declared with a value in `styles.css`, per the checked-in baseline
253
+ (`scripts/lib/theming-defined-tokens-baseline.json`) against an
254
+ unintentional rename or removal (run `pnpm docs:theming-baseline` after a
255
+ deliberate one), and ADR-93 for the `--liminis-editor-*` alias declarations
256
+ that make the defined set (baseline) a superset of this table's rows —
257
+ every consumed `--liminis-editor-*` name is now also a defined one — rather
258
+ than the disjoint sets they were before.
245
259
 
246
260
  <!-- theming-tokens:start -->
247
261
  | Custom property | Previous name | Controls | Kind | Has a default |
248
262
  | --- | --- | --- | --- | --- |
249
- | `--liminis-editor-background` | `--vscode-background` | Base background color of the editor surface and its popovers/menus. | Cosmetic | No (inline fallback only) |
250
- | `--liminis-editor-bold-color` | `--slashmd-bold-color` | Text color of bold (`**text**`) markdown spans. | Cosmetic | No (inline fallback only) |
251
- | `--liminis-editor-border` | `--vscode-border` | Default border color used throughout the editor chrome. | Cosmetic | No (inline fallback only) |
252
- | `--liminis-editor-button-background` | `--vscode-button-background` | Background of primary action buttons (e.g. the correction panel's "Apply" button). | Cosmetic | No (inline fallback only) |
253
- | `--liminis-editor-button-foreground` | `--vscode-button-foreground` | Text color of primary action buttons. | Cosmetic | No (inline fallback only) |
254
- | `--liminis-editor-callout-caution-bg` | `--slashmd-callout-caution-bg` | Background of "caution" callout blocks. | Cosmetic | No (inline fallback only) |
255
- | `--liminis-editor-callout-caution-border` | `--slashmd-callout-caution-border` | Left border accent of "caution" callout blocks. | Cosmetic | No (inline fallback only) |
256
- | `--liminis-editor-callout-important-bg` | `--slashmd-callout-important-bg` | Background of "important" callout blocks. | Cosmetic | No (inline fallback only) |
257
- | `--liminis-editor-callout-important-border` | `--slashmd-callout-important-border` | Left border accent of "important" callout blocks. | Cosmetic | No (inline fallback only) |
258
- | `--liminis-editor-callout-note-bg` | `--slashmd-callout-note-bg` | Background of "note" callout blocks. | Cosmetic | No (inline fallback only) |
259
- | `--liminis-editor-callout-note-border` | `--slashmd-callout-note-border` | Left border accent of "note" callout blocks. | Cosmetic | No (inline fallback only) |
260
- | `--liminis-editor-callout-tip-bg` | `--slashmd-callout-tip-bg` | Background of "tip" callout blocks. | Cosmetic | No (inline fallback only) |
261
- | `--liminis-editor-callout-tip-border` | `--slashmd-callout-tip-border` | Left border accent of "tip" callout blocks. | Cosmetic | No (inline fallback only) |
262
- | `--liminis-editor-callout-warning-bg` | `--slashmd-callout-warning-bg` | Background of "warning" callout blocks. | Cosmetic | No (inline fallback only) |
263
- | `--liminis-editor-callout-warning-border` | `--slashmd-callout-warning-border` | Left border accent of "warning" callout blocks. | Cosmetic | No (inline fallback only) |
264
- | `--liminis-editor-checkbox-border` | `--checkbox-border` | Border color of unchecked task-list checkboxes. | Cosmetic | No (inline fallback only) |
265
- | `--liminis-editor-code-bg` | `--vscode-code-bg` | Background of inline code spans and fenced code blocks. | Cosmetic | No (inline fallback only) |
266
- | `--liminis-editor-errorForeground` | `--vscode-errorForeground` | Text color for error and validation messages. | Cosmetic | No (inline fallback only) |
267
- | `--liminis-editor-external-link` | `--vscode-external-link` | Text color of links that point outside the document. | Cosmetic | No (inline fallback only) |
268
- | `--liminis-editor-focus-border` | `--vscode-focus-border` | Border color of the toolbar link-input field when focused. | Cosmetic | No (inline fallback only) |
269
- | `--liminis-editor-focusBorder` | `--vscode-focusBorder` | Color of the drag-and-drop position indicator while reordering blocks. | Cosmetic | No (inline fallback only) |
270
- | `--liminis-editor-font-family` | `--vscode-font-family` | Base font family for the editor content. | Structural | No (inline fallback only) |
271
- | `--liminis-editor-font-size` | `--vscode-font-size` | Base font size for the editor content. | Structural | No (inline fallback only) |
272
- | `--liminis-editor-foreground` | `--vscode-foreground` | Default text color throughout the editor. | Cosmetic | No (inline fallback only) |
273
- | `--liminis-editor-foreground-muted` | `--vscode-foreground-muted` | Hover border color for the frontmatter tray's raw-view toggle. | Cosmetic | No (inline fallback only) |
274
- | `--liminis-editor-h1-color` | `--slashmd-h1-color` | Text color of level-1 (`#`) headings. | Cosmetic | No (inline fallback only) |
275
- | `--liminis-editor-h1-indent` | `--slashmd-h1-indent` | Left margin of level-1 (`#`) headings. | Structural | No (inline fallback only) |
276
- | `--liminis-editor-h2-color` | `--slashmd-h2-color` | Text color of level-2 (`##`) headings. | Cosmetic | No (inline fallback only) |
277
- | `--liminis-editor-h2-indent` | `--slashmd-h2-indent` | Left margin of level-2 (`##`) headings. | Structural | No (inline fallback only) |
278
- | `--liminis-editor-h3-color` | `--slashmd-h3-color` | Text color of level-3 (`###`) headings. | Cosmetic | No (inline fallback only) |
279
- | `--liminis-editor-h3-indent` | `--slashmd-h3-indent` | Left margin of level-3 (`###`) headings. | Structural | No (inline fallback only) |
280
- | `--liminis-editor-h4-color` | `--slashmd-h4-color` | Text color of level-4 (`####`) headings. | Cosmetic | No (inline fallback only) |
281
- | `--liminis-editor-h4-indent` | `--slashmd-h4-indent` | Left margin of level-4 (`####`) headings. | Structural | No (inline fallback only) |
282
- | `--liminis-editor-h5-color` | `--slashmd-h5-color` | Text color of level-5 (`#####`) headings. | Cosmetic | No (inline fallback only) |
283
- | `--liminis-editor-h5-indent` | `--slashmd-h5-indent` | Left margin of level-5 (`#####`) headings. | Structural | No (inline fallback only) |
284
- | `--liminis-editor-input-bg` | `--vscode-input-bg` | Background of the toolbar link-input field. | Cosmetic | No (inline fallback only) |
285
- | `--liminis-editor-inputValidation-errorBackground` | `--vscode-inputValidation-errorBackground` | Background of inline validation-error messages. | Cosmetic | No (inline fallback only) |
286
- | `--liminis-editor-italic-color` | `--slashmd-italic-color` | Text color of italic (`*text*`) markdown spans. | Cosmetic | No (inline fallback only) |
287
- | `--liminis-editor-link` | `--vscode-link` | Text color of in-document links. | Cosmetic | No (inline fallback only) |
288
- | `--liminis-editor-menu-background` | `--vscode-menu-background` | Background of context menus (block, selection and correction menus). | Cosmetic | No (inline fallback only) |
289
- | `--liminis-editor-menu-border` | `--vscode-menu-border` | Border color of context menus. | Cosmetic | No (inline fallback only) |
290
- | `--liminis-editor-menu-foreground` | `--vscode-menu-foreground` | Text color of context menu items. | Cosmetic | No (inline fallback only) |
291
- | `--liminis-editor-menu-selectionBackground` | `--vscode-menu-selectionBackground` | Background of a hovered/selected context menu item. | Cosmetic | No (inline fallback only) |
292
- | `--liminis-editor-menu-separatorBackground` | `--vscode-menu-separatorBackground` | Color of separator lines inside context menus. | Cosmetic | No (inline fallback only) |
293
- | `--liminis-editor-muted-100` | `--color-muted-100` | Background of the C4 diagram layout-toggle buttons when inactive. | Cosmetic | No (inline fallback only) |
294
- | `--liminis-editor-muted-foreground` | `--color-muted-foreground` | Icon/text color of the C4 diagram layout-toggle buttons when inactive. | Cosmetic | No (inline fallback only) |
295
- | `--liminis-editor-notificationsInfoIcon-foreground` | `--vscode-notificationsInfoIcon-foreground` | Color of informational icons in inline notifications. | Cosmetic | No (inline fallback only) |
296
- | `--liminis-editor-primary` | `--color-primary` | Icon/text color of the C4 diagram layout-toggle buttons when active. | Cosmetic | No (inline fallback only) |
297
- | `--liminis-editor-primary-100` | `--color-primary-100` | Background of the C4 diagram layout-toggle buttons when active. | Cosmetic | No (inline fallback only) |
298
- | `--liminis-editor-selection` | `--vscode-selection` | Background color of selected/highlighted text. | Cosmetic | No (inline fallback only) |
299
- | `--liminis-editor-token-comment` | `--slashmd-token-comment` | Syntax-highlight color for comments in fenced code blocks. | Cosmetic | No (inline fallback only) |
300
- | `--liminis-editor-token-function` | `--slashmd-token-function` | Syntax-highlight color for function names in fenced code blocks. | Cosmetic | No (inline fallback only) |
301
- | `--liminis-editor-token-keyword` | `--slashmd-token-keyword` | Syntax-highlight color for keywords in fenced code blocks. | Cosmetic | No (inline fallback only) |
302
- | `--liminis-editor-token-operator` | `--slashmd-token-operator` | Syntax-highlight color for operators in fenced code blocks. | Cosmetic | No (inline fallback only) |
303
- | `--liminis-editor-token-property` | `--slashmd-token-property` | Syntax-highlight color for object properties in fenced code blocks. | Cosmetic | No (inline fallback only) |
304
- | `--liminis-editor-token-punctuation` | `--slashmd-token-punctuation` | Syntax-highlight color for punctuation in fenced code blocks. | Cosmetic | No (inline fallback only) |
305
- | `--liminis-editor-token-selector` | `--slashmd-token-selector` | Syntax-highlight color for CSS selectors in fenced code blocks. | Cosmetic | No (inline fallback only) |
306
- | `--liminis-editor-token-variable` | `--slashmd-token-variable` | Syntax-highlight color for variables in fenced code blocks. | Cosmetic | No (inline fallback only) |
307
- | `--liminis-editor-toolbar-hoverBackground` | `--vscode-toolbar-hoverBackground` | Background of a toolbar button on hover. | Cosmetic | No (inline fallback only) |
263
+ | `--liminis-editor-background` | `--vscode-background` | Base background color of the editor surface and its popovers/menus. | Cosmetic | Yes |
264
+ | `--liminis-editor-bold-color` | `--slashmd-bold-color` | Text color of bold (`**text**`) markdown spans. | Cosmetic | Yes |
265
+ | `--liminis-editor-border` | `--vscode-border` | Default border color used throughout the editor chrome. | Cosmetic | Yes |
266
+ | `--liminis-editor-button-background` | `--vscode-button-background` | Background of primary action buttons (e.g. the correction panel's "Apply" button). | Cosmetic | Yes |
267
+ | `--liminis-editor-button-foreground` | `--vscode-button-foreground` | Text color of primary action buttons. | Cosmetic | Yes |
268
+ | `--liminis-editor-callout-caution-bg` | `--slashmd-callout-caution-bg` | Background of "caution" callout blocks. | Cosmetic | Yes |
269
+ | `--liminis-editor-callout-caution-border` | `--slashmd-callout-caution-border` | Left border accent of "caution" callout blocks. | Cosmetic | Yes |
270
+ | `--liminis-editor-callout-important-bg` | `--slashmd-callout-important-bg` | Background of "important" callout blocks. | Cosmetic | Yes |
271
+ | `--liminis-editor-callout-important-border` | `--slashmd-callout-important-border` | Left border accent of "important" callout blocks. | Cosmetic | Yes |
272
+ | `--liminis-editor-callout-note-bg` | `--slashmd-callout-note-bg` | Background of "note" callout blocks. | Cosmetic | Yes |
273
+ | `--liminis-editor-callout-note-border` | `--slashmd-callout-note-border` | Left border accent of "note" callout blocks. | Cosmetic | Yes |
274
+ | `--liminis-editor-callout-tip-bg` | `--slashmd-callout-tip-bg` | Background of "tip" callout blocks. | Cosmetic | Yes |
275
+ | `--liminis-editor-callout-tip-border` | `--slashmd-callout-tip-border` | Left border accent of "tip" callout blocks. | Cosmetic | Yes |
276
+ | `--liminis-editor-callout-warning-bg` | `--slashmd-callout-warning-bg` | Background of "warning" callout blocks. | Cosmetic | Yes |
277
+ | `--liminis-editor-callout-warning-border` | `--slashmd-callout-warning-border` | Left border accent of "warning" callout blocks. | Cosmetic | Yes |
278
+ | `--liminis-editor-checkbox-border` | `--checkbox-border` | Border color of unchecked task-list checkboxes. | Cosmetic | Yes |
279
+ | `--liminis-editor-code-bg` | `--vscode-code-bg` | Background of inline code spans and fenced code blocks. | Cosmetic | Yes |
280
+ | `--liminis-editor-errorForeground` | `--vscode-errorForeground` | Text color for error and validation messages. | Cosmetic | Yes |
281
+ | `--liminis-editor-external-link` | `--vscode-external-link` | Text color of links that point outside the document. | Cosmetic | Yes |
282
+ | `--liminis-editor-focus-border` | `--vscode-focus-border` | Border color of the toolbar link-input field when focused. | Cosmetic | Yes |
283
+ | `--liminis-editor-focusBorder` | `--vscode-focusBorder` | Color of the drag-and-drop position indicator while reordering blocks. | Cosmetic | Yes |
284
+ | `--liminis-editor-font-family` | `--vscode-font-family` | Base font family for the editor content. | Structural | Yes |
285
+ | `--liminis-editor-font-size` | `--vscode-font-size` | Base font size for the editor content. | Structural | Yes |
286
+ | `--liminis-editor-foreground` | `--vscode-foreground` | Default text color throughout the editor. | Cosmetic | Yes |
287
+ | `--liminis-editor-foreground-muted` | `--vscode-foreground-muted` | Hover border color for the frontmatter tray's raw-view toggle. | Cosmetic | Yes |
288
+ | `--liminis-editor-h1-color` | `--slashmd-h1-color` | Text color of level-1 (`#`) headings. | Cosmetic | Yes |
289
+ | `--liminis-editor-h1-indent` | `--slashmd-h1-indent` | Left margin of level-1 (`#`) headings. | Structural | Yes |
290
+ | `--liminis-editor-h2-color` | `--slashmd-h2-color` | Text color of level-2 (`##`) headings. | Cosmetic | Yes |
291
+ | `--liminis-editor-h2-indent` | `--slashmd-h2-indent` | Left margin of level-2 (`##`) headings. | Structural | Yes |
292
+ | `--liminis-editor-h3-color` | `--slashmd-h3-color` | Text color of level-3 (`###`) headings. | Cosmetic | Yes |
293
+ | `--liminis-editor-h3-indent` | `--slashmd-h3-indent` | Left margin of level-3 (`###`) headings. | Structural | Yes |
294
+ | `--liminis-editor-h4-color` | `--slashmd-h4-color` | Text color of level-4 (`####`) headings. | Cosmetic | Yes |
295
+ | `--liminis-editor-h4-indent` | `--slashmd-h4-indent` | Left margin of level-4 (`####`) headings. | Structural | Yes |
296
+ | `--liminis-editor-h5-color` | `--slashmd-h5-color` | Text color of level-5 (`#####`) headings. | Cosmetic | Yes |
297
+ | `--liminis-editor-h5-indent` | `--slashmd-h5-indent` | Left margin of level-5 (`#####`) headings. | Structural | Yes |
298
+ | `--liminis-editor-input-bg` | `--vscode-input-bg` | Background of the toolbar link-input field. | Cosmetic | Yes |
299
+ | `--liminis-editor-inputValidation-errorBackground` | `--vscode-inputValidation-errorBackground` | Background of inline validation-error messages. | Cosmetic | Yes |
300
+ | `--liminis-editor-italic-color` | `--slashmd-italic-color` | Text color of italic (`*text*`) markdown spans. | Cosmetic | Yes |
301
+ | `--liminis-editor-link` | `--vscode-link` | Text color of in-document links. | Cosmetic | Yes |
302
+ | `--liminis-editor-menu-background` | `--vscode-menu-background` | Background of context menus (block, selection and correction menus). | Cosmetic | Yes |
303
+ | `--liminis-editor-menu-border` | `--vscode-menu-border` | Border color of context menus. | Cosmetic | Yes |
304
+ | `--liminis-editor-menu-foreground` | `--vscode-menu-foreground` | Text color of context menu items. | Cosmetic | Yes |
305
+ | `--liminis-editor-menu-selectionBackground` | `--vscode-menu-selectionBackground` | Background of a hovered/selected context menu item. | Cosmetic | Yes |
306
+ | `--liminis-editor-menu-separatorBackground` | `--vscode-menu-separatorBackground` | Color of separator lines inside context menus. | Cosmetic | Yes |
307
+ | `--liminis-editor-muted-100` | `--color-muted-100` | Background of the C4 diagram layout-toggle buttons when inactive. | Cosmetic | Yes |
308
+ | `--liminis-editor-muted-foreground` | `--color-muted-foreground` | Icon/text color of the C4 diagram layout-toggle buttons when inactive. | Cosmetic | Yes |
309
+ | `--liminis-editor-notificationsInfoIcon-foreground` | `--vscode-notificationsInfoIcon-foreground` | Color of informational icons in inline notifications. | Cosmetic | Yes |
310
+ | `--liminis-editor-primary` | `--color-primary` | Icon/text color of the C4 diagram layout-toggle buttons when active. | Cosmetic | Yes |
311
+ | `--liminis-editor-primary-100` | `--color-primary-100` | Background of the C4 diagram layout-toggle buttons when active. | Cosmetic | Yes |
312
+ | `--liminis-editor-selection` | `--vscode-selection` | Background color of selected/highlighted text. | Cosmetic | Yes |
313
+ | `--liminis-editor-token-comment` | `--slashmd-token-comment` | Syntax-highlight color for comments in fenced code blocks. | Cosmetic | Yes |
314
+ | `--liminis-editor-token-function` | `--slashmd-token-function` | Syntax-highlight color for function names in fenced code blocks. | Cosmetic | Yes |
315
+ | `--liminis-editor-token-keyword` | `--slashmd-token-keyword` | Syntax-highlight color for keywords in fenced code blocks. | Cosmetic | Yes |
316
+ | `--liminis-editor-token-operator` | `--slashmd-token-operator` | Syntax-highlight color for operators in fenced code blocks. | Cosmetic | Yes |
317
+ | `--liminis-editor-token-property` | `--slashmd-token-property` | Syntax-highlight color for object properties in fenced code blocks. | Cosmetic | Yes |
318
+ | `--liminis-editor-token-punctuation` | `--slashmd-token-punctuation` | Syntax-highlight color for punctuation in fenced code blocks. | Cosmetic | Yes |
319
+ | `--liminis-editor-token-selector` | `--slashmd-token-selector` | Syntax-highlight color for CSS selectors in fenced code blocks. | Cosmetic | Yes |
320
+ | `--liminis-editor-token-variable` | `--slashmd-token-variable` | Syntax-highlight color for variables in fenced code blocks. | Cosmetic | Yes |
321
+ | `--liminis-editor-toolbar-hoverBackground` | `--vscode-toolbar-hoverBackground` | Background of a toolbar button on hover. | Cosmetic | Yes |
308
322
  <!-- theming-tokens:end -->
309
323
 
310
324
  **A worked example.** To match a host's own palette, override a subset of
@@ -348,6 +362,25 @@ prefix swap (`--checkbox-border` became `--liminis-editor-checkbox-border`,
348
362
  not `--liminis-editor-border`, to avoid colliding with `--vscode-border`'s
349
363
  new name), so look it up rather than deriving it.
350
364
 
365
+ Reading, not just overriding, is also migratable: a host that currently reads
366
+ a legacy name directly (e.g. mapping its own design tokens onto
367
+ `--vscode-foreground`) can switch that read to the corresponding
368
+ `--liminis-editor-*` name and get an identical value, **as long as it isn't
369
+ also setting the `--liminis-editor-*` name itself** — a directly-set
370
+ `--liminis-editor-*` value always wins over the previous name's own value,
371
+ by ordinary cascade precedence (see "Has a default" below), so the two reads
372
+ are identical only while the host relies solely on the previous name. Until
373
+ ADR-93, `--liminis-editor-*` names were only ever *consumed*, never
374
+ themselves declared with a value — there was nothing for such a host to
375
+ migrate its reads to. Every `--liminis-editor-*` name now carries its own
376
+ `:root`/`.dark` alias declaration that resolves to the previous name's own
377
+ value in that legacy-only case, so the read migration is a like-for-like
378
+ swap with no observable difference (see verveguy/zusammen#129, the migration
379
+ this addresses). This guarantee holds for a previous-name override applied
380
+ at `:root`/`document.documentElement`, the standard integration point; see
381
+ ADR-93 for a documented limitation when a host scopes its override to a
382
+ descendant element instead.
383
+
351
384
  ## Annotations
352
385
 
353
386
  An annotation is a range-anchored marker over document text whose anchor
@@ -240,6 +240,20 @@ function CursorRestorePlugin({ contentVersion, cursorToRestoreRef, }) {
240
240
  const cursorToRestore = cursorToRestoreRef.current;
241
241
  if (!cursorToRestore)
242
242
  return;
243
+ // Only restore the caret if the user was actually in the editor when the
244
+ // reload arrived. A content reload is not always the user's doing: an
245
+ // agent writing the open file reaches here too, and re-focusing then pulls
246
+ // the caret out of whatever the user is typing in — a chat prompt beside
247
+ // the editor, say — mid-sentence. Restoring a caret nobody is looking at
248
+ // buys nothing, so an unfocused editor is left entirely alone (no
249
+ // selection write either, so reconciliation cannot move focus as a side
250
+ // effect). Same rule as `AutoFocusPlugin`: never take focus unasked.
251
+ // Read synchronously, before the update below can perturb focus.
252
+ const rootElement = editor.getRootElement();
253
+ const hadFocus = rootElement !== null &&
254
+ (rootElement === document.activeElement || rootElement.contains(document.activeElement));
255
+ if (!hadFocus)
256
+ return;
243
257
  console.log('[CursorRestorePlugin] Restoring cursor', {
244
258
  contentVersion,
245
259
  offset: cursorToRestore.offset,
@@ -262,11 +276,9 @@ function CursorRestorePlugin({ contentVersion, cursorToRestoreRef, }) {
262
276
  console.log('[CursorRestorePlugin] Selection restored at offset', newOffset);
263
277
  }
264
278
  });
265
- // Re-focus the editor
266
- const rootElement = editor.getRootElement();
267
- if (rootElement) {
268
- rootElement.focus({ preventScroll: true });
269
- }
279
+ // Re-focus the editor. Reached only when it already had focus above, so
280
+ // this restores focus the reload disturbed rather than taking it.
281
+ rootElement.focus({ preventScroll: true });
270
282
  });
271
283
  }, [editor, contentVersion, cursorToRestoreRef]);
272
284
  return null;
package/dist/styles.css CHANGED
@@ -107,6 +107,135 @@
107
107
  --slashmd-callout-caution-border: oklch(0.63 0.24 27);
108
108
  }
109
109
 
110
+ /* ========================================
111
+ PUBLIC ALIASES — --liminis-editor-* names (ADR-93)
112
+
113
+ The package's own :root/.dark declarations above keep carrying the real
114
+ defaults, under the legacy names, exactly as before. Every alias below
115
+ only reads a legacy name via var() — it never declares an independent
116
+ value — so a host overriding only the legacy name still wins: the alias
117
+ re-resolves through .dark and the @media print block's overrides of that
118
+ legacy name, since a var() reference resolves per-element at the point of
119
+ use, not at the point this declaration is parsed. This lets a host read
120
+ --liminis-editor-* directly (verveguy/zusammen#129) without disabling the
121
+ ADR-087 fallback layer that a host supplying only the legacy name relies
122
+ on.
123
+
124
+ Scope of the "legacy name still wins" guarantee: this re-resolution is
125
+ correct for a legacy override applied at (or that plainly inherits down
126
+ to) :root/document.documentElement — the standard integration point, and
127
+ the only one covered by this package's own e2e coverage. It does NOT
128
+ extend to a legacy override scoped to an arbitrary DESCENDANT element
129
+ between :root and the editor's own DOM (e.g. a per-widget wrapper div a
130
+ host might apply its own theme vars to): a custom property inherits its
131
+ parent's already-*computed* value, not the var() expression, so this
132
+ :root-declared alias is fixed at parse time using :root's own value and
133
+ won't pick up a change made lower in the tree. Re-declaring the alias on
134
+ every element (`*`) was tried and rejected: it fixes the descendant case
135
+ but then shadows a --liminis-editor-* override a host sets on an
136
+ ancestor of the element being read, breaking the higher-priority
137
+ guarantee (User Story 3) that a directly-set --liminis-editor-* name
138
+ always wins — confirmed by test, not assumed. Scoping the redeclaration
139
+ to a known package wrapper class (e.g. .editor-app-root) was also tried
140
+ and rejected: not every integration renders that wrapper (this repo's
141
+ own examples/electron shell doesn't), so the alias would go undefined
142
+ there. See ADR-93 for the full trade-off and verveguy/liminis-editor#93's
143
+ PR review thread for the CSS-inheritance mechanics that rule out a
144
+ `:root`-only or `*`-only fix satisfying both scenarios at once.
145
+ ======================================== */
146
+ :root {
147
+ /* Aliases for tokens with an existing --vscode-, --slashmd- or --checkbox- default */
148
+ --liminis-editor-background: var(--vscode-background);
149
+ --liminis-editor-bold-color: var(--slashmd-bold-color);
150
+ --liminis-editor-border: var(--vscode-border);
151
+ --liminis-editor-callout-caution-bg: var(--slashmd-callout-caution-bg);
152
+ --liminis-editor-callout-caution-border: var(--slashmd-callout-caution-border);
153
+ --liminis-editor-callout-important-bg: var(--slashmd-callout-important-bg);
154
+ --liminis-editor-callout-important-border: var(--slashmd-callout-important-border);
155
+ --liminis-editor-callout-note-bg: var(--slashmd-callout-note-bg);
156
+ --liminis-editor-callout-note-border: var(--slashmd-callout-note-border);
157
+ --liminis-editor-callout-tip-bg: var(--slashmd-callout-tip-bg);
158
+ --liminis-editor-callout-tip-border: var(--slashmd-callout-tip-border);
159
+ --liminis-editor-callout-warning-bg: var(--slashmd-callout-warning-bg);
160
+ --liminis-editor-callout-warning-border: var(--slashmd-callout-warning-border);
161
+ --liminis-editor-checkbox-border: var(--checkbox-border);
162
+ --liminis-editor-code-bg: var(--vscode-code-bg);
163
+ --liminis-editor-external-link: var(--vscode-external-link);
164
+ --liminis-editor-font-family: var(--vscode-font-family);
165
+ --liminis-editor-font-size: var(--vscode-font-size);
166
+ --liminis-editor-foreground: var(--vscode-foreground);
167
+ --liminis-editor-h1-color: var(--slashmd-h1-color);
168
+ --liminis-editor-h1-indent: var(--slashmd-h1-indent);
169
+ --liminis-editor-h2-color: var(--slashmd-h2-color);
170
+ --liminis-editor-h2-indent: var(--slashmd-h2-indent);
171
+ --liminis-editor-h3-color: var(--slashmd-h3-color);
172
+ --liminis-editor-h3-indent: var(--slashmd-h3-indent);
173
+ --liminis-editor-h4-color: var(--slashmd-h4-color);
174
+ --liminis-editor-h4-indent: var(--slashmd-h4-indent);
175
+ --liminis-editor-h5-color: var(--slashmd-h5-color);
176
+ --liminis-editor-h5-indent: var(--slashmd-h5-indent);
177
+ --liminis-editor-italic-color: var(--slashmd-italic-color);
178
+ --liminis-editor-link: var(--vscode-link);
179
+ --liminis-editor-selection: var(--vscode-selection);
180
+ --liminis-editor-token-comment: var(--slashmd-token-comment);
181
+ --liminis-editor-token-function: var(--slashmd-token-function);
182
+ --liminis-editor-token-keyword: var(--slashmd-token-keyword);
183
+ --liminis-editor-token-operator: var(--slashmd-token-operator);
184
+ --liminis-editor-token-property: var(--slashmd-token-property);
185
+ --liminis-editor-token-punctuation: var(--slashmd-token-punctuation);
186
+ --liminis-editor-token-selector: var(--slashmd-token-selector);
187
+ --liminis-editor-token-variable: var(--slashmd-token-variable);
188
+
189
+ /* Aliases preserving an existing nested consumption-site fallback chain —
190
+ these two legacy names have no --vscode-* declaration of their own, only
191
+ an existing fallback to a second legacy name at their consumption site. */
192
+ --liminis-editor-input-bg: var(--vscode-input-bg, var(--vscode-code-bg));
193
+ --liminis-editor-foreground-muted: var(--vscode-foreground-muted, var(--vscode-border));
194
+
195
+ /* Aliases for tokens with no CSS custom property backing anywhere — only an
196
+ inline literal fallback at their consumption site(s). The literal below
197
+ reproduces that existing light-mode fallback so a host supplying nothing
198
+ sees no change (FR-002); a host setting the legacy name still wins
199
+ (FR-003). Where the same token's literal differs by site (errorForeground,
200
+ toolbar-hoverBackground), a single canonical value is chosen here — see
201
+ ADR-93 for the two accepted visual deltas this causes at three sites. */
202
+ --liminis-editor-button-background: var(--vscode-button-background, #007acc);
203
+ --liminis-editor-button-foreground: var(--vscode-button-foreground, #ffffff);
204
+ --liminis-editor-menu-background: var(--vscode-menu-background, #ffffff);
205
+ --liminis-editor-menu-border: var(--vscode-menu-border, #d4d4d4);
206
+ --liminis-editor-menu-foreground: var(--vscode-menu-foreground, #333333);
207
+ --liminis-editor-menu-selectionBackground: var(--vscode-menu-selectionBackground, #e8e8e8);
208
+ --liminis-editor-menu-separatorBackground: var(--vscode-menu-separatorBackground, #d4d4d4);
209
+ --liminis-editor-toolbar-hoverBackground: var(--vscode-toolbar-hoverBackground, rgba(128, 128, 128, 0.15));
210
+ --liminis-editor-notificationsInfoIcon-foreground: var(--vscode-notificationsInfoIcon-foreground, #3794ff);
211
+ --liminis-editor-inputValidation-errorBackground: var(--vscode-inputValidation-errorBackground, rgba(255, 0, 0, 0.15));
212
+ --liminis-editor-errorForeground: var(--vscode-errorForeground, #f14c4c);
213
+ --liminis-editor-focus-border: var(--vscode-focus-border, #007acc);
214
+ --liminis-editor-focusBorder: var(--vscode-focusBorder, #007acc);
215
+
216
+ /* Aliases for liminis-app's own Tailwind @theme brand tokens — the package
217
+ only ever supplied a literal final fallback for these, never asserted
218
+ ownership; this alias makes that existing fallback reachable under the
219
+ new name too, without changing what it resolves to. */
220
+ --liminis-editor-primary: var(--color-primary, #3b82f6);
221
+ --liminis-editor-primary-100: var(--color-primary-100, rgba(59, 130, 246, 0.1));
222
+ --liminis-editor-muted-foreground: var(--color-muted-foreground, #6b7280);
223
+ --liminis-editor-muted-100: var(--color-muted-100, rgba(128, 128, 128, 0.1));
224
+ }
225
+
226
+ .dark {
227
+ /* Dark-mode literal overrides for the subset of the no-CSS-backing group
228
+ above whose consumption sites select a different literal in dark mode
229
+ (via a JS `isDark`/`dark` check reading the same .dark class this
230
+ selector keys off) rather than a single literal used in both themes. */
231
+ --liminis-editor-button-background: var(--vscode-button-background, #0e639c);
232
+ --liminis-editor-menu-background: var(--vscode-menu-background, #252526);
233
+ --liminis-editor-menu-border: var(--vscode-menu-border, #454545);
234
+ --liminis-editor-menu-foreground: var(--vscode-menu-foreground, #cccccc);
235
+ --liminis-editor-menu-selectionBackground: var(--vscode-menu-selectionBackground, #094771);
236
+ --liminis-editor-menu-separatorBackground: var(--vscode-menu-separatorBackground, #454545);
237
+ }
238
+
110
239
  * {
111
240
  box-sizing: border-box;
112
241
  }
@@ -1038,6 +1167,7 @@ body {
1038
1167
  }
1039
1168
 
1040
1169
  .drag-handle:hover .drag-handle-icon {
1170
+ /* Superseded by --liminis-editor-toolbar-hoverBackground's canonical 0.15-alpha default (ADR-93) */
1041
1171
  background: var(--liminis-editor-toolbar-hoverBackground, var(--vscode-toolbar-hoverBackground, rgba(128, 128, 128, 0.1)));
1042
1172
  }
1043
1173
 
@@ -1077,6 +1207,7 @@ body {
1077
1207
 
1078
1208
  .block-delete-button:hover .block-delete-icon {
1079
1209
  background: var(--liminis-editor-inputValidation-errorBackground, var(--vscode-inputValidation-errorBackground, rgba(255, 0, 0, 0.15)));
1210
+ /* Superseded by --liminis-editor-errorForeground's canonical #f14c4c default (ADR-93) */
1080
1211
  color: var(--liminis-editor-errorForeground, var(--vscode-errorForeground, #f44336));
1081
1212
  }
1082
1213
 
@@ -1592,6 +1723,7 @@ body {
1592
1723
  }
1593
1724
 
1594
1725
  .search-close-button:hover {
1726
+ /* Superseded by --liminis-editor-errorForeground's canonical #f14c4c default (ADR-93) */
1595
1727
  color: var(--liminis-editor-errorForeground, var(--vscode-errorForeground, #f44336));
1596
1728
  }
1597
1729
 
@@ -0,0 +1,152 @@
1
+ # ADR-92: The Lexical Peer Range Bumps Forward by a Narrow Single Caret, Never a Wide Band
2
+
3
+ **Date:** 2026-08-20
4
+ **Status:** Accepted
5
+ **Supersedes:** none
6
+ **Amends:** none
7
+ **Issue:** #92 (verveguy/liminis-editor)
8
+
9
+ ## Context
10
+
11
+ Every published version of `@liminis/editor`, including `0.2.2`, declared its
12
+ Lexical peer range as `^0.44.0` across all twelve Lexical family packages
13
+ (`lexical` and eleven `@lexical/*` scoped packages). Lexical itself moved on
14
+ to `0.49.0`. Because Lexical is a `0.x` package, `^0.44.0` resolves under
15
+ semver to `>=0.44.0 <0.45.0` — it admits patch releases of 0.44 only, and
16
+ excludes every 0.45+ release regardless of whether that particular release
17
+ was actually breaking. The practical effect: this package pinned every host
18
+ application to a Lexical line five minors behind, with no published version
19
+ offering a path forward.
20
+
21
+ This surfaced while refreshing `liminis-app`'s dependencies
22
+ (verveguy/liminis#1026): the Lexical family was bumped 0.44.0 → 0.49.0 and
23
+ tested in isolation there. It passed `liminis-app`'s own typecheck, lint,
24
+ build, and 3275-test suite — and was still wrong, because `liminis-app` would
25
+ have shipped in violation of this package's declared peer contract. That
26
+ app's suite does not exercise the editor deeply enough for a green run to be
27
+ evidence of Lexical compatibility; the only suite that can answer that
28
+ question is this package's own.
29
+
30
+ The peer-range shape was an open question, not a foregone conclusion: widen
31
+ the range to admit 0.44 through 0.49 (matching the issue's own suggested
32
+ example), or narrow it to `^0.49.0` and drop 0.44–0.48 support outright.
33
+
34
+ ## Decision
35
+
36
+ **The twelve Lexical peer ranges move to `^0.49.0` — a narrow single-caret
37
+ bump, not a wide multi-version band.** This is a deliberate, permanent
38
+ policy choice about how this package treats Lexical peer ranges going
39
+ forward, not a one-time bump: every future Lexical minor this package adopts
40
+ gets the same treatment — the range moves forward by exactly one caret,
41
+ paired with running the full suite against the new version, rather than
42
+ widening to claim a span of untested minors as compatible.
43
+
44
+ ### Why narrow, not wide
45
+
46
+ **Widening a peer range later is patch-safe; narrowing one is breaking.**
47
+ Starting narrow keeps both options open — if a wide band is ever wanted, it
48
+ can be added without breaking anyone. Starting wide commits the package to a
49
+ claim it can only walk back by breaking whoever relied on the wide end.
50
+
51
+ **This package's existing range philosophy for `react` does not transfer to
52
+ Lexical.** The `//peerDependencies` manifest comment already documents that
53
+ ranges are "the compatibility contract, not the tested matrix," and that
54
+ narrowing `react`'s range to match its `devDependency` version "would only
55
+ reject working consumers." That reasoning is sound for React specifically
56
+ *because* React's untested span sits inside a **stable major** — a
57
+ regression there is a bug in React, not a permitted outcome of its
58
+ versioning scheme. Lexical is `0.x`, where semver explicitly permits every
59
+ minor release to be breaking. A range like `>=0.44.0 <0.50.0` would assert
60
+ compatibility with six minors, five of them never run against this
61
+ package's own suite — a materially different, and unjustified, claim.
62
+
63
+ **No known consumer wants Lexical 0.44.** Both known consumers of this
64
+ package (`liminis-app` and the package's own test/build pipeline) are moving
65
+ *toward* 0.49, not sitting on 0.44 and wanting to stay there. The wide
66
+ band's benefit — "don't reject a working consumer on an old version" — is
67
+ close to hypothetical here, while its cost — asserting untested compatibility
68
+ across four intermediate minors known to contain breaking changes (see
69
+ Consequences) — is real.
70
+
71
+ A wide band remains available later, but only backed by CI matrix testing
72
+ across the band's endpoints — that is separate work, out of scope for this
73
+ decision.
74
+
75
+ ### What was verified before this decision was acted on
76
+
77
+ The twelve packages were bumped to `0.49.0` in both `peerDependencies` and
78
+ `devDependencies` (kept in lockstep, per this package's existing pairing
79
+ between the tested version and the declared floor), and the full
80
+ verification chain — `pnpm typecheck`, `pnpm lint`, `pnpm build`,
81
+ `pnpm test` (1591 tests), and `pnpm verify:package` (the packed-tarball
82
+ install-and-typecheck check against a fresh consumer) — ran clean with **no
83
+ source changes required**, despite Lexical's own changelog listing several
84
+ breaking changes in the 0.45–0.49 window (a `config()` protocol rework for
85
+ node classes in 0.49.0; `insertNodes` linebreak-handling changes and a
86
+ deprecated-export removal in 0.46.0; selection/backspace/reconcile changes
87
+ in 0.45.0). This package's sixteen custom Lexical node classes all define
88
+ explicit `getType`/`clone`/`importJSON` statics rather than relying on
89
+ auto-synthesis, which structurally avoided the highest-risk part of the
90
+ 0.49.0 change; the rest of the changelog's items apparently do not intersect
91
+ this package's actual usage patterns, since the suite exercises them and
92
+ passed unmodified.
93
+
94
+ ## Consequences
95
+
96
+ **Positive:**
97
+
98
+ - Consumers can now install this package alongside the current Lexical
99
+ release; the multi-minor stall the issue described cannot recur until
100
+ Lexical ships another minor this package hasn't yet adopted.
101
+ - The Lexical peer range's compatibility claim is now backed by an actual CI
102
+ run against the exact version it names — peer and devDependency are both
103
+ `0.49.0`, so no untested span exists in it. (React's own range still has
104
+ an intentionally untested lower half — peer `^19.2.0` vs. devDependency
105
+ `^19.2.5` — per the `//peerDependencies` note; that is unchanged by this
106
+ decision and follows the opposite, stable-major reasoning explained
107
+ above.)
108
+ - The policy is written down (`//lexicalPeerPolicy` in `package.json`, this
109
+ ADR, and the README's install section), so the next Lexical minor is a
110
+ known, bounded task rather than a rediscovery of this issue's reasoning.
111
+
112
+ **Negative:**
113
+
114
+ - **This is a breaking change.** `^0.44.0` and `^0.49.0` are non-overlapping
115
+ ranges; any consumer still on Lexical 0.44.0–0.48.x will see an
116
+ unmet-peer-dependency warning on installing the next release and must
117
+ upgrade its Lexical family to 0.49.0 first. That is the intended effect of
118
+ narrowing, not a regression.
119
+ - **The stall this issue describes will recur at every future Lexical
120
+ minor**, by design: this package's range never gets ahead of what it has
121
+ actually tested. The mitigation is that each recurrence is now a known,
122
+ bounded task (bump twelve versions, run the suite, adjust the range) with
123
+ a written rationale, rather than an accumulating five-minor gap discovered
124
+ incidentally by a downstream consumer's dependency refresh.
125
+
126
+ **Neutral:**
127
+
128
+ - `react`/`react-dom` peer ranges and all non-Lexical dependencies are
129
+ unaffected; this decision only concerns the Lexical family, and does not
130
+ reopen or alter the existing React range philosophy.
131
+ - No Lexical-API-floor guard test (the kind `tests/package-manifest-contract.test.ts`
132
+ already has for React) was added. That guard exists for React because its
133
+ range makes an untested-lower-half claim that needs policing; the narrow
134
+ Lexical range makes no such claim, so there is nothing analogous to guard
135
+ against.
136
+
137
+ ## References
138
+
139
+ - Issue #92 (this decision), verveguy/liminis#1026 (the originating
140
+ `liminis-app` dependency refresh that surfaced the stall)
141
+ - `package.json` — the `//peerDependencies` and `//lexicalPeerPolicy`
142
+ manifest comments; the twelve `peerDependencies`/`devDependencies` entries
143
+ - `README.md` — "Install" section, the Lexical `pnpm add` block and the
144
+ peer-range policy callout
145
+ - `CHANGELOG.md` — the `## Unreleased` / `### Breaking changes` entry
146
+ recording this bump
147
+ - `docs/decisions/adr-078.md`, `docs/decisions/adr-079.md` — prior ADRs on
148
+ consumer-facing package surface, cited as precedent for treating this as
149
+ ADR-worthy
150
+ - Related: #78 (a required member made 0.2.0 type-level breaking), #79
151
+ (token definitions documented as public API) — prior instances of
152
+ consumer-facing surface needing explicit treatment
@@ -0,0 +1,288 @@
1
+ # ADR-93: `--liminis-editor-*` Names Are Defined as Aliases of Their Legacy Names
2
+
3
+ **Date:** 2026-08-20
4
+ **Status:** Accepted
5
+ **Supersedes:** none
6
+ **Amends:** none
7
+ **Issue:** #93 (verveguy/liminis-editor)
8
+
9
+ ## Context
10
+
11
+ ADR-087 (#51) renamed every *consumption* site to `--liminis-editor-*`,
12
+ deliberately leaving every *definition* site (`:root`, `.dark`, the
13
+ `@media print` block) declaring the old, pre-`0.2.0` names. ADR-092 (#79)
14
+ built a checked-in baseline guarding those definitions, and explicitly
15
+ deferred a third item: whether the package should ever *define*
16
+ `--liminis-editor-*` names directly, with the legacy names kept as an
17
+ alias layer underneath.
18
+
19
+ That gap is not theoretical. Zusammen, a downstream host, reads this
20
+ package's definitions directly — `var(--vscode-background)`,
21
+ `var(--vscode-border)`, etc. — mapping its own design-system tokens onto
22
+ them rather than overriding them
23
+ ([verveguy/zusammen#129](https://github.com/verveguy/zusammen/issues/129)).
24
+ It wants to migrate those reads onto `--liminis-editor-*` instead, but
25
+ before this change there was nothing to migrate to: every row in the
26
+ README's token table read "Has a default: No (inline fallback only)."
27
+
28
+ **The naive fix is the trap ADR-087 already reasoned through once, now on
29
+ the definition side.** Adding `--liminis-editor-foreground: <default>;` to
30
+ the package's own `:root` unconditionally would resolve every one of the
31
+ 250 consumption chains (`var(--liminis-editor-foreground, var(--vscode-foreground))`)
32
+ at the new name before ever reaching the old one — silently disabling the
33
+ ADR-087 fallback layer. A host like `liminis-app`, which supplies only
34
+ `--color-primary`/`--color-muted-foreground` (its own Tailwind `@theme`
35
+ tokens, coincidentally the fallback names `C4Component.tsx` already uses),
36
+ would stop tracking its own overrides with no error and no failing test —
37
+ exactly the failure mode ADR-092 exists to guard against.
38
+
39
+ Two further, non-obvious problems surfaced during implementation, not
40
+ anticipated by the plan:
41
+
42
+ 1. **A definition-side alias's own `var()` reference is textually
43
+ indistinguishable from a consumption site.** `scripts/lib/theming-tokens.mjs`'s
44
+ `consumptionSitesIn()` scans raw text for depth-0 `var(--x` occurrences
45
+ with no awareness of whether the enclosing statement is a custom-property
46
+ *declaration* (`--liminis-editor-foreground: var(--vscode-foreground);`)
47
+ or an ordinary property/JS-style value (`color: var(--liminis-editor-foreground, ...)`).
48
+ Adding the alias block as originally planned would have made every one
49
+ of the ~40 flat-aliased legacy names register as a newly "consumed"
50
+ token, growing the README table and `TOKEN_DESCRIPTIONS` maintenance
51
+ surface for tokens no host-facing code actually reads — a regression
52
+ against this issue's own explicit Out of Scope ("does not add or remove
53
+ rows" from the consumed/documented table).
54
+ 2. **A CSS block comment containing a literal `*/` substring inside its
55
+ text terminates early.** An early draft of the new `:root` block's
56
+ header comment read `--vscode-*/--slashmd-*/--checkbox-*` — the `*/`
57
+ embedded in `--vscode-*/--slashmd-*` closed the comment there, both for
58
+ real CSS parsers and for this repo's own `stripCssComments()`, leaving
59
+ the remainder of the intended comment as live (invalid) CSS text. This
60
+ would have shipped a real authoring bug, not just a test artifact.
61
+
62
+ ## Decision
63
+
64
+ **Legacy names keep carrying the real defaults. Each `--liminis-editor-*`
65
+ name becomes a new declaration that reads its legacy name via `var()`** —
66
+ `--liminis-editor-foreground: var(--vscode-foreground);` — added in a new
67
+ `:root`/`.dark` block placed immediately after the package's existing
68
+ `:root`/`.dark` blocks in `src/styles.css`. This is the direction the
69
+ spec's Background illustrated and Research confirmed by inspecting this
70
+ file's cascade structure directly: a CSS custom property resolves against
71
+ the *element's own* cascade at the point of use, not at declaration time,
72
+ so a single `:root`-level alias re-resolves correctly through `.dark`'s and
73
+ the `@media print` block's overrides of the *legacy* name it points to —
74
+ no per-block alias duplication is needed, and neither `.dark` nor the print
75
+ block needed to change for the ~40 tokens with a real existing declaration.
76
+
77
+ **All 59 renamed tokens (`PREVIOUS_NAME`'s full set) get a real declaration
78
+ in this pass, not only the two the originating issue named.** FR-001 says
79
+ "every token it currently consumes"; inspection of every consumption site
80
+ found 19 tokens with no existing `:root`/`.dark` legacy declaration to
81
+ alias to, not 2, split into three groups:
82
+
83
+ - **2 tokens** (`--vscode-input-bg`, `--vscode-foreground-muted`) resolve
84
+ today through an existing *nested* fallback at their own consumption
85
+ site. Their alias preserves that chain rather than flattening it:
86
+ `--liminis-editor-input-bg: var(--vscode-input-bg, var(--vscode-code-bg));`.
87
+ - **13 tokens** have no CSS custom property backing anywhere — only a
88
+ literal inline fallback at each consumption site (e.g.
89
+ `var(--vscode-focus-border, #007acc)`). Their alias reproduces that
90
+ literal as the alias's own fallback:
91
+ `--liminis-editor-focus-border: var(--vscode-focus-border, #007acc);` —
92
+ a host supplying nothing sees the same literal as before (FR-002); a
93
+ host supplying the legacy name still wins (FR-003). 6 of these 13 vary by
94
+ theme via a JS `isDark`/`dark` ternary at their consumption sites
95
+ (`button-background`, all 5 `menu-*` tokens); those 6 get a matching
96
+ `.dark` override in the new block, mirroring the same light/dark split
97
+ their consumption sites already express in JS.
98
+ - **4 tokens** (`--color-primary`, `--color-primary-100`,
99
+ `--color-muted-foreground`, `--color-muted-100`) are `liminis-app`'s own
100
+ Tailwind `@theme` brand tokens, for which the package only ever supplied
101
+ a literal final fallback, never asserted ownership. They are aliased
102
+ identically to the 13 above — the mechanism doesn't newly assert
103
+ ownership, it makes the existing fallback literal reachable under the new
104
+ name too.
105
+
106
+ **Two of the 17 no-backing tokens have a real cross-site literal
107
+ inconsistency, discovered by direct inspection (one — `--vscode-errorForeground`
108
+ — was already flagged by Specify; the second — `--vscode-toolbar-hoverBackground`
109
+ — was not):**
110
+
111
+ | Token | Sites | Canonical value chosen |
112
+ |---|---|---|
113
+ | `--vscode-errorForeground` | `#f14c4c` (2 sites: `.editor-link-broken`, `:hover`) vs. `#f44336` (2 sites: `.block-delete-button:hover .block-delete-icon`, `.search-close-button:hover`) | `#f14c4c` — tie broken toward the more semantically central "broken link" indicator over two hover-only chrome details |
114
+ | `--vscode-toolbar-hoverBackground` | `rgba(128, 128, 128, 0.15)` (2 sites) vs. `rgba(128, 128, 128, 0.1)` (1 site, `.drag-handle:hover .drag-handle-icon`) | `rgba(128, 128, 128, 0.15)` — majority (2 of 3) |
115
+
116
+ Once a token has a single real definition, it necessarily wins over every
117
+ site's own inline fallback (fallback only applies when the property is
118
+ genuinely unset) — there is no mechanism that both defines the token
119
+ (FR-001) and preserves two different resolved values at different sites.
120
+ **This unifies 3 sites' rendered color to the canonical value, a small,
121
+ real, intentional visual change**, called out here per this repository's
122
+ convention of recording what a decision costs. The three affected call
123
+ sites (`src/styles.css:1148`, `:1188`, `:1704`) each carry a one-line
124
+ comment noting they are superseded by the new canonical default. The
125
+ spec's Out of Scope section explicitly permits this as a side effect of
126
+ choosing FR-001's value, not as a design goal in its own right.
127
+
128
+ **Consumption sites are left untouched.** All 224 `styles.css` sites and 26
129
+ `.tsx` sites keep their existing `var(--liminis-editor-x, var(--old-name-x, ...))`
130
+ chains. Simplifying them to a single `var(--liminis-editor-x)` call was
131
+ identified as optional cleanup (spec Assumptions) but would strip every
132
+ renamed token's `immediateFallback`, breaking `resolvesToPreviousName()`
133
+ (FR-011's existing drift guard) for all 59 tokens unless that guard were
134
+ also redesigned to check the *definition* site's alias target instead —
135
+ a materially larger, coordinated change deferred out of this issue's scope.
136
+ The now-redundant nested legacy fallback at each site is provably dead code
137
+ once its definition-side alias exists, left in place rather than removed.
138
+
139
+ **`scripts/lib/theming-tokens.mjs`'s `consumptionSitesIn()` gains a
140
+ declaration-value check.** A new helper,
141
+ `isCustomPropertyDeclarationValue(text, varStartIndex)`, walks back from a
142
+ depth-0 `var(` to the nearest statement boundary (`;`, `{`, or `}`) and
143
+ tests whether everything between that boundary and the `var(` is exactly
144
+ `--name:` — the shape only a custom-property declaration's value position
145
+ can have (an ordinary CSS property name never starts with `--`). Each
146
+ site now carries an `isDeclarationValue` flag; `consumedTokens()`'s Pass 1
147
+ skips depth-0 sites where it is true. This keeps the "consumed" inventory —
148
+ and therefore the README table's row set and the `TOKEN_DESCRIPTIONS`
149
+ maintenance surface — exactly as it was before this issue, satisfying its
150
+ Out of Scope constraint, while still letting `defaultedTokens()` (a
151
+ separate, unchanged function that just scans for any `--name:` declaration)
152
+ pick up all 59 new aliases as newly "defined."
153
+
154
+ **No other change to `theming-tokens.mjs` or its `.d.mts`.**
155
+ `isCustomPropertyDeclarationValue` is internal, not exported;
156
+ `defaultedTokens()` needed no change to recognize the new aliases; the
157
+ ADR-092 baseline guard, `resolvesWithoutHost()`, and `resolvesToPreviousName()`
158
+ all continue to operate over the same "consumed"/"defined" definitions they
159
+ already had, now simply seeing a larger defined set.
160
+
161
+ ## Consequences
162
+
163
+ **Good:**
164
+
165
+ - A host can now read `--liminis-editor-x` directly and get a real value in
166
+ every override state — the entire point of this issue and the
167
+ prerequisite for zusammen#129's read migration (FR-001, SC-001, SC-006).
168
+ - A host supplying only a legacy name **at `:root`/`document.documentElement`**
169
+ is unaffected: the alias's `var()` re-resolves through that name's own
170
+ `.dark`/`@media print` overrides at the point of use, verified directly
171
+ against this file's actual cascade structure rather than assumed from the
172
+ general CSS-custom-property theory alone (FR-002, FR-003, User Story 2).
173
+ This is the standard integration point and the one this package's own
174
+ e2e coverage exercises. It does not extend to a legacy override scoped to
175
+ an arbitrary descendant element — see Bad/accepted below.
176
+ - The ADR-092 baseline guard now protects all 59 new alias declarations the
177
+ same way it already protected the legacy ones — a future accidental
178
+ deletion of an alias fails `pnpm test`, naming the token (FR-005, US4).
179
+ - The declaration-value fix to `consumptionSitesIn()` is general: it holds
180
+ for any future alias declaration of this shape without further
181
+ special-casing, not just the 59 added here.
182
+ - The premature-comment-close bug was caught by the same regenerated test
183
+ suite that caught the consumption-site pollution, before either shipped —
184
+ the CI guards this issue extends are what surfaced both problems.
185
+
186
+ **Bad / accepted:**
187
+
188
+ - **The `:root`-only alias does not track a legacy-name override scoped to
189
+ a descendant element below `:root`** (e.g. a per-widget wrapper div a
190
+ host applies its own theme vars to, rather than `document.documentElement`
191
+ itself) — found during PR review (CodeRabbit), confirmed empirically in
192
+ a running Electron app, not merely reasoned about. A custom property
193
+ inherits its parent's already-*computed* value, not the `var()`
194
+ expression that produced it, so the alias's `var(--legacy-x)` is fixed
195
+ using `:root`'s own value of `--legacy-x` and does not re-evaluate for a
196
+ change made further down the tree. Two alternatives were tried and
197
+ rejected, each empirically, in a running app:
198
+ - **Re-declaring the alias on every element (`*`)** does fix the
199
+ descendant case, but then an element's own `*`-matched declaration
200
+ shadows whatever `--liminis-editor-x` value it would otherwise have
201
+ inherited from an ancestor — including a host's own direct
202
+ `--liminis-editor-x` override set on that ancestor. This broke User
203
+ Story 3 (a directly-set `--liminis-editor-*` name must win), which is
204
+ higher-confidence/already-tested behavior — confirmed by a real,
205
+ reproducible test failure, not a theoretical concern.
206
+ - **Scoping the redeclaration to the package's own root wrapper class**
207
+ (`.editor-app-root`) reduces but does not eliminate that same
208
+ shadowing (still breaks a `--liminis-editor-*` override set above
209
+ `.editor-app-root`), and is additionally unreliable on its own terms:
210
+ not every integration renders that wrapper — this repo's own
211
+ `examples/electron` shell mounts a lower-level component without it,
212
+ so the alias would go undeclared there, confirmed by inspecting the
213
+ actual DOM in a running instance.
214
+ - No mechanism was found that recomputes a legacy-name change made
215
+ anywhere below `:root` (User Story 2) while also respecting a
216
+ `--liminis-editor-*` override set on any ancestor of the read element
217
+ (User Story 3) — CSS custom-property inheritance passes down an
218
+ already-resolved value, not a live formula, so a property can prefer
219
+ "inherit if my ancestor set one" or "always recompute from a
220
+ dependency," but not both conditionally per-element without a
221
+ mechanism this package doesn't have (e.g. `@property` plus JS
222
+ reconciliation, well beyond this issue's scope). **The `:root`-only
223
+ design is kept, and this scope limitation is accepted and documented**
224
+ here and in `src/styles.css`'s alias-block comment, per this
225
+ repository's convention of recording what a decision costs rather than
226
+ silently narrowing FR-002/FR-003's stated guarantee. Extending it to
227
+ arbitrary DOM scope, if a specific host needs it, is deferred to a
228
+ follow-up issue — it is a materially larger design problem than this
229
+ ADR anticipated.
230
+ - Three consumption sites (`--vscode-errorForeground` at 2 sites,
231
+ `--vscode-toolbar-hoverBackground` at 1 site) render a different,
232
+ intentionally-unified color than before this change. A host relying on
233
+ the specific pre-existing `#f44336`/`0.1`-alpha rendering at exactly
234
+ those sites will see a small visual shift. This is an unavoidable
235
+ consequence of giving these two tokens a single real definition (FR-001)
236
+ when their own consumption sites already disagreed with each other —
237
+ there is no mechanism that satisfies FR-001 without picking one value.
238
+ - The checked-in baseline grows from 41 to 100 entries in one change. Per
239
+ ADR-092's own design the guard is one-directional (`missing` fails,
240
+ `added` never does), so this is a mechanical `pnpm docs:theming-baseline`
241
+ diff, not a CI risk — but it is a large diff for a human reviewer to
242
+ read line-by-line.
243
+ - Every one of the 250 existing consumption sites keeps a nested legacy
244
+ fallback that is now provably redundant dead code (the definition-side
245
+ alias means the fallback branch can never be reached in practice). Removing
246
+ it was explicitly deferred (see Decision) rather than done here, so this
247
+ verbosity persists in `styles.css` and the five `.tsx` files until a
248
+ future change picks it up.
249
+ - `consumptionSitesIn()`'s declaration-value detection is a text-boundary
250
+ heuristic (nearest `;`/`{`/`}` before the `var(`), not a real CSS parser.
251
+ It is correct for every declaration in this codebase today (all
252
+ single-line), but a future multi-line custom-property declaration split
253
+ across a statement boundary could evade it.
254
+
255
+ **Neutral:**
256
+
257
+ - The `@media print` block needed no changes: its `:root, .dark { ... }`
258
+ selector already overrides every legacy name it touches, and each new
259
+ alias's `var()` reference re-resolves through that override the same way
260
+ it re-resolves through `.dark`'s.
261
+ - `liminis-app`'s own `--color-primary`/`--color-muted-foreground` overrides
262
+ are unaffected either way — the 4 brand-token aliases only make their
263
+ existing fallback literal reachable under the new name too, without
264
+ changing what either name resolves to when the host supplies its usual
265
+ overrides (SC-003).
266
+
267
+ ## References
268
+
269
+ - Issue #93 (this decision); Issue #79 / ADR-092's "Not decided here" —
270
+ this decision's direct origin (Item 3)
271
+ - `docs/decisions/adr-087.md` — the consumption-side rename and fallback
272
+ design this decision extends to the definition side, and the trap
273
+ ("that alternative is broken...") this decision's alias direction avoids
274
+ repeating on the definition side
275
+ - `docs/decisions/adr-092.md` — the checked-in baseline guard this
276
+ decision's new declarations are added to
277
+ - `src/styles.css` — the new `:root`/`.dark` alias block (after the
278
+ existing `.dark` block); the three superseded-literal comments at the
279
+ drag-handle-hover, block-delete-hover, and search-close-hover sites
280
+ - `scripts/lib/theming-tokens.mjs` — `isCustomPropertyDeclarationValue()`,
281
+ `consumptionSitesIn()`'s new `isDeclarationValue` field, and
282
+ `consumedTokens()`'s Pass 1 filter
283
+ - `scripts/lib/theming-defined-tokens-baseline.json` — regenerated via
284
+ `pnpm docs:theming-baseline`, 41 → 100 entries
285
+ - `README.md`, "Theming: CSS custom properties" — regenerated table and
286
+ hand-rewritten prose describing the alias mechanism
287
+ - [verveguy/zusammen#129](https://github.com/verveguy/zusammen/issues/129)
288
+ — the downstream migration this decision unblocks
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@liminis/editor",
3
- "version": "0.2.2",
3
+ "version": "0.3.0",
4
4
  "//publishing": "Publishing is deliberate, never incidental. `private: true` was this package's guard until verveguy/liminis-editor#39 took the publish decision; it is gone because that decision was taken, not because it was tidied away. The guard is now `prepublishOnly` -> scripts/guard-publish.mjs, which refuses unless LIMINIS_ALLOW_PUBLISH=1 is set explicitly. That variable is set at step scope in .github/workflows/publish.yml and nowhere else, so a release is the only path that publishes. Note that `npm publish --dry-run` does NOT report a private package as blocked (npm 10.8.2), which is why the guard is a script rather than a flag.",
5
5
  "license": "MIT",
6
6
  "description": "Lexical-based markdown WYSIWYG editor with mdast round-trip and a host-injection seam",
@@ -80,20 +80,21 @@
80
80
  "build:examples": "node scripts/build-examples.mjs",
81
81
  "build:site": "node scripts/build-site.mjs"
82
82
  },
83
- "//peerDependencies": "Ranges are the compatibility contract, not the tested matrix. CI resolves one point version per range (currently react 19.2.x latest and lexical 0.44.x latest), so every caret range here has an untested lower half \u2014 narrowing `react` to the devDependency's `^19.2.5` would not change that, it would only reject working consumers. The react floor is not a claim, it is enforced: `tests/package-manifest-contract.test.ts` (\"imports no React API newer than the declared 19.2.0 peer floor\") scans every source file for post-19.0 named imports \u2014 `useEffectEvent`, `Activity`, `cacheSignal`, `ViewTransition`, `captureOwnerStack` \u2014 and fails if one appears. Reaching for a newer API therefore breaks CI until you raise the floor here too, which is the pairing this note would otherwise only assert. Raise a floor when the code actually starts needing a later API, not to mirror whatever CI happened to install.",
83
+ "//peerDependencies": "Ranges are the compatibility contract, not the tested matrix. CI resolves one point version per range (currently react 19.2.x latest and lexical 0.49.x latest), so every caret range here has an untested lower half \u2014 narrowing `react` to the devDependency's `^19.2.5` would not change that, it would only reject working consumers. The react floor is not a claim, it is enforced: `tests/package-manifest-contract.test.ts` (\"imports no React API newer than the declared 19.2.0 peer floor\") scans every source file for post-19.0 named imports \u2014 `useEffectEvent`, `Activity`, `cacheSignal`, `ViewTransition`, `captureOwnerStack` \u2014 and fails if one appears. Reaching for a newer API therefore breaks CI until you raise the floor here too, which is the pairing this note would otherwise only assert. Raise a floor when the code actually starts needing a later API, not to mirror whatever CI happened to install. This reasoning does not extend to the Lexical ranges below \u2014 see `//lexicalPeerPolicy`.",
84
+ "//lexicalPeerPolicy": "The twelve Lexical ranges are a single-caret bump per Lexical minor actually adopted and tested here, not a wide multi-version band. `react`'s untested lower half (above) is safe because a break there would be a bug in a stable major; Lexical is `0.x`, where every minor is permitted to break, so a wide band would claim compatibility with untested, potentially-breaking releases. Widening a range later is patch-safe; narrowing one is breaking \u2014 so this stays narrow by default and moves forward only when the code is actually run against the new minor. See docs/decisions/adr-92-lexical-peer-range-policy.md.",
84
85
  "peerDependencies": {
85
- "@lexical/code": "^0.44.0",
86
- "@lexical/code-prism": "^0.44.0",
87
- "@lexical/link": "^0.44.0",
88
- "@lexical/list": "^0.44.0",
89
- "@lexical/mark": "^0.44.0",
90
- "@lexical/markdown": "^0.44.0",
91
- "@lexical/react": "^0.44.0",
92
- "@lexical/rich-text": "^0.44.0",
93
- "@lexical/selection": "^0.44.0",
94
- "@lexical/table": "^0.44.0",
95
- "@lexical/utils": "^0.44.0",
96
- "lexical": "^0.44.0",
86
+ "@lexical/code": "^0.49.0",
87
+ "@lexical/code-prism": "^0.49.0",
88
+ "@lexical/link": "^0.49.0",
89
+ "@lexical/list": "^0.49.0",
90
+ "@lexical/mark": "^0.49.0",
91
+ "@lexical/markdown": "^0.49.0",
92
+ "@lexical/react": "^0.49.0",
93
+ "@lexical/rich-text": "^0.49.0",
94
+ "@lexical/selection": "^0.49.0",
95
+ "@lexical/table": "^0.49.0",
96
+ "@lexical/utils": "^0.49.0",
97
+ "lexical": "^0.49.0",
97
98
  "react": "^19.2.0",
98
99
  "react-dom": "^19.2.0"
99
100
  },
@@ -122,17 +123,17 @@
122
123
  },
123
124
  "devDependencies": {
124
125
  "@eslint/js": "^10.0.1",
125
- "@lexical/code": "^0.44.0",
126
- "@lexical/code-prism": "^0.44.0",
127
- "@lexical/link": "^0.44.0",
128
- "@lexical/list": "^0.44.0",
129
- "@lexical/mark": "^0.44.0",
130
- "@lexical/markdown": "^0.44.0",
131
- "@lexical/react": "^0.44.0",
132
- "@lexical/rich-text": "^0.44.0",
133
- "@lexical/selection": "^0.44.0",
134
- "@lexical/table": "^0.44.0",
135
- "@lexical/utils": "^0.44.0",
126
+ "@lexical/code": "^0.49.0",
127
+ "@lexical/code-prism": "^0.49.0",
128
+ "@lexical/link": "^0.49.0",
129
+ "@lexical/list": "^0.49.0",
130
+ "@lexical/mark": "^0.49.0",
131
+ "@lexical/markdown": "^0.49.0",
132
+ "@lexical/react": "^0.49.0",
133
+ "@lexical/rich-text": "^0.49.0",
134
+ "@lexical/selection": "^0.49.0",
135
+ "@lexical/table": "^0.49.0",
136
+ "@lexical/utils": "^0.49.0",
136
137
  "@testing-library/react": "^16.3.2",
137
138
  "@types/mdast": "^4.0.4",
138
139
  "@types/node": "^25.6.0",
@@ -146,7 +147,7 @@
146
147
  "eslint-plugin-react-refresh": "^0.5.2",
147
148
  "globals": "^17.5.0",
148
149
  "happy-dom": "^20.9.0",
149
- "lexical": "^0.44.0",
150
+ "lexical": "^0.49.0",
150
151
  "react": "^19.2.5",
151
152
  "react-dom": "^19.2.5",
152
153
  "tsc-alias": "^1.9.1",