Closed SergheiGurgurov closed 4 months ago
Hi @SergheiGurgurov,
sorry for the delay. Life kept me very busy.
Thanks for the PR. I have some thoughts: In your PR, you pass props to the constructor of the custom element, but that's not how custom elements normally work, so you would have to make the props parameter of the constructor optional and then check if it exists, so that you can set all attributes on it. You'd also have to remember the children, so that you can add them within the connectedCallback. All of this needs to be done manually for each custom element.
What do you think about this instead (untested)?
function defineCustomElement<T extends Record<string, any>>(
name: string,
constructor: CustomElementConstructor,
options?: ElementDefinitionOptions
) {
customElements.define(name, constructor, options);
return (props: T) => jsx(name, props);
}
const MyCustomElement = defineCustomElement<{ foo: string }>("my-custom-element", class extends HTMLElement {
// ...
});
const element = <MyCustomElement foo="bar" />;
That way the custom element code is still written in the exact same way as originally intended. You would just have to call defineCusomElement instead of customElements.define.
From a typescript perspective, this works. I just have not tested it yet in runtime.
I've just released a new version with a tested version of the above idea. Take a look at the documentation if you're interested: https://lusito.github.io/tsx-dom/tsx-dom/custom-elements.html
I'm closing this as solved differently. Thanks for the inspiration though :slightly_smiling_face:
TL;DR
i added support for native webcomponents inside tsx-dom, i made sure it passes all tests and linter control.
Description
Hi, i've been using tsx-dom to create some framework-agnostic reusable UI elements. i felt like a more complete support of webcomponents would be great for that task aswell so i added it in.
Behaviour
Before
After
Changes
the changes are really simple, the most important part is in the createElement function (and jsx-runtime counterpart)
Before
only accepts function components if className used as tagName this throws a runtime error
After
i check if the function is a class constructor (new function in utils) and if it is a use the "new" keyword to instantiate the class which create the corrisponding HTMLElement. i use uppercase "Tag" beacuse your linter configuration wants it for constructor functions