From 398a4c0cf7cc70cb030dafc8f91b56205c304c73 Mon Sep 17 00:00:00 2001 From: MinHo Lim Date: Tue, 16 Dec 2025 14:03:55 +0900 Subject: [PATCH 1/4] chore: add lint-staged --- .husky/pre-commit | 8 +- package-lock.json | 771 +++++++++++++++++++++++++++++++++++++++++++++- package.json | 10 +- 3 files changed, 769 insertions(+), 20 deletions(-) diff --git a/.husky/pre-commit b/.husky/pre-commit index b02f01a9..d0a77842 100644 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -1,7 +1 @@ -set -e - -STAGED_FILES=$(git diff --cached --name-only | grep -E '.js|.ts|.svelte' || true) - -if [ -n "$STAGED_FILES" ]; then - npm run lint -fi \ No newline at end of file +npx lint-staged \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 0366d326..6bd0db81 100644 --- a/package-lock.json +++ b/package-lock.json @@ -28,6 +28,7 @@ "@vitest/browser": "^4.0.8", "@vitest/browser-playwright": "^4.0.8", "husky": "^9.1.7", + "lint-staged": "^15.2.10", "pixi.js": "^8.14.1", "playwright": "^1.56.1", "rollup": "^4.53.2", @@ -1539,7 +1540,6 @@ "integrity": "sha512-qzQZRBqkFsYyaSWXuEHc2WR9c0a0CXwiE5FWUvn7ZM+vdy1uZLfCunD38UzhuB7YN/J11ndbDBcTmOdxJo9Q7A==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "undici-types": "~7.16.0" } @@ -1587,7 +1587,6 @@ "integrity": "sha512-MUi0msIAPXcA2YAuVMcssrSYP/yylxLt347xyTC6+ODl0c4XQFs0d2AN3Pc3iTa0pxIGmogflUV6eogXpPbJeA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@vitest/browser": "4.0.8", "@vitest/mocker": "4.0.8", @@ -1766,6 +1765,22 @@ "url": "https://github.com/sponsors/epoberezkin" } }, + "node_modules/ansi-escapes": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.2.0.tgz", + "integrity": "sha512-g6LhBsl+GBPRWGWsBtutpzBYuIIdBkLEvad5C/va/74Db018+5TZiyA26cZJAr3Rft5lprVqOIPxf5Vid6tqAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "environment": "^1.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", @@ -1776,6 +1791,19 @@ "node": ">=8" } }, + "node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", @@ -1919,6 +1947,93 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/cli-cursor": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz", + "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==", + "dev": true, + "license": "MIT", + "dependencies": { + "restore-cursor": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-truncate": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-4.0.0.tgz", + "integrity": "sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA==", + "dev": true, + "license": "MIT", + "dependencies": { + "slice-ansi": "^5.0.0", + "string-width": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-truncate/node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/cli-truncate/node_modules/emoji-regex": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", + "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", + "dev": true, + "license": "MIT" + }, + "node_modules/cli-truncate/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-truncate/node_modules/strip-ansi": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", + "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, "node_modules/cliui": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", @@ -1958,6 +2073,16 @@ "dev": true, "license": "MIT" }, + "node_modules/commander": { + "version": "13.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-13.1.0.tgz", + "integrity": "sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, "node_modules/commondir": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", @@ -3041,7 +3166,6 @@ "integrity": "sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "env-paths": "^2.2.1", "import-fresh": "^3.3.0", @@ -3081,6 +3205,21 @@ "typescript": ">=5" } }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, "node_modules/dargs": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/dargs/-/dargs-8.1.0.tgz", @@ -3318,6 +3457,19 @@ "node": ">=6" } }, + "node_modules/environment": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/environment/-/environment-1.1.0.tgz", + "integrity": "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/error-ex": { "version": "1.3.4", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", @@ -3410,6 +3562,30 @@ "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", "license": "MIT" }, + "node_modules/execa": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz", + "integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^8.0.1", + "human-signals": "^5.0.0", + "is-stream": "^3.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^5.1.0", + "onetime": "^6.0.0", + "signal-exit": "^4.1.0", + "strip-final-newline": "^3.0.0" + }, + "engines": { + "node": ">=16.17" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, "node_modules/expect-type": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.2.2.tgz", @@ -3593,6 +3769,19 @@ "node": "6.* || 8.* || >= 10.*" } }, + "node_modules/get-east-asian-width": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.4.0.tgz", + "integrity": "sha512-QZjmEOC+IT1uk6Rx0sX22V6uHWVwbdbxf1faPqJ1QhLdGgsRGCZoyaQBm/piRdJy/D2um6hM1UP7ZEeQ4EkP+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/get-pkg-repo": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/get-pkg-repo/-/get-pkg-repo-4.2.1.tgz", @@ -3697,6 +3886,19 @@ "node": ">=10" } }, + "node_modules/get-stream": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz", + "integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/gifuct-js": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/gifuct-js/-/gifuct-js-2.1.2.tgz", @@ -4120,6 +4322,16 @@ "node": ">=10" } }, + "node_modules/human-signals": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz", + "integrity": "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=16.17.0" + } + }, "node_modules/husky": { "version": "9.1.7", "resolved": "https://registry.npmjs.org/husky/-/husky-9.1.7.tgz", @@ -4335,6 +4547,19 @@ "@types/estree": "*" } }, + "node_modules/is-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-text-path": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-text-path/-/is-text-path-2.0.0.tgz", @@ -4355,6 +4580,13 @@ "dev": true, "license": "MIT" }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, "node_modules/ismobilejs": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ismobilejs/-/ismobilejs-1.1.1.tgz", @@ -4402,7 +4634,6 @@ "resolved": "https://registry.npmjs.org/jsep/-/jsep-1.4.0.tgz", "integrity": "sha512-B7qPcEVE3NVkmSJbaYxvv4cHkVW7DQsZz13pUMrfS8z8Q/BuShN+gcTXrUlPiGqM2/t/EEaI030bpxMqY8gMlw==", "license": "MIT", - "peer": true, "engines": { "node": ">= 10.16.0" } @@ -4500,6 +4731,19 @@ "node": ">=0.10.0" } }, + "node_modules/lilconfig": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", + "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" + } + }, "node_modules/lines-and-columns": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", @@ -4507,6 +4751,131 @@ "dev": true, "license": "MIT" }, + "node_modules/lint-staged": { + "version": "15.5.2", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-15.5.2.tgz", + "integrity": "sha512-YUSOLq9VeRNAo/CTaVmhGDKG+LBtA8KF1X4K5+ykMSwWST1vDxJRB2kv2COgLb1fvpCo+A/y9A0G0znNVmdx4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^5.4.1", + "commander": "^13.1.0", + "debug": "^4.4.0", + "execa": "^8.0.1", + "lilconfig": "^3.1.3", + "listr2": "^8.2.5", + "micromatch": "^4.0.8", + "pidtree": "^0.6.0", + "string-argv": "^0.3.2", + "yaml": "^2.7.0" + }, + "bin": { + "lint-staged": "bin/lint-staged.js" + }, + "engines": { + "node": ">=18.12.0" + }, + "funding": { + "url": "https://opencollective.com/lint-staged" + } + }, + "node_modules/listr2": { + "version": "8.3.3", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-8.3.3.tgz", + "integrity": "sha512-LWzX2KsqcB1wqQ4AHgYb4RsDXauQiqhjLk+6hjbaeHG4zpjjVAB6wC/gz6X0l+Du1cN3pUB5ZlrvTbhGSNnUQQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "cli-truncate": "^4.0.0", + "colorette": "^2.0.20", + "eventemitter3": "^5.0.1", + "log-update": "^6.1.0", + "rfdc": "^1.4.1", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/listr2/node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/listr2/node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "dev": true, + "license": "MIT" + }, + "node_modules/listr2/node_modules/emoji-regex": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", + "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", + "dev": true, + "license": "MIT" + }, + "node_modules/listr2/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/listr2/node_modules/strip-ansi": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", + "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/listr2/node_modules/wrap-ansi": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", + "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, "node_modules/load-json-file": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", @@ -4640,6 +5009,131 @@ "dev": true, "license": "MIT" }, + "node_modules/log-update": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/log-update/-/log-update-6.1.0.tgz", + "integrity": "sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-escapes": "^7.0.0", + "cli-cursor": "^5.0.0", + "slice-ansi": "^7.1.0", + "strip-ansi": "^7.1.0", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/log-update/node_modules/emoji-regex": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", + "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", + "dev": true, + "license": "MIT" + }, + "node_modules/log-update/node_modules/is-fullwidth-code-point": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-5.1.0.tgz", + "integrity": "sha512-5XHYaSyiqADb4RnZ1Bdad6cPp8Toise4TzEjcOYDHZkTCbKgiUl7WTUCpNWHuxmDt91wnsZBc9xinNzopv3JMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-east-asian-width": "^1.3.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/slice-ansi": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-7.1.2.tgz", + "integrity": "sha512-iOBWFgUX7caIZiuutICxVgX1SdxwAVFFKwt1EvMYYec/NWO5meOJ6K5uQxhrYBdQJne4KxiqZc+KptFOWFSI9w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "is-fullwidth-code-point": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/log-update/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/strip-ansi": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", + "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/log-update/node_modules/wrap-ansi": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", + "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, "node_modules/lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -4715,6 +5209,13 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true, + "license": "MIT" + }, "node_modules/merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", @@ -4765,6 +5266,32 @@ "node": ">=10.0.0" } }, + "node_modules/mimic-fn": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", + "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mimic-function": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz", + "integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/min-indent": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", @@ -4881,6 +5408,35 @@ "node": ">=10" } }, + "node_modules/npm-run-path": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.3.0.tgz", + "integrity": "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm-run-path/node_modules/path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -4891,6 +5447,22 @@ "wrappy": "1" } }, + "node_modules/onetime": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", + "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-fn": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/p-limit": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz", @@ -4991,6 +5563,16 @@ "node": ">=0.10.0" } }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/path-parse": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", @@ -5035,6 +5617,19 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/pidtree": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.6.0.tgz", + "integrity": "sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==", + "dev": true, + "license": "MIT", + "bin": { + "pidtree": "bin/pidtree.js" + }, + "engines": { + "node": ">=0.10" + } + }, "node_modules/pify": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", @@ -5072,7 +5667,6 @@ "resolved": "https://registry.npmjs.org/pixi.js/-/pixi.js-8.14.1.tgz", "integrity": "sha512-cwiY5VdzpbjoxW/n378bHBaPbZF8e81rYS36rfgUOSHyqLJ7AvC/YYUVfybnjJrT8/zVJ/gBIEpVSmt+A+FC6Q==", "license": "MIT", - "peer": true, "dependencies": { "@pixi/colord": "^2.9.6", "@types/css-font-loading-module": "^0.0.12", @@ -5097,7 +5691,6 @@ "integrity": "sha512-aFi5B0WovBHTEvpM3DzXTUaeN6eN0qWnTkKx4NQaH4Wvcmc153PdaY2UBdSYKaGYw+UyWXSVyxDUg5DoPEttjw==", "dev": true, "license": "Apache-2.0", - "peer": true, "dependencies": { "playwright-core": "1.56.1" }, @@ -5467,6 +6060,39 @@ "node": ">=8" } }, + "node_modules/restore-cursor": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz", + "integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==", + "dev": true, + "license": "MIT", + "dependencies": { + "onetime": "^7.0.0", + "signal-exit": "^4.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/restore-cursor/node_modules/onetime": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz", + "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-function": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/reusify": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", @@ -5478,13 +6104,19 @@ "node": ">=0.10.0" } }, + "node_modules/rfdc": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", + "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", + "dev": true, + "license": "MIT" + }, "node_modules/rollup": { "version": "4.53.2", "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.53.2.tgz", "integrity": "sha512-MHngMYwGJVi6Fmnk6ISmnk7JAHRNF0UkuucA0CUW3N3a4KnONPEZz+vUanQP/ZC/iY1Qkf3bwPWzyY84wEks1g==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@types/estree": "1.0.8" }, @@ -5606,6 +6238,29 @@ "node": ">=10" } }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/siginfo": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", @@ -5613,6 +6268,19 @@ "dev": true, "license": "ISC" }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/sirv": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/sirv/-/sirv-3.0.2.tgz", @@ -5638,6 +6306,36 @@ "node": ">=8" } }, + "node_modules/slice-ansi": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-5.0.0.tgz", + "integrity": "sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.0.0", + "is-fullwidth-code-point": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/slice-ansi/node_modules/is-fullwidth-code-point": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz", + "integrity": "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -5942,6 +6640,16 @@ "safe-buffer": "~5.2.0" } }, + "node_modules/string-argv": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.2.tgz", + "integrity": "sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.6.19" + } + }, "node_modules/string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", @@ -5988,6 +6696,19 @@ "node": ">=4" } }, + "node_modules/strip-final-newline": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", + "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/strip-indent": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", @@ -6169,7 +6890,6 @@ "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "dev": true, "license": "Apache-2.0", - "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -6246,7 +6966,6 @@ "integrity": "sha512-BxAKBWmIbrDgrokdGZH1IgkIk/5mMHDreLDmCJ0qpyJaAteP8NvMhkwr/ZCQNqNH97bw/dANTE9PDzqwJghfMQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.5.0", @@ -6337,7 +7056,6 @@ "integrity": "sha512-urzu3NCEV0Qa0Y2PwvBtRgmNtxhj5t5ULw7cuKhIHh3OrkKTLlut0lnBOv9qe5OvbkMH2g38G7KPDCTpIytBVg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@vitest/expect": "4.0.8", "@vitest/mocker": "4.0.8", @@ -6417,6 +7135,22 @@ "dev": true, "license": "MIT" }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, "node_modules/why-is-node-running": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", @@ -6551,6 +7285,22 @@ "dev": true, "license": "ISC" }, + "node_modules/yaml": { + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.2.tgz", + "integrity": "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==", + "dev": true, + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + }, + "funding": { + "url": "https://github.com/sponsors/eemeli" + } + }, "node_modules/yargs": { "version": "17.7.2", "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", @@ -6598,7 +7348,6 @@ "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", "license": "MIT", - "peer": true, "funding": { "url": "https://github.com/sponsors/colinhacks" } diff --git a/package.json b/package.json index 7b257e87..1aabcc18 100644 --- a/package.json +++ b/package.json @@ -72,6 +72,12 @@ "rollup-plugin-copy": "^3.5.0", "standard-version": "^9.5.0", "typescript": "^5.9.3", - "vitest": "^4.0.8" + "vitest": "^4.0.8", + "lint-staged": "^15.2.10" + }, + "lint-staged": { + "*.{js,ts,svelte}": [ + "biome check --write --no-errors-on-unmatched" + ] } -} +} \ No newline at end of file From b1faae4061d9dabbf40c003abc62fe3b4dc149c4 Mon Sep 17 00:00:00 2001 From: MinHo Lim Date: Tue, 16 Dec 2025 14:04:02 +0900 Subject: [PATCH 2/4] fix: enable update method to target viewport --- .gitignore | 2 +- biome.json | 3 ++- src/command/commands/update.js | 4 ++-- src/display/Viewport.js | 18 ++++++++++++++++++ src/display/components/Background.js | 4 ++-- src/display/components/Bar.js | 4 ++-- src/display/components/Icon.js | 4 ++-- src/display/components/Text.js | 4 ++-- src/display/draw.js | 4 ++-- src/display/elements/Grid.js | 4 ++-- src/display/elements/Group.js | 4 ++-- src/display/elements/Item.js | 4 ++-- src/display/elements/Relations.js | 6 +++--- src/display/mixins/Base.js | 6 +++--- src/display/mixins/Cellsable.js | 2 +- src/display/mixins/Childrenable.js | 2 +- src/display/mixins/Componentsable.js | 2 +- src/display/mixins/Itemable.js | 2 +- src/display/mixins/Itemsizeable.js | 2 +- src/display/update.js | 2 +- src/init.js | 9 ++++----- src/patchmap.js | 17 +++++++++++++---- src/utils/diff/create-patch.js | 5 +---- src/utils/diff/is-same.js | 5 +---- 24 files changed, 70 insertions(+), 49 deletions(-) create mode 100644 src/display/Viewport.js diff --git a/.gitignore b/.gitignore index b239677f..61c8ac19 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,4 @@ node_modules dist *.tgz -src/tests/*/__screenshots__ +src/tests/**/__screenshots__ diff --git a/biome.json b/biome.json index e6676e71..26959f1a 100644 --- a/biome.json +++ b/biome.json @@ -21,7 +21,8 @@ "recommended": true, "suspicious": { "noDebugger": "error", - "noImportAssign": "error" + "noImportAssign": "error", + "useIterableCallbackReturn": "off" }, "correctness": { "noUnusedVariables": "error", diff --git a/src/command/commands/update.js b/src/command/commands/update.js index bf6975a3..bac00602 100644 --- a/src/command/commands/update.js +++ b/src/command/commands/update.js @@ -10,14 +10,14 @@ export class UpdateCommand extends Command { } execute() { - this.element.update(this.changes, { + this.element.apply(this.changes, { ...this.options, historyId: false, }); } undo() { - this.element.update(this.previousProps, { + this.element.apply(this.previousProps, { ...this.options, mergeStrategy: 'replace', historyId: false, diff --git a/src/display/Viewport.js b/src/display/Viewport.js new file mode 100644 index 00000000..5408c28b --- /dev/null +++ b/src/display/Viewport.js @@ -0,0 +1,18 @@ +import { Viewport } from 'pixi-viewport'; +import { groupSchema } from './data-schema/element-schema'; +import { Base } from './mixins/Base'; +import { Childrenable } from './mixins/Childrenable'; +import { mixins } from './mixins/utils'; + +const ComposedViewport = mixins(Viewport, Base, Childrenable); + +export default class BaseViewport extends ComposedViewport { + constructor(options) { + super({ type: 'canvas', ...options }); + Object.assign(this.context, { viewport: this }); + } + + apply(changes, options) { + super.apply(changes, groupSchema, options); + } +} diff --git a/src/display/components/Background.js b/src/display/components/Background.js index 19944d04..5dc9be1d 100644 --- a/src/display/components/Background.js +++ b/src/display/components/Background.js @@ -23,7 +23,7 @@ export class Background extends ComposedBackground { super({ type: 'background', context, texture: Texture.WHITE }); } - update(changes, options) { - super.update(changes, backgroundSchema, options); + apply(changes, options) { + super.apply(changes, backgroundSchema, options); } } diff --git a/src/display/components/Bar.js b/src/display/components/Bar.js index c2c05450..1fe44425 100644 --- a/src/display/components/Bar.js +++ b/src/display/components/Bar.js @@ -34,7 +34,7 @@ export class Bar extends ComposedBar { ); } - update(changes, options) { - super.update(changes, barSchema, options); + apply(changes, options) { + super.apply(changes, barSchema, options); } } diff --git a/src/display/components/Icon.js b/src/display/components/Icon.js index 23abdc02..692e7420 100644 --- a/src/display/components/Icon.js +++ b/src/display/components/Icon.js @@ -32,7 +32,7 @@ export class Icon extends ComposedIcon { ); } - update(changes, options) { - super.update(changes, iconSchema, options); + apply(changes, options) { + super.apply(changes, iconSchema, options); } } diff --git a/src/display/components/Text.js b/src/display/components/Text.js index d03061f8..2d31864e 100644 --- a/src/display/components/Text.js +++ b/src/display/components/Text.js @@ -32,7 +32,7 @@ export class Text extends ComposedText { ); } - update(changes, options) { - super.update(changes, textSchema, options); + apply(changes, options) { + super.apply(changes, textSchema, options); } } diff --git a/src/display/draw.js b/src/display/draw.js index 3b9e17a2..0bc3aa4d 100644 --- a/src/display/draw.js +++ b/src/display/draw.js @@ -1,5 +1,5 @@ -import Element from './elements/Element'; import { newElement } from './elements/creator'; +import Element from './elements/Element'; export const draw = (context, data) => { const { viewport } = context; @@ -9,7 +9,7 @@ export const draw = (context, data) => { function render(parent, data) { for (const changes of data) { const element = newElement(changes.type, context); - element.update(changes); + element.apply(changes); parent.addChild(element); } } diff --git a/src/display/elements/Grid.js b/src/display/elements/Grid.js index 4394a030..89f8c071 100644 --- a/src/display/elements/Grid.js +++ b/src/display/elements/Grid.js @@ -11,7 +11,7 @@ export class Grid extends ComposedGrid { super({ type: 'grid', context }); } - update(changes, options) { - super.update(changes, gridSchema, options); + apply(changes, options) { + super.apply(changes, gridSchema, options); } } diff --git a/src/display/elements/Group.js b/src/display/elements/Group.js index 411ff0aa..c4f267ab 100644 --- a/src/display/elements/Group.js +++ b/src/display/elements/Group.js @@ -10,7 +10,7 @@ export class Group extends ComposedGroup { super({ type: 'group', context, isRenderGroup: true }); } - update(changes, options) { - super.update(changes, groupSchema, options); + apply(changes, options) { + super.apply(changes, groupSchema, options); } } diff --git a/src/display/elements/Item.js b/src/display/elements/Item.js index 4fd96529..62bd1e41 100644 --- a/src/display/elements/Item.js +++ b/src/display/elements/Item.js @@ -14,7 +14,7 @@ export class Item extends ComposedItem { super({ type: 'item', context }); } - update(changes, options) { - super.update(changes, itemSchema, options); + apply(changes, options) { + super.apply(changes, itemSchema, options); } } diff --git a/src/display/elements/Relations.js b/src/display/elements/Relations.js index f890d136..b1ef97a9 100644 --- a/src/display/elements/Relations.js +++ b/src/display/elements/Relations.js @@ -1,8 +1,8 @@ import { Graphics } from 'pixi.js'; import { calcOrientedBounds } from '../../utils/bounds'; import { relationsSchema } from '../data-schema/element-schema'; -import { Relationstyleable } from '../mixins/Relationstyleable'; import { Linksable } from '../mixins/linksable'; +import { Relationstyleable } from '../mixins/Relationstyleable'; import { mixins } from '../mixins/utils'; import Element from './Element'; @@ -20,8 +20,8 @@ export class Relations extends ComposedRelations { this.path = this.initPath(); } - update(changes, options) { - super.update(changes, relationsSchema, options); + apply(changes, options) { + super.apply(changes, relationsSchema, options); } initPath() { diff --git a/src/display/mixins/Base.js b/src/display/mixins/Base.js index e896e354..63e2386a 100644 --- a/src/display/mixins/Base.js +++ b/src/display/mixins/Base.js @@ -49,7 +49,7 @@ export const Base = (superClass) => { } static registerHandler(keys, handler, stage) { - if (!Object.prototype.hasOwnProperty.call(this, '_handlerRegistry')) { + if (!Object.hasOwn(this, '_handlerRegistry')) { this._handlerRegistry = new Map(this._handlerRegistry); this._handlerMap = new Map(this._handlerMap); } @@ -66,7 +66,7 @@ export const Base = (superClass) => { }); } - update(changes, schema, options = {}) { + apply(changes, schema, options = {}) { const { mergeStrategy = 'merge', refresh = false } = options; const effectiveChanges = refresh && !changes ? {} : changes; const validatedChanges = validate(effectiveChanges, deepPartial(schema)); @@ -116,7 +116,7 @@ export const Base = (superClass) => { this.constructor._handlerRegistry.get(handler).keys; const fullPayload = {}; keysForHandler.forEach((key) => { - if (Object.prototype.hasOwnProperty.call(this.props, key)) { + if (Object.hasOwn(this.props, key)) { fullPayload[key] = this.props[key]; } }); diff --git a/src/display/mixins/Cellsable.js b/src/display/mixins/Cellsable.js index 3ab44dc4..c5d07bb7 100644 --- a/src/display/mixins/Cellsable.js +++ b/src/display/mixins/Cellsable.js @@ -19,7 +19,7 @@ export const Cellsable = (superClass) => { requiredItemIds.add(id); if (!currentItemIds.has(id)) { const item = newElement('item', this.context); - item.update({ + item.apply({ type: 'item', id, ...itemProps, diff --git a/src/display/mixins/Childrenable.js b/src/display/mixins/Childrenable.js index ddf4cda6..4fcca114 100644 --- a/src/display/mixins/Childrenable.js +++ b/src/display/mixins/Childrenable.js @@ -38,7 +38,7 @@ export const Childrenable = (superClass) => { element = newElement(childChange.type, this.context); this.addChild(element); } - element.update(childChange, options); + element.apply(childChange, options); } } diff --git a/src/display/mixins/Componentsable.js b/src/display/mixins/Componentsable.js index ed43fb70..572675e7 100644 --- a/src/display/mixins/Componentsable.js +++ b/src/display/mixins/Componentsable.js @@ -38,7 +38,7 @@ export const Componentsable = (superClass) => { component = newComponent(componentChange.type, this.context); this.addChild(component); } - component.update( + component.apply( { type: componentChange.type, ...componentChange }, options, ); diff --git a/src/display/mixins/Itemable.js b/src/display/mixins/Itemable.js index 448b928f..2b66679a 100644 --- a/src/display/mixins/Itemable.js +++ b/src/display/mixins/Itemable.js @@ -14,7 +14,7 @@ export const Itemable = (superClass) => { const [rowIndex, colIndex] = coordsPart.split('.').map(Number); if (!Number.isNaN(rowIndex) && !Number.isNaN(colIndex)) { - child.update( + child.apply( { ...itemProps, attrs: { diff --git a/src/display/mixins/Itemsizeable.js b/src/display/mixins/Itemsizeable.js index 5bfe6eb8..c7d0251f 100644 --- a/src/display/mixins/Itemsizeable.js +++ b/src/display/mixins/Itemsizeable.js @@ -6,7 +6,7 @@ export const ItemSizeable = (superClass) => { const MixedClass = class extends superClass { _applyItemSize() { for (const child of this.children) { - child.update(null, { refresh: true }); + child.apply(null, { refresh: true }); } } }; diff --git a/src/display/update.js b/src/display/update.js index 1fedd173..50d6f332 100644 --- a/src/display/update.js +++ b/src/display/update.js @@ -32,7 +32,7 @@ export const update = (viewport, opts) => { if (config.relativeTransform && changes.attrs) { changes.attrs = applyRelativeTransform(element, changes.attrs); } - element.update(changes, { + element.apply(changes, { historyId, mergeStrategy: config.mergeStrategy, refresh: config.refresh, diff --git a/src/init.js b/src/init.js index 9010fdba..fd3000de 100644 --- a/src/init.js +++ b/src/init.js @@ -1,11 +1,10 @@ -import { gsap } from 'gsap'; +import gsap from 'gsap'; import { PixiPlugin } from 'gsap/PixiPlugin'; -import { Viewport } from 'pixi-viewport'; import * as PIXI from 'pixi.js'; import { firaCode } from './assets/fonts'; import { icons } from './assets/icons'; -import { Type } from './display/mixins/Type'; import { FONT_WEIGHT } from './display/mixins/constants'; +import BaseViewport from './display/Viewport'; import { deepMerge } from './utils/deepmerge/deepmerge'; import { plugin } from './utils/event/viewport'; import { uid } from './utils/uuid'; @@ -61,7 +60,7 @@ export const initApp = async (app, opts = {}) => { app.renderer.uid = uid(); }; -export const initViewport = (app, opts = {}) => { +export const initViewport = (app, opts = {}, context) => { const options = deepMerge( { ...DEFAULT_INIT_OPTIONS.viewport, @@ -71,7 +70,7 @@ export const initViewport = (app, opts = {}) => { }, opts, ); - const viewport = new (Type(Viewport))({ ...options, type: 'canvas' }); + const viewport = new BaseViewport({ ...options, context }); viewport.app = app; viewport.events = {}; viewport.plugin = { diff --git a/src/patchmap.js b/src/patchmap.js index 4f55904e..9a1ce682 100644 --- a/src/patchmap.js +++ b/src/patchmap.js @@ -4,7 +4,7 @@ import { isValidationError } from 'zod-validation-error'; import { UndoRedoManager } from './command/UndoRedoManager'; import { draw } from './display/draw'; import { update } from './display/update'; -import { fit, focus } from './events/focus-fit'; +import { fit as fitViewport, focus } from './events/focus-fit'; import { initApp, initAsset, @@ -127,14 +127,23 @@ class Patchmap extends WildcardEventEmitter { this._theme.set(themeOptions); this._app = new Application(); await initApp(this.app, { resizeTo: element, ...appOptions }); - this.viewport = initViewport(this.app, viewportOptions); + + const context = { + undoRedoManager: this.undoRedoManager, + theme: this.theme, + animationContext: this.animationContext, + }; + this.viewport = initViewport(this.app, viewportOptions, context); + await initAsset(assetsOptions); initCanvas(element, this.app); this._resizeObserver = initResizeObserver(element, this.app, this.viewport); this._stateManager = new StateManager(this); this._stateManager.register('selection', SelectionState, true); - this.transformer = transformer; + if (transformer) { + this.transformer = transformer; + } this.isInit = true; this.emit('patchmap:initialized', { target: this }); } @@ -222,7 +231,7 @@ class Patchmap extends WildcardEventEmitter { } fit(ids) { - fit(this.viewport, ids); + fitViewport(this.viewport, ids); } selector(path, opts) { diff --git a/src/utils/diff/create-patch.js b/src/utils/diff/create-patch.js index 7d12dae2..e5dfa802 100644 --- a/src/utils/diff/create-patch.js +++ b/src/utils/diff/create-patch.js @@ -15,10 +15,7 @@ export const createPatch = (obj1, obj2) => { const result = {}; for (const key of Object.keys(obj2)) { - if ( - !Object.prototype.hasOwnProperty.call(obj1, key) || - !isSame(obj1[key], obj2[key]) - ) { + if (!Object.hasOwn(obj1, key) || !isSame(obj1[key], obj2[key])) { const patchValue = createPatch(obj1[key], obj2[key]); result[key] = patchValue; } diff --git a/src/utils/diff/is-same.js b/src/utils/diff/is-same.js index d324a312..c10b6427 100644 --- a/src/utils/diff/is-same.js +++ b/src/utils/diff/is-same.js @@ -58,10 +58,7 @@ function _isSame(a, b, visited) { if (keysA.length !== keysB.length) return false; for (const key of keysA) { - if ( - !Object.prototype.hasOwnProperty.call(b, key) || - !_isSame(a[key], b[key], visited) - ) { + if (!Object.hasOwn(b, key) || !_isSame(a[key], b[key], visited)) { return false; } } From 35d1a1a835e840afe30ce13dac72bb80755fdb82 Mon Sep 17 00:00:00 2001 From: MinHo Lim Date: Tue, 16 Dec 2025 16:33:39 +0900 Subject: [PATCH 3/4] fix --- src/display/Viewport.js | 4 ++-- src/display/data-schema/element-schema.js | 10 ++++++++++ src/display/draw.js | 11 +---------- 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/src/display/Viewport.js b/src/display/Viewport.js index 5408c28b..a3823523 100644 --- a/src/display/Viewport.js +++ b/src/display/Viewport.js @@ -1,5 +1,5 @@ import { Viewport } from 'pixi-viewport'; -import { groupSchema } from './data-schema/element-schema'; +import { canvasSchema } from './data-schema/element-schema'; import { Base } from './mixins/Base'; import { Childrenable } from './mixins/Childrenable'; import { mixins } from './mixins/utils'; @@ -13,6 +13,6 @@ export default class BaseViewport extends ComposedViewport { } apply(changes, options) { - super.apply(changes, groupSchema, options); + super.apply(changes, canvasSchema, options); } } diff --git a/src/display/data-schema/element-schema.js b/src/display/data-schema/element-schema.js index 28c8afba..30aa3c6c 100644 --- a/src/display/data-schema/element-schema.js +++ b/src/display/data-schema/element-schema.js @@ -2,6 +2,16 @@ import { z } from 'zod'; import { componentArraySchema } from './component-schema'; import { Base, Gap, Margin, RelationsStyle, Size } from './primitive-schema'; +/** + * A viewport is a container that can be panned and zoomed. + * Visually represented by a `Viewport`. + * @see {@link https://viewport.pixijs.io/jsdoc/Viewport.html} + */ +export const canvasSchema = Base.extend({ + type: z.literal('canvas'), + children: z.array(z.lazy(() => elementTypes)), +}).strict(); + /** * Groups multiple elements to apply common properties.. * Visually represented by a `Container`. diff --git a/src/display/draw.js b/src/display/draw.js index 0bc3aa4d..16971bfe 100644 --- a/src/display/draw.js +++ b/src/display/draw.js @@ -1,18 +1,9 @@ -import { newElement } from './elements/creator'; import Element from './elements/Element'; export const draw = (context, data) => { const { viewport } = context; destroyChildren(viewport); - render(viewport, data); - - function render(parent, data) { - for (const changes of data) { - const element = newElement(changes.type, context); - element.apply(changes); - parent.addChild(element); - } - } + viewport.apply({ type: 'canvas', children: data }); }; const destroyChildren = (parent) => { From 8ee7482e273ed1b52a1a9c94e75be8ecb0282de2 Mon Sep 17 00:00:00 2001 From: MinHo Lim Date: Tue, 16 Dec 2025 18:26:47 +0900 Subject: [PATCH 4/4] fix --- src/display/Viewport.js | 1 - src/init.js | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/src/display/Viewport.js b/src/display/Viewport.js index a3823523..0562fd1e 100644 --- a/src/display/Viewport.js +++ b/src/display/Viewport.js @@ -9,7 +9,6 @@ const ComposedViewport = mixins(Viewport, Base, Childrenable); export default class BaseViewport extends ComposedViewport { constructor(options) { super({ type: 'canvas', ...options }); - Object.assign(this.context, { viewport: this }); } apply(changes, options) { diff --git a/src/init.js b/src/init.js index fd3000de..73885a82 100644 --- a/src/init.js +++ b/src/init.js @@ -71,6 +71,7 @@ export const initViewport = (app, opts = {}, context) => { opts, ); const viewport = new BaseViewport({ ...options, context }); + context.viewport = viewport; viewport.app = app; viewport.events = {}; viewport.plugin = {