irongit

A better version of regex 101

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