voyager-ionic-core 9.0.7 → 9.0.9
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/components/index.js +1 -1
- package/components/ion-action-sheet.js +1 -1
- package/components/ion-alert.js +1 -1
- package/components/ion-backdrop.js +1 -1
- package/components/ion-datetime.js +1 -1
- package/components/ion-input.js +1 -1
- package/components/ion-loading.js +1 -1
- package/components/ion-menu.js +1 -1
- package/components/ion-modal.js +1 -1
- package/components/ion-nav.js +1 -1
- package/components/ion-popover.js +1 -1
- package/components/ion-router-outlet.js +1 -1
- package/components/ion-select.js +1 -1
- package/components/ion-textarea.js +1 -1
- package/components/p-Bd8hg9FK.js +4 -0
- package/components/{p-DhfJAkyd.js → p-CKTjkpAq.js} +1 -1
- package/components/{p-DnGlmM4u.js → p-CONpe3oX.js} +1 -1
- package/components/{p-DMPsc_0r.js → p-CW84OFQa.js} +1 -1
- package/components/{p-D64Tyi-z.js → p-CYctYy9B.js} +1 -1
- package/components/{p-Dvyv9SMk.js → p-D0nwlsl_.js} +1 -1
- package/components/p-DfDIY2oP.js +4 -0
- package/components/p-SHHIB5F0.js +4 -0
- package/components/p-zQi7R3tS.js +4 -0
- package/css/core.css.map +1 -1
- package/css/ionic.bundle.css.map +1 -1
- package/dist/cjs/{index-DUiuw_fH.js → index-DCfr5hz-.js} +14 -2
- package/dist/cjs/index.cjs.js +3 -3
- package/dist/cjs/ion-app_8.cjs.entry.js +31 -3
- package/dist/cjs/ion-backdrop.cjs.entry.js +5 -1
- package/dist/cjs/ion-datetime.cjs.entry.js +55 -9
- package/dist/cjs/ion-input.cjs.entry.js +13 -13
- package/dist/cjs/ion-modal.cjs.entry.js +31 -81
- package/dist/cjs/ion-nav_2.cjs.entry.js +24 -2
- package/dist/cjs/ion-popover.cjs.entry.js +1 -1
- package/dist/cjs/ion-select_3.cjs.entry.js +12 -12
- package/dist/cjs/ion-textarea.cjs.entry.js +12 -12
- package/dist/cjs/{ios.transition-D85_rHf5.js → ios.transition-Ca6XODo9.js} +1 -1
- package/dist/cjs/{md.transition-Ce9X1WXr.js → md.transition-D8SfNYEp.js} +1 -1
- package/dist/cjs/{slot-mutation-controller-ClDxh3EK.js → slot-mutation-controller-B2OfJEBH.js} +67 -33
- package/dist/collection/components/backdrop/backdrop.js +6 -2
- package/dist/collection/components/datetime/datetime.js +56 -10
- package/dist/collection/components/input/input.ios.css +7 -3
- package/dist/collection/components/input/input.js +11 -11
- package/dist/collection/components/input/input.md.css +28 -15
- package/dist/collection/components/modal/gestures/sheet.js +30 -80
- package/dist/collection/components/nav/nav.js +24 -2
- package/dist/collection/components/router-outlet/router-outlet.js +31 -3
- package/dist/collection/components/select/select.ios.css +7 -3
- package/dist/collection/components/select/select.js +10 -10
- package/dist/collection/components/select/select.md.css +28 -15
- package/dist/collection/components/textarea/textarea.ios.css +7 -3
- package/dist/collection/components/textarea/textarea.js +10 -10
- package/dist/collection/components/textarea/textarea.md.css +28 -17
- package/dist/collection/utils/forms/index.js +1 -1
- package/dist/collection/utils/forms/{start-container-controller.js → start-end-container-controller.js} +66 -32
- package/dist/collection/utils/transition/index.js +11 -0
- package/dist/docs.json +3 -3
- package/dist/esm/{index-BBASprVu.js → index-z9vdZN7I.js} +14 -3
- package/dist/esm/index.js +3 -3
- package/dist/esm/ion-app_8.entry.js +31 -3
- package/dist/esm/ion-backdrop.entry.js +5 -1
- package/dist/esm/ion-datetime.entry.js +55 -9
- package/dist/esm/ion-input.entry.js +13 -13
- package/dist/esm/ion-modal.entry.js +31 -81
- package/dist/esm/ion-nav_2.entry.js +24 -2
- package/dist/esm/ion-popover.entry.js +1 -1
- package/dist/esm/ion-select_3.entry.js +12 -12
- package/dist/esm/ion-textarea.entry.js +12 -12
- package/dist/esm/{ios.transition-B8netzsb.js → ios.transition-BkUGiDUz.js} +1 -1
- package/dist/esm/{md.transition-DNCSSiXk.js → md.transition-B6hlrWjR.js} +1 -1
- package/dist/esm/{slot-mutation-controller-hAS2uJ7c.js → slot-mutation-controller-Btpr9-9O.js} +67 -33
- package/dist/html.html-data.json +1 -1
- package/dist/ionic/index.esm.js +1 -1
- package/dist/ionic/ionic.esm.js +1 -1
- package/dist/ionic/p-293cb1d5.entry.js +4 -0
- package/dist/ionic/p-61321cfa.entry.js +4 -0
- package/dist/ionic/p-657239f5.entry.js +4 -0
- package/dist/ionic/p-67f004eb.entry.js +4 -0
- package/dist/ionic/{p-230f510c.entry.js → p-76c189e7.entry.js} +1 -1
- package/dist/ionic/p-94f1f7df.entry.js +4 -0
- package/dist/ionic/{p-Bppj2PE0.js → p-BZTgGzGK.js} +1 -1
- package/dist/ionic/p-BpED_ep_.js +4 -0
- package/dist/ionic/{p-Bnc1L7Rk.js → p-CgcGX08t.js} +1 -1
- package/dist/ionic/p-Dk4Mdaru.js +4 -0
- package/dist/ionic/{p-4ed3c460.entry.js → p-a7d368b5.entry.js} +1 -1
- package/dist/ionic/p-e8e69c21.entry.js +4 -0
- package/dist/ionic/{p-af56702e.entry.js → p-f2116a54.entry.js} +1 -1
- package/dist/types/components/backdrop/backdrop.d.ts +4 -0
- package/dist/types/components/datetime/datetime.d.ts +20 -3
- package/dist/types/components/input/input.d.ts +2 -1
- package/dist/types/components/nav/nav.d.ts +1 -0
- package/dist/types/components/router-outlet/router-outlet.d.ts +1 -0
- package/dist/types/components/select/select.d.ts +2 -1
- package/dist/types/components/textarea/textarea.d.ts +2 -1
- package/dist/types/components.d.ts +3 -3
- package/dist/types/utils/forms/index.d.ts +1 -1
- package/dist/types/utils/forms/start-end-container-controller.d.ts +44 -0
- package/dist/types/utils/transition/index.d.ts +6 -0
- package/hydrate/index.js +254 -159
- package/hydrate/index.mjs +254 -159
- package/package.json +4 -4
- package/components/p-C7r5Gja6.js +0 -4
- package/components/p-CtiO6_sC.js +0 -4
- package/components/p-TLtgwTFF.js +0 -4
- package/components/p-Uk13YgEc.js +0 -4
- package/dist/ionic/p-27d96a9b.entry.js +0 -4
- package/dist/ionic/p-4d785062.entry.js +0 -4
- package/dist/ionic/p-6317d620.entry.js +0 -4
- package/dist/ionic/p-8b79061e.entry.js +0 -4
- package/dist/ionic/p-B8IuTu_r.js +0 -4
- package/dist/ionic/p-DQXtveHv.js +0 -4
- package/dist/ionic/p-c81ec0e8.entry.js +0 -4
- package/dist/ionic/p-d9a3dfd1.entry.js +0 -4
- package/dist/types/utils/forms/start-container-controller.d.ts +0 -34
|
@@ -7,6 +7,8 @@ import { clamp, getElementRoot, raf } from "../../../utils/helpers";
|
|
|
7
7
|
import { FOCUS_TRAP_DISABLE_CLASS } from "../../../utils/overlays";
|
|
8
8
|
import { getBackdropValueForSheet } from "../utils";
|
|
9
9
|
import { calculateSpringStep, canSwipeOnContent, handleCanDismiss } from "./utils";
|
|
10
|
+
/** How far ahead, in milliseconds, a drag's velocity is projected when snapping. */
|
|
11
|
+
const FLICK_PROJECTION_MS = 350;
|
|
10
12
|
export const createSheetGesture = (baseEl, backdropEl, wrapperEl, initialBreakpoint, backdropBreakpoint, animation, breakpoints = [], expandToScroll, getCurrentBreakpoint, onDismiss, onBreakpointChange, onDragStart, onDragMove, onDragEnd) => {
|
|
11
13
|
// Defaults for the sheet swipe animation
|
|
12
14
|
const defaultBackdrop = [
|
|
@@ -32,6 +34,11 @@ export const createSheetGesture = (baseEl, backdropEl, wrapperEl, initialBreakpo
|
|
|
32
34
|
const contentEl = baseEl.querySelector('ion-content');
|
|
33
35
|
// Cache the initial value so the gesture restores it instead of forcing scrolling on.
|
|
34
36
|
const initialContentScrollY = contentEl?.scrollY ?? true;
|
|
37
|
+
/**
|
|
38
|
+
* The height of the sheet the user actually sees. This comes from the wrapper
|
|
39
|
+
* rather than the host element, which is stretched to the full viewport no
|
|
40
|
+
* matter how tall the sheet itself is.
|
|
41
|
+
*/
|
|
35
42
|
const height = wrapperEl.clientHeight;
|
|
36
43
|
let currentBreakpoint = initialBreakpoint;
|
|
37
44
|
let offset = 0;
|
|
@@ -329,18 +336,18 @@ export const createSheetGesture = (baseEl, backdropEl, wrapperEl, initialBreakpo
|
|
|
329
336
|
: step;
|
|
330
337
|
offset = clamp(0.0001, processedStep, maxStep);
|
|
331
338
|
animation.progressStep(offset);
|
|
332
|
-
const snapBreakpoint = calculateSnapBreakpoint(detail.deltaY);
|
|
339
|
+
const snapBreakpoint = calculateSnapBreakpoint(detail.deltaY, detail.velocityY);
|
|
333
340
|
const eventDetail = {
|
|
334
341
|
currentY: detail.currentY,
|
|
335
342
|
deltaY: detail.deltaY,
|
|
336
343
|
velocityY: detail.velocityY,
|
|
337
|
-
progress:
|
|
344
|
+
progress: calculateEventProgress(detail.deltaY),
|
|
338
345
|
snapBreakpoint: snapBreakpoint,
|
|
339
346
|
};
|
|
340
347
|
onDragMove(eventDetail);
|
|
341
348
|
};
|
|
342
349
|
const onEnd = (detail) => {
|
|
343
|
-
const snapBreakpoint = calculateSnapBreakpoint(detail.deltaY);
|
|
350
|
+
const snapBreakpoint = calculateSnapBreakpoint(detail.deltaY, detail.velocityY);
|
|
344
351
|
/**
|
|
345
352
|
* `snapBreakpoint === 0` is not enough on its own. `canDismiss: false`
|
|
346
353
|
* snaps to 0 but never dismisses, since `handleCanDismiss` returns early
|
|
@@ -354,7 +361,7 @@ export const createSheetGesture = (baseEl, backdropEl, wrapperEl, initialBreakpo
|
|
|
354
361
|
currentY: detail.currentY,
|
|
355
362
|
deltaY: detail.deltaY,
|
|
356
363
|
velocityY: detail.velocityY,
|
|
357
|
-
progress:
|
|
364
|
+
progress: calculateEventProgress(detail.deltaY),
|
|
358
365
|
snapBreakpoint,
|
|
359
366
|
isDismissing,
|
|
360
367
|
};
|
|
@@ -530,24 +537,15 @@ export const createSheetGesture = (baseEl, backdropEl, wrapperEl, initialBreakpo
|
|
|
530
537
|
});
|
|
531
538
|
};
|
|
532
539
|
/**
|
|
533
|
-
*
|
|
534
|
-
* This determines where the sheet should snap to when the user releases the
|
|
535
|
-
* gesture.
|
|
540
|
+
* Decides which breakpoint the sheet should settle on for the current drag.
|
|
536
541
|
*
|
|
537
|
-
* @param deltaY The change in Y position since the gesture started
|
|
538
|
-
* @
|
|
542
|
+
* @param deltaY The change in Y position since the gesture started
|
|
543
|
+
* @param velocityY The velocity in pixels per millisecond
|
|
544
|
+
* @returns The snap breakpoint value
|
|
539
545
|
*/
|
|
540
|
-
const calculateSnapBreakpoint = (deltaY) => {
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
* We combine the wrapper's current bounding box position with the
|
|
544
|
-
* gesture's deltaY to account for the physical movement during the drag.
|
|
545
|
-
*/
|
|
546
|
-
const currentY = wrapperEl.getBoundingClientRect().top + deltaY;
|
|
547
|
-
/**
|
|
548
|
-
* Convert that pixel position back into a 0 to 1 progress value.
|
|
549
|
-
*/
|
|
550
|
-
const currentProgress = calculateProgress(currentY);
|
|
546
|
+
const calculateSnapBreakpoint = (deltaY, velocityY) => {
|
|
547
|
+
// Project the drag forward so a quick flick counts.
|
|
548
|
+
const currentProgress = calculateProgress(deltaY + velocityY * FLICK_PROJECTION_MS);
|
|
551
549
|
/**
|
|
552
550
|
* Find and return the defined breakpoint that is closest to the
|
|
553
551
|
* current progress.
|
|
@@ -558,74 +556,26 @@ export const createSheetGesture = (baseEl, backdropEl, wrapperEl, initialBreakpo
|
|
|
558
556
|
return snapBreakpoint;
|
|
559
557
|
};
|
|
560
558
|
/**
|
|
561
|
-
* Calculates the
|
|
559
|
+
* Calculates how open the sheet is part way through a gesture, on the same
|
|
560
|
+
* 0 to 1 scale as the breakpoints: 1 is fully open and 0 is fully closed.
|
|
562
561
|
*
|
|
563
|
-
*
|
|
564
|
-
* the swipe has progressed towards closing the modal.
|
|
565
|
-
*
|
|
566
|
-
* A value closer to 1 means the modal is closer to being opened,
|
|
567
|
-
* while a value closer to 0 means the modal is closer to being closed.
|
|
568
|
-
*
|
|
569
|
-
* @param currentY The current Y position of the gesture
|
|
562
|
+
* @param deltaY The change in Y position since the gesture started
|
|
570
563
|
* @returns The progress of the sheet gesture
|
|
571
564
|
*/
|
|
572
|
-
const calculateProgress = (
|
|
573
|
-
|
|
574
|
-
const
|
|
575
|
-
/**
|
|
576
|
-
* The lowest point the sheet can be dragged to aka the point at which
|
|
577
|
-
* the sheet is fully closed.
|
|
578
|
-
*/
|
|
579
|
-
const maxY = convertBreakpointToY(minBreakpoint);
|
|
580
|
-
/**
|
|
581
|
-
* The highest point the sheet can be dragged to aka the point at which
|
|
582
|
-
* the sheet is fully open.
|
|
583
|
-
*/
|
|
584
|
-
const minY = convertBreakpointToY(maxBreakpoint);
|
|
585
|
-
// The total distance between the fully open and fully closed positions.
|
|
586
|
-
const totalDistance = maxY - minY;
|
|
587
|
-
// The distance from the current position to the fully closed position.
|
|
588
|
-
const distanceFromBottom = maxY - currentY;
|
|
589
|
-
/**
|
|
590
|
-
* The progress represents how far the sheet is from the bottom relative
|
|
591
|
-
* to the total distance. When the user starts swiping up, the progress
|
|
592
|
-
* should be close to 1, and when the user has swiped all the way down,
|
|
593
|
-
* the progress should be close to 0.
|
|
594
|
-
*/
|
|
595
|
-
const progress = distanceFromBottom / totalDistance;
|
|
565
|
+
const calculateProgress = (deltaY) => {
|
|
566
|
+
// Mirrors the animation step in onMove, so the snap matches where the sheet is drawn.
|
|
567
|
+
const progress = currentBreakpoint - deltaY / height;
|
|
596
568
|
// Round to the nearest thousandth to avoid returning very small decimal
|
|
597
569
|
const roundedProgress = Math.round(progress * 1000) / 1000;
|
|
598
|
-
return
|
|
570
|
+
return clamp(0, roundedProgress, 1);
|
|
599
571
|
};
|
|
600
572
|
/**
|
|
601
|
-
*
|
|
602
|
-
*
|
|
603
|
-
*
|
|
604
|
-
* @param breakpoint The breakpoint value (e.g., 0.5 for half-open)
|
|
605
|
-
* @returns The pixel Y coordinate on the screen
|
|
573
|
+
* Scales the progress from the lowest to the highest breakpoint, so the
|
|
574
|
+
* drag events report 0 at the lowest breakpoint and 1 at the highest.
|
|
606
575
|
*/
|
|
607
|
-
const
|
|
608
|
-
const
|
|
609
|
-
|
|
610
|
-
// The bottom of the screen.
|
|
611
|
-
const viewportBottom = window.innerHeight;
|
|
612
|
-
/**
|
|
613
|
-
* The active height is how much of the modal is actually showing
|
|
614
|
-
* on the screen for this specific breakpoint.
|
|
615
|
-
*/
|
|
616
|
-
const activeHeight = modalHeight * breakpoint;
|
|
617
|
-
/**
|
|
618
|
-
* To find the Y coordinate, start at the bottom of the screen
|
|
619
|
-
* and move up by the active height of the modal.
|
|
620
|
-
*
|
|
621
|
-
* A breakpoint of 1.0 means the active height is the full modal height
|
|
622
|
-
* (fully open). A breakpoint of 0.0 means the active height is 0
|
|
623
|
-
* (fully closed).
|
|
624
|
-
*
|
|
625
|
-
* Since screen Y coordinates get smaller as you go up, we subtract the
|
|
626
|
-
* active height from the viewport bottom.
|
|
627
|
-
*/
|
|
628
|
-
return viewportBottom - activeHeight;
|
|
576
|
+
const calculateEventProgress = (deltaY) => {
|
|
577
|
+
const progress = (calculateProgress(deltaY) - minBreakpoint) / (maxBreakpoint - minBreakpoint);
|
|
578
|
+
return clamp(0, progress, 1);
|
|
629
579
|
};
|
|
630
580
|
const gesture = createGesture({
|
|
631
581
|
el: wrapperEl,
|
|
@@ -5,7 +5,7 @@ import { h } from "@stencil/core";
|
|
|
5
5
|
import { getTimeGivenProgression } from "../../utils/animation/cubic-bezier";
|
|
6
6
|
import { assert } from "../../utils/helpers";
|
|
7
7
|
import { printIonWarning } from "../../utils/logging/index";
|
|
8
|
-
import { lifecycle, setPageHidden, transition } from "../../utils/transition/index";
|
|
8
|
+
import { blockSwipeClicks, lifecycle, setPageHidden, transition } from "../../utils/transition/index";
|
|
9
9
|
import { config } from "../../global/config";
|
|
10
10
|
import { getIonMode } from "../../global/ionic-global";
|
|
11
11
|
import { LIFECYCLE_DID_LEAVE, LIFECYCLE_WILL_LEAVE, LIFECYCLE_WILL_UNLOAD } from "./constants";
|
|
@@ -68,6 +68,12 @@ export class Nav {
|
|
|
68
68
|
this.gesture.destroy();
|
|
69
69
|
this.gesture = undefined;
|
|
70
70
|
}
|
|
71
|
+
// Destroying the gesture skips onEnd, so end a deferred swipe here.
|
|
72
|
+
if (this.unblockSwipeClicks) {
|
|
73
|
+
this.unblockSwipeClicks();
|
|
74
|
+
this.unblockSwipeClicks = undefined;
|
|
75
|
+
this.gestureOrAnimationInProgress = false;
|
|
76
|
+
}
|
|
71
77
|
this.transInstr.length = 0;
|
|
72
78
|
this.views.length = 0;
|
|
73
79
|
this.destroyed = true;
|
|
@@ -688,6 +694,14 @@ export class Nav {
|
|
|
688
694
|
}
|
|
689
695
|
onStart() {
|
|
690
696
|
this.gestureOrAnimationInProgress = true;
|
|
697
|
+
/**
|
|
698
|
+
* Without animations there's nothing for the swipe to drive, so
|
|
699
|
+
* wait until the gesture ends to decide whether to go back.
|
|
700
|
+
*/
|
|
701
|
+
if (!(this.animated && config.getBoolean('animated', true))) {
|
|
702
|
+
this.unblockSwipeClicks = blockSwipeClicks(this.el);
|
|
703
|
+
return;
|
|
704
|
+
}
|
|
691
705
|
this.pop({ direction: 'back', progressAnimation: true });
|
|
692
706
|
}
|
|
693
707
|
onMove(stepValue) {
|
|
@@ -721,10 +735,18 @@ export class Nav {
|
|
|
721
735
|
}
|
|
722
736
|
else {
|
|
723
737
|
this.gestureOrAnimationInProgress = false;
|
|
738
|
+
const { unblockSwipeClicks } = this;
|
|
739
|
+
if (unblockSwipeClicks) {
|
|
740
|
+
this.unblockSwipeClicks = undefined;
|
|
741
|
+
if (shouldComplete) {
|
|
742
|
+
this.pop({ direction: 'back' });
|
|
743
|
+
}
|
|
744
|
+
unblockSwipeClicks();
|
|
745
|
+
}
|
|
724
746
|
}
|
|
725
747
|
}
|
|
726
748
|
render() {
|
|
727
|
-
return h("slot", { key: '
|
|
749
|
+
return h("slot", { key: '0aea554c0cf00dd3829757ec74c3855eccf1e068' });
|
|
728
750
|
}
|
|
729
751
|
static get is() { return "ion-nav"; }
|
|
730
752
|
static get encapsulation() { return "shadow"; }
|
|
@@ -7,7 +7,7 @@ import { attachComponent, detachComponent } from "../../utils/framework-delegate
|
|
|
7
7
|
import { shallowEqualStringMap, hasLazyBuild } from "../../utils/helpers";
|
|
8
8
|
import { createLockController } from "../../utils/lock-controller";
|
|
9
9
|
import { printIonError } from "../../utils/logging/index";
|
|
10
|
-
import { transition } from "../../utils/transition/index";
|
|
10
|
+
import { blockSwipeClicks, transition } from "../../utils/transition/index";
|
|
11
11
|
import { config } from "../../global/config";
|
|
12
12
|
import { getIonMode } from "../../global/ionic-global";
|
|
13
13
|
export class RouterOutlet {
|
|
@@ -32,6 +32,14 @@ export class RouterOutlet {
|
|
|
32
32
|
async connectedCallback() {
|
|
33
33
|
const onStart = () => {
|
|
34
34
|
this.gestureOrAnimationInProgress = true;
|
|
35
|
+
/**
|
|
36
|
+
* Without animations there's nothing for the swipe to drive, so
|
|
37
|
+
* wait until the gesture ends to decide whether to go back.
|
|
38
|
+
*/
|
|
39
|
+
if (!(this.animated && config.getBoolean('animated', true))) {
|
|
40
|
+
this.unblockSwipeClicks = blockSwipeClicks(this.el);
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
35
43
|
if (this.swipeHandler) {
|
|
36
44
|
this.swipeHandler.onStart();
|
|
37
45
|
}
|
|
@@ -65,7 +73,21 @@ export class RouterOutlet {
|
|
|
65
73
|
this.ani.progressEnd(shouldComplete ? 1 : 0, newStepValue, dur);
|
|
66
74
|
}
|
|
67
75
|
else {
|
|
68
|
-
|
|
76
|
+
const { swipeHandler, unblockSwipeClicks: unblock } = this;
|
|
77
|
+
this.unblockSwipeClicks = undefined;
|
|
78
|
+
// The stack can change during the swipe, so check that going back is still possible.
|
|
79
|
+
if (unblock && shouldComplete && swipeHandler?.canStart()) {
|
|
80
|
+
new Promise((resolve) => resolve(swipeHandler.onStart()))
|
|
81
|
+
.then(() => swipeHandler.onEnd(true))
|
|
82
|
+
.finally(() => {
|
|
83
|
+
this.gestureOrAnimationInProgress = false;
|
|
84
|
+
unblock();
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
this.gestureOrAnimationInProgress = false;
|
|
89
|
+
unblock?.();
|
|
90
|
+
}
|
|
69
91
|
}
|
|
70
92
|
});
|
|
71
93
|
if (this.swipeGesture === undefined) {
|
|
@@ -88,6 +110,12 @@ export class RouterOutlet {
|
|
|
88
110
|
this.gesture.destroy();
|
|
89
111
|
this.gesture = undefined;
|
|
90
112
|
}
|
|
113
|
+
// Destroying the gesture skips onEnd, so end a deferred swipe here.
|
|
114
|
+
if (this.unblockSwipeClicks) {
|
|
115
|
+
this.unblockSwipeClicks();
|
|
116
|
+
this.unblockSwipeClicks = undefined;
|
|
117
|
+
this.gestureOrAnimationInProgress = false;
|
|
118
|
+
}
|
|
91
119
|
}
|
|
92
120
|
/** @internal */
|
|
93
121
|
async commit(enteringEl, leavingEl, opts) {
|
|
@@ -199,7 +227,7 @@ export class RouterOutlet {
|
|
|
199
227
|
return true;
|
|
200
228
|
}
|
|
201
229
|
render() {
|
|
202
|
-
return h("slot", { key: '
|
|
230
|
+
return h("slot", { key: '811f32d8794e58fcc79deef1e217c4d419778742' });
|
|
203
231
|
}
|
|
204
232
|
static get is() { return "ion-router-outlet"; }
|
|
205
233
|
static get encapsulation() { return "shadow"; }
|
|
@@ -390,7 +390,11 @@ button {
|
|
|
390
390
|
* would not be able to see what they are typing.
|
|
391
391
|
*/
|
|
392
392
|
max-width: 200px;
|
|
393
|
-
|
|
393
|
+
/**
|
|
394
|
+
* The max-width animates with the transform so the label does not
|
|
395
|
+
* reveal its full floating width while it is still at full size.
|
|
396
|
+
*/
|
|
397
|
+
transition: color 150ms cubic-bezier(0.4, 0, 0.2, 1), transform 150ms cubic-bezier(0.4, 0, 0.2, 1), max-width 150ms cubic-bezier(0.4, 0, 0.2, 1);
|
|
394
398
|
/**
|
|
395
399
|
* This ensures that double tapping this text
|
|
396
400
|
* clicks the <label> and focuses the input
|
|
@@ -404,8 +408,8 @@ button {
|
|
|
404
408
|
* disable the label transition to prevent the floating label
|
|
405
409
|
* from animating as its position is adjusted.
|
|
406
410
|
*
|
|
407
|
-
* This class is applied by the start container controller,
|
|
408
|
-
* renaming it here requires renaming it there too.
|
|
411
|
+
* This class is applied by the start and end container controller,
|
|
412
|
+
* so renaming it here requires renaming it there too.
|
|
409
413
|
*/
|
|
410
414
|
:host(.skip-label-transition) .label-text-wrapper {
|
|
411
415
|
transition: none;
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import { Build, Host, h, forceUpdate, } from "@stencil/core";
|
|
5
5
|
import { ENABLE_HTML_CONTENT_DEFAULT } from "../../utils/config";
|
|
6
|
-
import { compareOptions, createClickController, createNotchController,
|
|
6
|
+
import { compareOptions, createClickController, createNotchController, createStartEndContainerController, getSlottedClickContent, isOptionSelected, checkInvalidState, } from "../../utils/forms/index";
|
|
7
7
|
import { focusVisibleElement, renderHiddenInput, inheritAttributes } from "../../utils/helpers";
|
|
8
8
|
import { printIonWarning } from "../../utils/logging/index";
|
|
9
9
|
import { actionSheetController, alertController, popoverController, modalController } from "../../utils/overlays";
|
|
@@ -186,14 +186,14 @@ export class Select {
|
|
|
186
186
|
async connectedCallback() {
|
|
187
187
|
const { el } = this;
|
|
188
188
|
this.slotMutationController = createSlotMutationController(el, ['label', 'start', 'end'], () => {
|
|
189
|
-
this.
|
|
189
|
+
this.startEndContainerController?.calculateContainerWidths();
|
|
190
190
|
forceUpdate(this);
|
|
191
191
|
});
|
|
192
192
|
this.notchController = createNotchController(el, () => this.notchSpacerEl, () => this.labelSlot);
|
|
193
|
-
this.
|
|
193
|
+
this.startEndContainerController = createStartEndContainerController(el, () => this.startContainerEl, () => this.endContainerEl, () => {
|
|
194
194
|
return Build.isBrowser && getIonMode(this) === 'md' && this.fill === 'outline';
|
|
195
195
|
});
|
|
196
|
-
this.
|
|
196
|
+
this.startEndContainerController.calculateContainerWidths();
|
|
197
197
|
this.clickController = createClickController(el);
|
|
198
198
|
this.updateOverlayOptions();
|
|
199
199
|
this.emitStyle();
|
|
@@ -274,9 +274,9 @@ export class Select {
|
|
|
274
274
|
this.notchController.destroy();
|
|
275
275
|
this.notchController = undefined;
|
|
276
276
|
}
|
|
277
|
-
if (this.
|
|
278
|
-
this.
|
|
279
|
-
this.
|
|
277
|
+
if (this.startEndContainerController) {
|
|
278
|
+
this.startEndContainerController.destroy();
|
|
279
|
+
this.startEndContainerController = undefined;
|
|
280
280
|
}
|
|
281
281
|
// Clean up validation observer to prevent memory leaks.
|
|
282
282
|
if (this.validationObserver) {
|
|
@@ -752,7 +752,7 @@ export class Select {
|
|
|
752
752
|
}
|
|
753
753
|
componentDidRender() {
|
|
754
754
|
this.notchController?.calculateNotchWidth();
|
|
755
|
-
this.
|
|
755
|
+
this.startEndContainerController?.calculateContainerWidths();
|
|
756
756
|
}
|
|
757
757
|
/**
|
|
758
758
|
* Gets any content passed into the `label` slot,
|
|
@@ -940,7 +940,7 @@ export class Select {
|
|
|
940
940
|
const hasOutlineFill = mode === 'md' && fill === 'outline';
|
|
941
941
|
renderHiddenInput(true, el, name, parseValue(value), disabled);
|
|
942
942
|
const labelShouldFloat = labelPlacement === 'stacked' || (labelPlacement === 'floating' && (hasValue || hasFocus || isExpanded));
|
|
943
|
-
return (h(Host, { key: '
|
|
943
|
+
return (h(Host, { key: 'c1949b8a58c5bde1cc7627d3b32c54bcb46a4752', onClick: this.onClick, class: createColorClasses(this.color, {
|
|
944
944
|
[mode]: true,
|
|
945
945
|
'in-item': inItem,
|
|
946
946
|
'in-item-color': hostContext('ion-item.ion-color', el),
|
|
@@ -958,7 +958,7 @@ export class Select {
|
|
|
958
958
|
[`select-justify-${justify}`]: justifyEnabled,
|
|
959
959
|
[`select-shape-${shape}`]: shape !== undefined,
|
|
960
960
|
[`select-label-placement-${labelPlacement}`]: true,
|
|
961
|
-
}) }, h("label", { key: '
|
|
961
|
+
}) }, h("label", { key: 'af4521a3679d9e4e08511e205f53663d8d5b6701', class: "select-wrapper", id: "select-label", onClick: this.onLabelClick, part: "wrapper" }, hasOutlineFill && this.renderOutlineContainer(), h("div", { key: '73e13f28ed4c2b0e9115f3d1b86934b84f8c5bc0', class: "select-start", part: "start", ref: (el) => (this.startContainerEl = el) }, h("slot", { key: 'ce88e5bbb15a4cde6a5f8580a35d7099e315e9e6', name: "start" })), h("div", { key: 'd1557c3d0ff41f5070a27b719fbfaf18eafa9052', class: "select-control", part: "control" }, this.renderLabel(), h("div", { key: 'bcd03ac6c6d72ab76a4344069d83c29a2cdaabf0', class: "native-wrapper", ref: (el) => (this.nativeWrapperEl = el), part: "container" }, this.renderSelectText(), this.renderListbox(), !hasFloatingOrStackedLabel && this.renderSelectIcon())), h("div", { key: '9be05035c1efb5c332a0044c81e032215c81278b', class: "select-end", part: "end", ref: (el) => (this.endContainerEl = el) }, hasFloatingOrStackedLabel && this.renderSelectIcon(), h("slot", { key: '551ab0cf3594805caaf14f36197f9cc56b9ee46a', name: "end" })), shouldRenderHighlight && h("div", { key: 'dd500fb4ae7d91d1733fec521dac9baaef6654a0', class: "select-highlight" })), this.renderBottomContent()));
|
|
962
962
|
}
|
|
963
963
|
static get is() { return "ion-select"; }
|
|
964
964
|
static get encapsulation() { return "shadow"; }
|
|
@@ -390,7 +390,11 @@ button {
|
|
|
390
390
|
* would not be able to see what they are typing.
|
|
391
391
|
*/
|
|
392
392
|
max-width: 200px;
|
|
393
|
-
|
|
393
|
+
/**
|
|
394
|
+
* The max-width animates with the transform so the label does not
|
|
395
|
+
* reveal its full floating width while it is still at full size.
|
|
396
|
+
*/
|
|
397
|
+
transition: color 150ms cubic-bezier(0.4, 0, 0.2, 1), transform 150ms cubic-bezier(0.4, 0, 0.2, 1), max-width 150ms cubic-bezier(0.4, 0, 0.2, 1);
|
|
394
398
|
/**
|
|
395
399
|
* This ensures that double tapping this text
|
|
396
400
|
* clicks the <label> and focuses the input
|
|
@@ -404,8 +408,8 @@ button {
|
|
|
404
408
|
* disable the label transition to prevent the floating label
|
|
405
409
|
* from animating as its position is adjusted.
|
|
406
410
|
*
|
|
407
|
-
* This class is applied by the start container controller,
|
|
408
|
-
* renaming it here requires renaming it there too.
|
|
411
|
+
* This class is applied by the start and end container controller,
|
|
412
|
+
* so renaming it here requires renaming it there too.
|
|
409
413
|
*/
|
|
410
414
|
:host(.skip-label-transition) .label-text-wrapper {
|
|
411
415
|
transition: none;
|
|
@@ -981,12 +985,20 @@ button {
|
|
|
981
985
|
--padding-end: 16px;
|
|
982
986
|
/**
|
|
983
987
|
* The measured width of the start container, as a negative offset
|
|
984
|
-
* in LTR and a positive one in RTL. Written to the host by the
|
|
985
|
-
*
|
|
988
|
+
* in LTR and a positive one in RTL. Written to the host by the start
|
|
989
|
+
* and end container controller, so renaming it here requires renaming
|
|
986
990
|
* it there too. Declared with a default so the label is positioned
|
|
987
991
|
* correctly before the first measurement runs.
|
|
988
992
|
*/
|
|
989
993
|
--internal-start-container-adjustment: 0px;
|
|
994
|
+
/**
|
|
995
|
+
* The measured combined width of the start and end containers.
|
|
996
|
+
* Written to the host by the start and end container controller, so
|
|
997
|
+
* renaming it here requires renaming it there too. Declared with a
|
|
998
|
+
* default so the floating label falls back to the width of the
|
|
999
|
+
* control before the first measurement runs.
|
|
1000
|
+
*/
|
|
1001
|
+
--internal-start-end-container-width: 0px;
|
|
990
1002
|
min-height: 56px;
|
|
991
1003
|
}
|
|
992
1004
|
|
|
@@ -1056,9 +1068,8 @@ button {
|
|
|
1056
1068
|
:host(.select-fill-outline.select-label-placement-floating) .label-text-wrapper {
|
|
1057
1069
|
position: absolute;
|
|
1058
1070
|
/**
|
|
1059
|
-
*
|
|
1060
|
-
* excludes the start and end slots.
|
|
1061
|
-
* containing block becomes the wrapper and the rule below takes over.
|
|
1071
|
+
* This is the width of the select, which already
|
|
1072
|
+
* excludes the start and end slots.
|
|
1062
1073
|
*/
|
|
1063
1074
|
max-width: 100%;
|
|
1064
1075
|
}
|
|
@@ -1074,11 +1085,12 @@ button {
|
|
|
1074
1085
|
}
|
|
1075
1086
|
|
|
1076
1087
|
/**
|
|
1077
|
-
* The
|
|
1078
|
-
* the
|
|
1079
|
-
*
|
|
1088
|
+
* The label is positioned relative to the control whether it is resting
|
|
1089
|
+
* over the select or floating in the notch, so its max-width always resolves
|
|
1090
|
+
* against the same width. This lets the max-width animate between the
|
|
1091
|
+
* resting and floating values without jumping.
|
|
1080
1092
|
*/
|
|
1081
|
-
:host(.select-fill-outline
|
|
1093
|
+
:host(.select-fill-outline) .select-control {
|
|
1082
1094
|
position: relative;
|
|
1083
1095
|
}
|
|
1084
1096
|
|
|
@@ -1092,10 +1104,11 @@ button {
|
|
|
1092
1104
|
margin-top: 0;
|
|
1093
1105
|
margin-bottom: 0;
|
|
1094
1106
|
/**
|
|
1095
|
-
* Label text should not extend
|
|
1096
|
-
*
|
|
1107
|
+
* Label text should not extend beyond the bounds of the select.
|
|
1108
|
+
* The control excludes the start and end slots, but the notch spans
|
|
1109
|
+
* the full width of the outline, so their width is added back.
|
|
1097
1110
|
*/
|
|
1098
|
-
max-width: calc((100%
|
|
1111
|
+
max-width: calc((100% + var(--internal-start-end-container-width) - 8px) / 0.75);
|
|
1099
1112
|
}
|
|
1100
1113
|
|
|
1101
1114
|
/**
|
|
@@ -453,7 +453,11 @@
|
|
|
453
453
|
* would not be able to see what they are typing.
|
|
454
454
|
*/
|
|
455
455
|
max-width: 200px;
|
|
456
|
-
|
|
456
|
+
/**
|
|
457
|
+
* The max-width animates with the transform so the label does not
|
|
458
|
+
* reveal its full floating width while it is still at full size.
|
|
459
|
+
*/
|
|
460
|
+
transition: color 150ms cubic-bezier(0.4, 0, 0.2, 1), transform 150ms cubic-bezier(0.4, 0, 0.2, 1), max-width 150ms cubic-bezier(0.4, 0, 0.2, 1);
|
|
457
461
|
/**
|
|
458
462
|
* This ensures that double tapping this text
|
|
459
463
|
* clicks the <label> and focuses the textarea
|
|
@@ -467,8 +471,8 @@
|
|
|
467
471
|
* disable the label transition to prevent the floating label
|
|
468
472
|
* from animating as its position is adjusted.
|
|
469
473
|
*
|
|
470
|
-
* This class is applied by the start container controller,
|
|
471
|
-
* renaming it here requires renaming it there too.
|
|
474
|
+
* This class is applied by the start and end container controller,
|
|
475
|
+
* so renaming it here requires renaming it there too.
|
|
472
476
|
*/
|
|
473
477
|
:host(.skip-label-transition) .label-text-wrapper {
|
|
474
478
|
transition: none;
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* (C) Ionic http://ionicframework.com - MIT License
|
|
3
3
|
*/
|
|
4
4
|
import { Build, Host, forceUpdate, h, writeTask, } from "@stencil/core";
|
|
5
|
-
import { createClickController, createNotchController,
|
|
5
|
+
import { createClickController, createNotchController, createStartEndContainerController, checkInvalidState, } from "../../utils/forms/index";
|
|
6
6
|
import { inheritAriaAttributes, debounceEvent, inheritAttributes, componentOnReady } from "../../utils/helpers";
|
|
7
7
|
import { createSlotMutationController } from "../../utils/slot-mutation-controller";
|
|
8
8
|
import { createColorClasses, hostContext } from "../../utils/theme";
|
|
@@ -194,14 +194,14 @@ export class Textarea {
|
|
|
194
194
|
connectedCallback() {
|
|
195
195
|
const { el } = this;
|
|
196
196
|
this.slotMutationController = createSlotMutationController(el, ['label', 'start', 'end'], () => {
|
|
197
|
-
this.
|
|
197
|
+
this.startEndContainerController?.calculateContainerWidths();
|
|
198
198
|
forceUpdate(this);
|
|
199
199
|
});
|
|
200
200
|
this.notchController = createNotchController(el, () => this.notchSpacerEl, () => this.labelSlot);
|
|
201
|
-
this.
|
|
201
|
+
this.startEndContainerController = createStartEndContainerController(el, () => this.startContainerEl, () => this.endContainerEl, () => {
|
|
202
202
|
return Build.isBrowser && getIonMode(this) === 'md' && this.fill === 'outline';
|
|
203
203
|
});
|
|
204
|
-
this.
|
|
204
|
+
this.startEndContainerController.calculateContainerWidths();
|
|
205
205
|
this.clickController = createClickController(el, () => this.nativeInput);
|
|
206
206
|
// Watch for class changes to update validation state
|
|
207
207
|
if (Build.isBrowser && typeof MutationObserver !== 'undefined') {
|
|
@@ -241,9 +241,9 @@ export class Textarea {
|
|
|
241
241
|
this.notchController.destroy();
|
|
242
242
|
this.notchController = undefined;
|
|
243
243
|
}
|
|
244
|
-
if (this.
|
|
245
|
-
this.
|
|
246
|
-
this.
|
|
244
|
+
if (this.startEndContainerController) {
|
|
245
|
+
this.startEndContainerController.destroy();
|
|
246
|
+
this.startEndContainerController = undefined;
|
|
247
247
|
}
|
|
248
248
|
// Clean up validation observer to prevent memory leaks
|
|
249
249
|
if (this.validationObserver) {
|
|
@@ -263,7 +263,7 @@ export class Textarea {
|
|
|
263
263
|
}
|
|
264
264
|
componentDidRender() {
|
|
265
265
|
this.notchController?.calculateNotchWidth();
|
|
266
|
-
this.
|
|
266
|
+
this.startEndContainerController?.calculateContainerWidths();
|
|
267
267
|
}
|
|
268
268
|
/**
|
|
269
269
|
* Sets focus on the native `textarea` in `ion-textarea`. Use this method instead of the global
|
|
@@ -458,7 +458,7 @@ export class Textarea {
|
|
|
458
458
|
* the textarea has a value or is focused.
|
|
459
459
|
*/
|
|
460
460
|
const labelShouldFloat = labelPlacement === 'stacked' || (labelPlacement === 'floating' && (hasValue || hasFocus));
|
|
461
|
-
return (h(Host, { key: '
|
|
461
|
+
return (h(Host, { key: '59f577d7b82036d5e12d7b4e7d5f0339af1d185a', class: createColorClasses(this.color, {
|
|
462
462
|
[mode]: true,
|
|
463
463
|
'has-value': hasValue,
|
|
464
464
|
'has-focus': hasFocus,
|
|
@@ -467,7 +467,7 @@ export class Textarea {
|
|
|
467
467
|
[`textarea-shape-${shape}`]: shape !== undefined,
|
|
468
468
|
[`textarea-label-placement-${labelPlacement}`]: true,
|
|
469
469
|
'textarea-disabled': disabled,
|
|
470
|
-
}) }, h("label", { key: '
|
|
470
|
+
}) }, h("label", { key: '4684c4e760f0272d377809fcb28ed6fcad48b542', class: "textarea-wrapper", htmlFor: inputId, onClick: this.onLabelClick }, hasOutlineFill && this.renderOutlineContainer(), h("div", { key: 'a3dd0e7b9494fce1ee33d011138600e8b697b227', class: "textarea-start", ref: (el) => (this.startContainerEl = el) }, h("slot", { key: '8f0a36f2373c859039b1437a0fdf8e7bef278272', name: "start" })), h("div", { key: '2cb3def25a6447aefb656e5fd89716be280055f1', class: "textarea-control" }, this.renderLabel(), h("div", { key: '613caadf5331ff4d9b52e1d2b22a7da36b248e76', class: "native-wrapper", ref: (el) => (this.textareaWrapper = el) }, h("textarea", { key: '3015a96367fa845f068118c5ae2484c4c8f30931', class: "native-textarea", ref: (el) => (this.nativeInput = el), id: inputId, disabled: disabled, autoCapitalize: this.autocapitalize, autoFocus: this.autofocus, enterKeyHint: this.enterkeyhint, inputMode: this.inputmode, minLength: this.minlength, maxLength: this.maxlength, name: this.name, placeholder: this.placeholder || '', readOnly: this.readonly, required: this.required, spellcheck: this.spellcheck, cols: this.cols, rows: this.rows, wrap: this.wrap, onInput: this.onInput, onChange: this.onChange, onBlur: this.onBlur, onFocus: this.onFocus, onKeyDown: this.onKeyDown, "aria-describedby": this.getHintTextID(), "aria-invalid": this.isInvalid ? 'true' : undefined, ...this.inheritedAttributes }, value))), h("div", { key: 'f97f361e9339125407b0ef5f53d8c55021f1f824', class: "textarea-end", ref: (el) => (this.endContainerEl = el) }, h("slot", { key: '032bd68ec3603f8cf598225714e02447712a283a', name: "end" })), shouldRenderHighlight && h("div", { key: '8e27cee63918d2f40a46c442a3bb2802be4cf3e4', class: "textarea-highlight" })), this.renderBottomContent()));
|
|
471
471
|
}
|
|
472
472
|
static get is() { return "ion-textarea"; }
|
|
473
473
|
static get encapsulation() { return "scoped"; }
|