@symfony/ux-live-component 3.2.0 → 3.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,10 @@
1
1
  import { Controller } from "@hotwired/stimulus";
2
2
  var BackendRequest_default = class {
3
+ promise;
4
+ actions;
5
+ updatedModels;
6
+ isResolved = false;
3
7
  constructor(promise, actions, updateModels) {
4
- this.isResolved = false;
5
8
  this.promise = promise;
6
9
  this.promise.then((response) => {
7
10
  this.isResolved = true;
@@ -18,6 +21,9 @@ var BackendRequest_default = class {
18
21
  }
19
22
  };
20
23
  var RequestBuilder_default = class {
24
+ url;
25
+ method;
26
+ credentials;
21
27
  constructor(url, method = "post", credentials = "same-origin") {
22
28
  this.url = url;
23
29
  this.method = method;
@@ -77,6 +83,7 @@ var RequestBuilder_default = class {
77
83
  }
78
84
  };
79
85
  var Backend_default = class {
86
+ requestBuilder;
80
87
  constructor(url, method = "post", credentials = "same-origin") {
81
88
  this.requestBuilder = new RequestBuilder_default(url, method, credentials);
82
89
  }
@@ -86,18 +93,55 @@ var Backend_default = class {
86
93
  }
87
94
  };
88
95
  var BackendResponse_default = class {
96
+ response;
97
+ body;
98
+ liveUrl;
99
+ download = null;
100
+ parsePromise = null;
89
101
  constructor(response) {
90
102
  this.response = response;
91
103
  }
92
104
  async getBody() {
93
- if (!this.body) this.body = await this.response.text();
105
+ if (!this.parsePromise) this.parsePromise = this.parse();
106
+ await this.parsePromise;
94
107
  return this.body;
95
108
  }
109
+ getDownload() {
110
+ return this.download;
111
+ }
96
112
  getLiveUrl() {
97
113
  if (void 0 === this.liveUrl) this.liveUrl = this.response.headers.get("X-Live-Url");
98
114
  return this.liveUrl;
99
115
  }
116
+ getDownloadUrl() {
117
+ return this.response.headers.get("X-Live-Download-Url");
118
+ }
119
+ isRemoved() {
120
+ return this.response.headers.has("X-Live-Remove");
121
+ }
122
+ async parse() {
123
+ const htmlLength = this.response.headers.get("X-Live-Html-Length");
124
+ if (null === htmlLength) {
125
+ this.body = await this.response.text();
126
+ return;
127
+ }
128
+ const buffer = await this.response.arrayBuffer();
129
+ const splitAt = Number.parseInt(htmlLength, 10);
130
+ this.body = new TextDecoder().decode(buffer.slice(0, splitAt));
131
+ this.download = {
132
+ filename: decodeFilename(this.response.headers.get("X-Live-Download-Filename")),
133
+ blob: new Blob([buffer.slice(splitAt)], { type: this.response.headers.get("X-Live-Download-Type") ?? "application/octet-stream" })
134
+ };
135
+ }
100
136
  };
137
+ function decodeFilename(value) {
138
+ if (!value) return "download";
139
+ try {
140
+ return decodeURIComponent(value) || "download";
141
+ } catch {
142
+ return "download";
143
+ }
144
+ }
101
145
  function getElementAsTagText(element) {
102
146
  return element.innerHTML ? element.outerHTML.slice(0, element.outerHTML.indexOf(element.innerHTML)) : element.outerHTML;
103
147
  }
@@ -262,6 +306,7 @@ function trimAll(str) {
262
306
  return str.replace(/[\s]+/g, " ").trim();
263
307
  }
264
308
  function normalizeModelName(model) {
309
+ if (!model.includes("[") && !model.includes("]")) return model;
265
310
  return model.replace(/\[]$/, "").split("[").map((s) => s.replace("]", "")).join(".");
266
311
  }
267
312
  function getValueFromElement(element, valueStore) {
@@ -386,9 +431,7 @@ function isNumericalInputElement(element) {
386
431
  return element instanceof HTMLInputElement && ["number", "range"].includes(element.type);
387
432
  }
388
433
  var HookManager_default = class {
389
- constructor() {
390
- this.hooks = /* @__PURE__ */ new Map();
391
- }
434
+ hooks = /* @__PURE__ */ new Map();
392
435
  register(hookName, callback) {
393
436
  const hooks = this.hooks.get(hookName) || [];
394
437
  hooks.push(callback);
@@ -409,8 +452,8 @@ var HookManager_default = class {
409
452
  };
410
453
  var Idiomorph = (function() {
411
454
  "use strict";
412
- let EMPTY_SET = /* @__PURE__ */ new Set();
413
- let defaults = {
455
+ const noOp = () => {};
456
+ const defaults = {
414
457
  morphStyle: "outerHTML",
415
458
  callbacks: {
416
459
  beforeNodeAdded: noOp,
@@ -423,190 +466,282 @@ var Idiomorph = (function() {
423
466
  },
424
467
  head: {
425
468
  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
- },
469
+ shouldPreserve: (elt) => elt.getAttribute("im-preserve") === "true",
470
+ shouldReAppend: (elt) => elt.getAttribute("im-re-append") === "true",
432
471
  shouldRemove: noOp,
433
472
  afterHeadMorphed: noOp
434
- }
473
+ },
474
+ restoreFocus: true
435
475
  };
436
476
  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;
477
+ oldNode = normalizeElement(oldNode);
478
+ const newNode = normalizeParent(newContent);
479
+ const ctx = createMorphContext(oldNode, newNode, config);
480
+ const morphedNodes = saveAndRestoreFocus(ctx, () => {
481
+ return withHeadBlocking(ctx, oldNode, newNode, (ctx) => {
482
+ if (ctx.morphStyle === "innerHTML") {
483
+ morphChildren(ctx, oldNode, newNode);
484
+ return Array.from(oldNode.childNodes);
485
+ } else return morphOuterHTML(ctx, oldNode, newNode);
486
+ });
487
+ });
488
+ ctx.pantry.remove();
489
+ return morphedNodes;
490
+ }
491
+ function morphOuterHTML(ctx, oldNode, newNode) {
492
+ const oldParent = normalizeParent(oldNode);
493
+ morphChildren(ctx, oldParent, newNode, oldNode, oldNode.nextSibling);
494
+ return Array.from(oldParent.childNodes);
495
+ }
496
+ function saveAndRestoreFocus(ctx, fn) {
497
+ if (!ctx.config.restoreFocus) return fn();
498
+ let activeElement = document.activeElement;
499
+ if (!(activeElement instanceof HTMLInputElement || activeElement instanceof HTMLTextAreaElement)) return fn();
500
+ const { id: activeElementId, selectionStart, selectionEnd } = activeElement;
501
+ const results = fn();
502
+ if (activeElementId && activeElementId !== document.activeElement?.getAttribute("id")) {
503
+ activeElement = ctx.target.querySelector(`[id="${activeElementId}"]`);
504
+ activeElement?.focus();
505
+ }
506
+ if (activeElement && !activeElement.selectionEnd && selectionEnd) activeElement.setSelectionRange(selectionStart, selectionEnd);
507
+ return results;
508
+ }
509
+ const morphChildren = (function() {
510
+ function morphChildren(ctx, oldParent, newParent, insertionPoint = null, endPoint = null) {
511
+ if (oldParent instanceof HTMLTemplateElement && newParent instanceof HTMLTemplateElement) {
512
+ oldParent = oldParent.content;
513
+ newParent = newParent.content;
514
+ }
515
+ insertionPoint ||= oldParent.firstChild;
516
+ for (const newChild of newParent.childNodes) {
517
+ if (insertionPoint && insertionPoint != endPoint) {
518
+ const bestMatch = findBestMatch(ctx, newChild, insertionPoint, endPoint);
519
+ if (bestMatch) {
520
+ if (bestMatch !== insertionPoint) removeNodesBetween(ctx, insertionPoint, bestMatch);
521
+ morphNode(bestMatch, newChild, ctx);
522
+ insertionPoint = bestMatch.nextSibling;
523
+ continue;
524
+ }
525
+ }
526
+ if (newChild instanceof Element) {
527
+ const newChildId = newChild.getAttribute("id");
528
+ if (ctx.persistentIds.has(newChildId)) {
529
+ const movedChild = moveBeforeById(oldParent, newChildId, insertionPoint, ctx);
530
+ morphNode(movedChild, newChild, ctx);
531
+ insertionPoint = movedChild.nextSibling;
532
+ continue;
533
+ }
534
+ }
535
+ const insertedNode = createNode(oldParent, newChild, insertionPoint, ctx);
536
+ if (insertedNode) insertionPoint = insertedNode.nextSibling;
537
+ }
538
+ while (insertionPoint && insertionPoint != endPoint) {
539
+ const tempNode = insertionPoint;
540
+ insertionPoint = insertionPoint.nextSibling;
541
+ removeNode(ctx, tempNode);
456
542
  }
457
543
  }
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);
544
+ function createNode(oldParent, newChild, insertionPoint, ctx) {
545
+ if (ctx.callbacks.beforeNodeAdded(newChild) === false) return null;
546
+ if (ctx.idMap.has(newChild)) {
547
+ const newEmptyChild = document.createElement(newChild.tagName);
548
+ oldParent.insertBefore(newEmptyChild, insertionPoint);
549
+ morphNode(newEmptyChild, newChild, ctx);
550
+ ctx.callbacks.afterNodeAdded(newEmptyChild);
551
+ return newEmptyChild;
552
+ } else {
553
+ const newClonedChild = document.importNode(newChild, true);
554
+ oldParent.insertBefore(newClonedChild, insertionPoint);
555
+ ctx.callbacks.afterNodeAdded(newClonedChild);
556
+ return newClonedChild;
492
557
  }
493
- ctx.callbacks.afterNodeMorphed(oldNode, newContent);
494
- return oldNode;
495
558
  }
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;
559
+ const findBestMatch = (function() {
560
+ function findBestMatch(ctx, node, startPoint, endPoint) {
561
+ let softMatch = null;
562
+ let nextSibling = node.nextSibling;
563
+ let siblingSoftMatchCount = 0;
564
+ let cursor = startPoint;
565
+ while (cursor && cursor != endPoint) {
566
+ if (isSoftMatch(cursor, node)) {
567
+ if (isIdSetMatch(ctx, cursor, node)) return cursor;
568
+ if (softMatch === null) {
569
+ if (!ctx.idMap.has(cursor)) softMatch = cursor;
570
+ }
571
+ }
572
+ if (softMatch === null && nextSibling && isSoftMatch(cursor, nextSibling)) {
573
+ siblingSoftMatchCount++;
574
+ nextSibling = nextSibling.nextSibling;
575
+ if (siblingSoftMatchCount >= 2) softMatch = void 0;
576
+ }
577
+ if (ctx.activeElementAndParents.includes(cursor)) break;
578
+ cursor = cursor.nextSibling;
579
+ }
580
+ return softMatch || null;
510
581
  }
511
- if (isIdSetMatch(newChild, insertionPoint, ctx)) {
512
- morphOldNodeTo(insertionPoint, newChild, ctx);
513
- insertionPoint = insertionPoint.nextSibling;
514
- removeIdsFromConsideration(ctx, newChild);
515
- continue;
582
+ function isIdSetMatch(ctx, oldNode, newNode) {
583
+ let oldSet = ctx.idMap.get(oldNode);
584
+ let newSet = ctx.idMap.get(newNode);
585
+ if (!newSet || !oldSet) return false;
586
+ for (const id of oldSet) if (newSet.has(id)) return true;
587
+ return false;
516
588
  }
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;
589
+ function isSoftMatch(oldNode, newNode) {
590
+ const oldElt = oldNode;
591
+ const newElt = newNode;
592
+ return oldElt.nodeType === newElt.nodeType && oldElt.tagName === newElt.tagName && (!oldElt.getAttribute?.("id") || oldElt.getAttribute?.("id") === newElt.getAttribute?.("id"));
523
593
  }
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;
594
+ return findBestMatch;
595
+ })();
596
+ function removeNode(ctx, node) {
597
+ if (ctx.idMap.has(node)) moveBefore(ctx.pantry, node, null);
598
+ else {
599
+ if (ctx.callbacks.beforeNodeRemoved(node) === false) return;
600
+ node.parentNode?.removeChild(node);
601
+ ctx.callbacks.afterNodeRemoved(node);
530
602
  }
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);
603
+ }
604
+ function removeNodesBetween(ctx, startInclusive, endExclusive) {
605
+ let cursor = startInclusive;
606
+ while (cursor && cursor !== endExclusive) {
607
+ let tempNode = cursor;
608
+ cursor = cursor.nextSibling;
609
+ removeNode(ctx, tempNode);
554
610
  }
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);
611
+ return cursor;
612
+ }
613
+ function moveBeforeById(parentNode, id, after, ctx) {
614
+ const target = ctx.target.getAttribute?.("id") === id && ctx.target || ctx.target.querySelector(`[id="${id}"]`) || ctx.pantry.querySelector(`[id="${id}"]`);
615
+ removeElementFromAncestorsIdMaps(target, ctx);
616
+ moveBefore(parentNode, target, after);
617
+ return target;
618
+ }
619
+ function removeElementFromAncestorsIdMaps(element, ctx) {
620
+ const id = element.getAttribute("id");
621
+ while (element = element.parentNode) {
622
+ let idSet = ctx.idMap.get(element);
623
+ if (idSet) {
624
+ idSet.delete(id);
625
+ if (!idSet.size) ctx.idMap.delete(element);
626
+ }
627
+ }
628
+ }
629
+ function moveBefore(parentNode, element, after) {
630
+ if (parentNode.moveBefore) try {
631
+ parentNode.moveBefore(element, after);
632
+ } catch (e) {
633
+ parentNode.insertBefore(element, after);
634
+ }
635
+ else parentNode.insertBefore(element, after);
636
+ }
637
+ return morphChildren;
638
+ })();
639
+ const morphNode = (function() {
640
+ function morphNode(oldNode, newContent, ctx) {
641
+ if (ctx.ignoreActive && oldNode === document.activeElement) return null;
642
+ if (ctx.callbacks.beforeNodeMorphed(oldNode, newContent) === false) return oldNode;
643
+ if (oldNode instanceof HTMLHeadElement && ctx.head.ignore) {} else if (oldNode instanceof HTMLHeadElement && ctx.head.style !== "morph") handleHeadElement(oldNode, newContent, ctx);
644
+ else {
645
+ morphAttributes(oldNode, newContent, ctx);
646
+ if (!ignoreValueOfActiveElement(oldNode, ctx)) morphChildren(ctx, oldNode, newContent);
559
647
  }
648
+ ctx.callbacks.afterNodeMorphed(oldNode, newContent);
649
+ return oldNode;
560
650
  }
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");
651
+ function morphAttributes(oldNode, newNode, ctx) {
652
+ let type = newNode.nodeType;
653
+ if (type === 1) {
654
+ const oldElt = oldNode;
655
+ const newElt = newNode;
656
+ const oldAttributes = oldElt.attributes;
657
+ const newAttributes = newElt.attributes;
658
+ for (const newAttribute of newAttributes) {
659
+ if (ignoreAttribute(newAttribute.name, oldElt, "update", ctx)) continue;
660
+ if (oldElt.getAttribute(newAttribute.name) !== newAttribute.value) oldElt.setAttribute(newAttribute.name, newAttribute.value);
585
661
  }
586
- } else if (fromValue !== toValue) {
587
- if (!ignoreAttribute("value", to, "update", ctx)) {
588
- to.setAttribute("value", fromValue);
589
- to.value = fromValue;
662
+ for (let i = oldAttributes.length - 1; 0 <= i; i--) {
663
+ const oldAttribute = oldAttributes[i];
664
+ if (!oldAttribute) continue;
665
+ if (!newElt.hasAttribute(oldAttribute.name)) {
666
+ if (ignoreAttribute(oldAttribute.name, oldElt, "remove", ctx)) continue;
667
+ oldElt.removeAttribute(oldAttribute.name);
668
+ }
590
669
  }
670
+ if (!ignoreValueOfActiveElement(oldElt, ctx)) syncInputValue(oldElt, newElt, ctx);
671
+ }
672
+ if (type === 8 || type === 3) {
673
+ if (oldNode.nodeValue !== newNode.nodeValue) oldNode.nodeValue = newNode.nodeValue;
674
+ }
675
+ }
676
+ function syncInputValue(oldElement, newElement, ctx) {
677
+ if (oldElement instanceof HTMLInputElement && newElement instanceof HTMLInputElement && newElement.type !== "file") {
678
+ let newValue = newElement.value;
679
+ let oldValue = oldElement.value;
680
+ syncBooleanAttribute(oldElement, newElement, "checked", ctx);
681
+ syncBooleanAttribute(oldElement, newElement, "disabled", ctx);
682
+ if (!newElement.hasAttribute("value")) {
683
+ if (!ignoreAttribute("value", oldElement, "remove", ctx)) {
684
+ oldElement.value = "";
685
+ oldElement.removeAttribute("value");
686
+ }
687
+ } else if (oldValue !== newValue) {
688
+ if (!ignoreAttribute("value", oldElement, "update", ctx)) {
689
+ oldElement.setAttribute("value", newValue);
690
+ oldElement.value = newValue;
691
+ }
692
+ }
693
+ } else if (oldElement instanceof HTMLOptionElement && newElement instanceof HTMLOptionElement) syncBooleanAttribute(oldElement, newElement, "selected", ctx);
694
+ else if (oldElement instanceof HTMLTextAreaElement && newElement instanceof HTMLTextAreaElement) {
695
+ let newValue = newElement.value;
696
+ let oldValue = oldElement.value;
697
+ if (ignoreAttribute("value", oldElement, "update", ctx)) return;
698
+ if (newValue !== oldValue) oldElement.value = newValue;
699
+ if (oldElement.firstChild && oldElement.firstChild.nodeValue !== newValue) oldElement.firstChild.nodeValue = newValue;
700
+ }
701
+ }
702
+ function syncBooleanAttribute(oldElement, newElement, attributeName, ctx) {
703
+ const newLiveValue = newElement[attributeName];
704
+ if (newLiveValue !== oldElement[attributeName]) {
705
+ const ignoreUpdate = ignoreAttribute(attributeName, oldElement, "update", ctx);
706
+ if (!ignoreUpdate) oldElement[attributeName] = newElement[attributeName];
707
+ if (newLiveValue) {
708
+ if (!ignoreUpdate) oldElement.setAttribute(attributeName, "");
709
+ } else if (!ignoreAttribute(attributeName, oldElement, "remove", ctx)) oldElement.removeAttribute(attributeName);
710
+ }
711
+ }
712
+ function ignoreAttribute(attr, element, updateType, ctx) {
713
+ if (attr === "value" && ctx.ignoreActiveValue && element === document.activeElement) return true;
714
+ return ctx.callbacks.beforeAttributeUpdated(attr, element, updateType) === false;
715
+ }
716
+ function ignoreValueOfActiveElement(possibleActiveElement, ctx) {
717
+ return !!ctx.ignoreActiveValue && possibleActiveElement === document.activeElement && possibleActiveElement !== document.body;
718
+ }
719
+ return morphNode;
720
+ })();
721
+ function withHeadBlocking(ctx, oldNode, newNode, callback) {
722
+ if (ctx.head.block) {
723
+ const oldHead = oldNode.querySelector("head");
724
+ const newHead = newNode.querySelector("head");
725
+ if (oldHead && newHead) {
726
+ const promises = handleHeadElement(oldHead, newHead, ctx);
727
+ return Promise.all(promises).then(() => {
728
+ return callback(Object.assign(ctx, { head: {
729
+ block: false,
730
+ ignore: true
731
+ } }));
732
+ });
591
733
  }
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
734
  }
735
+ return callback(ctx);
600
736
  }
601
- function handleHeadElement(newHeadTag, currentHead, ctx) {
737
+ function handleHeadElement(oldHead, newHead, ctx) {
602
738
  let added = [];
603
739
  let removed = [];
604
740
  let preserved = [];
605
741
  let nodesToAppend = [];
606
- let headMergeStyle = ctx.head.style;
607
742
  let srcToNewHeadNodes = /* @__PURE__ */ new Map();
608
- for (const newHeadChild of newHeadTag.children) srcToNewHeadNodes.set(newHeadChild.outerHTML, newHeadChild);
609
- for (const currentHeadElt of currentHead.children) {
743
+ for (const newHeadChild of newHead.children) srcToNewHeadNodes.set(newHeadChild.outerHTML, newHeadChild);
744
+ for (const currentHeadElt of oldHead.children) {
610
745
  let inNewContent = srcToNewHeadNodes.has(currentHeadElt.outerHTML);
611
746
  let isReAppended = ctx.head.shouldReAppend(currentHeadElt);
612
747
  let isPreserved = ctx.head.shouldPreserve(currentHeadElt);
@@ -615,7 +750,7 @@ var Idiomorph = (function() {
615
750
  srcToNewHeadNodes.delete(currentHeadElt.outerHTML);
616
751
  preserved.push(currentHeadElt);
617
752
  }
618
- else if (headMergeStyle === "append") {
753
+ else if (ctx.head.style === "append") {
619
754
  if (isReAppended) {
620
755
  removed.push(currentHeadElt);
621
756
  nodesToAppend.push(currentHeadElt);
@@ -627,8 +762,8 @@ var Idiomorph = (function() {
627
762
  for (const newNode of nodesToAppend) {
628
763
  let newElt = document.createRange().createContextualFragment(newNode.outerHTML).firstChild;
629
764
  if (ctx.callbacks.beforeNodeAdded(newElt) !== false) {
630
- if (newElt.href || newElt.src) {
631
- let resolve = null;
765
+ if ("href" in newElt && newElt.href || "src" in newElt && newElt.src) {
766
+ /** @type {(result?: any) => void} */ let resolve;
632
767
  let promise = new Promise(function(_resolve) {
633
768
  resolve = _resolve;
634
769
  });
@@ -637,218 +772,197 @@ var Idiomorph = (function() {
637
772
  });
638
773
  promises.push(promise);
639
774
  }
640
- currentHead.appendChild(newElt);
775
+ oldHead.appendChild(newElt);
641
776
  ctx.callbacks.afterNodeAdded(newElt);
642
777
  added.push(newElt);
643
778
  }
644
779
  }
645
780
  for (const removedElement of removed) if (ctx.callbacks.beforeNodeRemoved(removedElement) !== false) {
646
- currentHead.removeChild(removedElement);
781
+ oldHead.removeChild(removedElement);
647
782
  ctx.callbacks.afterNodeRemoved(removedElement);
648
783
  }
649
- ctx.head.afterHeadMorphed(currentHead, {
784
+ ctx.head.afterHeadMorphed(oldHead, {
650
785
  added,
651
786
  kept: preserved,
652
787
  removed
653
788
  });
654
789
  return promises;
655
790
  }
656
- function noOp() {}
657
- function mergeDefaults(config) {
658
- let finalConfig = {};
659
- Object.assign(finalConfig, defaults);
660
- Object.assign(finalConfig, config);
661
- finalConfig.callbacks = {};
662
- Object.assign(finalConfig.callbacks, defaults.callbacks);
663
- Object.assign(finalConfig.callbacks, config.callbacks);
664
- finalConfig.head = {};
665
- Object.assign(finalConfig.head, defaults.head);
666
- Object.assign(finalConfig.head, config.head);
667
- return finalConfig;
668
- }
669
- function createMorphContext(oldNode, newContent, config) {
670
- config = mergeDefaults(config);
671
- return {
672
- target: oldNode,
673
- newContent,
674
- config,
675
- morphStyle: config.morphStyle,
676
- ignoreActive: config.ignoreActive,
677
- ignoreActiveValue: config.ignoreActiveValue,
678
- idMap: createIdMap(oldNode, newContent),
679
- deadIds: /* @__PURE__ */ new Set(),
680
- callbacks: config.callbacks,
681
- head: config.head
682
- };
683
- }
684
- function isIdSetMatch(node1, node2, ctx) {
685
- if (node1 == null || node2 == null) return false;
686
- if (node1.nodeType === node2.nodeType && node1.tagName === node2.tagName) if (node1.id !== "" && node1.id === node2.id) return true;
687
- else return getIdIntersectionCount(ctx, node1, node2) > 0;
688
- return false;
689
- }
690
- function isSoftMatch(node1, node2) {
691
- if (node1 == null || node2 == null) return false;
692
- return node1.nodeType === node2.nodeType && node1.tagName === node2.tagName;
693
- }
694
- function removeNodesBetween(startInclusive, endExclusive, ctx) {
695
- while (startInclusive !== endExclusive) {
696
- let tempNode = startInclusive;
697
- startInclusive = startInclusive.nextSibling;
698
- removeNode(tempNode, ctx);
699
- }
700
- removeIdsFromConsideration(ctx, endExclusive);
701
- return endExclusive.nextSibling;
702
- }
703
- function findIdSetMatch(newContent, oldParent, newChild, insertionPoint, ctx) {
704
- let newChildPotentialIdCount = getIdIntersectionCount(ctx, newChild, oldParent);
705
- let potentialMatch = null;
706
- if (newChildPotentialIdCount > 0) {
707
- let potentialMatch = insertionPoint;
708
- let otherMatchCount = 0;
709
- while (potentialMatch != null) {
710
- if (isIdSetMatch(newChild, potentialMatch, ctx)) return potentialMatch;
711
- otherMatchCount += getIdIntersectionCount(ctx, potentialMatch, newContent);
712
- if (otherMatchCount > newChildPotentialIdCount) return null;
713
- potentialMatch = potentialMatch.nextSibling;
791
+ const createMorphContext = (function() {
792
+ function createMorphContext(oldNode, newContent, config) {
793
+ const { persistentIds, idMap } = createIdMaps(oldNode, newContent);
794
+ const mergedConfig = mergeDefaults(config);
795
+ const morphStyle = mergedConfig.morphStyle || "outerHTML";
796
+ if (!["innerHTML", "outerHTML"].includes(morphStyle)) throw `Do not understand how to morph style ${morphStyle}`;
797
+ return {
798
+ target: oldNode,
799
+ newContent,
800
+ config: mergedConfig,
801
+ morphStyle,
802
+ ignoreActive: mergedConfig.ignoreActive,
803
+ ignoreActiveValue: mergedConfig.ignoreActiveValue,
804
+ restoreFocus: mergedConfig.restoreFocus,
805
+ idMap,
806
+ persistentIds,
807
+ pantry: createPantry(),
808
+ activeElementAndParents: createActiveElementAndParents(oldNode),
809
+ callbacks: mergedConfig.callbacks,
810
+ head: mergedConfig.head
811
+ };
812
+ }
813
+ function mergeDefaults(config) {
814
+ let finalConfig = Object.assign({}, defaults);
815
+ Object.assign(finalConfig, config);
816
+ finalConfig.callbacks = Object.assign({}, defaults.callbacks, config.callbacks);
817
+ finalConfig.head = Object.assign({}, defaults.head, config.head);
818
+ return finalConfig;
819
+ }
820
+ function createPantry() {
821
+ const pantry = document.createElement("div");
822
+ pantry.hidden = true;
823
+ document.body.insertAdjacentElement("afterend", pantry);
824
+ return pantry;
825
+ }
826
+ function createActiveElementAndParents(oldNode) {
827
+ let activeElementAndParents = [];
828
+ let elt = document.activeElement;
829
+ if (elt?.tagName !== "BODY" && oldNode.contains(elt)) while (elt) {
830
+ activeElementAndParents.push(elt);
831
+ if (elt === oldNode) break;
832
+ elt = elt.parentElement;
714
833
  }
834
+ return activeElementAndParents;
835
+ }
836
+ function findIdElements(root) {
837
+ let elements = Array.from(root.querySelectorAll("[id]"));
838
+ if (root.getAttribute?.("id")) elements.push(root);
839
+ return elements;
715
840
  }
716
- return potentialMatch;
717
- }
718
- function findSoftMatch(newContent, oldParent, newChild, insertionPoint, ctx) {
719
- let potentialSoftMatch = insertionPoint;
720
- let nextSibling = newChild.nextSibling;
721
- let siblingSoftMatchCount = 0;
722
- while (potentialSoftMatch != null) {
723
- if (getIdIntersectionCount(ctx, potentialSoftMatch, newContent) > 0) return null;
724
- if (isSoftMatch(newChild, potentialSoftMatch)) return potentialSoftMatch;
725
- if (isSoftMatch(nextSibling, potentialSoftMatch)) {
726
- siblingSoftMatchCount++;
727
- nextSibling = nextSibling.nextSibling;
728
- if (siblingSoftMatchCount >= 2) return null;
841
+ function populateIdMapWithTree(idMap, persistentIds, root, elements) {
842
+ for (const elt of elements) {
843
+ const id = elt.getAttribute("id");
844
+ if (persistentIds.has(id)) {
845
+ let current = elt;
846
+ while (current) {
847
+ let idSet = idMap.get(current);
848
+ if (idSet == null) {
849
+ idSet = /* @__PURE__ */ new Set();
850
+ idMap.set(current, idSet);
851
+ }
852
+ idSet.add(id);
853
+ if (current === root) break;
854
+ current = current.parentElement;
855
+ }
856
+ }
729
857
  }
730
- potentialSoftMatch = potentialSoftMatch.nextSibling;
731
858
  }
732
- return potentialSoftMatch;
733
- }
734
- function parseContent(newContent) {
735
- let parser = new DOMParser();
736
- let contentWithSvgsRemoved = newContent.replace(/<svg(\s[^>]*>|>)([\s\S]*?)<\/svg>/gim, "");
737
- if (contentWithSvgsRemoved.match(/<\/html>/) || contentWithSvgsRemoved.match(/<\/head>/) || contentWithSvgsRemoved.match(/<\/body>/)) {
738
- let content = parser.parseFromString(newContent, "text/html");
739
- if (contentWithSvgsRemoved.match(/<\/html>/)) {
740
- content.generatedByIdiomorph = true;
741
- return content;
742
- } else {
743
- let htmlElement = content.firstChild;
744
- if (htmlElement) {
745
- htmlElement.generatedByIdiomorph = true;
746
- return htmlElement;
747
- } else return null;
859
+ function createIdMaps(oldContent, newContent) {
860
+ const oldIdElements = findIdElements(oldContent);
861
+ const newIdElements = findIdElements(newContent);
862
+ const persistentIds = createPersistentIds(oldIdElements, newIdElements);
863
+ let idMap = /* @__PURE__ */ new Map();
864
+ populateIdMapWithTree(idMap, persistentIds, oldContent, oldIdElements);
865
+ populateIdMapWithTree(idMap, persistentIds, newContent.__idiomorphRoot || newContent, newIdElements);
866
+ return {
867
+ persistentIds,
868
+ idMap
869
+ };
870
+ }
871
+ function createPersistentIds(oldIdElements, newIdElements) {
872
+ let duplicateIds = /* @__PURE__ */ new Set();
873
+ let oldIdTagNameMap = /* @__PURE__ */ new Map();
874
+ for (const { id, tagName } of oldIdElements) if (oldIdTagNameMap.has(id)) duplicateIds.add(id);
875
+ else oldIdTagNameMap.set(id, tagName);
876
+ let persistentIds = /* @__PURE__ */ new Set();
877
+ for (const { id, tagName } of newIdElements) if (persistentIds.has(id)) duplicateIds.add(id);
878
+ else if (oldIdTagNameMap.get(id) === tagName) persistentIds.add(id);
879
+ for (const id of duplicateIds) persistentIds.delete(id);
880
+ return persistentIds;
881
+ }
882
+ return createMorphContext;
883
+ })();
884
+ const { normalizeElement, normalizeParent } = (function() {
885
+ const generatedByIdiomorph = /* @__PURE__ */ new WeakSet();
886
+ function normalizeElement(content) {
887
+ if (content instanceof Document) return content.documentElement;
888
+ else return content;
889
+ }
890
+ function normalizeParent(newContent) {
891
+ if (newContent == null) return document.createElement("div");
892
+ else if (typeof newContent === "string") return normalizeParent(parseContent(newContent));
893
+ else if (generatedByIdiomorph.has(newContent)) return newContent;
894
+ else if (newContent instanceof Node) if (newContent.parentNode) return new SlicedParentNode(newContent);
895
+ else {
896
+ const dummyParent = document.createElement("div");
897
+ dummyParent.append(newContent);
898
+ return dummyParent;
899
+ }
900
+ else {
901
+ const dummyParent = document.createElement("div");
902
+ for (const elt of [...newContent]) dummyParent.append(elt);
903
+ return dummyParent;
748
904
  }
749
- } else {
750
- let content = parser.parseFromString("<body><template>" + newContent + "</template></body>", "text/html").body.querySelector("template").content;
751
- content.generatedByIdiomorph = true;
752
- return content;
753
- }
754
- }
755
- function normalizeContent(newContent) {
756
- if (newContent == null) return document.createElement("div");
757
- else if (newContent.generatedByIdiomorph) return newContent;
758
- else if (newContent instanceof Node) {
759
- const dummyParent = document.createElement("div");
760
- dummyParent.append(newContent);
761
- return dummyParent;
762
- } else {
763
- const dummyParent = document.createElement("div");
764
- for (const elt of [...newContent]) dummyParent.append(elt);
765
- return dummyParent;
766
905
  }
767
- }
768
- function insertSiblings(previousSibling, morphedNode, nextSibling) {
769
- let stack = [];
770
- let added = [];
771
- while (previousSibling != null) {
772
- stack.push(previousSibling);
773
- previousSibling = previousSibling.previousSibling;
774
- }
775
- while (stack.length > 0) {
776
- let node = stack.pop();
777
- added.push(node);
778
- morphedNode.parentElement.insertBefore(node, morphedNode);
779
- }
780
- added.push(morphedNode);
781
- while (nextSibling != null) {
782
- stack.push(nextSibling);
783
- added.push(nextSibling);
784
- nextSibling = nextSibling.nextSibling;
785
- }
786
- while (stack.length > 0) morphedNode.parentElement.insertBefore(stack.pop(), morphedNode.nextSibling);
787
- return added;
788
- }
789
- function findBestNodeMatch(newContent, oldNode, ctx) {
790
- let currentElement;
791
- currentElement = newContent.firstChild;
792
- let bestElement = currentElement;
793
- let score = 0;
794
- while (currentElement) {
795
- let newScore = scoreElement(currentElement, oldNode, ctx);
796
- if (newScore > score) {
797
- bestElement = currentElement;
798
- score = newScore;
906
+ class SlicedParentNode {
907
+ constructor(node) {
908
+ this.originalNode = node;
909
+ this.realParentNode = node.parentNode;
910
+ this.previousSibling = node.previousSibling;
911
+ this.nextSibling = node.nextSibling;
912
+ }
913
+ get childNodes() {
914
+ const nodes = [];
915
+ let cursor = this.previousSibling ? this.previousSibling.nextSibling : this.realParentNode.firstChild;
916
+ while (cursor && cursor != this.nextSibling) {
917
+ nodes.push(cursor);
918
+ cursor = cursor.nextSibling;
919
+ }
920
+ return nodes;
921
+ }
922
+ querySelectorAll(selector) {
923
+ return this.childNodes.reduce((results, node) => {
924
+ if (node instanceof Element) {
925
+ if (node.matches(selector)) results.push(node);
926
+ const nodeList = node.querySelectorAll(selector);
927
+ for (let i = 0; i < nodeList.length; i++) results.push(nodeList[i]);
928
+ }
929
+ return results;
930
+ }, []);
931
+ }
932
+ insertBefore(node, referenceNode) {
933
+ return this.realParentNode.insertBefore(node, referenceNode);
934
+ }
935
+ moveBefore(node, referenceNode) {
936
+ return this.realParentNode.moveBefore(node, referenceNode);
799
937
  }
800
- currentElement = currentElement.nextSibling;
801
- }
802
- return bestElement;
803
- }
804
- function scoreElement(node1, node2, ctx) {
805
- if (isSoftMatch(node1, node2)) return .5 + getIdIntersectionCount(ctx, node1, node2);
806
- return 0;
807
- }
808
- function removeNode(tempNode, ctx) {
809
- removeIdsFromConsideration(ctx, tempNode);
810
- if (ctx.callbacks.beforeNodeRemoved(tempNode) === false) return;
811
- tempNode.remove();
812
- ctx.callbacks.afterNodeRemoved(tempNode);
813
- }
814
- function isIdInConsideration(ctx, id) {
815
- return !ctx.deadIds.has(id);
816
- }
817
- function idIsWithinNode(ctx, id, targetNode) {
818
- return (ctx.idMap.get(targetNode) || EMPTY_SET).has(id);
819
- }
820
- function removeIdsFromConsideration(ctx, node) {
821
- let idSet = ctx.idMap.get(node) || EMPTY_SET;
822
- for (const id of idSet) ctx.deadIds.add(id);
823
- }
824
- function getIdIntersectionCount(ctx, node1, node2) {
825
- let sourceSet = ctx.idMap.get(node1) || EMPTY_SET;
826
- let matchCount = 0;
827
- for (const id of sourceSet) if (isIdInConsideration(ctx, id) && idIsWithinNode(ctx, id, node2)) ++matchCount;
828
- return matchCount;
829
- }
830
- function populateIdMapForNode(node, idMap) {
831
- let nodeParent = node.parentElement;
832
- let idElements = node.querySelectorAll("[id]");
833
- for (const elt of idElements) {
834
- let current = elt;
835
- while (current !== nodeParent && current != null) {
836
- let idSet = idMap.get(current);
837
- if (idSet == null) {
838
- idSet = /* @__PURE__ */ new Set();
839
- idMap.set(current, idSet);
938
+ get __idiomorphRoot() {
939
+ return this.originalNode;
940
+ }
941
+ }
942
+ function parseContent(newContent) {
943
+ let parser = new DOMParser();
944
+ let contentWithSvgsRemoved = newContent.replace(/<svg(\s[^>]*>|>)([\s\S]*?)<\/svg>/gim, "");
945
+ if (contentWithSvgsRemoved.match(/<\/html>/) || contentWithSvgsRemoved.match(/<\/head>/) || contentWithSvgsRemoved.match(/<\/body>/)) {
946
+ let content = parser.parseFromString(newContent, "text/html");
947
+ if (contentWithSvgsRemoved.match(/<\/html>/)) {
948
+ generatedByIdiomorph.add(content);
949
+ return content;
950
+ } else {
951
+ let htmlElement = content.firstChild;
952
+ if (htmlElement) generatedByIdiomorph.add(htmlElement);
953
+ return htmlElement;
840
954
  }
841
- idSet.add(elt.id);
842
- current = current.parentElement;
955
+ } else {
956
+ let content = parser.parseFromString("<body><template>" + newContent + "</template></body>", "text/html").body.querySelector("template").content;
957
+ generatedByIdiomorph.add(content);
958
+ return content;
843
959
  }
844
960
  }
845
- }
846
- function createIdMap(oldContent, newContent) {
847
- let idMap = /* @__PURE__ */ new Map();
848
- populateIdMapForNode(oldContent, idMap);
849
- populateIdMapForNode(newContent, idMap);
850
- return idMap;
851
- }
961
+ return {
962
+ normalizeElement,
963
+ normalizeParent
964
+ };
965
+ })();
852
966
  return {
853
967
  morph,
854
968
  defaults
@@ -869,89 +983,110 @@ const syncAttributes = (fromEl, toEl) => {
869
983
  toEl.setAttribute(attr.name, attr.value);
870
984
  }
871
985
  };
872
- function executeMorphdom(rootFromElement, rootToElement, modifiedFieldElements, getElementValue, externalMutationTracker) {
873
- const originalElementIdsToSwapAfter = [];
874
- const originalElementsToPreserve = /* @__PURE__ */ new Map();
875
- const markElementAsNeedingPostMorphSwap = (id, replaceWithClone) => {
876
- const oldElement = originalElementsToPreserve.get(id);
877
- if (!(oldElement instanceof HTMLElement)) throw new Error(`Original element with id ${id} not found`);
878
- originalElementIdsToSwapAfter.push(id);
879
- if (!replaceWithClone) return null;
880
- const clonedOldElement = cloneHTMLElement(oldElement);
881
- oldElement.replaceWith(clonedOldElement);
882
- return clonedOldElement;
883
- };
884
- rootToElement.querySelectorAll("[data-live-preserve]").forEach((newElement) => {
885
- const id = newElement.id;
886
- if (!id) throw new Error("The data-live-preserve attribute requires an id attribute to be set on the element");
887
- const oldElement = rootFromElement.querySelector(`#${id}`);
888
- if (!(oldElement instanceof HTMLElement)) throw new Error(`The element with id "${id}" was not found in the original HTML`);
889
- newElement.removeAttribute("data-live-preserve");
890
- originalElementsToPreserve.set(id, oldElement);
891
- syncAttributes(newElement, oldElement);
892
- });
893
- Idiomorph.morph(rootFromElement, rootToElement, { callbacks: {
894
- beforeNodeMorphed: (fromEl, toEl) => {
895
- if (!(fromEl instanceof Element) || !(toEl instanceof Element)) return true;
896
- if (fromEl === rootFromElement) return true;
897
- if (fromEl.id && originalElementsToPreserve.has(fromEl.id)) {
898
- if (fromEl.id === toEl.id) return false;
899
- const clonedFromEl = markElementAsNeedingPostMorphSwap(fromEl.id, true);
900
- if (!clonedFromEl) throw new Error("missing clone");
901
- Idiomorph.morph(clonedFromEl, toEl);
902
- return false;
903
- }
904
- if (fromEl instanceof HTMLElement && toEl instanceof HTMLElement) {
905
- if (typeof fromEl.__x !== "undefined") {
906
- 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.");
907
- if (typeof window.Alpine.morph !== "function") throw new Error("Unable to access Alpine.js morph function. Please make sure the Alpine.js Morph plugin is installed and loaded, see https://alpinejs.dev/plugins/morph for more information.");
908
- window.Alpine.morph(fromEl.__x, toEl);
909
- }
910
- if (externalMutationTracker.wasElementAdded(fromEl)) {
911
- fromEl.insertAdjacentElement("afterend", toEl);
986
+ const setId = (element, id) => {
987
+ if (id === null) element.removeAttribute("id");
988
+ else element.setAttribute("id", id);
989
+ };
990
+ function executeMorphdom(rootFromElement, rootToElement, modifiedFieldElements, getElementValue, externalMutationTracker, childComponents = []) {
991
+ const externallyChangedIds = /* @__PURE__ */ new Map();
992
+ try {
993
+ for (const [element, originalId] of externalMutationTracker.getOriginalIds()) {
994
+ externallyChangedIds.set(element, element.getAttribute("id"));
995
+ setId(element, originalId);
996
+ }
997
+ for (const { element, id } of childComponents) if (id && element.getAttribute("id") !== id) {
998
+ externallyChangedIds.set(element, element.getAttribute("id"));
999
+ setId(element, id);
1000
+ }
1001
+ const originalElementIdsToSwapAfter = [];
1002
+ const originalElementsToPreserve = /* @__PURE__ */ new Map();
1003
+ const markElementAsNeedingPostMorphSwap = (id, replaceWithClone) => {
1004
+ const oldElement = originalElementsToPreserve.get(id);
1005
+ if (!(oldElement instanceof HTMLElement)) throw new Error(`Original element with id ${id} not found`);
1006
+ originalElementIdsToSwapAfter.push(id);
1007
+ if (!replaceWithClone) return null;
1008
+ const clonedOldElement = cloneHTMLElement(oldElement);
1009
+ oldElement.replaceWith(clonedOldElement);
1010
+ return clonedOldElement;
1011
+ };
1012
+ rootToElement.querySelectorAll("[data-live-preserve]").forEach((newElement) => {
1013
+ const id = newElement.id;
1014
+ if (!id) throw new Error("The data-live-preserve attribute requires an id attribute to be set on the element");
1015
+ const oldElement = rootFromElement.querySelector(`#${id}`);
1016
+ if (!(oldElement instanceof HTMLElement)) throw new Error(`The element with id "${id}" was not found in the original HTML`);
1017
+ newElement.removeAttribute("data-live-preserve");
1018
+ originalElementsToPreserve.set(id, oldElement);
1019
+ syncAttributes(newElement, oldElement);
1020
+ });
1021
+ Idiomorph.morph(rootFromElement, rootToElement, { callbacks: {
1022
+ beforeNodeMorphed: (fromEl, toEl) => {
1023
+ if (!(fromEl instanceof Element) || !(toEl instanceof Element)) return true;
1024
+ if (fromEl === rootFromElement) return true;
1025
+ if (fromEl.id && originalElementsToPreserve.has(fromEl.id)) {
1026
+ if (fromEl.id === toEl.id) return false;
1027
+ const clonedFromEl = markElementAsNeedingPostMorphSwap(fromEl.id, true);
1028
+ if (!clonedFromEl) throw new Error("missing clone");
1029
+ Idiomorph.morph(clonedFromEl, toEl);
912
1030
  return false;
913
1031
  }
914
- if (modifiedFieldElements.includes(fromEl)) setValueOnElement(toEl, getElementValue(fromEl));
915
- if (fromEl === document.activeElement && fromEl !== document.body && null !== getModelDirectiveFromElement(fromEl, false)) setValueOnElement(toEl, getElementValue(fromEl));
916
- const elementChanges = externalMutationTracker.getChangedElement(fromEl);
917
- if (elementChanges) elementChanges.applyToElement(toEl);
918
- if (fromEl.nodeName.toUpperCase() !== "OPTION" && fromEl.isEqualNode(toEl)) {
919
- const normalizedFromEl = cloneHTMLElement(fromEl);
920
- normalizeAttributesForComparison(normalizedFromEl);
921
- const normalizedToEl = cloneHTMLElement(toEl);
922
- normalizeAttributesForComparison(normalizedToEl);
923
- if (normalizedFromEl.isEqualNode(normalizedToEl)) return false;
1032
+ if (fromEl instanceof HTMLElement && toEl instanceof HTMLElement) {
1033
+ if (typeof fromEl.__x !== "undefined") {
1034
+ 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.");
1035
+ if (typeof window.Alpine.morph !== "function") throw new Error("Unable to access Alpine.js morph function. Please make sure the Alpine.js Morph plugin is installed and loaded, see https://alpinejs.dev/plugins/morph for more information.");
1036
+ window.Alpine.morph(fromEl.__x, toEl);
1037
+ }
1038
+ if (externalMutationTracker.wasElementAdded(fromEl)) {
1039
+ const id = fromEl.getAttribute("id");
1040
+ if (id && id === toEl.getAttribute("id")) return false;
1041
+ toEl.before(document.createComment(""));
1042
+ return false;
1043
+ }
1044
+ if (modifiedFieldElements.includes(fromEl)) setValueOnElement(toEl, getElementValue(fromEl));
1045
+ if (fromEl === document.activeElement && fromEl !== document.body && null !== getModelDirectiveFromElement(fromEl, false)) setValueOnElement(toEl, getElementValue(fromEl));
1046
+ const elementChanges = externalMutationTracker.getChangedElement(fromEl);
1047
+ if (elementChanges) {
1048
+ const serverId = toEl.getAttribute("id");
1049
+ elementChanges.applyToElement(toEl);
1050
+ if (externallyChangedIds.has(fromEl)) setId(toEl, serverId);
1051
+ }
1052
+ if (fromEl.nodeName.toUpperCase() !== "OPTION" && fromEl.isEqualNode(toEl)) {
1053
+ const normalizedFromEl = cloneHTMLElement(fromEl);
1054
+ normalizeAttributesForComparison(normalizedFromEl);
1055
+ const normalizedToEl = cloneHTMLElement(toEl);
1056
+ normalizeAttributesForComparison(normalizedToEl);
1057
+ if (normalizedFromEl.isEqualNode(normalizedToEl)) return false;
1058
+ }
924
1059
  }
1060
+ if (fromEl.hasAttribute("data-skip-morph") || fromEl.id && fromEl.id !== toEl.id) {
1061
+ fromEl.innerHTML = toEl.innerHTML;
1062
+ return true;
1063
+ }
1064
+ if (fromEl.parentElement?.hasAttribute("data-skip-morph")) return false;
1065
+ return !fromEl.hasAttribute("data-live-ignore");
1066
+ },
1067
+ beforeNodeRemoved(node) {
1068
+ if (!(node instanceof HTMLElement)) return true;
1069
+ if (node.id && originalElementsToPreserve.has(node.id)) {
1070
+ markElementAsNeedingPostMorphSwap(node.id, false);
1071
+ return true;
1072
+ }
1073
+ if (externalMutationTracker.wasElementAdded(node)) return false;
1074
+ return !node.hasAttribute("data-live-ignore");
925
1075
  }
926
- if (fromEl.hasAttribute("data-skip-morph") || fromEl.id && fromEl.id !== toEl.id) {
927
- fromEl.innerHTML = toEl.innerHTML;
928
- return true;
929
- }
930
- if (fromEl.parentElement?.hasAttribute("data-skip-morph")) return false;
931
- return !fromEl.hasAttribute("data-live-ignore");
932
- },
933
- beforeNodeRemoved(node) {
934
- if (!(node instanceof HTMLElement)) return true;
935
- if (node.id && originalElementsToPreserve.has(node.id)) {
936
- markElementAsNeedingPostMorphSwap(node.id, false);
937
- return true;
938
- }
939
- if (externalMutationTracker.wasElementAdded(node)) return false;
940
- return !node.hasAttribute("data-live-ignore");
941
- }
942
- } });
943
- originalElementIdsToSwapAfter.forEach((id) => {
944
- const newElement = rootFromElement.querySelector(`#${id}`);
945
- const originalElement = originalElementsToPreserve.get(id);
946
- if (!(newElement instanceof HTMLElement) || !(originalElement instanceof HTMLElement)) throw new Error("Missing elements.");
947
- newElement.replaceWith(originalElement);
948
- });
1076
+ } });
1077
+ originalElementIdsToSwapAfter.forEach((id) => {
1078
+ const newElement = rootFromElement.querySelector(`#${id}`);
1079
+ const originalElement = originalElementsToPreserve.get(id);
1080
+ if (!(newElement instanceof HTMLElement) || !(originalElement instanceof HTMLElement)) throw new Error("Missing elements.");
1081
+ newElement.replaceWith(originalElement);
1082
+ });
1083
+ } finally {
1084
+ for (const [element, id] of externallyChangedIds) setId(element, id);
1085
+ }
949
1086
  }
950
1087
  var ChangingItemsTracker_default = class {
951
- constructor() {
952
- this.changedItems = /* @__PURE__ */ new Map();
953
- this.removedItems = /* @__PURE__ */ new Map();
954
- }
1088
+ changedItems = /* @__PURE__ */ new Map();
1089
+ removedItems = /* @__PURE__ */ new Map();
955
1090
  setItem(itemName, newValue, previousValue) {
956
1091
  if (this.removedItems.has(itemName)) {
957
1092
  const removedRecord = this.removedItems.get(itemName);
@@ -998,12 +1133,10 @@ var ChangingItemsTracker_default = class {
998
1133
  }
999
1134
  };
1000
1135
  var ElementChanges = class {
1001
- constructor() {
1002
- this.addedClasses = /* @__PURE__ */ new Set();
1003
- this.removedClasses = /* @__PURE__ */ new Set();
1004
- this.styleChanges = new ChangingItemsTracker_default();
1005
- this.attributeChanges = new ChangingItemsTracker_default();
1006
- }
1136
+ addedClasses = /* @__PURE__ */ new Set();
1137
+ removedClasses = /* @__PURE__ */ new Set();
1138
+ styleChanges = new ChangingItemsTracker_default();
1139
+ attributeChanges = new ChangingItemsTracker_default();
1007
1140
  addClass(className) {
1008
1141
  if (!this.removedClasses.delete(className)) this.addedClasses.add(className);
1009
1142
  }
@@ -1062,12 +1195,16 @@ var ElementChanges = class {
1062
1195
  }
1063
1196
  };
1064
1197
  var ExternalMutationTracker_default = class {
1198
+ element;
1199
+ shouldTrackChangeCallback;
1200
+ mutationObserver;
1201
+ changedElements = /* @__PURE__ */ new WeakMap();
1202
+ changedElementsCount = 0;
1203
+ addedElements = [];
1204
+ removedElements = [];
1205
+ isStarted = false;
1206
+ originalIds = /* @__PURE__ */ new Map();
1065
1207
  constructor(element, shouldTrackChangeCallback) {
1066
- this.changedElements = /* @__PURE__ */ new WeakMap();
1067
- this.changedElementsCount = 0;
1068
- this.addedElements = [];
1069
- this.removedElements = [];
1070
- this.isStarted = false;
1071
1208
  this.element = element;
1072
1209
  this.shouldTrackChangeCallback = shouldTrackChangeCallback;
1073
1210
  this.mutationObserver = new MutationObserver(this.onMutations.bind(this));
@@ -1091,6 +1228,10 @@ var ExternalMutationTracker_default = class {
1091
1228
  getChangedElement(element) {
1092
1229
  return this.changedElements.has(element) ? this.changedElements.get(element) : null;
1093
1230
  }
1231
+ getOriginalIds() {
1232
+ for (const element of this.originalIds.keys()) if (!this.element.contains(element)) this.originalIds.delete(element);
1233
+ return this.originalIds;
1234
+ }
1094
1235
  getAddedElements() {
1095
1236
  return this.addedElements;
1096
1237
  }
@@ -1197,6 +1338,10 @@ var ExternalMutationTracker_default = class {
1197
1338
  handleGenericAttributeMutation(mutation, elementChanges) {
1198
1339
  const attributeName = mutation.attributeName;
1199
1340
  const element = mutation.target;
1341
+ if (attributeName === "id") {
1342
+ if (!this.originalIds.has(element)) this.originalIds.set(element, mutation.oldValue);
1343
+ if (element.getAttribute("id") === this.originalIds.get(element)) this.originalIds.delete(element);
1344
+ }
1200
1345
  let oldValue = mutation.oldValue;
1201
1346
  let newValue = element.getAttribute(attributeName);
1202
1347
  if (oldValue === attributeName) oldValue = "";
@@ -1224,11 +1369,14 @@ var ExternalMutationTracker_default = class {
1224
1369
  }
1225
1370
  };
1226
1371
  var UnsyncedInputsTracker_default = class {
1372
+ component;
1373
+ modelElementResolver;
1374
+ unsyncedInputs;
1375
+ elementEventListeners = [{
1376
+ event: "input",
1377
+ callback: (event) => this.handleInputEvent(event)
1378
+ }];
1227
1379
  constructor(component, modelElementResolver) {
1228
- this.elementEventListeners = [{
1229
- event: "input",
1230
- callback: (event) => this.handleInputEvent(event)
1231
- }];
1232
1380
  this.component = component;
1233
1381
  this.modelElementResolver = modelElementResolver;
1234
1382
  this.unsyncedInputs = new UnsyncedInputContainer();
@@ -1268,9 +1416,10 @@ var UnsyncedInputsTracker_default = class {
1268
1416
  }
1269
1417
  };
1270
1418
  var UnsyncedInputContainer = class {
1419
+ unsyncedModelFields;
1420
+ unsyncedNonModelFields = [];
1421
+ unsyncedModelNames = [];
1271
1422
  constructor() {
1272
- this.unsyncedNonModelFields = [];
1273
- this.unsyncedModelNames = [];
1274
1423
  this.unsyncedModelFields = /* @__PURE__ */ new Map();
1275
1424
  }
1276
1425
  add(element, modelName = null) {
@@ -1316,11 +1465,11 @@ const parseDeepData = (data, propertyPath) => {
1316
1465
  };
1317
1466
  };
1318
1467
  var ValueStore_default = class {
1468
+ props = {};
1469
+ dirtyProps = {};
1470
+ pendingProps = {};
1471
+ updatedPropsFromParent = {};
1319
1472
  constructor(props) {
1320
- this.props = {};
1321
- this.dirtyProps = {};
1322
- this.pendingProps = {};
1323
- this.updatedPropsFromParent = {};
1324
1473
  this.props = props;
1325
1474
  }
1326
1475
  get(name) {
@@ -1372,14 +1521,27 @@ var ValueStore_default = class {
1372
1521
  }
1373
1522
  };
1374
1523
  var Component = class {
1524
+ element;
1525
+ name;
1526
+ listeners;
1527
+ backend;
1528
+ elementDriver;
1529
+ id;
1530
+ fingerprint = "";
1531
+ valueStore;
1532
+ unsyncedInputsTracker;
1533
+ hooks;
1534
+ defaultDebounce = 150;
1535
+ backendRequest = null;
1536
+ pendingActions = [];
1537
+ pendingFiles = {};
1538
+ isRequestPending = false;
1539
+ isRemoved = false;
1540
+ requestDebounceTimeout = null;
1541
+ nextRequestPromise;
1542
+ nextRequestPromiseResolve;
1543
+ externalMutationTracker;
1375
1544
  constructor(element, name, props, listeners, id, backend, elementDriver) {
1376
- this.fingerprint = "";
1377
- this.defaultDebounce = 150;
1378
- this.backendRequest = null;
1379
- this.pendingActions = [];
1380
- this.pendingFiles = {};
1381
- this.isRequestPending = false;
1382
- this.requestDebounceTimeout = null;
1383
1545
  this.element = element;
1384
1546
  this.name = name;
1385
1547
  this.backend = backend;
@@ -1397,6 +1559,11 @@ var Component = class {
1397
1559
  this.externalMutationTracker = new ExternalMutationTracker_default(this.element, (element) => elementBelongsToThisComponent(element, this));
1398
1560
  this.externalMutationTracker.start();
1399
1561
  }
1562
+ getOriginalId() {
1563
+ this.externalMutationTracker.handlePendingChanges();
1564
+ const originalIds = this.externalMutationTracker.getOriginalIds();
1565
+ return originalIds.has(this.element) ? originalIds.get(this.element) : this.element.getAttribute("id");
1566
+ }
1400
1567
  addPlugin(plugin) {
1401
1568
  plugin.attachToComponent(this);
1402
1569
  }
@@ -1477,7 +1644,21 @@ var Component = class {
1477
1644
  isTurboEnabled() {
1478
1645
  return typeof Turbo !== "undefined" && !this.element.closest("[data-turbo=\"false\"]");
1479
1646
  }
1647
+ removeFromPage() {
1648
+ this.isRemoved = true;
1649
+ this.disconnect();
1650
+ const element = this.element;
1651
+ for (const name of element.getAttributeNames()) if (name.startsWith("data-live-") && name.endsWith("-value")) element.removeAttribute(name);
1652
+ element.setAttribute("data-live-removing", "");
1653
+ requestAnimationFrame(() => {
1654
+ const animations = (element.getAnimations?.({ subtree: true }) ?? []).filter((animation) => animation.effect?.getComputedTiming().endTime !== Number.POSITIVE_INFINITY);
1655
+ Promise.allSettled(animations.map((animation) => animation.finished)).then(() => {
1656
+ element.remove();
1657
+ });
1658
+ });
1659
+ }
1480
1660
  tryStartingRequest() {
1661
+ if (this.isRemoved) return;
1481
1662
  if (!this.backendRequest) {
1482
1663
  this.performRequest();
1483
1664
  return;
@@ -1508,10 +1689,10 @@ var Component = class {
1508
1689
  this.isRequestPending = remainingActions.length > 0;
1509
1690
  this.backendRequest.promise.then(async (response) => {
1510
1691
  const backendResponse = new BackendResponse_default(response);
1511
- const html = await backendResponse.getBody();
1512
- for (const input of Object.values(this.pendingFiles)) input.value = "";
1513
1692
  const headers = backendResponse.response.headers;
1514
- if (!headers.get("Content-Type")?.includes("application/vnd.live-component+html") && !headers.get("X-Live-Redirect")) {
1693
+ for (const input of Object.values(this.pendingFiles)) input.value = "";
1694
+ const html = await backendResponse.getBody();
1695
+ if (!headers.get("Content-Type")?.includes("application/vnd.live-component+html") && !headers.get("X-Live-Redirect") && !headers.has("X-Live-Remove")) {
1515
1696
  const controls = { displayError: true };
1516
1697
  this.valueStore.pushPendingPropsBackToDirty();
1517
1698
  this.hooks.triggerHook("response:error", backendResponse, controls);
@@ -1520,6 +1701,14 @@ var Component = class {
1520
1701
  thisPromiseResolve(backendResponse);
1521
1702
  return response;
1522
1703
  }
1704
+ if (backendResponse.isRemoved()) {
1705
+ this.isRemoved = true;
1706
+ this.processRerender(html, backendResponse);
1707
+ this.backendRequest = null;
1708
+ thisPromiseResolve(backendResponse);
1709
+ this.removeFromPage();
1710
+ return response;
1711
+ }
1523
1712
  const liveUrl = backendResponse.getLiveUrl();
1524
1713
  if (liveUrl) history.replaceState(history.state, "", new URL(liveUrl + window.location.hash, window.location.origin));
1525
1714
  this.processRerender(html, backendResponse);
@@ -1556,7 +1745,7 @@ var Component = class {
1556
1745
  }
1557
1746
  this.externalMutationTracker.handlePendingChanges();
1558
1747
  this.externalMutationTracker.stop();
1559
- executeMorphdom(this.element, newElement, this.unsyncedInputsTracker.getUnsyncedInputs(), (element) => getValueFromElement(element, this.valueStore), this.externalMutationTracker);
1748
+ executeMorphdom(this.element, newElement, this.unsyncedInputsTracker.getUnsyncedInputs(), (element) => getValueFromElement(element, this.valueStore), this.externalMutationTracker, findChildren(this));
1560
1749
  this.externalMutationTracker.start();
1561
1750
  const newProps = this.elementDriver.getComponentProps();
1562
1751
  this.valueStore.reinitializeAllProps(newProps);
@@ -1582,6 +1771,14 @@ var Component = class {
1582
1771
  bubbles: true
1583
1772
  }));
1584
1773
  });
1774
+ try {
1775
+ const downloadUrl = backendResponse.getDownloadUrl();
1776
+ const download = backendResponse.getDownload();
1777
+ if (downloadUrl) triggerDownload({ url: downloadUrl });
1778
+ else if (download) triggerDownload(download);
1779
+ } catch (error) {
1780
+ console.error("Could not start the download:", error);
1781
+ }
1585
1782
  this.hooks.triggerHook("render:finished", this);
1586
1783
  }
1587
1784
  calculateDebounce(debounce) {
@@ -1662,6 +1859,7 @@ function proxifyComponent(component) {
1662
1859
  return Reflect.get(component, prop);
1663
1860
  }
1664
1861
  if (component.valueStore.has(prop)) return component.getData(prop);
1862
+ if ("toJSON" === prop || "then" === prop) return;
1665
1863
  return (args) => {
1666
1864
  return component.action.apply(component, [prop, args]);
1667
1865
  };
@@ -1676,7 +1874,23 @@ function proxifyComponent(component) {
1676
1874
  }
1677
1875
  });
1678
1876
  }
1877
+ function triggerDownload(download) {
1878
+ const fromUrl = "url" in download;
1879
+ const href = fromUrl ? download.url : URL.createObjectURL(download.blob);
1880
+ const link = Object.assign(document.createElement("a"), {
1881
+ href,
1882
+ download: fromUrl ? "" : download.filename,
1883
+ style: "display: none"
1884
+ });
1885
+ document.body.appendChild(link);
1886
+ link.click();
1887
+ setTimeout(() => {
1888
+ document.body.removeChild(link);
1889
+ if (!fromUrl) URL.revokeObjectURL(href);
1890
+ }, 75);
1891
+ }
1679
1892
  var StimulusElementDriver = class {
1893
+ controller;
1680
1894
  constructor(controller) {
1681
1895
  this.controller = controller;
1682
1896
  }
@@ -1745,8 +1959,9 @@ function get_model_binding_default(modelDirective) {
1745
1959
  };
1746
1960
  }
1747
1961
  var ChildComponentPlugin_default = class {
1962
+ component;
1963
+ parentModelBindings = [];
1748
1964
  constructor(component) {
1749
- this.parentModelBindings = [];
1750
1965
  this.component = component;
1751
1966
  const modelDirectives = getAllModelDirectiveFromElements(this.component.element);
1752
1967
  this.parentModelBindings = modelDirectives.map(get_model_binding_default);
@@ -1783,9 +1998,7 @@ var ChildComponentPlugin_default = class {
1783
1998
  }
1784
1999
  };
1785
2000
  var LazyPlugin_default = class {
1786
- constructor() {
1787
- this.intersectionObserver = null;
1788
- }
2001
+ intersectionObserver = null;
1789
2002
  attachToComponent(component) {
1790
2003
  if ("lazy" !== component.element.attributes.getNamedItem("loading")?.value) return;
1791
2004
  component.on("connect", () => {
@@ -1895,6 +2108,7 @@ var LoadingPlugin_default = class {
1895
2108
  const loadingDirectives = [];
1896
2109
  let matchingElements = Array.from(element.querySelectorAll("[data-loading]"));
1897
2110
  matchingElements = matchingElements.filter((elt) => elementBelongsToThisComponent(elt, component));
2111
+ matchingElements = matchingElements.filter((elt) => !elt.closest("[data-live-ignore]"));
1898
2112
  if (element.hasAttribute("data-loading")) matchingElements = [element, ...matchingElements];
1899
2113
  matchingElements.forEach((element) => {
1900
2114
  if (!(element instanceof HTMLElement) && !(element instanceof SVGElement)) throw new Error("Invalid Element Type");
@@ -1942,9 +2156,7 @@ const parseLoadingAction = (action, isLoading) => {
1942
2156
  throw new Error(`Unknown data-loading action "${action}"`);
1943
2157
  };
1944
2158
  var PageUnloadingPlugin_default = class {
1945
- constructor() {
1946
- this.isConnected = false;
1947
- }
2159
+ isConnected = false;
1948
2160
  attachToComponent(component) {
1949
2161
  component.on("render:started", (html, response, controls) => {
1950
2162
  if (!this.isConnected) controls.shouldRender = false;
@@ -1958,9 +2170,11 @@ var PageUnloadingPlugin_default = class {
1958
2170
  }
1959
2171
  };
1960
2172
  var PollingDirector_default = class {
2173
+ component;
2174
+ isPollingActive = true;
2175
+ polls;
2176
+ pollingIntervals = [];
1961
2177
  constructor(component) {
1962
- this.isPollingActive = true;
1963
- this.pollingIntervals = [];
1964
2178
  this.component = component;
1965
2179
  }
1966
2180
  addPoll(actionName, duration) {
@@ -2003,6 +2217,8 @@ var PollingDirector_default = class {
2003
2217
  }
2004
2218
  };
2005
2219
  var PollingPlugin_default = class {
2220
+ element;
2221
+ pollingDirector;
2006
2222
  attachToComponent(component) {
2007
2223
  this.element = component.element;
2008
2224
  this.pollingDirector = new PollingDirector_default(component);
@@ -2077,18 +2293,59 @@ var ValidatedFieldsPlugin_default = class {
2077
2293
  }
2078
2294
  };
2079
2295
  var LiveControllerDefault = class LiveControllerDefault extends Controller {
2080
- constructor(..._args) {
2081
- super(..._args);
2082
- this.pendingActionTriggerModelElement = null;
2083
- this.elementEventListeners = [{
2084
- event: "input",
2085
- callback: (event) => this.handleInputEvent(event)
2086
- }, {
2087
- event: "change",
2088
- callback: (event) => this.handleChangeEvent(event)
2089
- }];
2090
- this.pendingFiles = {};
2091
- }
2296
+ static 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
+ };
2336
+ proxiedComponent;
2337
+ mutationObserver;
2338
+ component;
2339
+ pendingActionTriggerModelElement = null;
2340
+ elementEventListeners = [{
2341
+ event: "input",
2342
+ callback: (event) => this.handleInputEvent(event)
2343
+ }, {
2344
+ event: "change",
2345
+ callback: (event) => this.handleChangeEvent(event)
2346
+ }];
2347
+ pendingFiles = {};
2348
+ static backendFactory = (controller) => new Backend_default(controller.urlValue, controller.requestMethodValue, controller.fetchCredentialsValue);
2092
2349
  initialize() {
2093
2350
  this.mutationObserver = new MutationObserver(this.onMutations.bind(this));
2094
2351
  this.createComponent();
@@ -2287,7 +2544,7 @@ var LiveControllerDefault = class LiveControllerDefault extends Controller {
2287
2544
  }
2288
2545
  onMutations(mutations) {
2289
2546
  mutations.forEach((mutation) => {
2290
- if (mutation.type === "attributes" && mutation.attributeName === "id" && this.element.id !== this.component.id) {
2547
+ if (mutation.type === "attributes" && mutation.attributeName === "id" && this.component.getOriginalId() !== this.component.id) {
2291
2548
  this.disconnectComponent();
2292
2549
  this.createComponent();
2293
2550
  this.connectComponent();
@@ -2295,45 +2552,4 @@ var LiveControllerDefault = class LiveControllerDefault extends Controller {
2295
2552
  });
2296
2553
  }
2297
2554
  };
2298
- LiveControllerDefault.values = {
2299
- name: String,
2300
- url: String,
2301
- props: {
2302
- type: Object,
2303
- default: {}
2304
- },
2305
- propsUpdatedFromParent: {
2306
- type: Object,
2307
- default: {}
2308
- },
2309
- listeners: {
2310
- type: Array,
2311
- default: []
2312
- },
2313
- eventsToEmit: {
2314
- type: Array,
2315
- default: []
2316
- },
2317
- eventsToDispatch: {
2318
- type: Array,
2319
- default: []
2320
- },
2321
- debounce: {
2322
- type: Number,
2323
- default: 150
2324
- },
2325
- fingerprint: {
2326
- type: String,
2327
- default: ""
2328
- },
2329
- requestMethod: {
2330
- type: String,
2331
- default: "post"
2332
- },
2333
- fetchCredentials: {
2334
- type: String,
2335
- default: "same-origin"
2336
- }
2337
- };
2338
- LiveControllerDefault.backendFactory = (controller) => new Backend_default(controller.urlValue, controller.requestMethodValue, controller.fetchCredentialsValue);
2339
2555
  export { Component, LiveControllerDefault as default, getComponent };