hypermedia-app / lit-any-views

@lit-any view elements for functional building of complex HTML
https://lit-any.hypermedia.app
MIT License
1 stars 0 forks source link

A better way to define render templates #1

Open tpluscode opened 5 years ago

tpluscode commented 5 years ago

The fluent style API does not really work well. Simply put, it's rather ugly when used directly. Instead, it'd like something more vue-like maybe.

Currently it is

import Templates from '@lit-any/lit-any/views'

Templates.default.when
  .scopeMatches('collection-item')
  .valueMatches((value) => value.type === 'collection-item')
  .renders((item) => {
    return html`${item}`
  })

The syntax is not nicely readable and a definition is also tightly coupled with the registry. Separating them would allow simple reuse.

tpluscode commented 5 years ago

For example using default export

// item-template.js

export default {
  scope: 'collection-item',
  valueMatcher: (value) => value.type === 'collection-item',
  template: (item) => {
    return html`${item}`
  }
}

This would then be appended to the template registry

import Templates from '@lit-any/lit-any/views'
import itemTemplate from './item-template.js'

Templates.default.import(itemTemplate)

In case of multiple templates, exported as name values, it would be done as

import Templates from '@lit-any/lit-any/views'
import * as templates from './collection-template.js'

Templates.default.import(templates)
tpluscode commented 5 years ago

In terms of reuse, reusing parts of the definition would be possible by simple object spread

const sharedDefinition = {
  scope: 'collection-item',
  valueMatcher: (value) => value.type === 'collection-item'
}

export default {
  ...sharedDefinition,
  template: (item) => {
    return html`${item}`
  }
}
tpluscode commented 5 years ago

@jerben would you welcome such API change? do you have any suggestions?

tpluscode commented 5 years ago

Another idea: add a function call context to the declaration so that functions can be extracted from the render body

{
  getItemHtml(item) {
    return html`<span>${item.name}</span>`
  }

  render: array => {
    return html`${array.map(this.getItemHtml)}`
  }
}

It would also be good to extend the context with at least an event dispatch method, bound to the nearest lit-view.

{
  clicked(e) {
    this.dispatchEvent(new CustomEvent('do-something'))
  }

  render: array => {
    return html`<button @click="${this.clicked}>Click me!</button>`
  }
}