Compare commits
27 Commits
ionic-modu
...
sp/FW-5743
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3de3da6a09 | ||
|
|
1b34c6283c | ||
|
|
8d2624d3a3 | ||
|
|
120cca5205 | ||
|
|
a92b6333d4 | ||
|
|
7623bc5aad | ||
|
|
79f188fdb7 | ||
|
|
fe54a649e4 | ||
|
|
adb1ce4dc4 | ||
|
|
3129b9ad77 | ||
|
|
7e2ccaaaf1 | ||
|
|
b10a3824c8 | ||
|
|
8a924f33cd | ||
|
|
26567e1661 | ||
|
|
300ad60a84 | ||
|
|
cd03fb242f | ||
|
|
1f2bb2f0bc | ||
|
|
298951b921 | ||
|
|
561998ecea | ||
|
|
4aa7d47dce | ||
|
|
b0aa270722 | ||
|
|
260ffdcc91 | ||
|
|
7f8a06d41c | ||
|
|
f9e719b3e7 | ||
|
|
8374d693ca | ||
|
|
d62ff1c50f | ||
|
|
815d9226ed |
@@ -702,6 +702,7 @@ ion-item-options,prop,side,"end" | "start",'end',false,false
|
||||
ion-item-options,event,ionSwipe,any,true
|
||||
|
||||
ion-item-sliding,none
|
||||
ion-item-sliding,prop,animationType,"legacy" | "modern",SlidingAnimation.Legacy,false,false
|
||||
ion-item-sliding,prop,disabled,boolean,false,false,false
|
||||
ion-item-sliding,method,close,close() => Promise<void>
|
||||
ion-item-sliding,method,closeOpened,closeOpened() => Promise<boolean>
|
||||
|
||||
10
core/src/components.d.ts
vendored
@@ -20,6 +20,7 @@ import { SpinnerTypes } from "./components/spinner/spinner-configs";
|
||||
import { InputChangeEventDetail, InputInputEventDetail } from "./components/input/input-interface";
|
||||
import { CounterFormatter } from "./components/item/item-interface";
|
||||
import { MenuChangeEventDetail, Side } from "./components/menu/menu-interface";
|
||||
import { SlidingAnimationType } from "./components/item-sliding/item-sliding-interface";
|
||||
import { ModalBreakpointChangeEventDetail, ModalHandleBehavior } from "./components/modal/modal-interface";
|
||||
import { NavComponent, NavComponentWithProps, NavOptions, RouterOutletOptions, SwipeGestureHandler, TransitionDoneFn, TransitionInstruction } from "./components/nav/nav-interface";
|
||||
import { ViewController } from "./components/nav/view-controller";
|
||||
@@ -56,6 +57,7 @@ export { SpinnerTypes } from "./components/spinner/spinner-configs";
|
||||
export { InputChangeEventDetail, InputInputEventDetail } from "./components/input/input-interface";
|
||||
export { CounterFormatter } from "./components/item/item-interface";
|
||||
export { MenuChangeEventDetail, Side } from "./components/menu/menu-interface";
|
||||
export { SlidingAnimationType } from "./components/item-sliding/item-sliding-interface";
|
||||
export { ModalBreakpointChangeEventDetail, ModalHandleBehavior } from "./components/modal/modal-interface";
|
||||
export { NavComponent, NavComponentWithProps, NavOptions, RouterOutletOptions, SwipeGestureHandler, TransitionDoneFn, TransitionInstruction } from "./components/nav/nav-interface";
|
||||
export { ViewController } from "./components/nav/view-controller";
|
||||
@@ -1438,6 +1440,10 @@ export namespace Components {
|
||||
"side": Side;
|
||||
}
|
||||
interface IonItemSliding {
|
||||
/**
|
||||
* Specifies the animation behavior for sliding item options. You can choose between two available options: "modern" and "legacy". - "legacy": The item will be swiped to reveal the option buttons beneath it. - "modern": As the item is swiped, all item options will smoothly and gradually reveal themselves.
|
||||
*/
|
||||
"animationType": SlidingAnimationType;
|
||||
/**
|
||||
* Close the sliding item. Items can also be closed from the [List](./list).
|
||||
*/
|
||||
@@ -6189,6 +6195,10 @@ declare namespace LocalJSX {
|
||||
"side"?: Side;
|
||||
}
|
||||
interface IonItemSliding {
|
||||
/**
|
||||
* Specifies the animation behavior for sliding item options. You can choose between two available options: "modern" and "legacy". - "legacy": The item will be swiped to reveal the option buttons beneath it. - "modern": As the item is swiped, all item options will smoothly and gradually reveal themselves.
|
||||
*/
|
||||
"animationType"?: SlidingAnimationType;
|
||||
/**
|
||||
* If `true`, the user cannot interact with the sliding item.
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
import { createAnimation } from '@utils/animation/animation';
|
||||
|
||||
/**
|
||||
* Animates the opening and closing of a sliding item option.
|
||||
* @param el The element to animate.
|
||||
* @param viewportOffset The offset of the element on the x-axis to locate it off-screen.
|
||||
* @param progress The progress of the animation. Accepted values are between 0 and 1. Represents the progress from the starting transform to the final transform.
|
||||
* @param isFinal Whether the animation is in its final state (collapsed or expanded).
|
||||
* @param isReset Whether to reset the element to its initial state.
|
||||
* @param zIndex _Optional_ The z-index to apply to the element.
|
||||
*/
|
||||
export const slidingItemAnimation = (
|
||||
el: HTMLIonItemOptionElement,
|
||||
viewportOffset: number,
|
||||
progress: number,
|
||||
isFinal: boolean,
|
||||
isReset: boolean,
|
||||
zIndex: number | undefined
|
||||
) => {
|
||||
const styles = zIndex !== undefined ? { zIndex: `${zIndex}` } : {};
|
||||
|
||||
const swipeAnimation = createAnimation()
|
||||
.addElement(el)
|
||||
/**
|
||||
* The specific value here does not actually
|
||||
* matter. We just need this to be a positive
|
||||
* value so the animation does not jump
|
||||
* to the end when the user begins to drag.
|
||||
*/
|
||||
.duration(1)
|
||||
.commitStyles()
|
||||
.keyframes([
|
||||
{ offset: 0, transform: `translate3d(${viewportOffset}px,0,0)`, ...styles },
|
||||
{ offset: 1, transform: `translate3d(0,0,0)`, ...styles },
|
||||
]);
|
||||
|
||||
if (isReset) {
|
||||
swipeAnimation.destroy();
|
||||
|
||||
const leaveAnimation = createAnimation()
|
||||
.addElement(el)
|
||||
.duration(300)
|
||||
.easing('ease-out')
|
||||
.beforeStyles({
|
||||
zIndex: zIndex,
|
||||
})
|
||||
.fromTo('transform', el.style.transform, `translate3d(${viewportOffset}px,0,0)`)
|
||||
.afterClearStyles(['z-index', 'transform']);
|
||||
|
||||
leaveAnimation.play().then(() => leaveAnimation.destroy());
|
||||
}
|
||||
|
||||
if (!isFinal) {
|
||||
swipeAnimation.progressStart(true, progress);
|
||||
} else {
|
||||
swipeAnimation.destroy();
|
||||
|
||||
const expandAnimation = createAnimation()
|
||||
.addElement(el)
|
||||
.duration(300)
|
||||
.easing('ease-out')
|
||||
.beforeStyles({
|
||||
zIndex: zIndex,
|
||||
})
|
||||
.fromTo('transform', el.style.transform, `translate3d(0,0,0)`)
|
||||
.afterClearStyles(['z-index', 'transform']);
|
||||
|
||||
expandAnimation.play();
|
||||
}
|
||||
};
|
||||
@@ -1,3 +1,5 @@
|
||||
export interface ItemSlidingCustomEvent extends CustomEvent {
|
||||
target: HTMLIonItemSlidingElement;
|
||||
}
|
||||
|
||||
export type SlidingAnimationType = 'modern' | 'legacy';
|
||||
|
||||
@@ -34,11 +34,6 @@ ion-item-sliding .item {
|
||||
}
|
||||
|
||||
.item-sliding-active-swipe-end .item-options-end .item-option-expandable {
|
||||
@include multi-dir() {
|
||||
/* stylelint-disable-next-line property-disallowed-list */
|
||||
padding-left: 100%;
|
||||
}
|
||||
|
||||
@include ltr() {
|
||||
order: 1;
|
||||
}
|
||||
@@ -46,9 +41,24 @@ ion-item-sliding .item {
|
||||
@include rtl() {
|
||||
order: -1;
|
||||
}
|
||||
}
|
||||
|
||||
transition-duration: .6s;
|
||||
transition-property: padding-left;
|
||||
// Item Sliding: Animation Legacy
|
||||
// --------------------------------------------------
|
||||
|
||||
.item-sliding-animation-legacy,
|
||||
// TODO: FW-5907 - Add support for modern animation with Ionic animations
|
||||
.item-sliding-animation-modern {
|
||||
// Animation to expand the item option
|
||||
&.item-sliding-active-swipe-end .item-options-end .item-option-expandable {
|
||||
@include multi-dir() {
|
||||
/* stylelint-disable-next-line property-disallowed-list */
|
||||
padding-left: 100%;
|
||||
}
|
||||
|
||||
transition-duration: .6s;
|
||||
transition-property: padding-left;
|
||||
}
|
||||
}
|
||||
|
||||
.item-sliding-active-swipe-start .item-options-start .item-option-expandable {
|
||||
|
||||
@@ -2,12 +2,16 @@ import type { ComponentInterface, EventEmitter } from '@stencil/core';
|
||||
import { Component, Element, Event, Host, Method, Prop, State, Watch, h } from '@stencil/core';
|
||||
import { findClosestIonContent, disableContentScrollY, resetContentScrollY } from '@utils/content';
|
||||
import { isEndSide } from '@utils/helpers';
|
||||
import { isRTL } from '@utils/rtl';
|
||||
import { watchForOptions } from '@utils/watch-options';
|
||||
|
||||
import { getIonMode } from '../../global/ionic-global';
|
||||
import type { Gesture, GestureDetail } from '../../interface';
|
||||
import { type Gesture, type GestureDetail } from '../../interface';
|
||||
import type { Side } from '../menu/menu-interface';
|
||||
|
||||
import { slidingItemAnimation } from './animations/item-sliding-options';
|
||||
import type { SlidingAnimationType } from './item-sliding-interface';
|
||||
|
||||
const SWIPE_MARGIN = 30;
|
||||
const ELASTIC_FACTOR = 0.55;
|
||||
|
||||
@@ -28,6 +32,11 @@ const enum SlidingState {
|
||||
SwipeStart = 1 << 6,
|
||||
}
|
||||
|
||||
const SlidingAnimation: { [key in string]: SlidingAnimationType } = {
|
||||
Modern: 'modern',
|
||||
Legacy: 'legacy',
|
||||
};
|
||||
|
||||
let openSlidingItem: HTMLIonItemSlidingElement | undefined;
|
||||
|
||||
@Component({
|
||||
@@ -65,6 +74,16 @@ export class ItemSliding implements ComponentInterface {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies the animation behavior for sliding item options.
|
||||
* You can choose between two available options: "modern" and "legacy".
|
||||
*
|
||||
* - "legacy": The item will be swiped to reveal the option buttons beneath it.
|
||||
* - "modern": As the item is swiped, all item options will smoothly and gradually reveal themselves.
|
||||
*
|
||||
*/
|
||||
@Prop() animationType: SlidingAnimationType = SlidingAnimation.Legacy;
|
||||
|
||||
/**
|
||||
* Emitted when the sliding position changes.
|
||||
*/
|
||||
@@ -243,6 +262,20 @@ export class ItemSliding implements ComponentInterface {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a side, return the width of the options on that side.
|
||||
*
|
||||
* @param side The side of the options to get the width for.
|
||||
*/
|
||||
private getOptionsWidth(side: 'start' | 'end'): number {
|
||||
if (side === 'start') {
|
||||
return this.optsWidthLeftSide;
|
||||
} else if (side === 'end') {
|
||||
return this.optsWidthRightSide;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
private async updateOptions() {
|
||||
const options = this.el.querySelectorAll('ion-item-options');
|
||||
|
||||
@@ -379,6 +412,7 @@ export class ItemSliding implements ComponentInterface {
|
||||
}
|
||||
|
||||
const state = this.state;
|
||||
|
||||
this.setOpenAmount(restingPoint, true);
|
||||
|
||||
if ((state & SlidingState.SwipeEnd) !== 0 && this.rightOptions) {
|
||||
@@ -415,7 +449,9 @@ export class ItemSliding implements ComponentInterface {
|
||||
return;
|
||||
}
|
||||
|
||||
const { el } = this;
|
||||
const { el, animationType } = this;
|
||||
|
||||
const rtl = isRTL(el);
|
||||
|
||||
const style = this.item.style;
|
||||
this.openAmount = openAmount;
|
||||
@@ -462,15 +498,62 @@ export class ItemSliding implements ComponentInterface {
|
||||
|
||||
openSlidingItem = undefined;
|
||||
style.transform = '';
|
||||
|
||||
if (animationType === SlidingAnimation.Modern) {
|
||||
this.animateSlidingItemOptions(0, rtl);
|
||||
}
|
||||
return;
|
||||
}
|
||||
style.transform = `translate3d(${-openAmount}px,0,0)`;
|
||||
|
||||
if (animationType === SlidingAnimation.Modern) {
|
||||
this.animateSlidingItemOptions(openAmount, rtl);
|
||||
}
|
||||
|
||||
this.ionDrag.emit({
|
||||
amount: openAmount,
|
||||
ratio: this.getSlidingRatioSync(),
|
||||
});
|
||||
}
|
||||
|
||||
private animateSlidingItemOptions(openAmount: number, isRTL: boolean) {
|
||||
/**
|
||||
* The total width of the 'processed' options.
|
||||
* Used to calculate the offset to move each option off the
|
||||
* screen, on top of each other.
|
||||
*/
|
||||
let optionWidthOffset = 0;
|
||||
|
||||
const side = this.state === SlidingState.Start ? 'start' : 'end';
|
||||
|
||||
const options = Array.from(this.getOptions(side)?.querySelectorAll('ion-item-option') || []);
|
||||
const optsWidth = this.getOptionsWidth(side);
|
||||
|
||||
const progress = Math.abs(openAmount / optsWidth);
|
||||
|
||||
options.forEach((option, index) => {
|
||||
let isFinal = false;
|
||||
let zIndex: number | undefined;
|
||||
let viewportOffset = 0;
|
||||
|
||||
const isReset = openAmount === 0;
|
||||
|
||||
if (side === 'start') {
|
||||
viewportOffset = isRTL ? -1 * (optsWidth - optionWidthOffset) : -1 * (option.clientWidth + optionWidthOffset);
|
||||
isFinal = openAmount <= -optsWidth;
|
||||
zIndex = isRTL ? undefined : options.length - index;
|
||||
} else {
|
||||
viewportOffset = isRTL ? optionWidthOffset + option.clientWidth : optsWidth - optionWidthOffset;
|
||||
isFinal = openAmount >= optsWidth;
|
||||
zIndex = isRTL ? options.length - index : undefined;
|
||||
}
|
||||
|
||||
slidingItemAnimation(option, viewportOffset, progress, isFinal, isReset, zIndex);
|
||||
|
||||
optionWidthOffset += option.clientWidth;
|
||||
});
|
||||
}
|
||||
|
||||
private getSlidingRatioSync(): number {
|
||||
if (this.openAmount > 0) {
|
||||
return this.openAmount / this.optsWidthRightSide;
|
||||
@@ -483,15 +566,17 @@ export class ItemSliding implements ComponentInterface {
|
||||
|
||||
render() {
|
||||
const mode = getIonMode(this);
|
||||
const { state, animationType } = this;
|
||||
return (
|
||||
<Host
|
||||
class={{
|
||||
[mode]: true,
|
||||
'item-sliding-active-slide': this.state !== SlidingState.Disabled,
|
||||
'item-sliding-active-options-end': (this.state & SlidingState.End) !== 0,
|
||||
'item-sliding-active-options-start': (this.state & SlidingState.Start) !== 0,
|
||||
'item-sliding-active-swipe-end': (this.state & SlidingState.SwipeEnd) !== 0,
|
||||
'item-sliding-active-swipe-start': (this.state & SlidingState.SwipeStart) !== 0,
|
||||
[`item-sliding-animation-${animationType}`]: true,
|
||||
'item-sliding-active-slide': state !== SlidingState.Disabled,
|
||||
'item-sliding-active-options-end': (state & SlidingState.End) !== 0,
|
||||
'item-sliding-active-options-start': (state & SlidingState.Start) !== 0,
|
||||
'item-sliding-active-swipe-end': (state & SlidingState.SwipeEnd) !== 0,
|
||||
'item-sliding-active-swipe-start': (state & SlidingState.SwipeStart) !== 0,
|
||||
}}
|
||||
></Host>
|
||||
);
|
||||
|
||||
@@ -30,6 +30,9 @@
|
||||
<ion-button expand="block" id="openItemOneSide" onclick="openItemOneSide()"
|
||||
>Open Item with only one side</ion-button
|
||||
>
|
||||
<ion-button expand="block" id="useModernAnimation" onclick="useModernAnimation()"
|
||||
>Use modern animation</ion-button
|
||||
>
|
||||
</div>
|
||||
|
||||
<ion-list id="list">
|
||||
@@ -187,6 +190,13 @@
|
||||
itemEle.close();
|
||||
}
|
||||
}
|
||||
|
||||
function useModernAnimation() {
|
||||
const slidingItems = document.querySelectorAll('ion-item-sliding');
|
||||
slidingItems.forEach((slidingItem) => {
|
||||
slidingItem.animationType = 'modern';
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</ion-content>
|
||||
</ion-app>
|
||||
|
||||
@@ -13,40 +13,88 @@ configs().forEach(({ title, screenshot, config }) => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto(`/src/components/item-sliding/test/basic`, config);
|
||||
});
|
||||
test.describe('start options', () => {
|
||||
test('should not have visual regressions', async ({ page }) => {
|
||||
const item = page.locator('#item2');
|
||||
|
||||
/**
|
||||
* Negative dragByX value to drag element from the right to the left
|
||||
* to reveal the options on the right side.
|
||||
* Positive dragByX value to drag element from the left to the right
|
||||
* to reveal the options on the left side.
|
||||
*/
|
||||
const dragByX = config.direction === 'rtl' ? -150 : 150;
|
||||
test.describe('legacy animation', () => {
|
||||
test.describe('start options', () => {
|
||||
test('should not have visual regressions', async ({ page }) => {
|
||||
const item = page.locator('#item2');
|
||||
|
||||
await dragElementBy(item, page, dragByX);
|
||||
await page.waitForChanges();
|
||||
/**
|
||||
* Negative dragByX value to drag element from the right to the left
|
||||
* to reveal the options on the right side.
|
||||
* Positive dragByX value to drag element from the left to the right
|
||||
* to reveal the options on the left side.
|
||||
*/
|
||||
const dragByX = config.direction === 'rtl' ? -150 : 150;
|
||||
|
||||
await expect(item).toHaveScreenshot(screenshot('item-sliding-start'));
|
||||
await dragElementBy(item, page, dragByX);
|
||||
await page.waitForChanges();
|
||||
|
||||
await expect(item).toHaveScreenshot(screenshot('item-sliding-start'));
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('end options', () => {
|
||||
test('should not have visual regressions', async ({ page }) => {
|
||||
const item = page.locator('#item2');
|
||||
|
||||
/**
|
||||
* Negative dragByX value to drag element from the right to the left
|
||||
* to reveal the options on the right side.
|
||||
* Positive dragByX value to drag element from the left to the right
|
||||
* to reveal the options on the left side.
|
||||
*/
|
||||
const dragByX = config.direction === 'rtl' ? 150 : -150;
|
||||
|
||||
await dragElementBy(item, page, dragByX);
|
||||
|
||||
await expect(item).toHaveScreenshot(screenshot('item-sliding-end'));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('end options', () => {
|
||||
test('should not have visual regressions', async ({ page }) => {
|
||||
const item = page.locator('#item2');
|
||||
test.describe('modern animation', () => {
|
||||
test.describe('start options', () => {
|
||||
test('should not have visual regressions', async ({ page }) => {
|
||||
const useModernAnimationBtn = page.locator('#useModernAnimation');
|
||||
await useModernAnimationBtn.click();
|
||||
|
||||
/**
|
||||
* Negative dragByX value to drag element from the right to the left
|
||||
* to reveal the options on the right side.
|
||||
* Positive dragByX value to drag element from the left to the right
|
||||
* to reveal the options on the left side.
|
||||
*/
|
||||
const dragByX = config.direction === 'rtl' ? 150 : -150;
|
||||
const item = page.locator('#item2');
|
||||
|
||||
await dragElementBy(item, page, dragByX);
|
||||
/**
|
||||
* Negative dragByX value to drag element from the right to the left
|
||||
* to reveal the options on the right side.
|
||||
* Positive dragByX value to drag element from the left to the right
|
||||
* to reveal the options on the left side.
|
||||
*/
|
||||
const dragByX = config.direction === 'rtl' ? -150 : 150;
|
||||
|
||||
await expect(item).toHaveScreenshot(screenshot('item-sliding-end'));
|
||||
await dragElementBy(item, page, dragByX);
|
||||
await page.waitForChanges();
|
||||
|
||||
await expect(item).toHaveScreenshot(screenshot('modern-item-sliding-start'));
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('end options', () => {
|
||||
test('should not have visual regressions', async ({ page }) => {
|
||||
const useModernAnimationBtn = page.locator('#useModernAnimation');
|
||||
await useModernAnimationBtn.click();
|
||||
|
||||
const item = page.locator('#item2');
|
||||
|
||||
/**
|
||||
* Negative dragByX value to drag element from the right to the left
|
||||
* to reveal the options on the right side.
|
||||
* Positive dragByX value to drag element from the left to the right
|
||||
* to reveal the options on the left side.
|
||||
*/
|
||||
const dragByX = config.direction === 'rtl' ? 150 : -150;
|
||||
|
||||
await dragElementBy(item, page, dragByX);
|
||||
|
||||
await expect(item).toHaveScreenshot(screenshot('modern-item-sliding-end'));
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
Before Width: | Height: | Size: 5.0 KiB After Width: | Height: | Size: 5.0 KiB |
|
Before Width: | Height: | Size: 6.3 KiB After Width: | Height: | Size: 6.3 KiB |
|
Before Width: | Height: | Size: 4.7 KiB After Width: | Height: | Size: 4.6 KiB |
|
Before Width: | Height: | Size: 5.0 KiB After Width: | Height: | Size: 5.0 KiB |
|
Before Width: | Height: | Size: 6.2 KiB After Width: | Height: | Size: 6.2 KiB |
|
Before Width: | Height: | Size: 4.6 KiB After Width: | Height: | Size: 4.5 KiB |
|
Before Width: | Height: | Size: 6.8 KiB After Width: | Height: | Size: 6.8 KiB |
|
Before Width: | Height: | Size: 7.9 KiB After Width: | Height: | Size: 8.0 KiB |
|
Before Width: | Height: | Size: 6.4 KiB After Width: | Height: | Size: 6.3 KiB |
|
Before Width: | Height: | Size: 7.0 KiB After Width: | Height: | Size: 7.0 KiB |
|
Before Width: | Height: | Size: 8.1 KiB After Width: | Height: | Size: 8.2 KiB |
|
Before Width: | Height: | Size: 6.5 KiB After Width: | Height: | Size: 6.5 KiB |
|
After Width: | Height: | Size: 5.0 KiB |
|
After Width: | Height: | Size: 6.4 KiB |
|
After Width: | Height: | Size: 4.7 KiB |
|
After Width: | Height: | Size: 5.0 KiB |
|
After Width: | Height: | Size: 6.2 KiB |
|
After Width: | Height: | Size: 4.6 KiB |
|
After Width: | Height: | Size: 4.7 KiB |
|
After Width: | Height: | Size: 5.9 KiB |
|
After Width: | Height: | Size: 4.3 KiB |
|
After Width: | Height: | Size: 4.4 KiB |
|
After Width: | Height: | Size: 5.5 KiB |
|
After Width: | Height: | Size: 4.1 KiB |
|
After Width: | Height: | Size: 6.8 KiB |
|
After Width: | Height: | Size: 7.9 KiB |
|
After Width: | Height: | Size: 6.3 KiB |
|
After Width: | Height: | Size: 7.0 KiB |
|
After Width: | Height: | Size: 8.2 KiB |
|
After Width: | Height: | Size: 6.5 KiB |
|
After Width: | Height: | Size: 6.4 KiB |
|
After Width: | Height: | Size: 7.5 KiB |
|
After Width: | Height: | Size: 5.7 KiB |
|
After Width: | Height: | Size: 6.6 KiB |
|
After Width: | Height: | Size: 7.6 KiB |
|
After Width: | Height: | Size: 5.9 KiB |
@@ -238,6 +238,14 @@ export interface Animation {
|
||||
* @internal
|
||||
*/
|
||||
animationFinish(): void;
|
||||
|
||||
/**
|
||||
* Writes the computed values of the animation's current styles
|
||||
* into its target element's style attribute.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
commitStyles(): Animation;
|
||||
}
|
||||
|
||||
export type AnimationLifecycle = (currentStep: 0 | 1, animation: Animation) => void;
|
||||
|
||||
@@ -49,6 +49,7 @@ export const createAnimation = (animationId?: string): Animation => {
|
||||
let beforeAddClasses: string[] = [];
|
||||
let beforeRemoveClasses: string[] = [];
|
||||
let initialized = false;
|
||||
let _commitStyles = false;
|
||||
let parentAnimation: Animation | undefined;
|
||||
let beforeStylesValue: { [property: string]: any } = {};
|
||||
let afterAddClasses: string[] = [];
|
||||
@@ -435,6 +436,14 @@ export const createAnimation = (animationId?: string): Animation => {
|
||||
return ani;
|
||||
};
|
||||
|
||||
const commitStyles = () => {
|
||||
_commitStyles = true;
|
||||
|
||||
update(true);
|
||||
|
||||
return ani;
|
||||
};
|
||||
|
||||
const duration = (animationDuration: number) => {
|
||||
/**
|
||||
* CSS Animation Durations of 0ms work fine on Chrome
|
||||
@@ -688,6 +697,10 @@ export const createAnimation = (animationId?: string): Animation => {
|
||||
direction: getDirection(),
|
||||
});
|
||||
|
||||
if (_commitStyles) {
|
||||
animation.commitStyles();
|
||||
}
|
||||
|
||||
animation.pause();
|
||||
|
||||
webAnimations.push(animation);
|
||||
@@ -721,6 +734,10 @@ export const createAnimation = (animationId?: string): Animation => {
|
||||
// When creating the animation the delay is guaranteed to be set to a number.
|
||||
animation.currentTime = animation.effect!.getComputedTiming().delay! + getDuration() * step;
|
||||
animation.pause();
|
||||
|
||||
if (_commitStyles) {
|
||||
animation.commitStyles();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
const animationDuration = `-${getDuration() * step}ms`;
|
||||
@@ -744,6 +761,10 @@ export const createAnimation = (animationId?: string): Animation => {
|
||||
fill: getFill(),
|
||||
direction: getDirection(),
|
||||
});
|
||||
|
||||
if (_commitStyles) {
|
||||
animation.commitStyles();
|
||||
}
|
||||
});
|
||||
|
||||
if (step !== undefined) {
|
||||
@@ -1117,6 +1138,7 @@ export const createAnimation = (animationId?: string): Animation => {
|
||||
addAnimation,
|
||||
addElement,
|
||||
update,
|
||||
commitStyles,
|
||||
fill,
|
||||
direction,
|
||||
iterations,
|
||||
|
||||
@@ -1130,7 +1130,7 @@ export declare interface IonItemOptions extends Components.IonItemOptions {
|
||||
|
||||
|
||||
@ProxyCmp({
|
||||
inputs: ['disabled'],
|
||||
inputs: ['animationType', 'disabled'],
|
||||
methods: ['getOpenAmount', 'getSlidingRatio', 'open', 'close', 'closeOpened']
|
||||
})
|
||||
@Component({
|
||||
@@ -1138,7 +1138,7 @@ export declare interface IonItemOptions extends Components.IonItemOptions {
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
template: '<ng-content></ng-content>',
|
||||
// eslint-disable-next-line @angular-eslint/no-inputs-metadata-property
|
||||
inputs: ['disabled'],
|
||||
inputs: ['animationType', 'disabled'],
|
||||
})
|
||||
export class IonItemSliding {
|
||||
protected el: HTMLElement;
|
||||
|
||||
@@ -1103,7 +1103,7 @@ export declare interface IonItemOptions extends Components.IonItemOptions {
|
||||
|
||||
@ProxyCmp({
|
||||
defineCustomElementFn: defineIonItemSliding,
|
||||
inputs: ['disabled'],
|
||||
inputs: ['animationType', 'disabled'],
|
||||
methods: ['getOpenAmount', 'getSlidingRatio', 'open', 'close', 'closeOpened']
|
||||
})
|
||||
@Component({
|
||||
@@ -1111,7 +1111,7 @@ export declare interface IonItemOptions extends Components.IonItemOptions {
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
template: '<ng-content></ng-content>',
|
||||
// eslint-disable-next-line @angular-eslint/no-inputs-metadata-property
|
||||
inputs: ['disabled'],
|
||||
inputs: ['animationType', 'disabled'],
|
||||
standalone: true
|
||||
})
|
||||
export class IonItemSliding {
|
||||
|
||||
@@ -491,6 +491,7 @@ export const IonItemOptions = /*@__PURE__*/ defineContainer<JSX.IonItemOptions>(
|
||||
|
||||
export const IonItemSliding = /*@__PURE__*/ defineContainer<JSX.IonItemSliding>('ion-item-sliding', defineIonItemSliding, [
|
||||
'disabled',
|
||||
'animationType',
|
||||
'ionDrag'
|
||||
]);
|
||||
|
||||
|
||||