PageSourceSearch

https://occasions.jeanlain.com/assets/@symfony/ux-live-component/live_controller-75n6hxx.js

js jeanlain.com collected 2026-09-25 03:46:28 UTC 84,419 bytes, 2,337 lines download raw bytes

1import { Controller } from "@hotwired/stimulus";
2var BackendRequest_default = class {
3	constructor(promise, actions, updateModels) {
4		this.isResolved = false;
5		this.promise = promise;
6		this.promise.then((response) => {
7			this.isResolved = true;
8			return response;
9		});
10		this.actions = actions;
11		this.updatedModels = updateModels;
12	}
13	containsOneOfActions(targetedActions) {
14		return this.actions.filter((action) => targetedActions.includes(action)).length > 0;
15	}
16	areAnyModelsUpdated(targetedModels) {
17		return this.updatedModels.filter((model) => targetedModels.includes(model)).length > 0;
18	}
19};
20var RequestBuilder_default = class {
21	constructor(url, method = "post", credentials = "same-origin") {
22		this.url = url;
23		this.method = method;
24		this.credentials = credentials;
25	}
26	buildRequest(props, actions, updated, children, updatedPropsFromParent, files) {
27		const splitUrl = this.url.split("?");
28		let [url] = splitUrl;
29		const [, queryString] = splitUrl;
30		const params = new URLSearchParams(queryString || "");
31		const fetchOptions = {};
32		fetchOptions.credentials = this.credentials;
33		fetchOptions.headers = {
34			Accept: "application/vnd.live-component+html",
35			"X-Requested-With": "XMLHttpRequest",
36			"X-Live-Url": window.location.pathname + window.location.search
37		};
38		const totalFiles = Object.entries(files).reduce((total, current) => total + current.length, 0);
39		const hasFingerprints = Object.keys(children).length > 0;
40		if (actions.length === 0 && totalFiles === 0 && this.method === "get" && this.willDataFitInUrl(JSON.stringify(props), JSON.stringify(updated), params, JSON.stringify(children), JSON.stringify(updatedPropsFromParent))) {
41			params.set("props", JSON.stringify(props));
42			params.set("updated", JSON.stringify(updated));
43			if (Object.keys(updatedPropsFromParent).length > 0) params.set("propsFromParent", JSON.stringify(updatedPropsFromParent));
44			if (hasFingerprints) params.set("children", JSON.stringify(children));
45			fetchOptions.method = "GET";
46		} else {
47			fetchOptions.method = "POST";
48			const requestData = {
49				props,
50				updated
51			};
52			if (Object.keys(updatedPropsFromParent).length > 0) requestData.propsFromParent = updatedPropsFromParent;
53			if (hasFingerprints) requestData.children = children;
54			if (actions.length > 0) if (actions.length === 1) {
55				requestData.args = actions[0].args;
56				url += `/${encodeURIComponent(actions[0].name)}`;
57			} else {
58				url += "/_batch";
59				requestData.actions = actions;
60			}
61			const formData = new FormData();
62			formData.append("data", JSON.stringify(requestData));
63			for (const [key, value] of Object.entries(files)) {
64				const length = value.length;
65				for (let i = 0; i < length; ++i) formData.append(key, value[i]);
66			}
67			fetchOptions.body = formData;
68		}
69		const paramsString = params.toString();
70		return {
71			url: `${url}${paramsString.length > 0 ? `?${paramsString}` : ""}`,
72			fetchOptions
73		};
74	}
75	willDataFitInUrl(propsJson, updatedJson, params, childrenJson, propsFromParentJson) {
76		return (new URLSearchParams(propsJson + updatedJson + childrenJson + propsFromParentJson).toString() + params.toString()).length < 1500;
77	}
78};
79var Backend_default = class {
80	constructor(url, method = "post", credentials = "same-origin") {
81		this.requestBuilder = new RequestBuilder_default(url, method, credentials);
82	}
83	makeRequest(props, actions, updated, children, updatedPropsFromParent, files) {
84		const { url, fetchOptions } = this.requestBuilder.buildRequest(props, actions, updated, children, updatedPropsFromParent, files);
85		return new BackendRequest_default(fetch(url, fetchOptions), actions.map((backendAction) => backendAction.name), Object.keys(updated));
86	}
87};
88var BackendResponse_default = class {
89	constructor(response) {
90		this.response = response;
91	}
92	async getBody() {
93		if (!this.body) this.body = await this.response.text();
94		return this.body;
95	}
96	getLiveUrl() {
97		if (void 0 === this.liveUrl) this.liveUrl = this.response.headers.get("X-Live-Url");
98		return this.liveUrl;
99	}
100};
101function getElementAsTagText(element) {
102	return element.innerHTML ? element.outerHTML.slice(0, element.outerHTML.indexOf(element.innerHTML)) : element.outerHTML;
103}
104let componentMapByElement = /* @__PURE__ */ new WeakMap();
105let componentMapByComponent = /* @__PURE__ */ new Map();
106const registerComponent = (component) => {
107	componentMapByElement.set(component.element, component);
108	componentMapByComponent.set(component, component.name);
109};
110const unregisterComponent = (component) => {
111	componentMapByElement.delete(component.element);
112	componentMapByComponent.delete(component);
113};
114const getComponent = (element) => new Promise((resolve, reject) => {
115	let count = 0;
116	const maxCount = 10;
117	const interval = setInterval(() => {
118		const component = componentMapByElement.get(element);
119		if (component) {
120			clearInterval(interval);
121			resolve(component);
122		}
123		count++;
124		if (count > maxCount) {
125			clearInterval(interval);
126			reject(/* @__PURE__ */ new Error(`Component not found for element ${getElementAsTagText(element)}`));
127		}
128	}, 5);
129});
130const findComponents = (currentComponent, onlyParents, onlyMatchName) => {
131	const components = [];
132	componentMapByComponent.forEach((componentName, component) => {
133		if (onlyParents && (currentComponent === component || !component.element.contains(currentComponent.element))) return;
134		if (onlyMatchName && componentName !== onlyMatchName) return;
135		components.push(component);
136	});
137	return components;
138};
139const findChildren = (currentComponent) => {
140	const children = [];
141	componentMapByComponent.forEach((componentName, component) => {
142		if (currentComponent === component) return;
143		if (!currentComponent.element.contains(component.element)) return;
144		let foundChildComponent = false;
145		componentMapByComponent.forEach((childComponentName, childComponent) => {
146			if (foundChildComponent) return;
147			if (childComponent === component) return;
148			if (childComponent.element.contains(component.element)) foundChildComponent = true;
149		});
150		children.push(component);
151	});
152	return children;
153};
154const findParent = (currentComponent) => {
155	let parentElement = currentComponent.element.parentElement;
156	while (parentElement) {
157		const component = componentMapByElement.get(parentElement);
158		if (component) return component;
159		parentElement = parentElement.parentElement;
160	}
161	return null;
162};
163function parseDirectives(content) {
164	const directives = [];
165	if (!content) return directives;
166	let currentActionName = "";
167	let currentArgumentValue = "";
168	let currentArguments = [];
169	let currentModifiers = [];
170	let state = "action";
171	const getLastActionName = () => {
172		if (currentActionName) return currentActionName;
173		if (directives.length === 0) throw new Error("Could not find any directives");
174		return directives[directives.length - 1].action;
175	};
176	const pushInstruction = () => {
177		directives.push({
178			action: currentActionName,
179			args: currentArguments,
180			modifiers: currentModifiers,
181			getString: () => {
182				return content;
183			}
184		});
185		currentActionName = "";
186		currentArgumentValue = "";
187		currentArguments = [];
188		currentModifiers = [];
189		state = "action";
190	};
191	const pushArgument = () => {
192		currentArguments.push(currentArgumentValue.trim());
193		currentArgumentValue = "";
194	};
195	const pushModifier = () => {
196		if (currentArguments.length > 1) throw new Error(`The modifier "${currentActionName}()" does not support multiple arguments.`);
197		currentModifiers.push({
198			name: currentActionName,
199			value: currentArguments.length > 0 ? currentArguments[0] : null
200		});
201		currentActionName = "";
202		currentArguments = [];
203		state = "action";
204	};
205	for (let i = 0; i < content.length; i++) {
206		const char = content[i];
207		switch (state) {
208			case "action":
209				if (char === "(") {
210					state = "arguments";
211					break;
212				}
213				if (char === " ") {
214					if (currentActionName) pushInstruction();
215					break;
216				}
217				if (char === "|") {
218					pushModifier();
219					break;
220				}
221				currentActionName += char;
222				break;
223			case "arguments":
224				if (char === ")") {
225					pushArgument();
226					state = "after_arguments";
227					break;
228				}
229				if (char === ",") {
230					pushArgument();
231					break;
232				}
233				currentArgumentValue += char;
234				break;
235			case "after_arguments":
236				if (char === "|") {
237					pushModifier();
238					break;
239				}
240				if (char !== " ") throw new Error(`Missing space after ${getLastActionName()}()`);
241				pushInstruction();
242				break;
243		}
244	}
245	switch (state) {
246		case "action":
247		case "after_arguments":
248			if (currentActionName) pushInstruction();
249			break;
250		default: throw new Error(`Did you forget to add a closing ")" after "${currentActionName}"?`);
251	}
252	return directives;
253}
254function combineSpacedArray(parts) {
255	const finalParts = [];
256	parts.forEach((part) => {
257		finalParts.push(...trimAll(part).split(" "));
258	});
259	return finalParts;
260}
261function trimAll(str) {
262	return str.replace(/[\s]+/g, " ").trim();
263}
264function normalizeModelName(model) {
265	return model.replace(/\[]$/, "").split("[").map((s) => s.replace("]", "")).join(".");
266}
267function getValueFromElement(element, valueStore) {
268	if (element instanceof HTMLInputElement) {
269		if (element.type === "checkbox") {
270			const modelNameData = getModelDirectiveFromElement(element, false);
271			if (modelNameData !== null) {
272				const modelValue = valueStore.get(modelNameData.action);
273				if (Array.isArray(modelValue)) return getMultipleCheckboxValue(element, modelValue);
274				if (Object(modelValue) === modelValue) return getMultipleCheckboxValue(element, Object.values(modelValue));
275			}
276			if (element.hasAttribute("value")) return element.checked ? element.getAttribute("value") : null;
277			return element.checked;
278		}
279		return inputValue(element);
280	}
281	if (element instanceof HTMLSelectElement) {
282		if (element.multiple) return Array.from(element.selectedOptions).map((el) => el.value);
283		return element.value;
284	}
285	if (element.hasAttribute("data-value")) return element.dataset.value;
286	if ("value" in element) return element.value;
287	if (element.hasAttribute("value")) return element.getAttribute("value");
288	return null;
289}
290function setValueOnElement(element, value) {
291	if (element instanceof HTMLInputElement) {
292		if (element.type === "file") return;
293		if (element.type === "radio") {
294			element.checked = element.value == value;
295			return;
296		}
297		if (element.type === "checkbox") {
298			if (Array.isArray(value)) element.checked = value.some((val) 
298=> val == element.value);
299			else if (element.hasAttribute("value")) element.checked = element.value == value;
300			else element.checked = value;
301			return;
302		}
303	}
304	if (element instanceof HTMLSelectElement) {
305		const arrayWrappedValue = [].concat(value).map((value) => {
306			return `${value}`;
307		});
308		Array.from(element.options).forEach((option) => {
309			option.selected = arrayWrappedValue.includes(option.value);
310		});
311		return;
312	}
313	value = value === void 0 ? "" : value;
314	element.value = value;
315}
316function getAllModelDirectiveFromElements(element) {
317	if (!element.dataset.model) return [];
318	const directives = parseDirectives(element.dataset.model);
319	directives.forEach((directive) => {
320		if (directive.args.length > 0) throw new Error(`The data-model="${element.dataset.model}" format is invalid: it does not support passing arguments to the model.`);
321		directive.action = normalizeModelName(directive.action);
322	});
323	return directives;
324}
325function getModelDirectiveFromElement(element, throwOnMissing = true) {
326	const dataModelDirectives = getAllModelDirectiveFromElements(element);
327	if (dataModelDirectives.length > 0) return dataModelDirectives[0];
328	if (element.getAttribute("name")) {
329		const formElement = element.closest("form");
330		if (formElement && "model" in formElement.dataset) {
331			const directive = parseDirectives(formElement.dataset.model || "*")[0];
332			if (directive.args.length > 0) throw new Error(`The data-model="${formElement.dataset.model}" format is invalid: it does not support passing arguments to the model.`);
333			directive.action = normalizeModelName(element.getAttribute("name"));
334			return directive;
335		}
336	}
337	if (!throwOnMissing) return null;
338	throw new Error(`Cannot determine the model name for "${getElementAsTagText(element)}": the element must either have a "data-model" (or "name" attribute living inside a <form data-model="*">).`);
339}
340function elementBelongsToThisComponent(element, component) {
341	if (component.element === element) return true;
342	if (!component.element.contains(element)) return false;
343	return element.closest("[data-controller~=\"live\"]") === component.element;
344}
345function cloneHTMLElement(element) {
346	const newElement = element.cloneNode(true);
347	if (!(newElement instanceof HTMLElement)) throw new Error("Could not clone element");
348	return newElement;
349}
350function htmlToElement(html) {
351	const template = document.createElement("template");
352	html = html.trim();
353	template.innerHTML = html;
354	if (template.content.childElementCount > 1) throw new Error(`Component HTML contains ${template.content.childElementCount} elements, but only 1 root element is allowed.`);
355	const child = template.content.firstElementChild;
356	if (!child) throw new Error("Child not found");
357	if (!(child instanceof HTMLElement)) throw new Error(`Created element is not an HTMLElement: ${html.trim()}`);
358	return child;
359}
360const getMultipleCheckboxValue = (element, currentValues) => {
361	const finalValues = [...currentValues];
362	const value = inputValue(element);
363	const index = currentValues.indexOf(value);
364	if (element.checked) {
365		if (index === -1) finalValues.push(value);
366		return finalValues;
367	}
368	if (index > -1) finalValues.splice(index, 1);
369	return finalValues;
370};
371const inputValue = (element) => element.dataset.value ? element.dataset.value : element.value;
372function isTextualInputElement(el) {
373	return el instanceof HTMLInputElement && [
374		"text",
375		"email",
376		"password",
377		"search",
378		"tel",
379		"url"
380	].includes(el.type);
381}
382function isTextareaElement(el) {
383	return el instanceof HTMLTextAreaElement;
384}
385function isNumericalInputElement(element) {
386	return element instanceof HTMLInputElement && ["number", "range"].includes(element.type);
387}
388var HookManager_default = class {
389	constructor() {
390		this.hooks = /* @__PURE__ */ new Map();
391	}
392	register(hookName, callback) {
393		const hooks = this.hooks.get(hookName) || [];
394		hooks.push(callback);
395		this.hooks.set(hookName, hooks);
396	}
397	unregister(hookName, callback) {
398		const hooks = this.hooks.get(hookName) || [];
399		const index = hooks.indexOf(callback);
400		if (index === -1) return;
401		hooks.splice(index, 1);
402		this.hooks.set(hookName, hooks);
403	}
404	triggerHook(hookName, ...args) {
405		(this.hooks.get(hookName) || []).forEach((callback) => {
406			callback(...args);
407		});
408	}
409};
410var Idiomorph = (function() {
411	"use strict";
412	let EMPTY_SET = /* @__PURE__ */ new Set();
413	let defaults = {
414		morphStyle: "outerHTML",
415		callbacks: {
416			beforeNodeAdded: noOp,
417			afterNodeAdded: noOp,
418			beforeNodeMorphed: noOp,
419			afterNodeMorphed: noOp,
420			beforeNodeRemoved: noOp,
421			afterNodeRemoved: noOp,
422			beforeAttributeUpdated: noOp
423		},
424		head: {
425			style: "merge",
426			shouldPreserve: function(elt) {
427				return elt.getAttribute("im-preserve") === "true";
428			},
429			shouldReAppend: function(elt) {
430				return elt.getAttribute("im-re-append") === "true";
431			},
432			shouldRemove: noOp,
433			afterHeadMorphed: noOp
434		}
435	};
436	function morph(oldNode, newContent, config = {}) {
437		if (oldNode instanceof Document) oldNode = oldNode.documentElement;
438		if (typeof newContent === "string") newContent = parseContent(newContent);
439		let normalizedContent = normalizeContent(newContent);
440		let ctx = createMorphContext(oldNode, normalizedContent, config);
441		return morphNormalizedContent(oldNode, normalizedContent, ctx);
442	}
443	function morphNormalizedContent(oldNode, normalizedNewContent, ctx) {
444		if (ctx.head.block) {
445			let oldHead = oldNode.querySelector("head");
446			let newHead = normalizedNewContent.querySelector("head");
447			if (oldHead && newHead) {
448				let promises = handleHeadElement(newHead, oldHead, ctx);
449				Promise.all(promises).then(function() {
450					morphNormalizedContent(oldNode, normalizedNewContent, Object.assign(ctx, { head: {
451						block: false,
452						ignore: true
453					} }));
454				});
455				return;
456			}
457		}
458		if (ctx.morphStyle === "innerHTML") {
459			morphChildren(normalizedNewContent, oldNode, ctx);
460			return oldNode.children;
461		} else if (ctx.morphStyle === "outerHTML" || ctx.morphStyle == null) {
462			let bestMatch = findBestNodeMatch(normalizedNewContent, oldNode, ctx);
463			let previousSibling = bestMatch?.previousSibling;
464			let nextSibling = bestMatch?.nextSibling;
465			let morphedNode = morphOldNodeTo(oldNode, bestMatch, ctx);
466			if (bestMatch) return insertSiblings(previousSibling, morphedNode, nextSibling);
467			else return [];
468		} else throw "Do not understand how to morph style " + ctx.morphStyle;
469	}
470	function ignoreValueOfActiveElement(possibleActiveElement, ctx) {
471		return ctx.ignoreActiveValue && possibleActiveElement === document.activeElement;
472	}
473	function morphOldNodeTo(oldNode, newContent, ctx) {
474		if (ctx.ignoreActive && oldNode === document.activeElement) {} else if (newContent == null) {
475			if (ctx.callbacks.beforeNodeRemoved(oldNode) === false) return oldNode;
476			oldNode.remove();
477			ctx.callbacks.afterNodeRemoved(oldNode);
478			return null;
479		} else if (!isSoftMatch(oldNode, newContent)) {
480			if (ctx.callbacks.beforeNodeRemoved(oldNode) === false) return oldNode;
481			if (ctx.callbacks.beforeNodeAdded(newContent) === false) return oldNode;
482			oldNode.parentElement.replaceChild(newContent, oldNode);
483			ctx.callbacks.afterNodeAdded(newContent);
484			ctx.callbacks.afterNodeRemoved(oldNode);
485			return newContent;
486		} else {
487			if (ctx.callbacks.beforeNodeMorphed(oldNode, newContent) === false) return oldNode;
488			if (oldNode instanceof HTMLHeadElement && ctx.head.ignore) {} else if (oldNode instanceof HTMLHeadElement && ctx.head.style !== "morph") handleHeadElement(newContent, oldNode, ctx);
489			else {
490				syncNodeFrom(newContent, oldNode, ctx);
491				if (!ignoreValueOfActiveElement(oldNode, ctx)) morphChildren(newContent, oldNode, ctx);
492			}
493			ctx.callbacks.afterNodeMorphed(oldNode, newContent);
494			return oldNode;
495		}
496	}
497	function morphChildren(newParent, oldParent, ctx) {
498		let nextNewChild = newParent.firstChild;
499		let insertionPoint = oldParent.firstChild;
500		let newChild;
501		while (nextNewChild) {
502			newChild = nextNewChild;
503			nextNewChild = newChild.nextSibling;
504			if (insertionPoint == null) {
505				if (ctx.callbacks.beforeNodeAdded(newChild) === false) return;
506				oldParent.appendChild(newChild);
507				ctx.callbacks.afterNodeAdded(newChild);
508				removeIdsFromConsideration(ctx, newChild);
509				continue;
510			}
511			if (isIdSetMatch(newChild, insertionPoint, ctx)) {
512				morphOldNodeTo(insertionPoint, newChild, ctx);
513				insertionPoint = insertionPoint.nextSibling;
514				removeIdsFromConsideration(ctx, newChild);
515				continue;
516			}
517			let idSetMatch = findIdSetMatch(newParent, oldParent, newChild, insertionPoint, ctx);
518			if (idSetMatch) {
519				insertionPoint = removeNodesBetween(insertionPoint, idSetMatch, ctx);
520				morphOldNodeTo(idSetMatch, newChild, ctx);
521				removeIdsFromConsideration(ctx, newChild);
522				continue;
523			}
524			let softMatch = findSoftMatch(newParent, oldParent, newChild, insertionPoint, ctx);
525			if (softMatch) {
526				insertionPoint = removeNodesBetween(insertionPoint, softMatch, ctx);
527				morphOldNodeTo(softMatch, newChild, ctx);
528				removeIdsFromConsideration(ctx, newChild);
529				continue;
530			}
531			if (ctx.callbacks.beforeNodeAdded(newChild) === false) return;
532			oldParent.insertBefore(newChild, insertionPoint);
533			ctx.callbacks.afterNodeAdded(newChild);
534			removeIdsFromConsideration(ctx, newChild);
535		}
536		while (insertionPoint !== null) {
537			let tempNode = insertionPoint;
538			insertionPoint = insertionPoint.nextSibling;
539			removeNode(tempNode, ctx);
540		}
541	}
542	function ignoreAttribute(attr, to, updateType, ctx) {
543		if (attr === "value" && ctx.ignoreActiveValue && to === document.activeElement) return true;
544		return ctx.callbacks.beforeAttributeUpdated(attr, to, updateType) === false;
545	}
546	function syncNodeFrom(from, to, ctx) {
547		let type = from.nodeType;
548		if (type === 1) {
549			const fromAttributes = from.attributes;
550			const toAttributes = to.attributes;
551			for (const fromAttribute of fromAttributes) {
552				if (ignoreAttribute(fromAttribute.name, to, "update", ctx)) continue;
553				if (to.getAttribute(fromAttribute.name) !== fromAttribute.value) to.setAttribute(fromAttribute.name, fromAttribute.value);
554			}
555			for (let i = toAttributes.length - 1; 0 <= i; i--) {
556				const toAttribute = toAttributes[i];
557				if (ignoreAttribute(toAttribute.name, to, "remove", ctx)) continue;
558				if (!from.hasAttribute(toAttribute.name)) to.removeAttribute(toAttribute.name);
559			}
560		}
561		if (type === 8 || type === 3) {
562			if (to.nodeValue !== from.nodeValue) to.nodeValue = from.nodeValue;
563		}
564		if (!ignoreValueOfActiveElement(to, ctx)) syncInputValue(from, to, ctx);
565	}
566	function syncBooleanAttribute(from, to, attributeName, ctx) {
567		if (from[attributeName] !== to[attributeName]) {
568			let ignoreUpdate = ignoreAttribute(attributeName, to, "update", ctx);
569			if (!ignoreUpdate) to[attributeName] = from[attributeName];
570			if (from[attributeName]) {
571				if (!ignoreUpdate) to.setAttribute(attributeName, from[attributeName]);
572			} else if (!ignoreAttribute(attributeName, to, "remove", ctx)) to.removeAttribute(attributeName);
573		}
574	}
575	function syncInputValue(from, to, ctx) {
576		if (from instanceof HTMLInputElement && to instanceof HTMLInputElement && from.type !== "file") {
577			let fromValue = from.value;
578			let toValue = to.value;
579			syncBooleanAttribute(from, to, "checked", ctx);
580			syncBooleanAttribute(from, to, "disabled", ctx);
581			if (!from.hasAttribute("value")) {
582				if (!ignoreAttribute("value", to, "remove", ctx)) {
583					to.value = "";
584					to.removeAttribute("value");
585				}
586			} else if (fromValue !== toValue) {
587				if (!ignoreAttribute("value", to, "update", ctx)) {
588					to.setAttribute("value", fromValue);
589					to.value = fromValue;
590				}
591			}
592		} else if (from instanceof HTMLOptionElement) syncBooleanAttribute(from, to, "selected", ctx);
593		else if (from instanceof HTMLTextAreaElement && to instanceof HTMLTextAreaElement) {
594			let fromValue = from.value;
595			let toValue = to.value;
596			if (ignoreAttribute("value", to, "update", ctx)) return;
597			if (fromValue !== toValue) to.value = fromValue;
598			if (to.firstChild && to.firstChild.nodeValue !== fromValue) to.firstChild.nodeValue = fromValue;
599		}
600	}
601	function handleHeadElement(newHeadTag, currentHead, ctx) {
602		let added = [];
603		let removed = [];
604		let preserved = [];
605		let nodesToAppend = [];
606		let headMergeStyle = ctx.head.style;
607		let srcToNewHeadNodes = /* @__PURE__ */ new Map();
608		for (const newHeadChild of newHeadTag.children) srcToNewHeadNodes.set(newHeadChild.outerHTML, newHeadChild);
609		for (const currentHeadElt of currentHead.children) {
610			let inNewContent = srcToNewHeadNodes.has(currentHeadElt.outerHTML);
611			let isReAppended = ctx.head.shouldReAppend(currentHeadElt);
612			let isPreserved = ctx.head.shouldPreserve(currentHeadElt);
613			if (inNewContent || isPreserved) if (isReAppended) removed.push(currentHeadElt);
614			else {
615				srcToNewHeadNodes.delete(currentHeadElt.outerHTML);
616				preserved.push(currentHeadElt);
617			}
618			else if (headMergeStyle === "append") {
619				if (isReAppended) {
620					removed.push(currentHeadElt);
621					nodesToAppend.push(currentHeadElt);
622				}
623			} else if (ctx.head.shouldRemove(currentHeadElt) !== false) removed.push(currentHeadElt);
624		}
625		nodesToAppend.push(...srcToNewHeadNodes.values());
626		log("to append: ", nodesToAppend);
627		let promises = [];
628		for (const newNode of nodesToAppend) {
629			log("adding: ", newNode);
630			let newElt = document.createRange().createContextualFragment(newNode.outerHTML).firstChild;
631			log(newElt);
632			if (ctx.callbacks.beforeNodeAdded(newElt) !== false) {
633				if (newElt.href || newElt.src) {
634					let resolve = null;
635					let promise = new Promise(function(_resolve) {
636						resolve = _resolve;
637					});
638					newElt.addEventListener("load", function() {
639						resolve();
640					});
641					promises.push(promise);
642				}
643				currentHead.appendChild(newElt);
644				ctx.callbacks.afterNodeAdded(newElt);
645				added.push(newElt);
646			}
647		}
648		for (const removedElement of removed) if (ctx.callbacks.beforeNodeRemoved(removedElement) !== false) {
649			currentHead.removeChild(removedElement);
650			ctx.callbacks.afterNodeRemoved(removedElement);
651		}
652		ctx.head.afterHeadMorphed(currentHead, {
653			added,
654			kept: preserved,
655			removed
656		});
657		return promises;
658	}
659	function log() {}
660	function noOp() {}
661	function mergeDefaults(config) {
662		let finalConfig = {};
663		Object.assign(finalConfig, defaults);
664		Object.assign(finalConfig, config);
665		finalConfig.callbacks = {};
666		Object.assign(finalConfig.callbacks, defaults.callbacks);
667		Object.assign(finalConfig.callbacks, config.callbacks);
668		finalConfig.head = {};
669		Object.assign(finalConfig.head, defaults.head);
670		Object.assign(finalConfig.head, config.head);
671		return finalConfig;
672	}
673	function createMorphContext(oldNode, newContent, config) {
674		config = mergeDefaults(config);
675		return {
676			target: oldNode,
677			newContent,
678			config,
679			morphStyle: config.morphStyle,
680			ignoreActive: config.ignoreActive,
681			ignoreActiveValue: config.ignoreActiveValue,
682			idMap: createIdMap(oldNode, newContent),
683			deadIds: /* @__PURE__ */ new Set(),
684			callbacks: config.callbacks,
685			head: config.head
686		};
687	}
688	function isIdSetMatch(node1, node2, ctx) {
689		if (node1 == null || node2 == null) return false;
690		if (node1.nodeType === node2.nodeType && node1.tagName === node2.tagName) if (node1.id !== "" && node1.id === node2.id) return true;
691		else return getIdIntersectionCount(ctx, node1, node2) > 0;
692		return false;
693	}
694	function isSoftMatch(node1, node2) {
695		if (node1 == null || node2 == null) return false;
696		return node1.nodeType === node2.nodeType && node1.tagName === node2.tagName;
697	}
698	function removeNodesBetween(startInclusive, endExclusive, ctx) {
699		while (startInclusive !== endExclusive) {
700			let tempNode = startInclusive;
701			startInclusive = startInclusive.nextSibling;
702			removeNode(tempNode, ctx);
703		}
704		removeIdsFromConsideration(ctx, endExclusive);
705		return endExclusive.nextSibling;
706	}
707	function findIdSetMatch(newContent, oldParent, newChild, insertionPoint, ctx) {
708		let newChildPotentialIdCount = getIdIntersectionCount(ctx, newChild, oldParent);
709		let potentialMatch = null;
710		if (newChildPotentialIdCount > 0) {
711			let potentialMatch = insertionPoint;
712			let otherMatchCount = 0;
713			while (potentialMatch != null) {
714				if (isIdSetMatch(newChild, potentialMatch, ctx)) return potentialMatch;
715				otherMatchCount += getIdIntersectionCount(ctx, potentialMatch, newContent);
716				if (otherMatchCount > newChildPotentialIdCount) return null;
717				potentialMatch = potentialMatch.nextSibling;
718			}
719		}
720		return potentialMatch;
721	}
722	function findSoftMatch(newContent, oldParent, newChild, insertionPoint, ctx) {
723		let potentialSoftMatch = insertionPoint;
724		let nextSibling = newChild.nextSibling;
725		let siblingSoftMatchCount = 0;
726		while (potentialSoftMatch != null) {
727			if (getIdIntersectionCount(ctx, potentialSoftMatch, newContent) > 0) return null;
728			if (isSoftMatch(newChild, potentialSoftMatch)) return potentialSoftMatch;
729			if (isSoftMatch(nextSibling, potentialSoftMatch)) {
730				siblingSoftMatchCount++;
731				nextSibling = nextSibling.nextSibling;
732				if (siblingSoftMatchCount >= 2) return null;
733			}
734			potentialSoftMatch = potentialSoftMatch.nextSibling;
735		}
736		return potentialSoftMatch;
737	}
738	function parseContent(newContent) {
739		let parser = new DOMParser();
740		let contentWithSvgsRemoved = newContent.replace(/<svg(\s[^>]*>|>)([\s\S]*?)<\/svg>/gim, "");
741		if (contentWithSvgsRemoved.match(/<\/html>/) || contentWithSvgsRemoved.match(/<\/head>/) || contentWithSvgsRemoved.match(/<\/body>/)) {
742			let content = parser.parseFromString(newContent, "text/html");
743			if (contentWithSvgsRemoved.match(/<\/html>/)) {
744				content.generatedByIdiomorph = true;
745				return content;
746			} else {
747				let htmlElement = content.firstChild;
748				if (htmlElement) {
749					htmlElement.generatedByIdiomorph = true;
750					return htmlElement;
751				} else return null;
752			}
753		} else {
754			let content = parser.parseFromString("<body><template>" + newContent + "</template></body>", "text/html").body.querySelector("template").content;
755			content.generatedByIdiomorph = true;
756			return content;
757		}
758	}
759	function normalizeContent(newContent) {
760		if (newContent == null) return document.createElement("div");
761		else if (newContent.generatedByIdiomorph) return newContent;
762		else if (newContent instanceof Node) {
763			const dummyParent = document.createElement("div");
764			dummyParent.append(newContent);
765			return dummyParent;
766		} else {
767			const dummyParent = document.createElement("div");
768			for (const elt of [...newContent]) dummyParent.append(elt);
769			return dummyParent;
770		}
771	}
772	function insertSiblings(previousSibling, morphedNode, nextSibling) {
773		let stack = [];
774		let added = [];
775		while (previousSibling != null) {
776			stack.push(previousSibling);
777			previousSibling = previousSibling.previousSibling;
778		}
779		while (stack.length > 0) {
780			let node = stack.pop();
781			added.push(node);
782			morphedNode.parentElement.insertBefore(node, morphedNode);
783		}
784		added.push(morphedNode);
785		while (nextSibling != null) {
786			stack.push(nextSibling);
787			added.push(nextSibling);
788			nextSibling = nextSibling.nextSibling;
789		}
790		while (stack.length > 0) morphedNode.parentElement.insertBefore(stack.pop(), morphedNode.nextSibling);
791		return added;
792	}
793	function findBestNodeMatch(newContent, oldNode, ctx) {
794		let currentElement;
795		currentElement = newContent.firstChild;
796		let bestElement = currentElement;
797		let score = 0;
798		while (currentElement) {
799			let newScore = scoreElement(currentElement, oldNode, ctx);
800			if (newScore > score) {
801				bestElement = currentElement;
802				score = newScore;
803			}
804			currentElement = currentElement.nextSibling;
805		}
806		return bestElement;
807	}
808	function scoreElement(node1, node2, ctx) {
809		if (isSoftMatch(node1, node2)) return .5 + getIdIntersectionCount(ctx, node1, node2);
810		return 0;
811	}
812	function removeNode(tempNode, ctx) {
813		removeIdsFromConsideration(ctx, tempNode);
814		if (ctx.callbacks.beforeNodeRemoved(tempNode) === false) return;
815		tempNode.remove();
816		ctx.callbacks.afterNodeRemoved(tempNode);
817	}
818	function isIdInConsideration(ctx, id) {
819		return !ctx.deadIds.has(id);
820	}
821	function idIsWithinNode(ctx, id, targetNode) {
822		return (ctx.idMap.get(targetNode) || EMPTY_SET).has(id);
823	}
824	function removeIdsFromConsideration(ctx, node) {
825		let idSet = ctx.idMap.get(node) || EMPTY_SET;
826		for (const id of idSet) ctx.deadIds.add(id);
827	}
828	function getIdIntersectionCount(ctx, node1, node2) {
829		let sourceSet = ctx.idMap.get(node1) || EMPTY_SET;
830		let matchCount = 0;
831		for (const id of sourceSet) if (isIdInConsideration(ctx, id) && idIsWithinNode(ctx, id, node2)) ++matchCount;
832		return matchCount;
833	}
834	function populateIdMapForNode(node, idMap) {
835		let nodeParent = node.parentElement;
836		let idElements = node.querySelectorAll("[id]");
837		for (const elt of idElements) {
838			let current = elt;
839			while (current !== nodeParent && current != null) {
840				let idSet = idMap.get(current);
841				if (idSet == null) {
842					idSet = /* @__PURE__ */ new Set();
843					idMap.set(current, idSet);
844				}
845				idSet.add(elt.id);
846				current = current.parentElement;
847			}
848		}
849	}
850	function createIdMap(oldContent, newContent) {
851		let idMap = /* @__PURE__ */ new Map();
852		populateIdMapForNode(oldContent, idMap);
853		populateIdMapForNode(newContent, idMap);
854		return idMap;
855	}
856	return {
857		morph,
858		defaults
859	};
860})();
861function normalizeAttributesForComparison(element) {
862	if (!(element instanceof HTMLInputElement && element.type === "file")) {
863		if ("value" in element) element.setAttribute("value", element.value);
864		else if (element.hasAttribute("value")) element.setAttribute("value", "");
865	}
866	Array.from(element.children).forEach((child) => {
867		normalizeAttributesForComparison(child);
868	});
869}
870const syncAttributes = (fromEl, toEl) => {
871	for (let i = 0; i < fromEl.attributes.length; i++) {
872		const attr = fromEl.attributes[i];
873		toEl.setAttribute(attr.name, attr.value);
874	}
875};
876function executeMorphdom(rootFromElement, rootToElement, modifiedFieldElements, getElementValue, externalMutationTracker) {
877	const originalElementIdsToSwapAfter = [];
878	const originalElementsToPreserve = /* @__PURE__ */ new Map();
879	const markElementAsNeedingPostMorphSwap = (id, replaceWithClone) => {
880		const oldElement = originalElementsToPreserve.get(id);
881		if (!(oldElement instanceof HTMLElement)) throw new Error(`Original element with id ${id} not found`);
882		originalElementIdsToSwapAfter.push(id);
883		if (!replaceWithClone) return null;
884		const clonedOldElement = cloneHTMLElement(oldElement);
885		oldElement.replaceWith(clonedOldElement);
886		return clonedOldElement;
887	};
888	rootToElement.querySelectorAll("[data-live-preserve]").forEach((newElement) => {
889		const id = newElement.id;
890		if (!id) throw new Error("The data-live-preserve attribute requires an id attribute to be set on the element");
891		const oldElement = rootFromElement.querySelector(`#${id}`);
892		if (!(oldElement instanceof HTMLElement)) throw new Error(`The element with id "${id}" was not found in the original HTML`);
893		newElement.removeAttribute("data-live-preserve");
894		originalElementsToPreserve.set(id, oldElement);
895		syncAttributes(newElement, oldElement);
896	});
897	Idiomorph.morph(rootFromElement, rootToElement, { callbacks: {
898		beforeNodeMorphed: (fromEl, toEl) => {
899			if (!(fromEl instanceof Element) || !(toEl instanceof Element)) return true;
900			if (fromEl === rootFromElement) return true;
901			if (fromEl.id && originalElementsToPreserve.has(fromEl.id)) {
902				if (fromEl.id === toEl.id) return false;
903				const clonedFromEl = markElementAsNeedingPostMorphSwap(fromEl.id, true);
904				if (!clonedFromEl) throw new Error("missing clone");
905				Idiomorph.morph(clonedFromEl, toEl);
906				return false;
907			}
908			if (fromEl instanceof HTMLElement && toEl instanceof HTMLElement) {
909				if (typeof fromEl.__x !== "undefined") {
910					if (!window.Alpine) throw new Error("Unable to access Alpine.js though the global window.Alpine variable. Please make sure Alpine.js is loaded before Symfony UX LiveComponent.");
911					if (typeof window.Alpine.morph !== "function") throw new Error("Unable to access Alpine.js morph function. Please make sure the Alpine.js Morp
911h plugin is installed and loaded, see https://alpinejs.dev/plugins/morph for more information.");
912					window.Alpine.morph(fromEl.__x, toEl);
913				}
914				if (externalMutationTracker.wasElementAdded(fromEl)) {
915					fromEl.insertAdjacentElement("afterend", toEl);
916					return false;
917				}
918				if (modifiedFieldElements.includes(fromEl)) setValueOnElement(toEl, getElementValue(fromEl));
919				if (fromEl === document.activeElement && fromEl !== document.body && null !== getModelDirectiveFromElement(fromEl, false)) setValueOnElement(toEl, getElementValue(fromEl));
920				const elementChanges = externalMutationTracker.getChangedElement(fromEl);
921				if (elementChanges) elementChanges.applyToElement(toEl);
922				if (fromEl.nodeName.toUpperCase() !== "OPTION" && fromEl.isEqualNode(toEl)) {
923					const normalizedFromEl = cloneHTMLElement(fromEl);
924					normalizeAttributesForComparison(normalizedFromEl);
925					const normalizedToEl = cloneHTMLElement(toEl);
926					normalizeAttributesForComparison(normalizedToEl);
927					if (normalizedFromEl.isEqualNode(normalizedToEl)) return false;
928				}
929			}
930			if (fromEl.hasAttribute("data-skip-morph") || fromEl.id && fromEl.id !== toEl.id) {
931				fromEl.innerHTML = toEl.innerHTML;
932				return true;
933			}
934			if (fromEl.parentElement?.hasAttribute("data-skip-morph")) return false;
935			return !fromEl.hasAttribute("data-live-ignore");
936		},
937		beforeNodeRemoved(node) {
938			if (!(node instanceof HTMLElement)) return true;
939			if (node.id && originalElementsToPreserve.has(node.id)) {
940				markElementAsNeedingPostMorphSwap(node.id, false);
941				return true;
942			}
943			if (externalMutationTracker.wasElementAdded(node)) return false;
944			return !node.hasAttribute("data-live-ignore");
945		}
946	} });
947	originalElementIdsToSwapAfter.forEach((id) => {
948		const newElement = rootFromElement.querySelector(`#${id}`);
949		const originalElement = originalElementsToPreserve.get(id);
950		if (!(newElement instanceof HTMLElement) || !(originalElement instanceof HTMLElement)) throw new Error("Missing elements.");
951		newElement.replaceWith(originalElement);
952	});
953}
954var ChangingItemsTracker_default = class {
955	constructor() {
956		this.changedItems = /* @__PURE__ */ new Map();
957		this.removedItems = /* @__PURE__ */ new Map();
958	}
959	setItem(itemName, newValue, previousValue) {
960		if (this.removedItems.has(itemName)) {
961			const removedRecord = this.removedItems.get(itemName);
962			this.removedItems.delete(itemName);
963			if (removedRecord.original === newValue) return;
964		}
965		if (this.changedItems.has(itemName)) {
966			const originalRecord = this.changedItems.get(itemName);
967			if (originalRecord.original === newValue) {
968				this.changedItems.delete(itemName);
969				return;
970			}
971			this.changedItems.set(itemName, {
972				original: originalRecord.original,
973				new: newValue
974			});
975			return;
976		}
977		this.changedItems.set(itemName, {
978			original: previousValue,
979			new: newValue
980		});
981	}
982	removeItem(itemName, currentValue) {
983		let trueOriginalValue = currentValue;
984		if (this.changedItems.has(itemName)) {
985			trueOriginalValue = this.changedItems.get(itemName).original;
986			this.changedItems.delete(itemName);
987			if (trueOriginalValue === null) return;
988		}
989		if (!this.removedItems.has(itemName)) this.removedItems.set(itemName, { original: trueOriginalValue });
990	}
991	getChangedItems() {
992		return Array.from(this.changedItems, ([name, { new: value }]) => ({
993			name,
994			value
995		}));
996	}
997	getRemovedItems() {
998		return Array.from(this.removedItems.keys());
999	}
1000	isEmpty() {
1001		return this.changedItems.size === 0 && this.removedItems.size === 0;
1002	}
1003};
1004var ElementChanges = class {
1005	constructor() {
1006		this.addedClasses = /* @__PURE__ */ new Set();
1007		this.removedClasses = /* @__PURE__ */ new Set();
1008		this.styleChanges = new ChangingItemsTracker_default();
1009		this.attributeChanges = new ChangingItemsTracker_default();
1010	}
1011	addClass(className) {
1012		if (!this.removedClasses.delete(className)) this.addedClasses.add(className);
1013	}
1014	removeClass(className) {
1015		if (!this.addedClasses.delete(className)) this.removedClasses.add(className);
1016	}
1017	addStyle(styleName, newValue, originalValue) {
1018		this.styleChanges.setItem(styleName, newValue, originalValue);
1019	}
1020	removeStyle(styleName, originalValue) {
1021		this.styleChanges.removeItem(styleName, originalValue);
1022	}
1023	addAttribute(attributeName, newValue, originalValue) {
1024		this.attributeChanges.setItem(attributeName, newValue, originalValue);
1025	}
1026	removeAttribute(attributeName, originalValue) {
1027		this.attributeChanges.removeItem(attributeName, originalValue);
1028	}
1029	getAddedClasses() {
1030		return [...this.addedClasses];
1031	}
1032	getRemovedClasses() {
1033		return [...this.removedClasses];
1034	}
1035	getChangedStyles() {
1036		return this.styleChanges.getChangedItems();
1037	}
1038	getRemovedStyles() {
1039		return this.styleChanges.getRemovedItems();
1040	}
1041	getChangedAttributes() {
1042		return this.attributeChanges.getChangedItems();
1043	}
1044	getRemovedAttributes() {
1045		return this.attributeChanges.getRemovedItems();
1046	}
1047	applyToElement(element) {
1048		element.classList.add(...this.addedClasses);
1049		element.classList.remove(...this.removedClasses);
1050		this.styleChanges.getChangedItems().forEach((change) => {
1051			if (/!\s*important/i.test(change.value)) element.style.setProperty(change.name, change.value.replace(/!\s*important/i, "").trim(), "important");
1052			else element.style.setProperty(change.name, change.value);
1053		});
1054		this.styleChanges.getRemovedItems().forEach((styleName) => {
1055			element.style.removeProperty(styleName);
1056		});
1057		this.attributeChanges.getChangedItems().forEach((change) => {
1058			element.setAttribute(change.name, change.value);
1059		});
1060		this.attributeChanges.getRemovedItems().forEach((attributeName) => {
1061			element.removeAttribute(attributeName);
1062		});
1063	}
1064	isEmpty() {
1065		return this.addedClasses.size === 0 && this.removedClasses.size === 0 && this.styleChanges.isEmpty() && this.attributeChanges.isEmpty();
1066	}
1067};
1068var ExternalMutationTracker_default = class {
1069	constructor(element, shouldTrackChangeCallback) {
1070		this.changedElements = /* @__PURE__ */ new WeakMap();
1071		this.changedElementsCount = 0;
1072		this.addedElements = [];
1073		this.removedElements = [];
1074		this.isStarted = false;
1075		this.element = element;
1076		this.shouldTrackChangeCallback = shouldTrackChangeCallback;
1077		this.mutationObserver = new MutationObserver(this.onMutations.bind(this));
1078	}
1079	start() {
1080		if (this.isStarted) return;
1081		this.mutationObserver.observe(this.element, {
1082			childList: true,
1083			subtree: true,
1084			attributes: true,
1085			attributeOldValue: true
1086		});
1087		this.isStarted = true;
1088	}
1089	stop() {
1090		if (this.isStarted) {
1091			this.mutationObserver.disconnect();
1092			this.isStarted = false;
1093		}
1094	}
1095	getChangedElement(element) {
1096		return this.changedElements.has(element) ? this.changedElements.get(element) : null;
1097	}
1098	getAddedElements() {
1099		return this.addedElements;
1100	}
1101	wasElementAdded(element) {
1102		return this.addedElements.includes(element);
1103	}
1104	handlePendingChanges() {
1105		this.onMutations(this.mutationObserver.takeRecords());
1106	}
1107	onMutations(mutations) {
1108		const handledAttributeMutations = /* @__PURE__ */ new WeakMap();
1109		for (const mutation of mutations) {
1110			const element = mutation.target;
1111			if (!this.shouldTrackChangeCallback(element)) continue;
1112			if (this.isElementAddedByTranslation(element)) continue;
1113			let isChangeInAddedElement = false;
1114			for (const addedElement of this.addedElements) if (addedElement.contains(element)) {
1115				isChangeInAddedElement = true;
1116				break;
1117			}
1118			if (isChangeInAddedElement) continue;
1119			switch (mutation.type) {
1120				case "childList":
1121					this.handleChildListMutation(mutation);
1122					break;
1123				case "attributes":
1124					if (!handledAttributeMutations.has(element)) handledAttributeMutations.set(element, []);
1125					if (!handledAttributeMutations.get(element).includes(mutation.attributeName)) {
1126						this.handleAttributeMutation(mutation);
1127						handledAttributeMutations.set(element, [...handledAttributeMutations.get(element), mutation.attributeName]);
1128					}
1129					break;
1130			}
1131		}
1132	}
1133	handleChildListMutation(mutation) {
1134		mutation.addedNodes.forEach((node) => {
1135			if (!(node instanceof Element)) return;
1136			if (this.removedElements.includes(node)) {
1137				this.removedElements.splice(this.removedElements.indexOf(node), 1);
1138				return;
1139			}
1140			if (this.isElementAddedByTranslation(node)) return;
1141			this.addedElements.push(node);
1142		});
1143		mutation.removedNodes.forEach((node) => {
1144			if (!(node instanceof Element)) return;
1145			if (this.addedElements.includes(node)) {
1146				this.addedElements.splice(this.addedElements.indexOf(node), 1);
1147				return;
1148			}
1149			this.removedElements.push(node);
1150		});
1151	}
1152	handleAttributeMutation(mutation) {
1153		const element = mutation.target;
1154		if (!this.changedElements.has(element)) {
1155			this.changedElements.set(element, new ElementChanges());
1156			this.changedElementsCount++;
1157		}
1158		const changedElement = this.changedElements.get(element);
1159		switch (mutation.attributeName) {
1160			case "class":
1161				this.handleClassAttributeMutation(mutation, changedElement);
1162				break;
1163			case "style":
1164				this.handleStyleAttributeMutation(mutation, changedElement);
1165				break;
1166			default: this.handleGenericAttributeMutation(mutation, changedElement);
1167		}
1168		if (changedElement.isEmpty()) {
1169			this.changedElements.delete(element);
1170			this.changedElementsCount--;
1171		}
1172	}
1173	handleClassAttributeMutation(mutation, elementChanges) {
1174		const element = mutation.target;
1175		const previousValues = (mutation.oldValue || "").match(/(\S+)/gu) || [];
1176		const newValues = [].slice.call(element.classList);
1177		const addedValues = newValues.filter((value) => !previousValues.includes(value));
1178		const removedValues = previousValues.filter((value) => !newValues.includes(value));
1179		addedValues.forEach((value) => {
1180			elementChanges.addClass(value);
1181		});
1182		removedValues.forEach((value) => {
1183			elementChanges.removeClass(value);
1184		});
1185	}
1186	handleStyleAttributeMutation(mutation, elementChanges) {
1187		const element = mutation.target;
1188		const previousValue = mutation.oldValue || "";
1189		const previousStyles = this.extractStyles(previousValue);
1190		const newValue = element.getAttribute("style") || "";
1191		const newStyles = this.extractStyles(newValue);
1192		const addedOrChangedStyles = Object.keys(newStyles).filter((key) => previousStyles[key] === void 0 || previousStyles[key] !== newStyles[key]);
1193		const removedStyles = Object.keys(previousStyles).filter((key) => !newStyles[key]);
1194		addedOrChangedStyles.forEach((style) => {
1195			elementChanges.addStyle(style, newStyles[style], previousStyles[style] === void 0 ? null : previousStyles[style]);
1196		});
1197		removedStyles.forEach((style) => {
1198			elementChanges.removeStyle(style, previousStyles[style]);
1199		});
1200	}
1201	handleGenericAttributeMutation(mutation, elementChanges) {
1202		const attributeName = mutation.attributeName;
1203		const element = mutation.target;
1204		let oldValue = mutation.oldValue;
1205		let newValue = element.getAttribute(attributeName);
1206		if (oldValue === attributeName) oldValue = "";
1207		if (newValue === attributeName) newValue = "";
1208		if (!element.hasAttribute(attributeName)) {
1209			if (oldValue === null) return;
1210			elementChanges.removeAttribute(attributeName, mutation.oldValue);
1211			return;
1212		}
1213		if (newValue === oldValue) return;
1214		elementChanges.addAttribute(attributeName, element.getAttribute(attributeName), mutation.oldValue);
1215	}
1216	extractStyles(styles) {
1217		const styleObject = {};
1218		styles.split(";").forEach((style) => {
1219			const parts = style.split(":");
1220			if (parts.length === 1) return;
1221			const property = parts[0].trim();
1222			styleObject[property] = parts.slice(1).join(":").trim();
1223		});
1224		return styleObject;
1225	}
1226	isElementAddedByTranslation(element) {
1227		return element.tagName === "FONT" && element.getAttribute("style") === "vertical-align: inherit;";
1228	}
1229};
1230var UnsyncedInputsTracker_default = class {
1231	constructor(component, modelElementResolver) {
1232		this.elementEventListeners = [{
1233			event: "input",
1234			callback: (event) => this.handleInputEvent(event)
1235		}];
1236		this.component = component;
1237		this.modelElementResolver = modelElementResolver;
1238		this.unsyncedInputs = new UnsyncedInputContainer();
1239	}
1240	activate() {
1241		this.elementEventListeners.forEach(({ event, callback }) => {
1242			this.component.element.addEventListener(event, callback);
1243		});
1244	}
1245	deactivate() {
1246		this.elementEventListeners.forEach(({ event, callback }) => {
1247			this.component.element.removeEventListener(event, callback);
1248		});
1249	}
1250	markModelAsSynced(modelName) {
1251		this.unsyncedInputs.markModelAsSynced(modelName);
1252	}
1253	handleInputEvent(event) {
1254		const target = event.target;
1255		if (!target) return;
1256		this.updateModelFromElement(target);
1257	}
1258	updateModelFromElement(element) {
1259		if (!elementBelongsToThisComponent(element, this.component)) return;
1260		if (!(element instanceof HTMLElement)) throw new Error("Could not update model for non HTMLElement");
1261		const modelName = this.modelElementResolver.getModelName(element);
1262		this.unsyncedInputs.add(element, modelName);
1263	}
1264	getUnsyncedInputs() {
1265		return this.unsyncedInputs.allUnsyncedInputs();
1266	}
1267	getUnsyncedModels() {
1268		return Array.from(this.unsyncedInputs.getUnsyncedModelNames());
1269	}
1270	resetUnsyncedFields() {
1271		this.unsyncedInputs.resetUnsyncedFields();
1272	}
1273};
1274var UnsyncedInputContainer = class {
1275	constructor() {
1276		this.unsyncedNonModelFields = [];
1277		this.unsyncedModelNames = [];
1278		this.unsyncedModelFields = /* @__PURE__ */ new Map();
1279	}
1280	add(element, modelName = null) {
1281		if (modelName) {
1282			this.unsyncedModelFields.set(modelName, element);
1283			if (!this.unsyncedModelNames.includes(modelName)) this.unsyncedModelNames.push(modelName);
1284			return;
1285		}
1286		this.unsyncedNonModelFields.push(element);
1287	}
1288	resetUnsyncedFields() {
1289		this.unsyncedModelFields.forEach((value, key) => {
1290			if (!this.unsyncedModelNames.includes(key)) this.unsyncedModelFields.delete(key);
1291		});
1292	}
1293	allUnsyncedInputs() {
1294		return [...this.unsyncedNonModelFields, ...this.unsyncedModelFields.values()];
1295	}
1296	markModelAsSynced(modelName) {
1297		const index = this.unsyncedModelNames.indexOf(modelName);
1298		if (index !== -1) this.unsyncedModelNames.splice(index, 1);
1299	}
1300	getUnsyncedModelNames() {
1301		return this.unsyncedModelNames;
1302	}
1303};
1304function getDeepData(data, propertyPath) {
1305	const { currentLevelData, finalKey } = parseDeepData(data, propertyPath);
1306	if (currentLevelData === void 0) return;
1307	return currentLevelData[finalKey];
1308}
1309const parseDeepData = (data, propertyPath) => {
1310	const finalData = JSON.parse(JSON.stringify(data));
1311	let currentLevelData = finalData;
1312	const parts = propertyPath.split(".");
1313	for (let i = 0; i < parts.length - 1; i++) currentLevelData = currentLevelData[parts[i]];
1314	const finalKey = parts[parts.length - 1];
1315	return {
1316		currentLevelData,
1317		finalData,
1318		finalKey,
1319		parts
1320	};
1321};
1322var ValueStore_default = class {
1323	constructor(props) {
1324		this.props = {};
1325		this.dirtyProps = {};
1326		this.pendingProps = {};
1327		this.updatedPropsFromParent = {};
1328		this.props = props;
1329	}
1330	get(name) {
1331		const normalizedName = normalizeModelName(name);
1332		if (this.dirtyProps[normalizedName] !== void 0) return this.dirtyProps[normalizedName];
1333		if (this.pendingProps[normalizedName] !== void 0) return this.pendingProps[normalizedName];
1334		if (this.props[normalizedName] !== void 0) return this.props[normalizedName];
1335		return getDeepData(this.props, normalizedName);
1336	}
1337	has(name) {
1338		return this.get(name) !== void 0;
1339	}
1340	set(name, value) {
1341		const normalizedName = normalizeModelName(name);
1342		if (this.get(normalizedName) === value) return false;
1343		this.dirtyProps[normalizedName] = value;
1344		return true;
1345	}
1346	getOriginalProps() {
1347		return { ...this.props };
1348	}
1349	getDirtyProps() {
1350		return { ...this.dirtyProps };
1351	}
1352	getUpdatedPropsFromParent() {
1353		return { ...this.updatedPropsFromParent };
1354	}
1355	flushDirtyPropsToPending() {
1356		this.pendingProps = { ...this.dirtyProps };
1357		this.dirtyProps = {};
1358	}
1359	reinitializeAllProps(props) {
1360		this.props = props;
1361		this.updatedPropsFromParent = {};
1362		this.pendingProps = {};
1363	}
1364	pushPendingPropsBackToDirty() {
1365		this.dirtyProps = {
1366			...this.pendingProps,
1367			...this.dirtyProps
1368		};
1369		this.pendingProps = {};
1370	}
1371	storeNewPropsFromParent(props) {
1372		let changed = false;
1373		for (const [key, value] of Object.entries(props)) if (this.get(key) !== value) changed = true;
1374		if (changed) this.updatedPropsFromParent = props;
1375		return changed;
1376	}
1377};
1378var Component = class {
1379	constructor(element, name, props, listeners, id, backend, elementDriver) {
1380		this.fingerprint = "";
1381		this.defaultDebounce = 150;
1382		this.backendRequest = null;
1383		this.pendingActions = [];
1384		this.pendingFiles = {};
1385		this.isRequestPending = false;
1386		this.requestDebounceTimeout = null;
1387		this.element = element;
1388		this.name = name;
1389		this.backend = backend;
1390		this.elementDriver = elementDriver;
1391		this.id = id;
1392		this.listeners = /* @__PURE__ */ new Map();
1393		listeners.forEach((listener) => {
1394			if (!this.listeners.has(listener.event)) this.listeners.set(listener.event, []);
1395			this.listeners.get(listener.event)?.push(listener.action);
1396		});
1397		this.valueStore = new ValueStore_default(props);
1398		this.unsyncedInputsTracker = new UnsyncedInputsTracker_default(this, elementDriver);
1399		this.hooks = new HookManager_default();
1400		this.resetPromise();
1401		this.externalMutationTracker = new ExternalMutationTracker_default(this.element, (element) => elementBelongsToThisComponent(element, this));
1402		this.externalMutationTracker.start();
1403	}
1404	addPlugin(plugin) {
1405		plugin.attachToComponent(this);
1406	}
1407	connect() {
1408		registerComponent(this);
1409		this.hooks.triggerHook("connect", this);
1410		this.unsyncedInputsTracker.activate();
1411		this.externalMutationTracker.start();
1412	}
1413	disconnect() {
1414		unregisterComponent(this);
1415		this.hooks.triggerHook("disconnect", this);
1416		this.clearRequestDebounceTimeout();
1417		this.unsyncedInputsTracker.deactivate();
1418		this.externalMutationTracker.stop();
1419	}
1420	on(hookName, callback) {
1421		this.hooks.register(hookName, callback);
1422	}
1423	off(hookName, callback) {
1424		this.hooks.unregister(hookName, callback);
1425	}
1426	set(model, value, reRender = false, debounce = false) {
1427		const promise = this.nextRequestPromise;
1428		const modelName = normalizeModelName(model);
1429		if (!this.valueStore.has(modelName)) throw new Error(`Invalid model name "${model}".`);
1430		const isChanged = this.valueStore.set(modelName, value);
1431		this.hooks.triggerHook("model:set", model, value, this);
1432		this.unsyncedInputsTracker.markModelAsSynced(modelName);
1433		if (reRender && isChanged) this.debouncedStartRequest(debounce);
1434		return promise;
1435	}
1436	getData(model) {
1437		const modelName = normalizeModelName(model);
1438		if (!this.valueStore.has(modelName)) throw new Error(`Invalid model "${model}".`);
1439		return this.valueStore.get(modelName);
1440	}
1441	action(name, args = {}, debounce = false) {
1442		const promise = this.nextRequestPromise;
1443		this.pendingActions.push({
1444			name,
1445			args
1446		});
1447		this.debouncedStartRequest(debounce);
1448		return promise;
1449	}
1450	files(key, input) {
1451		this.pendingFiles[key] = input;
1452	}
1453	render() {
1454		const promise = this.nextRequestPromise;
1455		this.tryStartingRequest();
1456		return promise;
1457	}
1458	getUnsyncedModels() {
1459		return this.unsyncedInputsTracker.getUnsyncedModels();
1460	}
1461	emit(name, data, onlyMatchingComponentsNamed = null) {
1462		this.performEmit(name, data, false, onlyMatchingComponentsNamed);
1463	}
1464	emitUp(name, data, onlyMatchingComponentsNamed = null) {
1465		this.performEmit(name, data, true, onlyMatchingComponentsNamed);
1466	}
1467	emitSelf(name, data) {
1468		this.doEmit(name, data);
1469	}
1470	performEmit(name, data, emitUp, matchingName) {
1471		findComponents(this, emitUp, matchingName).forEach((component) => {
1472			component.doEmit(name, data);
1473		});
1474	}
1475	doEmit(name, data) {
1476		if (!this.listeners.has(name)) return;
1477		(this.listeners.get(name) || []).forEach((action) => {
1478			this.action(action, data, 1);
1479		});
1480	}
1481	isTurboEnabled() {
1482		return typeof Turbo !== "undefined" && !this.element.closest("[data-turbo=\"false\"]");
1483	}
1484	tryStartingRequest() {
1485		if (!this.backendRequest) {
1486			this.performRequest();
1487			return;
1488		}
1489		this.isRequestPending = true;
1490	}
1491	performRequest() {
1492		const thisPromiseResolve = this.nextRequestPromiseResolve;
1493		this.resetPromise();
1494		this.unsyncedInputsTracker.resetUnsyncedFields();
1495		const filesToSend = {};
1496		for (const [key, value] of Object.entries(this.pendingFiles)) if (value.files) filesToSend[key] = value.files;
1497		const requestConfig = {
1498			props: this.valueStore.getOriginalProps(),
1499			actions: this.pendingActions,
1500			updated: this.valueStore.getDirtyProps(),
1501			children: {},
1502			updatedPropsFromParent: this.valueStore.getUpdatedPropsFromParent(),
1503			files: filesToSend
1504		};
1505		this.hooks.triggerHook("request:started", requestConfig);
1506		this.backendRequest = this.backend.makeRequest(requestConfig.props, requestConfig.actions, requestConfig.updated, requestConfig.children, requestConfig.updatedPropsFromParent, requestConfig.files);
1507		this.hooks.triggerHook("loading.state:started", this.element, this.backendRequest);
1508		this.pendingActions = [];
1509		this.valueStore.flushDirtyPropsToPending();
1510		this.isRequestPending = false;
1511		this.backendRequest.promise.then(async (response) => {
1512			const backendResponse = new BackendResponse_default(response);
1513			const html = await backendResponse.getBody();
1514			for (const input of Object.values(this.pendingFiles)) input.value = "";
1515			const headers = backendResponse.response.headers;
1516			if (!headers.get("Content-Type")?.includes("application/vnd.live-component+html") && !headers.get("X-Live-Redirect")) {
1517				const controls = { displayError: true };
1518				this.valueStore.pushPendingPropsBackToDirty();
1519				this.hooks.triggerHook("response:error", backendResponse, controls);
1520				if (controls.displayError) this.renderError(html);
1521				this.backendRequest = null;
1522				thisPromiseResolve(backendResponse);
1523				return response;
1524			}
1525			const liveUrl = backendResponse.getLiveUrl();
1526			if (liveUrl) history.replaceState(history.state, "", new URL(liveUrl + window.location.hash, window.location.origin));
1527			this.processRerender(html, backendResponse);
1528			this.backendRequest = null;
1529			thisPromiseResolve(backendResponse);
1530			if (this.isRequestPending) {
1531				this.isRequestPending = false;
1532				this.performRequest();
1533			}
1534			return response;
1535		});
1536	}
1537	processRerender(html, backendResponse) {
1538		const controls = { shouldRender: true };
1539		this.hooks.triggerHook("render:started", html, backendResponse, controls);
1540		if (!controls.shouldRender) return;
1541		if (backendResponse.response.headers.get("Location")) {
1542			if (this.isTurboEnabled()) Turbo.visit(backendResponse.response.headers.get("Location"));
1543			else window.location.href = backendResponse.response.headers.get("Location") || "";
1544			return;
1545		}
1546		this.hooks.triggerHook("loading.state:finished", this.element);
1547		const modifiedModelValues = {};
1548		Object.keys(this.valueStore.getDirtyProps()).forEach((modelName) => {
1549			modifiedModelValues[modelName] = this.valueStore.get(modelName);
1550		});
1551		let newElement;
1552		try {
1553			newElement = htmlToElement(html);
1554			if (!newElement.matches("[data-controller~=live]")) throw new Error("A live component template must contain a single root controller element.");
1555		} catch (error) {
1556			console.error(`There was a problem with the '${this.name}' component HTML returned:`, { id: this.id });
1557			throw error;
1558		}
1559		this.externalMutationTracker.handlePendingChanges();
1560		this.externalMutationTracker.stop();
1561		executeMorphdom(this.element, newElement, this.unsyncedInputsTracker.getUnsyncedInputs(), (element) => getValueFromElement(element, this.valueStore), this.externalMutationTracker);
1562		this.externalMutationTracker.start();
1563		const newProps = this.elementDriver.getComponentProps();
1564		this.valueStore.reinitializeAllProps(newProps);
1565		const eventsToEmit = this.elementDriver.getEventsToEmit();
1566		const browserEventsToDispatch = this.elementDriver.getBrowserEventsToDispatch();
1567		Object.keys(modifiedModelValues).forEach((modelName) => {
1568			this.valueStore.set(modelName, modifiedModelValues[modelName]);
1569		});
1570		eventsToEmit.forEach(({ event, data, target, componentName }) => {
1571			if (target === "up") {
1572				this.emitUp(event, data, componentName);
1573				return;
1574			}
1575			if (target === "self") {
1576				this.emitSelf(event, data);
1577				return;
1578			}
1579			this.emit(event, data, componentName);
1580		});
1581		browserEventsToDispatch.forEach(({ event, payload }) => {
1582			this.element.dispatchEvent(new CustomEvent(event, {
1583				detail: payload,
1584				bubbles: true
1585			}));
1586		});
1587		this.hooks.triggerHook("render:finished", this);
1588	}
1589	calculateDebounce(debounce) {
1590		if (debounce === true) return this.defaultDebounce;
1591		if (debounce === false) return 0;
1592		return debounce;
1593	}
1594	clearRequestDebounceTimeout() {
1595		if (this.requestDebounceTimeout) {
1596			clearTimeout(this.requestDebounceTimeout);
1597			this.requestDebounceTimeout = null;
1598		}
1599	}
1600	debouncedStartRequest(debounce) {
1601		this.clearRequestDebounceTimeout();
1602		this.requestDebounceTimeout = window.setTimeout(() => {
1603			this.render();
1604		}, this.calculateDebounce(debounce));
1605	}
1606	renderError(html) {
1607		let modal = document.getElementById("live-component-error");
1608		if (modal) modal.innerHTML = "";
1609		else {
1610			modal = document.createElement("div");
1611			modal.id = "live-component-error";
1612			modal.style.padding = "50px";
1613			modal.style.backgroundColor = "rgba(0, 0, 0, .5)";
1614			modal.style.zIndex = "100000";
1615			modal.style.position = "fixed";
1616			modal.style.top = "0px";
1617			modal.style.bottom = "0px";
1618			modal.style.left = "0px";
1619			modal.style.right = "0px";
1620			modal.style.display = "flex";
1621			modal.style.flexDirection = "column";
1622		}
1623		const iframe = document.createElement("iframe");
1624		iframe.style.borderRadius = "5px";
1625		iframe.style.flexGrow = "1";
1626		modal.appendChild(iframe);
1627		document.body.prepend(modal);
1628		document.body.style.overflow = "hidden";
1629		if (iframe.contentWindow) {
1630			iframe.contentWindow.document.open();
1631			iframe.contentWindow.document.write(html);
1632			iframe.contentWindow.document.close();
1633		}
1634		const closeModal = (modal) => {
1635			if (modal) modal.outerHTML = "";
1636			document.body.style.overflow = "visible";
1637		};
1638		modal.addEventListener("click", () => closeModal(modal));
1639		modal.setAttribute("tabindex", "0");
1640		modal.addEventListener("keydown", (e) => {
1641			if (e.key === "Escape") closeModal(modal);
1642		});
1643		modal.focus();
1644	}
1645	resetPromise() {
1646		this.nextRequestPromise = new Promise((resolve) => {
1647			this.nextRequestPromiseResolve = resolve;
1648		});
1649	}
1650	_updateFromParentProps(props) {
1651		if (this.valueStore.storeNewPropsFromParent(props)) this.render();
1652	}
1653};
1654function proxifyComponent(component) {
1655	return new Proxy(component, {
1656		get(component, prop) {
1657			if (prop in component || typeof prop !== "string") {
1658				if (typeof component[prop] === "function") {
1659					const callable = component[prop];
1660					return (...args) => {
1661						return callable.apply(component, args);
1662					};
1663				}
1664				return Reflect.get(component, prop);
1665			}
1666			if (component.valueStore.has(prop)) return component.getData(prop);
1667			return (args) => {
1668				return component.action.apply(component, [prop, args]);
1669			};
1670		},
1671		set(target, property, value) {
1672			if (property in target) {
1673				target[property] = value;
1674				return true;
1675			}
1676			target.set(property, value);
1677			return true;
1678		}
1679	});
1680}
1681var StimulusElementDriver = class {
1682	constructor(controller) {
1683		this.controller = controller;
1684	}
1685	getModelName(element) {
1686		const modelDirective = getModelDirectiveFromElement(element, false);
1687		if (!modelDirective) return null;
1688		return modelDirective.action;
1689	}
1690	getComponentProps() {
1691		return this.controller.propsValue;
1692	}
1693	getEventsToEmit() {
1694		return this.controller.eventsToEmitValue;
1695	}
1696	getBrowserEventsToDispatch() {
1697		return this.controller.eventsToDispatchValue;
1698	}
1699};
1700function get_model_binding_default(modelDirective) {
1701	let shouldRender = true;
1702	let targetEventName = null;
1703	let debounce = false;
1704	let minLength = null;
1705	let maxLength = null;
1706	let minValue = null;
1707	let maxValue = null;
1708	modelDirective.modifiers.forEach((modifier) => {
1709		switch (modifier.name) {
1710			case "on":
1711				if (!modifier.value) throw new Error(`The "on" modifier in ${modelDirective.getString()} requires a value - e.g. on(change).`);
1712				if (!["input", "change"].includes(modifier.value)) throw new Error(`The "on" modifier in ${modelDirective.getString()} only accepts the arguments "input" or "change".`);
1713				targetEventName = modifier.value;
1714				break;
1715			case "norender":
1716				shouldRender = false;
1717				break;
1718			case "debounce":
1719				debounce = modifier.value ? Number.parseInt(modifier.value) : true;
1720				break;
1721			case "min_length":
1722				minLength = modifier.value ? Number.parseInt(modifier.value) : null;
1723				break;
1724			case "max_length":
1725				maxLength = modifier.value ? Number.parseInt(modifier.value) : null;
1726				break;
1727			case "min_value":
1728				minValue = modifier.value ? Number.parseFloat(modifier.value) : null;
1729				break;
1730			case "max_value":
1731				maxValue = modifier.value ? Number.parseFloat(modifier.value) : null;
1732				break;
1733			default: throw new Error(`Unknown modifier "${modifier.name}" in data-model="${modelDirective.getString()}".`);
1734		}
1735	});
1736	const [modelName, innerModelName] = modelDirective.action.split(":");
1737	return {
1738		modelName,
1739		innerModelName: innerModelName || null,
1740		shouldRender,
1741		debounce,
1742		targetEventName,
1743		minLength,
1744		maxLength,
1745		minValue,
1746		maxValue
1747	};
1748}
1749var ChildComponentPlugin_default = class {
1750	constructor(component) {
1751		this.parentModelBindings = [];
1752		this.component = component;
1753		this.parentModelBindings = getAllModelDirectiveFromElements(this.component.element).map(get_model_binding_default);
1754	}
1755	attachToComponent(component) {
1756		component.on("request:started", (requestData) => {
1757			requestData.children = this.getChildrenFingerprints();
1758		});
1759		component.on("model:set", (model, value) => {
1760			this.notifyParentModelChange(model, value);
1761		});
1762	}
1763	getChildrenFingerprints() {
1764		const fingerprints = {};
1765		this.getChildren().forEach((child) => {
1766			if (!child.id) throw new Error("missing id");
1767			fingerprints[child.id] = {
1768				fingerprint: child.fingerprint,
1769				tag: child.element.tagName.toLowerCase()
1770			};
1771		});
1772		return fingerprints;
1773	}
1774	notifyParentModelChange(modelName, value) {
1775		const parentComponent = findParent(this.component);
1776		if (!parentComponent) return;
1777		this.parentModelBindings.forEach((modelBinding) => {
1778			if ((modelBinding.innerModelName || "value") !== modelName) return;
1779			parentComponent.set(modelBinding.modelName, value, modelBinding.shouldRender, modelBinding.debounce);
1780		});
1781	}
1782	getChildren() {
1783		return findChildren(this.component);
1784	}
1785};
1786var LazyPlugin_default = class {
1787	constructor() {
1788		this.intersectionObserver = null;
1789	}
1790	attachToComponent(component) {
1791		if ("lazy" !== component.element.attributes.getNamedItem("loading")?.value) return;
1792		component.on("connect", () => {
1793			this.getObserver().observe(component.element);
1794		});
1795		component.on("disconnect", () => {
1796			this.intersectionObserver?.unobserve(component.element);
1797		});
1798	}
1799	getObserver() {
1800		if (!this.intersectionObserver) this.intersectionObserver = new IntersectionObserver((entries, observer) => {
1801			entries.forEach((entry) => {
1802				if (entry.isIntersecting) {
1803					entry.target.dispatchEvent(new CustomEvent("live:appear"));
1804					observer.unobserve(entry.target);
1805				}
1806			});
1807		});
1808		return this.intersectionObserver;
1809	}
1810};
1811var LoadingPlugin_default = class {
1812	attachToComponent(component) {
1813		component.on("loading.state:started", (element, request) => {
1814			this.startLoading(component, element, request);
1815		});
1816		component.on("loading.state:finished", (element) => {
1817			this.finishLoading(component, element);
1818		});
1819		this.finishLoading(component, component.element);
1820	}
1821	startLoading(component, targetElement, backendRequest) {
1822		this.handleLoadingToggle(component, true, targetElement, backendRequest);
1823	}
1824	finishLoading(component, targetElement) {
1825		this.handleLoadingToggle(component, false, targetElement, null);
1826	}
1827	handleLoadingToggle(component, isLoading, targetElement, backendRequest) {
1828		if (isLoading) this.addAttributes(targetElement, ["busy"]);
1829		else this.removeAttributes(targetElement, ["busy"]);
1830		this.getLoadingDirectives(component, targetElement).forEach(({ element, directives }) => {
1831			if (isLoading) this.addAttributes(element, ["data-live-is-loading"]);
1832			else this.removeAttributes(element, ["data-live-is-loading"]);
1833			directives.forEach((directive) => {
1834				this.handleLoadingDirective(element, isLoading, directive, backendRequest);
1835			});
1836		});
1837	}
1838	handleLoadingDirective(element, isLoading, directive, backendRequest) {
1839		const finalAction = parseLoadingAction(directive.action, isLoading);
1840		const targetedActions = [];
1841		const targetedModels = [];
1842		let delay = 0;
1843		const validModifiers = /* @__PURE__ */ new Map();
1844		validModifiers.set("delay", (modifier) => {
1845			if (!isLoading) return;
1846			delay = modifier.value ? Number.parseInt(modifier.value) : 200;
1847		});
1848		validModifiers.set("action", (modifier) => {
1849			if (!modifier.value) throw new Error(`The "action" in data-loading must have an action name - e.g. action(foo). It's missing for "${directive.getString()}"`);
1850			targetedActions.push(modifier.value);
1851		});
1852		validModifiers.set("model", (modifier) => {
1853			if (!modifier.value) throw new Error(`The "model" in data-loading must have an action name - e.g. model(foo). It's missing for "${directive.getString()}"`);
1854			targetedModels.push(modifier.value);
1855		});
1856		directive.modifiers.forEach((modifier) => {
1857			if (validModifiers.has(modifier.name)) {
1858				(validModifiers.get(modifier.name) ?? (() => {}))(modifier);
1859				return;
1860			}
1861			throw new Error(`Unknown modifier "${modifier.name}" used in data-loading="${directive.getString()}". Available modifiers are: ${Array.from(validModifiers.keys()).join(", ")}.`);
1862		});
1863		if (isLoading && targetedActions.length > 0 && backendRequest && !backendRequest.containsOneOfActions(targetedActions)) return;
1864		if (isLoading && targetedModels.length > 0 && backendRequest && !backendRequest.areAnyModelsUpdated(targetedModels)) return;
1865		let loadingDirective;
1866		switch (finalAction) {
1867			case "show":
1868				loadingDirective = () => this.showElement(element);
1869				break;
1870			case "hide":
1871				loadingDirective = () => this.hideElement(element);
1872				break;
1873			case "addClass":
1874				loadingDirective = () => this.addClass(element, directive.args);
1875				break;
1876			case "removeClass":
1877				loadingDirective = () => this.removeClass(element, directive.args);
1878				break;
1879			case "addAttribute":
1880				loadingDirective = () => this.addAttributes(element, directive.args);
1881				break;
1882			case "removeAttribute":
1883				loadingDirective = () => this.removeAttributes(element, directive.args);
1884				break;
1885			default: throw new Error(`Unknown data-loading action "${finalAction}"`);
1886		}
1887		if (delay) {
1888			window.setTimeout(() => {
1889				if (backendRequest && !backendRequest.isResolved) loadingDirective();
1890			}, delay);
1891			return;
1892		}
1893		loadingDirective();
1894	}
1895	getLoadingDirectives(component, element) {
1896		const loadingDirectives = [];
1897		let matchingElements = Array.from(element.querySelectorAll("[data-loading]"));
1898		matchingElements = matchingElements.filter((elt) => elementBelongsToThisComponent(elt, component));
1899		if (element.hasAttribute("data-loading")) matchingElements = [element, ...matchingElements];
1900		matchingElements.forEach((element) => {
1901			if (!(element instanceof HTMLElement) && !(element instanceof SVGElement)) throw new Error("Invalid Element Type");
1902			const directives = parseDirectives(element.dataset.loading || "show");
1903			loadingDirectives.push({
1904				element,
1905				directives
1906			});
1907		});
1908		return loadingDirectives;
1909	}
1910	showElement(element) {
1911		element.style.display = "revert";
1912	}
1913	hideElement(element) {
1914		element.style.display = "none";
1915	}
1916	addClass(element, classes) {
1917		element.classList.add(...combineSpacedArray(classes));
1918	}
1919	removeClass(element, classes) {
1920		element.classList.remove(...combineSpacedArray(classes));
1921		if (element.classList.length === 0) element.removeAttribute("class");
1922	}
1923	addAttributes(element, attributes) {
1924		attributes.forEach((attribute) => {
1925			element.setAttribute(attribute, "");
1926		});
1927	}
1928	removeAttributes(element, attributes) {
1929		attributes.forEach((attribute) => {
1930			element.removeAttribute(attribute);
1931		});
1932	}
1933};
1934const parseLoadingAction = (action, isLoading) => {
1935	switch (action) {
1936		case "show": return isLoading ? "show" : "hide";
1937		case "hide": return isLoading ? "hide" : "show";
1938		case "addClass": return isLoading ? "addClass" : "removeClass";
1939		case "removeClass": return isLoading ? "removeClass" : "addClass";
1940		case "addAttribute": return isLoading ? "addAttribute" : "removeAttribute";
1941		case "removeAttribute": return isLoading ? "removeAttribute" : "addAttribute";
1942	}
1943	throw new Error(`Unknown data-loading action "${action}"`);
1944};
1945var PageUnloadingPlugin_default = class {
1946	constructor() {
1947		this.isConnected = false;
1948	}
1949	attachToComponent(component) {
1950		component.on("render:started", (html, response, controls) => {
1951			if (!this.isConnected) controls.shouldRender = false;
1952		});
1953		component.on("connect", () => {
1954			this.isConnected = true;
1955		});
1956		component.on("disconnect", () => {
1957			this.isConnected = false;
1958		});
1959	}
1960};
1961var PollingDirector_default = class {
1962	constructor(component) {
1963		this.isPollingActive = true;
1964		this.pollingIntervals = [];
1965		this.component = component;
1966	}
1967	addPoll(actionName, duration) {
1968		this.polls.push({
1969			actionName,
1970			duration
1971		});
1972		if (this.isPollingActive) this.initiatePoll(actionName, duration);
1973	}
1974	startAllPolling() {
1975		if (this.isPollingActive) return;
1976		this.isPollingActive = true;
1977		this.polls.forEach(({ actionName, duration }) => {
1978			this.initiatePoll(actionName, duration);
1979		});
1980	}
1981	stopAllPolling() {
1982		this.isPollingActive = false;
1983		this.pollingIntervals.forEach((interval) => {
1984			clearInterval(interval);
1985		});
1986	}
1987	clearPolling() {
1988		this.stopAllPolling();
1989		this.polls = [];
1990		this.startAllPolling();
1991	}
1992	initiatePoll(actionName, duration) {
1993		let callback;
1994		if (actionName === "$render") callback = () => {
1995			this.component.render();
1996		};
1997		else callback = () => {
1998			this.component.action(actionName, {}, 0);
1999		};
2000		const timer = window.setInterval(() => {
2001			callback();
2002		}, duration);
2003		this.pollingIntervals.push(timer);
2004	}
2005};
2006var PollingPlugin_default = class {
2007	attachToComponent(component) {
2008		this.element = component.element;
2009		this.pollingDirector = new PollingDirector_default(component);
2010		this.initializePolling();
2011		component.on("connect", () => {
2012			this.pollingDirector.startAllPolling();
2013		});
2014		component.on("disconnect", () => {
2015			this.pollingDirector.stopAllPolling();
2016		});
2017		component.on("render:finished", () => {
2018			this.initializePolling();
2019		});
2020	}
2021	addPoll(actionName, duration) {
2022		this.pollingDirector.addPoll(actionName, duration);
2023	}
2024	clearPolling() {
2025		this.pollingDirector.clearPolling();
2026	}
2027	initializePolling() {
2028		this.clearPolling();
2029		if (this.element.dataset.poll === void 0) return;
2030		const rawPollConfig = this.element.dataset.poll;
2031		parseDirectives(rawPollConfig || "$render").forEach((directive) => {
2032			let duration = 2e3;
2033			directive.modifiers.forEach((modifier) => {
2034				switch (modifier.name) {
2035					case "delay":
2036						if (modifier.value) duration = Number.parseInt(modifier.value);
2037						break;
2038					default: console.warn(`Unknown modifier "${modifier.name}" in data-poll "${rawPollConfig}".`);
2039				}
2040			});
2041			this.addPoll(directive.action, duration);
2042		});
2043	}
2044};
2045var SetValueOntoModelFieldsPlugin_default = class {
2046	attachToComponent(component) {
2047		this.synchronizeValueOfModelFields(component);
2048		component.on("render:finished", () => {
2049			this.synchronizeValueOfModelFields(component);
2050		});
2051	}
2052	synchronizeValueOfModelFields(component) {
2053		component.element.querySelectorAll("[data-model]").forEach((element) => {
2054			if (!(element instanceof HTMLElement)) throw new Error("Invalid element using data-model.");
2055			if (element instanceof HTMLFormElement) return;
2056			if (!elementBelongsToThisComponent(element, component)) return;
2057			const modelDirective = getModelDirectiveFromElement(element);
2058			if (!modelDirective) return;
2059			const modelName = modelDirective.action;
2060			if (component.getUnsyncedModels().includes(modelName)) return;
2061			if (component.valueStore.has(modelName)) setValueOnElement(element, component.valueStore.get(modelName));
2062			if (element instanceof HTMLSelectElement && !element.multiple) component.valueStore.set(modelName, getValueFromElement(element, component.valueStore));
2063		});
2064	}
2065};
2066var ValidatedFieldsPlugin_default = class {
2067	attachToComponent(component) {
2068		component.on("model:set", (modelName) => {
2069			this.handleModelSet(modelName, component.valueStore);
2070		});
2071	}
2072	handleModelSet(modelName, valueStore) {
2073		if (valueStore.has("validatedFields")) {
2074			const validatedFields = [...valueStore.get("validatedFields")];
2075			if (!validatedFields.includes(modelName)) validatedFields.push(modelName);
2076			valueStore.set("validatedFields", validatedFields);
2077		}
2078	}
2079};
2080var LiveControllerDefault = class LiveControllerDefault extends Controller {
2081	constructor(..._args) {
2082		super(..._args);
2083		this.pendingActionTriggerModelElement = null;
2084		this.elementEventListeners = [{
2085			event: "input",
2086			callback: (event) => this.handleInputEvent(event)
2087		}, {
2088			event: "change",
2089			callback: (event) => this.handleChangeEvent(event)
2090		}];
2091		this.pendingFiles = {};
2092	}
2093	initialize() {
2094		this.mutationObserver = new MutationObserver(this.onMutations.bind(this));
2095		this.createComponent();
2096	}
2097	connect() {
2098		this.connectComponent();
2099		this.mutationObserver.observe(this.element, { attributes: true });
2100	}
2101	disconnect() {
2102		this.disconnectComponent();
2103		this.mutationObserver.disconnect();
2104	}
2105	update(event) {
2106		if (event.type === "input" || event.type === "change") throw new Error(`Since LiveComponents 2.3, you no longer need data-action="live#update" on form elements. Found on element: ${getElementAsTagText(event.currentTarget)}`);
2107		this.updateModelFromElementEvent(event.currentTarget, null);
2108	}
2109	action(event) {
2110		const params = event.params;
2111		if (!params.action) throw new Error(`No action name provided on element: ${getElementAsTagText(event.currentTarget)}. Did you forget to add the "data-live-action-param" attribute?`);
2112		const rawAction = params.action;
2113		const actionArgs = { ...params };
2114		delete actionArgs.action;
2115		const directives = parseDirectives(rawAction);
2116		let debounce = false;
2117		directives.forEach((directive) => {
2118			let pendingFiles = {};
2119			const validModifiers = /* @__PURE__ */ new Map();
2120			validModifiers.set("stop", () => {
2121				event.stopPropagation();
2122			});
2123			validModifiers.set("self", () => {
2124				if (event.target !== event.currentTarget) return;
2125			});
2126			validModifiers.set("debounce", (modifier) => {
2127				debounce = modifier.value ? Number.parseInt(modifier.value) : true;
2128			});
2129			validModifiers.set("files", (modifier) => {
2130				if (!modifier.value) pendingFiles = this.pendingFiles;
2131				else if (this.pendingFiles[modifier.value]) pendingFiles[modifier.value] = this.pendingFiles[modifier.value];
2132			});
2133			directive.modifiers.forEach((modifier) => {
2134				if (validModifiers.has(modifier.name)) {
2135					(validModifiers.get(modifier.name) ?? (() => {}))(modifier);
2136					return;
2137				}
2138				console.warn(`Unknown modifier ${modifier.name} in action "${rawAction}". Available modifiers are: ${Array.from(validModifiers.keys()).join(", ")}.`);
2139			});
2140			for (const [key, input] of Object.entries(pendingFiles)) {
2141				if (input.files) this.component.files(key, input);
2142				delete this.pendingFiles[key];
2143			}
2144			this.component.action(directive.action, actionArgs, debounce);
2145			if (getModelDirectiveFromElement(event.currentTarget, false)) this.pendingActionTriggerModelElement = event.currentTarget;
2146		});
2147	}
2148	$render() {
2149		return this.component.render();
2150	}
2151	emit(event) {
2152		this.getEmitDirectives(event).forEach(({ name, data, nameMatch }) => {
2153			this.component.emit(name, data, nameMatch);
2154		});
2155	}
2156	emitUp(event) {
2157		this.getEmitDirectives(event).forEach(({ name, data, nameMatch }) => {
2158			this.component.emitUp(name, data, nameMatch);
2159		});
2160	}
2161	emitSelf(event) {
2162		this.getEmitDirectives(event).forEach(({ name, data }) => {
2163			this.component.emitSelf(name, data);
2164		});
2165	}
2166	$updateModel(model, value, shouldRender = true, debounce = true) {
2167		return this.component.set(model, value, shouldRender, debounce);
2168	}
2169	propsUpdatedFromParentValueChanged() {
2170		this.component._updateFromParentProps(this.propsUpdatedFromParentValue);
2171	}
2172	fingerprintValueChanged() {
2173		this.component.fingerprint = this.fingerprintValue;
2174	}
2175	getEmitDirectives(event) {
2176		const params = event.params;
2177		if (!params.event) throw new Error(`No event name provided on element: ${getElementAsTagText(event.currentTarget)}. Did you forget to add the "data-live-event-param" attribute?`);
2178		const eventInfo = params.event;
2179		const eventArgs = { ...params };
2180		delete eventArgs.event;
2181		const directives = parseDirectives(eventInfo);
2182		const emits = [];
2183		directives.forEach((directive) => {
2184			let nameMatch = null;
2185			directive.modifiers.forEach((modifier) => {
2186				switch (modifier.name) {
2187					case "name":
2188						nameMatch = modifier.value;
2189						break;
2190					default: throw new Error(`Unknown modifier ${modifier.name} in event "${eventInfo}".`);
2191				}
2192			});
2193			emits.push({
2194				name: directive.action,
2195				data: eventArgs,
2196				nameMatch
2197			});
2198		});
2199		return emits;
2200	}
2201	createComponent() {
2202		const id = this.element.id || null;
2203		this.component = new Component(this.element, this.nameValue, this.propsValue, this.listenersValue, id, LiveControllerDefault.backendFactory(this), new StimulusElementDriver(this));
2204		this.proxiedComponent = proxifyComponent(this.component);
2205		Object.defineProperty(this.element, "__component", {
2206			value: this.proxiedComponent,
2207			writable: true
2208		});
2209		if (this.hasDebounceValue) this.component.defaultDebounce = this.debounceValue;
2210		[
2211			new LoadingPlugin_default(),
2212			new LazyPlugin_default(),
2213			new ValidatedFieldsPlugin_default(),
2214			new PageUnloadingPlugin_default(),
2215			new PollingPlugin_default(),
2216			new SetValueOntoModelFieldsPlugin_default(),
2217			new ChildComponentPlugin_default(this.component)
2218		].forEach((plugin) => {
2219			this.component.addPlugin(plugin);
2220		});
2221	}
2222	connectComponent() {
2223		this.component.connect();
2224		this.mutationObserver.observe(this.element, { attributes: true });
2225		this.elementEventListeners.forEach(({ event, callback }) => {
2226			this.component.element.addEventListener(event, callback);
2227		});
2228		this.dispatchEvent("connect");
2229	}
2230	disconnectComponent() {
2231		this.component.disconnect();
2232		this.elementEventListeners.forEach(({ event, callback }) => {
2233			this.component.element.removeEventListener(event, callback);
2234		});
2235		this.dispatchEvent("disconnect");
2236	}
2237	handleInputEvent(event) {
2238		const target = event.target;
2239		if (!target) return;
2240		this.updateModelFromElementEvent(target, "input");
2241	}
2242	handleChangeEvent(event) {
2243		const target = event.target;
2244		if (!target) return;
2245		this.updateModelFromElementEvent(target, "change");
2246	}
2247	updateModelFromElementEvent(element, eventName) {
2248		if (!elementBelongsToThisComponent(element, this.component)) return;
2249		if (!(element instanceof HTMLElement)) throw new Error("Could not update model for non HTMLElement");
2250		if (element instanceof HTMLInputElement && element.type === "file") {
2251			const key = element.name;
2252			if (element.files?.length) this.pendingFiles[key] = element;
2253			else if (this.pendingFiles[key]) delete this.pendingFiles[key];
2254		}
2255		const modelDirective = getModelDirectiveFromElement(element, false);
2256		if (!modelDirective) return;
2257		const modelBinding = get_model_binding_default(modelDirective);
2258		if (!modelBinding.targetEventName) modelBinding.targetEventName = "input";
2259		if (this.pendingActionTriggerModelElement === element) modelBinding.shouldRender = false;
2260		if (eventName === "change" && modelBinding.targetEventName === "input") modelBinding.targetEventName = "change";
2261		if (eventName && modelBinding.targetEventName !== eventName) return;
2262		if (false === modelBinding.debounce) if (modelBinding.targetEventName === "input") modelBinding.debounce = true;
2263		else modelBinding.debounce = 0;
2264		const finalValue = getValueFromElement(element, this.component.valueStore);
2265		if (isTextualInputElement(element) || isTextareaElement(element)) {
2266			if (modelBinding.minLength !== null && typeof finalValue === "string" && finalValue.length < modelBinding.minLength) return;
2267			if (modelBinding.maxLength !== null && typeof finalValue === "string" && finalValue.length > modelBinding.maxLength) return;
2268		}
2269		if (isNumericalInputElement(element)) {
2270			const numericValue = Number(finalValue);
2271			if (modelBinding.minValue !== null && numericValue < modelBinding.minValue) return;
2272			if (modelBinding.maxValue !== null && numericValue > modelBinding.maxValue) return;
2273		}
2274		this.component.set(modelBinding.modelName, finalValue, modelBinding.shouldRender, modelBinding.debounce);
2275	}
2276	dispatchEvent(name, detail = {}, canBubble = true, cancelable = false) {
2277		detail.controller = this;
2278		detail.component = this.proxiedComponent;
2279		this.dispatch(name, {
2280			detail,
2281			prefix: "live",
2282			cancelable,
2283			bubbles: canBubble
2284		});
2285	}
2286	onMutations(mutations) {
2287		mutations.forEach((mutation) => {
2288			if (mutation.type === "attributes" && mutation.attributeName === "id" && this.element.id !== this.component.id) {
2289				this.disconnectComponent();
2290				this.createComponent();
2291				this.connectComponent();
2292			}
2293		});
2294	}
2295};
2296LiveControllerDefault.values = {
2297	name: String,
2298	url: String,
2299	props: {
2300		type: Object,
2301		default: {}
2302	},
2303	propsUpdatedFromParent: {
2304		type: Object,
2305		default: {}
2306	},
2307	listeners: {
2308		type: Array,
2309		default: []
2310	},
2311	eventsToEmit: {
2312		type: Array,
2313		default: []
2314	},
2315	eventsToDispatch: {
2316		type: Array,
2317		default: []
2318	},
2319	debounce: {
2320		type: Number,
2321		default: 150
2322	},
2323	fingerprint: {
2324		type: String,
2325		default: ""
2326	},
2327	requestMethod: {
2328		type: String,
2329		default: "post"
2330	},
2331	fetchCredentials: {
2332		type: String,
2333		default: "same-origin"
2334	}
2335};
2336LiveControllerDefault.backendFactory = (controller) => new Backend_default(controller.urlValue, controller.requestMethodValue, controller.fetchCredentialsValue);
2337export { Component, LiveControllerDefault as default, getComponent };

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.