1/* 2 * Copyright (C) 2022 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16import { BaseElement, element } from '../BaseElement.js'; 17 18@element('lit-switch') 19export default class LitSwitch extends BaseElement { 20 private switch: HTMLInputElement | null | undefined; 21 private isfocus: boolean | undefined; 22 23 static get observedAttributes() { 24 return ['disabled', 'checked']; 25 } 26 27 get disabled() { 28 return this.getAttribute('disabled') !== null; 29 } 30 31 set disabled(value) { 32 if (value === null || value === false) { 33 this.removeAttribute('disabled'); 34 } else { 35 this.setAttribute('disabled', ''); 36 } 37 } 38 39 get checked() { 40 return this.getAttribute('checked') !== null; 41 } 42 43 set checked(value) { 44 if (value === null || value === false) { 45 this.removeAttribute('checked'); 46 } else { 47 this.setAttribute('checked', ''); 48 } 49 } 50 51 get name() { 52 return this.getAttribute('name'); 53 } 54 55 initElements(): void {} 56 57 initHtml(): string { 58 return ` 59 <style> 60 :host{ 61 display:inline-block; 62 -webkit-tap-highlight-color: transparent; 63 } 64 #name{ 65 transition:0.31s width,0.31s height,0.31s background-color; 66 width:2.41em; 67 height:1.21em; 68 background: #3391FF; 69 display:flex; 70 padding:0.124em; 71 border-radius:1.21em; 72 cursor:pointer; 73 } 74 75 :host(:not([checked])) #name { 76 background: #999999; 77 } 78 79 #name::before{ 80 content:''; 81 flex:0; 82 transition:.2s cubic-bezier(.12, .4, .29, 1.46) flex; 83 } 84 #name::after{ 85 content:''; 86 width:.4em; 87 height:.4em; 88 border-radius:1.2em; 89 border:.4em solid #fff; 90 background-color:#ffffff; 91 transition:.3s background,.3s padding,.3s width,.3s height,.3s border-radius,.3s border; 92 box-shadow: 0 2px 4px 0 rgba(0,35,11,0.2); 93 } 94 #name:active::after{ 95 padding:0 .3em; 96 } 97 #switch:checked+#name{ 98 background:#42b983); 99 } 100 #switch:checked+#name::before{ 101 flex:1; 102 } 103 #switch{ 104 position:absolute; 105 clip:rect(0,0px,0px,0); 106 } 107 :host(:focus-within) #name::after,:host(:active) ::after{ 108 background:#42b983; 109 } 110 :host(:focus-within) #name{ 111 box-shadow: 0 0 10px rgba(0,0,0,0.1); 112 } 113 :host(:focus-within) #switch,:host(:active) #switch{ 114 z-index:2 115 } 116 :host([disabled]){ 117 pointer-events: none; 118 opacity:.5; 119 } 120 :host([disabled]) #name{ 121 pointer-events: all; 122 cursor: not-allowed; 123 } 124 </style> 125 <input type="checkbox" id="switch"><label id="name" for="switch"></label> 126 `; 127 } 128 129 connectedCallback() { 130 this.switch = this.shadowRoot?.getElementById('switch') as HTMLInputElement; 131 this.disabled = this.disabled; 132 this.checked = this.checked; 133 this.switch!.onchange = (ev) => { 134 this.checked = this.switch!.checked; 135 let changeEvent: CustomEventInit<LitSwitchChangeEvent> = { 136 detail: { 137 checked: this.checked, 138 }, 139 }; 140 this.dispatchEvent(new CustomEvent('change', changeEvent)); 141 }; 142 this.switch.onkeydown = (ev) => { 143 switch (ev.keyCode) { 144 case 13: //enter 145 this.checked = !this.checked; 146 let changeEvent: CustomEventInit<LitSwitchChangeEvent> = { 147 detail: { 148 checked: this.checked, 149 }, 150 }; 151 this.dispatchEvent(new CustomEvent('change', changeEvent)); 152 break; 153 default: 154 break; 155 } 156 }; 157 this.switch.onfocus = (ev) => { 158 ev.stopPropagation(); 159 if (!this.isfocus) { 160 this.dispatchEvent( 161 new CustomEvent('focus', { 162 detail: { value: this.switch!.value }, 163 }) 164 ); 165 } 166 }; 167 this.switch.onblur = (ev) => { 168 ev.stopPropagation(); 169 if (getComputedStyle(this.switch!).zIndex == '2') { 170 this.isfocus = true; 171 } else { 172 this.isfocus = false; 173 this.dispatchEvent( 174 new CustomEvent('blur', { 175 detail: { value: this.switch!.value }, 176 }) 177 ); 178 } 179 }; 180 } 181 182 attributeChangedCallback(name: string, oldValue: string, newValue: string) { 183 if (name === 'disabled' && this.switch) { 184 if (newValue !== null) { 185 this.switch.setAttribute('disabled', ''); 186 } else { 187 this.switch.removeAttribute('disabled'); 188 } 189 } 190 if (name === 'checked' && this.switch) { 191 if (newValue !== null) { 192 this.switch.checked = true; 193 } else { 194 this.switch.checked = false; 195 } 196 } 197 } 198} 199 200export interface LitSwitchChangeEvent { 201 checked: boolean; 202} 203