diff --git a/.changeset/config.json b/.changeset/config.json index 88387a7e87..77bbd09e67 100644 --- a/.changeset/config.json +++ b/.changeset/config.json @@ -12,8 +12,10 @@ "baseBranch": "main", "updateInternalDependencies": "patch", "ignore": [], + "snapshot": { + "useCalculatedVersion": true + }, "___experimentalUnsafeOptions_WILL_CHANGE_IN_PATCH": { - "useCalculatedVersionForSnapshots": true, "onlyUpdatePeerDependentsWhenOutOfRange": true } } diff --git a/.changeset/fresh-ranges-bow.md b/.changeset/fresh-ranges-bow.md new file mode 100644 index 0000000000..1461e72629 --- /dev/null +++ b/.changeset/fresh-ranges-bow.md @@ -0,0 +1,5 @@ +--- +"slate-dom": patch +--- + +Fix DOM selection resolution after structural edits with stale rendered paths. diff --git a/.changeset/silent-placeholders-smile.md b/.changeset/silent-placeholders-smile.md new file mode 100644 index 0000000000..083bb0e3a2 --- /dev/null +++ b/.changeset/silent-placeholders-smile.md @@ -0,0 +1,5 @@ +--- +"slate-react": patch +--- + +Render default placeholders inline so empty paragraphs keep valid HTML. diff --git a/.changeset/slate-browser-minor.md b/.changeset/slate-browser-minor.md new file mode 100644 index 0000000000..55a2559fa2 --- /dev/null +++ b/.changeset/slate-browser-minor.md @@ -0,0 +1,9 @@ +--- +"slate-browser": minor +--- + +Add the public Slate browser proof harness. + +Use `slate-browser/playwright` for editor behavior tests, `slate-browser/core` for pure proof contracts and release-proof artifacts, `slate-browser/browser` for DOM selection snapshots, and `slate-browser/transports` for device/browser proof-scope descriptors. The package is test infrastructure, not runtime editor API, and its root module is intentionally unavailable. + +Each public subpath ships typed ESM export conditions for consumer import and declaration resolution. diff --git a/.changeset/slate-dom-major.md b/.changeset/slate-dom-major.md new file mode 100644 index 0000000000..ae3aa8b1cf --- /dev/null +++ b/.changeset/slate-dom-major.md @@ -0,0 +1,17 @@ +--- +"slate-dom": major +--- + +Replace the public DOM bridge install surface with the Slate v2 `dom()` extension and editor DOM APIs. + +**Migration:** + +- Use `dom()` instead of `withDOM`. +- Use `editor.api.dom` and `editor.api.clipboard` instead of importing `DOMEditor` as a public runtime object. +- Import public DOM helpers from the `slate-dom` package root; Slate 0.x deep imports from `slate-dom/lib/*` are not public. +- Use nullable `resolveSlatePoint` and `resolveSlateRange` through the editor DOM API, and use assert-style DOM APIs only when unresolved DOM targets should throw. +- Replace DOM coverage `selectionPolicy: 'boundary'` with `selectionPolicy: 'skip'`. +- Replace DOM coverage `selectionPolicy: 'model-backed'` with `selectionPolicy: 'model'`. +- Replace DOM coverage `copyPolicy: 'include-model'` with `copyPolicy: 'model'`. +- Replace DOM coverage `copyPolicy: 'summary-only'` with `copyPolicy: 'summary'`. +- Replace DOM coverage `findPolicy: 'not-native-until-mounted'` with `findPolicy: 'native'` or `findPolicy: 'custom'`. diff --git a/.changeset/slate-dom-minor.md b/.changeset/slate-dom-minor.md new file mode 100644 index 0000000000..551076d825 --- /dev/null +++ b/.changeset/slate-dom-minor.md @@ -0,0 +1,7 @@ +--- +"slate-dom": minor +--- + +Add DOM coverage, clipboard, hotkey, text-diff, environment, ShadowRoot, and DOM selection utilities for non-React Slate integrations. + +Use `DOMCoverage` for hidden, staged, and virtualized same-root content; use `Hotkeys` and `isHotkey` for keyboard shortcut checks. diff --git a/.changeset/slate-dom-patch.md b/.changeset/slate-dom-patch.md new file mode 100644 index 0000000000..3ec1b1af9d --- /dev/null +++ b/.changeset/slate-dom-patch.md @@ -0,0 +1,5 @@ +--- +"slate-dom": patch +--- + +Fix DOM selection, focus, clipboard, ShadowRoot, live path lookup, split-leaf offset, broad range, and void-ended copy handling for Slate v2 editors. diff --git a/.changeset/slate-history-major.md b/.changeset/slate-history-major.md new file mode 100644 index 0000000000..2b9f3b5bdb --- /dev/null +++ b/.changeset/slate-history-major.md @@ -0,0 +1,7 @@ +--- +"slate-history": major +--- + +Replace `withHistory` and `HistoryEditor` with the Slate v2 `history()` extension. + +**Migration:** Install `history()` in `createEditor({ extensions })`, read undo/redo stacks through `state.history`, write history commands through `tx.history`, use `editor.api.history` for batching controls, and import from the package root export. diff --git a/.changeset/slate-hyperscript-major.md b/.changeset/slate-hyperscript-major.md new file mode 100644 index 0000000000..5242b1bc46 --- /dev/null +++ b/.changeset/slate-hyperscript-major.md @@ -0,0 +1,7 @@ +--- +"slate-hyperscript": major +--- + +Update hyperscript fixtures for the Slate v2 runtime and ESM package exports. + +**Migration:** Import `jsx`, `createHyperscript`, `createEditor`, and `createText` from the root package export. Generated editors initialize through the v2 editor runtime, so fixture children, selections, marks, and custom tags follow the current Slate transaction model. diff --git a/.changeset/slate-layout-minor.md b/.changeset/slate-layout-minor.md new file mode 100644 index 0000000000..5d1e765a15 --- /dev/null +++ b/.changeset/slate-layout-minor.md @@ -0,0 +1,7 @@ +--- +"slate-layout": minor +--- + +Add experimental page-layout primitives for Slate documents. + +Use `createSlateLayout` for derived page geometry, line fragments, page-break snapshots, Pretext-backed measurement, and mount plans. Use `slate-layout/react` for `PagedEditable` and React page-layout hooks. diff --git a/.changeset/slate-major.md b/.changeset/slate-major.md new file mode 100644 index 0000000000..d5939cf9c7 --- /dev/null +++ b/.changeset/slate-major.md @@ -0,0 +1,15 @@ +--- +"slate": major +--- + +Replace the mutable editor and `Transforms` surface with the Slate v2 runtime API. + +**Migration:** + +- Create editors with `createEditor({ initialValue })`. +- Read editor state through `editor.read(...)`. +- Mutate document, selection, marks, roots, state fields, and operations through `editor.update((tx) => ...)`. +- Replace `Transforms.*` calls and direct editor mutation with transaction groups such as `tx.nodes`, `tx.selection`, `tx.text`, `tx.value`, and `tx.roots`; write persistent state fields with `tx.setField(...)` and replay remote state changes with `tx.statePatches.replay(...)`. +- Replace helper value namespaces with `ElementApi`, `LocationApi`, `NodeApi`, `OperationApi`, `PathApi`, `PointApi`, `RangeApi`, `SpanApi`, and `TextApi`; keep model names such as `Element`, `Node`, `Range`, and `Text` as types. +- Move editor-root normalizers to `normalizers.editor`; keep non-root node normalizers in `normalizers.node`. +- Import through the package root export; `slate/internal` is the only supported internal subpath. diff --git a/.changeset/slate-minor.md b/.changeset/slate-minor.md new file mode 100644 index 0000000000..4c10be1d41 --- /dev/null +++ b/.changeset/slate-minor.md @@ -0,0 +1,7 @@ +--- +"slate": minor +--- + +Add the Slate v2 extension runtime for schema, state, command, transform, query, and commit integrations. + +Use editor extensions to define element behavior, element properties, content roots, state fields, transaction groups, normalizers, middleware, operation guards, runtime ids, bookmarks, and transaction-aware commit metadata. `InitialValue` also accepts `{ children, roots, state }` for multi-root documents and serializable document state. diff --git a/.changeset/slate-patch.md b/.changeset/slate-patch.md new file mode 100644 index 0000000000..e9121cfd66 --- /dev/null +++ b/.changeset/slate-patch.md @@ -0,0 +1,5 @@ +--- +"slate": patch +--- + +Fix core editing behavior across text insertion, fragment insertion, expanded-selection paste, Backspace empty-block merges, selectable void navigation, runtime-id path lookup, transaction rollback, and shifted root-order updates. diff --git a/.changeset/slate-react-major.md b/.changeset/slate-react-major.md new file mode 100644 index 0000000000..21ba67583d --- /dev/null +++ b/.changeset/slate-react-major.md @@ -0,0 +1,16 @@ +--- +"slate-react": major +--- + +Replace the Slate 0.x React wrapper and renderer surface with the Slate v2 React runtime. + +**Migration:** + +- Create React editors with `useSlateEditor` or `createReactEditor`; use the `react()` extension for lower-level composition. +- Use `` with the v2 ``. +- Use React 19.2 or newer and import through the `slate-react` package root export. +- Replace `withReact`, old `ReactEditor` value imports, `DefaultElement`, `DefaultLeaf`, `DefaultText`, `useSlate`, `useSlateStatic`, `useSlateSelector`, `useSlateSelection`, `useSelected`, `useFocused`, `useReadOnly`, and `useComposing` with the v2 components and hooks exported from `slate-react`. +- Use `SlateElement`, `SlateText`, `SlateLeaf`, and `SlatePlaceholder` for custom renderer DOM attributes. +- Resolve element paths inside handlers with `editor.api.dom.resolvePath(element)` or `useElementPath()` instead of reading eager `path` and `index` render props. +- Replace `Editable` input rules with model-owned editor extensions or browser-specific `onDOMBeforeInput` handling. +- Use DOM coverage policy props with `selectionPolicy="materialize" | "skip" | "model"`, `copyPolicy="model" | "summary" | "exclude" | "materialize"`, and `findPolicy="native" | "custom"`. diff --git a/.changeset/slate-react-minor.md b/.changeset/slate-react-minor.md new file mode 100644 index 0000000000..599c94ed3e --- /dev/null +++ b/.changeset/slate-react-minor.md @@ -0,0 +1,7 @@ +--- +"slate-react": minor +--- + +Add React APIs for Slate v2 annotations, widgets, decoration sources, root runtimes, content roots, DOM strategies, command callbacks, state fields, typed renderers, and virtualized editor surfaces. + +Use `useSlateRuntime`, `useSlateRuntimeState`, `useSlateRootState`, `useSlateRootEditor`, `useSlateActiveEditor`, `useSlateCommandCallback`, `useSlateRootEffect`, `useSlateContentRoot`, `useSlateDecorationSource`, `useSlateRangeDecorationSource`, `useSlateAnnotationStore`, `useSlateWidgetStore`, `useSlateNodeRef`, `useElementPath`, and `useElementSelected` for advanced integrations. diff --git a/.changeset/slate-react-patch.md b/.changeset/slate-react-patch.md new file mode 100644 index 0000000000..14d87cbca3 --- /dev/null +++ b/.changeset/slate-react-patch.md @@ -0,0 +1,5 @@ +--- +"slate-react": patch +--- + +Fix React editor behavior across async decorations, custom placeholders, editable void content roots, multi-root focus/history restoration, read-only selection, hidden DOM coverage selection, rich paste, undo/redo DOM repair, repeated caret autoscroll, SSR hook snapshots, selector cleanup, virtualized rendering, paged editing, and double-mounted content roots. diff --git a/.changeset/slate-yjs-from-scratch.md b/.changeset/slate-yjs-from-scratch.md new file mode 100644 index 0000000000..823f078211 --- /dev/null +++ b/.changeset/slate-yjs-from-scratch.md @@ -0,0 +1,5 @@ +--- +"@slate/yjs": patch +--- + +Add the first-party Yjs collaboration package scaffold with operation-level text, node, remove, split, merge, move, set, replace-children, replace-fragment, insert-fragment, delete-fragment, wrap, unwrap, and lift collaboration support, plus selection relative-position conversion, split undo repair, and virtual merge/wrapper refs for concurrent remote edits. Pin the audited Yjs UndoManager stack contract and keep broad replace-fragment fallback traceable as an identity-risk path. diff --git a/.changeset/slate-yjs-history-redo.md b/.changeset/slate-yjs-history-redo.md new file mode 100644 index 0000000000..71aa920a51 --- /dev/null +++ b/.changeset/slate-yjs-history-redo.md @@ -0,0 +1,5 @@ +--- +"@slate/yjs": patch +--- + +Fix split history undo and redo preserving concurrent edits, right-side text, no-op replace fragments, and cursor repair. diff --git a/.changeset/slate-yjs-offline-split-undo.md b/.changeset/slate-yjs-offline-split-undo.md new file mode 100644 index 0000000000..0cf2cd7198 --- /dev/null +++ b/.changeset/slate-yjs-offline-split-undo.md @@ -0,0 +1,5 @@ +--- +"@slate/yjs": patch +--- + +Fix offline split undo/redo convergence and structural Yjs path repair for concurrent wrap, move, merge, unwrap, and reconnect edits. diff --git a/.changeset/steady-yjs-structures.md b/.changeset/steady-yjs-structures.md new file mode 100644 index 0000000000..3e23f2d45a --- /dev/null +++ b/.changeset/steady-yjs-structures.md @@ -0,0 +1,5 @@ +--- +"@slate/yjs": patch +--- + +Fix structural collaboration edits that could crash or render nested paragraphs. diff --git a/.gitattributes b/.gitattributes index 6313b56c57..31dcb0e51c 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1 +1,6 @@ * text=auto eol=lf + +# Codex Autoresearch ledger files +autoresearch.jsonl text eol=lf +autoresearch.md text eol=lf +autoresearch.ideas.md text eol=lf diff --git a/.gitignore b/.gitignore index 8e01656f3d..7a7baba852 100644 --- a/.gitignore +++ b/.gitignore @@ -8,7 +8,13 @@ dist/ lib/ node_modules/ site/out/ -tmp/ +*tmp/ test-results/ coverage .DS_Store +.clawpatch/ +**/next-env.d.ts + +# Autoresearch session state +/autoresearch.* +/autoresearch.research/ diff --git a/Readme.md b/Readme.md index 5d6195f35d..f7d1166d30 100644 --- a/Readme.md +++ b/Readme.md @@ -1,173 +1,153 @@ -

- -

+# Slate -

- A completely customizable framework
- for building rich text editors. -

-
+Slate is a customizable framework for building rich-text editors. It owns the +document model, selection model, operations, history, DOM bridge, and React +editable runtime while leaving product features such as toolbars, schema rules, +serialization, comments, sync adapters, and layout to application code or +extensions. -

- Why? · - Principles · - Demo · - Examples · - Documentation · - Contributing! -

-
+The current public lifecycle is: -

- -

+```tsx +const value = editor.read((state) => state.value.get()) -

- - - - - - - - - -

-
- -Slate lets you build rich, intuitive editors like those in [Medium](https://medium.com/), [Dropbox Paper](https://www.dropbox.com/paper) or [Google Docs](https://www.google.com/docs/about/)—which are becoming table stakes for applications on the web—without your codebase getting mired in complexity. - -It can do this because all of its logic is implemented with a series of plugins, so you aren't ever constrained by what _is_ or _isn't_ in "core". You can think of it like a pluggable implementation of `contenteditable` built on top of [React](https://facebook.github.io/react/). It was inspired by libraries like [Draft.js](https://facebook.github.io/draft-js/), [Prosemirror](http://prosemirror.net/) and [Quill](http://quilljs.com/). - -> 🤖 **Slate is currently in beta.** Its core API is useable right now, but you might need to pull request improvements for advanced use cases, or fixes for some bugs. Some of its APIs are not "finalized" and will have breaking changes over time as we discover better solutions. There isn't currently a `1.0` release schedule, we're still getting the architecture right. - -> 🤖 **Slate is also contributor-driven.** It is not backed by any huge company, which means that all contributions are voluntary and done by the people who need them. If you need something improved, added, or fixed, please contribute it yourself or no one will. And if you want to become a more active maintainer, let us know in the Slack channel. - -
- -### Why? - -Why create Slate? Well... _(Beware: this section has a few of [my](https://github.com/ianstormtaylor) opinions!)_ - -Before creating Slate, I tried a lot of the other rich text libraries out there—[**Draft.js**](https://facebook.github.io/draft-js/), [**Prosemirror**](http://prosemirror.net/), [**Quill**](http://quilljs.com/), etc. What I found was that while getting simple examples to work was easy enough, once you started trying to build something like [Medium](https://medium.com/), [Dropbox Paper](https://www.dropbox.com/paper) or [Google Docs](https://www.google.com/docs/about/), you ran into deeper issues... - -- **The editor's "schema" was hardcoded and hard to customize.** Things like bold and italic were supported out of the box, but what about comments, or embeds, or even more domain-specific needs? - -- **Transforming the documents programmatically was very convoluted.** Writing as a user may have worked, but making programmatic changes, which is critical for building advanced behaviors, was needlessly complex. - -- **Serializing to HTML, Markdown, etc. seemed like an afterthought.** Simple things like transforming a document to HTML or Markdown involved writing lots of boilerplate code, for what seemed like very common use cases. - -- **Re-inventing the view layer seemed inefficient and limiting.** Most editors rolled their own views, instead of using existing technologies like React, so you have to learn a whole new system with new "gotchas". - -- **Collaborative editing wasn't designed for in advance.** Often the editor's internal representation of data made it impossible to use to for a realtime, collaborative editing use case without basically rewriting the editor. - -- **The repositories were monolithic, not small and reusable.** The code bases for many of the editors often didn't expose the internal tooling that could have been re-used by developers, leading to having to reinvent the wheel. - -- **Building complex, nested documents was impossible.** Many editors were designed around simplistic "flat" documents, making things like tables, embeds and captions difficult to reason about and sometimes impossible. - -Of course not every editor exhibits all of these issues, but if you've tried using another editor you might have run into similar problems. To get around the limitations of their API's and achieve the user experience you're after, you have to resort to very hacky things. And some experiences are just plain impossible to achieve. - -If that sounds familiar, you might like Slate. - -Which brings me to how Slate solves all of that... - -
- -### Principles - -Slate tries to solve the question of "[Why?](#why)" with a few principles: - -1. **First-class plugins.** The most important part of Slate is that plugins are first-class entities. That means you can _completely_ customize the editing experience, to build complex editors like Medium's or Dropbox's, without having to fight against the library's assumptions. - -2. **Schema-less core.** Slate's core logic assumes very little about the schema of the data you'll be editing, which means that there are no assumptions baked into the library that'll trip you up when you need to go beyond the most basic use cases. - -3. **Nested document model.** The document model used for Slate is a nested, recursive tree, just like the DOM itself. This means that creating complex components like tables or nested block quotes are possible for advanced use cases. But it's also easy to keep it simple by only using a single level of hierarchy. - -4. **Parallel to the DOM.** Slate's data model is based on the DOM—the document is a nested tree, it uses selections and ranges, and it exposes all the standard event handlers. This means that advanced behaviors like tables or nested block quotes are possible. Pretty much anything you can do in the DOM, you can do in Slate. - -5. **Intuitive commands.** Slate documents are edited using "commands", that are designed to be high-level and extremely intuitive to write and read, so that custom functionality is as expressive as possible. This greatly increases your ability to reason about your code. - -6. **Collaboration-ready data model.** The data model Slate uses—specifically how operations are applied to the document—has been designed to allow for collaborative editing to be layered on top, so you won't need to rethink everything if you decide to make your editor collaborative. - -7. **Clear "core" boundaries.** With a plugin-first architecture, and a schema-less core, it becomes a lot clearer where the boundary is between "core" and "custom", which means that the core experience doesn't get bogged down in edge cases. - -
- -### Demo - -Check out the [**live demo**](http://slatejs.org) of all of the examples! - -
- -### Examples - -To get a sense for how you might use Slate, check out a few of the examples: - -- [**Plain text**](https://github.com/ianstormtaylor/slate/tree/main/site/examples/ts/plaintext.tsx) — showing the most basic case: a glorified `