@pfmcodes/caret 0.2.9 → 0.3.1
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 +485 -379
- package/components/caret.js +95 -0
- package/components/font.js +16 -0
- package/components/lineCounter.js +91 -0
- package/components/textEditor.js +503 -0
- package/index.js +4 -19
- package/package.json +3 -13
- package/utilities.js +32 -0
- package/editor.js +0 -470
- package/index.css +0 -110
- package/theme.js +0 -14
- package/types/editor.ts +0 -481
- package/types/index.d.ts +0 -46
- package/types/index.ts +0 -22
- package/types/langauges.ts +0 -116
- package/types/theme.ts +0 -14
- /package/{langauges.js → components/languages.js} +0 -0
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* caret.js - Custom caret for EditContext based editors
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* createCaret {
|
|
7
|
+
* @param {HTMLElement} parent - the editor container
|
|
8
|
+
* @param {HTMLElement} main - the editor div
|
|
9
|
+
* @param {Object} options {
|
|
10
|
+
* @param {string} caretColor - caret color
|
|
11
|
+
* @param {number} caretWidth - caret width in px, default 2
|
|
12
|
+
* }
|
|
13
|
+
* @returns {{ update: (selStart, main) => void, show: () => void, hide: () => void, destroy: () => void }}
|
|
14
|
+
* }
|
|
15
|
+
*/
|
|
16
|
+
function createCaret(parent, main, options = {}) {
|
|
17
|
+
const color = options.caretColor || options.focusColor || "#fff";
|
|
18
|
+
const width = options.caretWidth || 2;
|
|
19
|
+
|
|
20
|
+
const caretEl = document.createElement("div");
|
|
21
|
+
caretEl.className = "Caret-caret-" + options.id;
|
|
22
|
+
caretEl.style.position = "absolute";
|
|
23
|
+
caretEl.style.width = `${width}px`;
|
|
24
|
+
caretEl.style.background = color;
|
|
25
|
+
caretEl.style.pointerEvents = "none";
|
|
26
|
+
caretEl.style.zIndex = "10";
|
|
27
|
+
caretEl.style.opacity = "0";
|
|
28
|
+
caretEl.style.borderRadius = "1px";
|
|
29
|
+
caretEl.style.animation = "caret-blink 1s step-end infinite";
|
|
30
|
+
|
|
31
|
+
if (!document.getElementById("caret-blink-style")) {
|
|
32
|
+
const style = document.createElement("style");
|
|
33
|
+
style.id = "caret-blink-style";
|
|
34
|
+
style.textContent = `@keyframes caret-blink { 0%,100%{opacity:1} 50%{opacity:0} }`;
|
|
35
|
+
document.head.appendChild(style);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
parent.appendChild(caretEl);
|
|
39
|
+
|
|
40
|
+
function update(selStart) {
|
|
41
|
+
// walk text nodes to find exact position
|
|
42
|
+
let remaining = selStart;
|
|
43
|
+
let targetNode = null;
|
|
44
|
+
let targetOffset = 0;
|
|
45
|
+
|
|
46
|
+
const walker = document.createTreeWalker(main, NodeFilter.SHOW_TEXT);
|
|
47
|
+
let node;
|
|
48
|
+
while ((node = walker.nextNode())) {
|
|
49
|
+
if (remaining <= node.textContent.length) {
|
|
50
|
+
targetNode = node;
|
|
51
|
+
targetOffset = remaining;
|
|
52
|
+
break;
|
|
53
|
+
}
|
|
54
|
+
remaining -= node.textContent.length;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (!targetNode) {
|
|
58
|
+
caretEl.style.left = "5px";
|
|
59
|
+
caretEl.style.top = "5px";
|
|
60
|
+
caretEl.style.height = "21px";
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const range = document.createRange();
|
|
65
|
+
range.setStart(targetNode, targetOffset);
|
|
66
|
+
range.collapse(true);
|
|
67
|
+
|
|
68
|
+
const rect = range.getBoundingClientRect();
|
|
69
|
+
const parentRect = parent.getBoundingClientRect();
|
|
70
|
+
|
|
71
|
+
if (rect.width === 0 && rect.height === 0) return;
|
|
72
|
+
|
|
73
|
+
caretEl.style.left = rect.left - parentRect.left + parent.scrollLeft + "px";
|
|
74
|
+
caretEl.style.top = rect.top - parentRect.top + parent.scrollTop + "px";
|
|
75
|
+
caretEl.style.height = (rect.height || 21) + "px";
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function show() {
|
|
79
|
+
caretEl.style.opacity = "1";
|
|
80
|
+
caretEl.style.animation = "caret-blink 1s step-end infinite";
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function hide() {
|
|
84
|
+
caretEl.style.opacity = "0";
|
|
85
|
+
caretEl.style.animation = "none";
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function destroy() {
|
|
89
|
+
caretEl.remove();
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return { update, show, hide, destroy };
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export { createCaret };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* loadFont {
|
|
3
|
+
* @param {string} name - name of the font
|
|
4
|
+
* @param {string/url} url - url to external font
|
|
5
|
+
* @returns {void}
|
|
6
|
+
* }
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
// load the font dynamically
|
|
10
|
+
async function loadFont(name, url) {
|
|
11
|
+
const font = new FontFace(name, `url("${url}")`);
|
|
12
|
+
await font.load();
|
|
13
|
+
document.fonts.add(font);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export { loadFont }
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* createLineCounter {
|
|
3
|
+
* @param {HTMLElement} parent - the parent element the line counter goes inside of
|
|
4
|
+
* @param {number} lines - number of lines in the code
|
|
5
|
+
* @param {string/number} id - id for sepration and distinguishtion of multiple instances
|
|
6
|
+
* @param {object} options {
|
|
7
|
+
* @param {string/color} focusColor - border color of the editor when its in use
|
|
8
|
+
* @param {string/color} background - background color of the line counter
|
|
9
|
+
* @param {boolean} dark - if the user has dark theme enabled or not
|
|
10
|
+
* @param {object} theme {
|
|
11
|
+
* @param {object} dark {
|
|
12
|
+
* @param {string/color} background - background color for the dark theme
|
|
13
|
+
* }
|
|
14
|
+
* @param {object} light {
|
|
15
|
+
* @param {string/color} background - background color for the light theme
|
|
16
|
+
* }
|
|
17
|
+
* }
|
|
18
|
+
* @param {object} font {
|
|
19
|
+
* @param {string} url - external font url or file path
|
|
20
|
+
* @param {string} name - font name, required for both internal and external custom font application
|
|
21
|
+
* }
|
|
22
|
+
* }
|
|
23
|
+
* }
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
import { loadFont } from "./font.js";
|
|
27
|
+
|
|
28
|
+
async function createLineCounter(parent, lines, id, options) {
|
|
29
|
+
let fontUrl;
|
|
30
|
+
let fontName;
|
|
31
|
+
const font = options.font || {};
|
|
32
|
+
if (!font.url && !font.name) {
|
|
33
|
+
fontName = "monospace";
|
|
34
|
+
parent.style.fontFamily = fontName;
|
|
35
|
+
}
|
|
36
|
+
else if (!font.url && font.name) {
|
|
37
|
+
parent.style.fontFamily = font.name;
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
fontUrl = font.url;
|
|
41
|
+
fontName = font.name;
|
|
42
|
+
loadFont(fontName, fontUrl);
|
|
43
|
+
parent.style.fontFamily = fontName;
|
|
44
|
+
}
|
|
45
|
+
const lineCounter = document.createElement("div");
|
|
46
|
+
lineCounter.className = "lineCounter";
|
|
47
|
+
lineCounter.id = `lineCounter-${id}`;
|
|
48
|
+
const dark = options.dark || false;
|
|
49
|
+
const theme = options.theme || {};
|
|
50
|
+
lineCounter.style.height = "auto";
|
|
51
|
+
lineCounter.style.fontSize = "14px";
|
|
52
|
+
lineCounter.style.lineHeight = "1.5";
|
|
53
|
+
lineCounter.style.minWidth = "25px";
|
|
54
|
+
lineCounter.style.top = "0px";
|
|
55
|
+
lineCounter.style.borderRight = options.focusColor || "#fff";
|
|
56
|
+
if (Object.keys(theme).length === 0) {
|
|
57
|
+
lineCounter.style.color = dark ? "#fff" : "#111";
|
|
58
|
+
lineCounter.style.background = dark ? "#1e1e1e" : "#fff";
|
|
59
|
+
parent.style.background = dark ? "#1e1e1e" : "#fff";
|
|
60
|
+
} else {
|
|
61
|
+
lineCounter.style.color = dark ? theme.dark["color.lineCounter"] : theme.light["color.lineCounter"];
|
|
62
|
+
lineCounter.style.background = dark ? theme.dark["background.lineCounter"] : theme.light["background.lineCounter"];
|
|
63
|
+
parent.style.background = dark ? theme.dark["background.lineCounter"] : theme.light["background.lineCounter"];
|
|
64
|
+
}
|
|
65
|
+
for (let i = 0; i < lines; i++) {
|
|
66
|
+
const lineNumber = document.createElement("div");
|
|
67
|
+
lineNumber.className = "line-number";
|
|
68
|
+
lineNumber.id = `line-number-${i}-${id}`;
|
|
69
|
+
lineNumber.innerText = i + 1;
|
|
70
|
+
lineCounter.appendChild(lineNumber);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
parent.appendChild(lineCounter);
|
|
74
|
+
return lineCounter; // 👈 return so you can update it later
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function updateLineCounter(lineCounter, lines) {
|
|
78
|
+
lineCounter.innerHTML = "";
|
|
79
|
+
for (let i = 0; i < lines; i++) {
|
|
80
|
+
const lineNumber = document.createElement("div");
|
|
81
|
+
lineNumber.className = "line-number";
|
|
82
|
+
lineNumber.innerText = i + 1;
|
|
83
|
+
lineCounter.appendChild(lineNumber);
|
|
84
|
+
lineNumber.style.height = "calc(14px * 1.5)"; // font-size * line-height
|
|
85
|
+
lineNumber.style.display = "flex";
|
|
86
|
+
lineNumber.style.alignItems = "center";
|
|
87
|
+
lineNumber.style.margin = "auto";
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export { createLineCounter, updateLineCounter };
|