¡Rompiendo las reglas con
<web-components/>!

Adrián González Rus

Software Crafter

BBVA Next Technologies

EmberJS Madrid Organizer

Pero... ¿Qué es un web component?

<input>

<video>

<audio>

<track>

<source>

<embed>

Composición

<web-component/>

#shadow-root

<div>Content</div>

¡A desarrollar!

class MyComponent extends HTMLElement {}
customElements.define('my-component', MyComponent);
<my-component/>
HTMLAudioElement
HTMLVideoElement
HTMLTrackElement
HTMLSourceElement

¡A Implementar!

const shadowRoot = element.attachShadow({ mode: 'open' });
shadowRoot.innerHTML = '<span>This is my content!</span>';
const template = document.getElementById('my-template');
const templateContent = template.content;

shadowRoot.appendChild(templateContent);
class MyComponent extends HTMLElement {
    constructor() {
        super();

        const shadowRoot = element.attachShadow({ mode: 'open' });
        const template = document.getElementById('my-template');
        const templateContent = template.content;
        
        shadowRoot.appendChild(templateContent);
    }
}

ALTERNATIVAS

Hybrids

FRameworks convencionales

y si... <framework-component>

antes de nada...

..CICLO DE Vida

class MyComponent extends HTMLElement {
    constructor() {}
    connectedCallback() {}
    disconnectedCallback() {}
    attributeChangedCallback() {}
    adoptedCallback() {}
}

Componentes en Ember

<!-- my-button.hbs -->
<style>
  button {
    background: #209cee;
    color: white;
    padding: 2rem 4rem;
    border: 0;
    font-size: 1.5rem;
  }
</style>
<button>Esto es un botón</button>
{{my-button}}

manos a la obra

class MyComponent extends HTMLElement {
    connectedCallback() {
        const shadow = this.attachShadow({ mode: 'open' });
    }
}
class MyComponent extends HTMLElement {
    connectedCallback() {
        const shadow = this.attachShadow({ mode: 'open' });
        const template = compileTemplate('{{my-component}}');
        const component = renderTemplate(app, template);
    }
}
class MyComponent extends HTMLElement {
    connectedCallback() {
        const shadow = this.attachShadow({ mode: 'open' });
        const template = compileTemplate('{{my-component}}');
        const component = renderTemplate(app, template);

        shadow.appendChild(component);
    }
}

atributos?

eventos?

Poco a poco...

..slots

<my-component>
   Esto es un texto de contenido
</my-component>
shadowRoot.innerHTML = '<slot></slot>';
<my-component>
   <span slot="header">Cabecera</span>
   <span slot="body">Mensaje</span>
</my-component>
shadowRoot.innerHTML = `
   <slot name="header"></slot>
   <slot name="body"></slot>
`;

paso de atributos

<my-component title="Mi Component"/>
const title = element.getAttribute('title');
const title = element.getAttribute('title');

shadowRoot.innerHTML = `<span>${title}</span>`;
{{my-component title='Mi componente'}}

Conectando atributos

connectedCallback() {
   // ...
   const controller = Controller.create();
   const component = renderTemplate(controller, template);
   // ...
}
connectedCallback() {
   // ...
   const controller = Controller.create();
   const attrs = element.getAttributeNames().map(attr => 
      `${attr}=${attr}`).join(' ');
   const template = compileTemplate(
      `{{${componentName} ${attrs}}}`);
   const component = renderTemplate(controller, template);
   // ...
}
attributeChangedCallback() {
   element.getAttributeNames().forEach(attr => {
      const value = element.getAttribute(attr);

      controller.set(attr, value);
   });
}

paso de mensajes

const event = new CustomEvent('onClick', {
   detail: 'Se ha producido un click',
});

element.dispatchEvent(event);
element.addEventListener('onClick', value => {
   console.log(value)
});

ember cli web components

Pero... ¿cómo funciona?

Ember App

Ember Addon

Bundle.js

integración en una app

<script src="bundled.js"></script>
defineCustomElements({
  'my-web-component': {
    name: 'my-ember-component'
  }
});

DEmo time

Conclusiones

¿</preguntas>?

Made with Slides.com