@witchcraft/ui 0.3.4 → 0.3.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/module.json +1 -1
- package/dist/module.mjs +1 -6
- package/dist/runtime/composables/useDarkMode.d.ts +44 -1
- package/dist/runtime/composables/useDarkMode.js +24 -7
- package/package.json +77 -77
- package/src/module.ts +1 -1
- package/src/runtime/components/LibDarkModeSwitcher/LibDarkModeSwitcher.stories.ts +49 -0
- package/src/runtime/composables/useDarkMode.ts +75 -7
package/dist/module.json
CHANGED
package/dist/module.mjs
CHANGED
|
@@ -12,11 +12,6 @@ import { unpluginIconViteOptions } from '../dist/runtime/build/unpluginIconViteO
|
|
|
12
12
|
import { themeConvertionOpts } from '../dist/runtime/tailwind/themeConvertionOpts.js';
|
|
13
13
|
import { theme } from '../dist/runtime/theme.js';
|
|
14
14
|
|
|
15
|
-
const dependencies = {
|
|
16
|
-
"reka-ui": "^2.5.0"};
|
|
17
|
-
const pkg = {
|
|
18
|
-
dependencies: dependencies};
|
|
19
|
-
|
|
20
15
|
const knownDirectives = ["vExtractRootEl", "vResizableCols", "vResizeObserver", "vResizableCols"];
|
|
21
16
|
const { resolve, resolvePath } = createResolver(import.meta.url);
|
|
22
17
|
const componentsInfo = globFiles([
|
|
@@ -51,7 +46,7 @@ const module = defineNuxtModule({
|
|
|
51
46
|
// defaults: unpluginIconViteOptions as any
|
|
52
47
|
// },
|
|
53
48
|
"reka-ui/nuxt": {
|
|
54
|
-
version:
|
|
49
|
+
version: "^2.5.0"
|
|
55
50
|
}
|
|
56
51
|
},
|
|
57
52
|
async setup(options, nuxt) {
|
|
@@ -10,13 +10,56 @@ import { type Ref } from "vue";
|
|
|
10
10
|
*
|
|
11
11
|
* Note that this should only be called once at the root of the app.
|
|
12
12
|
*/
|
|
13
|
-
export declare const useDarkMode: ({ useLocalStorage, darkModeOrder, isClientSide }?: DarkModeOptions) => DarkModeState & DarkModeCommands;
|
|
13
|
+
export declare const useDarkMode: ({ useLocalStorage, darkModeOrder, isClientSide, useViewTransition }?: DarkModeOptions) => DarkModeState & DarkModeCommands;
|
|
14
14
|
export declare const defaultDarkModeOrder: readonly ["system", "dark", "light"];
|
|
15
15
|
export type DarkModeOptions = {
|
|
16
16
|
useLocalStorage?: boolean | string;
|
|
17
17
|
darkModeOrder?: readonly ("system" | "dark" | "light")[];
|
|
18
18
|
/** True by default, should be passed import.meta.client if using nuxt, or false when running server side. */
|
|
19
19
|
isClientSide?: boolean;
|
|
20
|
+
/**
|
|
21
|
+
* Whether to use the view transition to animate the dark mode switch (you just need to add the css).
|
|
22
|
+
*
|
|
23
|
+
* Note that the transitition is NOT triggered if visually the mode does not change (e.g. system mode is dark and the user switches from system to dark, visually nothing changes so transitioning is skipped).
|
|
24
|
+
*
|
|
25
|
+
* There is an example in storybook. But basically:
|
|
26
|
+
*
|
|
27
|
+
* ```css
|
|
28
|
+
*
|
|
29
|
+
* #root { // the dark mode switcher works on the WRoot component not the html root
|
|
30
|
+
* view-transition-name: wroot;
|
|
31
|
+
* height: 100dvh;
|
|
32
|
+
* padding: 0;
|
|
33
|
+
* }
|
|
34
|
+
*
|
|
35
|
+
* ::view-transition-new(wroot) {
|
|
36
|
+
* animation: grow var(--story-anim-length) ease-in-out;
|
|
37
|
+
* animation-fill-mode: both;
|
|
38
|
+
* z-index: 2;
|
|
39
|
+
* mask: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40"><circle cx="20" cy="20" r="20" fill="white"/></svg>') center / 0 no-repeat;
|
|
40
|
+
* }
|
|
41
|
+
*
|
|
42
|
+
* ::view-transition-old(wroot) {
|
|
43
|
+
* animation: none;
|
|
44
|
+
* animation-fill-mode: both;
|
|
45
|
+
* z-index: 1;
|
|
46
|
+
* }
|
|
47
|
+
*
|
|
48
|
+
* @keyframes grow {
|
|
49
|
+
* from {
|
|
50
|
+
* mask-size: 0dvw;
|
|
51
|
+
* }
|
|
52
|
+
* to {
|
|
53
|
+
* mask-size: 300dvw;
|
|
54
|
+
* }
|
|
55
|
+
* }
|
|
56
|
+
* ```
|
|
57
|
+
*
|
|
58
|
+
* See https://theme-toggle.rdsx.dev/ for more ideas.
|
|
59
|
+
*
|
|
60
|
+
* @default true
|
|
61
|
+
*/
|
|
62
|
+
useViewTransition?: boolean;
|
|
20
63
|
};
|
|
21
64
|
export interface DarkModeCommands {
|
|
22
65
|
setDarkMode: (value: "dark" | "light" | "system") => void;
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import { computed, onMounted, provide, ref, watch } from "vue";
|
|
1
|
+
import { computed, nextTick, onMounted, provide, ref, watch } from "vue";
|
|
2
2
|
import { darkModeCommandsInjectionKey, darkModeStateInjectionKey, isDarkModeInjectionKey, manualDarkModeInjectionKey } from "../injectionKeys.js";
|
|
3
3
|
const defaultLocalStorageKey = "prefersColorSchemeDark";
|
|
4
4
|
const defaultOrder = ["system", "dark", "light"];
|
|
5
5
|
export const useDarkMode = ({
|
|
6
6
|
useLocalStorage = true,
|
|
7
7
|
darkModeOrder = defaultOrder,
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
isClientSide = true,
|
|
9
|
+
useViewTransition = true
|
|
10
10
|
} = {}) => {
|
|
11
11
|
const systemDarkMode = ref(false);
|
|
12
12
|
const manualDarkMode = ref(void 0);
|
|
@@ -22,13 +22,30 @@ export const useDarkMode = ({
|
|
|
22
22
|
function setDarkMode(value) {
|
|
23
23
|
manualDarkMode.value = value === "dark" ? true : value === "light" ? false : void 0;
|
|
24
24
|
}
|
|
25
|
+
function getNextValue() {
|
|
26
|
+
const index = darkModeOrder.indexOf(darkModeState.value);
|
|
27
|
+
return index === 2 ? darkModeOrder[0] : darkModeOrder[index + 1];
|
|
28
|
+
}
|
|
29
|
+
function _cycleDarkMode() {
|
|
30
|
+
setDarkMode(getNextValue());
|
|
31
|
+
}
|
|
25
32
|
function cycleDarkMode() {
|
|
33
|
+
if (!useViewTransition) {
|
|
34
|
+
_cycleDarkMode();
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
const nextValue = getNextValue();
|
|
26
38
|
const index = darkModeOrder.indexOf(darkModeState.value);
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
39
|
+
const systemDarkModeName = systemDarkMode.value ? "dark" : "light";
|
|
40
|
+
if (nextValue === "system" && systemDarkModeName === darkModeOrder[index]) {
|
|
41
|
+
_cycleDarkMode();
|
|
42
|
+
return;
|
|
31
43
|
}
|
|
44
|
+
if (!document.startViewTransition) _cycleDarkMode();
|
|
45
|
+
document.startViewTransition(async () => {
|
|
46
|
+
_cycleDarkMode();
|
|
47
|
+
await nextTick();
|
|
48
|
+
});
|
|
32
49
|
}
|
|
33
50
|
onMounted(() => {
|
|
34
51
|
window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change", ({ matches }) => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@witchcraft/ui",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.6",
|
|
4
4
|
"description": "Vue component library.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/runtime/main.lib.js",
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
"failOnWarn": false
|
|
50
50
|
},
|
|
51
51
|
"scripts": {
|
|
52
|
-
"prepare": "husky && pnpm gen:theme &&
|
|
52
|
+
"prepare": "husky && pnpm gen:theme && pnpm build",
|
|
53
53
|
"build": "nuxt-module-build prepare && nuxt-module-build build && nuxi generate playground",
|
|
54
54
|
"build:only": "nuxt-module-build build",
|
|
55
55
|
"dev:prepare": "nuxt-module-build build --stub && nuxt-module-build prepare && nuxi prepare playground",
|
|
@@ -73,9 +73,9 @@
|
|
|
73
73
|
"gen:theme": "echo src/runtime/build/generateTheme.ts"
|
|
74
74
|
},
|
|
75
75
|
"peerDependencies": {
|
|
76
|
-
"tailwindcss": "
|
|
77
|
-
"unplugin-icons": "
|
|
78
|
-
"vue": "
|
|
76
|
+
"tailwindcss": "catalog:",
|
|
77
|
+
"unplugin-icons": "catalog:",
|
|
78
|
+
"vue": "catalog:"
|
|
79
79
|
},
|
|
80
80
|
"peerDependenciesMeta": {
|
|
81
81
|
"tailwindcss": {
|
|
@@ -86,80 +86,80 @@
|
|
|
86
86
|
}
|
|
87
87
|
},
|
|
88
88
|
"dependencies": {
|
|
89
|
-
"@alanscodelog/utils": "
|
|
90
|
-
"@iconify/json": "
|
|
91
|
-
"@nuxt/kit": "
|
|
92
|
-
"@nuxt/schema": "
|
|
93
|
-
"@nuxt/types": "
|
|
94
|
-
"@tailwindcss/vite": "
|
|
95
|
-
"@witchcraft/nuxt-utils": "
|
|
96
|
-
"colord": "
|
|
97
|
-
"colorjs.io": "
|
|
98
|
-
"defu": "
|
|
99
|
-
"fast-glob": "
|
|
100
|
-
"metamorphosis": "
|
|
101
|
-
"reka-ui": "
|
|
102
|
-
"tailwind-merge": "
|
|
103
|
-
"unplugin-icons": "
|
|
104
|
-
"unplugin-vue-components": "
|
|
105
|
-
"vue-component-type-helpers": "
|
|
89
|
+
"@alanscodelog/utils": "catalog:",
|
|
90
|
+
"@iconify/json": "catalog:",
|
|
91
|
+
"@nuxt/kit": "catalog:",
|
|
92
|
+
"@nuxt/schema": "catalog:",
|
|
93
|
+
"@nuxt/types": "catalog:",
|
|
94
|
+
"@tailwindcss/vite": "catalog:",
|
|
95
|
+
"@witchcraft/nuxt-utils": "catalog:",
|
|
96
|
+
"colord": "catalog:",
|
|
97
|
+
"colorjs.io": "catalog:",
|
|
98
|
+
"defu": "catalog:",
|
|
99
|
+
"fast-glob": "catalog:",
|
|
100
|
+
"metamorphosis": "catalog:",
|
|
101
|
+
"reka-ui": "catalog:",
|
|
102
|
+
"tailwind-merge": "catalog:",
|
|
103
|
+
"unplugin-icons": "catalog:",
|
|
104
|
+
"unplugin-vue-components": "catalog:",
|
|
105
|
+
"vue-component-type-helpers": "catalog:"
|
|
106
106
|
},
|
|
107
107
|
"devDependencies": {
|
|
108
|
-
"@alanscodelog/commitlint-config": "
|
|
109
|
-
"@alanscodelog/eslint-config": "
|
|
110
|
-
"@alanscodelog/semantic-release-config": "
|
|
111
|
-
"@alanscodelog/tsconfigs": "
|
|
112
|
-
"@alanscodelog/vite-config": "
|
|
113
|
-
"@chromatic-com/storybook": "
|
|
114
|
-
"@commitlint/cli": "
|
|
115
|
-
"@internationalized/date": "
|
|
116
|
-
"@nuxt/eslint-config": "
|
|
117
|
-
"@nuxt/module-builder": "
|
|
118
|
-
"@nuxtjs/i18n": "
|
|
119
|
-
"@playwright/test": "
|
|
120
|
-
"@rollup/plugin-node-resolve": "
|
|
121
|
-
"@storybook/addon-a11y": "
|
|
122
|
-
"@storybook/addon-actions": "
|
|
123
|
-
"@storybook/addon-essentials": "
|
|
124
|
-
"@storybook/addon-interactions": "
|
|
125
|
-
"@storybook/addon-links": "
|
|
126
|
-
"@storybook/addon-storysource": "
|
|
127
|
-
"@storybook/blocks": "
|
|
128
|
-
"@storybook/manager-api": "
|
|
129
|
-
"@storybook/test": "
|
|
130
|
-
"@storybook/test-runner": "
|
|
131
|
-
"@storybook/vue3": "
|
|
132
|
-
"@storybook/vue3-vite": "
|
|
133
|
-
"@tailwindcss/cli": "
|
|
134
|
-
"@tailwindcss/postcss": "
|
|
135
|
-
"@types/node": "
|
|
136
|
-
"@vitejs/plugin-vue": "
|
|
137
|
-
"@vue/runtime-core": "
|
|
138
|
-
"@vue/runtime-dom": "
|
|
139
|
-
"@vueuse/components": "
|
|
140
|
-
"@vueuse/core": "
|
|
141
|
-
"autoprefixer": "
|
|
142
|
-
"concurrently": "
|
|
143
|
-
"eslint": "
|
|
144
|
-
"http-server": "
|
|
145
|
-
"husky": "
|
|
146
|
-
"indexit": "
|
|
147
|
-
"madge": "
|
|
148
|
-
"nuxt": "
|
|
149
|
-
"playwright": "
|
|
150
|
-
"playwright-core": "
|
|
151
|
-
"semantic-release": "
|
|
152
|
-
"storybook": "
|
|
153
|
-
"storybook-dark-mode": "
|
|
154
|
-
"tailwindcss": "
|
|
155
|
-
"ts-node": "
|
|
156
|
-
"typescript": "
|
|
157
|
-
"unbuild": "
|
|
158
|
-
"vite": "
|
|
159
|
-
"vite-tsconfig-paths": "
|
|
160
|
-
"vue": "
|
|
161
|
-
"vue-tsc": "
|
|
162
|
-
"wait-on": "
|
|
108
|
+
"@alanscodelog/commitlint-config": "catalog:",
|
|
109
|
+
"@alanscodelog/eslint-config": "catalog:",
|
|
110
|
+
"@alanscodelog/semantic-release-config": "catalog:",
|
|
111
|
+
"@alanscodelog/tsconfigs": "catalog:",
|
|
112
|
+
"@alanscodelog/vite-config": "catalog:",
|
|
113
|
+
"@chromatic-com/storybook": "catalog:",
|
|
114
|
+
"@commitlint/cli": "catalog:",
|
|
115
|
+
"@internationalized/date": "catalog:",
|
|
116
|
+
"@nuxt/eslint-config": "catalog:",
|
|
117
|
+
"@nuxt/module-builder": "catalog:",
|
|
118
|
+
"@nuxtjs/i18n": "catalog:",
|
|
119
|
+
"@playwright/test": "catalog:",
|
|
120
|
+
"@rollup/plugin-node-resolve": "catalog:",
|
|
121
|
+
"@storybook/addon-a11y": "catalog:",
|
|
122
|
+
"@storybook/addon-actions": "catalog:",
|
|
123
|
+
"@storybook/addon-essentials": "catalog:",
|
|
124
|
+
"@storybook/addon-interactions": "catalog:",
|
|
125
|
+
"@storybook/addon-links": "catalog:",
|
|
126
|
+
"@storybook/addon-storysource": "catalog:",
|
|
127
|
+
"@storybook/blocks": "catalog:",
|
|
128
|
+
"@storybook/manager-api": "catalog:",
|
|
129
|
+
"@storybook/test": "catalog:",
|
|
130
|
+
"@storybook/test-runner": "catalog:",
|
|
131
|
+
"@storybook/vue3": "catalog:",
|
|
132
|
+
"@storybook/vue3-vite": "catalog:",
|
|
133
|
+
"@tailwindcss/cli": "catalog:",
|
|
134
|
+
"@tailwindcss/postcss": "catalog:",
|
|
135
|
+
"@types/node": "catalog:",
|
|
136
|
+
"@vitejs/plugin-vue": "catalog:",
|
|
137
|
+
"@vue/runtime-core": "catalog:",
|
|
138
|
+
"@vue/runtime-dom": "catalog:",
|
|
139
|
+
"@vueuse/components": "catalog:",
|
|
140
|
+
"@vueuse/core": "catalog:",
|
|
141
|
+
"autoprefixer": "catalog:",
|
|
142
|
+
"concurrently": "catalog:",
|
|
143
|
+
"eslint": "catalog:",
|
|
144
|
+
"http-server": "catalog:",
|
|
145
|
+
"husky": "catalog:",
|
|
146
|
+
"indexit": "catalog:",
|
|
147
|
+
"madge": "catalog:",
|
|
148
|
+
"nuxt": "catalog:",
|
|
149
|
+
"playwright": "catalog:",
|
|
150
|
+
"playwright-core": "catalog:",
|
|
151
|
+
"semantic-release": "catalog:",
|
|
152
|
+
"storybook": "catalog:",
|
|
153
|
+
"storybook-dark-mode": "catalog:",
|
|
154
|
+
"tailwindcss": "catalog:",
|
|
155
|
+
"ts-node": "catalog:",
|
|
156
|
+
"typescript": "catalog:",
|
|
157
|
+
"unbuild": "catalog:",
|
|
158
|
+
"vite": "catalog:",
|
|
159
|
+
"vite-tsconfig-paths": "catalog:",
|
|
160
|
+
"vue": "catalog:",
|
|
161
|
+
"vue-tsc": "catalog:",
|
|
162
|
+
"wait-on": "catalog:"
|
|
163
163
|
},
|
|
164
164
|
"author": "Alan <alanscodelog@gmail.com>",
|
|
165
165
|
"repository": "https://github.com/witchcraftjs/ui",
|
package/src/module.ts
CHANGED
|
@@ -19,6 +19,7 @@ const meta: Meta<typeof LibDarkModeSwitcher> = {
|
|
|
19
19
|
export default meta
|
|
20
20
|
type Story = StoryObj<typeof LibDarkModeSwitcher>
|
|
21
21
|
|
|
22
|
+
|
|
22
23
|
export const Primary: Story = {
|
|
23
24
|
render: args => ({
|
|
24
25
|
components,
|
|
@@ -35,10 +36,15 @@ export const Primary: Story = {
|
|
|
35
36
|
@update:darkMode="darkMode = $event"
|
|
36
37
|
v-bind="{...args}"
|
|
37
38
|
></LibDarkModeSwitcher>
|
|
39
|
+
<!-- workaround for style tag not being allowed -->
|
|
40
|
+
<component is="style">
|
|
41
|
+
{{args.css}}
|
|
42
|
+
</component>
|
|
38
43
|
|
|
39
44
|
`
|
|
40
45
|
})
|
|
41
46
|
}
|
|
47
|
+
|
|
42
48
|
export const WithoutLabel: Story = {
|
|
43
49
|
...Primary,
|
|
44
50
|
args: {
|
|
@@ -46,3 +52,46 @@ export const WithoutLabel: Story = {
|
|
|
46
52
|
showLabel: false
|
|
47
53
|
}
|
|
48
54
|
}
|
|
55
|
+
|
|
56
|
+
export const WithViewTransitionApi: Story = {
|
|
57
|
+
...Primary,
|
|
58
|
+
args: {
|
|
59
|
+
...Primary.args,
|
|
60
|
+
css: `
|
|
61
|
+
:root {
|
|
62
|
+
--story-anim-length: 1s; /* Shorter for testing */
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
#root {
|
|
66
|
+
view-transition-name: wroot;
|
|
67
|
+
height: 100dvh;
|
|
68
|
+
padding: 0;
|
|
69
|
+
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
::view-transition-new(wroot) {
|
|
73
|
+
animation: grow var(--story-anim-length) ease-in-out;
|
|
74
|
+
animation-fill-mode: both;
|
|
75
|
+
z-index: 2;
|
|
76
|
+
mask: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40"><circle cx="20" cy="20" r="20" fill="white"/></svg>') center / 0 no-repeat;
|
|
77
|
+
mask-size: 50dvw;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
::view-transition-old(wroot) {
|
|
81
|
+
animation: none;
|
|
82
|
+
animation-fill-mode: both;
|
|
83
|
+
z-index: 1;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
@keyframes grow {
|
|
87
|
+
from {
|
|
88
|
+
mask-size: 0dvw;
|
|
89
|
+
}
|
|
90
|
+
to {
|
|
91
|
+
mask-size: 300dvw;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
`
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { computed, onMounted, provide, type Ref, ref, watch } from "vue"
|
|
1
|
+
import { computed, nextTick, onMounted, provide, type Ref, ref, watch } from "vue"
|
|
2
2
|
|
|
3
3
|
import { darkModeCommandsInjectionKey, darkModeStateInjectionKey, isDarkModeInjectionKey, manualDarkModeInjectionKey } from "../injectionKeys.js"
|
|
4
4
|
|
|
@@ -19,8 +19,9 @@ const defaultOrder = ["system", "dark", "light"] as const
|
|
|
19
19
|
export const useDarkMode = ({
|
|
20
20
|
useLocalStorage = true,
|
|
21
21
|
darkModeOrder = defaultOrder,
|
|
22
|
-
|
|
23
|
-
isClientSide = true
|
|
22
|
+
|
|
23
|
+
isClientSide = true,
|
|
24
|
+
useViewTransition = true
|
|
24
25
|
}: DarkModeOptions = {}): DarkModeState & DarkModeCommands => {
|
|
25
26
|
const systemDarkMode = ref(false)
|
|
26
27
|
const manualDarkMode = ref<boolean | undefined>(undefined)
|
|
@@ -48,14 +49,38 @@ export const useDarkMode = ({
|
|
|
48
49
|
? false
|
|
49
50
|
: undefined
|
|
50
51
|
}
|
|
52
|
+
|
|
53
|
+
function getNextValue(): "dark" | "light" | "system" {
|
|
54
|
+
const index = darkModeOrder.indexOf(darkModeState.value)
|
|
55
|
+
|
|
56
|
+
return index === 2
|
|
57
|
+
? darkModeOrder[0]!
|
|
58
|
+
: darkModeOrder[index + 1]!
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function _cycleDarkMode(): void {
|
|
62
|
+
setDarkMode(getNextValue())
|
|
63
|
+
}
|
|
64
|
+
|
|
51
65
|
function cycleDarkMode(): void {
|
|
66
|
+
if (!useViewTransition) {
|
|
67
|
+
_cycleDarkMode()
|
|
68
|
+
return
|
|
69
|
+
}
|
|
70
|
+
const nextValue = getNextValue()
|
|
52
71
|
const index = darkModeOrder.indexOf(darkModeState.value)
|
|
72
|
+
const systemDarkModeName = systemDarkMode.value ? "dark" : "light"
|
|
53
73
|
|
|
54
|
-
if (
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
74
|
+
if (nextValue === "system" && systemDarkModeName === darkModeOrder[index]) {
|
|
75
|
+
// don't do view transitions if we're not really transitioning
|
|
76
|
+
_cycleDarkMode()
|
|
77
|
+
return
|
|
58
78
|
}
|
|
79
|
+
if (!document.startViewTransition) _cycleDarkMode()
|
|
80
|
+
document.startViewTransition(async () => {
|
|
81
|
+
_cycleDarkMode()
|
|
82
|
+
await nextTick()
|
|
83
|
+
})
|
|
59
84
|
}
|
|
60
85
|
|
|
61
86
|
onMounted(() => {
|
|
@@ -111,6 +136,49 @@ export type DarkModeOptions = {
|
|
|
111
136
|
darkModeOrder?: readonly ("system" | "dark" | "light")[]
|
|
112
137
|
/** True by default, should be passed import.meta.client if using nuxt, or false when running server side. */
|
|
113
138
|
isClientSide?: boolean
|
|
139
|
+
/**
|
|
140
|
+
* Whether to use the view transition to animate the dark mode switch (you just need to add the css).
|
|
141
|
+
*
|
|
142
|
+
* Note that the transitition is NOT triggered if visually the mode does not change (e.g. system mode is dark and the user switches from system to dark, visually nothing changes so transitioning is skipped).
|
|
143
|
+
*
|
|
144
|
+
* There is an example in storybook. But basically:
|
|
145
|
+
*
|
|
146
|
+
* ```css
|
|
147
|
+
*
|
|
148
|
+
* #root { // the dark mode switcher works on the WRoot component not the html root
|
|
149
|
+
* view-transition-name: wroot;
|
|
150
|
+
* height: 100dvh;
|
|
151
|
+
* padding: 0;
|
|
152
|
+
* }
|
|
153
|
+
*
|
|
154
|
+
* ::view-transition-new(wroot) {
|
|
155
|
+
* animation: grow var(--story-anim-length) ease-in-out;
|
|
156
|
+
* animation-fill-mode: both;
|
|
157
|
+
* z-index: 2;
|
|
158
|
+
* mask: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40"><circle cx="20" cy="20" r="20" fill="white"/></svg>') center / 0 no-repeat;
|
|
159
|
+
* }
|
|
160
|
+
*
|
|
161
|
+
* ::view-transition-old(wroot) {
|
|
162
|
+
* animation: none;
|
|
163
|
+
* animation-fill-mode: both;
|
|
164
|
+
* z-index: 1;
|
|
165
|
+
* }
|
|
166
|
+
*
|
|
167
|
+
* @keyframes grow {
|
|
168
|
+
* from {
|
|
169
|
+
* mask-size: 0dvw;
|
|
170
|
+
* }
|
|
171
|
+
* to {
|
|
172
|
+
* mask-size: 300dvw;
|
|
173
|
+
* }
|
|
174
|
+
* }
|
|
175
|
+
* ```
|
|
176
|
+
*
|
|
177
|
+
* See https://theme-toggle.rdsx.dev/ for more ideas.
|
|
178
|
+
*
|
|
179
|
+
* @default true
|
|
180
|
+
*/
|
|
181
|
+
useViewTransition?: boolean
|
|
114
182
|
}
|
|
115
183
|
|
|
116
184
|
export interface DarkModeCommands {
|