@rededor/cura 2.0.0-alpha.11 → 2.0.0-alpha.13
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/dist/cjs/{cura-accordion_21.cjs.entry.js → cura-accordion_22.cjs.entry.js} +6872 -0
- package/dist/cjs/cura.cjs.js +1 -1
- package/dist/cjs/index.cjs.js +1140 -0
- package/dist/cjs/loader.cjs.js +1 -1
- package/dist/collection/components/cura-calendar/cura-calendar.css +27 -0
- package/dist/collection/components/cura-calendar/cura-calendar.js +65 -2
- package/dist/collection/components/cura-calendar/cura-calendar.stories.js +10 -0
- package/dist/collection/index.js +2 -0
- package/dist/components/cura-calendar.js +1 -1
- package/dist/components/cura-input-date.js +1 -1
- package/dist/components/index.js +1 -1
- package/dist/components/{p-CpmZ68rD.js → p-C05r6CQV.js} +1 -1
- package/dist/cura/cura.esm.js +1 -1
- package/dist/cura/index.esm.js +1 -1
- package/dist/cura/p-47fdb124.entry.js +1 -0
- package/dist/esm/{cura-accordion_21.entry.js → cura-accordion_22.entry.js} +6872 -1
- package/dist/esm/cura.js +1 -1
- package/dist/esm/index.js +1140 -0
- package/dist/esm/loader.js +1 -1
- package/dist/types/components/cura-calendar/cura-calendar.d.ts +11 -0
- package/dist/types/components/cura-calendar/cura-calendar.stories.d.ts +11 -0
- package/dist/types/components.d.ts +13 -0
- package/dist/types/index.d.ts +1 -0
- package/package.json +3 -2
- package/dist/cjs/cura-calendar.cjs.entry.js +0 -6840
- package/dist/cura/p-27ba7ef5.entry.js +0 -1
- package/dist/cura/p-54624944.entry.js +0 -1
- package/dist/esm/cura-calendar.entry.js +0 -6838
package/dist/cjs/index.cjs.js
CHANGED
|
@@ -4,6 +4,1146 @@ var curaThemeModule = require('./cura-theme-module-Dg1d3VUN.js');
|
|
|
4
4
|
require('./theme-legacy-default-COE-hjD7.js');
|
|
5
5
|
require('./static-DHz-FA_O.js');
|
|
6
6
|
|
|
7
|
+
/**
|
|
8
|
+
* This file contains the WeakMaps used throughout this project. The WeakMaps exist to tie
|
|
9
|
+
* objects together without polluting the objects themselves with references we'd rather keep
|
|
10
|
+
* hidden. This allows the polyfill to work as transparently as possible.
|
|
11
|
+
*/
|
|
12
|
+
/** Use an ElementInternals instance to get a reference to the element it is attached to */
|
|
13
|
+
const refMap = new WeakMap();
|
|
14
|
+
/** Usee an ElementsInternals instance to get its ValidityState object */
|
|
15
|
+
const validityMap = new WeakMap();
|
|
16
|
+
/** Use an ElementInternals instance to get its attached input[type="hidden"] */
|
|
17
|
+
const hiddenInputMap = new WeakMap();
|
|
18
|
+
/** Use a custom element to get its attached ElementInternals instance */
|
|
19
|
+
const internalsMap = new WeakMap();
|
|
20
|
+
/** Use an ElementInternals instance to get the attached validation message */
|
|
21
|
+
const validationMessageMap = new WeakMap();
|
|
22
|
+
/** Use a form element to get attached custom elements and ElementInternals instances */
|
|
23
|
+
const formsMap = new WeakMap();
|
|
24
|
+
/** Use a custom element or other object to get their associated MutationObservers */
|
|
25
|
+
const shadowHostsMap = new WeakMap();
|
|
26
|
+
/** Use a form element to get a set of attached custom elements */
|
|
27
|
+
const formElementsMap = new WeakMap();
|
|
28
|
+
/** Use an ElementInternals instance to get a reference to an element's value */
|
|
29
|
+
const refValueMap = new WeakMap();
|
|
30
|
+
/** Elements that need to be upgraded once added to the DOM */
|
|
31
|
+
const upgradeMap = new WeakMap();
|
|
32
|
+
/** Save references to shadow roots for inclusion in internals instance */
|
|
33
|
+
const shadowRootMap = new WeakMap();
|
|
34
|
+
/** Save a reference to the internals' validation anchor */
|
|
35
|
+
const validationAnchorMap = new WeakMap();
|
|
36
|
+
/** Map DocumentFragments to their MutationObservers so we can disconnect once elements are removed */
|
|
37
|
+
const documentFragmentMap = new WeakMap();
|
|
38
|
+
/** Whether connectedCallback has already been called. */
|
|
39
|
+
const connectedCallbackMap = new WeakMap();
|
|
40
|
+
/** Save a reference to validity state for elements that need to upgrade after being connected */
|
|
41
|
+
const validityUpgradeMap = new WeakMap();
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Set attribute if its value differs from existing one.
|
|
45
|
+
*
|
|
46
|
+
* In comparison to other attribute modification methods (removeAttribute and
|
|
47
|
+
* toggleAttribute), setAttribute always triggers attributeChangedCallback
|
|
48
|
+
* even if the actual value has not changed.
|
|
49
|
+
*
|
|
50
|
+
* This polyfill relies heavily on attributes to pass aria information to
|
|
51
|
+
* screen readers. This behaviour differs from native implementation which does
|
|
52
|
+
* not change attributes.
|
|
53
|
+
*
|
|
54
|
+
* To limit this difference we only set attribute value when it is different
|
|
55
|
+
* from the current state.
|
|
56
|
+
*
|
|
57
|
+
* @param {ICustomElement | Element} ref - The custom element instance
|
|
58
|
+
* @param {string} name - The attribute name
|
|
59
|
+
* @param {string} value - The attribute value
|
|
60
|
+
* @returns
|
|
61
|
+
*/
|
|
62
|
+
const setAttribute = (ref, name, value) => {
|
|
63
|
+
if (ref.getAttribute(name) === value) {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
ref.setAttribute(name, value);
|
|
67
|
+
};
|
|
68
|
+
/**
|
|
69
|
+
* Toggle's the disabled state (attributes & callback) on the given element
|
|
70
|
+
* @param {HTMLElement} ref - The custom element instance
|
|
71
|
+
* @param {boolean} disabled - The disabled state
|
|
72
|
+
*/
|
|
73
|
+
const setDisabled = (ref, disabled) => {
|
|
74
|
+
ref.toggleAttribute("internals-disabled", disabled);
|
|
75
|
+
if (disabled) {
|
|
76
|
+
setAttribute(ref, "aria-disabled", "true");
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
ref.removeAttribute("aria-disabled");
|
|
80
|
+
}
|
|
81
|
+
if (ref.formDisabledCallback) {
|
|
82
|
+
ref.formDisabledCallback.apply(ref, [disabled]);
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
/**
|
|
86
|
+
* Removes all hidden inputs for the given element internals instance
|
|
87
|
+
* @param {ElementInternals} internals - The element internals instance
|
|
88
|
+
* @return {void}
|
|
89
|
+
*/
|
|
90
|
+
const removeHiddenInputs = (internals) => {
|
|
91
|
+
const hiddenInputs = hiddenInputMap.get(internals);
|
|
92
|
+
hiddenInputs.forEach((hiddenInput) => {
|
|
93
|
+
hiddenInput.remove();
|
|
94
|
+
});
|
|
95
|
+
hiddenInputMap.set(internals, []);
|
|
96
|
+
};
|
|
97
|
+
/**
|
|
98
|
+
* Creates a hidden input for the given ref
|
|
99
|
+
* @param {HTMLElement} ref - The element to watch
|
|
100
|
+
* @param {ElementInternals} internals - The element internals instance for the ref
|
|
101
|
+
* @return {HTMLInputElement} The hidden input
|
|
102
|
+
*/
|
|
103
|
+
const createHiddenInput = (ref, internals) => {
|
|
104
|
+
const input = document.createElement("input");
|
|
105
|
+
input.type = "hidden";
|
|
106
|
+
input.name = ref.getAttribute("name");
|
|
107
|
+
ref.after(input);
|
|
108
|
+
hiddenInputMap.get(internals).push(input);
|
|
109
|
+
return input;
|
|
110
|
+
};
|
|
111
|
+
/**
|
|
112
|
+
* Set up labels for the ref
|
|
113
|
+
* @param {HTMLElement} ref - The ref to add labels to
|
|
114
|
+
* @param {NodeList} labels - A list of the labels
|
|
115
|
+
* @return {void}
|
|
116
|
+
*/
|
|
117
|
+
const initLabels = (ref, labels) => {
|
|
118
|
+
if (labels.length) {
|
|
119
|
+
const labelList = Array.from(labels);
|
|
120
|
+
labelList.forEach((label) => label.addEventListener("click", ref.click.bind(ref)));
|
|
121
|
+
const [firstLabel] = labelList;
|
|
122
|
+
let firstLabelId = firstLabel.id;
|
|
123
|
+
if (!firstLabel.id) {
|
|
124
|
+
firstLabelId = `${firstLabel.htmlFor}_Label`;
|
|
125
|
+
firstLabel.id = firstLabelId;
|
|
126
|
+
}
|
|
127
|
+
setAttribute(ref, "aria-labelledby", firstLabelId);
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
/**
|
|
131
|
+
* Sets the internals-valid and internals-invalid attributes
|
|
132
|
+
* based on form validity.
|
|
133
|
+
* @param {HTMLFormElement} - The target form
|
|
134
|
+
* @return {void}
|
|
135
|
+
*/
|
|
136
|
+
const setFormValidity = (form) => {
|
|
137
|
+
const nativeControlValidity = Array.from(form.elements)
|
|
138
|
+
.filter((element) => !element.tagName.includes("-") && element.validity)
|
|
139
|
+
.map((element) => element.validity.valid);
|
|
140
|
+
const polyfilledElements = formElementsMap.get(form) || [];
|
|
141
|
+
const polyfilledValidity = Array.from(polyfilledElements)
|
|
142
|
+
.filter((control) => control.isConnected)
|
|
143
|
+
.map((control) => internalsMap.get(control).validity.valid);
|
|
144
|
+
const hasInvalid = [...nativeControlValidity, ...polyfilledValidity].includes(false);
|
|
145
|
+
form.toggleAttribute("internals-invalid", hasInvalid);
|
|
146
|
+
form.toggleAttribute("internals-valid", !hasInvalid);
|
|
147
|
+
};
|
|
148
|
+
/**
|
|
149
|
+
* The global form input callback. Updates the form's validity
|
|
150
|
+
* attributes on input.
|
|
151
|
+
* @param {Event} - The form input event
|
|
152
|
+
* @return {void}
|
|
153
|
+
*/
|
|
154
|
+
const formInputCallback = (event) => {
|
|
155
|
+
setFormValidity(findParentForm(event.target));
|
|
156
|
+
};
|
|
157
|
+
/**
|
|
158
|
+
* The global form change callback. Updates the form's validity
|
|
159
|
+
* attributes on change.
|
|
160
|
+
* @param {Event} - The form change event
|
|
161
|
+
* @return {void}
|
|
162
|
+
*/
|
|
163
|
+
const formChangeCallback = (event) => {
|
|
164
|
+
setFormValidity(findParentForm(event.target));
|
|
165
|
+
};
|
|
166
|
+
/**
|
|
167
|
+
* The global form submit callback. We need to cancel any submission
|
|
168
|
+
* if a nested internals is invalid.
|
|
169
|
+
* @param {HTMLFormElement} - The form element
|
|
170
|
+
* @return {void}
|
|
171
|
+
*/
|
|
172
|
+
const wireSubmitLogic = (form) => {
|
|
173
|
+
const submitButtonSelector = [
|
|
174
|
+
"button[type=submit]",
|
|
175
|
+
"input[type=submit]",
|
|
176
|
+
"button:not([type])",
|
|
177
|
+
]
|
|
178
|
+
.map((sel) => `${sel}:not([disabled])`)
|
|
179
|
+
.map((sel) => `${sel}:not([form])${form.id ? `,${sel}[form='${form.id}']` : ""}`)
|
|
180
|
+
.join(",");
|
|
181
|
+
form.addEventListener("click", (event) => {
|
|
182
|
+
const target = event.target;
|
|
183
|
+
if (target.closest(submitButtonSelector)) {
|
|
184
|
+
// validate
|
|
185
|
+
const elements = formElementsMap.get(form);
|
|
186
|
+
/**
|
|
187
|
+
* If this form does not validate then we're done
|
|
188
|
+
*/
|
|
189
|
+
if (form.noValidate) {
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
/** If the Set has items, continue */
|
|
193
|
+
if (elements.size) {
|
|
194
|
+
const nodes = Array.from(elements);
|
|
195
|
+
/** Check the internals.checkValidity() of all nodes */
|
|
196
|
+
const validityList = nodes.reverse().map((node) => {
|
|
197
|
+
const internals = internalsMap.get(node);
|
|
198
|
+
return internals.reportValidity();
|
|
199
|
+
});
|
|
200
|
+
/** If any node is false, stop the event */
|
|
201
|
+
if (validityList.includes(false)) {
|
|
202
|
+
event.preventDefault();
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
});
|
|
207
|
+
};
|
|
208
|
+
/**
|
|
209
|
+
* The global form reset callback. This will loop over added
|
|
210
|
+
* inputs and call formResetCallback if applicable
|
|
211
|
+
* @return {void}
|
|
212
|
+
*/
|
|
213
|
+
const formResetCallback = (event) => {
|
|
214
|
+
/** Get the Set of elements attached to this form */
|
|
215
|
+
const elements = formElementsMap.get(event.target);
|
|
216
|
+
/** Some forms won't contain form associated custom elements */
|
|
217
|
+
if (elements && elements.size) {
|
|
218
|
+
/** Loop over the elements and call formResetCallback if applicable */
|
|
219
|
+
elements.forEach((element) => {
|
|
220
|
+
if (element.constructor.formAssociated &&
|
|
221
|
+
element.formResetCallback) {
|
|
222
|
+
element.formResetCallback.apply(element);
|
|
223
|
+
}
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
};
|
|
227
|
+
/**
|
|
228
|
+
* Initialize the form. We will need to add submit and reset listeners
|
|
229
|
+
* if they don't already exist. If they do, just add the new ref to the form.
|
|
230
|
+
* @param {HTMLElement} ref - The element ref that includes internals
|
|
231
|
+
* @param {HTMLFormElement} form - The form the ref belongs to
|
|
232
|
+
* @param {ElementInternals} internals - The internals for ref
|
|
233
|
+
* @return {void}
|
|
234
|
+
*/
|
|
235
|
+
const initForm = (ref, form, internals) => {
|
|
236
|
+
if (form) {
|
|
237
|
+
/** This will be a WeakMap<HTMLFormElement, Set<HTMLElement> */
|
|
238
|
+
const formElements = formElementsMap.get(form);
|
|
239
|
+
if (formElements) {
|
|
240
|
+
/** If formElements exists, add to it */
|
|
241
|
+
formElements.add(ref);
|
|
242
|
+
}
|
|
243
|
+
else {
|
|
244
|
+
/** If formElements doesn't exist, create it and add to it */
|
|
245
|
+
const initSet = new Set();
|
|
246
|
+
initSet.add(ref);
|
|
247
|
+
formElementsMap.set(form, initSet);
|
|
248
|
+
/** Add listeners to emulate validation and reset behavior */
|
|
249
|
+
wireSubmitLogic(form);
|
|
250
|
+
form.addEventListener("reset", formResetCallback);
|
|
251
|
+
form.addEventListener("input", formInputCallback);
|
|
252
|
+
form.addEventListener("change", formChangeCallback);
|
|
253
|
+
}
|
|
254
|
+
formsMap.set(form, { ref, internals });
|
|
255
|
+
/** Call formAssociatedCallback if applicable */
|
|
256
|
+
if (ref.constructor["formAssociated"] && ref.formAssociatedCallback) {
|
|
257
|
+
setTimeout(() => {
|
|
258
|
+
ref.formAssociatedCallback.apply(ref, [form]);
|
|
259
|
+
}, 0);
|
|
260
|
+
}
|
|
261
|
+
setFormValidity(form);
|
|
262
|
+
}
|
|
263
|
+
};
|
|
264
|
+
/**
|
|
265
|
+
* Recursively look for an element's parent form
|
|
266
|
+
* @param {Element} elem - The element to look for a parent form
|
|
267
|
+
* @return {HTMLFormElement|null} - The parent form, if one exists
|
|
268
|
+
*/
|
|
269
|
+
const findParentForm = (elem) => {
|
|
270
|
+
let parent = elem.parentNode;
|
|
271
|
+
if (parent && parent.tagName !== "FORM") {
|
|
272
|
+
parent = findParentForm(parent);
|
|
273
|
+
}
|
|
274
|
+
return parent;
|
|
275
|
+
};
|
|
276
|
+
/**
|
|
277
|
+
* Throw an error if the element ref is not form associated
|
|
278
|
+
* @param ref {HTMLElement} - The element to check if it is form associated
|
|
279
|
+
* @param message {string} - The error message to throw
|
|
280
|
+
* @param ErrorType {any} - The error type to throw, defaults to DOMException
|
|
281
|
+
*/
|
|
282
|
+
const throwIfNotFormAssociated = (ref, message, ErrorType = DOMException) => {
|
|
283
|
+
if (!ref.constructor["formAssociated"]) {
|
|
284
|
+
throw new ErrorType(message);
|
|
285
|
+
}
|
|
286
|
+
};
|
|
287
|
+
/**
|
|
288
|
+
* Called for each HTMLFormElement.checkValidity|reportValidity
|
|
289
|
+
* will loop over a form's added components and call the respective
|
|
290
|
+
* method modifying the default return value if needed
|
|
291
|
+
* @param form {HTMLFormElement} - The form element to run the method on
|
|
292
|
+
* @param returnValue {boolean} - The initial result of the original method
|
|
293
|
+
* @param method {'checkValidity'|'reportValidity'} - The original method
|
|
294
|
+
* @returns {boolean} The form's validity state
|
|
295
|
+
*/
|
|
296
|
+
const overrideFormMethod = (form, returnValue, method) => {
|
|
297
|
+
const elements = formElementsMap.get(form);
|
|
298
|
+
/** Some forms won't contain form associated custom elements */
|
|
299
|
+
if (elements && elements.size) {
|
|
300
|
+
elements.forEach((element) => {
|
|
301
|
+
const internals = internalsMap.get(element);
|
|
302
|
+
const valid = internals[method]();
|
|
303
|
+
if (!valid) {
|
|
304
|
+
returnValue = false;
|
|
305
|
+
}
|
|
306
|
+
});
|
|
307
|
+
}
|
|
308
|
+
return returnValue;
|
|
309
|
+
};
|
|
310
|
+
/**
|
|
311
|
+
* Will upgrade an ElementInternals instance by initializing the
|
|
312
|
+
* instance's form and labels. This is called when the element is
|
|
313
|
+
* either constructed or appended from a DocumentFragment
|
|
314
|
+
* @param ref {HTMLElement} - The custom element to upgrade
|
|
315
|
+
*/
|
|
316
|
+
const upgradeInternals = (ref) => {
|
|
317
|
+
let attached = false;
|
|
318
|
+
if (ref.constructor["formAssociated"]) {
|
|
319
|
+
let internals = internalsMap.get(ref);
|
|
320
|
+
// we might have cases where the internals are not set
|
|
321
|
+
if (internals === undefined) {
|
|
322
|
+
ref.attachInternals();
|
|
323
|
+
internals = internalsMap.get(ref);
|
|
324
|
+
attached = true;
|
|
325
|
+
}
|
|
326
|
+
const { labels, form } = internals;
|
|
327
|
+
initLabels(ref, labels);
|
|
328
|
+
initForm(ref, form, internals);
|
|
329
|
+
}
|
|
330
|
+
return attached;
|
|
331
|
+
};
|
|
332
|
+
/**
|
|
333
|
+
* Check to see if MutationObserver exists in the current
|
|
334
|
+
* execution context. Will likely return false on the server
|
|
335
|
+
* @returns {boolean}
|
|
336
|
+
*/
|
|
337
|
+
function mutationObserverExists() {
|
|
338
|
+
return typeof MutationObserver !== "undefined";
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
const aom = {
|
|
342
|
+
ariaAtomic: "aria-atomic",
|
|
343
|
+
ariaAutoComplete: "aria-autocomplete",
|
|
344
|
+
ariaBrailleLabel: "aria-braillelabel",
|
|
345
|
+
ariaBrailleRoleDescription: "aria-brailleroledescription",
|
|
346
|
+
ariaBusy: "aria-busy",
|
|
347
|
+
ariaChecked: "aria-checked",
|
|
348
|
+
ariaColCount: "aria-colcount",
|
|
349
|
+
ariaColIndex: "aria-colindex",
|
|
350
|
+
ariaColIndexText: "aria-colindextext",
|
|
351
|
+
ariaColSpan: "aria-colspan",
|
|
352
|
+
ariaCurrent: "aria-current",
|
|
353
|
+
ariaDescription: "aria-description",
|
|
354
|
+
ariaDisabled: "aria-disabled",
|
|
355
|
+
ariaExpanded: "aria-expanded",
|
|
356
|
+
ariaHasPopup: "aria-haspopup",
|
|
357
|
+
ariaHidden: "aria-hidden",
|
|
358
|
+
ariaInvalid: "aria-invalid",
|
|
359
|
+
ariaKeyShortcuts: "aria-keyshortcuts",
|
|
360
|
+
ariaLabel: "aria-label",
|
|
361
|
+
ariaLevel: "aria-level",
|
|
362
|
+
ariaLive: "aria-live",
|
|
363
|
+
ariaModal: "aria-modal",
|
|
364
|
+
ariaMultiLine: "aria-multiline",
|
|
365
|
+
ariaMultiSelectable: "aria-multiselectable",
|
|
366
|
+
ariaOrientation: "aria-orientation",
|
|
367
|
+
ariaPlaceholder: "aria-placeholder",
|
|
368
|
+
ariaPosInSet: "aria-posinset",
|
|
369
|
+
ariaPressed: "aria-pressed",
|
|
370
|
+
ariaReadOnly: "aria-readonly",
|
|
371
|
+
ariaRelevant: "aria-relevant",
|
|
372
|
+
ariaRequired: "aria-required",
|
|
373
|
+
ariaRoleDescription: "aria-roledescription",
|
|
374
|
+
ariaRowCount: "aria-rowcount",
|
|
375
|
+
ariaRowIndex: "aria-rowindex",
|
|
376
|
+
ariaRowIndexText: "aria-rowindextext",
|
|
377
|
+
ariaRowSpan: "aria-rowspan",
|
|
378
|
+
ariaSelected: "aria-selected",
|
|
379
|
+
ariaSetSize: "aria-setsize",
|
|
380
|
+
ariaSort: "aria-sort",
|
|
381
|
+
ariaValueMax: "aria-valuemax",
|
|
382
|
+
ariaValueMin: "aria-valuemin",
|
|
383
|
+
ariaValueNow: "aria-valuenow",
|
|
384
|
+
ariaValueText: "aria-valuetext",
|
|
385
|
+
role: "role",
|
|
386
|
+
};
|
|
387
|
+
const initAom = (ref, internals) => {
|
|
388
|
+
for (let key in aom) {
|
|
389
|
+
internals[key] = null;
|
|
390
|
+
let closureValue = null;
|
|
391
|
+
const attributeName = aom[key];
|
|
392
|
+
Object.defineProperty(internals, key, {
|
|
393
|
+
get() {
|
|
394
|
+
return closureValue;
|
|
395
|
+
},
|
|
396
|
+
set(value) {
|
|
397
|
+
closureValue = value;
|
|
398
|
+
if (ref.isConnected) {
|
|
399
|
+
setAttribute(ref, attributeName, value);
|
|
400
|
+
}
|
|
401
|
+
else {
|
|
402
|
+
upgradeMap.set(ref, internals);
|
|
403
|
+
}
|
|
404
|
+
},
|
|
405
|
+
});
|
|
406
|
+
}
|
|
407
|
+
};
|
|
408
|
+
|
|
409
|
+
/**
|
|
410
|
+
* Initialize a ref by setting up an attribute observe on it
|
|
411
|
+
* looking for changes to disabled
|
|
412
|
+
* @param {HTMLElement} ref - The element to watch
|
|
413
|
+
* @param {ElementInternals} internals - The element internals instance for the ref
|
|
414
|
+
* @return {void}
|
|
415
|
+
*/
|
|
416
|
+
const initRef = (ref, internals) => {
|
|
417
|
+
hiddenInputMap.set(internals, []);
|
|
418
|
+
disabledOrNameObserver.observe?.(ref, disabledOrNameObserverConfig);
|
|
419
|
+
};
|
|
420
|
+
function initNode(node) {
|
|
421
|
+
const internals = internalsMap.get(node);
|
|
422
|
+
const { form } = internals;
|
|
423
|
+
initForm(node, form, internals);
|
|
424
|
+
initLabels(node, internals.labels);
|
|
425
|
+
}
|
|
426
|
+
/**
|
|
427
|
+
* If a fieldset's disabled state is toggled, the formDisabledCallback
|
|
428
|
+
* on any child form-associated cusotm elements.
|
|
429
|
+
*/
|
|
430
|
+
const walkFieldset = (node, firstRender = false) => {
|
|
431
|
+
const walker = document.createTreeWalker(node, NodeFilter.SHOW_ELEMENT, {
|
|
432
|
+
acceptNode(node) {
|
|
433
|
+
return internalsMap.has(node) ?
|
|
434
|
+
NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_SKIP;
|
|
435
|
+
}
|
|
436
|
+
});
|
|
437
|
+
let current = walker.nextNode();
|
|
438
|
+
/**
|
|
439
|
+
* We don't need to call anything on first render if
|
|
440
|
+
* the element isn't disabled
|
|
441
|
+
*/
|
|
442
|
+
const isCallNecessary = (!firstRender || node.disabled);
|
|
443
|
+
while (current) {
|
|
444
|
+
if (current.formDisabledCallback && isCallNecessary) {
|
|
445
|
+
setDisabled(current, node.disabled);
|
|
446
|
+
}
|
|
447
|
+
current = walker.nextNode();
|
|
448
|
+
}
|
|
449
|
+
};
|
|
450
|
+
const disabledOrNameObserverConfig = { attributes: true, attributeFilter: ['disabled', 'name'] };
|
|
451
|
+
const disabledOrNameObserver = mutationObserverExists() ? new MutationObserver((mutationsList) => {
|
|
452
|
+
for (const mutation of mutationsList) {
|
|
453
|
+
const target = mutation.target;
|
|
454
|
+
/** Manage changes to the ref's disabled state */
|
|
455
|
+
if (mutation.attributeName === 'disabled') {
|
|
456
|
+
if (target.constructor['formAssociated']) {
|
|
457
|
+
setDisabled(target, target.hasAttribute('disabled'));
|
|
458
|
+
}
|
|
459
|
+
else if (target.localName === 'fieldset') {
|
|
460
|
+
/**
|
|
461
|
+
* Repurpose the observer for fieldsets which need
|
|
462
|
+
* to be walked whenever the disabled attribute is set
|
|
463
|
+
*/
|
|
464
|
+
walkFieldset(target);
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
/** Manage changes to the ref's name */
|
|
468
|
+
if (mutation.attributeName === 'name') {
|
|
469
|
+
if (target.constructor['formAssociated']) {
|
|
470
|
+
const internals = internalsMap.get(target);
|
|
471
|
+
const value = refValueMap.get(target);
|
|
472
|
+
internals.setFormValue(value);
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
}) : {};
|
|
477
|
+
function observerCallback(mutationList) {
|
|
478
|
+
mutationList.forEach(mutationRecord => {
|
|
479
|
+
const { addedNodes, removedNodes } = mutationRecord;
|
|
480
|
+
const added = Array.from(addedNodes);
|
|
481
|
+
const removed = Array.from(removedNodes);
|
|
482
|
+
added.forEach(node => {
|
|
483
|
+
/** Allows for dynamic addition of elements to forms */
|
|
484
|
+
if (internalsMap.has(node) && node.constructor['formAssociated']) {
|
|
485
|
+
initNode(node);
|
|
486
|
+
}
|
|
487
|
+
/** Upgrade the accessibility information on any previously connected */
|
|
488
|
+
if (upgradeMap.has(node)) {
|
|
489
|
+
const internals = upgradeMap.get(node);
|
|
490
|
+
const aomKeys = Object.keys(aom);
|
|
491
|
+
aomKeys
|
|
492
|
+
.filter(key => internals[key] !== null)
|
|
493
|
+
.forEach(key => {
|
|
494
|
+
setAttribute(node, aom[key], internals[key]);
|
|
495
|
+
});
|
|
496
|
+
upgradeMap.delete(node);
|
|
497
|
+
}
|
|
498
|
+
/** Upgrade the validity state when the element is connected */
|
|
499
|
+
if (validityUpgradeMap.has(node)) {
|
|
500
|
+
const internals = validityUpgradeMap.get(node);
|
|
501
|
+
setAttribute(node, 'internals-valid', internals.validity.valid.toString());
|
|
502
|
+
setAttribute(node, 'internals-invalid', (!internals.validity.valid).toString());
|
|
503
|
+
setAttribute(node, 'aria-invalid', (!internals.validity.valid).toString());
|
|
504
|
+
validityUpgradeMap.delete(node);
|
|
505
|
+
}
|
|
506
|
+
/** If the node that's added is a form, check the validity */
|
|
507
|
+
if (node.localName === 'form') {
|
|
508
|
+
const formElements = formElementsMap.get(node);
|
|
509
|
+
const walker = document.createTreeWalker(node, NodeFilter.SHOW_ELEMENT, {
|
|
510
|
+
acceptNode(node) {
|
|
511
|
+
return (internalsMap.has(node) && node.constructor['formAssociated'] && !(formElements && formElements.has(node))) ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_SKIP;
|
|
512
|
+
}
|
|
513
|
+
});
|
|
514
|
+
let current = walker.nextNode();
|
|
515
|
+
while (current) {
|
|
516
|
+
initNode(current);
|
|
517
|
+
current = walker.nextNode();
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
if (node.localName === 'fieldset') {
|
|
521
|
+
disabledOrNameObserver.observe?.(node, disabledOrNameObserverConfig);
|
|
522
|
+
walkFieldset(node, true);
|
|
523
|
+
}
|
|
524
|
+
});
|
|
525
|
+
removed.forEach(node => {
|
|
526
|
+
const internals = internalsMap.get(node);
|
|
527
|
+
/** Clean up any hidden input elements left after an element is disconnected */
|
|
528
|
+
if (internals && hiddenInputMap.get(internals)) {
|
|
529
|
+
removeHiddenInputs(internals);
|
|
530
|
+
}
|
|
531
|
+
/** Disconnect any unneeded MutationObservers */
|
|
532
|
+
if (shadowHostsMap.has(node)) {
|
|
533
|
+
const observer = shadowHostsMap.get(node);
|
|
534
|
+
observer.disconnect();
|
|
535
|
+
}
|
|
536
|
+
});
|
|
537
|
+
});
|
|
538
|
+
}
|
|
539
|
+
/**
|
|
540
|
+
* This observer callback is just for document fragments
|
|
541
|
+
* it will upgrade an ElementInternals instance if was appended
|
|
542
|
+
* from a document fragment.
|
|
543
|
+
*/
|
|
544
|
+
function fragmentObserverCallback(mutationList) {
|
|
545
|
+
mutationList.forEach(mutation => {
|
|
546
|
+
const { removedNodes } = mutation;
|
|
547
|
+
removedNodes.forEach(node => {
|
|
548
|
+
const observer = documentFragmentMap.get(mutation.target);
|
|
549
|
+
if (internalsMap.has(node)) {
|
|
550
|
+
upgradeInternals(node);
|
|
551
|
+
}
|
|
552
|
+
observer.disconnect();
|
|
553
|
+
});
|
|
554
|
+
});
|
|
555
|
+
}
|
|
556
|
+
/**
|
|
557
|
+
* Defer the upgrade of nodes withing a DocumentFragment
|
|
558
|
+
* @param fragment {DocumentFragment}
|
|
559
|
+
*/
|
|
560
|
+
const deferUpgrade = (fragment) => {
|
|
561
|
+
const observer = new MutationObserver(fragmentObserverCallback);
|
|
562
|
+
// is this using shady DOM and is not actually a DocumentFragment?
|
|
563
|
+
if (window?.ShadyDOM?.inUse &&
|
|
564
|
+
fragment.mode &&
|
|
565
|
+
fragment.host) {
|
|
566
|
+
// using shady DOM polyfill. Best to just observe the host.
|
|
567
|
+
fragment = fragment.host;
|
|
568
|
+
}
|
|
569
|
+
observer.observe?.(fragment, { childList: true });
|
|
570
|
+
documentFragmentMap.set(fragment, observer);
|
|
571
|
+
};
|
|
572
|
+
mutationObserverExists() ? new MutationObserver(observerCallback) : {};
|
|
573
|
+
const observerConfig = {
|
|
574
|
+
childList: true,
|
|
575
|
+
subtree: true
|
|
576
|
+
};
|
|
577
|
+
|
|
578
|
+
/** Emulate the browser's default ValidityState object */
|
|
579
|
+
class ValidityState {
|
|
580
|
+
constructor() {
|
|
581
|
+
this.badInput = false;
|
|
582
|
+
this.customError = false;
|
|
583
|
+
this.patternMismatch = false;
|
|
584
|
+
this.rangeOverflow = false;
|
|
585
|
+
this.rangeUnderflow = false;
|
|
586
|
+
this.stepMismatch = false;
|
|
587
|
+
this.tooLong = false;
|
|
588
|
+
this.tooShort = false;
|
|
589
|
+
this.typeMismatch = false;
|
|
590
|
+
this.valid = true;
|
|
591
|
+
this.valueMissing = false;
|
|
592
|
+
Object.seal(this);
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
/**
|
|
596
|
+
* Reset a ValidityState object back to valid
|
|
597
|
+
* @param {ValidityState} validityObject - The object to modify
|
|
598
|
+
* @return {ValidityState} - The modified ValidityStateObject
|
|
599
|
+
*/
|
|
600
|
+
const setValid = (validityObject) => {
|
|
601
|
+
validityObject.badInput = false;
|
|
602
|
+
validityObject.customError = false;
|
|
603
|
+
validityObject.patternMismatch = false;
|
|
604
|
+
validityObject.rangeOverflow = false;
|
|
605
|
+
validityObject.rangeUnderflow = false;
|
|
606
|
+
validityObject.stepMismatch = false;
|
|
607
|
+
validityObject.tooLong = false;
|
|
608
|
+
validityObject.tooShort = false;
|
|
609
|
+
validityObject.typeMismatch = false;
|
|
610
|
+
validityObject.valid = true;
|
|
611
|
+
validityObject.valueMissing = false;
|
|
612
|
+
return validityObject;
|
|
613
|
+
};
|
|
614
|
+
/**
|
|
615
|
+
* Reconcile a ValidityState object with a new state object
|
|
616
|
+
* @param {ValidityState} - The base object to reconcile with new state
|
|
617
|
+
* @param {Object} - A partial ValidityState object to override the original
|
|
618
|
+
* @return {ValidityState} - The updated ValidityState object
|
|
619
|
+
*/
|
|
620
|
+
const reconcileValidity = (validityObject, newState, form) => {
|
|
621
|
+
validityObject.valid = isValid(newState);
|
|
622
|
+
Object.keys(newState).forEach(key => validityObject[key] = newState[key]);
|
|
623
|
+
if (form) {
|
|
624
|
+
setFormValidity(form);
|
|
625
|
+
}
|
|
626
|
+
return validityObject;
|
|
627
|
+
};
|
|
628
|
+
/**
|
|
629
|
+
* Check if a partial ValidityState object should be valid
|
|
630
|
+
* @param {Object} - A partial ValidityState object
|
|
631
|
+
* @return {Boolean} - Should the new object be valid
|
|
632
|
+
*/
|
|
633
|
+
const isValid = (validityState) => {
|
|
634
|
+
let valid = true;
|
|
635
|
+
for (let key in validityState) {
|
|
636
|
+
if (key !== 'valid' && validityState[key] !== false) {
|
|
637
|
+
valid = false;
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
return valid;
|
|
641
|
+
};
|
|
642
|
+
|
|
643
|
+
/** Save a reference to the ref for the CustomStateSet */
|
|
644
|
+
const customStateMap = new WeakMap();
|
|
645
|
+
function addState(ref, stateName) {
|
|
646
|
+
ref.toggleAttribute(stateName, true);
|
|
647
|
+
if (ref.part) {
|
|
648
|
+
ref.part.add(stateName);
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
class CustomStateSet extends Set {
|
|
652
|
+
static get isPolyfilled() {
|
|
653
|
+
return true;
|
|
654
|
+
}
|
|
655
|
+
constructor(ref) {
|
|
656
|
+
super();
|
|
657
|
+
if (!ref || !ref.tagName || ref.tagName.indexOf("-") === -1) {
|
|
658
|
+
throw new TypeError("Illegal constructor");
|
|
659
|
+
}
|
|
660
|
+
customStateMap.set(this, ref);
|
|
661
|
+
}
|
|
662
|
+
add(state) {
|
|
663
|
+
if (!/^--/.test(state) || typeof state !== "string") {
|
|
664
|
+
throw new DOMException(`Failed to execute 'add' on 'CustomStateSet': The specified value ${state} must start with '--'.`);
|
|
665
|
+
}
|
|
666
|
+
const result = super.add(state);
|
|
667
|
+
const ref = customStateMap.get(this);
|
|
668
|
+
const stateName = `state${state}`;
|
|
669
|
+
/**
|
|
670
|
+
* Only add the state immediately if the ref is connected to the DOM;
|
|
671
|
+
* otherwise, wait a tick because the element is likely being constructed
|
|
672
|
+
* by document.createElement and would throw otherwise.
|
|
673
|
+
*/
|
|
674
|
+
if (ref.isConnected) {
|
|
675
|
+
addState(ref, stateName);
|
|
676
|
+
}
|
|
677
|
+
else {
|
|
678
|
+
setTimeout(() => {
|
|
679
|
+
addState(ref, stateName);
|
|
680
|
+
});
|
|
681
|
+
}
|
|
682
|
+
return result;
|
|
683
|
+
}
|
|
684
|
+
clear() {
|
|
685
|
+
for (let [entry] of this.entries()) {
|
|
686
|
+
this.delete(entry);
|
|
687
|
+
}
|
|
688
|
+
super.clear();
|
|
689
|
+
}
|
|
690
|
+
delete(state) {
|
|
691
|
+
const result = super.delete(state);
|
|
692
|
+
const ref = customStateMap.get(this);
|
|
693
|
+
/**
|
|
694
|
+
* Only toggle the state/attr immediately if the ref is connected to the DOM;
|
|
695
|
+
* otherwise, wait a tick because the element is likely being constructed
|
|
696
|
+
* by document.createElement and would throw otherwise.
|
|
697
|
+
*/
|
|
698
|
+
if (ref.isConnected) {
|
|
699
|
+
ref.toggleAttribute(`state${state}`, false);
|
|
700
|
+
if (ref.part) {
|
|
701
|
+
ref.part.remove(`state${state}`);
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
else {
|
|
705
|
+
setTimeout(() => {
|
|
706
|
+
ref.toggleAttribute(`state${state}`, false);
|
|
707
|
+
if (ref.part) {
|
|
708
|
+
ref.part.remove(`state${state}`);
|
|
709
|
+
}
|
|
710
|
+
});
|
|
711
|
+
}
|
|
712
|
+
return result;
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
var __classPrivateFieldSet = (undefined && undefined.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
|
|
717
|
+
if (kind === "m") throw new TypeError("Private method is not writable");
|
|
718
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
|
|
719
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
|
|
720
|
+
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
|
|
721
|
+
};
|
|
722
|
+
var __classPrivateFieldGet = (undefined && undefined.__classPrivateFieldGet) || function (receiver, state, kind, f) {
|
|
723
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
|
724
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
725
|
+
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
726
|
+
};
|
|
727
|
+
var _HTMLFormControlsCollection_elements;
|
|
728
|
+
class HTMLFormControlsCollection {
|
|
729
|
+
constructor(elements) {
|
|
730
|
+
_HTMLFormControlsCollection_elements.set(this, void 0);
|
|
731
|
+
__classPrivateFieldSet(this, _HTMLFormControlsCollection_elements, elements, "f");
|
|
732
|
+
for (let i = 0; i < elements.length; i++) {
|
|
733
|
+
let element = elements[i];
|
|
734
|
+
this[i] = element;
|
|
735
|
+
if (element.hasAttribute('name')) {
|
|
736
|
+
this[element.getAttribute('name')] = element;
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
Object.freeze(this);
|
|
740
|
+
}
|
|
741
|
+
get length() {
|
|
742
|
+
return __classPrivateFieldGet(this, _HTMLFormControlsCollection_elements, "f").length;
|
|
743
|
+
}
|
|
744
|
+
[(_HTMLFormControlsCollection_elements = new WeakMap(), Symbol.iterator)]() {
|
|
745
|
+
return __classPrivateFieldGet(this, _HTMLFormControlsCollection_elements, "f")[Symbol.iterator]();
|
|
746
|
+
}
|
|
747
|
+
item(i) {
|
|
748
|
+
return this[i] == null ? null : this[i];
|
|
749
|
+
}
|
|
750
|
+
namedItem(name) {
|
|
751
|
+
return this[name] == null ? null : this[name];
|
|
752
|
+
}
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
/**
|
|
756
|
+
* Patch the HTMLElement prototype
|
|
757
|
+
*
|
|
758
|
+
* This function patches checkValidity, reportValidity and elements
|
|
759
|
+
*/
|
|
760
|
+
function patchFormPrototype() {
|
|
761
|
+
const checkValidity = HTMLFormElement.prototype.checkValidity;
|
|
762
|
+
HTMLFormElement.prototype.checkValidity = checkValidityOverride;
|
|
763
|
+
const reportValidity = HTMLFormElement.prototype.reportValidity;
|
|
764
|
+
HTMLFormElement.prototype.reportValidity = reportValidityOverride;
|
|
765
|
+
function checkValidityOverride(...args) {
|
|
766
|
+
let returnValue = checkValidity.apply(this, args);
|
|
767
|
+
return overrideFormMethod(this, returnValue, 'checkValidity');
|
|
768
|
+
}
|
|
769
|
+
function reportValidityOverride(...args) {
|
|
770
|
+
let returnValue = reportValidity.apply(this, args);
|
|
771
|
+
return overrideFormMethod(this, returnValue, 'reportValidity');
|
|
772
|
+
}
|
|
773
|
+
const { get } = Object.getOwnPropertyDescriptor(HTMLFormElement.prototype, 'elements');
|
|
774
|
+
Object.defineProperty(HTMLFormElement.prototype, 'elements', {
|
|
775
|
+
get(...args) {
|
|
776
|
+
const elements = get.call(this, ...args);
|
|
777
|
+
const polyfilledElements = Array.from(formElementsMap.get(this) || []);
|
|
778
|
+
// If there are no polyfilled elements, return the native elements collection
|
|
779
|
+
if (polyfilledElements.length === 0) {
|
|
780
|
+
return elements;
|
|
781
|
+
}
|
|
782
|
+
// Merge the native elements with the polyfilled elements
|
|
783
|
+
// and order them by their position in the DOM
|
|
784
|
+
const orderedElements = Array.from(elements).concat(polyfilledElements).sort((a, b) => {
|
|
785
|
+
if (a.compareDocumentPosition) {
|
|
786
|
+
return a.compareDocumentPosition(b) & 2 ? 1 : -1;
|
|
787
|
+
}
|
|
788
|
+
return 0;
|
|
789
|
+
});
|
|
790
|
+
return new HTMLFormControlsCollection(orderedElements);
|
|
791
|
+
},
|
|
792
|
+
});
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
class ElementInternals {
|
|
796
|
+
static get isPolyfilled() {
|
|
797
|
+
return true;
|
|
798
|
+
}
|
|
799
|
+
constructor(ref) {
|
|
800
|
+
if (!ref || !ref.tagName || ref.tagName.indexOf("-") === -1) {
|
|
801
|
+
throw new TypeError("Illegal constructor");
|
|
802
|
+
}
|
|
803
|
+
const rootNode = ref.getRootNode();
|
|
804
|
+
const validity = new ValidityState();
|
|
805
|
+
this.states = new CustomStateSet(ref);
|
|
806
|
+
refMap.set(this, ref);
|
|
807
|
+
validityMap.set(this, validity);
|
|
808
|
+
internalsMap.set(ref, this);
|
|
809
|
+
initAom(ref, this);
|
|
810
|
+
initRef(ref, this);
|
|
811
|
+
Object.seal(this);
|
|
812
|
+
/**
|
|
813
|
+
* If appended from a DocumentFragment, wait until it is connected
|
|
814
|
+
* before attempting to upgrade the internals instance
|
|
815
|
+
*/
|
|
816
|
+
if (rootNode instanceof DocumentFragment) {
|
|
817
|
+
deferUpgrade(rootNode);
|
|
818
|
+
}
|
|
819
|
+
}
|
|
820
|
+
/**
|
|
821
|
+
* Will return true if the element is in a valid state
|
|
822
|
+
*/
|
|
823
|
+
checkValidity() {
|
|
824
|
+
const ref = refMap.get(this);
|
|
825
|
+
throwIfNotFormAssociated(ref, `Failed to execute 'checkValidity' on 'ElementInternals': The target element is not a form-associated custom element.`);
|
|
826
|
+
/** If the element will not validate, it is necessarily valid by default */
|
|
827
|
+
if (!this.willValidate) {
|
|
828
|
+
return true;
|
|
829
|
+
}
|
|
830
|
+
const validity = validityMap.get(this);
|
|
831
|
+
if (!validity.valid) {
|
|
832
|
+
const validityEvent = new Event("invalid", {
|
|
833
|
+
bubbles: false,
|
|
834
|
+
cancelable: true,
|
|
835
|
+
composed: false,
|
|
836
|
+
});
|
|
837
|
+
ref.dispatchEvent(validityEvent);
|
|
838
|
+
}
|
|
839
|
+
return validity.valid;
|
|
840
|
+
}
|
|
841
|
+
/** The form element the custom element is associated with */
|
|
842
|
+
get form() {
|
|
843
|
+
const ref = refMap.get(this);
|
|
844
|
+
throwIfNotFormAssociated(ref, `Failed to read the 'form' property from 'ElementInternals': The target element is not a form-associated custom element.`);
|
|
845
|
+
let form;
|
|
846
|
+
if (ref.constructor["formAssociated"] === true) {
|
|
847
|
+
form = findParentForm(ref);
|
|
848
|
+
}
|
|
849
|
+
return form;
|
|
850
|
+
}
|
|
851
|
+
/** A list of all relative form labels for this element */
|
|
852
|
+
get labels() {
|
|
853
|
+
const ref = refMap.get(this);
|
|
854
|
+
throwIfNotFormAssociated(ref, `Failed to read the 'labels' property from 'ElementInternals': The target element is not a form-associated custom element.`);
|
|
855
|
+
const id = ref.getAttribute("id");
|
|
856
|
+
const hostRoot = ref.getRootNode();
|
|
857
|
+
if (hostRoot && id) {
|
|
858
|
+
return hostRoot.querySelectorAll(`[for="${id}"]`);
|
|
859
|
+
}
|
|
860
|
+
return [];
|
|
861
|
+
}
|
|
862
|
+
/** Will report the elements validity state */
|
|
863
|
+
reportValidity() {
|
|
864
|
+
const ref = refMap.get(this);
|
|
865
|
+
throwIfNotFormAssociated(ref, `Failed to execute 'reportValidity' on 'ElementInternals': The target element is not a form-associated custom element.`);
|
|
866
|
+
/** If the element will not validate, it is valid by default */
|
|
867
|
+
if (!this.willValidate) {
|
|
868
|
+
return true;
|
|
869
|
+
}
|
|
870
|
+
const valid = this.checkValidity();
|
|
871
|
+
const anchor = validationAnchorMap.get(this);
|
|
872
|
+
if (anchor && !ref.constructor["formAssociated"]) {
|
|
873
|
+
throw new DOMException(`Failed to execute 'reportValidity' on 'ElementInternals': The target element is not a form-associated custom element.`);
|
|
874
|
+
}
|
|
875
|
+
if (!valid && anchor) {
|
|
876
|
+
ref.focus();
|
|
877
|
+
anchor.focus();
|
|
878
|
+
}
|
|
879
|
+
return valid;
|
|
880
|
+
}
|
|
881
|
+
/** Sets the element's value within the form */
|
|
882
|
+
setFormValue(value) {
|
|
883
|
+
const ref = refMap.get(this);
|
|
884
|
+
throwIfNotFormAssociated(ref, `Failed to execute 'setFormValue' on 'ElementInternals': The target element is not a form-associated custom element.`);
|
|
885
|
+
removeHiddenInputs(this);
|
|
886
|
+
if (value != null && !(value instanceof FormData)) {
|
|
887
|
+
if (ref.getAttribute("name")) {
|
|
888
|
+
const hiddenInput = createHiddenInput(ref, this);
|
|
889
|
+
hiddenInput.value = value;
|
|
890
|
+
}
|
|
891
|
+
}
|
|
892
|
+
else if (value != null && value instanceof FormData) {
|
|
893
|
+
Array.from(value)
|
|
894
|
+
.reverse()
|
|
895
|
+
.forEach(([formDataKey, formDataValue]) => {
|
|
896
|
+
if (typeof formDataValue === "string") {
|
|
897
|
+
const hiddenInput = createHiddenInput(ref, this);
|
|
898
|
+
hiddenInput.name = formDataKey;
|
|
899
|
+
hiddenInput.value = formDataValue;
|
|
900
|
+
}
|
|
901
|
+
});
|
|
902
|
+
}
|
|
903
|
+
refValueMap.set(ref, value);
|
|
904
|
+
}
|
|
905
|
+
/**
|
|
906
|
+
* Sets the element's validity. The first argument is a partial ValidityState object
|
|
907
|
+
* reflecting the changes to be made to the element's validity. If the element is invalid,
|
|
908
|
+
* the second argument sets the element's validation message.
|
|
909
|
+
*
|
|
910
|
+
* If the field is valid and a message is specified, the method will throw a TypeError.
|
|
911
|
+
*/
|
|
912
|
+
setValidity(validityChanges, validationMessage, anchor) {
|
|
913
|
+
const ref = refMap.get(this);
|
|
914
|
+
throwIfNotFormAssociated(ref, `Failed to execute 'setValidity' on 'ElementInternals': The target element is not a form-associated custom element.`);
|
|
915
|
+
if (!validityChanges) {
|
|
916
|
+
throw new TypeError("Failed to execute 'setValidity' on 'ElementInternals': 1 argument required, but only 0 present.");
|
|
917
|
+
}
|
|
918
|
+
validationAnchorMap.set(this, anchor);
|
|
919
|
+
const validity = validityMap.get(this);
|
|
920
|
+
const validityChangesObj = {};
|
|
921
|
+
for (const key in validityChanges) {
|
|
922
|
+
validityChangesObj[key] = validityChanges[key];
|
|
923
|
+
}
|
|
924
|
+
if (Object.keys(validityChangesObj).length === 0) {
|
|
925
|
+
setValid(validity);
|
|
926
|
+
}
|
|
927
|
+
const check = { ...validity, ...validityChangesObj };
|
|
928
|
+
delete check.valid;
|
|
929
|
+
const { valid } = reconcileValidity(validity, check, this.form);
|
|
930
|
+
if (!valid && !validationMessage) {
|
|
931
|
+
throw new DOMException(`Failed to execute 'setValidity' on 'ElementInternals': The second argument should not be empty if one or more flags in the first argument are true.`);
|
|
932
|
+
}
|
|
933
|
+
validationMessageMap.set(this, valid ? "" : validationMessage);
|
|
934
|
+
// check to make sure the host element is connected before adding attributes
|
|
935
|
+
// because safari doesnt allow elements to have attributes added in the constructor
|
|
936
|
+
if (ref.isConnected) {
|
|
937
|
+
ref.toggleAttribute("internals-invalid", !valid);
|
|
938
|
+
ref.toggleAttribute("internals-valid", valid);
|
|
939
|
+
setAttribute(ref, "aria-invalid", `${!valid}`);
|
|
940
|
+
}
|
|
941
|
+
else {
|
|
942
|
+
validityUpgradeMap.set(ref, this);
|
|
943
|
+
}
|
|
944
|
+
}
|
|
945
|
+
get shadowRoot() {
|
|
946
|
+
const ref = refMap.get(this);
|
|
947
|
+
const shadowRoot = shadowRootMap.get(ref);
|
|
948
|
+
if (shadowRoot) {
|
|
949
|
+
return shadowRoot;
|
|
950
|
+
}
|
|
951
|
+
return null;
|
|
952
|
+
}
|
|
953
|
+
/** The element's validation message set during a call to ElementInternals.setValidity */
|
|
954
|
+
get validationMessage() {
|
|
955
|
+
const ref = refMap.get(this);
|
|
956
|
+
throwIfNotFormAssociated(ref, `Failed to read the 'validationMessage' property from 'ElementInternals': The target element is not a form-associated custom element.`);
|
|
957
|
+
return validationMessageMap.get(this);
|
|
958
|
+
}
|
|
959
|
+
/** The current validity state of the object */
|
|
960
|
+
get validity() {
|
|
961
|
+
const ref = refMap.get(this);
|
|
962
|
+
throwIfNotFormAssociated(ref, `Failed to read the 'validity' property from 'ElementInternals': The target element is not a form-associated custom element.`);
|
|
963
|
+
const validity = validityMap.get(this);
|
|
964
|
+
return validity;
|
|
965
|
+
}
|
|
966
|
+
/** If true the element will participate in a form's constraint validation. */
|
|
967
|
+
get willValidate() {
|
|
968
|
+
const ref = refMap.get(this);
|
|
969
|
+
throwIfNotFormAssociated(ref, `Failed to read the 'willValidate' property from 'ElementInternals': The target element is not a form-associated custom element.`);
|
|
970
|
+
if (ref.matches(":disabled") ||
|
|
971
|
+
ref["disabled"] ||
|
|
972
|
+
ref.hasAttribute("disabled") ||
|
|
973
|
+
ref.hasAttribute("readonly")) {
|
|
974
|
+
return false;
|
|
975
|
+
}
|
|
976
|
+
return true;
|
|
977
|
+
}
|
|
978
|
+
}
|
|
979
|
+
function isElementInternalsSupported() {
|
|
980
|
+
if (typeof window === "undefined" ||
|
|
981
|
+
!window.ElementInternals ||
|
|
982
|
+
!HTMLElement.prototype.attachInternals) {
|
|
983
|
+
return false;
|
|
984
|
+
}
|
|
985
|
+
class ElementInternalsFeatureDetection extends HTMLElement {
|
|
986
|
+
constructor() {
|
|
987
|
+
super();
|
|
988
|
+
this.internals = this.attachInternals();
|
|
989
|
+
}
|
|
990
|
+
}
|
|
991
|
+
const randomName = `element-internals-feature-detection-${Math.random()
|
|
992
|
+
.toString(36)
|
|
993
|
+
.replace(/[^a-z]+/g, "")}`;
|
|
994
|
+
customElements.define(randomName, ElementInternalsFeatureDetection);
|
|
995
|
+
const featureDetectionElement = new ElementInternalsFeatureDetection();
|
|
996
|
+
return [
|
|
997
|
+
"shadowRoot",
|
|
998
|
+
"form",
|
|
999
|
+
"willValidate",
|
|
1000
|
+
"validity",
|
|
1001
|
+
"validationMessage",
|
|
1002
|
+
"labels",
|
|
1003
|
+
"setFormValue",
|
|
1004
|
+
"setValidity",
|
|
1005
|
+
"checkValidity",
|
|
1006
|
+
"reportValidity",
|
|
1007
|
+
].every((prop) => prop in featureDetectionElement.internals);
|
|
1008
|
+
}
|
|
1009
|
+
let hasElementInternalsPolyfillBeenApplied = false;
|
|
1010
|
+
let hasCustomStateSetPolyfillBeenApplied = false;
|
|
1011
|
+
/**
|
|
1012
|
+
* Forcibly applies the polyfill for CustomStateSet.
|
|
1013
|
+
*
|
|
1014
|
+
* https://developer.mozilla.org/en-US/docs/Web/API/CustomStateSet
|
|
1015
|
+
*/
|
|
1016
|
+
function forceCustomStateSetPolyfill(attachInternals) {
|
|
1017
|
+
if (hasCustomStateSetPolyfillBeenApplied) {
|
|
1018
|
+
return;
|
|
1019
|
+
}
|
|
1020
|
+
hasCustomStateSetPolyfillBeenApplied = true;
|
|
1021
|
+
/** @ts-expect-error These types won't match because this is a polyfill */
|
|
1022
|
+
window.CustomStateSet = CustomStateSet;
|
|
1023
|
+
if (attachInternals) {
|
|
1024
|
+
HTMLElement.prototype.attachInternals = function (...args) {
|
|
1025
|
+
const internals = attachInternals.call(this, args);
|
|
1026
|
+
internals.states = new CustomStateSet(this);
|
|
1027
|
+
return internals;
|
|
1028
|
+
};
|
|
1029
|
+
}
|
|
1030
|
+
}
|
|
1031
|
+
/**
|
|
1032
|
+
* Forcibly applies the polyfill for ElementInternals. Useful for situations
|
|
1033
|
+
* like Chrome extensions where Chrome supports ElementInternals, but the
|
|
1034
|
+
* CustomElements polyfill is required.
|
|
1035
|
+
*
|
|
1036
|
+
* https://developer.mozilla.org/en-US/docs/Web/API/ElementInternals
|
|
1037
|
+
*
|
|
1038
|
+
* @param forceCustomStateSet Optional: when true, forces the
|
|
1039
|
+
* [CustomStateSet](https://developer.mozilla.org/en-US/docs/Web/API/CustomStateSet)
|
|
1040
|
+
* polyfill as well.
|
|
1041
|
+
*/
|
|
1042
|
+
function forceElementInternalsPolyfill(forceCustomStateSet = true) {
|
|
1043
|
+
/**
|
|
1044
|
+
* This is a flag to prevent a DOMException from being thrown when
|
|
1045
|
+
* attachInternals is called in upgradeInternals.
|
|
1046
|
+
*/
|
|
1047
|
+
let attachedFlag = false;
|
|
1048
|
+
if (hasElementInternalsPolyfillBeenApplied) {
|
|
1049
|
+
return;
|
|
1050
|
+
}
|
|
1051
|
+
hasElementInternalsPolyfillBeenApplied = true;
|
|
1052
|
+
if (typeof window !== "undefined") {
|
|
1053
|
+
/** @ts-expect-error: we need to replace the default ElementInternals */
|
|
1054
|
+
window.ElementInternals = ElementInternals;
|
|
1055
|
+
}
|
|
1056
|
+
if (typeof CustomElementRegistry !== "undefined") {
|
|
1057
|
+
const define = CustomElementRegistry.prototype.define;
|
|
1058
|
+
CustomElementRegistry.prototype.define = function (name, constructor, options) {
|
|
1059
|
+
if (constructor.formAssociated) {
|
|
1060
|
+
const connectedCallback = constructor.prototype.connectedCallback;
|
|
1061
|
+
constructor.prototype.connectedCallback = function () {
|
|
1062
|
+
if (!connectedCallbackMap.has(this)) {
|
|
1063
|
+
connectedCallbackMap.set(this, true);
|
|
1064
|
+
if (this.hasAttribute("disabled")) {
|
|
1065
|
+
setDisabled(this, true);
|
|
1066
|
+
}
|
|
1067
|
+
}
|
|
1068
|
+
if (connectedCallback != null) {
|
|
1069
|
+
connectedCallback.apply(this);
|
|
1070
|
+
}
|
|
1071
|
+
// always upgradeInternals in connectedCallback instead of constructor
|
|
1072
|
+
attachedFlag = upgradeInternals(this);
|
|
1073
|
+
};
|
|
1074
|
+
}
|
|
1075
|
+
define.call(this, name, constructor, options);
|
|
1076
|
+
};
|
|
1077
|
+
}
|
|
1078
|
+
/**
|
|
1079
|
+
* Attaches an ElementInternals instance to a custom element. Calling this method
|
|
1080
|
+
* on a built-in element will throw an error.
|
|
1081
|
+
*/
|
|
1082
|
+
if (typeof HTMLElement !== "undefined") {
|
|
1083
|
+
HTMLElement.prototype.attachInternals = function () {
|
|
1084
|
+
if (!this.tagName) {
|
|
1085
|
+
/** This happens in the LitSSR environment. Here we can generally ignore internals for now */
|
|
1086
|
+
return {};
|
|
1087
|
+
}
|
|
1088
|
+
else if (this.tagName.indexOf("-") === -1) {
|
|
1089
|
+
throw new Error(`Failed to execute 'attachInternals' on 'HTMLElement': Unable to attach ElementInternals to non-custom elements.`);
|
|
1090
|
+
}
|
|
1091
|
+
if (internalsMap.has(this) && !attachedFlag) {
|
|
1092
|
+
throw new DOMException(`DOMException: Failed to execute 'attachInternals' on 'HTMLElement': ElementInternals for the specified element was already attached.`);
|
|
1093
|
+
}
|
|
1094
|
+
return new ElementInternals(this);
|
|
1095
|
+
};
|
|
1096
|
+
}
|
|
1097
|
+
if (typeof Element !== "undefined") {
|
|
1098
|
+
function attachShadowObserver(...args) {
|
|
1099
|
+
const shadowRoot = attachShadow.apply(this, args);
|
|
1100
|
+
shadowRootMap.set(this, shadowRoot);
|
|
1101
|
+
if (mutationObserverExists()) {
|
|
1102
|
+
const observer = new MutationObserver(observerCallback);
|
|
1103
|
+
if (window.ShadyDOM) {
|
|
1104
|
+
observer.observe(this, observerConfig);
|
|
1105
|
+
}
|
|
1106
|
+
else {
|
|
1107
|
+
observer.observe(shadowRoot, observerConfig);
|
|
1108
|
+
}
|
|
1109
|
+
shadowHostsMap.set(this, observer);
|
|
1110
|
+
}
|
|
1111
|
+
return shadowRoot;
|
|
1112
|
+
}
|
|
1113
|
+
const attachShadow = Element.prototype.attachShadow;
|
|
1114
|
+
Element.prototype.attachShadow = attachShadowObserver;
|
|
1115
|
+
}
|
|
1116
|
+
if (mutationObserverExists() && typeof document !== "undefined") {
|
|
1117
|
+
const documentObserver = new MutationObserver(observerCallback);
|
|
1118
|
+
documentObserver.observe(document.documentElement, observerConfig);
|
|
1119
|
+
}
|
|
1120
|
+
/**
|
|
1121
|
+
* Keeps the polyfill from throwing in environments where HTMLFormElement
|
|
1122
|
+
* is undefined like in a server environment
|
|
1123
|
+
*/
|
|
1124
|
+
if (typeof HTMLFormElement !== "undefined") {
|
|
1125
|
+
patchFormPrototype();
|
|
1126
|
+
}
|
|
1127
|
+
if (forceCustomStateSet ||
|
|
1128
|
+
(typeof window !== "undefined" && !window.CustomStateSet)) {
|
|
1129
|
+
forceCustomStateSetPolyfill();
|
|
1130
|
+
}
|
|
1131
|
+
}
|
|
1132
|
+
|
|
1133
|
+
// Deteermine whether the webcomponents polyfill has been applied.
|
|
1134
|
+
const isCePolyfill = !!customElements.polyfillWrapFlushCallback;
|
|
1135
|
+
// custom elements polyfill is on. Do not auto-apply. User should determine
|
|
1136
|
+
// whether to force or not.
|
|
1137
|
+
if (!isCePolyfill) {
|
|
1138
|
+
if (!isElementInternalsSupported()) {
|
|
1139
|
+
forceElementInternalsPolyfill(false);
|
|
1140
|
+
}
|
|
1141
|
+
else if (typeof window !== "undefined" && !window.CustomStateSet) {
|
|
1142
|
+
forceCustomStateSetPolyfill(HTMLElement.prototype.attachInternals);
|
|
1143
|
+
}
|
|
1144
|
+
}
|
|
1145
|
+
|
|
1146
|
+
/* Polyfill para suporte a Safari -16.5 */
|
|
7
1147
|
function CuraInit(options, w = window) {
|
|
8
1148
|
w.CuraInit = options;
|
|
9
1149
|
}
|