docs/solutions/logic-errors/2026-03-24-withscrolling-must-map-temporary-options-to-domplugin-keys-and-always-restore-state.md
Direct coverage on withScrolling(...) exposed two quiet failures in the temporary DOM scrolling helper.
The helper accepted { mode, operations, scrollOptions }, but it spread those fields directly into the DOM plugin option store. The real store keys are scrollMode, scrollOperations, and scrollOptions, so the temporary overrides never actually drove the scrolling logic.
It also reset state only after the callback returned normally. If the callback threw, the editor could keep AUTO_SCROLL enabled and retain the temporary DOMPlugin options.
The helper treated its input shape like the DOMPlugin store shape.
That assumption was wrong. mode and operations are convenience names on the helper API, not persisted option keys.
The reset path also relied on straight-line control flow instead of a try/finally.
Map the helper options onto the real DOMPlugin keys before writing them:
mode -> scrollModeoperations -> scrollOperationsscrollOptions -> scrollOptionsThen wrap the callback in try/finally so both AUTO_SCROLL and the previous DOMPlugin options are restored even when the callback throws.
The fix also keeps the nested option objects merged instead of replacing the whole store branch with partial data.
These checks passed:
bun test packages/core/src/lib/plugins/dom/withScrolling.spec.ts
bun test packages/code-block/src/lib/deserializer/htmlDeserializerCodeBlock.spec.ts packages/core/src/lib/plugins/html/HtmlPlugin.spec.ts packages/core/src/lib/plugins/ParserPlugin.spec.ts packages/core/src/lib/plugins/AstPlugin.spec.ts packages/core/src/lib/plugins/dom/withScrolling.spec.ts packages/core/src/lib/plugins/html/utils/htmlElementToLeaf.spec.ts packages/core/src/static/deserialize/htmlStringToEditorDOM.spec.ts packages/core/src/static/pluginRenderTextStatic.spec.tsx packages/core/src/static/pluginRenderLeafStatic.spec.tsx packages/core/src/static/pluginRenderElementStatic.spec.tsx packages/core/src/static/utils/getSelectedDomFragment.spec.tsx packages/core/src/static/utils/pipeDecorate.spec.ts packages/core/src/static/plugins/ViewPlugin.spec.ts packages/excalidraw/src/lib/BaseExcalidrawPlugin.spec.ts packages/dnd/src/transforms/onDropNode.spec.ts packages/link/src/lib/transforms/upsertLink.spec.tsx packages/markdown/src/lib/serializer/convertNodesSerialize.spec.ts
pnpm turbo build --filter=./packages/core --filter=./packages/code-block --filter=./packages/excalidraw --filter=./packages/dnd --filter=./packages/link --filter=./packages/markdown
pnpm turbo typecheck --concurrency=1 --filter=./packages/core --filter=./packages/code-block --filter=./packages/excalidraw --filter=./packages/dnd --filter=./packages/link --filter=./packages/markdown
pnpm lint:fix
For helper APIs that temporarily override plugin options, test both of these explicitly:
Otherwise the helper can look correct in types and still be functionally dead.