├── src ├── vite-env.d.ts ├── index.jsx ├── styles.css ├── App.jsx ├── LegacyClassApp.jsx └── mini-react.ts ├── .vscode ├── settings.json └── launch.json ├── .prettierrc.json ├── .editorconfig ├── vite.config.ts ├── .gitignore ├── index.html ├── tsconfig.json ├── package.json ├── README.md ├── LICENSE └── pnpm-lock.yaml /src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.formatOnSave": true, 3 | "editor.codeActionsOnSave": { 4 | "source.fixAll": "explicit" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /.prettierrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 80, 3 | "singleQuote": true, 4 | "trailingComma": "all", 5 | "proseWrap": "never", 6 | "endOfLine": "lf" 7 | } 8 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | -------------------------------------------------------------------------------- /src/index.jsx: -------------------------------------------------------------------------------- 1 | // Forked from https://reactjs.org/tutorial/tutorial.html#what-are-we-building 2 | 3 | import React from './mini-react'; 4 | import App from './App'; // OR `LegacyClassApp` 5 | import './styles.css'; 6 | 7 | React.render(, document.getElementById('root')); 8 | -------------------------------------------------------------------------------- /vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite'; 2 | import react from '@vitejs/plugin-react'; 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | optimizeDeps: { 7 | include: [], 8 | }, 9 | plugins: [ 10 | react({ 11 | jsxRuntime: 'classic', 12 | }), 13 | ], 14 | }); 15 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .idea 17 | .DS_Store 18 | *.suo 19 | *.ntvs* 20 | *.njsproj 21 | *.sln 22 | *.sw? 23 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Mini React App 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "type": "chrome", 9 | "request": "launch", 10 | "name": "Launch Chrome against localhost", 11 | "url": "http://localhost:5173", 12 | "webRoot": "${workspaceFolder}" 13 | } 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "module": "ESNext", 5 | "strict": true, 6 | "useDefineForClassFields": true, 7 | "lib": ["DOM", "DOM.Iterable", "ESNext"], 8 | "allowJs": true, 9 | "skipLibCheck": false, 10 | "esModuleInterop": false, 11 | "allowSyntheticDefaultImports": true, 12 | "forceConsistentCasingInFileNames": true, 13 | "moduleResolution": "Bundler", 14 | "resolveJsonModule": true, 15 | "isolatedModules": true, 16 | "noEmit": true, 17 | "jsx": "react-jsx" 18 | }, 19 | "include": ["src"] 20 | } 21 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mini-react", 3 | "version": "1.0.0", 4 | "type": "module", 5 | "packageManager": "pnpm@9.1.0", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "tsc && vite build", 9 | "preview": "vite preview" 10 | }, 11 | "dependencies": {}, 12 | "devDependencies": { 13 | "@vitejs/plugin-react": "^4.2.1", 14 | "typescript": "^5.4.5", 15 | "vite": "^5.2.11" 16 | }, 17 | "keywords": [ 18 | "react" 19 | ], 20 | "author": "", 21 | "license": "MIT", 22 | "bugs": { 23 | "url": "https://github.com/islizeqiang/mini-react/issues" 24 | }, 25 | "repository": { 26 | "type": "git", 27 | "url": "git+https://github.com/islizeqiang/mini-react.git" 28 | }, 29 | "homepage": "https://github.com/islizeqiang/mini-react#readme" 30 | } 31 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![Presentation](https://i.imgur.com/esCwk1l.png) 2 | 3 | # Mini-React 4 | 5 | **Implement Mini-React in 400 lines of code, a minimal model with asynchronous interruptible updates.** 6 | 7 | # Demos 8 | 9 | [Online Demo](https://stackblitz.com/~/github.com/ZacharyL2/mini-react) 10 | 11 | A simple running screenshot: 12 | 13 | ![Demo](https://i.imgur.com/wQV5IaC.gif) 14 | 15 | # Introduce 16 | 17 | I used the [Tic-Tac-Toe](https://react.dev/learn/tutorial-tic-tac-toe) tutorial example provided on the React website, and it works well. 18 | 19 | Additionally, it supports both functional and class components. Its overall logic and function naming are largely consistent with React's fundamentals. If you are interested in the inner workings of React, then this tutorial is suitable for you! 20 | 21 | [**See how to build it.**](https://webdeveloper.beehiiv.com/p/build-react-400-lines-code) 22 | 23 | # License 24 | 25 | [MIT](https://github.com/islizeqiang/mini-react/blob/master/LICENSE) 26 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Zachary Lee 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/styles.css: -------------------------------------------------------------------------------- 1 | * { 2 | box-sizing: border-box; 3 | } 4 | 5 | body { 6 | font-family: sans-serif; 7 | margin: 20px; 8 | padding: 0; 9 | } 10 | 11 | h1 { 12 | margin-top: 0; 13 | font-size: 22px; 14 | } 15 | 16 | h2 { 17 | margin-top: 0; 18 | font-size: 20px; 19 | } 20 | 21 | h3 { 22 | margin-top: 0; 23 | font-size: 18px; 24 | } 25 | 26 | h4 { 27 | margin-top: 0; 28 | font-size: 16px; 29 | } 30 | 31 | h5 { 32 | margin-top: 0; 33 | font-size: 14px; 34 | } 35 | 36 | h6 { 37 | margin-top: 0; 38 | font-size: 12px; 39 | } 40 | 41 | code { 42 | font-size: 1.2em; 43 | } 44 | 45 | ul { 46 | padding-inline-start: 20px; 47 | } 48 | 49 | * { 50 | box-sizing: border-box; 51 | } 52 | 53 | body { 54 | font-family: sans-serif; 55 | margin: 20px; 56 | padding: 0; 57 | } 58 | 59 | .square { 60 | background: #fff; 61 | border: 1px solid #999; 62 | float: left; 63 | font-size: 24px; 64 | font-weight: bold; 65 | line-height: 34px; 66 | height: 34px; 67 | margin-right: -1px; 68 | margin-top: -1px; 69 | padding: 0; 70 | text-align: center; 71 | width: 34px; 72 | } 73 | 74 | .board-row:after { 75 | clear: both; 76 | content: ''; 77 | display: table; 78 | } 79 | 80 | .status { 81 | margin-bottom: 10px; 82 | } 83 | .game { 84 | display: flex; 85 | flex-direction: row; 86 | } 87 | 88 | .game-info { 89 | margin-left: 20px; 90 | } 91 | -------------------------------------------------------------------------------- /src/App.jsx: -------------------------------------------------------------------------------- 1 | import React from './mini-react'; 2 | 3 | const { useState } = React; 4 | 5 | function Square({ value, onSquareClick }) { 6 | return ( 7 | 10 | ); 11 | } 12 | 13 | function Board({ xIsNext, squares, onPlay }) { 14 | function handleClick(i) { 15 | if (calculateWinner(squares) || squares[i]) { 16 | return; 17 | } 18 | const nextSquares = squares.slice(); 19 | if (xIsNext) { 20 | nextSquares[i] = 'X'; 21 | } else { 22 | nextSquares[i] = 'O'; 23 | } 24 | onPlay(nextSquares); 25 | } 26 | 27 | const winner = calculateWinner(squares); 28 | let status; 29 | if (winner) { 30 | status = 'Winner: ' + winner; 31 | } else { 32 | status = 'Next player: ' + (xIsNext ? 'X' : 'O'); 33 | } 34 | 35 | return ( 36 | <> 37 |
{status}
38 |
39 | handleClick(0)} /> 40 | handleClick(1)} /> 41 | handleClick(2)} /> 42 |
43 |
44 | handleClick(3)} /> 45 | handleClick(4)} /> 46 | handleClick(5)} /> 47 |
48 |
49 | handleClick(6)} /> 50 | handleClick(7)} /> 51 | handleClick(8)} /> 52 |
53 | 54 | ); 55 | } 56 | 57 | export default function Game() { 58 | const [history, setHistory] = useState([Array(9).fill(null)]); 59 | const [currentMove, setCurrentMove] = useState(0); 60 | const xIsNext = currentMove % 2 === 0; 61 | const currentSquares = history[currentMove]; 62 | 63 | function handlePlay(nextSquares) { 64 | const nextHistory = [...history.slice(0, currentMove + 1), nextSquares]; 65 | setHistory(nextHistory); 66 | setCurrentMove(nextHistory.length - 1); 67 | } 68 | 69 | function jumpTo(nextMove) { 70 | setCurrentMove(nextMove); 71 | } 72 | 73 | const moves = history.map((squares, move) => { 74 | let description; 75 | if (move > 0) { 76 | description = 'Go to move #' + move; 77 | } else { 78 | description = 'Go to game start'; 79 | } 80 | return ( 81 |
  • 82 | 83 |
  • 84 | ); 85 | }); 86 | 87 | return ( 88 |
    89 |
    90 | 91 |
    92 |
    93 |
      {moves}
    94 |
    95 |
    96 | ); 97 | } 98 | 99 | function calculateWinner(squares) { 100 | const lines = [ 101 | [0, 1, 2], 102 | [3, 4, 5], 103 | [6, 7, 8], 104 | [0, 3, 6], 105 | [1, 4, 7], 106 | [2, 5, 8], 107 | [0, 4, 8], 108 | [2, 4, 6], 109 | ]; 110 | for (let i = 0; i < lines.length; i++) { 111 | const [a, b, c] = lines[i]; 112 | if (squares[a] && squares[a] === squares[b] && squares[a] === squares[c]) { 113 | return squares[a]; 114 | } 115 | } 116 | return null; 117 | } 118 | -------------------------------------------------------------------------------- /src/LegacyClassApp.jsx: -------------------------------------------------------------------------------- 1 | import React from './mini-react'; 2 | 3 | function calculateWinner(squares) { 4 | const lines = [ 5 | [0, 1, 2], 6 | [3, 4, 5], 7 | [6, 7, 8], 8 | [0, 3, 6], 9 | [1, 4, 7], 10 | [2, 5, 8], 11 | [0, 4, 8], 12 | [2, 4, 6], 13 | ]; 14 | for (let i = 0; i < lines.length; i += 1) { 15 | const [a, b, c] = lines[i]; 16 | if (squares[a] && squares[a] === squares[b] && squares[a] === squares[c]) { 17 | return squares[a]; 18 | } 19 | } 20 | return null; 21 | } 22 | 23 | class Square extends React.Component { 24 | render() { 25 | return ( 26 | 29 | ); 30 | } 31 | } 32 | 33 | class Board extends React.Component { 34 | renderSquare(i) { 35 | return ( 36 | { 39 | this.props.onClick(i); 40 | }} 41 | /> 42 | ); 43 | } 44 | 45 | render() { 46 | return ( 47 |
    48 |
    49 | {this.renderSquare(0)} 50 | {this.renderSquare(1)} 51 | {this.renderSquare(2)} 52 |
    53 |
    54 | {this.renderSquare(3)} 55 | {this.renderSquare(4)} 56 | {this.renderSquare(5)} 57 |
    58 |
    59 | {this.renderSquare(6)} 60 | {this.renderSquare(7)} 61 | {this.renderSquare(8)} 62 |
    63 |
    64 | ); 65 | } 66 | } 67 | 68 | class App extends React.Component { 69 | constructor(props) { 70 | super(props); 71 | this.state = { 72 | history: [ 73 | { 74 | squares: Array(9).fill(null), 75 | }, 76 | ], 77 | stepNumber: 0, 78 | xIsNext: true, 79 | }; 80 | } 81 | 82 | handleClick(i) { 83 | const history = this.state.history.slice(0, this.state.stepNumber + 1); 84 | const current = history[history.length - 1]; 85 | const squares = current.squares.slice(); 86 | if (calculateWinner(squares) || squares[i]) { 87 | return; 88 | } 89 | 90 | squares[i] = this.state.xIsNext ? 'X' : 'O'; 91 | this.setState({ 92 | history: history.concat([ 93 | { 94 | squares, 95 | }, 96 | ]), 97 | stepNumber: history.length, 98 | xIsNext: !this.state.xIsNext, 99 | }); 100 | } 101 | 102 | jumpTo(step) { 103 | this.setState({ 104 | stepNumber: step, 105 | xIsNext: step % 2 === 0, 106 | }); 107 | } 108 | 109 | render() { 110 | const { history } = this.state; 111 | const current = history[this.state.stepNumber]; 112 | const winner = calculateWinner(current.squares); 113 | 114 | const moves = history.map((step, move) => { 115 | const desc = move ? `Go to move #${move}` : 'Go to game start'; 116 | return ( 117 |
  • 118 | 119 |
  • 120 | ); 121 | }); 122 | 123 | let status; 124 | if (winner) { 125 | status = `Winner: ${winner}`; 126 | } else { 127 | status = `Next player: ${this.state.xIsNext ? 'X' : 'O'}`; 128 | } 129 | 130 | return ( 131 |
    132 |
    133 | { 136 | this.handleClick(i); 137 | }} 138 | /> 139 |
    140 |
    141 |
    {status}
    142 |
      {moves}
    143 |
    144 |
    145 | ); 146 | } 147 | } 148 | 149 | export default App; 150 | -------------------------------------------------------------------------------- /src/mini-react.ts: -------------------------------------------------------------------------------- 1 | // TODO Optimization Type Description 2 | 3 | interface ComponentFunction { 4 | new (props: Record): Component; 5 | (props: Record): VirtualElement | string; 6 | } 7 | type VirtualElementType = ComponentFunction | string; 8 | 9 | interface VirtualElementProps { 10 | children?: VirtualElement[]; 11 | [propName: string]: unknown; 12 | } 13 | interface VirtualElement { 14 | type: VirtualElementType; 15 | props: VirtualElementProps; 16 | } 17 | 18 | type FiberNodeDOM = Element | Text | null | undefined; 19 | interface FiberNode extends VirtualElement { 20 | alternate: FiberNode | null; 21 | dom?: FiberNodeDOM; 22 | effectTag?: string; 23 | child?: FiberNode; 24 | return?: FiberNode; 25 | sibling?: FiberNode; 26 | hooks?: { 27 | state: S; 28 | queue: S[]; 29 | }[]; 30 | } 31 | 32 | let wipRoot: FiberNode | null = null; 33 | let nextUnitOfWork: FiberNode | null = null; 34 | let currentRoot: FiberNode | null = null; 35 | let deletions: FiberNode[] = []; 36 | let wipFiber: FiberNode; 37 | let hookIndex = 0; 38 | // Support React.Fragment syntax. 39 | const Fragment = Symbol.for('react.fragment'); 40 | 41 | // Enhanced requestIdleCallback. 42 | ((global: Window) => { 43 | const id = 1; 44 | const fps = 1e3 / 60; 45 | let frameDeadline: number; 46 | let pendingCallback: IdleRequestCallback; 47 | const channel = new MessageChannel(); 48 | const timeRemaining = () => frameDeadline - window.performance.now(); 49 | 50 | const deadline = { 51 | didTimeout: false, 52 | timeRemaining, 53 | }; 54 | 55 | channel.port2.onmessage = () => { 56 | if (typeof pendingCallback === 'function') { 57 | pendingCallback(deadline); 58 | } 59 | }; 60 | 61 | global.requestIdleCallback = (callback: IdleRequestCallback) => { 62 | global.requestAnimationFrame((frameTime) => { 63 | frameDeadline = frameTime + fps; 64 | pendingCallback = callback; 65 | channel.port1.postMessage(null); 66 | }); 67 | return id; 68 | }; 69 | })(window); 70 | 71 | const isDef = (param: T): param is NonNullable => 72 | param !== void 0 && param !== null; 73 | 74 | const isPlainObject = (val: unknown): val is Record => 75 | Object.prototype.toString.call(val) === '[object Object]' && 76 | [Object.prototype, null].includes(Object.getPrototypeOf(val)); 77 | 78 | // Simple judgment of virtual elements. 79 | const isVirtualElement = (e: unknown): e is VirtualElement => 80 | typeof e === 'object'; 81 | 82 | // Text elements require special handling. 83 | const createTextElement = (text: string): VirtualElement => ({ 84 | type: 'TEXT', 85 | props: { 86 | nodeValue: text, 87 | }, 88 | }); 89 | 90 | // Create custom JavaScript data structures. 91 | const createElement = ( 92 | type: VirtualElementType, 93 | props: Record = {}, 94 | ...child: (unknown | VirtualElement)[] 95 | ): VirtualElement => { 96 | const children = child.map((c) => 97 | isVirtualElement(c) ? c : createTextElement(String(c)), 98 | ); 99 | 100 | return { 101 | type, 102 | props: { 103 | ...props, 104 | children, 105 | }, 106 | }; 107 | }; 108 | 109 | // Update DOM properties. 110 | // For simplicity, we remove all the previous properties and add next properties. 111 | const updateDOM = ( 112 | DOM: NonNullable, 113 | prevProps: VirtualElementProps, 114 | nextProps: VirtualElementProps, 115 | ) => { 116 | const defaultPropKeys = 'children'; 117 | 118 | for (const [removePropKey, removePropValue] of Object.entries(prevProps)) { 119 | if (removePropKey.startsWith('on')) { 120 | DOM.removeEventListener( 121 | removePropKey.slice(2).toLowerCase(), 122 | removePropValue as EventListener, 123 | ); 124 | } else if (removePropKey !== defaultPropKeys) { 125 | // @ts-expect-error: Unreachable code error 126 | DOM[removePropKey] = ''; 127 | } 128 | } 129 | 130 | for (const [addPropKey, addPropValue] of Object.entries(nextProps)) { 131 | if (addPropKey.startsWith('on')) { 132 | DOM.addEventListener( 133 | addPropKey.slice(2).toLowerCase(), 134 | addPropValue as EventListener, 135 | ); 136 | } else if (addPropKey !== defaultPropKeys) { 137 | // @ts-expect-error: Unreachable code error 138 | DOM[addPropKey] = addPropValue; 139 | } 140 | } 141 | }; 142 | 143 | // Create DOM based on node type. 144 | const createDOM = (fiberNode: FiberNode): FiberNodeDOM => { 145 | const { type, props } = fiberNode; 146 | let DOM: FiberNodeDOM = null; 147 | 148 | if (type === 'TEXT') { 149 | DOM = document.createTextNode(''); 150 | } else if (typeof type === 'string') { 151 | DOM = document.createElement(type); 152 | } 153 | 154 | // Update properties based on props after creation. 155 | if (DOM !== null) { 156 | updateDOM(DOM, {}, props); 157 | } 158 | 159 | return DOM; 160 | }; 161 | 162 | // Change the DOM based on fiber node changes. 163 | // Note that we must complete the comparison of all fiber nodes before commitRoot. 164 | // The comparison of fiber nodes can be interrupted, but the commitRoot cannot be interrupted. 165 | const commitRoot = () => { 166 | const findParentFiber = (fiberNode?: FiberNode) => { 167 | if (fiberNode) { 168 | let parentFiber = fiberNode.return; 169 | while (parentFiber && !parentFiber.dom) { 170 | parentFiber = parentFiber.return; 171 | } 172 | return parentFiber; 173 | } 174 | 175 | return null; 176 | }; 177 | 178 | const commitDeletion = ( 179 | parentDOM: FiberNodeDOM, 180 | DOM: NonNullable, 181 | ) => { 182 | if (isDef(parentDOM)) { 183 | parentDOM.removeChild(DOM); 184 | } 185 | }; 186 | 187 | const commitReplacement = ( 188 | parentDOM: FiberNodeDOM, 189 | DOM: NonNullable, 190 | ) => { 191 | if (isDef(parentDOM)) { 192 | parentDOM.appendChild(DOM); 193 | } 194 | }; 195 | 196 | const commitWork = (fiberNode?: FiberNode) => { 197 | if (fiberNode) { 198 | if (fiberNode.dom) { 199 | const parentFiber = findParentFiber(fiberNode); 200 | const parentDOM = parentFiber?.dom; 201 | 202 | switch (fiberNode.effectTag) { 203 | case 'REPLACEMENT': 204 | commitReplacement(parentDOM, fiberNode.dom); 205 | break; 206 | case 'UPDATE': 207 | updateDOM( 208 | fiberNode.dom, 209 | fiberNode.alternate ? fiberNode.alternate.props : {}, 210 | fiberNode.props, 211 | ); 212 | break; 213 | default: 214 | break; 215 | } 216 | } 217 | 218 | commitWork(fiberNode.child); 219 | commitWork(fiberNode.sibling); 220 | } 221 | }; 222 | 223 | for (const deletion of deletions) { 224 | if (deletion.dom) { 225 | const parentFiber = findParentFiber(deletion); 226 | commitDeletion(parentFiber?.dom, deletion.dom); 227 | } 228 | } 229 | 230 | if (wipRoot !== null) { 231 | commitWork(wipRoot.child); 232 | currentRoot = wipRoot; 233 | } 234 | 235 | wipRoot = null; 236 | }; 237 | 238 | // Reconcile the fiber nodes before and after, compare and record the differences. 239 | const reconcileChildren = ( 240 | fiberNode: FiberNode, 241 | elements: VirtualElement[] = [], 242 | ) => { 243 | let index = 0; 244 | let oldFiberNode: FiberNode | undefined = void 0; 245 | let prevSibling: FiberNode | undefined = void 0; 246 | const virtualElements = elements.flat(Infinity); 247 | 248 | if (fiberNode.alternate?.child) { 249 | oldFiberNode = fiberNode.alternate.child; 250 | } 251 | 252 | while ( 253 | index < virtualElements.length || 254 | typeof oldFiberNode !== 'undefined' 255 | ) { 256 | const virtualElement = virtualElements[index]; 257 | let newFiber: FiberNode | undefined = void 0; 258 | 259 | const isSameType = Boolean( 260 | oldFiberNode && 261 | virtualElement && 262 | oldFiberNode.type === virtualElement.type, 263 | ); 264 | 265 | if (isSameType && oldFiberNode) { 266 | newFiber = { 267 | type: oldFiberNode.type, 268 | dom: oldFiberNode.dom, 269 | alternate: oldFiberNode, 270 | props: virtualElement.props, 271 | return: fiberNode, 272 | effectTag: 'UPDATE', 273 | }; 274 | } 275 | if (!isSameType && Boolean(virtualElement)) { 276 | newFiber = { 277 | type: virtualElement.type, 278 | dom: null, 279 | alternate: null, 280 | props: virtualElement.props, 281 | return: fiberNode, 282 | effectTag: 'REPLACEMENT', 283 | }; 284 | } 285 | if (!isSameType && oldFiberNode) { 286 | deletions.push(oldFiberNode); 287 | } 288 | 289 | if (oldFiberNode) { 290 | oldFiberNode = oldFiberNode.sibling; 291 | } 292 | 293 | if (index === 0) { 294 | fiberNode.child = newFiber; 295 | } else if (typeof prevSibling !== 'undefined') { 296 | prevSibling.sibling = newFiber; 297 | } 298 | 299 | prevSibling = newFiber; 300 | index += 1; 301 | } 302 | }; 303 | 304 | // Execute each unit task and return to the next unit task. 305 | // Different processing according to the type of fiber node. 306 | const performUnitOfWork = (fiberNode: FiberNode): FiberNode | null => { 307 | const { type } = fiberNode; 308 | switch (typeof type) { 309 | case 'function': { 310 | wipFiber = fiberNode; 311 | wipFiber.hooks = []; 312 | hookIndex = 0; 313 | let children: ReturnType; 314 | 315 | if (Object.getPrototypeOf(type).REACT_COMPONENT) { 316 | const C = type; 317 | const component = new C(fiberNode.props); 318 | const [state, setState] = useState(component.state); 319 | component.props = fiberNode.props; 320 | component.state = state; 321 | component.setState = setState; 322 | children = component.render.bind(component)(); 323 | } else { 324 | children = type(fiberNode.props); 325 | } 326 | reconcileChildren(fiberNode, [ 327 | isVirtualElement(children) 328 | ? children 329 | : createTextElement(String(children)), 330 | ]); 331 | break; 332 | } 333 | 334 | case 'number': 335 | case 'string': 336 | if (!fiberNode.dom) { 337 | fiberNode.dom = createDOM(fiberNode); 338 | } 339 | reconcileChildren(fiberNode, fiberNode.props.children); 340 | break; 341 | case 'symbol': 342 | if (type === Fragment) { 343 | reconcileChildren(fiberNode, fiberNode.props.children); 344 | } 345 | break; 346 | default: 347 | if (typeof fiberNode.props !== 'undefined') { 348 | reconcileChildren(fiberNode, fiberNode.props.children); 349 | } 350 | break; 351 | } 352 | 353 | if (fiberNode.child) { 354 | return fiberNode.child; 355 | } 356 | 357 | let nextFiberNode: FiberNode | undefined = fiberNode; 358 | 359 | while (typeof nextFiberNode !== 'undefined') { 360 | if (nextFiberNode.sibling) { 361 | return nextFiberNode.sibling; 362 | } 363 | 364 | nextFiberNode = nextFiberNode.return; 365 | } 366 | 367 | return null; 368 | }; 369 | 370 | // Use requestIdleCallback to query whether there is currently a unit task 371 | // and determine whether the DOM needs to be updated. 372 | const workLoop: IdleRequestCallback = (deadline) => { 373 | while (nextUnitOfWork && deadline.timeRemaining() > 1) { 374 | nextUnitOfWork = performUnitOfWork(nextUnitOfWork); 375 | } 376 | 377 | if (!nextUnitOfWork && wipRoot) { 378 | commitRoot(); 379 | } 380 | 381 | window.requestIdleCallback(workLoop); 382 | }; 383 | 384 | // Initial or reset. 385 | const render = (element: VirtualElement, container: Element) => { 386 | currentRoot = null; 387 | wipRoot = { 388 | type: 'div', 389 | dom: container, 390 | props: { 391 | children: [{ ...element }], 392 | }, 393 | alternate: currentRoot, 394 | }; 395 | nextUnitOfWork = wipRoot; 396 | deletions = []; 397 | }; 398 | 399 | abstract class Component { 400 | props: Record; 401 | abstract state: unknown; 402 | abstract setState: (value: unknown) => void; 403 | abstract render: () => VirtualElement; 404 | 405 | constructor(props: Record) { 406 | this.props = props; 407 | } 408 | 409 | // Identify Component. 410 | static REACT_COMPONENT = true; 411 | } 412 | 413 | // Associate the hook with the fiber node. 414 | function useState(initState: S): [S, (value: S) => void] { 415 | const fiberNode: FiberNode = wipFiber; 416 | const hook: { 417 | state: S; 418 | queue: S[]; 419 | } = fiberNode?.alternate?.hooks 420 | ? fiberNode.alternate.hooks[hookIndex] 421 | : { 422 | state: initState, 423 | queue: [], 424 | }; 425 | 426 | while (hook.queue.length) { 427 | let newState = hook.queue.shift(); 428 | if (isPlainObject(hook.state) && isPlainObject(newState)) { 429 | newState = { ...hook.state, ...newState }; 430 | } 431 | if (isDef(newState)) { 432 | hook.state = newState; 433 | } 434 | } 435 | 436 | if (typeof fiberNode.hooks === 'undefined') { 437 | fiberNode.hooks = []; 438 | } 439 | 440 | fiberNode.hooks.push(hook); 441 | hookIndex += 1; 442 | 443 | const setState = (value: S) => { 444 | hook.queue.push(value); 445 | if (currentRoot) { 446 | wipRoot = { 447 | type: currentRoot.type, 448 | dom: currentRoot.dom, 449 | props: currentRoot.props, 450 | alternate: currentRoot, 451 | }; 452 | nextUnitOfWork = wipRoot; 453 | deletions = []; 454 | currentRoot = null; 455 | } 456 | }; 457 | 458 | return [hook.state, setState]; 459 | } 460 | 461 | // Start the engine! 462 | void (function main() { 463 | window.requestIdleCallback(workLoop); 464 | })(); 465 | 466 | export default { 467 | createElement, 468 | render, 469 | useState, 470 | Component, 471 | Fragment, 472 | }; 473 | -------------------------------------------------------------------------------- /pnpm-lock.yaml: -------------------------------------------------------------------------------- 1 | lockfileVersion: '9.0' 2 | 3 | settings: 4 | autoInstallPeers: true 5 | excludeLinksFromLockfile: false 6 | 7 | importers: 8 | 9 | .: 10 | devDependencies: 11 | '@vitejs/plugin-react': 12 | specifier: ^4.2.1 13 | version: 4.2.1(vite@5.2.11) 14 | typescript: 15 | specifier: ^5.4.5 16 | version: 5.4.5 17 | vite: 18 | specifier: ^5.2.11 19 | version: 5.2.11 20 | 21 | packages: 22 | 23 | '@ampproject/remapping@2.3.0': 24 | resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} 25 | engines: {node: '>=6.0.0'} 26 | 27 | '@babel/code-frame@7.24.2': 28 | resolution: {integrity: sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ==} 29 | engines: {node: '>=6.9.0'} 30 | 31 | '@babel/compat-data@7.24.4': 32 | resolution: {integrity: sha512-vg8Gih2MLK+kOkHJp4gBEIkyaIi00jgWot2D9QOmmfLC8jINSOzmCLta6Bvz/JSBCqnegV0L80jhxkol5GWNfQ==} 33 | engines: {node: '>=6.9.0'} 34 | 35 | '@babel/core@7.24.5': 36 | resolution: {integrity: sha512-tVQRucExLQ02Boi4vdPp49svNGcfL2GhdTCT9aldhXgCJVAI21EtRfBettiuLUwce/7r6bFdgs6JFkcdTiFttA==} 37 | engines: {node: '>=6.9.0'} 38 | 39 | '@babel/generator@7.24.5': 40 | resolution: {integrity: sha512-x32i4hEXvr+iI0NEoEfDKzlemF8AmtOP8CcrRaEcpzysWuoEb1KknpcvMsHKPONoKZiDuItklgWhB18xEhr9PA==} 41 | engines: {node: '>=6.9.0'} 42 | 43 | '@babel/helper-compilation-targets@7.23.6': 44 | resolution: {integrity: sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ==} 45 | engines: {node: '>=6.9.0'} 46 | 47 | '@babel/helper-environment-visitor@7.22.20': 48 | resolution: {integrity: sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==} 49 | engines: {node: '>=6.9.0'} 50 | 51 | '@babel/helper-function-name@7.23.0': 52 | resolution: {integrity: sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==} 53 | engines: {node: '>=6.9.0'} 54 | 55 | '@babel/helper-hoist-variables@7.22.5': 56 | resolution: {integrity: sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==} 57 | engines: {node: '>=6.9.0'} 58 | 59 | '@babel/helper-module-imports@7.24.3': 60 | resolution: {integrity: sha512-viKb0F9f2s0BCS22QSF308z/+1YWKV/76mwt61NBzS5izMzDPwdq1pTrzf+Li3npBWX9KdQbkeCt1jSAM7lZqg==} 61 | engines: {node: '>=6.9.0'} 62 | 63 | '@babel/helper-module-transforms@7.24.5': 64 | resolution: {integrity: sha512-9GxeY8c2d2mdQUP1Dye0ks3VDyIMS98kt/llQ2nUId8IsWqTF0l1LkSX0/uP7l7MCDrzXS009Hyhe2gzTiGW8A==} 65 | engines: {node: '>=6.9.0'} 66 | peerDependencies: 67 | '@babel/core': ^7.0.0 68 | 69 | '@babel/helper-plugin-utils@7.24.5': 70 | resolution: {integrity: sha512-xjNLDopRzW2o6ba0gKbkZq5YWEBaK3PCyTOY1K2P/O07LGMhMqlMXPxwN4S5/RhWuCobT8z0jrlKGlYmeR1OhQ==} 71 | engines: {node: '>=6.9.0'} 72 | 73 | '@babel/helper-simple-access@7.24.5': 74 | resolution: {integrity: sha512-uH3Hmf5q5n7n8mz7arjUlDOCbttY/DW4DYhE6FUsjKJ/oYC1kQQUvwEQWxRwUpX9qQKRXeqLwWxrqilMrf32sQ==} 75 | engines: {node: '>=6.9.0'} 76 | 77 | '@babel/helper-split-export-declaration@7.24.5': 78 | resolution: {integrity: sha512-5CHncttXohrHk8GWOFCcCl4oRD9fKosWlIRgWm4ql9VYioKm52Mk2xsmoohvm7f3JoiLSM5ZgJuRaf5QZZYd3Q==} 79 | engines: {node: '>=6.9.0'} 80 | 81 | '@babel/helper-string-parser@7.24.1': 82 | resolution: {integrity: sha512-2ofRCjnnA9y+wk8b9IAREroeUP02KHp431N2mhKniy2yKIDKpbrHv9eXwm8cBeWQYcJmzv5qKCu65P47eCF7CQ==} 83 | engines: {node: '>=6.9.0'} 84 | 85 | '@babel/helper-validator-identifier@7.24.5': 86 | resolution: {integrity: sha512-3q93SSKX2TWCG30M2G2kwaKeTYgEUp5Snjuj8qm729SObL6nbtUldAi37qbxkD5gg3xnBio+f9nqpSepGZMvxA==} 87 | engines: {node: '>=6.9.0'} 88 | 89 | '@babel/helper-validator-option@7.23.5': 90 | resolution: {integrity: sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==} 91 | engines: {node: '>=6.9.0'} 92 | 93 | '@babel/helpers@7.24.5': 94 | resolution: {integrity: sha512-CiQmBMMpMQHwM5m01YnrM6imUG1ebgYJ+fAIW4FZe6m4qHTPaRHti+R8cggAwkdz4oXhtO4/K9JWlh+8hIfR2Q==} 95 | engines: {node: '>=6.9.0'} 96 | 97 | '@babel/highlight@7.24.5': 98 | resolution: {integrity: sha512-8lLmua6AVh/8SLJRRVD6V8p73Hir9w5mJrhE+IPpILG31KKlI9iz5zmBYKcWPS59qSfgP9RaSBQSHHE81WKuEw==} 99 | engines: {node: '>=6.9.0'} 100 | 101 | '@babel/parser@7.24.5': 102 | resolution: {integrity: sha512-EOv5IK8arwh3LI47dz1b0tKUb/1uhHAnHJOrjgtQMIpu1uXd9mlFrJg9IUgGUgZ41Ch0K8REPTYpO7B76b4vJg==} 103 | engines: {node: '>=6.0.0'} 104 | hasBin: true 105 | 106 | '@babel/plugin-transform-react-jsx-self@7.24.5': 107 | resolution: {integrity: sha512-RtCJoUO2oYrYwFPtR1/jkoBEcFuI1ae9a9IMxeyAVa3a1Ap4AnxmyIKG2b2FaJKqkidw/0cxRbWN+HOs6ZWd1w==} 108 | engines: {node: '>=6.9.0'} 109 | peerDependencies: 110 | '@babel/core': ^7.0.0-0 111 | 112 | '@babel/plugin-transform-react-jsx-source@7.24.1': 113 | resolution: {integrity: sha512-1v202n7aUq4uXAieRTKcwPzNyphlCuqHHDcdSNc+vdhoTEZcFMh+L5yZuCmGaIO7bs1nJUNfHB89TZyoL48xNA==} 114 | engines: {node: '>=6.9.0'} 115 | peerDependencies: 116 | '@babel/core': ^7.0.0-0 117 | 118 | '@babel/template@7.24.0': 119 | resolution: {integrity: sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA==} 120 | engines: {node: '>=6.9.0'} 121 | 122 | '@babel/traverse@7.24.5': 123 | resolution: {integrity: sha512-7aaBLeDQ4zYcUFDUD41lJc1fG8+5IU9DaNSJAgal866FGvmD5EbWQgnEC6kO1gGLsX0esNkfnJSndbTXA3r7UA==} 124 | engines: {node: '>=6.9.0'} 125 | 126 | '@babel/types@7.24.5': 127 | resolution: {integrity: sha512-6mQNsaLeXTw0nxYUYu+NSa4Hx4BlF1x1x8/PMFbiR+GBSr+2DkECc69b8hgy2frEodNcvPffeH8YfWd3LI6jhQ==} 128 | engines: {node: '>=6.9.0'} 129 | 130 | '@esbuild/aix-ppc64@0.20.2': 131 | resolution: {integrity: sha512-D+EBOJHXdNZcLJRBkhENNG8Wji2kgc9AZ9KiPr1JuZjsNtyHzrsfLRrY0tk2H2aoFu6RANO1y1iPPUCDYWkb5g==} 132 | engines: {node: '>=12'} 133 | cpu: [ppc64] 134 | os: [aix] 135 | 136 | '@esbuild/android-arm64@0.20.2': 137 | resolution: {integrity: sha512-mRzjLacRtl/tWU0SvD8lUEwb61yP9cqQo6noDZP/O8VkwafSYwZ4yWy24kan8jE/IMERpYncRt2dw438LP3Xmg==} 138 | engines: {node: '>=12'} 139 | cpu: [arm64] 140 | os: [android] 141 | 142 | '@esbuild/android-arm@0.20.2': 143 | resolution: {integrity: sha512-t98Ra6pw2VaDhqNWO2Oph2LXbz/EJcnLmKLGBJwEwXX/JAN83Fym1rU8l0JUWK6HkIbWONCSSatf4sf2NBRx/w==} 144 | engines: {node: '>=12'} 145 | cpu: [arm] 146 | os: [android] 147 | 148 | '@esbuild/android-x64@0.20.2': 149 | resolution: {integrity: sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg==} 150 | engines: {node: '>=12'} 151 | cpu: [x64] 152 | os: [android] 153 | 154 | '@esbuild/darwin-arm64@0.20.2': 155 | resolution: {integrity: sha512-4J6IRT+10J3aJH3l1yzEg9y3wkTDgDk7TSDFX+wKFiWjqWp/iCfLIYzGyasx9l0SAFPT1HwSCR+0w/h1ES/MjA==} 156 | engines: {node: '>=12'} 157 | cpu: [arm64] 158 | os: [darwin] 159 | 160 | '@esbuild/darwin-x64@0.20.2': 161 | resolution: {integrity: sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA==} 162 | engines: {node: '>=12'} 163 | cpu: [x64] 164 | os: [darwin] 165 | 166 | '@esbuild/freebsd-arm64@0.20.2': 167 | resolution: {integrity: sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw==} 168 | engines: {node: '>=12'} 169 | cpu: [arm64] 170 | os: [freebsd] 171 | 172 | '@esbuild/freebsd-x64@0.20.2': 173 | resolution: {integrity: sha512-d+DipyvHRuqEeM5zDivKV1KuXn9WeRX6vqSqIDgwIfPQtwMP4jaDsQsDncjTDDsExT4lR/91OLjRo8bmC1e+Cw==} 174 | engines: {node: '>=12'} 175 | cpu: [x64] 176 | os: [freebsd] 177 | 178 | '@esbuild/linux-arm64@0.20.2': 179 | resolution: {integrity: sha512-9pb6rBjGvTFNira2FLIWqDk/uaf42sSyLE8j1rnUpuzsODBq7FvpwHYZxQ/It/8b+QOS1RYfqgGFNLRI+qlq2A==} 180 | engines: {node: '>=12'} 181 | cpu: [arm64] 182 | os: [linux] 183 | 184 | '@esbuild/linux-arm@0.20.2': 185 | resolution: {integrity: sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg==} 186 | engines: {node: '>=12'} 187 | cpu: [arm] 188 | os: [linux] 189 | 190 | '@esbuild/linux-ia32@0.20.2': 191 | resolution: {integrity: sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig==} 192 | engines: {node: '>=12'} 193 | cpu: [ia32] 194 | os: [linux] 195 | 196 | '@esbuild/linux-loong64@0.20.2': 197 | resolution: {integrity: sha512-PR7sp6R/UC4CFVomVINKJ80pMFlfDfMQMYynX7t1tNTeivQ6XdX5r2XovMmha/VjR1YN/HgHWsVcTRIMkymrgQ==} 198 | engines: {node: '>=12'} 199 | cpu: [loong64] 200 | os: [linux] 201 | 202 | '@esbuild/linux-mips64el@0.20.2': 203 | resolution: {integrity: sha512-4BlTqeutE/KnOiTG5Y6Sb/Hw6hsBOZapOVF6njAESHInhlQAghVVZL1ZpIctBOoTFbQyGW+LsVYZ8lSSB3wkjA==} 204 | engines: {node: '>=12'} 205 | cpu: [mips64el] 206 | os: [linux] 207 | 208 | '@esbuild/linux-ppc64@0.20.2': 209 | resolution: {integrity: sha512-rD3KsaDprDcfajSKdn25ooz5J5/fWBylaaXkuotBDGnMnDP1Uv5DLAN/45qfnf3JDYyJv/ytGHQaziHUdyzaAg==} 210 | engines: {node: '>=12'} 211 | cpu: [ppc64] 212 | os: [linux] 213 | 214 | '@esbuild/linux-riscv64@0.20.2': 215 | resolution: {integrity: sha512-snwmBKacKmwTMmhLlz/3aH1Q9T8v45bKYGE3j26TsaOVtjIag4wLfWSiZykXzXuE1kbCE+zJRmwp+ZbIHinnVg==} 216 | engines: {node: '>=12'} 217 | cpu: [riscv64] 218 | os: [linux] 219 | 220 | '@esbuild/linux-s390x@0.20.2': 221 | resolution: {integrity: sha512-wcWISOobRWNm3cezm5HOZcYz1sKoHLd8VL1dl309DiixxVFoFe/o8HnwuIwn6sXre88Nwj+VwZUvJf4AFxkyrQ==} 222 | engines: {node: '>=12'} 223 | cpu: [s390x] 224 | os: [linux] 225 | 226 | '@esbuild/linux-x64@0.20.2': 227 | resolution: {integrity: sha512-1MdwI6OOTsfQfek8sLwgyjOXAu+wKhLEoaOLTjbijk6E2WONYpH9ZU2mNtR+lZ2B4uwr+usqGuVfFT9tMtGvGw==} 228 | engines: {node: '>=12'} 229 | cpu: [x64] 230 | os: [linux] 231 | 232 | '@esbuild/netbsd-x64@0.20.2': 233 | resolution: {integrity: sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ==} 234 | engines: {node: '>=12'} 235 | cpu: [x64] 236 | os: [netbsd] 237 | 238 | '@esbuild/openbsd-x64@0.20.2': 239 | resolution: {integrity: sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ==} 240 | engines: {node: '>=12'} 241 | cpu: [x64] 242 | os: [openbsd] 243 | 244 | '@esbuild/sunos-x64@0.20.2': 245 | resolution: {integrity: sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w==} 246 | engines: {node: '>=12'} 247 | cpu: [x64] 248 | os: [sunos] 249 | 250 | '@esbuild/win32-arm64@0.20.2': 251 | resolution: {integrity: sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ==} 252 | engines: {node: '>=12'} 253 | cpu: [arm64] 254 | os: [win32] 255 | 256 | '@esbuild/win32-ia32@0.20.2': 257 | resolution: {integrity: sha512-HfLOfn9YWmkSKRQqovpnITazdtquEW8/SoHW7pWpuEeguaZI4QnCRW6b+oZTztdBnZOS2hqJ6im/D5cPzBTTlQ==} 258 | engines: {node: '>=12'} 259 | cpu: [ia32] 260 | os: [win32] 261 | 262 | '@esbuild/win32-x64@0.20.2': 263 | resolution: {integrity: sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ==} 264 | engines: {node: '>=12'} 265 | cpu: [x64] 266 | os: [win32] 267 | 268 | '@jridgewell/gen-mapping@0.3.5': 269 | resolution: {integrity: sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==} 270 | engines: {node: '>=6.0.0'} 271 | 272 | '@jridgewell/resolve-uri@3.1.2': 273 | resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} 274 | engines: {node: '>=6.0.0'} 275 | 276 | '@jridgewell/set-array@1.2.1': 277 | resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==} 278 | engines: {node: '>=6.0.0'} 279 | 280 | '@jridgewell/sourcemap-codec@1.4.15': 281 | resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} 282 | 283 | '@jridgewell/trace-mapping@0.3.25': 284 | resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} 285 | 286 | '@rollup/rollup-android-arm-eabi@4.17.2': 287 | resolution: {integrity: sha512-NM0jFxY8bB8QLkoKxIQeObCaDlJKewVlIEkuyYKm5An1tdVZ966w2+MPQ2l8LBZLjR+SgyV+nRkTIunzOYBMLQ==} 288 | cpu: [arm] 289 | os: [android] 290 | 291 | '@rollup/rollup-android-arm64@4.17.2': 292 | resolution: {integrity: sha512-yeX/Usk7daNIVwkq2uGoq2BYJKZY1JfyLTaHO/jaiSwi/lsf8fTFoQW/n6IdAsx5tx+iotu2zCJwz8MxI6D/Bw==} 293 | cpu: [arm64] 294 | os: [android] 295 | 296 | '@rollup/rollup-darwin-arm64@4.17.2': 297 | resolution: {integrity: sha512-kcMLpE6uCwls023+kknm71ug7MZOrtXo+y5p/tsg6jltpDtgQY1Eq5sGfHcQfb+lfuKwhBmEURDga9N0ol4YPw==} 298 | cpu: [arm64] 299 | os: [darwin] 300 | 301 | '@rollup/rollup-darwin-x64@4.17.2': 302 | resolution: {integrity: sha512-AtKwD0VEx0zWkL0ZjixEkp5tbNLzX+FCqGG1SvOu993HnSz4qDI6S4kGzubrEJAljpVkhRSlg5bzpV//E6ysTQ==} 303 | cpu: [x64] 304 | os: [darwin] 305 | 306 | '@rollup/rollup-linux-arm-gnueabihf@4.17.2': 307 | resolution: {integrity: sha512-3reX2fUHqN7sffBNqmEyMQVj/CKhIHZd4y631duy0hZqI8Qoqf6lTtmAKvJFYa6bhU95B1D0WgzHkmTg33In0A==} 308 | cpu: [arm] 309 | os: [linux] 310 | 311 | '@rollup/rollup-linux-arm-musleabihf@4.17.2': 312 | resolution: {integrity: sha512-uSqpsp91mheRgw96xtyAGP9FW5ChctTFEoXP0r5FAzj/3ZRv3Uxjtc7taRQSaQM/q85KEKjKsZuiZM3GyUivRg==} 313 | cpu: [arm] 314 | os: [linux] 315 | 316 | '@rollup/rollup-linux-arm64-gnu@4.17.2': 317 | resolution: {integrity: sha512-EMMPHkiCRtE8Wdk3Qhtciq6BndLtstqZIroHiiGzB3C5LDJmIZcSzVtLRbwuXuUft1Cnv+9fxuDtDxz3k3EW2A==} 318 | cpu: [arm64] 319 | os: [linux] 320 | 321 | '@rollup/rollup-linux-arm64-musl@4.17.2': 322 | resolution: {integrity: sha512-NMPylUUZ1i0z/xJUIx6VUhISZDRT+uTWpBcjdv0/zkp7b/bQDF+NfnfdzuTiB1G6HTodgoFa93hp0O1xl+/UbA==} 323 | cpu: [arm64] 324 | os: [linux] 325 | 326 | '@rollup/rollup-linux-powerpc64le-gnu@4.17.2': 327 | resolution: {integrity: sha512-T19My13y8uYXPw/L/k0JYaX1fJKFT/PWdXiHr8mTbXWxjVF1t+8Xl31DgBBvEKclw+1b00Chg0hxE2O7bTG7GQ==} 328 | cpu: [ppc64] 329 | os: [linux] 330 | 331 | '@rollup/rollup-linux-riscv64-gnu@4.17.2': 332 | resolution: {integrity: sha512-BOaNfthf3X3fOWAB+IJ9kxTgPmMqPPH5f5k2DcCsRrBIbWnaJCgX2ll77dV1TdSy9SaXTR5iDXRL8n7AnoP5cg==} 333 | cpu: [riscv64] 334 | os: [linux] 335 | 336 | '@rollup/rollup-linux-s390x-gnu@4.17.2': 337 | resolution: {integrity: sha512-W0UP/x7bnn3xN2eYMql2T/+wpASLE5SjObXILTMPUBDB/Fg/FxC+gX4nvCfPBCbNhz51C+HcqQp2qQ4u25ok6g==} 338 | cpu: [s390x] 339 | os: [linux] 340 | 341 | '@rollup/rollup-linux-x64-gnu@4.17.2': 342 | resolution: {integrity: sha512-Hy7pLwByUOuyaFC6mAr7m+oMC+V7qyifzs/nW2OJfC8H4hbCzOX07Ov0VFk/zP3kBsELWNFi7rJtgbKYsav9QQ==} 343 | cpu: [x64] 344 | os: [linux] 345 | 346 | '@rollup/rollup-linux-x64-musl@4.17.2': 347 | resolution: {integrity: sha512-h1+yTWeYbRdAyJ/jMiVw0l6fOOm/0D1vNLui9iPuqgRGnXA0u21gAqOyB5iHjlM9MMfNOm9RHCQ7zLIzT0x11Q==} 348 | cpu: [x64] 349 | os: [linux] 350 | 351 | '@rollup/rollup-win32-arm64-msvc@4.17.2': 352 | resolution: {integrity: sha512-tmdtXMfKAjy5+IQsVtDiCfqbynAQE/TQRpWdVataHmhMb9DCoJxp9vLcCBjEQWMiUYxO1QprH/HbY9ragCEFLA==} 353 | cpu: [arm64] 354 | os: [win32] 355 | 356 | '@rollup/rollup-win32-ia32-msvc@4.17.2': 357 | resolution: {integrity: sha512-7II/QCSTAHuE5vdZaQEwJq2ZACkBpQDOmQsE6D6XUbnBHW8IAhm4eTufL6msLJorzrHDFv3CF8oCA/hSIRuZeQ==} 358 | cpu: [ia32] 359 | os: [win32] 360 | 361 | '@rollup/rollup-win32-x64-msvc@4.17.2': 362 | resolution: {integrity: sha512-TGGO7v7qOq4CYmSBVEYpI1Y5xDuCEnbVC5Vth8mOsW0gDSzxNrVERPc790IGHsrT2dQSimgMr9Ub3Y1Jci5/8w==} 363 | cpu: [x64] 364 | os: [win32] 365 | 366 | '@types/babel__core@7.20.5': 367 | resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} 368 | 369 | '@types/babel__generator@7.6.8': 370 | resolution: {integrity: sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==} 371 | 372 | '@types/babel__template@7.4.4': 373 | resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==} 374 | 375 | '@types/babel__traverse@7.20.5': 376 | resolution: {integrity: sha512-WXCyOcRtH37HAUkpXhUduaxdm82b4GSlyTqajXviN4EfiuPgNYR109xMCKvpl6zPIpua0DGlMEDCq+g8EdoheQ==} 377 | 378 | '@types/estree@1.0.5': 379 | resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==} 380 | 381 | '@vitejs/plugin-react@4.2.1': 382 | resolution: {integrity: sha512-oojO9IDc4nCUUi8qIR11KoQm0XFFLIwsRBwHRR4d/88IWghn1y6ckz/bJ8GHDCsYEJee8mDzqtJxh15/cisJNQ==} 383 | engines: {node: ^14.18.0 || >=16.0.0} 384 | peerDependencies: 385 | vite: ^4.2.0 || ^5.0.0 386 | 387 | ansi-styles@3.2.1: 388 | resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} 389 | engines: {node: '>=4'} 390 | 391 | browserslist@4.23.0: 392 | resolution: {integrity: sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==} 393 | engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} 394 | hasBin: true 395 | 396 | caniuse-lite@1.0.30001617: 397 | resolution: {integrity: sha512-mLyjzNI9I+Pix8zwcrpxEbGlfqOkF9kM3ptzmKNw5tizSyYwMe+nGLTqMK9cO+0E+Bh6TsBxNAaHWEM8xwSsmA==} 398 | 399 | chalk@2.4.2: 400 | resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} 401 | engines: {node: '>=4'} 402 | 403 | color-convert@1.9.3: 404 | resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} 405 | 406 | color-name@1.1.3: 407 | resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} 408 | 409 | convert-source-map@2.0.0: 410 | resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} 411 | 412 | debug@4.3.4: 413 | resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} 414 | engines: {node: '>=6.0'} 415 | peerDependencies: 416 | supports-color: '*' 417 | peerDependenciesMeta: 418 | supports-color: 419 | optional: true 420 | 421 | electron-to-chromium@1.4.760: 422 | resolution: {integrity: sha512-xF6AWMVM/QGQseTPgXjUewfNjCW2fgUcV/z5cSG0r+SiYcgtvcmRAL3oH/MSZwHBBD+fyKTXdQ4qGENJMSedEQ==} 423 | 424 | esbuild@0.20.2: 425 | resolution: {integrity: sha512-WdOOppmUNU+IbZ0PaDiTst80zjnrOkyJNHoKupIcVyU8Lvla3Ugx94VzkQ32Ijqd7UhHJy75gNWDMUekcrSJ6g==} 426 | engines: {node: '>=12'} 427 | hasBin: true 428 | 429 | escalade@3.1.2: 430 | resolution: {integrity: sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==} 431 | engines: {node: '>=6'} 432 | 433 | escape-string-regexp@1.0.5: 434 | resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} 435 | engines: {node: '>=0.8.0'} 436 | 437 | fsevents@2.3.3: 438 | resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} 439 | engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} 440 | os: [darwin] 441 | 442 | gensync@1.0.0-beta.2: 443 | resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} 444 | engines: {node: '>=6.9.0'} 445 | 446 | globals@11.12.0: 447 | resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} 448 | engines: {node: '>=4'} 449 | 450 | has-flag@3.0.0: 451 | resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} 452 | engines: {node: '>=4'} 453 | 454 | js-tokens@4.0.0: 455 | resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} 456 | 457 | jsesc@2.5.2: 458 | resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==} 459 | engines: {node: '>=4'} 460 | hasBin: true 461 | 462 | json5@2.2.3: 463 | resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} 464 | engines: {node: '>=6'} 465 | hasBin: true 466 | 467 | lru-cache@5.1.1: 468 | resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} 469 | 470 | ms@2.1.2: 471 | resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} 472 | 473 | nanoid@3.3.7: 474 | resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==} 475 | engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} 476 | hasBin: true 477 | 478 | node-releases@2.0.14: 479 | resolution: {integrity: sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==} 480 | 481 | picocolors@1.0.0: 482 | resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} 483 | 484 | postcss@8.4.38: 485 | resolution: {integrity: sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==} 486 | engines: {node: ^10 || ^12 || >=14} 487 | 488 | react-refresh@0.14.2: 489 | resolution: {integrity: sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==} 490 | engines: {node: '>=0.10.0'} 491 | 492 | rollup@4.17.2: 493 | resolution: {integrity: sha512-/9ClTJPByC0U4zNLowV1tMBe8yMEAxewtR3cUNX5BoEpGH3dQEWpJLr6CLp0fPdYRF/fzVOgvDb1zXuakwF5kQ==} 494 | engines: {node: '>=18.0.0', npm: '>=8.0.0'} 495 | hasBin: true 496 | 497 | semver@6.3.1: 498 | resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} 499 | hasBin: true 500 | 501 | source-map-js@1.2.0: 502 | resolution: {integrity: sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==} 503 | engines: {node: '>=0.10.0'} 504 | 505 | supports-color@5.5.0: 506 | resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} 507 | engines: {node: '>=4'} 508 | 509 | to-fast-properties@2.0.0: 510 | resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==} 511 | engines: {node: '>=4'} 512 | 513 | typescript@5.4.5: 514 | resolution: {integrity: sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==} 515 | engines: {node: '>=14.17'} 516 | hasBin: true 517 | 518 | update-browserslist-db@1.0.15: 519 | resolution: {integrity: sha512-K9HWH62x3/EalU1U6sjSZiylm9C8tgq2mSvshZpqc7QE69RaA2qjhkW2HlNA0tFpEbtyFz7HTqbSdN4MSwUodA==} 520 | hasBin: true 521 | peerDependencies: 522 | browserslist: '>= 4.21.0' 523 | 524 | vite@5.2.11: 525 | resolution: {integrity: sha512-HndV31LWW05i1BLPMUCE1B9E9GFbOu1MbenhS58FuK6owSO5qHm7GiCotrNY1YE5rMeQSFBGmT5ZaLEjFizgiQ==} 526 | engines: {node: ^18.0.0 || >=20.0.0} 527 | hasBin: true 528 | peerDependencies: 529 | '@types/node': ^18.0.0 || >=20.0.0 530 | less: '*' 531 | lightningcss: ^1.21.0 532 | sass: '*' 533 | stylus: '*' 534 | sugarss: '*' 535 | terser: ^5.4.0 536 | peerDependenciesMeta: 537 | '@types/node': 538 | optional: true 539 | less: 540 | optional: true 541 | lightningcss: 542 | optional: true 543 | sass: 544 | optional: true 545 | stylus: 546 | optional: true 547 | sugarss: 548 | optional: true 549 | terser: 550 | optional: true 551 | 552 | yallist@3.1.1: 553 | resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} 554 | 555 | snapshots: 556 | 557 | '@ampproject/remapping@2.3.0': 558 | dependencies: 559 | '@jridgewell/gen-mapping': 0.3.5 560 | '@jridgewell/trace-mapping': 0.3.25 561 | 562 | '@babel/code-frame@7.24.2': 563 | dependencies: 564 | '@babel/highlight': 7.24.5 565 | picocolors: 1.0.0 566 | 567 | '@babel/compat-data@7.24.4': {} 568 | 569 | '@babel/core@7.24.5': 570 | dependencies: 571 | '@ampproject/remapping': 2.3.0 572 | '@babel/code-frame': 7.24.2 573 | '@babel/generator': 7.24.5 574 | '@babel/helper-compilation-targets': 7.23.6 575 | '@babel/helper-module-transforms': 7.24.5(@babel/core@7.24.5) 576 | '@babel/helpers': 7.24.5 577 | '@babel/parser': 7.24.5 578 | '@babel/template': 7.24.0 579 | '@babel/traverse': 7.24.5 580 | '@babel/types': 7.24.5 581 | convert-source-map: 2.0.0 582 | debug: 4.3.4 583 | gensync: 1.0.0-beta.2 584 | json5: 2.2.3 585 | semver: 6.3.1 586 | transitivePeerDependencies: 587 | - supports-color 588 | 589 | '@babel/generator@7.24.5': 590 | dependencies: 591 | '@babel/types': 7.24.5 592 | '@jridgewell/gen-mapping': 0.3.5 593 | '@jridgewell/trace-mapping': 0.3.25 594 | jsesc: 2.5.2 595 | 596 | '@babel/helper-compilation-targets@7.23.6': 597 | dependencies: 598 | '@babel/compat-data': 7.24.4 599 | '@babel/helper-validator-option': 7.23.5 600 | browserslist: 4.23.0 601 | lru-cache: 5.1.1 602 | semver: 6.3.1 603 | 604 | '@babel/helper-environment-visitor@7.22.20': {} 605 | 606 | '@babel/helper-function-name@7.23.0': 607 | dependencies: 608 | '@babel/template': 7.24.0 609 | '@babel/types': 7.24.5 610 | 611 | '@babel/helper-hoist-variables@7.22.5': 612 | dependencies: 613 | '@babel/types': 7.24.5 614 | 615 | '@babel/helper-module-imports@7.24.3': 616 | dependencies: 617 | '@babel/types': 7.24.5 618 | 619 | '@babel/helper-module-transforms@7.24.5(@babel/core@7.24.5)': 620 | dependencies: 621 | '@babel/core': 7.24.5 622 | '@babel/helper-environment-visitor': 7.22.20 623 | '@babel/helper-module-imports': 7.24.3 624 | '@babel/helper-simple-access': 7.24.5 625 | '@babel/helper-split-export-declaration': 7.24.5 626 | '@babel/helper-validator-identifier': 7.24.5 627 | 628 | '@babel/helper-plugin-utils@7.24.5': {} 629 | 630 | '@babel/helper-simple-access@7.24.5': 631 | dependencies: 632 | '@babel/types': 7.24.5 633 | 634 | '@babel/helper-split-export-declaration@7.24.5': 635 | dependencies: 636 | '@babel/types': 7.24.5 637 | 638 | '@babel/helper-string-parser@7.24.1': {} 639 | 640 | '@babel/helper-validator-identifier@7.24.5': {} 641 | 642 | '@babel/helper-validator-option@7.23.5': {} 643 | 644 | '@babel/helpers@7.24.5': 645 | dependencies: 646 | '@babel/template': 7.24.0 647 | '@babel/traverse': 7.24.5 648 | '@babel/types': 7.24.5 649 | transitivePeerDependencies: 650 | - supports-color 651 | 652 | '@babel/highlight@7.24.5': 653 | dependencies: 654 | '@babel/helper-validator-identifier': 7.24.5 655 | chalk: 2.4.2 656 | js-tokens: 4.0.0 657 | picocolors: 1.0.0 658 | 659 | '@babel/parser@7.24.5': 660 | dependencies: 661 | '@babel/types': 7.24.5 662 | 663 | '@babel/plugin-transform-react-jsx-self@7.24.5(@babel/core@7.24.5)': 664 | dependencies: 665 | '@babel/core': 7.24.5 666 | '@babel/helper-plugin-utils': 7.24.5 667 | 668 | '@babel/plugin-transform-react-jsx-source@7.24.1(@babel/core@7.24.5)': 669 | dependencies: 670 | '@babel/core': 7.24.5 671 | '@babel/helper-plugin-utils': 7.24.5 672 | 673 | '@babel/template@7.24.0': 674 | dependencies: 675 | '@babel/code-frame': 7.24.2 676 | '@babel/parser': 7.24.5 677 | '@babel/types': 7.24.5 678 | 679 | '@babel/traverse@7.24.5': 680 | dependencies: 681 | '@babel/code-frame': 7.24.2 682 | '@babel/generator': 7.24.5 683 | '@babel/helper-environment-visitor': 7.22.20 684 | '@babel/helper-function-name': 7.23.0 685 | '@babel/helper-hoist-variables': 7.22.5 686 | '@babel/helper-split-export-declaration': 7.24.5 687 | '@babel/parser': 7.24.5 688 | '@babel/types': 7.24.5 689 | debug: 4.3.4 690 | globals: 11.12.0 691 | transitivePeerDependencies: 692 | - supports-color 693 | 694 | '@babel/types@7.24.5': 695 | dependencies: 696 | '@babel/helper-string-parser': 7.24.1 697 | '@babel/helper-validator-identifier': 7.24.5 698 | to-fast-properties: 2.0.0 699 | 700 | '@esbuild/aix-ppc64@0.20.2': 701 | optional: true 702 | 703 | '@esbuild/android-arm64@0.20.2': 704 | optional: true 705 | 706 | '@esbuild/android-arm@0.20.2': 707 | optional: true 708 | 709 | '@esbuild/android-x64@0.20.2': 710 | optional: true 711 | 712 | '@esbuild/darwin-arm64@0.20.2': 713 | optional: true 714 | 715 | '@esbuild/darwin-x64@0.20.2': 716 | optional: true 717 | 718 | '@esbuild/freebsd-arm64@0.20.2': 719 | optional: true 720 | 721 | '@esbuild/freebsd-x64@0.20.2': 722 | optional: true 723 | 724 | '@esbuild/linux-arm64@0.20.2': 725 | optional: true 726 | 727 | '@esbuild/linux-arm@0.20.2': 728 | optional: true 729 | 730 | '@esbuild/linux-ia32@0.20.2': 731 | optional: true 732 | 733 | '@esbuild/linux-loong64@0.20.2': 734 | optional: true 735 | 736 | '@esbuild/linux-mips64el@0.20.2': 737 | optional: true 738 | 739 | '@esbuild/linux-ppc64@0.20.2': 740 | optional: true 741 | 742 | '@esbuild/linux-riscv64@0.20.2': 743 | optional: true 744 | 745 | '@esbuild/linux-s390x@0.20.2': 746 | optional: true 747 | 748 | '@esbuild/linux-x64@0.20.2': 749 | optional: true 750 | 751 | '@esbuild/netbsd-x64@0.20.2': 752 | optional: true 753 | 754 | '@esbuild/openbsd-x64@0.20.2': 755 | optional: true 756 | 757 | '@esbuild/sunos-x64@0.20.2': 758 | optional: true 759 | 760 | '@esbuild/win32-arm64@0.20.2': 761 | optional: true 762 | 763 | '@esbuild/win32-ia32@0.20.2': 764 | optional: true 765 | 766 | '@esbuild/win32-x64@0.20.2': 767 | optional: true 768 | 769 | '@jridgewell/gen-mapping@0.3.5': 770 | dependencies: 771 | '@jridgewell/set-array': 1.2.1 772 | '@jridgewell/sourcemap-codec': 1.4.15 773 | '@jridgewell/trace-mapping': 0.3.25 774 | 775 | '@jridgewell/resolve-uri@3.1.2': {} 776 | 777 | '@jridgewell/set-array@1.2.1': {} 778 | 779 | '@jridgewell/sourcemap-codec@1.4.15': {} 780 | 781 | '@jridgewell/trace-mapping@0.3.25': 782 | dependencies: 783 | '@jridgewell/resolve-uri': 3.1.2 784 | '@jridgewell/sourcemap-codec': 1.4.15 785 | 786 | '@rollup/rollup-android-arm-eabi@4.17.2': 787 | optional: true 788 | 789 | '@rollup/rollup-android-arm64@4.17.2': 790 | optional: true 791 | 792 | '@rollup/rollup-darwin-arm64@4.17.2': 793 | optional: true 794 | 795 | '@rollup/rollup-darwin-x64@4.17.2': 796 | optional: true 797 | 798 | '@rollup/rollup-linux-arm-gnueabihf@4.17.2': 799 | optional: true 800 | 801 | '@rollup/rollup-linux-arm-musleabihf@4.17.2': 802 | optional: true 803 | 804 | '@rollup/rollup-linux-arm64-gnu@4.17.2': 805 | optional: true 806 | 807 | '@rollup/rollup-linux-arm64-musl@4.17.2': 808 | optional: true 809 | 810 | '@rollup/rollup-linux-powerpc64le-gnu@4.17.2': 811 | optional: true 812 | 813 | '@rollup/rollup-linux-riscv64-gnu@4.17.2': 814 | optional: true 815 | 816 | '@rollup/rollup-linux-s390x-gnu@4.17.2': 817 | optional: true 818 | 819 | '@rollup/rollup-linux-x64-gnu@4.17.2': 820 | optional: true 821 | 822 | '@rollup/rollup-linux-x64-musl@4.17.2': 823 | optional: true 824 | 825 | '@rollup/rollup-win32-arm64-msvc@4.17.2': 826 | optional: true 827 | 828 | '@rollup/rollup-win32-ia32-msvc@4.17.2': 829 | optional: true 830 | 831 | '@rollup/rollup-win32-x64-msvc@4.17.2': 832 | optional: true 833 | 834 | '@types/babel__core@7.20.5': 835 | dependencies: 836 | '@babel/parser': 7.24.5 837 | '@babel/types': 7.24.5 838 | '@types/babel__generator': 7.6.8 839 | '@types/babel__template': 7.4.4 840 | '@types/babel__traverse': 7.20.5 841 | 842 | '@types/babel__generator@7.6.8': 843 | dependencies: 844 | '@babel/types': 7.24.5 845 | 846 | '@types/babel__template@7.4.4': 847 | dependencies: 848 | '@babel/parser': 7.24.5 849 | '@babel/types': 7.24.5 850 | 851 | '@types/babel__traverse@7.20.5': 852 | dependencies: 853 | '@babel/types': 7.24.5 854 | 855 | '@types/estree@1.0.5': {} 856 | 857 | '@vitejs/plugin-react@4.2.1(vite@5.2.11)': 858 | dependencies: 859 | '@babel/core': 7.24.5 860 | '@babel/plugin-transform-react-jsx-self': 7.24.5(@babel/core@7.24.5) 861 | '@babel/plugin-transform-react-jsx-source': 7.24.1(@babel/core@7.24.5) 862 | '@types/babel__core': 7.20.5 863 | react-refresh: 0.14.2 864 | vite: 5.2.11 865 | transitivePeerDependencies: 866 | - supports-color 867 | 868 | ansi-styles@3.2.1: 869 | dependencies: 870 | color-convert: 1.9.3 871 | 872 | browserslist@4.23.0: 873 | dependencies: 874 | caniuse-lite: 1.0.30001617 875 | electron-to-chromium: 1.4.760 876 | node-releases: 2.0.14 877 | update-browserslist-db: 1.0.15(browserslist@4.23.0) 878 | 879 | caniuse-lite@1.0.30001617: {} 880 | 881 | chalk@2.4.2: 882 | dependencies: 883 | ansi-styles: 3.2.1 884 | escape-string-regexp: 1.0.5 885 | supports-color: 5.5.0 886 | 887 | color-convert@1.9.3: 888 | dependencies: 889 | color-name: 1.1.3 890 | 891 | color-name@1.1.3: {} 892 | 893 | convert-source-map@2.0.0: {} 894 | 895 | debug@4.3.4: 896 | dependencies: 897 | ms: 2.1.2 898 | 899 | electron-to-chromium@1.4.760: {} 900 | 901 | esbuild@0.20.2: 902 | optionalDependencies: 903 | '@esbuild/aix-ppc64': 0.20.2 904 | '@esbuild/android-arm': 0.20.2 905 | '@esbuild/android-arm64': 0.20.2 906 | '@esbuild/android-x64': 0.20.2 907 | '@esbuild/darwin-arm64': 0.20.2 908 | '@esbuild/darwin-x64': 0.20.2 909 | '@esbuild/freebsd-arm64': 0.20.2 910 | '@esbuild/freebsd-x64': 0.20.2 911 | '@esbuild/linux-arm': 0.20.2 912 | '@esbuild/linux-arm64': 0.20.2 913 | '@esbuild/linux-ia32': 0.20.2 914 | '@esbuild/linux-loong64': 0.20.2 915 | '@esbuild/linux-mips64el': 0.20.2 916 | '@esbuild/linux-ppc64': 0.20.2 917 | '@esbuild/linux-riscv64': 0.20.2 918 | '@esbuild/linux-s390x': 0.20.2 919 | '@esbuild/linux-x64': 0.20.2 920 | '@esbuild/netbsd-x64': 0.20.2 921 | '@esbuild/openbsd-x64': 0.20.2 922 | '@esbuild/sunos-x64': 0.20.2 923 | '@esbuild/win32-arm64': 0.20.2 924 | '@esbuild/win32-ia32': 0.20.2 925 | '@esbuild/win32-x64': 0.20.2 926 | 927 | escalade@3.1.2: {} 928 | 929 | escape-string-regexp@1.0.5: {} 930 | 931 | fsevents@2.3.3: 932 | optional: true 933 | 934 | gensync@1.0.0-beta.2: {} 935 | 936 | globals@11.12.0: {} 937 | 938 | has-flag@3.0.0: {} 939 | 940 | js-tokens@4.0.0: {} 941 | 942 | jsesc@2.5.2: {} 943 | 944 | json5@2.2.3: {} 945 | 946 | lru-cache@5.1.1: 947 | dependencies: 948 | yallist: 3.1.1 949 | 950 | ms@2.1.2: {} 951 | 952 | nanoid@3.3.7: {} 953 | 954 | node-releases@2.0.14: {} 955 | 956 | picocolors@1.0.0: {} 957 | 958 | postcss@8.4.38: 959 | dependencies: 960 | nanoid: 3.3.7 961 | picocolors: 1.0.0 962 | source-map-js: 1.2.0 963 | 964 | react-refresh@0.14.2: {} 965 | 966 | rollup@4.17.2: 967 | dependencies: 968 | '@types/estree': 1.0.5 969 | optionalDependencies: 970 | '@rollup/rollup-android-arm-eabi': 4.17.2 971 | '@rollup/rollup-android-arm64': 4.17.2 972 | '@rollup/rollup-darwin-arm64': 4.17.2 973 | '@rollup/rollup-darwin-x64': 4.17.2 974 | '@rollup/rollup-linux-arm-gnueabihf': 4.17.2 975 | '@rollup/rollup-linux-arm-musleabihf': 4.17.2 976 | '@rollup/rollup-linux-arm64-gnu': 4.17.2 977 | '@rollup/rollup-linux-arm64-musl': 4.17.2 978 | '@rollup/rollup-linux-powerpc64le-gnu': 4.17.2 979 | '@rollup/rollup-linux-riscv64-gnu': 4.17.2 980 | '@rollup/rollup-linux-s390x-gnu': 4.17.2 981 | '@rollup/rollup-linux-x64-gnu': 4.17.2 982 | '@rollup/rollup-linux-x64-musl': 4.17.2 983 | '@rollup/rollup-win32-arm64-msvc': 4.17.2 984 | '@rollup/rollup-win32-ia32-msvc': 4.17.2 985 | '@rollup/rollup-win32-x64-msvc': 4.17.2 986 | fsevents: 2.3.3 987 | 988 | semver@6.3.1: {} 989 | 990 | source-map-js@1.2.0: {} 991 | 992 | supports-color@5.5.0: 993 | dependencies: 994 | has-flag: 3.0.0 995 | 996 | to-fast-properties@2.0.0: {} 997 | 998 | typescript@5.4.5: {} 999 | 1000 | update-browserslist-db@1.0.15(browserslist@4.23.0): 1001 | dependencies: 1002 | browserslist: 4.23.0 1003 | escalade: 3.1.2 1004 | picocolors: 1.0.0 1005 | 1006 | vite@5.2.11: 1007 | dependencies: 1008 | esbuild: 0.20.2 1009 | postcss: 8.4.38 1010 | rollup: 4.17.2 1011 | optionalDependencies: 1012 | fsevents: 2.3.3 1013 | 1014 | yallist@3.1.1: {} 1015 | --------------------------------------------------------------------------------