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