{"_id":"@ricsam/selection-manager","_rev":"33-a1b6d3f702c5b73c2fe453281be00bd3","name":"@ricsam/selection-manager","dist-tags":{"latest":"0.0.33"},"versions":{"0.0.1":{"name":"@ricsam/selection-manager","version":"0.0.1","_id":"@ricsam/selection-manager@0.0.1","maintainers":[{"name":"ricsam","email":"oss@ricsam.dev"}],"dist":{"shasum":"2236693edcb6869818f4da726331ec1600f0de44","tarball":"https://registry.npmjs.org/@ricsam/selection-manager/-/selection-manager-0.0.1.tgz","fileCount":24,"integrity":"sha512-r3siSmkqwHY/3jbeD2DExp+SYw0UymBYtbhHD/uNqEnuXxCFEQ/46hiwmT75v1jQ+MgkfzdGR3GIP4nD7LSlyA==","signatures":[{"sig":"MEYCIQDY2Jqo0KfM+qRiwfkvCgvuOmvI9pxucsVaaQoe+L3/NQIhAMiW4OCCnU76aA4odMvg5rlF61r058+uPSy8ps1tij8p","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":208005},"main":"./dist/cjs/lib.cjs","types":"./dist/types/lib.d.ts","module":"./dist/mjs/lib.mjs","exports":{".":{"types":"./dist/types/lib.d.ts","import":"./dist/mjs/lib.mjs","require":"./dist/cjs/lib.cjs"}},"gitHead":"5ac17c78fb325292a71ce34daf082033ea06e75b","scripts":{"dev":"bun --hot index.html","lint":"eslint ."},"_npmUser":{"name":"ricsam","actor":{"name":"ricsam","type":"user","email":"oss@ricsam.dev"},"email":"oss@ricsam.dev"},"prettier":{},"_npmVersion":"10.8.2","description":"A React hook-based selection manager for grid-like interfaces with support for multi-selection, keyboard navigation, and both controlled and uncontrolled modes.","directories":{},"_nodeVersion":"24.3.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"peerDependencies":{"typescript":"^5"},"_npmOperationalInternal":{"tmp":"tmp/selection-manager_0.0.1_1751880648673_0.7094823938538879","host":"s3://npm-registry-packages-npm-production"}},"0.0.2":{"name":"@ricsam/selection-manager","version":"0.0.2","_id":"@ricsam/selection-manager@0.0.2","maintainers":[{"name":"ricsam","email":"oss@ricsam.dev"}],"dist":{"shasum":"a4716f693258824933561c3ebd49d42a9b19fdc4","tarball":"https://registry.npmjs.org/@ricsam/selection-manager/-/selection-manager-0.0.2.tgz","fileCount":24,"integrity":"sha512-MFCKD5V+OYwf30ys+xuO+5+OfuENtDqc7RtgIrsczJ+7Mq8LhuQ9EDdwGZOQGYzRzutwuB/tg5G0kYRJsSHTEQ==","signatures":[{"sig":"MEYCIQCRQ5NFLalUDHa8e7eiRMMeTQ3X74moarmo9cmQKAbFbwIhAO1emwfNlJPoB66fv2GSn9HtasFDk/GXJIbt0Vap3hYK","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":259268},"main":"./dist/cjs/lib.cjs","types":"./dist/types/lib.d.ts","module":"./dist/mjs/lib.mjs","exports":{".":{"types":"./dist/types/lib.d.ts","import":"./dist/mjs/lib.mjs","require":"./dist/cjs/lib.cjs"}},"gitHead":"c1445b0ecd0b9d605a29f4d9cc21fc6ed4f90d97","scripts":{"dev":"bun --hot index.html","lint":"eslint ."},"_npmUser":{"name":"ricsam","actor":{"name":"ricsam","type":"user","email":"oss@ricsam.dev"},"email":"oss@ricsam.dev"},"prettier":{},"_npmVersion":"10.8.2","description":"A React hook-based selection manager for grid-like interfaces with support for multi-selection, keyboard navigation, and both controlled and uncontrolled modes.","directories":{},"_nodeVersion":"24.3.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"peerDependencies":{"typescript":"^5"},"_npmOperationalInternal":{"tmp":"tmp/selection-manager_0.0.2_1751903835091_0.0015361339483674907","host":"s3://npm-registry-packages-npm-production"}},"0.0.3":{"name":"@ricsam/selection-manager","version":"0.0.3","_id":"@ricsam/selection-manager@0.0.3","maintainers":[{"name":"ricsam","email":"oss@ricsam.dev"}],"dist":{"shasum":"9211a447cf114aeb8ef6c5942c613073309b599a","tarball":"https://registry.npmjs.org/@ricsam/selection-manager/-/selection-manager-0.0.3.tgz","fileCount":29,"integrity":"sha512-viNazuQ1j2+uZgGEKdKuhlqu5mBTYwK25/aNfWUDWXd+IHA8UbIf/WCvhwxS1Yq+6vgG75HDz4Gbk1VSgihatg==","signatures":[{"sig":"MEUCIQDmv20ZLQoUUHgSivzDaDgnN3GGymVnh9+FmQPMESerHwIgXNDqUbP9K/RhwgrAgTJKY533GjRdGBLWNQodwLrm188=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":386885},"main":"./dist/cjs/lib.cjs","types":"./dist/types/lib.d.ts","module":"./dist/mjs/lib.mjs","exports":{".":{"types":"./dist/types/lib.d.ts","import":"./dist/mjs/lib.mjs","require":"./dist/cjs/lib.cjs"}},"gitHead":"450049b252250ceec65f5351bd8e310f3a167664","scripts":{"dev":"bun --hot index.html","lint":"eslint ."},"_npmUser":{"name":"ricsam","email":"oss@ricsam.dev"},"prettier":{},"_npmVersion":"10.8.2","description":"> A powerful React hook-based selection manager that makes building spreadsheet-like interfaces a breeze! ✨","directories":{},"_nodeVersion":"24.3.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"peerDependencies":{"typescript":"^5"},"_npmOperationalInternal":{"tmp":"tmp/selection-manager_0.0.3_1753372730210_0.6045625914939186","host":"s3://npm-registry-packages-npm-production"}},"0.0.4":{"name":"@ricsam/selection-manager","version":"0.0.4","_id":"@ricsam/selection-manager@0.0.4","maintainers":[{"name":"ricsam","email":"oss@ricsam.dev"}],"dist":{"shasum":"799470931debd7def42818a7b037a491164c1a95","tarball":"https://registry.npmjs.org/@ricsam/selection-manager/-/selection-manager-0.0.4.tgz","fileCount":29,"integrity":"sha512-IOt4EGlQEVPrFPmqJ6p0+sv177oWPz2h3TZnOdCM2AcEdO2ZfqKSr/Zk0TuUDdL+t3W8A4H5BorLQSoj/AzTMw==","signatures":[{"sig":"MEQCIFUE10RbDMibA+4MUOf9/DW1eswLih0IHnhgZ3zGt1yiAiBaCjy1QbIYkTtt1NpuW/17qebW+bjrnbF9itD2Tn39OA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":386933},"main":"./dist/cjs/lib.cjs","types":"./dist/types/lib.d.ts","module":"./dist/mjs/lib.mjs","exports":{".":{"types":"./dist/types/lib.d.ts","import":"./dist/mjs/lib.mjs","require":"./dist/cjs/lib.cjs"}},"gitHead":"8d38cec7a870f8beffb71c9406a6bba0f2fdc72a","scripts":{"dev":"bun --hot index.html","lint":"eslint ."},"_npmUser":{"name":"ricsam","email":"oss@ricsam.dev"},"prettier":{},"_npmVersion":"10.8.2","description":"> A powerful React hook-based selection manager that makes building spreadsheet-like interfaces a breeze! ✨","directories":{},"_nodeVersion":"24.3.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"peerDependencies":{"typescript":"^5"},"_npmOperationalInternal":{"tmp":"tmp/selection-manager_0.0.4_1753781446649_0.3113547666170722","host":"s3://npm-registry-packages-npm-production"}},"0.0.5":{"name":"@ricsam/selection-manager","version":"0.0.5","_id":"@ricsam/selection-manager@0.0.5","maintainers":[{"name":"ricsam","email":"oss@ricsam.dev"}],"dist":{"shasum":"fb1122d4bb86659b42c7fd49090cdae7fbe31652","tarball":"https://registry.npmjs.org/@ricsam/selection-manager/-/selection-manager-0.0.5.tgz","fileCount":29,"integrity":"sha512-VloXHwb16l6kMwSvEzBLCeu8me0zFDC+v5FwaKSJ775snL5YGFgUt3TmEBMzFGWlgP15rOxJvEcUQuFyhR+wAg==","signatures":[{"sig":"MEUCIHOkwWAhT0BTLZB+h5Iba/9O9jKAhe2qLNZjwUmspmH+AiEAkYrlRx1Srdf0SGVjuZNy6iQw5X4uhNWrVn+iovT5Pyo=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":388249},"main":"./dist/cjs/lib.cjs","types":"./dist/types/lib.d.ts","module":"./dist/mjs/lib.mjs","exports":{".":{"types":"./dist/types/lib.d.ts","import":"./dist/mjs/lib.mjs","require":"./dist/cjs/lib.cjs"}},"gitHead":"623b14f3fa5b65a7154193863d63e3a18c5efcf3","scripts":{"dev":"bun --hot index.html","lint":"eslint ."},"_npmUser":{"name":"ricsam","email":"oss@ricsam.dev"},"prettier":{},"_npmVersion":"10.8.2","description":"> A powerful React hook-based selection manager that makes building spreadsheet-like interfaces a breeze! ✨","directories":{},"_nodeVersion":"24.3.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"peerDependencies":{"typescript":"^5"},"_npmOperationalInternal":{"tmp":"tmp/selection-manager_0.0.5_1753890394722_0.8702858831188534","host":"s3://npm-registry-packages-npm-production"}},"0.0.6":{"name":"@ricsam/selection-manager","version":"0.0.6","_id":"@ricsam/selection-manager@0.0.6","maintainers":[{"name":"ricsam","email":"oss@ricsam.dev"}],"dist":{"shasum":"73d03485c263b32003c5f760f8c3fdb5c5e75a2c","tarball":"https://registry.npmjs.org/@ricsam/selection-manager/-/selection-manager-0.0.6.tgz","fileCount":29,"integrity":"sha512-p76BRXHUS1ylM8sH0qyoOgLMacp1B37GU4PtKvzopcv0nMNpjgNLccjLaiFN1nWypklQkwIU3R2OKeuM5utXgw==","signatures":[{"sig":"MEQCIBPbZ9F5/kUgiZF+A1mFmvnfJ8wk2E35QtE1ynBnzKnvAiAjn0AoV6/ur2HBYN+FD/wQt1ky5tw2BEgToWxpMQA4kA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":391377},"main":"./dist/cjs/lib.cjs","types":"./dist/types/lib.d.ts","module":"./dist/mjs/lib.mjs","exports":{".":{"types":"./dist/types/lib.d.ts","import":"./dist/mjs/lib.mjs","require":"./dist/cjs/lib.cjs"}},"gitHead":"1bd44553ce9fda90f12b2bcc39a493298f5055de","scripts":{"dev":"bun --hot index.html","lint":"eslint ."},"_npmUser":{"name":"ricsam","email":"oss@ricsam.dev"},"prettier":{},"_npmVersion":"10.8.2","description":"> A powerful React hook-based selection manager that makes building spreadsheet-like interfaces a breeze! ✨","directories":{},"_nodeVersion":"24.3.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"peerDependencies":{"typescript":"^5"},"_npmOperationalInternal":{"tmp":"tmp/selection-manager_0.0.6_1753962304668_0.5720577415963963","host":"s3://npm-registry-packages-npm-production"}},"0.0.7":{"name":"@ricsam/selection-manager","version":"0.0.7","_id":"@ricsam/selection-manager@0.0.7","maintainers":[{"name":"ricsam","email":"oss@ricsam.dev"}],"dist":{"shasum":"dba7786519f6444b53bb9c5b9dba35a5b081e6f7","tarball":"https://registry.npmjs.org/@ricsam/selection-manager/-/selection-manager-0.0.7.tgz","fileCount":29,"integrity":"sha512-mufjuVmJ30hM6pCsGqb0lbVpNQ8WsbHZ6p+PckKd7XB9S4a+TVsp6eySOSAaFdK9o1qkXg0bZcWCLBjEhfkscQ==","signatures":[{"sig":"MEYCIQCb8+8svEFzOcPhoBeovoOQt2hPXIrXTpRvMitqkf1qzwIhAL6Je4Rzkr3UkPWgclU318/8aV8hlnQ3giiLcU4zyau4","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":443452},"main":"./dist/cjs/lib.cjs","types":"./dist/types/lib.d.ts","module":"./dist/mjs/lib.mjs","exports":{".":{"types":"./dist/types/lib.d.ts","import":"./dist/mjs/lib.mjs","require":"./dist/cjs/lib.cjs"}},"gitHead":"13a74705089ded9ce548e88de84377394f1511f7","scripts":{"dev":"bun --hot index.html","lint":"eslint ."},"_npmUser":{"name":"ricsam","email":"oss@ricsam.dev"},"prettier":{},"_npmVersion":"10.8.2","description":"> A powerful React hook-based selection manager that makes building spreadsheet-like interfaces a breeze! ✨","directories":{},"_nodeVersion":"24.3.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"peerDependencies":{"typescript":"^5"},"_npmOperationalInternal":{"tmp":"tmp/selection-manager_0.0.7_1755678816911_0.06900113208890502","host":"s3://npm-registry-packages-npm-production"}},"0.0.8":{"name":"@ricsam/selection-manager","version":"0.0.8","_id":"@ricsam/selection-manager@0.0.8","maintainers":[{"name":"ricsam","email":"oss@ricsam.dev"}],"dist":{"shasum":"d0bf7cdb7efa7f94f70ef7e28a1c4cde8bd231aa","tarball":"https://registry.npmjs.org/@ricsam/selection-manager/-/selection-manager-0.0.8.tgz","fileCount":29,"integrity":"sha512-+RzH2YL3DPaig91JYmuzbPQ9vW+2nbRn58/Vab/9clKUIFM0e4OAl0TrClUD9zJcDBWwk2VEczVHAysfVSioaA==","signatures":[{"sig":"MEUCIQDtiWjL0iRQeeQCpcKwKTOuv1kc0A2PwpAc9NHRCAEoXQIgbkIKDTQRyE6q+lQDUNjKPIuA7xmzG8O00r59a3yY69E=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":446480},"main":"./dist/cjs/lib.cjs","types":"./dist/types/lib.d.ts","module":"./dist/mjs/lib.mjs","exports":{".":{"types":"./dist/types/lib.d.ts","import":"./dist/mjs/lib.mjs","require":"./dist/cjs/lib.cjs"}},"gitHead":"f3f261baeabe73726f19c51f522be27f8182463e","scripts":{"dev":"bun --hot index.html","lint":"eslint ."},"_npmUser":{"name":"ricsam","email":"oss@ricsam.dev"},"prettier":{},"_npmVersion":"10.8.2","description":"> A powerful React hook-based selection manager that makes building spreadsheet-like interfaces a breeze! ✨","directories":{},"_nodeVersion":"24.3.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"peerDependencies":{"typescript":"^5"},"_npmOperationalInternal":{"tmp":"tmp/selection-manager_0.0.8_1755679837962_0.9202131874130757","host":"s3://npm-registry-packages-npm-production"}},"0.0.9":{"name":"@ricsam/selection-manager","version":"0.0.9","_id":"@ricsam/selection-manager@0.0.9","maintainers":[{"name":"ricsam","email":"oss@ricsam.dev"}],"dist":{"shasum":"32ac4f31b8ecf8970dfd75590bb4f6d197d03b58","tarball":"https://registry.npmjs.org/@ricsam/selection-manager/-/selection-manager-0.0.9.tgz","fileCount":29,"integrity":"sha512-ui7VrMtE/Ur627i57bBppxMq1XVTaoNkKVsuJkBTsN6hOMKKA1v2USY4jAJYo6XZlFlwenORhGkilWpGGSSDSQ==","signatures":[{"sig":"MEUCIQCbpGkJ7RopQNBgdmwJ3gNh8s4LLsGKeAGPOieAWHCHTgIgBJbx07YzPC36ok4spt+nYtrxeXI7yepnkkWpJB4F+HM=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":506404},"main":"./dist/cjs/lib.cjs","types":"./dist/types/lib.d.ts","module":"./dist/mjs/lib.mjs","exports":{".":{"types":"./dist/types/lib.d.ts","import":"./dist/mjs/lib.mjs","require":"./dist/cjs/lib.cjs"}},"gitHead":"61de9ef3635908214b77c188a1bc06319544f64d","scripts":{"dev":"bun --hot index.html","lint":"eslint .","typecheck":"tsc --noEmit"},"_npmUser":{"name":"ricsam","email":"oss@ricsam.dev"},"prettier":{},"_npmVersion":"10.8.2","description":"> A powerful React hook-based selection manager that makes building spreadsheet-like interfaces a breeze! ✨","directories":{},"_nodeVersion":"24.3.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"peerDependencies":{"typescript":"^5"},"_npmOperationalInternal":{"tmp":"tmp/selection-manager_0.0.9_1755690938325_0.33483519283565966","host":"s3://npm-registry-packages-npm-production"}},"0.0.10":{"name":"@ricsam/selection-manager","version":"0.0.10","_id":"@ricsam/selection-manager@0.0.10","maintainers":[{"name":"ricsam","email":"oss@ricsam.dev"}],"dist":{"shasum":"0271fb6b73afb9656127cad02da71fa246affdbd","tarball":"https://registry.npmjs.org/@ricsam/selection-manager/-/selection-manager-0.0.10.tgz","fileCount":29,"integrity":"sha512-iY97Ly7HIaBW/a62Jf/efr3JvO8EvoXnQ0nf1C2I6GJ9cSKEYBD6T59UofgeXOua6DYMMk+b7jL6guw4ydzOmg==","signatures":[{"sig":"MEYCIQCFnmSvdZrwWhCawD74nof0VFeVPWhYWhvqyArNZTsasgIhAJ1PkFDUaCSN6UciFBQuiTjsemc5x197T9KmaPs84GpE","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":506567},"main":"./dist/cjs/lib.cjs","types":"./dist/types/lib.d.ts","module":"./dist/mjs/lib.mjs","exports":{".":{"types":"./dist/types/lib.d.ts","import":"./dist/mjs/lib.mjs","require":"./dist/cjs/lib.cjs"}},"gitHead":"9c7da21a8a844df5abfe650376e6ab5f2e78a3fe","scripts":{"dev":"bun --hot index.html","lint":"eslint .","typecheck":"tsc --noEmit"},"_npmUser":{"name":"ricsam","email":"oss@ricsam.dev"},"prettier":{},"_npmVersion":"10.8.2","description":"> A powerful React hook-based selection manager that makes building spreadsheet-like interfaces a breeze! ✨","directories":{},"_nodeVersion":"24.3.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"peerDependencies":{"typescript":"^5"},"_npmOperationalInternal":{"tmp":"tmp/selection-manager_0.0.10_1755696539722_0.5003347462901007","host":"s3://npm-registry-packages-npm-production"}},"0.0.11":{"name":"@ricsam/selection-manager","version":"0.0.11","_id":"@ricsam/selection-manager@0.0.11","maintainers":[{"name":"ricsam","email":"oss@ricsam.dev"}],"dist":{"shasum":"84b06493e3a6422cdabf9b8ca1773c3c62707733","tarball":"https://registry.npmjs.org/@ricsam/selection-manager/-/selection-manager-0.0.11.tgz","fileCount":29,"integrity":"sha512-LE2VfiuxU/G8orSM93lik7SM6JPZdbGvLCwO/TAJQwFkbAQrOBRTfn0u1ZftBKsOyxJ1H+qQM8IEPOufOHEStg==","signatures":[{"sig":"MEUCIFSRg86+C6Srq9qgVei04/lfytRz/VLkuRboB2riSUR5AiEAt3VlpwZ8g4pL0Cc0p//d5IV5rY/AX2A5Yb2ZVgwMrpY=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":544228},"main":"./dist/cjs/lib.cjs","types":"./dist/types/lib.d.ts","module":"./dist/mjs/lib.mjs","exports":{".":{"types":"./dist/types/lib.d.ts","import":"./dist/mjs/lib.mjs","require":"./dist/cjs/lib.cjs"}},"gitHead":"904cdb097ec61186b0f28c6bf172ae19bc1e445c","scripts":{"dev":"bun --hot index.html","lint":"eslint .","typecheck":"tsc --noEmit"},"_npmUser":{"name":"ricsam","email":"oss@ricsam.dev"},"prettier":{},"_npmVersion":"10.8.2","description":"> A powerful React hook-based selection manager that makes building spreadsheet-like interfaces a breeze! ✨","directories":{},"_nodeVersion":"24.3.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"peerDependencies":{"typescript":"^5"},"_npmOperationalInternal":{"tmp":"tmp/selection-manager_0.0.11_1757001674104_0.8042739235148006","host":"s3://npm-registry-packages-npm-production"}},"0.0.12":{"name":"@ricsam/selection-manager","version":"0.0.12","_id":"@ricsam/selection-manager@0.0.12","maintainers":[{"name":"ricsam","email":"oss@ricsam.dev"}],"dist":{"shasum":"ebdc19c282acaae47f2e19a1d150af7e1c83c566","tarball":"https://registry.npmjs.org/@ricsam/selection-manager/-/selection-manager-0.0.12.tgz","fileCount":29,"integrity":"sha512-jlMJbWJ+r9mt/YMasB8G7kRlNcVe7hqyVYWXa1jFyvc7Lcc0OdaF9y1f+xRxVtiC+oTyNAXHU07PaTk0Hw069g==","signatures":[{"sig":"MEUCIGHAl1rf6x5SYS645FrkvufwhCtg4tj0Tkn5uhyrtPLtAiEA1MTgFOKVgcPOdMaIo4nmh8yVTGp8fNU3bMHmkt+FYwE=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":535035},"main":"./dist/cjs/lib.cjs","types":"./dist/types/lib.d.ts","module":"./dist/mjs/lib.mjs","exports":{".":{"types":"./dist/types/lib.d.ts","import":"./dist/mjs/lib.mjs","require":"./dist/cjs/lib.cjs"}},"gitHead":"35721fbcfb2576cfee01e75bc80202f05438d883","scripts":{"dev":"bun --hot index.html","lint":"eslint .","typecheck":"tsc --noEmit"},"_npmUser":{"name":"ricsam","email":"oss@ricsam.dev"},"prettier":{},"_npmVersion":"10.8.2","description":"> A powerful React hook-based selection manager that makes building spreadsheet-like interfaces a breeze! ✨","directories":{},"_nodeVersion":"24.3.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"peerDependencies":{"typescript":"^5"},"_npmOperationalInternal":{"tmp":"tmp/selection-manager_0.0.12_1757057318667_0.6088512431835031","host":"s3://npm-registry-packages-npm-production"}},"0.0.13":{"name":"@ricsam/selection-manager","version":"0.0.13","_id":"@ricsam/selection-manager@0.0.13","maintainers":[{"name":"ricsam","email":"oss@ricsam.dev"}],"dist":{"shasum":"e387a8c9cba0d3ec1f8488ac94b0f290b9e2cf41","tarball":"https://registry.npmjs.org/@ricsam/selection-manager/-/selection-manager-0.0.13.tgz","fileCount":29,"integrity":"sha512-upIh5pP9WOMtDUpjXCDWLqUG+ZmM7iz0kKQa9MwI+i6I90rJmX3YtNvyEQ9geZwd0Bkfzqw+LGx3lVAZp3jh5Q==","signatures":[{"sig":"MEQCIF+czDDByoo7hD2LwkoqG3YZ4+QP8iBgWSlYpavdBpqTAiBLuUoTj/efbsLDT30rvy0wMuEM3A7lIXM/tBUACsNcAA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":553008},"main":"./dist/cjs/lib.cjs","types":"./dist/types/lib.d.ts","module":"./dist/mjs/lib.mjs","exports":{".":{"types":"./dist/types/lib.d.ts","import":"./dist/mjs/lib.mjs","require":"./dist/cjs/lib.cjs"}},"gitHead":"f913780e4236f8babefd2b22d337fb64c61a4290","scripts":{"dev":"bun --hot index.html","lint":"eslint .","typecheck":"tsc --noEmit"},"_npmUser":{"name":"ricsam","email":"oss@ricsam.dev"},"prettier":{},"_npmVersion":"10.8.2","description":"> A powerful React hook-based selection manager that makes building spreadsheet-like interfaces a breeze! ✨","directories":{},"_nodeVersion":"24.3.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"peerDependencies":{"typescript":"^5"},"_npmOperationalInternal":{"tmp":"tmp/selection-manager_0.0.13_1757325505215_0.18038185419748665","host":"s3://npm-registry-packages-npm-production"}},"0.0.14":{"name":"@ricsam/selection-manager","version":"0.0.14","_id":"@ricsam/selection-manager@0.0.14","maintainers":[{"name":"ricsam","email":"oss@ricsam.dev"}],"dist":{"shasum":"6eb28718de368c0ad4e1a3c3abe179add806b289","tarball":"https://registry.npmjs.org/@ricsam/selection-manager/-/selection-manager-0.0.14.tgz","fileCount":29,"integrity":"sha512-htUYcdT1rnKeYEz8qkOfJpXUOYdYQFqCk/yp3afsbHLCo8hHRt4MX7JJq4b7DLGjQ4nd6sZLfPo01OPYxG3g0A==","signatures":[{"sig":"MEUCIQCLibK9QMqPqS7svwtKSKRqQJf3Rff8oMtVWyQFTA90YwIgCVJW1+y2dZNfMA3WliEdROkhDnDcBtdSImdypM0dbzc=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":553333},"main":"./dist/cjs/lib.cjs","types":"./dist/types/lib.d.ts","module":"./dist/mjs/lib.mjs","exports":{".":{"types":"./dist/types/lib.d.ts","import":"./dist/mjs/lib.mjs","require":"./dist/cjs/lib.cjs"}},"gitHead":"769d556ce4c9535f255a369f41906d1070782cc3","scripts":{"dev":"bun --hot index.html","lint":"eslint .","typecheck":"tsc --noEmit"},"_npmUser":{"name":"ricsam","email":"oss@ricsam.dev"},"prettier":{},"_npmVersion":"10.8.2","description":"> A powerful React hook-based selection manager that makes building spreadsheet-like interfaces a breeze! ✨","directories":{},"_nodeVersion":"24.3.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"peerDependencies":{"typescript":"^5"},"_npmOperationalInternal":{"tmp":"tmp/selection-manager_0.0.14_1757326016487_0.9492091029215552","host":"s3://npm-registry-packages-npm-production"}},"0.0.15":{"name":"@ricsam/selection-manager","version":"0.0.15","_id":"@ricsam/selection-manager@0.0.15","maintainers":[{"name":"ricsam","email":"oss@ricsam.dev"}],"dist":{"shasum":"60c2b1f3560bb24f0c7a97d61a9444381de0d8dc","tarball":"https://registry.npmjs.org/@ricsam/selection-manager/-/selection-manager-0.0.15.tgz","fileCount":39,"integrity":"sha512-PYMRfYYZcX7RK8xlEfTvKIdKCNbhaePnYSV8WdbsPOSA2Z6vC2SwfNuSNorcvE+CNHUKgweNzzVmhEXbwIlAGw==","signatures":[{"sig":"MEUCIQDR9iN8rxFgThnvB5Ed+CVBpN7kXZ3p+Mxp3Hzvnf82bgIgA+IHKJj/iyixMslNy8xNOwdK9VqcQXokHQfHMbs7cP0=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":601581},"main":"./dist/cjs/lib.cjs","types":"./dist/types/lib.d.ts","module":"./dist/mjs/lib.mjs","exports":{".":{"types":"./dist/types/lib.d.ts","import":"./dist/mjs/lib.mjs","require":"./dist/cjs/lib.cjs"}},"gitHead":"c0a6ee686aa2808a47cfe027e22fa6ffdbb60436","scripts":{"dev":"bun --hot index.html","lint":"eslint .","typecheck":"tsc --noEmit"},"_npmUser":{"name":"ricsam","email":"oss@ricsam.dev"},"prettier":{},"_npmVersion":"10.8.2","description":"> A powerful React hook-based selection manager that makes building spreadsheet-like interfaces a breeze! ✨","directories":{},"_nodeVersion":"24.3.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"peerDependencies":{"typescript":"^5"},"_npmOperationalInternal":{"tmp":"tmp/selection-manager_0.0.15_1757338740827_0.12638978621017616","host":"s3://npm-registry-packages-npm-production"}},"0.0.16":{"name":"@ricsam/selection-manager","version":"0.0.16","_id":"@ricsam/selection-manager@0.0.16","maintainers":[{"name":"ricsam","email":"oss@ricsam.dev"}],"dist":{"shasum":"e20fe63d9ccc60ce39139cf8755dd4dda80d1daf","tarball":"https://registry.npmjs.org/@ricsam/selection-manager/-/selection-manager-0.0.16.tgz","fileCount":39,"integrity":"sha512-qAVdK6eTEXm3OV6EoK2jPgJw7A80stO//jZev6PW+73+m8ABUhB3+1886z7Vk3GkjRETK8/rs6efMgFh8SdN0w==","signatures":[{"sig":"MEUCIB/2PKhMmFeMbb9Tum3cPR5v5c/1OUPpDgHFJSu6wDPMAiEAk1lEp3fqqYIvW9+Q1pc9cU+SbUDeXCpvB/YG7zIT2bM=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":602055},"main":"./dist/cjs/lib.cjs","types":"./dist/types/lib.d.ts","module":"./dist/mjs/lib.mjs","exports":{".":{"types":"./dist/types/lib.d.ts","import":"./dist/mjs/lib.mjs","require":"./dist/cjs/lib.cjs"}},"gitHead":"afa3f9794f9b3b3bf4e4f41791ecbf605d12da22","scripts":{"dev":"bun --hot index.html","lint":"eslint .","typecheck":"tsc --noEmit"},"_npmUser":{"name":"ricsam","email":"oss@ricsam.dev"},"prettier":{},"_npmVersion":"10.8.2","description":"> A powerful React hook-based selection manager that makes building spreadsheet-like interfaces a breeze! ✨","directories":{},"_nodeVersion":"24.3.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"peerDependencies":{"typescript":"^5"},"_npmOperationalInternal":{"tmp":"tmp/selection-manager_0.0.16_1757340034590_0.5690940316303754","host":"s3://npm-registry-packages-npm-production"}},"0.0.17":{"name":"@ricsam/selection-manager","version":"0.0.17","_id":"@ricsam/selection-manager@0.0.17","maintainers":[{"name":"ricsam","email":"oss@ricsam.dev"}],"dist":{"shasum":"cf69b12f58a8ece2630fcc9acce400656973a0cd","tarball":"https://registry.npmjs.org/@ricsam/selection-manager/-/selection-manager-0.0.17.tgz","fileCount":39,"integrity":"sha512-OCsBa6POTH03kBN1V26DoSuxDhquVNcC74ZlxVNnMXwRDqjy3WQTKYS6VSPLuOt/Q0MoQhCfpnm3o1tFctYV8A==","signatures":[{"sig":"MEQCIBBLcQm3ky1dNgE723eNyQANBMdNaa4cZLBWlQ8RGO8xAiA+fksg4BRQqqyrHu2aPZQypbNNJXGzUfSO9T+LRdlbGw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":609872},"main":"./dist/cjs/lib.cjs","types":"./dist/types/lib.d.ts","module":"./dist/mjs/lib.mjs","exports":{".":{"types":"./dist/types/lib.d.ts","import":"./dist/mjs/lib.mjs","require":"./dist/cjs/lib.cjs"}},"gitHead":"d742126ad24215d6f04574ee6a9b2f9aaa1c8193","scripts":{"dev":"bun --hot index.html","lint":"eslint .","typecheck":"tsc --noEmit"},"_npmUser":{"name":"ricsam","email":"oss@ricsam.dev"},"prettier":{},"_npmVersion":"10.8.2","description":"> A powerful React hook-based selection manager that makes building spreadsheet-like interfaces a breeze! ✨","directories":{},"_nodeVersion":"24.3.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"peerDependencies":{"typescript":"^5"},"_npmOperationalInternal":{"tmp":"tmp/selection-manager_0.0.17_1757346878911_0.5863434592931411","host":"s3://npm-registry-packages-npm-production"}},"0.0.18":{"name":"@ricsam/selection-manager","version":"0.0.18","_id":"@ricsam/selection-manager@0.0.18","maintainers":[{"name":"ricsam","email":"oss@ricsam.dev"}],"dist":{"shasum":"c4bc39c37e2e2f392eba2a50b5cf0eeda68480ec","tarball":"https://registry.npmjs.org/@ricsam/selection-manager/-/selection-manager-0.0.18.tgz","fileCount":39,"integrity":"sha512-N6n60eVAEUk/Hcvqv2JCFVEhXeGGYHhSGkNr5We/v9oawMpIhlxY7utxDKI9JCZlW9dLosn+EJSMIpxL3fv9Fg==","signatures":[{"sig":"MEYCIQCIRRbxW8IFBAIjQClPq+dru94FNw9cqJ4PW8JBMJUERQIhAP+UOtI/5fPQp/L032KjE/Cq5BshYY0grORyY+B4bWRR","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":611078},"main":"./dist/cjs/lib.cjs","types":"./dist/types/lib.d.ts","module":"./dist/mjs/lib.mjs","exports":{".":{"types":"./dist/types/lib.d.ts","import":"./dist/mjs/lib.mjs","require":"./dist/cjs/lib.cjs"}},"gitHead":"fcb53b14bfb925ab1d52f0fbc0258aa3e3ce4050","scripts":{"dev":"bun --hot index.html","lint":"eslint .","typecheck":"tsc --noEmit"},"_npmUser":{"name":"ricsam","email":"oss@ricsam.dev"},"prettier":{},"_npmVersion":"10.8.2","description":"> A powerful React hook-based selection manager that makes building spreadsheet-like interfaces a breeze! ✨","directories":{},"_nodeVersion":"24.3.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"peerDependencies":{"typescript":"^5"},"_npmOperationalInternal":{"tmp":"tmp/selection-manager_0.0.18_1757347454468_0.2527091333850464","host":"s3://npm-registry-packages-npm-production"}},"0.0.19":{"name":"@ricsam/selection-manager","version":"0.0.19","_id":"@ricsam/selection-manager@0.0.19","maintainers":[{"name":"ricsam","email":"oss@ricsam.dev"}],"dist":{"shasum":"1bb880fdcf499ab25300dece8596b1ee27a7a786","tarball":"https://registry.npmjs.org/@ricsam/selection-manager/-/selection-manager-0.0.19.tgz","fileCount":39,"integrity":"sha512-Y5Vukwit2WnZcT/0K0KLCgInRydZYeRU8uZZ4gygmu5hnr6g+ChtV9/xBvZ1ijJVNqL2S7ZFX++TN5uLoPukSg==","signatures":[{"sig":"MEQCIFvy+DMvyXRaHtUaijJtUTw9FtQRAxtxDgGVJXMb0dVGAiBZuk0Fo0UIsqbf1eBFAAWvXVjmox41SPZzGWg7thxhlg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":615728},"main":"./dist/cjs/lib.cjs","types":"./dist/types/lib.d.ts","module":"./dist/mjs/lib.mjs","exports":{".":{"types":"./dist/types/lib.d.ts","import":"./dist/mjs/lib.mjs","require":"./dist/cjs/lib.cjs"}},"gitHead":"8e2cd4b487f0d33858977bb079470e454957495e","scripts":{"dev":"bun --hot index.html","lint":"eslint .","typecheck":"tsc --noEmit"},"_npmUser":{"name":"ricsam","email":"oss@ricsam.dev"},"prettier":{},"_npmVersion":"10.8.2","description":"> A powerful React hook-based selection manager that makes building spreadsheet-like interfaces a breeze! ✨","directories":{},"_nodeVersion":"24.3.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"peerDependencies":{"typescript":"^5"},"_npmOperationalInternal":{"tmp":"tmp/selection-manager_0.0.19_1762523014656_0.13293234269089482","host":"s3://npm-registry-packages-npm-production"}},"0.0.20":{"name":"@ricsam/selection-manager","version":"0.0.20","_id":"@ricsam/selection-manager@0.0.20","maintainers":[{"name":"ricsam","email":"oss@ricsam.dev"}],"dist":{"shasum":"353655499dcf2a929be069c1e528aa1111efd219","tarball":"https://registry.npmjs.org/@ricsam/selection-manager/-/selection-manager-0.0.20.tgz","fileCount":39,"integrity":"sha512-2eikSM3p05Z3EdGujkNPB3PKzT2h2HoMoEmvo6tXsjjPMW9DWKBMnq46s4JH6RVAaOlKZV4HQdNTZf1zquXkgQ==","signatures":[{"sig":"MEUCIQCanjvoBVJV9iaxgIFFsrjaGvDas5F2H4f/c45b1cOAIQIgef3TvStLr5nJnq66SPVto2hP3J9UtEI6TGd414Bborc=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":618281},"main":"./dist/cjs/lib.cjs","types":"./dist/types/lib.d.ts","module":"./dist/mjs/lib.mjs","exports":{".":{"types":"./dist/types/lib.d.ts","import":"./dist/mjs/lib.mjs","require":"./dist/cjs/lib.cjs"}},"gitHead":"5f16334e299ac9d66c751ec9771f5ab24c98cb6f","scripts":{"dev":"bun --hot index.html","lint":"eslint .","typecheck":"tsc --noEmit"},"_npmUser":{"name":"ricsam","email":"oss@ricsam.dev"},"prettier":{},"_npmVersion":"10.8.2","description":"> A powerful React hook-based selection manager that makes building spreadsheet-like interfaces a breeze! ✨","directories":{},"_nodeVersion":"24.3.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"peerDependencies":{"typescript":"^5"},"_npmOperationalInternal":{"tmp":"tmp/selection-manager_0.0.20_1763566787679_0.8022776308137145","host":"s3://npm-registry-packages-npm-production"}},"0.0.21":{"name":"@ricsam/selection-manager","version":"0.0.21","_id":"@ricsam/selection-manager@0.0.21","maintainers":[{"name":"ricsam","email":"oss@ricsam.dev"}],"dist":{"shasum":"e886f6a7342b77e32f6e0ab7cd43571eb4e44e46","tarball":"https://registry.npmjs.org/@ricsam/selection-manager/-/selection-manager-0.0.21.tgz","fileCount":39,"integrity":"sha512-JVGELsVm7Gx/1d3gp8pjOaqwqf2k4QH7yHZSC9AlCMXAEVwb1PdPAuxGEvSYwxDHED6HusApce8a+uzs07+rbA==","signatures":[{"sig":"MEUCIDixXSx7xB0erpbFhVUhxoMyGuT8MusPBEECNgFLOn1AAiEA4hjKljNaW/rnWnm3KvE2NX0vmqVvXxo7UDqNuh0Fvto=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":619141},"main":"./dist/cjs/lib.cjs","types":"./dist/types/lib.d.ts","module":"./dist/mjs/lib.mjs","exports":{".":{"types":"./dist/types/lib.d.ts","import":"./dist/mjs/lib.mjs","require":"./dist/cjs/lib.cjs"}},"gitHead":"b8c7226f77d8f3e7b6960bba4954430632cd4e1c","scripts":{"dev":"bun --hot index.html","lint":"eslint .","typecheck":"tsc --noEmit"},"_npmUser":{"name":"ricsam","email":"oss@ricsam.dev"},"prettier":{},"_npmVersion":"10.8.2","description":"> A powerful React hook-based selection manager that makes building spreadsheet-like interfaces a breeze! ✨","directories":{},"_nodeVersion":"24.3.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"peerDependencies":{"typescript":"^5"},"_npmOperationalInternal":{"tmp":"tmp/selection-manager_0.0.21_1763632736550_0.2361617623432679","host":"s3://npm-registry-packages-npm-production"}},"0.0.22":{"name":"@ricsam/selection-manager","version":"0.0.22","_id":"@ricsam/selection-manager@0.0.22","maintainers":[{"name":"ricsam","email":"oss@ricsam.dev"}],"dist":{"shasum":"cd80c541a64be48e9f0f9d8d956fe14811dacfc6","tarball":"https://registry.npmjs.org/@ricsam/selection-manager/-/selection-manager-0.0.22.tgz","fileCount":39,"integrity":"sha512-/T02U2FtAyoxUC6PO2K2WbsK7QM8iysyusAFLHQ5jkvNlEPCiklNah/rjFIGfskyvwaRwNPd20hdXmN2d6QqHA==","signatures":[{"sig":"MEUCIQDGtRFSKN6Fs0qeDsBbu6NllItJDuInwBcrvJi5DAi74gIgfcwUmE4cGppyYlJDIBzvEN69bZkHmzS1r1Julot0Xms=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":619350},"main":"./dist/cjs/lib.cjs","types":"./dist/types/lib.d.ts","module":"./dist/mjs/lib.mjs","exports":{".":{"types":"./dist/types/lib.d.ts","import":"./dist/mjs/lib.mjs","require":"./dist/cjs/lib.cjs"}},"gitHead":"ed9122ed826153bfe4c9dba8998b2bc9ab798076","scripts":{"dev":"bun --hot index.html","lint":"eslint .","typecheck":"tsc --noEmit"},"_npmUser":{"name":"ricsam","email":"oss@ricsam.dev"},"prettier":{},"_npmVersion":"10.8.2","description":"> A powerful React hook-based selection manager that makes building spreadsheet-like interfaces a breeze! ✨","directories":{},"_nodeVersion":"24.3.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"peerDependencies":{"typescript":"^5"},"_npmOperationalInternal":{"tmp":"tmp/selection-manager_0.0.22_1763640593388_0.8633249025302727","host":"s3://npm-registry-packages-npm-production"}},"0.0.23":{"name":"@ricsam/selection-manager","version":"0.0.23","_id":"@ricsam/selection-manager@0.0.23","maintainers":[{"name":"ricsam","email":"oss@ricsam.dev"}],"dist":{"shasum":"62357dc8a71a3db8262d9bc22ffd26f16324b6f0","tarball":"https://registry.npmjs.org/@ricsam/selection-manager/-/selection-manager-0.0.23.tgz","fileCount":39,"integrity":"sha512-flq1ZzxoGIMqXIGIQvWQ+gS3GIT9iKYES59Z3NnAxvXb6BkoNzzCmaJD7fr4OZ4MZidwG1inwnQZKudE9Yb1pg==","signatures":[{"sig":"MEUCIGuvTd9E4W+UZN1/ENFA4eAFgn5zhcBQtcIfTGDa2rz8AiEAhrFrmX9gKfY9zRZZFnG2UDWrcpI1Vy038BmNermgjCI=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":619222},"main":"./dist/cjs/lib.cjs","types":"./dist/types/lib.d.ts","module":"./dist/mjs/lib.mjs","exports":{".":{"types":"./dist/types/lib.d.ts","import":"./dist/mjs/lib.mjs","require":"./dist/cjs/lib.cjs"}},"gitHead":"277143456a238a4ab56722a887df8b1dbede4fcf","scripts":{"dev":"bun --hot index.html","lint":"eslint .","typecheck":"tsc --noEmit"},"_npmUser":{"name":"ricsam","email":"oss@ricsam.dev"},"prettier":{},"_npmVersion":"10.8.2","description":"> A powerful React hook-based selection manager that makes building spreadsheet-like interfaces a breeze! ✨","directories":{},"_nodeVersion":"24.3.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"peerDependencies":{"typescript":"^5"},"_npmOperationalInternal":{"tmp":"tmp/selection-manager_0.0.23_1763653614499_0.7602635201691064","host":"s3://npm-registry-packages-npm-production"}},"0.0.24":{"name":"@ricsam/selection-manager","version":"0.0.24","_id":"@ricsam/selection-manager@0.0.24","maintainers":[{"name":"ricsam","email":"oss@ricsam.dev"}],"dist":{"shasum":"71041a6c4631765824a6be2c5bb8ba3babbe340e","tarball":"https://registry.npmjs.org/@ricsam/selection-manager/-/selection-manager-0.0.24.tgz","fileCount":39,"integrity":"sha512-dr9cwuLspecgDBLlwNx7lZ5K19ebYIHAauj/IIn5p7RYW7Q5T8oWeruh4aSkFRDyXiW5e51j1UQmCY84yZA+5w==","signatures":[{"sig":"MEYCIQD0LhR6Z2NDpNg8GOaWrH6+eAWbEmG3ZrHyex19LzndjAIhAPsmcvSw6CFjE/j6dIjiIhZ38FvIueKS33zvobMJnNUx","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":620103},"main":"./dist/cjs/lib.cjs","types":"./dist/types/lib.d.ts","module":"./dist/mjs/lib.mjs","exports":{".":{"types":"./dist/types/lib.d.ts","import":"./dist/mjs/lib.mjs","require":"./dist/cjs/lib.cjs"}},"gitHead":"abf48fcf96dcdf12cf7095ba71c704f6f48f4bae","scripts":{"dev":"bun --hot index.html","lint":"eslint .","typecheck":"tsc --noEmit"},"_npmUser":{"name":"ricsam","email":"oss@ricsam.dev"},"prettier":{},"_npmVersion":"10.8.2","description":"> A powerful React hook-based selection manager that makes building spreadsheet-like interfaces a breeze! ✨","directories":{},"_nodeVersion":"24.3.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"peerDependencies":{"typescript":"^5"},"_npmOperationalInternal":{"tmp":"tmp/selection-manager_0.0.24_1764086585206_0.6040741933982874","host":"s3://npm-registry-packages-npm-production"}},"0.0.25":{"name":"@ricsam/selection-manager","version":"0.0.25","_id":"@ricsam/selection-manager@0.0.25","maintainers":[{"name":"ricsam","email":"oss@ricsam.dev"}],"dist":{"shasum":"dabede7ed9ba1625d21996f188314e4f0d79503a","tarball":"https://registry.npmjs.org/@ricsam/selection-manager/-/selection-manager-0.0.25.tgz","fileCount":39,"integrity":"sha512-Oddw4g1oTJrbL8Of9vqTzKYCA20FqR9KQKCLF5pS5NOdgzIkU6tCmcJwEMbHZ6RKFVTMfw++Z6NX1b43H+5Crw==","signatures":[{"sig":"MEUCIBbXJloLfHa7YcZhHWWN+Cnw0YfAtmIQg1mM2Yptg6fAAiEA/yYQS1Se/Y68m80dps/EjNsid4FZvU5onIEbeQVorio=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":622228},"main":"./dist/cjs/lib.cjs","types":"./dist/types/lib.d.ts","module":"./dist/mjs/lib.mjs","exports":{".":{"types":"./dist/types/lib.d.ts","import":"./dist/mjs/lib.mjs","require":"./dist/cjs/lib.cjs"}},"gitHead":"041dee1c4475198250796b8155e5b33384e8ed68","scripts":{"dev":"bun --hot index.html","lint":"eslint .","typecheck":"tsc --noEmit"},"_npmUser":{"name":"ricsam","email":"oss@ricsam.dev"},"prettier":{},"_npmVersion":"10.8.2","description":"> A powerful React hook-based selection manager that makes building spreadsheet-like interfaces a breeze! ✨","directories":{},"_nodeVersion":"24.3.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"peerDependencies":{"typescript":"^5"},"_npmOperationalInternal":{"tmp":"tmp/selection-manager_0.0.25_1764344501415_0.6503544444988356","host":"s3://npm-registry-packages-npm-production"}},"0.0.26":{"name":"@ricsam/selection-manager","version":"0.0.26","keywords":["selection","grid","table","spreadsheet","react","hook","excel","copy-paste","keyboard-navigation","data-grid"],"author":{"name":"ricsam","email":"oss@ricsam.dev"},"license":"MIT","_id":"@ricsam/selection-manager@0.0.26","maintainers":[{"name":"ricsam","email":"oss@ricsam.dev"}],"homepage":"https://github.com/ricsam/selection-manager#readme","bugs":{"url":"https://github.com/ricsam/selection-manager/issues"},"dist":{"shasum":"ef68a46d5b811da1c33bef6342b87cd70809a5c6","tarball":"https://registry.npmjs.org/@ricsam/selection-manager/-/selection-manager-0.0.26.tgz","fileCount":39,"integrity":"sha512-E+llhCNpQMYP/WMhEzQhEES1/45oBjJni0D3YdaRjtVS/nNySq6a+NR6tYCnPo2zZ73LqOtzGGEHO4sEg32dOg==","signatures":[{"sig":"MEUCIDW5tzoPbqZlLLry7t4rCccUf3I3j+ay8ese3pKb2SRwAiEArRcCxbk8cm9ftt8YYl+D6pS0/J1qYM5athBLgm0izVY=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@ricsam%2fselection-manager@0.0.26","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":641179},"main":"./dist/cjs/lib.cjs","types":"./dist/types/lib.d.ts","module":"./dist/mjs/lib.mjs","exports":{".":{"types":"./dist/types/lib.d.ts","import":"./dist/mjs/lib.mjs","require":"./dist/cjs/lib.cjs"}},"gitHead":"711574178a86aa52956feacffc29ddc2edeb909c","scripts":{"dev":"bun --hot index.html","lint":"eslint .","typecheck":"tsc --noEmit","install:local":"bun scripts/install-local-build.ts"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:efcc4999-75b1-4999-a53e-fc853684440a"}},"prettier":{},"repository":{"url":"git+https://github.com/ricsam/selection-manager.git","type":"git"},"_npmVersion":"11.12.1","description":"A selection manager for building spreadsheet-like React grids with keyboard navigation, editing, copy/paste, and fill-handle interactions.","directories":{},"_nodeVersion":"20.20.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"peerDependencies":{"typescript":"^5"},"_npmOperationalInternal":{"tmp":"tmp/selection-manager_0.0.26_1776766858035_0.9101860915113014","host":"s3://npm-registry-packages-npm-production"}},"0.0.27":{"name":"@ricsam/selection-manager","version":"0.0.27","keywords":["selection","grid","table","spreadsheet","react","hook","excel","copy-paste","keyboard-navigation","data-grid"],"author":{"name":"ricsam","email":"oss@ricsam.dev"},"license":"MIT","_id":"@ricsam/selection-manager@0.0.27","maintainers":[{"name":"ricsam","email":"oss@ricsam.dev"}],"homepage":"https://github.com/ricsam/selection-manager#readme","bugs":{"url":"https://github.com/ricsam/selection-manager/issues"},"dist":{"shasum":"de2561fc57df12b9dc5146d5788aff22e83f7062","tarball":"https://registry.npmjs.org/@ricsam/selection-manager/-/selection-manager-0.0.27.tgz","fileCount":39,"integrity":"sha512-b7lNgiKlIhPQ20QZconJH6nAiuh/blSgeHzR8Rz+ZpKbRVZ3gmm3kOyfU7sPhwsctTCXrOmTzxNqIupBUVy5og==","signatures":[{"sig":"MEUCIE0jgU9F2u6Xzu3IhOEmc6TI6xJrH+vKrw9orLLMc6ycAiEA6gCmBlegj3NsuI5VN4+AVs96faMA2dAZhWB8JWFoaHI=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@ricsam%2fselection-manager@0.0.27","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":651397},"main":"./dist/cjs/lib.cjs","types":"./dist/types/lib.d.ts","module":"./dist/mjs/lib.mjs","exports":{".":{"types":"./dist/types/lib.d.ts","import":"./dist/mjs/lib.mjs","require":"./dist/cjs/lib.cjs"}},"gitHead":"adfff555dac2f51b5c225cda5f3bfaa8c930d86a","scripts":{"dev":"bun --hot index.html","lint":"eslint .","typecheck":"tsc --noEmit","install:local":"bun scripts/install-local-build.ts"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:efcc4999-75b1-4999-a53e-fc853684440a"}},"prettier":{},"repository":{"url":"git+https://github.com/ricsam/selection-manager.git","type":"git"},"_npmVersion":"11.13.0","description":"A selection manager for building spreadsheet-like React grids with keyboard navigation, editing, copy/paste, and fill-handle interactions.","directories":{},"_nodeVersion":"20.20.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"peerDependencies":{"typescript":"^5"},"_npmOperationalInternal":{"tmp":"tmp/selection-manager_0.0.27_1777302664426_0.35712183753785887","host":"s3://npm-registry-packages-npm-production"}},"0.0.28":{"name":"@ricsam/selection-manager","version":"0.0.28","keywords":["selection","grid","table","spreadsheet","react","hook","excel","copy-paste","keyboard-navigation","data-grid"],"author":{"name":"ricsam","email":"oss@ricsam.dev"},"license":"MIT","_id":"@ricsam/selection-manager@0.0.28","maintainers":[{"name":"ricsam","email":"oss@ricsam.dev"}],"homepage":"https://github.com/ricsam/selection-manager#readme","bugs":{"url":"https://github.com/ricsam/selection-manager/issues"},"dist":{"shasum":"bd820620dd4616691231a671516338464e18506e","tarball":"https://registry.npmjs.org/@ricsam/selection-manager/-/selection-manager-0.0.28.tgz","fileCount":39,"integrity":"sha512-BUWu1kb8J34H882uK16aLO/zu18B5zq/Y1c5rRq3Vu/fcgkAwiML9mT2G2dZaod7OwHd9rlUG6neH8ITn/8P1A==","signatures":[{"sig":"MEQCIC2QTLEo6lImox5RlnYUI2HnnOj6+5bEK37BcNwDWG6rAiAHM/f4CcCJKTjXPzpnctzFwFnnQTkjyz8lBzyQFPBCWA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@ricsam%2fselection-manager@0.0.28","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":652445},"main":"./dist/cjs/lib.cjs","types":"./dist/types/lib.d.ts","module":"./dist/mjs/lib.mjs","exports":{".":{"types":"./dist/types/lib.d.ts","import":"./dist/mjs/lib.mjs","require":"./dist/cjs/lib.cjs"}},"gitHead":"d04b2fe043eff2b8e70a06bc6f0cee31e436b531","scripts":{"dev":"bun --hot index.html","lint":"eslint .","typecheck":"tsc --noEmit","install:local":"bun scripts/install-local-build.ts"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:efcc4999-75b1-4999-a53e-fc853684440a"}},"prettier":{},"repository":{"url":"git+https://github.com/ricsam/selection-manager.git","type":"git"},"_npmVersion":"11.16.0","description":"A selection manager for building spreadsheet-like React grids with keyboard navigation, editing, copy/paste, and fill-handle interactions.","directories":{},"_nodeVersion":"20.20.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"peerDependencies":{"typescript":"^5"},"_npmOperationalInternal":{"tmp":"tmp/selection-manager_0.0.28_1780658539636_0.12068658473436056","host":"s3://npm-registry-packages-npm-production"}},"0.0.29":{"name":"@ricsam/selection-manager","version":"0.0.29","keywords":["selection","grid","table","spreadsheet","react","hook","excel","copy-paste","keyboard-navigation","data-grid"],"author":{"name":"ricsam","email":"oss@ricsam.dev"},"license":"MIT","_id":"@ricsam/selection-manager@0.0.29","maintainers":[{"name":"ricsam","email":"oss@ricsam.dev"}],"homepage":"https://github.com/ricsam/selection-manager#readme","bugs":{"url":"https://github.com/ricsam/selection-manager/issues"},"dist":{"shasum":"84c4078fc4e9946e7798489875869f3eb6466e0f","tarball":"https://registry.npmjs.org/@ricsam/selection-manager/-/selection-manager-0.0.29.tgz","fileCount":39,"integrity":"sha512-pclCol6NDXTOGi7VAWSaryIiRbzs+qUEarUEOsgoR4TNHTQsuuRCuqYQDUy3ikhYm/g7dSR5taHefXcrI4SCvg==","signatures":[{"sig":"MEUCIQD1AJnCeWxpNMcfiNxy9EFjU2lvmVUo+CcPy7TP3OFiPQIgBUHvOWd7yXRovtz6V5UhE6ioDJnO+k3Xtp0XtXc1n7k=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@ricsam%2fselection-manager@0.0.29","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":725510},"main":"./dist/cjs/lib.cjs","types":"./dist/types/lib.d.ts","module":"./dist/mjs/lib.mjs","exports":{".":{"types":"./dist/types/lib.d.ts","import":"./dist/mjs/lib.mjs","require":"./dist/cjs/lib.cjs"}},"gitHead":"d2616bbc85cdd10868ffa62968afc0c7111f9458","scripts":{"dev":"bun --hot index.html","lint":"eslint .","typecheck":"tsc --noEmit","install:local":"bun scripts/install-local-build.ts"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:efcc4999-75b1-4999-a53e-fc853684440a"}},"prettier":{},"repository":{"url":"git+https://github.com/ricsam/selection-manager.git","type":"git"},"_npmVersion":"11.17.0","description":"A selection manager for building spreadsheet-like React grids with keyboard navigation, editing, copy/paste, and fill-handle interactions.","directories":{},"_nodeVersion":"24.19.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"peerDependencies":{"typescript":"^5"},"_npmOperationalInternal":{"tmp":"tmp/selection-manager_0.0.29_1788355906279_0.22571571846948713","host":"s3://npm-registry-packages-npm-production"}},"0.0.30":{"name":"@ricsam/selection-manager","version":"0.0.30","keywords":["selection","grid","table","spreadsheet","react","hook","excel","copy-paste","keyboard-navigation","data-grid"],"author":{"name":"ricsam","email":"oss@ricsam.dev"},"license":"MIT","_id":"@ricsam/selection-manager@0.0.30","maintainers":[{"name":"ricsam","email":"oss@ricsam.dev"}],"homepage":"https://github.com/ricsam/selection-manager#readme","bugs":{"url":"https://github.com/ricsam/selection-manager/issues"},"dist":{"shasum":"bc74e524e6a204ee74273aa783e433f2341dc521","tarball":"https://registry.npmjs.org/@ricsam/selection-manager/-/selection-manager-0.0.30.tgz","fileCount":39,"integrity":"sha512-4z54rjeYa0MIO8P6s7JY49UYnSYwLwavxnNwv8p3AHwqqQQpMSS/HcenzHOJDeG1LV90oClQXwCUFCFE/B3/FQ==","signatures":[{"sig":"MEUCIQCMC9XSi01h9ytRxdevYBgr+YoXPnAgIqKA6eZgnNqgwQIgflYvDWC1UEBh3OZFXnzWJuon3haI667r3JdYAWZlXcY=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@ricsam%2fselection-manager@0.0.30","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":726930},"main":"./dist/cjs/lib.cjs","types":"./dist/types/lib.d.ts","module":"./dist/mjs/lib.mjs","exports":{".":{"types":"./dist/types/lib.d.ts","import":"./dist/mjs/lib.mjs","require":"./dist/cjs/lib.cjs"}},"gitHead":"ac191007f34e4f0c1c534c6cef19dc2c61fb7622","scripts":{"dev":"bun --hot index.html","lint":"eslint .","typecheck":"tsc --noEmit","install:local":"bun scripts/install-local-build.ts"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:efcc4999-75b1-4999-a53e-fc853684440a"}},"prettier":{},"repository":{"url":"git+https://github.com/ricsam/selection-manager.git","type":"git"},"_npmVersion":"11.17.0","description":"A selection manager for building spreadsheet-like React grids with keyboard navigation, editing, copy/paste, and fill-handle interactions.","directories":{},"_nodeVersion":"24.19.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"peerDependencies":{"typescript":"^5"},"_npmOperationalInternal":{"tmp":"tmp/selection-manager_0.0.30_1788357348917_0.6314164953710211","host":"s3://npm-registry-packages-npm-production"}},"0.0.31":{"name":"@ricsam/selection-manager","version":"0.0.31","keywords":["selection","grid","table","spreadsheet","react","hook","excel","copy-paste","keyboard-navigation","data-grid"],"author":{"name":"ricsam","email":"oss@ricsam.dev"},"license":"MIT","_id":"@ricsam/selection-manager@0.0.31","maintainers":[{"name":"ricsam","email":"oss@ricsam.dev"}],"homepage":"https://github.com/ricsam/selection-manager#readme","bugs":{"url":"https://github.com/ricsam/selection-manager/issues"},"dist":{"shasum":"2740e127ed4d9da2e2e089eca743a826a585628a","tarball":"https://registry.npmjs.org/@ricsam/selection-manager/-/selection-manager-0.0.31.tgz","fileCount":39,"integrity":"sha512-zZJ3LuGpQeT8CHrmk4o5eXz9omWlUgh4yTc31eFc2kxbXutdqpfBMRyVDLEHiDKy9taBlsI5B2AQCgWuMNTdxg==","signatures":[{"sig":"MEUCIDFu6XzoW7PFX6/u6dDLt08laG7PZaKEwA1L9Lj3854JAiEA5gMFlt5fgmLWADsDB5hgBecUlIzbX5xvb06btz3JBzM=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@ricsam%2fselection-manager@0.0.31","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":730809},"main":"./dist/cjs/lib.cjs","types":"./dist/types/lib.d.ts","module":"./dist/mjs/lib.mjs","exports":{".":{"types":"./dist/types/lib.d.ts","import":"./dist/mjs/lib.mjs","require":"./dist/cjs/lib.cjs"}},"gitHead":"8ee17856ebfa69c667b71b8556dd9d53d703ad7d","scripts":{"dev":"bun --hot index.html","lint":"eslint .","typecheck":"tsc --noEmit","install:local":"bun scripts/install-local-build.ts"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:efcc4999-75b1-4999-a53e-fc853684440a"}},"prettier":{},"repository":{"url":"git+https://github.com/ricsam/selection-manager.git","type":"git"},"_npmVersion":"11.17.0","description":"A selection manager for building spreadsheet-like React grids with keyboard navigation, editing, copy/paste, and fill-handle interactions.","directories":{},"_nodeVersion":"24.19.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"peerDependencies":{"typescript":"^5"},"_npmOperationalInternal":{"tmp":"tmp/selection-manager_0.0.31_1788446507685_0.26798321980595596","host":"s3://npm-registry-packages-npm-production"}},"0.0.32":{"name":"@ricsam/selection-manager","version":"0.0.32","keywords":["selection","grid","table","spreadsheet","react","hook","excel","copy-paste","keyboard-navigation","data-grid"],"author":{"name":"ricsam","email":"oss@ricsam.dev"},"license":"MIT","_id":"@ricsam/selection-manager@0.0.32","maintainers":[{"name":"ricsam","email":"oss@ricsam.dev"}],"homepage":"https://github.com/ricsam/selection-manager#readme","bugs":{"url":"https://github.com/ricsam/selection-manager/issues"},"dist":{"shasum":"d656fa2bd8c2ab9b753ba49750083c9f3a5b4d30","tarball":"https://registry.npmjs.org/@ricsam/selection-manager/-/selection-manager-0.0.32.tgz","fileCount":39,"integrity":"sha512-MThLJICvQxgGwWad/joeQNx7D9obT3JVAxXJtkb9Fn1lC9GAQl8Ils4SF5RW4PWnhOPWYtxEXHcKVLHTFQ56Zw==","signatures":[{"sig":"MEUCICslSoOOMJWeb7gZyidzlbKvog6l7C+1Iaxmia8Rtj04AiEA79lSIerXMSMYZ9IbpWRe/CflNvwtt7nYMR6uMnaYzPY=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEQCICKHUpuOnmb1OAgPO+VnIBS+Zqxlpr+kf7UZ2k5AXBIFAiBX1rFN0Pu3zrH01RfUTL+h5O+KfToGiC7fUGRICxNO/g==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@ricsam%2fselection-manager@0.0.32","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":734487},"main":"./dist/cjs/lib.cjs","types":"./dist/types/lib.d.ts","module":"./dist/mjs/lib.mjs","exports":{".":{"types":"./dist/types/lib.d.ts","import":"./dist/mjs/lib.mjs","require":"./dist/cjs/lib.cjs"}},"gitHead":"3e38004458f2945ebf481fb3217c736636ec3bde","scripts":{"dev":"bun --hot index.html","lint":"eslint .","typecheck":"tsc --noEmit","install:local":"bun scripts/install-local-build.ts"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:efcc4999-75b1-4999-a53e-fc853684440a"}},"prettier":{},"repository":{"url":"git+https://github.com/ricsam/selection-manager.git","type":"git"},"_npmVersion":"11.17.0","description":"A selection manager for building spreadsheet-like React grids with keyboard navigation, editing, copy/paste, and fill-handle interactions.","directories":{},"_nodeVersion":"24.19.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"peerDependencies":{"typescript":"^5"},"_npmOperationalInternal":{"tmp":"tmp/selection-manager_0.0.32_1788457576276_0.9781881421151934","host":"s3://npm-registry-packages-npm-production"}},"0.0.33":{"_id":"@ricsam/selection-manager@0.0.33","bugs":{"url":"https://github.com/ricsam/selection-manager/issues"},"dist":{"shasum":"0f55ecaaa9d9e3b55be63b9274648f0f6efa1138","tarball":"https://registry.npmjs.org/@ricsam/selection-manager/-/selection-manager-0.0.33.tgz","fileCount":39,"integrity":"sha512-vBbWhyMJtSoWzFX4wdcle56/87VOPs+JTyOJRKW+vjdlmlTnjAtjlxfN8JFK+kGo43+bh+SaMzsecawpK1PplA==","signatures":[{"sig":"MEYCIQCVBop9T3s59inBLnyRT+1rjMX7UvkaW/xL3NFybB17wAIhAMqbHzb+0xQDkV6E4eJSYLTWWQUg8fmWmM1RbkQPqMAt","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQDDQv5f31R4FKtAABOuJ23rFsjTYEgK06ttQltJbuOldAIhAJNxkoLjDNXqUeaCzPBCzpukTMbsb04GSmVrBOO3oAWW"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@ricsam%2fselection-manager@0.0.33","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":747945},"main":"./dist/cjs/lib.cjs","name":"@ricsam/selection-manager","types":"./dist/types/lib.d.ts","author":{"name":"ricsam","email":"oss@ricsam.dev"},"module":"./dist/mjs/lib.mjs","exports":{".":{"types":"./dist/types/lib.d.ts","import":"./dist/mjs/lib.mjs","require":"./dist/cjs/lib.cjs"}},"gitHead":"2ed0e32284e8ff4764b3be0770f1249ca7f5ce96","license":"MIT","scripts":{"dev":"bun --hot index.html","lint":"eslint .","typecheck":"tsc --noEmit","install:local":"bun scripts/install-local-build.ts"},"version":"0.0.33","_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:efcc4999-75b1-4999-a53e-fc853684440a"}},"homepage":"https://github.com/ricsam/selection-manager#readme","keywords":["selection","grid","table","spreadsheet","react","hook","excel","copy-paste","keyboard-navigation","data-grid"],"prettier":{},"repository":{"url":"git+https://github.com/ricsam/selection-manager.git","type":"git"},"_npmVersion":"11.17.0","description":"A selection manager for building spreadsheet-like React grids with keyboard navigation, editing, copy/paste, and fill-handle interactions.","directories":{},"maintainers":[{"name":"ricsam","email":"oss@ricsam.dev"}],"_nodeVersion":"24.19.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"peerDependencies":{"typescript":"^5"},"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/selection-manager_0.0.33_1788515216497_0.962597661713716"}}},"time":{"created":"2025-07-07T09:30:48.581Z","modified":"2026-09-04T09:46:56.969Z","0.0.1":"2025-07-07T09:30:48.880Z","0.0.2":"2025-07-07T15:57:15.260Z","0.0.3":"2025-07-24T15:58:50.487Z","0.0.4":"2025-07-29T09:30:46.850Z","0.0.5":"2025-07-30T15:46:35.033Z","0.0.6":"2025-07-31T11:45:04.900Z","0.0.7":"2025-08-20T08:33:37.096Z","0.0.8":"2025-08-20T08:50:38.163Z","0.0.9":"2025-08-20T11:55:38.537Z","0.0.10":"2025-08-20T13:28:59.927Z","0.0.11":"2025-09-04T16:01:14.349Z","0.0.12":"2025-09-05T07:28:38.844Z","0.0.13":"2025-09-08T09:58:25.393Z","0.0.14":"2025-09-08T10:06:56.644Z","0.0.15":"2025-09-08T13:39:01.046Z","0.0.16":"2025-09-08T14:00:34.774Z","0.0.17":"2025-09-08T15:54:39.134Z","0.0.18":"2025-09-08T16:04:14.672Z","0.0.19":"2025-11-07T13:43:34.856Z","0.0.20":"2025-11-19T15:39:47.886Z","0.0.21":"2025-11-20T09:58:56.759Z","0.0.22":"2025-11-20T12:09:53.589Z","0.0.23":"2025-11-20T15:46:54.696Z","0.0.24":"2025-11-25T16:03:05.402Z","0.0.25":"2025-11-28T15:41:41.637Z","0.0.26":"2026-04-21T10:20:58.214Z","0.0.27":"2026-04-27T15:11:04.765Z","0.0.28":"2026-06-05T11:22:19.793Z","0.0.29":"2026-09-02T13:31:46.420Z","0.0.30":"2026-09-02T13:55:49.064Z","0.0.31":"2026-09-03T14:41:47.848Z","0.0.32":"2026-09-03T17:46:16.373Z","0.0.33":"2026-09-04T09:46:56.605Z"},"bugs":{"url":"https://github.com/ricsam/selection-manager/issues"},"author":{"name":"ricsam","email":"oss@ricsam.dev"},"license":"MIT","homepage":"https://github.com/ricsam/selection-manager#readme","keywords":["selection","grid","table","spreadsheet","react","hook","excel","copy-paste","keyboard-navigation","data-grid"],"repository":{"url":"git+https://github.com/ricsam/selection-manager.git","type":"git"},"description":"A selection manager for building spreadsheet-like React grids with keyboard navigation, editing, copy/paste, and fill-handle interactions.","maintainers":[{"name":"ricsam","email":"oss@ricsam.dev"}],"readme":"# 🎯 Selection Manager\n\n> A powerful React hook-based selection manager that makes building spreadsheet-like interfaces a breeze! ✨\n\nTransform any grid into an Excel-like powerhouse with intuitive multi-selection, keyboard navigation, copy/paste operations, and blazing-fast performance. Whether you're building the next Google Sheets or just need some fancy data tables, SelectionManager has got you covered! 🚀\n\n## ✨ Features That'll Make You Smile\n\n- 🎯 **Multi-selection magic** - Select ranges like a pro with Ctrl/Cmd + click\n- ⌨️ **Keyboard ninja mode** - Arrow keys, shortcuts, and everything you'd expect\n- 🖱️ **Mouse interactions** - Click, drag, double-click to edit - it just works!\n- ✏️ **Cell editing** - F2 or double-click for instant editing with smart keyboard handling\n- 🎨 **Visual feedback** - Beautiful borders and shadows that make selections pop\n- 🖱️ **Hover detection** - Know exactly which cells and headers users are hovering over\n- 🔗 **Merged cell support** - Handle grouped/merged cells like a real spreadsheet\n- 🎯 **Fill handle** - Excel-style drag-to-fill functionality for extending data patterns\n- 📊 **Data export** - Copy/paste TSV like you're in Excel (because why not?)\n- ♾️ **Infinite grids** - Go crazy with millions of rows and columns\n- 🔄 **Real-time updates** - Everything stays in sync, always\n- ⚡ **Stupid fast** - Optimized for grids with thousands of cells\n- 🎛️ **Flexible as yoga** - Works with React hooks or raw DOM manipulation\n\n## 🚀 Quick Install\n\n```bash\n# Using bun (because it's fast!)\nbun add selection-manager\n\n# Or your favorite package manager\nnpm install selection-manager\nyarn add selection-manager\npnpm add selection-manager\n```\n\n**📦 What's included:**\n\n```typescript\nimport {\n  // Main hooks\n  useInitializeSelectionManager,\n  useSelectionManager,\n\n  // Core class\n  SelectionManager,\n\n  // Utility functions\n  parseCSVContent,\n  writeToClipboard,\n\n  // Types\n  type CellData,\n  type SMSelection,\n  type SelectionManagerState,\n} from \"selection-manager\";\n```\n\n## 🎮 Quick Start - Let's Build Something Cool!\n\nHere's how to get started in less than 5 minutes:\n\n```tsx\nimport React, { useState } from \"react\";\nimport {\n  useInitializeSelectionManager,\n  useSelectionManager,\n} from \"selection-manager\";\n\nfunction MyAwesomeGrid() {\n  const [containerElement, setContainerElement] = useState(null);\n\n  // 🎉 This one hook does all the heavy lifting!\n  const selectionManager = useInitializeSelectionManager({\n    getNumRows: () => 10, // Your grid size\n    getNumCols: () => 10,\n    containerElement, // Auto-magic event handling!\n  });\n\n  // 📡 Subscribe to selection changes (React-style!)\n  const { selections, hasFocus, boxShadow } = useSelectionManager(\n    selectionManager,\n    () => ({\n      selections: selectionManager.selections,\n      hasFocus: selectionManager.hasFocus,\n      boxShadow: selectionManager.getCellBoxShadow({ row, col }),\n    }),\n  );\n\n  return (\n    <div\n      ref={setContainerElement}\n      style={{\n        outline: \"none\",\n        display: \"grid\",\n        gridTemplateColumns: \"repeat(10, 60px)\",\n        gap: \"1px\",\n        padding: \"20px\",\n        backgroundColor: \"#f5f5f5\",\n      }}\n    >\n      {Array.from({ length: 100 }, (_, i) => {\n        const row = Math.floor(i / 10);\n        const col = i % 10;\n        const isSelected = selectionManager.isSelected({ row, col });\n\n        return (\n          <div\n            key={i}\n            style={{\n              height: \"40px\",\n              backgroundColor: isSelected ? \"#e3f2fd\" : \"white\",\n              border: \"1px solid #ddd\",\n              display: \"flex\",\n              alignItems: \"center\",\n              justifyContent: \"center\",\n              cursor: \"pointer\",\n              // ✨ Magic selection borders!\n              boxShadow,\n            }}\n            onMouseDown={(e) => {\n              selectionManager.cellMouseDown(row, col, {\n                shiftKey: e.shiftKey,\n                ctrlKey: e.ctrlKey,\n                metaKey: e.metaKey,\n              });\n            }}\n            onMouseEnter={() => {\n              selectionManager.cellMouseEnter(row, col);\n            }}\n          >\n            {row},{col}\n          </div>\n        );\n      })}\n    </div>\n  );\n}\n```\n\n**🎊 That's it!** You now have a fully functional grid with:\n\n- ✅ Click and drag selection\n- ✅ Ctrl/Cmd+click for multi-selection\n- ✅ Shift+click to extend selections\n- ✅ Arrow key navigation\n- ✅ Ctrl/Cmd+A to select all\n- ✅ Beautiful visual feedback\n\n## 🎨 Core Concepts Made Simple\n\n### 🎯 The SelectionManager - Your New Best Friend\n\nThink of `SelectionManager` as the brain of your grid. It knows what's selected, handles all the complex mouse/keyboard logic, and gives you simple methods to query and manipulate selections.\n\n```tsx\n// 🧠 The brain that does it all\nconst selectionManager = useInitializeSelectionManager({\n  getNumRows: () => 1000, // Can be dynamic!\n  getNumCols: () => 50, // Even Infinity works!\n  containerElement, // Pass this for auto-magic\n});\n\n// 🔍 Ask it anything about selections\nconst isSelected = selectionManager.isSelected({ row: 5, col: 3 });\nconst allSelected = selectionManager.isAllSelected();\nconst topLeftCell = selectionManager.getTopLeftCellInSelection();\n```\n\n### 🎪 Mouse Interactions - Click, Drag, Repeat\n\nEvery mouse interaction has a purpose:\n\n- **👆 Click**: Select single cell\n- **👆👆 Double Click**: Start editing (like Excel!)\n- **🖱️ Click + Drag**: Select rectangular range\n- **⌘ + Click**: Add or remove from selection (multi-select!)\n- **⇧ + Click**: Extend current selection\n- **📊 Header Click**: Select entire row or column\n\n### ⌨️ Keyboard Shortcuts - For the Power Users\n\nWe've got all the shortcuts you expect (and they're smart about editing mode):\n\n| Shortcut           | Action                            | Available When |\n| ------------------ | --------------------------------- | -------------- |\n| `Arrow Keys`       | Navigate selection                | Not editing    |\n| `Shift + Arrows`   | Extend selection                  | Not editing    |\n| `Ctrl/Cmd + A`     | Select all                        | Not editing    |\n| `Ctrl/Cmd + C`     | Copy selection                    | Not editing    |\n| `Ctrl/Cmd + X`     | Cut selection                     | Not editing    |\n| `Delete/Backspace` | Clear cells                       | Not editing    |\n| `F2`               | Start editing                     | Always         |\n| `Escape`           | Cancel editing or clear selection | Always         |\n\n### Grid, data, and table bounds\n\nRows and columns describe the complete selectable grid. Bounds are zero-based\nand inclusive; a finite count of zero produces no grid bounds.\n\n```tsx\nconst selectionManager = useInitializeSelectionManager({\n  getNumRows: () => ({ type: \"number\", value: rows.length }),\n  getNumCols: () => ({ type: \"number\", value: columns.length }),\n  navigation: {\n    getUsedRange: () => dataIndex.usedRange,\n    getTableAt: (cell) => tableIndex.findAt(cell),\n  },\n});\n\nselectionManager.getGridBounds(); // whole selectable grid, or undefined\nselectionManager.getUsedRange(); // smallest range containing data, or undefined\nselectionManager.getTableAt({ row: 4, col: 2 }); // { id, bounds, dataBounds? }\n```\n\n`getUsedRange` and `getTableAt` are supplied by the host because\nSelectionManager does not own cell data. Use `{ type: \"infinity\" }` for an\nunbounded axis.\n\n### Data-aware keyboard navigation and scrolling\n\nCtrl/Cmd+Arrow creates a `jump` request. Adding Shift extends the active range\nto the same target. A host can resolve sparse data and table-specific behavior\nwithout putting data access into SelectionManager:\n\n```tsx\nconst selectionManager = useInitializeSelectionManager({\n  getNumRows: () => ({ type: \"infinity\" }),\n  getNumCols: () => ({ type: \"infinity\" }),\n  navigation: {\n    getUsedRange: () => dataIndex.usedRange,\n    getTableAt: (cell) => tableIndex.findAt(cell),\n    resolveTarget: (request) => {\n      if (request.kind !== \"jump\") return undefined;\n      return dataIndex.findJumpTarget(request.origin, request.direction);\n    },\n  },\n});\n\nconst unsubscribe = selectionManager.listenToViewportRequest((request) => {\n  if (request.type === \"reveal-cell\") {\n    viewport.scrollToCell(request.cell, { align: request.align });\n  } else {\n    viewport.scrollToRange(request.range, { align: request.align });\n  }\n});\n```\n\nReturning `undefined` from `resolveTarget` uses the built-in fallback: table\ndata bounds, table bounds, used range, then the finite grid edge. Every handled\nnavigation emits a `reveal-cell` request, including a jump whose target is\nalready active. The grid/virtualizer remains responsible for actual scrolling.\n\nUse `replaceSelections` when a host needs to move or restore the primary\nselection programmatically while still notifying React hooks, controlled-state\nlisteners, and other subscribers:\n\n```ts\nselectionManager.replaceSelections([\n  {\n    start: { row: 9, col: 2 },\n    end: {\n      row: { type: \"number\", value: 14 },\n      col: { type: \"number\", value: 5 },\n    },\n  },\n]);\n```\n\nThe manager defensively clones every supplied area and cancels any pointer\nselection currently in progress. This changes selection only; call\n`revealRange` as well when the host should scroll the replacement into view.\n\nHosts can use the same request channel to reveal a cell range without changing\nthe current selection. This is useful for commands such as “go to referenced\nrange” from a formula editor:\n\n```ts\nselectionManager.revealRange(\n  {\n    start: { row: 9, col: 2 },\n    end: {\n      row: { type: \"number\", value: 14 },\n      col: { type: \"number\", value: 5 },\n    },\n  },\n  { align: \"nearest\" },\n);\n```\n\n`revealRange` emits a `reveal-range` request with reason `programmatic`. Its\ndefault alignment is `nearest`, and the emitted request contains a clone of the\nrange supplied by the caller.\n\n### Formula reference selection\n\nReference mode keeps the formula's edited/primary selection intact while cell\nclicks and drags produce a separate reference range:\n\n```tsx\nselectionManager.beginReferenceSelection({\n  id: \"reference-at-caret\",\n  editedRange: {\n    start: { row: 1, col: 3 },\n    end: {\n      row: { type: \"number\", value: 1 },\n      col: { type: \"number\", value: 3 },\n    },\n  },\n});\n\nconst unsubscribe = selectionManager.listenToReferenceSelection((event) => {\n  if (event.phase === \"start\" || event.phase === \"change\") {\n    formulaEditor.replaceReferenceAtCaret(event.range);\n  }\n  if (event.phase === \"commit\") {\n    formulaEditor.finishReferenceInsertion(event.range);\n  }\n});\n\nselectionManager.getReferenceSelection();\nselectionManager.isCellInReferenceSelection({ row, col });\nselectionManager.referenceSelectionBorders({ row, col });\n\n// Leave reference mode when the formula edit ends. The range is cleared by default.\nselectionManager.endReferenceSelection();\n// Escape/cancel can instead notify listeners with a `cancel` event.\nselectionManager.cancelReferenceSelection();\n```\n\nDuring reference mode, cell/header pointer interactions update\n`state.referenceSelection` (`selecting` then `selected`) and do not mutate\n`state.selections`, `state.isSelecting`, or `state.isEditing`. Render the\nreference range as a separate overlay or use the membership/border queries to\napply a dotted selection treatment.\n\n### 🎨 Visual Magic - Borders That Make Sense\n\nSelectionManager automatically generates beautiful CSS for you:\n\n- **🔵 Blue borders**: Your committed selections\n- **⚫ Gray borders**: The selection you're currently making\n- **🟢 Green borders**: Active row/column headers\n- **🤎 Brown borders**: Cells and headers being hovered\n\n```tsx\n// ✨ Just apply the magic CSS!\n<div\n  style={{\n    boxShadow: useSelectionManager(selectionManager, () =>\n      selectionManager.getCellBoxShadow({ row, col }),\n    ),\n  }}\n>\n  My Cell\n</div>\n```\n\n## 🏗️ Real-World Examples\n\n### 📊 Building a Data Table with Headers\n\n```tsx\nimport React, { useState } from \"react\";\nimport {\n  useInitializeSelectionManager,\n  useSelectionManager,\n} from \"selection-manager\";\n\nfunction DataTable({ data }) {\n  const [containerElement, setContainerElement] = useState(null);\n\n  const selectionManager = useInitializeSelectionManager({\n    getNumRows: () => data.length,\n    getNumCols: () => data[0]?.length || 0,\n    containerElement,\n  });\n\n  return (\n    <div\n      ref={setContainerElement}\n      className=\"data-table\"\n      tabIndex={0}\n      style={{ outline: \"none\" }}\n    >\n      {/* 📋 Column headers */}\n      <div className=\"header-row\">\n        <div className=\"corner-cell\" />\n        {data[0]?.map((_, colIndex) => (\n          <ColumnHeader\n            key={colIndex}\n            index={colIndex}\n            selectionManager={selectionManager}\n          />\n        ))}\n      </div>\n\n      {/* 📊 Data rows */}\n      {data.map((row, rowIndex) => (\n        <div key={rowIndex} className=\"data-row\">\n          <RowHeader index={rowIndex} selectionManager={selectionManager} />\n          {row.map((cellData, colIndex) => (\n            <DataCell\n              key={`${rowIndex}-${colIndex}`}\n              row={rowIndex}\n              col={colIndex}\n              data={cellData}\n              selectionManager={selectionManager}\n            />\n          ))}\n        </div>\n      ))}\n    </div>\n  );\n}\n\n// 🏷️ Smart column header component\nfunction ColumnHeader({ index, selectionManager }) {\n  const isSelected = useSelectionManager(selectionManager, () =>\n    selectionManager.isWholeColSelected(index),\n  );\n\n  return (\n    <div\n      className={`column-header ${isSelected ? \"selected\" : \"\"}`}\n      style={{\n        boxShadow: selectionManager.getHeaderBoxShadow(index, \"col\"),\n      }}\n      onMouseDown={(e) => {\n        selectionManager.headerMouseDown(index, \"col\", {\n          shiftKey: e.shiftKey,\n          ctrlKey: e.ctrlKey,\n          metaKey: e.metaKey,\n        });\n      }}\n      onMouseEnter={() => {\n        selectionManager.headerMouseEnter(index, \"col\");\n      }}\n    >\n      {String.fromCharCode(65 + index)} {/* A, B, C... */}\n    </div>\n  );\n}\n\n// 🔢 Smart row header component\nfunction RowHeader({ index, selectionManager }) {\n  const isSelected = useSelectionManager(selectionManager, () =>\n    selectionManager.isWholeRowSelected(index),\n  );\n\n  return (\n    <div\n      className={`row-header ${isSelected ? \"selected\" : \"\"}`}\n      style={{\n        boxShadow: selectionManager.getHeaderBoxShadow(index, \"row\"),\n      }}\n      onMouseDown={(e) => {\n        selectionManager.headerMouseDown(index, \"row\", {\n          shiftKey: e.shiftKey,\n          ctrlKey: e.ctrlKey,\n          metaKey: e.metaKey,\n        });\n      }}\n      onMouseEnter={() => {\n        selectionManager.headerMouseEnter(index, \"row\");\n      }}\n    >\n      {index + 1}\n    </div>\n  );\n}\n```\n\n### ✏️ Editable Spreadsheet Experience\n\n```tsx\nfunction EditableSpreadsheet() {\n  const [data, setData] = useState(() => {\n    // 🎲 Generate some demo data\n    const grid = new Map();\n    for (let row = 0; row < 20; row++) {\n      for (let col = 0; col < 10; col++) {\n        grid.set(`${row},${col}`, `Cell ${row},${col}`);\n      }\n    }\n    return grid;\n  });\n\n  const [containerElement, setContainerElement] = useState(null);\n\n  const selectionManager = useInitializeSelectionManager({\n    getNumRows: () => 20,\n    getNumCols: () => 10,\n    containerElement,\n    // 💡 By default, auto clipboard handling is enabled (copy/cut/paste work automatically)\n    // Set disableAutoClipboard: true to handle clipboard operations manually\n    // disableAutoClipboard: true  // Uncomment to handle clipboard manually\n  });\n\n  // 📋 Handle copy operations like a pro\n  // Note: This example shows manual clipboard handling.\n  // If disableAutoClipboard is false (default), you can skip this and paste handling.\n  useEffect(() => {\n    return selectionManager.listenToCopy((isCut) => {\n      const boundingRect = selectionManager.getSelectionsBoundingRect();\n      if (!boundingRect) return;\n\n      // 🧮 Create a proper grid for export\n      const height = boundingRect.end.row - boundingRect.start.row + 1;\n      const width = boundingRect.end.col - boundingRect.start.col + 1;\n      const exportGrid = Array(height)\n        .fill(null)\n        .map(() => Array(width).fill(\"\"));\n\n      // 🎯 Fill only the selected cells\n      selectionManager.forEachSelectedCell(({ absolute, relative }) => {\n        const value = data.get(`${absolute.row},${absolute.col}`) || \"\";\n        exportGrid[relative.row][relative.col] = value;\n      });\n\n      // 📋 Copy to clipboard as TSV (Excel-compatible!)\n      const tsvString = exportGrid.map((row) => row.join(\"\\t\")).join(\"\\n\");\n      navigator.clipboard.writeText(tsvString);\n\n      if (isCut) {\n        // 🗑️ Clear the cut cells\n        selectionManager.getNonOverlappingSelections().forEach((selection) => {\n          for (let row = selection.start.row; row <= selection.end.row; row++) {\n            for (\n              let col = selection.start.col;\n              col <= selection.end.col;\n              col++\n            ) {\n              setData((prev) => {\n                const newData = new Map(prev);\n                newData.set(`${row},${col}`, \"\");\n                return newData;\n              });\n            }\n          }\n        });\n      }\n    });\n  }, [data, selectionManager]);\n\n  // 📋 Handle paste operations - REQUIRED for paste to work!\n  // Note: By default, useInitializeSelectionManager automatically handles paste.\n  // If you need custom paste handling, set disableAutoClipboard: true and handle it yourself.\n  // This example shows manual handling - you can remove this if using auto clipboard handling.\n  useEffect(() => {\n    return selectionManager.listenToPaste(({ updates, rawString }) => {\n      // The clipboard content has been parsed and positioned at the current selection\n      // You must save these updates to make paste work:\n      selectionManager.saveCellValues(updates);\n    });\n  }, [selectionManager]);\n\n  // 📝 Handle data updates (from cell editing, paste, etc.)\n  useEffect(() => {\n    return selectionManager.listenToUpdateData((updates) => {\n      setData((prev) => {\n        const newData = new Map(prev);\n        updates.forEach(({ rowIndex, colIndex, value }) => {\n          newData.set(`${rowIndex},${colIndex}`, value);\n        });\n        return newData;\n      });\n    });\n  }, [selectionManager]);\n\n  // 🎯 Custom CSV import example\n  const handleCsvImport = (csvText: string) => {\n    const cellData = parseCSVContent(csvText);\n    const topLeft = selectionManager.getTopLeftCellInSelection() || {\n      row: 0,\n      col: 0,\n    };\n\n    // Import at current selection position\n    setData((prev) => {\n      const newData = new Map(prev);\n      cellData.forEach(({ rowIndex, colIndex, value }) => {\n        const targetRow = topLeft.row + rowIndex;\n        const targetCol = topLeft.col + colIndex;\n        newData.set(`${targetRow},${targetCol}`, value);\n      });\n      return newData;\n    });\n  };\n\n  return (\n    <div className=\"spreadsheet-container\">\n      <div className=\"toolbar\">\n        <button\n          onClick={() => {\n            const tsv = selectionManager.selectionToTsv(data);\n            console.log(\"📊 Exported data:\", tsv);\n          }}\n        >\n          📊 Export Selection\n        </button>\n        <span className=\"selection-info\">\n          {selectionManager.hasSelection()\n            ? `Selected: ${selectionManager.getState().selections.length} range(s)`\n            : \"No selection\"}\n        </span>\n      </div>\n\n      <div ref={setContainerElement} className=\"spreadsheet-grid\" tabIndex={0}>\n        {Array.from({ length: 20 }, (_, row) =>\n          Array.from({ length: 10 }, (_, col) => (\n            <EditableCell\n              key={`${row}-${col}`}\n              row={row}\n              col={col}\n              data={data}\n              selectionManager={selectionManager}\n            />\n          )),\n        )}\n      </div>\n    </div>\n  );\n}\n\n// ✏️ A cell that can be edited\nconst EditableCell = React.memo(({ row, col, data, selectionManager }) => {\n  const isEditing = useSelectionManager(selectionManager, () =>\n    selectionManager.isEditingCell(row, col),\n  );\n\n  const isHovering = useSelectionManager(selectionManager, () =>\n    selectionManager.isHoveringCell(row, col),\n  );\n\n  const cellValue = data.get(`${row},${col}`) || \"\";\n\n  if (isEditing) {\n    return (\n      <input\n        className=\"cell-editor\"\n        autoFocus\n        defaultValue={cellValue} // 🔑 Use defaultValue, not value!\n        onBlur={() => selectionManager.cancelEditing()} // 🔥 Always cancel on blur\n        onKeyDown={(e) => {\n          if (e.key === \"Enter\") {\n            // 💾 Save using saveCellValue - triggers listenToUpdateData!\n            selectionManager.saveCellValue(\n              { rowIndex: row, colIndex: col },\n              e.target.value,\n            );\n            selectionManager.cancelEditing();\n          } else if (e.key === \"Escape\") {\n            selectionManager.cancelEditing();\n          }\n        }}\n      />\n    );\n  }\n\n  return (\n    <div\n      className={`spreadsheet-cell ${isHovering ? \"hovering\" : \"\"}`}\n      style={{\n        boxShadow: selectionManager.getCellBoxShadow({ row, col }),\n        // 🖱️ You can add custom hover styling too!\n        cursor: isHovering ? \"pointer\" : \"default\",\n      }}\n      onMouseDown={(e) => {\n        selectionManager.cellMouseDown(row, col, {\n          shiftKey: e.shiftKey,\n          ctrlKey: e.ctrlKey,\n          metaKey: e.metaKey,\n        });\n      }}\n      onMouseEnter={() => {\n        selectionManager.cellMouseEnter(row, col);\n      }}\n      onDoubleClick={() => {\n        selectionManager.cellDoubleClick(row, col);\n      }}\n    >\n      {cellValue}\n    </div>\n  );\n});\n```\n\n### 🚀 High-Performance Grid (For the Speed Demons)\n\nWhen you need to handle thousands of cells, use the DOM setup approach for maximum performance:\n\n```tsx\nimport React, { useCallback, useState } from \"react\";\n\n// 🏎️ Optimized cell component\nconst HighPerformanceCell = React.memo(\n  ({ row, col, selectionManager, data }) => {\n    // 🔑 Critical: useCallback prevents ref recreation\n    const cellRef = useCallback(\n      (el) => {\n        if (el) {\n          // ✨ This does ALL the work for you:\n          // - Event listeners\n          // - Style updates\n          // - State synchronization\n          return selectionManager.setupCellElement(el, { row, col });\n        }\n      },\n      [row, col, selectionManager],\n    );\n\n    return (\n      <div\n        ref={cellRef}\n        className=\"performance-cell\"\n        style={{\n          width: 60,\n          height: 30,\n          border: \"1px solid #e0e0e0\",\n          display: \"flex\",\n          alignItems: \"center\",\n          justifyContent: \"center\",\n          fontSize: \"12px\",\n          cursor: \"pointer\",\n          backgroundColor: \"white\",\n        }}\n      >\n        {data.get(`${row},${col}`) || `${row},${col}`}\n      </div>\n    );\n  },\n);\n\nfunction MassiveGrid() {\n  const [containerElement, setContainerElement] = useState(null);\n  const [data] = useState(() => {\n    // 🎲 Generate 50,000 cells of data\n    const grid = new Map();\n    for (let row = 0; row < 500; row++) {\n      for (let col = 0; col < 100; col++) {\n        grid.set(`${row},${col}`, Math.floor(Math.random() * 1000));\n      }\n    }\n    return grid;\n  });\n\n  const selectionManager = useInitializeSelectionManager({\n    getNumRows: () => 500,\n    getNumCols: () => 100,\n    containerElement,\n  });\n\n  return (\n    <div className=\"massive-grid-container\">\n      <h2>🚀 50,000 Cells - Still Smooth as Butter!</h2>\n      <div\n        ref={setContainerElement}\n        tabIndex={0}\n        style={{\n          display: \"grid\",\n          gridTemplateColumns: \"repeat(100, 60px)\",\n          gap: \"0\",\n          height: \"400px\",\n          overflow: \"auto\",\n          outline: \"none\",\n          border: \"2px solid #ddd\",\n        }}\n      >\n        {Array.from({ length: 500 }, (_, row) =>\n          Array.from({ length: 100 }, (_, col) => (\n            <HighPerformanceCell\n              key={`${row}-${col}`}\n              row={row}\n              col={col}\n              selectionManager={selectionManager}\n              data={data}\n            />\n          )),\n        )}\n      </div>\n    </div>\n  );\n}\n```\n\n### 🎮 Controlled Mode - Take Full Control\n\nSometimes you want to manage the selection state yourself:\n\n```tsx\nfunction ControlledExample() {\n  const [selectionState, setSelectionState] = useState({\n    selections: [],\n    hasFocus: false,\n    isSelecting: { type: \"none\" },\n    isEditing: { type: \"none\" },\n    isHovering: { type: \"none\" },\n    selectionMode: \"primary\",\n    referenceSelection: { type: \"none\" },\n  });\n\n  const selectionManager = useInitializeSelectionManager({\n    getNumRows: () => 10,\n    getNumCols: () => 10,\n    state: selectionState, // 🎛️ You control the state\n    onStateChange: setSelectionState, // 📡 Get notified of changes\n  });\n\n  // 🎯 Now you can manipulate selections programmatically!\n  const selectTopLeftCorner = () => {\n    setSelectionState((prev) => ({\n      ...prev,\n      selections: [{ start: { row: 0, col: 0 }, end: { row: 2, col: 2 } }],\n    }));\n  };\n\n  const clearAllSelections = () => {\n    setSelectionState((prev) => ({\n      ...prev,\n      selections: [],\n    }));\n  };\n\n  const clearHovering = () => {\n    // 🖱️ Clear any hovering state programmatically\n    selectionManager.cancelHovering();\n  };\n\n  return (\n    <div>\n      <div className=\"controls\">\n        <button onClick={selectTopLeftCorner}>🎯 Select Top-Left 3x3</button>\n        <button onClick={clearAllSelections}>🧹 Clear All</button>\n        <button onClick={clearHovering}>🖱️ Clear Hover</button>\n      </div>\n      <Grid selectionManager={selectionManager} />\n    </div>\n  );\n}\n```\n\n## 🧠 Deep Dive: API Reference\n\n### 🎯 Core Types (TypeScript Goodness)\n\n```typescript\n// 📐 A selection is just a rectangle\ntype SMSelection = {\n  start: { row: number; col: number };\n  end: { row: number; col: number };\n};\n\n// 🎪 What kind of selection is happening?\ntype IsSelecting =\n  | { type: \"none\" }                           // Nothing happening\n  | { type: \"drag\"; ...SMSelection }           // Normal drag selection\n  | { type: \"add\"; ...SMSelection }            // Ctrl+click adding\n  | { type: \"remove\"; ...SMSelection }         // Ctrl+click removing\n  | { type: \"shift\"; ...SMSelection };         // Shift+click extending\n\n// ✏️ Editing state\ntype IsEditing =\n  | { type: \"none\" }                           // Not editing\n  | { type: \"cell\"; row: number; col: number }; // Editing this cell\n\n// 🧠 The complete state\ntype SelectionManagerState = {\n  hasFocus: boolean;        // Is the grid focused?\n  selections: SMSelection[]; // All current selections\n  isSelecting: IsSelecting; // Current selection operation\n  isEditing: IsEditing;     // Current editing state\n  isHovering: IsHovering;   // Current hovering state\n  selectionMode: \"primary\" | \"reference\";\n  referenceSelection: ReferenceSelectionState;\n};\n\n// 🖱️ Hovering state\ntype IsHovering =\n  | { type: \"none\" }                                    // Not hovering\n  | { type: \"cell\"; row: number; col: number }          // Hovering over this cell\n  | { type: \"group\"; group: SMArea }                    // Hovering over merged cell group\n  | { type: \"header\"; index: number; headerType: \"row\" | \"col\" }; // Hovering over header\n\n// 📋 Paste event\ntype PasteEvent = {\n  updates: Array<{ rowIndex: number; colIndex: number; value: string }>; // Parsed cell data\n  rawString: string;  // Original clipboard content before parsing\n};\n\n// 🔒 Mark cells that can be selected/copied but not changed\ntype ReadonlyCellPredicate = (cell: {\n  rowIndex: number;\n  colIndex: number;\n}) => boolean;\n```\n\n### 🎨 Visual Styling Methods\n\n```typescript\n// ✨ Get beautiful CSS for your cells\nconst cellShadow = selectionManager.getCellBoxShadow({ row: 2, col: 3 });\nconst headerShadow = selectionManager.getHeaderBoxShadow(2, \"row\");\nconst containerShadow = selectionManager.getContainerBoxShadow();\n\n// 🎨 Or build your own with border information\nconst borders = selectionManager.selectionBorders({ row: 2, col: 3 });\n// Returns: Array<\"left\" | \"right\" | \"top\" | \"bottom\">\n```\n\n### 🔍 Selection Query Methods\n\n```typescript\n// 🤔 Is this cell selected?\nconst isSelected = selectionManager.isSelected({ row: 5, col: 3 });\n\n// 📊 Is this entire row/column selected?\nconst rowSelected = selectionManager.isWholeRowSelected(5);\nconst colSelected = selectionManager.isWholeColSelected(3);\n\n// 🌍 Is everything selected?\nconst allSelected = selectionManager.isAllSelected();\n\n// 🎯 Where's the action happening?\nconst topLeft = selectionManager.getTopLeftCellInSelection();\n\n// 📐 What's the smallest box containing all selections?\nconst boundingRect = selectionManager.getSelectionsBoundingRect();\n\n// 🧮 Break down overlapping selections\nconst cleanSelections = selectionManager.getNonOverlappingSelections();\n\n// 🔄 Iterate through every selected cell\nselectionManager.forEachSelectedCell(({ absolute, relative }) => {\n  console.log(\n    `Cell ${absolute.row},${absolute.col} -> Grid pos ${relative.row},${relative.col}`,\n  );\n});\n\n// 🖱️ Is this cell being hovered?\nconst isHovering = selectionManager.isHoveringCell(row, col);\n\n// 🔒 Is this cell readonly?\nconst readonly = selectionManager.isCellReadonly(rowIndex, colIndex);\n\n// 🧹 Cancel any hovering state\nselectionManager.cancelHovering();\n\n// 💾 Save a cell value (triggers listenToUpdateData listeners)\nselectionManager.saveCellValue({ rowIndex: 2, colIndex: 3 }, \"New Value\");\n\n// 💾 Save multiple cell values at once\nselectionManager.saveCellValues([\n  { rowIndex: 0, colIndex: 0, value: \"A1\" },\n  { rowIndex: 0, colIndex: 1, value: \"B1\" },\n  { rowIndex: 1, colIndex: 0, value: \"A2\" },\n]);\n\n// 🔗 Group/merged cell operations\nconst group = selectionManager.findGroupContainingCell({ row: 2, col: 3 });\nconst isHoveringGroup = selectionManager.isHoveringGroup(group);\nconst groupShadow = selectionManager.getBoxShadow({ color: \"#4CAF50\" });\n\n// 🎯 Fill handle operations\nconst canShowFillHandle = selectionManager.canCellHaveFillHandle({\n  row: 2,\n  col: 3,\n});\nconst fillBaseSelection = selectionManager.getFillHandleBaseSelection();\n```\n\n### 🛠️ DOM Setup Methods (High-Performance Mode)\n\nThese methods automatically handle event listeners, styling updates, and state synchronization. They update the DOM directly without React re-renders, making them ideal for grids with thousands of cells.\n\n```typescript\n// Cell setup - handles mouse events, visual updates, and input capture positioning\nconst cleanupCell = selectionManager.setupCellElement(el, { row, col });\n\n// Header setup - handles mouse events and visual updates\nconst cleanupHeader = selectionManager.setupHeaderElement(el, index, \"row\");\n\n// Container setup - handles all global events (keyboard, paste, drag/drop, focus)\nconst cleanupContainer = selectionManager.setupContainerElement(el);\n\n// Input setup - handles blur, Enter/Tab to save, focus management\nconst cleanupInput = selectionManager.setupInputElement(inputEl, {\n  rowIndex,\n  colIndex,\n});\n```\n\n**setupCellElement** automatically:\n\n- Sets up mouse event listeners (mousedown, mouseenter, dblclick)\n- Updates boxShadow style when selections change\n- Detects fill handle interactions via `data-fill-handle` attribute\n- Positions input capture element when cell becomes active\n\n**setupHeaderElement** automatically:\n\n- Sets up mouse event listeners (mousedown, mouseenter)\n- Updates boxShadow for header selection/hover states\n\n**setupContainerElement** automatically:\n\n- Handles global mouse events (mouseup, mousedown for selection completion)\n- Handles all keyboard shortcuts (arrows, Ctrl+C/V/X, etc.)\n- Handles paste events\n- Handles drag & drop for CSV/TSV files\n- Prevents text selection during drag operations\n- Creates and manages invisible input capture element for keyboard input\n- Updates container boxShadow on focus changes\n- Clears hover state when mouse leaves container\n\n**setupInputElement** automatically:\n\n- Saves cell value on blur\n- Handles Enter/Tab keys to save\n- Sets initial value from editing state\n- Focuses input and selects all text\n\n**Important**: Always use `useCallback` for refs to prevent unnecessary re-setup. Call cleanup functions when components unmount. `setupContainerElement` should be called once per grid.\n\n### ✏️ Cell Editing Best Practices\n\nWhen implementing cell editing, follow these patterns for the best user experience:\n\n```typescript\n// 🔑 Key editing patterns\nconst EditingCell = ({ row, col, selectionManager, initialValue }) => {\n  return (\n    <input\n      autoFocus                    // 🎯 Focus immediately\n      defaultValue={initialValue}  // 🔑 Use defaultValue, NOT value\n      onBlur={() => {\n        // 🔥 Always cancel on blur\n        selectionManager.cancelEditing();\n      }}\n      onKeyDown={(e) => {\n        if (e.key === 'Enter') {\n          // 💾 Save and exit - this triggers listenToUpdateData listeners!\n          selectionManager.saveCellValue(\n            { rowIndex: row, colIndex: col },\n            e.target.value\n          );\n          selectionManager.cancelEditing();\n        } else if (e.key === 'Escape') {\n          // ⏭️ Cancel without saving\n          selectionManager.cancelEditing();\n        }\n      }}\n      style={{\n        width: \"100%\",\n        height: \"100%\",\n        border: \"none\",\n        outline: \"none\",\n        backgroundColor: \"transparent\",\n        textAlign: \"center\"\n      }}\n    />\n  );\n};\n```\n\n**🎯 Key Takeaways:**\n\n1. **`defaultValue` not `value`**: Use `defaultValue` for better performance and to avoid React warnings\n2. **Always handle `onBlur`**: Cancel editing when the user clicks away\n3. **Use `saveCellValue()`**: This method automatically triggers all `listenToUpdateData` listeners\n4. **Handle Enter and Escape**: Standard spreadsheet behavior users expect\n\n### 🎯 Fill Handle - Excel-Style Data Extension\n\nThe fill handle lets users drag from the bottom-right corner of a selection to extend data patterns, just like in Excel:\n\n```tsx\nfunction CellWithFillHandle({ row, col, selectionManager, data }) {\n  const canHaveFillHandle = useSelectionManager(selectionManager, () =>\n    selectionManager.canCellHaveFillHandle({ row, col }),\n  );\n\n  return (\n    <div\n      className=\"cell\"\n      onMouseDown={(e) => {\n        const isFillHandle =\n          e.target instanceof HTMLElement &&\n          (e.target.hasAttribute(\"data-fill-handle\") ||\n            e.target.querySelector(\"[data-fill-handle]\") !== null);\n\n        selectionManager.cellMouseDown(row, col, {\n          shiftKey: e.shiftKey,\n          ctrlKey: e.ctrlKey,\n          metaKey: e.metaKey,\n          isFillHandle, // 🔑 Key parameter for fill handle detection\n        });\n      }}\n      // ... other props\n    >\n      {/* Your cell content */}\n      Cell content here\n      {/* 🎯 Fill handle - only shows on bottom-right cell of selection */}\n      {canHaveFillHandle && (\n        <div\n          data-fill-handle={true} // 🔑 Required attribute\n          style={{\n            position: \"absolute\",\n            bottom: 0,\n            right: 0,\n            width: 8,\n            height: 8,\n            backgroundColor: \"blue\",\n            cursor: \"crosshair\", // Excel-style cursor\n          }}\n        />\n      )}\n    </div>\n  );\n}\n\n// 🎧 Listen for fill operations\nReact.useEffect(() => {\n  return selectionManager.listenToFill((baseSelection, fillArea) => {\n    console.log(\"Fill operation:\", { from: baseSelection, to: fillArea });\n\n    // Implement your fill logic here\n    // Example: extend patterns, copy data, generate sequences, etc.\n    const updates = generateFillData(baseSelection, fillArea);\n    selectionManager.saveCellValues(updates);\n  });\n}, [selectionManager]);\n```\n\n**🎯 Key Fill Handle Features:**\n\n1. **Automatic detection**: Use `canCellHaveFillHandle()` to check if a cell should show the handle\n2. **Visual feedback**: Fill operations show with red borders during drag\n3. **Smart direction**: Automatically detects row-wise vs column-wise fill based on drag direction\n4. **Event driven**: Use `listenToFill()` to implement your own data extension logic\n5. **Excel-like UX**: Familiar crosshair cursor and bottom-right corner positioning\n\n**🎨 Fill Handle Styling:**\n\n```tsx\n// The fill handle gets special styling during drag operations\nconst cellBoxShadow = selectionManager.getCellBoxShadow({ row, col });\n// During fill operations, this returns red borders instead of blue\n\n// You can also detect fill mode programmatically\nconst isFillMode = selectionManager.isSelecting.type === \"fill\";\n```\n\n### 🔗 Merged Cell Groups (Advanced)\n\nFor spreadsheet-like applications with merged cells, SelectionManager supports grouped cells:\n\n```typescript\nconst selectionManager = useInitializeSelectionManager({\n  getNumRows: () => 10,\n  getNumCols: () => 5,\n  // 🔗 Define merged cell areas\n  getGroups: () => {\n    // Return areas that should be treated as merged cells\n    return [\n      { start: { row: 1, col: 1 }, end: { row: 2, col: 3 } }, // 2x3 merged area\n      { start: { row: 5, col: 0 }, end: { row: 5, col: 4 } }, // Merged row\n    ];\n  }\n});\n\n// 🎯 Usage in components\nconst GroupedCell = ({ row, col, group, selectionManager }) => {\n  // Only render content in the top-left cell of a group\n  const isTopLeft = group && group.start.row === row && group.start.col === col;\n\n  const groupBoxShadow = useSelectionManager(selectionManager, () => {\n    return (\n      group &&\n      selectionManager.isHoveringGroup(group) &&\n      selectionManager.getBoxShadow({ color: '#4CAF50' })\n    ) || undefined;\n  });\n\n  if (group && !isTopLeft) {\n    // Hidden cells in merged group\n    return <div style={{ display: 'none' }} />;\n  }\n\n  return (\n    <div\n      style={{\n        // Span multiple cells if this is a group\n        gridRowStart: row + 1,\n        gridRowEnd: group ? group.end.row + 2 : row + 2,\n        gridColumnStart: col + 1,\n        gridColumnEnd: group ? group.end.col + 2 : col + 2,\n        boxShadow: groupBoxShadow,\n        border: '1px solid #ddd',\n        padding: '8px'\n      }}\n    >\n      {group ? `Merged ${group.end.row - group.start.row + 1}x${group.end.col - group.start.col + 1}` : `${row},${col}`}\n    </div>\n  );\n};\n```\n\n**🎯 Key Patterns:**\n\n- **Dynamic groups**: `getGroups()` can return different areas based on data\n- **Hover detection**: Use `isHoveringGroup(group)` to detect group hovers\n- **Custom styling**: Use `getBoxShadow()` for group-specific visual feedback\n\n### 🛠️ Utility Functions\n\nSelectionManager exports helpful utility functions for data handling:\n\n```typescript\nimport {\n  parseCSVContent,\n  writeToClipboard,\n  type CellData,\n} from \"selection-manager\";\n\n// 📊 Parse CSV/TSV content into cell data format\ntype CellData = {\n  rowIndex: number;\n  colIndex: number;\n  value: string;\n};\n\nconst csvData = \"Name,Age,City\\nJohn,25,NYC\\nJane,30,LA\";\nconst cells: CellData[] = parseCSVContent(csvData);\n// Returns: [\n//   { rowIndex: 0, colIndex: 0, value: \"Name\" },\n//   { rowIndex: 0, colIndex: 1, value: \"Age\" },\n//   { rowIndex: 0, colIndex: 2, value: \"City\" },\n//   { rowIndex: 1, colIndex: 0, value: \"John\" },\n//   ...\n// ]\n\n// 📋 Write data to clipboard (with fallback for older browsers)\nwriteToClipboard(\"Hello\\tWorld\\nFoo\\tBar\"); // TSV format\n```\n\n**🎯 Smart Parsing Features:**\n\n- **Auto-delimiter detection**: Prefers tabs > commas > spaces\n- **Formatted numbers**: Handles \"1,234.56\" as single values, not CSV\n- **Quote handling**: Properly parses quoted CSV fields\n- **Cross-browser clipboard**: Fallback for older browsers\n\n### 📋 Data Operations (Copy/Paste Magic)\n\n**💡 Auto Clipboard Handling**: By default, `useInitializeSelectionManager` automatically handles copy/cut/paste operations. Copy/cut triggers `listenToCopy()` with `cut: true` for cut and `cut: false` for copy, and automatically clears cells on cut. Paste automatically calls `saveCellValues()`. Set `disableAutoClipboard: true` to handle clipboard operations manually.\n\n```typescript\n// 📋 Export selections as TSV\nconst dataMap = new Map([\n  [\"0,0\", \"Hello\"],\n  [\"0,1\", \"World\"],\n  [\"1,0\", \"42\"],\n  [\"1,1\", \"🎉\"],\n]);\nconst tsv = selectionManager.selectionToTsv(dataMap);\n// Returns: \"Hello\\tWorld\\n42\\t🎉\" (only selected cells)\n\n// 🎧 Listen for user actions (only needed if disableAutoClipboard: true)\nconst unsubscribeCopy = selectionManager.listenToCopy((isCut) => {\n  if (isCut) {\n    console.log(\"User cut data\");\n    // Handle cut: copy to clipboard and clear cells\n    selectionManager.clearSelectedCells();\n  } else {\n    console.log(\"User copied data\");\n    // Handle copy: copy to clipboard only\n  }\n});\n\n// 📋 Listen for paste operations - REQUIRED for paste to work!\n// Note: Only needed if disableAutoClipboard: true. Otherwise, paste is handled automatically.\nconst unsubscribePaste = selectionManager.listenToPaste(\n  ({ updates, rawString }) => {\n    // rawString: string - The original clipboard content before parsing\n    // The clipboard content has been parsed and positioned at the current selection\n    // You must handle these updates, typically by saving them:\n    selectionManager.saveCellValues(updates);\n  },\n);\n\nconst unsubscribeData = selectionManager.listenToUpdateData((data) => {\n  console.log(\"Data updated:\", data);\n  // data: Array<{ rowIndex: number; colIndex: number; value: string }>\n  // This fires for: cell editing, paste operations, file drops, and manual saves\n});\n\nconst unsubscribeFill = selectionManager.listenToFill(\n  (baseSelection, fillArea) => {\n    console.log(\"Fill operation:\", { from: baseSelection, to: fillArea });\n    // baseSelection: The original selected area being extended from\n    // fillArea: The new area being filled (includes direction and extent)\n\n    // Implement your fill logic: copy data, extend patterns, generate sequences, etc.\n    const fillUpdates = generateDataForFillArea(baseSelection, fillArea);\n    selectionManager.saveCellValues(fillUpdates);\n  },\n);\n\n// 🗑️ Clear selected cells (triggers listenToUpdateData with empty values)\nselectionManager.clearSelectedCells();\n\n// 💾 Save single cell value (triggers listenToUpdateData)\nselectionManager.saveCellValue({ rowIndex: 2, colIndex: 3 }, \"New Value\");\n\n// 💾 Save multiple cell values (triggers listenToUpdateData)\nselectionManager.saveCellValues([\n  { rowIndex: 0, colIndex: 0, value: \"A1\" },\n  { rowIndex: 0, colIndex: 1, value: \"B1\" },\n]);\n\n// 🧹 Clean up when done\nunsubscribeCopy();\nunsubscribePaste();\nunsubscribeData();\nunsubscribeFill();\n```\n\n### 🔒 Readonly Cells\n\nReadonly cells are still selectable, navigable, copyable, and usable as fill sources. Editing, paste, delete, cut clearing, drop imports, and saved fill updates skip readonly targets automatically.\n\n```typescript\nconst selectionManager = useInitializeSelectionManager({\n  getNumRows: () => ({ type: \"number\", value: rows.length }),\n  getNumCols: () => ({ type: \"number\", value: columns.length }),\n  isCellReadonly: ({ rowIndex, colIndex }) =>\n    rowIndex === 0 || columns[colIndex]?.readonly === true,\n});\n\n// Useful for styling locked cells in your grid.\nconst readonly = selectionManager.isCellReadonly(rowIndex, colIndex);\n```\n\n## 🎪 Advanced Patterns\n\n### ♾️ Infinite Grids - Go Wild!\n\n```tsx\nfunction InfiniteGrid() {\n  const selectionManager = useInitializeSelectionManager({\n    getNumRows: () => Infinity, // 🤯 Infinite rows!\n    getNumCols: () => Infinity, // 🤯 Infinite columns!\n  });\n\n  // Selections can now have Infinity as end coordinates\n  // Perfect for virtualized grids!\n}\n```\n\n### 🎭 Custom State Observation\n\n```tsx\nfunction SmartComponent() {\n  const selectionManager = useInitializeSelectionManager({\n    /* ... */\n  });\n\n  // 👀 Watch for specific state changes\n  useEffect(() => {\n    return selectionManager.observeStateChange(\n      (state) => state.isSelecting.type, // Watch selection type\n      (type) => {\n        if (type !== \"none\") {\n          console.log(\"Started selecting!\");\n          // Return cleanup function\n          return () => console.log(\"Stopped selecting!\");\n        }\n      },\n      true, // Run immediately with current state\n    );\n  }, [selectionManager]);\n\n  // 🖱️ Watch for hovering state changes\n  useEffect(() => {\n    return selectionManager.observeStateChange(\n      (state) => state.isHovering,\n      (hovering) => {\n        if (hovering.type === \"cell\") {\n          console.log(`Hovering over cell ${hovering.row},${hovering.col}`);\n        } else if (hovering.type === \"header\") {\n          console.log(\n            `Hovering over ${hovering.headerType} header ${hovering.index}`,\n          );\n        }\n      },\n      true,\n    );\n  }, [selectionManager]);\n}\n```\n\n### 🎨 Custom Styling with Borders\n\n```tsx\nfunction CustomStyledCell({ row, col, selectionManager }) {\n  const borders = useSelectionManager(selectionManager, () =>\n    selectionManager.selectionBorders({ row, col }),\n  );\n\n  const customStyle = {\n    borderLeft: borders.includes(\"left\")\n      ? \"2px solid #ff4081\"\n      : \"1px solid #ddd\",\n    borderRight: borders.includes(\"right\")\n      ? \"2px solid #ff4081\"\n      : \"1px solid #ddd\",\n    borderTop: borders.includes(\"top\") ? \"2px solid #ff4081\" : \"1px solid #ddd\",\n    borderBottom: borders.includes(\"bottom\")\n      ? \"2px solid #ff4081\"\n      : \"1px solid #ddd\",\n  };\n\n  return <div style={customStyle}>Custom styled cell!</div>;\n}\n```\n\n## 🏆 Performance Tips\n\n### 🚀 For Small Grids (< 1000 cells)\n\n- Use the React hooks approach with `useSelectionManager`\n- Manual event handlers are fine\n- Easy to debug and understand\n\n### ⚡ For Large Grids (> 1000 cells)\n\n- Use `setupCellElement` and `setupHeaderElement`\n- Individual components with `React.memo`\n- `useCallback` for refs (critical!)\n- Avoid creating refs in loops\n\n### 🎯 Best Practices\n\n1. **Always use `useCallback` for refs**:\n\n   ```tsx\n   // ✅ Good\n   const cellRef = useCallback(\n     (el) => {\n       if (el) return selectionManager.setupCellElement(el, { row, col });\n     },\n     [row, col, selectionManager],\n   );\n\n   // ❌ Bad - creates new function every render\n   const cellRef = (el) => {\n     if (el) return selectionManager.setupCellElement(el, { row, col });\n   };\n   ```\n\n2. **Set up focus correctly**:\n\n   ```tsx\n   <div\n     ref={setContainerElement}\n     tabIndex={0} // 🔑 Required for keyboard events\n     style={{ outline: \"none\" }} // 🎨 Remove ugly focus outline\n   />\n   ```\n\n3. **Use specific selectors**:\n\n   ```tsx\n   // ✅ Good - only re-renders when selections change\n   const selections = useSelectionManager(sm, (state) => state.selections);\n\n   // ❌ Bad - re-renders on any state change\n   const state = useSelectionManager(sm, (state) => state);\n   ```\n\n## 🎉 That's a Wrap!\n\nSelectionManager makes building grid interfaces fun instead of frustrating. Whether you're creating a simple data table or the next Excel competitor, we've got the tools to make it happen smoothly.\n\n**Quick links:**\n\n- 🌟 [Star us on GitHub](https://github.com/ricsam/selection-manager)\n- 🐛 [Report issues](https://github.com/ricsam/selection-manager/issues)\n\nNow go build something amazing! 🚀✨\n\n---\n\n## 📄 License\n\nMIT © ricsam - Go wild! 🎊\n","readmeFilename":"README.md"}