{"_id":"@teispace/next-themes","_rev":"16-a4c800692bd6fed47d3ce21f52c15800","name":"@teispace/next-themes","dist-tags":{"latest":"3.0.2"},"versions":{"0.2.0":{"name":"@teispace/next-themes","version":"0.2.0","keywords":["next-themes","theme","dark-mode","nextjs","react","ssr","no-flash","color-scheme","view-transitions","typescript"],"author":{"name":"Teispace"},"license":"MIT","_id":"@teispace/next-themes@0.2.0","maintainers":[{"name":"iamkrishnaa","email":"krishna.forkhaki@gmail.com"}],"homepage":"https://github.com/teispace/npm-packages/tree/main/packages/next-themes#readme","bugs":{"url":"https://github.com/teispace/npm-packages/issues"},"dist":{"shasum":"08266fb6d3f6a23bd9adb8b264318b5b415422a2","tarball":"https://registry.npmjs.org/@teispace/next-themes/-/next-themes-0.2.0.tgz","fileCount":35,"integrity":"sha512-cKiDKLf49a3D7wl9q6SidBu+1HqTV5l5T4E9C4QyOzYB9mMQS7BhwxFITGpnfnllYX9+/vgUlYDGSzLBaednHQ==","signatures":[{"sig":"MEQCIEcOKiXR6vvsRVLKphXqrnXb1FshAP/NMKLWYVbggnu7AiBZYj1o69z1qPfc/H9RESCj2vcgiG+ekEkszBo3FW+8fw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":195301},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./client":{"types":"./dist/client.d.ts","import":"./dist/client.js"},"./script":{"types":"./dist/script.d.ts","import":"./dist/script.js"},"./server":{"types":"./dist/server.d.ts","import":"./dist/server.js"},"./adapters":{"types":"./dist/adapters.d.ts","import":"./dist/adapters.js"},"./tailwind":{"types":"./dist/tailwind.d.ts","import":"./dist/tailwind.js"},"./package.json":"./package.json","./tailwind.css":"./tailwind.css","./codemod/from-next-themes":"./codemod/from-next-themes.cjs"},"gitHead":"dbdf15036e7b57f42f8c925aa1a61fac792b16d1","scripts":{"dev":"tsup --watch","test":"vitest run","build":"tsup","clean":"rm -rf dist","test:cov":"vitest run --coverage","test:watch":"vitest","type-check":"tsc --noEmit","prepublishOnly":"yarn build"},"_npmUser":{"name":"iamkrishnaa","email":"krishna.forkhaki@gmail.com"},"repository":{"url":"git+https://github.com/teispace/npm-packages.git","type":"git","directory":"packages/next-themes"},"_npmVersion":"10.8.2","description":"Feature-rich, lightweight theme management for Next.js and React. Zero-flash SSR, hybrid storage, view transitions, typed themes.","directories":{},"sideEffects":false,"_nodeVersion":"20.20.2","_hasShrinkwrap":false,"devDependencies":{"next":"^16.2.4","tsup":"^8.5.1","jsdom":"^29.0.2","react":"^19.2.5","vitest":"^4.1.4","react-dom":"^19.2.5","typescript":"^6.0.2","@types/node":"^25.6.0","jscodeshift":"^17.3.0","@types/react":"^19.2.14","@types/react-dom":"^19.2.3","@types/jscodeshift":"^17.3.0","@testing-library/dom":"^10.4.1","@testing-library/react":"^16.3.2"},"peerDependencies":{"next":">=13.0.0","react":">=18.0.0","react-dom":">=18.0.0"},"peerDependenciesMeta":{"next":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/next-themes_0.2.0_1776929141089_0.3948139587031172","host":"s3://npm-registry-packages-npm-production"}},"0.2.1":{"name":"@teispace/next-themes","version":"0.2.1","keywords":["next-themes","theme","dark-mode","nextjs","react","ssr","no-flash","color-scheme","view-transitions","typescript"],"author":{"name":"Teispace"},"license":"MIT","_id":"@teispace/next-themes@0.2.1","maintainers":[{"name":"iamkrishnaa","email":"krishna.forkhaki@gmail.com"}],"homepage":"https://github.com/teispace/npm-packages/tree/main/packages/next-themes#readme","bugs":{"url":"https://github.com/teispace/npm-packages/issues"},"dist":{"shasum":"77e09385bdd45ca093870a5ba336040885d370a7","tarball":"https://registry.npmjs.org/@teispace/next-themes/-/next-themes-0.2.1.tgz","fileCount":35,"integrity":"sha512-1s3AYfGZw6sXS6fWPun9Jyzyc/EF3wr/v5y/6lLAU82JALgEi9BEHyBgTfxScu3S6BczlJ8XzvuGIzfWsFUm7g==","signatures":[{"sig":"MEYCIQDnIxAo9jjzErtItGviq2INhDXG+8cI+4KZmOsK6vK16gIhALhYp7PuJhBIEEQ4xjJHcYcHLWXpAuUzwm3vPqDTi5+j","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":195301},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./client":{"types":"./dist/client.d.ts","import":"./dist/client.js"},"./script":{"types":"./dist/script.d.ts","import":"./dist/script.js"},"./server":{"types":"./dist/server.d.ts","import":"./dist/server.js"},"./adapters":{"types":"./dist/adapters.d.ts","import":"./dist/adapters.js"},"./tailwind":{"types":"./dist/tailwind.d.ts","import":"./dist/tailwind.js"},"./package.json":"./package.json","./tailwind.css":"./tailwind.css","./codemod/from-next-themes":"./codemod/from-next-themes.cjs"},"gitHead":"954e459e4045f33a77305c691375b18de6da599e","scripts":{"dev":"tsup --watch","test":"vitest run","build":"tsup","clean":"rm -rf dist","test:cov":"vitest run --coverage","test:watch":"vitest","type-check":"tsc --noEmit","prepublishOnly":"yarn build"},"_npmUser":{"name":"iamkrishnaa","email":"krishna.forkhaki@gmail.com"},"repository":{"url":"git+https://github.com/teispace/npm-packages.git","type":"git","directory":"packages/next-themes"},"_npmVersion":"10.8.2","description":"Feature-rich, lightweight theme management for Next.js and React. Zero-flash SSR, hybrid storage, view transitions, typed themes.","directories":{},"sideEffects":false,"_nodeVersion":"20.20.2","_hasShrinkwrap":false,"devDependencies":{"next":"^16.2.4","tsup":"^8.5.1","jsdom":"^29.0.2","react":"^19.2.5","vitest":"^4.1.5","react-dom":"^19.2.5","typescript":"^6.0.3","@types/node":"^25.6.0","jscodeshift":"^17.3.0","@types/react":"^19.2.14","@types/react-dom":"^19.2.3","@types/jscodeshift":"^17.3.0","@testing-library/dom":"^10.4.1","@testing-library/react":"^16.3.2"},"peerDependencies":{"next":">=13.0.0","react":">=18.0.0","react-dom":">=18.0.0"},"peerDependenciesMeta":{"next":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/next-themes_0.2.1_1777210618574_0.8458764942428141","host":"s3://npm-registry-packages-npm-production"}},"0.3.2":{"name":"@teispace/next-themes","version":"0.3.2","keywords":["next-themes","theme","dark-mode","nextjs","react","ssr","no-flash","color-scheme","view-transitions","typescript"],"author":{"name":"Teispace"},"license":"MIT","_id":"@teispace/next-themes@0.3.2","maintainers":[{"name":"iamkrishnaa","email":"krishna.forkhaki@gmail.com"}],"homepage":"https://github.com/teispace/npm-packages/tree/main/packages/next-themes#readme","bugs":{"url":"https://github.com/teispace/npm-packages/issues"},"dist":{"shasum":"90a8c4e0077b681a3673927dad017c07edb7edb6","tarball":"https://registry.npmjs.org/@teispace/next-themes/-/next-themes-0.3.2.tgz","fileCount":35,"integrity":"sha512-x2rSAIwrQ6d6dJXqBSfLJOX7/Kg/lL4O82XpHlpu9S+HrwmEV/80mTYnHglddY6ZQgNfdzMXJSqVtOycsNwSww==","signatures":[{"sig":"MEYCIQDCmzdat2dQt2GIbfN5n4NKCWz461oDDtK3ekyXKHlnLAIhAJKkzB61g/+9eRsNazBlC1tdFZuk+StGqUiD47IusCGl","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":219171},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./client":{"types":"./dist/client.d.ts","import":"./dist/client.js"},"./script":{"types":"./dist/script.d.ts","import":"./dist/script.js"},"./server":{"types":"./dist/server.d.ts","import":"./dist/server.js"},"./adapters":{"types":"./dist/adapters.d.ts","import":"./dist/adapters.js"},"./tailwind":{"types":"./dist/tailwind.d.ts","import":"./dist/tailwind.js"},"./package.json":"./package.json","./tailwind.css":"./tailwind.css","./codemod/from-next-themes":"./codemod/from-next-themes.cjs"},"gitHead":"f38600d0b031de4bd716d2beae6c655b3f673588","scripts":{"dev":"tsup --watch","test":"vitest run","build":"tsup","clean":"rm -rf dist","test:cov":"vitest run --coverage","test:watch":"vitest","type-check":"tsc --noEmit","prepublishOnly":"yarn build"},"_npmUser":{"name":"iamkrishnaa","email":"krishna.forkhaki@gmail.com"},"repository":{"url":"git+https://github.com/teispace/npm-packages.git","type":"git","directory":"packages/next-themes"},"_npmVersion":"10.8.2","description":"Feature-rich, lightweight theme management for Next.js and React. Zero-flash SSR, hybrid storage, view transitions, typed themes.","directories":{},"sideEffects":false,"_nodeVersion":"20.20.2","_hasShrinkwrap":false,"devDependencies":{"next":"^16.2.4","tsup":"^8.5.1","jsdom":"^29.1.1","react":"^19.2.5","vitest":"^4.1.5","react-dom":"^19.2.5","typescript":"^6.0.3","@types/node":"^25.6.0","jscodeshift":"^17.3.0","@types/react":"^19.2.14","@types/react-dom":"^19.2.3","@types/jscodeshift":"^17.3.0","@testing-library/dom":"^10.4.1","@testing-library/react":"^16.3.2"},"peerDependencies":{"next":">=13.0.0","react":">=18.0.0","react-dom":">=18.0.0"},"peerDependenciesMeta":{"next":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/next-themes_0.3.2_1777696010078_0.29689043898787504","host":"s3://npm-registry-packages-npm-production"}},"0.4.1":{"name":"@teispace/next-themes","version":"0.4.1","keywords":["next-themes","theme","dark-mode","nextjs","react","ssr","no-flash","color-scheme","view-transitions","typescript"],"author":{"name":"Teispace"},"license":"MIT","_id":"@teispace/next-themes@0.4.1","maintainers":[{"name":"iamkrishnaa","email":"krishna.forkhaki@gmail.com"}],"homepage":"https://github.com/teispace/npm-packages/tree/main/packages/next-themes#readme","bugs":{"url":"https://github.com/teispace/npm-packages/issues"},"dist":{"shasum":"d234f1ef30879603ebfe209671d731461d083eeb","tarball":"https://registry.npmjs.org/@teispace/next-themes/-/next-themes-0.4.1.tgz","fileCount":35,"integrity":"sha512-zAOyaij/OeTarfzwZ0EXh/61cKRl3MfNV0+WDGOagcCUg3vxaSYumF7r/THqAGIUjEnOtU9ebYP84hXgkmLYtw==","signatures":[{"sig":"MEQCIH6LQ+gLNOVG1hOyjtc5ytEf4nLHCKAJzKDxHDyZsf/xAiAT4NaXE9ZDNoBDDZfi8wJt6Y9RZa8aEbVs7N2ai+Ku4A==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":222774},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./client":{"types":"./dist/client.d.ts","import":"./dist/client.js"},"./script":{"types":"./dist/script.d.ts","import":"./dist/script.js"},"./server":{"types":"./dist/server.d.ts","import":"./dist/server.js"},"./adapters":{"types":"./dist/adapters.d.ts","import":"./dist/adapters.js"},"./tailwind":{"types":"./dist/tailwind.d.ts","import":"./dist/tailwind.js"},"./package.json":"./package.json","./tailwind.css":"./tailwind.css","./codemod/from-next-themes":"./codemod/from-next-themes.cjs"},"gitHead":"4f518ee24c82fab2bae5e94f7d758583b390c309","scripts":{"dev":"tsup --watch","test":"vitest run","build":"tsup","clean":"rm -rf dist","test:cov":"vitest run --coverage","test:watch":"vitest","type-check":"tsc --noEmit","prepublishOnly":"yarn build"},"_npmUser":{"name":"iamkrishnaa","email":"krishna.forkhaki@gmail.com"},"repository":{"url":"git+https://github.com/teispace/npm-packages.git","type":"git","directory":"packages/next-themes"},"_npmVersion":"10.8.2","description":"Feature-rich, lightweight theme management for Next.js and React. Zero-flash SSR, hybrid storage, view transitions, typed themes.","directories":{},"sideEffects":false,"_nodeVersion":"20.20.2","_hasShrinkwrap":false,"devDependencies":{"next":"^16.2.4","tsup":"^8.5.1","jsdom":"^29.1.1","react":"^19.2.5","vitest":"^4.1.5","react-dom":"^19.2.5","typescript":"^6.0.3","@types/node":"^25.6.0","jscodeshift":"^17.3.0","@types/react":"^19.2.14","@types/react-dom":"^19.2.3","@types/jscodeshift":"^17.3.0","@testing-library/dom":"^10.4.1","@testing-library/react":"^16.3.2"},"peerDependencies":{"next":">=13.0.0","react":">=18.0.0","react-dom":">=18.0.0"},"peerDependenciesMeta":{"next":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/next-themes_0.4.1_1777819110229_0.0019376340769605704","host":"s3://npm-registry-packages-npm-production"}},"0.4.2":{"name":"@teispace/next-themes","version":"0.4.2","keywords":["next-themes","theme","dark-mode","nextjs","react","ssr","no-flash","color-scheme","view-transitions","typescript"],"author":{"name":"Teispace"},"license":"MIT","_id":"@teispace/next-themes@0.4.2","maintainers":[{"name":"iamkrishnaa","email":"krishna.forkhaki@gmail.com"}],"homepage":"https://github.com/teispace/npm-packages/tree/main/packages/next-themes#readme","bugs":{"url":"https://github.com/teispace/npm-packages/issues"},"dist":{"shasum":"4969c93a54379a828d95131f4c1eed4d564c4acb","tarball":"https://registry.npmjs.org/@teispace/next-themes/-/next-themes-0.4.2.tgz","fileCount":35,"integrity":"sha512-RXbdToPKFPryxwdVyzuDqYkrOs+vN51+CbP8zysyPPF1jIXi8B98P2WlBzf21yU8htHF9+Uk/nYiTpMsvRq/rg==","signatures":[{"sig":"MEYCIQDyuEuEYw1/59LD+zGO/VWnV89IolnqcjqedXMZn/PB7wIhAIwhdX4gy7C1PJa+KlSlcw4mH6kJplqLxITcTp9S7vUy","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":242340},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./client":{"types":"./dist/client.d.ts","import":"./dist/client.js"},"./script":{"types":"./dist/script.d.ts","import":"./dist/script.js"},"./server":{"types":"./dist/server.d.ts","import":"./dist/server.js"},"./adapters":{"types":"./dist/adapters.d.ts","import":"./dist/adapters.js"},"./tailwind":{"types":"./dist/tailwind.d.ts","import":"./dist/tailwind.js"},"./package.json":"./package.json","./tailwind.css":"./tailwind.css","./codemod/from-next-themes":"./codemod/from-next-themes.cjs"},"gitHead":"4d71a19a6bab54b42872ec4fb648660ccbafa222","scripts":{"dev":"tsup --watch","test":"vitest run","build":"tsup","clean":"rm -rf dist","test:cov":"vitest run --coverage","test:watch":"vitest","type-check":"tsc --noEmit","prepublishOnly":"yarn build"},"_npmUser":{"name":"iamkrishnaa","email":"krishna.forkhaki@gmail.com"},"repository":{"url":"git+https://github.com/teispace/npm-packages.git","type":"git","directory":"packages/next-themes"},"_npmVersion":"10.8.2","description":"Feature-rich, lightweight theme management for Next.js and React. Zero-flash SSR, hybrid storage, view transitions, typed themes.","directories":{},"sideEffects":false,"_nodeVersion":"20.20.2","_hasShrinkwrap":false,"devDependencies":{"next":"^16.2.4","tsup":"^8.5.1","jsdom":"^29.1.1","react":"^19.2.5","vitest":"^4.1.5","react-dom":"^19.2.5","typescript":"^6.0.3","@types/node":"^25.6.0","jscodeshift":"^17.3.0","@types/react":"^19.2.14","@types/react-dom":"^19.2.3","@types/jscodeshift":"^17.3.0","@testing-library/dom":"^10.4.1","@testing-library/react":"^16.3.2"},"peerDependencies":{"next":">=13.0.0","react":">=18.0.0","react-dom":">=18.0.0"},"peerDependenciesMeta":{"next":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/next-themes_0.4.2_1778079411234_0.755288415270734","host":"s3://npm-registry-packages-npm-production"}},"0.4.3":{"name":"@teispace/next-themes","version":"0.4.3","keywords":["next-themes","theme","dark-mode","nextjs","react","ssr","no-flash","color-scheme","view-transitions","typescript"],"author":{"name":"Teispace"},"license":"MIT","_id":"@teispace/next-themes@0.4.3","maintainers":[{"name":"iamkrishnaa","email":"krishna.forkhaki@gmail.com"}],"homepage":"https://github.com/teispace/npm-packages/tree/main/packages/next-themes#readme","bugs":{"url":"https://github.com/teispace/npm-packages/issues"},"dist":{"shasum":"ae550bf4c18efb894177dfe33b333d56fba073f4","tarball":"https://registry.npmjs.org/@teispace/next-themes/-/next-themes-0.4.3.tgz","fileCount":35,"integrity":"sha512-6394schxKnoDv/kt7jMk3BcGuOaxeFhzk4pkoU9NaI8c3jQwJtnnbK2TAZofRN7yWa25CnC86wCdGi8qGbVaZw==","signatures":[{"sig":"MEYCIQCkcvRvx2BONdl4H9eI/Eyu7ZM+X0AoQruYTC8GjHbh6AIhAPSOUFmS6JWyGXOraUdXbsqaRC7/HNM5s0X7E/Lq+bgM","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@teispace%2fnext-themes@0.4.3","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":242340},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./client":{"types":"./dist/client.d.ts","import":"./dist/client.js"},"./script":{"types":"./dist/script.d.ts","import":"./dist/script.js"},"./server":{"types":"./dist/server.d.ts","import":"./dist/server.js"},"./adapters":{"types":"./dist/adapters.d.ts","import":"./dist/adapters.js"},"./tailwind":{"types":"./dist/tailwind.d.ts","import":"./dist/tailwind.js"},"./package.json":"./package.json","./tailwind.css":"./tailwind.css","./codemod/from-next-themes":"./codemod/from-next-themes.cjs"},"gitHead":"a91f139f0cfe8ead607ee9bb5dec6b8c91a12ec4","scripts":{"dev":"tsup --watch","test":"vitest run","build":"tsup","clean":"rm -rf dist","test:cov":"vitest run --coverage","test:watch":"vitest","type-check":"tsc --noEmit","prepublishOnly":"yarn build"},"_npmUser":{"name":"iamkrishnaa","email":"krishna.forkhaki@gmail.com"},"repository":{"url":"git+https://github.com/teispace/npm-packages.git","type":"git","directory":"packages/next-themes"},"_npmVersion":"10.8.2","description":"Feature-rich, lightweight theme management for Next.js and React. Zero-flash SSR, hybrid storage, view transitions, typed themes.","directories":{},"sideEffects":false,"_nodeVersion":"20.20.2","_hasShrinkwrap":false,"devDependencies":{"next":"^16.2.6","tsup":"^8.5.1","jsdom":"^29.1.1","react":"^19.2.6","vitest":"^4.1.6","react-dom":"^19.2.6","typescript":"^6.0.3","@types/node":"^25.8.0","jscodeshift":"^17.3.0","@types/react":"^19.2.14","@types/react-dom":"^19.2.3","@types/jscodeshift":"^17.3.0","@testing-library/dom":"^10.4.1","@testing-library/react":"^16.3.2"},"peerDependencies":{"next":">=13.0.0","react":">=18.0.0","react-dom":">=18.0.0"},"peerDependenciesMeta":{"next":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/next-themes_0.4.3_1779099270677_0.7341036291739305","host":"s3://npm-registry-packages-npm-production"}},"0.5.0":{"name":"@teispace/next-themes","version":"0.5.0","keywords":["next-themes","theme","dark-mode","nextjs","react","ssr","no-flash","color-scheme","view-transitions","typescript"],"author":{"name":"Teispace"},"license":"MIT","_id":"@teispace/next-themes@0.5.0","maintainers":[{"name":"iamkrishnaa","email":"krishna.forkhaki@gmail.com"}],"homepage":"https://github.com/teispace/npm-packages/tree/main/packages/next-themes#readme","bugs":{"url":"https://github.com/teispace/npm-packages/issues"},"dist":{"shasum":"4994e868200ded8d253ba67cc6073385e150f9f2","tarball":"https://registry.npmjs.org/@teispace/next-themes/-/next-themes-0.5.0.tgz","fileCount":35,"integrity":"sha512-Y/wijExDhEGmEbL3r8cDdTRsamOHxkDPJG78pqDJEqT6u35tlazC0qrwUXcRHz59YXzjlvyfQSRCIbuo5dGUiA==","signatures":[{"sig":"MEQCICOcigrpUoxgmL6deCQFRrQ+7H4J6HIicWlghYbw98O4AiBSjW7iVNUxh5aSwbM4a177rh+1pHcMy2P/E83HRekSew==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@teispace%2fnext-themes@0.5.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":249901},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./client":{"types":"./dist/client.d.ts","import":"./dist/client.js"},"./script":{"types":"./dist/script.d.ts","import":"./dist/script.js"},"./server":{"types":"./dist/server.d.ts","import":"./dist/server.js"},"./adapters":{"types":"./dist/adapters.d.ts","import":"./dist/adapters.js"},"./tailwind":{"types":"./dist/tailwind.d.ts","import":"./dist/tailwind.js"},"./package.json":"./package.json","./tailwind.css":"./tailwind.css","./codemod/from-next-themes":"./codemod/from-next-themes.cjs"},"gitHead":"302789516600e86177c2a94408b0058abd47f545","scripts":{"dev":"tsup --watch","test":"vitest run","build":"tsup","clean":"rm -rf dist","test:cov":"vitest run --coverage","test:watch":"vitest","type-check":"tsc --noEmit","prepublishOnly":"yarn build"},"_npmUser":{"name":"iamkrishnaa","email":"krishna.forkhaki@gmail.com"},"repository":{"url":"git+https://github.com/teispace/npm-packages.git","type":"git","directory":"packages/next-themes"},"_npmVersion":"10.8.2","description":"Feature-rich, lightweight theme management for Next.js and React. Zero-flash SSR, hybrid storage, view transitions, typed themes.","directories":{},"sideEffects":false,"_nodeVersion":"20.20.2","_hasShrinkwrap":false,"devDependencies":{"next":"^16.2.6","tsup":"^8.5.1","jsdom":"^29.1.1","react":"^19.2.6","vitest":"^4.1.6","react-dom":"^19.2.6","typescript":"^6.0.3","@types/node":"^25.8.0","jscodeshift":"^17.3.0","@types/react":"^19.2.14","@types/react-dom":"^19.2.3","@types/jscodeshift":"^17.3.0","@testing-library/dom":"^10.4.1","@testing-library/react":"^16.3.2"},"peerDependencies":{"next":">=13.0.0","react":">=18.0.0","react-dom":">=18.0.0"},"peerDependenciesMeta":{"next":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/next-themes_0.5.0_1779100558928_0.5541522932236493","host":"s3://npm-registry-packages-npm-production"}},"1.0.0":{"name":"@teispace/next-themes","version":"1.0.0","keywords":["next-themes","theme","dark-mode","nextjs","react","ssr","no-flash","color-scheme","view-transitions","typescript"],"author":{"name":"Teispace"},"license":"MIT","_id":"@teispace/next-themes@1.0.0","maintainers":[{"name":"iamkrishnaa","email":"krishna.forkhaki@gmail.com"}],"homepage":"https://github.com/teispace/npm-packages/tree/main/packages/next-themes#readme","bugs":{"url":"https://github.com/teispace/npm-packages/issues"},"dist":{"shasum":"b759e7f964d748a567daca07e23d182befde6460","tarball":"https://registry.npmjs.org/@teispace/next-themes/-/next-themes-1.0.0.tgz","fileCount":35,"integrity":"sha512-8oVHrh2uclbnVyXMqzupzGJFcnjbfOlXJtGMFjlwdatnsjxe/XeqXTaFQ3SUc8ked/xMy1KE+P9ycb0Sjj9Hjw==","signatures":[{"sig":"MEUCIQD5ZIc328o0iZpvBJGLRvMZ0LpY7ofAG6LxQ326x43oMQIgObinwe3G7H7KkILKfELClvqrY2Jw1joPw9zH4krM71c=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@teispace%2fnext-themes@1.0.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":249901},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./client":{"types":"./dist/client.d.ts","import":"./dist/client.js"},"./script":{"types":"./dist/script.d.ts","import":"./dist/script.js"},"./server":{"types":"./dist/server.d.ts","import":"./dist/server.js"},"./adapters":{"types":"./dist/adapters.d.ts","import":"./dist/adapters.js"},"./tailwind":{"types":"./dist/tailwind.d.ts","import":"./dist/tailwind.js"},"./package.json":"./package.json","./tailwind.css":"./tailwind.css","./codemod/from-next-themes":"./codemod/from-next-themes.cjs"},"gitHead":"f464ba6b2409337f002f95ea4fb26ff2d0802df3","scripts":{"dev":"tsup --watch","test":"vitest run","build":"tsup","clean":"rm -rf dist","test:cov":"vitest run --coverage","test:watch":"vitest","type-check":"tsc --noEmit","prepublishOnly":"yarn build"},"_npmUser":{"name":"iamkrishnaa","email":"krishna.forkhaki@gmail.com"},"repository":{"url":"git+https://github.com/teispace/npm-packages.git","type":"git","directory":"packages/next-themes"},"_npmVersion":"10.8.2","description":"Feature-rich, lightweight theme management for Next.js and React. Zero-flash SSR, hybrid storage, view transitions, typed themes.","directories":{},"sideEffects":false,"_nodeVersion":"20.20.2","_hasShrinkwrap":false,"devDependencies":{"next":"^16.2.6","tsup":"^8.5.1","jsdom":"^29.1.1","react":"^19.2.6","vitest":"^4.1.7","react-dom":"^19.2.6","typescript":"^6.0.3","@types/node":"^25.9.1","jscodeshift":"^17.3.0","@types/react":"^19.2.15","@types/react-dom":"^19.2.3","@types/jscodeshift":"^17.3.0","@testing-library/dom":"^10.4.1","@testing-library/react":"^16.3.2"},"peerDependencies":{"next":">=13.0.0","react":">=18.0.0","react-dom":">=18.0.0"},"peerDependenciesMeta":{"next":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/next-themes_1.0.0_1780201406781_0.5372265576360942","host":"s3://npm-registry-packages-npm-production"}},"2.0.0":{"name":"@teispace/next-themes","version":"2.0.0","keywords":["next-themes","theme","dark-mode","nextjs","react","ssr","no-flash","color-scheme","view-transitions","typescript"],"author":{"name":"Teispace"},"license":"MIT","_id":"@teispace/next-themes@2.0.0","maintainers":[{"name":"iamkrishnaa","email":"krishna.forkhaki@gmail.com"}],"homepage":"https://github.com/teispace/npm-packages/tree/main/packages/next-themes#readme","bugs":{"url":"https://github.com/teispace/npm-packages/issues"},"dist":{"shasum":"b069eed241143a62f06122fba7c37029b87f9c1e","tarball":"https://registry.npmjs.org/@teispace/next-themes/-/next-themes-2.0.0.tgz","fileCount":35,"integrity":"sha512-5SWvz6zJESzcaeG9NnshoGe1Mn6hRwE2V+3vejcjPywngOX0e4ZhkighB17jNcA86DV7RMIPbIm0lVTz15fwaA==","signatures":[{"sig":"MEUCIDWfeok5NLrvlT/MlbXdVfn5wkI2eo9aX7XsCRWYaX2XAiEAiWJKOE+F/CfjfpwBxVaSuaWDhIo1R8Ii7XQFNVsav9g=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@teispace%2fnext-themes@2.0.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":267147},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./client":{"types":"./dist/client.d.ts","import":"./dist/client.js"},"./script":{"types":"./dist/script.d.ts","import":"./dist/script.js"},"./server":{"types":"./dist/server.d.ts","import":"./dist/server.js"},"./adapters":{"types":"./dist/adapters.d.ts","import":"./dist/adapters.js"},"./tailwind":{"types":"./dist/tailwind.d.ts","import":"./dist/tailwind.js"},"./package.json":"./package.json","./tailwind.css":"./tailwind.css","./codemod/from-next-themes":"./codemod/from-next-themes.cjs"},"gitHead":"d88f33cd346fad1d8f4b90c74fd8a9707860455a","scripts":{"dev":"tsup --watch","test":"vitest run","build":"tsup","clean":"rm -rf dist","test:cov":"vitest run --coverage","test:watch":"vitest","type-check":"tsc --noEmit","prepublishOnly":"yarn build"},"_npmUser":{"name":"iamkrishnaa","email":"krishna.forkhaki@gmail.com"},"repository":{"url":"git+https://github.com/teispace/npm-packages.git","type":"git","directory":"packages/next-themes"},"_npmVersion":"10.8.2","description":"Feature-rich, lightweight theme management for Next.js and React. Zero-flash SSR, hybrid storage, view transitions, typed themes.","directories":{},"sideEffects":false,"_nodeVersion":"20.20.2","_hasShrinkwrap":false,"devDependencies":{"next":"^16.2.6","tsup":"^8.5.1","jsdom":"^29.1.1","react":"^19.2.6","vitest":"^4.1.7","react-dom":"^19.2.6","typescript":"^6.0.3","@types/node":"^25.9.1","jscodeshift":"^17.3.0","@types/react":"^19.2.15","@types/react-dom":"^19.2.3","@types/jscodeshift":"^17.3.0","@testing-library/dom":"^10.4.1","@testing-library/react":"^16.3.2"},"peerDependencies":{"next":">=13.0.0","react":">=18.0.0","react-dom":">=18.0.0"},"peerDependenciesMeta":{"next":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/next-themes_2.0.0_1780208827048_0.0897771270718064","host":"s3://npm-registry-packages-npm-production"}},"2.0.1":{"name":"@teispace/next-themes","version":"2.0.1","keywords":["next-themes","theme","dark-mode","nextjs","react","ssr","no-flash","color-scheme","view-transitions","typescript"],"author":{"name":"Teispace"},"license":"MIT","_id":"@teispace/next-themes@2.0.1","maintainers":[{"name":"iamkrishnaa","email":"krishna.forkhaki@gmail.com"}],"homepage":"https://github.com/teispace/npm-packages/tree/main/packages/next-themes#readme","bugs":{"url":"https://github.com/teispace/npm-packages/issues"},"dist":{"shasum":"3861ff7b044a8607982c7ab6ad9d14e2cbb707ee","tarball":"https://registry.npmjs.org/@teispace/next-themes/-/next-themes-2.0.1.tgz","fileCount":25,"integrity":"sha512-1+5+QTv9lHpG7n6PYHvKoucHNm+nhImYxGFw52MgyBGjQVC27pKlXLRuusJzaKUGvdfdwPLoZiKVkDIJk7T6Sw==","signatures":[{"sig":"MEUCICShlASfRA5j8rYsoqUT0LVDf7UJLAiYwfzPWvm2RnxcAiEA5FGrhvLvsfdt1qOZi5wBZlqppZ5tizRZK20NbmZvcCQ=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@teispace%2fnext-themes@2.0.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":106895},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./client":{"types":"./dist/client.d.ts","import":"./dist/client.js"},"./script":{"types":"./dist/script.d.ts","import":"./dist/script.js"},"./server":{"types":"./dist/server.d.ts","import":"./dist/server.js"},"./adapters":{"types":"./dist/adapters.d.ts","import":"./dist/adapters.js"},"./tailwind":{"types":"./dist/tailwind.d.ts","import":"./dist/tailwind.js"},"./package.json":"./package.json","./tailwind.css":"./tailwind.css","./codemod/from-next-themes":"./codemod/from-next-themes.cjs"},"gitHead":"e17139a4dc66b4ee21a6439ad9557fdd391cd8d1","scripts":{"dev":"tsup --watch","test":"vitest run","build":"tsup","clean":"rm -rf dist","test:cov":"vitest run --coverage","test:watch":"vitest","type-check":"tsc --noEmit","prepublishOnly":"yarn build"},"_npmUser":{"name":"iamkrishnaa","email":"krishna.forkhaki@gmail.com"},"repository":{"url":"git+https://github.com/teispace/npm-packages.git","type":"git","directory":"packages/next-themes"},"_npmVersion":"10.8.2","description":"Feature-rich, lightweight theme management for Next.js and React. Zero-flash SSR, hybrid storage, view transitions, typed themes.","directories":{},"sideEffects":false,"_nodeVersion":"20.20.2","_hasShrinkwrap":false,"devDependencies":{"next":"^16.2.6","tsup":"^8.5.1","jsdom":"^29.1.1","react":"^19.2.6","vitest":"^4.1.7","react-dom":"^19.2.6","typescript":"^6.0.3","@types/node":"^25.9.1","jscodeshift":"^17.3.0","@types/react":"^19.2.15","@types/react-dom":"^19.2.3","@types/jscodeshift":"^17.3.0","@testing-library/dom":"^10.4.1","@testing-library/react":"^16.3.2"},"peerDependencies":{"next":">=13.0.0","react":">=18.0.0","react-dom":">=18.0.0"},"peerDependenciesMeta":{"next":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/next-themes_2.0.1_1780213756424_0.11353181415389413","host":"s3://npm-registry-packages-npm-production"}},"2.0.2":{"name":"@teispace/next-themes","version":"2.0.2","keywords":["next-themes","theme","dark-mode","nextjs","react","ssr","no-flash","color-scheme","view-transitions","typescript"],"author":{"name":"Teispace"},"license":"MIT","_id":"@teispace/next-themes@2.0.2","maintainers":[{"name":"iamkrishnaa","email":"krishna.forkhaki@gmail.com"}],"homepage":"https://github.com/teispace/npm-packages/tree/main/packages/next-themes#readme","bugs":{"url":"https://github.com/teispace/npm-packages/issues"},"dist":{"shasum":"d1984744aca9ebf403f961d8b934d42de7b60e3c","tarball":"https://registry.npmjs.org/@teispace/next-themes/-/next-themes-2.0.2.tgz","fileCount":25,"integrity":"sha512-J7gxRIsQFrbg1VCykzpRJFJboXOviaiTx/ZHnXU5xa6MIQsYJDZJdKEsY8v8UPLFGgXYhU2UK4yob9MkNmL7uw==","signatures":[{"sig":"MEUCIQC8hGDooWIAbrncJQUEdEAXnt4R6VoejtVCPRzLcJaaJAIgRKeMHRUUFIjWad7N2ttgARasvOHyHGuchcCiR6n83d0=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@teispace%2fnext-themes@2.0.2","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":106895},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./client":{"types":"./dist/client.d.ts","import":"./dist/client.js"},"./script":{"types":"./dist/script.d.ts","import":"./dist/script.js"},"./server":{"types":"./dist/server.d.ts","import":"./dist/server.js"},"./adapters":{"types":"./dist/adapters.d.ts","import":"./dist/adapters.js"},"./tailwind":{"types":"./dist/tailwind.d.ts","import":"./dist/tailwind.js"},"./package.json":"./package.json","./tailwind.css":"./tailwind.css","./codemod/from-next-themes":"./codemod/from-next-themes.cjs"},"gitHead":"506750b2efe4530e1b8d26674b8ba285cad73f52","scripts":{"dev":"tsup --watch","test":"vitest run","build":"tsup","clean":"rm -rf dist","test:cov":"vitest run --coverage","test:watch":"vitest","type-check":"tsc --noEmit","prepublishOnly":"yarn build"},"_npmUser":{"name":"iamkrishnaa","email":"krishna.forkhaki@gmail.com"},"repository":{"url":"git+https://github.com/teispace/npm-packages.git","type":"git","directory":"packages/next-themes"},"_npmVersion":"10.8.2","description":"Feature-rich, lightweight theme management for Next.js and React. Zero-flash SSR, hybrid storage, view transitions, typed themes.","directories":{},"sideEffects":false,"_nodeVersion":"20.20.2","_hasShrinkwrap":false,"devDependencies":{"next":"^16.2.7","tsup":"^8.5.1","jsdom":"^29.1.1","react":"^19.2.7","vitest":"^4.1.8","react-dom":"^19.2.7","typescript":"^6.0.3","@types/node":"^25.9.2","jscodeshift":"^17.3.0","@types/react":"^19.2.17","@types/react-dom":"^19.2.3","@types/jscodeshift":"^17.3.0","@testing-library/dom":"^10.4.1","@testing-library/react":"^16.3.2"},"peerDependencies":{"next":">=13.0.0","react":">=18.0.0","react-dom":">=18.0.0"},"peerDependenciesMeta":{"next":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/next-themes_2.0.2_1780851342208_0.34901844931062764","host":"s3://npm-registry-packages-npm-production"}},"2.0.3":{"name":"@teispace/next-themes","version":"2.0.3","keywords":["next-themes","theme","dark-mode","nextjs","react","ssr","no-flash","color-scheme","view-transitions","typescript"],"author":{"name":"Teispace"},"license":"MIT","_id":"@teispace/next-themes@2.0.3","maintainers":[{"name":"iamkrishnaa","email":"krishna.forkhaki@gmail.com"}],"homepage":"https://github.com/teispace/npm-packages/tree/main/packages/next-themes#readme","bugs":{"url":"https://github.com/teispace/npm-packages/issues"},"dist":{"shasum":"832382001ee227f48e41218b0e5f754a4197ce99","tarball":"https://registry.npmjs.org/@teispace/next-themes/-/next-themes-2.0.3.tgz","fileCount":25,"integrity":"sha512-3sQv1bGzrQX03Y6e9PR3VVaXDIYG7T4fM1YZ/Fivomg2lQD52d5GX2kWhTqhxKIt4bNA3Bmp+RBELyOvgjz7Ig==","signatures":[{"sig":"MEQCIHVjoHt1YIRB6a74CoZCVbHjMA1HhQpdxpQUsXgqKmVUAiBpnvn+PEYE7txCd01syY4XYBcZb4uzCnhNE9BDaSeEVg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@teispace%2fnext-themes@2.0.3","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":107023},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","engines":{"node":">=24.0.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./client":{"types":"./dist/client.d.ts","import":"./dist/client.js"},"./script":{"types":"./dist/script.d.ts","import":"./dist/script.js"},"./server":{"types":"./dist/server.d.ts","import":"./dist/server.js"},"./adapters":{"types":"./dist/adapters.d.ts","import":"./dist/adapters.js"},"./tailwind":{"types":"./dist/tailwind.d.ts","import":"./dist/tailwind.js"},"./package.json":"./package.json","./tailwind.css":"./tailwind.css","./codemod/from-next-themes":"./codemod/from-next-themes.cjs"},"gitHead":"b83c5a740c63e3c8a789e13912f8e3b96d5f5297","scripts":{"dev":"tsup --watch","test":"vitest run","build":"tsup","clean":"rm -rf dist","test:cov":"vitest run --coverage","test:watch":"vitest","type-check":"tsc --noEmit","prepublishOnly":"yarn clean && yarn build"},"_npmUser":{"name":"iamkrishnaa","email":"krishna.forkhaki@gmail.com"},"repository":{"url":"git+https://github.com/teispace/npm-packages.git","type":"git","directory":"packages/next-themes"},"_npmVersion":"11.13.0","description":"Feature-rich, lightweight theme management for Next.js and React. Zero-flash SSR, hybrid storage, view transitions, typed themes.","directories":{},"sideEffects":false,"_nodeVersion":"24.16.0","_hasShrinkwrap":false,"devDependencies":{"next":"^16.2.7","tsup":"^8.5.1","jsdom":"^29.1.1","react":"^19.2.7","vitest":"^4.1.9","react-dom":"^19.2.7","typescript":"^6.0.3","@types/node":"^26.0.0","jscodeshift":"^17.3.0","@types/react":"^19.2.17","@types/react-dom":"^19.2.3","@types/jscodeshift":"^17.3.0","@testing-library/dom":"^10.4.1","@testing-library/react":"^16.3.2"},"peerDependencies":{"next":">=13.0.0","react":">=18.0.0","react-dom":">=18.0.0"},"peerDependenciesMeta":{"next":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/next-themes_2.0.3_1781960393843_0.08341056557378068","host":"s3://npm-registry-packages-npm-production"}},"2.0.4":{"name":"@teispace/next-themes","version":"2.0.4","keywords":["next-themes","theme","dark-mode","nextjs","react","ssr","no-flash","color-scheme","view-transitions","typescript"],"author":{"name":"Teispace"},"license":"MIT","_id":"@teispace/next-themes@2.0.4","maintainers":[{"name":"iamkrishnaa","email":"krishna.forkhaki@gmail.com"}],"homepage":"https://github.com/teispace/npm-packages/tree/main/packages/next-themes#readme","bugs":{"url":"https://github.com/teispace/npm-packages/issues"},"dist":{"shasum":"8278fad6a02171c4308dbc3dae47391ab4b58157","tarball":"https://registry.npmjs.org/@teispace/next-themes/-/next-themes-2.0.4.tgz","fileCount":25,"integrity":"sha512-Vyu1b4oARmGf6/WC83nqyrfX7ZrYWRueY55DakwkXhizgXDgOOIo0lCroNvbLpR+TxN1dquoZ2DnHN2PifsRnQ==","signatures":[{"sig":"MEUCIQC+7LFlarg5yefWmu2P0IyHmLxaQlWHzODfqlPaZ/oqZQIgLeYCcpnlq6fByHL11xnWdveG1Q20W+NUslrD5uAc/2Y=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@teispace%2fnext-themes@2.0.4","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":107023},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","engines":{"node":">=24.0.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./client":{"types":"./dist/client.d.ts","import":"./dist/client.js"},"./script":{"types":"./dist/script.d.ts","import":"./dist/script.js"},"./server":{"types":"./dist/server.d.ts","import":"./dist/server.js"},"./adapters":{"types":"./dist/adapters.d.ts","import":"./dist/adapters.js"},"./tailwind":{"types":"./dist/tailwind.d.ts","import":"./dist/tailwind.js"},"./package.json":"./package.json","./tailwind.css":"./tailwind.css","./codemod/from-next-themes":"./codemod/from-next-themes.cjs"},"gitHead":"712e50058d8c113ec1f1d0bef752a18252cf9e00","scripts":{"dev":"tsup --watch","test":"vitest run","build":"tsup","clean":"rm -rf dist","test:cov":"vitest run --coverage","test:watch":"vitest","type-check":"tsc --noEmit","prepublishOnly":"yarn clean && yarn build"},"_npmUser":{"name":"iamkrishnaa","email":"krishna.forkhaki@gmail.com"},"repository":{"url":"git+https://github.com/teispace/npm-packages.git","type":"git","directory":"packages/next-themes"},"_npmVersion":"11.13.0","description":"Feature-rich, lightweight theme management for Next.js and React. Zero-flash SSR, hybrid storage, view transitions, typed themes.","directories":{},"sideEffects":false,"_nodeVersion":"24.17.0","_hasShrinkwrap":false,"devDependencies":{"next":"^16.2.9","tsup":"^8.5.1","jsdom":"^29.1.1","react":"^19.2.7","vitest":"^4.1.9","react-dom":"^19.2.7","typescript":"^6.0.3","@types/node":"^26.0.1","jscodeshift":"^17.3.0","@types/react":"^19.2.17","@types/react-dom":"^19.2.3","@types/jscodeshift":"^17.3.0","@testing-library/dom":"^10.4.1","@testing-library/react":"^16.3.2"},"peerDependencies":{"next":">=13.0.0","react":">=18.0.0","react-dom":">=18.0.0"},"peerDependenciesMeta":{"next":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/next-themes_2.0.4_1782638681981_0.5451787401822272","host":"s3://npm-registry-packages-npm-production"}},"3.0.0":{"name":"@teispace/next-themes","version":"3.0.0","keywords":["next-themes","theme","dark-mode","nextjs","react","ssr","no-flash","color-scheme","view-transitions","typescript"],"author":{"name":"Teispace"},"license":"MIT","_id":"@teispace/next-themes@3.0.0","maintainers":[{"name":"iamkrishnaa","email":"krishna.forkhaki@gmail.com"}],"homepage":"https://github.com/teispace/npm-packages/tree/main/packages/next-themes#readme","bugs":{"url":"https://github.com/teispace/npm-packages/issues"},"dist":{"shasum":"e8f6b0dad93db02f5f6d0004e3db91ec4cb2231f","tarball":"https://registry.npmjs.org/@teispace/next-themes/-/next-themes-3.0.0.tgz","fileCount":49,"integrity":"sha512-YCrfq5wWvy7NfuQhdLjg6oKYWSF12FsfvnqeNIexGUMmte6XDchjwiJM7IGsRSxoeq8qye0d0lYFHyIj4sV9Og==","signatures":[{"sig":"MEYCIQCMDvM1ZJjdvTxKUZMVyp5jcbcdCN4HM87uHmTGuCA2RwIhALOssVFJKOFupHjGPUYnAoqMHeC99Ge0EO+w3BkibAbI","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEYCIQCqAqJc0lbvDga1ZGASxbWrplGCcdwRhDBGFfLzkLfHNwIhAIFhM3cY9JkZnGMbS56p23VFSalsfSlIuWpEcchhF1uw","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@teispace%2fnext-themes@3.0.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":132104},"type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","engines":{"node":">=20.9.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./client":{"types":"./dist/client.d.ts","import":"./dist/client.js"},"./script":{"types":"./dist/script.d.ts","import":"./dist/script.js"},"./server":{"types":"./dist/server.d.ts","import":"./dist/server.js"},"./adapters":{"types":"./dist/adapters.d.ts","import":"./dist/adapters.js"},"./tailwind":{"types":"./dist/tailwind.d.ts","import":"./dist/tailwind.js"},"./package.json":"./package.json","./tailwind.css":"./tailwind.css","./hooks/use-theme":{"types":"./dist/hooks/use-theme.d.ts","import":"./dist/hooks/use-theme.js"},"./hooks/use-hydrated":{"types":"./dist/hooks/use-hydrated.d.ts","import":"./dist/hooks/use-hydrated.js"},"./hooks/use-theme-value":{"types":"./dist/hooks/use-theme-value.d.ts","import":"./dist/hooks/use-theme-value.js"},"./components/themed-icon":{"types":"./dist/components/themed-icon.d.ts","import":"./dist/components/themed-icon.js"},"./hooks/use-theme-effect":{"types":"./dist/hooks/use-theme-effect.d.ts","import":"./dist/hooks/use-theme-effect.js"},"./components/scoped-theme":{"types":"./dist/components/scoped-theme.d.ts","import":"./dist/components/scoped-theme.js"},"./components/themed-image":{"types":"./dist/components/themed-image.d.ts","import":"./dist/components/themed-image.js"},"./codemod/from-next-themes":"./codemod/from-next-themes.cjs"},"gitHead":"1c946d7156e5034a52aabea99531cf811ba90e53","scripts":{"dev":"tsup --watch","test":"vitest run","build":"tsup","clean":"rm -rf dist","test:cov":"vitest run --coverage","test:watch":"vitest","type-check":"tsc --noEmit","prepublishOnly":"yarn clean && yarn build"},"_npmUser":{"name":"iamkrishnaa","email":"krishna.forkhaki@gmail.com"},"repository":{"url":"git+https://github.com/teispace/npm-packages.git","type":"git","directory":"packages/next-themes"},"_npmVersion":"11.17.0","description":"Feature-rich, lightweight theme management for Next.js and React. Zero-flash SSR, hybrid storage, view transitions, typed themes.","directories":{},"sideEffects":["*.css"],"_nodeVersion":"24.19.0","_hasShrinkwrap":false,"devDependencies":{"next":"^16.3.2","tsup":"^8.5.1","jsdom":"^30.0.1","react":"^19.2.8","vitest":"^4.1.11","react-dom":"^19.2.8","typescript":"^6.0.3","@types/node":"^26.2.0","jscodeshift":"^17.4.0","@types/react":"^19.2.18","@types/react-dom":"^19.2.4","@types/jscodeshift":"^17.3.0","@testing-library/dom":"^10.4.1","@testing-library/react":"^16.3.2"},"peerDependencies":{"next":">=13.0.0","react":">=18.0.0","react-dom":">=18.0.0"},"peerDependenciesMeta":{"next":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/next-themes_3.0.0_1787331128588_0.09653076084184997","host":"s3://npm-registry-packages-npm-production"}},"3.0.1":{"name":"@teispace/next-themes","version":"3.0.1","keywords":["next-themes","theme","dark-mode","nextjs","react","ssr","no-flash","color-scheme","view-transitions","typescript"],"author":{"name":"Teispace"},"license":"MIT","_id":"@teispace/next-themes@3.0.1","maintainers":[{"name":"iamkrishnaa","email":"krishna.forkhaki@gmail.com"}],"homepage":"https://github.com/teispace/npm-packages/tree/main/packages/next-themes#readme","bugs":{"url":"https://github.com/teispace/npm-packages/issues"},"dist":{"shasum":"4a6c76d2be03ace6f4ca5864ea050214c79326a4","tarball":"https://registry.npmjs.org/@teispace/next-themes/-/next-themes-3.0.1.tgz","fileCount":49,"integrity":"sha512-dtwTcNcWREJx7w8R3/9OYy3ZwFmxPQSQV63fuBogKmLqYbkTWECgwycVpLXEPmRaaO5vUxjnWN41ZokE/7yUOg==","signatures":[{"sig":"MEUCIQD1w8yX3+RwY6CDi6Au+tRR7zlgObxJsjvIz209yyx8lwIgXudO5soKY33nC3PBV5LsToPxjpBOdVLsCnAiGvnQrgA=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEYCIQCICsinXvB8eQ+zhnjbf55x33cGB5mLMiJWpraVUvLvtAIhALkfMYjKfCsjnD8rJU7xT7U8eobyU8gNELezFnlb9ZYX","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@teispace%2fnext-themes@3.0.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":132326},"type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","engines":{"node":">=20.9.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./client":{"types":"./dist/client.d.ts","import":"./dist/client.js"},"./script":{"types":"./dist/script.d.ts","import":"./dist/script.js"},"./server":{"types":"./dist/server.d.ts","import":"./dist/server.js"},"./adapters":{"types":"./dist/adapters.d.ts","import":"./dist/adapters.js"},"./tailwind":{"types":"./dist/tailwind.d.ts","import":"./dist/tailwind.js"},"./package.json":"./package.json","./tailwind.css":"./tailwind.css","./hooks/use-theme":{"types":"./dist/hooks/use-theme.d.ts","import":"./dist/hooks/use-theme.js"},"./hooks/use-hydrated":{"types":"./dist/hooks/use-hydrated.d.ts","import":"./dist/hooks/use-hydrated.js"},"./hooks/use-theme-value":{"types":"./dist/hooks/use-theme-value.d.ts","import":"./dist/hooks/use-theme-value.js"},"./components/themed-icon":{"types":"./dist/components/themed-icon.d.ts","import":"./dist/components/themed-icon.js"},"./hooks/use-theme-effect":{"types":"./dist/hooks/use-theme-effect.d.ts","import":"./dist/hooks/use-theme-effect.js"},"./components/scoped-theme":{"types":"./dist/components/scoped-theme.d.ts","import":"./dist/components/scoped-theme.js"},"./components/themed-image":{"types":"./dist/components/themed-image.d.ts","import":"./dist/components/themed-image.js"},"./codemod/from-next-themes":"./codemod/from-next-themes.cjs"},"gitHead":"e655a553558823d7bf8ef512cf7db1d544bb5dae","scripts":{"dev":"tsup --watch","test":"vitest run","build":"tsup","clean":"rm -rf dist","test:cov":"vitest run --coverage","test:watch":"vitest","type-check":"tsc --noEmit","prepublishOnly":"yarn clean && yarn build"},"_npmUser":{"name":"iamkrishnaa","email":"krishna.forkhaki@gmail.com"},"repository":{"url":"git+https://github.com/teispace/npm-packages.git","type":"git","directory":"packages/next-themes"},"_npmVersion":"11.19.0","description":"Feature-rich, lightweight theme management for Next.js and React. Zero-flash SSR, hybrid storage, view transitions, typed themes.","directories":{},"sideEffects":["*.css"],"_nodeVersion":"24.20.0","_hasShrinkwrap":false,"devDependencies":{"next":"^16.3.2","tsup":"^8.5.1","jsdom":"^30.0.1","react":"^19.2.8","vitest":"^4.1.11","react-dom":"^19.2.8","typescript":"^6.0.3","@types/node":"^26.2.0","jscodeshift":"^17.4.0","@types/react":"^19.2.18","@types/react-dom":"^19.2.4","@types/jscodeshift":"^17.3.0","@testing-library/dom":"^10.4.1","@testing-library/react":"^16.3.2"},"peerDependencies":{"next":">=13.0.0","react":">=18.0.0","react-dom":">=18.0.0"},"peerDependenciesMeta":{"next":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/next-themes_3.0.1_1788623356225_0.858680944873393","host":"s3://npm-registry-packages-npm-production"}},"3.0.2":{"_id":"@teispace/next-themes@3.0.2","bugs":{"url":"https://github.com/teispace/npm-packages/issues"},"dist":{"shasum":"25d2a7d1df3a5835a418f242f61f38c2a608d3a7","tarball":"https://registry.npmjs.org/@teispace/next-themes/-/next-themes-3.0.2.tgz","fileCount":49,"integrity":"sha512-60ha/eiWuW+DVI9fkUAFK6tTrnwAvviTrHp7h7ivQMYnQrwi/HDDbXgV3HK8HqMoyW6JxyxrKryG6l1X4uh74w==","signatures":[{"sig":"MEQCIG45celv2PEllT8yXVBZrrfPlXqWdSTZAfBp+JVMPel/AiBqwhMAlNbASTZUy0Hs3gsEs3+mx83PAJ+EXUqItg2hiw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQC8KE10C559AAWc0zejpr0J2Sc9+beJEYZi3/FULQ8SfAIhAM6//5LHFog7BPilQqmdousMo0A1IsXQ+k6Bqw0ZbDbb"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@teispace%2fnext-themes@3.0.2","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":132348},"name":"@teispace/next-themes","type":"module","types":"./dist/index.d.ts","author":{"name":"Teispace"},"module":"./dist/index.js","engines":{"node":">=20.9.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./client":{"types":"./dist/client.d.ts","import":"./dist/client.js"},"./script":{"types":"./dist/script.d.ts","import":"./dist/script.js"},"./server":{"types":"./dist/server.d.ts","import":"./dist/server.js"},"./adapters":{"types":"./dist/adapters.d.ts","import":"./dist/adapters.js"},"./tailwind":{"types":"./dist/tailwind.d.ts","import":"./dist/tailwind.js"},"./package.json":"./package.json","./tailwind.css":"./tailwind.css","./hooks/use-theme":{"types":"./dist/hooks/use-theme.d.ts","import":"./dist/hooks/use-theme.js"},"./hooks/use-hydrated":{"types":"./dist/hooks/use-hydrated.d.ts","import":"./dist/hooks/use-hydrated.js"},"./hooks/use-theme-value":{"types":"./dist/hooks/use-theme-value.d.ts","import":"./dist/hooks/use-theme-value.js"},"./components/themed-icon":{"types":"./dist/components/themed-icon.d.ts","import":"./dist/components/themed-icon.js"},"./hooks/use-theme-effect":{"types":"./dist/hooks/use-theme-effect.d.ts","import":"./dist/hooks/use-theme-effect.js"},"./components/scoped-theme":{"types":"./dist/components/scoped-theme.d.ts","import":"./dist/components/scoped-theme.js"},"./components/themed-image":{"types":"./dist/components/themed-image.d.ts","import":"./dist/components/themed-image.js"},"./codemod/from-next-themes":"./codemod/from-next-themes.cjs"},"gitHead":"422263b3f16348c3f7fbb5f06d3ec00b43cd54c0","license":"MIT","scripts":{"dev":"tsup --watch","test":"vitest run","build":"tsup","clean":"rm -rf dist","test:cov":"vitest run --coverage","test:watch":"vitest","type-check":"tsc --noEmit","prepublishOnly":"yarn clean && yarn build"},"version":"3.0.2","_npmUser":{"name":"iamkrishnaa","email":"krishna.forkhaki@gmail.com"},"homepage":"https://github.com/teispace/npm-packages/tree/main/packages/next-themes#readme","keywords":["next-themes","theme","dark-mode","nextjs","react","ssr","no-flash","color-scheme","view-transitions","typescript"],"repository":{"url":"git+https://github.com/teispace/npm-packages.git","type":"git","directory":"packages/next-themes"},"_npmVersion":"11.19.0","description":"Feature-rich, lightweight theme management for Next.js and React. Zero-flash SSR, hybrid storage, view transitions, typed themes.","directories":{},"maintainers":[{"name":"iamkrishnaa","email":"krishna.forkhaki@gmail.com"}],"sideEffects":["*.css"],"_nodeVersion":"24.20.0","_hasShrinkwrap":false,"devDependencies":{"next":"^16.3.2","tsup":"^8.5.1","vite":"^8.0.10","jsdom":"^30.0.1","react":"^19.2.8","vitest":"^5.0.0","react-dom":"^19.2.8","typescript":"^6.0.3","@types/node":"^26.2.0","jscodeshift":"^17.4.0","@types/react":"^19.2.18","@types/react-dom":"^19.2.4","@types/jscodeshift":"^17.3.0","@testing-library/dom":"^10.4.1","@testing-library/react":"^16.3.2"},"peerDependencies":{"next":">=13.0.0","react":">=18.0.0","react-dom":">=18.0.0"},"peerDependenciesMeta":{"next":{"optional":true}},"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/next-themes_3.0.2_1788690695445_0.26656609657091157"}}},"time":{"created":"2026-04-23T07:25:40.997Z","modified":"2026-09-06T10:31:35.926Z","0.2.0":"2026-04-23T07:25:41.287Z","0.2.1":"2026-04-26T13:36:58.726Z","0.3.2":"2026-05-02T04:26:50.233Z","0.4.1":"2026-05-03T14:38:30.454Z","0.4.2":"2026-05-06T14:56:51.392Z","0.4.3":"2026-05-18T10:14:30.840Z","0.5.0":"2026-05-18T10:35:59.075Z","1.0.0":"2026-05-31T04:23:26.949Z","2.0.0":"2026-05-31T06:27:07.178Z","2.0.1":"2026-05-31T07:49:16.567Z","2.0.2":"2026-06-07T16:55:42.378Z","2.0.3":"2026-06-20T12:59:54.012Z","2.0.4":"2026-06-28T09:24:42.138Z","3.0.0":"2026-08-21T16:52:08.672Z","3.0.1":"2026-09-05T15:49:16.330Z","3.0.2":"2026-09-06T10:31:35.541Z"},"bugs":{"url":"https://github.com/teispace/npm-packages/issues"},"author":{"name":"Teispace"},"license":"MIT","homepage":"https://github.com/teispace/npm-packages/tree/main/packages/next-themes#readme","keywords":["next-themes","theme","dark-mode","nextjs","react","ssr","no-flash","color-scheme","view-transitions","typescript"],"repository":{"url":"git+https://github.com/teispace/npm-packages.git","type":"git","directory":"packages/next-themes"},"description":"Feature-rich, lightweight theme management for Next.js and React. Zero-flash SSR, hybrid storage, view transitions, typed themes.","maintainers":[{"name":"iamkrishnaa","email":"krishna.forkhaki@gmail.com"}],"readme":"# @teispace/next-themes\n\n> Feature-rich, lightweight, production-grade theme management for Next.js and React.\n> Hybrid cookie + localStorage storage, typed themes, View Transitions, scoped sub-trees, Tailwind v4 preset, zero-FOUC SSR, codemod from `next-themes`.\n\n```bash\nyarn add @teispace/next-themes\n```\n\n---\n\n## Contents\n\n- [Why another theme library?](#why-another-theme-library)\n- [Install](#install)\n- [Quick start](#quick-start)\n  - [Next.js App Router](#nextjs-app-router)\n  - [Vite / Remix / Generic React](#vite--remix--generic-react)\n- [Core concepts](#core-concepts)\n  - [Attributes and selectors](#attributes-and-selectors)\n  - [Storage modes](#storage-modes)\n  - [The resolved theme](#the-resolved-theme)\n  - [The inline anti-FOUC script](#the-inline-anti-fouc-script)\n- [Server-side rendering](#server-side-rendering)\n  - [Reading the theme server-side](#reading-the-theme-server-side)\n  - [Reading the theme in middleware (sync, from `Request`)](#reading-the-theme-in-middleware-sync-from-request)\n  - [Prefers-color-scheme client hint](#prefers-color-scheme-client-hint)\n  - [Writing the cookie from server actions](#writing-the-cookie-from-server-actions)\n- [Typed factory — `createThemes`](#typed-factory--createthemes)\n- [Hooks](#hooks)\n  - [`useTheme`](#usetheme)\n  - [`useThemeValue`](#usethemevalue)\n  - [`useThemeEffect`](#usethemeeffect)\n- [Components](#components)\n  - [`<ThemedImage />`](#themedimage-)\n  - [`<ThemedIcon />`](#themedicon-)\n  - [`<ScopedTheme />`](#scopedtheme-)\n- [View transitions](#view-transitions)\n- [Tailwind](#tailwind)\n  - [Tailwind v4](#tailwind-v4)\n  - [Tailwind v3](#tailwind-v3)\n- [Storage adapters (advanced)](#storage-adapters-advanced)\n- [Upgrading from 2.x](#upgrading-from-2x)\n- [Migration from `next-themes`](#migration-from-next-themes)\n- [Full API reference](#full-api-reference)\n  - [`ThemeProvider` props](#themeprovider-props)\n  - [`setTheme(theme, options?)`](#setthemetheme-options)\n  - [Types](#types)\n  - [Exports by subpath](#exports-by-subpath)\n- [Recipes](#recipes)\n- [Troubleshooting / FAQ](#troubleshooting--faq)\n- [Performance & bundle sizes](#performance--bundle-sizes)\n- [Browser support](#browser-support)\n- [Examples app](#examples-app)\n- [License](#license)\n\n---\n\n## Why another theme library?\n\n`next-themes` by paco is battle-tested, but in 2026 it has unresolved React 19 bugs, no first-class server-side theme reading, and broken multi-class cleanup. Newer rewrites like `@wrksz/themes` closed some of those gaps but still ship a god-component provider, an inline script that re-inserts a transition-disable `<style>` on every apply (a real flicker source), and a fixed-storage model with no plugin path.\n\n**`@teispace/next-themes` is engineered for production from the inside out:**\n\n- **Hybrid storage** — cookie is authoritative for SSR (zero flash) while `localStorage` mirrors for cross-tab sync. Five modes: `hybrid`, `cookie`, `local`, `session`, `none`.\n- **`useSyncExternalStore` + external store** — state, DOM apply, transitions, and subscriptions all live *outside* React. State survives React 19 `Activity` / `cacheComponents` / suspension without going stale.\n- **`useServerInsertedHTML` script injection** — avoids the React 19 inline-script client warning and places the blocker where it actually blocks.\n- **No-op short-circuit** — `setTheme(currentTheme)` is a true no-op: no DOM write, no `<style>` injection, no flicker. (Common bug elsewhere — re-applying the same theme retriggers transition suppression.)\n- **XSS-hardened inline script** — escapes `</script>`, U+2028, U+2029 in every user-input path (`themeColor`, `value`, `forcedTheme`) so a hand-crafted prop value can't break out of the inline `<script>` tag.\n- **Bundler-proof script body** — the inline script is a raw string template, never serialized via `Function.toString()`, so esbuild/swc `__name(...)` wrappers and identifier renames can never crash it at runtime.\n- **Per-instance stores** — nested `<ThemeProvider>`s are genuinely independent. No hidden global state.\n- **Pluggable storage adapters** — public `StorageAdapter` interface (`get` / `set` / optional `subscribe`). Bring your own backend.\n- **Sync `getTheme(Request)` for middleware** — read the theme from a `Request` synchronously in middleware and edge functions, no `await` required.\n- **`Sec-CH-Prefers-Color-Scheme` client hint** — zero-flash SSR even for first-time visitors without a cookie.\n- **View Transitions** — opt into cursor-origin circular reveals or fade animations with one prop. Respects `prefers-reduced-motion`.\n- **`createThemes<T>()`** — full literal-type inference for your theme list across provider, hooks, and components.\n- **Eight subpath entries** — `.`, `/client`, `/server`, `/adapters`, `/script`, `/tailwind`, `/tailwind.css`, `/codemod/from-next-themes`. You pay only for what you import.\n- **Codemod** from `next-themes` — one `npx jscodeshift` command rewrites your imports.\n\n---\n\n## Install\n\n```bash\nyarn add @teispace/next-themes\n# or\nnpm install @teispace/next-themes\n# or\npnpm add @teispace/next-themes\n# or\nbun add @teispace/next-themes\n```\n\n**Peer dependencies:** `react ≥ 18`, `react-dom ≥ 18`, `next ≥ 13` (optional — only if you use the default Next entry).\n\n---\n\n## Quick start\n\n### Next.js App Router\n\nThree files: a provider boundary, a server-side seed, and your app code.\n\n```tsx\n// app/layout.tsx — STAYS A SERVER COMPONENT\nimport { ThemeProvider } from '@teispace/next-themes';\nimport { getTheme } from '@teispace/next-themes/server';\n\nexport default async function RootLayout({ children }: { children: React.ReactNode }) {\n  const initialTheme = await getTheme();\n  return (\n    <html lang=\"en\" suppressHydrationWarning>\n      <body>\n        <ThemeProvider attribute=\"class\" initialTheme={initialTheme ?? undefined}>\n          {children}\n        </ThemeProvider>\n      </body>\n    </html>\n  );\n}\n```\n\n**No `'use client'` required in your code.** `<ThemeProvider>` ships its own client boundary, so you can drop it into a server component (including `app/layout.tsx`) and Next.js handles the boundary automatically. Your `<html>`, `<body>`, and any siblings remain server-rendered.\n\n```tsx\n// any client component\n'use client';\nimport { useTheme } from '@teispace/next-themes';\n\nexport function Toggle() {\n  const { theme, setTheme } = useTheme();\n  return (\n    <button onClick={() => setTheme(theme === 'dark' ? 'light' : 'dark')}>\n      Toggle\n    </button>\n  );\n}\n```\n\nThat's it. The anti-FOUC script is injected server-side via `useServerInsertedHTML`, the theme is read from the cookie on the server, and the client picks up without mismatch.\n\n#### Zero-flicker setup (recommended for production)\n\n`useServerInsertedHTML` places the script wherever React reaches its first flush boundary — usually inside `<body>`. With streaming, partial prerendering, or `cacheComponents`, the body's first bytes can paint before the script lands, briefly showing the wrong theme. To eliminate every possible flicker source, render the script directly in `<head>` and tell the provider to skip its own injection:\n\n```tsx\n// app/layout.tsx — still a server component\nimport { ThemeProvider } from '@teispace/next-themes';\nimport { getTheme, getThemeScript } from '@teispace/next-themes/server';\n\nexport default async function RootLayout({ children }: { children: React.ReactNode }) {\n  const initialTheme = await getTheme();\n  const themeScript = getThemeScript({\n    attribute: 'class',\n    initialTheme: initialTheme ?? undefined,\n  });\n  return (\n    <html lang=\"en\" suppressHydrationWarning>\n      <head>\n        {/* biome-ignore lint/security/noDangerouslySetInnerHtml: anti-FOUC */}\n        <script dangerouslySetInnerHTML={{ __html: themeScript }} />\n      </head>\n      <body>\n        <ThemeProvider attribute=\"class\" initialTheme={initialTheme ?? undefined} noScript>\n          {children}\n        </ThemeProvider>\n      </body>\n    </html>\n  );\n}\n```\n\nThis guarantees the inline script runs **before** the browser paints any body pixels, regardless of how Next.js streams the response. Pass the same options to `getThemeScript()` and `<ThemeProvider>` so they stay in sync — or use [`createThemes()`](#typed-factory--createthemes) so the configuration lives in one place.\n\n### Vite / Remix / Generic React\n\n```tsx\n// App.tsx\nimport { ThemeProvider, useTheme } from '@teispace/next-themes/client';\n\nexport function App() {\n  return (\n    <ThemeProvider attribute=\"class\">\n      <Inner />\n    </ThemeProvider>\n  );\n}\n\nfunction Inner() {\n  const { theme, setTheme } = useTheme();\n  return <button onClick={() => setTheme(theme === 'dark' ? 'light' : 'dark')}>Toggle</button>;\n}\n```\n\nThe `/client` entry uses an inline `<script suppressHydrationWarning>` instead of `useServerInsertedHTML`. API is otherwise identical.\n\n---\n\n## Core concepts\n\n### Attributes and selectors\n\nThe provider applies the active theme to the target element (default `<html>`) as an HTML attribute. You control which attribute with the `attribute` prop:\n\n```tsx\n<ThemeProvider attribute=\"class\">              // <html class=\"dark\">\n<ThemeProvider attribute=\"data-theme\">         // <html data-theme=\"dark\">\n<ThemeProvider attribute={['class', 'data-theme']}>  // both\n```\n\nYour CSS then scopes styles to that attribute:\n\n```css\n/* class attribute */\n.dark { --bg: #0f1115; }\n\n/* data-theme attribute */\n[data-theme=\"dark\"] { --bg: #0f1115; }\n```\n\nIf your CSS expects a different value than your logical theme name, use `value`:\n\n```tsx\n<ThemeProvider\n  themes={['light', 'dark', 'solarized']}\n  attribute=\"class\"\n  value={{\n    dark: 'theme-dark',\n    solarized: 'theme-solarized high-contrast',  // multi-class works\n  }}\n>\n```\n\nThe library cleans up stale classes on every switch — including every value in the `value` map — so moving between multi-class themes never leaves leftovers.\n\n### Storage modes\n\nPick where the user's choice persists:\n\n| Mode | Server-readable | Cross-tab sync | When to use |\n|---|:-:|:-:|---|\n| `hybrid` *(default)* | ✅ | ✅ | Zero-flash SSR + multi-tab apps. |\n| `cookie` | ✅ | — | SSR apps where cross-tab doesn't matter. |\n| `local` | — | ✅ | SPAs with no server rendering. |\n| `session` | — | — | Per-tab, forgotten on close. |\n| `none` | — | — | `forcedTheme` or in-memory only. |\n\n```tsx\n<ThemeProvider storage=\"hybrid\" storageKey=\"theme\" />\n```\n\n**Hybrid semantics.** Cookie is authoritative on read (so the server and the inline script read the same value), while `localStorage` mirrors for cross-tab `storage` events. Writes go to both.\n\n### The resolved theme\n\nThere are two theme values:\n\n- `theme` — the *selected* theme, which may be `'system'`.\n- `resolvedTheme` — the *concrete* theme after system resolution (always one of your real themes).\n\n```ts\nconst { theme, resolvedTheme } = useTheme();\n// theme:         'system'\n// resolvedTheme: 'dark'   (user's OS preference)\n```\n\nUse `resolvedTheme` for rendering decisions (CSS, assets), and `theme` for toggle UI state.\n\n### The inline anti-FOUC script\n\nOn the server, the provider emits a tiny, synchronous, blocking `<script>` inside `<head>` (via `useServerInsertedHTML` on Next, via React's `dangerouslySetInnerHTML` with `suppressHydrationWarning` elsewhere). That script:\n\n1. Reads the theme from your configured storage (cookie first, then localStorage, then `initialTheme`, then `defaultTheme`).\n2. Resolves `'system'` via `matchMedia('(prefers-color-scheme: dark)')`.\n3. Applies the correct attribute + class + `color-scheme` + `<meta name=\"theme-color\">` to the target element.\n4. Optionally freezes CSS transitions for one frame.\n\nIt runs **before** React hydrates, **before** first paint, so the correct theme is visible in the first rendered frame — no flash.\n\nThe script accepts a `nonce` for CSP environments and always wraps its body in a `try/catch` so it is silent on any runtime error (never blocks rendering).\n\n---\n\n## Server-side rendering\n\n### Reading the theme server-side\n\n```tsx\nimport { getTheme } from '@teispace/next-themes/server';\n\nexport default async function RootLayout({ children }) {\n  const initialTheme = await getTheme();\n  // Preference order: theme cookie → Sec-CH-Prefers-Color-Scheme hint → null\n  return (\n    <html suppressHydrationWarning>\n      <body>\n        <ThemeProvider initialTheme={initialTheme ?? undefined}>\n          {children}\n        </ThemeProvider>\n      </body>\n    </html>\n  );\n}\n```\n\n#### With Next.js 16 Cache Components (`cacheComponents: true`)\n\n**The snippet above will not build with `cacheComponents: true`.** Cache Components\nmakes reading `cookies()` outside a cache boundary a build error, and that\nincludes a `getTheme()` call at the top level of a layout — `getTheme()` reads\nthe theme cookie.\n\nThis is not a problem for zero-flash rendering. The inline anti-FOUC script is\nwhat prevents the flash, and it needs no request data at all: it reads the\ncookie in the browser before first paint. `initialTheme` is only there to seed\nthe *React* tree so theme-dependent components (`<ThemedImage>`, `<ThemedIcon>`,\nanything branching on `useTheme()`) render the right thing during SSR.\n\nSo you have three options, in order of preference:\n\n**1. Drop `initialTheme` from the layout.** The script still eliminates the\nflash. Do this unless you render theme-dependent markup on the server.\n\n```tsx\nexport default function RootLayout({ children }) {\n  return (\n    <html suppressHydrationWarning>\n      <body>\n        <ThemeProvider>{children}</ThemeProvider>\n      </body>\n    </html>\n  );\n}\n```\n\n**2. Read the cookie inside a `'use cache: private'` boundary.** That directive\nis allowed to call `cookies()`, and its result is cached per-browser and never\non the server.\n\n```tsx\nasync function ThemeShell({ children }: { children: React.ReactNode }) {\n  'use cache: private';\n  const initialTheme = await getTheme();\n  return <ThemeProvider initialTheme={initialTheme ?? undefined}>{children}</ThemeProvider>;\n}\n```\n\n**3. Opt the segment out** with `export const instant = false` if you want the\nold request-time behaviour for that route.\n\n> **Do not let a per-user value reach the inline script.** The script is emitted\n> through `useServerInsertedHTML`, so it becomes part of the prerendered static\n> shell. Passing a request-derived `initialTheme` or `forcedTheme` bakes one\n> user's theme into a shell served to everyone. Seed the React tree (option 2)\n> rather than the script.\n\n\n### Reading the theme in middleware (sync, from `Request`)\n\n`getTheme()` has a sync overload that reads directly from a `Request` object — no `await`, no `next/headers`. Use this in middleware, edge functions, route rewriters, or anywhere you have a `Request` but no Next.js async context.\n\n```ts\n// proxy.ts  (Next.js 16 renamed middleware.ts -> proxy.ts, and the exported\n// function from `middleware` to `proxy`. On Next 15 and earlier use\n// middleware.ts / export function middleware.)\nimport { NextResponse, type NextRequest } from 'next/server';\nimport { getTheme } from '@teispace/next-themes/server';\n\nexport function proxy(request: NextRequest) {\n  const theme = getTheme(request, { defaultTheme: 'system' });\n  // Branch on the theme: rewrite, set a header, redirect, etc.\n  const res = NextResponse.next();\n  res.headers.set('x-theme', theme ?? 'system');\n  return res;\n}\n```\n\nThe sync overload reads the cookie *and* the `Sec-CH-Prefers-Color-Scheme` hint from `request.headers`, with the same precedence as the async path. Pass a `themes` whitelist if you want unknown cookie values treated as missing:\n\n```ts\nconst theme = getTheme(request, { themes: ['light', 'dark'], defaultTheme: 'light' });\n```\n\n**Pass the whitelist `as const` and the return type narrows to it**, so server\ncode can branch exhaustively without re-narrowing:\n\n```ts\nconst theme = getTheme(request, { themes: ['light', 'dark'] as const });\n//    ^? 'light' | 'dark' | 'system' | null\n\n// Without `as const` (or without `themes`) you get the wider `string | null`.\n```\n\n`'system'` is always included — it is a legitimate stored value that the\nprovider resolves — and `null` means neither the cookie nor the client hint\nsupplied anything.\n\n> **When to use which overload**\n> - `await getTheme()` — Server Components, Route Handlers (uses `cookies()` / `headers()` from `next/headers`).\n> - `getTheme(request)` — proxy/middleware, edge functions, custom servers (works on the raw `Request`, no Next.js binding).\n\n### Prefers-color-scheme client hint\n\nChromium browsers can send `Sec-CH-Prefers-Color-Scheme: light|dark` on each request — but only after the server asks for it via `Accept-CH`. With this hint, a first-time visitor with no cookie still gets zero-flash SSR matching their OS preference.\n\n> **Coverage.** `Sec-CH-Prefers-Color-Scheme` and `Accept-CH` are Chromium-only — Chrome, Edge and Chrome for Android 93+. Firefox and Safari do not send the hint and there is no sign they will. Treat this as a progressive enhancement for the majority of traffic, not a general zero-flash solution: the inline script is what guarantees no flash everywhere else.\n\n```ts\n// proxy.ts  (middleware.ts on Next 15 and earlier)\nimport { NextResponse } from 'next/server';\nimport { acceptClientHintsHeader } from '@teispace/next-themes/server';\n\nexport function proxy() {\n  const res = NextResponse.next();\n  res.headers.set('Accept-CH', acceptClientHintsHeader());\n  // → 'Accept-CH: Sec-CH-Prefers-Color-Scheme'\n  return res;\n}\n```\n\nAfter this runs once, subsequent navigations include the hint and `getTheme()` picks it up automatically.\n\n### Writing the cookie from server actions\n\nWhen you persist the theme from the server (e.g. on a user-preferences save):\n\n```ts\n'use server';\nimport { writeThemeCookie } from '@teispace/next-themes/server';\n\nexport async function saveTheme(theme: string) {\n  await writeThemeCookie(theme);\n  // ...persist to your user profile here\n}\n```\n\nOr, for custom servers / edge workers, build the header yourself:\n\n```ts\nimport { setThemeCookie } from '@teispace/next-themes/server';\n\nresponse.headers.set('Set-Cookie', setThemeCookie('dark', {\n  maxAge: 60 * 60 * 24 * 365,\n  secure: true,\n  domain: '.example.com',\n}));\n```\n\n---\n\n## Typed factory — `createThemes`\n\nFor maximum type safety, create a typed theme module once and import from it everywhere.\n\n```ts\n// app/theme.ts\n'use client';\nimport { createThemes } from '@teispace/next-themes';\n\nexport const {\n  ThemeProvider,\n  useTheme,\n  useThemeValue,\n  useThemeEffect,\n  ThemedImage,\n  ThemedIcon,\n  ScopedTheme,\n} = createThemes({\n  themes: ['light', 'dark', 'sepia', 'mint'] as const,   // ← literal tuple\n  defaultTheme: 'system',\n  attribute: 'class',\n  storage: 'hybrid',\n  // any ThemeProvider prop works as a default:\n  disableTransitionOnChange: true,\n  themeColor: { light: '#fff', dark: '#0f1115' },\n});\n```\n\nNow every consumer gets literal types:\n\n```tsx\nimport { useTheme, useThemeValue, ScopedTheme } from '@/app/theme';\n\nconst { theme, setTheme } = useTheme();\n// theme:   'light' | 'dark' | 'sepia' | 'mint' | 'system'\n// setTheme(value)  — value is typed to the union above\n\nconst accent = useThemeValue({\n  light: '#2563eb',\n  dark:  '#60a5fa',\n  sepia: '#b45309',\n  mint:  '#0f766e',\n  // unknown keys are a compile error\n});\n\n<ScopedTheme theme=\"sepia\">...</ScopedTheme>\n// ScopedTheme.theme is typed too\n```\n\nPer-use props on the returned `ThemeProvider` override the factory defaults, so you can still customize per-mount (e.g. set a different `defaultTheme` on an auth page).\n\n**When to use the factory vs. the generic hook.** The factory gives perfect inference from a single config. The generic `useTheme<T>()` takes a type parameter per-call and is handy for quick prototyping. Use the factory for shipped code.\n\n---\n\n### Each factory owns its own context\n\n`createThemes()` mints a **private React context** and binds its provider, hooks\nand components to it. Two independently-created theme APIs therefore never see\neach other's store, and can be nested:\n\n```tsx\n// app/theme.ts   — the app shell\nexport const Shell = createThemes({ themes: ['light', 'dark'] as const });\n\n// widgets/embed-theme.ts — an embedded widget with its own palette\nexport const Widget = createThemes({\n  themes: ['alpha', 'beta'] as const,\n  attribute: 'data-widget-theme',   // a distinct attribute avoids DOM contention\n});\n```\n\n```tsx\n<Shell.ThemeProvider>\n  <Header />                       {/* Shell.useTheme() → 'light' | 'dark' */}\n  <Widget.ThemeProvider>\n    <Embed />                      {/* Widget.useTheme() → 'alpha' | 'beta'   */}\n  </Widget.ThemeProvider>\n</Shell.ThemeProvider>\n```\n\nA factory hook used outside its own provider stays **inert** (`theme: ''`,\n`themes: []`) rather than silently falling through to a neighbouring API's\nstore — so `themes.length === 0` remains a reliable \"not mounted yet\" check.\n\n> **Changed in 3.0.** Previously every hook and component read one\n> module-level context, so two `createThemes()` APIs collided: whichever\n> provider sat nearest in the tree served *both* hook sets, and an embedded\n> widget could report the shell's themes. See\n> [Upgrading from 2.x](#upgrading-from-2x).\n\n## Hooks\n\n### `useTheme`\n\n```ts\nconst {\n  theme,          // string — the selected value (may be 'system')\n  resolvedTheme,  // string — the concrete theme after system resolution\n  systemTheme,    // 'light' | 'dark' | null\n  forcedTheme,    // string | null — echoes the forcedTheme prop\n  themes,         // string[] — list of available themes (includes 'system' when enableSystem)\n  setTheme,       // (theme, options?) => void\n} = useTheme();\n```\n\nTyping:\n\n```ts\n// generic form (no factory)\nconst { theme, setTheme } = useTheme<'light' | 'dark' | 'sepia'>();\n```\n\n### `useThemeValue`\n\nMap the active theme to a value. Resolution order: `resolvedTheme` → raw `theme` → `map.default`.\n\n```tsx\nimport { useThemeValue } from '@teispace/next-themes';\n\nconst accent = useThemeValue({ light: '#2563eb', dark: '#60a5fa', default: '#000' });\nconst copy   = useThemeValue({ light: 'Day mode', dark: 'Night mode' });\n```\n\nReturns `undefined` when no key matches and no default is provided.\n\n### `useThemeEffect`\n\nLike `useEffect`, but **skips the first render** and only fires on theme changes. Perfect for analytics, server-sync, one-shot side effects.\n\n```tsx\nimport { useThemeEffect } from '@teispace/next-themes';\n\nfunction Analytics() {\n  useThemeEffect((theme, resolvedTheme) => {\n    track('theme_changed', { theme, resolvedTheme });\n    return () => abortPending();  // optional cleanup on next change\n  });\n  return null;\n}\n```\n\nDeps work the same as `useEffect`:\n\n```tsx\nuseThemeEffect((theme) => { /* ... */ }, [user.id]);\n```\n\n---\n\n## Components\n\n### `<ThemedImage />`\n\nSwap `<img src>` based on the active theme. Reads from the external store directly, so when the provider is seeded with `initialTheme` from the server cookie, the **very first render** (server and client) picks the correct variant — no mount flag, no post-hydration swap, no flash.\n\n```tsx\nimport { ThemedImage } from '@teispace/next-themes';\n\n<ThemedImage\n  sources={{ light: '/logo-light.svg', dark: '/logo-dark.svg' }}\n  fallbackSrc=\"/logo-light.svg\"\n  alt=\"Brand logo\"\n  width={240}\n  height={100}\n  className=\"rounded-md\"\n/>\n```\n\nIf the resolved theme could legitimately differ between server and client (e.g. `theme=\"system\"` with no client hint), wrap the usage in a `<span suppressHydrationWarning>` or use the CSS pattern below.\n\nFor pixel-perfect SSR switching driven entirely by CSS, use theme-scoped `display`:\n\n```css\nhtml[data-theme=\"dark\"] .logo-light { display: none; }\nhtml[data-theme=\"dark\"] .logo-dark  { display: block; }\n```\n\n### `<ThemedIcon />`\n\nSame idea for arbitrary React nodes — SVG icons, logos, anything.\n\n```tsx\nimport { ThemedIcon } from '@teispace/next-themes';\n\n<ThemedIcon\n  variants={{ light: <SunIcon />, dark: <MoonIcon /> }}\n  fallback={<SunIcon />}\n/>\n```\n\n### `<ScopedTheme />`\n\nForce a sub-tree to a specific theme without touching the page root. Inside the scope, `useTheme()` reports the scoped theme and `setTheme` is a no-op.\n\n```tsx\nimport { ScopedTheme } from '@teispace/next-themes';\n\n<ScopedTheme theme=\"dark\">\n  <Modal />  {/* always dark, regardless of page theme */}\n</ScopedTheme>\n\n// render as any element, with any attribute strategy\n<ScopedTheme theme=\"sepia\" as=\"section\" attribute=\"data-theme\" className=\"preview\">\n  <Preview />\n</ScopedTheme>\n\n// map theme names to CSS class/attribute values\n<ScopedTheme theme=\"dark\" value={{ dark: 'theme-dark' }}>...</ScopedTheme>\n```\n\nProps: `theme`, `children`, `as?` (default `'div'`), `attribute?` (default `'class'`), `value?`, plus any DOM props passed through to the wrapper element.\n\n---\n\n## View transitions\n\nAnimate theme changes with the [View Transitions API](https://developer.mozilla.org/en-US/docs/Web/API/View_Transitions_API). Gracefully no-ops where the API is unsupported (Firefox as of 2026).\n\n### Provider-level default\n\n```tsx\n<ThemeProvider transition=\"circular\">{children}</ThemeProvider>\n```\n\n### Per-call override\n\n```tsx\nconst { setTheme } = useTheme();\n\nsetTheme('dark');                                    // uses provider default\nsetTheme('dark', { transition: 'circular' });        // override\nsetTheme('dark', { transition: false });             // skip animation this time\n```\n\n### Shorthand values\n\n| Value | Effect |\n|---|---|\n| `true` or `'fade'` | Browser-default cross-fade |\n| `'circular'` | Circular reveal expanding from the last pointerdown (or viewport center if none) |\n| `'none'` or `false` | Disabled |\n\n### Full options\n\n```tsx\n<ThemeProvider\n  transition={{\n    type: 'circular',                       // 'fade' | 'circular' | 'none'\n    duration: 500,                          // ms\n    easing: 'cubic-bezier(.4, 0, .2, 1)',\n    origin: 'cursor',                       // 'cursor' | 'center' | { x: 100, y: 200 }\n    css: '...',                             // fully custom ::view-transition CSS\n  }}\n>\n```\n\n### Reduced motion\n\nTransitions (and the transition-disabling freeze) are automatically skipped when the user has `prefers-reduced-motion: reduce`. Pass `respectReducedMotion={false}` to opt out.\n\n### Custom CSS recipe\n\nFor a full-page slide reveal:\n\n```tsx\nsetTheme(next, {\n  transition: {\n    type: 'fade',\n    duration: 600,\n    css: `\n::view-transition-old(root) { animation: out 600ms cubic-bezier(.4,0,.2,1); }\n::view-transition-new(root) { animation: in  600ms cubic-bezier(.4,0,.2,1); }\n@keyframes out { to { opacity: 0; transform: translateY(-10px); } }\n@keyframes in  { from { opacity: 0; transform: translateY( 10px); } }`,\n  },\n});\n```\n\n---\n\n## Tailwind\n\n### Tailwind v4\n\nImport the preset once in your app CSS; `dark:` and `light:` variants work everywhere.\n\n```css\n@import \"tailwindcss\";\n@import \"@teispace/next-themes/tailwind.css\";\n```\n\nThe preset matches **both** `attribute=\"class\"` *and* `attribute=\"data-theme\"` providers, so you can switch strategies without changing your markup.\n\n```html\n<!-- either of these works -->\n<html data-theme=\"dark\">...\n<html class=\"dark\">...\n```\n\nAdd custom variants for additional themes:\n\n```css\n@custom-variant sepia (\n  &:where([data-theme=\"sepia\"], [data-theme=\"sepia\"] *, .sepia, .sepia *)\n);\n@custom-variant mint (\n  &:where([data-theme=\"mint\"], [data-theme=\"mint\"] *, .mint, .mint *)\n);\n```\n\nUsage in markup:\n\n```html\n<div class=\"bg-white text-slate-900 dark:bg-slate-900 dark:text-white sepia:bg-amber-100\">\n  ...\n</div>\n```\n\n### Tailwind v3\n\n```ts\n// tailwind.config.ts\nimport { darkMode, themeVariant } from '@teispace/next-themes/tailwind';\nimport plugin from 'tailwindcss/plugin';\n\nexport default {\n  darkMode,\n  plugins: [\n    plugin(({ addVariant }) => {\n      addVariant('sepia', themeVariant('sepia'));\n      addVariant('mint',  themeVariant('mint'));\n    }),\n  ],\n};\n```\n\n---\n\n## Storage adapters (advanced)\n\nEach storage mode resolves to a tiny adapter with the shape:\n\n```ts\ninterface StorageAdapter {\n  get(): string | null;\n  set(value: string): void;\n  subscribe?(cb: (value: string | null) => void): () => void;\n}\n```\n\nYou can import adapter factories directly if you need to inspect values or roll your own:\n\n```ts\nimport {\n  localAdapter,\n  cookieAdapter,\n  sessionAdapter,\n  hybridAdapter,\n  resolveAdapter,\n  readCookieFromString,\n  serializeCookie,\n} from '@teispace/next-themes/adapters';\n\nconst a = hybridAdapter({ key: 'theme', cookie: { name: 'theme' } });\na.get();        // current value, if any\na.set('dark');\n```\n\n`resolveAdapter({ mode, key, cookieOptions })` returns the adapter the provider would use for a given config — handy for tests or sync-from-server flows.\n\n---\n\n## Upgrading from 2.x\n\nMost apps need **no changes**. Everything below is either additive or affects a\nsetup that was already behaving incorrectly.\n\n### Breaking\n\n**1. Each `createThemes()` gets its own context.**\nIf you called `createThemes()` **once**, nothing changes. If you called it more\nthan once, the APIs were previously sharing a single module-level context —\nwhichever provider was nearest in the tree served *all* of them, so a second\nAPI could silently report the first one's themes. They are now isolated.\n\n*Symptom of relying on the old behaviour:* a hook from factory **A** used\nwithout an `A.ThemeProvider` above it used to pick up **B**'s provider; it now\nreturns the inert state (`theme: ''`, `themes: []`). The fix is to render the\nmatching provider, which is what the code always meant.\n\n```diff\n  <B.ThemeProvider>\n+   <A.ThemeProvider>\n      <ComponentUsingAUseTheme />\n+   </A.ThemeProvider>\n  </B.ThemeProvider>\n```\n\n**2. `main` removed from `package.json`.**\nIt pointed at an ESM file, which misled CJS resolvers into `require()`-ing ESM.\nThe package is ESM-only and declares that through `exports`. Tooling that\nresolved via `main` and appeared to work was relying on a broken path; use a\nbundler or Node ≥ 20.9 with ESM.\n\n**3. Cookies now default to `Secure` on HTTPS.**\nPreviously `Secure` was opt-in, so the theme cookie was sent in cleartext on\notherwise-secure sites. It is now set automatically when\n`location.protocol === 'https:'`. Pass `cookieOptions={{ secure: false }}` to\nopt out (e.g. a plain-HTTP staging host reached over a non-TLS origin).\nServer-side callers (`setThemeCookie`, `writeThemeCookie`) are unaffected —\nthere is no `location` there, so pass `secure` explicitly.\n\n### Not breaking, but worth acting on\n\n- **`engines` lowered to `>=20.9.0`.** 2.x declared `>=24`, which blocked or\n  warned on Node 20/22 LTS for no technical reason. Next.js 16 itself only\n  requires 20.9.\n- **`sideEffects` is now `[\"*.css\"]` instead of `false`.** The old value told\n  bundlers every module was side-effect-free, which permitted them to drop\n  `import '@teispace/next-themes/tailwind.css'` — an import with no bindings is\n  exactly what that flag licenses eliding. If your Tailwind preset ever\n  mysteriously failed to apply, this was why.\n- **Fine-grained subpath exports.** Importing `useTheme` from the package root\n  pulls a ~7.8 kB chunk; `@teispace/next-themes/hooks/use-theme` is 509 B. See\n  [Exports by subpath](#exports-by-subpath).\n- **`useHydrated()`** and **`onStorageError`** are new — see their sections.\n- **View transitions are now typed.** `types: ['theme', '<resolvedTheme>']` is\n  passed where supported, so you can style from CSS instead of the `css` option.\n- **`getTheme()` infers literal themes** when you pass `themes` `as const`.\n\n### Nothing to do\n\n`ThemeProvider` props, `useTheme`, `useThemeValue`, `useThemeEffect`,\n`<ThemedImage>`, `<ThemedIcon>`, `<ScopedTheme>`, storage modes, the inline\nscript, and the server helpers are all source-compatible with 2.x.\n\n---\n\n## Migration from `next-themes`\n\nThe API is drop-in compatible for almost every `next-themes` app. Run the codemod:\n\n```bash\nnpx jscodeshift --parser=tsx \\\n  -t node_modules/@teispace/next-themes/codemod/from-next-themes.cjs \\\n  src/\n```\n\nThis rewrites:\n\n- `import ... from 'next-themes'` → `'@teispace/next-themes'`\n- `require('next-themes')` and dynamic `import('next-themes')`\n- `export { x } from 'next-themes'` and `export * from 'next-themes'`\n- `'next-themes/dist/<sub>'` → `'@teispace/next-themes/<sub>'`\n\nPass `--storage=hybrid` (or `cookie` / `local` / `session` / `none`) to also stamp `storage=\"<mode>\"` on every `<ThemeProvider>`:\n\n```bash\nnpx jscodeshift --parser=tsx \\\n  -t node_modules/@teispace/next-themes/codemod/from-next-themes.cjs \\\n  src/ \\\n  --storage=hybrid\n```\n\n**Behavioral differences to be aware of:**\n\n1. Default `storage` is `'hybrid'` (was localStorage-only). To preserve exact old behavior, set `storage=\"local\"`.\n2. `onChange(theme, resolvedTheme)` in this lib receives both values (was just the selected value). Harmless change unless you branched on the single argument.\n3. Nested `<ThemeProvider>` in this lib maintain independent state — the outer one no longer leaks. If you were relying on nested providers being no-ops, remove the inner ones.\n4. `<ThemedImage>` / `<ThemedIcon>` no longer use a mount-flag delay — when the provider has `initialTheme` seeded from the cookie, the first render is correct. If you relied on `fallbackSrc` showing for a frame, remove that expectation; otherwise this is a strict improvement.\n5. `ThemeProvider`, hooks, and theme-aware components ship with the `'use client'` directive baked in. You can drop `<ThemeProvider>` directly into a server `app/layout.tsx` — no wrapper file needed.\n\n**Upstream `next-themes` issues this package resolves:**\n\n| # | Issue | How we fix it |\n|---|---|---|\n| #397 | React 19.2 *\"Encountered a script tag while rendering React component\"* when the provider client-remounts (e.g. an `app/[lang]` locale switch) | The Next entry never renders the script into the React tree at all (`useServerInsertedHTML`); the generic entry emits it only while un-hydrated and drops it on the first client commit. |\n| #389 | `localStorage.getItem is not a function` on Node 25 (`window === globalThis`) | Capability probes (`hasLocalStorage()`, `isDom()`, ...) instead of `typeof window` checks. |\n| #387 / #385 | Inline `<script>` warning in React 19 / Next 16 | Script injected via `useServerInsertedHTML`, or out of the React tree via `getThemeScript()` in `<head>`. |\n| #375 | Stale theme with `cacheComponents` / `Activity` | Store lives outside React via `useSyncExternalStore` — never stale. |\n| #374 | `react-hooks/set-state-in-effect` ESLint warning | We never `setState` in effect; external store updates flow through `useSyncExternalStore`. |\n| #373 | Tailwind v4 toggle failure | First-class v4 preset at `@teispace/next-themes/tailwind.css`. |\n| #371 | `prefers-color-scheme` ignored | Script + store both subscribe to the media query directly. |\n| #370 / #369 / #368 | `__name is not defined` / minification / Cloudflare flash | Inline script body is a raw string literal (not a serialized function); build asserts no `__name(` survives. |\n| #367 | `children` missing on `ThemeProviderProps` | Props include `children?: ReactNode`. |\n| #351 | Theme class removed on back/forward | `pageshow` re-resolves on bfcache restore (script + store). |\n| #349 | Generate script string at build time | `getThemeScript()` exported from `/server`. |\n| #345 | LS overrides system after `setTheme` | `followSystem` prop forces system tracking and is honored by the inline script. |\n| #326 / #325 | Suspense / hydration boundary breaks with provider | `useSyncExternalStore` instead of `useState` + effect. |\n| #311 | Image example flickers on initial load | `<ThemedImage>` no longer waits for mount; honors `initialTheme`. |\n| #308 / #240 | `enableSystem={false}` + `defaultTheme` | `normalizeSelection` enforces the contract end-to-end. |\n| #295 | Don't store in localStorage | `storage=\"none\"`. |\n| #292 | Multiple classes per theme | `value` map accepts space-separated class strings. |\n| #254 / #215 / #219 | Nested / multi-provider | Per-instance stores; `<ScopedTheme>` for sub-tree overrides. |\n| #242 | Flash with `basePath` | Script doesn't depend on path; pre-paint placement via `getThemeScript()` eliminates flash. |\n| #236 | Multiple attributes | `attribute={['class', 'data-theme']}`. |\n| #226 / #187 | Force theme per route (App Router) | Route-group `<ThemeProvider forcedTheme=\"...\">`. |\n| #213 | XSS via cookie / `forcedTheme` value | Inline-script JSON is HTML-safe encoded (`</script>`, U+2028/9 escaped). |\n| #199 | Theme flips after login | Hybrid heal-on-read + bfcache `pageshow`. |\n| #164 | Track system after `setTheme` | `setTheme('system')` returns to system tracking; or use `followSystem`. |\n| #149 | Type-safe themes | `createThemes<T>()` factory with literal-tuple inference. |\n| #144 | Class on `<body>` | `target=\"body\"`. |\n| #142 | Custom resolved theme | `value` map. |\n| #78 | `theme-color` meta sync | `themeColor` prop. |\n| #72 | sessionStorage | `storage=\"session\"`. |\n| #70 | `finalTheme` | Exposed as `resolvedTheme`. |\n| #63 | Storybook `forcedTheme` not applying class | Forced themes apply to DOM on mount. |\n| #48 | Init from server DB | `initialTheme` prop, paired with `getTheme()` for cookie reads. |\n\nGenuine open feature requests not in scope: themes-with-themes (#309, #73), storybook addon (#63 has a workaround).\n\n---\n\n## Full API reference\n\n### `ThemeProvider` props\n\n| Prop | Type | Default | Description |\n|---|---|---|---|\n| `children` | `ReactNode` | — | Tree to wrap. |\n| `themes` | `string[]` | `['light', 'dark']` | Available theme names. |\n| `defaultTheme` | `string` | `'system'` | Theme used when storage is empty. |\n| `forcedTheme` | `string` | — | Lock to this value. `setTheme` becomes a no-op. |\n| `enableSystem` | `boolean` | `true` | Enable `'system'` as a valid theme + live OS detection. |\n| `followSystem` | `boolean` | `false` | Always track OS preference, ignoring storage. |\n| `attribute` | `Attribute \\| Attribute[]` | `'data-theme'` | HTML attribute(s) on the target element. |\n| `value` | `Record<string, string>` | — | Map logical theme → attribute value (supports multi-class). |\n| `target` | `string` (selector) | `'html'` | Element that receives the attribute. |\n| `storage` | `'hybrid' \\| 'cookie' \\| 'local' \\| 'session' \\| 'none'` | `'hybrid'` | Persistence strategy. |\n| `storageKey` | `string` | `'theme'` | Key for local/session storage and fallback cookie name. |\n| `cookieOptions` | `CookieOptions` | — | Overrides (name, maxAge, path, domain, sameSite, secure). |\n| `disableTransitionOnChange` | `boolean \\| string` | `false` | Freeze CSS transitions during a switch. Pass a CSS string to scope the freeze. |\n| `respectReducedMotion` | `boolean` | `true` | Skip transition-disable + View Transitions when user prefers reduced motion. |\n| `enableColorScheme` | `boolean` | `true` | Sync `style.colorScheme` on the target element. |\n| `themeColor` | `string \\| Record<string, string>` | — | Sync `<meta name=\"theme-color\">`. |\n| `initialTheme` | `string` | — | Seed from the server (cookie, DB, session). |\n| `nonce` | `string` | — | CSP nonce for the inline anti-FOUC script. |\n| `noScript` | `boolean` | `false` | Skip the inline script. Use when you have rendered `getThemeScript()` in `<head>` yourself — most flicker-resistant placement. |\n| `transition` | `TransitionConfig` | — | Animate theme changes via View Transitions. |\n| `onChange` | `(theme, resolvedTheme) => void` | — | Fires on every theme change. |\n\n### `setTheme(theme, options?)`\n\n```ts\nsetTheme('dark');\nsetTheme('dark', {\n  // Override the provider-level transition for this call.\n  transition: false | true | 'fade' | 'circular' | TransitionOptions,\n});\n```\n\n### Types\n\n```ts\ntype Attribute = 'class' | `data-${string}`;\n\ntype StorageMode = 'hybrid' | 'cookie' | 'local' | 'session' | 'none';\n\ninterface CookieOptions {\n  name?: string;\n  maxAge?: number;\n  path?: string;\n  domain?: string;\n  sameSite?: 'strict' | 'lax' | 'none';\n  secure?: boolean;\n}\n\ntype TransitionType = 'fade' | 'circular' | 'none';\ntype TransitionOrigin = 'cursor' | 'center' | { x: number; y: number };\ninterface TransitionOptions {\n  type?: TransitionType;\n  duration?: number;       // ms\n  easing?: string;         // CSS timing function\n  origin?: TransitionOrigin;\n  css?: string;            // custom ::view-transition CSS\n}\ntype TransitionConfig = boolean | TransitionType | TransitionOptions;\n\ninterface ThemeState {\n  theme: string;\n  resolvedTheme: string;\n  systemTheme: 'light' | 'dark' | null;\n  forcedTheme: string | null;\n  themes: string[];\n}\n```\n\n### `useHydrated()`\n\n`false` during the server render and the hydration render, `true` afterwards.\nUse it to gate browser-only UI without a hydration mismatch.\n\n```tsx\nimport { useHydrated } from '@teispace/next-themes/hooks/use-hydrated';\n\nconst hydrated = useHydrated();\nreturn <span>{hydrated ? resolvedTheme : null}</span>;\n```\n\nYou usually don't need it for theming itself — `<ThemedImage>`, `<ThemedIcon>`\nand `useTheme()` already read the store's seeded server snapshot.\n\n### `onStorageError`\n\nStorage failures are non-fatal by design (Safari private mode, sandboxed\niframes, disabled cookies, quota exceeded) — theming must never break because\npersistence did. They used to be silent, which made \"my theme doesn't stick\"\nundebuggable. Wire this to your logger:\n\n```tsx\n<ThemeProvider\n  onStorageError={(error, { operation, key }) => {\n    reportToSentry(error, { tags: { operation, key } });\n  }}\n>\n```\n\n### View transition types\n\nTheme changes are stamped with view-transition types — `theme` plus the resolved\ntheme name — so you can style them from your own CSS instead of passing a `css`\nstring:\n\n```css\n:root(:active-view-transition-type(dark))::view-transition-new(root) {\n  animation: slide-in 300ms ease;\n}\n```\n\nApplied only on engines that support `:active-view-transition-type()`\n(Chrome/Edge 125+, Safari 18.2+, Firefox 147+); elsewhere the built-in\n`fade`/`circular` CSS still runs.\n\n### Exports by subpath\n\n| Import | Purpose |\n|---|---|\n| `@teispace/next-themes` | Next.js App Router provider + hooks + components + `createThemes` |\n| `@teispace/next-themes/client` | Same API, generic React (Vite, Remix, CRA) |\n| `@teispace/next-themes/server` | `getTheme`, `getThemeScript`, `setThemeCookie`, `writeThemeCookie`, `readColorSchemeHint`, `acceptClientHintsHeader` |\n| `@teispace/next-themes/adapters` | Storage adapter factories + cookie helpers |\n| `@teispace/next-themes/script` | `buildScript({...})` — raw inline script builder |\n| `@teispace/next-themes/tailwind` | v3 `darkMode` + `themeVariant(name)` helpers |\n| `@teispace/next-themes/tailwind.css` | v4 CSS preset (import in your global CSS) |\n| `@teispace/next-themes/codemod/from-next-themes` | jscodeshift transform file |\n\n**Fine-grained entries.** Import a single hook or component when you don't need\nthe rest of the package — a leaf that only reads the theme shouldn't pull in the\nproviders, the factory, and every themed component. All of these share one\ninternal chunk, so there is still exactly one store and one context at runtime.\n\n| Import | gzip (transitive) |\n|---|---|\n| `@teispace/next-themes/hooks/use-theme` | 509 B |\n| `@teispace/next-themes/hooks/use-theme-value` | 601 B |\n| `@teispace/next-themes/hooks/use-theme-effect` | 613 B |\n| `@teispace/next-themes/hooks/use-hydrated` | 177 B |\n| `@teispace/next-themes/components/themed-image` | 708 B |\n| `@teispace/next-themes/components/themed-icon` | 693 B |\n| `@teispace/next-themes/components/scoped-theme` | 541 B |\n| *(full `@teispace/next-themes` entry, for comparison)* | 7,797 B |\n\n---\n\n## Recipes\n\n### Sync theme to a user profile on the server\n\n```tsx\n'use client';\nimport { ThemeProvider } from '@teispace/next-themes';\n\n<ThemeProvider\n  onChange={async (theme) => {\n    await fetch('/api/me/theme', {\n      method: 'POST',\n      body: JSON.stringify({ theme }),\n    });\n  }}\n>\n  {children}\n</ThemeProvider>\n```\n\n### Force a theme on a specific route\n\n```tsx\n// app/print/layout.tsx\nimport { ThemeProvider } from '@teispace/next-themes';\n\nexport default function PrintLayout({ children }) {\n  return (\n    <ThemeProvider forcedTheme=\"light\" storage=\"none\" enableSystem={false}>\n      {children}\n    </ThemeProvider>\n  );\n}\n```\n\n### Multi-brand with per-brand defaults\n\n```tsx\n// app/[brand]/layout.tsx\nimport { ThemeProvider } from '@teispace/next-themes';\n\nconst BRAND_DEFAULTS: Record<string, { default: string; themes: string[] }> = {\n  acme:   { default: 'acme-light',   themes: ['acme-light', 'acme-dark'] },\n  globex: { default: 'globex-light', themes: ['globex-light', 'globex-dark'] },\n};\n\nexport default function BrandLayout({ children, params }) {\n  const cfg = BRAND_DEFAULTS[params.brand];\n  return (\n    <ThemeProvider themes={cfg.themes} defaultTheme={cfg.default}>\n      {children}\n    </ThemeProvider>\n  );\n}\n```\n\n### CSS variables driven by theme tokens\n\n```css\n:root        { --bg: 0 0% 100%; --fg: 0 0% 10%; }\n.dark        { --bg: 220 15% 7%; --fg: 0 0% 96%; }\n.sepia       { --bg: 40 30% 94%; --fg: 25 25% 20%; }\n\nbody {\n  background: hsl(var(--bg));\n  color: hsl(var(--fg));\n}\n```\n\n### Build a theme toggle group\n\n```tsx\n'use client';\nimport { useTheme } from '@teispace/next-themes';\n\nexport function ThemeToggle() {\n  const { theme, setTheme } = useTheme();\n  return (\n    <div role=\"group\" aria-label=\"Theme\">\n      {(['light', 'system', 'dark'] as const).map((t) => (\n        <button\n          key={t}\n          type=\"button\"\n          aria-pressed={theme === t}\n          onClick={() => setTheme(t)}\n        >\n          {t}\n        </button>\n      ))}\n    </div>\n  );\n}\n```\n\n### Access the theme in a non-React context\n\nImport the adapter directly — useful for vanilla scripts or helpers outside the React tree:\n\n```ts\nimport { resolveAdapter } from '@teispace/next-themes/adapters';\n\nconst adapter = resolveAdapter({ mode: 'hybrid', key: 'theme' });\nconst currentTheme = adapter.get(); // 'light' | 'dark' | 'system' | null\n```\n\nOr read the raw cookie on the server:\n\n```ts\nimport { readCookieFromString } from '@teispace/next-themes/server';\nconst theme = readCookieFromString(req.headers.get('cookie') ?? '', 'theme');\n```\n\n---\n\n## Troubleshooting / FAQ\n\n### I see a hydration warning on `<html>`\n\nAdd `suppressHydrationWarning` to your `<html>` tag. The library already does the right thing — the warning is inherent to any inline script that mutates attributes before hydration.\n\n### The first paint is still flashing\n\nCauses, in order of likelihood:\n\n1. **Script runs too late.** `useServerInsertedHTML` places the inline script at the next React flush boundary, which on streamed responses can be inside `<body>` — after some pixels paint. Switch to the [zero-flicker setup](#zero-flicker-setup-recommended-for-production): render `getThemeScript()` directly in `<head>` and pass `noScript` to your provider. This is the most reliable fix.\n2. **Storage isn't server-readable.** `storage=\"local\"` and `storage=\"session\"` are client-only. Switch to `'hybrid'` (default) or `'cookie'`.\n3. **`initialTheme` not wired.** Without it, the server renders with `defaultTheme`, which may disagree with the cookie-stored preference and cause a one-frame flip:\n   ```tsx\n   const initialTheme = await getTheme();\n   <ThemeProvider initialTheme={initialTheme ?? undefined}>\n   ```\n4. **Cookie blocked / expired.** Hybrid storage now self-heals: when the cookie is missing but localStorage has a value, the cookie is rewritten on read so the server sees it on the next request. If you still see a flash, check that the cookie isn't blocked by an iframe sandbox, ITP, or a CDN that strips `Set-Cookie`.\n\n### Theme briefly flips when navigating back from another page\n\nThis is the browser's bfcache (back/forward cache) showing a stale snapshot. The library now re-runs the inline script on `pageshow` when `event.persisted === true`, and the React store also re-reads storage at the same time. If you've forked the script or pinned an old version, upgrade.\n\n### The circular reveal doesn't expand from the click\n\n`origin: 'cursor'` uses the last pointerdown position. If you trigger `setTheme` from a keyboard event (e.g. a keyboard shortcut) there's no click; it falls back to viewport center. Pass explicit coordinates when you need deterministic origin:\n\n```ts\nsetTheme(next, { transition: { type: 'circular', origin: { x: 0, y: 0 } } });\n```\n\n### Tailwind's `dark:` utilities don't work\n\nEither import the v4 preset (`@import \"@teispace/next-themes/tailwind.css\";`) or set `darkMode: ['variant', ['&:where([data-theme=\"dark\"] *)', '&:where(.dark *)']]` in your Tailwind v3 config.\n\n### I get \"useTheme() called outside a ThemeProvider\"\n\nThe hook logs this in dev when `useContext(ThemeStoreContext)` returns `null` — i.e. there's no `<ThemeProvider>` ancestor in the React tree at the point `useTheme()` runs. The hook then returns inert defaults instead of throwing, so the page still renders. In React Strict Mode you'll see the message printed twice (one render per pass) — that's expected, not a second bug.\n\nIf your code clearly wraps the consumer in `<ThemeProvider>` and you still see this, check in order:\n\n1. **The consumer really is a descendant.** It's easy to read your tree and miss that the call lives in a parallel route slot, an `error.tsx` / `not-found.tsx` rendered above the provider, a server-side path (Route Handler, `metadata`, RSC running before the client provider mounts), or a portal that escapes the subtree. The provider only covers what's rendered as `children`.\n\n2. **Two copies of `@teispace/next-themes` in `node_modules`.** If a dependency pulls in its own copy at a different version, your code and that dependency import different `ThemeStoreContext` objects, so `useContext` on one returns `null` even though the other is mounted. Run `npm ls @teispace/next-themes` (or `pnpm why` / `yarn why`); if you see more than one entry, dedupe (`npm dedupe`, `pnpm dedupe`).\n\n3. **Stale build cache after upgrade.** `rm -rf node_modules .next && <your-pkg-mgr> install` rules this out.\n\n4. **Mixed entries are fine.** Importing `<ThemeProvider>` from `@teispace/next-themes` and `useTheme` from `@teispace/next-themes/client` (or vice versa) shares the same context — the subpaths re-export the same module — so this isn't the cause.\n\n### My CSP blocks the inline script\n\nPass a nonce:\n\n```tsx\nimport { headers } from 'next/headers';\n\nconst nonce = (await headers()).get('x-nonce') ?? undefined;\n<ThemeProvider nonce={nonce}>{children}</ThemeProvider>\n```\n\n### I need per-theme images but want zero flash on SSR\n\nUse CSS rather than `<ThemedImage>` for SSR-perfect switching:\n\n```css\n.logo-light { display: block; }\n.logo-dark  { display: none; }\nhtml[data-theme=\"dark\"] .logo-light { display: none; }\nhtml[data-theme=\"dark\"] .logo-dark  { display: block; }\n```\n\n```tsx\n<img className=\"logo-light\" src=\"/logo-light.svg\" alt=\"\" />\n<img className=\"logo-dark\"  src=\"/logo-dark.svg\"  alt=\"\" />\n```\n\nBoth are server-rendered; the inline script flips `data-theme` before first paint, so only the right one is ever visible.\n\n### Does it work with React Server Components?\n\nYes. The provider itself is a client component (as is any stateful hook provider), but you can call `getTheme()` and `setThemeCookie()` / `writeThemeCookie()` from RSC and Server Actions via the `/server` entry. The `<html>` in your root layout stays a server component.\n\n### How do I test it?\n\nThe package ships tests for the anti-FOUC script (direct execution in a sandbox), the store, adapters, hooks, components, the factory, and the codemod. If you're testing *your* integration:\n\n- Use `happy-dom` or `jsdom` (Node ≥ 22 users: pass `NODE_OPTIONS='--no-experimental-webstorage'` so your DOM impl's `Storage` isn't shadowed — the package does this for its own test suite and documents it here).\n- For Playwright, the anti-FOUC guarantee is observable as \"first painted frame has the correct theme\"; script evaluation happens before `DOMContentLoaded`.\n\n---\n\n## Performance & bundle sizes\n\nAll ESM, unminified — subject to your bundler's minification + gzip. React is externalized.\n\n| Entry | Minified (approx) | Notes |\n|---|---:|---|\n| `.` (Next.js) | ~3 KB | Includes `useServerInsertedHTML` path |\n| `/client` | ~2.9 KB | Inline-script path |\n| `/server` | ~2.2 KB | Cookie + client-hint helpers |\n| `/adapters` | ~0.3 KB | Re-exports only (tree-shakes to near zero) |\n| `/script` | ~0.1 KB | Standalone script builder |\n| `/tailwind` (JS) | ~0.5 KB | v3 config helper |\n| `tailwind.css` | raw CSS preset | Published unbundled |\n\nShared code (store, DOM, view transitions, cursor tracker) lives in tree-shakeable chunks; you only load what an entry imports.\n\n**Runtime overhead:**\n- `useSyncExternalStore` is React-native — no polyfill.\n- The inline anti-FOUC script is ~3.5 KB HTML-embedded (runs once per page load).\n- Cursor tracker is a single passive `pointerdown` listener on `document`, installed lazily on first provider mount.\n\n---\n\n## Browser support\n\n| Feature | Support |\n|---|---|\n| Core | All browsers supported by React 18+ |\n| `useSyncExternalStore` | React 18 native |\n| `matchMedia` + `Storage` | Evergreen + IE11 (with polyfills) |\n| Cookie storage | Evergreen + IE11 |\n| View Transitions | Chromium 111+, Safari 18+, Firefox n/a (graceful fallback) |\n| `Sec-CH-Prefers-Color-Scheme` | Chromium 93+ (opt-in), behind flag elsewhere |\n\nThe View Transitions path detects support and degrades to synchronous theme application where unsupported, with no visual glitches.\n\n---\n\n## Examples app\n\nA full Next.js 16 app with a runnable demo for every feature:\n\n```bash\n# from the monorepo root\nyarn workspace next-themes-examples dev\n```\n\nSee [`examples/next-themes/`](../../examples/next-themes). Each route maps to a section of this README.\n\n---\n\n## License\n\nMIT © Teispace\n\n> Server runtimes: the storage adapters only probe `localStorage` when a `document` exists, so Node 22+ prints no `--localstorage-file` warning during server renders or builds.\n","readmeFilename":"README.md"}