-
Notifications
You must be signed in to change notification settings - Fork 109
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
a standard hyperscript API #66
Comments
This is probably a good idea. I think this wants a test suite that all those listed modules can pass. |
wow great idea!
+1 to that! :) I would have a use-case to plug |
Perhaps we should cc the creators of the other libraries into this as well? |
To make things tangible, I would like to propose to have (1) a standard "strict API" that libraries have to conform to, and (2) "lax APIs" that allows for more flexibility to the user, which can differ from library to library. The more flexible lax APi can be more convenient for the user to code the view manually, but can be a pain to fully implement and properly test and can easily become a source of bugs. Also likely various libraries will have their own opinions on different flexibility options. For the strict API, I would propose the closest one to the HTML structure:
|
Good idea. Just a note, as a snabbdom (a virtual DOM) library user, this assumption does not apply:
because |
Here is the proof of concept with very simple implementation of the extension of |
hey @dmitriz, awesome! for context, my motivation for this issue is more than just standardizing
and maybe also what do you think about this? |
why would events need to be seperate? they'd just be anything with an |
Thanks @ahdinosaur, I see what you mean. <input type="text" onkeypress="doSomething();"> So the closest API in the HyperScript would be h('input', {type: 'text', onkeypress: doSomething}, []) or in the single object (Abstract Node) notation h({tag: 'input', props: {type: 'text', onkeypress: doSomething}, children: []}) That way both attributes and events are treated equally in a simple flat object, and their names will never clash by the mere HTML design, so there will never be any confusion. That would also apply to React's vDom goes a bit further by introducing some non-native conventions that sometimes feel a bit like solutions to their problems 😈. For instance, their famous Snabbdom treats events slightly differently by grouping them inside the Just my few cents. |
i'm not sure how these are treated the same way... the problem is that hypescript is the DOM, not HTML, and there are many differences between the DOM and HTML.
that's how a many hyperscript implementations do events, so yes this is a legitimate approach. however i think it adds complexity because then you have many special cases to handle. so maybe a good way to describe my proposal is that it acknowledges the difference in behavior between keys in |
True, the |
Having However, having to define That ship may have sailed though, considering all existing implementations. |
@Michael-Zapata Would be interesting to hear the opinion from @lhorie, Mithril's creator. It seems most libraries keep their virtual node events directly on the props, notably React (and hence Preact, Inferno etc.). Snabbdom is one of the few doing it, where you have to write h('button'
, {on: {click: () => pipeToActions(increment)}}
, `Modify score by ${increment}`
) instead of h('button'
, {onclick: () => pipeToActions(increment)}
, `Modify score by ${increment}`
) where the latter feels less cluttered and without the annoying double braces. It might be slightly more work for the library writer (but then also can be less work without having to manage the nested structure), but at the end the library is only written once. On the other side, the shorter way will benefit the user and result in considerable code reduction, given how many times it is used. |
Hi, Mithril author here. Sorry I'm a bit late to the party. IMHO, the base API should support at a minimum what JSX compiles to, as it makes it super easy for anyone to plug it into babel via a pragma, and it's how a lot of people use Mithril and Preact. Personally, I'm not a JSX person, but I've witnessed a number of people express in the past that they would not use a hyperscript without JSX. In terms of API variations, the landscape is a bit all over the place. As was already pointed out, Snabbdom has a nested map of events instead of inline in the props/attrs object. If you consider React.createElement a hyperscript, it doesn't support CSS selectors, and for that matter, even optional props/attrs. The level of CSS selector support also varies across other implementations (Mithril, for example, supports There are variations in how attributes are handled, with some implementations allowing The variations go further in regards to support for HTML namespacing and SVG/MathML, React being one that has unusual naming edge cases. Mithril uses the Mithril also includes support for properties such as Another aspect where hyperscript implementations vary is in terms of varargs support, i.e. Many implementations have special vnode types. Mithril has a fragment type (basically, a range of elements can be keyed and have lifecycle hooks) and a trusted HTML type (i.e. Another significant aspect is component support. Mithril, React, Preact and friends support components as first args (again, because of JSX), but some systems don't have the concept of components at all (e.g. Snabbdom). Component hooks have different names, and their APIs vary very significantly, especially when it comes to APIs related to state and children. Mithril and inferno support hooks at the vnode level. If you're going to support it, I'd recommend baking it in. The For For With regards to attrs vs props, as far as DOM elements are concerned in Mithril, attrs are typically always attrs and data usually get into hook functions via closures. Components are where things get a bit murky, where props are usually data-oriented but they might also include HTML attributes (typically |
hey, should the .outerHTML method be part of this standard API?
Reasoning: if you're using some little framework designed for hyperx -for example-, but want to use hyperscript instead, then the framework calls toString() when it server renders and you get [object Object] (outerHTML is the right choice) |
I very much like the idea of a single object to define the element h(opts: HyperscriptOptions = {}, ...children: HTMLElement[])
// use this overload if the first parameter is an HTMLElement, default options.tag to 'div'
h(...children: HTMLElement[]) const el = h({
tag: 'a',
attr: {
href: 'https://gogogo.com',
'data-whatever': 'sweet!'
},
styles: {
// this is of type: ElementCSSInlineStyle
},
events: {
onclick: console.log
}
innerHTML: '<strong>Ok</strong>'
}, h())
document.body.appendChild(el) makes <a href="https://gogogo.com" data-whatever="sweet">
<div>
<strong>Ok</strong>
</div>
</a> |
hey,
i think
hyperscript
is great, it's a simple functional way to compose html trees, which has led to a vibrant ecosystem. but in this vibrant ecosystem, each module has a slightly different API.i'm interested in creating a standard
hyperscript
API. with this we could have standard tests that any hyperscript-compatible module must pass. (similar to:abstract-leveldown
,abstract-blob-store
,abstract-chunk-store
,test-flumelog
, etc)so how do we come up with a standard?
i'll try some history:
hyperscript
: the OG module:h (tag, attrs, [text?, Elements?,...])
tags
could bename.class1.class2#id
attrs
could be any positional arg (!)attrs
can be either html properties, attributes, or event listeners. is automatically inferred by the namevirtual-hyperscript
:h(selector, properties, children)
properties
is optional, otherwise arguments are fixedkey
andnamespace
ev-
hyperx
:<div a=${b}>...</div>
hyperscript-attribute-to-property
bel
:h(tag, props, children)
hyperx
, so has all fixed argumentsonevent
props as event listenersnamespace
mutant/html-element
:h(tag, props, children)
props.events
or inprops
with key starting withev-
props.attributes
props.hooks
props.style
is same ashyperscript
@skatejs/val
:h(tag, props, ...children)
props.events
props.attrs
i could go on, given all the many many virtual dom modules, but that's a start.
so here's my proposal (based on my own
hyps
):a
hyperscript
-compatible module is of shape:open questions:
parse-class
mutant/lib/parse-tag
mutant
does this (based onvirtual-hyperscript
): an array of functions ("hooks") called when element is added to the dom. if hook returns function, that will be called when the element is removed from the dom.style
property as a string, but do we support objects and if so, in what format? (camelCase like react or css names or)anyways, there's my brain dump. what do other people think?
The text was updated successfully, but these errors were encountered: