- From: Claudia Meadows <notifications@github.com>
- Date: Tue, 30 Jul 2024 08:36:15 -0700
- To: WICG/webcomponents <webcomponents@noreply.github.com>
- Cc: Subscribed <subscribed@noreply.github.com>
- Message-ID: <WICG/webcomponents/issues/1064@github.com>
Currently, classes have to manage a bunch of explicit wiring that has to be done almost every time. This could all be simplified a lot, to a module that doesn't need to do nearly as much. ```js <define name="my-counter" attributes="initial"> <template shadowrootmode="open"> <button data-inc="+1">+</button> <span>{{count}}</span> <button data-inc="-1">-</button> </template> <script type="module"> export default function initialize(shadowRoot, signal) { let count = +this.getAttribute("initial") || 0 let changed = false shadowRoot.updateTemplate({count}) shadowRoot.addEventListener("click", (ev) => { const {inc} = ev.target.dataset if (inc !== undefined) { ev.stopPropagation() count += inc changed = true shadowRoot.updateTemplate({count}) this.dispatchEvent(new Event("change")) } }, {signal}) shadowRoot.addEventListener("attributechanged", (event) => { if (!changed) count = +event.newValue || 0 }, {signal}) } </script> </define> ``` The `<define>` element would accept four attributes: - `name`: the tag name - `extends`: the builtin it extends (if applicable) - `attributes`: the observed attributes - `formassociated`: whether this is form-associated (boolean) Its children consist of zero or more of the following: - A `<template>`. If missing, it defaults to what's in its shadow root, replicating the shadow root options in its instances. This is cloned per-instance and used as the instances' children. - A `<style>` or `<link rel="stylesheet">`. This is adopted into the shadow root without cloning. - A `<script type="module">`. This has a single `default` export that initializes the instance state, receiving a shadow root and a signal (aborted on any reset). The shadow root would also receive all custom element lifecycle updates as events. State reset can be done via `elem.reset()`, and is done automatically on form reset. Form controls get `elem.form` and an implicitly handled `for` attribute to help simplify everything. > Why not a class? Classes have tons of setup boilerplate. This hides all of that and offloads it all to the browser. It'd also be nice to see `customElements.define` extended to likewise support such a simplified definition: ```webidl // `this` is an element instance // `signal` is aborted and the body re-initialized on state and form reset callback SimpleInitializer = CustomElementLifecycle (ShadowRoot root, AbortSignal signal); enum SimpleInitializerType { "simple", }; dictionary SimpleInitializerOptions { required DOMString name; DOMString? extends; sequence<DOMString> attributes = []; boolean formAssociated = false; (HTMLTemplateElement or DocumentFragment or TrustedHTML or DOMString) template; required SimpleInitializer initialize; }; enum FormStateRestoreType { "restore", "autocomplete", }; interface AttributeChangedEvent extends Event { readonly attribute DOMString attributeName; readonly attribute DOMString? oldValue; readonly attribute DOMString? newValue; } interface FormAssociatedEvent extends Event { readonly attribute HTMLFormElement form; } interface FormDisabledEvent extends Event { readonly attribute boolean disabled; } interface FormStateRestoreEvent extends Event { readonly attribute FormStateRestoreType restoreType; } partial interface CustomElementRegistry { void define(SimpleInitializerOptions options); }; ``` -- Reply to this email directly or view it on GitHub: https://github.com/WICG/webcomponents/issues/1064 You are receiving this because you are subscribed to this thread. Message ID: <WICG/webcomponents/issues/1064@github.com>
Received on Tuesday, 30 July 2024 15:36:19 UTC