TODO
TODO: <template hyper-component="tag-name">
TODO: ${} interpolation, #for, #if
TODO: default slots, named slots
attrs ProxyTODO: attribute evaluation in parent scope, bidirectional binding
TODO: automatic re-render via morph when dependencies change
TODO: dom-scope="isolated", ^var scoping boundaries
<template hyper-component="filter-list" _="set ^list to attrs.items">
<input type="text" placeholder="Search..."
_="on input
hide #no-match
show <li:not(#no-match)/> in closest <filter-list/>
when its textContent contains my value
ignoring case
show #no-match when the result is empty" />
<ul>
#for item in ^list
<li><a href="${item.url}">${item.name}</a></li>
#end
<li id="no-match" style="display:none; color:var(--text-muted)">No results</li>
</ul>
</template>
Usage:
<filter-list items="[{name: 'Macintosh 128K', url: 'https://en.wikipedia.org/wiki/Macintosh_128K'},
{name: 'Macintosh Plus', url: 'https://en.wikipedia.org/wiki/Macintosh_Plus'},
...]">
</filter-list>
Demo:
The same component using reactive rendering instead of show/hide. The #if inside #for filters
at render time: when ^query changes, the template re-renders and the result is morphed in. If no
matches are found it will show a "No Results" item.
<template hyper-component="reactive-filter-list"
_="set ^list to attrs.items
set ^query to ''">
<input type="text" placeholder="Search..." _="bind me to ^query" />
<ul>
#for item in ^list where its name contains the ^query ignoring case
<li><a href="${unescaped item.url}">${item.name}</a></li>
#else
<li>No Results</li>
#end
</ul>
</template>
Demo: