diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 0000000..0808c4f --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,33 @@ +module.exports = { + env: { + browser: true, + es2020: true, + }, + extends: [ + "airbnb-base", + "plugin:@typescript-eslint/recommended", + "plugin:prettier/recommended", + ], + parser: "@typescript-eslint/parser", + plugins: ["@typescript-eslint", "prettier", "react-hooks"], + rules: { + "prettier/prettier": "error", + "one-var": "off", // WHO CARES????? + "no-use-before-define": "off", // YOU ARE WRONG + "import/extensions": "off", + "import/no-unresolved": "off", + "no-param-reassign": "off", + "no-alert": "off", + "no-console": "off", + "func-names": "off", + "dot-notation": ["error", { allowPattern: "^[A-Z][a-z]+$" }], + "@typescript-eslint/ban-ts-comment": [ + "error", + { + "ts-expect-error": "allow-with-description", + }, + ], + "react-hooks/rules-of-hooks": "error", + "react-hooks/exhaustive-deps": "warn", + }, +}; diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..feda119 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,4 @@ +{ + "singleQuote": false, + "endOfLine": "auto" +} diff --git a/assets/images/logos/logo.svg b/assets/images/logos/logo.svg new file mode 100644 index 0000000..d1da010 --- /dev/null +++ b/assets/images/logos/logo.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/assets/images/logos/spinner.svg b/assets/images/logos/spinner.svg new file mode 100644 index 0000000..b032ba3 --- /dev/null +++ b/assets/images/logos/spinner.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/package.json b/package.json index 79517f0..9a770d9 100644 --- a/package.json +++ b/package.json @@ -5,16 +5,22 @@ "license": "MIT", "dependencies": { "@inlet/react-pixi": "^5.1.4", + "@reduxjs/toolkit": "^1.4.0", "@types/howler": "^2.2.1", "@types/react": "^16.9.49", "@types/react-dom": "^16.9.8", + "@types/react-redux": "^7.1.9", "animejs": "^3.2.0", + "eslint-plugin-react-hooks": "^4.1.2", "hotkeys-js": "^3.8.1", "howler": "^2.2.0", "parcel-bundler": "^1.12.4", "pixi.js": "^5.3.3", "react": "^16.13.1", "react-dom": "^16.13.1", + "react-redux": "^7.2.1", + "redux": "^4.0.5", + "redux-devtools-extension": "^2.13.8", "typescript": "^4.0.3" }, "scripts": { diff --git a/src/game/lib/hook.ts b/src/game/lib/hook.ts deleted file mode 100644 index e69de29..0000000 diff --git a/src/game/lib/loader.tsx b/src/game/lib/loader.tsx new file mode 100644 index 0000000..621c0d1 --- /dev/null +++ b/src/game/lib/loader.tsx @@ -0,0 +1,29 @@ +import { Loader, ILoaderOptions } from "pixi.js"; +import { useEffect, useState } from "react"; + +export type ResourceList = Record< + string, + string | { name: string; options: ILoaderOptions } +>; + +export default function useLoader(resources: ResourceList) { + const loader = new Loader(); + + const [state, setState] = useState({ loaded: false, resources: null }); + + useEffect(() => { + for (const res in resources) { + const param = resources[res]; + if (typeof param === "string") { + loader.add(res, param); + } else { + loader.add(res, param.name, param.options); + } + } + loader.load((loader, resources) => { + setState({ loaded: true, resources }); + }); + }, []); + + return state; +} diff --git a/src/game/scenes/Game.tsx b/src/game/scenes/Game.tsx new file mode 100644 index 0000000..5fb1c6a --- /dev/null +++ b/src/game/scenes/Game.tsx @@ -0,0 +1,32 @@ +import React, { Fragment } from "react"; +import useLoader from "~game/lib/Loader"; +import InGameSpaceBG from "./backgrounds/InGameSpaceBG"; + +// Resources, this will make TS go crazy! + +//@ts-expect-error Image resource +import NoiseSpaceFine from "~/../assets/images/noise/space_fine.png"; +//@ts-expect-error Image resource +import NoiseSpaceSparse from "~/../assets/images/noise/space_sparse.png"; + +export default function Game() { + const { loaded, resources } = useLoader({ + bg_fine: NoiseSpaceFine, + bg_sparse: NoiseSpaceSparse, + }); + + if (!loaded) { + return ; + } + + return ( + + + + ); +} diff --git a/src/game/scenes/LoadingScreen.tsx b/src/game/scenes/LoadingScreen.tsx new file mode 100644 index 0000000..885bdc9 --- /dev/null +++ b/src/game/scenes/LoadingScreen.tsx @@ -0,0 +1,5 @@ +import React, { Fragment } from "react"; + +export default function LoadingScreen() { + return ; +} diff --git a/src/game/scenes/MapEditor.tsx b/src/game/scenes/MapEditor.tsx new file mode 100644 index 0000000..023d186 --- /dev/null +++ b/src/game/scenes/MapEditor.tsx @@ -0,0 +1,35 @@ +import React, { Fragment } from "react"; +import useLoader from "~game/lib/Loader"; +import InGameSpaceBG from "./backgrounds/InGameSpaceBG"; + +// Resources, this will make TS go crazy! + +//@ts-expect-error Image resource +import NoiseSpaceFine from "~/../assets/images/noise/space_fine.png"; +//@ts-expect-error Image resource +import NoiseSpaceSparse from "~/../assets/images/noise/space_sparse.png"; +import LoadingScreen from "./LoadingScreen"; +import useUILayer from "~ui/utils/useLayer"; + +export default function MapEditor() { + const { loaded, resources } = useLoader({ + bg_fine: NoiseSpaceFine, + bg_sparse: NoiseSpaceSparse, + }); + const id = useUILayer({ type: "MapEditor" }, loaded); + + if (!loaded) { + return ; + } + + return ( + + + + ); +} diff --git a/src/game/scenes/TitleScreen.tsx b/src/game/scenes/TitleScreen.tsx new file mode 100644 index 0000000..1c03b54 --- /dev/null +++ b/src/game/scenes/TitleScreen.tsx @@ -0,0 +1,10 @@ +import React, { Fragment } from "react"; +import MenuBackground from "./backgrounds/MenuBackground"; + +export default function TitleScreen() { + return ( + + + + ); +} diff --git a/src/game/scenes/backgrounds/InGameSpaceBG.tsx b/src/game/scenes/backgrounds/InGameSpaceBG.tsx new file mode 100644 index 0000000..e8c2229 --- /dev/null +++ b/src/game/scenes/backgrounds/InGameSpaceBG.tsx @@ -0,0 +1,30 @@ +import React, { useEffect } from "react"; +import { Sprite, useApp, useTick } from "@inlet/react-pixi"; +import InGameSpace, { SpaceTextures } from "~graphics/filters/InGameSpace"; + +export interface InGameSpaceBGProps { + textures: SpaceTextures; +} + +export default function InGameSpaceBG({ textures }: InGameSpaceBGProps) { + const app = useApp(); + const scale = 1; + const menubg = new InGameSpace(app.renderer, scale, textures); + + useTick((delta) => { + menubg.update(delta); + menubg.render(); + }); + + useEffect(() => { + const handleResize = () => { + menubg.rescale(scale); + }; + app.renderer.on("resize", handleResize); + return () => { + app.renderer.off("resize", handleResize); + }; + }); + + return ; +} diff --git a/src/game/MenuBackground.tsx b/src/game/scenes/backgrounds/MenuBackground.tsx similarity index 53% rename from src/game/MenuBackground.tsx rename to src/game/scenes/backgrounds/MenuBackground.tsx index 79740e1..10afd06 100644 --- a/src/game/MenuBackground.tsx +++ b/src/game/scenes/backgrounds/MenuBackground.tsx @@ -1,5 +1,5 @@ -import * as React from "react"; -import MenuBackgroundFilter from "../graphics/filters/MenuBackground"; +import React, { useEffect } from "react"; +import MenuBackgroundFilter from "~graphics/filters/MenuBackground"; import { Sprite, useApp, useTick } from "@inlet/react-pixi"; export default function () { @@ -12,8 +12,14 @@ export default function () { menubg.render(); }); - window.addEventListener("resize", () => { - menubg.rescale(scale); + useEffect(() => { + const handleResize = () => { + menubg.rescale(scale); + }; + app.renderer.on("resize", handleResize); + return () => { + app.renderer.off("resize", handleResize); + }; }); return ; diff --git a/src/graphics/filters/InGameSpace.ts b/src/graphics/filters/InGameSpace.ts index e69de29..3edb86e 100644 --- a/src/graphics/filters/InGameSpace.ts +++ b/src/graphics/filters/InGameSpace.ts @@ -0,0 +1,49 @@ +import { Filter, Renderer, Texture, WRAP_MODES } from "pixi.js"; +import RTTShader from "../utils/RTTShader"; + +//@ts-expect-error Frag file +import filter_src from "./frag/InGameSpace.frag"; + +export interface SpaceTextures { + noise_sparse; + noise_fine; +} + +export default class InGameSpaceFilter extends RTTShader { + private elapsed: number; + private filter: Filter; + + constructor(renderer: Renderer, scale: number, textures: SpaceTextures) { + const noise_sparse = textures.noise_sparse.texture as Texture; + const noise_fine = textures.noise_fine.texture as Texture; + + noise_sparse.baseTexture.wrapMode = WRAP_MODES.REPEAT; + noise_fine.baseTexture.wrapMode = WRAP_MODES.REPEAT; + + const filter = new Filter(null, filter_src, { + time: 0, + ires: [renderer.width / scale, renderer.height / scale], + noise_sparse, + noise_fine, + scroll_speed: 0, + warp_boost: 0, + warp_opacity: 0, + }); + super(renderer, filter, scale); + this.elapsed = 0; + this.filter = filter; + } + + rescale(scale: number) { + super.rescale(scale); + this.filter.uniforms.ires = [ + this.renderer.width / scale, + this.renderer.height / scale, + ]; + } + + update(delta: number) { + this.filter.uniforms.time = this.elapsed; + this.elapsed += delta / 60; + } +} diff --git a/src/graphics/filters/MenuBackground.tsx b/src/graphics/filters/MenuBackground.ts similarity index 79% rename from src/graphics/filters/MenuBackground.tsx rename to src/graphics/filters/MenuBackground.ts index 5c78788..efc1da0 100644 --- a/src/graphics/filters/MenuBackground.tsx +++ b/src/graphics/filters/MenuBackground.ts @@ -1,4 +1,4 @@ -import * as PIXI from "pixi.js"; +import { Filter, Renderer } from "pixi.js"; import RTTShader from "../utils/RTTShader"; //@ts-expect-error Frag file @@ -6,10 +6,10 @@ import filter_src from "./frag/MenuBackground.frag"; export default class MenuBackgroundFilter extends RTTShader { private elapsed: number; - private filter: PIXI.Filter; + private filter: Filter; - constructor(renderer: PIXI.Renderer, scale: number) { - const filter = new PIXI.Filter(null, filter_src, { + constructor(renderer: Renderer, scale: number) { + const filter = new Filter(null, filter_src, { iTime: 0, iResolution: [renderer.width / scale, renderer.height / scale], }); diff --git a/src/graphics/filters/frag/InGameSpace.frag b/src/graphics/filters/frag/InGameSpace.frag index be47c81..a5efdd3 100644 --- a/src/graphics/filters/frag/InGameSpace.frag +++ b/src/graphics/filters/frag/InGameSpace.frag @@ -3,26 +3,26 @@ precision mediump float; uniform sampler2D noise_sparse; uniform sampler2D noise_fine; -uniform vec2 iResolution; +uniform vec2 ires; uniform float scroll_speed; uniform float warp_boost; uniform float warp_opacity; uniform float time; const float noise_sparse_scale = 0.0007; -const float noise_fine_scale = 0.003; +const float noise_fine_scale = 0.004; const float warp_clouds_scale = 0.0003; const vec2 scroll_dir = vec2(1,0); const vec2 blink_scroll = vec2(50.0, 0); const float PI = 3.1415; void main() { - vec2 uv=gl_FragCoord.xy/iResolution.xy; + vec2 uv=gl_FragCoord.xy/ires.xy; float scroll = scroll_speed * time; float sparse = texture2D(noise_sparse, (gl_FragCoord.xy + scroll_dir * scroll)*noise_sparse_scale).r; sparse = ((sparse * sparse) - 0.2) * 1.2; float fine = texture2D(noise_fine, (gl_FragCoord.xy + scroll_dir * scroll)*noise_fine_scale).r; - fine = fine - 0.6; + fine = fine - 0.62; if (fine > 0.) { fine = fine * 10.0; } diff --git a/src/graphics/utils/RTTShader.ts b/src/graphics/utils/RTTShader.ts index ede6d80..8a32859 100644 --- a/src/graphics/utils/RTTShader.ts +++ b/src/graphics/utils/RTTShader.ts @@ -1,17 +1,17 @@ -import * as PIXI from "pixi.js"; +import { RenderTexture, Container, Renderer, Filter } from "pixi.js"; export default class RTTShader { - readonly texture: PIXI.RenderTexture; - readonly container: PIXI.Container; - readonly renderer: PIXI.Renderer; + readonly texture: RenderTexture; + readonly container: Container; + readonly renderer: Renderer; - constructor(renderer: PIXI.Renderer, filter: PIXI.Filter, scale: number = 2) { + constructor(renderer: Renderer, filter: Filter, scale: number = 2) { this.renderer = renderer; - this.texture = PIXI.RenderTexture.create({ + this.texture = RenderTexture.create({ width: this.renderer.width / scale, height: this.renderer.height / scale, }); - this.container = new PIXI.Container(); + this.container = new Container(); this.container.filterArea = this.texture.frame; this.container.filters = [filter]; } diff --git a/src/index.tsx b/src/index.tsx index 4772e29..88a5411 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -1,8 +1,12 @@ -import * as React from "react"; import * as PIXI from "pixi.js"; +import React from "react"; import ReactDOM from "react-dom"; -import { Stage, useApp } from "@inlet/react-pixi"; -import MenuBackground from "./game/MenuBackground"; +import { Provider } from "react-redux"; +import { Stage } from "@inlet/react-pixi"; +import { configureStore } from "@reduxjs/toolkit"; +import UI from "~ui/UI"; +import reducer from "~store/reducer"; +import MapEditor from "~game/scenes/MapEditor"; PIXI.settings.SCALE_MODE = PIXI.SCALE_MODES.NEAREST; @@ -13,14 +17,18 @@ const mounted = (app: PIXI.Application) => { app.queueResize(); }; +const store = configureStore({ reducer }); + ReactDOM.render( - + + + -
-

Hello!

-
+ + +
, document.getElementById("app") ); diff --git a/src/store/reducer.ts b/src/store/reducer.ts new file mode 100644 index 0000000..714c993 --- /dev/null +++ b/src/store/reducer.ts @@ -0,0 +1,6 @@ +import { combineReducers } from "@reduxjs/toolkit"; +import uiReducer from "./ui/reducer"; + +const reducer = combineReducers({ ui: uiReducer }); + +export default reducer; diff --git a/src/store/state.ts b/src/store/state.ts new file mode 100644 index 0000000..d3fa593 --- /dev/null +++ b/src/store/state.ts @@ -0,0 +1,5 @@ +import UIStore from "./ui/state"; + +export interface GameStore { + ui: UIStore; +} diff --git a/src/store/ui/reducer.ts b/src/store/ui/reducer.ts new file mode 100644 index 0000000..6508b7c --- /dev/null +++ b/src/store/ui/reducer.ts @@ -0,0 +1,56 @@ +import { createSlice, PayloadAction } from "@reduxjs/toolkit"; +import { UILayer } from "~ui/UI"; +import UIStore from "./state"; + +const initialState: UIStore = { + layers: [], +}; + +export interface AddLayerPayload { + id: string; + data: UILayer; +} + +export interface LayerActionPayload { + id: string; +} + +const uiSlice = createSlice({ + name: "ui", + initialState, + reducers: { + addLayer(state, action: PayloadAction) { + state.layers.push({ ...action.payload, visible: false }); + }, + removeLayer(state, action: PayloadAction) { + const index = state.layers.findIndex( + (layer) => layer.id == action.payload.id + ); + if (index < 0) { + return; + } + state.layers.splice(index, 1); + }, + showLayer(state, action: PayloadAction) { + const index = state.layers.findIndex( + (layer) => layer.id == action.payload.id + ); + if (index < 0) { + return; + } + state.layers[index].visible = true; + }, + hideLayer(state, action: PayloadAction) { + const index = state.layers.findIndex( + (layer) => layer.id == action.payload.id + ); + if (index < 0) { + return; + } + state.layers[index].visible = false; + }, + }, +}); + +export const { addLayer, removeLayer, showLayer, hideLayer } = uiSlice.actions; +export default uiSlice.reducer; diff --git a/src/store/ui/state.ts b/src/store/ui/state.ts new file mode 100644 index 0000000..8a8cd40 --- /dev/null +++ b/src/store/ui/state.ts @@ -0,0 +1,5 @@ +import { LayerList } from "~ui/UI"; + +export default interface UIStore { + layers: LayerList; +} diff --git a/src/ui/App.tsx b/src/ui/App.tsx deleted file mode 100644 index d521fc6..0000000 --- a/src/ui/App.tsx +++ /dev/null @@ -1,4 +0,0 @@ -import * as React from "react"; -import ReactDOM from "react-dom"; - -ReactDOM.render(

Hello

, document.getElementById("ui")); diff --git a/src/ui/MapEditor.tsx b/src/ui/MapEditor.tsx new file mode 100644 index 0000000..9206fb5 --- /dev/null +++ b/src/ui/MapEditor.tsx @@ -0,0 +1,13 @@ +import React from "react"; + +export interface MapEditorLayer { + type: "MapEditor"; +} + +export default function MapEditor() { + return ( +
+

HEY HEY

+
+ ); +} diff --git a/src/ui/Menu.tsx b/src/ui/Menu.tsx index 4b7c4cb..e69de29 100644 --- a/src/ui/Menu.tsx +++ b/src/ui/Menu.tsx @@ -1 +0,0 @@ -import * as React from "react"; diff --git a/src/ui/UI.tsx b/src/ui/UI.tsx new file mode 100644 index 0000000..263580c --- /dev/null +++ b/src/ui/UI.tsx @@ -0,0 +1,28 @@ +import React from "react"; +import { useSelector } from "react-redux"; +import { GameStore } from "~store/state"; +import MapEditor, { MapEditorLayer } from "./MapEditor"; + +export type UILayer = MapEditorLayer; + +export type LayerList = { id: string; data: UILayer; visible: boolean }[]; + +function renderLayer(data: UILayer) { + switch (data.type) { + case "MapEditor": + return ; + default: + throw new Error("unknown or invalid ui layer"); + } +} + +export default function UI() { + const layers = useSelector((state) => state.ui.layers); + return ( +
+ {layers.map(({ id, data }) => ( +
{renderLayer(data)}
+ ))} +
+ ); +} diff --git a/src/ui/utils/useLayer.ts b/src/ui/utils/useLayer.ts new file mode 100644 index 0000000..f7e9d61 --- /dev/null +++ b/src/ui/utils/useLayer.ts @@ -0,0 +1,32 @@ +import { useEffect, useState } from "react"; +import { useDispatch } from "react-redux"; +import { UILayer } from "~ui/UI"; +import { addLayer, removeLayer, showLayer, hideLayer } from "~store/ui/reducer"; + +export default function useUILayer(data: UILayer, show: boolean) { + const dispatch = useDispatch(); + const id = data.type + "-" + Math.random().toString(32).slice(2); + + const [visible, setVisible] = useState(show); + + useEffect(() => { + dispatch(addLayer({ id, data })); + return () => { + dispatch(removeLayer({ id })); + }; + }, []); + + useEffect(() => { + if (visible) { + dispatch(showLayer({ id })); + } else { + dispatch(hideLayer({ id })); + } + }, [visible]); + + if (show != visible) { + setVisible(show); + } + + return id; +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..ad76ded --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,13 @@ +{ + "compilerOptions": { + "target": "ES2020", + "moduleResolution": "node", + "allowSyntheticDefaultImports": true, + "esModuleInterop": true, + "jsx": "react", + "baseUrl": ".", + "paths": { + "~*": ["./src/*"] + } + } +} diff --git a/yarn.lock b/yarn.lock index c980af1..142c828 100644 --- a/yarn.lock +++ b/yarn.lock @@ -837,7 +837,7 @@ "@babel/types" "^7.4.4" esutils "^2.0.2" -"@babel/runtime@^7.4.4", "@babel/runtime@^7.8.4": +"@babel/runtime@^7.4.4", "@babel/runtime@^7.5.5", "@babel/runtime@^7.8.4": version "7.11.2" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.11.2.tgz#f549c13c754cc40b87644b9fa9f09a6a95fe0736" integrity sha512-TeWkU52so0mPtDcaCTxNBI/IHiz0pZgr8VEFqXFtZWpYD08ZB6FaSwVAS8MKRQAP3bYKiVjwysOJgMFY28o6Tw== @@ -1263,6 +1263,24 @@ eventemitter3 "^3.1.0" url "^0.11.0" +"@reduxjs/toolkit@^1.4.0": + version "1.4.0" + resolved "https://registry.yarnpkg.com/@reduxjs/toolkit/-/toolkit-1.4.0.tgz#ee2e2384cc3d1d76780d844b9c2da3580d32710d" + integrity sha512-hkxQwVx4BNVRsYdxjNF6cAseRmtrkpSlcgJRr3kLUcHPIAMZAmMJkXmHh/eUEGTMqPzsYpJLM7NN2w9fxQDuGw== + dependencies: + immer "^7.0.3" + redux "^4.0.0" + redux-thunk "^2.3.0" + reselect "^4.0.0" + +"@types/hoist-non-react-statics@^3.3.0": + version "3.3.1" + resolved "https://registry.yarnpkg.com/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz#1124aafe5118cb591977aeb1ceaaed1070eb039f" + integrity sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA== + dependencies: + "@types/react" "*" + hoist-non-react-statics "^3.3.0" + "@types/howler@^2.2.1": version "2.2.1" resolved "https://registry.yarnpkg.com/@types/howler/-/howler-2.2.1.tgz#c95314724a8e970b1b29a731861975f39987b9ca" @@ -1285,6 +1303,16 @@ dependencies: "@types/react" "*" +"@types/react-redux@^7.1.9": + version "7.1.9" + resolved "https://registry.yarnpkg.com/@types/react-redux/-/react-redux-7.1.9.tgz#280c13565c9f13ceb727ec21e767abe0e9b4aec3" + integrity sha512-mpC0jqxhP4mhmOl3P4ipRsgTgbNofMRXJb08Ms6gekViLj61v1hOZEKWDCyWsdONr6EjEA6ZHXC446wdywDe0w== + dependencies: + "@types/hoist-non-react-statics" "^3.3.0" + "@types/react" "*" + hoist-non-react-statics "^3.3.0" + redux "^4.0.0" + "@types/react@*", "@types/react@^16.9.49": version "16.9.49" resolved "https://registry.yarnpkg.com/@types/react/-/react-16.9.49.tgz#09db021cf8089aba0cdb12a49f8021a69cce4872" @@ -2586,6 +2614,11 @@ escodegen@~1.9.0: optionalDependencies: source-map "~0.6.1" +eslint-plugin-react-hooks@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.1.2.tgz#2eb53731d11c95826ef7a7272303eabb5c9a271e" + integrity sha512-ykUeqkGyUGgwTtk78C0o8UG2fzwmgJ0qxBGPp2WqRKsTwcLuVf01kTDRAtOsd4u6whX2XOC8749n2vPydP82fg== + esprima@^3.1.3: version "3.1.3" resolved "https://registry.yarnpkg.com/esprima/-/esprima-3.1.3.tgz#fdca51cee6133895e3c88d535ce49dbff62a4633" @@ -3101,6 +3134,13 @@ hmac-drbg@^1.0.0: minimalistic-assert "^1.0.0" minimalistic-crypto-utils "^1.0.1" +hoist-non-react-statics@^3.3.0: + version "3.3.2" + resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45" + integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw== + dependencies: + react-is "^16.7.0" + hotkeys-js@^3.8.1: version "3.8.1" resolved "https://registry.yarnpkg.com/hotkeys-js/-/hotkeys-js-3.8.1.tgz#fa7051f73bf1dc92a8b8d580a40b247f91966376" @@ -3206,6 +3246,11 @@ ieee754@^1.1.4: resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.13.tgz#ec168558e95aa181fd87d37f55c32bbcb6708b84" integrity sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg== +immer@^7.0.3: + version "7.0.9" + resolved "https://registry.yarnpkg.com/immer/-/immer-7.0.9.tgz#28e7552c21d39dd76feccd2b800b7bc86ee4a62e" + integrity sha512-Vs/gxoM4DqNAYR7pugIxi0Xc8XAun/uy7AQu4fLLqaTBHxjOP9pJ266Q9MWA/ly4z6rAFZbvViOtihxUZ7O28A== + import-fresh@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-2.0.0.tgz#d81355c15612d386c61f9ddd3922d4304822a546" @@ -4733,7 +4778,7 @@ process@^0.11.10: resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" integrity sha1-czIwDoQBYb2j5podHZGn1LwW8YI= -prop-types@^15.6.2: +prop-types@^15.6.2, prop-types@^15.7.2: version "15.7.2" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5" integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ== @@ -4843,7 +4888,7 @@ react-dom@^16.13.1: prop-types "^15.6.2" scheduler "^0.19.1" -react-is@^16.8.1: +react-is@^16.7.0, react-is@^16.8.1, react-is@^16.9.0: version "16.13.1" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== @@ -4858,6 +4903,17 @@ react-reconciler@0.25.1: prop-types "^15.6.2" scheduler "^0.19.1" +react-redux@^7.2.1: + version "7.2.1" + resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-7.2.1.tgz#8dedf784901014db2feca1ab633864dee68ad985" + integrity sha512-T+VfD/bvgGTUA74iW9d2i5THrDQWbweXP0AVNI8tNd1Rk5ch1rnMiJkDD67ejw7YBKM4+REvcvqRuWJb7BLuEg== + dependencies: + "@babel/runtime" "^7.5.5" + hoist-non-react-statics "^3.3.0" + loose-envify "^1.4.0" + prop-types "^15.7.2" + react-is "^16.9.0" + react@^16.13.1: version "16.13.1" resolved "https://registry.yarnpkg.com/react/-/react-16.13.1.tgz#2e818822f1a9743122c063d6410d85c1e3afe48e" @@ -4915,6 +4971,24 @@ readdirp@~3.4.0: dependencies: picomatch "^2.2.1" +redux-devtools-extension@^2.13.8: + version "2.13.8" + resolved "https://registry.yarnpkg.com/redux-devtools-extension/-/redux-devtools-extension-2.13.8.tgz#37b982688626e5e4993ff87220c9bbb7cd2d96e1" + integrity sha512-8qlpooP2QqPtZHQZRhx3x3OP5skEV1py/zUdMY28WNAocbafxdG2tRD1MWE7sp8obGMNYuLWanhhQ7EQvT1FBg== + +redux-thunk@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/redux-thunk/-/redux-thunk-2.3.0.tgz#51c2c19a185ed5187aaa9a2d08b666d0d6467622" + integrity sha512-km6dclyFnmcvxhAcrQV2AkZmPQjzPDjgVlQtR0EQjxZPyJ0BnMf3in1ryuR8A2qU0HldVRfxYXbFSKlI3N7Slw== + +redux@^4.0.0, redux@^4.0.5: + version "4.0.5" + resolved "https://registry.yarnpkg.com/redux/-/redux-4.0.5.tgz#4db5de5816e17891de8a80c424232d06f051d93f" + integrity sha512-VSz1uMAH24DM6MF72vcojpYPtrTUu3ByVWfPL1nPfVRb5mZVTve5GnNCUV53QM/BZ66xfWrm0CTWoM+Xlz8V1w== + dependencies: + loose-envify "^1.4.0" + symbol-observable "^1.2.0" + regenerate-unicode-properties@^8.2.0: version "8.2.0" resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-8.2.0.tgz#e5de7111d655e7ba60c057dbe9ff37c87e65cdec" @@ -5033,6 +5107,11 @@ request@^2.88.0: tunnel-agent "^0.6.0" uuid "^3.3.2" +reselect@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/reselect/-/reselect-4.0.0.tgz#f2529830e5d3d0e021408b246a206ef4ea4437f7" + integrity sha512-qUgANli03jjAyGlnbYVAV5vvnOmJnODyABz51RdBN7M4WaVu8mecZWgyQNkG8Yqe3KRGRt0l4K4B3XVEULC4CA== + resolve-from@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-3.0.0.tgz#b22c7af7d9d6881bc8b6e653335eebcb0a188748" @@ -5521,6 +5600,11 @@ svgo@^1.0.0, svgo@^1.3.2: unquote "~1.1.1" util.promisify "~1.0.0" +symbol-observable@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804" + integrity sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ== + symbol-tree@^3.2.2: version "3.2.4" resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2"