- 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