UNPKG

office-ui-fabric-react

Version:

Reusable React components for building experiences for Office 365.

234 lines • 10.5 kB
import * as tslib_1 from "tslib"; import * as React from 'react'; import * as PropTypes from 'prop-types'; import { BaseComponent, createRef } from '../../Utilities'; import { StickyPositionType } from './Sticky.types'; var Sticky = /** @class */ (function (_super) { tslib_1.__extends(Sticky, _super); function Sticky(props) { var _this = _super.call(this, props) || this; _this._root = createRef(); _this._stickyContentTop = createRef(); _this._stickyContentBottom = createRef(); _this._nonStickyContent = createRef(); _this.syncScroll = function (container) { var nonStickyContent = _this.nonStickyContent; if (nonStickyContent && _this.props.isScrollSynced) { nonStickyContent.scrollLeft = container.scrollLeft; } }; _this._onScrollEvent = function (container, footerStickyContainer) { if (_this.root && _this.nonStickyContent) { _this.distanceFromTop = _this._getNonStickyDistanceFromTop(container); var isStickyTop = false; var isStickyBottom = false; if (_this.canStickyTop) { var distanceToStickTop = _this.distanceFromTop - _this._getStickyDistanceFromTop(); isStickyTop = distanceToStickTop <= container.scrollTop; } // Can sticky bottom if the scrollablePane - total sticky footer height is smaller than the sticky's distance from the top of the pane if (_this.canStickyBottom && container.clientHeight - footerStickyContainer.offsetHeight <= _this.distanceFromTop) { isStickyBottom = _this.distanceFromTop - container.scrollTop >= _this._getStickyDistanceFromTopForFooter(container, footerStickyContainer); } _this.setState({ isStickyTop: _this.canStickyTop && isStickyTop, isStickyBottom: isStickyBottom }); } }; _this._getStickyDistanceFromTop = function () { var distance = 0; if (_this.stickyContentTop) { distance = _this.stickyContentTop.offsetTop; } return distance; }; _this._getStickyDistanceFromTopForFooter = function (container, footerStickyVisibleContainer) { var distance = 0; if (_this.stickyContentBottom) { distance = container.clientHeight - footerStickyVisibleContainer.offsetHeight + _this.stickyContentBottom.offsetTop; } return distance; }; _this._getNonStickyDistanceFromTop = function (container) { var distance = 0; var currElem = _this.root; if (currElem) { while (currElem && currElem.offsetParent !== container) { distance += currElem.offsetTop; currElem = currElem.offsetParent; } if (currElem.offsetParent === container) { distance += currElem.offsetTop; } } return distance; }; _this.state = { isStickyTop: false, isStickyBottom: false }; _this.distanceFromTop = 0; return _this; } Object.defineProperty(Sticky.prototype, "root", { get: function () { return this._root.current; }, enumerable: true, configurable: true }); Object.defineProperty(Sticky.prototype, "stickyContentTop", { get: function () { return this._stickyContentTop.current; }, enumerable: true, configurable: true }); Object.defineProperty(Sticky.prototype, "stickyContentBottom", { get: function () { return this._stickyContentBottom.current; }, enumerable: true, configurable: true }); Object.defineProperty(Sticky.prototype, "nonStickyContent", { get: function () { return this._nonStickyContent.current; }, enumerable: true, configurable: true }); Object.defineProperty(Sticky.prototype, "canStickyTop", { get: function () { return (this.props.stickyPosition === StickyPositionType.Both || this.props.stickyPosition === StickyPositionType.Header); }, enumerable: true, configurable: true }); Object.defineProperty(Sticky.prototype, "canStickyBottom", { get: function () { return (this.props.stickyPosition === StickyPositionType.Both || this.props.stickyPosition === StickyPositionType.Footer); }, enumerable: true, configurable: true }); Sticky.prototype.componentDidMount = function () { var scrollablePane = this.context.scrollablePane; if (!scrollablePane) { return; } scrollablePane.subscribe(this._onScrollEvent); scrollablePane.addSticky(this); }; Sticky.prototype.componentWillUnmount = function () { var scrollablePane = this.context.scrollablePane; if (!scrollablePane) { return; } scrollablePane.unsubscribe(this._onScrollEvent); scrollablePane.removeSticky(this); }; Sticky.prototype.componentDidUpdate = function (prevProps, prevState) { var scrollablePane = this.context.scrollablePane; if (!scrollablePane) { return; } if (prevState.isStickyTop !== this.state.isStickyTop || prevState.isStickyBottom !== this.state.isStickyBottom) { scrollablePane.updateStickyRefHeights(); } }; Sticky.prototype.shouldComponentUpdate = function (nextProps, nextState) { if (!this.context.scrollablePane) { return true; } var _a = this.state, isStickyTop = _a.isStickyTop, isStickyBottom = _a.isStickyBottom; return (isStickyTop !== nextState.isStickyTop || isStickyBottom !== nextState.isStickyBottom || this.props.stickyPosition !== nextProps.stickyPosition || this.props.children !== nextProps.children); }; Sticky.prototype.render = function () { var _a = this.state, isStickyTop = _a.isStickyTop, isStickyBottom = _a.isStickyBottom; var _b = this.props, stickyClassName = _b.stickyClassName, children = _b.children; if (!this.context.scrollablePane) { return React.createElement("div", null, this.props.children); } return (React.createElement("div", { ref: this._root }, this.canStickyTop && (React.createElement("div", { ref: this._stickyContentTop, "aria-hidden": !isStickyTop, style: { pointerEvents: isStickyTop ? 'auto' : 'none' } }, React.createElement("div", { style: this._getStickyPlaceholderHeight(isStickyTop) }))), this.canStickyBottom && (React.createElement("div", { ref: this._stickyContentBottom, "aria-hidden": !isStickyBottom, style: { pointerEvents: isStickyBottom ? 'auto' : 'none' } }, React.createElement("div", { style: this._getStickyPlaceholderHeight(isStickyBottom) }))), React.createElement("div", { style: this._getNonStickyPlaceholderHeight(), ref: this._root }, React.createElement("div", { ref: this._nonStickyContent, className: isStickyTop || isStickyBottom ? stickyClassName : undefined, style: this._getContentStyles(isStickyTop || isStickyBottom) }, children)))); }; Sticky.prototype.addSticky = function (stickyContent) { if (this.nonStickyContent) { stickyContent.appendChild(this.nonStickyContent); } }; Sticky.prototype.resetSticky = function () { if (this.nonStickyContent && this.root) { this.root.appendChild(this.nonStickyContent); } }; Sticky.prototype.setDistanceFromTop = function (container) { this.distanceFromTop = this._getNonStickyDistanceFromTop(container); }; Sticky.prototype._getContentStyles = function (isSticky) { return { backgroundColor: this.props.stickyBackgroundColor || this._getBackground(), overflow: isSticky ? 'hidden' : '' }; }; Sticky.prototype._getStickyPlaceholderHeight = function (isSticky) { var height = this.nonStickyContent ? this.nonStickyContent.offsetHeight : 0; return { visibility: isSticky ? 'hidden' : 'visible', height: isSticky ? 0 : height }; }; Sticky.prototype._getNonStickyPlaceholderHeight = function () { var _a = this.state, isStickyTop = _a.isStickyTop, isStickyBottom = _a.isStickyBottom; if (isStickyTop || isStickyBottom) { var height = this.nonStickyContent ? this.nonStickyContent.offsetHeight : 0; return { height: height }; } else { return {}; } }; // Gets background of nearest parent element that has a declared background-color attribute Sticky.prototype._getBackground = function () { if (!this.root) { return undefined; } var curr = this.root; while (window.getComputedStyle(curr).getPropertyValue('background-color') === 'rgba(0, 0, 0, 0)' || window.getComputedStyle(curr).getPropertyValue('background-color') === 'transparent') { if (curr.tagName === 'HTML') { // Fallback color if no element has a declared background-color attribute return undefined; } if (curr.parentElement) { curr = curr.parentElement; } } return window.getComputedStyle(curr).getPropertyValue('background-color'); }; Sticky.defaultProps = { stickyPosition: StickyPositionType.Both, isScrollSynced: true }; Sticky.contextTypes = { scrollablePane: PropTypes.object }; return Sticky; }(BaseComponent)); export { Sticky }; //# sourceMappingURL=Sticky.js.map