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';
17import { replacePlaceholders } from '../utils/Template';
18
19let css = `
20<style>
21      :host{
22          display: flex;
23          position: absolute;
24          top: 0;
25          bottom: 0;
26          left: 0;
27          right: 0;
28          width: 100%;
29          height: 100%;
30          overflow: hidden;
31          z-index: 2001;
32          pointer-events: none;
33       }
34       :host([mask]) .bg{
35          position:absolute;
36          top: 0;
37          right: 0;
38          left: 0;
39          bottom: 0;
40          width: 100%;
41          height: 100%;
42          background-color: #00000055;
43       }
44       :host(:not([mask])) .bg{
45          display: none;
46       }
47       .title{
48          display: flex;
49          justify-content: space-between;
50          align-items: center;
51          padding: 12px 20px;
52          border-bottom: var(--dark-border1,#f0f0f0) 1px solid;
53          font-size: 18px;
54          font-weight: bold;
55          color: var(--dark-color1,#262626);
56       }
57       slot{
58          padding: {1};
59          display: block;
60       }
61       :host([visible]) .bg{
62          transition: all .3s;
63          opacity: 1;
64          visibility: visible;
65       }
66       :host(:not([visible])) .bg{
67          transition: all .3s;
68          opacity: 0;
69          visibility: hidden;
70       }
71       /*
72          right(默认)
73       */
74       :host(:not([placement])) .drawer,
75       :host([placement='right']) .drawer{
76          width: {2};
77          box-sizing: border-box;
78          position: absolute;
79          display: flex;
80          flex-direction: column;
81          right: 0px;
82          top: 0px;
83          bottom: 0px;
84          height: 100%;
85          overflow: auto;
86          background-color: var(--dark-background,#FFFFFF);
87          -webkit-transform: translateZ(0);
88          -moz-transform: translateZ(0);
89          -ms-transform: translateZ(0);
90          -o-transform: translateZ(0);
91          transform: translateZ(0);
92          transform: translateX(100%);
93          transition: transform .3s;
94       }
95       :host(:not([placement])[visible]) .drawer,
96       :host([placement='right'][visible]) .drawer{
97          transform: translateX(0%);
98          box-shadow: 0px 0 20px 0px #00000055;
99       }
100       :host(:not([visible]):not([placement])) .drawer,
101       :host(:not([visible])[placement='right']) .drawer{
102          transform: translateX(100%);
103       }
104       /*
105          左边
106       */
107       :host([placement='left']) .drawer{
108          width: {2};
109          box-sizing: border-box;
110          position: absolute;
111          display: flex;
112          flex-direction: column;
113          left: 0px;
114          top: 0px;
115          bottom: 0px;
116          right: auto;
117          height: 100%;
118          background-color: var(--dark-background,#FFFFFF);
119          webkit-transform: translate3d(0,0,0);
120          -moz-transform: translate3d(0,0,0);
121          -ms-transform: translate3d(0,0,0);
122          -o-transform: translate3d(0,0,0);
123          transform: translate3d(0,0,0);
124          transform: translate(0%,0%);
125       }
126       :host([placement='left']) .drawer{
127          transition: transform .3s;
128       }
129       :host([placement='left'][visible]) .drawer{
130          box-shadow: 0px 0 60px 0px #00000055;
131          transform: translate(0%,0%);
132       }
133       :host(:not([visible])[placement='left']) .drawer{
134          transform: translate(-100%,0%);
135       }
136       
137       /*
138          top
139       */
140       :host([placement='top']) .drawer{
141          box-sizing: border-box;
142          position: absolute;
143          display: flex;
144          flex-direction: column;
145          left: 0px;
146          top: 0px;
147          right: 0px;
148          width: 100%;
149          background-color: var(--dark-background,#FFFFFF);
150          webkit-transform: translate3d(0,0,0);
151          -moz-transform: translate3d(0,0,0);
152          -ms-transform: translate3d(0,0,0);
153          -o-transform: translate3d(0,0,0);
154          transform: translate3d(0,0,0);
155       }
156       :host([placement='top']) .drawer{
157          transform: translateY(-100%);
158          transition: transform .3s;
159       }
160       :host([placement='top'][visible]) .drawer{
161          box-shadow: 0px 0 60px 0px #00000055;
162          transform: translateY(0%);
163       }
164       :host(:not([visible])[placement='top']) .drawer{
165          transform: translateY(-100%);
166       }
167       
168       /*
169          bottom
170       */
171       :host([placement='bottom']) .drawer{
172          box-sizing: border-box;
173          position: absolute;
174          display: flex;
175          flex-direction: column;
176          left: 0px;
177          bottom: 0px;
178          right: 0px;
179          top: auto;
180          width: 100%;
181          background-color: var(--dark-background,#FFFFFF);
182          webkit-transform: translate3d(0,0,0);
183          -moz-transform: translate3d(0,0,0);
184          -ms-transform: translate3d(0,0,0);
185          -o-transform: translate3d(0,0,0);
186          transform: translate3d(0,0,0);
187          transform: translate(0%,0%);
188          transition: transform .3s;
189       }
190       :host([placement='bottom'][visible]) .drawer{
191          box-shadow: 0px 0 60px 0px #00000055;
192          transform: translate(0%,0%);
193       }
194       :host(:not([visible])[placement='bottom']) .drawer{
195          transform: translate(0%,100%);
196       }
197       
198       :host([closeable]) .close-icon{
199          display: flex;
200          color: #8c8c8c;
201          padding: 5px;
202       }
203       :host([closeable]) .close-icon:hover{
204          color: #414141;
205       }
206       :host(:not([closeable])) .close-icon{
207          display: none;
208       }
209      </style>
210`;
211
212const initHtmlStyle = (padding: string, width: string): string => {
213  return replacePlaceholders(css, padding, width);
214};
215
216@element('lit-drawer')
217export class LitDrawer extends BaseElement {
218  static get observedAttributes(): string[] {
219    return [
220      'drawer-title',
221      'visible',
222      'placement',
223      'mask',
224      'mask-closable',
225      'closeable',
226      'content-padding',
227      'content-width',
228    ];
229  }
230
231  initHtml(): string {
232    return `
233        ${initHtmlStyle(this.contentPadding, this.contentWidth)}
234        <div class="bg"></div>
235        <div class="drawer">
236            <div class="title">
237                <label id="drawer-tittle-text">${this.title}</label>
238                <lit-icon class="close-icon" name="close"></lit-icon>
239            </div>
240            <div style="overflow-x: hidden;overflow-y: auto">
241                <slot></slot>
242            </div>
243        </div>
244        `;
245  }
246  get contentWidth(): string {
247    return this.getAttribute('content-width') || '400px';
248  }
249  set contentWidth(value) {
250    this.shadowRoot!.querySelector<HTMLDivElement>('.drawer')!.style.width = value;
251    this.setAttribute('content-width', value);
252  }
253  get contentPadding(): string {
254    return this.getAttribute('content-padding') || '20px';
255  }
256  set contentPadding(value) {
257    this.shadowRoot!.querySelector('slot')!.style.padding = value;
258    this.setAttribute('content-padding', value);
259  }
260  get placement(): string | null {
261    return this.getAttribute('placement');
262  }
263  set placement(value: unknown) {
264    // @ts-ignore
265    this.setAttribute('placement', value);
266  }
267  get drawerTitle(): string {
268    return this.getAttribute('drawer-title') || '';
269  }
270  set drawerTitle(value) {
271    this.shadowRoot!.querySelector('#drawer-tittle-text')!.textContent = value;
272    this.setAttribute('drawer-title', value);
273  }
274  get visible(): boolean {
275    return this.getAttribute('visible') !== null;
276  }
277  set visible(value: unknown) {
278    if (value) {
279      // @ts-ignore
280      this.setAttribute('visible', value);
281    } else {
282      this.removeAttribute('visible');
283    }
284  }
285  get mask(): boolean {
286    return this.getAttribute('mask') !== null;
287  }
288  set mask(value) {
289    if (value) {
290      this.setAttribute('mask', '');
291    } else {
292      this.removeAttribute('mask');
293    }
294  }
295  get maskCloseable(): boolean {
296    return this.getAttribute('mask-closeable') !== null;
297  }
298  set maskCloseable(value) {
299    if (value) {
300      this.setAttribute('mask-closeable', '');
301    } else {
302      this.removeAttribute('mask-closeable');
303    }
304  }
305  get closeable(): boolean {
306    return this.getAttribute('closeable') !== null;
307  }
308
309  set closeable(value) {
310    if (value) {
311      this.setAttribute('closeable', '');
312    } else {
313      this.removeAttribute('closeable');
314    }
315  }
316
317  //当 custom element首次被插入文档DOM时,被调用。
318  initElements(): void {
319    let bg: HTMLDivElement | null = this.shadowRoot!.querySelector('.bg');
320    if (this.maskCloseable) {
321      bg!.onclick = (e: unknown): void => {
322        // @ts-ignore
323        e.stopPropagation();
324        this.visible = false; // @ts-ignore
325        this.dispatchEvent(new CustomEvent('onClose', e));
326      };
327    }
328    if (this.closeable) {
329      // @ts-ignore
330      (this.shadowRoot!.querySelector('.close-icon') as unknown).onclick = (e: unknown): void => {
331        this.visible = false; // @ts-ignore
332        this.dispatchEvent(new CustomEvent('onClose', e));
333      };
334    }
335  }
336  set onClose(fn: unknown) {
337    // @ts-ignore
338    this.addEventListener('onClose', fn);
339  }
340  //当 custom element从文档DOM中删除时,被调用。
341  disconnectedCallback(): void {}
342
343  //当 custom element被移动到新的文档时,被调用。
344  adoptedCallback(): void {}
345
346  //当 custom element增加、删除、修改自身属性时,被调用。
347  attributeChangedCallback(name: string, oldValue: string, newValue: string): void {
348    if (this.mask) {
349      if (name === 'visible') {
350        if (newValue !== null) {
351          this.style.pointerEvents = 'all';
352        } else {
353          this.style.pointerEvents = 'none';
354        }
355      } else if (name === 'placement') {
356        if (newValue === 'bottom') {
357          let el = this.shadowRoot!.querySelector('.drawer');
358        }
359      }
360    }
361  }
362}
363
364if (!customElements.get('lit-drawer')) {
365  customElements.define('lit-drawer', LitDrawer);
366}
367