@zubyjs/react 1.0.36 → 1.0.37
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/hooks/index.d.ts +1 -0
- package/hooks/index.js +1 -0
- package/hooks/useFetch.d.ts +28 -0
- package/hooks/useFetch.js +101 -0
- package/package.json +1 -1
- package/router.d.ts +5 -0
- package/router.js +8 -1
package/hooks/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { useFetch } from './useFetch.js';
|
package/hooks/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { useFetch } from './useFetch.js';
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
type FetchResponse = Object | string;
|
|
2
|
+
interface FetchResponseMetadata {
|
|
3
|
+
bodyUsed: boolean;
|
|
4
|
+
contentType: null | string;
|
|
5
|
+
headers: Headers;
|
|
6
|
+
ok: boolean;
|
|
7
|
+
redirected: boolean;
|
|
8
|
+
response: FetchResponse;
|
|
9
|
+
status: number;
|
|
10
|
+
statusText: string;
|
|
11
|
+
url: string;
|
|
12
|
+
}
|
|
13
|
+
interface Options {
|
|
14
|
+
lifespan?: number;
|
|
15
|
+
metadata?: boolean;
|
|
16
|
+
}
|
|
17
|
+
interface OptionsWithMetadata extends Options {
|
|
18
|
+
metadata: true;
|
|
19
|
+
}
|
|
20
|
+
interface OptionsWithoutMetadata extends Options {
|
|
21
|
+
metadata?: false;
|
|
22
|
+
}
|
|
23
|
+
interface UseFetch {
|
|
24
|
+
(input: RequestInfo, init?: RequestInit | undefined, options?: number | OptionsWithoutMetadata): FetchResponse;
|
|
25
|
+
(input: RequestInfo, init: RequestInit | undefined, options: OptionsWithMetadata): FetchResponseMetadata;
|
|
26
|
+
}
|
|
27
|
+
export declare const useFetch: UseFetch;
|
|
28
|
+
export {};
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
const getDefaultFetchFunction = () => {
|
|
2
|
+
if (typeof window === 'undefined') {
|
|
3
|
+
return () => {
|
|
4
|
+
return Promise.reject(new Error('Cannot find `window`. Use `createUseFetch` to provide a custom `fetch` function.'));
|
|
5
|
+
};
|
|
6
|
+
}
|
|
7
|
+
if (typeof window.fetch === 'undefined') {
|
|
8
|
+
return () => {
|
|
9
|
+
return Promise.reject(new Error('Cannot find `window.fetch`. Use `createUseFetch` to provide a custom `fetch` function.'));
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
return window.fetch;
|
|
13
|
+
};
|
|
14
|
+
const createUseFetch = (fetch = getDefaultFetchFunction()) => {
|
|
15
|
+
// Create a set of caches for this hook.
|
|
16
|
+
const caches = [];
|
|
17
|
+
function useFetch(input, init, options = 0) {
|
|
18
|
+
if (typeof options === 'number') {
|
|
19
|
+
return useFetch(input, init, { lifespan: options });
|
|
20
|
+
}
|
|
21
|
+
const { metadata = false, lifespan = 0 } = options;
|
|
22
|
+
// Check each cache by this useFetch hook.
|
|
23
|
+
for (const cache of caches) {
|
|
24
|
+
// If this cache matches the request,
|
|
25
|
+
if (JSON.stringify(cache.init) === JSON.stringify(init) &&
|
|
26
|
+
JSON.stringify(cache.input) === JSON.stringify(input)) {
|
|
27
|
+
// If an error occurred, throw it so that componentDidCatch can handle
|
|
28
|
+
// it.
|
|
29
|
+
if (Object.prototype.hasOwnProperty.call(cache, 'error')) {
|
|
30
|
+
throw cache.error;
|
|
31
|
+
}
|
|
32
|
+
// If a response was successful, return it.
|
|
33
|
+
if (Object.prototype.hasOwnProperty.call(cache, 'response')) {
|
|
34
|
+
if (metadata) {
|
|
35
|
+
return {
|
|
36
|
+
bodyUsed: cache.bodyUsed,
|
|
37
|
+
contentType: cache.contentType,
|
|
38
|
+
headers: cache.headers,
|
|
39
|
+
ok: cache.ok,
|
|
40
|
+
redirected: cache.redirected,
|
|
41
|
+
response: cache.response,
|
|
42
|
+
status: cache.status,
|
|
43
|
+
statusText: cache.statusText,
|
|
44
|
+
url: cache.url,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
return cache.response;
|
|
48
|
+
}
|
|
49
|
+
// If we are still waiting, throw the Promise so that Suspense can
|
|
50
|
+
// fallback.
|
|
51
|
+
throw cache.fetch;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
// If no request in the cache matched this one, create a new cache entry.
|
|
55
|
+
const cache = {
|
|
56
|
+
// Make the fetch request.
|
|
57
|
+
fetch: fetch(input, init)
|
|
58
|
+
// Parse the response.
|
|
59
|
+
.then((response) => {
|
|
60
|
+
cache.contentType = response.headers.get('Content-Type');
|
|
61
|
+
if (metadata) {
|
|
62
|
+
cache.bodyUsed = response.bodyUsed;
|
|
63
|
+
cache.headers = response.headers;
|
|
64
|
+
cache.ok = response.ok;
|
|
65
|
+
cache.redirected = response.redirected;
|
|
66
|
+
cache.status = response.status;
|
|
67
|
+
cache.statusText = response.statusText;
|
|
68
|
+
}
|
|
69
|
+
if (cache.contentType && cache.contentType.indexOf('application/json') !== -1) {
|
|
70
|
+
return response.json();
|
|
71
|
+
}
|
|
72
|
+
return response.text();
|
|
73
|
+
})
|
|
74
|
+
// Cache the response.
|
|
75
|
+
.then((response) => {
|
|
76
|
+
cache.response = response;
|
|
77
|
+
})
|
|
78
|
+
// Handle an error.
|
|
79
|
+
.catch((e) => {
|
|
80
|
+
cache.error = e;
|
|
81
|
+
})
|
|
82
|
+
// Invalidate the cache.
|
|
83
|
+
.then(() => {
|
|
84
|
+
if (lifespan > 0) {
|
|
85
|
+
setTimeout(() => {
|
|
86
|
+
const index = caches.indexOf(cache);
|
|
87
|
+
if (index !== -1) {
|
|
88
|
+
caches.splice(index, 1);
|
|
89
|
+
}
|
|
90
|
+
}, lifespan);
|
|
91
|
+
}
|
|
92
|
+
}),
|
|
93
|
+
init,
|
|
94
|
+
input,
|
|
95
|
+
};
|
|
96
|
+
caches.push(cache);
|
|
97
|
+
throw cache.fetch;
|
|
98
|
+
}
|
|
99
|
+
return useFetch;
|
|
100
|
+
};
|
|
101
|
+
export const useFetch = createUseFetch();
|
package/package.json
CHANGED
package/router.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { useRoute, useRouter, useParams, useLocation, Link, LinkProps, Redirect, RedirectProps, } from 'wouter';
|
|
2
|
+
import { LazyTemplate } from 'zuby/templates/types.js';
|
|
2
3
|
import { ZubyPageContext } from 'zuby/pageContext/index.js';
|
|
3
4
|
/**
|
|
4
5
|
* Zuby's Router component provides support for file-system based routing.
|
|
@@ -6,3 +7,7 @@ import { ZubyPageContext } from 'zuby/pageContext/index.js';
|
|
|
6
7
|
export default function Router({ context }: {
|
|
7
8
|
context: ZubyPageContext;
|
|
8
9
|
}): import("react/jsx-runtime").JSX.Element;
|
|
10
|
+
export declare function Page({ page, context }: {
|
|
11
|
+
page: LazyTemplate;
|
|
12
|
+
context: ZubyPageContext;
|
|
13
|
+
}): import("react/jsx-runtime").JSX.Element;
|
package/router.js
CHANGED
|
@@ -3,6 +3,7 @@ import { Router as WouterRouter, Route as WouterRoute, Switch as WouterSwitch }
|
|
|
3
3
|
export { useRoute, useRouter, useParams, useLocation, Link, Redirect, } from 'wouter';
|
|
4
4
|
import { Suspense, lazy } from 'react';
|
|
5
5
|
import { createElement } from 'react';
|
|
6
|
+
import { useFetch } from './hooks/index.js';
|
|
6
7
|
let pages;
|
|
7
8
|
let apps;
|
|
8
9
|
let errors;
|
|
@@ -31,7 +32,7 @@ export default function Router({ context }) {
|
|
|
31
32
|
return pathRegex.test(context.url.pathname ?? '');
|
|
32
33
|
});
|
|
33
34
|
const routes = [
|
|
34
|
-
...pages.map((page) => (_jsx(WouterRoute, { path: page.path, children: _jsx(
|
|
35
|
+
...pages.map((page) => (_jsx(WouterRoute, { path: page.path, children: _jsx(Page, { context: context, page: page }) }, page.path))),
|
|
35
36
|
_jsx(WouterRoute, { children: error?.component && (_jsx(error.component, { context: context, statusCode: (context.statusCode = 404), message: 'Page was not found' })) }, "error"),
|
|
36
37
|
];
|
|
37
38
|
const page = _jsx(WouterSwitch, { children: routes });
|
|
@@ -39,3 +40,9 @@ export default function Router({ context }) {
|
|
|
39
40
|
children: page,
|
|
40
41
|
}) }) }));
|
|
41
42
|
}
|
|
43
|
+
export function Page({ page, context }) {
|
|
44
|
+
if (typeof window !== 'undefined') {
|
|
45
|
+
context.props = useFetch('/_props' + context.url.pathname);
|
|
46
|
+
}
|
|
47
|
+
return _jsx(page.component, { context: context });
|
|
48
|
+
}
|