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

Commit 01ef22a

Browse files
committed
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 70cecda commit 01ef22a

File tree

3 files changed

+147
-101
lines changed

3 files changed

+147
-101
lines changed

src/components/panel/panel.js

Lines changed: 59 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1034,10 +1034,10 @@ MdPanelService.prototype._closeFirstOpenedPanel = function(groupName) {
10341034

10351035

10361036
/**
1037-
* Wraps the users template in two elements, md-panel-outer-wrapper, which
1038-
* covers the entire attachTo element, and md-panel, which contains only the
1039-
* template. This allows the panel control over positioning, animations,
1040-
* and similar properties.
1037+
* Wraps the user's template in three elements:
1038+
* - md-panel-outer-wrapper - covers the entire `attachTo` element.
1039+
* - md-panel-inner-wrapper - handles the positioning.
1040+
* - md-panel - contains the user's content and deals with the animations.
10411041
* @param {string} origTemplate The original template.
10421042
* @returns {string} The wrapped template.
10431043
* @private
@@ -1049,26 +1049,32 @@ MdPanelService.prototype._wrapTemplate = function(origTemplate) {
10491049
// height and width for positioning.
10501050
return '' +
10511051
'<div class="md-panel-outer-wrapper">' +
1052-
' <div class="md-panel" style="left: -9999px;">' + template + '</div>' +
1052+
'<div class="md-panel-inner-wrapper" style="left: -9999px;">' +
1053+
'<div class="md-panel">' + template + '</div>' +
1054+
'</div>' +
10531055
'</div>';
10541056
};
10551057

10561058

10571059
/**
1058-
* Wraps a content element in a md-panel-outer wrapper and
1059-
* positions it off-screen. Allows for proper control over positoning
1060-
* and animations.
1060+
* Wraps a content element in a `md-panel-outer-wrapper`, as well as
1061+
* a `md-panel-inner-wrapper`, and positions it off-screen. Allows for
1062+
* proper control over positoning and animations.
10611063
* @param {!angular.JQLite} contentElement Element to be wrapped.
10621064
* @return {!angular.JQLite} Wrapper element.
10631065
* @private
10641066
*/
10651067
MdPanelService.prototype._wrapContentElement = function(contentElement) {
1066-
var wrapper = angular.element('<div class="md-panel-outer-wrapper">');
1068+
var outerWrapper = angular.element(
1069+
'<div class="md-panel-outer-wrapper">' +
1070+
'<div class="md-panel-inner-wrapper" style="left: -9999px;"></div>' +
1071+
'</div>'
1072+
);
10671073

1068-
contentElement.addClass('md-panel').css('left', '-9999px');
1069-
wrapper.append(contentElement);
1074+
contentElement.addClass('md-panel');
1075+
outerWrapper.children().eq(0).append(contentElement);
10701076

1071-
return wrapper;
1077+
return outerWrapper;
10721078
};
10731079

10741080

@@ -1132,6 +1138,9 @@ function MdPanelRef(config, $injector) {
11321138
/** @type {!angular.JQLite|undefined} */
11331139
this.panelEl;
11341140

1141+
/** @type {!angular.JQLite|undefined} */
1142+
this.innerWrapper;
1143+
11351144
/**
11361145
* Whether the panel is attached. This is synchronous. When attach is called,
11371146
* isAttached is set to true. When detach is called, isAttached is set to
@@ -1574,6 +1583,11 @@ MdPanelRef.prototype._compile = function() {
15741583
);
15751584
}
15761585

1586+
// Save a reference to the inner wrapper.
1587+
self.innerWrapper = angular.element(
1588+
self.panelContainer[0].querySelector('.md-panel-inner-wrapper')
1589+
);
1590+
15771591
// Save a reference to the cleanup function from the compiler.
15781592
self._compilerCleanup = compileData.cleanup;
15791593

@@ -1648,11 +1662,11 @@ MdPanelRef.prototype._addStyles = function() {
16481662
var self = this;
16491663
return this._$q(function(resolve) {
16501664
self.panelContainer.css('z-index', self.config['zIndex']);
1651-
self.panelEl.css('z-index', self.config['zIndex'] + 1);
1665+
self.innerWrapper.css('z-index', self.config['zIndex'] + 1);
16521666

16531667
var hideAndResolve = function() {
16541668
// Remove left: -9999px and add hidden class.
1655-
self.panelEl.css('left', '');
1669+
self.innerWrapper.css('left', '');
16561670
self.panelContainer.addClass(MD_PANEL_HIDDEN);
16571671
resolve(self);
16581672
};
@@ -1704,26 +1718,26 @@ MdPanelRef.prototype._updatePosition = function(init) {
17041718
var positionConfig = this.config['position'];
17051719

17061720
if (positionConfig) {
1707-
positionConfig._setPanelPosition(this.panelEl);
1721+
positionConfig._setPanelPosition(this.innerWrapper);
17081722

17091723
// Hide the panel now that position is known.
17101724
if (init) {
17111725
this.panelContainer.addClass(MD_PANEL_HIDDEN);
17121726
}
17131727

1714-
this.panelEl.css(
1728+
this.innerWrapper.css(
17151729
MdPanelPosition.absPosition.TOP,
17161730
positionConfig.getTop()
17171731
);
1718-
this.panelEl.css(
1732+
this.innerWrapper.css(
17191733
MdPanelPosition.absPosition.BOTTOM,
17201734
positionConfig.getBottom()
17211735
);
1722-
this.panelEl.css(
1736+
this.innerWrapper.css(
17231737
MdPanelPosition.absPosition.LEFT,
17241738
positionConfig.getLeft()
17251739
);
1726-
this.panelEl.css(
1740+
this.innerWrapper.css(
17271741
MdPanelPosition.absPosition.RIGHT,
17281742
positionConfig.getRight()
17291743
);
@@ -2605,37 +2619,37 @@ MdPanelPosition.prototype.getTransform = function() {
26052619

26062620
/**
26072621
* Sets the `transform` value for a panel element.
2608-
* @param {!angular.JQLite} panelEl
2622+
* @param {!angular.JQLite} element
26092623
* @returns {!angular.JQLite}
26102624
* @private
26112625
*/
2612-
MdPanelPosition.prototype._setTransform = function(panelEl) {
2613-
return panelEl.css(this._$mdConstant.CSS.TRANSFORM, this.getTransform());
2626+
MdPanelPosition.prototype._setTransform = function(element) {
2627+
return element.css(this._$mdConstant.CSS.TRANSFORM, this.getTransform());
26142628
};
26152629

26162630

26172631
/**
26182632
* True if the panel is completely on-screen with this positioning; false
26192633
* otherwise.
2620-
* @param {!angular.JQLite} panelEl
2634+
* @param {!angular.JQLite} element
26212635
* @return {boolean}
26222636
* @private
26232637
*/
2624-
MdPanelPosition.prototype._isOnscreen = function(panelEl) {
2638+
MdPanelPosition.prototype._isOnscreen = function(element) {
26252639
// this works because we always use fixed positioning for the panel,
26262640
// which is relative to the viewport.
26272641
var left = parseInt(this.getLeft());
26282642
var top = parseInt(this.getTop());
26292643

26302644
if (this._translateX.length || this._translateY.length) {
26312645
var prefixedTransform = this._$mdConstant.CSS.TRANSFORM;
2632-
var offsets = getComputedTranslations(panelEl, prefixedTransform);
2646+
var offsets = getComputedTranslations(element, prefixedTransform);
26332647
left += offsets.x;
26342648
top += offsets.y;
26352649
}
26362650

2637-
var right = left + panelEl[0].offsetWidth;
2638-
var bottom = top + panelEl[0].offsetHeight;
2651+
var right = left + element[0].offsetWidth;
2652+
var bottom = top + element[0].offsetHeight;
26392653

26402654
return (left >= 0) &&
26412655
(top >= 0) &&
@@ -2675,52 +2689,52 @@ MdPanelPosition.prototype._reduceTranslateValues =
26752689
/**
26762690
* Sets the panel position based on the created panel element and best x/y
26772691
* positioning.
2678-
* @param {!angular.JQLite} panelEl
2692+
* @param {!angular.JQLite} element
26792693
* @private
26802694
*/
2681-
MdPanelPosition.prototype._setPanelPosition = function(panelEl) {
2695+
MdPanelPosition.prototype._setPanelPosition = function(element) {
26822696
// Remove the class in case it has been added before.
2683-
panelEl.removeClass('_md-panel-position-adjusted');
2697+
element.removeClass('_md-panel-position-adjusted');
26842698

26852699
// Only calculate the position if necessary.
26862700
if (this._absolute) {
2687-
this._setTransform(panelEl);
2701+
this._setTransform(element);
26882702
return;
26892703
}
26902704

26912705
if (this._actualPosition) {
2692-
this._calculatePanelPosition(panelEl, this._actualPosition);
2693-
this._setTransform(panelEl);
2706+
this._calculatePanelPosition(element, this._actualPosition);
2707+
this._setTransform(element);
26942708
return;
26952709
}
26962710

26972711
for (var i = 0; i < this._positions.length; i++) {
26982712
this._actualPosition = this._positions[i];
2699-
this._calculatePanelPosition(panelEl, this._actualPosition);
2700-
this._setTransform(panelEl);
2713+
this._calculatePanelPosition(element, this._actualPosition);
2714+
this._setTransform(element);
27012715

2702-
if (this._isOnscreen(panelEl)) {
2716+
if (this._isOnscreen(element)) {
27032717
return;
27042718
}
27052719
}
27062720

27072721
// Class that can be used to re-style the panel if it was repositioned.
2708-
panelEl.addClass('_md-panel-position-adjusted');
2709-
this._constrainToViewport(panelEl);
2722+
element.addClass('_md-panel-position-adjusted');
2723+
this._constrainToViewport(element);
27102724
};
27112725

27122726

27132727
/**
27142728
* Constrains a panel's position to the viewport.
2715-
* @param {!angular.JQLite} panelEl
2729+
* @param {!angular.JQLite} element
27162730
* @private
27172731
*/
2718-
MdPanelPosition.prototype._constrainToViewport = function(panelEl) {
2732+
MdPanelPosition.prototype._constrainToViewport = function(element) {
27192733
var margin = MdPanelPosition.viewportMargin;
27202734

27212735
if (this.getTop()) {
27222736
var top = parseInt(this.getTop());
2723-
var bottom = panelEl[0].offsetHeight + top;
2737+
var bottom = element[0].offsetHeight + top;
27242738
var viewportHeight = this._$window.innerHeight;
27252739

27262740
if (top < margin) {
@@ -2732,7 +2746,7 @@ MdPanelPosition.prototype._constrainToViewport = function(panelEl) {
27322746

27332747
if (this.getLeft()) {
27342748
var left = parseInt(this.getLeft());
2735-
var right = panelEl[0].offsetWidth + left;
2749+
var right = element[0].offsetWidth + left;
27362750
var viewportWidth = this._$window.innerWidth;
27372751

27382752
if (left < margin) {
@@ -2775,13 +2789,13 @@ MdPanelPosition.prototype._bidi = function(position) {
27752789
/**
27762790
* Calculates the panel position based on the created panel element and the
27772791
* provided positioning.
2778-
* @param {!angular.JQLite} panelEl
2792+
* @param {!angular.JQLite} element
27792793
* @param {!{x:string, y:string}} position
27802794
* @private
27812795
*/
2782-
MdPanelPosition.prototype._calculatePanelPosition = function(panelEl, position) {
2796+
MdPanelPosition.prototype._calculatePanelPosition = function(element, position) {
27832797

2784-
var panelBounds = panelEl[0].getBoundingClientRect();
2798+
var panelBounds = element[0].getBoundingClientRect();
27852799
var panelWidth = panelBounds.width;
27862800
var panelHeight = panelBounds.height;
27872801

src/components/panel/panel.scss

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,12 @@
66
width: 100%;
77
}
88

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

13-
._md-panel-fullscreen {
14-
border-radius: 0;
15-
left: 0;
16-
min-height: 100%;
17-
min-width: 100%;
18-
position: fixed;
19-
top: 0;
13+
._md-panel-hidden {
14+
display: none;
2015
}
2116

2217
// Only used when no animations are present.
@@ -27,7 +22,7 @@
2722

2823
.md-panel {
2924
opacity: 0;
30-
position: fixed;
25+
position: relative;
3126

3227
&._md-panel-shown {
3328
// Only used when custom animations are present.
@@ -53,7 +48,7 @@
5348

5449
&._md-panel-backdrop {
5550
height: 100%;
56-
position: absolute;
51+
position: fixed;
5752
width: 100%;
5853
}
5954

@@ -66,3 +61,12 @@
6661
transition: opacity $material-leave-duration $material-leave-timing-function;
6762
}
6863
}
64+
65+
._md-panel-fullscreen {
66+
border-radius: 0;
67+
left: 0;
68+
min-height: 100%;
69+
min-width: 100%;
70+
position: fixed;
71+
top: 0;
72+
}

0 commit comments

Comments
 (0)