neighbour-hoods / design-system-components

Storybook and UI component library for the Neighbourhoods design system.
0 stars 0 forks source link

Developer ergonomics pass for existing component interfaces #16

Closed pospi closed 10 months ago

pospi commented 1 year ago

Some of this looks a bit rough around the edges, I think we could improve what's there to get more flexible and idiomatic component syntax.

NHButton is a good example. It has a clickHandler and a label property:

<nh-button clickHandler=${this.dispatchCreateNeighbourhood} label="Create Neighbourhood"></nh-button>

but actually it would be nice if this was an event listener and syntactically similar to a regular <button> element:

<nh-button @click=${this.dispatchCreateNeighbourhood}>Create Neighbourhood</nh-button>

If such attributes were declared as event listeners it would also make them easier to test (see https://storybook.js.org/blog/interaction-testing-with-storybook/).

Where possible, components which service similar functionality to built-in DOM elements should mimic their interfaces.

adaburrows commented 11 months ago

Since some people may need a little pointing at the resources, here's the relevant links and a simple little example:

Slots

Events

// Simple custom button that uses a slot to accept the inner content
class CustomButton extends HTMLElement {
  constructor() {
    super()
    this.attachShadow({mode: 'open'})
  }

  connectedCallback() {
    this.updateComponent()
  }

  updateComponent() {
    const shadow = this.shadowRoot.innerHTML = `<button><slot>LABEL UNDEFINED!</slot></button>`
  }
}

customElements.define('c-b', CustomButton)
const p = document.createElement('p')
document.querySelector('body').appendChild(p)
p.innerHTML = `<c-b>This is a button</c-b>`

// NOTE: We are just listening to the even of the top level element, and we never actually need to listen to for the inner button event unless we had to do something extra before re-emitting the event.
document.querySelector('c-b').addEventListener('click', function(e) {console.log(`Clicked: ${e}`)})

Remember the @click=${this.something} property in the Lit html template is just a shortcut for addEventListener('click', this.something) after selecting the rendered HTML.

adaburrows commented 11 months ago

I've started to compile resources on the basics of web components and their interactions with various libraries here: https://hackmd.io/@adaburrows/B1_J1eKep

For now, this goes into detail on how web components work in vanilla JS and Lit along so the similarities are laid out quite clearly. Soon, it will go into the differences between Vue, Svelte, and React; but this should be quite good for now. There will be a test. ;-)

nick-stebbings commented 11 months ago

@adaburrows Had a read of that yesterday. It was very illuminating. Especially for the custom elements stuff!

adaburrows commented 11 months ago

Fantastic! I'm glad it was helpful. I'm hoping the section on how the Svelte, Vue, and React frameworks can be embedded inside a web component or can use web components (with workarounds for React < v19) will also be helpful.

nick-stebbings commented 11 months ago

Click handler, label ergonomics fixed in #23 and implemented in launcher latest PR feature/nh-home-styles