wadood commited on
Commit
8b9fb57
·
1 Parent(s): f0810d3

react based conversion

Browse files
Files changed (2) hide show
  1. src/App.tsx +6 -33
  2. src/SelectionApp.tsx +134 -0
src/App.tsx CHANGED
@@ -1,35 +1,8 @@
1
- import { useState } from 'react'
2
- import reactLogo from './assets/react.svg'
3
- import viteLogo from '/vite.svg'
4
- import './App.css'
5
 
6
- function App() {
7
- const [count, setCount] = useState(0)
 
8
 
9
- return (
10
- <>
11
- <div>
12
- <a href="https://vite.dev" target="_blank">
13
- <img src={viteLogo} className="logo" alt="Vite logo" />
14
- </a>
15
- <a href="https://react.dev" target="_blank">
16
- <img src={reactLogo} className="logo react" alt="React logo" />
17
- </a>
18
- </div>
19
- <h1>Vite + React</h1>
20
- <div className="card">
21
- <button onClick={() => setCount((count) => count + 1)}>
22
- count is {count}
23
- </button>
24
- <p>
25
- Add <code>app_build_command: npm run build</code> and <code>app_file: dist/index.html</code> in your README's metadata to easily build and deploy your app :)
26
- </p>
27
- </div>
28
- <p className="read-the-docs">
29
- Click on the Vite and React logos to learn more
30
- </p>
31
- </>
32
- )
33
- }
34
-
35
- export default App
 
1
+ import React from "react";
2
+ import SelectionApp from "./SelectionApp";
 
 
3
 
4
+ const App: React.FC = () => {
5
+ return <SelectionApp />;
6
+ };
7
 
8
+ export default App;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/SelectionApp.tsx ADDED
@@ -0,0 +1,134 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import React, { useState, useRef } from "react";
2
+
3
+ interface Span {
4
+ span_text: string;
5
+ start: number;
6
+ end: number;
7
+ }
8
+
9
+ const SelectionApp: React.FC = () => {
10
+ const [spans, setSpans] = useState<Span[]>([]);
11
+ const [keySpan, setKeySpan] = useState<string>("span_text");
12
+ const [keyStart, setKeyStart] = useState<string>("start");
13
+ const [keyEnd, setKeyEnd] = useState<string>("end");
14
+ const [lastText, setLastText] = useState<string>("");
15
+
16
+ const inputRef = useRef<HTMLDivElement>(null);
17
+
18
+ // Capture the selected text and its indices
19
+ const getSelectionIndices = () => {
20
+ if (!inputRef.current) return;
21
+ const container = inputRef.current;
22
+ const selection = window.getSelection();
23
+ if (!selection || !selection.rangeCount) return;
24
+
25
+ const range = selection.getRangeAt(0);
26
+ if (!container.contains(range.startContainer) || !container.contains(range.endContainer))
27
+ return;
28
+
29
+ const selectedText = selection.toString();
30
+ if (!selectedText) return;
31
+
32
+ // Compute start/end indices
33
+ const preRange = document.createRange();
34
+ preRange.setStart(container, 0);
35
+ preRange.setEnd(range.startContainer, range.startOffset);
36
+ const startIndex = preRange.toString().length;
37
+ const endIndex = startIndex + selectedText.length;
38
+
39
+ const newSpan: Span = { span_text: selectedText, start: startIndex, end: endIndex };
40
+ setSpans((prev) => [newSpan, ...prev].slice(0, 5)); // Keep only latest 5
41
+ };
42
+
43
+ // Map internal spans to current key names
44
+ const renderSpans = () => {
45
+ return spans.map((s) => ({
46
+ [keySpan]: s.span_text,
47
+ [keyStart]: s.start,
48
+ [keyEnd]: s.end,
49
+ }));
50
+ };
51
+
52
+ // Clear spans if input text changes
53
+ const handleInput = (e: React.FormEvent<HTMLDivElement>) => {
54
+ const currentText = e.currentTarget.innerText;
55
+ if (currentText !== lastText) {
56
+ setSpans([]);
57
+ setLastText(currentText);
58
+ }
59
+ };
60
+
61
+ return (
62
+ <div style={{ padding: "20px", fontFamily: "sans-serif" }}>
63
+ <h3>Highlight text to get indices</h3>
64
+
65
+ {/* Settings Panel */}
66
+ <div
67
+ style={{
68
+ marginBottom: "15px",
69
+ padding: "10px",
70
+ border: "1px solid #ccc",
71
+ borderRadius: "6px",
72
+ background: "#fafafa",
73
+ width: "90%",
74
+ }}
75
+ >
76
+ <strong>Settings (rename keys):</strong>
77
+ <br />
78
+ <br />
79
+ <label>
80
+ Span Text Key:{" "}
81
+ <input value={keySpan} onChange={(e) => setKeySpan(e.target.value)} />
82
+ </label>
83
+ <label style={{ marginLeft: "10px" }}>
84
+ Start Key:{" "}
85
+ <input value={keyStart} onChange={(e) => setKeyStart(e.target.value)} />
86
+ </label>
87
+ <label style={{ marginLeft: "10px" }}>
88
+ End Key:{" "}
89
+ <input value={keyEnd} onChange={(e) => setKeyEnd(e.target.value)} />
90
+ </label>
91
+ </div>
92
+
93
+ {/* Editable Div */}
94
+ <div
95
+ ref={inputRef}
96
+ contentEditable
97
+ onInput={handleInput}
98
+ style={{
99
+ width: "90%",
100
+ minHeight: "150px",
101
+ border: "1px solid #ccc",
102
+ padding: "10px",
103
+ whiteSpace: "pre-wrap",
104
+ overflowWrap: "break-word",
105
+ }}
106
+ ></div>
107
+
108
+ <button
109
+ onClick={getSelectionIndices}
110
+ style={{ marginTop: "10px", padding: "5px 10px" }}
111
+ >
112
+ Get Span JSON
113
+ </button>
114
+
115
+ {/* Display JSON */}
116
+ <pre
117
+ style={{
118
+ marginTop: "15px",
119
+ fontFamily: "monospace",
120
+ background: "#f4f4f4",
121
+ padding: "10px",
122
+ borderRadius: "6px",
123
+ border: "1px solid #ddd",
124
+ whiteSpace: "pre-wrap",
125
+ userSelect: "text",
126
+ }}
127
+ >
128
+ {spans.length ? JSON.stringify(renderSpans(), null, 2) : ""}
129
+ </pre>
130
+ </div>
131
+ );
132
+ };
133
+
134
+ export default SelectionApp;