diff --git a/.changeset/thick-fishes-dance.md b/.changeset/thick-fishes-dance.md
new file mode 100644
index 000000000..a9aa4d92b
--- /dev/null
+++ b/.changeset/thick-fishes-dance.md
@@ -0,0 +1,7 @@
+---
+'slate-react': minor
+---
+
+Fixes a bug with `ReactEditor.focus` where it would throw an error if the editor was in the middle of applying pending operations.
+With this change, setting focus will be retried until the editor no longer has any pending operations.
+Calling `ReactEditor.focus` on a editor without a current selection, will now make a selection in the top of the document.
diff --git a/packages/slate-react/package.json b/packages/slate-react/package.json
index b83d0b3c8..f091eb21b 100644
--- a/packages/slate-react/package.json
+++ b/packages/slate-react/package.json
@@ -26,15 +26,14 @@
},
"devDependencies": {
"@babel/runtime": "^7.23.2",
+ "@testing-library/react": "^14.0.0",
"@types/jest": "29.5.6",
"@types/jsdom": "^21.1.4",
"@types/react": "^18.2.28",
"@types/react-dom": "^18.2.13",
- "@types/react-test-renderer": "^18.0.3",
"@types/resize-observer-browser": "^0.1.8",
"react": "^18.2.0",
"react-dom": "^18.2.0",
- "react-test-renderer": "^18.2.0",
"slate": "^0.100.0",
"slate-hyperscript": "^0.100.0",
"source-map-loader": "^4.0.1"
diff --git a/packages/slate-react/src/plugin/react-editor.ts b/packages/slate-react/src/plugin/react-editor.ts
index 6c4d5e817..422b1e816 100644
--- a/packages/slate-react/src/plugin/react-editor.ts
+++ b/packages/slate-react/src/plugin/react-editor.ts
@@ -117,7 +117,7 @@ export interface ReactEditorInterface {
/**
* Focus the editor.
*/
- focus: (editor: ReactEditor) => void
+ focus: (editor: ReactEditor, options?: { retries: number }) => void
/**
* Return the host window of the current editor.
@@ -411,19 +411,44 @@ export const ReactEditor: ReactEditorInterface = {
)
},
- focus: editor => {
+ focus: (editor, options = { retries: 5 }) => {
+ // Return if already focused
+ if (IS_FOCUSED.get(editor)) {
+ return
+ }
+
+ // Retry setting focus if the editor has pending operations.
+ // The DOM (selection) is unstable while changes are applied.
+ // Retry until retries are exhausted or editor is focused.
+ if (options.retries <= 0) {
+ throw new Error(
+ 'Could not set focus, editor seems stuck with pending operations'
+ )
+ }
+ if (editor.operations.length > 0) {
+ setTimeout(() => {
+ ReactEditor.focus(editor, { retries: options.retries - 1 })
+ }, 10)
+ return
+ }
+
const el = ReactEditor.toDOMNode(editor, editor)
const root = ReactEditor.findDocumentOrShadowRoot(editor)
- IS_FOCUSED.set(editor, true)
-
if (root.activeElement !== el) {
+ // Ensure that the DOM selection state is set to the editor's selection
if (editor.selection && root instanceof Document) {
const domSelection = root.getSelection()
const domRange = ReactEditor.toDOMRange(editor, editor.selection)
domSelection?.removeAllRanges()
domSelection?.addRange(domRange)
}
+ // Create a new selection in the top of the document if missing
+ if (!editor.selection) {
+ Transforms.select(editor, Editor.start(editor, []))
+ editor.onChange()
+ }
el.focus({ preventScroll: true })
+ IS_FOCUSED.set(editor, true)
}
},
diff --git a/packages/slate-react/test/editable.spec.tsx b/packages/slate-react/test/editable.spec.tsx
new file mode 100644
index 000000000..d907cc1e5
--- /dev/null
+++ b/packages/slate-react/test/editable.spec.tsx
@@ -0,0 +1,204 @@
+import React, { useEffect } from 'react'
+import { createEditor, Text, Transforms } from 'slate'
+import { act, render } from '@testing-library/react'
+import { Slate, withReact, Editable } from '../src'
+
+describe('slate-react', () => {
+ describe('Editable', () => {
+ describe('NODE_TO_KEY logic', () => {
+ test('should not unmount the node that gets split on a split_node operation', async () => {
+ const editor = withReact(createEditor())
+ const initialValue = [{ type: 'block', children: [{ text: 'test' }] }]
+ const mounts = jest.fn()
+
+ act(() => {
+ render(
+ {}}
+ >
+ {
+ useEffect(() => mounts(), [])
+
+ return children
+ }}
+ />
+
+ )
+ })
+
+ // slate updates at next tick, so we need this to be async
+ await act(async () =>
+ Transforms.splitNodes(editor, { at: { path: [0, 0], offset: 2 } })
+ )
+
+ // 2 renders, one for the main element and one for the split element
+ expect(mounts).toHaveBeenCalledTimes(2)
+ })
+
+ test('should not unmount the node that gets merged into on a merge_node operation', async () => {
+ const editor = withReact(createEditor())
+ const initialValue = [
+ { type: 'block', children: [{ text: 'te' }] },
+ { type: 'block', children: [{ text: 'st' }] },
+ ]
+ const mounts = jest.fn()
+
+ act(() => {
+ render(
+ {}}
+ >
+ {
+ useEffect(() => mounts(), [])
+
+ return children
+ }}
+ />
+
+ )
+ })
+
+ // slate updates at next tick, so we need this to be async
+ await act(async () =>
+ Transforms.mergeNodes(editor, { at: { path: [0, 0], offset: 0 } })
+ )
+
+ // only 2 renders for the initial render
+ expect(mounts).toHaveBeenCalledTimes(2)
+ })
+ })
+ test('calls onSelectionChange when editor select change', async () => {
+ const editor = withReact(createEditor())
+ const initialValue = [
+ { type: 'block', children: [{ text: 'te' }] },
+ { type: 'block', children: [{ text: 'st' }] },
+ ]
+ const onChange = jest.fn()
+ const onValueChange = jest.fn()
+ const onSelectionChange = jest.fn()
+
+ act(() => {
+ render(
+
+
+
+ )
+ })
+
+ await act(async () =>
+ Transforms.select(editor, { path: [0, 0], offset: 2 })
+ )
+
+ expect(onSelectionChange).toHaveBeenCalled()
+ expect(onChange).toHaveBeenCalled()
+ expect(onValueChange).not.toHaveBeenCalled()
+ })
+
+ test('calls onValueChange when editor children change', async () => {
+ const editor = withReact(createEditor())
+ const initialValue = [{ type: 'block', children: [{ text: 'test' }] }]
+ const onChange = jest.fn()
+ const onValueChange = jest.fn()
+ const onSelectionChange = jest.fn()
+
+ act(() => {
+ render(
+
+
+
+ )
+ })
+
+ await act(async () => Transforms.insertText(editor, 'Hello word!'))
+
+ expect(onValueChange).toHaveBeenCalled()
+ expect(onChange).toHaveBeenCalled()
+ expect(onSelectionChange).not.toHaveBeenCalled()
+ })
+
+ test('calls onValueChange when editor setNodes', async () => {
+ const editor = withReact(createEditor())
+ const initialValue = [{ type: 'block', children: [{ text: 'test' }] }]
+ const onChange = jest.fn()
+ const onValueChange = jest.fn()
+ const onSelectionChange = jest.fn()
+
+ act(() => {
+ render(
+
+
+
+ )
+ })
+
+ await act(async () =>
+ Transforms.setNodes(
+ editor,
+ // @ts-ignore
+ { bold: true },
+ {
+ at: { path: [0, 0], offset: 2 },
+ match: Text.isText,
+ split: true,
+ }
+ )
+ )
+
+ expect(onChange).toHaveBeenCalled()
+ expect(onValueChange).toHaveBeenCalled()
+ expect(onSelectionChange).not.toHaveBeenCalled()
+ })
+
+ test('calls onValueChange when editor children change', async () => {
+ const editor = withReact(createEditor())
+ const initialValue = [{ type: 'block', children: [{ text: 'test' }] }]
+ const onChange = jest.fn()
+ const onValueChange = jest.fn()
+ const onSelectionChange = jest.fn()
+
+ act(() => {
+ render(
+
+
+
+ )
+ })
+
+ await act(async () => Transforms.insertText(editor, 'Hello word!'))
+
+ expect(onValueChange).toHaveBeenCalled()
+ expect(onChange).toHaveBeenCalled()
+ expect(onSelectionChange).not.toHaveBeenCalled()
+ })
+ })
+})
diff --git a/packages/slate-react/test/index.spec.tsx b/packages/slate-react/test/index.spec.tsx
deleted file mode 100644
index 47de4135b..000000000
--- a/packages/slate-react/test/index.spec.tsx
+++ /dev/null
@@ -1,201 +0,0 @@
-import React, { useEffect } from 'react'
-import { createEditor, Text, Transforms } from 'slate'
-import { create, act, ReactTestRenderer } from 'react-test-renderer'
-import { Slate, withReact, Editable } from '../src'
-
-const createNodeMock = () => ({
- ownerDocument: global.document,
- getRootNode: () => global.document,
-})
-
-class MockResizeObserver {
- observe() {}
-
- unobserve() {}
-
- disconnect() {}
-}
-
-describe('slate-react', () => {
- window.ResizeObserver = MockResizeObserver as any
-
- describe('Editable', () => {
- describe('NODE_TO_KEY logic', () => {
- test('should not unmount the node that gets split on a split_node operation', async () => {
- const editor = withReact(createEditor())
- const initialValue = [{ type: 'block', children: [{ text: 'test' }] }]
- const mounts = jest.fn()
-
- let el: ReactTestRenderer
-
- act(() => {
- el = create(
- {}}
- >
- {
- useEffect(() => mounts(), [])
-
- return children
- }}
- />
- ,
- { createNodeMock }
- )
- })
-
- // slate updates at next tick, so we need this to be async
- await act(async () =>
- Transforms.splitNodes(editor, { at: { path: [0, 0], offset: 2 } })
- )
-
- // 2 renders, one for the main element and one for the split element
- expect(mounts).toHaveBeenCalledTimes(2)
- })
-
- test('should not unmount the node that gets merged into on a merge_node operation', async () => {
- const editor = withReact(createEditor())
- const initialValue = [
- { type: 'block', children: [{ text: 'te' }] },
- { type: 'block', children: [{ text: 'st' }] },
- ]
- const mounts = jest.fn()
-
- let el: ReactTestRenderer
-
- act(() => {
- el = create(
- {}}
- >
- {
- useEffect(() => mounts(), [])
-
- return children
- }}
- />
- ,
- { createNodeMock }
- )
- })
-
- // slate updates at next tick, so we need this to be async
- await act(async () =>
- Transforms.mergeNodes(editor, { at: { path: [0, 0], offset: 0 } })
- )
-
- // only 2 renders for the initial render
- expect(mounts).toHaveBeenCalledTimes(2)
- })
- })
- })
-
- test('calls onSelectionChange when editor select change', async () => {
- const editor = withReact(createEditor())
- const initialValue = [
- { type: 'block', children: [{ text: 'te' }] },
- { type: 'block', children: [{ text: 'st' }] },
- ]
- const onChange = jest.fn()
- const onValueChange = jest.fn()
- const onSelectionChange = jest.fn()
-
- act(() => {
- create(
-
-
- ,
- { createNodeMock }
- )
- })
-
- await act(async () =>
- Transforms.select(editor, { path: [0, 0], offset: 2 })
- )
-
- expect(onSelectionChange).toHaveBeenCalled()
- expect(onChange).toHaveBeenCalled()
- expect(onValueChange).not.toHaveBeenCalled()
- })
-
- test('calls onValueChange when editor children change', async () => {
- const editor = withReact(createEditor())
- const initialValue = [{ type: 'block', children: [{ text: 'test' }] }]
- const onChange = jest.fn()
- const onValueChange = jest.fn()
- const onSelectionChange = jest.fn()
-
- act(() => {
- create(
-
-
- ,
- { createNodeMock }
- )
- })
-
- await act(async () => Transforms.insertText(editor, 'Hello word!'))
-
- expect(onValueChange).toHaveBeenCalled()
- expect(onChange).toHaveBeenCalled()
- expect(onSelectionChange).not.toHaveBeenCalled()
- })
-
- test('calls onValueChange when editor setNodes', async () => {
- const editor = withReact(createEditor())
- const initialValue = [{ type: 'block', children: [{ text: 'test' }] }]
- const onChange = jest.fn()
- const onValueChange = jest.fn()
- const onSelectionChange = jest.fn()
-
- act(() => {
- create(
-
-
- ,
- { createNodeMock }
- )
- })
-
- await act(async () =>
- Transforms.setNodes(
- editor,
- // @ts-ignore
- { bold: true },
- {
- at: { path: [0, 0], offset: 2 },
- match: Text.isText,
- split: true,
- }
- )
- )
-
- expect(onChange).toHaveBeenCalled()
- expect(onValueChange).toHaveBeenCalled()
- expect(onSelectionChange).not.toHaveBeenCalled()
- })
-})
diff --git a/packages/slate-react/test/react-editor.spec.tsx b/packages/slate-react/test/react-editor.spec.tsx
new file mode 100644
index 000000000..6ebd5c310
--- /dev/null
+++ b/packages/slate-react/test/react-editor.spec.tsx
@@ -0,0 +1,90 @@
+import React, { useEffect } from 'react'
+import { createEditor, Text, Transforms } from 'slate'
+import { act, render } from '@testing-library/react'
+import { Slate, withReact, Editable, ReactEditor } from '../src'
+
+describe('slate-react', () => {
+ describe('ReactEditor', () => {
+ describe('.focus', () => {
+ test('should set focus in top of document with no editor selection', async () => {
+ const editor = withReact(createEditor())
+ const initialValue = [{ type: 'block', children: [{ text: 'test' }] }]
+ const testSelection = {
+ anchor: { path: [0, 0], offset: 0 },
+ focus: { path: [0, 0], offset: 0 },
+ }
+
+ act(() => {
+ render(
+
+
+
+ )
+ })
+
+ expect(editor.selection).toBe(null)
+
+ await act(async () => {
+ ReactEditor.focus(editor)
+ })
+
+ expect(editor.selection).toEqual(testSelection)
+
+ await act(async () => {
+ const windowSelection = ReactEditor.getWindow(editor).getSelection()
+ expect(windowSelection?.focusNode?.textContent).toBe('test')
+ expect(windowSelection?.anchorNode?.textContent).toBe('test')
+ expect(windowSelection?.anchorOffset).toBe(
+ testSelection.anchor.offset
+ )
+ expect(windowSelection?.focusOffset).toBe(testSelection.focus.offset)
+ })
+ })
+
+ test('should be able to call .focus without getting toDOMNode errors', async () => {
+ const editor = withReact(createEditor())
+ const initialValue = [{ type: 'block', children: [{ text: 'test' }] }]
+ const propagatedValue = [
+ { type: 'block', children: [{ text: 'foo' }] },
+ { type: 'block', children: [{ text: 'bar' }] },
+ ]
+
+ const testSelection = {
+ anchor: { path: [1, 0], offset: 0 },
+ focus: { path: [1, 0], offset: 3 },
+ }
+
+ act(() => {
+ render(
+
+
+
+ )
+ })
+
+ await act(async () => {
+ Transforms.removeNodes(editor, { at: [0] })
+ Transforms.insertNodes(editor, propagatedValue)
+ ReactEditor.focus(editor) // Note: calling focus in the middle of these transformations.
+ Transforms.select(editor, testSelection)
+ })
+
+ expect(editor.selection).toEqual(testSelection)
+
+ await act(async () => {
+ ReactEditor.focus(editor)
+ })
+
+ await act(async () => {
+ const windowSelection = ReactEditor.getWindow(editor).getSelection()
+ expect(windowSelection?.focusNode?.textContent).toBe('bar')
+ expect(windowSelection?.anchorNode?.textContent).toBe('bar')
+ expect(windowSelection?.anchorOffset).toBe(
+ testSelection.anchor.offset
+ )
+ expect(windowSelection?.focusOffset).toBe(testSelection.focus.offset)
+ })
+ })
+ })
+ })
+})
diff --git a/yarn.lock b/yarn.lock
index 0ff5dfcc5..9b0d4c048 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -3223,6 +3223,36 @@ __metadata:
languageName: node
linkType: hard
+"@testing-library/dom@npm:^9.0.0":
+ version: 9.3.3
+ resolution: "@testing-library/dom@npm:9.3.3"
+ dependencies:
+ "@babel/code-frame": ^7.10.4
+ "@babel/runtime": ^7.12.5
+ "@types/aria-query": ^5.0.1
+ aria-query: 5.1.3
+ chalk: ^4.1.0
+ dom-accessibility-api: ^0.5.9
+ lz-string: ^1.5.0
+ pretty-format: ^27.0.2
+ checksum: 34e0a564da7beb92aa9cc44a9080221e2412b1a132eb37be3d513fe6c58027674868deb9f86195756d98d15ba969a30fe00632a4e26e25df2a5a4f6ac0686e37
+ languageName: node
+ linkType: hard
+
+"@testing-library/react@npm:^14.0.0":
+ version: 14.0.0
+ resolution: "@testing-library/react@npm:14.0.0"
+ dependencies:
+ "@babel/runtime": ^7.12.5
+ "@testing-library/dom": ^9.0.0
+ "@types/react-dom": ^18.0.0
+ peerDependencies:
+ react: ^18.0.0
+ react-dom: ^18.0.0
+ checksum: 4a54c8f56cc4a39b50803205f84f06280bb76521d6d5d4b3b36651d760c7c7752ef142d857d52aaf4fad4848ed7a8be49afc793a5dda105955d2f8bef24901ac
+ languageName: node
+ linkType: hard
+
"@tootallnate/once@npm:1":
version: 1.1.2
resolution: "@tootallnate/once@npm:1.1.2"
@@ -3254,6 +3284,13 @@ __metadata:
languageName: node
linkType: hard
+"@types/aria-query@npm:^5.0.1":
+ version: 5.0.4
+ resolution: "@types/aria-query@npm:5.0.4"
+ checksum: ad8b87e4ad64255db5f0a73bc2b4da9b146c38a3a8ab4d9306154334e0fc67ae64e76bfa298eebd1e71830591fb15987e5de7111bdb36a2221bdc379e3415fb0
+ languageName: node
+ linkType: hard
+
"@types/babel__core@npm:^7.1.14":
version: 7.1.15
resolution: "@types/babel__core@npm:7.1.15"
@@ -3470,6 +3507,15 @@ __metadata:
languageName: node
linkType: hard
+"@types/react-dom@npm:^18.0.0":
+ version: 18.2.15
+ resolution: "@types/react-dom@npm:18.2.15"
+ dependencies:
+ "@types/react": "*"
+ checksum: 8e9631600c21ff561328e38a951d1991b3b3b20f538af4c0efbd1327c883a5573a63f50e1b945c34fa51b114b30e1ca5e62317bd54f21e063d6697b4be843a03
+ languageName: node
+ linkType: hard
+
"@types/react-dom@npm:^18.2.13":
version: 18.2.13
resolution: "@types/react-dom@npm:18.2.13"
@@ -3479,15 +3525,6 @@ __metadata:
languageName: node
linkType: hard
-"@types/react-test-renderer@npm:^18.0.3":
- version: 18.0.3
- resolution: "@types/react-test-renderer@npm:18.0.3"
- dependencies:
- "@types/react": "*"
- checksum: 6834c7c998d9e699b7b9aca31ce0f550a29a63526a9ab15f62764eeade28fcce634030e5cfd223a8417e8c53234e01bfb961906b35fd9a72dd513aba549181f0
- languageName: node
- linkType: hard
-
"@types/react@npm:*, @types/react@npm:^18.2.28":
version: 18.2.28
resolution: "@types/react@npm:18.2.28"
@@ -4014,6 +4051,15 @@ __metadata:
languageName: node
linkType: hard
+"aria-query@npm:5.1.3":
+ version: 5.1.3
+ resolution: "aria-query@npm:5.1.3"
+ dependencies:
+ deep-equal: ^2.0.5
+ checksum: 929ff95f02857b650fb4cbcd2f41072eee2f46159a6605ea03bf63aa572e35ffdff43d69e815ddc462e16e07de8faba3978afc2813650b4448ee18c9895d982b
+ languageName: node
+ linkType: hard
+
"array-buffer-byte-length@npm:^1.0.0":
version: 1.0.0
resolution: "array-buffer-byte-length@npm:1.0.0"
@@ -5671,6 +5717,32 @@ __metadata:
languageName: node
linkType: hard
+"deep-equal@npm:^2.0.5":
+ version: 2.2.2
+ resolution: "deep-equal@npm:2.2.2"
+ dependencies:
+ array-buffer-byte-length: ^1.0.0
+ call-bind: ^1.0.2
+ es-get-iterator: ^1.1.3
+ get-intrinsic: ^1.2.1
+ is-arguments: ^1.1.1
+ is-array-buffer: ^3.0.2
+ is-date-object: ^1.0.5
+ is-regex: ^1.1.4
+ is-shared-array-buffer: ^1.0.2
+ isarray: ^2.0.5
+ object-is: ^1.1.5
+ object-keys: ^1.1.1
+ object.assign: ^4.1.4
+ regexp.prototype.flags: ^1.5.0
+ side-channel: ^1.0.4
+ which-boxed-primitive: ^1.0.2
+ which-collection: ^1.0.1
+ which-typed-array: ^1.1.9
+ checksum: eb61c35157b6ecb96a5359b507b083fbff8ddb4c86a78a781ee38485f77a667465e45d63ee2ebd8a00e86d94c80e499906900cd82c2debb400237e1662cd5397
+ languageName: node
+ linkType: hard
+
"deep-is@npm:^0.1.3":
version: 0.1.4
resolution: "deep-is@npm:0.1.4"
@@ -5897,6 +5969,13 @@ __metadata:
languageName: node
linkType: hard
+"dom-accessibility-api@npm:^0.5.9":
+ version: 0.5.16
+ resolution: "dom-accessibility-api@npm:0.5.16"
+ checksum: 005eb283caef57fc1adec4d5df4dd49189b628f2f575af45decb210e04d634459e3f1ee64f18b41e2dcf200c844bc1d9279d80807e686a30d69a4756151ad248
+ languageName: node
+ linkType: hard
+
"domexception@npm:^4.0.0":
version: 4.0.0
resolution: "domexception@npm:4.0.0"
@@ -6153,6 +6232,23 @@ __metadata:
languageName: node
linkType: hard
+"es-get-iterator@npm:^1.1.3":
+ version: 1.1.3
+ resolution: "es-get-iterator@npm:1.1.3"
+ dependencies:
+ call-bind: ^1.0.2
+ get-intrinsic: ^1.1.3
+ has-symbols: ^1.0.3
+ is-arguments: ^1.1.1
+ is-map: ^2.0.2
+ is-set: ^2.0.2
+ is-string: ^1.0.7
+ isarray: ^2.0.5
+ stop-iteration-iterator: ^1.0.0
+ checksum: 8fa118da42667a01a7c7529f8a8cca514feeff243feec1ce0bb73baaa3514560bd09d2b3438873cf8a5aaec5d52da248131de153b28e2638a061b6e4df13267d
+ languageName: node
+ linkType: hard
+
"es-iterator-helpers@npm:^1.0.12":
version: 1.0.15
resolution: "es-iterator-helpers@npm:1.0.15"
@@ -7065,6 +7161,13 @@ __metadata:
languageName: node
linkType: hard
+"function-bind@npm:^1.1.2":
+ version: 1.1.2
+ resolution: "function-bind@npm:1.1.2"
+ checksum: 2b0ff4ce708d99715ad14a6d1f894e2a83242e4a52ccfcefaee5e40050562e5f6dafc1adbb4ce2d4ab47279a45dc736ab91ea5042d843c3c092820dfe032efb1
+ languageName: node
+ linkType: hard
+
"function.prototype.name@npm:^1.1.5, function.prototype.name@npm:^1.1.6":
version: 1.1.6
resolution: "function.prototype.name@npm:1.1.6"
@@ -7162,6 +7265,18 @@ __metadata:
languageName: node
linkType: hard
+"get-intrinsic@npm:^1.2.2":
+ version: 1.2.2
+ resolution: "get-intrinsic@npm:1.2.2"
+ dependencies:
+ function-bind: ^1.1.2
+ has-proto: ^1.0.1
+ has-symbols: ^1.0.3
+ hasown: ^2.0.0
+ checksum: 447ff0724df26829908dc033b62732359596fcf66027bc131ab37984afb33842d9cd458fd6cecadfe7eac22fd8a54b349799ed334cf2726025c921c7250e7417
+ languageName: node
+ linkType: hard
+
"get-package-type@npm:^0.1.0":
version: 0.1.0
resolution: "get-package-type@npm:0.1.0"
@@ -7631,6 +7746,15 @@ __metadata:
languageName: node
linkType: hard
+"hasown@npm:^2.0.0":
+ version: 2.0.0
+ resolution: "hasown@npm:2.0.0"
+ dependencies:
+ function-bind: ^1.1.2
+ checksum: 6151c75ca12554565098641c98a40f4cc86b85b0fd5b6fe92360967e4605a4f9610f7757260b4e8098dd1c2ce7f4b095f2006fe72a570e3b6d2d28de0298c176
+ languageName: node
+ linkType: hard
+
"he@npm:1.2.0":
version: 1.2.0
resolution: "he@npm:1.2.0"
@@ -8016,6 +8140,17 @@ __metadata:
languageName: node
linkType: hard
+"internal-slot@npm:^1.0.4":
+ version: 1.0.6
+ resolution: "internal-slot@npm:1.0.6"
+ dependencies:
+ get-intrinsic: ^1.2.2
+ hasown: ^2.0.0
+ side-channel: ^1.0.4
+ checksum: 7872454888047553ce97a3fa1da7cc054a28ec5400a9c2e9f4dbe4fe7c1d041cb8e8301467614b80d4246d50377aad2fb58860b294ed74d6700cc346b6f89549
+ languageName: node
+ linkType: hard
+
"internal-slot@npm:^1.0.5":
version: 1.0.5
resolution: "internal-slot@npm:1.0.5"
@@ -8041,6 +8176,16 @@ __metadata:
languageName: node
linkType: hard
+"is-arguments@npm:^1.1.1":
+ version: 1.1.1
+ resolution: "is-arguments@npm:1.1.1"
+ dependencies:
+ call-bind: ^1.0.2
+ has-tostringtag: ^1.0.0
+ checksum: 7f02700ec2171b691ef3e4d0e3e6c0ba408e8434368504bb593d0d7c891c0dbfda6d19d30808b904a6cb1929bca648c061ba438c39f296c2a8ca083229c49f27
+ languageName: node
+ linkType: hard
+
"is-array-buffer@npm:^3.0.1, is-array-buffer@npm:^3.0.2":
version: 3.0.2
resolution: "is-array-buffer@npm:3.0.2"
@@ -8278,7 +8423,7 @@ __metadata:
languageName: node
linkType: hard
-"is-map@npm:^2.0.1":
+"is-map@npm:^2.0.1, is-map@npm:^2.0.2":
version: 2.0.2
resolution: "is-map@npm:2.0.2"
checksum: ace3d0ecd667bbdefdb1852de601268f67f2db725624b1958f279316e13fecb8fa7df91fd60f690d7417b4ec180712f5a7ee967008e27c65cfd475cc84337728
@@ -8399,7 +8544,7 @@ __metadata:
languageName: node
linkType: hard
-"is-set@npm:^2.0.1":
+"is-set@npm:^2.0.1, is-set@npm:^2.0.2":
version: 2.0.2
resolution: "is-set@npm:2.0.2"
checksum: b64343faf45e9387b97a6fd32be632ee7b269bd8183701f3b3f5b71a7cf00d04450ed8669d0bd08753e08b968beda96fca73a10fd0ff56a32603f64deba55a57
@@ -9892,6 +10037,15 @@ __metadata:
languageName: node
linkType: hard
+"lz-string@npm:^1.5.0":
+ version: 1.5.0
+ resolution: "lz-string@npm:1.5.0"
+ bin:
+ lz-string: bin/bin.js
+ checksum: 1ee98b4580246fd90dd54da6e346fb1caefcf05f677c686d9af237a157fdea3fd7c83a4bc58f858cd5b10a34d27afe0fdcbd0505a47e0590726a873dc8b8f65d
+ languageName: node
+ linkType: hard
+
"magic-string@npm:^0.22.5":
version: 0.22.5
resolution: "magic-string@npm:0.22.5"
@@ -11036,6 +11190,16 @@ __metadata:
languageName: node
linkType: hard
+"object-is@npm:^1.1.5":
+ version: 1.1.5
+ resolution: "object-is@npm:1.1.5"
+ dependencies:
+ call-bind: ^1.0.2
+ define-properties: ^1.1.3
+ checksum: 989b18c4cba258a6b74dc1d74a41805c1a1425bce29f6cabb50dcb1a6a651ea9104a1b07046739a49a5bb1bc49727bcb00efd5c55f932f6ea04ec8927a7901fe
+ languageName: node
+ linkType: hard
+
"object-keys@npm:^1.0.12, object-keys@npm:^1.1.1":
version: 1.1.1
resolution: "object-keys@npm:1.1.1"
@@ -11790,6 +11954,17 @@ __metadata:
languageName: node
linkType: hard
+"pretty-format@npm:^27.0.2":
+ version: 27.5.1
+ resolution: "pretty-format@npm:27.5.1"
+ dependencies:
+ ansi-regex: ^5.0.1
+ ansi-styles: ^5.0.0
+ react-is: ^17.0.1
+ checksum: cf610cffcb793885d16f184a62162f2dd0df31642d9a18edf4ca298e909a8fe80bdbf556d5c9573992c102ce8bf948691da91bf9739bee0ffb6e79c8a8a6e088
+ languageName: node
+ linkType: hard
+
"pretty-format@npm:^29.0.0, pretty-format@npm:^29.7.0":
version: 29.7.0
resolution: "pretty-format@npm:29.7.0"
@@ -12020,13 +12195,6 @@ __metadata:
languageName: node
linkType: hard
-"react-is@npm:^16.12.0 || ^17.0.0 || ^18.0.0, react-is@npm:^18.0.0, react-is@npm:^18.2.0":
- version: 18.2.0
- resolution: "react-is@npm:18.2.0"
- checksum: e72d0ba81b5922759e4aff17e0252bd29988f9642ed817f56b25a3e217e13eea8a7f2322af99a06edb779da12d5d636e9fda473d620df9a3da0df2a74141d53e
- languageName: node
- linkType: hard
-
"react-is@npm:^16.13.1, react-is@npm:^16.8.1":
version: 16.13.1
resolution: "react-is@npm:16.13.1"
@@ -12034,6 +12202,20 @@ __metadata:
languageName: node
linkType: hard
+"react-is@npm:^17.0.1":
+ version: 17.0.2
+ resolution: "react-is@npm:17.0.2"
+ checksum: 9d6d111d8990dc98bc5402c1266a808b0459b5d54830bbea24c12d908b536df7883f268a7868cfaedde3dd9d4e0d574db456f84d2e6df9c4526f99bb4b5344d8
+ languageName: node
+ linkType: hard
+
+"react-is@npm:^18.0.0":
+ version: 18.2.0
+ resolution: "react-is@npm:18.2.0"
+ checksum: e72d0ba81b5922759e4aff17e0252bd29988f9642ed817f56b25a3e217e13eea8a7f2322af99a06edb779da12d5d636e9fda473d620df9a3da0df2a74141d53e
+ languageName: node
+ linkType: hard
+
"react-router-dom@npm:^6.17.0":
version: 6.17.0
resolution: "react-router-dom@npm:6.17.0"
@@ -12058,31 +12240,6 @@ __metadata:
languageName: node
linkType: hard
-"react-shallow-renderer@npm:^16.15.0":
- version: 16.15.0
- resolution: "react-shallow-renderer@npm:16.15.0"
- dependencies:
- object-assign: ^4.1.1
- react-is: ^16.12.0 || ^17.0.0 || ^18.0.0
- peerDependencies:
- react: ^16.0.0 || ^17.0.0 || ^18.0.0
- checksum: 6052c7e3e9627485120ebd8257f128aad8f56386fe8d42374b7743eac1be457c33506d153c7886b4e32923c0c352d402ab805ef9ca02dbcd8393b2bdeb6e5af8
- languageName: node
- linkType: hard
-
-"react-test-renderer@npm:^18.2.0":
- version: 18.2.0
- resolution: "react-test-renderer@npm:18.2.0"
- dependencies:
- react-is: ^18.2.0
- react-shallow-renderer: ^16.15.0
- scheduler: ^0.23.0
- peerDependencies:
- react: ^18.2.0
- checksum: 6b6980ced93fa2b72662d5e4ab3b4896833586940047ce52ca9aca801e5432adf05fcbe28289b0af3ce6a2a7c590974e25dcc8aa43d0de658bfe8bbcd686f958
- languageName: node
- linkType: hard
-
"react-values@npm:^0.3.3":
version: 0.3.3
resolution: "react-values@npm:0.3.3"
@@ -13227,13 +13384,13 @@ __metadata:
dependencies:
"@babel/runtime": ^7.23.2
"@juggle/resize-observer": ^3.4.0
+ "@testing-library/react": ^14.0.0
"@types/is-hotkey": ^0.1.8
"@types/jest": 29.5.6
"@types/jsdom": ^21.1.4
"@types/lodash": ^4.14.200
"@types/react": ^18.2.28
"@types/react-dom": ^18.2.13
- "@types/react-test-renderer": ^18.0.3
"@types/resize-observer-browser": ^0.1.8
direction: ^1.0.4
is-hotkey: ^0.2.0
@@ -13241,7 +13398,6 @@ __metadata:
lodash: ^4.17.21
react: ^18.2.0
react-dom: ^18.2.0
- react-test-renderer: ^18.2.0
scroll-into-view-if-needed: ^3.1.0
slate: ^0.100.0
slate-hyperscript: ^0.100.0
@@ -13528,6 +13684,15 @@ __metadata:
languageName: node
linkType: hard
+"stop-iteration-iterator@npm:^1.0.0":
+ version: 1.0.0
+ resolution: "stop-iteration-iterator@npm:1.0.0"
+ dependencies:
+ internal-slot: ^1.0.4
+ checksum: d04173690b2efa40e24ab70e5e51a3ff31d56d699550cfad084104ab3381390daccb36652b25755e420245f3b0737de66c1879eaa2a8d4fc0a78f9bf892fcb42
+ languageName: node
+ linkType: hard
+
"stream-transform@npm:^2.1.3":
version: 2.1.3
resolution: "stream-transform@npm:2.1.3"