Mercurial
view design_system/src/components/collections.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 |
line wrap: on
line source
const HTMLElementBase = globalThis.HTMLElement || class {}; function rememberAttribute(state, element, name) { let attributes = state.get(element); if (!attributes) { attributes = new Map(); state.set(element, attributes); } if (!attributes.has(name)) { attributes.set(name, element.getAttribute(name)); } } function setManagedAttribute(state, element, name, value) { rememberAttribute(state, element, name); if (value === null) element.removeAttribute(name); else element.setAttribute(name, value); } function originalAttribute(state, element, name) { const attributes = state.get(element); return attributes?.has(name) ? attributes.get(name) : element.getAttribute(name); } function restoreElement(state, element) { const attributes = state.get(element); if (!attributes) return; for (const [name, value] of attributes) { if (value === null) element.removeAttribute(name); else element.setAttribute(name, value); } state.delete(element); } function restoreAttributes(state) { for (const element of [...state.keys()]) restoreElement(state, element); } function pruneAttributes(state, retained) { for (const element of [...state.keys()]) { if (!retained.has(element)) restoreElement(state, element); } } function setDefaultAttribute(state, element, name, value) { if (!element.hasAttribute(name) || state.get(element)?.has(name)) { setManagedAttribute(state, element, name, value); } } function eventElement(event) { const target = event.target; if (target?.nodeType === 1) return target; return target?.parentElement || null; } function ownedElement(host, selector) { return [...host.querySelectorAll(selector)].find( element => element.closest(host.localName) === host, ) || null; } function emit(element, type, detail) { element.dispatchEvent(new CustomEvent(type, { bubbles: true, detail, })); } function isDisabled(control) { return Boolean(control?.disabled) || control?.getAttribute("aria-disabled") === "true"; } /** * Enhances a native scroll-snap viewport with navigation controls. * * @extends {HTMLElement} */ export class ZenCarousel extends HTMLElementBase { connectedCallback() { this._managed ||= new Map(); this._onClick ||= event => { const control = eventElement(event)?.closest( "[data-zen-prev], [data-zen-next]", ); if (control === this._prev && !isDisabled(control)) this.move(-1); else if (control === this._next && !isDisabled(control)) this.move(1); }; this._onKeydown ||= event => { if (event.altKey || event.ctrlKey || event.metaKey || !["ArrowLeft", "ArrowRight"].includes(event.key)) { return; } const target = eventElement(event); if (target?.closest("input, textarea, select, [contenteditable]")) return; event.preventDefault(); this.move(event.key === "ArrowLeft" ? -1 : 1); }; this._onScroll ||= () => { globalThis.clearTimeout(this._scrollTimer); this._scrollTimer = globalThis.setTimeout(() => { this._scrollTimer = null; this.setIndex(this.currentIndex(), true); }, 100); }; this.addEventListener("click", this._onClick); this.addEventListener("keydown", this._onKeydown); this._observer ||= new MutationObserver(() => this.sync()); this._observer.observe(this, { childList: true, subtree: true }); this.sync(); } disconnectedCallback() { this._observer?.disconnect(); this.removeEventListener("click", this._onClick); this.removeEventListener("keydown", this._onKeydown); this._viewport?.removeEventListener("scroll", this._onScroll); globalThis.clearTimeout(this._scrollTimer); restoreAttributes(this._managed); this._viewport = null; this._slides = []; this._prev = null; this._next = null; this._index = null; this._scrollTimer = null; } sync() { const viewport = ownedElement(this, "[data-zen-viewport]"); if (viewport !== this._viewport) { this._viewport?.removeEventListener("scroll", this._onScroll); this._viewport = viewport; viewport?.addEventListener("scroll", this._onScroll, { passive: true }); } this._slides = viewport ? [...viewport.children] : []; this._prev = ownedElement(this, "[data-zen-prev]"); this._next = ownedElement(this, "[data-zen-next]"); const retained = new Set([ this, viewport, this._prev, this._next, ...this._slides, ].filter(Boolean)); pruneAttributes(this._managed, retained); setDefaultAttribute(this._managed, this, "role", "region"); setDefaultAttribute( this._managed, this, "aria-roledescription", "carousel", ); setDefaultAttribute(this._managed, this, "aria-label", "Carousel"); if (viewport) { setDefaultAttribute(this._managed, viewport, "tabindex", "0"); } for (const [index, slide] of this._slides.entries()) { setDefaultAttribute(this._managed, slide, "role", "group"); setDefaultAttribute( this._managed, slide, "aria-roledescription", "slide", ); setDefaultAttribute( this._managed, slide, "aria-label", `Slide ${index + 1} of ${this._slides.length}`, ); } const index = this.currentIndex(); this._index = index; this.render(); } currentIndex() { if (!this._viewport || !this._slides.length) return 0; const viewportLeft = this._viewport.getBoundingClientRect().left; let closest = 0; let distance = Infinity; for (const [index, slide] of this._slides.entries()) { const current = Math.abs(slide.getBoundingClientRect().left - viewportLeft); if (current < distance) { closest = index; distance = current; } } return closest; } move(offset) { if (!this._slides.length) return; const current = Number.isInteger(this._index) ? this._index : this.currentIndex(); this.scrollTo(Math.max(0, Math.min(this._slides.length - 1, current + offset))); } scrollTo(index) { const slide = this._slides[index]; if (!this._viewport || !slide || index === this._index) return; const viewportRect = this._viewport.getBoundingClientRect(); const slideRect = slide.getBoundingClientRect(); const left = this._viewport.scrollLeft + slideRect.left - viewportRect.left; if (typeof this._viewport.scrollTo === "function") { this._viewport.scrollTo({ left, behavior: "smooth" }); } else if (typeof slide.scrollIntoView === "function") { slide.scrollIntoView({ behavior: "smooth", block: "nearest", inline: "start", }); } this.setIndex(index, true); } setIndex(index, notify) { const next = Math.max( 0, Math.min(this._slides.length ? this._slides.length - 1 : 0, index), ); if (next === this._index) { this.render(); return; } this._index = next; this.render(); if (notify) emit(this, "zen-change", { index: next }); } render() { const last = Math.max(0, this._slides.length - 1); this.syncDisabled(this._prev, !this._slides.length || this._index <= 0); this.syncDisabled( this._next, !this._slides.length || this._index >= last, ); } syncDisabled(control, disabled) { if (!control) return; const authored = originalAttribute(this._managed, control, "disabled"); setManagedAttribute( this._managed, control, "disabled", disabled || authored !== null ? "" : null, ); } } /** * Keeps a message viewport pinned while the reader remains near its end. * * @extends {HTMLElement} */ export class ZenMessageScroller extends HTMLElementBase { connectedCallback() { this._managed ||= new Map(); this._onScroll ||= () => { this._nearEnd = this.isNearEnd(); this.render(); }; this._onClick ||= event => { const button = eventElement(event)?.closest("[data-zen-scroll-end]"); if (button === this._button && !isDisabled(button)) this.scrollEnd(true); }; this._viewport = ownedElement(this, "[data-zen-viewport]") || this; this._button = ownedElement(this, "[data-zen-scroll-end]"); this._nearEnd = this.isNearEnd(); this.addEventListener("click", this._onClick); this._viewport.addEventListener("scroll", this._onScroll, { passive: true }); this._observer ||= new MutationObserver(records => { if (!records.some(record => record.addedNodes.length)) return; const wasNearEnd = this._nearEnd; if (wasNearEnd) this.scrollEnd(false); else this.render(); }); this._observer.observe(this._viewport, { childList: true, subtree: true }); this.render(); } disconnectedCallback() { this._observer?.disconnect(); this.removeEventListener("click", this._onClick); this._viewport?.removeEventListener("scroll", this._onScroll); restoreAttributes(this._managed); this._viewport = null; this._button = null; } isNearEnd() { if (!this._viewport) return true; return this._viewport.scrollHeight - this._viewport.scrollTop - this._viewport.clientHeight <= 24; } scrollEnd(smooth) { if (!this._viewport) return; if (typeof this._viewport.scrollTo === "function") { this._viewport.scrollTo({ top: this._viewport.scrollHeight, behavior: smooth ? "smooth" : "auto", }); } else { this._viewport.scrollTop = this._viewport.scrollHeight; } this._nearEnd = true; this.render(); } render() { if (!this._button) return; setManagedAttribute( this._managed, this._button, "hidden", this._nearEnd ? "" : null, ); } } /** * Adds pointer and keyboard resizing to two native content panels. * * @extends {HTMLElement} */ export class ZenResizable extends HTMLElementBase { static get observedAttributes() { return ["min", "max"]; } connectedCallback() { this._managed ||= new Map(); this._onPointerDown ||= event => { const handle = eventElement(event)?.closest("[data-zen-handle]"); if (handle !== this._handle || (event.button !== 0 && event.button !== -1)) { return; } event.preventDefault(); this._pointerId = event.pointerId; this._handle.setPointerCapture?.(event.pointerId); }; this._onPointerMove ||= event => { if (event.pointerId !== this._pointerId) return; const rect = this.getBoundingClientRect(); if (!rect.width) return; this.setPercent((event.clientX - rect.left) / rect.width * 100, true); }; this._onPointerEnd ||= event => { if (event.pointerId !== this._pointerId) return; if (this._handle?.hasPointerCapture?.(event.pointerId)) { this._handle.releasePointerCapture(event.pointerId); } this._pointerId = null; }; this._onKeydown ||= event => { const handle = eventElement(event)?.closest("[data-zen-handle]"); if (handle !== this._handle || !["ArrowLeft", "ArrowRight"].includes(event.key)) { return; } event.preventDefault(); const step = Number(this.getAttribute("step")); const amount = Number.isFinite(step) && step > 0 ? step : 1; this.setPercent( this._percent + (event.key === "ArrowLeft" ? -amount : amount), true, ); }; this.addEventListener("pointerdown", this._onPointerDown); this.addEventListener("pointermove", this._onPointerMove); this.addEventListener("pointerup", this._onPointerEnd); this.addEventListener("pointercancel", this._onPointerEnd); this.addEventListener("keydown", this._onKeydown); this._observer ||= new MutationObserver(() => this.sync()); this._observer.observe(this, { childList: true }); this.sync(); } disconnectedCallback() { this._observer?.disconnect(); this.removeEventListener("pointerdown", this._onPointerDown); this.removeEventListener("pointermove", this._onPointerMove); this.removeEventListener("pointerup", this._onPointerEnd); this.removeEventListener("pointercancel", this._onPointerEnd); this.removeEventListener("keydown", this._onKeydown); restoreAttributes(this._managed); this._first = null; this._second = null; this._handle = null; this._pointerId = null; this._percent = null; } attributeChangedCallback() { if (this.isConnected && Number.isFinite(this._percent)) { this.setPercent(this._percent, false); } } limits() { const minimum = this.getAttribute("min"); const maximum = this.getAttribute("max"); const min = minimum !== null && Number.isFinite(Number(minimum)) ? Math.max(0, Math.min(100, Number(minimum))) : 0; const max = maximum !== null && Number.isFinite(Number(maximum)) ? Math.max(min, Math.min(100, Number(maximum))) : 100; return { min, max }; } sync() { const children = [...this.children]; const handle = children.find(child => child.hasAttribute("data-zen-handle")); const handleIndex = children.indexOf(handle); const first = children.slice(0, handleIndex).reverse().find( child => child.hasAttribute("data-zen-panel"), ); const second = children.slice(handleIndex + 1).find( child => child.hasAttribute("data-zen-panel"), ); if (!first || !second || !handle) { if (this._first) restoreElement(this._managed, this._first); if (this._handle) restoreElement(this._managed, this._handle); this._first = null; this._second = null; this._handle = null; this._percent = null; return; } if (this._first && this._first !== first) restoreElement(this._managed, this._first); if (this._handle && this._handle !== handle) { restoreElement(this._managed, this._handle); } this._first = first; this._second = second; this._handle = handle; setManagedAttribute(this._managed, this._handle, "role", "separator"); setManagedAttribute( this._managed, this._handle, "aria-orientation", "vertical", ); setDefaultAttribute(this._managed, this._handle, "tabindex", "0"); if (!Number.isFinite(this._percent)) { const containerWidth = this.getBoundingClientRect().width; const rendered = containerWidth ? this._first.getBoundingClientRect().width / containerWidth * 100 : Number.parseFloat(this._first.style.flexBasis); this._percent = Number.isFinite(rendered) ? rendered : 50; } this.setPercent(this._percent, false); } setPercent(percent, notify) { if (!this._first || !this._handle) return; const { min, max } = this.limits(); const next = Math.round(Math.max(min, Math.min(max, percent)) * 100) / 100; const changed = next !== this._percent; this._percent = next; rememberAttribute(this._managed, this._first, "style"); this._first.style.flexBasis = `${next}%`; setManagedAttribute(this._managed, this._handle, "aria-valuemin", String(min)); setManagedAttribute(this._managed, this._handle, "aria-valuemax", String(max)); setManagedAttribute(this._managed, this._handle, "aria-valuenow", String(next)); if (notify && changed) emit(this, "zen-resize", { percent: next }); } } /** * Adds stable client-side sorting to a native HTML table. * * @extends {HTMLElement} */ export class ZenDataTable extends HTMLElementBase { connectedCallback() { this._managed ||= new Map(); this._onClick ||= event => { const button = eventElement(event)?.closest("button[data-zen-sort]"); if (!this._buttons.includes(button) || isDisabled(button)) return; this.sort(button); }; this.addEventListener("click", this._onClick); this._observer ||= new MutationObserver(() => this.sync()); this._observer.observe(this, { childList: true, subtree: true }); this.sync(); } disconnectedCallback() { this._observer?.disconnect(); this.removeEventListener("click", this._onClick); restoreAttributes(this._managed); this._table = null; this._buttons = []; } sync() { this._table = this.querySelector(":scope > table") || this.querySelector("table"); this._buttons = this._table ? [...this._table.querySelectorAll("button[data-zen-sort]")].filter( button => button.closest("table") === this._table && button.closest("th"), ) : []; pruneAttributes( this._managed, new Set(this._buttons.map(button => button.closest("th"))), ); } sort(button) { const key = button.getAttribute("data-zen-sort"); const header = button.closest("th"); if (!this._table || !key || !header) return; const direction = header.getAttribute("aria-sort") === "ascending" ? "descending" : "ascending"; for (const candidate of this._buttons) { const candidateHeader = candidate.closest("th"); setManagedAttribute( this._managed, candidateHeader, "aria-sort", candidateHeader === header ? direction : null, ); } for (const body of this._table.tBodies) { const entries = [...body.rows].map((row, index) => { const cell = [...row.cells].find( candidate => candidate.getAttribute("data-key") === key, ); return { index, row, value: cell?.textContent?.trim() ?? "" }; }); const numeric = entries.every( entry => Number.isFinite(Number(entry.value)), ); const factor = direction === "ascending" ? 1 : -1; entries.sort((left, right) => { const compared = numeric ? Number(left.value) - Number(right.value) : left.value.localeCompare(right.value); return compared ? compared * factor : left.index - right.index; }); body.append(...entries.map(entry => entry.row)); } emit(this, "zen-sort", { column: key, direction }); } } const definitions = { "zen-carousel": ZenCarousel, "zen-data-table": ZenDataTable, "zen-message-scroller": ZenMessageScroller, "zen-resizable": ZenResizable, }; if (globalThis.customElements) { for (const [name, definition] of Object.entries(definitions)) { if (!globalThis.customElements.get(name)) { globalThis.customElements.define(name, definition); } } }