reacthub-pixitweenjs 0.2.4 → 0.2.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (29) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/build-storybook.log +79 -476
  3. package/package.json +26 -29
  4. package/src/components/PixiAnimatedSprite/PixiAnimatedSprite.tsx +51 -0
  5. package/src/components/PixiAnimatedSprite/index.ts +2 -0
  6. package/src/components/PixiAudioSprite/PixiAudioSprite.stories.tsx +61 -0
  7. package/src/components/PixiAudioSprite/PixiAudioSprite.tsx +212 -0
  8. package/src/components/PixiAudioSprite/index.ts +1 -0
  9. package/src/components/PixiGifSprite/PixiGifSprite.stories.tsx +135 -0
  10. package/src/components/PixiGifSprite/PixiGifSprite.tsx +451 -0
  11. package/src/components/PixiGifSprite/index.ts +2 -0
  12. package/src/components/PixiImageSprite/PixiImageSprite.stories.tsx +11 -0
  13. package/src/components/PixiImageSprite/PixiImageSprite.tsx +30 -36
  14. package/src/components/PixiSVGSprite/PixiSvgPathSprite.stories.tsx +137 -0
  15. package/src/components/PixiSVGSprite/PixiSvgPathSprite.tsx +378 -0
  16. package/src/components/PixiSVGSprite/index.ts +1 -0
  17. package/src/components/PixiVideoSprite/PixiVideoSprite.stories.tsx +147 -0
  18. package/src/components/PixiVideoSprite/PixiVideoSprite.tsx +684 -0
  19. package/src/components/PixiVideoSprite/PixiVideoSpriteBackup.txt +755 -0
  20. package/src/components/PixiVideoSprite/index.ts +1 -0
  21. package/src/declare.module.ts +5 -0
  22. package/src/providers/GsapPixieContextProvider.tsx +94 -8
  23. package/src/reacthub-react-bindings.d.ts +27 -0
  24. package/src/utils/AppStateProvider.tsx +15 -26
  25. package/src/utils/AppStateStage.tsx +1 -1
  26. package/src/utils/PixiStage.tsx +1 -5
  27. package/src/utils/PixiTransformer.tsx +100 -0
  28. package/src/utils/VideoSeekBar.tsx +34 -23
  29. package/src/utils/useDebounce.tsx +15 -0
@@ -0,0 +1 @@
1
+ export { default as PixiVideoSprite } from "./PixiVideoSprite";
@@ -0,0 +1,5 @@
1
+ // declare module "@pixi/react" {
2
+ // interface Container {
3
+ // children?: React.ReactNode;
4
+ // }
5
+ // }
@@ -7,18 +7,23 @@ import {
7
7
  useLayoutEffect,
8
8
  } from "react";
9
9
  import gsap from "gsap";
10
- import { emitCustomEvent } from "react-custom-events";
10
+ import { emitCustomEvent, useCustomEventListener } from "react-custom-events";
11
+ import { useDebounce } from "../utils/useDebounce";
11
12
 
12
13
  interface GsapPixieContextProps {
13
14
  gsapCtx: React.MutableRefObject<any>;
14
15
  tl: React.MutableRefObject<any>;
16
+ play: boolean;
17
+ isDragging: boolean;
15
18
  handlePlay: () => void;
16
19
  handlePause: () => void;
17
20
  handleReset: () => void;
18
- handleSeek: () => void;
21
+ handleSeek: (value: number) => void;
22
+ handleSeekTest: () => void;
19
23
  handleRestart: () => void;
20
24
  handleRepeat: () => void;
21
25
  playerTimeRef: React.MutableRefObject<number>;
26
+ totalDuration: number;
22
27
  }
23
28
 
24
29
  // Context has been created
@@ -30,6 +35,12 @@ const Events = {
30
35
  PAUSE: "GSAP_PAUSE",
31
36
  PLAY: "GSAP_PLAY",
32
37
  RESUME: "GSAP_RESUME",
38
+ RESTART: "GSAP_RESTART",
39
+ REPEAT: "GSAP_REPEAT",
40
+ SEEK: "GSAP_SEEK",
41
+ RESET: "GSAP_RESET",
42
+ DRAGGING_START: "GSAP_DRAGGING_START",
43
+ DRAGGING_END: "GSAP_DRAGGING_END",
33
44
  };
34
45
 
35
46
  // Provider
@@ -38,6 +49,10 @@ const GsapPixieContextProvider: React.FC<{ children: React.ReactNode }> = ({
38
49
  }) => {
39
50
  const [play, setPlay] = useState<boolean>(false);
40
51
  const [frameNumber, setFrameNumber] = useState<number>(0);
52
+ const [isDragging, setIsDragging] = useState<boolean>(false);
53
+ const [internalDuration, setInternalDuration] = useState<number>(0);
54
+ const [totalDuration, setTotalDuration] = useState<number>(0);
55
+ const delayedDuration = useDebounce(internalDuration, 600);
41
56
 
42
57
  const tl = useRef<any>();
43
58
  const gsapCtx = useRef<any>();
@@ -60,6 +75,14 @@ const GsapPixieContextProvider: React.FC<{ children: React.ReactNode }> = ({
60
75
  return () => gsapCtx.current.revert();
61
76
  }, []);
62
77
 
78
+ gsap.ticker.add((time, deltaTime, frame) => {
79
+ // console.log("timeframe", time, deltaTime, frame);
80
+ // setFrameNumber(frame);
81
+ if (tl.current && getTimelineDuration) {
82
+ setInternalDuration(getTimelineDuration());
83
+ }
84
+ });
85
+
63
86
  const onUpdate = useCallback(() => {
64
87
  /// console.log("update event callback");
65
88
  const timeline = tl.current;
@@ -73,16 +96,51 @@ const GsapPixieContextProvider: React.FC<{ children: React.ReactNode }> = ({
73
96
  playerTimeRef.current = now;
74
97
  }, []);
75
98
 
99
+ // set the total duration based on the delayed duration value
100
+ useEffect(() => {
101
+ setTotalDuration(delayedDuration);
102
+ }, [delayedDuration]);
103
+
76
104
  useEffect(() => {
77
105
  const timeline = tl.current;
78
106
  timeline
107
+ .eventCallback("onStart", function () {
108
+ // console.log("onstart", timeline.progress());
109
+ // setPlay(true);
110
+ // onUpdate();
111
+ })
112
+ .eventCallback("onInterrupt", function () {
113
+ /// console.log("onInterrupt", timeline.progress());
114
+ setPlay(false);
115
+ onUpdate();
116
+ })
79
117
  .eventCallback("onUpdate", function () {
80
118
  /// console.log("onupdate", timeline.progress());
81
119
  onUpdate();
82
120
  })
121
+ // .eventCallback("onRepeat", function () {
122
+ // /// console.log("onrepeat", timeline.progress());
123
+ // onUpdate();
124
+ // })
125
+ // .eventCallback("onReverseComplete", function () {
126
+ // /// console.log("onReverseComplete", timeline.progress());
127
+ // onUpdate();
128
+ // })
129
+ // write a pause event
130
+ .eventCallback("onPause", function () {
131
+ console.log("onPause", timeline.progress());
132
+ setPlay(false);
133
+ onUpdate();
134
+ })
135
+ .eventCallback("onResume", function () {
136
+ console.log("onResume", timeline.progress());
137
+ setPlay(true);
138
+ onUpdate();
139
+ })
83
140
  .eventCallback("onComplete", function () {
84
- timeline.seek(0.01);
141
+ timeline.seek(0);
85
142
  timeline.pause();
143
+ setPlay(false);
86
144
  onUpdate();
87
145
  });
88
146
  }, []);
@@ -110,39 +168,63 @@ const GsapPixieContextProvider: React.FC<{ children: React.ReactNode }> = ({
110
168
  const handleRestart = useCallback(() => {
111
169
  const timeline = tl.current;
112
170
  timeline.restart();
171
+ setPlay(true);
113
172
  }, []);
114
173
 
115
174
  const handleRepeat = useCallback(() => {
116
175
  const timeline = tl.current;
117
-
118
176
  timeline.repeat(1);
119
177
  timeline.restart();
178
+ // setPlay(true);
120
179
  }, []);
121
180
 
122
- const handleSeek = useCallback(() => {
181
+ const handleSeek = useCallback((value: number) => {
123
182
  const timeline = tl.current;
124
- timeline.seek(4);
183
+ timeline.seek(value);
125
184
  }, []);
126
185
 
127
- const setDurationTimeline = useCallback(() => {
186
+ const handleSeekTest = useCallback(() => {
128
187
  const timeline = tl.current;
188
+ timeline.seek(4);
189
+ }, []);
129
190
 
191
+ const setTimelineDuration = useCallback(() => {
192
+ const timeline = tl.current;
130
193
  timeline.totalDuration(3);
131
194
  }, []);
132
195
 
133
- const handlePause = () => {
196
+ const getTimelineDuration = useCallback(() => {
134
197
  const timeline = tl.current;
198
+ if (!timeline) return 0;
199
+ return timeline.totalDuration();
200
+ }, []);
135
201
 
202
+ const handlePause = () => {
203
+ const timeline = tl.current;
136
204
  timeline.pause();
137
205
  emitCustomEvent(Events.PAUSE);
206
+ setPlay(false);
138
207
  };
139
208
 
140
209
  const handlePlay = () => {
141
210
  const timeline = tl.current;
211
+ setPlay(true);
142
212
  timeline.resume();
143
213
  emitCustomEvent(Events.RESUME);
144
214
  };
145
215
 
216
+ /** Event listener dragging */
217
+ useCustomEventListener(Events.DRAGGING_START, (time) => {
218
+ console.log("dragging start");
219
+ setIsDragging(true);
220
+ });
221
+
222
+ useCustomEventListener(Events.DRAGGING_END, (time) => {
223
+ setIsDragging(false);
224
+ console.log("dragging end");
225
+ });
226
+
227
+ console.log("set play updated", play);
146
228
  return (
147
229
  <GsapPixieContext.Provider
148
230
  value={{
@@ -152,9 +234,13 @@ const GsapPixieContextProvider: React.FC<{ children: React.ReactNode }> = ({
152
234
  handlePause,
153
235
  handleReset,
154
236
  handleSeek,
237
+ handleSeekTest,
155
238
  handleRestart,
156
239
  handleRepeat,
157
240
  playerTimeRef,
241
+ play,
242
+ totalDuration,
243
+ isDragging,
158
244
  }}
159
245
  >
160
246
  {children}
@@ -0,0 +1,27 @@
1
+ import * as React from "react";
2
+ import * as PIXI from "pixi.js";
3
+
4
+ declare module "reacthub-react-bindings" {
5
+ interface TransformerProps {
6
+ group: PIXI.DisplayObject[];
7
+ rotateEnabled?: boolean;
8
+ boxRotationEnabled?: boolean;
9
+ boxScalingEnabled?: boolean;
10
+ wireframeStyle?: {
11
+ thickness: number;
12
+ color: number;
13
+ };
14
+ lockAspectRatio?: boolean;
15
+ scaleEnabled?: boolean;
16
+ handleStyle?: {
17
+ color?: number;
18
+ outlineColor?: number;
19
+ shape?: "circle" | "square";
20
+ radius?: number;
21
+ };
22
+ transformchange?: (transform: PIXI.Matrix) => void;
23
+ transformcommit?: (transform: PIXI.Matrix) => void;
24
+ }
25
+
26
+ export class Transformer extends React.Component<TransformerProps> {}
27
+ }
@@ -8,19 +8,6 @@ interface AppState {
8
8
  };
9
9
  }
10
10
 
11
- interface AppStateContextProps extends AppState {
12
- onAnchorTransformationEnd: (data: TransformationEnd) => void;
13
- onMouseOverSprite: (data: unknown) => void;
14
- onClickSprite: (data: unknown) => void;
15
- }
16
-
17
- export const AppStateContext = React.createContext<AppStateContextProps>({
18
- transformation: {},
19
- onAnchorTransformationEnd: () => {},
20
- onMouseOverSprite: () => {},
21
- onClickSprite: () => {},
22
- });
23
-
24
11
  interface AppStateContextProviderProps extends AppState {
25
12
  children: React.ReactNode;
26
13
  }
@@ -28,27 +15,30 @@ interface AppStateContextProviderProps extends AppState {
28
15
  export const AppStateContextProvider: React.FC<
29
16
  AppStateContextProviderProps
30
17
  > = ({ children, ...props }) => {
18
+ console.log("AppStateContextProvider", props);
31
19
  const [appState, setAppState] = React.useState<AppState>(props);
20
+ const appStateRef = React.useRef<AppState>(appState);
21
+
32
22
  useDeepEffect(() => {
33
23
  setAppState(props);
24
+ appStateRef.current = props;
34
25
  }, [props]);
35
26
 
36
27
  const onAnchorTransformationEnd = React.useCallback(
37
- (data: {
38
- uniqueId: string;
39
- transformation: { [key: string]: unknown };
40
- }) => {
28
+ (data: TransformationEnd) => {
29
+ console.log("onAnchorTransformationEnd", data);
41
30
  const { uniqueId, transformation } = data;
42
31
  const newAppState = {
43
- ...props,
32
+ ...appStateRef.current,
44
33
  transformation: {
45
- ...props.transformation,
34
+ ...appStateRef.current?.transformation,
46
35
  ...transformation,
47
36
  },
48
37
  };
38
+ console.log("saving state", newAppState);
49
39
  setAppState(newAppState);
50
40
  },
51
- [props],
41
+ []
52
42
  );
53
43
 
54
44
  const onMouseOverSprite = React.useCallback((data: unknown) => {}, []);
@@ -56,15 +46,14 @@ export const AppStateContextProvider: React.FC<
56
46
  const onClickSprite = React.useCallback((data: unknown) => {}, []);
57
47
 
58
48
  return (
59
- <AppStateContext.Provider
60
- value={{
49
+ <>
50
+ {/*@ts-ignore */}
51
+ {React.cloneElement(children, {
61
52
  ...appState,
62
53
  onAnchorTransformationEnd,
63
54
  onMouseOverSprite,
64
55
  onClickSprite,
65
- }}
66
- >
67
- {children}
68
- </AppStateContext.Provider>
56
+ })}
57
+ </>
69
58
  );
70
59
  };
@@ -1,6 +1,6 @@
1
1
  import * as React from "react";
2
2
  import ContextBridge from "./ContextBridge";
3
- import { AppStateContext } from "../providers/AppStateProvider";
3
+ import { AppStateContext } from "./AppStateProvider";
4
4
  import { Container as PixiContainer } from "@pixi/react";
5
5
 
6
6
  interface AppStateStageProps {
@@ -1,7 +1,6 @@
1
1
  import * as React from "react";
2
2
  import ContextBridge from "./ContextBridge";
3
3
  import { Stage as PixiStage } from "@pixi/react";
4
- import { AppStateContextProvider } from "./AppStateProvider";
5
4
  import { GsapPixieContext } from "../providers/GsapPixieContextProvider";
6
5
 
7
6
  interface StageProps {
@@ -18,10 +17,7 @@ const Stage: React.FC<StageProps> = ({ children, ...props }) => {
18
17
  render={(children: React.ReactNode | React.ReactElement) => (
19
18
  <PixiStage {...props}>
20
19
  {/* @ts-ignore */}
21
- <AppStateContextProvider {...props}>
22
- {/* @ts-ignore */}
23
- {children}
24
- </AppStateContextProvider>
20
+ {children}
25
21
  </PixiStage>
26
22
  )}
27
23
  >
@@ -0,0 +1,100 @@
1
+ import * as PIXI from "pixi.js";
2
+ import * as React from "react";
3
+ // @ts-ignore
4
+ import { Transformer } from "reacthub-react-bindings";
5
+
6
+ type PixiTransformerProps = {
7
+ pixiTransformerRef: React.MutableRefObject<any>;
8
+ imageRef: React.MutableRefObject<any>;
9
+ isMounted: boolean;
10
+ transformCommit?: (data: any) => void;
11
+ transformChange?: (data: any) => void;
12
+ mouseoverEvent?: (flag: boolean) => void;
13
+ uniqueId?: string;
14
+ };
15
+ const PixiTransformer = ({
16
+ pixiTransformerRef,
17
+ imageRef,
18
+ isMounted,
19
+ transformCommit,
20
+ transformChange,
21
+ mouseoverEvent,
22
+ uniqueId = "",
23
+ }: PixiTransformerProps) => {
24
+ const colorYellow = PIXI.utils.string2hex("#F3C409");
25
+ const anchorFill = PIXI.utils.string2hex("#F3C409");
26
+
27
+ const handleOnMouseOver = React.useCallback(() => {
28
+ if (mouseoverEvent) {
29
+ mouseoverEvent(true);
30
+ }
31
+ }, [mouseoverEvent]);
32
+
33
+ const handleOnMouseOut = React.useCallback(() => {
34
+ if (mouseoverEvent) {
35
+ mouseoverEvent(false);
36
+ }
37
+ }, [mouseoverEvent]);
38
+
39
+ const handleOnTransformCommit = React.useCallback(() => {
40
+ if (imageRef.current === null) return;
41
+ const x = imageRef.current.x;
42
+ const y = imageRef.current.y;
43
+ const width = imageRef.current.width;
44
+ const height = imageRef.current.height;
45
+ const rotate = imageRef.current.rotation;
46
+ const scale: [number, number] = [
47
+ imageRef.current.scale.x,
48
+ imageRef.current.scale.y,
49
+ ];
50
+ if (transformCommit) {
51
+ transformCommit({
52
+ uniqueId,
53
+ transformation: {
54
+ x: Math.round(x),
55
+ y: Math.round(y),
56
+ width: Math.round(Math.max(5, width)),
57
+ height: Math.round(Math.max(5, height)),
58
+ rotate: Math.round(rotate),
59
+ scale: scale,
60
+ },
61
+ });
62
+ }
63
+ }, [transformCommit]);
64
+
65
+ React.useEffect(() => {
66
+ if (pixiTransformerRef.current) {
67
+ pixiTransformerRef.current.on("mouseover", handleOnMouseOver);
68
+ pixiTransformerRef.current.on("mouseout", handleOnMouseOut);
69
+ }
70
+ return () => {
71
+ if (pixiTransformerRef.current) {
72
+ pixiTransformerRef.current.off("mouseover", handleOnMouseOver);
73
+ pixiTransformerRef.current.off("mouseout", handleOnMouseOut);
74
+ }
75
+ };
76
+ }, []);
77
+
78
+ return (
79
+ <Transformer
80
+ ref={pixiTransformerRef}
81
+ group={isMounted ? [imageRef.current] : []}
82
+ rotateEnabled={true}
83
+ boxRotationEnabled={true}
84
+ boxScalingEnabled={true}
85
+ wireframeStyle={{ thickness: 1, color: anchorFill }}
86
+ lockAspectRatio={true}
87
+ scaleEnabled={true}
88
+ handleStyle={{
89
+ // color: colorYellow,
90
+ outlineColor: colorYellow,
91
+ shape: "circle",
92
+ radius: 9,
93
+ }}
94
+ transformchange={transformChange}
95
+ transformcommit={handleOnTransformCommit}
96
+ />
97
+ );
98
+ };
99
+
100
+ export default PixiTransformer;
@@ -11,7 +11,11 @@ import {
11
11
  Box,
12
12
  Button,
13
13
  } from "@chakra-ui/react";
14
- import { GsapPixieContext } from "../providers/GsapPixieContextProvider";
14
+ import {
15
+ GsapPixieContext,
16
+ Events,
17
+ } from "../providers/GsapPixieContextProvider";
18
+ import { useCustomEventListener, emitCustomEvent } from "react-custom-events";
15
19
 
16
20
  import { gsap } from "gsap";
17
21
  import { Draggable } from "gsap/Draggable";
@@ -30,19 +34,18 @@ export const VideoSeekBar: React.FC = () => {
30
34
  handlePause,
31
35
  handleReset,
32
36
  handleSeek,
37
+ handleSeekTest,
33
38
  handleRestart,
34
39
  handleRepeat,
40
+ totalDuration: duration,
35
41
  } = React.useContext(GsapPixieContext);
36
42
 
37
43
  /// state
38
44
  const [time, setTime] = React.useState<number>(0);
39
- const [duration, setDuration] = React.useState<number>(0);
40
-
41
45
  const totalVideoSeconds = 20;
42
46
 
43
47
  const animate = (time: number) => {
44
48
  /// console.log("totalDuration", timeline.current.totalDuration());
45
- setDuration(timeline.current.totalDuration());
46
49
  if (playerTimeRef && playerTimeRef.current) {
47
50
  setTime(playerTimeRef.current);
48
51
  }
@@ -55,31 +58,39 @@ export const VideoSeekBar: React.FC = () => {
55
58
  }, []); // Make sure the effect runs only once
56
59
 
57
60
  const handleOnSliderChange = (value: number) => {
61
+ console.log("onslider change", value);
58
62
  const nTotSeconds =
59
63
  totalVideoSeconds && totalVideoSeconds > 0 ? totalVideoSeconds : 1;
60
64
  const progress = value / nTotSeconds;
61
65
  console.log("progressbar", value, progress);
66
+
62
67
  playerTimeRef.current = value;
63
- // @ts-ignore
64
- timeline && timeline.progress(progress);
65
- gsap.set(sliderProgressRef.current!, {
66
- scaleX: progress,
67
- });
68
+ // handleSeek(value);
69
+ // // @ts-ignore
70
+ timeline && timeline.current.progress(progress);
71
+ // timeline && timeline.current.pause();
72
+ // gsap.set(sliderProgressRef.current!, {
73
+ // scaleX: progress,
74
+ // });
68
75
  };
69
- const handleOnSliderChangeStart = (value: number) => {};
70
- const handleOnSliderChangeEnd = (value: number) => {};
71
76
 
72
- /** Create Draggable for the Gsap Player */
77
+ /** on slider start
78
+ * 1. pause the timeline
79
+ * 2. trigger custom event isDraggingStart
80
+ */
81
+ const handleOnSliderChangeStart = (value: number) => {
82
+ // trigger custom event and pause the timeline
83
+ emitCustomEvent(Events.DRAGGING_START);
84
+ timeline && timeline.current.pause();
85
+ };
73
86
 
74
- const updateDrag = React.useCallback(
75
- (x: number, maxX: number) => {
76
- console.log("updatgeDrag running", x, maxX);
77
- const currentTime = (x / maxX) * totalVideoSeconds;
78
- const prog = x / sliderRef.current!.offsetWidth;
79
- console.log("drage update", currentTime, prog);
80
- },
81
- [totalVideoSeconds],
82
- );
87
+ const handleOnSliderChangeEnd = (value: number) => {
88
+ // trigger custom event and pause the timeline
89
+ emitCustomEvent(Events.DRAGGING_END);
90
+ timeline && timeline.current.pause();
91
+ };
92
+
93
+ /** Create Draggable for the Gsap Player */
83
94
 
84
95
  return (
85
96
  <Flex flexDir={"column"}>
@@ -87,7 +98,7 @@ export const VideoSeekBar: React.FC = () => {
87
98
  <Button onClick={handleRestart}>Play</Button>
88
99
  <Button onClick={handlePause}>Pause</Button>
89
100
  <Button onClick={handlePlay}>Resume</Button>
90
- <Button onClick={handleSeek}>Seek (4:00)</Button>
101
+ <Button onClick={handleSeekTest}>Seek (4:00)</Button>
91
102
  </Box>
92
103
  <Flex px={1} mt={2}>
93
104
  <Slider
@@ -95,7 +106,7 @@ export const VideoSeekBar: React.FC = () => {
95
106
  data-testid="sliderthumb"
96
107
  value={playerTimeRef.current || 0}
97
108
  min={0}
98
- max={duration}
109
+ max={10}
99
110
  step={0.1}
100
111
  onChange={handleOnSliderChange}
101
112
  onChangeStart={handleOnSliderChangeStart}
@@ -0,0 +1,15 @@
1
+ import { useEffect, useState } from "react";
2
+
3
+ export function useDebounce<T>(value: T, delay?: number): T {
4
+ const [debouncedValue, setDebouncedValue] = useState<T>(value);
5
+
6
+ useEffect(() => {
7
+ const timer = setTimeout(() => setDebouncedValue(value), delay || 500);
8
+
9
+ return () => {
10
+ clearTimeout(timer);
11
+ };
12
+ }, [value, delay]);
13
+
14
+ return debouncedValue;
15
+ }