@rdlabo/ionic-theme-ios26 0.4.5 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,8 @@
1
+ import { Animation, AnimationKeyFrames } from '@ionic/core/dist/types/utils/animation/animation-interface';
2
+ import { AnimationPosition, EffectScales } from './interfaces';
3
+ import { GestureDetail } from '@ionic/core';
4
+ export declare const getScaleAnimation: (effectElement: Element) => Animation;
5
+ export declare const createPreMoveAnimation: (effectElement: Element, tabSelectedElement: Element, currentTouchedElement: Element, animationPosition: AnimationPosition) => Animation;
6
+ export declare const createMoveAnimation: (effectElement: Element, detail: GestureDetail, tabSelectedElement: Element, animationPosition: AnimationPosition) => Animation;
7
+ export declare const getMoveAnimationKeyframe: (type: "moveRight" | "moveLeft" | "slowly", scales: EffectScales) => AnimationKeyFrames;
8
+ //# sourceMappingURL=animations.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"animations.d.ts","sourceRoot":"","sources":["../../src/gestures/animations.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,kBAAkB,EAAE,MAAM,4DAA4D,CAAC;AAC3G,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC/D,OAAO,EAAmB,aAAa,EAAE,MAAM,aAAa,CAAC;AAG7D,eAAO,MAAM,iBAAiB,GAAI,eAAe,OAAO,KAAG,SAE1D,CAAC;AAEF,eAAO,MAAM,sBAAsB,GACjC,eAAe,OAAO,EACtB,oBAAoB,OAAO,EAC3B,uBAAuB,OAAO,EAC9B,mBAAmB,iBAAiB,KACnC,SA0BF,CAAC;AAEF,eAAO,MAAM,mBAAmB,GAC9B,eAAe,OAAO,EACtB,QAAQ,aAAa,EACrB,oBAAoB,OAAO,EAC3B,mBAAmB,iBAAiB,KACnC,SAiBF,CAAC;AAEF,eAAO,MAAM,wBAAwB,GAAI,MAAM,WAAW,GAAG,UAAU,GAAG,QAAQ,EAAE,QAAQ,YAAY,KAAG,kBAqD1G,CAAC"}
@@ -0,0 +1,97 @@
1
+ import { createAnimation } from '@ionic/core';
2
+ import { getStep } from './utils';
3
+ export const getScaleAnimation = (effectElement) => {
4
+ return createAnimation().addElement(effectElement.shadowRoot.querySelector('[part="native"]')).easing('ease-out');
5
+ };
6
+ export const createPreMoveAnimation = (effectElement, tabSelectedElement, currentTouchedElement, animationPosition) => {
7
+ const diff = Math.max(Math.abs(tabSelectedElement.getBoundingClientRect().left - currentTouchedElement.getBoundingClientRect().left), 120);
8
+ return createAnimation()
9
+ .duration(diff * 1.8)
10
+ .easing('ease-out')
11
+ .addElement(effectElement)
12
+ .beforeStyles({
13
+ width: `${tabSelectedElement.clientWidth}px`,
14
+ height: `${tabSelectedElement.clientHeight}px`,
15
+ display: 'block',
16
+ opacity: '1',
17
+ transform: 'none',
18
+ })
19
+ .keyframes([
20
+ {
21
+ offset: 0,
22
+ transform: `translate3d(${tabSelectedElement.getBoundingClientRect().left}px, ${animationPosition.positionY}px, 0)`,
23
+ },
24
+ {
25
+ offset: 1,
26
+ transform: `translate3d(${currentTouchedElement.getBoundingClientRect().left}px, ${animationPosition.positionY}px, 0)`,
27
+ },
28
+ ]);
29
+ };
30
+ export const createMoveAnimation = (effectElement, detail, tabSelectedElement, animationPosition) => {
31
+ return createAnimation()
32
+ .duration(500)
33
+ .addElement(effectElement)
34
+ .beforeStyles({
35
+ width: `${tabSelectedElement.clientWidth}px`,
36
+ height: `${tabSelectedElement.clientHeight}px`,
37
+ display: 'block',
38
+ opacity: '1',
39
+ transform: 'none',
40
+ })
41
+ .fromTo('transform', `translate3d(${animationPosition.minPositionX}px, ${animationPosition.positionY}px, 0)`, `translate3d(${animationPosition.maxPositionX}px, ${animationPosition.positionY}px, 0)`)
42
+ .progressStep(getStep(detail.currentX, animationPosition));
43
+ };
44
+ export const getMoveAnimationKeyframe = (type, scales) => {
45
+ return {
46
+ moveRight: [
47
+ {
48
+ offset: 0,
49
+ transform: scales.large,
50
+ },
51
+ {
52
+ offset: 0.4,
53
+ transform: scales.small,
54
+ },
55
+ {
56
+ offset: 0.75,
57
+ transform: scales.xlarge,
58
+ },
59
+ {
60
+ offset: 1,
61
+ transform: scales.large,
62
+ },
63
+ ],
64
+ moveLeft: [
65
+ {
66
+ offset: 0,
67
+ transform: scales.large,
68
+ },
69
+ {
70
+ offset: 0.1,
71
+ transform: scales.xlarge,
72
+ },
73
+ {
74
+ offset: 0.6,
75
+ transform: scales.small,
76
+ },
77
+ {
78
+ offset: 1,
79
+ transform: scales.large,
80
+ },
81
+ ],
82
+ slowly: [
83
+ {
84
+ offset: 0,
85
+ transform: scales.large,
86
+ },
87
+ {
88
+ offset: 0.4,
89
+ transform: scales.medium,
90
+ },
91
+ {
92
+ offset: 1,
93
+ transform: scales.large,
94
+ },
95
+ ],
96
+ }[type];
97
+ };
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/gestures/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAS9D,eAAO,MAAM,cAAc,GACzB,eAAe,WAAW,EAC1B,eAAe,MAAM,EACrB,mBAAmB,MAAM,EACzB,QAAQ,YAAY,KACnB,gBAAgB,GAAG,SAmRrB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/gestures/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAqB,YAAY,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAUjF,eAAO,MAAM,cAAc,GACzB,eAAe,WAAW,EAC1B,eAAe,MAAM,EACrB,mBAAmB,MAAM,EACzB,QAAQ,YAAY,KACnB,gBAAgB,GAAG,SAqLrB,CAAC"}
@@ -1,5 +1,6 @@
1
- import { createGesture, createAnimation } from '@ionic/core';
2
- import { cloneElement, getTransform } from './utils';
1
+ import { createGesture } from '@ionic/core';
2
+ import { changeSelectedElement, cloneElement, getStep } from './utils';
3
+ import { createMoveAnimation, createPreMoveAnimation, getMoveAnimationKeyframe, getScaleAnimation } from './animations';
3
4
  const GESTURE_NAME = 'ios26-enable-gesture';
4
5
  const ANIMATED_NAME = 'ios26-animated';
5
6
  export const registerEffect = (targetElement, effectTagName, selectedClassName, scales) => {
@@ -9,22 +10,20 @@ export const registerEffect = (targetElement, effectTagName, selectedClassName,
9
10
  let gesture;
10
11
  let moveAnimation;
11
12
  let currentTouchedElement;
12
- let animationLatestX;
13
- let effectElementPositionY;
14
- let enterAnimationPromise;
15
- let moveAnimationPromise;
16
13
  let clearActivatedTimer;
14
+ let animationPosition = undefined;
15
+ let scaleAnimationPromise;
16
+ let startAnimationPromise;
17
+ let maxVelocity = 0;
17
18
  const effectElement = cloneElement(effectTagName);
18
19
  const onPointerDown = () => {
19
20
  clearActivated();
20
- currentTouchedElement?.classList.remove('ion-activated');
21
21
  gesture.destroy();
22
22
  createAnimationGesture();
23
23
  };
24
24
  const onPointerUp = (event) => {
25
- clearActivatedTimer = setTimeout(() => {
26
- onEndGesture();
27
- currentTouchedElement?.classList.remove('ion-activated');
25
+ clearActivatedTimer = setTimeout(async () => {
26
+ await onEndGesture();
28
27
  gesture.destroy();
29
28
  createAnimationGesture();
30
29
  });
@@ -39,7 +38,9 @@ export const registerEffect = (targetElement, effectTagName, selectedClassName,
39
38
  gestureName: `${GESTURE_NAME}_${effectTagName}_${crypto.randomUUID()}`,
40
39
  onStart: (event) => onStartGesture(event),
41
40
  onMove: (event) => onMoveGesture(event),
42
- onEnd: () => onEndGesture(),
41
+ onEnd: () => {
42
+ onEndGesture().then();
43
+ },
43
44
  });
44
45
  gesture.enable(true);
45
46
  };
@@ -48,178 +49,94 @@ export const registerEffect = (targetElement, effectTagName, selectedClassName,
48
49
  if (!currentTouchedElement) {
49
50
  return;
50
51
  }
51
- requestAnimationFrame(() => {
52
- effectElement.style.display = 'none';
53
- effectElement.innerHTML = '';
54
- effectElement.style.transform = 'none';
55
- });
56
- targetElement.classList.remove(ANIMATED_NAME);
52
+ currentTouchedElement.click();
53
+ currentTouchedElement?.classList.remove('ion-activated');
57
54
  currentTouchedElement = undefined;
58
- moveAnimation = undefined;
59
- moveAnimationPromise = undefined;
60
- enterAnimationPromise = undefined;
55
+ effectElement.style.display = 'none';
56
+ maxVelocity = 0;
57
+ targetElement.classList.remove(ANIMATED_NAME);
61
58
  };
62
59
  const onStartGesture = (detail) => {
63
- enterAnimationPromise = undefined;
64
60
  currentTouchedElement = detail.event.target.closest(effectTagName) || undefined;
65
61
  const tabSelectedElement = targetElement.querySelector(`${effectTagName}.${selectedClassName}`);
66
62
  if (currentTouchedElement === undefined || tabSelectedElement === null) {
67
63
  return false;
68
64
  }
69
- effectElementPositionY = tabSelectedElement.getBoundingClientRect().top;
70
- const startTransform = getTransform(tabSelectedElement.getBoundingClientRect().left + tabSelectedElement.clientWidth / 2, effectElementPositionY, tabSelectedElement);
71
- const middleTransform = getTransform((tabSelectedElement.getBoundingClientRect().left + tabSelectedElement.clientWidth / 2 + detail.currentX) / 2, effectElementPositionY, currentTouchedElement);
72
- const endTransform = getTransform(detail.currentX, effectElementPositionY, currentTouchedElement);
73
- const enterAnimation = createAnimation();
74
- enterAnimation
75
- .addElement(effectElement)
76
- .delay(70)
77
- .beforeStyles({
78
- width: `${tabSelectedElement.clientWidth}px`,
79
- height: `${tabSelectedElement.clientHeight}px`,
80
- display: 'block',
81
- })
82
- .beforeAddWrite(() => {
83
- tabSelectedElement.childNodes.forEach((node) => {
84
- effectElement.appendChild(node.cloneNode(true));
85
- });
86
- targetElement.classList.add(ANIMATED_NAME);
87
- currentTouchedElement.classList.add('ion-activated');
88
- currentTouchedElement.click();
89
- });
90
- if (currentTouchedElement === tabSelectedElement) {
91
- enterAnimation
92
- .keyframes([
93
- {
94
- transform: `${startTransform} ${scales.small}`,
95
- opacity: 1,
96
- offset: 0,
97
- },
98
- {
99
- transform: `${middleTransform} ${scales.large}`,
100
- opacity: 1,
101
- offset: 0.6,
102
- },
103
- {
104
- transform: `${endTransform} ${scales.medium}`,
105
- opacity: 1,
106
- offset: 1,
107
- },
108
- ])
109
- .duration(160);
110
- }
111
- else {
112
- enterAnimation
113
- .keyframes([
114
- {
115
- transform: `${startTransform} ${scales.small}`,
116
- opacity: 1,
117
- offset: 0,
118
- },
119
- {
120
- transform: `${middleTransform} ${scales.large}`,
121
- opacity: 1,
122
- offset: 0.65,
123
- },
124
- {
125
- transform: `${endTransform} ${scales.medium}`,
126
- opacity: 1,
127
- offset: 1,
128
- },
129
- ])
130
- .duration(280);
131
- }
132
- animationLatestX = detail.currentX;
133
- enterAnimationPromise = enterAnimation.play().then(() => {
134
- enterAnimationPromise = undefined;
65
+ animationPosition = {
66
+ minPositionX: targetElement.getBoundingClientRect().left,
67
+ maxPositionX: targetElement.getBoundingClientRect().right - tabSelectedElement.clientWidth,
68
+ width: tabSelectedElement.clientWidth,
69
+ positionY: tabSelectedElement.getBoundingClientRect().top,
70
+ };
71
+ targetElement.classList.add(ANIMATED_NAME);
72
+ changeSelectedElement(targetElement, currentTouchedElement, effectTagName, selectedClassName);
73
+ startAnimationPromise = (() => {
74
+ if (tabSelectedElement === currentTouchedElement) {
75
+ return new Promise((resolve) => resolve());
76
+ }
77
+ else {
78
+ const preMoveAnimation = createPreMoveAnimation(effectElement, tabSelectedElement, currentTouchedElement, animationPosition);
79
+ return preMoveAnimation.play().finally(() => preMoveAnimation.destroy());
80
+ }
81
+ })();
82
+ startAnimationPromise.then(() => {
83
+ moveAnimation = createMoveAnimation(effectElement, detail, tabSelectedElement, animationPosition);
84
+ moveAnimation.progressStart(true, getStep(currentTouchedElement.getBoundingClientRect().left + currentTouchedElement.clientWidth / 2, animationPosition));
135
85
  });
86
+ getScaleAnimation(effectElement).duration(200).to('opacity', 1).to('transform', scales.large).play();
136
87
  return true;
137
88
  };
138
89
  const onMoveGesture = (detail) => {
139
- if (currentTouchedElement === undefined || enterAnimationPromise || moveAnimationPromise) {
140
- return true;
90
+ if (currentTouchedElement === undefined || !moveAnimation) {
91
+ return false;
141
92
  }
142
- const startTransform = getTransform(animationLatestX, effectElementPositionY, currentTouchedElement);
143
- const endTransform = getTransform(detail.currentX, effectElementPositionY, currentTouchedElement);
144
- if (!moveAnimation) {
145
- moveAnimation = createAnimation();
146
- moveAnimation
147
- .addElement(effectElement)
148
- .duration(800)
149
- .easing('ease-in-out')
150
- .keyframes([
151
- {
152
- transform: `${startTransform} ${scales.medium}`,
153
- opacity: 1,
154
- offset: 0,
155
- },
156
- {
157
- transform: `${startTransform} ${scales.xlarge}`,
158
- opacity: 1,
159
- offset: 0.2,
160
- },
161
- {
162
- transform: `${endTransform} ${scales.medium}`,
163
- opacity: 1,
164
- offset: 1,
165
- },
166
- ]);
93
+ if (scaleAnimationPromise === undefined) {
94
+ if (Math.abs(detail.velocityX) > maxVelocity) {
95
+ maxVelocity = Math.abs(detail.velocityX);
96
+ }
97
+ if (Math.abs(detail.velocityX) > 0.2) {
98
+ scaleAnimationPromise = getScaleAnimation(effectElement)
99
+ .duration(720)
100
+ .keyframes(getMoveAnimationKeyframe('slowly', scales))
101
+ .play()
102
+ .finally(() => (scaleAnimationPromise = undefined));
103
+ }
104
+ if (maxVelocity > 0.2 && Math.abs(detail.velocityX) < 0.15 && Math.abs(detail.startX - detail.currentX) > 100) {
105
+ scaleAnimationPromise = getScaleAnimation(effectElement)
106
+ .duration(720)
107
+ .keyframes(getMoveAnimationKeyframe(detail.velocityX > 0 ? 'moveRight' : 'moveLeft', scales))
108
+ .play()
109
+ .finally(() => (scaleAnimationPromise = undefined));
110
+ maxVelocity = 0;
111
+ }
167
112
  }
168
- else {
169
- moveAnimation.duration(0).keyframes([
170
- {
171
- transform: `${endTransform} ${scales.medium}`,
172
- opacity: 1,
173
- offset: 1,
174
- },
175
- {
176
- transform: `${endTransform} ${scales.medium}`,
177
- opacity: 1,
178
- offset: 1,
179
- },
180
- ]);
113
+ const latestTouchedElement = detail.event.target.closest(effectTagName) || undefined;
114
+ if (latestTouchedElement && currentTouchedElement !== latestTouchedElement) {
115
+ currentTouchedElement = latestTouchedElement;
116
+ changeSelectedElement(targetElement, currentTouchedElement, effectTagName, selectedClassName);
181
117
  }
182
- animationLatestX = detail.currentX;
183
- moveAnimationPromise = moveAnimation.play().then(() => {
184
- moveAnimationPromise = undefined;
185
- });
118
+ moveAnimation.progressStep(getStep(detail.currentX, animationPosition));
186
119
  return true;
187
120
  };
188
- const onEndGesture = () => {
121
+ const onEndGesture = async () => {
189
122
  if (clearActivatedTimer !== undefined) {
190
123
  clearTimeout(clearActivatedTimer);
191
124
  clearActivatedTimer = undefined;
192
125
  }
193
- if (currentTouchedElement === undefined) {
126
+ if (startAnimationPromise) {
127
+ await startAnimationPromise;
128
+ }
129
+ if (currentTouchedElement === undefined || !moveAnimation) {
194
130
  return false;
195
131
  }
196
- const transform = getTransform(animationLatestX, effectElementPositionY, currentTouchedElement);
197
- const leaveAnimation = createAnimation();
198
- leaveAnimation.addElement(effectElement);
199
- leaveAnimation
200
- .onFinish(() => clearActivated())
201
- .easing('ease-in')
202
- .duration(80)
203
- .keyframes([
204
- {
205
- transform: `${transform} ${scales.medium}`,
206
- opacity: 1,
207
- },
208
- {
209
- transform: `${transform} ${scales.small}`,
210
- opacity: 0,
211
- },
212
- ]);
213
- (async () => {
214
- if (enterAnimationPromise) {
215
- setTimeout(() => currentTouchedElement.classList.remove('ion-activated'), 50);
216
- await enterAnimationPromise;
217
- }
218
- else {
219
- currentTouchedElement.classList.remove('ion-activated');
220
- }
221
- leaveAnimation.play();
222
- })();
132
+ setTimeout(() => {
133
+ const targetX = currentTouchedElement.getBoundingClientRect().left + currentTouchedElement.clientWidth / 2;
134
+ const step = getStep(targetX, animationPosition);
135
+ moveAnimation.progressStep(step);
136
+ });
137
+ await getScaleAnimation(effectElement).duration(120).to('transform', `scale(1, 0.92)`).play();
138
+ moveAnimation.destroy();
139
+ clearActivated();
223
140
  return true;
224
141
  };
225
142
  return {
@@ -7,4 +7,10 @@ export interface EffectScales {
7
7
  export interface registeredEffect {
8
8
  destroy: () => void;
9
9
  }
10
+ export interface AnimationPosition {
11
+ minPositionX: number;
12
+ maxPositionX: number;
13
+ width: number;
14
+ positionY: number;
15
+ }
10
16
  //# sourceMappingURL=interfaces.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"interfaces.d.ts","sourceRoot":"","sources":["../../src/gestures/interfaces.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB"}
1
+ {"version":3,"file":"interfaces.d.ts","sourceRoot":"","sources":["../../src/gestures/interfaces.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED,MAAM,WAAW,iBAAiB;IAChC,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;CACnB"}
@@ -1,3 +1,5 @@
1
+ import { AnimationPosition } from './interfaces';
1
2
  export declare const cloneElement: (tagName: string) => HTMLElement;
2
- export declare const getTransform: (detailCurrentX: number, tabEffectElY: number, tabSelectedActual: Element) => string;
3
+ export declare const getStep: (targetX: number, animationPosition: AnimationPosition) => number;
4
+ export declare const changeSelectedElement: (targetElement: HTMLElement, selectedElement: HTMLElement, effectTagName: string, selectedClassName: string) => void;
3
5
  //# sourceMappingURL=utils.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/gestures/utils.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,YAAY,GAAI,SAAS,MAAM,KAAG,WAY9C,CAAC;AAEF,eAAO,MAAM,YAAY,GAAI,gBAAgB,MAAM,EAAE,cAAc,MAAM,EAAE,mBAAmB,OAAO,KAAG,MAavG,CAAC"}
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/gestures/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAEjD,eAAO,MAAM,YAAY,GAAI,SAAS,MAAM,KAAG,WAY9C,CAAC;AAEF,eAAO,MAAM,OAAO,GAAI,SAAS,MAAM,EAAE,mBAAmB,iBAAiB,WAQ5E,CAAC;AAEF,eAAO,MAAM,qBAAqB,GAChC,eAAe,WAAW,EAC1B,iBAAiB,WAAW,EAC5B,eAAe,MAAM,EACrB,mBAAmB,MAAM,KACxB,IAMF,CAAC"}
@@ -9,16 +9,19 @@ export const cloneElement = (tagName) => {
9
9
  document.body.appendChild(clonedEl);
10
10
  return clonedEl;
11
11
  };
12
- export const getTransform = (detailCurrentX, tabEffectElY, tabSelectedActual) => {
13
- const diff = -2;
14
- const currentX = detailCurrentX - tabSelectedActual.clientWidth / 2;
15
- const maxLeft = tabSelectedActual.getBoundingClientRect().left + diff;
16
- const maxRight = tabSelectedActual.getBoundingClientRect().right - diff - tabSelectedActual.clientWidth;
17
- if (maxLeft < currentX && currentX < maxRight) {
18
- return `translate3d(${currentX}px, ${tabEffectElY}px, 0)`;
12
+ export const getStep = (targetX, animationPosition) => {
13
+ if (animationPosition === undefined) {
14
+ return 0;
19
15
  }
20
- if (maxLeft > currentX) {
21
- return `translate3d(${maxLeft}px, ${tabEffectElY}px, 0)`;
22
- }
23
- return `translate3d(${maxRight}px, ${tabEffectElY}px, 0)`;
16
+ const currentX = targetX - animationPosition.width / 2;
17
+ let progress = (currentX - animationPosition.minPositionX) / (animationPosition.maxPositionX - animationPosition.minPositionX);
18
+ progress = Math.max(0, Math.min(1, progress));
19
+ return progress;
20
+ };
21
+ export const changeSelectedElement = (targetElement, selectedElement, effectTagName, selectedClassName) => {
22
+ targetElement.querySelectorAll(effectTagName).forEach((element) => {
23
+ element.classList.remove(selectedClassName);
24
+ element.classList.remove('ion-activated');
25
+ });
26
+ selectedElement.classList.add(selectedClassName, 'ion-activated');
24
27
  };
package/dist/index.js CHANGED
@@ -2,10 +2,10 @@ import { registerEffect } from './gestures';
2
2
  export * from './gestures/interfaces';
3
3
  export const registerTabBarEffect = (targetElement) => {
4
4
  return registerEffect(targetElement, 'ion-tab-button', 'tab-selected', {
5
- small: 'scale(1.1)',
5
+ small: 'scale(1.1, 1)',
6
6
  medium: 'scale(1.2)',
7
7
  large: 'scale(1.3)',
8
- xlarge: 'scale(1.3, 1.5)',
8
+ xlarge: 'scale(1.15, 1.4)',
9
9
  });
10
10
  };
11
11
  export const registerSegmentEffect = (targetElement) => {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@rdlabo/ionic-theme-ios26",
3
- "version": "0.4.5",
4
- "description": "iOS26 CSS Theme for Ionic Framework",
3
+ "version": "1.0.1",
4
+ "description": "iOS26 Theme for Ionic Framework",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.js",
7
7
  "types": "./dist/index.d.ts",
@@ -0,0 +1,120 @@
1
+ import { Animation, AnimationKeyFrames } from '@ionic/core/dist/types/utils/animation/animation-interface';
2
+ import { AnimationPosition, EffectScales } from './interfaces';
3
+ import { createAnimation, GestureDetail } from '@ionic/core';
4
+ import { getStep } from './utils';
5
+
6
+ export const getScaleAnimation = (effectElement: Element): Animation => {
7
+ return createAnimation().addElement(effectElement.shadowRoot!.querySelector<HTMLElement>('[part="native"]')!).easing('ease-out');
8
+ };
9
+
10
+ export const createPreMoveAnimation = (
11
+ effectElement: Element,
12
+ tabSelectedElement: Element,
13
+ currentTouchedElement: Element,
14
+ animationPosition: AnimationPosition,
15
+ ): Animation => {
16
+ const diff = Math.max(
17
+ Math.abs(tabSelectedElement.getBoundingClientRect().left - currentTouchedElement.getBoundingClientRect().left),
18
+ 120,
19
+ );
20
+ return createAnimation()
21
+ .duration(diff * 1.8)
22
+ .easing('ease-out')
23
+ .addElement(effectElement)
24
+ .beforeStyles({
25
+ width: `${tabSelectedElement.clientWidth}px`,
26
+ height: `${tabSelectedElement.clientHeight}px`,
27
+ display: 'block',
28
+ opacity: '1',
29
+ transform: 'none',
30
+ })
31
+ .keyframes([
32
+ {
33
+ offset: 0,
34
+ transform: `translate3d(${tabSelectedElement.getBoundingClientRect().left}px, ${animationPosition.positionY}px, 0)`,
35
+ },
36
+ {
37
+ offset: 1,
38
+ transform: `translate3d(${currentTouchedElement.getBoundingClientRect().left}px, ${animationPosition.positionY}px, 0)`,
39
+ },
40
+ ]);
41
+ };
42
+
43
+ export const createMoveAnimation = (
44
+ effectElement: Element,
45
+ detail: GestureDetail,
46
+ tabSelectedElement: Element,
47
+ animationPosition: AnimationPosition,
48
+ ): Animation => {
49
+ return createAnimation()
50
+ .duration(500)
51
+ .addElement(effectElement)
52
+ .beforeStyles({
53
+ width: `${tabSelectedElement.clientWidth}px`,
54
+ height: `${tabSelectedElement.clientHeight}px`,
55
+ display: 'block',
56
+ opacity: '1',
57
+ transform: 'none',
58
+ })
59
+ .fromTo(
60
+ 'transform',
61
+ `translate3d(${animationPosition.minPositionX}px, ${animationPosition.positionY}px, 0)`,
62
+ `translate3d(${animationPosition.maxPositionX}px, ${animationPosition.positionY}px, 0)`,
63
+ )
64
+ .progressStep(getStep(detail.currentX, animationPosition));
65
+ };
66
+
67
+ export const getMoveAnimationKeyframe = (type: 'moveRight' | 'moveLeft' | 'slowly', scales: EffectScales): AnimationKeyFrames => {
68
+ return {
69
+ moveRight: [
70
+ {
71
+ offset: 0,
72
+ transform: scales.large,
73
+ },
74
+ {
75
+ offset: 0.4,
76
+ transform: scales.small,
77
+ },
78
+ {
79
+ offset: 0.75,
80
+ transform: scales.xlarge,
81
+ },
82
+ {
83
+ offset: 1,
84
+ transform: scales.large,
85
+ },
86
+ ],
87
+ moveLeft: [
88
+ {
89
+ offset: 0,
90
+ transform: scales.large,
91
+ },
92
+ {
93
+ offset: 0.1,
94
+ transform: scales.xlarge,
95
+ },
96
+ {
97
+ offset: 0.6,
98
+ transform: scales.small,
99
+ },
100
+ {
101
+ offset: 1,
102
+ transform: scales.large,
103
+ },
104
+ ],
105
+ slowly: [
106
+ {
107
+ offset: 0,
108
+ transform: scales.large,
109
+ },
110
+ {
111
+ offset: 0.4,
112
+ transform: scales.medium,
113
+ },
114
+ {
115
+ offset: 1,
116
+ transform: scales.large,
117
+ },
118
+ ],
119
+ }[type];
120
+ };