blob: 1c6789f99569f33ce97b04be7b958c84c63d7899 [file] [log] [blame]
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/**
* @fileoverview CrContainerShadowBehavior holds logic for showing a drop shadow
* near the top of a container element, when the content has scrolled.
*
* Elements using this behavior are expected to define a #container element,
* which is the element being scrolled.
*
* The behavior will take care of inserting an element with ID
* 'cr-container-shadow' which holds the drop shadow effect. A 'has-shadow'
* CSS class is automatically added/removed while scrolling, as necessary.
*
* Clients should either use the existing shared styling in
* shared_styles_css.html, '#cr-container-shadow' and
* '#cr-container-shadow.has-shadow', or define their own styles.
*/
/** @polymerBehavior */
const CrContainerShadowBehavior = {
/** @private {?IntersectionObserver} */
intersectionObserver_: null,
/** @override */
attached: function() {
// The element holding the drop shadow effect to be shown.
const dropShadow = document.createElement('div');
// This ID should match the CSS rules in shared_styles_css.html.
dropShadow.id = 'cr-container-shadow';
this.$.container.parentNode.insertBefore(dropShadow, this.$.container);
// Dummy element used to detect scrolling. Has a 0px height intentionally.
const intersectionProbe = document.createElement('div');
this.$.container.prepend(intersectionProbe);
// Setup drop shadow logic.
const callback = entries => {
dropShadow.classList.toggle(
'has-shadow', entries[entries.length - 1].intersectionRatio == 0);
};
this.intersectionObserver_ = new IntersectionObserver(
callback,
/** @type {IntersectionObserverInit} */ ({
root: this.$.container,
threshold: 0,
}));
// Need to register the observer within a setTimeout() callback, otherwise
// the drop shadow flashes once on startup, because of the DOM modifications
// earlier in this function causing a relayout.
window.setTimeout(() => {
if (this.intersectionObserver_) // In case this is already detached.
this.intersectionObserver_.observe(intersectionProbe);
});
},
/** @override */
detached: function() {
this.intersectionObserver_.disconnect();
this.intersectionObserver_ = null;
},
};