annotate 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
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
254
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
1 const HTMLElementBase = globalThis.HTMLElement || class {};
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
2
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
3 function rememberAttribute(state, element, name) {
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
4 let attributes = state.get(element);
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
5 if (!attributes) {
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
6 attributes = new Map();
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
7 state.set(element, attributes);
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
8 }
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
9 if (!attributes.has(name)) {
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
10 attributes.set(name, element.getAttribute(name));
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
11 }
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
12 }
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
13
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
14 function setManagedAttribute(state, element, name, value) {
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
15 rememberAttribute(state, element, name);
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
16 if (value === null) element.removeAttribute(name);
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
17 else element.setAttribute(name, value);
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
18 }
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
19
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
20 function originalAttribute(state, element, name) {
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
21 const attributes = state.get(element);
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
22 return attributes?.has(name)
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
23 ? attributes.get(name)
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
24 : element.getAttribute(name);
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
25 }
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
26
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
27 function restoreElement(state, element) {
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
28 const attributes = state.get(element);
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
29 if (!attributes) return;
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
30 for (const [name, value] of attributes) {
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
31 if (value === null) element.removeAttribute(name);
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
32 else element.setAttribute(name, value);
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
33 }
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
34 state.delete(element);
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
35 }
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
36
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
37 function restoreAttributes(state) {
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
38 for (const element of [...state.keys()]) restoreElement(state, element);
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
39 }
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
40
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
41 function pruneAttributes(state, retained) {
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
42 for (const element of [...state.keys()]) {
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
43 if (!retained.has(element)) restoreElement(state, element);
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
44 }
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
45 }
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
46
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
47 function setDefaultAttribute(state, element, name, value) {
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
48 if (!element.hasAttribute(name) || state.get(element)?.has(name)) {
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
49 setManagedAttribute(state, element, name, value);
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
50 }
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
51 }
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
52
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
53 function eventElement(event) {
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
54 const target = event.target;
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
55 if (target?.nodeType === 1) return target;
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
56 return target?.parentElement || null;
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
57 }
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
58
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
59 function ownedElement(host, selector) {
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
60 return [...host.querySelectorAll(selector)].find(
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
61 element => element.closest(host.localName) === host,
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
62 ) || null;
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
63 }
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
64
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
65 function emit(element, type, detail) {
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
66 element.dispatchEvent(new CustomEvent(type, {
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
67 bubbles: true,
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
68 detail,
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
69 }));
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
70 }
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
71
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
72 function isDisabled(control) {
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
73 return Boolean(control?.disabled) ||
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
74 control?.getAttribute("aria-disabled") === "true";
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
75 }
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
76
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
77 /**
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
78 * Enhances a native scroll-snap viewport with navigation controls.
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
79 *
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
80 * @extends {HTMLElement}
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
81 */
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
82 export class ZenCarousel extends HTMLElementBase {
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
83 connectedCallback() {
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
84 this._managed ||= new Map();
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
85 this._onClick ||= event => {
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
86 const control = eventElement(event)?.closest(
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
87 "[data-zen-prev], [data-zen-next]",
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
88 );
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
89 if (control === this._prev && !isDisabled(control)) this.move(-1);
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
90 else if (control === this._next && !isDisabled(control)) this.move(1);
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
91 };
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
92 this._onKeydown ||= event => {
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
93 if (event.altKey || event.ctrlKey || event.metaKey ||
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
94 !["ArrowLeft", "ArrowRight"].includes(event.key)) {
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
95 return;
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
96 }
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
97 const target = eventElement(event);
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
98 if (target?.closest("input, textarea, select, [contenteditable]")) return;
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
99 event.preventDefault();
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
100 this.move(event.key === "ArrowLeft" ? -1 : 1);
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
101 };
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
102 this._onScroll ||= () => {
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
103 globalThis.clearTimeout(this._scrollTimer);
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
104 this._scrollTimer = globalThis.setTimeout(() => {
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
105 this._scrollTimer = null;
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
106 this.setIndex(this.currentIndex(), true);
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
107 }, 100);
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
108 };
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
109 this.addEventListener("click", this._onClick);
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
110 this.addEventListener("keydown", this._onKeydown);
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
111 this._observer ||= new MutationObserver(() => this.sync());
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
112 this._observer.observe(this, { childList: true, subtree: true });
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
113 this.sync();
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
114 }
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
115
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
116 disconnectedCallback() {
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
117 this._observer?.disconnect();
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
118 this.removeEventListener("click", this._onClick);
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
119 this.removeEventListener("keydown", this._onKeydown);
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
120 this._viewport?.removeEventListener("scroll", this._onScroll);
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
121 globalThis.clearTimeout(this._scrollTimer);
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
122 restoreAttributes(this._managed);
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
123 this._viewport = null;
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
124 this._slides = [];
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
125 this._prev = null;
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
126 this._next = null;
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
127 this._index = null;
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
128 this._scrollTimer = null;
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
129 }
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
130
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
131 sync() {
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
132 const viewport = ownedElement(this, "[data-zen-viewport]");
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
133 if (viewport !== this._viewport) {
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
134 this._viewport?.removeEventListener("scroll", this._onScroll);
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
135 this._viewport = viewport;
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
136 viewport?.addEventListener("scroll", this._onScroll, { passive: true });
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
137 }
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
138 this._slides = viewport ? [...viewport.children] : [];
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
139 this._prev = ownedElement(this, "[data-zen-prev]");
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
140 this._next = ownedElement(this, "[data-zen-next]");
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
141
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
142 const retained = new Set([
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
143 this,
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
144 viewport,
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
145 this._prev,
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
146 this._next,
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
147 ...this._slides,
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
148 ].filter(Boolean));
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
149 pruneAttributes(this._managed, retained);
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
150 setDefaultAttribute(this._managed, this, "role", "region");
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
151 setDefaultAttribute(
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
152 this._managed,
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
153 this,
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
154 "aria-roledescription",
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
155 "carousel",
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
156 );
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
157 setDefaultAttribute(this._managed, this, "aria-label", "Carousel");
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
158 if (viewport) {
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
159 setDefaultAttribute(this._managed, viewport, "tabindex", "0");
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
160 }
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
161 for (const [index, slide] of this._slides.entries()) {
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
162 setDefaultAttribute(this._managed, slide, "role", "group");
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
163 setDefaultAttribute(
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
164 this._managed,
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
165 slide,
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
166 "aria-roledescription",
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
167 "slide",
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
168 );
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
169 setDefaultAttribute(
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
170 this._managed,
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
171 slide,
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
172 "aria-label",
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
173 `Slide ${index + 1} of ${this._slides.length}`,
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
174 );
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
175 }
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
176
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
177 const index = this.currentIndex();
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
178 this._index = index;
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
179 this.render();
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
180 }
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
181
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
182 currentIndex() {
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
183 if (!this._viewport || !this._slides.length) return 0;
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
184 const viewportLeft = this._viewport.getBoundingClientRect().left;
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
185 let closest = 0;
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
186 let distance = Infinity;
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
187 for (const [index, slide] of this._slides.entries()) {
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
188 const current = Math.abs(slide.getBoundingClientRect().left - viewportLeft);
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
189 if (current < distance) {
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
190 closest = index;
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
191 distance = current;
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
192 }
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
193 }
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
194 return closest;
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
195 }
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
196
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
197 move(offset) {
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
198 if (!this._slides.length) return;
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
199 const current = Number.isInteger(this._index)
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
200 ? this._index
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
201 : this.currentIndex();
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
202 this.scrollTo(Math.max(0, Math.min(this._slides.length - 1, current + offset)));
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
203 }
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
204
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
205 scrollTo(index) {
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
206 const slide = this._slides[index];
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
207 if (!this._viewport || !slide || index === this._index) return;
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
208 const viewportRect = this._viewport.getBoundingClientRect();
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
209 const slideRect = slide.getBoundingClientRect();
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
210 const left = this._viewport.scrollLeft + slideRect.left - viewportRect.left;
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
211 if (typeof this._viewport.scrollTo === "function") {
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
212 this._viewport.scrollTo({ left, behavior: "smooth" });
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
213 } else if (typeof slide.scrollIntoView === "function") {
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
214 slide.scrollIntoView({
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
215 behavior: "smooth",
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
216 block: "nearest",
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
217 inline: "start",
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
218 });
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
219 }
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
220 this.setIndex(index, true);
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
221 }
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
222
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
223 setIndex(index, notify) {
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
224 const next = Math.max(
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
225 0,
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
226 Math.min(this._slides.length ? this._slides.length - 1 : 0, index),
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
227 );
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
228 if (next === this._index) {
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
229 this.render();
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
230 return;
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
231 }
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
232 this._index = next;
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
233 this.render();
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
234 if (notify) emit(this, "zen-change", { index: next });
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
235 }
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
236
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
237 render() {
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
238 const last = Math.max(0, this._slides.length - 1);
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
239 this.syncDisabled(this._prev, !this._slides.length || this._index <= 0);
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
240 this.syncDisabled(
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
241 this._next,
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
242 !this._slides.length || this._index >= last,
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
243 );
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
244 }
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
245
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
246 syncDisabled(control, disabled) {
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
247 if (!control) return;
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
248 const authored = originalAttribute(this._managed, control, "disabled");
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
249 setManagedAttribute(
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
250 this._managed,
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
251 control,
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
252 "disabled",
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
253 disabled || authored !== null ? "" : null,
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
254 );
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
255 }
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
256 }
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
257
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
258 /**
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
259 * Keeps a message viewport pinned while the reader remains near its end.
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
260 *
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
261 * @extends {HTMLElement}
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
262 */
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
263 export class ZenMessageScroller extends HTMLElementBase {
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
264 connectedCallback() {
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
265 this._managed ||= new Map();
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
266 this._onScroll ||= () => {
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
267 this._nearEnd = this.isNearEnd();
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
268 this.render();
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
269 };
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
270 this._onClick ||= event => {
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
271 const button = eventElement(event)?.closest("[data-zen-scroll-end]");
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
272 if (button === this._button && !isDisabled(button)) this.scrollEnd(true);
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
273 };
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
274 this._viewport = ownedElement(this, "[data-zen-viewport]") || this;
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
275 this._button = ownedElement(this, "[data-zen-scroll-end]");
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
276 this._nearEnd = this.isNearEnd();
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
277 this.addEventListener("click", this._onClick);
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
278 this._viewport.addEventListener("scroll", this._onScroll, { passive: true });
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
279 this._observer ||= new MutationObserver(records => {
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
280 if (!records.some(record => record.addedNodes.length)) return;
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
281 const wasNearEnd = this._nearEnd;
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
282 if (wasNearEnd) this.scrollEnd(false);
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
283 else this.render();
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
284 });
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
285 this._observer.observe(this._viewport, { childList: true, subtree: true });
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
286 this.render();
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
287 }
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
288
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
289 disconnectedCallback() {
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
290 this._observer?.disconnect();
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
291 this.removeEventListener("click", this._onClick);
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
292 this._viewport?.removeEventListener("scroll", this._onScroll);
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
293 restoreAttributes(this._managed);
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
294 this._viewport = null;
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
295 this._button = null;
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
296 }
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
297
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
298 isNearEnd() {
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
299 if (!this._viewport) return true;
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
300 return this._viewport.scrollHeight - this._viewport.scrollTop -
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
301 this._viewport.clientHeight <= 24;
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
302 }
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
303
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
304 scrollEnd(smooth) {
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
305 if (!this._viewport) return;
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
306 if (typeof this._viewport.scrollTo === "function") {
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
307 this._viewport.scrollTo({
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
308 top: this._viewport.scrollHeight,
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
309 behavior: smooth ? "smooth" : "auto",
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
310 });
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
311 } else {
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
312 this._viewport.scrollTop = this._viewport.scrollHeight;
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
313 }
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
314 this._nearEnd = true;
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
315 this.render();
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
316 }
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
317
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
318 render() {
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
319 if (!this._button) return;
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
320 setManagedAttribute(
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
321 this._managed,
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
322 this._button,
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
323 "hidden",
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
324 this._nearEnd ? "" : null,
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
325 );
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
326 }
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
327 }
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
328
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
329 /**
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
330 * Adds pointer and keyboard resizing to two native content panels.
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
331 *
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
332 * @extends {HTMLElement}
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
333 */
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
334 export class ZenResizable extends HTMLElementBase {
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
335 static get observedAttributes() {
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
336 return ["min", "max"];
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
337 }
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
338
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
339 connectedCallback() {
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
340 this._managed ||= new Map();
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
341 this._onPointerDown ||= event => {
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
342 const handle = eventElement(event)?.closest("[data-zen-handle]");
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
343 if (handle !== this._handle || (event.button !== 0 && event.button !== -1)) {
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
344 return;
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
345 }
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
346 event.preventDefault();
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
347 this._pointerId = event.pointerId;
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
348 this._handle.setPointerCapture?.(event.pointerId);
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
349 };
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
350 this._onPointerMove ||= event => {
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
351 if (event.pointerId !== this._pointerId) return;
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
352 const rect = this.getBoundingClientRect();
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
353 if (!rect.width) return;
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
354 this.setPercent((event.clientX - rect.left) / rect.width * 100, true);
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
355 };
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
356 this._onPointerEnd ||= event => {
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
357 if (event.pointerId !== this._pointerId) return;
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
358 if (this._handle?.hasPointerCapture?.(event.pointerId)) {
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
359 this._handle.releasePointerCapture(event.pointerId);
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
360 }
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
361 this._pointerId = null;
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
362 };
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
363 this._onKeydown ||= event => {
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
364 const handle = eventElement(event)?.closest("[data-zen-handle]");
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
365 if (handle !== this._handle ||
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
366 !["ArrowLeft", "ArrowRight"].includes(event.key)) {
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
367 return;
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
368 }
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
369 event.preventDefault();
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
370 const step = Number(this.getAttribute("step"));
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
371 const amount = Number.isFinite(step) && step > 0 ? step : 1;
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
372 this.setPercent(
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
373 this._percent + (event.key === "ArrowLeft" ? -amount : amount),
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
374 true,
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
375 );
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
376 };
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
377 this.addEventListener("pointerdown", this._onPointerDown);
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
378 this.addEventListener("pointermove", this._onPointerMove);
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
379 this.addEventListener("pointerup", this._onPointerEnd);
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
380 this.addEventListener("pointercancel", this._onPointerEnd);
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
381 this.addEventListener("keydown", this._onKeydown);
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
382 this._observer ||= new MutationObserver(() => this.sync());
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
383 this._observer.observe(this, { childList: true });
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
384 this.sync();
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
385 }
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
386
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
387 disconnectedCallback() {
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
388 this._observer?.disconnect();
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
389 this.removeEventListener("pointerdown", this._onPointerDown);
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
390 this.removeEventListener("pointermove", this._onPointerMove);
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
391 this.removeEventListener("pointerup", this._onPointerEnd);
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
392 this.removeEventListener("pointercancel", this._onPointerEnd);
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
393 this.removeEventListener("keydown", this._onKeydown);
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
394 restoreAttributes(this._managed);
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
395 this._first = null;
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
396 this._second = null;
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
397 this._handle = null;
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
398 this._pointerId = null;
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
399 this._percent = null;
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
400 }
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
401
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
402 attributeChangedCallback() {
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
403 if (this.isConnected && Number.isFinite(this._percent)) {
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
404 this.setPercent(this._percent, false);
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
405 }
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
406 }
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
407
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
408 limits() {
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
409 const minimum = this.getAttribute("min");
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
410 const maximum = this.getAttribute("max");
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
411 const min = minimum !== null && Number.isFinite(Number(minimum))
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
412 ? Math.max(0, Math.min(100, Number(minimum)))
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
413 : 0;
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
414 const max = maximum !== null && Number.isFinite(Number(maximum))
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
415 ? Math.max(min, Math.min(100, Number(maximum)))
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
416 : 100;
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
417 return { min, max };
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
418 }
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
419
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
420 sync() {
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
421 const children = [...this.children];
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
422 const handle = children.find(child => child.hasAttribute("data-zen-handle"));
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
423 const handleIndex = children.indexOf(handle);
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
424 const first = children.slice(0, handleIndex).reverse().find(
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
425 child => child.hasAttribute("data-zen-panel"),
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
426 );
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
427 const second = children.slice(handleIndex + 1).find(
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
428 child => child.hasAttribute("data-zen-panel"),
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
429 );
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
430
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
431 if (!first || !second || !handle) {
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
432 if (this._first) restoreElement(this._managed, this._first);
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
433 if (this._handle) restoreElement(this._managed, this._handle);
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
434 this._first = null;
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
435 this._second = null;
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
436 this._handle = null;
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
437 this._percent = null;
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
438 return;
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
439 }
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
440 if (this._first && this._first !== first) restoreElement(this._managed, this._first);
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
441 if (this._handle && this._handle !== handle) {
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
442 restoreElement(this._managed, this._handle);
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
443 }
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
444 this._first = first;
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
445 this._second = second;
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
446 this._handle = handle;
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
447
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
448 setManagedAttribute(this._managed, this._handle, "role", "separator");
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
449 setManagedAttribute(
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
450 this._managed,
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
451 this._handle,
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
452 "aria-orientation",
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
453 "vertical",
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
454 );
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
455 setDefaultAttribute(this._managed, this._handle, "tabindex", "0");
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
456
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
457 if (!Number.isFinite(this._percent)) {
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
458 const containerWidth = this.getBoundingClientRect().width;
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
459 const rendered = containerWidth
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
460 ? this._first.getBoundingClientRect().width / containerWidth * 100
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
461 : Number.parseFloat(this._first.style.flexBasis);
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
462 this._percent = Number.isFinite(rendered) ? rendered : 50;
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
463 }
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
464 this.setPercent(this._percent, false);
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
465 }
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
466
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
467 setPercent(percent, notify) {
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
468 if (!this._first || !this._handle) return;
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
469 const { min, max } = this.limits();
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
470 const next = Math.round(Math.max(min, Math.min(max, percent)) * 100) / 100;
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
471 const changed = next !== this._percent;
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
472 this._percent = next;
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
473 rememberAttribute(this._managed, this._first, "style");
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
474 this._first.style.flexBasis = `${next}%`;
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
475 setManagedAttribute(this._managed, this._handle, "aria-valuemin", String(min));
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
476 setManagedAttribute(this._managed, this._handle, "aria-valuemax", String(max));
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
477 setManagedAttribute(this._managed, this._handle, "aria-valuenow", String(next));
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
478 if (notify && changed) emit(this, "zen-resize", { percent: next });
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
479 }
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
480 }
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
481
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
482 /**
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
483 * Adds stable client-side sorting to a native HTML table.
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
484 *
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
485 * @extends {HTMLElement}
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
486 */
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
487 export class ZenDataTable extends HTMLElementBase {
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
488 connectedCallback() {
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
489 this._managed ||= new Map();
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
490 this._onClick ||= event => {
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
491 const button = eventElement(event)?.closest("button[data-zen-sort]");
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
492 if (!this._buttons.includes(button) || isDisabled(button)) return;
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
493 this.sort(button);
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
494 };
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
495 this.addEventListener("click", this._onClick);
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
496 this._observer ||= new MutationObserver(() => this.sync());
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
497 this._observer.observe(this, { childList: true, subtree: true });
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
498 this.sync();
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
499 }
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
500
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
501 disconnectedCallback() {
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
502 this._observer?.disconnect();
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
503 this.removeEventListener("click", this._onClick);
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
504 restoreAttributes(this._managed);
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
505 this._table = null;
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
506 this._buttons = [];
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
507 }
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
508
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
509 sync() {
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
510 this._table =
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
511 this.querySelector(":scope > table") || this.querySelector("table");
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
512 this._buttons = this._table
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
513 ? [...this._table.querySelectorAll("button[data-zen-sort]")].filter(
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
514 button => button.closest("table") === this._table &&
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
515 button.closest("th"),
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
516 )
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
517 : [];
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
518 pruneAttributes(
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
519 this._managed,
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
520 new Set(this._buttons.map(button => button.closest("th"))),
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
521 );
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
522 }
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
523
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
524 sort(button) {
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
525 const key = button.getAttribute("data-zen-sort");
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
526 const header = button.closest("th");
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
527 if (!this._table || !key || !header) return;
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
528 const direction =
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
529 header.getAttribute("aria-sort") === "ascending"
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
530 ? "descending"
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
531 : "ascending";
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
532
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
533 for (const candidate of this._buttons) {
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
534 const candidateHeader = candidate.closest("th");
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
535 setManagedAttribute(
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
536 this._managed,
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
537 candidateHeader,
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
538 "aria-sort",
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
539 candidateHeader === header ? direction : null,
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
540 );
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
541 }
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
542
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
543 for (const body of this._table.tBodies) {
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
544 const entries = [...body.rows].map((row, index) => {
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
545 const cell = [...row.cells].find(
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
546 candidate => candidate.getAttribute("data-key") === key,
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
547 );
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
548 return { index, row, value: cell?.textContent?.trim() ?? "" };
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
549 });
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
550 const numeric = entries.every(
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
551 entry => Number.isFinite(Number(entry.value)),
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
552 );
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
553 const factor = direction === "ascending" ? 1 : -1;
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
554 entries.sort((left, right) => {
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
555 const compared = numeric
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
556 ? Number(left.value) - Number(right.value)
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
557 : left.value.localeCompare(right.value);
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
558 return compared ? compared * factor : left.index - right.index;
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
559 });
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
560 body.append(...entries.map(entry => entry.row));
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
561 }
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
562 emit(this, "zen-sort", { column: key, direction });
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
563 }
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
564 }
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
565
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
566 const definitions = {
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
567 "zen-carousel": ZenCarousel,
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
568 "zen-data-table": ZenDataTable,
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
569 "zen-message-scroller": ZenMessageScroller,
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
570 "zen-resizable": ZenResizable,
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
571 };
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
572
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
573 if (globalThis.customElements) {
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
574 for (const [name, definition] of Object.entries(definitions)) {
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
575 if (!globalThis.customElements.get(name)) {
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
576 globalThis.customElements.define(name, definition);
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
577 }
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
578 }
2b6e732087ff [ui] Add complete native component catalog
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
579 }