From 794d08221810860b58a39ce58e3f899caecaf4d3 Mon Sep 17 00:00:00 2001 From: jlukic Date: Thu, 4 Jun 2015 18:03:00 -0400 Subject: [PATCH 1/3] Begin rewrite of popup calcs to cache correctly on each position check --- src/definitions/modules/popup.js | 227 ++++++++++++++++++------------- 1 file changed, 134 insertions(+), 93 deletions(-) diff --git a/src/definitions/modules/popup.js b/src/definitions/modules/popup.js index 5024cde80..f8f7da46b 100644 --- a/src/definitions/modules/popup.js +++ b/src/definitions/modules/popup.js @@ -59,6 +59,7 @@ $.fn.popup = function(parameters) { searchDepth = 0, triedPositions = false, + openedWithTouch = false, element = this, instance = $module.data(moduleNamespace), @@ -166,10 +167,24 @@ $.fn.popup = function(parameters) { clearTimeout(module.showTimer); module.hideTimer = setTimeout(module.hide, delay); }, + touchstart: function(event) { + openedWithTouch = true; + module.event.start(); + }, resize: function() { if( module.is.visible() ) { module.set.position(); } + }, + hideGracefully: function(event) { + // don't close on clicks inside popup + if(event && $(event.target).closest(selector.popup).length === 0) { + module.debug('Click occurred outside popup hiding popup'); + module.hide(); + } + else { + module.debug('Click was inside popup, keeping popup open'); + } } }, @@ -312,18 +327,6 @@ $.fn.popup = function(parameters) { }) ; }, - - hideGracefully: function(event) { - // don't close on clicks inside popup - if(event && $(event.target).closest(selector.popup).length === 0) { - module.debug('Click occurred outside popup hiding popup'); - module.hide(); - } - else { - module.debug('Click was inside popup, keeping popup open'); - } - }, - exists: function() { if(!$popup) { return false; @@ -438,15 +441,51 @@ $.fn.popup = function(parameters) { $module.removeData(metadata.variation); return $module.data(metadata.variation) || settings.variation; }, + sizes: function() { + var + targetElement = $target[0], + sizes = {} + ; + // grab position + sizes.target = (settings.inline || settings.popup) + ? $target.position() + : $target.offset() + ; + sizes = { + target: { + element : $target[0], + width : $target.outerWidth(), + height : $target.outerHeight(), + margin : {} + }, + popup: { + width: $popup.outerWidth(), + height: $popup.outerHeight() + }, + parent: { + width: $offsetParent.outerWidth(), + height: $offsetParent.outerHeight() + } + }; + + sizes.target.margin.top = (settings.inline) + ? parseInt( window.getComputedStyle(targetElement).getPropertyValue('margin-top'), 10) + : 0 + ; + sizes.target.margin.left = (settings.inline) + ? module.is.rtl() + ? parseInt( window.getComputedStyle(targetElement).getPropertyValue('margin-right'), 10) + : parseInt( window.getComputedStyle(targetElement).getPropertyValue('margin-left') , 10) + : 0 + ; + return sizes; + }, id: function() { return id; }, startEvent: function() { if(settings.on == 'hover') { - return (hasTouch && settings.addTouchEvents) - ? 'touchstart mouseenter' - : 'mouseenter' - ; + return 'mouseenter'; } else if(settings.on == 'focus') { return 'focus'; @@ -454,10 +493,7 @@ $.fn.popup = function(parameters) { return false; }, scrollEvent: function() { - return (hasTouch && settings.addTouchEvents) - ? 'touchmove scroll' - : 'scroll' - ; + return 'scroll'; }, endEvent: function() { if(settings.on == 'hover') { @@ -510,8 +546,8 @@ $.fn.popup = function(parameters) { right : screen.left + screen.width }, popup = { - width : $popup.width(), - height : $popup.height(), + width : $popup.outerWidth(), + height : $popup.outerHeight(), offset : $popup.offset() }, offstage = {}, @@ -610,7 +646,7 @@ $.fn.popup = function(parameters) { }, set: { - position: function(position, arrowOffset) { + position: function(position, sizes) { // exit conditions if($target.length === 0 || $popup.length === 0) { @@ -618,140 +654,125 @@ $.fn.popup = function(parameters) { return; } var - windowWidth = $(window).width(), - windowHeight = $(window).height(), - - targetWidth = $target.outerWidth(), - targetHeight = $target.outerHeight(), - - popupWidth = $popup.outerWidth(), - popupHeight = $popup.outerHeight(), - - parentWidth = $offsetParent.outerWidth(), - parentHeight = $offsetParent.outerHeight(), - - distanceAway = settings.distanceAway, - - targetElement = $target[0], - - marginTop = (settings.inline) - ? parseInt( window.getComputedStyle(targetElement).getPropertyValue('margin-top'), 10) - : 0, - marginLeft = (settings.inline) - ? module.is.rtl() - ? parseInt( window.getComputedStyle(targetElement).getPropertyValue('margin-right'), 10) - : parseInt( window.getComputedStyle(targetElement).getPropertyValue('margin-left') , 10) - : 0, - - target = (settings.inline || settings.popup) - ? $target.position() - : $target.offset(), - + offset, + distanceAway, + target, + popup, + parent, computedPosition, positioning, offstagePosition ; - position = position || $module.data(metadata.position) || settings.position; - arrowOffset = arrowOffset || $module.data(metadata.offset) || settings.offset; + sizes = sizes || module.get.sizes(); + position = position || $module.data(metadata.position) || settings.position; + + offset = $module.data(metadata.offset) || settings.offset; + distanceAway = settings.distanceAway; + + // shorthand + target = sizes.target; + popup = sizes.popup; + parent = sizes.parent; if(target.top === 0 && target.left === 0) { module.debug('Popup target is hidden, no action taken'); return false; } - if(searchDepth == settings.maxSearchDepth && settings.lastResort) { - module.debug('Using last resort position to display', settings.lastResort); - position = settings.lastResort; - } - if(settings.inline) { module.debug('Adding targets margin to calculation'); if(position == 'left center' || position == 'right center') { - arrowOffset += marginTop; - distanceAway += -marginLeft; + offset += target.margin.top; + distanceAway += -target.margin.left; } else if (position == 'top left' || position == 'top center' || position == 'top right') { - arrowOffset += marginLeft; - distanceAway -= marginTop; + offset += target.margin.left; + distanceAway -= target.margin.top; } else { - arrowOffset += marginLeft; - distanceAway += marginTop; + offset += target.margin.left; + distanceAway += target.margin.top; } } + module.debug('Calculating popup positioning', position); - computedPosition = position; if (module.is.rtl()) { - computedPosition = computedPosition.replace(/left|right/g, function (match) { + position = position.replace(/left|right/g, function (match) { return (match == 'left') ? 'right' : 'left' ; }); - module.debug('RTL: Popup positioning updated', computedPosition); + module.debug('RTL: Popup positioning updated', position); + } + + if(searchDepth == settings.maxSearchDepth && settings.lastResort) { + module.debug('Using last resort position to display', settings.lastResort); + position = settings.lastResort; } - switch (computedPosition) { + + switch (position) { case 'top left': positioning = { top : 'auto', - bottom : parentHeight - target.top + distanceAway, - left : target.left + arrowOffset, + bottom : parent.height - target.top + distanceAway, + left : target.left + offset, right : 'auto' }; break; case 'top center': positioning = { - bottom : parentHeight - target.top + distanceAway, - left : target.left + (targetWidth / 2) - (popupWidth / 2) + arrowOffset, + bottom : parent.height - target.top + distanceAway, + left : target.left + (target.width / 2) - (popup.width / 2) + offset, top : 'auto', right : 'auto' }; break; case 'top right': positioning = { - bottom : parentHeight - target.top + distanceAway, - right : parentWidth - target.left - targetWidth - arrowOffset, + bottom : parent.height - target.top + distanceAway, + right : parent.width - target.left - target.width - offset, top : 'auto', left : 'auto' }; break; case 'left center': positioning = { - top : target.top + (targetHeight / 2) - (popupHeight / 2) + arrowOffset, - right : parentWidth - target.left + distanceAway, + top : target.top + (target.height / 2) - (popup.height / 2) + offset, + right : parent.width - target.left + distanceAway, left : 'auto', bottom : 'auto' }; break; case 'right center': positioning = { - top : target.top + (targetHeight / 2) - (popupHeight / 2) + arrowOffset, - left : target.left + targetWidth + distanceAway, + top : target.top + (target.height / 2) - (popup.height / 2) + offset, + left : target.left + target.width + distanceAway, bottom : 'auto', right : 'auto' }; break; case 'bottom left': positioning = { - top : target.top + targetHeight + distanceAway, - left : target.left + arrowOffset, + top : target.top + target.height + distanceAway, + left : target.left + offset, bottom : 'auto', right : 'auto' }; break; case 'bottom center': positioning = { - top : target.top + targetHeight + distanceAway, - left : target.left + (targetWidth / 2) - (popupWidth / 2) + arrowOffset, + top : target.top + target.height + distanceAway, + left : target.left + (target.width / 2) - (popup.width / 2) + offset, bottom : 'auto', right : 'auto' }; break; case 'bottom right': positioning = { - top : target.top + targetHeight + distanceAway, - right : parentWidth - target.left - targetWidth - arrowOffset, + top : target.top + target.height + distanceAway, + right : parent.width - target.left - target.width - offset, left : 'auto', bottom : 'auto' }; @@ -781,7 +802,7 @@ $.fn.popup = function(parameters) { position = module.get.nextPosition(position); module.debug('Trying new position', position); return ($popup) - ? module.set.position(position) + ? module.set.position(position, sizes) : false ; } @@ -835,6 +856,11 @@ $.fn.popup = function(parameters) { .on('click' + eventNamespace, module.toggle) ; } + if(settings.on == 'hover' && hasTouch) { + $module + .on('touchstart' + eventNamespace, module.event.touchstart) + ; + } else if( module.get.startEvent() ) { $module .on(module.get.startEvent() + eventNamespace, module.event.start) @@ -855,21 +881,30 @@ $.fn.popup = function(parameters) { ; } }, - close:function() { - if(settings.hideOnScroll === true || settings.hideOnScroll == 'auto' && settings.on != 'click') { + close: function() { + if(settings.hideOnScroll === true || (settings.hideOnScroll == 'auto' && settings.on != 'click')) { $document - .one(module.get.scrollEvent() + elementNamespace, module.hideGracefully) + .one(module.get.scrollEvent() + elementNamespace, module.event.hideGracefully) ; $context - .one(module.get.scrollEvent() + elementNamespace, module.hideGracefully) + .one(module.get.scrollEvent() + elementNamespace, module.event.hideGracefully) + ; + } + if(settings.on == 'hover' && openedWithTouch) { + module.verbose('Binding popup close event to document'); + $document + .on('touchstart' + elementNamespace, function(event) { + module.verbose('Touched away from popup'); + module.event.hideGracefully.call(element, event); + }) ; } if(settings.on == 'click' && settings.closable) { module.verbose('Binding popup close event to document'); $document .on('click' + elementNamespace, function(event) { - module.verbose('Pop-up clickaway intent detected'); - module.hideGracefully.call(element, event); + module.verbose('Clicked away from popup'); + module.event.hideGracefully.call(element, event); }) ; } @@ -878,7 +913,7 @@ $.fn.popup = function(parameters) { unbind: { close: function() { - if(settings.hideOnScroll === true || settings.hideOnScroll == 'auto' && settings.on != 'click') { + if(settings.hideOnScroll === true || (settings.hideOnScroll == 'auto' && settings.on != 'click')) { $document .off('scroll' + elementNamespace, module.hide) ; @@ -886,6 +921,12 @@ $.fn.popup = function(parameters) { .off('scroll' + elementNamespace, module.hide) ; } + if(settings.on == 'hover' && openedWithTouch) { + $document + .off('touchstart' + elementNamespace) + ; + openedWithTouch = false; + } if(settings.on == 'click' && settings.closable) { module.verbose('Removing close event from document'); $document From d4aa9623d7e580158193d367536bba0370c9dfc1 Mon Sep 17 00:00:00 2001 From: jlukic Date: Fri, 5 Jun 2015 11:50:40 -0400 Subject: [PATCH 2/3] Finish popup rewrite --- src/definitions/modules/popup.js | 137 ++++++++++++++++--------------- 1 file changed, 72 insertions(+), 65 deletions(-) diff --git a/src/definitions/modules/popup.js b/src/definitions/modules/popup.js index f8f7da46b..945db8c53 100644 --- a/src/definitions/modules/popup.js +++ b/src/definitions/modules/popup.js @@ -17,6 +17,8 @@ $.fn.popup = function(parameters) { var $allModules = $(this), $document = $(document), + $window = $(window), + $body = $('body'), moduleSelector = $allModules.selector || '', @@ -52,8 +54,6 @@ $.fn.popup = function(parameters) { ? $(settings.target) : $module, - $window = $(window), - $body = $('body'), $popup, $offsetParent, @@ -277,7 +277,7 @@ $.fn.popup = function(parameters) { }, show: function(callback) { - callback = $.isFunction(callback) ? callback : function(){}; + callback = callback || function(){}; module.debug('Showing pop-up', settings.transition); if(module.is.hidden() && !( module.is.active() && module.is.dropdown()) ) { @@ -303,7 +303,7 @@ $.fn.popup = function(parameters) { hide: function(callback) { - callback = $.isFunction(callback) ? callback : function(){}; + callback = callback || function(){}; if( module.is.visible() || module.is.animating() ) { if(settings.onHide.call($popup, element) === false) { module.debug('onHide callback returned false, cancelling popup animation'); @@ -441,44 +441,60 @@ $.fn.popup = function(parameters) { $module.removeData(metadata.variation); return $module.data(metadata.variation) || settings.variation; }, - sizes: function() { + calculations: function() { var - targetElement = $target[0], - sizes = {} + targetElement = $target[0], + targetPosition = (settings.inline || settings.popup) + ? $target.position() + : $target.offset(), + calculations = {} ; - // grab position - sizes.target = (settings.inline || settings.popup) - ? $target.position() - : $target.offset() - ; - sizes = { - target: { + calculations = { + // element which is launching popup + target : { element : $target[0], width : $target.outerWidth(), height : $target.outerHeight(), + top : targetPosition.top, + left : targetPosition.left, margin : {} }, - popup: { - width: $popup.outerWidth(), - height: $popup.outerHeight() + // popup itself + popup : { + width : $popup.outerWidth(), + height : $popup.outerHeight() + }, + // offset container (or 3d context) + parent : { + width : $offsetParent.outerWidth(), + height : $offsetParent.outerHeight() + }, + // screen boundaries + screen : { + top : $window.scrollTop(), + left : $window.scrollLeft(), + width : $body.width(), + height : $body.height() + }, + boundary: { + top : screen.top, + bottom : screen.top + screen.height, + left : screen.left, + right : screen.left + screen.width }, - parent: { - width: $offsetParent.outerWidth(), - height: $offsetParent.outerHeight() - } }; - - sizes.target.margin.top = (settings.inline) + // add in margins if inline + calculations.target.margin.top = (settings.inline) ? parseInt( window.getComputedStyle(targetElement).getPropertyValue('margin-top'), 10) : 0 ; - sizes.target.margin.left = (settings.inline) + calculations.target.margin.left = (settings.inline) ? module.is.rtl() ? parseInt( window.getComputedStyle(targetElement).getPropertyValue('margin-right'), 10) : parseInt( window.getComputedStyle(targetElement).getPropertyValue('margin-left') , 10) : 0 ; - return sizes; + return calculations; }, id: function() { return id; @@ -531,37 +547,28 @@ $.fn.popup = function(parameters) { : $() ; }, - offstagePosition: function(position) { + offstagePosition: function(position, calculations) { var - screen = { - top : $(window).scrollTop(), - left : $(window).scrollLeft(), - width : $(window).width(), - height : $(window).height() - }, - boundary = { - top : screen.top, - bottom : screen.top + screen.height, - left : screen.left, - right : screen.left + screen.width - }, - popup = { - width : $popup.outerWidth(), - height : $popup.outerHeight(), - offset : $popup.offset() - }, - offstage = {}, - offstagePositions = [] + offset = $popup.offset(), + offstage = {}, + offstagePositions = [], + popup, + boundary ; - position = position || false; - if(popup.offset && position) { - module.verbose('Checking if outside viewable area', popup.offset); + position = position || false; + calculations = calculations || module.get.calculations(); + // shorthand + popup = calculations.popup; + boundary = calculations.boundary; + + if(offset && position) { offstage = { - top : (popup.offset.top < boundary.top), - bottom : (popup.offset.top + popup.height > boundary.bottom), - right : (popup.offset.left + popup.width > boundary.right), - left : (popup.offset.left < boundary.left) + top : (offset.top < boundary.top), + bottom : (offset.top + popup.height > boundary.bottom), + right : (offset.left + popup.width > boundary.right), + left : (offset.left < boundary.left) }; + module.verbose('Offstage positions determined', offset, offstage); } // return only boundaries that have been surpassed $.each(offstage, function(direction, isOffstage) { @@ -646,7 +653,7 @@ $.fn.popup = function(parameters) { }, set: { - position: function(position, sizes) { + position: function(position, calculations) { // exit conditions if($target.length === 0 || $popup.length === 0) { @@ -663,16 +670,16 @@ $.fn.popup = function(parameters) { positioning, offstagePosition ; - sizes = sizes || module.get.sizes(); - position = position || $module.data(metadata.position) || settings.position; + calculations = calculations || module.get.calculations(); + position = position || $module.data(metadata.position) || settings.position; offset = $module.data(metadata.offset) || settings.offset; distanceAway = settings.distanceAway; // shorthand - target = sizes.target; - popup = sizes.popup; - parent = sizes.parent; + target = calculations.target; + popup = calculations.popup; + parent = calculations.parent; if(target.top === 0 && target.left === 0) { module.debug('Popup target is hidden, no action taken'); @@ -680,9 +687,9 @@ $.fn.popup = function(parameters) { } if(settings.inline) { - module.debug('Adding targets margin to calculation'); + module.debug('Adding margin to calculation', target.margin); if(position == 'left center' || position == 'right center') { - offset += target.margin.top; + offset += target.margin.top; distanceAway += -target.margin.left; } else if (position == 'top left' || position == 'top center' || position == 'top right') { @@ -695,7 +702,7 @@ $.fn.popup = function(parameters) { } } - module.debug('Calculating popup positioning', position); + module.debug('Determining popup position from calculations', position, calculations); if (module.is.rtl()) { position = position.replace(/left|right/g, function (match) { @@ -704,11 +711,11 @@ $.fn.popup = function(parameters) { : 'left' ; }); - module.debug('RTL: Popup positioning updated', position); + module.debug('RTL: Popup position updated', position); } if(searchDepth == settings.maxSearchDepth && settings.lastResort) { - module.debug('Using last resort position to display', settings.lastResort); + module.debug('Using "last resort" position to display', settings.lastResort); position = settings.lastResort; } @@ -792,7 +799,7 @@ $.fn.popup = function(parameters) { .addClass(className.loading) ; // check if is offstage - offstagePosition = module.get.offstagePosition(position); + offstagePosition = module.get.offstagePosition(position, calculations); // recursively find new positioning if(offstagePosition) { @@ -802,7 +809,7 @@ $.fn.popup = function(parameters) { position = module.get.nextPosition(position); module.debug('Trying new position', position); return ($popup) - ? module.set.position(position, sizes) + ? module.set.position(position, calculations) : false ; } From b0f400fbc2ea691055663e150f76dfd3311aa4f5 Mon Sep 17 00:00:00 2001 From: jlukic Date: Fri, 5 Jun 2015 12:48:28 -0400 Subject: [PATCH 3/3] Finish popup rewrite --- src/definitions/modules/popup.js | 65 +++++++++++++++++++----------- src/definitions/modules/popup.less | 38 ++++++++++++++--- 2 files changed, 73 insertions(+), 30 deletions(-) diff --git a/src/definitions/modules/popup.js b/src/definitions/modules/popup.js index 945db8c53..a8de7c7f3 100644 --- a/src/definitions/modules/popup.js +++ b/src/definitions/modules/popup.js @@ -447,7 +447,8 @@ $.fn.popup = function(parameters) { targetPosition = (settings.inline || settings.popup) ? $target.position() : $target.offset(), - calculations = {} + calculations = {}, + screen ; calculations = { // element which is launching popup @@ -471,18 +472,15 @@ $.fn.popup = function(parameters) { }, // screen boundaries screen : { - top : $window.scrollTop(), - left : $window.scrollLeft(), - width : $body.width(), - height : $body.height() - }, - boundary: { - top : screen.top, - bottom : screen.top + screen.height, - left : screen.left, - right : screen.left + screen.width - }, + scroll: { + top : $window.scrollTop(), + left : $window.scrollLeft() + }, + width : $window.width(), + height : $window.height() + } }; + // add in margins if inline calculations.target.margin.top = (settings.inline) ? parseInt( window.getComputedStyle(targetElement).getPropertyValue('margin-top'), 10) @@ -494,6 +492,14 @@ $.fn.popup = function(parameters) { : parseInt( window.getComputedStyle(targetElement).getPropertyValue('margin-left') , 10) : 0 ; + // calculate screen boundaries + screen = calculations.screen; + calculations.boundary = { + top : screen.scroll.top, + bottom : screen.scroll.top + screen.height, + left : screen.scroll.left, + right : screen.scroll.left + screen.width + }; return calculations; }, id: function() { @@ -825,14 +831,15 @@ $.fn.popup = function(parameters) { module.debug('Position is on stage', position); module.remove.attempts(); - module.set.fluidWidth(); + module.set.fluidWidth(calculations); module.remove.loading(); return true; }, - fluidWidth: function() { + fluidWidth: function(calculations) { + calculations = calculations || module.get.calculations(); if( settings.setFluidWidth && $popup.hasClass(className.fluid) ) { - $popup.css('width', $offsetParent.width()); + $popup.css('width', calculations.parent.width); } }, @@ -1171,14 +1178,19 @@ $.fn.popup.settings = { // callback only when element added to dom onCreate : function(){}, + // callback before element removed from dom onRemove : function(){}, + // callback before show animation onShow : function(){}, + // callback after show animation onVisible : function(){}, + // callback before hide animation onHide : function(){}, + // callback after hide animation onHidden : function(){}, @@ -1190,36 +1202,49 @@ $.fn.popup.settings = { // default position relative to element position : 'top left', + // name of variation to use variation : '', + // whether popup should be moved to context movePopup : true, + // element which popup should be relative to target : false, + // jq selector or element that should be used as popup popup : false, + // popup should remain inline next to activator inline : false, + // popup should be removed from page on hide preserve : false, + // popup should not close when being hovered on hoverable : false, // explicitly set content content : false, + // explicitly set html html : false, + // explicitly set title title : false, // whether automatically close on clickaway when on click closable : true, + // automatically hide on scroll hideOnScroll : 'auto', + // hide other popups on show exclusive : false, + // context to attach popups context : 'body', + // position to prefer when calculating new position prefer : 'opposite', @@ -1235,7 +1260,6 @@ $.fn.popup.settings = { // whether fluid variation should assign width explicitly setFluidWidth : true, - // transition settings duration : 200, transition : 'scale', @@ -1246,7 +1270,7 @@ $.fn.popup.settings = { // offset on aligning axis from calculated position offset : 0, - // maximum times to look for a position before failing + // maximum times to look for a position before failing (9 positions total) maxSearchDepth : 20, error: { @@ -1325,12 +1349,5 @@ $.fn.popup.settings = { }; -// Adds easing -$.extend( $.easing, { - easeOutQuad: function (x, t, b, c, d) { - return -c *(t/=d)*(t-2) + b; - } -}); - })( jQuery, window , document ); diff --git a/src/definitions/modules/popup.less b/src/definitions/modules/popup.less index 6b077b8a2..65b560aea 100755 --- a/src/definitions/modules/popup.less +++ b/src/definitions/modules/popup.less @@ -82,17 +82,43 @@ .ui.popup { margin: 0em; } -.ui.popup.bottom { - margin: @popupDistanceAway 0em 0em; -} -.ui.popup.top { + +/* Extending from Top */ +.ui.top.popup { margin: 0em 0em @popupDistanceAway; } -.ui.popup.left.center { +.ui.top.left.popup { + transform-origin: bottom left; +} +.ui.top.center.popup { + transform-origin: bottom center; +} +.ui.top.right.popup { + transform-origin: bottom right; +} + +/* Extending from Vertical Center */ +.ui.left.center.popup { margin: 0em @popupDistanceAway 0em 0em; + transform-origin: right 50%; } -.ui.popup.right.center { +.ui.right.center.popup { margin: 0em 0em 0em @popupDistanceAway; + transform-origin: left 50%; +} + +/* Extending from Bottom */ +.ui.bottom.popup { + margin: @popupDistanceAway 0em 0em; +} +.ui.bottom.left.popup { + transform-origin: top left; +} +.ui.bottom.center.popup { + transform-origin: top center; +} +.ui.bottom.right.popup { + transform-origin: top right; } /*--------------