uikit
Version:
UIkit is a lightweight and modular front-end framework for developing fast and powerful web interfaces.
567 lines (426 loc) • 15.9 kB
JavaScript
/*! UIkit 3.14.1 | https://www.getuikit.com | (c) 2014 - 2022 YOOtheme | MIT License */
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('uikit-util')) :
typeof define === 'function' && define.amd ? define('uikitfilter', ['uikit-util'], factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.UIkitFilter = factory(global.UIkit.util));
})(this, (function (uikitUtil) { 'use strict';
function getRows(items) {
return sortBy(items, 'top', 'bottom');
}
function sortBy(items, startProp, endProp) {
const sorted = [[]];
for (const el of items) {
if (!uikitUtil.isVisible(el)) {
continue;
}
let dim = getOffset(el);
for (let i = sorted.length - 1; i >= 0; i--) {
const current = sorted[i];
if (!current[0]) {
current.push(el);
break;
}
let startDim;
if (current[0].offsetParent === el.offsetParent) {
startDim = getOffset(current[0]);
} else {
dim = getOffset(el, true);
startDim = getOffset(current[0], true);
}
if (dim[startProp] >= startDim[endProp] - 1 && dim[startProp] !== startDim[startProp]) {
sorted.push([el]);
break;
}
if (dim[endProp] - 1 > startDim[startProp] || dim[startProp] === startDim[startProp]) {
current.push(el);
break;
}
if (i === 0) {
sorted.unshift([el]);
break;
}
}
}
return sorted;
}
function getOffset(element, offset) {if (offset === void 0) {offset = false;}
let { offsetTop, offsetLeft, offsetHeight, offsetWidth } = element;
if (offset) {
[offsetTop, offsetLeft] = uikitUtil.offsetPosition(element);
}
return {
top: offsetTop,
left: offsetLeft,
bottom: offsetTop + offsetHeight,
right: offsetLeft + offsetWidth };
}
const clsLeave = 'uk-transition-leave';
const clsEnter = 'uk-transition-enter';
function fade(action, target, duration, stagger) {if (stagger === void 0) {stagger = 0;}
const index = transitionIndex(target, true);
const propsIn = { opacity: 1 };
const propsOut = { opacity: 0 };
const wrapIndexFn = (fn) => () => index === transitionIndex(target) ? fn() : Promise.reject();
const leaveFn = wrapIndexFn(() => {
uikitUtil.addClass(target, clsLeave);
return Promise.all(
getTransitionNodes(target).map(
(child, i) =>
new Promise((resolve) =>
setTimeout(
() =>
uikitUtil.Transition.start(child, propsOut, duration / 2, 'ease').then(
resolve),
i * stagger)))).
then(() => uikitUtil.removeClass(target, clsLeave));
});
const enterFn = wrapIndexFn(() => {
const oldHeight = uikitUtil.height(target);
uikitUtil.addClass(target, clsEnter);
action();
uikitUtil.css(uikitUtil.children(target), { opacity: 0 });
// Ensure UIkit updates have propagated
return new Promise((resolve) =>
requestAnimationFrame(() => {
const nodes = uikitUtil.children(target);
const newHeight = uikitUtil.height(target);
// Ensure Grid cells do not stretch when height is applied
uikitUtil.css(target, 'alignContent', 'flex-start');
uikitUtil.height(target, oldHeight);
const transitionNodes = getTransitionNodes(target);
uikitUtil.css(nodes, propsOut);
const transitions = transitionNodes.map(
(child, i) =>
new Promise((resolve) =>
setTimeout(
() =>
uikitUtil.Transition.start(child, propsIn, duration / 2, 'ease').then(
resolve),
i * stagger)));
if (oldHeight !== newHeight) {
transitions.push(
uikitUtil.Transition.start(
target,
{ height: newHeight },
duration / 2 + transitionNodes.length * stagger,
'ease'));
}
Promise.all(transitions).then(() => {
uikitUtil.removeClass(target, clsEnter);
if (index === transitionIndex(target)) {
uikitUtil.css(target, { height: '', alignContent: '' });
uikitUtil.css(nodes, { opacity: '' });
delete target.dataset.transition;
}
resolve();
});
}));
});
return uikitUtil.hasClass(target, clsLeave) ?
waitTransitionend(target).then(enterFn) :
uikitUtil.hasClass(target, clsEnter) ?
waitTransitionend(target).then(leaveFn).then(enterFn) :
leaveFn().then(enterFn);
}
function transitionIndex(target, next) {
if (next) {
target.dataset.transition = 1 + transitionIndex(target);
}
return uikitUtil.toNumber(target.dataset.transition) || 0;
}
function waitTransitionend(target) {
return Promise.all(
uikitUtil.children(target).
filter(uikitUtil.Transition.inProgress).
map(
(el) =>
new Promise((resolve) => uikitUtil.once(el, 'transitionend transitioncanceled', resolve))));
}
function getTransitionNodes(target) {
return getRows(uikitUtil.children(target)).reduce(
(nodes, row) =>
nodes.concat(
uikitUtil.sortBy(
row.filter((el) => uikitUtil.isInView(el)),
'offsetLeft')),
[]);
}
function slide (action, target, duration) {
return new Promise((resolve) =>
requestAnimationFrame(() => {
let nodes = uikitUtil.children(target);
// Get current state
const currentProps = nodes.map((el) => getProps(el, true));
const targetProps = uikitUtil.css(target, ['height', 'padding']);
// Cancel previous animations
uikitUtil.Transition.cancel(target);
nodes.forEach(uikitUtil.Transition.cancel);
reset(target);
// Adding, sorting, removing nodes
action();
// Find new nodes
nodes = nodes.concat(uikitUtil.children(target).filter((el) => !uikitUtil.includes(nodes, el)));
// Wait for update to propagate
Promise.resolve().then(() => {
// Force update
uikitUtil.fastdom.flush();
// Get new state
const targetPropsTo = uikitUtil.css(target, ['height', 'padding']);
const [propsTo, propsFrom] = getTransitionProps(target, nodes, currentProps);
// Reset to previous state
nodes.forEach((el, i) => propsFrom[i] && uikitUtil.css(el, propsFrom[i]));
uikitUtil.css(target, { display: 'block', ...targetProps });
// Start transitions on next frame
requestAnimationFrame(() => {
const transitions = nodes.
map(
(el, i) =>
uikitUtil.parent(el) === target &&
uikitUtil.Transition.start(el, propsTo[i], duration, 'ease')).
concat(uikitUtil.Transition.start(target, targetPropsTo, duration, 'ease'));
Promise.all(transitions).
then(() => {
nodes.forEach(
(el, i) =>
uikitUtil.parent(el) === target &&
uikitUtil.css(el, 'display', propsTo[i].opacity === 0 ? 'none' : ''));
reset(target);
}, uikitUtil.noop).
then(resolve);
});
});
}));
}
function getProps(el, opacity) {
const zIndex = uikitUtil.css(el, 'zIndex');
return uikitUtil.isVisible(el) ?
{
display: '',
opacity: opacity ? uikitUtil.css(el, 'opacity') : '0',
pointerEvents: 'none',
position: 'absolute',
zIndex: zIndex === 'auto' ? uikitUtil.index(el) : zIndex,
...getPositionWithMargin(el) } :
false;
}
function getTransitionProps(target, nodes, currentProps) {
const propsTo = nodes.map((el, i) =>
uikitUtil.parent(el) && i in currentProps ?
currentProps[i] ?
uikitUtil.isVisible(el) ?
getPositionWithMargin(el) :
{ opacity: 0 } :
{ opacity: uikitUtil.isVisible(el) ? 1 : 0 } :
false);
const propsFrom = propsTo.map((props, i) => {
const from = uikitUtil.parent(nodes[i]) === target && (currentProps[i] || getProps(nodes[i]));
if (!from) {
return false;
}
if (!props) {
delete from.opacity;
} else if (!('opacity' in props)) {
const { opacity } = from;
if (opacity % 1) {
props.opacity = 1;
} else {
delete from.opacity;
}
}
return from;
});
return [propsTo, propsFrom];
}
function reset(el) {
uikitUtil.css(el.children, {
height: '',
left: '',
opacity: '',
pointerEvents: '',
position: '',
top: '',
marginTop: '',
marginLeft: '',
transform: '',
width: '',
zIndex: '' });
uikitUtil.css(el, { height: '', display: '', padding: '' });
}
function getPositionWithMargin(el) {
const { height, width } = uikitUtil.offset(el);
const { top, left } = uikitUtil.position(el);
const { marginLeft, marginTop } = uikitUtil.css(el, ['marginTop', 'marginLeft']);
return { top, left, height, width, marginLeft, marginTop, transform: '' };
}
var Animate = {
props: {
duration: Number,
animation: Boolean },
data: {
duration: 150,
animation: 'slide' },
methods: {
animate(action, target) {if (target === void 0) {target = this.$el;}
const name = this.animation;
const animationFn =
name === 'fade' ?
fade :
name === 'delayed-fade' ?
function () {for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {args[_key] = arguments[_key];}return fade(...args, 40);} :
name ?
slide :
() => {
action();
return Promise.resolve();
};
return animationFn(action, target, this.duration).then(
() => this.$update(target, 'resize'),
uikitUtil.noop);
} } };
var Component = {
mixins: [Animate],
args: 'target',
props: {
target: Boolean,
selActive: Boolean },
data: {
target: null,
selActive: false,
attrItem: 'uk-filter-control',
cls: 'uk-active',
duration: 250 },
computed: {
toggles: {
get(_ref, $el) {let { attrItem } = _ref;
return uikitUtil.$$("[" + attrItem + "],[data-" + attrItem + "]", $el);
},
watch() {
this.updateState();
if (this.selActive !== false) {
const actives = uikitUtil.$$(this.selActive, this.$el);
this.toggles.forEach((el) => uikitUtil.toggleClass(el, this.cls, uikitUtil.includes(actives, el)));
}
},
immediate: true },
children: {
get(_ref2, $el) {let { target } = _ref2;
return uikitUtil.$$(target + " > *", $el);
},
watch(list, old) {
if (old && !isEqualList(list, old)) {
this.updateState();
}
},
immediate: true } },
events: [
{
name: 'click',
delegate() {
return "[" + this.attrItem + "],[data-" + this.attrItem + "]";
},
handler(e) {
e.preventDefault();
this.apply(e.current);
} }],
methods: {
apply(el) {
const prevState = this.getState();
const newState = mergeState(el, this.attrItem, this.getState());
if (!isEqualState(prevState, newState)) {
this.setState(newState);
}
},
getState() {
return this.toggles.
filter((item) => uikitUtil.hasClass(item, this.cls)).
reduce((state, el) => mergeState(el, this.attrItem, state), {
filter: { '': '' },
sort: [] });
},
setState(state, animate) {if (animate === void 0) {animate = true;}
state = { filter: { '': '' }, sort: [], ...state };
uikitUtil.trigger(this.$el, 'beforeFilter', [this, state]);
this.toggles.forEach((el) =>
uikitUtil.toggleClass(el, this.cls, !!matchFilter(el, this.attrItem, state)));
Promise.all(
uikitUtil.$$(this.target, this.$el).map((target) => {
const filterFn = () => {
applyState(state, target, uikitUtil.children(target));
this.$update(this.$el);
};
return animate ? this.animate(filterFn, target) : filterFn();
})).
then(() => uikitUtil.trigger(this.$el, 'afterFilter', [this]));
},
updateState() {
uikitUtil.fastdom.write(() => this.setState(this.getState(), false));
} } };
function getFilter(el, attr) {
return uikitUtil.parseOptions(uikitUtil.data(el, attr), ['filter']);
}
function isEqualState(stateA, stateB) {
return ['filter', 'sort'].every((prop) => uikitUtil.isEqual(stateA[prop], stateB[prop]));
}
function applyState(state, target, children) {
const selector = getSelector(state);
children.forEach((el) => uikitUtil.css(el, 'display', selector && !uikitUtil.matches(el, selector) ? 'none' : ''));
const [sort, order] = state.sort;
if (sort) {
const sorted = sortItems(children, sort, order);
if (!uikitUtil.isEqual(sorted, children)) {
uikitUtil.append(target, sorted);
}
}
}
function mergeState(el, attr, state) {
const filterBy = getFilter(el, attr);
const { filter, group, sort, order = 'asc' } = filterBy;
if (filter || uikitUtil.isUndefined(sort)) {
if (group) {
if (filter) {
delete state.filter[''];
state.filter[group] = filter;
} else {
delete state.filter[group];
if (uikitUtil.isEmpty(state.filter) || '' in state.filter) {
state.filter = { '': filter || '' };
}
}
} else {
state.filter = { '': filter || '' };
}
}
if (!uikitUtil.isUndefined(sort)) {
state.sort = [sort, order];
}
return state;
}
function matchFilter(
el,
attr, _ref3)
{let { filter: stateFilter = { '': '' }, sort: [stateSort, stateOrder] } = _ref3;
const { filter = '', group = '', sort, order = 'asc' } = getFilter(el, attr);
return uikitUtil.isUndefined(sort) ?
group in stateFilter && filter === stateFilter[group] ||
!filter && group && !(group in stateFilter) && !stateFilter[''] :
stateSort === sort && stateOrder === order;
}
function isEqualList(listA, listB) {
return listA.length === listB.length && listA.every((el) => listB.includes(el));
}
function getSelector(_ref4) {let { filter } = _ref4;
let selector = '';
uikitUtil.each(filter, (value) => selector += value || '');
return selector;
}
function sortItems(nodes, sort, order) {
return [...nodes].sort(
(a, b) =>
uikitUtil.data(a, sort).localeCompare(uikitUtil.data(b, sort), undefined, { numeric: true }) * (
order === 'asc' || -1));
}
if (typeof window !== 'undefined' && window.UIkit) {
window.UIkit.component('filter', Component);
}
return Component;
}));