All Projects → spring-media → sticky-observer

spring-media / sticky-observer

Licence: MIT license
A simple and basic sticky observer (or watcher) on HTMLElement's in a given container

Programming Languages

typescript
32286 projects
javascript
184084 projects - #8 most used programming language

Projects that are alternatives of or similar to sticky-observer

svelte-inview
A Svelte action that monitors an element enters or leaves the viewport.🔥
Stars: ✭ 358 (+984.85%)
Mutual labels:  observer
SwiftObserver
Elegant Reactive Primitives for Clean Swift Architecture #NoRx
Stars: ✭ 14 (-57.58%)
Mutual labels:  observer
react-sticky-headroom
A React Component to hide a Header using CSS sticky position
Stars: ✭ 22 (-33.33%)
Mutual labels:  sticky
Textylic
A note taking app developed for the 22nd century
Stars: ✭ 34 (+3.03%)
Mutual labels:  sticky
go-mq
Declare AMQP entities like queues, producers, and consumers in a declarative way. Can be used to work with RabbitMQ.
Stars: ✭ 76 (+130.3%)
Mutual labels:  rabbit
patterns
Good practices to create code in Java, open to other languages. ⚡
Stars: ✭ 14 (-57.58%)
Mutual labels:  observer
AppFacadeMVC
AppFacade For PureMVC
Stars: ✭ 13 (-60.61%)
Mutual labels:  observer
uot
🦁 A tiny setTimeout alternative with progress.
Stars: ✭ 43 (+30.3%)
Mutual labels:  observer
uon
🐨 A tiny 200b route change observer.
Stars: ✭ 83 (+151.52%)
Mutual labels:  observer
mr-Observer
An observer is a wrapper over JSON data, that provides an interface to know when data is changed, with a focus on performance and memory efficiency.
Stars: ✭ 22 (-33.33%)
Mutual labels:  observer
node-reactive-postgres
Reactive queries for PostgreSQL
Stars: ✭ 28 (-15.15%)
Mutual labels:  observer
react-sticky-mouse-tooltip
React tooltip component that follow mouse cursor.
Stars: ✭ 17 (-48.48%)
Mutual labels:  sticky
react-sticky-header
🍯 A sticky header for React.js
Stars: ✭ 55 (+66.67%)
Mutual labels:  sticky
GitHub-FixedHeader
Pinned header on GitHub
Stars: ✭ 63 (+90.91%)
Mutual labels:  sticky
admin-sticky-widget-areas
A simple WordPress plugin to make the widget areas on the right side at /wp-admin/widgets.php sticky.
Stars: ✭ 22 (-33.33%)
Mutual labels:  sticky
TOFileSystemObserver
A bullet-proof mechanism for detecting any changes made to the contents of a folder in iOS and macOS.
Stars: ✭ 35 (+6.06%)
Mutual labels:  observer
ecommerce
Arquitectura de Microservicios - 2018
Stars: ✭ 22 (-33.33%)
Mutual labels:  rabbit
react-use-observer
Performant react hooks for WebApi Observers, useResizeObserver, useInteractionObserver, useMutationObserver
Stars: ✭ 19 (-42.42%)
Mutual labels:  observer
vue-sticky
模拟 position: sticky; 的 vue 组件
Stars: ✭ 30 (-9.09%)
Mutual labels:  sticky
go-observer
Go package for simplifying channel-based broadcasting of events from multiple publishers to multiple observers
Stars: ✭ 66 (+100%)
Mutual labels:  observer

sticky-observer CircleCI

npm codecov dep GitHub license

A simple and easy to use sticky observer (or watcher) on HTMLElement's in a designated container. When scrolling or resizing the window sticky-observer will tell you if an element is STICKY, STICKY_END_OF_CONTAINER or NORMAL. This library does NOT include any preconfigured styling or positioning options, what happens when and how is left up to the you to configure with the help of some included helper functions.

Bring-Your-Own-Styling (BYOS)

This library was heavily inspired by sticky-js, it uses the same calculations and exhibits the same internal behaviour but due to it being completely unstyled it fits a different use case, all styling is left up to the you (BYOS).

Features

  • Full control over styling/positioning/placeholder. NO magic BUT more work for you.
  • Observing still works correctly with dynamic (out of control) appended container (ads)
  • Written in TypeScript
  • No dependencies
  • Fully tested
  • Small (cjs: 6.78 KB / 1.75 KB gzip) (esm: 5.88 KB / 1.59 KB gzip)

Demo

This library is in production on welt.de for a few main features.

  1. Sticky Page-Header (desktop only): Demo
  2. Sticky Video-Player (desktop only): Demo
  3. Sticky Social-Bar (mobile and desktop): Demo

Install

# via NPM
npm install @welt/sticky-observer
# via yarn
yarn add @welt/sticky-observer

Usage example

<div class="container"><div class="sticky-element" data-sticky-class="sticky-element--is-sticky">example</div></div>
import { StickyObserver } from '@welt/sticky-observer';

const stickyContainer = document.querySelector('.container');
const stickyElement = document.querySelector('.sticky-element');

const stickyObserver = new StickyObserver([stickyElement], stickyContainer);
stickyObserver.init();

stickyObserver.onStateChange(event => {
  switch (event.nextState) {
    case 'STICKY':
      event.element.sticky.addStickyClass();
      event.element.sticky.addPlaceholder();
      break;
    case 'NORMAL':
      event.element.sticky.removeStickyClass();
      event.element.sticky.removePlaceholder();
      break;
    default:
      // ignore
      break;
  }
});

stickyObserver.observe();

Options

new StickyObserver([stickyElement], stickyContainer, { offsetTop: 20, offsetBottom: 20 });

Each sticky-element can be configured with a few options via HTML [data-*] attributes. All configuration options are optional.

<div class="container">
  <!--
    [data-sticky-class]
    Css class to add when calling `addStickyClass()`. See API section.

    [data-sticky-placeholder-class]
    Css class to add when calling `addPlaceholder()` and [data-sticky-placeholder-auto-height] is `false`. See API section.

    [data-sticky-placeholder-auto-height]
    When calling `addPlaceholder()` a `<div/>` is added to the DOM with the same height of the sticky element.
    With this option you can disable the auto height and add your own css class for example.

    [data-sticky-offset-top]
    The top offset takes part in the 'NORMAL' to 'STICKY' calculation.
    With the offset you have some more control over the 'sticky breakpoint'. You can 'move' it up and down.
    The value must be a number without any units.

    [data-sticky-offset-bottom]
    The bottom offset takes part in the 'STICKY' to 'STICKY_END_OF_CONTAINER' calculation.
    With the offset you have some more control over the 'sticky breakpoint'. You can 'move' it up and down.
    The value must be a number without any units.
  -->
  <div
    class="sticky-element"
    data-sticky-class="sticky-element--is-sticky"
    data-sticky-placeholder-class="sticky-element__placeholder"
    data-sticky-placeholder-auto-height="false"
    data-sticky-offset-top="-20"
    data-sticky-offset-bottom="-20"
  >
    example
  </div>
</div>

API

// StickyObserver API

// Creating a new instance
// [stickyElement]: Array of HTMLElement
// stickyContainer: HTMLElement
// options: optional options (see: Options section)
const stickyObserver = new StickyObserver([stickyElement], stickyContainer, options);

// Mandatory
// Lazy initialize function. Binds all internal listeners but does not start the observer.
stickyObserver.init();

// Mandatory
// Starts the observer and notifies the listeners of any updates/changes/resizes.
stickyObserver.observe();

// All global listeners are still active but does not notify the listeners of any updates/changes/resizes.
stickyObserver.pause();

// Removes all global and element listeners. Deletes the `sticky` property of each sticky element
stickyObserver.destroy();

// Register a callback function to listen for (unique) state changes only (one event per change/transition).
// A basic flow is: NORMAL (start) -> STICKY -> STICKY_END_OF_CONTAINER
stickyObserver.onStateChange(stickyEvent => {});

// Register a callback function to listen for all window scroll and resize events (not throttled)
stickyObserver.onUpdate(stickyEvent => {});

// Register a callback function to listen for all window resize events only (not throttled)
stickyObserver.onResize(stickyEvent => {});

// Is the sticky observer still active.
// (boolean)
const isActive = stickyObserver.isActive();
// StickyState types
stickyObserver.onStateChange(stickyEvent => {
  // element is in default/non-sticky state
  const isNormal = stickyEvent.nextState === 'NORMAL';

  // element is in sticky state
  const isSticky = stickyEvent.nextState === 'STICKY';

  // element is below the the sticky container
  const isStickyEndOfContainer = stickyEvent.nextState === 'STICKY_END_OF_CONTAINER';
});
// StickyEvent API
stickyObserver.onStateChange(stickyEvent => {
  // The previous state of the sticky element
  // (string)
  const prevState = stickyEvent.prevState;

  // The next or updated/current state of the sticky element
  // (string)
  const nextState = stickyEvent.nextState;

  // The native HTMLElement with a `sticky` property for more options.
  // (HTMLElement)
  const element = stickyEvent.element;

  // The current scroll position based on `window.pageYOffset`
  // (number)
  const scrollTop = stickyEvent.scrollTop;
});
// Sticky element API
stickyObserver.onStateChange(stickyEvent => {
  const sticky = stickyEvent.element.sticky;

  // The offset top value used for the sticky calculation.
  // (number)
  const offsetTop = sticky.offsetTop;

  // The offset bottom value used for the sticky calculation.
  // (number)
  const offsetBottom = sticky.offsetBottom;

  // The default height of the element in a non-sticky state.
  // This is useful for an additional placeholder somewhere.
  // (number)
  const nonStickyHeight = sticky.nonStickyHeight;

  // Containing the `width`, `height`, `top` and `left` of the sticky element.
  // This is important for styling.
  // (object)
  const rect = sticky.rect;

  // Reference to the sticky container element
  // (HTMLElement)
  const container = sticky.container;

  // Containing the `width`, `height`, `top` and `left` of the sticky container element.
  // (object)
  const containerRect = sticky.container.rect;

  // Active state of the sticky element.
  // (boolean)
  const active = sticky.active;

  // Current state of the sticky element.
  // (string)
  const state = sticky.state;

  // Configured sticky class
  // (string)
  const stickyClass = sticky.stickyClass;

  // Configured placeholder class
  // (string)
  const placeholderClass = sticky.placeholderClass;

  // Configured placeholder auto height
  // (boolean)
  const placeholderAutoHeight = sticky.placeholderAutoHeight;

  // Adding the css class to the sticky element.
  // (null safe)
  sticky.addClass('some-special-class');

  // Removes the css class from the sticky element.
  // It does not throw an error when a class is not present
  sticky.removeClass('some-special-class');

  // Adds a configured sticky class.
  // When no sticky class is configured it does nothing
  sticky.addStickyClass();

  // Removes the configured sticky class.
  // When no sticky class is configured it does nothing
  sticky.removeStickyClass();

  // Adds a configured placeholder class.
  // When no placeholder class is configured it does nothing.
  sticky.addPlaceholder();

  // Removes the configured placeholder class.
  // When no placeholder class is configured it does nothing.
  sticky.removePlaceholder();
});

Usage standalone Browser version

See Demo

Browser support

This library is transpiled to ES5 without any special / custom browser API. This means:

  • in order for it to work on IE11 you must include the classList polyfill

Sticky-element works on all other major browsers.

Build

yarn install
yarn build

Test + Coverage

# You need a locally installed Chrome
yarn test

Release

The npm and GitHub releases are triggered manually (via release-it)

# You need a valid GITHUB_TOKEN
# See: https://github.com/webpro/release-it#github-releases
yarn publish

License

MIT

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].