soma3/src/demo.ts
2025-05-12 13:03:52 -04:00

390 lines
11 KiB
TypeScript

import { App } from ".";
import { computed } from "./reactivity/computed";
import { reactive } from "./reactivity/reactive";
import { ref } from "./reactivity/ref";
import { html } from "./util";
// ------------------------------------------------
// Slots, multiple default and named, :if and :for
// const card = {
// template: html`<div>
// <h3><slot /></h3>
// <slot name="body" />
// </div>`,
// };
// const main = {
// template: html`
// <div>
// <h1>card below</h1>
// <card>
// card title
// <template slot="body">Card body content</template>
// </card>
// </div>
// `,
// };
// const app = new App();
// app.register("card", card);
// app.mount(main, "#app");
// ------------------------------------------------
// Slots, multiple default and named, :if and :for
const app = new App();
const parent = {
template: html`
<div>
<h1>parent, bool: {{bool}}</h1>
<card>
<!-- default -->
<div :if="bool">
<div :teleport="body" id="teleported">
<div>showing 1-3 because bool is true</div>
<div>1</div>
<div>2</div>
<div>3</div>
</div>
</div>
content 1 always shown
<div :if="bool">
content 2, animals:
<div :for="animal in animals">animal: {{animal}}</div>
</div>
<!-- body -->
<template slot="body">card body from parent</template>
</card>
</div>
`,
main() {
const bool = ref(true);
const animals = reactive(["dog", "cat", "bear"]);
setInterval(() => {
bool.value = !bool.value;
}, 2000);
return { bool, animals };
},
};
const card = {
template: html`<div>
<h2>card</h2>
<h3><slot /></h3>
<slot name="body" />
</div>`,
};
app.register("card", card);
const parentBlock = app.mount(parent, "body");
const cardBlock = parentBlock.context.blocks[0];
// ------------------------------------------------
// Component pros, mirror and spread, bind and no bind
// const child = {
// template: html`<div>Animal: {{animal}} {{index}}</div>`,
// props: { animal: { default: "cat" }, index: { default: 0 } },
// main({ animal, index }) {
// return { animal, index };
// },
// };
// const parent = {
// template: html`
// <div class="sans-serif">
// <child :if="true" :for="x in list" />
// mirror, no bind:
// <child {animal} />
// <hr />
// mirror, bind:
// <child {animal:bind} />
// <hr />
// spread, no bind:
// <child ...spread />
// <hr />
// spread, bind:
// <child ...spread:bind />
// <hr />
// regular prop:
// <child .animal="animal" />
// <hr />
// regular prop, bind:
// <child .animal:bind="animal" />
// <hr />
// <div .id="animal">div has "id" set to animal.value</div>
// <hr />
// <div .id:bind="animal">div has "id" set and bound to animal.value</div>
// <hr />
// <div {animal}>div has "animal" set to animal.value</div>
// <hr />
// <div {animal:bind}>div has "animal" set and bound to animal.value</div>
// <hr />
// <div ...spread>div has "animal" spread</div>
// <hr />
// <div ...spread:bind>div has "animal" spread and bound</div>
// <hr />
// <hr />
// <hr />
// <hr />
// if bool, mirror, no bind:
// <child :if="bool" {animal} />
// if bool, mirror, bind:
// <child :if="bool" {animal:bind} />
// <hr />
// for list, mirror, no bind:
// <child :for="item in list" {animal} />
// <hr />
// for list, mirror, bind:
// <child :for="item in list" {animal:bind} />
// if bool, for list, mirror, no bind: these have the value "DOG!" because by the time for :for directive is evaluated, animal.value is "DOG!", and no longer "dog".
// <div :if="bool">
// <child :for="item in list" {animal} />
// </div>
// </div>
// `,
// main() {
// const bool = ref(false);
// const animal = ref("dog");
// const spread = reactive({ animal: "panther" });
// const list = reactive([1, 2, 3]);
// setTimeout(() => {
// spread.animal = "PANTHER!";
// animal.value = "DOG!";
// bool.value = true;
// }, 500);
// setTimeout(() => {
// animal.value = "DOG!!!!!";
// }, 1000);
// return { animal, spread, bool, list };
// },
// };
// const app = new App();
// app.register("child", child);
// app.mount(parent, "#app");
// ------------------------------------------------
// Event directive
// const counter = {
// template: html`
// <div class="sans-serif">
// <div :teleport="body">
// <div :if="style.color === 'gray'">color is gray</div>
// <div :if="style.color === 'white'">color is white</div>
// <div>{{style.color}}</div>
// </div>
// <h3 {style:bind}>Count: {{count}}{{count >= 2 ? '!!!' : ''}}</h3>
// <button @click="increment" class="padding-x-1 padding-y-0_5">+</button>
// <button @click="decrement" class="padding-x-1 padding-y-0_5">-</button>
// <div :teleport="body">
// <div :for="color in ['red', 'green', 'blue']">{{color}}</div>
// </div>
// </div>
// `,
// main() {
// const count = ref(0);
// const style = reactive({ color: "gray" });
// const increment = () => count.value++;
// const decrement = () => count.value--;
// setInterval(() => {
// style.color = style.color === "gray" ? "white" : "gray";
// }, 500);
// return { count, increment, decrement, style };
// },
// };
// const app = new App();
// app.mount(counter, "#app");
// ------------------------------------------------
// :if above :for
// :if with :teleport
// const main = {
// template: html`
// <div>
// <div :if="bool">
// <div :teleport="body">
// <div :for="item in items">{{item}}</div>
// </div>
// </div>
// <div :if="bool">
// <div :teleport="body">if bool teleported! {{items}}</div>
// </div>
// </div>
// `,
// main() {
// const items = reactive([1, 2, 3, 4, 5]);
// const bool = ref(true);
// setInterval(() => (bool.value = !bool.value), 2050);
// return { items, bool };
// },
// };
// const app = new App();
// app.mount(main, "#app");
// ------------------------------------------------
// :html
// const main = {
// template: html`<div :html="html"></div>`,
// main() {
// const html = ref("<h1>hello</h1>");
// setTimeout(() => {
// if (html.value === "<h1>hello</h1>") {
// html.value = "<h1>world</h1>";
// }
// }, 1000);
// return { html };
// },
// };
// const app = new App();
// app.mount(main, "#app");
// ------------------------------------------------
// Colors from css framework
// const main = {
// template: html`
// <div class="sans-serif margin-y-3 container" style="--column-gap: .5rem; --row-gap: .5rem;">
// <h1 class="f1 margin-bottom-1 color-60">phase</h1>
// <h2 class="f3 margin-bottom-1 color-peach-50">Colors</h2>
// <grid columns="6" class="f6 white-space-nowrap">
// <div :for="variant in ['base', 'accent', 'red', 'rose', 'orange', 'amber', 'yellow', 'lime', 'green', 'emerald', 'teal', 'cyan', 'sky', 'blue', 'indigo', 'lavender', 'violet', 'purple', 'plum', 'fuchsia', 'pink', 'peach']" class="border-color-30 border-2px">
// <div :for="rank, index in ranks">
// <div .style:bind="bg(variant, rank, index)" class="padding-1">{{variant}}-{{rank}}</div>
// </div>
// </div>
// </grid>
// </div>
// `,
// main() {
// const ranks = reactive(["5", "10", "20", "30", "40", "50", "60", "70", "80", "90"]);
// const basesReverse = computed(() => Array.from(ranks).reverse());
// const bg = (variant: string, rank: string, index: number) => ({ backgroundColor: `var(--${variant}-${rank})`, color: `var(--${variant}-${basesReverse.value[index]})` });
//
// return { ranks, bg };
// },
// };
//
// const app = new App();
// app.mount(main, "#app");
// ------------------------------------------------
// :scope
// const child = {
// template: html`
// <div>
// I am child and I have a cheeseburger: "{{food}}" (does not inherit)
// <div>
// <slot />
// </div>
// </div>
// `,
// main() {
// // Comment this out to implicitly inherit the
// // provided :scope value from the parent.
// const food = ref("🍔");
// return { food };
// },
// };
//
// const main = {
// template: html`
// <div class="hero sans-serif f2" :scope:provide="{ drink: '🍹' }">
// <div :scope:provide="{ food: '🍕' }">
// <div>Parent has pizza: {{food}} and scoped drink: {{drink}}</div>
// <child>Child slot, food: {{food}} {{drink}}</child>
// </div>
// </div>
// `,
// main() {
// // return { food: ref("nothing") };
// },
// };
//
// const app = new App();
// app.register("child", child);
// app.mount(main, "#app");
// ------------------------------------------------
// Practical :scope demo
// const main = {
// template: html`
// <div class="hero sans-serif f2" :scope="{ visible: true }">
// <div :show="visible">ON</div>
// <div :show="!visible">OFF</div>
// <button @click="visible = !visible" class="padding-x-1 padding-y-0_5 border-radius-0_25">Toggle</button>
// <div>visible: {{visible}} / foo: {{foo}}</div>
// </div>
// `,
// main() {
// const foo = ref("bar");
// return { foo };
// },
// };
// const app = new App();
// app.mount(main, "#app");
// --------
// weird issue
// const child = {
// template: html`<div>child{{thing}}</div>`,
// props: { thing: { default: 1 } },
// main({ thing }) {
// return { thing };
// },
// };
//
// const counter = {
// template: html`
// <div class="sans-serif">
// <div :if="true">
// <div :teleport="body">
// <div :for="color in colors">{{color}}</div>
// </div>
// <child :teleport="body" .thing="5" />
// </div>
// </div>
// `,
// main() {
// const colors = reactive(["red", "orange"]);
// return { colors };
// },
// };
//
// const app = new App();
// app.register("child", child);
// app.mount(counter, "#app");
// ------------------------------------------------
// <template>
// const templateTest = {
// template: html`
// <div>
// <!-- is dissolved -->
// <div :if="bool">hello</div>
//
// <template :if="bool">
// <span :for="num in [1,2,3]">{{num}}</span>
// </template>
// </div>
// `,
// main() {
// const bool = ref(true);
//
// return { bool };
// },
// };
//
// const app = new App();
// app.mount(templateTest, "#app");