Skip to content

Commit e0345a5

Browse files
committed
Replace React error overlay with plain vanilla JS
1 parent 7590b1d commit e0345a5

32 files changed

Lines changed: 158 additions & 31904 deletions

.gitignore

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,4 +142,3 @@ cython_debug/
142142
.vim
143143
.nvimrc
144144
Session.vim
145-
slippers/static

slippers/static/slippers/main.js

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
(function () {
2+
"use strict";
3+
4+
// ---------------------------------------------------------------------------
5+
// Safety
6+
// ---------------------------------------------------------------------------
7+
8+
function esc(value) {
9+
return String(value)
10+
.replace(/&/g, "&")
11+
.replace(/</g, "&lt;")
12+
.replace(/>/g, "&gt;")
13+
.replace(/"/g, "&quot;")
14+
.replace(/'/g, "&#39;");
15+
}
16+
17+
// ---------------------------------------------------------------------------
18+
// Styles
19+
// ---------------------------------------------------------------------------
20+
21+
const STYLES = `
22+
#slippers-overlay {
23+
position: fixed; inset: 0;
24+
background: rgba(0,0,0,0.92);
25+
color: #e4e4e7;
26+
font-family: sans-serif;
27+
padding: 3rem;
28+
overflow-y: auto;
29+
z-index: 99999;
30+
}
31+
#slippers-overlay h1 { color: #f87171; font-size: 1.5rem; margin: 0 0 2rem; }
32+
.slippers-close {
33+
margin-left: auto; padding: 0.5rem 1rem;
34+
background: #000; color: #fff; border: 1px solid #555; cursor: pointer;
35+
}
36+
.slippers-header { display: flex; align-items: flex-start; }
37+
.slippers-error-box { margin-bottom: 2rem; }
38+
.slippers-tag-label { font-size: 1.1rem; font-weight: bold; }
39+
.slippers-location { color: #a1a1aa; font-family: monospace; word-break: break-all; }
40+
.slippers-error-list {
41+
margin-top: 1rem; padding: 1rem;
42+
background: #27272a; list-style: disc; list-style-position: inside;
43+
}
44+
.slippers-error-list li + li { margin-top: 0.5rem; }
45+
.slippers-var { color: #818cf8; font-family: monospace; }
46+
.slippers-tag { color: #fb923c; font-family: monospace; }
47+
.slippers-type { color: #2dd4bf; font-family: monospace; }
48+
`;
49+
50+
// ---------------------------------------------------------------------------
51+
// HTML component functions (pure: data in, HTML string out)
52+
// ---------------------------------------------------------------------------
53+
54+
function renderPropError(propError, tagName) {
55+
const name = `<span class="slippers-var">${esc(propError.name)}</span>`;
56+
const tag = `<span class="slippers-tag">${esc(tagName)}</span>`;
57+
const exp = `<span class="slippers-type">${esc(propError.expected)}</span>`;
58+
const act = `<span class="slippers-type">${esc(propError.actual)}</span>`;
59+
60+
if (propError.error === "invalid")
61+
return `Invalid prop ${name} set on ${tag}. Expected ${exp}, got ${act}.`;
62+
if (propError.error === "missing")
63+
return `Required prop ${name} of type ${exp} not set on ${tag}.`;
64+
if (propError.error === "extra")
65+
return `Extra prop ${name} of type ${act} set on ${tag}.`;
66+
return esc(propError.error);
67+
}
68+
69+
function renderErrorBox(slippersError) {
70+
const items = slippersError.errors
71+
.map((e) => `<li>${renderPropError(e, slippersError.tag_name)}</li>`)
72+
.join("");
73+
return `
74+
<div class="slippers-error-box">
75+
<p class="slippers-tag-label">${esc(slippersError.tag_name)}</p>
76+
<p class="slippers-location">${esc(slippersError.template_name)}:${esc(slippersError.lineno)}</p>
77+
<ul class="slippers-error-list">${items}</ul>
78+
</div>`;
79+
}
80+
81+
function renderOverlay(errors) {
82+
const boxes = errors.map(renderErrorBox).join("");
83+
return `
84+
<style>${STYLES}</style>
85+
<div id="slippers-overlay">
86+
<div class="slippers-header">
87+
<h1>Slippers: Failed prop types</h1>
88+
<button class="slippers-close" id="slippers-close-btn">Close</button>
89+
</div>
90+
${boxes}
91+
</div>`;
92+
}
93+
94+
// ---------------------------------------------------------------------------
95+
// Console reporting
96+
// ---------------------------------------------------------------------------
97+
98+
function reportErrorsToConsole(errors) {
99+
console.group("Slippers: Failed prop types");
100+
errors.forEach(function (slippersError) {
101+
console.groupCollapsed(
102+
slippersError.tag_name + " in " + slippersError.template_name + ":" + slippersError.lineno
103+
);
104+
slippersError.errors.forEach(function (propError) {
105+
if (propError.error === "invalid")
106+
console.error(
107+
"Invalid prop " + propError.name + " set on " + slippersError.tag_name +
108+
". Expected " + propError.expected + ", got " + propError.actual + "."
109+
);
110+
else if (propError.error === "missing")
111+
console.error(
112+
"Required prop " + propError.name + " of type " + propError.expected +
113+
" not set on " + slippersError.tag_name + "."
114+
);
115+
else if (propError.error === "extra")
116+
console.error(
117+
"Extra prop " + propError.name + " of type " + propError.actual +
118+
" set on " + slippersError.tag_name + "."
119+
);
120+
});
121+
console.groupEnd();
122+
});
123+
console.groupEnd();
124+
}
125+
126+
// ---------------------------------------------------------------------------
127+
// Entry point
128+
// ---------------------------------------------------------------------------
129+
130+
document.addEventListener("DOMContentLoaded", function () {
131+
var errors = window.slippersPropErrors || [];
132+
var configEl = document.getElementById("slippers_type_checking_output");
133+
var config = JSON.parse((configEl && configEl.textContent) || "[]");
134+
135+
if (errors.length === 0) return;
136+
137+
if (config.includes("console")) reportErrorsToConsole(errors);
138+
139+
if (config.includes("overlay")) {
140+
var root = document.getElementById("slippers_errors_ui_root");
141+
if (!root) return;
142+
143+
root.innerHTML = renderOverlay(errors);
144+
145+
document.getElementById("slippers-close-btn").addEventListener("click", function () {
146+
root.innerHTML = "";
147+
});
148+
149+
document.addEventListener("keydown", function onKey(ev) {
150+
if (ev.key === "Escape") {
151+
root.innerHTML = "";
152+
document.removeEventListener("keydown", onKey);
153+
}
154+
});
155+
}
156+
});
157+
158+
})();

slippers/templates/slippers/overlay.html

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,5 @@
22
{% if SLIPPERS_RUNTIME_TYPE_CHECKING %}
33
<div id="slippers_errors_ui_root"></div>
44
{{ SLIPPERS_TYPE_CHECKING_OUTPUT|json_script:"slippers_type_checking_output" }}
5-
<link rel="stylesheet" href="{% static 'slippers/main.css' %}">
65
<script src="{% static "slippers/main.js" %}"></script>
76
{% endif %}

ui/.gitignore

Lines changed: 0 additions & 26 deletions
This file was deleted.

ui/.nvmrc

Lines changed: 0 additions & 1 deletion
This file was deleted.

ui/README.md

Lines changed: 0 additions & 69 deletions
This file was deleted.

ui/config/env.js

Lines changed: 0 additions & 104 deletions
This file was deleted.

0 commit comments

Comments
 (0)