irongit

A better version of regex 101

moonregex/src/App.jsx
177 lines5.1 KBJavaScript
1import { useState, useEffect } from "react";
2import parseBuilder, { readVars } from "./builder";
3import { AiFillSave } from "react-icons/ai";
4
5const placeholder = `Enter your variables here like below.
6group1Delim:\\n
7\tvar1:\\w
8\tvar2:\\d
9\tgroup2Delim:\\s
10\t\tvar3:\\w
11\t\tvar4:\\d`;
12
13function App() {
14 const [valid, setValid] = useState(false);
15 const [build, setBuild] = useState("");
16 const [edited, setEdited] = useState(0);
17 const [target, setTarget] = useState(null);
18 const [save, setSave] = useState(true);
19 const [hideVariables, setHideVariables] = useState(false);
20 const [hideBuilder, setHideBuilder] = useState(false);
21 const [varText, setVarText] = useState("");
22 const [builderText, setBuilderText] = useState("");
23 console.log("app is running");
24 const regexInput = document.querySelector(
25 "#regex-app > div > div.QtZzw > div > div.AUc0W > div.rjodX > div.cO83v > div.h9z_E.T886D > div > div > div:nth-child(1) > textarea"
26 );
27 const regexValue = document.querySelector(
28 "#regex-app > div > div.QtZzw > div > div.AUc0W > div.rjodX > div.cO83v > div.h9z_E.T886D > div > div > div.CodeMirror-scroll > div.CodeMirror-sizer > div > div > div > div.CodeMirror-code"
29 );
30 const hideButton = (setHide, hide) => {
31 return (
32 <div className="absolute flex bottom-3 w-full">
33 <button
34 className="h-10 w-24 rounded-md mx-auto bg-blue-500 text-white"
35 onClick={(e) => {
36 e.preventDefault();
37 setHide(!hide);
38 }}
39 >
40 {hide ? "Show" : "Hide"}
41 </button>
42 </div>
43 );
44 };
45 const variables = (
46 <div className="relative">
47 <textarea
48 rows={hideVariables ? 2 : 10}
49 className="w-full"
50 onChange={(e) => {
51 setVarText(e.target.value);
52 const parsedVars = readVars(e.target.value);
53 const parseBuild = parseBuilder(builderText, parsedVars);
54 if (!parseBuild) setValid(false);
55 else setValid(true);
56 setBuild(parseBuild);
57 }}
58 onKeyDown={(e) => {
59 if (e.ctrlKey && e.key == "s") {
60 saveBuild();
61 }
62 }}
63 ></textarea>
64 {hideButton(setHideVariables, hideVariables)}
65 </div>
66 );
67 const builder = (
68 <div className="relative">
69 <textarea
70 rows={hideBuilder ? 2 : 30}
71 className={
72 "w-full p-2 rounded-sm font-re101-input text-input decoration-slate-500 underline" +
73 (valid ? "" : " text-red-500")
74 }
75 placeholder={placeholder}
76 spellCheck="off"
77 onKeyDown={(e) => {
78 switch (e.key) {
79 case "Enter":
80 break;
81 case "Tab":
82 e.preventDefault();
83 const index = e.target.selectionStart;
84 e.target.value =
85 e.target.value.substring(0, index) +
86 "\t" +
87 e.target.value.substring(index);
88 e.target.selectionStart = e.target.selectionEnd = index + 1;
89 break;
90 }
91 if (e.ctrlKey && e.key == "s") {
92 saveBuild();
93 }
94 }}
95 onChangeCapture={(e) => {
96 const parsedVars = readVars(varText);
97 setBuilderText(e.target.value);
98 const parseBuild = parseBuilder(e.target.value, parsedVars);
99 if (!parseBuild) setValid(false);
100 else setValid(true);
101 setBuild(parseBuild);
102 setTarget(e.target);
103 setTimeout(
104 () =>
105 setEdited((old) => {
106 return old - 1;
107 }),
108 1000
109 );
110 setEdited(edited + 1);
111 }}
112 ></textarea>
113 {hideButton(setHideBuilder, hideBuilder)}
114 </div>
115 );
116
117 const updateRegex = () => {
118 if (edited !== 0 || !save) return;
119 saveBuild();
120 };
121
122 useEffect(updateRegex, [edited]);
123
124 useEffect(() => {
125 if (save) saveBuild();
126 }, [save]);
127
128 return (
129 <div>
130 <div className="w-full">
131 <div className="w-full text-lg text-center relative">
132 <div>Build Variables</div>
133 {variables}
134 <div>Build Regex</div>
135 {builder}
136 <div className="absolute right-8 top-8">
137 {saveButton(setSave, save)}
138 </div>
139 </div>
140 </div>
141 </div>
142 );
143
144 function saveBuild() {
145 if (!regexValue) return;
146 const length = regexValue.textContent.length;
147 for (let i = 0; i < length; i++)
148 regexInput.dispatchEvent(
149 new KeyboardEvent("keydown", {
150 key: "Backspace",
151 code: "Backspace",
152 keyCode: 8,
153 })
154 );
155 regexInput.value = build;
156 setTimeout(() => target?.focus(), 100);
157 }
158}
159
160export default App;
161function saveButton(setSave, save) {
162 const active = "bg-blue-500 h-10 p-1 rounded-sm hover:bg-blue-100";
163 const inactive = "bg-blue-100 h-10 p-1 rounded-sm hover:bg-blue-500";
164 const activeSave = <AiFillSave size="100%" color="white" />;
165 const inactiveSave = <AiFillSave size="100%" color="white" />;
166 return (
167 <button
168 className={save ? active : inactive}
169 onClick={(e) => {
170 e.preventDefault();
171 setSave(!save);
172 }}
173 >
174 {save ? activeSave : inactiveSave}
175 </button>
176 );
177}