@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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@alepha/react",
3
3
  "description": "Build server-side rendered (SSR) or single-page React applications.",
4
- "version": "0.10.5",
4
+ "version": "0.10.7",
5
5
  "type": "module",
6
6
  "engines": {
7
7
  "node": ">=22.0.0"
@@ -17,22 +17,22 @@
17
17
  "src"
18
18
  ],
19
19
  "dependencies": {
20
- "@alepha/core": "0.10.5",
21
- "@alepha/datetime": "0.10.5",
22
- "@alepha/logger": "0.10.5",
23
- "@alepha/router": "0.10.5",
24
- "@alepha/server": "0.10.5",
25
- "@alepha/server-cache": "0.10.5",
26
- "@alepha/server-links": "0.10.5",
27
- "@alepha/server-static": "0.10.5"
20
+ "@alepha/core": "0.10.7",
21
+ "@alepha/datetime": "0.10.7",
22
+ "@alepha/logger": "0.10.7",
23
+ "@alepha/router": "0.10.7",
24
+ "@alepha/server": "0.10.7",
25
+ "@alepha/server-cache": "0.10.7",
26
+ "@alepha/server-links": "0.10.7",
27
+ "@alepha/server-static": "0.10.7"
28
28
  },
29
29
  "devDependencies": {
30
- "@biomejs/biome": "^2.2.5",
30
+ "@biomejs/biome": "^2.2.6",
31
31
  "@types/react": "^19.2.2",
32
- "@types/react-dom": "^19.2.1",
32
+ "@types/react-dom": "^19.2.2",
33
33
  "react": "^19.2.0",
34
34
  "react-dom": "^19.2.0",
35
- "tsdown": "^0.15.6",
35
+ "tsdown": "^0.15.9",
36
36
  "typescript": "^5.9.3",
37
37
  "vitest": "^3.2.4"
38
38
  },
@@ -1,13 +1,13 @@
1
1
  import {
2
- type PropsWithChildren,
3
- type ReactNode,
4
- useEffect,
5
- useState,
2
+ type PropsWithChildren,
3
+ type ReactNode,
4
+ useEffect,
5
+ useState,
6
6
  } from "react";
7
7
 
8
8
  export interface ClientOnlyProps {
9
- fallback?: ReactNode;
10
- disabled?: boolean;
9
+ fallback?: ReactNode;
10
+ disabled?: boolean;
11
11
  }
12
12
 
13
13
  /**
@@ -21,15 +21,15 @@ export interface ClientOnlyProps {
21
21
  * - you want to prevent pre-rendering of a component
22
22
  */
23
23
  const ClientOnly = (props: PropsWithChildren<ClientOnlyProps>) => {
24
- const [mounted, setMounted] = useState(false);
24
+ const [mounted, setMounted] = useState(false);
25
25
 
26
- useEffect(() => setMounted(true), []);
26
+ useEffect(() => setMounted(true), []);
27
27
 
28
- if (props.disabled) {
29
- return props.children;
30
- }
28
+ if (props.disabled) {
29
+ return props.children;
30
+ }
31
31
 
32
- return mounted ? props.children : props.fallback;
32
+ return mounted ? props.children : props.fallback;
33
33
  };
34
34
 
35
35
  export default ClientOnly;
@@ -1,31 +1,31 @@
1
1
  import React, {
2
- type ErrorInfo,
3
- type PropsWithChildren,
4
- type ReactNode,
2
+ type ErrorInfo,
3
+ type PropsWithChildren,
4
+ type ReactNode,
5
5
  } from "react";
6
6
 
7
7
  /**
8
8
  * Props for the ErrorBoundary component.
9
9
  */
10
10
  export interface ErrorBoundaryProps {
11
- /**
12
- * Fallback React node to render when an error is caught.
13
- * If not provided, a default error message will be shown.
14
- */
15
- fallback: (error: Error) => ReactNode;
11
+ /**
12
+ * Fallback React node to render when an error is caught.
13
+ * If not provided, a default error message will be shown.
14
+ */
15
+ fallback: (error: Error) => ReactNode;
16
16
 
17
- /**
18
- * Optional callback that receives the error and error info.
19
- * Use this to log errors to a monitoring service.
20
- */
21
- onError?: (error: Error, info: ErrorInfo) => void;
17
+ /**
18
+ * Optional callback that receives the error and error info.
19
+ * Use this to log errors to a monitoring service.
20
+ */
21
+ onError?: (error: Error, info: ErrorInfo) => void;
22
22
  }
23
23
 
24
24
  /**
25
25
  * State of the ErrorBoundary component.
26
26
  */
27
27
  interface ErrorBoundaryState {
28
- error?: Error;
28
+ error?: Error;
29
29
  }
30
30
 
31
31
  /**
@@ -33,40 +33,40 @@ interface ErrorBoundaryState {
33
33
  * in any part of the React component tree.
34
34
  */
35
35
  export class ErrorBoundary extends React.Component<
36
- PropsWithChildren<ErrorBoundaryProps>,
37
- ErrorBoundaryState
36
+ PropsWithChildren<ErrorBoundaryProps>,
37
+ ErrorBoundaryState
38
38
  > {
39
- constructor(props: ErrorBoundaryProps) {
40
- super(props);
41
- this.state = {};
42
- }
39
+ constructor(props: ErrorBoundaryProps) {
40
+ super(props);
41
+ this.state = {};
42
+ }
43
43
 
44
- /**
45
- * Update state so the next render shows the fallback UI.
46
- */
47
- static getDerivedStateFromError(error: Error): ErrorBoundaryState {
48
- return {
49
- error,
50
- };
51
- }
44
+ /**
45
+ * Update state so the next render shows the fallback UI.
46
+ */
47
+ static getDerivedStateFromError(error: Error): ErrorBoundaryState {
48
+ return {
49
+ error,
50
+ };
51
+ }
52
52
 
53
- /**
54
- * Lifecycle method called when an error is caught.
55
- * You can log the error or perform side effects here.
56
- */
57
- componentDidCatch(error: Error, info: ErrorInfo): void {
58
- if (this.props.onError) {
59
- this.props.onError(error, info);
60
- }
61
- }
53
+ /**
54
+ * Lifecycle method called when an error is caught.
55
+ * You can log the error or perform side effects here.
56
+ */
57
+ componentDidCatch(error: Error, info: ErrorInfo): void {
58
+ if (this.props.onError) {
59
+ this.props.onError(error, info);
60
+ }
61
+ }
62
62
 
63
- render(): ReactNode {
64
- if (this.state.error) {
65
- return this.props.fallback(this.state.error);
66
- }
63
+ render(): ReactNode {
64
+ if (this.state.error) {
65
+ return this.props.fallback(this.state.error);
66
+ }
67
67
 
68
- return this.props.children;
69
- }
68
+ return this.props.children;
69
+ }
70
70
  }
71
71
 
72
72
  export default ErrorBoundary;
@@ -2,161 +2,161 @@ import type { Alepha } from "@alepha/core";
2
2
  import { useState } from "react";
3
3
 
4
4
  interface ErrorViewerProps {
5
- error: Error;
6
- alepha: Alepha;
5
+ error: Error;
6
+ alepha: Alepha;
7
7
  }
8
8
 
9
9
  // TODO: design this better
10
10
 
11
11
  const ErrorViewer = ({ error, alepha }: ErrorViewerProps) => {
12
- const [expanded, setExpanded] = useState(false);
13
- const isProduction = alepha.isProduction();
14
- // const status = isHttpError(error) ? error.status : 500;
12
+ const [expanded, setExpanded] = useState(false);
13
+ const isProduction = alepha.isProduction();
14
+ // const status = isHttpError(error) ? error.status : 500;
15
15
 
16
- if (isProduction) {
17
- return <ErrorViewerProduction />;
18
- }
16
+ if (isProduction) {
17
+ return <ErrorViewerProduction />;
18
+ }
19
19
 
20
- const stackLines = error.stack?.split("\n") ?? [];
21
- const previewLines = stackLines.slice(0, 5);
22
- const hiddenLineCount = stackLines.length - previewLines.length;
20
+ const stackLines = error.stack?.split("\n") ?? [];
21
+ const previewLines = stackLines.slice(0, 5);
22
+ const hiddenLineCount = stackLines.length - previewLines.length;
23
23
 
24
- const copyToClipboard = (text: string) => {
25
- navigator.clipboard.writeText(text).catch((err) => {
26
- console.error("Clipboard error:", err);
27
- });
28
- };
24
+ const copyToClipboard = (text: string) => {
25
+ navigator.clipboard.writeText(text).catch((err) => {
26
+ console.error("Clipboard error:", err);
27
+ });
28
+ };
29
29
 
30
- const styles = {
31
- container: {
32
- padding: "24px",
33
- backgroundColor: "#FEF2F2",
34
- color: "#7F1D1D",
35
- border: "1px solid #FECACA",
36
- borderRadius: "16px",
37
- boxShadow: "0 8px 24px rgba(0,0,0,0.05)",
38
- fontFamily: "monospace",
39
- maxWidth: "768px",
40
- margin: "40px auto",
41
- },
42
- heading: {
43
- fontSize: "20px",
44
- fontWeight: "bold",
45
- marginBottom: "10px",
46
- },
47
- name: {
48
- fontSize: "16px",
49
- fontWeight: 600,
50
- },
51
- message: {
52
- fontSize: "14px",
53
- marginBottom: "16px",
54
- },
55
- sectionHeader: {
56
- display: "flex",
57
- justifyContent: "space-between",
58
- alignItems: "center",
59
- fontSize: "12px",
60
- marginBottom: "4px",
61
- color: "#991B1B",
62
- },
63
- copyButton: {
64
- fontSize: "12px",
65
- color: "#DC2626",
66
- background: "none",
67
- border: "none",
68
- cursor: "pointer",
69
- textDecoration: "underline",
70
- },
71
- stackContainer: {
72
- backgroundColor: "#FEE2E2",
73
- padding: "12px",
74
- borderRadius: "8px",
75
- fontSize: "13px",
76
- lineHeight: "1.4",
77
- overflowX: "auto" as const,
78
- whiteSpace: "pre-wrap" as const,
79
- },
80
- expandLine: {
81
- color: "#F87171",
82
- cursor: "pointer",
83
- marginTop: "8px",
84
- },
85
- };
30
+ const styles = {
31
+ container: {
32
+ padding: "24px",
33
+ backgroundColor: "#FEF2F2",
34
+ color: "#7F1D1D",
35
+ border: "1px solid #FECACA",
36
+ borderRadius: "16px",
37
+ boxShadow: "0 8px 24px rgba(0,0,0,0.05)",
38
+ fontFamily: "monospace",
39
+ maxWidth: "768px",
40
+ margin: "40px auto",
41
+ },
42
+ heading: {
43
+ fontSize: "20px",
44
+ fontWeight: "bold",
45
+ marginBottom: "10px",
46
+ },
47
+ name: {
48
+ fontSize: "16px",
49
+ fontWeight: 600,
50
+ },
51
+ message: {
52
+ fontSize: "14px",
53
+ marginBottom: "16px",
54
+ },
55
+ sectionHeader: {
56
+ display: "flex",
57
+ justifyContent: "space-between",
58
+ alignItems: "center",
59
+ fontSize: "12px",
60
+ marginBottom: "4px",
61
+ color: "#991B1B",
62
+ },
63
+ copyButton: {
64
+ fontSize: "12px",
65
+ color: "#DC2626",
66
+ background: "none",
67
+ border: "none",
68
+ cursor: "pointer",
69
+ textDecoration: "underline",
70
+ },
71
+ stackContainer: {
72
+ backgroundColor: "#FEE2E2",
73
+ padding: "12px",
74
+ borderRadius: "8px",
75
+ fontSize: "13px",
76
+ lineHeight: "1.4",
77
+ overflowX: "auto" as const,
78
+ whiteSpace: "pre-wrap" as const,
79
+ },
80
+ expandLine: {
81
+ color: "#F87171",
82
+ cursor: "pointer",
83
+ marginTop: "8px",
84
+ },
85
+ };
86
86
 
87
- return (
88
- <div style={styles.container}>
89
- <div>
90
- <div style={styles.heading}>🔥 Error</div>
91
- <div style={styles.name}>{error.name}</div>
92
- <div style={styles.message}>{error.message}</div>
93
- </div>
87
+ return (
88
+ <div style={styles.container}>
89
+ <div>
90
+ <div style={styles.heading}>🔥 Error</div>
91
+ <div style={styles.name}>{error.name}</div>
92
+ <div style={styles.message}>{error.message}</div>
93
+ </div>
94
94
 
95
- {stackLines.length > 0 && (
96
- <div>
97
- <div style={styles.sectionHeader}>
98
- <span>Stack trace</span>
99
- <button
100
- onClick={() => copyToClipboard(error.stack!)}
101
- style={styles.copyButton}
102
- >
103
- Copy all
104
- </button>
105
- </div>
106
- <pre style={styles.stackContainer}>
107
- {(expanded ? stackLines : previewLines).map((line, i) => (
108
- <div key={i}>{line}</div>
109
- ))}
110
- {!expanded && hiddenLineCount > 0 && (
111
- <div style={styles.expandLine} onClick={() => setExpanded(true)}>
112
- + {hiddenLineCount} more lines...
113
- </div>
114
- )}
115
- </pre>
116
- </div>
117
- )}
118
- </div>
119
- );
95
+ {stackLines.length > 0 && (
96
+ <div>
97
+ <div style={styles.sectionHeader}>
98
+ <span>Stack trace</span>
99
+ <button
100
+ onClick={() => copyToClipboard(error.stack!)}
101
+ style={styles.copyButton}
102
+ >
103
+ Copy all
104
+ </button>
105
+ </div>
106
+ <pre style={styles.stackContainer}>
107
+ {(expanded ? stackLines : previewLines).map((line, i) => (
108
+ <div key={i}>{line}</div>
109
+ ))}
110
+ {!expanded && hiddenLineCount > 0 && (
111
+ <div style={styles.expandLine} onClick={() => setExpanded(true)}>
112
+ + {hiddenLineCount} more lines...
113
+ </div>
114
+ )}
115
+ </pre>
116
+ </div>
117
+ )}
118
+ </div>
119
+ );
120
120
  };
121
121
 
122
122
  export default ErrorViewer;
123
123
 
124
124
  const ErrorViewerProduction = () => {
125
- const styles = {
126
- container: {
127
- padding: "24px",
128
- backgroundColor: "#FEF2F2",
129
- color: "#7F1D1D",
130
- border: "1px solid #FECACA",
131
- borderRadius: "16px",
132
- boxShadow: "0 8px 24px rgba(0,0,0,0.05)",
133
- fontFamily: "monospace",
134
- maxWidth: "768px",
135
- margin: "40px auto",
136
- textAlign: "center" as const,
137
- },
138
- heading: {
139
- fontSize: "20px",
140
- fontWeight: "bold",
141
- marginBottom: "8px",
142
- },
143
- name: {
144
- fontSize: "16px",
145
- fontWeight: 600,
146
- marginBottom: "4px",
147
- },
148
- message: {
149
- fontSize: "14px",
150
- opacity: 0.85,
151
- },
152
- };
125
+ const styles = {
126
+ container: {
127
+ padding: "24px",
128
+ backgroundColor: "#FEF2F2",
129
+ color: "#7F1D1D",
130
+ border: "1px solid #FECACA",
131
+ borderRadius: "16px",
132
+ boxShadow: "0 8px 24px rgba(0,0,0,0.05)",
133
+ fontFamily: "monospace",
134
+ maxWidth: "768px",
135
+ margin: "40px auto",
136
+ textAlign: "center" as const,
137
+ },
138
+ heading: {
139
+ fontSize: "20px",
140
+ fontWeight: "bold",
141
+ marginBottom: "8px",
142
+ },
143
+ name: {
144
+ fontSize: "16px",
145
+ fontWeight: 600,
146
+ marginBottom: "4px",
147
+ },
148
+ message: {
149
+ fontSize: "14px",
150
+ opacity: 0.85,
151
+ },
152
+ };
153
153
 
154
- return (
155
- <div style={styles.container}>
156
- <div style={styles.heading}>🚨 An error occurred</div>
157
- <div style={styles.message}>
158
- Something went wrong. Please try again later.
159
- </div>
160
- </div>
161
- );
154
+ return (
155
+ <div style={styles.container}>
156
+ <div style={styles.heading}>🚨 An error occurred</div>
157
+ <div style={styles.message}>
158
+ Something went wrong. Please try again later.
159
+ </div>
160
+ </div>
161
+ );
162
162
  };
@@ -2,17 +2,17 @@ import type { AnchorHTMLAttributes } from "react";
2
2
  import { useRouter } from "../hooks/useRouter.ts";
3
3
 
4
4
  export interface LinkProps extends AnchorHTMLAttributes<HTMLAnchorElement> {
5
- href: string;
5
+ href: string;
6
6
  }
7
7
 
8
8
  const Link = (props: LinkProps) => {
9
- const router = useRouter();
9
+ const router = useRouter();
10
10
 
11
- return (
12
- <a {...props} {...router.anchor(props.href)}>
13
- {props.children}
14
- </a>
15
- );
11
+ return (
12
+ <a {...props} {...router.anchor(props.href)}>
13
+ {props.children}
14
+ </a>
15
+ );
16
16
  };
17
17
 
18
18
  export default Link;