Giter VIP home page Giter VIP logo

hyperx's People

Contributors

almost avatar anywhichway avatar colingourlay avatar dagingaa avatar diffcunha avatar emilbayes avatar feross avatar finnp avatar goto-bus-stop avatar jamen avatar jameskyburz avatar josephg avatar max-mapper avatar maxkueng avatar mreinstein avatar ngryman avatar nichoth avatar s9k avatar shama avatar siilwyn avatar slaskis avatar tornqvist avatar yerkopalma avatar yoshuawuyts avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

hyperx's Issues

Hyperx does not handle void elements + unquoted attributes correctly

In the HTML spec, some elements are void and don't have closing tags:

Void elements
area, base, br, col, embed, hr, img, input, keygen, link, menuitem, meta, param, source, track, wbr

But in hyperx, when combined with unquoted attributes they cause weird problems:

const hx = require('hyperx')(console.log)
hx`<span><input type=checkbox>some content</span>`

This should generate a span with 2 children (an input element and 'some content'). Instead, it tries to place the content inside the input element.

input { type: 'checkbox' } [ 'some content' ]
span {} [ undefined  /*input*/ ]

If I put quotes around the attribute (<input type="checkbox">) or put a useless space before the close of the tag > then it works:

input { type: 'checkbox' } undefined
span {} [ undefined /*input*/, 'some content' ]

One workaround is to always add quotes, but thats not possible when the last attribute is an event handler, eg this breaks:

hx`<span><input onchange=${myhandler}>some content</span>`

And the event handler doesn't work if its quoted.

Unquoted attributes

Unquoted attributes do not work properly with hyperx at the moment. Example:

const hyperx = require('hyperx')
const vdom = require('virtual-dom')

const html = hyperx(vdom.h)

console.log(html`<button class=test>Does work</button>`)
console.log(html`<button disabled class=test>Does work</button>`)
console.log(html`<button class="test" data-value=test>Does work</button>`)
console.log(html`<button class=test data-value=test>Doesn't work</button>`)
console.log(html`<button class=test data-value="test">Doesn't work</button>`)
console.log(html`<button class=test disabled>Doesn't work</button>`) // Uncaught Error: unhandled: 8

A related issue is with event listeners, which is probably my fault, but I didn't find it explicitly documented anywhere:

console.log(html`<button onclick=${e => alert(e)}>Does alert</button>`)
console.log(html`<button onclick="${e => alert(e)}">Doesn't alert</button>`)

I don't know if this is something that you intend to support. It is part of HTML5, but personally I actually liked XHTML, so I regard this as blasphemy.

Snabbdom Support

Snabbdom uses a hyper-script-like function to build it's vdoms, but it's second argument is different. Instead of attributes it's properties are used by various "modules";

h('div', {
  props: {title: someString}, // snabbdom/modules/props
  classes: {selected: isSelected}, // snabbdom/modules/class
  on: {click: doSomething}, // snabbdom/modules/eventlisteners
  style: {color: someColor} // snabbdom/modules/style
}, ['children'])

The snabbdom-jsx module handles this using prefixed attributes in JSX:

<div 
  title={someString} 
  class-selected={isSelected} 
  on-click={doSomething} 
  style: {({color: someColor})}
>
  children
</div>

Would it be feasible for hyperx to do this as well?

Breaks When Using <br/>

I tried to modify hyperapp's counter example. When inserting a line-break <br/> it broke. 🙁

Console

InvalidCharacterError (DOM Exception 5): The string contains invalid characters.

Minimal Repro

app({
    view: () => html`<div>a<br/>b</div>`
})

Meta

Corresponding issue on hyperapp's repo.
Related to #34.


Note that I do realize that <br> works. <br/> is more explicit though and as a React-user I'd like to keep this pattern.

React components?

How do you handle React components (=function calls)? You could either have a registry for component names or do this:

class EchoComponent {
    ···
}
let comp = jsx`<${EchoComponent} />`;
React.renderComponent(comp, document.body);

Can I become a maintainer on this project?

I'd like to do a major release for hyperx:

  • several fixes for open parsing bugs.
  • optionally consider adopting es6-isms (let, const, etc.)
  • optionally consider es modules since all LTS node versions and most browsers have support now

@substack @goto-bus-stop is this something you'd be interested in? This module underpins a lot of stuff for projects I work on and being able to fix some of the bit rot would be nice, so I don't have to maintain my own fork, and others could benefit too.

XML vs functions

Perhaps a strange place to put this issue, but was wondering why one would prefer the JSX/hyperx/XML API to just using the constructor functions. Do people find it easier to maintain / read / refactor?
I find I pass whole objects around as props in react so often that I'm pretty reliant on spread. I'd rather just pass the object to a function.

How to pass function as child?

👋 hi, wondering how to pass a function to a component. Trying to use the Query component from react-apollo.

const hyperx = require('hyperx');
const { Query } = require('react-apollo');
const gql = require('graphql-tag');
const { createElement } = require('react');

const hx = hyperx(createElement);

hx`<${Query}
  query=${gql`
    {
      // query here
    }
  `}
>
  ${({ loading, error, data }) => {
    // function content here
  }}
</${Query}>`

Returns:

Failed prop type: Invalid prop `children` of type `array` supplied to `Query`, expected `function`.
    in Query

Support for virtual-dom style object

From what I understand virtual-dom expects style property as an object while in hyperx this happens:

var tree = hx`<div style=${{color:'red'}}>`
console.log(tree);
//[Log] VirtualNode {tagName: "DIV", properties: {style: "[object Object]"}...

Feature: adding spread like operator

In JSX you can use spread naturally <MyReactComponent ...props>. I think for hyperx we should support a simple spread operator: <MyHyperxComponent ...${props}>.

I added this already by overriding my createElement function for yo-yo, works great and is super useful. A great little feature. The notation is different enough that it shouldn't effect existing hyperx components, but is super useful for building higher level components that are essentially bypasses.

The only other way to do this is by overriding the createElement methods of other libs like yo-yo and bel. Not very nice really.

Love hyperx, best.

Self-closing tag error

As of a few hours ago I've been getting an error (TypeError: Failed to execute 'appendChild' on 'Node': parameter 1 is not of type 'Node'.) when using self-closing tags. I think it had something to do with the last release (2.5.3).

Full trace:

TypeError: Failed to execute 'appendChild' on 'Node': parameter 1 is not of type 'Node'.
    at Object.convert (/src/node_modules/jsdom/lib/jsdom/living/generated/Node.js:749:11)
    at DocumentFragment.appendChild (/src/node_modules/jsdom/lib/jsdom/living/generated/Node.js:280:29)
    at Object.createFragment (/src/node_modules/nanohtml/lib/browser.js:96:14)
    at /src/node_modules/hyperx/index.js:152:44
    at html (/src/myfile.js)

Sample code (using Nanohtml):

const element= html`
        <div />
    `;

Rollup

I use Rollup to bundle my code. I use it so I can organize a project's code as ES6 modules. I can't seem to find a way to import Hyperx with Rollup. I've successfully used other NPM modules with Rollup, so I'm assuming its something about how hyperx is getting exported.
I'd like to be able to do the following:

import {hyperx} from  'hyperx'
const html = hyperx(h)
// etc

But I'm not having any luck.
I am using rollup-plugin-commonjs with rollup, so that's not the issue:

commonjs({
  include: 'node_modules/**'
})

But when I build, I get this error in the console:

Error: 'hyperx' is not exported by node_modules/hyperx/index.js

Any idea how to be able to use hyperx with Rollup like a normal ES6 module?

Boolean attributes

@substack: Is there a way to write boolean attributes, such as checked on <input type="checkbox"/>?I've tried various combinations of keys and values, and I can't get anything passed through to the wrapped hyperscript function.

SVG Support?

Would you be open to a PR adding SVG self closing tags? Or a PR that exposes the self closing tags so one could supply their own?

Such as:

var hyperx = require('hyperx')
var hx = hyperx(function (tag, props, children) {
  /* ... turn into thing ... */
}, {
  selfClosingTags: ['circle', /* ... */]
})

var circle = hx`<svg viewBox="0 0 100 100">
  <circle r="${r}" />
</svg>`

Here is a good list of svg elements. Thanks!

SVG elements with children

Issue

hyperx is not allowing many SVG elements to have animation-related tags embedded in them.

Both of these examples reproduce the issue:

const rectNode = html`<svg><rect>
        <animate attributeType="CSS" attributeName="opacity" 
                from="1" to="0" dur="5s" repeatCount="indefinite" />
        </rect></svg>`

//Markup by Aurer on Codepen: http://codepen.io/aurer/pen/jEGbA
const spinnerNode = html`
        <div class="loader loader--style1" title="0">
        <svg version="1.1" id="loader-1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
        width="40px" height="40px" viewBox="0 0 40 40" enable-background="new 0 0 40 40" xml:space="preserve">
            <path opacity="0.2" fill="#000" d="M20.201,5.169c-8.254,0-14.946,6.692-14.946,14.946c0,8.255,6.692,14.946,14.946,14.946
                s14.946-6.691,14.946-14.946C35.146,11.861,28.455,5.169,20.201,5.169z M20.201,31.749c-6.425,0-11.634-5.208-11.634-11.634
                c0-6.425,5.209-11.634,11.634-11.634c6.425,0,11.633,5.209,11.633,11.634C31.834,26.541,26.626,31.749,20.201,31.749z"/>
            <path fill="#000" d="M26.013,10.047l1.654-2.866c-2.198-1.272-4.743-2.012-7.466-2.012h0v3.312h0
                C22.32,8.481,24.301,9.057,26.013,10.047z">
                <animateTransform attributeType="xml"
                attributeName="transform"
                    type="rotate"
                    from="0 20 20"
                    to="360 20 20"
                    dur="0.5s"
                    repeatCount="indefinite"/>
            </path>
        </svg>
        </div>`

In the 1st example, Hyperx is treating the and tags as sibling elements.
In the 2nd example, Hyperx is treating the 2nd and tags as siblings.

It seems to be a fairly common technique for animating SVGs, based on Codepen examples and articles like this: https://css-tricks.com/guide-svg-animations-smil/

Is this something that could be allowed?

Multiple self-closing children causes nested children tree

While writing some tests for #33 I found that when using multiple self closing children in a parent it nests them.

In other words this:

<div>
  <div />
  <div />
</div>

Results in a nested tree like this:

<div>
  <div>
    <div></div>
  </div>
</div>

Another find, which is also in the tests, was that the whitelisted self-closing tags (such as <br>) instead causes an exception when written as a open tag, like <br></br>. Which might be correct, but the exception message (Error: multiple root elements must be wrapped in an enclosing tag) was a bit confusing.

Self closing tag whitelist vs blacklist

First of all, this is awesome. It lets me work on my electron app with jsx-like code without having any build step. It's great!

I'm just curious as to why self closing tags are whitelisted.

Because right now when I'm a bit lazy (or rushed) I just want to write <div id=bla /> when I know it won't have any children, but then it breaks the dom by not closing it. The fix is easy of course, just close it like <div id=bla></div> but it still gets me every time.

I'm sure there's a reason, obviously there is a nice opportunity to be able to validate the code, so we don't try to put children into a etc.

Another case which I'm currently playing around with an idea in my app to have custom component tags by registering the components (as opposed to the suggestion in #9) and replacing tagName with it in the rendering function, like this:

// hx.js
const {h} = require('preact') 
const render = hyperx(hr)
render.register = register
module.exports = render
const components = {}
function hr(tagName, attrs, children) {
  return h(components[tagName] || tagName, attrs, children)
}
function register(component) {
  components[component.name] = component
  return component
}

// Component.js
const hx = require('./hx')
const Component =({onClick}) => hx`<div onClick=${props.onClick} />` // <-- this i would like to be able to "self close" like this
register(Component)

// Parent.js
const hx = require('./hx')
const Parent = props => hx`<Component onClick=${props.onClick} />` // <-- this i would like to be able to "self close" like this

The bad part about this right now it that I have to require all the components somewhere, not necessarily where they're used (unlike when using it like in #9 or in React).

If there's some interest in flipping the whitelist to a blacklist instead (not allowing children for elements which don't support children) I'd love to give a PR a try.

idea: hyperxify

mithril has mithrilify and riot.js has riotify, perhaps we could have a hyperxify for hyperx?

This would save a flat 5kb minified / unminified per bundle, and some execution time too.

I'm currently not working on frontend stuff, so posting this here in case anyone has some spare time and reckons it'd be fun to build ✨

edit: also worth noting: this removes the hard dependency on multiline string support available in browsers; pretty useful when targeting older systems!

Feature: Allow tags to be set as variables

It would be interesting if tags could be set as variables

const tag = 'div'
const tree = hx`
  <${tag} arg1="foo">
    <span>child</span>
  </${tag}>
`
class Component extends HTMLElement { ... }
const tree = hx`
  <${Component} arg1="foo">
    <span>child</span>
  </${Component}>
`

This could help building support for web components using hyperx

Related to #9

Feature: allow custom optional closed tags

In react a custom component can be notated like this: <MyCustomComponent />, in hyperx you have to notate is like this <MyCustomComponent><MyCustomComponent>.

I would like to notate optionally closable, non-html tags that could or could not be closed at the end.

So I would register with hyperx these in opts, under optionallySelfClosing: []. If they are closed (i.e. ending with />) then they are treated as closed tags. If they are not (i.e. ending in >) then they have children and are not yet closed.

Another way would be to have a loose setting in opts. Where any tag, html or otherwise could be optional open or closed. However, this seems like more work to implement.

Example with properties not working?

var vdom = require('virtual-dom')
var hyperx = require('hyperx')
var hx = hyperx(vdom.h)
var title = 'hello';
var tree = hx`<h1 y="ab${1+2}cd">hello ${title}!</h1><div style=${{color:'red'}}>`
console.log(vdom.create(tree).toString())

In node.js

//<h1 y="ab3cd">hello bla!</h1>

In FF, Chrome, Saf on OSX

//[object HTMLHeadingElement]

Also in the browser the resulting DOM doesn't have y property.

Allow custom attrToProp function

Would it be a good idea to allow attrToProp to accept a function? That way as a user I can transform the needed attributes. I'm mainly asking this because the hyperscript-attribute-to-property dependency is missing basic attributes like srcset & seems unmaintained. Secondly it does not include SVG attributes like stroke-linecap which in my case are used directly in the templating.

Boolean `false` converted to string "false"

This makes it difficult (or impossible?) for a virtual DOM engine to determine whether the user meant false or "false".

html`${true}` // yields true
html`${false}` // yields "false"

screen shot 2017-02-17 at 1 02 04

If this is indeed determined to be a bug, I'd be delighted to help with if you'd be so kind to offer some help by pointing out where should I start looking in the code.

Cheers! 👋

undefined attribute values are converted to strings

When attribute values are undefined or null they are appended as strings 'undefined' or 'null'.

For example this code:

var none // unassigned
hx`<li.item class=${none}>...</li>`

Will result in html like this:

<li class="item undefined">...</li>

Whereas virtual-hyperscript will ignore the value and not add it to the class list.

I'm not sure if this is the correct behavior, but i expected it to do the same as virtual-hyperscript. This can be achieved by the developer by supplying a custom concat function, or by ensuring that undefined values are never used, but i think this should be handled by default?

If it is a bug, I think it can be fixed in the concat function, by making undefined parameters default to empty strings (''). However maybe there is a better way to do it?

react: key warnings

I seem to be getting a lot of key warnings when using hyperx with react. Here is an example that generates a key warning but shouldn't really:

const React = require('react')
const hyperx = require('hyperx')
const hx = hyperx(React.createElement)

hx`<div><a href="#">link</a></div>`

If I add a key to the anchor tag the warning goes away - but I shouldn't really need to do that.

Any solutions to this?

fails if undefined value is passed

The following code returns an error:

var foo = undefined
hx`<h1>${foo}</h1>`
Uncaught TypeError: Cannot read property '0' of undefined

I think there are two ways of resolving this:

  1. null and undefined values are treated as blank (e.g. yield <h1></h1>)
  2. null and undefined values are treated as errors that should never be rendered, and an appropriate error message is thrown

I think my preference goes out to option 1, as visual quirks in UI are generally non-critical; though perhaps there are good arguments for option 2 which is probably more correct.

How to handle multiple roots?

Right now, this will throw the error multiple root elements must be wrapped in an enclosing tag if more than one root element are given.

For nanohtml it would be pretty great to support multiple root elements, probably using DocumentFragment.

However it seems to me like all hyperscript-style modules also don't support multiple roots. There is a proposal, but it was never implemented: hyperhype/hyperscript#37

I suggest that maybe for now, we can allow an option on hyperx like createFragment. If it's spacified hyperx will call that function with the array of nodes instead of throwing an error.

The change would simply be:

      if (opts.createFragment) return opts.createFragment(tree[2])
      throw new Error(
        'multiple root elements must be wrapped in an enclosing tag'
      )

Then whoever uses hyperx (like nanohtml) could do something like for example:

function createFragment (nodes) {
  var fragment = document.createDocumentFragment()
  for (var i = 0; i < nodes.length; i++) {
    if (typeof nodes[i] === 'string') nodes[i] = document.createTextNode(nodes[i])
    fragment.appendChild(nodes[i])
  }
  return fragment  
}

hyperx(createElement, {
  comments: true
  createFragment: createFragment
})

I just tried this and it seemed to work, but I want to get some feedback first :)

is there any interest in a pure es modules PR?

It would be great to publish an experimental/alpha build of hyperx that is a pure es module (no commonjs.) It's still experimental in node v14 but if we were to publish a tagged package it might enable more experimentation.

Would you be open to a PR? Happy to submit one.

API doesn't match for virtual-dom - no way to set attributes?

Hi

If am creating a tree that includes a webcomponent which updates on attributeChangedCallback. However, through hyperx, all specified attributes end up being passed to virtual-dom as props, because attributes need to be all passed together within an attributes sub-object.
Currently with a view like below:

return html `<my-web-component class="${className}"
                            data-src="${src}"
                            style="display:flex;width:${width}px;height:${height}px">
                        </my-web-component>`

...all the three attributes end up being assigned directly to the DOM element rather than via setAttribute.

I realize this is perhaps because virtual-dom does not adhere to the hyperscript API (as specified, h(tagName, attrs, children), when virtual-dom actually takes h(tagName, props ={attributes: {} }, children)). But if hyperx shouldn't be expected to account for these differences, then the documentation should probably be updated to let people know it won't work as expected with virtual-dom specifically and save some time :) Thanks!

Is it possible to add some kind of opt-in for hyperscript-attribute-to-property?

Currently:

hx`<div class="hi">Hello</div>`

Produces (using a hyperscript-like function):

{
  children: ["Hello"],
  data: {
    className: "hi"
  },
  tag: "div"
}

This requires your vdom engine to check if data has a className prop and use class instead, otherwise you end up with HTML elements that have both class and className attributes.

On the other hand, JSX correctly yields:

{
  children: ["Hello"],
  data: {
    class: "hi"
  },
  tag: "div"
}

Related:

TypeScript support

This might not be possible but I'm wondering if anyone had success with type checking the ES6 tagged template string. Before hyperx, I wrote something similar called typed-tmpl which type checks the variables but check the html such as a missing an angle bracket like the TSX syntax does.

Has any had success with validating the HTML in the string?

Delegated Events

I see that you can create inline event handlers on individual elements. This is fine for simple things. However, it you are creating a complex UI with a lot of user interaction, this is not efficient. Say you have a list with a hundred or more list items, each of which might hold several actionable buttons. That would result in hundreds of events being registered. Is there some way to register delegated events?

Leading and trailing whitespace

Leading and trailing whitespace currently gives an error about only having one root component. For example:

hx`
  <div>Hello</div>
`;

Will result in an error. I think it would be a good idea to add code that removes leading and trailing whitespace IF there is a component in between them. I can send through a PR if you think that's a good idea.

inline <style> tags that include direct descendant css selectors break parsing

oy.js:

var vdom = require('virtual-dom')
var hyperx = require('hyperx')
var hx = hyperx(vdom.h)


const tree = hx`<div>
   <style>
       .test > ul {
          background-color: red;
       }
   </style>
</div>`

const r = vdom.create(tree).toString()
console.error(r)

output:

➜ node oy.js

<div>
   <style> ul {
          background-color: red;
       }
   </style>
</div>

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.