Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

affixing-header

Package Overview
Dependencies
Maintainers
1
Versions
11
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

affixing-header - npm Package Compare versions

Comparing version 0.3.3 to 1.0.0-beta.1

dist/affixing-header.d.ts

269

dist/affixing-header.js

@@ -1,124 +0,145 @@

(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('onscrolling')) :
typeof define === 'function' && define.amd ? define(['onscrolling'], factory) :
global.affixingHeader = factory(global.onscrolling)
}(this, function (onscrolling) { 'use strict';
'use strict';
var scrollYPrev = 0,
scrollY = 0,
upScrollCount = 0,
isNavAffixed = false,
isNavTransitioning = false,
documentDimensions = {},
headerDimensions = {},
header,
resizeTimeoutId;
function affixNavBar() {
isNavAffixed = true;
isNavTransitioning = false;
header.style.position = 'fixed';
header.style.top = '0px';
headerDimensions.top = 0;
}
function unAffixNavBar() {
var newHeaderTop = false;
if (!isNavAffixed) {
// Nothing to do here
return;
}
upScrollCount = 0;
isNavAffixed = false;
// Only set top position for switch from fixed absolute if not transitioning
if (!isNavTransitioning) {
// If user jumped down the page (e.g. paging with spacebar)
if (scrollY > scrollYPrev + headerDimensions.height + 5) {
newHeaderTop = scrollYPrev + 5;
} else {
newHeaderTop = scrollY;
}
} else {
isNavTransitioning = false;
}
if (newHeaderTop !== false) {
header.style.top = newHeaderTop + 'px';
headerDimensions.top = newHeaderTop;
}
header.style.position = 'absolute';
}
function checkNavPosition() {
if (!isNavAffixed && headerDimensions.top > scrollY) {
affixNavBar();
}
}
function handleScroll(scrollYCurrent) {
scrollY = scrollYCurrent;
// Make sure that the nav bar doesn't wind up stranded in the middle of the page
checkNavPosition();
// If this is bounce scrolling (e.g. Mac OS, iOS), bail
// Another way to check the top
//(scrollY + window.innerHeight) > document.documentElement.scrollHeight
if (scrollY < 0 || documentDimensions.scrollHeight - documentDimensions.scrollTop < documentDimensions.clientHeight) {
return;
}
if (scrollY < scrollYPrev) {
// If the user has scrolled up quickly / jumped up (like shift-spacebar)
// Or we are transitioning and have reached the top of the bar
if ((!isNavAffixed && scrollY + headerDimensions.height + 10 < scrollYPrev) || isNavTransitioning && scrollY <= headerDimensions.top + 2) {
affixNavBar();
} else if (!isNavAffixed && !isNavTransitioning) {
if (upScrollCount > 6) {
isNavAffixed = true;
// Need header height, so update cached dimensions
headerDimensions.height = header.offsetHeight;
// If the navbar is not currently visible, set the top to just above the viewport so it appears as we scroll up
if (scrollY > headerDimensions.top + headerDimensions.height + 25) {
headerDimensions.top = scrollY - headerDimensions.height - 25;
header.style.top = headerDimensions.top + 'px';
}
isNavTransitioning = true;
}
upScrollCount++;
}
} else if (isNavAffixed) {
unAffixNavBar();
}
scrollYPrev = scrollY;
}
function calculateDimensions() {
documentDimensions.clientHeight = document.documentElement.clientHeight;
documentDimensions.scrollHeight = document.documentElement.scrollHeight;
documentDimensions.scrollTop = document.documentElement.scrollTop;
headerDimensions.height = header.offsetHeight;
}
function onResizeDebouncer() {
if (resizeTimeoutId) {
window.clearTimeout(resizeTimeoutId);
}
window.setTimeout(calculateDimensions, 150);
}
return function(navElement) {
if (!navElement) {
return;
}
// Set initial state
header = navElement;
header.style.position = 'absolute';
header.style.top = '0px';
headerDimensions.top = 0;
// Trigger calculations caching and attach debouncer to resize event
calculateDimensions();
window.addEventListener('resize', onResizeDebouncer);
// Use onscrolling helper to listen for scroll changes
onscrolling(handleScroll);
};
}));
import onscrolling from 'onscrolling';
// Keep track of:
// - state of nav bar
// - scrolling direction
// - “deliberateness” of scroll in current direction (for affixing header, it shouldn't be just a casual slip)
// - state when transitioning for adjusting position
let scrollYPrev = 0;
let scrollY = 0;
let upScrollCount = 0;
let isNavAffixed = false;
let isNavTransitioning = false;
let resizeTimeoutID = null;
let header = null;
let headerDimensions = {};
const documentDimensions = {};
function affixNavBar() {
if (!header)
return;
isNavAffixed = true;
isNavTransitioning = false;
header.style.position = 'fixed';
header.style.top = '0px';
headerDimensions.top = 0;
}
function unaffixNavBar() {
if (!isNavAffixed || !header || headerDimensions.height == null) {
// Nothing to do here
return;
}
let newHeaderTop = null;
upScrollCount = 0;
isNavAffixed = false;
// Only set top position for switch from fixed absolute if not transitioning
if (!isNavTransitioning) {
// If user jumped down the page (e.g. paging with spacebar)
if (scrollY > scrollYPrev + headerDimensions.height + 5) {
newHeaderTop = scrollYPrev + 5;
}
else {
newHeaderTop = scrollY;
}
}
else {
isNavTransitioning = false;
}
if (newHeaderTop != null) {
header.style.top = newHeaderTop + 'px';
headerDimensions.top = newHeaderTop;
}
header.style.position = 'absolute';
}
function checkNavPosition() {
if (!isNavAffixed &&
headerDimensions.top != null &&
headerDimensions.top > scrollY) {
affixNavBar();
}
}
function handleScroll({ scrollY: scrollYCurrent, }) {
scrollY = scrollYCurrent;
// Make sure that the nav bar doesn't wind up stranded in the middle of the page
checkNavPosition();
// Type guard for null values
if (header == null ||
documentDimensions.clientHeight == null ||
documentDimensions.scrollHeight == null ||
documentDimensions.scrollTop == null ||
headerDimensions.height == null ||
headerDimensions.top == null) {
return;
}
// If this is bounce scrolling (e.g. Mac OS, iOS), bail
// Another way to check the top
//(scrollY + window.innerHeight) > document.documentElement.scrollHeight
if (scrollY < 0 ||
documentDimensions.scrollHeight - documentDimensions.scrollTop <
documentDimensions.clientHeight) {
return;
}
if (scrollY < scrollYPrev) {
// If the user has scrolled up quickly / jumped up (like shift-spacebar)
// Or we are transitioning and have reached the top of the bar
if ((!isNavAffixed &&
scrollY + headerDimensions.height + 10 < scrollYPrev) ||
(isNavTransitioning && scrollY <= headerDimensions.top + 2)) {
affixNavBar();
}
else if (!isNavAffixed && !isNavTransitioning) {
if (upScrollCount > 6) {
isNavAffixed = true;
// Need header height, so update cached dimensions
headerDimensions.height = header.offsetHeight;
// If the navbar is not currently visible, set the top to just above the viewport so it appears as we scroll up
if (scrollY > headerDimensions.top + headerDimensions.height + 25) {
headerDimensions.top = scrollY - headerDimensions.height - 25;
header.style.top = headerDimensions.top + 'px';
}
isNavTransitioning = true;
}
upScrollCount++;
}
}
else if (isNavAffixed) {
unaffixNavBar();
}
scrollYPrev = scrollY;
}
function calculateDimensions() {
resizeTimeoutID = null;
documentDimensions.clientHeight = document.documentElement.clientHeight;
documentDimensions.scrollHeight = document.documentElement.scrollHeight;
documentDimensions.scrollTop = document.documentElement.scrollTop;
headerDimensions.height = header === null || header === void 0 ? void 0 : header.offsetHeight;
}
function onResizeDebouncer() {
if (resizeTimeoutID != null) {
window.clearTimeout(resizeTimeoutID);
}
resizeTimeoutID = window.setTimeout(calculateDimensions, 150);
}
export default function (navElement) {
// Set initial state
header = navElement;
const initialHeaderPosition = header.style.position;
const initialHeaderTop = header.style.top;
header.style.position = 'absolute';
header.style.top = '0px';
headerDimensions.top = 0;
// Trigger calculations caching and attach debouncer to resize event
calculateDimensions();
window.addEventListener('resize', onResizeDebouncer);
// Use onscrolling helper to listen for scroll changes
const cleanupOnscrolling = onscrolling(handleScroll, { vertical: true });
return () => {
cleanupOnscrolling();
if (header) {
header.style.position = initialHeaderPosition;
header.style.top = initialHeaderTop;
header = null;
}
headerDimensions = {};
window.removeEventListener('resize', onResizeDebouncer);
};
}
//# sourceMappingURL=affixing-header.js.map
{
"name": "affixing-header",
"version": "0.3.3",
"description": "An affixing header that behaves normally as a user navigates down a page, but reveals itself naturally when a user scrolls or drags upwards. Inspired by iOS Safari, Medium, and others.",
"main": "dist/affixing-header.js",
"jsnext:main": "src/affixing-header.js",
"scripts": {
"test": "npm run build && npm run lint:tests && node test/bootstrap.js",
"test:mocha": "mocha --reporter spec test/bootstrap.js",
"lint:src": "jshint src/affixing-header.js",
"lint:tests": "jshint test/*.js && jshint --extract=auto test/*.html",
"build": "npm run lint:src && npm run build:normal && npm run build:bundle && npm run build:minify",
"build:normal": "esperanto --type umd --name affixingHeader --basedir=node_modules/onscrolling/src/ -i src/affixing-header.js -o dist/affixing-header.js",
"build:bundle": "esperanto --bundle --type umd --name affixingHeader --basedir=node_modules/onscrolling/src/ -i src/affixing-header.js -o dist/affixing-header-bundled.js",
"build:minify": "uglifyjs dist/affixing-header-bundled.js --screw-ie8 --mangle -o dist/affixing-header-bundled-min.js"
},
"repository": {
"type": "git",
"url": "https://github.com/acusti/affixing-header.git"
},
"keywords": [
"scroll",
"header",
"navbar",
"menubar",
"fixed",
"affix",
"browser",
"show-hide"
],
"author": "Andrew Patton <andrew@acusti.ca> (http://www.acusti.ca)",
"license": "CC0",
"bugs": {
"url": "https://github.com/acusti/affixing-header/issues"
},
"homepage": "https://github.com/acusti/affixing-header",
"devDependencies": {
"babel": "^4.7.16",
"chai": "^2.2.0",
"chai-as-promised": "^4.3.0",
"colors": "^1.0.3",
"es6-module-loader": "^0.16.1",
"esperanto": "^0.6.24",
"extend": "^2.0.0",
"finalhandler": "^0.3.4",
"jshint": "^2.6.3",
"mocha": "^2.2.1",
"mocha-multi": "^0.6.0",
"mocha-sauce-notifying-reporter": "0.0.1",
"saucelabs": "^0.1.1",
"selenium-webdriver": "^2.45.1",
"serve-static": "^1.9.2",
"uglify-js": "^2.4.19"
},
"dependencies": {
"onscrolling": "^0.3.0"
},
"jspm": {
"directories": {
"lib": "src"
"name": "affixing-header",
"version": "1.0.0-beta.1",
"description": "An affixing header that behaves normally as a user navigates down a page, but reveals itself naturally when a user scrolls or drags upwards. Inspired by iOS Safari, Medium, and others.",
"type": "module",
"sideEffects": false,
"exports": "./dist/affixing-header.js",
"main": "./dist/affixing-header.js",
"types": "./dist/affixing-header.d.ts",
"files": ["dist"],
"scripts": {
"build": "npm run lint && tsc --build",
"format": "prettier --write .",
"lint": "eslint --cache --cache-location ./node_modules/.cache/eslint .",
"test": "vitest",
"typecheck": "tsc"
},
"main": "affixing-header",
"format": "es6"
}
"repository": {
"type": "git",
"url": "https://github.com/acusti/affixing-header.git"
},
"prettier": {
"arrowParens": "always",
"singleQuote": true,
"printWidth": 84,
"tabWidth": 4,
"trailingComma": "all",
"useTabs": false,
"overrides": [
{
"files": "*.css",
"options": {
"singleQuote": false
}
}
]
},
"keywords": [
"scroll",
"header",
"navbar",
"menubar",
"fixed",
"affix",
"browser",
"show-hide"
],
"author": "Andrew Patton <andrew@acusti.ca> (http://www.acusti.ca)",
"license": "CC0-1.0",
"bugs": {
"url": "https://github.com/acusti/affixing-header/issues"
},
"homepage": "https://github.com/acusti/affixing-header",
"devDependencies": {
"@testing-library/jest-dom": "^6.4.6",
"@typescript-eslint/eslint-plugin": "^7.13.0",
"@typescript-eslint/parser": "^7.13.0",
"@vitest/coverage-v8": "^1.6.0",
"eslint": "^8",
"eslint-config-prettier": "^9.1.0",
"eslint-import-resolver-typescript": "^3.6.1",
"eslint-plugin-cypress": "^3.3.0",
"eslint-plugin-deprecation": "^3.0.0",
"eslint-plugin-import": "^2.29.1",
"eslint-plugin-jest": "^28.6.0",
"eslint-plugin-jest-dom": "^5.4.0",
"eslint-plugin-markdown": "^5.0.0",
"eslint-plugin-testing-library": "^6.2.2",
"eslint-plugin-typescript-sort-keys": "^3.2.0",
"happy-dom": "^14.12.0",
"prettier": "^2.8.0",
"typescript": "^5.3.3",
"vite-tsconfig-paths": "^4.3.2",
"vitest": "^1.6.0"
},
"dependencies": {
"onscrolling": "^2.0.0-beta.5"
}
}

@@ -1,24 +0,21 @@

# Affixing Header&nbsp; [![Build Status](https://travis-ci.org/acusti/affixing-header.svg?branch=master)](https://travis-ci.org/acusti/affixing-header)
# Affixing Header&nbsp; [![build workflow](https://github.com/acusti/affixing-header/actions/workflows/deploy.yml/badge.svg)](https://github.com/acusti/affixing-header/actions)
Create an affixing header that behaves normally as a user navigates down a page, but reveals itself naturally when a user scrolls or drags upwards. Inspired by iOS Safari, Medium, and others. See [an example implementation][acusti.ca] to see what it’s about. Works on desktop and mobile browsers.
[![Sauce Test Status](https://saucelabs.com/browser-matrix/acusti.svg)](https://saucelabs.com/u/acusti)
## Usage
The module itself is available in a wide range of flavors:
The module is ESM-only and exports a single default `affixingHeader` function:
1. As a CommonJS (Browserify-friendly) module (via [UMD]): `dist/affixing-header.js`
2. As an AMD (RequireJS-friendly) module (also via UMD): `dist/affixing-header.js`
3. As the `window.affixingHeader` global with dependencies bundled in: `dist/affixing-header-bundled.js`, or minified as `dist/affixing-header-bundled-min.js`
4. As an ES6/ES2015 module (identified by `jsnext:main` in package.json), compatible with ES6-compatible module loaders like [SystemJS][] or compilers like [Babel][]: `src/affixing-header.js`
### `affixingHeader( element )`
Exports a single function via `require('affixing-header')` if being used with a CommonJS or AMD module loader, or else exposes the function as a global named `window.affixingHeader`.
#### `element` HTMLElement
### `affixingHeader( element )`
The DOM element to which the affixing behavior should be attached. Must be a single `HTMLElement` (e.g., the result of `document.querySelector` or `document.getElementById`), not a `NodeList`.
#### `element` Element
### affixingHeader return value
The DOM element to which the affixing behavior should be attached. Must be a single Element (e.g., the result of `document.querySelector` or `document.getElementById`), not a `NodeList`.
#### `affixingHeader` function `(element: HTMLElement) => () => void`
The `affixingHeader` function returns a cleanup function that takes no arguments and is used to remove listeners and cleanup the affixing behavior.
### Dependencies

@@ -30,10 +27,7 @@

The scroll handling uses `requestAnimationFrame`, which is [only available in IE10+][raf-caniuse]. For older browsers, your header won’t affix to the top of the page when you scroll up, but you shouldn’t see any other issues (yay progressive enhancement). To add full support for older browsers, just include a [requestAnimationFrame polyfill][raf-polyfill].
The scroll handling uses `requestAnimationFrame`, which is [only available in IE10+][raf-caniuse]. To add full support for older browsers, just include a [requestAnimationFrame polyfill][raf-polyfill].
[acusti.ca]: http://www.acusti.ca
[UMD]: https://github.com/umdjs/umd
[SystemJS]: https://github.com/systemjs/systemjs
[Babel]: https://babeljs.io
[onscrolling]: https://github.com/acusti/onscrolling
[raf-caniuse]: http://caniuse.com/#feat=requestanimationframe
[raf-polyfill]: https://gist.github.com/paulirish/1579671
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc