Skip to content

Commit

Permalink
feat(true lazy rendering) (#102)
Browse files Browse the repository at this point in the history
* feat(true lazy rendering)

* bump ember-popper
  • Loading branch information
kybishop committed Mar 20, 2018
1 parent ecc5776 commit 1505a0d
Show file tree
Hide file tree
Showing 6 changed files with 1,437 additions and 1,517 deletions.
65 changes: 35 additions & 30 deletions addon/components/attach-popover.js
Expand Up @@ -63,13 +63,24 @@ export default Component.extend({
},

registerAPI(api) {
// Only 'popperTarget' has observers, everything else can be a direct property
this._disableEventListeners = api.disableEventListeners;
this._enableEventListeners = api.enableEventListeners;
this._popperElement = api.popperElement;
this._update = api.update;

this.set('popperTarget', api.popperTarget);
if (this._isHidden && !this.isDestroying && !this.isDestroyed) {
// Hide the attachment until it has been positioned,
// preventing jank during initial positioning
this._popperElement.style.visibility = 'hidden';

// The attachment has no width if initially hidden. This can cause it to be positioned so
// far to the right that it overflows the screen until enough updates fix its position.
// We avoid this by positioning initially hidden elements in the top left of the screen.
// The attachment will then correctly update its position from the first this._show()
this._popperElement.style.transform = null;

this._popperElement.style.display = this.get('isShown') ? '' : 'none';
}
}
},

Expand Down Expand Up @@ -129,6 +140,13 @@ export default Component.extend({
}),

_setIsVisibleAfterDelay(isVisible, delay) {
if (!this._popperElement) {
this._animationTimeout = requestAnimationFrame(() => {
this._animationTimeout = this._setIsVisibleAfterDelay(isVisible, delay);
});

return;
}
const onChange = this.get('onChange');

if (delay) {
Expand All @@ -137,6 +155,10 @@ export default Component.extend({
if (!this.isDestroyed && !this.isDestroying) {
this._popperElement.style.display = isVisible ? '' : 'none';

// Prevent jank by making the attachment invisible until positioned.
// The visibility style will be toggled by this._startShowAnimation()
this._popperElement.style.visibility = isVisible ? 'hidden' : '';

if (onChange) {
onChange(isVisible);
}
Expand All @@ -146,6 +168,10 @@ export default Component.extend({
} else {
this._popperElement.style.display = isVisible ? '' : 'none';

// Prevent jank by making the attachment invisible until positioned.
// The visibility style will be toggled by this._startShowAnimation()
this._popperElement.style.visibility = isVisible ? 'hidden' : '';

if (onChange) {
onChange(isVisible);
}
Expand Down Expand Up @@ -179,13 +205,16 @@ export default Component.extend({
init() {
this._super(...arguments);

// Used to determine the attachments initial parent element
this._parentFinder = self.document ? self.document.createTextNode('') : '';

// Holds the current popper target so event listeners can be removed if the target changes
this._currentTarget = null;

// The debounced _hide() and _show() are stored here so they can be cancelled when necessary
this._delayedVisibilityToggle = null;

this.id = this.id || `${guidFor(this)}-tooltip`;
this.id = this.id || `${guidFor(this)}-popper`;

// The final source of truth on whether or not all _hide() or _show() actions have completed
this._isHidden = true;
Expand Down Expand Up @@ -243,37 +272,13 @@ export default Component.extend({
didInsertElement() {
this._super(...arguments);

// The attachment has no width if initially hidden. This can cause it to be positioned so far
// to the right that it overflows the screen until enough updates fix its position.
// We avoid this issue by positioning initially hidden elements in the top left of the screen.
// The attachment will then correctly update its position from the first this._show()
next(this, () => {
if (this._isHidden && !this.isDestroying && !this.isDestroyed) {
this._popperElement.style.transform = null;

// Hide the attachment until it has been positioned, preventing jank during initial positioning
this._popperElement.style.visibility = 'hidden';
}
});

this._popperElement.style.display = this.get('isShown') ? '' : 'none';

this._initializeAttacher();
},

_initializeAttacher() {
this._removeEventListeners();

this._currentTarget = this.get('popperTarget');

if (!this._currentTarget) {
// Hide the attachment until a valid target is found
if (!this._isHidden) {
this._hide();
}

return;
}
this.set('_currentTarget', this.get('popperTarget') || this._parentFinder.parentNode);

this._addListenersForShowEvents();

Expand Down Expand Up @@ -382,8 +387,8 @@ export default Component.extend({
const popperElement = this._popperElement;

// Wait until the element is visible before continuing
if (popperElement.style.display === 'none') {
this._startShowAnimation();
if (!popperElement || popperElement.style.display === 'none') {
this._animationTimeout = this._startShowAnimation();

return;
}
Expand Down
6 changes: 6 additions & 0 deletions addon/components/attach-tooltip.js
Expand Up @@ -17,6 +17,12 @@ export default AttachPopover.extend({
}
}),

didInsertElement() {
this._super(...arguments);

this._currentTarget.setAttribute('aria-describedby', this.id);
},

popperTargetChanged: observer('popperTarget', function() {
const oldTarget = this._currentTarget;
if (oldTarget) {
Expand Down
28 changes: 15 additions & 13 deletions addon/templates/components/attach-popover.hbs
@@ -1,14 +1,16 @@
{{#ember-popper ariaRole=ariaRole
class="ember-attacher"
eventsEnabled=false
id=id
modifiers=_modifiers
placement=placement
popperContainer=popperContainer
registerAPI=(action 'registerAPI')
renderInPlace=renderInPlace
popperTarget=popperTarget as |emberPopper|}}
{{#if _shouldRender}}
{{unbound _parentFinder}}

{{#if (and _currentTarget _shouldRender)}}
{{#ember-popper ariaRole=ariaRole
class="ember-attacher"
eventsEnabled=false
id=id
modifiers=_modifiers
placement=placement
popperContainer=popperContainer
popperTarget=_currentTarget
registerAPI=(action 'registerAPI')
renderInPlace=renderInPlace as |emberPopper|}}
<div class="{{_class}}" style="{{_transitionDurationCss}}">
{{yield (hash emberPopper=emberPopper hide=(action 'hide'))}}

Expand All @@ -19,5 +21,5 @@
<div x-circle style="{{_circleTransitionDuration}}"></div>
{{/if}}
</div>
{{/if}}
{{/ember-popper}}
{{/ember-popper}}
{{/if}}
1 change: 1 addition & 0 deletions app/templates/components/attach-popover.js
@@ -0,0 +1 @@
export { default } from 'ember-attacher/templates/components/attach-popover';
2 changes: 1 addition & 1 deletion package.json
Expand Up @@ -33,7 +33,7 @@
"ember-cli-babel": "^6.11.0",
"ember-cli-htmlbars": "^2.0.2",
"ember-cli-sass": "^7.1.4",
"ember-popper": "^0.8.3",
"ember-popper": "^0.9.0",
"ember-truth-helpers": "^2.0.0"
},
"devDependencies": {
Expand Down

0 comments on commit 1505a0d

Please sign in to comment.