diff --git a/packages/shared/useToggle/index.test.ts b/packages/shared/useToggle/index.test.ts new file mode 100644 index 00000000000..a9496e9c785 --- /dev/null +++ b/packages/shared/useToggle/index.test.ts @@ -0,0 +1,96 @@ +import { isRef, ref, unref } from 'vue-demi' +import { useToggle } from '.' + +describe('useToggle', () => { + it('should be defined', () => { + expect(useToggle).toBeDefined() + }) + + it('default result', () => { + const result = useToggle() + const [value, toggle] = result + + expect(Array.isArray(result)).toBe(true) + expect(result.length).toBe(2) + + expect(typeof toggle).toBe('function') + expect(isRef(value)).toBe(true) + expect(unref(value)).toBe(false) + }) + + it('default result with initialValue', () => { + const result = useToggle(true) + const [value, toggle] = result + + expect(Array.isArray(result)).toBe(true) + expect(result.length).toBe(2) + + expect(typeof toggle).toBe('function') + expect(isRef(value)).toBe(true) + expect(unref(value)).toBe(true) + }) + + it('should toggle', () => { + const result = useToggle() + const [value, toggle] = result + + expect(toggle()).toBe(true) + expect(unref(value)).toBe(true) + + expect(toggle()).toBe(false) + expect(unref(value)).toBe(false) + }) + + it('should receive toggle param', () => { + const result = useToggle() + const [value, toggle] = result + + expect(toggle(false)).toBe(false) + expect(unref(value)).toBe(false) + + expect(toggle(true)).toBe(true) + expect(unref(value)).toBe(true) + }) + + it('ref initialValue', () => { + const isDark = ref(true) + const toggle = useToggle(isDark) + + expect(typeof toggle).toBe('function') + + expect(toggle()).toBe(false) + expect(unref(isDark)).toBe(false) + + expect(toggle()).toBe(true) + expect(unref(isDark)).toBe(true) + + expect(toggle(false)).toBe(false) + expect(unref(isDark)).toBe(false) + + expect(toggle(true)).toBe(true) + expect(unref(isDark)).toBe(true) + }) + + it('should toggle with truthy & falsy', () => { + const status = ref('ON') + const toggle = useToggle(status, { + truthyValue: 'ON', + falsyValue: 'OFF', + }) + + expect(unref(status)).toBe('ON') + expect(typeof toggle).toBe('function') + + expect(toggle()).toBe('OFF') + expect(unref(status)).toBe('OFF') + + expect(toggle()).toBe('ON') + expect(unref(status)).toBe('ON') + + expect(toggle('OFF')).toBe('OFF') + expect(unref(status)).toBe('OFF') + + expect(toggle('ON')).toBe('ON') + expect(unref(status)).toBe('ON') + }) +}) diff --git a/packages/shared/useToggle/index.ts b/packages/shared/useToggle/index.ts index 35b98901744..21c4ba69cd9 100644 --- a/packages/shared/useToggle/index.ts +++ b/packages/shared/useToggle/index.ts @@ -1,5 +1,14 @@ import type { Ref } from 'vue-demi' -import { isRef, ref } from 'vue-demi' +import { isRef, ref, unref } from 'vue-demi' +import type { MaybeRef } from '../utils' + +export interface UseToggleOptions { + truthyValue?: MaybeRef + falsyValue?: MaybeRef +} + +export function useToggle(initialValue: Ref, options?: UseToggleOptions): (value?: T) => T +export function useToggle(initialValue?: T, options?: UseToggleOptions): [Ref, (value?: T) => T] /** * A boolean ref with a toggler @@ -7,27 +16,29 @@ import { isRef, ref } from 'vue-demi' * @see https://vueuse.org/useToggle * @param [initialValue=false] */ -export function useToggle(value: Ref): (value?: boolean) => boolean -export function useToggle(initialValue?: boolean): [Ref, (value?: boolean) => boolean] +export function useToggle(initialValue: MaybeRef = false, options: UseToggleOptions = {}) { + const { + truthyValue = true, + falsyValue = false, + } = options + + const valueIsRef = isRef(initialValue) + const innerValue = ref(initialValue) as Ref -export function useToggle(initialValue: boolean | Ref = false) { - if (isRef(initialValue)) { - return (value?: boolean) => { - initialValue.value = typeof value === 'boolean' - ? value - : !initialValue.value - return initialValue.value + function toggle(value?: boolean) { + // has arguments + if (arguments.length) { + innerValue.value = value! + return innerValue.value } - } - else { - const boolean = ref(initialValue) - const toggle = (value?: boolean) => { - boolean.value = typeof value === 'boolean' - ? value - : !boolean.value - return boolean.value + else { + innerValue.value = innerValue.value === unref(truthyValue) ? unref(falsyValue) : unref(truthyValue) + return innerValue.value } - - return [boolean, toggle] as const } + + if (valueIsRef) + return toggle + else + return [innerValue, toggle] as const }