Skip to content

Commit

Permalink
#148 Make SplitTextWrapper polymorphic and add option to provide any …
Browse files Browse the repository at this point in the history
…children
  • Loading branch information
leroykorterink committed Oct 9, 2023
1 parent 28e11e1 commit 8b7b9d8
Show file tree
Hide file tree
Showing 8 changed files with 389 additions and 112 deletions.
45 changes: 44 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 8 additions & 2 deletions packages/react-animation/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
"fix:eslint": "npm run lint:eslint -- --fix",
"test": "npm-run-all -s test:*",
"test:jest": "NODE_NO_WARNINGS=1 NODE_OPTIONS=--experimental-vm-modules jest",
"test:storybook": "concurrently -k -s first \"npm run storybook:build --quiet && npx http-server ./.docs/react-transition-presence --port 6006 --silent\" \"wait-on tcp:6006 && npm run storybook:test\"",
"build": "npm-run-all -s clean build:*",
"build:ts": "tsc -p ./tsconfig.build.json",
"clean": "rimraf -rf ./dist",
Expand All @@ -51,16 +52,20 @@
"@storybook/addon-links": "^7.4.6",
"@storybook/blocks": "^7.4.6",
"@storybook/cli": "^7.4.6",
"@storybook/react-vite": "^7.4.6",
"@storybook/jest": "^0.2.3",
"@storybook/react": "^7.4.6",
"@storybook/react-vite": "^7.4.6",
"@storybook/testing-library": "^0.2.2",
"@storybook/types": "^7.4.6",
"@swc/cli": "^0.1.59",
"@swc/core": "^1.3.25",
"@swc/jest": "^0.2.24",
"@testing-library/react": "^13.4.0",
"@types/jest": "^29.2.4",
"@types/react": "^18.0.26",
"concurrently": "^8.2.1",
"gsap": "npm:@gsap/business@^3.12.2",
"http-server": "^14.1.1",
"jest": "^29.3.1",
"jest-environment-jsdom": "^29.3.1",
"npm-run-all": "^4.1.5",
Expand All @@ -69,7 +74,8 @@
"rimraf": "^5.0.5",
"storybook": "^7.4.6",
"ts-node": "^10.9.1",
"typescript": "^4.9.4"
"typescript": "^4.9.4",
"wait-on": "^7.0.1"
},
"peerDependencies": {
"@mediamonks/react-hooks": "^1.2.0",
Expand Down
120 changes: 79 additions & 41 deletions packages/react-animation/src/SplitTextWrapper/SplitTextWrapper.mdx
Original file line number Diff line number Diff line change
@@ -1,64 +1,102 @@
import { Meta } from '@storybook/blocks';
import { Canvas } from './../../.storybook/Canvas';
import { Example } from './SplitTextWrapper.stories';
import { Meta, Canvas, Controls } from '@storybook/blocks';
import * as stories from './SplitTextWrapper.stories';

<Meta title="components/SplitTextWrapper" />
<Meta title="components/SplitTextWrapper" of={stories} />

# SplitTextWrapper

The SplitTextWrapper creates a SplitText instance that can be retrieved using a ref. The SplitText
is available as soon as the just before the components is finished mounting. A new SplitText
instance is created when the children or variables change.

<Canvas>
<Example />
</Canvas>
<Canvas of={stories.Children} />

## Usage
## Rendering children

The SplitTextWrapper accepts 1 child, this child is rendered 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.
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.

> Warning: state inside the rendered children is lost when the children change.
```tsx
function Component(): ReactElement {
const splitTextRef = useRef<SplitText>(null);

useEffect(() => {
// Do something with `splitTextRef.current`
});

return (
<SplitTextWrapper ref={splitTextRef}>
Lorem ipsum dolor sit <i>amet consectetur</i>
<br /> adipisicing elit. <b>Tenetur perspiciatis</b> eius ea, ratione,
<br /> illo molestias, <code>quia sapiente</code> modi quo
<br /> molestiae temporibus.
</SplitTextWrapper>
);
}
```

### Demo

<Canvas of={stories.Children} />

## Using dangerouslySetInnerHTML

The children are rendered to a string, this is not necessary when the `dangerouslySetInnerHTML`
property of a component is used.

```tsx
function Example(): ReactElement {
function Component(): ReactElement {
const splitTextRef = useRef<SplitText>(null);

const animation = useAnimation(() => {
if (!splitTextRef.current) {
return;
}
useEffect(() => {
// Do something with `splitTextRef.current`
});

return (
<SplitTextWrapper
ref={splitTextRef}
dangerouslySetInnerHTML={{
__html:
'Lorem ipsum dolor sit <i>amet consectetur</i> <br /> adipisicing elit. <b>Tenetur perspiciatis</b> eius ea, ratione,<br /> illo molestias, <code>quia sapiente</code> modi quo<br /> molestiae temporibus.',
}}
/>
);
}
```

### Demo

return gsap.from(splitTextRef.current.words, {
y: 20,
x: 4,
opacity: 0,
duration: 0.2,
stagger: 0.05,
});
}, []);
<Canvas of={stories.DangerouslySetInnerHtml} />

const onReplay = useCallback(() => {
animation.current?.play(0);
}, [animation]);
## The `as` prop (polymorphic component)

The `SplitTextWrapper` wrapper renders a `div` element by default. The `as` prop can be used to
render the `SplitTextWrapper` as a different element.

```tsx
function Component(): ReactElement {
const splitTextRef1 = useRef<SplitText>(null);
const splitTextRef2 = useRef<SplitText>(null);

useEffect(() => {
// Do something with `splitTextRef1.current` or `splitTextRef2.current`
});

return (
<>
<h1>
<SplitTextWrapper ref={splitTextRef}>
<>
Lorem ipsum dolor sit <i>amet consectetur</i>
<br /> adipisicing elit. <b>Tenetur perspiciatis</b> eius ea, ratione,
<br /> illo molestias, <code>quia sapiente</code> modi quo
<br /> molestiae temporibus.
</>
</SplitTextWrapper>
</h1>

<button onClick={onReplay} type="button" style={{ cursor: 'pointer' }}>
Replay
</button>
<SplitTextWrapper ref={splitText1Ref} as="h1">
I'm an h1 element
</SplitTextWrapper>
<SplitTextWrapper ref={splitText2Ref} as="label" htmlFor="value">
I'm a code element
</SplitTextWrapper>
</>
);
}
```

### Demo

<Canvas of={stories.AsProp} />
Loading

0 comments on commit 8b7b9d8

Please sign in to comment.