@zubyjs/react 1.0.66 → 1.0.68
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/components/Text.d.ts +13 -0
- package/components/Text.js +16 -0
- package/components/index.d.ts +1 -0
- package/components/index.js +1 -0
- package/contexts/pageContext.d.ts +2 -0
- package/contexts/pageContext.js +3 -0
- package/hooks/index.d.ts +2 -1
- package/hooks/index.js +2 -1
- package/hooks/useLocalization.d.ts +9 -0
- package/hooks/useLocalization.js +12 -0
- package/hooks/usePageContext.d.ts +1 -0
- package/hooks/usePageContext.js +5 -0
- package/hooks/useTranslations.d.ts +7 -0
- package/hooks/useTranslations.js +19 -0
- package/image.d.ts +2 -1
- package/image.js +2 -2
- package/package.json +1 -1
- package/router.d.ts +1 -0
- package/router.js +23 -9
- package/templates/entry.js +1 -3
- package/hooks/useFetch.d.ts +0 -31
- package/hooks/useFetch.js +0 -101
- package/hooks/useProps.d.ts +0 -1
- package/hooks/useProps.js +0 -8
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { PropsWithChildren } from 'react';
|
|
2
|
+
export interface TextProps extends PropsWithChildren {
|
|
3
|
+
key: string;
|
|
4
|
+
locale?: string;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* The `Text` component is used to translate text in the application
|
|
8
|
+
* @param props.key - The key of the translation
|
|
9
|
+
* @param props.locale - The locale to use for the translation
|
|
10
|
+
* @param props.children - The backup text to use if the translation is not found
|
|
11
|
+
* @returns
|
|
12
|
+
*/
|
|
13
|
+
export declare function Text(props: TextProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Fragment as _Fragment, jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useLocalization } from '../hooks/index.js';
|
|
3
|
+
/**
|
|
4
|
+
* The `Text` component is used to translate text in the application
|
|
5
|
+
* @param props.key - The key of the translation
|
|
6
|
+
* @param props.locale - The locale to use for the translation
|
|
7
|
+
* @param props.children - The backup text to use if the translation is not found
|
|
8
|
+
* @returns
|
|
9
|
+
*/
|
|
10
|
+
export function Text(props) {
|
|
11
|
+
const { key, children, locale } = props;
|
|
12
|
+
const localizedText = useLocalization(key, '', {
|
|
13
|
+
locale,
|
|
14
|
+
});
|
|
15
|
+
return _jsx(_Fragment, { children: localizedText.length > 0 ? localizedText : children });
|
|
16
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './Text.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './Text.js';
|
package/hooks/index.d.ts
CHANGED
package/hooks/index.js
CHANGED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Returns the localized text for the given key.
|
|
3
|
+
* @param key The full key of the translation
|
|
4
|
+
* @param text The default text to use if the translation is not found
|
|
5
|
+
* @param options Additional options for the localization
|
|
6
|
+
*/
|
|
7
|
+
export declare function useLocalization(key: string, text: string, options?: {
|
|
8
|
+
locale?: string;
|
|
9
|
+
}): string;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { useTranslations } from './useTranslations.js';
|
|
2
|
+
/**
|
|
3
|
+
* Returns the localized text for the given key.
|
|
4
|
+
* @param key The full key of the translation
|
|
5
|
+
* @param text The default text to use if the translation is not found
|
|
6
|
+
* @param options Additional options for the localization
|
|
7
|
+
*/
|
|
8
|
+
export function useLocalization(key, text, options) {
|
|
9
|
+
const namespace = key.includes('.') ? key.replace(/\.(.+)$/, '.') : '';
|
|
10
|
+
const translations = useTranslations(namespace, options?.locale);
|
|
11
|
+
return translations?.[key] || text;
|
|
12
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function usePageContext(): import("zuby/contexts/pageContext.js").PageContext;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export type Translations = Record<string, string>;
|
|
2
|
+
/**
|
|
3
|
+
* Returns the translations object for the given namespace and locale
|
|
4
|
+
* @param namespace
|
|
5
|
+
* @param locale
|
|
6
|
+
*/
|
|
7
|
+
export declare function useTranslations(namespace: string, locale?: string): Record<string, string>;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { usePageContext } from './usePageContext.js';
|
|
2
|
+
let translationsCache = new Map();
|
|
3
|
+
/**
|
|
4
|
+
* Returns the translations object for the given namespace and locale
|
|
5
|
+
* @param namespace
|
|
6
|
+
* @param locale
|
|
7
|
+
*/
|
|
8
|
+
export function useTranslations(namespace, locale) {
|
|
9
|
+
const { getTranslations, locale: currentLocale } = usePageContext();
|
|
10
|
+
locale = locale || currentLocale;
|
|
11
|
+
const namespaceWithLocale = `${namespace}.${locale}`;
|
|
12
|
+
const translations = translationsCache.get(namespaceWithLocale) || getTranslations(namespace, locale);
|
|
13
|
+
if (translations instanceof Promise) {
|
|
14
|
+
translationsCache.set(namespaceWithLocale, translations);
|
|
15
|
+
translations.then(result => translationsCache.set(namespaceWithLocale, result));
|
|
16
|
+
throw translations;
|
|
17
|
+
}
|
|
18
|
+
return translations;
|
|
19
|
+
}
|
package/image.d.ts
CHANGED
|
@@ -6,5 +6,6 @@ export interface ImageProps {
|
|
|
6
6
|
height?: number;
|
|
7
7
|
format?: ImageFormat;
|
|
8
8
|
quality?: number;
|
|
9
|
+
lazy?: boolean;
|
|
9
10
|
}
|
|
10
|
-
export default function Image({ src: originalSrc, alt, width, height, format, quality, }: ImageProps): import("react/jsx-runtime").JSX.Element;
|
|
11
|
+
export default function Image({ src: originalSrc, alt, width, height, format, quality, lazy, }: ImageProps): import("react/jsx-runtime").JSX.Element;
|
package/image.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { useGlobalContext } from 'zuby/hooks/index.js';
|
|
3
3
|
import getNearestSize from 'zuby/image/getNearestSize.js';
|
|
4
|
-
export default function Image({ src: originalSrc, alt, width, height, format, quality, }) {
|
|
4
|
+
export default function Image({ src: originalSrc, alt, width, height, format, quality, lazy, }) {
|
|
5
5
|
const context = useGlobalContext();
|
|
6
6
|
format = format || context?.image?.defaultFormat;
|
|
7
7
|
quality = quality || context?.image?.defaultQuality;
|
|
@@ -17,5 +17,5 @@ export default function Image({ src: originalSrc, alt, width, height, format, qu
|
|
|
17
17
|
isAbsolute,
|
|
18
18
|
context,
|
|
19
19
|
});
|
|
20
|
-
return _jsx("img", { src: src, alt: alt, width: width, height: height });
|
|
20
|
+
return (_jsx("img", { src: src, alt: alt, width: width, height: height, loading: lazy ? 'lazy' : 'eager' }));
|
|
21
21
|
}
|
package/package.json
CHANGED
package/router.d.ts
CHANGED
package/router.js
CHANGED
|
@@ -5,7 +5,9 @@ import { useParams } from 'wouter';
|
|
|
5
5
|
import { createElement, Suspense } from 'react';
|
|
6
6
|
import { preloadPage } from 'zuby/preload/index.js';
|
|
7
7
|
import lazyWithPreload from './components/lazyWithPreload.js';
|
|
8
|
-
import useProps from '
|
|
8
|
+
import { useProps } from 'zuby/hooks/useProps.js';
|
|
9
|
+
import { pageContext } from './contexts/pageContext.js';
|
|
10
|
+
import { usePageContext } from '@zubyjs/preact/src/hooks/index.js';
|
|
9
11
|
let pages;
|
|
10
12
|
let apps;
|
|
11
13
|
let errors;
|
|
@@ -35,15 +37,20 @@ export default function Router({ context }) {
|
|
|
35
37
|
_jsx(WouterRoute, { children: error?.component && _jsx(Error, { context: context, error: error }) }, "error"),
|
|
36
38
|
];
|
|
37
39
|
const page = _jsx(WouterSwitch, { children: routes });
|
|
38
|
-
return (_jsx(WouterRouter, { ssrPath: context.url.pathname, children: _jsx(Suspense, { fallback: loader?.component && _jsx(loader.component, {}), children: createElement(app?.component, {
|
|
39
|
-
|
|
40
|
-
|
|
40
|
+
return (_jsx(pageContext.Provider, { value: context, children: _jsx(WouterRouter, { ssrPath: context.url.pathname, children: _jsx(Suspense, { fallback: loader?.component && _jsx(loader.component, {}), children: createElement(app?.component, {
|
|
41
|
+
children: page,
|
|
42
|
+
}) }) }) }));
|
|
41
43
|
}
|
|
42
44
|
export function Page({ page, context }) {
|
|
43
45
|
context.statusCode = 200;
|
|
44
46
|
context.params = useParams();
|
|
45
|
-
if (typeof window !== 'undefined'
|
|
46
|
-
|
|
47
|
+
if (typeof window !== 'undefined') {
|
|
48
|
+
if (context.isInitialPath) {
|
|
49
|
+
context.props = globalThis.initialPageContext || {};
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
context.props = useProps(context.url.pathname);
|
|
53
|
+
}
|
|
47
54
|
}
|
|
48
55
|
return _jsx(page.component, { ...context.props, context: context });
|
|
49
56
|
}
|
|
@@ -72,15 +79,22 @@ function matchTemplate(template, path) {
|
|
|
72
79
|
}
|
|
73
80
|
export function Link(props) {
|
|
74
81
|
const [isActive] = useRoute(props.href);
|
|
75
|
-
const
|
|
82
|
+
const { localizePath } = usePageContext();
|
|
83
|
+
let href = props.href || props.to || '#';
|
|
84
|
+
href = props?.locale ? localizePath(href, props.locale) : href;
|
|
85
|
+
const isRelative = href?.startsWith('/');
|
|
86
|
+
// Alias for Preact class names
|
|
76
87
|
props.activeClassName = props.activeClassName || 'active';
|
|
77
|
-
props.className = props
|
|
88
|
+
props.className = props.className || '';
|
|
78
89
|
const className = `${props?.className} ${isActive ? props.activeClassName : ''}`;
|
|
79
90
|
// Preload the page
|
|
80
|
-
if (href) {
|
|
91
|
+
if (href && isRelative) {
|
|
81
92
|
preloadPage(href, () => {
|
|
82
93
|
try {
|
|
83
94
|
matchTemplate(pages || [], href)?.component?.preload();
|
|
95
|
+
}
|
|
96
|
+
catch (_e) { }
|
|
97
|
+
try {
|
|
84
98
|
useProps(href, 'low');
|
|
85
99
|
}
|
|
86
100
|
catch (_e) { }
|
package/templates/entry.js
CHANGED
|
@@ -5,9 +5,7 @@ import { hydrateRoot, createRoot } from 'react-dom/client';
|
|
|
5
5
|
import Router from '@zubyjs/react/router.js';
|
|
6
6
|
import { PageContext } from 'zuby/contexts/index.js';
|
|
7
7
|
if (typeof window !== 'undefined') {
|
|
8
|
-
const pageContext = new PageContext(
|
|
9
|
-
...(globalThis?.initialPageContext || {}),
|
|
10
|
-
});
|
|
8
|
+
const pageContext = new PageContext();
|
|
11
9
|
const appElement = document.getElementById('app');
|
|
12
10
|
if (appElement.hasChildNodes()) {
|
|
13
11
|
hydrateRoot(appElement, _jsx(Router, { context: pageContext }));
|
package/hooks/useFetch.d.ts
DELETED
|
@@ -1,31 +0,0 @@
|
|
|
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?: UseRequestInit | undefined, options?: number | OptionsWithoutMetadata): FetchResponse;
|
|
25
|
-
(input: RequestInfo, init: UseRequestInit | undefined, options: OptionsWithMetadata): FetchResponseMetadata;
|
|
26
|
-
}
|
|
27
|
-
export interface UseRequestInit extends RequestInit {
|
|
28
|
-
priority?: 'low' | 'high' | 'auto';
|
|
29
|
-
}
|
|
30
|
-
export declare const useFetch: UseFetch;
|
|
31
|
-
export {};
|
package/hooks/useFetch.js
DELETED
|
@@ -1,101 +0,0 @@
|
|
|
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/hooks/useProps.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export default function useProps(path: string, priority?: 'low' | 'high' | 'auto'): string | Object;
|
package/hooks/useProps.js
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import { useFetch } from './useFetch.js';
|
|
2
|
-
import { getGlobalContext } from 'zuby/contexts/index.js';
|
|
3
|
-
export default function useProps(path, priority = 'auto') {
|
|
4
|
-
const { buildId } = getGlobalContext();
|
|
5
|
-
path = `/_props${path}/?${buildId}`;
|
|
6
|
-
path = path.replace(/\/+/g, '/');
|
|
7
|
-
return useFetch(path);
|
|
8
|
-
}
|