{"_id":"@brustack/vue-theme-transitions","_rev":"7-12da6f6db6c10098de8c1e7df219612b","name":"@brustack/vue-theme-transitions","dist-tags":{"latest":"2.1.3"},"versions":{"1.0.0":{"name":"@brustack/vue-theme-transitions","version":"1.0.0","keywords":["vue","vue3","composable","theme","theme-toggle","theme-switcher","dark-mode","dark-theme","view-transitions","view-transitions-api","spread","fade","transition","animation"],"author":{"name":"Bruno Neckel"},"license":"MIT","_id":"@brustack/vue-theme-transitions@1.0.0","maintainers":[{"name":"bncodes","email":"neckel.bw@gmail.com"}],"homepage":"https://github.com/brustack/theme-transitions#readme","bugs":{"url":"https://github.com/brustack/theme-transitions/issues"},"dist":{"shasum":"8aa3bd1a5280e87b2868cc6a71c307ac7e2f0cff","tarball":"https://registry.npmjs.org/@brustack/vue-theme-transitions/-/vue-theme-transitions-1.0.0.tgz","fileCount":6,"integrity":"sha512-02ipxzpd40QIvvaF/es7zjDD2/65nUodJgomKH9BufOx1zfdL6sxGlACAuxBW6woIfyRYVmM7J2o4txlCEGFYA==","signatures":[{"sig":"MEMCHxsE3iEquJR810GtBqLupKiFthfdgkoO+MgsQ4IQrDICIGU5pXspbNnw0y5kYInCwyNdR4v5etonrCD74h/urX3A","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":8005},"main":"./dist/index.mjs","type":"module","types":"./dist/index.d.mts","exports":{".":{"types":"./dist/index.d.mts","import":"./dist/index.mjs"}},"gitHead":"a5dce7075566e8e35cacb4793ef279b95cf12c08","scripts":{"build":"unbuild","typecheck":"tsc --noEmit","prepublishOnly":"npm run build"},"_npmUser":{"name":"bncodes","email":"neckel.bw@gmail.com"},"repository":{"url":"git+https://github.com/brustack/theme-transitions.git","type":"git","directory":"packages/vue"},"_npmVersion":"11.16.0","description":"Vue 3 composable for animated dark/light theme transitions using the View Transitions API","directories":{},"_nodeVersion":"24.18.0","dependencies":{"@brustack/theme-transitions-core":"^1.0.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vue":"^3.5.40","happy-dom":"^20.11.1","@vue/test-utils":"^2.4.11"},"peerDependencies":{"vue":"^3.5.0"},"_npmOperationalInternal":{"tmp":"tmp/vue-theme-transitions_1.0.0_1785969657543_0.778937194120441","host":"s3://npm-registry-packages-npm-production"}},"2.0.0":{"name":"@brustack/vue-theme-transitions","version":"2.0.0","keywords":["vue","vue3","composable","theme","theme-toggle","theme-switcher","dark-mode","dark-theme","view-transitions","view-transitions-api","spread","fade","transition","animation"],"author":{"name":"Bruno Neckel"},"license":"MIT","_id":"@brustack/vue-theme-transitions@2.0.0","maintainers":[{"name":"bncodes","email":"neckel.bw+bncodes@gmail.com"},{"name":"brunoneckel","email":"neckel.bw@gmail.com"}],"homepage":"https://github.com/brustack/theme-transitions#readme","bugs":{"url":"https://github.com/brustack/theme-transitions/issues"},"dist":{"shasum":"76e3b6581655dbf3db46af00ad06417baba19e0a","tarball":"https://registry.npmjs.org/@brustack/vue-theme-transitions/-/vue-theme-transitions-2.0.0.tgz","fileCount":6,"integrity":"sha512-rG0foUZWLNZJLfU8ElL2qQZlR+uOmt1qyNgbzrTC2bfnUp9H/xiy94fMYkBbTSA11BdS85WirhnW2rWZjZ8Low==","signatures":[{"sig":"MEUCIG9SC4YZkidhypXk9o8XhuKk3F1no89tUpRlHKGsiJK+AiEAs6u/W0SrEkbO0gGCzJoO0Um1SbrkhR36omTlQ8fWet8=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":11386},"main":"./dist/index.mjs","type":"module","types":"./dist/index.d.mts","exports":{".":{"types":"./dist/index.d.mts","import":"./dist/index.mjs"}},"gitHead":"c069b2835f557aa987344894b7fafc3c904cca1c","scripts":{"build":"unbuild","typecheck":"tsc --noEmit","prepublishOnly":"npm run build"},"_npmUser":{"name":"brunoneckel","email":"neckel.bw@gmail.com"},"repository":{"url":"git+https://github.com/brustack/theme-transitions.git","type":"git","directory":"packages/vue"},"_npmVersion":"11.16.0","description":"Vue 3 composable for animated dark/light theme transitions using the View Transitions API","directories":{},"_nodeVersion":"24.18.0","dependencies":{"@brustack/theme-transitions-core":"^2.0.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vue":"^3.5.40","happy-dom":"^20.11.1","@vue/test-utils":"^2.4.11"},"peerDependencies":{"vue":"^3.5.0"},"_npmOperationalInternal":{"tmp":"tmp/vue-theme-transitions_2.0.0_1786154608523_0.013509603388623725","host":"s3://npm-registry-packages-npm-production"}},"2.1.0":{"name":"@brustack/vue-theme-transitions","version":"2.1.0","keywords":["vue","vue3","composable","theme","theme-toggle","theme-switcher","dark-mode","dark-theme","view-transitions","view-transitions-api","spread","fade","transition","animation"],"author":{"name":"Bruno Neckel"},"license":"MIT","_id":"@brustack/vue-theme-transitions@2.1.0","maintainers":[{"name":"bncodes","email":"neckel.bw+bncodes@gmail.com"},{"name":"brunoneckel","email":"neckel.bw@gmail.com"}],"homepage":"https://github.com/brustack/theme-transitions#readme","bugs":{"url":"https://github.com/brustack/theme-transitions/issues"},"dist":{"shasum":"3b7a00193ae9c0ade63c28f75c31131f61d76c93","tarball":"https://registry.npmjs.org/@brustack/vue-theme-transitions/-/vue-theme-transitions-2.1.0.tgz","fileCount":6,"integrity":"sha512-yqr9T/hjMWUP8ayRZUQTKiK0tK8K1ghDlJrFIoa3tqvchzVhtRnzTBgM32XwiJf81fwqJjkd8WUuLvkC6H/rKQ==","signatures":[{"sig":"MEYCIQC/xVDfweRlk8zd6fRmPP2mzvUpMK1KPeFZH06gOxiuzQIhAJnX46pwsjPhVR58BBvtngJpjw9JwcG/j/5rr9o7bzFA","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":11631},"main":"./dist/index.mjs","type":"module","types":"./dist/index.d.mts","exports":{".":{"types":"./dist/index.d.mts","import":"./dist/index.mjs"}},"gitHead":"337469cc20d9eb7f8cd87f6e67eeb6037673146a","scripts":{"build":"unbuild","typecheck":"tsc --noEmit","prepublishOnly":"npm run build"},"_npmUser":{"name":"brunoneckel","email":"neckel.bw@gmail.com"},"repository":{"url":"git+https://github.com/brustack/theme-transitions.git","type":"git","directory":"packages/vue"},"_npmVersion":"11.16.0","description":"Vue 3 composable for animated dark/light theme transitions using the View Transitions API","directories":{},"_nodeVersion":"24.18.0","dependencies":{"@brustack/theme-transitions-core":"^2.1.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vue":"^3.5.40","happy-dom":"^20.11.1","@vue/test-utils":"^2.4.11"},"peerDependencies":{"vue":"^3.5.0"},"_npmOperationalInternal":{"tmp":"tmp/vue-theme-transitions_2.1.0_1786170493852_0.2777377098642999","host":"s3://npm-registry-packages-npm-production"}},"2.1.1":{"name":"@brustack/vue-theme-transitions","version":"2.1.1","keywords":["vue","vue3","composable","theme","theme-toggle","theme-switcher","dark-mode","dark-theme","view-transitions","view-transitions-api","spread","fade","transition","animation","custom-themes"],"author":{"name":"Bruno Neckel"},"license":"MIT","_id":"@brustack/vue-theme-transitions@2.1.1","maintainers":[{"name":"bncodes","email":"neckel.bw+bncodes@gmail.com"},{"name":"brunoneckel","email":"neckel.bw@gmail.com"}],"homepage":"https://github.com/brustack/theme-transitions#readme","bugs":{"url":"https://github.com/brustack/theme-transitions/issues"},"dist":{"shasum":"ad9f14698f0cb6cd92cbb71c799c33746f8f55dc","tarball":"https://registry.npmjs.org/@brustack/vue-theme-transitions/-/vue-theme-transitions-2.1.1.tgz","fileCount":6,"integrity":"sha512-NFlyi2J2a7t3pC5K70kd+Pz5/dcoI68Z4dh99bJGnSAsX/cOhE3eTWCGdBhuN3xvG2ZSOw0S8NSipkVS2Egcsw==","signatures":[{"sig":"MEQCIE/eQiYpWOJ0MA8k5A3CYJZJkBmhQHlkhEGZMJOH7ZVdAiAsUP9OxlfYmbzAFWQO2ZN17uZpF+R9VD4bY12zUNPuDA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@brustack%2fvue-theme-transitions@2.1.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":11553},"main":"./dist/index.mjs","type":"module","types":"./dist/index.d.mts","exports":{".":{"types":"./dist/index.d.mts","import":"./dist/index.mjs"}},"gitHead":"2bc2a22f2df2e0e2bfdc95948d058b063b65da06","scripts":{"build":"unbuild","typecheck":"tsc --noEmit","prepublishOnly":"npm run build"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:8b20b254-9abb-4484-86a4-fbcec56c2bf2"}},"repository":{"url":"git+https://github.com/brustack/theme-transitions.git","type":"git","directory":"packages/vue"},"_npmVersion":"11.16.0","description":"Vue 3 composable for animated theme transitions using the View Transitions API","directories":{},"_nodeVersion":"24.18.0","dependencies":{"@brustack/theme-transitions-core":"^2.2.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vue":"^3.5.40","happy-dom":"^20.11.1","@vue/test-utils":"^2.4.11"},"peerDependencies":{"vue":"^3.5.0"},"_npmOperationalInternal":{"tmp":"tmp/vue-theme-transitions_2.1.1_1786252834570_0.8777618576417232","host":"s3://npm-registry-packages-npm-production"}},"2.1.2":{"name":"@brustack/vue-theme-transitions","version":"2.1.2","keywords":["vue","vue3","composable","theme","theme-toggle","theme-switcher","dark-mode","dark-theme","view-transitions","view-transitions-api","spread","fade","transition","animation","custom-themes"],"author":{"name":"Bruno Neckel"},"license":"MIT","_id":"@brustack/vue-theme-transitions@2.1.2","maintainers":[{"name":"bncodes","email":"neckel.bw+bncodes@gmail.com"},{"name":"brunoneckel","email":"neckel.bw@gmail.com"}],"homepage":"https://github.com/brustack/theme-transitions#readme","bugs":{"url":"https://github.com/brustack/theme-transitions/issues"},"dist":{"shasum":"f1b57746eb99555b3c15dcf202e690da43c335cf","tarball":"https://registry.npmjs.org/@brustack/vue-theme-transitions/-/vue-theme-transitions-2.1.2.tgz","fileCount":6,"integrity":"sha512-RrhtfeIB59sRLq5HF+l7SFddpb5l5JpmgOfxhFZq9DTnKUcd/eDNSAS+Tycg2tT9qXnN4ZuLjceKkKYhKzN30Q==","signatures":[{"sig":"MEUCIQC80s3MZAMGbVlG+gpqKQmdd/EeJxU1EFFWXs+y1/sJbAIgFqTguEv4D7kTZJsjBDbwrr4r2sijpO7amN92Irh/qMM=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@brustack%2fvue-theme-transitions@2.1.2","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":11553},"main":"./dist/index.mjs","type":"module","types":"./dist/index.d.mts","exports":{".":{"types":"./dist/index.d.mts","import":"./dist/index.mjs"}},"gitHead":"4e1a122fcbdd3e99860a2081ba60873fbd15d0d2","scripts":{"build":"unbuild","typecheck":"tsc --noEmit","prepublishOnly":"npm run build"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:8b20b254-9abb-4484-86a4-fbcec56c2bf2"}},"repository":{"url":"git+https://github.com/brustack/theme-transitions.git","type":"git","directory":"packages/vue"},"_npmVersion":"11.16.0","description":"Vue 3 composable for animated theme transitions using the View Transitions API","directories":{},"_nodeVersion":"24.18.0","dependencies":{"@brustack/theme-transitions-core":"^3.0.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vue":"^3.5.40","happy-dom":"^20.11.1","@vue/test-utils":"^2.4.11"},"peerDependencies":{"vue":"^3.5.0"},"_npmOperationalInternal":{"tmp":"tmp/vue-theme-transitions_2.1.2_1786264571703_0.8556486231792411","host":"s3://npm-registry-packages-npm-production"}},"2.1.3":{"name":"@brustack/vue-theme-transitions","version":"2.1.3","description":"Vue 3 composable for animated theme transitions using the View Transitions API","author":{"name":"Bruno Neckel"},"license":"MIT","type":"module","sideEffects":false,"main":"./dist/index.mjs","types":"./dist/index.d.mts","exports":{".":{"types":"./dist/index.d.mts","import":"./dist/index.mjs"}},"repository":{"type":"git","url":"git+https://github.com/brustack/theme-transitions.git","directory":"packages/vue"},"publishConfig":{"access":"public"},"peerDependencies":{"vue":"^3.5.0"},"dependencies":{"@brustack/theme-transitions-core":"^3.1.0"},"devDependencies":{"@vue/test-utils":"^2.4.11","happy-dom":"^20.11.1","vue":"^3.5.40"},"scripts":{"build":"unbuild","prepublishOnly":"npm run build","typecheck":"tsc --noEmit"},"keywords":["vue","vue3","composable","theme","theme-toggle","theme-switcher","dark-mode","dark-theme","view-transitions","view-transitions-api","spread","fade","transition","animation","custom-themes"],"gitHead":"4845a776a8ab12fe65a58024ee8fbb6ba23d75fd","_id":"@brustack/vue-theme-transitions@2.1.3","bugs":{"url":"https://github.com/brustack/theme-transitions/issues"},"homepage":"https://github.com/brustack/theme-transitions#readme","_nodeVersion":"24.19.0","_npmVersion":"11.17.0","dist":{"integrity":"sha512-CM81LlAsMA8An7/Qs9xwNjT3QG2Y5GOmRJfJpxPzb9Ff6aOXOEQZFZdGEfnrpKZK6NkMdq+TVh5p/tM6GL5saw==","shasum":"6c86ea27479d85757c9e27acac5cb953ae3d526f","tarball":"https://registry.npmjs.org/@brustack/vue-theme-transitions/-/vue-theme-transitions-2.1.3.tgz","fileCount":6,"unpackedSize":11362,"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@brustack%2fvue-theme-transitions@2.1.3","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIB78H/8+mU6Cm7aa9d2fphIJpG4Pb0apl7+QK4tgjZK+AiBBZ/Dae7Vc3u/jZ30SOo8HwfrzwTrzOaisnBZ0nEt5Cg=="}]},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:8b20b254-9abb-4484-86a4-fbcec56c2bf2"}},"directories":{},"maintainers":[{"name":"bncodes","email":"neckel.bw+bncodes@gmail.com"},{"name":"brunoneckel","email":"neckel.bw@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/vue-theme-transitions_2.1.3_1786564426045_0.46165121436896994"},"_hasShrinkwrap":false}},"time":{"created":"2026-08-05T22:40:57.346Z","modified":"2026-08-12T19:53:46.562Z","1.0.0":"2026-08-05T22:40:57.700Z","2.0.0":"2026-08-08T02:03:28.665Z","2.1.0":"2026-08-08T06:28:14.015Z","2.1.1":"2026-08-09T05:20:34.709Z","2.1.2":"2026-08-09T08:36:11.913Z","2.1.3":"2026-08-12T19:53:46.262Z"},"bugs":{"url":"https://github.com/brustack/theme-transitions/issues"},"author":{"name":"Bruno Neckel"},"license":"MIT","homepage":"https://github.com/brustack/theme-transitions#readme","keywords":["vue","vue3","composable","theme","theme-toggle","theme-switcher","dark-mode","dark-theme","view-transitions","view-transitions-api","spread","fade","transition","animation","custom-themes"],"repository":{"type":"git","url":"git+https://github.com/brustack/theme-transitions.git","directory":"packages/vue"},"description":"Vue 3 composable for animated theme transitions using the View Transitions API","maintainers":[{"name":"bncodes","email":"neckel.bw+bncodes@gmail.com"},{"name":"brunoneckel","email":"neckel.bw@gmail.com"}],"readme":"# vue-theme-transitions\n\n[![made by brustack](https://img.shields.io/badge/MADE%20BY%20brustack-000000.svg?style=for-the-badge&labelColor=000&logo=data%3Aimage%2Fsvg%2Bxml%3Bbase64%2CPHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyMjYuNzcgMjI2Ljc3Ij48cG9seWdvbiBmaWxsPSIjRjRGMkVEIiBwb2ludHM9IjE1My43MyA4My4zOSAxNTMuNzMgMTUzLjczIDgzLjM5IDE1My43MyA4My4zOSAyMTMuNzMgMjEzLjczIDIxMy43MyAyMTMuNzMgODMuMzkgMTUzLjczIDgzLjM5Ii8%2BPHJlY3QgZmlsbD0iI0Y0RjJFRCIgeD0iODMuMzkiIHk9IjEzLjA0IiB3aWR0aD0iNjAiIGhlaWdodD0iNjAiLz48cmVjdCBmaWxsPSIjRjRGMkVEIiB4PSIxMy4wNCIgeT0iODMuMzkiIHdpZHRoPSI2MCIgaGVpZ2h0PSI2MCIvPjxyZWN0IGZpbGw9IiNGNEYyRUQiIHg9IjgzLjM5IiB5PSI4My4zOSIgd2lkdGg9IjYwIiBoZWlnaHQ9IjYwIi8%2BPC9zdmc%2BCg%3D%3D)](https://github.com/brustack)\n[![npm version](https://img.shields.io/npm/v/@brustack/vue-theme-transitions.svg?style=for-the-badge&labelColor=000000)](https://www.npmjs.com/package/@brustack/vue-theme-transitions)\n[![license](https://img.shields.io/npm/l/@brustack/vue-theme-transitions.svg?style=for-the-badge&labelColor=000000)](https://github.com/brustack/theme-transitions/blob/main/packages/vue/LICENSE)\n\nVue composable for animated theme transitions using the View Transitions API.\n\n- ✅ Multiple effects to choose from\n- ✅ Zero flash of the wrong theme on load\n- ✅ Syncs automatically with OS `prefers-color-scheme`\n- ✅ Custom themes beyond light/dark\n- ✅ Origin auto-derived from the click event, bind `toggleTheme` straight to `@click`\n- ✅ No Context, no Provider, just a composable\n\n<br>\n\n<p align=\"center\">\n  <img src=\"../../.github/assets/demo.gif\" alt=\"Demo: clicking anywhere on the page triggers an animated theme transition originating from the cursor\" />\n</p>\n\n<p align=\"center\">Check out the <a href=\"https://theme-transitions.brustack.dev\">Live Example</a> to try it for yourself.</p>\n\n## Install\n\n```sh\nnpm install @brustack/vue-theme-transitions\n# or\npnpm add @brustack/vue-theme-transitions\n# or\nyarn add @brustack/vue-theme-transitions\n```\n\nPrefer to see it running first?\n\n```sh\ngit clone https://github.com/brustack/theme-transitions.git\ncd theme-transitions\nnpm run install:vue-demo\nnpm run dev:vue-demo\n```\n\n## Usage\n\n```vue\n<script setup lang=\"ts\">\nimport { useThemeTransition } from '@brustack/vue-theme-transitions';\nimport '@brustack/theme-transitions-core/style.css';\n\nconst { theme, isAnimating, toggleTheme } = useThemeTransition();\n</script>\n\n<template>\n  <button :disabled=\"isAnimating\" @click=\"toggleTheme\">\n    {{ theme }}\n  </button>\n</template>\n```\n\nBinding `toggleTheme` directly to `@click` works because it accepts the native `MouseEvent` and derives the spread effect's origin from the click position automatically. No import from the core package needed.\n\n## Styling\n\n`useThemeTransition` applies the current theme's name (`dark`, `light`, or a custom name, see Custom themes below) as a class on `<html>`. Style your palette off that class with any approach.\n\n### CSS variables\n\n```css\n:root {\n  --bg: #ffffff;\n  --text: #111111;\n}\n\nhtml.dark {\n  --bg: #0b0b10;\n  --text: #f4f2ed;\n}\n\nhtml.sepia {\n  --bg: #f4ecd8;\n  --text: #4b3621;\n}\n\nbody {\n  background: var(--bg);\n  color: var(--text);\n}\n```\n\n### Tailwind\n\nSet `darkMode: 'class'` in your Tailwind config (see Install above), then map your color tokens to the CSS variables above:\n\n```js\n// tailwind.config.js\nmodule.exports = {\n  darkMode: 'class',\n  theme: {\n    extend: {\n      colors: {\n        bg: 'var(--bg)',\n        text: 'var(--text)',\n      },\n    },\n  },\n};\n```\n\n## Configuration (optional)\n\n| Variant | `duration` | `easing` |\n|---|:---:|:---:|\n| `spread` | `'1s'` | ❌ |\n| `fade` (default) | `'400ms'` | `'ease'` |\n| `none` | ❌ | ❌ |\n\n```ts\nuseThemeTransition({ variant: 'spread', duration: '1s' })\n```\n\nThe first call in the app sets the shared default. Pass a `MouseEvent` (as shown in Usage) or an options object to `toggleTheme`/`setTheme` to override just that one call.\n\n### Custom themes\n\nRegister extra theme names beyond `light`/`dark`/`system` via `themes`:\n\n```ts\nuseThemeTransition({ themes: ['sepia', 'sunset'] })\n```\n\n`setTheme('sepia')` then applies a `sepia` class the same way `light`/`dark` do (see Styling above). The composable's `themes` ref always includes `['light', 'dark', 'system', ...your custom names]`, useful for building a theme switcher. `toggleTheme()` is unaffected, it always flips between `light` and `dark`.\n\n## API\n\n| | |\n|---|---|\n| `theme` | Current resolved theme: `'light'`, `'dark'`, or a custom theme name |\n| `mode` | Current preference: `'light'`, `'dark'`, `'system'`, or a custom theme name |\n| `isAnimating` | `true` while a transition is running |\n| `themes` | All registered theme names: `['light', 'dark', 'system', ...custom]` |\n| `toggleTheme(eventOrOptions?)` | Switch between light and dark |\n| `setTheme(mode, eventOrOptions?)` | Set `light`, `dark`, `system`, or a custom theme name |\n\n## Vite plugin\n\nRegister the anti-flash init script in `vite.config.ts`:\n\n```ts\nimport { defineConfig } from 'vite';\nimport { themeTransitions } from '@brustack/theme-transitions-core/vite';\n\nexport default defineConfig({\n  plugins: [themeTransitions()],\n});\n```\n\nOptionally, pass the same options as above so every `useThemeTransition()` call in the app picks them up without repeating them:\n\n```ts\nplugins: [themeTransitions({ variant: 'spread', duration: '1s' })],\n```\n\n## Other bundlers\n\nNot using Vite? `themeTransitions()` is a thin wrapper around two functions the core package exports, so you can get the same anti-flash behavior with any bundler by calling them directly.\n\nWith webpack and `html-webpack-plugin`:\n\n```js\nconst { buildColorModeInitScript } = require('@brustack/theme-transitions-core');\n\nnew HtmlWebpackPlugin({\n  templateParameters: { themeInitScript: buildColorModeInitScript() },\n});\n```\n\n```html\n<!-- in the HTML template, inside <head> -->\n<script><%= htmlWebpackPlugin.options.templateParameters.themeInitScript %></script>\n```\n\nThe script must run in `<head>`, before the page paints, regardless of where your bundle's own `<script>` tags are injected. To also set app-wide default effect options (the same thing the Vite plugin's argument does), prepend `buildConfigInitScript(options)` (which sets `window.__themeConfig`) to the same string.\n\nWebpack also needs a CSS rule that reaches into `node_modules` for the core package's stylesheet. If your existing `.css` rule excludes `node_modules` (common when scoping CSS Modules to your own source), add its path to that rule's `include`:\n\n```js\n{\n  test: /\\.css$/,\n  include: [path.resolve(__dirname, 'node_modules/@brustack/theme-transitions-core')],\n  use: ['style-loader', 'css-loader'],\n}\n```\n\n## Notes\n\n- This package has no SSR-specific handling. It targets plain client-side Vue 3 apps.\n\n## Known issues\n\n- Chrome 150 has a regression where the `spread` effect's clip-path animation can render from the wrong position after the browser window moves between displays with different DPI/scaling. This is a Chrome bug, not something this package can work around. It's already fixed upstream and verified in Chrome Canary; the fix should reach the Stable channel in a future release. See [Chromium issue #535696703](https://issues.chromium.org/issues/535696703).\n","readmeFilename":"README.md"}