Closed dy closed 5 years ago
Hey dy,
Just want to shout out. Thank you for inspiration! I borrow a few ideas for my own lib.
🤟FTW, vuhg
✌️
You're welcome.
I saw pung, looks interesting.
Although I chose implicit react-like subscriptions over explicit, like R.oberve
/subscribe
, and less technical things like registering
.
That was the subject of API design research.
I'm re-writing at the moment 😅. It will be something like this.
const app = make('div', (props, el) => {
el.attr('class', 'container'); // static attributes
el.prop('class', props.isDark && 'is-dark' ); // binding attribute or prop
el.state('loading', true)
R.when([el.didMount], () => {
// loading or run anim
})
R.when([el.willMount], () => {
// unsubscribe
})
el.watch(model) // trigger incremental-dom patch if model change
el.html`some header code`;
el.html`some main code`;
el.html`some footer code`;
// make.p`some text`.style('color', 'blue').style('padding', '16px')
// there will be slots too
});
// static html, for static content, no binding or reactive
const staticButton = make.button`Hello World!`.css(``).render
render({
where: '#app',
app: app,
props: { isDark: false },
// router
// store
})
Your spect
remind me SwiftUI, which make me rethink and decide to rewrite.
I'm watching your repo with great interest. Keep up the great work!
Nice! I had these design considerations too, but opted for merging props & el
(props, el) => {...} // → (props) => {...}
in favor of direct element props - el
is props
in native DOM, and custom elements literally assign props
to el
, so that would be also react-compatible
make('div', (el /* which is props */) => {
el.attr('class', 'container'); // static attributes
el.prop('class', props.isDark && 'is-dark' ); // binding attribute or prop
el.state('loading', true)
But then to provide effects like attr
, prop
, ... you need some "wrapper", that was initially in your code as el
. But jQuery pattern is perfect for that purpose: $el = $(el)
.
Also I like your symbols approach for identifying lifecycle events to trigger hooks:
R.when([el.didMount], fn)
I had these considerations in https://github.com/spectjs/spect/issues/66#issuecomment-524059032, even started implementing custom async behavior. But turned out that time is just a form of "domain" - usually we work with "spatial" domains, like DOM, storage etc. - but, by analogy stream is array distributed in time, - async behavior is just another "effect" for time domain (hope that makes any sense :)) To explain a bit better
el.attr('class', 'container'); // attr is "attributes" domain
el.prop('class', ...) // prop is "properties" domain
// there can also be any other domain
el.state() // element state domain
el.html() // html domain
el.class() // classList domain
el.css() // styles domain
el.data() // dataset domain
el.local() // local storage domain
el.remote() // remote storage domain, with async write etc.
el.repo() // fancy: github repository domain
...
el.on() // events domain (distributed in time)
el.raf() // animation frame domain, also distributed in time
el.connected() // lifecycle domain - distributed in time
// ↑ so that's logically the R.when([el.didMount])
While I like React Component composition idea, i don't like its hooks or states management.
React's front-page states:A JavaScript library for building user interfaces
.
So i stay away from react-compatible idea.
So props, el
idea is from Vue 3's design, props, context
.
function make(tag, fn) {
return (props) => {
const el = View(tag)
// other stuff
fn(props, el)
// other stuff
return el
}
}
const app = make('div', (props, el) => {})
app({ /* some props*/ })
Thinking about event in time easier than hook lifecycle. That is why i don't like on, connected, mounted
. el.didMount
is a signal, event (observable object) that allows you to subscribe.
I would refer to have local, repo
should be in spect/utils
or spect-utils
.
I would like to use:
import { raf } from 'spect'
raf(() => {
// schedule some animation
})
Your ideas are interesting, i will spend some time to read your issues and steal some. Hehehe. (I will mention you credit, of course.) I would love to chat with you about this if you have time. Discord: vuhg_3000
Hm, can't find you in discord.
I very much like the spect-utils
, usually wholesome packages are better than a bunch of plugins, in terms of usability/bugs/friction.
As for global effects - the first design was just pure global effects. I liked it pretty much.
import $, { fx, html, state } from 'spect'
$('.target', el => {
let { count=0 } = state()
html`seconds: ${ count }`
setTimeout(() => {
state({ count: count++}) // the problem
}, 1000)
})
The problem here comes in async call in setTimeout
. The global state
effect in no way can figure out what element that state belongs to. For that, async callstack support is required, which is not available by default in browsers.
Besides, context-free effects create difficulty switching context within an aspect:
// this is canvas2D-like way to switch context for effects
$(target, el => {
context(external)
// ...effects
context(el)
// ...effects
})
That ↑ idea (#42) is problematic with async calls too.
So everything indicates (#86) for now that using Proxies for wrapped collections is the most livable solution.
Sorry, I'm vuhg_3000#1842
and my email is hi at v8dot1.me
.
8.0.0 is atomic, the matter of enhancing atomic effects.
Spect is ok, but needs drying up / making some things right.