Releases: michael/svedit
0.8.0
- feat: Add
--node-caret-boundaryCSS token that lets consumers clamp edge gaps (before first / after last node) to a parent element's border box, preventing overlap with neighboring UI elements - fix: When selection has no common parent, return null
- fix: document
--rowfor node arrays in README - fix: Move NodeGap from being a child of Node to a sibling rendered by NodeArrayProperty. The reason is that Node gaps are getting zero width when a node has transform, filter, or will-change (which create new containing blocks that break CSS anchor positioning for child elements).
Full Changelog: v0.7.1...v0.8.0
0.7.1
0.7.0
- feat: Beautifully aligned blinking cursors by @johannesmutter that fill the gaps between nodes, independent of your layout choices
- feat: NodeGap, NodeGapMarkers, NodeCursor, NodeSelectionMarkers exported from library with sensible defaults, overridable via system_components
- feat: gap computation with visibility culling (node_gap_computation.svelte.js)
- feat: Allow custom attributes to be passed to Node, AnnotatedTextProperty, CustomProperty, and NodeArrayProperty
- breaking: NodeCursorTrap removed from system_components — gap rendering now ships as a library default
- breaking: --layout-orientation: horizontal/vertical replaced by --row: 1/0 (pure CSS, no JS)
- breaking: --row default is 1 (horizontal), matching flex-direction: row — vertical containers must set --row: 0
- breaking: Overlays no longer renders selection highlights — use it only for custom UI (link previews, etc.)
- breaking: rename NodeCursorTrap → NodeGap, .cursor-trap → .node-gap, data-type="after-node-cursor-trap" → "gap-after", "position-zero-cursor-trap" → "gap-before"
- breaking: rename --node-cursor-caret-* CSS variables → --node-cursor-* (dropped redundant -caret- infix)
- breaking: Changed keyboard shortcut for change type/layout to Ctrl+Shift+Left/Right/Up/Down
- fix: Selection highlight causing DOM selection feedback loop
- fix: Cross-depth node selections now resolving to the lowest common ancestor node array instead of only handling one level of nesting
Full Changelog: v0.6.4...v0.7.0
Migration guide
Gap and selection rendering moved from user-land into the library with sensible defaults. Orientation detection replaced JS getComputedStyle reads with pure CSS (--row: 1/0). Gaps fill the space between nodes in a NodeArray (min 16px if no gap/padding), and hit targets fill available space for better ergonomics (Fitts's law). Components renamed for clarity.
Breaking changes
1. system_components: NodeCursorTrap no longer required
Before: NodeCursorTrap had to be imported from user-land and passed in system_components:
import NodeCursorTrap from './components/NodeCursorTrap.svelte';
import Overlays from './components/Overlays.svelte';
system_components: {
NodeCursorTrap,
Overlays
}After: Gap components ship as library defaults. Only pass your own overlays:
import Overlays from './components/Overlays.svelte';
system_components: {
Overlays // optional: link previews, image editors, etc.
}Overridable defaults (all optional): NodeGap, NodeGapMarkers, NodeSelectionMarkers.
2. Component and CSS renames
Before (main) |
After |
|---|---|
NodeCursorTrap component |
NodeGap (library export) |
.cursor-trap class |
.node-gap |
data-type="after-node-cursor-trap" |
data-type="gap-after" |
data-type="position-zero-cursor-trap" |
data-type="gap-before" |
Update any custom CSS or JS queries targeting these.
3. --layout-orientation replaced by --row
Before: Orientation was a CSS string read via JS at runtime:
--layout-orientation: horizontal; /* or vertical */After: Pure CSS numeric toggle, no JS needed:
--row: 1; /* horizontal (default — matches flex-direction: row) */
--row: 0; /* vertical */Default is 1 (horizontal). Vertical containers must set --row: 0 explicitly:
.my-vertical-container {
flex-direction: column;
--row: 0;
}4. Overlays is now user-land only
Before Overlays contained both node selection overlays and custom UI (link actions). Selection rendering now lives in NodeSelectionMarkers (rendered automatically by Svedit). Overlays is only for your own UI.
5. CSS variables to customize editor colors have changed
Override Svedit's default colors with:
--svedit-brand: oklch(60% 0.22 100);
--svedit-editing-stroke: var(--svedit-brand);
--svedit-editing-fill: oklch(from var(--svedit-brand) l c h / 0.1);
--svedit-canvas-stroke: color-mix(in oklch, currentColor 25%, transparent);0.6.4
- fix: Run oncut/oncopy/onpaste handlers only in edit mode
- fix: Do not extend an annotation when the caret is exactly at its start
- fix: Make sure text-transform is always disabled when a TextProperty is editable and focused
- demo: Type switcher now does nothing if there's only one type to switch to
Full Changelog: v0.6.3...v0.6.4
0.6.3
- fix: Expose node ids via id attribute, enabling deep linking
- fix: Revert to caret-shape: bar (caret-shape: block doesn’t feel nice)
Full Changelog: v0.6.2...v0.6.3
0.6.2
- fix: Selection mapping was wrong when last character is a newline and cursor is placed after
- fix: Negative tab-index for the Svedit canvas element (avoids accidental scrolls to the top of the canvas)
- fix: Make NodeCursorTrap render correctly in Firefox
Full Changelog: v0.6.1...v0.6.2
0.6.1
- fix: Ensure selection direction is preserved in when rendering text selections
- fix: Do not render selection highlight span for collapsed cursors, as this breaks Safari cursor navigation in empty nodes (see https://bugs.webkit.org/show_bug.cgi?id=304143)
Full Changelog: v0.6.0...v0.6.1
0.6.0
- feat: Opt-in batching of history entries
- feat: Set custom tag and class for Node / AnnotatedTextProperty / CustomProperty
- feat: Each change now yields a new document (session.doc) using copy on write making them immutable
- feat: New Command API that introduces custom command state (e.g. active state for annotation toggles)
- feat: Introduce KeyMapper for handling key combos on both app level and inside a Svedit scope
- feat: Render selection highlight for text selections to be used as an anchor for overlay positioning.
- feat: Add comprehensive API docs in README.md
- breaking: Serialization format now corresponds 1:1 with session.doc
- breaking: Equivalent, transparent, and fully controllable DOM structure (Node / AnnotatedTextProperty / CustomProperty) in read and edit mode.
- breaking: Removed Document in favor of Session, which holds a doc, selection and history (all immutable).
- fix: Handle text replacements at onbeforeinput stage (no more DOM leaking/diffing/recovery)
- fix: Stabilized character composition (relying only on oncompositionstart, oncompositionend, no more DOM diffing)
- fix: Annotation nodes are now properly disposed on tr.insert_text (when the selection is wrapping annotations)
- fix: Ensure sure annotations can not be created on a collapsed range
- fix: Fixed a series of bugs related to composition events on Android
- fix: Also handle input types ‘deleteWordBackward’, ‘deleteWordForward’, and ‘deleteContent’ which are fired by Mobile Safari
- fix: Rollback DOM at oncompositionend stage, enabling incremental re-rendering (no keyed block needed anymore).
Full Changelog: v0.5.0...v0.6.0
0.5.0
- feat: much improved copy & paste experience
- feat: image pastes from the file system can now be handled via handle_image_paste
- feat: automatically transform text nodes to other types if needed (e.g. pasting paragraphs into a list will turn them into list_items)
- feat: default values can now be specified in property definitions
- breaking: tr.insert_nodes now takes an array of node ids, which may have to be created with tr.create before
- fix: node selections are only copied when they are valid within the target, and are otherwise rejected
- fix: text annotations are now part of the copy payload
- fix: plain text payload for external copies is now correct
- fix: Much improved HTML export with a new default html exporter that only considers annotated_text properties
Full Changelog: v0.4.0...v0.5.0
0.4.0
- breaking: In a node schema properties are now defined inside a properties key.
- breaking: annotations are now modeled as nodes too
- breaking: doc.kind() got replaced with schema[node_type].kind
- breaking: annotated_string renamed to annotated_text and represented as an object rather than a tuple
- fix: when setting a selection it will be first validated (out of bound errors, etc.)
- fix: layout selector now also available when selection is in a child of the layout owner node
- feat: specify which annotations are allowed for an annotated_text property
- feat: specify if newlines are allowed in an annotated_text property
- demo: introduce a new ‘highlight’ annotation type in the Svedit demo
Full Changelog: v0.3.0...v0.4.0