@strangeskies/dope
v0.0.0
Published
An extremely lightweight component templating library which uses the platform. Targeted updates with no virtual DOM and no diffs.
Maintainers
Readme
dope
An extremely lightweight HTML templating library which uses the platform to the fullest possible extent.
Write templates declaratively in plain HTML using javascript template literals.
html`<span>Hello there.</span>`Declare slots using placeholders, which are filled by javascript expressions.
let greet = (name) => html`<span>Hello there, ${name}.</span>`;Templates compose trivially, simple pass a template into a slot.
let welcome = (name, destination) =>
html`
${greet(name)}
<span>Welcome to ${destination}!</span>
`;Templates may transparently define custom elements, with near-zero boilerplate and no manual class registration.
let welcomeAnywhere = (name) =>
let setDestination = (destination) => {
instance().destination = destination;
instance().updateDestination.forEach(call);
};
let getDestination = () => {
(instance().updateDestination ||= new Set()).add(runner().repeat);
return instance().destination;
};
component`
<welcome-somewhere ${{ destination: defaultDestination() }}>
${() => welcome(name, getDestination())}
<button @click=${() => setDestination(randomDestination())}>
</welcome-somewhere>
`;let welcomeAnywhere = (name) =>
component`
<welcome-somewhere ${{ destination: defaultDestination() }}>
${() => welcome(name, ctx.destination)}
<button @click=${() => ctx.destination = randomDestination()}>
</welcome-somewhere>
`;let welcomeAnywhere = (name) => {
let welcomeCtx = ctx`welcome`({ destination: defaultDestination() });
return component`
<welcome-somewhere ${welcomeCtx}>
${() => welcome(name, welcomeCtx.destination)}
<button @click=${() => welcomeCtx.destination = nextDestination()}>
</welcome-somewhere>
`;
};let welcomeAnywhere = (name) => {
let welcomeCtx = ctx`welcome`({ destination: defaultDestination() });
return component()`
<welcome-somewhere>
${() => welcome(name, welcomeCtx.destination)}
<button
${{
click: () => welcomeCtx.destination = nextDestination()
}}>
</welcome-somewhere>
`;
};function friendHook(friend) {
let friendState = state`friend`({ online: null });
let friendEffect = () => {
let handleStatusChange = status =>
friendState.online = status.isOnline;
ChatAPI.subscribeToFriendStatus(friend.id, handleStatusChange);
action().onUndo = () => {
ChatAPI.unsubscribeFromFriendStatus(friend.id, handleStatusChange);
};
};
return component`
<friend-status ${[ friendState, friendEffect ]}>
<h1>${friend.name}</h1>
${() => statusText(friendState.online)}
</friend-status>
`;
}function FriendStatus(friend) {
let friendKey = sym`friend-state`;
return component`
<friend-status ${friendHook(friend)}>
<h1>${friend.name}</h1>
${() => statusText(elem.friendOnline)}
</friend-status>
`;
}function App() {
const myResult = useAsync(myFunction, false);
return () => html`
<div>
<div>
${
myResult.value ||
myResult.error ||
"Start your journey by clicking a button"
}
</div>
<button @click=${myResult.execute} disabled=${myResult.pending}>
${myResult.pending ? "Loading..." : "Click me"}
</button>
</div>
`;
}const friendKey = Symbol('friendState');
function friendHook(friend) {
return [
{ [friendKey]: { online: null } },
() => {
let handleStatusChange = status =>
state().friendOnline = status.isOnline;
ChatAPI.subscribeToFriendStatus(
friend.id,
handleStatusChange);
return () => {
ChatAPI.unsubscribeFromFriendStatus(
friend.id,
handleStatusChange);
};
}
];
}
function friendState() {
return element()[friendKey];
}
function FriendStatus(friend) {
return component`
<friend-status ${friendHook(friend)}>
<h1>${friend.name}</h1>
${() => statusText(friendState().online)}
</friend-status>
`;
}Minimal, targeted DOM updates. No virtual DOM, and no diff heuristics. Uses the platform, no custom HTML parsing.
