import React from 'react';
import ReactDOM from 'react-dom';
const Counter = ({initial}) => {
const [count, setCount] = React.useState(initial);
return (
<div className="centered">
<button onClick={() => setCount(count - 1)}>
-
</button>
<span>{count}</span>
<button onClick={() => setCount(count + 1)}>
+
</button>
</div>
);
}
ReactDOM.render(
<Counter initial={10} />,
document.getElementById('react-app')
);
import 'zone.js'; import 'core-js/es/reflect'; import 'core-js/features/reflect';
import { BrowserModule } from '@angular/platform-browser';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { NgModule, Component, Input } from '@angular/core';
@Component({
selector: 'angular-counter',
template: `
<div class="centered">
<button (click)="setCount(count - 1)">
-
</button>
<span>{{count}}</span>
<button (click)="setCount(count + 1)">
+
</button>
</div>
`
})
class Counter {
@Input() count: number;
setCount(count: number) {
this.count = count;
}
}
@Component({ selector: 'angular-app', template: '<angular-counter [count]="10">' }) class App { }
@NgModule({
imports: [ BrowserModule ],
declarations: [ App, Counter ],
bootstrap: [ App ]
})
class AppModule { }
platformBrowserDynamic().bootstrapModule(AppModule);
import Vue from 'vue';
const Counter = Vue.component('vue-counter', {
props: { initial: Number },
data: function() {
return {
count: this.initial
}
},
template: `
<div class="centered">
<button @click="--count">
-
</button>
<span>{{count}}</span>
<button @click="++count">
+
</button>
</div>
`
});
new Vue({
el: '#vue-app',
components: { Counter },
template: '<vue-counter :initial="10" />'
})
class FullWebComp extends HTMLElement { constructor() { super();
this.attachShadow({mode: 'closed'}) .appendChild(document
.getElementById('h2-template') .content .cloneNode(true));
} } customElements.define('full-web-comp', FullWebComp);
style
const input = document.querySelector('[type="checkbox"]');
const [attr, prop] = [
input.getAttribute('checked'),
input.checked
];
verify(attr, prop);
class CheckboxWrapper extends HTMLElement { constructor() { super(); this.input = document.createElement('input'); this.input.type = 'checkbox'; }
get checked() { return this.isTrue('checked'); }
set checked(value) { const bool = !!value; if (bool === this.checked) return;
this.input.checked = bool;
bool ? this.setAttribute('checked', '') : this.removeAttribute('checked');
this.dispatchEvent(new Event('change', { bubbles: true }));
}
isTrue(attr) { return this.hasAttribute(attr) && this.getAttribute(attr) !== 'false'; }
}
customElements.define('m3-switch', class extends CheckboxWrapper {
constructor() {
super();
this.attachShadow({ mode: 'open' });
}
connectedCallback() {
this.input.checked = this.checked;
this.shadowRoot.innerHTML = `
`;
this.shadowRoot.prepend(this.input);
this.shadowRoot.appendChild(document.getElementById('style-template')
.content
.cloneNode(true));
this.onclick = (e) => {
e.preventDefault();
this.checked = !this.checked;
}
}
get round() { return this.isTrue('round'); }
});
<bad-component></bad-component>
<better-component>hello world</better-component>
<a is="twitter-share"
text="A Twitter share button with progressive enhancement"
url="https://codepen.io/WebReflection/pen/LKWyLB?editors=0010"
via="webreflection" />
import React, { useState, useEffect } from 'react';
import ReactDOM from 'react-dom';
const Demo = ({initial}) => {
const [checked, setChecked] = React.useState(initial);
const refWc = React.createRef();
const handleChange = (e) => setChecked(e.target.checked);
useEffect(() => {
refWc.current.onchange = handleChange;
});
return (
<label>
<m3-switch checked={checked} ref={refWc}></m3-switch>
{`${checked}`}
</label>
);
}
ReactDOM.render(
<Demo initial={true} />,
document.getElementById('react-wc-app')
);
import 'zone.js'; import 'core-js/es/reflect'; import 'core-js/features/reflect';
import { BrowserModule } from '@angular/platform-browser';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { NgModule, Component, Input, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
@Component({
selector: 'angular-wc-app',
template: `
<m3-switch [checked]="checked" (change)="handleChange($event)"></m3-switch>
{{checked}}
`
})
class Demo {
checked = true;
handleChange(event: Event) {
this.checked = event.target.checked;
}
}
@NgModule({
imports: [ BrowserModule ],
declarations: [ Demo ],
bootstrap: [ Demo ],
schemas: [ CUSTOM_ELEMENTS_SCHEMA ]
})
class AppModule { }
platformBrowserDynamic().bootstrapModule(AppModule);
import 'zone.js'; import 'core-js/es/reflect'; import 'core-js/features/reflect';
import { createCustomElement } from '@angular/elements';
import { BrowserModule } from '@angular/platform-browser';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import {
NgModule, Input, Output, Component, ViewEncapsulation, EventEmitter, Inject, Injector
} from '@angular/core';
@Component({
selector: 'm3-button',
template: `<button (click)="handleClick()" style="padding: .5em">{{label}}</button>`,
encapsulation: ViewEncapsulation.ShadowDom
})
class ButtonComponent {
@Input() label = 'default label';
@Output() action = new EventEmitter<number>();
private count = 0;
handleClick() { this.action.emit(++this.count); }
}
@NgModule({
imports: [ BrowserModule ],
declarations: [ ButtonComponent ],
entryComponents: [ ButtonComponent ]
})
class AppModule {
static parameters = [[Injector]];
constructor(private injector: Injector) {
const customButton = createCustomElement(ButtonComponent, { injector });
customElements.define('m3-button', customButton);
}
ngDoBootstrap() {}
}
platformBrowserDynamic().bootstrapModule(AppModule);
import React, { useState, useEffect } from 'react';
import ReactDOM from 'react-dom';
const Demo = ({label}) => {
const [count, setCount] = React.useState(0);
const refWc = React.createRef();
const handleClick = (e) => setCount(e.detail);
useEffect(() => {
refWc.current.addEventListener('action', handleClick);
});
return (
<>
<m3-button label={label} ref={refWc}></m3-button>
<small style={{verticalAlign: 'bottom'}}>{`x ${count}`}</small>
</>
);
}
ReactDOM.render(
<Demo label="test" />,
document.getElementById('react-wc-app2')
);
import Vue from 'vue';
const Demo = Vue.component('vue-demo', {
template: `<div>
<m3-switch :checked="checked" @change="handleChange"></m3-switch> {{checked}}
<br>
<m3-button :label="label" @action="handleClick"></m3-button>
</div>`,
methods: {
handleChange: function(e) { this.checked = e.target.checked; },
handleClick: function(e) { this.label = e.detail }
},
data: function() {
return {
checked: this.initial,
label: 0
}
},
props: { initial: Boolean }
});
new Vue({
el: '#vue-wc-app',
components: { Demo },
template: '<vue-demo :initial="true" />'
})
import Vue from 'vue';
import wrap from '@vue/web-component-wrapper';
const VueWebComponent = Vue.component('m3-hello', {
template: `<div>Hi, {{msg}}!</div>`,
props: { msg: String }
});
const CustomElement = wrap(Vue, VueWebComponent);
customElements.define('m3-hello', CustomElement);
document.getElementById('js-wc-app').innerHTML = `
<m3-hello msg="world"></m3-hello>
`;