phoenix_live_view 1.2.0-rc.2 → 1.2.0

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.
Files changed (27) hide show
  1. package/README.md +5 -5
  2. package/assets/js/phoenix_live_view/README.md +3 -0
  3. package/assets/js/phoenix_live_view/{aria.js → aria.ts} +18 -10
  4. package/assets/js/phoenix_live_view/{browser.js → browser.ts} +12 -8
  5. package/assets/js/phoenix_live_view/{dom.js → dom.ts} +107 -34
  6. package/assets/js/phoenix_live_view/{dom_patch.js → dom_patch.ts} +187 -124
  7. package/assets/js/phoenix_live_view/{dom_post_morph_restorer.js → dom_post_morph_restorer.ts} +17 -2
  8. package/assets/js/phoenix_live_view/{element_ref.js → element_ref.ts} +17 -11
  9. package/assets/js/phoenix_live_view/entry_uploader.js +4 -4
  10. package/assets/js/phoenix_live_view/{hooks.js → hooks.ts} +108 -91
  11. package/assets/js/phoenix_live_view/index.ts +14 -301
  12. package/assets/js/phoenix_live_view/js.js +2 -1
  13. package/assets/js/phoenix_live_view/js_commands.ts +12 -9
  14. package/assets/js/phoenix_live_view/{live_socket.js → live_socket.ts} +582 -114
  15. package/assets/js/phoenix_live_view/live_uploader.js +1 -1
  16. package/assets/js/phoenix_live_view/rendered.js +3 -0
  17. package/assets/js/phoenix_live_view/{utils.js → utils.ts} +35 -6
  18. package/assets/js/phoenix_live_view/{view.js → view.ts} +221 -110
  19. package/assets/js/phoenix_live_view/view_hook.ts +92 -32
  20. package/package.json +5 -2
  21. package/priv/static/phoenix_live_view.cjs.js +577 -314
  22. package/priv/static/phoenix_live_view.cjs.js.map +4 -4
  23. package/priv/static/phoenix_live_view.esm.js +577 -314
  24. package/priv/static/phoenix_live_view.esm.js.map +4 -4
  25. package/priv/static/phoenix_live_view.js +584 -314
  26. package/priv/static/phoenix_live_view.min.js +7 -7
  27. /package/assets/js/phoenix_live_view/{constants.js → constants.ts} +0 -0
@@ -37,14 +37,14 @@ var LiveView = (() => {
37
37
  // js/phoenix_live_view/index.ts
38
38
  var phoenix_live_view_exports = {};
39
39
  __export(phoenix_live_view_exports, {
40
- LiveSocket: () => LiveSocket2,
40
+ LiveSocket: () => LiveSocket,
41
41
  ViewHook: () => ViewHook,
42
42
  createHook: () => createHook,
43
43
  getFileURLForUpload: () => getFileURLForUpload,
44
44
  isUsedInput: () => isUsedInput
45
45
  });
46
46
 
47
- // js/phoenix_live_view/constants.js
47
+ // js/phoenix_live_view/constants.ts
48
48
  var CONSECUTIVE_RELOADS = "consecutive-reloads";
49
49
  var MAX_RELOADS = 10;
50
50
  var RELOAD_JITTER_MIN = 5e3;
@@ -186,12 +186,12 @@ var LiveView = (() => {
186
186
  }
187
187
  this.uploadChannel.leave();
188
188
  this.errored = true;
189
- clearTimeout(this.chunkTimer);
189
+ this.chunkTimer != null && clearTimeout(this.chunkTimer);
190
190
  this.entry.error(reason);
191
191
  }
192
192
  upload() {
193
193
  this.uploadChannel.onError((reason) => this.error(reason));
194
- this.uploadChannel.join().receive("ok", (_data) => this.readNextChunk()).receive("error", (reason) => this.error(reason));
194
+ this.uploadChannel.join().receive("ok", (_data) => this.readNextChunk()).receive("error", ({ reason }) => this.error(reason));
195
195
  }
196
196
  isDone() {
197
197
  return this.offset >= this.entry.file.size;
@@ -203,7 +203,8 @@ var LiveView = (() => {
203
203
  this.chunkSize + this.offset
204
204
  );
205
205
  reader.onload = (e) => {
206
- if (e.target.error === null) {
206
+ var _a, _b;
207
+ if (((_a = e.target) == null ? void 0 : _a.error) === null) {
207
208
  this.offset += /** @type {ArrayBuffer} */
208
209
  e.target.result.byteLength;
209
210
  this.pushChunk(
@@ -211,7 +212,7 @@ var LiveView = (() => {
211
212
  e.target.result
212
213
  );
213
214
  } else {
214
- return logError("Read error: " + e.target.error);
215
+ return logError("Read error: " + ((_b = e.target) == null ? void 0 : _b.error));
215
216
  }
216
217
  };
217
218
  reader.readAsArrayBuffer(blob);
@@ -232,8 +233,23 @@ var LiveView = (() => {
232
233
  }
233
234
  };
234
235
 
235
- // js/phoenix_live_view/utils.js
236
+ // js/phoenix_live_view/utils.ts
236
237
  var logError = (msg, obj) => console.error && console.error(msg, obj);
238
+ var ensureSameOrigin = (href, kind) => {
239
+ let url;
240
+ try {
241
+ url = new URL(href, window.location.href);
242
+ } catch (e) {
243
+ throw new Error(
244
+ `expected ${kind} destination to be a valid URL, got: ${href}`
245
+ );
246
+ }
247
+ if (url.origin !== window.location.origin) {
248
+ throw new Error(
249
+ `cannot ${kind} to "${href}" because its origin does not match the current origin "${window.location.origin}". Use window.location directly for cross-origin navigation.`
250
+ );
251
+ }
252
+ };
237
253
  var isCid = (cid) => {
238
254
  const type = typeof cid;
239
255
  return type === "number" || type === "string" && /^(0|[1-9]\d*)$/.test(cid);
@@ -274,12 +290,13 @@ var LiveView = (() => {
274
290
  var clone = (obj) => {
275
291
  return JSON.parse(JSON.stringify(obj));
276
292
  };
277
- var closestPhxBinding = (el, binding, borderEl) => {
293
+ var closestPhxBinding = (startEl, binding, borderEl) => {
294
+ let el = startEl;
278
295
  do {
279
- if (el.matches(`[${binding}]`) && !el.disabled) {
296
+ if (el.matches(`[${binding}]`) && !("disabled" in el && el.disabled)) {
280
297
  return el;
281
298
  }
282
- el = el.parentElement || el.parentNode;
299
+ el = el.parentElement;
283
300
  } while (el !== null && el.nodeType === 1 && !(borderEl && borderEl.isSameNode(el) || el.matches(PHX_VIEW_SELECTOR)));
284
301
  return null;
285
302
  };
@@ -311,7 +328,7 @@ var LiveView = (() => {
311
328
  return false;
312
329
  };
313
330
 
314
- // js/phoenix_live_view/browser.js
331
+ // js/phoenix_live_view/browser.ts
315
332
  var Browser = {
316
333
  canPushState() {
317
334
  return typeof history.pushState !== "undefined";
@@ -358,7 +375,7 @@ var LiveView = (() => {
358
375
  }
359
376
  });
360
377
  }
361
- } else {
378
+ } else if (to) {
362
379
  this.redirect(to);
363
380
  }
364
381
  },
@@ -375,7 +392,7 @@ var LiveView = (() => {
375
392
  deleteCookie(name) {
376
393
  document.cookie = `${name}=; max-age=-1; path=/`;
377
394
  },
378
- redirect(toURL, flash, navigate = (url) => {
395
+ redirect(toURL, flash = null, navigate = (url) => {
379
396
  window.location.href = url;
380
397
  }) {
381
398
  if (flash) {
@@ -396,11 +413,21 @@ var LiveView = (() => {
396
413
  };
397
414
  var browser_default = Browser;
398
415
 
399
- // js/phoenix_live_view/dom.js
416
+ // js/phoenix_live_view/dom.ts
400
417
  var DOM = {
401
418
  byId(id) {
402
419
  return document.getElementById(id) || logError(`no id found for ${id}`);
403
420
  },
421
+ elementFromTarget(target) {
422
+ if (!(target instanceof Node)) {
423
+ return null;
424
+ }
425
+ if (target.nodeType === Node.ELEMENT_NODE) {
426
+ return target;
427
+ } else {
428
+ return target.parentElement;
429
+ }
430
+ },
404
431
  removeClass(el, className) {
405
432
  el.classList.remove(className);
406
433
  if (el.classList.length === 0) {
@@ -438,12 +465,20 @@ var LiveView = (() => {
438
465
  inputsOutsideForm
439
466
  );
440
467
  },
441
- findComponentNodeList(viewId, cid, doc2 = document) {
442
- return this.all(
443
- doc2,
468
+ findComponent(viewId, cid, doc2 = document) {
469
+ return doc2.querySelector(
444
470
  `[${PHX_VIEW_REF}="${viewId}"][${PHX_COMPONENT}="${cid}"]`
445
471
  );
446
472
  },
473
+ getComponent(viewId, cid, doc2 = document) {
474
+ const el = this.findComponent(viewId, cid, doc2);
475
+ if (!el) {
476
+ throw new Error(
477
+ `no component found matching viewId ${viewId} and cid ${cid}`
478
+ );
479
+ }
480
+ return el;
481
+ },
447
482
  isPhxDestroyed(node) {
448
483
  return node.id && DOM.private(node, "destroyed") ? true : false;
449
484
  },
@@ -836,11 +871,23 @@ var LiveView = (() => {
836
871
  focused.setSelectionRange(selectionStart, selectionEnd);
837
872
  }
838
873
  },
839
- isFormInput(el) {
840
- if (el.localName && customElements.get(el.localName)) {
841
- return customElements.get(el.localName)[`formAssociated`];
874
+ /**
875
+ * Returns true if the element is an input that can be focused and edited by the user,
876
+ * so we can skip patching it if it has focus.
877
+ */
878
+ isEditableInput(el) {
879
+ return this.isFormAssociated(el) && !(el instanceof HTMLButtonElement) && !(el instanceof HTMLInputElement && el.type === "button");
880
+ },
881
+ isFormAssociated(el) {
882
+ if (!(el instanceof HTMLElement))
883
+ return false;
884
+ if (el.localName) {
885
+ const customEl = customElements.get(el.localName);
886
+ if (customEl) {
887
+ return customEl.formAssociated === true;
888
+ }
842
889
  }
843
- return /^(?:input|select|textarea)$/i.test(el.tagName) && el.type !== "button";
890
+ return el instanceof HTMLInputElement || el instanceof HTMLSelectElement || el instanceof HTMLTextAreaElement || el instanceof HTMLButtonElement;
844
891
  },
845
892
  syncAttrsToProps(el) {
846
893
  if (el instanceof HTMLInputElement && CHECKABLE_INPUTS.indexOf(el.type.toLocaleLowerCase()) >= 0) {
@@ -857,13 +904,13 @@ var LiveView = (() => {
857
904
  if (DOM.isPhxUpdate(container, phxUpdate, ["append", "prepend", PHX_STREAM])) {
858
905
  const toRemove = [];
859
906
  container.childNodes.forEach((childNode) => {
860
- if (!childNode.id) {
861
- const isEmptyTextNode = childNode.nodeType === Node.TEXT_NODE && childNode.nodeValue.trim() === "";
907
+ if (!("id" in childNode) || !childNode.id) {
908
+ const isEmptyTextNode = childNode.nodeType === Node.TEXT_NODE && childNode.nodeValue && childNode.nodeValue.trim() === "";
862
909
  if (!isEmptyTextNode && childNode.nodeType !== Node.COMMENT_NODE) {
863
910
  logError(
864
911
  `only HTML element tags with an id are allowed inside containers with phx-update.
865
912
 
866
- removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
913
+ removing illegal node: "${("outerHTML" in childNode && childNode.outerHTML || childNode.nodeValue || "").trim()}"
867
914
 
868
915
  `
869
916
  );
@@ -891,9 +938,12 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
891
938
  Object.keys(attrs).forEach(
892
939
  (attr) => newContainer.setAttribute(attr, attrs[attr])
893
940
  );
894
- retainedAttrs.forEach(
895
- (attr) => newContainer.setAttribute(attr, container.getAttribute(attr))
896
- );
941
+ retainedAttrs.forEach((attr) => {
942
+ const value = container.getAttribute(attr);
943
+ if (value !== null) {
944
+ newContainer.setAttribute(attr, value);
945
+ }
946
+ });
897
947
  newContainer.innerHTML = container.innerHTML;
898
948
  container.replaceWith(newContainer);
899
949
  return newContainer;
@@ -1145,7 +1195,7 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
1145
1195
  [],
1146
1196
  (existing) => existing.concat(newFiles)
1147
1197
  );
1148
- inputEl.value = null;
1198
+ inputEl.value = "";
1149
1199
  } else {
1150
1200
  if (dataTransfer && dataTransfer.files.length > 0) {
1151
1201
  inputEl.files = dataTransfer.files;
@@ -1228,20 +1278,20 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
1228
1278
  }
1229
1279
  };
1230
1280
 
1231
- // js/phoenix_live_view/aria.js
1281
+ // js/phoenix_live_view/aria.ts
1232
1282
  var ARIA = {
1233
1283
  anyOf(instance, classes) {
1234
- return classes.find((name) => instance instanceof name);
1284
+ return classes.some((name) => instance instanceof name);
1235
1285
  },
1236
- isFocusable(el, interactiveOnly) {
1237
- return el instanceof HTMLAnchorElement && el.rel !== "ignore" || el instanceof HTMLAreaElement && el.href !== void 0 || !el.disabled && this.anyOf(el, [
1286
+ isFocusable(el, interactiveOnly = false) {
1287
+ return el instanceof HTMLAnchorElement && el.rel !== "ignore" || el instanceof HTMLAreaElement && el.href !== void 0 || !("disabled" in el && el.disabled) && this.anyOf(el, [
1238
1288
  HTMLInputElement,
1239
1289
  HTMLSelectElement,
1240
1290
  HTMLTextAreaElement,
1241
1291
  HTMLButtonElement
1242
- ]) || el instanceof HTMLIFrameElement || el.tabIndex >= 0 && el.getAttribute("aria-hidden") !== "true" || !interactiveOnly && el.getAttribute("tabindex") !== null && el.getAttribute("aria-hidden") !== "true";
1292
+ ]) || el instanceof HTMLIFrameElement || el instanceof HTMLElement && el.tabIndex >= 0 && el.getAttribute("aria-hidden") !== "true" || !interactiveOnly && el.getAttribute("tabindex") !== null && el.getAttribute("aria-hidden") !== "true";
1243
1293
  },
1244
- attemptFocus(el, interactiveOnly) {
1294
+ attemptFocus(el, interactiveOnly = false) {
1245
1295
  if (this.isFocusable(el, interactiveOnly)) {
1246
1296
  try {
1247
1297
  el.focus();
@@ -1258,6 +1308,7 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
1258
1308
  }
1259
1309
  child = child.nextElementSibling;
1260
1310
  }
1311
+ return false;
1261
1312
  },
1262
1313
  focusFirst(el) {
1263
1314
  let child = el.firstElementChild;
@@ -1267,6 +1318,7 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
1267
1318
  }
1268
1319
  child = child.nextElementSibling;
1269
1320
  }
1321
+ return false;
1270
1322
  },
1271
1323
  focusLast(el) {
1272
1324
  let child = el.lastElementChild;
@@ -1276,79 +1328,12 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
1276
1328
  }
1277
1329
  child = child.previousElementSibling;
1278
1330
  }
1331
+ return false;
1279
1332
  }
1280
1333
  };
1281
1334
  var aria_default = ARIA;
1282
1335
 
1283
- // js/phoenix_live_view/hooks.js
1284
- var Hooks = {
1285
- LiveFileUpload: {
1286
- activeRefs() {
1287
- return this.el.getAttribute(PHX_ACTIVE_ENTRY_REFS);
1288
- },
1289
- preflightedRefs() {
1290
- return this.el.getAttribute(PHX_PREFLIGHTED_REFS);
1291
- },
1292
- mounted() {
1293
- this.js().ignoreAttributes(this.el, ["value"]);
1294
- this.preflightedWas = this.preflightedRefs();
1295
- },
1296
- updated() {
1297
- const newPreflights = this.preflightedRefs();
1298
- if (this.preflightedWas !== newPreflights) {
1299
- this.preflightedWas = newPreflights;
1300
- if (newPreflights === "") {
1301
- this.__view().cancelSubmit(this.el.form);
1302
- }
1303
- }
1304
- if (this.activeRefs() === "") {
1305
- this.el.value = null;
1306
- }
1307
- this.el.dispatchEvent(new CustomEvent(PHX_LIVE_FILE_UPDATED));
1308
- }
1309
- },
1310
- LiveImgPreview: {
1311
- mounted() {
1312
- this.ref = this.el.getAttribute("data-phx-entry-ref");
1313
- this.inputEl = document.getElementById(
1314
- this.el.getAttribute(PHX_UPLOAD_REF)
1315
- );
1316
- this.url = LiveUploader.getEntryDataURL(this.inputEl, this.ref);
1317
- this.el.src = this.url;
1318
- },
1319
- destroyed() {
1320
- URL.revokeObjectURL(this.url);
1321
- }
1322
- },
1323
- FocusWrap: {
1324
- mounted() {
1325
- this.focusStart = this.el.firstElementChild;
1326
- this.focusEnd = this.el.lastElementChild;
1327
- this.focusStart.addEventListener("focus", (e) => {
1328
- if (!e.relatedTarget || !this.el.contains(e.relatedTarget)) {
1329
- const nextFocus = e.target.nextElementSibling;
1330
- aria_default.attemptFocus(nextFocus) || aria_default.focusFirst(nextFocus);
1331
- } else {
1332
- aria_default.focusLast(this.el);
1333
- }
1334
- });
1335
- this.focusEnd.addEventListener("focus", (e) => {
1336
- if (!e.relatedTarget || !this.el.contains(e.relatedTarget)) {
1337
- const nextFocus = e.target.previousElementSibling;
1338
- aria_default.attemptFocus(nextFocus) || aria_default.focusLast(nextFocus);
1339
- } else {
1340
- aria_default.focusFirst(this.el);
1341
- }
1342
- });
1343
- if (!this.el.contains(document.activeElement)) {
1344
- this.el.addEventListener("phx:show-end", () => this.el.focus());
1345
- if (window.getComputedStyle(this.el).display !== "none") {
1346
- aria_default.focusFirst(this.el);
1347
- }
1348
- }
1349
- }
1350
- }
1351
- };
1336
+ // js/phoenix_live_view/hooks.ts
1352
1337
  var findScrollContainer = (el) => {
1353
1338
  if (["HTML", "BODY"].indexOf(el.nodeName.toUpperCase()) >= 0)
1354
1339
  return null;
@@ -1389,7 +1374,7 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
1389
1374
  const rect = el.getBoundingClientRect();
1390
1375
  return Math.ceil(rect.top) >= top(scrollContainer) && Math.floor(rect.top) <= bottom(scrollContainer);
1391
1376
  };
1392
- Hooks.InfiniteScroll = {
1377
+ var InfiniteScroll = {
1393
1378
  mounted() {
1394
1379
  this.scrollContainer = findScrollContainer(this.el);
1395
1380
  let scrollBefore = scrollTop(this.scrollContainer);
@@ -1465,9 +1450,9 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
1465
1450
  } else if (isScrollingDown && topOverran && rect.top <= 0) {
1466
1451
  topOverran = false;
1467
1452
  }
1468
- if (topEvent && isScrollingUp && isAtViewportTop(firstChild, this.scrollContainer)) {
1453
+ if (topEvent && isScrollingUp && firstChild && isAtViewportTop(firstChild, this.scrollContainer)) {
1469
1454
  onFirstChildAtTop(topEvent, firstChild);
1470
- } else if (bottomEvent && isScrollingDown && isAtViewportBottom(lastChild, this.scrollContainer)) {
1455
+ } else if (bottomEvent && isScrollingDown && lastChild && isAtViewportBottom(lastChild, this.scrollContainer)) {
1471
1456
  onLastChildAtBottom(bottomEvent, lastChild);
1472
1457
  }
1473
1458
  scrollBefore = scrollNow;
@@ -1531,9 +1516,80 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
1531
1516
  return rect;
1532
1517
  }
1533
1518
  };
1519
+ var LiveFileUpload = {
1520
+ activeRefs() {
1521
+ return this.el.getAttribute(PHX_ACTIVE_ENTRY_REFS);
1522
+ },
1523
+ preflightedRefs() {
1524
+ return this.el.getAttribute(PHX_PREFLIGHTED_REFS);
1525
+ },
1526
+ mounted() {
1527
+ this.js().ignoreAttributes(this.el, ["value"]);
1528
+ this.preflightedWas = this.preflightedRefs();
1529
+ },
1530
+ updated() {
1531
+ const newPreflights = this.preflightedRefs();
1532
+ if (this.preflightedWas !== newPreflights) {
1533
+ this.preflightedWas = newPreflights;
1534
+ if (newPreflights === "") {
1535
+ this.__view().cancelSubmit(this.el.form);
1536
+ }
1537
+ }
1538
+ if (this.activeRefs() === "") {
1539
+ this.el.value = "";
1540
+ }
1541
+ this.el.dispatchEvent(new CustomEvent(PHX_LIVE_FILE_UPDATED));
1542
+ }
1543
+ };
1544
+ var LiveImgPreview = {
1545
+ mounted() {
1546
+ this.ref = this.el.getAttribute("data-phx-entry-ref");
1547
+ this.inputEl = document.getElementById(
1548
+ this.el.getAttribute(PHX_UPLOAD_REF)
1549
+ );
1550
+ this.url = LiveUploader.getEntryDataURL(this.inputEl, this.ref);
1551
+ this.el.src = this.url;
1552
+ },
1553
+ destroyed() {
1554
+ URL.revokeObjectURL(this.url);
1555
+ }
1556
+ };
1557
+ var Hooks = {
1558
+ LiveFileUpload,
1559
+ LiveImgPreview,
1560
+ FocusWrap: {
1561
+ mounted() {
1562
+ this.focusStart = this.el.firstElementChild;
1563
+ this.focusEnd = this.el.lastElementChild;
1564
+ this.focusStart.addEventListener("focus", (e) => {
1565
+ if (!e.relatedTarget || !this.el.contains(e.relatedTarget)) {
1566
+ const nextFocus = e.target.nextElementSibling;
1567
+ aria_default.attemptFocus(nextFocus) || aria_default.focusFirst(nextFocus);
1568
+ } else {
1569
+ aria_default.focusLast(this.el);
1570
+ }
1571
+ });
1572
+ this.focusEnd.addEventListener("focus", (e) => {
1573
+ if (!e.relatedTarget || !this.el.contains(e.relatedTarget)) {
1574
+ const nextFocus = e.target.previousElementSibling;
1575
+ aria_default.attemptFocus(nextFocus) || aria_default.focusLast(nextFocus);
1576
+ } else {
1577
+ aria_default.focusFirst(this.el);
1578
+ }
1579
+ });
1580
+ if (!this.el.contains(document.activeElement)) {
1581
+ this.el.addEventListener("phx:show-end", () => this.el.focus());
1582
+ if (window.getComputedStyle(this.el).display !== "none") {
1583
+ aria_default.focusFirst(this.el);
1584
+ }
1585
+ }
1586
+ }
1587
+ },
1588
+ InfiniteScroll
1589
+ };
1534
1590
  var hooks_default = Hooks;
1535
1591
 
1536
- // js/phoenix_live_view/element_ref.js
1592
+ // js/phoenix_live_view/element_ref.ts
1537
1593
  var ElementRef = class {
1538
1594
  static onUnlock(el, callback) {
1539
1595
  if (!dom_default.isLocked(el) && !el.closest(`[${PHX_REF_LOCK}]`)) {
@@ -1629,11 +1685,11 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
1629
1685
  this.el.removeAttribute(PHX_REF_LOADING);
1630
1686
  const disabledVal = this.el.getAttribute(PHX_DISABLED);
1631
1687
  const readOnlyVal = this.el.getAttribute(PHX_READONLY);
1632
- if (readOnlyVal !== null) {
1688
+ if (readOnlyVal !== null && "readOnly" in this.el) {
1633
1689
  this.el.readOnly = readOnlyVal === "true" ? true : false;
1634
1690
  this.el.removeAttribute(PHX_READONLY);
1635
1691
  }
1636
- if (disabledVal !== null) {
1692
+ if (disabledVal !== null && "disabled" in this.el) {
1637
1693
  this.el.disabled = disabledVal === "true" ? true : false;
1638
1694
  this.el.removeAttribute(PHX_DISABLED);
1639
1695
  }
@@ -1660,6 +1716,7 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
1660
1716
  isLoadingUndoneBy(ref) {
1661
1717
  return this.loadingRef === null ? false : this.loadingRef <= ref;
1662
1718
  }
1719
+ /** @internal */
1663
1720
  isLockUndoneBy(ref) {
1664
1721
  return this.lockRef === null ? false : this.lockRef <= ref;
1665
1722
  }
@@ -1672,7 +1729,7 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
1672
1729
  }
1673
1730
  };
1674
1731
 
1675
- // js/phoenix_live_view/dom_post_morph_restorer.js
1732
+ // js/phoenix_live_view/dom_post_morph_restorer.ts
1676
1733
  var DOMPostMorphRestorer = class {
1677
1734
  constructor(containerBefore, containerAfter, updateType) {
1678
1735
  const idsBefore = /* @__PURE__ */ new Set();
@@ -2263,47 +2320,48 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
2263
2320
  var morphdom = morphdomFactory(morphAttrs);
2264
2321
  var morphdom_esm_default = morphdom;
2265
2322
 
2266
- // js/phoenix_live_view/dom_patch.js
2323
+ // js/phoenix_live_view/dom_patch.ts
2267
2324
  var DOMPatch = class {
2268
- constructor(view, container, id, html, streams, targetCID, opts = {}) {
2325
+ constructor(view, container, html, streams, targetCID, opts = {}) {
2326
+ var _a;
2269
2327
  this.view = view;
2270
2328
  this.liveSocket = view.liveSocket;
2271
2329
  this.container = container;
2272
- this.id = id;
2273
2330
  this.rootID = view.root.id;
2274
2331
  this.html = html;
2275
2332
  this.streams = streams;
2276
2333
  this.streamInserts = {};
2277
2334
  this.streamComponentRestore = {};
2278
2335
  this.targetCID = targetCID;
2279
- this.cidPatch = isCid(this.targetCID);
2280
2336
  this.pendingRemoves = [];
2281
2337
  this.phxRemove = this.liveSocket.binding("remove");
2282
- this.targetContainer = this.isCIDPatch() ? this.targetCIDContainer(html) : container;
2283
- this.callbacks = {
2284
- beforeadded: [],
2285
- beforeupdated: [],
2286
- beforephxChildAdded: [],
2287
- afteradded: [],
2288
- afterupdated: [],
2289
- afterdiscarded: [],
2290
- afterphxChildAdded: [],
2291
- aftertransitionsDiscarded: []
2292
- };
2338
+ this.targetContainer = targetCID ? dom_default.getComponent(this.view.id, targetCID) : container;
2339
+ this.beforeUpdatedCallbacks = [];
2340
+ this.afterAddedCallbacks = [];
2341
+ this.afterUpdatedCallbacks = [];
2342
+ this.afterPhxChildAddedCallbacks = [];
2343
+ this.afterDiscardedCallbacks = [];
2344
+ this.afterTransitionsDiscardedCallbacks = [];
2293
2345
  this.withChildren = opts.withChildren || opts.undoRef !== void 0 || false;
2294
- this.undoRef = opts.undoRef;
2346
+ this.undoRef = (_a = opts.undoRef) != null ? _a : null;
2347
+ }
2348
+ beforeUpdated(callback) {
2349
+ this.beforeUpdatedCallbacks.push(callback);
2295
2350
  }
2296
- before(kind, callback) {
2297
- this.callbacks[`before${kind}`].push(callback);
2351
+ afterAdded(callback) {
2352
+ this.afterAddedCallbacks.push(callback);
2298
2353
  }
2299
- after(kind, callback) {
2300
- this.callbacks[`after${kind}`].push(callback);
2354
+ afterUpdated(callback) {
2355
+ this.afterUpdatedCallbacks.push(callback);
2301
2356
  }
2302
- trackBefore(kind, ...args) {
2303
- this.callbacks[`before${kind}`].forEach((callback) => callback(...args));
2357
+ afterPhxChildAdded(callback) {
2358
+ this.afterPhxChildAddedCallbacks.push(callback);
2304
2359
  }
2305
- trackAfter(kind, ...args) {
2306
- this.callbacks[`after${kind}`].forEach((callback) => callback(...args));
2360
+ afterDiscarded(callback) {
2361
+ this.afterDiscardedCallbacks.push(callback);
2362
+ }
2363
+ afterTransitionsDiscarded(callback) {
2364
+ this.afterTransitionsDiscardedCallbacks.push(callback);
2307
2365
  }
2308
2366
  markPrunableContentForRemoval() {
2309
2367
  const phxUpdate = this.liveSocket.binding(PHX_UPDATE);
@@ -2318,10 +2376,7 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
2318
2376
  perform(isJoinPatch) {
2319
2377
  const { view, liveSocket, html, container } = this;
2320
2378
  let targetContainer = this.targetContainer;
2321
- if (this.isCIDPatch() && !this.targetContainer) {
2322
- return;
2323
- }
2324
- if (this.isCIDPatch()) {
2379
+ if (this.targetCID) {
2325
2380
  const closestLock = targetContainer.closest(`[${PHX_REF_LOCK}]`);
2326
2381
  if (closestLock && !closestLock.isSameNode(targetContainer)) {
2327
2382
  const clonedTree = dom_default.private(closestLock, PHX_REF_LOCK);
@@ -2353,6 +2408,8 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
2353
2408
  // another case is the recursive patch of a stream item that was kept on reset (-> onBeforeNodeAdded)
2354
2409
  childrenOnly: targetContainer2.getAttribute(PHX_COMPONENT) === null && !withChildren,
2355
2410
  getNodeKey: (node) => {
2411
+ if (!(node instanceof Element))
2412
+ return null;
2356
2413
  if (dom_default.isPhxDestroyed(node)) {
2357
2414
  return null;
2358
2415
  }
@@ -2360,9 +2417,9 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
2360
2417
  return node.id;
2361
2418
  }
2362
2419
  if (dom_default.private(node, "clientsideIdAttribute")) {
2363
- return node.getAttribute && node.getAttribute(PHX_MAGIC_ID);
2420
+ return node.getAttribute(PHX_MAGIC_ID);
2364
2421
  }
2365
- return node.id || node.getAttribute && node.getAttribute(PHX_MAGIC_ID);
2422
+ return node.id || node.getAttribute(PHX_MAGIC_ID);
2366
2423
  },
2367
2424
  // skip indexing from children when container is stream
2368
2425
  skipFromChildren: (from) => {
@@ -2383,7 +2440,7 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
2383
2440
  const nonStreamChild = Array.from(parent.children).find(
2384
2441
  (c) => !c.hasAttribute(PHX_STREAM_REF)
2385
2442
  );
2386
- parent.insertBefore(child, nonStreamChild);
2443
+ parent.insertBefore(child, nonStreamChild != null ? nonStreamChild : null);
2387
2444
  } else {
2388
2445
  parent.appendChild(child);
2389
2446
  }
@@ -2394,11 +2451,13 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
2394
2451
  },
2395
2452
  onBeforeNodeAdded: (el) => {
2396
2453
  var _a;
2454
+ if (!(el instanceof Element)) {
2455
+ return el;
2456
+ }
2397
2457
  if (((_a = this.getStreamInsert(el)) == null ? void 0 : _a.updateOnly) && !this.streamComponentRestore[el.id]) {
2398
2458
  return false;
2399
2459
  }
2400
2460
  dom_default.maintainPrivateHooks(el, el, phxViewportTop, phxViewportBottom);
2401
- this.trackBefore("added", el);
2402
2461
  let morphedEl = el;
2403
2462
  if (this.streamComponentRestore[el.id]) {
2404
2463
  morphedEl = this.streamComponentRestore[el.id];
@@ -2408,9 +2467,11 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
2408
2467
  return morphedEl;
2409
2468
  },
2410
2469
  onNodeAdded: (el) => {
2411
- if (el.getAttribute) {
2412
- this.maybeReOrderStream(el, true);
2470
+ if (!(el instanceof Element)) {
2471
+ added.push(el);
2472
+ return;
2413
2473
  }
2474
+ this.maybeReOrderStream(el, true);
2414
2475
  if (dom_default.isPortalTemplate(el)) {
2415
2476
  portalCallbacks.push(() => this.teleport(el, morph));
2416
2477
  }
@@ -2423,7 +2484,7 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
2423
2484
  externalFormTriggered = el;
2424
2485
  }
2425
2486
  if (dom_default.isPhxChild(el) && view.ownsElement(el) || dom_default.isPhxSticky(el) && view.ownsElement(el.parentNode)) {
2426
- this.trackAfter("phxChildAdded", el);
2487
+ this.trackAfterPhxChildAdded(el);
2427
2488
  }
2428
2489
  if (el.nodeName === "SCRIPT" && el.hasAttribute(PHX_RUNTIME_HOOK)) {
2429
2490
  this.handleRuntimeHook(el, source);
@@ -2432,7 +2493,11 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
2432
2493
  },
2433
2494
  onNodeDiscarded: (el) => this.onNodeDiscarded(el),
2434
2495
  onBeforeNodeDiscarded: (el) => {
2435
- if (el.getAttribute && el.getAttribute(PHX_PRUNE) !== null) {
2496
+ var _a;
2497
+ if (!(el instanceof Element)) {
2498
+ return true;
2499
+ }
2500
+ if (el.getAttribute(PHX_PRUNE) !== null) {
2436
2501
  return true;
2437
2502
  }
2438
2503
  if (el.parentElement !== null && el.id && dom_default.isPhxUpdate(el.parentElement, phxUpdate, [
@@ -2442,7 +2507,7 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
2442
2507
  ])) {
2443
2508
  return false;
2444
2509
  }
2445
- if (el.getAttribute && el.getAttribute(PHX_TELEPORTED_REF)) {
2510
+ if (el.getAttribute(PHX_TELEPORTED_REF)) {
2446
2511
  return false;
2447
2512
  }
2448
2513
  if (this.maybePendingRemove(el)) {
@@ -2453,7 +2518,7 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
2453
2518
  }
2454
2519
  if (dom_default.isPortalTemplate(el)) {
2455
2520
  const teleportedEl = document.getElementById(
2456
- el.content.firstElementChild.id
2521
+ ((_a = el.content.firstElementChild) == null ? void 0 : _a.id) || ""
2457
2522
  );
2458
2523
  if (teleportedEl) {
2459
2524
  teleportedEl.remove();
@@ -2484,7 +2549,7 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
2484
2549
  phxViewportBottom
2485
2550
  );
2486
2551
  dom_default.cleanChildNodes(toEl, phxUpdate);
2487
- const isFocusedFormEl = focused && fromEl.isSameNode(focused) && dom_default.isFormInput(fromEl);
2552
+ const isFocusedFormEl = focused && fromEl.isSameNode(focused) && dom_default.isEditableInput(fromEl);
2488
2553
  const focusedSelectChanged = isFocusedFormEl && this.isChangedSelect(fromEl, toEl);
2489
2554
  if (this.skipCIDSibling(toEl)) {
2490
2555
  this.maybeCloneLockedElement(fromEl, isFocusedFormEl);
@@ -2505,7 +2570,7 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
2505
2570
  return false;
2506
2571
  }
2507
2572
  if (dom_default.isIgnored(fromEl, phxUpdate) || fromEl.form && fromEl.form.isSameNode(externalFormTriggered)) {
2508
- this.trackBefore("updated", fromEl, toEl);
2573
+ this.trackBeforeUpdated(fromEl, toEl);
2509
2574
  dom_default.mergeAttrs(fromEl, toEl, {
2510
2575
  isIgnored: dom_default.isIgnored(fromEl, phxUpdate)
2511
2576
  });
@@ -2535,7 +2600,7 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
2535
2600
  return false;
2536
2601
  }
2537
2602
  if (isFocusedFormEl && fromEl.type !== "hidden" && !focusedSelectChanged) {
2538
- this.trackBefore("updated", fromEl, toEl);
2603
+ this.trackBeforeUpdated(fromEl, toEl);
2539
2604
  dom_default.mergeFocusedInput(fromEl, toEl);
2540
2605
  dom_default.syncAttrsToProps(fromEl);
2541
2606
  updates.push(fromEl);
@@ -2556,15 +2621,14 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
2556
2621
  }
2557
2622
  dom_default.syncAttrsToProps(toEl);
2558
2623
  dom_default.applyStickyOperations(toEl);
2559
- this.trackBefore("updated", fromEl, toEl);
2624
+ this.trackBeforeUpdated(fromEl, toEl);
2560
2625
  return fromEl;
2561
2626
  }
2562
2627
  }
2563
2628
  };
2564
2629
  morphdom_esm_default(targetContainer2, source, morphCallbacks);
2565
2630
  };
2566
- this.trackBefore("added", container);
2567
- this.trackBefore("updated", container, container);
2631
+ this.trackBeforeUpdated(container, container);
2568
2632
  liveSocket.time("morphdom", () => {
2569
2633
  this.streams.forEach(([ref, inserts, deleteIds, reset]) => {
2570
2634
  inserts.forEach(([key, streamAt, limit, updateOnly]) => {
@@ -2600,13 +2664,14 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
2600
2664
  this.view.portalElementIds.forEach((id) => {
2601
2665
  const el = document.getElementById(id);
2602
2666
  if (el) {
2603
- const source = document.getElementById(
2604
- el.getAttribute(PHX_TELEPORTED_SRC)
2605
- );
2606
- if (!source) {
2607
- el.remove();
2608
- this.onNodeDiscarded(el);
2609
- this.view.dropPortalElementId(id);
2667
+ const srcId = el.getAttribute(PHX_TELEPORTED_SRC);
2668
+ if (srcId) {
2669
+ const source = document.getElementById(srcId);
2670
+ if (!source) {
2671
+ el.remove();
2672
+ this.onNodeDiscarded(el);
2673
+ this.view.dropPortalElementId(id);
2674
+ }
2610
2675
  }
2611
2676
  }
2612
2677
  });
@@ -2634,8 +2699,8 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
2634
2699
  () => dom_default.restoreFocus(focused, selectionStart, selectionEnd)
2635
2700
  );
2636
2701
  dom_default.dispatchEvent(document, "phx:update");
2637
- added.forEach((el) => this.trackAfter("added", el));
2638
- updates.forEach((el) => this.trackAfter("updated", el));
2702
+ added.forEach((el) => this.trackAfterAdded(el));
2703
+ updates.forEach((el) => this.trackAfterUpdated(el));
2639
2704
  this.transitionPendingRemoves();
2640
2705
  if (externalFormTriggered) {
2641
2706
  liveSocket.unload();
@@ -2657,11 +2722,29 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
2657
2722
  }
2658
2723
  return true;
2659
2724
  }
2725
+ trackBeforeUpdated(fromEl, toEl) {
2726
+ this.beforeUpdatedCallbacks.forEach((cb) => cb(fromEl, toEl));
2727
+ }
2728
+ trackAfterAdded(el) {
2729
+ this.afterAddedCallbacks.forEach((cb) => cb(el));
2730
+ }
2731
+ trackAfterUpdated(el) {
2732
+ this.afterUpdatedCallbacks.forEach((cb) => cb(el));
2733
+ }
2734
+ trackAfterPhxChildAdded(el) {
2735
+ this.afterPhxChildAddedCallbacks.forEach((cb) => cb(el));
2736
+ }
2737
+ trackAfterDiscarded(el) {
2738
+ this.afterDiscardedCallbacks.forEach((cb) => cb(el));
2739
+ }
2740
+ trackAfterTransitionsDiscarded(els) {
2741
+ this.afterTransitionsDiscardedCallbacks.forEach((cb) => cb(els));
2742
+ }
2660
2743
  onNodeDiscarded(el) {
2661
2744
  if (dom_default.isPhxChild(el) || dom_default.isPhxSticky(el)) {
2662
2745
  this.liveSocket.destroyViewByEl(el);
2663
2746
  }
2664
- this.trackAfter("discarded", el);
2747
+ this.trackAfterDiscarded(el);
2665
2748
  }
2666
2749
  maybePendingRemove(node) {
2667
2750
  if (node.getAttribute && node.getAttribute(this.phxRemove) !== null) {
@@ -2696,7 +2779,7 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
2696
2779
  (el2) => el2.setAttribute(PHX_STREAM_REF, ref)
2697
2780
  );
2698
2781
  }
2699
- maybeReOrderStream(el, isNew) {
2782
+ maybeReOrderStream(el, isNew = false) {
2700
2783
  const { ref, streamAt, reset } = this.getStreamInsert(el);
2701
2784
  if (streamAt === void 0) {
2702
2785
  return;
@@ -2752,11 +2835,13 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
2752
2835
  }
2753
2836
  maybeLimitStream(el) {
2754
2837
  const { limit } = this.getStreamInsert(el);
2755
- const children = limit !== null && Array.from(el.parentElement.children);
2756
- if (limit && limit < 0 && children.length > limit * -1) {
2757
- children.slice(0, children.length + limit).forEach((child) => this.removeStreamChildElement(child));
2758
- } else if (limit && limit >= 0 && children.length > limit) {
2759
- children.slice(limit).forEach((child) => this.removeStreamChildElement(child));
2838
+ if (limit !== null) {
2839
+ const children = Array.from(el.parentElement.children);
2840
+ if (limit < 0 && children.length > limit * -1) {
2841
+ children.slice(0, children.length + limit).forEach((child) => this.removeStreamChildElement(child));
2842
+ } else if (limit >= 0 && children.length > limit) {
2843
+ children.slice(limit).forEach((child) => this.removeStreamChildElement(child));
2844
+ }
2760
2845
  }
2761
2846
  }
2762
2847
  transitionPendingRemoves() {
@@ -2770,7 +2855,7 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
2770
2855
  }
2771
2856
  el.remove();
2772
2857
  });
2773
- this.trackAfter("transitionsDiscarded", pendingRemoves);
2858
+ this.trackAfterTransitionsDiscarded(pendingRemoves);
2774
2859
  });
2775
2860
  }
2776
2861
  }
@@ -2784,9 +2869,6 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
2784
2869
  toEl.value = fromEl.value;
2785
2870
  return !fromEl.isEqualNode(toEl);
2786
2871
  }
2787
- isCIDPatch() {
2788
- return this.cidPatch;
2789
- }
2790
2872
  skipCIDSibling(el) {
2791
2873
  return el.nodeType === Node.ELEMENT_NODE && el.hasAttribute(PHX_SKIP);
2792
2874
  }
@@ -2794,7 +2876,7 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
2794
2876
  if (!fromEl.hasAttribute(PHX_REF_SRC))
2795
2877
  return fromEl;
2796
2878
  const ref = new ElementRef(fromEl);
2797
- if (ref.lockRef === null || this.undoRef !== void 0 && ref.isLockUndoneBy(this.undoRef)) {
2879
+ if (!fromEl.hasAttribute(PHX_REF_LOCK) || this.undoRef !== null && ref.isLockUndoneBy(this.undoRef)) {
2798
2880
  return fromEl;
2799
2881
  }
2800
2882
  dom_default.applyStickyOperations(fromEl);
@@ -2805,24 +2887,10 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
2805
2887
  return isFocusedFormEl ? fromEl : clone2;
2806
2888
  }
2807
2889
  copyNestedPrivateLock(fromEl, toEl) {
2808
- if (this.undoRef === void 0 || !dom_default.private(toEl, PHX_REF_LOCK))
2890
+ if (this.undoRef === null || !dom_default.private(toEl, PHX_REF_LOCK))
2809
2891
  return;
2810
2892
  dom_default.putPrivate(fromEl, PHX_REF_LOCK, dom_default.private(toEl, PHX_REF_LOCK));
2811
2893
  }
2812
- targetCIDContainer(html) {
2813
- if (!this.isCIDPatch()) {
2814
- return;
2815
- }
2816
- const [first, ...rest] = dom_default.findComponentNodeList(
2817
- this.view.id,
2818
- this.targetCID
2819
- );
2820
- if (rest.length === 0 && dom_default.childNodeLength(html) === 1) {
2821
- return first;
2822
- } else {
2823
- return first && first.parentNode;
2824
- }
2825
- }
2826
2894
  indexOf(parent, child) {
2827
2895
  return Array.from(parent.children).indexOf(child);
2828
2896
  }
@@ -2862,12 +2930,13 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
2862
2930
  this.view.pushPortalElementId(toTeleport.id);
2863
2931
  }
2864
2932
  handleRuntimeHook(el, source) {
2933
+ var _a, _b;
2865
2934
  const name = el.getAttribute(PHX_RUNTIME_HOOK);
2866
2935
  let nonce = el.hasAttribute("nonce") ? el.getAttribute("nonce") : null;
2867
2936
  if (el.hasAttribute("nonce")) {
2868
2937
  const template = document.createElement("template");
2869
2938
  template.innerHTML = source;
2870
- nonce = template.content.querySelector(`script[${PHX_RUNTIME_HOOK}="${CSS.escape(name)}"]`).getAttribute("nonce");
2939
+ nonce = (_b = (_a = template.content.querySelector(`script[${PHX_RUNTIME_HOOK}="${CSS.escape(name)}"]`)) == null ? void 0 : _a.getAttribute("nonce")) != null ? _b : null;
2871
2940
  }
2872
2941
  const script = document.createElement("script");
2873
2942
  script.textContent = el.textContent;
@@ -3389,7 +3458,7 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
3389
3458
  }
3390
3459
  if (eventType === "change") {
3391
3460
  let { newCid, _target } = args;
3392
- _target = _target || (dom_default.isFormInput(sourceEl) ? sourceEl.name : void 0);
3461
+ _target = _target || (dom_default.isFormAssociated(sourceEl) ? sourceEl.name : void 0);
3393
3462
  if (_target) {
3394
3463
  pushOpts._target = _target;
3395
3464
  }
@@ -3903,6 +3972,7 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
3903
3972
  });
3904
3973
  },
3905
3974
  navigate(href, opts = {}) {
3975
+ ensureSameOrigin(href, "navigate");
3906
3976
  const customEvent = new CustomEvent("phx:exec");
3907
3977
  liveSocket.historyRedirect(
3908
3978
  customEvent,
@@ -3913,6 +3983,7 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
3913
3983
  );
3914
3984
  },
3915
3985
  patch(href, opts = {}) {
3986
+ ensureSameOrigin(href, "patch");
3916
3987
  const customEvent = new CustomEvent("phx:exec");
3917
3988
  liveSocket.pushHistoryPatch(
3918
3989
  customEvent,
@@ -3935,15 +4006,19 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
3935
4006
  get liveSocket() {
3936
4007
  return this.__liveSocket();
3937
4008
  }
4009
+ /** @internal */
3938
4010
  static makeID() {
3939
4011
  return viewHookID++;
3940
4012
  }
4013
+ /** @internal */
3941
4014
  static elementID(el) {
3942
4015
  return dom_default.private(el, HOOK_ID);
3943
4016
  }
4017
+ /** @internal */
3944
4018
  static deadHook(el) {
3945
4019
  return dom_default.private(el, DEAD_HOOK) === true;
3946
4020
  }
4021
+ /** @internal */
3947
4022
  constructor(view, el, callbacks) {
3948
4023
  this.el = el;
3949
4024
  this.__attachView(view);
@@ -4097,7 +4172,12 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
4097
4172
  }
4098
4173
  );
4099
4174
  const promises = targetPair.map(({ view, targetCtx }) => {
4100
- return view.pushHookEvent(this.el, targetCtx, event, payload || {});
4175
+ return view.pushHookEvent(
4176
+ this.el,
4177
+ targetCtx,
4178
+ event,
4179
+ payload || {}
4180
+ );
4101
4181
  });
4102
4182
  return Promise.allSettled(promises);
4103
4183
  }
@@ -4149,7 +4229,7 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
4149
4229
  }
4150
4230
  };
4151
4231
 
4152
- // js/phoenix_live_view/view.js
4232
+ // js/phoenix_live_view/view.ts
4153
4233
  var prependFormDataKey = (key, prefix) => {
4154
4234
  const isArray = key.endsWith("[]");
4155
4235
  let baseKey = isArray ? key.slice(0, -2) : key;
@@ -4164,7 +4244,8 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
4164
4244
  const liveViewEl = el.closest(PHX_VIEW_SELECTOR);
4165
4245
  return liveViewEl ? dom_default.private(liveViewEl, "view") : null;
4166
4246
  }
4167
- constructor(el, liveSocket, parentView, flash, liveReferer) {
4247
+ constructor(el, liveSocket, parentView, flash = null, liveReferer = null) {
4248
+ this.rendered = null;
4168
4249
  this.isDead = false;
4169
4250
  this.liveSocket = liveSocket;
4170
4251
  this.flash = flash;
@@ -4213,6 +4294,7 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
4213
4294
  this.root.children[this.id] = {};
4214
4295
  this.formsForRecovery = {};
4215
4296
  this.channel = this.liveSocket.channel(`lv:${this.id}`, () => {
4297
+ var _a;
4216
4298
  const url = this.href && this.expandURL(this.href);
4217
4299
  return {
4218
4300
  redirect: this.redirect ? url : void 0,
@@ -4220,7 +4302,7 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
4220
4302
  params: this.connectParams(liveReferer),
4221
4303
  session: this.getSession(),
4222
4304
  static: this.getStatic(),
4223
- flash: this.flash,
4305
+ flash: (_a = this.flash) != null ? _a : void 0,
4224
4306
  sticky: this.el.hasAttribute(PHX_STICKY)
4225
4307
  };
4226
4308
  });
@@ -4238,13 +4320,15 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
4238
4320
  }
4239
4321
  connectParams(liveReferer) {
4240
4322
  const params = this.liveSocket.params(this.el);
4241
- const manifest = dom_default.all(document, `[${this.binding(PHX_TRACK_STATIC)}]`).map((node) => node.src || node.href).filter((url) => typeof url === "string");
4323
+ const manifest = dom_default.all(document, `[${this.binding(PHX_TRACK_STATIC)}]`).map(
4324
+ (node) => "src" in node && node.src || "href" in node && node.href
4325
+ ).filter((url) => typeof url === "string");
4242
4326
  if (manifest.length > 0) {
4243
4327
  params["_track_static"] = manifest;
4244
4328
  }
4245
4329
  params["_mounts"] = this.joinCount;
4246
4330
  params["_mount_attempts"] = this.joinAttempts;
4247
- params["_live_referer"] = liveReferer;
4331
+ params["_live_referer"] = liveReferer != null ? liveReferer : void 0;
4248
4332
  this.joinAttempts++;
4249
4333
  return params;
4250
4334
  }
@@ -4268,7 +4352,7 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
4268
4352
  if (this.parent) {
4269
4353
  delete this.root.children[this.parent.id][this.id];
4270
4354
  }
4271
- clearTimeout(this.loaderTimer);
4355
+ this.loaderTimer != null && clearTimeout(this.loaderTimer);
4272
4356
  const onFinished = () => {
4273
4357
  callback();
4274
4358
  for (const id in this.viewHooks) {
@@ -4290,7 +4374,7 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
4290
4374
  this.el.classList.add(...classes);
4291
4375
  }
4292
4376
  showLoader(timeout) {
4293
- clearTimeout(this.loaderTimer);
4377
+ this.loaderTimer != null && clearTimeout(this.loaderTimer);
4294
4378
  if (timeout) {
4295
4379
  this.loaderTimer = setTimeout(() => this.showLoader(), timeout);
4296
4380
  } else {
@@ -4308,8 +4392,8 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
4308
4392
  );
4309
4393
  }
4310
4394
  hideLoader() {
4311
- clearTimeout(this.loaderTimer);
4312
- clearTimeout(this.disconnectedTimer);
4395
+ this.loaderTimer != null && clearTimeout(this.loaderTimer);
4396
+ this.disconnectedTimer != null && clearTimeout(this.disconnectedTimer);
4313
4397
  this.setContainerClasses(PHX_CONNECTED_CLASS);
4314
4398
  this.execAll(this.binding("connected"));
4315
4399
  }
@@ -4339,11 +4423,14 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
4339
4423
  );
4340
4424
  }
4341
4425
  if (isCid(phxTarget)) {
4342
- const targets = dom_default.findComponentNodeList(this.id, phxTarget, dom);
4343
- if (targets.length === 0) {
4426
+ const target = dom_default.findComponent(this.id, phxTarget, dom);
4427
+ if (!target) {
4344
4428
  logError(`no component found matching phx-target of ${phxTarget}`);
4345
4429
  } else {
4346
- callback(this, parseInt(phxTarget));
4430
+ callback(
4431
+ this,
4432
+ typeof phxTarget === "number" ? phxTarget : parseInt(phxTarget)
4433
+ );
4347
4434
  }
4348
4435
  } else {
4349
4436
  const targets = Array.from(dom.querySelectorAll(phxTarget));
@@ -4470,7 +4557,11 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
4470
4557
  }
4471
4558
  }
4472
4559
  attachTrueDocEl() {
4473
- this.el = dom_default.byId(this.id);
4560
+ const el = dom_default.byId(this.id);
4561
+ if (!el) {
4562
+ throw new Error("unable to find root element for view");
4563
+ }
4564
+ this.el = el;
4474
4565
  this.el.setAttribute(PHX_ROOT_ID, this.root.id);
4475
4566
  }
4476
4567
  // this is invoked for dead and live views, so we must filter by
@@ -4519,7 +4610,7 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
4519
4610
  }
4520
4611
  }
4521
4612
  this.attachTrueDocEl();
4522
- const patch = new DOMPatch(this, this.el, this.id, html, streams, null);
4613
+ const patch = new DOMPatch(this, this.el, html, streams, null);
4523
4614
  patch.markPrunableContentForRemoval();
4524
4615
  this.performPatch(patch, false, true);
4525
4616
  this.joinNewChildren();
@@ -4565,7 +4656,7 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
4565
4656
  let phxChildrenAdded = false;
4566
4657
  const updatedHookIds = /* @__PURE__ */ new Set();
4567
4658
  this.liveSocket.triggerDOM("onPatchStart", [patch.targetContainer]);
4568
- patch.after("added", (el) => {
4659
+ patch.afterAdded((el) => {
4569
4660
  this.liveSocket.triggerDOM("onNodeAdded", [el]);
4570
4661
  const phxViewportTop = this.binding(PHX_VIEWPORT_TOP);
4571
4662
  const phxViewportBottom = this.binding(PHX_VIEWPORT_BOTTOM);
@@ -4575,33 +4666,32 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
4575
4666
  this.maybeMounted(el);
4576
4667
  }
4577
4668
  });
4578
- patch.after("phxChildAdded", (el) => {
4669
+ patch.afterPhxChildAdded((el) => {
4579
4670
  if (dom_default.isPhxSticky(el)) {
4580
4671
  this.liveSocket.joinRootViews();
4581
4672
  } else {
4582
4673
  phxChildrenAdded = true;
4583
4674
  }
4584
4675
  });
4585
- patch.before("updated", (fromEl, toEl) => {
4676
+ patch.beforeUpdated((fromEl, toEl) => {
4586
4677
  const hook = this.triggerBeforeUpdateHook(fromEl, toEl);
4587
4678
  if (hook) {
4588
4679
  updatedHookIds.add(fromEl.id);
4589
4680
  }
4590
4681
  js_default.onBeforeElUpdated(fromEl, toEl);
4591
4682
  });
4592
- patch.after("updated", (el) => {
4683
+ patch.afterUpdated((el) => {
4593
4684
  if (updatedHookIds.has(el.id)) {
4594
4685
  const hook = this.getHook(el);
4595
4686
  hook && hook.__updated();
4596
4687
  }
4597
4688
  });
4598
- patch.after("discarded", (el) => {
4689
+ patch.afterDiscarded((el) => {
4599
4690
  if (el.nodeType === Node.ELEMENT_NODE) {
4600
4691
  removedEls.push(el);
4601
4692
  }
4602
4693
  });
4603
- patch.after(
4604
- "transitionsDiscarded",
4694
+ patch.afterTransitionsDiscarded(
4605
4695
  (els) => this.afterElementsRemoved(els, pruneCids)
4606
4696
  );
4607
4697
  patch.perform(isJoinPatch);
@@ -4639,12 +4729,20 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
4639
4729
  dom_default.findPhxChildren(document, this.id).forEach((el) => this.joinChild(el));
4640
4730
  }
4641
4731
  maybeRecoverForms(html, callback) {
4732
+ var _a;
4642
4733
  const phxChange = this.binding("change");
4643
4734
  const oldForms = this.root.formsForRecovery;
4644
4735
  const template = document.createElement("template");
4645
4736
  template.innerHTML = html;
4737
+ if (!template.content.firstElementChild) {
4738
+ return;
4739
+ }
4646
4740
  dom_default.all(template.content, `[${PHX_PORTAL}]`).forEach((portalTemplate) => {
4647
- template.content.firstElementChild.appendChild(
4741
+ var _a2;
4742
+ if (!(portalTemplate instanceof HTMLTemplateElement)) {
4743
+ return;
4744
+ }
4745
+ (_a2 = template.content.firstElementChild) == null ? void 0 : _a2.appendChild(
4648
4746
  portalTemplate.content.firstElementChild
4649
4747
  );
4650
4748
  });
@@ -4652,8 +4750,8 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
4652
4750
  rootEl.id = this.id;
4653
4751
  rootEl.setAttribute(PHX_ROOT_ID, this.root.id);
4654
4752
  rootEl.setAttribute(PHX_SESSION, this.getSession());
4655
- rootEl.setAttribute(PHX_STATIC, this.getStatic());
4656
- rootEl.setAttribute(PHX_PARENT_ID, this.parent ? this.parent.id : null);
4753
+ rootEl.setAttribute(PHX_STATIC, (_a = this.getStatic()) != null ? _a : "");
4754
+ this.parent && rootEl.setAttribute(PHX_PARENT_ID, this.parent.id);
4657
4755
  const formsToRecover = (
4658
4756
  // we go over all forms in the new DOM; because this is only the HTML for the current
4659
4757
  // view, we can be sure that all forms are owned by this view:
@@ -4689,7 +4787,7 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
4689
4787
  if (el.id === this.id) {
4690
4788
  return this;
4691
4789
  } else {
4692
- return (_a = this.children[el.getAttribute(PHX_PARENT_ID)]) == null ? void 0 : _a[el.id];
4790
+ return this.children && ((_a = this.children[el.getAttribute(PHX_PARENT_ID)]) == null ? void 0 : _a[el.id]);
4693
4791
  }
4694
4792
  }
4695
4793
  destroyDescendent(id) {
@@ -4763,7 +4861,7 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
4763
4861
  } else if (!isEmpty(diff)) {
4764
4862
  this.liveSocket.time("full patch complete", () => {
4765
4863
  const [html, streams] = this.renderContainer(diff, "update");
4766
- const patch = new DOMPatch(this, this.el, this.id, html, streams, null);
4864
+ const patch = new DOMPatch(this, this.el, html, streams, null);
4767
4865
  phxChildrenAdded = this.performPatch(patch, true);
4768
4866
  });
4769
4867
  }
@@ -4785,7 +4883,7 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
4785
4883
  if (isEmpty(diff))
4786
4884
  return false;
4787
4885
  const { buffer: html, streams } = this.rendered.componentToString(cid);
4788
- const patch = new DOMPatch(this, this.el, this.id, html, streams, cid);
4886
+ const patch = new DOMPatch(this, this.el, html, streams, cid);
4789
4887
  const childrenAdded = this.performPatch(patch, true);
4790
4888
  return childrenAdded;
4791
4889
  }
@@ -4915,11 +5013,12 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
4915
5013
  expandURL(to) {
4916
5014
  return to.startsWith("/") ? `${window.location.protocol}//${window.location.host}${to}` : to;
4917
5015
  }
4918
- /**
4919
- * @param {{to: string, flash?: string, reloadToken?: string}} redirect
4920
- */
4921
- onRedirect({ to, flash, reloadToken }) {
4922
- this.liveSocket.redirect(to, flash, reloadToken);
5016
+ onRedirect({
5017
+ to,
5018
+ flash,
5019
+ reloadToken
5020
+ }) {
5021
+ this.liveSocket.redirect(to, flash != null ? flash : null, reloadToken != null ? reloadToken : null);
4923
5022
  }
4924
5023
  isDestroyed() {
4925
5024
  return this.destroyed;
@@ -4927,10 +5026,6 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
4927
5026
  joinDead() {
4928
5027
  this.isDead = true;
4929
5028
  }
4930
- joinPush() {
4931
- this.joinPush = this.joinPush || this.channel.join();
4932
- return this.joinPush;
4933
- }
4934
5029
  join(callback) {
4935
5030
  this.showLoader(this.liveSocket.loaderTimeout);
4936
5031
  this.bindChannel();
@@ -4952,6 +5047,9 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
4952
5047
  });
4953
5048
  }
4954
5049
  onJoinError(resp) {
5050
+ if (resp.events) {
5051
+ this.liveSocket.dispatchEvents(resp.events);
5052
+ }
4955
5053
  if (resp.reason === "reload") {
4956
5054
  this.log("error", () => [
4957
5055
  `failed mount with ${resp.status}. Falling back to page reload`,
@@ -5169,7 +5267,7 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
5169
5267
  undoElRef(el, ref, phxEvent) {
5170
5268
  const elRef = new ElementRef(el);
5171
5269
  elRef.maybeUndo(ref, phxEvent, (clonedTree) => {
5172
- const patch = new DOMPatch(this, el, this.id, clonedTree, [], null, {
5270
+ const patch = new DOMPatch(this, el, clonedTree, /* @__PURE__ */ new Set(), null, {
5173
5271
  undoRef: ref
5174
5272
  });
5175
5273
  const phxChildrenAdded = this.performPatch(patch, true);
@@ -5201,10 +5299,10 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
5201
5299
  }
5202
5300
  el.setAttribute(PHX_REF_SRC, this.refSrc());
5203
5301
  if (loading) {
5204
- el.setAttribute(PHX_REF_LOADING, newRef);
5302
+ el.setAttribute(PHX_REF_LOADING, newRef.toString());
5205
5303
  }
5206
5304
  if (lock) {
5207
- el.setAttribute(PHX_REF_LOCK, newRef);
5305
+ el.setAttribute(PHX_REF_LOCK, newRef.toString());
5208
5306
  }
5209
5307
  if (!loading || opts.submitter && !(el === opts.submitter || el === opts.form)) {
5210
5308
  continue;
@@ -5225,14 +5323,14 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
5225
5323
  const disableText = el.getAttribute(disableWith);
5226
5324
  if (disableText !== null) {
5227
5325
  if (!el.getAttribute(PHX_DISABLE_WITH_RESTORE)) {
5228
- el.setAttribute(PHX_DISABLE_WITH_RESTORE, el.textContent);
5326
+ el.setAttribute(PHX_DISABLE_WITH_RESTORE, el.textContent || "");
5229
5327
  }
5230
5328
  if (disableText !== "") {
5231
5329
  el.textContent = disableText;
5232
5330
  }
5233
5331
  el.setAttribute(
5234
5332
  PHX_DISABLED,
5235
- el.getAttribute(PHX_DISABLED) || el.disabled
5333
+ el.getAttribute(PHX_DISABLED) || ("disabled" in el ? String(el.disabled) : "")
5236
5334
  );
5237
5335
  el.setAttribute("disabled", "");
5238
5336
  }
@@ -5306,7 +5404,7 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
5306
5404
  }
5307
5405
  const cidOrSelector = opts.target || target.getAttribute(this.binding("target"));
5308
5406
  if (isCid(cidOrSelector)) {
5309
- return parseInt(cidOrSelector);
5407
+ return typeof cidOrSelector === "number" ? cidOrSelector : parseInt(cidOrSelector);
5310
5408
  } else if (targetCtx && (cidOrSelector !== null || opts.target)) {
5311
5409
  return this.closestComponentID(targetCtx);
5312
5410
  } else {
@@ -5356,7 +5454,9 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
5356
5454
  event,
5357
5455
  value: payload,
5358
5456
  cid: this.closestComponentID(targetCtx)
5359
- }).then(({ resp: _resp, reply, ref }) => ({ reply, ref }));
5457
+ }).then(
5458
+ ({ resp: _resp, reply, ref }) => ({ reply, ref })
5459
+ );
5360
5460
  }
5361
5461
  extractMeta(el, meta, value) {
5362
5462
  const prefix = this.binding("value-");
@@ -5388,7 +5488,7 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
5388
5488
  }
5389
5489
  return meta;
5390
5490
  }
5391
- serializeForm(form, opts, onlyNames = []) {
5491
+ serializeForm(form, opts = {}, onlyNames = []) {
5392
5492
  const { submitter } = opts;
5393
5493
  let injectedElement;
5394
5494
  if (submitter && submitter.name) {
@@ -5414,6 +5514,9 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
5414
5514
  const params = new URLSearchParams();
5415
5515
  const { inputsUnused, onlyHiddenInputs } = Array.from(form.elements).reduce(
5416
5516
  (acc, input) => {
5517
+ if (!dom_default.isFormAssociated(input)) {
5518
+ return acc;
5519
+ }
5417
5520
  const { inputsUnused: inputsUnused2, onlyHiddenInputs: onlyHiddenInputs2 } = acc;
5418
5521
  const key = input.name;
5419
5522
  if (!key) {
@@ -5600,27 +5703,30 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
5600
5703
  return el.hasAttribute(this.binding(PHX_DISABLE_WITH));
5601
5704
  };
5602
5705
  const filterButton = (el) => el.tagName == "BUTTON";
5603
- const filterInput = (el) => ["INPUT", "TEXTAREA", "SELECT"].includes(el.tagName);
5706
+ const filterInput = (el) => ["INPUT", "TEXTAREA"].includes(el.tagName);
5604
5707
  const formElements = Array.from(formEl.elements);
5605
5708
  const disables = formElements.filter(filterDisables);
5606
5709
  const buttons = formElements.filter(filterButton).filter(filterIgnored);
5607
5710
  const inputs = formElements.filter(filterInput).filter(filterIgnored);
5608
5711
  buttons.forEach((button) => {
5609
- button.setAttribute(PHX_DISABLED, button.disabled);
5712
+ button.setAttribute(PHX_DISABLED, button.disabled.toString());
5610
5713
  button.disabled = true;
5611
5714
  });
5612
5715
  inputs.forEach((input) => {
5613
- input.setAttribute(PHX_READONLY, input.readOnly);
5716
+ input.setAttribute(PHX_READONLY, input.readOnly.toString());
5614
5717
  input.readOnly = true;
5615
- if (input.files) {
5616
- input.setAttribute(PHX_DISABLED, input.disabled);
5718
+ if (input instanceof HTMLInputElement && input.files) {
5719
+ input.setAttribute(PHX_DISABLED, input.disabled.toString());
5617
5720
  input.disabled = true;
5618
5721
  }
5619
5722
  });
5620
5723
  const formEls = disables.concat(buttons).concat(inputs).map((el) => {
5621
5724
  return { el, loading: true, lock: true };
5622
5725
  });
5623
- const els = [{ el: formEl, loading: true, lock: false }].concat(formEls).reverse();
5726
+ const els = [
5727
+ { el: formEl, loading: true, lock: false },
5728
+ ...formEls
5729
+ ].reverse();
5624
5730
  return this.putRef(els, phxEvent, "submit", opts);
5625
5731
  }
5626
5732
  pushFormSubmit(formEl, targetCtx, phxEvent, submitter, opts, onReply) {
@@ -5751,7 +5857,7 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
5751
5857
  }
5752
5858
  targetCtxElement(targetCtx) {
5753
5859
  if (isCid(targetCtx)) {
5754
- const [target] = dom_default.findComponentNodeList(this.id, targetCtx);
5860
+ const target = dom_default.findComponent(this.id, targetCtx);
5755
5861
  return target;
5756
5862
  } else if (targetCtx) {
5757
5863
  return targetCtx;
@@ -5764,7 +5870,7 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
5764
5870
  const phxTarget = newForm.getAttribute(this.binding("target")) || newForm;
5765
5871
  const phxEvent = newForm.getAttribute(this.binding(PHX_AUTO_RECOVER)) || newForm.getAttribute(this.binding("change"));
5766
5872
  const inputs = Array.from(oldForm.elements).filter(
5767
- (el) => dom_default.isFormInput(el) && el.name && !el.hasAttribute(phxChange)
5873
+ (el) => dom_default.isFormAssociated(el) && el.name && !el.hasAttribute(phxChange)
5768
5874
  );
5769
5875
  if (inputs.length === 0) {
5770
5876
  callback();
@@ -5810,7 +5916,7 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
5810
5916
  null,
5811
5917
  "click"
5812
5918
  ) : null;
5813
- const fallback = () => this.liveSocket.redirect(window.location.href);
5919
+ const fallback = () => this.liveSocket.redirect(window.location.href, null, null);
5814
5920
  const url = href.startsWith("/") ? `${location.protocol}//${location.host}${href}` : href;
5815
5921
  this.pushWithReply(refGen, "live_patch", { url }).then(
5816
5922
  ({ resp }) => {
@@ -5839,14 +5945,14 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
5839
5945
  return dom_default.all(
5840
5946
  document,
5841
5947
  `#${CSS.escape(this.id)} form[${phxChange}], [${PHX_TELEPORTED_REF}="${CSS.escape(this.id)}"] form[${phxChange}]`
5842
- ).filter((form) => form.id).filter((form) => form.elements.length > 0).filter(
5948
+ ).filter((form) => form instanceof HTMLFormElement).filter((form) => form.id).filter((form) => form.elements.length > 0).filter(
5843
5949
  (form) => form.getAttribute(this.binding(PHX_AUTO_RECOVER)) !== "ignore"
5844
5950
  ).map((form) => {
5845
5951
  const clonedForm = form.cloneNode(true);
5846
5952
  morphdom_esm_default(clonedForm, form, {
5847
5953
  onBeforeElUpdated: (fromEl, toEl) => {
5848
5954
  dom_default.copyPrivates(fromEl, toEl);
5849
- if (fromEl.getAttribute("form") === form.id) {
5955
+ if (fromEl.getAttribute("form") === form.id && fromEl.parentNode) {
5850
5956
  fromEl.parentNode.removeChild(fromEl);
5851
5957
  return false;
5852
5958
  }
@@ -5857,10 +5963,7 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
5857
5963
  `[form="${CSS.escape(form.id)}"]`
5858
5964
  );
5859
5965
  Array.from(externalElements).forEach((el) => {
5860
- const clonedEl = (
5861
- /** @type {HTMLElement} */
5862
- el.cloneNode(true)
5863
- );
5966
+ const clonedEl = el.cloneNode(true);
5864
5967
  morphdom_esm_default(clonedEl, el);
5865
5968
  dom_default.copyPrivates(clonedEl, el);
5866
5969
  clonedEl.removeAttribute("form");
@@ -5874,7 +5977,7 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
5874
5977
  }
5875
5978
  maybePushComponentsDestroyed(destroyedCIDs) {
5876
5979
  let willDestroyCIDs = destroyedCIDs.filter((cid) => {
5877
- return dom_default.findComponentNodeList(this.id, cid).length === 0;
5980
+ return dom_default.findComponent(this.id, cid) === null;
5878
5981
  });
5879
5982
  const onError = (error) => {
5880
5983
  if (!this.isDestroyed()) {
@@ -5886,7 +5989,7 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
5886
5989
  this.pushWithReply(null, "cids_will_destroy", { cids: willDestroyCIDs }).then(() => {
5887
5990
  this.liveSocket.requestDOMUpdate(() => {
5888
5991
  let completelyDestroyCIDs = willDestroyCIDs.filter((cid) => {
5889
- return dom_default.findComponentNodeList(this.id, cid).length === 0;
5992
+ return dom_default.findComponent(this.id, cid) === null;
5890
5993
  });
5891
5994
  if (completelyDestroyCIDs.length > 0) {
5892
5995
  this.pushWithReply(null, "cids_destroyed", {
@@ -5907,7 +6010,7 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
5907
6010
  dom_default.putPrivate(form, PHX_HAS_SUBMITTED, true);
5908
6011
  const inputs = Array.from(form.elements);
5909
6012
  inputs.forEach((input) => dom_default.putPrivate(input, PHX_HAS_SUBMITTED, true));
5910
- this.liveSocket.blurActiveElement(this);
6013
+ this.liveSocket.blurActiveElement();
5911
6014
  this.pushFormSubmit(form, targetCtx, phxEvent, submitter, opts, () => {
5912
6015
  this.liveSocket.restorePreviouslyActiveFocus();
5913
6016
  });
@@ -5934,10 +6037,14 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
5934
6037
  }
5935
6038
  };
5936
6039
 
5937
- // js/phoenix_live_view/live_socket.js
6040
+ // js/phoenix_live_view/live_socket.ts
5938
6041
  var isUsedInput = (el) => dom_default.isUsedInput(el);
5939
6042
  var LiveSocket = class {
6043
+ /**
6044
+ * Creates a new LiveSocket instance.
6045
+ */
5940
6046
  constructor(url, phxSocket, opts = {}) {
6047
+ /** @internal */
5941
6048
  this.unloaded = false;
5942
6049
  if (!phxSocket || phxSocket.constructor.name === "Object") {
5943
6050
  throw new Error(`
@@ -5950,7 +6057,6 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
5950
6057
  }
5951
6058
  this.socket = new phxSocket(url, opts);
5952
6059
  this.bindingPrefix = opts.bindingPrefix || BINDING_PREFIX;
5953
- this.opts = opts;
5954
6060
  this.params = closure(opts.params || {});
5955
6061
  this.viewLogger = opts.viewLogger;
5956
6062
  this.metadataCallbacks = opts.metadata || {};
@@ -5991,7 +6097,7 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
5991
6097
  opts.dom || {}
5992
6098
  );
5993
6099
  this.transitions = new TransitionSet();
5994
- this.currentHistoryPosition = parseInt(this.sessionStorage.getItem(PHX_LV_HISTORY_POSITION)) || 0;
6100
+ this.currentHistoryPosition = parseInt(this.sessionStorage.getItem(PHX_LV_HISTORY_POSITION) || "0") || 0;
5995
6101
  window.addEventListener("pagehide", (_e) => {
5996
6102
  this.unloaded = true;
5997
6103
  });
@@ -6002,47 +6108,94 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
6002
6108
  });
6003
6109
  }
6004
6110
  // public
6111
+ /**
6112
+ * Returns the version of the LiveView client.
6113
+ */
6005
6114
  version() {
6006
- return "1.2.0-rc.2";
6115
+ return "1.2.0";
6007
6116
  }
6117
+ /**
6118
+ * Returns true if profiling is enabled. See {@link enableProfiling} and {@link disableProfiling}.
6119
+ */
6008
6120
  isProfileEnabled() {
6009
6121
  return this.sessionStorage.getItem(PHX_LV_PROFILE) === "true";
6010
6122
  }
6123
+ /**
6124
+ * Returns true if debugging is enabled. See {@link enableDebug} and {@link disableDebug}.
6125
+ */
6011
6126
  isDebugEnabled() {
6012
6127
  return this.sessionStorage.getItem(PHX_LV_DEBUG) === "true";
6013
6128
  }
6129
+ /**
6130
+ * Returns true if debugging is disabled. See {@link enableDebug} and {@link disableDebug}.
6131
+ */
6014
6132
  isDebugDisabled() {
6015
6133
  return this.sessionStorage.getItem(PHX_LV_DEBUG) === "false";
6016
6134
  }
6135
+ /**
6136
+ * Enables debugging.
6137
+ *
6138
+ * When debugging is enabled, the LiveView client will log debug information to the console.
6139
+ * See [Debugging client events](https://phoenix-live-view.hexdocs.pm/js-interop.html#debugging-client-events) for more information.
6140
+ */
6017
6141
  enableDebug() {
6018
6142
  this.sessionStorage.setItem(PHX_LV_DEBUG, "true");
6019
6143
  }
6144
+ /**
6145
+ * Enables profiling.
6146
+ *
6147
+ * When profiling is enabled, the LiveView client will log profiling information to the console.
6148
+ */
6020
6149
  enableProfiling() {
6021
6150
  this.sessionStorage.setItem(PHX_LV_PROFILE, "true");
6022
6151
  }
6152
+ /**
6153
+ * Disables debugging.
6154
+ */
6023
6155
  disableDebug() {
6024
6156
  this.sessionStorage.setItem(PHX_LV_DEBUG, "false");
6025
6157
  }
6158
+ /**
6159
+ * Disables profiling.
6160
+ */
6026
6161
  disableProfiling() {
6027
6162
  this.sessionStorage.removeItem(PHX_LV_PROFILE);
6028
6163
  }
6164
+ /**
6165
+ * Enables latency simulation.
6166
+ *
6167
+ * When latency simulation is enabled, the LiveView client will add a delay to requests and responses from the server.
6168
+ * See [Simulating Latency](https://phoenix-live-view.hexdocs.pm/js-interop.html#simulating-latency) for more information.
6169
+ */
6029
6170
  enableLatencySim(upperBoundMs) {
6030
6171
  this.enableDebug();
6031
6172
  console.log(
6032
6173
  "latency simulator enabled for the duration of this browser session. Call disableLatencySim() to disable"
6033
6174
  );
6034
- this.sessionStorage.setItem(PHX_LV_LATENCY_SIM, upperBoundMs);
6175
+ this.sessionStorage.setItem(PHX_LV_LATENCY_SIM, upperBoundMs.toString());
6035
6176
  }
6177
+ /**
6178
+ * Disables latency simulation.
6179
+ */
6036
6180
  disableLatencySim() {
6037
6181
  this.sessionStorage.removeItem(PHX_LV_LATENCY_SIM);
6038
6182
  }
6183
+ /**
6184
+ * Returns the current latency simulation upper bound.
6185
+ */
6039
6186
  getLatencySim() {
6040
6187
  const str = this.sessionStorage.getItem(PHX_LV_LATENCY_SIM);
6041
6188
  return str ? parseInt(str) : null;
6042
6189
  }
6190
+ /**
6191
+ * Returns the Phoenix Socket instance.
6192
+ */
6043
6193
  getSocket() {
6044
6194
  return this.socket;
6045
6195
  }
6196
+ /**
6197
+ * Connects to the LiveView server.
6198
+ */
6046
6199
  connect() {
6047
6200
  if (window.location.hostname === "localhost" && !this.isDebugDisabled()) {
6048
6201
  this.enableDebug();
@@ -6065,23 +6218,29 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
6065
6218
  document.addEventListener("DOMContentLoaded", () => doConnect());
6066
6219
  }
6067
6220
  }
6221
+ /**
6222
+ * Disconnects from the LiveView server.
6223
+ */
6068
6224
  disconnect(callback) {
6069
- clearTimeout(this.reloadWithJitterTimer);
6225
+ this.reloadWithJitterTimer != null && clearTimeout(this.reloadWithJitterTimer);
6070
6226
  if (this.serverCloseRef) {
6071
- this.socket.off(this.serverCloseRef);
6227
+ this.socket.off([this.serverCloseRef]);
6072
6228
  this.serverCloseRef = null;
6073
6229
  }
6074
6230
  this.socket.disconnect(callback);
6075
6231
  }
6232
+ /**
6233
+ * Can be used to replace the transport used by the underlying Phoenix Socket.
6234
+ */
6076
6235
  replaceTransport(transport) {
6077
- clearTimeout(this.reloadWithJitterTimer);
6236
+ this.reloadWithJitterTimer != null && clearTimeout(this.reloadWithJitterTimer);
6078
6237
  this.socket.replaceTransport(transport);
6079
6238
  this.connect();
6080
6239
  }
6081
6240
  /**
6082
- * @param {HTMLElement} el
6083
- * @param {import("./js_commands").EncodedJS} encodedJS
6084
- * @param {string | null} [eventType]
6241
+ * Executes an encoded JS command, targeting the given element.
6242
+ *
6243
+ * See [`Phoenix.LiveView.JS`](https://phoenix-live-view.hexdocs.pm/Phoenix.LiveView.JS.html) for more information.
6085
6244
  */
6086
6245
  execJS(el, encodedJS, eventType = null) {
6087
6246
  const e = new CustomEvent("phx:exec", { detail: { sourceElement: el } });
@@ -6091,12 +6250,13 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
6091
6250
  * Returns an object with methods to manipulate the DOM and execute JavaScript.
6092
6251
  * The applied changes integrate with server DOM patching.
6093
6252
  *
6094
- * @returns {import("./js_commands").LiveSocketJSCommands}
6253
+ * See [JavaScript interoperability](https://phoenix-live-view.hexdocs.pm/js-interop.html) for more information.
6095
6254
  */
6096
6255
  js() {
6097
6256
  return js_commands_default(this, "js");
6098
6257
  }
6099
6258
  // private
6259
+ /** @internal */
6100
6260
  unload() {
6101
6261
  if (this.unloaded) {
6102
6262
  return;
@@ -6108,9 +6268,11 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
6108
6268
  this.destroyAllViews();
6109
6269
  this.disconnect();
6110
6270
  }
6271
+ /** @internal */
6111
6272
  triggerDOM(kind, args) {
6112
6273
  this.domCallbacks[kind](...args);
6113
6274
  }
6275
+ /** @internal */
6114
6276
  time(name, func) {
6115
6277
  if (!this.isProfileEnabled() || !console.time) {
6116
6278
  return func();
@@ -6120,6 +6282,7 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
6120
6282
  console.timeEnd(name);
6121
6283
  return result;
6122
6284
  }
6285
+ /** @internal */
6123
6286
  log(view, kind, msgCallback) {
6124
6287
  if (this.viewLogger) {
6125
6288
  const [msg, obj] = msgCallback();
@@ -6129,16 +6292,20 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
6129
6292
  debug(view, kind, msg, obj);
6130
6293
  }
6131
6294
  }
6295
+ /** @internal */
6132
6296
  requestDOMUpdate(callback) {
6133
6297
  this.transitions.after(callback);
6134
6298
  }
6299
+ /** @internal */
6135
6300
  asyncTransition(promise) {
6136
6301
  this.transitions.addAsyncTransition(promise);
6137
6302
  }
6303
+ /** @internal */
6138
6304
  transition(time, onStart, onDone = function() {
6139
6305
  }) {
6140
6306
  this.transitions.addTransition(time, onStart, onDone);
6141
6307
  }
6308
+ /** @internal */
6142
6309
  onChannel(channel, event, cb) {
6143
6310
  channel.on(event, (data) => {
6144
6311
  const latency = this.getLatencySim();
@@ -6149,8 +6316,9 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
6149
6316
  }
6150
6317
  });
6151
6318
  }
6319
+ /** @internal */
6152
6320
  reloadWithJitter(view, log) {
6153
- clearTimeout(this.reloadWithJitterTimer);
6321
+ this.reloadWithJitterTimer != null && clearTimeout(this.reloadWithJitterTimer);
6154
6322
  this.disconnect();
6155
6323
  const minMs = this.reloadJitterMin;
6156
6324
  const maxMs = this.reloadJitterMax;
@@ -6178,22 +6346,25 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
6178
6346
  `exceeded ${this.maxReloads} consecutive reloads. Entering failsafe mode`
6179
6347
  ]);
6180
6348
  }
6181
- if (this.hasPendingLink()) {
6182
- window.location = this.pendingLink;
6349
+ if (this.pendingLink !== null) {
6350
+ window.location.href = this.pendingLink;
6183
6351
  } else {
6184
6352
  window.location.reload();
6185
6353
  }
6186
6354
  }, afterMs);
6187
6355
  }
6356
+ /** @internal */
6188
6357
  getHookDefinition(name) {
6189
6358
  if (!name) {
6190
6359
  return;
6191
6360
  }
6192
6361
  return this.maybeInternalHook(name) || this.hooks[name] || this.maybeRuntimeHook(name);
6193
6362
  }
6363
+ /** @internal */
6194
6364
  maybeInternalHook(name) {
6195
6365
  return name && name.startsWith("Phoenix.") && hooks_default[name.split(".")[1]];
6196
6366
  }
6367
+ /** @internal */
6197
6368
  maybeRuntimeHook(name) {
6198
6369
  const runtimeHook = document.querySelector(
6199
6370
  `script[${PHX_RUNTIME_HOOK}="${CSS.escape(name)}"]`
@@ -6215,21 +6386,27 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
6215
6386
  runtimeHook
6216
6387
  );
6217
6388
  }
6389
+ /** @internal */
6218
6390
  isUnloaded() {
6219
6391
  return this.unloaded;
6220
6392
  }
6393
+ /** @internal */
6221
6394
  isConnected() {
6222
6395
  return this.socket.isConnected();
6223
6396
  }
6397
+ /** @internal */
6224
6398
  getBindingPrefix() {
6225
6399
  return this.bindingPrefix;
6226
6400
  }
6401
+ /** @internal */
6227
6402
  binding(kind) {
6228
6403
  return `${this.getBindingPrefix()}${kind}`;
6229
6404
  }
6405
+ /** @internal */
6230
6406
  channel(topic, params) {
6231
6407
  return this.socket.channel(topic, params);
6232
6408
  }
6409
+ /** @internal */
6233
6410
  joinDeadView() {
6234
6411
  const body = document.body;
6235
6412
  if (body && !this.isPhxView(body) && !this.isPhxView(document.firstElementChild)) {
@@ -6246,6 +6423,7 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
6246
6423
  });
6247
6424
  }
6248
6425
  }
6426
+ /** @internal */
6249
6427
  joinRootViews() {
6250
6428
  let rootsFound = false;
6251
6429
  dom_default.all(
@@ -6267,6 +6445,7 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
6267
6445
  );
6268
6446
  return rootsFound;
6269
6447
  }
6448
+ /** @internal */
6270
6449
  redirect(to, flash, reloadToken) {
6271
6450
  if (reloadToken) {
6272
6451
  browser_default.setCookie(PHX_RELOAD_STATUS, reloadToken, 60);
@@ -6274,7 +6453,11 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
6274
6453
  this.unload();
6275
6454
  browser_default.redirect(to, flash);
6276
6455
  }
6456
+ /** @internal */
6277
6457
  replaceMain(href, flash, callback = null, linkRef = this.setPendingLink(href)) {
6458
+ if (!this.main) {
6459
+ return;
6460
+ }
6278
6461
  const liveReferer = this.currentLocation.href;
6279
6462
  this.outgoingMainEl = this.outgoingMainEl || this.main.el;
6280
6463
  const stickies = dom_default.findPhxSticky(document) || [];
@@ -6301,6 +6484,7 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
6301
6484
  }
6302
6485
  });
6303
6486
  }
6487
+ /** @internal */
6304
6488
  transitionRemoves(elements, callback) {
6305
6489
  const removeAttr = this.binding("remove");
6306
6490
  const silenceEvents = (e) => {
@@ -6322,14 +6506,17 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
6322
6506
  callback && callback();
6323
6507
  });
6324
6508
  }
6509
+ /** @internal */
6325
6510
  isPhxView(el) {
6326
6511
  return el.getAttribute && el.getAttribute(PHX_SESSION) !== null;
6327
6512
  }
6513
+ /** @internal */
6328
6514
  newRootView(el, flash, liveReferer) {
6329
6515
  const view = new View(el, this, null, flash, liveReferer);
6330
6516
  this.roots[view.id] = view;
6331
6517
  return view;
6332
6518
  }
6519
+ /** @internal */
6333
6520
  owner(childEl, callback) {
6334
6521
  let view;
6335
6522
  const viewEl = dom_default.closestViewEl(childEl);
@@ -6343,9 +6530,11 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
6343
6530
  }
6344
6531
  return view && callback ? callback(view) : view;
6345
6532
  }
6533
+ /** @internal */
6346
6534
  withinOwners(childEl, callback) {
6347
6535
  this.owner(childEl, (view) => callback(view, childEl));
6348
6536
  }
6537
+ /** @internal */
6349
6538
  getViewByEl(el) {
6350
6539
  const rootId = el.getAttribute(PHX_ROOT_ID);
6351
6540
  return maybe(
@@ -6353,9 +6542,11 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
6353
6542
  (root) => root.getDescendentByEl(el)
6354
6543
  );
6355
6544
  }
6545
+ /** @internal */
6356
6546
  getRootById(id) {
6357
6547
  return this.roots[id];
6358
6548
  }
6549
+ /** @internal */
6359
6550
  destroyAllViews() {
6360
6551
  for (const id in this.roots) {
6361
6552
  this.roots[id].destroy();
@@ -6363,6 +6554,7 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
6363
6554
  }
6364
6555
  this.main = null;
6365
6556
  }
6557
+ /** @internal */
6366
6558
  destroyViewByEl(el) {
6367
6559
  const root = this.getRootById(el.getAttribute(PHX_ROOT_ID));
6368
6560
  if (root && root.id === el.id) {
@@ -6372,28 +6564,30 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
6372
6564
  root.destroyDescendent(el.id);
6373
6565
  }
6374
6566
  }
6567
+ /** @internal */
6375
6568
  getActiveElement() {
6376
6569
  return document.activeElement;
6377
6570
  }
6571
+ /** @internal */
6378
6572
  dropActiveElement(view) {
6379
6573
  if (this.prevActive && view.ownsElement(this.prevActive)) {
6380
6574
  this.prevActive = null;
6381
6575
  }
6382
6576
  }
6577
+ /** @internal */
6383
6578
  restorePreviouslyActiveFocus() {
6384
6579
  if (this.prevActive && this.prevActive !== document.body && this.prevActive instanceof HTMLElement) {
6385
6580
  this.prevActive.focus();
6386
6581
  }
6387
6582
  }
6583
+ /** @internal */
6388
6584
  blurActiveElement() {
6389
6585
  this.prevActive = this.getActiveElement();
6390
6586
  if (this.prevActive !== document.body && this.prevActive instanceof HTMLElement) {
6391
6587
  this.prevActive.blur();
6392
6588
  }
6393
6589
  }
6394
- /**
6395
- * @param {{dead?: boolean}} [options={}]
6396
- */
6590
+ /** @internal */
6397
6591
  bindTopLevelEvents({ dead } = {}) {
6398
6592
  if (this.boundTopLevelEvents) {
6399
6593
  return;
@@ -6440,7 +6634,7 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
6440
6634
  { blur: "focusout", focus: "focusin" },
6441
6635
  (e, type, view, targetEl, phxEvent, phxTarget) => {
6442
6636
  if (!phxTarget) {
6443
- const data = __spreadValues({ key: e.key }, this.eventMeta(type, e, targetEl));
6637
+ const data = __spreadValues({}, this.eventMeta(type, e, targetEl));
6444
6638
  js_default.exec(e, type, phxEvent, view, targetEl, ["push", { data }]);
6445
6639
  }
6446
6640
  }
@@ -6456,10 +6650,11 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
6456
6650
  );
6457
6651
  this.on("dragover", (e) => e.preventDefault());
6458
6652
  this.on("dragenter", (e) => {
6459
- const dropzone = closestPhxBinding(
6460
- e.target,
6461
- this.binding(PHX_DROP_TARGET)
6462
- );
6653
+ let target = e.target && dom_default.elementFromTarget(e.target);
6654
+ if (!target) {
6655
+ return;
6656
+ }
6657
+ const dropzone = closestPhxBinding(target, this.binding(PHX_DROP_TARGET));
6463
6658
  if (!dropzone || !(dropzone instanceof HTMLElement)) {
6464
6659
  return;
6465
6660
  }
@@ -6468,10 +6663,11 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
6468
6663
  }
6469
6664
  });
6470
6665
  this.on("dragleave", (e) => {
6471
- const dropzone = closestPhxBinding(
6472
- e.target,
6473
- this.binding(PHX_DROP_TARGET)
6474
- );
6666
+ let target = e.target && dom_default.elementFromTarget(e.target);
6667
+ if (!target) {
6668
+ return;
6669
+ }
6670
+ const dropzone = closestPhxBinding(target, this.binding(PHX_DROP_TARGET));
6475
6671
  if (!dropzone || !(dropzone instanceof HTMLElement)) {
6476
6672
  return;
6477
6673
  }
@@ -6481,15 +6677,19 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
6481
6677
  }
6482
6678
  });
6483
6679
  this.on("drop", (e) => {
6680
+ let target = e.target && dom_default.elementFromTarget(e.target);
6681
+ if (!target) {
6682
+ return;
6683
+ }
6484
6684
  e.preventDefault();
6485
- const dropzone = closestPhxBinding(
6486
- e.target,
6487
- this.binding(PHX_DROP_TARGET)
6488
- );
6685
+ const dropzone = closestPhxBinding(target, this.binding(PHX_DROP_TARGET));
6489
6686
  if (!dropzone || !(dropzone instanceof HTMLElement)) {
6490
6687
  return;
6491
6688
  }
6492
6689
  this.js().removeClass(dropzone, PHX_DROP_TARGET_ACTIVE_CLASS);
6690
+ if (!e.dataTransfer) {
6691
+ return;
6692
+ }
6493
6693
  const dropTargetId = dropzone.getAttribute(this.binding(PHX_DROP_TARGET));
6494
6694
  const dropTarget = dropTargetId && document.getElementById(dropTargetId);
6495
6695
  const files = Array.from(e.dataTransfer.files || []);
@@ -6500,7 +6700,7 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
6500
6700
  dropTarget.dispatchEvent(new Event("input", { bubbles: true }));
6501
6701
  });
6502
6702
  this.on(PHX_TRACK_UPLOADS, (e) => {
6503
- const uploadTarget = e.target;
6703
+ const uploadTarget = e.target && dom_default.elementFromTarget(e.target);
6504
6704
  if (!dom_default.isUploadInput(uploadTarget)) {
6505
6705
  return;
6506
6706
  }
@@ -6511,47 +6711,67 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
6511
6711
  uploadTarget.dispatchEvent(new Event("input", { bubbles: true }));
6512
6712
  });
6513
6713
  }
6714
+ /** @internal */
6514
6715
  eventMeta(eventName, e, targetEl) {
6515
6716
  const callback = this.metadataCallbacks[eventName];
6516
6717
  return callback ? callback(e, targetEl) : {};
6517
6718
  }
6719
+ /** @internal */
6518
6720
  setPendingLink(href) {
6519
6721
  this.linkRef++;
6520
6722
  this.pendingLink = href;
6521
6723
  this.resetReloadStatus();
6522
6724
  return this.linkRef;
6523
6725
  }
6524
- // anytime we are navigating or connecting, drop reload cookie in case
6525
- // we issue the cookie but the next request was interrupted and the server never dropped it
6726
+ /**
6727
+ * @internal
6728
+ * anytime we are navigating or connecting, drop reload cookie in case
6729
+ * we issue the cookie but the next request was interrupted and the server never dropped it
6730
+ */
6526
6731
  resetReloadStatus() {
6527
6732
  browser_default.deleteCookie(PHX_RELOAD_STATUS);
6528
6733
  }
6734
+ /** @internal */
6529
6735
  commitPendingLink(linkRef) {
6530
6736
  if (this.linkRef !== linkRef) {
6531
6737
  return false;
6532
- } else {
6738
+ }
6739
+ if (this.pendingLink !== null) {
6533
6740
  this.href = this.pendingLink;
6534
6741
  this.pendingLink = null;
6535
- return true;
6536
6742
  }
6743
+ return true;
6537
6744
  }
6745
+ /** @internal */
6538
6746
  getHref() {
6539
6747
  return this.href;
6540
6748
  }
6749
+ /** @internal */
6541
6750
  hasPendingLink() {
6542
6751
  return !!this.pendingLink;
6543
6752
  }
6753
+ /** @internal */
6544
6754
  bind(events, callback) {
6545
6755
  for (const event in events) {
6546
6756
  const browserEventName = events[event];
6547
6757
  this.on(browserEventName, (e) => {
6548
6758
  const binding = this.binding(event);
6549
6759
  const windowBinding = this.binding(`window-${event}`);
6550
- const targetPhxEvent = e.target.getAttribute && e.target.getAttribute(binding);
6760
+ const targetPhxEvent = e.target instanceof Element && e.target.getAttribute(binding);
6761
+ if (!(e.target instanceof Element)) {
6762
+ return;
6763
+ }
6551
6764
  if (targetPhxEvent) {
6552
6765
  this.debounce(e.target, e, browserEventName, () => {
6553
6766
  this.withinOwners(e.target, (view) => {
6554
- callback(e, event, view, e.target, targetPhxEvent, null);
6767
+ callback(
6768
+ e,
6769
+ event,
6770
+ view,
6771
+ e.target,
6772
+ targetPhxEvent,
6773
+ null
6774
+ );
6555
6775
  });
6556
6776
  });
6557
6777
  } else {
@@ -6559,7 +6779,14 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
6559
6779
  const phxEvent = el.getAttribute(windowBinding);
6560
6780
  this.debounce(el, e, browserEventName, () => {
6561
6781
  this.withinOwners(el, (view) => {
6562
- callback(e, event, view, el, phxEvent, "window");
6782
+ callback(
6783
+ e,
6784
+ event,
6785
+ view,
6786
+ el,
6787
+ phxEvent,
6788
+ "window"
6789
+ );
6563
6790
  });
6564
6791
  });
6565
6792
  });
@@ -6567,23 +6794,31 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
6567
6794
  });
6568
6795
  }
6569
6796
  }
6797
+ /** @internal */
6570
6798
  bindClicks() {
6571
6799
  this.on("mousedown", (e) => this.clickStartedAtTarget = e.target);
6572
- this.bindClick("click", "click");
6800
+ this.bindClick();
6573
6801
  }
6574
- bindClick(eventName, bindingName) {
6575
- const click = this.binding(bindingName);
6802
+ /** @internal */
6803
+ bindClick() {
6804
+ const click = this.binding("click");
6576
6805
  window.addEventListener(
6577
- eventName,
6806
+ "click",
6578
6807
  (e) => {
6579
- let target = null;
6808
+ let target = e.target && dom_default.elementFromTarget(e.target);
6809
+ if (!target) {
6810
+ return;
6811
+ }
6580
6812
  if (e.detail === 0)
6581
- this.clickStartedAtTarget = e.target;
6582
- const clickStartedAtTarget = this.clickStartedAtTarget || e.target;
6583
- target = closestPhxBinding(e.target, click);
6813
+ this.clickStartedAtTarget = target;
6814
+ const clickStartedAtTarget = this.clickStartedAtTarget || target;
6815
+ target = closestPhxBinding(target, click);
6584
6816
  this.dispatchClickAway(e, clickStartedAtTarget);
6585
6817
  this.clickStartedAtTarget = null;
6586
- const phxEvent = target && target.getAttribute(click);
6818
+ if (!target) {
6819
+ return;
6820
+ }
6821
+ const phxEvent = target.getAttribute(click);
6587
6822
  if (!phxEvent) {
6588
6823
  if (dom_default.isNewPageClick(e, window.location)) {
6589
6824
  this.unload();
@@ -6608,6 +6843,7 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
6608
6843
  false
6609
6844
  );
6610
6845
  }
6846
+ /** @internal */
6611
6847
  dispatchClickAway(e, clickStartedAt) {
6612
6848
  const phxClickAway = this.binding("click-away");
6613
6849
  const portal = clickStartedAt.closest(`[${PHX_TELEPORTED_SRC}]`);
@@ -6638,6 +6874,7 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
6638
6874
  }
6639
6875
  });
6640
6876
  }
6877
+ /** @internal */
6641
6878
  bindNav() {
6642
6879
  if (!browser_default.canPushState()) {
6643
6880
  return;
@@ -6647,7 +6884,7 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
6647
6884
  }
6648
6885
  let scrollTimer = null;
6649
6886
  window.addEventListener("scroll", (_e) => {
6650
- clearTimeout(scrollTimer);
6887
+ scrollTimer != null && clearTimeout(scrollTimer);
6651
6888
  scrollTimer = setTimeout(() => {
6652
6889
  browser_default.updateCurrentState(
6653
6890
  (state) => Object.assign(state, { scroll: window.scrollY })
@@ -6681,7 +6918,7 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
6681
6918
  const callback = () => {
6682
6919
  this.maybeScroll(scroll);
6683
6920
  };
6684
- if (this.main.isConnected() && navType === "patch" && id === this.main.id) {
6921
+ if (this.main && this.main.isConnected() && navType === "patch" && id === this.main.id) {
6685
6922
  this.main.pushLinkPatch(event, href, null, callback);
6686
6923
  } else {
6687
6924
  this.replaceMain(href, null, callback);
@@ -6693,13 +6930,25 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
6693
6930
  window.addEventListener(
6694
6931
  "click",
6695
6932
  (e) => {
6696
- const target = closestPhxBinding(e.target, PHX_LIVE_LINK);
6933
+ let el = e.target && dom_default.elementFromTarget(e.target);
6934
+ if (!el) {
6935
+ return;
6936
+ }
6937
+ const target = closestPhxBinding(
6938
+ el,
6939
+ PHX_LIVE_LINK
6940
+ );
6697
6941
  const type = target && target.getAttribute(PHX_LIVE_LINK);
6698
6942
  if (!type || !this.isConnected() || !this.main || dom_default.wantsNewTab(e)) {
6699
6943
  return;
6700
6944
  }
6701
6945
  const href = target.href instanceof SVGAnimatedString ? target.href.baseVal : target.href;
6702
6946
  const linkState = target.getAttribute(PHX_LINK_STATE);
6947
+ if (linkState !== "replace" && linkState !== "push") {
6948
+ throw new Error(
6949
+ `expected ${PHX_LINK_STATE} to be "replace" or "push", got: ${linkState}`
6950
+ );
6951
+ }
6703
6952
  e.preventDefault();
6704
6953
  e.stopImmediatePropagation();
6705
6954
  if (this.pendingLink === href) {
@@ -6724,6 +6973,7 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
6724
6973
  false
6725
6974
  );
6726
6975
  }
6976
+ /** @internal */
6727
6977
  maybeScroll(scroll) {
6728
6978
  if (typeof scroll === "number") {
6729
6979
  requestAnimationFrame(() => {
@@ -6731,19 +6981,23 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
6731
6981
  });
6732
6982
  }
6733
6983
  }
6984
+ /** @internal */
6734
6985
  dispatchEvent(event, payload = {}) {
6735
6986
  dom_default.dispatchEvent(window, `phx:${event}`, { detail: payload });
6736
6987
  }
6988
+ /** @internal */
6737
6989
  dispatchEvents(events) {
6738
6990
  events.forEach(([event, payload]) => this.dispatchEvent(event, payload));
6739
6991
  }
6992
+ /** @internal */
6740
6993
  withPageLoading(info, callback) {
6741
6994
  dom_default.dispatchEvent(window, "phx:page-loading-start", { detail: info });
6742
6995
  const done = () => dom_default.dispatchEvent(window, "phx:page-loading-stop", { detail: info });
6743
6996
  return callback ? callback(done) : done;
6744
6997
  }
6998
+ /** @internal */
6745
6999
  pushHistoryPatch(e, href, linkState, targetEl) {
6746
- if (!this.isConnected() || !this.main.isMain()) {
7000
+ if (!this.isConnected() || !(this.main && this.main.isMain())) {
6747
7001
  return browser_default.redirect(href);
6748
7002
  }
6749
7003
  this.withPageLoading({ to: href, kind: "patch" }, (done) => {
@@ -6753,6 +7007,7 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
6753
7007
  });
6754
7008
  });
6755
7009
  }
7010
+ /** @internal */
6756
7011
  historyPatch(href, linkState, linkRef = this.setPendingLink(href)) {
6757
7012
  if (!this.commitPendingLink(linkRef)) {
6758
7013
  return;
@@ -6777,12 +7032,13 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
6777
7032
  });
6778
7033
  this.registerNewLocation(window.location);
6779
7034
  }
7035
+ /** @internal */
6780
7036
  historyRedirect(e, href, linkState, flash, targetEl) {
6781
7037
  const clickLoading = targetEl && e.isTrusted && e.type !== "popstate";
6782
7038
  if (clickLoading) {
6783
7039
  targetEl.classList.add("phx-click-loading");
6784
7040
  }
6785
- if (!this.isConnected() || !this.main.isMain()) {
7041
+ if (!this.isConnected() || !(this.main && this.main.isMain())) {
6786
7042
  return browser_default.redirect(href, flash);
6787
7043
  }
6788
7044
  if (/^\/$|^\/[^\/]+.*$/.test(href)) {
@@ -6823,6 +7079,7 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
6823
7079
  });
6824
7080
  });
6825
7081
  }
7082
+ /** @internal */
6826
7083
  registerNewLocation(newLocation) {
6827
7084
  const { pathname, search } = this.currentLocation;
6828
7085
  if (pathname + search === newLocation.pathname + newLocation.search) {
@@ -6832,10 +7089,13 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
6832
7089
  return true;
6833
7090
  }
6834
7091
  }
7092
+ /** @internal */
6835
7093
  bindForms() {
6836
7094
  let iterations = 0;
6837
7095
  let externalFormSubmitted = false;
6838
7096
  this.on("submit", (e) => {
7097
+ if (!(e.target instanceof HTMLFormElement))
7098
+ return;
6839
7099
  const phxSubmit = e.target.getAttribute(this.binding("submit"));
6840
7100
  const phxChange = e.target.getAttribute(this.binding("change"));
6841
7101
  if (!externalFormSubmitted && phxChange && !phxSubmit) {
@@ -6853,6 +7113,8 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
6853
7113
  }
6854
7114
  });
6855
7115
  this.on("submit", (e) => {
7116
+ if (!(e.target instanceof HTMLFormElement))
7117
+ return;
6856
7118
  const phxEvent = e.target.getAttribute(this.binding("submit"));
6857
7119
  if (!phxEvent) {
6858
7120
  if (dom_default.isUnloadableFormSubmit(e)) {
@@ -6871,7 +7133,10 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
6871
7133
  });
6872
7134
  for (const type of ["change", "input"]) {
6873
7135
  this.on(type, (e) => {
6874
- if (e instanceof CustomEvent && (e.target instanceof HTMLInputElement || e.target instanceof HTMLSelectElement || e.target instanceof HTMLTextAreaElement) && e.target.form === void 0) {
7136
+ if (!dom_default.isFormAssociated(e.target)) {
7137
+ return;
7138
+ }
7139
+ if (e instanceof CustomEvent && e.target.form === void 0) {
6875
7140
  if (e.detail && e.detail.dispatcher) {
6876
7141
  throw new Error(
6877
7142
  `dispatching a custom ${type} event is only supported on input elements inside a form`
@@ -6879,9 +7144,9 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
6879
7144
  }
6880
7145
  return;
6881
7146
  }
6882
- const phxChange = this.binding("change");
6883
7147
  const input = e.target;
6884
- if (this.blockPhxChangeWhileComposing && e.isComposing) {
7148
+ const phxChange = this.binding("change");
7149
+ if (this.blockPhxChangeWhileComposing && e instanceof InputEvent && e.isComposing) {
6885
7150
  const key = `composition-listener-${type}`;
6886
7151
  if (!dom_default.private(input, key)) {
6887
7152
  dom_default.putPrivate(input, key, true);
@@ -6921,7 +7186,7 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
6921
7186
  dom_default.putPrivate(input, PHX_HAS_FOCUSED, true);
6922
7187
  js_default.exec(e, "change", phxEvent, view, input, [
6923
7188
  "push",
6924
- { _target: e.target.name, dispatcher }
7189
+ { _target: input.name, dispatcher }
6925
7190
  ]);
6926
7191
  });
6927
7192
  });
@@ -6930,7 +7195,9 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
6930
7195
  this.on("reset", (e) => {
6931
7196
  const form = e.target;
6932
7197
  dom_default.resetForm(form);
6933
- const input = Array.from(form.elements).find((el) => el.type === "reset");
7198
+ const input = Array.from(form.elements).find(
7199
+ (el) => "type" in el && el.type === "reset"
7200
+ );
6934
7201
  if (input) {
6935
7202
  window.requestAnimationFrame(() => {
6936
7203
  input.dispatchEvent(
@@ -6940,6 +7207,7 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
6940
7207
  }
6941
7208
  });
6942
7209
  }
7210
+ /** @internal */
6943
7211
  debounce(el, event, eventType, callback) {
6944
7212
  if (eventType === "blur" || eventType === "focusout") {
6945
7213
  return callback();
@@ -6964,11 +7232,13 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
6964
7232
  );
6965
7233
  });
6966
7234
  }
7235
+ /** @internal */
6967
7236
  silenceEvents(callback) {
6968
7237
  this.silenced = true;
6969
7238
  callback();
6970
7239
  this.silenced = false;
6971
7240
  }
7241
+ /** @internal */
6972
7242
  on(event, callback) {
6973
7243
  this.boundEventNames.add(event);
6974
7244
  window.addEventListener(event, (e) => {
@@ -6977,6 +7247,7 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
6977
7247
  }
6978
7248
  });
6979
7249
  }
7250
+ /** @internal */
6980
7251
  jsQuerySelectorAll(sourceEl, query, defaultQuery) {
6981
7252
  const all = this.domCallbacks.jsQuerySelectorAll;
6982
7253
  return all ? all(sourceEl, query, defaultQuery) : defaultQuery();
@@ -7038,7 +7309,6 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
7038
7309
  };
7039
7310
 
7040
7311
  // js/phoenix_live_view/index.ts
7041
- var LiveSocket2 = LiveSocket;
7042
7312
  function createHook(el, callbacks) {
7043
7313
  let existingHook = dom_default.getCustomElHook(el);
7044
7314
  if (existingHook) {