tiny-essentials
Version:
Collection of small, essential scripts designed to be used across various projects. These simple utilities are crafted for speed, ease of use, and versatility.
524 lines (315 loc) โข 12.3 kB
Markdown
# ๐ฆ `TinySmartScroller` Class
A utility class for managing smart scroll behavior in DOM containers or the window. Ideal for dynamic content like chat UIs or live feeds.
## ๐งฉ Typedefs
### ๐งฑ `NodeSizes`
```js
type NodeSizes = { height: number, width: number };
```
Represents the **dimensions of a DOM element** in pixels.
### ๐ `NodeSizesEvent`
```js
type NodeSizesEvent = (elem, sizes, elemAmount) => NodeSizes | undefined;
```
A **callback function** used to compare previous and current element sizes, optionally returning custom size adjustments.
* `elem`: the DOM element.
* `sizes.old`: previous size.
* `sizes.now`: current size.
* `elemAmount.old` / `elemAmount.now`: number of matching elements before/after.
### ๐ก `ScrollListenersFunc`
```js
type ScrollListenersFunc = (payload: any) => void;
```
A generic **scroll event callback function**.
## ๐๏ธ Constructor
### โ
`new TinySmartScroller(target, options?)`
Initializes a new smart scroller instance.
```js
const scroller = new TinySmartScroller(document.querySelector('.chatbox'), {
autoScrollBottom: true,
observeMutations: true,
preserveScrollOnLayoutShift: true,
debounceTime: 100,
querySelector: '.message',
});
```
### ๐ง Options:
| Option | Type | Default | Description | |
| ----------------------------- | --------------------- | ----------- | -------------------------------------------------------------------- | ----------------------------------------- |
| `extraScrollBoundary` | `number` | `0` | Adds extra margin for scroll edge detection | |
| `autoScrollBottom` | `boolean` | `true` | Auto-scroll to bottom on updates | |
| `observeMutations` | `boolean` | `true` | Uses MutationObserver to detect DOM changes | |
| `preserveScrollOnLayoutShift` | `boolean` | `true` | Prevents jumps in scroll position due to layout shifts | |
| `debounceTime` | `number` | `100` | Debounce time (ms) for scroll processing | |
| `querySelector` | \`string | null\` | `null` | Filters which children should be observed |
| `attributeFilter` | `string[]\|Set\|null` | Default set | Which attributes to track for mutations (e.g., `src`, `style`, etc.) | |
## ๐ Size Helpers
### ๐ `getSimpleOnHeight(filter = [])`
Returns a size filter function that only compares height difference for allowed tags.
```js
const filter = scroller.getSimpleOnHeight(['IMG', 'VIDEO']);
```
#### โ
Use when:
* You want to track layout shifts that affect only **vertical space**.
* You want to limit updates by tag name (like images or videos only).
### โ `addSimpleOnHeight(filter)`
Same as `getSimpleOnHeight()`, but **registers the filter** into the scroll system.
```js
scroller.addSimpleOnHeight(['IFRAME']);
```
## ๐ผ๏ธ Load Tags Management
These are used to determine **which tags can trigger scroll corrections** when they load (e.g., images expanding).
### ๐ `getLoadTags()`
Returns a list of currently tracked **load-sensitive tag names**.
```js
const tags = scroller.getLoadTags(); // ['IMG', 'IFRAME', 'VIDEO']
```
### โ `addLoadTag(tag)`
Adds a tag to the **load tracking set**.
```js
scroller.addLoadTag('AUDIO');
```
### โ `removeLoadTag(tag)`
Removes a tag from the load tracking set.
```js
scroller.removeLoadTag('IFRAME');
```
### โ `hasLoadTag(tag)`
Checks if a tag is being tracked.
```js
scroller.hasLoadTag('IMG'); // true
```
### โป๏ธ `resetLoadTags(addDefault = false)`
Clears the load tags. If `addDefault` is true, resets to: `'IMG'`, `'IFRAME'`, `'VIDEO'`.
```js
scroller.resetLoadTags(true);
```
## ๐งฌ Attribute Filters Management
Used by the MutationObserver to watch **specific attribute changes**.
### ๐ `getAttributeFilters()`
Returns the current list of tracked attributes.
```js
scroller.getAttributeFilters(); // ['class', 'style', 'src', ...]
```
### โ `addAttributeFilter(attr)`
Adds an attribute to the filter set.
```js
scroller.addAttributeFilter('data-src');
```
### โ `removeAttributeFilter(attr)`
Removes an attribute from the filter set.
```js
scroller.removeAttributeFilter('style');
```
### โ `hasAttributeFilter(attr)`
Checks if an attribute is being watched.
```js
scroller.hasAttributeFilter('src'); // true
```
### โป๏ธ `resetAttributeFilters(addDefault = false)`
Clears attribute filters. If `addDefault` is true, resets to:
```js
['class', 'style', 'src', 'data-*', 'height', 'width']
```
## ๐ง Size Filter Handlers
### ๐ช `onSize(handler)`
Registers a custom handler to observe changes in element size.
```js
scroller.onSize((elem, sizes) => {
if (sizes.now.height > sizes.old.height) {
return { height: sizes.now.height - sizes.old.height, width: 0 };
}
});
```
* ๐ **Throws** if `handler` is not a function.
* ๐ซ Does nothing if the instance is destroyed.
### โ `offSize(handler)`
Removes a previously registered size change handler.
```js
scroller.offSize(mySizeHandler);
```
* ๐ **Throws** if `handler` is not a function.
* ๐ซ Does nothing if the instance is destroyed.
## ๐ฃ๏ธ Scroll Event Listeners
### ๐งท `on(event, handler)`
Registers a scroll-related listener.
```js
scroller.on('onAutoScroll', (payload) => {
console.log('Auto-scrolling triggered!', payload);
});
```
* ๐ **Valid events**:
`onScrollBoundary`, `onAutoScroll`, `onScrollPause`, `onExtraScrollBoundary`
* ๐ **Throws** if `event` is not a string or `handler` is not a function.
### โ `off(event, handler)`
Removes a scroll event listener.
```js
scroller.off('onAutoScroll', myListener);
```
* ๐ **Throws** if `event` is not a string or `handler` is not a function.
## ๐๏ธโ๐จ๏ธ Visibility Map Updater
### ๐ `_scrollDataUpdater()`
Scans visible elements and tracks visibility changes internally.
```js
const result = scroller._scrollDataUpdater();
// Map<Element, { oldIsVisible: boolean, isVisible: boolean }>
```
* โ
Returns a `Map` of visibility states for each target element.
## ๐ Internal Event Emission
### ๐ฃ `_emit(event, payload?)`
Calls all registered handlers for the specified scroll event.
```js
scroller._emit('onAutoScroll', { debug: true });
```
* ๐ **Throws** if `event` is not a string.
* ๐ซ Does nothing if the instance is destroyed.
## ๐ Scroll Position Evaluation
### ๐ข `_onScroll()`
Handles scroll updates, boundary detection, and emits relevant events:
```js
// Emits:
'onScrollBoundary'
'onExtraScrollBoundary'
'onAutoScroll'
'onScrollPause'
```
* ๐ Updates scroll direction states like `isAtBottom`, `isAtTop`.
* ๐ง Determines whether to pause or continue auto-scroll.
## ๐ง Scroll Correction on Layout Shifts
### ๐ช `_fixScroll(targets = [])`
Attempts to correct scroll position after layout changes (like image loading or content insertion).
```js
scroller._fixScroll([imgElement]);
```
* ๐ Measures height & width delta using `ResizeObserver` entries.
* ๐ Preserves scroll position intelligently unless scrolled to bottom.
* ๐ Throws if invalid return types are found in size handlers.
## ๐งฌ Mutation Observer Setup
### ๐ `_observeMutations()`
Initializes a `MutationObserver` to watch child mutations and trigger scroll adjustments.
* ๐ฏ Watches:
* Element insertion/removal
* Attribute changes (filtered)
* ๐ Automatically sets up `ResizeObserver` and load listeners on new elements.
## ๐ Resize Observer Setup
### ๐งฟ `_observeResizes(elements)`
Applies a `ResizeObserver` to elements for layout shift tracking.
```js
scroller._observeResizes(document.querySelectorAll('.message'));
```
* ๐ฏ Updates size maps (`#oldSizes`, `#newSizes`)
* ๐ Throws if `ResizeObserver` is missing or invalid.
## ๐ก Load Event Listener for Media
### ๐ฌ `_listenLoadEvents(elements)`
Tracks loading of elements like `IMG`, `IFRAME`, and `VIDEO`.
```js
scroller._listenLoadEvents(imgElement);
```
* โณ Listens for the `load` event.
* โ
Triggers scroll updates and auto-scroll when media finishes loading.
* โ
Honors load tags set by `addLoadTag()`.
## ๐งฑ DOM and Element Accessors
### ๐ฏ `target`
Returns the internal scroll container element being monitored.
```js
const container = scroller.target;
```
* ๐ Returns the target DOM element (or `window` if in window mode).
### ๐ต๏ธโโ๏ธ `getOldSize(el)`
Gets the previous recorded size of an element.
```js
scroller.getOldSize(myDiv); // โ { height: 120, width: 300 }
```
* โ Returns `null` if the element wasn't tracked.
### ๐ `getNewSize(el)`
Gets the most recent measured size of an element.
```js
scroller.getNewSize(myDiv); // โ { height: 150, width: 300 }
```
* โ Returns `null` if the element wasn't tracked.
## ๐๏ธ Visibility Status Checkers
### ๐ `wasVisible(el)`
Returns `true` if the element was visible during the last scroll update.
### ๐ `isVisible(el)`
Returns `true` if the element is currently visible in the scroll view.
### โฑ๏ธ `wasTimedVisible(el)`
Returns visibility based on the previous **timed** visibility update.
### โ `isTimedVisible(el)`
Returns visibility based on the current **timed** visibility update.
## ๐ Scroll Configuration and Info
### โ `setExtraScrollBoundary(pixels)`
Defines a custom pixel margin for top/bottom boundary detection.
```js
scroller.setExtraScrollBoundary(50);
```
* ๐ Throws if not a valid number.
### ๐ `getExtraScrollBoundary()`
Returns the currently defined extra scroll boundary in pixels.
### ๐ `getLastKnownScrollBottomOffset()`
Gets the last recorded scroll distance from the bottom (in pixels).
### โฌ๏ธ `scrollToBottom()`
Scrolls the target all the way to the bottom immediately.
### โฌ๏ธ `scrollToTop()`
Scrolls the target all the way to the top immediately.
## ๐งญ Scroll Position Status
### ๐ `isAtCustomBottom()`
Returns `true` if the user is within the custom boundary of the bottom.
### ๐ `isAtCustomTop()`
Returns `true` if the user is within the custom boundary of the top.
### ๐งจ `isAtBottom()`
Returns `true` if user is currently scrolled to the actual bottom.
### ๐งท `isAtTop()`
Returns `true` if user is currently scrolled to the actual top.
### โธ๏ธ `isScrollPaused()`
Returns `true` if auto-scroll is currently paused.
## ๐ป Internal Engine Status
### ๐ `isWindow()`
Returns `true` if the scroll target is the `window` object.
### ๐ `isDestroyed()`
Returns `true` if the instance has already been destroyed.
### ๐ `getAutoScrollBottom()`
Returns whether auto-scroll-to-bottom is active.
### ๐งฌ `getObserveMutations()`
Returns whether `MutationObserver` is currently enabled.
### ๐งท `getPreserveScrollOnLayoutShift()`
Returns whether scroll preservation is enabled when layout shifts.
### โ `getDebounceTime()`
Returns the debounce delay (ms) for scroll-based events.
## ๐งฎ Tracked Element Info
### ๐ `getElemAmount()`
Returns the current number of matching observed elements.
### ๐งพ `getPrevElemAmount()`
Returns the previous number of matching elements.
### ๐งต `getQuerySelector()`
Returns the CSS selector used to filter tracked elements.
## ๐ฃ Cleanup and Destruction
### โ ๏ธ `destroy()`
Disconnects all internal listeners and observers and clears memory.
```js
scroller.destroy();
```
* ๐งน Removes `scroll`, `resize`, and `load` listeners.
* ๐งผ Clears WeakMaps and listener registries.
* โ Once destroyed, the instance should not be reused.