• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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