@inertiajs/core 2.1.11 → 2.2.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
@@ -32,6 +32,7 @@ var index_exports = {};
32
32
  __export(index_exports, {
33
33
  createHeadManager: () => createHeadManager,
34
34
  formDataToObject: () => formDataToObject,
35
+ getScrollableParent: () => getScrollableParent,
35
36
  hideProgress: () => hide2,
36
37
  hrefToUrl: () => hrefToUrl,
37
38
  isUrlMethodPair: () => isUrlMethodPair,
@@ -44,10 +45,14 @@ __export(index_exports, {
44
45
  setupProgress: () => setupProgress,
45
46
  shouldIntercept: () => shouldIntercept,
46
47
  shouldNavigate: () => shouldNavigate,
47
- urlWithoutHash: () => urlWithoutHash
48
+ urlWithoutHash: () => urlWithoutHash,
49
+ useInfiniteScroll: () => useInfiniteScroll
48
50
  });
49
51
  module.exports = __toCommonJS(index_exports);
50
52
 
53
+ // src/router.ts
54
+ var import_lodash_es3 = require("lodash-es");
55
+
51
56
  // src/debounce.ts
52
57
  function debounce(fn, delay) {
53
58
  let timeoutID;
@@ -76,6 +81,9 @@ var fireFinishEvent = (visit) => {
76
81
  var fireInvalidEvent = (response) => {
77
82
  return fireEvent("invalid", { cancelable: true, detail: { response } });
78
83
  };
84
+ var fireBeforeUpdateEvent = (page2) => {
85
+ return fireEvent("beforeUpdate", { detail: { page: page2 } });
86
+ };
79
87
  var fireNavigateEvent = (page2) => {
80
88
  return fireEvent("navigate", { detail: { page: page2 } });
81
89
  };
@@ -742,6 +750,11 @@ var History = class {
742
750
  this.replaceState(this.current);
743
751
  }
744
752
  }
753
+ clearInitialState(key) {
754
+ if (this.initialState && this.initialState[key] !== void 0) {
755
+ delete this.initialState[key];
756
+ }
757
+ }
745
758
  hasAnyState() {
746
759
  return !!this.getAllState();
747
760
  }
@@ -871,6 +884,7 @@ var InitialVisit = class {
871
884
  static clearRememberedStateOnReload() {
872
885
  if (navigationType.isReload()) {
873
886
  history.deleteState(history.rememberedState);
887
+ history.clearInitialState(history.rememberedState);
874
888
  }
875
889
  }
876
890
  static handleBackForward() {
@@ -1238,6 +1252,7 @@ var PrefetchedRequests = class {
1238
1252
  "replace",
1239
1253
  "prefetch",
1240
1254
  "onBefore",
1255
+ "onBeforeUpdate",
1241
1256
  "onStart",
1242
1257
  "onProgress",
1243
1258
  "onFinish",
@@ -1266,6 +1281,7 @@ var RequestParams = class _RequestParams {
1266
1281
  } else {
1267
1282
  const wrappedCallbacks = {
1268
1283
  onBefore: this.wrapCallback(params, "onBefore"),
1284
+ onBeforeUpdate: this.wrapCallback(params, "onBeforeUpdate"),
1269
1285
  onStart: this.wrapCallback(params, "onStart"),
1270
1286
  onProgress: this.wrapCallback(params, "onProgress"),
1271
1287
  onFinish: this.wrapCallback(params, "onFinish"),
@@ -1396,6 +1412,9 @@ var RequestParams = class _RequestParams {
1396
1412
  }
1397
1413
  };
1398
1414
 
1415
+ // src/response.ts
1416
+ var import_lodash_es2 = require("lodash-es");
1417
+
1399
1418
  // src/modal.ts
1400
1419
  var modal_default = {
1401
1420
  modal: null,
@@ -1558,6 +1577,8 @@ var Response = class _Response {
1558
1577
  await this.setRememberedState(pageResponse);
1559
1578
  this.requestParams.setPreserveOptions(pageResponse);
1560
1579
  pageResponse.url = history.preserveUrl ? page.get().url : this.pageUrl(pageResponse);
1580
+ this.requestParams.all().onBeforeUpdate(pageResponse);
1581
+ fireBeforeUpdateEvent(pageResponse);
1561
1582
  return page.set(pageResponse, {
1562
1583
  replace: this.requestParams.all().replace,
1563
1584
  preserveScroll: this.requestParams.all().preserveScroll,
@@ -1597,36 +1618,43 @@ var Response = class _Response {
1597
1618
  if (!this.requestParams.isPartial() || pageResponse.component !== page.get().component) {
1598
1619
  return;
1599
1620
  }
1600
- const propsToMerge = pageResponse.mergeProps || [];
1621
+ const propsToAppend = pageResponse.mergeProps || [];
1622
+ const propsToPrepend = pageResponse.prependProps || [];
1601
1623
  const propsToDeepMerge = pageResponse.deepMergeProps || [];
1602
1624
  const matchPropsOn = pageResponse.matchPropsOn || [];
1603
- propsToMerge.forEach((prop) => {
1604
- const incomingProp = pageResponse.props[prop];
1625
+ const mergeProp = (prop, shouldAppend) => {
1626
+ const currentProp = (0, import_lodash_es2.get)(page.get().props, prop);
1627
+ const incomingProp = (0, import_lodash_es2.get)(pageResponse.props, prop);
1605
1628
  if (Array.isArray(incomingProp)) {
1606
- pageResponse.props[prop] = this.mergeOrMatchItems(
1607
- page.get().props[prop] || [],
1629
+ const newArray = this.mergeOrMatchItems(
1630
+ currentProp || [],
1608
1631
  incomingProp,
1609
1632
  prop,
1610
- matchPropsOn
1633
+ matchPropsOn,
1634
+ shouldAppend
1611
1635
  );
1636
+ (0, import_lodash_es2.set)(pageResponse.props, prop, newArray);
1612
1637
  } else if (typeof incomingProp === "object" && incomingProp !== null) {
1613
- pageResponse.props[prop] = {
1614
- ...page.get().props[prop] || [],
1638
+ const newObject = {
1639
+ ...currentProp || {},
1615
1640
  ...incomingProp
1616
1641
  };
1642
+ (0, import_lodash_es2.set)(pageResponse.props, prop, newObject);
1617
1643
  }
1618
- });
1644
+ };
1645
+ propsToAppend.forEach((prop) => mergeProp(prop, true));
1646
+ propsToPrepend.forEach((prop) => mergeProp(prop, false));
1619
1647
  propsToDeepMerge.forEach((prop) => {
1620
- const incomingProp = pageResponse.props[prop];
1621
1648
  const currentProp = page.get().props[prop];
1622
- const deepMerge = (target, source, currentKey) => {
1649
+ const incomingProp = pageResponse.props[prop];
1650
+ const deepMerge = (target, source, matchProp) => {
1623
1651
  if (Array.isArray(source)) {
1624
- return this.mergeOrMatchItems(target, source, currentKey, matchPropsOn);
1652
+ return this.mergeOrMatchItems(target, source, matchProp, matchPropsOn);
1625
1653
  }
1626
1654
  if (typeof source === "object" && source !== null) {
1627
1655
  return Object.keys(source).reduce(
1628
1656
  (acc, key) => {
1629
- acc[key] = deepMerge(target ? target[key] : void 0, source[key], `${currentKey}.${key}`);
1657
+ acc[key] = deepMerge(target ? target[key] : void 0, source[key], `${matchProp}.${key}`);
1630
1658
  return acc;
1631
1659
  },
1632
1660
  { ...target }
@@ -1638,32 +1666,52 @@ var Response = class _Response {
1638
1666
  });
1639
1667
  pageResponse.props = { ...page.get().props, ...pageResponse.props };
1640
1668
  }
1641
- mergeOrMatchItems(target, source, currentKey, matchPropsOn) {
1642
- const matchOn = matchPropsOn.find((key) => {
1643
- const path = key.split(".").slice(0, -1).join(".");
1644
- return path === currentKey;
1669
+ mergeOrMatchItems(existingItems, newItems, matchProp, matchPropsOn, shouldAppend = true) {
1670
+ const items = Array.isArray(existingItems) ? existingItems : [];
1671
+ const matchingKey = matchPropsOn.find((key) => {
1672
+ const keyPath = key.split(".").slice(0, -1).join(".");
1673
+ return keyPath === matchProp;
1645
1674
  });
1646
- if (!matchOn) {
1647
- return [...Array.isArray(target) ? target : [], ...source];
1648
- }
1649
- const uniqueProperty = matchOn.split(".").pop() || "";
1650
- const targetArray = Array.isArray(target) ? target : [];
1651
- const map = /* @__PURE__ */ new Map();
1652
- targetArray.forEach((item) => {
1653
- if (item && typeof item === "object" && uniqueProperty in item) {
1654
- map.set(item[uniqueProperty], item);
1655
- } else {
1656
- map.set(Symbol(), item);
1675
+ if (!matchingKey) {
1676
+ return shouldAppend ? [...items, ...newItems] : [...newItems, ...items];
1677
+ }
1678
+ const uniqueProperty = matchingKey.split(".").pop() || "";
1679
+ const newItemsMap = /* @__PURE__ */ new Map();
1680
+ newItems.forEach((item) => {
1681
+ if (this.hasUniqueProperty(item, uniqueProperty)) {
1682
+ newItemsMap.set(item[uniqueProperty], item);
1657
1683
  }
1658
1684
  });
1659
- source.forEach((item) => {
1660
- if (item && typeof item === "object" && uniqueProperty in item) {
1661
- map.set(item[uniqueProperty], item);
1662
- } else {
1663
- map.set(Symbol(), item);
1685
+ return shouldAppend ? this.appendWithMatching(items, newItems, newItemsMap, uniqueProperty) : this.prependWithMatching(items, newItems, newItemsMap, uniqueProperty);
1686
+ }
1687
+ appendWithMatching(existingItems, newItems, newItemsMap, uniqueProperty) {
1688
+ const updatedExisting = existingItems.map((item) => {
1689
+ if (this.hasUniqueProperty(item, uniqueProperty) && newItemsMap.has(item[uniqueProperty])) {
1690
+ return newItemsMap.get(item[uniqueProperty]);
1691
+ }
1692
+ return item;
1693
+ });
1694
+ const newItemsToAdd = newItems.filter((item) => {
1695
+ if (!this.hasUniqueProperty(item, uniqueProperty)) {
1696
+ return true;
1697
+ }
1698
+ return !existingItems.some(
1699
+ (existing) => this.hasUniqueProperty(existing, uniqueProperty) && existing[uniqueProperty] === item[uniqueProperty]
1700
+ );
1701
+ });
1702
+ return [...updatedExisting, ...newItemsToAdd];
1703
+ }
1704
+ prependWithMatching(existingItems, newItems, newItemsMap, uniqueProperty) {
1705
+ const untouchedExisting = existingItems.filter((item) => {
1706
+ if (this.hasUniqueProperty(item, uniqueProperty)) {
1707
+ return !newItemsMap.has(item[uniqueProperty]);
1664
1708
  }
1709
+ return true;
1665
1710
  });
1666
- return Array.from(map.values());
1711
+ return [...newItems, ...untouchedExisting];
1712
+ }
1713
+ hasUniqueProperty(item, property) {
1714
+ return item && typeof item === "object" && property in item;
1667
1715
  }
1668
1716
  async setRememberedState(pageResponse) {
1669
1717
  const rememberedState = await history.getState(history.rememberedState, {});
@@ -2005,6 +2053,43 @@ var Router = class {
2005
2053
  replace(params) {
2006
2054
  this.clientVisit(params, { replace: true });
2007
2055
  }
2056
+ replaceProp(name, value, options) {
2057
+ this.replace({
2058
+ preserveScroll: true,
2059
+ preserveState: true,
2060
+ props(currentProps) {
2061
+ const newValue = typeof value === "function" ? value((0, import_lodash_es3.get)(currentProps, name), currentProps) : value;
2062
+ return (0, import_lodash_es3.set)((0, import_lodash_es3.cloneDeep)(currentProps), name, newValue);
2063
+ },
2064
+ ...options || {}
2065
+ });
2066
+ }
2067
+ appendToProp(name, value, options) {
2068
+ this.replaceProp(
2069
+ name,
2070
+ (currentValue, currentProps) => {
2071
+ const newValue = typeof value === "function" ? value(currentValue, currentProps) : value;
2072
+ if (!Array.isArray(currentValue)) {
2073
+ currentValue = currentValue !== void 0 ? [currentValue] : [];
2074
+ }
2075
+ return [...currentValue, newValue];
2076
+ },
2077
+ options
2078
+ );
2079
+ }
2080
+ prependToProp(name, value, options) {
2081
+ this.replaceProp(
2082
+ name,
2083
+ (currentValue, currentProps) => {
2084
+ const newValue = typeof value === "function" ? value(currentValue, currentProps) : value;
2085
+ if (!Array.isArray(currentValue)) {
2086
+ currentValue = currentValue !== void 0 ? [currentValue] : [];
2087
+ }
2088
+ return [newValue, ...currentValue];
2089
+ },
2090
+ options
2091
+ );
2092
+ }
2008
2093
  push(params) {
2009
2094
  this.clientVisit(params);
2010
2095
  }
@@ -2097,6 +2182,8 @@ var Router = class {
2097
2182
  }),
2098
2183
  onBefore: options.onBefore || (() => {
2099
2184
  }),
2185
+ onBeforeUpdate: options.onBeforeUpdate || (() => {
2186
+ }),
2100
2187
  onStart: options.onStart || (() => {
2101
2188
  }),
2102
2189
  onProgress: options.onProgress || (() => {
@@ -2124,8 +2211,48 @@ var Router = class {
2124
2211
  }
2125
2212
  };
2126
2213
 
2214
+ // src/domUtils.ts
2215
+ var elementInViewport = (el) => {
2216
+ const rect = el.getBoundingClientRect();
2217
+ const verticallyVisible = rect.top < window.innerHeight && rect.bottom >= 0;
2218
+ const horizontallyVisible = rect.left < window.innerWidth && rect.right >= 0;
2219
+ return verticallyVisible && horizontallyVisible;
2220
+ };
2221
+ var getScrollableParent = (element) => {
2222
+ let parent = element?.parentElement;
2223
+ while (parent) {
2224
+ const overflowY = window.getComputedStyle(parent).overflowY;
2225
+ if (overflowY === "auto" || overflowY === "scroll") {
2226
+ return parent;
2227
+ }
2228
+ parent = parent.parentElement;
2229
+ }
2230
+ return null;
2231
+ };
2232
+ var getElementsInViewportFromCollection = (referenceElement, elements) => {
2233
+ const referenceIndex = elements.indexOf(referenceElement);
2234
+ const visibleElements = [];
2235
+ for (let i = referenceIndex; i >= 0; i--) {
2236
+ const element = elements[i];
2237
+ if (elementInViewport(element)) {
2238
+ visibleElements.push(element);
2239
+ } else {
2240
+ break;
2241
+ }
2242
+ }
2243
+ for (let i = referenceIndex + 1; i < elements.length; i++) {
2244
+ const element = elements[i];
2245
+ if (elementInViewport(element)) {
2246
+ visibleElements.push(element);
2247
+ } else {
2248
+ break;
2249
+ }
2250
+ }
2251
+ return visibleElements;
2252
+ };
2253
+
2127
2254
  // src/formObject.ts
2128
- var import_lodash_es2 = require("lodash-es");
2255
+ var import_lodash_es4 = require("lodash-es");
2129
2256
  function undotKey(key) {
2130
2257
  if (!key.includes(".")) {
2131
2258
  return key;
@@ -2160,15 +2287,15 @@ function formDataToObject(source) {
2160
2287
  const path = parseKey(undotKey(key));
2161
2288
  if (path[path.length - 1] === "") {
2162
2289
  const arrayPath = path.slice(0, -1);
2163
- const existing = (0, import_lodash_es2.get)(form, arrayPath);
2290
+ const existing = (0, import_lodash_es4.get)(form, arrayPath);
2164
2291
  if (Array.isArray(existing)) {
2165
2292
  existing.push(value);
2166
2293
  } else {
2167
- (0, import_lodash_es2.set)(form, arrayPath, [value]);
2294
+ (0, import_lodash_es4.set)(form, arrayPath, [value]);
2168
2295
  }
2169
2296
  continue;
2170
2297
  }
2171
- (0, import_lodash_es2.set)(form, path, value);
2298
+ (0, import_lodash_es4.set)(form, path, value);
2172
2299
  }
2173
2300
  return form;
2174
2301
  }
@@ -2285,6 +2412,463 @@ function createHeadManager(isServer2, titleCallback, onUpdate) {
2285
2412
  };
2286
2413
  }
2287
2414
 
2415
+ // src/infiniteScroll/data.ts
2416
+ var MERGE_INTENT_HEADER = "X-Inertia-Infinite-Scroll-Merge-Intent";
2417
+ var useInfiniteScrollData = (options) => {
2418
+ const getScrollPropFromCurrentPage = () => {
2419
+ const scrollProp = page.get().scrollProps?.[options.getPropName()];
2420
+ if (scrollProp) {
2421
+ return scrollProp;
2422
+ }
2423
+ throw new Error(`The page object does not contain a scroll prop named "${options.getPropName()}".`);
2424
+ };
2425
+ const { previousPage, nextPage, currentPage: lastLoadedPage } = getScrollPropFromCurrentPage();
2426
+ const state = {
2427
+ loading: false,
2428
+ previousPage,
2429
+ nextPage,
2430
+ lastLoadedPage,
2431
+ requestCount: 0
2432
+ };
2433
+ const getRememberKey = () => `inertia:infinite-scroll-data:${options.getPropName()}`;
2434
+ const rememberedState = router.restore(getRememberKey());
2435
+ if (rememberedState && typeof rememberedState === "object") {
2436
+ state.previousPage = rememberedState.previousPage;
2437
+ state.nextPage = rememberedState.nextPage;
2438
+ state.lastLoadedPage = rememberedState.lastLoadedPage;
2439
+ state.requestCount = rememberedState.requestCount || 0;
2440
+ }
2441
+ const getScrollPropKeyForSide = (side) => {
2442
+ return side === "next" ? "nextPage" : "previousPage";
2443
+ };
2444
+ const findPageToLoad = (side) => {
2445
+ const pagePropName = getScrollPropKeyForSide(side);
2446
+ return state[pagePropName];
2447
+ };
2448
+ const syncStateOnSuccess = (side) => {
2449
+ const scrollProp = getScrollPropFromCurrentPage();
2450
+ const paginationProp = getScrollPropKeyForSide(side);
2451
+ state.lastLoadedPage = scrollProp.currentPage;
2452
+ state[paginationProp] = scrollProp[paginationProp];
2453
+ state.requestCount += 1;
2454
+ router.remember(
2455
+ {
2456
+ previousPage: state.previousPage,
2457
+ nextPage: state.nextPage,
2458
+ lastLoadedPage: state.lastLoadedPage,
2459
+ requestCount: state.requestCount
2460
+ },
2461
+ getRememberKey()
2462
+ );
2463
+ };
2464
+ const getPageName = () => getScrollPropFromCurrentPage().pageName;
2465
+ const getRequestCount = () => state.requestCount;
2466
+ const fetchPage = (side, reloadOptions = {}) => {
2467
+ const page2 = findPageToLoad(side);
2468
+ if (state.loading || page2 === null) {
2469
+ return;
2470
+ }
2471
+ state.loading = true;
2472
+ router.reload({
2473
+ ...reloadOptions,
2474
+ data: { [getPageName()]: page2 },
2475
+ only: [options.getPropName()],
2476
+ preserveUrl: true,
2477
+ // we handle URL updates manually via useInfiniteScrollQueryString()
2478
+ headers: {
2479
+ [MERGE_INTENT_HEADER]: side === "previous" ? "prepend" : "append",
2480
+ ...reloadOptions.headers
2481
+ },
2482
+ onBefore: (visit) => {
2483
+ side === "next" ? options.onBeforeNextRequest() : options.onBeforePreviousRequest();
2484
+ reloadOptions.onBefore?.(visit);
2485
+ },
2486
+ onBeforeUpdate: (page3) => {
2487
+ options.onBeforeUpdate();
2488
+ reloadOptions.onBeforeUpdate?.(page3);
2489
+ },
2490
+ onSuccess: (page3) => {
2491
+ syncStateOnSuccess(side);
2492
+ reloadOptions.onSuccess?.(page3);
2493
+ },
2494
+ onFinish: (visit) => {
2495
+ state.loading = false;
2496
+ side === "next" ? options.onCompleteNextRequest(state.lastLoadedPage) : options.onCompletePreviousRequest(state.lastLoadedPage);
2497
+ reloadOptions.onFinish?.(visit);
2498
+ }
2499
+ });
2500
+ };
2501
+ const getLastLoadedPage = () => state.lastLoadedPage;
2502
+ const hasPrevious = () => !!state.previousPage;
2503
+ const hasNext = () => !!state.nextPage;
2504
+ const fetchPrevious = (reloadOptions) => fetchPage("previous", reloadOptions);
2505
+ const fetchNext = (reloadOptions) => fetchPage("next", reloadOptions);
2506
+ return {
2507
+ getLastLoadedPage,
2508
+ getPageName,
2509
+ getRequestCount,
2510
+ hasPrevious,
2511
+ hasNext,
2512
+ fetchNext,
2513
+ fetchPrevious
2514
+ };
2515
+ };
2516
+
2517
+ // src/intersectionObservers.ts
2518
+ var useIntersectionObservers = () => {
2519
+ const intersectionObservers = [];
2520
+ const newIntersectionObserver = (callback, options = {}) => {
2521
+ const observer = new IntersectionObserver((entries) => {
2522
+ for (const entry of entries) {
2523
+ if (entry.isIntersecting) {
2524
+ callback(entry);
2525
+ }
2526
+ }
2527
+ }, options);
2528
+ intersectionObservers.push(observer);
2529
+ return observer;
2530
+ };
2531
+ const flushAll = () => {
2532
+ intersectionObservers.forEach((observer) => observer.disconnect());
2533
+ intersectionObservers.length = 0;
2534
+ };
2535
+ return {
2536
+ new: newIntersectionObserver,
2537
+ flushAll
2538
+ };
2539
+ };
2540
+
2541
+ // src/infiniteScroll/elements.ts
2542
+ var INFINITE_SCROLL_PAGE_KEY = "infiniteScrollPage";
2543
+ var INFINITE_SCROLL_IGNORE_KEY = "infiniteScrollIgnore";
2544
+ var getPageFromElement = (element) => element.dataset[INFINITE_SCROLL_PAGE_KEY];
2545
+ var useInfiniteScrollElementManager = (options) => {
2546
+ const intersectionObservers = useIntersectionObservers();
2547
+ let itemsObserver;
2548
+ let startElementObserver;
2549
+ let endElementObserver;
2550
+ let itemsMutationObserver;
2551
+ let triggersEnabled = false;
2552
+ const setupObservers = () => {
2553
+ itemsMutationObserver = new MutationObserver((mutations) => {
2554
+ mutations.forEach((mutation) => {
2555
+ mutation.addedNodes.forEach((node) => {
2556
+ if (node.nodeType !== Node.ELEMENT_NODE) {
2557
+ return;
2558
+ }
2559
+ addedElements.add(node);
2560
+ });
2561
+ });
2562
+ rememberElementsDebounced();
2563
+ });
2564
+ itemsMutationObserver.observe(options.getItemsElement(), { childList: true });
2565
+ itemsObserver = intersectionObservers.new(
2566
+ (entry) => options.onItemIntersected(entry.target),
2567
+ { threshold: 0 }
2568
+ );
2569
+ const observerOptions = {
2570
+ root: options.getScrollableParent(),
2571
+ rootMargin: `${Math.max(1, options.getTriggerMargin())}px`
2572
+ };
2573
+ startElementObserver = intersectionObservers.new(options.onPreviousTriggered, observerOptions);
2574
+ endElementObserver = intersectionObservers.new(options.onNextTriggered, observerOptions);
2575
+ };
2576
+ const enableTriggers = () => {
2577
+ if (triggersEnabled) {
2578
+ disableTriggers();
2579
+ }
2580
+ const startElement = options.getStartElement();
2581
+ const endElement = options.getEndElement();
2582
+ if (startElement && options.shouldFetchPrevious()) {
2583
+ startElementObserver.observe(startElement);
2584
+ }
2585
+ if (endElement && options.shouldFetchNext()) {
2586
+ endElementObserver.observe(endElement);
2587
+ }
2588
+ triggersEnabled = true;
2589
+ };
2590
+ const disableTriggers = () => {
2591
+ if (!triggersEnabled) {
2592
+ return;
2593
+ }
2594
+ startElementObserver.disconnect();
2595
+ endElementObserver.disconnect();
2596
+ triggersEnabled = false;
2597
+ };
2598
+ const refreshTriggers = () => {
2599
+ if (triggersEnabled) {
2600
+ enableTriggers();
2601
+ }
2602
+ };
2603
+ const flushAll = () => {
2604
+ intersectionObservers.flushAll();
2605
+ itemsMutationObserver?.disconnect();
2606
+ };
2607
+ const addedElements = /* @__PURE__ */ new Set();
2608
+ const elementIsUntagged = (element) => !(INFINITE_SCROLL_PAGE_KEY in element.dataset) && !(INFINITE_SCROLL_IGNORE_KEY in element.dataset);
2609
+ const processManuallyAddedElements = () => {
2610
+ Array.from(addedElements).forEach((element) => {
2611
+ if (elementIsUntagged(element)) {
2612
+ element.dataset[INFINITE_SCROLL_IGNORE_KEY] = "true";
2613
+ }
2614
+ itemsObserver.observe(element);
2615
+ });
2616
+ addedElements.clear();
2617
+ };
2618
+ const findUntaggedElements = (containerElement) => {
2619
+ return Array.from(
2620
+ containerElement.querySelectorAll(
2621
+ `:scope > *:not([data-infinite-scroll-page]):not([data-infinite-scroll-ignore])`
2622
+ )
2623
+ );
2624
+ };
2625
+ let hasRestoredElements = false;
2626
+ const processServerLoadedElements = (loadedPage) => {
2627
+ if (!hasRestoredElements) {
2628
+ hasRestoredElements = true;
2629
+ if (restoreElements()) {
2630
+ return;
2631
+ }
2632
+ }
2633
+ findUntaggedElements(options.getItemsElement()).forEach((element) => {
2634
+ if (elementIsUntagged(element)) {
2635
+ element.dataset[INFINITE_SCROLL_PAGE_KEY] = loadedPage?.toString() || "1";
2636
+ }
2637
+ itemsObserver.observe(element);
2638
+ });
2639
+ rememberElements();
2640
+ };
2641
+ const getElementsRememberKey = () => `inertia:infinite-scroll-elements:${options.getPropName()}`;
2642
+ const rememberElements = () => {
2643
+ const pageElementRange = {};
2644
+ const childNodes = options.getItemsElement().childNodes;
2645
+ for (let index = 0; index < childNodes.length; index++) {
2646
+ const node = childNodes[index];
2647
+ if (node.nodeType !== Node.ELEMENT_NODE) {
2648
+ continue;
2649
+ }
2650
+ const page2 = getPageFromElement(node);
2651
+ if (typeof page2 === "undefined") {
2652
+ continue;
2653
+ }
2654
+ if (!(page2 in pageElementRange)) {
2655
+ pageElementRange[page2] = { from: index, to: index };
2656
+ } else {
2657
+ pageElementRange[page2].to = index;
2658
+ }
2659
+ }
2660
+ router.remember(pageElementRange, getElementsRememberKey());
2661
+ };
2662
+ const rememberElementsDebounced = debounce(rememberElements, 250);
2663
+ const restoreElements = () => {
2664
+ const pageElementRange = router.restore(getElementsRememberKey());
2665
+ if (!pageElementRange || typeof pageElementRange !== "object") {
2666
+ return false;
2667
+ }
2668
+ const childNodes = options.getItemsElement().childNodes;
2669
+ for (let index = 0; index < childNodes.length; index++) {
2670
+ const node = childNodes[index];
2671
+ if (node.nodeType !== Node.ELEMENT_NODE) {
2672
+ continue;
2673
+ }
2674
+ const element = node;
2675
+ let elementPage;
2676
+ for (const [page2, range] of Object.entries(pageElementRange)) {
2677
+ if (index >= range.from && index <= range.to) {
2678
+ elementPage = page2;
2679
+ break;
2680
+ }
2681
+ }
2682
+ if (elementPage) {
2683
+ element.dataset[INFINITE_SCROLL_PAGE_KEY] = elementPage;
2684
+ } else if (!elementIsUntagged(element)) {
2685
+ continue;
2686
+ } else {
2687
+ element.dataset[INFINITE_SCROLL_IGNORE_KEY] = "true";
2688
+ }
2689
+ itemsObserver.observe(element);
2690
+ }
2691
+ return true;
2692
+ };
2693
+ return {
2694
+ setupObservers,
2695
+ enableTriggers,
2696
+ disableTriggers,
2697
+ refreshTriggers,
2698
+ flushAll,
2699
+ processManuallyAddedElements,
2700
+ processServerLoadedElements
2701
+ };
2702
+ };
2703
+
2704
+ // src/infiniteScroll/queryString.ts
2705
+ var useInfiniteScrollQueryString = (options) => {
2706
+ const onItemIntersected = debounce((itemElement) => {
2707
+ if (options.shouldPreserveUrl() || !itemElement) {
2708
+ return;
2709
+ }
2710
+ const pageMap = /* @__PURE__ */ new Map();
2711
+ const elements = [...options.getItemsElement().children];
2712
+ getElementsInViewportFromCollection(itemElement, elements).forEach((element) => {
2713
+ const page2 = getPageFromElement(element) ?? "1";
2714
+ if (pageMap.has(page2)) {
2715
+ pageMap.set(page2, pageMap.get(page2) + 1);
2716
+ } else {
2717
+ pageMap.set(page2, 1);
2718
+ }
2719
+ });
2720
+ const sortedPages = Array.from(pageMap.entries()).sort((a, b) => b[1] - a[1]);
2721
+ const mostVisiblePage = sortedPages[0]?.[0];
2722
+ if (mostVisiblePage === void 0) {
2723
+ return;
2724
+ }
2725
+ const url = new URL(window.location.href);
2726
+ if (mostVisiblePage === "1") {
2727
+ url.searchParams.delete(options.getPageName());
2728
+ } else {
2729
+ url.searchParams.set(options.getPageName(), mostVisiblePage.toString());
2730
+ }
2731
+ router.replace({
2732
+ url: url.toString(),
2733
+ preserveScroll: true,
2734
+ preserveState: true
2735
+ });
2736
+ }, 250);
2737
+ return {
2738
+ onItemIntersected
2739
+ };
2740
+ };
2741
+
2742
+ // src/infiniteScroll/scrollPreservation.ts
2743
+ var useInfiniteScrollPreservation = (options) => {
2744
+ const createCallbacks = () => {
2745
+ let currentScrollTop;
2746
+ let referenceElement = null;
2747
+ let referenceElementTop = 0;
2748
+ const captureScrollPosition = () => {
2749
+ const scrollableContainer = options.getScrollableParent();
2750
+ const itemsElement = options.getItemsElement();
2751
+ currentScrollTop = scrollableContainer?.scrollTop || window.scrollY;
2752
+ const visibleElements = getElementsInViewportFromCollection(
2753
+ itemsElement.firstElementChild,
2754
+ [...itemsElement.children]
2755
+ );
2756
+ if (visibleElements.length > 0) {
2757
+ referenceElement = visibleElements[0];
2758
+ const containerRect = scrollableContainer?.getBoundingClientRect() || { top: 0 };
2759
+ const containerTop = scrollableContainer ? containerRect.top : 0;
2760
+ const rect = referenceElement.getBoundingClientRect();
2761
+ referenceElementTop = rect.top - containerTop;
2762
+ }
2763
+ };
2764
+ const restoreScrollPosition = () => {
2765
+ if (!referenceElement) {
2766
+ return;
2767
+ }
2768
+ let attempts = 0;
2769
+ let restored = false;
2770
+ const restore = () => {
2771
+ attempts++;
2772
+ if (restored || attempts > 10) {
2773
+ return false;
2774
+ }
2775
+ const scrollableContainer = options.getScrollableParent();
2776
+ const containerRect = scrollableContainer?.getBoundingClientRect() || { top: 0 };
2777
+ const containerTop = scrollableContainer ? containerRect.top : 0;
2778
+ const newRect = referenceElement.getBoundingClientRect();
2779
+ const newElementTop = newRect.top - containerTop;
2780
+ const adjustment = newElementTop - referenceElementTop;
2781
+ if (adjustment === 0) {
2782
+ window.requestAnimationFrame(restore);
2783
+ return;
2784
+ }
2785
+ if (scrollableContainer) {
2786
+ scrollableContainer.scrollTo({ top: currentScrollTop + adjustment });
2787
+ } else {
2788
+ window.scrollTo(0, window.scrollY + adjustment);
2789
+ }
2790
+ restored = true;
2791
+ };
2792
+ restore();
2793
+ };
2794
+ return {
2795
+ captureScrollPosition,
2796
+ restoreScrollPosition
2797
+ };
2798
+ };
2799
+ return {
2800
+ createCallbacks
2801
+ };
2802
+ };
2803
+
2804
+ // src/infiniteScroll.ts
2805
+ function useInfiniteScroll(options) {
2806
+ const queryStringManager = useInfiniteScrollQueryString({ ...options, getPageName: () => dataManager.getPageName() });
2807
+ const scrollPreservation = useInfiniteScrollPreservation(options);
2808
+ const elementManager = useInfiniteScrollElementManager({
2809
+ ...options,
2810
+ // As items enter viewport, update URL to reflect the most visible page
2811
+ onItemIntersected: queryStringManager.onItemIntersected,
2812
+ onPreviousTriggered: () => dataManager.fetchPrevious(),
2813
+ onNextTriggered: () => dataManager.fetchNext()
2814
+ });
2815
+ const dataManager = useInfiniteScrollData({
2816
+ ...options,
2817
+ // Before updating page data, tag any manually added DOM elements
2818
+ // so they don't get confused with server-loaded content
2819
+ onBeforeUpdate: elementManager.processManuallyAddedElements,
2820
+ // After successful request, tag new server content
2821
+ onCompletePreviousRequest: (loadedPage) => {
2822
+ setTimeout(() => {
2823
+ elementManager.processServerLoadedElements(loadedPage);
2824
+ options.onCompletePreviousRequest();
2825
+ window.queueMicrotask(elementManager.refreshTriggers);
2826
+ });
2827
+ },
2828
+ onCompleteNextRequest: (loadedPage) => {
2829
+ setTimeout(() => {
2830
+ elementManager.processServerLoadedElements(loadedPage);
2831
+ options.onCompleteNextRequest();
2832
+ window.queueMicrotask(elementManager.refreshTriggers);
2833
+ });
2834
+ }
2835
+ });
2836
+ const addScrollPreservationCallbacks = (reloadOptions) => {
2837
+ const { captureScrollPosition, restoreScrollPosition } = scrollPreservation.createCallbacks();
2838
+ const originalOnBeforeUpdate = reloadOptions.onBeforeUpdate || (() => {
2839
+ });
2840
+ const originalOnSuccess = reloadOptions.onSuccess || (() => {
2841
+ });
2842
+ reloadOptions.onBeforeUpdate = (page2) => {
2843
+ originalOnBeforeUpdate(page2);
2844
+ captureScrollPosition();
2845
+ };
2846
+ reloadOptions.onSuccess = (page2) => {
2847
+ originalOnSuccess(page2);
2848
+ restoreScrollPosition();
2849
+ };
2850
+ return reloadOptions;
2851
+ };
2852
+ const originalFetchNext = dataManager.fetchNext;
2853
+ dataManager.fetchNext = (reloadOptions = {}) => {
2854
+ if (options.inReverseMode()) {
2855
+ reloadOptions = addScrollPreservationCallbacks(reloadOptions);
2856
+ }
2857
+ originalFetchNext(reloadOptions);
2858
+ };
2859
+ const originalFetchPrevious = dataManager.fetchPrevious;
2860
+ dataManager.fetchPrevious = (reloadOptions = {}) => {
2861
+ if (!options.inReverseMode()) {
2862
+ reloadOptions = addScrollPreservationCallbacks(reloadOptions);
2863
+ }
2864
+ originalFetchPrevious(reloadOptions);
2865
+ };
2866
+ return {
2867
+ dataManager,
2868
+ elementManager
2869
+ };
2870
+ }
2871
+
2288
2872
  // src/navigationEvents.ts
2289
2873
  function shouldIntercept(event) {
2290
2874
  const isLink = event.currentTarget.tagName.toLowerCase() === "a";
@@ -2330,7 +2914,7 @@ var configure = (options) => {
2330
2914
  progress2.id = baseComponentSelector;
2331
2915
  progress2.innerHTML = settings.template;
2332
2916
  };
2333
- var set2 = (n) => {
2917
+ var set4 = (n) => {
2334
2918
  const started = isStarted();
2335
2919
  n = clamp(n, settings.minimum, 1);
2336
2920
  status = n === 1 ? null : n;
@@ -2379,7 +2963,7 @@ var set2 = (n) => {
2379
2963
  var isStarted = () => typeof status === "number";
2380
2964
  var start = () => {
2381
2965
  if (!status) {
2382
- set2(0);
2966
+ set4(0);
2383
2967
  }
2384
2968
  const work = function() {
2385
2969
  setTimeout(function() {
@@ -2399,7 +2983,7 @@ var done = (force) => {
2399
2983
  return;
2400
2984
  }
2401
2985
  increaseByRandom(0.3 + 0.5 * Math.random());
2402
- set2(1);
2986
+ set4(1);
2403
2987
  };
2404
2988
  var increaseByRandom = (amount) => {
2405
2989
  const n = status;
@@ -2423,7 +3007,7 @@ var increaseByRandom = (amount) => {
2423
3007
  }
2424
3008
  return 0;
2425
3009
  })();
2426
- return set2(clamp(n + amount, 0, 0.994));
3010
+ return set4(clamp(n + amount, 0, 0.994));
2427
3011
  };
2428
3012
  var render = (fromStart) => {
2429
3013
  if (isRendered()) {
@@ -2569,7 +3153,7 @@ var progress_component_default = {
2569
3153
  configure,
2570
3154
  isStarted,
2571
3155
  done,
2572
- set: set2,
3156
+ set: set4,
2573
3157
  remove,
2574
3158
  start,
2575
3159
  status,