Skip to content

Instantly share code, notes, and snippets.

@btakita
Last active November 1, 2023 09:43
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save btakita/dfd966bd612fec82824d937357e46412 to your computer and use it in GitHub Desktop.
Save btakita/dfd966bd612fec82824d937357e46412 to your computer and use it in GitHub Desktop.
van export-shared-types branch example
import type { ChildDom, Props, TagFunc, Tags, VanShape } from 'mini-van-plate/shared'
import _van, { type ElementProto } from 'mini-van-plate/van-plate'
import { Raw } from './Raw'
import { vanCleanProps } from './vanCleanProps'
const van = vanCleanProps(_van)
const { a } = van.tags
export function V_link_button($p:{
href:string
class?:string
ariaLabel?:string
title?:string
disabled?:boolean
}, ...children:ChildDom[]) {
const { ariaLabel, href, title, disabled } = $p
return (
a({
href: disabled ? '#' : href,
tabindex: disabled ? '-1' : '0',
class: `group inline-block hover:text-skin-accent${$p.class ? ` ${$p.class}` : ''}`,
ariaLabel,
title,
}, ...children.map(child=>
typeof child === 'string'
? Raw(van, child)
: child))
)
}
/// <reference lib="dom" />
import { type Van as MiniVan } from 'mini-van-plate'
import type { VanShape } from 'mini-van-plate/shared'
import { type Element as VanPlateElement, type ElementProto } from 'mini-van-plate/van-plate'
export function Raw<V extends VanShape>(van:V, html:string):Return<V>{
if (globalThis['window']) return htmlDocumentFragment(html) as Return<V>
const { __proto__ } = van.tags.div() as any as { __proto__:ElementProto }
return {
__proto__,
render: __proto__.render,
renderToBuf(buf:any[]) {
buf.push(html)
},
} as VanPlateElement as Return<V>
}
function htmlDocumentFragment(html:string) {
const frag = document.createDocumentFragment()
const temp = document.createElement('div')
temp.innerHTML = html
while (temp.firstChild) {
frag.appendChild(temp.firstChild)
}
return frag
}
type Return<V extends VanShape> = V extends MiniVan ? DocumentFragment : VanPlateElement
// import minivan from 'mini-van-plate'
// Raw(minivan, '<em>test</em>') // DocumentFragment
// import vanplate from 'mini-van-plate/van-plate'
// Raw(vanplate, '<em>test</em>') // VanPlateElement
import type { ChildDom, Props, TagFunc, Tags, VanShape } from 'mini-van-plate/shared'
import { type Van as VanPlate } from 'mini-van-plate/van-plate'
const protoOf = Object.getPrototypeOf
const objProto = protoOf({})
export function vanCleanProps<V extends VanShape>(van:V):Omit<V, 'tags'|'tagsNS'>&{
tags:Readonly<Record<string, TagFuncWithUndefined<V>>>
tagsNS:(namespaceURI:string)=>Readonly<Record<string, TagFuncWithUndefined<V>>>
} {
let tags = new Proxy<Tags<V>>(van.tags as Tags<V>, {
get(target, p, receiver) {
const tag = Reflect.get(target, p, receiver) as TagFunc<V>
if (!tag) return tag
return ((...args:Parameters<TagFunc<V>>)=>{
let [
props,
...children
] = (protoOf(args[0] ?? 0) === objProto ? args : [{}, ...args]) as [Props, ...ChildDom<VanPlate>[]]
return tag(cleanProps(props), ...children)
}) as TagFunc<V>
}
})
return new Proxy<V>(van, {
get(target, p, receiver) {
if (p === 'tags') return tags
return Reflect.get(target, p, receiver)
}
}) as VanWithUndefined<V>
}
function cleanProps(props:Props) {
for (const key of Object.keys(props)) {
if (props[key] === undefined) delete props[key]
}
return props
}
export type PropsWithUndefined = Record<string, Props[string]|undefined>
export type TagFuncWithUndefined<V extends VanShape> =
(first?:Props|ChildDom<V>|PropsWithUndefined, ...rest:readonly ChildDom<V>[])=>ReturnType<TagFunc<V>>
export type VanWithUndefined<V extends VanShape> = V&{
tags:Record<string, TagFuncWithUndefined<V>>
tagsNS:(namespaceURI:string)=>Readonly<Record<string, TagFuncWithUndefined<V>>>
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment