2024-10-17 21:14:54 +00:00
|
|
|
/**
|
|
|
|
* Class decorator to register components easily
|
|
|
|
* It's a wrapper around window.customElements.define
|
|
|
|
* What's nice about it is that you don't separate the component registration
|
|
|
|
* and the class definition
|
|
|
|
**/
|
|
|
|
export function registerComponent(name: string, options?: ElementDefinitionOptions) {
|
|
|
|
return (component: CustomElementConstructor) => {
|
|
|
|
window.customElements.define(name, component, options);
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2024-10-16 11:33:02 +00:00
|
|
|
/**
|
|
|
|
* Safari doesn't support inheriting from HTML tags on web components
|
|
|
|
* The technique is to:
|
|
|
|
* create a new web component
|
|
|
|
* create the desired type inside
|
|
|
|
* pass all attributes to the child component
|
2024-10-16 12:59:02 +00:00
|
|
|
* store is at as `node` inside the parent
|
2024-10-16 11:33:02 +00:00
|
|
|
*
|
2024-10-17 21:14:54 +00:00
|
|
|
* Since we can't use the generic type to instantiate the node, we create a generator function
|
|
|
|
*
|
|
|
|
* ```js
|
|
|
|
* class MyClass extends inheritHtmlElement("select") {
|
|
|
|
* // do whatever
|
|
|
|
* }
|
|
|
|
* ```
|
2024-10-16 11:33:02 +00:00
|
|
|
**/
|
2024-10-17 21:14:54 +00:00
|
|
|
export function inheritHtmlElement<K extends keyof HTMLElementTagNameMap>(tagName: K) {
|
|
|
|
return class Inherited extends HTMLElement {
|
|
|
|
protected node: HTMLElementTagNameMap[K];
|
2024-10-16 11:33:02 +00:00
|
|
|
|
2024-10-19 15:54:34 +00:00
|
|
|
connectedCallback(autoAddNode?: boolean) {
|
2024-10-17 21:14:54 +00:00
|
|
|
this.node = document.createElement(tagName);
|
|
|
|
const attributes: Attr[] = []; // We need to make a copy to delete while iterating
|
|
|
|
for (const attr of this.attributes) {
|
|
|
|
if (attr.name in this.node) {
|
|
|
|
attributes.push(attr);
|
|
|
|
}
|
2024-10-16 12:59:02 +00:00
|
|
|
}
|
2024-10-16 11:33:02 +00:00
|
|
|
|
2024-10-17 21:14:54 +00:00
|
|
|
for (const attr of attributes) {
|
|
|
|
this.removeAttributeNode(attr);
|
|
|
|
this.node.setAttributeNode(attr);
|
|
|
|
}
|
2024-10-20 16:29:48 +00:00
|
|
|
|
|
|
|
this.node.innerHTML = this.innerHTML;
|
|
|
|
this.innerHTML = "";
|
|
|
|
|
|
|
|
// Automatically add node to DOM if autoAddNode is true or unspecified
|
2024-10-19 15:54:34 +00:00
|
|
|
if (autoAddNode === undefined || autoAddNode) {
|
|
|
|
this.appendChild(this.node);
|
|
|
|
}
|
2024-10-16 11:33:02 +00:00
|
|
|
}
|
2024-10-17 21:14:54 +00:00
|
|
|
};
|
2024-10-16 11:33:02 +00:00
|
|
|
}
|