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 listHeight = ''; 19let css = ` 20<style> 21 :host{ 22 display: inline-flex; 23 overflow: visible; 24 cursor: pointer; 25 position: relative; 26 border-radius: 16px; 27 outline: none; 28 user-select:none; 29 width: 75%; 30 -webkit-user-select:none ; 31 -moz-user-select:none; 32 } 33 :host(:not([border])), 34 :host([border='true']){ 35 border: 1px solid var(--bark-prompt,#dcdcdc); 36 } 37 .multipleSelect{ 38 display: flex; 39 width: 100%; 40 z-index: 98; 41 position: relative; 42 padding: 3px 6px; 43 font-size: 1rem; 44 transition: all .3s; 45 outline: none; 46 user-select:none; 47 align-items: center; 48 justify-content: space-between; 49 -webkit-user-select:none ; 50 -moz-user-select:none; 51 } 52 input{ 53 display: inline-flex; 54 width:100%; 55 z-index: 8999; 56 color: var(--dark-color2,rgba(0,0,0,0.9)); 57 background-color: transparent; 58 border: 0; 59 user-select:none; 60 outline: none; 61 cursor: pointer; 62 -webkit-user-select:none ; 63 -moz-user-select:none; 64 } 65 .body{ 66 max-height: ${listHeight}; 67 width: 100%; 68 display: block; 69 overflow: auto; 70 position: absolute; 71 bottom: 100%; 72 padding-top: 5px; 73 margin-top: 2px; 74 transition: all 0.2s; 75 flex-direction: column; 76 transform-origin: bottom center; 77 box-shadow: 0 5px 15px 0px #00000033; 78 background-color: var(--dark-background4,#fff); 79 border-radius: 2px; 80 opacity: 0; 81 z-index: 99; 82 visibility: hidden; 83 } 84 :host([placement="bottom"]) .body{ 85 bottom:unset; 86 top: 100%; 87 transition: none; 88 transform: none; 89 } 90 .body-bottom{ 91 top: 100%; 92 transform-origin: top center; 93 bottom: auto; 94 } 95 .multipleRoot input::-webkit-input-placeholder { 96 color: var(--dark-color,#aab2bd); 97 } 98 :host([disabled]) { 99 pointer-events: none; 100 cursor: not-allowed; 101 background-color: var(--dark-background1,#f5f5f5); 102 } 103 </style> 104`; 105const initHtmlStyle = (height: string): string => { 106 listHeight = height; 107 return css; 108}; 109 110@element('lit-allocation-select') 111export class LitAllocationSelect extends BaseElement { 112 private selectAllocationInputEl: HTMLInputElement | null | undefined; 113 private selectAllocationInputContent: HTMLDivElement | undefined; 114 private selectAllocationOptions: any; 115 private processDataList: Array<string> = []; 116 117 static get observedAttributes() { 118 return ['value', 'disabled', 'placeholder']; 119 } 120 121 get defaultPlaceholder() { 122 return this.getAttribute('placeholder') || ''; 123 } 124 125 get placeholder() { 126 return this.getAttribute('placeholder') || this.defaultPlaceholder; 127 } 128 129 set placeholder(selectAllocationValue) { 130 this.setAttribute('placeholder', selectAllocationValue); 131 } 132 133 get value() { 134 return this.getAttribute('value') || ''; 135 } 136 137 set value(selectAllocationValue: string) { 138 this.setAttribute('value', selectAllocationValue); 139 } 140 141 set processData(value: Array<string>) { 142 this.processDataList = value; 143 this.selectAllocationOptions.innerHTML = ''; 144 value.forEach((item) => { 145 let option = document.createElement('div'); 146 option.className = 'option'; 147 option.innerHTML = item; 148 option.style.padding = '8px 10px'; 149 this.selectAllocationOptions.appendChild(option); 150 this.selectAllocationInputEl?.focus(); 151 }); 152 } 153 154 get placement(): string { 155 return this.getAttribute('placement') || ''; 156 } 157 158 set placement(selectAllocationValuePlacement: string) { 159 if (selectAllocationValuePlacement) { 160 this.setAttribute('placement', selectAllocationValuePlacement); 161 } else { 162 this.removeAttribute('placement'); 163 } 164 } 165 166 get listHeight() { 167 return this.getAttribute('list-height') || '256px'; 168 } 169 170 set listHeight(value) { 171 this.setAttribute('list-height', value); 172 } 173 174 attributeChangedCallback(name: any, oldValue: any, newValue: any) { 175 switch (name) { 176 case 'value': 177 this.selectAllocationInputEl!.value = newValue; 178 break; 179 case 'placeholder': 180 this.selectAllocationInputEl!.placeholder = newValue; 181 break; 182 } 183 } 184 185 initElements(): void { 186 this.selectAllocationInputContent = this.shadowRoot!.querySelector('.multipleSelect') as HTMLDivElement; 187 this.addEventListener('click', () => { 188 if (this.selectAllocationOptions.style.visibility == 'visible') { 189 this.selectAllocationOptions.style.visibility = 'hidden'; 190 this.selectAllocationOptions.style.opacity = '0'; 191 } else { 192 this.showProcessList(); 193 } 194 this.selectAllocationInputContent!.dispatchEvent(new CustomEvent('inputClick', {})); 195 }); 196 this.addEventListener('focusout', (e) => { 197 this.selectAllocationOptions.style.visibility = 'hidden'; 198 this.selectAllocationOptions.style.opacity = '0'; 199 }); 200 this.initData(); 201 } 202 203 showProcessList() { 204 setTimeout(() => { 205 if (this.processDataList.length > 0) { 206 this.selectAllocationOptions.style.visibility = 'visible'; 207 this.selectAllocationOptions.style.opacity = '1'; 208 } 209 }, 200); 210 } 211 212 initHtml() { 213 return ` 214 ${initHtmlStyle(this.listHeight)} 215 <div class="multipleSelect" tabindex="0"> 216 <div class="multipleRoot" id="select" style="width:100%"> 217 <input id="singleInput" placeholder="${this.placeholder}"/> 218 </div> 219 <lit-icon class="icon" name='down' color="#c3c3c3"></lit-icon> 220 </div> 221 <div class="body body-bottom"> 222 <slot></slot> 223 <slot name="footer"></slot> 224 </div> 225 `; 226 } 227 228 connectedCallback() { 229 this.selectAllocationInputEl!.onkeydown = (ev): void => { 230 // @ts-ignore 231 if (ev.key === '0' && ev.target.value.length === 1 && ev.target.value === '0') { 232 ev.preventDefault(); 233 } 234 }; 235 } 236 237 initData() { 238 this.selectAllocationInputEl = this.shadowRoot!.querySelector('input'); 239 this.selectAllocationOptions = this.shadowRoot!.querySelector('.body') as HTMLDivElement; 240 this.selectAllocationInputEl?.addEventListener('input', () => { 241 let filter = [...this.shadowRoot!.querySelectorAll<HTMLDivElement>('.option')].filter((a: HTMLDivElement) => { 242 if (a.textContent!.indexOf(this.selectAllocationInputEl!.value) <= -1) { 243 a.style.display = 'none'; 244 } else { 245 a.style.display = 'block'; 246 } 247 }); 248 this.value = this.selectAllocationInputEl!.value; 249 this.selectAllocationInputContent!.dispatchEvent(new CustomEvent('valuable', {})); 250 }); 251 this.shadowRoot?.querySelectorAll('.option').forEach((a) => { 252 a.addEventListener('mousedown', (e) => { 253 a.dispatchEvent( 254 new CustomEvent('onSelected', { 255 detail: { 256 selected: true, 257 text: a.textContent, 258 }, 259 }) 260 ); 261 }); 262 a.addEventListener('onSelected', (e: any) => { 263 this.selectAllocationInputEl!.value = e.detail.text; 264 this.value = e.detail.text; 265 this.selectAllocationInputContent!.dispatchEvent(new CustomEvent('valuable', {})); 266 }); 267 }); 268 } 269} 270