Skip to content

Commit

Permalink
feat(useColorMode): expose state to the ref, deprecated emitAuto (#…
Browse files Browse the repository at this point in the history
…2980)

Co-authored-by: Anthony Fu <anthonyfu117@hotmail.com>
  • Loading branch information
Waleed-KH and antfu committed Apr 22, 2023
1 parent 4bb5bf0 commit a1bef49
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 47 deletions.
10 changes: 5 additions & 5 deletions packages/core/useColorMode/index.test.ts
Expand Up @@ -117,10 +117,10 @@ describe('useColorMode', () => {
expect(htmlEl?.className).toMatch(/dark/)
})

it('should use state to access mode & preference', () => {
const state = useColorMode()
expect(state.store.value).toBe('auto')
expect(state.system.value).toBe('light')
expect(state.value).toBe('light')
it('should be able access the store & system preference', () => {
const mode = useColorMode()
expect(mode.store.value).toBe('auto')
expect(mode.system.value).toBe('light')
expect(mode.state.value).toBe('light')
})
})
75 changes: 41 additions & 34 deletions packages/core/useColorMode/index.ts
@@ -1,6 +1,7 @@
import type { Ref } from 'vue-demi'
import { computed, ref, watch } from 'vue-demi'
import { tryOnMounted } from '@vueuse/shared'
import type { ComputedRef, Ref } from 'vue-demi'
import { computed, watch } from 'vue-demi'
import type { MaybeRefOrGetter } from '@vueuse/shared'
import { toRef, tryOnMounted } from '@vueuse/shared'
import type { StorageLike } from '../ssr-handlers'
import { getSSRHandler } from '../ssr-handlers'
import type { UseStorageOptions } from '../useStorage'
Expand All @@ -10,9 +11,10 @@ import { usePreferredDark } from '../usePreferredDark'
import type { MaybeElementRef } from '../unrefElement'
import { unrefElement } from '../unrefElement'

export type BasicColorSchema = 'light' | 'dark' | 'auto'
export type BasicColorMode = 'light' | 'dark'
export type BasicColorSchema = BasicColorMode | 'auto'

export interface UseColorModeOptions<T extends string = BasicColorSchema> extends UseStorageOptions<T | BasicColorSchema> {
export interface UseColorModeOptions<T extends string = BasicColorMode> extends UseStorageOptions<T | BasicColorMode> {
/**
* CSS Selector for the target element applying to
*
Expand All @@ -32,7 +34,7 @@ export interface UseColorModeOptions<T extends string = BasicColorSchema> extend
*
* @default 'auto'
*/
initialValue?: T | BasicColorSchema
initialValue?: MaybeRefOrGetter<T | BasicColorSchema>

/**
* Prefix when adding value to the attribute
Expand All @@ -45,7 +47,7 @@ export interface UseColorModeOptions<T extends string = BasicColorSchema> extend
*
* @default undefined
*/
onChanged?: (mode: T | BasicColorSchema, defaultHandler:((mode: T | BasicColorSchema) => void)) => void
onChanged?: (mode: T | BasicColorMode, defaultHandler:((mode: T | BasicColorMode) => void)) => void

/**
* Custom storage ref
Expand Down Expand Up @@ -77,6 +79,8 @@ export interface UseColorModeOptions<T extends string = BasicColorSchema> extend
* This is useful when the fact that `auto` mode was selected needs to be known.
*
* @default undefined
* @deprecated use `store.value` when `auto` mode needs to be known
* @see https://vueuse.org/core/useColorMode/#advanced-usage
*/
emitAuto?: boolean

Expand All @@ -89,10 +93,11 @@ export interface UseColorModeOptions<T extends string = BasicColorSchema> extend
disableTransition?: boolean
}

export type UseColorModeReturn<T extends string = BasicColorSchema> =
Ref<T> & {
store: Ref<T>
system: Ref<'light' | 'dark'>
export type UseColorModeReturn<T extends string = BasicColorMode> =
Ref<T | BasicColorSchema> & {
store: Ref<T | BasicColorSchema>
system: ComputedRef<BasicColorMode>
state: ComputedRef<T | BasicColorMode>
}

/**
Expand All @@ -101,7 +106,7 @@ export type UseColorModeReturn<T extends string = BasicColorSchema> =
* @see https://vueuse.org/useColorMode
* @param options
*/
export function useColorMode<T extends string = BasicColorSchema>(
export function useColorMode<T extends string = BasicColorMode>(
options: UseColorModeOptions<T> = {},
): UseColorModeReturn<T> {
const {
Expand All @@ -127,20 +132,17 @@ export function useColorMode<T extends string = BasicColorSchema>(
const preferredDark = usePreferredDark({ window })
const system = computed(() => preferredDark.value ? 'dark' : 'light')

const store = storageRef || (storageKey == null
? ref(initialValue) as Ref<T | BasicColorSchema>
: useStorage<T | BasicColorSchema>(storageKey, initialValue as BasicColorSchema, storage, { window, listenToStorageChanges }))
const store = storageRef || (
storageKey == null
? toRef(initialValue) as Ref<T | BasicColorSchema>
: useStorage<T | BasicColorSchema>(storageKey, initialValue, storage, { window, listenToStorageChanges })
)

const state = computed<T | BasicColorSchema>({
get() {
return (store.value === 'auto' && !emitAuto)
? system.value
: store.value
},
set(v) {
store.value = v
},
})
const state = computed<T | BasicColorMode>(() =>
store.value === 'auto'
? system.value
: store.value,
)

const updateHTMLAttrs = getSSRHandler(
'updateHTMLAttrs',
Expand Down Expand Up @@ -182,12 +184,11 @@ export function useColorMode<T extends string = BasicColorSchema>(
}
})

function defaultOnChanged(mode: T | BasicColorSchema) {
const resolvedMode = mode === 'auto' ? system.value : mode
updateHTMLAttrs(selector, attribute, modes[resolvedMode] ?? resolvedMode)
function defaultOnChanged(mode: T | BasicColorMode) {
updateHTMLAttrs(selector, attribute, modes[mode] ?? mode)
}

function onChanged(mode: T | BasicColorSchema) {
function onChanged(mode: T | BasicColorMode) {
if (options.onChanged)
options.onChanged(mode, defaultOnChanged)
else
Expand All @@ -196,16 +197,22 @@ export function useColorMode<T extends string = BasicColorSchema>(

watch(state, onChanged, { flush: 'post', immediate: true })

if (emitAuto)
watch(system, () => onChanged(state.value), { flush: 'post' })

tryOnMounted(() => onChanged(state.value))

const auto = computed({
get() {
return emitAuto ? store.value : state.value
},
set(v) {
store.value = v
},
})

try {
return Object.assign(state, { store, system }) as UseColorModeReturn<T>
return Object.assign(auto, { store, system, state }) as UseColorModeReturn<T>
}
catch (e) {
// In Vue 2.6, ref might not be extensible
return state as any as UseColorModeReturn<T>
return auto as any as UseColorModeReturn<T>
}
}
12 changes: 4 additions & 8 deletions packages/core/useDark/index.ts
@@ -1,8 +1,6 @@
import { computed } from 'vue-demi'
import { defaultWindow } from '../_configurable'
import { usePreferredDark } from '../usePreferredDark'
import type { BasicColorSchema, UseColorModeOptions } from '../useColorMode'
import { useColorMode } from '../useColorMode'
import type { BasicColorSchema, UseColorModeOptions } from '../useColorMode'

export interface UseDarkOptions extends Omit<UseColorModeOptions<BasicColorSchema>, 'modes' | 'onChanged'> {
/**
Expand Down Expand Up @@ -38,7 +36,6 @@ export function useDark(options: UseDarkOptions = {}) {
const {
valueDark = 'dark',
valueLight = '',
window = defaultWindow,
} = options

const mode = useColorMode({
Expand All @@ -55,17 +52,16 @@ export function useDark(options: UseDarkOptions = {}) {
},
})

const preferredDark = usePreferredDark({ window })

const isDark = computed<boolean>({
get() {
return mode.value === 'dark'
},
set(v) {
if (v === preferredDark.value)
const modeVal = v ? 'dark' : 'light'
if (mode.system.value === modeVal)
mode.value = 'auto'
else
mode.value = v ? 'dark' : 'light'
mode.value = modeVal
},
})

Expand Down

0 comments on commit a1bef49

Please sign in to comment.