From 599234cefec9ffdd97b01289dcbabe283a9cfaff Mon Sep 17 00:00:00 2001 From: rittiev Date: Tue, 5 Aug 2025 16:52:54 +0100 Subject: [PATCH 01/15] config files from react to preact --- .eslintrc.cjs | 8 +- package.json | 20 +- pnpm-lock.yaml | 678 ++++++++++-------- .../InvalidBackgroundSelectionMessage.tsx | 3 +- src/ui/index.tsx | 7 +- .../blend-modes/map-figma-blend-to-canvas.ts | 2 +- tsconfig.json | 3 +- vite.config.ui.ts | 5 +- 8 files changed, 400 insertions(+), 326 deletions(-) diff --git a/.eslintrc.cjs b/.eslintrc.cjs index bdd1b7a..1ee821e 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -5,7 +5,7 @@ module.exports = { }, extends: [ 'standard-with-typescript', - 'plugin:react/recommended', + 'plugin:eslint-config-preact', 'prettier', 'plugin:perfectionist/recommended-alphabetical', 'plugin:tailwindcss/recommended', @@ -28,11 +28,11 @@ module.exports = { sourceType: 'module', project: './tsconfig.json', }, - plugins: ['react', 'prettier', 'jsx-a11y', 'boundaries'], + plugins: ['preact', 'prettier', 'jsx-a11y', 'boundaries'], rules: { 'import/no-default-export': 'error', 'func-style': ['error', 'expression'], - 'react/react-in-jsx-scope': 'off', + 'preact/preact-in-jsx-scope': 'off', 'boundaries/element-types': [ 2, { @@ -67,7 +67,7 @@ module.exports = { ['~test-utils', './src/test-utils'], ], }, - react: { + preact: { version: 'detect', }, 'boundaries/elements': [ diff --git a/package.json b/package.json index 94623db..e9953ae 100644 --- a/package.json +++ b/package.json @@ -20,13 +20,11 @@ "dependencies": { "@figma/plugin-typings": "^1.79.0", "@floating-ui/react": "^0.25.2", - "@nanostores/react": "^0.7.1", - "@testing-library/react": "^14.0.0", + "@nanostores/preact": "^1.0.0", + "@preact/compat": "^18.3.1", + "@preact/signals": "^2.2.1", "@types/apca-w3": "^0.1.0", "@types/culori": "^2.0.0", - "@types/react": "^18.2.14", - "@types/react-dom": "^18.2.6", - "@vitejs/plugin-react": "^4.0.1", "@vitest/coverage-v8": "^0.34.1", "apca-w3": "^0.1.9", "apcach": "^0.6.0", @@ -40,9 +38,7 @@ "postcss": "^8.4.24", "postcss-loader": "^7.3.3", "postcss-preset-env": "^9.0.0", - "react": "^18.2.0", - "react-dom": "^18.2.0", - "react-use-clipboard": "^1.0.9", + "preact": "^10.25.3", "tailwindcss": "^3.3.2", "typescript": "^5.0.2", "uint8-to-hex": "^2.0.0", @@ -52,11 +48,13 @@ "vitest": "^0.34.1" }, "devDependencies": { + "@preact/preset-vite": "^2.10.2", "@size-limit/preset-small-lib": "^11.2.0", "@types/node": "^20.4.1", "@typescript-eslint/eslint-plugin": "^5.61.0", "@typescript-eslint/parser": "^5.61.0", "eslint": "^8.44.0", + "eslint-config-preact": "^2.0.0", "eslint-config-prettier": "^8.8.0", "eslint-config-standard-with-typescript": "^36.0.0", "eslint-import-resolver-alias": "^1.1.2", @@ -66,9 +64,6 @@ "eslint-plugin-perfectionist": "^1.4.0", "eslint-plugin-prettier": "^4.2.1", "eslint-plugin-promise": "^6.0.0", - "eslint-plugin-react": "^7.32.2", - "eslint-plugin-react-hooks": "^4.6.0", - "eslint-plugin-react-refresh": "^0.4.1", "eslint-plugin-tailwindcss": "^3.13.0", "jsdom": "^22.1.0", "prettier": "^3.0.2", @@ -80,5 +75,6 @@ "path": "dist/api.js" } ], - "license": "MIT" + "license": "MIT", + "packageManager": "pnpm@9.13.2+sha1.969cc200a41db98449afee1bfa7578b3ce6ff330" } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 13c49ea..fcb3a60 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -14,27 +14,21 @@ importers: '@floating-ui/react': specifier: ^0.25.2 version: 0.25.4(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@nanostores/react': - specifier: ^0.7.1 - version: 0.7.3(nanostores@0.9.5)(react@18.3.1) - '@testing-library/react': - specifier: ^14.0.0 - version: 14.3.1(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@nanostores/preact': + specifier: ^1.0.0 + version: 1.0.0(nanostores@0.9.5)(preact@10.27.0) + '@preact/compat': + specifier: ^18.3.1 + version: 18.3.1(preact@10.27.0) + '@preact/signals': + specifier: ^2.2.1 + version: 2.2.1(preact@10.27.0) '@types/apca-w3': specifier: ^0.1.0 version: 0.1.3 '@types/culori': specifier: ^2.0.0 version: 2.1.1 - '@types/react': - specifier: ^18.2.14 - version: 18.3.23 - '@types/react-dom': - specifier: ^18.2.6 - version: 18.3.7(@types/react@18.3.23) - '@vitejs/plugin-react': - specifier: ^4.0.1 - version: 4.7.0(vite@4.5.14(@types/node@20.19.9)(terser@5.43.1)) '@vitest/coverage-v8': specifier: ^0.34.1 version: 0.34.6(vitest@0.34.6(jsdom@22.1.0)(terser@5.43.1)) @@ -74,15 +68,9 @@ importers: postcss-preset-env: specifier: ^9.0.0 version: 9.6.0(postcss@8.5.6) - react: - specifier: ^18.2.0 - version: 18.3.1 - react-dom: - specifier: ^18.2.0 - version: 18.3.1(react@18.3.1) - react-use-clipboard: - specifier: ^1.0.9 - version: 1.0.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + preact: + specifier: ^10.25.3 + version: 10.27.0 tailwindcss: specifier: ^3.3.2 version: 3.4.17 @@ -105,6 +93,9 @@ importers: specifier: ^0.34.1 version: 0.34.6(jsdom@22.1.0)(terser@5.43.1) devDependencies: + '@preact/preset-vite': + specifier: ^2.10.2 + version: 2.10.2(@babel/core@7.28.0)(preact@10.27.0)(vite@4.5.14(@types/node@20.19.9)(terser@5.43.1)) '@size-limit/preset-small-lib': specifier: ^11.2.0 version: 11.2.0(size-limit@11.2.0) @@ -120,6 +111,9 @@ importers: eslint: specifier: ^8.44.0 version: 8.57.1 + eslint-config-preact: + specifier: ^2.0.0 + version: 2.0.0(eslint@8.57.1) eslint-config-prettier: specifier: ^8.8.0 version: 8.10.2(eslint@8.57.1) @@ -147,15 +141,6 @@ importers: eslint-plugin-promise: specifier: ^6.0.0 version: 6.6.0(eslint@8.57.1) - eslint-plugin-react: - specifier: ^7.32.2 - version: 7.37.5(eslint@8.57.1) - eslint-plugin-react-hooks: - specifier: ^4.6.0 - version: 4.6.2(eslint@8.57.1) - eslint-plugin-react-refresh: - specifier: ^0.4.1 - version: 0.4.20(eslint@8.57.1) eslint-plugin-tailwindcss: specifier: ^3.13.0 version: 3.18.2(tailwindcss@3.4.17) @@ -194,10 +179,21 @@ packages: resolution: {integrity: sha512-UlLAnTPrFdNGoFtbSXwcGFQBtQZJCNjaN6hQNP3UPvuNXT1i82N26KL3dZeIpNalWywr9IuQuncaAfUaS1g6sQ==} engines: {node: '>=6.9.0'} + '@babel/eslint-parser@7.28.0': + resolution: {integrity: sha512-N4ntErOlKvcbTt01rr5wj3y55xnIdx1ymrfIr8C2WnM1Y9glFgWaGDEULJIazOX3XM9NRzhfJ6zZnQ1sBNWU+w==} + engines: {node: ^10.13.0 || ^12.13.0 || >=14.0.0} + peerDependencies: + '@babel/core': ^7.11.0 + eslint: ^7.5.0 || ^8.0.0 || ^9.0.0 + '@babel/generator@7.28.0': resolution: {integrity: sha512-lJjzvrbEeWrhB4P3QBsH7tey117PjLZnDbLiQEKjQ/fNJTjuq4HSqgFA+UNSwZT8D7dxxbnuSBMsa1lrWzKlQg==} engines: {node: '>=6.9.0'} + '@babel/helper-annotate-as-pure@7.27.3': + resolution: {integrity: sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==} + engines: {node: '>=6.9.0'} + '@babel/helper-compilation-targets@7.27.2': resolution: {integrity: sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==} engines: {node: '>=6.9.0'} @@ -241,21 +237,28 @@ packages: engines: {node: '>=6.0.0'} hasBin: true - '@babel/plugin-transform-react-jsx-self@7.27.1': - resolution: {integrity: sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==} + '@babel/plugin-syntax-class-properties@7.12.13': + resolution: {integrity: sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-jsx@7.27.1': + resolution: {integrity: sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-react-jsx-source@7.27.1': - resolution: {integrity: sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==} + '@babel/plugin-transform-react-jsx-development@7.27.1': + resolution: {integrity: sha512-ykDdF5yI4f1WrAolLqeF3hmYU12j9ntLQl/AOG1HAS21jxyg1Q0/J/tpREuYLfatGdGmXp/3yS0ZA76kOlVq9Q==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/runtime@7.27.6': - resolution: {integrity: sha512-vbavdySgbTTrmFE+EsiqUTzlOr5bzlnJtUv9PynGCAKvfQqjIXbvFdumPM/GxMDfyuGMJaJAU6TO4zc1Jf1i8Q==} + '@babel/plugin-transform-react-jsx@7.27.1': + resolution: {integrity: sha512-2KH4LWGSrJIkVf5tSiBFYuXDAoWRq2MMwgivCf+93dd0GQi8RXLjKA/0EvRnVV5G0hrHczsquXuD01L8s6dmBw==} engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 '@babel/template@7.27.2': resolution: {integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==} @@ -818,6 +821,10 @@ packages: resolution: {integrity: sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + '@eslint/js@9.32.0': + resolution: {integrity: sha512-BBpRFZK3eX6uMLKz8WxFOBIFFcGFJ/g8XuwjTHCqHROSIsopI+ddn/d5Cfh36+7+e5edVS8dbSHnBNhrLEX0zg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@figma/plugin-typings@1.116.0': resolution: {integrity: sha512-jpn7Vq3uxgJF5oQ5PwkWGGIyCwIjB260UjtSzBck9LL1WzXJSaxBH1wo+vrU4XXbV//TURUGBYIQ2tU7cdyRYQ==} @@ -889,12 +896,18 @@ packages: '@juanelas/base64@1.1.5': resolution: {integrity: sha512-mjAF27LzwfYobdwqnxZgeucbKT5wRRNvILg3h5OvCWK+3F7mw/A1tnjHnNiTYtLmTvT/bM1jA5AX7eQawDGs1w==} - '@nanostores/react@0.7.3': - resolution: {integrity: sha512-/XuLAMENRu/Q71biW4AZ4qmU070vkZgiQ28gaTSNRPm2SZF5zGAR81zPE1MaMB4SeOp6ZTst92NBaG75XSspNg==} - engines: {node: ^18.0.0 || >=20.0.0} + '@mdn/browser-compat-data@5.7.6': + resolution: {integrity: sha512-7xdrMX0Wk7grrTZQwAoy1GkvPMFoizStUoL+VmtUkAxegbCCec+3FKwOM6yc/uGU5+BEczQHXAlWiqvM8JeENg==} + + '@nanostores/preact@1.0.0': + resolution: {integrity: sha512-woHYvSwau1YtO9AEnGsh/jRPU2u5DTfNSrDHtKMZOeDUWV6EJfvyv7dJ7AaMps2I9uJcY6OlqXKkA9qTctEjyw==} + engines: {node: ^20.0.0 || >=22.0.0} peerDependencies: - nanostores: ^0.9.0 || ^0.10.0 || ^0.11.0 - react: '>=18.0.0' + nanostores: ^0.9.0 || ^0.10.0 || ^0.11.0 || ^1.0.0 + preact: '>=10.0.0' + + '@nicolo-ribaudo/eslint-scope-5-internals@5.1.1-v1': + resolution: {integrity: sha512-54/JRvkLIzzDWshCWfuhadfrfZVPiElY8Fcgmg1HroEly/EDSszzhBAsarCux+D/kOslTRquNzuyGSmUSTTHGg==} '@nodelib/fs.scandir@2.1.5': resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} @@ -912,8 +925,45 @@ packages: resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} - '@rolldown/pluginutils@1.0.0-beta.27': - resolution: {integrity: sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==} + '@preact/compat@18.3.1': + resolution: {integrity: sha512-Kog4PSRxtT4COtOXjsuQPV1vMXpUzREQfv+6Dmcy9/rMk0HOPK0HTE9fspFjAmY8R80T/T8gtgmZ68u5bOSngw==} + peerDependencies: + preact: '*' + + '@preact/preset-vite@2.10.2': + resolution: {integrity: sha512-K9wHlJOtkE+cGqlyQ5v9kL3Ge0Ql4LlIZjkUTL+1zf3nNdF88F9UZN6VTV8jdzBX9Fl7WSzeNMSDG7qECPmSmg==} + peerDependencies: + '@babel/core': 7.x + vite: 2.x || 3.x || 4.x || 5.x || 6.x || 7.x + + '@preact/signals-core@1.11.0': + resolution: {integrity: sha512-jglbibeWHuFRzEWVFY/TT7wB1PppJxmcSfUHcK+2J9vBRtiooMfw6tAPttojNYrrpdGViqAYCbPpmWYlMm+eMQ==} + + '@preact/signals@2.2.1': + resolution: {integrity: sha512-cX3mijdjHbbz3dBoJ6z687CGYEOp9ifj3uFnm4UKW+DxXKPMvE2y/VSdm0PXhXmHnr6F0iSnDJ+dLwmV7CYT5A==} + peerDependencies: + preact: '>= 10.25.0' + + '@prefresh/babel-plugin@0.5.2': + resolution: {integrity: sha512-AOl4HG6dAxWkJ5ndPHBgBa49oo/9bOiJuRDKHLSTyH+Fd9x00shTXpdiTj1W41l6oQIwUOAgJeHMn4QwIDpHkA==} + + '@prefresh/core@1.5.5': + resolution: {integrity: sha512-H6GTXUl4V4fe3ijz7yhSa/mZ+pGSOh7XaJb6uP/sQsagBx9yl0D1HKDaeoMQA8Ad2Xm27LqvbitMGSdY9UFSKQ==} + peerDependencies: + preact: ^10.0.0 + + '@prefresh/utils@1.2.1': + resolution: {integrity: sha512-vq/sIuN5nYfYzvyayXI4C2QkprfNaHUQ9ZX+3xLD8nL3rWyzpxOm1+K7RtMbhd+66QcaISViK7amjnheQ/4WZw==} + + '@prefresh/vite@2.4.8': + resolution: {integrity: sha512-H7vlo9UbJInuRbZhRQrdgVqLP7qKjDoX7TgYWWwIVhEHeHO0hZ4zyicvwBrV1wX5A3EPOmArgRkUaN7cPI2VXQ==} + peerDependencies: + preact: ^10.4.0 + vite: '>=2.0.0' + + '@rollup/pluginutils@4.2.1': + resolution: {integrity: sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ==} + engines: {node: '>= 8.0.0'} '@rollup/pluginutils@5.2.0': resolution: {integrity: sha512-qWJ2ZTbmumwiLFomfzTyt5Kng4hwPi9rwCYN4SHb6eaRU1KNO4ccxINHr/VhH4GgPlt1XfSTLX2LBTme8ne4Zw==} @@ -1015,17 +1065,6 @@ packages: peerDependencies: '@svgr/core': '*' - '@testing-library/dom@9.3.4': - resolution: {integrity: sha512-FlS4ZWlp97iiNWig0Muq8p+3rVDjRiYE+YKGbAqXOu9nwJFFOdL00kFpz42M+4huzYi86vAK1sOOfyOG45muIQ==} - engines: {node: '>=14'} - - '@testing-library/react@14.3.1': - resolution: {integrity: sha512-H99XjUhWQw0lTgyMN05W3xQG1Nh4lq574D8keFf1dDoNTJgp66VbJozRaczoF+wsiaPJNt/TcnfpLGufGxSrZQ==} - engines: {node: '>=14'} - peerDependencies: - react: ^18.0.0 - react-dom: ^18.0.0 - '@tootallnate/once@2.0.0': resolution: {integrity: sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==} engines: {node: '>= 10'} @@ -1033,21 +1072,6 @@ packages: '@types/apca-w3@0.1.3': resolution: {integrity: sha512-1C7e66xWCy1UOXHk/VXs4tjrY9hW3q3sykjJJxSC5TIIFt0lt9mh0ysdQxY0rVejTv4SW92G19j98PjqjCSz7Q==} - '@types/aria-query@5.0.4': - resolution: {integrity: sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==} - - '@types/babel__core@7.20.5': - resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} - - '@types/babel__generator@7.27.0': - resolution: {integrity: sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==} - - '@types/babel__template@7.4.4': - resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==} - - '@types/babel__traverse@7.20.7': - resolution: {integrity: sha512-dkO5fhS7+/oos4ciWxyEyjWe48zmG6wbCheo/G2ZnHx4fs3EU6YC6UM8rk56gAjNJ9P3MTH2jo5jb92/K6wbng==} - '@types/chai-subset@1.3.6': resolution: {integrity: sha512-m8lERkkQj+uek18hXOZuec3W/fCRTrU4hrnXjH3qhHy96ytuPaPiWGgu7sJb7tZxZonO75vYAjCvpe/e4VUwRw==} peerDependencies: @@ -1080,17 +1104,6 @@ packages: '@types/node@20.19.9': resolution: {integrity: sha512-cuVNgarYWZqxRJDQHEB58GEONhOK79QVR/qYx4S7kcUObQvUwvFnYxJuuHUKm2aieN9X3yZB4LZsuYNU1Qphsw==} - '@types/prop-types@15.7.15': - resolution: {integrity: sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==} - - '@types/react-dom@18.3.7': - resolution: {integrity: sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==} - peerDependencies: - '@types/react': ^18.0.0 - - '@types/react@18.3.23': - resolution: {integrity: sha512-/LDXMQh55EzZQ0uVAZmKKhfENivEvWz6E+EYzh+/MCjMhNsotd+ZHhBGIjFDTi6+fz0OhQQQLbTgdQIxxCsC0w==} - '@types/semver@7.7.0': resolution: {integrity: sha512-k107IF4+Xr7UHjwDc7Cfd6PRQfbdkiRabXGRjo07b4WyPahFBZCZ1sE+BNxYIJPPg73UkfOsVOLwqVc/6ETrIA==} @@ -1155,12 +1168,6 @@ packages: '@ungap/structured-clone@1.3.0': resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==} - '@vitejs/plugin-react@4.7.0': - resolution: {integrity: sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==} - engines: {node: ^14.18.0 || >=16.0.0} - peerDependencies: - vite: ^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 - '@vitest/coverage-v8@0.34.6': resolution: {integrity: sha512-fivy/OK2d/EsJFoEoxHFEnNGTg+MmdZBAVK9Ka4qhXR2K3J0DS08vcGVwzDtXSuUMabLv4KtPcpSKkcMXFDViw==} peerDependencies: @@ -1318,9 +1325,6 @@ packages: argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} - aria-query@5.1.3: - resolution: {integrity: sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==} - aria-query@5.3.2: resolution: {integrity: sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==} engines: {node: '>= 0.4'} @@ -1364,6 +1368,9 @@ packages: assertion-error@1.1.0: resolution: {integrity: sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==} + ast-metadata-inferer@0.8.1: + resolution: {integrity: sha512-ht3Dm6Zr7SXv6t1Ra6gFo0+kLDglHGrEbYihTkcycrbHw7WCcuhBzPlJYHEsIpycaUwzsJHje+vUcxXUX4ztTA==} + ast-types-flow@0.0.8: resolution: {integrity: sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==} @@ -1393,6 +1400,11 @@ packages: resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==} engines: {node: '>= 0.4'} + babel-plugin-transform-hook-names@1.0.2: + resolution: {integrity: sha512-5gafyjyyBTTdX/tQQ0hRgu4AhNHG/hqWi0ZZmg2xvs2FgRkJXzDNKBZCyoYqgFkovfDrgM8OoKg8karoUvWeCw==} + peerDependencies: + '@babel/core': ^7.12.10 + balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} @@ -1403,6 +1415,9 @@ packages: resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} engines: {node: '>=8'} + boolbase@1.0.0: + resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} + brace-expansion@1.1.12: resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==} @@ -1516,9 +1531,6 @@ packages: convert-source-map@2.0.0: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} - copy-to-clipboard@3.3.3: - resolution: {integrity: sha512-2KV8NhB5JqC3ky0r9PMCAZKbUHSwtEo4CwCs0KXgruG43gX5PMqDEBbVU4OUzw2MuAWUfsuFmWvEKG5QRfSnJA==} - cosmiconfig@8.3.6: resolution: {integrity: sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==} engines: {node: '>=14'} @@ -1550,6 +1562,13 @@ packages: peerDependencies: postcss: ^8.4 + css-select@5.2.2: + resolution: {integrity: sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==} + + css-what@6.2.2: + resolution: {integrity: sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==} + engines: {node: '>= 6'} + cssdb@8.3.1: resolution: {integrity: sha512-XnDRQMXucLueX92yDe0LPKupXetWoFOgawr4O4X41l5TltgK2NVbJJVDnnOywDYfW1sTJ28AcXGKOqdRKwCcmQ==} @@ -1562,9 +1581,6 @@ packages: resolution: {integrity: sha512-N4u2ABATi3Qplzf0hWbVCdjenim8F3ojEXpBDF5hBpjzW182MjNGLqfmQ0SkSPeQ+V86ZXgeH8aXj6kayd4jgg==} engines: {node: '>=14'} - csstype@3.1.3: - resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} - culori@3.3.0: resolution: {integrity: sha512-pHJg+jbuFsCjz9iclQBqyL3B2HLCBF71BwVNujUYEvCeQMvV97R59MNK3R2+jgJ3a1fcZgI9B3vYgz8lzr/BFQ==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -1612,10 +1628,6 @@ packages: resolution: {integrity: sha512-SUwdGfqdKOwxCPeVYjwSyRpJ7Z+fhpwIAtmCUdZIWZ/YP5R9WAsyuSgpLVDi9bjWoN2LXHNss/dk3urXtdQxGg==} engines: {node: '>=6'} - deep-equal@2.2.3: - resolution: {integrity: sha512-ZIwpnevOurS8bpT4192sqAowWM76JDKSHYzMLty3BZGSswgq6pBaH3DhCSW5xVAZICZyKdOBPjwww5wfgT/6PA==} - engines: {node: '>= 0.4'} - deep-is@0.1.4: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} @@ -1653,14 +1665,24 @@ packages: resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} engines: {node: '>=6.0.0'} - dom-accessibility-api@0.5.16: - resolution: {integrity: sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==} + dom-serializer@2.0.0: + resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==} + + domelementtype@2.3.0: + resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==} domexception@4.0.0: resolution: {integrity: sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw==} engines: {node: '>=12'} deprecated: Use your platform's native DOMException instead + domhandler@5.0.3: + resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==} + engines: {node: '>= 4'} + + domutils@3.2.2: + resolution: {integrity: sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==} + dot-case@3.0.4: resolution: {integrity: sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==} @@ -1707,9 +1729,6 @@ packages: resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} engines: {node: '>= 0.4'} - es-get-iterator@1.1.3: - resolution: {integrity: sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==} - es-iterator-helpers@1.2.1: resolution: {integrity: sha512-uDn+FE1yrDzyC0pCo961B2IHbdM8y/ACZsKD4dG6WqrjV53BADjwa7D+1aom2rsNVfLyDgU/eigvlJGJ08OQ4w==} engines: {node: '>= 0.4'} @@ -1751,6 +1770,11 @@ packages: resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} engines: {node: '>=10'} + eslint-config-preact@2.0.0: + resolution: {integrity: sha512-TFj70lEE7y3R9DQAFJ/clRfVmyaXdwE3q56gA9zm+iTmlpYjtZKtV1jv/jtgdF2LqgvJjlGlGE1rHVwE9yNdkg==} + peerDependencies: + eslint: ^8.57.1 || ^9.0.0 + eslint-config-prettier@8.10.2: resolution: {integrity: sha512-/IGJ6+Dka158JnP5n5YFMOszjDWrXggGz1LaK/guZq9vZTmniaKlHcsscvkAhn9y4U+BU3JuUdYvtAMcv30y4A==} hasBin: true @@ -1834,6 +1858,12 @@ packages: peerDependencies: eslint: '>=6.0.0' + eslint-plugin-compat@6.0.2: + resolution: {integrity: sha512-1ME+YfJjmOz1blH0nPZpHgjMGK4kjgEeoYqGCqoBPQ/mGu/dJzdoP0f1C8H2jcWZjzhZjAMccbM/VdXhPORIfA==} + engines: {node: '>=18.x'} + peerDependencies: + eslint: ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0 + eslint-plugin-es@4.1.0: resolution: {integrity: sha512-GILhQTnjYE2WorX5Jyi5i4dz5ALWxBIdQECVQavL6s7cI76IZTDWleTHkxz/QT3kvcs2QlGHvKLYsSlPOlPXnQ==} engines: {node: '>=8.10.0'} @@ -1884,16 +1914,11 @@ packages: peerDependencies: eslint: ^7.0.0 || ^8.0.0 || ^9.0.0 - eslint-plugin-react-hooks@4.6.2: - resolution: {integrity: sha512-QzliNJq4GinDBcD8gPB5v0wh6g8q3SUi6EFF0x8N/BL9PoVs0atuGc47ozMRyOWAKdwaZ5OnbOEa3WR+dSGKuQ==} + eslint-plugin-react-hooks@5.2.0: + resolution: {integrity: sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg==} engines: {node: '>=10'} peerDependencies: - eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 - - eslint-plugin-react-refresh@0.4.20: - resolution: {integrity: sha512-XpbHQ2q5gUF8BGOX4dHe+71qoirYMhApEPZ7sfhF/dNnOF1UXnCMGZf79SFTBO7Bz5YEIT4TMieSlJBWhP9WBA==} - peerDependencies: - eslint: '>=8.40' + eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 eslint-plugin-react@7.37.5: resolution: {integrity: sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==} @@ -2102,6 +2127,14 @@ packages: resolution: {integrity: sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==} engines: {node: '>=8'} + globals@15.15.0: + resolution: {integrity: sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg==} + engines: {node: '>=18'} + + globals@16.3.0: + resolution: {integrity: sha512-bqWEnJ1Nt3neqx2q5SFfGS8r/ahumIakg3HcwtNlrVlwXIeNumWn/c7Pn/wKzGhf6SaW6H6uWXLqC30STCMchQ==} + engines: {node: '>=18'} + globalthis@1.0.4: resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==} engines: {node: '>= 0.4'} @@ -2147,6 +2180,10 @@ packages: resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} engines: {node: '>= 0.4'} + he@1.2.0: + resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==} + hasBin: true + hex-encoding@2.0.3: resolution: {integrity: sha512-sSmMo4ij2Vejht+5UkzuzNGiYgIWTSUw0GQqxHIQXsuuXB1ozYnjCZJZ/nwWNYRoU8+92Dp736wqxmiAN6/fcw==} @@ -2192,10 +2229,6 @@ packages: resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==} engines: {node: '>= 0.4'} - is-arguments@1.2.0: - resolution: {integrity: sha512-7bVbi0huj/wrIAOzb8U1aszg9kdi3KN/CyU19CTI7tAoZYEZoL9yCDXpbXN+uPsuWnP02cyug1gleqq+TU+YCA==} - engines: {node: '>= 0.4'} - is-array-buffer@3.0.5: resolution: {integrity: sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==} engines: {node: '>= 0.4'} @@ -2410,6 +2443,9 @@ packages: keyv@4.5.4: resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + kolorist@1.8.0: + resolution: {integrity: sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==} + language-subtag-registry@0.3.23: resolution: {integrity: sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ==} @@ -2440,6 +2476,9 @@ packages: resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} engines: {node: '>=10'} + lodash.memoize@4.1.2: + resolution: {integrity: sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==} + lodash.merge@4.6.2: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} @@ -2459,10 +2498,6 @@ packages: lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} - lz-string@1.5.0: - resolution: {integrity: sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==} - hasBin: true - magic-string@0.30.17: resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==} @@ -2557,6 +2592,9 @@ packages: node-buffer-encoding@1.0.3: resolution: {integrity: sha512-9hJZNChhQoCN1rCFScJiEwtzvWEJw2wSnu2nhDLD/YOYl1Ce8GbtnorsnjwwjpSk4sWE7zSp2etX6j7+bO7fVA==} + node-html-parser@6.1.13: + resolution: {integrity: sha512-qIsTMOY4C/dAa5Q5vsobRpOOvPfC4pB61UVW2uSwZNUp0QU/jCekTal1vMmbO0DgdHeLUJpv/ARmDqErVxA3Sg==} + node-releases@2.0.19: resolution: {integrity: sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==} @@ -2568,6 +2606,9 @@ packages: resolution: {integrity: sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==} engines: {node: '>=0.10.0'} + nth-check@2.1.1: + resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} + nwsapi@2.2.20: resolution: {integrity: sha512-/ieB+mDe4MrrKMT8z+mQL8klXydZWGR5Dowt4RAGKbJ3kIGEx3X4ljUo+6V73IXtUPWgfOlU5B9MlGxFO5T+cA==} @@ -2583,10 +2624,6 @@ packages: resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} engines: {node: '>= 0.4'} - object-is@1.1.6: - resolution: {integrity: sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==} - engines: {node: '>= 0.4'} - object-keys@1.1.1: resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} engines: {node: '>= 0.4'} @@ -2907,6 +2944,9 @@ packages: resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} engines: {node: ^10 || ^12 || >=14} + preact@10.27.0: + resolution: {integrity: sha512-/DTYoB6mwwgPytiqQTh/7SFRL98ZdiD8Sk8zIUVOxtwq4oWcwrcd1uno9fE/zZmUaUrFNYzbH14CPebOz9tZQw==} + prelude-ls@1.2.1: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} engines: {node: '>= 0.8.0'} @@ -2920,10 +2960,6 @@ packages: engines: {node: '>=14'} hasBin: true - pretty-format@27.5.1: - resolution: {integrity: sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==} - engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} - pretty-format@29.7.0: resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -2955,22 +2991,9 @@ packages: react-is@16.13.1: resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} - react-is@17.0.2: - resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==} - react-is@18.3.1: resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} - react-refresh@0.17.0: - resolution: {integrity: sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==} - engines: {node: '>=0.10.0'} - - react-use-clipboard@1.0.9: - resolution: {integrity: sha512-OcMzc14usXhqQnAkvzmhCXAbW5WBT2LSgscVh2vKHXZfg72jFsSOsEearqdeC/nUj8YxEfLnziqe7AE7YkWFwA==} - peerDependencies: - react: ^16.8.0 || ^17 || ^18 - react-dom: ^16.8.0 || ^17 || ^18 - react@18.3.1: resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==} engines: {node: '>=0.10.0'} @@ -3125,6 +3148,9 @@ packages: resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} engines: {node: '>=14'} + simple-code-frame@1.3.0: + resolution: {integrity: sha512-MB4pQmETUBlNs62BBeRjIFGeuy/x6gGKh7+eRUemn1rCFhqo7K+4slPqsyizCbcbYLnaYqaoZ2FWsZ/jN06D8w==} + size-limit@11.2.0: resolution: {integrity: sha512-2kpQq2DD/pRpx3Tal/qRW1SYwcIeQ0iq8li5CJHQgOC+FtPn2BVmuDtzUCgNnpCrbgtfEHqh+iWzxK+Tq6C+RQ==} engines: {node: ^18.0.0 || >=20.0.0} @@ -3148,6 +3174,14 @@ packages: resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} engines: {node: '>=0.10.0'} + source-map@0.7.6: + resolution: {integrity: sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==} + engines: {node: '>= 12'} + + stack-trace@1.0.0-pre2: + resolution: {integrity: sha512-2ztBJRek8IVofG9DBJqdy2N5kulaacX30Nz7xmkYF6ale9WBVmIy6mFBchvGX7Vx/MyjBhx+Rcxqrj+dbOnQ6A==} + engines: {node: '>=16'} + stackback@0.0.2: resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} @@ -3297,9 +3331,6 @@ packages: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} - toggle-selection@1.0.6: - resolution: {integrity: sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ==} - tough-cookie@4.1.4: resolution: {integrity: sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==} engines: {node: '>=6'} @@ -3415,6 +3446,11 @@ packages: peerDependencies: vite: ^2.6.0 || 3 || 4 + vite-prerender-plugin@0.5.11: + resolution: {integrity: sha512-xWOhb8Ef2zoJIiinYVunIf3omRfUbEXcPEvrkQcrDpJ2yjDokxhvQ26eSJbkthRhymntWx6816jpATrJphh+ug==} + peerDependencies: + vite: 5.x || 6.x || 7.x + vite@4.5.14: resolution: {integrity: sha512-+v57oAaoYNnO3hIu5Z/tJRZjq5aHM2zDve9YZ8HngVHbhk66RStobhb1sqPMIPEleV6cNKYK4eGrAbE9Ulbl2g==} engines: {node: ^14.18.0 || >=16.0.0} @@ -3628,6 +3664,14 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/eslint-parser@7.28.0(@babel/core@7.28.0)(eslint@8.57.1)': + dependencies: + '@babel/core': 7.28.0 + '@nicolo-ribaudo/eslint-scope-5-internals': 5.1.1-v1 + eslint: 8.57.1 + eslint-visitor-keys: 2.1.0 + semver: 6.3.1 + '@babel/generator@7.28.0': dependencies: '@babel/parser': 7.28.0 @@ -3636,6 +3680,10 @@ snapshots: '@jridgewell/trace-mapping': 0.3.29 jsesc: 3.1.0 + '@babel/helper-annotate-as-pure@7.27.3': + dependencies: + '@babel/types': 7.28.1 + '@babel/helper-compilation-targets@7.27.2': dependencies: '@babel/compat-data': 7.28.0 @@ -3679,17 +3727,33 @@ snapshots: dependencies: '@babel/types': 7.28.1 - '@babel/plugin-transform-react-jsx-self@7.27.1(@babel/core@7.28.0)': + '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.28.0)': dependencies: '@babel/core': 7.28.0 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-react-jsx-source@7.27.1(@babel/core@7.28.0)': + '@babel/plugin-syntax-jsx@7.27.1(@babel/core@7.28.0)': dependencies: '@babel/core': 7.28.0 '@babel/helper-plugin-utils': 7.27.1 - '@babel/runtime@7.27.6': {} + '@babel/plugin-transform-react-jsx-development@7.27.1(@babel/core@7.28.0)': + dependencies: + '@babel/core': 7.28.0 + '@babel/plugin-transform-react-jsx': 7.27.1(@babel/core@7.28.0) + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-react-jsx@7.27.1(@babel/core@7.28.0)': + dependencies: + '@babel/core': 7.28.0 + '@babel/helper-annotate-as-pure': 7.27.3 + '@babel/helper-module-imports': 7.27.1 + '@babel/helper-plugin-utils': 7.27.1 + '@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.28.0) + '@babel/types': 7.28.1 + transitivePeerDependencies: + - supports-color '@babel/template@7.27.2': dependencies: @@ -4121,6 +4185,8 @@ snapshots: '@eslint/js@8.57.1': {} + '@eslint/js@9.32.0': {} + '@figma/plugin-typings@1.116.0': {} '@floating-ui/core@1.7.2': @@ -4198,10 +4264,16 @@ snapshots: '@juanelas/base64@1.1.5': {} - '@nanostores/react@0.7.3(nanostores@0.9.5)(react@18.3.1)': + '@mdn/browser-compat-data@5.7.6': {} + + '@nanostores/preact@1.0.0(nanostores@0.9.5)(preact@10.27.0)': dependencies: nanostores: 0.9.5 - react: 18.3.1 + preact: 10.27.0 + + '@nicolo-ribaudo/eslint-scope-5-internals@5.1.1-v1': + dependencies: + eslint-scope: 5.1.1 '@nodelib/fs.scandir@2.1.5': dependencies: @@ -4218,7 +4290,57 @@ snapshots: '@pkgjs/parseargs@0.11.0': optional: true - '@rolldown/pluginutils@1.0.0-beta.27': {} + '@preact/compat@18.3.1(preact@10.27.0)': + dependencies: + preact: 10.27.0 + + '@preact/preset-vite@2.10.2(@babel/core@7.28.0)(preact@10.27.0)(vite@4.5.14(@types/node@20.19.9)(terser@5.43.1))': + dependencies: + '@babel/core': 7.28.0 + '@babel/plugin-transform-react-jsx': 7.27.1(@babel/core@7.28.0) + '@babel/plugin-transform-react-jsx-development': 7.27.1(@babel/core@7.28.0) + '@prefresh/vite': 2.4.8(preact@10.27.0)(vite@4.5.14(@types/node@20.19.9)(terser@5.43.1)) + '@rollup/pluginutils': 4.2.1 + babel-plugin-transform-hook-names: 1.0.2(@babel/core@7.28.0) + debug: 4.4.1 + picocolors: 1.1.1 + vite: 4.5.14(@types/node@20.19.9)(terser@5.43.1) + vite-prerender-plugin: 0.5.11(vite@4.5.14(@types/node@20.19.9)(terser@5.43.1)) + transitivePeerDependencies: + - preact + - supports-color + + '@preact/signals-core@1.11.0': {} + + '@preact/signals@2.2.1(preact@10.27.0)': + dependencies: + '@preact/signals-core': 1.11.0 + preact: 10.27.0 + + '@prefresh/babel-plugin@0.5.2': {} + + '@prefresh/core@1.5.5(preact@10.27.0)': + dependencies: + preact: 10.27.0 + + '@prefresh/utils@1.2.1': {} + + '@prefresh/vite@2.4.8(preact@10.27.0)(vite@4.5.14(@types/node@20.19.9)(terser@5.43.1))': + dependencies: + '@babel/core': 7.28.0 + '@prefresh/babel-plugin': 0.5.2 + '@prefresh/core': 1.5.5(preact@10.27.0) + '@prefresh/utils': 1.2.1 + '@rollup/pluginutils': 4.2.1 + preact: 10.27.0 + vite: 4.5.14(@types/node@20.19.9)(terser@5.43.1) + transitivePeerDependencies: + - supports-color + + '@rollup/pluginutils@4.2.1': + dependencies: + estree-walker: 2.0.2 + picomatch: 2.3.1 '@rollup/pluginutils@5.2.0(rollup@3.29.5)': dependencies: @@ -4318,54 +4440,10 @@ snapshots: transitivePeerDependencies: - supports-color - '@testing-library/dom@9.3.4': - dependencies: - '@babel/code-frame': 7.27.1 - '@babel/runtime': 7.27.6 - '@types/aria-query': 5.0.4 - aria-query: 5.1.3 - chalk: 4.1.2 - dom-accessibility-api: 0.5.16 - lz-string: 1.5.0 - pretty-format: 27.5.1 - - '@testing-library/react@14.3.1(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@babel/runtime': 7.27.6 - '@testing-library/dom': 9.3.4 - '@types/react-dom': 18.3.7(@types/react@18.3.23) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - transitivePeerDependencies: - - '@types/react' - '@tootallnate/once@2.0.0': {} '@types/apca-w3@0.1.3': {} - '@types/aria-query@5.0.4': {} - - '@types/babel__core@7.20.5': - dependencies: - '@babel/parser': 7.28.0 - '@babel/types': 7.28.1 - '@types/babel__generator': 7.27.0 - '@types/babel__template': 7.4.4 - '@types/babel__traverse': 7.20.7 - - '@types/babel__generator@7.27.0': - dependencies: - '@babel/types': 7.28.1 - - '@types/babel__template@7.4.4': - dependencies: - '@babel/parser': 7.28.0 - '@babel/types': 7.28.1 - - '@types/babel__traverse@7.20.7': - dependencies: - '@babel/types': 7.28.1 - '@types/chai-subset@1.3.6(@types/chai@4.3.20)': dependencies: '@types/chai': 4.3.20 @@ -4396,17 +4474,6 @@ snapshots: dependencies: undici-types: 6.21.0 - '@types/prop-types@15.7.15': {} - - '@types/react-dom@18.3.7(@types/react@18.3.23)': - dependencies: - '@types/react': 18.3.23 - - '@types/react@18.3.23': - dependencies: - '@types/prop-types': 15.7.15 - csstype: 3.1.3 - '@types/semver@7.7.0': {} '@typescript-eslint/eslint-plugin@5.62.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1)(typescript@5.8.3)': @@ -4495,18 +4562,6 @@ snapshots: '@ungap/structured-clone@1.3.0': {} - '@vitejs/plugin-react@4.7.0(vite@4.5.14(@types/node@20.19.9)(terser@5.43.1))': - dependencies: - '@babel/core': 7.28.0 - '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.28.0) - '@babel/plugin-transform-react-jsx-source': 7.27.1(@babel/core@7.28.0) - '@rolldown/pluginutils': 1.0.0-beta.27 - '@types/babel__core': 7.20.5 - react-refresh: 0.17.0 - vite: 4.5.14(@types/node@20.19.9)(terser@5.43.1) - transitivePeerDependencies: - - supports-color - '@vitest/coverage-v8@0.34.6(vitest@0.34.6(jsdom@22.1.0)(terser@5.43.1))': dependencies: '@ampproject/remapping': 2.3.0 @@ -4710,10 +4765,6 @@ snapshots: argparse@2.0.1: {} - aria-query@5.1.3: - dependencies: - deep-equal: 2.2.3 - aria-query@5.3.2: {} array-buffer-byte-length@1.0.2: @@ -4787,6 +4838,10 @@ snapshots: assertion-error@1.1.0: {} + ast-metadata-inferer@0.8.1: + dependencies: + '@mdn/browser-compat-data': 5.7.6 + ast-types-flow@0.0.8: {} async-function@1.0.0: {} @@ -4811,6 +4866,10 @@ snapshots: axobject-query@4.1.0: {} + babel-plugin-transform-hook-names@1.0.2(@babel/core@7.28.0): + dependencies: + '@babel/core': 7.28.0 + balanced-match@1.0.2: {} bigint-conversion@2.4.3: @@ -4819,6 +4878,8 @@ snapshots: binary-extensions@2.3.0: {} + boolbase@1.0.0: {} + brace-expansion@1.1.12: dependencies: balanced-match: 1.0.2 @@ -4935,10 +4996,6 @@ snapshots: convert-source-map@2.0.0: {} - copy-to-clipboard@3.3.3: - dependencies: - toggle-selection: 1.0.6 - cosmiconfig@8.3.6(typescript@5.8.3): dependencies: import-fresh: 3.3.1 @@ -4970,6 +5027,16 @@ snapshots: dependencies: postcss: 8.5.6 + css-select@5.2.2: + dependencies: + boolbase: 1.0.0 + css-what: 6.2.2 + domhandler: 5.0.3 + domutils: 3.2.2 + nth-check: 2.1.1 + + css-what@6.2.2: {} + cssdb@8.3.1: {} cssesc@3.0.0: {} @@ -4978,8 +5045,6 @@ snapshots: dependencies: rrweb-cssom: 0.6.0 - csstype@3.1.3: {} - culori@3.3.0: {} damerau-levenshtein@1.0.8: {} @@ -5022,27 +5087,6 @@ snapshots: dependencies: type-detect: 4.1.0 - deep-equal@2.2.3: - dependencies: - array-buffer-byte-length: 1.0.2 - call-bind: 1.0.8 - es-get-iterator: 1.1.3 - get-intrinsic: 1.3.0 - is-arguments: 1.2.0 - is-array-buffer: 3.0.5 - is-date-object: 1.1.0 - is-regex: 1.2.1 - is-shared-array-buffer: 1.0.4 - isarray: 2.0.5 - object-is: 1.1.6 - object-keys: 1.1.1 - object.assign: 4.1.7 - regexp.prototype.flags: 1.5.4 - side-channel: 1.1.0 - which-boxed-primitive: 1.1.1 - which-collection: 1.0.2 - which-typed-array: 1.1.19 - deep-is@0.1.4: {} define-data-property@1.1.4: @@ -5077,12 +5121,28 @@ snapshots: dependencies: esutils: 2.0.3 - dom-accessibility-api@0.5.16: {} + dom-serializer@2.0.0: + dependencies: + domelementtype: 2.3.0 + domhandler: 5.0.3 + entities: 4.5.0 + + domelementtype@2.3.0: {} domexception@4.0.0: dependencies: webidl-conversions: 7.0.0 + domhandler@5.0.3: + dependencies: + domelementtype: 2.3.0 + + domutils@3.2.2: + dependencies: + dom-serializer: 2.0.0 + domelementtype: 2.3.0 + domhandler: 5.0.3 + dot-case@3.0.4: dependencies: no-case: 3.0.4 @@ -5176,18 +5236,6 @@ snapshots: es-errors@1.3.0: {} - es-get-iterator@1.1.3: - dependencies: - call-bind: 1.0.8 - get-intrinsic: 1.3.0 - has-symbols: 1.1.0 - is-arguments: 1.2.0 - is-map: 2.0.3 - is-set: 2.0.3 - is-string: 1.1.1 - isarray: 2.0.5 - stop-iteration-iterator: 1.1.0 - es-iterator-helpers@1.2.1: dependencies: call-bind: 1.0.8 @@ -5288,6 +5336,21 @@ snapshots: escape-string-regexp@4.0.0: {} + eslint-config-preact@2.0.0(eslint@8.57.1): + dependencies: + '@babel/core': 7.28.0 + '@babel/eslint-parser': 7.28.0(@babel/core@7.28.0)(eslint@8.57.1) + '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.28.0) + '@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.28.0) + '@eslint/js': 9.32.0 + eslint: 8.57.1 + eslint-plugin-compat: 6.0.2(eslint@8.57.1) + eslint-plugin-react: 7.37.5(eslint@8.57.1) + eslint-plugin-react-hooks: 5.2.0(eslint@8.57.1) + globals: 16.3.0 + transitivePeerDependencies: + - supports-color + eslint-config-prettier@8.10.2(eslint@8.57.1): dependencies: eslint: 8.57.1 @@ -5358,6 +5421,18 @@ snapshots: - eslint-import-resolver-webpack - supports-color + eslint-plugin-compat@6.0.2(eslint@8.57.1): + dependencies: + '@mdn/browser-compat-data': 5.7.6 + ast-metadata-inferer: 0.8.1 + browserslist: 4.25.1 + caniuse-lite: 1.0.30001727 + eslint: 8.57.1 + find-up: 5.0.0 + globals: 15.15.0 + lodash.memoize: 4.1.2 + semver: 7.7.2 + eslint-plugin-es@4.1.0(eslint@8.57.1): dependencies: eslint: 8.57.1 @@ -5449,11 +5524,7 @@ snapshots: dependencies: eslint: 8.57.1 - eslint-plugin-react-hooks@4.6.2(eslint@8.57.1): - dependencies: - eslint: 8.57.1 - - eslint-plugin-react-refresh@0.4.20(eslint@8.57.1): + eslint-plugin-react-hooks@5.2.0(eslint@8.57.1): dependencies: eslint: 8.57.1 @@ -5723,6 +5794,10 @@ snapshots: dependencies: type-fest: 0.20.2 + globals@15.15.0: {} + + globals@16.3.0: {} + globalthis@1.0.4: dependencies: define-properties: 1.2.1 @@ -5765,6 +5840,8 @@ snapshots: dependencies: function-bind: 1.1.2 + he@1.2.0: {} + hex-encoding@2.0.3: dependencies: node-buffer-encoding: 1.0.3 @@ -5817,11 +5894,6 @@ snapshots: hasown: 2.0.2 side-channel: 1.1.0 - is-arguments@1.2.0: - dependencies: - call-bound: 1.0.4 - has-tostringtag: 1.0.2 - is-array-buffer@3.0.5: dependencies: call-bind: 1.0.8 @@ -6060,6 +6132,8 @@ snapshots: dependencies: json-buffer: 3.0.1 + kolorist@1.8.0: {} + language-subtag-registry@0.3.23: {} language-tags@1.0.9: @@ -6083,6 +6157,8 @@ snapshots: dependencies: p-locate: 5.0.0 + lodash.memoize@4.1.2: {} + lodash.merge@4.6.2: {} loose-envify@1.4.0: @@ -6103,8 +6179,6 @@ snapshots: dependencies: yallist: 3.1.1 - lz-string@1.5.0: {} - magic-string@0.30.17: dependencies: '@jridgewell/sourcemap-codec': 1.5.4 @@ -6187,12 +6261,21 @@ snapshots: node-buffer-encoding@1.0.3: {} + node-html-parser@6.1.13: + dependencies: + css-select: 5.2.2 + he: 1.2.0 + node-releases@2.0.19: {} normalize-path@3.0.0: {} normalize-range@0.1.2: {} + nth-check@2.1.1: + dependencies: + boolbase: 1.0.0 + nwsapi@2.2.20: {} object-assign@4.1.1: {} @@ -6201,11 +6284,6 @@ snapshots: object-inspect@1.13.4: {} - object-is@1.1.6: - dependencies: - call-bind: 1.0.8 - define-properties: 1.2.1 - object-keys@1.1.1: {} object.assign@4.1.7: @@ -6588,6 +6666,8 @@ snapshots: picocolors: 1.1.1 source-map-js: 1.2.1 + preact@10.27.0: {} + prelude-ls@1.2.1: {} prettier-linter-helpers@1.0.0: @@ -6596,12 +6676,6 @@ snapshots: prettier@3.6.2: {} - pretty-format@27.5.1: - dependencies: - ansi-regex: 5.0.1 - ansi-styles: 5.2.0 - react-is: 17.0.2 - pretty-format@29.7.0: dependencies: '@jest/schemas': 29.6.3 @@ -6636,18 +6710,8 @@ snapshots: react-is@16.13.1: {} - react-is@17.0.2: {} - react-is@18.3.1: {} - react-refresh@0.17.0: {} - - react-use-clipboard@1.0.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1): - dependencies: - copy-to-clipboard: 3.3.3 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - react@18.3.1: dependencies: loose-envify: 1.4.0 @@ -6828,6 +6892,10 @@ snapshots: signal-exit@4.1.0: {} + simple-code-frame@1.3.0: + dependencies: + kolorist: 1.8.0 + size-limit@11.2.0: dependencies: bytes-iec: 3.1.1 @@ -6854,6 +6922,10 @@ snapshots: source-map@0.6.1: {} + source-map@0.7.6: {} + + stack-trace@1.0.0-pre2: {} + stackback@0.0.2: {} std-env@3.9.0: {} @@ -7043,8 +7115,6 @@ snapshots: dependencies: is-number: 7.0.0 - toggle-selection@1.0.6: {} - tough-cookie@4.1.4: dependencies: psl: 1.15.0 @@ -7194,6 +7264,16 @@ snapshots: - supports-color - typescript + vite-prerender-plugin@0.5.11(vite@4.5.14(@types/node@20.19.9)(terser@5.43.1)): + dependencies: + kolorist: 1.8.0 + magic-string: 0.30.17 + node-html-parser: 6.1.13 + simple-code-frame: 1.3.0 + source-map: 0.7.6 + stack-trace: 1.0.0-pre2 + vite: 4.5.14(@types/node@20.19.9)(terser@5.43.1) + vite@4.5.14(@types/node@20.19.9)(terser@5.43.1): dependencies: esbuild: 0.18.20 diff --git a/src/ui/components/InvalidBackgroundSelectionMessage.tsx b/src/ui/components/InvalidBackgroundSelectionMessage.tsx index 776ff80..f115477 100644 --- a/src/ui/components/InvalidBackgroundSelectionMessage.tsx +++ b/src/ui/components/InvalidBackgroundSelectionMessage.tsx @@ -1,7 +1,6 @@ import layersImage from '~ui/assets/layers@2x.webp'; -import { type ReactElement } from 'react'; -export const InvalidBackgroundSelectionMessage = (): ReactElement => { +export const InvalidBackgroundSelectionMessage = (): Elem => { return (

); + render(, container); } else { - console.error('Failed to find container element for React root'); + console.error('Failed to find container element for root'); } }); diff --git a/src/ui/services/blend-modes/map-figma-blend-to-canvas.ts b/src/ui/services/blend-modes/map-figma-blend-to-canvas.ts index 8e96afc..136b0c3 100644 --- a/src/ui/services/blend-modes/map-figma-blend-to-canvas.ts +++ b/src/ui/services/blend-modes/map-figma-blend-to-canvas.ts @@ -1,5 +1,5 @@ import { notEmpty } from '~utils/not-empty.ts'; -import { type CSSProperties } from 'react'; +import { CSSProperties } from 'preact/compat'; export const mapFigmaBlendToCanvas = ( figmaBlend?: BlendMode diff --git a/tsconfig.json b/tsconfig.json index 5cc2254..827a9dd 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -12,7 +12,8 @@ "resolveJsonModule": true, "isolatedModules": true, "noEmit": true, - "jsx": "react-jsx", + "jsx": "preserve", + "jsxImportSource": "preact", "noUncheckedIndexedAccess": true, diff --git a/vite.config.ui.ts b/vite.config.ui.ts index 2e1467e..5330ee1 100644 --- a/vite.config.ui.ts +++ b/vite.config.ui.ts @@ -1,9 +1,8 @@ /// import { defineConfig } from 'vite'; import { resolve } from 'path'; -import react from '@vitejs/plugin-react'; import { viteSingleFile } from 'vite-plugin-singlefile'; -import svgr from 'vite-plugin-svgr'; +import preact from "@preact/preset-vite"; export default defineConfig({ resolve: { @@ -14,7 +13,7 @@ export default defineConfig({ '~utils': resolve(__dirname, 'src', 'utils'), }, }, - plugins: [react(), svgr(), viteSingleFile()], + plugins: [preact(), viteSingleFile()], root: './src/ui', build: { emptyOutDir: false, From 7e6660841fb35f9ad0897e60e61e979e99a0d566 Mon Sep 17 00:00:00 2001 From: rittiev Date: Tue, 5 Aug 2025 17:45:31 +0100 Subject: [PATCH 02/15] replaced react types --- src/ui/components/AppContent.tsx | 4 ++-- src/ui/components/BasicColorPreviewIcon.tsx | 2 +- src/ui/components/ColorIndicator.tsx | 5 ++--- src/ui/components/ColorPreview.tsx | 2 +- src/ui/components/ContrastSample.tsx | 2 +- src/ui/components/EmptySelectionMessage.tsx | 2 +- src/ui/components/HelpIcon.tsx | 2 +- src/ui/components/HelpLink.tsx | 2 +- .../InvalidBackgroundSelectionMessage.tsx | 3 ++- src/ui/components/LayeredColorPreviewIcon.tsx | 2 +- src/ui/components/LurkersIcon.tsx | 2 +- src/ui/components/LurkersLink.tsx | 2 +- src/ui/components/PictureIcon.tsx | 2 +- src/ui/components/ProgressBar.tsx | 5 ++--- src/ui/components/RewardingAnimationBodyText.tsx | 2 +- .../components/RewardingAnimationContentText.tsx | 2 +- .../components/RewardingAnimationFluentText.tsx | 2 +- .../components/SegmentedFontStyleDefinition.tsx | 2 +- src/ui/components/Selection.tsx | 15 +++++++-------- src/ui/components/SelectionContent.tsx | 5 ++--- src/ui/components/SelectionsList.tsx | 2 +- src/ui/components/SettingsIcon.tsx | 2 +- src/ui/components/StopIcon.tsx | 2 +- src/ui/components/TextMetrics.tsx | 2 +- src/ui/components/ThemeVariablesProvider.tsx | 3 +-- .../UnprocessedBlendModesSelectionMessage.tsx | 2 +- src/ui/components/WarningIcon.tsx | 2 +- 27 files changed, 38 insertions(+), 42 deletions(-) diff --git a/src/ui/components/AppContent.tsx b/src/ui/components/AppContent.tsx index 250bf3e..38109cf 100644 --- a/src/ui/components/AppContent.tsx +++ b/src/ui/components/AppContent.tsx @@ -1,4 +1,4 @@ -import { useStore } from '@nanostores/react'; +import { useStore } from '@nanostores/preact'; import { EmptySelectionMessage } from '~ui/components/EmptySelectionMessage.tsx'; import { InvalidBackgroundSelectionMessage } from '~ui/components/InvalidBackgroundSelectionMessage.tsx'; import { Selection } from '~ui/components/Selection.tsx'; @@ -12,7 +12,7 @@ import { $isUnprocessedBlendModes, } from '~ui/stores/selected-nodes.ts'; import { isEmpty } from '~utils/not-empty.ts'; -import { type ReactElement } from 'react'; +import { type ReactElement } from 'preact/compat'; export const AppContent = (): ReactElement => { const isInvalidBackground = useStore($isInvalidBackground); diff --git a/src/ui/components/BasicColorPreviewIcon.tsx b/src/ui/components/BasicColorPreviewIcon.tsx index 41df3be..4f17fe1 100644 --- a/src/ui/components/BasicColorPreviewIcon.tsx +++ b/src/ui/components/BasicColorPreviewIcon.tsx @@ -1,4 +1,4 @@ -import { type ReactElement } from 'react'; +import { type ReactElement } from 'preact/compat'; interface Props { borderColor: string; diff --git a/src/ui/components/ColorIndicator.tsx b/src/ui/components/ColorIndicator.tsx index cfa8bc9..30434f8 100644 --- a/src/ui/components/ColorIndicator.tsx +++ b/src/ui/components/ColorIndicator.tsx @@ -1,4 +1,4 @@ -import { useStore } from '@nanostores/react'; +import { useStore } from '@nanostores/preact'; import { ColorPreview } from '~ui/components/ColorPreview.tsx'; import { ThemeVariablesKeys } from '~ui/components/ThemeVariablesProvider.tsx'; import { @@ -6,7 +6,7 @@ import { getFormatterForDisplaying, } from '~utils/colors/formatters.ts'; import { type Oklch } from 'culori/fn'; -import { type ReactElement } from 'react'; +import { type ReactElement } from 'preact/compat'; import useClipboard from 'react-use-clipboard'; import { $colorSpaceDisplayMode } from '../stores/color-space-display-mode.ts'; @@ -47,7 +47,6 @@ export const ColorIndicator = ({ - - {isCopied ? 'Copied!' : 'Copy as CSS'} + {displayValue} + + ); }; diff --git a/src/ui/components/HelpLink.tsx b/src/ui/components/HelpLink.tsx index c074545..bc54c95 100644 --- a/src/ui/components/HelpLink.tsx +++ b/src/ui/components/HelpLink.tsx @@ -1,27 +1,20 @@ import { HelpIcon } from '~ui/components/HelpIcon.tsx'; -import { - Tooltip, - TooltipContent, - TooltipTrigger, -} from '~ui/components/Tooltip.tsx'; +import { Tooltip } from '~ui/components/Tooltip.tsx'; import { type ReactElement } from 'preact/compat'; import { APCADocumentationURL } from '../../constants.ts'; export const HelpLink = (): ReactElement => { return ( - - - - - - - APCA in a Nutshell + + + + ); }; diff --git a/src/ui/components/LurkersLink.tsx b/src/ui/components/LurkersLink.tsx index e9325dc..5633a85 100644 --- a/src/ui/components/LurkersLink.tsx +++ b/src/ui/components/LurkersLink.tsx @@ -1,27 +1,20 @@ import { LurkersIcon } from '~ui/components/LurkersIcon.tsx'; -import { - Tooltip, - TooltipContent, - TooltipTrigger, -} from '~ui/components/Tooltip.tsx'; +import { Tooltip } from '~ui/components/Tooltip.tsx'; import { type ReactElement } from 'preact/compat'; import { evilMartiansSiteURL } from '../../constants.ts'; export const LurkersLink = (): ReactElement => { return ( - - - - - - - Evil Martians + + + + ); }; diff --git a/src/ui/components/SettingsButton.tsx b/src/ui/components/SettingsButton.tsx index 2698bc9..69b8a77 100644 --- a/src/ui/components/SettingsButton.tsx +++ b/src/ui/components/SettingsButton.tsx @@ -1,38 +1,22 @@ -import { useStore } from '@nanostores/react'; +import { useStore } from '@nanostores/preact'; import { SettingsIcon } from '~ui/components/SettingsIcon.tsx'; -import { - Tooltip, - TooltipContent, - TooltipTrigger, -} from '~ui/components/Tooltip.tsx'; import { $colorSpaceDisplayMode, changeColorSpaceDisplayMode, colorSpaceDisplayModesList, } from '~ui/stores/color-space-display-mode.ts'; import clsx from 'clsx'; -import { type ReactElement } from 'react'; +import { Tooltip } from '~ui/components/Tooltip.tsx'; -export const SettingsButton = (): ReactElement => { +export const SettingsButton = () => { const colorSpaceDisplayMode = useStore($colorSpaceDisplayMode); return ( - - - - - - -

+ {colorSpaceDisplayModesList.map((mode) => { const isActive = mode === colorSpaceDisplayMode; - return ( { ); })} -

- + + } + > + ); }; diff --git a/src/ui/components/Tooltip.tsx b/src/ui/components/Tooltip.tsx index e45ce5b..a30c4f6 100644 --- a/src/ui/components/Tooltip.tsx +++ b/src/ui/components/Tooltip.tsx @@ -1,188 +1,65 @@ -import { - autoUpdate, - flip, - FloatingPortal, - offset, - type Placement, - shift, - useDismiss, - useFloating, - useFocus, - useHover, - useInteractions, - useMergeRefs, - useRole, -} from '@floating-ui/react'; -import { isEmpty } from '~utils/not-empty.ts'; -import { - cloneElement, - createContext, - forwardRef, - type HTMLProps, - isValidElement, - type ReactElement, - type ReactNode, - useContext, - useMemo, - useState, -} from 'react'; - -interface TooltipOptions { - initialOpen?: boolean; - onOpenChange?: (open: boolean) => void; - open?: boolean; +import { useRef, useEffect, useState } from 'preact/compat'; +import { useFloatingTooltip } from '~hooks/useFloatingTooltip.ts'; +import { Placement } from '@floating-ui/dom'; +import { ComponentChildren } from 'preact'; + +interface TooltipProps { + children: ComponentChildren; + content: ComponentChildren; placement?: Placement; } -interface TooltipContextType { - floatingStyles: HTMLProps['style']; - getFloatingProps: ( - props?: HTMLProps - ) => HTMLProps; - getReferenceProps: ( - props?: HTMLProps - ) => HTMLProps; - open: boolean; - refs: { - setFloating: (node: HTMLElement | null) => void; - setReference: (node: HTMLElement | null) => void; - }; - setOpen: (open: boolean) => void; -} - -export const useTooltip = ({ - initialOpen = false, - onOpenChange: setControlledOpen, - open: controlledOpen, - placement = 'top', -}: TooltipOptions = {}): TooltipContextType => { - const [uncontrolledOpen, setUncontrolledOpen] = useState(initialOpen); - - const open = controlledOpen ?? uncontrolledOpen; - const setOpen = setControlledOpen ?? setUncontrolledOpen; - - const data = useFloating({ - middleware: [ - offset(5), - flip({ - crossAxis: placement.includes('-'), - fallbackAxisSideDirection: 'start', - padding: 5, - }), - shift({ padding: 5 }), - ], - onOpenChange: setOpen, - open, - placement, - whileElementsMounted: autoUpdate, - }); - - const context = data.context; - - const hover = useHover(context, { - delay: { - close: 0, - open: 150, - }, - enabled: isEmpty(controlledOpen), - move: false, - }); - const focus = useFocus(context, { - enabled: isEmpty(controlledOpen), - }); - const dismiss = useDismiss(context); - const role = useRole(context, { role: 'tooltip' }); - - const interactions = useInteractions([hover, focus, dismiss, role]); - - return useMemo( - () => ({ - open, - setOpen, - ...interactions, - ...data, - }), - [open, setOpen, interactions, data] - ); -}; - -type ContextType = null | ReturnType; - -const TooltipContext = createContext(null); - -export const useTooltipContext = (): ContextType => { - const context = useContext(TooltipContext); - - if (isEmpty(context)) { - throw new Error('Tooltip components must be wrapped in '); - } - - return context; -}; - export const Tooltip = ({ children, - ...options -}: { children: ReactNode } & TooltipOptions): ReactElement => { - const tooltip = useTooltip(options); - return ( - - {children} - - ); -}; - -export const TooltipTrigger = forwardRef< - HTMLButtonElement, - HTMLProps & { asChild?: boolean } ->(function TooltipTrigger({ asChild = false, children, ...props }, propRef) { - const context = useTooltipContext(); - const childrenRef = (children as any).ref; - const ref = useMergeRefs([context?.refs.setReference, propRef, childrenRef]); + content, + placement = 'top', +}: TooltipProps) => { + const triggerRef = useRef(null); + const tooltipRef = useRef(null); + const openTimeout = useRef(null); + const closeTimeout = useRef(null); + + const [visible, setVisible] = useState(false); + + useEffect(() => { + if (visible && triggerRef.current && tooltipRef.current) { + return useFloatingTooltip( + triggerRef.current, + tooltipRef.current, + placement + ); + } + }, [visible]); + + const onMouseEnter = () => { + if (closeTimeout.current) clearTimeout(closeTimeout.current); + openTimeout.current = window.setTimeout(() => setVisible(true), 150); + }; - if (asChild && isValidElement(children)) { - return cloneElement( - children, - context?.getReferenceProps({ - ref, - ...props, - ...children.props, - 'data-state': context.open ? 'open' : 'closed', - }) - ); - } + const onMouseLeave = () => { + if (openTimeout.current) clearTimeout(openTimeout.current); + closeTimeout.current = window.setTimeout(() => setVisible(false), 0); + }; return ( - {children} - - ); -}); - -export const TooltipContent = forwardRef< - HTMLDivElement, - HTMLProps ->(function TooltipContent({ style, ...props }, propRef) { - const context = useTooltipContext(); - const ref = useMergeRefs([context?.refs.setFloating, propRef]); - - if (context?.open === false) return null; - - return ( - -
- + {visible && ( +
+ {content} +
+ )} +
); -}); +}; diff --git a/src/ui/stores/color-space-display-mode.ts b/src/ui/stores/color-space-display-mode.ts index dd3255d..da6a61e 100644 --- a/src/ui/stores/color-space-display-mode.ts +++ b/src/ui/stores/color-space-display-mode.ts @@ -53,9 +53,12 @@ onMount($colorSpaceDisplayMode, () => { event.data?.pluginMessage.type === MessageTypes.ColorSpaceDisplayModeChange ) { - $colorSpaceDisplayMode.set( - event.data.pluginMessage.payload.colorSpaceDisplayMode - ); + const newValue = event.data.pluginMessage.payload.colorSpaceDisplayMode; + const currentValue = $colorSpaceDisplayMode.get(); + + if (newValue !== currentValue) { + $colorSpaceDisplayMode.set(newValue); + } } }; diff --git a/tsconfig.json b/tsconfig.json index 827a9dd..9e6924a 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -29,7 +29,8 @@ "~test-utils/*": ["src/test-utils/*"], "~types/*": ["src/types/*"], "~utils/*": ["src/utils/*"], - "~ui/*": ["src/ui/*"] + "~ui/*": ["src/ui/*"], + "~hooks/*": ["src/hooks/*"] } }, "include": ["src"], diff --git a/vite.config.ui.ts b/vite.config.ui.ts index 5330ee1..3b5610d 100644 --- a/vite.config.ui.ts +++ b/vite.config.ui.ts @@ -2,7 +2,7 @@ import { defineConfig } from 'vite'; import { resolve } from 'path'; import { viteSingleFile } from 'vite-plugin-singlefile'; -import preact from "@preact/preset-vite"; +import preact from '@preact/preset-vite'; export default defineConfig({ resolve: { @@ -11,6 +11,7 @@ export default defineConfig({ '~test-utils': resolve(__dirname, 'src', 'test-utils'), '~types': resolve(__dirname, 'src', 'types'), '~utils': resolve(__dirname, 'src', 'utils'), + '~hooks': resolve(__dirname, 'src', 'hooks'), }, }, plugins: [preact(), viteSingleFile()], From 1a32d9fe4b1c5e707b5660e4d53393dbe97a992c Mon Sep 17 00:00:00 2001 From: rittiev Date: Wed, 6 Aug 2025 14:45:21 +0100 Subject: [PATCH 04/15] fixed eslint bugs --- .eslintrc.cjs | 5 +++- package.json | 2 -- src/hooks/useFloatingTooltip.ts | 10 +++---- src/ui/components/App.tsx | 5 ++-- src/ui/components/SettingsButton.tsx | 7 ++--- src/ui/components/Tooltip.tsx | 40 ++++++++++++++-------------- 6 files changed, 36 insertions(+), 33 deletions(-) diff --git a/.eslintrc.cjs b/.eslintrc.cjs index 6a90f94..73cc37c 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -5,7 +5,6 @@ module.exports = { }, extends: [ 'standard-with-typescript', - 'plugin:eslint-config-preact', 'prettier', 'plugin:perfectionist/recommended-alphabetical', 'plugin:tailwindcss/recommended', @@ -92,6 +91,10 @@ module.exports = { type: 'test-utils', pattern: 'src/test-utils/*', }, + { + type: 'hooks', + pattern: 'src/hooks/*', + }, ], }, }; diff --git a/package.json b/package.json index aab12de..a70cfdf 100644 --- a/package.json +++ b/package.json @@ -53,8 +53,6 @@ "@preact/preset-vite": "^2.10.2", "@size-limit/preset-small-lib": "^11.2.0", "@types/node": "^20.4.1", - "@typescript-eslint/eslint-plugin": "^5.61.0", - "@typescript-eslint/parser": "^5.61.0", "eslint": "^8.44.0", "eslint-config-preact": "^2.0.0", "eslint-config-prettier": "^8.8.0", diff --git a/src/hooks/useFloatingTooltip.ts b/src/hooks/useFloatingTooltip.ts index 320e032..b73d980 100644 --- a/src/hooks/useFloatingTooltip.ts +++ b/src/hooks/useFloatingTooltip.ts @@ -6,15 +6,14 @@ import { shift, } from '@floating-ui/dom'; -export function useFloatingTooltip( +export const useFloatingTooltip = ( trigger: HTMLElement, tooltip: HTMLElement, placement: Placement = 'top' -) { +): void => { tooltip.style.position = 'absolute'; - computePosition(trigger, tooltip, { - placement, + void computePosition(trigger, tooltip, { middleware: [ offset(5), flip({ @@ -24,10 +23,11 @@ export function useFloatingTooltip( }), shift({ padding: 5 }), ], + placement, }).then(({ x, y }) => { Object.assign(tooltip.style, { left: `${x}px`, top: `${y}px`, }); }); -} +}; diff --git a/src/ui/components/App.tsx b/src/ui/components/App.tsx index 6a4ec41..f3e0492 100644 --- a/src/ui/components/App.tsx +++ b/src/ui/components/App.tsx @@ -1,3 +1,4 @@ +import { useStore } from '@nanostores/preact'; import { effect } from '@preact/signals'; import { MessageTypes } from '~types/messages.ts'; import { AppContent } from '~ui/components/AppContent.tsx'; @@ -5,10 +6,10 @@ import { HelpLink } from '~ui/components/HelpLink.tsx'; import { LurkersLink } from '~ui/components/LurkersLink.tsx'; import { SettingsButton } from '~ui/components/SettingsButton.tsx'; import { Tooltip } from '~ui/components/Tooltip.tsx'; -import { useStore } from '@nanostores/preact'; import { $isP3 } from '~ui/stores/selected-nodes.ts'; +import { type VNode } from 'preact'; -export const App = () => { +export const App = (): VNode => { const isP3 = useStore($isP3); effect(() => { diff --git a/src/ui/components/SettingsButton.tsx b/src/ui/components/SettingsButton.tsx index 69b8a77..b153596 100644 --- a/src/ui/components/SettingsButton.tsx +++ b/src/ui/components/SettingsButton.tsx @@ -1,14 +1,15 @@ import { useStore } from '@nanostores/preact'; import { SettingsIcon } from '~ui/components/SettingsIcon.tsx'; +import { Tooltip } from '~ui/components/Tooltip.tsx'; import { $colorSpaceDisplayMode, changeColorSpaceDisplayMode, colorSpaceDisplayModesList, } from '~ui/stores/color-space-display-mode.ts'; import clsx from 'clsx'; -import { Tooltip } from '~ui/components/Tooltip.tsx'; +import { type VNode } from 'preact'; -export const SettingsButton = () => { +export const SettingsButton = (): VNode => { const colorSpaceDisplayMode = useStore($colorSpaceDisplayMode); return ( @@ -32,9 +33,9 @@ export const SettingsButton = () => { } > diff --git a/src/ui/components/Tooltip.tsx b/src/ui/components/Tooltip.tsx index a30c4f6..2ded826 100644 --- a/src/ui/components/Tooltip.tsx +++ b/src/ui/components/Tooltip.tsx @@ -1,7 +1,7 @@ -import { useRef, useEffect, useState } from 'preact/compat'; +import { type Placement } from '@floating-ui/dom'; import { useFloatingTooltip } from '~hooks/useFloatingTooltip.ts'; -import { Placement } from '@floating-ui/dom'; -import { ComponentChildren } from 'preact'; +import { type ComponentChildren, type VNode } from 'preact'; +import { useEffect, useRef, useState } from 'preact/compat'; interface TooltipProps { children: ComponentChildren; @@ -13,32 +13,32 @@ export const Tooltip = ({ children, content, placement = 'top', -}: TooltipProps) => { +}: TooltipProps): VNode => { const triggerRef = useRef(null); const tooltipRef = useRef(null); - const openTimeout = useRef(null); - const closeTimeout = useRef(null); + const openTimeout = useRef(null); + const closeTimeout = useRef(null); const [visible, setVisible] = useState(false); useEffect(() => { - if (visible && triggerRef.current && tooltipRef.current) { - return useFloatingTooltip( - triggerRef.current, - tooltipRef.current, - placement - ); + if (visible && triggerRef.current != null && tooltipRef.current != null) { + useFloatingTooltip(triggerRef.current, tooltipRef.current, placement); } }, [visible]); - const onMouseEnter = () => { - if (closeTimeout.current) clearTimeout(closeTimeout.current); - openTimeout.current = window.setTimeout(() => setVisible(true), 150); + const onMouseEnter = (): void => { + if (closeTimeout.current != null) clearTimeout(closeTimeout.current); + openTimeout.current = window.setTimeout(() => { + setVisible(true); + }, 150); }; - const onMouseLeave = () => { - if (openTimeout.current) clearTimeout(openTimeout.current); - closeTimeout.current = window.setTimeout(() => setVisible(false), 0); + const onMouseLeave = (): void => { + if (openTimeout.current != null) clearTimeout(openTimeout.current); + closeTimeout.current = window.setTimeout(() => { + setVisible(false); + }, 0); }; return ( @@ -51,11 +51,11 @@ export const Tooltip = ({ {visible && (
{content}
From eef6613cbfcd0457b6355c8c0fcbd106614ed4d0 Mon Sep 17 00:00:00 2001 From: rittiev Date: Wed, 6 Aug 2025 15:14:05 +0100 Subject: [PATCH 05/15] fixed tooltip bugs --- src/hooks/useFloatingTooltip.ts | 18 ++++++------- src/ui/components/Tooltip.tsx | 47 ++++++++++++++++++++++----------- 2 files changed, 40 insertions(+), 25 deletions(-) diff --git a/src/hooks/useFloatingTooltip.ts b/src/hooks/useFloatingTooltip.ts index b73d980..0fc8f36 100644 --- a/src/hooks/useFloatingTooltip.ts +++ b/src/hooks/useFloatingTooltip.ts @@ -6,14 +6,12 @@ import { shift, } from '@floating-ui/dom'; -export const useFloatingTooltip = ( +export const useFloatingTooltip = async ( trigger: HTMLElement, tooltip: HTMLElement, placement: Placement = 'top' -): void => { - tooltip.style.position = 'absolute'; - - void computePosition(trigger, tooltip, { +): Promise => { + const { x, y } = await computePosition(trigger, tooltip, { middleware: [ offset(5), flip({ @@ -24,10 +22,10 @@ export const useFloatingTooltip = ( shift({ padding: 5 }), ], placement, - }).then(({ x, y }) => { - Object.assign(tooltip.style, { - left: `${x}px`, - top: `${y}px`, - }); + }); + + Object.assign(tooltip.style, { + left: `${x}px`, + top: `${y}px`, }); }; diff --git a/src/ui/components/Tooltip.tsx b/src/ui/components/Tooltip.tsx index 2ded826..28730f4 100644 --- a/src/ui/components/Tooltip.tsx +++ b/src/ui/components/Tooltip.tsx @@ -1,11 +1,18 @@ +import type { VNode } from 'preact'; + import { type Placement } from '@floating-ui/dom'; import { useFloatingTooltip } from '~hooks/useFloatingTooltip.ts'; -import { type ComponentChildren, type VNode } from 'preact'; -import { useEffect, useRef, useState } from 'preact/compat'; +import { + cloneElement, + isValidElement, + useEffect, + useRef, + useState, +} from 'preact/compat'; interface TooltipProps { - children: ComponentChildren; - content: ComponentChildren; + children: VNode; + content: string | VNode; placement?: Placement; } @@ -16,15 +23,23 @@ export const Tooltip = ({ }: TooltipProps): VNode => { const triggerRef = useRef(null); const tooltipRef = useRef(null); + const openTimeout = useRef(null); const closeTimeout = useRef(null); - const [visible, setVisible] = useState(false); useEffect(() => { - if (visible && triggerRef.current != null && tooltipRef.current != null) { - useFloatingTooltip(triggerRef.current, tooltipRef.current, placement); - } + const initTooltip = async (): Promise => { + if (visible && triggerRef.current != null && tooltipRef.current != null) { + await useFloatingTooltip( + triggerRef.current, + tooltipRef.current, + placement + ); + } + }; + + void initTooltip().catch(); }, [visible]); const onMouseEnter = (): void => { @@ -41,21 +56,23 @@ export const Tooltip = ({ }, 0); }; + const childWithRef = isValidElement(children) + ? cloneElement(children, { ref: triggerRef }) + : children; + return (
- {children} + {childWithRef} + {visible && (
{content}
From 5c28261587e5a3d79373b6382f0119c4525c6862 Mon Sep 17 00:00:00 2001 From: rittiev Date: Wed, 6 Aug 2025 17:12:58 +0100 Subject: [PATCH 06/15] fixed eslint bugs --- .eslintrc.cjs | 4 + package.json | 4 +- pnpm-lock.yaml | 408 ++++++++++++------ .../traverse-and-check-intersections.ts | 8 +- .../figma/nodes/create-polychrom-node.ts | 8 +- .../figma/nodes/is-valid-for-selection.ts | 8 +- .../build-general-selection-payload.ts | 8 +- src/ui/components/AppContent.tsx | 4 +- src/ui/components/BasicColorPreviewIcon.tsx | 4 +- src/ui/components/ColorIndicator.tsx | 2 +- src/ui/components/ContrastSample.tsx | 6 +- src/ui/components/EmptySelectionMessage.tsx | 4 +- src/ui/components/HelpIcon.tsx | 4 +- src/ui/components/HelpLink.tsx | 6 +- .../InvalidBackgroundSelectionMessage.tsx | 6 +- src/ui/components/LayeredColorPreviewIcon.tsx | 6 +- src/ui/components/LurkersIcon.tsx | 4 +- src/ui/components/LurkersLink.tsx | 4 +- src/ui/components/PictureIcon.tsx | 4 +- .../components/RewardingAnimationBodyText.tsx | 10 +- .../RewardingAnimationContentText.tsx | 4 +- .../RewardingAnimationFluentText.tsx | 12 +- src/ui/components/Selection.tsx | 2 +- src/ui/components/SelectionContent.tsx | 2 +- src/ui/components/SelectionsList.tsx | 4 +- src/ui/components/SettingsIcon.tsx | 4 +- src/ui/components/StopIcon.tsx | 4 +- .../UnprocessedBlendModesSelectionMessage.tsx | 4 +- src/ui/components/WarningIcon.tsx | 4 +- src/ui/index.tsx | 2 +- .../blend-modes/map-figma-blend-to-canvas.ts | 2 +- src/ui/services/blend/is-blended-fill.ts | 4 +- src/ui/services/canvas/get-fill-from-ctx.ts | 4 +- src/ui/services/theme/generate-ui-colors.ts | 26 +- src/ui/stores/selected-nodes.ts | 24 +- src/utils/apca/calculate-apca-score.ts | 4 +- src/utils/colors/formatters.ts | 8 +- src/utils/figma/get-actual-fill.ts | 4 +- src/utils/figma/get-actual-node.ts | 4 +- src/utils/figma/sort-by-depth-and-order.ts | 4 +- 40 files changed, 356 insertions(+), 282 deletions(-) diff --git a/.eslintrc.cjs b/.eslintrc.cjs index 73cc37c..b0b376f 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -3,8 +3,10 @@ module.exports = { browser: true, es2021: true, }, + parser: '@typescript-eslint/parser', extends: [ 'standard-with-typescript', + 'plugin:preact/recommended', 'prettier', 'plugin:perfectionist/recommended-alphabetical', 'plugin:tailwindcss/recommended', @@ -29,6 +31,8 @@ module.exports = { }, plugins: ['preact', 'prettier', 'jsx-a11y', 'boundaries'], rules: { + 'no-undef': 'off', + 'react/jsx-no-bind': 'off', 'import/no-default-export': 'error', 'func-style': ['error', 'expression'], 'preact/preact-in-jsx-scope': 'off', diff --git a/package.json b/package.json index a70cfdf..691521e 100644 --- a/package.json +++ b/package.json @@ -53,8 +53,9 @@ "@preact/preset-vite": "^2.10.2", "@size-limit/preset-small-lib": "^11.2.0", "@types/node": "^20.4.1", + "@typescript-eslint/eslint-plugin": "5.61.0", + "@typescript-eslint/parser": "5.61.0", "eslint": "^8.44.0", - "eslint-config-preact": "^2.0.0", "eslint-config-prettier": "^8.8.0", "eslint-config-standard-with-typescript": "^36.0.0", "eslint-import-resolver-alias": "^1.1.2", @@ -62,6 +63,7 @@ "eslint-plugin-jsx-a11y": "^6.7.1", "eslint-plugin-n": "^15.0.0", "eslint-plugin-perfectionist": "^1.4.0", + "eslint-plugin-preact": "^0.1.0", "eslint-plugin-prettier": "^4.2.1", "eslint-plugin-promise": "^6.0.0", "eslint-plugin-tailwindcss": "^3.13.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0d7ccff..34507b5 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -58,7 +58,7 @@ importers: version: 3.3.0 eslint-plugin-boundaries: specifier: ^3.4.0 - version: 3.4.1(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1) + version: 3.4.1(@typescript-eslint/parser@5.61.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1) nanoid: specifier: ^4.0.2 version: 4.0.2 @@ -109,29 +109,26 @@ importers: specifier: ^20.4.1 version: 20.19.9 '@typescript-eslint/eslint-plugin': - specifier: ^5.61.0 - version: 5.62.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1)(typescript@5.8.3) + specifier: 5.61.0 + version: 5.61.0(@typescript-eslint/parser@5.61.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1)(typescript@5.8.3) '@typescript-eslint/parser': - specifier: ^5.61.0 - version: 5.62.0(eslint@8.57.1)(typescript@5.8.3) + specifier: 5.61.0 + version: 5.61.0(eslint@8.57.1)(typescript@5.8.3) eslint: specifier: ^8.44.0 version: 8.57.1 - eslint-config-preact: - specifier: ^2.0.0 - version: 2.0.0(eslint@8.57.1) eslint-config-prettier: specifier: ^8.8.0 version: 8.10.2(eslint@8.57.1) eslint-config-standard-with-typescript: specifier: ^36.0.0 - version: 36.1.1(@typescript-eslint/eslint-plugin@5.62.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1)(typescript@5.8.3))(eslint-plugin-import@2.32.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1))(eslint-plugin-n@15.7.0(eslint@8.57.1))(eslint-plugin-promise@6.6.0(eslint@8.57.1))(eslint@8.57.1)(typescript@5.8.3) + version: 36.1.1(@typescript-eslint/eslint-plugin@5.61.0(@typescript-eslint/parser@5.61.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1)(typescript@5.8.3))(eslint-plugin-import@2.32.0(@typescript-eslint/parser@5.61.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1))(eslint-plugin-n@15.7.0(eslint@8.57.1))(eslint-plugin-promise@6.6.0(eslint@8.57.1))(eslint@8.57.1)(typescript@5.8.3) eslint-import-resolver-alias: specifier: ^1.1.2 - version: 1.1.2(eslint-plugin-import@2.32.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1)) + version: 1.1.2(eslint-plugin-import@2.32.0(@typescript-eslint/parser@5.61.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1)) eslint-plugin-import: specifier: ^2.25.2 - version: 2.32.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1) + version: 2.32.0(@typescript-eslint/parser@5.61.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1) eslint-plugin-jsx-a11y: specifier: ^6.7.1 version: 6.10.2(eslint@8.57.1) @@ -141,6 +138,9 @@ importers: eslint-plugin-perfectionist: specifier: ^1.4.0 version: 1.5.1(eslint@8.57.1)(typescript@5.8.3) + eslint-plugin-preact: + specifier: ^0.1.0 + version: 0.1.0(eslint@8.57.1)(typescript@5.8.3) eslint-plugin-prettier: specifier: ^4.2.1 version: 4.2.5(eslint-config-prettier@8.10.2(eslint@8.57.1))(eslint@8.57.1)(prettier@3.6.2) @@ -188,13 +188,6 @@ packages: resolution: {integrity: sha512-UlLAnTPrFdNGoFtbSXwcGFQBtQZJCNjaN6hQNP3UPvuNXT1i82N26KL3dZeIpNalWywr9IuQuncaAfUaS1g6sQ==} engines: {node: '>=6.9.0'} - '@babel/eslint-parser@7.28.0': - resolution: {integrity: sha512-N4ntErOlKvcbTt01rr5wj3y55xnIdx1ymrfIr8C2WnM1Y9glFgWaGDEULJIazOX3XM9NRzhfJ6zZnQ1sBNWU+w==} - engines: {node: ^10.13.0 || ^12.13.0 || >=14.0.0} - peerDependencies: - '@babel/core': ^7.11.0 - eslint: ^7.5.0 || ^8.0.0 || ^9.0.0 - '@babel/generator@7.28.0': resolution: {integrity: sha512-lJjzvrbEeWrhB4P3QBsH7tey117PjLZnDbLiQEKjQ/fNJTjuq4HSqgFA+UNSwZT8D7dxxbnuSBMsa1lrWzKlQg==} engines: {node: '>=6.9.0'} @@ -246,11 +239,6 @@ packages: engines: {node: '>=6.0.0'} hasBin: true - '@babel/plugin-syntax-class-properties@7.12.13': - resolution: {integrity: sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==} - peerDependencies: - '@babel/core': ^7.0.0-0 - '@babel/plugin-syntax-jsx@7.27.1': resolution: {integrity: sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==} engines: {node: '>=6.9.0'} @@ -830,10 +818,6 @@ packages: resolution: {integrity: sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - '@eslint/js@9.32.0': - resolution: {integrity: sha512-BBpRFZK3eX6uMLKz8WxFOBIFFcGFJ/g8XuwjTHCqHROSIsopI+ddn/d5Cfh36+7+e5edVS8dbSHnBNhrLEX0zg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@figma/plugin-typings@1.116.0': resolution: {integrity: sha512-jpn7Vq3uxgJF5oQ5PwkWGGIyCwIjB260UjtSzBck9LL1WzXJSaxBH1wo+vrU4XXbV//TURUGBYIQ2tU7cdyRYQ==} @@ -905,8 +889,8 @@ packages: '@juanelas/base64@1.1.5': resolution: {integrity: sha512-mjAF27LzwfYobdwqnxZgeucbKT5wRRNvILg3h5OvCWK+3F7mw/A1tnjHnNiTYtLmTvT/bM1jA5AX7eQawDGs1w==} - '@mdn/browser-compat-data@5.7.6': - resolution: {integrity: sha512-7xdrMX0Wk7grrTZQwAoy1GkvPMFoizStUoL+VmtUkAxegbCCec+3FKwOM6yc/uGU5+BEczQHXAlWiqvM8JeENg==} + '@mdn/browser-compat-data@3.3.14': + resolution: {integrity: sha512-n2RC9d6XatVbWFdHLimzzUJxJ1KY8LdjqrW6YvGPiRmsHkhOUx74/Ct10x5Yo7bC/Jvqx7cDEW8IMPv/+vwEzA==} '@nanostores/preact@1.0.0': resolution: {integrity: sha512-woHYvSwau1YtO9AEnGsh/jRPU2u5DTfNSrDHtKMZOeDUWV6EJfvyv7dJ7AaMps2I9uJcY6OlqXKkA9qTctEjyw==} @@ -915,9 +899,6 @@ packages: nanostores: ^0.9.0 || ^0.10.0 || ^0.11.0 || ^1.0.0 preact: '>=10.0.0' - '@nicolo-ribaudo/eslint-scope-5-internals@5.1.1-v1': - resolution: {integrity: sha512-54/JRvkLIzzDWshCWfuhadfrfZVPiElY8Fcgmg1HroEly/EDSszzhBAsarCux+D/kOslTRquNzuyGSmUSTTHGg==} - '@nodelib/fs.scandir@2.1.5': resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} engines: {node: '>= 8'} @@ -1116,8 +1097,8 @@ packages: '@types/semver@7.7.0': resolution: {integrity: sha512-k107IF4+Xr7UHjwDc7Cfd6PRQfbdkiRabXGRjo07b4WyPahFBZCZ1sE+BNxYIJPPg73UkfOsVOLwqVc/6ETrIA==} - '@typescript-eslint/eslint-plugin@5.62.0': - resolution: {integrity: sha512-TiZzBSJja/LbhNPvk6yc0JrX9XqhQ0hdh6M2svYfsHGejaKFIAGd9MQ+ERIMzLGlN/kZoYIgdxFV0PuljTKXag==} + '@typescript-eslint/eslint-plugin@5.61.0': + resolution: {integrity: sha512-A5l/eUAug103qtkwccSCxn8ZRwT+7RXWkFECdA4Cvl1dOlDUgTpAOfSEElZn2uSUxhdDpnCdetrf0jvU4qrL+g==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: '@typescript-eslint/parser': ^5.0.0 @@ -1127,8 +1108,14 @@ packages: typescript: optional: true - '@typescript-eslint/parser@5.62.0': - resolution: {integrity: sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==} + '@typescript-eslint/experimental-utils@2.34.0': + resolution: {integrity: sha512-eS6FTkq+wuMJ+sgtuNTtcqavWXqsflWcfBnlYhg/nS4aZ1leewkXGbvBhaapn1q6qf4M71bsR1tez5JTRMuqwA==} + engines: {node: ^8.10.0 || ^10.13.0 || >=11.10.1} + peerDependencies: + eslint: '*' + + '@typescript-eslint/parser@5.61.0': + resolution: {integrity: sha512-yGr4Sgyh8uO6fSi9hw3jAFXNBHbCtKKFMdX2IkT3ZqpKmtAq3lHS4ixB/COFuAIJpwl9/AqF7j72ZDWYKmIfvg==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 @@ -1137,12 +1124,16 @@ packages: typescript: optional: true + '@typescript-eslint/scope-manager@5.61.0': + resolution: {integrity: sha512-W8VoMjoSg7f7nqAROEmTt6LoBpn81AegP7uKhhW5KzYlehs8VV0ZW0fIDVbcZRcaP3aPSW+JZFua+ysQN+m/Nw==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + '@typescript-eslint/scope-manager@5.62.0': resolution: {integrity: sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - '@typescript-eslint/type-utils@5.62.0': - resolution: {integrity: sha512-xsSQreu+VnfbqQpW5vnCJdq1Z3Q0U31qiWmRhr98ONQmcp/yhiPJFPq8MXiJVLiksmOKSjIldZzkebzHuCGzew==} + '@typescript-eslint/type-utils@5.61.0': + resolution: {integrity: sha512-kk8u//r+oVK2Aj3ph/26XdH0pbAkC2RiSjUYhKD+PExemG4XSjpGFeyZ/QM8lBOa7O8aGOU+/yEbMJgQv/DnCg==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: '*' @@ -1151,10 +1142,32 @@ packages: typescript: optional: true + '@typescript-eslint/types@5.61.0': + resolution: {integrity: sha512-ldyueo58KjngXpzloHUog/h9REmHl59G1b3a5Sng1GfBo14BkS3ZbMEb3693gnP1k//97lh7bKsp6/V/0v1veQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + '@typescript-eslint/types@5.62.0': resolution: {integrity: sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + '@typescript-eslint/typescript-estree@2.34.0': + resolution: {integrity: sha512-OMAr+nJWKdlVM9LOqCqh3pQQPwxHAN7Du8DR6dmwCrAmxtiXQnhHJ6tBNtf+cggqfo51SG/FCwnKhXCIM7hnVg==} + engines: {node: ^8.10.0 || ^10.13.0 || >=11.10.1} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + '@typescript-eslint/typescript-estree@5.61.0': + resolution: {integrity: sha512-Fud90PxONnnLZ36oR5ClJBLTLfU4pIWBmnvGwTbEa2cXIqj70AEDEmOmpkFComjBZ/037ueKrOdHuYmSFVD7Rw==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + '@typescript-eslint/typescript-estree@5.62.0': resolution: {integrity: sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -1164,12 +1177,22 @@ packages: typescript: optional: true + '@typescript-eslint/utils@5.61.0': + resolution: {integrity: sha512-mV6O+6VgQmVE6+xzlA91xifndPW9ElFW8vbSF0xCT/czPXVhwDewKila1jOyRwa9AE19zKnrr7Cg5S3pJVrTWQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + '@typescript-eslint/utils@5.62.0': resolution: {integrity: sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + '@typescript-eslint/visitor-keys@5.61.0': + resolution: {integrity: sha512-50XQ5VdbWrX06mQXhy93WywSFZZGsv3EOjq+lqp6WC2t+j3mb6A9xYVdrRxafvK88vg9k9u+CT4l6D8PEatjKg==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + '@typescript-eslint/visitor-keys@5.62.0': resolution: {integrity: sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -1377,8 +1400,8 @@ packages: assertion-error@1.1.0: resolution: {integrity: sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==} - ast-metadata-inferer@0.8.1: - resolution: {integrity: sha512-ht3Dm6Zr7SXv6t1Ra6gFo0+kLDglHGrEbYihTkcycrbHw7WCcuhBzPlJYHEsIpycaUwzsJHje+vUcxXUX4ztTA==} + ast-metadata-inferer@0.7.0: + resolution: {integrity: sha512-OkMLzd8xelb3gmnp6ToFvvsHLtS6CbagTkFQvQ+ZYFe3/AIl9iKikNR9G7pY3GfOR/2Xc222hwBjzI7HLkE76Q==} ast-types-flow@0.0.8: resolution: {integrity: sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==} @@ -1409,6 +1432,13 @@ packages: resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==} engines: {node: '>= 0.4'} + babel-eslint@10.1.0: + resolution: {integrity: sha512-ifWaTHQ0ce+448CYop8AdrQiBsGrnC+bMgfyKFdi6EsPLTAWG+QfyDeM6OH+FmWnKvEq5NnBMLvlBUPKQZoDSg==} + engines: {node: '>=6'} + deprecated: babel-eslint is now @babel/eslint-parser. This package will no longer receive updates. + peerDependencies: + eslint: '>= 4.12.1' + babel-plugin-transform-hook-names@1.0.2: resolution: {integrity: sha512-5gafyjyyBTTdX/tQQ0hRgu4AhNHG/hqWi0ZZmg2xvs2FgRkJXzDNKBZCyoYqgFkovfDrgM8OoKg8karoUvWeCw==} peerDependencies: @@ -1543,6 +1573,9 @@ packages: copy-to-clipboard@3.3.3: resolution: {integrity: sha512-2KV8NhB5JqC3ky0r9PMCAZKbUHSwtEo4CwCs0KXgruG43gX5PMqDEBbVU4OUzw2MuAWUfsuFmWvEKG5QRfSnJA==} + core-js@3.45.0: + resolution: {integrity: sha512-c2KZL9lP4DjkN3hk/an4pWn5b5ZefhRJnAc42n6LJ19kSnbeRbdQZE5dSeE2LBol1OwJD3X1BQvFTAsa8ReeDA==} + cosmiconfig@8.3.6: resolution: {integrity: sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==} engines: {node: '>=14'} @@ -1786,10 +1819,10 @@ packages: resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} engines: {node: '>=10'} - eslint-config-preact@2.0.0: - resolution: {integrity: sha512-TFj70lEE7y3R9DQAFJ/clRfVmyaXdwE3q56gA9zm+iTmlpYjtZKtV1jv/jtgdF2LqgvJjlGlGE1rHVwE9yNdkg==} + eslint-config-developit@1.2.0: + resolution: {integrity: sha512-uUXirRR5R06sqsPgOk8XlA65HRxXNSlg5vPmyLvFwksCibZZLI/RxszuAn6R2EZ6tJUIJupLrVw8fkDYX3TVsQ==} peerDependencies: - eslint: ^8.57.1 || ^9.0.0 + eslint: '>=5' eslint-config-prettier@8.10.2: resolution: {integrity: sha512-/IGJ6+Dka158JnP5n5YFMOszjDWrXggGz1LaK/guZq9vZTmniaKlHcsscvkAhn9y4U+BU3JuUdYvtAMcv30y4A==} @@ -1874,11 +1907,11 @@ packages: peerDependencies: eslint: '>=6.0.0' - eslint-plugin-compat@6.0.2: - resolution: {integrity: sha512-1ME+YfJjmOz1blH0nPZpHgjMGK4kjgEeoYqGCqoBPQ/mGu/dJzdoP0f1C8H2jcWZjzhZjAMccbM/VdXhPORIfA==} - engines: {node: '>=18.x'} + eslint-plugin-compat@3.13.0: + resolution: {integrity: sha512-cv8IYMuTXm7PIjMVDN2y4k/KVnKZmoNGHNq27/9dLstOLydKblieIv+oe2BN2WthuXnFNhaNvv3N1Bvl4dbIGA==} + engines: {node: '>=9.x'} peerDependencies: - eslint: ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0 + eslint: ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 eslint-plugin-es@4.1.0: resolution: {integrity: sha512-GILhQTnjYE2WorX5Jyi5i4dz5ALWxBIdQECVQavL6s7cI76IZTDWleTHkxz/QT3kvcs2QlGHvKLYsSlPOlPXnQ==} @@ -1896,12 +1929,24 @@ packages: '@typescript-eslint/parser': optional: true + eslint-plugin-jest@23.20.0: + resolution: {integrity: sha512-+6BGQt85OREevBDWCvhqj1yYA4+BFK4XnRZSGJionuEYmcglMZYLNNBBemwzbqUAckURaHdJSBcjHPyrtypZOw==} + engines: {node: '>=8'} + peerDependencies: + eslint: '>=5' + eslint-plugin-jsx-a11y@6.10.2: resolution: {integrity: sha512-scB3nz4WmG75pV8+3eRUQOHZlNSUhFNq37xnpgRkCCELU3XMvXAxLk1eqWWyE22Ki4Q01Fnsw9BA3cJHDPgn2Q==} engines: {node: '>=4.0'} peerDependencies: eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9 + eslint-plugin-mocha@6.3.0: + resolution: {integrity: sha512-Cd2roo8caAyG21oKaaNTj7cqeYRWW1I2B5SfpKRp0Ip1gkfwoR1Ow0IGlPWnNjzywdF4n+kHL8/9vM6zCJUxdg==} + engines: {node: '>=8.0.0'} + peerDependencies: + eslint: '>= 4.0.0' + eslint-plugin-n@15.7.0: resolution: {integrity: sha512-jDex9s7D/Qial8AGVIHq4W7NswpUD5DPDL2RH8Lzd9EloWUuvUkHfv4FRLMipH5q2UtyurorBkPeNi1wVWNh3Q==} engines: {node: '>=12.22.0'} @@ -1913,6 +1958,9 @@ packages: peerDependencies: eslint: '>=8.0.0' + eslint-plugin-preact@0.1.0: + resolution: {integrity: sha512-/ZNTjrTLhDOkZmW8cY6W91lfrGEhyF5i0KFRhjlvCAPcWENxeXlx1TKbKgzjyvGtei8c2WlvWCgxO5PdyXe0EA==} + eslint-plugin-prettier@4.2.5: resolution: {integrity: sha512-9Ni+xgemM2IWLq6aXEpP2+V/V30GeA/46Ar629vcMqVPodFFWC9skHu/D1phvuqtS8bJCFnNf01/qcmqYEwNfg==} engines: {node: '>=12.0.0'} @@ -1930,12 +1978,6 @@ packages: peerDependencies: eslint: ^7.0.0 || ^8.0.0 || ^9.0.0 - eslint-plugin-react-hooks@5.2.0: - resolution: {integrity: sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg==} - engines: {node: '>=10'} - peerDependencies: - eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 - eslint-plugin-react@7.37.5: resolution: {integrity: sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==} engines: {node: '>=4'} @@ -2143,14 +2185,6 @@ packages: resolution: {integrity: sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==} engines: {node: '>=8'} - globals@15.15.0: - resolution: {integrity: sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg==} - engines: {node: '>=18'} - - globals@16.3.0: - resolution: {integrity: sha512-bqWEnJ1Nt3neqx2q5SFfGS8r/ahumIakg3HcwtNlrVlwXIeNumWn/c7Pn/wKzGhf6SaW6H6uWXLqC30STCMchQ==} - engines: {node: '>=18'} - globalthis@1.0.4: resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==} engines: {node: '>= 0.4'} @@ -2562,6 +2596,9 @@ packages: lodash.merge@4.6.2: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + lodash@4.17.21: + resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + loose-envify@1.4.0: resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} hasBin: true @@ -2578,6 +2615,10 @@ packages: lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + lru-cache@6.0.0: + resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} + engines: {node: '>=10'} + magic-string@0.30.17: resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==} @@ -3060,6 +3101,9 @@ packages: queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + ramda@0.27.2: + resolution: {integrity: sha512-SbiLPU40JuJniHexQSAgad32hfwd+DRUdwF2PlVuI5RZD0/vahUco7R8vD86J/tcEKKF9vZrUVwgtmGCqlCKyA==} + randombytes@2.1.0: resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} @@ -3183,6 +3227,11 @@ packages: resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} hasBin: true + semver@7.3.5: + resolution: {integrity: sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==} + engines: {node: '>=10'} + hasBin: true + semver@7.7.2: resolution: {integrity: sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==} engines: {node: '>=10'} @@ -3703,6 +3752,9 @@ packages: yallist@3.1.1: resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + yallist@4.0.0: + resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} + yaml@2.8.0: resolution: {integrity: sha512-4lLa/EcQCB0cJkyts+FpIRx5G/llPxfP6VQU5KByHEhLxY3IJCH0f0Hy1MHI8sClTvsIb8qwRJ6R/ZdlDJ/leQ==} engines: {node: '>= 14.6'} @@ -3753,14 +3805,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/eslint-parser@7.28.0(@babel/core@7.28.0)(eslint@8.57.1)': - dependencies: - '@babel/core': 7.28.0 - '@nicolo-ribaudo/eslint-scope-5-internals': 5.1.1-v1 - eslint: 8.57.1 - eslint-visitor-keys: 2.1.0 - semver: 6.3.1 - '@babel/generator@7.28.0': dependencies: '@babel/parser': 7.28.0 @@ -3816,11 +3860,6 @@ snapshots: dependencies: '@babel/types': 7.28.1 - '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.28.0)': - dependencies: - '@babel/core': 7.28.0 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-syntax-jsx@7.27.1(@babel/core@7.28.0)': dependencies: '@babel/core': 7.28.0 @@ -4274,8 +4313,6 @@ snapshots: '@eslint/js@8.57.1': {} - '@eslint/js@9.32.0': {} - '@figma/plugin-typings@1.116.0': {} '@floating-ui/core@1.7.3': @@ -4353,17 +4390,13 @@ snapshots: '@juanelas/base64@1.1.5': {} - '@mdn/browser-compat-data@5.7.6': {} + '@mdn/browser-compat-data@3.3.14': {} '@nanostores/preact@1.0.0(nanostores@0.9.5)(preact@10.27.0)': dependencies: nanostores: 0.9.5 preact: 10.27.0 - '@nicolo-ribaudo/eslint-scope-5-internals@5.1.1-v1': - dependencies: - eslint-scope: 5.1.1 - '@nodelib/fs.scandir@2.1.5': dependencies: '@nodelib/fs.stat': 2.0.5 @@ -4565,13 +4598,13 @@ snapshots: '@types/semver@7.7.0': {} - '@typescript-eslint/eslint-plugin@5.62.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1)(typescript@5.8.3)': + '@typescript-eslint/eslint-plugin@5.61.0(@typescript-eslint/parser@5.61.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1)(typescript@5.8.3)': dependencies: '@eslint-community/regexpp': 4.12.1 - '@typescript-eslint/parser': 5.62.0(eslint@8.57.1)(typescript@5.8.3) - '@typescript-eslint/scope-manager': 5.62.0 - '@typescript-eslint/type-utils': 5.62.0(eslint@8.57.1)(typescript@5.8.3) - '@typescript-eslint/utils': 5.62.0(eslint@8.57.1)(typescript@5.8.3) + '@typescript-eslint/parser': 5.61.0(eslint@8.57.1)(typescript@5.8.3) + '@typescript-eslint/scope-manager': 5.61.0 + '@typescript-eslint/type-utils': 5.61.0(eslint@8.57.1)(typescript@5.8.3) + '@typescript-eslint/utils': 5.61.0(eslint@8.57.1)(typescript@5.8.3) debug: 4.4.1 eslint: 8.57.1 graphemer: 1.4.0 @@ -4584,11 +4617,22 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.8.3)': + '@typescript-eslint/experimental-utils@2.34.0(eslint@8.57.1)(typescript@5.8.3)': dependencies: - '@typescript-eslint/scope-manager': 5.62.0 - '@typescript-eslint/types': 5.62.0 - '@typescript-eslint/typescript-estree': 5.62.0(typescript@5.8.3) + '@types/json-schema': 7.0.15 + '@typescript-eslint/typescript-estree': 2.34.0(typescript@5.8.3) + eslint: 8.57.1 + eslint-scope: 5.1.1 + eslint-utils: 2.1.0 + transitivePeerDependencies: + - supports-color + - typescript + + '@typescript-eslint/parser@5.61.0(eslint@8.57.1)(typescript@5.8.3)': + dependencies: + '@typescript-eslint/scope-manager': 5.61.0 + '@typescript-eslint/types': 5.61.0 + '@typescript-eslint/typescript-estree': 5.61.0(typescript@5.8.3) debug: 4.4.1 eslint: 8.57.1 optionalDependencies: @@ -4596,15 +4640,20 @@ snapshots: transitivePeerDependencies: - supports-color + '@typescript-eslint/scope-manager@5.61.0': + dependencies: + '@typescript-eslint/types': 5.61.0 + '@typescript-eslint/visitor-keys': 5.61.0 + '@typescript-eslint/scope-manager@5.62.0': dependencies: '@typescript-eslint/types': 5.62.0 '@typescript-eslint/visitor-keys': 5.62.0 - '@typescript-eslint/type-utils@5.62.0(eslint@8.57.1)(typescript@5.8.3)': + '@typescript-eslint/type-utils@5.61.0(eslint@8.57.1)(typescript@5.8.3)': dependencies: - '@typescript-eslint/typescript-estree': 5.62.0(typescript@5.8.3) - '@typescript-eslint/utils': 5.62.0(eslint@8.57.1)(typescript@5.8.3) + '@typescript-eslint/typescript-estree': 5.61.0(typescript@5.8.3) + '@typescript-eslint/utils': 5.61.0(eslint@8.57.1)(typescript@5.8.3) debug: 4.4.1 eslint: 8.57.1 tsutils: 3.21.0(typescript@5.8.3) @@ -4613,8 +4662,38 @@ snapshots: transitivePeerDependencies: - supports-color + '@typescript-eslint/types@5.61.0': {} + '@typescript-eslint/types@5.62.0': {} + '@typescript-eslint/typescript-estree@2.34.0(typescript@5.8.3)': + dependencies: + debug: 4.4.1 + eslint-visitor-keys: 1.3.0 + glob: 7.2.3 + is-glob: 4.0.3 + lodash: 4.17.21 + semver: 7.7.2 + tsutils: 3.21.0(typescript@5.8.3) + optionalDependencies: + typescript: 5.8.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/typescript-estree@5.61.0(typescript@5.8.3)': + dependencies: + '@typescript-eslint/types': 5.61.0 + '@typescript-eslint/visitor-keys': 5.61.0 + debug: 4.4.1 + globby: 11.1.0 + is-glob: 4.0.3 + semver: 7.7.2 + tsutils: 3.21.0(typescript@5.8.3) + optionalDependencies: + typescript: 5.8.3 + transitivePeerDependencies: + - supports-color + '@typescript-eslint/typescript-estree@5.62.0(typescript@5.8.3)': dependencies: '@typescript-eslint/types': 5.62.0 @@ -4629,6 +4708,21 @@ snapshots: transitivePeerDependencies: - supports-color + '@typescript-eslint/utils@5.61.0(eslint@8.57.1)(typescript@5.8.3)': + dependencies: + '@eslint-community/eslint-utils': 4.7.0(eslint@8.57.1) + '@types/json-schema': 7.0.15 + '@types/semver': 7.7.0 + '@typescript-eslint/scope-manager': 5.61.0 + '@typescript-eslint/types': 5.61.0 + '@typescript-eslint/typescript-estree': 5.61.0(typescript@5.8.3) + eslint: 8.57.1 + eslint-scope: 5.1.1 + semver: 7.7.2 + transitivePeerDependencies: + - supports-color + - typescript + '@typescript-eslint/utils@5.62.0(eslint@8.57.1)(typescript@5.8.3)': dependencies: '@eslint-community/eslint-utils': 4.7.0(eslint@8.57.1) @@ -4644,6 +4738,11 @@ snapshots: - supports-color - typescript + '@typescript-eslint/visitor-keys@5.61.0': + dependencies: + '@typescript-eslint/types': 5.61.0 + eslint-visitor-keys: 3.4.3 + '@typescript-eslint/visitor-keys@5.62.0': dependencies: '@typescript-eslint/types': 5.62.0 @@ -4927,9 +5026,9 @@ snapshots: assertion-error@1.1.0: {} - ast-metadata-inferer@0.8.1: + ast-metadata-inferer@0.7.0: dependencies: - '@mdn/browser-compat-data': 5.7.6 + '@mdn/browser-compat-data': 3.3.14 ast-types-flow@0.0.8: {} @@ -4955,6 +5054,18 @@ snapshots: axobject-query@4.1.0: {} + babel-eslint@10.1.0(eslint@8.57.1): + dependencies: + '@babel/code-frame': 7.27.1 + '@babel/parser': 7.28.0 + '@babel/traverse': 7.28.0 + '@babel/types': 7.28.1 + eslint: 8.57.1 + eslint-visitor-keys: 1.3.0 + resolve: 1.22.10 + transitivePeerDependencies: + - supports-color + babel-plugin-transform-hook-names@1.0.2(@babel/core@7.28.0): dependencies: '@babel/core': 7.28.0 @@ -5089,6 +5200,8 @@ snapshots: dependencies: toggle-selection: 1.0.6 + core-js@3.45.0: {} + cosmiconfig@8.3.6(typescript@5.8.3): dependencies: import-fresh: 3.3.1 @@ -5432,48 +5545,45 @@ snapshots: escape-string-regexp@4.0.0: {} - eslint-config-preact@2.0.0(eslint@8.57.1): + eslint-config-developit@1.2.0(eslint@8.57.1)(typescript@5.8.3): dependencies: - '@babel/core': 7.28.0 - '@babel/eslint-parser': 7.28.0(@babel/core@7.28.0)(eslint@8.57.1) - '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.28.0) - '@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.28.0) - '@eslint/js': 9.32.0 + babel-eslint: 10.1.0(eslint@8.57.1) eslint: 8.57.1 - eslint-plugin-compat: 6.0.2(eslint@8.57.1) + eslint-plugin-compat: 3.13.0(eslint@8.57.1) + eslint-plugin-jest: 23.20.0(eslint@8.57.1)(typescript@5.8.3) + eslint-plugin-mocha: 6.3.0(eslint@8.57.1) eslint-plugin-react: 7.37.5(eslint@8.57.1) - eslint-plugin-react-hooks: 5.2.0(eslint@8.57.1) - globals: 16.3.0 transitivePeerDependencies: - supports-color + - typescript eslint-config-prettier@8.10.2(eslint@8.57.1): dependencies: eslint: 8.57.1 - eslint-config-standard-with-typescript@36.1.1(@typescript-eslint/eslint-plugin@5.62.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1)(typescript@5.8.3))(eslint-plugin-import@2.32.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1))(eslint-plugin-n@15.7.0(eslint@8.57.1))(eslint-plugin-promise@6.6.0(eslint@8.57.1))(eslint@8.57.1)(typescript@5.8.3): + eslint-config-standard-with-typescript@36.1.1(@typescript-eslint/eslint-plugin@5.61.0(@typescript-eslint/parser@5.61.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1)(typescript@5.8.3))(eslint-plugin-import@2.32.0(@typescript-eslint/parser@5.61.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1))(eslint-plugin-n@15.7.0(eslint@8.57.1))(eslint-plugin-promise@6.6.0(eslint@8.57.1))(eslint@8.57.1)(typescript@5.8.3): dependencies: - '@typescript-eslint/eslint-plugin': 5.62.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1)(typescript@5.8.3) - '@typescript-eslint/parser': 5.62.0(eslint@8.57.1)(typescript@5.8.3) + '@typescript-eslint/eslint-plugin': 5.61.0(@typescript-eslint/parser@5.61.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1)(typescript@5.8.3) + '@typescript-eslint/parser': 5.61.0(eslint@8.57.1)(typescript@5.8.3) eslint: 8.57.1 - eslint-config-standard: 17.1.0(eslint-plugin-import@2.32.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1))(eslint-plugin-n@15.7.0(eslint@8.57.1))(eslint-plugin-promise@6.6.0(eslint@8.57.1))(eslint@8.57.1) - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1) + eslint-config-standard: 17.1.0(eslint-plugin-import@2.32.0(@typescript-eslint/parser@5.61.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1))(eslint-plugin-n@15.7.0(eslint@8.57.1))(eslint-plugin-promise@6.6.0(eslint@8.57.1))(eslint@8.57.1) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@5.61.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1) eslint-plugin-n: 15.7.0(eslint@8.57.1) eslint-plugin-promise: 6.6.0(eslint@8.57.1) typescript: 5.8.3 transitivePeerDependencies: - supports-color - eslint-config-standard@17.1.0(eslint-plugin-import@2.32.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1))(eslint-plugin-n@15.7.0(eslint@8.57.1))(eslint-plugin-promise@6.6.0(eslint@8.57.1))(eslint@8.57.1): + eslint-config-standard@17.1.0(eslint-plugin-import@2.32.0(@typescript-eslint/parser@5.61.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1))(eslint-plugin-n@15.7.0(eslint@8.57.1))(eslint-plugin-promise@6.6.0(eslint@8.57.1))(eslint@8.57.1): dependencies: eslint: 8.57.1 - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@5.61.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1) eslint-plugin-n: 15.7.0(eslint@8.57.1) eslint-plugin-promise: 6.6.0(eslint@8.57.1) - eslint-import-resolver-alias@1.1.2(eslint-plugin-import@2.32.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1)): + eslint-import-resolver-alias@1.1.2(eslint-plugin-import@2.32.0(@typescript-eslint/parser@5.61.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1)): dependencies: - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@5.61.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1) eslint-import-resolver-node@0.3.9: dependencies: @@ -5483,32 +5593,32 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-module-utils@2.12.1(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint@8.57.1): + eslint-module-utils@2.12.1(@typescript-eslint/parser@5.61.0(eslint@8.57.1)(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint@8.57.1): dependencies: debug: 3.2.7 optionalDependencies: - '@typescript-eslint/parser': 5.62.0(eslint@8.57.1)(typescript@5.8.3) + '@typescript-eslint/parser': 5.61.0(eslint@8.57.1)(typescript@5.8.3) eslint: 8.57.1 eslint-import-resolver-node: 0.3.9 transitivePeerDependencies: - supports-color - eslint-module-utils@2.8.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint@8.57.1): + eslint-module-utils@2.8.0(@typescript-eslint/parser@5.61.0(eslint@8.57.1)(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint@8.57.1): dependencies: debug: 3.2.7 optionalDependencies: - '@typescript-eslint/parser': 5.62.0(eslint@8.57.1)(typescript@5.8.3) + '@typescript-eslint/parser': 5.61.0(eslint@8.57.1)(typescript@5.8.3) eslint: 8.57.1 eslint-import-resolver-node: 0.3.9 transitivePeerDependencies: - supports-color - eslint-plugin-boundaries@3.4.1(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1): + eslint-plugin-boundaries@3.4.1(@typescript-eslint/parser@5.61.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1): dependencies: chalk: 4.1.2 eslint: 8.57.1 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.8.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint@8.57.1) + eslint-module-utils: 2.8.0(@typescript-eslint/parser@5.61.0(eslint@8.57.1)(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint@8.57.1) is-core-module: 2.13.1 micromatch: 4.0.5 transitivePeerDependencies: @@ -5517,17 +5627,17 @@ snapshots: - eslint-import-resolver-webpack - supports-color - eslint-plugin-compat@6.0.2(eslint@8.57.1): + eslint-plugin-compat@3.13.0(eslint@8.57.1): dependencies: - '@mdn/browser-compat-data': 5.7.6 - ast-metadata-inferer: 0.8.1 + '@mdn/browser-compat-data': 3.3.14 + ast-metadata-inferer: 0.7.0 browserslist: 4.25.1 caniuse-lite: 1.0.30001727 + core-js: 3.45.0 eslint: 8.57.1 find-up: 5.0.0 - globals: 15.15.0 lodash.memoize: 4.1.2 - semver: 7.7.2 + semver: 7.3.5 eslint-plugin-es@4.1.0(eslint@8.57.1): dependencies: @@ -5535,7 +5645,7 @@ snapshots: eslint-utils: 2.1.0 regexpp: 3.2.0 - eslint-plugin-import@2.32.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1): + eslint-plugin-import@2.32.0(@typescript-eslint/parser@5.61.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1): dependencies: '@rtsao/scc': 1.1.0 array-includes: 3.1.9 @@ -5546,7 +5656,7 @@ snapshots: doctrine: 2.1.0 eslint: 8.57.1 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.1(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint@8.57.1) + eslint-module-utils: 2.12.1(@typescript-eslint/parser@5.61.0(eslint@8.57.1)(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint@8.57.1) hasown: 2.0.2 is-core-module: 2.16.1 is-glob: 4.0.3 @@ -5558,12 +5668,20 @@ snapshots: string.prototype.trimend: 1.0.9 tsconfig-paths: 3.15.0 optionalDependencies: - '@typescript-eslint/parser': 5.62.0(eslint@8.57.1)(typescript@5.8.3) + '@typescript-eslint/parser': 5.61.0(eslint@8.57.1)(typescript@5.8.3) transitivePeerDependencies: - eslint-import-resolver-typescript - eslint-import-resolver-webpack - supports-color + eslint-plugin-jest@23.20.0(eslint@8.57.1)(typescript@5.8.3): + dependencies: + '@typescript-eslint/experimental-utils': 2.34.0(eslint@8.57.1)(typescript@5.8.3) + eslint: 8.57.1 + transitivePeerDependencies: + - supports-color + - typescript + eslint-plugin-jsx-a11y@6.10.2(eslint@8.57.1): dependencies: aria-query: 5.3.2 @@ -5583,6 +5701,12 @@ snapshots: safe-regex-test: 1.1.0 string.prototype.includes: 2.0.1 + eslint-plugin-mocha@6.3.0(eslint@8.57.1): + dependencies: + eslint: 8.57.1 + eslint-utils: 2.1.0 + ramda: 0.27.2 + eslint-plugin-n@15.7.0(eslint@8.57.1): dependencies: builtins: 5.1.0 @@ -5608,6 +5732,14 @@ snapshots: - supports-color - typescript + eslint-plugin-preact@0.1.0(eslint@8.57.1)(typescript@5.8.3): + dependencies: + eslint-config-developit: 1.2.0(eslint@8.57.1)(typescript@5.8.3) + transitivePeerDependencies: + - eslint + - supports-color + - typescript + eslint-plugin-prettier@4.2.5(eslint-config-prettier@8.10.2(eslint@8.57.1))(eslint@8.57.1)(prettier@3.6.2): dependencies: eslint: 8.57.1 @@ -5620,10 +5752,6 @@ snapshots: dependencies: eslint: 8.57.1 - eslint-plugin-react-hooks@5.2.0(eslint@8.57.1): - dependencies: - eslint: 8.57.1 - eslint-plugin-react@7.37.5(eslint@8.57.1): dependencies: array-includes: 3.1.9 @@ -5890,10 +6018,6 @@ snapshots: dependencies: type-fest: 0.20.2 - globals@15.15.0: {} - - globals@16.3.0: {} - globalthis@1.0.4: dependencies: define-properties: 1.2.1 @@ -6303,6 +6427,8 @@ snapshots: lodash.merge@4.6.2: {} + lodash@4.17.21: {} + loose-envify@1.4.0: dependencies: js-tokens: 4.0.0 @@ -6321,6 +6447,10 @@ snapshots: dependencies: yallist: 3.1.1 + lru-cache@6.0.0: + dependencies: + yallist: 4.0.0 + magic-string@0.30.17: dependencies: '@jridgewell/sourcemap-codec': 1.5.4 @@ -6840,6 +6970,8 @@ snapshots: queue-microtask@1.2.3: {} + ramda@0.27.2: {} + randombytes@2.1.0: dependencies: safe-buffer: 5.2.1 @@ -6974,6 +7106,10 @@ snapshots: semver@6.3.1: {} + semver@7.3.5: + dependencies: + lru-cache: 6.0.0 + semver@7.7.2: {} serialize-javascript@6.0.2: @@ -7606,6 +7742,8 @@ snapshots: yallist@3.1.1: {} + yallist@4.0.0: {} + yaml@2.8.0: {} yocto-queue@0.1.0: {} diff --git a/src/api/services/figma/intersections/traverse-and-check-intersections.ts b/src/api/services/figma/intersections/traverse-and-check-intersections.ts index b6e3636..b995cf4 100644 --- a/src/api/services/figma/intersections/traverse-and-check-intersections.ts +++ b/src/api/services/figma/intersections/traverse-and-check-intersections.ts @@ -7,17 +7,14 @@ import { getSiblingsThatAreBelowByZIndex } from './get-siblings-that-are-below-b const ifSelectedNodeIsChild = ( node: SceneNode, selectedNode: SceneNode -): boolean => { - return ( +): boolean => ( 'children' in node && node.children.some((n) => n.id === selectedNode.id) ); -}; export const traverseAndCheckIntersections = ( nodes: SceneNode[], selectedNode: SceneNode -): PolychromNode[] => { - return nodes.reduce((accumulator: PolychromNode[], node) => { +): PolychromNode[] => nodes.reduce((accumulator: PolychromNode[], node) => { if (areNodesIntersecting(node, selectedNode)) { const polychromNode = createPolychromNode(node, selectedNode.id); @@ -37,4 +34,3 @@ export const traverseAndCheckIntersections = ( return accumulator; }, []); -}; diff --git a/src/api/services/figma/nodes/create-polychrom-node.ts b/src/api/services/figma/nodes/create-polychrom-node.ts index f0e38ed..083f862 100644 --- a/src/api/services/figma/nodes/create-polychrom-node.ts +++ b/src/api/services/figma/nodes/create-polychrom-node.ts @@ -22,9 +22,9 @@ export const createPolychromNode = ( hex: formatHex({ ...fill.color, mode: 'rgb' }), oklch: convertToOklch({ ...fill.color, mode: 'rgb' }, 'oklch'), }; - } else { + } return fill; - } + }), id: node.id, isSelected: node.id === selectedNodeId, @@ -33,8 +33,6 @@ export const createPolychromNode = ( opacity: 'opacity' in node ? node.opacity : 1, parents, visible: 'visible' in node ? node.visible : true, - zIndex: node.parent?.children.findIndex((child) => { - return child.id === node.id; - }), + zIndex: node.parent?.children.findIndex((child) => child.id === node.id), }; }; diff --git a/src/api/services/figma/nodes/is-valid-for-selection.ts b/src/api/services/figma/nodes/is-valid-for-selection.ts index 32e4b62..8af5415 100644 --- a/src/api/services/figma/nodes/is-valid-for-selection.ts +++ b/src/api/services/figma/nodes/is-valid-for-selection.ts @@ -13,15 +13,15 @@ export const isValidForSelection = (node: SceneNode): boolean => { if ('fills' in node) { if (typeof node.fills === 'symbol') { return false; - } else { + } const actualFill = getActualFill(node.fills); if (notEmpty(actualFill)) { return actualFill.type === 'SOLID'; - } else { + } return false; - } - } + + } return false; diff --git a/src/api/services/payload/build-general-selection-payload.ts b/src/api/services/payload/build-general-selection-payload.ts index 65a2123..cefacec 100644 --- a/src/api/services/payload/build-general-selection-payload.ts +++ b/src/api/services/payload/build-general-selection-payload.ts @@ -16,13 +16,11 @@ enum PairState { const isValidSelection = ( pair: PairState | PolychromNode -): pair is PolychromNode => { - return ( +): pair is PolychromNode => ( notEmpty(pair) && pair !== PairState.InvalidBackground && pair !== PairState.InvalidBlendMode ); -}; export const buildGeneralSelectionPayload = ( selection: readonly SceneNode[] @@ -38,9 +36,9 @@ export const buildGeneralSelectionPayload = ( if (isValidForBackground(intersectingNodesTree)) { return intersectingNodesTree; - } else { + } return PairState.InvalidBackground; - } + }); const isSingleInvalidBackground = diff --git a/src/ui/components/AppContent.tsx b/src/ui/components/AppContent.tsx index 38109cf..47afa3b 100644 --- a/src/ui/components/AppContent.tsx +++ b/src/ui/components/AppContent.tsx @@ -39,7 +39,7 @@ export const AppContent = (): ReactElement => { if (isMultiSelection) { return ; - } else { + } const pair = contrastConclusion[0]; if (isEmpty(pair)) { @@ -47,5 +47,5 @@ export const AppContent = (): ReactElement => { } return ; - } + }; diff --git a/src/ui/components/BasicColorPreviewIcon.tsx b/src/ui/components/BasicColorPreviewIcon.tsx index 4f17fe1..0418456 100644 --- a/src/ui/components/BasicColorPreviewIcon.tsx +++ b/src/ui/components/BasicColorPreviewIcon.tsx @@ -8,8 +8,7 @@ interface Props { export const BasicColorPreviewIcon = ({ borderColor, indicatorColor, -}: Props): ReactElement => { - return ( +}: Props): ReactElement => ( ); -}; diff --git a/src/ui/components/ColorIndicator.tsx b/src/ui/components/ColorIndicator.tsx index 29aabba..7ed773f 100644 --- a/src/ui/components/ColorIndicator.tsx +++ b/src/ui/components/ColorIndicator.tsx @@ -1,6 +1,7 @@ import { useStore } from '@nanostores/preact'; import { ColorPreview } from '~ui/components/ColorPreview.tsx'; import { ThemeVariablesKeys } from '~ui/components/ThemeVariablesProvider.tsx'; +import { Tooltip } from '~ui/components/Tooltip.tsx'; import { getFormatterForCSS, getFormatterForDisplaying, @@ -10,7 +11,6 @@ import { type ReactElement } from 'preact/compat'; import useClipboard from 'react-use-clipboard'; import { $colorSpaceDisplayMode } from '../stores/color-space-display-mode.ts'; -import { Tooltip } from '~ui/components/Tooltip.tsx'; interface ColorIndicatorProps { borderColor: string; diff --git a/src/ui/components/ContrastSample.tsx b/src/ui/components/ContrastSample.tsx index e4cc858..584b39b 100644 --- a/src/ui/components/ContrastSample.tsx +++ b/src/ui/components/ContrastSample.tsx @@ -16,11 +16,10 @@ export const ContrastSample = ({ color, opacity, size, -}: Props): ReactElement => { - return ( +}: Props): ReactElement => (

); -}; diff --git a/src/ui/components/EmptySelectionMessage.tsx b/src/ui/components/EmptySelectionMessage.tsx index e3f7d60..d9361f3 100644 --- a/src/ui/components/EmptySelectionMessage.tsx +++ b/src/ui/components/EmptySelectionMessage.tsx @@ -1,8 +1,7 @@ import ufoImage from '~ui/assets/ufo@2x.webp'; import { type ReactElement } from 'preact/compat'; -export const EmptySelectionMessage = (): ReactElement => { - return ( +export const EmptySelectionMessage = (): ReactElement => (

{ Select a layer with a solid fill

); -}; diff --git a/src/ui/components/HelpIcon.tsx b/src/ui/components/HelpIcon.tsx index 6386dc9..1a4ad15 100644 --- a/src/ui/components/HelpIcon.tsx +++ b/src/ui/components/HelpIcon.tsx @@ -1,7 +1,6 @@ import { type ReactElement } from 'preact/compat'; -export const HelpIcon = (): ReactElement => { - return ( +export const HelpIcon = (): ReactElement => ( { /> ); -}; diff --git a/src/ui/components/HelpLink.tsx b/src/ui/components/HelpLink.tsx index bc54c95..e41e8a7 100644 --- a/src/ui/components/HelpLink.tsx +++ b/src/ui/components/HelpLink.tsx @@ -4,11 +4,10 @@ import { type ReactElement } from 'preact/compat'; import { APCADocumentationURL } from '../../constants.ts'; -export const HelpLink = (): ReactElement => { - return ( +export const HelpLink = (): ReactElement => ( { ); -}; diff --git a/src/ui/components/InvalidBackgroundSelectionMessage.tsx b/src/ui/components/InvalidBackgroundSelectionMessage.tsx index 92dfaf0..8d1ebb6 100644 --- a/src/ui/components/InvalidBackgroundSelectionMessage.tsx +++ b/src/ui/components/InvalidBackgroundSelectionMessage.tsx @@ -1,8 +1,7 @@ import layersImage from '~ui/assets/layers@2x.webp'; -import { ReactElement } from 'preact/compat'; +import { type ReactElement } from 'preact/compat'; -export const InvalidBackgroundSelectionMessage = (): ReactElement => { - return ( +export const InvalidBackgroundSelectionMessage = (): ReactElement => (

{ The background layer should be a solid fill

); -}; diff --git a/src/ui/components/LayeredColorPreviewIcon.tsx b/src/ui/components/LayeredColorPreviewIcon.tsx index 87e1548..96ffaf2 100644 --- a/src/ui/components/LayeredColorPreviewIcon.tsx +++ b/src/ui/components/LayeredColorPreviewIcon.tsx @@ -8,9 +8,8 @@ interface Props { export const LayeredColorPreviewIcon = ({ borderColor, indicatorColor, -}: Props): ReactElement => { - return ( -
+}: Props): ReactElement => ( +
); -}; diff --git a/src/ui/components/LurkersIcon.tsx b/src/ui/components/LurkersIcon.tsx index 156c655..09faa9e 100644 --- a/src/ui/components/LurkersIcon.tsx +++ b/src/ui/components/LurkersIcon.tsx @@ -1,7 +1,6 @@ import { type ReactElement } from 'preact/compat'; -export const LurkersIcon = (): ReactElement => { - return ( +export const LurkersIcon = (): ReactElement => (
{
); -}; diff --git a/src/ui/components/LurkersLink.tsx b/src/ui/components/LurkersLink.tsx index 5633a85..8e1f272 100644 --- a/src/ui/components/LurkersLink.tsx +++ b/src/ui/components/LurkersLink.tsx @@ -4,8 +4,7 @@ import { type ReactElement } from 'preact/compat'; import { evilMartiansSiteURL } from '../../constants.ts'; -export const LurkersLink = (): ReactElement => { - return ( +export const LurkersLink = (): ReactElement => ( { ); -}; diff --git a/src/ui/components/PictureIcon.tsx b/src/ui/components/PictureIcon.tsx index addd42e..10be6cc 100644 --- a/src/ui/components/PictureIcon.tsx +++ b/src/ui/components/PictureIcon.tsx @@ -1,8 +1,7 @@ import { ThemeVariablesKeys } from '~ui/components/ThemeVariablesProvider.tsx'; import { type ReactElement } from 'preact/compat'; -export const PictureIcon = (): ReactElement => { - return ( +export const PictureIcon = (): ReactElement => ( { /> ); -}; diff --git a/src/ui/components/RewardingAnimationBodyText.tsx b/src/ui/components/RewardingAnimationBodyText.tsx index 2ca428f..284ba3d 100644 --- a/src/ui/components/RewardingAnimationBodyText.tsx +++ b/src/ui/components/RewardingAnimationBodyText.tsx @@ -1,11 +1,9 @@ import { type ReactElement } from 'preact/compat'; -export const RewardingAnimationBodyText = (): ReactElement => { - return ( +export const RewardingAnimationBodyText = (): ReactElement => (
-
-
-
+
+
+
); -}; diff --git a/src/ui/components/RewardingAnimationContentText.tsx b/src/ui/components/RewardingAnimationContentText.tsx index 0c0cb47..3df6c36 100644 --- a/src/ui/components/RewardingAnimationContentText.tsx +++ b/src/ui/components/RewardingAnimationContentText.tsx @@ -1,9 +1,7 @@ import { type ReactElement } from 'preact/compat'; -export const RewardingAnimationContentText = (): ReactElement => { - return ( +export const RewardingAnimationContentText = (): ReactElement => (
); -}; diff --git a/src/ui/components/RewardingAnimationFluentText.tsx b/src/ui/components/RewardingAnimationFluentText.tsx index 97c3c76..038037f 100644 --- a/src/ui/components/RewardingAnimationFluentText.tsx +++ b/src/ui/components/RewardingAnimationFluentText.tsx @@ -1,12 +1,10 @@ import { type ReactElement } from 'preact/compat'; -export const RewardingAnimationFluentText = (): ReactElement => { - return ( +export const RewardingAnimationFluentText = (): ReactElement => (
-
-
-
-
+
+
+
+
); -}; diff --git a/src/ui/components/Selection.tsx b/src/ui/components/Selection.tsx index 68c5f95..c54d14a 100644 --- a/src/ui/components/Selection.tsx +++ b/src/ui/components/Selection.tsx @@ -1,3 +1,4 @@ +import { signal } from '@preact/signals-core'; import { ThemeVariablesKeys, ThemeVariablesProvider, @@ -6,7 +7,6 @@ import { type ContrastConclusion } from '~ui/types'; import { isEmpty } from '~utils/not-empty.ts'; import clsx from 'clsx'; import { type ReactElement } from 'preact/compat'; -import { signal } from '@preact/signals-core'; import { generateUIColors } from '../services/theme/generate-ui-colors.ts'; import { SegmentedFontStyleDefinition } from './SegmentedFontStyleDefinition.tsx'; diff --git a/src/ui/components/SelectionContent.tsx b/src/ui/components/SelectionContent.tsx index b7f46d5..4779333 100644 --- a/src/ui/components/SelectionContent.tsx +++ b/src/ui/components/SelectionContent.tsx @@ -31,7 +31,7 @@ export const SelectionContent = ({ const fgColor = formatColorForTheme(fg); return ( -
+
{ - return ( +export const SelectionsList = ({ contrastConclusion }: Props): ReactElement => (
    {contrastConclusion?.map((pair, index) => (
  • { ))}
); -}; diff --git a/src/ui/components/SettingsIcon.tsx b/src/ui/components/SettingsIcon.tsx index 177a25c..0e2769e 100644 --- a/src/ui/components/SettingsIcon.tsx +++ b/src/ui/components/SettingsIcon.tsx @@ -1,7 +1,6 @@ import { type ReactElement } from 'preact/compat'; -export const SettingsIcon = (): ReactElement => { - return ( +export const SettingsIcon = (): ReactElement => ( { /> ); -}; diff --git a/src/ui/components/StopIcon.tsx b/src/ui/components/StopIcon.tsx index ec08386..f13fdd9 100644 --- a/src/ui/components/StopIcon.tsx +++ b/src/ui/components/StopIcon.tsx @@ -1,8 +1,7 @@ import { ThemeVariablesKeys } from '~ui/components/ThemeVariablesProvider.tsx'; import { type ReactElement } from 'preact/compat'; -export const StopIcon = (): ReactElement => { - return ( +export const StopIcon = (): ReactElement => ( { /> ); -}; diff --git a/src/ui/components/UnprocessedBlendModesSelectionMessage.tsx b/src/ui/components/UnprocessedBlendModesSelectionMessage.tsx index 99a46f1..6ca7d28 100644 --- a/src/ui/components/UnprocessedBlendModesSelectionMessage.tsx +++ b/src/ui/components/UnprocessedBlendModesSelectionMessage.tsx @@ -1,8 +1,7 @@ import layersImage from '~ui/assets/layers@2x.webp'; import { type ReactElement } from 'preact/compat'; -export const UnprocessedBlendModesSelectionMessage = (): ReactElement => { - return ( +export const UnprocessedBlendModesSelectionMessage = (): ReactElement => (

{ The blending mode Plus Darker is not supported

); -}; diff --git a/src/ui/components/WarningIcon.tsx b/src/ui/components/WarningIcon.tsx index 117be4e..a7570c5 100644 --- a/src/ui/components/WarningIcon.tsx +++ b/src/ui/components/WarningIcon.tsx @@ -1,8 +1,7 @@ import { ThemeVariablesKeys } from '~ui/components/ThemeVariablesProvider.tsx'; import { type ReactElement } from 'preact/compat'; -export const WarningIcon = (): ReactElement => { - return ( +export const WarningIcon = (): ReactElement => ( { /> ); -}; diff --git a/src/ui/index.tsx b/src/ui/index.tsx index f902748..b7f47fd 100644 --- a/src/ui/index.tsx +++ b/src/ui/index.tsx @@ -4,7 +4,7 @@ import { notEmpty } from '../utils/not-empty.ts'; import { App } from './components/App'; import './style.css'; -document.addEventListener('DOMContentLoaded', function () { +document.addEventListener('DOMContentLoaded', () => { const container = document.getElementById('root'); if (notEmpty(container)) { diff --git a/src/ui/services/blend-modes/map-figma-blend-to-canvas.ts b/src/ui/services/blend-modes/map-figma-blend-to-canvas.ts index 136b0c3..3eef03d 100644 --- a/src/ui/services/blend-modes/map-figma-blend-to-canvas.ts +++ b/src/ui/services/blend-modes/map-figma-blend-to-canvas.ts @@ -1,5 +1,5 @@ import { notEmpty } from '~utils/not-empty.ts'; -import { CSSProperties } from 'preact/compat'; +import { type CSSProperties } from 'preact/compat'; export const mapFigmaBlendToCanvas = ( figmaBlend?: BlendMode diff --git a/src/ui/services/blend/is-blended-fill.ts b/src/ui/services/blend/is-blended-fill.ts index 5bfa7d2..fab84c2 100644 --- a/src/ui/services/blend/is-blended-fill.ts +++ b/src/ui/services/blend/is-blended-fill.ts @@ -5,9 +5,7 @@ import { notEmpty } from '~utils/not-empty.ts'; export const isBlendedFill = ( node?: PolychromNode, fill?: FigmaPaint -): boolean => { - return ( +): boolean => ( (notEmpty(node) && node.opacity !== 1) || (notEmpty(fill) && fill.opacity !== 1) ); -}; diff --git a/src/ui/services/canvas/get-fill-from-ctx.ts b/src/ui/services/canvas/get-fill-from-ctx.ts index f30ac05..9af72a8 100644 --- a/src/ui/services/canvas/get-fill-from-ctx.ts +++ b/src/ui/services/canvas/get-fill-from-ctx.ts @@ -7,8 +7,6 @@ export const getFillFromCtx = ( x: number, y: number, colorSpace: FigmaColorSpace -): Uint8ClampedArray => { - return ctx.getImageData(x, y, 1, 1, { +): Uint8ClampedArray => ctx.getImageData(x, y, 1, 1, { colorSpace: isSupportsOKLCH ? CanvasColorSpace[colorSpace] : 'srgb', }).data; -}; diff --git a/src/ui/services/theme/generate-ui-colors.ts b/src/ui/services/theme/generate-ui-colors.ts index 21f51c0..4391331 100644 --- a/src/ui/services/theme/generate-ui-colors.ts +++ b/src/ui/services/theme/generate-ui-colors.ts @@ -40,15 +40,13 @@ const fixHue = (oklchColor: null | Oklch): null | Oklch => { return oklchColor; }; -const apcachToCulori = (apcachColor: ApcachColor): Oklch => { - return { +const apcachToCulori = (apcachColor: ApcachColor): Oklch => ({ alpha: apcachColor.alpha, c: apcachColor.chroma, h: apcachColor.hue, l: apcachColor.lightness, mode: 'oklch', - }; -}; + }); const transformFgColor = (colorFg: UIColor, colorBg: UIColor): UIColor => { const { oklch: oklchFg } = colorFg; @@ -195,9 +193,9 @@ const getSecondaryColor = (colorBg: UIColor): UIColor => { ) { if (apcachSecondaryA.chroma >= apcachSecondaryB.chroma) { return { hex: hexSecondaryA, oklch: apcachToCulori(apcachSecondaryA) }; - } else { + } return { hex: hexSecondaryB, oklch: apcachToCulori(apcachSecondaryB) }; - } + } // Else prefer the option with greater contrast @@ -209,9 +207,7 @@ const getSecondaryColor = (colorBg: UIColor): UIColor => { }; const getThemeWithMaxLc = (themes: Theme[]): null | Theme => { - const Lcs = themes.map((theme) => { - return theme.Lc; - }); + const Lcs = themes.map((theme) => theme.Lc); const max = Math.max(...Lcs); @@ -272,9 +268,9 @@ export const generateUIColors = ( oklchFg, theme, }; - } else { + } themes.push(theme); - } + // CASE 2: If the result contrast isn’t good enough, let’s change the BG theme = getThemeWithTransformedBg(colorFg, colorBg); @@ -287,9 +283,9 @@ export const generateUIColors = ( oklchFg, theme, }; - } else { + } themes.push(theme); - } + // If nothing worked, it’s time to change both and end there theme = getThemeWithBothColorsTransformed(colorFg, colorBg); @@ -306,7 +302,7 @@ export const generateUIColors = ( oklchFg, theme: themeWithMaxLc, }; - } else { + } return undefined; - } + }; diff --git a/src/ui/stores/selected-nodes.ts b/src/ui/stores/selected-nodes.ts index f20cf37..cb8c76f 100644 --- a/src/ui/stores/selected-nodes.ts +++ b/src/ui/stores/selected-nodes.ts @@ -19,33 +19,25 @@ export const $userSelection = atom({ export const $contrastConclusion = atom([]); -export const $isP3 = computed($userSelection, (selection) => { - return 'colorSpace' in selection +export const $isP3 = computed($userSelection, (selection) => 'colorSpace' in selection ? selection.colorSpace === 'DISPLAY_P3' - : false; -}); + : false); -export const $isMultiSelection = computed($userSelection, (selection) => { - return 'selectedNodePairs' in selection +export const $isMultiSelection = computed($userSelection, (selection) => 'selectedNodePairs' in selection ? selection.selectedNodePairs.length > 1 - : false; -}); + : false); -export const $isInvalidBackground = computed($userSelection, (selection) => { - return ( +export const $isInvalidBackground = computed($userSelection, (selection) => ( 'text' in selection && selection.text === SelectionMessageTypes.invalidBackground - ); -}); + )); export const $isUnprocessedBlendModes = computed( $userSelection, - (selection) => { - return ( + (selection) => ( 'text' in selection && selection.text === SelectionMessageTypes.unprocessedBlendModes - ); - } + ) ); export const $isEmptySelection = computed( diff --git a/src/utils/apca/calculate-apca-score.ts b/src/utils/apca/calculate-apca-score.ts index 4da79a7..03a7991 100644 --- a/src/utils/apca/calculate-apca-score.ts +++ b/src/utils/apca/calculate-apca-score.ts @@ -13,7 +13,7 @@ export const calculateApcaScore = ( const contrast = APCAcontrast(fgY, bgY); return Math.round(Number(contrast)); - } else { + } const fgDecimal = convertDecimalRGBto255Scale(fg); const bgDecimal = convertDecimalRGBto255Scale(bg); @@ -25,5 +25,5 @@ export const calculateApcaScore = ( ) ) ); - } + }; diff --git a/src/utils/colors/formatters.ts b/src/utils/colors/formatters.ts index 19a02e0..f9cec42 100644 --- a/src/utils/colors/formatters.ts +++ b/src/utils/colors/formatters.ts @@ -29,12 +29,10 @@ export const convert255ScaleRGBtoDecimal = (color: { return { alpha: (alpha ?? 255) / 255, b: b / 255, g: g / 255, r: r / 255 }; }; -export const formatForOklchDisplay = (oklch: Oklch): string => { - return `${toPercent(oklch.l)} ${clearValue(oklch.c)} ${clearValue( +export const formatForOklchDisplay = (oklch: Oklch): string => `${toPercent(oklch.l)} ${clearValue(oklch.c)} ${clearValue( oklch.h ?? 0, 1 )}`; -}; export const formatForRgbDisplay = (oklch: Oklch): string => { const { b, g, r } = convertToRgb(oklch); @@ -90,12 +88,10 @@ export const formatForRGBCSS = (color: Oklch, opacity?: number): string => { return `rgb(${r255} ${g255} ${b255}${postfix})`; }; -export const formatForHexCSS = (color: Oklch): string => { - return formatHex({ +export const formatForHexCSS = (color: Oklch): string => formatHex({ ...color, mode: 'oklch', }); -}; export const getFormatterForCSS = ( colorSpaceDisplayMode: ColorSpaceDisplayModes diff --git a/src/utils/figma/get-actual-fill.ts b/src/utils/figma/get-actual-fill.ts index fa8aaab..0068faa 100644 --- a/src/utils/figma/get-actual-fill.ts +++ b/src/utils/figma/get-actual-fill.ts @@ -3,11 +3,9 @@ import { notEmpty } from '~utils/not-empty.ts'; export const getActualFill = ( fills: FigmaPaint[] | readonly Paint[] -): Paint | undefined => { - return Array.from(fills) +): Paint | undefined => Array.from(fills) .reverse() .find( (fill) => fill.visible === true && notEmpty(fill.opacity) && fill.opacity > 0 ); -}; diff --git a/src/utils/figma/get-actual-node.ts b/src/utils/figma/get-actual-node.ts index 2c029e1..a427fcd 100644 --- a/src/utils/figma/get-actual-node.ts +++ b/src/utils/figma/get-actual-node.ts @@ -3,8 +3,7 @@ import { notEmpty } from '~utils/not-empty.ts'; export const getActualNode = ( nodes: PolychromNode[] -): PolychromNode | undefined => { - return nodes.find( +): PolychromNode | undefined => nodes.find( (node) => node.visible === true && notEmpty(node.opacity) && @@ -15,4 +14,3 @@ export const getActualNode = ( fill.visible === true && notEmpty(fill.opacity) && fill.opacity > 0 ) ); -}; diff --git a/src/utils/figma/sort-by-depth-and-order.ts b/src/utils/figma/sort-by-depth-and-order.ts index 68a51ba..80d992f 100644 --- a/src/utils/figma/sort-by-depth-and-order.ts +++ b/src/utils/figma/sort-by-depth-and-order.ts @@ -5,11 +5,9 @@ import { type PolychromNode } from '~types/common.ts'; // In the Figma world the selected node is always on top of the other nodes export const sortByDepthAndOrder = ( flatNodesList: PolychromNode[] -): PolychromNode[] => { - return flatNodesList.sort((a, b) => { +): PolychromNode[] => flatNodesList.sort((a, b) => { const levelDifference = b.nestingLevel - a.nestingLevel; const zIndexDifference = Math.abs(b.zIndex ?? 0) - Math.abs(a.zIndex ?? 0); return levelDifference !== 0 ? levelDifference : zIndexDifference; }); -}; From 216084d9e857f2780858bef4190dd0bab5bc6322 Mon Sep 17 00:00:00 2001 From: rittiev Date: Wed, 6 Aug 2025 17:53:37 +0100 Subject: [PATCH 07/15] removed packageManager from package.json --- .eslintrc.cjs | 3 --- package.json | 4 +--- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/.eslintrc.cjs b/.eslintrc.cjs index b0b376f..15a5d68 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -71,9 +71,6 @@ module.exports = { ['~test-utils', './src/test-utils'], ], }, - preact: { - version: 'detect', - }, 'boundaries/elements': [ { type: 'api', diff --git a/package.json b/package.json index 691521e..2997bbd 100644 --- a/package.json +++ b/package.json @@ -77,7 +77,5 @@ { "path": "dist/api.js" } - ], - "license": "MIT", - "packageManager": "pnpm@9.13.2+sha1.969cc200a41db98449afee1bfa7578b3ce6ff330" + ] } From 08f41cea38c0edb5cada619a38086fc295651f55 Mon Sep 17 00:00:00 2001 From: rittiev Date: Wed, 6 Aug 2025 18:02:43 +0100 Subject: [PATCH 08/15] fixed figma types --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 2997bbd..2bf35e2 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,6 @@ "lint:size": "size-limit" }, "dependencies": { - "@figma/plugin-typings": "^1.79.0", "@floating-ui/dom": "^1.7.3", "@floating-ui/react": "^0.25.2", "@nanostores/preact": "^1.0.0", @@ -50,6 +49,7 @@ "vitest": "^0.34.1" }, "devDependencies": { + "@figma/plugin-typings": "^1.116.0", "@preact/preset-vite": "^2.10.2", "@size-limit/preset-small-lib": "^11.2.0", "@types/node": "^20.4.1", From b5098a5d87eeb9c7786b59ddff17e05ecc065e37 Mon Sep 17 00:00:00 2001 From: rittiev Date: Wed, 6 Aug 2025 18:18:42 +0100 Subject: [PATCH 09/15] removed @preact/compat and fixed .yaml --- package.json | 4 +- pnpm-lock.yaml | 18 +----- src/ui/components/AppContent.tsx | 17 +++-- src/ui/components/BasicColorPreviewIcon.tsx | 30 ++++----- src/ui/components/ColorIndicator.tsx | 4 +- src/ui/components/ColorPreview.tsx | 4 +- src/ui/components/ContrastSample.tsx | 38 +++++------ src/ui/components/EmptySelectionMessage.tsx | 22 +++---- src/ui/components/HelpIcon.tsx | 18 +++--- src/ui/components/HelpLink.tsx | 26 ++++---- .../InvalidBackgroundSelectionMessage.tsx | 22 +++---- src/ui/components/LayeredColorPreviewIcon.tsx | 60 ++++++++--------- src/ui/components/LurkersIcon.tsx | 64 +++++++++---------- src/ui/components/LurkersLink.tsx | 26 ++++---- src/ui/components/PictureIcon.tsx | 22 +++---- src/ui/components/ProgressBar.tsx | 4 +- .../components/RewardingAnimationBodyText.tsx | 16 ++--- .../RewardingAnimationContentText.tsx | 12 ++-- .../RewardingAnimationFluentText.tsx | 18 +++--- .../SegmentedFontStyleDefinition.tsx | 4 +- src/ui/components/Selection.tsx | 6 +- src/ui/components/SelectionContent.tsx | 4 +- src/ui/components/SelectionsList.tsx | 42 ++++++------ src/ui/components/SettingsIcon.tsx | 22 +++---- src/ui/components/StopIcon.tsx | 24 +++---- src/ui/components/TextMetrics.tsx | 4 +- src/ui/components/ThemeVariablesProvider.tsx | 6 +- src/ui/components/Tooltip.tsx | 21 ++---- .../UnprocessedBlendModesSelectionMessage.tsx | 22 +++---- src/ui/components/WarningIcon.tsx | 22 +++---- 30 files changed, 291 insertions(+), 311 deletions(-) diff --git a/package.json b/package.json index 2bf35e2..448801b 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,6 @@ "@floating-ui/dom": "^1.7.3", "@floating-ui/react": "^0.25.2", "@nanostores/preact": "^1.0.0", - "@preact/compat": "^18.3.1", "@preact/signals": "^2.2.1", "@preact/signals-core": "^1.11.0", "@types/apca-w3": "^0.1.0", @@ -77,5 +76,6 @@ { "path": "dist/api.js" } - ] + ], + "packageManager": "pnpm@9.13.2+sha1.969cc200a41db98449afee1bfa7578b3ce6ff330" } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 34507b5..0a9f1fb 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8,9 +8,6 @@ importers: .: dependencies: - '@figma/plugin-typings': - specifier: ^1.79.0 - version: 1.116.0 '@floating-ui/dom': specifier: ^1.7.3 version: 1.7.3 @@ -20,9 +17,6 @@ importers: '@nanostores/preact': specifier: ^1.0.0 version: 1.0.0(nanostores@0.9.5)(preact@10.27.0) - '@preact/compat': - specifier: ^18.3.1 - version: 18.3.1(preact@10.27.0) '@preact/signals': specifier: ^2.2.1 version: 2.2.1(preact@10.27.0) @@ -99,6 +93,9 @@ importers: specifier: ^0.34.1 version: 0.34.6(jsdom@22.1.0)(lightningcss@1.30.1)(terser@5.43.1) devDependencies: + '@figma/plugin-typings': + specifier: ^1.116.0 + version: 1.116.0 '@preact/preset-vite': specifier: ^2.10.2 version: 2.10.2(@babel/core@7.28.0)(preact@10.27.0)(vite@4.5.14(@types/node@20.19.9)(lightningcss@1.30.1)(terser@5.43.1)) @@ -915,11 +912,6 @@ packages: resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} - '@preact/compat@18.3.1': - resolution: {integrity: sha512-Kog4PSRxtT4COtOXjsuQPV1vMXpUzREQfv+6Dmcy9/rMk0HOPK0HTE9fspFjAmY8R80T/T8gtgmZ68u5bOSngw==} - peerDependencies: - preact: '*' - '@preact/preset-vite@2.10.2': resolution: {integrity: sha512-K9wHlJOtkE+cGqlyQ5v9kL3Ge0Ql4LlIZjkUTL+1zf3nNdF88F9UZN6VTV8jdzBX9Fl7WSzeNMSDG7qECPmSmg==} peerDependencies: @@ -4412,10 +4404,6 @@ snapshots: '@pkgjs/parseargs@0.11.0': optional: true - '@preact/compat@18.3.1(preact@10.27.0)': - dependencies: - preact: 10.27.0 - '@preact/preset-vite@2.10.2(@babel/core@7.28.0)(preact@10.27.0)(vite@4.5.14(@types/node@20.19.9)(lightningcss@1.30.1)(terser@5.43.1))': dependencies: '@babel/core': 7.28.0 diff --git a/src/ui/components/AppContent.tsx b/src/ui/components/AppContent.tsx index 47afa3b..e8f2d0a 100644 --- a/src/ui/components/AppContent.tsx +++ b/src/ui/components/AppContent.tsx @@ -12,9 +12,9 @@ import { $isUnprocessedBlendModes, } from '~ui/stores/selected-nodes.ts'; import { isEmpty } from '~utils/not-empty.ts'; -import { type ReactElement } from 'preact/compat'; +import { type JSX } from 'preact'; -export const AppContent = (): ReactElement => { +export const AppContent = (): JSX.Element => { const isInvalidBackground = useStore($isInvalidBackground); const isEmptySelection = useStore($isEmptySelection); const isMultiSelection = useStore($isMultiSelection); @@ -39,13 +39,12 @@ export const AppContent = (): ReactElement => { if (isMultiSelection) { return ; - } - const pair = contrastConclusion[0]; + } + const pair = contrastConclusion[0]; - if (isEmpty(pair)) { - return ; - } + if (isEmpty(pair)) { + return ; + } - return ; - + return ; }; diff --git a/src/ui/components/BasicColorPreviewIcon.tsx b/src/ui/components/BasicColorPreviewIcon.tsx index 0418456..652ff41 100644 --- a/src/ui/components/BasicColorPreviewIcon.tsx +++ b/src/ui/components/BasicColorPreviewIcon.tsx @@ -1,4 +1,4 @@ -import { type ReactElement } from 'preact/compat'; +import { type JSX } from 'preact'; interface Props { borderColor: string; @@ -8,17 +8,17 @@ interface Props { export const BasicColorPreviewIcon = ({ borderColor, indicatorColor, -}: Props): ReactElement => ( - - - - - ); +}: Props): JSX.Element => ( + + + + +); diff --git a/src/ui/components/ColorIndicator.tsx b/src/ui/components/ColorIndicator.tsx index 7ed773f..4eb69fd 100644 --- a/src/ui/components/ColorIndicator.tsx +++ b/src/ui/components/ColorIndicator.tsx @@ -7,7 +7,7 @@ import { getFormatterForDisplaying, } from '~utils/colors/formatters.ts'; import { type Oklch } from 'culori/fn'; -import { type ReactElement } from 'preact/compat'; +import { type JSX } from 'preact'; import useClipboard from 'react-use-clipboard'; import { $colorSpaceDisplayMode } from '../stores/color-space-display-mode.ts'; @@ -26,7 +26,7 @@ export const ColorIndicator = ({ indicatorColor, isBlended, textColor, -}: ColorIndicatorProps): ReactElement => { +}: ColorIndicatorProps): JSX.Element => { const colorSpaceDisplayMode = useStore($colorSpaceDisplayMode); const formatColorForDisplay = getFormatterForDisplaying( diff --git a/src/ui/components/ColorPreview.tsx b/src/ui/components/ColorPreview.tsx index a8fd040..1f022eb 100644 --- a/src/ui/components/ColorPreview.tsx +++ b/src/ui/components/ColorPreview.tsx @@ -1,6 +1,6 @@ import { BasicColorPreviewIcon } from '~ui/components/BasicColorPreviewIcon.tsx'; import { LayeredColorPreviewIcon } from '~ui/components/LayeredColorPreviewIcon.tsx'; -import { type ReactElement } from 'preact/compat'; +import { type JSX } from 'preact'; interface Props { borderColor: string; @@ -12,7 +12,7 @@ export const ColorPreview = ({ borderColor, indicatorColor, isBlended, -}: Props): ReactElement => { +}: Props): JSX.Element => { if (isBlended) { return (
diff --git a/src/ui/components/ContrastSample.tsx b/src/ui/components/ContrastSample.tsx index 584b39b..23fea07 100644 --- a/src/ui/components/ContrastSample.tsx +++ b/src/ui/components/ContrastSample.tsx @@ -1,6 +1,6 @@ import { ThemeVariablesKeys } from '~ui/components/ThemeVariablesProvider.tsx'; import clsx from 'clsx'; -import { type ReactElement } from 'preact/compat'; +import { type JSX } from 'preact'; interface Props { bgColor: string; @@ -16,24 +16,24 @@ export const ContrastSample = ({ color, opacity, size, -}: Props): ReactElement => ( -

( +

+ - - {exampleText} - -

- ); + {exampleText} + +

+); diff --git a/src/ui/components/EmptySelectionMessage.tsx b/src/ui/components/EmptySelectionMessage.tsx index d9361f3..1db5be4 100644 --- a/src/ui/components/EmptySelectionMessage.tsx +++ b/src/ui/components/EmptySelectionMessage.tsx @@ -1,13 +1,13 @@ import ufoImage from '~ui/assets/ufo@2x.webp'; -import { type ReactElement } from 'preact/compat'; +import { type JSX } from 'preact'; -export const EmptySelectionMessage = (): ReactElement => ( -

- Select a layer with a solid fill -

- ); +export const EmptySelectionMessage = (): JSX.Element => ( +

+ Select a layer with a solid fill +

+); diff --git a/src/ui/components/HelpIcon.tsx b/src/ui/components/HelpIcon.tsx index 1a4ad15..89410d3 100644 --- a/src/ui/components/HelpIcon.tsx +++ b/src/ui/components/HelpIcon.tsx @@ -1,10 +1,10 @@ -import { type ReactElement } from 'preact/compat'; +import { type JSX } from 'preact'; -export const HelpIcon = (): ReactElement => ( - - - - ); +export const HelpIcon = (): JSX.Element => ( + + + +); diff --git a/src/ui/components/HelpLink.tsx b/src/ui/components/HelpLink.tsx index e41e8a7..5b2fb65 100644 --- a/src/ui/components/HelpLink.tsx +++ b/src/ui/components/HelpLink.tsx @@ -1,18 +1,18 @@ import { HelpIcon } from '~ui/components/HelpIcon.tsx'; import { Tooltip } from '~ui/components/Tooltip.tsx'; -import { type ReactElement } from 'preact/compat'; +import { type JSX } from 'preact'; import { APCADocumentationURL } from '../../constants.ts'; -export const HelpLink = (): ReactElement => ( - - - - - - ); +export const HelpLink = (): JSX.Element => ( + + + + + +); diff --git a/src/ui/components/InvalidBackgroundSelectionMessage.tsx b/src/ui/components/InvalidBackgroundSelectionMessage.tsx index 8d1ebb6..a066062 100644 --- a/src/ui/components/InvalidBackgroundSelectionMessage.tsx +++ b/src/ui/components/InvalidBackgroundSelectionMessage.tsx @@ -1,13 +1,13 @@ import layersImage from '~ui/assets/layers@2x.webp'; -import { type ReactElement } from 'preact/compat'; +import { type JSX } from 'preact'; -export const InvalidBackgroundSelectionMessage = (): ReactElement => ( -

- The background layer should be a solid fill -

- ); +export const InvalidBackgroundSelectionMessage = (): JSX.Element => ( +

+ The background layer should be a solid fill +

+); diff --git a/src/ui/components/LayeredColorPreviewIcon.tsx b/src/ui/components/LayeredColorPreviewIcon.tsx index 96ffaf2..fde948b 100644 --- a/src/ui/components/LayeredColorPreviewIcon.tsx +++ b/src/ui/components/LayeredColorPreviewIcon.tsx @@ -1,4 +1,4 @@ -import { type ReactElement } from 'preact/compat'; +import { type JSX } from 'preact'; interface Props { borderColor: string; @@ -8,32 +8,32 @@ interface Props { export const LayeredColorPreviewIcon = ({ borderColor, indicatorColor, -}: Props): ReactElement => ( -
- - - - - - -
- ); +}: Props): JSX.Element => ( +
+ + + + + + +
+); diff --git a/src/ui/components/LurkersIcon.tsx b/src/ui/components/LurkersIcon.tsx index 09faa9e..c2ac875 100644 --- a/src/ui/components/LurkersIcon.tsx +++ b/src/ui/components/LurkersIcon.tsx @@ -1,33 +1,33 @@ -import { type ReactElement } from 'preact/compat'; +import { type JSX } from 'preact'; -export const LurkersIcon = (): ReactElement => ( -
- - - - - - -
- ); +export const LurkersIcon = (): JSX.Element => ( +
+ + + + + + +
+); diff --git a/src/ui/components/LurkersLink.tsx b/src/ui/components/LurkersLink.tsx index 8e1f272..55c1372 100644 --- a/src/ui/components/LurkersLink.tsx +++ b/src/ui/components/LurkersLink.tsx @@ -1,18 +1,18 @@ import { LurkersIcon } from '~ui/components/LurkersIcon.tsx'; import { Tooltip } from '~ui/components/Tooltip.tsx'; -import { type ReactElement } from 'preact/compat'; +import { type JSX } from 'preact'; import { evilMartiansSiteURL } from '../../constants.ts'; -export const LurkersLink = (): ReactElement => ( - - - - - - ); +export const LurkersLink = (): JSX.Element => ( + + + + + +); diff --git a/src/ui/components/PictureIcon.tsx b/src/ui/components/PictureIcon.tsx index 10be6cc..7decf74 100644 --- a/src/ui/components/PictureIcon.tsx +++ b/src/ui/components/PictureIcon.tsx @@ -1,13 +1,13 @@ import { ThemeVariablesKeys } from '~ui/components/ThemeVariablesProvider.tsx'; -import { type ReactElement } from 'preact/compat'; +import { type JSX } from 'preact'; -export const PictureIcon = (): ReactElement => ( - - - - ); +export const PictureIcon = (): JSX.Element => ( + + + +); diff --git a/src/ui/components/ProgressBar.tsx b/src/ui/components/ProgressBar.tsx index ddb2198..f89f35b 100644 --- a/src/ui/components/ProgressBar.tsx +++ b/src/ui/components/ProgressBar.tsx @@ -7,7 +7,7 @@ import { conclusions } from '~ui/services/apca/conclusion.ts'; import { $rewardAnimationLaunch } from '~ui/stores/selected-nodes.ts'; import { isEmpty } from '~utils/not-empty.ts'; import clsx from 'clsx'; -import { type ReactElement } from 'preact/compat'; +import { type JSX } from 'preact'; interface Props { apca: number; @@ -19,7 +19,7 @@ const APCA_NEGATIVE_MAX_SCALE = 108; const APCA_POSITIVE_MAX_SCALE = 106; const SERIF_OFFSET = 2; -export const ProgressBar = ({ apca, height }: Props): ReactElement => { +export const ProgressBar = ({ apca, height }: Props): JSX.Element => { const rewardAnimationLaunch = useStore($rewardAnimationLaunch); const maxScale = apca > 0 ? APCA_POSITIVE_MAX_SCALE : APCA_NEGATIVE_MAX_SCALE; const barWidth = maxScale * SCALE; diff --git a/src/ui/components/RewardingAnimationBodyText.tsx b/src/ui/components/RewardingAnimationBodyText.tsx index 284ba3d..07c77fe 100644 --- a/src/ui/components/RewardingAnimationBodyText.tsx +++ b/src/ui/components/RewardingAnimationBodyText.tsx @@ -1,9 +1,9 @@ -import { type ReactElement } from 'preact/compat'; +import { type JSX } from 'preact'; -export const RewardingAnimationBodyText = (): ReactElement => ( -
-
-
-
-
- ); +export const RewardingAnimationBodyText = (): JSX.Element => ( +
+
+
+
+
+); diff --git a/src/ui/components/RewardingAnimationContentText.tsx b/src/ui/components/RewardingAnimationContentText.tsx index 3df6c36..2336355 100644 --- a/src/ui/components/RewardingAnimationContentText.tsx +++ b/src/ui/components/RewardingAnimationContentText.tsx @@ -1,7 +1,7 @@ -import { type ReactElement } from 'preact/compat'; +import { type JSX } from 'preact'; -export const RewardingAnimationContentText = (): ReactElement => ( -
-
-
- ); +export const RewardingAnimationContentText = (): JSX.Element => ( +
+
+
+); diff --git a/src/ui/components/RewardingAnimationFluentText.tsx b/src/ui/components/RewardingAnimationFluentText.tsx index 038037f..5fef39b 100644 --- a/src/ui/components/RewardingAnimationFluentText.tsx +++ b/src/ui/components/RewardingAnimationFluentText.tsx @@ -1,10 +1,10 @@ -import { type ReactElement } from 'preact/compat'; +import { type JSX } from 'preact'; -export const RewardingAnimationFluentText = (): ReactElement => ( -
-
-
-
-
-
- ); +export const RewardingAnimationFluentText = (): JSX.Element => ( +
+
+
+
+
+
+); diff --git a/src/ui/components/SegmentedFontStyleDefinition.tsx b/src/ui/components/SegmentedFontStyleDefinition.tsx index 0345de7..8ab4fb7 100644 --- a/src/ui/components/SegmentedFontStyleDefinition.tsx +++ b/src/ui/components/SegmentedFontStyleDefinition.tsx @@ -1,6 +1,6 @@ import { type UIColor } from '~types/common.ts'; import { formatColorForTheme } from '~ui/components/ThemeVariablesProvider.tsx'; -import { type ReactElement } from 'preact/compat'; +import { type JSX } from 'preact'; interface Props { currentStyleNumber: number; @@ -14,7 +14,7 @@ export const SegmentedFontStyleDefinition = ({ id, primaryColor, secondaryColor, -}: Props): ReactElement => { +}: Props): JSX.Element => { const formattedCurrentStyleNumber = currentStyleNumber.toLocaleString( 'en-US', { diff --git a/src/ui/components/Selection.tsx b/src/ui/components/Selection.tsx index c54d14a..443402d 100644 --- a/src/ui/components/Selection.tsx +++ b/src/ui/components/Selection.tsx @@ -6,13 +6,13 @@ import { import { type ContrastConclusion } from '~ui/types'; import { isEmpty } from '~utils/not-empty.ts'; import clsx from 'clsx'; -import { type ReactElement } from 'preact/compat'; +import { type JSX } from 'preact'; import { generateUIColors } from '../services/theme/generate-ui-colors.ts'; import { SegmentedFontStyleDefinition } from './SegmentedFontStyleDefinition.tsx'; import { SelectionContent } from './SelectionContent.tsx'; -const CantCalculateMessage = (): ReactElement => ( +const CantCalculateMessage = (): JSX.Element => (

Can't calc

@@ -35,7 +35,7 @@ export const Selection = ({ isLast, size, userSelection: { apca, bg, fg }, -}: Props): ReactElement => { +}: Props): JSX.Element => { const currentStyleNumber = signal(SEGMENTED_FONT_STYLES.INITIAL); const handleCurrentStyleNumberChange = (): void => { diff --git a/src/ui/components/SelectionContent.tsx b/src/ui/components/SelectionContent.tsx index 4779333..a69d5dd 100644 --- a/src/ui/components/SelectionContent.tsx +++ b/src/ui/components/SelectionContent.tsx @@ -5,7 +5,7 @@ import { import { getConclusionByScore } from '~ui/services/apca/conclusion.ts'; import { type ContrastConclusion } from '~ui/types'; import clsx from 'clsx'; -import { type ReactElement } from 'preact/compat'; +import { type JSX } from 'preact'; import { ColorIndicator } from './ColorIndicator.tsx'; import { ContrastSample } from './ContrastSample.tsx'; @@ -26,7 +26,7 @@ export const SelectionContent = ({ isLast, onApcaDoubleClick, size, -}: Props): ReactElement => { +}: Props): JSX.Element => { const bgColor = formatColorForTheme(bg); const fgColor = formatColorForTheme(fg); diff --git a/src/ui/components/SelectionsList.tsx b/src/ui/components/SelectionsList.tsx index 6b0612e..e34183e 100644 --- a/src/ui/components/SelectionsList.tsx +++ b/src/ui/components/SelectionsList.tsx @@ -1,29 +1,29 @@ import { Selection } from '~ui/components/Selection.tsx'; import { type ContrastConclusionList } from '~ui/services/blend/blend-colors.ts'; import clsx from 'clsx'; -import { type ReactElement } from 'preact/compat'; +import { type JSX } from 'preact'; interface Props { contrastConclusion: ContrastConclusionList; } -export const SelectionsList = ({ contrastConclusion }: Props): ReactElement => ( -
    - {contrastConclusion?.map((pair, index) => ( -
  • - -
  • - ))} -
- ); +export const SelectionsList = ({ contrastConclusion }: Props): JSX.Element => ( +
    + {contrastConclusion?.map((pair, index) => ( +
  • + +
  • + ))} +
+); diff --git a/src/ui/components/SettingsIcon.tsx b/src/ui/components/SettingsIcon.tsx index 0e2769e..bf916f2 100644 --- a/src/ui/components/SettingsIcon.tsx +++ b/src/ui/components/SettingsIcon.tsx @@ -1,12 +1,12 @@ -import { type ReactElement } from 'preact/compat'; +import { type JSX } from 'preact'; -export const SettingsIcon = (): ReactElement => ( - - - - ); +export const SettingsIcon = (): JSX.Element => ( + + + +); diff --git a/src/ui/components/StopIcon.tsx b/src/ui/components/StopIcon.tsx index f13fdd9..bbdc1b6 100644 --- a/src/ui/components/StopIcon.tsx +++ b/src/ui/components/StopIcon.tsx @@ -1,14 +1,14 @@ import { ThemeVariablesKeys } from '~ui/components/ThemeVariablesProvider.tsx'; -import { type ReactElement } from 'preact/compat'; +import { type JSX } from 'preact'; -export const StopIcon = (): ReactElement => ( - - - - - ); +export const StopIcon = (): JSX.Element => ( + + + + +); diff --git a/src/ui/components/TextMetrics.tsx b/src/ui/components/TextMetrics.tsx index 4d41cb2..41799af 100644 --- a/src/ui/components/TextMetrics.tsx +++ b/src/ui/components/TextMetrics.tsx @@ -1,7 +1,7 @@ import { ThemeVariablesKeys } from '~ui/components/ThemeVariablesProvider.tsx'; import { conclusions } from '~ui/services/apca/conclusion.ts'; import { fontLookupAPCA } from 'apca-w3'; -import { type ReactElement } from 'preact/compat'; +import { type JSX } from 'preact'; import { PictureIcon } from './PictureIcon.tsx'; import { StopIcon } from './StopIcon.tsx'; @@ -11,7 +11,7 @@ interface Props { apca: number; } -export const TextMetrics = ({ apca }: Props): ReactElement => { +export const TextMetrics = ({ apca }: Props): JSX.Element => { const [, , , , regular, , , bold] = fontLookupAPCA(apca); if (Math.abs(apca) < conclusions['Not Readable']) { diff --git a/src/ui/components/ThemeVariablesProvider.tsx b/src/ui/components/ThemeVariablesProvider.tsx index b066ef6..7a1fc69 100644 --- a/src/ui/components/ThemeVariablesProvider.tsx +++ b/src/ui/components/ThemeVariablesProvider.tsx @@ -4,10 +4,10 @@ import { type Theme } from '~ui/services/theme/generate-ui-colors.ts'; import { formatForOklchCSS } from '~utils/colors/formatters.ts'; import { isEmpty, notEmpty } from '~utils/not-empty.ts'; import { formatHex8 } from 'culori/fn'; -import { type ReactElement } from 'preact/compat'; +import { type JSX } from 'preact'; interface Props { - children: ReactElement; + children: JSX.Element; theme: Theme; } @@ -45,7 +45,7 @@ export const formatColorForTheme = ( export const ThemeVariablesProvider = ({ children, theme, -}: Props): ReactElement => { +}: Props): JSX.Element => { const styles = { [ThemeVariablesKeys.bg]: formatColorForTheme(theme.bg), [ThemeVariablesKeys.bgBorder]: formatColorForTheme(theme.bgBorder), diff --git a/src/ui/components/Tooltip.tsx b/src/ui/components/Tooltip.tsx index 28730f4..53cea1e 100644 --- a/src/ui/components/Tooltip.tsx +++ b/src/ui/components/Tooltip.tsx @@ -1,14 +1,7 @@ -import type { VNode } from 'preact'; - import { type Placement } from '@floating-ui/dom'; import { useFloatingTooltip } from '~hooks/useFloatingTooltip.ts'; -import { - cloneElement, - isValidElement, - useEffect, - useRef, - useState, -} from 'preact/compat'; +import { cloneElement, createRef, isValidElement, type VNode } from 'preact'; +import { useEffect, useState } from 'preact/hooks'; interface TooltipProps { children: VNode; @@ -21,11 +14,11 @@ export const Tooltip = ({ content, placement = 'top', }: TooltipProps): VNode => { - const triggerRef = useRef(null); - const tooltipRef = useRef(null); + const triggerRef = createRef(); + const tooltipRef = createRef(); - const openTimeout = useRef(null); - const closeTimeout = useRef(null); + const openTimeout = createRef(); + const closeTimeout = createRef(); const [visible, setVisible] = useState(false); useEffect(() => { @@ -40,7 +33,7 @@ export const Tooltip = ({ }; void initTooltip().catch(); - }, [visible]); + }); const onMouseEnter = (): void => { if (closeTimeout.current != null) clearTimeout(closeTimeout.current); diff --git a/src/ui/components/UnprocessedBlendModesSelectionMessage.tsx b/src/ui/components/UnprocessedBlendModesSelectionMessage.tsx index 6ca7d28..4173d63 100644 --- a/src/ui/components/UnprocessedBlendModesSelectionMessage.tsx +++ b/src/ui/components/UnprocessedBlendModesSelectionMessage.tsx @@ -1,13 +1,13 @@ import layersImage from '~ui/assets/layers@2x.webp'; -import { type ReactElement } from 'preact/compat'; +import { type JSX } from 'preact'; -export const UnprocessedBlendModesSelectionMessage = (): ReactElement => ( -

- The blending mode Plus Darker is not supported -

- ); +export const UnprocessedBlendModesSelectionMessage = (): JSX.Element => ( +

+ The blending mode Plus Darker is not supported +

+); diff --git a/src/ui/components/WarningIcon.tsx b/src/ui/components/WarningIcon.tsx index a7570c5..69697aa 100644 --- a/src/ui/components/WarningIcon.tsx +++ b/src/ui/components/WarningIcon.tsx @@ -1,13 +1,13 @@ import { ThemeVariablesKeys } from '~ui/components/ThemeVariablesProvider.tsx'; -import { type ReactElement } from 'preact/compat'; +import { type JSX } from 'preact'; -export const WarningIcon = (): ReactElement => ( - - - - ); +export const WarningIcon = (): JSX.Element => ( + + + +); From b2b05d998f42673fab22201d3fb7a7c3e03eba7f Mon Sep 17 00:00:00 2001 From: rittiev Date: Thu, 7 Aug 2025 09:53:35 +0100 Subject: [PATCH 10/15] removed @preact/signals-core --- package.json | 1 - src/ui/components/Selection.tsx | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/package.json b/package.json index 448801b..d42d87f 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,6 @@ "@floating-ui/react": "^0.25.2", "@nanostores/preact": "^1.0.0", "@preact/signals": "^2.2.1", - "@preact/signals-core": "^1.11.0", "@types/apca-w3": "^0.1.0", "@types/culori": "^2.0.0", "@vitest/coverage-v8": "^0.34.1", diff --git a/src/ui/components/Selection.tsx b/src/ui/components/Selection.tsx index 443402d..6cbbf1f 100644 --- a/src/ui/components/Selection.tsx +++ b/src/ui/components/Selection.tsx @@ -1,4 +1,4 @@ -import { signal } from '@preact/signals-core'; +import { signal } from '@preact/signals'; import { ThemeVariablesKeys, ThemeVariablesProvider, From 7c12493cc17aa21d5221f844e13bc24b0d8a5fbf Mon Sep 17 00:00:00 2001 From: rittiev Date: Thu, 7 Aug 2025 10:10:06 +0100 Subject: [PATCH 11/15] fixed Tooltip.tsx --- src/hooks/useFloatingTooltip.ts | 31 ------ src/ui/components/Tooltip.tsx | 175 ++++++++++++++++++++++---------- 2 files changed, 122 insertions(+), 84 deletions(-) delete mode 100644 src/hooks/useFloatingTooltip.ts diff --git a/src/hooks/useFloatingTooltip.ts b/src/hooks/useFloatingTooltip.ts deleted file mode 100644 index 0fc8f36..0000000 --- a/src/hooks/useFloatingTooltip.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { - computePosition, - flip, - offset, - type Placement, - shift, -} from '@floating-ui/dom'; - -export const useFloatingTooltip = async ( - trigger: HTMLElement, - tooltip: HTMLElement, - placement: Placement = 'top' -): Promise => { - const { x, y } = await computePosition(trigger, tooltip, { - middleware: [ - offset(5), - flip({ - crossAxis: placement.includes('-'), - fallbackAxisSideDirection: 'start', - padding: 5, - }), - shift({ padding: 5 }), - ], - placement, - }); - - Object.assign(tooltip.style, { - left: `${x}px`, - top: `${y}px`, - }); -}; diff --git a/src/ui/components/Tooltip.tsx b/src/ui/components/Tooltip.tsx index 53cea1e..7f2c9e3 100644 --- a/src/ui/components/Tooltip.tsx +++ b/src/ui/components/Tooltip.tsx @@ -1,75 +1,144 @@ -import { type Placement } from '@floating-ui/dom'; -import { useFloatingTooltip } from '~hooks/useFloatingTooltip.ts'; -import { cloneElement, createRef, isValidElement, type VNode } from 'preact'; -import { useEffect, useState } from 'preact/hooks'; +import { + autoUpdate, + computePosition, + flip, + offset, + type Placement, + shift, +} from '@floating-ui/dom'; +import { + Component, + type ComponentChildren, + Fragment, + type VNode, +} from 'preact'; +import { useEffect, useRef, useState } from 'preact/hooks'; interface TooltipProps { - children: VNode; - content: string | VNode; + children: ComponentChildren; + className?: string; + content: ComponentChildren; + delay?: number; placement?: Placement; + style?: 'dark' | 'light'; + trigger?: 'click' | 'hover' | 'none'; +} + +type PreactComponent = { base: HTMLElement } & Component; + +class RefWrapper extends Component<{ children: ComponentChildren; ref: any }> { + render(): ComponentChildren { + return this.props.children; + } } export const Tooltip = ({ children, + className = '', content, + delay = 150, placement = 'top', + trigger = 'hover', }: TooltipProps): VNode => { - const triggerRef = createRef(); - const tooltipRef = createRef(); - - const openTimeout = createRef(); - const closeTimeout = createRef(); + const reference = useRef(null); + const floating = useRef(null); const [visible, setVisible] = useState(false); + const st = useRef(null); + const refCurrent = reference.current; + const floatingCurrent = floating.current; + /* ── position ─────────────────────────────────────────────────────── */ useEffect(() => { - const initTooltip = async (): Promise => { - if (visible && triggerRef.current != null && tooltipRef.current != null) { - await useFloatingTooltip( - triggerRef.current, - tooltipRef.current, - placement - ); - } - }; + if ( + refCurrent === null || + floatingCurrent === null || + refCurrent.base === null + ) + return; + + return autoUpdate(refCurrent.base, floatingCurrent, () => { + void computePosition(refCurrent.base, floatingCurrent, { + middleware: [ + offset(5), + flip({ + crossAxis: placement.includes('-'), + fallbackAxisSideDirection: 'start', + padding: 5, + }), + shift({ padding: 5 }), + ], + placement, + }).then(({ x, y }) => { + Object.assign(floatingCurrent.style, { + left: `${x}px`, + top: `${y}px`, + }); + }); + }); + }, [placement, visible]); + + /* ── trigger wiring ───────────────────────────────────────────────── */ + useEffect(() => { + const refEl = reference.current?.base; + const floatEl = floating.current; + if (refEl == null || floatEl == null) return; - void initTooltip().catch(); - }); + /* helpers */ + const clear = (): void => { + if (st.current != null) clearTimeout(st.current); + }; + const show = (): void => { + clear(); + st.current = setTimeout(() => { + setVisible(true); + }, delay); + }; + const hide = (): void => { + clear(); + setVisible(false); + }; - const onMouseEnter = (): void => { - if (closeTimeout.current != null) clearTimeout(closeTimeout.current); - openTimeout.current = window.setTimeout(() => { - setVisible(true); - }, 150); - }; + /* attach based on *current* trigger prop */ + if (trigger === 'hover') { + refEl.addEventListener('mouseenter', show); + refEl.addEventListener('mouseleave', hide); + floatEl.addEventListener('mouseenter', show); + floatEl.addEventListener('mouseleave', hide); + } + /* "none" ⇒ nothing attached */ - const onMouseLeave = (): void => { - if (openTimeout.current != null) clearTimeout(openTimeout.current); - closeTimeout.current = window.setTimeout(() => { + if (trigger === 'none') { + /* cancel any pending timers */ + if (st.current != null) clearTimeout(st.current); + /* instantly hide bubble */ setVisible(false); - }, 0); - }; + } - const childWithRef = isValidElement(children) - ? cloneElement(children, { ref: triggerRef }) - : children; + /* detach when `trigger` changes or component unmounts */ + return () => { + clear(); + if (trigger === 'hover') { + refEl.removeEventListener('mouseenter', show); + refEl.removeEventListener('mouseleave', hide); + floatEl.removeEventListener('mouseenter', show); + floatEl.removeEventListener('mouseleave', hide); + } + }; + }, [trigger, delay]); + /* ── render ───────────────────────────────────────────────────────── */ return ( -
- {childWithRef} - - {visible && ( -
- {content} -
- )} -
+ +
+ {content} +
+ {children} +
); }; From 4cb77c21d2da2e19275495160fdf6c6c7eb2e2a3 Mon Sep 17 00:00:00 2001 From: rittiev Date: Thu, 7 Aug 2025 10:11:02 +0100 Subject: [PATCH 12/15] removed unnecessary paths --- .eslintrc.cjs | 5 ----- tsconfig.json | 1 - vite.config.ui.ts | 1 - 3 files changed, 7 deletions(-) diff --git a/.eslintrc.cjs b/.eslintrc.cjs index 15a5d68..f321cc3 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -65,7 +65,6 @@ module.exports = { alias: [ ['~api', './src/api'], ['~ui', './src/ui'], - ['~hooks', './src/hooks'], ['~utils', './src/utils'], ['~types', './src/types'], ['~test-utils', './src/test-utils'], @@ -92,10 +91,6 @@ module.exports = { type: 'test-utils', pattern: 'src/test-utils/*', }, - { - type: 'hooks', - pattern: 'src/hooks/*', - }, ], }, }; diff --git a/tsconfig.json b/tsconfig.json index 9e6924a..ae2bd44 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -30,7 +30,6 @@ "~types/*": ["src/types/*"], "~utils/*": ["src/utils/*"], "~ui/*": ["src/ui/*"], - "~hooks/*": ["src/hooks/*"] } }, "include": ["src"], diff --git a/vite.config.ui.ts b/vite.config.ui.ts index 3b5610d..1dd7e7b 100644 --- a/vite.config.ui.ts +++ b/vite.config.ui.ts @@ -11,7 +11,6 @@ export default defineConfig({ '~test-utils': resolve(__dirname, 'src', 'test-utils'), '~types': resolve(__dirname, 'src', 'types'), '~utils': resolve(__dirname, 'src', 'utils'), - '~hooks': resolve(__dirname, 'src', 'hooks'), }, }, plugins: [preact(), viteSingleFile()], From 90c435ea285abce345079c4994171152ce790e71 Mon Sep 17 00:00:00 2001 From: rittiev Date: Thu, 7 Aug 2025 10:49:02 +0100 Subject: [PATCH 13/15] removed react-use-clipboard --- package.json | 2 +- pnpm-lock.yaml | 21 +++------------- src/ui/components/ColorIndicator.tsx | 2 +- src/utils/use-clickboard.ts | 36 ++++++++++++++++++++++++++++ 4 files changed, 41 insertions(+), 20 deletions(-) create mode 100644 src/utils/use-clickboard.ts diff --git a/package.json b/package.json index d42d87f..0ccb855 100644 --- a/package.json +++ b/package.json @@ -30,6 +30,7 @@ "autoprefixer": "^10.4.14", "bigint-conversion": "^2.4.2", "clsx": "^2.0.0", + "copy-to-clipboard": "^3.3.3", "culori": "^3.2.0", "eslint-plugin-boundaries": "^3.4.0", "nanoid": "^4.0.2", @@ -67,7 +68,6 @@ "eslint-plugin-tailwindcss": "^3.13.0", "jsdom": "^22.1.0", "prettier": "^3.0.2", - "react-use-clipboard": "^1.0.9", "size-limit": "^11.2.0", "terser": "^5.19.0" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0a9f1fb..e0d9c22 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -20,9 +20,6 @@ importers: '@preact/signals': specifier: ^2.2.1 version: 2.2.1(preact@10.27.0) - '@preact/signals-core': - specifier: ^1.11.0 - version: 1.11.0 '@types/apca-w3': specifier: ^0.1.0 version: 0.1.3 @@ -47,6 +44,9 @@ importers: clsx: specifier: ^2.0.0 version: 2.1.1 + copy-to-clipboard: + specifier: ^3.3.3 + version: 3.3.3 culori: specifier: ^3.2.0 version: 3.3.0 @@ -153,9 +153,6 @@ importers: prettier: specifier: ^3.0.2 version: 3.6.2 - react-use-clipboard: - specifier: ^1.0.9 - version: 1.0.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1) size-limit: specifier: ^11.2.0 version: 11.2.0 @@ -3110,12 +3107,6 @@ packages: react-is@18.3.1: resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} - react-use-clipboard@1.0.9: - resolution: {integrity: sha512-OcMzc14usXhqQnAkvzmhCXAbW5WBT2LSgscVh2vKHXZfg72jFsSOsEearqdeC/nUj8YxEfLnziqe7AE7YkWFwA==} - peerDependencies: - react: ^16.8.0 || ^17 || ^18 - react-dom: ^16.8.0 || ^17 || ^18 - react@18.3.1: resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==} engines: {node: '>=0.10.0'} @@ -6974,12 +6965,6 @@ snapshots: react-is@18.3.1: {} - react-use-clipboard@1.0.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1): - dependencies: - copy-to-clipboard: 3.3.3 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - react@18.3.1: dependencies: loose-envify: 1.4.0 diff --git a/src/ui/components/ColorIndicator.tsx b/src/ui/components/ColorIndicator.tsx index 4eb69fd..c81d020 100644 --- a/src/ui/components/ColorIndicator.tsx +++ b/src/ui/components/ColorIndicator.tsx @@ -6,9 +6,9 @@ import { getFormatterForCSS, getFormatterForDisplaying, } from '~utils/colors/formatters.ts'; +import { useClipboard } from '~utils/use-clickboard.ts'; import { type Oklch } from 'culori/fn'; import { type JSX } from 'preact'; -import useClipboard from 'react-use-clipboard'; import { $colorSpaceDisplayMode } from '../stores/color-space-display-mode.ts'; diff --git a/src/utils/use-clickboard.ts b/src/utils/use-clickboard.ts new file mode 100644 index 0000000..eaadda5 --- /dev/null +++ b/src/utils/use-clickboard.ts @@ -0,0 +1,36 @@ +import { useSignal } from '@preact/signals'; +import copy from 'copy-to-clipboard'; +import { useEffect, useRef } from 'preact/hooks'; + +export const useClipboard = ( + value: string, + options?: { + successDuration?: number; + } +): [boolean, () => void] => { + const isCopied = useSignal(false); + const timeoutRef = useRef>(null); + const successDuration = options?.successDuration ?? 2000; + + const setCopied = (): void => { + const copied = copy(value); + isCopied.value = copied; + + if (copied) { + if (timeoutRef.current !== null) clearTimeout(timeoutRef.current); + + timeoutRef.current = setTimeout(() => { + isCopied.value = false; + }, successDuration); + } + }; + + useEffect( + () => () => { + if (timeoutRef.current !== null) clearTimeout(timeoutRef.current); + }, + [] + ); + + return [isCopied.value, setCopied]; +}; From 17e8ebe7ee4bf5ceefa819aa026c96e47b3f0677 Mon Sep 17 00:00:00 2001 From: rittiev Date: Thu, 7 Aug 2025 14:08:16 +0100 Subject: [PATCH 14/15] removed packageManager --- package.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/package.json b/package.json index 0ccb855..786a4a9 100644 --- a/package.json +++ b/package.json @@ -75,6 +75,5 @@ { "path": "dist/api.js" } - ], - "packageManager": "pnpm@9.13.2+sha1.969cc200a41db98449afee1bfa7578b3ce6ff330" + ] } From ea33da9c7d19e279f444cb9af4bc3e5c52032d5c Mon Sep 17 00:00:00 2001 From: rittiev Date: Thu, 7 Aug 2025 15:14:54 +0100 Subject: [PATCH 15/15] removed @floating-ui/react --- package.json | 1 - pnpm-lock.yaml | 65 -------------------------------------------------- 2 files changed, 66 deletions(-) diff --git a/package.json b/package.json index 786a4a9..5204da0 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,6 @@ }, "dependencies": { "@floating-ui/dom": "^1.7.3", - "@floating-ui/react": "^0.25.2", "@nanostores/preact": "^1.0.0", "@preact/signals": "^2.2.1", "@types/apca-w3": "^0.1.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e0d9c22..e34a57c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -11,9 +11,6 @@ importers: '@floating-ui/dom': specifier: ^1.7.3 version: 1.7.3 - '@floating-ui/react': - specifier: ^0.25.2 - version: 0.25.4(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@nanostores/preact': specifier: ^1.0.0 version: 1.0.0(nanostores@0.9.5)(preact@10.27.0) @@ -821,21 +818,6 @@ packages: '@floating-ui/dom@1.7.3': resolution: {integrity: sha512-uZA413QEpNuhtb3/iIKoYMSK07keHPYeXF02Zhd6e213j+d1NamLix/mCLxBUDW/Gx52sPH2m+chlUsyaBs/Ag==} - '@floating-ui/react-dom@2.1.4': - resolution: {integrity: sha512-JbbpPhp38UmXDDAu60RJmbeme37Jbgsm7NrHGgzYYFKmblzRUh6Pa641dII6LsjwF4XlScDrde2UAzDo/b9KPw==} - peerDependencies: - react: '>=16.8.0' - react-dom: '>=16.8.0' - - '@floating-ui/react@0.25.4': - resolution: {integrity: sha512-lWRQ/UiTvSIBxohn0/2HFHEmnmOVRjl7j6XcRJuLH0ls6f/9AyHMWVzkAJFuwx0n9gaEeCmg9VccCSCJzbEJig==} - peerDependencies: - react: '>=16.8.0' - react-dom: '>=16.8.0' - - '@floating-ui/utils@0.1.6': - resolution: {integrity: sha512-OfX7E2oUDYxtBvsuS4e/jSn4Q9Qb6DzgeYtsAdkPZ47znpoNsMgZw0+tVijiv3uGNR6dgNlty6r9rzIzHjtd/A==} - '@floating-ui/utils@0.2.10': resolution: {integrity: sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==} @@ -3096,21 +3078,12 @@ packages: randombytes@2.1.0: resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} - react-dom@18.3.1: - resolution: {integrity: sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==} - peerDependencies: - react: ^18.3.1 - react-is@16.13.1: resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} react-is@18.3.1: resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} - react@18.3.1: - resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==} - engines: {node: '>=0.10.0'} - read-cache@1.0.0: resolution: {integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==} @@ -3199,9 +3172,6 @@ packages: resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==} engines: {node: '>=v12.22.7'} - scheduler@0.23.2: - resolution: {integrity: sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==} - schema-utils@4.3.2: resolution: {integrity: sha512-Gn/JaSk/Mt9gYubxTtSn/QCV4em9mpAPiR1rqy/Ocu19u/G9J5WWdNoUT4SiV6mFC3y6cxyFcFwdzPM3FgxGAQ==} engines: {node: '>= 10.13.0'} @@ -3383,9 +3353,6 @@ packages: symbol-tree@3.2.4: resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} - tabbable@6.2.0: - resolution: {integrity: sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==} - tailwindcss@3.4.17: resolution: {integrity: sha512-w33E2aCvSDP0tW9RZuNXadXlkHXqFzSkQew/aIa2i/Sj8fThxwovwlXHSPXTbAHwEIhBFXAedUhP2tueAKP8Og==} engines: {node: '>=14.0.0'} @@ -4307,22 +4274,6 @@ snapshots: '@floating-ui/core': 1.7.3 '@floating-ui/utils': 0.2.10 - '@floating-ui/react-dom@2.1.4(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@floating-ui/dom': 1.7.3 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - - '@floating-ui/react@0.25.4(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@floating-ui/react-dom': 2.1.4(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@floating-ui/utils': 0.1.6 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - tabbable: 6.2.0 - - '@floating-ui/utils@0.1.6': {} - '@floating-ui/utils@0.2.10': {} '@humanwhocodes/config-array@0.13.0': @@ -6955,20 +6906,10 @@ snapshots: dependencies: safe-buffer: 5.2.1 - react-dom@18.3.1(react@18.3.1): - dependencies: - loose-envify: 1.4.0 - react: 18.3.1 - scheduler: 0.23.2 - react-is@16.13.1: {} react-is@18.3.1: {} - react@18.3.1: - dependencies: - loose-envify: 1.4.0 - read-cache@1.0.0: dependencies: pify: 2.3.0 @@ -7066,10 +7007,6 @@ snapshots: dependencies: xmlchars: 2.2.0 - scheduler@0.23.2: - dependencies: - loose-envify: 1.4.0 - schema-utils@4.3.2: dependencies: '@types/json-schema': 7.0.15 @@ -7294,8 +7231,6 @@ snapshots: symbol-tree@3.2.4: {} - tabbable@6.2.0: {} - tailwindcss@3.4.17: dependencies: '@alloc/quick-lru': 5.2.0