@hotwired/turbo 7.0.0-rc.1 → 7.0.0-rc.3

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 (29) hide show
  1. package/dist/turbo.es2017-esm.js +185 -96
  2. package/dist/turbo.es2017-umd.js +185 -95
  3. package/dist/types/core/drive/form_submission.d.ts +1 -1
  4. package/dist/types/core/drive/navigator.d.ts +2 -2
  5. package/dist/types/core/drive/visit.d.ts +1 -1
  6. package/dist/types/core/frames/frame_controller.d.ts +2 -0
  7. package/dist/types/core/index.d.ts +3 -1
  8. package/dist/types/core/native/adapter.d.ts +3 -0
  9. package/dist/types/core/native/browser_adapter.d.ts +9 -3
  10. package/dist/types/core/session.d.ts +10 -3
  11. package/dist/types/core/view.d.ts +1 -0
  12. package/dist/types/http/fetch_request.d.ts +2 -1
  13. package/dist/types/tests/functional/drive_disabled_tests.d.ts +7 -0
  14. package/dist/types/tests/functional/drive_tests.d.ts +7 -0
  15. package/dist/types/tests/functional/form_submission_tests.d.ts +6 -0
  16. package/dist/types/tests/functional/frame_navigation_tests.d.ts +6 -0
  17. package/dist/types/tests/functional/frame_tests.d.ts +4 -0
  18. package/dist/types/tests/functional/index.d.ts +3 -0
  19. package/dist/types/tests/functional/navigation_tests.d.ts +9 -0
  20. package/dist/types/tests/helpers/functional_test_case.d.ts +3 -0
  21. package/dist/types/tests/helpers/turbo_drive_test_case.d.ts +2 -1
  22. package/dist/types/tests/unit/deprecated_adapter_support_test.d.ts +3 -0
  23. package/package.json +2 -2
  24. package/CHANGELOG.md +0 -3
  25. package/dist/turbo.es2017-esm.js.map +0 -1
  26. package/dist/turbo.es2017-umd.js.map +0 -1
  27. package/dist/turbo.es5-umd.js +0 -4121
  28. package/dist/turbo.es5-umd.js.map +0 -1
  29. package/dist/types/core/request_interceptor.d.ts +0 -6
@@ -1,5 +1,5 @@
1
1
  /*
2
- Turbo 7.0.0-rc.1
2
+ Turbo 7.0.0-rc.2
3
3
  Copyright © 2021 Basecamp, LLC
4
4
  */
5
5
  (function () {
@@ -338,8 +338,10 @@ class FetchRequest {
338
338
  return await this.receive(response);
339
339
  }
340
340
  catch (error) {
341
- this.delegate.requestErrored(this, error);
342
- throw error;
341
+ if (error.name !== 'AbortError') {
342
+ this.delegate.requestErrored(this, error);
343
+ throw error;
344
+ }
343
345
  }
344
346
  finally {
345
347
  this.delegate.requestFinished(this);
@@ -360,13 +362,15 @@ class FetchRequest {
360
362
  return fetchResponse;
361
363
  }
362
364
  get fetchOptions() {
365
+ var _a;
363
366
  return {
364
367
  method: FetchMethod[this.method].toUpperCase(),
365
368
  credentials: "same-origin",
366
369
  headers: this.headers,
367
370
  redirect: "follow",
368
371
  body: this.body,
369
- signal: this.abortSignal
372
+ signal: this.abortSignal,
373
+ referrer: (_a = this.delegate.referrer) === null || _a === void 0 ? void 0 : _a.href
370
374
  };
371
375
  }
372
376
  get defaultHeaders() {
@@ -505,7 +509,8 @@ class FormSubmission {
505
509
  }
506
510
  get action() {
507
511
  var _a;
508
- return ((_a = this.submitter) === null || _a === void 0 ? void 0 : _a.getAttribute("formaction")) || this.formElement.action;
512
+ const formElementAction = typeof this.formElement.action === 'string' ? this.formElement.action : null;
513
+ return ((_a = this.submitter) === null || _a === void 0 ? void 0 : _a.getAttribute("formaction")) || this.formElement.getAttribute("action") || formElementAction || "";
509
514
  }
510
515
  get location() {
511
516
  return expandURL(this.action);
@@ -631,12 +636,7 @@ class Snapshot {
631
636
  return this.getElementForAnchor(anchor) != null;
632
637
  }
633
638
  getElementForAnchor(anchor) {
634
- try {
635
- return this.element.querySelector(`[id='${anchor}'], a[name='${anchor}']`);
636
- }
637
- catch (_a) {
638
- return null;
639
- }
639
+ return anchor ? this.element.querySelector(`[id='${anchor}'], a[name='${anchor}']`) : null;
640
640
  }
641
641
  get isConnected() {
642
642
  return this.element.isConnected;
@@ -725,6 +725,9 @@ class View {
725
725
  scrollToPosition({ x, y }) {
726
726
  this.scrollRoot.scrollTo(x, y);
727
727
  }
728
+ scrollToTop() {
729
+ this.scrollToPosition({ x: 0, y: 0 });
730
+ }
728
731
  get scrollRoot() {
729
732
  return window;
730
733
  }
@@ -1293,6 +1296,9 @@ class Visit {
1293
1296
  get restorationData() {
1294
1297
  return this.history.getRestorationDataForIdentifier(this.restorationIdentifier);
1295
1298
  }
1299
+ get silent() {
1300
+ return this.isSamePage;
1301
+ }
1296
1302
  start() {
1297
1303
  if (this.state == VisitState.initialized) {
1298
1304
  this.recordTimingMetric(TimingMetric.visitStart);
@@ -1316,6 +1322,7 @@ class Visit {
1316
1322
  this.state = VisitState.completed;
1317
1323
  this.adapter.visitCompleted(this);
1318
1324
  this.delegate.visitCompleted(this);
1325
+ this.followRedirect();
1319
1326
  }
1320
1327
  }
1321
1328
  fail() {
@@ -1428,8 +1435,10 @@ class Visit {
1428
1435
  }
1429
1436
  followRedirect() {
1430
1437
  if (this.redirectedToLocation && !this.followedRedirect) {
1431
- this.location = this.redirectedToLocation;
1432
- this.history.replace(this.redirectedToLocation, this.restorationIdentifier);
1438
+ this.adapter.visitProposedToLocation(this.redirectedToLocation, {
1439
+ action: 'replace',
1440
+ response: this.response
1441
+ });
1433
1442
  this.followedRedirect = true;
1434
1443
  }
1435
1444
  }
@@ -1474,10 +1483,10 @@ class Visit {
1474
1483
  performScroll() {
1475
1484
  if (!this.scrolled) {
1476
1485
  if (this.action == "restore") {
1477
- this.scrollToRestoredPosition() || this.scrollToAnchor() || this.scrollToTop();
1486
+ this.scrollToRestoredPosition() || this.scrollToAnchor() || this.view.scrollToTop();
1478
1487
  }
1479
1488
  else {
1480
- this.scrollToAnchor() || this.scrollToTop();
1489
+ this.scrollToAnchor() || this.view.scrollToTop();
1481
1490
  }
1482
1491
  if (this.isSamePage) {
1483
1492
  this.delegate.visitScrolledToSamePageLocation(this.view.lastRenderedLocation, this.location);
@@ -1499,9 +1508,6 @@ class Visit {
1499
1508
  return true;
1500
1509
  }
1501
1510
  }
1502
- scrollToTop() {
1503
- this.view.scrollToPosition({ x: 0, y: 0 });
1504
- }
1505
1511
  recordTimingMetric(metric) {
1506
1512
  this.timingMetrics[metric] = new Date().getTime();
1507
1513
  }
@@ -1575,7 +1581,7 @@ class BrowserAdapter {
1575
1581
  visitRequestStarted(visit) {
1576
1582
  this.progressBar.setValue(0);
1577
1583
  if (visit.hasCachedSnapshot() || visit.action != "restore") {
1578
- this.showProgressBarAfterDelay();
1584
+ this.showVisitProgressBarAfterDelay();
1579
1585
  }
1580
1586
  else {
1581
1587
  this.showProgressBar();
@@ -1596,10 +1602,9 @@ class BrowserAdapter {
1596
1602
  }
1597
1603
  visitRequestFinished(visit) {
1598
1604
  this.progressBar.setValue(1);
1599
- this.hideProgressBar();
1605
+ this.hideVisitProgressBar();
1600
1606
  }
1601
1607
  visitCompleted(visit) {
1602
- visit.followRedirect();
1603
1608
  }
1604
1609
  pageInvalidated() {
1605
1610
  this.reload();
@@ -1608,14 +1613,34 @@ class BrowserAdapter {
1608
1613
  }
1609
1614
  visitRendered(visit) {
1610
1615
  }
1611
- showProgressBarAfterDelay() {
1612
- this.progressBarTimeout = window.setTimeout(this.showProgressBar, this.session.progressBarDelay);
1616
+ formSubmissionStarted(formSubmission) {
1617
+ this.progressBar.setValue(0);
1618
+ this.showFormProgressBarAfterDelay();
1619
+ }
1620
+ formSubmissionFinished(formSubmission) {
1621
+ this.progressBar.setValue(1);
1622
+ this.hideFormProgressBar();
1623
+ }
1624
+ showVisitProgressBarAfterDelay() {
1625
+ this.visitProgressBarTimeout = window.setTimeout(this.showProgressBar, this.session.progressBarDelay);
1626
+ }
1627
+ hideVisitProgressBar() {
1628
+ this.progressBar.hide();
1629
+ if (this.visitProgressBarTimeout != null) {
1630
+ window.clearTimeout(this.visitProgressBarTimeout);
1631
+ delete this.visitProgressBarTimeout;
1632
+ }
1613
1633
  }
1614
- hideProgressBar() {
1634
+ showFormProgressBarAfterDelay() {
1635
+ if (this.formProgressBarTimeout == null) {
1636
+ this.formProgressBarTimeout = window.setTimeout(this.showProgressBar, this.session.progressBarDelay);
1637
+ }
1638
+ }
1639
+ hideFormProgressBar() {
1615
1640
  this.progressBar.hide();
1616
- if (this.progressBarTimeout != null) {
1617
- window.clearTimeout(this.progressBarTimeout);
1618
- delete this.progressBarTimeout;
1641
+ if (this.formProgressBarTimeout != null) {
1642
+ window.clearTimeout(this.formProgressBarTimeout);
1643
+ delete this.formProgressBarTimeout;
1619
1644
  }
1620
1645
  }
1621
1646
  reload() {
@@ -1706,6 +1731,7 @@ class FrameRedirector {
1706
1731
  linkClickIntercepted(element, url) {
1707
1732
  const frame = this.findFrameElement(element);
1708
1733
  if (frame) {
1734
+ frame.setAttribute("reloadable", "");
1709
1735
  frame.src = url;
1710
1736
  }
1711
1737
  }
@@ -1715,6 +1741,7 @@ class FrameRedirector {
1715
1741
  formSubmissionIntercepted(element, submitter) {
1716
1742
  const frame = this.findFrameElement(element);
1717
1743
  if (frame) {
1744
+ frame.removeAttribute("reloadable");
1718
1745
  frame.delegate.formSubmissionIntercepted(element, submitter);
1719
1746
  }
1720
1747
  }
@@ -1821,7 +1848,8 @@ class LinkClickObserver {
1821
1848
  };
1822
1849
  this.clickBubbled = (event) => {
1823
1850
  if (this.clickEventIsSignificant(event)) {
1824
- const link = this.findLinkFromClickTarget(event.target);
1851
+ const target = (event.composedPath && event.composedPath()[0]) || event.target;
1852
+ const link = this.findLinkFromClickTarget(target);
1825
1853
  if (link) {
1826
1854
  const location = this.getLocationForLink(link);
1827
1855
  if (this.delegate.willFollowLinkToLocation(link, location)) {
@@ -1873,7 +1901,7 @@ class Navigator {
1873
1901
  this.delegate = delegate;
1874
1902
  }
1875
1903
  proposeVisit(location, options = {}) {
1876
- if (this.delegate.allowsVisitingLocation(location)) {
1904
+ if (this.delegate.allowsVisitingLocationWithAction(location, options.action)) {
1877
1905
  this.delegate.visitProposedToLocation(location, options);
1878
1906
  }
1879
1907
  }
@@ -1912,6 +1940,9 @@ class Navigator {
1912
1940
  return this.delegate.history;
1913
1941
  }
1914
1942
  formSubmissionStarted(formSubmission) {
1943
+ if (typeof this.adapter.formSubmissionStarted === 'function') {
1944
+ this.adapter.formSubmissionStarted(formSubmission);
1945
+ }
1915
1946
  }
1916
1947
  async formSubmissionSucceededWithResponse(formSubmission, fetchResponse) {
1917
1948
  if (formSubmission == this.formSubmission) {
@@ -1930,7 +1961,13 @@ class Navigator {
1930
1961
  const responseHTML = await fetchResponse.responseHTML;
1931
1962
  if (responseHTML) {
1932
1963
  const snapshot = PageSnapshot.fromHTMLString(responseHTML);
1933
- await this.view.renderPage(snapshot);
1964
+ if (fetchResponse.serverError) {
1965
+ await this.view.renderError(snapshot);
1966
+ }
1967
+ else {
1968
+ await this.view.renderPage(snapshot);
1969
+ }
1970
+ this.view.scrollToTop();
1934
1971
  this.view.clearSnapshotCache();
1935
1972
  }
1936
1973
  }
@@ -1938,6 +1975,9 @@ class Navigator {
1938
1975
  console.error(error);
1939
1976
  }
1940
1977
  formSubmissionFinished(formSubmission) {
1978
+ if (typeof this.adapter.formSubmissionFinished === 'function') {
1979
+ this.adapter.formSubmissionFinished(formSubmission);
1980
+ }
1941
1981
  }
1942
1982
  visitStarted(visit) {
1943
1983
  this.delegate.visitStarted(visit);
@@ -1946,8 +1986,12 @@ class Navigator {
1946
1986
  this.delegate.visitCompleted(visit);
1947
1987
  }
1948
1988
  locationWithActionIsSamePage(location, action) {
1949
- return getRequestURL(location) === getRequestURL(this.view.lastRenderedLocation) &&
1950
- (getAnchor(location) != null || action == "restore");
1989
+ const anchor = getAnchor(location);
1990
+ const currentAnchor = getAnchor(this.view.lastRenderedLocation);
1991
+ const isRestorationToTop = action === 'restore' && typeof anchor === 'undefined';
1992
+ return action !== "replace" &&
1993
+ getRequestURL(location) === getRequestURL(this.view.lastRenderedLocation) &&
1994
+ (isRestorationToTop || (anchor != null && anchor !== currentAnchor));
1951
1995
  }
1952
1996
  visitScrolledToSamePageLocation(oldURL, newURL) {
1953
1997
  this.delegate.visitScrolledToSamePageLocation(oldURL, newURL);
@@ -2335,6 +2379,7 @@ class Session {
2335
2379
  this.scrollObserver = new ScrollObserver(this);
2336
2380
  this.streamObserver = new StreamObserver(this);
2337
2381
  this.frameRedirector = new FrameRedirector(document.documentElement);
2382
+ this.drive = true;
2338
2383
  this.enabled = true;
2339
2384
  this.progressBarDelay = 500;
2340
2385
  this.started = false;
@@ -2408,7 +2453,7 @@ class Session {
2408
2453
  this.history.updateRestorationData({ scrollPosition: position });
2409
2454
  }
2410
2455
  willFollowLinkToLocation(link, location) {
2411
- return elementIsNavigable(link)
2456
+ return this.elementDriveEnabled(link)
2412
2457
  && this.locationIsVisitable(location)
2413
2458
  && this.applicationAllowsFollowingLinkToLocation(link, location);
2414
2459
  }
@@ -2417,21 +2462,20 @@ class Session {
2417
2462
  this.convertLinkWithMethodClickToFormSubmission(link) || this.visit(location.href, { action });
2418
2463
  }
2419
2464
  convertLinkWithMethodClickToFormSubmission(link) {
2420
- var _a;
2421
2465
  const linkMethod = link.getAttribute("data-turbo-method");
2422
2466
  if (linkMethod) {
2423
2467
  const form = document.createElement("form");
2424
2468
  form.method = linkMethod;
2425
2469
  form.action = link.getAttribute("href") || "undefined";
2426
- (_a = link.parentNode) === null || _a === void 0 ? void 0 : _a.insertBefore(form, link);
2470
+ document.body.appendChild(form);
2427
2471
  return dispatch("submit", { cancelable: true, target: form });
2428
2472
  }
2429
2473
  else {
2430
2474
  return false;
2431
2475
  }
2432
2476
  }
2433
- allowsVisitingLocation(location) {
2434
- return this.applicationAllowsVisitingLocation(location);
2477
+ allowsVisitingLocationWithAction(location, action) {
2478
+ return this.locationWithActionIsSamePage(location, action) || this.applicationAllowsVisitingLocation(location);
2435
2479
  }
2436
2480
  visitProposedToLocation(location, options) {
2437
2481
  extendURLWithDeprecatedProperties(location);
@@ -2439,7 +2483,9 @@ class Session {
2439
2483
  }
2440
2484
  visitStarted(visit) {
2441
2485
  extendURLWithDeprecatedProperties(visit.location);
2442
- this.notifyApplicationAfterVisitingLocation(visit.location, visit.action);
2486
+ if (!visit.silent) {
2487
+ this.notifyApplicationAfterVisitingLocation(visit.location, visit.action);
2488
+ }
2443
2489
  }
2444
2490
  visitCompleted(visit) {
2445
2491
  this.notifyApplicationAfterPageLoad(visit.getTimingMetrics());
@@ -2451,7 +2497,7 @@ class Session {
2451
2497
  this.notifyApplicationAfterVisitingSamePageLocation(oldURL, newURL);
2452
2498
  }
2453
2499
  willSubmitForm(form, submitter) {
2454
- return elementIsNavigable(form) && elementIsNavigable(submitter);
2500
+ return this.elementDriveEnabled(form) && this.elementDriveEnabled(submitter);
2455
2501
  }
2456
2502
  formSubmitted(form, submitter) {
2457
2503
  this.navigator.submitForm(form, submitter);
@@ -2470,7 +2516,10 @@ class Session {
2470
2516
  this.renderStreamMessage(message);
2471
2517
  }
2472
2518
  viewWillCacheSnapshot() {
2473
- this.notifyApplicationBeforeCachingSnapshot();
2519
+ var _a;
2520
+ if (!((_a = this.navigator.currentVisit) === null || _a === void 0 ? void 0 : _a.silent)) {
2521
+ this.notifyApplicationBeforeCachingSnapshot();
2522
+ }
2474
2523
  }
2475
2524
  allowsImmediateRender({ element }, resume) {
2476
2525
  const event = this.notifyApplicationBeforeRender(element, resume);
@@ -2483,6 +2532,12 @@ class Session {
2483
2532
  viewInvalidated() {
2484
2533
  this.adapter.pageInvalidated();
2485
2534
  }
2535
+ frameLoaded(frame) {
2536
+ this.notifyApplicationAfterFrameLoad(frame);
2537
+ }
2538
+ frameRendered(fetchResponse, frame) {
2539
+ this.notifyApplicationAfterFrameRender(fetchResponse, frame);
2540
+ }
2486
2541
  applicationAllowsFollowingLinkToLocation(link, location) {
2487
2542
  const event = this.notifyApplicationAfterClickingLinkToLocation(link, location);
2488
2543
  return !event.defaultPrevented;
@@ -2515,6 +2570,31 @@ class Session {
2515
2570
  notifyApplicationAfterVisitingSamePageLocation(oldURL, newURL) {
2516
2571
  dispatchEvent(new HashChangeEvent("hashchange", { oldURL: oldURL.toString(), newURL: newURL.toString() }));
2517
2572
  }
2573
+ notifyApplicationAfterFrameLoad(frame) {
2574
+ return dispatch("turbo:frame-load", { target: frame });
2575
+ }
2576
+ notifyApplicationAfterFrameRender(fetchResponse, frame) {
2577
+ return dispatch("turbo:frame-render", { detail: { fetchResponse }, target: frame, cancelable: true });
2578
+ }
2579
+ elementDriveEnabled(element) {
2580
+ const container = element === null || element === void 0 ? void 0 : element.closest("[data-turbo]");
2581
+ if (this.drive) {
2582
+ if (container) {
2583
+ return container.getAttribute("data-turbo") != "false";
2584
+ }
2585
+ else {
2586
+ return true;
2587
+ }
2588
+ }
2589
+ else {
2590
+ if (container) {
2591
+ return container.getAttribute("data-turbo") == "true";
2592
+ }
2593
+ else {
2594
+ return false;
2595
+ }
2596
+ }
2597
+ }
2518
2598
  getActionForLink(link) {
2519
2599
  const action = link.getAttribute("data-turbo-action");
2520
2600
  return isAction(action) ? action : "advance";
@@ -2526,15 +2606,6 @@ class Session {
2526
2606
  return this.view.snapshot;
2527
2607
  }
2528
2608
  }
2529
- function elementIsNavigable(element) {
2530
- const container = element === null || element === void 0 ? void 0 : element.closest("[data-turbo]");
2531
- if (container) {
2532
- return container.getAttribute("data-turbo") != "false";
2533
- }
2534
- else {
2535
- return true;
2536
- }
2537
- }
2538
2609
  function extendURLWithDeprecatedProperties(url) {
2539
2610
  Object.defineProperties(url, deprecatedLocationPropertyDescriptors);
2540
2611
  }
@@ -2546,6 +2617,49 @@ const deprecatedLocationPropertyDescriptors = {
2546
2617
  }
2547
2618
  };
2548
2619
 
2620
+ const session = new Session;
2621
+ const { navigator } = session;
2622
+ function start() {
2623
+ session.start();
2624
+ }
2625
+ function registerAdapter(adapter) {
2626
+ session.registerAdapter(adapter);
2627
+ }
2628
+ function visit(location, options) {
2629
+ session.visit(location, options);
2630
+ }
2631
+ function connectStreamSource(source) {
2632
+ session.connectStreamSource(source);
2633
+ }
2634
+ function disconnectStreamSource(source) {
2635
+ session.disconnectStreamSource(source);
2636
+ }
2637
+ function renderStreamMessage(message) {
2638
+ session.renderStreamMessage(message);
2639
+ }
2640
+ function clearCache() {
2641
+ session.clearCache();
2642
+ }
2643
+ function setProgressBarDelay(delay) {
2644
+ session.setProgressBarDelay(delay);
2645
+ }
2646
+
2647
+ var Turbo = /*#__PURE__*/Object.freeze({
2648
+ __proto__: null,
2649
+ navigator: navigator,
2650
+ session: session,
2651
+ PageRenderer: PageRenderer,
2652
+ PageSnapshot: PageSnapshot,
2653
+ start: start,
2654
+ registerAdapter: registerAdapter,
2655
+ visit: visit,
2656
+ connectStreamSource: connectStreamSource,
2657
+ disconnectStreamSource: disconnectStreamSource,
2658
+ renderStreamMessage: renderStreamMessage,
2659
+ clearCache: clearCache,
2660
+ setProgressBarDelay: setProgressBarDelay
2661
+ });
2662
+
2549
2663
  class FrameController {
2550
2664
  constructor(element) {
2551
2665
  this.resolveVisitPromise = () => { };
@@ -2561,6 +2675,7 @@ class FrameController {
2561
2675
  connect() {
2562
2676
  if (!this.connected) {
2563
2677
  this.connected = true;
2678
+ this.reloadable = false;
2564
2679
  if (this.loadingStyle == FrameLoadingStyle.lazy) {
2565
2680
  this.appearanceObserver.start();
2566
2681
  }
@@ -2597,7 +2712,7 @@ class FrameController {
2597
2712
  }
2598
2713
  }
2599
2714
  async loadSourceURL() {
2600
- if (!this.settingSourceURL && this.enabled && this.isActive && this.sourceURL != this.currentURL) {
2715
+ if (!this.settingSourceURL && this.enabled && this.isActive && (this.reloadable || this.sourceURL != this.currentURL)) {
2601
2716
  const previousURL = this.currentURL;
2602
2717
  this.currentURL = this.sourceURL;
2603
2718
  if (this.sourceURL) {
@@ -2606,6 +2721,7 @@ class FrameController {
2606
2721
  this.appearanceObserver.stop();
2607
2722
  await this.element.loaded;
2608
2723
  this.hasBeenLoaded = true;
2724
+ session.frameLoaded(this.element);
2609
2725
  }
2610
2726
  catch (error) {
2611
2727
  this.currentURL = previousURL;
@@ -2627,6 +2743,7 @@ class FrameController {
2627
2743
  if (this.view.renderPromise)
2628
2744
  await this.view.renderPromise;
2629
2745
  await this.view.render(renderer);
2746
+ session.frameRendered(fetchResponse, this.element);
2630
2747
  }
2631
2748
  }
2632
2749
  catch (error) {
@@ -2646,6 +2763,7 @@ class FrameController {
2646
2763
  }
2647
2764
  }
2648
2765
  linkClickIntercepted(element, url) {
2766
+ this.reloadable = true;
2649
2767
  this.navigateFrame(element, url);
2650
2768
  }
2651
2769
  shouldInterceptFormSubmission(element, submitter) {
@@ -2655,6 +2773,7 @@ class FrameController {
2655
2773
  if (this.formSubmission) {
2656
2774
  this.formSubmission.stop();
2657
2775
  }
2776
+ this.reloadable = false;
2658
2777
  this.formSubmission = new FormSubmission(this, element, submitter);
2659
2778
  if (this.formSubmission.fetchRequest.isIdempotent) {
2660
2779
  this.navigateFrame(element, this.formSubmission.fetchRequest.url.href);
@@ -2762,10 +2881,10 @@ class FrameController {
2762
2881
  return !frameElement.disabled;
2763
2882
  }
2764
2883
  }
2765
- if (!elementIsNavigable(element)) {
2884
+ if (!session.elementDriveEnabled(element)) {
2766
2885
  return false;
2767
2886
  }
2768
- if (submitter && !elementIsNavigable(submitter)) {
2887
+ if (submitter && !session.elementDriveEnabled(submitter)) {
2769
2888
  return false;
2770
2889
  }
2771
2890
  return true;
@@ -2781,6 +2900,19 @@ class FrameController {
2781
2900
  return this.element.src;
2782
2901
  }
2783
2902
  }
2903
+ get reloadable() {
2904
+ const frame = this.findFrameElement(this.element);
2905
+ return frame.hasAttribute("reloadable");
2906
+ }
2907
+ set reloadable(value) {
2908
+ const frame = this.findFrameElement(this.element);
2909
+ if (value) {
2910
+ frame.setAttribute("reloadable", "");
2911
+ }
2912
+ else {
2913
+ frame.removeAttribute("reloadable");
2914
+ }
2915
+ }
2784
2916
  set sourceURL(sourceURL) {
2785
2917
  this.settingSourceURL = true;
2786
2918
  this.element.src = sourceURL !== null && sourceURL !== void 0 ? sourceURL : null;
@@ -2983,50 +3115,7 @@ customElements.define("turbo-stream", StreamElement);
2983
3115
  }
2984
3116
  })();
2985
3117
 
2986
- const session = new Session;
2987
- const { navigator } = session;
2988
- function start() {
2989
- session.start();
2990
- }
2991
- function registerAdapter(adapter) {
2992
- session.registerAdapter(adapter);
2993
- }
2994
- function visit(location, options) {
2995
- session.visit(location, options);
2996
- }
2997
- function connectStreamSource(source) {
2998
- session.connectStreamSource(source);
2999
- }
3000
- function disconnectStreamSource(source) {
3001
- session.disconnectStreamSource(source);
3002
- }
3003
- function renderStreamMessage(message) {
3004
- session.renderStreamMessage(message);
3005
- }
3006
- function clearCache() {
3007
- session.clearCache();
3008
- }
3009
- function setProgressBarDelay(delay) {
3010
- session.setProgressBarDelay(delay);
3011
- }
3012
-
3013
- var Turbo = /*#__PURE__*/Object.freeze({
3014
- __proto__: null,
3015
- navigator: navigator,
3016
- PageRenderer: PageRenderer,
3017
- PageSnapshot: PageSnapshot,
3018
- start: start,
3019
- registerAdapter: registerAdapter,
3020
- visit: visit,
3021
- connectStreamSource: connectStreamSource,
3022
- disconnectStreamSource: disconnectStreamSource,
3023
- renderStreamMessage: renderStreamMessage,
3024
- clearCache: clearCache,
3025
- setProgressBarDelay: setProgressBarDelay
3026
- });
3027
-
3028
3118
  window.Turbo = Turbo;
3029
3119
  start();
3030
3120
 
3031
- export { PageRenderer, PageSnapshot, clearCache, connectStreamSource, disconnectStreamSource, navigator, registerAdapter, renderStreamMessage, setProgressBarDelay, start, visit };
3032
- //# sourceMappingURL=turbo.es2017-esm.js.map
3121
+ export { PageRenderer, PageSnapshot, clearCache, connectStreamSource, disconnectStreamSource, navigator, registerAdapter, renderStreamMessage, session, setProgressBarDelay, start, visit };