From 2dca619bba7c9b4bd266519167858f9d9f863f34 Mon Sep 17 00:00:00 2001 From: Victor Date: Fri, 20 Oct 2023 13:41:19 +0200 Subject: [PATCH] Implement support for children wrapped --- .../src/SplitTextWrapper/SplitTextWrapper.mdx | 33 +++++++++ .../SplitTextWrapper.stories.tsx | 74 +++++++++++++++++++ .../src/SplitTextWrapper/SplitTextWrapper.tsx | 6 +- 3 files changed, 112 insertions(+), 1 deletion(-) diff --git a/packages/react-animation/src/SplitTextWrapper/SplitTextWrapper.mdx b/packages/react-animation/src/SplitTextWrapper/SplitTextWrapper.mdx index 6463e0c..df0a7a5 100644 --- a/packages/react-animation/src/SplitTextWrapper/SplitTextWrapper.mdx +++ b/packages/react-animation/src/SplitTextWrapper/SplitTextWrapper.mdx @@ -41,6 +41,39 @@ function Component(): ReactElement { +## Rendering children wraped in a parent element + +The `SplitTextWrapper` renders to HTML inside the component to make sure that compnents from the +vDOM are not changed on render making them untargetable in the created SplitText instance. **_This +time the children being wrap in another parent element_** + +> Warning: state inside the rendered children is lost when the children change. + +```tsx +function Component(): ReactElement { + const splitTextRef = useRef(null); + + useEffect(() => { + // Do something with `splitTextRef.current` + }); + + return ( + +

+ Lorem ipsum dolor sit amet consectetur +
adipisicing elit. Tenetur perspiciatis eius ea, ratione, +
illo molestias, quia sapiente modi quo +
molestiae temporibus. +

+
+ ); +} +``` + +### Demo + + + ## Using dangerouslySetInnerHTML The children are rendered to a string, this is not necessary when the `dangerouslySetInnerHTML` diff --git a/packages/react-animation/src/SplitTextWrapper/SplitTextWrapper.stories.tsx b/packages/react-animation/src/SplitTextWrapper/SplitTextWrapper.stories.tsx index f1110d3..c65aeb4 100644 --- a/packages/react-animation/src/SplitTextWrapper/SplitTextWrapper.stories.tsx +++ b/packages/react-animation/src/SplitTextWrapper/SplitTextWrapper.stories.tsx @@ -88,6 +88,80 @@ export const Children: Story = { }, }; +export const ChildrenWrap: Story = { + render(): ReactElement { + const splitTextRef = useRef(null); + + const animation = useAnimation(() => { + if (!splitTextRef.current) { + return; + } + + return gsap.from(splitTextRef.current.lines, { + paused: true, + y: 20, + opacity: 0, + duration: 0.2, + stagger: 0.05, + }); + }, []); + + const onPlay = useCallback(() => { + animation.current?.play(0); + }, [animation]); + + return ( + <> + +

+ Lorem ipsum dolor sit amet consectetur +
adipisicing elit. Tenetur perspiciatis eius ea, ratione, +
illo molestias, quia sapiente modi quo +
molestiae temporibus. +

+
+ + + ); + }, + async play({ canvasElement }) { + const canvas = within(canvasElement); + const wrapper = canvas.getByTestId('wrapper'); + + expect(wrapper).toBeInTheDocument(); + expect(wrapper.childElementCount).toEqual(4); + + // Wait 2 ticks for styles to be initialized + await new Promise((resolve) => { + setTimeout(resolve, 0); + }); + await new Promise((resolve) => { + setTimeout(resolve, 0); + }); + + expect(wrapper.children[0]).toHaveStyle({ opacity: '0' }); + expect(wrapper.children[3]).toHaveStyle({ opacity: '0' }); + + await userEvent.click(canvas.getByText('Play')); + await new Promise((resolve) => { + setTimeout(resolve, 200 + wrapper.childElementCount * 50); + }); + + expect(wrapper.children[0]).toHaveStyle({ opacity: '1' }); + expect(wrapper.children[3]).toHaveStyle({ opacity: '1' }); + }, +}; + export const DangerouslySetInnerHtml: Story = { render(): ReactElement { const splitTextRef = useRef(null); diff --git a/packages/react-animation/src/SplitTextWrapper/SplitTextWrapper.tsx b/packages/react-animation/src/SplitTextWrapper/SplitTextWrapper.tsx index 4d5fc2a..df05abf 100644 --- a/packages/react-animation/src/SplitTextWrapper/SplitTextWrapper.tsx +++ b/packages/react-animation/src/SplitTextWrapper/SplitTextWrapper.tsx @@ -53,7 +53,11 @@ export const SplitTextWrapper: SplitTextWrapperComponent = ensuredForwardRef( return; } - ref.current = new SplitText(element, variables); + const content = + element.firstChild?.nodeType === Node.ELEMENT_NODE + ? element.querySelector((element.firstChild as HTMLElement).tagName.toLowerCase()) + : element; + ref.current = new SplitText(content, variables); }; const Component = (as ?? 'div') as unknown as ComponentType;