progressive-web-components

0.0.1 • Public • Published

Progressive Web Components

Unreleased work in progress

No Babel. No Webpack. Progressive Web Components let you build full web apps native custom HTML elements.

:host {
  --primary-color-base: #ff0000;
}
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <link src="./theme.css" type="text/my-app-theme" />
    <!-- Add your modules as script tags. -->
    <script src="https://unpkg.com/progressive-web-components/loader.js"></script> 
    <script type="module" src="https://unpkg.com/@progressive-web-components/web-component.js"></script> 
 
    <!-- Declare your components with minimal JavaScript -->
 
    <web-component tag-name="human-time">
      <observed-attribute name="date" type="number" required></observed-attribute>
 
      <template>
        <span title="${this.observedAttributes.date}">${this.humanizedTime()}</span>
      </template>
 
      <script type="module">
        import moment from './node_modules/moment/moment.js'
 
        this.humanizedTime = () => {
          return moment.fromNow(this.observedAttributes.date)
        }
 
        this.addEventListener('afterInsert', () => {
          this.interval = setInterval(() => {
            this.requestTemplateUpdate()
          }, 1000 * 60)
        })
 
        this.addEventListener('beforeRemove', () => {
          clearInterval(this.interval)
        })
      </script> 
    </web-component>
 
    <!-- ...Or reference components in separate files -->
 
    <web-component src="/components/human-time.component.html"></web-component>
 
    <!-- ...Or declare them as JavaScript classes for total control -->
 
    <script type="module">
      import WebComponent from 'node_modules/@progressive-web-components/web-component.js`
      import moment from './node_modules/moment/moment.js'
 
      class HumanTime extends WebComponent {
        static tagName = 'human-time'
 
        static observedAttributes = {
          date: {
            type: Date,
            required: true
          }
        }
 
        onafterinsert() {
          this.interval = setInterval(() => {
            this.requestTemplateUpdate()
          }, 1000 * 60)
 
        }
 
        onbeforeremove() {
          clearInterval(this.interval)
        }
 
        humanizedTime() {
          return moment.fromNow(this.observedAttributes.date)
        }
 
        template(html) {
          return html`
            <span title="${this.observedAttributes.date}">${this.humanizedTime()}</span>
          `
        }
      }
    </script>
 
    <script>
      // ...Then natively import them — without a build step.
      import MyApp from '/vendor/my-app.js'
 
      // Create native custom elements.
      MyApp.createElement('todo-list-page', {
        // Element scoped styles.
        styles(css) {
          css`
            :host {
              border: 1px dashed black;
            }
            .todos {
              border: 1px solid black;
            }
          `
        },
 
        methods: {
          markTodoComplete(event) {
            const { todoId } = event.target.dataset
 
            this.parentApp.sharable.markTodoComplete(todoId)
          }
        },
 
        render(html) {
          const { todos } = this.parentApp.sharable
 
          return html`
            <div>
              <h1>Todo List</h1>
 
              <ul class="todos">
                ${
                  todos.entries.map(
                    todo => html`
                      <li onClick=${this.markTodoComplete} data-todo-id=${todo.id}>${todo.title}</li>
                    `
                  )
                }
              </ul>
            </div>
          `
        }
      })
 
      const myApp = new MyApp({
        // Share global data with child nodes.
        sharable: {
          todos: {
            entries: [{ id: 'abc123', title: 'Try MyApp', complete: true }],
            markTodoComplete(todoId) {
              const todo = this.todos.find(todo => todo.id === todoId)
              todo.complete = true
            }
          }
        },
        routes: {
          // Map routes to custom elements.
          '/': TodoListPage,
          login: LoginPage
        }
      })
 
      document.body.appendChild(myApp)
    </script>
  </head>
 
  <body></body>
</html>

Theming (WIP)

<!DOCTYPE html>
<html>
<head>
  <link rel="stylesheet" type="text/css" media="screen" href="main.css" />
  <script type="module" src="material-button.js"></script> 
</head>
<body>
  <my-theme>
    <style>
      /* Global theme variables. */
      :root {
        --font-size: 16px;
        --color: #111;
      }
 
      /* Element overrides */
      material-button::part(text{
        font-style: italic;
      }
    </style> 
 
    <material-button>Click me!</material-button>
  <my-theme>
</body>
</html>

Readme

Keywords

none

Package Sidebar

Install

npm i progressive-web-components

Weekly Downloads

0

Version

0.0.1

License

MIT

Unpacked Size

77.7 kB

Total Files

46

Last publish

Collaborators

  • teffenellis