a post-component library for building user-interfaces on the web.

make HTML a class

tombl.dev 3f633f83 c917d5a2

verified
+35 -20
+2 -1
src/client/parts.ts
··· 5 5 is_keyed, 6 6 is_renderable, 7 7 single_part_template, 8 + unwrap_html, 8 9 type Displayable, 9 10 type Key, 10 11 type Renderable, ··· 172 173 } 173 174 174 175 if (is_html(value)) { 175 - const { _dynamics: dynamics, _statics: statics } = value 176 + const { _statics: statics, _dynamics: dynamics } = unwrap_html(value) 176 177 const template = compile_template(statics) 177 178 178 179 assert(
+4 -2
src/client/root.ts
··· 5 5 is_keyed, 6 6 is_renderable, 7 7 single_part_template, 8 + unwrap_html, 8 9 type Displayable, 9 10 type Key, 10 11 type Renderable, ··· 111 112 } 112 113 113 114 if (is_html(value)) { 114 - template = compile_template(value._statics) 115 + const { _statics: statics, _dynamics: dynamics } = unwrap_html(value) 116 + template = compile_template(statics) 115 117 116 118 const node_by_part: Array<Node | Span> = [] 117 119 ··· 180 182 _start: child.previousSibling, 181 183 _end: end, 182 184 }, 183 - value._dynamics[dynamic_index], 185 + dynamics[dynamic_index], 184 186 ), 185 187 ] 186 188 case PART_DIRECTIVE:
+4 -4
src/index.ts
··· 1 1 export { html, keyed, type Displayable, type HTML, type Renderable } from './shared.ts' 2 2 3 - import { is_html } from './shared.ts' 3 + import { is_html, unwrap_html } from './shared.ts' 4 4 5 5 if (__DEV__) { 6 6 type JsonML = string | readonly [tag: string, attrs?: Record<string, any>, ...children: JsonML[]] ··· 13 13 ;((globalThis as { devtoolsFormatters?: Formatter[] }).devtoolsFormatters ??= []).push({ 14 14 header(value) { 15 15 if (!is_html(value)) return null 16 + const { _statics: statics, _dynamics: dynamics } = unwrap_html(value) 16 17 17 18 const children: JsonML[] = [] 18 - for (let i = 0; i < value._dynamics.length; i++) 19 - children.push(value._statics[i], ['object', { object: value._dynamics[i] }]) 20 - children.push(value._statics[value._statics.length - 1]) 19 + for (let i = 0; i < dynamics.length; i++) children.push(statics[i], ['object', { object: dynamics[i] }]) 20 + children.push(statics[statics.length - 1]) 21 21 22 22 return ['span', {}, 'html`', ...children, '`'] 23 23 },
+11 -2
src/server.ts
··· 1 - import { assert, is_html, is_iterable, is_renderable, lexer, single_part_template, type Displayable } from './shared.ts' 1 + import { 2 + assert, 3 + is_html, 4 + is_iterable, 5 + is_renderable, 6 + lexer, 7 + single_part_template, 8 + unwrap_html, 9 + type Displayable, 10 + } from './shared.ts' 2 11 3 12 interface PartRenderer { 4 13 replace_start: number ··· 153 162 if (is_iterable(value)) { 154 163 for (const item of value) yield* render_child(item) 155 164 } else if (is_html(value)) { 156 - const { _statics: statics, _dynamics: dynamics } = value 165 + const { _statics: statics, _dynamics: dynamics } = unwrap_html(value) 157 166 const template = compile_template(statics) 158 167 159 168 assert(
+14 -11
src/shared.ts
··· 31 31 } 32 32 } 33 33 34 - export interface HTML { 35 - [html_tag]: true 36 - /* @internal */ _statics: TemplateStringsArray 37 - /* @internal */ _dynamics: unknown[] 34 + export let unwrap_html: (value: HTML) => { _statics: TemplateStringsArray; _dynamics: unknown[] } 35 + 36 + export class HTML { 37 + #statics: TemplateStringsArray 38 + #dynamics: unknown[] 39 + constructor(statics: TemplateStringsArray, dynamics: unknown[]) { 40 + this.#statics = statics 41 + this.#dynamics = dynamics 42 + } 43 + static { 44 + unwrap_html = value => ({ _statics: value.#statics, _dynamics: value.#dynamics }) 45 + } 38 46 } 39 47 40 - const html_tag: unique symbol = Symbol() 41 48 export function html(statics: TemplateStringsArray, ...dynamics: unknown[]): HTML { 42 - return { 43 - [html_tag]: true, 44 - _dynamics: dynamics, 45 - _statics: statics, 46 - } 49 + return new HTML(statics, dynamics) 47 50 } 48 51 49 52 export function is_html(value: unknown): value is HTML { 50 - return typeof value === 'object' && value !== null && html_tag in value 53 + return value instanceof HTML 51 54 } 52 55 53 56 export function single_part_template(part: Displayable): HTML {