Componentes com AngularJS

Mais poder ao HTML com AngularJS

guiseek@gmail.com

HTML

HyperText Markup Language

Tags

  • Palavras entre parênteses angulares
  • Marcação semântica
  • Hierarquia de elementos
  • Atributos e seus valores

Exemplo

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title></title>
    </head>
    <body>
        <header></header>
        <nav></nav>
        <main>
            <section>
                <article></article>
            </section>
            <aside>
            </aside>
        </main>
    </body>
</html>

Exemplo sem semântica

<div>
  <div>26/09/2016</div>
  <div>III Semana de Informática</div>
  <div>
    <span>UTFPR</span>
    <div>
      <span>Via Rosalina Maria dos Santos, 1233</span>
      <span>Campo Mourão</span>
      <span>Paraná</span>
    </div>
  </div>
</div>

Exemplo com semântica

<div itemscope itemtype="http://schema.org/Event">
  <div itemprop="startDate" content="2016-09-26T08:00">26/09/2015 08:00</div>
  <div itemprop="name">III Semana de Informática</div>
  <div itemprop="location" itemscope itemtype="http://schema.org/Place">
    <span itemprop="name">UTFPR</span>
    <div itemprop="address" itemscope itemtype="http://schema.org/PostalAddress">
      <span itemprop="streetAddress">Via Rosalina Maria dos Santos, 1233</span>
      <span itemprop="addressLocality">Campo Mourão</span>
      <span itemprop="addressRegion">Paraná</span>
    </div>
  </div>
</div>

Web Components

WTF?!

Web Components é composto de várias tecnologias distintas. Você pode pensar em Web Components como widgets de interface de usuário reutilizáveis que são criados utilizando tecnologias Web abertas. Eles fazem parte do navegador, e assim eles não precisam de bibliotecas externas, como jQuery ou Dojo. Um componente da Web existente pode ser usado sem escrever código, simplesmente adicionando uma instrução de importação para uma página HTML. Componentes Web usam novos ou ainda recursos em desenvolvimento do navegador.

  1. Custom Elements
  2. HTML Templates
  3. Shadow DOM
  4. HTML Imports

Web Components consiste nestas quatro tecnologias (embora cada uma possa ser usada separadamente):

Custom Elements

Nomes e scripts criados pelo desenvolvedor.

HTML Templates

Designers e Front-enders na view (HTML, CSS e/ou JS) e engenheiros na lógica e integração com uma API server-side.

Shadow DOM

Parte do código encapsulada e escondida pelo browser.

HTML Imports

Custom elements empacotados e lidos como um recurso.

Exemplo

<template>
    <p>Hello <strong></strong> :)</p>
</template>

<script>
(function(window, document, undefined) {
    var thatDoc = document;
    var thisDoc =  (thatDoc._currentScript || thatDoc.currentScript).ownerDocument;
    var template = thisDoc.querySelector('template').content;
    var MyElementProto = Object.create(HTMLElement.prototype);
    MyElementProto.who = 'World';
    MyElementProto.createdCallback = function() {
        var shadowRoot = this.createShadowRoot();
        var clone = thatDoc.importNode(template, true);
        shadowRoot.appendChild(clone);
        this.strong = shadowRoot.querySelector('strong');
        if (this.hasAttribute('who')) {
            var who = this.getAttribute('who');
            this.setWho(who);
        }
        else {
            this.setWho(this.who);
        }
    };
    MyElementProto.attributeChangedCallback = function(attr, oldVal, newVal) {
        if (attr === 'who') {
            this.setWho(newVal);
        }
    };
    MyElementProto.setWho = function(val) {
        this.who = val;
        this.strong.textContent = this.who;
    };
    window.MyElement = thatDoc.registerElement('hello-world', {
        prototype: MyElementProto
    });
})(window, document);
</script>

Exemplo de uso

<!doctype html>
<html>
<head>
    <meta charset="utf-8">
    <title><hello-world></title>
    <script src="webcomponents.min.js"></script>
    <link rel="import" href="hello-world.html">
</head>
<body>
    <hello-world who="Unicorn"></hello-world>
</body>
</html>

Como posso me aventurar?

Polymer

Lib polyfill

Web Components

Grupo de discussão

Ooou...

AngularJS

HTML é ótimo para declarar documentos estáticos, mas vacila quando tentamos usá-lo para declarar visualizações dinâmicas em aplicações web.

 

AngularJS permite estender elementos HTML para a sua aplicação.

 

O resultado é expressivo, legível e rápido para se desenvolver.

JavaScript The Right Way

Criado pelo Google, Angular.js é como um polyfill para o futuro do HTML.

Não sou eu quem está dizendo...

Camadas

  • Controllers
  • Services
  • Factories
  • Directives
  • Providers
  • Components

MVC ou MVWhatever

Dependency Injection

Data binding

Módulos e Componentes

A criação de módulos e componentes ficou fácil, por consequência disto, atualmente uma busca no NPM por angular retorna 9.373 packages e crescendo a cada dia.

Angular Component

Com AngularJS, um componente é um tipo especial de diretiva que usa uma configuração mais simples que é adequada para uma estrutura de aplicativo baseado em componentes.

Isto torna mais fácil escrever um aplicativo de forma semelhante ao uso de web components ou utilizando o estilo de arquitetura com aplicação Angular 2.

Vantagens

  • Reutilização de código no seu web app ou em futuros
  • Seguir padrões de novas tendências do mercado

Exemplo de Web App simples

<!doctype html>
<html ng-app>
  <head>
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.7/angular.min.js"></script>
  </head>
  <body>
    <div>
      <label>Nome:</label>
      <input type="text" ng-model="seuNome" placeholder="Seu nome">
      <hr>
      <h1>Olá {{seuNome}}!</h1>
    </div>
  </body>
</html>

Mais poder com diretivas do AngularJS

<div ng-controller="UsuarioCtrl as ctrl">
  <form ng-submit="ctrl.submit()" name="usuarioForm" novalidate>
    <div>
      <label>Usuário<label>
      <input type="text" name="usuario" ng-model="ctrl.usuario" ng-minlength="5" ng-maxlength="10" required>
      <div ng-show="usuarioForm.$submitted || usuarioForm.usuario.$touched">
        <div ng-show="usuarioForm.usuario.$error.required">Preencha seu nome.</div>
        <div ng-show="usuarioForm.usuario.$error.minlength">Deve ter mais de 5 caracteres.</div>
        <div ng-show="usuarioForm.usuario.$error.maxlength">Deve ter menos de 10 caracteres.</div>
      </div>
      <div>
        <button type="submit" ng-disabled="usuarioForm.$invalid">Salvar</button>
      </div>
    </div>
  </form>
</div>

Componentes

Como o AngularJS lida com manipulação do DOM e renderiza UI/Componentes reutilizáveis.

Desde trechos HTML simples até componentes complexos com comportamentos específicos definidos pelo desenvolvedor.

Angular Component

Vamos ver como funciona um componente

Entradas e Saídas

Isolamento escopo só vai tão longe, porque angular usa two-way bindings. Então, se você passar um objeto para um componente desta forma:

bindings: {item: '='}

E modificar uma de suas propriedades, a alteração será refletida no componente pai. No entanto, apenas o componente que possui os dados deve modificá-lo, para tornar mais fácil o raciocínio sobre quais e quando os dados forem alterados.

Entradas / Saídas

Entradas devem estar usando bindings < e @.

O símbolo < define one-way bindings.

A diferença para o = é que as propriedades ligadas no componente não são observadas, portanto, se você atribuir um novo valor no escopo do componente, ele não será refletido no escopo pai.

O símbolo @ pode ser usado quando a entrada é uma string, principalmente quando o valor não muda.

Exemplo

bindings: {
    title: '@',
    options: '=',
    musics: '<'
}

Entradas / Saídas

O símbolo & define chamadas de retorno para eventos de componentes.

O componente chama um evento de saída com os dados alterados. Isso significa que o componente não é responsável pela tarefa, mas envia de volta para o responsável.

Exemplo

bindings: {
    onSetMusic: '&'
},

Lifecycle

Componentes devem controlar apenas seu escopo e nunca elementos DOM ou quaisquer dados de fora.

  Com angular é possível modificar dados em qualquer lugar da aplicação usando herança de escopo e watches. Isto é prático, mas também pode levar a problemas quando não é claro qual a parte da aplicação é responsável por modificar os dados. Por isso componentes angular usam escopo isolado, restringindo a manipulação de escopo.

$onInit()

Chamado em cada controlador depois de todos os controladores em um elemento forem construídos e tiveram seus bindings inicializados.

Este é um bom lugar para colocar código de inicialização para seu controlador.

$onChanges(obj)

Chamado sempre que os one-way bindings são actualizados.

O obj é um hash cujas keys são os nomes das propriedades vinculadas que foram alterados, e os valores são um objeto {currentValue, previousValue, isFirstChange()}.

Utilize este gancho para acionar atualizações dentro de um componente, tais como a clonagem do valor para evitar mutação acidental do valor externo.

$doCheck()

Chamado em cada retorno do ciclo de digest. Oferece uma oportunidade para detectar e agir sobre as mudanças.

Este não tem efeito sobre quando o $onChanges é chamado.

$onDestroy()

Chamado em um controlador quando o seu escopo é destruído.

Utilize este gatilho para liberar recursos externos, watches e manipuladores de eventos.

$postLink()

Chamado após o elemento deste controlador e seus filhos terem sido associados. Este gatilho pode ser usado para configurar manipuladores de eventos DOM e fazer manipulação do DOM diretamente.

Módulo

import AudioPlayerComponent from './component/audio.js'
import AudioListComponent   from './component/audio.list.js'

angular
  .module('audio.player', [])
  .component('audioPlayer', AudioPlayerComponent)
  .component('audioList', AudioListComponent)

Component Audio Player

import template from './audio.template.js'

let AudioPlayerComponent = {
  restrict: 'E',
  bindings: {
    title: '@',
    options: '=',
    musics: '<',
    onSetMusic: '&'
  },
  template: template,
  controller: function($scope, $element, $attrs, $interval) {
    let ctrl = this

    let createAudio = () => {
      ctrl.audio = new Audio()
      ctrl.audio.loop = ctrl.options.loop
      ctrl.audio.autoplay = ctrl.options.autoplay
      ctrl.audio.crossOrigin = ctrl.options.origin || 'anonymous'
      ctrl.audio.addEventListener('ended', ctrl.next)
    }

    let getRandom = () => {
      return Math.floor(Math.random() * ctrl.musics.length)
    }

    ctrl.setCurrent = current => {
      ctrl.current = (current >= ctrl.musics.length) ? 0 : current
    }
    let song
    ctrl.setSong = () => {
      song = ctrl.musics[ctrl.current]
      ctrl.song = `${song.artist} - ${song.title}`
      ctrl.audio.src = song.value
    }
    ctrl.setMusic = index => {
      ctrl.setCurrent(index)
      ctrl.setSong()
      ctrl.play()
    }
    ctrl.changeVolume = () => {
      ctrl.audio.volume = ctrl.volume
    }
    ctrl.play = () => {
      ctrl.audio.play()
    }
    ctrl.pause = () => {
      ctrl.audio.pause()
    }
    ctrl.next = () => {
      if (ctrl.options.random) {
        ctrl.setMusic(getRandom())
        return
      }
      ctrl.setMusic(ctrl.current + 1)
    }
    ctrl.prev = () => {
      if (ctrl.options.random) {
        ctrl.setMusic(getRandom())
        return
      }
      ctrl.setMusic(ctrl.current - 1)
    }
    let getSvgFill = bool => {
      return bool ? '#000000' : '#999999'
    }
    let setLoopFill = () => {
      loop.style.fill = getSvgFill(ctrl.options.loop)
    }
    ctrl.changeLoop = () => {
      ctrl.audio.loop = ctrl.options.loop = !ctrl.options.loop
      setLoopFill()
    }
    let setRandomFill = () => {
      random.style.fill = getSvgFill(ctrl.options.random)
    }
    ctrl.changeRandom = () => {
      ctrl.options.random = !ctrl.options.random
      setRandomFill()
    }
    let h, m, s
    let secToTime = (seconds) => {
      h = Math.floor((seconds % 86400) / 3600)
      m = Math.floor(((seconds % 86400) % 3600) / 60)
      s = ((seconds % 86400) % 3600) % 60
      return `${('00'+h).slice(-2)}:${('00'+m).slice(-2)}:${('00'+s).slice(-2)}`
    }
    let duration, currentTime
    $interval(() => {
      duration = Math.floor(ctrl.audio.duration)
      currentTime = Math.floor(ctrl.audio.currentTime)
      ctrl.time = secToTime(currentTime)
      ctrl.timeLeft = secToTime(duration - currentTime)
      ctrl.percentage = Math.floor((100 / ctrl.audio.duration) * ctrl.audio.currentTime)
    }, 100)

    let audioContext, analyser, source, fbc_array
    let createAudioContext = () => {
      audioContext = new (window.AudioContext || window.webkitAudioContext)
      source = audioContext.createMediaElementSource(ctrl.audio)
      analyser = audioContext.createAnalyser()
      fbc_array = new Uint8Array(analyser.frequencyBinCount)
      source.connect(analyser)
      analyser.connect(audioContext.destination)
    }

    let canvas, canvasCtx
    let createCanvas = () => {
      canvas = document.getElementById('analyser')
      canvasCtx = canvas.getContext('2d')
    }
    let defineSizesCanvas = () => {
      canvas.width = 200
      canvas.height = 300
    }
    let bars, bar_x, bar_width, bar_height
    let frameLooper = () => {
      window.requestAnimationFrame(frameLooper)
      analyser.getByteFrequencyData(fbc_array)
      render()
    }

    let render = () => {
      canvasCtx.clearRect(0, 0, canvas.width, canvas.height)
      canvasCtx.fillStyle = 'orange'
      bars = 200
      for (let i = 0; i < bars; i++) {
        bar_width = canvas.width / bars
        bar_x = i * (bar_width + 2)
        bar_height = -(fbc_array[i])
        canvasCtx.fillRect(bar_x, canvas.height, bar_width, bar_height)
      }
    }

    ctrl.$onInit = () => {
      ctrl.current = 0
      ctrl.volume = 1
      ctrl.time = 0
      createAudio()
      createAudioContext()
      createCanvas()
      defineSizesCanvas()
      frameLooper()
      ctrl.setSong()
    }

    let loop, random
    ctrl.$postLink = () => {
      loop = $element[0].querySelector('#loop')
      setLoopFill()
      random = $element[0].querySelector('#random')
      setRandomFill()
    }
  }
}

export default AudioPlayerComponent

Template Audio Player

import style from './audio.style.js'

export default `
<style>${style}</style>
<fieldset>
  <legend>{{$ctrl.title}}</legend>
  <canvas id="analyser"></canvas>
  <div id="controls">
    <button type="button" ng-click="$ctrl.play()">
      <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M8,5.14V19.14L19,12.14L8,5.14Z" /></svg>
    </button>
    <button type="button" ng-click="$ctrl.pause()">
      <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M14,19H18V5H14M6,19H10V5H6V19Z" /></svg>
    </button>
    <button type="button" ng-click="$ctrl.prev()">
      <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M6,18V6H8V18H6M9.5,12L18,6V18L9.5,12Z" /></svg>
    </button>
    <button type="button" ng-click="$ctrl.next()">
      <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M16,18H18V6H16M6,18L14.5,12L6,6V18Z" /></svg>
    </button>
    <progress value="{{$ctrl.percentage}}" max="100">{{$ctrl.percentage}} %</progress>
    <div id="time">
      <span ng-bind="$ctrl.time"></span>
      <span ng-bind="$ctrl.timeLeft"></span>
    </div>
    <div id="options">
      <label data-ng-click="$ctrl.changeLoop()">
        <svg id="loop" fill="#000000" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg">
          <path d="M12 4V1L8 5l4 4V6c3.31 0 6 2.69 6 6 0 1.01-.25 1.97-.7 2.8l1.46 1.46C19.54 15.03 20 13.57 20 12c0-4.42-3.58-8-8-8zm0 14c-3.31 0-6-2.69-6-6 0-1.01.25-1.97.7-2.8L5.24 7.74C4.46 8.97 4 10.43 4 12c0 4.42 3.58 8 8 8v3l4-4-4-4v3z"/>
          <path d="M0 0h24v24H0z" fill="none"/>
        </svg>
      </label>
      <label data-ng-click="$ctrl.changeRandom()">
        <svg id="random" fill="#000000" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg">
          <path d="M0 0h24v24H0z" fill="none"/>
          <path d="M10.59 9.17L5.41 4 4 5.41l5.17 5.17 1.42-1.41zM14.5 4l2.04 2.04L4 18.59 5.41 20 17.96 7.46 20 9.5V4h-5.5zm.33 9.41l-1.41 1.41 3.13 3.13L14.5 20H20v-5.5l-2.04 2.04-3.13-3.13z"/>
        </svg>
      </label>
    </div>
    <input type="range" ng-change="$ctrl.changeVolume()" ng-model="$ctrl.volume" min="0.0" max="1" step="0.1" ng-value="$ctrl.volume">
    <span id="volume">{{$ctrl.volume}}</span>
  </div>
  <div id="current">
    <marquee scrolldelay="200">{{$ctrl.song}}</marquee>
  </div>
  <audio-list musics="$ctrl.musics" on-set-music="$ctrl.setMusic(index)"></audio-list>
</fieldset>`

Style Audio Player

export default `
audio-player {
  font-family: Arial, Helvetica, sans-serif;
  font-size: 13px;
}
audio-player fieldset {
  width: 205px;
  padding: 4px 9px 12px 10px;
  background-color: #f5f5f5;
  border: 2px solid #ccc;
}
audio-player legend {
  padding: 0 6px;
}
audio-player canvas {
  width: 200px;
  height: 100px;
  background-color: #eaeaea;
  border: 2px solid #ccc;
}
audio-player #controls {
  margin-top: 6px;
}
audio-player #controls button {
  margin: 0 0 4px;
  padding: 4px 0;
  width: 48px;
  font-size: 12px;
  background-color: #fff;
  border: 2px solid #ccc;
}
audio-player #controls #time,
audio-player #controls #options label {
  cursor: pointer;
}
audio-player #controls #options {
  width: 202px;
}
audio-player #controls #time span:last-child,
audio-player #controls #options label:last-child {
  text-align: right;
  float: right;
}
audio-player #controls progress {
  width: 202px;
  margin: 5px 0;
}
audio-player #controls #volume {
  margin: 4px 0;
  width: 20px;
  float: right;
  text-align: right;
}
audio-player #controls input[type="range"] {
  margin: 2px 0;
  width: 180px;
}
audio-player #current {
  margin: 0 0 2px 0;
  padding: 4px 0;
  border-bottom: 2px solid #ccc;
}
audio-player #current input[type="text"] {
  width: 202px;
  background-color: transparent;
  border: 0;
}`

Component Audio List

import template from './audio.list.template.js'

let AudioListComponent = {
  restrict: 'E',
  bindings: {
    musics: '<',
    onSetMusic: '&'
  },
  template: template,
  controller: function($scope, $element, $attrs) {
    let ctrl = this
    ctrl.setMusic = index => {
      ctrl.onSetMusic({index: index})
    }
    ctrl.toggle = () => {
      ctrl.show = !ctrl.show
    }
    ctrl.$onInit = () => {
      ctrl.show = true
    }
  }
}

export default AudioListComponent

Template Audio List

import style from './audio.list.style.js'

export default `
<style>${style}</style>
<button type="button" data-ng-click="$ctrl.toggle()">
  <svg data-ng-show="!$ctrl.show" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M10,4H14V13L17.5,9.5L19.92,11.92L12,19.84L4.08,11.92L6.5,9.5L10,13V4Z" /></svg>
  <svg data-ng-show="$ctrl.show" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M14,20H10V11L6.5,14.5L4.08,12.08L12,4.16L19.92,12.08L17.5,14.5L14,11V20Z" /></svg>
</button>
<ul id="list" data-ng-class="{hide: !$ctrl.show}">
  <li ng-repeat="music in $ctrl.musics" ng-click="$ctrl.setMusic($index)">
    <a>{{music.artist}} - {{music.title}}</a>
  </li>
</ul>`

Style Audio List

export default `
audio-player audio-list {
  display: block;
  position: relative;
}
audio-player audio-list button {
  position: absolute;
  left: 82px;
  bottom: -38px;
  cursor: pointer;
  background-color: transparent;
  border: 0;
}
audio-player audio-list #list {
  padding: 0;
  width: 202px;
  max-height: 120px;
  overflow-y: scroll;
  list-style: none;
  -webkit-transition: all 1s ease;
  -moz-transition: all 1s ease;
  -ms-transition: all 1s ease;
  -o-transition: all 1s ease;
  transition: all 1s ease;
}
audio-player audio-list #list.hide {
  max-height: 0;
}
audio-player audio-list #list li {
  margin: 3px 0;
  padding: 3px 0;
  cursor: pointer;
  white-space: nowrap;
  overflow-x: hidden;
  text-overflow: ellipsis;
  border-bottom: 1px solid #ccc;
}
audio-player audio-list #list li:last-child {
  border-bottom: 0;
}`

Exemplo de uso

Módulo do Web App e Controller

angular
  .module('app', ['audio.player'])
  .controller('AppController', ['$scope', function ($scope) {
    var ctrl = this;
    ctrl.options = {
      autoplay: true,
      loop: false,
      random: true,
      origin: 'anonymous' // Optional, anonymous is default
    }
    ctrl.list = [
      {
        artist: 'Chasing Ghosts',
        title: 'Fallen From Grace',
        album: 'Chasing Ghosts',
        value: 'musics/Chasing_Ghosts-Fallen_From_Grace.mp3'
      },
      {
        artist: 'Sepultura',
        title: 'Refuse/Resist',
        album: 'Chaos A.D.',
        value: 'musics/Sepultura-Refuse_Resist.mp3'
      },
      {
        artist: 'Raimundos',
        title: 'Baily Funk',
        album: 'Lapadas do povo',
        value: 'musics/Raimundos-Baily_Funk.mp3'
      }
    ]
  }])

Index

<!doctype html>
<html data-ng-app="app">
<head>
  <meta charset="utf-8">
  <title>Angular Audio Player Component - HTML5/ES6</title>
  <link rel="stylesheet" href="src/component/style.css">
</head>
<body data-ng-controller="AppController as ctrl">

  <!-- Component Audio Player -->
  <audio-player title="Audio Player" options="ctrl.options" musics="ctrl.list"></audio-player>
  <!-- /Component Audio Player -->

  <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.6/angular.min.js"></script>
  <script src="dist/bundle.min.js"></script>
  <script src="app.js"></script>
</body>
</html>

Tchanammm...

ES6?

Já posso usar no front-end?

Sebastian McKenzie

Criador do BabelJS

Babel is a JavaScript compiler.

Use next generation JavaScript, today.

Como?

npm install babel-cli --save-dev
npm install babel-preset-es2015 --save-dev
npm install babelify --save-dev

Vamos mais fundo

{
  "name": "angular-audio-player-html5-es6",
  "version": "2.1.0",
  "description": "Angular Audio Player Component - HTML5/ES6",
  "main": "./src/index.js",
  "scripts": {
    "dev": "npm-run-all -s -c build:concat",
    "build": "npm-run-all -p build:sequential",
    "build:sequential": "npm-run-all -s -c build:concat build:minify",
    "build:concat": "browserify ./src/index.js -o ./dist/bundle.js -t [ babelify ]",
    "build:minify": "uglifyjs ./dist/bundle.js -o ./dist/bundle.min.js",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "dependencies": {
    "angular": "^1.5.8"
  },
  "babel": {
    "presets": [
      "es2015"
    ]
  },
  "devDependencies": {
    "babel-cli": "^6.11.4",
    "babel-preset-es2015": "^6.13.2",
    "babelify": "^7.3.0",
    "browserify": "^13.1.0",
    "npm-run-all": "^2.3.0",
    "uglify-js": "^2.7.0",
    "watchify": "^3.7.0"
  },
  "repository": {
    "type": "git",
    "url": "https://github.com/guiseek/angular-audio-player-html5-es6.git"
  },
  "keywords": [
    "angular",
    "audio",
    "player",
    "component",
    "HTML5",
    "ES6"
  ],
  "author": "Gui Seek <guiseek@gmail.com>",
  "license": "MIT",
  "bugs": {
    "url": "https://github.com/guiseek/angular-audio-player-html5-es6/issues"
  },
  "homepage": "https://github.com/guiseek/angular-audio-player-html5-es6"
}

Conclusão

O HTML (em parceria com JavaScript) está ficando poderoso para criação de aplicações fazendo uso de componentes reutilizáveis.

Usem e escrevam seus custom elements! : )

Muito obrigado!

Meu Github

Sobre meu trabalho

DevParaná

Made with Slides.com