@inertiajs/core 2.3.17 → 3.0.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,66 +1,8 @@
1
- "use strict";
2
- var __create = Object.create;
3
- var __defProp = Object.defineProperty;
4
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
- var __getOwnPropNames = Object.getOwnPropertyNames;
6
- var __getProtoOf = Object.getPrototypeOf;
7
- var __hasOwnProp = Object.prototype.hasOwnProperty;
8
- var __export = (target, all) => {
9
- for (var name in all)
10
- __defProp(target, name, { get: all[name], enumerable: true });
11
- };
12
- var __copyProps = (to, from, except, desc) => {
13
- if (from && typeof from === "object" || typeof from === "function") {
14
- for (let key of __getOwnPropNames(from))
15
- if (!__hasOwnProp.call(to, key) && key !== except)
16
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
- }
18
- return to;
19
- };
20
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
- // If the importer is in node compatibility mode or this is not an ESM
22
- // file that has been converted to a CommonJS file using a Babel-
23
- // compatible transform (i.e. "__esModule" has not been set), then set
24
- // "default" to the CommonJS "module.exports" for node compatibility.
25
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
- mod
27
- ));
28
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
-
30
- // src/index.ts
31
- var index_exports = {};
32
- __export(index_exports, {
33
- FormComponentResetSymbol: () => FormComponentResetSymbol,
34
- UseFormUtils: () => UseFormUtils,
35
- config: () => config,
36
- createHeadManager: () => createHeadManager,
37
- formDataToObject: () => formDataToObject,
38
- getInitialPageFromDOM: () => getInitialPageFromDOM,
39
- getScrollableParent: () => getScrollableParent,
40
- hideProgress: () => hide2,
41
- hrefToUrl: () => hrefToUrl,
42
- isUrlMethodPair: () => isUrlMethodPair,
43
- mergeDataIntoQueryString: () => mergeDataIntoQueryString,
44
- objectToFormData: () => objectToFormData,
45
- progress: () => progress,
46
- resetFormFields: () => resetFormFields,
47
- revealProgress: () => reveal,
48
- router: () => router,
49
- setupProgress: () => setupProgress,
50
- shouldIntercept: () => shouldIntercept,
51
- shouldNavigate: () => shouldNavigate,
52
- urlHasProtocol: () => urlHasProtocol,
53
- urlToString: () => urlToString,
54
- urlWithoutHash: () => urlWithoutHash,
55
- useInfiniteScroll: () => useInfiniteScroll
56
- });
57
- module.exports = __toCommonJS(index_exports);
58
-
59
1
  // src/router.ts
60
- var import_lodash_es5 = require("lodash-es");
2
+ import { cloneDeep as cloneDeep3, get as get7, isEqual as isEqual3, set as set5 } from "lodash-es";
61
3
 
62
4
  // src/config.ts
63
- var import_lodash_es = require("lodash-es");
5
+ import { get, has, set } from "lodash-es";
64
6
  var Config = class {
65
7
  constructor(defaults) {
66
8
  this.config = {};
@@ -76,14 +18,14 @@ var Config = class {
76
18
  this.config = newConfig;
77
19
  }
78
20
  get(key) {
79
- return (0, import_lodash_es.has)(this.config, key) ? (0, import_lodash_es.get)(this.config, key) : (0, import_lodash_es.get)(this.defaults, key);
21
+ return has(this.config, key) ? get(this.config, key) : get(this.defaults, key);
80
22
  }
81
23
  set(keyOrValues, value) {
82
24
  if (typeof keyOrValues === "string") {
83
- (0, import_lodash_es.set)(this.config, keyOrValues, value);
25
+ set(this.config, keyOrValues, value);
84
26
  } else {
85
27
  Object.entries(keyOrValues).forEach(([key, val]) => {
86
- (0, import_lodash_es.set)(this.config, key, val);
28
+ set(this.config, key, val);
87
29
  });
88
30
  }
89
31
  }
@@ -94,18 +36,15 @@ var config = new Config({
94
36
  forceIndicesArrayFormatInFormData: true,
95
37
  withAllErrors: false
96
38
  },
97
- future: {
98
- preserveEqualProps: false,
99
- useDataInertiaHeadAttribute: false,
100
- useDialogForErrorModal: false,
101
- useScriptElementForInitialPage: false
102
- },
103
39
  prefetch: {
104
40
  cacheFor: 3e4,
105
41
  hoverDelay: 75
106
42
  }
107
43
  });
108
44
 
45
+ // src/eventHandler.ts
46
+ import { get as get4 } from "lodash-es";
47
+
109
48
  // src/debounce.ts
110
49
  function debounce(fn, delay) {
111
50
  let timeoutID;
@@ -125,14 +64,14 @@ var fireBeforeEvent = (visit) => {
125
64
  var fireErrorEvent = (errors) => {
126
65
  return fireEvent("error", { detail: { errors } });
127
66
  };
128
- var fireExceptionEvent = (exception) => {
129
- return fireEvent("exception", { cancelable: true, detail: { exception } });
67
+ var fireNetworkErrorEvent = (exception) => {
68
+ return fireEvent("networkError", { cancelable: true, detail: { exception } });
130
69
  };
131
70
  var fireFinishEvent = (visit) => {
132
71
  return fireEvent("finish", { detail: { visit } });
133
72
  };
134
- var fireInvalidEvent = (response) => {
135
- return fireEvent("invalid", { cancelable: true, detail: { response } });
73
+ var fireHttpExceptionEvent = (response) => {
74
+ return fireEvent("httpException", { cancelable: true, detail: { response } });
136
75
  };
137
76
  var fireBeforeUpdateEvent = (page2) => {
138
77
  return fireEvent("beforeUpdate", { detail: { page: page2 } });
@@ -150,7 +89,7 @@ var fireSuccessEvent = (page2) => {
150
89
  return fireEvent("success", { detail: { page: page2 } });
151
90
  };
152
91
  var firePrefetchedEvent = (response, visit) => {
153
- return fireEvent("prefetched", { detail: { fetchedAt: Date.now(), response: response.data, visit } });
92
+ return fireEvent("prefetched", { detail: { fetchedAt: Date.now(), response, visit } });
154
93
  };
155
94
  var firePrefetchingEvent = (visit) => {
156
95
  return fireEvent("prefetching", { detail: { visit } });
@@ -160,7 +99,7 @@ var fireFlashEvent = (flash) => {
160
99
  };
161
100
 
162
101
  // src/history.ts
163
- var import_lodash_es3 = require("lodash-es");
102
+ import { cloneDeep as cloneDeep2, isEqual } from "lodash-es";
164
103
 
165
104
  // src/sessionStorage.ts
166
105
  var SessionStorage = class {
@@ -331,8 +270,11 @@ var getKeyFromSessionStorage = async () => {
331
270
  return key;
332
271
  };
333
272
 
273
+ // src/page.ts
274
+ import { get as get3, set as set3 } from "lodash-es";
275
+
334
276
  // src/prefetched.ts
335
- var import_lodash_es2 = require("lodash-es");
277
+ import { cloneDeep, get as get2 } from "lodash-es";
336
278
 
337
279
  // src/objectUtils.ts
338
280
  var objectsAreEqual = (obj1, obj2, excludeKeys) => {
@@ -564,7 +506,7 @@ var PrefetchedRequests = class {
564
506
  }) || null;
565
507
  }
566
508
  withoutPurposePrefetchHeader(params) {
567
- const newParams = (0, import_lodash_es2.cloneDeep)(params);
509
+ const newParams = cloneDeep(params);
568
510
  if (newParams.headers["Purpose"] === "prefetch") {
569
511
  delete newParams.headers["Purpose"];
570
512
  }
@@ -593,7 +535,10 @@ var PrefetchedRequests = class {
593
535
  "onCancelToken",
594
536
  "onPrefetching",
595
537
  "async",
596
- "viewTransition"
538
+ "viewTransition",
539
+ "optimistic",
540
+ "component",
541
+ "pageProps"
597
542
  ]
598
543
  );
599
544
  }
@@ -603,7 +548,7 @@ var PrefetchedRequests = class {
603
548
  const pageResponse = response.getPageResponse();
604
549
  page.mergeOncePropsIntoResponse(pageResponse, { force: true });
605
550
  for (const [group, deferredProps] of Object.entries(pageResponse.deferredProps ?? {})) {
606
- const remaining = deferredProps.filter((prop) => pageResponse.props[prop] === void 0);
551
+ const remaining = deferredProps.filter((prop) => get2(pageResponse.props, prop) === void 0);
607
552
  if (remaining.length > 0) {
608
553
  pageResponse.deferredProps[group] = remaining;
609
554
  } else {
@@ -647,7 +592,7 @@ var elementInViewport = (el) => {
647
592
  var getScrollableParent = (element) => {
648
593
  const allowsVerticalScroll = (el) => {
649
594
  const computedStyle = window.getComputedStyle(el);
650
- if (["scroll", "overlay"].includes(computedStyle.overflowY)) {
595
+ if (computedStyle.overflowY === "scroll") {
651
596
  return true;
652
597
  }
653
598
  if (computedStyle.overflowY !== "auto") {
@@ -660,7 +605,7 @@ var getScrollableParent = (element) => {
660
605
  };
661
606
  const allowsHorizontalScroll = (el) => {
662
607
  const computedStyle = window.getComputedStyle(el);
663
- if (["scroll", "overlay"].includes(computedStyle.overflowX)) {
608
+ if (computedStyle.overflowX === "scroll") {
664
609
  return true;
665
610
  }
666
611
  if (computedStyle.overflowX !== "auto") {
@@ -736,16 +681,10 @@ var requestAnimationFrame = (cb, times = 1) => {
736
681
  }
737
682
  });
738
683
  };
739
- var getInitialPageFromDOM = (id, useScriptElement = false) => {
684
+ var getInitialPageFromDOM = (id) => {
740
685
  if (typeof window === "undefined") {
741
686
  return null;
742
687
  }
743
- if (!useScriptElement) {
744
- const el = document.getElementById(id);
745
- if (el?.dataset.page) {
746
- return JSON.parse(el.dataset.page);
747
- }
748
- }
749
688
  const scriptEl = document.querySelector(`script[data-page="${id}"][type="application/json"]`);
750
689
  if (scriptEl?.textContent) {
751
690
  return JSON.parse(scriptEl.textContent);
@@ -844,9 +783,6 @@ var Scroll = class {
844
783
  }
845
784
  };
846
785
 
847
- // src/url.ts
848
- var qs = __toESM(require("qs"), 1);
849
-
850
786
  // src/files.ts
851
787
  var isFile = (value) => typeof File !== "undefined" && value instanceof File || value instanceof Blob || typeof FileList !== "undefined" && value instanceof FileList && value.length > 0;
852
788
  function hasFiles(data) {
@@ -893,6 +829,88 @@ function append(form, key, value, format) {
893
829
  objectToFormData(value, form, key, format);
894
830
  }
895
831
 
832
+ // src/queryString.ts
833
+ function hasIndices(url) {
834
+ return /\[\d+\]/.test(decodeURIComponent(url.search));
835
+ }
836
+ function parse(query) {
837
+ if (!query || query === "?") {
838
+ return {};
839
+ }
840
+ const result = {};
841
+ query.replace(/^\?/, "").split("&").filter(Boolean).forEach((segment) => {
842
+ const [rawKey, rawValue] = splitPair(segment);
843
+ set2(result, decode(rawKey), decode(rawValue));
844
+ });
845
+ return result;
846
+ }
847
+ function stringify(data, arrayFormat) {
848
+ const pairs = [];
849
+ build(data, "", pairs, arrayFormat);
850
+ return pairs.length ? "?" + pairs.join("&") : "";
851
+ }
852
+ function splitPair(pair) {
853
+ const index = pair.indexOf("=");
854
+ return index === -1 ? [pair, ""] : [pair.substring(0, index), pair.substring(index + 1)];
855
+ }
856
+ function decode(value) {
857
+ return decodeURIComponent(value.replace(/\+/g, " "));
858
+ }
859
+ function set2(target, key, value) {
860
+ const keys = parseKey(key);
861
+ let current = target;
862
+ while (keys.length > 1) {
863
+ const segment = keys.shift();
864
+ const nextIsArrayPush = keys[0] === "";
865
+ if (typeof current[segment] !== "object" || current[segment] === null) {
866
+ current[segment] = nextIsArrayPush ? [] : {};
867
+ }
868
+ current = current[segment];
869
+ }
870
+ const final = keys.shift();
871
+ if (final === "" && Array.isArray(current)) {
872
+ current.push(value);
873
+ } else {
874
+ current[final] = value;
875
+ }
876
+ }
877
+ function parseKey(key) {
878
+ const segments = [];
879
+ const base = key.split("[")[0];
880
+ if (base) {
881
+ segments.push(base);
882
+ }
883
+ let match;
884
+ const pattern = /\[([^\]]*)\]/g;
885
+ while ((match = pattern.exec(key)) !== null) {
886
+ segments.push(match[1]);
887
+ }
888
+ return segments;
889
+ }
890
+ function build(value, prefix, pairs, arrayFormat) {
891
+ if (value === void 0) {
892
+ return;
893
+ }
894
+ if (value === null) {
895
+ pairs.push(`${prefix}=`);
896
+ return;
897
+ }
898
+ if (Array.isArray(value)) {
899
+ value.forEach((item, index) => {
900
+ const key = arrayFormat === "indices" ? `${prefix}[${index}]` : `${prefix}[]`;
901
+ build(item, key, pairs, arrayFormat);
902
+ });
903
+ return;
904
+ }
905
+ if (typeof value === "object") {
906
+ Object.keys(value).forEach((key) => {
907
+ build(value[key], prefix ? `${prefix}[${key}]` : key, pairs, arrayFormat);
908
+ });
909
+ return;
910
+ }
911
+ pairs.push(`${prefix}=${encodeURIComponent(String(value))}`);
912
+ }
913
+
896
914
  // src/url.ts
897
915
  function hrefToUrl(href) {
898
916
  return new URL(href.toString(), typeof window === "undefined" ? void 0 : window.location.toString());
@@ -921,15 +939,8 @@ function mergeDataIntoQueryString(method, href, data, qsArrayFormat = "brackets"
921
939
  const hasHash = href.toString().includes("#");
922
940
  const url = new URL(href.toString(), typeof window === "undefined" ? "http://localhost" : window.location.toString());
923
941
  if (hasDataForQueryString) {
924
- const hasIndices = /\[\d+\]/.test(decodeURIComponent(url.search));
925
- const parseOptions = { ignoreQueryPrefix: true, allowSparse: true };
926
- url.search = qs.stringify(
927
- { ...qs.parse(url.search, parseOptions), ...data },
928
- {
929
- encodeValuesOnly: true,
930
- arrayFormat: hasIndices ? "indices" : qsArrayFormat
931
- }
932
- );
942
+ const arrayFormat = hasIndices(url) ? "indices" : qsArrayFormat;
943
+ url.search = stringify({ ...parse(url.search), ...data }, arrayFormat);
933
944
  }
934
945
  return [
935
946
  [
@@ -961,6 +972,18 @@ var isSameUrlWithoutQueryOrHash = (url1, url2) => {
961
972
  function isUrlMethodPair(href) {
962
973
  return href !== null && typeof href === "object" && href !== void 0 && "url" in href && "method" in href;
963
974
  }
975
+ function resolveUrlMethodPairComponent(pair) {
976
+ if (!pair.component) {
977
+ return null;
978
+ }
979
+ if (Array.isArray(pair.component)) {
980
+ console.error(
981
+ `The "component" property on the URL method pair received an array of components (${pair.component.join(", ")}), but only a single component string is supported for instant visits. Pass an explicit component name instead.`
982
+ );
983
+ return null;
984
+ }
985
+ return pair.component;
986
+ }
964
987
  function urlHasProtocol(url) {
965
988
  return /^([a-z][a-z0-9+.-]*:)?\/\/[^/]/i.test(url);
966
989
  }
@@ -1015,7 +1038,7 @@ var CurrentPage = class {
1015
1038
  if (page2.clearHistory) {
1016
1039
  history.clear();
1017
1040
  }
1018
- return this.resolve(page2.component).then((component) => {
1041
+ return this.resolve(page2.component, page2).then((component) => {
1019
1042
  if (componentId !== this.componentId) {
1020
1043
  return;
1021
1044
  }
@@ -1025,6 +1048,7 @@ var CurrentPage = class {
1025
1048
  const scrollRegions = !isServer3 && preserveScroll ? Scroll.getScrollRegions() : [];
1026
1049
  replace = replace || isSameUrlWithoutHash(hrefToUrl(page2.url), location);
1027
1050
  const pageForHistory = { ...page2, flash: {} };
1051
+ delete pageForHistory.optimisticUpdatedAt;
1028
1052
  return new Promise(
1029
1053
  (resolve) => replace ? history.replaceState(pageForHistory, resolve) : history.pushState(pageForHistory, resolve)
1030
1054
  ).then(() => {
@@ -1073,7 +1097,7 @@ var CurrentPage = class {
1073
1097
  setQuietly(page2, {
1074
1098
  preserveState = false
1075
1099
  } = {}) {
1076
- return this.resolve(page2.component).then((component) => {
1100
+ return this.resolve(page2.component, page2).then((component) => {
1077
1101
  this.page = page2;
1078
1102
  this.cleared = false;
1079
1103
  history.setCurrent(page2);
@@ -1098,6 +1122,12 @@ var CurrentPage = class {
1098
1122
  merge(data) {
1099
1123
  this.page = { ...this.page, ...data };
1100
1124
  }
1125
+ setPropsQuietly(props) {
1126
+ this.page = { ...this.page, props };
1127
+ return this.resolve(this.page.component, this.page).then((component) => {
1128
+ return this.swap({ component, page: this.page, preserveState: true, viewTransition: false });
1129
+ });
1130
+ }
1101
1131
  setFlash(flash) {
1102
1132
  this.page = { ...this.page, flash };
1103
1133
  this.onFlashCallback?.(flash);
@@ -1126,8 +1156,22 @@ var CurrentPage = class {
1126
1156
  viewTransitionCallback(transitionResult);
1127
1157
  });
1128
1158
  }
1129
- resolve(component) {
1130
- return Promise.resolve(this.resolveComponent(component));
1159
+ resolve(component, page2) {
1160
+ return Promise.resolve(this.resolveComponent(component, page2));
1161
+ }
1162
+ recordOptimisticUpdate(keys, updatedAt) {
1163
+ if (!this.page.optimisticUpdatedAt) {
1164
+ this.page.optimisticUpdatedAt = {};
1165
+ }
1166
+ for (const key of keys) {
1167
+ if (updatedAt > (this.page.optimisticUpdatedAt[key] || 0)) {
1168
+ this.page.optimisticUpdatedAt[key] = updatedAt;
1169
+ }
1170
+ }
1171
+ }
1172
+ shouldPreserveOptimistic(key, updatedAt) {
1173
+ const lastUpdatedAt = this.page.optimisticUpdatedAt?.[key];
1174
+ return lastUpdatedAt !== void 0 && updatedAt < lastUpdatedAt;
1131
1175
  }
1132
1176
  isTheSame(page2) {
1133
1177
  return this.page.component === page2.component;
@@ -1147,8 +1191,8 @@ var CurrentPage = class {
1147
1191
  if (existingOnceProp === void 0) {
1148
1192
  return;
1149
1193
  }
1150
- if (force || response.props[onceProp.prop] === void 0) {
1151
- response.props[onceProp.prop] = this.page.props[existingOnceProp.prop];
1194
+ if (force || get3(response.props, onceProp.prop) === void 0) {
1195
+ set3(response.props, onceProp.prop, get3(this.page.props, existingOnceProp.prop));
1152
1196
  response.onceProps[key].expiresAt = existingOnceProp.expiresAt;
1153
1197
  }
1154
1198
  });
@@ -1236,7 +1280,7 @@ var History = class {
1236
1280
  } catch {
1237
1281
  return {
1238
1282
  ...page2,
1239
- props: (0, import_lodash_es3.cloneDeep)(page2.props)
1283
+ props: cloneDeep2(page2.props)
1240
1284
  };
1241
1285
  }
1242
1286
  }
@@ -1275,7 +1319,7 @@ var History = class {
1275
1319
  if (!window.history.state?.page) {
1276
1320
  return;
1277
1321
  }
1278
- if ((0, import_lodash_es3.isEqual)(this.getScrollRegions(), scrollRegions)) {
1322
+ if (isEqual(this.getScrollRegions(), scrollRegions)) {
1279
1323
  return;
1280
1324
  }
1281
1325
  return this.doReplaceState({
@@ -1291,7 +1335,7 @@ var History = class {
1291
1335
  if (!window.history.state?.page) {
1292
1336
  return;
1293
1337
  }
1294
- if ((0, import_lodash_es3.isEqual)(this.getDocumentScrollPosition(), scrollRegion)) {
1338
+ if (isEqual(this.getDocumentScrollPosition(), scrollRegion)) {
1295
1339
  return;
1296
1340
  }
1297
1341
  return this.doReplaceState({
@@ -1308,7 +1352,7 @@ var History = class {
1308
1352
  return window.history.state?.documentScrollPosition || { top: 0, left: 0 };
1309
1353
  }
1310
1354
  replaceState(page2, cb = null) {
1311
- if ((0, import_lodash_es3.isEqual)(this.current, page2)) {
1355
+ if (isEqual(this.current, page2)) {
1312
1356
  cb && cb();
1313
1357
  return;
1314
1358
  }
@@ -1486,7 +1530,7 @@ var EventHandler = class {
1486
1530
  const pendingDeferred = {};
1487
1531
  const pageProps = page.get().props;
1488
1532
  for (const [group, props] of Object.entries(data.initialDeferredProps ?? data.deferredProps ?? {})) {
1489
- const missing = props.filter((prop) => pageProps[prop] === void 0);
1533
+ const missing = props.filter((prop) => get4(pageProps, prop) === void 0);
1490
1534
  if (missing.length > 0) {
1491
1535
  pendingDeferred[group] = missing;
1492
1536
  }
@@ -1511,10 +1555,8 @@ var NavigationType = class {
1511
1555
  if (typeof window === "undefined") {
1512
1556
  return "navigate";
1513
1557
  }
1514
- if (window.performance && window.performance.getEntriesByType && window.performance.getEntriesByType("navigation").length > 0) {
1515
- return window.performance.getEntriesByType("navigation")[0].type;
1516
- }
1517
- return "navigate";
1558
+ const entry = window.performance?.getEntriesByType("navigation")[0];
1559
+ return entry?.type ?? "navigate";
1518
1560
  }
1519
1561
  get() {
1520
1562
  return this.type;
@@ -1639,8 +1681,8 @@ var Poll = class {
1639
1681
  }
1640
1682
  }, this.interval);
1641
1683
  }
1642
- isInBackground(hidden) {
1643
- this.throttle = this.keepAlive ? false : hidden;
1684
+ isInBackground(hidden2) {
1685
+ this.throttle = this.keepAlive ? false : hidden2;
1644
1686
  if (this.throttle) {
1645
1687
  this.cbCount = 0;
1646
1688
  }
@@ -1681,7 +1723,245 @@ var Polls = class {
1681
1723
  var polls = new Polls();
1682
1724
 
1683
1725
  // src/request.ts
1684
- var import_axios = __toESM(require("axios"), 1);
1726
+ import { get as get6 } from "lodash-es";
1727
+
1728
+ // src/http.ts
1729
+ import { client as precognitionClient } from "laravel-precognition";
1730
+
1731
+ // src/httpHandlers.ts
1732
+ var HttpHandlers = class {
1733
+ constructor() {
1734
+ this.requestHandlers = [];
1735
+ this.responseHandlers = [];
1736
+ this.errorHandlers = [];
1737
+ }
1738
+ onRequest(handler) {
1739
+ this.requestHandlers.push(handler);
1740
+ return () => {
1741
+ this.requestHandlers = this.requestHandlers.filter((h) => h !== handler);
1742
+ };
1743
+ }
1744
+ onResponse(handler) {
1745
+ this.responseHandlers.push(handler);
1746
+ return () => {
1747
+ this.responseHandlers = this.responseHandlers.filter((h) => h !== handler);
1748
+ };
1749
+ }
1750
+ onError(handler) {
1751
+ this.errorHandlers.push(handler);
1752
+ return () => {
1753
+ this.errorHandlers = this.errorHandlers.filter((h) => h !== handler);
1754
+ };
1755
+ }
1756
+ async processRequest(config2) {
1757
+ let result = config2;
1758
+ for (const handler of this.requestHandlers) {
1759
+ result = await handler(result);
1760
+ }
1761
+ return result;
1762
+ }
1763
+ async processResponse(response) {
1764
+ let result = response;
1765
+ for (const handler of this.responseHandlers) {
1766
+ result = await handler(result);
1767
+ }
1768
+ return result;
1769
+ }
1770
+ async processError(error) {
1771
+ for (const handler of this.errorHandlers) {
1772
+ await handler(error);
1773
+ }
1774
+ }
1775
+ };
1776
+ var httpHandlers = new HttpHandlers();
1777
+
1778
+ // src/httpErrors.ts
1779
+ var HttpResponseError = class extends Error {
1780
+ constructor(message, response, url) {
1781
+ super(url ? `${message} (${url})` : message);
1782
+ this.name = "HttpResponseError";
1783
+ this.response = response;
1784
+ this.url = url;
1785
+ }
1786
+ };
1787
+ var HttpCancelledError = class extends Error {
1788
+ constructor(message = "Request was cancelled", url) {
1789
+ super(url ? `${message} (${url})` : message);
1790
+ this.name = "HttpCancelledError";
1791
+ this.url = url;
1792
+ }
1793
+ };
1794
+ var HttpNetworkError = class extends Error {
1795
+ constructor(message, url, cause) {
1796
+ super(url ? `${message} (${url})` : message);
1797
+ this.code = "ERR_NETWORK";
1798
+ this.name = "HttpNetworkError";
1799
+ this.url = url;
1800
+ this.cause = cause;
1801
+ }
1802
+ };
1803
+
1804
+ // src/xhrHttpClient.ts
1805
+ function getCookie(name) {
1806
+ const match = document.cookie.match(new RegExp("(^|;\\s*)(" + name + ")=([^;]*)"));
1807
+ return match ? decodeURIComponent(match[3]) : null;
1808
+ }
1809
+ function parseHeaders(xhr) {
1810
+ const headers = {};
1811
+ xhr.getAllResponseHeaders().split("\r\n").forEach((line) => {
1812
+ const index = line.indexOf(":");
1813
+ if (index > 0) {
1814
+ headers[line.slice(0, index).toLowerCase().trim()] = line.slice(index + 1).trim();
1815
+ }
1816
+ });
1817
+ return headers;
1818
+ }
1819
+ function setHeaders(xhr, config2) {
1820
+ if (!config2.headers) {
1821
+ return;
1822
+ }
1823
+ const isFormData2 = config2.data instanceof FormData;
1824
+ Object.entries(config2.headers).forEach(([key, value]) => {
1825
+ if (key.toLowerCase() !== "content-type" || !isFormData2) {
1826
+ xhr.setRequestHeader(key, String(value));
1827
+ }
1828
+ });
1829
+ }
1830
+ function buildUrlWithParams(url, params) {
1831
+ if (!params || Object.keys(params).length === 0) {
1832
+ return url;
1833
+ }
1834
+ const [urlWithParams] = mergeDataIntoQueryString("get", url, params);
1835
+ return urlWithParams;
1836
+ }
1837
+ var XhrHttpClient = class {
1838
+ constructor(options = {}) {
1839
+ this.xsrfCookieName = options.xsrfCookieName ?? "XSRF-TOKEN";
1840
+ this.xsrfHeaderName = options.xsrfHeaderName ?? "X-XSRF-TOKEN";
1841
+ }
1842
+ async request(config2) {
1843
+ const processedConfig = await httpHandlers.processRequest(config2);
1844
+ try {
1845
+ const response = await this.doRequest(processedConfig);
1846
+ return await httpHandlers.processResponse(response);
1847
+ } catch (error) {
1848
+ if (error instanceof HttpResponseError || error instanceof HttpNetworkError || error instanceof HttpCancelledError) {
1849
+ await httpHandlers.processError(error);
1850
+ }
1851
+ throw error;
1852
+ }
1853
+ }
1854
+ doRequest(config2) {
1855
+ return new Promise((resolve, reject) => {
1856
+ const xhr = new XMLHttpRequest();
1857
+ const url = buildUrlWithParams(config2.url, config2.params);
1858
+ xhr.open(config2.method.toUpperCase(), url, true);
1859
+ const xsrfToken = getCookie(this.xsrfCookieName);
1860
+ if (xsrfToken) {
1861
+ xhr.setRequestHeader(this.xsrfHeaderName, xsrfToken);
1862
+ }
1863
+ let body = null;
1864
+ if (config2.data !== null && config2.data !== void 0) {
1865
+ if (config2.data instanceof FormData) {
1866
+ body = config2.data;
1867
+ } else if (typeof config2.data === "object") {
1868
+ body = JSON.stringify(config2.data);
1869
+ if (!config2.headers?.["Content-Type"] && !config2.headers?.["content-type"]) {
1870
+ xhr.setRequestHeader("Content-Type", "application/json");
1871
+ }
1872
+ } else {
1873
+ body = String(config2.data);
1874
+ }
1875
+ }
1876
+ setHeaders(xhr, config2);
1877
+ if (config2.onUploadProgress) {
1878
+ xhr.upload.onprogress = (event) => {
1879
+ config2.onUploadProgress({
1880
+ progress: event.lengthComputable ? event.loaded / event.total : void 0,
1881
+ loaded: event.loaded,
1882
+ total: event.lengthComputable ? event.total : void 0
1883
+ });
1884
+ };
1885
+ }
1886
+ if (config2.signal) {
1887
+ config2.signal.addEventListener("abort", () => xhr.abort());
1888
+ }
1889
+ xhr.onabort = () => reject(new HttpCancelledError("Request was cancelled", config2.url));
1890
+ xhr.onerror = () => reject(new HttpNetworkError("Network error", config2.url));
1891
+ xhr.onload = () => {
1892
+ const response = {
1893
+ status: xhr.status,
1894
+ data: xhr.responseText,
1895
+ headers: parseHeaders(xhr)
1896
+ };
1897
+ if (xhr.status >= 400) {
1898
+ reject(new HttpResponseError(`Request failed with status ${xhr.status}`, response, config2.url));
1899
+ } else {
1900
+ resolve(response);
1901
+ }
1902
+ };
1903
+ xhr.send(body);
1904
+ });
1905
+ }
1906
+ };
1907
+ var xhrHttpClient = new XhrHttpClient();
1908
+
1909
+ // src/http.ts
1910
+ var httpClient = xhrHttpClient;
1911
+ function isHttpClientOptions(client) {
1912
+ return !("request" in client);
1913
+ }
1914
+ var http = {
1915
+ /**
1916
+ * Get the current HTTP client
1917
+ */
1918
+ getClient() {
1919
+ return httpClient;
1920
+ },
1921
+ /**
1922
+ * Set the HTTP client to use for all Inertia requests
1923
+ */
1924
+ setClient(clientOrOptions) {
1925
+ if (!isHttpClientOptions(clientOrOptions)) {
1926
+ httpClient = clientOrOptions;
1927
+ return;
1928
+ }
1929
+ httpClient = new XhrHttpClient(clientOrOptions);
1930
+ if (clientOrOptions.xsrfCookieName) {
1931
+ precognitionClient.withXsrfCookieName(clientOrOptions.xsrfCookieName);
1932
+ }
1933
+ if (clientOrOptions.xsrfHeaderName) {
1934
+ precognitionClient.withXsrfHeaderName(clientOrOptions.xsrfHeaderName);
1935
+ }
1936
+ },
1937
+ /**
1938
+ * Register a request handler that runs before each request
1939
+ */
1940
+ onRequest: httpHandlers.onRequest.bind(httpHandlers),
1941
+ /**
1942
+ * Register a response handler that runs after each successful response
1943
+ */
1944
+ onResponse: httpHandlers.onResponse.bind(httpHandlers),
1945
+ /**
1946
+ * Register an error handler that runs when a request fails
1947
+ */
1948
+ onError: httpHandlers.onError.bind(httpHandlers),
1949
+ /**
1950
+ * Process a request config through all registered request handlers.
1951
+ * For use by custom HttpClient implementations.
1952
+ */
1953
+ processRequest: httpHandlers.processRequest.bind(httpHandlers),
1954
+ /**
1955
+ * Process a response through all registered response handlers.
1956
+ * For use by custom HttpClient implementations.
1957
+ */
1958
+ processResponse: httpHandlers.processResponse.bind(httpHandlers),
1959
+ /**
1960
+ * Process an error through all registered error handlers.
1961
+ * For use by custom HttpClient implementations.
1962
+ */
1963
+ processError: httpHandlers.processError.bind(httpHandlers)
1964
+ };
1685
1965
 
1686
1966
  // src/requestParams.ts
1687
1967
  var RequestParams = class _RequestParams {
@@ -1699,6 +1979,8 @@ var RequestParams = class _RequestParams {
1699
1979
  onCancel: this.wrapCallback(params, "onCancel"),
1700
1980
  onSuccess: this.wrapCallback(params, "onSuccess"),
1701
1981
  onError: this.wrapCallback(params, "onError"),
1982
+ onHttpException: this.wrapCallback(params, "onHttpException"),
1983
+ onNetworkError: this.wrapCallback(params, "onNetworkError"),
1702
1984
  onFlash: this.wrapCallback(params, "onFlash"),
1703
1985
  onCancelToken: this.wrapCallback(params, "onCancelToken"),
1704
1986
  onPrefetched: this.wrapCallback(params, "onPrefetched"),
@@ -1831,12 +2113,10 @@ var RequestParams = class _RequestParams {
1831
2113
  };
1832
2114
 
1833
2115
  // src/response.ts
1834
- var import_lodash_es4 = require("lodash-es");
2116
+ import { get as get5, isEqual as isEqual2, set as set4 } from "lodash-es";
1835
2117
 
1836
- // src/modal.ts
1837
- var modal_default = {
1838
- modal: null,
1839
- listener: null,
2118
+ // src/dialog.ts
2119
+ var dialog_default = {
1840
2120
  createIframeAndPage(html) {
1841
2121
  if (typeof html === "object") {
1842
2122
  html = `All Inertia requests must receive a valid Inertia response, however a plain JSON response was received.<hr>${JSON.stringify(
@@ -1855,44 +2135,6 @@ var modal_default = {
1855
2135
  },
1856
2136
  show(html) {
1857
2137
  const { iframe, page: page2 } = this.createIframeAndPage(html);
1858
- this.modal = document.createElement("div");
1859
- this.modal.style.position = "fixed";
1860
- this.modal.style.width = "100vw";
1861
- this.modal.style.height = "100vh";
1862
- this.modal.style.padding = "50px";
1863
- this.modal.style.boxSizing = "border-box";
1864
- this.modal.style.backgroundColor = "rgba(0, 0, 0, .6)";
1865
- this.modal.style.zIndex = 2e5;
1866
- this.modal.addEventListener("click", () => this.hide());
1867
- this.modal.appendChild(iframe);
1868
- document.body.prepend(this.modal);
1869
- document.body.style.overflow = "hidden";
1870
- if (!iframe.contentWindow) {
1871
- throw new Error("iframe not yet ready.");
1872
- }
1873
- iframe.contentWindow.document.open();
1874
- iframe.contentWindow.document.write(page2.outerHTML);
1875
- iframe.contentWindow.document.close();
1876
- this.listener = this.hideOnEscape.bind(this);
1877
- document.addEventListener("keydown", this.listener);
1878
- },
1879
- hide() {
1880
- this.modal.outerHTML = "";
1881
- this.modal = null;
1882
- document.body.style.overflow = "visible";
1883
- document.removeEventListener("keydown", this.listener);
1884
- },
1885
- hideOnEscape(event) {
1886
- if (event.keyCode === 27) {
1887
- this.hide();
1888
- }
1889
- }
1890
- };
1891
-
1892
- // src/dialog.ts
1893
- var dialog_default = {
1894
- show(html) {
1895
- const { iframe, page: page2 } = modal_default.createIframeAndPage(html);
1896
2138
  iframe.style.boxSizing = "border-box";
1897
2139
  iframe.style.display = "block";
1898
2140
  const dialog = document.createElement("dialog");
@@ -1946,10 +2188,14 @@ var Response = class _Response {
1946
2188
  this.response = response;
1947
2189
  this.originatingPage = originatingPage;
1948
2190
  this.wasPrefetched = false;
2191
+ this.processed = false;
1949
2192
  }
1950
2193
  static create(params, response, originatingPage) {
1951
2194
  return new _Response(params, response, originatingPage);
1952
2195
  }
2196
+ isProcessed() {
2197
+ return this.processed;
2198
+ }
1953
2199
  async handlePrefetch() {
1954
2200
  if (isSameUrlWithoutHash(this.requestParams.all().url, window.location)) {
1955
2201
  this.handle();
@@ -1967,6 +2213,7 @@ var Response = class _Response {
1967
2213
  return Promise.resolve();
1968
2214
  }
1969
2215
  this.requestParams.runCallbacks();
2216
+ this.processed = true;
1970
2217
  if (!this.isInertiaResponse()) {
1971
2218
  return this.handleNonInertiaResponse();
1972
2219
  }
@@ -1985,7 +2232,7 @@ var Response = class _Response {
1985
2232
  router.flush(page.get().url);
1986
2233
  }
1987
2234
  const { flash } = page.get();
1988
- if (Object.keys(flash).length > 0 && (!this.requestParams.isPartial() || !(0, import_lodash_es4.isEqual)(flash, previousFlash))) {
2235
+ if (Object.keys(flash).length > 0 && (!this.requestParams.isPartial() || !isEqual2(flash, previousFlash))) {
1989
2236
  fireFlashEvent(flash);
1990
2237
  this.requestParams.all().onFlash(flash);
1991
2238
  }
@@ -2004,6 +2251,14 @@ var Response = class _Response {
2004
2251
  return this.response.data = data;
2005
2252
  }
2006
2253
  async handleNonInertiaResponse() {
2254
+ if (this.isInertiaRedirect()) {
2255
+ router.visit(this.getHeader("x-inertia-redirect"), {
2256
+ ...this.requestParams.all(),
2257
+ method: "get",
2258
+ data: {}
2259
+ });
2260
+ return;
2261
+ }
2007
2262
  if (this.isLocationVisit()) {
2008
2263
  const locationUrl = hrefToUrl(this.getHeader("x-inertia-location"));
2009
2264
  setHashIfSameUrl(this.requestParams.all().url, locationUrl);
@@ -2013,8 +2268,11 @@ var Response = class _Response {
2013
2268
  ...this.response,
2014
2269
  data: this.getDataFromResponse(this.response.data)
2015
2270
  };
2016
- if (fireInvalidEvent(response)) {
2017
- return config.get("future.useDialogForErrorModal") ? dialog_default.show(response.data) : modal_default.show(response.data);
2271
+ if (this.requestParams.all().onHttpException(response) === false) {
2272
+ return;
2273
+ }
2274
+ if (fireHttpExceptionEvent(response)) {
2275
+ return dialog_default.show(response.data);
2018
2276
  }
2019
2277
  }
2020
2278
  isInertiaResponse() {
@@ -2029,6 +2287,9 @@ var Response = class _Response {
2029
2287
  hasHeader(header) {
2030
2288
  return this.getHeader(header) !== void 0;
2031
2289
  }
2290
+ isInertiaRedirect() {
2291
+ return this.hasStatus(409) && this.hasHeader("x-inertia-redirect");
2292
+ }
2032
2293
  isLocationVisit() {
2033
2294
  return this.hasStatus(409) && this.hasHeader("x-inertia-location");
2034
2295
  }
@@ -2059,6 +2320,7 @@ var Response = class _Response {
2059
2320
  }
2060
2321
  this.mergeProps(pageResponse);
2061
2322
  page.mergeOncePropsIntoResponse(pageResponse);
2323
+ this.preserveOptimisticProps(pageResponse);
2062
2324
  this.preserveEqualProps(pageResponse);
2063
2325
  await this.setRememberedState(pageResponse);
2064
2326
  this.requestParams.setPreserveOptions(pageResponse);
@@ -2098,16 +2360,32 @@ var Response = class _Response {
2098
2360
  }
2099
2361
  pageUrl(pageResponse) {
2100
2362
  const responseUrl = hrefToUrl(pageResponse.url);
2101
- setHashIfSameUrl(this.requestParams.all().url, responseUrl);
2363
+ if (pageResponse.preserveFragment) {
2364
+ responseUrl.hash = this.requestParams.all().url.hash;
2365
+ } else {
2366
+ setHashIfSameUrl(this.requestParams.all().url, responseUrl);
2367
+ }
2102
2368
  return responseUrl.pathname + responseUrl.search + responseUrl.hash;
2103
2369
  }
2370
+ preserveOptimisticProps(pageResponse) {
2371
+ const optimisticUpdatedAt = page.get().optimisticUpdatedAt;
2372
+ if (!optimisticUpdatedAt || !router.hasPendingOptimistic()) {
2373
+ return;
2374
+ }
2375
+ for (const key of Object.keys(pageResponse.props)) {
2376
+ if (key in optimisticUpdatedAt) {
2377
+ pageResponse.props[key] = page.get().props[key];
2378
+ }
2379
+ }
2380
+ pageResponse.optimisticUpdatedAt = { ...optimisticUpdatedAt };
2381
+ }
2104
2382
  preserveEqualProps(pageResponse) {
2105
- if (pageResponse.component !== page.get().component || config.get("future.preserveEqualProps") !== true) {
2383
+ if (pageResponse.component !== page.get().component) {
2106
2384
  return;
2107
2385
  }
2108
2386
  const currentPageProps = page.get().props;
2109
2387
  Object.entries(pageResponse.props).forEach(([key, value]) => {
2110
- if ((0, import_lodash_es4.isEqual)(value, currentPageProps[key])) {
2388
+ if (isEqual2(value, currentPageProps[key])) {
2111
2389
  pageResponse.props[key] = currentPageProps[key];
2112
2390
  }
2113
2391
  });
@@ -2121,8 +2399,8 @@ var Response = class _Response {
2121
2399
  const propsToDeepMerge = pageResponse.deepMergeProps || [];
2122
2400
  const matchPropsOn = pageResponse.matchPropsOn || [];
2123
2401
  const mergeProp = (prop, shouldAppend) => {
2124
- const currentProp = (0, import_lodash_es4.get)(page.get().props, prop);
2125
- const incomingProp = (0, import_lodash_es4.get)(pageResponse.props, prop);
2402
+ const currentProp = get5(page.get().props, prop);
2403
+ const incomingProp = get5(pageResponse.props, prop);
2126
2404
  if (Array.isArray(incomingProp)) {
2127
2405
  const newArray = this.mergeOrMatchItems(
2128
2406
  currentProp || [],
@@ -2131,20 +2409,20 @@ var Response = class _Response {
2131
2409
  matchPropsOn,
2132
2410
  shouldAppend
2133
2411
  );
2134
- (0, import_lodash_es4.set)(pageResponse.props, prop, newArray);
2412
+ set4(pageResponse.props, prop, newArray);
2135
2413
  } else if (typeof incomingProp === "object" && incomingProp !== null) {
2136
2414
  const newObject = {
2137
2415
  ...currentProp || {},
2138
2416
  ...incomingProp
2139
2417
  };
2140
- (0, import_lodash_es4.set)(pageResponse.props, prop, newObject);
2418
+ set4(pageResponse.props, prop, newObject);
2141
2419
  }
2142
2420
  };
2143
2421
  propsToAppend.forEach((prop) => mergeProp(prop, true));
2144
2422
  propsToPrepend.forEach((prop) => mergeProp(prop, false));
2145
2423
  propsToDeepMerge.forEach((prop) => {
2146
- const currentProp = page.get().props[prop];
2147
- const incomingProp = pageResponse.props[prop];
2424
+ const currentProp = get5(page.get().props, prop);
2425
+ const incomingProp = get5(pageResponse.props, prop);
2148
2426
  const deepMerge = (target, source, matchProp) => {
2149
2427
  if (Array.isArray(source)) {
2150
2428
  return this.mergeOrMatchItems(target, source, matchProp, matchPropsOn);
@@ -2160,15 +2438,21 @@ var Response = class _Response {
2160
2438
  }
2161
2439
  return source;
2162
2440
  };
2163
- pageResponse.props[prop] = deepMerge(currentProp, incomingProp, prop);
2441
+ set4(pageResponse.props, prop, deepMerge(currentProp, incomingProp, prop));
2164
2442
  });
2165
- pageResponse.props = { ...page.get().props, ...pageResponse.props };
2166
- if (this.requestParams.isDeferredPropsRequest()) {
2167
- const currentErrors = page.get().props.errors;
2168
- if (currentErrors && Object.keys(currentErrors).length > 0) {
2169
- pageResponse.props.errors = currentErrors;
2443
+ const nestedTopKeys = new Set(
2444
+ [...this.requestParams.all().only, ...this.requestParams.all().except].filter((prop) => prop.includes(".")).map((prop) => prop.split(".")[0])
2445
+ );
2446
+ for (const key of nestedTopKeys) {
2447
+ const currentValue = page.get().props[key];
2448
+ if (this.isObject(currentValue) && this.isObject(pageResponse.props[key])) {
2449
+ pageResponse.props[key] = this.deepMergeObjects(currentValue, pageResponse.props[key]);
2170
2450
  }
2171
2451
  }
2452
+ pageResponse.props = { ...page.get().props, ...pageResponse.props };
2453
+ if (this.shouldPreserveErrors(pageResponse)) {
2454
+ pageResponse.props.errors = page.get().props.errors;
2455
+ }
2172
2456
  if (page.get().scrollProps) {
2173
2457
  pageResponse.scrollProps = {
2174
2458
  ...page.get().scrollProps || {},
@@ -2190,6 +2474,42 @@ var Response = class _Response {
2190
2474
  pageResponse.initialDeferredProps = currentOriginalDeferred;
2191
2475
  }
2192
2476
  }
2477
+ /**
2478
+ * By default, the Laravel adapter shares validation errors via Inertia::always(),
2479
+ * so responses always include errors, even when empty. Components like
2480
+ * InfiniteScroll and WhenVisible, as well as loading deferred props,
2481
+ * perform async requests that should practically never reset errors.
2482
+ */
2483
+ shouldPreserveErrors(pageResponse) {
2484
+ if (!this.requestParams.all().preserveErrors) {
2485
+ return false;
2486
+ }
2487
+ const currentErrors = page.get().props.errors;
2488
+ if (!currentErrors || Object.keys(currentErrors).length === 0) {
2489
+ return false;
2490
+ }
2491
+ const responseErrors = pageResponse.props.errors;
2492
+ if (responseErrors && Object.keys(responseErrors).length > 0) {
2493
+ return false;
2494
+ }
2495
+ return true;
2496
+ }
2497
+ isObject(item) {
2498
+ return item && typeof item === "object" && !Array.isArray(item);
2499
+ }
2500
+ deepMergeObjects(target, source) {
2501
+ const result = { ...target };
2502
+ for (const key of Object.keys(source)) {
2503
+ const targetValue = target[key];
2504
+ const sourceValue = source[key];
2505
+ if (this.isObject(targetValue) && this.isObject(sourceValue)) {
2506
+ result[key] = this.deepMergeObjects(targetValue, sourceValue);
2507
+ } else {
2508
+ result[key] = sourceValue;
2509
+ }
2510
+ }
2511
+ return result;
2512
+ }
2193
2513
  mergeOrMatchItems(existingItems, newItems, matchProp, matchPropsOn, shouldAppend = true) {
2194
2514
  const items = Array.isArray(existingItems) ? existingItems : [];
2195
2515
  const matchingKey = matchPropsOn.find((key) => {
@@ -2253,18 +2573,25 @@ var Response = class _Response {
2253
2573
 
2254
2574
  // src/request.ts
2255
2575
  var Request = class _Request {
2256
- constructor(params, page2) {
2576
+ constructor(params, page2, { optimistic = false } = {}) {
2257
2577
  this.page = page2;
2258
2578
  this.requestHasFinished = false;
2259
2579
  this.requestParams = RequestParams.create(params);
2260
2580
  this.cancelToken = new AbortController();
2581
+ this.optimistic = optimistic;
2261
2582
  }
2262
- static create(params, page2) {
2263
- return new _Request(params, page2);
2583
+ static create(params, page2, options) {
2584
+ return new _Request(params, page2, options);
2264
2585
  }
2265
2586
  isPrefetch() {
2266
2587
  return this.requestParams.isPrefetch();
2267
2588
  }
2589
+ isOptimistic() {
2590
+ return this.optimistic;
2591
+ }
2592
+ isPendingOptimistic() {
2593
+ return this.isOptimistic() && (!this.response || !this.response.isProcessed());
2594
+ }
2268
2595
  async send() {
2269
2596
  this.requestParams.onCancelToken(() => this.cancel({ cancelled: true }));
2270
2597
  fireStartEvent(this.requestParams.all());
@@ -2274,31 +2601,30 @@ var Request = class _Request {
2274
2601
  firePrefetchingEvent(this.requestParams.all());
2275
2602
  }
2276
2603
  const originallyPrefetch = this.requestParams.all().prefetch;
2277
- return (0, import_axios.default)({
2604
+ return http.getClient().request({
2278
2605
  method: this.requestParams.all().method,
2279
2606
  url: urlWithoutHash(this.requestParams.all().url).href,
2280
2607
  data: this.requestParams.data(),
2281
- params: this.requestParams.queryParams(),
2282
2608
  signal: this.cancelToken.signal,
2283
2609
  headers: this.getHeaders(),
2284
- onUploadProgress: this.onProgress.bind(this),
2285
- // Why text? This allows us to delay JSON.parse until we're ready to use the response,
2286
- // helps with performance particularly on large responses + history encryption
2287
- responseType: "text"
2610
+ onUploadProgress: this.onProgress.bind(this)
2288
2611
  }).then((response) => {
2289
2612
  this.response = Response.create(this.requestParams, response, this.page);
2290
2613
  return this.response.handle();
2291
2614
  }).catch((error) => {
2292
- if (error?.response) {
2615
+ if (error instanceof HttpResponseError) {
2293
2616
  this.response = Response.create(this.requestParams, error.response, this.page);
2294
2617
  return this.response.handle();
2295
2618
  }
2296
2619
  return Promise.reject(error);
2297
2620
  }).catch((error) => {
2298
- if (import_axios.default.isCancel(error)) {
2621
+ if (error instanceof HttpCancelledError) {
2622
+ return;
2623
+ }
2624
+ if (this.requestParams.all().onNetworkError(error) === false) {
2299
2625
  return;
2300
2626
  }
2301
- if (fireExceptionEvent(error)) {
2627
+ if (fireNetworkErrorEvent(error)) {
2302
2628
  if (originallyPrefetch) {
2303
2629
  this.requestParams.onPrefetchError(error);
2304
2630
  }
@@ -2353,7 +2679,7 @@ var Request = class _Request {
2353
2679
  headers["X-Inertia-Version"] = page2.version;
2354
2680
  }
2355
2681
  const onceProps = Object.entries(page2.onceProps || {}).filter(([, onceProp]) => {
2356
- if (page2.props[onceProp.prop] === void 0) {
2682
+ if (get6(page2.props, onceProp.prop) === void 0) {
2357
2683
  return false;
2358
2684
  }
2359
2685
  return !onceProp.expiresAt || onceProp.expiresAt > Date.now();
@@ -2381,8 +2707,8 @@ var RequestStream = class {
2381
2707
  interruptInFlight() {
2382
2708
  this.cancel({ interrupted: true }, false);
2383
2709
  }
2384
- cancelInFlight({ prefetch = true } = {}) {
2385
- this.requests.filter((request) => prefetch || !request.isPrefetch()).forEach((request) => request.cancel({ cancelled: true }));
2710
+ cancelInFlight({ prefetch = true, optimistic = true } = {}) {
2711
+ this.requests.filter((request) => prefetch || !request.isPrefetch()).filter((request) => optimistic || !request.isOptimistic()).forEach((request) => request.cancel({ cancelled: true }));
2386
2712
  }
2387
2713
  cancel({ cancelled = false, interrupted = false } = {}, force = false) {
2388
2714
  if (!force && !this.shouldCancel()) {
@@ -2394,9 +2720,14 @@ var RequestStream = class {
2394
2720
  shouldCancel() {
2395
2721
  return this.interruptible && this.requests.length >= this.maxConcurrent;
2396
2722
  }
2723
+ hasPendingOptimistic() {
2724
+ return this.requests.some((request) => request.isPendingOptimistic());
2725
+ }
2397
2726
  };
2398
2727
 
2399
2728
  // src/router.ts
2729
+ var noop = () => {
2730
+ };
2400
2731
  var Router = class {
2401
2732
  constructor() {
2402
2733
  this.syncRequestStream = new RequestStream({
@@ -2408,6 +2739,7 @@ var Router = class {
2408
2739
  interruptible: false
2409
2740
  });
2410
2741
  this.clientVisitQueue = new Queue();
2742
+ this.pendingOptimisticCallback = void 0;
2411
2743
  }
2412
2744
  init({
2413
2745
  initialPage,
@@ -2435,6 +2767,10 @@ var Router = class {
2435
2767
  window.location.href = url;
2436
2768
  });
2437
2769
  }
2770
+ optimistic(callback) {
2771
+ this.pendingOptimisticCallback = callback;
2772
+ return this;
2773
+ }
2438
2774
  get(url, data = {}, options = {}) {
2439
2775
  return this.visit(url, { ...options, method: "get", data });
2440
2776
  }
@@ -2487,6 +2823,9 @@ var Router = class {
2487
2823
  cancel() {
2488
2824
  this.syncRequestStream.cancelInFlight();
2489
2825
  }
2826
+ hasPendingOptimistic() {
2827
+ return this.asyncRequestStream.hasPendingOptimistic();
2828
+ }
2490
2829
  cancelAll({ async = true, prefetch = true, sync = true } = {}) {
2491
2830
  if (async) {
2492
2831
  this.asyncRequestStream.cancelInFlight({ prefetch });
@@ -2496,15 +2835,20 @@ var Router = class {
2496
2835
  }
2497
2836
  }
2498
2837
  poll(interval, requestOptions = {}, options = {}) {
2499
- return polls.add(interval, () => this.reload(requestOptions), {
2838
+ return polls.add(interval, () => this.reload({ preserveErrors: true, ...requestOptions }), {
2500
2839
  autoStart: options.autoStart ?? true,
2501
2840
  keepAlive: options.keepAlive ?? false
2502
2841
  });
2503
2842
  }
2504
2843
  visit(href, options = {}) {
2844
+ options.optimistic = options.optimistic ?? this.pendingOptimisticCallback;
2845
+ this.pendingOptimisticCallback = void 0;
2846
+ if (options.optimistic) {
2847
+ options.async = options.async ?? true;
2848
+ }
2505
2849
  const visit = this.getPendingVisit(href, {
2506
2850
  ...options,
2507
- showProgress: options.showProgress ?? !options.async
2851
+ showProgress: options.showProgress ?? (!options.async || !!options.optimistic)
2508
2852
  });
2509
2853
  const events = this.getVisitEvents(options);
2510
2854
  if (events.onBefore(visit) === false || !fireBeforeEvent(visit)) {
@@ -2514,11 +2858,14 @@ var Router = class {
2514
2858
  const isPartialReload = visit.only.length > 0 || visit.except.length > 0 || visit.reset.length > 0;
2515
2859
  const isSamePage = isPartialReload ? isSameUrlWithoutQueryOrHash(visit.url, currentPageUrl) : isSameUrlWithoutHash(visit.url, currentPageUrl);
2516
2860
  if (!isSamePage) {
2517
- this.asyncRequestStream.cancelInFlight({ prefetch: false });
2861
+ this.asyncRequestStream.cancelInFlight({ prefetch: false, optimistic: false });
2518
2862
  }
2519
2863
  if (!visit.async) {
2520
2864
  this.syncRequestStream.interruptInFlight();
2521
2865
  }
2866
+ if (options.optimistic) {
2867
+ this.applyOptimisticUpdate(options.optimistic, events);
2868
+ }
2522
2869
  if (!page.isCleared() && !visit.preserveUrl) {
2523
2870
  Scroll.save();
2524
2871
  }
@@ -2526,14 +2873,34 @@ var Router = class {
2526
2873
  ...visit,
2527
2874
  ...events
2528
2875
  };
2529
- const prefetched = prefetchedRequests.get(requestParams);
2530
- if (prefetched) {
2531
- progress.reveal(prefetched.inFlight);
2532
- prefetchedRequests.use(prefetched, requestParams);
2876
+ const sendRequest = () => {
2877
+ const prefetched = prefetchedRequests.get(requestParams);
2878
+ if (prefetched) {
2879
+ progress.reveal(prefetched.inFlight);
2880
+ prefetchedRequests.use(prefetched, requestParams);
2881
+ } else {
2882
+ progress.reveal(true);
2883
+ const requestStream = visit.async ? this.asyncRequestStream : this.syncRequestStream;
2884
+ requestStream.send(Request.create(requestParams, page.get(), { optimistic: !!options.optimistic }));
2885
+ }
2886
+ };
2887
+ if (Array.isArray(visit.component)) {
2888
+ console.error(
2889
+ `The "component" prop received an array of components (${visit.component.join(", ")}), but only a single component string is supported for instant visits. Pass an explicit component name instead.`
2890
+ );
2891
+ visit.component = null;
2892
+ }
2893
+ if (visit.component) {
2894
+ history.processQueue().then(() => {
2895
+ this.performInstantSwap(visit).then(() => {
2896
+ requestParams.preserveState = true;
2897
+ requestParams.replace = true;
2898
+ requestParams.viewTransition = false;
2899
+ sendRequest();
2900
+ });
2901
+ });
2533
2902
  } else {
2534
- progress.reveal(true);
2535
- const requestStream = visit.async ? this.asyncRequestStream : this.syncRequestStream;
2536
- requestStream.send(Request.create(requestParams, page.get()));
2903
+ sendRequest();
2537
2904
  }
2538
2905
  }
2539
2906
  getCached(href, options = {}) {
@@ -2610,8 +2977,8 @@ var Router = class {
2610
2977
  decryptHistory() {
2611
2978
  return history.decrypt();
2612
2979
  }
2613
- resolveComponent(component) {
2614
- return page.resolve(component);
2980
+ resolveComponent(component, page2) {
2981
+ return page.resolve(component, page2);
2615
2982
  }
2616
2983
  replace(params) {
2617
2984
  this.clientVisit(params, { replace: true });
@@ -2621,8 +2988,8 @@ var Router = class {
2621
2988
  preserveScroll: true,
2622
2989
  preserveState: true,
2623
2990
  props(currentProps) {
2624
- const newValue = typeof value === "function" ? value((0, import_lodash_es5.get)(currentProps, name), currentProps) : value;
2625
- return (0, import_lodash_es5.set)((0, import_lodash_es5.cloneDeep)(currentProps), name, newValue);
2991
+ const newValue = typeof value === "function" ? value(get7(currentProps, name), currentProps) : value;
2992
+ return set5(cloneDeep3(currentProps), name, newValue);
2626
2993
  },
2627
2994
  ...options || {}
2628
2995
  });
@@ -2679,7 +3046,10 @@ var Router = class {
2679
3046
  performClientVisit(params, { replace = false } = {}) {
2680
3047
  const current = page.get();
2681
3048
  const onceProps = typeof params.props === "function" ? Object.fromEntries(
2682
- Object.values(current.onceProps ?? {}).map((onceProp) => [onceProp.prop, current.props[onceProp.prop]])
3049
+ Object.values(current.onceProps ?? {}).map((onceProp) => [
3050
+ onceProp.prop,
3051
+ get7(current.props, onceProp.prop)
3052
+ ])
2683
3053
  ) : {};
2684
3054
  const props = typeof params.props === "function" ? params.props(current.props, onceProps) : params.props ?? current.props;
2685
3055
  const flash = typeof params.flash === "function" ? params.flash(current.flash) : params.flash;
@@ -2712,6 +3082,34 @@ var Router = class {
2712
3082
  onError?.(scopedErrors);
2713
3083
  }).finally(() => onFinish?.(params));
2714
3084
  }
3085
+ performInstantSwap(visit) {
3086
+ const current = page.get();
3087
+ const sharedProps = Object.fromEntries(
3088
+ (current.sharedProps ?? []).filter((key) => key in current.props).map((key) => [key, current.props[key]])
3089
+ );
3090
+ const resolvedPageProps = typeof visit.pageProps === "function" ? visit.pageProps(cloneDeep3(current.props), cloneDeep3(sharedProps)) : visit.pageProps;
3091
+ const intermediateProps = resolvedPageProps !== null ? { ...resolvedPageProps } : { ...sharedProps };
3092
+ const intermediatePage = {
3093
+ component: visit.component,
3094
+ url: visit.url.pathname + visit.url.search + visit.url.hash,
3095
+ version: current.version,
3096
+ props: {
3097
+ ...intermediateProps,
3098
+ errors: {}
3099
+ },
3100
+ flash: {},
3101
+ clearHistory: false,
3102
+ encryptHistory: current.encryptHistory,
3103
+ sharedProps: current.sharedProps,
3104
+ rememberedState: {}
3105
+ };
3106
+ return page.set(intermediatePage, {
3107
+ replace: visit.replace,
3108
+ preserveScroll: RequestParams.resolvePreserveOption(visit.preserveScroll, intermediatePage),
3109
+ preserveState: false,
3110
+ viewTransition: visit.viewTransition
3111
+ });
3112
+ }
2715
3113
  getPrefetchParams(href, options) {
2716
3114
  return {
2717
3115
  ...this.getPendingVisit(href, {
@@ -2724,14 +3122,14 @@ var Router = class {
2724
3122
  ...this.getVisitEvents(options)
2725
3123
  };
2726
3124
  }
2727
- getPendingVisit(href, options, pendingVisitOptions = {}) {
3125
+ getPendingVisit(href, options) {
2728
3126
  if (isUrlMethodPair(href)) {
2729
3127
  const urlMethodPair = href;
2730
3128
  href = urlMethodPair.url;
2731
3129
  options.method = options.method ?? urlMethodPair.method;
2732
3130
  }
2733
3131
  const defaultVisitOptionsCallback = config.get("visitOptions");
2734
- const configuredOptions = defaultVisitOptionsCallback ? defaultVisitOptionsCallback(href.toString(), (0, import_lodash_es5.cloneDeep)(options)) || {} : {};
3132
+ const configuredOptions = defaultVisitOptionsCallback ? defaultVisitOptionsCallback(href.toString(), cloneDeep3(options)) || {} : {};
2735
3133
  const mergedOptions = {
2736
3134
  method: "get",
2737
3135
  data: {},
@@ -2749,9 +3147,12 @@ var Router = class {
2749
3147
  fresh: false,
2750
3148
  reset: [],
2751
3149
  preserveUrl: false,
3150
+ preserveErrors: false,
2752
3151
  prefetch: false,
2753
3152
  invalidateCacheTags: [],
2754
3153
  viewTransition: false,
3154
+ component: null,
3155
+ pageProps: null,
2755
3156
  ...options,
2756
3157
  ...configuredOptions
2757
3158
  };
@@ -2767,7 +3168,6 @@ var Router = class {
2767
3168
  completed: false,
2768
3169
  interrupted: false,
2769
3170
  ...mergedOptions,
2770
- ...pendingVisitOptions,
2771
3171
  url,
2772
3172
  data: _data
2773
3173
  };
@@ -2778,36 +3178,66 @@ var Router = class {
2778
3178
  }
2779
3179
  getVisitEvents(options) {
2780
3180
  return {
2781
- onCancelToken: options.onCancelToken || (() => {
2782
- }),
2783
- onBefore: options.onBefore || (() => {
2784
- }),
2785
- onBeforeUpdate: options.onBeforeUpdate || (() => {
2786
- }),
2787
- onStart: options.onStart || (() => {
2788
- }),
2789
- onProgress: options.onProgress || (() => {
2790
- }),
2791
- onFinish: options.onFinish || (() => {
2792
- }),
2793
- onCancel: options.onCancel || (() => {
2794
- }),
2795
- onSuccess: options.onSuccess || (() => {
2796
- }),
2797
- onError: options.onError || (() => {
2798
- }),
2799
- onFlash: options.onFlash || (() => {
2800
- }),
2801
- onPrefetched: options.onPrefetched || (() => {
2802
- }),
2803
- onPrefetching: options.onPrefetching || (() => {
2804
- })
3181
+ onCancelToken: options.onCancelToken || noop,
3182
+ onBefore: options.onBefore || noop,
3183
+ onBeforeUpdate: options.onBeforeUpdate || noop,
3184
+ onStart: options.onStart || noop,
3185
+ onProgress: options.onProgress || noop,
3186
+ onFinish: options.onFinish || noop,
3187
+ onCancel: options.onCancel || noop,
3188
+ onSuccess: options.onSuccess || noop,
3189
+ onError: options.onError || noop,
3190
+ onHttpException: options.onHttpException || noop,
3191
+ onNetworkError: options.onNetworkError || noop,
3192
+ onFlash: options.onFlash || noop,
3193
+ onPrefetched: options.onPrefetched || noop,
3194
+ onPrefetching: options.onPrefetching || noop
3195
+ };
3196
+ }
3197
+ applyOptimisticUpdate(optimistic, events) {
3198
+ const currentProps = page.get().props;
3199
+ const optimisticProps = optimistic(cloneDeep3(currentProps));
3200
+ if (!optimisticProps) {
3201
+ return;
3202
+ }
3203
+ const propsSnapshot = {};
3204
+ for (const key of Object.keys(optimisticProps)) {
3205
+ if (!isEqual3(currentProps[key], optimisticProps[key])) {
3206
+ propsSnapshot[key] = cloneDeep3(currentProps[key]);
3207
+ }
3208
+ }
3209
+ if (Object.keys(propsSnapshot).length === 0) {
3210
+ return;
3211
+ }
3212
+ const updatedAt = Date.now();
3213
+ page.recordOptimisticUpdate(Object.keys(propsSnapshot), updatedAt);
3214
+ page.setPropsQuietly({ ...currentProps, ...optimisticProps });
3215
+ let shouldRestore = true;
3216
+ const originalOnSuccess = events.onSuccess;
3217
+ events.onSuccess = (page2) => {
3218
+ shouldRestore = false;
3219
+ return originalOnSuccess(page2);
3220
+ };
3221
+ const originalOnFinish = events.onFinish;
3222
+ events.onFinish = (visit) => {
3223
+ if (shouldRestore) {
3224
+ const propsToRestore = {};
3225
+ for (const [key, value] of Object.entries(propsSnapshot)) {
3226
+ if (!page.shouldPreserveOptimistic(key, updatedAt)) {
3227
+ propsToRestore[key] = value;
3228
+ }
3229
+ }
3230
+ if (Object.keys(propsToRestore).length > 0) {
3231
+ page.setPropsQuietly({ ...page.get().props, ...propsToRestore });
3232
+ }
3233
+ }
3234
+ return originalOnFinish(visit);
2805
3235
  };
2806
3236
  }
2807
3237
  loadDeferredProps(deferred) {
2808
3238
  if (deferred) {
2809
- Object.entries(deferred).forEach(([_, group]) => {
2810
- this.doReload({ only: group, deferredProps: true });
3239
+ Object.values(deferred).forEach((props) => {
3240
+ this.doReload({ only: props, deferredProps: true, preserveErrors: true });
2811
3241
  });
2812
3242
  }
2813
3243
  }
@@ -2923,8 +3353,102 @@ var UseFormUtils = class {
2923
3353
  }
2924
3354
  };
2925
3355
 
3356
+ // src/axiosHttpClient.ts
3357
+ import axios from "axios";
3358
+ function normalizeHeaders(headers) {
3359
+ if (!headers || typeof headers !== "object") {
3360
+ return {};
3361
+ }
3362
+ const normalized = {};
3363
+ const entries = typeof headers.entries === "function" ? Array.from(headers.entries()) : Object.entries(headers);
3364
+ for (const [key, value] of entries) {
3365
+ if (typeof value === "string") {
3366
+ normalized[key.toLowerCase()] = value;
3367
+ } else if (Array.isArray(value)) {
3368
+ normalized[key.toLowerCase()] = value.join(", ");
3369
+ }
3370
+ }
3371
+ return normalized;
3372
+ }
3373
+ function toHttpProgressEvent(axiosEvent) {
3374
+ return {
3375
+ progress: axiosEvent.progress,
3376
+ loaded: axiosEvent.loaded,
3377
+ total: axiosEvent.total
3378
+ };
3379
+ }
3380
+ var AxiosHttpClient = class {
3381
+ constructor(instance) {
3382
+ this.axios = instance;
3383
+ }
3384
+ async getAxios() {
3385
+ if (!this.axios) {
3386
+ return this.axios = axios;
3387
+ }
3388
+ return this.axios;
3389
+ }
3390
+ async request(config2) {
3391
+ const processedConfig = await httpHandlers.processRequest(config2);
3392
+ try {
3393
+ const response = await this.doRequest(processedConfig);
3394
+ return await httpHandlers.processResponse(response);
3395
+ } catch (error) {
3396
+ if (error instanceof HttpResponseError || error instanceof HttpNetworkError || error instanceof HttpCancelledError) {
3397
+ await httpHandlers.processError(error);
3398
+ }
3399
+ throw error;
3400
+ }
3401
+ }
3402
+ async doRequest(config2) {
3403
+ const axios2 = await this.getAxios();
3404
+ try {
3405
+ const response = await axios2({
3406
+ method: config2.method,
3407
+ url: config2.url,
3408
+ data: config2.data,
3409
+ params: config2.params,
3410
+ headers: config2.headers,
3411
+ signal: config2.signal,
3412
+ responseType: "text",
3413
+ onUploadProgress: config2.onUploadProgress ? (event) => config2.onUploadProgress(toHttpProgressEvent(event)) : void 0
3414
+ });
3415
+ return {
3416
+ status: response.status,
3417
+ data: response.data,
3418
+ headers: normalizeHeaders(response.headers)
3419
+ };
3420
+ } catch (error) {
3421
+ const axiosModule = await import("axios");
3422
+ if (axiosModule.default.isCancel(error)) {
3423
+ throw new HttpCancelledError("Request was cancelled", config2.url);
3424
+ }
3425
+ if (error && typeof error === "object" && "response" in error) {
3426
+ const axiosError = error;
3427
+ const httpResponse = {
3428
+ status: axiosError.response.status,
3429
+ data: axiosError.response.data,
3430
+ headers: normalizeHeaders(axiosError.response.headers)
3431
+ };
3432
+ throw new HttpResponseError(
3433
+ `Request failed with status ${axiosError.response.status}`,
3434
+ httpResponse,
3435
+ config2.url
3436
+ );
3437
+ }
3438
+ throw new HttpNetworkError(
3439
+ error instanceof Error ? error.message : "Network error",
3440
+ config2.url,
3441
+ error instanceof Error ? error : void 0
3442
+ );
3443
+ }
3444
+ }
3445
+ };
3446
+ function axiosAdapter(instance) {
3447
+ return new AxiosHttpClient(instance);
3448
+ }
3449
+
2926
3450
  // src/formObject.ts
2927
- var import_lodash_es6 = require("lodash-es");
3451
+ import { get as get8, set as set6 } from "lodash-es";
2928
3452
  function undotKey(key) {
2929
3453
  if (!key.includes(".")) {
2930
3454
  return key;
@@ -2937,7 +3461,7 @@ function undotKey(key) {
2937
3461
  };
2938
3462
  return key.replace(/\\\./g, "__ESCAPED_DOT__").split(/(\[[^\]]*\])/).filter(Boolean).map(transformSegment).join("").replace(/__ESCAPED_DOT__/g, ".");
2939
3463
  }
2940
- function parseKey(key) {
3464
+ function parseKey2(key) {
2941
3465
  const path = [];
2942
3466
  const pattern = /([^\[\]]+)|\[(\d*)\]/g;
2943
3467
  let match;
@@ -2991,17 +3515,17 @@ function formDataToObject(source) {
2991
3515
  if (value instanceof File && value.size === 0 && value.name === "") {
2992
3516
  continue;
2993
3517
  }
2994
- const path = parseKey(undotKey(key));
3518
+ const path = parseKey2(undotKey(key));
2995
3519
  if (path[path.length - 1] === "") {
2996
3520
  const arrayPath = path.slice(0, -1);
2997
- const existing = (0, import_lodash_es6.get)(form, arrayPath);
3521
+ const existing = get8(form, arrayPath);
2998
3522
  if (Array.isArray(existing)) {
2999
3523
  existing.push(value);
3000
3524
  } else if (existing && typeof existing === "object" && !isFile(existing)) {
3001
3525
  const numericKeys = Object.keys(existing).filter((k) => /^\d+$/.test(k)).map(Number).sort((a, b) => a - b);
3002
- (0, import_lodash_es6.set)(form, arrayPath, numericKeys.length > 0 ? [...numericKeys.map((k) => existing[k]), value] : [value]);
3526
+ set6(form, arrayPath, numericKeys.length > 0 ? [...numericKeys.map((k) => existing[k]), value] : [value]);
3003
3527
  } else {
3004
- (0, import_lodash_es6.set)(form, arrayPath, [value]);
3528
+ set6(form, arrayPath, [value]);
3005
3529
  }
3006
3530
  continue;
3007
3531
  }
@@ -3012,9 +3536,6 @@ function formDataToObject(source) {
3012
3536
 
3013
3537
  // src/head.ts
3014
3538
  var Renderer = {
3015
- preferredAttribute() {
3016
- return config.get("future.useDataInertiaHeadAttribute") ? "data-inertia" : "inertia";
3017
- },
3018
3539
  buildDOMElement(tag) {
3019
3540
  const template = document.createElement("template");
3020
3541
  template.innerHTML = tag;
@@ -3030,13 +3551,12 @@ var Renderer = {
3030
3551
  return script;
3031
3552
  },
3032
3553
  isInertiaManagedElement(element) {
3033
- return element.nodeType === Node.ELEMENT_NODE && element.getAttribute(this.preferredAttribute()) !== null;
3554
+ return element.nodeType === Node.ELEMENT_NODE && element.getAttribute("data-inertia") !== null;
3034
3555
  },
3035
3556
  findMatchingElementIndex(element, elements) {
3036
- const attribute = this.preferredAttribute();
3037
- const key = element.getAttribute(attribute);
3557
+ const key = element.getAttribute("data-inertia");
3038
3558
  if (key !== null) {
3039
- return elements.findIndex((element2) => element2.getAttribute(attribute) === key);
3559
+ return elements.findIndex((element2) => element2.getAttribute("data-inertia") === key);
3040
3560
  }
3041
3561
  return -1;
3042
3562
  },
@@ -3048,12 +3568,12 @@ var Renderer = {
3048
3568
  targetElements.forEach((targetElement) => {
3049
3569
  const index = this.findMatchingElementIndex(targetElement, sourceElements);
3050
3570
  if (index === -1) {
3051
- targetElement?.parentNode?.removeChild(targetElement);
3571
+ targetElement.remove();
3052
3572
  return;
3053
3573
  }
3054
3574
  const sourceElement = sourceElements.splice(index, 1)[0];
3055
3575
  if (sourceElement && !targetElement.isEqualNode(sourceElement)) {
3056
- targetElement?.parentNode?.replaceChild(sourceElement, targetElement);
3576
+ targetElement.replaceWith(sourceElement);
3057
3577
  }
3058
3578
  });
3059
3579
  sourceElements.forEach((element) => document.head.appendChild(element));
@@ -3087,9 +3607,8 @@ function createHeadManager(isServer3, titleCallback, onUpdate) {
3087
3607
  }
3088
3608
  function collect() {
3089
3609
  const title = titleCallback("");
3090
- const attribute = Renderer.preferredAttribute();
3091
3610
  const defaults = {
3092
- ...title ? { title: `<title ${attribute}="">${title}</title>` } : {}
3611
+ ...title ? { title: `<title data-inertia="">${title}</title>` } : {}
3093
3612
  };
3094
3613
  const elements = Object.values(states).reduce((carry, elements2) => carry.concat(elements2), []).reduce((carry, element) => {
3095
3614
  if (element.indexOf("<") === -1) {
@@ -3100,7 +3619,7 @@ function createHeadManager(isServer3, titleCallback, onUpdate) {
3100
3619
  carry.title = title2 ? `${title2[1]}${titleCallback(title2[2])}${title2[3]}` : element;
3101
3620
  return carry;
3102
3621
  }
3103
- const match = element.match(attribute === "inertia" ? / inertia="[^"]+"/ : / data-inertia="[^"]+"/);
3622
+ const match = element.match(/ data-inertia="[^"]+"/);
3104
3623
  if (match) {
3105
3624
  carry[match[0]] = element;
3106
3625
  } else {
@@ -3119,7 +3638,6 @@ function createHeadManager(isServer3, titleCallback, onUpdate) {
3119
3638
  createProvider: function() {
3120
3639
  const id = connect();
3121
3640
  return {
3122
- preferredAttribute: Renderer.preferredAttribute,
3123
3641
  reconnect: () => reconnect(id),
3124
3642
  update: (elements) => update(id, elements),
3125
3643
  disconnect: () => disconnect(id)
@@ -3204,9 +3722,10 @@ var useInfiniteScrollData = (options) => {
3204
3722
  }
3205
3723
  state.loading = true;
3206
3724
  router.reload({
3725
+ preserveErrors: true,
3207
3726
  ...reloadOptions,
3208
- data: { [getPageName()]: page2 },
3209
- only: [options.getPropName()],
3727
+ data: { ...reloadOptions.data || {}, [getPageName()]: page2 },
3728
+ only: [...reloadOptions.only || [], options.getPropName()],
3210
3729
  preserveUrl: true,
3211
3730
  // we handle URL updates manually via useInfiniteScrollQueryString()
3212
3731
  headers: {
@@ -3607,6 +4126,7 @@ function useInfiniteScroll(options) {
3607
4126
  };
3608
4127
  const originalFetchNext = dataManager.fetchNext;
3609
4128
  dataManager.fetchNext = (reloadOptions = {}) => {
4129
+ reloadOptions = { ...options.getReloadOptions?.(), ...reloadOptions };
3610
4130
  if (options.inReverseMode()) {
3611
4131
  reloadOptions = addScrollPreservationCallbacks(reloadOptions);
3612
4132
  }
@@ -3614,6 +4134,7 @@ function useInfiniteScroll(options) {
3614
4134
  };
3615
4135
  const originalFetchPrevious = dataManager.fetchPrevious;
3616
4136
  dataManager.fetchPrevious = (reloadOptions = {}) => {
4137
+ reloadOptions = { ...options.getReloadOptions?.(), ...reloadOptions };
3617
4138
  if (!options.inReverseMode()) {
3618
4139
  reloadOptions = addScrollPreservationCallbacks(reloadOptions);
3619
4140
  }
@@ -3632,6 +4153,121 @@ function useInfiniteScroll(options) {
3632
4153
  };
3633
4154
  }
3634
4155
 
4156
+ // src/layout.ts
4157
+ import { isEqual as isEqual4 } from "lodash-es";
4158
+ function createLayoutPropsStore() {
4159
+ let shared = {};
4160
+ let named = {};
4161
+ let snapshot = { shared, named };
4162
+ const listeners = /* @__PURE__ */ new Set();
4163
+ let pendingNotify = false;
4164
+ const updateSnapshot = () => {
4165
+ snapshot = { shared, named };
4166
+ };
4167
+ const notify = () => {
4168
+ if (pendingNotify) {
4169
+ return;
4170
+ }
4171
+ pendingNotify = true;
4172
+ queueMicrotask(() => {
4173
+ pendingNotify = false;
4174
+ listeners.forEach((fn) => fn());
4175
+ });
4176
+ };
4177
+ return {
4178
+ set(props) {
4179
+ const merged = { ...shared, ...props };
4180
+ if (isEqual4(shared, merged)) {
4181
+ return;
4182
+ }
4183
+ shared = merged;
4184
+ updateSnapshot();
4185
+ notify();
4186
+ },
4187
+ setFor(name, props) {
4188
+ const current = named[name] || {};
4189
+ const merged = { ...current, ...props };
4190
+ if (isEqual4(current, merged)) {
4191
+ return;
4192
+ }
4193
+ named = { ...named, [name]: merged };
4194
+ updateSnapshot();
4195
+ notify();
4196
+ },
4197
+ reset() {
4198
+ shared = {};
4199
+ named = {};
4200
+ updateSnapshot();
4201
+ notify();
4202
+ },
4203
+ subscribe(callback) {
4204
+ listeners.add(callback);
4205
+ return () => listeners.delete(callback);
4206
+ },
4207
+ get: () => snapshot
4208
+ };
4209
+ }
4210
+ function mergeLayoutProps(defaults, staticProps, dynamicProps) {
4211
+ const result = { ...defaults };
4212
+ for (const key of Object.keys(defaults)) {
4213
+ if (key in staticProps && staticProps[key] !== void 0) {
4214
+ result[key] = staticProps[key];
4215
+ }
4216
+ if (key in dynamicProps && dynamicProps[key] !== void 0) {
4217
+ result[key] = dynamicProps[key];
4218
+ }
4219
+ }
4220
+ return result;
4221
+ }
4222
+ function isPlainObject(value) {
4223
+ return typeof value === "object" && value !== null && !Array.isArray(value);
4224
+ }
4225
+ function hasComponentKey(value) {
4226
+ return isPlainObject(value) && "component" in value;
4227
+ }
4228
+ function isNamedLayouts(value, isComponent) {
4229
+ if (!isPlainObject(value) || isComponent(value) || "component" in value) {
4230
+ return false;
4231
+ }
4232
+ return Object.values(value).some((v) => isComponent(v) || Array.isArray(v) && isComponent(v[0]));
4233
+ }
4234
+ function isTuple(value, isComponent) {
4235
+ return Array.isArray(value) && value.length === 2 && isComponent(value[0]) && isPlainObject(value[1]) && !isComponent(value[1]);
4236
+ }
4237
+ function extract(item, isComponent) {
4238
+ if (Array.isArray(item) && isComponent(item[0])) {
4239
+ return { component: item[0], props: item[1] ?? {} };
4240
+ }
4241
+ if (hasComponentKey(item) && isComponent(item.component)) {
4242
+ return { component: item.component, props: item.props ?? {} };
4243
+ }
4244
+ if (isComponent(item)) {
4245
+ return { component: item, props: {} };
4246
+ }
4247
+ throw new Error(`Invalid layout definition: received ${typeof item}`);
4248
+ }
4249
+ function normalizeLayouts(layout, isComponent, isRenderFunction) {
4250
+ if (!layout || isRenderFunction && isRenderFunction(layout)) {
4251
+ return [];
4252
+ }
4253
+ if (isNamedLayouts(layout, isComponent)) {
4254
+ return Object.entries(layout).map(([name, value]) => ({ ...extract(value, isComponent), name }));
4255
+ }
4256
+ if (isTuple(layout, isComponent)) {
4257
+ return [{ component: layout[0], props: layout[1] ?? {} }];
4258
+ }
4259
+ if (Array.isArray(layout)) {
4260
+ return layout.map((item) => extract(item, isComponent));
4261
+ }
4262
+ if (hasComponentKey(layout) && isComponent(layout.component)) {
4263
+ return [{ component: layout.component, props: layout.props ?? {} }];
4264
+ }
4265
+ if (isComponent(layout)) {
4266
+ return [{ component: layout, props: {} }];
4267
+ }
4268
+ return [];
4269
+ }
4270
+
3635
4271
  // src/navigationEvents.ts
3636
4272
  function isContentEditableOrPrevented(event) {
3637
4273
  return event.target instanceof HTMLElement && event.target.isContentEditable || event.defaultPrevented;
@@ -3647,11 +4283,11 @@ function shouldNavigate(event) {
3647
4283
 
3648
4284
  // src/progress-component.ts
3649
4285
  var baseComponentSelector = "nprogress";
4286
+ var usePopover;
3650
4287
  var progress2;
3651
4288
  var settings = {
3652
4289
  minimum: 0.08,
3653
4290
  easing: "linear",
3654
- positionUsing: "translate3d",
3655
4291
  speed: 200,
3656
4292
  trickle: true,
3657
4293
  trickleSpeed: 200,
@@ -3661,6 +4297,7 @@ var settings = {
3661
4297
  parent: "body",
3662
4298
  color: "#29d",
3663
4299
  includeCSS: true,
4300
+ popover: null,
3664
4301
  template: [
3665
4302
  '<div class="bar" role="bar">',
3666
4303
  '<div class="peg"></div>',
@@ -3671,16 +4308,21 @@ var settings = {
3671
4308
  ].join("")
3672
4309
  };
3673
4310
  var status = null;
4311
+ var hidden = false;
3674
4312
  var configure = (options) => {
3675
4313
  Object.assign(settings, options);
4314
+ usePopover = settings.popover ?? "popover" in HTMLElement.prototype;
3676
4315
  if (settings.includeCSS) {
3677
4316
  injectCSS(settings.color);
3678
4317
  }
3679
4318
  progress2 = document.createElement("div");
3680
4319
  progress2.id = baseComponentSelector;
3681
4320
  progress2.innerHTML = settings.template;
4321
+ if (usePopover) {
4322
+ progress2.popover = "manual";
4323
+ }
3682
4324
  };
3683
- var set5 = (n) => {
4325
+ var set7 = (n) => {
3684
4326
  const started = isStarted();
3685
4327
  n = clamp(n, settings.minimum, 1);
3686
4328
  status = n === 1 ? null : n;
@@ -3690,21 +4332,10 @@ var set5 = (n) => {
3690
4332
  const ease = settings.easing;
3691
4333
  progress3.offsetWidth;
3692
4334
  queue4((next) => {
3693
- const barStyles = (() => {
3694
- if (settings.positionUsing === "translate3d") {
3695
- return {
3696
- transition: `all ${speed}ms ${ease}`,
3697
- transform: `translate3d(${toBarPercentage(n)}%,0,0)`
3698
- };
3699
- }
3700
- if (settings.positionUsing === "translate") {
3701
- return {
3702
- transition: `all ${speed}ms ${ease}`,
3703
- transform: `translate(${toBarPercentage(n)}%,0)`
3704
- };
3705
- }
3706
- return { marginLeft: `${toBarPercentage(n)}%` };
3707
- })();
4335
+ const barStyles = {
4336
+ transition: `all ${speed}ms ${ease}`,
4337
+ transform: `translate3d(${toBarPercentage(n)}%,0,0)`
4338
+ };
3708
4339
  for (const key in barStyles) {
3709
4340
  bar.style[key] = barStyles[key];
3710
4341
  }
@@ -3729,7 +4360,7 @@ var set5 = (n) => {
3729
4360
  var isStarted = () => typeof status === "number";
3730
4361
  var start = () => {
3731
4362
  if (!status) {
3732
- set5(0);
4363
+ set7(0);
3733
4364
  }
3734
4365
  const work = function() {
3735
4366
  setTimeout(function() {
@@ -3749,7 +4380,7 @@ var done = (force) => {
3749
4380
  return;
3750
4381
  }
3751
4382
  increaseByRandom(0.3 + 0.5 * Math.random());
3752
- set5(1);
4383
+ set7(1);
3753
4384
  };
3754
4385
  var increaseByRandom = (amount) => {
3755
4386
  const n = status;
@@ -3773,7 +4404,7 @@ var increaseByRandom = (amount) => {
3773
4404
  }
3774
4405
  return 0;
3775
4406
  })();
3776
- return set5(clamp(n + amount, 0, 0.994));
4407
+ return set7(clamp(n + amount, 0, 0.994));
3777
4408
  };
3778
4409
  var render = (fromStart) => {
3779
4410
  if (isRendered()) {
@@ -3782,35 +4413,47 @@ var render = (fromStart) => {
3782
4413
  document.documentElement.classList.add(`${baseComponentSelector}-busy`);
3783
4414
  const bar = progress2.querySelector(settings.barSelector);
3784
4415
  const perc = fromStart ? "-100" : toBarPercentage(status || 0);
3785
- const parent = getParent();
3786
4416
  bar.style.transition = "all 0 linear";
3787
4417
  bar.style.transform = `translate3d(${perc}%,0,0)`;
3788
4418
  if (!settings.showSpinner) {
3789
4419
  progress2.querySelector(settings.spinnerSelector)?.remove();
3790
4420
  }
3791
- if (parent !== document.body) {
3792
- parent.classList.add(`${baseComponentSelector}-custom-parent`);
4421
+ if (usePopover) {
4422
+ document.body.appendChild(progress2);
4423
+ if (!hidden) {
4424
+ progress2.showPopover();
4425
+ }
4426
+ } else {
4427
+ const parent = getParent();
4428
+ if (parent !== document.body) {
4429
+ parent.classList.add(`${baseComponentSelector}-custom-parent`);
4430
+ }
4431
+ parent.appendChild(progress2);
4432
+ if (hidden) {
4433
+ progress2.style.display = "none";
4434
+ }
3793
4435
  }
3794
- parent.appendChild(progress2);
3795
4436
  return progress2;
3796
4437
  };
3797
4438
  var getParent = () => {
3798
- return isDOM(settings.parent) ? settings.parent : document.querySelector(settings.parent);
4439
+ return document.querySelector(settings.parent);
3799
4440
  };
3800
4441
  var remove = () => {
3801
4442
  document.documentElement.classList.remove(`${baseComponentSelector}-busy`);
3802
- getParent().classList.remove(`${baseComponentSelector}-custom-parent`);
4443
+ if (usePopover && progress2?.isConnected) {
4444
+ try {
4445
+ progress2.hidePopover();
4446
+ } catch {
4447
+ }
4448
+ }
4449
+ if (!usePopover) {
4450
+ getParent().classList.remove(`${baseComponentSelector}-custom-parent`);
4451
+ }
3803
4452
  progress2?.remove();
3804
4453
  };
3805
4454
  var isRendered = () => {
3806
4455
  return document.getElementById(baseComponentSelector) !== null;
3807
4456
  };
3808
- var isDOM = (obj) => {
3809
- if (typeof HTMLElement === "object") {
3810
- return obj instanceof HTMLElement;
3811
- }
3812
- return obj && typeof obj === "object" && obj.nodeType === 1 && typeof obj.nodeName === "string";
3813
- };
3814
4457
  function clamp(n, min, max) {
3815
4458
  if (n < min) {
3816
4459
  return min;
@@ -3841,6 +4484,21 @@ var injectCSS = (color) => {
3841
4484
  element.textContent = `
3842
4485
  #${baseComponentSelector} {
3843
4486
  pointer-events: none;
4487
+ background: none;
4488
+ border: none;
4489
+ margin: 0;
4490
+ padding: 0;
4491
+ overflow: visible;
4492
+ inset: unset;
4493
+ width: 100%;
4494
+ height: 0;
4495
+ position: fixed;
4496
+ top: 0;
4497
+ left: 0;
4498
+ }
4499
+
4500
+ #${baseComponentSelector}::backdrop {
4501
+ display: none;
3844
4502
  }
3845
4503
 
3846
4504
  #${baseComponentSelector} .bar {
@@ -3906,12 +4564,30 @@ var injectCSS = (color) => {
3906
4564
  document.head.appendChild(element);
3907
4565
  };
3908
4566
  var show = () => {
3909
- if (progress2) {
4567
+ hidden = false;
4568
+ if (!progress2?.isConnected) {
4569
+ return;
4570
+ }
4571
+ if (usePopover) {
4572
+ try {
4573
+ progress2.showPopover();
4574
+ } catch {
4575
+ }
4576
+ } else {
3910
4577
  progress2.style.display = "";
3911
4578
  }
3912
4579
  };
3913
4580
  var hide = () => {
3914
- if (progress2) {
4581
+ hidden = true;
4582
+ if (!progress2?.isConnected) {
4583
+ return;
4584
+ }
4585
+ if (usePopover) {
4586
+ try {
4587
+ progress2.hidePopover();
4588
+ } catch {
4589
+ }
4590
+ } else {
3915
4591
  progress2.style.display = "none";
3916
4592
  }
3917
4593
  };
@@ -3919,7 +4595,7 @@ var progress_component_default = {
3919
4595
  configure,
3920
4596
  isStarted,
3921
4597
  done,
3922
- set: set5,
4598
+ set: set7,
3923
4599
  remove,
3924
4600
  start,
3925
4601
  status,
@@ -3966,8 +4642,6 @@ var Progress = class {
3966
4642
  }
3967
4643
  };
3968
4644
  var progress = new Progress();
3969
- var reveal = progress.reveal;
3970
- var hide2 = progress.hide;
3971
4645
  function addEventListeners(delay) {
3972
4646
  document.addEventListener("inertia:start", (e) => handleStartEvent(e, delay));
3973
4647
  document.addEventListener("inertia:progress", handleProgressEvent);
@@ -4001,10 +4675,11 @@ function setupProgress({
4001
4675
  delay = 250,
4002
4676
  color = "#29d",
4003
4677
  includeCSS = true,
4004
- showSpinner = false
4678
+ showSpinner = false,
4679
+ popover = null
4005
4680
  } = {}) {
4006
4681
  addEventListeners(delay);
4007
- progress_component_default.configure({ showSpinner, includeCSS, color });
4682
+ progress_component_default.configure({ showSpinner, includeCSS, color, popover });
4008
4683
  }
4009
4684
 
4010
4685
  // src/resetFormFields.ts
@@ -4145,8 +4820,51 @@ function resetFormFields(formElement, defaults, fieldNames) {
4145
4820
  }
4146
4821
  }
4147
4822
 
4823
+ // src/ssrUtils.ts
4824
+ function buildSSRBody(id, page2, html) {
4825
+ const json = JSON.stringify(page2).replace(/\//g, "\\/");
4826
+ return `<script data-page="${id}" type="application/json">${json}<\/script><div data-server-rendered="true" id="${id}">${html}</div>`;
4827
+ }
4828
+
4148
4829
  // src/index.ts
4149
4830
  var router = new Router();
4831
+ export {
4832
+ FormComponentResetSymbol,
4833
+ HttpCancelledError,
4834
+ HttpNetworkError,
4835
+ HttpResponseError,
4836
+ UseFormUtils,
4837
+ XhrHttpClient,
4838
+ axiosAdapter,
4839
+ buildSSRBody,
4840
+ config,
4841
+ createHeadManager,
4842
+ createLayoutPropsStore,
4843
+ formDataToObject,
4844
+ getInitialPageFromDOM,
4845
+ getScrollableParent,
4846
+ hasFiles,
4847
+ hrefToUrl,
4848
+ http,
4849
+ isSameUrlWithoutQueryOrHash,
4850
+ isUrlMethodPair,
4851
+ mergeDataIntoQueryString,
4852
+ mergeLayoutProps,
4853
+ normalizeLayouts,
4854
+ objectToFormData,
4855
+ progress,
4856
+ resetFormFields,
4857
+ resolveUrlMethodPairComponent,
4858
+ router,
4859
+ setupProgress,
4860
+ shouldIntercept,
4861
+ shouldNavigate,
4862
+ urlHasProtocol,
4863
+ urlToString,
4864
+ urlWithoutHash,
4865
+ useInfiniteScroll,
4866
+ xhrHttpClient
4867
+ };
4150
4868
  /* NProgress, (c) 2013, 2014 Rico Sta. Cruz - http://ricostacruz.com/nprogress
4151
4869
  * @license MIT */
4152
4870
  //# sourceMappingURL=index.js.map