Skip to content

Commit 5393d18

Browse files
wesruvgithub-actions[bot]heyMP
authored
fix: Fixed jank on primary detail when expanding on compact layout (#1754)
* CPFED-4318: Fixing jank in pfe-primary-detail when expanding section in compact mode * Adding changelog info * Fixing attribute filter * Update elements/pfe-primary-detail/src/pfe-primary-detail.js Co-authored-by: Michael Potter <[email protected]> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Michael Potter <[email protected]>
1 parent 04ccc7d commit 5393d18

File tree

4 files changed

+70
-61
lines changed

4 files changed

+70
-61
lines changed

CHANGELOG-1.x.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
- [](https://github.com/patternfly/patternfly-elements/commit/) fix: Pfe-Primary-Detail - Fixing animation jank when expanding a section in compact mode
2+
13
# 1.11.0 (2021-08-18)
24

35
- [489c561](https://github.com/patternfly/patternfly-elements/commit/489c561fd825bd7f84ebd3c1addbdeac28304a0e) feat: Pfe-Primary-Detail - Added much improved a11y and keyboard navigation, added mobile optimized layout behavior, and added thorough tests using new framework.
Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
1-
<div id="details-nav" data-pristine>
2-
<slot name="details-nav--header"></slot>
3-
<slot name="details-nav"></slot>
4-
</div>
5-
<div id="details-wrapper">
6-
<div id="details-wrapper__header">
7-
<button id="details-wrapper__back"><div id="details-wrapper__heading"></div></button>
1+
<div id="wrapper" data-pristine>
2+
<div id="details-nav">
3+
<slot name="details-nav--header"></slot>
4+
<slot name="details-nav"></slot>
5+
</div>
6+
<div id="details-wrapper">
7+
<div id="details-wrapper__header">
8+
<button id="details-wrapper__back"><div id="details-wrapper__heading"></div></button>
9+
</div>
10+
<slot name="details"></slot>
11+
</div>
12+
<div id="details-nav__footer">
13+
<slot name="details-nav--footer"></slot>
814
</div>
9-
<slot name="details"></slot>
10-
</div>
11-
<div id="details-nav__footer">
12-
<slot name="details-nav--footer"></slot>
1315
</div>

elements/pfe-primary-detail/src/pfe-primary-detail.js

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,5 @@
11
import PFElement from "../../pfelement/dist/pfelement.js";
22

3-
// Config for mutation observer to see if things change inside of the component
4-
const lightDomObserverConfig = {
5-
childList: true,
6-
};
7-
83
/**
94
* Debounce helper function
105
* @see https://davidwalsh.name/javascript-debounce-function
@@ -135,6 +130,7 @@ class PfePrimaryDetail extends PFElement {
135130
this._setBreakpoint = this._setBreakpoint.bind(this);
136131
this._setDetailsNavVisibility = this._setDetailsNavVisibility.bind(this);
137132
this._updateBackButtonState = this._updateBackButtonState.bind(this);
133+
this._manageWrapperAttributes = this._manageWrapperAttributes.bind(this);
138134

139135
// Place to store references to the slotted elements
140136
this._slots = {
@@ -145,9 +141,11 @@ class PfePrimaryDetail extends PFElement {
145141
};
146142

147143
// Setup mutation observer to watch for content changes
148-
this._observer = new MutationObserver(this._processLightDom);
144+
this._childObserver = new MutationObserver(this._processLightDom);
145+
this._attributesObserver = new MutationObserver(this._manageWrapperAttributes);
149146

150147
// Commonly used shadow DOM elements
148+
this._wrapper = this.shadowRoot.getElementById("wrapper");
151149
this._detailsNav = this.shadowRoot.getElementById("details-nav");
152150
this._detailsWrapper = this.shadowRoot.getElementById("details-wrapper");
153151
this._detailsWrapperHeader = this.shadowRoot.getElementById("details-wrapper__header");
@@ -176,7 +174,8 @@ class PfePrimaryDetail extends PFElement {
176174
window.addEventListener("resize", this._debouncedSetBreakpoint);
177175

178176
// Process the light DOM on any update
179-
this._observer.observe(this, lightDomObserverConfig);
177+
this._childObserver.observe(this, { childList: true });
178+
this._attributesObserver.observe(this, { attributes: true, attributeFilter: ["active"] });
180179

181180
this._detailsBackButton.addEventListener("click", this.closeAll);
182181

@@ -185,7 +184,8 @@ class PfePrimaryDetail extends PFElement {
185184
}
186185

187186
disconnectedCallback() {
188-
this._observer.disconnect();
187+
this._childObserver.disconnect();
188+
this._attributesObserver.disconnect();
189189

190190
window.removeEventListener("resize", this._debouncedSetBreakpoint);
191191

@@ -199,6 +199,14 @@ class PfePrimaryDetail extends PFElement {
199199
this.removeEventListener("keydown", this._keyboardControls);
200200
}
201201

202+
_manageWrapperAttributes() {
203+
if (this.hasAttribute("active")) {
204+
this._wrapper.classList.add("active");
205+
} else {
206+
this._wrapper.classList.remove("active");
207+
}
208+
}
209+
202210
/**
203211
* Updates markup of details-nav elements to be toggle buttons
204212
* @param {object} toggle Slotted element (probably a headline, unless it's been initialized already)
@@ -295,7 +303,7 @@ class PfePrimaryDetail extends PFElement {
295303

296304
// If nothing has been touched and we move to mobile, the details nav should be shown,
297305
// not the item that was opened by default so the desktop design would work
298-
if (this._detailsNav.hasAttribute("data-pristine") && breakpointIs === "compact") {
306+
if (this._wrapper.hasAttribute("data-pristine") && breakpointIs === "compact") {
299307
const activeToggle = this.active ? document.getElementById(this.active) : false;
300308
if (activeToggle) {
301309
this._addCloseAttributes(activeToggle);
@@ -486,7 +494,7 @@ class PfePrimaryDetail extends PFElement {
486494
// Detect if handleHideShow was called by an event listener or manually in code
487495
if (typeof e === "object" && Array.isArray(e.path)) {
488496
// If the user has interacted with the component remove the pristine attribute
489-
this._detailsNav.removeAttribute("data-pristine");
497+
this._wrapper.removeAttribute("data-pristine");
490498
}
491499

492500
if (typeof nextToggle === "undefined") {
@@ -502,7 +510,7 @@ class PfePrimaryDetail extends PFElement {
502510
const currentToggle = document.getElementById(this.active);
503511

504512
// Update attribute to show which toggle is active
505-
this.setAttribute("active", nextToggle.id);
513+
this.active = nextToggle.id;
506514

507515
// Create the appropriate heading for the top of the content column
508516
let newHeading = null;

elements/pfe-primary-detail/src/pfe-primary-detail.scss

Lines changed: 36 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -26,43 +26,46 @@ $LOCAL-VARIABLES: (
2626
}
2727

2828
:host {
29-
display: grid;
30-
grid-template-columns: pfe-local(GridTemplateColumns);
29+
display: block;
3130
border: pfe-local(Border);
32-
align-items: stretch;
33-
justify-content: stretch;
3431
// For compact styling and transitioning from compact to normal styling
3532
overflow: hidden;
3633
}
3734

38-
:host([breakpoint='compact']) {
39-
grid-template-columns: 1fr;
40-
}
41-
4235
:host([hidden]) {
4336
display: none;
4437
}
4538

46-
#details-nav,
47-
#details-wrapper,
48-
#details-nav__footer {
49-
///
50-
// @todo [WR] Animation is janky nav item is selected,
51-
// disabling overflow: hidden on parent is only fix
52-
// I can find but we need that.
53-
//
54-
// Tried: delaying _setDetailsNavVisibility, changing to flexbox layout,
55-
// transitioning position, adding extra wrappers, will-change,
56-
// backface-visibility, and 4ish ways of laying this out and animating it
57-
///
39+
#wrapper {
40+
display: grid;
41+
grid-template-columns: pfe-local(GridTemplateColumns);
42+
align-items: stretch;
43+
justify-content: stretch;
44+
overflow: hidden;
5845
transition: transform 0.25s ease-in-out;
5946
will-change: transform;
6047
backface-visibility: visible;
6148

6249
@media (prefers-reduced-motion) {
63-
transform: none;
50+
transition: none;
51+
will-change: auto;
6452
}
6553

54+
:host([breakpoint='compact']) & {
55+
display: grid;
56+
grid-template-columns: 50% 50%;
57+
gap: 0;
58+
width: 200%;
59+
}
60+
61+
:host([breakpoint='compact']) &.active {
62+
// When active this column should be off the left side
63+
transform: translateX(-50%);
64+
}
65+
}
66+
67+
#details-nav,
68+
#details-nav__footer {
6669
:host([breakpoint='compact']) & {
6770
align-self: stretch;
6871
justify-self: stretch;
@@ -73,17 +76,9 @@ $LOCAL-VARIABLES: (
7376
}
7477
}
7578

76-
// Left column elements
77-
#details-nav,
7879
#details-nav__footer {
79-
8080
:host([breakpoint='compact']) & {
81-
transform: none;
82-
}
83-
84-
:host([breakpoint='compact'][active]) & {
85-
// When active this column should be off the left side
86-
transform: translateX(-100%);
81+
grid-row: 2;
8782
}
8883
}
8984

@@ -152,16 +147,11 @@ $LOCAL-VARIABLES: (
152147
background: pfe-local(Background, $region: details);
153148

154149
:host([breakpoint='compact']) & {
155-
// When inactive this should be shoved off the right side of the screen at mobile
156-
transform: translateX(100%);
157150
grid-row: 1 / span 2;
151+
grid-column: 2;
158152
padding-top: 0;
159153
}
160154

161-
:host([breakpoint='compact'][active]) & {
162-
transform: none;
163-
}
164-
165155
// Consistent height is enforced with grid, which will respect the max-height of the tallest thing in the grid area
166156
:host([consistent-height]) & {
167157
display: flex;
@@ -205,7 +195,7 @@ $LOCAL-VARIABLES: (
205195

206196
#details-wrapper__back {
207197
$focus-width: 2px;
208-
display: none;
198+
display: none; // Prevent from effecting layout at desktop
209199
position: relative;
210200
align-self: stretch;
211201
border: 0;
@@ -222,8 +212,15 @@ $LOCAL-VARIABLES: (
222212
outline-width: $focus-width !important;
223213
}
224214

225-
:host([active]) & {
226-
display: inline-block;
215+
:host([breakpoint='compact']) & {
216+
// Make sure it effects layout at compact
217+
// But shouldn't be selectable until it's active
218+
display: block;
219+
visibility: hidden;
220+
}
221+
222+
:host([breakpoint='compact']) .active & {
223+
visibility: visible;
227224
width: 100%;
228225
padding-left: 16px;
229226
}

0 commit comments

Comments
 (0)