diff --git a/.changeset/brown-pigs-end.md b/.changeset/brown-pigs-end.md new file mode 100644 index 0000000..fcf2155 --- /dev/null +++ b/.changeset/brown-pigs-end.md @@ -0,0 +1,5 @@ +--- +"penpot-exporter": minor +--- + +Basic support for custom fonts diff --git a/.eslintrc.cjs b/.eslintrc.cjs index 9382192..8df62e2 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -1,6 +1,7 @@ module.exports = { root: true, parserOptions: { + project: './tsconfig.base.json', parser: '@typescript-eslint/parser', ecmaVersion: 'latest', sourceType: 'module' diff --git a/package-lock.json b/package-lock.json index 5a65c24..e4c0185 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,16 +1,17 @@ { "name": "penpot-exporter", - "version": "0.0.1", + "version": "0.2.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "penpot-exporter", - "version": "0.0.1", + "version": "0.2.2", "license": "MPL2.0", "dependencies": { - "react": "^18.2", - "react-dom": "^18.2", + "react": "^18.3", + "react-dom": "^18.3", + "react-hook-form": "^7.51", "slugify": "^1.6", "svg-path-parser": "^1.1" }, @@ -18,13 +19,13 @@ "@changesets/changelog-github": "^0.5", "@changesets/cli": "^2.27", "@figma/eslint-plugin-figma-plugins": "^0.15", - "@figma/plugin-typings": "^1.90", + "@figma/plugin-typings": "^1.92", "@trivago/prettier-plugin-sort-imports": "^4.3", - "@types/react": "^18.2", - "@types/react-dom": "^18.2", + "@types/react": "^18.3", + "@types/react-dom": "^18.3", "@types/svg-path-parser": "^1.1", - "@typescript-eslint/eslint-plugin": "^7.5", - "@typescript-eslint/parser": "^7.5", + "@typescript-eslint/eslint-plugin": "^7.8", + "@typescript-eslint/parser": "^7.8", "@vitejs/plugin-react-swc": "^3.6", "concurrently": "^8.2", "esbuild": "^0.20", @@ -33,9 +34,8 @@ "eslint-plugin-prettier": "^5.1", "eslint-plugin-react": "^7.34", "prettier": "^3.2", - "stylelint": "^16.3", + "stylelint": "^16.4", "stylelint-config-standard": "^36.0", - "tsconfig-paths-webpack-plugin": "^4.1", "typescript": "^5.4", "vite": "^5.2", "vite-plugin-singlefile": "^2.0", @@ -1098,262 +1098,6 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/@esbuild/aix-ppc64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.20.2.tgz", - "integrity": "sha512-D+EBOJHXdNZcLJRBkhENNG8Wji2kgc9AZ9KiPr1JuZjsNtyHzrsfLRrY0tk2H2aoFu6RANO1y1iPPUCDYWkb5g==", - "cpu": [ - "ppc64" - ], - "dev": true, - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-arm": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.20.2.tgz", - "integrity": "sha512-t98Ra6pw2VaDhqNWO2Oph2LXbz/EJcnLmKLGBJwEwXX/JAN83Fym1rU8l0JUWK6HkIbWONCSSatf4sf2NBRx/w==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-arm64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.20.2.tgz", - "integrity": "sha512-mRzjLacRtl/tWU0SvD8lUEwb61yP9cqQo6noDZP/O8VkwafSYwZ4yWy24kan8jE/IMERpYncRt2dw438LP3Xmg==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.20.2.tgz", - "integrity": "sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.20.2.tgz", - "integrity": "sha512-4J6IRT+10J3aJH3l1yzEg9y3wkTDgDk7TSDFX+wKFiWjqWp/iCfLIYzGyasx9l0SAFPT1HwSCR+0w/h1ES/MjA==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.20.2.tgz", - "integrity": "sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.20.2.tgz", - "integrity": "sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.20.2.tgz", - "integrity": "sha512-d+DipyvHRuqEeM5zDivKV1KuXn9WeRX6vqSqIDgwIfPQtwMP4jaDsQsDncjTDDsExT4lR/91OLjRo8bmC1e+Cw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-arm": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.20.2.tgz", - "integrity": "sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.20.2.tgz", - "integrity": "sha512-9pb6rBjGvTFNira2FLIWqDk/uaf42sSyLE8j1rnUpuzsODBq7FvpwHYZxQ/It/8b+QOS1RYfqgGFNLRI+qlq2A==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.20.2.tgz", - "integrity": "sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.20.2.tgz", - "integrity": "sha512-PR7sp6R/UC4CFVomVINKJ80pMFlfDfMQMYynX7t1tNTeivQ6XdX5r2XovMmha/VjR1YN/HgHWsVcTRIMkymrgQ==", - "cpu": [ - "loong64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.20.2.tgz", - "integrity": "sha512-4BlTqeutE/KnOiTG5Y6Sb/Hw6hsBOZapOVF6njAESHInhlQAghVVZL1ZpIctBOoTFbQyGW+LsVYZ8lSSB3wkjA==", - "cpu": [ - "mips64el" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.20.2.tgz", - "integrity": "sha512-rD3KsaDprDcfajSKdn25ooz5J5/fWBylaaXkuotBDGnMnDP1Uv5DLAN/45qfnf3JDYyJv/ytGHQaziHUdyzaAg==", - "cpu": [ - "ppc64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.20.2.tgz", - "integrity": "sha512-snwmBKacKmwTMmhLlz/3aH1Q9T8v45bKYGE3j26TsaOVtjIag4wLfWSiZykXzXuE1kbCE+zJRmwp+ZbIHinnVg==", - "cpu": [ - "riscv64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.20.2.tgz", - "integrity": "sha512-wcWISOobRWNm3cezm5HOZcYz1sKoHLd8VL1dl309DiixxVFoFe/o8HnwuIwn6sXre88Nwj+VwZUvJf4AFxkyrQ==", - "cpu": [ - "s390x" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, "node_modules/@esbuild/linux-x64": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.20.2.tgz", @@ -1370,102 +1114,6 @@ "node": ">=12" } }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.20.2.tgz", - "integrity": "sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.20.2.tgz", - "integrity": "sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.20.2.tgz", - "integrity": "sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.20.2.tgz", - "integrity": "sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.20.2.tgz", - "integrity": "sha512-HfLOfn9YWmkSKRQqovpnITazdtquEW8/SoHW7pWpuEeguaZI4QnCRW6b+oZTztdBnZOS2hqJ6im/D5cPzBTTlQ==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.20.2.tgz", - "integrity": "sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, "node_modules/@eslint-community/eslint-utils": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", @@ -1571,9 +1219,9 @@ } }, "node_modules/@figma/plugin-typings": { - "version": "1.90.0", - "resolved": "https://registry.npmjs.org/@figma/plugin-typings/-/plugin-typings-1.90.0.tgz", - "integrity": "sha512-RvZrSkuV0SABRaYuRFO/S30u9+RGKJm6+CPjSG7MaMo60p8S1sX5YOWT+zDWZC6mqNEaxLkrbXdiyqWXsfdHQg==", + "version": "1.92.0", + "resolved": "https://registry.npmjs.org/@figma/plugin-typings/-/plugin-typings-1.92.0.tgz", + "integrity": "sha512-W02/uSt+n33Iro0/Goj+Dl1Fp+1i9+jjciw//BcBh0VOz2QzuiaurhftnboO8gKucOloBOROMbxe/Vylu4ItZw==", "dev": true }, "node_modules/@humanwhocodes/config-array": { @@ -1866,136 +1514,6 @@ } } }, - "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.14.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.14.2.tgz", - "integrity": "sha512-ahxSgCkAEk+P/AVO0vYr7DxOD3CwAQrT0Go9BJyGQ9Ef0QxVOfjDZMiF4Y2s3mLyPrjonchIMH/tbWHucJMykQ==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@rollup/rollup-android-arm64": { - "version": "4.14.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.14.2.tgz", - "integrity": "sha512-lAarIdxZWbFSHFSDao9+I/F5jDaKyCqAPMq5HqnfpBw8dKDiCaaqM0lq5h1pQTLeIqueeay4PieGR5jGZMWprw==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.14.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.14.2.tgz", - "integrity": "sha512-SWsr8zEUk82KSqquIMgZEg2GE5mCSfr9sE/thDROkX6pb3QQWPp8Vw8zOq2GyxZ2t0XoSIUlvHDkrf5Gmf7x3Q==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.14.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.14.2.tgz", - "integrity": "sha512-o/HAIrQq0jIxJAhgtIvV5FWviYK4WB0WwV91SLUnsliw1lSAoLsmgEEgRWzDguAFeUEUUoIWXiJrPqU7vGiVkA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.14.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.14.2.tgz", - "integrity": "sha512-nwlJ65UY9eGq91cBi6VyDfArUJSKOYt5dJQBq8xyLhvS23qO+4Nr/RreibFHjP6t+5ap2ohZrUJcHv5zk5ju/g==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.14.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.14.2.tgz", - "integrity": "sha512-Pg5TxxO2IVlMj79+c/9G0LREC9SY3HM+pfAwX7zj5/cAuwrbfj2Wv9JbMHIdPCfQpYsI4g9mE+2Bw/3aeSs2rQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.14.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.14.2.tgz", - "integrity": "sha512-cAOTjGNm84gc6tS02D1EXtG7tDRsVSDTBVXOLbj31DkwfZwgTPYZ6aafSU7rD/4R2a34JOwlF9fQayuTSkoclA==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { - "version": "4.14.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.14.2.tgz", - "integrity": "sha512-4RyT6v1kXb7C0fn6zV33rvaX05P0zHoNzaXI/5oFHklfKm602j+N4mn2YvoezQViRLPnxP8M1NaY4s/5kXO5cw==", - "cpu": [ - "ppc64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.14.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.14.2.tgz", - "integrity": "sha512-KNUH6jC/vRGAKSorySTyc/yRYlCwN/5pnMjXylfBniwtJx5O7X17KG/0efj8XM3TZU7raYRXJFFReOzNmL1n1w==", - "cpu": [ - "riscv64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.14.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.14.2.tgz", - "integrity": "sha512-xPV4y73IBEXToNPa3h5lbgXOi/v0NcvKxU0xejiFw6DtIYQqOTMhZ2DN18/HrrP0PmiL3rGtRG9gz1QE8vFKXQ==", - "cpu": [ - "s390x" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, "node_modules/@rollup/rollup-linux-x64-gnu": { "version": "4.14.2", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.14.2.tgz", @@ -2022,45 +1540,6 @@ "linux" ] }, - "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.14.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.14.2.tgz", - "integrity": "sha512-H4s8UjgkPnlChl6JF5empNvFHp77Jx+Wfy2EtmYPe9G22XV+PMuCinZVHurNe8ggtwoaohxARJZbaH/3xjB/FA==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.14.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.14.2.tgz", - "integrity": "sha512-djqpAjm/i8erWYF0K6UY4kRO3X5+T4TypIqw60Q8MTqSBaQNpNXDhxdjpZ3ikgb+wn99svA7jxcXpiyg9MUsdw==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.14.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.14.2.tgz", - "integrity": "sha512-teAqzLT0yTYZa8ZP7zhFKEx4cotS8Tkk5XiqNMJhD4CpaWB1BHARE4Qy+RzwnXvSAYv+Q3jAqCVBS+PS+Yee8Q==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ] - }, "node_modules/@svgr/babel-plugin-add-jsx-attribute": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-8.0.0.tgz", @@ -2352,86 +1831,6 @@ } } }, - "node_modules/@swc/core-darwin-arm64": { - "version": "1.4.13", - "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.4.13.tgz", - "integrity": "sha512-36P72FLpm5iq85IvoEjBvi22DiqkkEIanJ1M0E8bkxcFHUbjBrYfPY9T6cpPyK5oQqkaTBvNAc3j1BlVD6IH6w==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=10" - } - }, - "node_modules/@swc/core-darwin-x64": { - "version": "1.4.13", - "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.4.13.tgz", - "integrity": "sha512-ye7OgKpDdyA8AMIVVdmD1ICDaFXgoEXORnVO8bBHyul0WN71yUBZMX+YxEx2lpWtiftA2vY/1MAuOR80vHkBCw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=10" - } - }, - "node_modules/@swc/core-linux-arm-gnueabihf": { - "version": "1.4.13", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.4.13.tgz", - "integrity": "sha512-+x593Jlmu4c3lJtZUKRejWpV2MAij1Js5nmQLLdjo6ChR2D4B2rzj3iMiKn5gITew7fraF9t3fvXALdWh7HmUg==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=10" - } - }, - "node_modules/@swc/core-linux-arm64-gnu": { - "version": "1.4.13", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.4.13.tgz", - "integrity": "sha512-0x8OVw4dfyNerrs/9eZX9wNnmvwbwXSMCi+LbE6Xt1pXOIwvoLtFIXcV3NsrlkFboO3sr5UAQIwDxKqbIZA9pQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=10" - } - }, - "node_modules/@swc/core-linux-arm64-musl": { - "version": "1.4.13", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.4.13.tgz", - "integrity": "sha512-Z9c4JiequtZvngPcxbCuAOkmWBxi2vInZbjjhD5I+Q9oiJdXUz1t2USGwsGPS41Xvk1BOA3ecK2Sn1ilY3titg==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=10" - } - }, "node_modules/@swc/core-linux-x64-gnu": { "version": "1.4.13", "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.4.13.tgz", @@ -2464,54 +1863,6 @@ "node": ">=10" } }, - "node_modules/@swc/core-win32-arm64-msvc": { - "version": "1.4.13", - "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.4.13.tgz", - "integrity": "sha512-LVZfhlD+jHcAbz5NN+gAJ1BEasB0WpcvUzcsJt0nQSRsojgzPzFjJ+fzEBnvT7SMtqKkrnVJ0OmDYeh88bDRpw==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=10" - } - }, - "node_modules/@swc/core-win32-ia32-msvc": { - "version": "1.4.13", - "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.4.13.tgz", - "integrity": "sha512-78hxHWUvUZtWsnhcf8DKwhBcNFJw+j4y4fN2B9ioXmBWX2tIyw+BqUHOrismOtjPihaZmwe/Ok2e4qmkawE2fw==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=10" - } - }, - "node_modules/@swc/core-win32-x64-msvc": { - "version": "1.4.13", - "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.4.13.tgz", - "integrity": "sha512-WSfy1u2Xde6jU7UpHIInCUMW98Zw9iZglddKUAvmr1obkZji5U6EX0Oca3asEJdZPFb+2lMLjt0Mh5a1YisROg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=10" - } - }, "node_modules/@swc/counter": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz", @@ -2592,9 +1943,9 @@ "dev": true }, "node_modules/@types/react": { - "version": "18.2.77", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.77.tgz", - "integrity": "sha512-CUT9KUUF+HytDM7WiXKLF9qUSg4tGImwy4FXTlfEDPEkkNUzJ7rVFolYweJ9fS1ljoIaP7M7Rdjc5eUm/Yu5AA==", + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.1.tgz", + "integrity": "sha512-V0kuGBX3+prX+DQ/7r2qsv1NsdfnCLnTgnRJ1pYnxykBhGMz+qj+box5lq7XsO5mtZsBqpjwwTu/7wszPfMBcw==", "dev": true, "dependencies": { "@types/prop-types": "*", @@ -2602,9 +1953,9 @@ } }, "node_modules/@types/react-dom": { - "version": "18.2.25", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.25.tgz", - "integrity": "sha512-o/V48vf4MQh7juIKZU2QGDfli6p1+OOi5oXx36Hffpc9adsHeXjVp8rHuPkjd8VT8sOJ2Zp05HR7CdpGTIUFUA==", + "version": "18.3.0", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.0.tgz", + "integrity": "sha512-EhwApuTmMBmXuFOikhQLIBUn6uFg81SwLMOAUgodJF14SOBOCMdU04gDoYi0WOJJHD144TL32z4yDqCW3dnkQg==", "dev": true, "dependencies": { "@types/react": "*" @@ -2623,16 +1974,16 @@ "dev": true }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.6.0.tgz", - "integrity": "sha512-gKmTNwZnblUdnTIJu3e9kmeRRzV2j1a/LUO27KNNAnIC5zjy1aSvXSRp4rVNlmAoHlQ7HzX42NbKpcSr4jF80A==", + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.8.0.tgz", + "integrity": "sha512-gFTT+ezJmkwutUPmB0skOj3GZJtlEGnlssems4AjkVweUPGj7jRwwqg0Hhg7++kPGJqKtTYx+R05Ftww372aIg==", "dev": true, "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "7.6.0", - "@typescript-eslint/type-utils": "7.6.0", - "@typescript-eslint/utils": "7.6.0", - "@typescript-eslint/visitor-keys": "7.6.0", + "@typescript-eslint/scope-manager": "7.8.0", + "@typescript-eslint/type-utils": "7.8.0", + "@typescript-eslint/utils": "7.8.0", + "@typescript-eslint/visitor-keys": "7.8.0", "debug": "^4.3.4", "graphemer": "^1.4.0", "ignore": "^5.3.1", @@ -2658,13 +2009,13 @@ } }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/typescript-estree": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.6.0.tgz", - "integrity": "sha512-+7Y/GP9VuYibecrCQWSKgl3GvUM5cILRttpWtnAu8GNL9j11e4tbuGZmZjJ8ejnKYyBRb2ddGQ3rEFCq3QjMJw==", + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.8.0.tgz", + "integrity": "sha512-5pfUCOwK5yjPaJQNy44prjCwtr981dO8Qo9J9PwYXZ0MosgAbfEMB008dJ5sNo3+/BN6ytBPuSvXUg9SAqB0dg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.6.0", - "@typescript-eslint/visitor-keys": "7.6.0", + "@typescript-eslint/types": "7.8.0", + "@typescript-eslint/visitor-keys": "7.8.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -2686,17 +2037,17 @@ } }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/utils": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.6.0.tgz", - "integrity": "sha512-x54gaSsRRI+Nwz59TXpCsr6harB98qjXYzsRxGqvA5Ue3kQH+FxS7FYU81g/omn22ML2pZJkisy6Q+ElK8pBCA==", + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.8.0.tgz", + "integrity": "sha512-L0yFqOCflVqXxiZyXrDr80lnahQfSOfc9ELAAZ75sqicqp2i36kEZZGuUymHNFoYOqxRT05up760b4iGsl02nQ==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@types/json-schema": "^7.0.15", "@types/semver": "^7.5.8", - "@typescript-eslint/scope-manager": "7.6.0", - "@typescript-eslint/types": "7.6.0", - "@typescript-eslint/typescript-estree": "7.6.0", + "@typescript-eslint/scope-manager": "7.8.0", + "@typescript-eslint/types": "7.8.0", + "@typescript-eslint/typescript-estree": "7.8.0", "semver": "^7.6.0" }, "engines": { @@ -2726,15 +2077,15 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.6.0.tgz", - "integrity": "sha512-usPMPHcwX3ZoPWnBnhhorc14NJw9J4HpSXQX4urF2TPKG0au0XhJoZyX62fmvdHONUkmyUe74Hzm1//XA+BoYg==", + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.8.0.tgz", + "integrity": "sha512-KgKQly1pv0l4ltcftP59uQZCi4HUYswCLbTqVZEJu7uLX8CTLyswqMLqLN+2QFz4jCptqWVV4SB7vdxcH2+0kQ==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "7.6.0", - "@typescript-eslint/types": "7.6.0", - "@typescript-eslint/typescript-estree": "7.6.0", - "@typescript-eslint/visitor-keys": "7.6.0", + "@typescript-eslint/scope-manager": "7.8.0", + "@typescript-eslint/types": "7.8.0", + "@typescript-eslint/typescript-estree": "7.8.0", + "@typescript-eslint/visitor-keys": "7.8.0", "debug": "^4.3.4" }, "engines": { @@ -2754,13 +2105,13 @@ } }, "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/typescript-estree": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.6.0.tgz", - "integrity": "sha512-+7Y/GP9VuYibecrCQWSKgl3GvUM5cILRttpWtnAu8GNL9j11e4tbuGZmZjJ8ejnKYyBRb2ddGQ3rEFCq3QjMJw==", + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.8.0.tgz", + "integrity": "sha512-5pfUCOwK5yjPaJQNy44prjCwtr981dO8Qo9J9PwYXZ0MosgAbfEMB008dJ5sNo3+/BN6ytBPuSvXUg9SAqB0dg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.6.0", - "@typescript-eslint/visitor-keys": "7.6.0", + "@typescript-eslint/types": "7.8.0", + "@typescript-eslint/visitor-keys": "7.8.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -2797,13 +2148,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.6.0.tgz", - "integrity": "sha512-ngttyfExA5PsHSx0rdFgnADMYQi+Zkeiv4/ZxGYUWd0nLs63Ha0ksmp8VMxAIC0wtCFxMos7Lt3PszJssG/E6w==", + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.8.0.tgz", + "integrity": "sha512-viEmZ1LmwsGcnr85gIq+FCYI7nO90DVbE37/ll51hjv9aG+YZMb4WDE2fyWpUR4O/UrhGRpYXK/XajcGTk2B8g==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.6.0", - "@typescript-eslint/visitor-keys": "7.6.0" + "@typescript-eslint/types": "7.8.0", + "@typescript-eslint/visitor-keys": "7.8.0" }, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -2814,13 +2165,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.6.0.tgz", - "integrity": "sha512-NxAfqAPNLG6LTmy7uZgpK8KcuiS2NZD/HlThPXQRGwz6u7MDBWRVliEEl1Gj6U7++kVJTpehkhZzCJLMK66Scw==", + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.8.0.tgz", + "integrity": "sha512-H70R3AefQDQpz9mGv13Uhi121FNMh+WEaRqcXTX09YEDky21km4dV1ZXJIp8QjXc4ZaVkXVdohvWDzbnbHDS+A==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "7.6.0", - "@typescript-eslint/utils": "7.6.0", + "@typescript-eslint/typescript-estree": "7.8.0", + "@typescript-eslint/utils": "7.8.0", "debug": "^4.3.4", "ts-api-utils": "^1.3.0" }, @@ -2841,13 +2192,13 @@ } }, "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/typescript-estree": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.6.0.tgz", - "integrity": "sha512-+7Y/GP9VuYibecrCQWSKgl3GvUM5cILRttpWtnAu8GNL9j11e4tbuGZmZjJ8ejnKYyBRb2ddGQ3rEFCq3QjMJw==", + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.8.0.tgz", + "integrity": "sha512-5pfUCOwK5yjPaJQNy44prjCwtr981dO8Qo9J9PwYXZ0MosgAbfEMB008dJ5sNo3+/BN6ytBPuSvXUg9SAqB0dg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.6.0", - "@typescript-eslint/visitor-keys": "7.6.0", + "@typescript-eslint/types": "7.8.0", + "@typescript-eslint/visitor-keys": "7.8.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -2869,17 +2220,17 @@ } }, "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/utils": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.6.0.tgz", - "integrity": "sha512-x54gaSsRRI+Nwz59TXpCsr6harB98qjXYzsRxGqvA5Ue3kQH+FxS7FYU81g/omn22ML2pZJkisy6Q+ElK8pBCA==", + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.8.0.tgz", + "integrity": "sha512-L0yFqOCflVqXxiZyXrDr80lnahQfSOfc9ELAAZ75sqicqp2i36kEZZGuUymHNFoYOqxRT05up760b4iGsl02nQ==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@types/json-schema": "^7.0.15", "@types/semver": "^7.5.8", - "@typescript-eslint/scope-manager": "7.6.0", - "@typescript-eslint/types": "7.6.0", - "@typescript-eslint/typescript-estree": "7.6.0", + "@typescript-eslint/scope-manager": "7.8.0", + "@typescript-eslint/types": "7.8.0", + "@typescript-eslint/typescript-estree": "7.8.0", "semver": "^7.6.0" }, "engines": { @@ -2909,9 +2260,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.6.0.tgz", - "integrity": "sha512-h02rYQn8J+MureCvHVVzhl69/GAfQGPQZmOMjG1KfCl7o3HtMSlPaPUAPu6lLctXI5ySRGIYk94clD/AUMCUgQ==", + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.8.0.tgz", + "integrity": "sha512-wf0peJ+ZGlcH+2ZS23aJbOv+ztjeeP8uQ9GgwMJGVLx/Nj9CJt17GWgWWoSmoRVKAX2X+7fzEnAjxdvK2gqCLw==", "dev": true, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -3052,12 +2403,12 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.6.0.tgz", - "integrity": "sha512-4eLB7t+LlNUmXzfOu1VAIAdkjbu5xNSerURS9X/S5TUKWFRpXRQZbmtPqgKmYx8bj3J0irtQXSiWAOY82v+cgw==", + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.8.0.tgz", + "integrity": "sha512-q4/gibTNBQNA0lGyYQCmWRS5D15n8rXh4QjK3KV+MBPlTYHpfBUT3D3PaPR/HeNiI9W6R7FvlkcGhNyAoP+caA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.6.0", + "@typescript-eslint/types": "7.8.0", "eslint-visitor-keys": "^3.4.3" }, "engines": { @@ -3750,9 +3101,9 @@ } }, "node_modules/css-functions-list": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/css-functions-list/-/css-functions-list-3.2.1.tgz", - "integrity": "sha512-Nj5YcaGgBtuUmn1D7oHqPW0c9iui7xsTsj5lIX8ZgevdfhmjFfKB3r8moHJtNJnctnYXJyYX5I1pp90HM4TPgQ==", + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/css-functions-list/-/css-functions-list-3.2.2.tgz", + "integrity": "sha512-c+N0v6wbKVxTu5gOBBFkr9BEdBWaqqjQeiJ8QvSRIJOf+UxlJh930m8e6/WNeODIK0mYLFkoONrnj16i2EcvfQ==", "dev": true, "engines": { "node": ">=12 || >=16" @@ -4062,19 +3413,6 @@ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true }, - "node_modules/enhanced-resolve": { - "version": "5.16.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.16.0.tgz", - "integrity": "sha512-O+QWCviPNSSLAD9Ucn8Awv+poAkqn3T1XY5/N7kR7rQO9yfSGWkYZDwpJ+iKF7B8rxaQKWngSqACpgzeapSyoA==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.2.4", - "tapable": "^2.2.0" - }, - "engines": { - "node": ">=10.13.0" - } - }, "node_modules/enquirer": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.4.1.tgz", @@ -4918,20 +4256,6 @@ "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", "dev": true }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, "node_modules/function-bind": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", @@ -6171,15 +5495,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/minimist-options": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/minimist-options/-/minimist-options-4.1.0.tgz", @@ -6886,9 +6201,9 @@ } }, "node_modules/react": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", - "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", + "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", "dependencies": { "loose-envify": "^1.1.0" }, @@ -6897,15 +6212,30 @@ } }, "node_modules/react-dom": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", - "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", "dependencies": { "loose-envify": "^1.1.0", - "scheduler": "^0.23.0" + "scheduler": "^0.23.2" }, "peerDependencies": { - "react": "^18.2.0" + "react": "^18.3.1" + } + }, + "node_modules/react-hook-form": { + "version": "7.51.3", + "resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.51.3.tgz", + "integrity": "sha512-cvJ/wbHdhYx8aviSWh28w9ImjmVsb5Y05n1+FW786vEZQJV5STNM0pW6ujS+oiBecb0ARBxJFyAnXj9+GHXACQ==", + "engines": { + "node": ">=12.22.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/react-hook-form" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17 || ^18" } }, "node_modules/react-is": { @@ -7294,9 +6624,9 @@ "dev": true }, "node_modules/scheduler": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", - "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", + "version": "0.23.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", + "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", "dependencies": { "loose-envify": "^1.1.0" } @@ -7953,20 +7283,20 @@ } }, "node_modules/stylelint": { - "version": "16.3.1", - "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-16.3.1.tgz", - "integrity": "sha512-/JOwQnBvxEKOT2RtNgGpBVXnCSMBgKOL2k7w0K52htwCyJls4+cHvc4YZgXlVoAZS9QJd2DgYAiRnja96pTgxw==", + "version": "16.4.0", + "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-16.4.0.tgz", + "integrity": "sha512-uSx7VMuXwLuYcNSIg+0/fFNv0WinsfLAqsVVy7h7p80clKOHiGE8pfY6UjqwylTHiJrRIahTl6a8FPxGezhWoA==", "dev": true, "dependencies": { "@csstools/css-parser-algorithms": "^2.6.1", "@csstools/css-tokenizer": "^2.2.4", "@csstools/media-query-list-parser": "^2.1.9", - "@csstools/selector-specificity": "^3.0.2", + "@csstools/selector-specificity": "^3.0.3", "@dual-bundle/import-meta-resolve": "^4.0.0", "balanced-match": "^2.0.0", "colord": "^2.9.3", "cosmiconfig": "^9.0.0", - "css-functions-list": "^3.2.1", + "css-functions-list": "^3.2.2", "css-tree": "^2.3.1", "debug": "^4.3.4", "fast-glob": "^3.3.2", @@ -7995,7 +7325,7 @@ "strip-ansi": "^7.1.0", "supports-hyperlinks": "^3.0.0", "svg-tags": "^1.0.0", - "table": "^6.8.1", + "table": "^6.8.2", "write-file-atomic": "^5.0.1" }, "bin": { @@ -8232,15 +7562,6 @@ "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", "dev": true }, - "node_modules/tapable": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", - "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, "node_modules/term-size": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/term-size/-/term-size-2.2.1.tgz", @@ -8348,104 +7669,6 @@ } } }, - "node_modules/tsconfig-paths": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz", - "integrity": "sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==", - "dev": true, - "dependencies": { - "json5": "^2.2.2", - "minimist": "^1.2.6", - "strip-bom": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/tsconfig-paths-webpack-plugin": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/tsconfig-paths-webpack-plugin/-/tsconfig-paths-webpack-plugin-4.1.0.tgz", - "integrity": "sha512-xWFISjviPydmtmgeUAuXp4N1fky+VCtfhOkDUFIv5ea7p4wuTomI4QTrXvFBX2S4jZsmyTSrStQl+E+4w+RzxA==", - "dev": true, - "dependencies": { - "chalk": "^4.1.0", - "enhanced-resolve": "^5.7.0", - "tsconfig-paths": "^4.1.2" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/tsconfig-paths-webpack-plugin/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/tsconfig-paths-webpack-plugin/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/tsconfig-paths-webpack-plugin/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/tsconfig-paths-webpack-plugin/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/tsconfig-paths-webpack-plugin/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/tsconfig-paths-webpack-plugin/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/tslib": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", diff --git a/package.json b/package.json index bc9b22a..354221e 100644 --- a/package.json +++ b/package.json @@ -23,8 +23,9 @@ "author": "Kaleidos", "license": "MPL2.0", "dependencies": { - "react": "^18.2", - "react-dom": "^18.2", + "react": "^18.3", + "react-dom": "^18.3", + "react-hook-form": "^7.51", "slugify": "^1.6", "svg-path-parser": "^1.1" }, @@ -32,13 +33,13 @@ "@changesets/changelog-github": "^0.5", "@changesets/cli": "^2.27", "@figma/eslint-plugin-figma-plugins": "^0.15", - "@figma/plugin-typings": "^1.90", + "@figma/plugin-typings": "^1.92", "@trivago/prettier-plugin-sort-imports": "^4.3", - "@types/react": "^18.2", - "@types/react-dom": "^18.2", - "@typescript-eslint/eslint-plugin": "^7.5", - "@typescript-eslint/parser": "^7.5", + "@types/react": "^18.3", + "@types/react-dom": "^18.3", "@types/svg-path-parser": "^1.1", + "@typescript-eslint/eslint-plugin": "^7.8", + "@typescript-eslint/parser": "^7.8", "@vitejs/plugin-react-swc": "^3.6", "concurrently": "^8.2", "esbuild": "^0.20", @@ -47,9 +48,8 @@ "eslint-plugin-prettier": "^5.1", "eslint-plugin-react": "^7.34", "prettier": "^3.2", - "stylelint": "^16.3", + "stylelint": "^16.4", "stylelint-config-standard": "^36.0", - "tsconfig-paths-webpack-plugin": "^4.1", "typescript": "^5.4", "vite": "^5.2", "vite-plugin-singlefile": "^2.0", diff --git a/plugin-src/code.ts b/plugin-src/code.ts index b11ffdf..114e8f9 100644 --- a/plugin-src/code.ts +++ b/plugin-src/code.ts @@ -1,19 +1,33 @@ -import { - handleCancelMessage, - handleExportMessage, - handleResizeMessage -} from '@plugin/messageHandlers'; +import { transformDocumentNode } from '@plugin/transformers'; -figma.showUI(__html__, { themeColors: true, height: 200, width: 300 }); +import { findAllTextNodes } from './findAllTextnodes'; +import { setCustomFontId } from './translators/text/custom'; -figma.ui.onmessage = async msg => { - if (msg.type === 'export') { - await handleExportMessage(); +figma.showUI(__html__, { themeColors: true, height: 300, width: 400 }); + +figma.ui.onmessage = message => { + if (message.type === 'ready') { + findAllTextNodes(); } - if (msg.type === 'cancel') { - handleCancelMessage(); + + if (message.type === 'export') { + handleExportMessage(message.data as Record); } - if (msg.type === 'resize') { - handleResizeMessage(msg.width, msg.height); + + if (message.type === 'cancel') { + figma.closePlugin(); } }; + +const handleExportMessage = async (missingFontIds: Record) => { + await figma.loadAllPagesAsync(); + + Object.entries(missingFontIds).forEach(([fontFamily, fontId]) => { + setCustomFontId(fontFamily, fontId); + }); + + figma.ui.postMessage({ + type: 'PENPOT_DOCUMENT', + data: await transformDocumentNode(figma.root) + }); +}; diff --git a/plugin-src/findAllTextnodes.ts b/plugin-src/findAllTextnodes.ts new file mode 100644 index 0000000..7189a52 --- /dev/null +++ b/plugin-src/findAllTextnodes.ts @@ -0,0 +1,40 @@ +import { isGoogleFont } from './translators/text/gfonts'; +import { isLocalFont } from './translators/text/local'; + +export const findAllTextNodes = async () => { + await figma.loadAllPagesAsync(); + + const nodes = figma.root.findAllWithCriteria({ + types: ['TEXT'] + }); + + const fonts = new Set(); + + nodes.forEach(node => { + const styledTextSegments = node.getStyledTextSegments(['fontName']); + + styledTextSegments.forEach(segment => { + if (isGoogleFont(segment.fontName) || isLocalFont(segment.fontName)) { + return; + } + + fonts.add(segment.fontName.family); + }); + }); + + figma.ui.postMessage({ + type: 'CUSTOM_FONTS', + data: Array.from(fonts) + }); + + const maxHeight = 300; + + if (fonts.size === 0) return; + + if (fonts.size * 40 > maxHeight) { + figma.ui.resize(400, 300 + maxHeight); + return; + } + + figma.ui.resize(400, 300 + fonts.size * 40); +}; diff --git a/plugin-src/messageHandlers/handleCancelMessage.ts b/plugin-src/messageHandlers/handleCancelMessage.ts deleted file mode 100644 index b91a3b7..0000000 --- a/plugin-src/messageHandlers/handleCancelMessage.ts +++ /dev/null @@ -1,3 +0,0 @@ -export function handleCancelMessage() { - figma.closePlugin(); -} diff --git a/plugin-src/messageHandlers/handleExportMessage.ts b/plugin-src/messageHandlers/handleExportMessage.ts deleted file mode 100644 index 3d33147..0000000 --- a/plugin-src/messageHandlers/handleExportMessage.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { transformDocumentNode } from '@plugin/transformers'; - -export async function handleExportMessage() { - await figma.loadAllPagesAsync(); - - const penpotNode = await transformDocumentNode(figma.root); - figma.ui.postMessage({ type: 'FIGMAFILE', data: penpotNode }); -} diff --git a/plugin-src/messageHandlers/handleResizeMessage.ts b/plugin-src/messageHandlers/handleResizeMessage.ts deleted file mode 100644 index b4e322b..0000000 --- a/plugin-src/messageHandlers/handleResizeMessage.ts +++ /dev/null @@ -1,3 +0,0 @@ -export function handleResizeMessage(width: number, height: number) { - figma.ui.resize(width, height); -} diff --git a/plugin-src/messageHandlers/index.ts b/plugin-src/messageHandlers/index.ts deleted file mode 100644 index 4c54b10..0000000 --- a/plugin-src/messageHandlers/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from './handleCancelMessage'; -export * from './handleExportMessage'; -export * from './handleResizeMessage'; diff --git a/plugin-src/translators/text/custom/customFontIds.ts b/plugin-src/translators/text/custom/customFontIds.ts new file mode 100644 index 0000000..7a421a8 --- /dev/null +++ b/plugin-src/translators/text/custom/customFontIds.ts @@ -0,0 +1,9 @@ +const customFontIds = new Map(); + +export const getCustomFontId = (fontName: FontName) => { + return customFontIds.get(fontName.family); +}; + +export const setCustomFontId = (fontFamily: string, fontId: string) => { + customFontIds.set(fontFamily, fontId); +}; diff --git a/plugin-src/translators/text/custom/index.ts b/plugin-src/translators/text/custom/index.ts index 5e609ae..49e3ab5 100644 --- a/plugin-src/translators/text/custom/index.ts +++ b/plugin-src/translators/text/custom/index.ts @@ -1 +1,3 @@ +export * from './customFontIds'; export * from './translateCustomFont'; +export * from './translateFontVariantId'; diff --git a/plugin-src/translators/text/custom/translateCustomFont.ts b/plugin-src/translators/text/custom/translateCustomFont.ts index eda5915..684ada2 100644 --- a/plugin-src/translators/text/custom/translateCustomFont.ts +++ b/plugin-src/translators/text/custom/translateCustomFont.ts @@ -1,17 +1,10 @@ -import slugify from 'slugify'; +import { getCustomFontId, translateFontVariantId } from '@plugin/translators/text/custom'; import { FontId } from '@ui/lib/types/text/textContent'; -/** - * @TODO: implement custom font loading for Penpot - */ -export const translateCustomFont = (fontName: FontName): FontId | undefined => { - // For now display a message in the UI, so the user knows - // that the file is using a custom font not present in Penpot - figma.ui.postMessage({ type: 'FONT_NAME', data: fontName.family }); - +export const translateCustomFont = (fontName: FontName, fontWeight: number): FontId | undefined => { return { - fontId: slugify(fontName.family.toLowerCase()), - fontVariantId: fontName.style.toLowerCase().replace(/\s/g, '') + fontId: `custom-${getCustomFontId(fontName)}`, + fontVariantId: translateFontVariantId(fontName, fontWeight) }; }; diff --git a/plugin-src/translators/text/custom/translateFontVariantId.ts b/plugin-src/translators/text/custom/translateFontVariantId.ts new file mode 100644 index 0000000..112e5db --- /dev/null +++ b/plugin-src/translators/text/custom/translateFontVariantId.ts @@ -0,0 +1,5 @@ +export const translateFontVariantId = (fontName: FontName, fontWeight: number) => { + const style = fontName.style.toLowerCase().includes('italic') ? 'italic' : 'normal'; + + return `${style}-${fontWeight.toString()}`; +}; diff --git a/plugin-src/translators/text/gfonts/translateGoogleFont.ts b/plugin-src/translators/text/gfonts/translateGoogleFont.ts index d57a295..e40d2c2 100644 --- a/plugin-src/translators/text/gfonts/translateGoogleFont.ts +++ b/plugin-src/translators/text/gfonts/translateGoogleFont.ts @@ -18,6 +18,10 @@ export const translateGoogleFont = (fontName: FontName, fontWeight: number): Fon }; }; +export const isGoogleFont = (fontName: FontName): boolean => { + return getGoogleFont(fontName) !== undefined; +}; + const getGoogleFont = (fontName: FontName): GoogleFont | undefined => { return gfonts.find(font => font.family === fontName.family); }; diff --git a/plugin-src/translators/text/local/translateLocalFont.ts b/plugin-src/translators/text/local/translateLocalFont.ts index 959ee8a..26abdd8 100644 --- a/plugin-src/translators/text/local/translateLocalFont.ts +++ b/plugin-src/translators/text/local/translateLocalFont.ts @@ -15,6 +15,10 @@ export const translateLocalFont = (fontName: FontName, fontWeight: number): Font }; }; +export const isLocalFont = (fontName: FontName): boolean => { + return getLocalFont(fontName) !== undefined; +}; + const getLocalFont = (fontName: FontName): LocalFont | undefined => { return localFonts.find(localFont => localFont.name === fontName.family); }; diff --git a/plugin-src/translators/text/translateFontId.ts b/plugin-src/translators/text/translateFontId.ts index 6eeda67..97aaf17 100644 --- a/plugin-src/translators/text/translateFontId.ts +++ b/plugin-src/translators/text/translateFontId.ts @@ -8,6 +8,6 @@ export const translateFontId = (fontName: FontName, fontWeight: number): FontId return ( translateGoogleFont(fontName, fontWeight) ?? translateLocalFont(fontName, fontWeight) ?? - translateCustomFont(fontName) + translateCustomFont(fontName, fontWeight) ); }; diff --git a/plugin-src/tsconfig.json b/plugin-src/tsconfig.json index b29aaf0..776a1f6 100644 --- a/plugin-src/tsconfig.json +++ b/plugin-src/tsconfig.json @@ -1,8 +1,8 @@ { "extends": "../tsconfig.base.json", "compilerOptions": { - "target": "es6", - "lib": ["es6"], + "target": "ES2017", + "lib": ["ES2017"], "strict": true, "typeRoots": ["../node_modules/@figma"], "moduleResolution": "Node", diff --git a/ui-src/App.tsx b/ui-src/App.tsx new file mode 100644 index 0000000..be898c6 --- /dev/null +++ b/ui-src/App.tsx @@ -0,0 +1,12 @@ +import Logo from '@ui/assets/logo.svg?react'; +import { PenpotExporter } from '@ui/components/PenpotExporter'; + +export const App = () => ( +
+
+ +

Penpot Exporter

+
+ +
+); diff --git a/ui-src/PenpotExporter.tsx b/ui-src/PenpotExporter.tsx deleted file mode 100644 index c02a638..0000000 --- a/ui-src/PenpotExporter.tsx +++ /dev/null @@ -1,94 +0,0 @@ -import { useEffect, useState } from 'react'; - -import { createPenpotFile } from '@ui/converters'; -import { PenpotDocument } from '@ui/lib/types/penpotDocument'; - -import Logo from './logo.svg?react'; - -export const PenpotExporter = () => { - const [missingFonts, setMissingFonts] = useState(new Set()); - const [exporting, setExporting] = useState(false); - - const addFontWarning = (font: string) => { - setMissingFonts(missingFonts => missingFonts.add(font)); - }; - - const onMessage = (event: MessageEvent<{ pluginMessage: { type: string; data: unknown } }>) => { - if (event.data.pluginMessage?.type == 'FIGMAFILE') { - const document = event.data.pluginMessage.data as PenpotDocument; - const file = createPenpotFile(document); - - file.export(); - - setExporting(false); - } else if (event.data.pluginMessage?.type == 'FONT_NAME') { - addFontWarning(event.data.pluginMessage.data as string); - } - }; - - const onCreatePenpot = () => { - setExporting(true); - - parent.postMessage({ pluginMessage: { type: 'export' } }, '*'); - }; - - const onCancel = () => { - parent.postMessage({ pluginMessage: { type: 'cancel' } }, '*'); - }; - - const setDimensions = () => { - const isMissingFonts = missingFonts.size > 0; - - let width = 300; - let height = 280; - - if (isMissingFonts) { - height += missingFonts.size * 20; - width = 400; - parent.postMessage({ pluginMessage: { type: 'resize', width: width, height: height } }, '*'); - } - }; - - useEffect(() => { - window.addEventListener('message', onMessage); - - return () => { - window.removeEventListener('message', onMessage); - }; - }, []); - - useEffect(() => { - setDimensions(); - }, [missingFonts]); - - return ( -
-
- -

Penpot Exporter

-
-
-
0 ? 'inline' : 'none' }}> -
- {missingFonts.size} non-default font - {missingFonts.size > 1 ? 's' : ''}:{' '} -
- Ensure fonts are installed in Penpot before importing. -
-
    - {Array.from(missingFonts).map(font => ( -
  • {font}
  • - ))} -
-
-
-
-
- - -
-
- ); -}; diff --git a/ui-src/logo.svg b/ui-src/assets/logo.svg similarity index 100% rename from ui-src/logo.svg rename to ui-src/assets/logo.svg diff --git a/ui-src/components/Loader.tsx b/ui-src/components/Loader.tsx new file mode 100644 index 0000000..7ec728f --- /dev/null +++ b/ui-src/components/Loader.tsx @@ -0,0 +1,9 @@ +type LoaderProps = { + loading: boolean; +}; + +export const Loader = ({ loading }: LoaderProps) => { + if (!loading) return; + + return
Checking for missing fonts...
; +}; diff --git a/ui-src/components/MissingFontsSection.tsx b/ui-src/components/MissingFontsSection.tsx new file mode 100644 index 0000000..a7156bd --- /dev/null +++ b/ui-src/components/MissingFontsSection.tsx @@ -0,0 +1,34 @@ +import { useFormContext } from 'react-hook-form'; + +type MissingFontsSectionProps = { + fonts?: string[]; +}; + +export const MissingFontsSection = ({ fonts }: MissingFontsSectionProps) => { + const { register } = useFormContext(); + + if (fonts === undefined || !fonts.length) return; + + return ( +
+
+ {fonts.length} missing font{fonts.length > 1 ? 's' : ''}:{' '} +
+ + Ensure fonts are installed in Penpot before exporting. + +
+ {fonts.map(font => ( +
+ {font} + +
+ ))} +
+
+ ); +}; diff --git a/ui-src/components/PenpotExporter.tsx b/ui-src/components/PenpotExporter.tsx new file mode 100644 index 0000000..4a9b313 --- /dev/null +++ b/ui-src/components/PenpotExporter.tsx @@ -0,0 +1,78 @@ +import { useEffect, useState } from 'react'; +import { FormProvider, useForm } from 'react-hook-form'; + +import { createPenpotFile } from '@ui/converters'; +import { PenpotDocument } from '@ui/lib/types/penpotDocument'; + +import { Loader } from './Loader'; +import { MissingFontsSection } from './MissingFontsSection'; + +type FormValues = Record; + +export const PenpotExporter = () => { + const [missingFonts, setMissingFonts] = useState(); + const [exporting, setExporting] = useState(false); + const methods = useForm(); + + methods.getValues(); + + const onMessage = (event: MessageEvent<{ pluginMessage: { type: string; data: unknown } }>) => { + if (event.data.pluginMessage?.type == 'PENPOT_DOCUMENT') { + const document = event.data.pluginMessage.data as PenpotDocument; + const file = createPenpotFile(document); + + file.export(); + + setExporting(false); + } else if (event.data.pluginMessage?.type == 'CUSTOM_FONTS') { + setMissingFonts(event.data.pluginMessage.data as string[]); + } + }; + + const exportPenpot = (data: FormValues) => { + setExporting(true); + + parent.postMessage( + { + pluginMessage: { + type: 'export', + data + } + }, + '*' + ); + }; + + const cancel = () => { + parent.postMessage({ pluginMessage: { type: 'cancel' } }, '*'); + }; + + useEffect(() => { + window.addEventListener('message', onMessage); + + parent.postMessage({ pluginMessage: { type: 'ready' } }, '*'); + + return () => { + window.removeEventListener('message', onMessage); + }; + }, []); + + const pluginReady = missingFonts !== undefined; + + return ( + +
+ +
+ +
+
+ + +
+ +
+ ); +}; diff --git a/ui-src/main.css b/ui-src/main.css index c6a6b40..f565ef0 100644 --- a/ui-src/main.css +++ b/ui-src/main.css @@ -123,3 +123,54 @@ ul { padding: 0; list-style-type: none; } + +.centered-form { + display: flex; + flex-direction: column; + align-items: center; + width: 100%; +} + +.missing-fonts-form-container { + width: 100%; + margin: 0 auto 10px; + max-height: 300px; + overflow: auto; +} + +.missing-fonts-section { + width: 100%; + max-width: 500px; + margin: 0 auto; +} + +.missing-fonts-list { + display: flex; + flex-direction: column; + align-items: stretch; + width: 90%; +} + +.font-input-row { + display: flex; + align-items: center; + justify-content: space-between; + margin-bottom: 15px; +} + +.font-name { + flex: 0 0 auto; + width: 100%; + max-width: 30%; + text-align: center; + white-space: normal; +} + +.font-id-input { + flex: 1; + width: 70%; + max-width: 70%; + margin-left: 10px; + padding: 5px; + box-sizing: border-box; +} diff --git a/ui-src/main.tsx b/ui-src/main.tsx index dd7c8be..2c09097 100644 --- a/ui-src/main.tsx +++ b/ui-src/main.tsx @@ -1,11 +1,11 @@ import { StrictMode } from 'react'; import { createRoot } from 'react-dom/client'; -import { PenpotExporter } from './PenpotExporter'; +import { App } from './App'; import './main.css'; createRoot(document.getElementById('root') as HTMLElement).render( - + ); diff --git a/ui-src/tsconfig.json b/ui-src/tsconfig.json index e85af1c..bcec7bf 100644 --- a/ui-src/tsconfig.json +++ b/ui-src/tsconfig.json @@ -13,6 +13,7 @@ "moduleResolution": "Node", "isolatedModules": true, "noEmit": true, - "jsx": "react-jsx" + "jsx": "react-jsx", + "allowSyntheticDefaultImports": true } }