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