https://domlink.deployments.hotsocket.fyi/

Threw in some fancy doc comments

Changed files
+60 -26
src
+2
readme
··· 26 26 - @poggers.website 27 27 at://did:plc:7ggpsji45es4auo5pqjmnarr/app.bsky.feed.post/3lx5d3p4oos2n 28 28 29 + bro idk what this is anymore but im a fan of it and will keep going 30 +
+55 -23
src/domlink.ts
··· 1 - let _LCounter = 0; // is there a point to this? idk. might be unnecessary overhead. 1 + let _LCounter = 0; // is there a point to this? IDK but it feels useful. 2 + 3 + /** Core wrapper for {@link HTMLElement DOM elements}. */ 2 4 export class Node { 3 5 wraps: HTMLElement; 4 6 children: Node[] = []; 5 - id: string = "L" + _LCounter++;; 6 - constructor(wrap: HTMLElement) { 7 - this.wraps = wrap; 7 + id: string = "L" + _LCounter++; 8 + /** 9 + * Creates a node, wrapping an HTML element. 10 + * @example new Node(document.createElement("h1")); 11 + */ 12 + constructor(wraps: HTMLElement) { 13 + this.wraps = wraps; 8 14 this.wraps.id = this.id; 9 15 } 10 - // could i make add and with one function? yeah. 11 - // will i do that? no. 12 - // why not? because it feels nice to have them separate. 13 - add(node: Node | string) { 16 + /** Adds a child node. Should not be overridden. */ 17 + add(node: NodeEquivalent) { 14 18 if (node != undefined) { 15 19 let xnode: Node; 16 20 if (typeof node === "string") { ··· 25 29 } 26 30 return this; 27 31 } 28 - remove(node: Node) { 32 + /** Works similarly to {@link add}, but takes multiple nodes and is the one you would want to override. */ 33 + with(...nodes: NodeEquivalent[]) { 34 + nodes.forEach(x=>{this.add(x)}); 35 + return this; 36 + } 37 + /** Removes a child node in the same way {@link add} does. */ 38 + delete(node: Node) { 29 39 let idx = this.children.indexOf(node); 30 40 if (idx < 0) { 31 - throw new Error("node not a child of this node"); 41 + throw new Error(`Node ${node.id} not found.`); 32 42 } 33 43 this.children.splice(idx, 1); 34 44 this.wraps.removeChild(node.wraps); 35 45 } 36 - with(...nodes: (Node | string)[]) { 37 - nodes.forEach(x=>{this.add(x)}); 38 - return this 39 - } 40 - style(fn: (style: CSSStyleDeclaration) => void) { 46 + /** Removes one or more child nodes, like {@link with} does adding them. */ 47 + remove(...nodes: Node[]) { 48 + nodes.forEach(x=>{this.delete(x)}); 49 + return this; 50 + } 51 + /** Conveniently chain-able callback thing for styling your nodes. 52 + * @example new Label("This is a label!").style((s)=>{s.color="maroon";}) */ 53 + style(fn: (style: CSSStyleDeclaration) => void) { 41 54 fn(this.wraps.style); 42 55 return this; 43 56 } 57 + /** Adds a CSS class to your node. 58 + * @example new Container().class("my-class") */ 44 59 class(cls: string) { 45 60 this.wraps.classList.add(cls); 46 61 return this; ··· 52 67 NEW_TAB = "_blank", 53 68 OUT_FRAME = "_parent", 54 69 NOT_FRAME = "_top" 55 - }; 70 + } 71 + /** Wrapper for {@link HTMLAnchorElement `<a>`} */ 56 72 export class Link extends Node { 57 73 constructor(around: NodeEquivalent | null) { 58 74 let a = document.createElement("a"); ··· 65 81 set destination(x: string) { 66 82 (this.wraps as HTMLAnchorElement).href = x; 67 83 } 68 - get destination(): string { 84 + // noinspection JSUnusedGlobalSymbols 85 + get destination(): string { 69 86 return (this.wraps as HTMLAnchorElement).href; 70 87 } 71 88 set target(x: string) { ··· 81 98 } 82 99 83 100 } 101 + /** Wrapper for {@link HTMLDivElement `<div>`} */ 84 102 export class Container extends Node { 85 103 constructor() { 86 104 let div = document.createElement("div"); ··· 88 106 super(div); 89 107 } 90 108 } 109 + /** Vertical Flexbox container */ 91 110 export class Column extends Container { 92 111 constructor() { 93 112 super(); 94 113 this.wraps.classList.add("LColumn"); 95 114 } 96 115 } 116 + /** Horizontal Flexbox container */ 97 117 export class Row extends Container { 98 118 constructor() { 99 119 super(); 100 120 this.wraps.classList.add("LRow"); 101 121 } 102 122 } 123 + /** Wrapper for {@link HTMLTableElement `<table>`} */ 103 124 export class Table extends Node { 104 125 constructor() { 105 126 let table = document.createElement("table"); ··· 107 128 super(table); 108 129 } 109 130 } 131 + /** Wrapper for {@link HTMLTableRowElement `<tr>`} */ 110 132 export class TableRow extends Node { 111 133 constructor() { 112 134 let tr = document.createElement("tr"); ··· 114 136 super(tr); 115 137 } 116 138 } 139 + /** Wrapper for {@link HTMLTableCellElement `<td>`} */ 117 140 export class TableCell extends Node { 118 141 constructor() { 119 142 let td = document.createElement("td"); ··· 121 144 super(td); 122 145 } 123 146 } 147 + /** An "abstract" class of sorts for {@link HTMLElement}s that have a textContent member. */ 124 148 export class Text extends Node { 125 149 private _text: string = ""; 126 150 get text() { ··· 131 155 this.wraps.textContent = x; 132 156 } 133 157 } 158 + /** Wrapper for {@link HTMLSpanElement `<span>`} */ 134 159 export class Label extends Text { 135 160 constructor(text: string = "") { 136 161 let el = document.createElement("span"); ··· 139 164 this.text = text; 140 165 } 141 166 } 167 + /** Wrapper for {@link HTMLButtonElement `<button>`} */ 142 168 export class Button extends Text { 143 169 constructor(label: string, action: EventListener) { 144 170 let btn = document.createElement("button"); ··· 149 175 this.text = label; 150 176 } 151 177 } 152 - interface Updatable { 153 - watch: (watcher: (newValue: string)=>void) => void; 178 + /** Interface providing {@link Updatable.watch} */ 179 + interface Updatable<T> { 180 + /** Takes a callback `watcher` that is called when something like a text input is updated. */ 181 + watch: (watcher: (newValue: T)=>void) => void; 154 182 } 155 - export class Input extends Text implements Updatable { 183 + export class Input extends Text implements Updatable<string> { 156 184 constructor(type: HTMLInputElement["type"] = "text") { 157 185 let el = document.createElement("input"); 158 186 el.type = type; ··· 172 200 173 201 174 202 175 - // Implementation for Updatable 176 203 watching: ((newValue: string) => void)[] = []; 204 + /** Implementation for {@link Updatable.watch} */ 177 205 watch(watcher: (newValue: string)=>void) { 178 206 this.watching.push(watcher); 179 - this.wraps.oninput = (e)=>{watcher(this.value)}; 207 + this.wraps.oninput = ()=>{watcher(this.value)}; 180 208 watcher(this.value); 181 209 } 182 210 } 211 + /** Wrapper for {@link HTMLImageElement `<img>`} */ 183 212 export class Image extends Node { 184 213 constructor(src: string) { 185 214 let img = document.createElement("img"); ··· 188 217 super(img); 189 218 } 190 219 } 220 + /** Wrapper for {@link HTMLDialogElement `<dialog>`} with methods to show/hide it as a modal. */ 191 221 export class Modal extends Node { 192 222 constructor() { 193 223 let dlg: HTMLDialogElement = document.createElement("dialog"); 194 224 dlg.classList.add("LModal"); 195 225 super(dlg); 196 226 } 227 + /** Shows the dialog as a modal. */ 197 228 show() { 198 229 Body.add(this); 199 230 (this.wraps as HTMLDialogElement).showModal(); 200 231 } 232 + /** Hides the dialog. */ 201 233 hide() { 202 234 (this.wraps as HTMLDialogElement).close(); 203 235 Body.wraps.removeChild(this.wraps); 204 236 } 205 237 } 206 238 207 - // user helper shit 239 + /** Convenience wrapper for the {@link HTMLBodyElement body} of the document. */ 208 240 export const Body = new Node(document.body);
+2 -2
src/issuesearch.ts
··· 146 146 (runButton.wraps as HTMLButtonElement).disabled = true; 147 147 if (last) { 148 148 try { 149 - Body.remove(last); 149 + Body.delete(last); 150 150 } catch {} 151 151 last = null; 152 152 } ··· 171 171 searchInput.watch((search)=>{ 172 172 if (allIssues.length > 0) { 173 173 if (last) { 174 - Body.remove(last); 174 + Body.delete(last); 175 175 } 176 176 search = search.toLowerCase(); 177 177 last = renderIssues(allIssues.filter((item)=>{
+1 -1
src/pds.ts
··· 65 65 let runButton = new Button("GO!",async ()=>{ 66 66 (runButton.wraps as HTMLButtonElement).disabled = true; 67 67 if (last) { 68 - Body.remove(last); 68 + Body.delete(last); 69 69 } 70 70 try { 71 71 last = await listActiveUsers(hostInput.value);