scrollspy.mjs.map 14 KB

1
  1. {"version":3,"file":"scrollspy.mjs","sources":["../../src/strings/scrollspyString.ts","../../src/strings/scrollspyComponent.ts","../../src/components/scrollspy.ts"],"sourcesContent":["/** @type {string} */\nconst scrollspyString = \"scrollspy\";\nexport default scrollspyString;\n","/** @type {string} */\nconst scrollspyComponent = \"ScrollSpy\";\nexport default scrollspyComponent;\n","/* Native JavaScript for Bootstrap 5 | ScrollSpy\n------------------------------------------------ */\nimport {\n addClass,\n closest,\n createCustomEvent,\n dispatchEvent,\n getAttribute,\n getBoundingClientRect,\n getDocument,\n getDocumentElement,\n getElementById,\n getElementsByTagName,\n getInstance,\n hasClass,\n mouseclickEvent,\n MouseEvent,\n querySelector,\n removeClass,\n} from \"@thednp/shorty\";\n\nimport PositionObserver from \"@thednp/position-observer\";\nimport { addListener, removeListener } from \"@thednp/event-listener\";\n\nimport activeClass from \"~/strings/activeClass\";\nimport scrollspyString from \"~/strings/scrollspyString\";\nimport scrollspyComponent from \"~/strings/scrollspyComponent\";\nimport isDisabled from \"~/util/isDisabled\";\nimport BaseComponent from \"./base-component\";\nimport { ScrollSpyEvent, ScrollSpyOptions } from \"~/interface/scrollspy\";\n\n// SCROLLSPY PRIVATE GC\n// ====================\nconst scrollspySelector = '[data-bs-spy=\"scroll\"]';\nconst scrollSpyAnchorSelector = \"[href]\";\n\nconst scrollspyDefaults: Partial<ScrollSpyOptions> = {\n offset: 10,\n target: undefined,\n};\n\ntype ScrollSpyEventProps = {\n relatedTarget: HTMLElement;\n};\n\n/**\n * Static method which returns an existing `ScrollSpy` instance associated\n * to a target `Element`.\n */\nconst getScrollSpyInstance = (element: Element) =>\n getInstance<ScrollSpy>(element, scrollspyComponent);\n\n/**\n * A `ScrollSpy` initialization callback.\n */\nconst scrollspyInitCallback = (element: Element) => new ScrollSpy(element);\n\n// SCROLLSPY CUSTOM EVENT\n// ======================\nconst activateScrollSpy = createCustomEvent<\n ScrollSpyEventProps,\n ScrollSpyEvent\n>(`activate.bs.${scrollspyString}`);\n\n// SCROLLSPY PRIVATE METHODS\n// =========================\n/**\n * Update the state of all items.\n *\n * @param self the `ScrollSpy` instance\n */\nconst updateSpyTargets = (self: ScrollSpy) => {\n const {\n target,\n _itemsLength,\n _observables,\n } = self;\n\n const links = getElementsByTagName<HTMLAnchorElement>(\"A\", target);\n const doc = getDocument(target);\n\n // only update items once or with each mutation\n // istanbul ignore else @preserve\n if (!links.length || _itemsLength === _observables.size) return;\n // reset arrays & update\n _observables.clear();\n\n Array.from(links).forEach((link) => {\n const hash = getAttribute(link, \"href\")?.slice(1);\n const targetItem = hash?.length ? doc.getElementById(hash) : null;\n\n if (targetItem && !isDisabled(link)) {\n self._observables.set(targetItem, link);\n }\n });\n self._itemsLength = self._observables.size;\n};\n\n/**\n * Clear all items of the target.\n *\n * @param target a single item\n */\nconst clear = (target: Element) => {\n Array.from(getElementsByTagName<HTMLAnchorElement>(\"A\", target)).forEach(\n (item) => {\n if (hasClass(item, activeClass)) removeClass(item, activeClass);\n },\n );\n};\n\n/**\n * Activates a new item.\n *\n * @param self the `ScrollSpy` instance\n * @param item a single item\n */\nconst activate = (self: ScrollSpy, item: HTMLElement) => {\n const { target, element } = self;\n\n // istanbul ignore else @preserve\n clear(target);\n\n self._activeItem = item;\n addClass(item, activeClass);\n\n // activate all parents\n let parentItem = item;\n while (parentItem !== target) {\n parentItem = parentItem.parentElement as HTMLElement;\n if (\n [\"nav\", \"dropdown-menu\", \"list-group\"].some((c) =>\n hasClass(parentItem, c)\n )\n ) {\n const parentLink = parentItem.previousElementSibling as\n | HTMLElement\n | null;\n\n // istanbul ignore else @preserve\n if (parentLink && !hasClass(parentLink, activeClass)) {\n addClass(parentLink, activeClass);\n }\n }\n }\n\n // dispatch\n activateScrollSpy.relatedTarget = item;\n dispatchEvent(element, activateScrollSpy);\n};\n\nconst getOffset = (self: ScrollSpy, target: HTMLElement) => {\n const { scrollTarget, element, options } = self;\n\n return (scrollTarget !== element\n ? getBoundingClientRect(target).top + scrollTarget.scrollTop\n : target.offsetTop) - (options.offset as number || 10);\n};\n\n// SCROLLSPY DEFINITION\n// ====================\n/** Returns a new `ScrollSpy` instance. */\nexport default class ScrollSpy extends BaseComponent {\n static selector = scrollspySelector;\n static init = scrollspyInitCallback;\n static getInstance = getScrollSpyInstance;\n declare element: HTMLElement;\n declare options: ScrollSpyOptions;\n declare target: HTMLElement;\n declare scrollTarget: HTMLElement;\n declare _itemsLength: number;\n declare _activeItem: HTMLElement | null;\n declare _observables: Map<HTMLElement, HTMLElement>;\n declare _observer: PositionObserver; //| IntersectionObserver;\n\n /**\n * @param target the target element\n * @param config the instance options\n */\n constructor(\n target: Element | string,\n config?: Partial<ScrollSpyOptions>,\n ) {\n super(target, config);\n\n // initialization element & options\n const { element, options } = this;\n\n // get target\n const spyTarget = querySelector(\n options.target,\n getDocument(element),\n );\n\n // invalidate\n if (!spyTarget) return;\n this.target = spyTarget;\n\n // set initial state\n this.scrollTarget = element.clientHeight < element.scrollHeight\n ? element\n : getDocumentElement(element);\n this._observables = new Map();\n\n // run an initial burst, we need to know the targets\n this.refresh();\n // updateSpyTargets(this);\n\n // create observer\n this._observer = new PositionObserver(() => {\n requestAnimationFrame(() => this.refresh());\n }, {\n root: this.scrollTarget,\n });\n\n // add event handlers\n this._toggleEventListeners(true);\n }\n\n /* eslint-disable */\n /**\n * Returns component name string.\n */\n get name() {\n return scrollspyComponent;\n }\n /**\n * Returns component default options.\n */\n get defaults() {\n return scrollspyDefaults;\n }\n /* eslint-enable */\n\n // SCROLLSPY PUBLIC METHODS\n // ========================\n /** Updates all items. */\n refresh = () => {\n const { target, scrollTarget } = this;\n // check if target is visible and invalidate\n // istanbul ignore if @preserve\n if (!target || target.offsetHeight === 0) return;\n\n updateSpyTargets(this);\n const { _itemsLength, _observables, _activeItem } = this;\n\n // istanbul ignore if @preserve\n if (!_itemsLength) return;\n const entries = _observables.entries().toArray();\n\n const { scrollTop, scrollHeight, clientHeight } = scrollTarget;\n\n if (scrollTop >= scrollHeight - clientHeight) {\n const newActiveItem = entries[_itemsLength - 1]?.[1];\n\n // istanbul ignore else @preserve\n if (_activeItem !== newActiveItem) activate(this, newActiveItem);\n return;\n }\n\n const firstOffset = entries[0]?.[0]\n ? getOffset(this, entries[0][0])\n : /* istanbul ignore next */ null;\n if (\n firstOffset !== null && scrollTop < firstOffset &&\n firstOffset > 0\n ) {\n this._activeItem = null;\n clear(target);\n return;\n }\n\n for (let i = 0; i < _itemsLength; i += 1) {\n const [targetItem, item] = entries[i];\n const offsetTop = getOffset(this, targetItem);\n const nextTarget = entries[i + 1]?.[0];\n const nextOffsetTop = nextTarget\n ? getOffset(this, nextTarget)\n : /* istanbul ignore next */ null;\n\n // istanbul ignore else @preserve\n if (\n _activeItem !== item &&\n scrollTop >= offsetTop &&\n (nextOffsetTop === null || scrollTop < nextOffsetTop)\n ) {\n activate(this, item);\n break;\n }\n }\n };\n\n /**\n * This method provides an event handle\n * for scrollspy\n * @param e the event listener object\n */\n _scrollTo = (e: MouseEvent<HTMLAnchorElement>) => {\n const item = closest(e.target, scrollSpyAnchorSelector);\n const hash = item && getAttribute(item, \"href\")?.slice(1);\n const targetItem = hash && getElementById(hash, this.target);\n\n // istanbul ignore else @preserve\n if (targetItem) {\n this.scrollTarget.scrollTo({\n top: targetItem.offsetTop,\n behavior: \"smooth\",\n });\n e.preventDefault();\n }\n };\n\n /**\n * Toggles on/off the component observer.\n *\n * @param self the ScrollSpy instance\n * @param add when `true`, listener is added\n */\n _toggleEventListeners = (\n add?: boolean,\n ) => {\n const { target, _observables, _observer, _scrollTo } = this;\n const action = add ? addListener : removeListener;\n action(target, mouseclickEvent, _scrollTo);\n\n if (add) {\n _observables?.forEach((_, targetItem) => _observer.observe(targetItem));\n } else _observer.disconnect();\n };\n\n /** Removes `ScrollSpy` from the target element. */\n dispose() {\n this._toggleEventListeners();\n super.dispose();\n }\n}\n"],"names":["scrollspyString","scrollspyComponent","scrollspySelector","scrollSpyAnchorSelector","scrollspyDefaults","getScrollSpyInstance","element","getInstance","scrollspyInitCallback","ScrollSpy","activateScrollSpy","createCustomEvent","updateSpyTargets","self","target","_itemsLength","_observables","links","getElementsByTagName","doc","getDocument","link","hash","getAttribute","targetItem","isDisabled","clear","item","hasClass","activeClass","removeClass","activate","addClass","parentItem","c","parentLink","dispatchEvent","getOffset","scrollTarget","options","getBoundingClientRect","BaseComponent","config","spyTarget","querySelector","getDocumentElement","PositionObserver","_activeItem","entries","scrollTop","scrollHeight","clientHeight","newActiveItem","firstOffset","i","offsetTop","nextTarget","nextOffsetTop","e","closest","getElementById","add","_observer","_scrollTo","addListener","removeListener","mouseclickEvent","_"],"mappings":"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"}