UNPKG

svelte-ux

Version:

- Increment version in `package.json` and commit as `Version bump to x.y.z` - `npm run publish`

91 lines (90 loc) 3.82 kB
import { keys } from '../types/typeHelpers'; import DomTracker from './_domTracker'; /* TODO - [ ] Consider raising a `stuck` event for styling (example: https://svelte.dev/repl/4ad71e00c86c47d29806e17f09ff0869?version=3.35.0) */ export function sticky(node, options) { // Track changes so they can be reversed on an update const tracker = new DomTracker(node); function update(options) { if (options === undefined) { // Default to top sticky if no options passed options = { top: true }; } // Reset state from last update tracker.reset(); keys(options).forEach((edge) => { var _a; const enabled = (_a = options[edge]) !== null && _a !== void 0 ? _a : false; if (enabled) { // TODO: Could smartly only enable once tracker.addStyle('position', 'sticky'); } if (enabled) { switch (edge) { case 'top': tracker.addStyle('top', `calc(var(--sticky-top, 0px) + ${node.offsetTop}px)` // Add offsetTop to parent (for nested table headers) ); break; case 'bottom': tracker.addStyle('bottom', `calc(var(--sticky-bottom, 0px))`); break; case 'left': // TODO: Determine workaround for reading `node.offsetLeft` having big performance implicaitons tracker.addStyle('left', // `calc(var(--sticky-left, 0px) + ${node.offsetLeft}px)` // Add offsetLeft to parent (for columns after the first) `calc(var(--sticky-left, 0px))`); break; case 'right': tracker.addStyle('right', `calc(var(--sticky-right, 0px))`); break; } } }); } update(options); function destroy() { // Do we always need to reset if being unmounted? tracker.reset(); } return { update, destroy, }; } export function stickyContext(node, options) { var _a; const type = (_a = options === null || options === void 0 ? void 0 : options.type) !== null && _a !== void 0 ? _a : 'page'; function setSticky() { let stickyTop = 0; let stickyBottom = 0; switch (type) { case 'page': const marginTop = getComputedStyle(node).marginTop; // Remove marginTop (offsetTop does not include margins) stickyTop = node.offsetTop - parseInt(marginTop); // If any parent is overflow: 'auto', etc, remove their offset top (as they are the scroll container) let parent = node.parentElement; while (parent) { const overflow = getComputedStyle(parent).overflow; if (overflow !== 'visible') { stickyTop -= parent.offsetTop; } parent = parent.parentElement; } break; case 'container': stickyTop = 0; node.style.setProperty('overflow', 'scroll'); break; default: console.log(`Unexpected type: ${type}`); } // console.log({ stickyTop }); // debugger; node.style.setProperty('--sticky-top', `${stickyTop}px`); // TODO: Calculate stickyBottom offset instead of always 0 (only useful for last row). Tricky as rows can be rendered one at a time (ex. HierarchyTable) node.style.setProperty('--sticky-bottom', `${stickyBottom}px`); } setSticky(); }