@chahindb7/vue-masonry-wall
Version:
Responsive masonry layout with SSR support and zero dependencies for Vue 3 (modified by Chahin).
209 lines (208 loc) • 5.71 kB
JavaScript
import { defineComponent as Y, ref as M, nextTick as F, onBeforeUnmount as H, onMounted as U, watch as q, toRefs as G, openBlock as p, createElementBlock as m, createElementVNode as _, toDisplayString as j, normalizeStyle as $, Fragment as A, renderList as C, unref as J, renderSlot as K, createTextVNode as P } from "vue";
function Q(n, l) {
try {
let o;
return (...c) => {
o !== void 0 && clearTimeout(o), o = setTimeout(() => n(...c), l);
};
} catch (o) {
console.error("Error debouncing", o);
}
}
function X({
columns: n,
columnWidth: l,
emit: o,
gap: c,
items: u,
maxColumns: i,
minColumns: g,
nextTick: s,
onBeforeUnmount: b,
onMounted: S,
rtl: f,
scrollContainer: a,
ssrColumns: h,
vue: L,
wall: w,
watch: k
}) {
function R(t, e, r, y) {
try {
const d = z(r);
return y + e + d <= t ? R(
t,
e,
r + 1,
y + e + d
) : r;
} catch (d) {
console.error("Error counting iteratively", d);
}
}
function z(t) {
try {
const e = Array.isArray(l.value) ? l.value : [l.value];
return e[t % e.length];
} catch (e) {
console.error("Error getting column width target", e);
}
}
function N() {
try {
const t = R(
w.value.getBoundingClientRect().width,
c.value,
0,
// Needs to be offset my negative gap to prevent gap counts being off by one
-c.value
), e = W(V(t));
return e > 0 ? e : 1;
} catch (t) {
console.error("Error getting column count", t);
}
}
function V(t) {
try {
const e = i == null ? void 0 : i.value;
return e && t > e ? e : t;
} catch (e) {
console.error("Error getting below max", e);
}
}
function W(t) {
try {
const e = g == null ? void 0 : g.value;
return e && t < e ? e : t;
} catch (e) {
console.error("Error getting above min", e);
}
}
let B = 0;
async function T(t, e) {
try {
if (t >= u.value.length || (await s(), B !== e))
return;
const r = [...w.value.children];
f.value && r.reverse();
const y = r.reduce(
(d, x) => x.getBoundingClientRect().height < d.getBoundingClientRect().height ? x : d
);
n.value[+y.dataset.index].push(t), await T(t + 1, e);
} catch (r) {
console.error("Error filling columns", r);
}
}
async function E(t = !1) {
try {
const e = N();
if (n.value.length === e && !t) {
o(L === 2 ? "redraw-skip" : "redrawSkip");
return;
}
n.value = D(e);
const r = a == null ? void 0 : a.value, y = r ? r.scrollTop : window.scrollY;
await T(0, ++B), r && r instanceof HTMLElement && (r == null || r.scrollBy({ top: y - r.scrollTop })), o("redraw");
} catch (e) {
console.error("Error redrawing", e);
}
}
const v = typeof ResizeObserver > "u" ? void 0 : new ResizeObserver(Q(() => E()));
if (S(() => {
E(), v == null || v.observe(w.value);
}), b(() => v == null ? void 0 : v.unobserve(w.value)), k([u, f], () => E(!0)), k([l, c, g, i], () => E()), h.value > 0) {
console.log("Creating SSR columns");
try {
const t = D(h.value);
console.log("SSR columns created", t), u.value.forEach(
(e, r) => t[r % h.value].push(r)
), console.log("SSR columns filled", t), n.value = [[0], [1], [2], []];
} catch (t) {
console.error("Error creating SSR columns", t);
}
}
return { getColumnWidthTarget: z };
}
function D(n) {
try {
return Array.from({ length: n }).map(() => []);
} catch (l) {
return console.error("Error creating columns", l), [];
}
}
const Z = { style: { "margin-bottom": "10px", color: "black" } }, O = ["data-index"], ee = /* @__PURE__ */ Y({
__name: "MasonryWall",
props: {
columnWidth: { default: 400 },
items: {},
gap: { default: 0 },
rtl: { type: Boolean, default: !1 },
ssrColumns: { default: 0 },
scrollContainer: { default: null },
minColumns: { default: 1 },
maxColumns: {},
keyMapper: {}
},
emits: ["redraw", "redrawSkip"],
setup(n, { emit: l }) {
const o = n, c = l, u = M([]), i = M();
console.log("zjzzjzjzjzzj");
const { getColumnWidthTarget: g } = X({
columns: u,
emit: c,
nextTick: F,
onBeforeUnmount: H,
onMounted: U,
vue: 3,
wall: i,
watch: q,
...G(o)
});
return (s, b) => (p(), m("div", null, [
_("div", Z, j(u.value), 1),
_("div", {
ref_key: "wall",
ref: i,
class: "masonry-wall",
style: $({ display: "flex", gap: `${s.gap}px` })
}, [
(p(!0), m(A, null, C(u.value, (S, f) => (p(), m("div", {
key: f,
class: "masonry-column",
"data-index": f,
style: $({
display: "flex",
"flex-basis": `${J(g)(f)}px`,
"flex-direction": "column",
"flex-grow": 1,
gap: `${s.gap}px`,
height: [
"-webkit-max-content",
"-moz-max-content",
"max-content"
],
"min-width": 0
})
}, [
(p(!0), m(A, null, C(S, (a, h) => (p(), m("div", {
key: a,
class: "masonry-item"
}, [
K(s.$slots, "default", {
item: s.items[a],
column: f,
row: h,
index: a
}, () => [
P(j(s.items[a]), 1)
])
]))), 128))
], 12, O))), 128))
], 4)
]));
}
});
export {
ee as default
};
//# sourceMappingURL=vue-masonry-wall.es.js.map