├── .gitignore
├── .npmignore
├── README.md
├── example
├── .gitignore
├── README.md
├── package-lock.json
├── package.json
├── public
│ ├── favicon.ico
│ ├── index.html
│ ├── logo192.png
│ ├── logo512.png
│ ├── manifest.json
│ └── robots.txt
└── src
│ ├── App.css
│ ├── App.js
│ ├── index.css
│ └── index.js
├── lib
└── index.js
├── package-lock.json
├── package.json
├── rollup.config.js
├── src
├── hooks
│ ├── index.js
│ ├── useCapsuleCollider.js
│ ├── useCharacterState.js
│ ├── useInputEventManager.js
│ ├── useInputMovementRotation.js
│ ├── useKeyboardMouseMovement.js
│ ├── useRay.js
│ ├── useThirdPersonAnimations.js
│ └── useThirdPersonCameraControls.js
└── index.js
└── yarn.lock
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | example/
2 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # react-three-third-person
2 |
3 | Third person controls for driving a character model inside a `@react-three/fiber` app driven by `@react-three/cannon` physics.
4 |
5 | ## Dependencies
6 |
7 | - `react` v16.14.0 or higher
8 | - `@react-three/fiber` v7.0.26 or higher
9 | - `@react-three/drei` v8.7.3 or higher
10 | - `@react-three/cannon` v6.3.0 or higher
11 |
12 | ## Installation
13 |
14 | ```bash
15 | npm install react-three-third-person
16 | ```
17 |
18 | ## Usage
19 |
20 | ```js
21 | import ThirdPersonCharacterControls from "react-three-third-person";
22 | import { useGLTF } from "@react-three/drei";
23 |
24 | const PATH = "https://yourhost.com/animations";
25 |
26 | const animationPaths = {
27 | idle: `${PATH}/idle.glb`,
28 | walk: `${PATH}/walk.glb`,
29 | run: `${PATH}/run.glb`,
30 | jump: `${PATH}/jump.glb`,
31 | landing: `${PATH}/landing.glb`,
32 | inAir: `${PATH}/falling_idle.glb`,
33 | backpedal: `${PATH}/backpedal.glb`,
34 | turnLeft: `${PATH}/turn_left.glb`,
35 | turnRight: `${PATH}/turn_right.glb`,
36 | strafeLeft: `${PATH}/strafe_left.glb`,
37 | strafeRight: `${PATH}/strafe_right.glb`,
38 | };
39 |
40 | function ThirdPersonCharacter() {
41 | const characterObj = useGLTF(`${PATH}/your_model.glb`);
42 | const characterProps = {
43 | scale: 1.75,
44 | velocity: 8,
45 | radius: 0.5,
46 | };
47 |
48 | return (
49 |
60 | );
61 | }
62 | ```
63 |
64 | ## Configuration
65 |
66 | | Prop | Type | Default | Description |
67 | | -------------- | -------------- | --------- | ------------------------------------------------- |
68 | | cameraOptions | object | {} | configuration object for control's camera options |
69 | | characterProps | object | {} | configuration object for character |
70 | | characterObj | THREE.Object3D | undefined | three.js object for character model |
71 | | animationPaths | object | {} | object for animation clip configuration |
72 | | onLoad | function | () => {} | called when animation clips are done loading |
73 |
74 | #### cameraOptions
75 |
76 | | Prop | Type | Default | Description |
77 | | ------------------- | ------- | ------- | -------------------------------------------------------------------- |
78 | | yOffset | float | 1.6 | amount of y added to the camera following the character model |
79 | | minDistance | float | 0.6 | maximum zoom in capability of camera |
80 | | maxDistance | float | 7 | maximum zoom out capability of camera |
81 | | collisionFilterMask | integer | 2 | the cannon.js group given to "world" objects for collision detection |
82 | | cameraCollisionOn | boolean | off | if turned on, will use colllisionFilterMask to add collision to the camera (experimental and unoptimized) |
83 |
84 | #### characterProps
85 |
86 | | Prop | Type | Default | Description |
87 | | ------------------- | ------- | ------- | -------------------------------------------------------------------- |
88 | | scale | float | 1 | amount to scale the character model |
89 | | radius | float | 0.3 | value used for creating character capsule collider |
90 | | velocity | float | 4 | speed at which character moves |
91 |
92 | #### characterObj
93 |
94 | you can use any model here compatible with the [mixamo](https://www.mixamo.com) rig. For best results, use a model sized to the default mixamo character.
95 |
96 | #### animationPaths
97 |
98 | this prop expects an object with key/value pairs pointing to a complete set of animations to use on your character model. Refer to the object below for the full list of animations needed, all of which are available as free animations on [mixamo](https://www.mixamo.com).
99 |
100 | ```
101 | {
102 | idle: 'idle.glb',
103 | walk: 'walk.glb',
104 | run: 'run.glb',
105 | jump: 'jump.glb',
106 | landing: 'landing.glb',
107 | inAir: 'falling_idle.glb',
108 | backpedal: 'backpedal.glb',
109 | turnLeft: 'turn_left.glb',
110 | turnRight: 'turn_right.glb',
111 | strafeLeft: 'strafe_left.glb',
112 | strafeRight: 'strafe_right.glb',
113 | }
114 | ```
115 |
116 | ## Example App Usage
117 |
118 | ```js
119 | import React from "react";
120 | import ReactDOM from "react-dom/client";
121 | import { Canvas, useThree } from "@react-three/fiber";
122 | import { Physics, useBox } from "@react-three/cannon";
123 | import manny from "manny";
124 | import ThirdPersonCharacterControls from "react-three-third-person";
125 |
126 | const BASE_ANIMATIONS_PATH =
127 | "https://mannys-game.s3.amazonaws.com/third-person/animations";
128 |
129 | const animationPaths = {
130 | idle: `${BASE_ANIMATIONS_PATH}/idle.glb`,
131 | walk: `${BASE_ANIMATIONS_PATH}/walk.glb`,
132 | run: `${BASE_ANIMATIONS_PATH}/run.glb`,
133 | jump: `${BASE_ANIMATIONS_PATH}/jump.glb`,
134 | landing: `${BASE_ANIMATIONS_PATH}/landing.glb`,
135 | inAir: `${BASE_ANIMATIONS_PATH}/falling_idle.glb`,
136 | backpedal: `${BASE_ANIMATIONS_PATH}/backpedal.glb`,
137 | turnLeft: `${BASE_ANIMATIONS_PATH}/turn_left.glb`,
138 | turnRight: `${BASE_ANIMATIONS_PATH}/turn_right.glb`,
139 | strafeLeft: `${BASE_ANIMATIONS_PATH}/strafe_left.glb`,
140 | strafeRight: `${BASE_ANIMATIONS_PATH}/strafe_right.glb`,
141 | };
142 |
143 | function ThirdPersonCharacter() {
144 | const mannyObj = manny();
145 |
146 | return (
147 |
157 | );
158 | }
159 |
160 | function Lighting() {
161 | return (
162 | <>
163 |
168 |
174 | >
175 | );
176 | }
177 |
178 | function Floor() {
179 | const [ref] = useBox(() => ({
180 | type: "Static",
181 | args: [25, 0.2, 25],
182 | mass: 0,
183 | material: {
184 | friction: 0,
185 | name: "floor",
186 | },
187 | collisionFilterGroup: 2,
188 | }));
189 | return (
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 | );
198 | }
199 |
200 | function Wall({ args, ...props }) {
201 | const [ref] = useBox(() => ({
202 | type: "Static",
203 | args,
204 | mass: 0,
205 | material: {
206 | friction: 0.3,
207 | name: "wall",
208 | },
209 | collisionFilterGroup: 2,
210 | ...props,
211 | }));
212 | return (
213 |
214 |
215 |
216 |
217 | );
218 | }
219 |
220 | function App() {
221 | return (
222 |
223 |
250 |
251 | );
252 | }
253 |
254 | const root = ReactDOM.createRoot(document.getElementById("root"));
255 | root.render(
256 |
257 |
258 |
259 | );
260 | ```
261 |
262 | ## Running Locally
263 |
264 | ```bash
265 | npm run dev
266 | ```
267 |
268 | Go to `localhost:3000` to see the local test application.
269 |
--------------------------------------------------------------------------------
/example/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # production
12 | /build
13 |
14 | # misc
15 | .DS_Store
16 | .env.local
17 | .env.development.local
18 | .env.test.local
19 | .env.production.local
20 |
21 | npm-debug.log*
22 | yarn-debug.log*
23 | yarn-error.log*
24 |
--------------------------------------------------------------------------------
/example/README.md:
--------------------------------------------------------------------------------
1 | # Getting Started with Create React App
2 |
3 | This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).
4 |
5 | ## Available Scripts
6 |
7 | In the project directory, you can run:
8 |
9 | ### `npm start`
10 |
11 | Runs the app in the development mode.\
12 | Open [http://localhost:3000](http://localhost:3000) to view it in your browser.
13 |
14 | The page will reload when you make changes.\
15 | You may also see any lint errors in the console.
16 |
17 | ### `npm test`
18 |
19 | Launches the test runner in the interactive watch mode.\
20 | See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information.
21 |
22 | ### `npm run build`
23 |
24 | Builds the app for production to the `build` folder.\
25 | It correctly bundles React in production mode and optimizes the build for the best performance.
26 |
27 | The build is minified and the filenames include the hashes.\
28 | Your app is ready to be deployed!
29 |
30 | See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information.
31 |
32 | ### `npm run eject`
33 |
34 | **Note: this is a one-way operation. Once you `eject`, you can't go back!**
35 |
36 | If you aren't satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project.
37 |
38 | Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you're on your own.
39 |
40 | You don't have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn't feel obligated to use this feature. However we understand that this tool wouldn't be useful if you couldn't customize it when you are ready for it.
41 |
42 | ## Learn More
43 |
44 | You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started).
45 |
46 | To learn React, check out the [React documentation](https://reactjs.org/).
47 |
48 | ### Code Splitting
49 |
50 | This section has moved here: [https://facebook.github.io/create-react-app/docs/code-splitting](https://facebook.github.io/create-react-app/docs/code-splitting)
51 |
52 | ### Analyzing the Bundle Size
53 |
54 | This section has moved here: [https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size](https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size)
55 |
56 | ### Making a Progressive Web App
57 |
58 | This section has moved here: [https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app](https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app)
59 |
60 | ### Advanced Configuration
61 |
62 | This section has moved here: [https://facebook.github.io/create-react-app/docs/advanced-configuration](https://facebook.github.io/create-react-app/docs/advanced-configuration)
63 |
64 | ### Deployment
65 |
66 | This section has moved here: [https://facebook.github.io/create-react-app/docs/deployment](https://facebook.github.io/create-react-app/docs/deployment)
67 |
68 | ### `npm run build` fails to minify
69 |
70 | This section has moved here: [https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify](https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify)
71 |
--------------------------------------------------------------------------------
/example/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "example",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "@react-three/cannon": "^6.3.0",
7 | "@react-three/drei": "^8.7.3",
8 | "@react-three/fiber": "^7.0.26",
9 | "manny": "^3.0.0",
10 | "react-three-third-person": "file:../",
11 | "react": "^18.2.0",
12 | "react-dom": "^18.2.0",
13 | "react-scripts": "5.0.1",
14 | "three": "^0.137.4",
15 | "web-vitals": "^2.1.4"
16 | },
17 | "scripts": {
18 | "start": "react-scripts start",
19 | "build": "react-scripts build",
20 | "eject": "react-scripts eject"
21 | },
22 | "eslintConfig": {
23 | "extends": [
24 | "react-app",
25 | "react-app/jest"
26 | ]
27 | },
28 | "browserslist": {
29 | "production": [
30 | ">0.2%",
31 | "not dead",
32 | "not op_mini all"
33 | ],
34 | "development": [
35 | "last 1 chrome version",
36 | "last 1 firefox version",
37 | "last 1 safari version"
38 | ]
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/example/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mannynotfound/react-three-third-person/737077f7e88445c9c3b7112b95616b45a489bccd/example/public/favicon.ico
--------------------------------------------------------------------------------
/example/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
12 |
13 |
17 |
18 |
27 | React App
28 |
29 |
30 |
31 |
32 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/example/public/logo192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mannynotfound/react-three-third-person/737077f7e88445c9c3b7112b95616b45a489bccd/example/public/logo192.png
--------------------------------------------------------------------------------
/example/public/logo512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mannynotfound/react-three-third-person/737077f7e88445c9c3b7112b95616b45a489bccd/example/public/logo512.png
--------------------------------------------------------------------------------
/example/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | },
10 | {
11 | "src": "logo192.png",
12 | "type": "image/png",
13 | "sizes": "192x192"
14 | },
15 | {
16 | "src": "logo512.png",
17 | "type": "image/png",
18 | "sizes": "512x512"
19 | }
20 | ],
21 | "start_url": ".",
22 | "display": "standalone",
23 | "theme_color": "#000000",
24 | "background_color": "#ffffff"
25 | }
26 |
--------------------------------------------------------------------------------
/example/public/robots.txt:
--------------------------------------------------------------------------------
1 | # https://www.robotstxt.org/robotstxt.html
2 | User-agent: *
3 | Disallow:
4 |
--------------------------------------------------------------------------------
/example/src/App.css:
--------------------------------------------------------------------------------
1 | .App {
2 | height: 100vh;
3 | width: 100%;
4 | }
5 |
--------------------------------------------------------------------------------
/example/src/App.js:
--------------------------------------------------------------------------------
1 | import React, { Suspense } from "react";
2 | import { Canvas } from "@react-three/fiber";
3 | import { Physics, Debug, useBox } from "@react-three/cannon";
4 | import manny from "manny";
5 | import ThirdPersonCharacterControls from "react-three-third-person";
6 |
7 | const BASE_ANIMATIONS_PATH =
8 | "https://mannys-game.s3.amazonaws.com/third-person/animations";
9 |
10 | const animationPaths = {
11 | idle: `${BASE_ANIMATIONS_PATH}/idle.glb`,
12 | walk: `${BASE_ANIMATIONS_PATH}/walk.glb`,
13 | run: `${BASE_ANIMATIONS_PATH}/run.glb`,
14 | jump: `${BASE_ANIMATIONS_PATH}/jump.glb`,
15 | landing: `${BASE_ANIMATIONS_PATH}/landing.glb`,
16 | inAir: `${BASE_ANIMATIONS_PATH}/falling_idle.glb`,
17 | backpedal: `${BASE_ANIMATIONS_PATH}/backpedal.glb`,
18 | turnLeft: `${BASE_ANIMATIONS_PATH}/turn_left.glb`,
19 | turnRight: `${BASE_ANIMATIONS_PATH}/turn_right.glb`,
20 | strafeLeft: `${BASE_ANIMATIONS_PATH}/strafe_left.glb`,
21 | strafeRight: `${BASE_ANIMATIONS_PATH}/strafe_right.glb`,
22 | };
23 |
24 | function ThirdPersonCharacter() {
25 | const mannyObj = manny();
26 |
27 | return (
28 |
38 | );
39 | }
40 |
41 | function Lighting() {
42 | return (
43 | <>
44 |
49 |
55 | >
56 | );
57 | }
58 |
59 | function Floor() {
60 | const [ref] = useBox(() => ({
61 | type: "Static",
62 | args: [25, 0.2, 25],
63 | mass: 0,
64 | material: {
65 | friction: 0,
66 | name: "floor",
67 | },
68 | collisionFilterGroup: 2,
69 | }));
70 | return (
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 | );
79 | }
80 |
81 | function Wall({ args, ...props }) {
82 | const [ref] = useBox(() => ({
83 | type: "Static",
84 | args,
85 | mass: 0,
86 | material: {
87 | friction: 0.3,
88 | name: "wall",
89 | },
90 | collisionFilterGroup: 2,
91 | ...props,
92 | }));
93 | return (
94 |
95 |
96 |
97 |
98 | );
99 | }
100 |
101 | function App() {
102 | return (
103 |
104 |
135 |
136 | );
137 | }
138 |
139 | export default App;
140 |
--------------------------------------------------------------------------------
/example/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
4 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
5 | sans-serif;
6 | -webkit-font-smoothing: antialiased;
7 | -moz-osx-font-smoothing: grayscale;
8 | }
9 |
10 | code {
11 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
12 | monospace;
13 | }
14 |
--------------------------------------------------------------------------------
/example/src/index.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ReactDOM from "react-dom/client";
3 | import "./index.css";
4 | import App from "./App";
5 |
6 | const root = ReactDOM.createRoot(document.getElementById("root"));
7 | root.render(
8 |
9 |
10 |
11 | );
12 |
--------------------------------------------------------------------------------
/lib/index.js:
--------------------------------------------------------------------------------
1 | import { useRef, useState, useEffect, useMemo, Suspense } from 'react';
2 | import * as THREE from 'three';
3 | import { AnimationMixer } from 'three';
4 | import { useFrame, useThree } from '@react-three/fiber';
5 | import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
6 | import { FBXLoader } from 'three/examples/jsm/loaders/FBXLoader';
7 | import 'default-passive-events';
8 | import { useRaycastClosest, useCompoundBody } from '@react-three/cannon';
9 | import { jsx } from 'react/jsx-runtime';
10 |
11 | const FBX_LOADER = new FBXLoader();
12 | const GLTF_LOADER = new GLTFLoader();
13 | async function asyncForEach(array, callback) {
14 | for (let index = 0; index < array.length; index++) {
15 | await callback(array[index], index, array);
16 | }
17 | }
18 | function loadModelSync(url, loader) {
19 | return new Promise((resolve, reject) => {
20 | loader.load(url, data => resolve(data), null, reject);
21 | });
22 | }
23 | function useThirdPersonAnimations(characterObj, animationPaths, onLoad) {
24 | if (animationPaths === void 0) {
25 | animationPaths = {};
26 | }
27 | if (onLoad === void 0) {
28 | onLoad = () => {};
29 | }
30 | const ref = useRef();
31 | const [clips, setClips] = useState([]);
32 | const [actualRef, setRef] = useState(ref);
33 | const [mixer, setMixer] = useState(new AnimationMixer(undefined));
34 | const lazyActions = useRef({});
35 | const [animations, setAnimations] = useState({});
36 |
37 | // set character obj + mixer for character
38 | useEffect(() => {
39 | if (characterObj) {
40 | setRef({
41 | current: characterObj
42 | });
43 | setMixer(new AnimationMixer(undefined));
44 | }
45 | }, [characterObj.name]);
46 |
47 | // load animations async initially
48 | useEffect(() => {
49 | const loadAnimations = async () => {
50 | const newAnimations = {};
51 | const keys = ['idle', 'walk', 'run', 'jump', 'landing', 'inAir', 'backpedal', 'turnLeft', 'turnRight', 'strafeLeft', 'strafeRight'];
52 | await asyncForEach(keys, async key => {
53 | const fileExt = animationPaths[key].split('.').pop();
54 | const loader = fileExt === 'fbx' ? FBX_LOADER : GLTF_LOADER;
55 | const model = await loadModelSync(animationPaths[key], loader);
56 | newAnimations[key] = model;
57 | });
58 | setAnimations(newAnimations);
59 | onLoad();
60 | };
61 | loadAnimations();
62 | }, []);
63 |
64 | // set clips once animations are loaded
65 | useEffect(() => {
66 | const clipsToSet = [];
67 | Object.keys(animations).forEach(name => {
68 | var _animations$name, _animations$name$anim;
69 | if ((_animations$name = animations[name]) != null && (_animations$name$anim = _animations$name.animations) != null && _animations$name$anim.length) {
70 | animations[name].animations[0].name = name;
71 | clipsToSet.push(animations[name].animations[0]);
72 | }
73 | });
74 | if (clips.length < clipsToSet.length) {
75 | setClips(clipsToSet);
76 | }
77 | }, [animations]);
78 | const api = useMemo(() => {
79 | if (!mixer || !clips.length) {
80 | return {
81 | actions: {}
82 | };
83 | }
84 | const actions = {};
85 | clips.forEach(clip => Object.defineProperty(actions, clip.name, {
86 | enumerable: true,
87 | get() {
88 | if (actualRef.current) {
89 | lazyActions.current[clip.name] = mixer.clipAction(clip, actualRef.current);
90 | const clampers = ['jump', 'landing'];
91 | if (clampers.includes(clip.name)) {
92 | lazyActions.current[clip.name].setLoop(2200); // 2200 = THREE.LoopOnce
93 | lazyActions.current[clip.name].clampWhenFinished = true;
94 | }
95 | return lazyActions.current[clip.name];
96 | }
97 | return null;
98 | }
99 | }));
100 | return {
101 | ref: actualRef,
102 | clips,
103 | actions,
104 | names: clips.map(c => c.name),
105 | mixer
106 | };
107 | }, [clips, characterObj.name, mixer]);
108 | useEffect(() => {
109 | const currentRoot = actualRef.current;
110 | return () => {
111 | // Clean up only when clips change, wipe out lazy actions and uncache clips
112 | lazyActions.current = {};
113 | Object.values(api.actions).forEach(action => {
114 | if (currentRoot) {
115 | mixer.uncacheAction(action, currentRoot);
116 | }
117 | });
118 | };
119 | }, [clips]);
120 | useFrame((_, delta) => {
121 | mixer.update(delta);
122 | });
123 | return api;
124 | }
125 |
126 | /*
127 | * Based on code written by knav.eth for chainspace (https://somnet.chainrunners.xyz/chainspace)
128 | */
129 | const CameraControlOperation = {
130 | NONE: -1,
131 | ROTATE: 0,
132 | TOUCH_ROTATE: 3,
133 | TOUCH_ZOOM_ROTATE: 6
134 | };
135 | const ROTATION_ANGLE = new THREE.Vector3(0, 1, 0);
136 | class CameraState {
137 | operation = CameraControlOperation.NONE;
138 | pointers = [];
139 | pointerPositions = {};
140 | reset() {
141 | this.operation = CameraControlOperation.NONE;
142 | this.pointers = [];
143 | this.pointerPositions = {};
144 | }
145 | }
146 | class ThirdPersonCameraControls {
147 | enabled = true;
148 | // How far you can zoom in and out ( PerspectiveCamera only )
149 | minDistance = 0;
150 | maxDistance = Infinity;
151 |
152 | // How far you can orbit vertically, upper and lower limits.
153 | // Range is 0 to Math.PI radians.
154 | minPolarAngle = 0;
155 | maxPolarAngle = Math.PI;
156 | enableZoom = true;
157 | zoomSpeed = 1.75;
158 | enableRotate = true;
159 | rotateSpeed = 1.0;
160 |
161 | // "target" sets the location of focus, where the object orbits around
162 | targetOffset = new THREE.Vector3(0, 0, 0);
163 | spherical = new THREE.Spherical(3.5, Math.PI / 3, Math.PI);
164 | rotateStart = new THREE.Vector2();
165 | rotateEnd = new THREE.Vector2();
166 | rotateDelta = new THREE.Vector2();
167 | zoomStart = new THREE.Vector2();
168 | zoomEnd = new THREE.Vector2();
169 | zoomDelta = new THREE.Vector2();
170 | outerCameraContainer = new THREE.Object3D();
171 | constructor(camera, domElement, target, inputManager, options, cameraContainer) {
172 | var _options, _options2;
173 | if (options === void 0) {
174 | options = {};
175 | }
176 | this.camera = camera;
177 | this.cameraState = new CameraState();
178 | this.cameraContainer = cameraContainer;
179 | this.domElement = domElement;
180 | this.input = {};
181 | const k = 'camera';
182 | inputManager.subscribe('wheel', k, this.handleMouseWheel.bind(this));
183 | inputManager.subscribe('pointerlockchange', k, this.onPointerLockChange.bind(this));
184 | inputManager.subscribe('pointerdown', k, this.onPointerDown.bind(this));
185 | inputManager.subscribe('pointerup', k, this.onPointerUp.bind(this));
186 | inputManager.subscribe('pointermove', k, this.onPointerMove.bind(this));
187 | inputManager.subscribe('pointercancel', k, this.onPointerCancel.bind(this));
188 | inputManager.subscribe('pointerlockerror', k, e => console.error('POINTERLOCK ERROR ', e));
189 | inputManager.subscribe('contextmenu', k, this.onContextMenu.bind(this));
190 | this.cameraCollisionOn = (_options = options) == null ? void 0 : _options.cameraCollisionOn;
191 | this.targetOffset.y = ((_options2 = options) == null ? void 0 : _options2.yOffset) ?? 1.6;
192 | this.outerCameraContainer.position.copy(this.targetOffset);
193 | this.outerCameraContainer.add(this.cameraContainer);
194 | this.target = target;
195 | this.target.add(this.outerCameraContainer);
196 | }
197 | _cameraPos = new THREE.Vector3();
198 | _raycastTargetVector = new THREE.Vector3();
199 | getCameraPosition(rayResult) {
200 | this.cameraContainer.position.setFromSphericalCoords(this.spherical.radius, this.spherical.phi, this.spherical.theta);
201 | if (rayResult.hasHit && this.cameraCollisionOn) {
202 | this.cameraContainer.position.setFromSphericalCoords(rayResult.distance - 0.1, this.spherical.phi, this.spherical.theta);
203 | }
204 | this.cameraContainer.getWorldPosition(this._cameraPos);
205 | return this._cameraPos;
206 | }
207 | _workingVec = new THREE.Vector3();
208 | getCameraLookVec() {
209 | this.target.getWorldPosition(this._workingVec).add(this.targetOffset);
210 | return this._workingVec;
211 | }
212 | _workingQuat = new THREE.Quaternion();
213 | update(rayResult) {
214 | if (this.input.isMouseLooking) {
215 | this._workingQuat.setFromAxisAngle(ROTATION_ANGLE, this.spherical.theta - Math.PI);
216 | this.target.quaternion.multiply(this._workingQuat);
217 | this.spherical.theta = Math.PI;
218 | }
219 |
220 | // restrict phi to be between desired limits
221 | this.spherical.phi = Math.max(this.minPolarAngle, Math.min(this.maxPolarAngle, this.spherical.phi));
222 | this.spherical.makeSafe();
223 |
224 | // restrict radius to be between desired limits
225 | this.spherical.radius = Math.max(this.minDistance, Math.min(this.maxDistance, this.spherical.radius));
226 |
227 | // copy maths to actual three.js camera
228 | this.camera.position.copy(this.getCameraPosition(rayResult));
229 | this.camera.lookAt(this.getCameraLookVec());
230 | }
231 | getZoomScale() {
232 | return 0.95 ** this.zoomSpeed;
233 | }
234 | rotateLeft(angle) {
235 | this.spherical.theta -= angle;
236 | }
237 | rotateUp(angle) {
238 | this.spherical.phi -= angle;
239 | }
240 | handleApplyRotate(speedMultiplier) {
241 | if (speedMultiplier === void 0) {
242 | speedMultiplier = 1;
243 | }
244 | this.rotateDelta.subVectors(this.rotateEnd, this.rotateStart).multiplyScalar(this.rotateSpeed * speedMultiplier);
245 | const element = this.domElement;
246 | this.rotateLeft(2 * Math.PI * this.rotateDelta.x / element.clientHeight); // yes, height
247 |
248 | this.rotateUp(2 * Math.PI * this.rotateDelta.y / element.clientHeight);
249 | this.rotateStart.copy(this.rotateEnd);
250 | }
251 | zoomOut(zoomScale) {
252 | this.spherical.radius /= zoomScale;
253 | }
254 | zoomIn(zoomScale) {
255 | this.spherical.radius *= zoomScale;
256 | }
257 |
258 | // Event Handlers
259 | handleMouseDownRotate(event) {
260 | this.rotateEnd.set(event.clientX, event.clientY);
261 | this.rotateStart.set(event.clientX, event.clientY);
262 | }
263 | handleMouseMoveRotate(event) {
264 | if (document.pointerLockElement === this.domElement) {
265 | this.rotateEnd.x += event.movementX * 0.25;
266 | this.rotateEnd.y += event.movementY * 0.25 * 0.8;
267 | } else {
268 | this.domElement.requestPointerLock();
269 | this.domElement.style.cursor = 'none';
270 | this.rotateEnd.set(event.clientX, event.clientY);
271 | }
272 | this.handleApplyRotate();
273 | }
274 | handleMouseWheel(event) {
275 | if (event.deltaY < 0) {
276 | this.zoomIn(this.getZoomScale());
277 | } else if (event.deltaY > 0) {
278 | this.zoomOut(this.getZoomScale());
279 | }
280 | }
281 | handleTouchStartRotate() {
282 | if (this.cameraState.pointers.length === 1) {
283 | this.rotateStart.set(this.cameraState.pointers[0].pageX, this.cameraState.pointers[0].pageY);
284 | } else {
285 | const x = 0.5 * (this.cameraState.pointers[0].pageX + this.cameraState.pointers[1].pageX);
286 | const y = 0.5 * (this.cameraState.pointers[0].pageY + this.cameraState.pointers[1].pageY);
287 | this.rotateStart.set(x, y);
288 | }
289 | }
290 | handleTouchStartZoom() {
291 | const dx = this.cameraState.pointers[0].pageX - this.cameraState.pointers[1].pageX;
292 | const dy = this.cameraState.pointers[0].pageY - this.cameraState.pointers[1].pageY;
293 | const distance = Math.sqrt(dx * dx + dy * dy);
294 | this.zoomStart.set(0, distance);
295 | }
296 | handleTouchStartZoomRotate() {
297 | if (this.enableZoom) this.handleTouchStartZoom();
298 | if (this.enableRotate) this.handleTouchStartRotate();
299 | }
300 | handleTouchMoveRotate(event) {
301 | if (this.cameraState.pointers.length === 1) {
302 | this.rotateEnd.set(event.pageX, event.pageY);
303 | } else {
304 | const position = this.getSecondPointerPosition(event);
305 | const x = 0.5 * (event.pageX + position.x);
306 | const y = 0.5 * (event.pageY + position.y);
307 | this.rotateEnd.set(x, y);
308 | }
309 | this.handleApplyRotate(1.3);
310 | }
311 | handleTouchMoveZoom(event) {
312 | const position = this.getSecondPointerPosition(event);
313 | const dx = event.pageX - position.x;
314 | const dy = event.pageY - position.y;
315 | const distance = Math.sqrt(dx * dx + dy * dy);
316 | this.zoomEnd.set(0, distance);
317 | this.zoomDelta.set(0, (this.zoomEnd.y / this.zoomStart.y) ** this.zoomSpeed);
318 | this.zoomOut(this.zoomDelta.y);
319 | this.zoomStart.copy(this.zoomEnd);
320 | }
321 | handleTouchMoveZoomRotate(event) {
322 | if (this.enableZoom) this.handleTouchMoveZoom(event);
323 | if (this.enableRotate) this.handleTouchMoveRotate(event);
324 | }
325 |
326 | // Event Controllers
327 | onPointerDown(event) {
328 | if (!this.enabled) return;
329 | if (this.cameraState.pointers.length === 0) {
330 | this.domElement.setPointerCapture(event.pointerId);
331 | }
332 | this.addPointer(event);
333 | if (event.pointerType === 'touch') {
334 | this.onTouchStart(event);
335 | } else {
336 | this.onMouseDown(event);
337 | }
338 | }
339 | onPointerMove(event) {
340 | this.lastCheck = Date.now();
341 | if (!this.enabled) return;
342 | if (!this.input.isMouseLocked && !this.cameraState.pointers.length) return;
343 | if (!this.cameraState.pointers.find(e => e.pointerId === event.pointerId)) {
344 | return;
345 | }
346 | if (event.pointerType === 'touch') {
347 | this.onTouchMove(event);
348 | } else {
349 | this.onMouseMove(event);
350 | }
351 | }
352 | onPointerUp(event) {
353 | if (event.pointerType === 'touch') {
354 | this.onTouchEnd();
355 | } else {
356 | this.onMouseUp();
357 | }
358 | this.removePointer(event);
359 | if (this.cameraState.pointers.length === 0 && event.pointerType === 'touch') {
360 | this.domElement.releasePointerCapture(event.pointerId);
361 | }
362 | }
363 |
364 | // Touch
365 | onTouchStart(event) {
366 | this.trackPointer(event);
367 | switch (this.cameraState.pointers.length) {
368 | case 1:
369 | if (!this.enableRotate) return;
370 | this.handleTouchStartRotate();
371 | this.input.isMouseLooking = true;
372 | this.cameraState.operation = CameraControlOperation.TOUCH_ROTATE;
373 | break;
374 | case 2:
375 | if (!this.enableZoom && !this.enableRotate) return;
376 | this.handleTouchStartZoomRotate();
377 | this.input.isMouseLooking = true;
378 | this.cameraState.operation = CameraControlOperation.TOUCH_ZOOM_ROTATE;
379 | break;
380 | default:
381 | this.cameraState.operation = CameraControlOperation.NONE;
382 | }
383 | }
384 | onTouchMove(event) {
385 | this.trackPointer(event);
386 | switch (this.cameraState.operation) {
387 | case CameraControlOperation.TOUCH_ROTATE:
388 | if (!this.enableRotate) return;
389 | this.handleTouchMoveRotate(event);
390 | break;
391 | case CameraControlOperation.TOUCH_ZOOM_ROTATE:
392 | if (!this.enableZoom && !this.enableRotate) return;
393 | this.handleTouchMoveZoomRotate(event);
394 | break;
395 | default:
396 | this.cameraState.operation = CameraControlOperation.NONE;
397 | }
398 | }
399 | onTouchEnd() {
400 | this.cameraState.operation = CameraControlOperation.NONE;
401 | }
402 |
403 | // Mouse
404 | onPointerLockChange() {
405 | // do initial check to see if mouse is locked
406 | this.input.isMouseLocked = document.pointerLockElement === this.domElement;
407 | if (!this.input.isMouseLocked) {
408 | // wait 100ms and then check again as sometimes document.pointerLockElement
409 | // is null after doing a document.requestPointerLock()
410 | setTimeout(() => {
411 | this.input.isMouseLocked = document.pointerLockElement === this.domElement;
412 | if (!this.input.isMouseLocked) {
413 | this.input.isMouseLooking = false;
414 | this.cameraState.operation = CameraControlOperation.NONE;
415 | }
416 | }, 100);
417 | }
418 | }
419 | onMouseDown(event) {
420 | switch (event.button) {
421 | case 0:
422 | if (!this.enableRotate) return;
423 | this.handleMouseDownRotate(event);
424 | this.cameraState.operation = CameraControlOperation.ROTATE;
425 | break;
426 | case 1:
427 | this.cameraState.operation = CameraControlOperation.NONE;
428 | break;
429 | case 2:
430 | if (!this.enableRotate) return;
431 | this.input.isMouseLooking = true;
432 | this.rightClickTime = Date.now();
433 | this.handleMouseDownRotate(event);
434 | this.cameraState.operation = CameraControlOperation.ROTATE;
435 | break;
436 | default:
437 | this.cameraState.operation = CameraControlOperation.NONE;
438 | }
439 | }
440 | onMouseMove(event) {
441 | if (!this.enabled) return;
442 | if (this.cameraState.operation === CameraControlOperation.ROTATE) {
443 | if (!this.enableRotate) return;
444 | this.handleMouseMoveRotate(event);
445 | }
446 | }
447 | onMouseUp() {
448 | this.domElement.style.cursor = 'initial';
449 | document.exitPointerLock();
450 | this.input.isMouseLooking = false;
451 | }
452 | onMouseWheel(event) {
453 | if (!this.enabled || !this.enableZoom || this.cameraState.operation !== CameraControlOperation.NONE && this.cameraState.operation !== CameraControlOperation.ROTATE) {
454 | return;
455 | }
456 | this.handleMouseWheel(event);
457 | }
458 |
459 | // Pointer Utils
460 | getSecondPointerPosition(event) {
461 | const pointer = event.pointerId === this.cameraState.pointers[0].pointerId ? this.cameraState.pointers[1] : this.cameraState.pointers[0];
462 | return this.cameraState.pointerPositions[pointer.pointerId];
463 | }
464 | addPointer(event) {
465 | this.cameraState.pointers.push(event);
466 | }
467 | removePointer(event) {
468 | delete this.cameraState.pointerPositions[event.pointerId];
469 | for (let i = 0; i < this.cameraState.pointers.length; i++) {
470 | if (this.cameraState.pointers[i].pointerId === event.pointerId) {
471 | this.cameraState.pointers.splice(i, 1);
472 | return;
473 | }
474 | }
475 | }
476 | trackPointer(event) {
477 | let position = this.cameraState.pointerPositions[event.pointerId];
478 | if (position === undefined) {
479 | position = new THREE.Vector2();
480 | this.cameraState.pointerPositions[event.pointerId] = position;
481 | }
482 | position.set(event.pageX, event.pageY);
483 | }
484 | onPointerCancel(event) {
485 | this.removePointer(event);
486 | }
487 | onContextMenu(event) {
488 | if (!this.enabled) return;
489 | event.preventDefault();
490 | }
491 | reset() {
492 | this.cameraState.reset();
493 | this.domElement.style.cursor = 'initial';
494 | try {
495 | document.exitPointerLock();
496 | } catch (e) {
497 | // lol
498 | }
499 | }
500 | dispose() {
501 | // remove event listeners here
502 | }
503 | }
504 | function useThirdPersonCameraControls(_ref) {
505 | let {
506 | camera,
507 | domElement,
508 | target,
509 | inputManager,
510 | cameraOptions,
511 | cameraContainer
512 | } = _ref;
513 | const [controls, setControls] = useState(null);
514 | useEffect(() => {
515 | if (!target) {
516 | return;
517 | }
518 | const newControls = new ThirdPersonCameraControls(camera, domElement, target, inputManager, {
519 | yOffset: cameraOptions.yOffset || 0
520 | }, cameraContainer.current);
521 | newControls.minDistance = (cameraOptions == null ? void 0 : cameraOptions.minDistance) || 404;
522 | newControls.maxDistance = (cameraOptions == null ? void 0 : cameraOptions.maxDistance) || 808;
523 | setControls(newControls);
524 | return () => {
525 | newControls.dispose();
526 | };
527 | }, [camera, domElement, target]);
528 | return controls;
529 | }
530 |
531 | function useInputEventManager(container) {
532 | if (container === void 0) {
533 | container = window;
534 | }
535 | const [subscriptions, setSubscriptions] = useState({});
536 | const subscribe = (eventName, key, subscribeFn) => {
537 | setSubscriptions(prevState => ({
538 | ...prevState,
539 | [eventName]: {
540 | ...prevState[eventName],
541 | [key]: subscribeFn
542 | }
543 | }));
544 | };
545 | const unsubscribe = (eventName, key) => {
546 | setSubscriptions(prevState => {
547 | var _prevState$eventName;
548 | prevState == null ? true : (_prevState$eventName = prevState[eventName]) == null ? true : delete _prevState$eventName[key];
549 | return prevState;
550 | });
551 | };
552 | const makeEventHandler = eventName => event => {
553 | const handlers = subscriptions[eventName] ?? {};
554 | const subscribers = Object.values(handlers);
555 | subscribers.forEach(sub => sub(event));
556 | };
557 | const keydownHandler = makeEventHandler("keydown");
558 | const keyupHandler = makeEventHandler("keyup");
559 | const wheelHandler = makeEventHandler("wheel");
560 | const pointerdownHandler = makeEventHandler("pointerdown");
561 | const pointerupHandler = makeEventHandler("pointerup");
562 | const pointermoveHandler = makeEventHandler("pointermove");
563 | const pointercancelHandler = makeEventHandler("pointercancel");
564 | const pointerlockchangeHandler = makeEventHandler("pointerlockchange");
565 | const pointerlockerrorHandler = makeEventHandler("pointerlockerror");
566 | const contextmenuHandler = makeEventHandler("contextmenu");
567 | const setupEventListeners = () => {
568 | window.addEventListener("keydown", keydownHandler);
569 | window.addEventListener("keyup", keyupHandler);
570 | container.addEventListener("wheel", wheelHandler);
571 | container.addEventListener("pointerdown", pointerdownHandler);
572 | container.addEventListener("pointerup", pointerupHandler);
573 | container.addEventListener("pointermove", pointermoveHandler);
574 | container.addEventListener("pointercancel", pointercancelHandler);
575 | container.addEventListener("contextmenu", contextmenuHandler);
576 | document.addEventListener("pointerlockchange", pointerlockchangeHandler);
577 | document.addEventListener("pointerlockerror", pointerlockerrorHandler);
578 | return () => {
579 | window.removeEventListener("keydown", keydownHandler);
580 | window.removeEventListener("keyup", keyupHandler);
581 | container.removeEventListener("wheel", wheelHandler);
582 | container.removeEventListener("pointerdown", pointerdownHandler);
583 | container.removeEventListener("pointerup", pointerupHandler);
584 | container.removeEventListener("pointermove", pointermoveHandler);
585 | container.removeEventListener("pointercancel", pointercancelHandler);
586 | container.removeEventListener("contextmenu", contextmenuHandler);
587 | document.removeEventListener("pointerlockchange", pointerlockchangeHandler);
588 | document.removeEventListener("pointerlockerror", pointerlockerrorHandler);
589 | };
590 | };
591 | useEffect(setupEventListeners, [subscriptions, container]);
592 | return {
593 | subscribe,
594 | unsubscribe
595 | };
596 | }
597 |
598 | const defaultMap = {
599 | up: "w",
600 | down: "s",
601 | right: "d",
602 | left: "a",
603 | jump: " ",
604 | walk: "Shift"
605 | };
606 | const getInputFromKeyboard = (keyMap, keyPressed) => {
607 | let inputFound = "";
608 | Object.entries(keyMap).forEach(_ref => {
609 | let [k, v] = _ref;
610 | if (v === keyPressed) {
611 | inputFound = k;
612 | }
613 | });
614 | return inputFound;
615 | };
616 | function useKeyboardInput(inputManager, userKeyMap) {
617 | if (userKeyMap === void 0) {
618 | userKeyMap = {};
619 | }
620 | const [isMouseLooking, setIsMouseLooking] = useState(false);
621 | const [inputsPressed, setInputsPressed] = useState({});
622 | const keyMap = {
623 | ...defaultMap,
624 | ...userKeyMap
625 | };
626 | function downHandler(_ref2) {
627 | let {
628 | key
629 | } = _ref2;
630 | const input = getInputFromKeyboard(keyMap, key);
631 | if (input) {
632 | setInputsPressed(prevState => ({
633 | ...prevState,
634 | [input]: true
635 | }));
636 | }
637 | }
638 | const upHandler = _ref3 => {
639 | let {
640 | key
641 | } = _ref3;
642 | const input = getInputFromKeyboard(keyMap, key);
643 | if (input) {
644 | setInputsPressed(prevState => ({
645 | ...prevState,
646 | [input]: false
647 | }));
648 | }
649 | };
650 | function pointerdownHandler(_ref4) {
651 | let {
652 | button
653 | } = _ref4;
654 | if (button === 2) {
655 | setIsMouseLooking(true);
656 | }
657 | }
658 | const pointerupHandler = _ref5 => {
659 | let {
660 | button
661 | } = _ref5;
662 | if (button === 2) {
663 | setIsMouseLooking(false);
664 | }
665 | };
666 | useEffect(() => {
667 | inputManager.subscribe("keydown", "character-controls", downHandler);
668 | inputManager.subscribe("keyup", "character-controls", upHandler);
669 | inputManager.subscribe("pointerdown", "character-controls", pointerdownHandler);
670 | inputManager.subscribe("pointerup", "character-controls", pointerupHandler);
671 | return () => {
672 | inputManager.unsubscribe("keydown", "character-controls");
673 | inputManager.unsubscribe("keyup", "character-controls");
674 | inputManager.unsubscribe("pointerdown", "character-controls");
675 | inputManager.unsubscribe("pointerup", "character-controls");
676 | };
677 | }, []);
678 | return {
679 | ...inputsPressed,
680 | isMouseLooking
681 | };
682 | }
683 |
684 | /*
685 | * Based on code written by knav.eth for chainspace (https://somnet.chainrunners.xyz/chainspace)
686 | */
687 |
688 | /**
689 | * Finds an angle between two vectors
690 | * @param {THREE.Vector3} v1
691 | * @param {THREE.Vector3} v2
692 | */
693 | function getAngleBetweenVectors(v1, v2, dotThreshold) {
694 | if (dotThreshold === void 0) {
695 | dotThreshold = 0.0005;
696 | }
697 | let angle;
698 | const dot = v1.dot(v2);
699 |
700 | // If dot is close to 1, we'll round angle to zero
701 | if (dot > 1 - dotThreshold) {
702 | angle = 0;
703 | } else if (dot < -1 + dotThreshold) {
704 | // Dot too close to -1
705 | angle = Math.PI;
706 | } else {
707 | // Get angle difference in radians
708 | angle = Math.acos(dot);
709 | }
710 | return angle;
711 | }
712 |
713 | /**
714 | * Finds an angle between two vectors with a sign relative to normal vector
715 | */
716 | function getSignedAngleBetweenVectors(v1, v2, normal, dotThreshold) {
717 | if (normal === void 0) {
718 | normal = new THREE.Vector3(0, 1, 0);
719 | }
720 | if (dotThreshold === void 0) {
721 | dotThreshold = 0.0005;
722 | }
723 | let angle = getAngleBetweenVectors(v1, v2, dotThreshold);
724 |
725 | // Get vector pointing up or down
726 | const cross = new THREE.Vector3().crossVectors(v1, v2);
727 | // Compare cross with normal to find out direction
728 | if (normal.dot(cross) < 0) {
729 | angle = -angle;
730 | }
731 | return angle;
732 | }
733 | function getRotationDirection(_ref) {
734 | let {
735 | left,
736 | right,
737 | isMouseLooking
738 | } = _ref;
739 | let direction = 0;
740 | if (!isMouseLooking) {
741 | if (left) {
742 | direction = -1;
743 | }
744 | if (right) {
745 | direction = 1;
746 | }
747 | }
748 | return direction;
749 | }
750 | function getMovementDirection(_ref2) {
751 | let {
752 | up,
753 | down,
754 | right,
755 | left,
756 | isMouseLooking
757 | } = _ref2;
758 | const positiveX = isMouseLooking && right ? -1 : 0;
759 | const negativeX = isMouseLooking && left ? 1 : 0;
760 | const positiveZ = up ? 1 : 0;
761 | const negativeZ = down ? -1 : 0;
762 | return new THREE.Vector3(positiveX + negativeX, 0, positiveZ + negativeZ).normalize();
763 | }
764 | const FORWARD = new THREE.Vector3(0, 0, 1);
765 | function getModelRotation(inputs) {
766 | const {
767 | up,
768 | down,
769 | right,
770 | left,
771 | isMouseLooking
772 | } = inputs;
773 | const movementDirection = getMovementDirection(inputs);
774 | let modelRotation = 0;
775 | if ((up || down) && !(down && up) && (left || right) && isMouseLooking) {
776 | const rotationDirection = getRotationDirection(inputs);
777 | const movementAngle = getSignedAngleBetweenVectors(movementDirection, FORWARD);
778 | if (up) {
779 | modelRotation = rotationDirection === 0 ? -movementAngle : Math.PI / 8 * rotationDirection * -1;
780 | } else if (down) {
781 | if (rotationDirection === 0) {
782 | if (movementDirection.x > 0) {
783 | modelRotation = Math.PI - movementAngle;
784 | } else if (movementDirection.x < 0) {
785 | modelRotation = Math.PI - movementAngle;
786 | }
787 | } else {
788 | modelRotation = Math.PI / 8 * rotationDirection * -1;
789 | }
790 | }
791 | }
792 | return modelRotation;
793 | }
794 | function useInputMovementRotation(inputs) {
795 | const direction = getRotationDirection(inputs);
796 | const rotation = getModelRotation(inputs);
797 | const movement = getMovementDirection(inputs);
798 | return {
799 | model: {
800 | direction,
801 | rotation
802 | },
803 | movement
804 | };
805 | }
806 |
807 | const getAnimationFromUserInputs = inputs => {
808 | const {
809 | up,
810 | down,
811 | right,
812 | left,
813 | isMouseLooking
814 | } = inputs;
815 | if (up && !down) {
816 | return 'run';
817 | }
818 | if (down && !up) {
819 | return 'backpedal';
820 | }
821 | if (!right && left) {
822 | return isMouseLooking ? 'strafeLeft' : 'turnLeft';
823 | }
824 | if (!left && right) {
825 | return isMouseLooking ? 'strafeRight' : 'turnRight';
826 | }
827 | return 'idle';
828 | };
829 | function useCharacterState(inputs, position, mixer) {
830 | if (inputs === void 0) {
831 | inputs = {};
832 | }
833 | const [characterState, setCharacterState] = useState({
834 | animation: 'idle',
835 | isJumping: false,
836 | inAir: false,
837 | isMoving: false
838 | });
839 | const [jumpPressed, setJumpPressed] = useState(false);
840 | const [landed, setLanded] = useState();
841 | const {
842 | up,
843 | down,
844 | right,
845 | left,
846 | jump,
847 | isMouseLooking
848 | } = inputs;
849 | const {
850 | isJumping,
851 | inAir,
852 | isLanding
853 | } = characterState;
854 | useEffect(() => {
855 | setJumpPressed(jump);
856 | setLanded(false);
857 | }, [jump]);
858 | const rayFrom = [position[0], position[1], position[2]];
859 | const rayTo = [position[0], position[1] - 0.2, position[2]];
860 | useRaycastClosest({
861 | from: rayFrom,
862 | to: rayTo,
863 | skipBackfaces: true
864 | }, e => {
865 | if (e.hasHit && !landed) {
866 | setLanded(true);
867 | }
868 | }, [position]);
869 | useEffect(() => {
870 | if (inAir && landed) {
871 | setCharacterState(prevState => ({
872 | ...prevState,
873 | inAir: false,
874 | animation: 'landing',
875 | isLanding: true
876 | }));
877 | }
878 | }, [landed, inAir]);
879 | useEffect(() => {
880 | setCharacterState(prevState => ({
881 | ...prevState,
882 | isMoving: up || down || left || right
883 | }));
884 | }, [up, down, left, right]);
885 | useEffect(() => {
886 | if (isJumping || inAir) {
887 | return;
888 | }
889 | const newState = {
890 | animation: getAnimationFromUserInputs(inputs)
891 | };
892 | if (jump && !jumpPressed) {
893 | newState.animation = 'jump';
894 | newState.isJumping = true;
895 | }
896 |
897 | // let landing animation playout if we're still landing
898 | if (isLanding && newState.animation === 'idle') {
899 | return;
900 | }
901 | setCharacterState(prevState => ({
902 | ...prevState,
903 | isLanding: false,
904 | ...newState
905 | }));
906 | }, [up, down, left, right, jump, isMouseLooking, isJumping, inAir]);
907 | useEffect(() => {
908 | const checker = () => {
909 | setCharacterState(prevState => ({
910 | ...prevState,
911 | isJumping: false,
912 | inAir: true,
913 | animation: 'inAir'
914 | }));
915 | };
916 | if (characterState.isJumping) {
917 | // play 200ms of jump animation then transition to inAir
918 | setTimeout(checker, 200);
919 | }
920 | return () => {
921 | clearTimeout(checker);
922 | };
923 | }, [characterState.isJumping]);
924 | useEffect(() => {
925 | if (!mixer) {
926 | return;
927 | }
928 | const onMixerFinish = () => {
929 | setCharacterState(prevState => ({
930 | ...prevState,
931 | isJumping: false,
932 | inAir: false,
933 | isLanding: false,
934 | animation: 'idle'
935 | }));
936 | };
937 | mixer.addEventListener('finished', onMixerFinish);
938 | return () => {
939 | mixer.removeEventListener('finished', onMixerFinish);
940 | };
941 | }, [mixer]);
942 | return characterState;
943 | }
944 |
945 | function useCapsuleCollider(radius) {
946 | if (radius === void 0) {
947 | radius = 0.5;
948 | }
949 | const [, collider] = useCompoundBody(() => ({
950 | mass: 0.2,
951 | fixedRotation: true,
952 | linearDamping: 0,
953 | angularDamping: 0,
954 | material: {
955 | friction: 0,
956 | name: 'no-fric-zone'
957 | },
958 | shapes: [{
959 | type: 'Sphere',
960 | position: [0, radius, 0],
961 | args: [radius]
962 | }, {
963 | type: 'Sphere',
964 | position: [0, radius * 4.2, 0],
965 | args: [radius]
966 | }, {
967 | type: 'Sphere',
968 | position: [0, radius * 5 - radius * 2.3, 0],
969 | args: [radius]
970 | }],
971 | position: [0, 0, 0],
972 | rotation: [0, Math.PI, 0],
973 | collisionFilterGroup: 1
974 | }));
975 | return collider;
976 | }
977 |
978 | function useRay(_ref) {
979 | let {
980 | rayVector,
981 | position,
982 | collisionFilterMask
983 | } = _ref;
984 | const rayChecker = useRef(setTimeout);
985 | const from = [position[0], position[1], position[2]];
986 | const to = [rayVector.current.x, rayVector.current.y, rayVector.current.z];
987 | const [ray, setRay] = useState({});
988 | useRaycastClosest({
989 | from,
990 | to,
991 | skipBackfaces: true,
992 | collisionFilterMask
993 | }, e => {
994 | clearTimeout(rayChecker.current);
995 | setRay({
996 | hasHit: e.hasHit,
997 | distance: e.distance
998 | });
999 | // this callback only fires constantly on collision so this
1000 | // timeout resets state once we've stopped colliding
1001 | rayChecker.current = setTimeout(() => {
1002 | setRay({});
1003 | }, 100);
1004 | }, [from, to]);
1005 | return ray;
1006 | }
1007 |
1008 | const ThirdPersonCharacterControls = _ref => {
1009 | let {
1010 | cameraOptions = {},
1011 | characterObj,
1012 | characterProps = {},
1013 | animationPaths = {},
1014 | onLoad
1015 | } = _ref;
1016 | const {
1017 | camera,
1018 | gl: {
1019 | domElement
1020 | }
1021 | } = useThree();
1022 | // set up refs that influence character and camera position
1023 | const collider = useCapsuleCollider(characterProps.radius);
1024 | const [position, setPosition] = useState([0, 0, 0]);
1025 | const modelRef = useRef();
1026 | const cameraContainer = useRef(new THREE.Object3D());
1027 | const rayVector = useRef(new THREE.Vector3());
1028 | const ray = useRay({
1029 | position,
1030 | rayVector,
1031 | ...cameraOptions
1032 | });
1033 |
1034 | // get character state based on user inputs + collider position + animations
1035 | const inputManager = useInputEventManager(domElement);
1036 | const inputs = useKeyboardInput(inputManager);
1037 | const controls = useThirdPersonCameraControls({
1038 | camera,
1039 | domElement,
1040 | target: modelRef.current,
1041 | inputManager,
1042 | cameraOptions,
1043 | cameraContainer
1044 | });
1045 | const {
1046 | actions,
1047 | mixer
1048 | } = useThirdPersonAnimations(characterObj, animationPaths, onLoad);
1049 | const {
1050 | animation,
1051 | isMoving
1052 | } = useCharacterState(inputs, position, mixer);
1053 |
1054 | // subscribe to collider velocity/position changes
1055 | const charVelocity = characterProps.velocity ?? 4;
1056 | const velocity = useRef([0, 0, 0]);
1057 | useEffect(() => {
1058 | collider.velocity.subscribe(v => {
1059 | velocity.current = v;
1060 | });
1061 | collider.position.subscribe(p => {
1062 | var _modelRef$current;
1063 | // position is set on collider so we copy it to model
1064 | (_modelRef$current = modelRef.current) == null ? void 0 : _modelRef$current.position.set(...p);
1065 | // setState with position to useCharacterState
1066 | setPosition(p);
1067 | });
1068 | }, []);
1069 | useFrame(() => {
1070 | let newRotation = new THREE.Euler();
1071 | let xVelocity = 0;
1072 | let zVelocity = 0;
1073 | const {
1074 | quaternion
1075 | } = modelRef.current;
1076 | if (isMoving) {
1077 | const {
1078 | model,
1079 | movement
1080 | } = useInputMovementRotation(inputs);
1081 |
1082 | // first rotate the model group
1083 | modelRef.current.rotateY(model.direction * -0.05);
1084 | newRotation = characterObj.rotation.clone();
1085 | newRotation.y = model.rotation;
1086 | const mtx = new THREE.Matrix4().makeRotationFromQuaternion(quaternion);
1087 | movement.applyMatrix4(mtx);
1088 |
1089 | // then apply velocity to collider influenced by model groups rotation
1090 | const baseVelocity = inputs.down ? charVelocity / 2 : charVelocity;
1091 | xVelocity = movement.x * baseVelocity;
1092 | zVelocity = movement.z * baseVelocity;
1093 | }
1094 | collider.velocity.set(xVelocity, velocity.current[1], zVelocity);
1095 |
1096 | // after applying x/z velocity, apply y velocity if user has jumped while grounded
1097 | const isGrounded = Math.abs(velocity.current[1].toFixed(2)) === 0;
1098 | if (animation === 'jump' && isGrounded) {
1099 | collider.velocity.set(velocity.current[0], 8, velocity.current[2]);
1100 | }
1101 |
1102 | // rotate character model inside model group
1103 | const newQuat = new THREE.Quaternion().setFromEuler(newRotation);
1104 | characterObj.quaternion.slerp(newQuat, 0.1);
1105 |
1106 | // quaternion is set on model group so we copy it to collider
1107 | collider.quaternion.copy(quaternion);
1108 | // check camera raycast collision and pass that to controls to
1109 | cameraContainer.current.getWorldPosition(rayVector.current);
1110 | controls == null ? void 0 : controls.update(ray);
1111 | });
1112 |
1113 | // Transition to new animation when loaded
1114 | useEffect(() => {
1115 | var _actions$animation;
1116 | actions == null ? void 0 : (_actions$animation = actions[animation]) == null ? void 0 : _actions$animation.reset().fadeIn(0.2).play();
1117 | return () => {
1118 | var _actions$animation2;
1119 | actions == null ? void 0 : (_actions$animation2 = actions[animation]) == null ? void 0 : _actions$animation2.fadeOut(0.2);
1120 | };
1121 | }, [animation, actions]);
1122 | return /*#__PURE__*/jsx("group", {
1123 | ref: modelRef,
1124 | rotation: [0, Math.PI, 0],
1125 | ...characterProps,
1126 | children: /*#__PURE__*/jsx(Suspense, {
1127 | fallback: () => null,
1128 | children: /*#__PURE__*/jsx("primitive", {
1129 | object: characterObj,
1130 | dispose: null
1131 | })
1132 | })
1133 | });
1134 | };
1135 |
1136 | export { ThirdPersonCharacterControls as default };
1137 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-three-third-person",
3 | "version": "0.4.06",
4 | "description": "package for adding third person controls in @react-three/fiber.",
5 | "main": "./lib/index.js",
6 | "scripts": {
7 | "dev": "cd example && npm start",
8 | "build": "rollup -c"
9 | },
10 | "repository": {
11 | "type": "git",
12 | "url": "https://github.com/mannynotfound/react-three-third-person.git"
13 | },
14 | "author": "@mannynotfound",
15 | "license": "WTFPL",
16 | "devDependencies": {
17 | "@babel/core": "^7.17.8",
18 | "@babel/plugin-transform-runtime": "^7.17.0",
19 | "@babel/preset-env": "^7.16.11",
20 | "@babel/preset-react": "^7.16.7",
21 | "@rollup/plugin-babel": "^5.3.1",
22 | "@rollup/plugin-node-resolve": "^13.1.3",
23 | "rollup": "^2.70.1"
24 | },
25 | "dependencies": {
26 | "default-passive-events": "^2.0.0"
27 | },
28 | "peerDependencies": {
29 | "@react-three/fiber": ">=7",
30 | "@react-three/drei": ">=8",
31 | "@react-three/cannon": ">=6",
32 | "react": ">=16",
33 | "three": ">=0.137"
34 | },
35 | "keywords": [
36 | "three.js",
37 | "react-three-fiber",
38 | "cannon-js"
39 | ],
40 | "homepage": "https://mannynotfound.github.io"
41 | }
42 |
--------------------------------------------------------------------------------
/rollup.config.js:
--------------------------------------------------------------------------------
1 | import babel from "@rollup/plugin-babel";
2 | import pluginNodeResolve from "@rollup/plugin-node-resolve";
3 |
4 | // These are our dependencies, everything else is in the bundle
5 | const external = [
6 | "@react-three/fiber",
7 | "@react-three/drei",
8 | "@react-three/cannon",
9 | "default-passive-events",
10 | "react",
11 | "react/jsx-runtime",
12 | "three",
13 | ];
14 | const extensions = [".js", ".jsx", ".json"];
15 |
16 | const getBabelOptions = ({ useESModules }, targets) => ({
17 | babelHelpers: "runtime",
18 | babelrc: false,
19 | extensions,
20 | include: ["src/**/*", "**/node_modules/**"],
21 | plugins: [["@babel/transform-runtime", { regenerator: false, useESModules }]],
22 | presets: [
23 | ["@babel/preset-env", { loose: true, modules: false, targets }],
24 | ["@babel/preset-react", { runtime: "automatic" }],
25 | ],
26 | });
27 |
28 | export default [
29 | {
30 | external,
31 | input: `./src/index.js`,
32 | output: { dir: "lib", format: "es" },
33 | plugins: [
34 | pluginNodeResolve({ extensions }),
35 | babel(
36 | getBabelOptions(
37 | { useESModules: true },
38 | ">1%, not dead, not ie 11, not op_mini all"
39 | )
40 | ),
41 | ],
42 | },
43 | ];
44 |
--------------------------------------------------------------------------------
/src/hooks/index.js:
--------------------------------------------------------------------------------
1 | export { default as useThirdPersonAnimations } from "./useThirdPersonAnimations";
2 | export { default as useThirdPersonCameraControls } from "./useThirdPersonCameraControls";
3 | export { default as useInputEventManager } from "./useInputEventManager";
4 | export { default as useKeyboardMouseMovement } from "./useKeyboardMouseMovement";
5 | export { default as useInputMovementRotation } from "./useInputMovementRotation";
6 | export { default as useCharacterState } from "./useCharacterState";
7 | export { default as useCapsuleCollider } from "./useCapsuleCollider";
8 | export { default as useRay } from "./useRay";
9 |
--------------------------------------------------------------------------------
/src/hooks/useCapsuleCollider.js:
--------------------------------------------------------------------------------
1 | import { useCompoundBody } from '@react-three/cannon';
2 |
3 | export default function useCapsuleCollider(radius = 0.5) {
4 | const [, collider] = useCompoundBody(() => ({
5 | mass: 0.2,
6 | fixedRotation: true,
7 | linearDamping: 0,
8 | angularDamping: 0,
9 | material: {
10 | friction: 0,
11 | name: 'no-fric-zone',
12 | },
13 | shapes: [
14 | { type: 'Sphere', position: [0, radius, 0], args: [radius] },
15 | { type: 'Sphere', position: [0, radius * 4.2, 0], args: [radius] },
16 | {
17 | type: 'Sphere',
18 | position: [0, radius * 5 - radius * 2.3, 0],
19 | args: [radius],
20 | },
21 | ],
22 | position: [0, 0, 0],
23 | rotation: [0, Math.PI, 0],
24 | collisionFilterGroup: 1,
25 | }));
26 |
27 | return collider;
28 | }
29 |
--------------------------------------------------------------------------------
/src/hooks/useCharacterState.js:
--------------------------------------------------------------------------------
1 | import { useRaycastClosest } from '@react-three/cannon';
2 | import { useState, useEffect } from 'react';
3 |
4 | const getAnimationFromUserInputs = (inputs) => {
5 | const { up, down, right, left, isMouseLooking } = inputs;
6 |
7 | if (up && !down) {
8 | return 'run';
9 | }
10 |
11 | if (down && !up) {
12 | return 'backpedal';
13 | }
14 |
15 | if (!right && left) {
16 | return isMouseLooking ? 'strafeLeft' : 'turnLeft';
17 | }
18 |
19 | if (!left && right) {
20 | return isMouseLooking ? 'strafeRight' : 'turnRight';
21 | }
22 |
23 | return 'idle';
24 | };
25 |
26 | export default function useCharacterState(inputs = {}, position, mixer) {
27 | const [characterState, setCharacterState] = useState({
28 | animation: 'idle',
29 | isJumping: false,
30 | inAir: false,
31 | isMoving: false,
32 | });
33 |
34 | const [jumpPressed, setJumpPressed] = useState(false);
35 | const [landed, setLanded] = useState();
36 |
37 | const { up, down, right, left, jump, isMouseLooking } = inputs;
38 | const { isJumping, inAir, isLanding } = characterState;
39 |
40 | useEffect(() => {
41 | setJumpPressed(jump);
42 | setLanded(false);
43 | }, [jump]);
44 |
45 | const rayFrom = [position[0], position[1], position[2]];
46 | const rayTo = [position[0], position[1] - 0.2, position[2]];
47 | useRaycastClosest(
48 | {
49 | from: rayFrom,
50 | to: rayTo,
51 | skipBackfaces: true,
52 | },
53 | (e) => {
54 | if (e.hasHit && !landed) {
55 | setLanded(true);
56 | }
57 | },
58 | [position]
59 | );
60 |
61 | useEffect(() => {
62 | if (inAir && landed) {
63 | setCharacterState((prevState) => ({
64 | ...prevState,
65 | inAir: false,
66 | animation: 'landing',
67 | isLanding: true,
68 | }));
69 | }
70 | }, [landed, inAir]);
71 |
72 | useEffect(() => {
73 | setCharacterState((prevState) => ({
74 | ...prevState,
75 | isMoving: up || down || left || right,
76 | }));
77 | }, [up, down, left, right]);
78 |
79 | useEffect(() => {
80 | if (isJumping || inAir) {
81 | return;
82 | }
83 | const newState = {
84 | animation: getAnimationFromUserInputs(inputs),
85 | };
86 |
87 | if (jump && !jumpPressed) {
88 | newState.animation = 'jump';
89 | newState.isJumping = true;
90 | }
91 |
92 | // let landing animation playout if we're still landing
93 | if (isLanding && newState.animation === 'idle') {
94 | return;
95 | }
96 |
97 | setCharacterState((prevState) => ({
98 | ...prevState,
99 | isLanding: false,
100 | ...newState,
101 | }));
102 | }, [up, down, left, right, jump, isMouseLooking, isJumping, inAir]);
103 |
104 | useEffect(() => {
105 | const checker = () => {
106 | setCharacterState((prevState) => ({
107 | ...prevState,
108 | isJumping: false,
109 | inAir: true,
110 | animation: 'inAir',
111 | }));
112 | };
113 | if (characterState.isJumping) {
114 | // play 200ms of jump animation then transition to inAir
115 | setTimeout(checker, 200);
116 | }
117 | return () => {
118 | clearTimeout(checker);
119 | };
120 | }, [characterState.isJumping]);
121 |
122 | useEffect(() => {
123 | if (!mixer) {
124 | return;
125 | }
126 | const onMixerFinish = () => {
127 | setCharacterState((prevState) => ({
128 | ...prevState,
129 | isJumping: false,
130 | inAir: false,
131 | isLanding: false,
132 | animation: 'idle',
133 | }));
134 | };
135 |
136 | mixer.addEventListener('finished', onMixerFinish);
137 |
138 | return () => {
139 | mixer.removeEventListener('finished', onMixerFinish);
140 | };
141 | }, [mixer]);
142 |
143 | return characterState;
144 | }
145 |
--------------------------------------------------------------------------------
/src/hooks/useInputEventManager.js:
--------------------------------------------------------------------------------
1 | import "default-passive-events";
2 | import { useState, useEffect } from "react";
3 |
4 | export default function useInputEventManager(container = window) {
5 | const [subscriptions, setSubscriptions] = useState({});
6 |
7 | const subscribe = (eventName, key, subscribeFn) => {
8 | setSubscriptions((prevState) => ({
9 | ...prevState,
10 | [eventName]: {
11 | ...prevState[eventName],
12 | [key]: subscribeFn,
13 | },
14 | }));
15 | };
16 |
17 | const unsubscribe = (eventName, key) => {
18 | setSubscriptions((prevState) => {
19 | delete prevState?.[eventName]?.[key];
20 | return prevState;
21 | });
22 | };
23 |
24 | const makeEventHandler = (eventName) => (event) => {
25 | const handlers = subscriptions[eventName] ?? {};
26 | const subscribers = Object.values(handlers);
27 | subscribers.forEach((sub) => sub(event));
28 | };
29 |
30 | const keydownHandler = makeEventHandler("keydown");
31 | const keyupHandler = makeEventHandler("keyup");
32 | const wheelHandler = makeEventHandler("wheel");
33 | const pointerdownHandler = makeEventHandler("pointerdown");
34 | const pointerupHandler = makeEventHandler("pointerup");
35 | const pointermoveHandler = makeEventHandler("pointermove");
36 | const pointercancelHandler = makeEventHandler("pointercancel");
37 | const pointerlockchangeHandler = makeEventHandler("pointerlockchange");
38 | const pointerlockerrorHandler = makeEventHandler("pointerlockerror");
39 | const contextmenuHandler = makeEventHandler("contextmenu");
40 |
41 | const setupEventListeners = () => {
42 | window.addEventListener("keydown", keydownHandler);
43 | window.addEventListener("keyup", keyupHandler);
44 |
45 | container.addEventListener("wheel", wheelHandler);
46 | container.addEventListener("pointerdown", pointerdownHandler);
47 | container.addEventListener("pointerup", pointerupHandler);
48 | container.addEventListener("pointermove", pointermoveHandler);
49 | container.addEventListener("pointercancel", pointercancelHandler);
50 | container.addEventListener("contextmenu", contextmenuHandler);
51 |
52 | document.addEventListener("pointerlockchange", pointerlockchangeHandler);
53 | document.addEventListener("pointerlockerror", pointerlockerrorHandler);
54 |
55 | return () => {
56 | window.removeEventListener("keydown", keydownHandler);
57 | window.removeEventListener("keyup", keyupHandler);
58 |
59 | container.removeEventListener("wheel", wheelHandler);
60 | container.removeEventListener("pointerdown", pointerdownHandler);
61 | container.removeEventListener("pointerup", pointerupHandler);
62 | container.removeEventListener("pointermove", pointermoveHandler);
63 | container.removeEventListener("pointercancel", pointercancelHandler);
64 | container.removeEventListener("contextmenu", contextmenuHandler);
65 |
66 | document.removeEventListener(
67 | "pointerlockchange",
68 | pointerlockchangeHandler
69 | );
70 | document.removeEventListener("pointerlockerror", pointerlockerrorHandler);
71 | };
72 | };
73 |
74 | useEffect(setupEventListeners, [subscriptions, container]);
75 |
76 | return {
77 | subscribe,
78 | unsubscribe,
79 | };
80 | }
81 |
--------------------------------------------------------------------------------
/src/hooks/useInputMovementRotation.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Based on code written by knav.eth for chainspace (https://somnet.chainrunners.xyz/chainspace)
3 | */
4 | import * as THREE from "three";
5 |
6 | /**
7 | * Finds an angle between two vectors
8 | * @param {THREE.Vector3} v1
9 | * @param {THREE.Vector3} v2
10 | */
11 | function getAngleBetweenVectors(v1, v2, dotThreshold = 0.0005) {
12 | let angle;
13 | const dot = v1.dot(v2);
14 |
15 | // If dot is close to 1, we'll round angle to zero
16 | if (dot > 1 - dotThreshold) {
17 | angle = 0;
18 | } else if (dot < -1 + dotThreshold) {
19 | // Dot too close to -1
20 | angle = Math.PI;
21 | } else {
22 | // Get angle difference in radians
23 | angle = Math.acos(dot);
24 | }
25 |
26 | return angle;
27 | }
28 |
29 | /**
30 | * Finds an angle between two vectors with a sign relative to normal vector
31 | */
32 | function getSignedAngleBetweenVectors(
33 | v1,
34 | v2,
35 | normal = new THREE.Vector3(0, 1, 0),
36 | dotThreshold = 0.0005
37 | ) {
38 | let angle = getAngleBetweenVectors(v1, v2, dotThreshold);
39 |
40 | // Get vector pointing up or down
41 | const cross = new THREE.Vector3().crossVectors(v1, v2);
42 | // Compare cross with normal to find out direction
43 | if (normal.dot(cross) < 0) {
44 | angle = -angle;
45 | }
46 |
47 | return angle;
48 | }
49 |
50 | function getRotationDirection({ left, right, isMouseLooking }) {
51 | let direction = 0;
52 | if (!isMouseLooking) {
53 | if (left) {
54 | direction = -1;
55 | }
56 | if (right) {
57 | direction = 1;
58 | }
59 | }
60 | return direction;
61 | }
62 |
63 | function getMovementDirection({ up, down, right, left, isMouseLooking }) {
64 | const positiveX = isMouseLooking && right ? -1 : 0;
65 | const negativeX = isMouseLooking && left ? 1 : 0;
66 | const positiveZ = up ? 1 : 0;
67 | const negativeZ = down ? -1 : 0;
68 |
69 | return new THREE.Vector3(
70 | positiveX + negativeX,
71 | 0,
72 | positiveZ + negativeZ
73 | ).normalize();
74 | }
75 |
76 | const FORWARD = new THREE.Vector3(0, 0, 1);
77 |
78 | function getModelRotation(inputs) {
79 | const { up, down, right, left, isMouseLooking } = inputs;
80 | const movementDirection = getMovementDirection(inputs);
81 | let modelRotation = 0;
82 |
83 | if ((up || down) && !(down && up) && (left || right) && isMouseLooking) {
84 | const rotationDirection = getRotationDirection(inputs);
85 | const movementAngle = getSignedAngleBetweenVectors(
86 | movementDirection,
87 | FORWARD
88 | );
89 |
90 | if (up) {
91 | modelRotation =
92 | rotationDirection === 0
93 | ? -movementAngle
94 | : (Math.PI / 8) * rotationDirection * -1;
95 | } else if (down) {
96 | if (rotationDirection === 0) {
97 | if (movementDirection.x > 0) {
98 | modelRotation = Math.PI - movementAngle;
99 | } else if (movementDirection.x < 0) {
100 | modelRotation = Math.PI - movementAngle;
101 | }
102 | } else {
103 | modelRotation = (Math.PI / 8) * rotationDirection * -1;
104 | }
105 | }
106 | }
107 |
108 | return modelRotation;
109 | }
110 |
111 | export default function useInputMovementRotation(inputs) {
112 | const direction = getRotationDirection(inputs);
113 | const rotation = getModelRotation(inputs);
114 | const movement = getMovementDirection(inputs);
115 | return { model: { direction, rotation }, movement };
116 | }
117 |
--------------------------------------------------------------------------------
/src/hooks/useKeyboardMouseMovement.js:
--------------------------------------------------------------------------------
1 | import { useState, useEffect } from "react";
2 |
3 | const defaultMap = {
4 | up: "w",
5 | down: "s",
6 | right: "d",
7 | left: "a",
8 | jump: " ",
9 | walk: "Shift",
10 | };
11 |
12 | const getInputFromKeyboard = (keyMap, keyPressed) => {
13 | let inputFound = "";
14 | Object.entries(keyMap).forEach(([k, v]) => {
15 | if (v === keyPressed) {
16 | inputFound = k;
17 | }
18 | });
19 | return inputFound;
20 | };
21 |
22 | export default function useKeyboardInput(inputManager, userKeyMap = {}) {
23 | const [isMouseLooking, setIsMouseLooking] = useState(false);
24 | const [inputsPressed, setInputsPressed] = useState({});
25 | const keyMap = {
26 | ...defaultMap,
27 | ...userKeyMap,
28 | };
29 |
30 | function downHandler({ key }) {
31 | const input = getInputFromKeyboard(keyMap, key);
32 | if (input) {
33 | setInputsPressed((prevState) => ({
34 | ...prevState,
35 | [input]: true,
36 | }));
37 | }
38 | }
39 |
40 | const upHandler = ({ key }) => {
41 | const input = getInputFromKeyboard(keyMap, key);
42 | if (input) {
43 | setInputsPressed((prevState) => ({
44 | ...prevState,
45 | [input]: false,
46 | }));
47 | }
48 | };
49 |
50 | function pointerdownHandler({ button }) {
51 | if (button === 2) {
52 | setIsMouseLooking(true);
53 | }
54 | }
55 |
56 | const pointerupHandler = ({ button }) => {
57 | if (button === 2) {
58 | setIsMouseLooking(false);
59 | }
60 | };
61 |
62 | useEffect(() => {
63 | inputManager.subscribe("keydown", "character-controls", downHandler);
64 | inputManager.subscribe("keyup", "character-controls", upHandler);
65 | inputManager.subscribe(
66 | "pointerdown",
67 | "character-controls",
68 | pointerdownHandler
69 | );
70 | inputManager.subscribe("pointerup", "character-controls", pointerupHandler);
71 |
72 | return () => {
73 | inputManager.unsubscribe("keydown", "character-controls");
74 | inputManager.unsubscribe("keyup", "character-controls");
75 | inputManager.unsubscribe("pointerdown", "character-controls");
76 | inputManager.unsubscribe("pointerup", "character-controls");
77 | };
78 | }, []);
79 |
80 | return { ...inputsPressed, isMouseLooking };
81 | }
82 |
--------------------------------------------------------------------------------
/src/hooks/useRay.js:
--------------------------------------------------------------------------------
1 | import { useState, useRef } from "react";
2 | import { useRaycastClosest } from "@react-three/cannon";
3 |
4 | export default function useRay({ rayVector, position, collisionFilterMask }) {
5 | const rayChecker = useRef(setTimeout);
6 | const from = [position[0], position[1], position[2]];
7 | const to = [rayVector.current.x, rayVector.current.y, rayVector.current.z];
8 |
9 | const [ray, setRay] = useState({});
10 | useRaycastClosest(
11 | {
12 | from,
13 | to,
14 | skipBackfaces: true,
15 | collisionFilterMask,
16 | },
17 | (e) => {
18 | clearTimeout(rayChecker.current);
19 | setRay({
20 | hasHit: e.hasHit,
21 | distance: e.distance,
22 | });
23 | // this callback only fires constantly on collision so this
24 | // timeout resets state once we've stopped colliding
25 | rayChecker.current = setTimeout(() => {
26 | setRay({});
27 | }, 100);
28 | },
29 | [from, to]
30 | );
31 |
32 | return ray;
33 | }
34 |
--------------------------------------------------------------------------------
/src/hooks/useThirdPersonAnimations.js:
--------------------------------------------------------------------------------
1 | import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
2 | import { FBXLoader } from 'three/examples/jsm/loaders/FBXLoader';
3 | import { useEffect, useState, useRef, useMemo } from 'react';
4 | import { AnimationMixer } from 'three';
5 | import { useFrame } from '@react-three/fiber';
6 |
7 | const FBX_LOADER = new FBXLoader();
8 | const GLTF_LOADER = new GLTFLoader();
9 |
10 | async function asyncForEach(array, callback) {
11 | for (let index = 0; index < array.length; index++) {
12 | await callback(array[index], index, array);
13 | }
14 | };
15 |
16 | function loadModelSync(url, loader) {
17 | return new Promise((resolve, reject) => {
18 | loader.load(url, (data) => resolve(data), null, reject);
19 | });
20 | }
21 |
22 | function useThirdPersonAnimations(
23 | characterObj,
24 | animationPaths = {},
25 | onLoad = () => {}
26 | ) {
27 | const ref = useRef();
28 | const [clips, setClips] = useState([]);
29 | const [actualRef, setRef] = useState(ref);
30 | const [mixer, setMixer] = useState(new AnimationMixer(undefined));
31 | const lazyActions = useRef({});
32 | const [animations, setAnimations] = useState({});
33 |
34 | // set character obj + mixer for character
35 | useEffect(() => {
36 | if (characterObj) {
37 | setRef({ current: characterObj });
38 | setMixer(new AnimationMixer(undefined));
39 | }
40 | }, [characterObj.name]);
41 |
42 | // load animations async initially
43 | useEffect(() => {
44 | const loadAnimations = async () => {
45 | const newAnimations = {};
46 | const keys = [
47 | 'idle',
48 | 'walk',
49 | 'run',
50 | 'jump',
51 | 'landing',
52 | 'inAir',
53 | 'backpedal',
54 | 'turnLeft',
55 | 'turnRight',
56 | 'strafeLeft',
57 | 'strafeRight',
58 | ];
59 | await asyncForEach(keys, async (key) => {
60 | const fileExt = animationPaths[key].split('.').pop();
61 | const loader = fileExt === 'fbx' ? FBX_LOADER : GLTF_LOADER;
62 | const model = await loadModelSync(animationPaths[key], loader);
63 | newAnimations[key] = model;
64 | });
65 | setAnimations(newAnimations);
66 | onLoad();
67 | };
68 |
69 | loadAnimations();
70 | }, []);
71 |
72 | // set clips once animations are loaded
73 | useEffect(() => {
74 | const clipsToSet = [];
75 |
76 | Object.keys(animations).forEach((name) => {
77 | if (animations[name]?.animations?.length) {
78 | animations[name].animations[0].name = name;
79 | clipsToSet.push(animations[name].animations[0]);
80 | }
81 | });
82 |
83 | if (clips.length < clipsToSet.length) {
84 | setClips(clipsToSet);
85 | }
86 | }, [animations]);
87 |
88 | const api = useMemo(() => {
89 | if (!mixer || !clips.length) {
90 | return {
91 | actions: {},
92 | };
93 | }
94 | const actions = {};
95 | clips.forEach((clip) =>
96 | Object.defineProperty(actions, clip.name, {
97 | enumerable: true,
98 | get() {
99 | if (actualRef.current) {
100 | lazyActions.current[clip.name] = mixer.clipAction(
101 | clip,
102 | actualRef.current
103 | );
104 |
105 | const clampers = ['jump', 'landing'];
106 | if (clampers.includes(clip.name)) {
107 | lazyActions.current[clip.name].setLoop(2200); // 2200 = THREE.LoopOnce
108 | lazyActions.current[clip.name].clampWhenFinished = true;
109 | }
110 |
111 | return lazyActions.current[clip.name];
112 | }
113 |
114 | return null;
115 | },
116 | })
117 | );
118 | return {
119 | ref: actualRef,
120 | clips,
121 | actions,
122 | names: clips.map((c) => c.name),
123 | mixer,
124 | };
125 | }, [clips, characterObj.name, mixer]);
126 |
127 | useEffect(() => {
128 | const currentRoot = actualRef.current;
129 | return () => {
130 | // Clean up only when clips change, wipe out lazy actions and uncache clips
131 | lazyActions.current = {};
132 | Object.values(api.actions).forEach((action) => {
133 | if (currentRoot) {
134 | mixer.uncacheAction(action, currentRoot);
135 | }
136 | });
137 | };
138 | }, [clips]);
139 |
140 | useFrame((_, delta) => {
141 | mixer.update(delta);
142 | });
143 |
144 | return api;
145 | }
146 |
147 | export default useThirdPersonAnimations;
148 |
--------------------------------------------------------------------------------
/src/hooks/useThirdPersonCameraControls.js:
--------------------------------------------------------------------------------
1 | import * as THREE from 'three';
2 | import { useState, useEffect } from 'react';
3 |
4 | /*
5 | * Based on code written by knav.eth for chainspace (https://somnet.chainrunners.xyz/chainspace)
6 | */
7 | const CameraControlOperation = {
8 | NONE: -1,
9 | ROTATE: 0,
10 | TOUCH_ROTATE: 3,
11 | TOUCH_ZOOM_ROTATE: 6,
12 | };
13 |
14 | const ROTATION_ANGLE = new THREE.Vector3(0, 1, 0);
15 |
16 | class CameraState {
17 | operation = CameraControlOperation.NONE;
18 | pointers = [];
19 | pointerPositions = {};
20 |
21 | reset() {
22 | this.operation = CameraControlOperation.NONE;
23 | this.pointers = [];
24 | this.pointerPositions = {};
25 | }
26 | }
27 |
28 | class ThirdPersonCameraControls {
29 | enabled = true;
30 | // How far you can zoom in and out ( PerspectiveCamera only )
31 | minDistance = 0;
32 | maxDistance = Infinity;
33 |
34 | // How far you can orbit vertically, upper and lower limits.
35 | // Range is 0 to Math.PI radians.
36 | minPolarAngle = 0;
37 | maxPolarAngle = Math.PI;
38 |
39 | enableZoom = true;
40 | zoomSpeed = 1.75;
41 |
42 | enableRotate = true;
43 | rotateSpeed = 1.0;
44 |
45 | // "target" sets the location of focus, where the object orbits around
46 | targetOffset = new THREE.Vector3(0, 0, 0);
47 |
48 | spherical = new THREE.Spherical(3.5, Math.PI / 3, Math.PI);
49 |
50 | rotateStart = new THREE.Vector2();
51 | rotateEnd = new THREE.Vector2();
52 | rotateDelta = new THREE.Vector2();
53 |
54 | zoomStart = new THREE.Vector2();
55 | zoomEnd = new THREE.Vector2();
56 | zoomDelta = new THREE.Vector2();
57 |
58 | outerCameraContainer = new THREE.Object3D();
59 |
60 | constructor(
61 | camera,
62 | domElement,
63 | target,
64 | inputManager,
65 | options = {},
66 | cameraContainer
67 | ) {
68 | this.camera = camera;
69 | this.cameraState = new CameraState();
70 | this.cameraContainer = cameraContainer;
71 | this.domElement = domElement;
72 |
73 | this.input = {};
74 | const k = 'camera';
75 | inputManager.subscribe('wheel', k, this.handleMouseWheel.bind(this));
76 | inputManager.subscribe(
77 | 'pointerlockchange',
78 | k,
79 | this.onPointerLockChange.bind(this)
80 | );
81 | inputManager.subscribe('pointerdown', k, this.onPointerDown.bind(this));
82 | inputManager.subscribe('pointerup', k, this.onPointerUp.bind(this));
83 | inputManager.subscribe('pointermove', k, this.onPointerMove.bind(this));
84 | inputManager.subscribe('pointercancel', k, this.onPointerCancel.bind(this));
85 | inputManager.subscribe('pointerlockerror', k, (e) =>
86 | console.error('POINTERLOCK ERROR ', e)
87 | );
88 | inputManager.subscribe('contextmenu', k, this.onContextMenu.bind(this));
89 | this.cameraCollisionOn = options?.cameraCollisionOn;
90 | this.targetOffset.y = options?.yOffset ?? 1.6;
91 | this.outerCameraContainer.position.copy(this.targetOffset);
92 | this.outerCameraContainer.add(this.cameraContainer);
93 |
94 | this.target = target;
95 | this.target.add(this.outerCameraContainer);
96 | }
97 |
98 | _cameraPos = new THREE.Vector3();
99 | _raycastTargetVector = new THREE.Vector3();
100 |
101 | getCameraPosition(rayResult) {
102 | this.cameraContainer.position.setFromSphericalCoords(
103 | this.spherical.radius,
104 | this.spherical.phi,
105 | this.spherical.theta
106 | );
107 |
108 | if (rayResult.hasHit && this.cameraCollisionOn) {
109 | this.cameraContainer.position.setFromSphericalCoords(
110 | rayResult.distance - 0.1,
111 | this.spherical.phi,
112 | this.spherical.theta
113 | );
114 | }
115 |
116 | this.cameraContainer.getWorldPosition(this._cameraPos);
117 | return this._cameraPos;
118 | }
119 |
120 | _workingVec = new THREE.Vector3();
121 |
122 | getCameraLookVec() {
123 | this.target.getWorldPosition(this._workingVec).add(this.targetOffset);
124 | return this._workingVec;
125 | }
126 |
127 | _workingQuat = new THREE.Quaternion();
128 |
129 | update(rayResult) {
130 | if (this.input.isMouseLooking) {
131 | this._workingQuat.setFromAxisAngle(
132 | ROTATION_ANGLE,
133 | this.spherical.theta - Math.PI
134 | );
135 |
136 | this.target.quaternion.multiply(this._workingQuat);
137 | this.spherical.theta = Math.PI;
138 | }
139 |
140 | // restrict phi to be between desired limits
141 | this.spherical.phi = Math.max(
142 | this.minPolarAngle,
143 | Math.min(this.maxPolarAngle, this.spherical.phi)
144 | );
145 | this.spherical.makeSafe();
146 |
147 | // restrict radius to be between desired limits
148 | this.spherical.radius = Math.max(
149 | this.minDistance,
150 | Math.min(this.maxDistance, this.spherical.radius)
151 | );
152 |
153 | // copy maths to actual three.js camera
154 | this.camera.position.copy(this.getCameraPosition(rayResult));
155 | this.camera.lookAt(this.getCameraLookVec());
156 | }
157 |
158 | getZoomScale() {
159 | return 0.95 ** this.zoomSpeed;
160 | }
161 |
162 | rotateLeft(angle) {
163 | this.spherical.theta -= angle;
164 | }
165 |
166 | rotateUp(angle) {
167 | this.spherical.phi -= angle;
168 | }
169 |
170 | handleApplyRotate(speedMultiplier = 1) {
171 | this.rotateDelta
172 | .subVectors(this.rotateEnd, this.rotateStart)
173 | .multiplyScalar(this.rotateSpeed * speedMultiplier);
174 |
175 | const element = this.domElement;
176 |
177 | this.rotateLeft((2 * Math.PI * this.rotateDelta.x) / element.clientHeight); // yes, height
178 |
179 | this.rotateUp((2 * Math.PI * this.rotateDelta.y) / element.clientHeight);
180 |
181 | this.rotateStart.copy(this.rotateEnd);
182 | }
183 |
184 | zoomOut(zoomScale) {
185 | this.spherical.radius /= zoomScale;
186 | }
187 |
188 | zoomIn(zoomScale) {
189 | this.spherical.radius *= zoomScale;
190 | }
191 |
192 | // Event Handlers
193 | handleMouseDownRotate(event) {
194 | this.rotateEnd.set(event.clientX, event.clientY);
195 | this.rotateStart.set(event.clientX, event.clientY);
196 | }
197 |
198 | handleMouseMoveRotate(event) {
199 | if (document.pointerLockElement === this.domElement) {
200 | this.rotateEnd.x += event.movementX * 0.25;
201 | this.rotateEnd.y += event.movementY * 0.25 * 0.8;
202 | } else {
203 | this.domElement.requestPointerLock();
204 | this.domElement.style.cursor = 'none';
205 | this.rotateEnd.set(event.clientX, event.clientY);
206 | }
207 | this.handleApplyRotate();
208 | }
209 |
210 | handleMouseWheel(event) {
211 | if (event.deltaY < 0) {
212 | this.zoomIn(this.getZoomScale());
213 | } else if (event.deltaY > 0) {
214 | this.zoomOut(this.getZoomScale());
215 | }
216 | }
217 |
218 | handleTouchStartRotate() {
219 | if (this.cameraState.pointers.length === 1) {
220 | this.rotateStart.set(
221 | this.cameraState.pointers[0].pageX,
222 | this.cameraState.pointers[0].pageY
223 | );
224 | } else {
225 | const x =
226 | 0.5 *
227 | (this.cameraState.pointers[0].pageX +
228 | this.cameraState.pointers[1].pageX);
229 | const y =
230 | 0.5 *
231 | (this.cameraState.pointers[0].pageY +
232 | this.cameraState.pointers[1].pageY);
233 |
234 | this.rotateStart.set(x, y);
235 | }
236 | }
237 |
238 | handleTouchStartZoom() {
239 | const dx =
240 | this.cameraState.pointers[0].pageX - this.cameraState.pointers[1].pageX;
241 | const dy =
242 | this.cameraState.pointers[0].pageY - this.cameraState.pointers[1].pageY;
243 |
244 | const distance = Math.sqrt(dx * dx + dy * dy);
245 |
246 | this.zoomStart.set(0, distance);
247 | }
248 |
249 | handleTouchStartZoomRotate() {
250 | if (this.enableZoom) this.handleTouchStartZoom();
251 |
252 | if (this.enableRotate) this.handleTouchStartRotate();
253 | }
254 |
255 | handleTouchMoveRotate(event) {
256 | if (this.cameraState.pointers.length === 1) {
257 | this.rotateEnd.set(event.pageX, event.pageY);
258 | } else {
259 | const position = this.getSecondPointerPosition(event);
260 |
261 | const x = 0.5 * (event.pageX + position.x);
262 | const y = 0.5 * (event.pageY + position.y);
263 |
264 | this.rotateEnd.set(x, y);
265 | }
266 |
267 | this.handleApplyRotate(1.3);
268 | }
269 |
270 | handleTouchMoveZoom(event) {
271 | const position = this.getSecondPointerPosition(event);
272 |
273 | const dx = event.pageX - position.x;
274 | const dy = event.pageY - position.y;
275 |
276 | const distance = Math.sqrt(dx * dx + dy * dy);
277 |
278 | this.zoomEnd.set(0, distance);
279 |
280 | this.zoomDelta.set(
281 | 0,
282 | (this.zoomEnd.y / this.zoomStart.y) ** this.zoomSpeed
283 | );
284 |
285 | this.zoomOut(this.zoomDelta.y);
286 |
287 | this.zoomStart.copy(this.zoomEnd);
288 | }
289 |
290 | handleTouchMoveZoomRotate(event) {
291 | if (this.enableZoom) this.handleTouchMoveZoom(event);
292 | if (this.enableRotate) this.handleTouchMoveRotate(event);
293 | }
294 |
295 | // Event Controllers
296 | onPointerDown(event) {
297 | if (!this.enabled) return;
298 |
299 | if (this.cameraState.pointers.length === 0) {
300 | this.domElement.setPointerCapture(event.pointerId);
301 | }
302 |
303 | this.addPointer(event);
304 | if (event.pointerType === 'touch') {
305 | this.onTouchStart(event);
306 | } else {
307 | this.onMouseDown(event);
308 | }
309 | }
310 |
311 | onPointerMove(event) {
312 | this.lastCheck = Date.now();
313 | if (!this.enabled) return;
314 | if (!this.input.isMouseLocked && !this.cameraState.pointers.length) return;
315 | if (
316 | !this.cameraState.pointers.find((e) => e.pointerId === event.pointerId)
317 | ) {
318 | return;
319 | }
320 |
321 | if (event.pointerType === 'touch') {
322 | this.onTouchMove(event);
323 | } else {
324 | this.onMouseMove(event);
325 | }
326 | }
327 |
328 | onPointerUp(event) {
329 | if (event.pointerType === 'touch') {
330 | this.onTouchEnd();
331 | } else {
332 | this.onMouseUp();
333 | }
334 |
335 | this.removePointer(event);
336 |
337 | if (
338 | this.cameraState.pointers.length === 0 &&
339 | event.pointerType === 'touch'
340 | ) {
341 | this.domElement.releasePointerCapture(event.pointerId);
342 | }
343 | }
344 |
345 | // Touch
346 | onTouchStart(event) {
347 | this.trackPointer(event);
348 |
349 | switch (this.cameraState.pointers.length) {
350 | case 1:
351 | if (!this.enableRotate) return;
352 |
353 | this.handleTouchStartRotate();
354 | this.input.isMouseLooking = true;
355 | this.cameraState.operation = CameraControlOperation.TOUCH_ROTATE;
356 | break;
357 |
358 | case 2:
359 | if (!this.enableZoom && !this.enableRotate) return;
360 |
361 | this.handleTouchStartZoomRotate();
362 | this.input.isMouseLooking = true;
363 | this.cameraState.operation = CameraControlOperation.TOUCH_ZOOM_ROTATE;
364 | break;
365 |
366 | default:
367 | this.cameraState.operation = CameraControlOperation.NONE;
368 | }
369 | }
370 |
371 | onTouchMove(event) {
372 | this.trackPointer(event);
373 |
374 | switch (this.cameraState.operation) {
375 | case CameraControlOperation.TOUCH_ROTATE:
376 | if (!this.enableRotate) return;
377 |
378 | this.handleTouchMoveRotate(event);
379 | break;
380 |
381 | case CameraControlOperation.TOUCH_ZOOM_ROTATE:
382 | if (!this.enableZoom && !this.enableRotate) return;
383 |
384 | this.handleTouchMoveZoomRotate(event);
385 | break;
386 |
387 | default:
388 | this.cameraState.operation = CameraControlOperation.NONE;
389 | }
390 | }
391 |
392 | onTouchEnd() {
393 | this.cameraState.operation = CameraControlOperation.NONE;
394 | }
395 |
396 | // Mouse
397 | onPointerLockChange() {
398 | // do initial check to see if mouse is locked
399 | this.input.isMouseLocked = document.pointerLockElement === this.domElement;
400 | if (!this.input.isMouseLocked) {
401 | // wait 100ms and then check again as sometimes document.pointerLockElement
402 | // is null after doing a document.requestPointerLock()
403 | setTimeout(() => {
404 | this.input.isMouseLocked =
405 | document.pointerLockElement === this.domElement;
406 | if (!this.input.isMouseLocked) {
407 | this.input.isMouseLooking = false;
408 | this.cameraState.operation = CameraControlOperation.NONE;
409 | }
410 | }, 100);
411 | }
412 | }
413 |
414 | onMouseDown(event) {
415 | switch (event.button) {
416 | case 0:
417 | if (!this.enableRotate) return;
418 |
419 | this.handleMouseDownRotate(event);
420 | this.cameraState.operation = CameraControlOperation.ROTATE;
421 | break;
422 | case 1:
423 | this.cameraState.operation = CameraControlOperation.NONE;
424 | break;
425 | case 2:
426 | if (!this.enableRotate) return;
427 | this.input.isMouseLooking = true;
428 | this.rightClickTime = Date.now();
429 | this.handleMouseDownRotate(event);
430 | this.cameraState.operation = CameraControlOperation.ROTATE;
431 | break;
432 | default:
433 | this.cameraState.operation = CameraControlOperation.NONE;
434 | }
435 | }
436 |
437 | onMouseMove(event) {
438 | if (!this.enabled) return;
439 |
440 | if (this.cameraState.operation === CameraControlOperation.ROTATE) {
441 | if (!this.enableRotate) return;
442 | this.handleMouseMoveRotate(event);
443 | }
444 | }
445 |
446 | onMouseUp() {
447 | this.domElement.style.cursor = 'initial';
448 | document.exitPointerLock();
449 | this.input.isMouseLooking = false;
450 | }
451 |
452 | onMouseWheel(event) {
453 | if (
454 | !this.enabled ||
455 | !this.enableZoom ||
456 | (this.cameraState.operation !== CameraControlOperation.NONE &&
457 | this.cameraState.operation !== CameraControlOperation.ROTATE)
458 | ) {
459 | return;
460 | }
461 | this.handleMouseWheel(event);
462 | }
463 |
464 | // Pointer Utils
465 | getSecondPointerPosition(event) {
466 | const pointer =
467 | event.pointerId === this.cameraState.pointers[0].pointerId
468 | ? this.cameraState.pointers[1]
469 | : this.cameraState.pointers[0];
470 |
471 | return this.cameraState.pointerPositions[pointer.pointerId];
472 | }
473 |
474 | addPointer(event) {
475 | this.cameraState.pointers.push(event);
476 | }
477 |
478 | removePointer(event) {
479 | delete this.cameraState.pointerPositions[event.pointerId];
480 |
481 | for (let i = 0; i < this.cameraState.pointers.length; i++) {
482 | if (this.cameraState.pointers[i].pointerId === event.pointerId) {
483 | this.cameraState.pointers.splice(i, 1);
484 | return;
485 | }
486 | }
487 | }
488 |
489 | trackPointer(event) {
490 | let position = this.cameraState.pointerPositions[event.pointerId];
491 |
492 | if (position === undefined) {
493 | position = new THREE.Vector2();
494 | this.cameraState.pointerPositions[event.pointerId] = position;
495 | }
496 |
497 | position.set(event.pageX, event.pageY);
498 | }
499 |
500 | onPointerCancel(event) {
501 | this.removePointer(event);
502 | }
503 |
504 | onContextMenu(event) {
505 | if (!this.enabled) return;
506 | event.preventDefault();
507 | }
508 |
509 | reset() {
510 | this.cameraState.reset();
511 | this.domElement.style.cursor = 'initial';
512 | try {
513 | document.exitPointerLock();
514 | } catch (e) {
515 | // lol
516 | }
517 | }
518 |
519 | dispose() {
520 | // remove event listeners here
521 | }
522 | }
523 |
524 | export default function useThirdPersonCameraControls({
525 | camera,
526 | domElement,
527 | target,
528 | inputManager,
529 | cameraOptions,
530 | cameraContainer,
531 | }) {
532 | const [controls, setControls] = useState(null);
533 |
534 | useEffect(() => {
535 | if (!target) {
536 | return;
537 | }
538 | const newControls = new ThirdPersonCameraControls(
539 | camera,
540 | domElement,
541 | target,
542 | inputManager,
543 | { yOffset: cameraOptions.yOffset || 0 },
544 | cameraContainer.current
545 | );
546 |
547 | newControls.minDistance = cameraOptions?.minDistance || 404;
548 | newControls.maxDistance = cameraOptions?.maxDistance || 808;
549 | setControls(newControls);
550 | return () => {
551 | newControls.dispose();
552 | };
553 | }, [camera, domElement, target]);
554 |
555 | return controls;
556 | }
557 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import { Suspense, useEffect, useRef, useState } from 'react';
2 | import * as THREE from 'three';
3 | import { useFrame, useThree } from '@react-three/fiber';
4 | import {
5 | useThirdPersonAnimations,
6 | useThirdPersonCameraControls,
7 | useInputEventManager,
8 | useKeyboardMouseMovement,
9 | useInputMovementRotation,
10 | useCharacterState,
11 | useCapsuleCollider,
12 | useRay,
13 | } from './hooks';
14 |
15 | const ThirdPersonCharacterControls = ({
16 | cameraOptions = {},
17 | characterObj,
18 | characterProps = {},
19 | animationPaths = {},
20 | onLoad,
21 | }) => {
22 | const {
23 | camera,
24 | gl: { domElement },
25 | } = useThree();
26 | // set up refs that influence character and camera position
27 | const collider = useCapsuleCollider(characterProps.radius);
28 | const [position, setPosition] = useState([0, 0, 0]);
29 | const modelRef = useRef();
30 | const cameraContainer = useRef(new THREE.Object3D());
31 | const rayVector = useRef(new THREE.Vector3());
32 | const ray = useRay({ position, rayVector, ...cameraOptions });
33 |
34 | // get character state based on user inputs + collider position + animations
35 | const inputManager = useInputEventManager(domElement);
36 | const inputs = useKeyboardMouseMovement(inputManager);
37 | const controls = useThirdPersonCameraControls({
38 | camera,
39 | domElement,
40 | target: modelRef.current,
41 | inputManager,
42 | cameraOptions,
43 | cameraContainer,
44 | });
45 | const { actions, mixer } = useThirdPersonAnimations(
46 | characterObj,
47 | animationPaths,
48 | onLoad
49 | );
50 | const { animation, isMoving } = useCharacterState(inputs, position, mixer);
51 |
52 | // subscribe to collider velocity/position changes
53 | const charVelocity = characterProps.velocity ?? 4;
54 | const velocity = useRef([0, 0, 0]);
55 | useEffect(() => {
56 | collider.velocity.subscribe((v) => {
57 | velocity.current = v;
58 | });
59 |
60 | collider.position.subscribe((p) => {
61 | // position is set on collider so we copy it to model
62 | modelRef.current?.position.set(...p);
63 | // setState with position to useCharacterState
64 | setPosition(p);
65 | });
66 | }, []);
67 |
68 | useFrame(() => {
69 | let newRotation = new THREE.Euler();
70 | let xVelocity = 0;
71 | let zVelocity = 0;
72 | const { quaternion } = modelRef.current;
73 |
74 | if (isMoving) {
75 | const { model, movement } = useInputMovementRotation(inputs);
76 |
77 | // first rotate the model group
78 | modelRef.current.rotateY(model.direction * -0.05);
79 | newRotation = characterObj.rotation.clone();
80 | newRotation.y = model.rotation;
81 |
82 | const mtx = new THREE.Matrix4().makeRotationFromQuaternion(quaternion);
83 | movement.applyMatrix4(mtx);
84 |
85 | // then apply velocity to collider influenced by model groups rotation
86 | const baseVelocity = inputs.down ? charVelocity / 2 : charVelocity;
87 | xVelocity = movement.x * baseVelocity;
88 | zVelocity = movement.z * baseVelocity;
89 | }
90 |
91 | collider.velocity.set(xVelocity, velocity.current[1], zVelocity);
92 |
93 | // after applying x/z velocity, apply y velocity if user has jumped while grounded
94 | const isGrounded = Math.abs(velocity.current[1].toFixed(2)) === 0;
95 | if (animation === 'jump' && isGrounded) {
96 | collider.velocity.set(velocity.current[0], 8, velocity.current[2]);
97 | }
98 |
99 | // rotate character model inside model group
100 | const newQuat = new THREE.Quaternion().setFromEuler(newRotation);
101 | characterObj.quaternion.slerp(newQuat, 0.1);
102 |
103 | // quaternion is set on model group so we copy it to collider
104 | collider.quaternion.copy(quaternion);
105 | // check camera raycast collision and pass that to controls to
106 | cameraContainer.current.getWorldPosition(rayVector.current);
107 | controls?.update(ray);
108 | });
109 |
110 | // Transition to new animation when loaded
111 | useEffect(() => {
112 | actions?.[animation]?.reset().fadeIn(0.2).play();
113 | return () => {
114 | actions?.[animation]?.fadeOut(0.2);
115 | };
116 | }, [animation, actions]);
117 |
118 | return (
119 |
120 | null}>
121 |
122 |
123 |
124 | );
125 | };
126 |
127 | export default ThirdPersonCharacterControls;
128 |
--------------------------------------------------------------------------------
/yarn.lock:
--------------------------------------------------------------------------------
1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
2 | # yarn lockfile v1
3 |
4 |
5 | "@ampproject/remapping@^2.1.0":
6 | version "2.2.0"
7 | resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.2.0.tgz#56c133824780de3174aed5ab6834f3026790154d"
8 | integrity sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==
9 | dependencies:
10 | "@jridgewell/gen-mapping" "^0.1.0"
11 | "@jridgewell/trace-mapping" "^0.3.9"
12 |
13 | "@babel/code-frame@^7.18.6":
14 | version "7.18.6"
15 | resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.18.6.tgz#3b25d38c89600baa2dcc219edfa88a74eb2c427a"
16 | integrity sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==
17 | dependencies:
18 | "@babel/highlight" "^7.18.6"
19 |
20 | "@babel/compat-data@^7.17.7", "@babel/compat-data@^7.19.3", "@babel/compat-data@^7.19.4":
21 | version "7.19.4"
22 | resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.19.4.tgz#95c86de137bf0317f3a570e1b6e996b427299747"
23 | integrity sha512-CHIGpJcUQ5lU9KrPHTjBMhVwQG6CQjxfg36fGXl3qk/Gik1WwWachaXFuo0uCWJT/mStOKtcbFJCaVLihC1CMw==
24 |
25 | "@babel/core@^7.17.8":
26 | version "7.19.3"
27 | resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.19.3.tgz#2519f62a51458f43b682d61583c3810e7dcee64c"
28 | integrity sha512-WneDJxdsjEvyKtXKsaBGbDeiyOjR5vYq4HcShxnIbG0qixpoHjI3MqeZM9NDvsojNCEBItQE4juOo/bU6e72gQ==
29 | dependencies:
30 | "@ampproject/remapping" "^2.1.0"
31 | "@babel/code-frame" "^7.18.6"
32 | "@babel/generator" "^7.19.3"
33 | "@babel/helper-compilation-targets" "^7.19.3"
34 | "@babel/helper-module-transforms" "^7.19.0"
35 | "@babel/helpers" "^7.19.0"
36 | "@babel/parser" "^7.19.3"
37 | "@babel/template" "^7.18.10"
38 | "@babel/traverse" "^7.19.3"
39 | "@babel/types" "^7.19.3"
40 | convert-source-map "^1.7.0"
41 | debug "^4.1.0"
42 | gensync "^1.0.0-beta.2"
43 | json5 "^2.2.1"
44 | semver "^6.3.0"
45 |
46 | "@babel/generator@^7.19.3", "@babel/generator@^7.19.4":
47 | version "7.19.4"
48 | resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.19.4.tgz#60050cf3f0a593d7b2471b4be4f62a56b949237f"
49 | integrity sha512-5T2lY5vXqS+5UEit/5TwcIUeCnwgCljcF8IQRT6XRQPBrvLeq5V8W+URv+GvwoF3FP8tkhp++evVyDzkDGzNmA==
50 | dependencies:
51 | "@babel/types" "^7.19.4"
52 | "@jridgewell/gen-mapping" "^0.3.2"
53 | jsesc "^2.5.1"
54 |
55 | "@babel/helper-annotate-as-pure@^7.18.6":
56 | version "7.18.6"
57 | resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz#eaa49f6f80d5a33f9a5dd2276e6d6e451be0a6bb"
58 | integrity sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA==
59 | dependencies:
60 | "@babel/types" "^7.18.6"
61 |
62 | "@babel/helper-builder-binary-assignment-operator-visitor@^7.18.6":
63 | version "7.18.9"
64 | resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.18.9.tgz#acd4edfd7a566d1d51ea975dff38fd52906981bb"
65 | integrity sha512-yFQ0YCHoIqarl8BCRwBL8ulYUaZpz3bNsA7oFepAzee+8/+ImtADXNOmO5vJvsPff3qi+hvpkY/NYBTrBQgdNw==
66 | dependencies:
67 | "@babel/helper-explode-assignable-expression" "^7.18.6"
68 | "@babel/types" "^7.18.9"
69 |
70 | "@babel/helper-compilation-targets@^7.17.7", "@babel/helper-compilation-targets@^7.18.9", "@babel/helper-compilation-targets@^7.19.0", "@babel/helper-compilation-targets@^7.19.3":
71 | version "7.19.3"
72 | resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.19.3.tgz#a10a04588125675d7c7ae299af86fa1b2ee038ca"
73 | integrity sha512-65ESqLGyGmLvgR0mst5AdW1FkNlj9rQsCKduzEoEPhBCDFGXvz2jW6bXFG6i0/MrV2s7hhXjjb2yAzcPuQlLwg==
74 | dependencies:
75 | "@babel/compat-data" "^7.19.3"
76 | "@babel/helper-validator-option" "^7.18.6"
77 | browserslist "^4.21.3"
78 | semver "^6.3.0"
79 |
80 | "@babel/helper-create-class-features-plugin@^7.18.6":
81 | version "7.19.0"
82 | resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.19.0.tgz#bfd6904620df4e46470bae4850d66be1054c404b"
83 | integrity sha512-NRz8DwF4jT3UfrmUoZjd0Uph9HQnP30t7Ash+weACcyNkiYTywpIjDBgReJMKgr+n86sn2nPVVmJ28Dm053Kqw==
84 | dependencies:
85 | "@babel/helper-annotate-as-pure" "^7.18.6"
86 | "@babel/helper-environment-visitor" "^7.18.9"
87 | "@babel/helper-function-name" "^7.19.0"
88 | "@babel/helper-member-expression-to-functions" "^7.18.9"
89 | "@babel/helper-optimise-call-expression" "^7.18.6"
90 | "@babel/helper-replace-supers" "^7.18.9"
91 | "@babel/helper-split-export-declaration" "^7.18.6"
92 |
93 | "@babel/helper-create-regexp-features-plugin@^7.18.6", "@babel/helper-create-regexp-features-plugin@^7.19.0":
94 | version "7.19.0"
95 | resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.19.0.tgz#7976aca61c0984202baca73d84e2337a5424a41b"
96 | integrity sha512-htnV+mHX32DF81amCDrwIDr8nrp1PTm+3wfBN9/v8QJOLEioOCOG7qNyq0nHeFiWbT3Eb7gsPwEmV64UCQ1jzw==
97 | dependencies:
98 | "@babel/helper-annotate-as-pure" "^7.18.6"
99 | regexpu-core "^5.1.0"
100 |
101 | "@babel/helper-define-polyfill-provider@^0.3.3":
102 | version "0.3.3"
103 | resolved "https://registry.yarnpkg.com/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.3.tgz#8612e55be5d51f0cd1f36b4a5a83924e89884b7a"
104 | integrity sha512-z5aQKU4IzbqCC1XH0nAqfsFLMVSo22SBKUc0BxGrLkolTdPTructy0ToNnlO2zA4j9Q/7pjMZf0DSY+DSTYzww==
105 | dependencies:
106 | "@babel/helper-compilation-targets" "^7.17.7"
107 | "@babel/helper-plugin-utils" "^7.16.7"
108 | debug "^4.1.1"
109 | lodash.debounce "^4.0.8"
110 | resolve "^1.14.2"
111 | semver "^6.1.2"
112 |
113 | "@babel/helper-environment-visitor@^7.18.9":
114 | version "7.18.9"
115 | resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz#0c0cee9b35d2ca190478756865bb3528422f51be"
116 | integrity sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==
117 |
118 | "@babel/helper-explode-assignable-expression@^7.18.6":
119 | version "7.18.6"
120 | resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.18.6.tgz#41f8228ef0a6f1a036b8dfdfec7ce94f9a6bc096"
121 | integrity sha512-eyAYAsQmB80jNfg4baAtLeWAQHfHFiR483rzFK+BhETlGZaQC9bsfrugfXDCbRHLQbIA7U5NxhhOxN7p/dWIcg==
122 | dependencies:
123 | "@babel/types" "^7.18.6"
124 |
125 | "@babel/helper-function-name@^7.18.9", "@babel/helper-function-name@^7.19.0":
126 | version "7.19.0"
127 | resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz#941574ed5390682e872e52d3f38ce9d1bef4648c"
128 | integrity sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==
129 | dependencies:
130 | "@babel/template" "^7.18.10"
131 | "@babel/types" "^7.19.0"
132 |
133 | "@babel/helper-hoist-variables@^7.18.6":
134 | version "7.18.6"
135 | resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz#d4d2c8fb4baeaa5c68b99cc8245c56554f926678"
136 | integrity sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==
137 | dependencies:
138 | "@babel/types" "^7.18.6"
139 |
140 | "@babel/helper-member-expression-to-functions@^7.18.9":
141 | version "7.18.9"
142 | resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.18.9.tgz#1531661e8375af843ad37ac692c132841e2fd815"
143 | integrity sha512-RxifAh2ZoVU67PyKIO4AMi1wTenGfMR/O/ae0CCRqwgBAt5v7xjdtRw7UoSbsreKrQn5t7r89eruK/9JjYHuDg==
144 | dependencies:
145 | "@babel/types" "^7.18.9"
146 |
147 | "@babel/helper-module-imports@^7.10.4", "@babel/helper-module-imports@^7.18.6":
148 | version "7.18.6"
149 | resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz#1e3ebdbbd08aad1437b428c50204db13c5a3ca6e"
150 | integrity sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==
151 | dependencies:
152 | "@babel/types" "^7.18.6"
153 |
154 | "@babel/helper-module-transforms@^7.18.6", "@babel/helper-module-transforms@^7.19.0":
155 | version "7.19.0"
156 | resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.19.0.tgz#309b230f04e22c58c6a2c0c0c7e50b216d350c30"
157 | integrity sha512-3HBZ377Fe14RbLIA+ac3sY4PTgpxHVkFrESaWhoI5PuyXPBBX8+C34qblV9G89ZtycGJCmCI/Ut+VUDK4bltNQ==
158 | dependencies:
159 | "@babel/helper-environment-visitor" "^7.18.9"
160 | "@babel/helper-module-imports" "^7.18.6"
161 | "@babel/helper-simple-access" "^7.18.6"
162 | "@babel/helper-split-export-declaration" "^7.18.6"
163 | "@babel/helper-validator-identifier" "^7.18.6"
164 | "@babel/template" "^7.18.10"
165 | "@babel/traverse" "^7.19.0"
166 | "@babel/types" "^7.19.0"
167 |
168 | "@babel/helper-optimise-call-expression@^7.18.6":
169 | version "7.18.6"
170 | resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.18.6.tgz#9369aa943ee7da47edab2cb4e838acf09d290ffe"
171 | integrity sha512-HP59oD9/fEHQkdcbgFCnbmgH5vIQTJbxh2yf+CdM89/glUNnuzr87Q8GIjGEnOktTROemO0Pe0iPAYbqZuOUiA==
172 | dependencies:
173 | "@babel/types" "^7.18.6"
174 |
175 | "@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.16.7", "@babel/helper-plugin-utils@^7.18.6", "@babel/helper-plugin-utils@^7.18.9", "@babel/helper-plugin-utils@^7.19.0", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3":
176 | version "7.19.0"
177 | resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.19.0.tgz#4796bb14961521f0f8715990bee2fb6e51ce21bf"
178 | integrity sha512-40Ryx7I8mT+0gaNxm8JGTZFUITNqdLAgdg0hXzeVZxVD6nFsdhQvip6v8dqkRHzsz1VFpFAaOCHNn0vKBL7Czw==
179 |
180 | "@babel/helper-remap-async-to-generator@^7.18.6", "@babel/helper-remap-async-to-generator@^7.18.9":
181 | version "7.18.9"
182 | resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.18.9.tgz#997458a0e3357080e54e1d79ec347f8a8cd28519"
183 | integrity sha512-dI7q50YKd8BAv3VEfgg7PS7yD3Rtbi2J1XMXaalXO0W0164hYLnh8zpjRS0mte9MfVp/tltvr/cfdXPvJr1opA==
184 | dependencies:
185 | "@babel/helper-annotate-as-pure" "^7.18.6"
186 | "@babel/helper-environment-visitor" "^7.18.9"
187 | "@babel/helper-wrap-function" "^7.18.9"
188 | "@babel/types" "^7.18.9"
189 |
190 | "@babel/helper-replace-supers@^7.18.6", "@babel/helper-replace-supers@^7.18.9":
191 | version "7.19.1"
192 | resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.19.1.tgz#e1592a9b4b368aa6bdb8784a711e0bcbf0612b78"
193 | integrity sha512-T7ahH7wV0Hfs46SFh5Jz3s0B6+o8g3c+7TMxu7xKfmHikg7EAZ3I2Qk9LFhjxXq8sL7UkP5JflezNwoZa8WvWw==
194 | dependencies:
195 | "@babel/helper-environment-visitor" "^7.18.9"
196 | "@babel/helper-member-expression-to-functions" "^7.18.9"
197 | "@babel/helper-optimise-call-expression" "^7.18.6"
198 | "@babel/traverse" "^7.19.1"
199 | "@babel/types" "^7.19.0"
200 |
201 | "@babel/helper-simple-access@^7.18.6":
202 | version "7.19.4"
203 | resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.19.4.tgz#be553f4951ac6352df2567f7daa19a0ee15668e7"
204 | integrity sha512-f9Xq6WqBFqaDfbCzn2w85hwklswz5qsKlh7f08w4Y9yhJHpnNC0QemtSkK5YyOY8kPGvyiwdzZksGUhnGdaUIg==
205 | dependencies:
206 | "@babel/types" "^7.19.4"
207 |
208 | "@babel/helper-skip-transparent-expression-wrappers@^7.18.9":
209 | version "7.18.9"
210 | resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.18.9.tgz#778d87b3a758d90b471e7b9918f34a9a02eb5818"
211 | integrity sha512-imytd2gHi3cJPsybLRbmFrF7u5BIEuI2cNheyKi3/iOBC63kNn3q8Crn2xVuESli0aM4KYsyEqKyS7lFL8YVtw==
212 | dependencies:
213 | "@babel/types" "^7.18.9"
214 |
215 | "@babel/helper-split-export-declaration@^7.18.6":
216 | version "7.18.6"
217 | resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz#7367949bc75b20c6d5a5d4a97bba2824ae8ef075"
218 | integrity sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==
219 | dependencies:
220 | "@babel/types" "^7.18.6"
221 |
222 | "@babel/helper-string-parser@^7.19.4":
223 | version "7.19.4"
224 | resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz#38d3acb654b4701a9b77fb0615a96f775c3a9e63"
225 | integrity sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==
226 |
227 | "@babel/helper-validator-identifier@^7.18.6", "@babel/helper-validator-identifier@^7.19.1":
228 | version "7.19.1"
229 | resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz#7eea834cf32901ffdc1a7ee555e2f9c27e249ca2"
230 | integrity sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==
231 |
232 | "@babel/helper-validator-option@^7.18.6":
233 | version "7.18.6"
234 | resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz#bf0d2b5a509b1f336099e4ff36e1a63aa5db4db8"
235 | integrity sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==
236 |
237 | "@babel/helper-wrap-function@^7.18.9":
238 | version "7.19.0"
239 | resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.19.0.tgz#89f18335cff1152373222f76a4b37799636ae8b1"
240 | integrity sha512-txX8aN8CZyYGTwcLhlk87KRqncAzhh5TpQamZUa0/u3an36NtDpUP6bQgBCBcLeBs09R/OwQu3OjK0k/HwfNDg==
241 | dependencies:
242 | "@babel/helper-function-name" "^7.19.0"
243 | "@babel/template" "^7.18.10"
244 | "@babel/traverse" "^7.19.0"
245 | "@babel/types" "^7.19.0"
246 |
247 | "@babel/helpers@^7.19.0":
248 | version "7.19.4"
249 | resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.19.4.tgz#42154945f87b8148df7203a25c31ba9a73be46c5"
250 | integrity sha512-G+z3aOx2nfDHwX/kyVii5fJq+bgscg89/dJNWpYeKeBv3v9xX8EIabmx1k6u9LS04H7nROFVRVK+e3k0VHp+sw==
251 | dependencies:
252 | "@babel/template" "^7.18.10"
253 | "@babel/traverse" "^7.19.4"
254 | "@babel/types" "^7.19.4"
255 |
256 | "@babel/highlight@^7.18.6":
257 | version "7.18.6"
258 | resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.18.6.tgz#81158601e93e2563795adcbfbdf5d64be3f2ecdf"
259 | integrity sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==
260 | dependencies:
261 | "@babel/helper-validator-identifier" "^7.18.6"
262 | chalk "^2.0.0"
263 | js-tokens "^4.0.0"
264 |
265 | "@babel/parser@^7.18.10", "@babel/parser@^7.19.3", "@babel/parser@^7.19.4":
266 | version "7.19.4"
267 | resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.19.4.tgz#03c4339d2b8971eb3beca5252bafd9b9f79db3dc"
268 | integrity sha512-qpVT7gtuOLjWeDTKLkJ6sryqLliBaFpAtGeqw5cs5giLldvh+Ch0plqnUMKoVAUS6ZEueQQiZV+p5pxtPitEsA==
269 |
270 | "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.18.6":
271 | version "7.18.6"
272 | resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.18.6.tgz#da5b8f9a580acdfbe53494dba45ea389fb09a4d2"
273 | integrity sha512-Dgxsyg54Fx1d4Nge8UnvTrED63vrwOdPmyvPzlNN/boaliRP54pm3pGzZD1SJUwrBA+Cs/xdG8kXX6Mn/RfISQ==
274 | dependencies:
275 | "@babel/helper-plugin-utils" "^7.18.6"
276 |
277 | "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@^7.18.9":
278 | version "7.18.9"
279 | resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.18.9.tgz#a11af19aa373d68d561f08e0a57242350ed0ec50"
280 | integrity sha512-AHrP9jadvH7qlOj6PINbgSuphjQUAK7AOT7DPjBo9EHoLhQTnnK5u45e1Hd4DbSQEO9nqPWtQ89r+XEOWFScKg==
281 | dependencies:
282 | "@babel/helper-plugin-utils" "^7.18.9"
283 | "@babel/helper-skip-transparent-expression-wrappers" "^7.18.9"
284 | "@babel/plugin-proposal-optional-chaining" "^7.18.9"
285 |
286 | "@babel/plugin-proposal-async-generator-functions@^7.19.1":
287 | version "7.19.1"
288 | resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.19.1.tgz#34f6f5174b688529342288cd264f80c9ea9fb4a7"
289 | integrity sha512-0yu8vNATgLy4ivqMNBIwb1HebCelqN7YX8SL3FDXORv/RqT0zEEWUCH4GH44JsSrvCu6GqnAdR5EBFAPeNBB4Q==
290 | dependencies:
291 | "@babel/helper-environment-visitor" "^7.18.9"
292 | "@babel/helper-plugin-utils" "^7.19.0"
293 | "@babel/helper-remap-async-to-generator" "^7.18.9"
294 | "@babel/plugin-syntax-async-generators" "^7.8.4"
295 |
296 | "@babel/plugin-proposal-class-properties@^7.18.6":
297 | version "7.18.6"
298 | resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.18.6.tgz#b110f59741895f7ec21a6fff696ec46265c446a3"
299 | integrity sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ==
300 | dependencies:
301 | "@babel/helper-create-class-features-plugin" "^7.18.6"
302 | "@babel/helper-plugin-utils" "^7.18.6"
303 |
304 | "@babel/plugin-proposal-class-static-block@^7.18.6":
305 | version "7.18.6"
306 | resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.18.6.tgz#8aa81d403ab72d3962fc06c26e222dacfc9b9020"
307 | integrity sha512-+I3oIiNxrCpup3Gi8n5IGMwj0gOCAjcJUSQEcotNnCCPMEnixawOQ+KeJPlgfjzx+FKQ1QSyZOWe7wmoJp7vhw==
308 | dependencies:
309 | "@babel/helper-create-class-features-plugin" "^7.18.6"
310 | "@babel/helper-plugin-utils" "^7.18.6"
311 | "@babel/plugin-syntax-class-static-block" "^7.14.5"
312 |
313 | "@babel/plugin-proposal-dynamic-import@^7.18.6":
314 | version "7.18.6"
315 | resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.18.6.tgz#72bcf8d408799f547d759298c3c27c7e7faa4d94"
316 | integrity sha512-1auuwmK+Rz13SJj36R+jqFPMJWyKEDd7lLSdOj4oJK0UTgGueSAtkrCvz9ewmgyU/P941Rv2fQwZJN8s6QruXw==
317 | dependencies:
318 | "@babel/helper-plugin-utils" "^7.18.6"
319 | "@babel/plugin-syntax-dynamic-import" "^7.8.3"
320 |
321 | "@babel/plugin-proposal-export-namespace-from@^7.18.9":
322 | version "7.18.9"
323 | resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.18.9.tgz#5f7313ab348cdb19d590145f9247540e94761203"
324 | integrity sha512-k1NtHyOMvlDDFeb9G5PhUXuGj8m/wiwojgQVEhJ/fsVsMCpLyOP4h0uGEjYJKrRI+EVPlb5Jk+Gt9P97lOGwtA==
325 | dependencies:
326 | "@babel/helper-plugin-utils" "^7.18.9"
327 | "@babel/plugin-syntax-export-namespace-from" "^7.8.3"
328 |
329 | "@babel/plugin-proposal-json-strings@^7.18.6":
330 | version "7.18.6"
331 | resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.18.6.tgz#7e8788c1811c393aff762817e7dbf1ebd0c05f0b"
332 | integrity sha512-lr1peyn9kOdbYc0xr0OdHTZ5FMqS6Di+H0Fz2I/JwMzGmzJETNeOFq2pBySw6X/KFL5EWDjlJuMsUGRFb8fQgQ==
333 | dependencies:
334 | "@babel/helper-plugin-utils" "^7.18.6"
335 | "@babel/plugin-syntax-json-strings" "^7.8.3"
336 |
337 | "@babel/plugin-proposal-logical-assignment-operators@^7.18.9":
338 | version "7.18.9"
339 | resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.18.9.tgz#8148cbb350483bf6220af06fa6db3690e14b2e23"
340 | integrity sha512-128YbMpjCrP35IOExw2Fq+x55LMP42DzhOhX2aNNIdI9avSWl2PI0yuBWarr3RYpZBSPtabfadkH2yeRiMD61Q==
341 | dependencies:
342 | "@babel/helper-plugin-utils" "^7.18.9"
343 | "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4"
344 |
345 | "@babel/plugin-proposal-nullish-coalescing-operator@^7.18.6":
346 | version "7.18.6"
347 | resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.18.6.tgz#fdd940a99a740e577d6c753ab6fbb43fdb9467e1"
348 | integrity sha512-wQxQzxYeJqHcfppzBDnm1yAY0jSRkUXR2z8RePZYrKwMKgMlE8+Z6LUno+bd6LvbGh8Gltvy74+9pIYkr+XkKA==
349 | dependencies:
350 | "@babel/helper-plugin-utils" "^7.18.6"
351 | "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3"
352 |
353 | "@babel/plugin-proposal-numeric-separator@^7.18.6":
354 | version "7.18.6"
355 | resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.18.6.tgz#899b14fbafe87f053d2c5ff05b36029c62e13c75"
356 | integrity sha512-ozlZFogPqoLm8WBr5Z8UckIoE4YQ5KESVcNudyXOR8uqIkliTEgJ3RoketfG6pmzLdeZF0H/wjE9/cCEitBl7Q==
357 | dependencies:
358 | "@babel/helper-plugin-utils" "^7.18.6"
359 | "@babel/plugin-syntax-numeric-separator" "^7.10.4"
360 |
361 | "@babel/plugin-proposal-object-rest-spread@^7.19.4":
362 | version "7.19.4"
363 | resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.19.4.tgz#a8fc86e8180ff57290c91a75d83fe658189b642d"
364 | integrity sha512-wHmj6LDxVDnL+3WhXteUBaoM1aVILZODAUjg11kHqG4cOlfgMQGxw6aCgvrXrmaJR3Bn14oZhImyCPZzRpC93Q==
365 | dependencies:
366 | "@babel/compat-data" "^7.19.4"
367 | "@babel/helper-compilation-targets" "^7.19.3"
368 | "@babel/helper-plugin-utils" "^7.19.0"
369 | "@babel/plugin-syntax-object-rest-spread" "^7.8.3"
370 | "@babel/plugin-transform-parameters" "^7.18.8"
371 |
372 | "@babel/plugin-proposal-optional-catch-binding@^7.18.6":
373 | version "7.18.6"
374 | resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.18.6.tgz#f9400d0e6a3ea93ba9ef70b09e72dd6da638a2cb"
375 | integrity sha512-Q40HEhs9DJQyaZfUjjn6vE8Cv4GmMHCYuMGIWUnlxH6400VGxOuwWsPt4FxXxJkC/5eOzgn0z21M9gMT4MOhbw==
376 | dependencies:
377 | "@babel/helper-plugin-utils" "^7.18.6"
378 | "@babel/plugin-syntax-optional-catch-binding" "^7.8.3"
379 |
380 | "@babel/plugin-proposal-optional-chaining@^7.18.9":
381 | version "7.18.9"
382 | resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.18.9.tgz#e8e8fe0723f2563960e4bf5e9690933691915993"
383 | integrity sha512-v5nwt4IqBXihxGsW2QmCWMDS3B3bzGIk/EQVZz2ei7f3NJl8NzAJVvUmpDW5q1CRNY+Beb/k58UAH1Km1N411w==
384 | dependencies:
385 | "@babel/helper-plugin-utils" "^7.18.9"
386 | "@babel/helper-skip-transparent-expression-wrappers" "^7.18.9"
387 | "@babel/plugin-syntax-optional-chaining" "^7.8.3"
388 |
389 | "@babel/plugin-proposal-private-methods@^7.18.6":
390 | version "7.18.6"
391 | resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.18.6.tgz#5209de7d213457548a98436fa2882f52f4be6bea"
392 | integrity sha512-nutsvktDItsNn4rpGItSNV2sz1XwS+nfU0Rg8aCx3W3NOKVzdMjJRu0O5OkgDp3ZGICSTbgRpxZoWsxoKRvbeA==
393 | dependencies:
394 | "@babel/helper-create-class-features-plugin" "^7.18.6"
395 | "@babel/helper-plugin-utils" "^7.18.6"
396 |
397 | "@babel/plugin-proposal-private-property-in-object@^7.18.6":
398 | version "7.18.6"
399 | resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.18.6.tgz#a64137b232f0aca3733a67eb1a144c192389c503"
400 | integrity sha512-9Rysx7FOctvT5ouj5JODjAFAkgGoudQuLPamZb0v1TGLpapdNaftzifU8NTWQm0IRjqoYypdrSmyWgkocDQ8Dw==
401 | dependencies:
402 | "@babel/helper-annotate-as-pure" "^7.18.6"
403 | "@babel/helper-create-class-features-plugin" "^7.18.6"
404 | "@babel/helper-plugin-utils" "^7.18.6"
405 | "@babel/plugin-syntax-private-property-in-object" "^7.14.5"
406 |
407 | "@babel/plugin-proposal-unicode-property-regex@^7.18.6", "@babel/plugin-proposal-unicode-property-regex@^7.4.4":
408 | version "7.18.6"
409 | resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.18.6.tgz#af613d2cd5e643643b65cded64207b15c85cb78e"
410 | integrity sha512-2BShG/d5yoZyXZfVePH91urL5wTG6ASZU9M4o03lKK8u8UW1y08OMttBSOADTcJrnPMpvDXRG3G8fyLh4ovs8w==
411 | dependencies:
412 | "@babel/helper-create-regexp-features-plugin" "^7.18.6"
413 | "@babel/helper-plugin-utils" "^7.18.6"
414 |
415 | "@babel/plugin-syntax-async-generators@^7.8.4":
416 | version "7.8.4"
417 | resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d"
418 | integrity sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==
419 | dependencies:
420 | "@babel/helper-plugin-utils" "^7.8.0"
421 |
422 | "@babel/plugin-syntax-class-properties@^7.12.13":
423 | version "7.12.13"
424 | resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz#b5c987274c4a3a82b89714796931a6b53544ae10"
425 | integrity sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==
426 | dependencies:
427 | "@babel/helper-plugin-utils" "^7.12.13"
428 |
429 | "@babel/plugin-syntax-class-static-block@^7.14.5":
430 | version "7.14.5"
431 | resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz#195df89b146b4b78b3bf897fd7a257c84659d406"
432 | integrity sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==
433 | dependencies:
434 | "@babel/helper-plugin-utils" "^7.14.5"
435 |
436 | "@babel/plugin-syntax-dynamic-import@^7.8.3":
437 | version "7.8.3"
438 | resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz#62bf98b2da3cd21d626154fc96ee5b3cb68eacb3"
439 | integrity sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==
440 | dependencies:
441 | "@babel/helper-plugin-utils" "^7.8.0"
442 |
443 | "@babel/plugin-syntax-export-namespace-from@^7.8.3":
444 | version "7.8.3"
445 | resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz#028964a9ba80dbc094c915c487ad7c4e7a66465a"
446 | integrity sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==
447 | dependencies:
448 | "@babel/helper-plugin-utils" "^7.8.3"
449 |
450 | "@babel/plugin-syntax-import-assertions@^7.18.6":
451 | version "7.18.6"
452 | resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.18.6.tgz#cd6190500a4fa2fe31990a963ffab4b63e4505e4"
453 | integrity sha512-/DU3RXad9+bZwrgWJQKbr39gYbJpLJHezqEzRzi/BHRlJ9zsQb4CK2CA/5apllXNomwA1qHwzvHl+AdEmC5krQ==
454 | dependencies:
455 | "@babel/helper-plugin-utils" "^7.18.6"
456 |
457 | "@babel/plugin-syntax-json-strings@^7.8.3":
458 | version "7.8.3"
459 | resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz#01ca21b668cd8218c9e640cb6dd88c5412b2c96a"
460 | integrity sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==
461 | dependencies:
462 | "@babel/helper-plugin-utils" "^7.8.0"
463 |
464 | "@babel/plugin-syntax-jsx@^7.18.6":
465 | version "7.18.6"
466 | resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.18.6.tgz#a8feef63b010150abd97f1649ec296e849943ca0"
467 | integrity sha512-6mmljtAedFGTWu2p/8WIORGwy+61PLgOMPOdazc7YoJ9ZCWUyFy3A6CpPkRKLKD1ToAesxX8KGEViAiLo9N+7Q==
468 | dependencies:
469 | "@babel/helper-plugin-utils" "^7.18.6"
470 |
471 | "@babel/plugin-syntax-logical-assignment-operators@^7.10.4":
472 | version "7.10.4"
473 | resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz#ca91ef46303530448b906652bac2e9fe9941f699"
474 | integrity sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==
475 | dependencies:
476 | "@babel/helper-plugin-utils" "^7.10.4"
477 |
478 | "@babel/plugin-syntax-nullish-coalescing-operator@^7.8.3":
479 | version "7.8.3"
480 | resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz#167ed70368886081f74b5c36c65a88c03b66d1a9"
481 | integrity sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==
482 | dependencies:
483 | "@babel/helper-plugin-utils" "^7.8.0"
484 |
485 | "@babel/plugin-syntax-numeric-separator@^7.10.4":
486 | version "7.10.4"
487 | resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz#b9b070b3e33570cd9fd07ba7fa91c0dd37b9af97"
488 | integrity sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==
489 | dependencies:
490 | "@babel/helper-plugin-utils" "^7.10.4"
491 |
492 | "@babel/plugin-syntax-object-rest-spread@^7.8.3":
493 | version "7.8.3"
494 | resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871"
495 | integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==
496 | dependencies:
497 | "@babel/helper-plugin-utils" "^7.8.0"
498 |
499 | "@babel/plugin-syntax-optional-catch-binding@^7.8.3":
500 | version "7.8.3"
501 | resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz#6111a265bcfb020eb9efd0fdfd7d26402b9ed6c1"
502 | integrity sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==
503 | dependencies:
504 | "@babel/helper-plugin-utils" "^7.8.0"
505 |
506 | "@babel/plugin-syntax-optional-chaining@^7.8.3":
507 | version "7.8.3"
508 | resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz#4f69c2ab95167e0180cd5336613f8c5788f7d48a"
509 | integrity sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==
510 | dependencies:
511 | "@babel/helper-plugin-utils" "^7.8.0"
512 |
513 | "@babel/plugin-syntax-private-property-in-object@^7.14.5":
514 | version "7.14.5"
515 | resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz#0dc6671ec0ea22b6e94a1114f857970cd39de1ad"
516 | integrity sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==
517 | dependencies:
518 | "@babel/helper-plugin-utils" "^7.14.5"
519 |
520 | "@babel/plugin-syntax-top-level-await@^7.14.5":
521 | version "7.14.5"
522 | resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz#c1cfdadc35a646240001f06138247b741c34d94c"
523 | integrity sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==
524 | dependencies:
525 | "@babel/helper-plugin-utils" "^7.14.5"
526 |
527 | "@babel/plugin-transform-arrow-functions@^7.18.6":
528 | version "7.18.6"
529 | resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.18.6.tgz#19063fcf8771ec7b31d742339dac62433d0611fe"
530 | integrity sha512-9S9X9RUefzrsHZmKMbDXxweEH+YlE8JJEuat9FdvW9Qh1cw7W64jELCtWNkPBPX5En45uy28KGvA/AySqUh8CQ==
531 | dependencies:
532 | "@babel/helper-plugin-utils" "^7.18.6"
533 |
534 | "@babel/plugin-transform-async-to-generator@^7.18.6":
535 | version "7.18.6"
536 | resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.18.6.tgz#ccda3d1ab9d5ced5265fdb13f1882d5476c71615"
537 | integrity sha512-ARE5wZLKnTgPW7/1ftQmSi1CmkqqHo2DNmtztFhvgtOWSDfq0Cq9/9L+KnZNYSNrydBekhW3rwShduf59RoXag==
538 | dependencies:
539 | "@babel/helper-module-imports" "^7.18.6"
540 | "@babel/helper-plugin-utils" "^7.18.6"
541 | "@babel/helper-remap-async-to-generator" "^7.18.6"
542 |
543 | "@babel/plugin-transform-block-scoped-functions@^7.18.6":
544 | version "7.18.6"
545 | resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.18.6.tgz#9187bf4ba302635b9d70d986ad70f038726216a8"
546 | integrity sha512-ExUcOqpPWnliRcPqves5HJcJOvHvIIWfuS4sroBUenPuMdmW+SMHDakmtS7qOo13sVppmUijqeTv7qqGsvURpQ==
547 | dependencies:
548 | "@babel/helper-plugin-utils" "^7.18.6"
549 |
550 | "@babel/plugin-transform-block-scoping@^7.19.4":
551 | version "7.19.4"
552 | resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.19.4.tgz#315d70f68ce64426db379a3d830e7ac30be02e9b"
553 | integrity sha512-934S2VLLlt2hRJwPf4MczaOr4hYF0z+VKPwqTNxyKX7NthTiPfhuKFWQZHXRM0vh/wo/VyXB3s4bZUNA08l+tQ==
554 | dependencies:
555 | "@babel/helper-plugin-utils" "^7.19.0"
556 |
557 | "@babel/plugin-transform-classes@^7.19.0":
558 | version "7.19.0"
559 | resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.19.0.tgz#0e61ec257fba409c41372175e7c1e606dc79bb20"
560 | integrity sha512-YfeEE9kCjqTS9IitkgfJuxjcEtLUHMqa8yUJ6zdz8vR7hKuo6mOy2C05P0F1tdMmDCeuyidKnlrw/iTppHcr2A==
561 | dependencies:
562 | "@babel/helper-annotate-as-pure" "^7.18.6"
563 | "@babel/helper-compilation-targets" "^7.19.0"
564 | "@babel/helper-environment-visitor" "^7.18.9"
565 | "@babel/helper-function-name" "^7.19.0"
566 | "@babel/helper-optimise-call-expression" "^7.18.6"
567 | "@babel/helper-plugin-utils" "^7.19.0"
568 | "@babel/helper-replace-supers" "^7.18.9"
569 | "@babel/helper-split-export-declaration" "^7.18.6"
570 | globals "^11.1.0"
571 |
572 | "@babel/plugin-transform-computed-properties@^7.18.9":
573 | version "7.18.9"
574 | resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.18.9.tgz#2357a8224d402dad623caf6259b611e56aec746e"
575 | integrity sha512-+i0ZU1bCDymKakLxn5srGHrsAPRELC2WIbzwjLhHW9SIE1cPYkLCL0NlnXMZaM1vhfgA2+M7hySk42VBvrkBRw==
576 | dependencies:
577 | "@babel/helper-plugin-utils" "^7.18.9"
578 |
579 | "@babel/plugin-transform-destructuring@^7.19.4":
580 | version "7.19.4"
581 | resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.19.4.tgz#46890722687b9b89e1369ad0bd8dc6c5a3b4319d"
582 | integrity sha512-t0j0Hgidqf0aM86dF8U+vXYReUgJnlv4bZLsyoPnwZNrGY+7/38o8YjaELrvHeVfTZao15kjR0PVv0nju2iduA==
583 | dependencies:
584 | "@babel/helper-plugin-utils" "^7.19.0"
585 |
586 | "@babel/plugin-transform-dotall-regex@^7.18.6", "@babel/plugin-transform-dotall-regex@^7.4.4":
587 | version "7.18.6"
588 | resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.18.6.tgz#b286b3e7aae6c7b861e45bed0a2fafd6b1a4fef8"
589 | integrity sha512-6S3jpun1eEbAxq7TdjLotAsl4WpQI9DxfkycRcKrjhQYzU87qpXdknpBg/e+TdcMehqGnLFi7tnFUBR02Vq6wg==
590 | dependencies:
591 | "@babel/helper-create-regexp-features-plugin" "^7.18.6"
592 | "@babel/helper-plugin-utils" "^7.18.6"
593 |
594 | "@babel/plugin-transform-duplicate-keys@^7.18.9":
595 | version "7.18.9"
596 | resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.18.9.tgz#687f15ee3cdad6d85191eb2a372c4528eaa0ae0e"
597 | integrity sha512-d2bmXCtZXYc59/0SanQKbiWINadaJXqtvIQIzd4+hNwkWBgyCd5F/2t1kXoUdvPMrxzPvhK6EMQRROxsue+mfw==
598 | dependencies:
599 | "@babel/helper-plugin-utils" "^7.18.9"
600 |
601 | "@babel/plugin-transform-exponentiation-operator@^7.18.6":
602 | version "7.18.6"
603 | resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.18.6.tgz#421c705f4521888c65e91fdd1af951bfefd4dacd"
604 | integrity sha512-wzEtc0+2c88FVR34aQmiz56dxEkxr2g8DQb/KfaFa1JYXOFVsbhvAonFN6PwVWj++fKmku8NP80plJ5Et4wqHw==
605 | dependencies:
606 | "@babel/helper-builder-binary-assignment-operator-visitor" "^7.18.6"
607 | "@babel/helper-plugin-utils" "^7.18.6"
608 |
609 | "@babel/plugin-transform-for-of@^7.18.8":
610 | version "7.18.8"
611 | resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.18.8.tgz#6ef8a50b244eb6a0bdbad0c7c61877e4e30097c1"
612 | integrity sha512-yEfTRnjuskWYo0k1mHUqrVWaZwrdq8AYbfrpqULOJOaucGSp4mNMVps+YtA8byoevxS/urwU75vyhQIxcCgiBQ==
613 | dependencies:
614 | "@babel/helper-plugin-utils" "^7.18.6"
615 |
616 | "@babel/plugin-transform-function-name@^7.18.9":
617 | version "7.18.9"
618 | resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.18.9.tgz#cc354f8234e62968946c61a46d6365440fc764e0"
619 | integrity sha512-WvIBoRPaJQ5yVHzcnJFor7oS5Ls0PYixlTYE63lCj2RtdQEl15M68FXQlxnG6wdraJIXRdR7KI+hQ7q/9QjrCQ==
620 | dependencies:
621 | "@babel/helper-compilation-targets" "^7.18.9"
622 | "@babel/helper-function-name" "^7.18.9"
623 | "@babel/helper-plugin-utils" "^7.18.9"
624 |
625 | "@babel/plugin-transform-literals@^7.18.9":
626 | version "7.18.9"
627 | resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.18.9.tgz#72796fdbef80e56fba3c6a699d54f0de557444bc"
628 | integrity sha512-IFQDSRoTPnrAIrI5zoZv73IFeZu2dhu6irxQjY9rNjTT53VmKg9fenjvoiOWOkJ6mm4jKVPtdMzBY98Fp4Z4cg==
629 | dependencies:
630 | "@babel/helper-plugin-utils" "^7.18.9"
631 |
632 | "@babel/plugin-transform-member-expression-literals@^7.18.6":
633 | version "7.18.6"
634 | resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.18.6.tgz#ac9fdc1a118620ac49b7e7a5d2dc177a1bfee88e"
635 | integrity sha512-qSF1ihLGO3q+/g48k85tUjD033C29TNTVB2paCwZPVmOsjn9pClvYYrM2VeJpBY2bcNkuny0YUyTNRyRxJ54KA==
636 | dependencies:
637 | "@babel/helper-plugin-utils" "^7.18.6"
638 |
639 | "@babel/plugin-transform-modules-amd@^7.18.6":
640 | version "7.18.6"
641 | resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.18.6.tgz#8c91f8c5115d2202f277549848874027d7172d21"
642 | integrity sha512-Pra5aXsmTsOnjM3IajS8rTaLCy++nGM4v3YR4esk5PCsyg9z8NA5oQLwxzMUtDBd8F+UmVza3VxoAaWCbzH1rg==
643 | dependencies:
644 | "@babel/helper-module-transforms" "^7.18.6"
645 | "@babel/helper-plugin-utils" "^7.18.6"
646 | babel-plugin-dynamic-import-node "^2.3.3"
647 |
648 | "@babel/plugin-transform-modules-commonjs@^7.18.6":
649 | version "7.18.6"
650 | resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.18.6.tgz#afd243afba166cca69892e24a8fd8c9f2ca87883"
651 | integrity sha512-Qfv2ZOWikpvmedXQJDSbxNqy7Xr/j2Y8/KfijM0iJyKkBTmWuvCA1yeH1yDM7NJhBW/2aXxeucLj6i80/LAJ/Q==
652 | dependencies:
653 | "@babel/helper-module-transforms" "^7.18.6"
654 | "@babel/helper-plugin-utils" "^7.18.6"
655 | "@babel/helper-simple-access" "^7.18.6"
656 | babel-plugin-dynamic-import-node "^2.3.3"
657 |
658 | "@babel/plugin-transform-modules-systemjs@^7.19.0":
659 | version "7.19.0"
660 | resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.19.0.tgz#5f20b471284430f02d9c5059d9b9a16d4b085a1f"
661 | integrity sha512-x9aiR0WXAWmOWsqcsnrzGR+ieaTMVyGyffPVA7F8cXAGt/UxefYv6uSHZLkAFChN5M5Iy1+wjE+xJuPt22H39A==
662 | dependencies:
663 | "@babel/helper-hoist-variables" "^7.18.6"
664 | "@babel/helper-module-transforms" "^7.19.0"
665 | "@babel/helper-plugin-utils" "^7.19.0"
666 | "@babel/helper-validator-identifier" "^7.18.6"
667 | babel-plugin-dynamic-import-node "^2.3.3"
668 |
669 | "@babel/plugin-transform-modules-umd@^7.18.6":
670 | version "7.18.6"
671 | resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.18.6.tgz#81d3832d6034b75b54e62821ba58f28ed0aab4b9"
672 | integrity sha512-dcegErExVeXcRqNtkRU/z8WlBLnvD4MRnHgNs3MytRO1Mn1sHRyhbcpYbVMGclAqOjdW+9cfkdZno9dFdfKLfQ==
673 | dependencies:
674 | "@babel/helper-module-transforms" "^7.18.6"
675 | "@babel/helper-plugin-utils" "^7.18.6"
676 |
677 | "@babel/plugin-transform-named-capturing-groups-regex@^7.19.1":
678 | version "7.19.1"
679 | resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.19.1.tgz#ec7455bab6cd8fb05c525a94876f435a48128888"
680 | integrity sha512-oWk9l9WItWBQYS4FgXD4Uyy5kq898lvkXpXQxoJEY1RnvPk4R/Dvu2ebXU9q8lP+rlMwUQTFf2Ok6d78ODa0kw==
681 | dependencies:
682 | "@babel/helper-create-regexp-features-plugin" "^7.19.0"
683 | "@babel/helper-plugin-utils" "^7.19.0"
684 |
685 | "@babel/plugin-transform-new-target@^7.18.6":
686 | version "7.18.6"
687 | resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.18.6.tgz#d128f376ae200477f37c4ddfcc722a8a1b3246a8"
688 | integrity sha512-DjwFA/9Iu3Z+vrAn+8pBUGcjhxKguSMlsFqeCKbhb9BAV756v0krzVK04CRDi/4aqmk8BsHb4a/gFcaA5joXRw==
689 | dependencies:
690 | "@babel/helper-plugin-utils" "^7.18.6"
691 |
692 | "@babel/plugin-transform-object-super@^7.18.6":
693 | version "7.18.6"
694 | resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.18.6.tgz#fb3c6ccdd15939b6ff7939944b51971ddc35912c"
695 | integrity sha512-uvGz6zk+pZoS1aTZrOvrbj6Pp/kK2mp45t2B+bTDre2UgsZZ8EZLSJtUg7m/no0zOJUWgFONpB7Zv9W2tSaFlA==
696 | dependencies:
697 | "@babel/helper-plugin-utils" "^7.18.6"
698 | "@babel/helper-replace-supers" "^7.18.6"
699 |
700 | "@babel/plugin-transform-parameters@^7.18.8":
701 | version "7.18.8"
702 | resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.18.8.tgz#ee9f1a0ce6d78af58d0956a9378ea3427cccb48a"
703 | integrity sha512-ivfbE3X2Ss+Fj8nnXvKJS6sjRG4gzwPMsP+taZC+ZzEGjAYlvENixmt1sZ5Ca6tWls+BlKSGKPJ6OOXvXCbkFg==
704 | dependencies:
705 | "@babel/helper-plugin-utils" "^7.18.6"
706 |
707 | "@babel/plugin-transform-property-literals@^7.18.6":
708 | version "7.18.6"
709 | resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.18.6.tgz#e22498903a483448e94e032e9bbb9c5ccbfc93a3"
710 | integrity sha512-cYcs6qlgafTud3PAzrrRNbQtfpQ8+y/+M5tKmksS9+M1ckbH6kzY8MrexEM9mcA6JDsukE19iIRvAyYl463sMg==
711 | dependencies:
712 | "@babel/helper-plugin-utils" "^7.18.6"
713 |
714 | "@babel/plugin-transform-react-display-name@^7.18.6":
715 | version "7.18.6"
716 | resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.18.6.tgz#8b1125f919ef36ebdfff061d664e266c666b9415"
717 | integrity sha512-TV4sQ+T013n61uMoygyMRm+xf04Bd5oqFpv2jAEQwSZ8NwQA7zeRPg1LMVg2PWi3zWBz+CLKD+v5bcpZ/BS0aA==
718 | dependencies:
719 | "@babel/helper-plugin-utils" "^7.18.6"
720 |
721 | "@babel/plugin-transform-react-jsx-development@^7.18.6":
722 | version "7.18.6"
723 | resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.18.6.tgz#dbe5c972811e49c7405b630e4d0d2e1380c0ddc5"
724 | integrity sha512-SA6HEjwYFKF7WDjWcMcMGUimmw/nhNRDWxr+KaLSCrkD/LMDBvWRmHAYgE1HDeF8KUuI8OAu+RT6EOtKxSW2qA==
725 | dependencies:
726 | "@babel/plugin-transform-react-jsx" "^7.18.6"
727 |
728 | "@babel/plugin-transform-react-jsx@^7.18.6":
729 | version "7.19.0"
730 | resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.19.0.tgz#b3cbb7c3a00b92ec8ae1027910e331ba5c500eb9"
731 | integrity sha512-UVEvX3tXie3Szm3emi1+G63jyw1w5IcMY0FSKM+CRnKRI5Mr1YbCNgsSTwoTwKphQEG9P+QqmuRFneJPZuHNhg==
732 | dependencies:
733 | "@babel/helper-annotate-as-pure" "^7.18.6"
734 | "@babel/helper-module-imports" "^7.18.6"
735 | "@babel/helper-plugin-utils" "^7.19.0"
736 | "@babel/plugin-syntax-jsx" "^7.18.6"
737 | "@babel/types" "^7.19.0"
738 |
739 | "@babel/plugin-transform-react-pure-annotations@^7.18.6":
740 | version "7.18.6"
741 | resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.18.6.tgz#561af267f19f3e5d59291f9950fd7b9663d0d844"
742 | integrity sha512-I8VfEPg9r2TRDdvnHgPepTKvuRomzA8+u+nhY7qSI1fR2hRNebasZEETLyM5mAUr0Ku56OkXJ0I7NHJnO6cJiQ==
743 | dependencies:
744 | "@babel/helper-annotate-as-pure" "^7.18.6"
745 | "@babel/helper-plugin-utils" "^7.18.6"
746 |
747 | "@babel/plugin-transform-regenerator@^7.18.6":
748 | version "7.18.6"
749 | resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.18.6.tgz#585c66cb84d4b4bf72519a34cfce761b8676ca73"
750 | integrity sha512-poqRI2+qiSdeldcz4wTSTXBRryoq3Gc70ye7m7UD5Ww0nE29IXqMl6r7Nd15WBgRd74vloEMlShtH6CKxVzfmQ==
751 | dependencies:
752 | "@babel/helper-plugin-utils" "^7.18.6"
753 | regenerator-transform "^0.15.0"
754 |
755 | "@babel/plugin-transform-reserved-words@^7.18.6":
756 | version "7.18.6"
757 | resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.18.6.tgz#b1abd8ebf8edaa5f7fe6bbb8d2133d23b6a6f76a"
758 | integrity sha512-oX/4MyMoypzHjFrT1CdivfKZ+XvIPMFXwwxHp/r0Ddy2Vuomt4HDFGmft1TAY2yiTKiNSsh3kjBAzcM8kSdsjA==
759 | dependencies:
760 | "@babel/helper-plugin-utils" "^7.18.6"
761 |
762 | "@babel/plugin-transform-runtime@^7.17.0":
763 | version "7.19.1"
764 | resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.19.1.tgz#a3df2d7312eea624c7889a2dcd37fd1dfd25b2c6"
765 | integrity sha512-2nJjTUFIzBMP/f/miLxEK9vxwW/KUXsdvN4sR//TmuDhe6yU2h57WmIOE12Gng3MDP/xpjUV/ToZRdcf8Yj4fA==
766 | dependencies:
767 | "@babel/helper-module-imports" "^7.18.6"
768 | "@babel/helper-plugin-utils" "^7.19.0"
769 | babel-plugin-polyfill-corejs2 "^0.3.3"
770 | babel-plugin-polyfill-corejs3 "^0.6.0"
771 | babel-plugin-polyfill-regenerator "^0.4.1"
772 | semver "^6.3.0"
773 |
774 | "@babel/plugin-transform-shorthand-properties@^7.18.6":
775 | version "7.18.6"
776 | resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.18.6.tgz#6d6df7983d67b195289be24909e3f12a8f664dc9"
777 | integrity sha512-eCLXXJqv8okzg86ywZJbRn19YJHU4XUa55oz2wbHhaQVn/MM+XhukiT7SYqp/7o00dg52Rj51Ny+Ecw4oyoygw==
778 | dependencies:
779 | "@babel/helper-plugin-utils" "^7.18.6"
780 |
781 | "@babel/plugin-transform-spread@^7.19.0":
782 | version "7.19.0"
783 | resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.19.0.tgz#dd60b4620c2fec806d60cfaae364ec2188d593b6"
784 | integrity sha512-RsuMk7j6n+r752EtzyScnWkQyuJdli6LdO5Klv8Yx0OfPVTcQkIUfS8clx5e9yHXzlnhOZF3CbQ8C2uP5j074w==
785 | dependencies:
786 | "@babel/helper-plugin-utils" "^7.19.0"
787 | "@babel/helper-skip-transparent-expression-wrappers" "^7.18.9"
788 |
789 | "@babel/plugin-transform-sticky-regex@^7.18.6":
790 | version "7.18.6"
791 | resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.18.6.tgz#c6706eb2b1524028e317720339583ad0f444adcc"
792 | integrity sha512-kfiDrDQ+PBsQDO85yj1icueWMfGfJFKN1KCkndygtu/C9+XUfydLC8Iv5UYJqRwy4zk8EcplRxEOeLyjq1gm6Q==
793 | dependencies:
794 | "@babel/helper-plugin-utils" "^7.18.6"
795 |
796 | "@babel/plugin-transform-template-literals@^7.18.9":
797 | version "7.18.9"
798 | resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.18.9.tgz#04ec6f10acdaa81846689d63fae117dd9c243a5e"
799 | integrity sha512-S8cOWfT82gTezpYOiVaGHrCbhlHgKhQt8XH5ES46P2XWmX92yisoZywf5km75wv5sYcXDUCLMmMxOLCtthDgMA==
800 | dependencies:
801 | "@babel/helper-plugin-utils" "^7.18.9"
802 |
803 | "@babel/plugin-transform-typeof-symbol@^7.18.9":
804 | version "7.18.9"
805 | resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.18.9.tgz#c8cea68263e45addcd6afc9091429f80925762c0"
806 | integrity sha512-SRfwTtF11G2aemAZWivL7PD+C9z52v9EvMqH9BuYbabyPuKUvSWks3oCg6041pT925L4zVFqaVBeECwsmlguEw==
807 | dependencies:
808 | "@babel/helper-plugin-utils" "^7.18.9"
809 |
810 | "@babel/plugin-transform-unicode-escapes@^7.18.10":
811 | version "7.18.10"
812 | resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.18.10.tgz#1ecfb0eda83d09bbcb77c09970c2dd55832aa246"
813 | integrity sha512-kKAdAI+YzPgGY/ftStBFXTI1LZFju38rYThnfMykS+IXy8BVx+res7s2fxf1l8I35DV2T97ezo6+SGrXz6B3iQ==
814 | dependencies:
815 | "@babel/helper-plugin-utils" "^7.18.9"
816 |
817 | "@babel/plugin-transform-unicode-regex@^7.18.6":
818 | version "7.18.6"
819 | resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.18.6.tgz#194317225d8c201bbae103364ffe9e2cea36cdca"
820 | integrity sha512-gE7A6Lt7YLnNOL3Pb9BNeZvi+d8l7tcRrG4+pwJjK9hD2xX4mEvjlQW60G9EEmfXVYRPv9VRQcyegIVHCql/AA==
821 | dependencies:
822 | "@babel/helper-create-regexp-features-plugin" "^7.18.6"
823 | "@babel/helper-plugin-utils" "^7.18.6"
824 |
825 | "@babel/preset-env@^7.16.11":
826 | version "7.19.4"
827 | resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.19.4.tgz#4c91ce2e1f994f717efb4237891c3ad2d808c94b"
828 | integrity sha512-5QVOTXUdqTCjQuh2GGtdd7YEhoRXBMVGROAtsBeLGIbIz3obCBIfRMT1I3ZKkMgNzwkyCkftDXSSkHxnfVf4qg==
829 | dependencies:
830 | "@babel/compat-data" "^7.19.4"
831 | "@babel/helper-compilation-targets" "^7.19.3"
832 | "@babel/helper-plugin-utils" "^7.19.0"
833 | "@babel/helper-validator-option" "^7.18.6"
834 | "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression" "^7.18.6"
835 | "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining" "^7.18.9"
836 | "@babel/plugin-proposal-async-generator-functions" "^7.19.1"
837 | "@babel/plugin-proposal-class-properties" "^7.18.6"
838 | "@babel/plugin-proposal-class-static-block" "^7.18.6"
839 | "@babel/plugin-proposal-dynamic-import" "^7.18.6"
840 | "@babel/plugin-proposal-export-namespace-from" "^7.18.9"
841 | "@babel/plugin-proposal-json-strings" "^7.18.6"
842 | "@babel/plugin-proposal-logical-assignment-operators" "^7.18.9"
843 | "@babel/plugin-proposal-nullish-coalescing-operator" "^7.18.6"
844 | "@babel/plugin-proposal-numeric-separator" "^7.18.6"
845 | "@babel/plugin-proposal-object-rest-spread" "^7.19.4"
846 | "@babel/plugin-proposal-optional-catch-binding" "^7.18.6"
847 | "@babel/plugin-proposal-optional-chaining" "^7.18.9"
848 | "@babel/plugin-proposal-private-methods" "^7.18.6"
849 | "@babel/plugin-proposal-private-property-in-object" "^7.18.6"
850 | "@babel/plugin-proposal-unicode-property-regex" "^7.18.6"
851 | "@babel/plugin-syntax-async-generators" "^7.8.4"
852 | "@babel/plugin-syntax-class-properties" "^7.12.13"
853 | "@babel/plugin-syntax-class-static-block" "^7.14.5"
854 | "@babel/plugin-syntax-dynamic-import" "^7.8.3"
855 | "@babel/plugin-syntax-export-namespace-from" "^7.8.3"
856 | "@babel/plugin-syntax-import-assertions" "^7.18.6"
857 | "@babel/plugin-syntax-json-strings" "^7.8.3"
858 | "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4"
859 | "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3"
860 | "@babel/plugin-syntax-numeric-separator" "^7.10.4"
861 | "@babel/plugin-syntax-object-rest-spread" "^7.8.3"
862 | "@babel/plugin-syntax-optional-catch-binding" "^7.8.3"
863 | "@babel/plugin-syntax-optional-chaining" "^7.8.3"
864 | "@babel/plugin-syntax-private-property-in-object" "^7.14.5"
865 | "@babel/plugin-syntax-top-level-await" "^7.14.5"
866 | "@babel/plugin-transform-arrow-functions" "^7.18.6"
867 | "@babel/plugin-transform-async-to-generator" "^7.18.6"
868 | "@babel/plugin-transform-block-scoped-functions" "^7.18.6"
869 | "@babel/plugin-transform-block-scoping" "^7.19.4"
870 | "@babel/plugin-transform-classes" "^7.19.0"
871 | "@babel/plugin-transform-computed-properties" "^7.18.9"
872 | "@babel/plugin-transform-destructuring" "^7.19.4"
873 | "@babel/plugin-transform-dotall-regex" "^7.18.6"
874 | "@babel/plugin-transform-duplicate-keys" "^7.18.9"
875 | "@babel/plugin-transform-exponentiation-operator" "^7.18.6"
876 | "@babel/plugin-transform-for-of" "^7.18.8"
877 | "@babel/plugin-transform-function-name" "^7.18.9"
878 | "@babel/plugin-transform-literals" "^7.18.9"
879 | "@babel/plugin-transform-member-expression-literals" "^7.18.6"
880 | "@babel/plugin-transform-modules-amd" "^7.18.6"
881 | "@babel/plugin-transform-modules-commonjs" "^7.18.6"
882 | "@babel/plugin-transform-modules-systemjs" "^7.19.0"
883 | "@babel/plugin-transform-modules-umd" "^7.18.6"
884 | "@babel/plugin-transform-named-capturing-groups-regex" "^7.19.1"
885 | "@babel/plugin-transform-new-target" "^7.18.6"
886 | "@babel/plugin-transform-object-super" "^7.18.6"
887 | "@babel/plugin-transform-parameters" "^7.18.8"
888 | "@babel/plugin-transform-property-literals" "^7.18.6"
889 | "@babel/plugin-transform-regenerator" "^7.18.6"
890 | "@babel/plugin-transform-reserved-words" "^7.18.6"
891 | "@babel/plugin-transform-shorthand-properties" "^7.18.6"
892 | "@babel/plugin-transform-spread" "^7.19.0"
893 | "@babel/plugin-transform-sticky-regex" "^7.18.6"
894 | "@babel/plugin-transform-template-literals" "^7.18.9"
895 | "@babel/plugin-transform-typeof-symbol" "^7.18.9"
896 | "@babel/plugin-transform-unicode-escapes" "^7.18.10"
897 | "@babel/plugin-transform-unicode-regex" "^7.18.6"
898 | "@babel/preset-modules" "^0.1.5"
899 | "@babel/types" "^7.19.4"
900 | babel-plugin-polyfill-corejs2 "^0.3.3"
901 | babel-plugin-polyfill-corejs3 "^0.6.0"
902 | babel-plugin-polyfill-regenerator "^0.4.1"
903 | core-js-compat "^3.25.1"
904 | semver "^6.3.0"
905 |
906 | "@babel/preset-modules@^0.1.5":
907 | version "0.1.5"
908 | resolved "https://registry.yarnpkg.com/@babel/preset-modules/-/preset-modules-0.1.5.tgz#ef939d6e7f268827e1841638dc6ff95515e115d9"
909 | integrity sha512-A57th6YRG7oR3cq/yt/Y84MvGgE0eJG2F1JLhKuyG+jFxEgrd/HAMJatiFtmOiZurz+0DkrvbheCLaV5f2JfjA==
910 | dependencies:
911 | "@babel/helper-plugin-utils" "^7.0.0"
912 | "@babel/plugin-proposal-unicode-property-regex" "^7.4.4"
913 | "@babel/plugin-transform-dotall-regex" "^7.4.4"
914 | "@babel/types" "^7.4.4"
915 | esutils "^2.0.2"
916 |
917 | "@babel/preset-react@^7.16.7":
918 | version "7.18.6"
919 | resolved "https://registry.yarnpkg.com/@babel/preset-react/-/preset-react-7.18.6.tgz#979f76d6277048dc19094c217b507f3ad517dd2d"
920 | integrity sha512-zXr6atUmyYdiWRVLOZahakYmOBHtWc2WGCkP8PYTgZi0iJXDY2CN180TdrIW4OGOAdLc7TifzDIvtx6izaRIzg==
921 | dependencies:
922 | "@babel/helper-plugin-utils" "^7.18.6"
923 | "@babel/helper-validator-option" "^7.18.6"
924 | "@babel/plugin-transform-react-display-name" "^7.18.6"
925 | "@babel/plugin-transform-react-jsx" "^7.18.6"
926 | "@babel/plugin-transform-react-jsx-development" "^7.18.6"
927 | "@babel/plugin-transform-react-pure-annotations" "^7.18.6"
928 |
929 | "@babel/runtime@^7.8.4":
930 | version "7.19.4"
931 | resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.19.4.tgz#a42f814502ee467d55b38dd1c256f53a7b885c78"
932 | integrity sha512-EXpLCrk55f+cYqmHsSR+yD/0gAIMxxA9QK9lnQWzhMCvt+YmoBN7Zx94s++Kv0+unHk39vxNO8t+CMA2WSS3wA==
933 | dependencies:
934 | regenerator-runtime "^0.13.4"
935 |
936 | "@babel/template@^7.18.10":
937 | version "7.18.10"
938 | resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.18.10.tgz#6f9134835970d1dbf0835c0d100c9f38de0c5e71"
939 | integrity sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA==
940 | dependencies:
941 | "@babel/code-frame" "^7.18.6"
942 | "@babel/parser" "^7.18.10"
943 | "@babel/types" "^7.18.10"
944 |
945 | "@babel/traverse@^7.19.0", "@babel/traverse@^7.19.1", "@babel/traverse@^7.19.3", "@babel/traverse@^7.19.4":
946 | version "7.19.4"
947 | resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.19.4.tgz#f117820e18b1e59448a6c1fa9d0ff08f7ac459a8"
948 | integrity sha512-w3K1i+V5u2aJUOXBFFC5pveFLmtq1s3qcdDNC2qRI6WPBQIDaKFqXxDEqDO/h1dQ3HjsZoZMyIy6jGLq0xtw+g==
949 | dependencies:
950 | "@babel/code-frame" "^7.18.6"
951 | "@babel/generator" "^7.19.4"
952 | "@babel/helper-environment-visitor" "^7.18.9"
953 | "@babel/helper-function-name" "^7.19.0"
954 | "@babel/helper-hoist-variables" "^7.18.6"
955 | "@babel/helper-split-export-declaration" "^7.18.6"
956 | "@babel/parser" "^7.19.4"
957 | "@babel/types" "^7.19.4"
958 | debug "^4.1.0"
959 | globals "^11.1.0"
960 |
961 | "@babel/types@^7.18.10", "@babel/types@^7.18.6", "@babel/types@^7.18.9", "@babel/types@^7.19.0", "@babel/types@^7.19.3", "@babel/types@^7.19.4", "@babel/types@^7.4.4":
962 | version "7.19.4"
963 | resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.19.4.tgz#0dd5c91c573a202d600490a35b33246fed8a41c7"
964 | integrity sha512-M5LK7nAeS6+9j7hAq+b3fQs+pNfUtTGq+yFFfHnauFA8zQtLRfmuipmsKDKKLuyG+wC8ABW43A153YNawNTEtw==
965 | dependencies:
966 | "@babel/helper-string-parser" "^7.19.4"
967 | "@babel/helper-validator-identifier" "^7.19.1"
968 | to-fast-properties "^2.0.0"
969 |
970 | "@jridgewell/gen-mapping@^0.1.0":
971 | version "0.1.1"
972 | resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz#e5d2e450306a9491e3bd77e323e38d7aff315996"
973 | integrity sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==
974 | dependencies:
975 | "@jridgewell/set-array" "^1.0.0"
976 | "@jridgewell/sourcemap-codec" "^1.4.10"
977 |
978 | "@jridgewell/gen-mapping@^0.3.2":
979 | version "0.3.2"
980 | resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz#c1aedc61e853f2bb9f5dfe6d4442d3b565b253b9"
981 | integrity sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==
982 | dependencies:
983 | "@jridgewell/set-array" "^1.0.1"
984 | "@jridgewell/sourcemap-codec" "^1.4.10"
985 | "@jridgewell/trace-mapping" "^0.3.9"
986 |
987 | "@jridgewell/resolve-uri@3.1.0":
988 | version "3.1.0"
989 | resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz#2203b118c157721addfe69d47b70465463066d78"
990 | integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==
991 |
992 | "@jridgewell/set-array@^1.0.0", "@jridgewell/set-array@^1.0.1":
993 | version "1.1.2"
994 | resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72"
995 | integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==
996 |
997 | "@jridgewell/sourcemap-codec@1.4.14", "@jridgewell/sourcemap-codec@^1.4.10":
998 | version "1.4.14"
999 | resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24"
1000 | integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==
1001 |
1002 | "@jridgewell/trace-mapping@^0.3.9":
1003 | version "0.3.16"
1004 | resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.16.tgz#a7982f16c18cae02be36274365433e5b49d7b23f"
1005 | integrity sha512-LCQ+NeThyJ4k1W2d+vIKdxuSt9R3pQSZ4P92m7EakaYuXcVWbHuT5bjNcqLd4Rdgi6xYWYDvBJZJLZSLanjDcA==
1006 | dependencies:
1007 | "@jridgewell/resolve-uri" "3.1.0"
1008 | "@jridgewell/sourcemap-codec" "1.4.14"
1009 |
1010 | "@rollup/plugin-babel@^5.3.1":
1011 | version "5.3.1"
1012 | resolved "https://registry.yarnpkg.com/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz#04bc0608f4aa4b2e4b1aebf284344d0f68fda283"
1013 | integrity sha512-WFfdLWU/xVWKeRQnKmIAQULUI7Il0gZnBIH/ZFO069wYIfPu+8zrfp/KMW0atmELoRDq8FbiP3VCss9MhCut7Q==
1014 | dependencies:
1015 | "@babel/helper-module-imports" "^7.10.4"
1016 | "@rollup/pluginutils" "^3.1.0"
1017 |
1018 | "@rollup/plugin-node-resolve@^13.1.3":
1019 | version "13.3.0"
1020 | resolved "https://registry.yarnpkg.com/@rollup/plugin-node-resolve/-/plugin-node-resolve-13.3.0.tgz#da1c5c5ce8316cef96a2f823d111c1e4e498801c"
1021 | integrity sha512-Lus8rbUo1eEcnS4yTFKLZrVumLPY+YayBdWXgFSHYhTT2iJbMhoaaBL3xl5NCdeRytErGr8tZ0L71BMRmnlwSw==
1022 | dependencies:
1023 | "@rollup/pluginutils" "^3.1.0"
1024 | "@types/resolve" "1.17.1"
1025 | deepmerge "^4.2.2"
1026 | is-builtin-module "^3.1.0"
1027 | is-module "^1.0.0"
1028 | resolve "^1.19.0"
1029 |
1030 | "@rollup/pluginutils@^3.1.0":
1031 | version "3.1.0"
1032 | resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-3.1.0.tgz#706b4524ee6dc8b103b3c995533e5ad680c02b9b"
1033 | integrity sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==
1034 | dependencies:
1035 | "@types/estree" "0.0.39"
1036 | estree-walker "^1.0.1"
1037 | picomatch "^2.2.2"
1038 |
1039 | "@types/estree@0.0.39":
1040 | version "0.0.39"
1041 | resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.39.tgz#e177e699ee1b8c22d23174caaa7422644389509f"
1042 | integrity sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==
1043 |
1044 | "@types/node@*":
1045 | version "18.8.3"
1046 | resolved "https://registry.yarnpkg.com/@types/node/-/node-18.8.3.tgz#ce750ab4017effa51aed6a7230651778d54e327c"
1047 | integrity sha512-0os9vz6BpGwxGe9LOhgP/ncvYN5Tx1fNcd2TM3rD/aCGBkysb+ZWpXEocG24h6ZzOi13+VB8HndAQFezsSOw1w==
1048 |
1049 | "@types/resolve@1.17.1":
1050 | version "1.17.1"
1051 | resolved "https://registry.yarnpkg.com/@types/resolve/-/resolve-1.17.1.tgz#3afd6ad8967c77e4376c598a82ddd58f46ec45d6"
1052 | integrity sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==
1053 | dependencies:
1054 | "@types/node" "*"
1055 |
1056 | ansi-styles@^3.2.1:
1057 | version "3.2.1"
1058 | resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d"
1059 | integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==
1060 | dependencies:
1061 | color-convert "^1.9.0"
1062 |
1063 | babel-plugin-dynamic-import-node@^2.3.3:
1064 | version "2.3.3"
1065 | resolved "https://registry.yarnpkg.com/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz#84fda19c976ec5c6defef57f9427b3def66e17a3"
1066 | integrity sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==
1067 | dependencies:
1068 | object.assign "^4.1.0"
1069 |
1070 | babel-plugin-polyfill-corejs2@^0.3.3:
1071 | version "0.3.3"
1072 | resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.3.tgz#5d1bd3836d0a19e1b84bbf2d9640ccb6f951c122"
1073 | integrity sha512-8hOdmFYFSZhqg2C/JgLUQ+t52o5nirNwaWM2B9LWteozwIvM14VSwdsCAUET10qT+kmySAlseadmfeeSWFCy+Q==
1074 | dependencies:
1075 | "@babel/compat-data" "^7.17.7"
1076 | "@babel/helper-define-polyfill-provider" "^0.3.3"
1077 | semver "^6.1.1"
1078 |
1079 | babel-plugin-polyfill-corejs3@^0.6.0:
1080 | version "0.6.0"
1081 | resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.6.0.tgz#56ad88237137eade485a71b52f72dbed57c6230a"
1082 | integrity sha512-+eHqR6OPcBhJOGgsIar7xoAB1GcSwVUA3XjAd7HJNzOXT4wv6/H7KIdA/Nc60cvUlDbKApmqNvD1B1bzOt4nyA==
1083 | dependencies:
1084 | "@babel/helper-define-polyfill-provider" "^0.3.3"
1085 | core-js-compat "^3.25.1"
1086 |
1087 | babel-plugin-polyfill-regenerator@^0.4.1:
1088 | version "0.4.1"
1089 | resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.4.1.tgz#390f91c38d90473592ed43351e801a9d3e0fd747"
1090 | integrity sha512-NtQGmyQDXjQqQ+IzRkBVwEOz9lQ4zxAQZgoAYEtU9dJjnl1Oc98qnN7jcp+bE7O7aYzVpavXE3/VKXNzUbh7aw==
1091 | dependencies:
1092 | "@babel/helper-define-polyfill-provider" "^0.3.3"
1093 |
1094 | browserslist@^4.21.3, browserslist@^4.21.4:
1095 | version "4.21.4"
1096 | resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.21.4.tgz#e7496bbc67b9e39dd0f98565feccdcb0d4ff6987"
1097 | integrity sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==
1098 | dependencies:
1099 | caniuse-lite "^1.0.30001400"
1100 | electron-to-chromium "^1.4.251"
1101 | node-releases "^2.0.6"
1102 | update-browserslist-db "^1.0.9"
1103 |
1104 | builtin-modules@^3.3.0:
1105 | version "3.3.0"
1106 | resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-3.3.0.tgz#cae62812b89801e9656336e46223e030386be7b6"
1107 | integrity sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==
1108 |
1109 | call-bind@^1.0.2:
1110 | version "1.0.2"
1111 | resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c"
1112 | integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==
1113 | dependencies:
1114 | function-bind "^1.1.1"
1115 | get-intrinsic "^1.0.2"
1116 |
1117 | caniuse-lite@^1.0.30001400:
1118 | version "1.0.30001418"
1119 | resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001418.tgz#5f459215192a024c99e3e3a53aac310fc7cf24e6"
1120 | integrity sha512-oIs7+JL3K9JRQ3jPZjlH6qyYDp+nBTCais7hjh0s+fuBwufc7uZ7hPYMXrDOJhV360KGMTcczMRObk0/iMqZRg==
1121 |
1122 | chalk@^2.0.0:
1123 | version "2.4.2"
1124 | resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
1125 | integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
1126 | dependencies:
1127 | ansi-styles "^3.2.1"
1128 | escape-string-regexp "^1.0.5"
1129 | supports-color "^5.3.0"
1130 |
1131 | color-convert@^1.9.0:
1132 | version "1.9.3"
1133 | resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8"
1134 | integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==
1135 | dependencies:
1136 | color-name "1.1.3"
1137 |
1138 | color-name@1.1.3:
1139 | version "1.1.3"
1140 | resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
1141 | integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==
1142 |
1143 | convert-source-map@^1.7.0:
1144 | version "1.8.0"
1145 | resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.8.0.tgz#f3373c32d21b4d780dd8004514684fb791ca4369"
1146 | integrity sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==
1147 | dependencies:
1148 | safe-buffer "~5.1.1"
1149 |
1150 | core-js-compat@^3.25.1:
1151 | version "3.25.5"
1152 | resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.25.5.tgz#0016e8158c904f7b059486639e6e82116eafa7d9"
1153 | integrity sha512-ovcyhs2DEBUIE0MGEKHP4olCUW/XYte3Vroyxuh38rD1wAO4dHohsovUC4eAOuzFxE6b+RXvBU3UZ9o0YhUTkA==
1154 | dependencies:
1155 | browserslist "^4.21.4"
1156 |
1157 | debug@^4.1.0, debug@^4.1.1:
1158 | version "4.3.4"
1159 | resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865"
1160 | integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==
1161 | dependencies:
1162 | ms "2.1.2"
1163 |
1164 | deepmerge@^4.2.2:
1165 | version "4.2.2"
1166 | resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955"
1167 | integrity sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==
1168 |
1169 | default-passive-events@^2.0.0:
1170 | version "2.0.0"
1171 | resolved "https://registry.yarnpkg.com/default-passive-events/-/default-passive-events-2.0.0.tgz#79b1aa67becbaab38b718469b5480fef92eda649"
1172 | integrity sha512-eMtt76GpDVngZQ3ocgvRcNCklUMwID1PaNbCNxfpDXuiOXttSh0HzBbda1HU9SIUsDc02vb7g9+3I5tlqe/qMQ==
1173 |
1174 | define-properties@^1.1.4:
1175 | version "1.1.4"
1176 | resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.4.tgz#0b14d7bd7fbeb2f3572c3a7eda80ea5d57fb05b1"
1177 | integrity sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==
1178 | dependencies:
1179 | has-property-descriptors "^1.0.0"
1180 | object-keys "^1.1.1"
1181 |
1182 | electron-to-chromium@^1.4.251:
1183 | version "1.4.276"
1184 | resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.276.tgz#17837b19dafcc43aba885c4689358b298c19b520"
1185 | integrity sha512-EpuHPqu8YhonqLBXHoU6hDJCD98FCe6KDoet3/gY1qsQ6usjJoHqBH2YIVs8FXaAtHwVL8Uqa/fsYao/vq9VWQ==
1186 |
1187 | escalade@^3.1.1:
1188 | version "3.1.1"
1189 | resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40"
1190 | integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==
1191 |
1192 | escape-string-regexp@^1.0.5:
1193 | version "1.0.5"
1194 | resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
1195 | integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==
1196 |
1197 | estree-walker@^1.0.1:
1198 | version "1.0.1"
1199 | resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-1.0.1.tgz#31bc5d612c96b704106b477e6dd5d8aa138cb700"
1200 | integrity sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==
1201 |
1202 | esutils@^2.0.2:
1203 | version "2.0.3"
1204 | resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64"
1205 | integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==
1206 |
1207 | fsevents@~2.3.2:
1208 | version "2.3.2"
1209 | resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a"
1210 | integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==
1211 |
1212 | function-bind@^1.1.1:
1213 | version "1.1.1"
1214 | resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
1215 | integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==
1216 |
1217 | gensync@^1.0.0-beta.2:
1218 | version "1.0.0-beta.2"
1219 | resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0"
1220 | integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==
1221 |
1222 | get-intrinsic@^1.0.2, get-intrinsic@^1.1.1:
1223 | version "1.1.3"
1224 | resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.3.tgz#063c84329ad93e83893c7f4f243ef63ffa351385"
1225 | integrity sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==
1226 | dependencies:
1227 | function-bind "^1.1.1"
1228 | has "^1.0.3"
1229 | has-symbols "^1.0.3"
1230 |
1231 | globals@^11.1.0:
1232 | version "11.12.0"
1233 | resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e"
1234 | integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==
1235 |
1236 | has-flag@^3.0.0:
1237 | version "3.0.0"
1238 | resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
1239 | integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==
1240 |
1241 | has-property-descriptors@^1.0.0:
1242 | version "1.0.0"
1243 | resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz#610708600606d36961ed04c196193b6a607fa861"
1244 | integrity sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==
1245 | dependencies:
1246 | get-intrinsic "^1.1.1"
1247 |
1248 | has-symbols@^1.0.3:
1249 | version "1.0.3"
1250 | resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8"
1251 | integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==
1252 |
1253 | has@^1.0.3:
1254 | version "1.0.3"
1255 | resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796"
1256 | integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==
1257 | dependencies:
1258 | function-bind "^1.1.1"
1259 |
1260 | is-builtin-module@^3.1.0:
1261 | version "3.2.0"
1262 | resolved "https://registry.yarnpkg.com/is-builtin-module/-/is-builtin-module-3.2.0.tgz#bb0310dfe881f144ca83f30100ceb10cf58835e0"
1263 | integrity sha512-phDA4oSGt7vl1n5tJvTWooWWAsXLY+2xCnxNqvKhGEzujg+A43wPlPOyDg3C8XQHN+6k/JTQWJ/j0dQh/qr+Hw==
1264 | dependencies:
1265 | builtin-modules "^3.3.0"
1266 |
1267 | is-core-module@^2.9.0:
1268 | version "2.10.0"
1269 | resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.10.0.tgz#9012ede0a91c69587e647514e1d5277019e728ed"
1270 | integrity sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg==
1271 | dependencies:
1272 | has "^1.0.3"
1273 |
1274 | is-module@^1.0.0:
1275 | version "1.0.0"
1276 | resolved "https://registry.yarnpkg.com/is-module/-/is-module-1.0.0.tgz#3258fb69f78c14d5b815d664336b4cffb6441591"
1277 | integrity sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==
1278 |
1279 | js-tokens@^4.0.0:
1280 | version "4.0.0"
1281 | resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
1282 | integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
1283 |
1284 | jsesc@^2.5.1:
1285 | version "2.5.2"
1286 | resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4"
1287 | integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==
1288 |
1289 | jsesc@~0.5.0:
1290 | version "0.5.0"
1291 | resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d"
1292 | integrity sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==
1293 |
1294 | json5@^2.2.1:
1295 | version "2.2.1"
1296 | resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.1.tgz#655d50ed1e6f95ad1a3caababd2b0efda10b395c"
1297 | integrity sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==
1298 |
1299 | lodash.debounce@^4.0.8:
1300 | version "4.0.8"
1301 | resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af"
1302 | integrity sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==
1303 |
1304 | ms@2.1.2:
1305 | version "2.1.2"
1306 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
1307 | integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
1308 |
1309 | node-releases@^2.0.6:
1310 | version "2.0.6"
1311 | resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.6.tgz#8a7088c63a55e493845683ebf3c828d8c51c5503"
1312 | integrity sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==
1313 |
1314 | object-keys@^1.1.1:
1315 | version "1.1.1"
1316 | resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e"
1317 | integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==
1318 |
1319 | object.assign@^4.1.0:
1320 | version "4.1.4"
1321 | resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.4.tgz#9673c7c7c351ab8c4d0b516f4343ebf4dfb7799f"
1322 | integrity sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==
1323 | dependencies:
1324 | call-bind "^1.0.2"
1325 | define-properties "^1.1.4"
1326 | has-symbols "^1.0.3"
1327 | object-keys "^1.1.1"
1328 |
1329 | path-parse@^1.0.7:
1330 | version "1.0.7"
1331 | resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735"
1332 | integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==
1333 |
1334 | picocolors@^1.0.0:
1335 | version "1.0.0"
1336 | resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c"
1337 | integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==
1338 |
1339 | picomatch@^2.2.2:
1340 | version "2.3.1"
1341 | resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42"
1342 | integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==
1343 |
1344 | regenerate-unicode-properties@^10.1.0:
1345 | version "10.1.0"
1346 | resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.0.tgz#7c3192cab6dd24e21cb4461e5ddd7dd24fa8374c"
1347 | integrity sha512-d1VudCLoIGitcU/hEg2QqvyGZQmdC0Lf8BqdOMXGFSvJP4bNV1+XqbPQeHHLD51Jh4QJJ225dlIFvY4Ly6MXmQ==
1348 | dependencies:
1349 | regenerate "^1.4.2"
1350 |
1351 | regenerate@^1.4.2:
1352 | version "1.4.2"
1353 | resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.2.tgz#b9346d8827e8f5a32f7ba29637d398b69014848a"
1354 | integrity sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==
1355 |
1356 | regenerator-runtime@^0.13.4:
1357 | version "0.13.9"
1358 | resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz#8925742a98ffd90814988d7566ad30ca3b263b52"
1359 | integrity sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==
1360 |
1361 | regenerator-transform@^0.15.0:
1362 | version "0.15.0"
1363 | resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.15.0.tgz#cbd9ead5d77fae1a48d957cf889ad0586adb6537"
1364 | integrity sha512-LsrGtPmbYg19bcPHwdtmXwbW+TqNvtY4riE3P83foeHRroMbH6/2ddFBfab3t7kbzc7v7p4wbkIecHImqt0QNg==
1365 | dependencies:
1366 | "@babel/runtime" "^7.8.4"
1367 |
1368 | regexpu-core@^5.1.0:
1369 | version "5.2.1"
1370 | resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-5.2.1.tgz#a69c26f324c1e962e9ffd0b88b055caba8089139"
1371 | integrity sha512-HrnlNtpvqP1Xkb28tMhBUO2EbyUHdQlsnlAhzWcwHy8WJR53UWr7/MAvqrsQKMbV4qdpv03oTMG8iIhfsPFktQ==
1372 | dependencies:
1373 | regenerate "^1.4.2"
1374 | regenerate-unicode-properties "^10.1.0"
1375 | regjsgen "^0.7.1"
1376 | regjsparser "^0.9.1"
1377 | unicode-match-property-ecmascript "^2.0.0"
1378 | unicode-match-property-value-ecmascript "^2.0.0"
1379 |
1380 | regjsgen@^0.7.1:
1381 | version "0.7.1"
1382 | resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.7.1.tgz#ee5ef30e18d3f09b7c369b76e7c2373ed25546f6"
1383 | integrity sha512-RAt+8H2ZEzHeYWxZ3H2z6tF18zyyOnlcdaafLrm21Bguj7uZy6ULibiAFdXEtKQY4Sy7wDTwDiOazasMLc4KPA==
1384 |
1385 | regjsparser@^0.9.1:
1386 | version "0.9.1"
1387 | resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.9.1.tgz#272d05aa10c7c1f67095b1ff0addae8442fc5709"
1388 | integrity sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==
1389 | dependencies:
1390 | jsesc "~0.5.0"
1391 |
1392 | resolve@^1.14.2, resolve@^1.19.0:
1393 | version "1.22.1"
1394 | resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.1.tgz#27cb2ebb53f91abb49470a928bba7558066ac177"
1395 | integrity sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==
1396 | dependencies:
1397 | is-core-module "^2.9.0"
1398 | path-parse "^1.0.7"
1399 | supports-preserve-symlinks-flag "^1.0.0"
1400 |
1401 | rollup@^2.70.1:
1402 | version "2.79.1"
1403 | resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.79.1.tgz#bedee8faef7c9f93a2647ac0108748f497f081c7"
1404 | integrity sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==
1405 | optionalDependencies:
1406 | fsevents "~2.3.2"
1407 |
1408 | safe-buffer@~5.1.1:
1409 | version "5.1.2"
1410 | resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
1411 | integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
1412 |
1413 | semver@^6.1.1, semver@^6.1.2, semver@^6.3.0:
1414 | version "6.3.0"
1415 | resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
1416 | integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==
1417 |
1418 | supports-color@^5.3.0:
1419 | version "5.5.0"
1420 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f"
1421 | integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==
1422 | dependencies:
1423 | has-flag "^3.0.0"
1424 |
1425 | supports-preserve-symlinks-flag@^1.0.0:
1426 | version "1.0.0"
1427 | resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09"
1428 | integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==
1429 |
1430 | to-fast-properties@^2.0.0:
1431 | version "2.0.0"
1432 | resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e"
1433 | integrity sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==
1434 |
1435 | unicode-canonical-property-names-ecmascript@^2.0.0:
1436 | version "2.0.0"
1437 | resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz#301acdc525631670d39f6146e0e77ff6bbdebddc"
1438 | integrity sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==
1439 |
1440 | unicode-match-property-ecmascript@^2.0.0:
1441 | version "2.0.0"
1442 | resolved "https://registry.yarnpkg.com/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz#54fd16e0ecb167cf04cf1f756bdcc92eba7976c3"
1443 | integrity sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==
1444 | dependencies:
1445 | unicode-canonical-property-names-ecmascript "^2.0.0"
1446 | unicode-property-aliases-ecmascript "^2.0.0"
1447 |
1448 | unicode-match-property-value-ecmascript@^2.0.0:
1449 | version "2.0.0"
1450 | resolved "https://registry.yarnpkg.com/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.0.0.tgz#1a01aa57247c14c568b89775a54938788189a714"
1451 | integrity sha512-7Yhkc0Ye+t4PNYzOGKedDhXbYIBe1XEQYQxOPyhcXNMJ0WCABqqj6ckydd6pWRZTHV4GuCPKdBAUiMc60tsKVw==
1452 |
1453 | unicode-property-aliases-ecmascript@^2.0.0:
1454 | version "2.1.0"
1455 | resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz#43d41e3be698bd493ef911077c9b131f827e8ccd"
1456 | integrity sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==
1457 |
1458 | update-browserslist-db@^1.0.9:
1459 | version "1.0.10"
1460 | resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz#0f54b876545726f17d00cd9a2561e6dade943ff3"
1461 | integrity sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==
1462 | dependencies:
1463 | escalade "^3.1.1"
1464 | picocolors "^1.0.0"
1465 |
--------------------------------------------------------------------------------