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';
17import { replacePlaceholders } from '../utils/Template';
18
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: {1};
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  return replacePlaceholders(css, height);
107};
108
109@element('lit-allocation-select')
110export class LitAllocationSelect extends BaseElement {
111  private selectAllocationInputEl: HTMLInputElement | null | undefined;
112  private selectAllocationInputContent: HTMLDivElement | undefined;
113  private selectAllocationOptions: unknown;
114  private processDataList: Array<string> = [];
115
116  static get observedAttributes(): string[] {
117    return ['value', 'disabled', 'placeholder'];
118  }
119
120  get defaultPlaceholder(): string {
121    return this.getAttribute('placeholder') || '';
122  }
123
124  get placeholder(): string {
125    return this.getAttribute('placeholder') || this.defaultPlaceholder;
126  }
127
128  set placeholder(selectAllocationValue) {
129    this.setAttribute('placeholder', selectAllocationValue);
130  }
131
132  get value(): string {
133    return this.getAttribute('value') || '';
134  }
135
136  set value(selectAllocationValue: string) {
137    this.setAttribute('value', selectAllocationValue);
138  }
139
140  set processData(value: Array<string>) {
141    this.processDataList = value; // @ts-ignore
142    this.selectAllocationOptions.innerHTML = '';
143    value.forEach((item) => {
144      let option = document.createElement('div');
145      option.className = 'option';
146      option.innerHTML = item;
147      option.style.padding = '8px 10px'; // @ts-ignore
148      this.selectAllocationOptions.appendChild(option);
149      this.selectAllocationInputEl?.focus();
150    });
151  }
152
153  get placement(): string {
154    return this.getAttribute('placement') || '';
155  }
156
157  set placement(selectAllocationValuePlacement: string) {
158    if (selectAllocationValuePlacement) {
159      this.setAttribute('placement', selectAllocationValuePlacement);
160    } else {
161      this.removeAttribute('placement');
162    }
163  }
164
165  get listHeight(): string {
166    return this.getAttribute('list-height') || '256px';
167  }
168
169  set listHeight(value) {
170    this.setAttribute('list-height', value);
171  }
172
173  attributeChangedCallback(name: unknown, oldValue: unknown, newValue: unknown): void {
174    switch (name) {
175      case 'value': // @ts-ignore
176        this.selectAllocationInputEl!.value = newValue;
177        break;
178      case 'placeholder': // @ts-ignore
179        this.selectAllocationInputEl!.placeholder = newValue;
180        break;
181    }
182  }
183
184  initElements(): void {
185    this.selectAllocationInputContent = this.shadowRoot!.querySelector('.multipleSelect') as HTMLDivElement;
186    this.addEventListener('click', () => {
187      // @ts-ignore
188      if (this.selectAllocationOptions.style.visibility === 'visible') {
189        // @ts-ignore
190        this.selectAllocationOptions.style.visibility = 'hidden'; // @ts-ignore
191        this.selectAllocationOptions.style.opacity = '0';
192      } else {
193        this.showProcessList();
194      }
195      this.selectAllocationInputContent!.dispatchEvent(new CustomEvent('inputClick', {}));
196    });
197    this.addEventListener('focusout', (e) => {
198      // @ts-ignore
199      this.selectAllocationOptions.style.visibility = 'hidden'; // @ts-ignore
200      this.selectAllocationOptions.style.opacity = '0';
201    });
202    this.initData();
203  }
204
205  showProcessList(): void {
206    setTimeout(() => {
207      if (this.processDataList.length > 0) {
208        // @ts-ignore
209        this.selectAllocationOptions.style.visibility = 'visible'; // @ts-ignore
210        this.selectAllocationOptions.style.opacity = '1';
211      }
212    }, 200);
213  }
214
215  initHtml(): string {
216    return `
217        ${initHtmlStyle(this.listHeight)}
218        <div class="multipleSelect" tabindex="0">
219            <div class="multipleRoot" id="select" style="width:100%">
220            <input id="singleInput" placeholder="${this.placeholder}"/>
221        </div>
222            <lit-icon class="icon" name='down' color="#c3c3c3"></lit-icon>
223        </div>
224        <div class="body body-bottom">
225            <slot></slot>
226            <slot name="footer"></slot>
227        </div>
228        `;
229  }
230
231  connectedCallback(): void {
232    this.selectAllocationInputEl!.onkeydown = (ev): void => {
233      // @ts-ignore
234      if (ev.key === '0' && ev.target.value.length === 1 && ev.target.value === '0') {
235        ev.preventDefault();
236      }
237    };
238  }
239
240  initData(): void {
241    this.selectAllocationInputEl = this.shadowRoot!.querySelector('input');
242    this.selectAllocationOptions = this.shadowRoot!.querySelector('.body') as HTMLDivElement;
243    this.selectAllocationInputEl?.addEventListener('input', () => {
244      let filter = [...this.shadowRoot!.querySelectorAll<HTMLDivElement>('.option')].filter((a: HTMLDivElement) => {
245        if (a.textContent!.indexOf(this.selectAllocationInputEl!.value) <= -1) {
246          a.style.display = 'none';
247        } else {
248          a.style.display = 'block';
249        }
250      });
251      this.value = this.selectAllocationInputEl!.value;
252      this.selectAllocationInputContent!.dispatchEvent(new CustomEvent('valuable', {}));
253    });
254    this.shadowRoot?.querySelectorAll('.option').forEach((a) => {
255      a.addEventListener('mousedown', (e) => {
256        a.dispatchEvent(
257          new CustomEvent('onSelected', {
258            detail: {
259              selected: true,
260              text: a.textContent,
261            },
262          })
263        );
264      });
265      a.addEventListener('onSelected', (e: unknown) => {
266        // @ts-ignore
267        this.selectAllocationInputEl!.value = e.detail.text; // @ts-ignore
268        this.value = e.detail.text;
269        this.selectAllocationInputContent!.dispatchEvent(new CustomEvent('valuable', {}));
270      });
271    });
272  }
273}
274