Skip to content

Instantly share code, notes, and snippets.

@bcherny
Created March 25, 2018 19:03
Show Gist options
  • Select an option

  • Save bcherny/7bde28f59519d826a99edd87fb348a4d to your computer and use it in GitHub Desktop.

Select an option

Save bcherny/7bde28f59519d826a99edd87fb348a4d to your computer and use it in GitHub Desktop.
// hyperscript and React-inspired DSL
// "react in 50 lines"
void function() {
/////////// tags
type Tagish = string | Tag
type Attrs = {
className: string
[k: string]: any
}
class Tag<T extends string = string> {
constructor(
private type: T,
public children: Tagish[],
private attrs: Partial<Attrs>
) { }
attr(as: Partial<Attrs>) {
return new Tag(
this.type,
this.children,
{ ...this.attrs, ...as }
)
}
toHTML() {
let html = document.createElement(this.type)
for (let attr in this.attrs) {
html.setAttribute(attr, this.attrs[attr])
}
return html
}
}
let tag = <T extends string>(type: T) =>
(...children: Tagish[]) =>
new Tag(type, children, {})
let div = tag('div')
let a = tag('a')
let dom = a(
div('hello world').attr({ className: 'a' })
)
////////// components
type XProps = {
a: number
}
let x = ({ a }: XProps) =>
div(
'(x) a is ',
a.toString(),
y({ a, b: true })
)
type YProps = {
a: number
b: boolean
}
let y = ({ a, b }: YProps) =>
div('(y) a is ', a.toString(), ' and b is ', b.toString())
let dom2 = a(
div('hello world').attr({ className: 'a' }),
x({ a: 120 })
)
////////// renderer
function render(
dom: Tagish,
container: Element
) {
if (typeof dom === 'string') {
container.textContent = dom
} else {
let html = dom.toHTML()
dom.children.forEach(_ => render(_, html))
container.appendChild(html)
}
}
render(dom2, document.body)
/////////// TODO: JSX parser
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment