codemix / babel-plugin-hyperhtml

Babel plugin which compiles JSX into hyperHTML
MIT License
12 stars 2 forks source link

Enabled slotted invokation: proposing a new transformation #3

Closed WebReflection closed 5 years ago

WebReflection commented 5 years ago

As explained in here, I'd like to know if there's any interest in improving the current transformation or if I should just fork this and try to make it work as intended.

There is a little, but huge, change that opens doors for this transformation in a pretty seamless way.

JSX

const { Component, bind } = hyperHTML;

class Rando extends Component {
  render() {
    return this.html(
      <Sub value={1 + this.props.rand} />
      <Sub value={2 + this.props.rand} />
    );
  }
}

class Sub extends Component {
  render() {
    return this.html(
      <div>
        Value <strong>{this.props.value}</strong>
      </div>
    );
  }
}

const render = bind(document.body);
render(
  <div>
    <Rando rand={Math.random()} />
  </div>
);

should become

const { Component, bind } = hyperHTML;

class Rando extends Component {
  render() {
    return this.html`
      ${node => {
        const comp = Sub.for(node);
        comp.props = {value: 1 + this.props.rand};
        return comp.render();
      }}
      ${node => {
        const comp = Sub.for(node);
        comp.props = {value: 2 + this.props.rand};
        return comp.render();
      }}
    `;
  }
}

class Sub extends Component {
  render() {
    return this.html`
      <div>
        Value <strong>${this.props.value}</strong>
      </div>
    `;
  }
}

const render = bind(document.body);
render`
  <div>
    ${node => {
      const comp = Rando.for(node);
      comp.props = {rand: Math.random()};
      return comp.render();
    }}
  </div>
`;

enabling the following features:

How to transform

The rule is pretty simple:

<ComponentName attr1={123} attr2=456 attr3={what('ever')} />

Should become

${node => {
  const comp = ComponentName.for(parent);
  comp.props = {attr1: 123, attr2: 456, attr3: what('ever')};
  return comp.render();
}}

So that attributes would be passed as props.

The Template Literal rules

The JSX surrounding parenthesis will mark the beginning and the end of the Template Literal, and holes found outside components should be replaced by ${} instead of {} so that this:

render(
  <div onclick={event => alert(event.target)}>
    <Comp stuff={'cool'} />
  </div>
);

would become

render`
  <div onclick=${event => alert(event.target)}>
    ${node => {
      const comp = Comp.for(node);
      comp.props = {stuff: 'cool'};
      return comp.render();
    }}
  </div>
`;

I hope all details are clear enough.

TBD

I am not sure it makes sense to pass along children, since each component can create those directly in the render method, and use props to define children, i.e.

<ComponentName sub={['first child', 'last child']} />

So, actually, I think for the time being having just the proposed transform would be awesome.

Thank You !!!

You had this idea and I'm trying to make it happen for the whole hyperHTML user-base, which I'm pretty sure would appreciate the possibility of using JSX to simplifying lightweight components usage in hyperHTML instead of Custom Elements.

Thanks in advance for considering this or, eventually, for sharing your thoughts on this.

Best Regards.

Code Pen live here https://codepen.io/WebReflection/pen/MPxBzJ?editors=0010

WebReflection commented 5 years ago

P.S. a simplified shortcut could also be:

${node => Object.assign(Sub.for(node), {
  props: {value: 1 + this.props.rand}
}).render()}
WebReflection commented 5 years ago

apologies I've just realized the received node is not necessarily the parent and it's also already unique per invocation so that the static id part is simplified.

Editing the initial request right after posting this.

WebReflection commented 5 years ago

it's "clean up" duty time, closing all my issues that never had an update 👋

Please add a deprecated / abandoned info in the README, thanks.