Coder Social home page Coder Social logo

html effect about spect HOT 13 CLOSED

dy avatar dy commented on July 28, 2024
html effect

from spect.

Comments (13)

dy avatar dy commented on July 28, 2024

Recap.

  • $(el, el => {fx()}) acts very similar to with($(el)) { fx() }, meaning that the effect is a feature of wrapped observer. $(el).init(() => () => {}) is the same as $(el, el => {}), mb we could even shrink that syntax to just $(target)[effect](), and then the let aspect = $(el) would indeed return some live-wrapper of all DOM instances ever going to appear, a piece of behavior (unlike jquery one-timer).
  • <${target}></> are possibly prohibited in html, at least not for portal uses, but for indicating order of insertion.

from spect.

dy avatar dy commented on July 28, 2024

De-resolution.
HTM has prohibited <...> tags, besides that adds a dimension of complexity required to learn.
So we're with <div>${el.childNodes}</div> for html reducers. Which makes sense extending to <${el}></>, enabling portals as <${target}></>.
Prohibited reducers remove the drawbacks of unclear reducer context, making html a single entry.

// creates raw html
let els = html`<div></div>`

// mounts html on target
html`<${el}><div></div></>`

// mounts target to html, el can be a fragment/array/fn etc
html`<div>${el}</div>`

// mounts target to html, applies props/children to target
// watch out: `el` is going to have empty children
html`<div><${el}/></div>`
  • not as elegant default effect html<${el}>content</>. (although apparent).
  • useful as independent tool indeed.

Since <${el}/> isn't as elegant and also adds to confusion of wrapping, we can reuse known atomico pattern <host></host>. That allows graceful syntax, scoping inner styles via :host and explicitly separates current context element. Although, that renders plain multiple elements useless:

html`<host><a></a></host><b></b>`
// is effectively meaningless. Does it return just a list of elements?

So again, what's bad about $(el, el => <div></div>)?

  • unobvious where the dom is attached, even confusing
  • complex syntax.

Actually, look again.

let [hostEl, portalEl, fooEl: { children: [bar]}] = html`
<host>...</>
<${modal.container}></><foo>
<bar/></foo>`
// isn't that super-cool way to get refs?

// we can possibly introduce selectors via proxy:
let { '#x': xEl, '.s': sClassEls } = html`...`

// mb even modifying via proxy as
let [x, y, [z]] = html`<x/><y/><><z/></>` // z is first child

Looks brilliant (if that's not an illusion).

from spect.

dy avatar dy commented on July 28, 2024

host is from web-components terminology, no need to engage it here.
For most of nested components returning html works as unwrapped mount:

const Log = (data) => html`<p>${data}</p>`

from spect.

dy avatar dy commented on July 28, 2024

Another turn.
html`<${mount}>content</>` creates contradictory situation where html is no more an effect: $(target).html`now requires wrapping here` - not elegant.
Also, making it anonymous effect creating detached content creates bottleneck on rendering functions:

function A () {
html`<${B}></>`
}
function B () {
// here B can't do DOM diff, it is required to build fully detached raw HTML from scratch.
return html`content`
}

Instead, having pure HTML effect is not contradictory to passing selectors internally.

function A () {
html`<${B}></>`
}
function B () {
// no contradiction, effect is applied to B [custom] element
html`content`
}

So let's opt for html as effect, but returning created content for obtaining refs and portal-mount.

el => {
let [a, b, c] = html`
<a/>
<${B} localTarget/>
<${externalTarget} ...attrs/>
`
}

from spect.

dy avatar dy commented on July 28, 2024

Should multiple html instances rewrite each other, or augment?

el =>  {
html`Current content`
...
html`<${portal}>Content</>`
}

How to provide combined html, and is that required?

? What if we engage yield mechanism for augmented html?

// multiple renders at the time of yield
function* (el) {
yield html`Content`
yield html`<${portal}>Content</>`
}
// single planned render, html replace planned rendering
(el) => {
html`Content`
html`<${portal}>Content</>`
}

Should h render itself instantly on the time of call, or plan total VDOM update by the end of render?

  • instant rendering allows to read reference straight ahead
    ? no clear way to mount on call
  • delayed rendering allows batching and is easier to implement effect
  • delayed rendering corresponds to react practice
  • delayed rendering is confusing if html effect takes place before other effect.

. for throttle and raf there should be separate effects. That should be as easy as raf(fn) - to plan a set of effects for the next frame.
? could we possibly provide update effect, flushing every planned action? Would that be nice?

el => {
<div id='x'>content</div>
render()
let a = el.querySelector('#x')
}
  • no, that doesn't look nice. Better have some h-related renderer:
el => {
html(<div id='x'>content</div>)
let a = el.querySelector('#x')
}

✔ yes, that's right. html should be able to take VDOM as an argument, and h is just a JSX-constructor.

import $, { html, h } from 'spect'
$(app, el => {
html(<div id='123'/>)
})

from spect.

dy avatar dy commented on July 28, 2024

Ok, html is now direct effect again #107.
Unlike other effects, it could be

html`<${el}>...content</>`

So, just global html rerenderer.

Some questions:

  1. What should it return?
  2. How should that render vdom?
  3. How to create new real content?

Some considerations:

  • html is just htm builder
  • html`<${el}></>` returns top element or list of elements

We can do everything via domdiff and fully avoid vdom. What's the price of that?

from spect.

dy avatar dy commented on July 28, 2024

Done as direct morphdom implementation.

from spect.

dy avatar dy commented on July 28, 2024

Deresolution.

html is [anyways] can be an effect with observables, so libs like lit-html aren't directly useful here.

html`<time ${{date}}>${ date().toLocaleTimeString() }</time>`

And it automatically binds to observables.

The consideration is - organization of morphing. If <${el}></>, then morphing classes can be

html`<${el} class=${ clx => [...clx, 'additional-class'] } ${attrs => {...attrs, ...additionalAttrs }}>
${ content => [...content, additionalPiece]}
</>`

from spect.

dy avatar dy commented on July 28, 2024

Another feature of html effect: it creates an observable from all the internal nodes. That allows to create composable streamable structures.

const time = html`<time date=${ date.toISOString() }>${ date.toLocaleString() }</time>`
const post = article => html`<article>${ article.author }${ article.content }${ article.time }</article>`
const articles = map(data, post) // calc((...items) => items.map(item => post(item)), arr(items))
const list = html`<div class="articles">${ articles }</div>`

From here, for list, we need a special structure, returning observable with mapped items.
But in general, instead of dom diffing (mb internally), the effect subscribes to all input observables.

from spect.

dy avatar dy commented on July 28, 2024

Сreates an observable node, that morphs whenever content changes

let div = html`<div>${ content }</div>`

Morphs existing node whenever props or content changes
Passing el === null removes node

let el = html`<${el} ...${props}>${ content }</>`

Can also be useful to map existing props/content?
Or that contradicts to observables?

html`<${el} ...${props => {...props}}>${c => c}</>`

Or should we just guess by default extending existing element's props, instead of forcing template?

html`<${el} additional='a' class='${ clsx => clsx }'></>`

Is there contradiction at all between observable and reducer?

// state
const clsx = state('a b c')
html`<div class=${clsx} />`
// rendering html sets clsx state, so `clsx` is controlled by html
// if we detect that clsx is async iterable, it's possible to stream clsx to html instead

// observable
const obs = o.value('a b c')
html`<div class=${obs}/>`
// here, html should subscribe to obs updates by passing a function into `obs`
// passing value as in reducer scenario would just update obs.

// direct fn
html`<div class=${clsx => clsx}/>`
// similar to ref, but can be useless, because it's not reactive
// that makes the whole html just a 1-time 'setter' effect, which isn't 100% correct 

! This brings to an idea - connecting observables by passing observables into observables:

let count = state(0)
let count2 = state(count) // just a proxy observable
let prop2 = state(prop1) // proxy for prop1
let el = html`<div>${ count1 }</div>` // live element

from spect.

dy avatar dy commented on July 28, 2024

Ok, that takes long.
Essential cases of html:

1. define live template

let article = html`<article class=${clsx} ${prop} ...${props}>${ content }</article>`

This case is clear.

2. hydrate existing html

html`<${target} class=${clsx} ${prop} ...${props}>${ content }</>`

Here it's not clear - the target is extended or forced to this form.
Since redefining all props is impossible, rewriting only passed ones makes more sense.
But then single props ares till overridden. How to extend them too?

// v1. create classes observable
const cl = clsx(target)
cl(c => c + ' additional')
html`<${target} class=${clx}></>`

// v2. just read target classes - target is known anyways
html`<${target} class="${target.className} additional"/>`

// ⚠️ dangerous
html`<${target} ...${target}/>`

So we don't need prop reducers, since target is available.

from spect.

dy avatar dy commented on July 28, 2024

Due to single-call html nature, we don't even need caching statics, that is perfect match for xhtm.

from spect.

dy avatar dy commented on July 28, 2024

Done in 15.0.0

from spect.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.