blendy
Version:
_A framework-agnostic tool that smoothly transitions one element into another with just a few lines of code._
334 lines (333 loc) • 9.97 kB
JavaScript
function B(t) {
return typeof t == "object" && t !== null && "x" in t && "y" in t && "unit" in t && typeof t.unit == "string" && typeof t.x == "object" && typeof t.y == "object" && "topLeft" in t.x && "topRight" in t.x && "bottomRight" in t.x && "bottomLeft" in t.x && "topLeft" in t.y && "topRight" in t.y && "bottomRight" in t.y && "bottomLeft" in t.y;
}
function A(t) {
var y;
const e = t.match(/(\d+(?:\.\d+)?)(px|%)/g);
if (!e)
return {
x: { topLeft: 0, topRight: 0, bottomRight: 0, bottomLeft: 0 },
y: { topLeft: 0, topRight: 0, bottomRight: 0, bottomLeft: 0 },
unit: "px"
};
const n = e.map((f) => {
const [u, g, m] = f.match(/(\d+(?:\.\d+)?)(px|%)/) ?? [];
return { value: parseFloat(g), unit: m };
}), o = ((y = n[0]) == null ? void 0 : y.unit) || "px";
if (n.some((f) => f.unit !== o))
throw new Error("Inconsistent units in border-radius string.");
const [l, s, r, a] = n.map((f) => f.value), i = {
topLeft: l ?? 0,
topRight: s ?? l ?? 0,
bottomRight: r ?? l ?? 0,
bottomLeft: a ?? s ?? l ?? 0
};
return {
x: { ...i },
y: { ...i },
unit: o
};
}
function R({ x: t, y: e, unit: n }, o, l) {
if (n === "px") {
const s = {
topLeft: t.topLeft / o,
topRight: t.topRight / o,
bottomLeft: t.bottomLeft / o,
bottomRight: t.bottomRight / o
}, r = {
topLeft: e.topLeft / l,
topRight: e.topRight / l,
bottomLeft: e.bottomLeft / l,
bottomRight: e.bottomRight / l
};
return { x: s, y: r, unit: "px" };
} else if (n === "%")
return { x: t, y: e, unit: "%" };
return { x: t, y: e, unit: n };
}
function $(t) {
return `
${t.x.topLeft}${t.unit} ${t.x.topRight}${t.unit} ${t.x.bottomRight}${t.unit} ${t.x.bottomLeft}${t.unit}
/
${t.y.topLeft}${t.unit} ${t.y.topRight}${t.unit} ${t.y.bottomRight}${t.unit} ${t.y.bottomLeft}${t.unit}
`;
}
function T(t) {
return typeof t == "object" && "x" in t && "y" in t;
}
function d(t, e) {
return { x: t, y: e };
}
function E(t, e) {
return d(t.x + e.x, t.y + e.y);
}
function O(t, e) {
return d(t.x - e.x, t.y - e.y);
}
function X(t, e) {
return d(t.x * e, t.y * e);
}
function h(t, e, n) {
return t + (e - t) * n;
}
function Y(t, e, n) {
return E(t, X(O(e, t), n));
}
function q(t, e, n) {
return {
x: {
topLeft: h(t.x.topLeft, e.x.topLeft, n),
topRight: h(t.x.topRight, e.x.topRight, n),
bottomRight: h(t.x.bottomRight, e.x.bottomRight, n),
bottomLeft: h(t.x.bottomLeft, e.x.bottomLeft, n)
},
y: {
topLeft: h(t.y.topLeft, e.y.topLeft, n),
topRight: h(t.y.topRight, e.y.topRight, n),
bottomRight: h(t.y.bottomRight, e.y.bottomRight, n),
bottomLeft: h(t.y.bottomLeft, e.y.bottomLeft, n)
},
unit: t.unit
};
}
function w(t, e, n) {
return Math.min(Math.max(t, e), n);
}
const M = {
duration: 350,
easing: (t) => t
};
function j(t, e, n, o) {
let l = !1;
const s = () => {
l = !0;
}, r = { ...M, ...o };
let a;
function i(y) {
a === void 0 && (a = y);
const f = y - a, u = w(f / r.duration, 0, 1), g = Object.keys(t), m = Object.keys(e);
if (!g.every((c) => m.includes(c))) {
console.error("animate Error: `from` keys are different than `to`");
return;
}
const x = {};
g.forEach((c) => {
typeof t[c] == "number" && typeof e[c] == "number" ? x[c] = h(
t[c],
e[c],
r.easing(u)
) : B(t[c]) && B(e[c]) ? x[c] = q(
t[c],
e[c],
r.easing(u)
) : T(t[c]) && T(e[c]) && (x[c] = Y(
t[c],
e[c],
r.easing(u)
));
}), n(x, u >= 1, u), u < 1 && !l && requestAnimationFrame(i);
}
return requestAnimationFrame(i), s;
}
function k(t) {
return 1 + 2.5 * Math.pow(t - 1, 3) + 1.5 * Math.pow(t - 1, 2);
}
function z(t) {
return 1 - Math.pow(1 - t, 3);
}
function P(t) {
return {
x: t.x,
y: t.y,
width: t.width,
height: t.height
};
}
function N(t) {
let e = t, n = 0, o = 0;
for (; e; )
n += e.offsetTop, o += e.offsetLeft, e = e.offsetParent;
return {
x: o,
y: n,
width: t.offsetWidth,
height: t.offsetHeight
};
}
function v(t, e) {
let n = t, o = {
translateX: 0,
translateY: 0,
scaleX: 1,
scaleY: 1
};
typeof n.originalBorderRadius > "u" && (n.originalBorderRadius = window.getComputedStyle(n).borderRadius);
const l = {
el: () => n,
id: () => e,
setTransform: s,
clearTransform: r,
currentTransform: () => o,
originalBorderRadius: () => A(n.originalBorderRadius),
currentBorderRadius: () => A(window.getComputedStyle(n).borderRadius),
layoutRect: () => N(n),
boundingRect: () => P(n.getBoundingClientRect()),
cssPosition: () => window.getComputedStyle(n).position
};
function s(i) {
o = { ...o, ...i }, a();
}
function r() {
o = {
translateX: 0,
translateY: 0,
scaleX: 1,
scaleY: 1
}, a();
}
function a() {
const { translateX: i, translateY: y, scaleX: f, scaleY: u } = o;
i === 0 && y === 0 && f === 1 && u === 1 ? n.style.transform = "" : n.style.transform = `translate(${i}px, ${y}px) scale(${f}, ${u})`;
}
return l;
}
function _({
sourceViews: t,
config: e
}) {
const o = { ...{
config: e,
sourceViews: t,
toggleStatus: /* @__PURE__ */ new Map(),
targetViews: /* @__PURE__ */ new Map(),
cancelAnimation: {
blendy: null
}
} };
function l(s) {
const r = o.sourceViews.map(({ id: i }) => i()), a = s.filter(
(i) => !r.includes(i.id())
);
o.sourceViews.push(...a), a.forEach((i) => {
o.toggleStatus.set(i.id(), !1), o.targetViews.set(i.id(), null);
});
}
return {
sourceViewById: (s) => o.sourceViews.find((r) => s === r.id()),
isToggled: (s) => o.toggleStatus.get(s) || !1,
toggle: (s, r) => {
o.toggleStatus.set(s, !0), o.targetViews.set(s, r);
},
untoggle: (s) => {
o.toggleStatus.set(s, !1), o.targetViews.set(s, null);
},
targetView: (s) => o.targetViews.get(s),
cancelAnimation: () => o.cancelAnimation,
config: () => e,
syncSourceViews: l
};
}
const G = {
animation: "dynamic"
};
function U(t) {
switch (t) {
case "dynamic":
return { easing: z, duration: 450 };
case "spring":
return { easing: k, duration: 400 };
}
}
function H(t) {
const e = { ...G, ...t };
let n = [];
const o = _({ sourceViews: [], config: e });
requestAnimationFrame(l);
function l() {
n = Array.from(
document.querySelectorAll("[data-blendy-from]")
).map((i) => {
const y = i;
return v(y, y.dataset.blendyFrom);
}), o.syncSourceViews(n);
}
function s(i, y) {
o.isToggled(i) || requestAnimationFrame(() => {
const f = o.sourceViewById(i), u = document.querySelector(
`[data-blendy-to=${i}]`
);
if (u) {
const g = v(u, i);
o.toggle(i, g), C(f, g, o, y);
}
});
}
function r(i, y) {
o.isToggled(i) && requestAnimationFrame(() => {
const f = o.sourceViewById(i), u = o.targetView(i);
f && (C(u, f, o, y), o.untoggle(i));
});
}
function a() {
requestAnimationFrame(() => {
l();
});
}
return {
toggle: s,
untoggle: r,
update: a
};
}
function C(t, e, n, o) {
var c, S;
(S = (c = n.cancelAnimation()).blendy) == null || S.call(c);
const l = t.boundingRect(), s = e.boundingRect(), r = t.el().children[0], a = e.el().children[0], i = getComputedStyle(r).display === "inline", y = getComputedStyle(a).display === "inline", f = s.x - l.x, u = s.y - l.y, g = s.width / l.width, m = s.height / l.height, x = e.el().style.zIndex || "0";
requestAnimationFrame(() => {
e.el().style.opacity = "1", t.el().style.opacity = "1", e.el().style.pointerEvents = "", t.el().style.pointerEvents = "none", i && (r.style.display = "block"), y && (a.style.display = "block"), e.el().style.overflow = "hidden", t.el().style.overflow = "hidden";
}), e.el().style.transformOrigin = "0 0", t.el().style.transformOrigin = "0 0", t.cssPosition() === "static" && (t.el().style.position = "relative"), e.cssPosition() === "static" && (e.el().style.position = "relative"), e.setTransform({
translateX: -f,
translateY: -u,
scaleX: 1 / g,
scaleY: 1 / m
}), e.el().style.borderRadius = $(
R(
t.originalBorderRadius(),
1 / g,
1 / m
)
), t.el().style.zIndex = `${Number(x + 1e3)}`, n.cancelAnimation().blendy = j(
{
translate: d(0, 0),
scale: d(1, 1),
borderRadius: t.originalBorderRadius()
},
{
translate: d(f, u),
scale: d(g, m),
borderRadius: e.originalBorderRadius()
},
({ translate: L, scale: p, borderRadius: b }, I, F) => {
t.setTransform({
translateX: L.x,
translateY: L.y,
scaleX: p.x,
scaleY: p.y
}), t.el().style.borderRadius = $(
R(b, p.x, p.y)
), t.el().style.opacity = `${h(1, 0, F * 6)}`, r.style.transform = `scale(${1 / p.x}, ${1 / p.y})`, e.setTransform({
translateX: L.x - f,
translateY: L.y - u,
scaleX: p.x / g,
scaleY: p.y / m
}), a.style.transform = `scale(${g / p.x}, ${m / p.y})`, e.el().style.borderRadius = $(
R(b, p.x / g, p.y / m)
), I && (r.style.display = "", a.style.display = "", r.style.transform = "", a.style.transform = "", e.el().style.overflow = "", t.el().style.overflow = "", e.el().style.position = "", t.el().style.position = "", e.el().style.zIndex = "", t.el().style.zIndex = "", e.el().style.opacity = "", t.el().style.opacity = "0", t.el().style.pointerEvents = "none", t.clearTransform(), e.clearTransform(), t.el().style.transformOrigin = "", e.el().style.transformOrigin = "", t.el().style.borderRadius = "", e.el().style.borderRadius = "", o == null || o());
},
U(n.config().animation)
);
}
export {
H as createBlendy
};