baseframe-js
Version:
Baseframe JS is a comprehensive suite of modular plugins and utilities designed for front-end development
1,329 lines (1,302 loc) • 126 kB
JavaScript
function getDefaultExportFromCjs (x) {
return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
}
var baseElemJs$1 = {exports: {}};
var baseElemJs = baseElemJs$1.exports;
var hasRequiredBaseElemJs;
function requireBaseElemJs () {
if (hasRequiredBaseElemJs) return baseElemJs$1.exports;
hasRequiredBaseElemJs = 1;
(function (module, exports) {
(function (global, factory) {
module.exports = factory() ;
})(baseElemJs, (function () {
// Dom shortcuts
const w = window, d = document, body = d.body, root = d.documentElement, toType = (object) => ({}).toString.call(object).match(/\s([a-zA-Z]+)/)[1].toLowerCase(), oa = Object.assign, af = Array.from, isArr = Array.isArray, isStr = (str) => typeof str === 'string', isObj = (obj) => toType(obj) === 'object';
const eventFnCache = new WeakMap();
const cssSplitRgx = /([\.\#][\w-_\s]+)/g;
const
// region Props
CSS_ACTION_STATES = Object.freeze({
active: 'active',
starting: 'starting',
ending: 'ending'
}), cssActionStates = (nameSpace, baseObj = CSS_ACTION_STATES) => {
const retObj = {};
const prefix = nameSpace ? nameSpace + '-' : '';
for (const key in baseObj) {
if (Object.hasOwn(baseObj, key)) {
oa(retObj, {
[key]: prefix + baseObj[key]
});
}
}
return retObj;
},
//
// region Finding Elems
//
findBy$1 = (type, find, base = d) => {
return type === 'class' ? af(base.getElementsByClassName(find)) :
type === 'id' ? d.getElementById(find) :
type === 'tag' ? af(base.getElementsByTagName(find)) :
null;
}, find$1 = (el, base = d) => {
return af(base.querySelectorAll(el));
}, findOne$1 = (el, base = d) => {
return base.querySelector(el);
}, map$1 = (elems, fn, unique = false) => {
let i = 0, elem, prevRes;
const retElems = [];
while (elem = elems[i]) {
const res = fn(elem, i++);
if (!res)
continue; // only truthy value
if (unique) {
if (res !== prevRes || !elems.find(el => el === res))
retElems.push(res);
prevRes = res;
}
else
retElems.push(res);
}
return retElems;
}, parents$1 = (elem, selector, untilElem = root) => {
const untilIsStr = isStr(untilElem);
const retElems = [];
while (elem = elem.parentElement) {
if (elem.matches(selector))
retElems.unshift(elem);
if (untilIsStr ? elem.matches(untilElem) : elem === untilElem)
break;
}
return retElems;
}, siblings$1 = (elem, selector, includeKeyEl = false) => {
const siblings = af(elem.parentElement.childNodes).filter(el => el instanceof HTMLElement &&
(selector ? el.matches(selector) : true) &&
(includeKeyEl ? true : el !== elem));
return siblings;
}, next$1 = (elem, selector) => {
let nextElem = elem.nextElementSibling;
if (selector)
while (nextElem) {
if (nextElem.matches(selector))
break;
nextElem = nextElem.nextElementSibling;
}
// always return an element
return (nextElem ?? elem);
}, prev$1 = (elem, selector) => {
let prevElem = elem.previousElementSibling;
if (selector)
while (prevElem) {
if (prevElem.matches(selector))
break;
prevElem = prevElem.previousElementSibling;
}
// always return an element
return (prevElem ?? elem);
},
//
// region CSS and Attrs
//
attr$1 = (elem, attrs) => {
if (isStr(attrs)) {
if (attrs === 'value')
return elem.value;
return elem.getAttribute(attrs);
}
else {
for (const key in attrs) {
const val = attrs[key];
val === null ?
elem.removeAttribute(key) :
elem.setAttribute(key, val);
}
}
}, css$1 = (elem, attrs) => {
if (isStr(attrs)) {
const styles = getComputedStyle(elem);
return styles.getPropertyValue(attrs);
}
else {
for (const key in attrs) {
const val = attrs[key];
if (key.startsWith('--')) {
elem.style.setProperty(key, val);
}
else {
elem.style[key] = val;
}
}
}
return '';
}, _cl = (elem) => elem.classList, addClass$1 = (elem, cssNames) => {
const cl = _cl(elem);
isArr(cssNames) ? cl.add(...cssNames) : cl.add(cssNames);
}, rmClass$1 = (elem, cssNames) => {
const cl = _cl(elem);
isArr(cssNames) ? cl.remove(...cssNames) : cl.remove(cssNames);
}, tgClass$1 = (elem, cssNames, toggle) => {
const cl = _cl(elem);
if (isArr(cssNames)) {
for (const cssName of cssNames) {
cl.toggle(cssName, toggle);
}
}
else {
cl.toggle(cssNames, toggle);
}
}, hasClass$1 = (elem, cssNames) => {
const cl = _cl(elem);
return isArr(cssNames) ? cssNames.every(cls => cl.contains(cls)) : cl.contains(cssNames);
}, elemRects$1 = (elem) => {
return elem.getBoundingClientRect();
}, offset$1 = (elem) => {
const rects = elemRects$1(elem);
return {
top: rects.top + w.pageYOffset,
left: rects.left + w.pageXOffset
};
},
//
// region Element Creation / Removal
//
make = (selector, propsOrHtml = {}, html) => {
const [tag, ...attrs] = selector.split(cssSplitRgx), baseAttrs = getTagAttrs(attrs), propsIsHtml = isArr(propsOrHtml) || propsOrHtml instanceof HTMLElement, propsIsContent = isStr(propsOrHtml) || propsIsHtml, makeProps = propsIsContent ? {} : propsOrHtml, props = oa(baseAttrs, makeProps), { style } = props, elem = oa(d.createElement(tag), props), htmlToUse = propsIsContent && !html ? propsOrHtml : (html ? html : '');
if (style && isObj(style))
css$1(elem, style);
if (htmlToUse)
elem.append(...(isStr(htmlToUse) ? htmlParse$1(htmlToUse) :
isArr(htmlToUse) ? htmlToUse : [htmlToUse]));
return elem;
}, htmlParse$1 = (htmlStr) => {
const root = (new DOMParser()).parseFromString(htmlStr, 'text/html').body;
// remove scripts, even though they're non-exectable with the DOMParser
const scripts = find$1('script', root);
if (scripts)
scripts.forEach(s => s.remove());
const elList = af(root.childNodes);
return elList;
}, empty$1 = (elem) => {
while (elem.firstChild) {
elem.removeChild(elem.firstChild);
}
}, merge = (configOrTarget, ...objects) => {
const options = isArr(configOrTarget) ? configOrTarget :
toType(configOrTarget) === 'string' || toType(configOrTarget) === 'boolean' ? [configOrTarget] : [],
// end options;
hasOptions = options.length > 0, getOpt = (configOpt) => hasOptions ? options.some(opt => opt === configOpt) : false, deep = getOpt('deep') || getOpt(true), noNull = getOpt('noNull'), noFalsy = getOpt('noFalsy'), target = hasOptions ? objects.shift() : configOrTarget;
let mergeObj, i = 0;
while (mergeObj = objects[i++]) {
for (const key in mergeObj) {
const value = mergeObj[key];
if (deep && isObj(value)) {
const targetObj = target[key] ? target[key] : target[key] = {};
merge(options, targetObj, value);
}
else {
target[key] = value;
if ((noNull && value === null) || (noFalsy && !value)) {
delete target[key];
}
}
}
}
return target;
},
//
// region Event
//
on$1 = (baseEl = body, evtName, fn, delegateEl = null, config = false) => {
const evt = evtName.split('.')[0];
const evtFn = (e) => {
const data = e['___cdata'] || [];
if (delegateEl && baseEl instanceof HTMLElement) {
const delegateElems = isStr(delegateEl) ? find$1(delegateEl, baseEl) : delegateEl;
// if isTrusted then its a native click
const elTarget = e.isTrusted ? e.target : (e['___synthTarget'] ?? e.target);
// const delegateElem = getDelegatedElem(baseEl, delegateElems, elTarget);
const delegateElem = delegateElems.find(elem => elem === elTarget || elem.contains(elTarget));
if (delegateElem)
fn(e, delegateElem, ...data);
}
else {
fn(e, baseEl, ...data);
}
};
if (eventFnCache.has(baseEl)) {
eventFnCache.get(baseEl).set(evtName, evtFn);
}
else {
eventFnCache.set(baseEl, new Map([[evtName, evtFn]]));
}
baseEl.addEventListener(evt, evtFn, config);
}, off$1 = (target = body, evtName, config = false) => {
if (eventFnCache.has(target)) {
const tgtFnMap = eventFnCache.get(target), evt = evtName.split('.')[0], fn = tgtFnMap.get(evtName);
target.removeEventListener(evt, fn, config);
tgtFnMap.delete(evtName);
}
}, trigger$1 = (target = body, evtName, delegateEl = null, data = [], config = false) => {
evtName = evtName.trim();
const delegateEls = delegateEl ? find$1(delegateEl, target instanceof Window ? body : target) : null;
if (delegateEls && delegateEls.length === 0)
return;
const elTarget = delegateEls ? delegateEls[0] : target, [evt, nameSpace = ''] = evtName.split('.'), evtIsSynthetic = /^\[.+\]$/.test(evtName), elEvt = new Event(evtIsSynthetic ? evtName : evt);
if (data.length)
oa(elEvt, { ___cdata: data });
if (nameSpace || evtIsSynthetic) {
const cache = eventFnCache.get(target);
if (!cache)
return;
const fn = cache.get(evtName);
oa(elEvt, { ___synthTarget: elTarget });
if (fn) {
if (evtIsSynthetic) {
target.addEventListener(evtName, fn, config);
target.dispatchEvent(elEvt);
target.removeEventListener(evtName, fn, config);
}
else
fn(elEvt, elTarget);
}
}
else
target.dispatchEvent(elEvt);
},
//
// region Transition
//
useTransition = () => {
let inTransition = false;
let tto = null;
let currEndTransitionFn = () => { };
return (startFn, endFn, duration = 300) => {
if (inTransition) {
currEndTransitionFn();
clearTimeout(tto);
}
startFn();
currEndTransitionFn = endFn;
inTransition = true;
tto = setTimeout(() => {
currEndTransitionFn();
inTransition = false;
}, duration);
};
}, useCssAnimate = (elems, baseCss = '') => {
const transition = useTransition();
const cssState = cssActionStates(baseCss);
const cssAnimate = (start, duration = 400, endFn = () => { }) => {
const cssTarget = start ? cssState.starting : cssState.ending;
const startAnimate = (elem) => {
elem.offsetHeight; //reflow
addClass$1(elem, cssTarget);
rmClass$1(elem, cssState.active);
};
const endAnimate = (elem) => {
rmClass$1(elem, cssTarget);
tgClass$1(elem, cssState.active, start);
};
transition(() => {
isArr(elems) ?
elems.forEach(startAnimate) :
startAnimate(elems);
}, () => {
isArr(elems) ?
elems.forEach(endAnimate) :
endAnimate(elems);
endFn();
}, duration);
};
return [
cssAnimate,
cssState
];
}, animateByFrame = (fn, fps = 60) => {
fps = Math.min(Math.max(1, fps), 60); // clamp fps between 1 and 60
let requestAnimate = null;
let msPrev = performance.now();
const msPerFrame = 1000 / fps;
const cancelAnimation = () => cancelAnimationFrame(requestAnimate);
const refresh = (msNow) => {
requestAnimate = window.requestAnimationFrame(refresh);
const msPassed = msNow - msPrev;
if (msPassed < msPerFrame)
return;
const excessTime = msPassed % msPerFrame;
msPrev = msNow - excessTime;
fn(cancelAnimation);
};
// Initial call
fn(cancelAnimation);
refresh(msPrev);
return cancelAnimation;
},
// region visibility
isVisible = (el) => {
const vis = el.offsetParent !== null ||
!!(el.offsetWidth ||
el.offsetHeight ||
el.getClientRects().length);
return vis;
}, isHidden = (el) => !isVisible(el);
//
// Helpers
//
const getTagAttr = (attrList, rm) => attrList.filter(e => e.startsWith(rm)).map(e => e.substring(1));
const getTagAttrs = (attrList) => {
const attrs = {}, classes = getTagAttr(attrList, '.'), id = getTagAttr(attrList, '#');
for (const val of attrList) {
if (classes.length)
oa(attrs, { className: classes.join(' ') });
if (id.length)
oa(attrs, { id: id[0] });
}
return attrs;
};
const BaseStatic = {
CSS_ACTION_STATES,
addClass: addClass$1,
attr: attr$1,
css: css$1,
cssActionStates,
empty: empty$1,
find: find$1,
findBy: findBy$1,
findOne: findOne$1,
hasClass: hasClass$1,
htmlParse: htmlParse$1,
isVisible,
isHidden,
make,
map: map$1,
merge,
next: next$1,
parents: parents$1,
prev: prev$1,
siblings: siblings$1,
elemRects: elemRects$1,
offset: offset$1,
off: off$1,
on: on$1,
trigger: trigger$1,
rmClass: rmClass$1,
tgClass: tgClass$1,
useTransition,
useCssAnimate,
animateByFrame,
//utils
af, isArr, isStr, isObj, oa, toType
};
const { addClass, attr, css, elemRects, offset, empty, find, findBy, findOne, map, next, prev, hasClass, htmlParse, off, on, parents, siblings, trigger, rmClass, tgClass } = BaseStatic;
const noElemMsg = 'Element is not defined with index: ';
class BaseElem {
elem = [];
constructor(selector, base) {
if (isStr(selector)) {
this.elem = find(selector, base);
}
else if (selector instanceof BaseElem) {
this.elem = [...selector.elem];
}
else {
//not checking type for HTMLElement[]
if (selector) {
this.elem = isArr(selector) ? selector : [selector];
}
}
return this;
}
// ---------------
// region Private Methods
// ---------------
#iterate(fn) {
let i = 0, elem;
while (elem = this.elem[i]) {
fn(elem, i++);
}
}
#strOrObj(attrs, fn = () => '') {
if (isStr(attrs)) {
const elem = this.elem[0];
return fn(elem, attrs);
}
else {
this.#iterate(elem => fn(elem, attrs));
}
return '';
}
#content(fn, content) {
if (content) {
this.#iterate((elem) => {
empty(elem);
const nodes = fn(content);
isArr(nodes) ? elem.append(...nodes) : elem.append(nodes);
});
}
else {
// return copy
return this.elem[0];
}
return null;
}
// ---------
// region Selectors
// ---------
find(selector, filter) {
if (isStr(selector)) {
const elems = this.elem.map(elem => find(selector, elem)).flat();
return new BaseElem(filter ? elems.filter(filter) : elems);
}
else {
return new BaseElem(this.map(selector, true));
}
}
findBy(type, selector, filter) {
const elems = this.elem.map(elem => findBy(type, selector, elem)).flat();
return new BaseElem(filter ? elems.filter(filter) : elems);
}
findOne(selector) {
const elem = this.elem.map(elem => findOne(selector, elem)).filter(Boolean);
return new BaseElem(elem);
}
filter(fn) {
// not error checking for the document or window
return new BaseElem(this.elem.filter(fn));
}
// -------------------
// region Array and iteration
// -------------------
toArray() {
return [...this.elem];
}
map(fn, unique = false) {
return map(this.elem, fn, unique);
}
parents(selector, untilElem) {
if (untilElem instanceof BaseElem)
untilElem = untilElem.elem[0];
const elems = map(this.elem, (elem) => parents(elem, selector, untilElem));
return new BaseElem(elems.flat());
}
siblings(selector, includeKeyEl = false, index = 0) {
return new BaseElem(siblings(this.elem[index], selector, includeKeyEl));
}
next(selector) {
return new BaseElem(next(this.elem[0], selector));
}
prev(selector) {
return new BaseElem(prev(this.elem[0], selector));
}
get(index) {
const elem = this.elem[index];
if (elem)
return new BaseElem(elem);
else
console.warn(noElemMsg + index);
}
each(fn) {
this.#iterate(fn);
return this;
}
css(attrs) {
const val = this.#strOrObj(attrs, css);
if (val)
return val;
return this;
}
addClass(cssNames) {
this.#iterate(elem => addClass(elem, cssNames));
return this;
}
rmClass(cssNames) {
this.#iterate(elem => rmClass(elem, cssNames));
return this;
}
tgClass(cssNames, toggle) {
this.#iterate(elem => tgClass(elem, cssNames, toggle));
return this;
}
hasClass(cssNames, method = 'some') {
return !isArr(this.elem) ?
hasClass(this.elem, cssNames) :
method === 'some' ?
this.elem.some(elem => hasClass(elem, cssNames)) :
this.elem.every(elem => hasClass(elem, cssNames));
}
attr(attrs) {
const val = this.#strOrObj(attrs, attr);
if (val)
return val;
return this;
}
#getOne(index = 0, fn) {
const elem = this.elem[index];
if (elem) {
return fn(elem);
}
else {
console.warn(noElemMsg + index);
return undefined;
}
}
elemRects(index = 0) {
return this.#getOne(index, elemRects);
}
offset(index = 0) {
return this.#getOne(index, offset);
}
get hasEls() {
return this.elem.length > 0;
}
get size() {
return this.elem.length;
}
// ------------------------------
// region Removal and Appending Elements
// ------------------------------
empty() {
this.#iterate(empty);
return this;
}
remove() {
this.#iterate(elem => elem.remove());
return this;
}
insert(html, method = 'append') {
this.#iterate((elem) => {
const elems = (isArr(html) ? html.map(getElems).flat() : isStr(html) ? htmlParse(html) : getElems(html));
if (method === 'append')
elem.append(...elems);
if (method === 'prepend')
elem.prepend(...elems);
if (method === 'after')
elem.after(...elems);
if (method === 'before')
elem.before(...elems);
});
return this;
}
html(html) {
const retEl = this.#content(htmlParse, html);
if (retEl)
return retEl.innerHTML.trim();
return this;
}
text(text) {
const retEl = this.#content((text) => new Text(text), text);
if (retEl)
return retEl.textContent.trim();
return this;
}
// ------
// region Events
// ------
on(evtName, fn, delegateEl = null, config = false) {
if (isArr(evtName)) {
for (const evName of evtName) {
this.#iterate((elem) => on(elem, evName, fn, delegateEl, config));
}
}
else {
this.#iterate((elem) => on(elem, evtName, fn, delegateEl, config));
}
return this;
}
trigger(evtName, delgateEl, data) {
this.#iterate((elem) => trigger(elem, evtName, delgateEl, data));
return this;
}
off(evtName, config = false) {
if (isArr(evtName)) {
for (const evName of evtName) {
this.#iterate((elem) => off(elem, evName, config));
}
}
else {
this.#iterate((elem) => off(elem, evtName, config));
}
return this;
}
}
//
// Helper
//
const getElems = (el) => el instanceof BaseElem ? el.elem : [el];
const $be = (selector, base) => new BaseElem(selector, base);
oa($be, BaseStatic);
$be.BaseElem = BaseElem;
return $be;
}));
} (baseElemJs$1, baseElemJs$1.exports));
return baseElemJs$1.exports;
}
var baseElemJsExports = requireBaseElemJs();
const $be = /*@__PURE__*/getDefaultExportFromCjs(baseElemJsExports);
const parseObjectFromString = (options) => {
let retObj = {};
if (typeof options === 'string') {
retObj = JSON.parse(options.replace(/:\s*"([^"]*)"/g, function (match, p1) {
return ': "' + p1.replace(/:/g, '@colon@') + '"';
}).replace(/:\s*'([^']*)'/g, function (match, p1) {
return ': "' + p1.replace(/:/g, '@colon@') + '"';
}).replace(/(['"])?([a-z0-9A-Z_]+)(['"])?\s*:/g, '"$2": ')
.replace(/@colon@/g, ':'));
}
return retObj;
};
const { merge, toType, isArr, isStr, oa, af } = $be;
// region DOM shortcuts
const d = document, body = d.body, isFunc = (fn) => toType(fn) === 'function', reflow = (elem) => elem.offsetHeight, noop = () => { };
// region plugin helpers
const setParams = (defaults, options, dataOptions) => {
const useOptions = toType(options) === 'object' ? options : {};
return merge([true], {}, defaults, useOptions, dataOptions);
};
const getDataOptions = (el, evtName) => parseObjectFromString(el.dataset[evtName + 'Options']);
const camelCase = (str) => str.replace(/-./g, x => x.toUpperCase()[1]);
const lowercaseFirstLetter = (str) => str.charAt(0).toLowerCase() + str.substring(1);
// region device
const isMobileOS = () => /Android|webOS|iPhone|iPad|iPod|Opera Mini/i.test(navigator.userAgent);
const storeMap = new WeakMap();
const Store = (storeElem, key, value) => {
const storeRecord = storeMap.get(storeElem) || storeMap.set(storeElem, {});
const keyExists = Reflect.has(storeRecord, key);
if (keyExists) {
const valueIsNull = value === null;
if (valueIsNull) {
delete storeRecord[key];
return null;
}
if (value) {
storeRecord[key] = value;
}
}
else {
if (value && value !== null) {
storeRecord[key] = value;
}
}
return storeRecord[key];
};
const libraryExtend = (Plugins, Library = $be, notify = false) => {
if (isArr(Plugins)) {
Plugins.forEach(Plugin => libraryExtend(Plugin, Library, notify));
}
else {
const dataName = Plugins.pluginName, pluginName = lowercaseFirstLetter(dataName), isBaseElem = !!Library.BaseElem, $library = isBaseElem ? Library.BaseElem.prototype : Library.fn;
const storeInstanceEach = (elem, index, params) => {
const Instance = Store(elem, dataName);
if (!Instance)
Store(elem, dataName, new Plugins(elem, params, index));
else {
const canUpdate = Instance.handleUpdate && $be.toType(Instance.handleUpdate) === 'function';
if (isStr(params)) {
if (params === 'remove')
Plugins.remove(elem);
if (params === 'update' && canUpdate)
Instance.handleUpdate();
return;
}
checkIfParamsExist(Instance.params, params, notify);
$be.merge(Instance.params, params);
if (canUpdate)
Instance.handleUpdate();
}
return Instance;
};
const pluginFn = function (params) {
const s = this;
if (isBaseElem) {
return s.each((elem, index) => {
storeInstanceEach(elem, index, params);
});
}
else {
//Cash or jQuery
return s.each(function (index, elem) {
storeInstanceEach(elem, index, params);
});
}
};
pluginFn.getInstance = (elem) => {
return Store(elem, dataName);
};
// to get it to print the function name
const o = { [pluginName]: pluginFn };
$library[pluginName] = o[pluginName];
}
};
const checkIfParamsExist = (setParams, params, notify = true) => {
for (let k in params) {
if (!({}).hasOwnProperty.call(setParams, k)) {
if (notify)
console.warn(`${k} is not a property that can be used`);
delete params[k];
}
}
if (notify)
console.log(`Params updated:`, params);
return params;
};
const EVENT_NAME$c = 'UrlState';
const urlStateMap = new Map([
['search', new URLSearchParams(location.search.replace('?', ''))],
['hash', new URLSearchParams(location.hash.replace('#', ''))]
]);
const toUrl = (state = 'replace') => {
let vals = '';
const hash = urlStateMap.get('hash').toString();
const search = urlStateMap.get('search').toString();
(search !== '') ? vals += '?' + search : vals += location.href.split(/(\?|\#)/)[0];
if (hash !== '')
vals += '#' + hash;
// clean-up
vals = vals.replace(/(\=\&)+/g, '&').replace(/\=$/, '');
state === "replace" ? history.replaceState(null, '', vals) : history.pushState(null, '', vals);
};
const setHashVal = (value, state) => {
const params = urlStateMap.get('hash');
for (const key of params.keys()) {
params.delete(key);
}
if (value !== null)
params.set(value, '');
if (state) {
toUrl(state);
}
};
const set = (type, paramName, value, state) => {
if (type === 'hashVal') {
console.warn(`use 'setHashVal' method for setting only the hash val`);
return;
}
const params = urlStateMap.get(type);
if (value === null) {
params.has(paramName) && params.delete(paramName);
}
else {
const isArray = Array.isArray(value);
const adjustedVal = isArray ? `[${value.join(',')}]` : value;
params.set(paramName, adjustedVal);
}
if (state) {
toUrl(state);
}
};
const get = (type, paramName) => {
const params = urlStateMap.get(type);
if (type === 'hashVal') {
return location.hash.replace('#', '');
}
if (params.has(paramName)) {
const rawVal = params.get(paramName).trim();
if (rawVal.slice(0, 1) === '[' && rawVal.slice(-1) === ']') {
const valSplits = rawVal.slice(1, -1).split(',');
return valSplits.map(el => !(/\D/).test(el) ? +el : el);
}
else {
return rawVal;
}
}
return null;
};
const refresh = (on = true) => {
if (on) {
$be(window).off(`popstate.${EVENT_NAME$c}`).on(`popstate.${EVENT_NAME$c}`, () => {
urlStateMap.set('search', new URLSearchParams(location.search.replace('?', '')));
urlStateMap.set('hash', new URLSearchParams(location.hash.replace('#', '')));
});
}
else {
$be(window).off(`popstate.${EVENT_NAME$c}`);
}
};
// print URL params
const print = (type, options) => {
const params = urlStateMap.get(type), defaultOptions = { pattern: 'normal', brackets: true }, { pattern, brackets } = Object.assign(defaultOptions, options), bkts = brackets ? '[]' : '';
if (pattern === 'repeat') {
return [...params.keys()].map((key) => {
const val = get(type, key);
if (Array.isArray(val)) {
return val.map(el => `${key}${bkts}=${encodeURIComponent(el)}`).join('&');
}
return `${key}=${val}`;
}).join('&');
}
return params.toString();
};
// run refresh initially
refresh();
const UrlState = {
refresh,
print,
toUrl,
set,
setHashVal,
get
};
const animate = (fn, fps = 60) => {
let requestAnimate = null;
let msPrev = performance.now();
const msPerFrame = 1000 / fps;
const cancelAnimation = () => cancelAnimationFrame(requestAnimate);
const refresh = (msNow) => {
requestAnimate = window.requestAnimationFrame(refresh);
const msPassed = msNow - msPrev;
if (msPassed < msPerFrame)
return;
const excessTime = msPassed % msPerFrame;
msPrev = msNow - excessTime;
fn(cancelAnimation);
};
refresh(msPrev);
return cancelAnimation;
};
const defaultConfig = {
immediate: false,
delay: 100
};
const debounceResize = (cb, namespace = 'debounceResize', immediate = false, delay = 100) => {
const nm = namespace !== '' ? `.${namespace}` : '';
const events = [`resize${nm}`];
debounce(window, events, cb, { immediate, delay });
};
const debounce = (elem, event, cb, config) => {
const $elem = $be(elem);
const p = { ...defaultConfig, ...config };
let timer = null;
$elem.on(event, (ev, elem) => {
clearTimeout(timer);
timer = setTimeout(cb, p.delay, ev, elem);
});
if (p.immediate) {
$elem.each((elem) => {
const ev = new Event(typeof event === 'string' ? event : event[0]);
setTimeout(cb, 0, ev, elem);
});
}
};
//from: https://gist.github.com/gre/1650294... inspired by: https://nicmulvaney.com/easing
const easeInOutQuart = (t) => t < .5 ? 8 * t * t * t * t : 1 - 8 * (--t) * t * t * t;
const easeInOutCubic = (t) => t < .5 ? 4 * t * t * t : (t - 1) * (2 * t - 2) * (2 * t - 2) + 1;
const easeOutQuint = (t) => 1 + (--t) * t * t * t * t;
const linear = (t) => t;
const Easing = {
// no easing, no acceleration
linear,
// acceleration until halfway, then deceleration
easeInOutCubic,
// acceleration until halfway, then deceleration
easeInOutQuart,
// decelerating to zero velocity
easeOutQuint
};
const EVENT_NAME$b = 'smoothScroll';
const userBreakEvents = [`wheel.${EVENT_NAME$b}`, `touchstart.${EVENT_NAME$b}`];
let activeScroll = false;
function smoothScroll(scrollTargetY, duration = 500, easing = 'easeOutQuint', scrollEndFn) {
if (activeScroll)
return;
let progress = 0;
const startScrollY = window.scrollY, scrollDistance = Math.abs(startScrollY - scrollTargetY), scrollDir = startScrollY < scrollTargetY ? 1 : -1, msPerFrame = 1000 / 60, frames = duration / msPerFrame, progressSize = scrollDistance / frames;
if (scrollDistance === 0)
return;
activeScroll = true;
body.style.scrollBehavior = 'auto';
const easingFn = isFunc(easing)
? easing
: Easing[easing];
const cancelAnimation = animate(() => {
progress += progressSize;
const scrollProgress = scrollDistance * easingFn(progress / scrollDistance);
const yPos = startScrollY + scrollProgress * scrollDir;
window.scroll(0, yPos);
if (progress > scrollDistance)
cancel();
});
const cancel = () => {
if (isFunc(scrollEndFn))
scrollEndFn();
cancelAnimation();
$be(window).off([...userBreakEvents, `scroll.${EVENT_NAME$b}`]);
body.style.scrollBehavior = null;
activeScroll = false;
};
$be(window).on(userBreakEvents, cancel);
debounce(window, `scroll.${EVENT_NAME$b}`, cancel);
}
const Cookies = {
get(name) {
const arg = name + "=";
const alen = arg.length;
const clen = document.cookie.length;
let i = 0;
while (i < clen) {
let j = i + alen;
if (document.cookie.substring(i, j) == arg) {
return getCookieVal(j);
}
i = document.cookie.indexOf(" ", i) + 1;
if (i == 0)
break;
}
return "";
},
set(name, value, props = {}) {
const d = new Date();
d.setTime(d.getTime() + ((props.expires || 0) * 60 * 1000));
const expires = props.expires ? d.toUTCString() : null;
document.cookie = name + "=" + encodeURI(value) +
((expires) ? "; expires=" + expires : "") +
"; path=" + (props.path ? props.path : "/") +
((props.domain) ? "; domain=" + props.domain : "") +
((props.sameSite) ? "; sameSite=" + props.sameSite : "") +
((props.secure || props.sameSite && props.sameSite.toLowerCase() === "none") ? "; secure" : "");
},
remove(name, path, domain) {
if (this.get(name)) {
document.cookie = name + "=" +
((path) ? "; path=" + path : "") +
((domain) ? "; domain=" + domain : "") +
"; expires=Thu, 01-Jan-70 00:00:01 GMT";
}
},
};
//utility
function getCookieVal(offset) {
let endstr = document.cookie.indexOf(";", offset);
if (endstr == -1) {
endstr = document.cookie.length;
}
return decodeURI(document.cookie.substring(offset, endstr));
}
const defaultProps = {
focusFirst: true,
nameSpace: 'focusTrap',
focusable: ['button', 'a', 'input', 'select', 'textarea', '[tabindex]']
};
const canFocusEls = (el) => {
const baseFocusableRules = $be.isVisible(el) && el.tabIndex !== -1;
const nodeName = el.nodeName.toUpperCase();
if ((nodeName === 'BUTTON' || nodeName === 'INPUT')) {
return baseFocusableRules && !el.disabled;
}
return baseFocusableRules && el.style.pointerEvents !== 'none';
};
const focusTrap = (elem, props) => {
const d = document;
const body = d.body;
const { focusFirst, focusable, nameSpace } = { ...defaultProps, ...props };
const $trapElem = $be(elem);
const focusableJoined = typeof focusable === 'string' ? focusable : focusable.join(',');
const $firstFocusable = $trapElem.find(focusableJoined).filter(canFocusEls);
let firstFocusable = $firstFocusable.hasEls ? $firstFocusable.elem[0] : null;
if (focusFirst && firstFocusable) {
firstFocusable.focus();
}
$be(body).on(`keydown.${nameSpace}`, function (e) {
const $focusable = $trapElem.find(focusableJoined).filter(canFocusEls);
if (!$focusable.hasEls)
return;
const activeEl = d.activeElement;
const lastFocusable = $focusable.elem[$focusable.size - 1];
const isTabPressed = e.key === 'Tab';
firstFocusable = $focusable.elem[0];
if (!isTabPressed) {
return;
}
if (activeEl.nodeName.toUpperCase() === 'BODY') {
// somehow we lost focus
// this can happen if the last element is disabled if it was focused
// so re-assign to the first element
firstFocusable && firstFocusable.focus();
e.preventDefault();
}
if (e.shiftKey) {
// if shift key pressed for shift + tab combination
if (activeEl &&
firstFocusable &&
d.activeElement === firstFocusable) {
lastFocusable && lastFocusable.focus();
e.preventDefault();
}
}
else {
// if tab key is pressed
if (activeEl &&
lastFocusable &&
activeEl === lastFocusable) {
firstFocusable && firstFocusable.focus();
e.preventDefault();
}
}
});
return {
remove: () => {
$be(body).off(`keydown.${nameSpace}`);
}
};
};
const KEYS = {
esc: 'Escape',
left: 'ArrowLeft',
right: 'ArrowRight',
down: 'ArrowDown',
up: 'ArrowUp',
enter: 'Enter',
shift: 'Shift',
space: 'Space',
tab: 'Tab'
};
const VERSION$a = "1.3.0", DATA_NAME$a = 'AccessibleMenu', EVENT_NAME$a = 'accessibleMenu', DEFAULTS$a = {
keyDirections: ['horizontal', 'vertical', 'vertical'],
focusCss: 'focus',
focusInElems: 'a, [tabindex]',
focusLeaveElems: 'a, [tabindex], select, button'
};
class AccessibleMenu {
static defaults = DEFAULTS$a;
static version = VERSION$a;
static pluginName = DATA_NAME$a;
element;
$element;
params;
$aeLiParents = null;
activeElem = null;
focusInElems = '';
constructor(element, options) {
const s = this;
const dataOptions = getDataOptions(element, EVENT_NAME$a);
s.element = element;
s.$element = $be(element);
s.params = setParams(AccessibleMenu.defaults, options, dataOptions);
s.#handleEvents();
return s;
}
static remove(element, plugin) {
$be(element).each((elem) => {
const s = plugin || Store(elem, DATA_NAME$a);
s.$element.off([
`focusin.${EVENT_NAME$a}`,
`mouseleave.${EVENT_NAME$a}`,
`blur.${EVENT_NAME$a}`,
`keydown.${EVENT_NAME$a}`
]);
Store(elem, DATA_NAME$a, null);
});
}
#prev(e) {
const s = this, p = s.params, l = s.$aeLiParents.elem.length - 1, key = e.key, dirs = p.keyDirections;
if (key === KEYS.left && dirs[l] === "horizontal" ||
key === KEYS.up && dirs[l] === "vertical" ||
key === KEYS.left && dirs[l] === "vertical" &&
(l > 1 && dirs[l - 1] === "vertical" && s.$aeLiParents.hasEls)) {
s.#focusListItem(true);
e.preventDefault();
}
}
#next(e) {
const s = this, p = s.params, l = s.$aeLiParents.size - 1, atRootUl = s.$aeLiParents.size === 1, key = e.key, keyIsRight = key === KEYS.right && p.keyDirections[l], keyIsDown = key === KEYS.down && p.keyDirections[l], activeLi = s.activeElem.closest('li'), $sliblingLis = $be(activeLi).siblings('li', true), isLastLi = $sliblingLis.elem.at(-1) === activeLi, isLastAtRoolLevel = atRootUl && isLastLi;
//go to sibling <li>
if (keyIsRight === "horizontal" || keyIsDown === "vertical") {
if (!isLastAtRoolLevel) {
s.#focusListItem(false);
e.preventDefault();
}
}
if (key === KEYS.esc && isLastAtRoolLevel) {
$be(s.activeElem.closest('li')).rmClass(p.focusCss);
}
//go to the nestled <li>
if (keyIsRight === "vertical" || keyIsDown === "horizontal") {
const $nestledUl = $be(s.activeElem.closest('li')).findOne('ul');
s.#focusFirstElem($nestledUl);
e.preventDefault();
}
}
#handleEvents() {
const s = this, p = s.params, $lis = s.$element.findBy('tag', 'li'), lis = $lis.toArray();
let focusOutDelay = null;
s.$element.on(`focusin.${EVENT_NAME$a}`, () => {
s.activeElem = document.activeElement;
focusOutDelay && clearTimeout(focusOutDelay);
$be(s.activeElem.closest('li'))
.addClass(p.focusCss)
.siblings('li').rmClass(p.focusCss);
}, lis)
.on(`focusout.${EVENT_NAME$a}`, () => {
focusOutDelay = setTimeout(() => $lis.rmClass(p.focusCss), 200);
})
.on(`mouseleave.${EVENT_NAME$a}`, () => {
$lis.rmClass(p.focusCss);
})
.on(`keydown.${EVENT_NAME$a}`, (e) => {
s.$aeLiParents = $be(s.activeElem).parents('li', s.element);
if (e.key == KEYS.esc)
s.#focusFirstElem(s.$aeLiParents);
s.#prev(e);
s.#next(e);
});
}
#focusFirstElem($focusWrapEl, prev = false, index = 0) {
if (!$focusWrapEl.hasEls)
return;
const s = this, p = s.params, $focusEls = $focusWrapEl.find(p.focusInElems, $be.isVisible);
if ($focusEls.hasEls) {
const focusEl = $focusEls.elem[index];
$be(focusEl.closest('li')).tgClass(p.focusCss, !prev);
focusEl.focus();
}
}
#focusListItem(prev) {
const s = this, p = s.params, currLi = s.activeElem.closest('li'), siblingLi = (prev ? currLi.previousElementSibling : currLi.nextElementSibling), $currLi = $be(currLi), $siblingLi = $be(siblingLi);
if ($siblingLi.hasEls) {
s.#focusFirstElem($siblingLi, prev);
}
else {
// go to the parent <li> if there is no sibling <li>
const nth = s.$aeLiParents.size > 2 ? -2 : 0;
$currLi.rmClass(p.focusCss);
s.#focusFirstElem($be(s.$aeLiParents.elem.at(nth)), prev);
}
}
}
const VERSION$9 = "4.0.0", DATA_NAME$9 = 'Collapse', EVENT_NAME$9 = 'collapse', DEFAULTS$9 = {
cssPrefix: 'collapse',
toggleDuration: 500,
toggleGroup: false,
moveToTopOnOpen: false,
moveToTopOffset: 0,
moveToTopDuration: 500,
urlFilterType: 'hash',
historyType: 'replace',
locationFilter: null,
loadLocation: true,
afterOpen: noop,
afterClose: noop,
afterInit: noop
};
class Collapse {
$element;
element;
params;
toggling;
$btnElems;
btnElems;
$activeItem;
initLoaded;
static defaults = DEFAULTS$9;
static version = VERSION$9;
static pluginName = DATA_NAME$9;
#transition = $be.useTransition();
constructor(element, options, index) {
const s = this;
s.element = element;
s.$element = $be(element);
const dataOptions = getDataOptions(element, EVENT_NAME$9);
s.params = setParams(Collapse.defaults, options, dataOptions);
s.toggling = false;
s.$btnElems = s.$element.find(`.${s.params.cssPrefix}__btn`).attr({ 'aria-expanded': 'false' });
s.btnElems = s.$btnElems.toArray();
s.$activeItem = null;
s.initLoaded = false;
// init
s.#loadFromUrl();
s.#handleEvents();
s.params.afterInit(element);
Store(element, DATA_NAME$9, s);
return s;
}
static remove(element, plugin) {
$be(element).each((elem) => {
const s = plugin || Store(elem, DATA_NAME$9);
s.$element.off([`click.${EVENT_NAME$9}`, `[${EVENT_NAME$9}]`]);
$be(window).off(`popstate.${EVENT_NAME$9}`);
// delete the Store item
Store(elem, DATA_NAME$9, null);
});
}
#handleEvents() {
const s = this;
const { cssPrefix } = s.params;
s.$element.on([`click.${EVENT_NAME$9}`, `[${EVENT_NAME$9}]`], function (e, elem) {
const elemId = $be(elem).attr('aria-controls') || elem.hash.substring(1);
s.toggle(elemId);
e.preventDefault();
}, `.${cssPrefix}__btn`);
$be(window).on(`popstate.${EVENT_NAME$9}`, (e) => {
if (s.params.historyType === 'push') {
s.#loadFromUrl();
s.initLoaded = true;
e.preventDefault();
}
});
}
#loadFromUrl() {
const s = this;
const p = s.params;
const loadElem = (filterEl) => {
const cssOpen = `${p.cssPrefix}--open`;
const $tryElem = s.$element.find('#' + filterEl);
if ($tryElem.elem.length) {
s.$activeItem = $tryElem;
s.$activeItem.addClass(cssOpen);
s.$btnElems
.filter(el => $be(el).attr('aria-controls') === filterEl)
.attr({ 'aria-expanded': 'true' });
}
};
if (p.locationFilter !== null && p.loadLocation && p.urlFilterType !== 'none') {
const filterEl = UrlState.get(p.urlFilterType, p.locationFilter);
const cssOpen = `${p.cssPrefix}--open`;
s.$element.find(`.${p.cssPrefix}__body.${cssOpen}`).rmClass(cssOpen);
s.$btnElems.attr({ 'aria-expanded': 'false' });
if (filterEl) {
if (Array.isArray(filterEl)) {
filterEl.forEach(loadElem);
}
else {
loadElem(filterEl);
}
}
}
}
#moveToTopOnOpen() {
const s = this;
const p = s.params;
if (s.$activeItem) {
const item = s.$activeItem.map(el => el.closest(`.${p.cssPrefix}__item`));
const offsetTop = typeof p.moveToTopOffset === 'function' ? p.moveToTopOffset() : p.moveToTopOffset;
if (item.length && p.moveToTopOnOpen) {
const top = (item[0].getBoundingClientRect().top + window.scrollY) - offsetTop;
smoothScroll(top, p.moveToTopDuration);
}
}
}
toggle(currElemID, allAtOnce = false) {
const s = this;
const p = s.params;
const activeItem = $be.findOne('#' + currElemID, s.element);
if ((s.toggling && !allAtOnce) || currElemID === null || !activeItem)
return;
s.$activeItem = s.$element.find('#' + currElemID);
const cssPrefix = `${p.cssPrefix}--`, cssOpen = `${cssPrefix}open`, cssToggling = `${cssPrefix}toggling`, cssOpening = `${cssPrefix}opening`, cssClosing = `${cssPrefix}closing`, cssBodyOpen = `.${p.cssPrefix}__body.${cssOpen}`, $currOpenItems = s.$element.find(cssBodyOpen), $itemsToClose = $currOpenItems.filter(el => p.toggleGroup || el.id === currElemID), activeAlreadyOpen = s.$activeItem.hasClass(cssOpen);
$itemsToClose.each((elem) => $be.css(elem, { height: elem.scrollHeight + 'px' }));
const start = () => {
s.toggling = true;
s.$btnElems.each((elem) => {
const $btn = $be(elem);
const current = $btn.attr('aria-controls') === currElemID;
const expanded = $btn.attr('aria-expanded') === 'false';
if (p.toggleGroup) {
$btn.attr({ 'aria-expanded': (current && expanded) + '' });
}
else if (current) {
$btn.attr({ 'aria-expanded': expanded + '' });
}
});
$itemsToClose
.rmClass(cssOpen)