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