@aquera/nile-elements 1.1.3-beta-1.4 → 1.1.3-beta-2.1
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/demo/index.html +124 -24
- package/dist/index.js +729 -770
- package/dist/nile-grid/nile-grid.cjs.js +1 -1
- package/dist/nile-grid/nile-grid.cjs.js.map +1 -1
- package/dist/nile-grid/nile-grid.css.cjs.js +1 -1
- package/dist/nile-grid/nile-grid.css.cjs.js.map +1 -1
- package/dist/nile-grid/nile-grid.css.esm.js +4 -8
- package/dist/nile-grid/nile-grid.esm.js +6 -6
- package/dist/nile-grid/nile-grid.utils.cjs.js +1 -1
- package/dist/nile-grid/nile-grid.utils.cjs.js.map +1 -1
- package/dist/nile-grid/nile-grid.utils.esm.js +1 -1
- package/dist/nile-grid-body/nile-grid-body.cjs.js +1 -1
- package/dist/nile-grid-body/nile-grid-body.cjs.js.map +1 -1
- package/dist/nile-grid-body/nile-grid-body.css.cjs.js +1 -1
- package/dist/nile-grid-body/nile-grid-body.css.cjs.js.map +1 -1
- package/dist/nile-grid-body/nile-grid-body.css.esm.js +4 -0
- package/dist/nile-grid-body/nile-grid-body.esm.js +3 -3
- package/dist/nile-grid-cell-item/nile-grid-cell-item.cjs.js +1 -1
- package/dist/nile-grid-cell-item/nile-grid-cell-item.cjs.js.map +1 -1
- package/dist/nile-grid-cell-item/nile-grid-cell-item.css.cjs.js +1 -1
- package/dist/nile-grid-cell-item/nile-grid-cell-item.css.cjs.js.map +1 -1
- package/dist/nile-grid-cell-item/nile-grid-cell-item.css.esm.js +3 -18
- package/dist/nile-grid-cell-item/nile-grid-cell-item.esm.js +3 -3
- package/dist/nile-grid-head/nile-grid-head.cjs.js +1 -1
- package/dist/nile-grid-head/nile-grid-head.cjs.js.map +1 -1
- package/dist/nile-grid-head/nile-grid-head.css.cjs.js +1 -1
- package/dist/nile-grid-head/nile-grid-head.css.cjs.js.map +1 -1
- package/dist/nile-grid-head/nile-grid-head.css.esm.js +1 -1
- package/dist/nile-grid-head/nile-grid-head.esm.js +3 -3
- package/dist/nile-grid-head-item/nile-grid-head-item.cjs.js +1 -1
- package/dist/nile-grid-head-item/nile-grid-head-item.cjs.js.map +1 -1
- package/dist/nile-grid-head-item/nile-grid-head-item.css.cjs.js +1 -1
- package/dist/nile-grid-head-item/nile-grid-head-item.css.cjs.js.map +1 -1
- package/dist/nile-grid-head-item/nile-grid-head-item.css.esm.js +5 -20
- package/dist/nile-grid-head-item/nile-grid-head-item.esm.js +3 -4
- package/dist/nile-grid-row/nile-grid-row.cjs.js +1 -1
- package/dist/nile-grid-row/nile-grid-row.cjs.js.map +1 -1
- package/dist/nile-grid-row/nile-grid-row.css.cjs.js +1 -1
- package/dist/nile-grid-row/nile-grid-row.css.cjs.js.map +1 -1
- package/dist/nile-grid-row/nile-grid-row.css.esm.js +5 -17
- package/dist/nile-grid-row/nile-grid-row.esm.js +5 -4
- package/dist/nile-select/nile-select.cjs.js +1 -1
- package/dist/nile-select/nile-select.cjs.js.map +1 -1
- package/dist/nile-select/nile-select.esm.js +2 -2
- package/dist/nile-select/virtual-scroll-helper.cjs.js +1 -1
- package/dist/nile-select/virtual-scroll-helper.cjs.js.map +1 -1
- package/dist/nile-select/virtual-scroll-helper.esm.js +1 -0
- package/dist/nile-virtual-select/nile-virtual-select.cjs.js +2 -2
- package/dist/nile-virtual-select/nile-virtual-select.cjs.js.map +1 -1
- package/dist/nile-virtual-select/nile-virtual-select.esm.js +7 -6
- package/dist/src/nile-grid/nile-grid.css.js +2 -6
- package/dist/src/nile-grid/nile-grid.css.js.map +1 -1
- package/dist/src/nile-grid/nile-grid.d.ts +3 -9
- package/dist/src/nile-grid/nile-grid.js +20 -96
- package/dist/src/nile-grid/nile-grid.js.map +1 -1
- package/dist/src/nile-grid/nile-grid.utils.d.ts +2 -3
- package/dist/src/nile-grid/nile-grid.utils.js +81 -223
- package/dist/src/nile-grid/nile-grid.utils.js.map +1 -1
- package/dist/src/nile-grid-body/nile-grid-body.css.js +4 -0
- package/dist/src/nile-grid-body/nile-grid-body.css.js.map +1 -1
- package/dist/src/nile-grid-body/nile-grid-body.js +1 -1
- package/dist/src/nile-grid-body/nile-grid-body.js.map +1 -1
- package/dist/src/nile-grid-cell-item/nile-grid-cell-item.css.js +2 -17
- package/dist/src/nile-grid-cell-item/nile-grid-cell-item.css.js.map +1 -1
- package/dist/src/nile-grid-cell-item/nile-grid-cell-item.d.ts +3 -0
- package/dist/src/nile-grid-cell-item/nile-grid-cell-item.js +11 -1
- package/dist/src/nile-grid-cell-item/nile-grid-cell-item.js.map +1 -1
- package/dist/src/nile-grid-head/nile-grid-head.css.js +1 -1
- package/dist/src/nile-grid-head/nile-grid-head.css.js.map +1 -1
- package/dist/src/nile-grid-head/nile-grid-head.js +1 -1
- package/dist/src/nile-grid-head/nile-grid-head.js.map +1 -1
- package/dist/src/nile-grid-head-item/nile-grid-head-item.css.js +3 -18
- package/dist/src/nile-grid-head-item/nile-grid-head-item.css.js.map +1 -1
- package/dist/src/nile-grid-head-item/nile-grid-head-item.d.ts +2 -3
- package/dist/src/nile-grid-head-item/nile-grid-head-item.js +11 -14
- package/dist/src/nile-grid-head-item/nile-grid-head-item.js.map +1 -1
- package/dist/src/nile-grid-row/nile-grid-row.css.js +5 -17
- package/dist/src/nile-grid-row/nile-grid-row.css.js.map +1 -1
- package/dist/src/nile-grid-row/nile-grid-row.d.ts +1 -4
- package/dist/src/nile-grid-row/nile-grid-row.js +4 -19
- package/dist/src/nile-grid-row/nile-grid-row.js.map +1 -1
- package/dist/src/nile-select/nile-select.d.ts +1 -0
- package/dist/src/nile-select/nile-select.js +4 -0
- package/dist/src/nile-select/nile-select.js.map +1 -1
- package/dist/src/nile-select/virtual-scroll-helper.js +1 -0
- package/dist/src/nile-select/virtual-scroll-helper.js.map +1 -1
- package/dist/src/nile-virtual-select/nile-virtual-select.d.ts +18 -0
- package/dist/src/nile-virtual-select/nile-virtual-select.js +230 -3
- package/dist/src/nile-virtual-select/nile-virtual-select.js.map +1 -1
- package/dist/src/version.js +1 -1
- package/dist/src/version.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/nile-grid/nile-grid.css.ts +2 -6
- package/src/nile-grid/nile-grid.ts +21 -124
- package/src/nile-grid/nile-grid.utils.ts +98 -353
- package/src/nile-grid-body/nile-grid-body.css.ts +4 -0
- package/src/nile-grid-body/nile-grid-body.ts +2 -2
- package/src/nile-grid-cell-item/nile-grid-cell-item.css.ts +2 -17
- package/src/nile-grid-cell-item/nile-grid-cell-item.ts +11 -3
- package/src/nile-grid-head/nile-grid-head.css.ts +1 -1
- package/src/nile-grid-head/nile-grid-head.ts +2 -2
- package/src/nile-grid-head-item/nile-grid-head-item.css.ts +3 -18
- package/src/nile-grid-head-item/nile-grid-head-item.ts +16 -8
- package/src/nile-grid-row/nile-grid-row.css.ts +5 -17
- package/src/nile-grid-row/nile-grid-row.ts +6 -9
- package/src/nile-select/nile-select.ts +2 -0
- package/src/nile-select/virtual-scroll-helper.ts +1 -0
- package/src/nile-virtual-select/nile-virtual-select.ts +257 -3
- package/vscode-html-custom-data.json +75 -38
- package/src/nile-grid/nile-grid.types.ts +0 -1
|
@@ -12,8 +12,7 @@ import { css } from 'lit';
|
|
|
12
12
|
*/
|
|
13
13
|
export const styles = css`
|
|
14
14
|
:host {
|
|
15
|
-
--padding: var(--nile-spacing-
|
|
16
|
-
--height: 50px;
|
|
15
|
+
--padding: var(--nile-spacing-xl) var(--nile-spacing-3xl);
|
|
17
16
|
position: relative;
|
|
18
17
|
box-sizing: border-box;
|
|
19
18
|
user-select: none;
|
|
@@ -24,16 +23,7 @@ export const styles = css`
|
|
|
24
23
|
padding: var(--padding);
|
|
25
24
|
background-color: var(--nile-colors-neutral-100);
|
|
26
25
|
border-bottom: 1px solid var(--nile-colors-neutral-400);
|
|
27
|
-
|
|
28
|
-
font-weight: 500;
|
|
29
|
-
font-family: var(--nile-font-weight-medium);
|
|
30
|
-
min-height: var(--height);
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
.head-item-base {
|
|
34
|
-
width: 100%;
|
|
35
|
-
overflow: hidden;
|
|
36
|
-
text-overflow: ellipsis;
|
|
26
|
+
border-right: 1px solid var(--nile-colors-neutral-400);
|
|
37
27
|
}
|
|
38
28
|
|
|
39
29
|
::slotted(*) {
|
|
@@ -42,17 +32,12 @@ export const styles = css`
|
|
|
42
32
|
white-space: nowrap;
|
|
43
33
|
}
|
|
44
34
|
|
|
45
|
-
:host(:last-child) .resize-handle {
|
|
46
|
-
border-right: none;
|
|
47
|
-
display: none;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
35
|
.resize-handle {
|
|
51
36
|
position: absolute;
|
|
52
37
|
top: 0;
|
|
53
38
|
right: 0;
|
|
54
39
|
height: 100%;
|
|
55
|
-
cursor:
|
|
40
|
+
cursor: col-resize;
|
|
56
41
|
touch-action: none;
|
|
57
42
|
z-index: 1;
|
|
58
43
|
width: 2px;
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import { html, CSSResultArray, TemplateResult } from 'lit';
|
|
8
|
+
import { LitElement, html, CSSResultArray, TemplateResult } from 'lit';
|
|
9
9
|
import { customElement, property } from 'lit/decorators.js';
|
|
10
10
|
import { styles } from './nile-grid-head-item.css';
|
|
11
11
|
import NileElement from '../internal/nile-element';
|
|
@@ -33,14 +33,18 @@ export class NileGridHeadItem extends NileElement {
|
|
|
33
33
|
|
|
34
34
|
@property({ type: Number, reflect: true, attribute: true }) colspan = 1;
|
|
35
35
|
@property({ type: Number, reflect: true, attribute: true }) rowspan = 1;
|
|
36
|
+
@property({ type: String, reflect: true, attribute: true }) scope:
|
|
37
|
+
| 'col'
|
|
38
|
+
| 'row' = 'col';
|
|
36
39
|
@property({ type: Boolean, reflect: true, attribute: true }) resizable = false;
|
|
37
|
-
@property({ type: Boolean, reflect: true, attribute: true })
|
|
38
|
-
@property({ type: Boolean, reflect: true, attribute: true }) lastColSticky = false;
|
|
39
|
-
@property({ type: Number, reflect: true, attribute: true }) customWidth: number | null = null;
|
|
40
|
+
@property({ type: Boolean, reflect: true, attribute: true }) sticky = false;
|
|
40
41
|
|
|
41
42
|
connectedCallback() {
|
|
42
43
|
super.connectedCallback();
|
|
43
|
-
this.setAttribute(
|
|
44
|
+
this.setAttribute(
|
|
45
|
+
'role',
|
|
46
|
+
this.scope === 'row' ? 'rowheader' : 'columnheader'
|
|
47
|
+
);
|
|
44
48
|
}
|
|
45
49
|
|
|
46
50
|
private onHandlePointerDown = (ev: PointerEvent) => {
|
|
@@ -65,7 +69,12 @@ export class NileGridHeadItem extends NileElement {
|
|
|
65
69
|
};
|
|
66
70
|
|
|
67
71
|
protected updated(changed: Map<string, unknown>) {
|
|
68
|
-
|
|
72
|
+
if (changed.has('scope')) {
|
|
73
|
+
this.setAttribute(
|
|
74
|
+
'role',
|
|
75
|
+
this.scope === 'row' ? 'rowheader' : 'columnheader'
|
|
76
|
+
);
|
|
77
|
+
}
|
|
69
78
|
}
|
|
70
79
|
|
|
71
80
|
disconnectedCallback() {
|
|
@@ -75,14 +84,13 @@ export class NileGridHeadItem extends NileElement {
|
|
|
75
84
|
|
|
76
85
|
public render(): TemplateResult {
|
|
77
86
|
return html`
|
|
78
|
-
<div
|
|
87
|
+
<div style="display: contents;">
|
|
79
88
|
<slot></slot>
|
|
80
89
|
${this.resizable
|
|
81
90
|
? html`
|
|
82
91
|
<div
|
|
83
92
|
aria-hidden="false"
|
|
84
93
|
class="resize-handle"
|
|
85
|
-
part="resize-handle"
|
|
86
94
|
@pointerdown=${this.onHandlePointerDown}
|
|
87
95
|
></div>
|
|
88
96
|
`
|
|
@@ -12,30 +12,18 @@ import { css } from 'lit';
|
|
|
12
12
|
*/
|
|
13
13
|
export const styles = css`
|
|
14
14
|
:host {
|
|
15
|
-
display:
|
|
16
|
-
grid-template-columns: var(--nile-grid-columns);
|
|
17
|
-
position: relative;
|
|
15
|
+
display: contents;
|
|
18
16
|
}
|
|
19
17
|
|
|
20
|
-
|
|
18
|
+
::slotted(nile-grid-header) {
|
|
21
19
|
background-color: var(--nile-colors-neutral-100);
|
|
22
20
|
}
|
|
23
21
|
|
|
24
|
-
.row-
|
|
25
|
-
|
|
26
|
-
pointer-events: none;
|
|
22
|
+
.row-layer {
|
|
23
|
+
background-color: var(--row-bg, transparent);
|
|
27
24
|
z-index: 0;
|
|
28
|
-
|
|
25
|
+
pointer-events: auto;
|
|
29
26
|
}
|
|
30
|
-
|
|
31
|
-
.row-slot {
|
|
32
|
-
grid-column: 1 / -1;
|
|
33
|
-
display: contents;
|
|
34
|
-
z-index: 1;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
:host([selected]) .row-bg { background: var(--row-selected-bg, rgba(0,0,0,.08)); }
|
|
38
|
-
:host([error]) .row-bg { background: var(--row-error-bg, #fff4f4); }
|
|
39
27
|
`;
|
|
40
28
|
|
|
41
29
|
export default [styles];
|
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import { html, CSSResultArray, TemplateResult
|
|
9
|
-
import { customElement
|
|
8
|
+
import { LitElement, html, CSSResultArray, TemplateResult } from 'lit';
|
|
9
|
+
import { customElement } from 'lit/decorators.js';
|
|
10
10
|
import { styles } from './nile-grid-row.css';
|
|
11
11
|
import NileElement from '../internal/nile-element';
|
|
12
12
|
|
|
@@ -26,21 +26,18 @@ export class NileGridRow extends NileElement {
|
|
|
26
26
|
return [styles];
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
@property({ type: Boolean, reflect: true, attribute: true }) disabled: boolean = false;
|
|
30
|
-
@property({ type: Boolean, reflect: true, attribute: true }) hover: boolean = false;
|
|
31
|
-
@property({ type: Boolean, reflect: true, attribute: true }) selected: boolean = false;
|
|
32
|
-
|
|
33
29
|
connectedCallback() {
|
|
34
30
|
super.connectedCallback();
|
|
35
31
|
this.setAttribute('role', 'row');
|
|
36
32
|
}
|
|
37
33
|
|
|
38
|
-
|
|
34
|
+
public render(): TemplateResult {
|
|
39
35
|
return html`
|
|
40
|
-
<div part="row-
|
|
36
|
+
<div part="row-layer" class="row-layer" data-row-bg></div>
|
|
37
|
+
|
|
38
|
+
<div style="display: contents;">
|
|
41
39
|
<slot></slot>
|
|
42
40
|
</div>
|
|
43
|
-
<div part="row-bg" class="row-bg"></div>
|
|
44
41
|
`;
|
|
45
42
|
}
|
|
46
43
|
|
|
@@ -174,6 +174,8 @@ export class NileSelect extends NileElement implements NileFormControl{
|
|
|
174
174
|
|
|
175
175
|
@property({ type: Boolean, reflect: true }) noWidthSync = false;
|
|
176
176
|
|
|
177
|
+
@property({ type: Boolean, reflect: true }) bodyAppend = false;
|
|
178
|
+
|
|
177
179
|
/** Allows more than one option to be selected. */
|
|
178
180
|
@property({
|
|
179
181
|
reflect: true,
|
|
@@ -247,6 +247,12 @@ export class NileVirtualSelect extends NileElement implements NileFormControl {
|
|
|
247
247
|
/** Disable width synchronization */
|
|
248
248
|
@property({ type: Boolean, reflect: true }) noWidthSync = false;
|
|
249
249
|
|
|
250
|
+
/**
|
|
251
|
+
* When true, the listbox will be appended to the document body instead of the parent container.
|
|
252
|
+
* This is useful when the parent has overflow: hidden, clip-path, or transform applied.
|
|
253
|
+
*/
|
|
254
|
+
@property({ type: Boolean, reflect: true }) bodyAppend = false;
|
|
255
|
+
|
|
250
256
|
/**
|
|
251
257
|
* The maximum number of selected options to show when `multiple` is true. After the maximum, "+n" will be shown to
|
|
252
258
|
* indicate the number of additional items that are selected. Set to 0 to remove the limit.
|
|
@@ -256,6 +262,10 @@ export class NileVirtualSelect extends NileElement implements NileFormControl {
|
|
|
256
262
|
|
|
257
263
|
@state() oldMaxOptionsVisible: number = 1;
|
|
258
264
|
@state() showListbox: boolean = false;
|
|
265
|
+
|
|
266
|
+
// Body append-related state
|
|
267
|
+
@state() private bodyAppendContainer: HTMLElement | null = null;
|
|
268
|
+
@state() private bodyAppendListbox: HTMLElement | null = null;
|
|
259
269
|
|
|
260
270
|
/** Gets the validity state object */
|
|
261
271
|
get validity() {
|
|
@@ -286,6 +296,8 @@ export class NileVirtualSelect extends NileElement implements NileFormControl {
|
|
|
286
296
|
clearTimeout(this.scrollTimeout);
|
|
287
297
|
this.scrollTimeout = undefined;
|
|
288
298
|
}
|
|
299
|
+
// Clean up body append elements
|
|
300
|
+
this.cleanupBodyAppend();
|
|
289
301
|
}
|
|
290
302
|
|
|
291
303
|
protected updated(changedProperties: PropertyValues): void {
|
|
@@ -343,6 +355,8 @@ export class NileVirtualSelect extends NileElement implements NileFormControl {
|
|
|
343
355
|
this.handleDocumentKeyDown = this.handleDocumentKeyDown.bind(this);
|
|
344
356
|
this.handleDocumentMouseDown = this.handleDocumentMouseDown.bind(this);
|
|
345
357
|
this.handleWindowError = this.handleWindowError.bind(this);
|
|
358
|
+
this.handleWindowResize = this.handleWindowResize.bind(this);
|
|
359
|
+
this.handleWindowScroll = this.handleWindowScroll.bind(this);
|
|
346
360
|
}
|
|
347
361
|
|
|
348
362
|
private addOpenListeners(): void {
|
|
@@ -350,6 +364,11 @@ export class NileVirtualSelect extends NileElement implements NileFormControl {
|
|
|
350
364
|
document.addEventListener('keydown', this.handleDocumentKeyDown);
|
|
351
365
|
document.addEventListener('mousedown', this.handleDocumentMouseDown);
|
|
352
366
|
window.addEventListener('error', this.handleWindowError);
|
|
367
|
+
|
|
368
|
+
if (this.bodyAppend) {
|
|
369
|
+
window.addEventListener('resize', this.handleWindowResize);
|
|
370
|
+
window.addEventListener('scroll', this.handleWindowScroll, true);
|
|
371
|
+
}
|
|
353
372
|
}
|
|
354
373
|
|
|
355
374
|
private removeOpenListeners(): void {
|
|
@@ -357,6 +376,8 @@ export class NileVirtualSelect extends NileElement implements NileFormControl {
|
|
|
357
376
|
document.removeEventListener('keydown', this.handleDocumentKeyDown);
|
|
358
377
|
document.removeEventListener('mousedown', this.handleDocumentMouseDown);
|
|
359
378
|
window.removeEventListener('error', this.handleWindowError);
|
|
379
|
+
window.removeEventListener('resize', this.handleWindowResize);
|
|
380
|
+
window.removeEventListener('scroll', this.handleWindowScroll, true);
|
|
360
381
|
}
|
|
361
382
|
|
|
362
383
|
private handleFocus(): void {
|
|
@@ -374,8 +395,9 @@ export class NileVirtualSelect extends NileElement implements NileFormControl {
|
|
|
374
395
|
const path = event.composedPath();
|
|
375
396
|
const hitSelf = path.includes(this);
|
|
376
397
|
const hitPopup = this.popup && path.includes(this.popup);
|
|
398
|
+
const hitBodyAppend = this.bodyAppend && this.bodyAppendContainer && path.includes(this.bodyAppendContainer);
|
|
377
399
|
|
|
378
|
-
if (!hitSelf && !hitPopup) {
|
|
400
|
+
if (!hitSelf && !hitPopup && !hitBodyAppend) {
|
|
379
401
|
this.hide();
|
|
380
402
|
}
|
|
381
403
|
}
|
|
@@ -437,8 +459,9 @@ export class NileVirtualSelect extends NileElement implements NileFormControl {
|
|
|
437
459
|
const path = event.composedPath();
|
|
438
460
|
const hitSelf = path.includes(this);
|
|
439
461
|
const hitPopup = this.popup && path.includes(this.popup);
|
|
462
|
+
const hitBodyAppend = this.bodyAppend && this.bodyAppendContainer && path.includes(this.bodyAppendContainer);
|
|
440
463
|
|
|
441
|
-
if (!hitSelf && !hitPopup) {
|
|
464
|
+
if (!hitSelf && !hitPopup && !hitBodyAppend) {
|
|
442
465
|
this.hide();
|
|
443
466
|
}
|
|
444
467
|
};
|
|
@@ -456,6 +479,14 @@ export class NileVirtualSelect extends NileElement implements NileFormControl {
|
|
|
456
479
|
}
|
|
457
480
|
};
|
|
458
481
|
|
|
482
|
+
private handleWindowResize = (): void => {
|
|
483
|
+
this.updateBodyAppendPosition();
|
|
484
|
+
};
|
|
485
|
+
|
|
486
|
+
private handleWindowScroll = (): void => {
|
|
487
|
+
this.updateBodyAppendPosition();
|
|
488
|
+
};
|
|
489
|
+
|
|
459
490
|
private handleFooterClick(event: MouseEvent): void {
|
|
460
491
|
event.stopPropagation();
|
|
461
492
|
event.preventDefault();
|
|
@@ -807,6 +838,11 @@ export class NileVirtualSelect extends NileElement implements NileFormControl {
|
|
|
807
838
|
this.showNoResults = false;
|
|
808
839
|
}
|
|
809
840
|
this.requestUpdate();
|
|
841
|
+
|
|
842
|
+
// Update body append content if it's active
|
|
843
|
+
if (this.bodyAppend && this.bodyAppendContainer) {
|
|
844
|
+
this.updateBodyAppendContent();
|
|
845
|
+
}
|
|
810
846
|
}
|
|
811
847
|
|
|
812
848
|
@watch('renderItemConfig', { waitUntilFirstUpdate: true })
|
|
@@ -824,6 +860,22 @@ export class NileVirtualSelect extends NileElement implements NileFormControl {
|
|
|
824
860
|
this.showNoResults = true;
|
|
825
861
|
}
|
|
826
862
|
this.requestUpdate();
|
|
863
|
+
|
|
864
|
+
// Update body append content if it's active
|
|
865
|
+
if (this.bodyAppend && this.bodyAppendContainer) {
|
|
866
|
+
this.updateBodyAppendContent();
|
|
867
|
+
}
|
|
868
|
+
}
|
|
869
|
+
|
|
870
|
+
@watch('bodyAppend', { waitUntilFirstUpdate: true })
|
|
871
|
+
handleBodyAppendChange(): void {
|
|
872
|
+
if (this.open) {
|
|
873
|
+
if (this.bodyAppend) {
|
|
874
|
+
this.setupBodyAppend();
|
|
875
|
+
} else {
|
|
876
|
+
this.cleanupBodyAppend();
|
|
877
|
+
}
|
|
878
|
+
}
|
|
827
879
|
}
|
|
828
880
|
|
|
829
881
|
@watch('open', { waitUntilFirstUpdate: true })
|
|
@@ -831,9 +883,17 @@ export class NileVirtualSelect extends NileElement implements NileFormControl {
|
|
|
831
883
|
if (this.open && !this.disabled) {
|
|
832
884
|
await this.handleOpen();
|
|
833
885
|
this.showListbox = true;
|
|
886
|
+
|
|
887
|
+
if (this.bodyAppend) {
|
|
888
|
+
this.setupBodyAppend();
|
|
889
|
+
}
|
|
834
890
|
} else {
|
|
835
891
|
await this.handleClose();
|
|
836
892
|
this.showListbox = false;
|
|
893
|
+
|
|
894
|
+
if (this.bodyAppend) {
|
|
895
|
+
this.cleanupBodyAppend();
|
|
896
|
+
}
|
|
837
897
|
}
|
|
838
898
|
}
|
|
839
899
|
|
|
@@ -1219,9 +1279,10 @@ export class NileVirtualSelect extends NileElement implements NileFormControl {
|
|
|
1219
1279
|
part="listbox"
|
|
1220
1280
|
class="select__listbox ${this.searchEnabled
|
|
1221
1281
|
? 'select__search-enabled '
|
|
1222
|
-
: ''}"
|
|
1282
|
+
: ''} ${this.bodyAppend ? 'select__body-append-hidden' : ''}"
|
|
1223
1283
|
tabindex="-1"
|
|
1224
1284
|
@mouseup=${this.handleOptionClick}
|
|
1285
|
+
style=${this.bodyAppend ? 'display: none;' : ''}
|
|
1225
1286
|
>
|
|
1226
1287
|
${this.renderSearch()}
|
|
1227
1288
|
${this.renderLoader()}
|
|
@@ -1425,6 +1486,199 @@ export class NileVirtualSelect extends NileElement implements NileFormControl {
|
|
|
1425
1486
|
}
|
|
1426
1487
|
});
|
|
1427
1488
|
}
|
|
1489
|
+
|
|
1490
|
+
private createBodyAppendContainer(): HTMLElement {
|
|
1491
|
+
const container = document.createElement('div');
|
|
1492
|
+
container.style.position = 'absolute';
|
|
1493
|
+
container.style.zIndex = '9999';
|
|
1494
|
+
container.style.pointerEvents = 'none';
|
|
1495
|
+
container.className = 'nile-virtual-select-body-append';
|
|
1496
|
+
|
|
1497
|
+
// Apply additional styling to match the original popup
|
|
1498
|
+
container.style.background = 'white';
|
|
1499
|
+
container.style.border = '1px solid #e0e0e0';
|
|
1500
|
+
container.style.borderRadius = '4px';
|
|
1501
|
+
container.style.boxShadow = '0 4px 6px rgba(0, 0, 0, 0.1)';
|
|
1502
|
+
container.style.maxHeight = '300px';
|
|
1503
|
+
container.style.overflow = 'hidden';
|
|
1504
|
+
|
|
1505
|
+
return container;
|
|
1506
|
+
}
|
|
1507
|
+
|
|
1508
|
+
private createBodyAppendListbox(): HTMLElement {
|
|
1509
|
+
const listbox = document.createElement('div');
|
|
1510
|
+
listbox.id = 'listbox';
|
|
1511
|
+
listbox.setAttribute('role', 'listbox');
|
|
1512
|
+
listbox.setAttribute('aria-expanded', this.open ? 'true' : 'false');
|
|
1513
|
+
listbox.setAttribute('aria-multiselectable', this.multiple ? 'true' : 'false');
|
|
1514
|
+
listbox.setAttribute('aria-labelledby', 'label');
|
|
1515
|
+
listbox.setAttribute('part', 'listbox');
|
|
1516
|
+
listbox.className = `select__listbox ${this.searchEnabled ? 'select__search-enabled ' : ''}`;
|
|
1517
|
+
listbox.setAttribute('tabindex', '-1');
|
|
1518
|
+
|
|
1519
|
+
// Apply styling to match the original listbox
|
|
1520
|
+
listbox.style.background = 'white';
|
|
1521
|
+
listbox.style.border = 'none';
|
|
1522
|
+
listbox.style.borderRadius = '4px';
|
|
1523
|
+
listbox.style.maxHeight = '300px';
|
|
1524
|
+
listbox.style.overflowY = 'auto';
|
|
1525
|
+
|
|
1526
|
+
listbox.addEventListener('mouseup', this.handleOptionClick.bind(this));
|
|
1527
|
+
return listbox;
|
|
1528
|
+
}
|
|
1529
|
+
|
|
1530
|
+
private positionBodyAppend(): void {
|
|
1531
|
+
if (!this.bodyAppendContainer || !this.popup) return;
|
|
1532
|
+
|
|
1533
|
+
const rect = this.getBoundingClientRect();
|
|
1534
|
+
|
|
1535
|
+
// Position the body append container to match the popup position
|
|
1536
|
+
this.bodyAppendContainer.style.left = `${rect.left}px`;
|
|
1537
|
+
this.bodyAppendContainer.style.top = `${rect.bottom + 6}px`; // 6px is the distance from the popup
|
|
1538
|
+
this.bodyAppendContainer.style.width = `${rect.width}px`;
|
|
1539
|
+
this.bodyAppendContainer.style.pointerEvents = 'auto';
|
|
1540
|
+
}
|
|
1541
|
+
|
|
1542
|
+
private updateBodyAppendPosition(): void {
|
|
1543
|
+
if (this.bodyAppend && this.bodyAppendContainer) {
|
|
1544
|
+
this.positionBodyAppend();
|
|
1545
|
+
}
|
|
1546
|
+
}
|
|
1547
|
+
|
|
1548
|
+
private async updateBodyAppendContent(): Promise<void> {
|
|
1549
|
+
if (!this.bodyAppendListbox) return;
|
|
1550
|
+
|
|
1551
|
+
// Clear the body append listbox
|
|
1552
|
+
this.bodyAppendListbox.innerHTML = '';
|
|
1553
|
+
|
|
1554
|
+
// Create a new listbox element
|
|
1555
|
+
const listbox = document.createElement('div');
|
|
1556
|
+
listbox.id = 'listbox';
|
|
1557
|
+
listbox.setAttribute('role', 'listbox');
|
|
1558
|
+
listbox.setAttribute('aria-expanded', this.open ? 'true' : 'false');
|
|
1559
|
+
listbox.setAttribute('aria-multiselectable', this.multiple ? 'true' : 'false');
|
|
1560
|
+
listbox.setAttribute('aria-labelledby', 'label');
|
|
1561
|
+
listbox.setAttribute('part', 'listbox');
|
|
1562
|
+
listbox.className = `select__listbox ${this.searchEnabled ? 'select__search-enabled ' : ''}`;
|
|
1563
|
+
listbox.setAttribute('tabindex', '-1');
|
|
1564
|
+
|
|
1565
|
+
// Render the content using Lit's render function
|
|
1566
|
+
const { render } = await import('lit');
|
|
1567
|
+
|
|
1568
|
+
// Render search
|
|
1569
|
+
if (this.searchEnabled) {
|
|
1570
|
+
const searchContent = this.renderSearch();
|
|
1571
|
+
const searchDiv = document.createElement('div');
|
|
1572
|
+
render(searchContent, searchDiv);
|
|
1573
|
+
listbox.appendChild(searchDiv.firstElementChild as HTMLElement);
|
|
1574
|
+
}
|
|
1575
|
+
|
|
1576
|
+
// Render loader
|
|
1577
|
+
const loaderContent = this.renderLoader();
|
|
1578
|
+
const loaderDiv = document.createElement('div');
|
|
1579
|
+
render(loaderContent, loaderDiv);
|
|
1580
|
+
if (loaderDiv.firstElementChild) {
|
|
1581
|
+
listbox.appendChild(loaderDiv.firstElementChild as HTMLElement);
|
|
1582
|
+
}
|
|
1583
|
+
|
|
1584
|
+
// Render virtualized content
|
|
1585
|
+
const virtualizedContent = this.getVirtualizedContent();
|
|
1586
|
+
const virtualizedDiv = document.createElement('div');
|
|
1587
|
+
render(virtualizedContent, virtualizedDiv);
|
|
1588
|
+
if (virtualizedDiv.firstElementChild) {
|
|
1589
|
+
listbox.appendChild(virtualizedDiv.firstElementChild as HTMLElement);
|
|
1590
|
+
}
|
|
1591
|
+
|
|
1592
|
+
// Render footer
|
|
1593
|
+
if (this.multiple) {
|
|
1594
|
+
const footerContent = this.renderFooter();
|
|
1595
|
+
const footerDiv = document.createElement('div');
|
|
1596
|
+
render(footerContent, footerDiv);
|
|
1597
|
+
if (footerDiv.firstElementChild) {
|
|
1598
|
+
listbox.appendChild(footerDiv.firstElementChild as HTMLElement);
|
|
1599
|
+
}
|
|
1600
|
+
}
|
|
1601
|
+
|
|
1602
|
+
// Append the listbox to the body append container
|
|
1603
|
+
this.bodyAppendListbox.appendChild(listbox);
|
|
1604
|
+
|
|
1605
|
+
// Re-attach event listeners
|
|
1606
|
+
this.attachBodyAppendEventListeners();
|
|
1607
|
+
}
|
|
1608
|
+
|
|
1609
|
+
private attachBodyAppendEventListeners(): void {
|
|
1610
|
+
if (!this.bodyAppendListbox) return;
|
|
1611
|
+
|
|
1612
|
+
// Find the cloned listbox within the body append container
|
|
1613
|
+
const clonedListbox = this.bodyAppendListbox.querySelector('.select__listbox') as HTMLElement;
|
|
1614
|
+
if (!clonedListbox) return;
|
|
1615
|
+
|
|
1616
|
+
// Re-attach the option click handler - use event delegation for better performance
|
|
1617
|
+
clonedListbox.addEventListener('mouseup', this.handleOptionClick.bind(this));
|
|
1618
|
+
|
|
1619
|
+
// Also add click handler for nile-option elements specifically
|
|
1620
|
+
clonedListbox.addEventListener('click', (event) => {
|
|
1621
|
+
const target = event.target as HTMLElement;
|
|
1622
|
+
const option = target.closest('nile-option');
|
|
1623
|
+
if (option) {
|
|
1624
|
+
event.preventDefault();
|
|
1625
|
+
event.stopPropagation();
|
|
1626
|
+
this.handleOptionClick(event);
|
|
1627
|
+
}
|
|
1628
|
+
});
|
|
1629
|
+
|
|
1630
|
+
// Re-attach search handlers if search is enabled
|
|
1631
|
+
const searchInput = clonedListbox.querySelector('nile-input');
|
|
1632
|
+
if (searchInput) {
|
|
1633
|
+
searchInput.addEventListener('nile-input', this.handleSearchChange.bind(this));
|
|
1634
|
+
searchInput.addEventListener('nile-focus', this.handleSearchFocus.bind(this));
|
|
1635
|
+
searchInput.addEventListener('nile-change', this.onInputChange.bind(this));
|
|
1636
|
+
}
|
|
1637
|
+
|
|
1638
|
+
// Re-attach scroll handler
|
|
1639
|
+
const virtualizedContainer = clonedListbox.querySelector('.virtualized') as HTMLElement;
|
|
1640
|
+
if (virtualizedContainer) {
|
|
1641
|
+
virtualizedContainer.addEventListener('scroll', this.handleScroll.bind(this));
|
|
1642
|
+
}
|
|
1643
|
+
|
|
1644
|
+
// Re-attach footer handlers if multiple
|
|
1645
|
+
if (this.multiple) {
|
|
1646
|
+
const showSelectedSpan = clonedListbox.querySelector('.select__footer span[style*="cursor: pointer"]');
|
|
1647
|
+
if (showSelectedSpan) {
|
|
1648
|
+
showSelectedSpan.addEventListener('click', this.toggleShowSelected.bind(this));
|
|
1649
|
+
}
|
|
1650
|
+
|
|
1651
|
+
const clearSpan = clonedListbox.querySelector('.select__clear');
|
|
1652
|
+
if (clearSpan) {
|
|
1653
|
+
clearSpan.addEventListener('click', this.unSelectAll.bind(this));
|
|
1654
|
+
}
|
|
1655
|
+
}
|
|
1656
|
+
}
|
|
1657
|
+
|
|
1658
|
+
private setupBodyAppend(): void {
|
|
1659
|
+
if (!this.bodyAppend) return;
|
|
1660
|
+
|
|
1661
|
+
this.bodyAppendContainer = this.createBodyAppendContainer();
|
|
1662
|
+
this.bodyAppendListbox = this.createBodyAppendListbox();
|
|
1663
|
+
|
|
1664
|
+
this.bodyAppendContainer.appendChild(this.bodyAppendListbox);
|
|
1665
|
+
document.body.appendChild(this.bodyAppendContainer);
|
|
1666
|
+
|
|
1667
|
+
this.positionBodyAppend();
|
|
1668
|
+
|
|
1669
|
+
// Wait for the next tick to ensure the original listbox is rendered
|
|
1670
|
+
this.updateComplete.then(async () => {
|
|
1671
|
+
await this.updateBodyAppendContent();
|
|
1672
|
+
});
|
|
1673
|
+
}
|
|
1674
|
+
|
|
1675
|
+
private cleanupBodyAppend(): void {
|
|
1676
|
+
if (this.bodyAppendContainer && this.bodyAppendContainer.parentNode) {
|
|
1677
|
+
this.bodyAppendContainer.parentNode.removeChild(this.bodyAppendContainer);
|
|
1678
|
+
}
|
|
1679
|
+
this.bodyAppendContainer = null;
|
|
1680
|
+
this.bodyAppendListbox = null;
|
|
1681
|
+
}
|
|
1428
1682
|
}
|
|
1429
1683
|
|
|
1430
1684
|
setDefaultAnimation('select.show', {
|