@operato/popup 8.0.0-beta.0 → 8.0.0-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +18 -0
- package/package.json +4 -4
- package/.editorconfig +0 -29
- package/.storybook/main.js +0 -3
- package/.storybook/preview.js +0 -52
- package/.storybook/server.mjs +0 -8
- package/demo/index.html +0 -153
- package/demo/ox-popup-list.html +0 -93
- package/demo/ox-popup-menu.html +0 -153
- package/demo/ox-popup.html +0 -42
- package/src/index.ts +0 -7
- package/src/open-popup.ts +0 -166
- package/src/ox-floating-overlay.ts +0 -618
- package/src/ox-popup-list.ts +0 -577
- package/src/ox-popup-menu.ts +0 -247
- package/src/ox-popup-menuitem.ts +0 -187
- package/src/ox-popup.ts +0 -400
- package/src/ox-prompt.ts +0 -549
- package/src/position-converter.ts +0 -37
- package/stories/open-popup.stories.ts +0 -104
- package/stories/ox-popup-list-sortable.stories.ts +0 -215
- package/stories/ox-popup-list.stories.ts +0 -121
- package/stories/ox-popup-menu.stories.ts +0 -188
- package/stories/ox-popup.stories.ts +0 -79
- package/stories/ox-prompt-icon.stories.ts +0 -87
- package/stories/ox-prompt-normal.stories.ts +0 -80
- package/stories/ox-prompt.stories.ts +0 -82
- package/tsconfig.json +0 -25
- package/web-dev-server.config.mjs +0 -27
- package/web-test-runner.config.mjs +0 -41
package/src/ox-popup-list.ts
DELETED
@@ -1,577 +0,0 @@
|
|
1
|
-
import '@material/web/icon/icon.js'
|
2
|
-
|
3
|
-
import { css, CSSResult, html, PropertyValues } from 'lit'
|
4
|
-
import { render } from 'lit-html'
|
5
|
-
import { customElement, property, query, state } from 'lit/decorators.js'
|
6
|
-
import Sortable from 'sortablejs'
|
7
|
-
|
8
|
-
import { OxPopup } from './ox-popup.js'
|
9
|
-
import { convertToFixedPosition } from './position-converter.js'
|
10
|
-
|
11
|
-
function guaranteeFocus(element: HTMLElement) {
|
12
|
-
// 1. Give focus opportunity to the first focusable element within the option element.
|
13
|
-
const focusible = element.querySelector('button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])')
|
14
|
-
|
15
|
-
if (focusible) {
|
16
|
-
;(focusible as HTMLElement).focus()
|
17
|
-
return
|
18
|
-
}
|
19
|
-
|
20
|
-
// 2. Give focus opportunity to the closest parent, including itself.
|
21
|
-
const closest = element.closest(
|
22
|
-
'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
|
23
|
-
) as HTMLElement
|
24
|
-
|
25
|
-
closest?.focus()
|
26
|
-
}
|
27
|
-
|
28
|
-
/**
|
29
|
-
* A custom element representing a list-like popup menu.
|
30
|
-
*/
|
31
|
-
@customElement('ox-popup-list')
|
32
|
-
export class OxPopupList extends OxPopup {
|
33
|
-
static styles = [
|
34
|
-
...OxPopup.styles,
|
35
|
-
css`
|
36
|
-
:host {
|
37
|
-
display: none;
|
38
|
-
align-items: stretch;
|
39
|
-
background-color: var(--ox-popup-list-background-color, var(--md-sys-color-surface-container-lowest));
|
40
|
-
color: var(--ox-popup-list-color, var(--md-sys-color-on-surface));
|
41
|
-
z-index: 100;
|
42
|
-
box-shadow: 2px 3px 10px 5px rgba(0, 0, 0, 0.15);
|
43
|
-
padding: var(--spacing-small) 0;
|
44
|
-
border-radius: var(--md-sys-shape-corner-small, 5px);
|
45
|
-
|
46
|
-
font-size: var(--md-sys-typescale-label-large-size, 0.875rem);
|
47
|
-
}
|
48
|
-
|
49
|
-
:host([active]) {
|
50
|
-
display: flex;
|
51
|
-
flex-direction: column;
|
52
|
-
}
|
53
|
-
|
54
|
-
:host(*:focus) {
|
55
|
-
outline: none;
|
56
|
-
}
|
57
|
-
|
58
|
-
:host([nowrap]) ::slotted([option]) {
|
59
|
-
white-space: nowrap;
|
60
|
-
}
|
61
|
-
|
62
|
-
::slotted([option]) {
|
63
|
-
border-left: 3px solid transparent;
|
64
|
-
}
|
65
|
-
|
66
|
-
::slotted(*) {
|
67
|
-
padding: var(--spacing-medium);
|
68
|
-
border-bottom: 1px solid var(--md-sys-color-surface-variant);
|
69
|
-
cursor: pointer;
|
70
|
-
outline: none;
|
71
|
-
color: var(--ox-popup-list-color, var(--md-sys-color-on-surface-variant));
|
72
|
-
}
|
73
|
-
|
74
|
-
::slotted(*:focus) {
|
75
|
-
outline: none;
|
76
|
-
}
|
77
|
-
|
78
|
-
::slotted([option][active]),
|
79
|
-
::slotted([option]:hover) {
|
80
|
-
background-color: var(--ox-popup-list-background-color-variant, var(--md-sys-color-surface-variant));
|
81
|
-
color: var(--ox-popup-list-color-variant, var(--md-sys-color-on-surface-variant));
|
82
|
-
}
|
83
|
-
|
84
|
-
::slotted([option][selected]) {
|
85
|
-
border-left: 3px solid var(--md-sys-color-primary);
|
86
|
-
font-weight: var(--md-sys-typescale-label-large-weight, var(--md-ref-typeface-weight-medium, 500));
|
87
|
-
}
|
88
|
-
|
89
|
-
::slotted([separator]) {
|
90
|
-
height: 1px;
|
91
|
-
width: 100%;
|
92
|
-
padding: 0;
|
93
|
-
background-color: var(--ox-popup-menu-separator-color, var(--md-sys-color-surface-variant));
|
94
|
-
}
|
95
|
-
|
96
|
-
::slotted([hidden]) {
|
97
|
-
display: none;
|
98
|
-
}
|
99
|
-
|
100
|
-
[search] {
|
101
|
-
display: flex;
|
102
|
-
position: relative;
|
103
|
-
align-items: center;
|
104
|
-
padding: var(--spacing-small) var(--spacing-medium);
|
105
|
-
|
106
|
-
--md-icon-size: var(--icon-size-small);
|
107
|
-
}
|
108
|
-
|
109
|
-
[search] [type='text'] {
|
110
|
-
flex: 1;
|
111
|
-
background-color: transparent;
|
112
|
-
border: 0;
|
113
|
-
padding: 0 0 0 var(--spacing-huge);
|
114
|
-
outline: none;
|
115
|
-
width: 50px;
|
116
|
-
}
|
117
|
-
|
118
|
-
[search] md-icon {
|
119
|
-
color: var(--md-sys-color-secondary);
|
120
|
-
}
|
121
|
-
|
122
|
-
[search] md-icon[search-icon] {
|
123
|
-
position: absolute;
|
124
|
-
}
|
125
|
-
|
126
|
-
[search] md-icon[delete-icon] {
|
127
|
-
opacity: 0.5;
|
128
|
-
--md-icon-size: var(--icon-size-tiny);
|
129
|
-
}
|
130
|
-
|
131
|
-
[nothing] {
|
132
|
-
opacity: 0.5;
|
133
|
-
text-align: center;
|
134
|
-
}
|
135
|
-
|
136
|
-
div[body] {
|
137
|
-
flex: 1;
|
138
|
-
display: flex;
|
139
|
-
flex-direction: column;
|
140
|
-
margin: 0;
|
141
|
-
padding: 0;
|
142
|
-
overflow: auto;
|
143
|
-
}
|
144
|
-
`
|
145
|
-
]
|
146
|
-
|
147
|
-
/**
|
148
|
-
* A boolean property that, when set to true, allows multiple options to be selected in the popup list.
|
149
|
-
* @type {boolean}
|
150
|
-
*/
|
151
|
-
@property({ type: Boolean, attribute: true, reflect: true }) multiple: boolean = false
|
152
|
-
|
153
|
-
/**
|
154
|
-
* An optional attribute that specifies the name of the attribute used to mark selected options in the list.
|
155
|
-
* @type {string|undefined}
|
156
|
-
*/
|
157
|
-
@property({ type: String, attribute: 'attr-selected', reflect: true }) attrSelected?: string
|
158
|
-
|
159
|
-
/**
|
160
|
-
* A boolean property that, when set to true, enables the search functionality in the popup list.
|
161
|
-
* Users can search/filter options by typing in a search bar.
|
162
|
-
* @type {boolean|undefined}
|
163
|
-
*/
|
164
|
-
@property({ type: Boolean, attribute: 'with-search', reflect: true }) withSearch?: boolean
|
165
|
-
|
166
|
-
/**
|
167
|
-
* A boolean property that, when set to true, enables the drag-and-drop sorting functionality within the popup list.
|
168
|
-
* This allows users to reorder the options in the list by dragging them into new positions.
|
169
|
-
* @type {boolean|undefined}
|
170
|
-
*/
|
171
|
-
@property({ type: Boolean, attribute: 'sortable', reflect: true }) sortable?: boolean = false
|
172
|
-
|
173
|
-
/**
|
174
|
-
* The value(s) of the selected option(s) in the popup list.
|
175
|
-
* This property can be a string or an array of strings, depending on whether multiple selections are allowed.
|
176
|
-
* @type {string|string[]|undefined}
|
177
|
-
*/
|
178
|
-
@property({ type: String }) value?: string | string[]
|
179
|
-
|
180
|
-
@state() activeIndex?: number
|
181
|
-
@state() searchKeyword?: string
|
182
|
-
@state() nothingToSelect: boolean = false
|
183
|
-
|
184
|
-
@query('[search] input') searchInput!: HTMLInputElement
|
185
|
-
@query('div[body]') body!: HTMLDivElement
|
186
|
-
|
187
|
-
private sortableObject?: Sortable
|
188
|
-
private locked: boolean = false
|
189
|
-
|
190
|
-
render() {
|
191
|
-
return html`
|
192
|
-
<slot name="header"> </slot>
|
193
|
-
|
194
|
-
${this.withSearch
|
195
|
-
? html`
|
196
|
-
<label search for="search" @input=${(e: InputEvent) => this._oninputsearch(e)}>
|
197
|
-
<md-icon search-icon>search</md-icon>
|
198
|
-
<input
|
199
|
-
id="search"
|
200
|
-
type="text"
|
201
|
-
autocomplete="off"
|
202
|
-
@keydown=${(e: KeyboardEvent) => this._onkeydownsearch(e)}
|
203
|
-
@change=${(e: InputEvent) => this._onchangesearch(e)}
|
204
|
-
/>
|
205
|
-
<md-icon
|
206
|
-
@click=${() => {
|
207
|
-
this.searchInput.value = ''
|
208
|
-
this.searchKeyword = ''
|
209
|
-
}}
|
210
|
-
delete-icon
|
211
|
-
>delete</md-icon
|
212
|
-
>
|
213
|
-
</label>
|
214
|
-
`
|
215
|
-
: html``}
|
216
|
-
|
217
|
-
<div body>
|
218
|
-
<slot
|
219
|
-
@change=${(e: Event) => {
|
220
|
-
e.stopPropagation()
|
221
|
-
}}
|
222
|
-
>
|
223
|
-
</slot>
|
224
|
-
</div>
|
225
|
-
|
226
|
-
${this.nothingToSelect ? html`<label nothing>nothing to select</label>` : html``}
|
227
|
-
`
|
228
|
-
}
|
229
|
-
|
230
|
-
protected _oninputsearch(e: InputEvent) {
|
231
|
-
e.stopPropagation()
|
232
|
-
e.preventDefault()
|
233
|
-
|
234
|
-
this.searchKeyword = (e.target as HTMLInputElement).value
|
235
|
-
}
|
236
|
-
|
237
|
-
protected _onchangesearch(e: InputEvent) {
|
238
|
-
e.stopPropagation()
|
239
|
-
this.searchKeyword = (e.target as HTMLInputElement).value
|
240
|
-
}
|
241
|
-
|
242
|
-
protected _onkeydownsearch(e: KeyboardEvent) {
|
243
|
-
const keys = ['Esc', 'Escape', 'Up', 'ArrowUp', 'Down', 'ArrowDown']
|
244
|
-
if (!keys.includes(e.key)) {
|
245
|
-
e.stopPropagation()
|
246
|
-
}
|
247
|
-
}
|
248
|
-
|
249
|
-
protected _onkeydown: (e: KeyboardEvent) => void = function (this: OxPopupList, e: KeyboardEvent) {
|
250
|
-
e.stopPropagation()
|
251
|
-
|
252
|
-
switch (e.key) {
|
253
|
-
case 'Esc': // for IE/Edge
|
254
|
-
case 'Escape':
|
255
|
-
this.close()
|
256
|
-
break
|
257
|
-
|
258
|
-
case 'Left': // for IE/Edge
|
259
|
-
case 'ArrowLeft':
|
260
|
-
case 'Up': // for IE/Edge
|
261
|
-
case 'ArrowUp':
|
262
|
-
this.activeIndex!--
|
263
|
-
break
|
264
|
-
|
265
|
-
case 'Right': // for IE/Edge
|
266
|
-
case 'ArrowRight':
|
267
|
-
case 'Down': // for IE/Edge
|
268
|
-
case 'ArrowDown':
|
269
|
-
this.activeIndex!++
|
270
|
-
break
|
271
|
-
|
272
|
-
case 'Enter':
|
273
|
-
case ' ':
|
274
|
-
case 'Spacebar': // for old firefox
|
275
|
-
this.setActive(this.activeIndex!, true)
|
276
|
-
this.select()
|
277
|
-
break
|
278
|
-
}
|
279
|
-
}.bind(this)
|
280
|
-
|
281
|
-
protected _onfocusout: (e: FocusEvent) => void = function (this: OxPopupList, e: FocusEvent) {
|
282
|
-
const to = e.relatedTarget as HTMLElement
|
283
|
-
|
284
|
-
if (!this.contains(to)) {
|
285
|
-
/* If the focus has clearly moved to an element outside of my range, the ox-popup-list should be closed. */
|
286
|
-
// @ts-ignore for debug
|
287
|
-
!this.preventCloseOnBlur && !this.debug && !window.POPUP_DEBUG && this.close()
|
288
|
-
}
|
289
|
-
}.bind(this)
|
290
|
-
|
291
|
-
protected _onclick: (e: MouseEvent) => void = function (this: OxPopupList, e: MouseEvent) {
|
292
|
-
e.stopPropagation()
|
293
|
-
|
294
|
-
// Check if the click event target is a checkbox
|
295
|
-
if ((e.target as HTMLElement).closest('input[type="checkbox"]')) {
|
296
|
-
return // Do not proceed if it's a checkbox click
|
297
|
-
}
|
298
|
-
|
299
|
-
const option = (e.target as HTMLElement)?.closest('[option]')
|
300
|
-
if (option) {
|
301
|
-
this.setActive(option, true)
|
302
|
-
this.select()
|
303
|
-
}
|
304
|
-
}.bind(this)
|
305
|
-
|
306
|
-
updated(changes: PropertyValues<this>) {
|
307
|
-
if (changes.has('activeIndex')) {
|
308
|
-
this.activeIndex !== undefined && this.setActive(this.activeIndex)
|
309
|
-
}
|
310
|
-
|
311
|
-
if (changes.has('sortable')) {
|
312
|
-
this.sortableObject && this.sortableObject.destroy()
|
313
|
-
|
314
|
-
if (this.sortable) {
|
315
|
-
this.sortableObject = Sortable.create(this, {
|
316
|
-
handle: '[option]',
|
317
|
-
draggable: '[option]',
|
318
|
-
direction: 'vertical',
|
319
|
-
animation: 150,
|
320
|
-
touchStartThreshold: 10,
|
321
|
-
onEnd: e => {
|
322
|
-
this.locked = false
|
323
|
-
this.dispatchEvent(
|
324
|
-
new CustomEvent('sorted', {
|
325
|
-
detail: Array.from(this.querySelectorAll('[option]'))
|
326
|
-
})
|
327
|
-
)
|
328
|
-
},
|
329
|
-
onMove: e => {
|
330
|
-
// Check if the drag event target is a checkbox
|
331
|
-
if ((e.dragged as HTMLElement).querySelector('input[type="checkbox"]')) {
|
332
|
-
return false // Prevent sorting if it's a checkbox drag
|
333
|
-
}
|
334
|
-
this.locked = true
|
335
|
-
}
|
336
|
-
})
|
337
|
-
}
|
338
|
-
}
|
339
|
-
|
340
|
-
if (changes.has('searchKeyword')) {
|
341
|
-
const attrSelected = this.attrSelected || 'selected'
|
342
|
-
this.querySelectorAll(`[option]`).forEach(item => {
|
343
|
-
if (!this.searchKeyword || item.textContent?.match(new RegExp(this.searchKeyword, 'i'))) {
|
344
|
-
item.removeAttribute('hidden')
|
345
|
-
} else {
|
346
|
-
item.removeAttribute('selected')
|
347
|
-
item.setAttribute('hidden', '')
|
348
|
-
}
|
349
|
-
})
|
350
|
-
this.nothingToSelect = this.querySelectorAll(`[option]:not([hidden])`).length === 0
|
351
|
-
}
|
352
|
-
|
353
|
-
if (changes.has('value')) {
|
354
|
-
const options = Array.from(this.querySelectorAll(':scope > [option]'))
|
355
|
-
|
356
|
-
var values = this.value
|
357
|
-
if (!(values instanceof Array)) {
|
358
|
-
values = [values as string]
|
359
|
-
}
|
360
|
-
|
361
|
-
options.forEach(option => {
|
362
|
-
if (values?.includes((option as HTMLElement).getAttribute('value') || '')) {
|
363
|
-
option.setAttribute(this.attrSelected || 'selected', '')
|
364
|
-
} else {
|
365
|
-
option.removeAttribute(this.attrSelected || 'selected')
|
366
|
-
}
|
367
|
-
})
|
368
|
-
}
|
369
|
-
}
|
370
|
-
|
371
|
-
/**
|
372
|
-
* Retrieves the labels of the selected options in the popup list.
|
373
|
-
* If multiple selections are allowed, an array of labels is returned. Otherwise, a single label is returned.
|
374
|
-
* @returns {string|string[]} The label(s) of the selected option(s).
|
375
|
-
*/
|
376
|
-
public getSelectedLabels(): string | string[] {
|
377
|
-
const options = Array.from(this.querySelectorAll(':scope > [option]'))
|
378
|
-
|
379
|
-
const selected = options
|
380
|
-
.filter(option => option.hasAttribute('value') && option.hasAttribute(this.attrSelected || 'selected'))
|
381
|
-
.map(option => option.textContent || '')
|
382
|
-
|
383
|
-
return this.multiple ? selected : selected[0]
|
384
|
-
}
|
385
|
-
|
386
|
-
/**
|
387
|
-
* Handles the selection of options in the popup list and dispatches a 'select' event with the selected value(s).
|
388
|
-
* If multiple selections are allowed, an array of selected values is dispatched; otherwise, a single value is dispatched.
|
389
|
-
* Also, it checks whether the selected option should remain alive and whether the popup should be closed.
|
390
|
-
*/
|
391
|
-
async select() {
|
392
|
-
await this.updateComplete
|
393
|
-
|
394
|
-
const options = Array.from(this.querySelectorAll(':scope > [option]'))
|
395
|
-
|
396
|
-
const selected = options
|
397
|
-
.filter(option => option.hasAttribute('value') && option.hasAttribute(this.attrSelected || 'selected'))
|
398
|
-
.map(option => option.getAttribute('value'))
|
399
|
-
|
400
|
-
this.dispatchEvent(
|
401
|
-
new CustomEvent('select', {
|
402
|
-
bubbles: true,
|
403
|
-
composed: true,
|
404
|
-
detail: this.multiple ? selected : selected[0]
|
405
|
-
})
|
406
|
-
)
|
407
|
-
|
408
|
-
const option = options[this.activeIndex!]
|
409
|
-
if (!option.hasAttribute('alive-on-select') && !this.hasAttribute('multiple')) {
|
410
|
-
this.close()
|
411
|
-
}
|
412
|
-
}
|
413
|
-
|
414
|
-
/**
|
415
|
-
* Sets the active option within the popup list based on the given index or Element.
|
416
|
-
* If 'withSelect' is true, it also manages the selection state of the option.
|
417
|
-
*
|
418
|
-
* @param {number | Element | null} active - The index or Element of the option to set as active.
|
419
|
-
* @param {boolean | undefined} withSelect - Indicates whether to manage the selection state of the option.
|
420
|
-
*/
|
421
|
-
setActive(active: number | Element | null, withSelect?: boolean) {
|
422
|
-
var options = Array.from(this.querySelectorAll('[option]:not([hidden])'))
|
423
|
-
if (this.withSearch) {
|
424
|
-
options.push(this.renderRoot.querySelector('[search]')!)
|
425
|
-
}
|
426
|
-
|
427
|
-
if (active instanceof Element) {
|
428
|
-
const index = options.findIndex(option => option === active)
|
429
|
-
this.setActive(index === -1 ? 0 : index, withSelect)
|
430
|
-
return
|
431
|
-
}
|
432
|
-
|
433
|
-
const attrSelected = this.attrSelected || 'selected'
|
434
|
-
|
435
|
-
options.forEach(async (option, index) => {
|
436
|
-
if (typeof active === 'number' && index === (active + options.length) % options.length) {
|
437
|
-
option.setAttribute('active', '')
|
438
|
-
|
439
|
-
if (withSelect && !this.attrSelected) {
|
440
|
-
/* being set attribute attrs-selected means, that element should know how to do when event happened. */
|
441
|
-
this.multiple ? option.toggleAttribute('selected') : option.setAttribute('selected', '')
|
442
|
-
}
|
443
|
-
|
444
|
-
guaranteeFocus(option as HTMLElement)
|
445
|
-
|
446
|
-
this.activeIndex = index
|
447
|
-
} else {
|
448
|
-
option.removeAttribute('active')
|
449
|
-
/* even thought attribute attrs-selected set, ox-popup-list have to unset others. */
|
450
|
-
!this.multiple && withSelect && option.removeAttribute(attrSelected)
|
451
|
-
}
|
452
|
-
})
|
453
|
-
}
|
454
|
-
|
455
|
-
/**
|
456
|
-
* Overrides the 'open' method of the base class 'OxPopup' to set the initial active index
|
457
|
-
* when the popup list is opened. It ensures that an option is initially selected for user interaction.
|
458
|
-
*
|
459
|
-
* @param {object} params - The parameters for opening the popup, including position and size.
|
460
|
-
*/
|
461
|
-
override open(params: {
|
462
|
-
left?: number
|
463
|
-
top?: number
|
464
|
-
right?: number
|
465
|
-
bottom?: number
|
466
|
-
width?: string
|
467
|
-
height?: string
|
468
|
-
silent?: boolean
|
469
|
-
// fixed?: boolean
|
470
|
-
}) {
|
471
|
-
super.open(params)
|
472
|
-
|
473
|
-
if (this.activeIndex === undefined) {
|
474
|
-
const activeElement = this.querySelector(`[${this.attrSelected || 'selected'}]`)
|
475
|
-
this.setActive(activeElement || 0)
|
476
|
-
} else {
|
477
|
-
this.setActive(this.activeIndex)
|
478
|
-
}
|
479
|
-
}
|
480
|
-
|
481
|
-
/**
|
482
|
-
* Overrides the 'close' method of the base class 'OxPopup' to dispatch a custom event
|
483
|
-
* indicating that the popup list is being closed. This event can be used for further interactions
|
484
|
-
* or logic in the application.
|
485
|
-
*/
|
486
|
-
override close() {
|
487
|
-
if (this.locked) {
|
488
|
-
return
|
489
|
-
}
|
490
|
-
|
491
|
-
if (this.hasAttribute('active')) {
|
492
|
-
this.dispatchEvent(
|
493
|
-
new CustomEvent('close', {
|
494
|
-
bubbles: true,
|
495
|
-
composed: true
|
496
|
-
})
|
497
|
-
)
|
498
|
-
}
|
499
|
-
|
500
|
-
super.close()
|
501
|
-
}
|
502
|
-
|
503
|
-
/**
|
504
|
-
* Open OxPopup
|
505
|
-
*
|
506
|
-
* @param {PopupOpenOptions}
|
507
|
-
*/
|
508
|
-
static open({
|
509
|
-
template,
|
510
|
-
top,
|
511
|
-
left,
|
512
|
-
right,
|
513
|
-
bottom,
|
514
|
-
parent,
|
515
|
-
multiple,
|
516
|
-
sortable,
|
517
|
-
attrSelected,
|
518
|
-
styles,
|
519
|
-
debug
|
520
|
-
}: {
|
521
|
-
template: unknown
|
522
|
-
top?: number
|
523
|
-
left?: number
|
524
|
-
right?: number
|
525
|
-
bottom?: number
|
526
|
-
parent?: Element | null
|
527
|
-
multiple?: boolean
|
528
|
-
sortable?: boolean
|
529
|
-
debug?: boolean
|
530
|
-
attrSelected?: string
|
531
|
-
styles?: CSSResult
|
532
|
-
}): OxPopupList {
|
533
|
-
const target = document.createElement('ox-popup-list') as OxPopupList
|
534
|
-
|
535
|
-
if (styles) {
|
536
|
-
const style = document.createElement('style')
|
537
|
-
style.textContent = styles.cssText
|
538
|
-
|
539
|
-
const shadow = target.attachShadow({ mode: 'open' })
|
540
|
-
shadow.appendChild(style)
|
541
|
-
}
|
542
|
-
|
543
|
-
if (!!debug) {
|
544
|
-
target.setAttribute('debug', '')
|
545
|
-
}
|
546
|
-
|
547
|
-
if (!!multiple) {
|
548
|
-
target.setAttribute('multiple', '')
|
549
|
-
}
|
550
|
-
|
551
|
-
if (!!sortable) {
|
552
|
-
target.setAttribute('sortable', '')
|
553
|
-
}
|
554
|
-
|
555
|
-
if (attrSelected) {
|
556
|
-
target.setAttribute('attr-selected', attrSelected)
|
557
|
-
}
|
558
|
-
|
559
|
-
render(template, target)
|
560
|
-
|
561
|
-
if (parent) {
|
562
|
-
var { left, top, right, bottom } = convertToFixedPosition({
|
563
|
-
left,
|
564
|
-
top,
|
565
|
-
right,
|
566
|
-
bottom,
|
567
|
-
relativeElement: parent as HTMLElement
|
568
|
-
})
|
569
|
-
}
|
570
|
-
|
571
|
-
document.body.appendChild(target)
|
572
|
-
target.removeAfterUse = true
|
573
|
-
target.open({ top, left, right, bottom })
|
574
|
-
|
575
|
-
return target
|
576
|
-
}
|
577
|
-
}
|