Skip to content

Commit 8071add

Browse files
author
Jan Fischer
committed
Finalize target names, Add docz example
1 parent 90e0c92 commit 8071add

File tree

5 files changed

+95
-18
lines changed

5 files changed

+95
-18
lines changed

packages/docz/src/components/Timeline.mdx

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ menu: Components
66
import { Fragment } from 'react';
77
import { Playground, Props } from 'docz'
88
import { Controls, PlayState } from './../../../react-gsap/src/'
9-
import { Timeline, TimelinePropsDummy } from './Timeline'
9+
import { Timeline, TimelinePropsDummy, TargetWithNames } from './Timeline'
1010
import { Tween } from './Tween'
1111

1212
# Timeline
@@ -78,6 +78,39 @@ If you don't add a target you transform all target components.
7878
</Controls>
7979
</Playground>
8080

81+
## Advanced multiple targets
82+
83+
If you need to target individual elements you can use a special forwardRef function.
84+
The `targets` parameter provide the `set` function, which you can use to set a ref to a certain key.
85+
86+
If you use an array as value, as seen in the example, you can save multiple elements as array under one key and use e.g. the `stagger` prop.
87+
88+
```javascript
89+
const TargetWithNames = forwardRef((props, targets) => (
90+
<div style={{ textAlign: 'center' }}>
91+
<h3 ref={div => targets.set('div1', div)}>THIS</h3>
92+
<SplitChars
93+
ref={(div: ReactElement) => targets.set('div2', [div])}
94+
wrapper={<h3 style={{ display: 'inline-block' }} />}
95+
>
96+
TEST
97+
</SplitChars>
98+
<h3 ref={div => targets.set('div3', div)}>IS A</h3>
99+
</div>
100+
));
101+
102+
```
103+
104+
<Playground>
105+
<Controls playState={PlayState.stop}>
106+
<Timeline target={<TargetWithNames />}>
107+
<Tween from={{ x: '-100vw' }} target="div1" position="0" />
108+
<Tween from={{ x: '-100vw' }} target="div2" position="2" stagger={0.1} />
109+
<Tween from={{ x: '-100vw' }} target="div3" position="1" />
110+
</Timeline>
111+
</Controls>
112+
</Playground>
113+
81114
## Nested Timelines
82115

83116
You can nest other Timelines or HTML structures.
Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,22 @@
1-
import React from 'react';
1+
import React, { forwardRef, ReactElement } from 'react';
22
import Timeline, { TimelineProps } from './../../../react-gsap/src/Timeline';
3+
import { SplitChars } from './../../../react-gsap/src';
34

45
export const TimelinePropsDummy: React.FunctionComponent<TimelineProps> = props => (
56
<div {...props} />
67
);
7-
export { Timeline };
8+
9+
const TargetWithNames = forwardRef((props, targets: any) => (
10+
<div style={{ textAlign: 'center' }}>
11+
<h3 ref={div => targets.set('div1', div)}>THIS</h3>
12+
<SplitChars
13+
ref={(div: ReactElement) => targets.set('div2', [div])}
14+
wrapper={<h3 style={{ display: 'inline-block' }} />}
15+
>
16+
TEST
17+
</SplitChars>
18+
<h3 ref={div => targets.set('div3', div)}>IS A</h3>
19+
</div>
20+
));
21+
22+
export { Timeline, TargetWithNames };

packages/playground/src/examples/Timeline.tsx

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
1-
import React, { forwardRef, Fragment, useRef, useImperativeHandle, ReactElement } from 'react';
1+
import React, {
2+
forwardRef,
3+
Fragment,
4+
useRef,
5+
useImperativeHandle,
6+
ReactElement,
7+
ReactHTMLElement,
8+
} from 'react';
29
import styled from 'styled-components';
3-
import { Tween, Timeline, SplitWords, SplitLetters, Controls, PlayState } from 'react-gsap';
10+
import { Tween, Timeline, SplitWords, SplitChars, Controls, PlayState } from 'react-gsap';
411

512
const TimelineStyled = styled.div``;
613

@@ -87,9 +94,9 @@ const TimelineComponent = () => (
8794
wrapper={<div style={{ position: 'relative', left: '90px' }} />}
8895
target={
8996
<Fragment>
90-
<SplitLetters wrapper={<div style={{ fontSize: '80px', display: 'inline-block' }} />}>
97+
<SplitChars wrapper={<div style={{ fontSize: '80px', display: 'inline-block' }} />}>
9198
AIIIIGHHT
92-
</SplitLetters>
99+
</SplitChars>
93100
</Fragment>
94101
}
95102
labels={[
@@ -117,9 +124,12 @@ const TimelineComponent = () => (
117124
const TargetWithNames = forwardRef((props, targets: any) => (
118125
<div>
119126
<div ref={div => targets.set('div1', div)}>first</div>
120-
<div ref={div => targets.set('div2', div)} style={{ display: 'inline-block' }}>
127+
<SplitChars
128+
ref={(div: ReactElement) => targets.set('div2', [div])}
129+
wrapper={<span style={{ display: 'inline-block' }} />}
130+
>
121131
second
122-
</div>
132+
</SplitChars>
123133
<div ref={div => targets.set('div3', div)}>third</div>
124134
</div>
125135
));
@@ -128,8 +138,8 @@ const TimelineTargets = () => {
128138
return (
129139
<Timeline target={<TargetWithNames />}>
130140
<Tween to={{ x: '200px' }} target="div3" position="0" />
131-
<Tween to={{ x: '200px' }} target="div1" position="0" />
132-
<Tween to={{ x: '200px', rotation: 0 }} from={{ rotation: 180 }} target="div2" position="0" />
141+
<Tween to={{ x: '200px' }} target="div1" position="0.5" />
142+
<Tween to={{ x: '200px' }} target="div2" position="1" stagger={0.1} />
133143
</Timeline>
134144
);
135145
};

packages/react-gsap/src/Timeline.tsx

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,10 @@ type Label = {
1111
position: string | number;
1212
};
1313

14-
export type Targets = Map<string | number, ReactElement>;
14+
export type Targets = Map<string | number, ReactElement | ReactElement[]>;
15+
export type TargetsRef = {
16+
set: (key: string, target: any) => void;
17+
};
1518

1619
export type Target = ReactElement | null;
1720

@@ -37,6 +40,12 @@ class Timeline extends Provider<TimelineProps> {
3740
timeline: any;
3841
targets: Targets = new Map();
3942

43+
constructor(props: TimelineProps) {
44+
super(props);
45+
46+
this.setTarget = this.setTarget.bind(this);
47+
}
48+
4049
setPlayState(playState: PlayState) {
4150
const { playState: previousPlayState } = this.props;
4251
setPlayState(playState, previousPlayState, this.timeline);
@@ -113,12 +122,15 @@ class Timeline extends Provider<TimelineProps> {
113122
if (consumer.tween && !consumer.props.children) {
114123
const { position, target, stagger, ...vars } = consumer.props as TweenProps;
115124

125+
// get target if not nullish
126+
let targets = null;
127+
if (target !== null && typeof target !== 'undefined') {
128+
targets = this.targets.get(target);
129+
}
130+
116131
const tween = getTweenFunction(
117132
// @ts-ignore
118-
nullishCoalescing(
119-
target ? this.targets.get(target) : null,
120-
Array.from(this.targets.values())
121-
),
133+
nullishCoalescing(targets, Array.from(this.targets.values())),
122134
{
123135
stagger,
124136
...vars,
@@ -161,6 +173,13 @@ class Timeline extends Provider<TimelineProps> {
161173

162174
setTarget(key: string, target: any) {
163175
if (target !== null) {
176+
if (this.targets.has(key)) {
177+
const targets = this.targets.get(key);
178+
if (Array.isArray(targets)) {
179+
this.targets.set(key, [...targets, ...target]);
180+
return;
181+
}
182+
}
164183
this.targets.set(key, target);
165184
}
166185
}
@@ -187,7 +206,7 @@ class Timeline extends Provider<TimelineProps> {
187206

188207
// if is forwardRef clone and pass targets as ref
189208
if (isForwardRef(target)) {
190-
return <target.type ref={this.targets} />;
209+
return <target.type ref={{ set: this.setTarget }} />;
191210
}
192211

193212
// else iterate the first level of children and set targets

packages/react-gsap/src/helper.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ const refOrInnerRef = (child: any) => {
136136
return 'ref';
137137
};
138138

139-
const nullishCoalescing = (value: any, ifNullish: any) => {
139+
const nullishCoalescing = <T, R>(value: T, ifNullish: R): T | R => {
140140
if (value === null || typeof value === 'undefined') {
141141
return ifNullish;
142142
}

0 commit comments

Comments
 (0)