@teo-garcia/react-shared 0.1.8 → 1.0.0
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 +76 -168
- package/dist/components/error-boundary/error-boundary.d.ts.map +1 -1
- package/dist/components/error-boundary/error-boundary.js +1 -1
- package/dist/components/index.d.ts +0 -5
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/index.js +0 -5
- package/dist/hooks/index.d.ts +6 -5
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/index.js +6 -4
- package/dist/hooks/use-debounce.d.ts +2 -0
- package/dist/hooks/use-debounce.d.ts.map +1 -0
- package/dist/hooks/use-debounce.js +9 -0
- package/dist/hooks/use-isomorphic-layout-effect.d.ts +3 -0
- package/dist/hooks/use-isomorphic-layout-effect.d.ts.map +1 -0
- package/dist/hooks/use-isomorphic-layout-effect.js +4 -0
- package/dist/hooks/use-local-storage.d.ts +2 -0
- package/dist/hooks/use-local-storage.d.ts.map +1 -0
- package/dist/hooks/use-local-storage.js +37 -0
- package/dist/hooks/use-media-query.d.ts +2 -0
- package/dist/hooks/use-media-query.d.ts.map +1 -0
- package/dist/hooks/use-media-query.js +18 -0
- package/dist/hooks/use-on-click-outside.d.ts +3 -0
- package/dist/hooks/use-on-click-outside.d.ts.map +1 -0
- package/dist/hooks/use-on-click-outside.js +17 -0
- package/dist/hooks/use-previous.d.ts +2 -0
- package/dist/hooks/use-previous.d.ts.map +1 -0
- package/dist/hooks/use-previous.js +8 -0
- package/dist/index.d.ts +6 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -9
- package/dist/test-utils/index.d.ts +14 -0
- package/dist/test-utils/index.d.ts.map +1 -0
- package/dist/test-utils/index.js +22 -0
- package/dist/types.d.ts +0 -34
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/cn.d.ts +3 -0
- package/dist/utils/cn.d.ts.map +1 -0
- package/dist/utils/cn.js +5 -0
- package/dist/utils/index.d.ts +1 -5
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +1 -5
- package/package.json +62 -45
- package/dist/adapters/environment/index.d.ts +0 -6
- package/dist/adapters/environment/index.d.ts.map +0 -1
- package/dist/adapters/environment/index.js +0 -5
- package/dist/adapters/environment/next.d.ts +0 -17
- package/dist/adapters/environment/next.d.ts.map +0 -1
- package/dist/adapters/environment/next.js +0 -20
- package/dist/adapters/environment/vite.d.ts +0 -17
- package/dist/adapters/environment/vite.d.ts.map +0 -1
- package/dist/adapters/environment/vite.js +0 -20
- package/dist/adapters/index.d.ts +0 -9
- package/dist/adapters/index.d.ts.map +0 -1
- package/dist/adapters/index.js +0 -8
- package/dist/adapters/theme/custom.d.ts +0 -32
- package/dist/adapters/theme/custom.d.ts.map +0 -1
- package/dist/adapters/theme/custom.js +0 -26
- package/dist/adapters/theme/index.d.ts +0 -6
- package/dist/adapters/theme/index.d.ts.map +0 -1
- package/dist/adapters/theme/index.js +0 -5
- package/dist/adapters/theme/next-themes.d.ts +0 -18
- package/dist/adapters/theme/next-themes.d.ts.map +0 -1
- package/dist/adapters/theme/next-themes.js +0 -23
- package/dist/components/theme-switch/index.d.ts +0 -3
- package/dist/components/theme-switch/index.d.ts.map +0 -1
- package/dist/components/theme-switch/index.js +0 -1
- package/dist/components/theme-switch/theme-switch.d.ts +0 -36
- package/dist/components/theme-switch/theme-switch.d.ts.map +0 -1
- package/dist/components/theme-switch/theme-switch.js +0 -74
- package/dist/components/viewport-info/index.d.ts +0 -3
- package/dist/components/viewport-info/index.d.ts.map +0 -1
- package/dist/components/viewport-info/index.js +0 -1
- package/dist/components/viewport-info/viewport-info.d.ts +0 -40
- package/dist/components/viewport-info/viewport-info.d.ts.map +0 -1
- package/dist/components/viewport-info/viewport-info.js +0 -69
- package/dist/hooks/use-healthcheck.d.ts +0 -42
- package/dist/hooks/use-healthcheck.d.ts.map +0 -1
- package/dist/hooks/use-healthcheck.js +0 -53
- package/dist/utils/environment.d.ts +0 -71
- package/dist/utils/environment.d.ts.map +0 -1
- package/dist/utils/environment.js +0 -86
- package/dist/utils/msw.d.ts +0 -54
- package/dist/utils/msw.d.ts.map +0 -1
- package/dist/utils/msw.js +0 -62
package/README.md
CHANGED
|
@@ -1,55 +1,57 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
1
3
|
# @teo-garcia/react-shared
|
|
2
4
|
|
|
3
|
-
Shared React components, hooks, utilities, and adapters for fullstack web
|
|
5
|
+
**Shared React components, hooks, utilities, and adapters for fullstack web
|
|
6
|
+
templates**
|
|
4
7
|
|
|
5
|
-
|
|
8
|
+
[](LICENSE)
|
|
9
|
+
[](https://www.npmjs.com/package/@teo-garcia/react-shared)
|
|
10
|
+
[](https://react.dev)
|
|
6
11
|
|
|
7
|
-
|
|
12
|
+
Part of the [@teo-garcia/templates](https://github.com/teo-garcia/templates)
|
|
13
|
+
ecosystem
|
|
8
14
|
|
|
9
|
-
|
|
10
|
-
pnpm add @teo-garcia/react-shared
|
|
11
|
-
```
|
|
15
|
+
</div>
|
|
12
16
|
|
|
13
|
-
|
|
17
|
+
---
|
|
14
18
|
|
|
15
|
-
|
|
19
|
+
## Features
|
|
16
20
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
21
|
+
| Area | Includes |
|
|
22
|
+
| ----------------- | ------------------------------------------------------------------ |
|
|
23
|
+
| **Components** | `ThemeSwitch`, `ViewportInfo`, `ErrorBoundary` |
|
|
24
|
+
| **Hooks** | `useHealthcheck` with React Query |
|
|
25
|
+
| **Utilities** | Environment helpers and MSW setup helpers |
|
|
26
|
+
| **Adapters** | Theme and environment adapters for Next.js and Vite-based apps |
|
|
27
|
+
| **Compatibility** | Framework-agnostic usage across Next.js and React Router templates |
|
|
28
|
+
| **Type Safety** | TypeScript definitions for all exports |
|
|
29
|
+
| **Packaging** | Tree-shakeable module exports |
|
|
20
30
|
|
|
21
|
-
|
|
31
|
+
## Requirements
|
|
22
32
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
33
|
+
- React 18+
|
|
34
|
+
- TypeScript
|
|
35
|
+
- Tailwind CSS for included component styles
|
|
26
36
|
|
|
27
|
-
|
|
37
|
+
## Quick Start
|
|
28
38
|
|
|
29
39
|
```bash
|
|
30
|
-
|
|
31
|
-
|
|
40
|
+
# Install the package
|
|
41
|
+
pnpm add @teo-garcia/react-shared
|
|
32
42
|
|
|
33
|
-
|
|
43
|
+
# Required peer dependencies
|
|
44
|
+
pnpm add react react-dom lucide-react
|
|
34
45
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
- **Utilities**: Pure helper functions (environment detection, MSW setup)
|
|
38
|
-
- **Adapters**: Framework bridges for theme providers and environment detection
|
|
39
|
-
- **Framework Agnostic**: Works with Next.js, React Router, and other React frameworks
|
|
40
|
-
- **TypeScript**: Full type safety with TypeScript definitions
|
|
41
|
-
- **Tree-shakeable**: Import only what you need
|
|
46
|
+
# Optional for hooks
|
|
47
|
+
pnpm add @tanstack/react-query
|
|
42
48
|
|
|
43
|
-
|
|
49
|
+
# Optional for MSW helpers
|
|
50
|
+
pnpm add -D msw
|
|
51
|
+
```
|
|
44
52
|
|
|
45
53
|
### Components
|
|
46
54
|
|
|
47
|
-
#### ThemeSwitch
|
|
48
|
-
|
|
49
|
-
A button that cycles through light, dark, and system themes.
|
|
50
|
-
|
|
51
|
-
**Next.js (with next-themes):**
|
|
52
|
-
|
|
53
55
|
```tsx
|
|
54
56
|
import { ThemeSwitch } from '@teo-garcia/react-shared/components'
|
|
55
57
|
import { useNextThemesAdapter } from '@teo-garcia/react-shared/adapters/theme'
|
|
@@ -60,75 +62,8 @@ export function App() {
|
|
|
60
62
|
}
|
|
61
63
|
```
|
|
62
64
|
|
|
63
|
-
**React Router (with custom provider):**
|
|
64
|
-
|
|
65
|
-
```tsx
|
|
66
|
-
import { ThemeSwitch } from '@teo-garcia/react-shared/components'
|
|
67
|
-
import { createCustomThemeAdapter } from '@teo-garcia/react-shared/adapters/theme'
|
|
68
|
-
import { useTheme } from '~/components/theme-provider'
|
|
69
|
-
|
|
70
|
-
export function App() {
|
|
71
|
-
const themeAdapter = createCustomThemeAdapter(useTheme())
|
|
72
|
-
return <ThemeSwitch themeAdapter={themeAdapter} />
|
|
73
|
-
}
|
|
74
|
-
```
|
|
75
|
-
|
|
76
|
-
#### ViewportInfo
|
|
77
|
-
|
|
78
|
-
Displays current viewport dimensions and Tailwind breakpoint (dev mode only).
|
|
79
|
-
|
|
80
|
-
```tsx
|
|
81
|
-
import { ViewportInfo } from '@teo-garcia/react-shared/components'
|
|
82
|
-
import { nextEnvironmentAdapter } from '@teo-garcia/react-shared/adapters/environment'
|
|
83
|
-
|
|
84
|
-
export function App() {
|
|
85
|
-
return <ViewportInfo environmentAdapter={nextEnvironmentAdapter} />
|
|
86
|
-
}
|
|
87
|
-
```
|
|
88
|
-
|
|
89
|
-
**For Vite/React Router:**
|
|
90
|
-
|
|
91
|
-
```tsx
|
|
92
|
-
import { ViewportInfo } from '@teo-garcia/react-shared/components'
|
|
93
|
-
import { viteEnvironmentAdapter } from '@teo-garcia/react-shared/adapters/environment'
|
|
94
|
-
|
|
95
|
-
export function App() {
|
|
96
|
-
return <ViewportInfo environmentAdapter={viteEnvironmentAdapter} />
|
|
97
|
-
}
|
|
98
|
-
```
|
|
99
|
-
|
|
100
|
-
#### ErrorBoundary
|
|
101
|
-
|
|
102
|
-
Catches JavaScript errors in child components.
|
|
103
|
-
|
|
104
|
-
```tsx
|
|
105
|
-
import { ErrorBoundary } from '@teo-garcia/react-shared/components'
|
|
106
|
-
|
|
107
|
-
export function App() {
|
|
108
|
-
return (
|
|
109
|
-
<ErrorBoundary
|
|
110
|
-
fallback={(error) => (
|
|
111
|
-
<div>
|
|
112
|
-
<h1>Something went wrong</h1>
|
|
113
|
-
<p>{error.message}</p>
|
|
114
|
-
</div>
|
|
115
|
-
)}
|
|
116
|
-
onError={(error, errorInfo) => {
|
|
117
|
-
console.error('Error caught:', error, errorInfo)
|
|
118
|
-
}}
|
|
119
|
-
>
|
|
120
|
-
<YourApp />
|
|
121
|
-
</ErrorBoundary>
|
|
122
|
-
)
|
|
123
|
-
}
|
|
124
|
-
```
|
|
125
|
-
|
|
126
65
|
### Hooks
|
|
127
66
|
|
|
128
|
-
#### useHealthcheck
|
|
129
|
-
|
|
130
|
-
Fetches health status from an API endpoint using React Query.
|
|
131
|
-
|
|
132
67
|
```tsx
|
|
133
68
|
import { useHealthcheck } from '@teo-garcia/react-shared/hooks'
|
|
134
69
|
|
|
@@ -145,78 +80,45 @@ export function HealthStatus() {
|
|
|
145
80
|
|
|
146
81
|
### Utilities
|
|
147
82
|
|
|
148
|
-
#### Environment Detection
|
|
149
|
-
|
|
150
83
|
```tsx
|
|
151
|
-
import {
|
|
84
|
+
import { isClient, isDevelopment } from '@teo-garcia/react-shared/utils'
|
|
152
85
|
|
|
153
86
|
if (isDevelopment()) {
|
|
154
87
|
console.log('Running in dev mode')
|
|
155
88
|
}
|
|
156
89
|
|
|
157
90
|
if (isClient()) {
|
|
158
|
-
// Access browser APIs
|
|
159
91
|
localStorage.setItem('key', 'value')
|
|
160
92
|
}
|
|
161
93
|
```
|
|
162
94
|
|
|
163
|
-
#### MSW Setup
|
|
164
|
-
|
|
165
|
-
```tsx
|
|
166
|
-
import { setupMSWBrowser } from '@teo-garcia/react-shared/utils'
|
|
167
|
-
import { handlers } from './mocks/handlers'
|
|
168
|
-
|
|
169
|
-
// In your app initialization
|
|
170
|
-
if (isDevelopment()) {
|
|
171
|
-
await setupMSWBrowser(handlers)
|
|
172
|
-
}
|
|
173
|
-
```
|
|
174
|
-
|
|
175
95
|
### Adapters
|
|
176
96
|
|
|
177
|
-
Adapters bridge the gap between different framework-specific implementations and our components.
|
|
178
|
-
|
|
179
|
-
#### Theme Adapters
|
|
180
|
-
|
|
181
|
-
**Next.js (next-themes):**
|
|
182
|
-
|
|
183
|
-
```tsx
|
|
184
|
-
import { useNextThemesAdapter } from '@teo-garcia/react-shared/adapters/theme'
|
|
185
|
-
|
|
186
|
-
const themeAdapter = useNextThemesAdapter()
|
|
187
|
-
```
|
|
188
|
-
|
|
189
|
-
**Custom Theme Provider:**
|
|
190
|
-
|
|
191
97
|
```tsx
|
|
192
|
-
import {
|
|
193
|
-
import {
|
|
194
|
-
|
|
195
|
-
const themeAdapter = createCustomThemeAdapter(useTheme())
|
|
196
|
-
```
|
|
197
|
-
|
|
198
|
-
#### Environment Adapters
|
|
199
|
-
|
|
200
|
-
**Next.js:**
|
|
98
|
+
import { ViewportInfo } from '@teo-garcia/react-shared/components'
|
|
99
|
+
import { viteEnvironmentAdapter } from '@teo-garcia/react-shared/adapters/environment'
|
|
201
100
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
101
|
+
export function App() {
|
|
102
|
+
return <ViewportInfo environmentAdapter={viteEnvironmentAdapter} />
|
|
103
|
+
}
|
|
205
104
|
```
|
|
206
105
|
|
|
207
|
-
|
|
106
|
+
## Exports
|
|
208
107
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
108
|
+
| Export | Description |
|
|
109
|
+
| ----------------------------------------------- | ---------------------------- |
|
|
110
|
+
| `@teo-garcia/react-shared/components` | Shared React UI components |
|
|
111
|
+
| `@teo-garcia/react-shared/hooks` | Shared React hooks |
|
|
112
|
+
| `@teo-garcia/react-shared/utils` | Framework-agnostic utilities |
|
|
113
|
+
| `@teo-garcia/react-shared/adapters/theme` | Theme adapters |
|
|
114
|
+
| `@teo-garcia/react-shared/adapters/environment` | Environment adapters |
|
|
213
115
|
|
|
214
|
-
##
|
|
116
|
+
## Included APIs
|
|
215
117
|
|
|
216
118
|
### Components
|
|
217
119
|
|
|
218
120
|
- `ThemeSwitch` - Theme switcher button
|
|
219
|
-
- `ViewportInfo` - Viewport dimensions display
|
|
121
|
+
- `ViewportInfo` - Viewport dimensions display for development
|
|
220
122
|
- `ErrorBoundary` - Error boundary component
|
|
221
123
|
|
|
222
124
|
### Hooks
|
|
@@ -225,35 +127,41 @@ import { viteEnvironmentAdapter } from '@teo-garcia/react-shared/adapters/enviro
|
|
|
225
127
|
|
|
226
128
|
### Utilities
|
|
227
129
|
|
|
228
|
-
- `isDevelopment()` - Check if in development mode
|
|
229
|
-
- `isProduction()` - Check if in production mode
|
|
230
|
-
- `isServer()` - Check if running on server
|
|
231
|
-
- `isClient()` - Check if running
|
|
232
|
-
- `setupMSWBrowser()` - Setup MSW for browser
|
|
233
|
-
- `setupMSWServer()` - Setup MSW for Node.js
|
|
130
|
+
- `isDevelopment()` - Check if running in development mode
|
|
131
|
+
- `isProduction()` - Check if running in production mode
|
|
132
|
+
- `isServer()` - Check if running on the server
|
|
133
|
+
- `isClient()` - Check if running in the browser
|
|
134
|
+
- `setupMSWBrowser()` - Setup MSW for browser usage
|
|
135
|
+
- `setupMSWServer()` - Setup MSW for Node.js and test usage
|
|
234
136
|
|
|
235
137
|
### Adapters
|
|
236
138
|
|
|
237
|
-
|
|
139
|
+
- `useNextThemesAdapter()` - Adapter for `next-themes`
|
|
140
|
+
- `createCustomThemeAdapter()` - Adapter for custom theme providers
|
|
141
|
+
- `nextEnvironmentAdapter` - Environment adapter for Next.js
|
|
142
|
+
- `viteEnvironmentAdapter` - Environment adapter for Vite-based apps
|
|
238
143
|
|
|
239
|
-
|
|
240
|
-
- `createCustomThemeAdapter()` - Create adapter for custom theme provider
|
|
144
|
+
## Notes
|
|
241
145
|
|
|
242
|
-
|
|
146
|
+
- Components assume Tailwind CSS is available in the consuming app.
|
|
147
|
+
- Hooks and adapters are designed to be framework-agnostic where possible.
|
|
148
|
+
- Consumers should import only the module paths they need.
|
|
243
149
|
|
|
244
|
-
|
|
245
|
-
- `viteEnvironmentAdapter` - Environment detection for Vite
|
|
246
|
-
|
|
247
|
-
## Requirements
|
|
150
|
+
## Related Packages
|
|
248
151
|
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
-
|
|
152
|
+
| Package | Description |
|
|
153
|
+
| ------------------------------------------------------------------------------------------ | ------------------- |
|
|
154
|
+
| [@teo-garcia/eslint-config-shared](https://github.com/teo-garcia/eslint-config-shared) | ESLint rules |
|
|
155
|
+
| [@teo-garcia/prettier-config-shared](https://github.com/teo-garcia/prettier-config-shared) | Prettier formatting |
|
|
156
|
+
| [@teo-garcia/tsconfig-shared](https://github.com/teo-garcia/tsconfig-shared) | TypeScript settings |
|
|
157
|
+
| [@teo-garcia/vitest-config-shared](https://github.com/teo-garcia/vitest-config-shared) | Test configuration |
|
|
252
158
|
|
|
253
159
|
## License
|
|
254
160
|
|
|
255
161
|
MIT
|
|
256
162
|
|
|
257
|
-
|
|
163
|
+
---
|
|
258
164
|
|
|
259
|
-
|
|
165
|
+
<div align="center">
|
|
166
|
+
<sub>Built by <a href="https://github.com/teo-garcia">teo-garcia</a></sub>
|
|
167
|
+
</div>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"error-boundary.d.ts","sourceRoot":"","sources":["../../../src/components/error-boundary/error-boundary.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAA;AAEjD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAA;AAErD,UAAU,kBAAkB;IAC1B,QAAQ,EAAE,OAAO,CAAA;IACjB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAA;CACpB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgDG;AACH,qBAAa,aAAc,SAAQ,SAAS,
|
|
1
|
+
{"version":3,"file":"error-boundary.d.ts","sourceRoot":"","sources":["../../../src/components/error-boundary/error-boundary.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAA;AAEjD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAA;AAErD,UAAU,kBAAkB;IAC1B,QAAQ,EAAE,OAAO,CAAA;IACjB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAA;CACpB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgDG;AACH,qBAAa,aAAc,SAAQ,SAAS,CAC1C,kBAAkB,EAClB,kBAAkB,CACnB;gBACa,KAAK,EAAE,kBAAkB;IAKrC;;;OAGG;IACH,MAAM,CAAC,wBAAwB,CAAC,KAAK,EAAE,KAAK,GAAG,kBAAkB;IAIjE;;;OAGG;IACH,iBAAiB,CAAC,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,CAAC,SAAS,GAAG,IAAI;IAOjE,MAAM,IAAI,SAAS;CA0CpB"}
|
|
@@ -85,7 +85,7 @@ export class ErrorBoundary extends Component {
|
|
|
85
85
|
return fallback;
|
|
86
86
|
}
|
|
87
87
|
// Default fallback UI if none provided
|
|
88
|
-
return (_jsxs("div", { role:
|
|
88
|
+
return (_jsxs("div", { role: 'alert', style: {
|
|
89
89
|
padding: '20px',
|
|
90
90
|
margin: '20px',
|
|
91
91
|
border: '1px solid #f5c6cb',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/components/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/components/index.ts"],"names":[],"mappings":"AAAA,cAAc,2BAA2B,CAAA"}
|
package/dist/components/index.js
CHANGED
package/dist/hooks/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
export {
|
|
5
|
-
export
|
|
1
|
+
export { useDebounce } from './use-debounce.js';
|
|
2
|
+
export { useIsomorphicLayoutEffect } from './use-isomorphic-layout-effect.js';
|
|
3
|
+
export { useLocalStorage } from './use-local-storage.js';
|
|
4
|
+
export { useMediaQuery } from './use-media-query.js';
|
|
5
|
+
export { useOnClickOutside } from './use-on-click-outside.js';
|
|
6
|
+
export { usePrevious } from './use-previous.js';
|
|
6
7
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/hooks/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/hooks/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAC/C,OAAO,EAAE,yBAAyB,EAAE,MAAM,mCAAmC,CAAA;AAC7E,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAA;AACxD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AACpD,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAA;AAC7D,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA"}
|
package/dist/hooks/index.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
export {
|
|
1
|
+
export { useDebounce } from './use-debounce.js';
|
|
2
|
+
export { useIsomorphicLayoutEffect } from './use-isomorphic-layout-effect.js';
|
|
3
|
+
export { useLocalStorage } from './use-local-storage.js';
|
|
4
|
+
export { useMediaQuery } from './use-media-query.js';
|
|
5
|
+
export { useOnClickOutside } from './use-on-click-outside.js';
|
|
6
|
+
export { usePrevious } from './use-previous.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-debounce.d.ts","sourceRoot":"","sources":["../../src/hooks/use-debounce.ts"],"names":[],"mappings":"AAEA,wBAAgB,WAAW,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,GAAG,CAAC,CASzD"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { useEffect, useState } from 'react';
|
|
2
|
+
export function useDebounce(value, delay) {
|
|
3
|
+
const [debouncedValue, setDebouncedValue] = useState(value);
|
|
4
|
+
useEffect(() => {
|
|
5
|
+
const timer = setTimeout(() => setDebouncedValue(value), delay);
|
|
6
|
+
return () => clearTimeout(timer);
|
|
7
|
+
}, [value, delay]);
|
|
8
|
+
return debouncedValue;
|
|
9
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-isomorphic-layout-effect.d.ts","sourceRoot":"","sources":["../../src/hooks/use-isomorphic-layout-effect.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAmB,MAAM,OAAO,CAAA;AAIlD,eAAO,MAAM,yBAAyB,kBACuB,CAAA"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { useEffect, useLayoutEffect } from 'react';
|
|
2
|
+
// useLayoutEffect warns in SSR. This hook silences that by falling back to
|
|
3
|
+
// useEffect on the server where window is not available.
|
|
4
|
+
export const useIsomorphicLayoutEffect = typeof window !== 'undefined' ? useLayoutEffect : useEffect;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-local-storage.d.ts","sourceRoot":"","sources":["../../src/hooks/use-local-storage.ts"],"names":[],"mappings":"AAYA,wBAAgB,eAAe,CAAC,CAAC,EAC/B,GAAG,EAAE,MAAM,EACX,YAAY,EAAE,CAAC,GACd,CAAC,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,IAAI,EAAE,MAAM,IAAI,CAAC,CAmCxD"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { useCallback, useRef, useState } from 'react';
|
|
2
|
+
function readFromStorage(key, fallback) {
|
|
3
|
+
if (typeof window === 'undefined')
|
|
4
|
+
return fallback;
|
|
5
|
+
try {
|
|
6
|
+
const item = window.localStorage.getItem(key);
|
|
7
|
+
return item !== null ? JSON.parse(item) : fallback;
|
|
8
|
+
}
|
|
9
|
+
catch {
|
|
10
|
+
return fallback;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
export function useLocalStorage(key, initialValue) {
|
|
14
|
+
const initialValueRef = useRef(initialValue);
|
|
15
|
+
const [storedValue, setStoredValue] = useState(() => readFromStorage(key, initialValueRef.current));
|
|
16
|
+
const setValue = useCallback((value) => {
|
|
17
|
+
setStoredValue((prev) => {
|
|
18
|
+
const next = value instanceof Function ? value(prev) : value;
|
|
19
|
+
if (typeof window !== 'undefined') {
|
|
20
|
+
try {
|
|
21
|
+
window.localStorage.setItem(key, JSON.stringify(next));
|
|
22
|
+
}
|
|
23
|
+
catch (error) {
|
|
24
|
+
console.error(`useLocalStorage: failed to write key "${key}"`, error);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return next;
|
|
28
|
+
});
|
|
29
|
+
}, [key]);
|
|
30
|
+
const removeValue = useCallback(() => {
|
|
31
|
+
if (typeof window !== 'undefined') {
|
|
32
|
+
window.localStorage.removeItem(key);
|
|
33
|
+
}
|
|
34
|
+
setStoredValue(initialValueRef.current);
|
|
35
|
+
}, [key]);
|
|
36
|
+
return [storedValue, setValue, removeValue];
|
|
37
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-media-query.d.ts","sourceRoot":"","sources":["../../src/hooks/use-media-query.ts"],"names":[],"mappings":"AAEA,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAkBpD"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { useEffect, useState } from 'react';
|
|
2
|
+
export function useMediaQuery(query) {
|
|
3
|
+
const [matches, setMatches] = useState(() => {
|
|
4
|
+
if (typeof window === 'undefined')
|
|
5
|
+
return false;
|
|
6
|
+
return window.matchMedia(query).matches;
|
|
7
|
+
});
|
|
8
|
+
useEffect(() => {
|
|
9
|
+
if (typeof window === 'undefined')
|
|
10
|
+
return;
|
|
11
|
+
const mql = window.matchMedia(query);
|
|
12
|
+
setMatches(mql.matches);
|
|
13
|
+
const handler = (event) => setMatches(event.matches);
|
|
14
|
+
mql.addEventListener('change', handler);
|
|
15
|
+
return () => mql.removeEventListener('change', handler);
|
|
16
|
+
}, [query]);
|
|
17
|
+
return matches;
|
|
18
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-on-click-outside.d.ts","sourceRoot":"","sources":["../../src/hooks/use-on-click-outside.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAa,MAAM,OAAO,CAAA;AAEjD,wBAAgB,iBAAiB,CAAC,CAAC,SAAS,WAAW,EACrD,GAAG,EAAE,SAAS,CAAC,CAAC,GAAG,IAAI,CAAC,EACxB,OAAO,EAAE,CAAC,KAAK,EAAE,UAAU,GAAG,UAAU,KAAK,IAAI,GAChD,IAAI,CAeN"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { useEffect } from 'react';
|
|
2
|
+
export function useOnClickOutside(ref, handler) {
|
|
3
|
+
useEffect(() => {
|
|
4
|
+
const listener = (event) => {
|
|
5
|
+
const el = ref.current;
|
|
6
|
+
if (!el || el.contains(event.target))
|
|
7
|
+
return;
|
|
8
|
+
handler(event);
|
|
9
|
+
};
|
|
10
|
+
document.addEventListener('mousedown', listener);
|
|
11
|
+
document.addEventListener('touchstart', listener);
|
|
12
|
+
return () => {
|
|
13
|
+
document.removeEventListener('mousedown', listener);
|
|
14
|
+
document.removeEventListener('touchstart', listener);
|
|
15
|
+
};
|
|
16
|
+
}, [ref, handler]);
|
|
17
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-previous.d.ts","sourceRoot":"","sources":["../../src/hooks/use-previous.ts"],"names":[],"mappings":"AAEA,wBAAgB,WAAW,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,CAAC,GAAG,SAAS,CAQtD"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @teo-garcia/react-shared
|
|
3
3
|
*
|
|
4
|
-
* Shared React
|
|
4
|
+
* Shared React hooks, utilities, and test helpers for the teo-garcia template portfolio.
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
6
|
+
* Exports:
|
|
7
|
+
* - Hooks: useDebounce, useIsomorphicLayoutEffect, useLocalStorage, useMediaQuery, useOnClickOutside, usePrevious
|
|
8
|
+
* - Components: ErrorBoundary
|
|
9
|
+
* - Utils: cn (clsx + tailwind-merge)
|
|
10
|
+
* - Test utilities: createWrapper, renderWithProviders (import from react-shared/test-utils)
|
|
8
11
|
*
|
|
9
12
|
* @packageDocumentation
|
|
10
13
|
*/
|
|
11
14
|
export * from './components/index.js';
|
|
12
15
|
export * from './hooks/index.js';
|
|
13
16
|
export * from './utils/index.js';
|
|
14
|
-
export * from './adapters/index.js';
|
|
15
17
|
export * from './types.js';
|
|
16
18
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,cAAc,uBAAuB,CAAA;AACrC,cAAc,kBAAkB,CAAA;AAChC,cAAc,kBAAkB,CAAA;AAChC,cAAc,YAAY,CAAA"}
|
package/dist/index.js
CHANGED
|
@@ -1,20 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @teo-garcia/react-shared
|
|
3
3
|
*
|
|
4
|
-
* Shared React
|
|
4
|
+
* Shared React hooks, utilities, and test helpers for the teo-garcia template portfolio.
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
6
|
+
* Exports:
|
|
7
|
+
* - Hooks: useDebounce, useIsomorphicLayoutEffect, useLocalStorage, useMediaQuery, useOnClickOutside, usePrevious
|
|
8
|
+
* - Components: ErrorBoundary
|
|
9
|
+
* - Utils: cn (clsx + tailwind-merge)
|
|
10
|
+
* - Test utilities: createWrapper, renderWithProviders (import from react-shared/test-utils)
|
|
8
11
|
*
|
|
9
12
|
* @packageDocumentation
|
|
10
13
|
*/
|
|
11
|
-
// Export all components
|
|
12
14
|
export * from './components/index.js';
|
|
13
|
-
// Export all hooks
|
|
14
15
|
export * from './hooks/index.js';
|
|
15
|
-
// Export all utilities
|
|
16
16
|
export * from './utils/index.js';
|
|
17
|
-
// Export all adapters
|
|
18
|
-
export * from './adapters/index.js';
|
|
19
|
-
// Export all types
|
|
20
17
|
export * from './types.js';
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { QueryClient } from '@tanstack/react-query';
|
|
2
|
+
import { type RenderOptions, type RenderResult } from '@testing-library/react';
|
|
3
|
+
import { type ReactNode } from 'react';
|
|
4
|
+
export interface WrapperOptions {
|
|
5
|
+
queryClient?: QueryClient;
|
|
6
|
+
}
|
|
7
|
+
export declare function createWrapper(options?: WrapperOptions): ({ children }: {
|
|
8
|
+
children: ReactNode;
|
|
9
|
+
}) => import("react").FunctionComponentElement<import("@tanstack/react-query").QueryClientProviderProps>;
|
|
10
|
+
export interface RenderWithProvidersOptions extends Omit<RenderOptions, 'wrapper'> {
|
|
11
|
+
queryClient?: QueryClient;
|
|
12
|
+
}
|
|
13
|
+
export declare function renderWithProviders(ui: React.ReactElement, options?: RenderWithProvidersOptions): RenderResult;
|
|
14
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/test-utils/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAuB,MAAM,uBAAuB,CAAA;AACxE,OAAO,EAEL,KAAK,aAAa,EAClB,KAAK,YAAY,EAClB,MAAM,wBAAwB,CAAA;AAC/B,OAAO,EAAiB,KAAK,SAAS,EAAE,MAAM,OAAO,CAAA;AAErD,MAAM,WAAW,cAAc;IAC7B,WAAW,CAAC,EAAE,WAAW,CAAA;CAC1B;AAED,wBAAgB,aAAa,CAAC,OAAO,GAAE,cAAmB,IAUhC,cAAc;IAAE,QAAQ,EAAE,SAAS,CAAA;CAAE,wGAG9D;AAED,MAAM,WAAW,0BACf,SAAQ,IAAI,CAAC,aAAa,EAAE,SAAS,CAAC;IACtC,WAAW,CAAC,EAAE,WAAW,CAAA;CAC1B;AAED,wBAAgB,mBAAmB,CACjC,EAAE,EAAE,KAAK,CAAC,YAAY,EACtB,OAAO,GAAE,0BAA+B,GACvC,YAAY,CAMd"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
|
2
|
+
import { render, } from '@testing-library/react';
|
|
3
|
+
import { createElement } from 'react';
|
|
4
|
+
export function createWrapper(options = {}) {
|
|
5
|
+
const client = options.queryClient ??
|
|
6
|
+
new QueryClient({
|
|
7
|
+
defaultOptions: {
|
|
8
|
+
queries: { retry: false, gcTime: 0 },
|
|
9
|
+
mutations: { retry: false },
|
|
10
|
+
},
|
|
11
|
+
});
|
|
12
|
+
return function Wrapper({ children }) {
|
|
13
|
+
return createElement(QueryClientProvider, { client }, children);
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
export function renderWithProviders(ui, options = {}) {
|
|
17
|
+
const { queryClient, ...renderOptions } = options;
|
|
18
|
+
return render(ui, {
|
|
19
|
+
wrapper: createWrapper({ queryClient }),
|
|
20
|
+
...renderOptions,
|
|
21
|
+
});
|
|
22
|
+
}
|