revine 1.1.3 → 1.1.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/runtime/bundler/errorBoundary.d.ts +2 -0
- package/dist/runtime/bundler/errorBoundary.d.ts.map +1 -0
- package/dist/runtime/bundler/errorBoundary.js +122 -0
- package/dist/runtime/bundler/revinePlugin.d.ts.map +1 -1
- package/dist/runtime/bundler/revinePlugin.js +286 -2
- package/package.json +1 -1
- package/src/runtime/bundler/revinePlugin.ts +288 -3
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export declare const errorBoundaryComponent = "\nfunction RevineErrorDialog() {\n const error = useRouteError();\n const [expanded, setExpanded] = React.useState(false);\n\n const message = error?.message || String(error) || \"An unexpected error occurred.\";\n const stack = error?.stack || \"\";\n // Pull only the first meaningful line from the stack (skip the error message repeat)\n const stackLines = stack\n .split(\"\\n\")\n .filter((l) => l.trim().startsWith(\"at \"))\n .slice(0, 8);\n\n return React.createElement(\n \"div\",\n { style: overlayStyle },\n React.createElement(\n \"div\",\n { style: dialogStyle },\n // Header\n React.createElement(\n \"div\",\n { style: headerStyle },\n React.createElement(\"span\", { style: iconStyle }, \"\u2715\"),\n React.createElement(\"span\", { style: titleStyle }, \"Application Error\")\n ),\n // Message\n React.createElement(\"p\", { style: messageStyle }, message),\n // Stack toggle\n stackLines.length > 0 &&\n React.createElement(\n \"div\",\n null,\n React.createElement(\n \"button\",\n { onClick: () => setExpanded((v) => !v), style: toggleBtnStyle },\n expanded ? \"\u25B2 Hide stack trace\" : \"\u25BC Show stack trace\"\n ),\n expanded &&\n React.createElement(\n \"pre\",\n { style: stackStyle },\n stackLines.join(\"\\n\")\n )\n ),\n // Actions\n React.createElement(\n \"div\",\n { style: actionsStyle },\n React.createElement(\n \"button\",\n { onClick: () => window.location.reload(), style: primaryBtnStyle },\n \"Reload page\"\n ),\n React.createElement(\n \"button\",\n { onClick: () => (window.location.href = \"/\"), style: secondaryBtnStyle },\n \"Go to home\"\n )\n )\n )\n );\n}\n\nconst overlayStyle = {\n position: \"fixed\", inset: 0, background: \"rgba(0,0,0,0.65)\",\n backdropFilter: \"blur(4px)\", display: \"flex\",\n alignItems: \"center\", justifyContent: \"center\",\n zIndex: 9999, fontFamily: \"ui-monospace, 'Cascadia Code', monospace\",\n};\nconst dialogStyle = {\n background: \"#1a1a1a\", border: \"1px solid #ff4d4f55\",\n borderRadius: \"10px\", padding: \"28px 32px\",\n maxWidth: \"560px\", width: \"90%\", boxShadow: \"0 24px 64px rgba(0,0,0,0.6)\",\n color: \"#e5e5e5\",\n};\nconst headerStyle = {\n display: \"flex\", alignItems: \"center\", gap: \"10px\",\n marginBottom: \"14px\",\n};\nconst iconStyle = {\n display: \"inline-flex\", alignItems: \"center\", justifyContent: \"center\",\n width: \"26px\", height: \"26px\", borderRadius: \"50%\",\n background: \"#ff4d4f22\", color: \"#ff4d4f\", fontSize: \"13px\", fontWeight: 700,\n};\nconst titleStyle = {\n fontFamily: \"system-ui, sans-serif\",\n fontSize: \"16px\", fontWeight: 600, color: \"#fff\",\n};\nconst messageStyle = {\n fontFamily: \"ui-monospace, monospace\",\n fontSize: \"13px\", color: \"#ff7875\",\n background: \"#ff4d4f0f\", border: \"1px solid #ff4d4f22\",\n borderRadius: \"6px\", padding: \"10px 14px\",\n marginBottom: \"16px\", wordBreak: \"break-word\", lineHeight: 1.6,\n};\nconst toggleBtnStyle = {\n background: \"none\", border: \"none\", cursor: \"pointer\",\n color: \"#888\", fontSize: \"12px\", padding: \"0 0 10px 0\",\n fontFamily: \"system-ui, sans-serif\",\n};\nconst stackStyle = {\n background: \"#111\", borderRadius: \"6px\", padding: \"12px 14px\",\n fontSize: \"11px\", color: \"#aaa\", overflowX: \"auto\",\n lineHeight: 1.7, marginBottom: \"16px\",\n border: \"1px solid #2a2a2a\",\n};\nconst actionsStyle = {\n display: \"flex\", gap: \"10px\", marginTop: \"6px\",\n};\nconst primaryBtnStyle = {\n flex: 1, padding: \"9px 0\", borderRadius: \"6px\", border: \"none\",\n background: \"#ff4d4f\", color: \"#fff\", fontWeight: 600,\n fontSize: \"13px\", cursor: \"pointer\", fontFamily: \"system-ui, sans-serif\",\n};\nconst secondaryBtnStyle = {\n flex: 1, padding: \"9px 0\", borderRadius: \"6px\",\n border: \"1px solid #333\", background: \"transparent\",\n color: \"#aaa\", fontSize: \"13px\", cursor: \"pointer\",\n fontFamily: \"system-ui, sans-serif\",\n};\n";
|
|
2
|
+
//# sourceMappingURL=errorBoundary.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errorBoundary.d.ts","sourceRoot":"","sources":["../../../src/runtime/bundler/errorBoundary.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,sBAAsB,suIAyHlC,CAAC"}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
export const errorBoundaryComponent = `
|
|
2
|
+
function RevineErrorDialog() {
|
|
3
|
+
const error = useRouteError();
|
|
4
|
+
const [expanded, setExpanded] = React.useState(false);
|
|
5
|
+
|
|
6
|
+
const message = error?.message || String(error) || "An unexpected error occurred.";
|
|
7
|
+
const stack = error?.stack || "";
|
|
8
|
+
// Pull only the first meaningful line from the stack (skip the error message repeat)
|
|
9
|
+
const stackLines = stack
|
|
10
|
+
.split("\\n")
|
|
11
|
+
.filter((l) => l.trim().startsWith("at "))
|
|
12
|
+
.slice(0, 8);
|
|
13
|
+
|
|
14
|
+
return React.createElement(
|
|
15
|
+
"div",
|
|
16
|
+
{ style: overlayStyle },
|
|
17
|
+
React.createElement(
|
|
18
|
+
"div",
|
|
19
|
+
{ style: dialogStyle },
|
|
20
|
+
// Header
|
|
21
|
+
React.createElement(
|
|
22
|
+
"div",
|
|
23
|
+
{ style: headerStyle },
|
|
24
|
+
React.createElement("span", { style: iconStyle }, "✕"),
|
|
25
|
+
React.createElement("span", { style: titleStyle }, "Application Error")
|
|
26
|
+
),
|
|
27
|
+
// Message
|
|
28
|
+
React.createElement("p", { style: messageStyle }, message),
|
|
29
|
+
// Stack toggle
|
|
30
|
+
stackLines.length > 0 &&
|
|
31
|
+
React.createElement(
|
|
32
|
+
"div",
|
|
33
|
+
null,
|
|
34
|
+
React.createElement(
|
|
35
|
+
"button",
|
|
36
|
+
{ onClick: () => setExpanded((v) => !v), style: toggleBtnStyle },
|
|
37
|
+
expanded ? "▲ Hide stack trace" : "▼ Show stack trace"
|
|
38
|
+
),
|
|
39
|
+
expanded &&
|
|
40
|
+
React.createElement(
|
|
41
|
+
"pre",
|
|
42
|
+
{ style: stackStyle },
|
|
43
|
+
stackLines.join("\\n")
|
|
44
|
+
)
|
|
45
|
+
),
|
|
46
|
+
// Actions
|
|
47
|
+
React.createElement(
|
|
48
|
+
"div",
|
|
49
|
+
{ style: actionsStyle },
|
|
50
|
+
React.createElement(
|
|
51
|
+
"button",
|
|
52
|
+
{ onClick: () => window.location.reload(), style: primaryBtnStyle },
|
|
53
|
+
"Reload page"
|
|
54
|
+
),
|
|
55
|
+
React.createElement(
|
|
56
|
+
"button",
|
|
57
|
+
{ onClick: () => (window.location.href = "/"), style: secondaryBtnStyle },
|
|
58
|
+
"Go to home"
|
|
59
|
+
)
|
|
60
|
+
)
|
|
61
|
+
)
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const overlayStyle = {
|
|
66
|
+
position: "fixed", inset: 0, background: "rgba(0,0,0,0.65)",
|
|
67
|
+
backdropFilter: "blur(4px)", display: "flex",
|
|
68
|
+
alignItems: "center", justifyContent: "center",
|
|
69
|
+
zIndex: 9999, fontFamily: "ui-monospace, 'Cascadia Code', monospace",
|
|
70
|
+
};
|
|
71
|
+
const dialogStyle = {
|
|
72
|
+
background: "#1a1a1a", border: "1px solid #ff4d4f55",
|
|
73
|
+
borderRadius: "10px", padding: "28px 32px",
|
|
74
|
+
maxWidth: "560px", width: "90%", boxShadow: "0 24px 64px rgba(0,0,0,0.6)",
|
|
75
|
+
color: "#e5e5e5",
|
|
76
|
+
};
|
|
77
|
+
const headerStyle = {
|
|
78
|
+
display: "flex", alignItems: "center", gap: "10px",
|
|
79
|
+
marginBottom: "14px",
|
|
80
|
+
};
|
|
81
|
+
const iconStyle = {
|
|
82
|
+
display: "inline-flex", alignItems: "center", justifyContent: "center",
|
|
83
|
+
width: "26px", height: "26px", borderRadius: "50%",
|
|
84
|
+
background: "#ff4d4f22", color: "#ff4d4f", fontSize: "13px", fontWeight: 700,
|
|
85
|
+
};
|
|
86
|
+
const titleStyle = {
|
|
87
|
+
fontFamily: "system-ui, sans-serif",
|
|
88
|
+
fontSize: "16px", fontWeight: 600, color: "#fff",
|
|
89
|
+
};
|
|
90
|
+
const messageStyle = {
|
|
91
|
+
fontFamily: "ui-monospace, monospace",
|
|
92
|
+
fontSize: "13px", color: "#ff7875",
|
|
93
|
+
background: "#ff4d4f0f", border: "1px solid #ff4d4f22",
|
|
94
|
+
borderRadius: "6px", padding: "10px 14px",
|
|
95
|
+
marginBottom: "16px", wordBreak: "break-word", lineHeight: 1.6,
|
|
96
|
+
};
|
|
97
|
+
const toggleBtnStyle = {
|
|
98
|
+
background: "none", border: "none", cursor: "pointer",
|
|
99
|
+
color: "#888", fontSize: "12px", padding: "0 0 10px 0",
|
|
100
|
+
fontFamily: "system-ui, sans-serif",
|
|
101
|
+
};
|
|
102
|
+
const stackStyle = {
|
|
103
|
+
background: "#111", borderRadius: "6px", padding: "12px 14px",
|
|
104
|
+
fontSize: "11px", color: "#aaa", overflowX: "auto",
|
|
105
|
+
lineHeight: 1.7, marginBottom: "16px",
|
|
106
|
+
border: "1px solid #2a2a2a",
|
|
107
|
+
};
|
|
108
|
+
const actionsStyle = {
|
|
109
|
+
display: "flex", gap: "10px", marginTop: "6px",
|
|
110
|
+
};
|
|
111
|
+
const primaryBtnStyle = {
|
|
112
|
+
flex: 1, padding: "9px 0", borderRadius: "6px", border: "none",
|
|
113
|
+
background: "#ff4d4f", color: "#fff", fontWeight: 600,
|
|
114
|
+
fontSize: "13px", cursor: "pointer", fontFamily: "system-ui, sans-serif",
|
|
115
|
+
};
|
|
116
|
+
const secondaryBtnStyle = {
|
|
117
|
+
flex: 1, padding: "9px 0", borderRadius: "6px",
|
|
118
|
+
border: "1px solid #333", background: "transparent",
|
|
119
|
+
color: "#aaa", fontSize: "13px", cursor: "pointer",
|
|
120
|
+
fontFamily: "system-ui, sans-serif",
|
|
121
|
+
};
|
|
122
|
+
`;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"revinePlugin.d.ts","sourceRoot":"","sources":["../../../src/runtime/bundler/revinePlugin.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"revinePlugin.d.ts","sourceRoot":"","sources":["../../../src/runtime/bundler/revinePlugin.ts"],"names":[],"mappings":"AA0RA,wBAAgB,YAAY,IAAI,GAAG,CAmHlC"}
|
|
@@ -1,4 +1,283 @@
|
|
|
1
1
|
const VIRTUAL_ROUTING_ID = "\0revine:routing";
|
|
2
|
+
const errorBoundaryComponent = `
|
|
3
|
+
function RevineErrorDialog() {
|
|
4
|
+
const error = useRouteError();
|
|
5
|
+
const [expanded, setExpanded] = React.useState(false);
|
|
6
|
+
const [copied, setCopied] = React.useState(false);
|
|
7
|
+
|
|
8
|
+
const message = error?.message || String(error) || "An unexpected error occurred.";
|
|
9
|
+
const stack = error?.stack || "";
|
|
10
|
+
const stackLines = stack
|
|
11
|
+
.split("\\n")
|
|
12
|
+
.filter((l) => l.trim().startsWith("at "))
|
|
13
|
+
.slice(0, 8)
|
|
14
|
+
.join("\\n");
|
|
15
|
+
|
|
16
|
+
const handleCopy = () => {
|
|
17
|
+
const text = message + (stackLines ? "\\n\\n" + stackLines : "");
|
|
18
|
+
navigator.clipboard.writeText(text).then(() => {
|
|
19
|
+
setCopied(true);
|
|
20
|
+
setTimeout(() => setCopied(false), 2000);
|
|
21
|
+
});
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
return React.createElement(
|
|
25
|
+
"div",
|
|
26
|
+
{ style: overlayStyle },
|
|
27
|
+
React.createElement(
|
|
28
|
+
"div",
|
|
29
|
+
{ style: dialogStyle },
|
|
30
|
+
|
|
31
|
+
// ── Top bar: Revine brand + badge
|
|
32
|
+
React.createElement(
|
|
33
|
+
"div",
|
|
34
|
+
{ style: topBarStyle },
|
|
35
|
+
React.createElement(
|
|
36
|
+
"div",
|
|
37
|
+
{ style: brandStyle },
|
|
38
|
+
React.createElement(
|
|
39
|
+
"svg",
|
|
40
|
+
{ width: "18", height: "18", viewBox: "0 0 24 24", fill: "none",
|
|
41
|
+
stroke: "#a78bfa", strokeWidth: "2.2", strokeLinecap: "round",
|
|
42
|
+
strokeLinejoin: "round", style: { flexShrink: 0 } },
|
|
43
|
+
React.createElement("polygon", { points: "13 2 3 14 12 14 11 22 21 10 12 10 13 2" })
|
|
44
|
+
),
|
|
45
|
+
React.createElement("span", { style: brandNameStyle }, "Revine")
|
|
46
|
+
),
|
|
47
|
+
React.createElement("span", { style: badgeStyle }, "Runtime Error")
|
|
48
|
+
),
|
|
49
|
+
|
|
50
|
+
// ── Divider
|
|
51
|
+
React.createElement("div", { style: dividerStyle }),
|
|
52
|
+
|
|
53
|
+
// ── Error icon + title
|
|
54
|
+
React.createElement(
|
|
55
|
+
"div",
|
|
56
|
+
{ style: headerStyle },
|
|
57
|
+
React.createElement(
|
|
58
|
+
"div",
|
|
59
|
+
{ style: iconWrapStyle },
|
|
60
|
+
React.createElement(
|
|
61
|
+
"svg",
|
|
62
|
+
{ width: "16", height: "16", viewBox: "0 0 24 24", fill: "none",
|
|
63
|
+
stroke: "#f87171", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round" },
|
|
64
|
+
React.createElement("circle", { cx: "12", cy: "12", r: "10" }),
|
|
65
|
+
React.createElement("line", { x1: "12", y1: "8", x2: "12", y2: "12" }),
|
|
66
|
+
React.createElement("line", { x1: "12", y1: "16", x2: "12.01", y2: "16" })
|
|
67
|
+
)
|
|
68
|
+
),
|
|
69
|
+
React.createElement("span", { style: titleStyle }, "Application Error")
|
|
70
|
+
),
|
|
71
|
+
|
|
72
|
+
// ── Error message + copy button
|
|
73
|
+
React.createElement(
|
|
74
|
+
"div",
|
|
75
|
+
{ style: messagePanelStyle },
|
|
76
|
+
React.createElement("p", { style: messageStyle }, message),
|
|
77
|
+
React.createElement(
|
|
78
|
+
"button",
|
|
79
|
+
{ onClick: handleCopy, style: copyBtnStyle, title: "Copy error" },
|
|
80
|
+
copied
|
|
81
|
+
? React.createElement(
|
|
82
|
+
"svg",
|
|
83
|
+
{ width: "14", height: "14", viewBox: "0 0 24 24", fill: "none",
|
|
84
|
+
stroke: "#4ade80", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round" },
|
|
85
|
+
React.createElement("polyline", { points: "20 6 9 17 4 12" })
|
|
86
|
+
)
|
|
87
|
+
: React.createElement(
|
|
88
|
+
"svg",
|
|
89
|
+
{ width: "14", height: "14", viewBox: "0 0 24 24", fill: "none",
|
|
90
|
+
stroke: "#888", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" },
|
|
91
|
+
React.createElement("rect", { x: "9", y: "9", width: "13", height: "13", rx: "2", ry: "2" }),
|
|
92
|
+
React.createElement("path", { d: "M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1" })
|
|
93
|
+
)
|
|
94
|
+
)
|
|
95
|
+
),
|
|
96
|
+
|
|
97
|
+
// ── Stack trace toggle + content
|
|
98
|
+
stackLines.length > 0 &&
|
|
99
|
+
React.createElement(
|
|
100
|
+
"div",
|
|
101
|
+
{ style: stackSectionStyle },
|
|
102
|
+
React.createElement(
|
|
103
|
+
"button",
|
|
104
|
+
{ onClick: () => setExpanded((v) => !v), style: toggleBtnStyle },
|
|
105
|
+
React.createElement(
|
|
106
|
+
"svg",
|
|
107
|
+
{ width: "12", height: "12", viewBox: "0 0 24 24", fill: "none",
|
|
108
|
+
stroke: "#666", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round",
|
|
109
|
+
style: { transform: expanded ? "rotate(90deg)" : "rotate(0deg)",
|
|
110
|
+
transition: "transform 200ms ease", flexShrink: 0 } },
|
|
111
|
+
React.createElement("polyline", { points: "9 18 15 12 9 6" })
|
|
112
|
+
),
|
|
113
|
+
React.createElement("span", null, "Stack trace")
|
|
114
|
+
),
|
|
115
|
+
expanded &&
|
|
116
|
+
React.createElement("pre", { style: stackStyle }, stackLines)
|
|
117
|
+
),
|
|
118
|
+
|
|
119
|
+
// ── Actions
|
|
120
|
+
React.createElement(
|
|
121
|
+
"div",
|
|
122
|
+
{ style: actionsStyle },
|
|
123
|
+
React.createElement(
|
|
124
|
+
"button",
|
|
125
|
+
{ onClick: () => window.location.reload(), style: primaryBtnStyle },
|
|
126
|
+
React.createElement(
|
|
127
|
+
"svg",
|
|
128
|
+
{ width: "14", height: "14", viewBox: "0 0 24 24", fill: "none",
|
|
129
|
+
stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round" },
|
|
130
|
+
React.createElement("polyline", { points: "23 4 23 10 17 10" }),
|
|
131
|
+
React.createElement("path", { d: "M20.49 15a9 9 0 1 1-2.12-9.36L23 10" })
|
|
132
|
+
),
|
|
133
|
+
"Reload page"
|
|
134
|
+
),
|
|
135
|
+
React.createElement(
|
|
136
|
+
"button",
|
|
137
|
+
{ onClick: () => (window.location.href = "/"), style: secondaryBtnStyle },
|
|
138
|
+
React.createElement(
|
|
139
|
+
"svg",
|
|
140
|
+
{ width: "14", height: "14", viewBox: "0 0 24 24", fill: "none",
|
|
141
|
+
stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round" },
|
|
142
|
+
React.createElement("path", { d: "M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z" }),
|
|
143
|
+
React.createElement("polyline", { points: "9 22 9 12 15 12 15 22" })
|
|
144
|
+
),
|
|
145
|
+
"Go to home"
|
|
146
|
+
)
|
|
147
|
+
)
|
|
148
|
+
)
|
|
149
|
+
);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const overlayStyle = {
|
|
153
|
+
position: "fixed", inset: 0,
|
|
154
|
+
background: "rgba(0,0,0,0.72)",
|
|
155
|
+
backdropFilter: "blur(6px)",
|
|
156
|
+
display: "flex", alignItems: "center", justifyContent: "center",
|
|
157
|
+
zIndex: 9999,
|
|
158
|
+
};
|
|
159
|
+
const dialogStyle = {
|
|
160
|
+
background: "#141414",
|
|
161
|
+
border: "1px solid #2a2a2a",
|
|
162
|
+
borderRadius: "14px",
|
|
163
|
+
padding: "0",
|
|
164
|
+
maxWidth: "580px", width: "92%",
|
|
165
|
+
boxShadow: "0 32px 80px rgba(0,0,0,0.7), 0 0 0 1px rgba(255,255,255,0.04) inset",
|
|
166
|
+
color: "#e5e5e5",
|
|
167
|
+
overflow: "hidden",
|
|
168
|
+
fontFamily: "system-ui, -apple-system, sans-serif",
|
|
169
|
+
};
|
|
170
|
+
const topBarStyle = {
|
|
171
|
+
display: "flex", alignItems: "center", justifyContent: "space-between",
|
|
172
|
+
padding: "12px 18px",
|
|
173
|
+
background: "#0e0e0e",
|
|
174
|
+
};
|
|
175
|
+
const brandStyle = {
|
|
176
|
+
display: "flex", alignItems: "center", gap: "7px",
|
|
177
|
+
};
|
|
178
|
+
const brandNameStyle = {
|
|
179
|
+
fontSize: "13px", fontWeight: 700,
|
|
180
|
+
color: "#c4b5fd", letterSpacing: "0.04em",
|
|
181
|
+
fontFamily: "system-ui, sans-serif",
|
|
182
|
+
};
|
|
183
|
+
const badgeStyle = {
|
|
184
|
+
fontSize: "11px", fontWeight: 600,
|
|
185
|
+
color: "#f87171",
|
|
186
|
+
background: "rgba(248,113,113,0.1)",
|
|
187
|
+
border: "1px solid rgba(248,113,113,0.2)",
|
|
188
|
+
borderRadius: "999px", padding: "2px 10px",
|
|
189
|
+
letterSpacing: "0.03em",
|
|
190
|
+
};
|
|
191
|
+
const dividerStyle = {
|
|
192
|
+
height: "1px", background: "#1f1f1f",
|
|
193
|
+
};
|
|
194
|
+
const headerStyle = {
|
|
195
|
+
display: "flex", alignItems: "center", gap: "10px",
|
|
196
|
+
padding: "20px 22px 0 22px",
|
|
197
|
+
};
|
|
198
|
+
const iconWrapStyle = {
|
|
199
|
+
width: "28px", height: "28px", borderRadius: "8px",
|
|
200
|
+
background: "rgba(248,113,113,0.1)",
|
|
201
|
+
border: "1px solid rgba(248,113,113,0.15)",
|
|
202
|
+
display: "flex", alignItems: "center", justifyContent: "center",
|
|
203
|
+
flexShrink: 0,
|
|
204
|
+
};
|
|
205
|
+
const titleStyle = {
|
|
206
|
+
fontSize: "15px", fontWeight: 650, color: "#fff",
|
|
207
|
+
letterSpacing: "-0.01em",
|
|
208
|
+
};
|
|
209
|
+
const messagePanelStyle = {
|
|
210
|
+
position: "relative",
|
|
211
|
+
margin: "14px 22px 0 22px",
|
|
212
|
+
background: "rgba(248,113,113,0.05)",
|
|
213
|
+
border: "1px solid rgba(248,113,113,0.12)",
|
|
214
|
+
borderRadius: "8px",
|
|
215
|
+
padding: "12px 40px 12px 14px",
|
|
216
|
+
};
|
|
217
|
+
const messageStyle = {
|
|
218
|
+
fontFamily: "ui-monospace, 'Cascadia Code', 'Fira Code', monospace",
|
|
219
|
+
fontSize: "12.5px", color: "#fca5a5",
|
|
220
|
+
margin: 0, lineHeight: 1.65, wordBreak: "break-word",
|
|
221
|
+
};
|
|
222
|
+
const copyBtnStyle = {
|
|
223
|
+
position: "absolute", top: "10px", right: "10px",
|
|
224
|
+
background: "rgba(255,255,255,0.05)",
|
|
225
|
+
border: "1px solid #2e2e2e",
|
|
226
|
+
borderRadius: "6px",
|
|
227
|
+
width: "28px", height: "28px",
|
|
228
|
+
display: "flex", alignItems: "center", justifyContent: "center",
|
|
229
|
+
cursor: "pointer", transition: "background 150ms ease",
|
|
230
|
+
flexShrink: 0,
|
|
231
|
+
};
|
|
232
|
+
const stackSectionStyle = {
|
|
233
|
+
margin: "14px 22px 0 22px",
|
|
234
|
+
};
|
|
235
|
+
const toggleBtnStyle = {
|
|
236
|
+
background: "none", border: "none", cursor: "pointer",
|
|
237
|
+
color: "#666", fontSize: "12px",
|
|
238
|
+
padding: "4px 0",
|
|
239
|
+
display: "flex", alignItems: "center", gap: "6px",
|
|
240
|
+
letterSpacing: "0.02em",
|
|
241
|
+
transition: "color 150ms ease",
|
|
242
|
+
};
|
|
243
|
+
const stackStyle = {
|
|
244
|
+
background: "#0a0a0a",
|
|
245
|
+
border: "1px solid #222",
|
|
246
|
+
borderRadius: "8px",
|
|
247
|
+
padding: "14px 16px",
|
|
248
|
+
fontSize: "11px", color: "#888",
|
|
249
|
+
overflowX: "auto", lineHeight: 1.8,
|
|
250
|
+
marginTop: "8px", marginBottom: 0,
|
|
251
|
+
whiteSpace: "pre-wrap", wordBreak: "break-all",
|
|
252
|
+
fontFamily: "ui-monospace, 'Cascadia Code', monospace",
|
|
253
|
+
};
|
|
254
|
+
const actionsStyle = {
|
|
255
|
+
display: "flex", gap: "10px",
|
|
256
|
+
padding: "18px 22px 22px 22px",
|
|
257
|
+
marginTop: "16px",
|
|
258
|
+
};
|
|
259
|
+
const primaryBtnStyle = {
|
|
260
|
+
flex: 1, padding: "10px 0",
|
|
261
|
+
borderRadius: "8px", border: "none",
|
|
262
|
+
background: "linear-gradient(135deg, #7c3aed, #6d28d9)",
|
|
263
|
+
color: "#fff", fontWeight: 600,
|
|
264
|
+
fontSize: "13px", cursor: "pointer",
|
|
265
|
+
display: "flex", alignItems: "center", justifyContent: "center", gap: "7px",
|
|
266
|
+
letterSpacing: "0.01em",
|
|
267
|
+
boxShadow: "0 2px 12px rgba(124,58,237,0.35)",
|
|
268
|
+
fontFamily: "system-ui, sans-serif",
|
|
269
|
+
};
|
|
270
|
+
const secondaryBtnStyle = {
|
|
271
|
+
flex: 1, padding: "10px 0",
|
|
272
|
+
borderRadius: "8px",
|
|
273
|
+
border: "1px solid #2e2e2e",
|
|
274
|
+
background: "rgba(255,255,255,0.03)",
|
|
275
|
+
color: "#999", fontSize: "13px", cursor: "pointer",
|
|
276
|
+
display: "flex", alignItems: "center", justifyContent: "center", gap: "7px",
|
|
277
|
+
letterSpacing: "0.01em",
|
|
278
|
+
fontFamily: "system-ui, sans-serif",
|
|
279
|
+
};
|
|
280
|
+
`;
|
|
2
281
|
export function revinePlugin() {
|
|
3
282
|
return {
|
|
4
283
|
name: "revine",
|
|
@@ -11,8 +290,11 @@ export function revinePlugin() {
|
|
|
11
290
|
load(id) {
|
|
12
291
|
if (id === VIRTUAL_ROUTING_ID) {
|
|
13
292
|
return `
|
|
14
|
-
import { createBrowserRouter } from "react-router-dom";
|
|
293
|
+
import { createBrowserRouter, useRouteError } from "react-router-dom";
|
|
15
294
|
import { lazy, Suspense, createElement } from "react";
|
|
295
|
+
import React from "react";
|
|
296
|
+
|
|
297
|
+
${errorBoundaryComponent}
|
|
16
298
|
|
|
17
299
|
const notFoundModules = import.meta.glob("/src/NotFound.tsx", { eager: true });
|
|
18
300
|
const NotFoundComponent = Object.values(notFoundModules)[0]?.default;
|
|
@@ -81,7 +363,7 @@ const routes = pageEntries.map(([filePath, component]) => {
|
|
|
81
363
|
|
|
82
364
|
const fallback = Loading
|
|
83
365
|
? createElement(Loading)
|
|
84
|
-
: createElement("div", null, "Loading
|
|
366
|
+
: createElement("div", null, "Loading\u2026");
|
|
85
367
|
|
|
86
368
|
const pageElement = createElement(
|
|
87
369
|
Suspense,
|
|
@@ -92,6 +374,7 @@ const routes = pageEntries.map(([filePath, component]) => {
|
|
|
92
374
|
return {
|
|
93
375
|
path: routePath,
|
|
94
376
|
element: layouts.length > 0 ? wrapWithLayouts(pageElement, layouts) : pageElement,
|
|
377
|
+
errorElement: createElement(RevineErrorDialog),
|
|
95
378
|
};
|
|
96
379
|
});
|
|
97
380
|
|
|
@@ -100,6 +383,7 @@ routes.push({
|
|
|
100
383
|
element: NotFoundComponent
|
|
101
384
|
? createElement(NotFoundComponent)
|
|
102
385
|
: createElement("div", null, "404 - Page Not Found"),
|
|
386
|
+
errorElement: createElement(RevineErrorDialog),
|
|
103
387
|
});
|
|
104
388
|
|
|
105
389
|
export const router = createBrowserRouter(routes);
|
package/package.json
CHANGED
|
@@ -1,5 +1,285 @@
|
|
|
1
1
|
const VIRTUAL_ROUTING_ID = "\0revine:routing";
|
|
2
2
|
|
|
3
|
+
const errorBoundaryComponent = `
|
|
4
|
+
function RevineErrorDialog() {
|
|
5
|
+
const error = useRouteError();
|
|
6
|
+
const [expanded, setExpanded] = React.useState(false);
|
|
7
|
+
const [copied, setCopied] = React.useState(false);
|
|
8
|
+
|
|
9
|
+
const message = error?.message || String(error) || "An unexpected error occurred.";
|
|
10
|
+
const stack = error?.stack || "";
|
|
11
|
+
const stackLines = stack
|
|
12
|
+
.split("\\n")
|
|
13
|
+
.filter((l) => l.trim().startsWith("at "))
|
|
14
|
+
.slice(0, 8)
|
|
15
|
+
.join("\\n");
|
|
16
|
+
|
|
17
|
+
const handleCopy = () => {
|
|
18
|
+
const text = message + (stackLines ? "\\n\\n" + stackLines : "");
|
|
19
|
+
navigator.clipboard.writeText(text).then(() => {
|
|
20
|
+
setCopied(true);
|
|
21
|
+
setTimeout(() => setCopied(false), 2000);
|
|
22
|
+
});
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
return React.createElement(
|
|
26
|
+
"div",
|
|
27
|
+
{ style: overlayStyle },
|
|
28
|
+
React.createElement(
|
|
29
|
+
"div",
|
|
30
|
+
{ style: dialogStyle },
|
|
31
|
+
|
|
32
|
+
// ── Top bar: Revine brand + badge
|
|
33
|
+
React.createElement(
|
|
34
|
+
"div",
|
|
35
|
+
{ style: topBarStyle },
|
|
36
|
+
React.createElement(
|
|
37
|
+
"div",
|
|
38
|
+
{ style: brandStyle },
|
|
39
|
+
React.createElement(
|
|
40
|
+
"svg",
|
|
41
|
+
{ width: "18", height: "18", viewBox: "0 0 24 24", fill: "none",
|
|
42
|
+
stroke: "#a78bfa", strokeWidth: "2.2", strokeLinecap: "round",
|
|
43
|
+
strokeLinejoin: "round", style: { flexShrink: 0 } },
|
|
44
|
+
React.createElement("polygon", { points: "13 2 3 14 12 14 11 22 21 10 12 10 13 2" })
|
|
45
|
+
),
|
|
46
|
+
React.createElement("span", { style: brandNameStyle }, "Revine")
|
|
47
|
+
),
|
|
48
|
+
React.createElement("span", { style: badgeStyle }, "Runtime Error")
|
|
49
|
+
),
|
|
50
|
+
|
|
51
|
+
// ── Divider
|
|
52
|
+
React.createElement("div", { style: dividerStyle }),
|
|
53
|
+
|
|
54
|
+
// ── Error icon + title
|
|
55
|
+
React.createElement(
|
|
56
|
+
"div",
|
|
57
|
+
{ style: headerStyle },
|
|
58
|
+
React.createElement(
|
|
59
|
+
"div",
|
|
60
|
+
{ style: iconWrapStyle },
|
|
61
|
+
React.createElement(
|
|
62
|
+
"svg",
|
|
63
|
+
{ width: "16", height: "16", viewBox: "0 0 24 24", fill: "none",
|
|
64
|
+
stroke: "#f87171", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round" },
|
|
65
|
+
React.createElement("circle", { cx: "12", cy: "12", r: "10" }),
|
|
66
|
+
React.createElement("line", { x1: "12", y1: "8", x2: "12", y2: "12" }),
|
|
67
|
+
React.createElement("line", { x1: "12", y1: "16", x2: "12.01", y2: "16" })
|
|
68
|
+
)
|
|
69
|
+
),
|
|
70
|
+
React.createElement("span", { style: titleStyle }, "Application Error")
|
|
71
|
+
),
|
|
72
|
+
|
|
73
|
+
// ── Error message + copy button
|
|
74
|
+
React.createElement(
|
|
75
|
+
"div",
|
|
76
|
+
{ style: messagePanelStyle },
|
|
77
|
+
React.createElement("p", { style: messageStyle }, message),
|
|
78
|
+
React.createElement(
|
|
79
|
+
"button",
|
|
80
|
+
{ onClick: handleCopy, style: copyBtnStyle, title: "Copy error" },
|
|
81
|
+
copied
|
|
82
|
+
? React.createElement(
|
|
83
|
+
"svg",
|
|
84
|
+
{ width: "14", height: "14", viewBox: "0 0 24 24", fill: "none",
|
|
85
|
+
stroke: "#4ade80", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round" },
|
|
86
|
+
React.createElement("polyline", { points: "20 6 9 17 4 12" })
|
|
87
|
+
)
|
|
88
|
+
: React.createElement(
|
|
89
|
+
"svg",
|
|
90
|
+
{ width: "14", height: "14", viewBox: "0 0 24 24", fill: "none",
|
|
91
|
+
stroke: "#888", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" },
|
|
92
|
+
React.createElement("rect", { x: "9", y: "9", width: "13", height: "13", rx: "2", ry: "2" }),
|
|
93
|
+
React.createElement("path", { d: "M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1" })
|
|
94
|
+
)
|
|
95
|
+
)
|
|
96
|
+
),
|
|
97
|
+
|
|
98
|
+
// ── Stack trace toggle + content
|
|
99
|
+
stackLines.length > 0 &&
|
|
100
|
+
React.createElement(
|
|
101
|
+
"div",
|
|
102
|
+
{ style: stackSectionStyle },
|
|
103
|
+
React.createElement(
|
|
104
|
+
"button",
|
|
105
|
+
{ onClick: () => setExpanded((v) => !v), style: toggleBtnStyle },
|
|
106
|
+
React.createElement(
|
|
107
|
+
"svg",
|
|
108
|
+
{ width: "12", height: "12", viewBox: "0 0 24 24", fill: "none",
|
|
109
|
+
stroke: "#666", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round",
|
|
110
|
+
style: { transform: expanded ? "rotate(90deg)" : "rotate(0deg)",
|
|
111
|
+
transition: "transform 200ms ease", flexShrink: 0 } },
|
|
112
|
+
React.createElement("polyline", { points: "9 18 15 12 9 6" })
|
|
113
|
+
),
|
|
114
|
+
React.createElement("span", null, "Stack trace")
|
|
115
|
+
),
|
|
116
|
+
expanded &&
|
|
117
|
+
React.createElement("pre", { style: stackStyle }, stackLines)
|
|
118
|
+
),
|
|
119
|
+
|
|
120
|
+
// ── Actions
|
|
121
|
+
React.createElement(
|
|
122
|
+
"div",
|
|
123
|
+
{ style: actionsStyle },
|
|
124
|
+
React.createElement(
|
|
125
|
+
"button",
|
|
126
|
+
{ onClick: () => window.location.reload(), style: primaryBtnStyle },
|
|
127
|
+
React.createElement(
|
|
128
|
+
"svg",
|
|
129
|
+
{ width: "14", height: "14", viewBox: "0 0 24 24", fill: "none",
|
|
130
|
+
stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round" },
|
|
131
|
+
React.createElement("polyline", { points: "23 4 23 10 17 10" }),
|
|
132
|
+
React.createElement("path", { d: "M20.49 15a9 9 0 1 1-2.12-9.36L23 10" })
|
|
133
|
+
),
|
|
134
|
+
"Reload page"
|
|
135
|
+
),
|
|
136
|
+
React.createElement(
|
|
137
|
+
"button",
|
|
138
|
+
{ onClick: () => (window.location.href = "/"), style: secondaryBtnStyle },
|
|
139
|
+
React.createElement(
|
|
140
|
+
"svg",
|
|
141
|
+
{ width: "14", height: "14", viewBox: "0 0 24 24", fill: "none",
|
|
142
|
+
stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round" },
|
|
143
|
+
React.createElement("path", { d: "M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z" }),
|
|
144
|
+
React.createElement("polyline", { points: "9 22 9 12 15 12 15 22" })
|
|
145
|
+
),
|
|
146
|
+
"Go to home"
|
|
147
|
+
)
|
|
148
|
+
)
|
|
149
|
+
)
|
|
150
|
+
);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const overlayStyle = {
|
|
154
|
+
position: "fixed", inset: 0,
|
|
155
|
+
background: "rgba(0,0,0,0.72)",
|
|
156
|
+
backdropFilter: "blur(6px)",
|
|
157
|
+
display: "flex", alignItems: "center", justifyContent: "center",
|
|
158
|
+
zIndex: 9999,
|
|
159
|
+
};
|
|
160
|
+
const dialogStyle = {
|
|
161
|
+
background: "#141414",
|
|
162
|
+
border: "1px solid #2a2a2a",
|
|
163
|
+
borderRadius: "14px",
|
|
164
|
+
padding: "0",
|
|
165
|
+
maxWidth: "580px", width: "92%",
|
|
166
|
+
boxShadow: "0 32px 80px rgba(0,0,0,0.7), 0 0 0 1px rgba(255,255,255,0.04) inset",
|
|
167
|
+
color: "#e5e5e5",
|
|
168
|
+
overflow: "hidden",
|
|
169
|
+
fontFamily: "system-ui, -apple-system, sans-serif",
|
|
170
|
+
};
|
|
171
|
+
const topBarStyle = {
|
|
172
|
+
display: "flex", alignItems: "center", justifyContent: "space-between",
|
|
173
|
+
padding: "12px 18px",
|
|
174
|
+
background: "#0e0e0e",
|
|
175
|
+
};
|
|
176
|
+
const brandStyle = {
|
|
177
|
+
display: "flex", alignItems: "center", gap: "7px",
|
|
178
|
+
};
|
|
179
|
+
const brandNameStyle = {
|
|
180
|
+
fontSize: "13px", fontWeight: 700,
|
|
181
|
+
color: "#c4b5fd", letterSpacing: "0.04em",
|
|
182
|
+
fontFamily: "system-ui, sans-serif",
|
|
183
|
+
};
|
|
184
|
+
const badgeStyle = {
|
|
185
|
+
fontSize: "11px", fontWeight: 600,
|
|
186
|
+
color: "#f87171",
|
|
187
|
+
background: "rgba(248,113,113,0.1)",
|
|
188
|
+
border: "1px solid rgba(248,113,113,0.2)",
|
|
189
|
+
borderRadius: "999px", padding: "2px 10px",
|
|
190
|
+
letterSpacing: "0.03em",
|
|
191
|
+
};
|
|
192
|
+
const dividerStyle = {
|
|
193
|
+
height: "1px", background: "#1f1f1f",
|
|
194
|
+
};
|
|
195
|
+
const headerStyle = {
|
|
196
|
+
display: "flex", alignItems: "center", gap: "10px",
|
|
197
|
+
padding: "20px 22px 0 22px",
|
|
198
|
+
};
|
|
199
|
+
const iconWrapStyle = {
|
|
200
|
+
width: "28px", height: "28px", borderRadius: "8px",
|
|
201
|
+
background: "rgba(248,113,113,0.1)",
|
|
202
|
+
border: "1px solid rgba(248,113,113,0.15)",
|
|
203
|
+
display: "flex", alignItems: "center", justifyContent: "center",
|
|
204
|
+
flexShrink: 0,
|
|
205
|
+
};
|
|
206
|
+
const titleStyle = {
|
|
207
|
+
fontSize: "15px", fontWeight: 650, color: "#fff",
|
|
208
|
+
letterSpacing: "-0.01em",
|
|
209
|
+
};
|
|
210
|
+
const messagePanelStyle = {
|
|
211
|
+
position: "relative",
|
|
212
|
+
margin: "14px 22px 0 22px",
|
|
213
|
+
background: "rgba(248,113,113,0.05)",
|
|
214
|
+
border: "1px solid rgba(248,113,113,0.12)",
|
|
215
|
+
borderRadius: "8px",
|
|
216
|
+
padding: "12px 40px 12px 14px",
|
|
217
|
+
};
|
|
218
|
+
const messageStyle = {
|
|
219
|
+
fontFamily: "ui-monospace, 'Cascadia Code', 'Fira Code', monospace",
|
|
220
|
+
fontSize: "12.5px", color: "#fca5a5",
|
|
221
|
+
margin: 0, lineHeight: 1.65, wordBreak: "break-word",
|
|
222
|
+
};
|
|
223
|
+
const copyBtnStyle = {
|
|
224
|
+
position: "absolute", top: "10px", right: "10px",
|
|
225
|
+
background: "rgba(255,255,255,0.05)",
|
|
226
|
+
border: "1px solid #2e2e2e",
|
|
227
|
+
borderRadius: "6px",
|
|
228
|
+
width: "28px", height: "28px",
|
|
229
|
+
display: "flex", alignItems: "center", justifyContent: "center",
|
|
230
|
+
cursor: "pointer", transition: "background 150ms ease",
|
|
231
|
+
flexShrink: 0,
|
|
232
|
+
};
|
|
233
|
+
const stackSectionStyle = {
|
|
234
|
+
margin: "14px 22px 0 22px",
|
|
235
|
+
};
|
|
236
|
+
const toggleBtnStyle = {
|
|
237
|
+
background: "none", border: "none", cursor: "pointer",
|
|
238
|
+
color: "#666", fontSize: "12px",
|
|
239
|
+
padding: "4px 0",
|
|
240
|
+
display: "flex", alignItems: "center", gap: "6px",
|
|
241
|
+
letterSpacing: "0.02em",
|
|
242
|
+
transition: "color 150ms ease",
|
|
243
|
+
};
|
|
244
|
+
const stackStyle = {
|
|
245
|
+
background: "#0a0a0a",
|
|
246
|
+
border: "1px solid #222",
|
|
247
|
+
borderRadius: "8px",
|
|
248
|
+
padding: "14px 16px",
|
|
249
|
+
fontSize: "11px", color: "#888",
|
|
250
|
+
overflowX: "auto", lineHeight: 1.8,
|
|
251
|
+
marginTop: "8px", marginBottom: 0,
|
|
252
|
+
whiteSpace: "pre-wrap", wordBreak: "break-all",
|
|
253
|
+
fontFamily: "ui-monospace, 'Cascadia Code', monospace",
|
|
254
|
+
};
|
|
255
|
+
const actionsStyle = {
|
|
256
|
+
display: "flex", gap: "10px",
|
|
257
|
+
padding: "18px 22px 22px 22px",
|
|
258
|
+
marginTop: "16px",
|
|
259
|
+
};
|
|
260
|
+
const primaryBtnStyle = {
|
|
261
|
+
flex: 1, padding: "10px 0",
|
|
262
|
+
borderRadius: "8px", border: "none",
|
|
263
|
+
background: "linear-gradient(135deg, #7c3aed, #6d28d9)",
|
|
264
|
+
color: "#fff", fontWeight: 600,
|
|
265
|
+
fontSize: "13px", cursor: "pointer",
|
|
266
|
+
display: "flex", alignItems: "center", justifyContent: "center", gap: "7px",
|
|
267
|
+
letterSpacing: "0.01em",
|
|
268
|
+
boxShadow: "0 2px 12px rgba(124,58,237,0.35)",
|
|
269
|
+
fontFamily: "system-ui, sans-serif",
|
|
270
|
+
};
|
|
271
|
+
const secondaryBtnStyle = {
|
|
272
|
+
flex: 1, padding: "10px 0",
|
|
273
|
+
borderRadius: "8px",
|
|
274
|
+
border: "1px solid #2e2e2e",
|
|
275
|
+
background: "rgba(255,255,255,0.03)",
|
|
276
|
+
color: "#999", fontSize: "13px", cursor: "pointer",
|
|
277
|
+
display: "flex", alignItems: "center", justifyContent: "center", gap: "7px",
|
|
278
|
+
letterSpacing: "0.01em",
|
|
279
|
+
fontFamily: "system-ui, sans-serif",
|
|
280
|
+
};
|
|
281
|
+
`;
|
|
282
|
+
|
|
3
283
|
export function revinePlugin(): any {
|
|
4
284
|
return {
|
|
5
285
|
name: "revine",
|
|
@@ -14,8 +294,11 @@ export function revinePlugin(): any {
|
|
|
14
294
|
load(id: string) {
|
|
15
295
|
if (id === VIRTUAL_ROUTING_ID) {
|
|
16
296
|
return `
|
|
17
|
-
import { createBrowserRouter } from "react-router-dom";
|
|
297
|
+
import { createBrowserRouter, useRouteError } from "react-router-dom";
|
|
18
298
|
import { lazy, Suspense, createElement } from "react";
|
|
299
|
+
import React from "react";
|
|
300
|
+
|
|
301
|
+
${errorBoundaryComponent}
|
|
19
302
|
|
|
20
303
|
const notFoundModules = import.meta.glob("/src/NotFound.tsx", { eager: true });
|
|
21
304
|
const NotFoundComponent = Object.values(notFoundModules)[0]?.default;
|
|
@@ -84,7 +367,7 @@ const routes = pageEntries.map(([filePath, component]) => {
|
|
|
84
367
|
|
|
85
368
|
const fallback = Loading
|
|
86
369
|
? createElement(Loading)
|
|
87
|
-
: createElement("div", null, "Loading
|
|
370
|
+
: createElement("div", null, "Loading\u2026");
|
|
88
371
|
|
|
89
372
|
const pageElement = createElement(
|
|
90
373
|
Suspense,
|
|
@@ -95,6 +378,7 @@ const routes = pageEntries.map(([filePath, component]) => {
|
|
|
95
378
|
return {
|
|
96
379
|
path: routePath,
|
|
97
380
|
element: layouts.length > 0 ? wrapWithLayouts(pageElement, layouts) : pageElement,
|
|
381
|
+
errorElement: createElement(RevineErrorDialog),
|
|
98
382
|
};
|
|
99
383
|
});
|
|
100
384
|
|
|
@@ -103,6 +387,7 @@ routes.push({
|
|
|
103
387
|
element: NotFoundComponent
|
|
104
388
|
? createElement(NotFoundComponent)
|
|
105
389
|
: createElement("div", null, "404 - Page Not Found"),
|
|
390
|
+
errorElement: createElement(RevineErrorDialog),
|
|
106
391
|
});
|
|
107
392
|
|
|
108
393
|
export const router = createBrowserRouter(routes);
|
|
@@ -110,4 +395,4 @@ export const router = createBrowserRouter(routes);
|
|
|
110
395
|
}
|
|
111
396
|
},
|
|
112
397
|
};
|
|
113
|
-
}
|
|
398
|
+
}
|