diff --git a/.github/workflows/_common_jobs.yml b/.github/workflows/_common_jobs.yml index 24faf9e..3d65fbb 100644 --- a/.github/workflows/_common_jobs.yml +++ b/.github/workflows/_common_jobs.yml @@ -2,47 +2,35 @@ name: Launch CI jobs for a package or app on: workflow_call: inputs: - working-directory: + workspace: required: true type: string jobs: lint: - defaults: - run: - working-directory: ${{ inputs.working-directory }} runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - run: npm i - - run: npm run lint + - run: npm run lint -w ${{ inputs.workspace }} typecheck: - defaults: - run: - working-directory: ${{ inputs.working-directory }} runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - run: npm i - - run: npx tsc + - run: npm run typecheck -w ${{ inputs.workspace }} test: - defaults: - run: - working-directory: ${{ inputs.working-directory }} runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - run: npm i - - run: npm run coverage + - run: npm run coverage -w ${{ inputs.workspace }} buildcheck: - defaults: - run: - working-directory: ${{ inputs.working-directory }} runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - run: npm i - - run: npm run build + - run: npm run build -w ${{ inputs.workspace }} \ No newline at end of file diff --git a/.github/workflows/check_dependencies.yml b/.github/workflows/check_dependencies.yml new file mode 100644 index 0000000..d22f518 --- /dev/null +++ b/.github/workflows/check_dependencies.yml @@ -0,0 +1,16 @@ +name: check dependencies +on: + push: + paths: + - '**/package.json' + - '.github/workflows/check_dependencies.yml' +jobs: + check-dependencies: + runs-on: ubuntu-latest + steps: + - name: Checkout the repository + uses: actions/checkout@v4 + - name: Install dependencies + run: npm i + - name: Check if the dependencies are free of any conflict and match "overrides" in the root package.json + run: npm ls diff --git a/.github/workflows/ci_apps_hightable_demo.yml b/.github/workflows/ci_apps_hightable_demo.yml index be088c4..a045831 100644 --- a/.github/workflows/ci_apps_hightable_demo.yml +++ b/.github/workflows/ci_apps_hightable_demo.yml @@ -5,9 +5,10 @@ on: - 'apps/hightable-demo/**' - '.github/workflows/_common_jobs.yml' - '.github/workflows/ci_apps_hightable_demo.yml' - - 'shared.eslint.config.js' + - 'eslint.config.js' + - 'package.json' jobs: ci: uses: ./.github/workflows/_common_jobs.yml with: - working-directory: apps/hightable-demo + workspace: hightable-demo diff --git a/.github/workflows/ci_apps_hyparquet_demo.yml b/.github/workflows/ci_apps_hyparquet_demo.yml index e969854..f6a55e7 100644 --- a/.github/workflows/ci_apps_hyparquet_demo.yml +++ b/.github/workflows/ci_apps_hyparquet_demo.yml @@ -2,12 +2,24 @@ name: apps/hyparquet-demo on: push: paths: + - 'packages/components/**' - 'apps/hyparquet-demo/**' - '.github/workflows/_common_jobs.yml' - '.github/workflows/ci_apps_hyparquet_demo.yml' - - 'shared.eslint.config.js' + - 'eslint.config.js' + - 'package.json' jobs: + build-components: + runs-on: ubuntu-latest + steps: + - name: Checkout the repository + uses: actions/checkout@v4 + - name: Install dependencies + run: npm i + - name: Build components package + run: npm run build -w @hyparam/components ci: + needs: build-components uses: ./.github/workflows/_common_jobs.yml with: - working-directory: apps/hyparquet-demo + workspace: hyparquet-demo diff --git a/.github/workflows/ci_packages_cli.yml b/.github/workflows/ci_packages_cli.yml index 73116bf..0f3658d 100644 --- a/.github/workflows/ci_packages_cli.yml +++ b/.github/workflows/ci_packages_cli.yml @@ -2,12 +2,24 @@ name: apps/cli on: push: paths: + - 'packages/components/**' - 'packages/cli/**' - '.github/workflows/_common_jobs.yml' - '.github/workflows/ci_packages_cli.yml' - - 'shared.eslint.config.js' + - 'eslint.config.js' + - 'package.json' jobs: + build-components: + runs-on: ubuntu-latest + steps: + - name: Checkout the repository + uses: actions/checkout@v4 + - name: Install dependencies + run: npm i + - name: Build components package + run: npm run build -w @hyparam/components ci: + needs: build-components uses: ./.github/workflows/_common_jobs.yml with: - working-directory: packages/cli + workspace: hyperparam diff --git a/.github/workflows/ci_packages_components.yml b/.github/workflows/ci_packages_components.yml index 4e08156..efdb8f0 100644 --- a/.github/workflows/ci_packages_components.yml +++ b/.github/workflows/ci_packages_components.yml @@ -5,9 +5,10 @@ on: - 'packages/components/**' - '.github/workflows/_common_jobs.yml' - '.github/workflows/ci_packages_components.yml' - - 'shared.eslint.config.js' + - 'eslint.config.js' + - 'package.json' jobs: ci: uses: ./.github/workflows/_common_jobs.yml with: - working-directory: packages/components + workspace: '@hyparam/components' diff --git a/.github/workflows/ci_root.yml b/.github/workflows/ci_root.yml new file mode 100644 index 0000000..57260de --- /dev/null +++ b/.github/workflows/ci_root.yml @@ -0,0 +1,22 @@ +name: root +on: + push: + paths: + - '*' + - 'test/**' + - '.github/workflows/ci_root.yml' + - 'eslint.config.js' +jobs: + lint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - run: npm i + - run: npm run lint + + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - run: npm i + - run: npm run test diff --git a/.github/workflows/deploy_pages.yml b/.github/workflows/deploy_pages.yml index 6c96967..8b3f9e2 100644 --- a/.github/workflows/deploy_pages.yml +++ b/.github/workflows/deploy_pages.yml @@ -4,9 +4,11 @@ on: push: branches: ["master"] paths: + - "packages/components/**" - "apps/hyparquet-demo/**" - "apps/hightable-demo/**" - ".github/workflows/deploy_pages.yml" + - 'package.json' workflow_dispatch: jobs: @@ -16,16 +18,12 @@ jobs: steps: - name: Checkout the repository uses: actions/checkout@v4 - - name: Build hyparquet demo + - name: Build components package and demo apps run: | npm i - npm run build - working-directory: ./apps/hyparquet-demo - - name: Build hightable demo - run: | - npm i - npm run build - working-directory: ./apps/hightable-demo + npm run build -w @hyparam/components + npm run build -w hyparquet-demo + npm run build -w hightable-demo - name: Move the build outputs to a folder run: | mkdir -p build_outputs_folder/apps diff --git a/README.md b/README.md index cda2b1d..b08a271 100644 --- a/README.md +++ b/README.md @@ -3,15 +3,81 @@ This is a monorepo for the Hyperparam project. It contains the following packages, published to npm: + - [`@hyparam/components`](./packages/components): a library of React components and utilities for building Hyperparam UIs. - [`hyperparam`](./packages/cli): a cli tool for viewing arbitrarily large datasets in the browser. It also contains the following applications: + - [`hightable-demo`](./apps/hightable-demo): an example project showing how to use [hightable](https://github.com/hyparam/hightable). - [`hyparquet-demo`](./apps/hyparquet-demo): an example project showing how to use [hyparquet](https://github.com/hyparam/hyparquet). +## Use + +Install all the workspaces with: + +```bash +npm install +``` + +Lint all the workspaces: + +```bash +npm run lint -ws +``` + +Test all the workspaces: + +```bash +npm test -ws +``` + +Compute the coverage for all the workspaces: + +```bash +npm run coverage -ws +``` + +Build all the workspaces (they are built in order, so the dependencies are built first - it's defined manually by the order of the workspaces in the `package.json`): + +```bash +npm run build -ws +``` + +Run an app: + +- `hightable-demo`: + +```bash +npm run dev -w hightable-demo +``` + +- `hyparquet-demo`: + +```bash +npm run dev -w hyparquet-demo +``` + +- `hyperparam`: + +```bash +npm run dev -w hyperparam +``` + +- `components`: + +```bash +npm run dev -w @hyparam/components +``` + ## Development -The dependencies between the packages and applications of this monorepo are pinned, and the packages are published to npm. It means that the changes in a dependency are not automatically reflected in the dependent package or application. +The monorepo is managed with [npm workspaces](https://docs.npmjs.com/cli/v10/using-npm/workspaces). Some workspaces are dependencies of others. Currently: + +- `@hyparam/components` is a dependency of `hyperparam` and `hyparquet-demo`. + +It means that if you make a change to `@hyparam/components`, you need to rebuild it before developing `hyperparam` or `hyparquet-demo`. + +Also, if you increment the version of `@hyparam/components`, you need to update the version of `@hyparam/components` in the `package.json` of `hyperparam` and `hyparquet-demo`, as we use exact versions in the `package.json` of the workspaces. Note that we don't have to increment the version after every change, only when we want to publish a new version with a significant batch of changes. -To make the development easier, you can locally replace the npm dependencies with the local packages, 1. creating a local package with `npm pack`, 2. replacing the pinned versions (eg `"@hyparam/components": "0.1.3",`) with a relative path to the local package (`"@hyparam/components": "file:../../packages/components/hyparam-components-0.1.3.tgz",`). +The root package.json contains a special field, `overrides`, which sets the shared dependencies versions we want to have in all the workspaces. The "check_dependencies" GitHub action checks that the dependencies are the same in all the workspaces (`npm ls` would fail if dependency version mismatch). diff --git a/apps/hightable-demo/eslint.config.js b/apps/hightable-demo/eslint.config.js index de86df4..bb25791 100644 --- a/apps/hightable-demo/eslint.config.js +++ b/apps/hightable-demo/eslint.config.js @@ -4,8 +4,7 @@ import reactHooks from 'eslint-plugin-react-hooks' import reactRefresh from 'eslint-plugin-react-refresh' import globals from 'globals' import tseslint from 'typescript-eslint' -import sharedEslintRules from '../../shared.eslint.config.js' -const { sharedJsRules, sharedTsRules } = sharedEslintRules +import { sharedJsRules, sharedTsRules } from '../../eslint.config.js' export default tseslint.config( { ignores: ['dist', 'coverage/'] }, diff --git a/apps/hightable-demo/package.json b/apps/hightable-demo/package.json index 54a853e..bc20a03 100644 --- a/apps/hightable-demo/package.json +++ b/apps/hightable-demo/package.json @@ -10,27 +10,12 @@ "build": "tsc -b && vite build", "lint": "eslint .", "preview": "vite preview", - "test": "vitest run --dir test" + "test": "vitest run --dir test", + "typecheck": "tsc" }, "dependencies": { "hightable": "0.7.2", "react": "18.3.1", "react-dom": "18.3.1" - }, - "devDependencies": { - "@eslint/js": "9.16.0", - "@types/react": "18.3.12", - "@types/react-dom": "18.3.1", - "@vitejs/plugin-react": "4.3.4", - "@vitest/coverage-v8": "2.1.8", - "eslint": "9.16.0", - "eslint-plugin-react": "7.37.2", - "eslint-plugin-react-hooks": "5.1.0", - "eslint-plugin-react-refresh": "0.4.16", - "globals": "15.13.0", - "typescript": "5.7.2", - "typescript-eslint": "8.18.0", - "vite": "6.0.3", - "vitest": "2.1.8" } } diff --git a/apps/hightable-demo/test/package.test.js b/apps/hightable-demo/test/package.test.js index 6fcfb02..6107400 100644 --- a/apps/hightable-demo/test/package.test.js +++ b/apps/hightable-demo/test/package.test.js @@ -14,7 +14,7 @@ describe('package.json', () => { it('should have precise dependency versions', () => { const { dependencies, devDependencies } = packageJson const allDependencies = { ...dependencies, ...devDependencies } - Object.entries(allDependencies).filter(([name]) => !name.startsWith('@hyparam/')).forEach(([, version]) => { + Object.values(allDependencies).forEach(version => { expect(version).toMatch(/^\d+\.\d+\.\d+$/) }) }) diff --git a/apps/hyparquet-demo/eslint.config.js b/apps/hyparquet-demo/eslint.config.js index d54e90d..86920e4 100644 --- a/apps/hyparquet-demo/eslint.config.js +++ b/apps/hyparquet-demo/eslint.config.js @@ -4,8 +4,7 @@ import reactHooks from 'eslint-plugin-react-hooks' import reactRefresh from 'eslint-plugin-react-refresh' import globals from 'globals' import tseslint from 'typescript-eslint' -import sharedEslintRules from '../../shared.eslint.config.js' -const { sharedJsRules, sharedTsRules } = sharedEslintRules +import { sharedJsRules, sharedTsRules } from '../../eslint.config.js' export default tseslint.config( { ignores: ['dist', 'coverage'] }, diff --git a/apps/hyparquet-demo/package.json b/apps/hyparquet-demo/package.json index 8a73122..39d2e9b 100644 --- a/apps/hyparquet-demo/package.json +++ b/apps/hyparquet-demo/package.json @@ -10,7 +10,8 @@ "build": "tsc -b && vite build", "lint": "eslint .", "preview": "vite preview", - "test": "vitest run --dir test" + "test": "vitest run --dir test", + "typecheck": "tsc" }, "dependencies": { "@hyparam/components": "0.1.11", @@ -19,21 +20,5 @@ "hyparquet-compressors": "1.0.0", "react": "18.3.1", "react-dom": "18.3.1" - }, - "devDependencies": { - "@eslint/js": "9.16.0", - "@types/react": "18.3.12", - "@types/react-dom": "18.3.1", - "@vitejs/plugin-react": "4.3.4", - "@vitest/coverage-v8": "2.1.8", - "eslint": "9.16.0", - "eslint-plugin-react": "7.37.2", - "eslint-plugin-react-hooks": "5.1.0", - "eslint-plugin-react-refresh": "0.4.16", - "globals": "15.13.0", - "typescript": "5.7.2", - "typescript-eslint": "8.18.0", - "vite": "6.0.3", - "vitest": "2.1.8" } } diff --git a/apps/hyparquet-demo/test/package.test.js b/apps/hyparquet-demo/test/package.test.js index 64804ba..a4fd020 100644 --- a/apps/hyparquet-demo/test/package.test.js +++ b/apps/hyparquet-demo/test/package.test.js @@ -14,7 +14,7 @@ describe('package.json', () => { it('should have precise dependency versions', () => { const { dependencies, devDependencies } = packageJson const allDependencies = { ...dependencies, ...devDependencies } - Object.entries(allDependencies).filter(([name]) => !name.startsWith('@hyparam/')).forEach(([, version]) => { + Object.values(allDependencies).forEach(version => { expect(version).toMatch(/^\d+\.\d+\.\d+$/) }) }) diff --git a/shared.eslint.config.js b/eslint.config.js similarity index 66% rename from shared.eslint.config.js rename to eslint.config.js index c284cb5..3ac5dac 100644 --- a/shared.eslint.config.js +++ b/eslint.config.js @@ -1,4 +1,8 @@ -const sharedJsRules = { +import javascript from '@eslint/js' +import globals from 'globals' + +/** @type {import('eslint').Linter.Config.RulesRecord} */ +export const sharedJsRules = { 'arrow-spacing': 'error', camelcase: 'off', 'comma-spacing': 'error', @@ -36,9 +40,26 @@ const sharedJsRules = { 'space-infix-ops': 'error', } -const sharedTsRules = { +/** @type {import('eslint').Linter.Config.RulesRecord} */ +export const sharedTsRules = { '@typescript-eslint/restrict-template-expressions': 'off', '@typescript-eslint/no-unused-vars': 'warn', } -module.exports = { sharedJsRules, sharedTsRules } + +/** @type {import('eslint').Linter.Config[]} */ +export default [ + { + languageOptions: { + globals: { + ...globals.browser, + ...globals.node, + }, + }, + rules: { + ...javascript.configs.recommended.rules, + ...sharedJsRules, + }, + files: ['*.js', 'test/**/*.js'], + }, +] diff --git a/package.json b/package.json new file mode 100644 index 0000000..fcb582d --- /dev/null +++ b/package.json @@ -0,0 +1,43 @@ +{ + "name": "@hyparam/monorepo", + "version": "0.0.0", + "private": true, + "license": "MIT", + "type": "module", + "workspaces": [ + "packages/components", + "packages/cli", + "apps/hightable-demo", + "apps/hyparquet-demo" + ], + "scripts": { + "lint": "eslint .", + "test": "vitest run --dir test" + }, + "overrides": { + "highlight.js": "11.10.0", + "hightable": "0.7.2", + "hyparquet": "1.6.4", + "hyparquet-compressors": "1.0.0", + "react": "18.3.1", + "react-dom": "18.3.1" + }, + "devDependencies": { + "@testing-library/react": "16.1.0", + "@types/node": "22.10.2", + "@types/react": "19.0.1", + "@types/react-dom": "19.0.2", + "@vitejs/plugin-react": "4.3.4", + "@vitest/coverage-v8": "2.1.8", + "eslint": "9.16.0", + "eslint-plugin-react": "7.37.2", + "eslint-plugin-react-hooks": "5.1.0", + "eslint-plugin-react-refresh": "0.4.16", + "globals": "15.13.0", + "jsdom": "25.0.1", + "typescript": "5.7.2", + "typescript-eslint": "8.18.0", + "vite": "6.0.3", + "vitest": "2.1.8" + } +} diff --git a/packages/cli/eslint.config.js b/packages/cli/eslint.config.js index 6014d3e..ab92bf9 100644 --- a/packages/cli/eslint.config.js +++ b/packages/cli/eslint.config.js @@ -1,8 +1,7 @@ import javascript from '@eslint/js' import globals from 'globals' import typescript from 'typescript-eslint' -import sharedEslintRules from '../../shared.eslint.config.js' -const { sharedJsRules } = sharedEslintRules +import { sharedJsRules } from '../../eslint.config.js' export default [ { diff --git a/packages/cli/package.json b/packages/cli/package.json index 16a3dc3..b9c7de9 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -18,11 +18,13 @@ "scripts": { "build": "rollup -c", "coverage": "vitest run --coverage --coverage.include=src", + "dev": "npm run serve", "lint": "eslint", "prepublishOnly": "npm run build", "serve": "node src/cli.js", "url": "node src/cli.js https://hyperparam.blob.core.windows.net/hyperparam/starcoderdata-js-00000-of-00065.parquet", - "test": "vitest run --dir test" + "test": "vitest run --dir test", + "typecheck": "tsc" }, "dependencies": { "highlight.js": "11.10.0", @@ -36,20 +38,8 @@ "@rollup/plugin-replace": "6.0.1", "@rollup/plugin-terser": "0.4.4", "@rollup/plugin-typescript": "12.1.1", - "@testing-library/react": "16.1.0", - "@types/node": "22.10.2", - "@types/react": "18.3.12", - "@types/react-dom": "18.3.1", - "@vitejs/plugin-react": "4.3.4", - "@vitest/coverage-v8": "2.1.8", - "eslint": "9.16.0", - "globals": "15.13.0", - "jsdom": "25.0.1", "rollup": "4.28.1", "rollup-plugin-postcss": "4.0.2", - "tslib": "2.8.1", - "typescript": "5.7.2", - "typescript-eslint": "8.18.0", - "vitest": "2.1.8" + "tslib": "2.8.1" } } diff --git a/packages/cli/public/build/app.min.js b/packages/cli/public/build/app.min.js index 6eba39a..72445a7 100644 --- a/packages/cli/public/build/app.min.js +++ b/packages/cli/public/build/app.min.js @@ -1,4 +1,4 @@ -function e(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e}var l,n,t={exports:{}},a={};function d(){if(l)return a;l=1;var e=Symbol.for("react.element"),n=Symbol.for("react.portal"),t=Symbol.for("react.fragment"),d=Symbol.for("react.strict_mode"),r=Symbol.for("react.profiler"),c=Symbol.for("react.provider"),i=Symbol.for("react.context"),o=Symbol.for("react.forward_ref"),s=Symbol.for("react.suspense"),V=Symbol.for("react.memo"),u=Symbol.for("react.lazy"),Z=Symbol.iterator;var U={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},m=Object.assign,W={};function N(e,l,n){this.props=e,this.context=l,this.refs=W,this.updater=n||U}function R(){}function p(e,l,n){this.props=e,this.context=l,this.refs=W,this.updater=n||U}N.prototype.isReactComponent={},N.prototype.setState=function(e,l){if("object"!=typeof e&&"function"!=typeof e&&null!=e)throw Error("setState(...): takes an object of state variables to update or a function which returns an object of state variables.");this.updater.enqueueSetState(this,e,l,"setState")},N.prototype.forceUpdate=function(e){this.updater.enqueueForceUpdate(this,e,"forceUpdate")},R.prototype=N.prototype;var b=p.prototype=new R;b.constructor=p,m(b,N.prototype),b.isPureReactComponent=!0;var T=Array.isArray,F=Object.prototype.hasOwnProperty,M={current:null},h={key:!0,ref:!0,__self:!0,__source:!0};function S(l,n,t){var a,d={},r=null,c=null;if(null!=n)for(a in void 0!==n.ref&&(c=n.ref),void 0!==n.key&&(r=""+n.key),n)F.call(n,a)&&!h.hasOwnProperty(a)&&(d[a]=n[a]);var i=arguments.length-2;if(1===i)d.children=t;else if(1>>1,d=e[t];if(!(0>>1;ta(i,n))oa(s,i)?(e[t]=s,e[o]=n,t=o):(e[t]=i,e[c]=n,t=c);else{if(!(oa(s,n)))break e;e[t]=s,e[o]=n,t=o}}}return l}function a(e,l){var n=e.sortIndex-l.sortIndex;return 0!==n?n:e.id-l.id}if("object"==typeof performance&&"function"==typeof performance.now){var d=performance;e.unstable_now=function(){return d.now()}}else{var r=Date,c=r.now();e.unstable_now=function(){return r.now()-c}}var i=[],o=[],s=1,V=null,u=3,Z=!1,U=!1,m=!1,W="function"==typeof setTimeout?setTimeout:null,N="function"==typeof clearTimeout?clearTimeout:null,R="undefined"!=typeof setImmediate?setImmediate:null;function p(e){for(var a=n(o);null!==a;){if(null===a.callback)t(o);else{if(!(a.startTime<=e))break;t(o),a.sortIndex=a.expirationTime,l(i,a)}a=n(o)}}function b(e){if(m=!1,p(e),!U)if(null!==n(i))U=!0,f(T);else{var l=n(o);null!==l&&w(b,l.startTime-e)}}function T(l,a){U=!1,m&&(m=!1,N(S),S=-1),Z=!0;var d=u;try{for(p(a),V=n(i);null!==V&&(!(V.expirationTime>a)||l&&!Q());){var r=V.callback;if("function"==typeof r){V.callback=null,u=V.priorityLevel;var c=r(V.expirationTime<=a);a=e.unstable_now(),"function"==typeof c?V.callback=c:V===n(i)&&t(i),p(a)}else t(i);V=n(i)}if(null!==V)var s=!0;else{var W=n(o);null!==W&&w(b,W.startTime-a),s=!1}return s}finally{V=null,u=d,Z=!1}}"undefined"!=typeof navigator&&void 0!==navigator.scheduling&&void 0!==navigator.scheduling.isInputPending&&navigator.scheduling.isInputPending.bind(navigator.scheduling);var F,M=!1,h=null,S=-1,k=5,y=-1;function Q(){return!(e.unstable_now()-ye||125r?(t.sortIndex=d,l(o,t),null===n(i)&&t===n(o)&&(m?(N(S),S=-1):m=!0,w(b,d-r))):(t.sortIndex=c,l(i,t),U||Z||(U=!0,f(T))),t},e.unstable_shouldYield=Q,e.unstable_wrapCallback=function(e){var l=u;return function(){var n=u;u=l;try{return e.apply(this,arguments)}finally{u=n}}}}(R)),R)),N.exports} +function e(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e}var n,t,r={exports:{}},o={};function l(){if(n)return o;n=1;var e=Symbol.for("react.element"),t=Symbol.for("react.portal"),r=Symbol.for("react.fragment"),l=Symbol.for("react.strict_mode"),i=Symbol.for("react.profiler"),a=Symbol.for("react.provider"),u=Symbol.for("react.context"),s=Symbol.for("react.forward_ref"),c=Symbol.for("react.suspense"),f=Symbol.for("react.memo"),d=Symbol.for("react.lazy"),p=Symbol.iterator;var h={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},g=Object.assign,m={};function A(e,n,t){this.props=e,this.context=n,this.refs=m,this.updater=t||h}function w(){}function v(e,n,t){this.props=e,this.context=n,this.refs=m,this.updater=t||h}A.prototype.isReactComponent={},A.prototype.setState=function(e,n){if("object"!=typeof e&&"function"!=typeof e&&null!=e)throw Error("setState(...): takes an object of state variables to update or a function which returns an object of state variables.");this.updater.enqueueSetState(this,e,n,"setState")},A.prototype.forceUpdate=function(e){this.updater.enqueueForceUpdate(this,e,"forceUpdate")},w.prototype=A.prototype;var y=v.prototype=new w;y.constructor=v,g(y,A.prototype),y.isPureReactComponent=!0;var b=Array.isArray,E=Object.prototype.hasOwnProperty,I={current:null},S={key:!0,ref:!0,__self:!0,__source:!0};function C(n,t,r){var o,l={},i=null,a=null;if(null!=t)for(o in void 0!==t.ref&&(a=t.ref),void 0!==t.key&&(i=""+t.key),t)E.call(t,o)&&!S.hasOwnProperty(o)&&(l[o]=t[o]);var u=arguments.length-2;if(1===u)l.children=r;else if(1>>1,l=e[r];if(!(0>>1;ro(u,t))so(c,u)?(e[r]=c,e[s]=t,r=s):(e[r]=u,e[a]=t,r=a);else{if(!(so(c,t)))break e;e[r]=c,e[s]=t,r=s}}}return n}function o(e,n){var t=e.sortIndex-n.sortIndex;return 0!==t?t:e.id-n.id}if("object"==typeof performance&&"function"==typeof performance.now){var l=performance;e.unstable_now=function(){return l.now()}}else{var i=Date,a=i.now();e.unstable_now=function(){return i.now()-a}}var u=[],s=[],c=1,f=null,d=3,p=!1,h=!1,g=!1,m="function"==typeof setTimeout?setTimeout:null,A="function"==typeof clearTimeout?clearTimeout:null,w="undefined"!=typeof setImmediate?setImmediate:null;function v(e){for(var o=t(s);null!==o;){if(null===o.callback)r(s);else{if(!(o.startTime<=e))break;r(s),o.sortIndex=o.expirationTime,n(u,o)}o=t(s)}}function y(e){if(g=!1,v(e),!h)if(null!==t(u))h=!0,P(b);else{var n=t(s);null!==n&&R(y,n.startTime-e)}}function b(n,o){h=!1,g&&(g=!1,A(C),C=-1),p=!0;var l=d;try{for(v(o),f=t(u);null!==f&&(!(f.expirationTime>o)||n&&!B());){var i=f.callback;if("function"==typeof i){f.callback=null,d=f.priorityLevel;var a=i(f.expirationTime<=o);o=e.unstable_now(),"function"==typeof a?f.callback=a:f===t(u)&&r(u),v(o)}else r(u);f=t(u)}if(null!==f)var c=!0;else{var m=t(s);null!==m&&R(y,m.startTime-o),c=!1}return c}finally{f=null,d=l,p=!1}}"undefined"!=typeof navigator&&void 0!==navigator.scheduling&&void 0!==navigator.scheduling.isInputPending&&navigator.scheduling.isInputPending.bind(navigator.scheduling);var E,I=!1,S=null,C=-1,k=5,x=-1;function B(){return!(e.unstable_now()-xe||125i?(r.sortIndex=l,n(s,r),null===t(u)&&r===t(s)&&(g?(A(C),C=-1):g=!0,R(y,l-i))):(r.sortIndex=a,n(u,r),h||p||(h=!0,P(b))),r},e.unstable_shouldYield=B,e.unstable_wrapCallback=function(e){var n=d;return function(){var t=d;d=n;try{return e.apply(this,arguments)}finally{d=t}}}}(w)),w)),A.exports} /** * @license React * react-dom.production.min.js @@ -7,5 +7,5 @@ function e(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,"de * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. - */function b(){if(o)return W;o=1;var e=r(),l=p();function n(e){for(var l="https://reactjs.org/docs/error-decoder.html?invariant="+e,n=1;n