{"_id":"@bomjan133/react-crud-ui","_rev":"12-c8c739c32e0351e94b19a1667086e002","name":"@bomjan133/react-crud-ui","dist-tags":{"latest":"1.2.16"},"versions":{"1.2.5":{"name":"@bomjan133/react-crud-ui","version":"1.2.5","keywords":["react","crud","ui-components","zustand","react-hook-form","tailwindcss","shadcn"],"author":{"name":"Sujan Bomjan"},"license":"MIT","_id":"@bomjan133/react-crud-ui@1.2.5","maintainers":[{"name":"bomjan133","email":"bomjan133@gmail.com"}],"homepage":"https://gitlab.com/bomjan133/react-crud#readme","bugs":{"url":"https://gitlab.com/bomjan133/react-crud/issues"},"bin":{"react-crud-ui":"bin/cli.js"},"dist":{"shasum":"a648cdc28f1db1edf67c6612d1d9b09841c0ea08","tarball":"https://registry.npmjs.org/@bomjan133/react-crud-ui/-/react-crud-ui-1.2.5.tgz","fileCount":30,"integrity":"sha512-HIQEBeaLET/5iSmZiROFJLSC0rhqqtDLMrlDniuGz5dDKoexGBNQi48W/MwPsCTOJMWXY1d0vI4VYXLTMcNFpQ==","signatures":[{"sig":"MEUCIQCAL5HcR1fY3Y152GmEskRLwHOIfQdX6oNFt3P5JfHB5QIgGgrK6qKM00asJLlKFyyjiPsJCfryJ8WzjUnhjaI+CAM=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":20988825},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./styles":"./dist/style.css","./styles.css":"./dist/style.css"},"gitHead":"0c6232fde7010cf9c93307c386f44020f2b73576","scripts":{"dev":"vite","lint":"eslint . --ext js,jsx --report-unused-disable-directives --max-warnings 0","build":"vite build","watch":"vite build --watch","preview":"vite preview","prepublishOnly":"npm run build"},"_npmUser":{"name":"bomjan133","email":"bomjan133@gmail.com"},"repository":{"url":"git+https://gitlab.com/bomjan133/react-crud.git","type":"git"},"_npmVersion":"10.9.2","description":"A comprehensive React CRUD and UI component library with Zustand store integration","directories":{},"sideEffects":["**/*.css"],"_nodeVersion":"22.17.1","dependencies":{"zod":"^3.22.4","clsx":"^2.1.0","axios":"^1.6.8","katex":"^0.16.27","epubjs":"^0.3.93","date-fns":"^4.1.0","suneditor":"^2.47.8","html2canvas":"^1.4.1","lucide-react":"^0.460.0","react-pageflip":"^2.0.3","tailwind-merge":"^2.2.1","react-hook-form":"^7.51.0","suneditor-react":"^3.6.1","react-day-picker":"^9.13.0","@hookform/resolvers":"^3.3.4","@radix-ui/react-slot":"^1.1.0","@radix-ui/react-tabs":"^1.1.0","@tailwindcss/postcss":"^4.1.18","@radix-ui/react-label":"^2.1.0","@radix-ui/react-avatar":"^1.1.0","@radix-ui/react-dialog":"^1.1.0","@radix-ui/react-select":"^2.1.0","@radix-ui/react-switch":"^1.1.0","@radix-ui/react-popover":"^1.1.0","@radix-ui/react-tooltip":"^1.1.0","@radix-ui/react-checkbox":"^1.1.0","class-variance-authority":"^0.7.0","@radix-ui/react-separator":"^1.1.0","@radix-ui/react-collapsible":"^1.1.12","@radix-ui/react-scroll-area":"^1.1.0","@radix-ui/react-alert-dialog":"^1.1.15","@radix-ui/react-dropdown-menu":"^2.1.0"},"_hasShrinkwrap":false,"devDependencies":{"glob":"^10.3.10","vite":"^5.1.0","eslint":"^8.56.0","postcss":"^8.4.35","typescript":"^5.3.3","@types/node":"^20.11.0","tailwindcss":"^4.0.0","@types/react":"^18.2.56","autoprefixer":"^10.4.18","vite-plugin-dts":"^3.7.3","@types/react-dom":"^18.2.19","eslint-plugin-react":"^7.33.2","@vitejs/plugin-react":"^4.2.1","eslint-plugin-react-hooks":"^4.6.0","eslint-plugin-react-refresh":"^0.4.5"},"peerDependencies":{"react":">=18.0.0","zustand":">=4.0.0","react-dom":">=18.0.0","react-router-dom":">=6.0.0"},"_npmOperationalInternal":{"tmp":"tmp/react-crud-ui_1.2.5_1784002979693_0.3550835558219758","host":"s3://npm-registry-packages-npm-production"}},"1.2.6":{"name":"@bomjan133/react-crud-ui","version":"1.2.6","keywords":["react","crud","ui-components","zustand","react-hook-form","tailwindcss","shadcn"],"author":{"name":"Sujan Bomjan"},"license":"MIT","_id":"@bomjan133/react-crud-ui@1.2.6","maintainers":[{"name":"bomjan133","email":"bomjan133@gmail.com"}],"homepage":"https://gitlab.com/bomjan133/react-crud#readme","bugs":{"url":"https://gitlab.com/bomjan133/react-crud/issues"},"bin":{"react-crud-ui":"bin/cli.js"},"dist":{"shasum":"378a06dc42e0ace8a549f354e8d17a4104cacc02","tarball":"https://registry.npmjs.org/@bomjan133/react-crud-ui/-/react-crud-ui-1.2.6.tgz","fileCount":30,"integrity":"sha512-zaQoqI+wB2SGkmEMbMfYJDm0e3p0PtHr3I7guCheJKF5yMVP9U0md1oWArefh/YRW8+tVyMhQuo9KIeygOESuA==","signatures":[{"sig":"MEUCIQD+7kuCyg11LpfgEy7JAJ6q2v229CZT0Pf8ohBTSj8k7AIgdOvZj9zwZZVL14h8pbZoK/cZUhmgiBm1f8IqwFxLq9g=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":20983994},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./styles":"./dist/style.css","./styles.css":"./dist/style.css"},"gitHead":"d55b9118f0302b88dc52434b8d8ce06bccf4ca4a","scripts":{"dev":"vite","lint":"eslint . --ext js,jsx --report-unused-disable-directives --max-warnings 0","build":"vite build","watch":"vite build --watch","preview":"vite preview","prepublishOnly":"npm run build"},"_npmUser":{"name":"bomjan133","email":"bomjan133@gmail.com"},"repository":{"url":"git+https://gitlab.com/bomjan133/react-crud.git","type":"git"},"_npmVersion":"10.9.2","description":"A comprehensive React CRUD and UI component library with Zustand store integration","directories":{},"sideEffects":["**/*.css"],"_nodeVersion":"22.17.1","dependencies":{"zod":"^3.22.4","clsx":"^2.1.0","axios":"^1.6.8","katex":"^0.16.27","epubjs":"^0.3.93","date-fns":"^4.1.0","suneditor":"^2.47.8","html2canvas":"^1.4.1","lucide-react":"^0.460.0","react-pageflip":"^2.0.3","tailwind-merge":"^2.2.1","react-hook-form":"^7.51.0","suneditor-react":"^3.6.1","react-day-picker":"^9.13.0","@hookform/resolvers":"^3.3.4","@radix-ui/react-slot":"^1.1.0","@radix-ui/react-tabs":"^1.1.0","@tailwindcss/postcss":"^4.1.18","@radix-ui/react-label":"^2.1.0","@radix-ui/react-avatar":"^1.1.0","@radix-ui/react-dialog":"^1.1.0","@radix-ui/react-select":"^2.1.0","@radix-ui/react-switch":"^1.1.0","@radix-ui/react-popover":"^1.1.0","@radix-ui/react-tooltip":"^1.1.0","@radix-ui/react-checkbox":"^1.1.0","class-variance-authority":"^0.7.0","@radix-ui/react-separator":"^1.1.0","@radix-ui/react-collapsible":"^1.1.12","@radix-ui/react-scroll-area":"^1.1.0","@radix-ui/react-alert-dialog":"^1.1.15","@radix-ui/react-dropdown-menu":"^2.1.0"},"_hasShrinkwrap":false,"devDependencies":{"glob":"^10.3.10","vite":"^5.1.0","eslint":"^8.56.0","postcss":"^8.4.35","typescript":"^5.3.3","@types/node":"^20.11.0","tailwindcss":"^4.0.0","@types/react":"^18.2.56","autoprefixer":"^10.4.18","vite-plugin-dts":"^3.7.3","@types/react-dom":"^18.2.19","eslint-plugin-react":"^7.33.2","@vitejs/plugin-react":"^4.2.1","eslint-plugin-react-hooks":"^4.6.0","eslint-plugin-react-refresh":"^0.4.5"},"peerDependencies":{"react":">=18.0.0","zustand":">=4.0.0","react-dom":">=18.0.0","react-router-dom":">=6.0.0"},"_npmOperationalInternal":{"tmp":"tmp/react-crud-ui_1.2.6_1784003839037_0.19230826131037726","host":"s3://npm-registry-packages-npm-production"}},"1.2.7":{"name":"@bomjan133/react-crud-ui","version":"1.2.7","keywords":["react","crud","ui-components","zustand","react-hook-form","tailwindcss","shadcn"],"author":{"name":"Sujan Bomjan"},"license":"MIT","_id":"@bomjan133/react-crud-ui@1.2.7","maintainers":[{"name":"bomjan133","email":"bomjan133@gmail.com"}],"homepage":"https://gitlab.com/bomjan133/react-crud#readme","bugs":{"url":"https://gitlab.com/bomjan133/react-crud/issues"},"bin":{"react-crud-ui":"bin/cli.js"},"dist":{"shasum":"47056f85c6df44bbe94c0942b00cb809047d5844","tarball":"https://registry.npmjs.org/@bomjan133/react-crud-ui/-/react-crud-ui-1.2.7.tgz","fileCount":95,"integrity":"sha512-ShYbEDKv3aa9yTIpEUycuPifuFOv6KoCHbGd+Q8iD60mtDy6QA48IenUOsVZQdC0l8n/GePYOnl1lLHYV6d9cw==","signatures":[{"sig":"MEUCIQCJTbv374BBNSahViY4FweBr3pG9ZexjtwUvXxGYlfR8QIgOSqU/kS5M989Kij9yqn7+/mQaYVYicDvxOI+Q7vW3Qo=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":21208370},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./styles":"./dist/style.css","./styles.css":"./dist/style.css"},"gitHead":"d339b81ccbb44c83181b2324b20e55812e1c90cc","scripts":{"dev":"vite","lint":"eslint . --ext js,jsx --report-unused-disable-directives --max-warnings 0","build":"vite build","watch":"vite build --watch","preview":"vite preview","prepublishOnly":"npm run build"},"_npmUser":{"name":"bomjan133","email":"bomjan133@gmail.com"},"repository":{"url":"git+https://gitlab.com/bomjan133/react-crud.git","type":"git"},"_npmVersion":"10.9.2","description":"A comprehensive React CRUD and UI component library with Zustand store integration","directories":{},"sideEffects":["**/*.css"],"_nodeVersion":"22.17.1","dependencies":{"zod":"^3.22.4","clsx":"^2.1.0","axios":"^1.6.8","katex":"^0.16.27","epubjs":"^0.3.93","date-fns":"^4.1.0","suneditor":"^2.47.8","html2canvas":"^1.4.1","lucide-react":"^0.460.0","react-pageflip":"^2.0.3","tailwind-merge":"^2.2.1","react-hook-form":"^7.51.0","suneditor-react":"^3.6.1","react-day-picker":"^9.13.0","@hookform/resolvers":"^3.3.4","@radix-ui/react-slot":"^1.1.0","@radix-ui/react-tabs":"^1.1.0","@tailwindcss/postcss":"^4.1.18","@radix-ui/react-label":"^2.1.0","@radix-ui/react-avatar":"^1.1.0","@radix-ui/react-dialog":"^1.1.0","@radix-ui/react-select":"^2.1.0","@radix-ui/react-switch":"^1.1.0","@radix-ui/react-popover":"^1.1.0","@radix-ui/react-tooltip":"^1.1.0","@radix-ui/react-checkbox":"^1.1.0","class-variance-authority":"^0.7.0","@radix-ui/react-separator":"^1.1.0","@radix-ui/react-collapsible":"^1.1.12","@radix-ui/react-scroll-area":"^1.1.0","@radix-ui/react-alert-dialog":"^1.1.15","@radix-ui/react-dropdown-menu":"^2.1.0"},"_hasShrinkwrap":false,"devDependencies":{"glob":"^10.3.10","vite":"^5.1.0","eslint":"^8.56.0","postcss":"^8.4.35","typescript":"^5.3.3","@types/node":"^20.11.0","tailwindcss":"^4.0.0","@types/react":"^18.2.56","autoprefixer":"^10.4.18","vite-plugin-dts":"^3.7.3","@types/react-dom":"^18.2.19","eslint-plugin-react":"^7.33.2","@vitejs/plugin-react":"^4.2.1","eslint-plugin-react-hooks":"^4.6.0","eslint-plugin-react-refresh":"^0.4.5"},"peerDependencies":{"react":">=18.0.0","zustand":">=4.0.0","react-dom":">=18.0.0","react-router-dom":">=6.0.0"},"_npmOperationalInternal":{"tmp":"tmp/react-crud-ui_1.2.7_1784193290641_0.3345111338190232","host":"s3://npm-registry-packages-npm-production"}},"1.2.8":{"name":"@bomjan133/react-crud-ui","version":"1.2.8","keywords":["react","crud","ui-components","zustand","react-hook-form","tailwindcss","shadcn"],"author":{"name":"Sujan Bomjan"},"license":"MIT","_id":"@bomjan133/react-crud-ui@1.2.8","maintainers":[{"name":"bomjan133","email":"bomjan133@gmail.com"}],"homepage":"https://gitlab.com/bomjan133/react-crud#readme","bugs":{"url":"https://gitlab.com/bomjan133/react-crud/issues"},"bin":{"react-crud-ui":"bin/cli.js"},"dist":{"shasum":"133e6ea1c0ad7e24e84d826a40b7ebeb9141c51a","tarball":"https://registry.npmjs.org/@bomjan133/react-crud-ui/-/react-crud-ui-1.2.8.tgz","fileCount":95,"integrity":"sha512-d1JjWqGkgw0RN76iDGXFOBN85bqJr34RlxsoStJG3x2LsUPJiOb9YgO2LzPVtwr0V71ugMxVsGtYD1ep1gpsQQ==","signatures":[{"sig":"MEQCIA6wFC7zk7aML+McK3P0reu5p/vz9SUOauRa0ZEypS+TAiBz9MOQirWTwGdRYq4mXbsGTuJvPzgCP63WoYH0bs88Ag==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":21209809},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./styles":"./dist/style.css","./styles.css":"./dist/style.css"},"gitHead":"dbb46e7215dbbf105543b09c607fa2c03bf1c25a","scripts":{"dev":"vite","lint":"eslint . --ext js,jsx --report-unused-disable-directives --max-warnings 0","build":"vite build","watch":"vite build --watch","preview":"vite preview","prepublishOnly":"npm run build"},"_npmUser":{"name":"bomjan133","email":"bomjan133@gmail.com"},"repository":{"url":"git+https://gitlab.com/bomjan133/react-crud.git","type":"git"},"_npmVersion":"10.9.2","description":"A comprehensive React CRUD and UI component library with Zustand store integration","directories":{},"sideEffects":["**/*.css"],"_nodeVersion":"22.17.1","dependencies":{"zod":"^3.22.4","clsx":"^2.1.0","axios":"^1.6.8","katex":"^0.16.27","epubjs":"^0.3.93","date-fns":"^4.1.0","suneditor":"^2.47.8","html2canvas":"^1.4.1","lucide-react":"^0.460.0","react-pageflip":"^2.0.3","tailwind-merge":"^2.2.1","react-hook-form":"^7.51.0","suneditor-react":"^3.6.1","react-day-picker":"^9.13.0","@hookform/resolvers":"^3.3.4","@radix-ui/react-slot":"^1.1.0","@radix-ui/react-tabs":"^1.1.0","@tailwindcss/postcss":"^4.1.18","@radix-ui/react-label":"^2.1.0","@radix-ui/react-avatar":"^1.1.0","@radix-ui/react-dialog":"^1.1.0","@radix-ui/react-select":"^2.1.0","@radix-ui/react-switch":"^1.1.0","@radix-ui/react-popover":"^1.1.0","@radix-ui/react-tooltip":"^1.1.0","@radix-ui/react-checkbox":"^1.1.0","class-variance-authority":"^0.7.0","@radix-ui/react-separator":"^1.1.0","@radix-ui/react-collapsible":"^1.1.12","@radix-ui/react-scroll-area":"^1.1.0","@radix-ui/react-alert-dialog":"^1.1.15","@radix-ui/react-dropdown-menu":"^2.1.0"},"_hasShrinkwrap":false,"devDependencies":{"glob":"^10.3.10","vite":"^5.1.0","eslint":"^8.56.0","postcss":"^8.4.35","typescript":"^5.3.3","@types/node":"^20.11.0","tailwindcss":"^4.0.0","@types/react":"^18.2.56","autoprefixer":"^10.4.18","vite-plugin-dts":"^3.7.3","@types/react-dom":"^18.2.19","eslint-plugin-react":"^7.33.2","@vitejs/plugin-react":"^4.2.1","eslint-plugin-react-hooks":"^4.6.0","eslint-plugin-react-refresh":"^0.4.5"},"peerDependencies":{"react":">=18.0.0","zustand":">=4.0.0","react-dom":">=18.0.0","react-router-dom":">=6.0.0"},"_npmOperationalInternal":{"tmp":"tmp/react-crud-ui_1.2.8_1786518098275_0.6040152162146655","host":"s3://npm-registry-packages-npm-production"}},"1.2.9":{"name":"@bomjan133/react-crud-ui","version":"1.2.9","keywords":["react","crud","ui-components","zustand","react-hook-form","tailwindcss","shadcn"],"author":{"name":"Sujan Bomjan"},"license":"MIT","_id":"@bomjan133/react-crud-ui@1.2.9","maintainers":[{"name":"bomjan133","email":"bomjan133@gmail.com"}],"homepage":"https://gitlab.com/bomjan133/react-crud#readme","bugs":{"url":"https://gitlab.com/bomjan133/react-crud/issues"},"bin":{"react-crud-ui":"bin/cli.js"},"dist":{"shasum":"58b456c5fee080e8e2cc295e5f984fab22effca1","tarball":"https://registry.npmjs.org/@bomjan133/react-crud-ui/-/react-crud-ui-1.2.9.tgz","fileCount":95,"integrity":"sha512-EVCWisl6KbiXJppq30IcW17TX48eZRoVBa4n94zkFrmpK0TwVKLjZGMviibfdFV6+mscBDwZr1QskjXYIzWQlg==","signatures":[{"sig":"MEYCIQDpcWEEJEQLa5Vh90JW1eKYZWznximJt0K1xPj0A2zewAIhAJrUSpFKoIeSdDCVS14kJImffWICIFgpauiQELGKg3JB","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":21208694},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./styles":"./dist/style.css","./styles.css":"./dist/style.css"},"gitHead":"d04200166cb6a9330fbe6782edaef1c8a7ddd877","scripts":{"dev":"vite","lint":"eslint . --ext js,jsx --report-unused-disable-directives --max-warnings 0","build":"vite build","watch":"vite build --watch","preview":"vite preview","prepublishOnly":"npm run build"},"_npmUser":{"name":"bomjan133","email":"bomjan133@gmail.com"},"repository":{"url":"git+https://gitlab.com/bomjan133/react-crud.git","type":"git"},"_npmVersion":"10.9.2","description":"A comprehensive React CRUD and UI component library with Zustand store integration","directories":{},"sideEffects":["**/*.css"],"_nodeVersion":"22.17.1","dependencies":{"zod":"^3.22.4","clsx":"^2.1.0","axios":"^1.6.8","katex":"^0.16.27","epubjs":"^0.3.93","date-fns":"^4.1.0","suneditor":"^2.47.8","html2canvas":"^1.4.1","lucide-react":"^0.460.0","react-pageflip":"^2.0.3","tailwind-merge":"^2.2.1","react-hook-form":"^7.51.0","suneditor-react":"^3.6.1","react-day-picker":"^9.13.0","@hookform/resolvers":"^3.3.4","@radix-ui/react-slot":"^1.1.0","@radix-ui/react-tabs":"^1.1.0","@tailwindcss/postcss":"^4.1.18","@radix-ui/react-label":"^2.1.0","@radix-ui/react-avatar":"^1.1.0","@radix-ui/react-dialog":"^1.1.0","@radix-ui/react-select":"^2.1.0","@radix-ui/react-switch":"^1.1.0","@radix-ui/react-popover":"^1.1.0","@radix-ui/react-tooltip":"^1.1.0","@radix-ui/react-checkbox":"^1.1.0","class-variance-authority":"^0.7.0","@radix-ui/react-separator":"^1.1.0","@radix-ui/react-collapsible":"^1.1.12","@radix-ui/react-scroll-area":"^1.1.0","@radix-ui/react-alert-dialog":"^1.1.15","@radix-ui/react-dropdown-menu":"^2.1.0"},"_hasShrinkwrap":false,"devDependencies":{"glob":"^10.3.10","vite":"^5.1.0","eslint":"^8.56.0","postcss":"^8.4.35","typescript":"^5.3.3","@types/node":"^20.11.0","tailwindcss":"^4.0.0","@types/react":"^18.2.56","autoprefixer":"^10.4.18","vite-plugin-dts":"^3.7.3","@types/react-dom":"^18.2.19","eslint-plugin-react":"^7.33.2","@vitejs/plugin-react":"^4.2.1","eslint-plugin-react-hooks":"^4.6.0","eslint-plugin-react-refresh":"^0.4.5"},"peerDependencies":{"react":">=18.0.0","zustand":">=4.0.0","react-dom":">=18.0.0","react-router-dom":">=6.0.0"},"_npmOperationalInternal":{"tmp":"tmp/react-crud-ui_1.2.9_1786597334078_0.7852894321096113","host":"s3://npm-registry-packages-npm-production"}},"1.2.10":{"name":"@bomjan133/react-crud-ui","version":"1.2.10","keywords":["react","crud","ui-components","zustand","react-hook-form","tailwindcss","shadcn"],"author":{"name":"Sujan Bomjan"},"license":"MIT","_id":"@bomjan133/react-crud-ui@1.2.10","maintainers":[{"name":"bomjan133","email":"bomjan133@gmail.com"}],"homepage":"https://gitlab.com/bomjan133/react-crud#readme","bugs":{"url":"https://gitlab.com/bomjan133/react-crud/issues"},"bin":{"react-crud-ui":"bin/cli.js"},"dist":{"shasum":"e86c97544cdaffae6807b633aaa1813356ae12f8","tarball":"https://registry.npmjs.org/@bomjan133/react-crud-ui/-/react-crud-ui-1.2.10.tgz","fileCount":95,"integrity":"sha512-e7H2Y3Ogo8QW5e4xWkICc6/bJ2nkDfcWU3nstgfR/jznjDHSikrw0ET5LnK0tu6parRnsdoPrsQL3c8M8OQjlg==","signatures":[{"sig":"MEUCIQDHL4L8BDTKUuIf9ge7zST2HLC6xKcSnMaIDSOoK999nAIgehtVN8JcaE7iSpsFe9V+Gl2Qngf3Y/3AyGVoA0x6Xjw=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":21260123},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./styles":"./dist/style.css","./styles.css":"./dist/style.css"},"gitHead":"86956a5f8b1cac4f8d69a82e85ab2e55ec1f8771","scripts":{"dev":"vite","lint":"eslint . --ext js,jsx --report-unused-disable-directives --max-warnings 0","build":"vite build","watch":"vite build --watch","preview":"vite preview","prepublishOnly":"npm run build"},"_npmUser":{"name":"bomjan133","email":"bomjan133@gmail.com"},"repository":{"url":"git+https://gitlab.com/bomjan133/react-crud.git","type":"git"},"_npmVersion":"10.9.2","description":"A comprehensive React CRUD and UI component library with Zustand store integration","directories":{},"sideEffects":["**/*.css"],"_nodeVersion":"22.17.1","dependencies":{"zod":"^3.22.4","clsx":"^2.1.0","axios":"^1.6.8","katex":"^0.16.27","epubjs":"^0.3.93","date-fns":"^4.1.0","suneditor":"^2.47.8","html2canvas":"^1.4.1","lucide-react":"^0.460.0","react-pageflip":"^2.0.3","tailwind-merge":"^2.2.1","react-hook-form":"^7.51.0","suneditor-react":"^3.6.1","react-day-picker":"^9.13.0","@hookform/resolvers":"^3.3.4","@radix-ui/react-slot":"^1.1.0","@radix-ui/react-tabs":"^1.1.0","@tailwindcss/postcss":"^4.1.18","@radix-ui/react-label":"^2.1.0","@radix-ui/react-avatar":"^1.1.0","@radix-ui/react-dialog":"^1.1.0","@radix-ui/react-select":"^2.1.0","@radix-ui/react-switch":"^1.1.0","@radix-ui/react-popover":"^1.1.0","@radix-ui/react-tooltip":"^1.1.0","@radix-ui/react-checkbox":"^1.1.0","class-variance-authority":"^0.7.0","@radix-ui/react-separator":"^1.1.0","@radix-ui/react-collapsible":"^1.1.12","@radix-ui/react-scroll-area":"^1.1.0","@radix-ui/react-alert-dialog":"^1.1.15","@radix-ui/react-dropdown-menu":"^2.1.0"},"_hasShrinkwrap":false,"devDependencies":{"glob":"^10.3.10","vite":"^5.1.0","eslint":"^8.56.0","postcss":"^8.4.35","typescript":"^5.3.3","@types/node":"^20.11.0","tailwindcss":"^4.0.0","@types/react":"^18.2.56","autoprefixer":"^10.4.18","vite-plugin-dts":"^3.7.3","@types/react-dom":"^18.2.19","eslint-plugin-react":"^7.33.2","@vitejs/plugin-react":"^4.2.1","eslint-plugin-react-hooks":"^4.6.0","eslint-plugin-react-refresh":"^0.4.5"},"peerDependencies":{"react":">=18.0.0","zustand":">=4.0.0","react-dom":">=18.0.0","react-router-dom":">=6.0.0"},"_npmOperationalInternal":{"tmp":"tmp/react-crud-ui_1.2.10_1787114841920_0.2062932633133141","host":"s3://npm-registry-packages-npm-production"}},"1.2.11":{"name":"@bomjan133/react-crud-ui","version":"1.2.11","keywords":["react","crud","ui-components","zustand","react-hook-form","tailwindcss","shadcn"],"author":{"name":"Sujan Bomjan"},"license":"MIT","_id":"@bomjan133/react-crud-ui@1.2.11","maintainers":[{"name":"bomjan133","email":"bomjan133@gmail.com"}],"homepage":"https://gitlab.com/bomjan133/react-crud#readme","bugs":{"url":"https://gitlab.com/bomjan133/react-crud/issues"},"bin":{"react-crud-ui":"bin/cli.js"},"dist":{"shasum":"85d7a806b7581a500d3a056afb182f4436ec1f57","tarball":"https://registry.npmjs.org/@bomjan133/react-crud-ui/-/react-crud-ui-1.2.11.tgz","fileCount":95,"integrity":"sha512-DA8jh6GBMFpRRAmrFSVlzu104WCEngPX0L3uPuOBU4eFwke7IESbpAqT3HwyeIUwHMW3PeEdq0fMyb3NgmC3Yg==","signatures":[{"sig":"MEQCIEQw5oCzUhs1Msjle0phA6hgxH4bkkh8AclHc31kkI3nAiBw525paPnMtlIih8ok5lisQjGPZ8gLPzPLsQ/nUr/qHA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":21279957},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./styles":"./dist/style.css","./styles.css":"./dist/style.css"},"gitHead":"28724a8470b0f0cc000d94f2e37efc87ff053a03","scripts":{"dev":"vite","lint":"eslint . --ext js,jsx --report-unused-disable-directives --max-warnings 0","build":"vite build","watch":"vite build --watch","preview":"vite preview","prepublishOnly":"npm run build"},"_npmUser":{"name":"bomjan133","email":"bomjan133@gmail.com"},"repository":{"url":"git+https://gitlab.com/bomjan133/react-crud.git","type":"git"},"_npmVersion":"10.9.2","description":"A comprehensive React CRUD and UI component library with Zustand store integration","directories":{},"sideEffects":["**/*.css"],"_nodeVersion":"22.17.1","dependencies":{"zod":"^3.22.4","clsx":"^2.1.0","axios":"^1.6.8","katex":"^0.16.27","epubjs":"^0.3.93","date-fns":"^4.1.0","suneditor":"^2.47.8","html2canvas":"^1.4.1","lucide-react":"^0.460.0","react-pageflip":"^2.0.3","tailwind-merge":"^2.2.1","react-hook-form":"^7.51.0","suneditor-react":"^3.6.1","react-day-picker":"^9.13.0","@hookform/resolvers":"^3.3.4","@radix-ui/react-slot":"^1.1.0","@radix-ui/react-tabs":"^1.1.0","@tailwindcss/postcss":"^4.1.18","@radix-ui/react-label":"^2.1.0","@radix-ui/react-avatar":"^1.1.0","@radix-ui/react-dialog":"^1.1.0","@radix-ui/react-select":"^2.1.0","@radix-ui/react-switch":"^1.1.0","@radix-ui/react-popover":"^1.1.0","@radix-ui/react-tooltip":"^1.1.0","@radix-ui/react-checkbox":"^1.1.0","class-variance-authority":"^0.7.0","@radix-ui/react-separator":"^1.1.0","@radix-ui/react-collapsible":"^1.1.12","@radix-ui/react-scroll-area":"^1.1.0","@radix-ui/react-alert-dialog":"^1.1.15","@radix-ui/react-dropdown-menu":"^2.1.0"},"_hasShrinkwrap":false,"devDependencies":{"glob":"^10.3.10","vite":"^5.1.0","eslint":"^8.56.0","postcss":"^8.4.35","typescript":"^5.3.3","@types/node":"^20.11.0","tailwindcss":"^4.0.0","@types/react":"^18.2.56","autoprefixer":"^10.4.18","vite-plugin-dts":"^3.7.3","@types/react-dom":"^18.2.19","eslint-plugin-react":"^7.33.2","@vitejs/plugin-react":"^4.2.1","eslint-plugin-react-hooks":"^4.6.0","eslint-plugin-react-refresh":"^0.4.5"},"peerDependencies":{"react":">=18.0.0","zustand":">=4.0.0","react-dom":">=18.0.0","react-router-dom":">=6.0.0"},"_npmOperationalInternal":{"tmp":"tmp/react-crud-ui_1.2.11_1787134238592_0.910307305241431","host":"s3://npm-registry-packages-npm-production"}},"1.2.12":{"name":"@bomjan133/react-crud-ui","version":"1.2.12","keywords":["react","crud","ui-components","zustand","react-hook-form","tailwindcss","shadcn"],"author":{"name":"Sujan Bomjan"},"license":"MIT","_id":"@bomjan133/react-crud-ui@1.2.12","maintainers":[{"name":"bomjan133","email":"bomjan133@gmail.com"}],"homepage":"https://gitlab.com/bomjan133/react-crud#readme","bugs":{"url":"https://gitlab.com/bomjan133/react-crud/issues"},"bin":{"react-crud-ui":"bin/cli.js"},"dist":{"shasum":"edae66289a00123ba472be2c3ae7cd1f473d46cc","tarball":"https://registry.npmjs.org/@bomjan133/react-crud-ui/-/react-crud-ui-1.2.12.tgz","fileCount":95,"integrity":"sha512-aTrnU2olopH1Rco/rrroyK7HnTcJwGduz16wlqW7hbtwNwLx9nhqpr4VElJnoaA66cEZMYQ6o6UdZgs40g59LA==","signatures":[{"sig":"MEUCIQCfEDCNxBGlA1qrXTiQaDlcwpOvi95OVG8uBqh2n9uy8AIgYLG6wHB7Y1SOHfo9mgBg15IsJZ0OBV7PkU2JkwdMLAU=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":21282652},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./styles":"./dist/style.css","./styles.css":"./dist/style.css"},"gitHead":"73777e9e4b6f79f778bde68f9259b876ef589741","scripts":{"dev":"vite","lint":"eslint . --ext js,jsx --report-unused-disable-directives --max-warnings 0","build":"vite build","watch":"vite build --watch","preview":"vite preview","prepublishOnly":"npm run build"},"_npmUser":{"name":"bomjan133","email":"bomjan133@gmail.com"},"repository":{"url":"git+https://gitlab.com/bomjan133/react-crud.git","type":"git"},"_npmVersion":"10.9.2","description":"A comprehensive React CRUD and UI component library with Zustand store integration","directories":{},"sideEffects":["**/*.css"],"_nodeVersion":"22.17.1","dependencies":{"zod":"^3.22.4","clsx":"^2.1.0","axios":"^1.6.8","katex":"^0.16.27","epubjs":"^0.3.93","date-fns":"^4.1.0","suneditor":"^2.47.8","html2canvas":"^1.4.1","lucide-react":"^0.460.0","react-pageflip":"^2.0.3","tailwind-merge":"^2.2.1","react-hook-form":"^7.51.0","suneditor-react":"^3.6.1","react-day-picker":"^9.13.0","@hookform/resolvers":"^3.3.4","@radix-ui/react-slot":"^1.1.0","@radix-ui/react-tabs":"^1.1.0","@tailwindcss/postcss":"^4.1.18","@radix-ui/react-label":"^2.1.0","@radix-ui/react-avatar":"^1.1.0","@radix-ui/react-dialog":"^1.1.0","@radix-ui/react-select":"^2.1.0","@radix-ui/react-switch":"^1.1.0","@radix-ui/react-popover":"^1.1.0","@radix-ui/react-tooltip":"^1.1.0","@radix-ui/react-checkbox":"^1.1.0","class-variance-authority":"^0.7.0","@radix-ui/react-separator":"^1.1.0","@radix-ui/react-collapsible":"^1.1.12","@radix-ui/react-scroll-area":"^1.1.0","@radix-ui/react-alert-dialog":"^1.1.15","@radix-ui/react-dropdown-menu":"^2.1.0"},"_hasShrinkwrap":false,"devDependencies":{"glob":"^10.3.10","vite":"^5.1.0","eslint":"^8.56.0","postcss":"^8.4.35","typescript":"^5.3.3","@types/node":"^20.11.0","tailwindcss":"^4.0.0","@types/react":"^18.2.56","autoprefixer":"^10.4.18","vite-plugin-dts":"^3.7.3","@types/react-dom":"^18.2.19","eslint-plugin-react":"^7.33.2","@vitejs/plugin-react":"^4.2.1","eslint-plugin-react-hooks":"^4.6.0","eslint-plugin-react-refresh":"^0.4.5"},"peerDependencies":{"react":">=18.0.0","zustand":">=4.0.0","react-dom":">=18.0.0","react-router-dom":">=6.0.0"},"_npmOperationalInternal":{"tmp":"tmp/react-crud-ui_1.2.12_1787199989505_0.3478436467965187","host":"s3://npm-registry-packages-npm-production"}},"1.2.13":{"name":"@bomjan133/react-crud-ui","version":"1.2.13","keywords":["react","crud","ui-components","zustand","react-hook-form","tailwindcss","shadcn"],"author":{"name":"Sujan Bomjan"},"license":"MIT","_id":"@bomjan133/react-crud-ui@1.2.13","maintainers":[{"name":"bomjan133","email":"bomjan133@gmail.com"}],"homepage":"https://gitlab.com/bomjan133/react-crud#readme","bugs":{"url":"https://gitlab.com/bomjan133/react-crud/issues"},"bin":{"react-crud-ui":"bin/cli.js"},"dist":{"shasum":"e0ec07335a701b450bb06f501c1ae5d5a0f8467b","tarball":"https://registry.npmjs.org/@bomjan133/react-crud-ui/-/react-crud-ui-1.2.13.tgz","fileCount":95,"integrity":"sha512-tsuB3C9mrc0fc4AQlsTbLNiEWjyDunw4oAYR76uA7zoN/1VRC9dP0B1w1UZ9yQPA04PZvT8r5Bjh8qFzWK+G4w==","signatures":[{"sig":"MEUCIHojNXYINR+3ajZSWtnp5mR64gsDCtv0AOvtRtEvvmSsAiEA75dLVEmLhbrLDpLWltxwMIF8L2j0c86KcSqkKZMMX0I=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":21285898},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./styles":"./dist/style.css","./styles.css":"./dist/style.css"},"gitHead":"ba85d6b21b662b215185188c38594dead3da43bc","scripts":{"dev":"vite","lint":"eslint . --ext js,jsx --report-unused-disable-directives --max-warnings 0","build":"vite build","watch":"vite build --watch","preview":"vite preview","prepublishOnly":"npm run build"},"_npmUser":{"name":"bomjan133","email":"bomjan133@gmail.com"},"repository":{"url":"git+https://gitlab.com/bomjan133/react-crud.git","type":"git"},"_npmVersion":"10.9.2","description":"A comprehensive React CRUD and UI component library with Zustand store integration","directories":{},"sideEffects":["**/*.css"],"_nodeVersion":"22.17.1","dependencies":{"zod":"^3.22.4","clsx":"^2.1.0","axios":"^1.6.8","katex":"^0.16.27","epubjs":"^0.3.93","date-fns":"^4.1.0","suneditor":"^2.47.8","html2canvas":"^1.4.1","lucide-react":"^0.460.0","react-pageflip":"^2.0.3","tailwind-merge":"^2.2.1","react-hook-form":"^7.51.0","suneditor-react":"^3.6.1","react-day-picker":"^9.13.0","@hookform/resolvers":"^3.3.4","@radix-ui/react-slot":"^1.1.0","@radix-ui/react-tabs":"^1.1.0","@tailwindcss/postcss":"^4.1.18","@radix-ui/react-label":"^2.1.0","@radix-ui/react-avatar":"^1.1.0","@radix-ui/react-dialog":"^1.1.0","@radix-ui/react-select":"^2.1.0","@radix-ui/react-switch":"^1.1.0","@radix-ui/react-popover":"^1.1.0","@radix-ui/react-tooltip":"^1.1.0","@radix-ui/react-checkbox":"^1.1.0","class-variance-authority":"^0.7.0","@radix-ui/react-separator":"^1.1.0","@radix-ui/react-collapsible":"^1.1.12","@radix-ui/react-scroll-area":"^1.1.0","@radix-ui/react-alert-dialog":"^1.1.15","@radix-ui/react-dropdown-menu":"^2.1.0"},"_hasShrinkwrap":false,"devDependencies":{"glob":"^10.3.10","vite":"^5.1.0","eslint":"^8.56.0","postcss":"^8.4.35","typescript":"^5.3.3","@types/node":"^20.11.0","tailwindcss":"^4.0.0","@types/react":"^18.2.56","autoprefixer":"^10.4.18","vite-plugin-dts":"^3.7.3","@types/react-dom":"^18.2.19","eslint-plugin-react":"^7.33.2","@vitejs/plugin-react":"^4.2.1","eslint-plugin-react-hooks":"^4.6.0","eslint-plugin-react-refresh":"^0.4.5"},"peerDependencies":{"react":">=18.0.0","zustand":">=4.0.0","react-dom":">=18.0.0","react-router-dom":">=6.0.0"},"_npmOperationalInternal":{"tmp":"tmp/react-crud-ui_1.2.13_1787201501927_0.7223944439732377","host":"s3://npm-registry-packages-npm-production"}},"1.2.14":{"name":"@bomjan133/react-crud-ui","version":"1.2.14","keywords":["react","crud","ui-components","zustand","react-hook-form","tailwindcss","shadcn"],"author":{"name":"Sujan Bomjan"},"license":"MIT","_id":"@bomjan133/react-crud-ui@1.2.14","maintainers":[{"name":"bomjan133","email":"bomjan133@gmail.com"}],"homepage":"https://gitlab.com/bomjan133/react-crud#readme","bugs":{"url":"https://gitlab.com/bomjan133/react-crud/issues"},"bin":{"react-crud-ui":"bin/cli.js"},"dist":{"shasum":"0357feb95f1439c9b9e3b00f902a1f781c90ccff","tarball":"https://registry.npmjs.org/@bomjan133/react-crud-ui/-/react-crud-ui-1.2.14.tgz","fileCount":95,"integrity":"sha512-R3ny6SBqxs+hZOvYXdaUisyktBBRF3lTu122J2L8RAvZCOm1eKje/Io72as+k78VJzT/Jnvuy8PuUv21FElyIw==","signatures":[{"sig":"MEUCIEEJPgc6bWfVGuxHxQGY9fymIKXo+TnUPA1c+9mEoDa7AiEA4IjA384nyYMILmxJ9cdM6alvMNnxsUMRwqsRhmY9Nrw=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":21279957},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./styles":"./dist/style.css","./styles.css":"./dist/style.css"},"gitHead":"72563a3ed914f7a5cee94b4fffa959af810c515f","scripts":{"dev":"vite","lint":"eslint . --ext js,jsx --report-unused-disable-directives --max-warnings 0","build":"vite build","watch":"vite build --watch","preview":"vite preview","prepublishOnly":"npm run build"},"_npmUser":{"name":"bomjan133","email":"bomjan133@gmail.com"},"repository":{"url":"git+https://gitlab.com/bomjan133/react-crud.git","type":"git"},"_npmVersion":"10.9.2","description":"A comprehensive React CRUD and UI component library with Zustand store integration","directories":{},"sideEffects":["**/*.css"],"_nodeVersion":"22.17.1","dependencies":{"zod":"^3.22.4","clsx":"^2.1.0","axios":"^1.6.8","katex":"^0.16.27","epubjs":"^0.3.93","date-fns":"^4.1.0","suneditor":"^2.47.8","html2canvas":"^1.4.1","lucide-react":"^0.460.0","react-pageflip":"^2.0.3","tailwind-merge":"^2.2.1","react-hook-form":"^7.51.0","suneditor-react":"^3.6.1","react-day-picker":"^9.13.0","@hookform/resolvers":"^3.3.4","@radix-ui/react-slot":"^1.1.0","@radix-ui/react-tabs":"^1.1.0","@tailwindcss/postcss":"^4.1.18","@radix-ui/react-label":"^2.1.0","@radix-ui/react-avatar":"^1.1.0","@radix-ui/react-dialog":"^1.1.0","@radix-ui/react-select":"^2.1.0","@radix-ui/react-switch":"^1.1.0","@radix-ui/react-popover":"^1.1.0","@radix-ui/react-tooltip":"^1.1.0","@radix-ui/react-checkbox":"^1.1.0","class-variance-authority":"^0.7.0","@radix-ui/react-separator":"^1.1.0","@radix-ui/react-collapsible":"^1.1.12","@radix-ui/react-scroll-area":"^1.1.0","@radix-ui/react-alert-dialog":"^1.1.15","@radix-ui/react-dropdown-menu":"^2.1.0"},"_hasShrinkwrap":false,"devDependencies":{"glob":"^10.3.10","vite":"^5.1.0","eslint":"^8.56.0","postcss":"^8.4.35","typescript":"^5.3.3","@types/node":"^20.11.0","tailwindcss":"^4.0.0","@types/react":"^18.2.56","autoprefixer":"^10.4.18","vite-plugin-dts":"^3.7.3","@types/react-dom":"^18.2.19","eslint-plugin-react":"^7.33.2","@vitejs/plugin-react":"^4.2.1","eslint-plugin-react-hooks":"^4.6.0","eslint-plugin-react-refresh":"^0.4.5"},"peerDependencies":{"react":">=18.0.0","zustand":">=4.0.0","react-dom":">=18.0.0","react-router-dom":">=6.0.0"},"_npmOperationalInternal":{"tmp":"tmp/react-crud-ui_1.2.14_1787201765771_0.34607910611739645","host":"s3://npm-registry-packages-npm-production"}},"1.2.15":{"name":"@bomjan133/react-crud-ui","version":"1.2.15","keywords":["react","crud","ui-components","zustand","react-hook-form","tailwindcss","shadcn"],"author":{"name":"Sujan Bomjan"},"license":"MIT","_id":"@bomjan133/react-crud-ui@1.2.15","maintainers":[{"name":"bomjan133","email":"bomjan133@gmail.com"}],"homepage":"https://gitlab.com/bomjan133/react-crud#readme","bugs":{"url":"https://gitlab.com/bomjan133/react-crud/issues"},"bin":{"react-crud-ui":"bin/cli.js"},"dist":{"shasum":"7c0265ce7100265241661d20d81080f6d60a6f8e","tarball":"https://registry.npmjs.org/@bomjan133/react-crud-ui/-/react-crud-ui-1.2.15.tgz","fileCount":95,"integrity":"sha512-VARo8x86o+Q6CbbM5oH4g8gtB5Lf4Nmyf3kILarHP3Ogoeh2/HaFITFHHAW6KWsZutsCTp80E1qOdgfLF0koUg==","signatures":[{"sig":"MEUCIQDyE075Ao5+ygXcgrDocXKw2stqPQBrhHSFCpJ4Idbi0gIgYP3K+/vK7detA1jh6Q9r4DrMwp31R8EHdPWAWYUKvok=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":21288350},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./styles":"./dist/style.css","./styles.css":"./dist/style.css"},"gitHead":"0276ce8849e6f639f897055570e0c501bcf77ba7","scripts":{"dev":"vite","lint":"eslint . --ext js,jsx --report-unused-disable-directives --max-warnings 0","build":"vite build","watch":"vite build --watch","preview":"vite preview","prepublishOnly":"npm run build"},"_npmUser":{"name":"bomjan133","email":"bomjan133@gmail.com"},"repository":{"url":"git+https://gitlab.com/bomjan133/react-crud.git","type":"git"},"_npmVersion":"10.9.2","description":"A comprehensive React CRUD and UI component library with Zustand store integration","directories":{},"sideEffects":["**/*.css"],"_nodeVersion":"22.17.1","dependencies":{"zod":"^3.22.4","clsx":"^2.1.0","axios":"^1.6.8","katex":"^0.16.27","epubjs":"^0.3.93","date-fns":"^4.1.0","suneditor":"^2.47.8","html2canvas":"^1.4.1","lucide-react":"^0.460.0","react-pageflip":"^2.0.3","tailwind-merge":"^2.2.1","react-hook-form":"^7.51.0","suneditor-react":"^3.6.1","react-day-picker":"^9.13.0","@hookform/resolvers":"^3.3.4","@radix-ui/react-slot":"^1.1.0","@radix-ui/react-tabs":"^1.1.0","@tailwindcss/postcss":"^4.1.18","@radix-ui/react-label":"^2.1.0","@radix-ui/react-avatar":"^1.1.0","@radix-ui/react-dialog":"^1.1.0","@radix-ui/react-select":"^2.1.0","@radix-ui/react-switch":"^1.1.0","@radix-ui/react-popover":"^1.1.0","@radix-ui/react-tooltip":"^1.1.0","@radix-ui/react-checkbox":"^1.1.0","class-variance-authority":"^0.7.0","@radix-ui/react-separator":"^1.1.0","@radix-ui/react-collapsible":"^1.1.12","@radix-ui/react-scroll-area":"^1.1.0","@radix-ui/react-alert-dialog":"^1.1.15","@radix-ui/react-dropdown-menu":"^2.1.0"},"_hasShrinkwrap":false,"devDependencies":{"glob":"^10.3.10","vite":"^5.1.0","eslint":"^8.56.0","postcss":"^8.4.35","typescript":"^5.3.3","@types/node":"^20.11.0","tailwindcss":"^4.0.0","@types/react":"^18.2.56","autoprefixer":"^10.4.18","vite-plugin-dts":"^3.7.3","@types/react-dom":"^18.2.19","eslint-plugin-react":"^7.33.2","@vitejs/plugin-react":"^4.2.1","eslint-plugin-react-hooks":"^4.6.0","eslint-plugin-react-refresh":"^0.4.5"},"peerDependencies":{"react":">=18.0.0","zustand":">=4.0.0","react-dom":">=18.0.0","react-router-dom":">=6.0.0"},"_npmOperationalInternal":{"tmp":"tmp/react-crud-ui_1.2.15_1788150491429_0.5815374643063826","host":"s3://npm-registry-packages-npm-production"}},"1.2.16":{"name":"@bomjan133/react-crud-ui","version":"1.2.16","description":"A comprehensive React CRUD and UI component library with Zustand store integration","type":"module","main":"./dist/index.cjs","module":"./dist/index.js","types":"./dist/index.d.ts","bin":{"react-crud-ui":"bin/cli.js"},"exports":{".":{"import":"./dist/index.js","require":"./dist/index.cjs","types":"./dist/index.d.ts"},"./styles":"./dist/style.css","./styles.css":"./dist/style.css"},"sideEffects":["**/*.css"],"scripts":{"dev":"vite","build":"vite build","lint":"eslint . --ext js,jsx --report-unused-disable-directives --max-warnings 0","preview":"vite preview","watch":"vite build --watch","prepublishOnly":"npm run build"},"peerDependencies":{"react":">=18.0.0","react-dom":">=18.0.0","react-router-dom":">=6.0.0","zustand":">=4.0.0"},"dependencies":{"@hookform/resolvers":"^3.3.4","@radix-ui/react-alert-dialog":"^1.1.15","@radix-ui/react-avatar":"^1.1.0","@radix-ui/react-checkbox":"^1.1.0","@radix-ui/react-collapsible":"^1.1.12","@radix-ui/react-dialog":"^1.1.0","@radix-ui/react-dropdown-menu":"^2.1.0","@radix-ui/react-label":"^2.1.0","@radix-ui/react-popover":"^1.1.0","@radix-ui/react-scroll-area":"^1.1.0","@radix-ui/react-select":"^2.1.0","@radix-ui/react-separator":"^1.1.0","@radix-ui/react-slot":"^1.1.0","@radix-ui/react-switch":"^1.1.0","@radix-ui/react-tabs":"^1.1.0","@radix-ui/react-tooltip":"^1.1.0","@tailwindcss/postcss":"^4.1.18","axios":"^1.6.8","class-variance-authority":"^0.7.0","clsx":"^2.1.0","date-fns":"^4.1.0","epubjs":"^0.3.93","html2canvas":"^1.4.1","katex":"^0.16.27","lucide-react":"^0.460.0","react-day-picker":"^9.13.0","react-hook-form":"^7.51.0","react-pageflip":"^2.0.3","suneditor":"^2.47.8","suneditor-react":"^3.6.1","tailwind-merge":"^2.2.1","zod":"^3.22.4"},"devDependencies":{"@types/node":"^20.11.0","@types/react":"^18.2.56","@types/react-dom":"^18.2.19","@vitejs/plugin-react":"^4.2.1","autoprefixer":"^10.4.18","eslint":"^8.56.0","eslint-plugin-react":"^7.33.2","eslint-plugin-react-hooks":"^4.6.0","eslint-plugin-react-refresh":"^0.4.5","glob":"^10.3.10","postcss":"^8.4.35","tailwindcss":"^4.0.0","typescript":"^5.3.3","vite":"^5.1.0","vite-plugin-dts":"^3.7.3"},"keywords":["react","crud","ui-components","zustand","react-hook-form","tailwindcss","shadcn"],"author":{"name":"Sujan Bomjan"},"license":"MIT","repository":{"type":"git","url":"git+https://gitlab.com/bomjan133/react-crud.git"},"_id":"@bomjan133/react-crud-ui@1.2.16","gitHead":"3b88620a40b348d5dc552ba8550cc317fe488a06","bugs":{"url":"https://gitlab.com/bomjan133/react-crud/issues"},"homepage":"https://gitlab.com/bomjan133/react-crud#readme","_nodeVersion":"22.17.1","_npmVersion":"10.9.2","dist":{"integrity":"sha512-LuEKvVS3xy++R5e6yNaK9ZzmQW0feYJ4TmPVUOJkg44vMDriuAgKoosX99wIjjEfymkXP4Tmm70akz3T6tzr9g==","shasum":"95d5772a2a4ba4109d8eac1245e9ccb7147ba6af","tarball":"https://registry.npmjs.org/@bomjan133/react-crud-ui/-/react-crud-ui-1.2.16.tgz","fileCount":95,"unpackedSize":21301985,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIBOBYVFzih5fSl6Z37tDGZsw/DAmCxPJh78lspFeyuv1AiAMPnBL/VobIW2C4yAnn/AViM6kSnZDWF+85JVtaVs4FA=="}]},"_npmUser":{"name":"bomjan133","email":"bomjan133@gmail.com"},"directories":{},"maintainers":[{"name":"bomjan133","email":"bomjan133@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/react-crud-ui_1.2.16_1788153708250_0.8417835120845529"},"_hasShrinkwrap":false}},"time":{"created":"2026-07-14T04:22:59.579Z","modified":"2026-08-31T05:21:48.675Z","1.2.5":"2026-07-14T04:22:59.928Z","1.2.6":"2026-07-14T04:37:19.367Z","1.2.7":"2026-07-16T09:14:50.892Z","1.2.8":"2026-08-12T07:01:38.546Z","1.2.9":"2026-08-13T05:02:14.380Z","1.2.10":"2026-08-19T04:47:22.185Z","1.2.11":"2026-08-19T10:10:38.917Z","1.2.12":"2026-08-20T04:26:29.790Z","1.2.13":"2026-08-20T04:51:42.254Z","1.2.14":"2026-08-20T04:56:06.050Z","1.2.15":"2026-08-31T04:28:11.711Z","1.2.16":"2026-08-31T05:21:48.501Z"},"bugs":{"url":"https://gitlab.com/bomjan133/react-crud/issues"},"author":{"name":"Sujan Bomjan"},"license":"MIT","homepage":"https://gitlab.com/bomjan133/react-crud#readme","keywords":["react","crud","ui-components","zustand","react-hook-form","tailwindcss","shadcn"],"repository":{"type":"git","url":"git+https://gitlab.com/bomjan133/react-crud.git"},"description":"A comprehensive React CRUD and UI component library with Zustand store integration","maintainers":[{"name":"bomjan133","email":"bomjan133@gmail.com"}],"readme":"# @bomjan133/react-crud-ui\n\nA comprehensive React CRUD and UI component library with Zustand store integration, layout components, and CLI code generator.\n\n## Features\n\n- 🎨 **20+ UI Components** - Button, Card, Badge, Dialog, Select, Tabs, Table, and more\n- 📊 **CRUD Components** - DataTable, CrudList, CrudForm, CrudDetail with store integration\n- 🔄 **Zustand Store Factory** - Create CRUD stores with minimal code\n- 🎯 **Form Components** - QInput, QSelect, QSwitch, QSearchSelect with validation\n- 🏗️ **Layout Components** - AuthLayout, LoginPage, DashboardLayout with Sidebar & Header\n- 📱 **Responsive** - Mobile-first design with Tailwind CSS v4\n- 🌙 **Dark Mode** - Built-in dark mode support via CSS variables\n- ⚡ **TypeScript Ready** - Full TypeScript support\n- 🛠️ **CLI Generator** - Generate CRUD modules with one command\n\n## Documentation\n\nThe full component/API reference ships inside the package (`node_modules/@bomjan133/react-crud-ui/docs/`) and is also inlined below as collapsible sections, so you can read it directly on this page (npmjs.com or GitLab) without leaving it.\n\n- [Getting Started](#getting-started) - Installation and setup\n- [UI Components](#ui-components) - Button, Card, Badge, Input, Select, etc.\n- [CRUD Components](#crud-components) - DataTable, CrudList, CrudForm, CrudDetail\n- [Form Components](#form-components) - QInput, QTextarea, QSelect, QSwitch\n- [Layout Components](#layout-components) - AuthLayout, LoginPage, DashboardLayout\n- [Store Factory](#store-factory) - createCrudStore and store patterns\n- [Book Viewer](#book-viewer) - BookViewer, EpubViewer, PdfViewer for EPUB/PDF flipbooks\n- [Toast Notifications](#toast-notifications) - useToast, ToastContainer\n- [Utilities](#utilities) - formatCurrency, formatDate, debounce, slugify, and more\n\n<a id=\"getting-started\"></a>\n<details>\n<summary><strong>1. Getting Started</strong></summary>\n\nA comprehensive React CRUD and UI component library with Zustand store integration.\n\n## Table of Contents\n1. [Installation](#installation)\n2. [Quick Setup](#quick-setup)\n3. [Project Structure](#project-structure)\n4. [Creating Your First CRUD Module](#creating-your-first-crud-module)\n\n---\n\n## Installation\n\n```bash\nnpm install @bomjan133/react-crud-ui\n# or\nyarn add @bomjan133/react-crud-ui\n# or\npnpm add @bomjan133/react-crud-ui\n```\n\n### Peer Dependencies\n\nMake sure you have these peer dependencies installed:\n\n```bash\nnpm install react react-dom react-router-dom zustand axios\n```\n\n---\n\n## Quick Setup\n\n### 1. Import Styles\n\nAdd the styles to your main entry file (e.g., `main.jsx` or `App.jsx`):\n\n```jsx\nimport '@bomjan133/react-crud-ui/styles.css'\n```\n\n### 2. Configure Tailwind v4 (Optional)\n\nIf you're using Tailwind CSS v4 in your project:\n\n**index.css:**\n```css\n@import \"tailwindcss\";\n\n@theme {\n  /* Light theme - Clean white/gray palette */\n  --color-background: #ffffff;\n  --color-foreground: #09090b;\n  --color-card: #ffffff;\n  --color-card-foreground: #09090b;\n  --color-popover: #ffffff;\n  --color-popover-foreground: #09090b;\n  --color-primary: #000000;\n  --color-primary-foreground: #fef2f2;\n  --color-secondary: #f4f4f5;\n  --color-secondary-foreground: #18181b;\n  --color-muted: #f4f4f5;\n  --color-muted-foreground: #71717a;\n  --color-accent: #f4f4f5;\n  --color-accent-foreground: #18181b;\n  --color-destructive: #ef4444;\n  --color-destructive-foreground: #fafafa;\n  --color-border: #e4e4e7;\n  --color-input: #e4e4e7;\n  --color-ring: #000000;\n\n  /* Sidebar specific */\n  --color-sidebar: #fafafa;\n  --color-sidebar-foreground: #3f3f46;\n  --color-sidebar-primary: #000000;\n  --color-sidebar-primary-foreground: #fafafa;\n  --color-sidebar-accent: #f4f4f5;\n  --color-sidebar-accent-foreground: #18181b;\n  --color-sidebar-border: #e5e7eb;\n\n  /* Border radius */\n  --radius-sm: 0.25rem;\n  --radius-md: 0.375rem;\n  --radius-lg: 0.5rem;\n}\n```\n\n### 3. Set up API Client\n\nCreate an axios client for API calls:\n\n**src/lib/apiClient.js:**\n```js\nimport axios from 'axios';\n\nconst API_BASE_URL = import.meta.env.VITE_API_BASE_URL || 'http://localhost:8000/api/v1';\n\nconst apiClient = axios.create({\n  baseURL: API_BASE_URL,\n  headers: { 'Content-Type': 'application/json' },\n});\n\n// Add auth token to requests\napiClient.interceptors.request.use((config) => {\n  const token = localStorage.getItem('auth_token');\n  if (token) {\n    config.headers.Authorization = `Bearer ${token}`;\n  }\n  return config;\n});\n\n// Handle auth errors\napiClient.interceptors.response.use(\n  (response) => response,\n  (error) => {\n    if (error.response?.status === 401) {\n      localStorage.removeItem('auth_token');\n      window.location.href = '/login';\n    }\n    return Promise.reject({\n      message: error.response?.data?.error || error.message,\n      status: error.response?.status,\n      data: error.response?.data,\n    });\n  }\n);\n\nexport default apiClient;\n```\n\n---\n\n## Project Structure\n\nRecommended project structure when using this package:\n\n```\nsrc/\n├── App.jsx                 # Main app component\n├── main.jsx                # Entry point\n├── index.css               # Global styles (Tailwind)\n│\n├── pages/                  # Page components (by module)\n│   ├── auth/\n│   │   └── LoginPage.jsx\n│   ├── dashboard/\n│   │   └── DashboardPage.jsx\n│   ├── users/\n│   │   ├── UserListPage.jsx\n│   │   ├── UserFormPage.jsx\n│   │   └── UserDetailPage.jsx\n│   └── products/\n│       ├── ProductListPage.jsx\n│       ├── ProductFormPage.jsx\n│       └── ProductDetailPage.jsx\n│\n├── routes/\n│   ├── index.jsx           # Main router\n│   ├── guards.jsx          # Protected/Public route guards\n│   └── modules/\n│       ├── userRoutes.js\n│       └── productRoutes.js\n│\n├── stores/\n│   ├── createCrudStore.js  # Import from package or customize\n│   ├── useAuthStore.js     # Auth state\n│   ├── useUIStore.js       # UI state (toasts, modals, sidebar)\n│   ├── useUserStore.js\n│   └── useProductStore.js\n│\n├── components/\n│   └── layouts/\n│       ├── MainLayout.jsx  # Uses DashboardLayout from package\n│       └── AuthLayout.jsx  # Uses AuthLayout from package\n│\n├── hooks/\n│   └── useUI.js            # Toast, modal, sidebar hooks\n│\n└── lib/\n    ├── apiClient.js        # Axios instance\n    └── utils.js            # Utility functions\n```\n\n---\n\n## Creating Your First CRUD Module\n\n### Method 1: Using the CLI (Recommended)\n\n```bash\nnpx @bomjan133/react-crud-ui generate product\n```\n\nThis creates:\n- `src/pages/products/ProductListPage.jsx`\n- `src/pages/products/ProductFormPage.jsx`\n- `src/pages/products/ProductDetailPage.jsx`\n- `src/routes/modules/productRoutes.js`\n- `src/stores/useProductStore.js`\n\n### Method 2: Manual Setup\n\n**1. Create the Store:**\n\n```js\n// src/stores/useProductStore.js\nimport { createCrudStore } from '@bomjan133/react-crud-ui';\n\nconst defaultFormValues = {\n  name: '',\n  description: '',\n  price: 0,\n  is_active: true,\n};\n\nconst useProductStore = createCrudStore('product', '/products/', defaultFormValues);\n\nexport default useProductStore;\n```\n\n**2. Create the List Page:**\n\n```jsx\n// src/pages/products/ProductListPage.jsx\nimport { CrudList, Badge } from '@bomjan133/react-crud-ui';\nimport useProductStore from '@/stores/useProductStore';\n\nconst columns = [\n  { key: 'name', label: 'Name', sortable: true },\n  { key: 'price', label: 'Price', render: (v) => `$${v}` },\n  {\n    key: 'is_active',\n    label: 'Status',\n    render: (v) => <Badge variant={v ? 'success' : 'secondary'}>{v ? 'Active' : 'Inactive'}</Badge>,\n  },\n];\n\nexport default function ProductListPage() {\n  const store = useProductStore();\n\n  return (\n    <CrudList\n      title=\"Products\"\n      description=\"Manage products\"\n      createPath=\"/products/create\"\n      editPath=\"/products\"\n      store={store}\n      columns={columns}\n      searchPlaceholder=\"Search products...\"\n      getDeleteItemName={(item) => item?.name}\n    />\n  );\n}\n```\n\n**3. Create the Form Page:**\n\n```jsx\n// src/pages/products/ProductFormPage.jsx\nimport { Box } from 'lucide-react';\nimport { CrudForm, QInput, QTextarea, QSwitch } from '@bomjan133/react-crud-ui';\nimport useProductStore from '@/stores/useProductStore';\n\nexport default function ProductFormPage() {\n  const { form, setFormField } = useProductStore();\n\n  return (\n    <CrudForm\n      title=\"Product\"\n      description=\"Enter product information\"\n      icon={Box}\n      listPath=\"/products\"\n      useStore={useProductStore}\n    >\n      <QInput\n        name=\"name\"\n        label=\"Name\"\n        value={form.values.name || ''}\n        onChange={(val) => setFormField('name', val)}\n        error={form.errors.name}\n        placeholder=\"Enter name\"\n        required\n      />\n      <QTextarea\n        name=\"description\"\n        label=\"Description\"\n        value={form.values.description || ''}\n        onChange={(val) => setFormField('description', val)}\n        rows={4}\n      />\n      <QInput\n        name=\"price\"\n        label=\"Price\"\n        type=\"number\"\n        value={form.values.price || 0}\n        onChange={(val) => setFormField('price', parseFloat(val))}\n      />\n      <QSwitch\n        label=\"Active\"\n        checked={form.values.is_active ?? true}\n        onChange={(val) => setFormField('is_active', val)}\n      />\n    </CrudForm>\n  );\n}\n```\n\n**4. Create Routes:**\n\n```jsx\n// src/routes/modules/productRoutes.js\nimport ProductListPage from '@/pages/products/ProductListPage';\nimport ProductFormPage from '@/pages/products/ProductFormPage';\n\nconst productRoutes = [\n  { path: '/products', element: <ProductListPage /> },\n  { path: '/products/create', element: <ProductFormPage /> },\n  { path: '/products/:id/edit', element: <ProductFormPage /> },\n];\n\nexport default productRoutes;\n```\n\n---\n\n## Next Steps\n\n- [UI Components Guide](#ui-components) - Learn about all available UI components\n- [CRUD Components Guide](#crud-components) - Deep dive into CRUD components\n- [Form Components Guide](#form-components) - Form fields and validation\n- [Layout Components Guide](#layout-components) - Dashboard and Auth layouts\n- [Store Factory Guide](#store-factory) - Creating and customizing stores\n\n</details>\n\n<a id=\"ui-components\"></a>\n<details>\n<summary><strong>2. UI Components Guide</strong></summary>\n\nComplete reference for all UI components included in @bomjan133/react-crud-ui.\n\n## Table of Contents\n1. [Button](#button)\n2. [Card](#card)\n3. [Badge](#badge)\n4. [Input & Label](#input--label)\n5. [Select](#select)\n6. [Checkbox & Switch](#checkbox--switch)\n7. [Dialog](#dialog)\n8. [Dropdown Menu](#dropdown-menu)\n9. [Tabs](#tabs)\n10. [Table](#table)\n11. [Avatar](#avatar)\n12. [Tooltip](#tooltip)\n13. [Date Picker](#date-picker)\n14. [Rich Text Editor](#rich-text-editor)\n15. [Separator](#separator)\n16. [Skeleton](#skeleton)\n16. [Alert](#alert)\n\n---\n\n## Button\n\n```jsx\nimport { Button, buttonVariants } from '@bomjan133/react-crud-ui';\n\n// Variants\n<Button>Default</Button>\n<Button variant=\"secondary\">Secondary</Button>\n<Button variant=\"destructive\">Destructive</Button>\n<Button variant=\"outline\">Outline</Button>\n<Button variant=\"ghost\">Ghost</Button>\n<Button variant=\"link\">Link</Button>\n<Button variant=\"success\">Success</Button>\n\n// Sizes\n<Button size=\"sm\">Small</Button>\n<Button size=\"default\">Default</Button>\n<Button size=\"lg\">Large</Button>\n<Button size=\"icon\"><Icon /></Button>\n\n// With icon\n<Button>\n  <Plus className=\"h-4 w-4 mr-2\" />\n  Add Item\n</Button>\n\n// Loading state\n<Button disabled>\n  <Loader2 className=\"h-4 w-4 mr-2 animate-spin\" />\n  Loading...\n</Button>\n\n// As link using buttonVariants\n<a href=\"/path\" className={buttonVariants({ variant: \"outline\" })}>\n  Link Button\n</a>\n```\n\n---\n\n## Card\n\n```jsx\nimport { \n  Card, \n  CardHeader, \n  CardTitle, \n  CardDescription, \n  CardContent, \n  CardFooter \n} from '@bomjan133/react-crud-ui';\n\n<Card>\n  <CardHeader>\n    <CardTitle>Card Title</CardTitle>\n    <CardDescription>Card description text</CardDescription>\n  </CardHeader>\n  <CardContent>\n    <p>Card content goes here</p>\n  </CardContent>\n  <CardFooter className=\"flex justify-end gap-2\">\n    <Button variant=\"outline\">Cancel</Button>\n    <Button>Save</Button>\n  </CardFooter>\n</Card>\n```\n\n---\n\n## Badge\n\n```jsx\nimport { Badge, badgeVariants } from '@bomjan133/react-crud-ui';\n\n// Variants\n<Badge>Default</Badge>\n<Badge variant=\"secondary\">Secondary</Badge>\n<Badge variant=\"destructive\">Destructive</Badge>\n<Badge variant=\"outline\">Outline</Badge>\n<Badge variant=\"success\">Success</Badge>\n<Badge variant=\"warning\">Warning</Badge>\n<Badge variant=\"info\">Info</Badge>\n\n// Status badges pattern\nconst StatusBadge = ({ status }) => {\n  const variants = {\n    active: 'success',\n    pending: 'warning',\n    inactive: 'secondary',\n    error: 'destructive',\n  };\n  return <Badge variant={variants[status]}>{status}</Badge>;\n};\n```\n\n---\n\n## Input & Label\n\n```jsx\nimport { Input } from '@bomjan133/react-crud-ui';\nimport { Label } from '@bomjan133/react-crud-ui';\n\n// Basic input\n<div className=\"space-y-2\">\n  <Label htmlFor=\"email\">Email</Label>\n  <Input \n    id=\"email\" \n    type=\"email\" \n    placeholder=\"Enter email\"\n    value={value}\n    onChange={(e) => setValue(e.target.value)}\n  />\n</div>\n\n// With error\n<div className=\"space-y-2\">\n  <Label htmlFor=\"name\">Name</Label>\n  <Input \n    id=\"name\" \n    className=\"border-destructive\"\n    value={value}\n    onChange={(e) => setValue(e.target.value)}\n  />\n  <p className=\"text-sm text-destructive\">Name is required</p>\n</div>\n\n// Disabled\n<Input disabled placeholder=\"Disabled input\" />\n```\n\n---\n\n## Select\n\n```jsx\nimport {\n  Select,\n  SelectGroup,\n  SelectValue,\n  SelectTrigger,\n  SelectContent,\n  SelectLabel,\n  SelectItem,\n  SelectSeparator,\n} from '@bomjan133/react-crud-ui';\n\n// Basic select\n<Select value={value} onValueChange={setValue}>\n  <SelectTrigger className=\"w-[200px]\">\n    <SelectValue placeholder=\"Select option\" />\n  </SelectTrigger>\n  <SelectContent>\n    <SelectItem value=\"option1\">Option 1</SelectItem>\n    <SelectItem value=\"option2\">Option 2</SelectItem>\n    <SelectItem value=\"option3\">Option 3</SelectItem>\n  </SelectContent>\n</Select>\n\n// With groups\n<Select>\n  <SelectTrigger>\n    <SelectValue placeholder=\"Select fruit\" />\n  </SelectTrigger>\n  <SelectContent>\n    <SelectGroup>\n      <SelectLabel>Fruits</SelectLabel>\n      <SelectItem value=\"apple\">Apple</SelectItem>\n      <SelectItem value=\"banana\">Banana</SelectItem>\n    </SelectGroup>\n    <SelectSeparator />\n    <SelectGroup>\n      <SelectLabel>Vegetables</SelectLabel>\n      <SelectItem value=\"carrot\">Carrot</SelectItem>\n      <SelectItem value=\"potato\">Potato</SelectItem>\n    </SelectGroup>\n  </SelectContent>\n</Select>\n```\n\n---\n\n## Checkbox & Switch\n\n```jsx\nimport { Checkbox } from '@bomjan133/react-crud-ui';\nimport { Switch } from '@bomjan133/react-crud-ui';\nimport { Label } from '@bomjan133/react-crud-ui';\n\n// Checkbox\n<div className=\"flex items-center space-x-2\">\n  <Checkbox \n    id=\"terms\" \n    checked={checked}\n    onCheckedChange={setChecked}\n  />\n  <Label htmlFor=\"terms\">Accept terms and conditions</Label>\n</div>\n\n// Switch\n<div className=\"flex items-center space-x-2\">\n  <Switch \n    id=\"active\" \n    checked={active}\n    onCheckedChange={setActive}\n  />\n  <Label htmlFor=\"active\">Active</Label>\n</div>\n\n// Switch with description\n<div className=\"flex items-center justify-between rounded-lg border p-4\">\n  <div className=\"space-y-0.5\">\n    <Label>Marketing emails</Label>\n    <p className=\"text-sm text-muted-foreground\">\n      Receive emails about new products\n    </p>\n  </div>\n  <Switch checked={marketing} onCheckedChange={setMarketing} />\n</div>\n```\n\n---\n\n## Dialog\n\n```jsx\nimport {\n  Dialog,\n  DialogTrigger,\n  DialogContent,\n  DialogHeader,\n  DialogTitle,\n  DialogDescription,\n  DialogFooter,\n  DialogClose,\n} from '@bomjan133/react-crud-ui';\n\n<Dialog open={open} onOpenChange={setOpen}>\n  <DialogTrigger asChild>\n    <Button>Open Dialog</Button>\n  </DialogTrigger>\n  <DialogContent>\n    <DialogHeader>\n      <DialogTitle>Dialog Title</DialogTitle>\n      <DialogDescription>\n        This is the dialog description.\n      </DialogDescription>\n    </DialogHeader>\n    <div className=\"py-4\">\n      {/* Dialog content */}\n    </div>\n    <DialogFooter>\n      <DialogClose asChild>\n        <Button variant=\"outline\">Cancel</Button>\n      </DialogClose>\n      <Button onClick={handleSubmit}>Save</Button>\n    </DialogFooter>\n  </DialogContent>\n</Dialog>\n```\n\n---\n\n## Dropdown Menu\n\n```jsx\nimport {\n  DropdownMenu,\n  DropdownMenuTrigger,\n  DropdownMenuContent,\n  DropdownMenuItem,\n  DropdownMenuLabel,\n  DropdownMenuSeparator,\n  DropdownMenuCheckboxItem,\n  DropdownMenuRadioGroup,\n  DropdownMenuRadioItem,\n  DropdownMenuSub,\n  DropdownMenuSubTrigger,\n  DropdownMenuSubContent,\n} from '@bomjan133/react-crud-ui';\n\n<DropdownMenu>\n  <DropdownMenuTrigger asChild>\n    <Button variant=\"ghost\" size=\"icon\">\n      <MoreHorizontal className=\"h-4 w-4\" />\n    </Button>\n  </DropdownMenuTrigger>\n  <DropdownMenuContent align=\"end\">\n    <DropdownMenuLabel>Actions</DropdownMenuLabel>\n    <DropdownMenuSeparator />\n    <DropdownMenuItem onClick={() => handleEdit(item)}>\n      <Edit className=\"h-4 w-4 mr-2\" />\n      Edit\n    </DropdownMenuItem>\n    <DropdownMenuItem onClick={() => handleView(item)}>\n      <Eye className=\"h-4 w-4 mr-2\" />\n      View\n    </DropdownMenuItem>\n    <DropdownMenuSeparator />\n    <DropdownMenuItem \n      onClick={() => handleDelete(item)}\n      className=\"text-destructive\"\n    >\n      <Trash className=\"h-4 w-4 mr-2\" />\n      Delete\n    </DropdownMenuItem>\n  </DropdownMenuContent>\n</DropdownMenu>\n```\n\n---\n\n## Tabs\n\n```jsx\nimport { Tabs, TabsList, TabsTrigger, TabsContent } from '@bomjan133/react-crud-ui';\nimport { QTabs } from '@bomjan133/react-crud-ui';\n\n// Basic Tabs\n<Tabs defaultValue=\"tab1\">\n  <TabsList>\n    <TabsTrigger value=\"tab1\">Tab 1</TabsTrigger>\n    <TabsTrigger value=\"tab2\">Tab 2</TabsTrigger>\n    <TabsTrigger value=\"tab3\">Tab 3</TabsTrigger>\n  </TabsList>\n  <TabsContent value=\"tab1\">Content 1</TabsContent>\n  <TabsContent value=\"tab2\">Content 2</TabsContent>\n  <TabsContent value=\"tab3\">Content 3</TabsContent>\n</Tabs>\n\n// QTabs - Quick tabs with config\nconst tabs = [\n  { value: 'overview', label: 'Overview', content: <Overview /> },\n  { value: 'analytics', label: 'Analytics', content: <Analytics /> },\n  { value: 'settings', label: 'Settings', content: <Settings /> },\n];\n\n<QTabs tabs={tabs} defaultValue=\"overview\" />\n```\n\n---\n\n## Table\n\n```jsx\nimport {\n  Table,\n  TableHeader,\n  TableBody,\n  TableFooter,\n  TableHead,\n  TableRow,\n  TableCell,\n  TableCaption,\n} from '@bomjan133/react-crud-ui';\n\n<Table>\n  <TableCaption>A list of recent invoices.</TableCaption>\n  <TableHeader>\n    <TableRow>\n      <TableHead>Invoice</TableHead>\n      <TableHead>Status</TableHead>\n      <TableHead>Method</TableHead>\n      <TableHead className=\"text-right\">Amount</TableHead>\n    </TableRow>\n  </TableHeader>\n  <TableBody>\n    {invoices.map((invoice) => (\n      <TableRow key={invoice.id}>\n        <TableCell className=\"font-medium\">{invoice.id}</TableCell>\n        <TableCell>{invoice.status}</TableCell>\n        <TableCell>{invoice.method}</TableCell>\n        <TableCell className=\"text-right\">{invoice.amount}</TableCell>\n      </TableRow>\n    ))}\n  </TableBody>\n  <TableFooter>\n    <TableRow>\n      <TableCell colSpan={3}>Total</TableCell>\n      <TableCell className=\"text-right\">$2,500.00</TableCell>\n    </TableRow>\n  </TableFooter>\n</Table>\n```\n\n`Table` renders the `<table>` inside a scrolling wrapper. Pass `containerClassName` to restyle that wrapper — e.g. `containerClassName=\"overflow-visible\"` to drop the scroll container so a `sticky` header can pin to the viewport instead of to the wrapper.\n\n---\n\n## Avatar\n\n```jsx\nimport { Avatar, AvatarImage, AvatarFallback } from '@bomjan133/react-crud-ui';\n\n<Avatar>\n  <AvatarImage src=\"/avatar.jpg\" alt=\"User\" />\n  <AvatarFallback>JD</AvatarFallback>\n</Avatar>\n\n// With size\n<Avatar className=\"h-16 w-16\">\n  <AvatarImage src=\"/avatar.jpg\" alt=\"User\" />\n  <AvatarFallback className=\"text-lg\">JD</AvatarFallback>\n</Avatar>\n```\n\n---\n\n## Tooltip\n\n```jsx\nimport { \n  Tooltip, \n  TooltipTrigger, \n  TooltipContent, \n  TooltipProvider \n} from '@bomjan133/react-crud-ui';\n\n// Wrap your app with TooltipProvider\n<TooltipProvider>\n  <App />\n</TooltipProvider>\n\n// Usage\n<Tooltip>\n  <TooltipTrigger asChild>\n    <Button variant=\"ghost\" size=\"icon\">\n      <Info className=\"h-4 w-4\" />\n    </Button>\n  </TooltipTrigger>\n  <TooltipContent>\n    <p>This is helpful information</p>\n  </TooltipContent>\n</Tooltip>\n```\n\n---\n\n## Date Picker\n\n```jsx\nimport { DatePicker, DateRangePicker } from '@bomjan133/react-crud-ui';\n\n// Single date picker\nconst [date, setDate] = useState();\n<DatePicker\n  date={date}\n  onDateChange={setDate}\n  placeholder=\"Pick a date\"\n/>\n\n// Date range picker\nconst [dateRange, setDateRange] = useState();\n<DateRangePicker\n  dateRange={dateRange}\n  onDateRangeChange={setDateRange}\n  placeholder=\"Pick a date range\"\n/>\n```\n\n---\n\n## Rich Text Editor\n\n```jsx\nimport { RichTextEditor } from '@bomjan133/react-crud-ui';\n\nconst [content, setContent] = useState('');\n\n<RichTextEditor\n  value={content}\n  onChange={setContent}\n  placeholder=\"Start writing...\"\n  height=\"300px\"\n/>\n```\n\n---\n\n## Separator\n\n```jsx\nimport { Separator } from '@bomjan133/react-crud-ui';\n\n// Horizontal\n<div>\n  <h2>Section 1</h2>\n  <Separator className=\"my-4\" />\n  <h2>Section 2</h2>\n</div>\n\n// Vertical\n<div className=\"flex h-5 items-center space-x-4\">\n  <span>Item 1</span>\n  <Separator orientation=\"vertical\" />\n  <span>Item 2</span>\n  <Separator orientation=\"vertical\" />\n  <span>Item 3</span>\n</div>\n```\n\n---\n\n## Skeleton\n\n```jsx\nimport { Skeleton } from '@bomjan133/react-crud-ui';\n\n// Basic skeleton\n<Skeleton className=\"h-4 w-[250px]\" />\n\n// Card skeleton\n<div className=\"flex items-center space-x-4\">\n  <Skeleton className=\"h-12 w-12 rounded-full\" />\n  <div className=\"space-y-2\">\n    <Skeleton className=\"h-4 w-[250px]\" />\n    <Skeleton className=\"h-4 w-[200px]\" />\n  </div>\n</div>\n\n// Table skeleton\n<div className=\"space-y-2\">\n  {[1, 2, 3, 4, 5].map((i) => (\n    <Skeleton key={i} className=\"h-10 w-full\" />\n  ))}\n</div>\n```\n\n---\n\n## Alert\n\n```jsx\nimport { \n  Alert, \n  AlertTitle, \n  AlertDescription, \n  AlertWithIcon, \n  alertVariants \n} from '@bomjan133/react-crud-ui';\n\n// Basic alert\n<Alert>\n  <AlertTitle>Heads up!</AlertTitle>\n  <AlertDescription>\n    You can add components to your app using the cli.\n  </AlertDescription>\n</Alert>\n\n// Destructive alert\n<Alert variant=\"destructive\">\n  <AlertTitle>Error</AlertTitle>\n  <AlertDescription>\n    Your session has expired. Please log in again.\n  </AlertDescription>\n</Alert>\n\n// With icon\n<AlertWithIcon type=\"success\" title=\"Success\" message=\"Changes saved successfully\" />\n<AlertWithIcon type=\"error\" title=\"Error\" message=\"Something went wrong\" />\n<AlertWithIcon type=\"warning\" title=\"Warning\" message=\"This action cannot be undone\" />\n<AlertWithIcon type=\"info\" title=\"Info\" message=\"New features available\" />\n```\n\n</details>\n\n<a id=\"crud-components\"></a>\n<details>\n<summary><strong>3. CRUD Components Guide</strong></summary>\n\nComplete reference for CRUD components in @bomjan133/react-crud-ui.\n\n## Table of Contents\n1. [DataTable](#datatable)\n2. [CrudList](#crudlist)\n3. [CrudForm](#crudform)\n4. [CrudDetail](#cruddetail)\n5. [Pagination](#pagination)\n6. [Loading Components](#loading-components)\n7. [Empty States](#empty-states)\n8. [Modal Components](#modal-components)\n\n---\n\n## DataTable\n\nA data table with sorting, pagination, search, row selection, clickable \"link\" columns, and a per-row dropdown actions menu.\n\n### Props\n\n| Prop | Type | Default | Description |\n|------|------|---------|--------------|\n| `data` | `array` | `[]` | Rows to display (current page only — this component does not paginate client-side). |\n| `columns` | `array` | `[]` | Column definitions. See Column Definition below. |\n| `loading` | `boolean` | `false` | Shows a full-width `Loading` row instead of the data rows. |\n| `error` | `any` | `null` | Accepted but currently unused — nothing in the component reads or renders this value. |\n| `pagination` | `boolean` | `null` | Only meaningful when set to `false`, which hides the pagination footer entirely. Any other value (including the default `null`) shows it. Pagination is otherwise driven by the flat props below — it is **not** an object with `{ page, totalPages, total }`. |\n| `currentPage` | `number` | `1` | Current page (1-indexed). Used to compute serial numbers and passed through to the internal `Pagination` component. |\n| `pageSize` | `number` | `15` | Items per page. Used to compute serial numbers and passed to `Pagination`. |\n| `totalItems` | `number` | `0` | Total item count, passed to `Pagination`. |\n| `totalPages` | `number` | `1` | Total page count, passed to `Pagination`. |\n| `onPageChange` | `function` | - | Passed to `Pagination`; called with the new page. |\n| `onPageSizeChange` | `function` | - | Passed to `Pagination`; called when the page size changes. |\n| `sortable` | `boolean` | `true` | Global switch for sorting. A column must also set `sortable: true` to become sortable. |\n| `sortColumn` | `string` | `null` | The field currently sorted on (compared against each column's `sortKey`/`accessor`/`key`). |\n| `sortDirection` | `'asc' \\| 'desc' \\| null` | `null` | Current sort direction. |\n| `onSort` | `function` | - | Called as `onSort(field, direction)` when a sortable header is clicked. Clicking cycles asc → desc → none; on the third click it's called as `onSort(null, null)`. |\n| `openInNewTab` | `boolean` | `false` | When a column renders as a link (via `onViewLink`), opens it in a new tab (`target=\"_blank\"`) instead of the same tab. |\n| `searchable` | `boolean` | `true` | Shows/hides the search input in the toolbar. |\n| `searchValue` | `string` | `''` | **Initial value only** — seeds the component's internal search state on mount. The input is managed internally after that; changing this prop later does not reset the input. |\n| `onSearchChange` | `function` | - | Called with the search string, debounced 300ms after the user stops typing (fixed delay, not configurable). |\n| `searchPlaceholder` | `string` | `'Search...'` | Placeholder text for the search input. |\n| `filters` | `node` | - | Extra filter control(s) rendered next to the search box. Accepts a single element or an array/fragment of elements; each is wrapped in a `w-[200px]` container. |\n| `toolbarActions` | `node` | - | Content rendered on the right side of the toolbar (e.g. an \"Add\" button). |\n| `selectable` | `boolean` | `false` | Shows a checkbox column for row selection, plus a tri-state select-all checkbox in the header. |\n| `selectedRows` | `array` | `[]` | Array of currently-selected row keys (as returned by `getRowKey`). |\n| `onSelectionChange` | `function` | - | Called with the new array of selected row keys, on both row and select-all/clear actions. |\n\n#### Select-all header checkbox\n\nWhen `selectable` is set, the header cell renders a tri-state checkbox that reflects the rows on the **current page**:\n\n| Rows selected on this page | Header state | Clicking it |\n|---|---|---|\n| None | unchecked | selects every row on the page |\n| Some, but not all | indeterminate (a dash, not a tick) | selects every row on the page |\n| All | checked | deselects every row on the page |\n\nSelections made on other pages are preserved — select-all merges the current page's keys into `selectedRows`, and deselect-all removes only that page's keys. To wipe the selection entirely, call `onSelectionChange([])` yourself (that is what the toolbar's \"Clear\" button does).\n| `actions` | `array` | `[]` | Row-level dropdown menu actions. There is no `onEdit`/`onDelete`/`onView`/`showActions` prop on `DataTable` itself — a single `actions` array drives the whole menu. See Actions Column below. |\n| `onRowClick` | `function` | - | Called with the row object when a row is clicked (ignored if the click originates from the checkbox or actions cells, which stop propagation). |\n| `striped` | `boolean` | `false` | Applies a light background to odd rows. |\n| `hover` | `boolean` | `true` | Gates two visual behaviors: shows a pointer cursor on rows when `onRowClick` is set, and (when `onRowClick` is *not* set) highlights selected rows with a tinted background. It does not add a generic hover background by itself. |\n| `compact` | `boolean` | `false` | Reduces cell vertical padding. |\n| `className` | `string` | - | Class for the outer wrapping `<div>`. |\n| `emptyTitle` | `string` | `'No data found'` | Empty-state title. |\n| `emptyDescription` | `string` | `'There are no items to display.'` | Empty-state description text. |\n| `emptyAction` | `string` | - | Label for an optional empty-state action button. |\n| `onEmptyAction` | `function` | - | Handler for the empty-state action button. |\n| `getRowKey` | `function` | `(row) => row.id \\|\\| row._id` | Derives a unique key per row; used for React keys and selection tracking. |\n| `showSerialNumber` | `boolean` | `true` | Shows a leading row-number column. |\n| `serialNumberHeader` | `string` | `'SN'` | Header label for the serial number column. |\n| `onViewClick` | `function` | - | If set, \"clickable\" columns (see `clickableColumns`) render their value as a button; clicking it calls `onViewClick(row)`. |\n| `onViewLink` | `function` | - | If set, \"clickable\" columns render their value as an `<a>`; called as `onViewLink(row)` to compute the `href`. Takes precedence over `onViewClick`. |\n| `onBeforeNavigate` | `function` | - | Only used when `onViewLink` is set and `openInNewTab` is `false`. If provided, clicking the link is intercepted (`preventDefault`/`stopPropagation`) and `onBeforeNavigate(href)` is called instead of navigating. |\n| `clickableColumns` | `array` | `[]` | List of column `accessor`/`key` strings that should render as links/buttons. Pass `['*']` to make every column clickable. If left empty, only columns whose accessor/key is `\"name\"` or `\"title\"` are clickable by default. |\n| `enableTextClamping` | `boolean` | `true` | Truncates long string cell values (30+ characters) with an ellipsis and shows the full text in a tooltip on hover. |\n| `defaultMaxLines` | `number` | `1` | Default number of lines before clamping; overridable per-column via `column.maxLines`. |\n| `tableClassName` | `string` | - | Class passed to the root `<Table>`. |\n| `tableHeaderClassName` | `string` | - | Class passed to `<TableHeader>`. |\n| `tableBodyClassName` | `string` | - | Class passed to `<TableBody>`. |\n| `tableRowClassName` | `string` | - | Class merged onto every data/status `<TableRow>`. |\n| `tableHeadClassName` | `string` | - | Class merged onto every `<TableHead>` cell (selection, SN, data, and actions headers). |\n| `tableCellClassName` | `string` | - | Class merged onto every `<TableCell>` (selection, SN, data, actions, and loading/empty cells). |\n| `headerRowClassName` | `string` | - | Class merged onto the header `<TableRow>`. |\n| `statusRowClassName` | `string` | - | Class merged onto the loading/empty-state `<TableRow>`. |\n| `paginationClassName` | `string` | - | Class passed to the `Pagination` component. |\n| `stickyPagination` | `boolean` | `false` | Pins the pagination bar to the bottom of the viewport while the table scrolls, so page controls stay reachable on long pages (e.g. the default 15 rows). |\n| `stickyPaginationClassName` | `string` | - | Class on the sticky pagination wrapper — use it to offset the bar (`bottom-16`) or restyle its surface. |\n| `stickyHeader` | `boolean` | `false` | Pins the column headers to the top of the viewport while the table scrolls. Enabling this removes the table's horizontal scrolling (see note below). |\n| `stickyHeaderOffset` | `number \\| string` | auto | Distance from the top of the viewport where the header parks. A number is treated as pixels. Left unset it reads `--rcu-header-offset`, which `DashboardLayout` sets to its own header height — so the table header parks below the app header instead of behind it. Falls back to `0`. |\n| `stickyHeaderClassName` | `string` | - | Class merged onto every pinned `<th>` — use it to change the pinned background or z-index. |\n\n> **Not implemented:** `onEdit`, `onDelete`, `onView`, `showActions`, and `emptyMessage` do not exist on `DataTable` — they were fabricated in an earlier version of this doc. Use `actions` (below) and `emptyTitle`/`emptyDescription` instead.\n\n> **`stickyHeader` and horizontal scrolling are mutually exclusive.** A `sticky` element pins to its nearest scrolling ancestor, so while the table sits inside a horizontally scrollable wrapper the header can only pin to that wrapper — never to the window. Turning on `stickyHeader` therefore drops the wrapper's `overflow-auto`, and a table wider than its container will be clipped rather than scrollable. Leave `stickyHeader` off for wide tables, or give the columns narrower `width`/`maxWidth` values first.\n\n### Column Definition\n\n```js\nconst columns = [\n  {\n    // Value extraction — accessor wins over key\n    accessor: 'name',        // string, OR a function: (row) => value\n    key: 'name',              // fallback for accessor; also used as React key/sort field if accessor is absent\n\n    // Header text — header wins over label\n    header: 'Name',\n    label: 'Name',             // fallback if header is not set\n\n    sortable: true,             // enables sorting for this column (requires top-level sortable !== false)\n    sortKey: 'name',            // optional override of the field name used for sort comparisons/onSort\n\n    render: (value, row, index) => (\n      <span className=\"font-medium\">{value}</span>\n    ),                          // custom cell renderer, highest precedence\n    format: (value, row) => value,  // used only if render is not provided\n\n    width: 200,                 // inline style: width\n    minWidth: 120,               // inline style: minWidth\n    maxWidth: 300,               // inline style: maxWidth (cells default to '300px' if unset)\n\n    headerClassName: '',         // extra className on the <TableHead>\n    cellClassName: '',           // extra className on the <TableCell>\n\n    disableClamping: false,      // opt this column out of enableTextClamping\n    maxLines: 1,                 // per-column override of defaultMaxLines\n  },\n];\n```\n\n> A column-level `className` field does not exist — the real per-column style hooks are `headerClassName` and `cellClassName`.\n\n### Actions Column\n\nPassing a non-empty `actions` array is what causes the Actions column (header cell + per-row dropdown trigger) to render — there is no separate `showActions` toggle.\n\n```js\nconst actions = [\n  {\n    label: 'Edit',\n    icon: PencilIcon,               // optional component, rendered at 16px with right margin\n    onClick: (row) => handleEdit(row),\n    disabled: false,                 // optional\n  },\n  {\n    label: 'Delete',\n    icon: TrashIcon,\n    variant: 'destructive',          // only 'destructive' has special styling (red text)\n    onClick: (row) => handleDelete(row),\n    hidden: (row) => row.locked,      // boolean, or a function(row) => boolean\n  },\n];\n```\n\n- Items render in a `DropdownMenu` opened by an icon-only ghost button, in the same order as the `actions` array.\n- Per row, an action is filtered out of the menu if `hidden` is `true`, or if `hidden` is a function returning `true` for that row.\n- `disabled` maps directly to the underlying menu item's disabled state.\n- Clicking a row's actions cell does not trigger `onRowClick` (click propagation is stopped).\n\n### Usage\n\n```jsx\nimport { DataTable } from '@bomjan133/react-crud-ui';\nimport { PencilIcon, TrashIcon } from 'lucide-react';\n\n<DataTable\n  data={users}\n  columns={[\n    { key: 'name', label: 'Name', sortable: true },\n    { key: 'email', label: 'Email' },\n    {\n      key: 'status',\n      label: 'Status',\n      render: (value) => <Badge>{value}</Badge>,\n    },\n  ]}\n  loading={isLoading}\n  searchValue={search}\n  onSearchChange={setSearch}\n  currentPage={page}\n  pageSize={15}\n  totalItems={total}\n  totalPages={Math.ceil(total / 15)}\n  onPageChange={setPage}\n  sortColumn={sortColumn}\n  sortDirection={sortDirection}\n  onSort={(field, direction) => {\n    setSortColumn(field);\n    setSortDirection(direction);\n  }}\n  actions={[\n    { label: 'Edit', icon: PencilIcon, onClick: (row) => openEdit(row) },\n    {\n      label: 'Delete',\n      icon: TrashIcon,\n      variant: 'destructive',\n      onClick: (row) => openDelete(row),\n    },\n  ]}\n  emptyTitle=\"No users found\"\n  emptyDescription=\"Try adjusting your search or add a new user.\"\n/>\n\n// Selectable rows with a clickable \"name\" column linking to a detail page\n<DataTable\n  data={orders}\n  columns={[{ key: 'name', label: 'Order' }, { key: 'amount', label: 'Amount' }]}\n  selectable\n  selectedRows={selectedIds}\n  onSelectionChange={setSelectedIds}\n  onViewLink={(row) => `/orders/${row.id}`}\n  clickableColumns={['name']}\n  getRowKey={(row) => row.id}\n/>\n```\n\n---\n\n## CrudList\n\nA complete list view component that combines `DataTable` with a header, toolbar (search/create/refresh/export/bulk actions), pagination, row actions (view/edit/delete + custom), and a delete-confirmation modal. It can source its data either from a store object or from direct props — each store capability (`items`, `loading`, `error`, `pagination`, `fetchList`, `delete`, `setPage`, `setPageSize`, `setFilters`, sorting) is read independently via optional chaining and falls back to the matching direct prop if the store doesn't provide it.\n\n### Store integration (preferred)\n\n| Prop | Type | Default | Description |\n|------|------|---------|--------------|\n| `store` | `object` | - | A store instance (e.g. a Zustand store). Recognized shape: `store.items` (array), `store.loading` (bool), `store.error`, `store.pagination` (`{ page, pageSize, total, totalPages }`), `store.fetchList()`, `store.delete(id)`, `store.setPage(page)`, `store.setPageSize(size)`, `store.setFilters({ search })`, `store.sortColumn`, `store.sortDirection`, `store.setSort(column, direction)`. None of these are required — missing pieces fall back to the direct props below. |\n\n> **Note if you're using this package's own [`createCrudStore`](#store-factory):** its pagination fields are flat (`page`/`pageSize`/`totalItems`/`totalPages`), not a nested `pagination` object. Since `CrudList` specifically reads `store.pagination`, a plain `createCrudStore` instance won't provide it and pagination will appear stuck — bridge it yourself, e.g. `store={{ ...store, pagination: { page: store.page, pageSize: store.pageSize, total: store.totalItems, totalPages: store.totalPages } }}`. See [Store Factory → Compatibility](#compatibility-with-crudlist--crudform--cruddetail) for the full compatibility matrix (this also applies to `CrudDetail`'s `currentItem` vs. `item`, and `CrudForm`'s store mode).\n\n### Direct data props (used if store not provided)\n\n| Prop | Type | Default | Description |\n|------|------|---------|--------------|\n| `data` | `array` | - | Row data. Used when `store?.items` is nullish. |\n| `loading` | `boolean` | `false` | Loading state, used when `store?.loading` is nullish. |\n| `error` | `any` | `null` | Error state, used when `store?.error` is nullish. |\n| `skipInitialFetch` | `boolean` | `false` | When a store is provided, skips the automatic call to `store.fetchList()` on mount. |\n\n### Columns configuration\n\n| Prop | Type | Default | Description |\n|------|------|---------|--------------|\n| `columns` | `array` | `[]` | Column definitions, forwarded to the internal `DataTable` — see [DataTable's Column Definition](#column-definition) for the full field list (`accessor`/`key`, `header`/`label`, `sortable`, `sortKey`, `render`, `format`, width fields, `headerClassName`/`cellClassName`, clamping options). |\n\n### Pagination (direct-prop mode)\n\n| Prop | Type | Default | Description |\n|------|------|---------|--------------|\n| `currentPage` | `number` | `1` | Current page, used when no `store.pagination` value is available. |\n| `pageSize` | `number` | `15` | Page size fallback. |\n| `totalItems` | `number` | `0` | Total item count fallback. |\n| `totalPages` | `number` | `1` | Total page count fallback. |\n| `onPageChange` | `function(page)` | - | Called when the store has no `setPage` method. |\n| `onPageSizeChange` | `function(size)` | - | Called when the store has no `setPageSize` method. |\n\n> There is no `showPagination` prop. `CrudList` never passes a `pagination` prop through to `DataTable`, and `DataTable` renders its pagination footer whenever there is data — so pagination is always shown once you have data.\n\n### Sorting\n\n| Prop | Type | Default | Description |\n|------|------|---------|--------------|\n| `sortColumn` | `string` | - | Current sort column, used when the store doesn't expose `sortColumn`. |\n| `sortDirection` | `'asc' \\| 'desc' \\| null` | - | Current sort direction fallback. |\n| `onSort` | `function(column, direction)` | - | Called on sort-header click when no `store` is present. When a `store` **is** present, sort clicks instead call `store.setSort(column, direction)` followed by `store.fetchList()`, regardless of whether `onSort` is also passed. |\n\n### Search\n\n| Prop | Type | Default | Description |\n|------|------|---------|--------------|\n| `searchValue` | `string` | `\"\"` | Controlled search text, used only when the store has no `setFilters` method. |\n| `onSearchChange` | `function(value)` | - | Called on search input change when the store has no `setFilters` method. |\n| `searchPlaceholder` | `string` | `\"Search...\"` | Placeholder text for the search input. |\n| `searchable` | `boolean` | `true` | Whether the search input (and debounced store search) is enabled. This is the real prop for what an earlier version of this doc called `showSearch`, which does not exist. |\n| `openInNewTab` | `boolean` | `false` | When true, clickable-column/view links open via `window.open(..., \"_blank\")` instead of SPA navigation, and scroll-position save/restore is skipped. |\n\nWhen a store with `setFilters` is present, typing in the search box updates internal state, and after a 300ms debounce calls `store.setFilters({ search })`, resets to page 1, then calls `store.fetchList()`.\n\n### Selection\n\n| Prop | Type | Default | Description |\n|------|------|---------|--------------|\n| `selectable` | `boolean` | `false` | Enables row checkboxes and the tri-state \"select all\" header checkbox (see [Select-all header checkbox](#select-all-header-checkbox)). |\n| `selectedRows` | `array` | `[]` | Array of currently-selected row keys (as returned by `getRowKey`). Controlled — the component does not manage this internally. |\n| `onSelectionChange` | `function(newSelectedRowKeys: array)` | - | Called with the full updated array whenever a row or \"select all\" checkbox changes. |\n| `showBulkDelete` | `boolean` | `false` | Shows a trash icon inside the \"N selected\" chip. Clicking it opens a confirmation modal. |\n| `onBulkDelete` | `function(selectedRowKeys: array)` | - | Runs on confirm. If omitted, CrudList falls back to calling the store's `delete` once per selected key. |\n| `bulkDeleteLabel` | `string` | `\"Delete selected\"` | Tooltip/aria-label on the trash icon. |\n\nSelection is **uncontrolled by default** — `selectable` on its own is enough, and CrudList holds the array internally. Pass `selectedRows` to take control (needed when something outside the table, like an export button, has to read the selection); `onSelectionChange` still fires either way.\n\n### CRUD Actions (direct-prop mode, used if paths not provided)\n\n| Prop | Type | Default | Description |\n|------|------|---------|--------------|\n| `onCreate` | `function()` | - | Called by the Create button when `createPath` is not set. |\n| `onView` | `function(row)` | - | Called by the row \"View\" action when `detailPath` is not set. |\n| `onEdit` | `function(row)` | - | Called by the row \"Edit\" action when `editPath` is not set. |\n| `onDelete` | `function(row): Promise` | - | Called on delete confirmation when the store has no `delete` method. Awaited; success shows a toast, thrown errors show an error toast. |\n| `onRefresh` | `function()` | - | Called by the Refresh button when the store has no `fetchList` method. |\n| `onExport` | `function() \\| React element` | - | If a valid React element, it is rendered as-is in the toolbar. If a function, a default \"Export\" button is rendered that calls it on click. |\n\n### Table & button styling overrides\n\nPurely presentational, forwarded straight through to `DataTable`/toolbar buttons:\n\n| Prop | Type | Description |\n|------|------|-------------|\n| `tableClassName` | `string` | Class on the `<Table>` element. |\n| `tableHeaderClassName` | `string` | Class on `<TableHeader>`. |\n| `tableBodyClassName` | `string` | Class on `<TableBody>`. |\n| `tableRowClassName` | `string` | Class on each `<TableRow>` (data + status rows). |\n| `tableHeadClassName` | `string` | Class on each `<TableHead>` cell. |\n| `tableCellClassName` | `string` | Class on each `<TableCell>`. |\n| `headerRowClassName` | `string` | Class on the header `<TableRow>`. |\n| `statusRowClassName` | `string` | Class on the loading/empty status row. |\n| `paginationClassName` | `string` | Class passed to the `Pagination` component. |\n| `stickyPagination` | `boolean` | Pins the pagination bar to the bottom of the viewport while the list scrolls (default `false`). |\n| `stickyPaginationClassName` | `string` | Class on the sticky pagination wrapper — use it to offset the bar (`bottom-16`) or restyle its surface. |\n| `stickyHeader` | `boolean` | Pins the column headers to the top of the viewport while the list scrolls (default `false`). Removes the table's horizontal scrolling. |\n| `stickyHeaderOffset` | `number \\| string` | Where the pinned header parks, measured from the top of the viewport; a number means pixels. Defaults to `--rcu-header-offset`, which `DashboardLayout` sets to its own header height, else `0`. |\n| `stickyHeaderClassName` | `string` | Class merged onto every pinned `<th>`. |\n| `createButtonClassName` | `string` | Class on the Create button. |\n| `refreshButtonClassName` | `string` | Class on the Refresh button. |\n| `exportButtonClassName` | `string` | Class on the default Export button. |\n| `bulkActionButtonClassName` | `string` | Class applied to every bulk-action button. |\n\n### Navigation paths\n\n| Prop | Type | Default | Description |\n|------|------|---------|--------------|\n| `createPath` | `string` | - | If set, the Create button navigates here (via `react-router`'s `navigate`) instead of calling `onCreate`. Used as-is — no suffix appended. |\n| `detailPath` | `string` | - | If set, the row \"View\" action and clickable-name columns navigate to `` `${detailPath}/${getRowKey(row)}` `` instead of calling `onView`. |\n| `editPath` | `string` | - | If set, the row \"Edit\" action navigates to `` `${editPath}/${getRowKey(row)}/edit` `` instead of calling `onEdit`. |\n\n> **Correction:** there is no `viewPath` prop — the real prop is `detailPath`. An earlier version of this doc used `viewPath`, which has no effect.\n\n### Breadcrumb helper\n\n| Prop | Type | Default | Description |\n|------|------|---------|--------------|\n| `getBreadcrumbName` | `function(row)` | - | Returns a display name passed as `location.state.breadcrumbName` when navigating to the detail page. |\n| `customBreadcrumbPaths` | `object` | - | Static breadcrumb path map passed as `location.state.customBreadcrumbPaths` on create/view/edit navigation, unless `getCustomBreadcrumbPath` is given. |\n| `getCustomBreadcrumbPath` | `function(row)` | - | Per-row/per-action function that computes breadcrumb paths, overriding `customBreadcrumbPaths` when provided. |\n| `getParentPath` | `function(row)` | - | Returns a parent path string; used to build `{ [firstPathSegment]: parentPath }` (passed as `location.state.parentPath`) when neither `customBreadcrumbPaths` nor `getCustomBreadcrumbPath` produced a result. |\n| `preserveLocationState` | `boolean` | `false` | If true, spreads the current `location.state` into the state object passed to create/view/edit navigations. |\n\n### Custom actions\n\n| Prop | Type | Default | Description |\n|------|------|---------|--------------|\n| `additionalActions` | `array` | `[]` | Extra per-row dropdown actions, inserted between the built-in Edit and Delete actions. Each item: `{ label, icon?: Component, onClick(row), variant?: 'destructive', disabled?: boolean, hidden?: boolean \\| (row) => boolean }`. |\n| `bulkActions` | `array` | `[]` | Toolbar buttons shown only when `selectable` is true and at least one row is selected. Each item: `{ label, icon?: Component, variant?: string (default \"outline\"), onClick(selectedRowKeys), disabled?: boolean, className?: string }`. |\n\n### Labels\n\n| Prop | Type | Default | Description |\n|------|------|---------|--------------|\n| `title` | `string` | - | Card title text. Also used verbatim in the delete-success toast: `` `${title} Deleted successfully` `` (note: uses `title`, not `itemName`). |\n| `description` | `string` | - | Card description text. |\n| `createLabel` | `string` | `\"Create\"` | Create button label. |\n| `refreshLabel` | `string` | `\"Refresh\"` | Refresh button label. |\n| `exportLabel` | `string` | `\"Export\"` | Default Export button label. |\n| `viewLabel` | `string` | `\"View\"` | Row \"View\" action label. |\n| `editLabel` | `string` | `\"Edit\"` | Row \"Edit\" action label. |\n| `deleteLabel` | `string` | `\"Delete\"` | Row \"Delete\" action label. |\n| `itemName` | `string` | `\"item\"` | Used in the default delete-confirmation title/description and the empty-state text (`` `No ${itemName}s found` ``, `` `Create your first ${itemName} to get started.` ``). |\n\n### Row key\n\n| Prop | Type | Default | Description |\n|------|------|---------|--------------|\n| `getRowKey` | `function(row)` | `(row) => row.uuid \\|\\| row.id \\|\\| row._id` | Derives a unique key/id for each row; used for selection, navigation URLs, delete calls, and React keys. |\n\n### Appearance\n\n| Prop | Type | Default | Description |\n|------|------|---------|--------------|\n| `showHeader` | `boolean` | `true` | Whether to wrap content in a `Card` with a header (title/description/toolbar). If false (or no title/description), content renders in a plain `<div>`. |\n| `showToolbar` | `boolean` | `true` | Whether to render the toolbar (header actions, bulk actions, export, refresh, create) — independent of `showHeader`. |\n| `compact` | `boolean` | `false` | Passed to `DataTable` to tighten row padding. |\n| `className` | `string` | - | Class on the outer `Card`/`div` wrapper. |\n| `filters` | `node` | - | Custom filter control(s) rendered in the `DataTable` toolbar next to the search box. |\n| `headerActions` | `node` | - | Arbitrary content rendered at the start of the toolbar, before bulk actions/export/refresh/create. **This is the real \"custom header actions\" slot** — `children` is not read anywhere in `CrudList` and has no effect. |\n| `showEditButton` | `boolean` | `true` | Hides the built-in row \"Edit\" action when `false`, even if `editPath`/`onEdit` is set. |\n| `showDeleteButton` | `boolean` | `true` | Hides the built-in row \"Delete\" action when `false`, even if delete is otherwise available. |\n| `clickableColumns` | `array` | `[]` | Accessor keys that should render as clickable links/buttons to the detail view. Pass `[\"*\"]` for all columns. Forwarded to `DataTable`. |\n\n> **Correction:** `icon` (a title icon) and `children` (custom header actions) do not exist on `CrudList` — both were fabricated in an earlier version of this doc. Use `headerActions` for custom toolbar content.\n\n### Delete confirmation\n\n| Prop | Type | Default | Description |\n|------|------|---------|--------------|\n| `deleteConfirmTitle` | `string` | - | Overrides the delete modal's title (default: `` `Delete ${itemName}` ``). |\n| `deleteConfirmDescription` | `string` | - | Overrides the modal's description (default asks to confirm deleting the resolved item name). |\n| `getDeleteItemName` | `function(item)` | - | Returns the display name for the item being deleted (HTML-stripped and truncated to 80 chars internally); falls back to `item.name \\|\\| item.title \\|\\| itemName`. |\n\n> There is no `onDeleteSuccess` callback — delete success always shows a hardcoded toast using `title` (see Labels above).\n\n### Usage\n\n**Basic (store-based):**\n\n```jsx\nimport { CrudList } from '@bomjan133/react-crud-ui';\nimport { useUserStore } from './stores/useUserStore';\n\nconst columns = [\n  { accessor: 'name', header: 'Name', sortable: true },\n  { accessor: 'email', header: 'Email' },\n  {\n    accessor: 'createdAt',\n    header: 'Created',\n    format: (value) => new Date(value).toLocaleDateString(),\n  },\n];\n\nfunction UsersPage() {\n  const store = useUserStore();\n\n  return (\n    <CrudList\n      store={store}\n      title=\"Users\"\n      description=\"Manage your organization's users\"\n      columns={columns}\n      createPath=\"/users/create\"\n      detailPath=\"/users\"\n      editPath=\"/users\"\n      itemName=\"user\"\n      getRowKey={(row) => row.id}\n    />\n  );\n}\n```\n\n**Selection + bulk actions (direct data props):**\n\n```jsx\nimport { useState } from 'react';\nimport { CrudList } from '@bomjan133/react-crud-ui';\nimport { Archive, Trash2 } from 'lucide-react';\n\nconst columns = [\n  { accessor: 'name', header: 'Name', sortable: true },\n  { accessor: 'status', header: 'Status' },\n];\n\nfunction InvoicesPage({ invoices, isLoading }) {\n  const [selectedRows, setSelectedRows] = useState([]);\n\n  const bulkActions = [\n    { label: 'Archive', icon: Archive, onClick: (rowKeys) => archiveInvoices(rowKeys) },\n    { label: 'Delete', icon: Trash2, variant: 'destructive', onClick: (rowKeys) => deleteInvoices(rowKeys) },\n  ];\n\n  return (\n    <CrudList\n      data={invoices}\n      loading={isLoading}\n      columns={columns}\n      title=\"Invoices\"\n      itemName=\"invoice\"\n      selectable\n      selectedRows={selectedRows}\n      onSelectionChange={setSelectedRows}\n      bulkActions={bulkActions}\n      onCreate={() => openCreateModal()}\n      onView={(row) => openDetailModal(row)}\n      onEdit={(row) => openEditModal(row)}\n      onDelete={async (row) => deleteInvoice(row.id)}\n      getRowKey={(row) => row.id}\n    />\n  );\n}\n```\n\n---\n\n## CrudForm\n\nA form component for create/edit operations. **It is dual-mode** — which mode renders is decided by a single runtime check: `useStore && children` (both truthy).\n\n- **Store mode** (`useStore` **and** `children` both supplied): renders `children` verbatim inside a `<form>`, does its own lightweight \"required\" validation by inspecting each child's `name`/`required`/`label` props, and calls `store.create`/`store.update`. `fields`, `onSubmit`, `initialData`, `defaultValues`, `validationSchema`, and `columns` are all ignored in this mode.\n- **Fields mode** (anything else — including `useStore` *without* `children`, or `children` *without* `useStore`): a self-contained `react-hook-form` + optional Zod form driven by the `fields` array and `onSubmit`. `useStore`, `children`, `onBeforeSubmit`, `onAfterCreate`, and `getBreadcrumbName` are all ignored in this mode — `children` isn't even rendered.\n\n`CrudForm` unconditionally calls `useNavigate()`/`useParams()` (react-router) and `useBreadcrumb()`, so it must be rendered under a router and a `BreadcrumbProvider` regardless of which mode you use.\n\n> ⚠️ **Store-shape warning:** `CrudForm`'s store mode expects a store exposing `form.values`, `form.isSubmitting`, `create(data)`, `update(id, data)`, `resetForm()`, `setFormErrors(errorsObj)`, and one of `fetchAndPopulateForm(id)` / `fetchById(id)` / `fetchOne(id)`. **The `createCrudStore`/`createStore` factory shipped in this same package does not produce this shape** — it exposes `item`, `fetchOne`, `create`, `update`, `loading`, `submitting`, `error`, with no `form`, `resetForm`, `setFormErrors`, or `fetchAndPopulateForm`. If you're using `createCrudStore`, use **fields mode** instead (`fields` + `onSubmit`), or hand-write a store matching store mode's expected shape.\n\n### Props\n\n| Prop | Type | Default | Description |\n|------|------|---------|--------------|\n| `useStore` | `function` | - | Zustand store hook. Combined with `children` to trigger store mode. See store-shape warning above. |\n| `children` | `node` | - | Store mode only. Rendered as-is inside `<form>` — `CrudForm` does **not** clone children or inject `value`/`onChange`. Each field is a fully generic controlled component; you must wire `value`/`onChange` to the store yourself. `CrudForm` only recursively reads each descendant's `name`, `required`, and `label` props to run its own \"is empty\" required-field check — unrelated to `validationSchema`/Zod. If passed without `useStore` (or vice versa), it is silently dropped and fields mode renders instead. |\n| `fields` | `array` | `[]` | Fields mode only. Array of field descriptors: `{ name, type, label, placeholder, description, required, disabled, options, className, hidden, colSpan, render, ...rest }`. `type` is one of `text \\| email \\| password \\| number \\| url \\| tel \\| textarea \\| select \\| search-select \\| switch \\| section \\| custom` (unknown/omitted types fall back to a text `QInput`). `hidden` may be a boolean or `(allValues) => boolean`. `colSpan` is `1 \\| 2 \\| 3 \\| 4 \\| 'full'`. `type: 'section'` renders a divider using its own `title`/`description`/`icon`. `type: 'custom'` calls `field.render({ form, field, error, value })`. |\n| `defaultValues` | `object` | `{}` | Fields mode only. Initial `react-hook-form` values, used when `initialData` is not provided. |\n| `validationSchema` | Zod schema | - | Fields mode only. Passed to `zodResolver` for `react-hook-form` validation. No effect in store mode. |\n| `initialData` | `object` | `null` | Fields mode only. When present, seeds and re-syncs the form (`reset()`) — the fields-mode equivalent of \"edit\" data. Store mode instead fetches edit data itself via `fetchById`/`fetchAndPopulateForm`. |\n| `onSubmit` | `function(data)` | - | Fields mode only. Called with the `react-hook-form`-validated data. Thrown errors are caught and shown via a toast; there is **no** built-in success toast in fields mode (unlike store mode) — handle success yourself. |\n| `onCancel` | `function` | - | Store mode: called by the Cancel button (after `resetForm()`); if omitted, Cancel falls back to the back-navigation handler. Fields mode: the Cancel button is **only rendered if `onCancel` is truthy**, and clicking it calls `onCancel` directly with no fallback. |\n| `onBack` | `function` | - | Store mode: the back-arrow button (when `showBack` is true) always calls a `handleBack()` that uses `onBack` if given, else `navigate(listPath)`, else `navigate(-1)`. Fields mode: the back-arrow button is **only rendered if `showBack && onBack` are both truthy**, and calls `onBack` directly (no `listPath`/`navigate(-1)` fallback). |\n| `onBeforeSubmit` | `function(values) => values` | - | Store mode only. Called synchronously (not awaited) with the current `store.form.values` right before submit. **Its return value directly replaces the values passed to `create`/`update`** — there is no \"return `false` to cancel\" behavior; it must always return an object. |\n| `onAfterCreate` | `function(result, navigate)` | - | Store mode only, and only fires after `create` (never `update`), and only if `create()` resolved with a truthy result. If omitted (or the result is falsy), falls back to the back-navigation handler. No equivalent hook exists for the update/edit path. |\n| `title` | `string` | - | Store mode: form title, auto-prefixed as `` `Edit ${title}` `` or `` `Create ${title}` `` depending on edit-mode detection (see below), and used in the auto success toast (`\"{title} created/updated successfully\"`, default `\"Item\"` if omitted). Fields mode: rendered as-is (no Edit/Create prefix), and only shown at all if `showHeader` and (`title` or `description` or `showBack`) are truthy. |\n| `description` | `string` | - | Subtitle shown under the title, both modes. |\n| `submitLabel` | `string` | `\"Save\"` | Submit button text, both modes. Shows a spinner + \"Saving...\" while submitting. |\n| `cancelLabel` | `string` | `\"Cancel\"` | Cancel button text, both modes (subject to the `onCancel` visibility rule above). |\n| `columns` | `1 \\| 2 \\| 3 \\| 4` | `1` | Fields mode only. Grid column count for laying out `fields`. No effect in store mode. |\n| `showHeader` | `boolean` | `true` | Fields mode only. Gates whether the Card+header wrapper is used (vs. a plain `<div>`). No effect in store mode (its header is unconditional). |\n| `showFooter` | `boolean` | `true` | Shows/hides the Cancel/Submit button row, both modes. |\n| `showBack` | `boolean` | `true` | Shows the back-arrow icon button. See the asymmetric per-mode behavior under `onBack`. |\n| `showCard` | `boolean` | `true` | **Only honored in store mode** (wraps output in `Card` vs. a plain `<div>`). In fields mode, Card-vs-div is decided solely by `showHeader && (title \\|\\| description \\|\\| showBack)` — this prop is read but never checked there. |\n| `listPath` | `string` | - | Fallback destination for `handleBack()` when no `onBack` is given, in both modes. |\n| `icon` | `component` | - | **Only rendered in store mode when `showCard` is `false`.** Not used in the Card-wrapped store header, and not used anywhere in fields mode. |\n| `className` | `string` | - | Applied to the outer `Card`/`div` wrapper, both modes. |\n| `getBreadcrumbName` | `function(values)` | - | Store mode only, active only while editing (`uuid` route param present). Called with `store.form.values` once they look populated; its return value is registered via `useBreadcrumb().setBreadcrumbName(uuid, name)` and cleared on unmount. Requires an ancestor `BreadcrumbProvider`. |\n| `loading` | `boolean` | `false` | OR'd with the store's own `loading` (store mode). Disables fields and combines with `submitting` to disable Submit. |\n| `submitting` | `boolean` | `false` | OR'd with the store's own `form.isSubmitting` (store mode). Disables Cancel/Submit and swaps Submit's label/icon for a spinner + \"Saving...\". |\n\n> **Not implemented / dead props:** there is no `onSuccess` callback — store mode's success message is a hardcoded toast (`\"{title} created/updated successfully\"`); the closest customization hook is `onAfterCreate` (create only). `backLabel` is destructured but never rendered anywhere — it has no effect.\n\n**Edit-mode detection**: create-vs-edit is determined solely by `Boolean(useParams().uuid)` — `CrudForm` must be rendered on a route with a literal `:uuid` param (not `:id`, and not an `id` prop). This flag drives the title prefix, whether `fetchById`/`fetchAndPopulateForm`/`fetchOne` runs, and whether submit calls `store.update(uuid, values)` vs `store.create(values)`. Fields mode ignores this entirely — there, \"edit\" is just whatever `initialData` you pass in.\n\n### Usage\n\n**Store mode** (requires a hand-written store matching the shape described in the warning above), rendered on routes like `/users/new` and `/users/:uuid/edit`:\n\n```jsx\nimport { CrudForm, QInput } from '@bomjan133/react-crud-ui';\n\nfunction UserForm() {\n  return (\n    <CrudForm\n      title=\"User\"\n      useStore={useUserFormStore}\n      listPath=\"/users\"\n      getBreadcrumbName={(values) => values.name}\n      onBeforeSubmit={(values) => ({ ...values, email: values.email.trim().toLowerCase() })}\n      onAfterCreate={(result, navigate) => navigate(`/users/${result.uuid}/edit`)}\n    >\n      <QInput\n        name=\"name\"\n        label=\"Name\"\n        required\n        value={useUserFormStore((s) => s.form.values.name) ?? ''}\n        onChange={(val) => useUserFormStore.getState().setFormValue('name', val)}\n      />\n      <QInput\n        name=\"email\"\n        label=\"Email\"\n        required\n        value={useUserFormStore((s) => s.form.values.email) ?? ''}\n        onChange={(val) => useUserFormStore.getState().setFormValue('email', val)}\n      />\n    </CrudForm>\n  );\n}\n```\n\n**Fields mode** (self-contained `react-hook-form`, no store, no router param required — pass `initialData` for edit, omit it for create):\n\n```jsx\nimport { CrudForm } from '@bomjan133/react-crud-ui';\n\n<CrudForm\n  title=\"User\"\n  description=\"Basic account details\"\n  fields={[\n    { name: 'email', type: 'email', label: 'Email', required: true },\n    {\n      name: 'role',\n      type: 'select',\n      label: 'Role',\n      options: [\n        { value: 'admin', label: 'Admin' },\n        { value: 'member', label: 'Member' },\n      ],\n    },\n  ]}\n  initialData={editingUser} // omit for create mode\n  columns={2}\n  onSubmit={async (data) => {\n    await api.saveUser(data);\n    toast.success('Saved');\n  }}\n  onCancel={() => navigate('/users')}\n  onBack={() => navigate('/users')}\n/>\n```\n\n---\n\n## CrudDetail\n\nA detail-view component for a single record. It supports two distinct rendering modes, and can source its data either from a Zustand-style store hook (`useStore`) or directly via a `data` prop.\n\n**Mode selection is automatic and based on `children`:**\n- **Store + render-prop mode** — used only when *both* `useStore` is passed **and** `children` is a function. Renders whatever `children(data)` returns inside a plain header + content wrapper (no Card).\n- **Fields-based mode** — used in every other case (no `useStore`, or `useStore` without a function `children`, or `children` that isn't a function). Renders a `Card` with a field grid built from the `fields` array. **`children` is completely ignored in this mode.**\n\n`useStore` can also be used purely for fetching/deleting without triggering render-prop mode, as long as `children` isn't a function — data then comes from the store and renders via `fields`.\n\n> ⚠️ **`children` is a render-prop function, not a plain node**, and only takes effect when `us","readmeFilename":"README.md"}