[ ] this instanceof Class where instance is from @build(Component) reside
[ ] bind`accessor` (see SSR/SSG issue)
single accessor(value)
Behind the scene, accessor(value) is just a syntactic sugar for new Accessor(value) where
const defineAccessor = () => @allocate(Infinity) class {
accessor value
constructor(value) { this.value = value }
valueOf() { return this.value }
}
which the Accessor class is unique per scopes of Component
let prevC1_a, currentC2_a
function C1() {
const a = accessor()
const b = accessor()
// each variables are differ from others
assert(a.prototype !== b.prototype)
// but each same variables is constructed by the same class
if (prevC1_a) assert(
prevC1_a.prototype === a.prototype
)
prevC1_a = a
// however, it will be different if it came from different scopes although it's in the same order
if (currentC2_a) assert(
currentC2_a.prototype !== a.prototype
)
}
function C2() {
const a = accessor()
const b = accessor()
currentC2_a = a
}
Warning: so yeah. The accessor must always be on top and in the same order. Not dynamically created in if, in for, in ternary operator, created after await, created inside callback, etc. Think of it like super() constructor.
In async generator, each yield and return will replace previous yield. However, normal generator function will behave the same way as Array of \<Component>.
async function IPAddress() {
const res = await fetch("https://api.ipify.org")
const address = await res.text()
return <span class="rainbow">{address}</span>
}
async function *Island() {
yield <span class="spinner">Loading...</span>
const addr = await fetch("https://api.ipify.org").then(as => as.text())
yield <span class="red">Your IP {addr}</span>
yield <span class="green">
{await fetch("https://api.ipify.org")
.then(as => as.text())} is
</span>
// render/print same 100 IP address 😂
return await Promise.all(Array.from(
{ length: 100 },
() => <IPAddress />,
))
}
export default class {
@build(IPAdress)
ip // <slot :=ip>Loading...</slot>
@build(Island)
stressIP // <div :=stressIP />
}
Behind the scene, async function is same as async generator where it yield new Comment(function.name) before the function is awaiting.
Basically, that \<IPAdress> is same as:
async function *IPAddress() {
yield new Comment("IPAddress")
const res = await fetch("https://api.ipify.org")
const address = await res.text()
return <span class="rainbow">{address}</span>
}
exposing local data when creating children
Expose local variable for some operation similar on how Svelte directive let:variable being used.
function ColorManager({ children }) {
const colors = ['red', 'green', 'blue']
if (!("colors" in this)) this.colors = colors
return <>
...
children
</>
}
<ColorManager>{({ colors }) =>
<ul>{
colors.map(color =>
<li>{color}</li>
)
}</ul>
}</ColorManager>;
non-JSX DOM builder/factory
Although this feature can be replaced by integrating with other SPA framework, most of them rely on compiler/transformer so there is no harm to experiment new approach.
Hint: check my previous prototype in different repo
Also, always think if certain approach is performance. Think about if JS engine:
Cause deopt like switching from IC to MapRecord
Can opt like auto inline and dce
REJECTED
```ts
type Children = Array<
| Element
| Primitive
| Text
>
interface HTML {
[key: string]: (
$1?:
| Record>
& { $children:
| Children
| Primitive
| Text }
| Children
| Primitive | Text
| ($: SelfElement) => void,
$2?:
| Children // if $1 not Array
| ($: SelfElement) => void // if $1 not function
) => HTMLElement
}
export const
html = new Proxy,
svg = new Proxy
function text(
value: Primitive | Signal
): Text
function text(
str: string[],
val: Primitive | Signal,
): Text
export function text(
$1: (Primitive | Signal) | string[],
$2?: Primitive | Signal,
): Text { }
export let on = {}
export function attrs(
$: Record>
) { }
export function props(
$: Record
) { }
```
```js
import { defer, use } from "wiles/std"
import { html, svg, text, on } from "wiles/dom/fun-runtime"
const { div, button, h3 } = html
function Component() {
const [c, c_] = use(Counter)
function stopAt10 (e) {
if (c.count++ === 10)
msg([h3(10)]) // auto unbind c.count
btn(e.target.type = "submit")
//on.click = null // specific abort listener of e.target
this.abort$() // self abort stopAt10
}
}
let msg
defer(() => assert(msg() instanceof HTMLDivElement))
return div([//
}
```
> **Note**: something not allowed in micro/macro-task inside `el(?, $ => {/*here/*})`
> * add event listener via `on.event = () => {}`
> * append children via `html.el()` or `text()`
>
> but it still ok if doing thats inside `on.event` and `el(?, $ => {/*here/*})`
Ergonomic Island
accessor(value)
factoryiterate(local_accessor, values => {})
custom = accessor.of(_: Array | TypedArray | { set(?), get() })
List()
componentthis instanceof Class
where instance is from@build(Component)
residebind`accessor`
(see SSR/SSG issue)single
accessor(value)
Behind the scene,
accessor(value)
is just a syntactic sugar fornew Accessor(value)
wherewhich the
Accessor
class is unique per scopes of Componentexample
async function and generator
In async generator, each
yield
andreturn
will replace previousyield
. However, normal generator function will behave the same way as Array of \<Component>.Behind the scene, async function is same as async generator where it
yield new Comment(function.name)
before the function isawait
ing.Basically, that \<IPAdress> is same as:
exposing local data when creating children
Expose local variable for some operation similar on how Svelte directive
let:variable
being used.non-JSX DOM builder/factory
Although this feature can be replaced by integrating with other SPA framework, most of them rely on compiler/transformer so there is no harm to experiment new approach.
REJECTED
```ts type Children = Array< | Element | Primitive | Text > interface HTML { [key: string]: ( $1?: | Record