@portabletext/editor 1.49.8 → 1.49.10

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.
@@ -24,16 +24,16 @@ import type {
24
24
  } from '@sanity/types'
25
25
  import {
26
26
  Element,
27
+ Node,
27
28
  Text,
28
29
  Transforms,
29
30
  type Descendant,
30
- type Node,
31
31
  type Path as SlatePath,
32
32
  } from 'slate'
33
33
  import type {EditorSchema} from '../editor/editor-schema'
34
34
  import type {PortableTextSlateEditor} from '../types/editor'
35
35
  import {debugWithName} from './debug'
36
- import {toSlateValue} from './values'
36
+ import {isEqualToEmptyEditor, toSlateValue} from './values'
37
37
  import {KEY_TO_SLATE_ELEMENT} from './weakMaps'
38
38
 
39
39
  const debug = debugWithName('applyPatches')
@@ -173,9 +173,24 @@ function insertPatch(
173
173
  const targetBlockIndex = targetBlockPath[0]
174
174
  const normalizedIdx =
175
175
  position === 'after' ? targetBlockIndex + 1 : targetBlockIndex
176
+
176
177
  debug(`Inserting blocks at path [${normalizedIdx}]`)
177
178
  debugState(editor, 'before')
179
+
180
+ const editorWasEmptyBefore = isEqualToEmptyEditor(editor.children, schema)
181
+
178
182
  Transforms.insertNodes(editor, blocksToInsert, {at: [normalizedIdx]})
183
+
184
+ if (
185
+ editorWasEmptyBefore &&
186
+ typeof patch.path[0] === 'number' &&
187
+ patch.path[0] === 0
188
+ ) {
189
+ Transforms.removeNodes(editor, {
190
+ at: [position === 'before' ? targetBlockIndex + 1 : targetBlockIndex],
191
+ })
192
+ }
193
+
179
194
  debugState(editor, 'after')
180
195
  return true
181
196
  }
@@ -319,9 +334,15 @@ function unsetPatch(editor: PortableTextSlateEditor, patch: UnsetPatch) {
319
334
  debugState(editor, 'before')
320
335
  const previousSelection = editor.selection
321
336
  Transforms.deselect(editor)
322
- editor.children.forEach((_child, i) => {
323
- Transforms.removeNodes(editor, {at: [i]})
337
+
338
+ const children = Node.children(editor, [], {
339
+ reverse: true,
324
340
  })
341
+
342
+ for (const [_, path] of children) {
343
+ Transforms.removeNodes(editor, {at: path})
344
+ }
345
+
325
346
  Transforms.insertNodes(editor, editor.pteCreateTextBlock({decorators: []}))
326
347
  if (previousSelection) {
327
348
  Transforms.select(editor, {
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Copy/pasted from https://github.com/statelyai/xstate/blob/main/packages/xstate-react/src/stopRootWithRehydration.ts
3
+ * and renamed to `stopActor`
4
+ */
5
+
6
+ import type {AnyActorRef, Snapshot} from 'xstate'
7
+
8
+ const forEachActor = (
9
+ actorRef: AnyActorRef,
10
+ callback: (ref: AnyActorRef) => void,
11
+ ) => {
12
+ callback(actorRef)
13
+ const children = actorRef.getSnapshot().children
14
+ if (children) {
15
+ Object.values(children).forEach((child) => {
16
+ forEachActor(child as AnyActorRef, callback)
17
+ })
18
+ }
19
+ }
20
+
21
+ export function stopActor(actorRef: AnyActorRef) {
22
+ // persist snapshot here in a custom way allows us to persist inline actors and to preserve actor references
23
+ // we do it to avoid setState in useEffect when the effect gets "reconnected"
24
+ // this currently only happens in Strict Effects but it simulates the Offscreen aka Activity API
25
+ // it also just allows us to end up with a somewhat more predictable behavior for the users
26
+ const persistedSnapshots: Array<[AnyActorRef, Snapshot<unknown>]> = []
27
+ forEachActor(actorRef, (ref) => {
28
+ persistedSnapshots.push([ref, ref.getSnapshot()])
29
+ // muting observers allow us to avoid `useSelector` from being notified about the stopped snapshot
30
+ // React reconnects its subscribers (from the useSyncExternalStore) on its own
31
+ // and userland subscibers should basically always do the same anyway
32
+ // as each subscription should have its own cleanup logic and that should be called each such reconnect
33
+ ;(ref as any).observers = new Set()
34
+ })
35
+ const systemSnapshot = actorRef.system.getSnapshot?.()
36
+
37
+ actorRef.stop()
38
+ ;(actorRef.system as any)._snapshot = systemSnapshot
39
+ persistedSnapshots.forEach(([ref, snapshot]) => {
40
+ ;(ref as any)._processingStatus = 0
41
+ ;(ref as any)._snapshot = snapshot
42
+ })
43
+ }
@@ -0,0 +1,15 @@
1
+ import React from 'react'
2
+
3
+ type ConstantRef<TConstant> = {constant: TConstant}
4
+
5
+ export default function useConstant<TConstant>(
6
+ factory: () => TConstant,
7
+ ): TConstant {
8
+ const ref = React.useRef<ConstantRef<TConstant>>(null)
9
+
10
+ if (!ref.current) {
11
+ ref.current = {constant: factory()}
12
+ }
13
+
14
+ return ref.current.constant
15
+ }