refactor: factor SelectionStateProvider shape into createSliceStore#2759
Draft
christianhg wants to merge 3 commits into
Draft
refactor: factor SelectionStateProvider shape into createSliceStore#2759christianhg wants to merge 3 commits into
christianhg wants to merge 3 commits into
Conversation
🦋 Changeset detectedLatest commit: de6497e The changes in this PR will be included in the next version bump. This PR includes changesets to release 12 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Contributor
📦 Bundle Stats —
|
| Metric | Value | vs main (fe62016) |
|---|---|---|
| Internal (raw) | 781.7 KB | +3.9 KB, +0.5% |
| Internal (gzip) | 148.8 KB | +1.0 KB, +0.7% |
| Bundled (raw) | 1.39 MB | +3.9 KB, +0.3% |
| Bundled (gzip) | 310.7 KB | +1.0 KB, +0.3% |
| Import time | 96ms | +1ms, +1.1% |
@portabletext/editor/behaviors
| Metric | Value | vs main (fe62016) |
|---|---|---|
| Internal (raw) | 467 B | - |
| Internal (gzip) | 207 B | - |
| Bundled (raw) | 424 B | - |
| Bundled (gzip) | 171 B | - |
| Import time | 2ms | +0ms, +0.3% |
@portabletext/editor/plugins
| Metric | Value | vs main (fe62016) |
|---|---|---|
| Internal (raw) | 2.7 KB | - |
| Internal (gzip) | 894 B | - |
| Bundled (raw) | 2.5 KB | - |
| Bundled (gzip) | 827 B | - |
| Import time | 7ms | +0ms, +0.3% |
@portabletext/editor/selectors
| Metric | Value | vs main (fe62016) |
|---|---|---|
| Internal (raw) | 79.4 KB | - |
| Internal (gzip) | 14.5 KB | - |
| Bundled (raw) | 74.9 KB | - |
| Bundled (gzip) | 13.4 KB | - |
| Import time | 8ms | +0ms, +0.9% |
@portabletext/editor/traversal
| Metric | Value | vs main (fe62016) |
|---|---|---|
| Internal (raw) | 25.5 KB | - |
| Internal (gzip) | 5.0 KB | - |
| Bundled (raw) | 25.5 KB | - |
| Bundled (gzip) | 5.0 KB | - |
| Import time | 6ms | -0ms, -0.6% |
@portabletext/editor/utils
| Metric | Value | vs main (fe62016) |
|---|---|---|
| Internal (raw) | 28.8 KB | - |
| Internal (gzip) | 6.0 KB | - |
| Bundled (raw) | 26.7 KB | - |
| Bundled (gzip) | 5.7 KB | - |
| Import time | 6ms | -0ms, -2.2% |
🗺️ . · ./behaviors · ./plugins · ./selectors · ./traversal · ./utils · Artifacts
Details
- Import time regressions over 10% are flagged with
⚠️ - Sizes shown as raw / gzip 🗜️. Internal bytes = own code only. Total bytes = with all dependencies. Import time = Node.js cold-start median.
📦 Bundle Stats — @portabletext/markdown
Compared against main (fe62016a)
| Metric | Value | vs main (fe62016) |
|---|---|---|
| Internal (raw) | 53.0 KB | - |
| Internal (gzip) | 9.6 KB | - |
| Bundled (raw) | 347.6 KB | - |
| Bundled (gzip) | 96.0 KB | - |
| Import time | 39ms | -1ms, -2.7% |
🗺️ View treemap · Artifacts
Details
- Import time regressions over 10% are flagged with
⚠️ - Sizes shown as raw / gzip 🗜️. Internal bytes = own code only. Total bytes = with all dependencies. Import time = Node.js cold-start median.
Extracts the actor-subscription + microtask-coalesced recompute + per-slice notify pattern out of selection-state-context.tsx into a reusable createSliceStore primitive. The factor is structural only: same actor (editor firehose), same mount-time reconcile, same equality short-circuit, same exposed hooks. No consumer-observable change. selection-state-context.tsx shrinks from 255 to 174 lines as it loses the framework code and keeps only the domain bits (SelectionState shape, defaultSelectionState, selectionStatesEqual, compute closure, the four useIs* slice hooks). createSliceStore is internal-only; not exported from index.ts. Future slice stores for engine signals (drop-target, list-index, etc.) will consume it.
2a5c631 to
c1d112b
Compare
…d*` and `useIsSelected*` hooks
The render callbacks of `defineContainer`, `defineTextBlock`,
`defineBlockObject`, `defineInlineObject`, and `defineSpan` no
longer receive `focused` and `selected`. Read them from inside the
render body via the new `useIsFocused{Container,Leaf}` and
`useIsSelected{Container,Leaf}` hooks. Each hook subscribes to a
single slice and only triggers a re-render when its own value flips,
so renders that don't read `focused` or `selected` no longer
re-render when the caret moves between unrelated nodes.
The legacy `renderBlock`, `renderChild`, `renderDecorator`, and
`renderAnnotation` callbacks on `<PortableTextEditable>` keep their
existing `focused` and `selected` props.
Adds an `@alpha` primitive that lets plugins define a slice of state derived from the editor snapshot. The slice is computed once per snapshot change and shared across all consumers — components reading the slice only re-render when their selected value flips. The primitive is intentionally minimal: a plugin author writes a `compute(snapshot)` function and an `equal(a, b)` selector comparator, and gets back a `Plugin` to mount and a `useSlice(select)` hook to read. The engine owns the slice host and registry; plugins don't need to know how subscription, coalescing, or fan-out work.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
SelectionStateProviderships a self-contained pattern that's worth reusing: subscribe once to an actor, recompute a state struct per change (microtask-coalesced), expose it through auseSyncExternalStore-compatible store so consumers attach per-slice and re-render only when their slice flips.This PR extracts the framework code into
createSliceStore<TState>and rewritesSelectionStateProvideron top of it. Static parts (the context, the default store, the equality function) live on the factory return; dynamic parts (the actor, the compute closure) are Provider props so callers can thread engine refs without forcing a context tear-down on engine change.The factor is structural only:
useIsFocusedContainer/useIsSelectedContainer/useIsFocusedLeaf/useIsSelectedLeaf) with identical behavior.selection-state-context.tsxshrinks from 255 to 174 lines, keeping only the domain bits:SelectionState,defaultSelectionState,selectionStatesEqual, thecomputeclosure that readseditorEngine.snapshot, and the four slice hooks.createSliceStoreis internal-only — not exported fromindex.ts. Future slice stores for engine signals (drop target, list index, focused/selected migration off render-props) consume it.No consumer-observable change.
render-count-regression's "Typing into one sibling re-renders constant work, not O(N) siblings" still passes — the per-slice fan-out cost shape is what the factor is preserving.