office-ui-fabric-react
Version:
Reusable React components for building experiences for Office 365.
234 lines • 10.5 kB
JavaScript
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