UPDATE: Adds cell context menu
This commit is contained in:
committed by
Nicolás Hatcher Andrés
parent
f96481feb8
commit
99125f1fea
@@ -8,12 +8,20 @@
|
||||
- New document server (Thanks Dani!)
|
||||
- New function FORMULATEXT
|
||||
- Name Manager ([#212](https://github.com/ironcalc/IronCalc/pull/212) [#220](https://github.com/ironcalc/IronCalc/pull/220))
|
||||
- Add context menu. We can now insert rows and columns. Freeze and unfreeze rows and columns. Delete rows and columns [#271]
|
||||
- Add nodejs bindings [#254]
|
||||
- Add python bindings for all platforms
|
||||
- Add is split into the product and widget
|
||||
- Add Python documentation [#260]
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed several issues with pasting content
|
||||
- Fixed several issues with borders
|
||||
- Fixed bug where columns and rows could be resized to negative width and height, respectively
|
||||
- Undo/redo when add/delete sheet now works [#270]
|
||||
- Numerous small fixes
|
||||
- Multiple fixes to the documentation
|
||||
|
||||
## [0.2.0] - 2024-11-06 (The HN release)
|
||||
|
||||
|
||||
2
Cargo.lock
generated
2
Cargo.lock
generated
@@ -1070,7 +1070,7 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||
|
||||
[[package]]
|
||||
name = "wasm"
|
||||
version = "0.3.0"
|
||||
version = "0.3.2"
|
||||
dependencies = [
|
||||
"ironcalc_base",
|
||||
"serde",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "wasm"
|
||||
version = "0.3.0"
|
||||
version = "0.3.2"
|
||||
authors = ["Nicolas Hatcher <nicolas@theuniverse.today>"]
|
||||
description = "IronCalc Web bindings"
|
||||
license = "MIT/Apache-2.0"
|
||||
|
||||
188
webapp/IronCalc/package-lock.json
generated
188
webapp/IronCalc/package-lock.json
generated
@@ -45,7 +45,7 @@
|
||||
}
|
||||
},
|
||||
"../../bindings/wasm/pkg": {
|
||||
"version": "0.3.0",
|
||||
"version": "0.3.2",
|
||||
"license": "MIT/Apache-2.0"
|
||||
},
|
||||
"node_modules/@adobe/css-tools": {
|
||||
@@ -1383,9 +1383,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rollup/rollup-android-arm-eabi": {
|
||||
"version": "4.34.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.34.2.tgz",
|
||||
"integrity": "sha512-6Fyg9yQbwJR+ykVdT9sid1oc2ewejS6h4wzQltmJfSW53N60G/ah9pngXGANdy9/aaE/TcUFpWosdm7JXS1WTQ==",
|
||||
"version": "4.34.6",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.34.6.tgz",
|
||||
"integrity": "sha512-+GcCXtOQoWuC7hhX1P00LqjjIiS/iOouHXhMdiDSnq/1DGTox4SpUvO52Xm+div6+106r+TcvOeo/cxvyEyTgg==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
@@ -1396,9 +1396,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-android-arm64": {
|
||||
"version": "4.34.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.34.2.tgz",
|
||||
"integrity": "sha512-K5GfWe+vtQ3kyEbihrimM38UgX57UqHp+oME7X/EX9Im6suwZfa7Hsr8AtzbJvukTpwMGs+4s29YMSO3rwWtsw==",
|
||||
"version": "4.34.6",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.34.6.tgz",
|
||||
"integrity": "sha512-E8+2qCIjciYUnCa1AiVF1BkRgqIGW9KzJeesQqVfyRITGQN+dFuoivO0hnro1DjT74wXLRZ7QF8MIbz+luGaJA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -1409,9 +1409,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-darwin-arm64": {
|
||||
"version": "4.34.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.34.2.tgz",
|
||||
"integrity": "sha512-PSN58XG/V/tzqDb9kDGutUruycgylMlUE59f40ny6QIRNsTEIZsrNQTJKUN2keMMSmlzgunMFqyaGLmly39sug==",
|
||||
"version": "4.34.6",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.34.6.tgz",
|
||||
"integrity": "sha512-z9Ib+OzqN3DZEjX7PDQMHEhtF+t6Mi2z/ueChQPLS/qUMKY7Ybn5A2ggFoKRNRh1q1T03YTQfBTQCJZiepESAg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -1422,9 +1422,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-darwin-x64": {
|
||||
"version": "4.34.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.34.2.tgz",
|
||||
"integrity": "sha512-gQhK788rQJm9pzmXyfBB84VHViDERhAhzGafw+E5mUpnGKuxZGkMVDa3wgDFKT6ukLC5V7QTifzsUKdNVxp5qQ==",
|
||||
"version": "4.34.6",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.34.6.tgz",
|
||||
"integrity": "sha512-PShKVY4u0FDAR7jskyFIYVyHEPCPnIQY8s5OcXkdU8mz3Y7eXDJPdyM/ZWjkYdR2m0izD9HHWA8sGcXn+Qrsyg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -1435,9 +1435,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-freebsd-arm64": {
|
||||
"version": "4.34.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.34.2.tgz",
|
||||
"integrity": "sha512-eiaHgQwGPpxLC3+zTAcdKl4VsBl3r0AiJOd1Um/ArEzAjN/dbPK1nROHrVkdnoE6p7Svvn04w3f/jEZSTVHunA==",
|
||||
"version": "4.34.6",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.34.6.tgz",
|
||||
"integrity": "sha512-YSwyOqlDAdKqs0iKuqvRHLN4SrD2TiswfoLfvYXseKbL47ht1grQpq46MSiQAx6rQEN8o8URtpXARCpqabqxGQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -1448,9 +1448,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-freebsd-x64": {
|
||||
"version": "4.34.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.34.2.tgz",
|
||||
"integrity": "sha512-lhdiwQ+jf8pewYOTG4bag0Qd68Jn1v2gO1i0mTuiD+Qkt5vNfHVK/jrT7uVvycV8ZchlzXp5HDVmhpzjC6mh0g==",
|
||||
"version": "4.34.6",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.34.6.tgz",
|
||||
"integrity": "sha512-HEP4CgPAY1RxXwwL5sPFv6BBM3tVeLnshF03HMhJYCNc6kvSqBgTMmsEjb72RkZBAWIqiPUyF1JpEBv5XT9wKQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -1461,9 +1461,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-arm-gnueabihf": {
|
||||
"version": "4.34.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.34.2.tgz",
|
||||
"integrity": "sha512-lfqTpWjSvbgQP1vqGTXdv+/kxIznKXZlI109WkIFPbud41bjigjNmOAAKoazmRGx+k9e3rtIdbq2pQZPV1pMig==",
|
||||
"version": "4.34.6",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.34.6.tgz",
|
||||
"integrity": "sha512-88fSzjC5xeH9S2Vg3rPgXJULkHcLYMkh8faix8DX4h4TIAL65ekwuQMA/g2CXq8W+NJC43V6fUpYZNjaX3+IIg==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
@@ -1474,9 +1474,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-arm-musleabihf": {
|
||||
"version": "4.34.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.34.2.tgz",
|
||||
"integrity": "sha512-RGjqULqIurqqv+NJTyuPgdZhka8ImMLB32YwUle2BPTDqDoXNgwFjdjQC59FbSk08z0IqlRJjrJ0AvDQ5W5lpw==",
|
||||
"version": "4.34.6",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.34.6.tgz",
|
||||
"integrity": "sha512-wM4ztnutBqYFyvNeR7Av+reWI/enK9tDOTKNF+6Kk2Q96k9bwhDDOlnCUNRPvromlVXo04riSliMBs/Z7RteEg==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
@@ -1487,9 +1487,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-arm64-gnu": {
|
||||
"version": "4.34.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.34.2.tgz",
|
||||
"integrity": "sha512-ZvkPiheyXtXlFqHpsdgscx+tZ7hoR59vOettvArinEspq5fxSDSgfF+L5wqqJ9R4t+n53nyn0sKxeXlik7AY9Q==",
|
||||
"version": "4.34.6",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.34.6.tgz",
|
||||
"integrity": "sha512-9RyprECbRa9zEjXLtvvshhw4CMrRa3K+0wcp3KME0zmBe1ILmvcVHnypZ/aIDXpRyfhSYSuN4EPdCCj5Du8FIA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -1500,9 +1500,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-arm64-musl": {
|
||||
"version": "4.34.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.34.2.tgz",
|
||||
"integrity": "sha512-UlFk+E46TZEoxD9ufLKDBzfSG7Ki03fo6hsNRRRHF+KuvNZ5vd1RRVQm8YZlGsjcJG8R252XFK0xNPay+4WV7w==",
|
||||
"version": "4.34.6",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.34.6.tgz",
|
||||
"integrity": "sha512-qTmklhCTyaJSB05S+iSovfo++EwnIEZxHkzv5dep4qoszUMX5Ca4WM4zAVUMbfdviLgCSQOu5oU8YoGk1s6M9Q==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -1513,9 +1513,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-loongarch64-gnu": {
|
||||
"version": "4.34.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.34.2.tgz",
|
||||
"integrity": "sha512-hJhfsD9ykx59jZuuoQgYT1GEcNNi3RCoEmbo5OGfG8RlHOiVS7iVNev9rhLKh7UBYq409f4uEw0cclTXx8nh8Q==",
|
||||
"version": "4.34.6",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.34.6.tgz",
|
||||
"integrity": "sha512-4Qmkaps9yqmpjY5pvpkfOerYgKNUGzQpFxV6rnS7c/JfYbDSU0y6WpbbredB5cCpLFGJEqYX40WUmxMkwhWCjw==",
|
||||
"cpu": [
|
||||
"loong64"
|
||||
],
|
||||
@@ -1526,9 +1526,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-powerpc64le-gnu": {
|
||||
"version": "4.34.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.34.2.tgz",
|
||||
"integrity": "sha512-g/O5IpgtrQqPegvqopvmdCF9vneLE7eqYfdPWW8yjPS8f63DNam3U4ARL1PNNB64XHZDHKpvO2Giftf43puB8Q==",
|
||||
"version": "4.34.6",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.34.6.tgz",
|
||||
"integrity": "sha512-Zsrtux3PuaxuBTX/zHdLaFmcofWGzaWW1scwLU3ZbW/X+hSsFbz9wDIp6XvnT7pzYRl9MezWqEqKy7ssmDEnuQ==",
|
||||
"cpu": [
|
||||
"ppc64"
|
||||
],
|
||||
@@ -1539,9 +1539,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-riscv64-gnu": {
|
||||
"version": "4.34.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.34.2.tgz",
|
||||
"integrity": "sha512-bSQijDC96M6PuooOuXHpvXUYiIwsnDmqGU8+br2U7iPoykNi9JtMUpN7K6xml29e0evK0/g0D1qbAUzWZFHY5Q==",
|
||||
"version": "4.34.6",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.34.6.tgz",
|
||||
"integrity": "sha512-aK+Zp+CRM55iPrlyKiU3/zyhgzWBxLVrw2mwiQSYJRobCURb781+XstzvA8Gkjg/hbdQFuDw44aUOxVQFycrAg==",
|
||||
"cpu": [
|
||||
"riscv64"
|
||||
],
|
||||
@@ -1552,9 +1552,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-s390x-gnu": {
|
||||
"version": "4.34.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.34.2.tgz",
|
||||
"integrity": "sha512-49TtdeVAsdRuiUHXPrFVucaP4SivazetGUVH8CIxVsNsaPHV4PFkpLmH9LeqU/R4Nbgky9lzX5Xe1NrzLyraVA==",
|
||||
"version": "4.34.6",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.34.6.tgz",
|
||||
"integrity": "sha512-WoKLVrY9ogmaYPXwTH326+ErlCIgMmsoRSx6bO+l68YgJnlOXhygDYSZe/qbUJCSiCiZAQ+tKm88NcWuUXqOzw==",
|
||||
"cpu": [
|
||||
"s390x"
|
||||
],
|
||||
@@ -1565,9 +1565,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-x64-gnu": {
|
||||
"version": "4.34.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.34.2.tgz",
|
||||
"integrity": "sha512-j+jFdfOycLIQ7FWKka9Zd3qvsIyugg5LeZuHF6kFlXo6MSOc6R1w37YUVy8VpAKd81LMWGi5g9J25P09M0SSIw==",
|
||||
"version": "4.34.6",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.34.6.tgz",
|
||||
"integrity": "sha512-Sht4aFvmA4ToHd2vFzwMFaQCiYm2lDFho5rPcvPBT5pCdC+GwHG6CMch4GQfmWTQ1SwRKS0dhDYb54khSrjDWw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -1578,9 +1578,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-x64-musl": {
|
||||
"version": "4.34.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.34.2.tgz",
|
||||
"integrity": "sha512-aDPHyM/D2SpXfSNCVWCxyHmOqN9qb7SWkY1+vaXqMNMXslZYnwh9V/UCudl6psyG0v6Ukj7pXanIpfZwCOEMUg==",
|
||||
"version": "4.34.6",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.34.6.tgz",
|
||||
"integrity": "sha512-zmmpOQh8vXc2QITsnCiODCDGXFC8LMi64+/oPpPx5qz3pqv0s6x46ps4xoycfUiVZps5PFn1gksZzo4RGTKT+A==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -1591,9 +1591,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-win32-arm64-msvc": {
|
||||
"version": "4.34.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.34.2.tgz",
|
||||
"integrity": "sha512-LQRkCyUBnAo7r8dbEdtNU08EKLCJMgAk2oP5H3R7BnUlKLqgR3dUjrLBVirmc1RK6U6qhtDw29Dimeer8d5hzQ==",
|
||||
"version": "4.34.6",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.34.6.tgz",
|
||||
"integrity": "sha512-3/q1qUsO/tLqGBaD4uXsB6coVGB3usxw3qyeVb59aArCgedSF66MPdgRStUd7vbZOsko/CgVaY5fo2vkvPLWiA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -1604,9 +1604,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-win32-ia32-msvc": {
|
||||
"version": "4.34.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.34.2.tgz",
|
||||
"integrity": "sha512-wt8OhpQUi6JuPFkm1wbVi1BByeag87LDFzeKSXzIdGcX4bMLqORTtKxLoCbV57BHYNSUSOKlSL4BYYUghainYA==",
|
||||
"version": "4.34.6",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.34.6.tgz",
|
||||
"integrity": "sha512-oLHxuyywc6efdKVTxvc0135zPrRdtYVjtVD5GUm55I3ODxhU/PwkQFD97z16Xzxa1Fz0AEe4W/2hzRtd+IfpOA==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
@@ -1617,9 +1617,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-win32-x64-msvc": {
|
||||
"version": "4.34.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.34.2.tgz",
|
||||
"integrity": "sha512-rUrqINax0TvrPBXrFKg0YbQx18NpPN3NNrgmaao9xRNbTwek7lOXObhx8tQy8gelmQ/gLaGy1WptpU2eKJZImg==",
|
||||
"version": "4.34.6",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.34.6.tgz",
|
||||
"integrity": "sha512-0PVwmgzZ8+TZ9oGBmdZoQVXflbvuwzN/HRclujpl4N/q3i+y0lqLw8n1bXA8ru3sApDjlmONaNAuYr38y1Kr9w==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -3020,9 +3020,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/caniuse-lite": {
|
||||
"version": "1.0.30001697",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001697.tgz",
|
||||
"integrity": "sha512-GwNPlWJin8E+d7Gxq96jxM6w0w+VFeyyXRsjU58emtkYqnbwHqXm5uT2uCmO0RQE9htWknOP4xtBlLmM/gWxvQ==",
|
||||
"version": "1.0.30001698",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001698.tgz",
|
||||
"integrity": "sha512-xJ3km2oiG/MbNU8G6zIq6XRZ6HtAOVXsbOrP/blGazi52kc5Yy7b6sDA5O+FbROzRrV7BSTllLHuNvmawYUJjw==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
@@ -3295,9 +3295,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/electron-to-chromium": {
|
||||
"version": "1.5.91",
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.91.tgz",
|
||||
"integrity": "sha512-sNSHHyq048PFmZY4S90ax61q+gLCs0X0YmcOII9wG9S2XwbVr+h4VW2wWhnbp/Eys3cCwTxVF292W3qPaxIapQ==",
|
||||
"version": "1.5.96",
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.96.tgz",
|
||||
"integrity": "sha512-8AJUW6dh75Fm/ny8+kZKJzI1pgoE8bKLZlzDU2W1ENd+DXKJrx7I7l9hb8UWR4ojlnb5OlixMt00QWiYJoVw1w==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/entities": {
|
||||
@@ -4252,9 +4252,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/possible-typed-array-names": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz",
|
||||
"integrity": "sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==",
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz",
|
||||
"integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
@@ -4550,9 +4550,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/rollup": {
|
||||
"version": "4.34.2",
|
||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.34.2.tgz",
|
||||
"integrity": "sha512-sBDUoxZEaqLu9QeNalL8v3jw6WjPku4wfZGyTU7l7m1oC+rpRihXc/n/H+4148ZkGz5Xli8CHMns//fFGKvpIQ==",
|
||||
"version": "4.34.6",
|
||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.34.6.tgz",
|
||||
"integrity": "sha512-wc2cBWqJgkU3Iz5oztRkQbfVkbxoz5EhnCGOrnJvnLnQ7O0WhQUYyv18qQI79O8L7DdHrrlJNeCHd4VGpnaXKQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/estree": "1.0.6"
|
||||
@@ -4565,25 +4565,25 @@
|
||||
"npm": ">=8.0.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@rollup/rollup-android-arm-eabi": "4.34.2",
|
||||
"@rollup/rollup-android-arm64": "4.34.2",
|
||||
"@rollup/rollup-darwin-arm64": "4.34.2",
|
||||
"@rollup/rollup-darwin-x64": "4.34.2",
|
||||
"@rollup/rollup-freebsd-arm64": "4.34.2",
|
||||
"@rollup/rollup-freebsd-x64": "4.34.2",
|
||||
"@rollup/rollup-linux-arm-gnueabihf": "4.34.2",
|
||||
"@rollup/rollup-linux-arm-musleabihf": "4.34.2",
|
||||
"@rollup/rollup-linux-arm64-gnu": "4.34.2",
|
||||
"@rollup/rollup-linux-arm64-musl": "4.34.2",
|
||||
"@rollup/rollup-linux-loongarch64-gnu": "4.34.2",
|
||||
"@rollup/rollup-linux-powerpc64le-gnu": "4.34.2",
|
||||
"@rollup/rollup-linux-riscv64-gnu": "4.34.2",
|
||||
"@rollup/rollup-linux-s390x-gnu": "4.34.2",
|
||||
"@rollup/rollup-linux-x64-gnu": "4.34.2",
|
||||
"@rollup/rollup-linux-x64-musl": "4.34.2",
|
||||
"@rollup/rollup-win32-arm64-msvc": "4.34.2",
|
||||
"@rollup/rollup-win32-ia32-msvc": "4.34.2",
|
||||
"@rollup/rollup-win32-x64-msvc": "4.34.2",
|
||||
"@rollup/rollup-android-arm-eabi": "4.34.6",
|
||||
"@rollup/rollup-android-arm64": "4.34.6",
|
||||
"@rollup/rollup-darwin-arm64": "4.34.6",
|
||||
"@rollup/rollup-darwin-x64": "4.34.6",
|
||||
"@rollup/rollup-freebsd-arm64": "4.34.6",
|
||||
"@rollup/rollup-freebsd-x64": "4.34.6",
|
||||
"@rollup/rollup-linux-arm-gnueabihf": "4.34.6",
|
||||
"@rollup/rollup-linux-arm-musleabihf": "4.34.6",
|
||||
"@rollup/rollup-linux-arm64-gnu": "4.34.6",
|
||||
"@rollup/rollup-linux-arm64-musl": "4.34.6",
|
||||
"@rollup/rollup-linux-loongarch64-gnu": "4.34.6",
|
||||
"@rollup/rollup-linux-powerpc64le-gnu": "4.34.6",
|
||||
"@rollup/rollup-linux-riscv64-gnu": "4.34.6",
|
||||
"@rollup/rollup-linux-s390x-gnu": "4.34.6",
|
||||
"@rollup/rollup-linux-x64-gnu": "4.34.6",
|
||||
"@rollup/rollup-linux-x64-musl": "4.34.6",
|
||||
"@rollup/rollup-win32-arm64-msvc": "4.34.6",
|
||||
"@rollup/rollup-win32-ia32-msvc": "4.34.6",
|
||||
"@rollup/rollup-win32-x64-msvc": "4.34.6",
|
||||
"fsevents": "~2.3.2"
|
||||
}
|
||||
},
|
||||
@@ -5031,14 +5031,14 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/vite": {
|
||||
"version": "6.0.11",
|
||||
"resolved": "https://registry.npmjs.org/vite/-/vite-6.0.11.tgz",
|
||||
"integrity": "sha512-4VL9mQPKoHy4+FE0NnRE/kbY51TOfaknxAjt3fJbGJxhIpBZiqVzlZDEesWWsuREXHwNdAoOFZ9MkPEVXczHwg==",
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/vite/-/vite-6.1.0.tgz",
|
||||
"integrity": "sha512-RjjMipCKVoR4hVfPY6GQTgveinjNuyLw+qruksLDvA5ktI1150VmcMBKmQaEWJhg/j6Uaf6dNCNA0AfdzUb/hQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"esbuild": "^0.24.2",
|
||||
"postcss": "^8.4.49",
|
||||
"rollup": "^4.23.0"
|
||||
"postcss": "^8.5.1",
|
||||
"rollup": "^4.30.1"
|
||||
},
|
||||
"bin": {
|
||||
"vite": "bin/vite.js"
|
||||
|
||||
286
webapp/IronCalc/src/components/CellContextMenu.tsx
Normal file
286
webapp/IronCalc/src/components/CellContextMenu.tsx
Normal file
@@ -0,0 +1,286 @@
|
||||
import { Menu, MenuItem, styled } from "@mui/material";
|
||||
import {
|
||||
BetweenHorizontalStart,
|
||||
BetweenVerticalStart,
|
||||
ChevronRight,
|
||||
Snowflake,
|
||||
Trash2,
|
||||
} from "lucide-react";
|
||||
import { useRef, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
const red_color = "rgb(235, 12, 12)";
|
||||
|
||||
interface CellContextMenuProps {
|
||||
open: boolean;
|
||||
onClose: () => void;
|
||||
anchorEl: HTMLDivElement | null;
|
||||
onInsertRowAbove: () => void;
|
||||
onInsertRowBelow: () => void;
|
||||
onInsertColumnLeft: () => void;
|
||||
onInsertColumnRight: () => void;
|
||||
onFreezeColumns: () => void;
|
||||
onFreezeRows: () => void;
|
||||
onUnfreezeColumns: () => void;
|
||||
onUnfreezeRows: () => void;
|
||||
onDeleteRow: () => void;
|
||||
onDeleteColumn: () => void;
|
||||
row: number;
|
||||
column: string;
|
||||
}
|
||||
|
||||
const CellContextMenu = (properties: CellContextMenuProps) => {
|
||||
const { t } = useTranslation();
|
||||
const {
|
||||
open,
|
||||
onClose,
|
||||
anchorEl,
|
||||
onInsertRowAbove,
|
||||
onInsertRowBelow,
|
||||
onInsertColumnLeft,
|
||||
onInsertColumnRight,
|
||||
onFreezeColumns,
|
||||
onFreezeRows,
|
||||
onUnfreezeColumns,
|
||||
onUnfreezeRows,
|
||||
onDeleteRow,
|
||||
onDeleteColumn,
|
||||
row,
|
||||
column,
|
||||
} = properties;
|
||||
const [freezeMenuOpen, setFreezeMenuOpen] = useState(false);
|
||||
const freezeRef = useRef(null);
|
||||
|
||||
const [insertRowMenuOpen, setInsertRowMenuOpen] = useState(false);
|
||||
const insertRowRef = useRef(null);
|
||||
|
||||
const [insertColumnMenuOpen, setInsertColumnMenuOpen] = useState(false);
|
||||
const insertColumnRef = useRef(null);
|
||||
|
||||
return (
|
||||
<>
|
||||
<StyledMenu
|
||||
open={open}
|
||||
onClose={onClose}
|
||||
anchorEl={anchorEl}
|
||||
anchorOrigin={{
|
||||
vertical: "top",
|
||||
horizontal: "left",
|
||||
}}
|
||||
transformOrigin={{
|
||||
vertical: "bottom",
|
||||
horizontal: 6,
|
||||
}}
|
||||
>
|
||||
<StyledMenuItem
|
||||
ref={insertColumnRef}
|
||||
onClick={() => setInsertColumnMenuOpen(true)}
|
||||
>
|
||||
<BetweenVerticalStartStyled />
|
||||
<ItemNameStyled>{t("cell_context.insert_column")}</ItemNameStyled>
|
||||
<ChevronRightStyled />
|
||||
</StyledMenuItem>
|
||||
<StyledMenuItem
|
||||
ref={insertRowRef}
|
||||
onClick={() => setInsertRowMenuOpen(true)}
|
||||
>
|
||||
<BetweenHorizontalStartStyled />
|
||||
<ItemNameStyled>{t("cell_context.insert_row")}</ItemNameStyled>
|
||||
<ChevronRightStyled />
|
||||
</StyledMenuItem>
|
||||
<MenuDivider />
|
||||
<StyledMenuItem ref={freezeRef} onClick={() => setFreezeMenuOpen(true)}>
|
||||
<StyledSnowflake />
|
||||
<ItemNameStyled>{t("cell_context.freeze")}</ItemNameStyled>
|
||||
<ChevronRightStyled />
|
||||
</StyledMenuItem>
|
||||
<MenuDivider />
|
||||
<StyledMenuItem onClick={onDeleteRow}>
|
||||
<StyledTrash />
|
||||
<ItemNameStyled style={{ color: red_color }}>
|
||||
{t("cell_context.delete_row", { row })}
|
||||
</ItemNameStyled>
|
||||
</StyledMenuItem>
|
||||
<StyledMenuItem onClick={onDeleteColumn}>
|
||||
<StyledTrash />
|
||||
<ItemNameStyled style={{ color: red_color }}>
|
||||
{t("cell_context.delete_column", { column })}
|
||||
</ItemNameStyled>
|
||||
</StyledMenuItem>
|
||||
</StyledMenu>
|
||||
<StyledMenu
|
||||
open={insertRowMenuOpen}
|
||||
onClose={() => setInsertRowMenuOpen(false)}
|
||||
anchorEl={insertRowRef.current}
|
||||
anchorOrigin={{
|
||||
vertical: "top",
|
||||
horizontal: "right",
|
||||
}}
|
||||
>
|
||||
<StyledMenuItem
|
||||
onClick={() => {
|
||||
setInsertRowMenuOpen(false);
|
||||
onInsertRowAbove();
|
||||
}}
|
||||
>
|
||||
<ItemNameStyled>{t("cell_context.insert_row_above")}</ItemNameStyled>
|
||||
</StyledMenuItem>
|
||||
<StyledMenuItem
|
||||
onClick={() => {
|
||||
setInsertRowMenuOpen(false);
|
||||
onInsertRowBelow();
|
||||
}}
|
||||
>
|
||||
<ItemNameStyled>{t("cell_context.insert_row_below")}</ItemNameStyled>
|
||||
</StyledMenuItem>
|
||||
</StyledMenu>
|
||||
<StyledMenu
|
||||
open={insertColumnMenuOpen}
|
||||
onClose={() => setInsertColumnMenuOpen(false)}
|
||||
anchorEl={insertColumnRef.current}
|
||||
anchorOrigin={{
|
||||
vertical: "top",
|
||||
horizontal: "right",
|
||||
}}
|
||||
>
|
||||
<StyledMenuItem
|
||||
onClick={() => {
|
||||
setInsertColumnMenuOpen(false);
|
||||
onInsertColumnLeft();
|
||||
}}
|
||||
>
|
||||
<ItemNameStyled>
|
||||
{t("cell_context.insert_column_before")}
|
||||
</ItemNameStyled>
|
||||
</StyledMenuItem>
|
||||
<StyledMenuItem
|
||||
onClick={() => {
|
||||
setInsertColumnMenuOpen(false);
|
||||
onInsertColumnRight();
|
||||
}}
|
||||
>
|
||||
<ItemNameStyled>
|
||||
{t("cell_context.insert_column_after")}
|
||||
</ItemNameStyled>
|
||||
</StyledMenuItem>
|
||||
</StyledMenu>
|
||||
<StyledMenu
|
||||
open={freezeMenuOpen}
|
||||
onClose={() => setFreezeMenuOpen(false)}
|
||||
anchorEl={freezeRef.current}
|
||||
anchorOrigin={{
|
||||
vertical: "top",
|
||||
horizontal: "right",
|
||||
}}
|
||||
>
|
||||
<StyledMenuItem
|
||||
onClick={() => {
|
||||
onFreezeColumns();
|
||||
setFreezeMenuOpen(false);
|
||||
}}
|
||||
>
|
||||
<ItemNameStyled>
|
||||
{t("cell_context.freeze_columns", { column })}
|
||||
</ItemNameStyled>
|
||||
</StyledMenuItem>
|
||||
<StyledMenuItem
|
||||
onClick={() => {
|
||||
onFreezeRows();
|
||||
setFreezeMenuOpen(false);
|
||||
}}
|
||||
>
|
||||
<ItemNameStyled>
|
||||
{t("cell_context.freeze_rows", { row })}
|
||||
</ItemNameStyled>
|
||||
</StyledMenuItem>
|
||||
<StyledMenuItem
|
||||
onClick={() => {
|
||||
onUnfreezeColumns();
|
||||
setFreezeMenuOpen(false);
|
||||
}}
|
||||
>
|
||||
<ItemNameStyled>{t("cell_context.unfreeze_columns")}</ItemNameStyled>
|
||||
</StyledMenuItem>
|
||||
<StyledMenuItem
|
||||
onClick={() => {
|
||||
onUnfreezeRows();
|
||||
setFreezeMenuOpen(false);
|
||||
}}
|
||||
>
|
||||
<ItemNameStyled>{t("cell_context.unfreeze_rows")}</ItemNameStyled>
|
||||
</StyledMenuItem>
|
||||
</StyledMenu>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const BetweenVerticalStartStyled = styled(BetweenVerticalStart)`
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
color: #333333;
|
||||
padding-right: 10px;
|
||||
`;
|
||||
|
||||
const BetweenHorizontalStartStyled = styled(BetweenHorizontalStart)`
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
color: #333333;
|
||||
padding-right: 10px;
|
||||
`;
|
||||
|
||||
const StyledSnowflake = styled(Snowflake)`
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
color: #333333;
|
||||
padding-right: 10px;
|
||||
`;
|
||||
|
||||
const StyledTrash = styled(Trash2)`
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
color: ${red_color};
|
||||
padding-right: 10px;
|
||||
`;
|
||||
|
||||
const StyledMenu = styled(Menu)({
|
||||
"& .MuiPaper-root": {
|
||||
borderRadius: 8,
|
||||
padding: 4,
|
||||
},
|
||||
"& .MuiList-padding": {
|
||||
padding: 0,
|
||||
},
|
||||
});
|
||||
|
||||
const StyledMenuItem = styled(MenuItem)`
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
font-size: 14px;
|
||||
width: calc(100% - 8px);
|
||||
min-width: 172px;
|
||||
margin: 0px 4px;
|
||||
border-radius: 4px;
|
||||
padding: 8px;
|
||||
height: 32px;
|
||||
`;
|
||||
|
||||
const MenuDivider = styled("div")`
|
||||
width: 100%;
|
||||
margin: auto;
|
||||
margin-top: 4px;
|
||||
margin-bottom: 4px;
|
||||
border-top: 1px solid #eeeeee;
|
||||
`;
|
||||
|
||||
const ItemNameStyled = styled("div")`
|
||||
font-size: 12px;
|
||||
color: #333;
|
||||
flex-grow: 2;
|
||||
`;
|
||||
|
||||
const ChevronRightStyled = styled(ChevronRight)`
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
`;
|
||||
|
||||
export default CellContextMenu;
|
||||
@@ -240,7 +240,6 @@ const usePointer = (options: PointerSettings): PointerEvents => {
|
||||
onPointerMove,
|
||||
onPointerUp,
|
||||
onPointerHandleDown,
|
||||
// onContextMenu,
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import type { Model } from "@ironcalc/wasm";
|
||||
import { type Model, columnNameFromNumber } from "@ironcalc/wasm";
|
||||
import { styled } from "@mui/material/styles";
|
||||
import { useEffect, useLayoutEffect, useRef, useState } from "react";
|
||||
import CellContextMenu from "./CellContextMenu";
|
||||
import {
|
||||
COLUMN_WIDTH_SCALE,
|
||||
ROW_HEIGH_SCALE,
|
||||
@@ -52,6 +53,8 @@ function Worksheet(props: {
|
||||
const columnHeaders = useRef<HTMLDivElement>(null);
|
||||
const worksheetCanvas = useRef<WorksheetCanvas | null>(null);
|
||||
|
||||
const [contextMenuOpen, setContextMenuOpen] = useState(false);
|
||||
|
||||
const ignoreScrollEventRef = useRef(false);
|
||||
|
||||
const { model, workbookState, refresh } = props;
|
||||
@@ -147,174 +150,175 @@ function Worksheet(props: {
|
||||
worksheetCanvas.current = canvas;
|
||||
});
|
||||
|
||||
const {
|
||||
onPointerMove,
|
||||
onPointerDown,
|
||||
onPointerHandleDown,
|
||||
onPointerUp,
|
||||
// onContextMenu,
|
||||
} = usePointer({
|
||||
model,
|
||||
workbookState,
|
||||
refresh,
|
||||
onCellSelected: (cell: Cell, event: React.MouseEvent) => {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
model.setSelectedCell(cell.row, cell.column);
|
||||
refresh();
|
||||
},
|
||||
onAreaSelecting: (cell: Cell) => {
|
||||
const canvas = worksheetCanvas.current;
|
||||
if (!canvas) {
|
||||
return;
|
||||
}
|
||||
const { row, column } = cell;
|
||||
model.onAreaSelecting(row, column);
|
||||
canvas.renderSheet();
|
||||
refresh();
|
||||
},
|
||||
onAreaSelected: () => {
|
||||
const styles = workbookState.getCopyStyles();
|
||||
if (styles?.length) {
|
||||
model.onPasteStyles(styles);
|
||||
const { onPointerMove, onPointerDown, onPointerHandleDown, onPointerUp } =
|
||||
usePointer({
|
||||
model,
|
||||
workbookState,
|
||||
refresh,
|
||||
onCellSelected: (cell: Cell, event: React.MouseEvent) => {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
model.setSelectedCell(cell.row, cell.column);
|
||||
refresh();
|
||||
},
|
||||
onAreaSelecting: (cell: Cell) => {
|
||||
const canvas = worksheetCanvas.current;
|
||||
if (!canvas) {
|
||||
return;
|
||||
}
|
||||
const { row, column } = cell;
|
||||
model.onAreaSelecting(row, column);
|
||||
canvas.renderSheet();
|
||||
}
|
||||
workbookState.setCopyStyles(null);
|
||||
if (worksheetElement.current) {
|
||||
worksheetElement.current.style.cursor = "auto";
|
||||
}
|
||||
refresh();
|
||||
},
|
||||
onExtendToCell: (cell) => {
|
||||
const canvas = worksheetCanvas.current;
|
||||
if (!canvas) {
|
||||
return;
|
||||
}
|
||||
const { row, column } = cell;
|
||||
const {
|
||||
range: [rowStart, columnStart, rowEnd, columnEnd],
|
||||
} = model.getSelectedView();
|
||||
// We are either extending by rows or by columns
|
||||
// And we could be doing it in the positive direction (downwards or right)
|
||||
// or the negative direction (upwards or left)
|
||||
|
||||
if (
|
||||
row > rowEnd &&
|
||||
((column <= columnEnd && column >= columnStart) ||
|
||||
(column < columnStart && columnStart - column < row - rowEnd) ||
|
||||
(column > columnEnd && column - columnEnd < row - rowEnd))
|
||||
) {
|
||||
// rows downwards
|
||||
const area = {
|
||||
type: AreaType.rowsDown,
|
||||
rowStart: rowEnd + 1,
|
||||
rowEnd: row,
|
||||
columnStart,
|
||||
columnEnd,
|
||||
};
|
||||
workbookState.setExtendToArea(area);
|
||||
canvas.renderSheet();
|
||||
} else if (
|
||||
row < rowStart &&
|
||||
((column <= columnEnd && column >= columnStart) ||
|
||||
(column < columnStart && columnStart - column < rowStart - row) ||
|
||||
(column > columnEnd && column - columnEnd < rowStart - row))
|
||||
) {
|
||||
// rows upwards
|
||||
const area = {
|
||||
type: AreaType.rowsUp,
|
||||
rowStart: row,
|
||||
rowEnd: rowStart,
|
||||
columnStart,
|
||||
columnEnd,
|
||||
};
|
||||
workbookState.setExtendToArea(area);
|
||||
canvas.renderSheet();
|
||||
} else if (
|
||||
column > columnEnd &&
|
||||
((row <= rowEnd && row >= rowStart) ||
|
||||
(row < rowStart && rowStart - row < column - columnEnd) ||
|
||||
(row > rowEnd && row - rowEnd < column - columnEnd))
|
||||
) {
|
||||
// columns right
|
||||
const area = {
|
||||
type: AreaType.columnsRight,
|
||||
rowStart,
|
||||
rowEnd,
|
||||
columnStart: columnEnd + 1,
|
||||
columnEnd: column,
|
||||
};
|
||||
workbookState.setExtendToArea(area);
|
||||
canvas.renderSheet();
|
||||
} else if (
|
||||
column < columnStart &&
|
||||
((row <= rowEnd && row >= rowStart) ||
|
||||
(row < rowStart && rowStart - row < columnStart - column) ||
|
||||
(row > rowEnd && row - rowEnd < columnStart - column))
|
||||
) {
|
||||
// columns left
|
||||
const area = {
|
||||
type: AreaType.columnsLeft,
|
||||
rowStart,
|
||||
rowEnd,
|
||||
columnStart: column,
|
||||
columnEnd: columnStart,
|
||||
};
|
||||
workbookState.setExtendToArea(area);
|
||||
canvas.renderSheet();
|
||||
}
|
||||
},
|
||||
onExtendToEnd: () => {
|
||||
const canvas = worksheetCanvas.current;
|
||||
if (!canvas) {
|
||||
return;
|
||||
}
|
||||
const { sheet, range } = model.getSelectedView();
|
||||
const extendedArea = workbookState.getExtendToArea();
|
||||
if (!extendedArea) {
|
||||
return;
|
||||
}
|
||||
const rowStart = Math.min(range[0], range[2]);
|
||||
const height = Math.abs(range[2] - range[0]) + 1;
|
||||
const width = Math.abs(range[3] - range[1]) + 1;
|
||||
const columnStart = Math.min(range[1], range[3]);
|
||||
|
||||
const area = { sheet, row: rowStart, column: columnStart, width, height };
|
||||
|
||||
switch (extendedArea.type) {
|
||||
case AreaType.rowsDown:
|
||||
model.autoFillRows(area, extendedArea.rowEnd);
|
||||
break;
|
||||
case AreaType.rowsUp: {
|
||||
model.autoFillRows(area, extendedArea.rowStart);
|
||||
break;
|
||||
refresh();
|
||||
},
|
||||
onAreaSelected: () => {
|
||||
const styles = workbookState.getCopyStyles();
|
||||
if (styles?.length) {
|
||||
model.onPasteStyles(styles);
|
||||
const canvas = worksheetCanvas.current;
|
||||
if (!canvas) {
|
||||
return;
|
||||
}
|
||||
canvas.renderSheet();
|
||||
}
|
||||
case AreaType.columnsRight: {
|
||||
model.autoFillColumns(area, extendedArea.columnEnd);
|
||||
break;
|
||||
workbookState.setCopyStyles(null);
|
||||
if (worksheetElement.current) {
|
||||
worksheetElement.current.style.cursor = "auto";
|
||||
}
|
||||
case AreaType.columnsLeft: {
|
||||
model.autoFillColumns(area, extendedArea.columnStart);
|
||||
break;
|
||||
refresh();
|
||||
},
|
||||
onExtendToCell: (cell) => {
|
||||
const canvas = worksheetCanvas.current;
|
||||
if (!canvas) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
model.setSelectedRange(
|
||||
Math.min(rowStart, extendedArea.rowStart),
|
||||
Math.min(columnStart, extendedArea.columnStart),
|
||||
Math.max(rowStart + height - 1, extendedArea.rowEnd),
|
||||
Math.max(columnStart + width - 1, extendedArea.columnEnd),
|
||||
);
|
||||
workbookState.clearExtendToArea();
|
||||
canvas.renderSheet();
|
||||
},
|
||||
canvasElement,
|
||||
worksheetElement,
|
||||
worksheetCanvas,
|
||||
});
|
||||
const { row, column } = cell;
|
||||
const {
|
||||
range: [rowStart, columnStart, rowEnd, columnEnd],
|
||||
} = model.getSelectedView();
|
||||
// We are either extending by rows or by columns
|
||||
// And we could be doing it in the positive direction (downwards or right)
|
||||
// or the negative direction (upwards or left)
|
||||
|
||||
if (
|
||||
row > rowEnd &&
|
||||
((column <= columnEnd && column >= columnStart) ||
|
||||
(column < columnStart && columnStart - column < row - rowEnd) ||
|
||||
(column > columnEnd && column - columnEnd < row - rowEnd))
|
||||
) {
|
||||
// rows downwards
|
||||
const area = {
|
||||
type: AreaType.rowsDown,
|
||||
rowStart: rowEnd + 1,
|
||||
rowEnd: row,
|
||||
columnStart,
|
||||
columnEnd,
|
||||
};
|
||||
workbookState.setExtendToArea(area);
|
||||
canvas.renderSheet();
|
||||
} else if (
|
||||
row < rowStart &&
|
||||
((column <= columnEnd && column >= columnStart) ||
|
||||
(column < columnStart && columnStart - column < rowStart - row) ||
|
||||
(column > columnEnd && column - columnEnd < rowStart - row))
|
||||
) {
|
||||
// rows upwards
|
||||
const area = {
|
||||
type: AreaType.rowsUp,
|
||||
rowStart: row,
|
||||
rowEnd: rowStart,
|
||||
columnStart,
|
||||
columnEnd,
|
||||
};
|
||||
workbookState.setExtendToArea(area);
|
||||
canvas.renderSheet();
|
||||
} else if (
|
||||
column > columnEnd &&
|
||||
((row <= rowEnd && row >= rowStart) ||
|
||||
(row < rowStart && rowStart - row < column - columnEnd) ||
|
||||
(row > rowEnd && row - rowEnd < column - columnEnd))
|
||||
) {
|
||||
// columns right
|
||||
const area = {
|
||||
type: AreaType.columnsRight,
|
||||
rowStart,
|
||||
rowEnd,
|
||||
columnStart: columnEnd + 1,
|
||||
columnEnd: column,
|
||||
};
|
||||
workbookState.setExtendToArea(area);
|
||||
canvas.renderSheet();
|
||||
} else if (
|
||||
column < columnStart &&
|
||||
((row <= rowEnd && row >= rowStart) ||
|
||||
(row < rowStart && rowStart - row < columnStart - column) ||
|
||||
(row > rowEnd && row - rowEnd < columnStart - column))
|
||||
) {
|
||||
// columns left
|
||||
const area = {
|
||||
type: AreaType.columnsLeft,
|
||||
rowStart,
|
||||
rowEnd,
|
||||
columnStart: column,
|
||||
columnEnd: columnStart,
|
||||
};
|
||||
workbookState.setExtendToArea(area);
|
||||
canvas.renderSheet();
|
||||
}
|
||||
},
|
||||
onExtendToEnd: () => {
|
||||
const canvas = worksheetCanvas.current;
|
||||
if (!canvas) {
|
||||
return;
|
||||
}
|
||||
const { sheet, range } = model.getSelectedView();
|
||||
const extendedArea = workbookState.getExtendToArea();
|
||||
if (!extendedArea) {
|
||||
return;
|
||||
}
|
||||
const rowStart = Math.min(range[0], range[2]);
|
||||
const height = Math.abs(range[2] - range[0]) + 1;
|
||||
const width = Math.abs(range[3] - range[1]) + 1;
|
||||
const columnStart = Math.min(range[1], range[3]);
|
||||
|
||||
const area = {
|
||||
sheet,
|
||||
row: rowStart,
|
||||
column: columnStart,
|
||||
width,
|
||||
height,
|
||||
};
|
||||
|
||||
switch (extendedArea.type) {
|
||||
case AreaType.rowsDown:
|
||||
model.autoFillRows(area, extendedArea.rowEnd);
|
||||
break;
|
||||
case AreaType.rowsUp: {
|
||||
model.autoFillRows(area, extendedArea.rowStart);
|
||||
break;
|
||||
}
|
||||
case AreaType.columnsRight: {
|
||||
model.autoFillColumns(area, extendedArea.columnEnd);
|
||||
break;
|
||||
}
|
||||
case AreaType.columnsLeft: {
|
||||
model.autoFillColumns(area, extendedArea.columnStart);
|
||||
break;
|
||||
}
|
||||
}
|
||||
model.setSelectedRange(
|
||||
Math.min(rowStart, extendedArea.rowStart),
|
||||
Math.min(columnStart, extendedArea.columnStart),
|
||||
Math.max(rowStart + height - 1, extendedArea.rowEnd),
|
||||
Math.max(columnStart + width - 1, extendedArea.columnEnd),
|
||||
);
|
||||
workbookState.clearExtendToArea();
|
||||
canvas.renderSheet();
|
||||
},
|
||||
canvasElement,
|
||||
worksheetElement,
|
||||
worksheetCanvas,
|
||||
});
|
||||
|
||||
const onScroll = (): void => {
|
||||
if (!scrollElement.current || !worksheetCanvas.current) {
|
||||
@@ -340,6 +344,11 @@ function Worksheet(props: {
|
||||
onPointerDown={onPointerDown}
|
||||
onPointerMove={onPointerMove}
|
||||
onPointerUp={onPointerUp}
|
||||
onContextMenu={(event) => {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
setContextMenuOpen(true);
|
||||
}}
|
||||
onDoubleClick={(event) => {
|
||||
// Starts editing cell
|
||||
const { sheet, row, column } = model.getSelectedView();
|
||||
@@ -392,6 +401,63 @@ function Worksheet(props: {
|
||||
<RowResizeGuide ref={rowResizeGuide} />
|
||||
<ColumnHeaders ref={columnHeaders} />
|
||||
</SheetContainer>
|
||||
<CellContextMenu
|
||||
open={contextMenuOpen}
|
||||
onClose={() => setContextMenuOpen(false)}
|
||||
anchorEl={cellOutline.current}
|
||||
onInsertRowAbove={(): void => {
|
||||
const view = model.getSelectedView();
|
||||
model.insertRow(view.sheet, view.row);
|
||||
setContextMenuOpen(false);
|
||||
}}
|
||||
onInsertRowBelow={(): void => {
|
||||
const view = model.getSelectedView();
|
||||
model.insertRow(view.sheet, view.row + 1);
|
||||
setContextMenuOpen(false);
|
||||
}}
|
||||
onInsertColumnLeft={(): void => {
|
||||
const view = model.getSelectedView();
|
||||
model.insertColumn(view.sheet, view.column);
|
||||
setContextMenuOpen(false);
|
||||
}}
|
||||
onInsertColumnRight={(): void => {
|
||||
const view = model.getSelectedView();
|
||||
model.insertColumn(view.sheet, view.column + 1);
|
||||
setContextMenuOpen(false);
|
||||
}}
|
||||
onFreezeColumns={(): void => {
|
||||
const view = model.getSelectedView();
|
||||
model.setFrozenColumnsCount(view.sheet, view.column);
|
||||
setContextMenuOpen(false);
|
||||
}}
|
||||
onFreezeRows={(): void => {
|
||||
const view = model.getSelectedView();
|
||||
model.setFrozenRowsCount(view.sheet, view.row);
|
||||
setContextMenuOpen(false);
|
||||
}}
|
||||
onUnfreezeColumns={(): void => {
|
||||
const sheet = model.getSelectedSheet();
|
||||
model.setFrozenColumnsCount(sheet, 0);
|
||||
setContextMenuOpen(false);
|
||||
}}
|
||||
onUnfreezeRows={(): void => {
|
||||
const sheet = model.getSelectedSheet();
|
||||
model.setFrozenRowsCount(sheet, 0);
|
||||
setContextMenuOpen(false);
|
||||
}}
|
||||
onDeleteRow={(): void => {
|
||||
const view = model.getSelectedView();
|
||||
model.deleteRow(view.sheet, view.row);
|
||||
setContextMenuOpen(false);
|
||||
}}
|
||||
onDeleteColumn={(): void => {
|
||||
const view = model.getSelectedView();
|
||||
model.deleteColumn(view.sheet, view.column);
|
||||
setContextMenuOpen(false);
|
||||
}}
|
||||
row={model.getSelectedView().row}
|
||||
column={columnNameFromNumber(model.getSelectedView().column)}
|
||||
/>
|
||||
</Wrapper>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -100,5 +100,20 @@
|
||||
"edit": "Edit Range",
|
||||
"apply": "Apply changes",
|
||||
"discard": "Discard changes"
|
||||
},
|
||||
"cell_context": {
|
||||
"insert_row_above": "Insert 1 row above",
|
||||
"insert_row_below": "Insert 1 row below",
|
||||
"insert_column_before": "Insert 1 column left",
|
||||
"insert_column_after": "Insert 1 column right",
|
||||
"freeze_columns": "Freeze up to column '{{column}}'",
|
||||
"freeze_rows": "Freeze up to row '{{row}}'",
|
||||
"unfreeze_rows": "Unfreeze rows",
|
||||
"unfreeze_columns": "Unfreeze columns",
|
||||
"delete_row": "Delete row '{{row}}'",
|
||||
"delete_column": "Delete column '{{column}}'",
|
||||
"freeze": "Freeze",
|
||||
"insert_row": "Insert row",
|
||||
"insert_column": "Insert column"
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user