@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.
@@ -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 };