Mercurial
comparison design_system/src/components/button.js @ 251:117c4d53c9a4
[ui] Add HTML-first Web Component system
Co-authored-by: Copilot <[email protected]>
| author | MrJuneJune <me@mrjunejune.com> |
|---|---|
| date | Tue, 04 Aug 2026 09:14:57 -0700 |
| parents | |
| children | 2b6e732087ff |
comparison
equal
deleted
inserted
replaced
| 250:745fd127b2a1 | 251:117c4d53c9a4 |
|---|---|
| 1 export class ZenButton extends HTMLElement { | |
| 2 static get observedAttributes() { | |
| 3 return ["disabled", "loading"]; | |
| 4 } | |
| 5 | |
| 6 connectedCallback() { | |
| 7 if (!this._blockInteraction) { | |
| 8 this._blockInteraction = event => { | |
| 9 if (!this.hasAttribute("disabled") && | |
| 10 !this.hasAttribute("loading")) return; | |
| 11 event.preventDefault(); | |
| 12 event.stopImmediatePropagation(); | |
| 13 }; | |
| 14 } | |
| 15 this.addEventListener("click", this._blockInteraction, true); | |
| 16 if (!this._observer) { | |
| 17 this._observer = new MutationObserver(records => { | |
| 18 for (const record of records) { | |
| 19 for (const node of record.removedNodes) { | |
| 20 if (node instanceof Element && | |
| 21 node.matches("button, a")) { | |
| 22 this.restoreManagedState(node); | |
| 23 } | |
| 24 } | |
| 25 } | |
| 26 this.sync(); | |
| 27 }); | |
| 28 } | |
| 29 this._observer.observe(this, { childList: true }); | |
| 30 this.sync(); | |
| 31 } | |
| 32 | |
| 33 disconnectedCallback() { | |
| 34 this._observer?.disconnect(); | |
| 35 this.removeEventListener("click", this._blockInteraction, true); | |
| 36 } | |
| 37 | |
| 38 attributeChangedCallback() { | |
| 39 this.sync(); | |
| 40 } | |
| 41 | |
| 42 sync() { | |
| 43 const control = this.querySelector(":scope > button, :scope > a"); | |
| 44 if (!control) return; | |
| 45 | |
| 46 const disabled = | |
| 47 this.hasAttribute("disabled") || | |
| 48 this.hasAttribute("loading"); | |
| 49 | |
| 50 if (disabled) { | |
| 51 if (control.dataset.zenManagedAriaDisabled !== "true") { | |
| 52 control.dataset.zenOriginalAriaDisabled = | |
| 53 control.getAttribute("aria-disabled") ?? "__zen_missing__"; | |
| 54 control.dataset.zenManagedAriaDisabled = "true"; | |
| 55 } | |
| 56 control.setAttribute("aria-disabled", "true"); | |
| 57 } else { | |
| 58 this.restoreDisabledState(control); | |
| 59 } | |
| 60 | |
| 61 if (this.hasAttribute("loading")) { | |
| 62 if (control.dataset.zenManagedAriaBusy !== "true") { | |
| 63 control.dataset.zenOriginalAriaBusy = | |
| 64 control.getAttribute("aria-busy") ?? "__zen_missing__"; | |
| 65 control.dataset.zenManagedAriaBusy = "true"; | |
| 66 } | |
| 67 control.setAttribute("aria-busy", "true"); | |
| 68 } else if (control.dataset.zenManagedAriaBusy === "true") { | |
| 69 if (control.dataset.zenOriginalAriaBusy === "__zen_missing__") { | |
| 70 control.removeAttribute("aria-busy"); | |
| 71 } else { | |
| 72 control.setAttribute( | |
| 73 "aria-busy", | |
| 74 control.dataset.zenOriginalAriaBusy, | |
| 75 ); | |
| 76 } | |
| 77 delete control.dataset.zenManagedAriaBusy; | |
| 78 delete control.dataset.zenOriginalAriaBusy; | |
| 79 } | |
| 80 } | |
| 81 | |
| 82 restoreDisabledState(control) { | |
| 83 if (control.dataset.zenManagedAriaDisabled === "true") { | |
| 84 if (control.dataset.zenOriginalAriaDisabled === "__zen_missing__") { | |
| 85 control.removeAttribute("aria-disabled"); | |
| 86 } else { | |
| 87 control.setAttribute( | |
| 88 "aria-disabled", | |
| 89 control.dataset.zenOriginalAriaDisabled, | |
| 90 ); | |
| 91 } | |
| 92 delete control.dataset.zenManagedAriaDisabled; | |
| 93 delete control.dataset.zenOriginalAriaDisabled; | |
| 94 } | |
| 95 } | |
| 96 | |
| 97 restoreManagedState(control) { | |
| 98 this.restoreDisabledState(control); | |
| 99 if (control.dataset.zenManagedAriaBusy === "true") { | |
| 100 if (control.dataset.zenOriginalAriaBusy === "__zen_missing__") { | |
| 101 control.removeAttribute("aria-busy"); | |
| 102 } else { | |
| 103 control.setAttribute( | |
| 104 "aria-busy", | |
| 105 control.dataset.zenOriginalAriaBusy, | |
| 106 ); | |
| 107 } | |
| 108 delete control.dataset.zenManagedAriaBusy; | |
| 109 delete control.dataset.zenOriginalAriaBusy; | |
| 110 } | |
| 111 } | |
| 112 } | |
| 113 | |
| 114 if (!customElements.get("zen-button")) { | |
| 115 customElements.define("zen-button", ZenButton); | |
| 116 } |