PageSourceSearch

https://www.hocoarts.org/wp-content/themes/Social-Sorbet/assets/js/components.js?ver=1788200483

js hocoarts.org collected 2026-10-02 10:27:52 UTC 11,365 bytes, 504 lines download raw bytes

1// https://tailwindui.com/plus/v2-assets/components.js
2
3window.Components = {};
4
5window.Components.listbox = function listbox(options) {
6	let modelName = options.modelName || "selected";
7	let pointer = useTrackedPointer();
8
9	return {
10		init() {
11			this.optionCount = this.$refs.listbox.children.length;
12			this.$watch("activeIndex", (value) => {
13				if (!this.open) return;
14
15				if (this.activeIndex === null) {
16					this.activeDescendant = "";
17					return;
18				}
19
20				this.activeDescendant =
21					this.$refs.listbox.children[this.activeIndex].id;
22			});
23		},
24		activeDescendant: null,
25		optionCount: null,
26		open: false,
27		activeIndex: null,
28		selectedIndex: 0,
29		get active() {
30			return this.items[this.activeIndex];
31		},
32		get [modelName]() {
33			return this.items[this.selectedIndex];
34		},
35		choose(option) {
36			this.selectedIndex = option;
37			this.open = false;
38		},
39		onButtonClick() {
40			if (this.open) return;
41			this.activeIndex = this.selectedIndex;
42			this.open = true;
43			this.$nextTick(() => {
44				this.$refs.listbox.focus();
45				this.$refs.listbox.children[this.activeIndex].scrollIntoView({
46					block: "nearest",
47				});
48			});
49		},
50		onOptionSelect() {
51			if (this.activeIndex !== null) {
52				this.selectedIndex = this.activeIndex;
53			}
54			this.open = false;
55			this.$refs.button.focus();
56		},
57		onEscape() {
58			this.open = false;
59			this.$refs.button.focus();
60		},
61		onArrowUp() {
62			this.activeIndex =
63				this.activeIndex - 1 < 0 ? this.optionCount - 1 : this.activeIndex - 1;
64			this.$refs.listbox.children[this.activeIndex].scrollIntoView({
65				block: "nearest",
66			});
67		},
68		onArrowDown() {
69			this.activeIndex =
70				this.activeIndex + 1 > this.optionCount - 1 ? 0 : this.activeIndex + 1;
71			this.$refs.listbox.children[this.activeIndex].scrollIntoView({
72				block: "nearest",
73			});
74		},
75		onMouseEnter(evt) {
76			pointer.update(evt);
77		},
78		onMouseMove(evt, newIndex) {
79			// Only highlight when the cursor has moved
80			// Pressing arrow keys can otherwise scroll the container and override the selected item
81			if (!pointer.wasMoved(evt)) return;
82			this.activeIndex = newIndex;
83		},
84		onMouseLeave(evt) {
85			// Only unhighlight when the cursor has moved
86			// Pressing arrow keys can otherwise scroll the container and override the selected item
87			if (!pointer.wasMoved(evt)) return;
88			this.activeIndex = null;
89		},
90		...options,
91	};
92};
93
94window.Components.menu = function menu(options = { open: false }) {
95	let pointer = useTrackedPointer();
96
97	return {
98		init() {
99			this.items = Array.from(this.$el.querySelectorAll('[role="menuitem"]'));
100			this.$watch("open", () => {
101				if (this.open) {
102					this.activeIndex = -1;
103				}
104			});
105		},
106		activeDescendant: null,
107		activeIndex: null,
108		items: null,
109		open: options.open,
110		focusButton() {
111			this.$refs.button.focus();
112		},
113		onButtonClick() {
114			this.open = !this.open;
115			if (this.open) {
116				this.$nextTick(() => {
117					this.$refs["menu-items"].focus();
118				});
119			}
120		},
121		onButtonEnter() {
122			this.open = !this.open;
123			if (this.open) {
124				this.activeIndex = 0;
125				this.activeDescendant = this.items[this.activeIndex].id;
126				this.$nextTick(() => {
127					this.$refs["menu-items"].focus();
128				});
129			}
130		},
131		onArrowUp() {
132			if (!this.open) {
133				this.open = true;
134				this.activeIndex = this.items.length - 1;
135				this.activeDescendant = this.items[this.activeIndex].id;
136
137				return;
138			}
139
140			if (this.activeIndex === 0) {
141				return;
142			}
143
144			this.activeIndex =
145				this.activeIndex === -1 ? this.items.length - 1 : this.activeIndex - 1;
146			this.activeDescendant = this.items[this.activeIndex].id;
147		},
148		onArrowDown() {
149			if (!this.open) {
150				this.open = true;
151				this.activeIndex = 0;
152				this.activeDescendant = this.items[this.activeIndex].id;
153
154				return;
155			}
156
157			if (this.activeIndex === this.items.length - 1) {
158				return;
159			}
160
161			this.activeIndex = this.activeIndex + 1;
162			this.activeDescendant = this.items[this.activeIndex].id;
163		},
164		onClickAway($event) {
165			if (this.open) {
166				const focusableSelector = [
167					"[contentEditable=true]",
168					"[tabindex]",
169					"a[href]",
170					"area[href]",
171					"button:not([disabled])",
172					"iframe",
173					"input:not([disabled])",
174					"select:not([disabled])",
175					"textarea:not([disabled])",
176				]
177					.map((selector) => `${selector}:not([tabindex='-1'])`)
178					.join(",");
179
180				this.open = false;
181
182				if (!$event.target.closest(focusableSelector)) {
183					this.focusButton();
184				}
185			}
186		},
187
188		onMouseEnter(evt) {
189			pointer.update(evt);
190		},
191		onMouseMove(evt, newIndex) {
192			// Only highlight when the cursor has moved
193			// Pressing arrow keys can otherwise scroll the container and override the selected item
194			if (!pointer.wasMoved(evt)) return;
195			this.activeIndex = newIndex;
196		},
197		onMouseLeave(evt) {
198			// Only unhighlight when the cursor has moved
199			// Pressing arrow keys can otherwise scroll the container and override the selected item
200			if (!pointer.wasMoved(evt)) return;
201			this.activeIndex = -1;
202		},
203	};
204};
205
206window.Components.popoverGroup = function popoverGroup() {
207	return {
208		__type: "popoverGroup",
209		init() {
210			let handler = (e) => {
211				if (!document.body.contains(this.$el)) {
212					window.removeEventListener("focus", handler, true);
213					return;
214				}
215				if (e.target instanceof Element && !this.$el.contains(e.target)) {
216					window.dispatchEvent(
217						new CustomEvent("close-popover-group", {
218							detail: this.$el,
219						}),
220					);
221				}
222			};
223			window.addEventListener("focus", handler, true);
224		},
225	};
226};
227
228window.Components.popover = function popover({
229	open = false,
230	focus = false,
231} = {}) {
232	const focusableSelector = [
233		"[contentEditable=true]",
234		"[tabindex]",
235		"a[href]",
236		"area[href]",
237		"button:not([disabled])",
238		"iframe",
239		"input:not([disabled])",
240		"select:not([disabled])",
241		"textarea:not([disabled])",
242	]
243		.map((selector) => `${selector}:not([tabindex='-1'])`)
244		.join(",");
245
246	function focusFirst(container) {
247		const focusableElements = Array.from(
248			container.querySelectorAll(focusableSelector),
249		);
250
251		function tryFocus(element) {
252			if (element === undefined) return;
253
254			element.focus({ preventScroll: true });
255
256			if (document.activeElement !== element) {
257				tryFocus(focusableElements[focusableElements.indexOf(element) + 1]);
258			}
259		}
260
261		tryFocus(focusableElements[0]);
262	}
263
264	return {
265		__type: "popover",
266		open,
267		init() {
268			if (focus) {
269				this.$watch("open", (open) => {
270					if (open) {
271						this.$nextTick(() => {
272							focusFirst(this.$refs.panel);
273						});
274					}
275				});
276			}
277
278			let handler = (e) => {
279				if (!document.body.contains(this.$el)) {
280					window.removeEventListener("focus", handler, true);
281					return;
282				}
283				let ref = focus ? this.$refs.panel : this.$el;
284				if (
285					this.open &&
286					e.target instanceof Element &&
287					!ref.contains(e.target)
288				) {
289					let node = this.$el;
290					while (node.parentNode) {
291						node = node.parentNode;
292						if (node.__x instanceof this.constructor) {
293							if (node.__x.$data.__type === "popoverGroup") return;
294							if (node.__x.$data.__type === "popover") break;
295						}
296					}
297					this.open = false;
298				}
299			};
300
301			window.addEventListener("focus", handler, true);
302		},
303		onEscape() {
304			this.open = false;
305			if (this.restoreEl) {
306				this.restoreEl.focus();
307			}
308		},
309		onClosePopoverGroup(e) {
310			if (e.detail.contains(this.$el)) {
311				this.open = false;
312			}
313		},
314		toggle(e) {
315			this.open = !this.open;
316			if (this.open) {
317				this.restoreEl = e.currentTarget;
318			} else if (this.restoreEl) {
319				this.restoreEl.focus();
320			}
321		},
322	};
323};
324
325window.Components.radioGroup = function radioGroup({
326	initialCheckedIndex = 0,
327} = {}) {
328	return {
329		value: undefined,
330		active: undefined,
331		init() {
332			let options = Array.from(this.$el.querySelectorAll("input"));
333
334			this.value = options[initialCheckedIndex]?.value;
335
336			for (let option of options) {
337				option.addEventListener("change", () => {
338					this.active = option.value;
339				});
340				option.addEventListener("focus", () => {
341					this.active = option.value;
342				});
343			}
344
345			window.addEventListener(
346				"focus",
347				() => {
348					if (!options.includes(document.activeElement)) {
349						this.active = undefined;
350					}
351				},
352				true,
353			);
354		},
355	};
356};
357
358window.Components.tabs = function tabs() {
359	return {
360		selectedIndex: 0,
361		onTabClick(event) {
362			if (!this.$el.contains(event.detail)) return;
363
364			let tabs = Array.from(
365				this.$el.querySelectorAll('[x-data^="Components.tab("]'),
366			);
367			let panels = Array.from(
368				this.$el.querySelectorAll('[x-data^="Components.tabPanel("]'),
369			);
370
371			let idx = tabs.indexOf(event.detail);
372			this.selectedIndex = idx;
373
374			window.dispatchEvent(
375				new CustomEvent("tab-select", {
376					detail: {
377						tab: event.detail,
378						panel: panels[idx],
379					},
380				}),
381			);
382		},
383		onTabKeydown(event) {
384			if (!this.$el.contains(event.detail.tab)) return;
385
386			let tabs = Array.from(
387				this.$el.querySelectorAll('[x-data^="Components.tab("]'),
388			);
389			let tabIndex = tabs.indexOf(event.detail.tab);
390
391			if (event.detail.key === "ArrowLeft") {
392				this.onTabClick({
393					detail: tabs[(tabIndex - 1 + tabs.length) % tabs.length],
394				});
395			} else if (event.detail.key === "ArrowRight") {
396				this.onTabClick({ detail: tabs[(tabIndex + 1) % tabs.length] });
397			} else if (event.detail.key === "Home" || event.detail.key === "PageUp") {
398				this.onTabClick({ detail: tabs[0] });
399			} else if (
400				event.detail.key === "End" ||
401				event.detail.key === "PageDown"
402			) {
403				this.onTabClick({ detail: tabs[tabs.length - 1] });
404			}
405		},
406	};
407};
408
409window.Components.tab = function tab(defaultIndex = 0) {
410	return {
411		selected: false,
412		init() {
413			let tabs = Array.from(
414				this.$el
415					.closest('[x-data^="Components.tabs("]')
416					.querySelectorAll('[x-data^="Components.tab("]'),
417			);
418			this.selected = tabs.indexOf(this.$el) === defaultIndex;
419			this.$watch("selected", (selected) => {
420				if (selected) {
421					this.$el.focus();
422				}
423			});
424		},
425		onClick() {
426			window.dispatchEvent(
427				new CustomEvent("tab-click", {
428					detail: this.$el,
429				}),
430			);
431		},
432		onKeydown(event) {
433			if (
434				[
435					"ArrowLeft",
436					"ArrowRight",
437					"Home",
438					"PageUp",
439					"End",
440					"PageDown",
441				].includes(event.key)
442			) {
443				event.preventDefault();
444			}
445
446			window.dispatchEvent(
447				new CustomEvent("tab-keydown", {
448					detail: {
449						tab: this.$el,
450						key: event.key,
451					},
452				}),
453			);
454		},
455		onTabSelect(event) {
456			this.selected = event.detail.tab === this.$el;
457		},
458	};
459};
460
461window.Components.tabPanel = function tabPanel(defaultIndex = 0) {
462	return {
463		selected: false,
464		init() {
465			let panels = Array.from(
466				this.$el
467					.closest('[x-data^="Components.tabs("]')
468					.querySelectorAll('[x-data^="Components.tabPanel("]'),
469			);
470			this.selected = panels.indexOf(this.$el) === defaultIndex;
471		},
472		onTabSelect(event) {
473			this.selected = event.detail.panel === this.$el;
474		},
475	};
476};
477
478function useTrackedPointer() {
479	/** @type {[x: number, y: number]} */
480	let lastPos = [-1, -1];
481
482	return {
483		/**
484		 * @param {PointerEvent} evt
485		 */
486		wasMoved(evt) {
487			let newPos = [evt.screenX, evt.screenY];
488
489			if (lastPos[0] === newPos[0] && lastPos[1] === newPos[1]) {
490				return false;
491			}
492
493			lastPos = newPos;
494			return true;
495		},
496
497		/**
498		 * @param {PointerEvent} evt
499		 */
500		update(evt) {
501			lastPos = [evt.screenX, evt.screenY];
502		},
503	};
504}

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.