Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
fd9d9cf
feature/new-docs 🧊 init docs
tungulin Mar 1, 2026
da0ff28
feat: docs wip
tungulin Mar 1, 2026
4b45bf3
feat: docs wip
tungulin Mar 1, 2026
7daf803
feat: docs wip
tungulin Mar 1, 2026
8edfb72
feat: docs wip
tungulin Mar 4, 2026
ab58d85
feat: wip
tungulin Mar 7, 2026
30e49de
feat: wip
tungulin Mar 7, 2026
0dd2baa
feat: minor
tungulin Mar 7, 2026
79426ae
feat: clear
tungulin Mar 7, 2026
71b1d4e
feat: clear
tungulin Mar 7, 2026
92cc66d
feat: wip
tungulin Mar 7, 2026
74011c0
feat:wip
tungulin Mar 7, 2026
e71fd51
feat:wip
tungulin Mar 7, 2026
904f0f5
feature/new-docs 🧊 feat: add script for generation
tungulin Mar 7, 2026
ac1d4ab
feat:wip
tungulin Mar 7, 2026
2a629cd
feat:wip
tungulin Mar 14, 2026
675edfa
feature/new-docs 🧊 feat: docs wip
tungulin Mar 21, 2026
d562940
feat: docs wip
tungulin Mar 21, 2026
71a943c
feat: docs wip
tungulin Mar 21, 2026
52c727a
feature/new-docs 🧊 feat: wip
tungulin Mar 22, 2026
c674abd
feature/new-docs 🧊 feat: wip
tungulin Mar 23, 2026
5929c9f
feature/new-docs 🧊 feat: add search
tungulin Mar 28, 2026
f08901e
feature/new-docs 🧊 feat: docs wip
tungulin Mar 29, 2026
371fbf1
feature/new-docs 🧊 feat: toc section
tungulin Mar 29, 2026
8489022
feature/new-docs 🧊 feat: docs wip
tungulin Mar 29, 2026
e5727ca
feature/new-docs 🧊 add gitignore docgen
tungulin Apr 2, 2026
ea695f9
feature/new-docs 🧊 docs: wip
tungulin Apr 5, 2026
cccdc1a
feature/new-docs 🧊 feat: delete old docs
tungulin Apr 5, 2026
a301679
feature/new-docs 🧊 feat: delete old docs
tungulin Apr 5, 2026
f4c8cc7
feature/new-docs 🧊 feat: wip
tungulin Apr 5, 2026
02dd845
feature/new-docs 🧊 feat: wip
tungulin Apr 5, 2026
1233903
feat: pretty
tungulin Apr 5, 2026
435383b
feat: alias import
tungulin Apr 5, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -222,3 +222,8 @@ generated
# Reactuse

**/registry.json


# Docgen. Generated content
packages/docs/content/docs/hooks/
.source
4 changes: 2 additions & 2 deletions .prettierrc.mjs
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
import { prettier } from "@siberiacancode/prettier";
import { prettier } from '@siberiacancode/prettier';

export default { ...prettier, plugins: ["prettier-plugin-tailwindcss"] };
export default { ...prettier, plugins: ['prettier-plugin-tailwindcss'] };
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
"scripts": {
"cli:build": "pnpm --filter @siberiacancode/cli build && pnpm --filter @siberiacancode/cli generate-registry",
"cli:build:registry": "pnpm --filter useverse build:registry",
"docs:build": "pnpm --filter @siberiacancode/docs build",
"docs:build": "pnpm --filter @siberiacancode/docs build & pnpm format",
"core:build:js": "pnpm --filter @siberiacancode/reactuse build:js",
"lint": "pnpm --recursive lint",
"format": "prettier --write .",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { cn } from '@siberiacancode/docs/utils';
import { cn } from '../../../../docs/lib/utils';
import { useClickOutside, useCounter } from '@siberiacancode/reactuse';

const Demo = () => {
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/hooks/useGamepad/useGamepad.demo.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
'use client';
import { useGamepad } from '@siberiacancode/reactuse';

const Demo = () => {
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/hooks/useIdle/useIdle.demo.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { cn } from '@siberiacancode/docs/utils';
import { cn } from '../../../../docs/lib/utils';
import { useIdle } from '@siberiacancode/reactuse';

const Demo = () => {
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/hooks/useMergedRef/useMergedRef.demo.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { cn } from '@siberiacancode/docs/utils';
import { cn } from '../../../../docs/lib/utils';
import {
useClickOutside,
useCounter,
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/hooks/useMouse/useMouse.demo.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { cn } from '@siberiacancode/docs/utils';
import { cn } from '../../../../docs/lib/utils';
import { useHover, useMouse } from '@siberiacancode/reactuse';

const Demo = () => {
Expand Down
124 changes: 57 additions & 67 deletions packages/core/src/hooks/useMutation/useMutation.test.ts
Original file line number Diff line number Diff line change
@@ -1,41 +1,35 @@
import { act, renderHook, waitFor } from "@testing-library/react";
import { act, renderHook, waitFor } from '@testing-library/react';

import { renderHookServer } from "@/tests";
import { renderHookServer } from '@/tests';

import { useMutation } from "./useMutation";
import { useMutation } from './useMutation';

it("Should use mutation", () => {
const { result } = renderHook(() =>
useMutation(() => Promise.resolve("data"))
);
it('Should use mutation', () => {
const { result } = renderHook(() => useMutation(() => Promise.resolve('data')));

expect(result.current.data).toBeNull();
expect(result.current.error).toBeNull();
expect(result.current.isError).toBeFalsy();
expect(result.current.isLoading).toBeFalsy();
expect(result.current.isSuccess).toBeFalsy();
expect(result.current.mutate).toBeTypeOf("function");
expect(result.current.mutateAsync).toBeTypeOf("function");
expect(result.current.mutate).toBeTypeOf('function');
expect(result.current.mutateAsync).toBeTypeOf('function');
});

it("Should use mutation on server side", () => {
const { result } = renderHookServer(() =>
useMutation(() => Promise.resolve("data"))
);
it('Should use mutation on server side', () => {
const { result } = renderHookServer(() => useMutation(() => Promise.resolve('data')));

expect(result.current.data).toBeNull();
expect(result.current.error).toBeNull();
expect(result.current.isError).toBeFalsy();
expect(result.current.isLoading).toBeFalsy();
expect(result.current.isSuccess).toBeFalsy();
expect(result.current.mutate).toBeTypeOf("function");
expect(result.current.mutateAsync).toBeTypeOf("function");
expect(result.current.mutate).toBeTypeOf('function');
expect(result.current.mutateAsync).toBeTypeOf('function');
});

it("Should mutate data successfully", async () => {
const { result } = renderHook(() =>
useMutation(() => Promise.resolve("data"))
);
it('Should mutate data successfully', async () => {
const { result } = renderHook(() => useMutation(() => Promise.resolve('data')));

act(result.current.mutate);

Expand All @@ -45,14 +39,12 @@ it("Should mutate data successfully", async () => {
await waitFor(() => {
expect(result.current.isLoading).toBeFalsy();
expect(result.current.isSuccess).toBeTruthy();
expect(result.current.data).toBe("data");
expect(result.current.data).toBe('data');
});
});

it("Should handle errors", async () => {
const { result } = renderHook(() =>
useMutation(() => Promise.reject(new Error("error")))
);
it('Should handle errors', async () => {
const { result } = renderHook(() => useMutation(() => Promise.reject(new Error('error'))));

await act(async () => {
try {
Expand All @@ -66,29 +58,27 @@ it("Should handle errors", async () => {
await waitFor(() => {
expect(result.current.isLoading).toBeFalsy();
expect(result.current.isError).toBeTruthy();
expect(result.current.error).toEqual(new Error("error"));
expect(result.current.error).toEqual(new Error('error'));
expect(result.current.data).toBeNull();
});
});

it("Should mutate async", async () => {
const { result } = renderHook(() =>
useMutation((input) => Promise.resolve(`data-${input}`))
);
it('Should mutate async', async () => {
const { result } = renderHook(() => useMutation((input) => Promise.resolve(`data-${input}`)));

await act(async () => {
const response = await result.current.mutateAsync("test");
expect(response).toBe("data-test");
const response = await result.current.mutateAsync('test');
expect(response).toBe('data-test');
});

expect(result.current.data).toBe("data-test");
expect(result.current.data).toBe('data-test');
expect(result.current.isSuccess).toBeTruthy();
});

it("Should triggered onSuccess callback", async () => {
it('Should triggered onSuccess callback', async () => {
const { result } = renderHook(() =>
useMutation(() => Promise.resolve("data"), {
onSuccess: (data) => expect(data).toBe("data"),
useMutation(() => Promise.resolve('data'), {
onSuccess: (data) => expect(data).toBe('data')
})
);

Expand All @@ -97,10 +87,10 @@ it("Should triggered onSuccess callback", async () => {
await waitFor(() => expect(result.current.isSuccess).toBeTruthy());
});

it("Should triggered onError callback", async () => {
it('Should triggered onError callback', async () => {
const { result } = renderHook(() =>
useMutation(() => Promise.reject(new Error("error")), {
onError: (error) => expect(error).toEqual(new Error("error")),
useMutation(() => Promise.reject(new Error('error')), {
onError: (error) => expect(error).toEqual(new Error('error'))
})
);

Expand All @@ -109,19 +99,19 @@ it("Should triggered onError callback", async () => {
await waitFor(() => expect(result.current.isError).toBeTruthy());
});

it("Should retry on error once", async () => {
it('Should retry on error once', async () => {
let retries = 0;

const { result } = renderHook(() =>
useMutation(
() =>
new Promise((resolve, reject) => {
if (retries === 1) resolve("data");
if (retries === 1) resolve('data');
retries++;
reject(new Error("error"));
reject(new Error('error'));
}),
{
retry: true,
retry: true
}
)
);
Expand All @@ -130,22 +120,22 @@ it("Should retry on error once", async () => {

expect(result.current.data).toBeNull();

await waitFor(() => expect(result.current.data).toBe("data"));
await waitFor(() => expect(result.current.data).toBe('data'));
});

it("Should retry on error multiple times", async () => {
it('Should retry on error multiple times', async () => {
let retries = 0;

const { result } = renderHook(() =>
useMutation(
() =>
new Promise((resolve, reject) => {
if (retries === 2) resolve("data");
if (retries === 2) resolve('data');
retries++;
reject(new Error("error"));
reject(new Error('error'));
}),
{
retry: 2,
retry: 2
}
)
);
Expand All @@ -154,36 +144,36 @@ it("Should retry on error multiple times", async () => {

expect(result.current.data).toBeNull();

await waitFor(() => expect(result.current.data).toBe("data"));
await waitFor(() => expect(result.current.data).toBe('data'));
});

it("Should override global options with mutate options", async () => {
it('Should override global options with mutate options', async () => {
const globalOnSuccess = vi.fn();
const localOnSuccess = vi.fn();

const { result } = renderHook(() =>
useMutation(() => Promise.resolve("data"), {
onSuccess: globalOnSuccess,
useMutation(() => Promise.resolve('data'), {
onSuccess: globalOnSuccess
})
);

act(() => result.current.mutate(undefined, { onSuccess: localOnSuccess }));

await waitFor(() => expect(result.current.isSuccess).toBeTruthy());

expect(localOnSuccess).toHaveBeenCalledWith("data");
expect(localOnSuccess).toHaveBeenCalledWith('data');
expect(globalOnSuccess).not.toHaveBeenCalled();
});

it("Should reset error state on successful mutation", async () => {
it('Should reset error state on successful mutation', async () => {
let shouldFail = true;

const { result } = renderHook(() =>
useMutation(() => {
if (shouldFail) {
return Promise.reject(new Error("error"));
return Promise.reject(new Error('error'));
}
return Promise.resolve("data");
return Promise.resolve('data');
})
);

Expand All @@ -205,35 +195,35 @@ it("Should reset error state on successful mutation", async () => {
});
});

it("Should retry by number delay", async () => {
it('Should retry by number delay', async () => {
let retries = 0;
const { result } = renderHook(() =>
useMutation(() => {
retries++;
if (retries < 2) {
return Promise.reject(new Error("error"));
return Promise.reject(new Error('error'));
}
return Promise.resolve("data");
return Promise.resolve('data');
})
);

act(() => result.current.mutate(undefined, { retry: 1, retryDelay: 100 }));

expect(result.current.isLoading).toBeTruthy();

await waitFor(() => expect(result.current.data).toBe("data"));
await waitFor(() => expect(result.current.data).toBe('data'));
});

it("Should retry by number global delay", async () => {
it('Should retry by number global delay', async () => {
let retries = 0;
const { result } = renderHook(() =>
useMutation(
() => {
retries++;
if (retries < 2) {
return Promise.reject(new Error("error"));
return Promise.reject(new Error('error'));
}
return Promise.resolve("data");
return Promise.resolve('data');
},
{ retryDelay: 100, retry: 1 }
)
Expand All @@ -243,20 +233,20 @@ it("Should retry by number global delay", async () => {

expect(result.current.isLoading).toBeTruthy();

await waitFor(() => expect(result.current.data).toBe("data"));
await waitFor(() => expect(result.current.data).toBe('data'));
});

it("Should retry by function delay", async () => {
it('Should retry by function delay', async () => {
const retryDelay = vi.fn(() => 100);
let retries = 0;

const { result } = renderHook(() =>
useMutation(() => {
retries++;
if (retries < 2) {
return Promise.reject(new Error("error"));
return Promise.reject(new Error('error'));
}
return Promise.resolve("data");
return Promise.resolve('data');
})
);

Expand All @@ -265,7 +255,7 @@ it("Should retry by function delay", async () => {
expect(result.current.isLoading).toBeTruthy();

await waitFor(() => {
expect(result.current.data).toBe("data");
expect(result.current.data).toBe('data');
expect(retryDelay).toHaveBeenCalledOnce();
});
});
Loading