@ionic/core 8.8.17 → 8.8.18-dev.11786109471.1285bcfb

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. package/components/ion-app.js +1 -1
  2. package/components/ion-footer.js +1 -1
  3. package/components/ion-header.js +1 -1
  4. package/components/ion-infinite-scroll.js +1 -1
  5. package/components/ion-item-sliding.js +1 -1
  6. package/components/ion-modal.js +1 -1
  7. package/components/ion-range.js +1 -1
  8. package/components/ion-refresher.js +1 -1
  9. package/components/ion-reorder-group.js +1 -1
  10. package/components/ion-router.js +1 -1
  11. package/components/ion-select-modal.js +1 -1
  12. package/components/ion-select.js +1 -1
  13. package/components/{p-KEFO0w3i.js → p-BMaKgJFV.js} +1 -1
  14. package/components/p-Cp4GRDqq.js +4 -0
  15. package/components/p-D7uN07a3.js +4 -0
  16. package/components/p-R8zmRi4c.js +4 -0
  17. package/components/p-tr4_8ZS8.js +4 -0
  18. package/components/{p-DJZp0KTQ.js → p-vRBNsYbs.js} +1 -1
  19. package/dist/cjs/{index-CIrkNXqJ.js → index-Dqpns5vP.js} +32 -0
  20. package/dist/cjs/{input-shims-CFLg7uzj.js → input-shims-DpA1zUN9.js} +1 -1
  21. package/dist/cjs/ion-app_8.cjs.entry.js +3 -3
  22. package/dist/cjs/ion-infinite-scroll_2.cjs.entry.js +1 -1
  23. package/dist/cjs/ion-item-option_3.cjs.entry.js +1 -1
  24. package/dist/cjs/ion-modal.cjs.entry.js +34 -66
  25. package/dist/cjs/ion-range.cjs.entry.js +1 -1
  26. package/dist/cjs/ion-refresher_2.cjs.entry.js +3 -3
  27. package/dist/cjs/ion-reorder_2.cjs.entry.js +1 -1
  28. package/dist/cjs/ion-route_4.cjs.entry.js +1 -1
  29. package/dist/cjs/{status-tap-BXX8H8_Y.js → status-tap-N1kaBbuk.js} +1 -1
  30. package/dist/collection/components/modal/gestures/sheet.js +5 -23
  31. package/dist/collection/components/modal/gestures/swipe-to-close.js +3 -32
  32. package/dist/collection/components/modal/gestures/utils.js +17 -0
  33. package/dist/collection/components/refresher/refresher.js +3 -3
  34. package/dist/collection/utils/content/index.js +30 -0
  35. package/dist/docs.json +1 -1
  36. package/dist/esm/{index-MEDq2S8l.js → index-Dw-wN0Ja.js} +31 -1
  37. package/dist/esm/{input-shims-D10mwcw1.js → input-shims-LXhI7LEx.js} +1 -1
  38. package/dist/esm/ion-app_8.entry.js +3 -3
  39. package/dist/esm/ion-infinite-scroll_2.entry.js +1 -1
  40. package/dist/esm/ion-item-option_3.entry.js +1 -1
  41. package/dist/esm/ion-modal.entry.js +22 -54
  42. package/dist/esm/ion-range.entry.js +1 -1
  43. package/dist/esm/ion-refresher_2.entry.js +3 -3
  44. package/dist/esm/ion-reorder_2.entry.js +1 -1
  45. package/dist/esm/ion-route_4.entry.js +1 -1
  46. package/dist/esm/{status-tap-Kan2W7sh.js → status-tap-vO-6s4Yp.js} +1 -1
  47. package/dist/ionic/ionic.esm.js +1 -1
  48. package/dist/ionic/p-0caa922c.entry.js +4 -0
  49. package/dist/ionic/{p-e0be05c5.entry.js → p-5334df12.entry.js} +1 -1
  50. package/dist/ionic/{p-20b1a044.entry.js → p-746fa988.entry.js} +1 -1
  51. package/dist/ionic/p-8158d422.entry.js +4 -0
  52. package/dist/ionic/{p-Dfbt-q2k.js → p-CmcFnK-B.js} +1 -1
  53. package/dist/ionic/{p-8fce95d5.entry.js → p-af55a72f.entry.js} +1 -1
  54. package/dist/ionic/p-b2020591.entry.js +4 -0
  55. package/dist/ionic/{p-b6a7397c.entry.js → p-b9fadbfe.entry.js} +1 -1
  56. package/dist/ionic/p-biz8zWmJ.js +4 -0
  57. package/dist/ionic/{p-485fda23.entry.js → p-d1aac015.entry.js} +1 -1
  58. package/dist/ionic/p-uWtqTrG8.js +4 -0
  59. package/dist/types/components/modal/gestures/utils.d.ts +11 -0
  60. package/dist/types/utils/content/index.d.ts +12 -0
  61. package/hydrate/index.js +52 -54
  62. package/hydrate/index.mjs +52 -54
  63. package/package.json +1 -1
  64. package/components/p-DHTSTb52.js +0 -4
  65. package/components/p-DRugphUN.js +0 -4
  66. package/components/p-VWbRkLT7.js +0 -4
  67. package/components/p-sijaAIYG.js +0 -4
  68. package/dist/ionic/p-4ac4f3d6.entry.js +0 -4
  69. package/dist/ionic/p-9f1103ce.entry.js +0 -4
  70. package/dist/ionic/p-DSG2s2Eb.js +0 -4
  71. package/dist/ionic/p-Wk5HzclC.js +0 -4
  72. package/dist/ionic/p-ad306193.entry.js +0 -4
@@ -4,7 +4,7 @@
4
4
  'use strict';
5
5
 
6
6
  var index$3 = require('./index-Ct7gcRif.js');
7
- var index$2 = require('./index-CIrkNXqJ.js');
7
+ var index$1 = require('./index-Dqpns5vP.js');
8
8
  var frameworkDelegate = require('./framework-delegate-BtICZDHr.js');
9
9
  var helpers = require('./helpers-Cv23MFHM.js');
10
10
  var lockController = require('./lock-controller-aDB9wrEf.js');
@@ -16,7 +16,7 @@ var ionicGlobal = require('./ionic-global-B-cA6LkY.js');
16
16
  var keyboard = require('./keyboard-hHzlEQpk.js');
17
17
  var animation = require('./animation-BJq0kcy2.js');
18
18
  var cubicBezier = require('./cubic-bezier-DAjy1V-e.js');
19
- var index$1 = require('./index-CAvQ7Tka.js');
19
+ var index$2 = require('./index-CAvQ7Tka.js');
20
20
  var index = require('./index-DkNv4J_i.js');
21
21
  require('./hardware-back-button-iUuF_76h.js');
22
22
  require('./gesture-controller-dtqlP_q4.js');
@@ -129,6 +129,21 @@ const setCardStatusBarDefault = (defaultStyle = Style.Default) => {
129
129
  StatusBar.setStyle({ style: defaultStyle });
130
130
  };
131
131
 
132
+ /**
133
+ * Swiping is only possible when the content is scrolled to the top, so that we
134
+ * do not interfere with scrolling, and never on content with a refresher.
135
+ *
136
+ * Note: We cannot solve the refresher case with gesture priority as the iOS
137
+ * native refresh gesture uses a scroll listener in addition to a gesture.
138
+ *
139
+ * Note: Do not use `getScrollElement` here because we need this to be a
140
+ * synchronous operation, and `getScrollElement` is asynchronous.
141
+ */
142
+ const canSwipeOnContent = (contentEl) => {
143
+ const scrollEl = index$1.isIonContent(contentEl) ? helpers.getElementRoot(contentEl).querySelector('.inner-scroll') : contentEl;
144
+ const hasRefresherInContent = !!index$1.findRefresherInContent(contentEl);
145
+ return !hasRefresherInContent && scrollEl.scrollTop === 0;
146
+ };
132
147
  const handleCanDismiss = async (el, animation) => {
133
148
  /**
134
149
  * If canDismiss is not a function
@@ -259,12 +274,11 @@ const createSwipeToCloseGesture = (el, animation, statusBarStyle, onDismiss, onD
259
274
  let isOpen = false;
260
275
  let canDismissBlocksGesture = false;
261
276
  let contentEl = null;
262
- let scrollEl = null;
263
277
  const canDismissMaxStep = 0.2;
264
278
  let initialScrollY = true;
265
279
  let lastStep = 0;
266
280
  const getScrollY = () => {
267
- if (contentEl && index$2.isIonContent(contentEl)) {
281
+ if (contentEl && index$1.isIonContent(contentEl)) {
268
282
  return contentEl.scrollY;
269
283
  /**
270
284
  * Custom scroll containers are intended to be
@@ -282,12 +296,6 @@ const createSwipeToCloseGesture = (el, animation, statusBarStyle, onDismiss, onD
282
296
  return true;
283
297
  }
284
298
  /**
285
- * If we are swiping on the content,
286
- * swiping should only be possible if
287
- * the content is scrolled all the way
288
- * to the top so that we do not interfere
289
- * with scrolling.
290
- *
291
299
  * We cannot assume that the `ion-content`
292
300
  * target will remain consistent between
293
301
  * swipes. For example, when using
@@ -296,31 +304,9 @@ const createSwipeToCloseGesture = (el, animation, statusBarStyle, onDismiss, onD
296
304
  * swipe again. The target content will not
297
305
  * be the same between swipes.
298
306
  */
299
- contentEl = index$2.findClosestIonContent(target);
307
+ contentEl = index$1.findClosestIonContent(target);
300
308
  if (contentEl) {
301
- /**
302
- * The card should never swipe to close
303
- * on the content with a refresher.
304
- * Note: We cannot solve this by making the
305
- * swipeToClose gesture have a higher priority
306
- * than the refresher gesture as the iOS native
307
- * refresh gesture uses a scroll listener in
308
- * addition to a gesture.
309
- *
310
- * Note: Do not use getScrollElement here
311
- * because we need this to be a synchronous
312
- * operation, and getScrollElement is
313
- * asynchronous.
314
- */
315
- if (index$2.isIonContent(contentEl)) {
316
- const root = helpers.getElementRoot(contentEl);
317
- scrollEl = root.querySelector('.inner-scroll');
318
- }
319
- else {
320
- scrollEl = contentEl;
321
- }
322
- const hasRefresherInContent = !!contentEl.querySelector('ion-refresher');
323
- return !hasRefresherInContent && scrollEl.scrollTop === 0;
309
+ return canSwipeOnContent(contentEl);
324
310
  }
325
311
  /**
326
312
  * Card should be swipeable on all
@@ -363,7 +349,7 @@ const createSwipeToCloseGesture = (el, animation, statusBarStyle, onDismiss, onD
363
349
  * happen at the same time as the gesture.
364
350
  */
365
351
  if (deltaY > 0 && contentEl) {
366
- index$2.disableContentScrollY(contentEl);
352
+ index$1.disableContentScrollY(contentEl);
367
353
  }
368
354
  animation.progressStart(true, isOpen ? 1 : 0);
369
355
  onDragStart();
@@ -377,7 +363,7 @@ const createSwipeToCloseGesture = (el, animation, statusBarStyle, onDismiss, onD
377
363
  * happen at the same time as the gesture.
378
364
  */
379
365
  if (deltaY > 0 && contentEl) {
380
- index$2.disableContentScrollY(contentEl);
366
+ index$1.disableContentScrollY(contentEl);
381
367
  }
382
368
  /**
383
369
  * If we are swiping on the content
@@ -472,7 +458,7 @@ const createSwipeToCloseGesture = (el, animation, statusBarStyle, onDismiss, onD
472
458
  isOpen = shouldComplete;
473
459
  gesture.enable(false);
474
460
  if (contentEl) {
475
- index$2.resetContentScrollY(contentEl, initialScrollY);
461
+ index$1.resetContentScrollY(contentEl, initialScrollY);
476
462
  }
477
463
  animation
478
464
  .onFinish(() => {
@@ -507,7 +493,7 @@ const createSwipeToCloseGesture = (el, animation, statusBarStyle, onDismiss, onD
507
493
  };
508
494
  onDragEnd(eventDetail);
509
495
  };
510
- const gesture = index$1.createGesture({
496
+ const gesture = index$2.createGesture({
511
497
  el,
512
498
  gestureName: 'modalSwipeToClose',
513
499
  gesturePriority: overlays.OVERLAY_GESTURE_PRIORITY,
@@ -1192,36 +1178,18 @@ const createSheetGesture = (baseEl, backdropEl, wrapperEl, initialBreakpoint, ba
1192
1178
  }
1193
1179
  const canStart = (detail) => {
1194
1180
  /**
1195
- * If we are swiping on the content, swiping should only be possible if the content
1196
- * is scrolled all the way to the top so that we do not interfere with scrolling.
1197
- *
1198
1181
  * We cannot assume that the `ion-content` target will remain consistent between swipes.
1199
1182
  * For example, when using ion-nav within a modal it is possible to swipe, push a view,
1200
1183
  * and then swipe again. The target content will not be the same between swipes.
1201
1184
  */
1202
- const contentEl = index$2.findClosestIonContent(detail.event.target);
1185
+ const contentEl = index$1.findClosestIonContent(detail.event.target);
1203
1186
  currentBreakpoint = getCurrentBreakpoint();
1204
1187
  /**
1205
- * If `expandToScroll` is disabled, we should not allow the swipe gesture
1206
- * to start if the content is not scrolled to the top.
1188
+ * Upwards swipes on the content cannot move the sheet anyway, so this only
1189
+ * blocks swiping the sheet down from the content.
1207
1190
  */
1208
- if (!expandToScroll && contentEl) {
1209
- const scrollEl = index$2.isIonContent(contentEl) ? helpers.getElementRoot(contentEl).querySelector('.inner-scroll') : contentEl;
1210
- return scrollEl.scrollTop === 0;
1211
- }
1212
- if (currentBreakpoint === 1 && contentEl) {
1213
- /**
1214
- * The modal should never swipe to close on the content with a refresher.
1215
- * Note 1: We cannot solve this by making this gesture have a higher priority than
1216
- * the refresher gesture as the iOS native refresh gesture uses a scroll listener in
1217
- * addition to a gesture.
1218
- *
1219
- * Note 2: Do not use getScrollElement here because we need this to be a synchronous
1220
- * operation, and getScrollElement is asynchronous.
1221
- */
1222
- const scrollEl = index$2.isIonContent(contentEl) ? helpers.getElementRoot(contentEl).querySelector('.inner-scroll') : contentEl;
1223
- const hasRefresherInContent = !!contentEl.querySelector('ion-refresher');
1224
- return !hasRefresherInContent && scrollEl.scrollTop === 0;
1191
+ if (contentEl && (!expandToScroll || currentBreakpoint === 1)) {
1192
+ return canSwipeOnContent(contentEl);
1225
1193
  }
1226
1194
  return true;
1227
1195
  };
@@ -1252,9 +1220,9 @@ const createSheetGesture = (baseEl, backdropEl, wrapperEl, initialBreakpoint, ba
1252
1220
  * which would impact performance significantly.
1253
1221
  */
1254
1222
  if (!expandToScroll) {
1255
- const targetEl = index$2.findClosestIonContent(detail.event.target);
1223
+ const targetEl = index$1.findClosestIonContent(detail.event.target);
1256
1224
  cachedScrollEl =
1257
- targetEl && index$2.isIonContent(targetEl) ? helpers.getElementRoot(targetEl).querySelector('.inner-scroll') : targetEl;
1225
+ targetEl && index$1.isIonContent(targetEl) ? helpers.getElementRoot(targetEl).querySelector('.inner-scroll') : targetEl;
1258
1226
  }
1259
1227
  /**
1260
1228
  * If expandToScroll is disabled, we need to swap
@@ -1632,7 +1600,7 @@ const createSheetGesture = (baseEl, backdropEl, wrapperEl, initialBreakpoint, ba
1632
1600
  */
1633
1601
  return viewportBottom - activeHeight;
1634
1602
  };
1635
- const gesture = index$1.createGesture({
1603
+ const gesture = index$2.createGesture({
1636
1604
  el: wrapperEl,
1637
1605
  gestureName: 'modalSheet',
1638
1606
  gesturePriority: 40,
@@ -2344,9 +2312,9 @@ const Modal = class {
2344
2312
  presentingEl: this.presentingElement,
2345
2313
  expandToScroll: this.expandToScroll,
2346
2314
  }));
2347
- const contentEl = index$2.findIonContent(el);
2315
+ const contentEl = index$1.findIonContent(el);
2348
2316
  if (!contentEl) {
2349
- index$2.printIonContentErrorMsg(el);
2317
+ index$1.printIonContentErrorMsg(el);
2350
2318
  return;
2351
2319
  }
2352
2320
  const statusBarStyle = (_a = this.statusBarStyle) !== null && _a !== void 0 ? _a : Style.Default;
@@ -4,7 +4,7 @@
4
4
  'use strict';
5
5
 
6
6
  var index = require('./index-Ct7gcRif.js');
7
- var index$1 = require('./index-CIrkNXqJ.js');
7
+ var index$1 = require('./index-Dqpns5vP.js');
8
8
  var helpers = require('./helpers-Cv23MFHM.js');
9
9
  var dir = require('./dir-Cn0z1rJH.js');
10
10
  var theme = require('./theme-CeDs6Hcv.js');
@@ -5,7 +5,7 @@
5
5
 
6
6
  var index = require('./index-Ct7gcRif.js');
7
7
  var cubicBezier = require('./cubic-bezier-DAjy1V-e.js');
8
- var index$1 = require('./index-CIrkNXqJ.js');
8
+ var index$1 = require('./index-Dqpns5vP.js');
9
9
  var helpers = require('./helpers-Cv23MFHM.js');
10
10
  var haptic = require('./haptic-ClPPQ_PS.js');
11
11
  var ionicGlobal = require('./ionic-global-B-cA6LkY.js');
@@ -595,7 +595,7 @@ const Refresher = class {
595
595
  * or the background content element.
596
596
  */
597
597
  helpers.componentOnReady(contentEl, async () => {
598
- const customScrollTarget = contentEl.querySelector(index$1.ION_CONTENT_CLASS_SELECTOR);
598
+ const customScrollTarget = index$1.findRefresherScrollHost(contentEl);
599
599
  /**
600
600
  * Query the custom scroll target (if available), first. In refresher implementations,
601
601
  * the ion-refresher element will always be a direct child of ion-content (slot="fixed"). By
@@ -945,7 +945,7 @@ const Refresher = class {
945
945
  }
946
946
  render() {
947
947
  const mode = ionicGlobal.getIonMode(this);
948
- return (index.h(index.Host, { key: '2eaca7f85b3d40418f213077434e519dfacd9d42', slot: "fixed", class: {
948
+ return (index.h(index.Host, { key: '6b94f11bd5382bdf4e92c43d4b5d0550c290852d', slot: "fixed", class: {
949
949
  [mode]: true,
950
950
  // Used internally for styling
951
951
  [`refresher-${mode}`]: true,
@@ -6,7 +6,7 @@
6
6
  var index = require('./index-Ct7gcRif.js');
7
7
  var index$1 = require('./index-DqmRDbxg.js');
8
8
  var ionicGlobal = require('./ionic-global-B-cA6LkY.js');
9
- var index$2 = require('./index-CIrkNXqJ.js');
9
+ var index$2 = require('./index-Dqpns5vP.js');
10
10
  var helpers = require('./helpers-Cv23MFHM.js');
11
11
  var haptic = require('./haptic-ClPPQ_PS.js');
12
12
  require('./capacitor-DmA66EwP.js');
@@ -5,7 +5,7 @@
5
5
 
6
6
  var index = require('./index-Ct7gcRif.js');
7
7
  var helpers = require('./helpers-Cv23MFHM.js');
8
- var index$1 = require('./index-CIrkNXqJ.js');
8
+ var index$1 = require('./index-Dqpns5vP.js');
9
9
  var theme = require('./theme-CeDs6Hcv.js');
10
10
  var ionicGlobal = require('./ionic-global-B-cA6LkY.js');
11
11
 
@@ -4,7 +4,7 @@
4
4
  'use strict';
5
5
 
6
6
  var index = require('./index-Ct7gcRif.js');
7
- var index$1 = require('./index-CIrkNXqJ.js');
7
+ var index$1 = require('./index-Dqpns5vP.js');
8
8
  var helpers = require('./helpers-Cv23MFHM.js');
9
9
 
10
10
  const startStatusTap = () => {
@@ -6,7 +6,7 @@ import { createGesture } from "../../../utils/gesture/index";
6
6
  import { clamp, getElementRoot, raf } from "../../../utils/helpers";
7
7
  import { FOCUS_TRAP_DISABLE_CLASS } from "../../../utils/overlays";
8
8
  import { getBackdropValueForSheet } from "../utils";
9
- import { calculateSpringStep, handleCanDismiss } from "./utils";
9
+ import { calculateSpringStep, canSwipeOnContent, handleCanDismiss } from "./utils";
10
10
  export const createSheetGesture = (baseEl, backdropEl, wrapperEl, initialBreakpoint, backdropBreakpoint, animation, breakpoints = [], expandToScroll, getCurrentBreakpoint, onDismiss, onBreakpointChange, onDragStart, onDragMove, onDragEnd) => {
11
11
  // Defaults for the sheet swipe animation
12
12
  const defaultBackdrop = [
@@ -190,9 +190,6 @@ export const createSheetGesture = (baseEl, backdropEl, wrapperEl, initialBreakpo
190
190
  }
191
191
  const canStart = (detail) => {
192
192
  /**
193
- * If we are swiping on the content, swiping should only be possible if the content
194
- * is scrolled all the way to the top so that we do not interfere with scrolling.
195
- *
196
193
  * We cannot assume that the `ion-content` target will remain consistent between swipes.
197
194
  * For example, when using ion-nav within a modal it is possible to swipe, push a view,
198
195
  * and then swipe again. The target content will not be the same between swipes.
@@ -200,26 +197,11 @@ export const createSheetGesture = (baseEl, backdropEl, wrapperEl, initialBreakpo
200
197
  const contentEl = findClosestIonContent(detail.event.target);
201
198
  currentBreakpoint = getCurrentBreakpoint();
202
199
  /**
203
- * If `expandToScroll` is disabled, we should not allow the swipe gesture
204
- * to start if the content is not scrolled to the top.
200
+ * Upwards swipes on the content cannot move the sheet anyway, so this only
201
+ * blocks swiping the sheet down from the content.
205
202
  */
206
- if (!expandToScroll && contentEl) {
207
- const scrollEl = isIonContent(contentEl) ? getElementRoot(contentEl).querySelector('.inner-scroll') : contentEl;
208
- return scrollEl.scrollTop === 0;
209
- }
210
- if (currentBreakpoint === 1 && contentEl) {
211
- /**
212
- * The modal should never swipe to close on the content with a refresher.
213
- * Note 1: We cannot solve this by making this gesture have a higher priority than
214
- * the refresher gesture as the iOS native refresh gesture uses a scroll listener in
215
- * addition to a gesture.
216
- *
217
- * Note 2: Do not use getScrollElement here because we need this to be a synchronous
218
- * operation, and getScrollElement is asynchronous.
219
- */
220
- const scrollEl = isIonContent(contentEl) ? getElementRoot(contentEl).querySelector('.inner-scroll') : contentEl;
221
- const hasRefresherInContent = !!contentEl.querySelector('ion-refresher');
222
- return !hasRefresherInContent && scrollEl.scrollTop === 0;
203
+ if (contentEl && (!expandToScroll || currentBreakpoint === 1)) {
204
+ return canSwipeOnContent(contentEl);
223
205
  }
224
206
  return true;
225
207
  };
@@ -4,10 +4,10 @@
4
4
  import { getTimeGivenProgression } from "../../../utils/animation/cubic-bezier";
5
5
  import { isIonContent, findClosestIonContent, disableContentScrollY, resetContentScrollY } from "../../../utils/content/index";
6
6
  import { createGesture } from "../../../utils/gesture/index";
7
- import { clamp, getElementRoot } from "../../../utils/helpers";
7
+ import { clamp } from "../../../utils/helpers";
8
8
  import { OVERLAY_GESTURE_PRIORITY } from "../../../utils/overlays";
9
9
  import { setCardStatusBarDark, setCardStatusBarDefault } from "../utils";
10
- import { calculateSpringStep, handleCanDismiss } from "./utils";
10
+ import { calculateSpringStep, canSwipeOnContent, handleCanDismiss } from "./utils";
11
11
  // Defaults for the card swipe animation
12
12
  export const SwipeToCloseDefaults = {
13
13
  MIN_PRESENTING_SCALE: 0.915,
@@ -22,7 +22,6 @@ export const createSwipeToCloseGesture = (el, animation, statusBarStyle, onDismi
22
22
  let isOpen = false;
23
23
  let canDismissBlocksGesture = false;
24
24
  let contentEl = null;
25
- let scrollEl = null;
26
25
  const canDismissMaxStep = 0.2;
27
26
  let initialScrollY = true;
28
27
  let lastStep = 0;
@@ -45,12 +44,6 @@ export const createSwipeToCloseGesture = (el, animation, statusBarStyle, onDismi
45
44
  return true;
46
45
  }
47
46
  /**
48
- * If we are swiping on the content,
49
- * swiping should only be possible if
50
- * the content is scrolled all the way
51
- * to the top so that we do not interfere
52
- * with scrolling.
53
- *
54
47
  * We cannot assume that the `ion-content`
55
48
  * target will remain consistent between
56
49
  * swipes. For example, when using
@@ -61,29 +54,7 @@ export const createSwipeToCloseGesture = (el, animation, statusBarStyle, onDismi
61
54
  */
62
55
  contentEl = findClosestIonContent(target);
63
56
  if (contentEl) {
64
- /**
65
- * The card should never swipe to close
66
- * on the content with a refresher.
67
- * Note: We cannot solve this by making the
68
- * swipeToClose gesture have a higher priority
69
- * than the refresher gesture as the iOS native
70
- * refresh gesture uses a scroll listener in
71
- * addition to a gesture.
72
- *
73
- * Note: Do not use getScrollElement here
74
- * because we need this to be a synchronous
75
- * operation, and getScrollElement is
76
- * asynchronous.
77
- */
78
- if (isIonContent(contentEl)) {
79
- const root = getElementRoot(contentEl);
80
- scrollEl = root.querySelector('.inner-scroll');
81
- }
82
- else {
83
- scrollEl = contentEl;
84
- }
85
- const hasRefresherInContent = !!contentEl.querySelector('ion-refresher');
86
- return !hasRefresherInContent && scrollEl.scrollTop === 0;
57
+ return canSwipeOnContent(contentEl);
87
58
  }
88
59
  /**
89
60
  * Card should be swipeable on all
@@ -1,7 +1,24 @@
1
1
  /*!
2
2
  * (C) Ionic http://ionicframework.com - MIT License
3
3
  */
4
+ import { findRefresherInContent, isIonContent } from "../../../utils/content/index";
5
+ import { getElementRoot } from "../../../utils/helpers";
4
6
  import { GESTURE } from "../../../utils/overlays";
7
+ /**
8
+ * Swiping is only possible when the content is scrolled to the top, so that we
9
+ * do not interfere with scrolling, and never on content with a refresher.
10
+ *
11
+ * Note: We cannot solve the refresher case with gesture priority as the iOS
12
+ * native refresh gesture uses a scroll listener in addition to a gesture.
13
+ *
14
+ * Note: Do not use `getScrollElement` here because we need this to be a
15
+ * synchronous operation, and `getScrollElement` is asynchronous.
16
+ */
17
+ export const canSwipeOnContent = (contentEl) => {
18
+ const scrollEl = isIonContent(contentEl) ? getElementRoot(contentEl).querySelector('.inner-scroll') : contentEl;
19
+ const hasRefresherInContent = !!findRefresherInContent(contentEl);
20
+ return !hasRefresherInContent && scrollEl.scrollTop === 0;
21
+ };
5
22
  export const handleCanDismiss = async (el, animation) => {
6
23
  /**
7
24
  * If canDismiss is not a function
@@ -3,7 +3,7 @@
3
3
  */
4
4
  import { Host, h, readTask, writeTask } from "@stencil/core";
5
5
  import { getTimeGivenProgression } from "../../utils/animation/cubic-bezier";
6
- import { getScrollElement, ION_CONTENT_CLASS_SELECTOR, ION_CONTENT_ELEMENT_SELECTOR, printIonContentErrorMsg, } from "../../utils/content/index";
6
+ import { findRefresherScrollHost, getScrollElement, ION_CONTENT_CLASS_SELECTOR, ION_CONTENT_ELEMENT_SELECTOR, printIonContentErrorMsg, } from "../../utils/content/index";
7
7
  import { clamp, componentOnReady, getElementRoot, raf, transitionEndAsync } from "../../utils/helpers";
8
8
  import { printIonError } from "../../utils/logging/index";
9
9
  import { ImpactStyle, hapticImpact } from "../../utils/native/haptic";
@@ -393,7 +393,7 @@ export class Refresher {
393
393
  * or the background content element.
394
394
  */
395
395
  componentOnReady(contentEl, async () => {
396
- const customScrollTarget = contentEl.querySelector(ION_CONTENT_CLASS_SELECTOR);
396
+ const customScrollTarget = findRefresherScrollHost(contentEl);
397
397
  /**
398
398
  * Query the custom scroll target (if available), first. In refresher implementations,
399
399
  * the ion-refresher element will always be a direct child of ion-content (slot="fixed"). By
@@ -743,7 +743,7 @@ export class Refresher {
743
743
  }
744
744
  render() {
745
745
  const mode = getIonMode(this);
746
- return (h(Host, { key: '2eaca7f85b3d40418f213077434e519dfacd9d42', slot: "fixed", class: {
746
+ return (h(Host, { key: '6b94f11bd5382bdf4e92c43d4b5d0550c290852d', slot: "fixed", class: {
747
747
  [mode]: true,
748
748
  // Used internally for styling
749
749
  [`refresher-${mode}`]: true,
@@ -54,6 +54,36 @@ export const findIonContent = (el) => {
54
54
  export const findClosestIonContent = (el) => {
55
55
  return el.closest(ION_CONTENT_SELECTOR);
56
56
  };
57
+ /**
58
+ * Queries the custom scroll host an `ion-refresher` scrolls with in the given
59
+ * `ion-content`. A refresher only pairs with the first host.
60
+ */
61
+ export const findRefresherScrollHost = (ionContent) => {
62
+ return ionContent.querySelector(ION_CONTENT_CLASS_SELECTOR);
63
+ };
64
+ /**
65
+ * Queries the `ion-refresher` that scrolls with the given content element,
66
+ * which may be an `ion-content` or a custom scroll host. A refresher is a
67
+ * `slot="fixed"` child of `ion-content`, so it is a sibling of a scroll host
68
+ * rather than a descendant of it.
69
+ */
70
+ export const findRefresherInContent = (contentEl) => {
71
+ // An `ion-content` owns any refresher inside it, scroll host or not.
72
+ if (isIonContent(contentEl)) {
73
+ return contentEl.querySelector('ion-refresher');
74
+ }
75
+ // A refresher needs an `ion-content` ancestor to initialize.
76
+ const ionContent = contentEl.closest(ION_CONTENT_ELEMENT_SELECTOR);
77
+ if (ionContent === null) {
78
+ return null;
79
+ }
80
+ // Any scroll host other than the refresher's own has no refresher.
81
+ const refresherScrollHost = findRefresherScrollHost(ionContent);
82
+ if (refresherScrollHost === null || !refresherScrollHost.contains(contentEl)) {
83
+ return null;
84
+ }
85
+ return ionContent.querySelector('ion-refresher');
86
+ };
57
87
  /**
58
88
  * Scrolls to the top of the element. If an `ion-content` is found, it will scroll
59
89
  * using the public API `scrollToTop` with a duration.
package/dist/docs.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "timestamp": "2026-08-05T17:13:24",
2
+ "timestamp": "2026-08-07T13:32:45",
3
3
  "compiler": {
4
4
  "name": "@stencil/core",
5
5
  "version": "4.43.5",
@@ -55,6 +55,36 @@ const findIonContent = (el) => {
55
55
  const findClosestIonContent = (el) => {
56
56
  return el.closest(ION_CONTENT_SELECTOR);
57
57
  };
58
+ /**
59
+ * Queries the custom scroll host an `ion-refresher` scrolls with in the given
60
+ * `ion-content`. A refresher only pairs with the first host.
61
+ */
62
+ const findRefresherScrollHost = (ionContent) => {
63
+ return ionContent.querySelector(ION_CONTENT_CLASS_SELECTOR);
64
+ };
65
+ /**
66
+ * Queries the `ion-refresher` that scrolls with the given content element,
67
+ * which may be an `ion-content` or a custom scroll host. A refresher is a
68
+ * `slot="fixed"` child of `ion-content`, so it is a sibling of a scroll host
69
+ * rather than a descendant of it.
70
+ */
71
+ const findRefresherInContent = (contentEl) => {
72
+ // An `ion-content` owns any refresher inside it, scroll host or not.
73
+ if (isIonContent(contentEl)) {
74
+ return contentEl.querySelector('ion-refresher');
75
+ }
76
+ // A refresher needs an `ion-content` ancestor to initialize.
77
+ const ionContent = contentEl.closest(ION_CONTENT_ELEMENT_SELECTOR);
78
+ if (ionContent === null) {
79
+ return null;
80
+ }
81
+ // Any scroll host other than the refresher's own has no refresher.
82
+ const refresherScrollHost = findRefresherScrollHost(ionContent);
83
+ if (refresherScrollHost === null || !refresherScrollHost.contains(contentEl)) {
84
+ return null;
85
+ }
86
+ return ionContent.querySelector('ion-refresher');
87
+ };
58
88
  /**
59
89
  * Scrolls to the top of the element. If an `ion-content` is found, it will scroll
60
90
  * using the public API `scrollToTop` with a duration.
@@ -125,4 +155,4 @@ const resetContentScrollY = (contentEl, initialScrollY) => {
125
155
  }
126
156
  };
127
157
 
128
- export { ION_CONTENT_CLASS_SELECTOR as I, findIonContent as a, ION_CONTENT_ELEMENT_SELECTOR as b, scrollByPoint as c, disableContentScrollY as d, findClosestIonContent as f, getScrollElement as g, isIonContent as i, printIonContentErrorMsg as p, resetContentScrollY as r, scrollToTop as s };
158
+ export { ION_CONTENT_CLASS_SELECTOR as I, findClosestIonContent as a, findIonContent as b, ION_CONTENT_ELEMENT_SELECTOR as c, disableContentScrollY as d, findRefresherScrollHost as e, findRefresherInContent as f, getScrollElement as g, scrollByPoint as h, isIonContent as i, printIonContentErrorMsg as p, resetContentScrollY as r, scrollToTop as s };
@@ -2,7 +2,7 @@
2
2
  * (C) Ionic http://ionicframework.com - MIT License
3
3
  */
4
4
  import { w as win, d as doc } from './index-ZjP4CjeZ.js';
5
- import { g as getScrollElement, c as scrollByPoint, f as findClosestIonContent } from './index-MEDq2S8l.js';
5
+ import { g as getScrollElement, h as scrollByPoint, a as findClosestIonContent } from './index-Dw-wN0Ja.js';
6
6
  import { f as addEventListener, m as removeEventListener, c as componentOnReady } from './helpers-HEqiOzXb.js';
7
7
  import { a as KeyboardResize, K as Keyboard } from './keyboard-CUw4ekVy.js';
8
8
  import './index-tcQvqkiX.js';
@@ -7,7 +7,7 @@ import { a as isPlatform, b as getIonMode } from './ionic-global-Cp_eT4sZ.js';
7
7
  import { i as inheritAriaAttributes, h as hasLazyBuild, c as componentOnReady, e as clamp, s as shallowEqualStringMap } from './helpers-HEqiOzXb.js';
8
8
  import { i as isRTL } from './dir-C53feagD.js';
9
9
  import { c as createColorClasses, h as hostContext } from './theme-DiVJyqlX.js';
10
- import { a as findIonContent, p as printIonContentErrorMsg, g as getScrollElement } from './index-MEDq2S8l.js';
10
+ import { b as findIonContent, p as printIonContentErrorMsg, g as getScrollElement } from './index-Dw-wN0Ja.js';
11
11
  import { c as createKeyboardController } from './keyboard-controller-BaaVITYt.js';
12
12
  import { g as getTimeGivenProgression } from './cubic-bezier-hHmYLOfE.js';
13
13
  import { a as attachComponent, d as detachComponent } from './framework-delegate-FnPGymXL.js';
@@ -31,7 +31,7 @@ const App = class {
31
31
  import('./index-BRHzoo00.js').then((module) => module.startTapClick(config));
32
32
  }
33
33
  if (config.getBoolean('statusTap', isHybrid)) {
34
- import('./status-tap-Kan2W7sh.js').then((module) => module.startStatusTap());
34
+ import('./status-tap-vO-6s4Yp.js').then((module) => module.startStatusTap());
35
35
  }
36
36
  if (config.getBoolean('inputShims', needInputShims())) {
37
37
  /**
@@ -39,7 +39,7 @@ const App = class {
39
39
  * platforms proceed into this block.
40
40
  */
41
41
  const platform = isPlatform(window, 'ios') ? 'ios' : 'android';
42
- import('./input-shims-D10mwcw1.js').then((module) => module.startInputShims(config, platform));
42
+ import('./input-shims-LXhI7LEx.js').then((module) => module.startInputShims(config, platform));
43
43
  }
44
44
  const hardwareBackButtonModule = await import('./hardware-back-button-B93Gru0Y.js');
45
45
  const supportsHardwareBackButtonEvents = isHybrid || shouldUseCloseWatcher();
@@ -2,7 +2,7 @@
2
2
  * (C) Ionic http://ionicframework.com - MIT License
3
3
  */
4
4
  import { r as registerInstance, c as createEvent, w as writeTask, a as readTask, h, d as Host, g as getElement, e as config } from './index-tcQvqkiX.js';
5
- import { f as findClosestIonContent, p as printIonContentErrorMsg, g as getScrollElement } from './index-MEDq2S8l.js';
5
+ import { a as findClosestIonContent, p as printIonContentErrorMsg, g as getScrollElement } from './index-Dw-wN0Ja.js';
6
6
  import { b as getIonMode } from './ionic-global-Cp_eT4sZ.js';
7
7
  import { E as ENABLE_HTML_CONTENT_DEFAULT, a as sanitizeDOMString } from './config-DQCONYYp.js';
8
8
  import './helpers-HEqiOzXb.js';
@@ -5,7 +5,7 @@ import { r as registerInstance, h, d as Host, g as getElement, c as createEvent,
5
5
  import { c as createColorClasses } from './theme-DiVJyqlX.js';
6
6
  import { b as getIonMode } from './ionic-global-Cp_eT4sZ.js';
7
7
  import { o as isEndSide } from './helpers-HEqiOzXb.js';
8
- import { f as findClosestIonContent, d as disableContentScrollY, r as resetContentScrollY } from './index-MEDq2S8l.js';
8
+ import { a as findClosestIonContent, d as disableContentScrollY, r as resetContentScrollY } from './index-Dw-wN0Ja.js';
9
9
  import { w as watchForOptions } from './watch-options-Dtdm8lKC.js';
10
10
 
11
11
  const itemOptionIosCss = () => `:host{--background:var(--ion-color-primary, #0054e9);--color:var(--ion-color-primary-contrast, #fff);background:var(--background);color:var(--color);font-family:var(--ion-font-family, inherit)}:host(.ion-color){background:var(--ion-color-base);color:var(--ion-color-contrast)}.button-native{font-family:inherit;font-size:inherit;font-style:inherit;font-weight:inherit;letter-spacing:inherit;text-decoration:inherit;text-indent:inherit;text-overflow:inherit;text-transform:inherit;text-align:inherit;white-space:inherit;color:inherit;-webkit-padding-start:0.7em;padding-inline-start:0.7em;-webkit-padding-end:0.7em;padding-inline-end:0.7em;padding-top:0;padding-bottom:0;display:inline-block;position:relative;width:100%;height:100%;border:0;outline:none;background:transparent;cursor:pointer;-webkit-appearance:none;-moz-appearance:none;appearance:none;-webkit-box-sizing:border-box;box-sizing:border-box}.button-inner{display:-ms-flexbox;display:flex;-ms-flex-flow:column nowrap;flex-flow:column nowrap;-ms-flex-negative:0;flex-shrink:0;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;width:100%;height:100%}.horizontal-wrapper{display:-ms-flexbox;display:flex;-ms-flex-flow:row nowrap;flex-flow:row nowrap;-ms-flex-negative:0;flex-shrink:0;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;width:100%}::slotted(*){-ms-flex-negative:0;flex-shrink:0}::slotted([slot=start]){-webkit-margin-start:0;margin-inline-start:0;-webkit-margin-end:5px;margin-inline-end:5px;margin-top:0;margin-bottom:0}::slotted([slot=end]){-webkit-margin-start:5px;margin-inline-start:5px;-webkit-margin-end:0;margin-inline-end:0;margin-top:0;margin-bottom:0}::slotted([slot=icon-only]){padding-left:0;padding-right:0;padding-top:0;padding-bottom:0;-webkit-margin-start:10px;margin-inline-start:10px;-webkit-margin-end:10px;margin-inline-end:10px;margin-top:0;margin-bottom:0;min-width:0.9em;font-size:1.8em}:host(.item-option-expandable){-ms-flex-negative:0;flex-shrink:0;-webkit-transition-duration:0;transition-duration:0;-webkit-transition-property:none;transition-property:none;-webkit-transition-timing-function:cubic-bezier(0.65, 0.05, 0.36, 1);transition-timing-function:cubic-bezier(0.65, 0.05, 0.36, 1)}:host(.item-option-disabled){pointer-events:none}:host(.item-option-disabled) .button-native{cursor:default;opacity:0.5;pointer-events:none}:host{font-size:clamp(16px, 1rem, 35.2px)}:host(.ion-activated){background:var(--ion-color-primary-shade, #004acd)}:host(.ion-color.ion-activated){background:var(--ion-color-shade)}`;