From 5ec0fa061087eda1194b08e54a4a12652a6dc767 Mon Sep 17 00:00:00 2001 From: Craig Date: Sat, 27 Apr 2024 11:09:37 +0100 Subject: [PATCH 1/6] wip: added new base folder --- fast-context-generic-extended/.gitignore | 25 + fast-context-generic-extended/index.html | 13 + fast-context-generic-extended/package.json | 22 + fast-context-generic-extended/public/vite.svg | 1 + fast-context-generic-extended/src/App.css | 0 fast-context-generic-extended/src/App.tsx | 71 ++ .../src/assets/react.svg | 1 + .../src/createFastContext.tsx | 71 ++ fast-context-generic-extended/src/index.css | 14 + fast-context-generic-extended/src/main.tsx | 10 + .../src/vite-env.d.ts | 1 + fast-context-generic-extended/tsconfig.json | 21 + .../tsconfig.node.json | 9 + fast-context-generic-extended/vite.config.ts | 7 + fast-context-generic-extended/yarn.lock | 632 ++++++++++++++++++ fast-context-generic/.gitignore | 1 + 16 files changed, 899 insertions(+) create mode 100644 fast-context-generic-extended/.gitignore create mode 100644 fast-context-generic-extended/index.html create mode 100644 fast-context-generic-extended/package.json create mode 100644 fast-context-generic-extended/public/vite.svg create mode 100644 fast-context-generic-extended/src/App.css create mode 100644 fast-context-generic-extended/src/App.tsx create mode 100644 fast-context-generic-extended/src/assets/react.svg create mode 100644 fast-context-generic-extended/src/createFastContext.tsx create mode 100644 fast-context-generic-extended/src/index.css create mode 100644 fast-context-generic-extended/src/main.tsx create mode 100644 fast-context-generic-extended/src/vite-env.d.ts create mode 100644 fast-context-generic-extended/tsconfig.json create mode 100644 fast-context-generic-extended/tsconfig.node.json create mode 100644 fast-context-generic-extended/vite.config.ts create mode 100644 fast-context-generic-extended/yarn.lock diff --git a/fast-context-generic-extended/.gitignore b/fast-context-generic-extended/.gitignore new file mode 100644 index 0000000..2107e24 --- /dev/null +++ b/fast-context-generic-extended/.gitignore @@ -0,0 +1,25 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +package-lock.json +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/fast-context-generic-extended/index.html b/fast-context-generic-extended/index.html new file mode 100644 index 0000000..e0d1c84 --- /dev/null +++ b/fast-context-generic-extended/index.html @@ -0,0 +1,13 @@ + + + + + + + Vite + React + TS + + +
+ + + diff --git a/fast-context-generic-extended/package.json b/fast-context-generic-extended/package.json new file mode 100644 index 0000000..503cc0b --- /dev/null +++ b/fast-context-generic-extended/package.json @@ -0,0 +1,22 @@ +{ + "name": "simple-context", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "tsc && vite build", + "preview": "vite preview" + }, + "dependencies": { + "react": "^18.2.0", + "react-dom": "^18.2.0" + }, + "devDependencies": { + "@types/react": "^18.0.17", + "@types/react-dom": "^18.0.6", + "@vitejs/plugin-react": "^2.1.0", + "typescript": "^4.6.4", + "vite": "^3.1.0" + } +} \ No newline at end of file diff --git a/fast-context-generic-extended/public/vite.svg b/fast-context-generic-extended/public/vite.svg new file mode 100644 index 0000000..e7b8dfb --- /dev/null +++ b/fast-context-generic-extended/public/vite.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/fast-context-generic-extended/src/App.css b/fast-context-generic-extended/src/App.css new file mode 100644 index 0000000..e69de29 diff --git a/fast-context-generic-extended/src/App.tsx b/fast-context-generic-extended/src/App.tsx new file mode 100644 index 0000000..b28e4bc --- /dev/null +++ b/fast-context-generic-extended/src/App.tsx @@ -0,0 +1,71 @@ +import createFastContext from "./createFastContext"; + +const { Provider, useStore } = createFastContext({ + first: "", + last: "", +}); + +const TextInput = ({ value }: { value: "first" | "last" }) => { + const [fieldValue, setStore] = useStore((store) => store[value]); + return ( +
+ {value}:{" "} + setStore({ [value]: e.target.value })} + /> +
+ ); +}; + +const Display = ({ value }: { value: "first" | "last" }) => { + const [fieldValue] = useStore((store) => store[value]); + return ( +
+ {value}: {fieldValue} +
+ ); +}; + +const FormContainer = () => { + return ( +
+
FormContainer
+ + +
+ ); +}; + +const DisplayContainer = () => { + return ( +
+
DisplayContainer
+ + +
+ ); +}; + +const ContentContainer = () => { + return ( +
+
ContentContainer
+ + +
+ ); +}; + +function App() { + return ( + +
+
App
+ +
+
+ ); +} + +export default App; diff --git a/fast-context-generic-extended/src/assets/react.svg b/fast-context-generic-extended/src/assets/react.svg new file mode 100644 index 0000000..6c87de9 --- /dev/null +++ b/fast-context-generic-extended/src/assets/react.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/fast-context-generic-extended/src/createFastContext.tsx b/fast-context-generic-extended/src/createFastContext.tsx new file mode 100644 index 0000000..292c1cf --- /dev/null +++ b/fast-context-generic-extended/src/createFastContext.tsx @@ -0,0 +1,71 @@ +import React, { + useRef, + createContext, + useContext, + useCallback, + useSyncExternalStore, +} from "react"; + +export default function createFastContext(initialState: Store) { + function useStoreData(): { + get: () => Store; + set: (value: Partial) => void; + subscribe: (callback: () => void) => () => void; + } { + const store = useRef(initialState); + + const get = useCallback(() => store.current, []); + + const subscribers = useRef(new Set<() => void>()); + + const set = useCallback((value: Partial) => { + store.current = { ...store.current, ...value }; + subscribers.current.forEach((callback) => callback()); + }, []); + + const subscribe = useCallback((callback: () => void) => { + subscribers.current.add(callback); + return () => subscribers.current.delete(callback); + }, []); + + return { + get, + set, + subscribe, + }; + } + + type UseStoreDataReturnType = ReturnType; + + const StoreContext = createContext(null); + + function Provider({ children }: { children: React.ReactNode }) { + return ( + + {children} + + ); + } + + function useStore( + selector: (store: Store) => SelectorOutput + ): [SelectorOutput, (value: Partial) => void] { + const store = useContext(StoreContext); + if (!store) { + throw new Error("Store not found"); + } + + const state = useSyncExternalStore( + store.subscribe, + () => selector(store.get()), + () => selector(initialState), + ); + + return [state, store.set]; + } + + return { + Provider, + useStore, + }; +} diff --git a/fast-context-generic-extended/src/index.css b/fast-context-generic-extended/src/index.css new file mode 100644 index 0000000..2e0abbc --- /dev/null +++ b/fast-context-generic-extended/src/index.css @@ -0,0 +1,14 @@ +body { + font-family: Arial, Helvetica, sans-serif; + padding: 1rem; +} + +.container { + margin-top: 0.5rem; + padding: 0.5rem 1.5rem; + border: 1px solid #ccc; +} + +.field, .value { + padding: 0.5rem; +} \ No newline at end of file diff --git a/fast-context-generic-extended/src/main.tsx b/fast-context-generic-extended/src/main.tsx new file mode 100644 index 0000000..611e848 --- /dev/null +++ b/fast-context-generic-extended/src/main.tsx @@ -0,0 +1,10 @@ +import React from 'react' +import ReactDOM from 'react-dom/client' +import App from './App' +import './index.css' + +ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render( + + + +) diff --git a/fast-context-generic-extended/src/vite-env.d.ts b/fast-context-generic-extended/src/vite-env.d.ts new file mode 100644 index 0000000..11f02fe --- /dev/null +++ b/fast-context-generic-extended/src/vite-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/fast-context-generic-extended/tsconfig.json b/fast-context-generic-extended/tsconfig.json new file mode 100644 index 0000000..3d0a51a --- /dev/null +++ b/fast-context-generic-extended/tsconfig.json @@ -0,0 +1,21 @@ +{ + "compilerOptions": { + "target": "ESNext", + "useDefineForClassFields": true, + "lib": ["DOM", "DOM.Iterable", "ESNext"], + "allowJs": false, + "skipLibCheck": true, + "esModuleInterop": false, + "allowSyntheticDefaultImports": true, + "strict": true, + "forceConsistentCasingInFileNames": true, + "module": "ESNext", + "moduleResolution": "Node", + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + "jsx": "react-jsx" + }, + "include": ["src"], + "references": [{ "path": "./tsconfig.node.json" }] +} diff --git a/fast-context-generic-extended/tsconfig.node.json b/fast-context-generic-extended/tsconfig.node.json new file mode 100644 index 0000000..9d31e2a --- /dev/null +++ b/fast-context-generic-extended/tsconfig.node.json @@ -0,0 +1,9 @@ +{ + "compilerOptions": { + "composite": true, + "module": "ESNext", + "moduleResolution": "Node", + "allowSyntheticDefaultImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/fast-context-generic-extended/vite.config.ts b/fast-context-generic-extended/vite.config.ts new file mode 100644 index 0000000..b1b5f91 --- /dev/null +++ b/fast-context-generic-extended/vite.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [react()] +}) diff --git a/fast-context-generic-extended/yarn.lock b/fast-context-generic-extended/yarn.lock new file mode 100644 index 0000000..c4ebcbf --- /dev/null +++ b/fast-context-generic-extended/yarn.lock @@ -0,0 +1,632 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@ampproject/remapping@^2.1.0": + version "2.2.0" + resolved "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz" + integrity sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w== + dependencies: + "@jridgewell/gen-mapping" "^0.1.0" + "@jridgewell/trace-mapping" "^0.3.9" + +"@babel/code-frame@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz" + integrity sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q== + dependencies: + "@babel/highlight" "^7.18.6" + +"@babel/compat-data@^7.19.3": + version "7.19.3" + resolved "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.19.3.tgz" + integrity sha512-prBHMK4JYYK+wDjJF1q99KK4JLL+egWS4nmNqdlMUgCExMZ+iZW0hGhyC3VEbsPjvaN0TBhW//VIFwBrk8sEiw== + +"@babel/core@^7.0.0", "@babel/core@^7.0.0-0", "@babel/core@^7.18.13": + version "7.19.3" + resolved "https://registry.npmjs.org/@babel/core/-/core-7.19.3.tgz" + integrity sha512-WneDJxdsjEvyKtXKsaBGbDeiyOjR5vYq4HcShxnIbG0qixpoHjI3MqeZM9NDvsojNCEBItQE4juOo/bU6e72gQ== + dependencies: + "@ampproject/remapping" "^2.1.0" + "@babel/code-frame" "^7.18.6" + "@babel/generator" "^7.19.3" + "@babel/helper-compilation-targets" "^7.19.3" + "@babel/helper-module-transforms" "^7.19.0" + "@babel/helpers" "^7.19.0" + "@babel/parser" "^7.19.3" + "@babel/template" "^7.18.10" + "@babel/traverse" "^7.19.3" + "@babel/types" "^7.19.3" + convert-source-map "^1.7.0" + debug "^4.1.0" + gensync "^1.0.0-beta.2" + json5 "^2.2.1" + semver "^6.3.0" + +"@babel/generator@^7.19.3": + version "7.19.3" + resolved "https://registry.npmjs.org/@babel/generator/-/generator-7.19.3.tgz" + integrity sha512-fqVZnmp1ncvZU757UzDheKZpfPgatqY59XtW2/j/18H7u76akb8xqvjw82f+i2UKd/ksYsSick/BCLQUUtJ/qQ== + dependencies: + "@babel/types" "^7.19.3" + "@jridgewell/gen-mapping" "^0.3.2" + jsesc "^2.5.1" + +"@babel/helper-annotate-as-pure@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz" + integrity sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA== + dependencies: + "@babel/types" "^7.18.6" + +"@babel/helper-compilation-targets@^7.19.3": + version "7.19.3" + resolved "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.19.3.tgz" + integrity sha512-65ESqLGyGmLvgR0mst5AdW1FkNlj9rQsCKduzEoEPhBCDFGXvz2jW6bXFG6i0/MrV2s7hhXjjb2yAzcPuQlLwg== + dependencies: + "@babel/compat-data" "^7.19.3" + "@babel/helper-validator-option" "^7.18.6" + browserslist "^4.21.3" + semver "^6.3.0" + +"@babel/helper-environment-visitor@^7.18.9": + version "7.18.9" + resolved "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz" + integrity sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg== + +"@babel/helper-function-name@^7.19.0": + version "7.19.0" + resolved "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz" + integrity sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w== + dependencies: + "@babel/template" "^7.18.10" + "@babel/types" "^7.19.0" + +"@babel/helper-hoist-variables@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz" + integrity sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q== + dependencies: + "@babel/types" "^7.18.6" + +"@babel/helper-module-imports@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz" + integrity sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA== + dependencies: + "@babel/types" "^7.18.6" + +"@babel/helper-module-transforms@^7.19.0": + version "7.19.0" + resolved "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.19.0.tgz" + integrity sha512-3HBZ377Fe14RbLIA+ac3sY4PTgpxHVkFrESaWhoI5PuyXPBBX8+C34qblV9G89ZtycGJCmCI/Ut+VUDK4bltNQ== + dependencies: + "@babel/helper-environment-visitor" "^7.18.9" + "@babel/helper-module-imports" "^7.18.6" + "@babel/helper-simple-access" "^7.18.6" + "@babel/helper-split-export-declaration" "^7.18.6" + "@babel/helper-validator-identifier" "^7.18.6" + "@babel/template" "^7.18.10" + "@babel/traverse" "^7.19.0" + "@babel/types" "^7.19.0" + +"@babel/helper-plugin-utils@^7.18.6", "@babel/helper-plugin-utils@^7.19.0": + version "7.19.0" + resolved "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.19.0.tgz" + integrity sha512-40Ryx7I8mT+0gaNxm8JGTZFUITNqdLAgdg0hXzeVZxVD6nFsdhQvip6v8dqkRHzsz1VFpFAaOCHNn0vKBL7Czw== + +"@babel/helper-simple-access@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.18.6.tgz" + integrity sha512-iNpIgTgyAvDQpDj76POqg+YEt8fPxx3yaNBg3S30dxNKm2SWfYhD0TGrK/Eu9wHpUW63VQU894TsTg+GLbUa1g== + dependencies: + "@babel/types" "^7.18.6" + +"@babel/helper-split-export-declaration@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz" + integrity sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA== + dependencies: + "@babel/types" "^7.18.6" + +"@babel/helper-string-parser@^7.18.10": + version "7.18.10" + resolved "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.18.10.tgz" + integrity sha512-XtIfWmeNY3i4t7t4D2t02q50HvqHybPqW2ki1kosnvWCwuCMeo81Jf0gwr85jy/neUdg5XDdeFE/80DXiO+njw== + +"@babel/helper-validator-identifier@^7.18.6", "@babel/helper-validator-identifier@^7.19.1": + version "7.19.1" + resolved "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz" + integrity sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w== + +"@babel/helper-validator-option@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz" + integrity sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw== + +"@babel/helpers@^7.19.0": + version "7.19.0" + resolved "https://registry.npmjs.org/@babel/helpers/-/helpers-7.19.0.tgz" + integrity sha512-DRBCKGwIEdqY3+rPJgG/dKfQy9+08rHIAJx8q2p+HSWP87s2HCrQmaAMMyMll2kIXKCW0cO1RdQskx15Xakftg== + dependencies: + "@babel/template" "^7.18.10" + "@babel/traverse" "^7.19.0" + "@babel/types" "^7.19.0" + +"@babel/highlight@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz" + integrity sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g== + dependencies: + "@babel/helper-validator-identifier" "^7.18.6" + chalk "^2.0.0" + js-tokens "^4.0.0" + +"@babel/parser@^7.18.10", "@babel/parser@^7.19.3": + version "7.19.3" + resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.19.3.tgz" + integrity sha512-pJ9xOlNWHiy9+FuFP09DEAFbAn4JskgRsVcc169w2xRBC3FRGuQEwjeIMMND9L2zc0iEhO/tGv4Zq+km+hxNpQ== + +"@babel/plugin-syntax-jsx@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.18.6.tgz" + integrity sha512-6mmljtAedFGTWu2p/8WIORGwy+61PLgOMPOdazc7YoJ9ZCWUyFy3A6CpPkRKLKD1ToAesxX8KGEViAiLo9N+7Q== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-react-jsx-development@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.18.6.tgz" + integrity sha512-SA6HEjwYFKF7WDjWcMcMGUimmw/nhNRDWxr+KaLSCrkD/LMDBvWRmHAYgE1HDeF8KUuI8OAu+RT6EOtKxSW2qA== + dependencies: + "@babel/plugin-transform-react-jsx" "^7.18.6" + +"@babel/plugin-transform-react-jsx-self@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.18.6.tgz" + integrity sha512-A0LQGx4+4Jv7u/tWzoJF7alZwnBDQd6cGLh9P+Ttk4dpiL+J5p7NSNv/9tlEFFJDq3kjxOavWmbm6t0Gk+A3Ig== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-react-jsx-source@^7.18.6": + version "7.18.6" + resolved "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.18.6.tgz" + integrity sha512-utZmlASneDfdaMh0m/WausbjUjEdGrQJz0vFK93d7wD3xf5wBtX219+q6IlCNZeguIcxS2f/CvLZrlLSvSHQXw== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-react-jsx@^7.18.10", "@babel/plugin-transform-react-jsx@^7.18.6": + version "7.19.0" + resolved "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.19.0.tgz" + integrity sha512-UVEvX3tXie3Szm3emi1+G63jyw1w5IcMY0FSKM+CRnKRI5Mr1YbCNgsSTwoTwKphQEG9P+QqmuRFneJPZuHNhg== + dependencies: + "@babel/helper-annotate-as-pure" "^7.18.6" + "@babel/helper-module-imports" "^7.18.6" + "@babel/helper-plugin-utils" "^7.19.0" + "@babel/plugin-syntax-jsx" "^7.18.6" + "@babel/types" "^7.19.0" + +"@babel/template@^7.18.10": + version "7.18.10" + resolved "https://registry.npmjs.org/@babel/template/-/template-7.18.10.tgz" + integrity sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA== + dependencies: + "@babel/code-frame" "^7.18.6" + "@babel/parser" "^7.18.10" + "@babel/types" "^7.18.10" + +"@babel/traverse@^7.19.0", "@babel/traverse@^7.19.3": + version "7.19.3" + resolved "https://registry.npmjs.org/@babel/traverse/-/traverse-7.19.3.tgz" + integrity sha512-qh5yf6149zhq2sgIXmwjnsvmnNQC2iw70UFjp4olxucKrWd/dvlUsBI88VSLUsnMNF7/vnOiA+nk1+yLoCqROQ== + dependencies: + "@babel/code-frame" "^7.18.6" + "@babel/generator" "^7.19.3" + "@babel/helper-environment-visitor" "^7.18.9" + "@babel/helper-function-name" "^7.19.0" + "@babel/helper-hoist-variables" "^7.18.6" + "@babel/helper-split-export-declaration" "^7.18.6" + "@babel/parser" "^7.19.3" + "@babel/types" "^7.19.3" + debug "^4.1.0" + globals "^11.1.0" + +"@babel/types@^7.18.10", "@babel/types@^7.18.6", "@babel/types@^7.19.0", "@babel/types@^7.19.3": + version "7.19.3" + resolved "https://registry.npmjs.org/@babel/types/-/types-7.19.3.tgz" + integrity sha512-hGCaQzIY22DJlDh9CH7NOxgKkFjBk0Cw9xDO1Xmh2151ti7wiGfQ3LauXzL4HP1fmFlTX6XjpRETTpUcv7wQLw== + dependencies: + "@babel/helper-string-parser" "^7.18.10" + "@babel/helper-validator-identifier" "^7.19.1" + to-fast-properties "^2.0.0" + +"@jridgewell/gen-mapping@^0.1.0": + version "0.1.1" + resolved "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz" + integrity sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w== + dependencies: + "@jridgewell/set-array" "^1.0.0" + "@jridgewell/sourcemap-codec" "^1.4.10" + +"@jridgewell/gen-mapping@^0.3.2": + version "0.3.2" + resolved "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz" + integrity sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A== + dependencies: + "@jridgewell/set-array" "^1.0.1" + "@jridgewell/sourcemap-codec" "^1.4.10" + "@jridgewell/trace-mapping" "^0.3.9" + +"@jridgewell/resolve-uri@^3.0.3": + version "3.1.0" + resolved "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz" + integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w== + +"@jridgewell/set-array@^1.0.0", "@jridgewell/set-array@^1.0.1": + version "1.1.2" + resolved "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz" + integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw== + +"@jridgewell/sourcemap-codec@^1.4.10": + version "1.4.14" + resolved "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz" + integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw== + +"@jridgewell/trace-mapping@^0.3.9": + version "0.3.15" + resolved "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.15.tgz" + integrity sha512-oWZNOULl+UbhsgB51uuZzglikfIKSUBO/M9W2OfEjn7cmqoAiCgmv9lyACTUacZwBz0ITnJ2NqjU8Tx0DHL88g== + dependencies: + "@jridgewell/resolve-uri" "^3.0.3" + "@jridgewell/sourcemap-codec" "^1.4.10" + +"@types/prop-types@*": + version "15.7.5" + resolved "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz" + integrity sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w== + +"@types/react-dom@^18.0.6": + version "18.0.6" + resolved "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.0.6.tgz" + integrity sha512-/5OFZgfIPSwy+YuIBP/FgJnQnsxhZhjjrnxudMddeblOouIodEQ75X14Rr4wGSG/bknL+Omy9iWlLo1u/9GzAA== + dependencies: + "@types/react" "*" + +"@types/react@*", "@types/react@^18.0.17": + version "18.0.21" + resolved "https://registry.npmjs.org/@types/react/-/react-18.0.21.tgz" + integrity sha512-7QUCOxvFgnD5Jk8ZKlUAhVcRj7GuJRjnjjiY/IUBWKgOlnvDvTMLD4RTF7NPyVmbRhNrbomZiOepg7M/2Kj1mA== + dependencies: + "@types/prop-types" "*" + "@types/scheduler" "*" + csstype "^3.0.2" + +"@types/scheduler@*": + version "0.16.2" + resolved "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz" + integrity sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew== + +"@vitejs/plugin-react@^2.1.0": + version "2.1.0" + resolved "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-2.1.0.tgz" + integrity sha512-am6rPyyU3LzUYne3Gd9oj9c4Rzbq5hQnuGXSMT6Gujq45Il/+bunwq3lrB7wghLkiF45ygMwft37vgJ/NE8IAA== + dependencies: + "@babel/core" "^7.18.13" + "@babel/plugin-transform-react-jsx" "^7.18.10" + "@babel/plugin-transform-react-jsx-development" "^7.18.6" + "@babel/plugin-transform-react-jsx-self" "^7.18.6" + "@babel/plugin-transform-react-jsx-source" "^7.18.6" + magic-string "^0.26.2" + react-refresh "^0.14.0" + +ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz" + integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== + dependencies: + color-convert "^1.9.0" + +browserslist@^4.21.3, "browserslist@>= 4.21.0": + version "4.21.4" + resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz" + integrity sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw== + dependencies: + caniuse-lite "^1.0.30001400" + electron-to-chromium "^1.4.251" + node-releases "^2.0.6" + update-browserslist-db "^1.0.9" + +caniuse-lite@^1.0.30001400: + version "1.0.30001414" + resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001414.tgz" + integrity sha512-t55jfSaWjCdocnFdKQoO+d2ct9C59UZg4dY3OnUlSZ447r8pUtIKdp0hpAzrGFultmTC+Us+KpKi4GZl/LXlFg== + +chalk@^2.0.0: + version "2.4.2" + resolved "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +color-convert@^1.9.0: + version "1.9.3" + resolved "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz" + integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== + +convert-source-map@^1.7.0: + version "1.8.0" + resolved "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz" + integrity sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA== + dependencies: + safe-buffer "~5.1.1" + +csstype@^3.0.2: + version "3.1.1" + resolved "https://registry.npmjs.org/csstype/-/csstype-3.1.1.tgz" + integrity sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw== + +debug@^4.1.0: + version "4.3.4" + resolved "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== + dependencies: + ms "2.1.2" + +electron-to-chromium@^1.4.251: + version "1.4.270" + resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.270.tgz" + integrity sha512-KNhIzgLiJmDDC444dj9vEOpZEgsV96ult9Iff98Vanumn+ShJHd5se8aX6KeVxdc0YQeqdrezBZv89rleDbvSg== + +esbuild-windows-64@0.15.10: + version "0.15.10" + resolved "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.15.10.tgz" + integrity sha512-2H0gdsyHi5x+8lbng3hLbxDWR7mKHWh5BXZGKVG830KUmXOOWFE2YKJ4tHRkejRduOGDrBvHBriYsGtmTv3ntA== + +esbuild@^0.15.6: + version "0.15.10" + resolved "https://registry.npmjs.org/esbuild/-/esbuild-0.15.10.tgz" + integrity sha512-N7wBhfJ/E5fzn/SpNgX+oW2RLRjwaL8Y0ezqNqhjD6w0H2p0rDuEz2FKZqpqLnO8DCaWumKe8dsC/ljvVSSxng== + optionalDependencies: + "@esbuild/android-arm" "0.15.10" + "@esbuild/linux-loong64" "0.15.10" + esbuild-android-64 "0.15.10" + esbuild-android-arm64 "0.15.10" + esbuild-darwin-64 "0.15.10" + esbuild-darwin-arm64 "0.15.10" + esbuild-freebsd-64 "0.15.10" + esbuild-freebsd-arm64 "0.15.10" + esbuild-linux-32 "0.15.10" + esbuild-linux-64 "0.15.10" + esbuild-linux-arm "0.15.10" + esbuild-linux-arm64 "0.15.10" + esbuild-linux-mips64le "0.15.10" + esbuild-linux-ppc64le "0.15.10" + esbuild-linux-riscv64 "0.15.10" + esbuild-linux-s390x "0.15.10" + esbuild-netbsd-64 "0.15.10" + esbuild-openbsd-64 "0.15.10" + esbuild-sunos-64 "0.15.10" + esbuild-windows-32 "0.15.10" + esbuild-windows-64 "0.15.10" + esbuild-windows-arm64 "0.15.10" + +escalade@^3.1.1: + version "3.1.1" + resolved "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz" + integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== + +escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz" + integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== + +function-bind@^1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz" + integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== + +gensync@^1.0.0-beta.2: + version "1.0.0-beta.2" + resolved "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz" + integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== + +globals@^11.1.0: + version "11.12.0" + resolved "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz" + integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz" + integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== + +has@^1.0.3: + version "1.0.3" + resolved "https://registry.npmjs.org/has/-/has-1.0.3.tgz" + integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== + dependencies: + function-bind "^1.1.1" + +is-core-module@^2.9.0: + version "2.10.0" + resolved "https://registry.npmjs.org/is-core-module/-/is-core-module-2.10.0.tgz" + integrity sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg== + dependencies: + has "^1.0.3" + +"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== + +jsesc@^2.5.1: + version "2.5.2" + resolved "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz" + integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== + +json5@^2.2.1: + version "2.2.1" + resolved "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz" + integrity sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA== + +loose-envify@^1.1.0: + version "1.4.0" + resolved "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz" + integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== + dependencies: + js-tokens "^3.0.0 || ^4.0.0" + +magic-string@^0.26.2: + version "0.26.5" + resolved "https://registry.npmjs.org/magic-string/-/magic-string-0.26.5.tgz" + integrity sha512-yXUIYOOQnEHKHOftp5shMWpB9ImfgfDJpapa38j/qMtTj5QHWucvxP4lUtuRmHT9vAzvtpHkWKXW9xBwimXeNg== + dependencies: + sourcemap-codec "^1.4.8" + +ms@2.1.2: + version "2.1.2" + resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + +nanoid@^3.3.4: + version "3.3.4" + resolved "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz" + integrity sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw== + +node-releases@^2.0.6: + version "2.0.6" + resolved "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz" + integrity sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg== + +path-parse@^1.0.7: + version "1.0.7" + resolved "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz" + integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== + +picocolors@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz" + integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== + +postcss@^8.4.16: + version "8.4.17" + resolved "https://registry.npmjs.org/postcss/-/postcss-8.4.17.tgz" + integrity sha512-UNxNOLQydcOFi41yHNMcKRZ39NeXlr8AxGuZJsdub8vIb12fHzcq37DTU/QtbI6WLxNg2gF9Z+8qtRwTj1UI1Q== + dependencies: + nanoid "^3.3.4" + picocolors "^1.0.0" + source-map-js "^1.0.2" + +react-dom@^18.2.0: + version "18.2.0" + resolved "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz" + integrity sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g== + dependencies: + loose-envify "^1.1.0" + scheduler "^0.23.0" + +react-refresh@^0.14.0: + version "0.14.0" + resolved "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.0.tgz" + integrity sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ== + +react@^18.2.0: + version "18.2.0" + resolved "https://registry.npmjs.org/react/-/react-18.2.0.tgz" + integrity sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ== + dependencies: + loose-envify "^1.1.0" + +resolve@^1.22.1: + version "1.22.1" + resolved "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz" + integrity sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw== + dependencies: + is-core-module "^2.9.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + +rollup@~2.78.0: + version "2.78.1" + resolved "https://registry.npmjs.org/rollup/-/rollup-2.78.1.tgz" + integrity sha512-VeeCgtGi4P+o9hIg+xz4qQpRl6R401LWEXBmxYKOV4zlF82lyhgh2hTZnheFUbANE8l2A41F458iwj2vEYaXJg== + optionalDependencies: + fsevents "~2.3.2" + +safe-buffer@~5.1.1: + version "5.1.2" + resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz" + integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== + +scheduler@^0.23.0: + version "0.23.0" + resolved "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz" + integrity sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw== + dependencies: + loose-envify "^1.1.0" + +semver@^6.3.0: + version "6.3.0" + resolved "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz" + integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== + +source-map-js@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz" + integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw== + +sourcemap-codec@^1.4.8: + version "1.4.8" + resolved "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz" + integrity sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA== + +supports-color@^5.3.0: + version "5.5.0" + resolved "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== + dependencies: + has-flag "^3.0.0" + +supports-preserve-symlinks-flag@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz" + integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== + +to-fast-properties@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz" + integrity sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog== + +typescript@^4.6.4: + version "4.8.4" + resolved "https://registry.npmjs.org/typescript/-/typescript-4.8.4.tgz" + integrity sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ== + +update-browserslist-db@^1.0.9: + version "1.0.9" + resolved "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.9.tgz" + integrity sha512-/xsqn21EGVdXI3EXSum1Yckj3ZVZugqyOZQ/CxYPBD/R+ko9NSUScf8tFF4dOKY+2pvSSJA/S+5B8s4Zr4kyvg== + dependencies: + escalade "^3.1.1" + picocolors "^1.0.0" + +vite@^3.0.0, vite@^3.1.0: + version "3.1.4" + resolved "https://registry.npmjs.org/vite/-/vite-3.1.4.tgz" + integrity sha512-JoQI08aBjY9lycL7jcEq4p9o1xUjq5aRvdH4KWaXtkSx7e7RpAh9D3IjzDWRD4Fg44LS3oDAIOG/Kq1L+82psA== + dependencies: + esbuild "^0.15.6" + postcss "^8.4.16" + resolve "^1.22.1" + rollup "~2.78.0" + optionalDependencies: + fsevents "~2.3.2" diff --git a/fast-context-generic/.gitignore b/fast-context-generic/.gitignore index a547bf3..de3b5a1 100644 --- a/fast-context-generic/.gitignore +++ b/fast-context-generic/.gitignore @@ -8,6 +8,7 @@ pnpm-debug.log* lerna-debug.log* node_modules +package dist dist-ssr *.local From 83f18cbc5ccd98115451dd1c27a5afb51fd105ab Mon Sep 17 00:00:00 2001 From: Craig Date: Sat, 27 Apr 2024 22:43:32 +0100 Subject: [PATCH 2/6] wip: simple single field use complete --- fast-context-generic-extended/src/App.tsx | 76 ++++------------ .../src/app/createFastContext.tsx | 87 +++++++++++++++++++ .../src/components/ContentContainer.tsx | 13 +++ .../src/components/Display.tsx | 13 +++ .../src/components/DisplayContainer.tsx | 15 ++++ .../src/components/FormContainer.tsx | 15 ++++ .../src/components/TextInput.tsx | 16 ++++ .../src/createFastContext.tsx | 71 --------------- .../src/pages/MainPage.tsx | 12 +++ 9 files changed, 186 insertions(+), 132 deletions(-) create mode 100644 fast-context-generic-extended/src/app/createFastContext.tsx create mode 100644 fast-context-generic-extended/src/components/ContentContainer.tsx create mode 100644 fast-context-generic-extended/src/components/Display.tsx create mode 100644 fast-context-generic-extended/src/components/DisplayContainer.tsx create mode 100644 fast-context-generic-extended/src/components/FormContainer.tsx create mode 100644 fast-context-generic-extended/src/components/TextInput.tsx delete mode 100644 fast-context-generic-extended/src/createFastContext.tsx create mode 100644 fast-context-generic-extended/src/pages/MainPage.tsx diff --git a/fast-context-generic-extended/src/App.tsx b/fast-context-generic-extended/src/App.tsx index b28e4bc..cf16d37 100644 --- a/fast-context-generic-extended/src/App.tsx +++ b/fast-context-generic-extended/src/App.tsx @@ -1,70 +1,24 @@ -import createFastContext from "./createFastContext"; - -const { Provider, useStore } = createFastContext({ - first: "", - last: "", +import createFastContext from "./app/createFastContext"; +import MainPage from "./pages/MainPage"; + +export const { + FastContextProvider:AppFastContextProvider, + useFastContextField:useAppFastContextField, + useFastContextFields:useAppFastContextFields +} = createFastContext({ + first: "" as string, + last: "" as string, }); -const TextInput = ({ value }: { value: "first" | "last" }) => { - const [fieldValue, setStore] = useStore((store) => store[value]); - return ( -
- {value}:{" "} - setStore({ [value]: e.target.value })} - /> -
- ); -}; - -const Display = ({ value }: { value: "first" | "last" }) => { - const [fieldValue] = useStore((store) => store[value]); - return ( -
- {value}: {fieldValue} -
- ); -}; - -const FormContainer = () => { - return ( -
-
FormContainer
- - -
- ); -}; - -const DisplayContainer = () => { - return ( -
-
DisplayContainer
- - -
- ); -}; - -const ContentContainer = () => { - return ( -
-
ContentContainer
- - -
- ); -}; - function App() { + console.log(`App Rendering`) return ( - +
-
App
- +

App

+
-
+ ); } diff --git a/fast-context-generic-extended/src/app/createFastContext.tsx b/fast-context-generic-extended/src/app/createFastContext.tsx new file mode 100644 index 0000000..6676673 --- /dev/null +++ b/fast-context-generic-extended/src/app/createFastContext.tsx @@ -0,0 +1,87 @@ +import React, { + useRef, + createContext, + useContext, + useCallback, + useSyncExternalStore, +} from "react"; + +export default function createFastContext(initialState: FastContext) { + function useFastContextData(): { + get: () => FastContext; + set: (value: Partial) => void; + subscribe: (callback: () => void) => () => void; + } { + const store = useRef(initialState); + + const get = useCallback(() => store.current, []); + + const subscribers = useRef(new Set<() => void>()); + + const set = useCallback((value: Partial) => { + console.log('set', value); + store.current = { ...store.current, ...value }; + subscribers.current.forEach((callback) => callback()); + }, []); + + const subscribe = useCallback((callback: () => void) => { + subscribers.current.add(callback); + return () => subscribers.current.delete(callback); + }, []); + + return { + get, + set, + subscribe, + }; + } + + type UseFastContextDataReturnType = ReturnType; + + const FastContext = createContext(null); + + function FastContextProvider({ children }: Readonly<{ children: React.ReactNode }>) { + return ( + + {children} + + ); + } + + function useFastContext( + selector: (store: FastContext) => SelectorOutput + ): [SelectorOutput, (value: Partial) => void] { + const fastContext = useContext(FastContext); + if (!fastContext) { + throw new Error("Store not found"); + } + + const state = useSyncExternalStore( + fastContext.subscribe, + () => selector(fastContext.get()), + () => selector(initialState), + ); + + return [state, fastContext.set]; + } + + function useFastContextField( + field: string + ): [SelectorOutput, (value: SelectorOutput) => void]{ + const [fieldValue, setter] = useFastContext((store) => (store as Record)[field]); + const setField = (value: any) => setter({ [field]: value } as Partial); + return [fieldValue, setField as (value: SelectorOutput) => void]; + } + + function useFastContextFields( + field: string[] + ): [SelectorOutput, (value: Partial) => void][] { + return [useFastContext((store) => (store as Record)[field[0]])]; + } + + return { + FastContextProvider, + useFastContextField, + useFastContextFields, + }; +} diff --git a/fast-context-generic-extended/src/components/ContentContainer.tsx b/fast-context-generic-extended/src/components/ContentContainer.tsx new file mode 100644 index 0000000..d7b89d6 --- /dev/null +++ b/fast-context-generic-extended/src/components/ContentContainer.tsx @@ -0,0 +1,13 @@ +import FormContainer from "./FormContainer"; +import DisplayContainer from "./DisplayContainer"; + +export default function ContentContainer() { + console.log(`Content Rendering`) + return ( +
+

ContentContainer

+ + +
+ ); +}; diff --git a/fast-context-generic-extended/src/components/Display.tsx b/fast-context-generic-extended/src/components/Display.tsx new file mode 100644 index 0000000..61ab24b --- /dev/null +++ b/fast-context-generic-extended/src/components/Display.tsx @@ -0,0 +1,13 @@ +type Props = { + label?: string; + value: string; +}; +export default function Display({label, value}: Readonly) { + console.log(`${label} display change`) + return ( +
+ {label ? : null} + +
+ ); +}; diff --git a/fast-context-generic-extended/src/components/DisplayContainer.tsx b/fast-context-generic-extended/src/components/DisplayContainer.tsx new file mode 100644 index 0000000..aa29bd5 --- /dev/null +++ b/fast-context-generic-extended/src/components/DisplayContainer.tsx @@ -0,0 +1,15 @@ +import { useAppFastContextField } from "../App"; +import Display from "./Display"; + +export default function DisplayContainer() { + console.log(`Display Rendering`) + const [first] = useAppFastContextField('first'); + const [last] = useAppFastContextField('last'); + return ( +
+

DisplayContainer

+ + +
+ ); +}; diff --git a/fast-context-generic-extended/src/components/FormContainer.tsx b/fast-context-generic-extended/src/components/FormContainer.tsx new file mode 100644 index 0000000..e0a5214 --- /dev/null +++ b/fast-context-generic-extended/src/components/FormContainer.tsx @@ -0,0 +1,15 @@ +import { useAppFastContextField } from "../App"; +import TextInput from "./TextInput"; + +export default function FormContainer() { + console.log(`Form Rendering`) + const [firstName, setFirstName] = useAppFastContextField("first"); + const [lastName, setLastName] = useAppFastContextField("last"); + return ( +
+

FormContainer

+ + +
+ ); +}; \ No newline at end of file diff --git a/fast-context-generic-extended/src/components/TextInput.tsx b/fast-context-generic-extended/src/components/TextInput.tsx new file mode 100644 index 0000000..3696433 --- /dev/null +++ b/fast-context-generic-extended/src/components/TextInput.tsx @@ -0,0 +1,16 @@ +type Props = { + label?: string; + value: string; + onChange: (value: string) => void; +}; +export default function TextInput( { label = '', value, onChange}: Readonly ) { + return ( +
+ {label ? : null} + onChange(e.target.value)} + /> +
+ ); +}; diff --git a/fast-context-generic-extended/src/createFastContext.tsx b/fast-context-generic-extended/src/createFastContext.tsx deleted file mode 100644 index 292c1cf..0000000 --- a/fast-context-generic-extended/src/createFastContext.tsx +++ /dev/null @@ -1,71 +0,0 @@ -import React, { - useRef, - createContext, - useContext, - useCallback, - useSyncExternalStore, -} from "react"; - -export default function createFastContext(initialState: Store) { - function useStoreData(): { - get: () => Store; - set: (value: Partial) => void; - subscribe: (callback: () => void) => () => void; - } { - const store = useRef(initialState); - - const get = useCallback(() => store.current, []); - - const subscribers = useRef(new Set<() => void>()); - - const set = useCallback((value: Partial) => { - store.current = { ...store.current, ...value }; - subscribers.current.forEach((callback) => callback()); - }, []); - - const subscribe = useCallback((callback: () => void) => { - subscribers.current.add(callback); - return () => subscribers.current.delete(callback); - }, []); - - return { - get, - set, - subscribe, - }; - } - - type UseStoreDataReturnType = ReturnType; - - const StoreContext = createContext(null); - - function Provider({ children }: { children: React.ReactNode }) { - return ( - - {children} - - ); - } - - function useStore( - selector: (store: Store) => SelectorOutput - ): [SelectorOutput, (value: Partial) => void] { - const store = useContext(StoreContext); - if (!store) { - throw new Error("Store not found"); - } - - const state = useSyncExternalStore( - store.subscribe, - () => selector(store.get()), - () => selector(initialState), - ); - - return [state, store.set]; - } - - return { - Provider, - useStore, - }; -} diff --git a/fast-context-generic-extended/src/pages/MainPage.tsx b/fast-context-generic-extended/src/pages/MainPage.tsx new file mode 100644 index 0000000..dccdcbe --- /dev/null +++ b/fast-context-generic-extended/src/pages/MainPage.tsx @@ -0,0 +1,12 @@ +import ContentContainer from "../components/ContentContainer"; + + +export default function MainPage() { + console.log(`Page Rendering`) + return ( +
+

Page

+ +
+ ); +} From 775a8a7cb9f2ad56701ba6e7ea40d89b12e5117a Mon Sep 17 00:00:00 2001 From: Craig Date: Sun, 28 Apr 2024 00:17:53 +0100 Subject: [PATCH 3/6] wip: split into self and prop driven versions --- .../public/DevToolsImage.png | Bin 0 -> 42520 bytes fast-context-generic-extended/src/App.tsx | 5 +++- .../src/app/createFastContext.tsx | 1 - .../src/components/ContentContainer.tsx | 25 +++++++++++++----- .../src/components/Display.tsx | 20 +++++++++++--- .../src/components/DisplayContainer.tsx | 23 +++++++++++----- .../src/components/FormContainer.tsx | 23 +++++++++++----- .../src/components/TextInput.tsx | 25 +++++++++++++++--- .../src/pages/MainPage.tsx | 10 ++++--- 9 files changed, 101 insertions(+), 31 deletions(-) create mode 100644 fast-context-generic-extended/public/DevToolsImage.png diff --git a/fast-context-generic-extended/public/DevToolsImage.png b/fast-context-generic-extended/public/DevToolsImage.png new file mode 100644 index 0000000000000000000000000000000000000000..6b44162e2ebecc2d2545c40461c65c0ede0b7c89 GIT binary patch literal 42520 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
-

App

+ Dev Tools +

App (NO RE-RENDERS)

+

The App's Fast Context is created and exported here, but could be created in any file.

+

Switch on the re-render highlight function (see image) in dev tools to see when re-renders happen.

diff --git a/fast-context-generic-extended/src/app/createFastContext.tsx b/fast-context-generic-extended/src/app/createFastContext.tsx index 6676673..052c30d 100644 --- a/fast-context-generic-extended/src/app/createFastContext.tsx +++ b/fast-context-generic-extended/src/app/createFastContext.tsx @@ -19,7 +19,6 @@ export default function createFastContext(initialState: FastContext const subscribers = useRef(new Set<() => void>()); const set = useCallback((value: Partial) => { - console.log('set', value); store.current = { ...store.current, ...value }; subscribers.current.forEach((callback) => callback()); }, []); diff --git a/fast-context-generic-extended/src/components/ContentContainer.tsx b/fast-context-generic-extended/src/components/ContentContainer.tsx index d7b89d6..04ca13f 100644 --- a/fast-context-generic-extended/src/components/ContentContainer.tsx +++ b/fast-context-generic-extended/src/components/ContentContainer.tsx @@ -1,13 +1,24 @@ -import FormContainer from "./FormContainer"; -import DisplayContainer from "./DisplayContainer"; +import { PropDrivenDisplayContainer, SelfDrivenDisplayContainer } from "./DisplayContainer"; +import { PropDrivenFormContainer, SelfDrivenFormContainer } from "./FormContainer"; -export default function ContentContainer() { - console.log(`Content Rendering`) +export function PropDrivenContentContainer() { + console.log(`Prop Driven Content Rendering`) return (
-

ContentContainer

- - +

'Prop Driven' Content Container (NO RE-RENDERS)

+ + +
+ ); +}; + +export function SelfDrivenContentContainer() { + console.log(`Self Driven Content Rendering`) + return ( +
+

'Self Driven' Content Container (NO RE-RENDERS)

+ +
); }; diff --git a/fast-context-generic-extended/src/components/Display.tsx b/fast-context-generic-extended/src/components/Display.tsx index 61ab24b..a5eb93f 100644 --- a/fast-context-generic-extended/src/components/Display.tsx +++ b/fast-context-generic-extended/src/components/Display.tsx @@ -1,9 +1,12 @@ +import { useAppFastContextField } from "../App"; + type Props = { + fieldName?: string; label?: string; - value: string; + value?: string; }; -export default function Display({label, value}: Readonly) { - console.log(`${label} display change`) +export function PropDrivenDisplay({label, value}: Readonly) { + console.log(`Prop Driven ${label} display rendering`) return (
{label ? : null} @@ -11,3 +14,14 @@ export default function Display({label, value}: Readonly) {
); }; + +export function SelfDrivenDisplay({ fieldName, label }: Readonly) { + console.log(`Self Driven ${label} display rendering`) + const [value] = useAppFastContextField(fieldName as string); + return ( +
+ {label ? : null} + +
+ ); +}; diff --git a/fast-context-generic-extended/src/components/DisplayContainer.tsx b/fast-context-generic-extended/src/components/DisplayContainer.tsx index aa29bd5..6b2e8b8 100644 --- a/fast-context-generic-extended/src/components/DisplayContainer.tsx +++ b/fast-context-generic-extended/src/components/DisplayContainer.tsx @@ -1,15 +1,26 @@ import { useAppFastContextField } from "../App"; -import Display from "./Display"; +import { PropDrivenDisplay, SelfDrivenDisplay } from "./Display"; -export default function DisplayContainer() { - console.log(`Display Rendering`) +export function PropDrivenDisplayContainer() { + console.log(`Prop Driven Display Rendering`) const [first] = useAppFastContextField('first'); const [last] = useAppFastContextField('last'); return (
-

DisplayContainer

- - +

'Prop Driven' Display (Container AND children re-render on field changes)

+ + +
+ ); +}; + +export function SelfDrivenDisplayContainer() { + console.log(`Self Driven Display Rendering`) + return ( +
+

'Self Driven' Display (NO RE-RENDERS - only children re-render on field changes)

+ +
); }; diff --git a/fast-context-generic-extended/src/components/FormContainer.tsx b/fast-context-generic-extended/src/components/FormContainer.tsx index e0a5214..aa6ce36 100644 --- a/fast-context-generic-extended/src/components/FormContainer.tsx +++ b/fast-context-generic-extended/src/components/FormContainer.tsx @@ -1,15 +1,26 @@ import { useAppFastContextField } from "../App"; -import TextInput from "./TextInput"; +import { FormDrivenTextInput, SelfDrivenTextInput } from "./TextInput"; -export default function FormContainer() { - console.log(`Form Rendering`) +export function PropDrivenFormContainer() { + console.log(`Prop Driven Form Rendering`) const [firstName, setFirstName] = useAppFastContextField("first"); const [lastName, setLastName] = useAppFastContextField("last"); return (
-

FormContainer

- - +

'Prop Driven' Input Form (Form AND children re-render on field changes)

+ + +
+ ); +}; + +export function SelfDrivenFormContainer() { + console.log(`Self Driven Form Rendering`) + return ( +
+

'Self Driven' Input Form (NO RE-RENDERS - only children re-render on field changes)

+ +
); }; \ No newline at end of file diff --git a/fast-context-generic-extended/src/components/TextInput.tsx b/fast-context-generic-extended/src/components/TextInput.tsx index 3696433..37b7b80 100644 --- a/fast-context-generic-extended/src/components/TextInput.tsx +++ b/fast-context-generic-extended/src/components/TextInput.tsx @@ -1,9 +1,13 @@ +import { useAppFastContextField } from "../App"; + type Props = { + fieldName?: string; label?: string; - value: string; - onChange: (value: string) => void; + value?: string; + onChange?: (value: string) => void; }; -export default function TextInput( { label = '', value, onChange}: Readonly ) { +export function FormDrivenTextInput( { label = '', value, onChange = (v) => {}}: Readonly ) { + console.log(`Prop Driven ${label} input rendering`) return (
{label ? : null} @@ -14,3 +18,18 @@ export default function TextInput( { label = '', value, onChange}: Readonly ); }; + + +export function SelfDrivenTextInput( { fieldName, label }: Readonly ) { + console.log(`Self Driven ${label} input rendering`) + const [value, setValue] = useAppFastContextField(fieldName as string); + return ( +
+ {label ? : null} + setValue(e.target.value)} + /> +
+ ); +}; diff --git a/fast-context-generic-extended/src/pages/MainPage.tsx b/fast-context-generic-extended/src/pages/MainPage.tsx index dccdcbe..9f159c7 100644 --- a/fast-context-generic-extended/src/pages/MainPage.tsx +++ b/fast-context-generic-extended/src/pages/MainPage.tsx @@ -1,12 +1,14 @@ -import ContentContainer from "../components/ContentContainer"; - +import { PropDrivenContentContainer, SelfDrivenContentContainer } from "../components/ContentContainer"; export default function MainPage() { console.log(`Page Rendering`) return (
-

Page

- +

Page (NO RE-RENDERS)

+
+ + +
); } From b3c2847a45d342ad852f8369bc9e6317c02e88b4 Mon Sep 17 00:00:00 2001 From: Craig Date: Sun, 28 Apr 2024 01:16:33 +0100 Subject: [PATCH 4/6] extended demo completed --- .../src/app/createFastContext.tsx | 16 +++++++++++----- .../src/components/DisplayContainer.tsx | 9 ++++----- .../src/components/FormContainer.tsx | 9 ++++----- 3 files changed, 19 insertions(+), 15 deletions(-) diff --git a/fast-context-generic-extended/src/app/createFastContext.tsx b/fast-context-generic-extended/src/app/createFastContext.tsx index 052c30d..af64590 100644 --- a/fast-context-generic-extended/src/app/createFastContext.tsx +++ b/fast-context-generic-extended/src/app/createFastContext.tsx @@ -66,16 +66,22 @@ export default function createFastContext(initialState: FastContext function useFastContextField( field: string - ): [SelectorOutput, (value: SelectorOutput) => void]{ - const [fieldValue, setter] = useFastContext((store) => (store as Record)[field]); + ): [SelectorOutput, (value: SelectorOutput) => void] { + const [fieldValue, setter] = useFastContext((fc) => (fc as Record)[field]); const setField = (value: any) => setter({ [field]: value } as Partial); return [fieldValue, setField as (value: SelectorOutput) => void]; } function useFastContextFields( - field: string[] - ): [SelectorOutput, (value: Partial) => void][] { - return [useFastContext((store) => (store as Record)[field[0]])]; + fieldNames: string[] + ): { [key: string]: { get: SelectorOutput, set: (value: any) => void } } { + const valuesAndSetters: { [key: string]: { get: SelectorOutput, set: (value: any) => void } } = {}; + for (const fieldName of fieldNames) { + const [fieldValue, setter] = useFastContextField(fieldName); + valuesAndSetters[fieldName] = { get: fieldValue as SelectorOutput, set: setter }; + } + return valuesAndSetters; + } return { diff --git a/fast-context-generic-extended/src/components/DisplayContainer.tsx b/fast-context-generic-extended/src/components/DisplayContainer.tsx index 6b2e8b8..7f82792 100644 --- a/fast-context-generic-extended/src/components/DisplayContainer.tsx +++ b/fast-context-generic-extended/src/components/DisplayContainer.tsx @@ -1,15 +1,14 @@ -import { useAppFastContextField } from "../App"; +import { useAppFastContextFields } from "../App"; import { PropDrivenDisplay, SelfDrivenDisplay } from "./Display"; export function PropDrivenDisplayContainer() { console.log(`Prop Driven Display Rendering`) - const [first] = useAppFastContextField('first'); - const [last] = useAppFastContextField('last'); + const fields = useAppFastContextFields(['first', 'last']); return (

'Prop Driven' Display (Container AND children re-render on field changes)

- - + +
); }; diff --git a/fast-context-generic-extended/src/components/FormContainer.tsx b/fast-context-generic-extended/src/components/FormContainer.tsx index aa6ce36..8f98523 100644 --- a/fast-context-generic-extended/src/components/FormContainer.tsx +++ b/fast-context-generic-extended/src/components/FormContainer.tsx @@ -1,15 +1,14 @@ -import { useAppFastContextField } from "../App"; +import { useAppFastContextFields } from "../App"; import { FormDrivenTextInput, SelfDrivenTextInput } from "./TextInput"; export function PropDrivenFormContainer() { console.log(`Prop Driven Form Rendering`) - const [firstName, setFirstName] = useAppFastContextField("first"); - const [lastName, setLastName] = useAppFastContextField("last"); + const fields = useAppFastContextFields(['first', 'last']); return (

'Prop Driven' Input Form (Form AND children re-render on field changes)

- - + +
); }; From d9f067545107eeade87f5782a71a96bc5f3b87ac Mon Sep 17 00:00:00 2001 From: Craig Date: Sun, 28 Apr 2024 01:55:11 +0100 Subject: [PATCH 5/6] removed use single field option --- fast-context-generic-extended/src/App.tsx | 1 - .../src/app/createFastContext.tsx | 19 +++++-------------- .../src/components/Display.tsx | 8 ++++---- .../src/components/FormContainer.tsx | 1 + .../src/components/TextInput.tsx | 10 +++++----- 5 files changed, 15 insertions(+), 24 deletions(-) diff --git a/fast-context-generic-extended/src/App.tsx b/fast-context-generic-extended/src/App.tsx index 592315d..dd201d8 100644 --- a/fast-context-generic-extended/src/App.tsx +++ b/fast-context-generic-extended/src/App.tsx @@ -3,7 +3,6 @@ import MainPage from "./pages/MainPage"; export const { FastContextProvider:AppFastContextProvider, - useFastContextField:useAppFastContextField, useFastContextFields:useAppFastContextFields } = createFastContext({ first: "" as string, diff --git a/fast-context-generic-extended/src/app/createFastContext.tsx b/fast-context-generic-extended/src/app/createFastContext.tsx index af64590..321fb7c 100644 --- a/fast-context-generic-extended/src/app/createFastContext.tsx +++ b/fast-context-generic-extended/src/app/createFastContext.tsx @@ -64,29 +64,20 @@ export default function createFastContext(initialState: FastContext return [state, fastContext.set]; } - function useFastContextField( - field: string - ): [SelectorOutput, (value: SelectorOutput) => void] { - const [fieldValue, setter] = useFastContext((fc) => (fc as Record)[field]); - const setField = (value: any) => setter({ [field]: value } as Partial); - return [fieldValue, setField as (value: SelectorOutput) => void]; - } - function useFastContextFields( fieldNames: string[] ): { [key: string]: { get: SelectorOutput, set: (value: any) => void } } { - const valuesAndSetters: { [key: string]: { get: SelectorOutput, set: (value: any) => void } } = {}; + const gettersAndSetters: { [key: string]: { get: SelectorOutput, set: (value: any) => void } } = {}; for (const fieldName of fieldNames) { - const [fieldValue, setter] = useFastContextField(fieldName); - valuesAndSetters[fieldName] = { get: fieldValue as SelectorOutput, set: setter }; + const [getter, setter] = useFastContext((fc) => (fc as Record)[fieldName]); + gettersAndSetters[fieldName] = { get: getter, set: (value: any) => setter({ [fieldName]: value } as Partial) }; } - return valuesAndSetters; - + + return gettersAndSetters; } return { FastContextProvider, - useFastContextField, useFastContextFields, }; } diff --git a/fast-context-generic-extended/src/components/Display.tsx b/fast-context-generic-extended/src/components/Display.tsx index a5eb93f..a62f8ba 100644 --- a/fast-context-generic-extended/src/components/Display.tsx +++ b/fast-context-generic-extended/src/components/Display.tsx @@ -1,4 +1,4 @@ -import { useAppFastContextField } from "../App"; +import { useAppFastContextFields } from "../App"; type Props = { fieldName?: string; @@ -15,13 +15,13 @@ export function PropDrivenDisplay({label, value}: Readonly) { ); }; -export function SelfDrivenDisplay({ fieldName, label }: Readonly) { +export function SelfDrivenDisplay({ fieldName = "", label }: Readonly) { console.log(`Self Driven ${label} display rendering`) - const [value] = useAppFastContextField(fieldName as string); + const value = useAppFastContextFields([fieldName]); return (
{label ? : null} - +
); }; diff --git a/fast-context-generic-extended/src/components/FormContainer.tsx b/fast-context-generic-extended/src/components/FormContainer.tsx index 8f98523..a41392d 100644 --- a/fast-context-generic-extended/src/components/FormContainer.tsx +++ b/fast-context-generic-extended/src/components/FormContainer.tsx @@ -4,6 +4,7 @@ import { FormDrivenTextInput, SelfDrivenTextInput } from "./TextInput"; export function PropDrivenFormContainer() { console.log(`Prop Driven Form Rendering`) const fields = useAppFastContextFields(['first', 'last']); + console.log(`fields:`, fields) return (

'Prop Driven' Input Form (Form AND children re-render on field changes)

diff --git a/fast-context-generic-extended/src/components/TextInput.tsx b/fast-context-generic-extended/src/components/TextInput.tsx index 37b7b80..ecd1bd2 100644 --- a/fast-context-generic-extended/src/components/TextInput.tsx +++ b/fast-context-generic-extended/src/components/TextInput.tsx @@ -1,4 +1,4 @@ -import { useAppFastContextField } from "../App"; +import { useAppFastContextFields } from "../App"; type Props = { fieldName?: string; @@ -20,15 +20,15 @@ export function FormDrivenTextInput( { label = '', value, onChange = (v) => {}}: }; -export function SelfDrivenTextInput( { fieldName, label }: Readonly ) { +export function SelfDrivenTextInput( { fieldName = "", label }: Readonly ) { console.log(`Self Driven ${label} input rendering`) - const [value, setValue] = useAppFastContextField(fieldName as string); + const field = useAppFastContextFields([fieldName]); return (
{label ? : null} setValue(e.target.value)} + value={field[fieldName].get as string} + onChange={(e) => field[fieldName].set(e.target.value)} />
); From eff84c7dcef14a04c52a75ea03c6918013734be1 Mon Sep 17 00:00:00 2001 From: Craig Date: Sun, 28 Apr 2024 02:13:46 +0100 Subject: [PATCH 6/6] fix: wrong field name --- fast-context-generic-extended/src/components/FormContainer.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fast-context-generic-extended/src/components/FormContainer.tsx b/fast-context-generic-extended/src/components/FormContainer.tsx index a41392d..da2bb34 100644 --- a/fast-context-generic-extended/src/components/FormContainer.tsx +++ b/fast-context-generic-extended/src/components/FormContainer.tsx @@ -8,7 +8,7 @@ export function PropDrivenFormContainer() { return (

'Prop Driven' Input Form (Form AND children re-render on field changes)

- +
);