- rasa
- dew
- water
- humidify
- sprinkle
- va
- soma
- ley
- ros
- dewdrops
- mtn-dew
- pores
- drips
- straw
- spores
- spor
- spores
- russian
- spor
- sport
- spore
- sporae
- scottish twist
- sounds russian-ish too
- a bit unusual from API perspective...
- similar to algae
- dots associate with colon prefix
- spour
- sprae?
- reference to sporae and similar assoication
- simpler word
- better assoc with hydration
- spree
- spread
- sprinkle
- better meaning
- stands out less than sprae
- aerosol
- sprea
- inherits sprae
- prea(ct)
- spree and spread
- something priya
- anagram: parse, spare, spear
- river: https://en.wiktionary.org/wiki/Sprea
- spring
- sprae has nice ae ligature
- sprae is closer to spray
- sprae is closer to a verb
[x] :attr, :data, :id, :class, :style, :on, :aria - do we enforce JS syntax or support unscoped expression? -> Use JS convention, too many use-cases.
- JS object
- JS object can directly set value as
:props="obj"
- JS object is a bit verbose
:props="{a:1, b:2}"
,:on="{click(e){}, touch(e){}}"
- It's very explicitly JS, no confusion must be introduced
- It makes HTML look a bit more noisy
- It is more familiar
- JS syntax saves redundant questions and an item from docs
- Custom expressions
- We anyways introduce custom-ish expression in
:each="item in items"
- Vue introduces simple-ish parsing for that
- Custom expressions are shorter:
:attr="a:1, b:2, c:3"
- Custom expressions are confusing for style:
:style="a:1, b:2, c:3"
- very similar to direct style string
:=obj
reminds pascal assignment operator, which is cool:={a:1,b:2}
is natural convention from vue/alpine as - all props in object are assigned as:{attr}
- We can use
:="{data}"
fro sprae autoinit, since scope has confusing name::scope={}
,:sprae={}
,:with={}
-> let's use :prop= for now, since:={}
can have multiple interpretations
[x] Scopes mechanism: prototype inheritance chain vs multiple with
wrappers -> init subtrees, no need for explicit mechanism
- prototype inheritance chain causes deps update difficulties
- prototype chain is messy-ish
- prototype chain is a bit more difficult to provide multiple parent scopes
- prototype state object is inheritance mess - can be super-hard to analyze
~
with(a) with(b) with(c)
is the same aswith(a)
with prototype inheritance in terms of access. with
chain allows runtime update of scopes, eg. child scope was updated to something new.prototype
chain is fixed from the time of init.
prototype
chain hails to unidentified root scope and inherits from that. Maybe we should clarify scopes inhertiance and first implement reactive store (see next item).
? what if we avoid scope inheritance mechanism (what's the real use for it?) and instead just make reactive store object, so that :with directive subscribes to any input props, but "shadows" subtree? ? are there uses for inheritance
? Do we need scopes at all? Only for the purpose of autoinit?
- it seems scopes can introduce more confusion and mess in templates: indicating full paths is more beneficial
- unless we introduce proper ":with="item.x as x""
- prototype chain is a single object:
- meaning updators receive one actual-for-element scope instance
- that makes external API easier
- that allows handling store via single reactive object
-> possibly we have to just subscribe via mechanism of signals-like deps, and :with just initializes subtree with extended object
- Get rid of :with
+ with is bad JS practice/association
+? is there a bona-fide use case?
+ the implementation is heavy/unoptimal: two assign-updates happen: for root, for children
+ it is exception blocking streamline implementation of refs
+ it shadows data which creates all sorts of nasty debugging effects / states. Isn't it better to keep data/state transparent?
- it even enables transparency of :each scopes, since they inherit root scope
+ it's easier to look out for data in one single place (state init), rather than in a bunch of markup locations
+?! can be replaced with sort of
<x :xyz="xyz=...calc"></x>
, no? -> would need wrapping noname scope access +:with
defines too many concerns:
- binds root updates -> child updates;
- binds child updates to root updates (writes);
- defines local variables
- aliases root variables
? is there value in all of these concerns? It seems we need only local variables, isn't it? Is there a chance partial extension can be required?
-
:with
can provide situational variables that are useful for props precalculation (since these variables can be reactive.) - eg.
<span class="preloader" :with="{str: ''}" :init="setTimeout(() => str+='.', 500)" :text="str" />
- that plays role of watch that doesn't require to be outside of local component state.
-
:with
allows local component state not cluttering global state. There's really no way to define local state that doesn't affect global state. 1.1 Slim:with="{a,b,c}"
- just initializes vars - Doesn't give easy init syntax + Convevtional and not hard to implement
- it even enables transparency of :each scopes, since they inherit root scope
+ it's easier to look out for data in one single place (state init), rather than in a bunch of markup locations
+?! can be replaced with sort of
- Use
:let="x, y=2"
? + Doesn't pollute scope but instead cleanly declares local variables + Indicates only local initializer, not subscription + Liquid hasassign
tag{% assign myVar = false %}
- it only initializes variable + Djangowith
performs only alias / complex calc access https://docs.djangoproject.com/en/4.1/ref/templates/builtins/#with - it doesn't sync up global state. ? call it:define="x, y, z"
? -> it seems:with="x=1, y=2"
works well.:let
has dissonance with js'y let. ? how to extend state :with.x="1", :with.y="2"
+ easier to parse, since init code can be messy
[x] Should we inherit values from init
in sprae(el, init)
, instead of creating a snapshot of reactive values in init
? -> nah, nice idea but too little use. Better create signals struct.
- it allows passing any arbitrary scope to initialize from.
- it can make hard finding reactive sources...
- it is sort-of neat pattern: object parent updates its particular state: it can also have observable method making object a store -> can be delegated to a separate functionality - init just gets converted to reactive store
- it sort-of makes
init
directly a scope (a parent of scope), which is more natural-ish rather than 2 independent entities - can pass both observables and direct state anywhere, eg. init child components from it -> worthy of a separate library, signal-struct?
[x] Per-directive initialize vs per-element initialize -> directives can immediately initialize rest on elements
- Per-directive is very simple and trivial approach
- Per-directive doesn't read attributes order and init directives independently ~ Practically linear in-order init doesn't make much service either here
- Per-directive is a bit hard to deal with scopes -> gotta benchmark, vs just walker. -> seems unavoidable to combine :if within :each, since :each should remove elements and init on find only
? what if we use preact/signals to subscribe only to required props? -> parseExpr is going to need to be handled by core.js (not directives), and detect & subscribe to dependencies itself -> so that directive updator gets invoked only when any of expr dependencies change -> gotta solve via signal-struct
:else :if=""
is meaningful expansion of both directives:else :if
is coming from JS:else :if
doesn't throw error in JSDOM tests
- less resemblance with vue: who cares, we already remotely resemble it
-> No: first, there's :class directive changing the class itself; -> Second, there's easier way to just "evaporate" directive = not initialize twice; -> Third, there's too much pollution with class markers
- introduces malign hole of including sprae inside of html
- nah: can easily be done manually as
:html="this.innerHTML = abc"
. Just need passing context
- let's wait for use-case
- doesn't necessarily useful, since any directive is already an effect
- works already out of box, just creates
fx
attribute if value is returned
- waiting for use-case
-> it's better to init element via js than via inline code. Gotta add
:oninit
event.
- opens gateway to generic modifiers
- introduces a whole mental layer to learn, including combinations of modifiers all around.
- can be conflicting with event classes.
- too adhoc-y
- can be easily done as
:onkeypress="e => e.key === 'Enter'"
-> waiting for use-case
? do we really need typecast?
- it can be done manually as
:key="Boolean(abc)"
this === element
+ Allows this.innerHTML and other customs- Can be done easily via
:ref="xxx"
- External handlers don't have access to refs. + Existing convention
- Can be done easily via
this === scope
- scope is not supposed to be extendible - scope is already available + methods provided ininit
may not have access to scope yet. ~- not reliable way to obtain scope viathis.x
- better be explicit asstate.x
[x] :onconnected/:ondisconnected? -> nah, just use noname effect or external functionality eg fast-on-load
- can be useful for :if, :each handlers, eg to start animation when element appears in DOM.
- it is not connected-disconnected: it has nothing to do with document: it attaches/detaches from parent.
- connected-disconnected is too long name
? attach-detach?
? onmount-onunmount?
- slows down domdiff
- can be solved as
<x :if="xxx" :="xxx && (...)'">
automatically
- useful for :if, :each
- useful to dispose listeners via :onunmount (opposed to hidden symbols)
- doesn't really solve disposal: if element is attached again, it would need to reattach removed listeners -> can be dolved via teardowns returned from updators -> nah, event listeners don't need collection, just make sure no refs to element remain
- can be useful for lazy-loadings
- makes proper use-case for direct code events
- doesn't make sense for rective properties inside
- better fit for special props like
:mount
- tons of new special-meaning namespace props
-
focus/blur, connected/disconnected, mousedown/mouseup, keydown/keyup, touchstart/touchmove/touchend, dragstart/dragover/dragend, animationstart/animationover/animationend, transitionstart/transitionend ? is there a way to organize handlers for chains of events?
- :onfocus:onblur="e => e => {}"
- :onblur looks more like a pseudo
- a bit better distinctive visually, less noisy
- combining root-level attrs them doesn't seem very intuitive for fn waterfall.
- :onfocus-blur="e => e => {}"
- ? is there dash-events? looks like a single event
- ? why not :on-focus-blur
- ? why not :onfocus-onblur
- can be converted from on="{ focusBlur: event }" via dash notation
- messy error messages
- less :on prefixes
- has better "flowy" meaning
- 2.1 :onfocus-onblur="e => e => {}"
- distinctive visually as 1
- flowy nature of 2
- blocks
:onfile-attached
and other dashed eventsona-onb
vsona-b-onc
is hard to parse mentally
- :onfocus.onblur="e => e => {}"
- looks like a modifier
- . can be used as event class onclick.x
:onfocus--blur="e => e => {}"
- reminds BEM
- reminds BEM
:onfocus..blur="e => e => {}"
- reminds range
- literally means start..end
- all pros of 2.
- reminds spray via dots
- can be confusing if
blur
is event or just property (can that be a property?)
:onfocus..onblur="e => e => {}"
- all props of 5.
- more obvious that blur is event.
:onfocus="e => e => {}"
Keep registered pairs of events: just expect focus return blur, etc.
- Shorter syntax
- Avoids :onfile-attachment-accepted problem
- Less verbose and explicit
- No way to customize sequences, eg. custom events
@sprae/tailwind:<x :tw="mt-1 mx-2"></x>
- separate tailwind utility classes from main ones; allow conditional setters.- @sprae/item:
<x :item="{type:a, scope:b}"
– provide microdata- can be solved naturally, unless there's special meaning
- @sprae/hcodes:
<x :hcode=""
– provide microformats - @sprae/onvisible?
- can be solved externally
- @sprae/onintersects
- Since we support attr walking, maybe instead of :on and :prop just allow any attributes?
- that would allow event and attr modifiers...
- that would allow somewhat alpine/vue-compatible code
- makes sense for
:="{}"
spread - makes place for other specific directives
:init=""
etc
? :model="value"
- v-model, x-model
- confusing ? :in="text" ? :input="text" ? :bind="value"
- more accurate logically
- conflicts with existing naming (bind is used for attrs)
- conflict if used along with
:value="x" :bind="y"
-> :value="value" :onchange="e=>value=e.target.value"
- more apparent and explicit
- less mental load, "model" is too heavy term
- overhead is minimal
- react-like
- it has better control over serialization
:onchange:oninput="e=>xyz"
is very good
- What for? We anyways expose almost everything.
- To make eval safer.
- we cannot provide absolute safety anyways
- To make eval safer.
- Use subscript?
- solves access to any internal signals on syntactic level
- can tentatively be faster than signal-struct
- could tentatively get rid of struct and just use signals as input ~ Yep, it's a bit weird template converts data into some reactive state. Just expose an update method instead and current state like useState hook. This way you can avoid exposing signal-specific functions.
- Provides precisely controlled sandbox
- Some limited lang opportunities
- need to match many syntax quirks, can be tedious ~ can be fine to limit expressions to meaningful default: no Proxy, generators, awaits, global access etc.
- Somewhat heavy to bundle
~ 1-2kb is not super-heavy, besides kicks out signal-struct (with preact signals?)
- compared to including signals maybe not as much
- Allows detecting precisely deps from syntax level, not deep-live-detection, which can be unwanted
- Allows creating optimized evaluator, without proxy
- Scope is easier to provide: no need for signal proxy
- Can detect access errors in advance
- Syntax-level access to signals can be inavoidable: external signals still "leak in" (via arrays or etc.).
- Updating simple objects should also rerender the template parts, not just signals.
- Deps can be analyzed / implemented without signals
- Screwed up debugging / stacktrace (unless errored properly)
~+ can actually provide better trace since no internal framework stuff is shown
- can let means to enhance subscript's logs
- that "unlimits" returned struct, so that any property can be added/deleted.
- doesn't really save from
new (()=>{}).constructor
hack: we gotta substitute objects too. ~ Proxy doesn't save from that either ~+ we can prohibitnew
and braces/functions in general, straight fn bodies
- allows easier handle of
:with="a=1,b=2,c=3"
- we just naturally get local variables without messup with global- we can even define locals without
let
...
- we can even define locals without
- not having "comfy" compatible JS at hand: cognitive load of whole language "layer" in-between
~
:each
is not js anyways- it's unsafe feeling (also CSP) having JS straight in attributes
- there's certain hacks and limitations to JS anyways (we can't use let,const,var)
- there's some established convention for jessie, justin, jsep etc.
- not having full JS can be a good practice and protection agains unnecessary stuff
- that can be a very common syntax
- allows
let a = 1; a;
case instead oflet a = 1; return a;
- we can't identify dynamic parts like
x[y]
, whereas Proxy subscribe dynamically ~ we can detect dynamic parts and handle them on proxy- at least we know about dynamic reads
- subscript allows subscriptions to async functions, unlike signals
+? we can detect
array.length
, not sure what for
- SO that can be a simplified subset of JS, like Jessie or Jason
-> We can benchmark if updating set of known dependencies is faster than using preact subscriptions.
- it seems more logical min-ground to know in advance what we depend on, rather than detect by-call as signals do.
- it's safer not to depend on external tech, considering there's so much competition and changes in reactive land ~ it indeed takes some reactive-struct, capable of notifying which paths have been changed ? maybe define setters such that when they're set
- Use sandboxed proxy
- tougher evaluation
- no full protection (Function.constructor)
- relatively slow
- does minimal catch
- allows scope control
- allows dynamic subscription to requested fields ( no need for preact/signals neither for signal-struct )
- we anyways need sandbox even in case of subscript
- It causes recursion in
:x='array.push(x)'
- Ignore arrays as insubscribable
- allows signals-only store (signal-struct)
- fastest
- ignores array mutations, unless explicitly called
0.a Abandon returning single-property store, in favor of batch-update
- Simpler API
- Very precise diff-update
- No need for batch method
~ essentially encourages signals-proxy or proxy, since
- why not exposing proxy as just props-access, that applies throttled batch-update (collects multiple updates and runs batch after)
- since API allows only batch, why not allowing signals as single-prop entries
- Detect when
.length
is called within.push/protoMethod
via method wrapping
- doesn't solve generic implicit subscription, like
buf.write()
that calls implicitly subscribablebuf.size
- Detect from source by subscript
- limited syntax
- heavier to bundle
- messy stacktrace
- no comfy js at hand
- doesn't detect dynamic subs like
calc().length
- Signals struct
- fastest
- limits access to not-existing props
- seals object
- no circular update trouble
- doesn't handle arrays -~ no sandboxing -~ no dynamic props
- Proxy
- any-prop access, including not-existing
- modern-ish
- own tech
- allows handling arrays
- some mess with .length subscription
- doesn't take in individual signals
- slow-ish ~ must be improved
- some mess with proto access ~ must be improved
- no circular update detection
- allows detecting precisely what array ops were performed, to apply corresponding DOM updates
- Signals proxy
- medium performance
- no proxy store mess
- subscriptions handled via signals (proved)
- circular update detection
- heavy-ish
- not own tech
- hi-quality though
- doesn't solve recursive .length out of the box ~ alleviated by tracking
- Subscript-based something
- Eg. we pass simple object, not store.
- Subscript wraps prop access into reading
.valueOf()
, so we don't have to deal with signals in templates - Or we can even expose signals as-is, since they cast to their value in expressions and whatnot
- Subscript wraps prop access into reading
- that solves issue of CSP
- that detects globals in-advance
- that gives anticipated store schema
~ there's no update via proxy, reactivity is only via signals
- fits web-components case -~ problems of subscript above
- doesn't solve live arrays: they can only be signals
~+ which can be more explicit of what's going on
~ implies swapdom since full-array gets updated every time
~ can be better for updates than full-update as it is now
- we anyways enforce full-update for object changes
- we must subscribe to each item from the list - it should update itself only, not the whole list. How?
-
Async reconciliation part - it plans list rerendering (loop part) in the next tick, and this tick may have as many item changes as needed
-
Individual effects per-item
fx(() => {updateItem(list[idx])})
- Can be created in advance, and list updates only cause effects changes
- Nested effects: parent effects don't get subscribed in internal effects, so we just modify :each to create multiple internal effects per-item.
- we might not need swapdom, since nodes manage themselves
- note the untracked function
- compatible with direct
onclick=...
- no need for arrow/regular functions syntax in templates
- still need that syntax for filters, maps etc
- can be made async by default
- illicit
event
object- we don't seem to ever need that event argument, many cases are covered by
.prevent
or.stop
~+ generallye=>
seem to conflict logically with modifiers sense
- we don't seem to ever need that event argument, many cases are covered by
e=>
brings syntax burden - we may not ever need functions- less problem detecting
const/let
in code
- less problem detecting
- conflicts with regular attrs logic: the code is immediately invoked and can assign a function.
:oninput="e => (handleCaret(e), updateTimecodes())"
~:oninput="handleCaret(event), updateTimecodes()"
:onbeforeinput="handleBeforeInput"
~:onbeforeinput="handleBeforeInput(event)"
:ondragenter..ondragleave:ondragenter..ondrop="e=>(this.classList.add('w-dragover'),e=>this.classList.remove('w-dragover'))"
~:ondragenter..ondragleave:ondragenter..ondrop="this.classList.add('w-dragover'), e=>this.classList.remove('w-dragover')"
:ondrop="e=>console.log(e.dataTransfer.types)||e.preventDefault()"
~:ondrop.prevent="console.log(event.dataTransfer.types)"
:onfocus="e => (e.relatedTarget ? e.relatedTarget.focus() : e.target.blur())"
~:onfocus="event.relatedTarget ? event.relatedTarget.focus() : event.target.blur()"
:onpopstate.window="e => goto(e.state)"
~:onpopstate.window="goto(event.state)"
:onclick.toggle="play"
~:onclick.toggle="play()"
[x] Should we introduce @click
for short-notation events? -> let's keep :onx
for raw events, @x
for normal events
- gives shorter code for majority of cases
- can be non-conflicting
- compatible with all frameworks (vue, alpine, lucia, lit)
- gives better meaning to modifiers - moves them outside of
:
attribute
- multiple events
@input@change="code"
is not nice ~ that's fine and even meaningful - chain of events
@focus..@blur="return (e)=>{}"
creates confusingreturn
outside of body, as well as inconsistent chain pattern ? remove that pattern- it's still unsatisfactory:
@mousedown.document..@mouseup.document="e=> (isMouseDown = true, e=> isMouseDown = false)"
works, but what if we want to add@touchstart..@touchend
, or .@click..@click="play" @keydown.alt-space..@keydown.alt-space="play"
, so in other words we need cross-reaction@click_or_altspace..@click_or_altspace
, not just one single chain.- actually here
@click@keydown.space..@click@keydown.space
is possible, unlike:ona..onb
case, the question is how to provide sequence in attribute - the thing is that local state, introduced by initiator events, is not useful by itself, detached from scope.
. the state is better reflected in data scope, rather than by initiator event.
? what about temporaries like
@a..@b="id=setTimeout(),()=>clearTimeout(id)"
or@a.toggle="stop=play(),stop"
. use:with={id:null} @a="id=setTimeout()" @b="clearTimeout(id)"
- actually here
- it's still unsatisfactory:
- introduces illicit
event
variable ~ although compatible with standard, still obscure @
prefix is unchangeable ~ can be removed, not set, but still on the verge.@click.toggle="code"
has same problem as@a..@b
- how can we make code separation in attribute?- remove toggle
- overall less code
- Consider
:onclick..onclick="play"
:onkeydown.document.alt-space..onkeydown.document.alt-space="play"
- When started by click and ended by alt-space, it doesn't clear the onclick
- We actually want here
:onclick:onkeydown.document.alt-space..onclick:onkeydown.document.alt-space
.- this makes inconsistency of
..onclick
- colon is missing - also it makes precedence of
:
and..
unclear - what comes before what after.
- this makes inconsistency of
? Can we use :onclick.toggle="play"
?
- it doesn't help with switch-over
? Some 'or' character :onclick--onkeydown
? We can redirect to main event, that's it for now
- shorter and nicer syntax
- possibly longer init
- :ref="
a-${1}
" - 🆔ref="xyz"
:id
is string,:ref
is var name ? maybe id should have same signature ? should it be very similar mechanism to:with="a=1,b=2"
~ ref must be possible as:fx="x=this"
- returning non-null sets effect prop
- ref can have predefined signal as value, then signal must be set, not directly prop
- .prevent,.stop - not needed since expects a function
? or should we just trigger it for user?
? :onclick.outside
? :onclick.window, :onclick.document
- can be needed, eg. mousedown..up can happen outside of current element (stop caret tracking in waveplay) ? :onclick.once, :onclick.passive, :onclick.capture
- can pass props to event listener: there's no other way to do that ? :onclick.debounce-330 ? :onclick.throttle-750
- ...just handy everydayers and saves tons of noise ? :onclick.self ~ clicked on self, not the child ? :onspecial-event.camel, :onx-y.dot ~ ? :onkeypress.shift.enter, :onmousemove.shift, :onmousemove.alt .shift Shift .enter Enter .space Space .ctrl Ctrl .cmd Cmd .meta Cmd on Mac, Windows key on Windows .alt Alt .up .down .left .right .escape Escape .tab Tab .caps-lock Caps Lock .equal Equal .period Period .slash Foward Slash
- allows separating various key handlers: atm waveplay handles separate keys in the same method
handleKey
- allows tracking mouse interactions with shift hold
- conflict with dot-separated events ~not so popular nor encouraged
- lots of ad-hoc non-standard rules, can be handled in code
- allow multiple setters for same props or multiple listeners for same events
- oldschool jquery-compatible events
- Event modifiers
- onevt.x, onevt.y
- jquery-like
- multiple same events
- onevt.once, onevt.passive, onevt.capture
- standard props passing
- onevt.prevent, onevt.stop
- conventional mods
- onevt.outside onevt.window, onevt.document, onevt.self
- useful handlers, conventional mods
- onevt.throttle-xxx, onevt.debounce-xxx
- conventional
- onevt.shift, onevt.cmd.shift, onevt.meta
- conventional
- onkey.enter, .space, .up|.down|.left|.right, .escape, .tab, .period, .slash, .caps-lock
- conventional
- onkey.nexttick
- seems to be needed, but what's the name?
- onkey.tick, onkey.nexttick, onkey.next,
- onkey.after, onkey.microtask, onkey.defer, onkey.immediate
- onkey.tick-1?
- onevt.x, onevt.y
- overall seems code complication without much benefit
- value.bind? value.watch?
- let's wait for use-case: value can be too big to set it every time
- prop.reflect, prop.observe
- let's wait for use-case
- prop.boolean, .number, .string, .array, .object
- let's wait for use-case
- prop.once, prop.fx ? prop.init?
- doesn't seem required, let's wait for use case
- prop.change - run only if value changes
- seems like unnecessary manual optimization that must be done always automatically ? are there cases where force-update is necessary?
- prop.throttle-xxx, prop.debounce-xxx
- let's wait until that's really a problem
- prop.class ? what's the use-case
- prop.next="" - run update after other DOM updates happen
- prop.fx="" - run effect without changing property
- x.prop="xyz" - set element property, rather than attribute (following topic)
- x.raf="abc" - run regularly?
- x.watch-a-b-c - update by change of any of the deps
- :x.always - update by any dep change
- :class.active="active"
- :x.persist="v"
-
:x="abc"
creates property + attribute - can be excessive pollution -
.x="abc"
~:x.x=""
writes both property and attribute... - conflicts with class selector - blocks dot-separated values - breaks convention of reserved namespace via:
2.1 _x="abc"
- conflicts with _target="blank"
-
:.x="abc"
+ keeps convention + compatible with:on*
- can be a bit too noisy syntax -
:_x
+ reference to "private" - conflicts with:_target="blank"
-
:x="this.x=value"
+ yepyepyep
- Makes easy use of repeatable fragments, instead of web-components
- sort-of "detached" for-each
- reinforces :ref ? does it replace element or puts a content?
- Refs:
- https://github.com/justinfagnani/html-include-element - src=
- https://www.npmjs.com/package/imported-template - content=path-to-file
- https://github.com/SirPepe/html-import src="content.selector"
- https://github.com/Juicy/juicy-html - html="rawhtml"
- https://www.npmjs.com/package/html-import-wc - src=path
- https://github.com/sashafirsov/slotted-element - src=path-to-htmlor-json
- https://github.com/webcomponents/html-imports - href=filepath
- https://github.com/giuseppeg/xm - import src=filepath
- https://github.com/ProjectEvergreen/greenwood/tree/master/packages/plugin-include-html#link-tag-html-only
- https://github.com/maherbo/include-HTML-document-fragment - link href=path
- https://github.com/github/include-fragment-element - src=path-to-html
- :use="ref-id"
<template :ref="abc" id="abc"><span :text="abc"></span></template>
<div :use="abc" :with="{abc:'def'}"></div>
<div :use="'#abc'" :with="{abc:'def'}"></div>
<use>
from SVG replaces element, but we need inserting content
- :content="#template-id"
- conflicts with direct inline content
- :include="#template-id"
- conflicts with path to file
- :tpl="#template-id"
- some confusion of meaning
- :render="#template-id"
- compatible with liquid 5.0
- makes sense as :render=a :with=b
- Let's think consequently.
<template>
element has direct purpose for that- We provide content fallback for unloaded elements in case of
:text
as<x :text="abc">fallback</x>
- There's too many ways to implement fetching - ideally we leave that concern out and focus only on including content
- The approach is almost ready declarative custom element.
<template>
is standard part of it - adds to 1.
- :scope="{$template:xxx}"
- like petite-vue
- some special prop is needed
- :aria - can be defined via plain attributes
- :data - confusable with :scope, doesn't provide much value, can be used as
:data-x=""
etc - :={} - what's the meaning? Can be replaced with multiple attributes, no? No: no easy way to spread attributes.
[x] let/const in expressions: allow or prohibit -> let's prohibit, force user to wrap into a function himself
- allowing forces wrapping internally, which creates return statement confustion
- Parent state can dynamically obtain new signal, and nested states won't have access to that
- Since exposing signals in templates didn't seem to have worked well, we can predefine state values instead of creating a proxy.
- props would need to be predefined in advance
- it must simplify tracking new props in object (we just prohibit that)
- less API
- anyways updating every prop reflects DOM update immediately, there doesn't seem to be a big win
- multiple props can be combined into computed signal or called manually via batch
- subscript-based parsing
- see subscript-based store analysis, mainly CSP, justin limits, better access to source, better internal JS
- :with -> :scope
- with has bad associations
- :scope potentially allows for
$template
property - :scope is alpine, vue compatible
- Get rid of
:on
events - attributes are no-fn expressions - Get rid of sprae.auto
- No-batch
- No store, directly signals