UNPKG

lucid-ui

Version:

A UI component library from Xandr.

225 lines 10.2 kB
"use strict"; var __extends = (this && this.__extends) || (function () { var extendStatics = function (d, b) { extendStatics = Object.setPrototypeOf || ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; return extendStatics(d, b); }; return function (d, b) { if (typeof b !== "function" && b !== null) throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); extendStatics(d, b); function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; })(); var __assign = (this && this.__assign) || function () { __assign = Object.assign || function(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __rest = (this && this.__rest) || function (s, e) { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]]; } return t; }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); var lodash_1 = __importStar(require("lodash")); var react_1 = __importDefault(require("react")); var prop_types_1 = __importDefault(require("prop-types")); var style_helpers_1 = require("../../util/style-helpers"); var dom_helpers_1 = require("../../util/dom-helpers"); var cx = style_helpers_1.lucidClassNames.bind('&-StickySection'); var node = prop_types_1.default.node, number = prop_types_1.default.number, object = prop_types_1.default.object, string = prop_types_1.default.string; var StickySection = /** @class */ (function (_super) { __extends(StickySection, _super); function StickySection() { var _this = _super !== null && _super.apply(this, arguments) || this; _this.scrollContainer = react_1.default.createRef(); _this.stickySection = react_1.default.createRef(); _this.stickyFrame = react_1.default.createRef(); _this.state = { isAboveFold: false, containerRect: { bottom: 0, height: 0, left: 0, right: 0, top: 0, width: 0, frameLeft: 0, scrollWidth: 0, }, }; _this.handleScroll = function () { var _a = _this.props, lowerBound = _a.lowerBound, _b = _a.topOffset, topOffset = _b === void 0 ? 0 : _b; var _c = _this.state, isAboveFold = _c.isAboveFold, containerRect = _c.containerRect; var nextContainerRect = _this.getContainerRect(); if (window.pageYOffset + topOffset >= nextContainerRect.top) { if (!isAboveFold) { _this.setState({ isAboveFold: true, }); } } else { if (isAboveFold) { _this.setState({ isAboveFold: false, }); } } if (lodash_1.default.isNumber(lowerBound) && window.pageYOffset >= lowerBound) { _this.setState({ isAboveFold: false, }); } if (containerRect.bottom !== nextContainerRect.bottom || containerRect.height !== nextContainerRect.height || containerRect.left !== nextContainerRect.left || containerRect.right !== nextContainerRect.right || containerRect.top !== nextContainerRect.top || containerRect.width !== nextContainerRect.width || containerRect.scrollWidth !== nextContainerRect.scrollWidth || containerRect.frameLeft !== nextContainerRect.frameLeft) { _this.setState({ containerRect: nextContainerRect, }); } }; _this.getContainerRect = function () { var containerRect = (0, dom_helpers_1.getAbsoluteBoundingClientRect)(_this.scrollContainer.current); var stickyRect = _this.stickySection.current.getBoundingClientRect(); var frameRect = _this.stickyFrame.current.getBoundingClientRect(); return { bottom: containerRect.top + stickyRect.height, height: stickyRect.height, left: containerRect.left, right: containerRect.left + stickyRect.width, top: containerRect.top, scrollWidth: _this.stickySection.current.scrollWidth, width: containerRect.width, frameLeft: frameRect.left, }; }; return _this; } StickySection.prototype.componentDidMount = function () { var _this = this; setTimeout(function () { _this.setState({ containerRect: _this.getContainerRect(), }); _this.handleScroll(); }, 1); window.addEventListener('scroll', this.handleScroll, true); }; StickySection.prototype.componentWillUnmount = function () { window.removeEventListener('scroll', this.handleScroll, true); }; StickySection.prototype.render = function () { var _a = this.props, children = _a.children, className = _a.className, style = _a.style, _b = _a.topOffset, topOffset = _b === void 0 ? 0 : _b, viewportWidth = _a.viewportWidth, passThroughs = __rest(_a, ["children", "className", "style", "topOffset", "viewportWidth"]); var _c = this.state, isAboveFold = _c.isAboveFold, containerRect = _c.containerRect; return (react_1.default.createElement("div", __assign({}, (0, lodash_1.omit)(passThroughs, [ 'lowerBound', 'topOffset', 'initialState', 'callbackId', ]), { className: cx('&', className), style: __assign(__assign({}, (isAboveFold ? { height: containerRect.height, visibility: 'hidden', } : {})), style), ref: this.scrollContainer }), react_1.default.createElement("div", { className: cx('&-sticky-frame'), ref: this.stickyFrame, style: __assign(__assign({}, (isAboveFold ? { visibility: 'visible', position: 'fixed', top: topOffset, width: lodash_1.default.isNumber(viewportWidth) ? viewportWidth : containerRect.width, height: containerRect.height, overflow: 'hidden', } : {})), style) }, react_1.default.createElement("div", { className: cx('&-sticky-section'), ref: this.stickySection, style: __assign(__assign({}, (isAboveFold ? { position: 'absolute', top: 0, left: containerRect.left - containerRect.frameLeft || 0, width: containerRect.scrollWidth, height: containerRect.height, } : { position: 'relative', })), style) }, children)))); }; StickySection.displayName = 'StickySection'; StickySection.peek = { description: "`StickySection` can be wrapped around any content to make it _stick_ to the top edge of the screen when a user scrolls beyond its initial location.", categories: ['helpers'], }; StickySection.propTypes = { /** any valid React children */ children: node, /** Appended to the component-specific class names set on the root element. */ className: string, /** Styles that are passed through to the root container. */ style: object, /** Pixel value from the top of the document. When scrolled passed, the sticky header is no longer sticky, and renders normally. */ lowerBound: number, /** Top offset threshold before sticking to the top. The sticky content will display with this offset. */ topOffset: number, }; return StickySection; }(react_1.default.Component)); exports.default = StickySection; //# sourceMappingURL=StickySection.js.map