@rdlabo/ionic-theme-ios26 1.1.1 → 1.2.0
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/README.md +62 -3
- package/dist/css/components/ion-fab.css +1 -1
- package/dist/css/components/ion-searchbar.css +1 -1
- package/dist/css/components/ion-toolbar.css +1 -1
- package/dist/css/ionic-theme-ios26.css +1 -1
- package/dist/css/utils/searchable.css +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/popover/animations/ios.enter.d.ts.map +1 -1
- package/dist/popover/animations/ios.enter.js +3 -17
- package/dist/popover/utils.d.ts +2 -13
- package/dist/popover/utils.d.ts.map +1 -1
- package/dist/popover/utils.js +11 -119
- package/dist/sheets-of-glass/index.d.ts.map +1 -1
- package/dist/sheets-of-glass/index.js +6 -1
- package/dist/tab-bar-searchable/animations/enter.d.ts +8 -0
- package/dist/tab-bar-searchable/animations/enter.d.ts.map +1 -0
- package/dist/tab-bar-searchable/animations/enter.js +73 -0
- package/dist/tab-bar-searchable/animations/leave.d.ts +8 -0
- package/dist/tab-bar-searchable/animations/leave.d.ts.map +1 -0
- package/dist/tab-bar-searchable/animations/leave.js +66 -0
- package/dist/tab-bar-searchable/index.d.ts +4 -0
- package/dist/tab-bar-searchable/index.d.ts.map +1 -0
- package/dist/tab-bar-searchable/index.js +75 -0
- package/dist/tab-bar-searchable/interfaces.d.ts +41 -0
- package/dist/tab-bar-searchable/interfaces.d.ts.map +1 -0
- package/dist/tab-bar-searchable/interfaces.js +5 -0
- package/dist/tab-bar-searchable/utils.d.ts +12 -0
- package/dist/tab-bar-searchable/utils.d.ts.map +1 -0
- package/dist/tab-bar-searchable/utils.js +60 -0
- package/package.json +1 -1
- package/src/index.ts +1 -0
- package/src/popover/animations/ios.enter.ts +20 -52
- package/src/popover/utils.ts +8 -230
- package/src/sheets-of-glass/index.ts +6 -1
- package/src/styles/components/ion-fab.scss +31 -1
- package/src/styles/components/ion-searchbar.scss +10 -0
- package/src/styles/components/ion-toolbar.scss +20 -0
- package/src/styles/utils/searchable.scss +0 -0
- package/src/tab-bar-searchable/animations/enter.ts +92 -0
- package/src/tab-bar-searchable/animations/leave.ts +89 -0
- package/src/tab-bar-searchable/index.ts +141 -0
- package/src/tab-bar-searchable/interfaces.ts +28 -0
- package/src/tab-bar-searchable/utils.ts +75 -0
package/dist/popover/utils.js
CHANGED
|
@@ -1,12 +1,5 @@
|
|
|
1
1
|
import { getElementRoot, raf } from '../utils';
|
|
2
2
|
import { POPOVER_IOS_BODY_MARGIN } from './animations/ios.enter';
|
|
3
|
-
export const getArrowDimensions = (arrowEl) => {
|
|
4
|
-
if (!arrowEl) {
|
|
5
|
-
return { arrowWidth: 0, arrowHeight: 0 };
|
|
6
|
-
}
|
|
7
|
-
const { width, height } = arrowEl.getBoundingClientRect();
|
|
8
|
-
return { arrowWidth: width, arrowHeight: height };
|
|
9
|
-
};
|
|
10
3
|
export const getPopoverDimensions = (size, contentEl, triggerEl) => {
|
|
11
4
|
const contentDimentions = contentEl.getBoundingClientRect();
|
|
12
5
|
const contentHeight = contentDimentions.height;
|
|
@@ -170,70 +163,7 @@ const focusItem = (item) => {
|
|
|
170
163
|
raf(() => button.focus());
|
|
171
164
|
}
|
|
172
165
|
};
|
|
173
|
-
export const
|
|
174
|
-
export const configureKeyboardInteraction = (popoverEl) => {
|
|
175
|
-
const callback = async (ev) => {
|
|
176
|
-
const activeElement = document.activeElement;
|
|
177
|
-
let items = [];
|
|
178
|
-
const targetTagName = ev.target?.tagName;
|
|
179
|
-
if (targetTagName !== 'ION-POPOVER' && targetTagName !== 'ION-ITEM') {
|
|
180
|
-
return;
|
|
181
|
-
}
|
|
182
|
-
try {
|
|
183
|
-
items = Array.from(popoverEl.querySelectorAll('ion-item:not(ion-popover ion-popover *):not([disabled])'));
|
|
184
|
-
}
|
|
185
|
-
catch { }
|
|
186
|
-
switch (ev.key) {
|
|
187
|
-
case 'ArrowLeft':
|
|
188
|
-
const parentPopover = await popoverEl.getParentPopover();
|
|
189
|
-
if (parentPopover) {
|
|
190
|
-
popoverEl.dismiss(undefined, undefined, false);
|
|
191
|
-
}
|
|
192
|
-
break;
|
|
193
|
-
case 'ArrowDown':
|
|
194
|
-
ev.preventDefault();
|
|
195
|
-
const nextItem = getNextItem(items, activeElement);
|
|
196
|
-
if (nextItem !== undefined) {
|
|
197
|
-
focusItem(nextItem);
|
|
198
|
-
}
|
|
199
|
-
break;
|
|
200
|
-
case 'ArrowUp':
|
|
201
|
-
ev.preventDefault();
|
|
202
|
-
const prevItem = getPrevItem(items, activeElement);
|
|
203
|
-
if (prevItem !== undefined) {
|
|
204
|
-
focusItem(prevItem);
|
|
205
|
-
}
|
|
206
|
-
break;
|
|
207
|
-
case 'Home':
|
|
208
|
-
ev.preventDefault();
|
|
209
|
-
const firstItem = items[0];
|
|
210
|
-
if (firstItem !== undefined) {
|
|
211
|
-
focusItem(firstItem);
|
|
212
|
-
}
|
|
213
|
-
break;
|
|
214
|
-
case 'End':
|
|
215
|
-
ev.preventDefault();
|
|
216
|
-
const lastItem = items[items.length - 1];
|
|
217
|
-
if (lastItem !== undefined) {
|
|
218
|
-
focusItem(lastItem);
|
|
219
|
-
}
|
|
220
|
-
break;
|
|
221
|
-
case 'ArrowRight':
|
|
222
|
-
case ' ':
|
|
223
|
-
case 'Enter':
|
|
224
|
-
if (activeElement && isTriggerElement(activeElement)) {
|
|
225
|
-
const rightEvent = new CustomEvent('ionPopoverActivateTrigger');
|
|
226
|
-
activeElement.dispatchEvent(rightEvent);
|
|
227
|
-
}
|
|
228
|
-
break;
|
|
229
|
-
default:
|
|
230
|
-
break;
|
|
231
|
-
}
|
|
232
|
-
};
|
|
233
|
-
popoverEl.addEventListener('keydown', callback);
|
|
234
|
-
return () => popoverEl.removeEventListener('keydown', callback);
|
|
235
|
-
};
|
|
236
|
-
export const getPopoverPosition = (isRTL, contentWidth, contentHeight, arrowWidth, arrowHeight, reference, side, align, defaultPosition, triggerEl, event) => {
|
|
166
|
+
export const getPopoverPosition = (isRTL, contentWidth, contentHeight, reference, side, align, defaultPosition, triggerEl, event) => {
|
|
237
167
|
let referenceCoordinates = {
|
|
238
168
|
top: 0,
|
|
239
169
|
left: 0,
|
|
@@ -269,13 +199,12 @@ export const getPopoverPosition = (isRTL, contentWidth, contentHeight, arrowWidt
|
|
|
269
199
|
};
|
|
270
200
|
break;
|
|
271
201
|
}
|
|
272
|
-
const coordinates = calculatePopoverSide(side, referenceCoordinates, contentWidth, contentHeight,
|
|
202
|
+
const coordinates = calculatePopoverSide(side, referenceCoordinates, contentWidth, contentHeight, isRTL);
|
|
273
203
|
const alignedCoordinates = calculatePopoverAlign(align, side, referenceCoordinates, contentWidth, contentHeight);
|
|
274
204
|
const top = coordinates.top + alignedCoordinates.top;
|
|
275
205
|
const left = coordinates.left + alignedCoordinates.left;
|
|
276
|
-
const { arrowTop, arrowLeft } = calculateArrowPosition(side, arrowWidth, arrowHeight, top, left, contentWidth, contentHeight, isRTL);
|
|
277
206
|
const { originX, originY } = calculatePopoverOrigin(side, align, isRTL);
|
|
278
|
-
return { top, left, referenceCoordinates,
|
|
207
|
+
return { top, left, referenceCoordinates, originX, originY };
|
|
279
208
|
};
|
|
280
209
|
const calculatePopoverOrigin = (side, align, isRTL) => {
|
|
281
210
|
switch (side) {
|
|
@@ -313,49 +242,26 @@ const getOriginYAlignment = (align) => {
|
|
|
313
242
|
return 'bottom';
|
|
314
243
|
}
|
|
315
244
|
};
|
|
316
|
-
const
|
|
317
|
-
const leftPosition = {
|
|
318
|
-
arrowTop: top + contentHeight / 2 - arrowWidth / 2,
|
|
319
|
-
arrowLeft: left + contentWidth - arrowWidth / 2,
|
|
320
|
-
};
|
|
321
|
-
const rightPosition = { arrowTop: top + contentHeight / 2 - arrowWidth / 2, arrowLeft: left - arrowWidth * 1.5 };
|
|
322
|
-
switch (side) {
|
|
323
|
-
case 'top':
|
|
324
|
-
return { arrowTop: top + contentHeight, arrowLeft: left + contentWidth / 2 - arrowWidth / 2 };
|
|
325
|
-
case 'bottom':
|
|
326
|
-
return { arrowTop: top - arrowHeight, arrowLeft: left + contentWidth / 2 - arrowWidth / 2 };
|
|
327
|
-
case 'left':
|
|
328
|
-
return leftPosition;
|
|
329
|
-
case 'right':
|
|
330
|
-
return rightPosition;
|
|
331
|
-
case 'start':
|
|
332
|
-
return isRTL ? rightPosition : leftPosition;
|
|
333
|
-
case 'end':
|
|
334
|
-
return isRTL ? leftPosition : rightPosition;
|
|
335
|
-
default:
|
|
336
|
-
return { arrowTop: 0, arrowLeft: 0 };
|
|
337
|
-
}
|
|
338
|
-
};
|
|
339
|
-
const calculatePopoverSide = (side, triggerBoundingBox, contentWidth, contentHeight, arrowWidth, arrowHeight, isRTL) => {
|
|
245
|
+
const calculatePopoverSide = (side, triggerBoundingBox, contentWidth, contentHeight, isRTL) => {
|
|
340
246
|
const sideLeft = {
|
|
341
247
|
top: triggerBoundingBox.top,
|
|
342
|
-
left: triggerBoundingBox.left - contentWidth
|
|
248
|
+
left: triggerBoundingBox.left - contentWidth,
|
|
343
249
|
};
|
|
344
250
|
const sideRight = {
|
|
345
251
|
top: triggerBoundingBox.top,
|
|
346
|
-
left: triggerBoundingBox.left + triggerBoundingBox.width
|
|
252
|
+
left: triggerBoundingBox.left + triggerBoundingBox.width,
|
|
347
253
|
};
|
|
348
254
|
switch (side) {
|
|
349
255
|
case 'top':
|
|
350
256
|
return {
|
|
351
|
-
top: triggerBoundingBox.top - contentHeight
|
|
257
|
+
top: triggerBoundingBox.top - contentHeight,
|
|
352
258
|
left: triggerBoundingBox.left,
|
|
353
259
|
};
|
|
354
260
|
case 'right':
|
|
355
261
|
return sideRight;
|
|
356
262
|
case 'bottom':
|
|
357
263
|
return {
|
|
358
|
-
top: triggerBoundingBox.top + triggerBoundingBox.height
|
|
264
|
+
top: triggerBoundingBox.top + triggerBoundingBox.height,
|
|
359
265
|
left: triggerBoundingBox.left,
|
|
360
266
|
};
|
|
361
267
|
case 'left':
|
|
@@ -415,9 +321,7 @@ const calculatePopoverCenterAlign = (side, triggerBoundingBox, contentWidth, con
|
|
|
415
321
|
};
|
|
416
322
|
}
|
|
417
323
|
};
|
|
418
|
-
export const calculateWindowAdjustment = (side, coordTop, coordLeft, bodyPadding, bodyWidth, bodyHeight, contentWidth, contentHeight, safeAreaMargin, contentOriginX, contentOriginY, triggerCoordinates,
|
|
419
|
-
let arrowTop = coordArrowTop;
|
|
420
|
-
const arrowLeft = coordArrowLeft;
|
|
324
|
+
export const calculateWindowAdjustment = (side, coordTop, coordLeft, bodyPadding, bodyWidth, bodyHeight, contentWidth, contentHeight, safeAreaMargin, contentOriginX, contentOriginY, triggerCoordinates, eventElementRect, isReplace = false) => {
|
|
421
325
|
const triggerTop = triggerCoordinates ? triggerCoordinates.top + triggerCoordinates.height : bodyHeight / 2 - contentHeight / 2;
|
|
422
326
|
const triggerHeight = triggerCoordinates ? triggerCoordinates.height : 0;
|
|
423
327
|
let left = coordLeft;
|
|
@@ -442,12 +346,11 @@ export const calculateWindowAdjustment = (side, coordTop, coordLeft, bodyPadding
|
|
|
442
346
|
if (compareTop > bodyHeight / 2 && (side === 'top' || side === 'bottom')) {
|
|
443
347
|
if (triggerTop - contentHeight > 0) {
|
|
444
348
|
if (!isReplace) {
|
|
445
|
-
top = Math.max(12, triggerTop - contentHeight - triggerHeight
|
|
349
|
+
top = Math.max(12, triggerTop - contentHeight - triggerHeight) - POPOVER_IOS_BODY_MARGIN;
|
|
446
350
|
}
|
|
447
351
|
else {
|
|
448
|
-
top = Math.max(12, triggerTop - contentHeight
|
|
352
|
+
top = Math.max(12, triggerTop - contentHeight);
|
|
449
353
|
}
|
|
450
|
-
arrowTop = top + contentHeight;
|
|
451
354
|
originY = 'bottom';
|
|
452
355
|
addPopoverBottomClass = true;
|
|
453
356
|
}
|
|
@@ -463,17 +366,6 @@ export const calculateWindowAdjustment = (side, coordTop, coordLeft, bodyPadding
|
|
|
463
366
|
originY,
|
|
464
367
|
checkSafeAreaLeft,
|
|
465
368
|
checkSafeAreaRight,
|
|
466
|
-
arrowTop,
|
|
467
|
-
arrowLeft,
|
|
468
369
|
addPopoverBottomClass,
|
|
469
370
|
};
|
|
470
371
|
};
|
|
471
|
-
export const shouldShowArrow = (side, didAdjustBounds = false, ev, trigger) => {
|
|
472
|
-
if (!ev && !trigger) {
|
|
473
|
-
return false;
|
|
474
|
-
}
|
|
475
|
-
if (side !== 'top' && side !== 'bottom' && didAdjustBounds) {
|
|
476
|
-
return false;
|
|
477
|
-
}
|
|
478
|
-
return true;
|
|
479
|
-
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/sheets-of-glass/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,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/sheets-of-glass/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,SA8LrB,CAAC"}
|
|
@@ -15,6 +15,7 @@ export const registerEffect = (targetElement, effectTagName, selectedClassName,
|
|
|
15
15
|
let scaleAnimationPromise;
|
|
16
16
|
let startAnimationPromise;
|
|
17
17
|
let maxVelocity = 0;
|
|
18
|
+
let wasRealUserClick = false;
|
|
18
19
|
const effectElement = cloneElement(effectTagName);
|
|
19
20
|
const onPointerDown = () => {
|
|
20
21
|
clearActivated();
|
|
@@ -22,6 +23,7 @@ export const registerEffect = (targetElement, effectTagName, selectedClassName,
|
|
|
22
23
|
createAnimationGesture();
|
|
23
24
|
};
|
|
24
25
|
const onPointerUp = (event) => {
|
|
26
|
+
wasRealUserClick = true;
|
|
25
27
|
clearActivatedTimer = setTimeout(async () => {
|
|
26
28
|
await onEndGesture();
|
|
27
29
|
gesture.destroy();
|
|
@@ -49,12 +51,15 @@ export const registerEffect = (targetElement, effectTagName, selectedClassName,
|
|
|
49
51
|
if (!currentTouchedElement) {
|
|
50
52
|
return;
|
|
51
53
|
}
|
|
52
|
-
|
|
54
|
+
if (!wasRealUserClick) {
|
|
55
|
+
currentTouchedElement.click();
|
|
56
|
+
}
|
|
53
57
|
currentTouchedElement?.classList.remove('ion-activated');
|
|
54
58
|
currentTouchedElement = undefined;
|
|
55
59
|
effectElement.style.display = 'none';
|
|
56
60
|
maxVelocity = 0;
|
|
57
61
|
targetElement.classList.remove(ANIMATED_NAME);
|
|
62
|
+
wasRealUserClick = false;
|
|
58
63
|
};
|
|
59
64
|
const onStartGesture = (detail) => {
|
|
60
65
|
currentTouchedElement = detail.event.target.closest(effectTagName) || undefined;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { ElementReferences, ElementSizes } from '../interfaces';
|
|
2
|
+
import { Animation } from '@ionic/core';
|
|
3
|
+
export declare const createEffectAnimation: (references: ElementReferences, sizes: ElementSizes) => Animation;
|
|
4
|
+
export declare const createSearchContainerAnimation: (references: ElementReferences, sizes: ElementSizes) => Animation;
|
|
5
|
+
export declare const createCloseButtonsAnimation: (references: ElementReferences) => Animation;
|
|
6
|
+
export declare const createTabBarAnimation: (ionTabBar: HTMLElement, references: ElementReferences, sizes: ElementSizes) => Animation;
|
|
7
|
+
export declare const createFabButtonAnimation: (ionFabButton: HTMLElement) => Animation;
|
|
8
|
+
//# sourceMappingURL=enter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"enter.d.ts","sourceRoot":"","sources":["../../../src/tab-bar-searchable/animations/enter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAChE,OAAO,EAAE,SAAS,EAAmB,MAAM,aAAa,CAAC;AAIzD,eAAO,MAAM,qBAAqB,GAAI,YAAY,iBAAiB,EAAE,OAAO,YAAY,KAAG,SA0B1F,CAAC;AAEF,eAAO,MAAM,8BAA8B,GAAI,YAAY,iBAAiB,EAAE,OAAO,YAAY,KAAG,SAUnG,CAAC;AAEF,eAAO,MAAM,2BAA2B,GAAI,YAAY,iBAAiB,KAAG,SAO3E,CAAC;AAEF,eAAO,MAAM,qBAAqB,GAAI,WAAW,WAAW,EAAE,YAAY,iBAAiB,EAAE,OAAO,YAAY,KAAG,SAwBlH,CAAC;AAEF,eAAO,MAAM,wBAAwB,GAAI,cAAc,WAAW,KAAG,SAWpE,CAAC"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { createAnimation } from '@ionic/core';
|
|
2
|
+
import { cloneElement } from '../../utils';
|
|
3
|
+
import { ANIMATION_DELAY_CLOSE_BUTTONS, OPACITY_TRANSITION } from '../utils';
|
|
4
|
+
export const createEffectAnimation = (references, sizes) => {
|
|
5
|
+
const effectElement = cloneElement('ion-icon');
|
|
6
|
+
const closeButtonRect = references.closeButtonIcon?.getBoundingClientRect();
|
|
7
|
+
const iconName = references.selectedTabButtonIcon?.getAttribute('name');
|
|
8
|
+
const selectedTabButtonIconRect = references.selectedTabButtonIcon?.getBoundingClientRect();
|
|
9
|
+
return createAnimation()
|
|
10
|
+
.addElement(effectElement)
|
|
11
|
+
.beforeAddWrite(() => {
|
|
12
|
+
effectElement.style.display = 'inline-block';
|
|
13
|
+
references.closeButtonIcon.style.opacity = '0';
|
|
14
|
+
if (iconName && closeButtonRect) {
|
|
15
|
+
effectElement.setAttribute('name', iconName);
|
|
16
|
+
effectElement.style.width = `${closeButtonRect.width}px`;
|
|
17
|
+
effectElement.style.height = `${closeButtonRect.height}px`;
|
|
18
|
+
}
|
|
19
|
+
})
|
|
20
|
+
.afterAddWrite(() => {
|
|
21
|
+
effectElement.style.display = 'none';
|
|
22
|
+
references.closeButtonIcon.style.opacity = '1';
|
|
23
|
+
})
|
|
24
|
+
.fromTo('transform', `translate3d(${selectedTabButtonIconRect.left}px, ${selectedTabButtonIconRect.top}px, 0)`, `translate3d(${closeButtonRect.left}px, ${closeButtonRect.top}px, 0)`);
|
|
25
|
+
};
|
|
26
|
+
export const createSearchContainerAnimation = (references, sizes) => {
|
|
27
|
+
return createAnimation()
|
|
28
|
+
.addElement(references.searchContainer)
|
|
29
|
+
.beforeAddWrite(() => (references.searchContainer.style.transformOrigin = 'right center'))
|
|
30
|
+
.fromTo('transform', `scale(${sizes.fabButton.width / sizes.searchContainer.width}, ${sizes.fabButton.height / sizes.searchContainer.height})`, 'scale(1)')
|
|
31
|
+
.fromTo('opacity', '0.2', '1');
|
|
32
|
+
};
|
|
33
|
+
export const createCloseButtonsAnimation = (references) => {
|
|
34
|
+
return createAnimation()
|
|
35
|
+
.delay(ANIMATION_DELAY_CLOSE_BUTTONS)
|
|
36
|
+
.addElement(references.closeButtons)
|
|
37
|
+
.beforeAddWrite(() => (references.closeButtons.style.transformOrigin = 'left center'))
|
|
38
|
+
.afterClearStyles(['transform', 'transform-origin'])
|
|
39
|
+
.fromTo('transform', 'scale(1.5, 1)', 'scale(1)');
|
|
40
|
+
};
|
|
41
|
+
export const createTabBarAnimation = (ionTabBar, references, sizes) => {
|
|
42
|
+
return createAnimation()
|
|
43
|
+
.addElement(ionTabBar)
|
|
44
|
+
.beforeAddWrite(() => {
|
|
45
|
+
ionTabBar.querySelectorAll('ion-tab-button').forEach((element) => {
|
|
46
|
+
element.style.transition = OPACITY_TRANSITION;
|
|
47
|
+
element.style.opacity = '0';
|
|
48
|
+
});
|
|
49
|
+
references.selectedTabButton.classList.remove('tab-selected');
|
|
50
|
+
const iconName = references.selectedTabButtonIcon?.getAttribute('name');
|
|
51
|
+
if (iconName) {
|
|
52
|
+
references.closeButtonIcon?.setAttribute('name', iconName);
|
|
53
|
+
}
|
|
54
|
+
})
|
|
55
|
+
.afterAddWrite(() => {
|
|
56
|
+
references.selectedTabButton.classList.add('tab-selected');
|
|
57
|
+
ionTabBar.style.pointerEvents = 'none';
|
|
58
|
+
})
|
|
59
|
+
.fromTo('transform', 'scale(1)', `scale(${sizes.closeButton.width / sizes.tabBar.width}, ${sizes.closeButton.height / sizes.tabBar.height})`)
|
|
60
|
+
.fromTo('opacity', '1', '0');
|
|
61
|
+
};
|
|
62
|
+
export const createFabButtonAnimation = (ionFabButton) => {
|
|
63
|
+
return createAnimation()
|
|
64
|
+
.addElement(ionFabButton)
|
|
65
|
+
.beforeAddWrite(() => {
|
|
66
|
+
ionFabButton.style.transformOrigin = 'center right';
|
|
67
|
+
ionFabButton.querySelector('ion-icon')?.style.setProperty('opacity', '0');
|
|
68
|
+
})
|
|
69
|
+
.afterAddWrite(() => {
|
|
70
|
+
ionFabButton.style.pointerEvents = 'none';
|
|
71
|
+
})
|
|
72
|
+
.fromTo('opacity', '1', '0');
|
|
73
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { ElementReferences, ElementSizes } from '../interfaces';
|
|
2
|
+
import { Animation } from '@ionic/core';
|
|
3
|
+
export declare const createReverseEffectAnimation: (references: ElementReferences, searchableElementSizes: ElementSizes, colorSelected: string) => Animation;
|
|
4
|
+
export declare const createReverseSearchContainerAnimation: (references: ElementReferences, sizes: ElementSizes) => Animation;
|
|
5
|
+
export declare const createReverseCloseButtonsAnimation: (references: ElementReferences) => Animation;
|
|
6
|
+
export declare const createReverseTabBarAnimation: (ionTabBar: HTMLElement, references: ElementReferences, sizes: ElementSizes) => Animation;
|
|
7
|
+
export declare const createReverseFabButtonAnimation: (ionFabButton: HTMLElement, references: ElementSizes) => Animation;
|
|
8
|
+
//# sourceMappingURL=leave.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"leave.d.ts","sourceRoot":"","sources":["../../../src/tab-bar-searchable/animations/leave.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAChE,OAAO,EAAE,SAAS,EAAmB,MAAM,aAAa,CAAC;AAIzD,eAAO,MAAM,4BAA4B,GACvC,YAAY,iBAAiB,EAC7B,wBAAwB,YAAY,EACpC,eAAe,MAAM,KACpB,SAyBF,CAAC;AAEF,eAAO,MAAM,qCAAqC,GAAI,YAAY,iBAAiB,EAAE,OAAO,YAAY,KAAG,SAU1G,CAAC;AAEF,eAAO,MAAM,kCAAkC,GAAI,YAAY,iBAAiB,KAAG,SAOlF,CAAC;AAEF,eAAO,MAAM,4BAA4B,GAAI,WAAW,WAAW,EAAE,YAAY,iBAAiB,EAAE,OAAO,YAAY,KAAG,SAiBzH,CAAC;AAEF,eAAO,MAAM,+BAA+B,GAAI,cAAc,WAAW,EAAE,YAAY,YAAY,KAAG,SAYrG,CAAC"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { createAnimation } from '@ionic/core';
|
|
2
|
+
import { cloneElement } from '../../utils';
|
|
3
|
+
import { ANIMATION_DELAY_CLOSE_BUTTONS, OPACITY_TRANSITION } from '../utils';
|
|
4
|
+
export const createReverseEffectAnimation = (references, searchableElementSizes, colorSelected) => {
|
|
5
|
+
const effectElement = cloneElement('ion-icon');
|
|
6
|
+
const closeButtonRect = references.closeButtonIcon?.getBoundingClientRect();
|
|
7
|
+
return createAnimation()
|
|
8
|
+
.addElement(effectElement)
|
|
9
|
+
.beforeAddWrite(() => {
|
|
10
|
+
effectElement.style.display = 'inline-block';
|
|
11
|
+
references.closeButtonIcon.style.opacity = '0';
|
|
12
|
+
if (searchableElementSizes.selectedTabButtonIcon) {
|
|
13
|
+
effectElement.style.width = `${searchableElementSizes.selectedTabButtonIcon.width}px`;
|
|
14
|
+
effectElement.style.height = `${searchableElementSizes.selectedTabButtonIcon.height}px`;
|
|
15
|
+
effectElement.style.color = colorSelected;
|
|
16
|
+
}
|
|
17
|
+
})
|
|
18
|
+
.afterAddWrite(() => {
|
|
19
|
+
effectElement.style.display = 'none';
|
|
20
|
+
references.closeButtonIcon.style.opacity = '1';
|
|
21
|
+
effectElement.style.color = '';
|
|
22
|
+
})
|
|
23
|
+
.fromTo('transform', `translate3d(${closeButtonRect.left}px, ${closeButtonRect.top}px, 0)`, `translate3d(${searchableElementSizes.selectedTabButtonIcon.left}px, ${searchableElementSizes.selectedTabButtonIcon.top}px, 0)`);
|
|
24
|
+
};
|
|
25
|
+
export const createReverseSearchContainerAnimation = (references, sizes) => {
|
|
26
|
+
return createAnimation()
|
|
27
|
+
.addElement(references.searchContainer)
|
|
28
|
+
.beforeAddWrite(() => (references.searchContainer.style.transformOrigin = 'right center'))
|
|
29
|
+
.fromTo('transform', 'scale(1)', `scale(${sizes.fabButton.width / sizes.searchContainer.width}, ${sizes.fabButton.height / sizes.searchContainer.height})`)
|
|
30
|
+
.fromTo('opacity', '1', '0.2');
|
|
31
|
+
};
|
|
32
|
+
export const createReverseCloseButtonsAnimation = (references) => {
|
|
33
|
+
return createAnimation()
|
|
34
|
+
.delay(ANIMATION_DELAY_CLOSE_BUTTONS)
|
|
35
|
+
.addElement(references.closeButtons)
|
|
36
|
+
.beforeAddWrite(() => (references.closeButtons.style.transformOrigin = 'left center'))
|
|
37
|
+
.afterClearStyles(['transform', 'transform-origin'])
|
|
38
|
+
.fromTo('transform', 'scale(1)', 'scale(1.5, 1)');
|
|
39
|
+
};
|
|
40
|
+
export const createReverseTabBarAnimation = (ionTabBar, references, sizes) => {
|
|
41
|
+
return createAnimation()
|
|
42
|
+
.addElement(ionTabBar)
|
|
43
|
+
.beforeAddWrite(() => {
|
|
44
|
+
ionTabBar.style.pointerEvents = 'auto';
|
|
45
|
+
ionTabBar.querySelectorAll('ion-tab-button').forEach((element) => {
|
|
46
|
+
element.style.transition = OPACITY_TRANSITION;
|
|
47
|
+
element.style.opacity = '1';
|
|
48
|
+
});
|
|
49
|
+
})
|
|
50
|
+
.afterClearStyles(['transform', 'opacity'])
|
|
51
|
+
.fromTo('transform', `scale(${sizes.closeButton.width / sizes.tabBar.width}, ${sizes.closeButton.height / sizes.tabBar.height})`, 'scale(1)')
|
|
52
|
+
.fromTo('opacity', '0', '1');
|
|
53
|
+
};
|
|
54
|
+
export const createReverseFabButtonAnimation = (ionFabButton, references) => {
|
|
55
|
+
return createAnimation()
|
|
56
|
+
.addElement(ionFabButton)
|
|
57
|
+
.beforeAddWrite(() => {
|
|
58
|
+
ionFabButton.querySelector('ion-icon')?.style.setProperty('opacity', '1');
|
|
59
|
+
ionFabButton.style.transformOrigin = 'center right';
|
|
60
|
+
})
|
|
61
|
+
.afterAddWrite(() => {
|
|
62
|
+
ionFabButton.style.pointerEvents = 'auto';
|
|
63
|
+
})
|
|
64
|
+
.fromTo('opacity', '0', '1')
|
|
65
|
+
.fromTo('transform', `scale(${references.searchContainer.height / references.fabButton.height})`, 'scale(1)');
|
|
66
|
+
};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { TabBarSearchableFunction } from './interfaces';
|
|
2
|
+
export * from './interfaces';
|
|
3
|
+
export declare const attachTabBarSearchable: (ionTabBar: HTMLElement, ionFabButton: HTMLElement, ionFooter: HTMLElement) => TabBarSearchableFunction;
|
|
4
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tab-bar-searchable/index.ts"],"names":[],"mappings":"AASA,OAAO,EAAwB,wBAAwB,EAAwB,MAAM,cAAc,CAAC;AAgBpG,cAAc,cAAc,CAAC;AAqB7B,eAAO,MAAM,sBAAsB,GACjC,WAAW,WAAW,EACtB,cAAc,WAAW,EACzB,WAAW,WAAW,KACrB,wBAsBF,CAAC"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { createAnimation } from '@ionic/core';
|
|
2
|
+
import { ANIMATION_DELAY_BASE, ANIMATION_DURATION, ANIMATION_EASING, getElementReferences, getElementSizes, throwErrorByFailedClickElement, } from './utils';
|
|
3
|
+
import { TabBarSearchableType } from './interfaces';
|
|
4
|
+
import { createCloseButtonsAnimation, createEffectAnimation, createFabButtonAnimation, createSearchContainerAnimation, createTabBarAnimation, } from './animations/enter';
|
|
5
|
+
import { createReverseCloseButtonsAnimation, createReverseEffectAnimation, createReverseFabButtonAnimation, createReverseSearchContainerAnimation, createReverseTabBarAnimation, } from './animations/leave';
|
|
6
|
+
export * from './interfaces';
|
|
7
|
+
export const attachTabBarSearchable = (ionTabBar, ionFabButton, ionFooter) => {
|
|
8
|
+
if (!ionTabBar || !ionFabButton || !ionFooter) {
|
|
9
|
+
throw new Error('TabBarSearchable should be defined with props');
|
|
10
|
+
}
|
|
11
|
+
ionFooter.style.pointerEvents = 'none';
|
|
12
|
+
ionFooter.style.opacity = '0';
|
|
13
|
+
ionTabBar.style.transformOrigin = 'left center';
|
|
14
|
+
let searchableEventCache;
|
|
15
|
+
return async (event, type) => {
|
|
16
|
+
if (type === TabBarSearchableType.Enter) {
|
|
17
|
+
searchableEventCache = await enterEvent(event, ionTabBar, ionFabButton, ionFooter);
|
|
18
|
+
}
|
|
19
|
+
else if (searchableEventCache !== undefined) {
|
|
20
|
+
await leaveEvent(event, searchableEventCache, ionTabBar, ionFabButton, ionFooter);
|
|
21
|
+
searchableEventCache = undefined;
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
throw new Error('TabBarSearchableType.Leave should be run after TabBarSearchableType.Enter');
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
};
|
|
28
|
+
const enterEvent = async (event, ionTabBar, ionFabButton, ionFooter) => {
|
|
29
|
+
if (!event.target?.closest('ion-fab-button')) {
|
|
30
|
+
throw throwErrorByFailedClickElement('ion-fab-button');
|
|
31
|
+
}
|
|
32
|
+
const references = getElementReferences(ionTabBar, ionFooter);
|
|
33
|
+
const sizes = getElementSizes(ionTabBar, ionFabButton, references);
|
|
34
|
+
const colorSelected = references.selectedTabButton
|
|
35
|
+
? getComputedStyle(references.selectedTabButton).getPropertyValue('--color-selected').trim()
|
|
36
|
+
: '';
|
|
37
|
+
const effectAnimation = createEffectAnimation(references, sizes);
|
|
38
|
+
const searchContainerAnimation = createSearchContainerAnimation(references, sizes);
|
|
39
|
+
const closeButtonsAnimation = createCloseButtonsAnimation(references);
|
|
40
|
+
const tabBarAnimation = createTabBarAnimation(ionTabBar, references, sizes);
|
|
41
|
+
const fabButtonAnimation = createFabButtonAnimation(ionFabButton);
|
|
42
|
+
await createAnimation()
|
|
43
|
+
.delay(ANIMATION_DELAY_BASE)
|
|
44
|
+
.duration(ANIMATION_DURATION)
|
|
45
|
+
.easing(ANIMATION_EASING)
|
|
46
|
+
.addElement(ionFooter)
|
|
47
|
+
.afterAddWrite(() => (ionFooter.style.pointerEvents = 'auto'))
|
|
48
|
+
.fromTo('opacity', '0.8', '1')
|
|
49
|
+
.addAnimation([tabBarAnimation, fabButtonAnimation, searchContainerAnimation, effectAnimation, closeButtonsAnimation])
|
|
50
|
+
.play();
|
|
51
|
+
return {
|
|
52
|
+
elementSizes: sizes,
|
|
53
|
+
colorSelected,
|
|
54
|
+
};
|
|
55
|
+
};
|
|
56
|
+
const leaveEvent = async (event, searchableEventCache, ionTabBar, ionFabButton, ionFooter) => {
|
|
57
|
+
if (!event.target?.closest('ion-buttons[slot=start] ion-button')) {
|
|
58
|
+
throw throwErrorByFailedClickElement('ion-buttons[slot=start] ion-button');
|
|
59
|
+
}
|
|
60
|
+
const references = getElementReferences(ionTabBar, ionFooter);
|
|
61
|
+
const effectAnimation = createReverseEffectAnimation(references, searchableEventCache.elementSizes, searchableEventCache.colorSelected);
|
|
62
|
+
const searchContainerAnimation = createReverseSearchContainerAnimation(references, searchableEventCache.elementSizes);
|
|
63
|
+
const closeButtonsAnimation = createReverseCloseButtonsAnimation(references);
|
|
64
|
+
const tabBarAnimation = createReverseTabBarAnimation(ionTabBar, references, searchableEventCache.elementSizes);
|
|
65
|
+
const fabButtonAnimation = createReverseFabButtonAnimation(ionFabButton, searchableEventCache.elementSizes);
|
|
66
|
+
await createAnimation()
|
|
67
|
+
.delay(ANIMATION_DELAY_BASE)
|
|
68
|
+
.duration(ANIMATION_DURATION)
|
|
69
|
+
.easing(ANIMATION_EASING)
|
|
70
|
+
.addElement(ionFooter)
|
|
71
|
+
.afterAddWrite(() => (ionFooter.style.pointerEvents = 'none'))
|
|
72
|
+
.fromTo('opacity', '1', '0')
|
|
73
|
+
.addAnimation([tabBarAnimation, fabButtonAnimation, searchContainerAnimation, effectAnimation, closeButtonsAnimation])
|
|
74
|
+
.play();
|
|
75
|
+
};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
export declare enum TabBarSearchableType {
|
|
2
|
+
Enter = "enter",
|
|
3
|
+
Leave = "leave"
|
|
4
|
+
}
|
|
5
|
+
export type TabBarSearchableFunction = (event: Event, type: TabBarSearchableType) => Promise<void>;
|
|
6
|
+
export interface SearchableEventCache {
|
|
7
|
+
elementSizes: ElementSizes;
|
|
8
|
+
colorSelected: string;
|
|
9
|
+
}
|
|
10
|
+
export interface ElementSizes {
|
|
11
|
+
tabBar: {
|
|
12
|
+
width: number;
|
|
13
|
+
height: number;
|
|
14
|
+
};
|
|
15
|
+
closeButton: {
|
|
16
|
+
width: number;
|
|
17
|
+
height: number;
|
|
18
|
+
};
|
|
19
|
+
fabButton: {
|
|
20
|
+
width: number;
|
|
21
|
+
height: number;
|
|
22
|
+
};
|
|
23
|
+
searchContainer: {
|
|
24
|
+
width: number;
|
|
25
|
+
height: number;
|
|
26
|
+
};
|
|
27
|
+
selectedTabButtonIcon: {
|
|
28
|
+
width: number;
|
|
29
|
+
height: number;
|
|
30
|
+
top: number;
|
|
31
|
+
left: number;
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
export interface ElementReferences {
|
|
35
|
+
searchContainer: HTMLElement;
|
|
36
|
+
closeButtons: HTMLElement;
|
|
37
|
+
selectedTabButton: HTMLElement;
|
|
38
|
+
selectedTabButtonIcon: HTMLElement;
|
|
39
|
+
closeButtonIcon: HTMLElement;
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=interfaces.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interfaces.d.ts","sourceRoot":"","sources":["../../src/tab-bar-searchable/interfaces.ts"],"names":[],"mappings":"AAAA,oBAAY,oBAAoB;IAC9B,KAAK,UAAU;IACf,KAAK,UAAU;CAChB;AAED,MAAM,MAAM,wBAAwB,GAAG,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,oBAAoB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;AAEnG,MAAM,WAAW,oBAAoB;IACnC,YAAY,EAAE,YAAY,CAAC;IAC3B,aAAa,EAAE,MAAM,CAAC;CACvB;AAGD,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IAC1C,WAAW,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IAC/C,SAAS,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IAC7C,eAAe,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IACnD,qBAAqB,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;CACrF;AAED,MAAM,WAAW,iBAAiB;IAChC,eAAe,EAAE,WAAW,CAAC;IAC7B,YAAY,EAAE,WAAW,CAAC;IAC1B,iBAAiB,EAAE,WAAW,CAAC;IAC/B,qBAAqB,EAAE,WAAW,CAAC;IACnC,eAAe,EAAE,WAAW,CAAC;CAC9B"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { ElementReferences, ElementSizes } from './interfaces';
|
|
2
|
+
export declare const ANIMATION_DURATION = 400;
|
|
3
|
+
export declare const ANIMATION_DELAY_BASE = 140;
|
|
4
|
+
export declare const ANIMATION_DELAY_CLOSE_BUTTONS = 240;
|
|
5
|
+
export declare const ANIMATION_EASING = "cubic-bezier(0, 1, 0.22, 1)";
|
|
6
|
+
export declare const OPACITY_TRANSITION = "opacity 140ms ease";
|
|
7
|
+
export declare const throwErrorByFailedClickElement: (selector: string) => Error;
|
|
8
|
+
export declare const throwErrorByFailedExistElement: (selector: string) => Error;
|
|
9
|
+
export declare const getElement: (docs: HTMLElement, selector: string) => HTMLElement;
|
|
10
|
+
export declare const getElementReferences: (ionTabBar: HTMLElement, ionFooter: HTMLElement) => ElementReferences;
|
|
11
|
+
export declare const getElementSizes: (ionTabBar: HTMLElement, ionFabButton: HTMLElement, references: ElementReferences) => ElementSizes;
|
|
12
|
+
//# sourceMappingURL=utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/tab-bar-searchable/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAE/D,eAAO,MAAM,kBAAkB,MAAM,CAAC;AACtC,eAAO,MAAM,oBAAoB,MAAM,CAAC;AACxC,eAAO,MAAM,6BAA6B,MAAM,CAAC;AACjD,eAAO,MAAM,gBAAgB,gCAAgC,CAAC;AAC9D,eAAO,MAAM,kBAAkB,uBAAuB,CAAC;AAEvD,eAAO,MAAM,8BAA8B,GAAI,UAAU,MAAM,KAAG,KAEjE,CAAC;AAEF,eAAO,MAAM,8BAA8B,GAAI,UAAU,MAAM,KAAG,KAEjE,CAAC;AAEF,eAAO,MAAM,UAAU,GAAI,MAAM,WAAW,EAAE,UAAU,MAAM,KAAG,WAMhE,CAAC;AAEF,eAAO,MAAM,oBAAoB,GAAI,WAAW,WAAW,EAAE,WAAW,WAAW,KAAG,iBA0BrF,CAAC;AAKF,eAAO,MAAM,eAAe,GAAI,WAAW,WAAW,EAAE,cAAc,WAAW,EAAE,YAAY,iBAAiB,KAAG,YAmBlH,CAAC"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
export const ANIMATION_DURATION = 400;
|
|
2
|
+
export const ANIMATION_DELAY_BASE = 140;
|
|
3
|
+
export const ANIMATION_DELAY_CLOSE_BUTTONS = 240;
|
|
4
|
+
export const ANIMATION_EASING = 'cubic-bezier(0, 1, 0.22, 1)';
|
|
5
|
+
export const OPACITY_TRANSITION = 'opacity 140ms ease';
|
|
6
|
+
export const throwErrorByFailedClickElement = (selector) => {
|
|
7
|
+
return new Error('Expected click element to be inside `' + selector + '`');
|
|
8
|
+
};
|
|
9
|
+
export const throwErrorByFailedExistElement = (selector) => {
|
|
10
|
+
return new Error('Expected element `' + selector + '` to exist');
|
|
11
|
+
};
|
|
12
|
+
export const getElement = (docs, selector) => {
|
|
13
|
+
const el = docs.querySelector(selector);
|
|
14
|
+
if (!el) {
|
|
15
|
+
throw throwErrorByFailedClickElement(selector);
|
|
16
|
+
}
|
|
17
|
+
return el;
|
|
18
|
+
};
|
|
19
|
+
export const getElementReferences = (ionTabBar, ionFooter) => {
|
|
20
|
+
const searchContainer = getElement(ionFooter, 'ion-searchbar .searchbar-input-container');
|
|
21
|
+
const closeButtons = getElement(ionFooter, 'ion-buttons[slot=start]');
|
|
22
|
+
const selectedTabButton = ionTabBar.querySelector('ion-tab-button.tab-selected');
|
|
23
|
+
const selectedTabButtonIcon = selectedTabButton?.querySelector('ion-icon');
|
|
24
|
+
const closeButtonIcon = closeButtons.querySelector('ion-icon');
|
|
25
|
+
if (!selectedTabButton) {
|
|
26
|
+
throw throwErrorByFailedExistElement('ion-tab-button.tab-selected');
|
|
27
|
+
}
|
|
28
|
+
if (!selectedTabButtonIcon) {
|
|
29
|
+
throw throwErrorByFailedExistElement('ion-tab-button.tab-selected ion-icon');
|
|
30
|
+
}
|
|
31
|
+
if (!closeButtonIcon) {
|
|
32
|
+
throw throwErrorByFailedExistElement('ion-buttons[slot=start] ion-button ion-icon');
|
|
33
|
+
}
|
|
34
|
+
return {
|
|
35
|
+
searchContainer,
|
|
36
|
+
closeButtons,
|
|
37
|
+
selectedTabButton,
|
|
38
|
+
selectedTabButtonIcon,
|
|
39
|
+
closeButtonIcon,
|
|
40
|
+
};
|
|
41
|
+
};
|
|
42
|
+
export const getElementSizes = (ionTabBar, ionFabButton, references) => {
|
|
43
|
+
const tabBarRect = ionTabBar.getBoundingClientRect();
|
|
44
|
+
const fabButtonRect = ionFabButton.getBoundingClientRect();
|
|
45
|
+
const closeButtonRect = references.closeButtons.getBoundingClientRect();
|
|
46
|
+
const searchContainerRect = references.searchContainer.getBoundingClientRect();
|
|
47
|
+
const selectedTabButtonIconRect = references.selectedTabButtonIcon.getBoundingClientRect();
|
|
48
|
+
return {
|
|
49
|
+
tabBar: { width: tabBarRect.width, height: tabBarRect.height },
|
|
50
|
+
closeButton: { width: closeButtonRect.width, height: closeButtonRect.height },
|
|
51
|
+
fabButton: { width: fabButtonRect.width, height: fabButtonRect.height },
|
|
52
|
+
searchContainer: { width: searchContainerRect.width, height: searchContainerRect.height },
|
|
53
|
+
selectedTabButtonIcon: {
|
|
54
|
+
width: selectedTabButtonIconRect.width,
|
|
55
|
+
height: selectedTabButtonIconRect.height,
|
|
56
|
+
top: selectedTabButtonIconRect.top,
|
|
57
|
+
left: selectedTabButtonIconRect.left,
|
|
58
|
+
},
|
|
59
|
+
};
|
|
60
|
+
};
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { registerEffect } from './sheets-of-glass';
|
|
|
3
3
|
export * from './sheets-of-glass/interfaces';
|
|
4
4
|
export { iosEnterAnimation as popoverEnterAnimation } from './popover/animations/ios.enter';
|
|
5
5
|
export { iosLeaveAnimation as popoverLeaveAnimation } from './popover/animations/ios.leave';
|
|
6
|
+
export * from './tab-bar-searchable';
|
|
6
7
|
|
|
7
8
|
export const registerTabBarEffect = (targetElement: HTMLElement): registeredEffect | undefined => {
|
|
8
9
|
return registerEffect(targetElement, 'ion-tab-button', 'tab-selected', {
|