From b7d4aa606b8f366715ec4f44ef60e90ac978cf00 Mon Sep 17 00:00:00 2001 From: AMAGI / Jun Yuri Date: Tue, 11 Jun 2024 12:21:09 -0700 Subject: [PATCH] feat: accept overflow size in `overflow` property (#58) * feat: accept overflow size * docs: specify overflow size in docs * feat: accept object * chore: remove unnecessary eslint rule * chore: improve type declarations * fix: hit test not working correctly * refactor: use object as the internal representation for overflow * feat: consider overflow values in hit test * test: add tests * ci: add CI script for test * refactor: make isRectInViewport testable * fix: add missing overflow size * fix: all elements are being rendered in the initial state --- .github/workflows/ci.yml | 26 + package-lock.json | 1038 +++++++++++++-------- package.json | 3 +- packages/docs/src/dom/AuthorSection.tsx | 2 +- packages/docs/src/dom/ExamplesSection.tsx | 10 +- packages/docs/src/dom/IntroSection.tsx | 4 +- packages/docs/src/dom/LogoSection.tsx | 2 +- packages/docs/src/dom/UsageSection.tsx | 2 +- packages/react-vfx/.eslintrc | 33 +- packages/react-vfx/package.json | 7 +- packages/react-vfx/src/constants.ts | 4 +- packages/react-vfx/src/types.ts | 33 +- packages/react-vfx/src/vfx-player.test.ts | 245 +++++ packages/react-vfx/src/vfx-player.ts | 149 ++- packages/react-vfx/tsconfig.json | 2 +- 15 files changed, 1083 insertions(+), 477 deletions(-) create mode 100644 .github/workflows/ci.yml create mode 100644 packages/react-vfx/src/vfx-player.test.ts diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..b617376 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,26 @@ +name: Test + +on: + push: + branches: + - main + pull_request: + +jobs: + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Setup Node + uses: actions/setup-node@v3 + with: + node-version: "20" + cache: "npm" + cache-dependency-path: "**/package-lock.json" + + - name: Install dependencies + run: npm ci + + - name: Test + run: npm test diff --git a/package-lock.json b/package-lock.json index a3de042..913959e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -940,6 +940,18 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, + "node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "dev": true, + "dependencies": { + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.5", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", @@ -1403,6 +1415,12 @@ "win32" ] }, + "node_modules/@sinclair/typebox": { + "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", + "dev": true + }, "node_modules/@tweenjs/tween.js": { "version": "23.1.2", "resolved": "https://registry.npmjs.org/@tweenjs/tween.js/-/tween.js-23.1.2.tgz", @@ -1468,15 +1486,6 @@ "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", "dev": true }, - "node_modules/@types/hast": { - "version": "2.3.10", - "resolved": "https://registry.npmjs.org/@types/hast/-/hast-2.3.10.tgz", - "integrity": "sha512-McWspRw8xx8J9HurkVBfYj0xKoE25tOFlHGdx4MJ5xORQrMGZNqJhVQWaIbm6Oyla5kYOXtDiopzKRJzEOkwJw==", - "license": "MIT", - "dependencies": { - "@types/unist": "^2" - } - }, "node_modules/@types/is-mobile": { "version": "2.1.4", "resolved": "https://registry.npmjs.org/@types/is-mobile/-/is-mobile-2.1.4.tgz", @@ -1569,16 +1578,6 @@ "@types/react": "*" } }, - "node_modules/@types/react-syntax-highlighter": { - "version": "15.5.13", - "resolved": "https://registry.npmjs.org/@types/react-syntax-highlighter/-/react-syntax-highlighter-15.5.13.tgz", - "integrity": "sha512-uLGJ87j6Sz8UaBAooU0T6lWJ0dBmjZgN1PZTrj05TNql2/XpC6+4HhMT5syIdFUUt+FASfCeLLv4kBygNU+8qA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/react": "*" - } - }, "node_modules/@types/stats.js": { "version": "0.17.3", "resolved": "https://registry.npmjs.org/@types/stats.js/-/stats.js-0.17.3.tgz", @@ -1601,12 +1600,6 @@ "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.2.tgz", "integrity": "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==" }, - "node_modules/@types/unist": { - "version": "2.0.10", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.10.tgz", - "integrity": "sha512-IfYcSBWE3hLpBg8+X2SEa8LVkJdJEkT2Ese2aaLs3ptGdVtABxndrMaxuFlQ1qdFf9Q5rDvDpxI3WwgvKFAsQA==", - "license": "MIT" - }, "node_modules/@types/webxr": { "version": "0.5.16", "resolved": "https://registry.npmjs.org/@types/webxr/-/webxr-0.5.16.tgz", @@ -1620,6 +1613,102 @@ "dev": true, "license": "ISC" }, + "node_modules/@vitest/expect": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-1.6.0.tgz", + "integrity": "sha512-ixEvFVQjycy/oNgHjqsL6AZCDduC+tflRluaHIzKIsdbzkLn2U/iBnVeJwB6HsIjQBdfMR8Z0tRxKUsvFJEeWQ==", + "dev": true, + "dependencies": { + "@vitest/spy": "1.6.0", + "@vitest/utils": "1.6.0", + "chai": "^4.3.10" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/runner": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-1.6.0.tgz", + "integrity": "sha512-P4xgwPjwesuBiHisAVz/LSSZtDjOTPYZVmNAnpHHSR6ONrf8eCJOFRvUwdHn30F5M1fxhqtl7QZQUk2dprIXAg==", + "dev": true, + "dependencies": { + "@vitest/utils": "1.6.0", + "p-limit": "^5.0.0", + "pathe": "^1.1.1" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/runner/node_modules/p-limit": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-5.0.0.tgz", + "integrity": "sha512-/Eaoq+QyLSiXQ4lyYV23f14mZRQcXnxfHrN0vCai+ak9G0pp9iEQukIIZq5NccEvwRB8PUnZT0KsOoDCINS1qQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^1.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@vitest/runner/node_modules/yocto-queue": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.0.0.tgz", + "integrity": "sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==", + "dev": true, + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@vitest/snapshot": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-1.6.0.tgz", + "integrity": "sha512-+Hx43f8Chus+DCmygqqfetcAZrDJwvTj0ymqjQq4CvmpKFSTVteEOBzCusu1x2tt4OJcvBflyHUE0DZSLgEMtQ==", + "dev": true, + "dependencies": { + "magic-string": "^0.30.5", + "pathe": "^1.1.1", + "pretty-format": "^29.7.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/spy": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-1.6.0.tgz", + "integrity": "sha512-leUTap6B/cqi/bQkXUu6bQV5TZPx7pmMBKBQiI0rJA8c3pB56ZsaTbREnF7CJfmvAS4V2cXIBAh/3rVwrrCYgw==", + "dev": true, + "dependencies": { + "tinyspy": "^2.2.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/utils": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-1.6.0.tgz", + "integrity": "sha512-21cPiuGMoMZwiOHa2i4LXkMkMkCGzA+MVFV70jRwHo95dL4x/ts5GZhML1QWuy7yfp3WzK3lRvZi3JnXTYqrBw==", + "dev": true, + "dependencies": { + "diff-sequences": "^29.6.3", + "estree-walker": "^3.0.3", + "loupe": "^2.3.7", + "pretty-format": "^29.7.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, "node_modules/acorn": { "version": "8.11.3", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", @@ -1643,6 +1732,15 @@ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, + "node_modules/acorn-walk": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.2.tgz", + "integrity": "sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/ajv": { "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", @@ -1864,6 +1962,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "dev": true, + "engines": { + "node": "*" + } + }, "node_modules/available-typed-arrays": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", @@ -1988,6 +2095,15 @@ "ieee754": "^1.2.1" } }, + "node_modules/cac": { + "version": "6.7.14", + "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", + "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/call-bind": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", @@ -2039,6 +2155,24 @@ ], "license": "CC-BY-4.0" }, + "node_modules/chai": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.4.1.tgz", + "integrity": "sha512-13sOfMv2+DWduEU+/xbun3LScLoqN17nBeTLUsmDfKdoiC1fr0n9PU4guu4AhRcOVFk/sW8LyZWHuhWtQZiF+g==", + "dev": true, + "dependencies": { + "assertion-error": "^1.1.0", + "check-error": "^1.0.3", + "deep-eql": "^4.1.3", + "get-func-name": "^2.0.2", + "loupe": "^2.3.6", + "pathval": "^1.1.1", + "type-detect": "^4.0.8" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/chalk": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", @@ -2054,34 +2188,16 @@ "node": ">=4" } }, - "node_modules/character-entities": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-1.2.4.tgz", - "integrity": "sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/character-entities-legacy": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz", - "integrity": "sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/character-reference-invalid": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-1.1.4.tgz", - "integrity": "sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "node_modules/check-error": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz", + "integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==", + "dev": true, + "dependencies": { + "get-func-name": "^2.0.2" + }, + "engines": { + "node": "*" } }, "node_modules/cli-cursor": { @@ -2146,16 +2262,6 @@ "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", "dev": true }, - "node_modules/comma-separated-tokens": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-1.0.8.tgz", - "integrity": "sha512-GHuDRO12Sypu2cV70d1dkA2EUmXHgntrzbpvOB+Qy+49ypNfGgFQIC2fhhXbnyrJRynDCAARsT7Ou0M6hirpfw==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, "node_modules/commander": { "version": "12.1.0", "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", @@ -2172,6 +2278,12 @@ "dev": true, "license": "MIT" }, + "node_modules/confbox": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.1.7.tgz", + "integrity": "sha512-uJcB/FKZtBMCJpK8MQji6bJHgu1tixKPxRLeGkNzBoOZzpnZUJm0jm2/sBDWcuBx1dYgxV4JU+g5hmNxCyAmdA==", + "dev": true + }, "node_modules/convert-source-map": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", @@ -2291,6 +2403,18 @@ } } }, + "node_modules/deep-eql": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.4.tgz", + "integrity": "sha512-SUwdGfqdKOwxCPeVYjwSyRpJ7Z+fhpwIAtmCUdZIWZ/YP5R9WAsyuSgpLVDi9bjWoN2LXHNss/dk3urXtdQxGg==", + "dev": true, + "dependencies": { + "type-detect": "^4.0.0" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", @@ -2334,6 +2458,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/diff-sequences": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", + "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", + "dev": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, "node_modules/dir-glob": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", @@ -3340,6 +3473,15 @@ "node": ">=4.0" } }, + "node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "dependencies": { + "@types/estree": "^1.0.0" + } + }, "node_modules/esutils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", @@ -3447,19 +3589,6 @@ "reusify": "^1.0.4" } }, - "node_modules/fault": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/fault/-/fault-1.0.4.tgz", - "integrity": "sha512-CJ0HCB5tL5fYTEA7ToAq5+kTwd++Borf1/bifxd9iT70QcXr4MRrO3Llf8Ifs70q+SJcGHFtnIE/Nw6giCtECA==", - "license": "MIT", - "dependencies": { - "format": "^0.2.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, "node_modules/fflate": { "version": "0.6.10", "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.6.10.tgz", @@ -3557,14 +3686,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/format": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/format/-/format-0.2.2.tgz", - "integrity": "sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww==", - "engines": { - "node": ">=0.4.x" - } - }, "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -3647,6 +3768,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/get-func-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", + "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==", + "dev": true, + "engines": { + "node": "*" + } + }, "node_modules/get-intrinsic": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", @@ -3900,42 +4030,6 @@ "node": ">= 0.4" } }, - "node_modules/hast-util-parse-selector": { - "version": "2.2.5", - "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-2.2.5.tgz", - "integrity": "sha512-7j6mrk/qqkSehsM92wQjdIgWM2/BW61u/53G6xmC8i1OmEdKLHbk419QKQUjz6LglWsfqoiHmyMRkP1BGjecNQ==", - "license": "MIT", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/hastscript": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-6.0.0.tgz", - "integrity": "sha512-nDM6bvd7lIqDUiYEiu5Sl/+6ReP0BMk/2f4U/Rooccxkj0P5nm+acM5PrGJ/t5I8qPGiqZSE6hVAwZEdZIvP4w==", - "license": "MIT", - "dependencies": { - "@types/hast": "^2.0.0", - "comma-separated-tokens": "^1.0.0", - "hast-util-parse-selector": "^2.0.0", - "property-information": "^5.0.0", - "space-separated-tokens": "^1.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/highlight.js": { - "version": "10.7.3", - "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz", - "integrity": "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==", - "license": "BSD-3-Clause", - "engines": { - "node": "*" - } - }, "node_modules/hosted-git-info": { "version": "2.8.9", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", @@ -4057,30 +4151,6 @@ "node": ">= 0.4" } }, - "node_modules/is-alphabetical": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-1.0.4.tgz", - "integrity": "sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/is-alphanumerical": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-1.0.4.tgz", - "integrity": "sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A==", - "license": "MIT", - "dependencies": { - "is-alphabetical": "^1.0.0", - "is-decimal": "^1.0.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, "node_modules/is-array-buffer": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz", @@ -4209,16 +4279,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-decimal": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-1.0.4.tgz", - "integrity": "sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -4283,16 +4343,6 @@ "node": ">=0.10.0" } }, - "node_modules/is-hexadecimal": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz", - "integrity": "sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, "node_modules/is-map": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", @@ -4774,6 +4824,22 @@ "node": ">=4" } }, + "node_modules/local-pkg": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-0.5.0.tgz", + "integrity": "sha512-ok6z3qlYyCDS4ZEU27HaU6x/xZa9Whf8jD4ptH5UZTQYZVYeb9bnZ3ojVhiJNLiXK1Hfc0GNbLXcmZ5plLDDBg==", + "dev": true, + "dependencies": { + "mlly": "^1.4.2", + "pkg-types": "^1.0.3" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, "node_modules/locate-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", @@ -4877,18 +4943,13 @@ "loose-envify": "cli.js" } }, - "node_modules/lowlight": { - "version": "1.20.0", - "resolved": "https://registry.npmjs.org/lowlight/-/lowlight-1.20.0.tgz", - "integrity": "sha512-8Ktj+prEb1RoCPkEOrPMYUN/nCggB7qAWe3a7OpMjWQkh3l2RD5wKRQ+o8Q8YuI9RG/xs95waaI/E6ym/7NsTw==", - "license": "MIT", + "node_modules/loupe": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz", + "integrity": "sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==", + "dev": true, "dependencies": { - "fault": "^1.0.0", - "highlight.js": "~10.7.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "get-func-name": "^2.0.1" } }, "node_modules/lru-cache": { @@ -4911,6 +4972,15 @@ "three": ">=0.144.0" } }, + "node_modules/magic-string": { + "version": "0.30.10", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.10.tgz", + "integrity": "sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ==", + "dev": true, + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.4.15" + } + }, "node_modules/memorystream": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz", @@ -4988,6 +5058,18 @@ "node": ">=16 || 14 >=14.17" } }, + "node_modules/mlly": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.7.1.tgz", + "integrity": "sha512-rrVRZRELyQzrIUAVMHxP97kv+G786pHmOKzuFII8zDYahFBS7qnHh2AlYSl1GAHhaMPCz6/oHjVMcfFYgFYHgA==", + "dev": true, + "dependencies": { + "acorn": "^8.11.3", + "pathe": "^1.1.2", + "pkg-types": "^1.1.1", + "ufo": "^1.5.3" + } + }, "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -5414,24 +5496,6 @@ "node": ">=6" } }, - "node_modules/parse-entities": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-2.0.0.tgz", - "integrity": "sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ==", - "license": "MIT", - "dependencies": { - "character-entities": "^1.0.0", - "character-entities-legacy": "^1.0.0", - "character-reference-invalid": "^1.0.0", - "is-alphanumerical": "^1.0.0", - "is-decimal": "^1.0.0", - "is-hexadecimal": "^1.0.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, "node_modules/parse-json": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", @@ -5521,6 +5585,21 @@ "node": ">=4" } }, + "node_modules/pathe": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.2.tgz", + "integrity": "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==", + "dev": true + }, + "node_modules/pathval": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", + "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", + "dev": true, + "engines": { + "node": "*" + } + }, "node_modules/picocolors": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", @@ -5564,6 +5643,17 @@ "node": ">=4" } }, + "node_modules/pkg-types": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.1.1.tgz", + "integrity": "sha512-ko14TjmDuQJ14zsotODv7dBlwxKhUKQEhuhmbqo1uCi9BB0Z2alo/wAXg6q1dTR5TyuqYyWhjtfe/Tsh+X28jQ==", + "dev": true, + "dependencies": { + "confbox": "^0.1.7", + "mlly": "^1.7.0", + "pathe": "^1.1.2" + } + }, "node_modules/possible-typed-array-names": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz", @@ -5659,25 +5749,48 @@ "node": ">=6.0.0" } }, - "node_modules/prism-react-renderer": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/prism-react-renderer/-/prism-react-renderer-2.3.1.tgz", - "integrity": "sha512-Rdf+HzBLR7KYjzpJ1rSoxT9ioO85nZngQEoFIhL07XhtJHlCU3SOz0GJ6+qvMyQe0Se+BV3qpe6Yd/NmQF5Juw==", + "node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "dev": true, "dependencies": { - "@types/prismjs": "^1.26.0", - "clsx": "^2.0.0" + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" }, - "peerDependencies": { - "react": ">=16.0.0" + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/prismjs": { - "version": "1.29.0", - "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.29.0.tgz", - "integrity": "sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==", - "license": "MIT", + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, "engines": { - "node": ">=6" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/pretty-format/node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true + }, + "node_modules/prism-react-renderer": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/prism-react-renderer/-/prism-react-renderer-2.3.1.tgz", + "integrity": "sha512-Rdf+HzBLR7KYjzpJ1rSoxT9ioO85nZngQEoFIhL07XhtJHlCU3SOz0GJ6+qvMyQe0Se+BV3qpe6Yd/NmQF5Juw==", + "dependencies": { + "@types/prismjs": "^1.26.0", + "clsx": "^2.0.0" + }, + "peerDependencies": { + "react": ">=16.0.0" } }, "node_modules/prop-types": { @@ -5692,19 +5805,6 @@ "react-is": "^16.13.1" } }, - "node_modules/property-information": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/property-information/-/property-information-5.6.0.tgz", - "integrity": "sha512-YUHSPk+A30YPv+0Qf8i9Mbfe/C0hdPXk1s1jPVToV8pk8BQtpw10ct89Eo7OWkutrwqvT0eicAxlOg3dOAu8JA==", - "license": "MIT", - "dependencies": { - "xtend": "^4.0.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", @@ -5813,22 +5913,6 @@ "node": ">=0.10.0" } }, - "node_modules/react-syntax-highlighter": { - "version": "15.5.0", - "resolved": "https://registry.npmjs.org/react-syntax-highlighter/-/react-syntax-highlighter-15.5.0.tgz", - "integrity": "sha512-+zq2myprEnQmH5yw6Gqc8lD55QHnpKaU8TOcFeC/Lg/MQSs8UknEA0JC4nTZGFAXC2J2Hyj/ijJ7NlabyPi2gg==", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.3.1", - "highlight.js": "^10.4.1", - "lowlight": "^1.17.0", - "prismjs": "^1.27.0", - "refractor": "^3.6.0" - }, - "peerDependencies": { - "react": ">= 0.14.0" - } - }, "node_modules/react-use-measure": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/react-use-measure/-/react-use-measure-2.1.1.tgz", @@ -5883,30 +5967,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/refractor": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/refractor/-/refractor-3.6.0.tgz", - "integrity": "sha512-MY9W41IOWxxk31o+YvFCNyNzdkc9M20NoZK5vq6jkv4I/uh2zkWcfudj0Q1fovjUQJrNewS9NMzeTtqPf+n5EA==", - "license": "MIT", - "dependencies": { - "hastscript": "^6.0.0", - "parse-entities": "^2.0.0", - "prismjs": "~1.27.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/refractor/node_modules/prismjs": { - "version": "1.27.0", - "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.27.0.tgz", - "integrity": "sha512-t13BGPUlFDR7wRB5kQDG4jjl7XeuH6jbJGt11JHPL96qwsEHNX2+68tFXqc1/k+/jALsbSWJKUOT/hcYAZ5LkA==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, "node_modules/regenerator-runtime": { "version": "0.14.1", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", @@ -6039,6 +6099,41 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/rollup": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.18.0.tgz", + "integrity": "sha512-QmJz14PX3rzbJCN1SG4Xe/bAAX2a6NpCP8ab2vfu2GiUr8AQcr2nCV/oEO3yneFarB67zk8ShlIyWb2LGTb3Sg==", + "dev": true, + "dependencies": { + "@types/estree": "1.0.5" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.18.0", + "@rollup/rollup-android-arm64": "4.18.0", + "@rollup/rollup-darwin-arm64": "4.18.0", + "@rollup/rollup-darwin-x64": "4.18.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.18.0", + "@rollup/rollup-linux-arm-musleabihf": "4.18.0", + "@rollup/rollup-linux-arm64-gnu": "4.18.0", + "@rollup/rollup-linux-arm64-musl": "4.18.0", + "@rollup/rollup-linux-powerpc64le-gnu": "4.18.0", + "@rollup/rollup-linux-riscv64-gnu": "4.18.0", + "@rollup/rollup-linux-s390x-gnu": "4.18.0", + "@rollup/rollup-linux-x64-gnu": "4.18.0", + "@rollup/rollup-linux-x64-musl": "4.18.0", + "@rollup/rollup-win32-arm64-msvc": "4.18.0", + "@rollup/rollup-win32-ia32-msvc": "4.18.0", + "@rollup/rollup-win32-x64-msvc": "4.18.0", + "fsevents": "~2.3.2" + } + }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -6205,6 +6300,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/siginfo": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", + "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", + "dev": true + }, "node_modules/signal-exit": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", @@ -6265,16 +6366,6 @@ "node": ">=0.10.0" } }, - "node_modules/space-separated-tokens": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-1.1.5.tgz", - "integrity": "sha512-q/JSVd1Lptzhf5bkYm4ob4iWPjx0KiRe3sRFBNrVqbJkFaBm5vbbowy1mymoPNLRa52+oadOhJ+K49wsSeSjTA==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, "node_modules/spdx-correct": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", @@ -6311,6 +6402,18 @@ "dev": true, "license": "CC0-1.0" }, + "node_modules/stackback": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", + "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", + "dev": true + }, + "node_modules/std-env": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.7.0.tgz", + "integrity": "sha512-JPbdCEQLj1w5GilpiHAx3qJvFndqybBysA3qUOnznweH4QbNYUsW/ea8QzSrnh0vNsezMMw5bcVool8lM0gwzg==", + "dev": true + }, "node_modules/string-argv": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.2.tgz", @@ -6559,6 +6662,24 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/strip-literal": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-2.1.0.tgz", + "integrity": "sha512-Op+UycaUt/8FbN/Z2TWPBLge3jWrP3xj10f3fnYxf052bKuS3EKs1ZQcVGjnEMdsNVAM+plXRdmjrZ/KgG3Skw==", + "dev": true, + "dependencies": { + "js-tokens": "^9.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/strip-literal/node_modules/js-tokens": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.0.tgz", + "integrity": "sha512-WriZw1luRMlmV3LGJaR6QOJjWwgLUTf89OwT2lUOyjX2dJGBwgmIkbcz+7WFZjrZM635JOIR517++e/67CP9dQ==", + "dev": true + }, "node_modules/supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", @@ -6645,6 +6766,30 @@ "three": ">=0.128.0" } }, + "node_modules/tinybench": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.8.0.tgz", + "integrity": "sha512-1/eK7zUnIklz4JUUlL+658n58XO2hHLQfSk1Zf2LKieUjxidN16eKFEoDEfjHc3ohofSSqK3X5yO6VGb6iW8Lw==", + "dev": true + }, + "node_modules/tinypool": { + "version": "0.8.4", + "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-0.8.4.tgz", + "integrity": "sha512-i11VH5gS6IFeLY3gMBQ00/MmLncVP7JLXOw1vlgkytLmJK7QnEr7NXf0LBdxfmNPAeyetukOk0bOYrJrFGjYJQ==", + "dev": true, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tinyspy": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-2.2.1.tgz", + "integrity": "sha512-KYad6Vy5VDWV4GH3fjpseMQ/XU2BhIYP7Vzd0LG44qRWm/Yt2WCOTicFdvmgo6gWaqooMQCawTtILVQJupKu7A==", + "dev": true, + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/to-fast-properties": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", @@ -6788,6 +6933,15 @@ "node": ">= 0.8.0" } }, + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, "node_modules/type-fest": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", @@ -6891,6 +7045,12 @@ "node": ">=14.17" } }, + "node_modules/ufo": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.5.3.tgz", + "integrity": "sha512-Y7HYmWaFwPUmkoQCUIAYpKqkOf+SbVj/2fJJZ4RJMCfZp0rTGwRbzQD+HghfnhKOjL9E01okqz+ncJskGYfBNw==", + "dev": true + }, "node_modules/unbox-primitive": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", @@ -6972,6 +7132,186 @@ "integrity": "sha512-vHtIYWt9uLl2P2tLlatVpMwv9+ezuJCtMNjUVIpzd5Pa/dJXN8AtqkKmVRcNSlmXyCjkCkbMQX/Vs9axmdlfgg==", "license": "MIT" }, + "node_modules/vite": { + "version": "5.2.13", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.2.13.tgz", + "integrity": "sha512-SSq1noJfY9pR3I1TUENL3rQYDQCFqgD+lM6fTRAM8Nv6Lsg5hDLaXkjETVeBt+7vZBCMoibD+6IWnT2mJ+Zb/A==", + "dev": true, + "dependencies": { + "esbuild": "^0.20.1", + "postcss": "^8.4.38", + "rollup": "^4.13.0" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || >=20.0.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + }, + "node_modules/vite-node": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-1.6.0.tgz", + "integrity": "sha512-de6HJgzC+TFzOu0NTC4RAIsyf/DY/ibWDYQUcuEA84EMHhcefTUGkjFHKKEJhQN4A+6I0u++kr3l36ZF2d7XRw==", + "dev": true, + "dependencies": { + "cac": "^6.7.14", + "debug": "^4.3.4", + "pathe": "^1.1.1", + "picocolors": "^1.0.0", + "vite": "^5.0.0" + }, + "bin": { + "vite-node": "vite-node.mjs" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/vite/node_modules/esbuild": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.20.2.tgz", + "integrity": "sha512-WdOOppmUNU+IbZ0PaDiTst80zjnrOkyJNHoKupIcVyU8Lvla3Ugx94VzkQ32Ijqd7UhHJy75gNWDMUekcrSJ6g==", + "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.20.2", + "@esbuild/android-arm": "0.20.2", + "@esbuild/android-arm64": "0.20.2", + "@esbuild/android-x64": "0.20.2", + "@esbuild/darwin-arm64": "0.20.2", + "@esbuild/darwin-x64": "0.20.2", + "@esbuild/freebsd-arm64": "0.20.2", + "@esbuild/freebsd-x64": "0.20.2", + "@esbuild/linux-arm": "0.20.2", + "@esbuild/linux-arm64": "0.20.2", + "@esbuild/linux-ia32": "0.20.2", + "@esbuild/linux-loong64": "0.20.2", + "@esbuild/linux-mips64el": "0.20.2", + "@esbuild/linux-ppc64": "0.20.2", + "@esbuild/linux-riscv64": "0.20.2", + "@esbuild/linux-s390x": "0.20.2", + "@esbuild/linux-x64": "0.20.2", + "@esbuild/netbsd-x64": "0.20.2", + "@esbuild/openbsd-x64": "0.20.2", + "@esbuild/sunos-x64": "0.20.2", + "@esbuild/win32-arm64": "0.20.2", + "@esbuild/win32-ia32": "0.20.2", + "@esbuild/win32-x64": "0.20.2" + } + }, + "node_modules/vitest": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-1.6.0.tgz", + "integrity": "sha512-H5r/dN06swuFnzNFhq/dnz37bPXnq8xB2xB5JOVk8K09rUtoeNN+LHWkoQ0A/i3hvbUKKcCei9KpbxqHMLhLLA==", + "dev": true, + "dependencies": { + "@vitest/expect": "1.6.0", + "@vitest/runner": "1.6.0", + "@vitest/snapshot": "1.6.0", + "@vitest/spy": "1.6.0", + "@vitest/utils": "1.6.0", + "acorn-walk": "^8.3.2", + "chai": "^4.3.10", + "debug": "^4.3.4", + "execa": "^8.0.1", + "local-pkg": "^0.5.0", + "magic-string": "^0.30.5", + "pathe": "^1.1.1", + "picocolors": "^1.0.0", + "std-env": "^3.5.0", + "strip-literal": "^2.0.0", + "tinybench": "^2.5.1", + "tinypool": "^0.8.3", + "vite": "^5.0.0", + "vite-node": "1.6.0", + "why-is-node-running": "^2.2.2" + }, + "bin": { + "vitest": "vitest.mjs" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@types/node": "^18.0.0 || >=20.0.0", + "@vitest/browser": "1.6.0", + "@vitest/ui": "1.6.0", + "happy-dom": "*", + "jsdom": "*" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@vitest/browser": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + } + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -7071,6 +7411,22 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/why-is-node-running": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.2.2.tgz", + "integrity": "sha512-6tSwToZxTOcotxHeA+qGCq1mVzKR3CwcJGmVcY+QE8SHy6TnpFnh8PAvPNHYr7EcuVeG0QSMxtYCuO1ta/G/oA==", + "dev": true, + "dependencies": { + "siginfo": "^2.0.0", + "stackback": "0.0.2" + }, + "bin": { + "why-is-node-running": "cli.js" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/word-wrap": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", @@ -7218,15 +7574,6 @@ "dev": true, "license": "ISC" }, - "node_modules/xtend": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", - "license": "MIT", - "engines": { - "node": ">=0.4" - } - }, "node_modules/yallist": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", @@ -7290,7 +7637,6 @@ "react": "^18.3.1", "react-dom": "^18.3.1", "react-lazyload": "^3.2.1", - "react-syntax-highlighter": "^15.5.0", "react-vfx": "*", "three": "^0.165.0", "vh-check": "^2.0.5" @@ -7304,7 +7650,6 @@ "@types/react": "^18.3.3", "@types/react-dom": "^18.3.0", "@types/react-lazyload": "^3.2.3", - "@types/react-syntax-highlighter": "^15.5.13", "@types/three": "^0.165.0", "@vitejs/plugin-react": "^4.3.0", "rimraf": "^5.0.7", @@ -7340,44 +7685,6 @@ "balanced-match": "^1.0.0" } }, - "packages/docs/node_modules/esbuild": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.20.2.tgz", - "integrity": "sha512-WdOOppmUNU+IbZ0PaDiTst80zjnrOkyJNHoKupIcVyU8Lvla3Ugx94VzkQ32Ijqd7UhHJy75gNWDMUekcrSJ6g==", - "dev": true, - "hasInstallScript": true, - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=12" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.20.2", - "@esbuild/android-arm": "0.20.2", - "@esbuild/android-arm64": "0.20.2", - "@esbuild/android-x64": "0.20.2", - "@esbuild/darwin-arm64": "0.20.2", - "@esbuild/darwin-x64": "0.20.2", - "@esbuild/freebsd-arm64": "0.20.2", - "@esbuild/freebsd-x64": "0.20.2", - "@esbuild/linux-arm": "0.20.2", - "@esbuild/linux-arm64": "0.20.2", - "@esbuild/linux-ia32": "0.20.2", - "@esbuild/linux-loong64": "0.20.2", - "@esbuild/linux-mips64el": "0.20.2", - "@esbuild/linux-ppc64": "0.20.2", - "@esbuild/linux-riscv64": "0.20.2", - "@esbuild/linux-s390x": "0.20.2", - "@esbuild/linux-x64": "0.20.2", - "@esbuild/netbsd-x64": "0.20.2", - "@esbuild/openbsd-x64": "0.20.2", - "@esbuild/sunos-x64": "0.20.2", - "@esbuild/win32-arm64": "0.20.2", - "@esbuild/win32-ia32": "0.20.2", - "@esbuild/win32-x64": "0.20.2" - } - }, "packages/docs/node_modules/glob": { "version": "10.4.1", "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.1.tgz", @@ -7433,96 +7740,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "packages/docs/node_modules/rollup": { - "version": "4.18.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.18.0.tgz", - "integrity": "sha512-QmJz14PX3rzbJCN1SG4Xe/bAAX2a6NpCP8ab2vfu2GiUr8AQcr2nCV/oEO3yneFarB67zk8ShlIyWb2LGTb3Sg==", - "dev": true, - "dependencies": { - "@types/estree": "1.0.5" - }, - "bin": { - "rollup": "dist/bin/rollup" - }, - "engines": { - "node": ">=18.0.0", - "npm": ">=8.0.0" - }, - "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.18.0", - "@rollup/rollup-android-arm64": "4.18.0", - "@rollup/rollup-darwin-arm64": "4.18.0", - "@rollup/rollup-darwin-x64": "4.18.0", - "@rollup/rollup-linux-arm-gnueabihf": "4.18.0", - "@rollup/rollup-linux-arm-musleabihf": "4.18.0", - "@rollup/rollup-linux-arm64-gnu": "4.18.0", - "@rollup/rollup-linux-arm64-musl": "4.18.0", - "@rollup/rollup-linux-powerpc64le-gnu": "4.18.0", - "@rollup/rollup-linux-riscv64-gnu": "4.18.0", - "@rollup/rollup-linux-s390x-gnu": "4.18.0", - "@rollup/rollup-linux-x64-gnu": "4.18.0", - "@rollup/rollup-linux-x64-musl": "4.18.0", - "@rollup/rollup-win32-arm64-msvc": "4.18.0", - "@rollup/rollup-win32-ia32-msvc": "4.18.0", - "@rollup/rollup-win32-x64-msvc": "4.18.0", - "fsevents": "~2.3.2" - } - }, - "packages/docs/node_modules/vite": { - "version": "5.2.13", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.2.13.tgz", - "integrity": "sha512-SSq1noJfY9pR3I1TUENL3rQYDQCFqgD+lM6fTRAM8Nv6Lsg5hDLaXkjETVeBt+7vZBCMoibD+6IWnT2mJ+Zb/A==", - "dev": true, - "dependencies": { - "esbuild": "^0.20.1", - "postcss": "^8.4.38", - "rollup": "^4.13.0" - }, - "bin": { - "vite": "bin/vite.js" - }, - "engines": { - "node": "^18.0.0 || >=20.0.0" - }, - "funding": { - "url": "https://github.com/vitejs/vite?sponsor=1" - }, - "optionalDependencies": { - "fsevents": "~2.3.3" - }, - "peerDependencies": { - "@types/node": "^18.0.0 || >=20.0.0", - "less": "*", - "lightningcss": "^1.21.0", - "sass": "*", - "stylus": "*", - "sugarss": "*", - "terser": "^5.4.0" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, - "less": { - "optional": true - }, - "lightningcss": { - "optional": true - }, - "sass": { - "optional": true - }, - "stylus": { - "optional": true - }, - "sugarss": { - "optional": true - }, - "terser": { - "optional": true - } - } - }, "packages/react-vfx": { "version": "0.5.0", "license": "MIT", @@ -7545,7 +7762,8 @@ "npm-run-all": "^4.1.5", "prettier": "^3.3.1", "rimraf": "^5.0.7", - "typescript": "^5.4.5" + "typescript": "^5.4.5", + "vitest": "^1.6.0" }, "peerDependencies": { "react": ">= 16.12.0", diff --git a/package.json b/package.json index 39de8a1..e1ecb3d 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,8 @@ "dev": "turbo run dev", "clean": "turbo run clean", "lint": "turbo run lint", - "prepare": "husky install" + "prepare": "husky install", + "test": "npm --workspace=react-vfx test" }, "repository": { "type": "git", diff --git a/packages/docs/src/dom/AuthorSection.tsx b/packages/docs/src/dom/AuthorSection.tsx index 3def7af..bf75a3c 100644 --- a/packages/docs/src/dom/AuthorSection.tsx +++ b/packages/docs/src/dom/AuthorSection.tsx @@ -18,7 +18,7 @@ const AuthorSection: React.FC = () => { className="icon" src={pub("amagi.png")} shader="glitch" - overflow + overflow={[0, 200, 0, 200]} />

Made by AMAGI

diff --git a/packages/docs/src/dom/ExamplesSection.tsx b/packages/docs/src/dom/ExamplesSection.tsx index bc32150..173a858 100644 --- a/packages/docs/src/dom/ExamplesSection.tsx +++ b/packages/docs/src/dom/ExamplesSection.tsx @@ -24,7 +24,7 @@ const ExamplesSection: React.FC = () => { @@ -44,14 +44,14 @@ const ExamplesSection: React.FC = () => { @@ -76,7 +76,7 @@ const ExamplesSection: React.FC = () => {
- + You can also add effects to
plain text!!!!!
@@ -86,7 +86,7 @@ const ExamplesSection: React.FC = () => {
diff --git a/packages/docs/src/dom/IntroSection.tsx b/packages/docs/src/dom/IntroSection.tsx index a974743..a8a7675 100644 --- a/packages/docs/src/dom/IntroSection.tsx +++ b/packages/docs/src/dom/IntroSection.tsx @@ -27,14 +27,14 @@ const IntroSection: React.FC = () => { glitched images,{" "} stylized videos {" "} diff --git a/packages/docs/src/dom/LogoSection.tsx b/packages/docs/src/dom/LogoSection.tsx index b25db13..325a219 100644 --- a/packages/docs/src/dom/LogoSection.tsx +++ b/packages/docs/src/dom/LogoSection.tsx @@ -12,7 +12,7 @@ const LogoSection: React.FC = () => {
); diff --git a/packages/docs/src/dom/UsageSection.tsx b/packages/docs/src/dom/UsageSection.tsx index 783845e..efbf95d 100644 --- a/packages/docs/src/dom/UsageSection.tsx +++ b/packages/docs/src/dom/UsageSection.tsx @@ -336,7 +336,7 @@ const UsageSection: React.VFC = () => ( window.scrollY / (document.body.scrollHeight - window.innerHeight), }} - overflow + overflow={{ left: 1000, right: 1000 }} > I'm scrolling! diff --git a/packages/react-vfx/.eslintrc b/packages/react-vfx/.eslintrc index fcc7508..c9249ab 100644 --- a/packages/react-vfx/.eslintrc +++ b/packages/react-vfx/.eslintrc @@ -3,42 +3,43 @@ "env": { "es6": true, "node": true, - "browser": true + "browser": true, }, "extends": [ "eslint:recommended", "plugin:@typescript-eslint/recommended", "prettier", - "plugin:react/recommended" + "plugin:react/recommended", ], "plugins": ["@typescript-eslint", "react-hooks"], "parserOptions": { "sourceType": "module", - "project": "./tsconfig.json" + "project": "./tsconfig.json", }, "rules": { "@typescript-eslint/explicit-function-return-type": [ "warn", { "allowExpressions": true, - "allowTypedFunctionExpressions": true - } + "allowTypedFunctionExpressions": true, + }, ], - "@typescript-eslint/indent": ["warn", 4], "react/prop-types": "off", "react-hooks/rules-of-hooks": "error", - "react-hooks/exhaustive-deps": "warn" + "react-hooks/exhaustive-deps": "warn", }, "settings": { "react": { - "version": "detect" - } + "version": "detect", + }, }, - "overrides": [{ - "files": ["*.js"], - "rules": { - "@typescript-eslint/no-var-requires": 0 - } - }], - "ignorePatterns": ["src/gifuct-js"] + "overrides": [ + { + "files": ["*.js"], + "rules": { + "@typescript-eslint/no-var-requires": 0, + }, + }, + ], + "ignorePatterns": ["src/gifuct-js"], } diff --git a/packages/react-vfx/package.json b/packages/react-vfx/package.json index 299b6e6..5ec3ba8 100644 --- a/packages/react-vfx/package.json +++ b/packages/react-vfx/package.json @@ -30,7 +30,8 @@ "npm-run-all": "^4.1.5", "prettier": "^3.3.1", "rimraf": "^5.0.7", - "typescript": "^5.4.5" + "typescript": "^5.4.5", + "vitest": "^1.6.0" }, "homepage": "https://amagi.dev/react-vfx", "keywords": [ @@ -67,7 +68,9 @@ "watch:cjs": "tsc -d -w", "watch:esm": "tsc -d -w -p tsconfig.esm.json", "lint": "eslint src/**/*.ts src/**/*.tsx", - "lint-staged": "lint-staged" + "lint-staged": "lint-staged", + "test": "vitest --dir src --run", + "test:watch": "vitest --dir src" }, "types": "lib/esm/index.d.ts" } diff --git a/packages/react-vfx/src/constants.ts b/packages/react-vfx/src/constants.ts index 598009e..dc708ec 100644 --- a/packages/react-vfx/src/constants.ts +++ b/packages/react-vfx/src/constants.ts @@ -497,4 +497,6 @@ export const shaders = { gl_FragColor = texture2D(src, uv); } `, -}; +} as const; + +export type ShaderPreset = keyof typeof shaders; diff --git a/packages/react-vfx/src/types.ts b/packages/react-vfx/src/types.ts index 23fcbc4..dbdeed9 100644 --- a/packages/react-vfx/src/types.ts +++ b/packages/react-vfx/src/types.ts @@ -1,10 +1,33 @@ import THREE from "three"; +import { ShaderPreset } from "./constants"; export interface VFXProps { - shader?: string; + /** + * Shader code or preset name. + */ + shader?: ShaderPreset | (string & NonNullable); + release?: number; uniforms?: VFXUniforms; - overflow?: boolean; + + /** + * Allow shader outputs to oveflow the original element area. + * If true, REACT-VFX will render the shader in fullscreen. + * If number is specified, REACT-VFX adds paddings with the given value. + * + * You can also specify the overflow size for each direction like CSS's `padding` property. + * If you pass an array, it will be parsed as the top, right, bottom and left overflow. + * For example, `` will render the image with + * 100px right padding and 200px bottom padding. + * + * If you pass an object like ``, + * REACT-VFX will add paddings only to the given direction (only to the `top` in this example). + */ + overflow?: + | true + | number + | [top: number, right: number, bottom: number, left: number] + | { top?: number; right?: number; bottom?: number; left?: number }; } export type VFXUniforms = { @@ -33,5 +56,9 @@ export interface VFXElement { leaveTime: number; release: number; isGif: boolean; - overflow: boolean; + overflow: VFXElementOverflow; } + +export type VFXElementOverflow = + | "fullscreen" + | { top: number; right: number; bottom: number; left: number }; diff --git a/packages/react-vfx/src/vfx-player.test.ts b/packages/react-vfx/src/vfx-player.test.ts new file mode 100644 index 0000000..20fde3a --- /dev/null +++ b/packages/react-vfx/src/vfx-player.test.ts @@ -0,0 +1,245 @@ +import { expect, describe, test } from "vitest"; +import { isRectInViewport, sanitizeOverflow } from "./vfx-player"; + +describe("sanitizeOverflow", () => { + test('true => "fullscreen"', () => { + expect(sanitizeOverflow(true)).toBe("fullscreen"); + }); + + test("undefined => 0", () => { + expect(sanitizeOverflow(undefined)).toStrictEqual({ + top: 0, + right: 0, + bottom: 0, + left: 0, + }); + }); + + test("number", () => { + expect(sanitizeOverflow(100)).toStrictEqual({ + top: 100, + right: 100, + bottom: 100, + left: 100, + }); + }); + + test("number array", () => { + expect(sanitizeOverflow([0, 100, 200, 300])).toStrictEqual({ + top: 0, + right: 100, + bottom: 200, + left: 300, + }); + }); + + test("object", () => { + expect(sanitizeOverflow({})).toStrictEqual({ + top: 0, + right: 0, + bottom: 0, + left: 0, + }); + expect(sanitizeOverflow({ top: 100 })).toStrictEqual({ + top: 100, + right: 0, + bottom: 0, + left: 0, + }); + expect(sanitizeOverflow({ left: 100 })).toStrictEqual({ + top: 0, + right: 0, + bottom: 0, + left: 100, + }); + expect(sanitizeOverflow({ top: 100, left: 200 })).toStrictEqual({ + top: 100, + right: 0, + bottom: 0, + left: 200, + }); + expect( + sanitizeOverflow({ top: 100, right: 200, bottom: 300, left: 400 }), + ).toStrictEqual({ + top: 100, + right: 200, + bottom: 300, + left: 400, + }); + }); +}); + +describe("isRectInViewport", () => { + const rect = (x: number, y: number, w: number, h: number) => { + return { + left: x, + top: y, + right: x + w, + bottom: y + h, + }; + }; + + const pad = (t: number) => ({ left: t, right: t, top: t, bottom: t }); + + test("no overflow", () => { + expect( + isRectInViewport(rect(0, 0, 1, 1), rect(0, 0, 1, 1), pad(0)), + ).toBe(true); + + // adjacent rects + expect( + isRectInViewport( + rect(0, 0, 1, 1), + rect(-1, 0, 1, 1), // left + pad(0), + ), + ).toBe(true); + expect( + isRectInViewport( + rect(0, 0, 1, 1), + rect(1, 0, 1, 1), // right + pad(0), + ), + ).toBe(true); + expect( + isRectInViewport( + rect(0, 0, 1, 1), + rect(0, -1, 1, 1), // top + pad(0), + ), + ).toBe(true); + expect( + isRectInViewport( + rect(0, 0, 1, 1), + rect(0, 1, 1, 1), // bottom + pad(0), + ), + ).toBe(true); + + // distant rects + expect( + isRectInViewport( + rect(0, 0, 1, 1), + rect(-2, 0, 1, 1), // 1px left + pad(0), + ), + ).toBe(false); + expect( + isRectInViewport( + rect(0, 0, 1, 1), + rect(2, 0, 1, 1), // 1px right + pad(0), + ), + ).toBe(false); + expect( + isRectInViewport( + rect(0, 0, 1, 1), + rect(0, -2, 1, 1), // 1px top + pad(0), + ), + ).toBe(false); + expect( + isRectInViewport( + rect(0, 0, 1, 1), + rect(0, 2, 1, 1), // 1px bottom + pad(0), + ), + ).toBe(false); + }); + + test("with overflow", () => { + expect( + isRectInViewport(rect(0, 0, 1, 1), rect(0, 0, 1, 1), pad(1)), + ).toBe(true); + + // adjacent rects + expect( + isRectInViewport( + rect(0, 0, 1, 1), + rect(-1, 0, 1, 1), // left + pad(1), + ), + ).toBe(true); + expect( + isRectInViewport( + rect(0, 0, 1, 1), + rect(1, 0, 1, 1), // right + pad(1), + ), + ).toBe(true); + expect( + isRectInViewport( + rect(0, 0, 1, 1), + rect(0, -1, 1, 1), // top + pad(1), + ), + ).toBe(true); + expect( + isRectInViewport( + rect(0, 0, 1, 1), + rect(0, 1, 1, 1), // bottom + pad(1), + ), + ).toBe(true); + + // distant rects + expect( + isRectInViewport( + rect(0, 0, 1, 1), + rect(-2, 0, 1, 1), // 1px left + pad(1), + ), + ).toBe(true); + expect( + isRectInViewport( + rect(0, 0, 1, 1), + rect(2, 0, 1, 1), // 1px right + pad(1), + ), + ).toBe(true); + expect( + isRectInViewport( + rect(0, 0, 1, 1), + rect(0, -2, 1, 1), // 1px top + pad(1), + ), + ).toBe(true); + expect( + isRectInViewport( + rect(0, 0, 1, 1), + rect(0, 2, 1, 1), // 1px bottom + pad(1), + ), + ).toBe(true); + + // more distant rects + expect( + isRectInViewport( + rect(0, 0, 1, 1), + rect(-3, 0, 1, 1), // 2px left + pad(1), + ), + ).toBe(false); + expect( + isRectInViewport( + rect(0, 0, 1, 1), + rect(3, 0, 1, 1), // 2px right + pad(1), + ), + ).toBe(false); + expect( + isRectInViewport( + rect(0, 0, 1, 1), + rect(0, -3, 1, 1), // 2px top + pad(1), + ), + ).toBe(false); + expect( + isRectInViewport( + rect(0, 0, 1, 1), + rect(0, 3, 1, 1), // 2px bottom + pad(1), + ), + ).toBe(false); + }); +}); diff --git a/packages/react-vfx/src/vfx-player.ts b/packages/react-vfx/src/vfx-player.ts index b0a52f0..82a012a 100644 --- a/packages/react-vfx/src/vfx-player.ts +++ b/packages/react-vfx/src/vfx-player.ts @@ -2,7 +2,24 @@ import * as THREE from "three"; import dom2canvas from "./dom-to-canvas"; import { shaders, DEFAULT_VERTEX_SHADER } from "./constants"; import GIFData from "./gif"; -import { VFXProps, VFXElement, VFXElementType, VFXUniformValue } from "./types"; +import { + VFXProps, + VFXElement, + VFXElementType, + VFXUniformValue, + VFXElementOverflow, +} from "./types"; + +/** + * top-left origin rect. + * Subset of DOMRect, which is returned by `HTMLElement.getBoundingClientRect()`. + */ +type Rect = { + left: number; + right: number; + top: number; + bottom: number; +}; const gifFor = new Map(); @@ -15,8 +32,13 @@ export default class VFXPlayer { textureLoader = new THREE.TextureLoader(); - w = 0; - h = 0; + viewport: Rect = { + left: 0, + right: 0, + top: 0, + bottom: 0, + }; + scrollX = 0; scrollY = 0; @@ -63,17 +85,29 @@ export default class VFXPlayer { const w = window.innerWidth; const h = window.innerHeight; - if (w !== this.w || h !== this.h) { + if (w !== this.width() || h !== this.height()) { this.canvas.width = w; this.canvas.height = h; this.renderer.setSize(w, h); this.renderer.setPixelRatio(this.pixelRatio); - this.w = w; - this.h = h; + this.viewport = { + top: 0, + left: 0, + right: w, + bottom: h, + }; } } } + private width(): number { + return this.viewport.right - this.viewport.left; + } + + private height(): number { + return this.viewport.bottom - this.viewport.top; + } + private resize = async (): Promise => { if (typeof window !== "undefined") { // Update dom2canvas result. @@ -142,7 +176,8 @@ export default class VFXPlayer { const shader = this.getShader(opts.shader || "uvGradient"); const rect = element.getBoundingClientRect(); - const isInViewport = this.isRectInViewport(rect); + const overflow = sanitizeOverflow(opts.overflow); + const isInViewport = isRectInViewport(this.viewport, rect, overflow); // Create values for element types let texture: THREE.Texture; @@ -230,10 +265,10 @@ export default class VFXPlayer { uniformGenerators, startTime: now, enterTime: isInViewport ? now : -1, - leaveTime: Infinity, + leaveTime: -Infinity, release: opts.release ?? 0, isGif, - overflow: opts.overflow ?? false, + overflow, }; this.elements.push(elem); @@ -279,18 +314,27 @@ export default class VFXPlayer { const rect = e.element.getBoundingClientRect(); // Check intersection - const isInViewport = this.isRectInViewport(rect); + const isInViewport = isRectInViewport( + this.viewport, + rect, + e.overflow, + ); + + // entering if (isInViewport && !e.isInViewport) { e.enterTime = now; e.leaveTime = Infinity; } + + // leaving if (!isInViewport && e.isInViewport) { e.leaveTime = now; } e.isInViewport = isInViewport; - if (isInViewport && now - e.leaveTime > e.release) { - return; + // Quit if the element has left and the transition has ended + if (!isInViewport && now - e.leaveTime > e.release) { + continue; } // Update uniforms @@ -311,18 +355,14 @@ export default class VFXPlayer { e.uniforms[key].value = gen(); } - // Update GIF frame - const gif = gifFor.get(e.element); - if (gif !== undefined) { - gif.update(); - } - + // Update GIF / video + gifFor.get(e.element)?.update(); if (e.type === "video" || e.isGif) { e.uniforms["src"].value.needsUpdate = true; } // Set viewport - if (e.overflow) { + if (e.overflow === "fullscreen") { this.renderer.setViewport( 0, 0, @@ -331,10 +371,12 @@ export default class VFXPlayer { ); } else { this.renderer.setViewport( - rect.left, - window.innerHeight - (rect.top + rect.height), - rect.width, - rect.height, + rect.left - e.overflow.left, + window.innerHeight - + (rect.top + rect.height) - + e.overflow.bottom, + rect.width + (e.overflow.left + e.overflow.right), + rect.height + (e.overflow.top + e.overflow.bottom), ); } @@ -352,16 +394,6 @@ export default class VFXPlayer { } }; - private isRectInViewport(rect: DOMRect): boolean { - // TODO: Consider custom root element - return ( - rect.left <= this.w && - rect.right >= 0 && - rect.top <= this.h && - rect.bottom >= 0 - ); - } - private getShader(shaderNameOrCode: string): string { if (shaderNameOrCode in shaders) { return shaders[shaderNameOrCode as keyof typeof shaders]; @@ -370,3 +402,54 @@ export default class VFXPlayer { } } } + +// TODO: Consider custom root element +export function isRectInViewport( + viewport: Rect, + rect: Rect, + overflow: VFXElementOverflow, +): boolean { + if (overflow === "fullscreen") { + return true; + } + + return ( + rect.left - overflow.left <= viewport.right && + rect.right + overflow.right >= viewport.left && + rect.top - overflow.top <= viewport.bottom && + rect.bottom + overflow.bottom >= viewport.top + ); +} + +export function sanitizeOverflow( + overflow: VFXProps["overflow"], +): VFXElementOverflow { + if (overflow === true) { + return "fullscreen"; + } + if (overflow === undefined) { + return { top: 0, right: 0, bottom: 0, left: 0 }; + } + if (typeof overflow === "number") { + return { + top: overflow, + right: overflow, + bottom: overflow, + left: overflow, + }; + } + if (Array.isArray(overflow)) { + return { + top: overflow[0], + right: overflow[1], + bottom: overflow[2], + left: overflow[3], + }; + } + return { + top: overflow.top ?? 0, + right: overflow.right ?? 0, + bottom: overflow.bottom ?? 0, + left: overflow.left ?? 0, + }; +} diff --git a/packages/react-vfx/tsconfig.json b/packages/react-vfx/tsconfig.json index 37f795e..5baace3 100644 --- a/packages/react-vfx/tsconfig.json +++ b/packages/react-vfx/tsconfig.json @@ -5,7 +5,7 @@ "lib": ["es2015", "dom"], "sourceMap": true, "outDir": "lib/cjs", - "removeComments": true, + "removeComments": false, "strict": true, "noUnusedLocals": true, "noUnusedParameters": true,