diff --git a/package-lock.json b/package-lock.json index 4f7fc813..ded76994 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@recogito/text-annotator-monorepo", - "version": "3.0.0-rc.18", + "version": "3.0.0-rc.20", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@recogito/text-annotator-monorepo", - "version": "3.0.0-rc.18", + "version": "3.0.0-rc.20", "license": "BSD-3-Clause", "workspaces": [ "./packages/text-annotator", @@ -28,20 +28,19 @@ } }, "node_modules/@annotorious/annotorious": { - "version": "3.0.0-rc.21", - "resolved": "https://registry.npmjs.org/@annotorious/annotorious/-/annotorious-3.0.0-rc.21.tgz", - "integrity": "sha512-P38n6sY3++gDkIkjtcnxtpDhk08+MY49rItxjEuTAWwxw4yHwuX2k5IVeVTW4lW7E72jsHA6PrBMrUz5PExcpg==", - "peer": true, + "version": "3.0.0-rc.22", + "resolved": "https://registry.npmjs.org/@annotorious/annotorious/-/annotorious-3.0.0-rc.22.tgz", + "integrity": "sha512-vsG2f2LqtONnwQS/GfWMvK2d5o4yR317UsaPHufOMtMLsNgtRFg7xIWV0Y8Fm7KEGh7iNTQYWgb4aUGcmd5G9g==", "dependencies": { - "@annotorious/core": "^3.0.0-rc.20", + "@annotorious/core": "3.0.0-rc.22", "rbush": "^3.0.1", "uuid": "^9.0.1" } }, "node_modules/@annotorious/core": { - "version": "3.0.0-rc.21", - "resolved": "https://registry.npmjs.org/@annotorious/core/-/core-3.0.0-rc.21.tgz", - "integrity": "sha512-IAa/agVVg0JDEEgfBmHWFvCOCe5qonNlghvhY/9OY+KqtKIu8wt6SqkgvL2u1ZQce+/DpSTjc4ow7fA6Uorzag==", + "version": "3.0.0-rc.22", + "resolved": "https://registry.npmjs.org/@annotorious/core/-/core-3.0.0-rc.22.tgz", + "integrity": "sha512-lXcw12hMf7IVAuRbw1RPogfVfXp98YKOet3JB+8wr/RceNM3d1MdrLWT88MhY7EioNi99cslFaXzGJ2lLmyazw==", "dependencies": { "dequal": "^2.0.3", "nanoevents": "^9.0.0", @@ -50,13 +49,12 @@ } }, "node_modules/@annotorious/openseadragon": { - "version": "3.0.0-rc.21", - "resolved": "https://registry.npmjs.org/@annotorious/openseadragon/-/openseadragon-3.0.0-rc.21.tgz", - "integrity": "sha512-tkZFta+I+gd1dQWQ8Djf57r2qh0eUBikXBDxbPVAAMOcu1NyJkYZEUHWGf0QEFCoc1WIPfGLHPgJl4QSZp7Yog==", - "peer": true, + "version": "3.0.0-rc.22", + "resolved": "https://registry.npmjs.org/@annotorious/openseadragon/-/openseadragon-3.0.0-rc.22.tgz", + "integrity": "sha512-3ouC3K+4wyUlpsDLaxFuBFQGDV1QnsKO30S0y/Pdzk/yhkSfuMcaho9gBuaIl2YuxCb9jCG6ntt8hNLtIP+YCQ==", "dependencies": { - "@annotorious/annotorious": "^3.0.0-rc.20", - "@annotorious/core": "^3.0.0-rc.20", + "@annotorious/annotorious": "3.0.0-rc.22", + "@annotorious/core": "3.0.0-rc.22", "pixi.js": "^7.4.2", "uuid": "^9.0.1" }, @@ -65,14 +63,13 @@ } }, "node_modules/@annotorious/react": { - "version": "3.0.0-rc.21", - "resolved": "https://registry.npmjs.org/@annotorious/react/-/react-3.0.0-rc.21.tgz", - "integrity": "sha512-B8cDXJVMIhK8JyJNDCSeuK+tcmvhLqqi0CMZ4HbDr4y9UPSfBr42JaiWmoWrneCoR9BPRfmRPCw7L3yoGBHaDw==", - "peer": true, - "dependencies": { - "@annotorious/annotorious": "^3.0.0-rc.20", - "@annotorious/core": "^3.0.0-rc.20", - "@annotorious/openseadragon": "^3.0.0-rc.20", + "version": "3.0.0-rc.22", + "resolved": "https://registry.npmjs.org/@annotorious/react/-/react-3.0.0-rc.22.tgz", + "integrity": "sha512-85nwk825P2b72+ZAC6S8DSrF0wj0Lyh/SmPOirGFPMYn8fSUPkbRzr0DpK/GhuX5PekV8Gm0r2qY0Qznt3euSQ==", + "dependencies": { + "@annotorious/annotorious": "3.0.0-rc.22", + "@annotorious/core": "3.0.0-rc.22", + "@annotorious/openseadragon": "3.0.0-rc.22", "@neodrag/react": "^2.0.3" }, "peerDependencies": { @@ -138,15 +135,6 @@ "url": "https://opencollective.com/babel" } }, - "node_modules/@babel/core/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, "node_modules/@babel/generator": { "version": "7.24.1", "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.1.tgz", @@ -178,30 +166,6 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/helper-compilation-targets/node_modules/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dev": true, - "dependencies": { - "yallist": "^3.0.2" - } - }, - "node_modules/@babel/helper-compilation-targets/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@babel/helper-compilation-targets/node_modules/yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true - }, "node_modules/@babel/helper-environment-visitor": { "version": "7.22.20", "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", @@ -356,12 +320,6 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/highlight/node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, "node_modules/@babel/parser": { "version": "7.24.1", "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.1.tgz", @@ -882,43 +840,71 @@ } }, "node_modules/@microsoft/api-extractor": { - "version": "7.39.0", - "resolved": "https://registry.npmjs.org/@microsoft/api-extractor/-/api-extractor-7.39.0.tgz", - "integrity": "sha512-PuXxzadgnvp+wdeZFPonssRAj/EW4Gm4s75TXzPk09h3wJ8RS3x7typf95B4vwZRrPTQBGopdUl+/vHvlPdAcg==", + "version": "7.43.0", + "resolved": "https://registry.npmjs.org/@microsoft/api-extractor/-/api-extractor-7.43.0.tgz", + "integrity": "sha512-GFhTcJpB+MI6FhvXEI9b2K0snulNLWHqC/BbcJtyNYcKUiw7l3Lgis5ApsYncJ0leALX7/of4XfmXk+maT111w==", "dev": true, "dependencies": { - "@microsoft/api-extractor-model": "7.28.3", + "@microsoft/api-extractor-model": "7.28.13", "@microsoft/tsdoc": "0.14.2", "@microsoft/tsdoc-config": "~0.16.1", - "@rushstack/node-core-library": "3.62.0", - "@rushstack/rig-package": "0.5.1", - "@rushstack/ts-command-line": "4.17.1", - "colors": "~1.2.1", + "@rushstack/node-core-library": "4.0.2", + "@rushstack/rig-package": "0.5.2", + "@rushstack/terminal": "0.10.0", + "@rushstack/ts-command-line": "4.19.1", "lodash": "~4.17.15", + "minimatch": "~3.0.3", "resolve": "~1.22.1", "semver": "~7.5.4", "source-map": "~0.6.1", - "typescript": "5.3.3" + "typescript": "5.4.2" }, "bin": { "api-extractor": "bin/api-extractor" } }, "node_modules/@microsoft/api-extractor-model": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@microsoft/api-extractor-model/-/api-extractor-model-7.28.3.tgz", - "integrity": "sha512-wT/kB2oDbdZXITyDh2SQLzaWwTOFbV326fP0pUwNW00WeliARs0qjmXBWmGWardEzp2U3/axkO3Lboqun6vrig==", + "version": "7.28.13", + "resolved": "https://registry.npmjs.org/@microsoft/api-extractor-model/-/api-extractor-model-7.28.13.tgz", + "integrity": "sha512-39v/JyldX4MS9uzHcdfmjjfS6cYGAoXV+io8B5a338pkHiSt+gy2eXQ0Q7cGFJ7quSa1VqqlMdlPrB6sLR/cAw==", "dev": true, "dependencies": { "@microsoft/tsdoc": "0.14.2", "@microsoft/tsdoc-config": "~0.16.1", - "@rushstack/node-core-library": "3.62.0" + "@rushstack/node-core-library": "4.0.2" + } + }, + "node_modules/@microsoft/api-extractor/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@microsoft/api-extractor/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" } }, "node_modules/@microsoft/api-extractor/node_modules/typescript": { - "version": "5.3.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", - "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", + "version": "5.4.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.2.tgz", + "integrity": "sha512-+2/g0Fds1ERlP6JsakQQDXjZdZMM+rqpamFZJEKh4kwTIn3iDkgKtby0CeNd5ATNZ4Ry1ax15TMx0W2V+miizQ==", "dev": true, "bin": { "tsc": "bin/tsc", @@ -928,6 +914,12 @@ "node": ">=14.17" } }, + "node_modules/@microsoft/api-extractor/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, "node_modules/@microsoft/tsdoc": { "version": "0.14.2", "resolved": "https://registry.npmjs.org/@microsoft/tsdoc/-/tsdoc-0.14.2.tgz", @@ -968,7 +960,6 @@ "version": "7.4.2", "resolved": "https://registry.npmjs.org/@pixi/accessibility/-/accessibility-7.4.2.tgz", "integrity": "sha512-R6VEolm8uyy1FB1F2qaLKxVbzXAFTZCF2ka8fl9lsz7We6ZfO4QpXv9ur7DvzratjCQUQVCKo0/V7xL5q1EV/g==", - "peer": true, "peerDependencies": { "@pixi/core": "7.4.2", "@pixi/display": "7.4.2", @@ -979,7 +970,6 @@ "version": "7.4.2", "resolved": "https://registry.npmjs.org/@pixi/app/-/app-7.4.2.tgz", "integrity": "sha512-ugkH3kOgjT8P1mTMY29yCOgEh+KuVMAn8uBxeY0aMqaUgIMysfpnFv+Aepp2CtvI9ygr22NC+OiKl+u+eEaQHw==", - "peer": true, "peerDependencies": { "@pixi/core": "7.4.2", "@pixi/display": "7.4.2" @@ -989,7 +979,6 @@ "version": "7.4.2", "resolved": "https://registry.npmjs.org/@pixi/assets/-/assets-7.4.2.tgz", "integrity": "sha512-anxho59H9egZwoaEdM5aLvYyxoz6NCy3CaQIvNHD1bbGg8L16Ih0e26QSBR5fu53jl8OjT6M7s+p6n7uu4+fGA==", - "peer": true, "dependencies": { "@types/css-font-loading-module": "^0.0.12" }, @@ -1001,7 +990,6 @@ "version": "7.4.2", "resolved": "https://registry.npmjs.org/@pixi/color/-/color-7.4.2.tgz", "integrity": "sha512-av1LOvhHsiaW8+T4n/FgnOKHby55/w7VcA1HzPIHRBtEcsmxvSCDanT1HU2LslNhrxLPzyVx18nlmalOyt5OBg==", - "peer": true, "dependencies": { "@pixi/colord": "^2.9.6" } @@ -1009,14 +997,12 @@ "node_modules/@pixi/colord": { "version": "2.9.6", "resolved": "https://registry.npmjs.org/@pixi/colord/-/colord-2.9.6.tgz", - "integrity": "sha512-nezytU2pw587fQstUu1AsJZDVEynjskwOL+kibwcdxsMBFqPsFFNA7xl0ii/gXuDi6M0xj3mfRJj8pBSc2jCfA==", - "peer": true + "integrity": "sha512-nezytU2pw587fQstUu1AsJZDVEynjskwOL+kibwcdxsMBFqPsFFNA7xl0ii/gXuDi6M0xj3mfRJj8pBSc2jCfA==" }, "node_modules/@pixi/compressed-textures": { "version": "7.4.2", "resolved": "https://registry.npmjs.org/@pixi/compressed-textures/-/compressed-textures-7.4.2.tgz", "integrity": "sha512-VJrt7el6O4ZJSWkeOGXwrhJaiLg1UBhHB3fj42VR4YloYkAxpfd9K6s6IcbcVz7n9L48APKBMgHyaB2pX2Ck/A==", - "peer": true, "peerDependencies": { "@pixi/assets": "7.4.2", "@pixi/core": "7.4.2" @@ -1025,14 +1011,12 @@ "node_modules/@pixi/constants": { "version": "7.4.2", "resolved": "https://registry.npmjs.org/@pixi/constants/-/constants-7.4.2.tgz", - "integrity": "sha512-N9vn6Wpz5WIQg7ugUg2+SdqD2u2+NM0QthE8YzLJ4tLH2Iz+/TrnPKUJzeyIqbg3sxJG5ZpGGPiacqIBpy1KyA==", - "peer": true + "integrity": "sha512-N9vn6Wpz5WIQg7ugUg2+SdqD2u2+NM0QthE8YzLJ4tLH2Iz+/TrnPKUJzeyIqbg3sxJG5ZpGGPiacqIBpy1KyA==" }, "node_modules/@pixi/core": { "version": "7.4.2", "resolved": "https://registry.npmjs.org/@pixi/core/-/core-7.4.2.tgz", "integrity": "sha512-UbMtgSEnyCOFPzbE6ThB9qopXxbZ5GCof2ArB4FXOC5Xi/83MOIIYg5kf5M8689C5HJMhg2SrJu3xLKppF+CMg==", - "peer": true, "dependencies": { "@pixi/color": "7.4.2", "@pixi/constants": "7.4.2", @@ -1052,7 +1036,6 @@ "version": "7.4.2", "resolved": "https://registry.npmjs.org/@pixi/display/-/display-7.4.2.tgz", "integrity": "sha512-DaD0J7gIlNlzO0Fdlby/0OH+tB5LtCY6rgFeCBKVDnzmn8wKW3zYZRenWBSFJ0Psx6vLqXYkSIM/rcokaKviIw==", - "peer": true, "peerDependencies": { "@pixi/core": "7.4.2" } @@ -1061,7 +1044,6 @@ "version": "7.4.2", "resolved": "https://registry.npmjs.org/@pixi/events/-/events-7.4.2.tgz", "integrity": "sha512-Jw/w57heZjzZShIXL0bxOvKB+XgGIevyezhGtfF2ZSzQoSBWo+Fj1uE0QwKd0RIaXegZw/DhSmiMJSbNmcjifA==", - "peer": true, "peerDependencies": { "@pixi/core": "7.4.2", "@pixi/display": "7.4.2" @@ -1070,14 +1052,12 @@ "node_modules/@pixi/extensions": { "version": "7.4.2", "resolved": "https://registry.npmjs.org/@pixi/extensions/-/extensions-7.4.2.tgz", - "integrity": "sha512-Hmx2+O0yZ8XIvgomHM9GZEGcy9S9Dd8flmtOK5Aa3fXs/8v7xD08+ANQpN9ZqWU2Xs+C6UBlpqlt2BWALvKKKA==", - "peer": true + "integrity": "sha512-Hmx2+O0yZ8XIvgomHM9GZEGcy9S9Dd8flmtOK5Aa3fXs/8v7xD08+ANQpN9ZqWU2Xs+C6UBlpqlt2BWALvKKKA==" }, "node_modules/@pixi/extract": { "version": "7.4.2", "resolved": "https://registry.npmjs.org/@pixi/extract/-/extract-7.4.2.tgz", "integrity": "sha512-JOX27TRWjVEjauGBbF8PU7/g6LYXnivehdgqS5QlVDv1CNHTOrz/j3MdKcVWOhyZPbH5c9sh7lxyRxvd9AIuTQ==", - "peer": true, "peerDependencies": { "@pixi/core": "7.4.2" } @@ -1086,7 +1066,6 @@ "version": "7.4.2", "resolved": "https://registry.npmjs.org/@pixi/filter-alpha/-/filter-alpha-7.4.2.tgz", "integrity": "sha512-9OsKJ+yvY2wIcQXwswj5HQBiwNGymwmqdxfp7mo+nZSBoDmxUqvMZzE9UNJ3eUlswuNvNRO8zNOsQvwdz7WFww==", - "peer": true, "peerDependencies": { "@pixi/core": "7.4.2" } @@ -1095,7 +1074,6 @@ "version": "7.4.2", "resolved": "https://registry.npmjs.org/@pixi/filter-blur/-/filter-blur-7.4.2.tgz", "integrity": "sha512-gOXBbIUx6CRZP1fmsis2wLzzSsofrqmIHhbf1gIkZMIQaLsc9T7brj+PaLTTiOiyJgnvGN5j20RZnkERWWKV0Q==", - "peer": true, "peerDependencies": { "@pixi/core": "7.4.2" } @@ -1104,7 +1082,6 @@ "version": "7.4.2", "resolved": "https://registry.npmjs.org/@pixi/filter-color-matrix/-/filter-color-matrix-7.4.2.tgz", "integrity": "sha512-ykZiR59Gvj80UKs9qm7jeUTKvn+wWk6HBVJOmJbK9jFK5juakDWp7BbH26U78Q61EWj97kI1FdfcbMkuQ7rqkA==", - "peer": true, "peerDependencies": { "@pixi/core": "7.4.2" } @@ -1113,7 +1090,6 @@ "version": "7.4.2", "resolved": "https://registry.npmjs.org/@pixi/filter-displacement/-/filter-displacement-7.4.2.tgz", "integrity": "sha512-QS/eWp/ivsxef3xapNeGwpPX7vrqQQeo99Fux4k5zsvplnNEsf91t6QYJLG776AbZEu/qh8VYRBA5raIVY/REw==", - "peer": true, "peerDependencies": { "@pixi/core": "7.4.2" } @@ -1122,7 +1098,6 @@ "version": "7.4.2", "resolved": "https://registry.npmjs.org/@pixi/filter-fxaa/-/filter-fxaa-7.4.2.tgz", "integrity": "sha512-U/ptJgDsfs/r8y2a6gCaiPfDu2IFAxpQ4wtfmBpz6vRhqeE4kI8yNIUx5dZbui57zlsJaW0BNacOQxHU0vLkyQ==", - "peer": true, "peerDependencies": { "@pixi/core": "7.4.2" } @@ -1131,7 +1106,6 @@ "version": "7.4.2", "resolved": "https://registry.npmjs.org/@pixi/filter-noise/-/filter-noise-7.4.2.tgz", "integrity": "sha512-Vy9ViBFhZEGh6xKkd3kFWErolZTwv1Y5Qb1bV7qPIYbvBECYsqzlR4uCrrjBV6KKm0PufpG/+NKC5vICZaqKzg==", - "peer": true, "peerDependencies": { "@pixi/core": "7.4.2" } @@ -1140,7 +1114,6 @@ "version": "7.4.2", "resolved": "https://registry.npmjs.org/@pixi/graphics/-/graphics-7.4.2.tgz", "integrity": "sha512-jH4/Tum2RqWzHGzvlwEr7HIVduoLO57Ze705N2zQPkUD57TInn5911aGUeoua7f/wK8cTLGzgB9BzSo2kTdcHw==", - "peer": true, "peerDependencies": { "@pixi/core": "7.4.2", "@pixi/display": "7.4.2", @@ -1150,14 +1123,12 @@ "node_modules/@pixi/math": { "version": "7.4.2", "resolved": "https://registry.npmjs.org/@pixi/math/-/math-7.4.2.tgz", - "integrity": "sha512-7jHmCQoYk6e0rfSKjdNFOPl0wCcdgoraxgteXJTTHv3r0bMNx2pHD9FJ0VvocEUG7XHfj55O3+u7yItOAx0JaQ==", - "peer": true + "integrity": "sha512-7jHmCQoYk6e0rfSKjdNFOPl0wCcdgoraxgteXJTTHv3r0bMNx2pHD9FJ0VvocEUG7XHfj55O3+u7yItOAx0JaQ==" }, "node_modules/@pixi/mesh": { "version": "7.4.2", "resolved": "https://registry.npmjs.org/@pixi/mesh/-/mesh-7.4.2.tgz", "integrity": "sha512-mEkKyQvvMrYXC3pahvH5WBIKtrtB63WixRr91ANFI7zXD+ESG6Ap6XtxMCJmXDQPwBDNk7SWVMiCflYuchG7kA==", - "peer": true, "peerDependencies": { "@pixi/core": "7.4.2", "@pixi/display": "7.4.2" @@ -1167,7 +1138,6 @@ "version": "7.4.2", "resolved": "https://registry.npmjs.org/@pixi/mesh-extras/-/mesh-extras-7.4.2.tgz", "integrity": "sha512-vNR/7wjxjs7sv9fGoKkHyU91ZAD+7EnMHBS5F3CVISlOIFxLi96NNZCB81oUIdky/90pHw40johd/4izR5zTyw==", - "peer": true, "peerDependencies": { "@pixi/core": "7.4.2", "@pixi/mesh": "7.4.2" @@ -1177,7 +1147,6 @@ "version": "7.4.2", "resolved": "https://registry.npmjs.org/@pixi/mixin-cache-as-bitmap/-/mixin-cache-as-bitmap-7.4.2.tgz", "integrity": "sha512-6dgthi2ruUT/lervSrFDQ7vXkEsHo6CxdgV7W/wNdW1dqgQlKfDvO6FhjXzyIMRLSooUf5FoeluVtfsjkUIYrw==", - "peer": true, "peerDependencies": { "@pixi/core": "7.4.2", "@pixi/display": "7.4.2", @@ -1188,7 +1157,6 @@ "version": "7.4.2", "resolved": "https://registry.npmjs.org/@pixi/mixin-get-child-by-name/-/mixin-get-child-by-name-7.4.2.tgz", "integrity": "sha512-0Cfw8JpQhsixprxiYph4Lj+B5n83Kk4ftNMXgM5xtZz+tVLz5s91qR0MqcdzwTGTJ7utVygiGmS4/3EfR/duRQ==", - "peer": true, "peerDependencies": { "@pixi/display": "7.4.2" } @@ -1197,7 +1165,6 @@ "version": "7.4.2", "resolved": "https://registry.npmjs.org/@pixi/mixin-get-global-position/-/mixin-get-global-position-7.4.2.tgz", "integrity": "sha512-LcsahbVdX4DFS2IcGfNp4KaXuu7SjAwUp/flZSGIfstyKOKb5FWFgihtqcc9ZT4coyri3gs2JbILZub/zPZj1w==", - "peer": true, "peerDependencies": { "@pixi/core": "7.4.2", "@pixi/display": "7.4.2" @@ -1207,7 +1174,6 @@ "version": "7.4.2", "resolved": "https://registry.npmjs.org/@pixi/particle-container/-/particle-container-7.4.2.tgz", "integrity": "sha512-B78Qq86kt0lEa5WtB2YFIm3+PjhKfw9La9R++GBSgABl+g13s2UaZ6BIPxvY3JxWMdxPm4iPrQPFX1QWRN68mw==", - "peer": true, "peerDependencies": { "@pixi/core": "7.4.2", "@pixi/display": "7.4.2", @@ -1218,7 +1184,6 @@ "version": "7.4.2", "resolved": "https://registry.npmjs.org/@pixi/prepare/-/prepare-7.4.2.tgz", "integrity": "sha512-PugyMzReCHXUzc3so9PPJj2OdHwibpUNWyqG4mWY2UUkb6c8NAGK1AnAPiscOvLilJcv/XQSFoNhX+N1jrvJEg==", - "peer": true, "peerDependencies": { "@pixi/core": "7.4.2", "@pixi/display": "7.4.2", @@ -1229,14 +1194,12 @@ "node_modules/@pixi/runner": { "version": "7.4.2", "resolved": "https://registry.npmjs.org/@pixi/runner/-/runner-7.4.2.tgz", - "integrity": "sha512-LPBpwym4vdyyDY5ucF4INQccaGyxztERyLTY1YN6aqJyyMmnc7iqXlIKt+a0euMBtNoLoxy6MWMvIuZj0JfFPA==", - "peer": true + "integrity": "sha512-LPBpwym4vdyyDY5ucF4INQccaGyxztERyLTY1YN6aqJyyMmnc7iqXlIKt+a0euMBtNoLoxy6MWMvIuZj0JfFPA==" }, "node_modules/@pixi/settings": { "version": "7.4.2", "resolved": "https://registry.npmjs.org/@pixi/settings/-/settings-7.4.2.tgz", "integrity": "sha512-pMN+L6aWgvUbwhFIL/BTHKe2ShYGPZ8h9wlVBnFHMtUcJcFLMF1B3lzuvCayZRepOphs6RY0TqvnDvVb585JhQ==", - "peer": true, "dependencies": { "@pixi/constants": "7.4.2", "@types/css-font-loading-module": "^0.0.12", @@ -1247,7 +1210,6 @@ "version": "7.4.2", "resolved": "https://registry.npmjs.org/@pixi/sprite/-/sprite-7.4.2.tgz", "integrity": "sha512-Ccf/OVQsB+HQV0Fyf5lwD+jk1jeU7uSIqEjbxenNNssmEdB7S5qlkTBV2EJTHT83+T6Z9OMOHsreJZerydpjeg==", - "peer": true, "peerDependencies": { "@pixi/core": "7.4.2", "@pixi/display": "7.4.2" @@ -1257,7 +1219,6 @@ "version": "7.4.2", "resolved": "https://registry.npmjs.org/@pixi/sprite-animated/-/sprite-animated-7.4.2.tgz", "integrity": "sha512-QPT6yxCUGOBN+98H3pyIZ1ZO6Y7BN1o0Q2IMZEsD1rNfZJrTYS3Q8VlCG5t2YlFlcB8j5iBo24bZb6FUxLOmsQ==", - "peer": true, "peerDependencies": { "@pixi/core": "7.4.2", "@pixi/sprite": "7.4.2" @@ -1267,7 +1228,6 @@ "version": "7.4.2", "resolved": "https://registry.npmjs.org/@pixi/sprite-tiling/-/sprite-tiling-7.4.2.tgz", "integrity": "sha512-Z8PP6ewy3nuDYL+NeEdltHAhuucVgia33uzAitvH3OqqRSx6a6YRBFbNLUM9Sx+fBO2Lk3PpV1g6QZX+NE5LOg==", - "peer": true, "peerDependencies": { "@pixi/core": "7.4.2", "@pixi/display": "7.4.2", @@ -1278,7 +1238,6 @@ "version": "7.4.2", "resolved": "https://registry.npmjs.org/@pixi/spritesheet/-/spritesheet-7.4.2.tgz", "integrity": "sha512-YIvHdpXW+AYp8vD0NkjJmrdnVHTZKidCnx6k8ATSuuvCT6O5Tuh2N/Ul2oDj4/QaePy0lVhyhAbZpJW00Jr7mQ==", - "peer": true, "peerDependencies": { "@pixi/assets": "7.4.2", "@pixi/core": "7.4.2" @@ -1288,7 +1247,6 @@ "version": "7.4.2", "resolved": "https://registry.npmjs.org/@pixi/text/-/text-7.4.2.tgz", "integrity": "sha512-rZZWpJNsIQ8WoCWrcVg8Gi6L/PDakB941clo6dO3XjoII2ucoOUcnpe5HIkudxi2xPvS/8Bfq990gFEx50TP5A==", - "peer": true, "peerDependencies": { "@pixi/core": "7.4.2", "@pixi/sprite": "7.4.2" @@ -1298,7 +1256,6 @@ "version": "7.4.2", "resolved": "https://registry.npmjs.org/@pixi/text-bitmap/-/text-bitmap-7.4.2.tgz", "integrity": "sha512-lPBMJ83JnpFVL+6ckQ8KO8QmwdPm0z9Zs/M0NgFKH2F+BcjelRNnk80NI3O0qBDYSEDQIE+cFbKoZ213kf7zwA==", - "peer": true, "peerDependencies": { "@pixi/assets": "7.4.2", "@pixi/core": "7.4.2", @@ -1311,7 +1268,6 @@ "version": "7.4.2", "resolved": "https://registry.npmjs.org/@pixi/text-html/-/text-html-7.4.2.tgz", "integrity": "sha512-duOu8oDYeDNuyPozj2DAsQ5VZBbRiwIXy78Gn7H2pCiEAefw/Uv5jJYwdgneKME0e1tOxz1eOUGKPcI6IJnZjw==", - "peer": true, "peerDependencies": { "@pixi/core": "7.4.2", "@pixi/display": "7.4.2", @@ -1323,7 +1279,6 @@ "version": "7.4.2", "resolved": "https://registry.npmjs.org/@pixi/ticker/-/ticker-7.4.2.tgz", "integrity": "sha512-cAvxCh/KI6IW4m3tp2b+GQIf+DoSj9NNmPJmsOeEJ7LzvruG8Ps7SKI6CdjQob5WbceL1apBTDbqZ/f77hFDiQ==", - "peer": true, "dependencies": { "@pixi/extensions": "7.4.2", "@pixi/settings": "7.4.2", @@ -1334,7 +1289,6 @@ "version": "7.4.2", "resolved": "https://registry.npmjs.org/@pixi/utils/-/utils-7.4.2.tgz", "integrity": "sha512-aU/itcyMC4TxFbmdngmak6ey4kC5c16Y5ntIYob9QnjNAfD/7GTsYIBnP6FqEAyO1eq0MjkAALxdONuay1BG3g==", - "peer": true, "dependencies": { "@pixi/color": "7.4.2", "@pixi/constants": "7.4.2", @@ -1386,9 +1340,9 @@ "dev": true }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.13.0.tgz", - "integrity": "sha512-5ZYPOuaAqEH/W3gYsRkxQATBW3Ii1MfaT4EQstTnLKViLi2gLSQmlmtTpGucNP3sXEpOiI5tdGhjdE111ekyEg==", + "version": "4.13.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.13.2.tgz", + "integrity": "sha512-3XFIDKWMFZrMnao1mJhnOT1h2g0169Os848NhhmGweEcfJ4rCi+3yMCOLG4zA61rbJdkcrM/DjVZm9Hg5p5w7g==", "cpu": [ "arm" ], @@ -1399,9 +1353,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.13.0.tgz", - "integrity": "sha512-BSbaCmn8ZadK3UAQdlauSvtaJjhlDEjS5hEVVIN3A4bbl3X+otyf/kOJV08bYiRxfejP3DXFzO2jz3G20107+Q==", + "version": "4.13.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.13.2.tgz", + "integrity": "sha512-GdxxXbAuM7Y/YQM9/TwwP+L0omeE/lJAR1J+olu36c3LqqZEBdsIWeQ91KBe6nxwOnb06Xh7JS2U5ooWU5/LgQ==", "cpu": [ "arm64" ], @@ -1412,9 +1366,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.13.0.tgz", - "integrity": "sha512-Ovf2evVaP6sW5Ut0GHyUSOqA6tVKfrTHddtmxGQc1CTQa1Cw3/KMCDEEICZBbyppcwnhMwcDce9ZRxdWRpVd6g==", + "version": "4.13.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.13.2.tgz", + "integrity": "sha512-mCMlpzlBgOTdaFs83I4XRr8wNPveJiJX1RLfv4hggyIVhfB5mJfN4P8Z6yKh+oE4Luz+qq1P3kVdWrCKcMYrrA==", "cpu": [ "arm64" ], @@ -1425,9 +1379,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.13.0.tgz", - "integrity": "sha512-U+Jcxm89UTK592vZ2J9st9ajRv/hrwHdnvyuJpa5A2ngGSVHypigidkQJP+YiGL6JODiUeMzkqQzbCG3At81Gg==", + "version": "4.13.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.13.2.tgz", + "integrity": "sha512-yUoEvnH0FBef/NbB1u6d3HNGyruAKnN74LrPAfDQL3O32e3k3OSfLrPgSJmgb3PJrBZWfPyt6m4ZhAFa2nZp2A==", "cpu": [ "x64" ], @@ -1438,9 +1392,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.13.0.tgz", - "integrity": "sha512-8wZidaUJUTIR5T4vRS22VkSMOVooG0F4N+JSwQXWSRiC6yfEsFMLTYRFHvby5mFFuExHa/yAp9juSphQQJAijQ==", + "version": "4.13.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.13.2.tgz", + "integrity": "sha512-GYbLs5ErswU/Xs7aGXqzc3RrdEjKdmoCrgzhJWyFL0r5fL3qd1NPcDKDowDnmcoSiGJeU68/Vy+OMUluRxPiLQ==", "cpu": [ "arm" ], @@ -1451,9 +1405,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.13.0.tgz", - "integrity": "sha512-Iu0Kno1vrD7zHQDxOmvweqLkAzjxEVqNhUIXBsZ8hu8Oak7/5VTPrxOEZXYC1nmrBVJp0ZcL2E7lSuuOVaE3+w==", + "version": "4.13.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.13.2.tgz", + "integrity": "sha512-L1+D8/wqGnKQIlh4Zre9i4R4b4noxzH5DDciyahX4oOz62CphY7WDWqJoQ66zNR4oScLNOqQJfNSIAe/6TPUmQ==", "cpu": [ "arm64" ], @@ -1464,9 +1418,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.13.0.tgz", - "integrity": "sha512-C31QrW47llgVyrRjIwiOwsHFcaIwmkKi3PCroQY5aVq4H0A5v/vVVAtFsI1nfBngtoRpeREvZOkIhmRwUKkAdw==", + "version": "4.13.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.13.2.tgz", + "integrity": "sha512-tK5eoKFkXdz6vjfkSTCupUzCo40xueTOiOO6PeEIadlNBkadH1wNOH8ILCPIl8by/Gmb5AGAeQOFeLev7iZDOA==", "cpu": [ "arm64" ], @@ -1476,10 +1430,23 @@ "linux" ] }, + "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { + "version": "4.13.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.13.2.tgz", + "integrity": "sha512-zvXvAUGGEYi6tYhcDmb9wlOckVbuD+7z3mzInCSTACJ4DQrdSLPNUeDIcAQW39M3q6PDquqLWu7pnO39uSMRzQ==", + "cpu": [ + "ppc64le" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.13.0.tgz", - "integrity": "sha512-Oq90dtMHvthFOPMl7pt7KmxzX7E71AfyIhh+cPhLY9oko97Zf2C9tt/XJD4RgxhaGeAraAXDtqxvKE1y/j35lA==", + "version": "4.13.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.13.2.tgz", + "integrity": "sha512-C3GSKvMtdudHCN5HdmAMSRYR2kkhgdOfye4w0xzyii7lebVr4riCgmM6lRiSCnJn2w1Xz7ZZzHKuLrjx5620kw==", "cpu": [ "riscv64" ], @@ -1489,10 +1456,23 @@ "linux" ] }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.13.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.13.2.tgz", + "integrity": "sha512-l4U0KDFwzD36j7HdfJ5/TveEQ1fUTjFFQP5qIt9gBqBgu1G8/kCaq5Ok05kd5TG9F8Lltf3MoYsUMw3rNlJ0Yg==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.13.0.tgz", - "integrity": "sha512-yUD/8wMffnTKuiIsl6xU+4IA8UNhQ/f1sAnQebmE/lyQ8abjsVyDkyRkWop0kdMhKMprpNIhPmYlCxgHrPoXoA==", + "version": "4.13.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.13.2.tgz", + "integrity": "sha512-xXMLUAMzrtsvh3cZ448vbXqlUa7ZL8z0MwHp63K2IIID2+DeP5iWIT6g1SN7hg1VxPzqx0xZdiDM9l4n9LRU1A==", "cpu": [ "x64" ], @@ -1503,9 +1483,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.13.0.tgz", - "integrity": "sha512-9RyNqoFNdF0vu/qqX63fKotBh43fJQeYC98hCaf89DYQpv+xu0D8QFSOS0biA7cGuqJFOc1bJ+m2rhhsKcw1hw==", + "version": "4.13.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.13.2.tgz", + "integrity": "sha512-M/JYAWickafUijWPai4ehrjzVPKRCyDb1SLuO+ZyPfoXgeCEAlgPkNXewFZx0zcnoIe3ay4UjXIMdXQXOZXWqA==", "cpu": [ "x64" ], @@ -1516,9 +1496,9 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.13.0.tgz", - "integrity": "sha512-46ue8ymtm/5PUU6pCvjlic0z82qWkxv54GTJZgHrQUuZnVH+tvvSP0LsozIDsCBFO4VjJ13N68wqrKSeScUKdA==", + "version": "4.13.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.13.2.tgz", + "integrity": "sha512-2YWwoVg9KRkIKaXSh0mz3NmfurpmYoBBTAXA9qt7VXk0Xy12PoOP40EFuau+ajgALbbhi4uTj3tSG3tVseCjuA==", "cpu": [ "arm64" ], @@ -1529,9 +1509,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.13.0.tgz", - "integrity": "sha512-P5/MqLdLSlqxbeuJ3YDeX37srC8mCflSyTrUsgbU1c/U9j6l2g2GiIdYaGD9QjdMQPMSgYm7hgg0551wHyIluw==", + "version": "4.13.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.13.2.tgz", + "integrity": "sha512-2FSsE9aQ6OWD20E498NYKEQLneShWes0NGMPQwxWOdws35qQXH+FplabOSP5zEe1pVjurSDOGEVCE2agFwSEsw==", "cpu": [ "ia32" ], @@ -1542,9 +1522,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.13.0.tgz", - "integrity": "sha512-UKXUQNbO3DOhzLRwHSpa0HnhhCgNODvfoPWv2FCXme8N/ANFfhIPMGuOT+QuKd16+B5yxZ0HdpNlqPvTMS1qfw==", + "version": "4.13.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.13.2.tgz", + "integrity": "sha512-7h7J2nokcdPePdKykd8wtc8QqqkqxIrUz7MHj6aNr8waBRU//NLDVnNjQnqQO6fqtjrtCdftpbTuOKAyrAQETQ==", "cpu": [ "x64" ], @@ -1555,12 +1535,11 @@ ] }, "node_modules/@rushstack/node-core-library": { - "version": "3.62.0", - "resolved": "https://registry.npmjs.org/@rushstack/node-core-library/-/node-core-library-3.62.0.tgz", - "integrity": "sha512-88aJn2h8UpSvdwuDXBv1/v1heM6GnBf3RjEy6ZPP7UnzHNCqOHA2Ut+ScYUbXcqIdfew9JlTAe3g+cnX9xQ/Aw==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@rushstack/node-core-library/-/node-core-library-4.0.2.tgz", + "integrity": "sha512-hyES82QVpkfQMeBMteQUnrhASL/KHPhd7iJ8euduwNJG4mu2GSOKybf0rOEjOm1Wz7CwJEUm9y0yD7jg2C1bfg==", "dev": true, "dependencies": { - "colors": "~1.2.1", "fs-extra": "~7.0.1", "import-lazy": "~4.0.0", "jju": "~1.4.0", @@ -1577,25 +1556,100 @@ } } }, + "node_modules/@rushstack/node-core-library/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@rushstack/node-core-library/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@rushstack/node-core-library/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, "node_modules/@rushstack/rig-package": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/@rushstack/rig-package/-/rig-package-0.5.1.tgz", - "integrity": "sha512-pXRYSe29TjRw7rqxD4WS3HN/sRSbfr+tJs4a9uuaSIBAITbUggygdhuG0VrO0EO+QqH91GhYMN4S6KRtOEmGVA==", + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/@rushstack/rig-package/-/rig-package-0.5.2.tgz", + "integrity": "sha512-mUDecIJeH3yYGZs2a48k+pbhM6JYwWlgjs2Ca5f2n1G2/kgdgP9D/07oglEGf6mRyXEnazhEENeYTSNDRCwdqA==", "dev": true, "dependencies": { "resolve": "~1.22.1", "strip-json-comments": "~3.1.1" } }, + "node_modules/@rushstack/terminal": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/@rushstack/terminal/-/terminal-0.10.0.tgz", + "integrity": "sha512-UbELbXnUdc7EKwfH2sb8ChqNgapUOdqcCIdQP4NGxBpTZV2sQyeekuK3zmfQSa/MN+/7b4kBogl2wq0vpkpYGw==", + "dev": true, + "dependencies": { + "@rushstack/node-core-library": "4.0.2", + "supports-color": "~8.1.1" + }, + "peerDependencies": { + "@types/node": "*" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@rushstack/terminal/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@rushstack/terminal/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, "node_modules/@rushstack/ts-command-line": { - "version": "4.17.1", - "resolved": "https://registry.npmjs.org/@rushstack/ts-command-line/-/ts-command-line-4.17.1.tgz", - "integrity": "sha512-2jweO1O57BYP5qdBGl6apJLB+aRIn5ccIRTPDyULh0KMwVzFqWtw6IZWt1qtUoZD/pD2RNkIOosH6Cq45rIYeg==", + "version": "4.19.1", + "resolved": "https://registry.npmjs.org/@rushstack/ts-command-line/-/ts-command-line-4.19.1.tgz", + "integrity": "sha512-J7H768dgcpG60d7skZ5uSSwyCZs/S2HrWP1Ds8d1qYAyaaeJmpmmLr9BVw97RjFzmQPOYnoXcKA4GkqDCkduQg==", "dev": true, "dependencies": { + "@rushstack/terminal": "0.10.0", "@types/argparse": "1.0.38", "argparse": "~1.0.9", - "colors": "~1.2.1", "string-argv": "~0.3.1" } }, @@ -1655,14 +1709,12 @@ "node_modules/@types/css-font-loading-module": { "version": "0.0.12", "resolved": "https://registry.npmjs.org/@types/css-font-loading-module/-/css-font-loading-module-0.0.12.tgz", - "integrity": "sha512-x2tZZYkSxXqWvTDgveSynfjq/T2HyiZHXb00j/+gy19yp70PHCizM48XFdjBCWH7eHBD0R5i/pw9yMBP/BH5uA==", - "peer": true + "integrity": "sha512-x2tZZYkSxXqWvTDgveSynfjq/T2HyiZHXb00j/+gy19yp70PHCizM48XFdjBCWH7eHBD0R5i/pw9yMBP/BH5uA==" }, "node_modules/@types/earcut": { "version": "2.1.4", "resolved": "https://registry.npmjs.org/@types/earcut/-/earcut-2.1.4.tgz", - "integrity": "sha512-qp3m9PPz4gULB9MhjGID7wpo3gJ4bTGXm7ltNDsmOvsPduTeHp8wSW9YckBj3mljeOh4F0m2z/0JKAALRKbmLQ==", - "peer": true + "integrity": "sha512-qp3m9PPz4gULB9MhjGID7wpo3gJ4bTGXm7ltNDsmOvsPduTeHp8wSW9YckBj3mljeOh4F0m2z/0JKAALRKbmLQ==" }, "node_modules/@types/estree": { "version": "1.0.5", @@ -1703,31 +1755,24 @@ "dev": true }, "node_modules/@types/react": { - "version": "18.2.71", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.71.tgz", - "integrity": "sha512-PxEsB9OjmQeYGffoWnYAd/r5FiJuUw2niFQHPc2v2idwh8wGPkkYzOHuinNJJY6NZqfoTCiOIizDOz38gYNsyw==", + "version": "18.2.73", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.73.tgz", + "integrity": "sha512-XcGdod0Jjv84HOC7N5ziY3x+qL0AfmubvKOZ9hJjJ2yd5EE+KYjWhdOjt387e9HPheHkdggF9atTifMRtyAaRA==", "dev": true, "dependencies": { "@types/prop-types": "*", - "@types/scheduler": "*", "csstype": "^3.0.2" } }, "node_modules/@types/react-dom": { - "version": "18.2.22", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.22.tgz", - "integrity": "sha512-fHkBXPeNtfvri6gdsMYyW+dW7RXFo6Ad09nLFK0VQWR7yGLai/Cyvyj696gbwYvBnhGtevUG9cET0pmUbMtoPQ==", + "version": "18.2.23", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.23.tgz", + "integrity": "sha512-ZQ71wgGOTmDYpnav2knkjr3qXdAFu0vsk8Ci5w3pGAIdj7/kKAyn+VsQDhXsmzzzepAiI9leWMmubXz690AI/A==", "dev": true, "dependencies": { "@types/react": "*" } }, - "node_modules/@types/scheduler": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.23.0.tgz", - "integrity": "sha512-YIoDCTH3Af6XM5VuwGG/QL/CJqga1Zm3NkU3HZ4ZHK2fRMPYP1VczsTUqtsf43PH/iJNVlPHAo2oWX7BSdB2Hw==", - "dev": true - }, "node_modules/@types/tough-cookie": { "version": "4.0.5", "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.5.tgz", @@ -1910,6 +1955,30 @@ } } }, + "node_modules/@vue/language-core/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@vue/language-core/node_modules/minimatch": { + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", + "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/@vue/shared": { "version": "3.4.21", "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.4.21.tgz", @@ -1966,15 +2035,15 @@ } }, "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==", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "dev": true, - "engines": { - "node": ">=10" + "dependencies": { + "color-convert": "^1.9.0" }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "engines": { + "node": ">=4" } }, "node_modules/argparse": { @@ -2026,12 +2095,13 @@ "dev": true }, "node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, "dependencies": { - "balanced-match": "^1.0.0" + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, "node_modules/browserslist": { @@ -2079,7 +2149,6 @@ "version": "1.0.7", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", - "peer": true, "dependencies": { "es-define-property": "^1.0.0", "es-errors": "^1.3.0", @@ -2151,18 +2220,6 @@ "node": ">=4" } }, - "node_modules/chalk/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/check-error": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz", @@ -2208,15 +2265,6 @@ "resolved": "https://registry.npmjs.org/colord/-/colord-2.9.3.tgz", "integrity": "sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==" }, - "node_modules/colors": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.2.5.tgz", - "integrity": "sha512-erNRLao/Y3Fv54qUa0LBB+//Uf3YwMUmdJinN20yMXm9zdKKqH9wt7R9IIVZ+K7ShzfpLV/Zg8+VyrBJYB4lpg==", - "dev": true, - "engines": { - "node": ">=0.1.90" - } - }, "node_modules/combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", @@ -2245,6 +2293,12 @@ "integrity": "sha512-7CEBgcMjVmitjYo5q8JTJVra6X5mQ20uTThdK+0kR7UEaDrAWEQcRiBtWJzga4eRpP6afNwwLsX2SET2JhVB1Q==", "dev": true }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "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", @@ -2354,7 +2408,6 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", - "peer": true, "dependencies": { "es-define-property": "^1.0.0", "es-errors": "^1.3.0", @@ -2396,13 +2449,12 @@ "node_modules/earcut": { "version": "2.2.4", "resolved": "https://registry.npmjs.org/earcut/-/earcut-2.2.4.tgz", - "integrity": "sha512-/pjZsA1b4RPHbeWZQn66SWS8nZZWLQQ23oE3Eam7aroEFGEvwKAsJfZ9ytiEMycfzXWpca4FA9QIOehf7PocBQ==", - "peer": true + "integrity": "sha512-/pjZsA1b4RPHbeWZQn66SWS8nZZWLQQ23oE3Eam7aroEFGEvwKAsJfZ9ytiEMycfzXWpca4FA9QIOehf7PocBQ==" }, "node_modules/electron-to-chromium": { - "version": "1.4.717", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.717.tgz", - "integrity": "sha512-6Fmg8QkkumNOwuZ/5mIbMU9WI3H2fmn5ajcVya64I5Yr5CcNmO7vcLt0Y7c96DCiMO5/9G+4sI2r6eEvdg1F7A==", + "version": "1.4.721", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.721.tgz", + "integrity": "sha512-k1x2r6foI8iJOp+1qTxbbrrWMsOiHkzGBYwYigaq+apO1FSqtn44KTo3Sy69qt7CRr7149zTcsDvH7MUKsOuIQ==", "dev": true }, "node_modules/entities": { @@ -2421,7 +2473,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", - "peer": true, "dependencies": { "get-intrinsic": "^1.2.4" }, @@ -2433,7 +2484,6 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", - "peer": true, "engines": { "node": ">= 0.4" } @@ -2506,8 +2556,7 @@ "node_modules/eventemitter3": { "version": "4.0.7", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", - "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", - "peer": true + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==" }, "node_modules/execa": { "version": "8.0.1", @@ -2625,7 +2674,6 @@ "version": "1.2.4", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", - "peer": true, "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2", @@ -2671,7 +2719,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", - "peer": true, "dependencies": { "get-intrinsic": "^1.1.3" }, @@ -2698,7 +2745,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", - "peer": true, "dependencies": { "es-define-property": "^1.0.0" }, @@ -2710,7 +2756,6 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", - "peer": true, "engines": { "node": ">= 0.4" }, @@ -2722,7 +2767,6 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", - "peer": true, "engines": { "node": ">= 0.4" }, @@ -2866,8 +2910,7 @@ "node_modules/ismobilejs": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ismobilejs/-/ismobilejs-1.1.1.tgz", - "integrity": "sha512-VaFW53yt8QO61k2WJui0dHf4SlL8lxBofUuUmwBo0ljPk0Drz2TiuDW4jo3wDcv41qy/SxrJ+VAzJ/qYqsmzRw==", - "peer": true + "integrity": "sha512-VaFW53yt8QO61k2WJui0dHf4SlL8lxBofUuUmwBo0ljPk0Drz2TiuDW4jo3wDcv41qy/SxrJ+VAzJ/qYqsmzRw==" }, "node_modules/jju": { "version": "1.4.0", @@ -2876,10 +2919,9 @@ "dev": true }, "node_modules/js-tokens": { - "version": "8.0.3", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-8.0.3.tgz", - "integrity": "sha512-UfJMcSJc+SEXEl9lH/VLHSZbThQyLpw1vLO1Lb+j4RWDvG3N2f7yj3PVQA3cmkTBNldJ9eFnM+xEXxHIXrYiJw==", - "dev": true + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" }, "node_modules/jsdom": { "version": "24.0.0", @@ -3023,11 +3065,6 @@ "loose-envify": "cli.js" } }, - "node_modules/loose-envify/node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" - }, "node_modules/loupe": { "version": "2.3.7", "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz", @@ -3038,15 +3075,12 @@ } }, "node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", "dev": true, "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" + "yallist": "^3.0.2" } }, "node_modules/magic-string": { @@ -3107,18 +3141,15 @@ } }, "node_modules/minimatch": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", - "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.8.tgz", + "integrity": "sha512-6FsRAQsxQ61mw+qP1ZzbL9Bc78x2p5OqNgNpnoAFLTrX8n5Kxph0CsnhmKKNXTWjXqU5L0pGPR7hYk+XWZr60Q==", "dev": true, "dependencies": { - "brace-expansion": "^2.0.1" + "brace-expansion": "^1.1.7" }, "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "node": "*" } }, "node_modules/mlly": { @@ -3213,7 +3244,6 @@ "version": "1.13.1", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", - "peer": true, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -3337,7 +3367,6 @@ "version": "7.4.2", "resolved": "https://registry.npmjs.org/pixi.js/-/pixi.js-7.4.2.tgz", "integrity": "sha512-TifqgHGNofO7UCEbdZJOpUu7dUnpu4YZ0o76kfCqxDa4RS8ITc9zjECCbtalmuNXkVhSEZmBKQvE7qhHMqw/xg==", - "peer": true, "dependencies": { "@pixi/accessibility": "7.4.2", "@pixi/app": "7.4.2", @@ -3446,6 +3475,18 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "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": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, "node_modules/psl": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", @@ -3465,7 +3506,6 @@ "version": "6.12.0", "resolved": "https://registry.npmjs.org/qs/-/qs-6.12.0.tgz", "integrity": "sha512-trVZiI6RMOkO476zLGaBIzszOdFPnCCXHPG9kn0yuS1uz6xdVxPfZdB3vUig9pxPFDM9BRAgz/YUIVQ1/vuiUg==", - "peer": true, "dependencies": { "side-channel": "^1.0.6" }, @@ -3557,9 +3597,9 @@ } }, "node_modules/rollup": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.13.0.tgz", - "integrity": "sha512-3YegKemjoQnYKmsBlOHfMLVPPA5xLkQ8MHLLSw/fBrFaVkEayL51DilPpNNLq1exr98F2B1TzrV0FUlN3gWRPg==", + "version": "4.13.2", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.13.2.tgz", + "integrity": "sha512-MIlLgsdMprDBXC+4hsPgzWUasLO9CE4zOkj/u6j+Z6j5A4zRY+CtiXAdJyPtgCsc42g658Aeh1DlrdVEJhsL2g==", "dev": true, "dependencies": { "@types/estree": "1.0.5" @@ -3572,19 +3612,21 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.13.0", - "@rollup/rollup-android-arm64": "4.13.0", - "@rollup/rollup-darwin-arm64": "4.13.0", - "@rollup/rollup-darwin-x64": "4.13.0", - "@rollup/rollup-linux-arm-gnueabihf": "4.13.0", - "@rollup/rollup-linux-arm64-gnu": "4.13.0", - "@rollup/rollup-linux-arm64-musl": "4.13.0", - "@rollup/rollup-linux-riscv64-gnu": "4.13.0", - "@rollup/rollup-linux-x64-gnu": "4.13.0", - "@rollup/rollup-linux-x64-musl": "4.13.0", - "@rollup/rollup-win32-arm64-msvc": "4.13.0", - "@rollup/rollup-win32-ia32-msvc": "4.13.0", - "@rollup/rollup-win32-x64-msvc": "4.13.0", + "@rollup/rollup-android-arm-eabi": "4.13.2", + "@rollup/rollup-android-arm64": "4.13.2", + "@rollup/rollup-darwin-arm64": "4.13.2", + "@rollup/rollup-darwin-x64": "4.13.2", + "@rollup/rollup-linux-arm-gnueabihf": "4.13.2", + "@rollup/rollup-linux-arm64-gnu": "4.13.2", + "@rollup/rollup-linux-arm64-musl": "4.13.2", + "@rollup/rollup-linux-powerpc64le-gnu": "4.13.2", + "@rollup/rollup-linux-riscv64-gnu": "4.13.2", + "@rollup/rollup-linux-s390x-gnu": "4.13.2", + "@rollup/rollup-linux-x64-gnu": "4.13.2", + "@rollup/rollup-linux-x64-musl": "4.13.2", + "@rollup/rollup-win32-arm64-msvc": "4.13.2", + "@rollup/rollup-win32-ia32-msvc": "4.13.2", + "@rollup/rollup-win32-x64-msvc": "4.13.2", "fsevents": "~2.3.2" } }, @@ -3621,25 +3663,18 @@ } }, "node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, "bin": { "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" } }, "node_modules/set-function-length": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", - "peer": true, "dependencies": { "define-data-property": "^1.1.4", "es-errors": "^1.3.0", @@ -3677,7 +3712,6 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", - "peer": true, "dependencies": { "call-bind": "^1.0.7", "es-errors": "^1.3.0", @@ -3779,17 +3813,23 @@ } }, "node_modules/strip-literal": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-2.0.0.tgz", - "integrity": "sha512-f9vHgsCWBq2ugHAkGMiiYY+AYG0D/cbloKKg0nhaaaSNsujdGIpVXCNsrJpCKr5M0f4aI31mr13UjY6GAuXCKA==", + "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": "^8.0.2" + "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", @@ -4011,7 +4051,6 @@ "version": "0.11.3", "resolved": "https://registry.npmjs.org/url/-/url-0.11.3.tgz", "integrity": "sha512-6hxOLGfZASQK/cijlZnZJTq8OXAkt/3YGfQX45vvMYXpZoo8NdWZcY73K108Jf759lS1Bv/8wXnHDTSz17dSRw==", - "peer": true, "dependencies": { "punycode": "^1.4.1", "qs": "^6.11.2" @@ -4030,8 +4069,7 @@ "node_modules/url/node_modules/punycode": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==", - "peer": true + "integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==" }, "node_modules/uuid": { "version": "9.0.1", @@ -4055,13 +4093,13 @@ } }, "node_modules/vite": { - "version": "5.2.6", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.2.6.tgz", - "integrity": "sha512-FPtnxFlSIKYjZ2eosBQamz4CbyrTizbZ3hnGJlh/wMtCrlp1Hah6AzBLjGI5I2urTfNnpovpHdrL6YRuBOPnCA==", + "version": "5.2.7", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.2.7.tgz", + "integrity": "sha512-k14PWOKLI6pMaSzAuGtT+Cf0YmIx12z9YGon39onaJNy8DLBfBJrzg9FQEmkAM5lpHBZs9wksWAsyF/HkpEwJA==", "dev": true, "dependencies": { "esbuild": "^0.20.1", - "postcss": "^8.4.36", + "postcss": "^8.4.38", "rollup": "^4.13.0" }, "bin": { @@ -4132,17 +4170,18 @@ } }, "node_modules/vite-plugin-dts": { - "version": "3.7.3", - "resolved": "https://registry.npmjs.org/vite-plugin-dts/-/vite-plugin-dts-3.7.3.tgz", - "integrity": "sha512-26eTlBYdpjRLWCsTJebM8vkCieE+p9gP3raf+ecDnzzK5E3FG6VE1wcy55OkRpfWWVlVvKkYFe6uvRHYWx7Nog==", + "version": "3.8.1", + "resolved": "https://registry.npmjs.org/vite-plugin-dts/-/vite-plugin-dts-3.8.1.tgz", + "integrity": "sha512-zEYyQxH7lKto1VTKZHF3ZZeOPkkJgnMrePY4VxDHfDSvDjmYMMfWjZxYmNwW8QxbaItWJQhhXY+geAbyNphI7g==", "dev": true, "dependencies": { - "@microsoft/api-extractor": "7.39.0", + "@microsoft/api-extractor": "7.43.0", "@rollup/pluginutils": "^5.1.0", - "@vue/language-core": "^1.8.26", + "@vue/language-core": "^1.8.27", "debug": "^4.3.4", "kolorist": "^1.8.0", - "vue-tsc": "^1.8.26" + "magic-string": "^0.30.8", + "vue-tsc": "^1.8.27" }, "engines": { "node": "^14.18.0 || >=16.0.0" @@ -4268,6 +4307,39 @@ "typescript": "*" } }, + "node_modules/vue-tsc/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/vue-tsc/node_modules/semver": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", + "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/vue-tsc/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, "node_modules/w3c-xmlserializer": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz", @@ -4391,9 +4463,9 @@ "dev": true }, "node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", "dev": true }, "node_modules/yocto-queue": { @@ -4430,25 +4502,27 @@ }, "packages/extension-tei": { "name": "@recogito/text-annotator-tei", - "version": "3.0.0-rc.18", + "version": "3.0.0-rc.20", "license": "BSD-3-Clause", - "dependencies": { - "@annotorious/core": "^3.0.0-rc.21" - }, "devDependencies": { "CETEIcean": "^1.9.2", - "typescript": "^5.3.3", - "vite": "^5.2.6", - "vite-plugin-dts": "^3.7.3" + "typescript": "^5.4.3", + "vite": "^5.2.7", + "vite-plugin-dts": "^3.8.1" + }, + "peerDependencies": { + "@annotorious/core": "^3.0.0-rc.22", + "@recogito/text-annotator": "^3.0.0-rc.20" } }, "packages/text-annotator": { "name": "@recogito/text-annotator", - "version": "3.0.0-rc.18", + "version": "3.0.0-rc.20", "license": "BSD-3-Clause", "dependencies": { - "@annotorious/core": "^3.0.0-rc.21", + "@annotorious/core": "^3.0.0-rc.22", "colord": "^2.9.3", + "dequal": "^2.0.3", "rbush": "^3.0.1", "uuid": "^9.0.1" }, @@ -4458,33 +4532,36 @@ "@types/uuid": "^9.0.8", "jsdom": "^24.0.0", "svelte": "^4.2.12", - "typescript": "^5.3.3", - "vite": "^5.2.6", - "vite-plugin-dts": "^3.7.3", + "typescript": "^5.4.3", + "vite": "^5.2.7", + "vite-plugin-dts": "^3.8.1", "vitest": "^1.4.0" } }, "packages/text-annotator-react": { "name": "@recogito/react-text-annotator", - "version": "3.0.0-rc.18", + "version": "3.0.0-rc.20", "license": "BSD-3-Clause", "dependencies": { + "@annotorious/core": "^3.0.0-rc.22", + "@annotorious/react": "^3.0.0-rc.22", "@neodrag/react": "^2.0.3", + "@recogito/text-annotator": "^3.0.0-rc.20", + "@recogito/text-annotator-tei": "^3.0.0-rc.20", "CETEIcean": "^1.9.2" }, "devDependencies": { - "@types/react-dom": "^18.2.22", + "@types/react-dom": "^18.2.23", "@vitejs/plugin-react": "^4.2.1", "openseadragon": "4.1.0", "react": "^18.2.0", "react-dom": "^18.2.0", - "typescript": "^5.3.3", - "vite": "^5.2.6", - "vite-plugin-dts": "^3.7.3", + "typescript": "^5.4.3", + "vite": "^5.2.7", + "vite-plugin-dts": "^3.8.1", "vite-tsconfig-paths": "^4.3.2" }, "peerDependencies": { - "@annotorious/react": "^3.0.0-rc.21", "react": "16.8.0 || >=17.x || >=18.x", "react-dom": "16.8.0 || >=17.x || >=18.x" } diff --git a/package.json b/package.json index 775d5197..d3ed24ab 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@recogito/text-annotator-monorepo", - "version": "3.0.0-rc.18", + "version": "3.0.0-rc.21", "description": "Recogito Text Annotator monorepo", "author": "Rainer Simon", "repository": { diff --git a/packages/extension-tei/package.json b/packages/extension-tei/package.json index e5857c16..9461c358 100644 --- a/packages/extension-tei/package.json +++ b/packages/extension-tei/package.json @@ -1,6 +1,6 @@ { "name": "@recogito/text-annotator-tei", - "version": "3.0.0-rc.18", + "version": "3.0.0-rc.21", "description": "Recogito Text Annotator TEI extension", "author": "Rainer Simon", "license": "BSD-3-Clause", @@ -27,11 +27,12 @@ }, "devDependencies": { "CETEIcean": "^1.9.2", - "typescript": "^5.3.3", - "vite": "^5.2.6", - "vite-plugin-dts": "^3.7.3" + "typescript": "^5.4.3", + "vite": "^5.2.7", + "vite-plugin-dts": "^3.8.1" }, - "dependencies": { - "@annotorious/core": "^3.0.0-rc.21" + "peerDependencies": { + "@annotorious/core": "^3.0.0-rc.22", + "@recogito/text-annotator": "3.0.0-rc.21" } -} +} \ No newline at end of file diff --git a/packages/text-annotator-react/package.json b/packages/text-annotator-react/package.json index 266cb9ab..a4c7d62a 100644 --- a/packages/text-annotator-react/package.json +++ b/packages/text-annotator-react/package.json @@ -1,6 +1,6 @@ { "name": "@recogito/react-text-annotator", - "version": "3.0.0-rc.18", + "version": "3.0.0-rc.21", "description": "Recogito Text Annotator React bindings", "author": "Rainer Simon", "license": "BSD-3-Clause", @@ -24,23 +24,26 @@ "module": "./dist/react-text-annotator.es.js", "types": "./dist/index.d.ts", "devDependencies": { - "@types/react-dom": "^18.2.22", + "@types/react-dom": "^18.2.23", "@vitejs/plugin-react": "^4.2.1", "openseadragon": "4.1.0", "react": "^18.2.0", "react-dom": "^18.2.0", - "typescript": "^5.3.3", - "vite": "^5.2.6", - "vite-plugin-dts": "^3.7.3", + "typescript": "^5.4.3", + "vite": "^5.2.7", + "vite-plugin-dts": "^3.8.1", "vite-tsconfig-paths": "^4.3.2" }, "peerDependencies": { - "@annotorious/react": "^3.0.0-rc.21", "react": "16.8.0 || >=17.x || >=18.x", "react-dom": "16.8.0 || >=17.x || >=18.x" }, "dependencies": { + "@annotorious/core": "^3.0.0-rc.22", + "@annotorious/react": "^3.0.0-rc.22", + "@recogito/text-annotator": "3.0.0-rc.21", + "@recogito/text-annotator-tei": "3.0.0-rc.21", "@neodrag/react": "^2.0.3", "CETEIcean": "^1.9.2" } -} +} \ No newline at end of file diff --git a/packages/text-annotator-react/src/TextAnnotator.tsx b/packages/text-annotator-react/src/TextAnnotator.tsx index 5fcf352f..6176f2e3 100644 --- a/packages/text-annotator-react/src/TextAnnotator.tsx +++ b/packages/text-annotator-react/src/TextAnnotator.tsx @@ -1,11 +1,12 @@ import { ReactNode, useContext, useEffect, useRef } from 'react'; -import { AnnotoriousContext, DrawingStyle, Filter } from '@annotorious/react'; +import { AnnotoriousContext, Filter } from '@annotorious/react'; import type { FormatAdapter } from '@annotorious/core'; -import type { TextAnnotation, TextAnnotatorOptions } from '@recogito/text-annotator'; +import type { HighlightStyleExpression, TextAnnotation, TextAnnotatorOptions } from '@recogito/text-annotator'; import { createTextAnnotator } from '@recogito/text-annotator'; import '@recogito/text-annotator/dist/text-annotator.css'; + export interface TextAnnotatorProps extends Omit, 'adapter'> { children?: ReactNode | JSX.Element; @@ -14,7 +15,7 @@ export interface TextAnnotatorProps extends Omit DrawingStyle); + style?: HighlightStyleExpression className?: string; diff --git a/packages/text-annotator-react/src/tei/TEIAnnotator.tsx b/packages/text-annotator-react/src/tei/TEIAnnotator.tsx index 8e9f4e1c..284481fb 100644 --- a/packages/text-annotator-react/src/tei/TEIAnnotator.tsx +++ b/packages/text-annotator-react/src/tei/TEIAnnotator.tsx @@ -1,8 +1,8 @@ import { Children, ReactElement, ReactNode, cloneElement, useContext, useEffect } from 'react'; -import { AnnotoriousContext, DrawingStyle, Filter } from '@annotorious/react'; +import { AnnotoriousContext, Filter } from '@annotorious/react'; import { TEIPlugin } from '@recogito/text-annotator-tei'; -import { createTextAnnotator } from '@recogito/text-annotator'; -import type { TextAnnotatorOptions, TextAnnotation } from '@recogito/text-annotator'; +import { createTextAnnotator, HighlightStyleExpression } from '@recogito/text-annotator'; +import type { TextAnnotatorOptions } from '@recogito/text-annotator'; import '@recogito/text-annotator/dist/text-annotator.css'; @@ -12,7 +12,7 @@ export type TEIAnnotatorProps = TextAnnotatorOptions & { filter?: Filter; - style?: DrawingStyle | ((annotation: TextAnnotation) => DrawingStyle); + style?: HighlightStyleExpression } @@ -48,4 +48,4 @@ export const TEIAnnotator = (props: TEIAnnotatorProps) => { ) : null; -} \ No newline at end of file +} diff --git a/packages/text-annotator-react/vite.config.js b/packages/text-annotator-react/vite.config.js index 9522ccc0..145f73d8 100644 --- a/packages/text-annotator-react/vite.config.js +++ b/packages/text-annotator-react/vite.config.js @@ -18,6 +18,7 @@ export default defineConfig(({ command, mode }) => ({ open: '/test/index.html' }, build: { + minify: false, lib: { entry: './src/index.ts', name: 'ReactTextAnnotator', @@ -26,17 +27,15 @@ export default defineConfig(({ command, mode }) => ({ }, rollupOptions: { external: [ - ...Object.keys(packageJson.peerDependencies) + ...Object.keys(packageJson.peerDependencies), + "@annotorious/core", + "@annotorious/react", + "@recogito/text-annotator", + "@recogito/text-annotator-tei" ], output: { preserveModules: true, - assetFileNames: 'react-text-annotator.[ext]', - globals: { - '@annotorious/react': 'AnnotoriousReact', - 'openseadragon': 'OpenSeadragon', - 'react': 'React', - 'react-dom': 'ReactDOM' - } + assetFileNames: 'react-text-annotator.[ext]' } }, sourcemap: true diff --git a/packages/text-annotator/package.json b/packages/text-annotator/package.json index b1401ae6..3953e29b 100644 --- a/packages/text-annotator/package.json +++ b/packages/text-annotator/package.json @@ -1,6 +1,6 @@ { "name": "@recogito/text-annotator", - "version": "3.0.0-rc.18", + "version": "3.0.0-rc.21", "description": "A JavaScript text annotation library", "author": "Rainer Simon", "license": "BSD-3-Clause", @@ -31,15 +31,16 @@ "@types/uuid": "^9.0.8", "jsdom": "^24.0.0", "svelte": "^4.2.12", - "typescript": "^5.3.3", - "vite": "^5.2.6", - "vite-plugin-dts": "^3.7.3", + "typescript": "^5.4.3", + "vite": "^5.2.7", + "vite-plugin-dts": "^3.8.1", "vitest": "^1.4.0" }, "dependencies": { - "@annotorious/core": "^3.0.0-rc.21", + "@annotorious/core": "^3.0.0-rc.22", "colord": "^2.9.3", + "dequal": "^2.0.3", "rbush": "^3.0.1", "uuid": "^9.0.1" } -} +} \ No newline at end of file diff --git a/packages/text-annotator/src/TextAnnotator.ts b/packages/text-annotator/src/TextAnnotator.ts index e5454025..2d6e2a28 100644 --- a/packages/text-annotator/src/TextAnnotator.ts +++ b/packages/text-annotator/src/TextAnnotator.ts @@ -1,19 +1,24 @@ -import { createAnonymousGuest, createLifecyleObserver, createBaseAnnotator, DrawingStyle, Filter, createUndoStack } from '@annotorious/core'; +import { createAnonymousGuest, createLifecyleObserver, createBaseAnnotator, Filter, createUndoStack } from '@annotorious/core'; import type { Annotator, User, PresenceProvider } from '@annotorious/core'; -import { createCanvasHighlightRenderer, createCSSHighlightRenderer } from './highlight'; +import { createCanvasRenderer, createHighlightsRenderer, createSpansRenderer, type HighlightStyleExpression } from './highlight'; import { createPresencePainter } from './presence'; import { scrollIntoView } from './api'; import { TextAnnotationStore, TextAnnotatorState, createTextAnnotatorState } from './state'; import type { TextAnnotation } from './model'; -import type { TextAnnotatorOptions } from './TextAnnotatorOptions'; +import type { RendererType, TextAnnotatorOptions } from './TextAnnotatorOptions'; import { SelectionHandler } from './SelectionHandler'; import './TextAnnotator.css'; + +const USE_DEFAULT_RENDERER: RendererType = 'SPANS'; + export interface TextAnnotator extends Annotator { element: HTMLElement; + setStyle(style: HighlightStyleExpression | undefined): void; + // Returns true if successful (or false if the annotation is not currently rendered) scrollIntoView(annotation: TextAnnotation): boolean; @@ -42,20 +47,26 @@ export const createTextAnnotator = ( let currentUser: User = createAnonymousGuest(); - // Switch on CSS Custom Highlight rendering, if requested in the init - // opts and API is available in this browser - // @ts-ignore - const useExperimentalCSSRenderer = opts.experimentalCSSRenderer && Boolean(CSS.highlights); + // Use selected renderer, or fall back to default. If CSS_HIGHLIGHT is + // requested, check if CSS Custom Highlights are supported, and fall + // back to default renderer if not. + const useRenderer: RendererType = + opts.renderer === 'CSS_HIGHLIGHTS' + ? Boolean(CSS.highlights) ? 'CSS_HIGHLIGHTS' : USE_DEFAULT_RENDERER + : opts.renderer || USE_DEFAULT_RENDERER; - if (useExperimentalCSSRenderer) - console.log('Using experimental CSS Custom Highlight API renderer'); + const highlightRenderer = + useRenderer === 'SPANS' ? createSpansRenderer(container, state, viewport) : + useRenderer === 'CSS_HIGHLIGHTS' ? createHighlightsRenderer(container, state, viewport) : + useRenderer === 'CANVAS' ? createCanvasRenderer(container, state, viewport) : undefined; - const highlightRenderer = useExperimentalCSSRenderer - ? createCSSHighlightRenderer(container, state, viewport) - : createCanvasHighlightRenderer(container, state, viewport); + if (!highlightRenderer) + throw `Unknown renderer implementation: ${useRenderer}`; + console.debug(`Using ${useRenderer} renderer`); + if (opts.style) - highlightRenderer.setDrawingStyle(opts.style); + highlightRenderer.setStyle(opts.style); const selectionHandler = SelectionHandler(container, state, opts.offsetReferenceSelector); @@ -73,8 +84,8 @@ export const createTextAnnotator = ( const setFilter = (filter?: Filter) => highlightRenderer.setFilter(filter); - const setStyle = (drawingStyle: DrawingStyle | ((annotation: TextAnnotation) => DrawingStyle) | undefined) => - highlightRenderer.setDrawingStyle(drawingStyle); + const setStyle = (style: HighlightStyleExpression | undefined) => + highlightRenderer.setStyle(style); const setUser = (user: User) => { currentUser = user; @@ -84,7 +95,7 @@ export const createTextAnnotator = ( const setPresenceProvider = (provider: PresenceProvider) => { if (provider) { highlightRenderer.setPainter(createPresencePainter(container, provider, opts.presence)); - provider.on('selectionChange', () => highlightRenderer.refresh()); + provider.on('selectionChange', () => highlightRenderer.redraw()); } } @@ -96,6 +107,9 @@ export const createTextAnnotator = ( } } + const setVisible = (visible: boolean) => + highlightRenderer.setVisible(visible); + const destroy = () => { highlightRenderer.destroy(); selectionHandler.destroy(); @@ -114,6 +128,7 @@ export const createTextAnnotator = ( setUser, setSelected, setPresenceProvider, + setVisible, on: lifecycle.on, off: lifecycle.off, scrollIntoView: scrollIntoView(container, store), diff --git a/packages/text-annotator/src/TextAnnotatorOptions.ts b/packages/text-annotator/src/TextAnnotatorOptions.ts index 1bcc037e..01d4f725 100644 --- a/packages/text-annotator/src/TextAnnotatorOptions.ts +++ b/packages/text-annotator/src/TextAnnotatorOptions.ts @@ -1,12 +1,13 @@ -import type { DrawingStyle, FormatAdapter, PointerSelectAction } from '@annotorious/core'; +import type { FormatAdapter, PointerSelectAction } from '@annotorious/core'; import type { PresencePainterOptions } from './presence'; import type { TextAnnotation } from './model'; +import type { HighlightStyleExpression } from './highlight'; export interface TextAnnotatorOptions { adapter?: FormatAdapter | null; - experimentalCSSRenderer?: boolean; + renderer?: RendererType; offsetReferenceSelector?: string; @@ -14,6 +15,8 @@ export interface TextAnnotatorOptions { presence?: PresencePainterOptions; - style?: DrawingStyle | ((annotation: TextAnnotation) => DrawingStyle); + style?: HighlightStyleExpression; } + +export type RendererType = 'SPANS' | 'CANVAS' | 'CSS_HIGHLIGHTS'; diff --git a/packages/text-annotator/src/highlight/Highlight.ts b/packages/text-annotator/src/highlight/Highlight.ts new file mode 100644 index 00000000..52b141eb --- /dev/null +++ b/packages/text-annotator/src/highlight/Highlight.ts @@ -0,0 +1,8 @@ +import type { AnnotationState } from '@annotorious/core'; +import type { AnnotationRects } from '../state'; + +export interface Highlight extends AnnotationRects { + + state: AnnotationState; + +} \ No newline at end of file diff --git a/packages/text-annotator/src/highlight/HighlightPainter.ts b/packages/text-annotator/src/highlight/HighlightPainter.ts index ac42915a..297ecf83 100644 --- a/packages/text-annotator/src/highlight/HighlightPainter.ts +++ b/packages/text-annotator/src/highlight/HighlightPainter.ts @@ -1,5 +1,7 @@ -import type { AnnotationRects } from '../state'; -import type { HighlightStyle } from './HighlightStyle'; + +import type { Highlight } from './Highlight'; +import { DEFAULT_SELECTED_STYLE, DEFAULT_STYLE } from './HighlightStyle'; +import type { HighlightStyle, HighlightStyleExpression } from './HighlightStyle'; import type { ViewportBounds } from './viewport'; export interface HighlightPainter { @@ -8,12 +10,28 @@ export interface HighlightPainter { destroy(): void; - paint( - annotation: AnnotationRects, - viewportBounds: ViewportBounds, - isSelected?: boolean - ): HighlightStyle; + paint(highlight: Highlight, viewportBounds: ViewportBounds): HighlightStyle; reset(): void; +} + +/** Helper **/ +export const paint = ( + highlight: Highlight, + viewportBounds: ViewportBounds, + style?: HighlightStyleExpression, + painter?: HighlightPainter, + zIndex?: number +) => { + const base: HighlightStyle = style + ? typeof style === 'function' + ? style(highlight.annotation, highlight.state, zIndex) + : style + : highlight.state?.selected + ? DEFAULT_SELECTED_STYLE + : DEFAULT_STYLE; + + // Trigger the custom painter (if any) as a side-effect + return painter ? painter.paint(highlight, viewportBounds) || base : base; } \ No newline at end of file diff --git a/packages/text-annotator/src/highlight/HighlightStyle.ts b/packages/text-annotator/src/highlight/HighlightStyle.ts index 14280d8e..ea73cf1e 100644 --- a/packages/text-annotator/src/highlight/HighlightStyle.ts +++ b/packages/text-annotator/src/highlight/HighlightStyle.ts @@ -1,23 +1,30 @@ -import type { DrawingStyle } from '@annotorious/core'; - -export const DEFAULT_STYLE: DrawingStyle = { - fill: 'rgb(0, 128, 255)', - fillOpacity: 0.18 -}; - -export const DEFAULT_SELECTED_STYLE: DrawingStyle = { - fill: 'rgb(0, 128, 255)', - fillOpacity: 0.45 -}; +import type { AnnotationState, Color, DrawingStyle } from '@annotorious/core'; +import type { TextAnnotation } from 'src/model'; export interface HighlightStyle extends Pick { underlineStyle?: string; - underlineColor?: number; + underlineColor?: Color; underlineOffset?: number; underlineThickness?: number; -} \ No newline at end of file +} + +export type HighlightStyleExpression = HighlightStyle + | ((annotation: TextAnnotation, state: AnnotationState, zIndex?: number) => HighlightStyle) + +export const DEFAULT_STYLE: HighlightStyle = { + fill: 'rgb(0, 128, 255)', + fillOpacity: 0.18 +}; + +export const DEFAULT_SELECTED_STYLE: HighlightStyle = { + fill: 'rgb(0, 128, 255)', + fillOpacity: 0.45 +}; + + + diff --git a/packages/text-annotator/src/highlight/baseRenderer.ts b/packages/text-annotator/src/highlight/baseRenderer.ts new file mode 100644 index 00000000..a7f6f2df --- /dev/null +++ b/packages/text-annotator/src/highlight/baseRenderer.ts @@ -0,0 +1,190 @@ +import type { Filter, ViewportState } from '@annotorious/core'; +import type { TextAnnotatorState } from '../state'; +import { debounce } from '../utils'; +import { ViewportBounds, getViewportBounds, trackViewport } from './viewport'; +import type { HighlightPainter } from './HighlightPainter'; +import type { Highlight } from './Highlight'; +import type { HighlightStyleExpression } from './HighlightStyle'; + +export interface RendererImplementation { + + destroy(): void; + + redraw( + + highlights:Highlight[], + + bounds: ViewportBounds, + + style?: HighlightStyleExpression, + + painter?: HighlightPainter, + + lazy?: boolean + + ): void; + + setVisible(visible: boolean): void; + +} + +export interface Renderer { + + destroy(): void; + + redraw(force?: boolean): void; + + setStyle(style?: HighlightStyleExpression): void; + + setFilter(filter?: Filter): void; + + setPainter(painter?: HighlightPainter): void; + + setVisible(visible: boolean): void; + +} + +export const createBaseRenderer = ( + container: HTMLElement, + state: TextAnnotatorState, + viewport: ViewportState, + renderer: RendererImplementation +): Renderer => { + const { store, selection, hover } = state; + + let currentStyle: HighlightStyleExpression | undefined; + + let currentFilter: Filter | undefined; + + let customPainter: HighlightPainter; + + const onDraw = trackViewport(viewport); + + const onPointerMove = (event: PointerEvent) => { + const {x, y} = container.getBoundingClientRect(); + + const hit = store.getAt(event.clientX - x, event.clientY - y); + const isVisibleHit = hit && (!currentFilter || currentFilter(hit)); + + if (isVisibleHit) { + if (hover.current !== hit.id) { + container.classList.add('hovered'); + hover.set(hit.id); + } + } else { + if (hover.current) { + container.classList.remove('hovered'); + hover.set(null); + } + } + } + + container.addEventListener('pointermove', onPointerMove); + + const redraw = (lazy: boolean = false) => { + if (customPainter) + customPainter.clear(); + + const bounds = getViewportBounds(container); + + const { minX, minY, maxX, maxY } = bounds; + + const annotationsInView = currentFilter + ? store.getIntersecting(minX, minY, maxX, maxY).filter(({ annotation }) => currentFilter(annotation)) + : store.getIntersecting(minX, minY, maxX, maxY); + + const selectedIds = selection.selected.map(({ id }) => id); + + const highlights: Highlight[] = annotationsInView.map(({ annotation, rects }) => { + const selected = selectedIds.includes(annotation.id); + const hovered = annotation.id === hover.current; + + // TODO minor API changes coming up soon... + return { annotation, rects, state: { selected, hover: hovered, custom: {} }}; + }) + + renderer.redraw(highlights, bounds, currentStyle, customPainter, lazy); + + setTimeout(() => onDraw(annotationsInView.map(({ annotation }) => annotation)), 1); + } + + const setPainter = (painter: HighlightPainter) => { + customPainter = painter; + redraw(); + } + + const setStyle = (style?: HighlightStyleExpression) => { + currentStyle = style; + redraw(); + } + + const setFilter = (filter?: Filter) => { + currentFilter = filter; + redraw(false); + } + + // Refresh on store change + const onStoreChange = () => redraw(); + store.observe(onStoreChange); + + // Refresh on selection change + const unsubscribeSelection = selection.subscribe(() => redraw()); + + // Refresh on scroll + const onScroll = () => redraw(true); + document.addEventListener('scroll', onScroll, { capture: true, passive: true }); + + // Refresh on resize + const onResize = debounce(() => { + store.recalculatePositions(); + + if (customPainter) + customPainter.reset(); + + redraw(); + }); + + window.addEventListener('resize', onResize); + + const resizeObserver = new ResizeObserver(onResize); + resizeObserver.observe(container); + + // This is an extra precaution. The position of the container + // might shift (without resizing) due to layout changes higher-up + // in the DOM. (This happens in Recogito for example) + const config: MutationObserverInit = { attributes: true, childList: true, subtree: true }; + + const mutationObserver = new MutationObserver((records: MutationRecord[]) => { + const isInternal = records.every(record => record.target === container || container.contains(record.target)); + if (!isInternal) redraw(true); + }); + + mutationObserver.observe(document.body, config); + + const destroy = () => { + container.removeEventListener('pointermove', onPointerMove); + + renderer.destroy(); + + store.unobserve(onStoreChange); + + unsubscribeSelection(); + + document.removeEventListener('scroll', onScroll); + + window.removeEventListener('resize', onResize); + resizeObserver.disconnect(); + + mutationObserver.disconnect(); + } + + return { + destroy, + redraw, + setStyle, + setFilter, + setPainter, + setVisible: renderer.setVisible + } + +} \ No newline at end of file diff --git a/packages/text-annotator/src/highlight/canvas/canvasRenderer.ts b/packages/text-annotator/src/highlight/canvas/canvasRenderer.ts new file mode 100644 index 00000000..c792a92d --- /dev/null +++ b/packages/text-annotator/src/highlight/canvas/canvasRenderer.ts @@ -0,0 +1,126 @@ +import type { ViewportBounds } from '../viewport'; +import { debounce } from '../../utils'; +import type { HighlightStyle } from '../HighlightStyle'; +import { DEFAULT_SELECTED_STYLE, DEFAULT_STYLE, HighlightStyleExpression } from '../HighlightStyle'; +import type { HighlightPainter } from '../HighlightPainter'; +import { createBaseRenderer, type RendererImplementation } from '../baseRenderer'; +import type { Highlight } from '../Highlight'; +import type { TextAnnotatorState } from 'src/state'; +import type { ViewportState } from '@annotorious/core'; + +const createCanvas = () => { + const canvas = document.createElement('canvas'); + canvas.width = window.innerWidth; + canvas.height = window.innerHeight; + canvas.className = 'r6o-highlight-layer bg'; + return canvas; +} + +const resetCanvas = (canvas: HTMLCanvasElement, highres?: boolean) => { + canvas.width = highres ? 2 * window.innerWidth : window.innerWidth; + canvas.height = highres ? 2 * window.innerHeight : window.innerHeight; + + if (highres) { + // Note that resizing the canvas resets the context + const context = canvas.getContext('2d'); + context.scale(2, 2); + context.translate(0.5, 0.5); + } +} + +const createRenderer = (container: HTMLElement): RendererImplementation => { + + container.classList.add('r6o-annotatable'); + + const canvas = createCanvas(); + const ctx = canvas.getContext('2d'); + + container.insertBefore(canvas, container.firstChild); + + const redraw = ( + highlights: Highlight[], + viewportBounds: ViewportBounds, + currentStyle?: HighlightStyleExpression, + painter?: HighlightPainter + ) => requestAnimationFrame(() => { + + const { width, height } = canvas; + + // New render loop - clear canvases + ctx.clearRect(-0.5, -0.5, width + 1, height + 1); + + if (painter) + painter.clear(); + + const { top, left } = viewportBounds; + + highlights.forEach(h => { + const base: HighlightStyle = currentStyle + ? typeof currentStyle === 'function' + ? currentStyle(h.annotation, h.state) + : currentStyle + : h.state?.selected + ? DEFAULT_SELECTED_STYLE + : DEFAULT_STYLE; + + // Trigger the custom painter (if any) as a side-effect + const style = painter ? painter.paint(h, viewportBounds) || base : base; + + // Offset annotation rects by current scroll position + const offsetRects = h.rects.map(({ x, y, width, height }) => ({ + x: x + left, + y: y + top, + width, + height + })); + + ctx.fillStyle = style.fill; + ctx.globalAlpha = style.fillOpacity || 1; + + offsetRects.forEach(({ x, y, width, height }) => ctx.fillRect(x, y - 2.5, width, height + 5)); + + if (style.underlineColor) { + ctx.globalAlpha = 1; + ctx.strokeStyle = style.underlineColor; + + offsetRects.forEach(({ x, y, width, height }) => { + ctx.beginPath(); + ctx.moveTo(x, y + height + 4); + ctx.lineTo(x + width, y + height + 4); + + // Draw the Path + ctx.stroke(); + }); + } + }); + }); + + const onResize = debounce(() => { + resetCanvas(canvas); + }); + + window.addEventListener('resize', onResize); + + const setVisible = (visible: boolean) => { + console.log('setVisible not implemented on Canvas renderer'); + } + + const destroy = () => { + container.removeChild(canvas); + + window.removeEventListener('resize', onResize); + } + + return { + destroy, + setVisible, + redraw + } + +} + +export const createCanvasRenderer = ( + container: HTMLElement, + state: TextAnnotatorState, + viewport: ViewportState +) => createBaseRenderer(container, state, viewport, createRenderer(container)); diff --git a/packages/text-annotator/src/highlight/canvas/highlightRenderer.ts b/packages/text-annotator/src/highlight/canvas/highlightRenderer.ts deleted file mode 100644 index e3d8f1f3..00000000 --- a/packages/text-annotator/src/highlight/canvas/highlightRenderer.ts +++ /dev/null @@ -1,199 +0,0 @@ -import type { DrawingStyle, Filter, ViewportState } from '@annotorious/core'; -import type { TextAnnotation } from '../../model'; -import type { TextAnnotatorState } from '../../state'; -import { getViewportBounds, trackViewport } from '../viewport'; -import { debounce } from '../../utils'; -import { DEFAULT_SELECTED_STYLE, DEFAULT_STYLE, type HighlightStyle } from '../HighlightStyle'; -import type { HighlightPainter } from '../HighlightPainter'; - -const createCanvas = () => { - const canvas = document.createElement('canvas'); - canvas.width = window.innerWidth; - canvas.height = window.innerHeight; - canvas.className = 'r6o-highlight-layer bg'; - return canvas; -} - -const resetCanvas = (canvas: HTMLCanvasElement, highres?: boolean) => { - canvas.width = highres ? 2 * window.innerWidth : window.innerWidth; - canvas.height = highres ? 2 * window.innerHeight : window.innerHeight; - - if (highres) { - // Note that resizing the canvas resets the context - const context = canvas.getContext('2d'); - context.scale(2, 2); - context.translate(0.5, 0.5); - } -} - -export const createCanvasHighlightRenderer = ( - container: HTMLElement, - state: TextAnnotatorState, - viewport: ViewportState -) => { - const { store, selection, hover } = state; - - let currentStyle: DrawingStyle | ((annotation: TextAnnotation, selected?: boolean) => DrawingStyle) | undefined; - - let currentFilter: Filter | undefined; - - let customPainter: HighlightPainter; - - const onDraw = trackViewport(viewport); - - container.classList.add('r6o-annotatable'); - - const canvas = createCanvas(); - const ctx = canvas.getContext('2d'); - - container.insertBefore(canvas, container.firstChild); - - const onPointerMove = (event: PointerEvent) => { - const {x, y} = container.getBoundingClientRect(); - - const hit = store.getAt(event.clientX - x, event.clientY - y); - const isVisibleHit = hit && (!currentFilter || currentFilter(hit)); - - if (isVisibleHit) { - if (hover.current !== hit.id) { - container.classList.add('hovered'); - hover.set(hit.id); - } - } else { - if (hover.current) { - container.classList.remove('hovered'); - hover.set(null); - } - } - } - - container.addEventListener('pointermove', onPointerMove); - - const refresh = () => requestAnimationFrame(() => { - const bounds = getViewportBounds(container); - - const { top, left, minX, minY, maxX, maxY } = bounds; - - const annotationsInView = currentFilter - ? store.getIntersectingRects(minX, minY, maxX, maxY).filter(({ annotation }) => currentFilter(annotation)) - : store.getIntersectingRects(minX, minY, maxX, maxY); - - const { width, height } = canvas; - - // Get current selection - const selectedIds = new Set(selection.selected.map(({ id }) => id)); - - // New render loop - clear canvases - ctx.clearRect(-0.5, -0.5, width + 1, height + 1); - - if (customPainter) - customPainter.clear(); - - annotationsInView.forEach(h => { - const isSelected = selectedIds.has(h.annotation.id); - - const base: HighlightStyle = currentStyle - ? typeof currentStyle === 'function' - ? currentStyle(h.annotation, isSelected) - : currentStyle - : isSelected - ? DEFAULT_SELECTED_STYLE - : DEFAULT_STYLE; - - // Trigger the custom painter (if any) as a side-effect - const style = customPainter ? customPainter.paint(h, bounds, isSelected) || base : base; - - // Offset annotation rects by current scroll position - const offsetRects = h.rects.map(({ x, y, width, height }) => ({ - x: x + left, - y: y + top, - width, - height - })); - - ctx.fillStyle = style.fill; - ctx.globalAlpha = style.fillOpacity || 1; - - offsetRects.forEach(({ x, y, width, height }) => ctx.fillRect(x, y - 2.5, width, height + 5)); - }); - - setTimeout(() => onDraw(annotationsInView.map(({ annotation }) => annotation)), 1); - }); - - const setDrawingStyle = (style: DrawingStyle | ((a: TextAnnotation, selected?: boolean) => DrawingStyle)) => { - currentStyle = style; - refresh(); - } - - const setFilter = (filter?: Filter) => { - currentFilter = filter; - refresh(); - } - - // Redraw on store change - const onStoreChange = () => refresh(); - store.observe(onStoreChange); - - // Redraw on selection change - const unsubscribeSelection = selection.subscribe(() => refresh()); - - // Redraw on scroll - const onScroll = () => refresh(); - document.addEventListener('scroll', onScroll, { capture: true, passive: true }); - - // Redraw on resize. Note that in cases where the element resized - // due to a window resize, onResize will be triggered twice. This - // is probably not a huge issue. But definitely an area for - // future optimization. In terms of how to do this: there's - // probably no ideal solution, but one straightforward way - // would be to just set a flag in - const onResize = debounce(() => { - resetCanvas(canvas); - - store.recalculatePositions(); - - if (customPainter) - customPainter.reset(); - - refresh(); - }); - - window.addEventListener('resize', onResize); - - const resizeObserver = new ResizeObserver(onResize); - resizeObserver.observe(container); - - const config: MutationObserverInit = { attributes: true, childList: true, subtree: true }; - - // This is an extra precaution. The position of the container - // might shift (without resizing) due to layout changes higher-up - // in the DOM. (This happens in Recogito+ for example) - const mutationObserver = new MutationObserver(refresh); - mutationObserver.observe(document.body, config); - - const destroy = () => { - container.removeEventListener('pointermove', onPointerMove); - - container.removeChild(canvas); - - store.unobserve(onStoreChange); - - unsubscribeSelection(); - - document.removeEventListener('scroll', onScroll); - - window.removeEventListener('resize', onResize); - resizeObserver.disconnect(); - - mutationObserver.disconnect(); - } - - return { - destroy, - refresh, - setDrawingStyle, - setFilter, - setPainter: (painter: HighlightPainter) => customPainter = painter - } - -} diff --git a/packages/text-annotator/src/highlight/canvas/index.ts b/packages/text-annotator/src/highlight/canvas/index.ts index ef7c33cf..802b801a 100644 --- a/packages/text-annotator/src/highlight/canvas/index.ts +++ b/packages/text-annotator/src/highlight/canvas/index.ts @@ -1 +1 @@ -export * from './highlightRenderer'; \ No newline at end of file +export * from './canvasRenderer'; \ No newline at end of file diff --git a/packages/text-annotator/src/highlight/css/highlightRenderer.ts b/packages/text-annotator/src/highlight/css/highlightRenderer.ts deleted file mode 100644 index 3d163a68..00000000 --- a/packages/text-annotator/src/highlight/css/highlightRenderer.ts +++ /dev/null @@ -1,139 +0,0 @@ -import type { DrawingStyle, Filter, ViewportState } from '@annotorious/core'; -import type { TextAnnotatorState } from '../../state'; -import type { TextAnnotation } from '../../model'; -import { debounce } from '../../utils'; -import { getViewportBounds, trackViewport } from '../viewport'; -import type { HighlightPainter } from '../HighlightPainter'; -import { createHighlights } from './highlights'; - -export const createCSSHighlightRenderer = ( - container: HTMLElement, - state: TextAnnotatorState, - viewport: ViewportState -) => { - const { store, selection, hover } = state; - - let customPainter: HighlightPainter; - - let currentStyle: DrawingStyle | ((annotation: TextAnnotation, selected?: boolean) => DrawingStyle) | undefined; - - let currentFilter: Filter | undefined; - - const highlights = createHighlights(); - - const onDraw = trackViewport(viewport); - - const onPointerMove = (event: PointerEvent) => { - const {x, y} = container.getBoundingClientRect(); - - const hit = store.getAt(event.clientX - x, event.clientY - y); - const isVisibleHit = hit && (!currentFilter || currentFilter(hit)); - - if (isVisibleHit) { - if (hover.current !== hit.id) { - container.classList.add('hovered'); - hover.set(hit.id); - } - } else { - if (hover.current) { - container.classList.remove('hovered'); - hover.set(null); - } - } - } - - container.addEventListener('pointermove', onPointerMove); - - const refresh = () => { - const bounds = getViewportBounds(container); - - const { minX, minY, maxX, maxY } = bounds; - - const annotationsInView = currentFilter - ? store.getIntersectingRects(minX, minY, maxX, maxY).filter(({ annotation }) => currentFilter(annotation)) - : store.getIntersectingRects(minX, minY, maxX, maxY); - - // Get current selection - const selectedIds = selection.selected.map(({ id }) => id); - - highlights.refresh(annotationsInView, bounds, selectedIds, currentStyle); - - setTimeout(() => onDraw(annotationsInView.map(({ annotation }) => annotation)), 1); - } - - const setPainter = (painter: HighlightPainter) => { - customPainter = painter; - highlights.setPainter(painter); - } - - // Refresh when style changes - const setDrawingStyle = (style: DrawingStyle | ((a: TextAnnotation, selected?: boolean) => DrawingStyle)) => { - currentStyle = style; - refresh(); - } - - // Refresh when filter changes - const setFilter = (filter?: Filter) => { - currentFilter = filter; - refresh(); - } - - // Refresh on store change - const onStoreChange = () => refresh(); - store.observe(onStoreChange); - - // Refresh on selection change - const unsubscribeSelection = selection.subscribe(() => refresh()); - - // Refresh on scroll - document.addEventListener('scroll', refresh, { capture: true, passive: true }); - - // Refresh on resize - const onResize = debounce(() => { - store.recalculatePositions(); - - if (customPainter) - customPainter.reset(); - - refresh(); - }); - - window.addEventListener('resize', onResize); - - const resizeObserver = new ResizeObserver(onResize); - resizeObserver.observe(container); - - // This is an extra precaution. The position of the container - // might shift (without resizing) due to layout changes higher-up - // in the DOM. (This happens in Recogito+ for example) - const config: MutationObserverInit = { attributes: true, childList: true, subtree: true }; - - const mutationObserver = new MutationObserver(refresh); - mutationObserver.observe(document.body, config); - - const destroy = () => { - container.removeEventListener('pointermove', onPointerMove); - - highlights.destroy(); - - store.unobserve(onStoreChange); - - unsubscribeSelection(); - - document.removeEventListener('scroll', refresh); - - window.removeEventListener('resize', onResize); - resizeObserver.disconnect(); - - mutationObserver.disconnect(); - } - - return { - destroy, - refresh, - setDrawingStyle, - setFilter, - setPainter - } - -} \ No newline at end of file diff --git a/packages/text-annotator/src/highlight/css/highlights.ts b/packages/text-annotator/src/highlight/css/highlights.ts deleted file mode 100644 index bf096145..00000000 --- a/packages/text-annotator/src/highlight/css/highlights.ts +++ /dev/null @@ -1,95 +0,0 @@ -import type { DrawingStyle } from '@annotorious/core'; -import { colord } from 'colord'; -import type { TextAnnotation } from '../../model'; -import type { HighlightPainter } from '../HighlightPainter'; -import type { AnnotationRects } from 'src/state'; -import type { ViewportBounds } from '../viewport'; -import { DEFAULT_SELECTED_STYLE, DEFAULT_STYLE } from '../HighlightStyle'; - -const toCSS = (s: DrawingStyle) => { - const backgroundColor = colord(s.fill || DEFAULT_STYLE.fill).alpha(s.fillOpacity || DEFAULT_STYLE.fillOpacity).toHex(); - return `background-color: ${backgroundColor};` -} - -export const createHighlights = () => { - const elem = document.createElement('style'); - document.getElementsByTagName('head')[0].appendChild(elem); - - let customPainter: HighlightPainter; - - let currentRendered = new Set(); - - const refresh = ( - highlights: AnnotationRects[], - viewportBounds: ViewportBounds, - selected: string[], - currentStyle: DrawingStyle | ((annotation: TextAnnotation, selected: boolean) => DrawingStyle) - ) => { - if (customPainter) - customPainter.clear(); - - // Next set of rendered annotation IDs and selections - const nextRendered = new Set(highlights.map(h => h.annotation.id)); - const nextSelected = new Set(selected); - - // Annotations currently in this stylesheet that no longer need rendering - const toRemove = Array.from(currentRendered).filter(id => !nextRendered.has(id)); - - // For simplicity, re-generate the whole stylesheet - const updatedCSS = highlights.map(h => { - const isSelected = nextSelected.has(h.annotation.id); - - const base = currentStyle - ? typeof currentStyle === 'function' - ? currentStyle(h.annotation, isSelected) - : currentStyle - : isSelected ? DEFAULT_SELECTED_STYLE : DEFAULT_STYLE; - - // Trigger the custom painter (if any) as a side-effect - const style = customPainter ? customPainter.paint(h, viewportBounds, isSelected) || base : base; - - return `::highlight(_${h.annotation.id}) { ${toCSS(style)} }`; - }); - - elem.innerHTML = updatedCSS.join('\n'); - - // After we have the styles, we need to update the Highlights. - // Note that the (experimental) CSS Custom Highlight API is not yet - // available in TypeScript! - - // @ts-ignore - toRemove.forEach(id => CSS.highlights.delete(`_${id}`)); - - // Could be improved further by (re-)setting only annotations that - // have changes. - highlights.forEach(({ annotation }) => { - const ranges = annotation.target.selector.map(s => s.range); - - // @ts-ignore - const highlights = new Highlight(...ranges); - - // @ts-ignore - CSS.highlights.set(`_${annotation.id}`, highlights); - }); - - currentRendered = nextRendered; - } - - const setPainter = (painter: HighlightPainter) => customPainter = painter; - - const destroy = () => { - // Clear all highlights from the Highlight Registry - // @ts-ignore - CSS.highlights.clear(); - - // Remove the stylesheet - elem.remove(); - } - - return { - destroy, - refresh, - setPainter - } - -} \ No newline at end of file diff --git a/packages/text-annotator/src/highlight/css/index.ts b/packages/text-annotator/src/highlight/css/index.ts deleted file mode 100644 index f9a054f1..00000000 --- a/packages/text-annotator/src/highlight/css/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './highlightRenderer' diff --git a/packages/text-annotator/src/highlight/highlights/highlightsRenderer.ts b/packages/text-annotator/src/highlight/highlights/highlightsRenderer.ts new file mode 100644 index 00000000..7bb9f2d6 --- /dev/null +++ b/packages/text-annotator/src/highlight/highlights/highlightsRenderer.ts @@ -0,0 +1,111 @@ +import type { ViewportState } from '@annotorious/core'; +import { colord } from 'colord'; +import type { HighlightPainter } from '../HighlightPainter'; +import type { TextAnnotatorState } from 'src/state'; +import type { ViewportBounds } from '../viewport'; +import { DEFAULT_SELECTED_STYLE, DEFAULT_STYLE, HighlightStyle, HighlightStyleExpression } from '../HighlightStyle'; +import { RendererImplementation, createBaseRenderer } from '../baseRenderer'; +import type { Highlight } from '../Highlight'; + +const toCSS = (s?: HighlightStyle) => { + const backgroundColor = colord(s?.fill || DEFAULT_STYLE.fill) + .alpha(s?.fillOpacity === undefined ? DEFAULT_STYLE.fillOpacity : s.fillOpacity) + .toHex(); + + const rules = [ + `background-color:${backgroundColor}`, + s?.underlineThickness ? `text-decoration:underline` : undefined, + s?.underlineColor ? `text-decoration-color:${s.underlineColor}` : undefined, + s?.underlineOffset ? `text-underline-offset:${s.underlineOffset}px` : undefined, + s?.underlineThickness ? `text-decoration-thickness:${s.underlineThickness}px` : undefined + ].filter(Boolean); + + return rules.join(';'); +} + +export const createRenderer = (): RendererImplementation => { + const elem = document.createElement('style'); + document.getElementsByTagName('head')[0].appendChild(elem); + + let currentRendered = new Set(); + + const redraw = ( + highlights: Highlight[], + viewportBounds: ViewportBounds, + currentStyle?: HighlightStyleExpression, + painter?: HighlightPainter + ) => { + if (painter) + painter.clear(); + + // Next set of rendered annotation IDs and selections + const nextRendered = new Set(highlights.map(h => h.annotation.id)); + + // Annotations currently in this stylesheet that no longer need rendering + const toRemove = Array.from(currentRendered).filter(id => !nextRendered.has(id)); + + // For simplicity, re-generate the whole stylesheet + const updatedCSS = highlights.map(h => { + const base = currentStyle + ? typeof currentStyle === 'function' + ? currentStyle(h.annotation, h.state) + : currentStyle + : h.state?.selected ? DEFAULT_SELECTED_STYLE : DEFAULT_STYLE; + + // Trigger the custom painter (if any) as a side-effect + const style = painter ? painter.paint(h, viewportBounds) || base : base; + + return `::highlight(_${h.annotation.id}) { ${toCSS(style)} }`; + }); + + elem.innerHTML = updatedCSS.join('\n'); + + // After we have the styles, we need to update the Highlights. + // Note that the (experimental) CSS Custom Highlight API is not yet + // available in TypeScript! + + // @ts-ignore + CSS.highlights.clear(); + // toRemove.forEach(id => CSS.highlights.delete(`_${id}`)); + + // Could be improved further by (re-)setting only annotations that + // have changes. + highlights.forEach(({ annotation }) => { + const ranges = annotation.target.selector.map(s => s.range); + + // @ts-ignore + const highlights = new Highlight(...ranges); + + // @ts-ignore + CSS.highlights.set(`_${annotation.id}`, highlights); + }); + + currentRendered = nextRendered; + } + + const setVisible = (visible: boolean) => { + console.log('setVisible not implemented on CSS Custom Highlights renderer'); + } + + const destroy = () => { + // Clear all highlights from the Highlight Registry + // @ts-ignore + CSS.highlights.clear(); + + // Remove the stylesheet + elem.remove(); + } + + return { + destroy, + setVisible, + redraw + } + +} + +export const createHighlightsRenderer = ( + container: HTMLElement, + state: TextAnnotatorState, + viewport: ViewportState +) => createBaseRenderer(container, state, viewport, createRenderer()); \ No newline at end of file diff --git a/packages/text-annotator/src/highlight/highlights/index.ts b/packages/text-annotator/src/highlight/highlights/index.ts new file mode 100644 index 00000000..535943b5 --- /dev/null +++ b/packages/text-annotator/src/highlight/highlights/index.ts @@ -0,0 +1 @@ +export * from './highlightsRenderer' diff --git a/packages/text-annotator/src/highlight/index.ts b/packages/text-annotator/src/highlight/index.ts index cdd1a143..318d2628 100644 --- a/packages/text-annotator/src/highlight/index.ts +++ b/packages/text-annotator/src/highlight/index.ts @@ -1,2 +1,6 @@ +export * from './Highlight'; +export * from './HighlightStyle'; +export * from './HighlightPainter'; export * from './canvas'; -export * from './css'; \ No newline at end of file +export * from './highlights'; +export * from './span'; diff --git a/packages/text-annotator/src/highlight/span/index.ts b/packages/text-annotator/src/highlight/span/index.ts new file mode 100644 index 00000000..9d1fe54f --- /dev/null +++ b/packages/text-annotator/src/highlight/span/index.ts @@ -0,0 +1 @@ +export * from './spansRenderer'; \ No newline at end of file diff --git a/packages/text-annotator/src/highlight/span/spansRenderer.css b/packages/text-annotator/src/highlight/span/spansRenderer.css new file mode 100644 index 00000000..cd1b51c6 --- /dev/null +++ b/packages/text-annotator/src/highlight/span/spansRenderer.css @@ -0,0 +1,19 @@ +.r6o-annotatable .r6o-span-highlight-layer { + height: 100%; + left: 0; + pointer-events: none; + position: absolute; + top: 0; + width: 100%; +} + +.r6o-annotatable .r6o-span-highlight-layer.hidden { + display: none; +} + +.r6o-annotatable .r6o-span-highlight-layer .r6o-annotation { + border-style: solid; + border-width: 0; + position: absolute; + display: block; +} diff --git a/packages/text-annotator/src/highlight/span/spansRenderer.ts b/packages/text-annotator/src/highlight/span/spansRenderer.ts new file mode 100644 index 00000000..cf77c871 --- /dev/null +++ b/packages/text-annotator/src/highlight/span/spansRenderer.ts @@ -0,0 +1,126 @@ +import type { ViewportState } from '@annotorious/core'; +import { colord } from 'colord'; +import { dequal } from 'dequal/lite'; +import type { Rect, TextAnnotatorState } from '../../state'; +import { paint, type HighlightPainter } from '../HighlightPainter'; +import type { ViewportBounds } from '../viewport'; +import { createBaseRenderer, type RendererImplementation } from '../baseRenderer'; +import type { Highlight } from '../Highlight'; +import { DEFAULT_STYLE, type HighlightStyleExpression } from '../HighlightStyle'; + +import './spansRenderer.css'; + +const computeZIndex = (rect: Rect, all: Rect[]): number => { + const intersects = (a: Rect, b: Rect): boolean => ( + a.x <= b.x + b.width && a.x + a.width >= b.x && + a.y <= b.y + b.height && a.y + a.height >= b.y + ); + + return all.filter(other => ( + rect !== other && + intersects(rect, other) && + other.width > rect.width + )).length; +} + +const createRenderer = (container: HTMLElement): RendererImplementation => { + + container.classList.add('r6o-annotatable'); + + const highlightLayer = document.createElement('div'); + highlightLayer.className = 'r6o-span-highlight-layer'; + + container.insertBefore(highlightLayer, container.firstChild); + + let customPainter: HighlightPainter; + + // Currently rendered highlights + let currentRendered: Highlight[] = []; + + const redraw = ( + highlights: Highlight[], + viewportBounds: ViewportBounds, + currentStyle?: HighlightStyleExpression, + painter?: HighlightPainter, + lazy?: boolean + ) => { + // Only redraw if annotations or annotation states changed + const noChanges = dequal(currentRendered, highlights); + if (noChanges && lazy) return; + + highlightLayer.innerHTML = ''; + + if (customPainter) + customPainter.clear(); + + // Rects from all visible annotations, for z-index computation + const allRects = highlights.reduce((all, { rects }) => ([...all, ...rects]), []); + + highlights.forEach(highlight => { + const spans = highlight.rects.map(rect => { + const span = document.createElement('span'); + span.className = 'r6o-annotation'; + span.dataset.annotation = highlight.annotation.id; + + span.style.left = `${rect.x}px`; + span.style.top = `${rect.y}px`; + span.style.width = `${rect.width}px`; + span.style.height = `${rect.height}px`; + + const zIndex = computeZIndex(rect, allRects); + + const style = paint(highlight, viewportBounds, currentStyle, painter, zIndex); + + const backgroundColor = colord(style?.fill || DEFAULT_STYLE.fill) + .alpha(style?.fillOpacity === undefined ? DEFAULT_STYLE.fillOpacity : style.fillOpacity) + .toHex(); + + span.style.backgroundColor = backgroundColor; + + if (style.underlineStyle) + span.style.borderStyle = style.underlineStyle; + + if (style.underlineColor) + span.style.borderColor = style.underlineColor; + + if (style.underlineThickness) + span.style.borderBottomWidth = `${style.underlineThickness}px`; + + if (style.underlineOffset) + span.style.paddingBottom = `${style.underlineOffset}px`; + + highlightLayer.appendChild(span); + + return span; + }); + + return { id: highlight.annotation.id, spans }; + }); + + currentRendered = highlights; + } + + const setVisible = (visible: boolean) => { + if (visible) + highlightLayer.classList.remove('hidden'); + else + highlightLayer.classList.add('hidden'); + } + + const destroy = () => { + highlightLayer.remove(); + } + + return { + destroy, + redraw, + setVisible + } + +} + +export const createSpansRenderer = ( + container: HTMLElement, + state: TextAnnotatorState, + viewport: ViewportState +) => createBaseRenderer(container, state, viewport, createRenderer(container)); \ No newline at end of file diff --git a/packages/text-annotator/src/state/TextAnnotationStore.ts b/packages/text-annotator/src/state/TextAnnotationStore.ts index d2be4aa7..07c789f6 100644 --- a/packages/text-annotator/src/state/TextAnnotationStore.ts +++ b/packages/text-annotator/src/state/TextAnnotationStore.ts @@ -15,9 +15,7 @@ export interface TextAnnotationStore extends Omit, 'addAnn getAt(x: number, y: number): TextAnnotation | undefined; - getIntersecting(minX: number, minY: number, maxX: number, maxY: number): TextAnnotation[]; - - getIntersectingRects(minX: number, minY: number, maxX: number, maxY: number): AnnotationRects[]; + getIntersecting(minX: number, minY: number, maxX: number, maxY: number): AnnotationRects[]; recalculatePositions(): void; diff --git a/packages/text-annotator/src/state/TextAnnotatorState.ts b/packages/text-annotator/src/state/TextAnnotatorState.ts index d7e0be98..b1805057 100644 --- a/packages/text-annotator/src/state/TextAnnotatorState.ts +++ b/packages/text-annotator/src/state/TextAnnotatorState.ts @@ -9,9 +9,9 @@ import { Origin, createViewportState } from '@annotorious/core'; -import { IndexedHighlightRect, createSpatialTree } from './spatialTree'; +import { createSpatialTree } from './spatialTree'; import type { TextAnnotation, TextAnnotationTarget } from '../model'; -import type { AnnotationRects, TextAnnotationStore } from './TextAnnotationStore'; +import type { TextAnnotationStore } from './TextAnnotationStore'; import { isRevived, reviveAnnotation, reviveTarget } from '../utils'; export interface TextAnnotatorState extends AnnotatorState { @@ -112,17 +112,8 @@ export const createTextAnnotatorState = ( return annotationId ? store.getAnnotation(annotationId) : undefined; } - const getIntersecting = (minX: number, minY: number, maxX: number, maxY: number) => { - const rects = tree.getIntersectingRects(minX, minY, maxX, maxY); - const ids = Array.from(new Set(rects.map(item => item.annotation.id))); - - // Note that the tree could be slightly out of sync (because it updates - // by listening to changes, just like anyone else) - return ids.map(id => store.getAnnotation(id)).filter(Boolean); - } - const getAnnotationBounds = (id: string, x?: number, y?: number, buffer = 5): DOMRect => { - const rects = tree.getDOMRectsForAnnotation(id); + const rects = tree.getAnnotationRects(id); if (rects.length === 0) return; if (x && y) { @@ -133,30 +124,7 @@ export const createTextAnnotatorState = ( if (match) return match; } - return tree.getBoundsForAnnotation(id); - } - - const getIntersectingRects = ( - minX: number, - minY: number, - maxX: number, - maxY: number - ): AnnotationRects[] => { - const rects = tree.getIntersectingRects(minX, minY, maxX, maxY); - - // Group by annotation ID - const groupedByAnnotationId: { [key:string]: IndexedHighlightRect[] } = rects.reduce((grouped, rect) => { - (grouped[rect.annotation.id] = grouped[rect.annotation.id] || []).push(rect); - return grouped; - }, {}); - - // Resolve annotation IDs. Note that the tree could be slightly out of sync (because - // it updates by listening to changes, just like anyone else) - return Object.entries(groupedByAnnotationId).map(([annotationId, rects]) => ({ - annotation: store.getAnnotation(annotationId), - rects: rects.map(({ minX, minY, maxX, maxY }) => - ({ x: minX, y: minY, width: maxX - minX, height: maxY - minY })) - })).filter(t => Boolean(t.annotation)); + return tree.getAnnotationBounds(id); } const recalculatePositions = () => tree.recalculate(); @@ -185,8 +153,7 @@ export const createTextAnnotatorState = ( bulkUpsertAnnotations, getAnnotationBounds, getAt, - getIntersecting, - getIntersectingRects, + getIntersecting: tree.getIntersecting, recalculatePositions, updateTarget }, diff --git a/packages/text-annotator/src/state/spatialTree.ts b/packages/text-annotator/src/state/spatialTree.ts index ff76dd2d..ea8b9f35 100644 --- a/packages/text-annotator/src/state/spatialTree.ts +++ b/packages/text-annotator/src/state/spatialTree.ts @@ -4,12 +4,13 @@ import type { TextAnnotation, TextAnnotationTarget } from '../model'; import { mergeClientRects } from '../utils'; import { getClientRectsPonyfill } from '../utils/getClientRectsPonyfill'; import { reviveSelector } from '../utils'; +import type { AnnotationRects } from './TextAnnotationStore'; const isFirefox = false; // navigator.userAgent.match(/firefox|fxios/i); if (isFirefox) console.warn('Firefox interop enabled'); -export interface IndexedHighlightRect { +interface IndexedHighlightRect { minX: number; @@ -36,9 +37,7 @@ export const createSpatialTree = (store: Store, container: HTMLE const index = new Map(); // Helper: converts a single text annotation target to a list of hightlight rects - const toItems = (target: TextAnnotationTarget): IndexedHighlightRect[] => { - const offset = container.getBoundingClientRect(); - + const toItems = (target: TextAnnotationTarget, offset: DOMRect): IndexedHighlightRect[] => { const rects = target.selector.flatMap(s => { const isValidRange = s.range instanceof Range && @@ -53,16 +52,20 @@ export const createSpatialTree = (store: Store, container: HTMLE Array.from(revivedRange.getClientRects()); }); - const merged = mergeClientRects(rects); + const merged = mergeClientRects(rects) + // Offset the merged client rects so that coords + // are relative to the parent container + .map(({ left, top, right, bottom }) => + new DOMRect(left - offset.left, top - offset.top, right - left, bottom - top)); return merged.map(rect => { const { x, y, width, height } = rect; return { - minX: x - offset.x, - minY: y - offset.y, - maxX: x - offset.x + width, - maxY: y - offset.y + height, + minX: x, + minY: y, + maxX: x + width, + maxY: y + height, annotation: { id: target.annotation, rects: merged @@ -79,7 +82,8 @@ export const createSpatialTree = (store: Store, container: HTMLE } const insert = (target: TextAnnotationTarget) => { - const rects = toItems(target); + const rects = toItems(target, container.getBoundingClientRect()); + rects.forEach(rect => tree.insert(rect)); index.set(target.annotation, rects); } @@ -101,7 +105,9 @@ export const createSpatialTree = (store: Store, container: HTMLE if (replace) clear(); - const rectsByTarget = targets.map(target => ({ target, rects: toItems(target) })); + const offset = container.getBoundingClientRect(); + + const rectsByTarget = targets.map(target => ({ target, rects: toItems(target, offset) })); rectsByTarget.forEach(({ target, rects }) => index.set(target.annotation, rects)); const allRects = rectsByTarget.reduce((all, { rects }) => [...all, ...rects], []); @@ -127,8 +133,8 @@ export const createSpatialTree = (store: Store, container: HTMLE } } - const getBoundsForAnnotation = (id: string): DOMRect => { - const rects = getDOMRectsForAnnotation(id); + const getAnnotationBounds = (id: string): DOMRect => { + const rects = getAnnotationRects(id); if (rects.length === 0) return undefined; @@ -150,7 +156,7 @@ export const createSpatialTree = (store: Store, container: HTMLE return new DOMRect(left, top, right - left, bottom - top); } - const getDOMRectsForAnnotation = (id: string): DOMRect[] => { + const getAnnotationRects = (id: string): DOMRect[] => { const indexed = index.get(id); if (indexed) { // Reminder: *each* IndexedHighlightRect stores *all* @@ -161,8 +167,25 @@ export const createSpatialTree = (store: Store, container: HTMLE } } - const getIntersectingRects = (minX: number, minY: number, maxX: number, maxY: number) => - tree.search({ minX, minY, maxX, maxY }); + const getIntersecting = ( + minX: number, + minY: number, + maxX: number, + maxY: number, + ): AnnotationRects[] => { + // All rects in this area, regardless of annotation + const rects = tree.search({ minX, minY, maxX, maxY }); + + // Distinct annotation IDs + const annotationIds = new Set(rects.reduce((ids, rect) => ([...ids, rect.annotation.id]), [])); + + // Resolve annotation IDs. Note that the tree could be slightly out of sync (because + // it updates by listening to changes, just like anyone else) + return Array.from(annotationIds).map(annotationId => ({ + annotation: store.getAnnotation(annotationId), + rects: getAnnotationRects(annotationId) + })).filter(t => Boolean(t.annotation)); + } const size = () => tree.all().length; @@ -173,9 +196,9 @@ export const createSpatialTree = (store: Store, container: HTMLE all, clear, getAt, - getBoundsForAnnotation, - getDOMRectsForAnnotation, - getIntersectingRects, + getAnnotationBounds, + getAnnotationRects, + getIntersecting, insert, recalculate, remove, diff --git a/packages/text-annotator/src/utils/splitAnnotatableRanges.ts b/packages/text-annotator/src/utils/splitAnnotatableRanges.ts index f580fe79..d91f45da 100644 --- a/packages/text-annotator/src/utils/splitAnnotatableRanges.ts +++ b/packages/text-annotator/src/utils/splitAnnotatableRanges.ts @@ -1,4 +1,4 @@ -const NOT_ANNOTATABLE_CLASS = 'not-annotatable'; +export const NOT_ANNOTATABLE_CLASS = 'not-annotatable'; export const NOT_ANNOTATABLE_SELECTOR = `.${NOT_ANNOTATABLE_CLASS}`; @@ -14,7 +14,10 @@ const iterateNotAnnotatableElements = function*(range: Range): Generator - node instanceof HTMLElement && node.classList.contains(NOT_ANNOTATABLE_CLASS) && range.intersectsNode(node) + node instanceof HTMLElement // Only elements that can have the class applied + && node.classList.contains(NOT_ANNOTATABLE_CLASS) // Only elements that are not annotatable + && !node.parentElement.closest(NOT_ANNOTATABLE_SELECTOR) // Only elements that are not descendants of a not annotatable element + && range.intersectsNode(node) // Only elements that are within the range ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_SKIP ); diff --git a/packages/text-annotator/test/annotations.w3c.json b/packages/text-annotator/test/annotations.w3c.json index cb250aa8..a2c81216 100644 --- a/packages/text-annotator/test/annotations.w3c.json +++ b/packages/text-annotator/test/annotations.w3c.json @@ -82,5 +82,65 @@ } ] } + }, + { + "id": "d254db75-0950-4cd0-89c9-6a41af09bd06", + "@context": "http://www.w3.org/ns/anno.jsonld", + "type": "Annotation", + "body": [], + "creator": { + "isGuest": true, + "id": "htjjQ0q46ZxyQajyl__F" + }, + "created": "2024-03-26T12:55:49.144Z", + "target": [ + { + "annotation": "d254db75-0950-4cd0-89c9-6a41af09bd06", + "source": "https://www.gutenberg.org", + "selector": [ + { + "type": "TextQuoteSelector", + "exact": "t as years went by, the", + "prefix": "ry him. Bu", + "suffix": "re came a " + }, + { + "type": "TextPositionSelector", + "start": 988, + "end": 1011 + } + ] + } + ] + }, + { + "id": "7bae8714-63d9-4e31-9458-ca3aa465bd1b", + "@context": "http://www.w3.org/ns/anno.jsonld", + "type": "Annotation", + "body": [], + "creator": { + "isGuest": true, + "id": "htjjQ0q46ZxyQajyl__F" + }, + "created": "2024-03-26T12:56:39.961Z", + "target": [ + { + "annotation": "7bae8714-63d9-4e31-9458-ca3aa465bd1b", + "source": "https://www.gutenberg.org", + "selector": [ + { + "type": "TextQuoteSelector", + "exact": "d to marry him. But as years we", + "prefix": " and wante", + "suffix": "nt by, the" + }, + { + "type": "TextPositionSelector", + "start": 970, + "end": 1001 + } + ] + } + ] } -] +] \ No newline at end of file diff --git a/packages/text-annotator/test/index.html b/packages/text-annotator/test/index.html index f4ebd9a7..8be3f13d 100644 --- a/packages/text-annotator/test/index.html +++ b/packages/text-annotator/test/index.html @@ -24,7 +24,8 @@ } #content .not-annotatable { - background-color: wheat; + color: dimgray; + border: 3px solid wheat; } h1 { @@ -107,13 +108,16 @@
other gods:

-

- "See now, how men lay blame upon us gods for what is after all nothing but their own folly. Look at Aegisthus; - he must needs make love to Agamemnon's wife unrighteously and then kill Agamemnon, though he knew it would be - the death of him; for I sent Mercury to warn him not to do either of these things, inasmuch as Orestes would be - sure to take his revenge when he grew up and wanted to return home. Mercury told him this in all good will but - he would not listen, and now he has paid for everything in full." -

+
+

Not annotatable block!

+

+ "See now, how men lay blame upon us gods for what is after all nothing but their own folly. Look at Aegisthus; + he must needs make love to Agamemnon's wife unrighteously and then kill Agamemnon, though he knew it would be + the death of him; for I sent Mercury to warn him not to do either of these things, inasmuch as Orestes would be + sure to take his revenge when he grew up and wanted to return home. Mercury told him this in all good will but + he would not listen, and now he has paid for everything in full." +

+

Then Minerva said, "Father, son of Saturn, King of kings, it served Aegisthus right, and so it would any one @@ -283,9 +287,17 @@

window.onload = async () => { var contentContainer = document.getElementById('content'); + const style = ((annotation, state, z) => ({ + fillOpacity: 0.2, + underlineColor: '#00ff00', + underlineOffset: z * 3.5, + underlineThickness: 2 + })); + var r = createTextAnnotator(contentContainer, { adapter: W3CTextFormat('https://www.gutenberg.org', contentContainer), - experimentalCSSRenderer: true + renderer: 'SPANS', + style }); var annotations; @@ -371,6 +383,9 @@
}) } }); + + // Make global so we can manipulate from the console + window.r = r; } diff --git a/update-version.js b/update-version.js new file mode 100644 index 00000000..150de241 --- /dev/null +++ b/update-version.js @@ -0,0 +1,58 @@ +const fs = require('fs'); +const path = require('path'); + +const searchDirectories = (dir, fileList = []) => { + const files = fs.readdirSync(dir); + + files.forEach(file => { + const filePath = path.join(dir, file); + if (fs.statSync(filePath).isDirectory()) { + if (file !== 'node_modules') + fileList = searchDirectories(filePath, fileList); + } else { + if (file === 'package.json') { + fileList.push(filePath); + } + } + }); + + return fileList; +}; + +const updateVersionNumbers = (filePath, newVersion) => { + try { + let packageJson = fs.readFileSync(filePath, 'utf8'); + const packageData = JSON.parse(packageJson); + + packageData.version = newVersion; + + ['dependencies', 'peerDependencies'].forEach(depType => { + if (packageData[depType]) { + for (const dep in packageData[depType]) { + if (dep.startsWith('@recogito/text-')) { + packageData[depType][dep] = newVersion; + } + } + } + }); + + fs.writeFileSync(filePath, JSON.stringify(packageData, null, 2), 'utf8'); + console.log(`Updated ${filePath}`); + } catch (error) { + console.error(`Error updating ${filePath}: ${error}`); + } +} + +const main = () => { + const newVersion = process.argv[2]; + + const packageJsonFiles = searchDirectories('.'); + + packageJsonFiles.forEach(filePath => { + updateVersionNumbers(filePath, newVersion); + }); + + console.log(`All package.json files updated to version ${newVersion}`); +}; + +main(); \ No newline at end of file