thunderous 1.1.1 → 2.0.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/dist/index.cjs +43 -456
- package/dist/index.d.cts +15 -582
- package/dist/index.d.ts +15 -582
- package/dist/index.js +40 -453
- package/package.json +9 -1
package/dist/index.d.cts
CHANGED
@@ -1,587 +1,9 @@
|
|
1
|
-
/**
|
2
|
-
* @license
|
3
|
-
* Copyright (c) 2020 The Polymer Project Authors. All rights reserved.
|
4
|
-
* This code may only be used under the BSD style license found at
|
5
|
-
* http://polymer.github.io/LICENSE.txt
|
6
|
-
* The complete set of authors may be found at
|
7
|
-
* http://polymer.github.io/AUTHORS.txt
|
8
|
-
* The complete set of contributors may be found at
|
9
|
-
* http://polymer.github.io/CONTRIBUTORS.txt
|
10
|
-
* Code distributed by Google as part of the polymer project is also
|
11
|
-
* subject to an additional IP rights grant found at
|
12
|
-
* http://polymer.github.io/PATENTS.txt
|
13
|
-
*/
|
14
|
-
if (typeof window !== 'undefined') {
|
15
|
-
if (!ShadowRoot.prototype.createElement) {
|
16
|
-
const NativeHTMLElement = window.HTMLElement;
|
17
|
-
const nativeDefine = window.customElements.define;
|
18
|
-
const nativeGet = window.customElements.get;
|
19
|
-
const nativeRegistry = window.customElements;
|
20
|
-
|
21
|
-
const definitionForElement = new WeakMap();
|
22
|
-
const pendingRegistryForElement = new WeakMap();
|
23
|
-
const globalDefinitionForConstructor = new WeakMap();
|
24
|
-
// TBD: This part of the spec proposal is unclear:
|
25
|
-
// > Another option for looking up registries is to store an element's
|
26
|
-
// > originating registry with the element. The Chrome DOM team was concerned
|
27
|
-
// > about the small additional memory overhead on all elements. Looking up the
|
28
|
-
// > root avoids this.
|
29
|
-
const scopeForElement = new WeakMap();
|
30
|
-
|
31
|
-
// Constructable CE registry class, which uses the native CE registry to
|
32
|
-
// register stand-in elements that can delegate out to CE classes registered
|
33
|
-
// in scoped registries
|
34
|
-
window.CustomElementRegistry = class {
|
35
|
-
constructor() {
|
36
|
-
this._definitionsByTag = new Map();
|
37
|
-
this._definitionsByClass = new Map();
|
38
|
-
this._whenDefinedPromises = new Map();
|
39
|
-
this._awaitingUpgrade = new Map();
|
40
|
-
}
|
41
|
-
|
42
|
-
define(tagName, elementClass) {
|
43
|
-
tagName = tagName.toLowerCase();
|
44
|
-
if (this._getDefinition(tagName) !== undefined) {
|
45
|
-
throw new DOMException(
|
46
|
-
`Failed to execute 'define' on 'CustomElementRegistry': the name "${tagName}" has already been used with this registry`
|
47
|
-
);
|
48
|
-
}
|
49
|
-
if (this._definitionsByClass.get(elementClass) !== undefined) {
|
50
|
-
throw new DOMException(
|
51
|
-
`Failed to execute 'define' on 'CustomElementRegistry': this constructor has already been used with this registry`
|
52
|
-
);
|
53
|
-
}
|
54
|
-
// Since observedAttributes can't change, we approximate it by patching
|
55
|
-
// set/remove/toggleAttribute on the user's class
|
56
|
-
const attributeChangedCallback =
|
57
|
-
elementClass.prototype.attributeChangedCallback;
|
58
|
-
const observedAttributes = new Set(elementClass.observedAttributes || []);
|
59
|
-
patchAttributes(
|
60
|
-
elementClass,
|
61
|
-
observedAttributes,
|
62
|
-
attributeChangedCallback
|
63
|
-
);
|
64
|
-
// Register the definition
|
65
|
-
const definition = {
|
66
|
-
elementClass,
|
67
|
-
connectedCallback: elementClass.prototype.connectedCallback,
|
68
|
-
disconnectedCallback: elementClass.prototype.disconnectedCallback,
|
69
|
-
adoptedCallback: elementClass.prototype.adoptedCallback,
|
70
|
-
attributeChangedCallback,
|
71
|
-
'formAssociated': elementClass['formAssociated'],
|
72
|
-
'formAssociatedCallback':
|
73
|
-
elementClass.prototype['formAssociatedCallback'],
|
74
|
-
'formDisabledCallback': elementClass.prototype['formDisabledCallback'],
|
75
|
-
'formResetCallback': elementClass.prototype['formResetCallback'],
|
76
|
-
'formStateRestoreCallback':
|
77
|
-
elementClass.prototype['formStateRestoreCallback'],
|
78
|
-
observedAttributes,
|
79
|
-
};
|
80
|
-
this._definitionsByTag.set(tagName, definition);
|
81
|
-
this._definitionsByClass.set(elementClass, definition);
|
82
|
-
// Register a stand-in class which will handle the registry lookup & delegation
|
83
|
-
let standInClass = nativeGet.call(nativeRegistry, tagName);
|
84
|
-
if (!standInClass) {
|
85
|
-
standInClass = createStandInElement(tagName);
|
86
|
-
nativeDefine.call(nativeRegistry, tagName, standInClass);
|
87
|
-
}
|
88
|
-
if (this === window.customElements) {
|
89
|
-
globalDefinitionForConstructor.set(elementClass, definition);
|
90
|
-
definition.standInClass = standInClass;
|
91
|
-
}
|
92
|
-
// Upgrade any elements created in this scope before define was called
|
93
|
-
const awaiting = this._awaitingUpgrade.get(tagName);
|
94
|
-
if (awaiting) {
|
95
|
-
this._awaitingUpgrade.delete(tagName);
|
96
|
-
for (const element of awaiting) {
|
97
|
-
pendingRegistryForElement.delete(element);
|
98
|
-
customize(element, definition, true);
|
99
|
-
}
|
100
|
-
}
|
101
|
-
// Flush whenDefined callbacks
|
102
|
-
const info = this._whenDefinedPromises.get(tagName);
|
103
|
-
if (info !== undefined) {
|
104
|
-
info.resolve(elementClass);
|
105
|
-
this._whenDefinedPromises.delete(tagName);
|
106
|
-
}
|
107
|
-
return elementClass;
|
108
|
-
}
|
109
|
-
|
110
|
-
upgrade() {
|
111
|
-
creationContext.push(this);
|
112
|
-
nativeRegistry.upgrade.apply(nativeRegistry, arguments);
|
113
|
-
creationContext.pop();
|
114
|
-
}
|
115
|
-
|
116
|
-
get(tagName) {
|
117
|
-
const definition = this._definitionsByTag.get(tagName);
|
118
|
-
return definition?.elementClass;
|
119
|
-
}
|
120
|
-
|
121
|
-
_getDefinition(tagName) {
|
122
|
-
return this._definitionsByTag.get(tagName);
|
123
|
-
}
|
124
|
-
|
125
|
-
whenDefined(tagName) {
|
126
|
-
const definition = this._getDefinition(tagName);
|
127
|
-
if (definition !== undefined) {
|
128
|
-
return Promise.resolve(definition.elementClass);
|
129
|
-
}
|
130
|
-
let info = this._whenDefinedPromises.get(tagName);
|
131
|
-
if (info === undefined) {
|
132
|
-
info = {};
|
133
|
-
info.promise = new Promise((r) => (info.resolve = r));
|
134
|
-
this._whenDefinedPromises.set(tagName, info);
|
135
|
-
}
|
136
|
-
return info.promise;
|
137
|
-
}
|
138
|
-
|
139
|
-
_upgradeWhenDefined(element, tagName, shouldUpgrade) {
|
140
|
-
let awaiting = this._awaitingUpgrade.get(tagName);
|
141
|
-
if (!awaiting) {
|
142
|
-
this._awaitingUpgrade.set(tagName, (awaiting = new Set()));
|
143
|
-
}
|
144
|
-
if (shouldUpgrade) {
|
145
|
-
awaiting.add(element);
|
146
|
-
} else {
|
147
|
-
awaiting.delete(element);
|
148
|
-
}
|
149
|
-
}
|
150
|
-
};
|
151
|
-
|
152
|
-
// User extends this HTMLElement, which returns the CE being upgraded
|
153
|
-
let upgradingInstance;
|
154
|
-
window.HTMLElement = function HTMLElement() {
|
155
|
-
// Upgrading case: the StandInElement constructor was run by the browser's
|
156
|
-
// native custom elements and we're in the process of running the
|
157
|
-
// "constructor-call trick" on the natively constructed instance, so just
|
158
|
-
// return that here
|
159
|
-
let instance = upgradingInstance;
|
160
|
-
if (instance) {
|
161
|
-
upgradingInstance = undefined;
|
162
|
-
return instance;
|
163
|
-
}
|
164
|
-
// Construction case: we need to construct the StandInElement and return
|
165
|
-
// it; note the current spec proposal only allows new'ing the constructor
|
166
|
-
// of elements registered with the global registry
|
167
|
-
const definition = globalDefinitionForConstructor.get(this.constructor);
|
168
|
-
if (!definition) {
|
169
|
-
throw new TypeError(
|
170
|
-
'Illegal constructor (custom element class must be registered with global customElements registry to be newable)'
|
171
|
-
);
|
172
|
-
}
|
173
|
-
instance = Reflect.construct(
|
174
|
-
NativeHTMLElement,
|
175
|
-
[],
|
176
|
-
definition.standInClass
|
177
|
-
);
|
178
|
-
Object.setPrototypeOf(instance, this.constructor.prototype);
|
179
|
-
definitionForElement.set(instance, definition);
|
180
|
-
return instance;
|
181
|
-
};
|
182
|
-
window.HTMLElement.prototype = NativeHTMLElement.prototype;
|
183
|
-
|
184
|
-
// Helpers to return the scope for a node where its registry would be located
|
185
|
-
const isValidScope = (node) =>
|
186
|
-
node === document || node instanceof ShadowRoot;
|
187
|
-
const registryForNode = (node) => {
|
188
|
-
// TODO: the algorithm for finding the scope is a bit up in the air; assigning
|
189
|
-
// a one-time scope at creation time would require walking every tree ever
|
190
|
-
// created, which is avoided for now
|
191
|
-
let scope = node.getRootNode();
|
192
|
-
// If we're not attached to the document (i.e. in a disconnected tree or
|
193
|
-
// fragment), we need to get the scope from the creation context; that should
|
194
|
-
// be a Document or ShadowRoot, unless it was created via innerHTML
|
195
|
-
if (!isValidScope(scope)) {
|
196
|
-
const context = creationContext[creationContext.length - 1];
|
197
|
-
// When upgrading via registry.upgrade(), the registry itself is put on the
|
198
|
-
// creationContext stack
|
199
|
-
if (context instanceof CustomElementRegistry) {
|
200
|
-
return context;
|
201
|
-
}
|
202
|
-
// Otherwise, get the root node of the element this was created from
|
203
|
-
scope = context.getRootNode();
|
204
|
-
// The creation context wasn't a Document or ShadowRoot or in one; this
|
205
|
-
// means we're being innerHTML'ed into a disconnected element; for now, we
|
206
|
-
// hope that root node was created imperatively, where we stash _its_
|
207
|
-
// scopeForElement. Beyond that, we'd need more costly tracking.
|
208
|
-
if (!isValidScope(scope)) {
|
209
|
-
scope = scopeForElement.get(scope)?.getRootNode() || document;
|
210
|
-
}
|
211
|
-
}
|
212
|
-
return scope.customElements;
|
213
|
-
};
|
214
|
-
|
215
|
-
// Helper to create stand-in element for each tagName registered that delegates
|
216
|
-
// out to the registry for the given element
|
217
|
-
const createStandInElement = (tagName) => {
|
218
|
-
return class ScopedCustomElementBase {
|
219
|
-
static get ['formAssociated']() {
|
220
|
-
return true;
|
221
|
-
}
|
222
|
-
constructor() {
|
223
|
-
// Create a raw HTMLElement first
|
224
|
-
const instance = Reflect.construct(
|
225
|
-
NativeHTMLElement,
|
226
|
-
[],
|
227
|
-
this.constructor
|
228
|
-
);
|
229
|
-
// We need to install the minimum HTMLElement prototype so that
|
230
|
-
// scopeForNode can use DOM API to determine our construction scope;
|
231
|
-
// upgrade will eventually install the full CE prototype
|
232
|
-
Object.setPrototypeOf(instance, HTMLElement.prototype);
|
233
|
-
// Get the node's scope, and its registry (falls back to global registry)
|
234
|
-
const registry = registryForNode(instance) || window.customElements;
|
235
|
-
const definition = registry._getDefinition(tagName);
|
236
|
-
if (definition) {
|
237
|
-
customize(instance, definition);
|
238
|
-
} else {
|
239
|
-
pendingRegistryForElement.set(instance, registry);
|
240
|
-
}
|
241
|
-
return instance;
|
242
|
-
}
|
243
|
-
|
244
|
-
connectedCallback() {
|
245
|
-
const definition = definitionForElement.get(this);
|
246
|
-
if (definition) {
|
247
|
-
// Delegate out to user callback
|
248
|
-
definition.connectedCallback &&
|
249
|
-
definition.connectedCallback.apply(this, arguments);
|
250
|
-
} else {
|
251
|
-
// Register for upgrade when defined (only when connected, so we don't leak)
|
252
|
-
pendingRegistryForElement
|
253
|
-
.get(this)
|
254
|
-
._upgradeWhenDefined(this, tagName, true);
|
255
|
-
}
|
256
|
-
}
|
257
|
-
|
258
|
-
disconnectedCallback() {
|
259
|
-
const definition = definitionForElement.get(this);
|
260
|
-
if (definition) {
|
261
|
-
// Delegate out to user callback
|
262
|
-
definition.disconnectedCallback &&
|
263
|
-
definition.disconnectedCallback.apply(this, arguments);
|
264
|
-
} else {
|
265
|
-
// Un-register for upgrade when defined (so we don't leak)
|
266
|
-
pendingRegistryForElement
|
267
|
-
.get(this)
|
268
|
-
._upgradeWhenDefined(this, tagName, false);
|
269
|
-
}
|
270
|
-
}
|
271
|
-
|
272
|
-
adoptedCallback() {
|
273
|
-
const definition = definitionForElement.get(this);
|
274
|
-
definition?.adoptedCallback?.apply(this, arguments);
|
275
|
-
}
|
276
|
-
|
277
|
-
// Form-associated custom elements lifecycle methods
|
278
|
-
['formAssociatedCallback']() {
|
279
|
-
const definition = definitionForElement.get(this);
|
280
|
-
if (definition && definition['formAssociated']) {
|
281
|
-
definition?.['formAssociatedCallback']?.apply(this, arguments);
|
282
|
-
}
|
283
|
-
}
|
284
|
-
|
285
|
-
['formDisabledCallback']() {
|
286
|
-
const definition = definitionForElement.get(this);
|
287
|
-
if (definition?.['formAssociated']) {
|
288
|
-
definition?.['formDisabledCallback']?.apply(this, arguments);
|
289
|
-
}
|
290
|
-
}
|
291
|
-
|
292
|
-
['formResetCallback']() {
|
293
|
-
const definition = definitionForElement.get(this);
|
294
|
-
if (definition?.['formAssociated']) {
|
295
|
-
definition?.['formResetCallback']?.apply(this, arguments);
|
296
|
-
}
|
297
|
-
}
|
298
|
-
|
299
|
-
['formStateRestoreCallback']() {
|
300
|
-
const definition = definitionForElement.get(this);
|
301
|
-
if (definition?.['formAssociated']) {
|
302
|
-
definition?.['formStateRestoreCallback']?.apply(this, arguments);
|
303
|
-
}
|
304
|
-
}
|
305
|
-
|
306
|
-
// no attributeChangedCallback or observedAttributes since these
|
307
|
-
// are simulated via setAttribute/removeAttribute patches
|
308
|
-
};
|
309
|
-
};
|
310
|
-
|
311
|
-
// Helper to patch CE class setAttribute/getAttribute/toggleAttribute to
|
312
|
-
// implement attributeChangedCallback
|
313
|
-
const patchAttributes = (
|
314
|
-
elementClass,
|
315
|
-
observedAttributes,
|
316
|
-
attributeChangedCallback
|
317
|
-
) => {
|
318
|
-
if (
|
319
|
-
observedAttributes.size === 0 ||
|
320
|
-
attributeChangedCallback === undefined
|
321
|
-
) {
|
322
|
-
return;
|
323
|
-
}
|
324
|
-
const setAttribute = elementClass.prototype.setAttribute;
|
325
|
-
if (setAttribute) {
|
326
|
-
elementClass.prototype.setAttribute = function (n, value) {
|
327
|
-
const name = n.toLowerCase();
|
328
|
-
if (observedAttributes.has(name)) {
|
329
|
-
const old = this.getAttribute(name);
|
330
|
-
setAttribute.call(this, name, value);
|
331
|
-
attributeChangedCallback.call(this, name, old, value);
|
332
|
-
} else {
|
333
|
-
setAttribute.call(this, name, value);
|
334
|
-
}
|
335
|
-
};
|
336
|
-
}
|
337
|
-
const removeAttribute = elementClass.prototype.removeAttribute;
|
338
|
-
if (removeAttribute) {
|
339
|
-
elementClass.prototype.removeAttribute = function (n) {
|
340
|
-
const name = n.toLowerCase();
|
341
|
-
if (observedAttributes.has(name)) {
|
342
|
-
const old = this.getAttribute(name);
|
343
|
-
removeAttribute.call(this, name);
|
344
|
-
attributeChangedCallback.call(this, name, old, null);
|
345
|
-
} else {
|
346
|
-
removeAttribute.call(this, name);
|
347
|
-
}
|
348
|
-
};
|
349
|
-
}
|
350
|
-
const toggleAttribute = elementClass.prototype.toggleAttribute;
|
351
|
-
if (toggleAttribute) {
|
352
|
-
elementClass.prototype.toggleAttribute = function (n, force) {
|
353
|
-
const name = n.toLowerCase();
|
354
|
-
if (observedAttributes.has(name)) {
|
355
|
-
const old = this.getAttribute(name);
|
356
|
-
toggleAttribute.call(this, name, force);
|
357
|
-
const newValue = this.getAttribute(name);
|
358
|
-
attributeChangedCallback.call(this, name, old, newValue);
|
359
|
-
} else {
|
360
|
-
toggleAttribute.call(this, name, force);
|
361
|
-
}
|
362
|
-
};
|
363
|
-
}
|
364
|
-
};
|
365
|
-
|
366
|
-
// Helper to patch CE class hierarchy changing those CE classes created before applying the polyfill
|
367
|
-
// to make them work with the new patched CustomElementsRegistry
|
368
|
-
const patchHTMLElement = (elementClass) => {
|
369
|
-
const parentClass = Object.getPrototypeOf(elementClass);
|
370
|
-
|
371
|
-
if (parentClass !== window.HTMLElement) {
|
372
|
-
if (parentClass === NativeHTMLElement) {
|
373
|
-
return Object.setPrototypeOf(elementClass, window.HTMLElement);
|
374
|
-
}
|
375
|
-
|
376
|
-
return patchHTMLElement(parentClass);
|
377
|
-
}
|
378
|
-
};
|
379
|
-
|
380
|
-
// Helper to upgrade an instance with a CE definition using "constructor call trick"
|
381
|
-
const customize = (instance, definition, isUpgrade = false) => {
|
382
|
-
Object.setPrototypeOf(instance, definition.elementClass.prototype);
|
383
|
-
definitionForElement.set(instance, definition);
|
384
|
-
upgradingInstance = instance;
|
385
|
-
try {
|
386
|
-
new definition.elementClass();
|
387
|
-
} catch (_) {
|
388
|
-
patchHTMLElement(definition.elementClass);
|
389
|
-
new definition.elementClass();
|
390
|
-
}
|
391
|
-
if (definition.attributeChangedCallback) {
|
392
|
-
// Approximate observedAttributes from the user class, since the stand-in element had none
|
393
|
-
definition.observedAttributes.forEach((attr) => {
|
394
|
-
if (instance.hasAttribute(attr)) {
|
395
|
-
definition.attributeChangedCallback.call(
|
396
|
-
instance,
|
397
|
-
attr,
|
398
|
-
null,
|
399
|
-
instance.getAttribute(attr)
|
400
|
-
);
|
401
|
-
}
|
402
|
-
});
|
403
|
-
}
|
404
|
-
if (isUpgrade && definition.connectedCallback && instance.isConnected) {
|
405
|
-
definition.connectedCallback.call(instance);
|
406
|
-
}
|
407
|
-
};
|
408
|
-
|
409
|
-
// Patch attachShadow to set customElements on shadowRoot when provided
|
410
|
-
const nativeAttachShadow = Element.prototype.attachShadow;
|
411
|
-
Element.prototype.attachShadow = function (init) {
|
412
|
-
const shadowRoot = nativeAttachShadow.apply(this, arguments);
|
413
|
-
if (init.customElements) {
|
414
|
-
shadowRoot.customElements = init.customElements;
|
415
|
-
}
|
416
|
-
return shadowRoot;
|
417
|
-
};
|
418
|
-
|
419
|
-
// Install scoped creation API on Element & ShadowRoot
|
420
|
-
let creationContext = [document];
|
421
|
-
const installScopedCreationMethod = (ctor, method, from = undefined) => {
|
422
|
-
const native = (from ? Object.getPrototypeOf(from) : ctor.prototype)[
|
423
|
-
method
|
424
|
-
];
|
425
|
-
ctor.prototype[method] = function () {
|
426
|
-
creationContext.push(this);
|
427
|
-
const ret = native.apply(from || this, arguments);
|
428
|
-
// For disconnected elements, note their creation scope so that e.g.
|
429
|
-
// innerHTML into them will use the correct scope; note that
|
430
|
-
// insertAdjacentHTML doesn't return an element, but that's fine since
|
431
|
-
// it will have a parent that should have a scope
|
432
|
-
if (ret !== undefined) {
|
433
|
-
scopeForElement.set(ret, this);
|
434
|
-
}
|
435
|
-
creationContext.pop();
|
436
|
-
return ret;
|
437
|
-
};
|
438
|
-
};
|
439
|
-
installScopedCreationMethod(ShadowRoot, 'createElement', document);
|
440
|
-
installScopedCreationMethod(ShadowRoot, 'importNode', document);
|
441
|
-
installScopedCreationMethod(Element, 'insertAdjacentHTML');
|
442
|
-
|
443
|
-
// Install scoped innerHTML on Element & ShadowRoot
|
444
|
-
const installScopedCreationSetter = (ctor, name) => {
|
445
|
-
const descriptor = Object.getOwnPropertyDescriptor(ctor.prototype, name);
|
446
|
-
Object.defineProperty(ctor.prototype, name, {
|
447
|
-
...descriptor,
|
448
|
-
set(value) {
|
449
|
-
creationContext.push(this);
|
450
|
-
descriptor.set.call(this, value);
|
451
|
-
creationContext.pop();
|
452
|
-
},
|
453
|
-
});
|
454
|
-
};
|
455
|
-
installScopedCreationSetter(Element, 'innerHTML');
|
456
|
-
installScopedCreationSetter(ShadowRoot, 'innerHTML');
|
457
|
-
|
458
|
-
// Install global registry
|
459
|
-
Object.defineProperty(window, 'customElements', {
|
460
|
-
value: new CustomElementRegistry(),
|
461
|
-
configurable: true,
|
462
|
-
writable: true,
|
463
|
-
});
|
464
|
-
|
465
|
-
if (
|
466
|
-
!!window['ElementInternals'] &&
|
467
|
-
!!window['ElementInternals'].prototype['setFormValue']
|
468
|
-
) {
|
469
|
-
const internalsToHostMap = new WeakMap();
|
470
|
-
const attachInternals = HTMLElement.prototype['attachInternals'];
|
471
|
-
const methods = [
|
472
|
-
'setFormValue',
|
473
|
-
'setValidity',
|
474
|
-
'checkValidity',
|
475
|
-
'reportValidity',
|
476
|
-
];
|
477
|
-
|
478
|
-
HTMLElement.prototype['attachInternals'] = function (...args) {
|
479
|
-
const internals = attachInternals.call(this, ...args);
|
480
|
-
internalsToHostMap.set(internals, this);
|
481
|
-
return internals;
|
482
|
-
};
|
483
|
-
|
484
|
-
methods.forEach((method) => {
|
485
|
-
const proto = window['ElementInternals'].prototype;
|
486
|
-
const originalMethod = proto[method];
|
487
|
-
|
488
|
-
proto[method] = function (...args) {
|
489
|
-
const host = internalsToHostMap.get(this);
|
490
|
-
const definition = definitionForElement.get(host);
|
491
|
-
if (definition['formAssociated'] === true) {
|
492
|
-
return originalMethod?.call(this, ...args);
|
493
|
-
} else {
|
494
|
-
throw new DOMException(
|
495
|
-
`Failed to execute ${originalMethod} on 'ElementInternals': The target element is not a form-associated custom element.`
|
496
|
-
);
|
497
|
-
}
|
498
|
-
};
|
499
|
-
});
|
500
|
-
|
501
|
-
// Emulate the native RadioNodeList object
|
502
|
-
class RadioNodeList extends Array {
|
503
|
-
constructor(elements) {
|
504
|
-
super(...elements);
|
505
|
-
this._elements = elements;
|
506
|
-
}
|
507
|
-
|
508
|
-
get ['value']() {
|
509
|
-
return (
|
510
|
-
this._elements.find((element) => element['checked'] === true)
|
511
|
-
?.value || ''
|
512
|
-
);
|
513
|
-
}
|
514
|
-
}
|
515
|
-
|
516
|
-
// Emulate the native HTMLFormControlsCollection object
|
517
|
-
class HTMLFormControlsCollection {
|
518
|
-
constructor(elements) {
|
519
|
-
const entries = new Map();
|
520
|
-
elements.forEach((element, index) => {
|
521
|
-
const name = element.getAttribute('name');
|
522
|
-
const nameReference = entries.get(name) || [];
|
523
|
-
this[+index] = element;
|
524
|
-
nameReference.push(element);
|
525
|
-
entries.set(name, nameReference);
|
526
|
-
});
|
527
|
-
this['length'] = elements.length;
|
528
|
-
entries.forEach((value, key) => {
|
529
|
-
if (!value) return;
|
530
|
-
if (value.length === 1) {
|
531
|
-
this[key] = value[0];
|
532
|
-
} else {
|
533
|
-
this[key] = new RadioNodeList(value);
|
534
|
-
}
|
535
|
-
});
|
536
|
-
}
|
537
|
-
|
538
|
-
['namedItem'](key) {
|
539
|
-
return this[key];
|
540
|
-
}
|
541
|
-
}
|
542
|
-
|
543
|
-
// Override the built-in HTMLFormElements.prototype.elements getter
|
544
|
-
const formElementsDescriptor = Object.getOwnPropertyDescriptor(
|
545
|
-
HTMLFormElement.prototype,
|
546
|
-
'elements'
|
547
|
-
);
|
548
|
-
|
549
|
-
Object.defineProperty(HTMLFormElement.prototype, 'elements', {
|
550
|
-
get: function () {
|
551
|
-
const nativeElements = formElementsDescriptor.get.call(this, []);
|
552
|
-
|
553
|
-
const include = [];
|
554
|
-
|
555
|
-
for (const element of nativeElements) {
|
556
|
-
const definition = definitionForElement.get(element);
|
557
|
-
|
558
|
-
// Only purposefully formAssociated elements or built-ins will feature in elements
|
559
|
-
if (!definition || definition['formAssociated'] === true) {
|
560
|
-
include.push(element);
|
561
|
-
}
|
562
|
-
}
|
563
|
-
|
564
|
-
return new HTMLFormControlsCollection(include);
|
565
|
-
},
|
566
|
-
});
|
567
|
-
}
|
568
|
-
}
|
569
|
-
class TrackableCustomElementRegistry extends window.CustomElementRegistry {
|
570
|
-
__tagNames = new Set();
|
571
|
-
define(tagName, constructor, options) {
|
572
|
-
super.define(tagName, constructor, options);
|
573
|
-
this.__tagNames.add(tagName);
|
574
|
-
}
|
575
|
-
}
|
576
|
-
window.CustomElementRegistry = TrackableCustomElementRegistry;
|
577
|
-
}
|
578
|
-
|
579
1
|
declare global {
|
580
2
|
interface DocumentFragment {
|
581
3
|
host: HTMLElement;
|
582
4
|
}
|
583
5
|
interface Element {
|
584
|
-
|
6
|
+
__customCallbackFns?: Map<string, AnyFn>;
|
585
7
|
}
|
586
8
|
interface CustomElementRegistry {
|
587
9
|
__tagNames: Set<string>;
|
@@ -617,7 +39,11 @@ type RenderArgs<Props extends CustomElementProps> = {
|
|
617
39
|
formStateRestoreCallback: (fn: () => void) => void;
|
618
40
|
formAssociatedCallback: (fn: () => void) => void;
|
619
41
|
clientOnlyCallback: (fn: () => void) => void;
|
620
|
-
|
42
|
+
getter: <T>(fn: () => T) => SignalGetter<T>;
|
43
|
+
/**
|
44
|
+
* @deprecated You can now pass callback functions directly to templates.
|
45
|
+
*/
|
46
|
+
customCallback: (fn: () => void) => `this.getRootNode().host.__customCallbackFns.get('${string}')(event)` | '';
|
621
47
|
attrSignals: Record<string, Signal<string | null>>;
|
622
48
|
propSignals: {
|
623
49
|
[K in keyof Props]: Signal<Props[K]>;
|
@@ -669,10 +95,17 @@ type RegistryArgs = {
|
|
669
95
|
type Styles = CSSStyleSheet | HTMLStyleElement;
|
670
96
|
|
671
97
|
type SignalOptions = { debugMode: boolean; label?: string };
|
672
|
-
type SignalGetter<T> =
|
98
|
+
type SignalGetter<T> = {
|
99
|
+
(options?: SignalOptions): T;
|
100
|
+
getter: true;
|
101
|
+
};
|
673
102
|
type SignalSetter<T> = (newValue: T, options?: SignalOptions) => void;
|
674
103
|
type Signal<T = unknown> = [SignalGetter<T>, SignalSetter<T>];
|
675
104
|
|
105
|
+
// Flexible typing is necessary to support generic functions
|
106
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
107
|
+
type AnyFn = (...args: any[]) => any;
|
108
|
+
|
676
109
|
/**
|
677
110
|
* Create a custom element that can be defined for use in the DOM.
|
678
111
|
* @example
|
@@ -740,4 +173,4 @@ declare const createEffect: (fn: () => void) => void;
|
|
740
173
|
declare const html: (strings: TemplateStringsArray, ...values: unknown[]) => DocumentFragment;
|
741
174
|
declare const css: (strings: TemplateStringsArray, ...values: unknown[]) => Styles;
|
742
175
|
|
743
|
-
export { type RenderArgs, type RenderFunction, type
|
176
|
+
export { type RenderArgs, type RenderFunction, type Signal, type SignalGetter, type SignalSetter, clientOnlyCallback, createEffect, createRegistry, createSignal, css, customElement, derived, html, insertTemplates, onServerDefine };
|