@dile/ui 3.18.5 → 3.19.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/components/floating-menu/src/DileFloatingMenu.js +1 -6
- package/components/input/src/DileInput.js +10 -0
- package/components/input/src/DileInputContact.js +2 -0
- package/components/input/src/DileInputIcon.js +2 -0
- package/components/list/index.js +2 -0
- package/components/list/list-item.js +5 -0
- package/components/list/list.js +6 -0
- package/components/list/src/DileList.js +606 -0
- package/components/list/src/DileListItem.js +499 -0
- package/components/select/src/DileSelect.js +37 -8
- package/components/select/src/DileSelectOverlay.js +41 -7
- package/components/select/src/DileSelectSearch.js +3 -1
- package/components/select/src/DileSelectSearchableBase.js +44 -0
- package/mixins/close-document-click/src/DileCloseDocumentClick.js +10 -1
- package/mixins/overlay/src/DileOverlay.js +38 -10
- package/package.json +2 -2
|
@@ -65,6 +65,8 @@ export class DileSelectSearch extends DileSelectSearchableBase {
|
|
|
65
65
|
value: option.value,
|
|
66
66
|
text: option.textContent.trim(),
|
|
67
67
|
icon: option.dataset.icon || select.dataset.icon,
|
|
68
|
+
// The native <option>, so an optionRenderer can read its dataset.
|
|
69
|
+
element: option,
|
|
68
70
|
}));
|
|
69
71
|
}
|
|
70
72
|
|
|
@@ -91,7 +93,7 @@ export class DileSelectSearch extends DileSelectSearchableBase {
|
|
|
91
93
|
* Template method: decide whether an option matches the keyword.
|
|
92
94
|
* By default it searches the keyword anywhere in the option text, ignoring case and accents.
|
|
93
95
|
* Override it in a subclass to customize the search (e.g. also match option.value).
|
|
94
|
-
* @param {{value: string, text: string, icon: string}} option
|
|
96
|
+
* @param {{value: string, text: string, icon: string, element: HTMLOptionElement}} option
|
|
95
97
|
* @param {string} keyword
|
|
96
98
|
* @returns {boolean}
|
|
97
99
|
*/
|
|
@@ -11,6 +11,8 @@ import { labelStyles } from '../../input/src/label-styles.js';
|
|
|
11
11
|
import { messageStyles } from '../../input/src/message-styles.js';
|
|
12
12
|
|
|
13
13
|
const NAVIGATION_KEYS = ['ArrowDown', 'ArrowUp', 'Home', 'End', 'Enter', 'Escape', 'Tab'];
|
|
14
|
+
// Parts of the nested dile-select-overlay re-exported to this component's host.
|
|
15
|
+
const OPTION_PARTS = ['option', 'option-highlighted', 'option-selected', 'option-content'];
|
|
14
16
|
|
|
15
17
|
/**
|
|
16
18
|
* Base class for the searchable members of the select family (dile-select-ajax-overlay,
|
|
@@ -158,6 +160,13 @@ export class DileSelectSearchableBase extends DileEmmitChange(LitElement) {
|
|
|
158
160
|
/** dile-iconlib "family.name" icon string applied to every option that has no icon of its
|
|
159
161
|
* own via iconProperty. */
|
|
160
162
|
icon: { type: String },
|
|
163
|
+
/** Optional custom renderer for the content of each result: `(item, index) => TemplateResult | string`,
|
|
164
|
+
* receiving the original data object. The displayProperty text is still used for the accessible
|
|
165
|
+
* name, the keyboard announcements and the selected text. */
|
|
166
|
+
optionRenderer: { attribute: false },
|
|
167
|
+
/** Space or comma separated extra part names used inside optionRenderer templates, re-exported
|
|
168
|
+
* from the nested dile-select-overlay so they can be styled with ::part() from outside. */
|
|
169
|
+
optionParts: { type: String },
|
|
161
170
|
delay: { type: Number },
|
|
162
171
|
keyword: {
|
|
163
172
|
type: String,
|
|
@@ -382,6 +391,8 @@ export class DileSelectSearchableBase extends DileEmmitChange(LitElement) {
|
|
|
382
391
|
name="generated-select-field"
|
|
383
392
|
placeholder="${this.placeholder}"
|
|
384
393
|
?disabled=${this.disabled}
|
|
394
|
+
exportparts="${this.exportedOptionParts}"
|
|
395
|
+
.optionRenderer=${this.nestedOptionRenderer}
|
|
385
396
|
@element-changed=${this.doSelected}
|
|
386
397
|
>
|
|
387
398
|
<select slot="select" data-icon="${ifDefined(this.icon)}">
|
|
@@ -393,6 +404,39 @@ export class DileSelectSearchableBase extends DileEmmitChange(LitElement) {
|
|
|
393
404
|
`;
|
|
394
405
|
}
|
|
395
406
|
|
|
407
|
+
/** exportparts value for the nested dile-select-overlay: built-in option parts plus optionParts. */
|
|
408
|
+
get exportedOptionParts() {
|
|
409
|
+
const extra = (this.optionParts || '').split(/[\s,]+/).filter(Boolean);
|
|
410
|
+
return [...new Set([...OPTION_PARTS, ...extra])].join(', ');
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
/** Adapts optionRenderer (which receives data items) to the nested overlay's (option, index) signature.
|
|
414
|
+
* Cached per optionRenderer so the nested component doesn't see a new function on every render. */
|
|
415
|
+
get nestedOptionRenderer() {
|
|
416
|
+
if (typeof this.optionRenderer !== 'function') {
|
|
417
|
+
return undefined;
|
|
418
|
+
}
|
|
419
|
+
if (this._nestedRendererFor !== this.optionRenderer) {
|
|
420
|
+
const renderer = this.optionRenderer;
|
|
421
|
+
this._nestedRendererFor = renderer;
|
|
422
|
+
this._nestedRenderer = (option, index) => {
|
|
423
|
+
const item = this.findItemForOption(option, index);
|
|
424
|
+
return item === undefined ? option.text : renderer(item, index);
|
|
425
|
+
};
|
|
426
|
+
}
|
|
427
|
+
return this._nestedRenderer;
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
/** Data item behind an option of the nested overlay: by index (options are generated from
|
|
431
|
+
* `data` in order), checked against idProperty, falling back to a search by idProperty. */
|
|
432
|
+
findItemForOption(option, index) {
|
|
433
|
+
const byIndex = this.data[index];
|
|
434
|
+
if (byIndex && String(byIndex[this.idProperty]) === option.value) {
|
|
435
|
+
return byIndex;
|
|
436
|
+
}
|
|
437
|
+
return this.data.find(item => String(item[this.idProperty]) === option.value);
|
|
438
|
+
}
|
|
439
|
+
|
|
396
440
|
get messageTemplate() {
|
|
397
441
|
return html`
|
|
398
442
|
${this.message
|
|
@@ -28,7 +28,7 @@ export const DileCloseDocumentClick = (SuperClass) =>
|
|
|
28
28
|
DileCloseDocumentClick.closeDocumentHandler = () => {
|
|
29
29
|
if(DileCloseDocumentClick.elements) {
|
|
30
30
|
for (let ele of DileCloseDocumentClick.elements) {
|
|
31
|
-
ele.
|
|
31
|
+
ele.closeFromDocumentClick();
|
|
32
32
|
}
|
|
33
33
|
}
|
|
34
34
|
};
|
|
@@ -70,6 +70,15 @@ export const DileCloseDocumentClick = (SuperClass) =>
|
|
|
70
70
|
});
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
+
/**
|
|
74
|
+
* Close requested by a click in the document. Calls close() by default.
|
|
75
|
+
* Override it to ignore these closes in some states, as DileOverlay does
|
|
76
|
+
* while the overlay is opening.
|
|
77
|
+
*/
|
|
78
|
+
closeFromDocumentClick() {
|
|
79
|
+
this.close();
|
|
80
|
+
}
|
|
81
|
+
|
|
73
82
|
/**
|
|
74
83
|
* This method only alerts the developer to create the close() method in his component
|
|
75
84
|
*/
|
|
@@ -80,35 +80,63 @@ export const DileOverlay = function(superClass) {
|
|
|
80
80
|
}
|
|
81
81
|
/**
|
|
82
82
|
* closes the overlay
|
|
83
|
+
*
|
|
84
|
+
* An explicit close() while the overlay is still opening (the 50ms delay of open())
|
|
85
|
+
* cancels the opening, so the overlay ends up closed.
|
|
83
86
|
*/
|
|
84
87
|
close() {
|
|
85
|
-
if(
|
|
88
|
+
if(this._opening) {
|
|
89
|
+
this.cancelDelay();
|
|
90
|
+
this._opening = false;
|
|
91
|
+
this._overlayClass = '';
|
|
92
|
+
this.overlay.style.display = 'none';
|
|
93
|
+
this._dispatchClosed();
|
|
94
|
+
} else if(this._overlayClass=='opened') {
|
|
86
95
|
this._overlayClass = '';
|
|
87
96
|
this._removePositionListeners();
|
|
88
97
|
this.cancelDelay();
|
|
89
98
|
this.delayId = setTimeout(() => {
|
|
90
99
|
this.overlay.style.display = 'none'
|
|
91
100
|
}, 500);
|
|
92
|
-
this.
|
|
101
|
+
this._dispatchClosed();
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Close requested by a document click (DileCloseDocumentClick). It is ignored while
|
|
106
|
+
* the overlay is opening, because the same click that opens the overlay bubbles up
|
|
107
|
+
* to the document.
|
|
108
|
+
*/
|
|
109
|
+
closeFromDocumentClick() {
|
|
110
|
+
if(!this._opening) {
|
|
111
|
+
this.close();
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
_dispatchClosed() {
|
|
115
|
+
this.dispatchEvent(new CustomEvent('overlay-closed', {
|
|
93
116
|
bubbles: true,
|
|
94
117
|
composed: true,
|
|
95
118
|
}));
|
|
96
|
-
}
|
|
97
119
|
}
|
|
98
120
|
/**
|
|
99
121
|
* opens the overlay
|
|
122
|
+
*
|
|
123
|
+
* overlay-opened is only dispatched when the overlay was closed, so every
|
|
124
|
+
* overlay-opened is paired with one overlay-closed.
|
|
100
125
|
*/
|
|
101
126
|
open() {
|
|
102
|
-
this.
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
127
|
+
if(!this._opening && this._overlayClass != 'opened') {
|
|
128
|
+
this.dispatchEvent(new CustomEvent('overlay-opened', {
|
|
129
|
+
bubbles: true,
|
|
130
|
+
composed: true,
|
|
131
|
+
}));
|
|
132
|
+
}
|
|
106
133
|
if(!this._opening) {
|
|
107
134
|
this._opening = true;
|
|
108
135
|
this.updatePosition();
|
|
109
|
-
if
|
|
110
|
-
|
|
111
|
-
|
|
136
|
+
// Close the other overlays, even if they are still opening.
|
|
137
|
+
if(this.closeOthers) {
|
|
138
|
+
this.closeOthers();
|
|
139
|
+
}
|
|
112
140
|
this.overlay.style.display = 'block';
|
|
113
141
|
this.cancelDelay();
|
|
114
142
|
this.delayId = setTimeout(() => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dile/ui",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.19.1",
|
|
4
4
|
"description": "UI Core components from dile-components.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -28,5 +28,5 @@
|
|
|
28
28
|
"publishConfig": {
|
|
29
29
|
"access": "public"
|
|
30
30
|
},
|
|
31
|
-
"gitHead": "
|
|
31
|
+
"gitHead": "33fa981c48f488be6c9a381f1a32eeffa5b92b24"
|
|
32
32
|
}
|