UNPKG

@eccenca/gui-elements

Version:

GUI elements based on other libraries, usable in React application, written in Typescript.

126 lines 7.35 kB
"use strict"; 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 }); exports.StickyTarget = void 0; const react_1 = __importDefault(require("react")); const common_1 = require("../../common/"); const constants_1 = require("../../configuration/constants"); /** * Element wraps the content that need to be displayed sticky. * The content then offset relative to its nearest scrolling ancestor and containing block (nearest block-level ancestor). */ const StickyTarget = (_a) => { var { className, to = "top", local = false, offset, background = "transparent", fillMainGap, fillSecondaryGap, style, getConnectedElement } = _a, otherDivProps = __rest(_a, ["className", "to", "local", "offset", "background", "fillMainGap", "fillSecondaryGap", "style", "getConnectedElement"]); const stickyTargetRef = react_1.default.useRef(null); let offsetStyle = {}; if (typeof offset !== "undefined") { offsetStyle = Object.assign(Object.assign({}, style), { "--eccgui-sticky-target-localoffset": offset }); } react_1.default.useEffect(() => { let removeEventForConnectedOffset = () => { /* no event need to be removed */ }; let removeEventForStickynessCheck = () => { /* no event need to be removed */ }; /** * If the target should be sticky to a defined element then: * * check for the element and its scroll parent * * listen to scroll events and use the elements position as offset */ if (getConnectedElement && stickyTargetRef) { const stickyConnection = getConnectedElement(stickyTargetRef); if (stickyConnection) { const scrollParent = common_1.utils.getScrollParent(stickyConnection); const scrollParentFallback = !scrollParent ? document.documentElement : false; if (scrollParent || scrollParentFallback) { const updateTargetOffset = () => { var _a; let connectedOffset = 0; const scrollParentPosition = (scrollParent || scrollParentFallback).getBoundingClientRect(); const stickyConnectionPosition = stickyConnection.getBoundingClientRect(); if (to === "top") { connectedOffset = stickyConnectionPosition.top - Math.max(0, scrollParentPosition.top) + stickyConnectionPosition.height; } if (to === "bottom") { connectedOffset = Math.max(scrollParentPosition.height, scrollParentPosition.bottom) - stickyConnectionPosition.bottom + stickyConnectionPosition.height; } (_a = stickyTargetRef.current) === null || _a === void 0 ? void 0 : _a.style.setProperty("--eccgui-sticky-target-applicationoffset", `${connectedOffset}px`); }; updateTargetOffset(); const eventListeningTarget = scrollParent || window; const eventListeningMethod = (_event) => { updateTargetOffset(); }; eventListeningTarget.addEventListener("scroll", eventListeningMethod); removeEventForConnectedOffset = () => { eventListeningTarget.removeEventListener("scroll", eventListeningMethod); }; } } } /** * Check if sticky target element is currently in sticky mode. * sticky mode = current position === defined sticky position */ if (stickyTargetRef && (fillMainGap || fillSecondaryGap)) { const stickyTarget = stickyTargetRef.current; const scrollParent = common_1.utils.getScrollParent(stickyTarget); const checkStickyness = () => { const definedPosition = parseInt(window.getComputedStyle(stickyTarget)[to], 10); const scrollParentPosition = scrollParent ? scrollParent.getBoundingClientRect()[to] : 0; const currentPosition = (to === "top" ? 1 : -1) * (stickyTarget.getBoundingClientRect()[to] - scrollParentPosition); // check stickyness in a small position range (not exact value) because of float values const isSticky = currentPosition <= definedPosition + 1 && currentPosition >= definedPosition - 1; if (isSticky && !stickyTarget.classList.contains(`${constants_1.CLASSPREFIX}-sticky__target--issticky`)) { stickyTarget.classList.add(`${constants_1.CLASSPREFIX}-sticky__target--issticky`); } if (!isSticky && stickyTarget.classList.contains(`${constants_1.CLASSPREFIX}-sticky__target--issticky`)) { stickyTarget.classList.remove(`${constants_1.CLASSPREFIX}-sticky__target--issticky`); } }; checkStickyness(); const eventListeningTarget = scrollParent || window; const eventListeningMethod = (_event) => { checkStickyness(); }; eventListeningTarget.addEventListener("scroll", eventListeningMethod); removeEventForStickynessCheck = () => { eventListeningTarget.removeEventListener("scroll", eventListeningMethod); }; } return () => { removeEventForConnectedOffset(); removeEventForStickynessCheck(); }; }, [getConnectedElement, stickyTargetRef, to, fillMainGap, fillSecondaryGap]); return (react_1.default.createElement("div", Object.assign({ ref: stickyTargetRef, className: `${constants_1.CLASSPREFIX}-sticky__target` + (to ? ` ${constants_1.CLASSPREFIX}-sticky__target--${to}` : "") + (local ? ` ${constants_1.CLASSPREFIX}-sticky__target--localscrollarea` : "") + (background ? ` ${constants_1.CLASSPREFIX}-sticky__target--bg-${background}` : "") + (fillMainGap ? ` ${constants_1.CLASSPREFIX}-sticky__target--maingapfill-${fillMainGap}` : "") + (fillSecondaryGap ? ` ${constants_1.CLASSPREFIX}-sticky__target--secondarygapfill-${fillSecondaryGap}` : "") + (className ? ` ${className}` : ""), style: offset ? offsetStyle : style }, otherDivProps))); }; exports.StickyTarget = StickyTarget; exports.default = exports.StickyTarget; //# sourceMappingURL=StickyTarget.js.map