mirror of
https://github.com/ae-utbm/sith.git
synced 2024-11-22 06:03:20 +00:00
Add register decorator for web components and a better inheriting system for html elements
This commit is contained in:
parent
cac185634d
commit
4165f8d4af
@ -1,16 +1,17 @@
|
|||||||
import "tom-select/dist/css/tom-select.css";
|
import "tom-select/dist/css/tom-select.css";
|
||||||
import { InheritedComponent } from "#core:utils/web-components";
|
import { inheritHtmlElement, registerComponent } from "#core:utils/web-components";
|
||||||
import TomSelect from "tom-select";
|
import TomSelect from "tom-select";
|
||||||
import type { TomItem, TomLoadCallback, TomOption } from "tom-select/dist/types/types";
|
import type { TomItem, TomLoadCallback, TomOption } from "tom-select/dist/types/types";
|
||||||
import type { escape_html } from "tom-select/dist/types/utils";
|
import type { escape_html } from "tom-select/dist/types/utils";
|
||||||
import { type UserProfileSchema, userSearchUsers } from "#openapi";
|
import { type UserProfileSchema, userSearchUsers } from "#openapi";
|
||||||
|
|
||||||
export class AjaxSelect extends InheritedComponent<"select"> {
|
@registerComponent("ajax-select")
|
||||||
widget: TomSelect;
|
export class AjaxSelect extends inheritHtmlElement("select") {
|
||||||
filter?: <T>(items: T[]) => T[];
|
public widget: TomSelect;
|
||||||
|
public filter?: <T>(items: T[]) => T[];
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super("select");
|
super();
|
||||||
|
|
||||||
window.addEventListener("DOMContentLoaded", () => {
|
window.addEventListener("DOMContentLoaded", () => {
|
||||||
this.loadTomSelect();
|
this.loadTomSelect();
|
||||||
@ -90,5 +91,3 @@ export class AjaxSelect extends InheritedComponent<"select"> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
window.customElements.define("ajax-select", AjaxSelect);
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
// biome-ignore lint/correctness/noUndeclaredDependencies: shipped by easymde
|
// biome-ignore lint/correctness/noUndeclaredDependencies: shipped by easymde
|
||||||
import "codemirror/lib/codemirror.css";
|
import "codemirror/lib/codemirror.css";
|
||||||
import "easymde/src/css/easymde.css";
|
import "easymde/src/css/easymde.css";
|
||||||
import { InheritedComponent } from "#core:utils/web-components";
|
import { inheritHtmlElement, registerComponent } from "#core:utils/web-components";
|
||||||
// biome-ignore lint/correctness/noUndeclaredDependencies: Imported by EasyMDE
|
// biome-ignore lint/correctness/noUndeclaredDependencies: Imported by EasyMDE
|
||||||
import type CodeMirror from "codemirror";
|
import type CodeMirror from "codemirror";
|
||||||
// biome-ignore lint/style/useNamingConvention: This is how they called their namespace
|
// biome-ignore lint/style/useNamingConvention: This is how they called their namespace
|
||||||
@ -9,7 +9,7 @@ import EasyMDE from "easymde";
|
|||||||
import { markdownRenderMarkdown } from "#openapi";
|
import { markdownRenderMarkdown } from "#openapi";
|
||||||
|
|
||||||
const loadEasyMde = (textarea: HTMLTextAreaElement) => {
|
const loadEasyMde = (textarea: HTMLTextAreaElement) => {
|
||||||
const easyMde = new EasyMDE({
|
new EasyMDE({
|
||||||
element: textarea,
|
element: textarea,
|
||||||
spellChecker: false,
|
spellChecker: false,
|
||||||
autoDownloadFontAwesome: false,
|
autoDownloadFontAwesome: false,
|
||||||
@ -183,12 +183,10 @@ const loadEasyMde = (textarea: HTMLTextAreaElement) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class MarkdownInput extends InheritedComponent<"textarea"> {
|
@registerComponent("markdown-input")
|
||||||
|
class MarkdownInput extends inheritHtmlElement("textarea") {
|
||||||
constructor() {
|
constructor() {
|
||||||
super("textarea");
|
super();
|
||||||
|
|
||||||
window.addEventListener("DOMContentLoaded", () => loadEasyMde(this.node));
|
window.addEventListener("DOMContentLoaded", () => loadEasyMde(this.node));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
window.customElements.define("markdown-input", MarkdownInput);
|
|
||||||
|
@ -1,3 +1,15 @@
|
|||||||
|
/**
|
||||||
|
* 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);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Safari doesn't support inheriting from HTML tags on web components
|
* Safari doesn't support inheriting from HTML tags on web components
|
||||||
* The technique is to:
|
* The technique is to:
|
||||||
@ -6,28 +18,33 @@
|
|||||||
* pass all attributes to the child component
|
* pass all attributes to the child component
|
||||||
* store is at as `node` inside the parent
|
* store is at as `node` inside the parent
|
||||||
*
|
*
|
||||||
* To use this, you must use the tag name twice, once for creating the class
|
* Since we can't use the generic type to instantiate the node, we create a generator function
|
||||||
* and the second time while calling super to pass it to the constructor
|
*
|
||||||
|
* ```js
|
||||||
|
* class MyClass extends inheritHtmlElement("select") {
|
||||||
|
* // do whatever
|
||||||
|
* }
|
||||||
|
* ```
|
||||||
**/
|
**/
|
||||||
export class InheritedComponent<
|
export function inheritHtmlElement<K extends keyof HTMLElementTagNameMap>(tagName: K) {
|
||||||
K extends keyof HTMLElementTagNameMap,
|
return class Inherited extends HTMLElement {
|
||||||
> extends HTMLElement {
|
protected node: HTMLElementTagNameMap[K];
|
||||||
node: HTMLElementTagNameMap[K];
|
|
||||||
|
|
||||||
constructor(tagName: K) {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
this.node = document.createElement(tagName);
|
this.node = document.createElement(tagName);
|
||||||
const attributes: Attr[] = []; // We need to make a copy to delete while iterating
|
const attributes: Attr[] = []; // We need to make a copy to delete while iterating
|
||||||
for (const attr of this.attributes) {
|
for (const attr of this.attributes) {
|
||||||
if (attr.name in this.node) {
|
if (attr.name in this.node) {
|
||||||
attributes.push(attr);
|
attributes.push(attr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
for (const attr of attributes) {
|
for (const attr of attributes) {
|
||||||
this.removeAttributeNode(attr);
|
this.removeAttributeNode(attr);
|
||||||
this.node.setAttributeNode(attr);
|
this.node.setAttributeNode(attr);
|
||||||
|
}
|
||||||
|
this.appendChild(this.node);
|
||||||
}
|
}
|
||||||
this.appendChild(this.node);
|
};
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
"target": "es6",
|
"target": "es6",
|
||||||
"allowJs": true,
|
"allowJs": true,
|
||||||
"moduleResolution": "node",
|
"moduleResolution": "node",
|
||||||
|
"experimentalDecorators": true,
|
||||||
"allowSyntheticDefaultImports": true,
|
"allowSyntheticDefaultImports": true,
|
||||||
"esModuleInterop": true,
|
"esModuleInterop": true,
|
||||||
"types": ["jquery", "alpinejs"],
|
"types": ["jquery", "alpinejs"],
|
||||||
|
Loading…
Reference in New Issue
Block a user