[FEAT] UI context menu streamline

This commit is contained in:
2026-01-07 16:13:21 +01:00
parent ad28f6a607
commit f9635ba044
6 changed files with 442 additions and 298 deletions

390
package-lock.json generated
View File

@@ -1390,9 +1390,9 @@
}
},
"node_modules/@rollup/rollup-android-arm-eabi": {
"version": "4.54.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.54.0.tgz",
"integrity": "sha512-OywsdRHrFvCdvsewAInDKCNyR3laPA2mc9bRYJ6LBp5IyvF3fvXbbNR0bSzHlZVFtn6E0xw2oZlyjg4rKCVcng==",
"version": "4.55.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.55.1.tgz",
"integrity": "sha512-9R0DM/ykwfGIlNu6+2U09ga0WXeZ9MRC2Ter8jnz8415VbuIykVuc6bhdrbORFZANDmTDvq26mJrEVTl8TdnDg==",
"cpu": [
"arm"
],
@@ -1403,9 +1403,9 @@
]
},
"node_modules/@rollup/rollup-android-arm64": {
"version": "4.54.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.54.0.tgz",
"integrity": "sha512-Skx39Uv+u7H224Af+bDgNinitlmHyQX1K/atIA32JP3JQw6hVODX5tkbi2zof/E69M1qH2UoN3Xdxgs90mmNYw==",
"version": "4.55.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.55.1.tgz",
"integrity": "sha512-eFZCb1YUqhTysgW3sj/55du5cG57S7UTNtdMjCW7LwVcj3dTTcowCsC8p7uBdzKsZYa8J7IDE8lhMI+HX1vQvg==",
"cpu": [
"arm64"
],
@@ -1416,9 +1416,9 @@
]
},
"node_modules/@rollup/rollup-darwin-arm64": {
"version": "4.54.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.54.0.tgz",
"integrity": "sha512-k43D4qta/+6Fq+nCDhhv9yP2HdeKeP56QrUUTW7E6PhZP1US6NDqpJj4MY0jBHlJivVJD5P8NxrjuobZBJTCRw==",
"version": "4.55.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.55.1.tgz",
"integrity": "sha512-p3grE2PHcQm2e8PSGZdzIhCKbMCw/xi9XvMPErPhwO17vxtvCN5FEA2mSLgmKlCjHGMQTP6phuQTYWUnKewwGg==",
"cpu": [
"arm64"
],
@@ -1429,9 +1429,9 @@
]
},
"node_modules/@rollup/rollup-darwin-x64": {
"version": "4.54.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.54.0.tgz",
"integrity": "sha512-cOo7biqwkpawslEfox5Vs8/qj83M/aZCSSNIWpVzfU2CYHa2G3P1UN5WF01RdTHSgCkri7XOlTdtk17BezlV3A==",
"version": "4.55.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.55.1.tgz",
"integrity": "sha512-rDUjG25C9qoTm+e02Esi+aqTKSBYwVTaoS1wxcN47/Luqef57Vgp96xNANwt5npq9GDxsH7kXxNkJVEsWEOEaQ==",
"cpu": [
"x64"
],
@@ -1442,9 +1442,9 @@
]
},
"node_modules/@rollup/rollup-freebsd-arm64": {
"version": "4.54.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.54.0.tgz",
"integrity": "sha512-miSvuFkmvFbgJ1BevMa4CPCFt5MPGw094knM64W9I0giUIMMmRYcGW/JWZDriaw/k1kOBtsWh1z6nIFV1vPNtA==",
"version": "4.55.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.55.1.tgz",
"integrity": "sha512-+JiU7Jbp5cdxekIgdte0jfcu5oqw4GCKr6i3PJTlXTCU5H5Fvtkpbs4XJHRmWNXF+hKmn4v7ogI5OQPaupJgOg==",
"cpu": [
"arm64"
],
@@ -1455,9 +1455,9 @@
]
},
"node_modules/@rollup/rollup-freebsd-x64": {
"version": "4.54.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.54.0.tgz",
"integrity": "sha512-KGXIs55+b/ZfZsq9aR026tmr/+7tq6VG6MsnrvF4H8VhwflTIuYh+LFUlIsRdQSgrgmtM3fVATzEAj4hBQlaqQ==",
"version": "4.55.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.55.1.tgz",
"integrity": "sha512-V5xC1tOVWtLLmr3YUk2f6EJK4qksksOYiz/TCsFHu/R+woubcLWdC9nZQmwjOAbmExBIVKsm1/wKmEy4z4u4Bw==",
"cpu": [
"x64"
],
@@ -1468,9 +1468,9 @@
]
},
"node_modules/@rollup/rollup-linux-arm-gnueabihf": {
"version": "4.54.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.54.0.tgz",
"integrity": "sha512-EHMUcDwhtdRGlXZsGSIuXSYwD5kOT9NVnx9sqzYiwAc91wfYOE1g1djOEDseZJKKqtHAHGwnGPQu3kytmfaXLQ==",
"version": "4.55.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.55.1.tgz",
"integrity": "sha512-Rn3n+FUk2J5VWx+ywrG/HGPTD9jXNbicRtTM11e/uorplArnXZYsVifnPPqNNP5BsO3roI4n8332ukpY/zN7rQ==",
"cpu": [
"arm"
],
@@ -1481,9 +1481,9 @@
]
},
"node_modules/@rollup/rollup-linux-arm-musleabihf": {
"version": "4.54.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.54.0.tgz",
"integrity": "sha512-+pBrqEjaakN2ySv5RVrj/qLytYhPKEUwk+e3SFU5jTLHIcAtqh2rLrd/OkbNuHJpsBgxsD8ccJt5ga/SeG0JmA==",
"version": "4.55.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.55.1.tgz",
"integrity": "sha512-grPNWydeKtc1aEdrJDWk4opD7nFtQbMmV7769hiAaYyUKCT1faPRm2av8CX1YJsZ4TLAZcg9gTR1KvEzoLjXkg==",
"cpu": [
"arm"
],
@@ -1494,9 +1494,9 @@
]
},
"node_modules/@rollup/rollup-linux-arm64-gnu": {
"version": "4.54.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.54.0.tgz",
"integrity": "sha512-NSqc7rE9wuUaRBsBp5ckQ5CVz5aIRKCwsoa6WMF7G01sX3/qHUw/z4pv+D+ahL1EIKy6Enpcnz1RY8pf7bjwng==",
"version": "4.55.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.55.1.tgz",
"integrity": "sha512-a59mwd1k6x8tXKcUxSyISiquLwB5pX+fJW9TkWU46lCqD/GRDe9uDN31jrMmVP3feI3mhAdvcCClhV8V5MhJFQ==",
"cpu": [
"arm64"
],
@@ -1507,9 +1507,9 @@
]
},
"node_modules/@rollup/rollup-linux-arm64-musl": {
"version": "4.54.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.54.0.tgz",
"integrity": "sha512-gr5vDbg3Bakga5kbdpqx81m2n9IX8M6gIMlQQIXiLTNeQW6CucvuInJ91EuCJ/JYvc+rcLLsDFcfAD1K7fMofg==",
"version": "4.55.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.55.1.tgz",
"integrity": "sha512-puS1MEgWX5GsHSoiAsF0TYrpomdvkaXm0CofIMG5uVkP6IBV+ZO9xhC5YEN49nsgYo1DuuMquF9+7EDBVYu4uA==",
"cpu": [
"arm64"
],
@@ -1520,9 +1520,22 @@
]
},
"node_modules/@rollup/rollup-linux-loong64-gnu": {
"version": "4.54.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.54.0.tgz",
"integrity": "sha512-gsrtB1NA3ZYj2vq0Rzkylo9ylCtW/PhpLEivlgWe0bpgtX5+9j9EZa0wtZiCjgu6zmSeZWyI/e2YRX1URozpIw==",
"version": "4.55.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.55.1.tgz",
"integrity": "sha512-r3Wv40in+lTsULSb6nnoudVbARdOwb2u5fpeoOAZjFLznp6tDU8kd+GTHmJoqZ9lt6/Sys33KdIHUaQihFcu7g==",
"cpu": [
"loong64"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-loong64-musl": {
"version": "4.55.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.55.1.tgz",
"integrity": "sha512-MR8c0+UxAlB22Fq4R+aQSPBayvYa3+9DrwG/i1TKQXFYEaoW3B5b/rkSRIypcZDdWjWnpcvxbNaAJDcSbJU3Lw==",
"cpu": [
"loong64"
],
@@ -1533,9 +1546,22 @@
]
},
"node_modules/@rollup/rollup-linux-ppc64-gnu": {
"version": "4.54.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.54.0.tgz",
"integrity": "sha512-y3qNOfTBStmFNq+t4s7Tmc9hW2ENtPg8FeUD/VShI7rKxNW7O4fFeaYbMsd3tpFlIg1Q8IapFgy7Q9i2BqeBvA==",
"version": "4.55.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.55.1.tgz",
"integrity": "sha512-3KhoECe1BRlSYpMTeVrD4sh2Pw2xgt4jzNSZIIPLFEsnQn9gAnZagW9+VqDqAHgm1Xc77LzJOo2LdigS5qZ+gw==",
"cpu": [
"ppc64"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-ppc64-musl": {
"version": "4.55.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.55.1.tgz",
"integrity": "sha512-ziR1OuZx0vdYZZ30vueNZTg73alF59DicYrPViG0NEgDVN8/Jl87zkAPu4u6VjZST2llgEUjaiNl9JM6HH1Vdw==",
"cpu": [
"ppc64"
],
@@ -1546,9 +1572,9 @@
]
},
"node_modules/@rollup/rollup-linux-riscv64-gnu": {
"version": "4.54.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.54.0.tgz",
"integrity": "sha512-89sepv7h2lIVPsFma8iwmccN7Yjjtgz0Rj/Ou6fEqg3HDhpCa+Et+YSufy27i6b0Wav69Qv4WBNl3Rs6pwhebQ==",
"version": "4.55.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.55.1.tgz",
"integrity": "sha512-uW0Y12ih2XJRERZ4jAfKamTyIHVMPQnTZcQjme2HMVDAHY4amf5u414OqNYC+x+LzRdRcnIG1YodLrrtA8xsxw==",
"cpu": [
"riscv64"
],
@@ -1559,9 +1585,9 @@
]
},
"node_modules/@rollup/rollup-linux-riscv64-musl": {
"version": "4.54.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.54.0.tgz",
"integrity": "sha512-ZcU77ieh0M2Q8Ur7D5X7KvK+UxbXeDHwiOt/CPSBTI1fBmeDMivW0dPkdqkT4rOgDjrDDBUed9x4EgraIKoR2A==",
"version": "4.55.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.55.1.tgz",
"integrity": "sha512-u9yZ0jUkOED1BFrqu3BwMQoixvGHGZ+JhJNkNKY/hyoEgOwlqKb62qu+7UjbPSHYjiVy8kKJHvXKv5coH4wDeg==",
"cpu": [
"riscv64"
],
@@ -1572,9 +1598,9 @@
]
},
"node_modules/@rollup/rollup-linux-s390x-gnu": {
"version": "4.54.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.54.0.tgz",
"integrity": "sha512-2AdWy5RdDF5+4YfG/YesGDDtbyJlC9LHmL6rZw6FurBJ5n4vFGupsOBGfwMRjBYH7qRQowT8D/U4LoSvVwOhSQ==",
"version": "4.55.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.55.1.tgz",
"integrity": "sha512-/0PenBCmqM4ZUd0190j7J0UsQ/1nsi735iPRakO8iPciE7BQ495Y6msPzaOmvx0/pn+eJVVlZrNrSh4WSYLxNg==",
"cpu": [
"s390x"
],
@@ -1585,9 +1611,9 @@
]
},
"node_modules/@rollup/rollup-linux-x64-gnu": {
"version": "4.54.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.54.0.tgz",
"integrity": "sha512-WGt5J8Ij/rvyqpFexxk3ffKqqbLf9AqrTBbWDk7ApGUzaIs6V+s2s84kAxklFwmMF/vBNGrVdYgbblCOFFezMQ==",
"version": "4.55.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.55.1.tgz",
"integrity": "sha512-a8G4wiQxQG2BAvo+gU6XrReRRqj+pLS2NGXKm8io19goR+K8lw269eTrPkSdDTALwMmJp4th2Uh0D8J9bEV1vg==",
"cpu": [
"x64"
],
@@ -1598,9 +1624,9 @@
]
},
"node_modules/@rollup/rollup-linux-x64-musl": {
"version": "4.54.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.54.0.tgz",
"integrity": "sha512-JzQmb38ATzHjxlPHuTH6tE7ojnMKM2kYNzt44LO/jJi8BpceEC8QuXYA908n8r3CNuG/B3BV8VR3Hi1rYtmPiw==",
"version": "4.55.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.55.1.tgz",
"integrity": "sha512-bD+zjpFrMpP/hqkfEcnjXWHMw5BIghGisOKPj+2NaNDuVT+8Ds4mPf3XcPHuat1tz89WRL+1wbcxKY3WSbiT7w==",
"cpu": [
"x64"
],
@@ -1610,10 +1636,23 @@
"linux"
]
},
"node_modules/@rollup/rollup-openbsd-x64": {
"version": "4.55.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.55.1.tgz",
"integrity": "sha512-eLXw0dOiqE4QmvikfQ6yjgkg/xDM+MdU9YJuP4ySTibXU0oAvnEWXt7UDJmD4UkYialMfOGFPJnIHSe/kdzPxg==",
"cpu": [
"x64"
],
"license": "MIT",
"optional": true,
"os": [
"openbsd"
]
},
"node_modules/@rollup/rollup-openharmony-arm64": {
"version": "4.54.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.54.0.tgz",
"integrity": "sha512-huT3fd0iC7jigGh7n3q/+lfPcXxBi+om/Rs3yiFxjvSxbSB6aohDFXbWvlspaqjeOh+hx7DDHS+5Es5qRkWkZg==",
"version": "4.55.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.55.1.tgz",
"integrity": "sha512-xzm44KgEP11te3S2HCSyYf5zIzWmx3n8HDCc7EE59+lTcswEWNpvMLfd9uJvVX8LCg9QWG67Xt75AuHn4vgsXw==",
"cpu": [
"arm64"
],
@@ -1624,9 +1663,9 @@
]
},
"node_modules/@rollup/rollup-win32-arm64-msvc": {
"version": "4.54.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.54.0.tgz",
"integrity": "sha512-c2V0W1bsKIKfbLMBu/WGBz6Yci8nJ/ZJdheE0EwB73N3MvHYKiKGs3mVilX4Gs70eGeDaMqEob25Tw2Gb9Nqyw==",
"version": "4.55.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.55.1.tgz",
"integrity": "sha512-yR6Bl3tMC/gBok5cz/Qi0xYnVbIxGx5Fcf/ca0eB6/6JwOY+SRUcJfI0OpeTpPls7f194as62thCt/2BjxYN8g==",
"cpu": [
"arm64"
],
@@ -1637,9 +1676,9 @@
]
},
"node_modules/@rollup/rollup-win32-ia32-msvc": {
"version": "4.54.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.54.0.tgz",
"integrity": "sha512-woEHgqQqDCkAzrDhvDipnSirm5vxUXtSKDYTVpZG3nUdW/VVB5VdCYA2iReSj/u3yCZzXID4kuKG7OynPnB3WQ==",
"version": "4.55.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.55.1.tgz",
"integrity": "sha512-3fZBidchE0eY0oFZBnekYCfg+5wAB0mbpCBuofh5mZuzIU/4jIVkbESmd2dOsFNS78b53CYv3OAtwqkZZmU5nA==",
"cpu": [
"ia32"
],
@@ -1650,9 +1689,9 @@
]
},
"node_modules/@rollup/rollup-win32-x64-gnu": {
"version": "4.54.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.54.0.tgz",
"integrity": "sha512-dzAc53LOuFvHwbCEOS0rPbXp6SIhAf2txMP5p6mGyOXXw5mWY8NGGbPMPrs4P1WItkfApDathBj/NzMLUZ9rtQ==",
"version": "4.55.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.55.1.tgz",
"integrity": "sha512-xGGY5pXj69IxKb4yv/POoocPy/qmEGhimy/FoTpTSVju3FYXUQQMFCaZZXJVidsmGxRioZAwpThl/4zX41gRKg==",
"cpu": [
"x64"
],
@@ -1663,9 +1702,9 @@
]
},
"node_modules/@rollup/rollup-win32-x64-msvc": {
"version": "4.54.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.54.0.tgz",
"integrity": "sha512-hYT5d3YNdSh3mbCU1gwQyPgQd3T2ne0A3KG8KSBdav5TiBg6eInVmV+TeR5uHufiIgSFg0XsOWGW5/RhNcSvPg==",
"version": "4.55.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.55.1.tgz",
"integrity": "sha512-SPEpaL6DX4rmcXtnhdrQYgzQ5W2uW3SCJch88lB2zImhJRhIIK44fkUrgIV/Q8yUNfw5oyZ5vkeQsZLhCb06lw==",
"cpu": [
"x64"
],
@@ -2505,9 +2544,9 @@
"license": "MIT"
},
"node_modules/baseline-browser-mapping": {
"version": "2.9.11",
"resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.11.tgz",
"integrity": "sha512-Sg0xJUNDU1sJNGdfGWhVHX0kkZ+HWcvmVymJbj6NSgZZmW/8S9Y2HQ5euytnIgakgxN6papOAWiwDo1ctFDcoQ==",
"version": "2.9.12",
"resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.12.tgz",
"integrity": "sha512-Mij6Lij93pTAIsSYy5cyBQ975Qh9uLEc5rwGTpomiZeXZL9yIS6uORJakb3ScHgfs0serMMfIbXzokPMuEiRyw==",
"dev": true,
"license": "Apache-2.0",
"bin": {
@@ -4181,9 +4220,9 @@
"license": "MIT"
},
"node_modules/rollup": {
"version": "4.54.0",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.54.0.tgz",
"integrity": "sha512-3nk8Y3a9Ea8szgKhinMlGMhGMw89mqule3KWczxhIzqudyHdCIOHw8WJlj/r329fACjKLEh13ZSk7oE22kyeIw==",
"version": "4.55.1",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.55.1.tgz",
"integrity": "sha512-wDv/Ht1BNHB4upNbK74s9usvl7hObDnvVzknxqY/E/O3X6rW1U1rV1aENEfJ54eFZDTNo7zv1f5N4edCluH7+A==",
"license": "MIT",
"dependencies": {
"@types/estree": "1.0.8"
@@ -4196,28 +4235,31 @@
"npm": ">=8.0.0"
},
"optionalDependencies": {
"@rollup/rollup-android-arm-eabi": "4.54.0",
"@rollup/rollup-android-arm64": "4.54.0",
"@rollup/rollup-darwin-arm64": "4.54.0",
"@rollup/rollup-darwin-x64": "4.54.0",
"@rollup/rollup-freebsd-arm64": "4.54.0",
"@rollup/rollup-freebsd-x64": "4.54.0",
"@rollup/rollup-linux-arm-gnueabihf": "4.54.0",
"@rollup/rollup-linux-arm-musleabihf": "4.54.0",
"@rollup/rollup-linux-arm64-gnu": "4.54.0",
"@rollup/rollup-linux-arm64-musl": "4.54.0",
"@rollup/rollup-linux-loong64-gnu": "4.54.0",
"@rollup/rollup-linux-ppc64-gnu": "4.54.0",
"@rollup/rollup-linux-riscv64-gnu": "4.54.0",
"@rollup/rollup-linux-riscv64-musl": "4.54.0",
"@rollup/rollup-linux-s390x-gnu": "4.54.0",
"@rollup/rollup-linux-x64-gnu": "4.54.0",
"@rollup/rollup-linux-x64-musl": "4.54.0",
"@rollup/rollup-openharmony-arm64": "4.54.0",
"@rollup/rollup-win32-arm64-msvc": "4.54.0",
"@rollup/rollup-win32-ia32-msvc": "4.54.0",
"@rollup/rollup-win32-x64-gnu": "4.54.0",
"@rollup/rollup-win32-x64-msvc": "4.54.0",
"@rollup/rollup-android-arm-eabi": "4.55.1",
"@rollup/rollup-android-arm64": "4.55.1",
"@rollup/rollup-darwin-arm64": "4.55.1",
"@rollup/rollup-darwin-x64": "4.55.1",
"@rollup/rollup-freebsd-arm64": "4.55.1",
"@rollup/rollup-freebsd-x64": "4.55.1",
"@rollup/rollup-linux-arm-gnueabihf": "4.55.1",
"@rollup/rollup-linux-arm-musleabihf": "4.55.1",
"@rollup/rollup-linux-arm64-gnu": "4.55.1",
"@rollup/rollup-linux-arm64-musl": "4.55.1",
"@rollup/rollup-linux-loong64-gnu": "4.55.1",
"@rollup/rollup-linux-loong64-musl": "4.55.1",
"@rollup/rollup-linux-ppc64-gnu": "4.55.1",
"@rollup/rollup-linux-ppc64-musl": "4.55.1",
"@rollup/rollup-linux-riscv64-gnu": "4.55.1",
"@rollup/rollup-linux-riscv64-musl": "4.55.1",
"@rollup/rollup-linux-s390x-gnu": "4.55.1",
"@rollup/rollup-linux-x64-gnu": "4.55.1",
"@rollup/rollup-linux-x64-musl": "4.55.1",
"@rollup/rollup-openbsd-x64": "4.55.1",
"@rollup/rollup-openharmony-arm64": "4.55.1",
"@rollup/rollup-win32-arm64-msvc": "4.55.1",
"@rollup/rollup-win32-ia32-msvc": "4.55.1",
"@rollup/rollup-win32-x64-gnu": "4.55.1",
"@rollup/rollup-win32-x64-msvc": "4.55.1",
"fsevents": "~2.3.2"
}
},
@@ -4251,9 +4293,9 @@
"license": "MIT"
},
"node_modules/sass": {
"version": "1.97.1",
"resolved": "https://registry.npmjs.org/sass/-/sass-1.97.1.tgz",
"integrity": "sha512-uf6HoO8fy6ClsrShvMgaKUn14f2EHQLQRtpsZZLeU/Mv0Q1K5P0+x2uvH6Cub39TVVbWNSrraUhDAoFph6vh0A==",
"version": "1.97.2",
"resolved": "https://registry.npmjs.org/sass/-/sass-1.97.2.tgz",
"integrity": "sha512-y5LWb0IlbO4e97Zr7c3mlpabcbBtS+ieiZ9iwDooShpFKWXf62zz5pEPdwrLYm+Bxn1fnbwFGzHuCLSA9tBmrw==",
"license": "MIT",
"optional": true,
"dependencies": {
@@ -4272,9 +4314,9 @@
}
},
"node_modules/sass-embedded": {
"version": "1.97.1",
"resolved": "https://registry.npmjs.org/sass-embedded/-/sass-embedded-1.97.1.tgz",
"integrity": "sha512-wH3CbOThHYGX0bUyqFf7laLKyhVWIFc2lHynitkqMIUCtX2ixH9mQh0bN7+hkUu5BFt/SXvEMjFbkEbBMpQiSQ==",
"version": "1.97.2",
"resolved": "https://registry.npmjs.org/sass-embedded/-/sass-embedded-1.97.2.tgz",
"integrity": "sha512-lKJcskySwAtJ4QRirKrikrWMFa2niAuaGenY2ElHjd55IwHUiur5IdKu6R1hEmGYMs4Qm+6rlRW0RvuAkmcryg==",
"devOptional": true,
"license": "MIT",
"dependencies": {
@@ -4294,30 +4336,30 @@
"node": ">=16.0.0"
},
"optionalDependencies": {
"sass-embedded-all-unknown": "1.97.1",
"sass-embedded-android-arm": "1.97.1",
"sass-embedded-android-arm64": "1.97.1",
"sass-embedded-android-riscv64": "1.97.1",
"sass-embedded-android-x64": "1.97.1",
"sass-embedded-darwin-arm64": "1.97.1",
"sass-embedded-darwin-x64": "1.97.1",
"sass-embedded-linux-arm": "1.97.1",
"sass-embedded-linux-arm64": "1.97.1",
"sass-embedded-linux-musl-arm": "1.97.1",
"sass-embedded-linux-musl-arm64": "1.97.1",
"sass-embedded-linux-musl-riscv64": "1.97.1",
"sass-embedded-linux-musl-x64": "1.97.1",
"sass-embedded-linux-riscv64": "1.97.1",
"sass-embedded-linux-x64": "1.97.1",
"sass-embedded-unknown-all": "1.97.1",
"sass-embedded-win32-arm64": "1.97.1",
"sass-embedded-win32-x64": "1.97.1"
"sass-embedded-all-unknown": "1.97.2",
"sass-embedded-android-arm": "1.97.2",
"sass-embedded-android-arm64": "1.97.2",
"sass-embedded-android-riscv64": "1.97.2",
"sass-embedded-android-x64": "1.97.2",
"sass-embedded-darwin-arm64": "1.97.2",
"sass-embedded-darwin-x64": "1.97.2",
"sass-embedded-linux-arm": "1.97.2",
"sass-embedded-linux-arm64": "1.97.2",
"sass-embedded-linux-musl-arm": "1.97.2",
"sass-embedded-linux-musl-arm64": "1.97.2",
"sass-embedded-linux-musl-riscv64": "1.97.2",
"sass-embedded-linux-musl-x64": "1.97.2",
"sass-embedded-linux-riscv64": "1.97.2",
"sass-embedded-linux-x64": "1.97.2",
"sass-embedded-unknown-all": "1.97.2",
"sass-embedded-win32-arm64": "1.97.2",
"sass-embedded-win32-x64": "1.97.2"
}
},
"node_modules/sass-embedded-all-unknown": {
"version": "1.97.1",
"resolved": "https://registry.npmjs.org/sass-embedded-all-unknown/-/sass-embedded-all-unknown-1.97.1.tgz",
"integrity": "sha512-0au5gUNibfob7W/g+ycBx74O22CL8vwHiZdEDY6J0uzMkHPiSJk//h0iRf5AUnMArFHJjFd3urIiQIaoRKYa1Q==",
"version": "1.97.2",
"resolved": "https://registry.npmjs.org/sass-embedded-all-unknown/-/sass-embedded-all-unknown-1.97.2.tgz",
"integrity": "sha512-Fj75+vOIDv1T/dGDwEpQ5hgjXxa2SmMeShPa8yrh2sUz1U44bbmY4YSWPCdg8wb7LnwiY21B2KRFM+HF42yO4g==",
"cpu": [
"!arm",
"!arm64",
@@ -4327,13 +4369,13 @@
"license": "MIT",
"optional": true,
"dependencies": {
"sass": "1.97.1"
"sass": "1.97.2"
}
},
"node_modules/sass-embedded-android-arm": {
"version": "1.97.1",
"resolved": "https://registry.npmjs.org/sass-embedded-android-arm/-/sass-embedded-android-arm-1.97.1.tgz",
"integrity": "sha512-B5dlv4utJ+yC8ZpBeWTHwSZPVKRlqA8pcaD0FAzeNm/DelIFgQUQtt0UwgYoAI6wDIiie5uSVpMK9l2DaCbiBQ==",
"version": "1.97.2",
"resolved": "https://registry.npmjs.org/sass-embedded-android-arm/-/sass-embedded-android-arm-1.97.2.tgz",
"integrity": "sha512-BPT9m19ttY0QVHYYXRa6bmqmS3Fa2EHByNUEtSVcbm5PkIk1ntmYkG9fn5SJpIMbNmFDGwHx+pfcZMmkldhnRg==",
"cpu": [
"arm"
],
@@ -4347,9 +4389,9 @@
}
},
"node_modules/sass-embedded-android-arm64": {
"version": "1.97.1",
"resolved": "https://registry.npmjs.org/sass-embedded-android-arm64/-/sass-embedded-android-arm64-1.97.1.tgz",
"integrity": "sha512-h62DmOiS2Jn87s8+8GhJcMerJnTKa1IsIa9iIKjLiqbAvBDKCGUs027RugZkM+Zx7I+vhPq86PUXBYZ9EkRxdw==",
"version": "1.97.2",
"resolved": "https://registry.npmjs.org/sass-embedded-android-arm64/-/sass-embedded-android-arm64-1.97.2.tgz",
"integrity": "sha512-pF6I+R5uThrscd3lo9B3DyNTPyGFsopycdx0tDAESN6s+dBbiRgNgE4Zlpv50GsLocj/lDLCZaabeTpL3ubhYA==",
"cpu": [
"arm64"
],
@@ -4363,9 +4405,9 @@
}
},
"node_modules/sass-embedded-android-riscv64": {
"version": "1.97.1",
"resolved": "https://registry.npmjs.org/sass-embedded-android-riscv64/-/sass-embedded-android-riscv64-1.97.1.tgz",
"integrity": "sha512-tGup88vgaXPnUHEgDMujrt5rfYadvkiVjRb/45FJTx2hQFoGVbmUXz5XqUFjIIbEjQ3kAJqp86A2jy11s43UiQ==",
"version": "1.97.2",
"resolved": "https://registry.npmjs.org/sass-embedded-android-riscv64/-/sass-embedded-android-riscv64-1.97.2.tgz",
"integrity": "sha512-fprI8ZTJdz+STgARhg8zReI2QhhGIT9G8nS7H21kc3IkqPRzhfaemSxEtCqZyvDbXPcgYiDLV7AGIReHCuATog==",
"cpu": [
"riscv64"
],
@@ -4379,9 +4421,9 @@
}
},
"node_modules/sass-embedded-android-x64": {
"version": "1.97.1",
"resolved": "https://registry.npmjs.org/sass-embedded-android-x64/-/sass-embedded-android-x64-1.97.1.tgz",
"integrity": "sha512-CAzKjjzu90LZduye2O9+UGX1oScMyF5/RVOa5CxACKALeIS+3XL3LVdV47kwKPoBv5B1aFUvGLscY0CR7jBAbg==",
"version": "1.97.2",
"resolved": "https://registry.npmjs.org/sass-embedded-android-x64/-/sass-embedded-android-x64-1.97.2.tgz",
"integrity": "sha512-RswwSjURZxupsukEmNt2t6RGvuvIw3IAD5sDq1Pc65JFvWFY3eHqCmH0lG0oXqMg6KJcF0eOxHOp2RfmIm2+4w==",
"cpu": [
"x64"
],
@@ -4395,9 +4437,9 @@
}
},
"node_modules/sass-embedded-darwin-arm64": {
"version": "1.97.1",
"resolved": "https://registry.npmjs.org/sass-embedded-darwin-arm64/-/sass-embedded-darwin-arm64-1.97.1.tgz",
"integrity": "sha512-tyDzspzh5PbqdAFGtVKUXuf0up6Lff3c1U8J7+4Y7jW6AWRBnq95vTzIIxfnNifGCTI2fW5e7GAZpYygKpNwcw==",
"version": "1.97.2",
"resolved": "https://registry.npmjs.org/sass-embedded-darwin-arm64/-/sass-embedded-darwin-arm64-1.97.2.tgz",
"integrity": "sha512-xcsZNnU1XZh21RE/71OOwNqPVcGBU0qT9A4k4QirdA34+ts9cDIaR6W6lgHOBR/Bnnu6w6hXJR4Xth7oFrefPA==",
"cpu": [
"arm64"
],
@@ -4411,9 +4453,9 @@
}
},
"node_modules/sass-embedded-darwin-x64": {
"version": "1.97.1",
"resolved": "https://registry.npmjs.org/sass-embedded-darwin-x64/-/sass-embedded-darwin-x64-1.97.1.tgz",
"integrity": "sha512-FMrRuSPI2ICt2M2SYaLbiG4yxn86D6ae+XtrRdrrBMhWprAcB7Iyu67bgRzZkipMZNIKKeTR7EUvJHgZzi5ixQ==",
"version": "1.97.2",
"resolved": "https://registry.npmjs.org/sass-embedded-darwin-x64/-/sass-embedded-darwin-x64-1.97.2.tgz",
"integrity": "sha512-T/9DTMpychm6+H4slHCAsYJRJ6eM+9H9idKlBPliPrP4T8JdC2Cs+ZOsYqrObj6eOtAD0fGf+KgyNhnW3xVafA==",
"cpu": [
"x64"
],
@@ -4427,9 +4469,9 @@
}
},
"node_modules/sass-embedded-linux-arm": {
"version": "1.97.1",
"resolved": "https://registry.npmjs.org/sass-embedded-linux-arm/-/sass-embedded-linux-arm-1.97.1.tgz",
"integrity": "sha512-48VxaTUApLyx1NXFdZhKqI/7FYLmz8Ju3Ki2V/p+mhn5raHgAiYeFgn8O1WGxTOh+hBb9y3FdSR5a8MNTbmKMQ==",
"version": "1.97.2",
"resolved": "https://registry.npmjs.org/sass-embedded-linux-arm/-/sass-embedded-linux-arm-1.97.2.tgz",
"integrity": "sha512-yDRe1yifGHl6kibkDlRIJ2ZzAU03KJ1AIvsAh4dsIDgK5jx83bxZLV1ZDUv7a8KK/iV/80LZnxnu/92zp99cXQ==",
"cpu": [
"arm"
],
@@ -4443,9 +4485,9 @@
}
},
"node_modules/sass-embedded-linux-arm64": {
"version": "1.97.1",
"resolved": "https://registry.npmjs.org/sass-embedded-linux-arm64/-/sass-embedded-linux-arm64-1.97.1.tgz",
"integrity": "sha512-im80gfDWRivw9Su3r3YaZmJaCATcJgu3CsCSLodPk1b1R2+X/E12zEQayvrl05EGT9PDwTtuiqKgS4ND4xjwVg==",
"version": "1.97.2",
"resolved": "https://registry.npmjs.org/sass-embedded-linux-arm64/-/sass-embedded-linux-arm64-1.97.2.tgz",
"integrity": "sha512-Wh+nQaFer9tyE5xBPv5murSUZE/+kIcg8MyL5uqww6be9Iq+UmZpcJM7LUk+q8klQ9LfTmoDSNFA74uBqxD6IA==",
"cpu": [
"arm64"
],
@@ -4459,9 +4501,9 @@
}
},
"node_modules/sass-embedded-linux-musl-arm": {
"version": "1.97.1",
"resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-arm/-/sass-embedded-linux-musl-arm-1.97.1.tgz",
"integrity": "sha512-FUFs466t3PVViVOKY/60JgLLtl61Pf7OW+g5BeEfuqVcSvYUECVHeiYHtX1fT78PEVa0h9tHpM6XpWti+7WYFA==",
"version": "1.97.2",
"resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-arm/-/sass-embedded-linux-musl-arm-1.97.2.tgz",
"integrity": "sha512-GIO6xfAtahJAWItvsXZ3MD1HM6s8cKtV1/HL088aUpKJaw/2XjTCveiOO2AdgMpLNztmq9DZ1lx5X5JjqhS45g==",
"cpu": [
"arm"
],
@@ -4475,9 +4517,9 @@
}
},
"node_modules/sass-embedded-linux-musl-arm64": {
"version": "1.97.1",
"resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-arm64/-/sass-embedded-linux-musl-arm64-1.97.1.tgz",
"integrity": "sha512-kD35WSD9o0279Ptwid3Jnbovo1FYnuG2mayYk9z4ZI4mweXEK6vTu+tlvCE/MdF/zFKSj11qaxaH+uzXe2cO5A==",
"version": "1.97.2",
"resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-arm64/-/sass-embedded-linux-musl-arm64-1.97.2.tgz",
"integrity": "sha512-NfUqZSjHwnHvpSa7nyNxbWfL5obDjNBqhHUYmqbHUcmqBpFfHIQsUPgXME9DKn1yBlBc3mWnzMxRoucdYTzd2Q==",
"cpu": [
"arm64"
],
@@ -4491,9 +4533,9 @@
}
},
"node_modules/sass-embedded-linux-musl-riscv64": {
"version": "1.97.1",
"resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-riscv64/-/sass-embedded-linux-musl-riscv64-1.97.1.tgz",
"integrity": "sha512-ZgpYps5YHuhA2+KiLkPukRbS5298QObgUhPll/gm5i0LOZleKCwrFELpVPcbhsSBuxqji2uaag5OL+n3JRBVVg==",
"version": "1.97.2",
"resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-riscv64/-/sass-embedded-linux-musl-riscv64-1.97.2.tgz",
"integrity": "sha512-qtM4dJ5gLfvyTZ3QencfNbsTEShIWImSEpkThz+Y2nsCMbcMP7/jYOA03UWgPfEOKSehQQ7EIau7ncbFNoDNPQ==",
"cpu": [
"riscv64"
],
@@ -4507,9 +4549,9 @@
}
},
"node_modules/sass-embedded-linux-musl-x64": {
"version": "1.97.1",
"resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-x64/-/sass-embedded-linux-musl-x64-1.97.1.tgz",
"integrity": "sha512-wcAigOyyvZ6o1zVypWV7QLZqpOEVnlBqJr9MbpnRIm74qFTSbAEmShoh8yMXBymzuVSmEbThxAwW01/TLf62tA==",
"version": "1.97.2",
"resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-x64/-/sass-embedded-linux-musl-x64-1.97.2.tgz",
"integrity": "sha512-ZAxYOdmexcnxGnzdsDjYmNe3jGj+XW3/pF/n7e7r8y+5c6D2CQRrCUdapLgaqPt1edOPQIlQEZF8q5j6ng21yw==",
"cpu": [
"x64"
],
@@ -4523,9 +4565,9 @@
}
},
"node_modules/sass-embedded-linux-riscv64": {
"version": "1.97.1",
"resolved": "https://registry.npmjs.org/sass-embedded-linux-riscv64/-/sass-embedded-linux-riscv64-1.97.1.tgz",
"integrity": "sha512-9j1qE1ZrLMuGb+LUmBzw93Z4TNfqlRkkxjPVZy6u5vIggeSfvGbte7eRoYBNWX6SFew/yBCL90KXIirWFSGrlQ==",
"version": "1.97.2",
"resolved": "https://registry.npmjs.org/sass-embedded-linux-riscv64/-/sass-embedded-linux-riscv64-1.97.2.tgz",
"integrity": "sha512-reVwa9ZFEAOChXpDyNB3nNHHyAkPMD+FTctQKECqKiVJnIzv2EaFF6/t0wzyvPgBKeatA8jszAIeOkkOzbYVkQ==",
"cpu": [
"riscv64"
],
@@ -4539,9 +4581,9 @@
}
},
"node_modules/sass-embedded-linux-x64": {
"version": "1.97.1",
"resolved": "https://registry.npmjs.org/sass-embedded-linux-x64/-/sass-embedded-linux-x64-1.97.1.tgz",
"integrity": "sha512-7nrLFYMH/UgvEgXR5JxQJ6y9N4IJmnFnYoDxN0nw0jUp+CQWQL4EJ4RqAKTGelneueRbccvt2sEyPK+X0KJ9Jg==",
"version": "1.97.2",
"resolved": "https://registry.npmjs.org/sass-embedded-linux-x64/-/sass-embedded-linux-x64-1.97.2.tgz",
"integrity": "sha512-bvAdZQsX3jDBv6m4emaU2OMTpN0KndzTAMgJZZrKUgiC0qxBmBqbJG06Oj/lOCoXGCxAvUOheVYpezRTF+Feog==",
"cpu": [
"x64"
],
@@ -4555,9 +4597,9 @@
}
},
"node_modules/sass-embedded-unknown-all": {
"version": "1.97.1",
"resolved": "https://registry.npmjs.org/sass-embedded-unknown-all/-/sass-embedded-unknown-all-1.97.1.tgz",
"integrity": "sha512-oPSeKc7vS2dx3ZJHiUhHKcyqNq0GWzAiR8zMVpPd/kVMl5ZfVyw+5HTCxxWDBGkX02lNpou27JkeBPCaneYGAQ==",
"version": "1.97.2",
"resolved": "https://registry.npmjs.org/sass-embedded-unknown-all/-/sass-embedded-unknown-all-1.97.2.tgz",
"integrity": "sha512-86tcYwohjPgSZtgeU9K4LikrKBJNf8ZW/vfsFbdzsRlvc73IykiqanufwQi5qIul0YHuu9lZtDWyWxM2dH/Rsg==",
"license": "MIT",
"optional": true,
"os": [
@@ -4567,13 +4609,13 @@
"!win32"
],
"dependencies": {
"sass": "1.97.1"
"sass": "1.97.2"
}
},
"node_modules/sass-embedded-win32-arm64": {
"version": "1.97.1",
"resolved": "https://registry.npmjs.org/sass-embedded-win32-arm64/-/sass-embedded-win32-arm64-1.97.1.tgz",
"integrity": "sha512-L5j7J6CbZgHGwcfVedMVpM3z5MYeighcyZE8GF2DVmjWzZI3JtPKNY11wNTD/P9o1Uql10YPOKhGH0iWIXOT7Q==",
"version": "1.97.2",
"resolved": "https://registry.npmjs.org/sass-embedded-win32-arm64/-/sass-embedded-win32-arm64-1.97.2.tgz",
"integrity": "sha512-Cv28q8qNjAjZfqfzTrQvKf4JjsZ6EOQ5FxyHUQQeNzm73R86nd/8ozDa1Vmn79Hq0kwM15OCM9epanDuTG1ksA==",
"cpu": [
"arm64"
],
@@ -4587,9 +4629,9 @@
}
},
"node_modules/sass-embedded-win32-x64": {
"version": "1.97.1",
"resolved": "https://registry.npmjs.org/sass-embedded-win32-x64/-/sass-embedded-win32-x64-1.97.1.tgz",
"integrity": "sha512-rfaZAKXU8cW3E7gvdafyD6YtgbEcsDeT99OEiHXRT0UGFuXT8qCOjpAwIKaOA3XXr2d8S42xx6cXcaZ1a+1fgw==",
"version": "1.97.2",
"resolved": "https://registry.npmjs.org/sass-embedded-win32-x64/-/sass-embedded-win32-x64-1.97.2.tgz",
"integrity": "sha512-DVxLxkeDCGIYeyHLAvWW3yy9sy5Ruk5p472QWiyfyyG1G1ASAR8fgfIY5pT0vE6Rv+VAKVLwF3WTspUYu7S1/Q==",
"cpu": [
"x64"
],

View File

@@ -1,40 +1,19 @@
<template>
<Teleport to="body">
<div v-if="showContextMenu" @click.stop class="fixed bg-white dark:bg-gray-800 border border-gray-300 dark:border-gray-600 rounded-lg shadow-xl z-50 py-1 min-w-[160px] overflow-hidden" :style="{ left: contextMenuX + 'px', top: contextMenuY + 'px' }">
<button @click="addSprite" class="w-full px-3 py-1.5 text-left hover:bg-blue-50 dark:hover:bg-blue-900/30 text-gray-700 dark:text-gray-200 flex items-center gap-2 transition-colors text-sm">
<i class="fas fa-plus text-blue-600 dark:text-blue-400 text-xs w-4"></i>
<span>Add sprite</span>
</button>
<button v-if="contextMenuSpriteId" @click="rotateSpriteInMenu(90)" class="w-full px-3 py-1.5 text-left hover:bg-green-50 dark:hover:bg-green-900/30 text-gray-700 dark:text-gray-200 flex items-center gap-2 transition-colors text-sm">
<i class="fas fa-redo text-green-600 dark:text-green-400 text-xs w-4"></i>
<span>Rotate +90°</span>
</button>
<button v-if="contextMenuSpriteId" @click="flipSpriteInMenu('horizontal')" class="w-full px-3 py-1.5 text-left hover:bg-orange-50 dark:hover:bg-orange-900/30 text-gray-700 dark:text-gray-200 flex items-center gap-2 transition-colors text-sm">
<i class="fas fa-arrows-alt-h text-orange-600 dark:text-orange-400 text-xs w-4"></i>
<span>Flip horizontal</span>
</button>
<button v-if="contextMenuSpriteId" @click="flipSpriteInMenu('vertical')" class="w-full px-3 py-1.5 text-left hover:bg-orange-50 dark:hover:bg-orange-900/30 text-gray-700 dark:text-gray-200 flex items-center gap-2 transition-colors text-sm">
<i class="fas fa-arrows-alt-v text-orange-600 dark:text-orange-400 text-xs w-4"></i>
<span>Flip vertical</span>
</button>
<button v-if="contextMenuSpriteId" @click="replaceSprite" class="w-full px-3 py-1.5 text-left hover:bg-purple-50 dark:hover:bg-purple-900/30 text-gray-700 dark:text-gray-200 flex items-center gap-2 transition-colors text-sm">
<i class="fas fa-exchange-alt text-purple-600 dark:text-purple-400 text-xs w-4"></i>
<span>Replace sprite</span>
</button>
<button v-if="contextMenuSpriteId" @click="openCopyToFrameModal" class="w-full px-3 py-1.5 text-left hover:bg-cyan-50 dark:hover:bg-cyan-900/30 text-gray-700 dark:text-gray-200 flex items-center gap-2 transition-colors text-sm">
<i class="fas fa-copy text-cyan-600 dark:text-cyan-400 text-xs w-4"></i>
<span>Copy to frame...</span>
</button>
<button v-if="contextMenuSpriteId" @click="openPixelEditor" class="w-full px-3 py-1.5 text-left hover:bg-indigo-50 dark:hover:bg-indigo-900/30 text-gray-700 dark:text-gray-200 flex items-center gap-2 transition-colors text-sm">
<i class="fas fa-paint-brush text-indigo-600 dark:text-indigo-400 text-xs w-4"></i>
<span>Edit in Pixel Editor</span>
</button>
<div v-if="contextMenuSpriteId" class="h-px bg-gray-200 dark:bg-gray-600 my-1"></div>
<button v-if="contextMenuSpriteId" @click="removeSprite" class="w-full px-3 py-1.5 text-left hover:bg-red-50 dark:hover:bg-red-900/30 text-red-600 dark:text-red-400 flex items-center gap-2 transition-colors text-sm">
<i class="fas fa-trash text-xs w-4"></i>
<span>{{ selectedSpriteIds.size > 1 ? `Remove ${selectedSpriteIds.size} sprites` : 'Remove sprite' }}</span>
</button>
</div>
<SpriteContextMenu
:is-open="isContextMenuOpen"
:position="contextMenuPosition"
:has-sprite="!!contextMenuSpriteId"
:selected-count="selectedSpriteIds.size"
@add="addSpriteRefined"
@rotate="rotateSpriteInMenu"
@flip="flipSpriteInMenu"
@replace="replaceSprite"
@copy-to-frame="openCopyToFrameModal"
@edit-in-pixel-editor="openPixelEditor"
@remove="removeSprite"
@close="closeContextMenu"
/>
<!-- Copy to Frame Modal -->
<CopyToFrameModal :is-open="showCopyToFrameModal" :layers="props.layers" :initial-layer-id="copyTargetLayerId" @close="closeCopyToFrameModal" @copy="confirmCopyToFrame" />
@@ -60,7 +39,7 @@
@touchstart="handleTouchStart"
@touchmove="handleTouchMove"
@touchend="stopDrag"
@contextmenu.prevent
@contextmenu.prevent.stop
@dragover="handleDragOver"
@dragenter="handleDragEnter"
@dragleave="onDragLeave"
@@ -187,7 +166,7 @@
</div>
</div>
<input ref="fileInput" type="file" accept="image/*" class="hidden" @change="handleFileChange" />
<input ref="fileInput" type="file" accept="image/*" class="hidden" @change="handleFileChangeRefined" />
</div>
</template>
@@ -199,6 +178,8 @@
import { useFileDrop } from '@/composables/useFileDrop';
import { useGridMetrics } from '@/composables/useGridMetrics';
import { useBackgroundStyles } from '@/composables/useBackgroundStyles';
import { useContextMenu } from '@/composables/useContextMenu';
import SpriteContextMenu from '@/components/shared/SpriteContextMenu.vue';
import CopyToFrameModal from './utilities/CopyToFrameModal.vue';
import type { Layer } from '@/types/sprites';
@@ -289,11 +270,12 @@
onAddSpriteWithResize: file => emit('addSpriteWithResize', file),
});
const showContextMenu = ref(false);
const contextMenuX = ref(0);
const contextMenuY = ref(0);
const contextMenuIndex = ref<number | null>(null);
const contextMenuSpriteId = ref<string | null>(null);
const { isOpen: isContextMenuOpen, position: contextMenuPosition, contextData: contextMenuData, open: openContextMenuBase, close: closeContextMenu } = useContextMenu<{ spriteId?: string; layerId?: string; index?: number }>();
// Computed properties to access context data safely
const contextMenuSpriteId = computed(() => contextMenuData.value?.spriteId || null);
const contextMenuIndex = computed(() => contextMenuData.value?.index ?? null); // Use ?? to allow 0 index
const replacingSpriteId = ref<string | null>(null);
const fileInput = ref<HTMLInputElement | null>(null);
@@ -359,7 +341,7 @@
}
if (!gridContainerRef.value) return;
showContextMenu.value = false;
closeContextMenu();
if ('button' in event && (event as MouseEvent).button === 2) {
event.preventDefault();
@@ -367,8 +349,10 @@
if (!pos) return;
const clickedSprite = findSpriteAtPosition(pos.x, pos.y);
contextMenuIndex.value = findCellAtPosition(pos.x, pos.y)?.index ?? null;
contextMenuSpriteId.value = clickedSprite?.id || null;
const clickedCell = findCellAtPosition(pos.x, pos.y);
const cellIndex = clickedCell?.index ?? null;
const spriteId = clickedSprite?.id || undefined;
if (clickedSprite) {
if (!selectedSpriteIds.value.has(clickedSprite.id)) {
@@ -379,10 +363,10 @@
selectedSpriteIds.value.clear();
}
contextMenuX.value = event.clientX;
contextMenuY.value = event.clientY;
showContextMenu.value = true;
openContextMenuBase(event, {
spriteId: spriteId,
index: cellIndex !== null ? cellIndex : undefined,
});
return;
}
@@ -431,13 +415,12 @@
if (selectedSpriteIds.value.size > 0) {
emit('removeSprites', Array.from(selectedSpriteIds.value));
selectedSpriteIds.value.clear();
showContextMenu.value = false;
contextMenuSpriteId.value = null;
} else if (contextMenuSpriteId.value) {
emit('removeSprite', contextMenuSpriteId.value);
showContextMenu.value = false;
contextMenuSpriteId.value = null;
}
closeContextMenu();
// Note: SpriteContextMenu component will also emit 'close' after action if using emitAndClose,
// but duplicate close calls are harmless.
};
const rotateSpriteInMenu = (angle: number) => {
@@ -448,7 +431,7 @@
} else if (contextMenuSpriteId.value) {
emit('rotateSprite', contextMenuSpriteId.value, angle);
}
showContextMenu.value = false;
closeContextMenu();
};
const flipSpriteInMenu = (direction: 'horizontal' | 'vertical') => {
@@ -459,7 +442,7 @@
} else if (contextMenuSpriteId.value) {
emit('flipSprite', contextMenuSpriteId.value, direction);
}
showContextMenu.value = false;
closeContextMenu();
};
const handleKeyDown = (event: KeyboardEvent) => {
@@ -477,20 +460,29 @@
if (contextMenuSpriteId.value && fileInput.value) {
replacingSpriteId.value = contextMenuSpriteId.value;
fileInput.value.click();
showContextMenu.value = false;
contextMenuSpriteId.value = null;
closeContextMenu();
}
};
const addSprite = () => {
// Refined addSprite with index caching logic
const pendingAddIndex = ref<number | null>(null);
const addSpriteRefined = () => {
// Capture index
if (contextMenuIndex.value !== null) {
pendingAddIndex.value = contextMenuIndex.value;
} else {
pendingAddIndex.value = null;
}
if (fileInput.value) {
fileInput.value.click();
showContextMenu.value = false;
contextMenuSpriteId.value = null;
closeContextMenu();
}
};
const handleFileChange = (event: Event) => {
// Refined handleFileChange
const handleFileChangeRefined = (event: Event) => {
const input = event.target as HTMLInputElement;
if (input.files && input.files.length > 0) {
@@ -499,8 +491,8 @@
if (replacingSpriteId.value) {
emit('replaceSprite', replacingSpriteId.value, file);
} else {
if (contextMenuIndex.value !== null) {
emit('addSprite', file, contextMenuIndex.value);
if (pendingAddIndex.value !== null) {
emit('addSprite', file, pendingAddIndex.value);
} else {
emit('addSprite', file);
}
@@ -510,21 +502,16 @@
}
}
replacingSpriteId.value = null;
contextMenuIndex.value = null;
pendingAddIndex.value = null; // Clear it
input.value = '';
};
const hideContextMenu = () => {
showContextMenu.value = false;
contextMenuSpriteId.value = null;
};
const openCopyToFrameModal = () => {
if (contextMenuSpriteId.value) {
copySpriteId.value = contextMenuSpriteId.value;
copyTargetLayerId.value = props.activeLayerId;
showCopyToFrameModal.value = true;
showContextMenu.value = false;
closeContextMenu();
}
};
@@ -550,8 +537,7 @@
emit('openPixelEditor', props.activeLayerId, frameIndex);
}
}
showContextMenu.value = false;
contextMenuSpriteId.value = null;
closeContextMenu();
}
};

View File

@@ -1,37 +1,24 @@
<template>
<Teleport to="body">
<div v-if="showContextMenu" @click.stop class="fixed bg-white dark:bg-gray-800 border border-gray-300 dark:border-gray-600 rounded-lg shadow-xl z-50 py-1 min-w-[160px] overflow-hidden" :style="{ left: contextMenuX + 'px', top: contextMenuY + 'px' }">
<button @click="rotateSpriteInMenu(90)" class="w-full px-3 py-1.5 text-left hover:bg-green-50 dark:hover:bg-green-900/30 text-gray-700 dark:text-gray-200 flex items-center gap-2 transition-colors text-sm">
<i class="fas fa-redo text-green-600 dark:text-green-400 text-xs w-4"></i>
<span>Rotate +90°</span>
</button>
<button @click="flipSpriteInMenu('horizontal')" class="w-full px-3 py-1.5 text-left hover:bg-orange-50 dark:hover:bg-orange-900/30 text-gray-700 dark:text-gray-200 flex items-center gap-2 transition-colors text-sm">
<i class="fas fa-arrows-alt-h text-orange-600 dark:text-orange-400 text-xs w-4"></i>
<span>Flip Horizontal</span>
</button>
<button @click="flipSpriteInMenu('vertical')" class="w-full px-3 py-1.5 text-left hover:bg-orange-50 dark:hover:bg-orange-900/30 text-gray-700 dark:text-gray-200 flex items-center gap-2 transition-colors text-sm">
<i class="fas fa-arrows-alt-v text-orange-600 dark:text-orange-400 text-xs w-4"></i>
<span>Flip Vertical</span>
</button>
<button @click="replaceSprite" class="w-full px-3 py-1.5 text-left hover:bg-purple-50 dark:hover:bg-purple-900/30 text-gray-700 dark:text-gray-200 flex items-center gap-2 transition-colors text-sm">
<i class="fas fa-exchange-alt text-purple-600 dark:text-purple-400 text-xs w-4"></i>
<span>Replace Sprite</span>
</button>
<button @click="openCopyToFrameModal" class="w-full px-3 py-1.5 text-left hover:bg-cyan-50 dark:hover:bg-cyan-900/30 text-gray-700 dark:text-gray-200 flex items-center gap-2 transition-colors text-sm">
<i class="fas fa-copy text-cyan-600 dark:text-cyan-400 text-xs w-4"></i>
<span>Copy to Frame...</span>
</button>
<button @click="openPixelEditor" class="w-full px-3 py-1.5 text-left hover:bg-indigo-50 dark:hover:bg-indigo-900/30 text-gray-700 dark:text-gray-200 flex items-center gap-2 transition-colors text-sm">
<i class="fas fa-paint-brush text-indigo-600 dark:text-indigo-400 text-xs w-4"></i>
<span>Edit in Pixel Editor</span>
</button>
</div>
<SpriteContextMenu
:is-open="isContextMenuOpen"
:position="contextMenuPosition"
:has-sprite="!!contextMenuSpriteId"
@add="addSprite"
@rotate="rotateSpriteInMenu"
@flip="flipSpriteInMenu"
@replace="replaceSprite"
@copy-to-frame="openCopyToFrameModal"
@edit-in-pixel-editor="openPixelEditor"
@remove="removeSprite"
@close="closeContextMenu"
/>
<!-- Copy to Frame Modal -->
<CopyToFrameModal :is-open="showCopyToFrameModal" :layers="props.layers" :initial-layer-id="copyTargetLayerId" @close="closeCopyToFrameModal" @copy="confirmCopyToFrame" />
</Teleport>
<div class="spritesheet-preview w-full h-full" @click="hideContextMenu">
<div class="spritesheet-preview w-full h-full" @click="closeContextMenu">
<div class="flex flex-col lg:flex-row gap-4 h-full min-h-0">
<div class="flex-1 min-w-0 flex flex-col min-h-0">
<div
@@ -99,7 +86,7 @@
imageRendering: settingsStore.pixelPerfect ? 'pixelated' : 'auto',
transform: `rotate(${layer.sprites[currentFrameIndex].rotation || 0}deg) scale(${layer.sprites[currentFrameIndex].flipX ? -1 : 1}, ${layer.sprites[currentFrameIndex].flipY ? -1 : 1})`,
}"
@contextmenu.prevent="openContextMenu($event, layer.sprites[currentFrameIndex], layer.id)"
@contextmenu.prevent.stop="openContextMenu($event, layer.sprites[currentFrameIndex], layer.id)"
draggable="false"
/>
</template>
@@ -303,6 +290,8 @@
import { useAnimationFrames } from '@/composables/useAnimationFrames';
import { useGridMetrics } from '@/composables/useGridMetrics';
import { useBackgroundStyles } from '@/composables/useBackgroundStyles';
import { useContextMenu } from '@/composables/useContextMenu';
import SpriteContextMenu from '@/components/shared/SpriteContextMenu.vue';
import CopyToFrameModal from './utilities/CopyToFrameModal.vue';
const props = defineProps<{
@@ -319,6 +308,7 @@
(e: 'flipSprite', id: string, direction: 'horizontal' | 'vertical'): void;
(e: 'copySpriteToFrame', spriteId: string, targetLayerId: string, targetFrameIndex: number): void;
(e: 'replaceSprite', id: string, file: File): void;
(e: 'removeSprite', id: string): void;
(e: 'openPixelEditor', layerId: string, frameIndex: number): void;
}>();
@@ -368,11 +358,6 @@
const showAllSprites = ref(false);
const isDragOver = ref(false);
const showContextMenu = ref(false);
const contextMenuX = ref(0);
const contextMenuY = ref(0);
const contextMenuSpriteId = ref<string | null>(null);
const contextMenuLayerId = ref<string | null>(null);
const fileInput = ref<HTMLInputElement | null>(null);
const replacingSpriteId = ref<string | null>(null);
@@ -654,40 +639,34 @@
);
watch(currentFrameIndex, () => {});
/* Context Menu */
const { isOpen: isContextMenuOpen, position: contextMenuPosition, contextData: contextMenuData, open: openContextMenuBase, close: closeContextMenu } = useContextMenu<{ spriteId: string; layerId: string }>();
const openContextMenu = (event: MouseEvent, sprite: Sprite, layerId: string) => {
event.preventDefault();
contextMenuSpriteId.value = sprite.id;
contextMenuLayerId.value = layerId;
contextMenuX.value = event.clientX;
contextMenuY.value = event.clientY;
showContextMenu.value = true;
openContextMenuBase(event, { spriteId: sprite.id, layerId });
};
const hideContextMenu = () => {
showContextMenu.value = false;
contextMenuSpriteId.value = null;
contextMenuLayerId.value = null;
};
const contextMenuSpriteId = computed(() => contextMenuData.value?.spriteId || null);
const contextMenuLayerId = computed(() => contextMenuData.value?.layerId || null);
const rotateSpriteInMenu = (angle: number) => {
if (contextMenuSpriteId.value) {
emit('rotateSprite', contextMenuSpriteId.value, angle);
}
hideContextMenu();
// Context menu closes automatically via component emit
};
const flipSpriteInMenu = (direction: 'horizontal' | 'vertical') => {
if (contextMenuSpriteId.value) {
emit('flipSprite', contextMenuSpriteId.value, direction);
}
hideContextMenu();
};
const openCopyToFrameModal = () => {
if (contextMenuSpriteId.value) {
copyTargetLayerId.value = contextMenuLayerId.value || props.activeLayerId;
showCopyToFrameModal.value = true;
showContextMenu.value = false;
closeContextMenu();
}
};
@@ -699,15 +678,15 @@
if (contextMenuSpriteId.value) {
emit('copySpriteToFrame', contextMenuSpriteId.value, targetLayerId, targetFrameIndex);
closeCopyToFrameModal();
contextMenuSpriteId.value = null;
}
// We don't null contextMenuSpriteId here since it's computed now, but closing the menu does the trick effectively for the user flow.
};
const replaceSprite = () => {
if (contextMenuSpriteId.value && fileInput.value) {
replacingSpriteId.value = contextMenuSpriteId.value;
fileInput.value.click();
hideContextMenu();
closeContextMenu();
}
};
@@ -716,8 +695,13 @@
if (input.files && input.files.length > 0) {
const file = input.files[0];
if (file.type.startsWith('image/') && replacingSpriteId.value) {
if (file.type.startsWith('image/')) {
if (replacingSpriteId.value) {
emit('replaceSprite', replacingSpriteId.value, file);
} else {
// Add sprite case - use dropSprite emit as it handles adding files to layer/frame
emit('dropSprite', props.activeLayerId, currentFrameIndex.value, [file]);
}
}
}
replacingSpriteId.value = null;
@@ -727,7 +711,21 @@
const openPixelEditor = () => {
if (contextMenuSpriteId.value && contextMenuLayerId.value) {
emit('openPixelEditor', contextMenuLayerId.value, currentFrameIndex.value);
hideContextMenu();
closeContextMenu();
}
};
const addSprite = () => {
if (fileInput.value) {
replacingSpriteId.value = null;
fileInput.value.click();
closeContextMenu();
}
};
const removeSprite = () => {
if (contextMenuSpriteId.value) {
(emit as any)('removeSprite', contextMenuSpriteId.value);
closeContextMenu();
}
};
</script>

View File

@@ -0,0 +1,85 @@
<template>
<Teleport to="body">
<div v-if="isOpen" @click.stop class="fixed bg-white dark:bg-gray-800 border border-gray-300 dark:border-gray-600 rounded-lg shadow-xl z-50 py-1 min-w-[160px] overflow-hidden" :style="{ left: position.x + 'px', top: position.y + 'px' }">
<button @click="emit('add')" class="w-full px-3 py-1.5 text-left hover:bg-blue-50 dark:hover:bg-blue-900/30 text-gray-700 dark:text-gray-200 flex items-center gap-2 transition-colors text-sm">
<i class="fas fa-plus text-blue-600 dark:text-blue-400 text-xs w-4"></i>
<span>Add sprite</span>
</button>
<template v-if="hasSprite">
<button @click="emitAndClose('rotate', 90)" class="w-full px-3 py-1.5 text-left hover:bg-green-50 dark:hover:bg-green-900/30 text-gray-700 dark:text-gray-200 flex items-center gap-2 transition-colors text-sm">
<i class="fas fa-redo text-green-600 dark:text-green-400 text-xs w-4"></i>
<span>Rotate +90°</span>
</button>
<button @click="emitAndClose('flip', 'horizontal')" class="w-full px-3 py-1.5 text-left hover:bg-orange-50 dark:hover:bg-orange-900/30 text-gray-700 dark:text-gray-200 flex items-center gap-2 transition-colors text-sm">
<i class="fas fa-arrows-alt-h text-orange-600 dark:text-orange-400 text-xs w-4"></i>
<span>Flip horizontal</span>
</button>
<button @click="emitAndClose('flip', 'vertical')" class="w-full px-3 py-1.5 text-left hover:bg-orange-50 dark:hover:bg-orange-900/30 text-gray-700 dark:text-gray-200 flex items-center gap-2 transition-colors text-sm">
<i class="fas fa-arrows-alt-v text-orange-600 dark:text-orange-400 text-xs w-4"></i>
<span>Flip vertical</span>
</button>
<button @click="emit('replace')" class="w-full px-3 py-1.5 text-left hover:bg-purple-50 dark:hover:bg-purple-900/30 text-gray-700 dark:text-gray-200 flex items-center gap-2 transition-colors text-sm">
<i class="fas fa-exchange-alt text-purple-600 dark:text-purple-400 text-xs w-4"></i>
<span>Replace sprite</span>
</button>
<button @click="emit('copyToFrame')" class="w-full px-3 py-1.5 text-left hover:bg-cyan-50 dark:hover:bg-cyan-900/30 text-gray-700 dark:text-gray-200 flex items-center gap-2 transition-colors text-sm">
<i class="fas fa-copy text-cyan-600 dark:text-cyan-400 text-xs w-4"></i>
<span>Copy to frame...</span>
</button>
<button @click="emit('editInPixelEditor')" class="w-full px-3 py-1.5 text-left hover:bg-indigo-50 dark:hover:bg-indigo-900/30 text-gray-700 dark:text-gray-200 flex items-center gap-2 transition-colors text-sm">
<i class="fas fa-paint-brush text-indigo-600 dark:text-indigo-400 text-xs w-4"></i>
<span>Edit in Pixel Editor</span>
</button>
<div class="h-px bg-gray-200 dark:bg-gray-600 my-1"></div>
<button @click="emitAndClose('remove')" class="w-full px-3 py-1.5 text-left hover:bg-red-50 dark:hover:bg-red-900/30 text-red-600 dark:text-red-400 flex items-center gap-2 transition-colors text-sm">
<i class="fas fa-trash text-xs w-4"></i>
<span>{{ (selectedCount || 0) > 1 ? `Remove ${selectedCount} sprites` : 'Remove sprite' }}</span>
</button>
</template>
</div>
</Teleport>
</template>
<script setup lang="ts">
import { onMounted, onUnmounted } from 'vue';
const props = defineProps<{
isOpen: boolean;
position: { x: number; y: number };
hasSprite: boolean;
selectedCount?: number;
}>();
const emit = defineEmits<{
(e: 'add'): void;
(e: 'rotate', angle: number): void;
(e: 'flip', direction: 'horizontal' | 'vertical'): void;
(e: 'replace'): void;
(e: 'copyToFrame'): void;
(e: 'editInPixelEditor'): void;
(e: 'remove'): void;
(e: 'close'): void;
}>();
const emitAndClose = (event: 'rotate' | 'flip' | 'remove', arg?: any) => {
emit(event as any, arg);
emit('close');
};
const closeOnClickOutside = () => {
if (props.isOpen) {
emit('close');
}
};
onMounted(() => {
window.addEventListener('click', closeOnClickOutside);
window.addEventListener('contextmenu', closeOnClickOutside); // Close on right click elsewhere
});
onUnmounted(() => {
window.removeEventListener('click', closeOnClickOutside);
window.removeEventListener('contextmenu', closeOnClickOutside);
});
</script>

View File

@@ -0,0 +1,32 @@
import { ref } from 'vue';
export interface ContextMenuPosition {
x: number;
y: number;
}
export function useContextMenu<T = any>() {
const isOpen = ref(false);
const position = ref<ContextMenuPosition>({ x: 0, y: 0 });
const contextData = ref<T | null>(null);
const open = (event: MouseEvent, data: T) => {
event.preventDefault();
isOpen.value = true;
position.value = { x: event.clientX, y: event.clientY };
contextData.value = data;
};
const close = () => {
isOpen.value = false;
contextData.value = null;
};
return {
isOpen,
position,
contextData,
open,
close,
};
}

View File

@@ -322,6 +322,7 @@
@rotate-sprite="rotateSprite"
@flip-sprite="flipSprite"
@copy-sprite-to-frame="copySpriteToFrame"
@remove-sprite="removeSprite"
@replace-sprite="replaceSprite"
@open-pixel-editor="openPixelEditor"
/>