@pfmcodes/caret 0.1.4 → 0.2.0
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/README.md +42 -34
- package/commonjs/editor.js +67 -15
- package/commonjs/theme.js +1 -1
- package/esm/editor.js +61 -15
- package/esm/theme.js +1 -1
- package/index.css +7 -2
- package/package.json +10 -7
- package/types/editor.ts +334 -0
- package/types/esm-highlight.d.ts +4 -0
- package/types/index.d.ts +34 -0
- package/types/index.ts +10 -0
- package/types/languages.ts +117 -0
- package/types/theme.ts +18 -0
package/README.md
CHANGED
|
@@ -1,25 +1,25 @@
|
|
|
1
1
|
# Caret
|
|
2
2
|
|
|
3
3
|
[](https://opensource.org/licenses/MIT)
|
|
4
|
-
[](https://github.com/PFMCODES/lexius-edior)
|
|
5
|
+
[](https://github.com/PFMCODES/lexius-edior)
|
|
6
|
+
[](https://github.com/pfmcodes/lexius-editor)
|
|
7
7
|
|
|
8
8
|
A lightweight, feature-rich code editor with real-time syntax highlighting and custom caret rendering. Built with vanilla JavaScript and powered by Highlight.js, caret delivers a smooth coding experience with professional-grade features.
|
|
9
9
|
|
|
10
|
-
##
|
|
10
|
+
## Features
|
|
11
11
|
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
-
|
|
15
|
-
-
|
|
16
|
-
-
|
|
17
|
-
-
|
|
18
|
-
-
|
|
19
|
-
-
|
|
20
|
-
-
|
|
12
|
+
- **Live Syntax Highlighting** - Real-time code highlighting powered by Highlight.js
|
|
13
|
+
- **Custom Caret** - Smooth, pixel-perfect Caret positioning and rendering
|
|
14
|
+
- **Line Numbers** - Built-in line counter with dynamic updates
|
|
15
|
+
- **Smart Indentation** - Tab/Shift+Tab support for indenting/unindenting code blocks
|
|
16
|
+
- **Theme Support** - Multiple syntax highlighting themes (light/dark modes)
|
|
17
|
+
- **Smooth Scrolling** - Synchronized scrolling for code, highlights, and line numbers
|
|
18
|
+
- **ES Modules** - Modern ESM architecture for easy integration
|
|
19
|
+
- **TypeScript Ready** - Full TypeScript definitions included
|
|
20
|
+
- **Lightweight** - Pure JavaScript, no heavy frameworks required
|
|
21
21
|
|
|
22
|
-
##
|
|
22
|
+
## Table of Contents
|
|
23
23
|
|
|
24
24
|
- [What's new](#What's-New?)
|
|
25
25
|
- [Installation](#installation)
|
|
@@ -29,12 +29,14 @@ A lightweight, feature-rich code editor with real-time syntax highlighting and c
|
|
|
29
29
|
- [Customization](#customization)
|
|
30
30
|
- [Contributing](#contributing)
|
|
31
31
|
- [License](#license)
|
|
32
|
+
- [Performance Notes](#performance-notes)
|
|
32
33
|
|
|
33
34
|
## What's-New?
|
|
34
35
|
|
|
35
|
-
###
|
|
36
|
+
### The editor has been optimized like crazy, the editor used to lag at 500 lines not it does not lag until 10k+ lines(x20 performance increase)
|
|
37
|
+
### for more info about the performance check out [this.](#performance-notes)
|
|
36
38
|
|
|
37
|
-
##
|
|
39
|
+
## Installation
|
|
38
40
|
|
|
39
41
|
### NPM
|
|
40
42
|
|
|
@@ -54,7 +56,7 @@ yarn add @pfmcodes/caret
|
|
|
54
56
|
pnpm add @pfmcodes/caret
|
|
55
57
|
```
|
|
56
58
|
|
|
57
|
-
##
|
|
59
|
+
## Quick Start
|
|
58
60
|
|
|
59
61
|
### Basic Usage
|
|
60
62
|
|
|
@@ -73,7 +75,7 @@ pnpm add @pfmcodes/caret
|
|
|
73
75
|
<script type="module">
|
|
74
76
|
import editor from './node_modules/@pfmcodes/caret/esm/index.js';
|
|
75
77
|
|
|
76
|
-
const instance = await editor.createEditor(
|
|
78
|
+
const instance = await editor.editor.createEditor(
|
|
77
79
|
document.getElementById('editor'),
|
|
78
80
|
{
|
|
79
81
|
value: 'console.log("Hello, World!");',
|
|
@@ -92,7 +94,7 @@ pnpm add @pfmcodes/caret
|
|
|
92
94
|
import editor from '@pfmcodes/caret';
|
|
93
95
|
|
|
94
96
|
// Create editor instance
|
|
95
|
-
const editorInstance = await editor.createEditor(
|
|
97
|
+
const editorInstance = await editor.editor.createEditor(
|
|
96
98
|
document.getElementById('editor'),
|
|
97
99
|
{
|
|
98
100
|
value: '', // Initial code
|
|
@@ -102,7 +104,7 @@ const editorInstance = await editor.createEditor(
|
|
|
102
104
|
);
|
|
103
105
|
```
|
|
104
106
|
|
|
105
|
-
##
|
|
107
|
+
## Project Structure
|
|
106
108
|
|
|
107
109
|
```
|
|
108
110
|
caret/
|
|
@@ -116,14 +118,14 @@ caret/
|
|
|
116
118
|
└── LICENSE # MIT License
|
|
117
119
|
```
|
|
118
120
|
|
|
119
|
-
##
|
|
121
|
+
## Usage
|
|
120
122
|
|
|
121
123
|
### JavaScript Editor
|
|
122
124
|
|
|
123
125
|
```javascript
|
|
124
|
-
import editor from '@pfmcodes/caret';
|
|
126
|
+
import editor from '@pfmcodes/caret'; // auto link to commonjs version
|
|
125
127
|
|
|
126
|
-
const jsEditor = await editor.createEditor(
|
|
128
|
+
const jsEditor = await editor.editor.createEditor(
|
|
127
129
|
document.getElementById('js-editor'),
|
|
128
130
|
{
|
|
129
131
|
value: `function greet(name) {
|
|
@@ -168,7 +170,7 @@ const emptyEditor = await editor.createEditor(
|
|
|
168
170
|
);
|
|
169
171
|
```
|
|
170
172
|
|
|
171
|
-
##
|
|
173
|
+
## Customization
|
|
172
174
|
|
|
173
175
|
### Custom Styling
|
|
174
176
|
|
|
@@ -205,7 +207,7 @@ The editor comes with default styles that you can override:
|
|
|
205
207
|
}
|
|
206
208
|
```
|
|
207
209
|
|
|
208
|
-
##
|
|
210
|
+
## Advanced Features
|
|
209
211
|
|
|
210
212
|
### Multi-Language Support
|
|
211
213
|
|
|
@@ -290,7 +292,7 @@ Caret supports all Highlight.js themes. Popular options include:
|
|
|
290
292
|
- `stackoverflow-light`
|
|
291
293
|
- `xcode`
|
|
292
294
|
|
|
293
|
-
##
|
|
295
|
+
## API Reference
|
|
294
296
|
|
|
295
297
|
### createEditor(container, options)
|
|
296
298
|
|
|
@@ -339,7 +341,7 @@ The editor features a custom-rendered Caret that adapts to your theme (light/dar
|
|
|
339
341
|
#### Synchronized Scrolling
|
|
340
342
|
All editor components (code, highlights, line numbers) scroll together smoothly.
|
|
341
343
|
|
|
342
|
-
##
|
|
344
|
+
## Complete Example
|
|
343
345
|
|
|
344
346
|
Here's a complete working example:
|
|
345
347
|
|
|
@@ -457,7 +459,7 @@ for (let i = 0; i < 10; i++) {
|
|
|
457
459
|
</html>
|
|
458
460
|
```
|
|
459
461
|
|
|
460
|
-
##
|
|
462
|
+
## Technical Details
|
|
461
463
|
|
|
462
464
|
### How It Works
|
|
463
465
|
|
|
@@ -478,6 +480,7 @@ The editor synchronizes all layers during:
|
|
|
478
480
|
- **Real-time Highlighting**: Uses Highlight.js for fast, accurate syntax highlighting
|
|
479
481
|
- **Canvas Measurement**: Employs HTML5 Canvas API for precise text width calculations
|
|
480
482
|
- **Event Optimization**: Efficiently updates only what's necessary on each interaction
|
|
483
|
+
- **Heavy Optimization**: previous version(0.1.6) used to handle 500 lines before lagging, with new caret@0.2.0, there's almost 20 times perfomace increase now it can handle 10K+ lines smoothly before lagging(better results in optimized browsers like firfox)
|
|
481
484
|
|
|
482
485
|
### Browser Support
|
|
483
486
|
|
|
@@ -485,7 +488,7 @@ The editor synchronizes all layers during:
|
|
|
485
488
|
- Chrome, Firefox, Safari, Edge (latest versions)
|
|
486
489
|
- Requires JavaScript modules support
|
|
487
490
|
|
|
488
|
-
##
|
|
491
|
+
## Contributing
|
|
489
492
|
|
|
490
493
|
Contributions are welcome! Please follow these steps:
|
|
491
494
|
|
|
@@ -514,26 +517,31 @@ npm run dev
|
|
|
514
517
|
npm run build
|
|
515
518
|
```
|
|
516
519
|
|
|
517
|
-
##
|
|
520
|
+
## License
|
|
518
521
|
|
|
519
522
|
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
|
520
523
|
|
|
521
|
-
##
|
|
524
|
+
## Performance Notes
|
|
525
|
+
- Handles 10k+ lines smoothly in all browsers
|
|
526
|
+
- Firefox DevTools can inspect up to 3M lines without breaking a sweat
|
|
527
|
+
- Chrome DevTools politely requests you don't inspect past 300k lines
|
|
528
|
+
|
|
529
|
+
## Acknowledgments
|
|
522
530
|
|
|
523
531
|
- Built with modern JavaScript/TypeScript
|
|
524
532
|
- Syntax highlighting powered by Highlight.js
|
|
525
533
|
- Inspired by various text editor projects in the JavaScript ecosystem
|
|
526
534
|
|
|
527
|
-
##
|
|
535
|
+
## Support
|
|
528
536
|
|
|
529
537
|
- **Issues**: [GitHub Issues](https://github.com/pfmcodes/lexius-editor/issues)
|
|
530
538
|
- **Discussions**: [GitHub Discussions](https://github.com/pfmcodes/lexius-editor/discussions)
|
|
531
539
|
|
|
532
|
-
##
|
|
540
|
+
## Links
|
|
533
541
|
|
|
534
542
|
- [GitHub Repository](https://github.com/pfmcodes/lexius-editor)
|
|
535
543
|
- [NPM Package](https://www.npmjs.com/package/@pfmcodes/caret) *(if published)*
|
|
536
544
|
|
|
537
545
|
---
|
|
538
546
|
|
|
539
|
-
Made with ❤️ by [PFMCODES](https://github.com/PFMCODES)
|
|
547
|
+
Made with ❤️ by [PFMCODES](https://github.com/PFMCODES)
|
package/commonjs/editor.js
CHANGED
|
@@ -18,6 +18,10 @@ async function createEditor(editor, data) {
|
|
|
18
18
|
highlighted.id = "Caret-highlighted";
|
|
19
19
|
caret.id = "Caret-caret";
|
|
20
20
|
lineCounter.id = "Caret-lineCounter";
|
|
21
|
+
editor1.className = 'dark';
|
|
22
|
+
highlighted.className = 'dark';
|
|
23
|
+
caret.className = 'dark';
|
|
24
|
+
lineCounter.className = 'dark';
|
|
21
25
|
editor1.style.backgroundColor = isDark ? "#222" : "#fff";
|
|
22
26
|
let code = data.value || "";
|
|
23
27
|
let language = data.language;
|
|
@@ -33,10 +37,10 @@ async function createEditor(editor, data) {
|
|
|
33
37
|
const link = document.createElement("link");
|
|
34
38
|
link.rel = "stylesheet";
|
|
35
39
|
link.id = "Caret-theme";
|
|
36
|
-
link.href =
|
|
40
|
+
link.href = `https://esm.sh/@pfmcodes/highlight.js@1.0.0/styles/${theme}.css`;
|
|
37
41
|
document.head.appendChild(link);
|
|
38
42
|
} else {
|
|
39
|
-
themeLink.href =
|
|
43
|
+
themeLink.href = `https://esm.sh/@pfmcodes/highlight.js@1.0.0/styles/${theme}.css`;
|
|
40
44
|
}
|
|
41
45
|
} else {
|
|
42
46
|
let themeLink = document.getElementById("Caret-theme");
|
|
@@ -44,7 +48,7 @@ async function createEditor(editor, data) {
|
|
|
44
48
|
const link = document.createElement("link");
|
|
45
49
|
link.rel = "stylesheet";
|
|
46
50
|
link.id = "Caret-theme";
|
|
47
|
-
link.href =
|
|
51
|
+
link.href = `https://esm.sh/@pfmcodes/highlight.js@1.0.0/styles/hybrid.css`;
|
|
48
52
|
document.head.appendChild(link);
|
|
49
53
|
} else {
|
|
50
54
|
themeLink.href = `./highlight.js/styles/hybrid.css`;
|
|
@@ -55,12 +59,13 @@ async function createEditor(editor, data) {
|
|
|
55
59
|
editor1.autocomplete = "off";
|
|
56
60
|
editor1.autocorrect = "off";
|
|
57
61
|
editor.style = "position: relative; width: 600px; height: 300px; overflow: hidden; /* 👈 CRITICAL */ font-size: 14px;"
|
|
58
|
-
if (code) {
|
|
59
|
-
editor1.value = code;
|
|
62
|
+
if (code && editor && editor1 && language && highlighted) {
|
|
60
63
|
editor1.style.paddingTop = "-9px";
|
|
61
|
-
|
|
64
|
+
console.log(data.value + " data.value");
|
|
65
|
+
editor1.value = data.value;
|
|
66
|
+
highlighted.innerHTML = await _render(data.value, language, editor1);
|
|
62
67
|
}
|
|
63
|
-
const keyDown = (e) => {
|
|
68
|
+
const keyDown = async (e) => {
|
|
64
69
|
if (e.key !== "Tab") return;
|
|
65
70
|
|
|
66
71
|
e.preventDefault();
|
|
@@ -113,7 +118,7 @@ async function createEditor(editor, data) {
|
|
|
113
118
|
editor1.selectionEnd =
|
|
114
119
|
end + delta * newLines.length;
|
|
115
120
|
|
|
116
|
-
highlighted.innerHTML =
|
|
121
|
+
highlighted.innerHTML = await _render(editor1.value, language, editor1);
|
|
117
122
|
updateLineNumbers();
|
|
118
123
|
updateCaret();
|
|
119
124
|
}
|
|
@@ -139,6 +144,7 @@ async function createEditor(editor, data) {
|
|
|
139
144
|
lineCounter.innerHTML = html;
|
|
140
145
|
}
|
|
141
146
|
|
|
147
|
+
highlighted.style.paddingTop = "12px"
|
|
142
148
|
|
|
143
149
|
function getFontMetrics() {
|
|
144
150
|
const metrics = measureCtx.measureText("Mg");
|
|
@@ -187,19 +193,19 @@ async function createEditor(editor, data) {
|
|
|
187
193
|
(lineHeight - ascent) +
|
|
188
194
|
"px";
|
|
189
195
|
|
|
190
|
-
caret.style.height = `${lineHeight}px`;
|
|
196
|
+
caret.style.height = `${lineHeight - 5}px`;
|
|
191
197
|
}
|
|
192
|
-
const input = () => {
|
|
198
|
+
const input = async () => {
|
|
193
199
|
caret.style.opacity = "1";
|
|
194
|
-
highlighted.innerHTML =
|
|
200
|
+
highlighted.innerHTML = await _render(editor1.value, language, editor1);
|
|
195
201
|
updateLineNumbers();
|
|
196
202
|
updateCaret();
|
|
197
203
|
};
|
|
198
204
|
editor1.addEventListener("input", input);
|
|
199
|
-
const scroll = () => {
|
|
205
|
+
const scroll = async () => {
|
|
200
206
|
const x = -editor1.scrollLeft;
|
|
201
207
|
const y = -editor1.scrollTop;
|
|
202
|
-
|
|
208
|
+
highlighted.innerHTML = await _render(editor1.value, language, editor1);
|
|
203
209
|
highlighted.style.transform = `translate(${x}px, ${y}px)`;
|
|
204
210
|
caret.style.transform = `translate(${x}px, ${y}px)`;
|
|
205
211
|
lineCounter.style.transform = `translateY(${y}px)`;
|
|
@@ -225,8 +231,8 @@ async function createEditor(editor, data) {
|
|
|
225
231
|
editor1.removeEventListener('keydown', keyDown);
|
|
226
232
|
editor.innerHTML = "";
|
|
227
233
|
}
|
|
228
|
-
function refresh() {
|
|
229
|
-
highlighted.innerHTML =
|
|
234
|
+
async function refresh() {
|
|
235
|
+
highlighted.innerHTML = await _render(editor1.value, language, editor1);
|
|
230
236
|
updateLineNumbers();
|
|
231
237
|
updateCaret();
|
|
232
238
|
}
|
|
@@ -258,6 +264,52 @@ async function createEditor(editor, data) {
|
|
|
258
264
|
};
|
|
259
265
|
}
|
|
260
266
|
|
|
267
|
+
function escapeHtml(str) {
|
|
268
|
+
return str
|
|
269
|
+
.replace(/&/g, "&")
|
|
270
|
+
.replace(/</g, "<")
|
|
271
|
+
.replace(/>/g, ">");
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
async function _render(code, language, editor) {
|
|
275
|
+
// If no editor context provided, just highlight everything (initial load)
|
|
276
|
+
if (!editor) {
|
|
277
|
+
return hljs.highlight(code, { language }).value;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
const scrollTop = editor.scrollTop;
|
|
281
|
+
const scrollBottom = scrollTop + editor.clientHeight;
|
|
282
|
+
const style = getComputedStyle(editor);
|
|
283
|
+
const lineHeight = parseFloat(style.lineHeight);
|
|
284
|
+
|
|
285
|
+
// Calculate visible line range
|
|
286
|
+
const startLine = Math.floor(scrollTop / lineHeight);
|
|
287
|
+
const endLine = Math.ceil(scrollBottom / lineHeight);
|
|
288
|
+
|
|
289
|
+
const lines = code.split("\n");
|
|
290
|
+
|
|
291
|
+
// Add buffer (render extra lines above/below for smooth scrolling)
|
|
292
|
+
const bufferLines = 10;
|
|
293
|
+
const visibleStart = Math.max(0, startLine - bufferLines) || 0;
|
|
294
|
+
const visibleEnd = Math.min(lines.length, endLine + bufferLines) || 0;
|
|
295
|
+
|
|
296
|
+
// Split into three sections
|
|
297
|
+
const beforeLines = lines.slice(0, visibleStart);
|
|
298
|
+
const visibleLines = lines.slice(visibleStart, visibleEnd);
|
|
299
|
+
const afterLines = lines.slice(visibleEnd);
|
|
300
|
+
|
|
301
|
+
// Only highlight visible portion
|
|
302
|
+
|
|
303
|
+
const highlightedVisible = hljs.highlight(visibleLines.join("\n"), { language }).value;
|
|
304
|
+
// Plain text for non-visible areas (no highlighting = faster)
|
|
305
|
+
if (highlightedVisible.trim() === "") {
|
|
306
|
+
return hljs.highlight(escapeHtml(code), { language }).value;
|
|
307
|
+
}
|
|
308
|
+
const beforeHTML = "\n".repeat(beforeLines.length);
|
|
309
|
+
const afterHTML = "\n".repeat(afterLines.length);
|
|
310
|
+
return beforeHTML + highlightedVisible + afterHTML;
|
|
311
|
+
}
|
|
312
|
+
|
|
261
313
|
const editor = {
|
|
262
314
|
createEditor
|
|
263
315
|
};
|
package/commonjs/theme.js
CHANGED
package/esm/editor.js
CHANGED
|
@@ -22,7 +22,6 @@ async function createEditor(editor, data) {
|
|
|
22
22
|
highlighted.className = 'dark';
|
|
23
23
|
caret.className = 'dark';
|
|
24
24
|
lineCounter.className = 'dark';
|
|
25
|
-
editor.classList.add("");
|
|
26
25
|
editor1.style.backgroundColor = isDark ? "#222" : "#fff";
|
|
27
26
|
let code = data.value || "";
|
|
28
27
|
let language = data.language;
|
|
@@ -38,10 +37,10 @@ async function createEditor(editor, data) {
|
|
|
38
37
|
const link = document.createElement("link");
|
|
39
38
|
link.rel = "stylesheet";
|
|
40
39
|
link.id = "Caret-theme";
|
|
41
|
-
link.href =
|
|
40
|
+
link.href = `https://esm.sh/@pfmcodes/highlight.js@1.0.0/styles/${theme}.css`;
|
|
42
41
|
document.head.appendChild(link);
|
|
43
42
|
} else {
|
|
44
|
-
themeLink.href =
|
|
43
|
+
themeLink.href = `https://esm.sh/@pfmcodes/highlight.js@1.0.0/styles/${theme}.css`;
|
|
45
44
|
}
|
|
46
45
|
} else {
|
|
47
46
|
let themeLink = document.getElementById("Caret-theme");
|
|
@@ -49,7 +48,7 @@ async function createEditor(editor, data) {
|
|
|
49
48
|
const link = document.createElement("link");
|
|
50
49
|
link.rel = "stylesheet";
|
|
51
50
|
link.id = "Caret-theme";
|
|
52
|
-
link.href =
|
|
51
|
+
link.href = `https://esm.sh/@pfmcodes/highlight.js@1.0.0/styles/hybrid.css`;
|
|
53
52
|
document.head.appendChild(link);
|
|
54
53
|
} else {
|
|
55
54
|
themeLink.href = `./highlight.js/styles/hybrid.css`;
|
|
@@ -60,12 +59,13 @@ async function createEditor(editor, data) {
|
|
|
60
59
|
editor1.autocomplete = "off";
|
|
61
60
|
editor1.autocorrect = "off";
|
|
62
61
|
editor.style = "position: relative; width: 600px; height: 300px; overflow: hidden; /* 👈 CRITICAL */ font-size: 14px;"
|
|
63
|
-
if (code) {
|
|
64
|
-
editor1.value = code;
|
|
62
|
+
if (code && editor && editor1 && language && highlighted) {
|
|
65
63
|
editor1.style.paddingTop = "-9px";
|
|
66
|
-
|
|
64
|
+
console.log(data.value + " data.value");
|
|
65
|
+
editor1.value = data.value;
|
|
66
|
+
highlighted.innerHTML = await _render(data.value, language, editor1);
|
|
67
67
|
}
|
|
68
|
-
const keyDown = (e) => {
|
|
68
|
+
const keyDown = async (e) => {
|
|
69
69
|
if (e.key !== "Tab") return;
|
|
70
70
|
|
|
71
71
|
e.preventDefault();
|
|
@@ -118,7 +118,7 @@ async function createEditor(editor, data) {
|
|
|
118
118
|
editor1.selectionEnd =
|
|
119
119
|
end + delta * newLines.length;
|
|
120
120
|
|
|
121
|
-
highlighted.innerHTML =
|
|
121
|
+
highlighted.innerHTML = await _render(editor1.value, language, editor1);
|
|
122
122
|
updateLineNumbers();
|
|
123
123
|
updateCaret();
|
|
124
124
|
}
|
|
@@ -195,17 +195,17 @@ async function createEditor(editor, data) {
|
|
|
195
195
|
|
|
196
196
|
caret.style.height = `${lineHeight - 5}px`;
|
|
197
197
|
}
|
|
198
|
-
const input = () => {
|
|
198
|
+
const input = async () => {
|
|
199
199
|
caret.style.opacity = "1";
|
|
200
|
-
highlighted.innerHTML =
|
|
200
|
+
highlighted.innerHTML = await _render(editor1.value, language, editor1);
|
|
201
201
|
updateLineNumbers();
|
|
202
202
|
updateCaret();
|
|
203
203
|
};
|
|
204
204
|
editor1.addEventListener("input", input);
|
|
205
|
-
const scroll = () => {
|
|
205
|
+
const scroll = async () => {
|
|
206
206
|
const x = -editor1.scrollLeft;
|
|
207
207
|
const y = -editor1.scrollTop;
|
|
208
|
-
|
|
208
|
+
highlighted.innerHTML = await _render(editor1.value, language, editor1);
|
|
209
209
|
highlighted.style.transform = `translate(${x}px, ${y}px)`;
|
|
210
210
|
caret.style.transform = `translate(${x}px, ${y}px)`;
|
|
211
211
|
lineCounter.style.transform = `translateY(${y}px)`;
|
|
@@ -231,8 +231,8 @@ async function createEditor(editor, data) {
|
|
|
231
231
|
editor1.removeEventListener('keydown', keyDown);
|
|
232
232
|
editor.innerHTML = "";
|
|
233
233
|
}
|
|
234
|
-
function refresh() {
|
|
235
|
-
highlighted.innerHTML =
|
|
234
|
+
async function refresh() {
|
|
235
|
+
highlighted.innerHTML = await _render(editor1.value, language, editor1);
|
|
236
236
|
updateLineNumbers();
|
|
237
237
|
updateCaret();
|
|
238
238
|
}
|
|
@@ -264,6 +264,52 @@ async function createEditor(editor, data) {
|
|
|
264
264
|
};
|
|
265
265
|
}
|
|
266
266
|
|
|
267
|
+
function escapeHtml(str) {
|
|
268
|
+
return str
|
|
269
|
+
.replace(/&/g, "&")
|
|
270
|
+
.replace(/</g, "<")
|
|
271
|
+
.replace(/>/g, ">");
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
async function _render(code, language, editor) {
|
|
275
|
+
// If no editor context provided, just highlight everything (initial load)
|
|
276
|
+
if (!editor) {
|
|
277
|
+
return hljs.highlight(code, { language }).value;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
const scrollTop = editor.scrollTop;
|
|
281
|
+
const scrollBottom = scrollTop + editor.clientHeight;
|
|
282
|
+
const style = getComputedStyle(editor);
|
|
283
|
+
const lineHeight = parseFloat(style.lineHeight);
|
|
284
|
+
|
|
285
|
+
// Calculate visible line range
|
|
286
|
+
const startLine = Math.floor(scrollTop / lineHeight);
|
|
287
|
+
const endLine = Math.ceil(scrollBottom / lineHeight);
|
|
288
|
+
|
|
289
|
+
const lines = code.split("\n");
|
|
290
|
+
|
|
291
|
+
// Add buffer (render extra lines above/below for smooth scrolling)
|
|
292
|
+
const bufferLines = 10;
|
|
293
|
+
const visibleStart = Math.max(0, startLine - bufferLines) || 0;
|
|
294
|
+
const visibleEnd = Math.min(lines.length, endLine + bufferLines) || 0;
|
|
295
|
+
|
|
296
|
+
// Split into three sections
|
|
297
|
+
const beforeLines = lines.slice(0, visibleStart);
|
|
298
|
+
const visibleLines = lines.slice(visibleStart, visibleEnd);
|
|
299
|
+
const afterLines = lines.slice(visibleEnd);
|
|
300
|
+
|
|
301
|
+
// Only highlight visible portion
|
|
302
|
+
|
|
303
|
+
const highlightedVisible = hljs.highlight(visibleLines.join("\n"), { language }).value;
|
|
304
|
+
// Plain text for non-visible areas (no highlighting = faster)
|
|
305
|
+
if (highlightedVisible.trim() === "") {
|
|
306
|
+
return hljs.highlight(escapeHtml(code), { language }).value;
|
|
307
|
+
}
|
|
308
|
+
const beforeHTML = "\n".repeat(beforeLines.length);
|
|
309
|
+
const afterHTML = "\n".repeat(afterLines.length);
|
|
310
|
+
return beforeHTML + highlightedVisible + afterHTML;
|
|
311
|
+
}
|
|
312
|
+
|
|
267
313
|
const editor = {
|
|
268
314
|
createEditor
|
|
269
315
|
};
|
package/esm/theme.js
CHANGED
package/index.css
CHANGED
|
@@ -2,16 +2,21 @@
|
|
|
2
2
|
position: absolute;
|
|
3
3
|
border: none;
|
|
4
4
|
inset: 0;
|
|
5
|
-
padding: 10px;
|
|
5
|
+
padding: 10px 10px 10px 0px;
|
|
6
6
|
font-family: monospace;
|
|
7
7
|
background: transparent;
|
|
8
8
|
color: transparent;
|
|
9
9
|
caret-color: #fff;
|
|
10
10
|
border: 1px solid #ccc;
|
|
11
|
-
overflow: scroll; /* 👈 ONLY THIS SCROLLS */
|
|
11
|
+
overflow-x: scroll; /* 👈 ONLY THIS SCROLLS */
|
|
12
12
|
z-index: 1;
|
|
13
13
|
width: 100%;
|
|
14
14
|
}
|
|
15
|
+
|
|
16
|
+
#Caret-texarea::-webkit-scrollbar {
|
|
17
|
+
z-index: 3;
|
|
18
|
+
}
|
|
19
|
+
|
|
15
20
|
#Caret-textarea:focus {
|
|
16
21
|
outline: none;
|
|
17
22
|
}
|
package/package.json
CHANGED
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pfmcodes/caret",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "The official code editor engine for lexius",
|
|
5
5
|
"type": "module",
|
|
6
|
-
"main": "./index.
|
|
7
|
-
"types": "./types/
|
|
6
|
+
"main": "./esm/index.js",
|
|
7
|
+
"types": "./types/index.d.ts",
|
|
8
8
|
"exports": {
|
|
9
9
|
".": {
|
|
10
|
+
"types": "./types/index.d.ts",
|
|
10
11
|
"import": "./esm/index.js",
|
|
11
|
-
"require": "./commonjs/index.js"
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
"require": "./commonjs/index.js"
|
|
13
|
+
},
|
|
14
|
+
"./commonjs": "./commonjs/index.js",
|
|
15
|
+
"./esm": "./esm/index.js"
|
|
14
16
|
},
|
|
15
17
|
"repository": {
|
|
16
18
|
"type": "git",
|
|
@@ -24,6 +26,7 @@
|
|
|
24
26
|
"syntax-highlighting",
|
|
25
27
|
"language-server",
|
|
26
28
|
"typescript",
|
|
29
|
+
"python",
|
|
27
30
|
"javascript",
|
|
28
31
|
"ide",
|
|
29
32
|
"browser-editor",
|
|
@@ -35,4 +38,4 @@
|
|
|
35
38
|
"url": "https://github.com/PFMCODES/lexius-editor/issues"
|
|
36
39
|
},
|
|
37
40
|
"homepage": "https://github.com/PFMCODES/lexius-editor#readme"
|
|
38
|
-
}
|
|
41
|
+
}
|
package/types/editor.ts
ADDED
|
@@ -0,0 +1,334 @@
|
|
|
1
|
+
import hljs from "https://esm.sh/@pfmcodes/highlight.js@1.0.0/es/core.js"; // Use default export
|
|
2
|
+
import languages from "./languages.ts";
|
|
3
|
+
|
|
4
|
+
languages.init();
|
|
5
|
+
|
|
6
|
+
async function createEditor(editor: HTMLElement, data: { value?: string, language: string, theme?: string }) {
|
|
7
|
+
const editor1: HTMLTextAreaElement = document.createElement("textarea");
|
|
8
|
+
const highlighted: HTMLPreElement = document.createElement("pre");
|
|
9
|
+
const caret: HTMLDivElement = document.createElement("div");
|
|
10
|
+
const measureCanvas: HTMLCanvasElement = document.createElement("canvas");
|
|
11
|
+
const measureCtx: CanvasRenderingContext2D = measureCanvas.getContext("2d") as CanvasRenderingContext2D;
|
|
12
|
+
if (!measureCtx) {
|
|
13
|
+
throw new Error("Failed to get 2D context from canvas");
|
|
14
|
+
}
|
|
15
|
+
const isDark = data.theme && (data.theme.includes("dark") || data.theme.includes("night"));
|
|
16
|
+
const caretColor = isDark ? "#fff" : "#7116d8";
|
|
17
|
+
const lineColor = isDark ? "#fff" : "#000";
|
|
18
|
+
const lineCounter: HTMLDivElement = document.createElement("div");
|
|
19
|
+
|
|
20
|
+
editor1.id = "Caret-textarea";
|
|
21
|
+
highlighted.id = "Caret-highlighted";
|
|
22
|
+
caret.id = "Caret-caret";
|
|
23
|
+
lineCounter.id = "Caret-lineCounter";
|
|
24
|
+
editor1.className = 'dark';
|
|
25
|
+
highlighted.className = 'dark';
|
|
26
|
+
caret.className = 'dark';
|
|
27
|
+
lineCounter.className = 'dark';
|
|
28
|
+
editor1.style.backgroundColor = isDark ? "#222" : "#fff";
|
|
29
|
+
let code = data.value || "";
|
|
30
|
+
let language = data.language;
|
|
31
|
+
let theme = data.theme;
|
|
32
|
+
if (!languages.registeredLanguages.includes(language)) {
|
|
33
|
+
const mod = await import(`https://esm.sh/@pfmcodes/highlight.js@1.0.0/es/languages/${language}.js`);
|
|
34
|
+
languages.registerLanguage(language, mod.default);
|
|
35
|
+
languages.registeredLanguages.push(language);
|
|
36
|
+
}
|
|
37
|
+
if (theme) {
|
|
38
|
+
let themeLink: HTMLLinkElement | null = document.getElementById("Caret-theme") as HTMLLinkElement;
|
|
39
|
+
if (!themeLink) {
|
|
40
|
+
const link = document.createElement("link");
|
|
41
|
+
link.rel = "stylesheet";
|
|
42
|
+
link.id = "Caret-theme";
|
|
43
|
+
link.href = `https://esm.sh/@pfmcodes/highlight.js@1.0.0/styles/${theme}.css`;
|
|
44
|
+
document.head.appendChild(link);
|
|
45
|
+
} else {
|
|
46
|
+
themeLink.href = `https://esm.sh/@pfmcodes/highlight.js@1.0.0/styles/${theme}.css`;
|
|
47
|
+
}
|
|
48
|
+
} else {
|
|
49
|
+
let themeLink: HTMLLinkElement | null = document.getElementById("Caret-theme") as HTMLLinkElement;
|
|
50
|
+
if (!themeLink) {
|
|
51
|
+
const link = document.createElement("link");
|
|
52
|
+
link.rel = "stylesheet";
|
|
53
|
+
link.id = "Caret-theme";
|
|
54
|
+
link.href = `https://esm.sh/@pfmcodes/highlight.js@1.0.0/styles/hybrid.css`;
|
|
55
|
+
document.head.appendChild(link);
|
|
56
|
+
} else {
|
|
57
|
+
themeLink.href = `./highlight.js/styles/hybrid.css`;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
editor1.spellcheck = false;
|
|
61
|
+
editor1.autocapitalize = "off";
|
|
62
|
+
editor1.autocomplete = "off";
|
|
63
|
+
editor1.autocorrect = "off" as any;
|
|
64
|
+
editor.style = "position: relative; width: 600px; height: 300px; overflow: hidden; /* 👈 CRITICAL */ font-size: 14px;"
|
|
65
|
+
if (code && editor && editor1 && language && highlighted) {
|
|
66
|
+
editor1.style.paddingTop = "-9px";
|
|
67
|
+
console.log(data.value + " data.value");
|
|
68
|
+
editor1.value = data.value as string;
|
|
69
|
+
highlighted.innerHTML = await _render(code, language, editor1);
|
|
70
|
+
}
|
|
71
|
+
const keyDown = async (e: KeyboardEvent) => {
|
|
72
|
+
if (e.key !== "Tab") return;
|
|
73
|
+
|
|
74
|
+
e.preventDefault();
|
|
75
|
+
|
|
76
|
+
const value = editor1.value;
|
|
77
|
+
const start = editor1.selectionStart;
|
|
78
|
+
const end = editor1.selectionEnd;
|
|
79
|
+
|
|
80
|
+
const indent = " ";
|
|
81
|
+
|
|
82
|
+
// Find line start & end
|
|
83
|
+
const lineStart = value.lastIndexOf("\n", start - 1) + 1;
|
|
84
|
+
const lineEnd = value.indexOf("\n", end);
|
|
85
|
+
const finalLineEnd = lineEnd === -1 ? value.length : lineEnd;
|
|
86
|
+
|
|
87
|
+
const block = value.slice(lineStart, finalLineEnd);
|
|
88
|
+
const lines = block.split("\n");
|
|
89
|
+
|
|
90
|
+
let newLines;
|
|
91
|
+
let delta = 0;
|
|
92
|
+
|
|
93
|
+
if (e.shiftKey) {
|
|
94
|
+
// UNINDENT
|
|
95
|
+
newLines = lines.map(line => {
|
|
96
|
+
if (line.startsWith(indent)) {
|
|
97
|
+
delta -= indent.length;
|
|
98
|
+
return line.slice(indent.length);
|
|
99
|
+
}
|
|
100
|
+
if (line.startsWith("\t")) {
|
|
101
|
+
delta -= 1;
|
|
102
|
+
return line.slice(1);
|
|
103
|
+
}
|
|
104
|
+
return line;
|
|
105
|
+
});
|
|
106
|
+
} else {
|
|
107
|
+
// INDENT
|
|
108
|
+
newLines = lines.map(line => indent + line);
|
|
109
|
+
delta = indent.length;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const newBlock = newLines.join("\n");
|
|
113
|
+
|
|
114
|
+
editor1.value =
|
|
115
|
+
value.slice(0, lineStart) +
|
|
116
|
+
newBlock +
|
|
117
|
+
value.slice(finalLineEnd);
|
|
118
|
+
|
|
119
|
+
// Fix selection
|
|
120
|
+
editor1.selectionStart = start + delta;
|
|
121
|
+
editor1.selectionEnd =
|
|
122
|
+
end + delta * newLines.length;
|
|
123
|
+
|
|
124
|
+
highlighted.innerHTML = await _render(editor1.value, language, editor1);
|
|
125
|
+
updateLineNumbers();
|
|
126
|
+
updateCaret();
|
|
127
|
+
}
|
|
128
|
+
editor1.addEventListener("keydown", keyDown);
|
|
129
|
+
editor.appendChild(lineCounter);
|
|
130
|
+
editor.appendChild(highlighted);
|
|
131
|
+
editor.appendChild(editor1);
|
|
132
|
+
editor.appendChild(caret);
|
|
133
|
+
|
|
134
|
+
function updateFontMetrics() {
|
|
135
|
+
const style = getComputedStyle(editor1);
|
|
136
|
+
measureCtx.font = `${style.fontSize} ${style.fontFamily}`;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function updateLineNumbers() {
|
|
140
|
+
const lineCount = editor1.value.split("\n").length;
|
|
141
|
+
|
|
142
|
+
let html = "";
|
|
143
|
+
for (let i = 1; i <= lineCount; i++) {
|
|
144
|
+
html += `<div class="Caret-lineCounter-number" style="color: ${lineColor}">${i}</div>`;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
lineCounter.innerHTML = html;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
highlighted.style.paddingTop = "12px"
|
|
151
|
+
|
|
152
|
+
function getFontMetrics() {
|
|
153
|
+
const metrics = measureCtx.measureText("Mg");
|
|
154
|
+
return {
|
|
155
|
+
ascent: metrics.actualBoundingBoxAscent,
|
|
156
|
+
descent: metrics.actualBoundingBoxDescent,
|
|
157
|
+
height: metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
const focus = () => {
|
|
161
|
+
caret.style.opacity = "1";
|
|
162
|
+
caret.style.background = caretColor;
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
editor1.addEventListener("focus", focus);
|
|
166
|
+
|
|
167
|
+
const blur = () => {
|
|
168
|
+
caret.style.opacity = "0";
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
editor1.addEventListener("blur", blur);
|
|
172
|
+
|
|
173
|
+
function updateCaret() {
|
|
174
|
+
const start = editor1.selectionStart;
|
|
175
|
+
const text = editor1.value.slice(0, start);
|
|
176
|
+
|
|
177
|
+
const lines = text.split("\n");
|
|
178
|
+
const lineIndex = lines.length - 1;
|
|
179
|
+
const lineText = lines[lineIndex].replace(/\t/g, " ");
|
|
180
|
+
|
|
181
|
+
const style = getComputedStyle(editor1);
|
|
182
|
+
const paddingLeft = parseFloat(style.paddingLeft);
|
|
183
|
+
const paddingTop = parseFloat(style.paddingTop);
|
|
184
|
+
const lineHeight = parseFloat(style.lineHeight);
|
|
185
|
+
|
|
186
|
+
updateFontMetrics();
|
|
187
|
+
const metrics = measureCtx.measureText("Mg");
|
|
188
|
+
const ascent = metrics.actualBoundingBoxAscent;
|
|
189
|
+
|
|
190
|
+
caret.style.left =
|
|
191
|
+
paddingLeft + measureCtx.measureText(lineText).width + "px";
|
|
192
|
+
caret.style.top =
|
|
193
|
+
-9 +
|
|
194
|
+
paddingTop +
|
|
195
|
+
lineIndex * lineHeight +
|
|
196
|
+
(lineHeight - ascent) +
|
|
197
|
+
"px";
|
|
198
|
+
|
|
199
|
+
caret.style.height = `${lineHeight - 5}px`;
|
|
200
|
+
}
|
|
201
|
+
const input = async () => {
|
|
202
|
+
caret.style.opacity = "1";
|
|
203
|
+
highlighted.innerHTML = await _render(editor1.value, language, editor1);
|
|
204
|
+
updateLineNumbers();
|
|
205
|
+
updateCaret();
|
|
206
|
+
};
|
|
207
|
+
editor1.addEventListener("input", input);
|
|
208
|
+
const scroll = async () => {
|
|
209
|
+
const x = -editor1.scrollLeft;
|
|
210
|
+
const y = -editor1.scrollTop;
|
|
211
|
+
highlighted.innerHTML = await _render(editor1.value, language, editor1);
|
|
212
|
+
highlighted.style.transform = `translate(${x}px, ${y}px)`;
|
|
213
|
+
caret.style.transform = `translate(${x}px, ${y}px)`;
|
|
214
|
+
lineCounter.style.transform = `translateY(${y}px)`;
|
|
215
|
+
};
|
|
216
|
+
editor1.addEventListener("scroll", scroll);
|
|
217
|
+
|
|
218
|
+
updateFontMetrics();
|
|
219
|
+
getFontMetrics();
|
|
220
|
+
|
|
221
|
+
editor1.addEventListener("click", updateCaret);
|
|
222
|
+
editor1.addEventListener("keyup", updateCaret);
|
|
223
|
+
|
|
224
|
+
// Initial caret position
|
|
225
|
+
updateLineNumbers();
|
|
226
|
+
updateCaret();
|
|
227
|
+
|
|
228
|
+
// Focus the editor
|
|
229
|
+
editor1.focus();
|
|
230
|
+
function destroy() {
|
|
231
|
+
editor1.removeEventListener('click', updateCaret);
|
|
232
|
+
editor1.removeEventListener('keyup', updateCaret);
|
|
233
|
+
editor1.removeEventListener('scroll', scroll);
|
|
234
|
+
editor1.removeEventListener('keydown', keyDown);
|
|
235
|
+
editor.innerHTML = "";
|
|
236
|
+
}
|
|
237
|
+
async function refresh() {
|
|
238
|
+
highlighted.innerHTML = await _render(editor1.value, language, editor1);
|
|
239
|
+
updateLineNumbers();
|
|
240
|
+
updateCaret();
|
|
241
|
+
}
|
|
242
|
+
function getValue() {
|
|
243
|
+
return editor1.value;
|
|
244
|
+
}
|
|
245
|
+
function setValue(i: string) {
|
|
246
|
+
editor1.value = i;
|
|
247
|
+
refresh();
|
|
248
|
+
}
|
|
249
|
+
async function setLanguage(l: string) {
|
|
250
|
+
if (!languages.registeredLanguages.includes(l)) {
|
|
251
|
+
if (l === "html" || l === "svg") {
|
|
252
|
+
language = "xml";
|
|
253
|
+
l = "xml";
|
|
254
|
+
}
|
|
255
|
+
const mod = await import(`https://esm.sh/@pfmcodes/highlight.js@1.0.0/es/languages/${l}.js`);
|
|
256
|
+
|
|
257
|
+
}
|
|
258
|
+
language = l;
|
|
259
|
+
refresh();
|
|
260
|
+
}
|
|
261
|
+
return {
|
|
262
|
+
getValue,
|
|
263
|
+
setValue,
|
|
264
|
+
focus,
|
|
265
|
+
setLanguage,
|
|
266
|
+
destroy
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
function escapeHtml(str: string) {
|
|
271
|
+
return str
|
|
272
|
+
.replace(/&/g, "&")
|
|
273
|
+
.replace(/</g, "<")
|
|
274
|
+
.replace(/>/g, ">");
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
async function _render(code: string, language: string, editor: HTMLElement) {
|
|
278
|
+
// If no editor context provided, just highlight everything (initial load)
|
|
279
|
+
if (!editor) {
|
|
280
|
+
return hljs.highlight(code, { language }).value;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
const scrollTop = editor.scrollTop;
|
|
284
|
+
const scrollBottom = scrollTop + editor.clientHeight;
|
|
285
|
+
const style = getComputedStyle(editor);
|
|
286
|
+
const lineHeight = parseFloat(style.lineHeight);
|
|
287
|
+
|
|
288
|
+
// Calculate visible line range
|
|
289
|
+
const startLine = Math.floor(scrollTop / lineHeight);
|
|
290
|
+
const endLine = Math.ceil(scrollBottom / lineHeight);
|
|
291
|
+
|
|
292
|
+
const lines = code.split("\n");
|
|
293
|
+
|
|
294
|
+
// Add buffer (render extra lines above/below for smooth scrolling)
|
|
295
|
+
const bufferLines = 10;
|
|
296
|
+
const visibleStart = Math.max(0, startLine - bufferLines) || 0;
|
|
297
|
+
const visibleEnd = Math.min(lines.length, endLine + bufferLines) || 0;
|
|
298
|
+
|
|
299
|
+
// Split into three sections
|
|
300
|
+
const beforeLines = lines.slice(0, visibleStart);
|
|
301
|
+
const visibleLines = lines.slice(visibleStart, visibleEnd);
|
|
302
|
+
const afterLines = lines.slice(visibleEnd);
|
|
303
|
+
|
|
304
|
+
// Only highlight visible portion
|
|
305
|
+
|
|
306
|
+
const highlightedVisible = hljs.highlight(visibleLines.join("\n"), { language }).value;
|
|
307
|
+
// Plain text for non-visible areas (no highlighting = faster)
|
|
308
|
+
if (highlightedVisible.trim() === "") {
|
|
309
|
+
return hljs.highlight(escapeHtml(code), { language }).value;
|
|
310
|
+
}
|
|
311
|
+
const beforeHTML = "\n".repeat(beforeLines.length);
|
|
312
|
+
const afterHTML = "\n".repeat(afterLines.length);
|
|
313
|
+
return beforeHTML + highlightedVisible + afterHTML;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
const editor = {
|
|
317
|
+
createEditor
|
|
318
|
+
};
|
|
319
|
+
|
|
320
|
+
export default editor;
|
|
321
|
+
|
|
322
|
+
/*
|
|
323
|
+
|
|
324
|
+
createEditor: creates the main editor, using html Elements like, textarea and etc.
|
|
325
|
+
refresh: refreshs the editor
|
|
326
|
+
getValue: return the current value from the editor
|
|
327
|
+
setValue: sets a certain value to the editor's value
|
|
328
|
+
focus: focusses the editor
|
|
329
|
+
destroy: destroys and removeEventListeners
|
|
330
|
+
updateCaret: updates the caret positon, height and other metrics using math
|
|
331
|
+
updateLineNumbers: just add new line numbers
|
|
332
|
+
getFontMetrics: returns back the font's metrics like height
|
|
333
|
+
updateFontMetrics: update the fontMetrics
|
|
334
|
+
*/
|
package/types/index.d.ts
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
declare module "@pfmcodes/caret" {
|
|
2
|
+
interface CaretEditorAPI {
|
|
3
|
+
createEditor(
|
|
4
|
+
el: HTMLElement,
|
|
5
|
+
data: any
|
|
6
|
+
): Promise<{
|
|
7
|
+
getValue(): string;
|
|
8
|
+
setValue(v: string): void;
|
|
9
|
+
focus(): void;
|
|
10
|
+
setLanguage(l: string): Promise<void>;
|
|
11
|
+
destroy(): void;
|
|
12
|
+
}>;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
interface CaretThemeApi {
|
|
16
|
+
setTheme(name: string): void;
|
|
17
|
+
removeTheme(name: string): void;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
interface CaretLanguageApi {
|
|
21
|
+
registeredLanguages: string[];
|
|
22
|
+
init(): void;
|
|
23
|
+
registerLanguage(name: string, definition: any): void;
|
|
24
|
+
hljs: any;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const Caret: {
|
|
28
|
+
editor: CaretEditorAPI;
|
|
29
|
+
theme: CaretThemeApi;
|
|
30
|
+
language: CaretLanguageApi;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export default Caret;
|
|
34
|
+
}
|
package/types/index.ts
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
// @ts-ignore
|
|
2
|
+
import javascript from "https://esm.sh/@pfmcodes/highlight.js@1.0.0/es/languages/javascript.js";
|
|
3
|
+
// @ts-ignore
|
|
4
|
+
import xml from "https://esm.sh/@pfmcodes/highlight.js@1.0.0/es/languages/xml.js";
|
|
5
|
+
// @ts-ignore
|
|
6
|
+
import css from "https://esm.sh/@pfmcodes/highlight.js@1.0.0/es/languages/css.js";
|
|
7
|
+
// @ts-ignore
|
|
8
|
+
import python from "https://esm.sh/@pfmcodes/highlight.js@1.0.0/es/languages/python.js";
|
|
9
|
+
// @ts-ignore
|
|
10
|
+
import java from "https://esm.sh/@pfmcodes/highlight.js@1.0.0/es/languages/java.js";
|
|
11
|
+
// @ts-ignore
|
|
12
|
+
import csharp from "https://esm.sh/@pfmcodes/highlight.js@1.0.0/es/languages/csharp.js";
|
|
13
|
+
// @ts-ignore
|
|
14
|
+
import cpp from "https://esm.sh/@pfmcodes/highlight.js@1.0.0/es/languages/cpp.js";
|
|
15
|
+
// @ts-ignore
|
|
16
|
+
import ruby from "https://esm.sh/@pfmcodes/highlight.js@1.0.0/es/languages/ruby.js";
|
|
17
|
+
// @ts-ignore
|
|
18
|
+
import php from "https://esm.sh/@pfmcodes/highlight.js@1.0.0/es/languages/php.js";
|
|
19
|
+
// @ts-ignore
|
|
20
|
+
import go from "https://esm.sh/@pfmcodes/highlight.js@1.0.0/es/languages/go.js";
|
|
21
|
+
// @ts-ignore
|
|
22
|
+
import c from "https://esm.sh/@pfmcodes/highlight.js@1.0.0/es/languages/c.js";
|
|
23
|
+
// @ts-ignore
|
|
24
|
+
import rust from "https://esm.sh/@pfmcodes/highlight.js@1.0.0/es/languages/rust.js";
|
|
25
|
+
// @ts-ignore
|
|
26
|
+
import kotlin from "https://esm.sh/@pfmcodes/highlight.js@1.0.0/es/languages/kotlin.js";
|
|
27
|
+
// @ts-ignore
|
|
28
|
+
import swift from "https://esm.sh/@pfmcodes/highlight.js@1.0.0/es/languages/swift.js";
|
|
29
|
+
// @ts-ignore
|
|
30
|
+
import typescript from "https://esm.sh/@pfmcodes/highlight.js@1.0.0/es/languages/typescript.js";
|
|
31
|
+
// @ts-ignore
|
|
32
|
+
import json from "https://esm.sh/@pfmcodes/highlight.js@1.0.0/es/languages/json.js";
|
|
33
|
+
// @ts-ignore
|
|
34
|
+
import bash from "https://esm.sh/@pfmcodes/highlight.js@1.0.0/es/languages/bash.js";
|
|
35
|
+
// @ts-ignore
|
|
36
|
+
import plaintext from "https://esm.sh/@pfmcodes/highlight.js@1.0.0/es/languages/plaintext.js";
|
|
37
|
+
// @ts-ignore
|
|
38
|
+
import hljs from "https://esm.sh/@pfmcodes/highlight.js@1.0.0/es/core.js";
|
|
39
|
+
|
|
40
|
+
let registeredLanguages: Array<T> = [];
|
|
41
|
+
type T = any
|
|
42
|
+
|
|
43
|
+
function init() {
|
|
44
|
+
// Register all languages
|
|
45
|
+
hljs.registerLanguage("javascript", javascript);
|
|
46
|
+
hljs.registerLanguage("xml", xml);
|
|
47
|
+
hljs.registerLanguage("css", css);
|
|
48
|
+
hljs.registerLanguage("html", xml);
|
|
49
|
+
hljs.registerLanguage("python", python);
|
|
50
|
+
hljs.registerLanguage("java", java);
|
|
51
|
+
hljs.registerLanguage("csharp", csharp);
|
|
52
|
+
hljs.registerLanguage("cpp", cpp);
|
|
53
|
+
hljs.registerLanguage("ruby", ruby);
|
|
54
|
+
hljs.registerLanguage("php", php);
|
|
55
|
+
hljs.registerLanguage("go", go);
|
|
56
|
+
hljs.registerLanguage("c", c);
|
|
57
|
+
hljs.registerLanguage("rust", rust);
|
|
58
|
+
hljs.registerLanguage("kotlin", kotlin);
|
|
59
|
+
hljs.registerLanguage("swift", swift);
|
|
60
|
+
hljs.registerLanguage("typescript", typescript);
|
|
61
|
+
hljs.registerLanguage("json", json);
|
|
62
|
+
hljs.registerLanguage("bash", bash);
|
|
63
|
+
hljs.registerLanguage("shell", bash);
|
|
64
|
+
hljs.registerLanguage("sh", bash);
|
|
65
|
+
hljs.registerLanguage("plaintext", plaintext);
|
|
66
|
+
registeredLanguages = [
|
|
67
|
+
"javascript",
|
|
68
|
+
"js",
|
|
69
|
+
"xml",
|
|
70
|
+
"html",
|
|
71
|
+
"svg",
|
|
72
|
+
"python",
|
|
73
|
+
"java",
|
|
74
|
+
"csharp",
|
|
75
|
+
"cpp",
|
|
76
|
+
"ruby",
|
|
77
|
+
"php",
|
|
78
|
+
"go",
|
|
79
|
+
"c",
|
|
80
|
+
"rust",
|
|
81
|
+
"kotlin",
|
|
82
|
+
"swift",
|
|
83
|
+
"typescript",
|
|
84
|
+
"json",
|
|
85
|
+
"bash",
|
|
86
|
+
"shell",
|
|
87
|
+
"sh",
|
|
88
|
+
"plaintext"
|
|
89
|
+
]
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function registerLanguage(name: string, definition: any) {
|
|
93
|
+
hljs.registerLanguage(name, definition);
|
|
94
|
+
if (!registeredLanguages.includes(name)) {
|
|
95
|
+
registeredLanguages.push(name);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const languages = {
|
|
100
|
+
init,
|
|
101
|
+
registeredLanguages,
|
|
102
|
+
registerLanguage,
|
|
103
|
+
hljs
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export default languages;
|
|
107
|
+
|
|
108
|
+
/*
|
|
109
|
+
|
|
110
|
+
registeredLannguage: added for the editor.js can check if the langauge provided already is regsitered or not
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
init: just registers some languages and updates the registeredLangauges variable
|
|
114
|
+
|
|
115
|
+
registerLanguage: just registers a language
|
|
116
|
+
|
|
117
|
+
*/
|
package/types/theme.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
function setTheme(name: string) {
|
|
2
|
+
const link = document.getElementById("Caret-theme") as HTMLLinkElement;
|
|
3
|
+
link.href = `./highlight.js/styles/${name}.css`;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
function removeTheme() {
|
|
7
|
+
const link = document.getElementById("Caret-theme") as HTMLLinkElement;
|
|
8
|
+
if (link && link.parentNode) {
|
|
9
|
+
link.parentNode.removeChild(link);
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const theme = {
|
|
14
|
+
removeTheme,
|
|
15
|
+
setTheme
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export default theme;
|