@alepha/react 0.10.6 → 0.11.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.
@@ -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
- children?: ReactNode;
12
- errorBoundary?: false | ((error: Error) => ReactNode);
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
- 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
- );
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
- animationLike: PageAnimation | undefined,
166
- state: ReactRouterState,
167
- type: "enter" | "exit" = "enter",
165
+ animationLike: PageAnimation | undefined,
166
+ state: ReactRouterState,
167
+ type: "enter" | "exit" = "enter",
168
168
  ):
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;
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
- 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
- );
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
- index: number;
5
- path: string;
4
+ index: number;
5
+ path: string;
6
6
  }
7
7
 
8
8
  export const RouterLayerContext = createContext<
9
- RouterLayerContextValue | undefined
9
+ RouterLayerContextValue | undefined
10
10
  >(undefined);