summary refs log tree commit diff
path: root/elements.ts
diff options
context:
space:
mode:
Diffstat (limited to 'elements.ts')
-rw-r--r--elements.ts125
1 files changed, 125 insertions, 0 deletions
diff --git a/elements.ts b/elements.ts
new file mode 100644
index 0000000..d089931
--- /dev/null
+++ b/elements.ts
@@ -0,0 +1,125 @@
+// deno-lint-ignore-file no-case-declarations ban-ts-comment no-process-globals
+import chalk from "chalk";
+import { type Key } from 'node:readline';
+import { type Screen } from "./screen.ts";
+
+export abstract class Element {
+    focusable: boolean = false;
+    focused: boolean = false;
+    // screen property is asigned by the addElement function of Scren
+    //@ts-ignore
+    screen: Screen;
+    abstract render(): void;
+    onkeypres(_key: Key): void {};
+}
+
+export class Text extends Element {
+    text: string;
+
+    processText: (text: string) => string;
+
+    constructor(text: string, processText = (t:string)=>t) {
+        super();
+        this.text = text;
+        this.processText = processText
+    }
+    render() {
+        process.stdout.write(this.processText(this.text))
+    }
+}
+
+export class HR extends Element {
+    constructor() {
+        super()
+    }
+    render(): void {
+        console.log('-'.repeat(process.stdout.columns))
+    }
+}
+
+export class BR extends Element {
+    constructor() {
+        super()
+    }
+    render(): void {
+        console.log()
+    }
+}
+
+export class Input extends Element {
+    override focusable: boolean = true;
+    value: string = "";
+
+    textarea = false;
+    br = false;
+
+    isPassword: boolean = false;
+
+    render(): void {
+        let text = this.value
+        if (this.isPassword) text = text.replace(/[^]/g, '*');
+        if (this.focused) text += "_"
+        process.stdout.write(text)
+    }
+
+    override onkeypres(key: Key): void {
+        //@ts-ignore
+        if (key.meta || key.code || ["return", "backspace"].includes(key.name)) {
+            switch (key.name) {
+                case "return":
+                    if(this.textarea) {
+                        this.value += '\n'
+                        break;
+                    }
+                    this.focused = false;
+                    const focusableIDs = Object.keys(this.screen.getFocusable());
+                    const focusedIndex = focusableIDs.indexOf(this.screen.focusedElementId);
+                    this.screen.focus(focusableIDs[(focusedIndex + 1) % focusableIDs.length]);
+                    break;
+                
+                case "backspace":
+                    const prevValue = '' + this.value
+                    // logs.push(`doing backspace : before ${prevValue}, after ${prevValue.substring(0, prevValue.length - 1)} : 0-${prevValue.length - 1}`)
+                    this.value = prevValue.substring(0, prevValue.length - 1)
+                    break;
+            }
+            this.screen.render()
+            return;
+        }
+	// check if the character ism't typable
+	// checks:
+	// sequience length > 1 (eg ^[ ^[[A)
+	// key name != sequence (and if name exists)
+        //@ts-ignore
+        if (!key.sequence || key.sequence.length > 1 || key.name != key.sequence?.toLowerCase() && !["space"].includes(key.name) && key.name) return;
+        this.value += key.sequence;
+        this.screen.render()
+    }
+
+    constructor(isPassword: boolean = false, br: boolean = false, textarea: boolean = false) {
+        super()
+        this.br = br
+        this.isPassword = isPassword;
+        this.textarea = textarea;
+    }
+}
+
+export class Button extends Text {
+    override focusable: boolean = true;
+    onclick: ()=>void;
+    constructor (text: string, onclick=()=>{}) {
+        super(text);
+        this.onclick = onclick
+    }
+
+    override render(): void {
+        process.stdout.write(`(${(this.focused ? chalk.bgWhite : (a:string)=>a)(this.text)})`)
+    }
+
+    override onkeypres(key: Key): void {
+        //@ts-ignore
+        if (["return", "space"].includes(key.name)) {
+            this.onclick.call(this.screen)
+        }
+    }
+}