annotate design_system/src/components/collections.js @ 259:667156fcd3e3

Add dev-only cyberpunk JRPG page
author MrJuneJune <me@mrjunejune.com>
date Wed, 05 Aug 2026 09:19:41 -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 }