polyfiddle
Polymer boilerplate for jsFiddle
HTML
<script>
Polymer = {
dom: 'shadow',
lazyRegister: true,
suppressBindingNotifications: true,
suppressTemplateNotifications: true,
useNativeCSSProperties: true,
};
</script>
<base href="https://rawcdn.githack.com/StartPolymer/cdn/v1.11.0/components/">
<link href="polymer/polymer.html" rel="import">
<dom-module id="cr-toggle">
<template>
<style>
:host {
cursor: pointer;
display: block;
outline: none;
}
:host([disabled]) {
cursor: initial;
pointer-events: none;
}
#container {
position: relative;
width: 34px;
z-index: 0;
}
#bar {
background-color: black;
border-radius: 8px;
height: 12px;
left: 3px;
opacity: 0.4;
position: absolute;
top: 2px;
transition: background-color linear 80ms;
width: 28px;
z-index: 0;
}
:host([checked]) #bar {
background-color: blue;
}
:host([disabled]) #bar {
background-color: black;
opacity: 0.12;
}
#button {
background-color: lightgray;
border-radius: 50%;
box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.4);
height: 16px;
position: relative;
transition: transform linear 80ms, background-color linear 80ms;
width: 16px;
z-index: 1;
}
:host([checked]) #button {
background-color: red;
transform: translate3d(18px, 0, 0);
}
:host-context([dir=rtl]):host([checked]) #button {
transform: translate3d(-18px, 0, 0);
}
:host([disabled]) #button {
background-color: #bdbdbd;
opacity: 1;
}
</style>
<div id="container">
<div id="bar"></div>
<div id="button"></div>
</div>
</template>
</dom-module>
Use-case requirements
<ul>
<li>Switch can be toggled by...
CSS
body {
font-family: sans-serif;
margin: 0;
}
.clickable-row {
display: flex;
margin: 20px;
padding: 5px;
background-color: yellow;
cursor: pointer;
user-select: none;
}
.clickable-row span {
flex: 1;
}
JavaScript
Polymer({
is: 'cr-toggle',
properties: {
checked: {
type: Boolean,
value: false,
reflectToAttribute: true,
observer: 'checkedChanged_',
notify: true,
},
disabled: {
type: Boolean,
value: false,
reflectToAttribute: true,
observer: 'disabledChanged_',
},
},
hostAttributes: {
'aria-disabled': 'false',
'aria-pressed': 'false',
role: 'button',
tabindex: 0,
},
listeners: {
'pointerdown': 'onPointerDown_',
'pointerup': 'onPointerUp_',
'click': 'onTap_',
'keypress': 'onKeyPress_',
},
/** @private {?Function} */
boundPointerMove_: null,
/**
* Number of pixels required to move to consider the pointermove event as
* intentional.
* @type {number}
*/
MOVE_THRESHOLD_PX: 5,
/**
* Whether the state of the toggle has already taken into account by
* |pointeremove| handlers. Used in the 'tap' handler.
* @private {boolean}
*/
handledInPointerMove_: false,
/** @private {number} */
lastPointerUpTime_: 0,
/** @override */
attached: function() {
let direction = this.matches(':host-context([dir=rtl]) cr-toggle') ? -1 : 1;
this.boundPointerMove_ = (e) => {
// Prevent unwanted text selection to occur while moving the pointer, this
// is important.
e.preventDefault();
let diff = e.clientX - this.pointerDownX_;
if (Math.abs(diff) < this.MOVE_THRESHOLD_PX)
return;
this.handledInPointerMove_ = true;
let shouldToggle = (diff * direction < 0 && this.checked) ||
(diff * direction > 0 && !this.checked);
if (shouldToggle)
this.toggleState_();
};
},
/** @private */
checkedChanged_: function() {
this.setAttribute('aria-pressed', this.checked ? 'true' : 'false');
},
/** @private */
disabledChanged_: function() {
this.setAttribute('tabindex', this.disabled ? -1 : 0);
this.setAttribute('aria-disabled', this.disabled ?...