@hotwired/turbo 7.1.0-rc.1 → 7.1.0-rc.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
1
  /*
2
- Turbo 7.0.1
2
+ Turbo 7.1.0-rc.1
3
3
  Copyright © 2021 Basecamp, LLC
4
4
  */
5
5
  (function () {
@@ -1010,10 +1010,11 @@ function createPlaceholderForPermanentElement(permanentElement) {
1010
1010
  }
1011
1011
 
1012
1012
  class Renderer {
1013
- constructor(currentSnapshot, newSnapshot, isPreview) {
1013
+ constructor(currentSnapshot, newSnapshot, isPreview, willRender = true) {
1014
1014
  this.currentSnapshot = currentSnapshot;
1015
1015
  this.newSnapshot = newSnapshot;
1016
1016
  this.isPreview = isPreview;
1017
+ this.willRender = willRender;
1017
1018
  this.promise = new Promise((resolve, reject) => this.resolvingFunctions = { resolve, reject });
1018
1019
  }
1019
1020
  get shouldRender() {
@@ -1389,8 +1390,9 @@ var VisitState;
1389
1390
  })(VisitState || (VisitState = {}));
1390
1391
  const defaultOptions = {
1391
1392
  action: "advance",
1392
- delegate: {},
1393
1393
  historyChanged: false,
1394
+ visitCachedSnapshot: () => { },
1395
+ willRender: true,
1394
1396
  };
1395
1397
  var SystemStatusCode;
1396
1398
  (function (SystemStatusCode) {
@@ -1410,14 +1412,16 @@ class Visit {
1410
1412
  this.delegate = delegate;
1411
1413
  this.location = location;
1412
1414
  this.restorationIdentifier = restorationIdentifier || uuid();
1413
- const { action, historyChanged, referrer, snapshotHTML, response, delegate: optionalDelegate } = Object.assign(Object.assign({}, defaultOptions), options);
1415
+ const { action, historyChanged, referrer, snapshotHTML, response, visitCachedSnapshot, willRender } = Object.assign(Object.assign({}, defaultOptions), options);
1414
1416
  this.action = action;
1415
1417
  this.historyChanged = historyChanged;
1416
1418
  this.referrer = referrer;
1417
1419
  this.snapshotHTML = snapshotHTML;
1418
1420
  this.response = response;
1419
1421
  this.isSamePage = this.delegate.locationWithActionIsSamePage(this.location, this.action);
1420
- this.optionalDelegate = optionalDelegate;
1422
+ this.visitCachedSnapshot = visitCachedSnapshot;
1423
+ this.willRender = willRender;
1424
+ this.scrolled = !willRender;
1421
1425
  }
1422
1426
  get adapter() {
1423
1427
  return this.delegate.adapter;
@@ -1440,8 +1444,6 @@ class Visit {
1440
1444
  this.state = VisitState.started;
1441
1445
  this.adapter.visitStarted(this);
1442
1446
  this.delegate.visitStarted(this);
1443
- if (this.optionalDelegate.visitStarted)
1444
- this.optionalDelegate.visitStarted(this);
1445
1447
  }
1446
1448
  }
1447
1449
  cancel() {
@@ -1521,7 +1523,7 @@ class Visit {
1521
1523
  if (this.view.renderPromise)
1522
1524
  await this.view.renderPromise;
1523
1525
  if (isSuccessful(statusCode) && responseHTML != null) {
1524
- await this.view.renderPage(PageSnapshot.fromHTMLString(responseHTML));
1526
+ await this.view.renderPage(PageSnapshot.fromHTMLString(responseHTML), false, this.willRender);
1525
1527
  this.adapter.visitRendered(this);
1526
1528
  this.complete();
1527
1529
  }
@@ -1561,7 +1563,7 @@ class Visit {
1561
1563
  else {
1562
1564
  if (this.view.renderPromise)
1563
1565
  await this.view.renderPromise;
1564
- await this.view.renderPage(snapshot, isPreview);
1566
+ await this.view.renderPage(snapshot, isPreview, this.willRender);
1565
1567
  this.adapter.visitRendered(this);
1566
1568
  if (!isPreview) {
1567
1569
  this.complete();
@@ -1672,15 +1674,13 @@ class Visit {
1672
1674
  return !this.hasCachedSnapshot();
1673
1675
  }
1674
1676
  else {
1675
- return true;
1677
+ return this.willRender;
1676
1678
  }
1677
1679
  }
1678
1680
  cacheSnapshot() {
1679
1681
  if (!this.snapshotCached) {
1680
- this.view.cacheSnapshot();
1682
+ this.view.cacheSnapshot().then(snapshot => snapshot && this.visitCachedSnapshot(snapshot));
1681
1683
  this.snapshotCached = true;
1682
- if (this.optionalDelegate.visitCachedSnapshot)
1683
- this.optionalDelegate.visitCachedSnapshot(this);
1684
1684
  }
1685
1685
  }
1686
1686
  async render(callback) {
@@ -2134,9 +2134,6 @@ class Navigator {
2134
2134
  visitCompleted(visit) {
2135
2135
  this.delegate.visitCompleted(visit);
2136
2136
  }
2137
- visitCachedSnapshot(visit) {
2138
- this.delegate.visitCachedSnapshot(visit);
2139
- }
2140
2137
  locationWithActionIsSamePage(location, action) {
2141
2138
  const anchor = getAnchor(location);
2142
2139
  const currentAnchor = getAnchor(this.view.lastRenderedLocation);
@@ -2350,7 +2347,9 @@ class PageRenderer extends Renderer {
2350
2347
  this.mergeHead();
2351
2348
  }
2352
2349
  async render() {
2353
- this.replaceBody();
2350
+ if (this.willRender) {
2351
+ this.replaceBody();
2352
+ }
2354
2353
  }
2355
2354
  finishRendering() {
2356
2355
  super.finishRendering();
@@ -2488,8 +2487,8 @@ class PageView extends View {
2488
2487
  this.snapshotCache = new SnapshotCache(10);
2489
2488
  this.lastRenderedLocation = new URL(location.href);
2490
2489
  }
2491
- renderPage(snapshot, isPreview = false) {
2492
- const renderer = new PageRenderer(this.snapshot, snapshot, isPreview);
2490
+ renderPage(snapshot, isPreview = false, willRender = true) {
2491
+ const renderer = new PageRenderer(this.snapshot, snapshot, isPreview, willRender);
2493
2492
  return this.render(renderer);
2494
2493
  }
2495
2494
  renderError(snapshot) {
@@ -2504,7 +2503,9 @@ class PageView extends View {
2504
2503
  this.delegate.viewWillCacheSnapshot();
2505
2504
  const { snapshot, lastRenderedLocation: location } = this;
2506
2505
  await nextEventLoopTick();
2507
- this.snapshotCache.put(location, snapshot.clone());
2506
+ const cachedSnapshot = snapshot.clone();
2507
+ this.snapshotCache.put(location, cachedSnapshot);
2508
+ return cachedSnapshot;
2508
2509
  }
2509
2510
  }
2510
2511
  getCachedSnapshotForLocation(location) {
@@ -2654,8 +2655,6 @@ class Session {
2654
2655
  visitCompleted(visit) {
2655
2656
  this.notifyApplicationAfterPageLoad(visit.getTimingMetrics());
2656
2657
  }
2657
- visitCachedSnapshot(visit) {
2658
- }
2659
2658
  locationWithActionIsSamePage(location, action) {
2660
2659
  return this.navigator.locationWithActionIsSamePage(location, action);
2661
2660
  }
@@ -2846,6 +2845,7 @@ var Turbo = /*#__PURE__*/Object.freeze({
2846
2845
 
2847
2846
  class FrameController {
2848
2847
  constructor(element) {
2848
+ this.fetchResponseLoaded = (fetchResponse) => { };
2849
2849
  this.currentFetchRequest = null;
2850
2850
  this.resolveVisitPromise = () => { };
2851
2851
  this.connected = false;
@@ -2915,7 +2915,7 @@ class FrameController {
2915
2915
  }
2916
2916
  }
2917
2917
  async loadResponse(fetchResponse) {
2918
- if (fetchResponse.redirected) {
2918
+ if (fetchResponse.redirected || (fetchResponse.succeeded && fetchResponse.isHTML)) {
2919
2919
  this.sourceURL = fetchResponse.response.url;
2920
2920
  }
2921
2921
  try {
@@ -2923,18 +2923,22 @@ class FrameController {
2923
2923
  if (html) {
2924
2924
  const { body } = parseHTMLDocument(html);
2925
2925
  const snapshot = new Snapshot(await this.extractForeignFrameElement(body));
2926
- const renderer = new FrameRenderer(this.view.snapshot, snapshot, false);
2926
+ const renderer = new FrameRenderer(this.view.snapshot, snapshot, false, false);
2927
2927
  if (this.view.renderPromise)
2928
2928
  await this.view.renderPromise;
2929
2929
  await this.view.render(renderer);
2930
2930
  session.frameRendered(fetchResponse, this.element);
2931
2931
  session.frameLoaded(this.element);
2932
+ this.fetchResponseLoaded(fetchResponse);
2932
2933
  }
2933
2934
  }
2934
2935
  catch (error) {
2935
2936
  console.error(error);
2936
2937
  this.view.invalidate();
2937
2938
  }
2939
+ finally {
2940
+ this.fetchResponseLoaded = () => { };
2941
+ }
2938
2942
  }
2939
2943
  elementAppearedInViewport(element) {
2940
2944
  this.loadSourceURL();
@@ -3035,17 +3039,15 @@ class FrameController {
3035
3039
  proposeVisitIfNavigatedWithAction(frame, element, submitter) {
3036
3040
  const action = getAttribute("data-turbo-action", submitter, element, frame);
3037
3041
  if (isAction(action)) {
3038
- const delegate = new SnapshotSubstitution(frame);
3039
- const proposeVisit = (event) => {
3040
- const { target, detail: { fetchResponse } } = event;
3041
- if (target instanceof FrameElement && target.src) {
3042
+ const { visitCachedSnapshot } = new SnapshotSubstitution(frame);
3043
+ frame.delegate.fetchResponseLoaded = (fetchResponse) => {
3044
+ if (frame.src) {
3042
3045
  const { statusCode, redirected } = fetchResponse;
3043
- const responseHTML = target.ownerDocument.documentElement.outerHTML;
3046
+ const responseHTML = frame.ownerDocument.documentElement.outerHTML;
3044
3047
  const response = { statusCode, redirected, responseHTML };
3045
- session.visit(target.src, { action, response, delegate });
3048
+ session.visit(frame.src, { action, response, visitCachedSnapshot, willRender: false });
3046
3049
  }
3047
3050
  };
3048
- frame.addEventListener("turbo:frame-render", proposeVisit, { once: true });
3049
3051
  }
3050
3052
  }
3051
3053
  findFrameElement(element, submitter) {
@@ -3145,19 +3147,14 @@ class FrameController {
3145
3147
  }
3146
3148
  class SnapshotSubstitution {
3147
3149
  constructor(element) {
3150
+ this.visitCachedSnapshot = ({ element }) => {
3151
+ var _a;
3152
+ const { id, clone } = this;
3153
+ (_a = element.querySelector("#" + id)) === null || _a === void 0 ? void 0 : _a.replaceWith(clone);
3154
+ };
3148
3155
  this.clone = element.cloneNode(true);
3149
3156
  this.id = element.id;
3150
3157
  }
3151
- visitStarted(visit) {
3152
- this.snapshot = visit.view.snapshot;
3153
- }
3154
- visitCachedSnapshot() {
3155
- var _a;
3156
- const { snapshot, id, clone } = this;
3157
- if (snapshot) {
3158
- (_a = snapshot.element.querySelector("#" + id)) === null || _a === void 0 ? void 0 : _a.replaceWith(clone);
3159
- }
3160
- }
3161
3158
  }
3162
3159
  function getFrameElementById(id) {
3163
3160
  if (id != null) {
@@ -3178,6 +3175,7 @@ function activateElement(element, currentURL) {
3178
3175
  }
3179
3176
  if (element instanceof FrameElement) {
3180
3177
  element.connectedCallback();
3178
+ element.disconnectedCallback();
3181
3179
  return element;
3182
3180
  }
3183
3181
  }
@@ -1,5 +1,5 @@
1
1
  /*
2
- Turbo 7.0.1
2
+ Turbo 7.1.0-rc.1
3
3
  Copyright © 2021 Basecamp, LLC
4
4
  */
5
5
  (function (global, factory) {
@@ -1016,10 +1016,11 @@ Copyright © 2021 Basecamp, LLC
1016
1016
  }
1017
1017
 
1018
1018
  class Renderer {
1019
- constructor(currentSnapshot, newSnapshot, isPreview) {
1019
+ constructor(currentSnapshot, newSnapshot, isPreview, willRender = true) {
1020
1020
  this.currentSnapshot = currentSnapshot;
1021
1021
  this.newSnapshot = newSnapshot;
1022
1022
  this.isPreview = isPreview;
1023
+ this.willRender = willRender;
1023
1024
  this.promise = new Promise((resolve, reject) => this.resolvingFunctions = { resolve, reject });
1024
1025
  }
1025
1026
  get shouldRender() {
@@ -1395,8 +1396,9 @@ Copyright © 2021 Basecamp, LLC
1395
1396
  })(VisitState || (VisitState = {}));
1396
1397
  const defaultOptions = {
1397
1398
  action: "advance",
1398
- delegate: {},
1399
1399
  historyChanged: false,
1400
+ visitCachedSnapshot: () => { },
1401
+ willRender: true,
1400
1402
  };
1401
1403
  var SystemStatusCode;
1402
1404
  (function (SystemStatusCode) {
@@ -1416,14 +1418,16 @@ Copyright © 2021 Basecamp, LLC
1416
1418
  this.delegate = delegate;
1417
1419
  this.location = location;
1418
1420
  this.restorationIdentifier = restorationIdentifier || uuid();
1419
- const { action, historyChanged, referrer, snapshotHTML, response, delegate: optionalDelegate } = Object.assign(Object.assign({}, defaultOptions), options);
1421
+ const { action, historyChanged, referrer, snapshotHTML, response, visitCachedSnapshot, willRender } = Object.assign(Object.assign({}, defaultOptions), options);
1420
1422
  this.action = action;
1421
1423
  this.historyChanged = historyChanged;
1422
1424
  this.referrer = referrer;
1423
1425
  this.snapshotHTML = snapshotHTML;
1424
1426
  this.response = response;
1425
1427
  this.isSamePage = this.delegate.locationWithActionIsSamePage(this.location, this.action);
1426
- this.optionalDelegate = optionalDelegate;
1428
+ this.visitCachedSnapshot = visitCachedSnapshot;
1429
+ this.willRender = willRender;
1430
+ this.scrolled = !willRender;
1427
1431
  }
1428
1432
  get adapter() {
1429
1433
  return this.delegate.adapter;
@@ -1446,8 +1450,6 @@ Copyright © 2021 Basecamp, LLC
1446
1450
  this.state = VisitState.started;
1447
1451
  this.adapter.visitStarted(this);
1448
1452
  this.delegate.visitStarted(this);
1449
- if (this.optionalDelegate.visitStarted)
1450
- this.optionalDelegate.visitStarted(this);
1451
1453
  }
1452
1454
  }
1453
1455
  cancel() {
@@ -1527,7 +1529,7 @@ Copyright © 2021 Basecamp, LLC
1527
1529
  if (this.view.renderPromise)
1528
1530
  await this.view.renderPromise;
1529
1531
  if (isSuccessful(statusCode) && responseHTML != null) {
1530
- await this.view.renderPage(PageSnapshot.fromHTMLString(responseHTML));
1532
+ await this.view.renderPage(PageSnapshot.fromHTMLString(responseHTML), false, this.willRender);
1531
1533
  this.adapter.visitRendered(this);
1532
1534
  this.complete();
1533
1535
  }
@@ -1567,7 +1569,7 @@ Copyright © 2021 Basecamp, LLC
1567
1569
  else {
1568
1570
  if (this.view.renderPromise)
1569
1571
  await this.view.renderPromise;
1570
- await this.view.renderPage(snapshot, isPreview);
1572
+ await this.view.renderPage(snapshot, isPreview, this.willRender);
1571
1573
  this.adapter.visitRendered(this);
1572
1574
  if (!isPreview) {
1573
1575
  this.complete();
@@ -1678,15 +1680,13 @@ Copyright © 2021 Basecamp, LLC
1678
1680
  return !this.hasCachedSnapshot();
1679
1681
  }
1680
1682
  else {
1681
- return true;
1683
+ return this.willRender;
1682
1684
  }
1683
1685
  }
1684
1686
  cacheSnapshot() {
1685
1687
  if (!this.snapshotCached) {
1686
- this.view.cacheSnapshot();
1688
+ this.view.cacheSnapshot().then(snapshot => snapshot && this.visitCachedSnapshot(snapshot));
1687
1689
  this.snapshotCached = true;
1688
- if (this.optionalDelegate.visitCachedSnapshot)
1689
- this.optionalDelegate.visitCachedSnapshot(this);
1690
1690
  }
1691
1691
  }
1692
1692
  async render(callback) {
@@ -2140,9 +2140,6 @@ Copyright © 2021 Basecamp, LLC
2140
2140
  visitCompleted(visit) {
2141
2141
  this.delegate.visitCompleted(visit);
2142
2142
  }
2143
- visitCachedSnapshot(visit) {
2144
- this.delegate.visitCachedSnapshot(visit);
2145
- }
2146
2143
  locationWithActionIsSamePage(location, action) {
2147
2144
  const anchor = getAnchor(location);
2148
2145
  const currentAnchor = getAnchor(this.view.lastRenderedLocation);
@@ -2356,7 +2353,9 @@ Copyright © 2021 Basecamp, LLC
2356
2353
  this.mergeHead();
2357
2354
  }
2358
2355
  async render() {
2359
- this.replaceBody();
2356
+ if (this.willRender) {
2357
+ this.replaceBody();
2358
+ }
2360
2359
  }
2361
2360
  finishRendering() {
2362
2361
  super.finishRendering();
@@ -2494,8 +2493,8 @@ Copyright © 2021 Basecamp, LLC
2494
2493
  this.snapshotCache = new SnapshotCache(10);
2495
2494
  this.lastRenderedLocation = new URL(location.href);
2496
2495
  }
2497
- renderPage(snapshot, isPreview = false) {
2498
- const renderer = new PageRenderer(this.snapshot, snapshot, isPreview);
2496
+ renderPage(snapshot, isPreview = false, willRender = true) {
2497
+ const renderer = new PageRenderer(this.snapshot, snapshot, isPreview, willRender);
2499
2498
  return this.render(renderer);
2500
2499
  }
2501
2500
  renderError(snapshot) {
@@ -2510,7 +2509,9 @@ Copyright © 2021 Basecamp, LLC
2510
2509
  this.delegate.viewWillCacheSnapshot();
2511
2510
  const { snapshot, lastRenderedLocation: location } = this;
2512
2511
  await nextEventLoopTick();
2513
- this.snapshotCache.put(location, snapshot.clone());
2512
+ const cachedSnapshot = snapshot.clone();
2513
+ this.snapshotCache.put(location, cachedSnapshot);
2514
+ return cachedSnapshot;
2514
2515
  }
2515
2516
  }
2516
2517
  getCachedSnapshotForLocation(location) {
@@ -2660,8 +2661,6 @@ Copyright © 2021 Basecamp, LLC
2660
2661
  visitCompleted(visit) {
2661
2662
  this.notifyApplicationAfterPageLoad(visit.getTimingMetrics());
2662
2663
  }
2663
- visitCachedSnapshot(visit) {
2664
- }
2665
2664
  locationWithActionIsSamePage(location, action) {
2666
2665
  return this.navigator.locationWithActionIsSamePage(location, action);
2667
2666
  }
@@ -2852,6 +2851,7 @@ Copyright © 2021 Basecamp, LLC
2852
2851
 
2853
2852
  class FrameController {
2854
2853
  constructor(element) {
2854
+ this.fetchResponseLoaded = (fetchResponse) => { };
2855
2855
  this.currentFetchRequest = null;
2856
2856
  this.resolveVisitPromise = () => { };
2857
2857
  this.connected = false;
@@ -2921,7 +2921,7 @@ Copyright © 2021 Basecamp, LLC
2921
2921
  }
2922
2922
  }
2923
2923
  async loadResponse(fetchResponse) {
2924
- if (fetchResponse.redirected) {
2924
+ if (fetchResponse.redirected || (fetchResponse.succeeded && fetchResponse.isHTML)) {
2925
2925
  this.sourceURL = fetchResponse.response.url;
2926
2926
  }
2927
2927
  try {
@@ -2929,18 +2929,22 @@ Copyright © 2021 Basecamp, LLC
2929
2929
  if (html) {
2930
2930
  const { body } = parseHTMLDocument(html);
2931
2931
  const snapshot = new Snapshot(await this.extractForeignFrameElement(body));
2932
- const renderer = new FrameRenderer(this.view.snapshot, snapshot, false);
2932
+ const renderer = new FrameRenderer(this.view.snapshot, snapshot, false, false);
2933
2933
  if (this.view.renderPromise)
2934
2934
  await this.view.renderPromise;
2935
2935
  await this.view.render(renderer);
2936
2936
  session.frameRendered(fetchResponse, this.element);
2937
2937
  session.frameLoaded(this.element);
2938
+ this.fetchResponseLoaded(fetchResponse);
2938
2939
  }
2939
2940
  }
2940
2941
  catch (error) {
2941
2942
  console.error(error);
2942
2943
  this.view.invalidate();
2943
2944
  }
2945
+ finally {
2946
+ this.fetchResponseLoaded = () => { };
2947
+ }
2944
2948
  }
2945
2949
  elementAppearedInViewport(element) {
2946
2950
  this.loadSourceURL();
@@ -3041,17 +3045,15 @@ Copyright © 2021 Basecamp, LLC
3041
3045
  proposeVisitIfNavigatedWithAction(frame, element, submitter) {
3042
3046
  const action = getAttribute("data-turbo-action", submitter, element, frame);
3043
3047
  if (isAction(action)) {
3044
- const delegate = new SnapshotSubstitution(frame);
3045
- const proposeVisit = (event) => {
3046
- const { target, detail: { fetchResponse } } = event;
3047
- if (target instanceof FrameElement && target.src) {
3048
+ const { visitCachedSnapshot } = new SnapshotSubstitution(frame);
3049
+ frame.delegate.fetchResponseLoaded = (fetchResponse) => {
3050
+ if (frame.src) {
3048
3051
  const { statusCode, redirected } = fetchResponse;
3049
- const responseHTML = target.ownerDocument.documentElement.outerHTML;
3052
+ const responseHTML = frame.ownerDocument.documentElement.outerHTML;
3050
3053
  const response = { statusCode, redirected, responseHTML };
3051
- session.visit(target.src, { action, response, delegate });
3054
+ session.visit(frame.src, { action, response, visitCachedSnapshot, willRender: false });
3052
3055
  }
3053
3056
  };
3054
- frame.addEventListener("turbo:frame-render", proposeVisit, { once: true });
3055
3057
  }
3056
3058
  }
3057
3059
  findFrameElement(element, submitter) {
@@ -3151,19 +3153,14 @@ Copyright © 2021 Basecamp, LLC
3151
3153
  }
3152
3154
  class SnapshotSubstitution {
3153
3155
  constructor(element) {
3156
+ this.visitCachedSnapshot = ({ element }) => {
3157
+ var _a;
3158
+ const { id, clone } = this;
3159
+ (_a = element.querySelector("#" + id)) === null || _a === void 0 ? void 0 : _a.replaceWith(clone);
3160
+ };
3154
3161
  this.clone = element.cloneNode(true);
3155
3162
  this.id = element.id;
3156
3163
  }
3157
- visitStarted(visit) {
3158
- this.snapshot = visit.view.snapshot;
3159
- }
3160
- visitCachedSnapshot() {
3161
- var _a;
3162
- const { snapshot, id, clone } = this;
3163
- if (snapshot) {
3164
- (_a = snapshot.element.querySelector("#" + id)) === null || _a === void 0 ? void 0 : _a.replaceWith(clone);
3165
- }
3166
- }
3167
3164
  }
3168
3165
  function getFrameElementById(id) {
3169
3166
  if (id != null) {
@@ -3184,6 +3181,7 @@ Copyright © 2021 Basecamp, LLC
3184
3181
  }
3185
3182
  if (element instanceof FrameElement) {
3186
3183
  element.connectedCallback();
3184
+ element.disconnectedCallback();
3187
3185
  return element;
3188
3186
  }
3189
3187
  }
@@ -27,7 +27,6 @@ export declare class Navigator {
27
27
  formSubmissionFinished(formSubmission: FormSubmission): void;
28
28
  visitStarted(visit: Visit): void;
29
29
  visitCompleted(visit: Visit): void;
30
- visitCachedSnapshot(visit: Visit): void;
31
30
  locationWithActionIsSamePage(location: URL, action?: Action): boolean;
32
31
  visitScrolledToSamePageLocation(oldURL: URL, newURL: URL): void;
33
32
  get location(): URL;
@@ -10,10 +10,10 @@ declare type PageViewRenderer = PageRenderer | ErrorRenderer;
10
10
  export declare class PageView extends View<Element, PageSnapshot, PageViewRenderer, PageViewDelegate> {
11
11
  readonly snapshotCache: SnapshotCache;
12
12
  lastRenderedLocation: URL;
13
- renderPage(snapshot: PageSnapshot, isPreview?: boolean): Promise<void>;
13
+ renderPage(snapshot: PageSnapshot, isPreview?: boolean, willRender?: boolean): Promise<void>;
14
14
  renderError(snapshot: PageSnapshot): Promise<void>;
15
15
  clearSnapshotCache(): void;
16
- cacheSnapshot(): Promise<void>;
16
+ cacheSnapshot(): Promise<PageSnapshot | undefined>;
17
17
  getCachedSnapshotForLocation(location: URL): PageSnapshot | undefined;
18
18
  get snapshot(): PageSnapshot;
19
19
  get shouldCacheSnapshot(): boolean;
@@ -2,6 +2,7 @@ import { Adapter } from "../native/adapter";
2
2
  import { FetchRequest, FetchRequestDelegate } from "../../http/fetch_request";
3
3
  import { FetchResponse } from "../../http/fetch_response";
4
4
  import { History } from "./history";
5
+ import { Snapshot } from "../snapshot";
5
6
  import { PageSnapshot } from "./page_snapshot";
6
7
  import { Action } from "../types";
7
8
  import { PageView } from "./page_view";
@@ -11,7 +12,6 @@ export interface VisitDelegate {
11
12
  readonly view: PageView;
12
13
  visitStarted(visit: Visit): void;
13
14
  visitCompleted(visit: Visit): void;
14
- visitCachedSnapshot(visit: Visit): void;
15
15
  locationWithActionIsSamePage(location: URL, action: Action): boolean;
16
16
  visitScrolledToSamePageLocation(oldURL: URL, newURL: URL): void;
17
17
  }
@@ -33,11 +33,12 @@ export declare enum VisitState {
33
33
  }
34
34
  export declare type VisitOptions = {
35
35
  action: Action;
36
- delegate: Partial<VisitDelegate>;
37
36
  historyChanged: boolean;
38
37
  referrer?: URL;
39
38
  snapshotHTML?: string;
40
39
  response?: VisitResponse;
40
+ visitCachedSnapshot(snapshot: Snapshot): void;
41
+ willRender: boolean;
41
42
  };
42
43
  export declare type VisitResponse = {
43
44
  statusCode: number;
@@ -56,7 +57,8 @@ export declare class Visit implements FetchRequestDelegate {
56
57
  readonly action: Action;
57
58
  readonly referrer?: URL;
58
59
  readonly timingMetrics: TimingMetrics;
59
- readonly optionalDelegate: Partial<VisitDelegate>;
60
+ readonly visitCachedSnapshot: (snapshot: Snapshot) => void;
61
+ readonly willRender: boolean;
60
62
  followedRedirect: boolean;
61
63
  frame?: number;
62
64
  historyChanged: boolean;
@@ -16,6 +16,7 @@ export declare class FrameController implements AppearanceObserverDelegate, Fetc
16
16
  readonly formInterceptor: FormInterceptor;
17
17
  currentURL?: string | null;
18
18
  formSubmission?: FormSubmission;
19
+ fetchResponseLoaded: (fetchResponse: FetchResponse) => void;
19
20
  private currentFetchRequest;
20
21
  private resolveVisitPromise;
21
22
  private connected;
@@ -3,9 +3,10 @@ export declare abstract class Renderer<E extends Element, S extends Snapshot<E>
3
3
  readonly currentSnapshot: S;
4
4
  readonly newSnapshot: S;
5
5
  readonly isPreview: boolean;
6
+ readonly willRender: boolean;
6
7
  readonly promise: Promise<void>;
7
8
  private resolvingFunctions?;
8
- constructor(currentSnapshot: S, newSnapshot: S, isPreview: boolean);
9
+ constructor(currentSnapshot: S, newSnapshot: S, isPreview: boolean, willRender?: boolean);
9
10
  get shouldRender(): boolean;
10
11
  prepareToRender(): void;
11
12
  abstract render(): Promise<void>;
@@ -54,7 +54,6 @@ export declare class Session implements FormSubmitObserverDelegate, HistoryDeleg
54
54
  visitProposedToLocation(location: URL, options: Partial<VisitOptions>): void;
55
55
  visitStarted(visit: Visit): void;
56
56
  visitCompleted(visit: Visit): void;
57
- visitCachedSnapshot(visit: Visit): void;
58
57
  locationWithActionIsSamePage(location: URL, action?: Action): boolean;
59
58
  visitScrolledToSamePageLocation(oldURL: URL, newURL: URL): void;
60
59
  willSubmitForm(form: HTMLFormElement, submitter?: HTMLElement): boolean;
@@ -12,6 +12,7 @@ export interface FrameElementDelegate {
12
12
  formSubmissionIntercepted(element: HTMLFormElement, submitter?: HTMLElement): void;
13
13
  linkClickIntercepted(element: Element, url: string): void;
14
14
  loadResponse(response: FetchResponse): void;
15
+ fetchResponseLoaded: (fetchResponse: FetchResponse) => void;
15
16
  isLoading: boolean;
16
17
  }
17
18
  export declare class FrameElement extends HTMLElement {
@@ -1,6 +1,7 @@
1
1
  import { TurboDriveTestCase } from "../helpers/turbo_drive_test_case";
2
2
  export declare class FrameTests extends TurboDriveTestCase {
3
3
  setup(): Promise<void>;
4
+ "test navigating a frame a second time does not leak event listeners"(): Promise<void>;
4
5
  "test following a link preserves the current <turbo-frame> element's attributes"(): Promise<void>;
5
6
  "test a frame whose src references itself does not infinitely loop"(): Promise<void>;
6
7
  "test following a link driving a frame toggles the [aria-busy=true] attribute"(): Promise<void>;
@@ -28,16 +29,24 @@ export declare class FrameTests extends TurboDriveTestCase {
28
29
  "test an inner/outer form reloads frame on every submit"(): Promise<void>;
29
30
  "test reconnecting after following a link does not reload the frame"(): Promise<void>;
30
31
  "test navigating pushing URL state from a frame navigation fires events"(): Promise<void>;
32
+ "test navigating a frame with a form[method=get] that does not redirect still updates the [src]"(): Promise<void>;
31
33
  "test navigating turbo-frame[data-turbo-action=advance] from within pushes URL state"(): Promise<void>;
34
+ "test navigating turbo-frame[data-turbo-action=advance] to the same URL clears the [aria-busy] and [data-turbo-preview] state"(): Promise<void>;
35
+ "test navigating a turbo-frame with an a[data-turbo-action=advance] preserves page state"(): Promise<void>;
36
+ "test a turbo-frame that has been driven by a[data-turbo-action] can be navigated normally"(): Promise<void>;
32
37
  "test navigating turbo-frame from within with a[data-turbo-action=advance] pushes URL state"(): Promise<void>;
33
38
  "test navigating frame with a[data-turbo-action=advance] pushes URL state"(): Promise<void>;
34
39
  "test navigating frame with form[method=get][data-turbo-action=advance] pushes URL state"(): Promise<void>;
40
+ "test navigating frame with form[method=get][data-turbo-action=advance] to the same URL clears the [aria-busy] and [data-turbo-preview] state"(): Promise<void>;
35
41
  "test navigating frame with form[method=post][data-turbo-action=advance] pushes URL state"(): Promise<void>;
42
+ "test navigating frame with form[method=post][data-turbo-action=advance] to the same URL clears the [aria-busy] and [data-turbo-preview] state"(): Promise<void>;
36
43
  "test navigating frame with button[data-turbo-action=advance] pushes URL state"(): Promise<void>;
37
44
  "test navigating back after pushing URL state from a turbo-frame[data-turbo-action=advance] restores the frames previous contents"(): Promise<void>;
38
45
  "test navigating back then forward after pushing URL state from a turbo-frame[data-turbo-action=advance] restores the frames next contents"(): Promise<void>;
39
46
  "test turbo:before-fetch-request fires on the frame element"(): Promise<void>;
40
47
  "test turbo:before-fetch-response fires on the frame element"(): Promise<void>;
48
+ withoutChangingEventListenersCount(callback: () => void): Promise<void>;
49
+ fillInSelector(selector: string, value: string): Promise<void>;
41
50
  get frameScriptEvaluationCount(): Promise<number | undefined>;
42
51
  }
43
52
  declare global {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hotwired/turbo",
3
- "version": "7.1.0-rc.1",
3
+ "version": "7.1.0-rc.2",
4
4
  "description": "The speed of a single-page web application without having to write any JavaScript",
5
5
  "module": "dist/turbo.es2017-esm.js",
6
6
  "main": "dist/turbo.es2017-umd.js",