diff --git a/.changeset/curvy-seals-attack.md b/.changeset/curvy-seals-attack.md new file mode 100644 index 0000000000..aa574f471b --- /dev/null +++ b/.changeset/curvy-seals-attack.md @@ -0,0 +1,5 @@ +--- +'slate-react': patch +--- + +fix: sync built-in state on undo when editor is unfocused diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f421f8a537..549b4d2fcb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,7 +10,8 @@ permissions: jobs: ci: name: ${{ matrix.command }} - runs-on: ubuntu-latest + # Pin the version to avoid dependency installation issues + runs-on: ubuntu-22.04 strategy: matrix: command: diff --git a/docs/libraries/slate-history/history-editor.md b/docs/libraries/slate-history/history-editor.md index 425f76f4f3..304931b9c0 100644 --- a/docs/libraries/slate-history/history-editor.md +++ b/docs/libraries/slate-history/history-editor.md @@ -39,6 +39,11 @@ Undo to the previous saved state. ### Merging and Saving +#### `HistoryEditor.withMerging(editor: HistoryEditor, fn: () => void): void` + +Apply a series of changes inside a synchronous `fn`, These operations will +be merged into the previous history. + #### `HistoryEditor.withoutMerging(editor: HistoryEditor, fn: () => void): void` Apply a series of changes inside a synchronous `fn`, without merging any of diff --git a/package.json b/package.json index ba65c15db0..69b34f32a0 100644 --- a/package.json +++ b/package.json @@ -31,8 +31,8 @@ "test": "yarn run test:mocha && yarn run test:jest", "test:custom": "mocha --require ./config/babel/register.cjs ./packages/slate/test/index.js", "test:inspect": "yarn test --inspect-brk", - "test:integration": "playwright install && run-p -r serve playwright", - "test:integration-local": "run-p -r serve playwright", + "test:integration": "playwright install --with-deps && run-p -r serve playwright", + "test:integration-local": "playwright install && run-p -r serve playwright", "test:mocha": "mocha --require ./config/babel/register.cjs ./packages/{slate,slate-history,slate-hyperscript}/test/**/*.{js,ts}", "test:jest": "jest --config jest.config.js", "tsc:examples": "tsc --project ./site/tsconfig.example.json", diff --git a/packages/slate-react/src/components/editable.tsx b/packages/slate-react/src/components/editable.tsx index f1945d53ae..98ee43887a 100644 --- a/packages/slate-react/src/components/editable.tsx +++ b/packages/slate-react/src/components/editable.tsx @@ -1042,8 +1042,31 @@ export const Editable = forwardRef( op() } deferredOperations.current = [] + + // COMPAT: Since `beforeinput` doesn't fully `preventDefault`, + // there's a chance that content might be placed in the browser's undo stack. + // This means undo can be triggered even when the div is not focused, + // and it only triggers the input event for the node. (2024/10/09) + if (!ReactEditor.isFocused(editor)) { + const native = event.nativeEvent as InputEvent + const maybeHistoryEditor: any = editor + if ( + native.inputType === 'historyUndo' && + typeof maybeHistoryEditor.undo === 'function' + ) { + maybeHistoryEditor.undo() + return + } + if ( + native.inputType === 'historyRedo' && + typeof maybeHistoryEditor.redo === 'function' + ) { + maybeHistoryEditor.redo() + return + } + } }, - [attributes.onInput] + [attributes.onInput, editor] )} onBlur={useCallback( (event: React.FocusEvent) => {