@alepha/react 0.10.5 → 0.10.7
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/index.browser.js +32 -48
- package/dist/index.browser.js.map +1 -1
- package/dist/index.d.ts +39 -39
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +40 -63
- package/dist/index.js.map +1 -1
- package/package.json +12 -12
- package/src/components/ClientOnly.tsx +12 -12
- package/src/components/ErrorBoundary.tsx +43 -43
- package/src/components/ErrorViewer.tsx +140 -140
- package/src/components/Link.tsx +7 -7
- package/src/components/NestedView.tsx +177 -177
- package/src/components/NotFound.tsx +19 -19
- package/src/contexts/RouterLayerContext.ts +3 -3
- package/src/descriptors/$page.ts +292 -290
- package/src/errors/Redirection.ts +5 -5
- package/src/hooks/useActive.ts +41 -41
- package/src/hooks/useAlepha.ts +7 -7
- package/src/hooks/useClient.ts +5 -5
- package/src/hooks/useInject.ts +2 -2
- package/src/hooks/useQueryParams.ts +37 -37
- package/src/hooks/useRouter.ts +1 -1
- package/src/hooks/useRouterEvents.ts +46 -46
- package/src/hooks/useRouterState.ts +5 -5
- package/src/hooks/useSchema.ts +55 -55
- package/src/hooks/useStore.ts +25 -25
- package/src/index.browser.ts +18 -18
- package/src/index.ts +49 -49
- package/src/providers/ReactBrowserProvider.ts +268 -261
- package/src/providers/ReactBrowserRendererProvider.ts +15 -15
- package/src/providers/ReactBrowserRouterProvider.ts +124 -124
- package/src/providers/ReactPageProvider.ts +616 -618
- package/src/providers/ReactServerProvider.ts +505 -505
- package/src/services/ReactRouter.ts +191 -191
|
@@ -8,8 +8,8 @@ import type { ReactRouterState } from "../providers/ReactPageProvider.ts";
|
|
|
8
8
|
import ErrorBoundary from "./ErrorBoundary.tsx";
|
|
9
9
|
|
|
10
10
|
export interface NestedViewProps {
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
children?: ReactNode;
|
|
12
|
+
errorBoundary?: false | ((error: Error) => ReactNode);
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
/**
|
|
@@ -34,185 +34,185 @@ export interface NestedViewProps {
|
|
|
34
34
|
* ```
|
|
35
35
|
*/
|
|
36
36
|
const NestedView = (props: NestedViewProps) => {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
37
|
+
const index = use(RouterLayerContext)?.index ?? 0;
|
|
38
|
+
const state = useRouterState();
|
|
39
|
+
|
|
40
|
+
const [view, setView] = useState<ReactNode | undefined>(
|
|
41
|
+
state.layers[index]?.element,
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
const [animation, setAnimation] = useState("");
|
|
45
|
+
const animationExitDuration = useRef<number>(0);
|
|
46
|
+
const animationExitNow = useRef<number>(0);
|
|
47
|
+
|
|
48
|
+
useRouterEvents(
|
|
49
|
+
{
|
|
50
|
+
onBegin: async ({ previous, state }) => {
|
|
51
|
+
// --------- Animations Begin ---------
|
|
52
|
+
const layer = previous.layers[index];
|
|
53
|
+
if (`${state.url.pathname}/`.startsWith(`${layer?.path}/`)) {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const animationExit = parseAnimation(
|
|
58
|
+
layer.route?.animation,
|
|
59
|
+
state,
|
|
60
|
+
"exit",
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
if (animationExit) {
|
|
64
|
+
const duration = animationExit.duration || 200;
|
|
65
|
+
animationExitNow.current = Date.now();
|
|
66
|
+
animationExitDuration.current = duration;
|
|
67
|
+
setAnimation(animationExit.animation);
|
|
68
|
+
} else {
|
|
69
|
+
animationExitNow.current = 0;
|
|
70
|
+
animationExitDuration.current = 0;
|
|
71
|
+
setAnimation("");
|
|
72
|
+
}
|
|
73
|
+
// --------- Animations End ---------
|
|
74
|
+
},
|
|
75
|
+
onEnd: async ({ state }) => {
|
|
76
|
+
const layer = state.layers[index];
|
|
77
|
+
|
|
78
|
+
// --------- Animations Begin ---------
|
|
79
|
+
if (animationExitNow.current) {
|
|
80
|
+
const duration = animationExitDuration.current;
|
|
81
|
+
const diff = Date.now() - animationExitNow.current;
|
|
82
|
+
if (diff < duration) {
|
|
83
|
+
await new Promise((resolve) =>
|
|
84
|
+
setTimeout(resolve, duration - diff),
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
// --------- Animations End ---------
|
|
89
|
+
|
|
90
|
+
if (!layer?.cache) {
|
|
91
|
+
setView(layer?.element);
|
|
92
|
+
|
|
93
|
+
// --------- Animations Begin ---------
|
|
94
|
+
const animationEnter = parseAnimation(
|
|
95
|
+
layer?.route?.animation,
|
|
96
|
+
state,
|
|
97
|
+
"enter",
|
|
98
|
+
);
|
|
99
|
+
|
|
100
|
+
if (animationEnter) {
|
|
101
|
+
setAnimation(animationEnter.animation);
|
|
102
|
+
} else {
|
|
103
|
+
setAnimation("");
|
|
104
|
+
}
|
|
105
|
+
// --------- Animations End ---------
|
|
106
|
+
}
|
|
107
|
+
},
|
|
108
|
+
},
|
|
109
|
+
[],
|
|
110
|
+
);
|
|
111
|
+
|
|
112
|
+
let element = view ?? props.children ?? null;
|
|
113
|
+
|
|
114
|
+
// --------- Animations Begin ---------
|
|
115
|
+
if (animation) {
|
|
116
|
+
element = (
|
|
117
|
+
<div
|
|
118
|
+
style={{
|
|
119
|
+
display: "flex",
|
|
120
|
+
flex: 1,
|
|
121
|
+
height: "100%",
|
|
122
|
+
width: "100%",
|
|
123
|
+
position: "relative",
|
|
124
|
+
overflow: "hidden",
|
|
125
|
+
}}
|
|
126
|
+
>
|
|
127
|
+
<div
|
|
128
|
+
style={{ height: "100%", width: "100%", display: "flex", animation }}
|
|
129
|
+
>
|
|
130
|
+
{element}
|
|
131
|
+
</div>
|
|
132
|
+
</div>
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
// --------- Animations End ---------
|
|
136
|
+
|
|
137
|
+
if (props.errorBoundary === false) {
|
|
138
|
+
return <>{element}</>;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
if (props.errorBoundary) {
|
|
142
|
+
return (
|
|
143
|
+
<ErrorBoundary fallback={props.errorBoundary}>{element}</ErrorBoundary>
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
return (
|
|
148
|
+
<ErrorBoundary
|
|
149
|
+
fallback={(error) => {
|
|
150
|
+
const result = state.onError(error, state); // TODO: onError is not refreshed
|
|
151
|
+
if (result instanceof Redirection) {
|
|
152
|
+
return "Redirection inside ErrorBoundary is not allowed.";
|
|
153
|
+
}
|
|
154
|
+
return result as ReactNode;
|
|
155
|
+
}}
|
|
156
|
+
>
|
|
157
|
+
{element}
|
|
158
|
+
</ErrorBoundary>
|
|
159
|
+
);
|
|
160
160
|
};
|
|
161
161
|
|
|
162
162
|
export default memo(NestedView);
|
|
163
163
|
|
|
164
164
|
function parseAnimation(
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
165
|
+
animationLike: PageAnimation | undefined,
|
|
166
|
+
state: ReactRouterState,
|
|
167
|
+
type: "enter" | "exit" = "enter",
|
|
168
168
|
):
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
169
|
+
| {
|
|
170
|
+
duration: number;
|
|
171
|
+
animation: string;
|
|
172
|
+
}
|
|
173
|
+
| undefined {
|
|
174
|
+
if (!animationLike) {
|
|
175
|
+
return undefined;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
const DEFAULT_DURATION = 300;
|
|
179
|
+
|
|
180
|
+
const animation =
|
|
181
|
+
typeof animationLike === "function" ? animationLike(state) : animationLike;
|
|
182
|
+
|
|
183
|
+
if (typeof animation === "string") {
|
|
184
|
+
if (type === "exit") {
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
return {
|
|
188
|
+
duration: DEFAULT_DURATION,
|
|
189
|
+
animation: `${DEFAULT_DURATION}ms ${animation}`,
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
if (typeof animation === "object") {
|
|
194
|
+
const anim = animation[type];
|
|
195
|
+
const duration =
|
|
196
|
+
typeof anim === "object"
|
|
197
|
+
? (anim.duration ?? DEFAULT_DURATION)
|
|
198
|
+
: DEFAULT_DURATION;
|
|
199
|
+
const name = typeof anim === "object" ? anim.name : anim;
|
|
200
|
+
|
|
201
|
+
if (type === "exit") {
|
|
202
|
+
const timing = typeof anim === "object" ? (anim.timing ?? "") : "";
|
|
203
|
+
return {
|
|
204
|
+
duration,
|
|
205
|
+
animation: `${duration}ms ${timing} ${name}`,
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
const timing = typeof anim === "object" ? (anim.timing ?? "") : "";
|
|
210
|
+
|
|
211
|
+
return {
|
|
212
|
+
duration,
|
|
213
|
+
animation: `${duration}ms ${timing} ${name}`,
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
return undefined;
|
|
218
218
|
}
|
|
@@ -1,23 +1,23 @@
|
|
|
1
1
|
import type { CSSProperties } from "react";
|
|
2
2
|
|
|
3
3
|
export default function NotFoundPage(props: { style?: CSSProperties }) {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
4
|
+
return (
|
|
5
|
+
<div
|
|
6
|
+
style={{
|
|
7
|
+
height: "100vh",
|
|
8
|
+
display: "flex",
|
|
9
|
+
flexDirection: "column",
|
|
10
|
+
justifyContent: "center",
|
|
11
|
+
alignItems: "center",
|
|
12
|
+
textAlign: "center",
|
|
13
|
+
fontFamily: "sans-serif",
|
|
14
|
+
padding: "1rem",
|
|
15
|
+
...props.style,
|
|
16
|
+
}}
|
|
17
|
+
>
|
|
18
|
+
<h1 style={{ fontSize: "1rem", marginBottom: "0.5rem" }}>
|
|
19
|
+
404 - This page does not exist
|
|
20
|
+
</h1>
|
|
21
|
+
</div>
|
|
22
|
+
);
|
|
23
23
|
}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { createContext } from "react";
|
|
2
2
|
|
|
3
3
|
export interface RouterLayerContextValue {
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
index: number;
|
|
5
|
+
path: string;
|
|
6
6
|
}
|
|
7
7
|
|
|
8
8
|
export const RouterLayerContext = createContext<
|
|
9
|
-
|
|
9
|
+
RouterLayerContextValue | undefined
|
|
10
10
|
>(undefined);
|