Skip to content
This repository was archived by the owner on Dec 11, 2025. It is now read-only.

Commit 79dd6cb

Browse files
authored
feat: useToggle (#55)
1 parent 7267a92 commit 79dd6cb

File tree

8 files changed

+629
-0
lines changed

8 files changed

+629
-0
lines changed

.changeset/fluffy-nights-try.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
---
2+
'unuse': minor
3+
'unuse-angular': minor
4+
'unuse-react': minor
5+
'unuse-solid': minor
6+
'unuse-vue': minor
7+
---
8+
9+
feat: useToggle

packages/unuse/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,5 @@ export * from './unRefElement';
1111
export * from './unResolve';
1212
export * from './useEventListener';
1313
export * from './useIntervalFn';
14+
export * from './useToggle';
1415
export * from './useWebSocket';
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
// @vitest-environment happy-dom
2+
3+
import type { WritableSignal } from '@angular/core';
4+
import { isSignal, signal } from '@angular/core';
5+
import { getTestBed } from '@angular/core/testing';
6+
import {
7+
BrowserTestingModule,
8+
platformBrowserTesting,
9+
} from '@angular/platform-browser/testing';
10+
import { beforeAll, expect, it } from 'vitest';
11+
import { describeAngular, ZonelessTestModule } from '../_testUtils/angular';
12+
import type { ToggleFn } from './index';
13+
import { useToggle } from './index';
14+
15+
describeAngular('useToggle', () => {
16+
beforeAll(() => {
17+
getTestBed().initTestEnvironment(
18+
[BrowserTestingModule, ZonelessTestModule],
19+
platformBrowserTesting()
20+
);
21+
});
22+
23+
it('default result', () => {
24+
const result = useToggle() as unknown as [
25+
WritableSignal<boolean>,
26+
ToggleFn,
27+
];
28+
const [value, toggle] = result;
29+
30+
expect(Array.isArray(result)).toBe(true);
31+
expect(result).toHaveLength(2);
32+
33+
expect(toggle).toBeTypeOf('function');
34+
expect(value).toSatisfy(isSignal);
35+
expect(value()).toBe(false);
36+
});
37+
38+
it('default result with initialValue', () => {
39+
const result = useToggle(true) as unknown as [
40+
WritableSignal<boolean>,
41+
ToggleFn,
42+
];
43+
const [value, toggle] = result;
44+
45+
expect(Array.isArray(result)).toBe(true);
46+
expect(result).toHaveLength(2);
47+
48+
expect(toggle).toBeTypeOf('function');
49+
expect(value).toSatisfy(isSignal);
50+
expect(value()).toBe(true);
51+
});
52+
53+
it('should toggle', () => {
54+
const result = useToggle() as unknown as [
55+
WritableSignal<boolean>,
56+
ToggleFn,
57+
];
58+
const [value, toggle] = result;
59+
60+
expect(toggle()).toBe(true);
61+
expect(value()).toBe(true);
62+
63+
expect(toggle()).toBe(false);
64+
expect(value()).toBe(false);
65+
});
66+
67+
it('should receive toggle param', () => {
68+
const result = useToggle() as unknown as [
69+
WritableSignal<boolean>,
70+
ToggleFn,
71+
];
72+
const [value, toggle] = result;
73+
74+
expect(toggle(false)).toBe(false);
75+
expect(value()).toBe(false);
76+
77+
expect(toggle(true)).toBe(true);
78+
expect(value()).toBe(true);
79+
});
80+
81+
it('signal initialValue', () => {
82+
getTestBed().runInInjectionContext(() => {
83+
const isDark = signal(true);
84+
const toggle = useToggle(isDark);
85+
86+
expect(toggle).toBeTypeOf('function');
87+
88+
expect(toggle()).toBe(false);
89+
expect(isDark()).toBe(false);
90+
91+
expect(toggle()).toBe(true);
92+
expect(isDark()).toBe(true);
93+
94+
expect(toggle(false)).toBe(false);
95+
expect(isDark()).toBe(false);
96+
97+
expect(toggle(true)).toBe(true);
98+
expect(isDark()).toBe(true);
99+
});
100+
});
101+
102+
it('should toggle with truthy & falsy', () => {
103+
getTestBed().runInInjectionContext(() => {
104+
const status = signal('ON');
105+
const toggle = useToggle(status, {
106+
truthyValue: 'ON',
107+
falsyValue: 'OFF',
108+
});
109+
110+
expect(status()).toBe('ON');
111+
expect(toggle).toBeTypeOf('function');
112+
113+
expect(toggle()).toBe('OFF');
114+
expect(status()).toBe('OFF');
115+
116+
expect(toggle()).toBe('ON');
117+
expect(status()).toBe('ON');
118+
119+
expect(toggle('OFF')).toBe('OFF');
120+
expect(status()).toBe('OFF');
121+
122+
expect(toggle('ON')).toBe('ON');
123+
expect(status()).toBe('ON');
124+
});
125+
});
126+
});
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
// @vitest-environment happy-dom
2+
3+
import { renderHook } from '@testing-library/react';
4+
import { useState } from 'react';
5+
import { expect, it } from 'vitest';
6+
import { describeReact } from '../_testUtils/react';
7+
import type { ToggleFn } from './index';
8+
import { useToggle } from './index';
9+
10+
describeReact('useToggle', () => {
11+
it('default result', () => {
12+
renderHook(() => {
13+
const result = useToggle() as unknown as [
14+
ReturnType<typeof useState<boolean>>,
15+
ToggleFn,
16+
];
17+
const [value, toggle] = result;
18+
19+
expect(Array.isArray(result)).toBe(true);
20+
expect(result).toHaveLength(2);
21+
22+
expect(toggle).toBeTypeOf('function');
23+
expect(value).toSatisfy(Array.isArray);
24+
expect(value[0]).toBe(false);
25+
});
26+
});
27+
28+
it('default result with initialValue', () => {
29+
renderHook(() => {
30+
const result = useToggle(true) as unknown as [
31+
ReturnType<typeof useState<boolean>>,
32+
ToggleFn,
33+
];
34+
const [value, toggle] = result;
35+
36+
expect(Array.isArray(result)).toBe(true);
37+
expect(result).toHaveLength(2);
38+
39+
expect(toggle).toBeTypeOf('function');
40+
expect(value).toBeTypeOf('object');
41+
expect(value[0]).toBe(true);
42+
});
43+
});
44+
45+
it.todo('should toggle', () => {
46+
renderHook(() => {
47+
const result = useToggle() as unknown as [
48+
ReturnType<typeof useState<boolean>>,
49+
ToggleFn,
50+
];
51+
const [value, toggle] = result;
52+
53+
expect(toggle()).toBe(true);
54+
expect(value[0]).toBe(true);
55+
56+
expect(toggle()).toBe(false);
57+
expect(value[0]).toBe(false);
58+
});
59+
});
60+
61+
it.todo('should receive toggle param', () => {
62+
renderHook(() => {
63+
const result = useToggle() as unknown as [
64+
ReturnType<typeof useState<boolean>>,
65+
ToggleFn,
66+
];
67+
const [value, toggle] = result;
68+
69+
expect(toggle(false)).toBe(false);
70+
expect(value[0]).toBe(false);
71+
72+
expect(toggle(true)).toBe(true);
73+
expect(value[0]).toBe(true);
74+
});
75+
});
76+
77+
it.todo('state initialValue', () => {
78+
renderHook(() => {
79+
const isDark = useState(true);
80+
const toggle = useToggle(isDark);
81+
82+
expect(toggle).toBeTypeOf('function');
83+
84+
expect(toggle()).toBe(false);
85+
expect(isDark[0]).toBe(false);
86+
87+
expect(toggle()).toBe(true);
88+
expect(isDark[0]).toBe(true);
89+
90+
expect(toggle(false)).toBe(false);
91+
expect(isDark[0]).toBe(false);
92+
93+
expect(toggle(true)).toBe(true);
94+
expect(isDark[0]).toBe(true);
95+
});
96+
});
97+
98+
it.todo('should toggle with truthy & falsy', () => {
99+
renderHook(() => {
100+
const status = useState('ON');
101+
const toggle = useToggle(status, {
102+
truthyValue: 'ON',
103+
falsyValue: 'OFF',
104+
});
105+
106+
expect(status[0]).toBe('ON');
107+
expect(toggle).toBeTypeOf('function');
108+
109+
expect(toggle()).toBe('OFF');
110+
expect(status[0]).toBe('OFF');
111+
112+
expect(toggle()).toBe('ON');
113+
expect(status[0]).toBe('ON');
114+
115+
expect(toggle('OFF')).toBe('OFF');
116+
expect(status[0]).toBe('OFF');
117+
118+
expect(toggle('ON')).toBe('ON');
119+
expect(status[0]).toBe('ON');
120+
});
121+
});
122+
});
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
import type { Signal } from 'solid-js';
2+
import { createSignal } from 'solid-js';
3+
import { expect, it } from 'vitest';
4+
import { describeSolid } from '../_testUtils/solid';
5+
import type { ToggleFn } from './index';
6+
import { useToggle } from './index';
7+
8+
describeSolid('useToggle', () => {
9+
it('default result', () => {
10+
const result = useToggle() as unknown as [Signal<boolean>, ToggleFn];
11+
const [value, toggle] = result;
12+
13+
expect(Array.isArray(result)).toBe(true);
14+
expect(result).toHaveLength(2);
15+
16+
expect(toggle).toBeTypeOf('function');
17+
expect(value).toSatisfy(Array.isArray);
18+
expect(value[0]()).toBe(false);
19+
});
20+
21+
it('default result with initialValue', () => {
22+
const result = useToggle(true) as unknown as [Signal<boolean>, ToggleFn];
23+
const [value, toggle] = result;
24+
25+
expect(Array.isArray(result)).toBe(true);
26+
expect(result).toHaveLength(2);
27+
28+
expect(toggle).toBeTypeOf('function');
29+
expect(value).toSatisfy(Array.isArray);
30+
expect(value[0]()).toBe(true);
31+
});
32+
33+
it('should toggle', () => {
34+
const result = useToggle() as unknown as [Signal<boolean>, ToggleFn];
35+
const [value, toggle] = result;
36+
37+
expect(toggle()).toBe(true);
38+
expect(value[0]()).toBe(true);
39+
40+
expect(toggle()).toBe(false);
41+
expect(value[0]()).toBe(false);
42+
});
43+
44+
it('should receive toggle param', () => {
45+
const result = useToggle() as unknown as [Signal<boolean>, ToggleFn];
46+
const [value, toggle] = result;
47+
48+
expect(toggle(false)).toBe(false);
49+
expect(value[0]()).toBe(false);
50+
51+
expect(toggle(true)).toBe(true);
52+
expect(value[0]()).toBe(true);
53+
});
54+
55+
it('signal initialValue', () => {
56+
const isDark = createSignal(true);
57+
const toggle = useToggle(isDark);
58+
59+
expect(toggle).toBeTypeOf('function');
60+
61+
expect(toggle()).toBe(false);
62+
expect(isDark[0]()).toBe(false);
63+
64+
expect(toggle()).toBe(true);
65+
expect(isDark[0]()).toBe(true);
66+
67+
expect(toggle(false)).toBe(false);
68+
expect(isDark[0]()).toBe(false);
69+
70+
expect(toggle(true)).toBe(true);
71+
expect(isDark[0]()).toBe(true);
72+
});
73+
74+
it('should toggle with truthy & falsy', () => {
75+
const status = createSignal('ON');
76+
const toggle = useToggle(status, {
77+
truthyValue: 'ON',
78+
falsyValue: 'OFF',
79+
});
80+
81+
expect(status[0]()).toBe('ON');
82+
expect(toggle).toBeTypeOf('function');
83+
84+
expect(toggle()).toBe('OFF');
85+
expect(status[0]()).toBe('OFF');
86+
87+
expect(toggle()).toBe('ON');
88+
expect(status[0]()).toBe('ON');
89+
90+
expect(toggle('OFF')).toBe('OFF');
91+
expect(status[0]()).toBe('OFF');
92+
93+
expect(toggle('ON')).toBe('ON');
94+
expect(status[0]()).toBe('ON');
95+
});
96+
});

0 commit comments

Comments
 (0)