reacthub-pixitweenjs 0.2.2 → 0.2.4

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 (38) hide show
  1. package/.storybook/{main.js → main.ts} +9 -1
  2. package/.storybook/{preview.jsx → preview.tsx} +3 -7
  3. package/CHANGELOG.md +28 -0
  4. package/README.md +29 -80
  5. package/build-storybook.log +491 -0
  6. package/index.html +1 -1
  7. package/package.json +54 -19
  8. package/src/App.tsx +29 -0
  9. package/src/{stories/PixiImageSprite/PixiImageSprite.stories.js → components/PixiImageSprite/PixiImageSprite.stories.tsx} +25 -8
  10. package/src/components/PixiImageSprite/PixiImageSprite.tsx +346 -0
  11. package/src/components/PixiImageSprite/index.ts +1 -0
  12. package/src/hooks/usePixiTransformer.tsx +168 -0
  13. package/src/index.ts +3 -0
  14. package/src/providers/{GsapPixieContextProvider.jsx → GsapPixieContextProvider.tsx} +27 -24
  15. package/src/providers/index.ts +1 -0
  16. package/src/stories/Introduction.mdx +0 -99
  17. package/src/types/transformation.tsx +13 -0
  18. package/src/utils/AppStateProvider.tsx +70 -0
  19. package/src/utils/AppStateStage.tsx +27 -0
  20. package/src/utils/AppWrapper.tsx +43 -0
  21. package/src/utils/ContextBridge.tsx +25 -0
  22. package/src/{providers/GsapAnim.jsx → utils/GsapAnim.tsx} +35 -4
  23. package/src/utils/PixiStage.tsx +33 -0
  24. package/src/utils/VideoSeekBar.tsx +118 -0
  25. package/src/utils/useDeepEffect.tsx +23 -0
  26. package/src/vite-env.d.ts +1 -0
  27. package/tsconfig.json +37 -0
  28. package/tsconfig.node.json +10 -0
  29. package/{vite.config.js → vite.config.ts} +4 -2
  30. package/vitest.config.ts +11 -0
  31. package/src/App.jsx +0 -35
  32. package/src/index.js +0 -3
  33. package/src/providers/ContextBridge.jsx +0 -67
  34. package/src/providers/VideoSeekBar.jsx +0 -186
  35. package/src/providers/index.js +0 -3
  36. package/src/stories/PixiImageSprite/PixiImageSprite.jsx +0 -318
  37. package/src/stories/PixiImageSprite/index.js +0 -1
  38. /package/src/{main.jsx → main.tsx} +0 -0
@@ -0,0 +1,168 @@
1
+ import { Transformer } from "@pixi-essentials/transformer";
2
+ import * as PIXI from "pixi.js";
3
+ import { useApp } from "@pixi/react";
4
+ import * as React from "react";
5
+ import { useEffect, useRef, useCallback } from "react";
6
+ import { Transformation } from "../types/transformation";
7
+ // @ts-ignore
8
+ import has from "lodash/has";
9
+
10
+ const colorYellow = PIXI.utils.string2hex("#F3C409");
11
+ const anchorFill = PIXI.utils.string2hex("#F3C409");
12
+
13
+ interface Events {
14
+ dblclick?: (e: any) => void;
15
+ }
16
+
17
+ interface Props {
18
+ uniqueId?: string;
19
+ onTransformEnd?: (data: {
20
+ uniqueId: string;
21
+ transformation: Transformation;
22
+ }) => void;
23
+ events?: Events;
24
+ mouseoverEvent?: (flag: boolean) => void;
25
+ setDragging?: (flag: boolean) => void;
26
+ }
27
+
28
+ export const usePixiTransformer = ({
29
+ uniqueId = "",
30
+ onTransformEnd,
31
+ events = {},
32
+ mouseoverEvent = (f) => f,
33
+ setDragging = (f) => f,
34
+ }: Props) => {
35
+ const [isDragging, setIsDragging] = React.useState(false);
36
+ const PixiTransformer = React.useRef<PIXI.Container>(null);
37
+ const mounted = React.useRef(false);
38
+ const app = useApp();
39
+ const transformerRef = useRef<Transformer>(null);
40
+ const parentRef = useRef<PIXI.Container>(null);
41
+
42
+ useEffect(() => {
43
+ mounted.current = true;
44
+ return () => {
45
+ mounted.current = false;
46
+ if (transformerRef.current) {
47
+ parentRef.current?.removeChild(transformerRef.current);
48
+ }
49
+ };
50
+ }, []);
51
+
52
+ const transformChange = useCallback(() => {
53
+ setIsDragging(true);
54
+ setDragging(true);
55
+ }, []);
56
+
57
+ const transformCommit = useCallback(() => {
58
+ if (PixiTransformer.current === null) return;
59
+ const x = PixiTransformer.current.x;
60
+ const y = PixiTransformer.current.y;
61
+ const width = PixiTransformer.current.width;
62
+ const height = PixiTransformer.current.height;
63
+ const rotate = PixiTransformer.current.rotation;
64
+ const scale: [number, number] = [
65
+ PixiTransformer.current.scale.x,
66
+ PixiTransformer.current.scale.y,
67
+ ];
68
+ if (onTransformEnd) {
69
+ onTransformEnd({
70
+ uniqueId,
71
+ transformation: {
72
+ x: Math.round(x),
73
+ y: Math.round(y),
74
+ width: Math.round(Math.max(5, width)),
75
+ height: Math.round(Math.max(5, height)),
76
+ rotate: Math.round(rotate),
77
+ scale: scale,
78
+ },
79
+ });
80
+ }
81
+ setIsDragging(false);
82
+ setDragging(false);
83
+ }, []);
84
+
85
+ const handleOnDblClick = useCallback((e: any) => {
86
+ if (events && has(events, "dblclick") && events.dblclick) {
87
+ events.dblclick(e);
88
+ }
89
+ }, []);
90
+
91
+ const handleOnMouseOver = useCallback(
92
+ (msevent: any) => {
93
+ if (mouseoverEvent) {
94
+ mouseoverEvent(true);
95
+ }
96
+ },
97
+ [mouseoverEvent],
98
+ );
99
+
100
+ const handleOnMouseOut = useCallback(
101
+ (msevent: any) => {
102
+ if (mouseoverEvent) {
103
+ mouseoverEvent(false);
104
+ }
105
+ },
106
+ [mouseoverEvent],
107
+ );
108
+
109
+ const handleTransformer = useCallback(
110
+ (node: PIXI.Container, parentNode: PIXI.Container) => {
111
+ const isEnabled = true;
112
+ // @ts-ignore
113
+ PixiTransformer.current = node;
114
+ const transformer = new Transformer({
115
+ rotateEnabled: isEnabled,
116
+ boxRotationEnabled: isEnabled,
117
+ boxScalingEnabled: isEnabled,
118
+ scaleEnabled: isEnabled,
119
+ group: [node],
120
+ wireframeStyle: {
121
+ thickness: 2,
122
+ color: anchorFill,
123
+ },
124
+ lockAspectRatio: true,
125
+ handleStyle: {
126
+ // color: colorYellow,
127
+ outlineColor: colorYellow,
128
+ shape: "circle",
129
+ radius: 10,
130
+ },
131
+ });
132
+
133
+ // transformer.addListener("transformchange", transformChange);
134
+ // @ts-ignore
135
+ transformer.addListener("transformcommit", transformCommit);
136
+ // transformer.addListener("dblclick", (evt) => {
137
+ // handleOnDblClick(evt);
138
+ // });
139
+ // transformer.on("mouseover", () => {
140
+ // handleOnMouseOver(true);
141
+ // });
142
+ // transformer.on("mouseout", () => {
143
+ // handleOnMouseOut(false);
144
+ // });
145
+ // @ts-ignore
146
+ transformerRef.current = transformer;
147
+ // @ts-ignore
148
+ parentRef.current = parentNode;
149
+ parentRef.current.addChild(transformerRef.current);
150
+ },
151
+ [
152
+ transformCommit,
153
+ transformChange,
154
+ handleOnMouseOver,
155
+ handleOnMouseOut,
156
+ handleOnDblClick,
157
+ ],
158
+ );
159
+
160
+ const removeTransformer = useCallback(() => {
161
+ if (transformerRef.current) {
162
+ // @ts-ignore
163
+ parentRef.current.removeChild(transformerRef.current);
164
+ }
165
+ }, []);
166
+
167
+ return { handleTransformer, removeTransformer, isDragging };
168
+ };
package/src/index.ts ADDED
@@ -0,0 +1,3 @@
1
+ export * from "./components/PixiImageSprite";
2
+ // Path: src\index.js
3
+ export * from "./providers";
@@ -1,4 +1,5 @@
1
- import React, {
1
+ import * as React from "react";
2
+ import {
2
3
  useState,
3
4
  useEffect,
4
5
  useCallback,
@@ -7,10 +8,22 @@ import React, {
7
8
  } from "react";
8
9
  import gsap from "gsap";
9
10
  import { emitCustomEvent } from "react-custom-events";
10
- // import { Power4 } from "gsap";
11
+
12
+ interface GsapPixieContextProps {
13
+ gsapCtx: React.MutableRefObject<any>;
14
+ tl: React.MutableRefObject<any>;
15
+ handlePlay: () => void;
16
+ handlePause: () => void;
17
+ handleReset: () => void;
18
+ handleSeek: () => void;
19
+ handleRestart: () => void;
20
+ handleRepeat: () => void;
21
+ playerTimeRef: React.MutableRefObject<number>;
22
+ }
11
23
 
12
24
  // Context has been created
13
- const GsapPixieContext = React.createContext({});
25
+ // @ts-ignore
26
+ const GsapPixieContext = React.createContext<GsapPixieContextProps>({});
14
27
 
15
28
  const Events = {
16
29
  STOP: "GSAP_STOP",
@@ -18,21 +31,19 @@ const Events = {
18
31
  PLAY: "GSAP_PLAY",
19
32
  RESUME: "GSAP_RESUME",
20
33
  };
21
- // Provider
22
- const GsapPixieContextProvider = ({ children }) => {
23
- const [play, setPlay] = useState(false);
24
- const [frameNumber, setFrameNumber] = useState(0);
25
34
 
26
- const tl = useRef();
27
- const gsapCtx = useRef();
28
- const playerTimeRef = useRef(0.001);
35
+ // Provider
36
+ const GsapPixieContextProvider: React.FC<{ children: React.ReactNode }> = ({
37
+ children,
38
+ }) => {
39
+ const [play, setPlay] = useState<boolean>(false);
40
+ const [frameNumber, setFrameNumber] = useState<number>(0);
29
41
 
30
- // gsap.ticker.add((time, deltaTime, frame) => {
31
- // console.log("timeframe", time, deltaTime, frame);
32
- // setFrameNumber(frame);
33
- // });
42
+ const tl = useRef<any>();
43
+ const gsapCtx = useRef<any>();
44
+ const playerTimeRef = useRef<number>(0.001);
34
45
 
35
- const parentElementRef = useRef();
46
+ const parentElementRef = useRef<any>();
36
47
  // передаем предка анимируемых элементов
37
48
  const q = gsap.utils.selector(parentElementRef);
38
49
 
@@ -62,14 +73,6 @@ const GsapPixieContextProvider = ({ children }) => {
62
73
  playerTimeRef.current = now;
63
74
  }, []);
64
75
 
65
- // const timeline = React.useCallback(
66
- // gsap.timeline({
67
- // paused: true,
68
- // defaults: { duration: 0, onUpdate: onUpdate },
69
- // }),
70
- // [],
71
- // );
72
-
73
76
  useEffect(() => {
74
77
  const timeline = tl.current;
75
78
  timeline
@@ -93,7 +96,7 @@ const GsapPixieContextProvider = ({ children }) => {
93
96
  }
94
97
  }, [play]);
95
98
 
96
- const addTotalDuration = (duration) => {
99
+ const addTotalDuration = (duration: number) => {
97
100
  const timeline = tl.current;
98
101
  timeline.totalDuration(duration);
99
102
  };
@@ -0,0 +1 @@
1
+ export * from "./GsapPixieContextProvider";
@@ -136,104 +136,5 @@ reacthub-pixitweenjs also provides a set of React components that make it easy t
136
136
 
137
137
  Overall, reacthub-pixitweenjs is a great choice for developers who want to create stunning animations and interactive graphics in their React applications. It provides a powerful set of tools and a simple API that makes it easy to create complex animations and manipulate images in a timeline sequence.
138
138
 
139
- Storybook helps you build UI components in isolation from your app's business logic, data, and context.
140
- That makes it easy to develop hard-to-reach states. Save these UI states as **stories** to revisit during development, testing, or QA.
141
-
142
139
  Browse example stories now by navigating to them in the sidebar.
143
140
  View their code in the `stories` directory to learn how they work.
144
- We recommend building UIs with a [**component-driven**](https://componentdriven.org) process starting with atomic components and ending with pages.
145
-
146
- <div className="subheading">Configure</div>
147
-
148
- <div className="link-list">
149
- <a
150
- className="link-item"
151
- href="https://storybook.js.org/docs/react/addons/addon-types"
152
- target="_blank"
153
- >
154
- <img src={Plugin} alt="plugin" />
155
- <span>
156
- <strong>Presets for popular tools</strong>
157
- Easy setup for TypeScript, SCSS and more.
158
- </span>
159
- </a>
160
- <a
161
- className="link-item"
162
- href="https://storybook.js.org/docs/react/configure/webpack"
163
- target="_blank"
164
- >
165
- <img src={StackAlt} alt="Build" />
166
- <span>
167
- <strong>Build configuration</strong>
168
- How to customize webpack and Babel
169
- </span>
170
- </a>
171
- <a
172
- className="link-item"
173
- href="https://storybook.js.org/docs/react/configure/styling-and-css"
174
- target="_blank"
175
- >
176
- <img src={Colors} alt="colors" />
177
- <span>
178
- <strong>Styling</strong>
179
- How to load and configure CSS libraries
180
- </span>
181
- </a>
182
- <a
183
- className="link-item"
184
- href="https://storybook.js.org/docs/react/get-started/setup#configure-storybook-for-your-stack"
185
- target="_blank"
186
- >
187
- <img src={Flow} alt="flow" />
188
- <span>
189
- <strong>Data</strong>
190
- Providers and mocking for data libraries
191
- </span>
192
- </a>
193
- </div>
194
-
195
- <div className="subheading">Learn</div>
196
-
197
- <div className="link-list">
198
- <a className="link-item" href="https://storybook.js.org/docs" target="_blank">
199
- <img src={Repo} alt="repo" />
200
- <span>
201
- <strong>Storybook documentation</strong>
202
- Configure, customize, and extend
203
- </span>
204
- </a>
205
- <a
206
- className="link-item"
207
- href="https://storybook.js.org/tutorials/"
208
- target="_blank"
209
- >
210
- <img src={Direction} alt="direction" />
211
- <span>
212
- <strong>In-depth guides</strong>
213
- Best practices from leading teams
214
- </span>
215
- </a>
216
- <a
217
- className="link-item"
218
- href="https://github.com/storybookjs/storybook"
219
- target="_blank"
220
- >
221
- <img src={Code} alt="code" />
222
- <span>
223
- <strong>GitHub project</strong>
224
- View the source and add issues
225
- </span>
226
- </a>
227
- <a className="link-item" href="https://discord.gg/storybook" target="_blank">
228
- <img src={Comments} alt="comments" />
229
- <span>
230
- <strong>Discord chat</strong>
231
- Chat with maintainers and the community
232
- </span>
233
- </a>
234
- </div>
235
-
236
- <div className="tip-wrapper">
237
- <span className="tip">Tip</span>Edit the Markdown in{" "}
238
- <code>stories/Introduction.stories.mdx</code>
239
- </div>
@@ -0,0 +1,13 @@
1
+ export interface Transformation {
2
+ x: number;
3
+ y: number;
4
+ width: number;
5
+ height: number;
6
+ rotate: number;
7
+ scale: [number, number];
8
+ }
9
+
10
+ export interface TransformationEnd {
11
+ uniqueId: string;
12
+ transformation: Transformation;
13
+ }
@@ -0,0 +1,70 @@
1
+ import * as React from "react";
2
+ import useDeepEffect from "./useDeepEffect";
3
+ import { TransformationEnd } from "../types/transformation";
4
+
5
+ interface AppState {
6
+ transformation: {
7
+ [key: string]: unknown;
8
+ };
9
+ }
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
+ interface AppStateContextProviderProps extends AppState {
25
+ children: React.ReactNode;
26
+ }
27
+
28
+ export const AppStateContextProvider: React.FC<
29
+ AppStateContextProviderProps
30
+ > = ({ children, ...props }) => {
31
+ const [appState, setAppState] = React.useState<AppState>(props);
32
+ useDeepEffect(() => {
33
+ setAppState(props);
34
+ }, [props]);
35
+
36
+ const onAnchorTransformationEnd = React.useCallback(
37
+ (data: {
38
+ uniqueId: string;
39
+ transformation: { [key: string]: unknown };
40
+ }) => {
41
+ const { uniqueId, transformation } = data;
42
+ const newAppState = {
43
+ ...props,
44
+ transformation: {
45
+ ...props.transformation,
46
+ ...transformation,
47
+ },
48
+ };
49
+ setAppState(newAppState);
50
+ },
51
+ [props],
52
+ );
53
+
54
+ const onMouseOverSprite = React.useCallback((data: unknown) => {}, []);
55
+
56
+ const onClickSprite = React.useCallback((data: unknown) => {}, []);
57
+
58
+ return (
59
+ <AppStateContext.Provider
60
+ value={{
61
+ ...appState,
62
+ onAnchorTransformationEnd,
63
+ onMouseOverSprite,
64
+ onClickSprite,
65
+ }}
66
+ >
67
+ {children}
68
+ </AppStateContext.Provider>
69
+ );
70
+ };
@@ -0,0 +1,27 @@
1
+ import * as React from "react";
2
+ import ContextBridge from "./ContextBridge";
3
+ import { AppStateContext } from "../providers/AppStateProvider";
4
+ import { Container as PixiContainer } from "@pixi/react";
5
+
6
+ interface AppStateStageProps {
7
+ children: React.ReactNode;
8
+ }
9
+
10
+ const AppStateStage: React.FC<AppStateStageProps> = ({
11
+ children,
12
+ ...props
13
+ }) => {
14
+ return (
15
+ <ContextBridge
16
+ Context={AppStateContext}
17
+ render={(children: React.ReactNode) => (
18
+ // @ts-ignore
19
+ <PixiContainer {...props}>{children}</PixiContainer>
20
+ )}
21
+ >
22
+ {children}
23
+ </ContextBridge>
24
+ );
25
+ };
26
+
27
+ export default AppStateStage;
@@ -0,0 +1,43 @@
1
+ import * as React from "react";
2
+ import { Flex, Box } from "@chakra-ui/react";
3
+ import * as PIXI from "pixi.js";
4
+ import { ChakraProvider } from "@chakra-ui/react";
5
+ import { GsapPixieContextProvider } from "../providers/GsapPixieContextProvider";
6
+ import { VideoSeekBar } from "./VideoSeekBar";
7
+ import Stage from "./PixiStage";
8
+
9
+ interface AppProps {
10
+ children: React.ReactNode;
11
+ backgroundColor?: string;
12
+ }
13
+
14
+ export const AppWrapper: React.FC<AppProps> = ({
15
+ children,
16
+ backgroundColor,
17
+ }) => {
18
+ const backgroundColorx = PIXI.utils.string2hex(backgroundColor || "#2D2E3C");
19
+ const width = 600;
20
+ const height = 500;
21
+ /// color: 0x1099bb,
22
+ return (
23
+ <div className="App">
24
+ <GsapPixieContextProvider>
25
+ <ChakraProvider>
26
+ <Flex flexDir={"column"}>
27
+ <Stage
28
+ width={width}
29
+ height={height}
30
+ // options={{ background: backgroundColor }}
31
+ options={{ backgroundColor: backgroundColorx, resolution: 2 }}
32
+ >
33
+ {children}
34
+ </Stage>
35
+ <Box mt={5} w={600}>
36
+ <VideoSeekBar />
37
+ </Box>
38
+ </Flex>
39
+ </ChakraProvider>
40
+ </GsapPixieContextProvider>
41
+ </div>
42
+ );
43
+ };
@@ -0,0 +1,25 @@
1
+ // your Stage:
2
+ // the context bridge:
3
+ import * as React from "react";
4
+
5
+ const ContextBridge = <T,>({
6
+ children,
7
+ Context,
8
+ render,
9
+ }: {
10
+ children: React.ReactNode;
11
+ Context: React.Context<T>;
12
+ render: (children: React.ReactNode) => JSX.Element;
13
+ }) => {
14
+ return (
15
+ <Context.Consumer>
16
+ {(value) => {
17
+ return render(
18
+ <Context.Provider value={value}>{children}</Context.Provider>,
19
+ );
20
+ }}
21
+ </Context.Consumer>
22
+ );
23
+ };
24
+
25
+ export default ContextBridge;
@@ -1,8 +1,39 @@
1
- /// import { Elastic } from "gsap";
2
- // import BezierEasing from 'bezier-easing';
1
+ interface Ease {
2
+ from?: {
3
+ duration: number;
4
+ ease: string;
5
+ y?: number;
6
+ x?: number;
7
+ };
8
+ fromTo?: {
9
+ from: {
10
+ y?: number;
11
+ x?: number;
12
+ alpha?: number;
13
+ };
14
+ to: {
15
+ ease: string;
16
+ y?: number;
17
+ x?: number;
18
+ alpha?: number;
19
+ duration: number;
20
+ };
21
+ };
22
+ to?: {
23
+ ease: string;
24
+ alpha: number;
25
+ duration: number;
26
+ };
27
+ }
3
28
 
4
- export const getAnimByName = (animate, stageWidth, stageHeight, x, y) => {
5
- let ease = {};
29
+ export const getAnimByName = (
30
+ animate: string,
31
+ stageWidth?: number,
32
+ stageHeight?: number,
33
+ x?: number,
34
+ y?: number,
35
+ ): Ease => {
36
+ let ease: Ease = {};
6
37
  switch (animate) {
7
38
  case "NONE":
8
39
  case "none":
@@ -0,0 +1,33 @@
1
+ import * as React from "react";
2
+ import ContextBridge from "./ContextBridge";
3
+ import { Stage as PixiStage } from "@pixi/react";
4
+ import { AppStateContextProvider } from "./AppStateProvider";
5
+ import { GsapPixieContext } from "../providers/GsapPixieContextProvider";
6
+
7
+ interface StageProps {
8
+ children: React.ReactNode;
9
+ width: number;
10
+ height: number;
11
+ options: any;
12
+ }
13
+
14
+ const Stage: React.FC<StageProps> = ({ children, ...props }) => {
15
+ return (
16
+ <ContextBridge
17
+ Context={GsapPixieContext}
18
+ render={(children: React.ReactNode | React.ReactElement) => (
19
+ <PixiStage {...props}>
20
+ {/* @ts-ignore */}
21
+ <AppStateContextProvider {...props}>
22
+ {/* @ts-ignore */}
23
+ {children}
24
+ </AppStateContextProvider>
25
+ </PixiStage>
26
+ )}
27
+ >
28
+ {children}
29
+ </ContextBridge>
30
+ );
31
+ };
32
+
33
+ export default Stage;