• 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';
17let width = '';
18let css = `
19<style>
20    :host{
21        outline: none;
22        display:inline-block;
23        position: relative;
24        overflow: visible;
25    }
26
27    .title{
28        padding: 6px 15px;
29        font-weight: bold;
30        font-size: 0.9rem;
31        border-bottom: 1px solid #f0f0f0;
32    }
33    .content{
34        padding: 10px;
35    }
36   .trigger-click {
37        position: absolute;
38        visibility: hidden;
39        z-index: -100;
40        width: 100%;
41        height: 100%;
42    }
43    /*通用*/
44    .popover{
45        width: ${width};
46        min-width: 160px;
47        display: flex;
48        flex-direction: column;
49        visibility: hidden;
50        opacity: 0;
51        transition: all 0.3s;
52        z-index: 1;
53        position: absolute;
54        border-radius: 2px;
55        background-color: var(--dark-background3,#fff);
56        box-shadow: 0 0 20px #00000044;
57    }
58    .popover:after{
59        content: '';
60        display: flex;
61        position: absolute;
62        width: 12px;
63        height: 12px;
64        background: linear-gradient(45deg, var(--dark-background3,#FFFFFF),
65        var(--dark-background3,#FFFFFF) 50%, transparent 50%, transparent 100%);
66    }
67    :host(:not([placement])) .popover,
68    :host([placement='top']) .popover{
69        top: 0;
70        left: 50%;
71        right: 0;
72        transform: translate(-50%,calc(-100% - 12px)) scale(0.5);
73        transform-origin: bottom;
74    }
75    :host(:not([placement])) .popover:after,
76    :host([placement='top']) .popover:after{
77        border-top: 6px solid #fff;
78        left: 0;
79        top: calc(100%);
80        transform: translate(-50%,0%);
81        left: 50%;
82    }
83    :host(:not([placement])[trigger='hover']:hover)  .popover,
84    :host(:not([placement]):not([trigger]):hover)  .popover,
85    :host([placement='top'][trigger='hover']:hover)  .popover,
86    :host([placement='top']:not([trigger]):hover)  .popover {
87        visibility: visible;
88        opacity: 1;
89        transform: translate(-50%,calc(-100% - 12px)) scale(1);
90    }
91    :host(:not([placement])[trigger='click']) input[type=checkbox]:checked ~ .popover,
92    :host([placement='top'][trigger='click']) input[type=checkbox]:checked ~ .popover {
93        visibility: visible;
94        opacity: 1;
95        transform: translate(-50%,calc(-100% - 12px)) scale(1);
96    }
97    :host([placement='topLeft']) .popover{
98        top: 0;
99        left: 50%;
100        right: 0;
101        transform: translate(0,calc(-100% - 12px)) scale(0.5);
102        transform-origin: left bottom;
103    }
104    :host([placement='topLeft']) .popover:after{
105        top: 99%;
106        transform: rotateX(180deg);
107    }
108    :host([placement='topLeft']:not([trigger]):hover)  .popover,
109    :host([placement='topLeft'][trigger='hover']:hover)  .popover {
110        visibility: visible;
111        opacity: 1;
112        transform: translate(0%,calc(-100% - 12px)) scale(1);
113    }
114    :host([placement='topLeft'][trigger='click']) input[type=checkbox]:checked ~ .popover {
115        visibility: visible;
116        opacity: 1;
117        transform: translate(0%,calc(-100% - 12px)) scale(1);
118    }
119    :host([placement='topRight']) .popover{
120        top: 0;
121        right: 0;
122        transform: translate(0,calc(-100% - 12px)) scale(0.5);
123        transform-origin: right bottom;
124    }
125    :host([placement='topRight']) .popover:after{
126        border-top: 6px solid #fff;
127        top: calc(100%);
128        transform: translate(0%,0%);
129        right: 20px;
130    }
131    :host([placement='topRight']:not([trigger]):hover)  .popover,
132    :host([placement='topRight'][trigger='hover']:hover)  .popover {
133        visibility: visible;
134        opacity: 1;
135        transform: translate(0%,calc(-100% - 12px)) scale(1);
136    }
137    :host([placement='topRight'][trigger='click']) input[type=checkbox]:checked ~ .popover {
138        visibility: visible;
139        opacity: 1;
140        transform: translate(0%,calc(-100% - 12px)) scale(1);
141    }
142    :host([placement='leftTop']) .popover{
143        top: 0;
144        right: 100%;
145        transform: translate(-12px,0) scale(0.5);
146        transform-origin: right top;
147    }
148    :host([placement='leftTop']) .popover:after{
149        border-left: 6px solid #fff;
150        top: 10px;
151        right: -12px;
152        transform: translate(0px,0%);
153    }
154    :host([placement='leftTop']:not([trigger]):hover)  .popover,
155    :host([placement='leftTop'][trigger='hover']:hover)  .popover {
156        visibility: visible;
157        opacity: 1;
158        right: 100%;
159        transform: translate(-12px,0) scale(1);
160    }
161    :host([placement='leftTop'][trigger='click']) input[type=checkbox]:checked ~ .popover {
162        visibility: visible;
163        opacity: 1;
164        transform: translate(-12px,0) scale(1);
165    }
166    :host([placement='left']) .popover{
167        right: 100%;
168        top: 50%;
169        transform: translate(-12px,-50%) scale(0.5);
170        transform-origin: right center;
171    }
172    :host([placement='left']) .popover:after{
173        border-left: 6px solid #fff;
174        top: 50%;
175        right: -12px;
176        transform: translate(0px,-50%);
177    }
178    :host([placement='left']:not([trigger]):hover)  .popover,
179    :host([placement='left'][trigger='hover']:hover)  .popover {
180        visibility: visible;
181        opacity: 1;
182        right: 100%;
183        transform: translate(-12px,-50%) scale(1);
184    }
185    :host([placement='left'][trigger='click']) input[type=checkbox]:checked ~ .popover {
186        visibility: visible;
187        opacity: 1;
188        transform: translate(-12px,-50%) scale(1);
189    }
190    :host([placement='leftBottom']) .popover{
191        right: 100%;
192        bottom: 0;
193        transform: translate(-12px,0%) scale(0.5);
194        transform-origin: right bottom;
195    }
196    :host([placement='leftBottom']) .popover:after{
197        border-left: 6px solid #fff;
198        bottom: 10px;
199        right: -12px;
200        transform: translate(0px,-50%);
201    }
202    :host([placement='leftBottom']:not([trigger]):hover)  .popover,
203    :host([placement='leftBottom'][trigger='hover']:hover)  .popover {
204        visibility: visible;
205        opacity: 1;
206        right: 100%;
207        transform: translate(-12px,0%) scale(1);
208    }
209    :host([placement='leftBottom'][trigger='click']) input[type=checkbox]:checked ~ .popover {
210        visibility: visible;
211        opacity: 1;
212        transform: translate(-12px,0%) scale(1);
213    }
214    :host([placement='rightTop']) .popover{
215        top: 0;
216        left: 100%;
217        transform: translate(12px,0) scale(0.5);
218        transform-origin: left top;
219    }
220    :host([placement='rightTop']) .popover:after{
221        border-right: 6px solid #fff;
222        top: 10px;
223        left: -12px;
224        transform: translate(0px,0%);
225    }
226    :host([placement='rightTop']:not([trigger]):hover)  .popover,
227    :host([placement='rightTop'][trigger='hover']:hover)  .popover {
228        visibility: visible;
229        opacity: 1;
230        left: 100%;
231        transform: translate(12px,0) scale(1);
232    }
233    :host([placement='rightTop'][trigger='click']) input[type=checkbox]:checked ~ .popover {
234        visibility: visible;
235        opacity: 1;
236        transform: translate(12px,0) scale(1);
237    }
238    :host([placement='right']) .popover{
239        top: 50%;
240        left: 100%;
241        transform: translate(12px,-50%) scale(0.5);
242        transform-origin: left center;
243    }
244    :host([placement='right']) .popover:after{
245        border-right: 6px solid #fff;
246        top: 50%;
247        left: -12px;
248        transform: translate(0px,-50%);
249    }
250    :host([placement='right']:not([trigger]):hover)  .popover,
251    :host([placement='right'][trigger='hover']:hover)  .popover {
252        visibility: visible;
253        opacity: 1;
254        left: 100%;
255        transform: translate(12px,-50%) scale(1);
256    }
257    :host([placement='right'][trigger='click']) input[type=checkbox]:checked ~ .popover {
258        visibility: visible;
259        opacity: 1;
260        transform: translate(12px,-50%) scale(1);
261    }
262    :host([placement='rightBottom']) .popover{
263        bottom: 0;
264        left: 100%;
265        transform: translate(12px,0%) scale(0.5);
266        transform-origin: left bottom;
267    }
268    :host([placement='rightBottom']) .popover:after{
269        border-right: 6px solid #fff;
270        left: -12px;
271        bottom: 10px;
272        transform: translate(0px,0);
273    }
274    :host([placement='rightBottom']:not([trigger]):hover)  .popover,
275    :host([placement='rightBottom'][trigger='hover']:hover)  .popover {
276        visibility: visible;
277        opacity: 1;
278        bottom: 0;
279        transform: translate(12px,0%) scale(1);
280    }
281    :host([placement='rightBottom'][trigger='click']) input[type=checkbox]:checked ~ .popover {
282        visibility: visible;
283        opacity: 1;
284        transform: translate(12px,0%) scale(1);
285    }
286
287    :host([placement='bottomLeft']) .popover{
288        bottom: 0;
289        /*left: 0;*/
290        left: 8px;
291        right: 0;
292        transform: translate(0,calc(100% + 12px)) scale(0.5);
293        transform-origin: top left;
294    }
295    :host([placement='bottomLeft']) .popover:after{
296        bottom: calc(100%);
297        transform: translate(0%,0%);
298        left: 0;
299    }
300    :host([placement='bottomLeft']:not([trigger]):hover)  .popover,
301    :host([placement='bottomLeft'][trigger='hover']:hover)  .popover {
302        visibility: visible;
303        opacity: 1;
304        transform: translate(0%,calc(100% + 12px)) scale(1);
305    }
306    :host([placement='bottomLeft'][trigger='click']) input[type=checkbox]:checked ~ .popover {
307        visibility: visible;
308        opacity: 1;
309        transform: translate(0%,calc(100% + 12px)) scale(1);
310    }
311    :host([placement='bottom']) .popover{
312        bottom: 0;
313        left: 50%;
314        right: 0;
315        transform: translate(-50%,calc(100% + 12px)) scale(0.5);
316        transform-origin: top center;
317    }
318    :host([placement='bottom']) .popover:after{
319        border-bottom: 6px solid #fff;
320        bottom: calc(100%);
321        transform: translate(-50%,0%);
322        left: 50%;
323    }
324    :host([placement='bottom']:not([trigger]):hover)  .popover,
325    :host([placement='bottom'][trigger='hover']:hover)  .popover {
326        visibility: visible;
327        opacity: 1;
328        transform: translate(-50%,calc(100% + 12px)) scale(1);
329    }
330    :host([placement='bottom'][trigger='click']) input[type=checkbox]:checked ~ .popover {
331        visibility: visible;
332        opacity: 1;
333        transform: translate(-50%,calc(100% + 12px)) scale(1);
334    }
335    /*bottomRight*/
336    :host([placement='bottomRight']) .popover{
337        bottom: 0;
338        right: 0;
339        transform: translate(0%,calc(100% + 12px)) scale(0.5);
340        transform-origin: top right;
341    }
342    :host([placement='bottomRight']) .popover:after{
343        border-bottom: 6px solid #fff;
344        bottom: calc(100%);
345        transform: translate(-50%,0%);
346        right: 10px;
347    }
348    :host([placement='bottomRight']:not([trigger]):hover)  .popover,
349    :host([placement='bottomRight'][trigger='hover']:hover)  .popover {
350        visibility: visible;
351        opacity: 1;
352        transform: translate(0,calc(100% + 12px)) scale(1);
353    }
354    :host([placement='bottomRight'][trigger='click']) input[type=checkbox]:checked ~ .popover {
355        visibility: visible;
356        opacity: 1;
357        transform: translate(0%,calc(100% + 12px)) scale(1);
358    }
359    :host(:not([title])) .title{
360        display: none;
361    }
362    </style>
363`
364const initHtmlStyle = (wid: string) => {
365  width = wid;
366  return css;
367};
368
369@element('lit-popover')
370export class LitPopover extends BaseElement {
371  static get observedAttributes() {
372    return ['title', 'trigger', 'width', 'placement', 'visible'];
373  }
374
375  get visible() {
376    return this.getAttribute('visible') || 'false';
377  }
378
379  set visible(value) {
380    if (value) {
381      this.setAttribute('visible', 'true');
382    } else {
383      this.setAttribute('visible', 'false');
384    }
385  }
386
387  set placement(value) {
388    this.setAttribute('placement', value || 'bottomLeft');
389  }
390
391  get placement() {
392    return this.getAttribute('placement');
393  }
394
395  get trigger() {
396    return this.getAttribute('trigger') || 'hover';
397  }
398
399  set trigger(value) {
400    this.setAttribute('trigger', value);
401  }
402
403  get title() {
404    return this.getAttribute('title');
405  }
406
407  set title(value: any) {
408    this.setAttribute('title', value);
409  }
410
411  get width() {
412    return this.getAttribute('width') || 'max-content';
413  }
414
415  set width(value) {
416    this.setAttribute('width', value);
417  }
418
419  get haveRadio() {
420    return this.getAttribute('haveRadio');
421  }
422
423  initElements(): void {}
424
425  initHtml() {
426    return `
427        ${initHtmlStyle(this.width)}
428        <input class="trigger-click" type="checkbox">
429        <div class="popover" title="">
430            <div class="title">${this.title}</div>
431            <div class="content"><slot name="content" ></slot></div>
432        </div>
433        <slot></slot>
434        `;
435  }
436
437  connectedCallback() {
438    let popover: any = this.shadowRoot!.querySelector('.popover');
439    let checkbox: any = this.shadowRoot!.querySelector('.trigger-click');
440    this.setAttribute('tabindex', '1');
441    popover.onclick = (e: any) => {
442      e.stopPropagation();
443    };
444    popover.addEventListener('mousemove', (e: any) => {
445      e.stopPropagation();
446    });
447    this.onclick = (e: any) => {
448      e.stopPropagation();
449      if (e.relatedTarget?.hasAttribute('not-close')) {
450        this.focus();
451      }
452      checkbox.checked = !checkbox.checked;
453      this.visible = checkbox.checked;
454    };
455    popover.onmouseleave = () => {
456      this.focus();
457    };
458    this.onblur = (ev: any) => {
459      if (ev.relatedTarget && this.haveRadio) {
460        if (ev.relatedTarget.hasAttribute('not-close')) {
461        } else if (ev.relatedTarget.type === 'radio') {
462          this.focus();
463        } else {
464          // @ts-ignore
465          this.visible = false;
466        }
467      } else {
468        // @ts-ignore
469        this.visible = false;
470      }
471    };
472  }
473
474  disconnectedCallback() {}
475
476  adoptedCallback() {}
477
478  attributeChangedCallback(name: any, oldValue: any, newValue: any) {
479    if (name === 'visible') {
480      if (newValue === 'false') {
481        // @ts-ignore
482        this.shadowRoot!.querySelector('.trigger-click')!.checked = false;
483      } else {
484        // @ts-ignore
485        this.shadowRoot!.querySelector('.trigger-click')!.checked = true;
486      }
487    }
488  }
489}
490