Skip to content
This repository was archived by the owner on Sep 5, 2024. It is now read-only.

Commit 93d6572

Browse files
crisbetoSplaktar
authored andcommitted
fix(panel): allow transform to be animated on an offset panel
Previously, if a panel had a position with an offset (e.g. `$mdPanel.newPanelPosition().center()`), the positioning would break any `transform` animations on the panel. This was due to the fact that `mdPanel` uses inline `transform` styles to do the offsetting. These changes introduce a wrapper around the panel (`.md-panel-inner-wrapper`), which will handle all of the positioning, allowing for any animations to be applied to the `.md-panel` itself. Relates to #9641. Fixes #9905.
1 parent 7fdf9da commit 93d6572

File tree

3 files changed

+157
-108
lines changed

3 files changed

+157
-108
lines changed

src/components/panel/panel.js

+65-48
Original file line numberDiff line numberDiff line change
@@ -1304,10 +1304,10 @@ MdPanelService.prototype._closeFirstOpenedPanel = function(groupName) {
13041304

13051305

13061306
/**
1307-
* Wraps the users template in two elements, md-panel-outer-wrapper, which
1308-
* covers the entire attachTo element, and md-panel, which contains only the
1309-
* template. This allows the panel control over positioning, animations,
1310-
* and similar properties.
1307+
* Wraps the user's template in three elements:
1308+
* - md-panel-outer-wrapper - covers the entire `attachTo` element.
1309+
* - md-panel-inner-wrapper - handles the positioning.
1310+
* - md-panel - contains the user's content and deals with the animations.
13111311
* @param {string} origTemplate The original template.
13121312
* @returns {string} The wrapped template.
13131313
* @private
@@ -1319,26 +1319,32 @@ MdPanelService.prototype._wrapTemplate = function(origTemplate) {
13191319
// height and width for positioning.
13201320
return '' +
13211321
'<div class="md-panel-outer-wrapper">' +
1322-
' <div class="md-panel _md-panel-offscreen">' + template + '</div>' +
1322+
'<div class="md-panel-inner-wrapper" style="left: -9999px;">' +
1323+
'<div class="md-panel _md-panel-offscreen">' + template + '</div>' +
1324+
'</div>' +
13231325
'</div>';
13241326
};
13251327

13261328

13271329
/**
1328-
* Wraps a content element in a md-panel-outer wrapper and
1329-
* positions it off-screen. Allows for proper control over positoning
1330-
* and animations.
1330+
* Wraps a content element in a `md-panel-outer-wrapper`, as well as
1331+
* a `md-panel-inner-wrapper`, and positions it off-screen. Allows for
1332+
* proper control over positoning and animations.
13311333
* @param {!angular.JQLite} contentElement Element to be wrapped.
13321334
* @return {!angular.JQLite} Wrapper element.
13331335
* @private
13341336
*/
13351337
MdPanelService.prototype._wrapContentElement = function(contentElement) {
1336-
var wrapper = angular.element('<div class="md-panel-outer-wrapper">');
1338+
var outerWrapper = angular.element(
1339+
'<div class="md-panel-outer-wrapper">' +
1340+
'<div class="md-panel-inner-wrapper" style="left: -9999px;"></div>' +
1341+
'</div>'
1342+
);
13371343

13381344
contentElement.addClass('md-panel _md-panel-offscreen');
1339-
wrapper.append(contentElement);
1345+
outerWrapper.children().eq(0).append(contentElement);
13401346

1341-
return wrapper;
1347+
return outerWrapper;
13421348
};
13431349

13441350

@@ -1405,6 +1411,9 @@ function MdPanelRef(config, $injector) {
14051411
/** @type {!angular.JQLite|undefined} */
14061412
this.panelEl;
14071413

1414+
/** @type {!angular.JQLite|undefined} */
1415+
this.innerWrapper;
1416+
14081417
/**
14091418
* Whether the panel is attached. This is synchronous. When attach is called,
14101419
* isAttached is set to true. When detach is called, isAttached is set to
@@ -1851,6 +1860,11 @@ MdPanelRef.prototype._compile = function() {
18511860
);
18521861
}
18531862

1863+
// Save a reference to the inner wrapper.
1864+
self.innerWrapper = angular.element(
1865+
self.panelContainer[0].querySelector('.md-panel-inner-wrapper')
1866+
);
1867+
18541868
// Save a reference to the cleanup function from the compiler.
18551869
self._compilerCleanup = compileData.cleanup;
18561870

@@ -1927,14 +1941,17 @@ MdPanelRef.prototype._addStyles = function() {
19271941
var self = this;
19281942
return this._$q(function(resolve) {
19291943
self.panelContainer.css('z-index', self.config['zIndex']);
1930-
self.panelEl.css('z-index', self.config['zIndex'] + 1);
1944+
self.innerWrapper.css('z-index', self.config['zIndex'] + 1);
19311945

19321946
var hideAndResolve = function() {
19331947
// Theme the element and container.
19341948
self._setTheming();
19351949

19361950
// Remove offscreen class and add hidden class.
19371951
self.panelEl.removeClass('_md-panel-offscreen');
1952+
1953+
// Remove left: -9999px and add hidden class.
1954+
self.innerWrapper.css('left', '');
19381955
self.panelContainer.addClass(MD_PANEL_HIDDEN);
19391956

19401957
resolve(self);
@@ -2001,27 +2018,27 @@ MdPanelRef.prototype._updatePosition = function(init) {
20012018
var positionConfig = this.config['position'];
20022019

20032020
if (positionConfig) {
2004-
positionConfig._setPanelPosition(this.panelEl);
2021+
positionConfig._setPanelPosition(this.innerWrapper);
20052022

20062023
// Hide the panel now that position is known.
20072024
if (init) {
20082025
this.panelEl.removeClass('_md-panel-offscreen');
20092026
this.panelContainer.addClass(MD_PANEL_HIDDEN);
20102027
}
20112028

2012-
this.panelEl.css(
2029+
this.innerWrapper.css(
20132030
MdPanelPosition.absPosition.TOP,
20142031
positionConfig.getTop()
20152032
);
2016-
this.panelEl.css(
2033+
this.innerWrapper.css(
20172034
MdPanelPosition.absPosition.BOTTOM,
20182035
positionConfig.getBottom()
20192036
);
2020-
this.panelEl.css(
2037+
this.innerWrapper.css(
20212038
MdPanelPosition.absPosition.LEFT,
20222039
positionConfig.getLeft()
20232040
);
2024-
this.panelEl.css(
2041+
this.innerWrapper.css(
20252042
MdPanelPosition.absPosition.RIGHT,
20262043
positionConfig.getRight()
20272044
);
@@ -2928,38 +2945,38 @@ MdPanelPosition.prototype.getTransform = function() {
29282945

29292946

29302947
/**
2931-
* Sets the `transform` value for a panel element.
2932-
* @param {!angular.JQLite} panelEl
2948+
* Sets the `transform` value for an element.
2949+
* @param {!angular.JQLite} el
29332950
* @returns {!angular.JQLite}
29342951
* @private
29352952
*/
2936-
MdPanelPosition.prototype._setTransform = function(panelEl) {
2937-
return panelEl.css(this._$mdConstant.CSS.TRANSFORM, this.getTransform());
2953+
MdPanelPosition.prototype._setTransform = function(el) {
2954+
return el.css(this._$mdConstant.CSS.TRANSFORM, this.getTransform());
29382955
};
29392956

29402957

29412958
/**
29422959
* True if the panel is completely on-screen with this positioning; false
29432960
* otherwise.
2944-
* @param {!angular.JQLite} panelEl
2961+
* @param {!angular.JQLite} el
29452962
* @return {boolean}
29462963
* @private
29472964
*/
2948-
MdPanelPosition.prototype._isOnscreen = function(panelEl) {
2965+
MdPanelPosition.prototype._isOnscreen = function(el) {
29492966
// this works because we always use fixed positioning for the panel,
29502967
// which is relative to the viewport.
29512968
var left = parseInt(this.getLeft());
29522969
var top = parseInt(this.getTop());
29532970

29542971
if (this._translateX.length || this._translateY.length) {
29552972
var prefixedTransform = this._$mdConstant.CSS.TRANSFORM;
2956-
var offsets = getComputedTranslations(panelEl, prefixedTransform);
2973+
var offsets = getComputedTranslations(el, prefixedTransform);
29572974
left += offsets.x;
29582975
top += offsets.y;
29592976
}
29602977

2961-
var right = left + panelEl[0].offsetWidth;
2962-
var bottom = top + panelEl[0].offsetHeight;
2978+
var right = left + el[0].offsetWidth;
2979+
var bottom = top + el[0].offsetHeight;
29632980

29642981
return (left >= 0) &&
29652982
(top >= 0) &&
@@ -2998,53 +3015,53 @@ MdPanelPosition.prototype._reduceTranslateValues =
29983015
/**
29993016
* Sets the panel position based on the created panel element and best x/y
30003017
* positioning.
3001-
* @param {!angular.JQLite} panelEl
3018+
* @param {!angular.JQLite} el
30023019
* @private
30033020
*/
3004-
MdPanelPosition.prototype._setPanelPosition = function(panelEl) {
3005-
// Remove the "position adjusted" class in case it has been added before.
3006-
panelEl.removeClass('_md-panel-position-adjusted');
3021+
MdPanelPosition.prototype._setPanelPosition = function(el) {
3022+
// Remove the class in case it has been added before.
3023+
el.removeClass('_md-panel-position-adjusted');
30073024

30083025
// Only calculate the position if necessary.
30093026
if (this._absolute) {
3010-
this._setTransform(panelEl);
3027+
this._setTransform(el);
30113028
return;
30123029
}
30133030

30143031
if (this._actualPosition) {
3015-
this._calculatePanelPosition(panelEl, this._actualPosition);
3016-
this._setTransform(panelEl);
3017-
this._constrainToViewport(panelEl);
3032+
this._calculatePanelPosition(el, this._actualPosition);
3033+
this._setTransform(el);
3034+
this._constrainToViewport(el);
30183035
return;
30193036
}
30203037

30213038
for (var i = 0; i < this._positions.length; i++) {
30223039
this._actualPosition = this._positions[i];
3023-
this._calculatePanelPosition(panelEl, this._actualPosition);
3024-
this._setTransform(panelEl);
3040+
this._calculatePanelPosition(el, this._actualPosition);
3041+
this._setTransform(el);
30253042

3026-
if (this._isOnscreen(panelEl)) {
3043+
if (this._isOnscreen(el)) {
30273044
return;
30283045
}
30293046
}
30303047

3031-
this._constrainToViewport(panelEl);
3048+
this._constrainToViewport(el);
30323049
};
30333050

30343051

30353052
/**
30363053
* Constrains a panel's position to the viewport.
3037-
* @param {!angular.JQLite} panelEl
3054+
* @param {!angular.JQLite} el
30383055
* @private
30393056
*/
3040-
MdPanelPosition.prototype._constrainToViewport = function(panelEl) {
3057+
MdPanelPosition.prototype._constrainToViewport = function(el) {
30413058
var margin = MdPanelPosition.viewportMargin;
30423059
var initialTop = this._top;
30433060
var initialLeft = this._left;
30443061

30453062
if (this.getTop()) {
30463063
var top = parseInt(this.getTop());
3047-
var bottom = panelEl[0].offsetHeight + top;
3064+
var bottom = el[0].offsetHeight + top;
30483065
var viewportHeight = this._$window.innerHeight;
30493066

30503067
if (top < margin) {
@@ -3056,7 +3073,7 @@ MdPanelPosition.prototype._constrainToViewport = function(panelEl) {
30563073

30573074
if (this.getLeft()) {
30583075
var left = parseInt(this.getLeft());
3059-
var right = panelEl[0].offsetWidth + left;
3076+
var right = el[0].offsetWidth + left;
30603077
var viewportWidth = this._$window.innerWidth;
30613078

30623079
if (left < margin) {
@@ -3067,7 +3084,7 @@ MdPanelPosition.prototype._constrainToViewport = function(panelEl) {
30673084
}
30683085

30693086
// Class that can be used to re-style the panel if it was repositioned.
3070-
panelEl.toggleClass(
3087+
el.toggleClass(
30713088
'_md-panel-position-adjusted',
30723089
this._top !== initialTop || this._left !== initialLeft
30733090
);
@@ -3106,15 +3123,15 @@ MdPanelPosition.prototype._bidi = function(position) {
31063123
/**
31073124
* Calculates the panel position based on the created panel element and the
31083125
* provided positioning.
3109-
* @param {!angular.JQLite} panelEl
3126+
* @param {!angular.JQLite} el
31103127
* @param {!{x:string, y:string}} position
31113128
* @private
31123129
*/
3113-
MdPanelPosition.prototype._calculatePanelPosition = function(panelEl, position) {
3130+
MdPanelPosition.prototype._calculatePanelPosition = function(el, position) {
31143131

3115-
var panelBounds = panelEl[0].getBoundingClientRect();
3116-
var panelWidth = Math.max(panelBounds.width, panelEl[0].clientWidth);
3117-
var panelHeight = Math.max(panelBounds.height, panelEl[0].clientHeight);
3132+
var panelBounds = el[0].getBoundingClientRect();
3133+
var panelWidth = Math.max(panelBounds.width, el[0].clientWidth);
3134+
var panelHeight = Math.max(panelBounds.height, el[0].clientHeight);
31183135

31193136
var targetBounds = this._relativeToEl[0].getBoundingClientRect();
31203137

src/components/panel/panel.scss

+15-11
Original file line numberDiff line numberDiff line change
@@ -6,21 +6,16 @@
66
width: 100%;
77
}
88

9-
._md-panel-hidden {
10-
display: none;
9+
.md-panel-inner-wrapper {
10+
position: fixed;
1111
}
1212

1313
._md-panel-offscreen {
1414
left: -9999px;
1515
}
1616

17-
._md-panel-fullscreen {
18-
border-radius: 0;
19-
left: 0;
20-
min-height: 100%;
21-
min-width: 100%;
22-
position: fixed;
23-
top: 0;
17+
._md-panel-hidden {
18+
display: none;
2419
}
2520

2621
// Only used when no animations are present.
@@ -31,7 +26,7 @@
3126

3227
.md-panel {
3328
opacity: 0;
34-
position: fixed;
29+
position: relative;
3530

3631
&._md-panel-shown {
3732
// Only used when custom animations are present.
@@ -57,7 +52,7 @@
5752

5853
&._md-panel-backdrop {
5954
height: 100%;
60-
position: absolute;
55+
position: fixed;
6156
width: 100%;
6257
}
6358

@@ -70,3 +65,12 @@
7065
transition: opacity $material-leave-duration $material-leave-timing-function;
7166
}
7267
}
68+
69+
._md-panel-fullscreen {
70+
border-radius: 0;
71+
left: 0;
72+
min-height: 100%;
73+
min-width: 100%;
74+
position: fixed;
75+
top: 0;
76+
}

0 commit comments

Comments
 (0)