From 677ff51ea58f956a563a19fc671bca14ee038c80 Mon Sep 17 00:00:00 2001 From: Sli Date: Wed, 16 Oct 2024 13:33:02 +0200 Subject: [PATCH] Create web component util --- core/static/webpack/easymde-index.ts | 18 ++---------- core/static/webpack/utils/web-components.ts | 31 +++++++++++++++++++++ 2 files changed, 34 insertions(+), 15 deletions(-) create mode 100644 core/static/webpack/utils/web-components.ts diff --git a/core/static/webpack/easymde-index.ts b/core/static/webpack/easymde-index.ts index 81bdf71d..664d4291 100644 --- a/core/static/webpack/easymde-index.ts +++ b/core/static/webpack/easymde-index.ts @@ -1,6 +1,7 @@ // biome-ignore lint/correctness/noUndeclaredDependencies: shipped by easymde import "codemirror/lib/codemirror.css"; import "easymde/src/css/easymde.css"; +import { InheritedComponent } from "#core:utils/web-components"; // biome-ignore lint/correctness/noUndeclaredDependencies: Imported by EasyMDE import type CodeMirror from "codemirror"; // biome-ignore lint/style/useNamingConvention: This is how they called their namespace @@ -182,23 +183,10 @@ const loadEasyMde = (textarea: HTMLTextAreaElement) => { } }; -class MarkdownInput extends HTMLElement { - widget: HTMLTextAreaElement; - +class MarkdownInput extends InheritedComponent<"textarea"> { constructor() { - super(); - this.widget = document.createElement("textarea"); + super("textarea"); - const attributes: Attr[] = []; // We need to make a copy to delete while iterating - for (const attr of this.attributes) { - attributes.push(attr); - } - - for (const attr of attributes) { - this.removeAttributeNode(attr); - this.widget.setAttributeNode(attr); - } - this.appendChild(this.widget); window.addEventListener("DOMContentLoaded", () => loadEasyMde(this.widget)); } } diff --git a/core/static/webpack/utils/web-components.ts b/core/static/webpack/utils/web-components.ts new file mode 100644 index 00000000..4d4f41b4 --- /dev/null +++ b/core/static/webpack/utils/web-components.ts @@ -0,0 +1,31 @@ +/** + * 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 + * store is at as a widget inside the parent + * + * To use this, you must use the tag name twice, once for creating the class + * and the second time while calling super to pass it to the constructor + **/ +export class InheritedComponent< + K extends keyof HTMLElementTagNameMap, +> extends HTMLElement { + widget: HTMLElementTagNameMap[K]; + + constructor(tagName: K) { + super(); + this.widget = document.createElement(tagName); + const attributes: Attr[] = []; // We need to make a copy to delete while iterating + for (const attr of this.attributes) { + attributes.push(attr); + } + + for (const attr of attributes) { + this.removeAttributeNode(attr); + this.widget.setAttributeNode(attr); + } + this.appendChild(this.widget); + } +}