Mercurial
annotate design_system/src/components/field.js @ 279:b3b547563ec7
Add Google connector service and agent wiki
Implement the C/Seobeo Google Drive and Gmail connector with encrypted OAuth storage, Zenbu authentication, browser testing, AI tool discovery, chunked HTTP decoding, and Bazel coverage. Consolidate repository guidance into progressive wiki documentation and enforce arena-first allocation for new first-party C code.
Co-authored-by: Copilot <[email protected]>
Copilot-Session: 84c338fd-0939-4bb3-b7f3-1062eb213e5d
| author | MrJuneJune <me@mrjunejune.com> |
|---|---|
| date | Mon, 17 Aug 2026 22:22:36 -0700 |
| parents | 2b6e732087ff |
| children |
| rev | line source |
|---|---|
|
251
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
1 let nextFieldId = 1; |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
2 |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
3 function uniqueId(base) { |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
4 let candidate = base; |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
5 let suffix = 2; |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
6 while (document.getElementById(candidate)) { |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
7 candidate = `${base}-${suffix++}`; |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
8 } |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
9 return candidate; |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
10 } |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
11 |
|
254
2b6e732087ff
[ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
251
diff
changeset
|
12 /** |
|
2b6e732087ff
[ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
251
diff
changeset
|
13 * Associates a label, native form control, and descriptive help text. |
|
2b6e732087ff
[ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
251
diff
changeset
|
14 * |
|
2b6e732087ff
[ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
251
diff
changeset
|
15 * @extends {HTMLElement} |
|
2b6e732087ff
[ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
251
diff
changeset
|
16 */ |
|
251
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
17 export class ZenField extends HTMLElement { |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
18 connectedCallback() { |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
19 if (!this._observer) { |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
20 this._observer = new MutationObserver(() => this.sync()); |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
21 } |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
22 this._observer.observe(this, { |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
23 attributes: true, |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
24 attributeFilter: ["id"], |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
25 childList: true, |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
26 subtree: true, |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
27 }); |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
28 this.sync(); |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
29 } |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
30 |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
31 disconnectedCallback() { |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
32 this._observer?.disconnect(); |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
33 this.disconnectControl(); |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
34 } |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
35 |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
36 disconnectControl() { |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
37 if (!this._control || !this._updateValidity) return; |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
38 this._control.removeEventListener("invalid", this._updateValidity); |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
39 this._control.removeEventListener("input", this._updateValidity); |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
40 this._control.removeEventListener("change", this._updateValidity); |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
41 if (this._addedDescription) { |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
42 const describedBy = (this._control.getAttribute("aria-describedby") || "") |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
43 .split(/\s+/) |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
44 .filter(value => value && value !== this._addedDescription); |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
45 if (describedBy.length) { |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
46 this._control.setAttribute( |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
47 "aria-describedby", |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
48 describedBy.join(" "), |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
49 ); |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
50 } else { |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
51 this._control.removeAttribute("aria-describedby"); |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
52 } |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
53 } |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
54 if (this._label) { |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
55 if (this._originalLabelFor === null) { |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
56 this._label.removeAttribute("for"); |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
57 } else { |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
58 this._label.setAttribute("for", this._originalLabelFor); |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
59 } |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
60 } |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
61 this._control = null; |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
62 this._label = null; |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
63 this._help = null; |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
64 this._controlId = null; |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
65 this._helpId = null; |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
66 this._addedDescription = null; |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
67 this._originalLabelFor = null; |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
68 this._updateValidity = null; |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
69 this.removeAttribute("data-invalid"); |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
70 } |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
71 |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
72 sync() { |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
73 const label = this.querySelector(":scope > label"); |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
74 const control = this.querySelector( |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
75 ":scope > input, :scope > select, :scope > textarea", |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
76 ); |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
77 if (!label || !control) { |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
78 this.disconnectControl(); |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
79 return; |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
80 } |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
81 const help = this.querySelector(":scope > small, :scope > [data-help]"); |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
82 if (control === this._control && |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
83 label === this._label && |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
84 help === this._help && |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
85 control.id === this._controlId && |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
86 (help?.id || null) === this._helpId) return; |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
87 |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
88 this.disconnectControl(); |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
89 this._control = control; |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
90 this._label = label; |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
91 this._help = help; |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
92 if (!control.id) { |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
93 control.id = uniqueId(`zen-field-${nextFieldId++}`); |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
94 } |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
95 this._originalLabelFor = label.getAttribute("for"); |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
96 label.htmlFor = control.id; |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
97 |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
98 if (help) { |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
99 if (!help.id) help.id = uniqueId(`${control.id}-help`); |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
100 const describedBy = new Set( |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
101 (control.getAttribute("aria-describedby") || "") |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
102 .split(/\s+/) |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
103 .filter(Boolean), |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
104 ); |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
105 if (!describedBy.has(help.id)) { |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
106 this._addedDescription = help.id; |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
107 } |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
108 describedBy.add(help.id); |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
109 control.setAttribute( |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
110 "aria-describedby", |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
111 [...describedBy].join(" "), |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
112 ); |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
113 } |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
114 this._controlId = control.id; |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
115 this._helpId = help?.id || null; |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
116 |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
117 this._updateValidity = () => { |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
118 this.toggleAttribute( |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
119 "data-invalid", |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
120 !control.validity.valid, |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
121 ); |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
122 }; |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
123 control.addEventListener("invalid", this._updateValidity); |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
124 control.addEventListener("input", this._updateValidity); |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
125 control.addEventListener("change", this._updateValidity); |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
126 } |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
127 } |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
128 |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
129 if (!customElements.get("zen-field")) { |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
130 customElements.define("zen-field", ZenField); |
|
117c4d53c9a4
[ui] Add HTML-first Web Component system
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
131 } |