@hotwired/turbo 7.2.5 → 7.3.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 (37) hide show
  1. package/dist/turbo.es2017-esm.js +135 -75
  2. package/dist/turbo.es2017-umd.js +135 -75
  3. package/dist/types/core/drive/form_submission.d.ts +8 -4
  4. package/dist/types/core/drive/head_snapshot.d.ts +3 -3
  5. package/dist/types/core/drive/history.d.ts +3 -3
  6. package/dist/types/core/drive/navigator.d.ts +1 -1
  7. package/dist/types/core/drive/page_view.d.ts +2 -2
  8. package/dist/types/core/drive/visit.d.ts +3 -3
  9. package/dist/types/core/errors.d.ts +2 -0
  10. package/dist/types/core/frames/frame_controller.d.ts +6 -2
  11. package/dist/types/core/frames/frame_view.d.ts +2 -2
  12. package/dist/types/core/index.d.ts +5 -4
  13. package/dist/types/core/native/browser_adapter.d.ts +1 -1
  14. package/dist/types/core/renderer.d.ts +1 -1
  15. package/dist/types/core/session.d.ts +12 -12
  16. package/dist/types/core/snapshot.d.ts +1 -1
  17. package/dist/types/core/streams/stream_actions.d.ts +2 -2
  18. package/dist/types/core/types.d.ts +3 -3
  19. package/dist/types/core/url.d.ts +1 -1
  20. package/dist/types/core/view.d.ts +1 -1
  21. package/dist/types/elements/frame_element.d.ts +1 -1
  22. package/dist/types/elements/stream_element.d.ts +2 -2
  23. package/dist/types/http/fetch_request.d.ts +7 -7
  24. package/dist/types/http/index.d.ts +1 -1
  25. package/dist/types/observers/cache_observer.d.ts +5 -1
  26. package/dist/types/observers/form_link_click_observer.d.ts +1 -1
  27. package/dist/types/polyfills/custom-elements-native-shim.d.ts +1 -0
  28. package/dist/types/tests/helpers/dom_test_case.d.ts +1 -2
  29. package/dist/types/tests/helpers/page.d.ts +10 -10
  30. package/dist/types/tests/unit/deprecated_adapter_support_tests.d.ts +1 -0
  31. package/dist/types/tests/unit/export_tests.d.ts +1 -5
  32. package/dist/types/tests/unit/stream_element_tests.d.ts +0 -10
  33. package/dist/types/util.d.ts +1 -1
  34. package/package.json +16 -10
  35. package/dist/types/tests/helpers/intern_test_case.d.ts +0 -19
  36. package/dist/types/tests/unit/deprecated_adapter_support_test.d.ts +0 -24
  37. package/dist/types/tests/unit/index.d.ts +0 -3
@@ -1,5 +1,5 @@
1
1
  /*
2
- Turbo 7.2.5
2
+ Turbo 7.3.0
3
3
  Copyright © 2023 37signals LLC
4
4
  */
5
5
  (function (global, factory) {
@@ -93,16 +93,13 @@ Copyright © 2023 37signals LLC
93
93
  (function () {
94
94
  if ("submitter" in Event.prototype)
95
95
  return;
96
- let prototype;
96
+ let prototype = window.Event.prototype;
97
97
  if ("SubmitEvent" in window && /Apple Computer/.test(navigator.vendor)) {
98
98
  prototype = window.SubmitEvent.prototype;
99
99
  }
100
100
  else if ("SubmitEvent" in window) {
101
101
  return;
102
102
  }
103
- else {
104
- prototype = window.Event.prototype;
105
- }
106
103
  addEventListener("click", clickCaptured, true);
107
104
  Object.defineProperty(prototype, "submitter", {
108
105
  get() {
@@ -119,14 +116,14 @@ Copyright © 2023 37signals LLC
119
116
  FrameLoadingStyle["lazy"] = "lazy";
120
117
  })(exports.FrameLoadingStyle || (exports.FrameLoadingStyle = {}));
121
118
  class FrameElement extends HTMLElement {
119
+ static get observedAttributes() {
120
+ return ["disabled", "complete", "loading", "src"];
121
+ }
122
122
  constructor() {
123
123
  super();
124
124
  this.loaded = Promise.resolve();
125
125
  this.delegate = new FrameElement.delegateConstructor(this);
126
126
  }
127
- static get observedAttributes() {
128
- return ["disabled", "complete", "loading", "src"];
129
- }
130
127
  connectedCallback() {
131
128
  this.delegate.connect();
132
129
  }
@@ -566,7 +563,7 @@ Copyright © 2023 37signals LLC
566
563
  credentials: "same-origin",
567
564
  headers: this.headers,
568
565
  redirect: "follow",
569
- body: this.isIdempotent ? null : this.body,
566
+ body: this.isSafe ? null : this.body,
570
567
  signal: this.abortSignal,
571
568
  referrer: (_a = this.delegate.referrer) === null || _a === void 0 ? void 0 : _a.href,
572
569
  };
@@ -576,8 +573,8 @@ Copyright © 2023 37signals LLC
576
573
  Accept: "text/html, application/xhtml+xml",
577
574
  };
578
575
  }
579
- get isIdempotent() {
580
- return this.method == FetchMethod.get;
576
+ get isSafe() {
577
+ return this.method === FetchMethod.get;
581
578
  }
582
579
  get abortSignal() {
583
580
  return this.abortController.signal;
@@ -637,9 +634,6 @@ Copyright © 2023 37signals LLC
637
634
  }
638
635
 
639
636
  class StreamMessage {
640
- constructor(fragment) {
641
- this.fragment = importStreamElements(fragment);
642
- }
643
637
  static wrap(message) {
644
638
  if (typeof message == "string") {
645
639
  return new this(createDocumentFragment(message));
@@ -648,6 +642,9 @@ Copyright © 2023 37signals LLC
648
642
  return message;
649
643
  }
650
644
  }
645
+ constructor(fragment) {
646
+ this.fragment = importStreamElements(fragment);
647
+ }
651
648
  }
652
649
  StreamMessage.contentType = "text/vnd.turbo-stream.html";
653
650
  function importStreamElements(fragment) {
@@ -687,6 +684,9 @@ Copyright © 2023 37signals LLC
687
684
  }
688
685
  }
689
686
  class FormSubmission {
687
+ static confirmMethod(message, _element, _submitter) {
688
+ return Promise.resolve(confirm(message));
689
+ }
690
690
  constructor(delegate, formElement, submitter, mustRedirect = false) {
691
691
  this.state = FormSubmissionState.initialized;
692
692
  this.delegate = delegate;
@@ -700,9 +700,6 @@ Copyright © 2023 37signals LLC
700
700
  this.fetchRequest = new FetchRequest(this, this.method, this.location, this.body, this.formElement);
701
701
  this.mustRedirect = mustRedirect;
702
702
  }
703
- static confirmMethod(message, _element, _submitter) {
704
- return Promise.resolve(confirm(message));
705
- }
706
703
  get method() {
707
704
  var _a;
708
705
  const method = ((_a = this.submitter) === null || _a === void 0 ? void 0 : _a.getAttribute("formmethod")) || this.formElement.getAttribute("method") || "";
@@ -730,8 +727,8 @@ Copyright © 2023 37signals LLC
730
727
  var _a;
731
728
  return formEnctypeFromString(((_a = this.submitter) === null || _a === void 0 ? void 0 : _a.getAttribute("formenctype")) || this.formElement.enctype);
732
729
  }
733
- get isIdempotent() {
734
- return this.fetchRequest.isIdempotent;
730
+ get isSafe() {
731
+ return this.fetchRequest.isSafe;
735
732
  }
736
733
  get stringFormData() {
737
734
  return [...this.formData].reduce((entries, [name, value]) => {
@@ -761,7 +758,7 @@ Copyright © 2023 37signals LLC
761
758
  }
762
759
  }
763
760
  prepareRequest(request) {
764
- if (!request.isIdempotent) {
761
+ if (!request.isSafe) {
765
762
  const token = getCookieValue(getMetaContent("csrf-param")) || getMetaContent("csrf-token");
766
763
  if (token) {
767
764
  request.headers["X-CSRF-Token"] = token;
@@ -775,6 +772,7 @@ Copyright © 2023 37signals LLC
775
772
  var _a;
776
773
  this.state = FormSubmissionState.waiting;
777
774
  (_a = this.submitter) === null || _a === void 0 ? void 0 : _a.setAttribute("disabled", "");
775
+ this.setSubmitsWith();
778
776
  dispatch("turbo:submit-start", {
779
777
  target: this.formElement,
780
778
  detail: { formSubmission: this },
@@ -810,17 +808,46 @@ Copyright © 2023 37signals LLC
810
808
  var _a;
811
809
  this.state = FormSubmissionState.stopped;
812
810
  (_a = this.submitter) === null || _a === void 0 ? void 0 : _a.removeAttribute("disabled");
811
+ this.resetSubmitterText();
813
812
  dispatch("turbo:submit-end", {
814
813
  target: this.formElement,
815
814
  detail: Object.assign({ formSubmission: this }, this.result),
816
815
  });
817
816
  this.delegate.formSubmissionFinished(this);
818
817
  }
818
+ setSubmitsWith() {
819
+ if (!this.submitter || !this.submitsWith)
820
+ return;
821
+ if (this.submitter.matches("button")) {
822
+ this.originalSubmitText = this.submitter.innerHTML;
823
+ this.submitter.innerHTML = this.submitsWith;
824
+ }
825
+ else if (this.submitter.matches("input")) {
826
+ const input = this.submitter;
827
+ this.originalSubmitText = input.value;
828
+ input.value = this.submitsWith;
829
+ }
830
+ }
831
+ resetSubmitterText() {
832
+ if (!this.submitter || !this.originalSubmitText)
833
+ return;
834
+ if (this.submitter.matches("button")) {
835
+ this.submitter.innerHTML = this.originalSubmitText;
836
+ }
837
+ else if (this.submitter.matches("input")) {
838
+ const input = this.submitter;
839
+ input.value = this.originalSubmitText;
840
+ }
841
+ }
819
842
  requestMustRedirect(request) {
820
- return !request.isIdempotent && this.mustRedirect;
843
+ return !request.isSafe && this.mustRedirect;
821
844
  }
822
845
  requestAcceptsTurboStreamResponse(request) {
823
- return !request.isIdempotent || hasAttribute("data-turbo-stream", this.submitter, this.formElement);
846
+ return !request.isSafe || hasAttribute("data-turbo-stream", this.submitter, this.formElement);
847
+ }
848
+ get submitsWith() {
849
+ var _a;
850
+ return (_a = this.submitter) === null || _a === void 0 ? void 0 : _a.getAttribute("data-turbo-submits-with");
824
851
  }
825
852
  }
826
853
  function buildFormData(formElement, submitter) {
@@ -1060,8 +1087,8 @@ Copyright © 2023 37signals LLC
1060
1087
  }
1061
1088
 
1062
1089
  class FrameView extends View {
1063
- invalidate() {
1064
- this.element.innerHTML = "";
1090
+ missing() {
1091
+ this.element.innerHTML = `<strong class="turbo-frame-error">Content missing</strong>`;
1065
1092
  }
1066
1093
  get snapshot() {
1067
1094
  return new Snapshot(this.element);
@@ -1222,16 +1249,16 @@ Copyright © 2023 37signals LLC
1222
1249
  }
1223
1250
 
1224
1251
  class Bardo {
1225
- constructor(delegate, permanentElementMap) {
1226
- this.delegate = delegate;
1227
- this.permanentElementMap = permanentElementMap;
1228
- }
1229
1252
  static async preservingPermanentElements(delegate, permanentElementMap, callback) {
1230
1253
  const bardo = new this(delegate, permanentElementMap);
1231
1254
  bardo.enter();
1232
1255
  await callback();
1233
1256
  bardo.leave();
1234
1257
  }
1258
+ constructor(delegate, permanentElementMap) {
1259
+ this.delegate = delegate;
1260
+ this.permanentElementMap = permanentElementMap;
1261
+ }
1235
1262
  enter() {
1236
1263
  for (const id in this.permanentElementMap) {
1237
1264
  const [currentPermanentElement, newPermanentElement] = this.permanentElementMap[id];
@@ -1338,10 +1365,6 @@ Copyright © 2023 37signals LLC
1338
1365
  }
1339
1366
 
1340
1367
  class FrameRenderer extends Renderer {
1341
- constructor(delegate, currentSnapshot, newSnapshot, renderElement, isPreview, willRender = true) {
1342
- super(currentSnapshot, newSnapshot, renderElement, isPreview, willRender);
1343
- this.delegate = delegate;
1344
- }
1345
1368
  static renderElement(currentElement, newElement) {
1346
1369
  var _a;
1347
1370
  const destinationRange = document.createRange();
@@ -1354,6 +1377,10 @@ Copyright © 2023 37signals LLC
1354
1377
  currentElement.appendChild(sourceRange.extractContents());
1355
1378
  }
1356
1379
  }
1380
+ constructor(delegate, currentSnapshot, newSnapshot, renderElement, isPreview, willRender = true) {
1381
+ super(currentSnapshot, newSnapshot, renderElement, isPreview, willRender);
1382
+ this.delegate = delegate;
1383
+ }
1357
1384
  get shouldRender() {
1358
1385
  return true;
1359
1386
  }
@@ -1412,18 +1439,6 @@ Copyright © 2023 37signals LLC
1412
1439
  }
1413
1440
 
1414
1441
  class ProgressBar {
1415
- constructor() {
1416
- this.hiding = false;
1417
- this.value = 0;
1418
- this.visible = false;
1419
- this.trickle = () => {
1420
- this.setValue(this.value + Math.random() / 100);
1421
- };
1422
- this.stylesheetElement = this.createStylesheetElement();
1423
- this.progressElement = this.createProgressElement();
1424
- this.installStylesheetElement();
1425
- this.setValue(0);
1426
- }
1427
1442
  static get defaultCSS() {
1428
1443
  return unindent `
1429
1444
  .turbo-progress-bar {
@@ -1441,6 +1456,18 @@ Copyright © 2023 37signals LLC
1441
1456
  }
1442
1457
  `;
1443
1458
  }
1459
+ constructor() {
1460
+ this.hiding = false;
1461
+ this.value = 0;
1462
+ this.visible = false;
1463
+ this.trickle = () => {
1464
+ this.setValue(this.value + Math.random() / 100);
1465
+ };
1466
+ this.stylesheetElement = this.createStylesheetElement();
1467
+ this.progressElement = this.createProgressElement();
1468
+ this.installStylesheetElement();
1469
+ this.setValue(0);
1470
+ }
1444
1471
  show() {
1445
1472
  if (!this.visible) {
1446
1473
  this.visible = true;
@@ -1611,10 +1638,6 @@ Copyright © 2023 37signals LLC
1611
1638
  }
1612
1639
 
1613
1640
  class PageSnapshot extends Snapshot {
1614
- constructor(element, headSnapshot) {
1615
- super(element);
1616
- this.headSnapshot = headSnapshot;
1617
- }
1618
1641
  static fromHTMLString(html = "") {
1619
1642
  return this.fromDocument(parseHTMLDocument(html));
1620
1643
  }
@@ -1624,6 +1647,10 @@ Copyright © 2023 37signals LLC
1624
1647
  static fromDocument({ head, body }) {
1625
1648
  return new this(body, new HeadSnapshot(head));
1626
1649
  }
1650
+ constructor(element, headSnapshot) {
1651
+ super(element);
1652
+ this.headSnapshot = headSnapshot;
1653
+ }
1627
1654
  clone() {
1628
1655
  const clonedElement = this.element.cloneNode(true);
1629
1656
  const selectElements = this.element.querySelectorAll("select");
@@ -2123,10 +2150,11 @@ Copyright © 2023 37signals LLC
2123
2150
 
2124
2151
  class CacheObserver {
2125
2152
  constructor() {
2153
+ this.selector = "[data-turbo-temporary]";
2154
+ this.deprecatedSelector = "[data-turbo-cache=false]";
2126
2155
  this.started = false;
2127
- this.removeStaleElements = ((_event) => {
2128
- const staleElements = [...document.querySelectorAll('[data-turbo-cache="false"]')];
2129
- for (const element of staleElements) {
2156
+ this.removeTemporaryElements = ((_event) => {
2157
+ for (const element of this.temporaryElements) {
2130
2158
  element.remove();
2131
2159
  }
2132
2160
  });
@@ -2134,15 +2162,25 @@ Copyright © 2023 37signals LLC
2134
2162
  start() {
2135
2163
  if (!this.started) {
2136
2164
  this.started = true;
2137
- addEventListener("turbo:before-cache", this.removeStaleElements, false);
2165
+ addEventListener("turbo:before-cache", this.removeTemporaryElements, false);
2138
2166
  }
2139
2167
  }
2140
2168
  stop() {
2141
2169
  if (this.started) {
2142
2170
  this.started = false;
2143
- removeEventListener("turbo:before-cache", this.removeStaleElements, false);
2171
+ removeEventListener("turbo:before-cache", this.removeTemporaryElements, false);
2144
2172
  }
2145
2173
  }
2174
+ get temporaryElements() {
2175
+ return [...document.querySelectorAll(this.selector), ...this.temporaryElementsWithDeprecation];
2176
+ }
2177
+ get temporaryElementsWithDeprecation() {
2178
+ const elements = document.querySelectorAll(this.deprecatedSelector);
2179
+ if (elements.length) {
2180
+ console.warn(`The ${this.deprecatedSelector} selector is deprecated and will be removed in a future version. Use ${this.selector} instead.`);
2181
+ }
2182
+ return [...elements];
2183
+ }
2146
2184
  }
2147
2185
 
2148
2186
  class FrameRedirector {
@@ -2341,7 +2379,7 @@ Copyright © 2023 37signals LLC
2341
2379
  if (formSubmission == this.formSubmission) {
2342
2380
  const responseHTML = await fetchResponse.responseHTML;
2343
2381
  if (responseHTML) {
2344
- const shouldCacheSnapshot = formSubmission.method == FetchMethod.get;
2382
+ const shouldCacheSnapshot = formSubmission.isSafe;
2345
2383
  if (!shouldCacheSnapshot) {
2346
2384
  this.view.clearSnapshotCache();
2347
2385
  }
@@ -3301,6 +3339,9 @@ Copyright © 2023 37signals LLC
3301
3339
  StreamActions: StreamActions
3302
3340
  });
3303
3341
 
3342
+ class TurboFrameMissingError extends Error {
3343
+ }
3344
+
3304
3345
  class FrameController {
3305
3346
  constructor(element) {
3306
3347
  this.fetchResponseLoaded = (_fetchResponse) => { };
@@ -3401,30 +3442,16 @@ Copyright © 2023 37signals LLC
3401
3442
  try {
3402
3443
  const html = await fetchResponse.responseHTML;
3403
3444
  if (html) {
3404
- const { body } = parseHTMLDocument(html);
3405
- const newFrameElement = await this.extractForeignFrameElement(body);
3406
- if (newFrameElement) {
3407
- const snapshot = new Snapshot(newFrameElement);
3408
- const renderer = new FrameRenderer(this, this.view.snapshot, snapshot, FrameRenderer.renderElement, false, false);
3409
- if (this.view.renderPromise)
3410
- await this.view.renderPromise;
3411
- this.changeHistory();
3412
- await this.view.render(renderer);
3413
- this.complete = true;
3414
- session.frameRendered(fetchResponse, this.element);
3415
- session.frameLoaded(this.element);
3416
- this.fetchResponseLoaded(fetchResponse);
3445
+ const document = parseHTMLDocument(html);
3446
+ const pageSnapshot = PageSnapshot.fromDocument(document);
3447
+ if (pageSnapshot.isVisitable) {
3448
+ await this.loadFrameResponse(fetchResponse, document);
3417
3449
  }
3418
- else if (this.willHandleFrameMissingFromResponse(fetchResponse)) {
3419
- console.warn(`A matching frame for #${this.element.id} was missing from the response, transforming into full-page Visit.`);
3420
- this.visitResponse(fetchResponse.response);
3450
+ else {
3451
+ await this.handleUnvisitableFrameResponse(fetchResponse);
3421
3452
  }
3422
3453
  }
3423
3454
  }
3424
- catch (error) {
3425
- console.error(error);
3426
- this.view.invalidate();
3427
- }
3428
3455
  finally {
3429
3456
  this.fetchResponseLoaded = () => { };
3430
3457
  }
@@ -3477,7 +3504,6 @@ Copyright © 2023 37signals LLC
3477
3504
  this.resolveVisitPromise();
3478
3505
  }
3479
3506
  async requestFailedWithResponse(request, response) {
3480
- console.error(response);
3481
3507
  await this.loadResponse(response);
3482
3508
  this.resolveVisitPromise();
3483
3509
  }
@@ -3495,9 +3521,13 @@ Copyright © 2023 37signals LLC
3495
3521
  const frame = this.findFrameElement(formSubmission.formElement, formSubmission.submitter);
3496
3522
  frame.delegate.proposeVisitIfNavigatedWithAction(frame, formSubmission.formElement, formSubmission.submitter);
3497
3523
  frame.delegate.loadResponse(response);
3524
+ if (!formSubmission.isSafe) {
3525
+ session.clearCache();
3526
+ }
3498
3527
  }
3499
3528
  formSubmissionFailedWithResponse(formSubmission, fetchResponse) {
3500
3529
  this.element.delegate.loadResponse(fetchResponse);
3530
+ session.clearCache();
3501
3531
  }
3502
3532
  formSubmissionErrored(formSubmission, error) {
3503
3533
  console.error(error);
@@ -3525,6 +3555,24 @@ Copyright © 2023 37signals LLC
3525
3555
  willRenderFrame(currentElement, _newElement) {
3526
3556
  this.previousFrameElement = currentElement.cloneNode(true);
3527
3557
  }
3558
+ async loadFrameResponse(fetchResponse, document) {
3559
+ const newFrameElement = await this.extractForeignFrameElement(document.body);
3560
+ if (newFrameElement) {
3561
+ const snapshot = new Snapshot(newFrameElement);
3562
+ const renderer = new FrameRenderer(this, this.view.snapshot, snapshot, FrameRenderer.renderElement, false, false);
3563
+ if (this.view.renderPromise)
3564
+ await this.view.renderPromise;
3565
+ this.changeHistory();
3566
+ await this.view.render(renderer);
3567
+ this.complete = true;
3568
+ session.frameRendered(fetchResponse, this.element);
3569
+ session.frameLoaded(this.element);
3570
+ this.fetchResponseLoaded(fetchResponse);
3571
+ }
3572
+ else if (this.willHandleFrameMissingFromResponse(fetchResponse)) {
3573
+ this.handleFrameMissingFromResponse(fetchResponse);
3574
+ }
3575
+ }
3528
3576
  async visit(url) {
3529
3577
  var _a;
3530
3578
  const request = new FetchRequest(this, FetchMethod.get, url, new URLSearchParams(), this.element);
@@ -3577,6 +3625,10 @@ Copyright © 2023 37signals LLC
3577
3625
  session.history.update(method, expandURL(this.element.src || ""), this.restorationIdentifier);
3578
3626
  }
3579
3627
  }
3628
+ async handleUnvisitableFrameResponse(fetchResponse) {
3629
+ console.warn(`The response (${fetchResponse.statusCode}) from <turbo-frame id="${this.element.id}"> is performing a full page visit due to turbo-visit-control.`);
3630
+ await this.visitResponse(fetchResponse.response);
3631
+ }
3580
3632
  willHandleFrameMissingFromResponse(fetchResponse) {
3581
3633
  this.element.setAttribute("complete", "");
3582
3634
  const response = fetchResponse.response;
@@ -3595,6 +3647,14 @@ Copyright © 2023 37signals LLC
3595
3647
  });
3596
3648
  return !event.defaultPrevented;
3597
3649
  }
3650
+ handleFrameMissingFromResponse(fetchResponse) {
3651
+ this.view.missing();
3652
+ this.throwFrameMissingError(fetchResponse);
3653
+ }
3654
+ throwFrameMissingError(fetchResponse) {
3655
+ const message = `The response (${fetchResponse.statusCode}) did not contain the expected <turbo-frame id="${this.element.id}"> and will be ignored. To perform a full page visit instead, set turbo-visit-control to reload.`;
3656
+ throw new TurboFrameMissingError(message);
3657
+ }
3598
3658
  async visitResponse(response) {
3599
3659
  const wrapped = new FetchResponse(response);
3600
3660
  const responseHTML = await wrapped.responseHTML;
@@ -7,7 +7,7 @@ export interface FormSubmissionDelegate {
7
7
  formSubmissionErrored(formSubmission: FormSubmission, error: Error): void;
8
8
  formSubmissionFinished(formSubmission: FormSubmission): void;
9
9
  }
10
- export declare type FormSubmissionResult = {
10
+ export type FormSubmissionResult = {
11
11
  success: boolean;
12
12
  fetchResponse: FetchResponse;
13
13
  } | {
@@ -27,10 +27,10 @@ declare enum FormEnctype {
27
27
  multipart = "multipart/form-data",
28
28
  plain = "text/plain"
29
29
  }
30
- export declare type TurboSubmitStartEvent = CustomEvent<{
30
+ export type TurboSubmitStartEvent = CustomEvent<{
31
31
  formSubmission: FormSubmission;
32
32
  }>;
33
- export declare type TurboSubmitEndEvent = CustomEvent<{
33
+ export type TurboSubmitEndEvent = CustomEvent<{
34
34
  formSubmission: FormSubmission;
35
35
  } & {
36
36
  [K in keyof FormSubmissionResult]?: FormSubmissionResult[K];
@@ -45,13 +45,14 @@ export declare class FormSubmission {
45
45
  readonly mustRedirect: boolean;
46
46
  state: FormSubmissionState;
47
47
  result?: FormSubmissionResult;
48
+ originalSubmitText?: string;
48
49
  static confirmMethod(message: string, _element: HTMLFormElement, _submitter: HTMLElement | undefined): Promise<boolean>;
49
50
  constructor(delegate: FormSubmissionDelegate, formElement: HTMLFormElement, submitter?: HTMLElement, mustRedirect?: boolean);
50
51
  get method(): FetchMethod;
51
52
  get action(): string;
52
53
  get body(): FormData;
53
54
  get enctype(): FormEnctype;
54
- get isIdempotent(): boolean;
55
+ get isSafe(): boolean;
55
56
  get stringFormData(): [string, string][];
56
57
  start(): Promise<void | FetchResponse>;
57
58
  stop(): true | undefined;
@@ -62,7 +63,10 @@ export declare class FormSubmission {
62
63
  requestFailedWithResponse(request: FetchRequest, response: FetchResponse): void;
63
64
  requestErrored(request: FetchRequest, error: Error): void;
64
65
  requestFinished(_request: FetchRequest): void;
66
+ setSubmitsWith(): void;
67
+ resetSubmitterText(): void;
65
68
  requestMustRedirect(request: FetchRequest): boolean;
66
69
  requestAcceptsTurboStreamResponse(request: FetchRequest): boolean;
70
+ get submitsWith(): string | null | undefined;
67
71
  }
68
72
  export {};
@@ -1,13 +1,13 @@
1
1
  import { Snapshot } from "../snapshot";
2
- declare type ElementDetailMap = {
2
+ type ElementDetailMap = {
3
3
  [outerHTML: string]: ElementDetails;
4
4
  };
5
- declare type ElementDetails = {
5
+ type ElementDetails = {
6
6
  type?: ElementType;
7
7
  tracked: boolean;
8
8
  elements: Element[];
9
9
  };
10
- declare type ElementType = "script" | "stylesheet";
10
+ type ElementType = "script" | "stylesheet";
11
11
  export declare class HeadSnapshot extends Snapshot<HTMLHeadElement> {
12
12
  readonly detailsByOuterHTML: ElementDetailMap;
13
13
  get trackedElementSignature(): string;
@@ -2,11 +2,11 @@ import { Position } from "../types";
2
2
  export interface HistoryDelegate {
3
3
  historyPoppedToLocationWithRestorationIdentifier(location: URL, restorationIdentifier: string): void;
4
4
  }
5
- declare type HistoryMethod = (this: typeof history, state: any, title: string, url?: string | null | undefined) => void;
6
- export declare type RestorationData = {
5
+ type HistoryMethod = (this: typeof history, state: any, title: string, url?: string | null | undefined) => void;
6
+ export type RestorationData = {
7
7
  scrollPosition?: Position;
8
8
  };
9
- export declare type RestorationDataMap = {
9
+ export type RestorationDataMap = {
10
10
  [restorationIdentifier: string]: RestorationData;
11
11
  };
12
12
  export declare class History {
@@ -3,7 +3,7 @@ import { FetchResponse } from "../../http/fetch_response";
3
3
  import { FormSubmission } from "./form_submission";
4
4
  import { Locatable } from "../url";
5
5
  import { Visit, VisitDelegate, VisitOptions } from "./visit";
6
- export declare type NavigatorDelegate = VisitDelegate & {
6
+ export type NavigatorDelegate = VisitDelegate & {
7
7
  allowsVisitingLocationWithAction(location: URL, action?: Action): boolean;
8
8
  visitProposedToLocation(location: URL, options: Partial<VisitOptions>): void;
9
9
  notifyApplicationAfterVisitingSamePageLocation(oldURL: URL, newURL: URL): void;
@@ -4,11 +4,11 @@ import { PageRenderer } from "./page_renderer";
4
4
  import { PageSnapshot } from "./page_snapshot";
5
5
  import { SnapshotCache } from "./snapshot_cache";
6
6
  import { Visit } from "./visit";
7
- export declare type PageViewRenderOptions = ViewRenderOptions<HTMLBodyElement>;
7
+ export type PageViewRenderOptions = ViewRenderOptions<HTMLBodyElement>;
8
8
  export interface PageViewDelegate extends ViewDelegate<HTMLBodyElement, PageSnapshot> {
9
9
  viewWillCacheSnapshot(): void;
10
10
  }
11
- declare type PageViewRenderer = PageRenderer | ErrorRenderer;
11
+ type PageViewRenderer = PageRenderer | ErrorRenderer;
12
12
  export declare class PageView extends View<HTMLBodyElement, PageSnapshot, PageViewRenderer, PageViewDelegate> {
13
13
  readonly snapshotCache: SnapshotCache;
14
14
  lastRenderedLocation: URL;
@@ -21,7 +21,7 @@ export declare enum TimingMetric {
21
21
  requestEnd = "requestEnd",
22
22
  visitEnd = "visitEnd"
23
23
  }
24
- export declare type TimingMetrics = Partial<{
24
+ export type TimingMetrics = Partial<{
25
25
  [metric in TimingMetric]: any;
26
26
  }>;
27
27
  export declare enum VisitState {
@@ -31,7 +31,7 @@ export declare enum VisitState {
31
31
  failed = "failed",
32
32
  completed = "completed"
33
33
  }
34
- export declare type VisitOptions = {
34
+ export type VisitOptions = {
35
35
  action: Action;
36
36
  historyChanged: boolean;
37
37
  referrer?: URL;
@@ -46,7 +46,7 @@ export declare type VisitOptions = {
46
46
  frame?: string;
47
47
  acceptsStreamResponse: boolean;
48
48
  };
49
- export declare type VisitResponse = {
49
+ export type VisitResponse = {
50
50
  statusCode: number;
51
51
  redirected: boolean;
52
52
  responseHTML?: string;
@@ -0,0 +1,2 @@
1
+ export declare class TurboFrameMissingError extends Error {
2
+ }
@@ -11,8 +11,8 @@ import { FrameView } from "./frame_view";
11
11
  import { LinkInterceptor, LinkInterceptorDelegate } from "./link_interceptor";
12
12
  import { FormLinkClickObserver, FormLinkClickObserverDelegate } from "../../observers/form_link_click_observer";
13
13
  import { VisitOptions } from "../drive/visit";
14
- declare type VisitFallback = (location: Response | Locatable, options: Partial<VisitOptions>) => Promise<void>;
15
- export declare type TurboFrameMissingEvent = CustomEvent<{
14
+ type VisitFallback = (location: Response | Locatable, options: Partial<VisitOptions>) => Promise<void>;
15
+ export type TurboFrameMissingEvent = CustomEvent<{
16
16
  response: Response;
17
17
  visit: VisitFallback;
18
18
  }>;
@@ -69,11 +69,15 @@ export declare class FrameController implements AppearanceObserverDelegate<Frame
69
69
  viewInvalidated(): void;
70
70
  willRenderFrame(currentElement: FrameElement, _newElement: FrameElement): void;
71
71
  visitCachedSnapshot: ({ element }: Snapshot) => void;
72
+ private loadFrameResponse;
72
73
  private visit;
73
74
  private navigateFrame;
74
75
  proposeVisitIfNavigatedWithAction(frame: FrameElement, element: Element, submitter?: HTMLElement): void;
75
76
  changeHistory(): void;
77
+ private handleUnvisitableFrameResponse;
76
78
  private willHandleFrameMissingFromResponse;
79
+ private handleFrameMissingFromResponse;
80
+ private throwFrameMissingError;
77
81
  private visitResponse;
78
82
  private findFrameElement;
79
83
  extractForeignFrameElement(container: ParentNode): Promise<FrameElement | null>;
@@ -1,8 +1,8 @@
1
1
  import { FrameElement } from "../../elements";
2
2
  import { Snapshot } from "../snapshot";
3
3
  import { View, ViewRenderOptions } from "../view";
4
- export declare type FrameViewRenderOptions = ViewRenderOptions<FrameElement>;
4
+ export type FrameViewRenderOptions = ViewRenderOptions<FrameElement>;
5
5
  export declare class FrameView extends View<FrameElement> {
6
- invalidate(): void;
6
+ missing(): void;
7
7
  get snapshot(): Snapshot<FrameElement>;
8
8
  }
@@ -12,10 +12,11 @@ declare const session: Session;
12
12
  declare const cache: Cache;
13
13
  declare const navigator: import("./drive/navigator").Navigator;
14
14
  export { navigator, session, cache, PageRenderer, PageSnapshot, FrameRenderer };
15
- export { TurboBeforeCacheEvent, TurboBeforeRenderEvent, TurboBeforeVisitEvent, TurboClickEvent, TurboBeforeFrameRenderEvent, TurboFrameLoadEvent, TurboFrameRenderEvent, TurboLoadEvent, TurboRenderEvent, TurboVisitEvent, } from "./session";
16
- export { TurboSubmitStartEvent, TurboSubmitEndEvent } from "./drive/form_submission";
17
- export { TurboFrameMissingEvent } from "./frames/frame_controller";
18
- export { StreamActions, TurboStreamAction, TurboStreamActions } from "./streams/stream_actions";
15
+ export type { TurboBeforeCacheEvent, TurboBeforeRenderEvent, TurboBeforeVisitEvent, TurboClickEvent, TurboBeforeFrameRenderEvent, TurboFrameLoadEvent, TurboFrameRenderEvent, TurboLoadEvent, TurboRenderEvent, TurboVisitEvent, } from "./session";
16
+ export type { TurboSubmitStartEvent, TurboSubmitEndEvent } from "./drive/form_submission";
17
+ export type { TurboFrameMissingEvent } from "./frames/frame_controller";
18
+ export { StreamActions } from "./streams/stream_actions";
19
+ export type { TurboStreamAction, TurboStreamActions } from "./streams/stream_actions";
19
20
  export declare function start(): void;
20
21
  export declare function registerAdapter(adapter: Adapter): void;
21
22
  export declare function visit(location: Locatable, options?: Partial<VisitOptions>): void;
@@ -3,7 +3,7 @@ import { ProgressBar } from "../drive/progress_bar";
3
3
  import { Visit, VisitOptions } from "../drive/visit";
4
4
  import { FormSubmission } from "../drive/form_submission";
5
5
  import { Session } from "../session";
6
- export declare type ReloadReason = StructuredReason | undefined;
6
+ export type ReloadReason = StructuredReason | undefined;
7
7
  interface StructuredReason {
8
8
  reason: string;
9
9
  context?: {
@@ -1,7 +1,7 @@
1
1
  import { BardoDelegate } from "./bardo";
2
2
  import { Snapshot } from "./snapshot";
3
3
  import { ReloadReason } from "./native/browser_adapter";
4
- export declare type Render<E> = (currentElement: E, newElement: E) => void;
4
+ export type Render<E> = (currentElement: E, newElement: E) => void;
5
5
  export declare abstract class Renderer<E extends Element, S extends Snapshot<E> = Snapshot<E>> implements BardoDelegate {
6
6
  readonly currentSnapshot: S;
7
7
  readonly newSnapshot: S;