diff --git a/packages/core/src/components/popover/animations/ios.enter.ts b/packages/core/src/components/popover/animations/ios.enter.ts
index 76bd7f8047..ed533233d7 100644
--- a/packages/core/src/components/popover/animations/ios.enter.ts
+++ b/packages/core/src/components/popover/animations/ios.enter.ts
@@ -10,16 +10,11 @@ export default function(Animation: Animation, baseElm: HTMLElement) {
const backdropAnimation = new Animation();
backdropAnimation.addElement(baseElm.querySelector('.popover-backdrop'));
- const wrapperAnimation = new Animation();
- wrapperAnimation.addElement(baseElm.querySelector('.popover-wrapper'));
-
- wrapperAnimation.fromTo('opacity', 0.01, 1);
backdropAnimation.fromTo('opacity', 0.01, 0.08);
return baseAnimation
.addElement(baseElm)
.easing('ease')
.duration(100)
- .add(backdropAnimation)
- .add(wrapperAnimation);
+ .add(backdropAnimation);
}
diff --git a/packages/core/src/components/popover/popover.tsx b/packages/core/src/components/popover/popover.tsx
index db279b5982..c4854c07b1 100644
--- a/packages/core/src/components/popover/popover.tsx
+++ b/packages/core/src/components/popover/popover.tsx
@@ -52,92 +52,127 @@ export class Popover {
}
- // TODO currently only positions iOS
- private positionView(nativeEle: HTMLElement, ev: any, mode: string) {
- // Default to material design mode unless mode is ios
- const popoverMode = (mode === 'ios') ? mode : 'md';
- const popoverProps = popoverViewProps[popoverMode];
- const popoverPadding = popoverProps.bodyPadding;
+ private positionPopover(nativeEl: HTMLElement, ev: any, props: any) {
+ console.debug('Position popover', nativeEl, ev, props);
// Declare the popover elements
- let popoverWrapperEle = nativeEle.querySelector('.popover-wrapper') as HTMLElement;
- let popoverContentEle = nativeEle.querySelector('.popover-content') as HTMLElement;
- let popoverArrowEle = nativeEle.querySelector('.popover-arrow') as HTMLElement;
+ let contentEl = nativeEl.querySelector('.popover-content') as HTMLElement;
+ let arrowEl = nativeEl.querySelector('.popover-arrow') as HTMLElement;
- // Grab the default origin from the properties
- let originY = 'top';
- let originX = 'left';
+ // Set the default transform origin direction
+ let origin = {
+ y: 'top',
+ x: 'left'
+ }
// Popover content width and height
- let popoverDim = popoverContentEle.getBoundingClientRect();
- let popoverWidth = popoverDim.width;
- let popoverHeight = popoverDim.height;
+ const popover = {
+ width: contentEl.getBoundingClientRect().width,
+ height: contentEl.getBoundingClientRect().height
+ }
// Window body width and height
// TODO need to check if portrait/landscape?
- let bodyWidth = window.screen.width;
- let bodyHeight = window.screen.height;
+ const body = {
+ width: window.screen.width,
+ height: window.screen.height
+ }
// If ev was passed, use that for target element
let targetDim = ev && ev.target && ev.target.getBoundingClientRect();
- let targetTop = (targetDim && 'top' in targetDim) ? targetDim.top : (bodyHeight / 2) - (popoverHeight / 2);
- let targetLeft = (targetDim && 'left' in targetDim) ? targetDim.left : (bodyWidth / 2);
- let targetWidth = targetDim && targetDim.width || 0;
- let targetHeight = targetDim && targetDim.height || 0;
+ // The target is the object that dispatched the event that was passed
+ let target = {
+ top: (targetDim && 'top' in targetDim) ? targetDim.top : (body.height / 2) - (popover.height / 2),
+ left: (targetDim && 'left' in targetDim) ? targetDim.left : (body.width / 2) - (popover.width / 2),
+ width: targetDim && targetDim.width || 0,
+ height: targetDim && targetDim.height || 0
+ };
+
+ // If the popover should be centered to the target
+ if (props.centerTarget) {
+ target.left = (targetDim && 'left' in targetDim) ? targetDim.left : (body.width / 2);
+ }
// The arrow that shows above the popover on iOS
- let arrowDim = popoverArrowEle.getBoundingClientRect();
- var arrowWidth = arrowDim.width;
- var arrowHeight = arrowDim.height;
+ let arrowDim = arrowEl.getBoundingClientRect();
+
+ const arrow = {
+ width: arrowDim.width,
+ height: arrowDim.height
+ }
// If no ev was passed, hide the arrow
if (!targetDim) {
- popoverArrowEle.style.display = 'none';
+ arrowEl.style.display = 'none';
}
let arrowCSS = {
- top: targetTop + targetHeight,
- left: targetLeft + (targetWidth / 2) - (arrowWidth / 2)
+ top: target.top + target.height,
+ left: target.left + (target.width / 2) - (arrow.width / 2)
};
let popoverCSS = {
- top: targetTop + targetHeight + (arrowHeight - 1),
- left: targetLeft + (targetWidth / 2) - (popoverWidth / 2)
+ top: target.top + target.height + (arrow.height - 1),
+ left: target.left
};
+ // If the popover should be centered to the target
+ if (props.centerTarget) {
+ popoverCSS.left = target.left + (target.width / 2) - (popover.width / 2)
+ }
+
// If the popover left is less than the padding it is off screen
// to the left so adjust it, else if the width of the popover
// exceeds the body width it is off screen to the right so adjust
- if (popoverCSS.left < popoverPadding) {
- popoverCSS.left = popoverPadding;
- } else if (popoverWidth + popoverPadding + popoverCSS.left > bodyWidth) {
- popoverCSS.left = bodyWidth - popoverWidth - popoverPadding;
- originX = 'right';
+ if (popoverCSS.left < props.padding) {
+ popoverCSS.left = props.padding;
+ } else if (popover.width + props.padding + popoverCSS.left > body.width) {
+ popoverCSS.left = body.width - popover.width - props.padding;
+ origin.x = 'right';
}
// If the popover when popped down stretches past bottom of screen,
// make it pop up if there's room above
- if (targetTop + targetHeight + popoverHeight > bodyHeight && targetTop - popoverHeight > 0) {
- arrowCSS.top = targetTop - (arrowHeight + 1);
- popoverCSS.top = targetTop - popoverHeight - (arrowHeight - 1);
- nativeEle.className = nativeEle.className + ' popover-bottom';
- originY = 'bottom';
- // If there isn't room for it to pop up above the target cut it off
- } else if (targetTop + targetHeight + popoverHeight > bodyHeight) {
- popoverContentEle.style.bottom = popoverPadding + '%';
+ if (this.showFromBottom(target, popover, body)) {
+ nativeEl.className = nativeEl.className + ' popover-bottom';
+ origin.y = 'bottom';
+
+ popoverCSS.top = target.top - popover.height;
+
+ if (props.showArrow) {
+ arrowCSS.top = target.top - (arrow.height + 1);
+ popoverCSS.top = target.top - popover.height - (arrow.height - 1);
+ }
+
+ // If the popover exceeds the viewport then cut the bottom off
+ } else if (this.exceedsViewport(target, popover, body)) {
+ contentEl.style.bottom = props.padding + props.unit;
}
- popoverArrowEle.style.top = arrowCSS.top + 'px';
- popoverArrowEle.style.left = arrowCSS.left + 'px';
+ arrowEl.style.top = arrowCSS.top + 'px';
+ arrowEl.style.left = arrowCSS.left + 'px';
- popoverContentEle.style.top = popoverCSS.top + 'px';
- popoverContentEle.style.left = popoverCSS.left + 'px';
+ contentEl.style.top = popoverCSS.top + 'px';
+ contentEl.style.left = popoverCSS.left + 'px';
- popoverContentEle.style.transformOrigin = originY + ' ' + originX;
+ contentEl.style.transformOrigin = origin.y + ' ' + origin.x;
// Since the transition starts before styling is done we
// want to wait for the styles to apply before showing the wrapper
+ this.displayWrapper();
+ }
+
+ private showFromBottom(target: any, popover: any, body: any): boolean {
+ return target.top + target.height + popover.height > body.height && target.top - popover.height > 0;
+ }
+
+ private exceedsViewport(target: any, popover: any, body: any): boolean {
+ return target.top + target.height + popover.height > body.height;
+ }
+
+ private displayWrapper() {
+ let popoverWrapperEle = this.el.querySelector('.popover-wrapper') as HTMLElement;
popoverWrapperEle.style.opacity = '1';
}
@@ -164,7 +199,7 @@ export class Popover {
animation.onFinish((a: any) => {
a.destroy();
this.ionViewDidEnter();
- this.positionView(this.el, this.ev, this.mode);
+ this.positionPopover(this.el, this.ev, POPOVER_POSITION_PROPERTIES[this.mode]);
resolve();
}).play();
});
@@ -279,16 +314,23 @@ export interface PopoverEvent {
};
}
-export const popoverViewProps: any = {
+export const POPOVER_POSITION_PROPERTIES: any = {
ios: {
- bodyPadding: 2,
- showArrow: true
+ padding: 2,
+ unit: '%',
+ showArrow: true,
+ centerTarget: true
},
md: {
- bodyPadding: 12,
- showArrow: false
+ padding: 12,
+ unit: 'px',
+ showArrow: false,
+ centerTarget: false
+ },
+ wp: {
+ padding: 12,
+ unit: 'px',
+ showArrow: false,
+ centerTarget: false
}
}
-
-// TODO FIX
-const POPOVER_MD_BODY_PADDING = 12;
diff --git a/packages/core/src/components/popover/test/basic.html b/packages/core/src/components/popover/test/basic.html
index 36f3fed4e4..e3d35987aa 100644
--- a/packages/core/src/components/popover/test/basic.html
+++ b/packages/core/src/components/popover/test/basic.html
@@ -26,6 +26,17 @@
+
+
+
+
+
+
+
+
+ Popover
+
+