{"_id":"@canvastack/canvable","_rev":"27-4982713d4a076728c33420cd7c383bdd","name":"@canvastack/canvable","dist-tags":{"latest":"1.0.2"},"versions":{"0.3.5":{"name":"@canvastack/canvable","version":"0.3.5","keywords":["react","nextjs","table","datatable","canvastack","canvable","enterprise-table","headless","grid","export-csv","pagination"],"author":{"name":"Canvastack Team"},"license":"SEE LICENSE IN LICENSE.md","_id":"@canvastack/canvable@0.3.5","maintainers":[{"name":"canvastack","email":"canvastacks@gmail.com"}],"dist":{"shasum":"494a5c75f8ea90ee405283efdf4fcee2a4c11845","tarball":"https://registry.npmjs.org/@canvastack/canvable/-/canvable-0.3.5.tgz","fileCount":8,"integrity":"sha512-kWvd0Y3DRzT+W2PgdNIxr4p6Hv7R5JQg95fAQc5ge7iFms+t5Bi4ge1+j7oItsIWGr+OjEqsD7AuMOtwHd/q7A==","signatures":[{"sig":"MEUCIAUwTs9o61yUQMqtIz0TqtVA0o1xLdeoP3zcmyM1wawwAiEA0zteCxCpepoFhpOdWcVkP0XmKVD70DpyfRfNEUntKfg=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":242250},"main":"./dist/index.js","types":"./dist/index.d.ts","module":"./dist/index.mjs","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","default":"./dist/index.mjs","require":"./dist/index.js"}},"gitHead":"622d9709612e6b812d7e250fd84baa6a3c89ff7d","scripts":{"dev":"tsup --watch","build":"tsup && node -e \"const fs = require('fs'); ['dist/index.js', 'dist/index.mjs'].forEach(f => { if (fs.existsSync(f)) { const content = fs.readFileSync(f, 'utf8'); if (!content.startsWith('\\\"use client\\\";')) fs.writeFileSync(f, '\\\"use client\\\";\\n' + content); } });\"","prepare":"npm run build","typecheck":"tsc --noEmit","prepublishOnly":"npm run build"},"_npmUser":{"name":"canvastack","email":"canvastacks@gmail.com"},"_npmVersion":"11.13.0","description":"Enterprise-grade, data-agnostic, themeable table component for React and Next.js by Canvastack","directories":{},"_nodeVersion":"24.16.0","dependencies":{"clsx":"^2.1.1","jspdf":"^4.2.1","lucide-react":"^0.475.0 || ^1.0.0","tailwind-merge":"^3.0.1","jspdf-autotable":"^5.0.8"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.3.6","typescript":"^5.7.0","@types/react":"^19.0.0","@types/react-dom":"^19.0.0"},"peerDependencies":{"react":"^18.0.0 || ^19.0.0","react-dom":"^18.0.0 || ^19.0.0"},"_npmOperationalInternal":{"tmp":"tmp/canvable_0.3.5_1787942915169_0.18381736918352787","host":"s3://npm-registry-packages-npm-production"},"deprecated":"Package no longer supported. Contact Support at https://www.npmjs.com/support for more info."},"0.3.6":{"name":"@canvastack/canvable","version":"0.3.6","keywords":["react","nextjs","table","datatable","canvastack","canvable","enterprise-table","headless","grid","export-csv","pagination"],"author":{"name":"Canvastack Team"},"license":"SEE LICENSE IN LICENSE.md","_id":"@canvastack/canvable@0.3.6","maintainers":[{"name":"canvastack","email":"canvastacks@gmail.com"}],"dist":{"shasum":"0b1f20d1989c9eda2d7fc2992f679078a42e6475","tarball":"https://registry.npmjs.org/@canvastack/canvable/-/canvable-0.3.6.tgz","fileCount":8,"integrity":"sha512-m2DhzijyTTRIPwFuDzSE8dBFyIcR4R+vzMea6z9GPIb4tzV2gTLTbeyhUpwoMGByhq79CIPJRCJEonHrtyjZQg==","signatures":[{"sig":"MEQCIErrwrpyxYtM/vRo9yu7XFKjRcyv2FEg8z4NXFNsM3TNAiAZAkXw6rpiyh7fxkaK3hRnjZ5tVlgX635lCdJL+168Uw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":245982},"main":"./dist/index.js","types":"./dist/index.d.ts","module":"./dist/index.mjs","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","default":"./dist/index.mjs","require":"./dist/index.js"}},"gitHead":"5ae6cfe4c39518c6dcfeab9ce5c55b2912be4dae","scripts":{"dev":"tsup --watch","build":"tsup && node -e \"const fs = require('fs'); ['dist/index.js', 'dist/index.mjs'].forEach(f => { if (fs.existsSync(f)) { const content = fs.readFileSync(f, 'utf8'); if (!content.startsWith('\\\"use client\\\";')) fs.writeFileSync(f, '\\\"use client\\\";\\n' + content); } });\"","prepare":"npm run build","typecheck":"tsc --noEmit","prepublishOnly":"npm run build"},"_npmUser":{"name":"canvastack","email":"canvastacks@gmail.com"},"_npmVersion":"11.13.0","description":"Enterprise-grade, data-agnostic, themeable table component for React and Next.js by Canvastack","directories":{},"_nodeVersion":"24.16.0","dependencies":{"clsx":"^2.1.1","jspdf":"^4.2.1","lucide-react":"^0.475.0 || ^1.0.0","tailwind-merge":"^3.0.1","jspdf-autotable":"^5.0.8"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.3.6","typescript":"^5.7.0","@types/react":"^19.0.0","@types/react-dom":"^19.0.0"},"peerDependencies":{"react":"^18.0.0 || ^19.0.0","react-dom":"^18.0.0 || ^19.0.0"},"_npmOperationalInternal":{"tmp":"tmp/canvable_0.3.6_1788234015481_0.31072772720141906","host":"s3://npm-registry-packages-npm-production"},"deprecated":"Package no longer supported. Contact Support at https://www.npmjs.com/support for more info."},"0.3.7":{"name":"@canvastack/canvable","version":"0.3.7","keywords":["react","nextjs","table","datatable","canvastack","canvable","enterprise-table","headless","grid","export-csv","pagination"],"author":{"name":"Canvastack Team"},"license":"SEE LICENSE IN LICENSE.md","_id":"@canvastack/canvable@0.3.7","maintainers":[{"name":"canvastack","email":"canvastacks@gmail.com"}],"dist":{"shasum":"ec0feb79536ea7156154423f6af8fb43dfc38eee","tarball":"https://registry.npmjs.org/@canvastack/canvable/-/canvable-0.3.7.tgz","fileCount":8,"integrity":"sha512-UNqmKOCbCUrR1AAd0sdqYeFdO/8pes3JancH4iqx+xCdnTqiPQfDaH1OkaG7sRnzTPYiSTtgEXSCUmGXP3MBcQ==","signatures":[{"sig":"MEQCID03n/nOzCeAmh4+4Tjav5MKi09mFgHItidko4/7RAp7AiBUvaI/+LVjNkSrNoLsPGpyMGcHY1bOEeZR9ze+RLaauA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":246164},"main":"./dist/index.js","types":"./dist/index.d.ts","module":"./dist/index.mjs","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","default":"./dist/index.mjs","require":"./dist/index.js"}},"gitHead":"6d180d0caae3778e4f2d47d6655f6f887e05c3b5","scripts":{"dev":"tsup --watch","build":"tsup && node -e \"const fs = require('fs'); ['dist/index.js', 'dist/index.mjs'].forEach(f => { if (fs.existsSync(f)) { const content = fs.readFileSync(f, 'utf8'); if (!content.startsWith('\\\"use client\\\";')) fs.writeFileSync(f, '\\\"use client\\\";\\n' + content); } });\"","prepare":"npm run build","typecheck":"tsc --noEmit","prepublishOnly":"npm run build"},"_npmUser":{"name":"canvastack","email":"canvastacks@gmail.com"},"_npmVersion":"11.13.0","description":"Enterprise-grade, data-agnostic, themeable table component for React and Next.js by Canvastack","directories":{},"_nodeVersion":"24.16.0","dependencies":{"clsx":"^2.1.1","jspdf":"^4.2.1","lucide-react":"^0.475.0 || ^1.0.0","tailwind-merge":"^3.0.1","jspdf-autotable":"^5.0.8"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.3.6","typescript":"^5.7.0","@types/react":"^19.0.0","@types/react-dom":"^19.0.0"},"peerDependencies":{"react":"^18.0.0 || ^19.0.0","react-dom":"^18.0.0 || ^19.0.0"},"_npmOperationalInternal":{"tmp":"tmp/canvable_0.3.7_1788238366934_0.6740989789980203","host":"s3://npm-registry-packages-npm-production"},"deprecated":"Package no longer supported. Contact Support at https://www.npmjs.com/support for more info."},"0.3.8":{"name":"@canvastack/canvable","version":"0.3.8","keywords":["react","nextjs","table","datatable","canvastack","canvable","enterprise-table","headless","grid","export-csv","pagination"],"author":{"name":"Canvastack Team"},"license":"SEE LICENSE IN LICENSE.md","_id":"@canvastack/canvable@0.3.8","maintainers":[{"name":"canvastack","email":"canvastacks@gmail.com"}],"dist":{"shasum":"f5dc217be4471d9c10a1100721fdeb13f6a4e579","tarball":"https://registry.npmjs.org/@canvastack/canvable/-/canvable-0.3.8.tgz","fileCount":8,"integrity":"sha512-bx9iZRIyzXlHJNCBJvYheF3dMQOXT84NIpCAUEw7h4DZSNPDJPTEkJ89DwYU8wFL4i6vXJRgwgmUzIJYTxjq7w==","signatures":[{"sig":"MEYCIQDz00zaEvbcUVQniuyxfp4faB79sWHFkBEEqgQMEfuIgQIhAJN0OTUW/EChZM+VIfDbSluXwxar1RlSWHDZVsc1UqRb","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":246164},"main":"./dist/index.js","types":"./dist/index.d.ts","module":"./dist/index.mjs","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","default":"./dist/index.mjs","require":"./dist/index.js"}},"gitHead":"63d9ec69a626fc0575567090b905f8ec0067a2a6","scripts":{"dev":"tsup --watch","build":"tsup && node -e \"const fs = require('fs'); ['dist/index.js', 'dist/index.mjs'].forEach(f => { if (fs.existsSync(f)) { const content = fs.readFileSync(f, 'utf8'); if (!content.startsWith('\\\"use client\\\";')) fs.writeFileSync(f, '\\\"use client\\\";\\n' + content); } });\"","prepare":"npm run build","typecheck":"tsc --noEmit","prepublishOnly":"npm run build"},"_npmUser":{"name":"canvastack","email":"canvastacks@gmail.com"},"_npmVersion":"11.13.0","description":"Enterprise-grade, data-agnostic, themeable table component for React and Next.js by Canvastack","directories":{},"_nodeVersion":"24.16.0","dependencies":{"clsx":"^2.1.1","jspdf":"^4.2.1","lucide-react":"^0.475.0 || ^1.0.0","tailwind-merge":"^3.0.1","jspdf-autotable":"^5.0.8"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.3.6","typescript":"^5.7.0","@types/react":"^19.0.0","@types/react-dom":"^19.0.0"},"peerDependencies":{"react":"^18.0.0 || ^19.0.0","react-dom":"^18.0.0 || ^19.0.0"},"_npmOperationalInternal":{"tmp":"tmp/canvable_0.3.8_1788238501067_0.7853517715234881","host":"s3://npm-registry-packages-npm-production"},"deprecated":"Package no longer supported. Contact Support at https://www.npmjs.com/support for more info."},"0.4.0":{"name":"@canvastack/canvable","version":"0.4.0","keywords":["react","nextjs","table","datatable","canvastack","canvable","enterprise-table","headless","grid","export-csv","pagination"],"author":{"name":"Canvastack Team"},"license":"SEE LICENSE IN LICENSE.md","_id":"@canvastack/canvable@0.4.0","maintainers":[{"name":"canvastack","email":"canvastacks@gmail.com"}],"dist":{"shasum":"37ab6edd8a78156a546ee6f464549ad0b264986f","tarball":"https://registry.npmjs.org/@canvastack/canvable/-/canvable-0.4.0.tgz","fileCount":8,"integrity":"sha512-GRc4T/h+Jq5nEuoHxk464aXQNxJ1OGzVqvDnGqqFVyOlLZh6vkyuuUxw+uIttQymoGj8ZyUTEewz2dgNTR8hpA==","signatures":[{"sig":"MEYCIQD0RAg1o+iPnSIg+E6xp6UztnqnLB/9dYSxWV3f8WBOjgIhAPV9OW1jwHFaDkANGRFujavW9Ii4rxZ/16CSsdbHIxDP","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":268348},"main":"./dist/index.js","types":"./dist/index.d.ts","module":"./dist/index.mjs","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","default":"./dist/index.mjs","require":"./dist/index.js"}},"gitHead":"282a6d22f396252d97358fc692977b3ea84c7004","scripts":{"dev":"tsup --watch","build":"tsup && node -e \"const fs = require('fs'); ['dist/index.js', 'dist/index.mjs'].forEach(f => { if (fs.existsSync(f)) { const content = fs.readFileSync(f, 'utf8'); if (!content.startsWith('\\\"use client\\\";')) fs.writeFileSync(f, '\\\"use client\\\";\\n' + content); } });\"","prepare":"npm run build","typecheck":"tsc --noEmit","prepublishOnly":"npm run build"},"_npmUser":{"name":"canvastack","email":"canvastacks@gmail.com"},"_npmVersion":"11.13.0","description":"Enterprise-grade, data-agnostic, themeable table component for React and Next.js by Canvastack","directories":{},"_nodeVersion":"24.16.0","dependencies":{"clsx":"^2.1.1","jspdf":"^4.2.1","lucide-react":"^0.475.0 || ^1.0.0","tailwind-merge":"^3.0.1","jspdf-autotable":"^5.0.8"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.3.6","typescript":"^5.7.0","@types/react":"^19.0.0","@types/react-dom":"^19.0.0"},"peerDependencies":{"react":"^18.0.0 || ^19.0.0","react-dom":"^18.0.0 || ^19.0.0"},"_npmOperationalInternal":{"tmp":"tmp/canvable_0.4.0_1788371797619_0.883259235600353","host":"s3://npm-registry-packages-npm-production"},"deprecated":"Package no longer supported. Contact Support at https://www.npmjs.com/support for more info."},"1.0.0":{"name":"@canvastack/canvable","version":"1.0.0","keywords":["react","nextjs","table","datatable","canvastack","canvable","enterprise-table","headless","grid","export-csv","pagination"],"author":{"name":"Canvastack Team"},"license":"SEE LICENSE IN LICENSE.md","_id":"@canvastack/canvable@1.0.0","maintainers":[{"name":"canvastack","email":"canvastacks@gmail.com"}],"dist":{"shasum":"b8b2125ac2b8f593d3d1840b144ffd5674e2588f","tarball":"https://registry.npmjs.org/@canvastack/canvable/-/canvable-1.0.0.tgz","fileCount":8,"integrity":"sha512-WexdKjPtYAcbiyxviTvCGxj8dlSNVIpOYRajQCKUQBdHKSrbVEVKXyUDdtfvcYgyJIGuGU8lY1sVhKj8iKp8MA==","signatures":[{"sig":"MEQCIEnp2igZkMoWEy0QzSyu2kEy7lU5kVVUKjJOrCVCD4NAAiAAimDRiJBrCOXhefwOyZk0ZZbHkZ6cANf59nbSEag7Pg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":328606},"main":"./dist/index.js","types":"./dist/index.d.ts","module":"./dist/index.mjs","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","default":"./dist/index.mjs","require":"./dist/index.js"}},"gitHead":"aef532b474a8b228cdaceaf75655936cf663d467","scripts":{"dev":"tsup --watch","build":"tsup && node -e \"const fs = require('fs'); ['dist/index.js', 'dist/index.mjs'].forEach(f => { if (fs.existsSync(f)) { const content = fs.readFileSync(f, 'utf8'); if (!content.startsWith('\\\"use client\\\";')) fs.writeFileSync(f, '\\\"use client\\\";\\n' + content); } });\"","prepare":"npm run build","typecheck":"tsc --noEmit","prepublishOnly":"npm run build"},"_npmUser":{"name":"canvastack","email":"canvastacks@gmail.com"},"_npmVersion":"11.13.0","description":"Enterprise-grade, data-agnostic, themeable table component for React and Next.js by Canvastack","directories":{},"_nodeVersion":"24.16.0","dependencies":{"clsx":"^2.1.1","jspdf":"^4.2.1","lucide-react":"^0.475.0 || ^1.0.0","tailwind-merge":"^3.0.1","jspdf-autotable":"^5.0.8"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.3.6","typescript":"^5.7.0","@types/react":"^19.0.0","@types/react-dom":"^19.0.0"},"peerDependencies":{"react":"^18.0.0 || ^19.0.0","react-dom":"^18.0.0 || ^19.0.0"},"_npmOperationalInternal":{"tmp":"tmp/canvable_1.0.0_1788373971594_0.8954921479260254","host":"s3://npm-registry-packages-npm-production"},"deprecated":"Package no longer supported. Contact Support at https://www.npmjs.com/support for more info."},"1.0.1":{"name":"@canvastack/canvable","version":"1.0.1","keywords":["react","nextjs","table","datatable","canvastack","canvable","enterprise-table","headless","grid","export-csv","pagination"],"author":{"name":"Canvastack Team"},"license":"SEE LICENSE IN LICENSE.md","_id":"@canvastack/canvable@1.0.1","maintainers":[{"name":"canvastack","email":"canvastacks@gmail.com"}],"dist":{"shasum":"caf25677dcd84af261bc53f786292b5c57f0b2b1","tarball":"https://registry.npmjs.org/@canvastack/canvable/-/canvable-1.0.1.tgz","fileCount":8,"integrity":"sha512-sha36OYr8ihX8mzw6unDRqU0r359AhZWzfr8DP2wNhEF5Ljqf7RLYHE3YiTJ23ls7QuA+kvgU5b4sfMmiykHRA==","signatures":[{"sig":"MEUCIQDvfrTBrN6qpLwABxPwxHhadXZ8bjrEqfHAf+q9PNVa9QIgMTwQ9P/8TgQI6h6nXKxU3LS2aBoFcKCiaj4P+WHK8g0=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":335946},"main":"./dist/index.js","types":"./dist/index.d.ts","module":"./dist/index.mjs","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","default":"./dist/index.mjs","require":"./dist/index.js"}},"gitHead":"0d4e51d9fa7917e7e94eb4803ea1bb76d9dfdef4","scripts":{"dev":"tsup --watch","build":"tsup && node -e \"const fs = require('fs'); ['dist/index.js', 'dist/index.mjs'].forEach(f => { if (fs.existsSync(f)) { const content = fs.readFileSync(f, 'utf8'); if (!content.startsWith('\\\"use client\\\";')) fs.writeFileSync(f, '\\\"use client\\\";\\n' + content); } });\"","prepare":"npm run build","typecheck":"tsc --noEmit","prepublishOnly":"npm run build"},"_npmUser":{"name":"canvastack","email":"canvastacks@gmail.com"},"_npmVersion":"11.13.0","description":"Enterprise-grade, data-agnostic, themeable table component for React and Next.js by Canvastack","directories":{},"_nodeVersion":"24.16.0","dependencies":{"clsx":"^2.1.1","jspdf":"^4.2.1","lucide-react":"^0.475.0 || ^1.0.0","tailwind-merge":"^3.0.1","jspdf-autotable":"^5.0.8"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.3.6","typescript":"^5.7.0","@types/react":"^19.0.0","@types/react-dom":"^19.0.0"},"peerDependencies":{"react":"^18.0.0 || ^19.0.0","react-dom":"^18.0.0 || ^19.0.0"},"_npmOperationalInternal":{"tmp":"tmp/canvable_1.0.1_1788375790434_0.4177004366140715","host":"s3://npm-registry-packages-npm-production"},"deprecated":"Package no longer supported. Contact Support at https://www.npmjs.com/support for more info."},"1.0.2":{"name":"@canvastack/canvable","version":"1.0.2","keywords":["react","nextjs","table","datatable","canvastack","canvable","enterprise-table","headless","grid","export-csv","pagination"],"author":{"name":"Canvastack Team"},"license":"SEE LICENSE IN LICENSE.md","_id":"@canvastack/canvable@1.0.2","maintainers":[{"name":"canvastack","email":"canvastacks@gmail.com"}],"dist":{"shasum":"a7140085a007fe5a2f5a5d3b90ab0e863ab713df","tarball":"https://registry.npmjs.org/@canvastack/canvable/-/canvable-1.0.2.tgz","fileCount":8,"integrity":"sha512-RqW8+VqMib4y4DfOHKvvbSQ5ZCvjKJGqApB6V4amLQ9uAuT5JQ/FmMI9s/csVclZy4hsvz5zyOn7IUwgZPF8mg==","signatures":[{"sig":"MEUCIFPLUyZtSW2i5zqWtzGMAh4NhSWOl+5K/1nm19RMaD60AiEA7jKreOsnVGnx+9go7PvD5kVzmH8L6gQ5QEi5aiAxuFs=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":371668},"main":"./dist/index.js","types":"./dist/index.d.ts","module":"./dist/index.mjs","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","default":"./dist/index.mjs","require":"./dist/index.js"}},"gitHead":"c7b226b1718656f22506da55c028c66cbf42eaa7","scripts":{"dev":"tsup --watch","build":"tsup && node -e \"const fs = require('fs'); ['dist/index.js', 'dist/index.mjs'].forEach(f => { if (fs.existsSync(f)) { const content = fs.readFileSync(f, 'utf8'); if (!content.startsWith('\\\"use client\\\";')) fs.writeFileSync(f, '\\\"use client\\\";\\n' + content); } });\"","prepare":"npm run build","typecheck":"tsc --noEmit","prepublishOnly":"npm run build"},"_npmUser":{"name":"canvastack","email":"canvastacks@gmail.com"},"_npmVersion":"11.13.0","description":"Enterprise-grade, data-agnostic, themeable table component for React and Next.js by Canvastack","directories":{},"_nodeVersion":"24.16.0","dependencies":{"clsx":"^2.1.1","jspdf":"^4.2.1","lucide-react":"^0.475.0 || ^1.0.0","tailwind-merge":"^3.0.1","jspdf-autotable":"^5.0.8"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.3.6","typescript":"^5.7.0","@types/react":"^19.0.0","@types/react-dom":"^19.0.0"},"peerDependencies":{"react":"^18.0.0 || ^19.0.0","react-dom":"^18.0.0 || ^19.0.0"},"_npmOperationalInternal":{"tmp":"tmp/canvable_1.0.2_1788377200313_0.5010333477741808","host":"s3://npm-registry-packages-npm-production"},"deprecated":"Package no longer supported. Contact Support at https://www.npmjs.com/support for more info."}},"time":{"created":"2026-08-28T18:48:34.921Z","modified":"2026-09-07T17:30:59.222Z","0.1.0":"2026-08-27T05:14:01.308Z","0.1.1":"2026-08-27T05:34:28.762Z","0.1.2":"2026-08-27T05:52:51.741Z","0.1.3":"2026-08-27T06:24:59.828Z","0.1.4":"2026-08-27T06:45:43.679Z","0.1.5":"2026-08-27T07:09:35.203Z","0.2.0":"2026-08-27T10:31:08.260Z","0.2.1":"2026-08-27T10:42:20.776Z","0.2.2":"2026-08-27T10:45:30.755Z","0.2.3":"2026-08-27T10:52:48.381Z","0.2.4":"2026-08-27T15:58:24.967Z","0.3.0":"2026-08-27T16:44:38.705Z","0.3.1":"2026-08-27T17:03:14.661Z","0.3.2":"2026-08-27T18:37:50.359Z","0.3.3":"2026-08-27T19:44:43.216Z","0.3.4":"2026-08-27T20:02:01.176Z","0.3.5":"2026-08-28T18:48:35.310Z","0.3.6":"2026-09-01T03:40:15.626Z","0.3.7":"2026-09-01T04:52:47.070Z","0.3.8":"2026-09-01T04:55:01.228Z","0.4.0":"2026-09-02T17:56:37.773Z","1.0.0":"2026-09-02T18:32:51.774Z","1.0.1":"2026-09-02T19:03:10.592Z","1.0.2":"2026-09-02T19:26:40.482Z"},"author":{"name":"Canvastack Team"},"license":"SEE LICENSE IN LICENSE.md","keywords":["react","nextjs","table","datatable","canvastack","canvable","enterprise-table","headless","grid","export-csv","pagination"],"description":"Enterprise-grade, data-agnostic, themeable table component for React and Next.js by Canvastack","maintainers":[{"name":"canvastack","email":"canvastacks@gmail.com"}],"readme":"# CanvaStack Table\r\n***(`@canvastack/canvable`)***\r\n\r\n> Enterprise-grade, data-agnostic, themeable table component for React and Next.js by **CanvaStack**.\r\n\r\n[![npm version](https://img.shields.io/npm/v/@canvastack/canvable.svg)](https://www.npmjs.com/package/@canvastack/canvable)\r\n[![License: Dual](https://img.shields.io/badge/License-Dual%20(MIT%2B%2BCommercial)-blue.svg)](./LICENSE.md)\r\n\r\n---\r\n\r\n## ✨ Features\r\n\r\n### 🎯 **Core Features**\r\n-  **100% Data & Backend Agnostic**: Works seamlessly with PostgreSQL, MySQL, MongoDB, Firebase, Supabase, Go, Laravel, FastAPI, etc.\r\n-  **Plug & Play Data Fetching**: Supports Controlled Mode (SWR / React Query), Auto-Fetcher Callback Mode, and In-Memory Client-Side Mode.\r\n-  **Nested Dot-Notation Keys**: Access deep relations effortlessly (`\"guardian.profile.name\"`).\r\n\r\n### 📊 **Data Management**\r\n-  **Enterprise Pagination**: First, Prev, Smart Ellipsis numbers, Next, Last, Dynamic Total Pages calculation, and Direct Jump.\r\n-  **Cascading Auto-Complete Filtering**: Column-specific filter drawer with free-text substring search, A–Z unique suggestions dropdown, single-field (X) clear, and interconnected cross-filtering.\r\n-  **Interactive Row Drag & Drop Reordering**: Drag rows or use accessible Up/Down buttons with automatic gap-free `1..N` sequential renumbering.\r\n-  **Dynamic Sorting**: Client-side and server-side multi-sorting with visual indicators.\r\n-  **Row Grouping**: Dynamic row grouping with collapse/expand functionality.\r\n-  **Expandable Rows**: Master-detail pattern support with nested component rendering.\r\n\r\n### 🎨 **UI/UX Features**\r\n-  **Anti-Wrapping & Strict 1-Row Layout**: Headers and cells never wrap unintentionally; truncates with tooltip and smooth horizontal scrolling.\r\n-  **Table ⇄ Card Grid Switcher**: Instant view toggle between standard table rows and responsive cards.\r\n-  **Fullscreen Mode**: Expand to full viewport for comfortable high-volume data analysis.\r\n-  **Bulk Select & Action Bar**: Master checkbox, multi-selection, and docked bulk action toolbar.\r\n-  **Column Management**: Show/hide columns, reorder columns, pin columns (left/right sticky).\r\n\r\n### ⌨️ **Keyboard Navigation**\r\n-  **Quick Search**: Press `/` to focus search input\r\n-  **Menu Controls**: `e` for export, `c` for columns, `r` for refresh\r\n-  **View Controls**: `f` for fullscreen toggle, `Esc` to close menus\r\n-  **Table Navigation**: `Ctrl+Home/End` for horizontal table scrolling\r\n-  **Compact View**: `d` for density toggle\r\n-  **Help**: Press `?` to view all keyboard shortcuts\r\n\r\n### 💾 **View Presets**\r\n-  **Saved Views**: Save and restore table configurations (filters, sorting, columns, grouping)\r\n-  **localStorage Persistence**: Automatic state preservation across sessions\r\n-  **Multiple Views**: Create unlimited view presets per table instance\r\n\r\n### 📤 **Export Suite**\r\n-  **Multiple Export Formats**: CSV, Excel (.xls), Plain Text (.txt), PDF (with jsPDF), Print (HTML render).\r\n-  **Professional Print Output**: Styled print templates with headers, footers, page numbers, and branding.\r\n-  **PDF Generation**: High-quality PDF with auto-table layout, landscape A4 format, and metadata.\r\n-  **Copy to Clipboard**: Instant TSV clipboard copy with success feedback.\r\n-  **Smart Export**: Export selected rows or all displayed rows.\r\n\r\n### 🎨 **Theming & Styling**\r\n-  **Themeable & CSS Variables Friendly**: Automatically inherits your project's Tailwind or CSS variables.\r\n-  **Dark Mode Support**: Built-in dark mode compatibility.\r\n-  **Brand Color Integration**: Custom primary color support (#C8102E default).\r\n\r\n---\r\n\r\n## 🎯 Feature Tier Breakdown\r\n\r\n### ✅ **BASIC TIER** (FREE - MIT License)\r\nAlways available in all tiers:\r\n- Realtime Global Search with Debounce & Highlight\r\n- Multi-direction Column Sorting (Ascending / Descending)\r\n- Standard Pagination & Dynamic Page Size Controls\r\n- Row Hovering & Zebra Striping\r\n- Native Dark / Light Mode Compatibility\r\n- Cascading Auto-Complete Column Filters & Switcher\r\n- Document Print Engine (Isolated Iframe & Ctrl+P)\r\n- Standard Status Badges (`CanvableStatusPill`)\r\n\r\n### 💎 **PREMIUM TIER** (Commercial License)\r\nUnlock professional features:\r\n- Refresh Button (`enableRefresh`)\r\n- Multi-format Export Suite: CSV, Excel (.xls), Plain Text (.txt) (`enableExportSuite`)\r\n- Row Density Switcher: Comfortable vs Compact (`enableDensityToggle`)\r\n- Column Settings: Visibility Toggle & Column Reordering (`enableColumnToggle`)\r\n- Card Grid View: Dynamic Table ⇄ Card Grid View Mode Switch (`enableCardView`)\r\n- Quick Clipboard Copy (`enableClipboardCopy`)\r\n- Fullscreen Focus Mode (`enableFullscreen`)\r\n- Direct Jump-to-Page Pagination (`enableJumpToPage`)\r\n\r\n### 🚀 **ENTERPRISE TIER** (Commercial License)\r\nFull-featured powerhouse for mission-critical systems:\r\n- Interactive Row Drag & Drop Reordering (`enableRowDnD`, `dndSortable`, `onRowReorder`)\r\n- Inline Cell Editing & Batch Dirty Saving Bar (`enableInlineEdit`, `onBatchSave`)\r\n- Excel-like Cell Range Selection & TSV Copy/Paste (`enableCellSelection`)\r\n- Direct Drag & Drop Column Header Reordering (`enableHeaderDnD`)\r\n- Conditional Formatting: Heatmaps, Data Bars & Thresholds (`enableConditionalFormatting`)\r\n- Advanced Date-Range & Number Range Slider Filters (`enableRangeFilters`)\r\n- 2D Pivot Matrix Cross-Tabulation Grid View (`enablePivotMode`)\r\n- DOM Virtual Scrolling Engine for 100k+ Rows (`enableVirtualization`)\r\n- Infinite Scroll & Intersection Virtual Pagination (`enableInfiniteScroll`)\r\n- Row Audit Trail & Details Side-Drawer (`enableAuditDrawer`)\r\n- Branded PDF Template Official Export (`enableBrandedPdf`)\r\n- Sticky Column Pinning: Pin Left / Pin Right (`enableColumnPinning`)\r\n- Pure Vector Client-side PDF Generation (`enablePdfExport`)\r\n- JSON Payload & Markdown Table Export (`enableJsonExport`, `enableMarkdownExport`)\r\n- Global Search Query Text Highlighter (`enableSearchHighlight`)\r\n- Interactive Drag Column Resizing (`enableColumnResizing`)\r\n- Quick Status Filter Chips Bar (`enableFilterChips`)\r\n- Multi-Column Sorting with Shift+Click (`enableMultiSort`)\r\n- Dynamic Multi-column Row Grouping with Accordion (`enableGrouping`)\r\n- Saved View Profiles: Filters/Columns Storage (`enableSavedViews`)\r\n- Enterprise Keyboard Navigation Shortcuts (`enableKeyboardShortcuts`)\r\n- Multi-row Bulk Selection & Sticky Action Bar (`enableBulkSelect`)\r\n- Nested Sub-Component / Expandable Sub-Rows (`enableSubComponent`)\r\n- Summary Footer Row Aggregations (`enableAggregations`)\r\n\r\n---\r\n\r\n## 📦 Installation\r\n\r\nInstall directly from GitHub repository or NPM:\r\n\r\n```bash\r\n# Using npm\r\nnpm install @canvastack/canvable\r\n\r\n# Using pnpm\r\npnpm add @canvastack/canvable\r\n\r\n# Using yarn\r\nyarn add @canvastack/canvable\r\n\r\n# From GitHub (always latest)\r\nnpm install git+https://github.com/canvastack/canvable.git\r\n```\r\n\r\n---\r\n\r\n## 🚀 Quick Start Examples\r\n\r\n### 1. Controlled Mode (SWR / React Query)\r\n\r\n```tsx\r\n\"use client\";\r\n\r\nimport { useState } from \"react\";\r\nimport useSWR from \"swr\";\r\nimport { CanvableTable, type CanvableColumn } from \"@canvastack/canvable\";\r\n\r\ninterface User {\r\n  id: string;\r\n  name: string;\r\n  email: string;\r\n  role: { name: string };\r\n}\r\n\r\nconst columns: CanvableColumn<User>[] = [\r\n  { key: \"id\", label_id: \"ID\", label_en: \"ID\", sortable: true },\r\n  { key: \"name\", label_id: \"Nama\", label_en: \"Name\", sortable: true },\r\n  { key: \"email\", label_id: \"Email\", label_en: \"Email\" },\r\n  { key: \"role.name\", label_id: \"Peran\", label_en: \"Role\" }, // Nested dot notation!\r\n];\r\n\r\nexport function UserList() {\r\n  const [page, setPage] = useState(1);\r\n  const [search, setSearch] = useState(\"\");\r\n  \r\n  const { data, isLoading } = useSWR(`/api/users?page=${page}&q=${search}`);\r\n\r\n  return (\r\n    <CanvableTable\r\n      columns={columns}\r\n      data={data?.items}\r\n      isLoading={isLoading}\r\n      currentPage={page}\r\n      totalPages={data?.total_pages}\r\n      totalRecords={data?.total_records}\r\n      onPageChange={setPage}\r\n      onSearch={setSearch}\r\n      enableExport\r\n      enableFullscreen\r\n      enableBulkSelect\r\n      enableKeyboardShortcuts\r\n      enableSavedViews\r\n    />\r\n  );\r\n}\r\n```\r\n\r\n---\r\n\r\n### 2. Auto-Fetcher Mode (Zero Boilerplate)\r\n\r\n```tsx\r\n\"use client\";\r\n\r\nimport { CanvableTable } from \"@canvastack/canvable\";\r\nimport axios from \"axios\";\r\n\r\nexport function AutoFetchTable() {\r\n  return (\r\n    <CanvableTable\r\n      columns={columns}\r\n      fetcher={async ({ page, pageSize, search, sortKey, sortDirection, filters }) => {\r\n        const res = await axios.get(\"/api/products\", {\r\n          params: { page, limit: pageSize, q: search, sort: sortKey, dir: sortDirection, ...filters },\r\n        });\r\n        return {\r\n          data: res.data.items,\r\n          totalRecords: res.data.total,\r\n          totalPages: res.data.pages,\r\n        };\r\n      }}\r\n      enableKeyboardShortcuts\r\n      enableGrouping\r\n    />\r\n  );\r\n}\r\n```\r\n\r\n---\r\n\r\n### 3. In-Memory Client-Side Mode\r\n\r\n```tsx\r\n<CanvableTable\r\n  columns={columns}\r\n  data={staticOrPrefetchedArray} // Automatically handles client-side filtering, sorting, and pagination!\r\n  pageSize={10}\r\n  enableKeyboardShortcuts\r\n  enableSavedViews\r\n/>\r\n```\r\n\r\n---\r\n\r\n### 4. With Expandable Rows (Master-Detail)\r\n\r\n```tsx\r\n<CanvableTable\r\n  columns={columns}\r\n  data={orders}\r\n  renderSubComponent={(row) => (\r\n    <div className=\"p-4 bg-muted/50\">\r\n      <h4 className=\"font-semibold mb-2\">Order Items</h4>\r\n      <CanvableTable\r\n        columns={itemColumns}\r\n        data={row.items}\r\n        enableExport={false}\r\n        enableFullscreen={false}\r\n      />\r\n    </div>\r\n  )}\r\n/>\r\n```\r\n\r\n---\r\n\r\n### 5. With Row Grouping\r\n\r\n```tsx\r\n<CanvableTable\r\n  columns={columns}\r\n  data={transactions}\r\n  groupBy=\"status\" // Group by field\r\n  // or\r\n  groupBy={(row) => row.createdAt.slice(0, 7)} // Group by custom logic\r\n  enableGrouping\r\n/>\r\n```\r\n\r\n---\r\n\r\n### 6. With Saved Views\r\n\r\n```tsx\r\n<CanvableTable\r\n  columns={columns}\r\n  data={data}\r\n  enableSavedViews\r\n  savedViewsStorageKey=\"my-custom-table-views\" // Unique key per table\r\n/>\r\n```\r\n\r\n---\r\n\r\n### 7. With Interactive Row Drag & Drop Reordering\r\n\r\n```tsx\r\nconst columns: CanvableColumn<Item>[] = [\r\n  {\r\n    key: \"sort_order\",\r\n    label_id: \"Urutan\",\r\n    label_en: \"Order\",\r\n    dndSortable: true, // Enables DnD grip & Up/Down chevron buttons\r\n    width: \"120px\",\r\n  },\r\n  { key: \"name\", label_id: \"Nama\", label_en: \"Name\", sortable: true },\r\n];\r\n\r\n<CanvableTable\r\n  columns={columns}\r\n  data={items}\r\n  enableRowDnD\r\n  dndSortKey=\"sort_order\"\r\n  onRowReorder={async (reorderedList, movedItem, newIndex) => {\r\n    // 1. Optimistic UI update\r\n    setItems(reorderedList);\r\n    // 2. Persist to your backend API\r\n    await apiClient.put(\"/api/items/reorder\", { items: reorderedList });\r\n  }}\r\n/>\r\n```\r\n\r\n---\r\n\r\n## ⚙️ Tier Configuration\r\n\r\nUse `resolveCanvableFeatures()` to configure features based on your tier:\r\n\r\n```typescript\r\nimport { resolveCanvableTable, type CanvableTier } from \"@canvastack/canvable\";\r\n\r\n// Auto-resolve from environment\r\nconst features = resolveCanvableFeatures({\r\n  NEXT_PUBLIC_CANVABLE_TIER: \"enterprise\"\r\n});\r\n\r\n// Or explicit tier\r\nconst premiumFeatures = resolveCanvableFeatures({ tier: \"premium\" });\r\n\r\n// Access resolved features\r\nconsole.log(features.enablePdfExport); // true (enterprise)\r\nconsole.log(features.enableGrouping); // true (enterprise)\r\nconsole.log(features.enableExportSuite); // true (premium+)\r\n```\r\n\r\n**Environment Variables:**\r\n```bash\r\n# Tier-based activation\r\nNEXT_PUBLIC_CANVABLE_TIER=basic|premium|enterprise\r\n\r\n# Bulk feature toggles\r\nNEXT_PUBLIC_CANVABLE_PREMIUM_ALL=true\r\nNEXT_PUBLIC_CANVABLE_ENTERPRISE_ALL=true\r\n\r\n# Granular feature control\r\nNEXT_PUBLIC_CANVABLE_FEATURE_PDF_EXPORT=true\r\nNEXT_PUBLIC_CANVABLE_FEATURE_GROUPING=true\r\nNEXT_PUBLIC_CANVABLE_FEATURE_KEYBOARD_SHORTCUTS=true\r\nNEXT_PUBLIC_CANVABLE_FEATURE_BULK_SELECT=true\r\nNEXT_PUBLIC_CANVABLE_FEATURE_SAVED_VIEWS=true\r\nNEXT_PUBLIC_CANVABLE_FEATURE_COLUMN_PINNING=true\r\n# ... and more\r\n```\r\n\r\n---\r\n\r\n## 📚 Props Reference\r\n\r\n### Core Props\r\n\r\n| Prop | Type | Default | Description |\r\n|---|---|---|---|\r\n| `columns` | `CanvableColumn<T>[]` | **Required** | Column definitions array |\r\n| `data` | `T[]` | `[]` | Data array for controlled or client-side mode |\r\n| `fetcher` | `(params) => Promise<...>` | `undefined` | Async fetcher function for auto-fetching mode |\r\n| `isLoading` | `boolean` | `false` | Loading skeleton trigger |\r\n| `rowKey` | `(row: T) => string` | `(row) => row.id` | Unique key accessor for each row |\r\n\r\n### Pagination Props\r\n\r\n| Prop | Type | Default | Description |\r\n|---|---|---|---|\r\n| `pageSize` | `number` | `10` | Rows per page |\r\n| `pageSizeOptions` | `number[]` | `[10, 25, 50, 100]` | Dropdown page size choices |\r\n| `currentPage` | `number` | `1` | Current active page (1-indexed) |\r\n| `totalPages` | `number` | `1` | Total number of pages |\r\n| `totalRecords` | `number` | `undefined` | Total records count |\r\n| `onPageChange` | `(page: number) => void` | `undefined` | Page change callback |\r\n| `onPageSizeChange` | `(size: number) => void` | `undefined` | Page size change callback |\r\n\r\n### Search & Filter Props\r\n\r\n| Prop | Type | Default | Description |\r\n|---|---|---|---|\r\n| `searchPlaceholder` | `string` | `\"Cari data…\"` | Placeholder for search input |\r\n| `searchDebounceMs` | `number` | `300` | Debounce delay for search (ms) |\r\n| `onSearch` | `(query: string) => void` | `undefined` | Search query callback |\r\n| `enableFilterSwitch` | `boolean` | `true` | Show ON/OFF filter drawer switch |\r\n\r\n### Sorting Props\r\n\r\n| Prop | Type | Default | Description |\r\n|---|---|---|---|\r\n| `onSort` | `(key: string, dir: \"asc\"\\|\"desc\") => void` | `undefined` | Sort callback |\r\n| `sortKey` | `string` | `undefined` | Active sort column key |\r\n| `sortDirection` | `\"asc\" \\| \"desc\"` | `undefined` | Active sort direction |\r\n\r\n### Selection Props\r\n\r\n| Prop | Type | Default | Description |\r\n|---|---|---|---|\r\n| `selectedRows` | `Set<string>` | `undefined` | Selected row keys set |\r\n| `onSelectionChange` | `(selected: Set<string>) => void` | `undefined` | Selection change callback |\r\n| `enableBulkSelect` | `boolean` | `true` | Enable multi-row bulk selection |\r\n| `bulkActionsSlot` | `(selectedIds: string[]) => ReactNode` | `undefined` | Custom bulk actions slot |\r\n\r\n### Row Expansion Props\r\n\r\n| Prop | Type | Default | Description |\r\n|---|---|---|---|\r\n| `renderSubComponent` | `(row: T, index: number) => ReactNode` | `undefined` | Render nested component/table |\r\n| `expandedRows` | `Set<string>` | `undefined` | Controlled expanded row keys |\r\n| `onExpandedRowsChange` | `(expanded: Set<string>) => void` | `undefined` | Expansion change callback |\r\n\r\n### Grouping Props\r\n\r\n| Prop | Type | Default | Description |\r\n|---|---|---|---|\r\n| `groupBy` | `string \\| ((row: T) => string)` | `undefined` | Field key or accessor for grouping |\r\n| `enableGrouping` | `boolean` | `true` | Enable dynamic grouping selector |\r\n\r\n### Keyboard & UX Props\r\n\r\n| Prop | Type | Default | Description |\r\n|---|---|---|---|\r\n| `enableKeyboardShortcuts` | `boolean` | `true` | Enable keyboard navigation (/, f, e, c, r, ?) |\r\n| `enableSavedViews` | `boolean` | `true` | Enable view presets feature |\r\n| `savedViewsStorageKey` | `string` | `auto-generated` | localStorage key for views |\r\n\r\n### Export Props\r\n\r\n| Prop | Type | Default | Description |\r\n|---|---|---|---|\r\n| `enableExport` | `boolean` | `true` | Show CSV, Excel, TXT, Print export menu |\r\n| `exportFilename` | `string` | `\"canvable-data-export\"` | Base filename for exports |\r\n\r\n### UI Props\r\n\r\n| Prop | Type | Default | Description |\r\n|---|---|---|---|\r\n| `enableColumnToggle` | `boolean` | `true` | Allow users to show/hide columns |\r\n| `enableFullscreen` | `boolean` | `true` | Enable full viewport expansion |\r\n| `enableViewModeSwitch` | `boolean` | `true` | Switch between Table and Card Grid |\r\n| `defaultViewMode` | `\"table\" \\| \"grid\"` | `\"table\"` | Default view mode |\r\n| `language` | `\"id\" \\| \"en\"` | `\"id\"` | UI language (Indonesian/English) |\r\n| `emptyMessage` | `string` | `auto` | Message when no data matches |\r\n| `className` | `string` | `\"\"` | Additional container CSS class |\r\n\r\n### Action Props\r\n\r\n| Prop | Type | Default | Description |\r\n|---|---|---|---|\r\n| `actions` | `(row: T) => ReactNode` | `undefined` | Row action buttons render function |\r\n| `onRowClick` | `(row: T) => void` | `undefined` | Row click callback |\r\n| `onRefresh` | `() => void` | `undefined` | Refresh data callback |\r\n| `filtersSlot` | `ReactNode` | `undefined` | Custom filter slot in toolbar |\r\n\r\n---\r\n\r\n## 🎹 Keyboard Shortcuts\r\n\r\n### Basic Shortcuts\r\n| Key | Action |\r\n|---|---|\r\n| `/` | Focus search input |\r\n| `Esc` | Close menus / Exit fullscreen / Blur input |\r\n| `f` or `F` | Toggle fullscreen mode |\r\n| `e` or `E` | Toggle export menu |\r\n| `c` or `C` | Toggle column visibility menu |\r\n| `r` or `R` | Refresh/reload data |\r\n| `?` | Show keyboard shortcuts help modal |\r\n\r\n### Advanced Navigation\r\n| Key | Action |\r\n|---|---|\r\n| `Ctrl+Home` or `Cmd+Home` | Scroll table to leftmost (first column) |\r\n| `Ctrl+End` or `Cmd+End` | Scroll table to rightmost (last column) |\r\n| `d` or `D` | Toggle compact table view |\r\n| `p` or `P` | Open print dialog for styled print |\r\n\r\n> **Note:** Shortcuts are disabled when input/textarea is focused to prevent conflicts.\r\n\r\n---\r\n\r\n## 🎨 Column Definition\r\n\r\n```typescript\r\ninterface CanvableColumn<T> {\r\n  key: string;                    // Unique key or nested path (e.g., \"user.profile.name\")\r\n  label_id: string;               // Indonesian header label\r\n  label_en: string;               // English header label\r\n  sortable?: boolean;             // Enable sorting (default: false)\r\n  sticky?: \"left\" | \"right\";      // Pin column position\r\n  aggregation?: \"sum\" | \"avg\" | \"count\" | \"min\" | \"max\" | ((data: T[]) => ReactNode); // Summary footer\r\n  className?: string;             // Custom CSS classes\r\n  maxWidth?: string;              // Max width for truncation\r\n  exportValue?: (value: any, row: T) => string; // Custom export formatter\r\n  render?: (value: any, row: T, index: number) => ReactNode; // Custom render function\r\n}\r\n```\r\n\r\n---\r\n\r\n## 💡 Advanced Features\r\n\r\n### Export Formats\r\n\r\n```typescript\r\n// PDF Export with jsPDF\r\n<CanvableTable\r\n  columns={columns}\r\n  data={data}\r\n  enableExport // Automatically includes CSV, Excel, TXT, PDF, Print\r\n  exportFilename=\"my-report\"\r\n/>\r\n\r\n// Export handlers\r\nconst handleExport = (format: \"csv\" | \"excel\" | \"txt\" | \"pdf\" | \"print\") => {\r\n  // Triggered via export menu or keyboard shortcut\r\n};\r\n```\r\n\r\n### Custom Export Formatting\r\n\r\n```typescript\r\nconst columns: CanvableColumn<Transaction>[] = [\r\n  {\r\n    key: \"amount\",\r\n    label_id: \"Jumlah\",\r\n    label_en: \"Amount\",\r\n    exportValue: (value) => `Rp ${Number(value).toLocaleString(\"id-ID\")}`,\r\n    render: (value) => <span className=\"font-mono\">Rp {value.toLocaleString(\"id-ID\")}</span>\r\n  }\r\n];\r\n```\r\n\r\n### Interactive Status Pills\r\n\r\n```typescript\r\nimport { CanvableStatusPill } from \"@canvastack/canvable\";\r\n\r\n<CanvableStatusPill \r\n  tone=\"on\" \r\n  onClick={() => handleStatusChange()}\r\n  loading={isUpdating}\r\n  interactive\r\n>\r\n  Active\r\n</CanvableStatusPill>\r\n```\r\n\r\n### Column Pinning\r\n\r\n```typescript\r\nconst columns: CanvableColumn[] = [\r\n  { key: \"id\", label_id: \"ID\", label_en: \"ID\", sticky: \"left\" },\r\n  { key: \"name\", label_id: \"Nama\", label_en: \"Name\" },\r\n  { key: \"actions\", label_id: \"Aksi\", label_en: \"Actions\", sticky: \"right\" }\r\n];\r\n```\r\n\r\n---\r\n\r\n## 🔄 Migration Guide\r\n\r\n**All changes are backward compatible!** No breaking changes.\r\n\r\n**New optional features:**\r\n- Keyboard shortcuts (enabled by default, disable with `enableKeyboardShortcuts={false}`)\r\n- Saved views (enabled by default, disable with `enableSavedViews={false}`)\r\n- Row grouping (enabled by default, disable with `enableGrouping={false}`)\r\n\r\n---\r\n\r\n## 📝 TypeScript Support\r\n\r\nFully typed with TypeScript. Import types:\r\n\r\n```typescript\r\nimport type { \r\n  CanvableColumn,\r\n  CanvableTableProps,\r\n  CanvableFetcherParams,\r\n  CanvableFetcherResponse,\r\n  CanvableSavedView,\r\n  CanvableLanguage,\r\n  CanvableViewMode,\r\n  CanvableToneKey\r\n} from \"@canvastack/canvable\";\r\n```\r\n\r\n---\r\n\r\n## 🚀 Development & CI/CD\r\n\r\n### Automated Build Optimization\r\n- **GitHub Actions CI/CD Pipeline**: Automatic build, minification, and validation on every push\r\n- **Bundle Minification**: Production-optimized builds with ES2022 target\r\n- **Source Maps Disabled**: Smaller bundle sizes (~30% reduction)\r\n- **Auto-commit**: Minified dist automatically committed on master/main\r\n- **TypeScript Validation**: Type checking on every build\r\n\r\n### Local Development\r\n```bash\r\n# Install dependencies\r\nnpm install\r\n\r\n# Development with watch mode\r\nnpm run dev\r\n\r\n# Type checking\r\nnpm run typecheck\r\n\r\n# Production build\r\nnpm run build\r\n\r\n# Auto-build on install (prepare hook)\r\nnpm install @canvastack/canvable  # Automatically builds dist\r\n```\r\n\r\n### Build Configuration\r\n- **Format**: CommonJS (CJS) + ECMAScript Modules (ESM)\r\n- **Target**: ES2022\r\n- **Minification**: Enabled for production\r\n- **Source Maps**: Disabled for smaller bundle\r\n- **Type Declarations**: Full TypeScript support (DTS)\r\n- **Tree-shaking**: Enabled for optimal code splitting\r\n\r\n### Bundle Size Optimization\r\n| Compressed | Minified | Change |\r\n|-----------|----------|--------|\r\n| ~154 KB | N/A | Before optimization |\r\n| **~98 KB** | -36% | With minification |\r\n| **~85 KB** (prod) | -45% | With gzip |\r\n\r\n---\r\n\r\n## 🤝 Contributing\r\n\r\nContributions are welcome! Please feel free to submit a Pull Request.\r\n\r\n---\r\n\r\n## 📄 License\r\n\r\n**Dual License Model:**\r\n- **Basic Tier**: MIT © [CanvaStack](https://github.com/canvastack)\r\n- **Premium & Enterprise Tiers**: Commercial License (Proprietary)\r\n\r\n[📖 View Full License Terms](./LICENSE.md)\r\n\r\n**Commercial Licensing:**\r\nFor premium and enterprise features, a valid commercial license is required.\r\n- **Contact**: license@canvastack.id\r\n- **Website**: https://canvastack.id/pricing\r\n\r\n---\r\n\r\n## 🔗 Links\r\n\r\n- **NPM Package**: https://www.npmjs.com/package/@canvastack/canvable\r\n- **GitHub Repository**: https://github.com/canvastack/canvable\r\n- **Changelog**: [CHANGELOG.md](./CHANGELOG.md)\r\n\r\n\r\n---\r\n\r\n## 📋 Licensing & Tier System\r\n\r\n**CanvaStack Canvable** uses a **Dual Licensing Model**:\r\n\r\n| Tier | License | Cost | Best For |\r\n|------|---------|------|----------|\r\n| **Basic** | MIT (Open Source) | Free | Individual projects, Open-source |\r\n| **Premium** | Commercial License | Contact us | Small teams, SaaS applications |\r\n| **Enterprise** | Commercial License | Contact us | Large organizations, Mission-critical systems |\r\n\r\n**Activate Tiers Via Environment Variables:**\r\n```bash\r\n# Via .env.local\r\nNEXT_PUBLIC_CANVABLE_TIER=enterprise\r\n\r\n# Or specific feature flags\r\nNEXT_PUBLIC_CANVABLE_ENTERPRISE_ALL=true\r\nNEXT_PUBLIC_CANVABLE_PREMIUM_ALL=true\r\n```\r\n\r\n[📖 Full Licensing Details](./LICENSE.md) | [💼 Commercial Licensing](https://canvastack.id/pricing)\r\n\r\n\r\n---\r\n\r\n## Credits\r\n\r\nBuilt by the [CanvaStack Team](https://github.com/canvastack)\r\n\r\nPowered by:\r\n- [React](https://react.dev/)\r\n- [TypeScript](https://www.typescriptlang.org/)\r\n- [Tailwind CSS](https://tailwindcss.com/)\r\n- [Lucide Icons](https://lucide.dev/)\r\n- [jsPDF](https://github.com/parallax/jsPDF) - PDF generation\r\n- [jsPDF-AutoTable](https://github.com/simonbengtsson/jsPDF-AutoTable) - Table formatting for PDFs\r\n","readmeFilename":"README.md"}