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