From 2a8d86f1a40bcc806422e6fe3658ddd810ce73a5 Mon Sep 17 00:00:00 2001 From: jasonphillips Date: Thu, 24 Mar 2022 19:31:35 -0500 Subject: [PATCH] Fix child element decorations (#4910) * fix slate-react handling of nested element decorations * chore: add changeset * changes from review --- .changeset/poor-hats-design.md | 5 ++ .../slate-react/src/hooks/use-children.tsx | 8 +- packages/slate-react/test/index.spec.tsx | 75 +++++++++++++++++++ 3 files changed, 85 insertions(+), 3 deletions(-) create mode 100644 .changeset/poor-hats-design.md diff --git a/.changeset/poor-hats-design.md b/.changeset/poor-hats-design.md new file mode 100644 index 000000000..0a236bd2f --- /dev/null +++ b/.changeset/poor-hats-design.md @@ -0,0 +1,5 @@ +--- +'slate-react': patch +--- + +Fix decorations applied across nested elements diff --git a/packages/slate-react/src/hooks/use-children.tsx b/packages/slate-react/src/hooks/use-children.tsx index 948c631c4..b7ef71230 100644 --- a/packages/slate-react/src/hooks/use-children.tsx +++ b/packages/slate-react/src/hooks/use-children.tsx @@ -5,7 +5,6 @@ import ElementComponent from '../components/element' import TextComponent from '../components/text' import { ReactEditor } from '..' import { useSlateStatic } from './use-slate-static' -import { useDecorate } from './use-decorate' import { NODE_TO_INDEX, NODE_TO_PARENT } from '../utils/weak-maps' import { RenderElementProps, @@ -34,7 +33,6 @@ const useChildren = (props: { renderLeaf, selection, } = props - const decorate = useDecorate() const editor = useSlateStatic() const path = ReactEditor.findPath(editor, node) const children = [] @@ -50,7 +48,11 @@ const useChildren = (props: { const range = Editor.range(editor, p) const sel = selection && Range.intersection(range, selection) - const ds = decorations.filter(dec => Range.intersection(dec, range)) + const ds = decorations.reduce((acc, dec) => { + const intersection = Range.intersection(dec, range) + if (intersection) acc.push(intersection) + return acc + }, []) if (Element.isElement(n)) { children.push( diff --git a/packages/slate-react/test/index.spec.tsx b/packages/slate-react/test/index.spec.tsx index 5b3c02050..2ade14361 100644 --- a/packages/slate-react/test/index.spec.tsx +++ b/packages/slate-react/test/index.spec.tsx @@ -6,7 +6,9 @@ import { withReact, DefaultEditable, RenderElementProps, + RenderLeafProps, DefaultElement, + DefaultLeaf, } from '../src' describe('slate-react', () => { @@ -96,6 +98,79 @@ describe('slate-react', () => { expect(renderElement).toHaveBeenCalledTimes(3) }) + + it('should pass the intersecting part of decorations to nested elements', () => { + const editor = withReact(createEditor()) + + const value = [ + { + type: 'parent', + children: [ + { type: 'block', children: [{ text: 'foo', highlight: false }] }, + { type: 'block', children: [{ text: 'bar', highlight: false }] }, + { type: 'block', children: [{ text: 'baz', highlight: false }] }, + ], + }, + ] + + const decorate = jest.fn(([node]) => { + if (node !== value[0]) { + return [] + } + return [ + { + anchor: { path: [0, 1, 0], offset: 1 }, + focus: { path: [0, 2, 0], offset: 2 }, + highlight: true, + }, + ] + }) + + const renderLeaf = jest.fn(DefaultLeaf) + const onChange = jest.fn() + let el: ReactTestRenderer + + act(() => { + el = create( + + + , + { createNodeMock } + ) + }) + + // 4 renders, for foo,b,ar,ba,z + expect(renderLeaf).toHaveBeenCalledTimes(5) + expect(renderLeaf.mock.calls).toEqual( + expect.arrayContaining([ + [ + expect.objectContaining({ + leaf: { highlight: false, text: 'foo' }, + }), + ], + [ + expect.objectContaining({ + leaf: { highlight: false, text: 'b' }, + }), + ], + [ + expect.objectContaining({ + leaf: { highlight: true, text: 'ar' }, + }), + ], + [ + expect.objectContaining({ + leaf: { highlight: true, text: 'ba' }, + }), + ], + [ + expect.objectContaining({ + leaf: { highlight: false, text: 'z' }, + }), + ], + ]) + ) + }) }) }) })