add line numbers to code editor
this is the sort of fancy stuff we can do now
This commit is contained in:
parent
09a81ec032
commit
92e3b8fcb7
|
@ -11,6 +11,9 @@
|
||||||
--color-shaded-background: rgba(0, 0, 0, 5%);
|
--color-shaded-background: rgba(0, 0, 0, 5%);
|
||||||
|
|
||||||
--dialog-backdrop: rgba(255, 255, 255, 0.5);
|
--dialog-backdrop: rgba(255, 255, 255, 0.5);
|
||||||
|
|
||||||
|
--font-body: "Atkinson Hyperlegible", sans-serif;
|
||||||
|
--font-monospace: "Iosevka Hyperlegible", monospace;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Reset */
|
/* Reset */
|
||||||
|
@ -24,7 +27,7 @@ body {
|
||||||
/* Fonts */
|
/* Fonts */
|
||||||
|
|
||||||
:root {
|
:root {
|
||||||
font-family: "Atkinson Hyperlegible", sans-serif;
|
font-family: var(--font-body);
|
||||||
}
|
}
|
||||||
|
|
||||||
button, textarea, input {
|
button, textarea, input {
|
||||||
|
@ -33,7 +36,7 @@ button, textarea, input {
|
||||||
}
|
}
|
||||||
|
|
||||||
pre, code, textarea {
|
pre, code, textarea {
|
||||||
font-family: "Iosevka Hyperlegible", monospace;
|
font-family: var(--font-monospace);
|
||||||
line-height: 1.5;
|
line-height: 1.5;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,9 @@ export class CodeEditor extends HTMLElement {
|
||||||
connectedCallback() {
|
connectedCallback() {
|
||||||
this.indentWidth = 2;
|
this.indentWidth = 2;
|
||||||
|
|
||||||
|
this.layerGutter = this.appendChild(document.createElement("pre"));
|
||||||
|
this.layerGutter.classList.add("layer", "layer-gutter");
|
||||||
|
|
||||||
this.textArea = this.appendChild(document.createElement("textarea"));
|
this.textArea = this.appendChild(document.createElement("textarea"));
|
||||||
this.textArea.spellcheck = false;
|
this.textArea.spellcheck = false;
|
||||||
this.textArea.rows = 1;
|
this.textArea.rows = 1;
|
||||||
|
@ -29,13 +32,17 @@ export class CodeEditor extends HTMLElement {
|
||||||
|
|
||||||
this.#textAreaAutoSizingBehaviour();
|
this.#textAreaAutoSizingBehaviour();
|
||||||
this.#keyShortcutBehaviours();
|
this.#keyShortcutBehaviours();
|
||||||
|
|
||||||
|
this.#renderLayers();
|
||||||
}
|
}
|
||||||
|
|
||||||
get code() {
|
get code() {
|
||||||
return this.textArea.value;
|
return this.textArea.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
#sendCodeChanged() {
|
#codeChanged() {
|
||||||
|
this.#resizeTextArea();
|
||||||
|
this.#renderLayers();
|
||||||
this.dispatchEvent(
|
this.dispatchEvent(
|
||||||
Object.assign(new Event(".codeChanged"), {
|
Object.assign(new Event(".codeChanged"), {
|
||||||
newCode: this.code,
|
newCode: this.code,
|
||||||
|
@ -45,14 +52,14 @@ export class CodeEditor extends HTMLElement {
|
||||||
|
|
||||||
setCode(value) {
|
setCode(value) {
|
||||||
this.textArea.value = value;
|
this.textArea.value = value;
|
||||||
this.#resizeTextArea();
|
this.#codeChanged();
|
||||||
this.#sendCodeChanged();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Resizing the text area
|
||||||
|
|
||||||
#textAreaAutoSizingBehaviour() {
|
#textAreaAutoSizingBehaviour() {
|
||||||
this.textArea.addEventListener("input", () => {
|
this.textArea.addEventListener("input", () => {
|
||||||
this.#resizeTextArea();
|
this.#codeChanged();
|
||||||
this.#sendCodeChanged();
|
|
||||||
});
|
});
|
||||||
this.#resizeTextArea();
|
this.#resizeTextArea();
|
||||||
document.fonts.addEventListener("loadingdone", () => this.#resizeTextArea());
|
document.fonts.addEventListener("loadingdone", () => this.#resizeTextArea());
|
||||||
|
@ -84,6 +91,24 @@ export class CodeEditor extends HTMLElement {
|
||||||
this.textArea.style.height = `${this.textArea.scrollHeight}px`;
|
this.textArea.style.height = `${this.textArea.scrollHeight}px`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Layers
|
||||||
|
|
||||||
|
#renderLayers() {
|
||||||
|
this.#renderGutter();
|
||||||
|
}
|
||||||
|
|
||||||
|
#renderGutter() {
|
||||||
|
this.layerGutter.replaceChildren();
|
||||||
|
|
||||||
|
for (let line of this.code.split("\n")) {
|
||||||
|
let lineElement = this.layerGutter.appendChild(document.createElement("span"));
|
||||||
|
lineElement.classList.add("line");
|
||||||
|
lineElement.textContent = line;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Text editing
|
||||||
|
|
||||||
#keyShortcutBehaviours() {
|
#keyShortcutBehaviours() {
|
||||||
this.textArea.addEventListener("keydown", (event) => {
|
this.textArea.addEventListener("keydown", (event) => {
|
||||||
let keyComponents = [];
|
let keyComponents = [];
|
||||||
|
|
|
@ -169,15 +169,72 @@ rkgk-reticle-cursor {
|
||||||
/* Code editor */
|
/* Code editor */
|
||||||
|
|
||||||
rkgk-code-editor {
|
rkgk-code-editor {
|
||||||
|
--gutter-width: 2.5em;
|
||||||
|
|
||||||
|
display: block;
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
&>.layer {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
|
||||||
|
margin: 0;
|
||||||
|
|
||||||
|
pointer-events: none;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
&>.line {
|
||||||
|
white-space: pre-wrap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&>.layer-gutter {
|
||||||
|
user-select: none;
|
||||||
|
|
||||||
|
counter-reset: line;
|
||||||
|
|
||||||
|
color: transparent;
|
||||||
|
|
||||||
|
&>.line {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
|
||||||
|
counter-increment: line;
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
display: block;
|
||||||
|
width: var(--gutter-width);
|
||||||
|
flex-shrink: 0;
|
||||||
|
padding-right: 0.5em;
|
||||||
|
box-sizing: border-box;
|
||||||
|
|
||||||
|
content: counter(line);
|
||||||
|
text-align: right;
|
||||||
|
|
||||||
|
color: var(--color-text);
|
||||||
|
opacity: 40%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
&>textarea {
|
&>textarea {
|
||||||
display: block;
|
display: block;
|
||||||
width: 100%;
|
width: calc(100% - var(--gutter-width));
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
margin-left: var(--gutter-width);
|
||||||
|
padding: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
overflow: hidden;
|
||||||
resize: none;
|
resize: none;
|
||||||
white-space: pre-wrap;
|
white-space: pre-wrap;
|
||||||
border: none;
|
border: none;
|
||||||
overflow: hidden;
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue