react-solidlike 2.5.2 → 2.5.4
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/dist/QueryBoundary.d.ts +3 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +39 -16
- package/dist/utils.d.ts +5 -0
- package/package.json +2 -2
package/dist/QueryBoundary.d.ts
CHANGED
|
@@ -13,6 +13,8 @@ export interface QueryResult<T> {
|
|
|
13
13
|
export interface QueryBoundaryProps<T> {
|
|
14
14
|
/** Query result object, usually from @tanstack/react-query's useQuery | 查询结果对象,通常来自 @tanstack/react-query 的 useQuery */
|
|
15
15
|
query: QueryResult<T> | null | undefined;
|
|
16
|
+
/** When false, renders nothing directly | 为 false 时直接不渲染任何内容 */
|
|
17
|
+
when?: boolean;
|
|
16
18
|
/** Content to show while loading | 加载中时显示的内容 */
|
|
17
19
|
loading?: ReactNode | (() => ReactNode);
|
|
18
20
|
/** Content to show when error occurs | 发生错误时显示的内容 */
|
|
@@ -57,4 +59,4 @@ export interface QueryBoundaryProps<T> {
|
|
|
57
59
|
* {(data) => <ItemList items={data.items} />}
|
|
58
60
|
* </QueryBoundary>
|
|
59
61
|
*/
|
|
60
|
-
export declare function QueryBoundary<T>({ query, loading, error, empty, children, isEmptyFn, }: QueryBoundaryProps<T>): ReactNode;
|
|
62
|
+
export declare function QueryBoundary<T>({ query, when, loading, error, empty, children, isEmptyFn, }: QueryBoundaryProps<T>): ReactNode;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
export { Await, type AwaitProps } from "./Await";
|
|
2
|
+
export { ClientOnly, type ClientOnlyProps } from "./ClientOnly";
|
|
2
3
|
export { Dynamic, type DynamicProps } from "./Dynamic";
|
|
3
4
|
export { ErrorBoundary, type ErrorBoundaryProps } from "./ErrorBoundary";
|
|
4
5
|
export { For, type ForProps } from "./For";
|
|
6
|
+
export { Once, type OnceProps } from "./Once";
|
|
5
7
|
export { QueryBoundary, type QueryBoundaryProps, type QueryResult } from "./QueryBoundary";
|
|
6
8
|
export { Repeat, type RepeatProps } from "./Repeat";
|
|
7
9
|
export { Show, type ShowProps } from "./Show";
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import { Children, Component, Fragment, cloneElement, createElement, isValidElement, useEffect, useRef, useState } from "react";
|
|
2
2
|
import { jsx } from "react/jsx-runtime";
|
|
3
3
|
|
|
4
|
+
function resolveNode(node) {
|
|
5
|
+
return typeof node === "function" ? node() : node;
|
|
6
|
+
}
|
|
7
|
+
|
|
4
8
|
function Await({ promise, loading = null, error = null, children }) {
|
|
5
9
|
const [state, setState] = useState(() => {
|
|
6
10
|
if (!(promise instanceof Promise)) return {
|
|
@@ -34,17 +38,24 @@ function Await({ promise, loading = null, error = null, children }) {
|
|
|
34
38
|
cancelled = true;
|
|
35
39
|
};
|
|
36
40
|
}, [promise]);
|
|
37
|
-
if (state.status === "pending") return
|
|
38
|
-
if (state.status === "rejected")
|
|
39
|
-
if (typeof error === "function") return error(state.error);
|
|
40
|
-
return error;
|
|
41
|
-
}
|
|
41
|
+
if (state.status === "pending") return resolveNode(loading);
|
|
42
|
+
if (state.status === "rejected") return typeof error === "function" ? error(state.error) : error;
|
|
42
43
|
if (typeof children === "function") return children(state.value);
|
|
43
44
|
return children;
|
|
44
45
|
}
|
|
45
46
|
|
|
47
|
+
function ClientOnly({ children, fallback = null }) {
|
|
48
|
+
const [isClient, setIsClient] = useState(false);
|
|
49
|
+
useEffect(() => {
|
|
50
|
+
setIsClient(true);
|
|
51
|
+
}, []);
|
|
52
|
+
if (!isClient) return resolveNode(fallback);
|
|
53
|
+
if (typeof children === "function") return children();
|
|
54
|
+
return children;
|
|
55
|
+
}
|
|
56
|
+
|
|
46
57
|
function Dynamic({ component, fallback = null, ...props }) {
|
|
47
|
-
if (!component) return
|
|
58
|
+
if (!component) return resolveNode(fallback);
|
|
48
59
|
return createElement(component, props);
|
|
49
60
|
}
|
|
50
61
|
|
|
@@ -88,6 +99,18 @@ function For({ each, children, keyExtractor, fallback = null, wrapper, reverse }
|
|
|
88
99
|
return wrapper && isValidElement(wrapper) ? cloneElement(wrapper, {}, elements) : elements;
|
|
89
100
|
}
|
|
90
101
|
|
|
102
|
+
function Once({ children }) {
|
|
103
|
+
const cachedRef = useRef({
|
|
104
|
+
rendered: false,
|
|
105
|
+
content: null
|
|
106
|
+
});
|
|
107
|
+
if (!cachedRef.current.rendered) {
|
|
108
|
+
cachedRef.current.rendered = true;
|
|
109
|
+
cachedRef.current.content = children;
|
|
110
|
+
}
|
|
111
|
+
return cachedRef.current.content;
|
|
112
|
+
}
|
|
113
|
+
|
|
91
114
|
function defaultIsEmpty(data) {
|
|
92
115
|
if (data == null) return true;
|
|
93
116
|
if (Array.isArray(data)) return data.length === 0;
|
|
@@ -95,12 +118,12 @@ function defaultIsEmpty(data) {
|
|
|
95
118
|
return false;
|
|
96
119
|
}
|
|
97
120
|
|
|
98
|
-
function QueryBoundary({ query, loading = null, error = null, empty = null, children, isEmptyFn = defaultIsEmpty }) {
|
|
99
|
-
if (!query) return null;
|
|
121
|
+
function QueryBoundary({ query, when = true, loading = null, error = null, empty = null, children, isEmptyFn = defaultIsEmpty }) {
|
|
122
|
+
if (!when || !query) return null;
|
|
100
123
|
const { data, isPending, isError, isEmpty: queryIsEmpty } = query;
|
|
101
|
-
if (isPending) return
|
|
102
|
-
if (isError && isEmptyFn(data)) return
|
|
103
|
-
if (queryIsEmpty ?? isEmptyFn(data)) return
|
|
124
|
+
if (isPending) return resolveNode(loading);
|
|
125
|
+
if (isError && isEmptyFn(data)) return resolveNode(error);
|
|
126
|
+
if (queryIsEmpty ?? isEmptyFn(data)) return resolveNode(empty);
|
|
104
127
|
if (typeof children === "function") return children(data);
|
|
105
128
|
return children;
|
|
106
129
|
}
|
|
@@ -117,7 +140,7 @@ function Repeat({ times, children, ...props }) {
|
|
|
117
140
|
function Show({ when, children, fallback = null, onFallback }) {
|
|
118
141
|
if (!when || isEmpty(when)) {
|
|
119
142
|
onFallback?.();
|
|
120
|
-
return
|
|
143
|
+
return resolveNode(fallback);
|
|
121
144
|
}
|
|
122
145
|
if (typeof children === "function") return children(when);
|
|
123
146
|
return children;
|
|
@@ -169,7 +192,7 @@ function isDefaultElement(child) {
|
|
|
169
192
|
|
|
170
193
|
function Switch({ children, fallback = null }) {
|
|
171
194
|
const childArray = Children.toArray(children);
|
|
172
|
-
let defaultContent =
|
|
195
|
+
let defaultContent = resolveNode(fallback);
|
|
173
196
|
for (const child of childArray) {
|
|
174
197
|
if (isDefaultElement(child)) {
|
|
175
198
|
defaultContent = child.props.children;
|
|
@@ -195,7 +218,7 @@ function Timeout({ ms, children, mode = "after", fallback = null, onTimeout }) {
|
|
|
195
218
|
}, ms);
|
|
196
219
|
return () => clearTimeout(timer);
|
|
197
220
|
}, [ms, onTimeout]);
|
|
198
|
-
if (mode === "after") return ready ? children :
|
|
221
|
+
if (mode === "after") return ready ? children : resolveNode(fallback);
|
|
199
222
|
return ready ? children : null;
|
|
200
223
|
}
|
|
201
224
|
|
|
@@ -246,8 +269,8 @@ function Visible({ children, fallback = null, rootMargin = "0px", threshold = 0,
|
|
|
246
269
|
if (!isSupported) return children;
|
|
247
270
|
return /* @__PURE__ */ jsx("div", {
|
|
248
271
|
ref,
|
|
249
|
-
children: (once ? hasBeenVisible : isVisible) ? children :
|
|
272
|
+
children: (once ? hasBeenVisible : isVisible) ? children : resolveNode(fallback)
|
|
250
273
|
});
|
|
251
274
|
}
|
|
252
275
|
|
|
253
|
-
export { Await, Default, Dynamic, ErrorBoundary, For, Match, QueryBoundary, Repeat, Show, Split, Switch, Timeout, Visible };
|
|
276
|
+
export { Await, ClientOnly, Default, Dynamic, ErrorBoundary, For, Match, Once, QueryBoundary, Repeat, Show, Split, Switch, Timeout, Visible };
|
package/dist/utils.d.ts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
/** Node that can be either a ReactNode or a function returning a ReactNode | 可以是 ReactNode 或返回 ReactNode 的函数 */
|
|
3
|
+
export type ResolvableNode = ReactNode | (() => ReactNode);
|
|
4
|
+
/** Resolve a node that may be a function into a ReactNode | 将可能是函数的节点解析为 ReactNode */
|
|
5
|
+
export declare function resolveNode(node: ResolvableNode): ReactNode;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-solidlike",
|
|
3
|
-
"version": "2.5.
|
|
3
|
+
"version": "2.5.4",
|
|
4
4
|
"description": "Declarative React control flow components inspired by Solid.js, replacing ternary expressions and array.map() in JSX",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
"@types/react-dom": "^19.2.3",
|
|
54
54
|
"react": "^19.2.3",
|
|
55
55
|
"react-dom": "^19.2.3",
|
|
56
|
-
"rolldown": "^1.0.0-rc.
|
|
56
|
+
"rolldown": "^1.0.0-rc.3",
|
|
57
57
|
"typescript": "^5.9.3"
|
|
58
58
|
}
|
|
59
59
|
}
|