react-solidlike 2.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.en.md +251 -0
- package/README.md +251 -0
- package/dist/Await.d.ts +46 -0
- package/dist/Await.d.ts.map +1 -0
- package/dist/Dynamic.d.ts +56 -0
- package/dist/Dynamic.d.ts.map +1 -0
- package/dist/ErrorBoundary.d.ts +63 -0
- package/dist/ErrorBoundary.d.ts.map +1 -0
- package/dist/For.d.ts +36 -0
- package/dist/For.d.ts.map +1 -0
- package/dist/If.d.ts +32 -0
- package/dist/If.d.ts.map +1 -0
- package/dist/QueryBoundary.d.ts +61 -0
- package/dist/QueryBoundary.d.ts.map +1 -0
- package/dist/Repeat.d.ts +32 -0
- package/dist/Repeat.d.ts.map +1 -0
- package/dist/Show.d.ts +34 -0
- package/dist/Show.d.ts.map +1 -0
- package/dist/Switch.d.ts +85 -0
- package/dist/Switch.d.ts.map +1 -0
- package/dist/index.cjs +241 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +209 -0
- package/package.json +59 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
// src/Await.tsx
|
|
2
|
+
import { useEffect, useState } from "react";
|
|
3
|
+
function Await({ promise, loading = null, error = null, children }) {
|
|
4
|
+
const [state, setState] = useState(() => {
|
|
5
|
+
if (!(promise instanceof Promise)) {
|
|
6
|
+
return { status: "fulfilled", value: promise };
|
|
7
|
+
}
|
|
8
|
+
return { status: "pending" };
|
|
9
|
+
});
|
|
10
|
+
useEffect(() => {
|
|
11
|
+
if (!(promise instanceof Promise)) {
|
|
12
|
+
setState({ status: "fulfilled", value: promise });
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
setState({ status: "pending" });
|
|
16
|
+
let cancelled = false;
|
|
17
|
+
promise.then((value) => {
|
|
18
|
+
if (!cancelled) {
|
|
19
|
+
setState({ status: "fulfilled", value });
|
|
20
|
+
}
|
|
21
|
+
}).catch((err) => {
|
|
22
|
+
if (!cancelled) {
|
|
23
|
+
setState({ status: "rejected", error: err });
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
return () => {
|
|
27
|
+
cancelled = true;
|
|
28
|
+
};
|
|
29
|
+
}, [promise]);
|
|
30
|
+
if (state.status === "pending") {
|
|
31
|
+
return loading;
|
|
32
|
+
}
|
|
33
|
+
if (state.status === "rejected") {
|
|
34
|
+
if (typeof error === "function") {
|
|
35
|
+
return error(state.error);
|
|
36
|
+
}
|
|
37
|
+
return error;
|
|
38
|
+
}
|
|
39
|
+
if (typeof children === "function") {
|
|
40
|
+
return children(state.value);
|
|
41
|
+
}
|
|
42
|
+
return children;
|
|
43
|
+
}
|
|
44
|
+
// src/Dynamic.tsx
|
|
45
|
+
import { createElement } from "react";
|
|
46
|
+
function Dynamic({ component, fallback = null, ...props }) {
|
|
47
|
+
if (!component) {
|
|
48
|
+
return fallback;
|
|
49
|
+
}
|
|
50
|
+
return createElement(component, props);
|
|
51
|
+
}
|
|
52
|
+
// src/ErrorBoundary.tsx
|
|
53
|
+
import { Component } from "react";
|
|
54
|
+
|
|
55
|
+
class ErrorBoundary extends Component {
|
|
56
|
+
constructor(props) {
|
|
57
|
+
super(props);
|
|
58
|
+
this.state = { error: null };
|
|
59
|
+
}
|
|
60
|
+
static getDerivedStateFromError(error) {
|
|
61
|
+
return { error };
|
|
62
|
+
}
|
|
63
|
+
componentDidCatch(error, errorInfo) {
|
|
64
|
+
this.props.onError?.(error, errorInfo);
|
|
65
|
+
}
|
|
66
|
+
componentDidUpdate(prevProps) {
|
|
67
|
+
if (this.state.error && prevProps.resetKey !== this.props.resetKey) {
|
|
68
|
+
this.reset();
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
reset = () => {
|
|
72
|
+
this.setState({ error: null });
|
|
73
|
+
};
|
|
74
|
+
render() {
|
|
75
|
+
const { error } = this.state;
|
|
76
|
+
const { fallback, children } = this.props;
|
|
77
|
+
if (error) {
|
|
78
|
+
if (typeof fallback === "function") {
|
|
79
|
+
return fallback(error, this.reset);
|
|
80
|
+
}
|
|
81
|
+
return fallback;
|
|
82
|
+
}
|
|
83
|
+
return children;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
// src/For.tsx
|
|
87
|
+
import { Fragment } from "react";
|
|
88
|
+
import { jsx } from "react/jsx-runtime";
|
|
89
|
+
function For({ each, children, keyExtractor, fallback = null }) {
|
|
90
|
+
if (!each || each.length === 0) {
|
|
91
|
+
return fallback;
|
|
92
|
+
}
|
|
93
|
+
return each.map((item, index) => {
|
|
94
|
+
const key = keyExtractor ? keyExtractor(item, index) : index;
|
|
95
|
+
return /* @__PURE__ */ jsx(Fragment, {
|
|
96
|
+
children: children(item, index)
|
|
97
|
+
}, key);
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
// src/QueryBoundary.tsx
|
|
101
|
+
function defaultIsEmpty(data) {
|
|
102
|
+
if (data == null)
|
|
103
|
+
return true;
|
|
104
|
+
if (Array.isArray(data))
|
|
105
|
+
return data.length === 0;
|
|
106
|
+
if (typeof data === "object")
|
|
107
|
+
return Object.keys(data).length === 0;
|
|
108
|
+
return false;
|
|
109
|
+
}
|
|
110
|
+
function QueryBoundary({
|
|
111
|
+
query,
|
|
112
|
+
loading = null,
|
|
113
|
+
error = null,
|
|
114
|
+
empty = null,
|
|
115
|
+
children,
|
|
116
|
+
isEmptyFn = defaultIsEmpty
|
|
117
|
+
}) {
|
|
118
|
+
if (!query) {
|
|
119
|
+
return null;
|
|
120
|
+
}
|
|
121
|
+
const { data, isPending, isError, isEmpty: queryIsEmpty } = query;
|
|
122
|
+
if (isPending) {
|
|
123
|
+
return loading;
|
|
124
|
+
}
|
|
125
|
+
if (isError && isEmptyFn(data)) {
|
|
126
|
+
return error;
|
|
127
|
+
}
|
|
128
|
+
const isEmpty = queryIsEmpty ?? isEmptyFn(data);
|
|
129
|
+
if (isEmpty) {
|
|
130
|
+
return empty;
|
|
131
|
+
}
|
|
132
|
+
if (typeof children === "function") {
|
|
133
|
+
return children(data);
|
|
134
|
+
}
|
|
135
|
+
return children;
|
|
136
|
+
}
|
|
137
|
+
// src/Repeat.tsx
|
|
138
|
+
import { Fragment as Fragment2 } from "react";
|
|
139
|
+
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
140
|
+
function Repeat({ times, children }) {
|
|
141
|
+
if (times <= 0) {
|
|
142
|
+
return null;
|
|
143
|
+
}
|
|
144
|
+
const elements = [];
|
|
145
|
+
for (let i = 0;i < times; i++) {
|
|
146
|
+
elements.push(/* @__PURE__ */ jsx2(Fragment2, {
|
|
147
|
+
children: children(i)
|
|
148
|
+
}, i));
|
|
149
|
+
}
|
|
150
|
+
return elements;
|
|
151
|
+
}
|
|
152
|
+
// src/Show.tsx
|
|
153
|
+
function Show({ when, children, fallback = null }) {
|
|
154
|
+
if (!when) {
|
|
155
|
+
return fallback;
|
|
156
|
+
}
|
|
157
|
+
if (typeof children === "function") {
|
|
158
|
+
return children(when);
|
|
159
|
+
}
|
|
160
|
+
return children;
|
|
161
|
+
}
|
|
162
|
+
// src/Switch.tsx
|
|
163
|
+
import { Children } from "react";
|
|
164
|
+
function Match(_props) {
|
|
165
|
+
return null;
|
|
166
|
+
}
|
|
167
|
+
function Default(_props) {
|
|
168
|
+
return null;
|
|
169
|
+
}
|
|
170
|
+
Match.__isMatch = true;
|
|
171
|
+
Default.__isDefault = true;
|
|
172
|
+
function isMatchElement(child) {
|
|
173
|
+
return child !== null && typeof child === "object" && "type" in child && typeof child.type === "function" && "__isMatch" in child.type && child.type.__isMatch === true;
|
|
174
|
+
}
|
|
175
|
+
function isDefaultElement(child) {
|
|
176
|
+
return child !== null && typeof child === "object" && "type" in child && typeof child.type === "function" && "__isDefault" in child.type && child.type.__isDefault === true;
|
|
177
|
+
}
|
|
178
|
+
function Switch({ children, fallback = null }) {
|
|
179
|
+
const childArray = Children.toArray(children);
|
|
180
|
+
let defaultContent = fallback;
|
|
181
|
+
for (const child of childArray) {
|
|
182
|
+
if (isDefaultElement(child)) {
|
|
183
|
+
defaultContent = child.props.children;
|
|
184
|
+
continue;
|
|
185
|
+
}
|
|
186
|
+
if (isMatchElement(child)) {
|
|
187
|
+
const { when, children: matchChildren } = child.props;
|
|
188
|
+
if (when) {
|
|
189
|
+
if (typeof matchChildren === "function") {
|
|
190
|
+
return matchChildren(when);
|
|
191
|
+
}
|
|
192
|
+
return matchChildren;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
return defaultContent;
|
|
197
|
+
}
|
|
198
|
+
export {
|
|
199
|
+
Switch,
|
|
200
|
+
Show,
|
|
201
|
+
Repeat,
|
|
202
|
+
QueryBoundary,
|
|
203
|
+
Match,
|
|
204
|
+
For,
|
|
205
|
+
ErrorBoundary,
|
|
206
|
+
Dynamic,
|
|
207
|
+
Default,
|
|
208
|
+
Await
|
|
209
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "react-solidlike",
|
|
3
|
+
"version": "2.0.0",
|
|
4
|
+
"description": "Declarative React control flow components inspired by Solid.js, replacing ternary expressions and array.map() in JSX",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.js",
|
|
13
|
+
"require": "./dist/index.cjs"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"dist"
|
|
18
|
+
],
|
|
19
|
+
"scripts": {
|
|
20
|
+
"build": "NODE_ENV=production bun run build:esm && bun run build:cjs && bun run build:types",
|
|
21
|
+
"build:esm": "bun build ./src/index.ts --outdir ./dist --format esm --external react --external 'react/*'",
|
|
22
|
+
"build:cjs": "bun build ./src/index.ts --outfile ./dist/index.cjs --format cjs --external react --external 'react/*'",
|
|
23
|
+
"build:types": "tsc -p tsconfig.build.json",
|
|
24
|
+
"test": "bun test",
|
|
25
|
+
"lint": "biome check .",
|
|
26
|
+
"lint:fix": "biome check --write .",
|
|
27
|
+
"format": "biome format --write .",
|
|
28
|
+
"prepublishOnly": "bun test && bun run build"
|
|
29
|
+
},
|
|
30
|
+
"keywords": [
|
|
31
|
+
"react",
|
|
32
|
+
"solidjs",
|
|
33
|
+
"control-flow",
|
|
34
|
+
"conditional-rendering",
|
|
35
|
+
"declarative",
|
|
36
|
+
"jsx"
|
|
37
|
+
],
|
|
38
|
+
"author": "ldystudio",
|
|
39
|
+
"license": "MIT",
|
|
40
|
+
"repository": {
|
|
41
|
+
"type": "git",
|
|
42
|
+
"url": "git+https://github.com/ldystudio/react-solidlike.git"
|
|
43
|
+
},
|
|
44
|
+
"peerDependencies": {
|
|
45
|
+
"react": ">=17.0.0"
|
|
46
|
+
},
|
|
47
|
+
"devDependencies": {
|
|
48
|
+
"@biomejs/biome": "^2.3.11",
|
|
49
|
+
"@happy-dom/global-registrator": "^20.1.0",
|
|
50
|
+
"@testing-library/react": "^16.3.1",
|
|
51
|
+
"@testing-library/user-event": "^14.6.1",
|
|
52
|
+
"@types/bun": "latest",
|
|
53
|
+
"@types/react": "^19.2.8",
|
|
54
|
+
"@types/react-dom": "^19.2.3",
|
|
55
|
+
"react": "^19.2.3",
|
|
56
|
+
"react-dom": "^19.2.3",
|
|
57
|
+
"typescript": "^5.9.3"
|
|
58
|
+
}
|
|
59
|
+
}
|