@mustib/web-components 0.0.0-alpha.0
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/README.md +17 -0
- package/components/mu-element.d.ts +107 -0
- package/components/mu-element.js +4 -0
- package/components/mu-icon.d.ts +25 -0
- package/components/mu-icon.js +65 -0
- package/components/mu-range-fill.d.ts +48 -0
- package/components/mu-range-fill.js +94 -0
- package/components/mu-range-thumb-value.d.ts +48 -0
- package/components/mu-range-thumb-value.js +137 -0
- package/components/mu-range-thumb.d.ts +120 -0
- package/components/mu-range-thumb.js +305 -0
- package/components/mu-range.d.ts +206 -0
- package/components/mu-range.js +661 -0
- package/components/mu-select-item.d.ts +29 -0
- package/components/mu-select-item.js +124 -0
- package/components/mu-select-items.d.ts +218 -0
- package/components/mu-select-items.js +570 -0
- package/components/mu-select-label-content.d.ts +38 -0
- package/components/mu-select-label-content.js +159 -0
- package/components/mu-select-label.d.ts +52 -0
- package/components/mu-select-label.js +352 -0
- package/components/mu-select.d.ts +63 -0
- package/components/mu-select.js +347 -0
- package/components/mu-transparent.d.ts +56 -0
- package/components/mu-transparent.js +75 -0
- package/components/mu-trigger.d.ts +129 -0
- package/components/mu-trigger.js +175 -0
- package/decorators.d.ts +34 -0
- package/decorators.js +50 -0
- package/index.d.ts +15 -0
- package/index.js +17 -0
- package/mu-element-CZDI_RCY.js +1117 -0
- package/package.json +45 -0
|
@@ -0,0 +1,347 @@
|
|
|
1
|
+
import { M as MUElement, E as EventAction, _ as __decorate } from '../mu-element-CZDI_RCY.js';
|
|
2
|
+
import { css, html } from 'lit';
|
|
3
|
+
import { property, queryAssignedElements } from 'lit/decorators.js';
|
|
4
|
+
import { MuSelectItems } from './mu-select-items.js';
|
|
5
|
+
import { MuSelectLabel } from './mu-select-label.js';
|
|
6
|
+
import { MuTransparent } from './mu-transparent.js';
|
|
7
|
+
import { staticProperty } from '../decorators.js';
|
|
8
|
+
import './mu-select-item.js';
|
|
9
|
+
import './mu-trigger.js';
|
|
10
|
+
import './mu-select-label-content.js';
|
|
11
|
+
import 'lit/directives/repeat.js';
|
|
12
|
+
import './mu-icon.js';
|
|
13
|
+
|
|
14
|
+
class MuSelect extends MUElement {
|
|
15
|
+
constructor() {
|
|
16
|
+
super(...arguments);
|
|
17
|
+
this.opened = false;
|
|
18
|
+
this.noCloseAfterSelect = false;
|
|
19
|
+
this.noCloseAfterBlur = false;
|
|
20
|
+
/**
|
|
21
|
+
* for internal usage
|
|
22
|
+
*
|
|
23
|
+
* this is used to prevent closing the select when a value change is dispatched through a way that shouldn't require select to close after receiving a value change event fired by select items like pressing Backspace to remove a value in autocomplete mode
|
|
24
|
+
*/
|
|
25
|
+
this._canCloseAfterChange = true;
|
|
26
|
+
this._value = [];
|
|
27
|
+
this._isReady = this.generateIsReadyPromise();
|
|
28
|
+
this.eventActionData = {
|
|
29
|
+
eventAction: MuSelect.eventAction,
|
|
30
|
+
events: ['click', 'pointerdown', 'pointerup', 'keydown', 'input']
|
|
31
|
+
};
|
|
32
|
+
this.itemsChangeHandler = (e) => {
|
|
33
|
+
e.detail.isCurrentSelection && this._valueChanged(e.detail.values);
|
|
34
|
+
if (this._labelElement?.hasAutocomplete) {
|
|
35
|
+
this._labelElement.clearAutocompleteValue();
|
|
36
|
+
this._itemsElement?.clearFilteredOutItems();
|
|
37
|
+
}
|
|
38
|
+
if (!this.noCloseAfterSelect && this._canCloseAfterChange) {
|
|
39
|
+
this.opened = false;
|
|
40
|
+
this.focus();
|
|
41
|
+
}
|
|
42
|
+
this._canCloseAfterChange = true;
|
|
43
|
+
};
|
|
44
|
+
this._slotChangeHandler = () => {
|
|
45
|
+
const assignElement = (element) => {
|
|
46
|
+
if (element instanceof MuSelectItems) {
|
|
47
|
+
this._itemsElement = element;
|
|
48
|
+
}
|
|
49
|
+
else if (element instanceof MuSelectLabel) {
|
|
50
|
+
this._labelElement = element;
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
this._assignedElements.forEach(element => {
|
|
54
|
+
if (element instanceof MuTransparent) {
|
|
55
|
+
element.contents.forEach(el => assignElement(el));
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
assignElement(element);
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
if (this._labelElement) {
|
|
62
|
+
this._labelElement.opened = this.opened;
|
|
63
|
+
this._labelElement.disabled = this.disabled;
|
|
64
|
+
this._labelElement.setListboxId(this._itemsElement?.id);
|
|
65
|
+
}
|
|
66
|
+
if (this._itemsElement) {
|
|
67
|
+
this._itemsElement.opened = this.opened;
|
|
68
|
+
this._itemsElement.disabled = this.disabled;
|
|
69
|
+
this._valueChanged(this._itemsElement.getValue());
|
|
70
|
+
this._itemsElement.setAttribute('aria-label', this._labelElement?.legend ?? '');
|
|
71
|
+
}
|
|
72
|
+
this._isReady.resolve();
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
_addEventActionAttributes() {
|
|
76
|
+
this.setAttribute('data-select-keydown', JSON.stringify([
|
|
77
|
+
// open and switch active item on ArrowUp and ArrowDown keys
|
|
78
|
+
'#key:ArrowDown? #prevent',
|
|
79
|
+
'#key:ArrowDown? open',
|
|
80
|
+
'#key:ArrowDown? ||switch-active-item:next-true',
|
|
81
|
+
'#key:ArrowUp? #prevent',
|
|
82
|
+
'#key:ArrowUp? open',
|
|
83
|
+
'#key:ArrowUp? ||switch-active-item:prev-true',
|
|
84
|
+
// switch active template value on ArrowLeft and ArrowRight keys
|
|
85
|
+
'#key:ArrowLeft? template? no-autocomplete-value? #prevent',
|
|
86
|
+
'#key:ArrowLeft? template? no-autocomplete-value? ||switch-active-template:prev',
|
|
87
|
+
'#key:ArrowRight? template? no-autocomplete-value? #prevent',
|
|
88
|
+
'#key:ArrowRight? template? no-autocomplete-value? ||switch-active-template:next',
|
|
89
|
+
'#key:Escape? ||close',
|
|
90
|
+
// toggle active select if opened and has active item on Enter
|
|
91
|
+
'#key:Enter? opened? has-active-item? #prevent',
|
|
92
|
+
'#key:Enter? opened? has-active-item? ||toggle-active-select',
|
|
93
|
+
// close if opened and no active item on Enter
|
|
94
|
+
'#key:Enter? opened? no-active-item? #prevent',
|
|
95
|
+
'#key:Enter? opened? no-active-item? ||close',
|
|
96
|
+
// open if closed on Enter
|
|
97
|
+
'#key:Enter? closed? #prevent',
|
|
98
|
+
'#key:Enter? closed? ||open',
|
|
99
|
+
// open if closed and not autocomplete on space
|
|
100
|
+
`#key:Space? closed? no-autocomplete? #prevent`,
|
|
101
|
+
`#key:Space? closed? no-autocomplete? ||open`,
|
|
102
|
+
// close if opened and not autocomplete and not active item on space
|
|
103
|
+
`#key:Space? opened? no-autocomplete? no-active-item? #prevent`,
|
|
104
|
+
`#key:Space? opened? no-autocomplete? no-active-item? ||close`,
|
|
105
|
+
// toggle active select if opened and not autocomplete and has active item on space
|
|
106
|
+
`#key:Space? opened? no-autocomplete? has-active-item? #prevent`,
|
|
107
|
+
`#key:Space? opened? no-autocomplete? has-active-item? ||toggle-active-select`,
|
|
108
|
+
// remove last value if no autocomplete on Backspace
|
|
109
|
+
'#key:Backspace? no-autocomplete? #prevent',
|
|
110
|
+
'#key:Backspace? no-autocomplete? ||remove-last-value',
|
|
111
|
+
// remove last value if autocomplete both and not empty on Backspace
|
|
112
|
+
'#key:Backspace? autocomplete:both? not-empty? #prevent',
|
|
113
|
+
'#key:Backspace? autocomplete:both? not-empty? ||remove-last-value',
|
|
114
|
+
// remove last value if autocomplete and has active template value on Backspace
|
|
115
|
+
'#key:Backspace? autocomplete? has-active-template? #prevent',
|
|
116
|
+
'#key:Backspace? autocomplete? has-active-template? ||remove-last-value:template',
|
|
117
|
+
// remove last value if autocomplete and no active template value on Backspace
|
|
118
|
+
'#key:Backspace? autocomplete? no-autocomplete-value? #prevent',
|
|
119
|
+
'#key:Backspace? autocomplete? no-autocomplete-value? ||remove-last-value',
|
|
120
|
+
], undefined, 0));
|
|
121
|
+
}
|
|
122
|
+
focus() {
|
|
123
|
+
this._labelElement?.focus();
|
|
124
|
+
}
|
|
125
|
+
connectedCallback() {
|
|
126
|
+
super.connectedCallback();
|
|
127
|
+
this.addEventListener('focusout', (e) => {
|
|
128
|
+
if (!this.noCloseAfterBlur)
|
|
129
|
+
this.opened = false;
|
|
130
|
+
});
|
|
131
|
+
this.addEventListener('mu-select-items-change-forced', (e) => {
|
|
132
|
+
this._valueChanged(e.detail.values);
|
|
133
|
+
});
|
|
134
|
+
this.addEventListener('mu-transparent-slotchange', this._slotChangeHandler);
|
|
135
|
+
this.addEventListener('mu-select-items-change', this.itemsChangeHandler);
|
|
136
|
+
}
|
|
137
|
+
_valueChanged(value) {
|
|
138
|
+
const valueArr = Array.isArray(value) ? value : value?.split(',') ?? [];
|
|
139
|
+
this._value = valueArr;
|
|
140
|
+
if (this._labelElement) {
|
|
141
|
+
this._labelElement.value = valueArr;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
_handleOpenChange() {
|
|
145
|
+
this._itemsElement && (this._itemsElement.opened = this.opened);
|
|
146
|
+
this._labelElement && (this._labelElement.opened = this.opened);
|
|
147
|
+
if (this.opened) {
|
|
148
|
+
this.focus();
|
|
149
|
+
this.dispatchEvent(new CustomEvent('mu-select-opened', { bubbles: true, composed: true }));
|
|
150
|
+
}
|
|
151
|
+
else {
|
|
152
|
+
if (this._itemsElement)
|
|
153
|
+
this._itemsElement.opened = false;
|
|
154
|
+
this.dispatchEvent(new CustomEvent('mu-select-closed', { bubbles: true, composed: true }));
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
async getUpdateComplete() {
|
|
158
|
+
const result = await super.getUpdateComplete();
|
|
159
|
+
await this._isReady.promise;
|
|
160
|
+
return result;
|
|
161
|
+
}
|
|
162
|
+
updated(_changedProperties) {
|
|
163
|
+
if (_changedProperties.has('opened')) {
|
|
164
|
+
this._handleOpenChange();
|
|
165
|
+
}
|
|
166
|
+
if (_changedProperties.has('disabled')) {
|
|
167
|
+
this._itemsElement && (this._itemsElement.disabled = this.disabled);
|
|
168
|
+
this._labelElement && (this._labelElement.disabled = this.disabled);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
async firstUpdated(_changedProperties) {
|
|
172
|
+
await this._isReady.promise;
|
|
173
|
+
if (this.opened)
|
|
174
|
+
this._itemsElement?.focusFirstNavigableItem('next');
|
|
175
|
+
if (!this._itemsElement || !this._labelElement) {
|
|
176
|
+
console.warn('mu-select should have mu-select-items and mu-select-label as children', this);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
render() {
|
|
180
|
+
return html `
|
|
181
|
+
<div id='container' part='container'>
|
|
182
|
+
<slot @slotchange=${this._slotChangeHandler}></slot>
|
|
183
|
+
</div>
|
|
184
|
+
`;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
MuSelect.styles = [MUElement.cssBase, css `
|
|
188
|
+
:host([opened]) #container {
|
|
189
|
+
z-index: 100;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
#container {
|
|
193
|
+
position: relative;
|
|
194
|
+
min-width: fit-content;
|
|
195
|
+
max-width: 100%;
|
|
196
|
+
margin: auto;
|
|
197
|
+
}
|
|
198
|
+
`];
|
|
199
|
+
MuSelect.eventAction = new EventAction({
|
|
200
|
+
getEventAttributeName(eventName) {
|
|
201
|
+
return `data-select-${eventName}`;
|
|
202
|
+
},
|
|
203
|
+
currTargetSelector: 'mu-select',
|
|
204
|
+
actions: {
|
|
205
|
+
toggle(data) {
|
|
206
|
+
const select = data.event.currentTarget;
|
|
207
|
+
if (!select.interactable)
|
|
208
|
+
return;
|
|
209
|
+
select.opened = !select.opened;
|
|
210
|
+
},
|
|
211
|
+
open(data) {
|
|
212
|
+
const select = data.event.currentTarget;
|
|
213
|
+
if (!select.interactable)
|
|
214
|
+
return;
|
|
215
|
+
select.opened = true;
|
|
216
|
+
},
|
|
217
|
+
close(data) {
|
|
218
|
+
const select = data.event.currentTarget;
|
|
219
|
+
if (!select.interactable)
|
|
220
|
+
return;
|
|
221
|
+
select.opened = false;
|
|
222
|
+
},
|
|
223
|
+
'remove-value'(data) {
|
|
224
|
+
const select = data.event.currentTarget;
|
|
225
|
+
const value = data.actionParam;
|
|
226
|
+
if (!select.interactable || typeof value !== 'string')
|
|
227
|
+
return;
|
|
228
|
+
select._canCloseAfterChange = false;
|
|
229
|
+
select._itemsElement?.unselect([value]);
|
|
230
|
+
},
|
|
231
|
+
"remove-last-value"(data) {
|
|
232
|
+
const select = data.event.currentTarget;
|
|
233
|
+
if (!select.interactable)
|
|
234
|
+
return;
|
|
235
|
+
select._canCloseAfterChange = false;
|
|
236
|
+
let type;
|
|
237
|
+
if (data.actionParam === 'template')
|
|
238
|
+
type = 'template';
|
|
239
|
+
else if (data.actionParam === 'item')
|
|
240
|
+
type = 'item';
|
|
241
|
+
else {
|
|
242
|
+
type = select._labelElement?.activeTemplateValue ? 'template' : 'item';
|
|
243
|
+
}
|
|
244
|
+
if (type === 'template') {
|
|
245
|
+
const value = select._labelElement?.activeTemplateValue;
|
|
246
|
+
value && select._itemsElement?.unselect([value]);
|
|
247
|
+
}
|
|
248
|
+
else if (type === 'item')
|
|
249
|
+
select._itemsElement?.unselectLatestItem();
|
|
250
|
+
},
|
|
251
|
+
'remove-all'(data) {
|
|
252
|
+
const select = data.event.currentTarget;
|
|
253
|
+
if (!select.interactable)
|
|
254
|
+
return;
|
|
255
|
+
select._canCloseAfterChange = false;
|
|
256
|
+
select._itemsElement?.unselectAll();
|
|
257
|
+
},
|
|
258
|
+
'switch-active-item'({ event, actionParam }) {
|
|
259
|
+
if (typeof actionParam !== 'string')
|
|
260
|
+
return;
|
|
261
|
+
const [dir, switchBack] = actionParam.split('-');
|
|
262
|
+
if (dir === 'next')
|
|
263
|
+
event.currentTarget._itemsElement?.switchActiveItem('next', { switchBack: switchBack === 'true' });
|
|
264
|
+
else if (dir === 'prev')
|
|
265
|
+
event.currentTarget._itemsElement?.switchActiveItem('prev', { switchBack: switchBack === 'true' });
|
|
266
|
+
},
|
|
267
|
+
'toggle-active-select'(data) {
|
|
268
|
+
data.event.currentTarget._itemsElement?.toggleActiveItemSelect();
|
|
269
|
+
},
|
|
270
|
+
'switch-active-template'({ event, actionParam }) {
|
|
271
|
+
if (actionParam === 'next')
|
|
272
|
+
event.currentTarget._labelElement?.switchActiveTemplate('next');
|
|
273
|
+
else if (actionParam === 'prev')
|
|
274
|
+
event.currentTarget._labelElement?.switchActiveTemplate('prev');
|
|
275
|
+
},
|
|
276
|
+
filter(data) {
|
|
277
|
+
const select = data.event.currentTarget;
|
|
278
|
+
if (!select.interactable)
|
|
279
|
+
return;
|
|
280
|
+
const hasValue = (el) => typeof el?.value === 'string';
|
|
281
|
+
const value = typeof data.actionParam === 'string' && data.actionParam ? data.actionParam : hasValue(data.matchedTarget) ? data.matchedTarget.value : '';
|
|
282
|
+
select._itemsElement?.filterOutItems(value);
|
|
283
|
+
}
|
|
284
|
+
},
|
|
285
|
+
switches: {
|
|
286
|
+
opened(data) {
|
|
287
|
+
return data.event.currentTarget.opened;
|
|
288
|
+
},
|
|
289
|
+
closed(data) {
|
|
290
|
+
return !data.event.currentTarget.opened;
|
|
291
|
+
},
|
|
292
|
+
empty(data) {
|
|
293
|
+
return data.event.currentTarget._value.length === 0;
|
|
294
|
+
},
|
|
295
|
+
'not-empty'(data) {
|
|
296
|
+
return data.event.currentTarget._value.length > 0;
|
|
297
|
+
},
|
|
298
|
+
'has-active-item'(data) {
|
|
299
|
+
return data.event.currentTarget._itemsElement?.activeValue !== undefined;
|
|
300
|
+
},
|
|
301
|
+
'no-active-item'(data) {
|
|
302
|
+
return data.event.currentTarget._itemsElement?.activeValue === undefined;
|
|
303
|
+
},
|
|
304
|
+
template(data) {
|
|
305
|
+
return data.event.currentTarget._labelElement?.hasTemplate === true;
|
|
306
|
+
},
|
|
307
|
+
'no-template'(data) {
|
|
308
|
+
return data.event.currentTarget._labelElement?.hasTemplate !== true;
|
|
309
|
+
},
|
|
310
|
+
'has-active-template'(data) {
|
|
311
|
+
return !!data.event.currentTarget._labelElement?.activeTemplateValue;
|
|
312
|
+
},
|
|
313
|
+
'no-active-template'(data) {
|
|
314
|
+
return !data.event.currentTarget._labelElement?.activeTemplateValue;
|
|
315
|
+
},
|
|
316
|
+
autocomplete(data) {
|
|
317
|
+
const select = data.event.currentTarget;
|
|
318
|
+
if (data.switchParam === 'both')
|
|
319
|
+
return select._labelElement?.hasAutocompleteBoth === true;
|
|
320
|
+
return select._labelElement?.hasAutocomplete === true;
|
|
321
|
+
},
|
|
322
|
+
'no-autocomplete'(data) {
|
|
323
|
+
return data.event.currentTarget._labelElement?.hasAutocomplete !== true;
|
|
324
|
+
},
|
|
325
|
+
'has-autocomplete-value'(data) {
|
|
326
|
+
return !!data.event.currentTarget._labelElement?.autocompleteValue;
|
|
327
|
+
},
|
|
328
|
+
'no-autocomplete-value'(data) {
|
|
329
|
+
return !data.event.currentTarget._labelElement?.autocompleteValue;
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
});
|
|
333
|
+
__decorate([
|
|
334
|
+
property({ reflect: true, type: Boolean })
|
|
335
|
+
], MuSelect.prototype, "opened", void 0);
|
|
336
|
+
__decorate([
|
|
337
|
+
staticProperty({ converter: Boolean })
|
|
338
|
+
], MuSelect.prototype, "noCloseAfterSelect", void 0);
|
|
339
|
+
__decorate([
|
|
340
|
+
staticProperty({ converter: Boolean })
|
|
341
|
+
], MuSelect.prototype, "noCloseAfterBlur", void 0);
|
|
342
|
+
__decorate([
|
|
343
|
+
queryAssignedElements({ flatten: true })
|
|
344
|
+
], MuSelect.prototype, "_assignedElements", void 0);
|
|
345
|
+
MuSelect.register('mu-select');
|
|
346
|
+
|
|
347
|
+
export { MuSelect };
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { MUElement } from './mu-element.js';
|
|
2
|
+
import { CSSResultGroup } from 'lit';
|
|
3
|
+
import '@mustib/utils/browser';
|
|
4
|
+
|
|
5
|
+
type Events = {
|
|
6
|
+
'mu-transparent-slotchange': CustomEvent<{
|
|
7
|
+
source: MuTransparent;
|
|
8
|
+
}>;
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* A base class for "transparent" wrapper components.
|
|
12
|
+
*
|
|
13
|
+
* Transparent components introduce an extra DOM node,
|
|
14
|
+
* but parent components treat them as if they were semantically invisible.
|
|
15
|
+
*
|
|
16
|
+
* Their purpose is to add behavior, context, or interaction forwarding
|
|
17
|
+
* without changing how parents interact with child elements.
|
|
18
|
+
*
|
|
19
|
+
* It can be extended to add functionalities like context menus, scroll containers, triggering events, etc.
|
|
20
|
+
*
|
|
21
|
+
* Use the `content` property to access the underlying
|
|
22
|
+
* meaningful child element, regardless of the wrapping.
|
|
23
|
+
*/
|
|
24
|
+
declare class MuTransparent extends MUElement {
|
|
25
|
+
static styles?: CSSResultGroup;
|
|
26
|
+
eventActionData: undefined;
|
|
27
|
+
_addEventActionAttributes: undefined;
|
|
28
|
+
/**
|
|
29
|
+
* The selector of the elements that transparent wraps so that they can be queried when needed.
|
|
30
|
+
*
|
|
31
|
+
* it defaults to `& > *` which means all child elements
|
|
32
|
+
*/
|
|
33
|
+
contentSelector: string;
|
|
34
|
+
/**
|
|
35
|
+
* Returns the meaningful child elements of the transparent component.
|
|
36
|
+
*
|
|
37
|
+
* The contents are the child elements that are not part of the
|
|
38
|
+
* transparent wrapper. If `contentSelector` is not set, any child
|
|
39
|
+
* element is considered meaningful. If `contentSelector` is set,
|
|
40
|
+
* only the child elements that match the selector are considered meaningful.
|
|
41
|
+
*/
|
|
42
|
+
get contents(): unknown[];
|
|
43
|
+
constructor();
|
|
44
|
+
protected _dispatchSlotChange: () => void;
|
|
45
|
+
protected render(): unknown;
|
|
46
|
+
}
|
|
47
|
+
declare global {
|
|
48
|
+
interface HTMLElementTagNameMap {
|
|
49
|
+
"mu-transparent": MuTransparent;
|
|
50
|
+
}
|
|
51
|
+
interface GlobalEventHandlersEventMap extends Events {
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export { MuTransparent };
|
|
56
|
+
export type { Events };
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { _ as __decorate, M as MUElement } from '../mu-element-CZDI_RCY.js';
|
|
2
|
+
import { property } from 'lit/decorators.js';
|
|
3
|
+
import { css, html } from 'lit';
|
|
4
|
+
import '../decorators.js';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* A base class for "transparent" wrapper components.
|
|
8
|
+
*
|
|
9
|
+
* Transparent components introduce an extra DOM node,
|
|
10
|
+
* but parent components treat them as if they were semantically invisible.
|
|
11
|
+
*
|
|
12
|
+
* Their purpose is to add behavior, context, or interaction forwarding
|
|
13
|
+
* without changing how parents interact with child elements.
|
|
14
|
+
*
|
|
15
|
+
* It can be extended to add functionalities like context menus, scroll containers, triggering events, etc.
|
|
16
|
+
*
|
|
17
|
+
* Use the `content` property to access the underlying
|
|
18
|
+
* meaningful child element, regardless of the wrapping.
|
|
19
|
+
*/
|
|
20
|
+
class MuTransparent extends MUElement {
|
|
21
|
+
/**
|
|
22
|
+
* Returns the meaningful child elements of the transparent component.
|
|
23
|
+
*
|
|
24
|
+
* The contents are the child elements that are not part of the
|
|
25
|
+
* transparent wrapper. If `contentSelector` is not set, any child
|
|
26
|
+
* element is considered meaningful. If `contentSelector` is set,
|
|
27
|
+
* only the child elements that match the selector are considered meaningful.
|
|
28
|
+
*/
|
|
29
|
+
get contents() {
|
|
30
|
+
const contents = this.querySelectorAll(this.contentSelector);
|
|
31
|
+
if (!contents.length)
|
|
32
|
+
throw new Error(`No contents found for ${this.tagName}`);
|
|
33
|
+
return Array.from(contents);
|
|
34
|
+
}
|
|
35
|
+
;
|
|
36
|
+
constructor() {
|
|
37
|
+
super();
|
|
38
|
+
this.eventActionData = undefined;
|
|
39
|
+
this._addEventActionAttributes = undefined;
|
|
40
|
+
/**
|
|
41
|
+
* The selector of the elements that transparent wraps so that they can be queried when needed.
|
|
42
|
+
*
|
|
43
|
+
* it defaults to `& > *` which means all child elements
|
|
44
|
+
*/
|
|
45
|
+
this.contentSelector = '& > *';
|
|
46
|
+
this._dispatchSlotChange = () => {
|
|
47
|
+
const eventName = 'mu-transparent-slotchange';
|
|
48
|
+
const event = new CustomEvent(eventName, { bubbles: true, composed: true, detail: { source: this } });
|
|
49
|
+
this.dispatchEvent(event);
|
|
50
|
+
};
|
|
51
|
+
this.updateComplete.then(() => {
|
|
52
|
+
/**
|
|
53
|
+
* Forward slotchange events skipping the first event because the parent must handle it
|
|
54
|
+
* a way to inform the parent that the contents have changed instead of using MutationObserver
|
|
55
|
+
*/
|
|
56
|
+
this.renderRoot.addEventListener('slotchange', this._dispatchSlotChange);
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
render() {
|
|
60
|
+
return html `
|
|
61
|
+
<slot></slot>
|
|
62
|
+
`;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
MuTransparent.styles = css `
|
|
66
|
+
:host {
|
|
67
|
+
display: contents !important;
|
|
68
|
+
}
|
|
69
|
+
`;
|
|
70
|
+
__decorate([
|
|
71
|
+
property({ attribute: 'content-selector' })
|
|
72
|
+
], MuTransparent.prototype, "contentSelector", void 0);
|
|
73
|
+
MuTransparent.register("mu-transparent");
|
|
74
|
+
|
|
75
|
+
export { MuTransparent };
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { MuTransparent } from './mu-transparent.js';
|
|
2
|
+
import './mu-element.js';
|
|
3
|
+
import 'lit';
|
|
4
|
+
import '@mustib/utils/browser';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* `<mu-trigger>` is a helper element that listens for a specified event
|
|
8
|
+
* (e.g., `click`) and dispatches a custom event (e.g., `mu-trigger-toggle`)
|
|
9
|
+
* to a target element.
|
|
10
|
+
*
|
|
11
|
+
* This is useful when you want to listen to event and dispatch a custom event
|
|
12
|
+
* like dispatch toggle when a user clicks on a button.
|
|
13
|
+
*
|
|
14
|
+
* it abstracts away the logic of selecting the element, listening to the event, dispatching the custom event, removing the event listener when the element is disconnected, and more.
|
|
15
|
+
*
|
|
16
|
+
* you can reuse different triggers (click, keydown, hover, etc.)
|
|
17
|
+
* without hard-coding logic inside the parent element (e.g., `mu-select`).
|
|
18
|
+
*/
|
|
19
|
+
declare class MuTrigger<T extends Event = Event> extends MuTransparent {
|
|
20
|
+
/**
|
|
21
|
+
* The DOM event to listen for (e.g., `"click"`, `"keydown"`, `"mouseenter"`).
|
|
22
|
+
* @attr listen-to
|
|
23
|
+
* @default "click"
|
|
24
|
+
*/
|
|
25
|
+
listenTo: string;
|
|
26
|
+
/**
|
|
27
|
+
* A JSON string representing the detail to pass to the custom event.
|
|
28
|
+
* @default undefined
|
|
29
|
+
*/
|
|
30
|
+
detail: any;
|
|
31
|
+
/**
|
|
32
|
+
* A boolean value indicates if the event should call `stopPropagation`.
|
|
33
|
+
* @default false
|
|
34
|
+
*/
|
|
35
|
+
stopPropagation: boolean;
|
|
36
|
+
/**
|
|
37
|
+
* A boolean value indicates if the event should call `stopImmediatePropagation`.
|
|
38
|
+
* @default false
|
|
39
|
+
*/
|
|
40
|
+
stopImmediatePropagation: boolean;
|
|
41
|
+
/**
|
|
42
|
+
* The name of the custom event to dispatch when the trigger fires.
|
|
43
|
+
* @default "mu-trigger-toggle"
|
|
44
|
+
*/
|
|
45
|
+
dispatch: string;
|
|
46
|
+
/**
|
|
47
|
+
* Whether the event is no-cancelable.
|
|
48
|
+
* @default false
|
|
49
|
+
*/
|
|
50
|
+
noCancelable: boolean;
|
|
51
|
+
/**
|
|
52
|
+
* Whether the custom event should not bubble.
|
|
53
|
+
*
|
|
54
|
+
* @default false
|
|
55
|
+
*/
|
|
56
|
+
noBubble: boolean;
|
|
57
|
+
/**
|
|
58
|
+
* A boolean value indicates if the listener should not be added as a capture listener.
|
|
59
|
+
* @default false
|
|
60
|
+
*/
|
|
61
|
+
noCapture: boolean;
|
|
62
|
+
/**
|
|
63
|
+
* A css selector that is used to find the element that will listen for the event.
|
|
64
|
+
* which is the current target of the event.
|
|
65
|
+
*
|
|
66
|
+
* current target will be this element by default
|
|
67
|
+
*
|
|
68
|
+
* @default undefined
|
|
69
|
+
*/
|
|
70
|
+
currentTargetSelector?: string;
|
|
71
|
+
/**
|
|
72
|
+
* A boolean value indicates if the event should not call `preventDefault`.
|
|
73
|
+
* @default false
|
|
74
|
+
*/
|
|
75
|
+
noPreventDefault: boolean;
|
|
76
|
+
/**
|
|
77
|
+
* A CSS selector used to find the element where the event should be dispatched.
|
|
78
|
+
* If not provided, the trigger dispatches the event on itself.
|
|
79
|
+
*
|
|
80
|
+
* Example: `dispatch-to-selector="#mu-select"`
|
|
81
|
+
*
|
|
82
|
+
* @attr dispatch-to-selector
|
|
83
|
+
*/
|
|
84
|
+
dispatchToSelector?: string;
|
|
85
|
+
eventActionData: undefined;
|
|
86
|
+
_addEventActionAttributes: undefined;
|
|
87
|
+
/**
|
|
88
|
+
* The current target of the event.
|
|
89
|
+
*/
|
|
90
|
+
protected get _currentTarget(): Element;
|
|
91
|
+
/**
|
|
92
|
+
* A function that returns the element where the event should be dispatched.
|
|
93
|
+
* If not provided, the trigger dispatches the event on itself.
|
|
94
|
+
*/
|
|
95
|
+
protected _getDispatchElement(): Element;
|
|
96
|
+
/**
|
|
97
|
+
* This function is called after the event is fired.
|
|
98
|
+
* You can return a custom object with the following properties to customize the dispatching of the event.
|
|
99
|
+
* - `shouldDispatch`: a boolean indicating whether the event should be dispatched.
|
|
100
|
+
* - `eventName`: a string indicating the name of the event to be dispatched.
|
|
101
|
+
* - `dispatchElement`: an element indicating where the event should be dispatched.
|
|
102
|
+
*
|
|
103
|
+
* If you return nothing, the event will not be dispatched.
|
|
104
|
+
*
|
|
105
|
+
* @param e The original event that was fired.
|
|
106
|
+
* @returns {Object} An object with the properties above.
|
|
107
|
+
*/
|
|
108
|
+
protected _createDispatchEvent(e: T): {
|
|
109
|
+
shouldDispatch: boolean;
|
|
110
|
+
eventName: string;
|
|
111
|
+
dispatchElement: Element;
|
|
112
|
+
};
|
|
113
|
+
/**
|
|
114
|
+
*
|
|
115
|
+
*/
|
|
116
|
+
protected _listener: (e: Event) => void;
|
|
117
|
+
/**
|
|
118
|
+
*
|
|
119
|
+
*/
|
|
120
|
+
connectedCallback(): void;
|
|
121
|
+
disconnectedCallback(): void;
|
|
122
|
+
}
|
|
123
|
+
declare global {
|
|
124
|
+
interface HTMLElementTagNameMap {
|
|
125
|
+
'mu-trigger': MuTrigger;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export { MuTrigger };
|