npm.io
3.0.1 • Published 5d ago

belter

Licence
Apache-2.0
Version
3.0.1
Deps
2
Size
118 kB
Vulns
0
Weekly
0
Stars
17

belter

Small browser helpers for code that embeds things in pages.

npm install belter
import { iframe, awaitFrameWindow, onResize, watchElementForClose, cleanup } from 'belter';

const clean = cleanup();
const frame = iframe({ url: 'https://example.com/widget', container: '#widget' });

clean.register(() => frame.remove());

const win = await awaitFrameWindow(frame);                       // the frame's window, once loaded
const resize = onResize({ element: frame, handler: ({ width, height }) => { ... } });
const watch = watchElementForClose({ element: frame, handler: () => clean.all() });

ES modules, TypeScript types included, ES2019 syntax. For current browsers: nothing here exists to work around an old one. Depends on cross-domain-utils and zalgo-promise; the functions that wait for something return a ZalgoPromise, which settles synchronously when it can and is also a plain thenable.

What's here

Frames and popups

Function Gives
iframe({ url?, attributes?, style?, classes?, container? }) A transparent, borderless iframe with an id, appended and then pointed at url
popup(url, { name?, width?, height?, closeOnUnload?, ...features }) A popup centred on this window; throws PopupOpenError when blocked
awaitFrameLoad(frame), awaitFrameWindow(frame) Resolve once the frame has loaded, with the frame or its window
writeElementToWindow(win, htmlElement) Replace a same-origin window's document with the children of an <html> element

Elements

Function Gives
createElement({ tag?, id?, classes?, style?, attributes?, html?, container?, doc? }) An element with everything set
getElement(ref, doc?), getElementSafe(ref, doc?) An element from a selector or the element itself; the safe one returns undefined
elementReady(ref, doc?) Resolves with the element as soon as it exists, rejects once the document has loaded without it
isElement(value), isElementVisible(el), isElementClosed(el) Checks: duck-typed element, takes up space, removed from its document
showElement(el), hideElement(el), destroyElement(el) Display toggles (display: none !important) and removal
addEventListener(target, event, handler) A listener that returns { cancel }
describeElementRef(ref) How a reference reads in an error message

Watching

Function Gives
watchElementForClose({ element, handler }) Calls handler once when the element leaves its document, even if it is put straight back (ancestor observers plus a one-second poll); returns { cancel }
onResize({ element, handler, width?, height?, win? }) Calls handler({ width, height }) now and whenever the watched dimensions change while visible
waitForDocumentReady(doc?), waitForDocumentBody(doc?), waitForWindowReady(win?) Resolve once the document is parsed, its body exists, or the window has loaded

Shadow DOM

Function Gives
isShadowElement(node), getShadowRoot(node), getShadowHost(node) Where a node sits relative to a shadow root
insertShadowSlot(element) A light-DOM element that is projected into element, through nested shadow roots

Script tags

Function Gives
getScriptUID(script) A stable id for a script tag: its data-uid, else a hash of its src and data attributes
getCurrentScript(), getCurrentScriptUID() The script tag that loaded this code (classic scripts only), and its uid, or a random one

Functions and state

Function Gives
memoize(fn) Caches by argument values (functions by identity, elements as {}); .reset() clears
memoizePromise(fn) Shares one in-flight promise between identical calls, then forgets it
weakMapMemoize(fn) Caches on one object argument, held weakly
once(fn), debounce(fn, time?), safeInterval(fn, time) The usual; the interval never overlaps itself and returns { cancel }
eventEmitter<Events>() on, once, trigger, triggerOnce, reset; triggers resolve once every handler has
cleanup() register(task) and all(err?); a task registered after all runs at once
getOrSet({ map, key, create }), tryCatch(fn) Odds and ends

Values

Function Gives
uniqueID() uid_ and sixteen hex characters
base64encode(str), base64decode(str) Unicode-safe, no padding
stringifyError(err) A string for any thrown value, never throws itself
dotify(obj), undotify(obj) { a: { b: 1 }, c: [ 1, 2 ] } to and from { 'a.b': '1', 'c[]': '1,2' }
parseQuery(str), formatQuery(obj), extendQuery(str, obj), extendUrl(url, { query?, hash? }) Query strings with encodeURIComponent values
isPerc(v), isPx(v), toNum(v), toPx(v), toCSS(v), percOf(num, perc), normalizeDimension(v, max) CSS dimensions: 100px, 50%, or a bare number
noop, identity, isDefined, assertExists(value, what), isPlainObject Tiny

Types: Cancelable, ElementRef, Dimensions, Query, PopupOptions, EventEmitter, Cleanup, Memoized, TryCatchResult.

Changes in 3.0

Published as belter again (2.x lived under @krakenjs). ES modules and TypeScript only, and the surface is what current browser code needs rather than everything 1.x and 2.x accumulated:

  • Gone, because the platform has it or no supported browser needs it: extend (Object.assign), values, arrayFrom, getGlobal (globalThis), appendChild, addClass / removeClass, isLocalStorageEnabled, the document.write path (writeToWindow), vendor-prefixed animations (animate, setVendorCSS, showAndAnimate, animateAndHide), the allowTransparency and about:blank iframe quirks, the stack-trace script lookup, and ExtendableError.
  • Gone, because it belonged to one product or one era: device.js (every isIE / isIos / isAndroid / webview sniff), screenHeights.js, http.js, experiment.js, storage.js, decorators.js, test.js, the safe-weakmap global namespace, sanitizeUrl, regex / regexAll / regexMap / regexTokenize, patchMethod, awaitKey, cycle, copyProp, defineLazyProp, replaceObject, promisify, inlineMemoize, memoize.clear, dedupeErrors, hashStr, svgToBase64, get, perc / min / max / roundUp, getPerformance / getPageRenderTime / getResourceLoadTime, getBrowserLocales, hasMetaViewPort, onClick, getScript, redirect, urlWillRedirectPage, htmlEncode, querySelectorAll, fixScripts, preventClickFocus, camelToDasherize / dasherizeToCamel / capitalizeFirstLetter, isRegex, isInteger / isFloat, serializePrimitive / deserializePrimitive, unique, constHas, removeFromArray, objFilter, promiseDebounce, safeTimeout, weakMapMemoizePromise, getObjectID, getFunctionName / setFunctionName, bindEvents, setStyle, makeElementVisible / makeElementInvisible. submitForm lives in cross-domain-utils.
  • Options objects where there were three or more positional arguments: createElement({ ... }), iframe({ ... }), watchElementForClose({ element, handler }), onResize({ element, handler, ... }), getOrSet({ map, key, create }). assertExists(value, what) takes the value first. cleanup() takes no object and has no set.
  • watchElementForClose no longer plants a sacrificial iframe inside the element; onResize uses ResizeObserver and the window's resize event with no polling; elementReady uses a MutationObserver instead of a 10ms poll; uniqueID is uid_ plus sixteen random hex characters; memoize keys on argument values only (no this namespace, no expiry).
  • isDocumentReady, waitForDocumentReady, waitForDocumentBody, elementReady and createElement take an optional document, so they work on a frame's document too.
  • The test suite runs in a real browser (Playwright) with real frames, popups and shadow roots, and in Node for the pure helpers.

License

Apache-2.0

Keywords