@pfmcodes/caret 0.1.1 → 0.1.3

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 CHANGED
@@ -1,16 +1,16 @@
1
1
  # Caret
2
2
 
3
- [![License: MIT](https://img.shields.io/badge/License-MIT-lightblue.svg)](https://opensource.org/licenses/MIT)
4
- [![JavaScript](https://img.shields.io/badge/JavaScript-64.0%25-yellow)](https://github.com/PFMCODES/caret)
5
- [![CSS](https://img.shields.io/badge/CSS-18.0%25-blue)](https://github.com/PFMCODES/caret)
6
- [![SCSS](https://img.shields.io/badge/SCSS-18.0%25-pink)](https://github.com/PFMCODES/caret)
3
+ [![License: MIT](https://img.shields.io/badge/License-MIT-4000ff.svg)](https://opensource.org/licenses/MIT)
4
+ [![JavaScript](https://img.shields.io/badge/JavaScript-64.0%25-f6fa03)](https://github.com/PFMCODES/lexius-edior)
5
+ [![CSS](https://img.shields.io/badge/CSS-18.0%25-2e7ad1)](https://github.com/pfmcodes/lexius-editor)
6
+ [![SCSS](https://img.shields.io/badge/SCSS-18.0%25-f8899d)](https://github.com/pfmcodes/lexius-editor)
7
7
 
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.
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
12
  - 🎨 **Live Syntax Highlighting** - Real-time code highlighting powered by Highlight.js
13
- - 🖱️ **Custom Caret** - Smooth, pixel-perfect caret positioning and rendering
13
+ - 🖱️ **Custom Caret** - Smooth, pixel-perfect Caret positioning and rendering
14
14
  - 🔢 **Line Numbers** - Built-in line counter with dynamic updates
15
15
  - ⌨️ **Smart Indentation** - Tab/Shift+Tab support for indenting/unindenting code blocks
16
16
  - 🎭 **Theme Support** - Multiple syntax highlighting themes (light/dark modes)
@@ -34,19 +34,19 @@ A lightweight, feature-rich code editor with real-time syntax highlighting and c
34
34
  ### NPM
35
35
 
36
36
  ```bash
37
- npm install caret
37
+ npm install @pfmcodes/caret
38
38
  ```
39
39
 
40
40
  ### Yarn
41
41
 
42
42
  ```bash
43
- yarn add caret
43
+ yarn add @pfmcodes/caret
44
44
  ```
45
45
 
46
46
  ### PNPM
47
47
 
48
48
  ```bash
49
- pnpm add caret
49
+ pnpm add @pfmcodes/caret
50
50
  ```
51
51
 
52
52
  ## 🏁 Quick Start
@@ -66,7 +66,7 @@ pnpm add caret
66
66
  <div id="editor"></div>
67
67
 
68
68
  <script type="module">
69
- import editor from './node_modules/caret/esm/index.js';
69
+ import editor from './node_modules/@pfmcodes/caret/esm/index.js';
70
70
 
71
71
  const instance = await editor.createEditor(
72
72
  document.getElementById('editor'),
@@ -84,7 +84,7 @@ pnpm add caret
84
84
  ### ES Module Import
85
85
 
86
86
  ```javascript
87
- import editor from 'caret/esm';
87
+ import editor from '@pfmcodes/caret';
88
88
 
89
89
  // Create editor instance
90
90
  const editorInstance = await editor.createEditor(
@@ -116,7 +116,7 @@ caret/
116
116
  ### JavaScript Editor
117
117
 
118
118
  ```javascript
119
- import editor from 'caret/esm';
119
+ import editor from '@pfmcodes/caret';
120
120
 
121
121
  const jsEditor = await editor.createEditor(
122
122
  document.getElementById('js-editor'),
@@ -193,7 +193,7 @@ The editor comes with default styles that you can override:
193
193
  line-height: 1.6;
194
194
  }
195
195
 
196
- /* Customize the caret */
196
+ /* Customize the Caret */
197
197
  #Caret-caret {
198
198
  background: #00ff00 !important;
199
199
  width: 3px !important;
@@ -244,7 +244,7 @@ editorInstance.setLanguage('python');
244
244
  The editor automatically:
245
245
  - Updates syntax highlighting as you type
246
246
  - Adjusts line numbers dynamically
247
- - Maintains caret position accurately
247
+ - Maintains Caret position accurately
248
248
  - Synchronizes all visual components
249
249
 
250
250
  ### Configuration Options
@@ -329,7 +329,7 @@ Line numbers are automatically generated and synchronized with your code.
329
329
  - **Shift + Tab** - Unindent selected lines
330
330
 
331
331
  #### Custom Caret
332
- The editor features a custom-rendered caret that adapts to your theme (light/dark).
332
+ The editor features a custom-rendered Caret that adapts to your theme (light/dark).
333
333
 
334
334
  #### Synchronized Scrolling
335
335
  All editor components (code, highlights, line numbers) scroll together smoothly.
@@ -460,7 +460,7 @@ Caret uses a clever layering technique:
460
460
 
461
461
  1. **Textarea Layer** - Handles user input and cursor management
462
462
  2. **Pre/Code Layer** - Displays syntax-highlighted code (overlay)
463
- 3. **Custom Caret** - Renders a styled caret in the correct position
463
+ 3. **Custom Caret** - Renders a styled Caret in the correct position
464
464
  4. **Line Numbers** - Dynamically generated and synchronized
465
465
 
466
466
  The editor synchronizes all layers during:
@@ -494,10 +494,10 @@ Contributions are welcome! Please follow these steps:
494
494
 
495
495
  ```bash
496
496
  # Clone the repository
497
- git clone https://github.com/PFMCODES/caret.git
497
+ git clone https://github.com/pfmcodes/lexius-editor.git
498
498
 
499
499
  # Navigate to the directory
500
- cd caret
500
+ cd lexius-editor
501
501
 
502
502
  # Install dependencies
503
503
  npm install
@@ -521,13 +521,13 @@ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file
521
521
 
522
522
  ## 📞 Support
523
523
 
524
- - **Issues**: [GitHub Issues](https://github.com/PFMCODES/caret/issues)
525
- - **Discussions**: [GitHub Discussions](https://github.com/PFMCODES/caret/discussions)
524
+ - **Issues**: [GitHub Issues](https://github.com/pfmcodes/lexius-editor/issues)
525
+ - **Discussions**: [GitHub Discussions](https://github.com/pfmcodes/lexius-editor/discussions)
526
526
 
527
527
  ## 🔗 Links
528
528
 
529
- - [GitHub Repository](https://github.com/PFMCODES/caret)
530
- - [NPM Package](https://www.npmjs.com/package/caret) *(if published)*
529
+ - [GitHub Repository](https://github.com/pfmcodes/lexius-editor)
530
+ - [NPM Package](https://www.npmjs.com/package/@pfmcodes/caret) *(if published)*
531
531
 
532
532
  ---
533
533
 
@@ -0,0 +1,280 @@
1
+ const hljs = require("../highlight.js/es/core.js"); // Use default export
2
+ const languages = require("./languages.js");
3
+
4
+ languages.init();
5
+
6
+ async function createEditor(editor, data) {
7
+ const editor1 = document.createElement("textarea");
8
+ const highlighted = document.createElement("pre");
9
+ const caret = document.createElement("div");
10
+ const measureCanvas = document.createElement("canvas");
11
+ const measureCtx = measureCanvas.getContext("2d");
12
+ const isDark = data.theme && (data.theme.includes("dark") || data.theme.includes("night"));
13
+ const caretColor = isDark ? "#fff" : "#7116d8";
14
+ const lineColor = isDark ? "#fff" : "#000";
15
+ const lineCounter = document.createElement("div");
16
+
17
+ editor1.id = "Caret-textarea";
18
+ highlighted.id = "Caret-highlighted";
19
+ caret.id = "Caret-caret";
20
+ lineCounter.id = "Caret-lineCounter";
21
+ editor1.style.backgroundColor = isDark ? "#222" : "#fff";
22
+ let code = data.value || "";
23
+ let language = data.language;
24
+ let theme = data.theme;
25
+ if (!languages.registeredLanguages.includes(language)) {
26
+ const mod = await import(`../highlight.js/es/languages/${language}.js`);
27
+ languages.registerLanguage(language, mod.default);
28
+ languages.registeredLanguages.push(language);
29
+ }
30
+ if (theme) {
31
+ let themeLink = document.getElementById("Caret-theme")
32
+ if (!themeLink) {
33
+ const link = document.createElement("link");
34
+ link.rel = "stylesheet";
35
+ link.id = "Caret-theme";
36
+ link.href = `./highlight.js/styles/${theme}.css`;
37
+ document.head.appendChild(link);
38
+ } else {
39
+ themeLink.href = `./highlight.js/styles/${theme}.css`;
40
+ }
41
+ } else {
42
+ let themeLink = document.getElementById("Caret-theme");
43
+ if (!themeLink) {
44
+ const link = document.createElement("link");
45
+ link.rel = "stylesheet";
46
+ link.id = "Caret-theme";
47
+ link.href = `./highlight.js/styles/hybrid.css`;
48
+ document.head.appendChild(link);
49
+ } else {
50
+ themeLink.href = `./highlight.js/styles/hybrid.css`;
51
+ }
52
+ }
53
+ editor1.spellcheck = false;
54
+ editor1.autocapitalize = "off";
55
+ editor1.autocomplete = "off";
56
+ editor1.autocorrect = "off";
57
+ editor.style = "position: relative; width: 600px; height: 300px; overflow: hidden; /* 👈 CRITICAL */ font-size: 14px;"
58
+ if (code) {
59
+ editor1.value = code;
60
+ editor1.style.paddingTop = "-9px";
61
+ highlighted.innerHTML = hljs.highlight(code, { language: language }).value;
62
+ }
63
+ const keyDown = (e) => {
64
+ if (e.key !== "Tab") return;
65
+
66
+ e.preventDefault();
67
+
68
+ const value = editor1.value;
69
+ const start = editor1.selectionStart;
70
+ const end = editor1.selectionEnd;
71
+
72
+ const indent = " ";
73
+
74
+ // Find line start & end
75
+ const lineStart = value.lastIndexOf("\n", start - 1) + 1;
76
+ const lineEnd = value.indexOf("\n", end);
77
+ const finalLineEnd = lineEnd === -1 ? value.length : lineEnd;
78
+
79
+ const block = value.slice(lineStart, finalLineEnd);
80
+ const lines = block.split("\n");
81
+
82
+ let newLines;
83
+ let delta = 0;
84
+
85
+ if (e.shiftKey) {
86
+ // UNINDENT
87
+ newLines = lines.map(line => {
88
+ if (line.startsWith(indent)) {
89
+ delta -= indent.length;
90
+ return line.slice(indent.length);
91
+ }
92
+ if (line.startsWith("\t")) {
93
+ delta -= 1;
94
+ return line.slice(1);
95
+ }
96
+ return line;
97
+ });
98
+ } else {
99
+ // INDENT
100
+ newLines = lines.map(line => indent + line);
101
+ delta = indent.length;
102
+ }
103
+
104
+ const newBlock = newLines.join("\n");
105
+
106
+ editor1.value =
107
+ value.slice(0, lineStart) +
108
+ newBlock +
109
+ value.slice(finalLineEnd);
110
+
111
+ // Fix selection
112
+ editor1.selectionStart = start + delta;
113
+ editor1.selectionEnd =
114
+ end + delta * newLines.length;
115
+
116
+ highlighted.innerHTML = hljs.highlight(editor1.value, { language }).value;
117
+ updateLineNumbers();
118
+ updateCaret();
119
+ }
120
+ editor1.addEventListener("keydown", keyDown);
121
+ editor.appendChild(lineCounter);
122
+ editor.appendChild(highlighted);
123
+ editor.appendChild(editor1);
124
+ editor.appendChild(caret);
125
+
126
+ function updateFontMetrics() {
127
+ const style = getComputedStyle(editor1);
128
+ measureCtx.font = `${style.fontSize} ${style.fontFamily}`;
129
+ }
130
+
131
+ function updateLineNumbers() {
132
+ const lineCount = editor1.value.split("\n").length;
133
+
134
+ let html = "";
135
+ for (let i = 1; i <= lineCount; i++) {
136
+ html += `<div class="Caret-lineCounter-number" style="color: ${lineColor}">${i}</div>`;
137
+ }
138
+
139
+ lineCounter.innerHTML = html;
140
+ }
141
+
142
+
143
+ function getFontMetrics() {
144
+ const metrics = measureCtx.measureText("Mg");
145
+ return {
146
+ ascent: metrics.actualBoundingBoxAscent,
147
+ descent: metrics.actualBoundingBoxDescent,
148
+ height: metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent
149
+ };
150
+ }
151
+ const focus = () => {
152
+ caret.style.opacity = "1";
153
+ caret.style.background = caretColor;
154
+ };
155
+
156
+ editor1.addEventListener("focus", focus);
157
+
158
+ const blur = () => {
159
+ caret.style.opacity = "0";
160
+ };
161
+
162
+ editor1.addEventListener("blur", blur);
163
+
164
+ function updateCaret() {
165
+ const start = editor1.selectionStart;
166
+ const text = editor1.value.slice(0, start);
167
+
168
+ const lines = text.split("\n");
169
+ const lineIndex = lines.length - 1;
170
+ const lineText = lines[lineIndex].replace(/\t/g, " ");
171
+
172
+ const style = getComputedStyle(editor1);
173
+ const paddingLeft = parseFloat(style.paddingLeft);
174
+ const paddingTop = parseFloat(style.paddingTop);
175
+ const lineHeight = parseFloat(style.lineHeight);
176
+
177
+ updateFontMetrics();
178
+ const metrics = measureCtx.measureText("Mg");
179
+ const ascent = metrics.actualBoundingBoxAscent;
180
+
181
+ caret.style.left =
182
+ paddingLeft + measureCtx.measureText(lineText).width + "px";
183
+ caret.style.top =
184
+ -9 +
185
+ paddingTop +
186
+ lineIndex * lineHeight +
187
+ (lineHeight - ascent) +
188
+ "px";
189
+
190
+ caret.style.height = `${lineHeight}px`;
191
+ }
192
+ const input = () => {
193
+ caret.style.opacity = "1";
194
+ highlighted.innerHTML = hljs.highlight(editor1.value, { language: language }).value;
195
+ updateLineNumbers();
196
+ updateCaret();
197
+ };
198
+ editor1.addEventListener("input", input);
199
+ const scroll = () => {
200
+ const x = -editor1.scrollLeft;
201
+ const y = -editor1.scrollTop;
202
+
203
+ highlighted.style.transform = `translate(${x}px, ${y}px)`;
204
+ caret.style.transform = `translate(${x}px, ${y}px)`;
205
+ lineCounter.style.transform = `translateY(${y}px)`;
206
+ };
207
+ editor1.addEventListener("scroll", scroll);
208
+
209
+ updateFontMetrics();
210
+ getFontMetrics();
211
+
212
+ editor1.addEventListener("click", updateCaret);
213
+ editor1.addEventListener("keyup", updateCaret);
214
+
215
+ // Initial caret position
216
+ updateLineNumbers();
217
+ updateCaret();
218
+
219
+ // Focus the editor
220
+ editor1.focus();
221
+ function destroy() {
222
+ editor1.removeEventListener('click', updateCaret);
223
+ editor1.removeEventListener('keyup', updateCaret);
224
+ editor1.removeEventListener('scroll', scroll);
225
+ editor1.removeEventListener('keydown', keyDown);
226
+ editor.innerHTML = "";
227
+ }
228
+ function refresh() {
229
+ highlighted.innerHTML = hljs.highlight(editor1.value, { language }).value;
230
+ updateLineNumbers();
231
+ updateCaret();
232
+ }
233
+ function getValue() {
234
+ return editor1.value;
235
+ }
236
+ function setValue(i) {
237
+ editor1.value = i;
238
+ refresh();
239
+ }
240
+ async function setLanguage(l) {
241
+ if (!languages.registeredLanguages.includes(l)) {
242
+ if (l === "html" || l === "svg") {
243
+ language = "xml";
244
+ l = "xml";
245
+ }
246
+ const mod = await import(`../highlight.js/es/languages/${l}.js`);
247
+
248
+ }
249
+ language = l;
250
+ refresh();
251
+ }
252
+ return {
253
+ getValue,
254
+ setValue,
255
+ focus,
256
+ setLanguage,
257
+ destroy
258
+ };
259
+ }
260
+
261
+ const editor = {
262
+ createEditor
263
+ };
264
+
265
+ module.exports = editor;
266
+
267
+ /*
268
+
269
+ createEditor: creates the main editor, using html Elements like, textarea and etc.
270
+ refresh: refreshs the editor
271
+ getValue: return the current value from the editor
272
+ setValue: sets a certain value to the editor's value
273
+ focus: focusses the editor
274
+ destroy: destroys and removeEventListeners
275
+ updateCaret: updates the caret positon, height and other metrics using math
276
+ updateLineNumbers: just add new line numbers
277
+ getFontMetrics: returns back the font's metrics like height
278
+ updateFontMetrics: update the fontMetrics
279
+
280
+ */
@@ -0,0 +1,10 @@
1
+ const editor = require("./editor.js");
2
+ const theme = require("./theme.js");
3
+ const language = require("./languages.js");
4
+
5
+ const Caret = {
6
+ editor,
7
+ theme,
8
+ language
9
+ }
10
+ module.exports = Caret;
@@ -0,0 +1,97 @@
1
+ const javascript = require("../highlight.js/es/languages/javascript.js");
2
+ const xml = require("../highlight.js/es/languages/xml.js");
3
+ const css = require("../highlight.js/es/languages/css.js");
4
+ const python = require("../highlight.js/es/languages/python.js");
5
+ const java = require("../highlight.js/es/languages/java.js");
6
+ const csharp = require("../highlight.js/es/languages/csharp.js");
7
+ const cpp = require("../highlight.js/es/languages/cpp.js");
8
+ const ruby = require("../highlight.js/es/languages/ruby.js");
9
+ const php = require("../highlight.js/es/languages/php.js");
10
+ const go = require("../highlight.js/es/languages/go.js");
11
+ const c = require("../highlight.js/es/languages/c.js");
12
+ const rust = require("../highlight.js/es/languages/rust.js");
13
+ const kotlin = require("../highlight.js/es/languages/kotlin.js");
14
+ const swift = require("../highlight.js/es/languages/swift.js");
15
+ const typescript = require("../highlight.js/es/languages/typescript.js");
16
+ const json = require("../highlight.js/es/languages/json.js");
17
+ const bash = require("../highlight.js/es/languages/bash.js");
18
+ const plaintext = require("../highlight.js/es/languages/plaintext.js");
19
+ const hljs = require("../highlight.js/es/core.js");
20
+
21
+ let registeredLanguages = [];
22
+
23
+ function init() {
24
+ // Register all languages
25
+ hljs.registerLanguage("javascript", javascript);
26
+ hljs.registerLanguage("xml", xml);
27
+ hljs.registerLanguage("css", css);
28
+ hljs.registerLanguage("html", xml);
29
+ hljs.registerLanguage("python", python);
30
+ hljs.registerLanguage("java", java);
31
+ hljs.registerLanguage("csharp", csharp);
32
+ hljs.registerLanguage("cpp", cpp);
33
+ hljs.registerLanguage("ruby", ruby);
34
+ hljs.registerLanguage("php", php);
35
+ hljs.registerLanguage("go", go);
36
+ hljs.registerLanguage("c", c);
37
+ hljs.registerLanguage("rust", rust);
38
+ hljs.registerLanguage("kotlin", kotlin);
39
+ hljs.registerLanguage("swift", swift);
40
+ hljs.registerLanguage("typescript", typescript);
41
+ hljs.registerLanguage("json", json);
42
+ hljs.registerLanguage("bash", bash);
43
+ hljs.registerLanguage("shell", bash);
44
+ hljs.registerLanguage("sh", bash);
45
+ hljs.registerLanguage("plaintext", plaintext);
46
+ registeredLanguages = [
47
+ "javascript",
48
+ "js",
49
+ "xml",
50
+ "html",
51
+ "svg",
52
+ "python",
53
+ "java",
54
+ "csharp",
55
+ "cpp",
56
+ "ruby",
57
+ "php",
58
+ "go",
59
+ "c",
60
+ "rust",
61
+ "kotlin",
62
+ "swift",
63
+ "typescript",
64
+ "json",
65
+ "bash",
66
+ "shell",
67
+ "sh",
68
+ "plaintext"
69
+ ]
70
+ }
71
+
72
+ function registerLanguage(name, definition) {
73
+ hljs.registerLanguage(name, definition);
74
+ if (!registeredLanguages.includes(name)) {
75
+ registeredLanguages.push(name);
76
+ }
77
+ }
78
+
79
+ const languages = {
80
+ init,
81
+ registeredLanguages,
82
+ registerLanguage,
83
+ hljs
84
+ }
85
+
86
+ module.exports = languages;
87
+
88
+ /*
89
+
90
+ registeredLannguage: added for the editor.js can check if the langauge provided already is regsitered or not
91
+
92
+
93
+ init: just registers some languages and updates the registeredLangauges variable
94
+
95
+ registerLanguage: just registers a language
96
+
97
+ */
@@ -0,0 +1,18 @@
1
+ function setTheme(name) {
2
+ const link = document.getElementById("Caret-theme");
3
+ link.href = `./highlight.js/styles/${name}.css`;
4
+ }
5
+
6
+ function removeTheme() {
7
+ const link = document.getElementById("Caret-theme");
8
+ if (link) {
9
+ link.parentNode.removeChild(link);
10
+ }
11
+ }
12
+
13
+ const theme = {
14
+ removeTheme,
15
+ setTheme
16
+ }
17
+
18
+ module.exports = theme;