@spelyco/react-lib 1.0.0-c0454a79-beta → 1.1.0-beta
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/README.md +49 -47
- package/dist/index.d.mts +4 -6
- package/dist/index.d.ts +4 -6
- package/dist/index.js +11 -7
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +13 -8
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,102 +1,104 @@
|
|
|
1
1
|
# @spelyco/react-lib
|
|
2
2
|
|
|
3
|
-
Shared
|
|
3
|
+
Shared hooks and utilities used by `@spelyco/react` and `@spelyco/react-native`.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
You can also install it standalone if you only need the hooks.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Install
|
|
6
10
|
|
|
7
11
|
```bash
|
|
8
12
|
bun add @spelyco/react-lib
|
|
9
13
|
```
|
|
10
14
|
|
|
15
|
+
---
|
|
16
|
+
|
|
11
17
|
## Hooks
|
|
12
18
|
|
|
13
|
-
### useBoolean
|
|
19
|
+
### `useBoolean`
|
|
14
20
|
|
|
15
|
-
|
|
21
|
+
A simple true/false toggle — great for modals, dropdowns, or anything that opens/closes.
|
|
16
22
|
|
|
17
23
|
```tsx
|
|
18
24
|
import { useBoolean } from "@spelyco/react-lib";
|
|
19
25
|
|
|
20
|
-
function
|
|
26
|
+
function MyModal() {
|
|
21
27
|
const { value: isOpen, setTrue: open, setFalse: close, toggle } = useBoolean(false);
|
|
22
28
|
|
|
23
29
|
return (
|
|
24
30
|
<>
|
|
25
|
-
<button onClick={open}>Open</button>
|
|
26
|
-
|
|
31
|
+
<button onClick={open}>Open modal</button>
|
|
32
|
+
<button onClick={toggle}>Toggle</button>
|
|
33
|
+
|
|
34
|
+
{isOpen && (
|
|
35
|
+
<dialog>
|
|
36
|
+
<p>Modal content</p>
|
|
37
|
+
<button onClick={close}>Close</button>
|
|
38
|
+
</dialog>
|
|
39
|
+
)}
|
|
27
40
|
</>
|
|
28
41
|
);
|
|
29
42
|
}
|
|
30
43
|
```
|
|
31
44
|
|
|
32
|
-
**
|
|
45
|
+
**What you get back:**
|
|
33
46
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
}
|
|
42
|
-
```
|
|
47
|
+
| Name | Type | What it does |
|
|
48
|
+
| --- | --- | --- |
|
|
49
|
+
| `value` | `boolean` | The current state |
|
|
50
|
+
| `setTrue` | `() => void` | Set to `true` |
|
|
51
|
+
| `setFalse` | `() => void` | Set to `false` |
|
|
52
|
+
| `toggle` | `() => void` | Flip between true/false |
|
|
53
|
+
| `setValue` | `(v: boolean) => void` | Set any value manually |
|
|
43
54
|
|
|
44
55
|
---
|
|
45
56
|
|
|
46
|
-
### useDebounce
|
|
57
|
+
### `useDebounce`
|
|
47
58
|
|
|
48
|
-
|
|
59
|
+
Waits until the user stops typing before updating the value. Perfect for search inputs — you don't want to fire an API call on every keystroke.
|
|
49
60
|
|
|
50
61
|
```tsx
|
|
51
62
|
import { useDebounce } from "@spelyco/react-lib";
|
|
63
|
+
import { useEffect, useState } from "react";
|
|
52
64
|
|
|
53
65
|
function Search() {
|
|
54
66
|
const [query, setQuery] = useState("");
|
|
55
|
-
const debouncedQuery = useDebounce(query, 400);
|
|
67
|
+
const debouncedQuery = useDebounce(query, 400); // wait 400ms after last keystroke
|
|
56
68
|
|
|
57
69
|
useEffect(() => {
|
|
58
|
-
if (debouncedQuery)
|
|
70
|
+
if (debouncedQuery) {
|
|
71
|
+
fetchResults(debouncedQuery); // only runs when user stops typing
|
|
72
|
+
}
|
|
59
73
|
}, [debouncedQuery]);
|
|
60
74
|
|
|
61
|
-
return <input onChange={(e) => setQuery(e.target.value)} />;
|
|
75
|
+
return <input onChange={(e) => setQuery(e.target.value)} placeholder="Search..." />;
|
|
62
76
|
}
|
|
63
77
|
```
|
|
64
78
|
|
|
65
|
-
**
|
|
79
|
+
**Parameters:**
|
|
66
80
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
81
|
+
| Parameter | Type | Default | Description |
|
|
82
|
+
| --- | --- | --- | --- |
|
|
83
|
+
| `value` | `T` | — | The value to debounce |
|
|
84
|
+
| `delay` | `number` | `300` | Wait time in milliseconds |
|
|
71
85
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
### cn
|
|
75
|
-
|
|
76
|
-
Merges class names, filtering out falsy values. Lightweight alternative to `clsx`.
|
|
77
|
-
|
|
78
|
-
```tsx
|
|
79
|
-
import { cn } from "@spelyco/react-lib";
|
|
86
|
+
---
|
|
80
87
|
|
|
81
|
-
|
|
82
|
-
// → "btn btn--active btn--lg"
|
|
88
|
+
## Utils
|
|
83
89
|
|
|
84
|
-
|
|
85
|
-
// → "base nested classes"
|
|
86
|
-
```
|
|
90
|
+
### `theme`
|
|
87
91
|
|
|
88
|
-
|
|
92
|
+
A pre-configured Mantine theme object with Spelyco defaults. Used internally by `SpelycoProvider`.
|
|
89
93
|
|
|
90
94
|
```ts
|
|
91
|
-
|
|
92
|
-
//
|
|
95
|
+
import { theme } from "@spelyco/react-lib";
|
|
96
|
+
// MantineTheme with defaultRadius: "md" and button defaults
|
|
93
97
|
```
|
|
94
98
|
|
|
95
|
-
|
|
99
|
+
You probably don't need this directly — it's applied automatically by `SpelycoProvider`.
|
|
96
100
|
|
|
97
|
-
|
|
98
|
-
|---|---|
|
|
99
|
-
| `react` | `>=18` |
|
|
101
|
+
---
|
|
100
102
|
|
|
101
103
|
## License
|
|
102
104
|
|
package/dist/index.d.mts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import * as _mantine_core from '@mantine/core';
|
|
2
|
+
import { MantineColor } from '@mantine/core';
|
|
2
3
|
|
|
3
4
|
interface UseBooleanReturn {
|
|
4
5
|
value: boolean;
|
|
@@ -11,10 +12,7 @@ declare function useBoolean(initialValue?: boolean): UseBooleanReturn;
|
|
|
11
12
|
|
|
12
13
|
declare function useDebounce<T>(value: T, delay?: number): T;
|
|
13
14
|
|
|
14
|
-
|
|
15
|
-
declare function cn(...inputs: ClassValue[]): string;
|
|
16
|
-
|
|
17
|
-
declare const theme: (primaryColor?: string) => {
|
|
15
|
+
declare const theme: (primaryColor?: MantineColor) => {
|
|
18
16
|
focusRing?: "auto" | "always" | "never" | undefined;
|
|
19
17
|
scale?: number | undefined;
|
|
20
18
|
fontSmoothing?: boolean | undefined;
|
|
@@ -22,7 +20,6 @@ declare const theme: (primaryColor?: string) => {
|
|
|
22
20
|
black?: string | undefined;
|
|
23
21
|
colors?: {
|
|
24
22
|
[x: string & {}]: _mantine_core.MantineColorsTuple | undefined;
|
|
25
|
-
blue?: _mantine_core.MantineColorsTuple | undefined;
|
|
26
23
|
dark?: _mantine_core.MantineColorsTuple | undefined;
|
|
27
24
|
gray?: _mantine_core.MantineColorsTuple | undefined;
|
|
28
25
|
red?: _mantine_core.MantineColorsTuple | undefined;
|
|
@@ -30,6 +27,7 @@ declare const theme: (primaryColor?: string) => {
|
|
|
30
27
|
grape?: _mantine_core.MantineColorsTuple | undefined;
|
|
31
28
|
violet?: _mantine_core.MantineColorsTuple | undefined;
|
|
32
29
|
indigo?: _mantine_core.MantineColorsTuple | undefined;
|
|
30
|
+
blue?: _mantine_core.MantineColorsTuple | undefined;
|
|
33
31
|
cyan?: _mantine_core.MantineColorsTuple | undefined;
|
|
34
32
|
green?: _mantine_core.MantineColorsTuple | undefined;
|
|
35
33
|
lime?: _mantine_core.MantineColorsTuple | undefined;
|
|
@@ -162,4 +160,4 @@ declare const theme: (primaryColor?: string) => {
|
|
|
162
160
|
} | undefined;
|
|
163
161
|
};
|
|
164
162
|
|
|
165
|
-
export {
|
|
163
|
+
export { theme, useBoolean, useDebounce };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import * as _mantine_core from '@mantine/core';
|
|
2
|
+
import { MantineColor } from '@mantine/core';
|
|
2
3
|
|
|
3
4
|
interface UseBooleanReturn {
|
|
4
5
|
value: boolean;
|
|
@@ -11,10 +12,7 @@ declare function useBoolean(initialValue?: boolean): UseBooleanReturn;
|
|
|
11
12
|
|
|
12
13
|
declare function useDebounce<T>(value: T, delay?: number): T;
|
|
13
14
|
|
|
14
|
-
|
|
15
|
-
declare function cn(...inputs: ClassValue[]): string;
|
|
16
|
-
|
|
17
|
-
declare const theme: (primaryColor?: string) => {
|
|
15
|
+
declare const theme: (primaryColor?: MantineColor) => {
|
|
18
16
|
focusRing?: "auto" | "always" | "never" | undefined;
|
|
19
17
|
scale?: number | undefined;
|
|
20
18
|
fontSmoothing?: boolean | undefined;
|
|
@@ -22,7 +20,6 @@ declare const theme: (primaryColor?: string) => {
|
|
|
22
20
|
black?: string | undefined;
|
|
23
21
|
colors?: {
|
|
24
22
|
[x: string & {}]: _mantine_core.MantineColorsTuple | undefined;
|
|
25
|
-
blue?: _mantine_core.MantineColorsTuple | undefined;
|
|
26
23
|
dark?: _mantine_core.MantineColorsTuple | undefined;
|
|
27
24
|
gray?: _mantine_core.MantineColorsTuple | undefined;
|
|
28
25
|
red?: _mantine_core.MantineColorsTuple | undefined;
|
|
@@ -30,6 +27,7 @@ declare const theme: (primaryColor?: string) => {
|
|
|
30
27
|
grape?: _mantine_core.MantineColorsTuple | undefined;
|
|
31
28
|
violet?: _mantine_core.MantineColorsTuple | undefined;
|
|
32
29
|
indigo?: _mantine_core.MantineColorsTuple | undefined;
|
|
30
|
+
blue?: _mantine_core.MantineColorsTuple | undefined;
|
|
33
31
|
cyan?: _mantine_core.MantineColorsTuple | undefined;
|
|
34
32
|
green?: _mantine_core.MantineColorsTuple | undefined;
|
|
35
33
|
lime?: _mantine_core.MantineColorsTuple | undefined;
|
|
@@ -162,4 +160,4 @@ declare const theme: (primaryColor?: string) => {
|
|
|
162
160
|
} | undefined;
|
|
163
161
|
};
|
|
164
162
|
|
|
165
|
-
export {
|
|
163
|
+
export { theme, useBoolean, useDebounce };
|
package/dist/index.js
CHANGED
|
@@ -19,24 +19,28 @@ function useDebounce(value, delay = 300) {
|
|
|
19
19
|
}, [value, delay]);
|
|
20
20
|
return debouncedValue;
|
|
21
21
|
}
|
|
22
|
-
|
|
23
|
-
// src/utils/cn.ts
|
|
24
|
-
function cn(...inputs) {
|
|
25
|
-
return inputs.flat(Infinity).filter(Boolean).join(" ");
|
|
26
|
-
}
|
|
27
22
|
var theme = (primaryColor) => core.createTheme({
|
|
28
|
-
primaryColor: primaryColor ?? "
|
|
23
|
+
primaryColor: primaryColor ?? "gray",
|
|
29
24
|
defaultRadius: "md",
|
|
30
25
|
components: {
|
|
31
26
|
Button: core.Button.extend({
|
|
32
27
|
defaultProps: {
|
|
33
28
|
variant: "default"
|
|
34
29
|
}
|
|
30
|
+
}),
|
|
31
|
+
ActionIcon: core.ActionIcon.extend({
|
|
32
|
+
defaultProps: {
|
|
33
|
+
variant: "transparent"
|
|
34
|
+
}
|
|
35
|
+
}),
|
|
36
|
+
NavLink: core.NavLink.extend({
|
|
37
|
+
defaultProps: {
|
|
38
|
+
variant: "light"
|
|
39
|
+
}
|
|
35
40
|
})
|
|
36
41
|
}
|
|
37
42
|
});
|
|
38
43
|
|
|
39
|
-
exports.cn = cn;
|
|
40
44
|
exports.theme = theme;
|
|
41
45
|
exports.useBoolean = useBoolean;
|
|
42
46
|
exports.useDebounce = useDebounce;
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/hooks/useBoolean.ts","../src/hooks/useDebounce.ts","../src/utils/
|
|
1
|
+
{"version":3,"sources":["../src/hooks/useBoolean.ts","../src/hooks/useDebounce.ts","../src/utils/theme.ts"],"names":["useState","useCallback","useEffect","createTheme","Button","ActionIcon","NavLink"],"mappings":";;;;;;AAUO,SAAS,UAAA,CAAW,eAAe,KAAA,EAAyB;AACjE,EAAA,MAAM,CAAC,KAAA,EAAO,QAAQ,CAAA,GAAIA,eAAS,YAAY,CAAA;AAE/C,EAAA,MAAM,UAAUC,iBAAA,CAAY,MAAM,SAAS,IAAI,CAAA,EAAG,EAAE,CAAA;AACpD,EAAA,MAAM,WAAWA,iBAAA,CAAY,MAAM,SAAS,KAAK,CAAA,EAAG,EAAE,CAAA;AACtD,EAAA,MAAM,MAAA,GAASA,iBAAA,CAAY,MAAM,QAAA,CAAS,CAAC,MAAM,CAAC,CAAC,CAAA,EAAG,EAAE,CAAA;AAExD,EAAA,OAAO,EAAE,KAAA,EAAO,OAAA,EAAS,QAAA,EAAU,QAAQ,QAAA,EAAS;AACtD;AChBO,SAAS,WAAA,CAAe,KAAA,EAAU,KAAA,GAAQ,GAAA,EAAQ;AACvD,EAAA,MAAM,CAAC,cAAA,EAAgB,iBAAiB,CAAA,GAAID,eAAY,KAAK,CAAA;AAE7D,EAAAE,eAAA,CAAU,MAAM;AACd,IAAA,MAAM,QAAQ,UAAA,CAAW,MAAM,iBAAA,CAAkB,KAAK,GAAG,KAAK,CAAA;AAC9D,IAAA,OAAO,MAAM,aAAa,KAAK,CAAA;AAAA,EACjC,CAAA,EAAG,CAAC,KAAA,EAAO,KAAK,CAAC,CAAA;AAEjB,EAAA,OAAO,cAAA;AACT;ACTO,IAAM,KAAA,GAAQ,CAAC,YAAA,KACpBC,gBAAA,CAAY;AAAA,EACV,cAAc,YAAA,IAAgB,MAAA;AAAA,EAC9B,aAAA,EAAe,IAAA;AAAA,EACf,UAAA,EAAY;AAAA,IACV,MAAA,EAAQC,YAAO,MAAA,CAAO;AAAA,MACpB,YAAA,EAAc;AAAA,QACZ,OAAA,EAAS;AAAA;AACX,KACD,CAAA;AAAA,IACD,UAAA,EAAYC,gBAAW,MAAA,CAAO;AAAA,MAC5B,YAAA,EAAc;AAAA,QACZ,OAAA,EAAS;AAAA;AACX,KACD,CAAA;AAAA,IACD,OAAA,EAASC,aAAQ,MAAA,CAAO;AAAA,MACtB,YAAA,EAAc;AAAA,QACZ,OAAA,EAAS;AAAA;AACX,KACD;AAAA;AAEL,CAAC","file":"index.js","sourcesContent":["import { useCallback, useState } from \"react\";\n\nexport interface UseBooleanReturn {\n value: boolean;\n setTrue: () => void;\n setFalse: () => void;\n toggle: () => void;\n setValue: (value: boolean) => void;\n}\n\nexport function useBoolean(initialValue = false): UseBooleanReturn {\n const [value, setValue] = useState(initialValue);\n\n const setTrue = useCallback(() => setValue(true), []);\n const setFalse = useCallback(() => setValue(false), []);\n const toggle = useCallback(() => setValue((v) => !v), []);\n\n return { value, setTrue, setFalse, toggle, setValue };\n}\n","import { useEffect, useState } from \"react\";\n\nexport function useDebounce<T>(value: T, delay = 300): T {\n const [debouncedValue, setDebouncedValue] = useState<T>(value);\n\n useEffect(() => {\n const timer = setTimeout(() => setDebouncedValue(value), delay);\n return () => clearTimeout(timer);\n }, [value, delay]);\n\n return debouncedValue;\n}\n","import { ActionIcon, Button, createTheme, type MantineColor, NavLink } from \"@mantine/core\";\n\nexport const theme = (primaryColor?: MantineColor) =>\n createTheme({\n primaryColor: primaryColor ?? \"gray\",\n defaultRadius: \"md\",\n components: {\n Button: Button.extend({\n defaultProps: {\n variant: \"default\",\n },\n }),\n ActionIcon: ActionIcon.extend({\n defaultProps: {\n variant: \"transparent\",\n },\n }),\n NavLink: NavLink.extend({\n defaultProps: {\n variant: \"light\",\n },\n }),\n },\n });\n"]}
|
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { useState, useCallback, useEffect } from 'react';
|
|
2
|
-
import { createTheme, Button } from '@mantine/core';
|
|
2
|
+
import { createTheme, NavLink, ActionIcon, Button } from '@mantine/core';
|
|
3
3
|
|
|
4
4
|
// src/hooks/useBoolean.ts
|
|
5
5
|
function useBoolean(initialValue = false) {
|
|
@@ -17,23 +17,28 @@ function useDebounce(value, delay = 300) {
|
|
|
17
17
|
}, [value, delay]);
|
|
18
18
|
return debouncedValue;
|
|
19
19
|
}
|
|
20
|
-
|
|
21
|
-
// src/utils/cn.ts
|
|
22
|
-
function cn(...inputs) {
|
|
23
|
-
return inputs.flat(Infinity).filter(Boolean).join(" ");
|
|
24
|
-
}
|
|
25
20
|
var theme = (primaryColor) => createTheme({
|
|
26
|
-
primaryColor: primaryColor ?? "
|
|
21
|
+
primaryColor: primaryColor ?? "gray",
|
|
27
22
|
defaultRadius: "md",
|
|
28
23
|
components: {
|
|
29
24
|
Button: Button.extend({
|
|
30
25
|
defaultProps: {
|
|
31
26
|
variant: "default"
|
|
32
27
|
}
|
|
28
|
+
}),
|
|
29
|
+
ActionIcon: ActionIcon.extend({
|
|
30
|
+
defaultProps: {
|
|
31
|
+
variant: "transparent"
|
|
32
|
+
}
|
|
33
|
+
}),
|
|
34
|
+
NavLink: NavLink.extend({
|
|
35
|
+
defaultProps: {
|
|
36
|
+
variant: "light"
|
|
37
|
+
}
|
|
33
38
|
})
|
|
34
39
|
}
|
|
35
40
|
});
|
|
36
41
|
|
|
37
|
-
export {
|
|
42
|
+
export { theme, useBoolean, useDebounce };
|
|
38
43
|
//# sourceMappingURL=index.mjs.map
|
|
39
44
|
//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/hooks/useBoolean.ts","../src/hooks/useDebounce.ts","../src/utils/
|
|
1
|
+
{"version":3,"sources":["../src/hooks/useBoolean.ts","../src/hooks/useDebounce.ts","../src/utils/theme.ts"],"names":["useState"],"mappings":";;;;AAUO,SAAS,UAAA,CAAW,eAAe,KAAA,EAAyB;AACjE,EAAA,MAAM,CAAC,KAAA,EAAO,QAAQ,CAAA,GAAI,SAAS,YAAY,CAAA;AAE/C,EAAA,MAAM,UAAU,WAAA,CAAY,MAAM,SAAS,IAAI,CAAA,EAAG,EAAE,CAAA;AACpD,EAAA,MAAM,WAAW,WAAA,CAAY,MAAM,SAAS,KAAK,CAAA,EAAG,EAAE,CAAA;AACtD,EAAA,MAAM,MAAA,GAAS,WAAA,CAAY,MAAM,QAAA,CAAS,CAAC,MAAM,CAAC,CAAC,CAAA,EAAG,EAAE,CAAA;AAExD,EAAA,OAAO,EAAE,KAAA,EAAO,OAAA,EAAS,QAAA,EAAU,QAAQ,QAAA,EAAS;AACtD;AChBO,SAAS,WAAA,CAAe,KAAA,EAAU,KAAA,GAAQ,GAAA,EAAQ;AACvD,EAAA,MAAM,CAAC,cAAA,EAAgB,iBAAiB,CAAA,GAAIA,SAAY,KAAK,CAAA;AAE7D,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,MAAM,QAAQ,UAAA,CAAW,MAAM,iBAAA,CAAkB,KAAK,GAAG,KAAK,CAAA;AAC9D,IAAA,OAAO,MAAM,aAAa,KAAK,CAAA;AAAA,EACjC,CAAA,EAAG,CAAC,KAAA,EAAO,KAAK,CAAC,CAAA;AAEjB,EAAA,OAAO,cAAA;AACT;ACTO,IAAM,KAAA,GAAQ,CAAC,YAAA,KACpB,WAAA,CAAY;AAAA,EACV,cAAc,YAAA,IAAgB,MAAA;AAAA,EAC9B,aAAA,EAAe,IAAA;AAAA,EACf,UAAA,EAAY;AAAA,IACV,MAAA,EAAQ,OAAO,MAAA,CAAO;AAAA,MACpB,YAAA,EAAc;AAAA,QACZ,OAAA,EAAS;AAAA;AACX,KACD,CAAA;AAAA,IACD,UAAA,EAAY,WAAW,MAAA,CAAO;AAAA,MAC5B,YAAA,EAAc;AAAA,QACZ,OAAA,EAAS;AAAA;AACX,KACD,CAAA;AAAA,IACD,OAAA,EAAS,QAAQ,MAAA,CAAO;AAAA,MACtB,YAAA,EAAc;AAAA,QACZ,OAAA,EAAS;AAAA;AACX,KACD;AAAA;AAEL,CAAC","file":"index.mjs","sourcesContent":["import { useCallback, useState } from \"react\";\n\nexport interface UseBooleanReturn {\n value: boolean;\n setTrue: () => void;\n setFalse: () => void;\n toggle: () => void;\n setValue: (value: boolean) => void;\n}\n\nexport function useBoolean(initialValue = false): UseBooleanReturn {\n const [value, setValue] = useState(initialValue);\n\n const setTrue = useCallback(() => setValue(true), []);\n const setFalse = useCallback(() => setValue(false), []);\n const toggle = useCallback(() => setValue((v) => !v), []);\n\n return { value, setTrue, setFalse, toggle, setValue };\n}\n","import { useEffect, useState } from \"react\";\n\nexport function useDebounce<T>(value: T, delay = 300): T {\n const [debouncedValue, setDebouncedValue] = useState<T>(value);\n\n useEffect(() => {\n const timer = setTimeout(() => setDebouncedValue(value), delay);\n return () => clearTimeout(timer);\n }, [value, delay]);\n\n return debouncedValue;\n}\n","import { ActionIcon, Button, createTheme, type MantineColor, NavLink } from \"@mantine/core\";\n\nexport const theme = (primaryColor?: MantineColor) =>\n createTheme({\n primaryColor: primaryColor ?? \"gray\",\n defaultRadius: \"md\",\n components: {\n Button: Button.extend({\n defaultProps: {\n variant: \"default\",\n },\n }),\n ActionIcon: ActionIcon.extend({\n defaultProps: {\n variant: \"transparent\",\n },\n }),\n NavLink: NavLink.extend({\n defaultProps: {\n variant: \"light\",\n },\n }),\n },\n });\n"]}
|