tudou-waterfall 0.1.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs ADDED
@@ -0,0 +1,182 @@
1
+ "use strict";
2
+ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: "Module" } });
3
+ const vue = require("vue");
4
+ const _sfc_main = /* @__PURE__ */ vue.defineComponent({
5
+ __name: "Waterfall",
6
+ props: {
7
+ items: {},
8
+ cols: { default: 0 },
9
+ gap: { default: 15 },
10
+ estimatedHeight: { default: 220 },
11
+ overscan: { default: 600 },
12
+ breakpoints: { default: () => [
13
+ { minWidth: 1400, cols: 9 },
14
+ { minWidth: 1200, cols: 8 },
15
+ { minWidth: 900, cols: 7 },
16
+ { minWidth: 700, cols: 6 },
17
+ { minWidth: 500, cols: 5 }
18
+ ] },
19
+ defaultCols: { default: 2 }
20
+ },
21
+ emits: ["reflow"],
22
+ setup(__props, { emit: __emit }) {
23
+ const props = __props;
24
+ const emit = __emit;
25
+ const containerRef = vue.ref(null);
26
+ const scrollTop = vue.ref(0);
27
+ const viewportHeight = vue.ref(0);
28
+ const colPositions = vue.ref([]);
29
+ const colTotalHeights = vue.ref([]);
30
+ const measuredHeights = /* @__PURE__ */ new Map();
31
+ const getColCount = () => {
32
+ var _a, _b;
33
+ if (props.cols > 0) return props.cols;
34
+ const width = ((_a = containerRef.value) == null ? void 0 : _a.clientWidth) ?? window.innerWidth;
35
+ const sorted = [...props.breakpoints].sort((a, b) => b.minWidth - a.minWidth);
36
+ return ((_b = sorted.find((bp) => width >= bp.minWidth)) == null ? void 0 : _b.cols) ?? props.defaultCols;
37
+ };
38
+ const reflow = async () => {
39
+ await vue.nextTick();
40
+ const count = getColCount();
41
+ const cols = Array.from({ length: count }, () => []);
42
+ const colH = new Array(count).fill(0);
43
+ props.items.forEach((item, i) => {
44
+ const minIdx = colH.indexOf(Math.min(...colH));
45
+ const h = measuredHeights.get(i) ?? props.estimatedHeight;
46
+ cols[minIdx].push({ item, globalIdx: i, top: colH[minIdx], height: h });
47
+ colH[minIdx] += h + props.gap;
48
+ });
49
+ colPositions.value = cols;
50
+ colTotalHeights.value = colH;
51
+ emit("reflow");
52
+ };
53
+ const patchHeight = (globalIdx, newHeight) => {
54
+ const old = measuredHeights.get(globalIdx) ?? props.estimatedHeight;
55
+ if (Math.abs(old - newHeight) < 2) return;
56
+ measuredHeights.set(globalIdx, newHeight);
57
+ for (let ci = 0; ci < colPositions.value.length; ci++) {
58
+ const col = colPositions.value[ci];
59
+ const pos = col.findIndex((p) => p.globalIdx === globalIdx);
60
+ if (pos === -1) continue;
61
+ const delta = newHeight - col[pos].height;
62
+ col[pos].height = newHeight;
63
+ for (let j = pos + 1; j < col.length; j++) {
64
+ col[j] = { ...col[j], top: col[j].top + delta };
65
+ }
66
+ colTotalHeights.value[ci] += delta;
67
+ break;
68
+ }
69
+ };
70
+ const visibleItems = vue.computed(() => {
71
+ const top = scrollTop.value - props.overscan;
72
+ const bottom = scrollTop.value + viewportHeight.value + props.overscan;
73
+ return colPositions.value.map(
74
+ (col) => col.filter((p) => p.top + p.height >= top && p.top <= bottom)
75
+ );
76
+ });
77
+ let scrollEl = null;
78
+ const findScrollParent = (el) => {
79
+ let cur = el.parentElement;
80
+ while (cur) {
81
+ const { overflow, overflowY } = getComputedStyle(cur);
82
+ if (/auto|scroll/.test(overflow + overflowY)) return cur;
83
+ cur = cur.parentElement;
84
+ }
85
+ return document.documentElement;
86
+ };
87
+ const onScroll = (e) => {
88
+ const st = e.target.scrollTop;
89
+ const containerOffset = containerRef.value ? containerRef.value.offsetTop : 0;
90
+ scrollTop.value = Math.max(0, st - containerOffset);
91
+ };
92
+ const itemElMap = /* @__PURE__ */ new WeakMap();
93
+ const itemRo = new ResizeObserver((entries) => {
94
+ for (const entry of entries) {
95
+ const globalIdx = itemElMap.get(entry.target);
96
+ if (globalIdx === void 0) continue;
97
+ const h = entry.contentRect.height;
98
+ if (h > 0) patchHeight(globalIdx, h);
99
+ }
100
+ });
101
+ const observeItem = (el, globalIdx) => {
102
+ itemElMap.set(el, globalIdx);
103
+ itemRo.observe(el);
104
+ };
105
+ const unobserveItem = (el) => {
106
+ itemRo.unobserve(el);
107
+ itemElMap.delete(el);
108
+ };
109
+ let containerRo = null;
110
+ vue.onMounted(async () => {
111
+ await vue.nextTick();
112
+ if (!containerRef.value) return;
113
+ scrollEl = findScrollParent(containerRef.value);
114
+ scrollEl.addEventListener("scroll", onScroll, { passive: true });
115
+ viewportHeight.value = scrollEl === document.documentElement ? window.innerHeight : scrollEl.clientHeight;
116
+ containerRo = new ResizeObserver(() => {
117
+ viewportHeight.value = scrollEl === document.documentElement ? window.innerHeight : scrollEl.clientHeight;
118
+ reflow();
119
+ });
120
+ containerRo.observe(containerRef.value);
121
+ reflow();
122
+ });
123
+ vue.onUnmounted(() => {
124
+ scrollEl == null ? void 0 : scrollEl.removeEventListener("scroll", onScroll);
125
+ containerRo == null ? void 0 : containerRo.disconnect();
126
+ itemRo.disconnect();
127
+ });
128
+ vue.watch(() => props.items.length, (newLen, oldLen) => {
129
+ if (newLen < oldLen) measuredHeights.clear();
130
+ reflow();
131
+ });
132
+ return (_ctx, _cache) => {
133
+ return vue.openBlock(), vue.createElementBlock("div", {
134
+ ref_key: "containerRef",
135
+ ref: containerRef,
136
+ class: "wf-root",
137
+ style: vue.normalizeStyle({ gap: `${__props.gap}px` })
138
+ }, [
139
+ (vue.openBlock(true), vue.createElementBlock(vue.Fragment, null, vue.renderList(colPositions.value, (_col, ci) => {
140
+ return vue.openBlock(), vue.createElementBlock("div", {
141
+ key: ci,
142
+ class: "wf-col",
143
+ style: vue.normalizeStyle({ height: `${colTotalHeights.value[ci]}px` })
144
+ }, [
145
+ (vue.openBlock(true), vue.createElementBlock(vue.Fragment, null, vue.renderList(visibleItems.value[ci], ({ item, globalIdx, top }) => {
146
+ return vue.openBlock(), vue.createElementBlock("div", {
147
+ key: globalIdx,
148
+ ref_for: true,
149
+ ref: (el) => {
150
+ if (el) observeItem(el, globalIdx);
151
+ },
152
+ class: "wf-item",
153
+ style: vue.normalizeStyle({ transform: `translateY(${top}px)` }),
154
+ onVnodeUnmounted: _cache[0] || (_cache[0] = ({ el }) => unobserveItem(el))
155
+ }, [
156
+ vue.renderSlot(_ctx.$slots, "default", { item }, void 0, true)
157
+ ], 4);
158
+ }), 128))
159
+ ], 4);
160
+ }), 128))
161
+ ], 4);
162
+ };
163
+ }
164
+ });
165
+ const _export_sfc = (sfc, props) => {
166
+ const target = sfc.__vccOpts || sfc;
167
+ for (const [key, val] of props) {
168
+ target[key] = val;
169
+ }
170
+ return target;
171
+ };
172
+ const Waterfall = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-946f6fbc"]]);
173
+ function install(app) {
174
+ app.component("TdWaterfall", Waterfall);
175
+ }
176
+ const TudouWaterfall = {
177
+ install
178
+ };
179
+ exports.TudouWaterfall = TudouWaterfall;
180
+ exports.Waterfall = Waterfall;
181
+ exports.default = TudouWaterfall;
182
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.cjs","sources":["../src/components/Waterfall.vue","../src/index.ts"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ref, computed, onMounted, onUnmounted, nextTick, watch } from 'vue'\n\nexport interface WaterfallBreakpoint {\n minWidth: number\n cols: number\n}\n\nexport interface WaterfallProps {\n items: any[]\n cols?: number\n gap?: number\n estimatedHeight?: number\n overscan?: number\n /**\n * Responsive breakpoints. Sorted descending by minWidth at runtime.\n * Example: [{ minWidth: 1400, cols: 5 }, { minWidth: 900, cols: 3 }]\n * Falls back to defaultCols when no breakpoint matches.\n */\n breakpoints?: WaterfallBreakpoint[]\n /** Column count when no breakpoint matches (default: 2) */\n defaultCols?: number\n}\n\nconst props = withDefaults(defineProps<WaterfallProps>(), {\n cols: 0,\n gap: 15,\n estimatedHeight: 220,\n overscan: 600,\n breakpoints: () => [\n { minWidth: 1400, cols: 9 },\n { minWidth: 1200, cols: 8 },\n { minWidth: 900, cols: 7 },\n { minWidth: 700, cols: 6 },\n { minWidth: 500, cols: 5 },\n ],\n defaultCols: 2,\n})\n\nconst emit = defineEmits<{ (e: 'reflow'): void }>()\n\n// ─── types ────────────────────────────────────────────────────────────────────\n\ninterface PositionedItem {\n item: any\n globalIdx: number\n top: number\n height: number\n}\n\n// ─── state ────────────────────────────────────────────────────────────────────\n\nconst containerRef = ref<HTMLElement | null>(null)\nconst scrollTop = ref(0)\nconst viewportHeight = ref(0)\n\n// colPositions[colIdx] = sorted array of positioned items\nconst colPositions = ref<PositionedItem[][]>([])\n// colTotalHeight[colIdx] = total height of that column (for the spacer div)\nconst colTotalHeights = ref<number[]>([])\n\n// globalIdx -> measured height (updated after image load)\nconst measuredHeights = new Map<number, number>()\n\n// ─── column count ─────────────────────────────────────────────────────────────\n\nconst getColCount = () => {\n if (props.cols > 0) return props.cols\n const width = containerRef.value?.clientWidth ?? window.innerWidth\n const sorted = [...props.breakpoints].sort((a, b) => b.minWidth - a.minWidth)\n return sorted.find(bp => width >= bp.minWidth)?.cols ?? props.defaultCols\n}\n\n// ─── full reflow: re-assign items to columns ──────────────────────────────────\n// Only called when items list changes or viewport width changes.\n// Does NOT re-assign on height updates to avoid item jumping between columns.\n\nconst reflow = async () => {\n await nextTick()\n const count = getColCount()\n const cols: PositionedItem[][] = Array.from({ length: count }, () => [])\n const colH = new Array(count).fill(0)\n\n props.items.forEach((item, i) => {\n const minIdx = colH.indexOf(Math.min(...colH))\n const h = measuredHeights.get(i) ?? props.estimatedHeight\n cols[minIdx].push({ item, globalIdx: i, top: colH[minIdx], height: h })\n colH[minIdx] += h + props.gap\n })\n\n colPositions.value = cols\n colTotalHeights.value = colH\n emit('reflow')\n}\n\n// ─── patch: update one item's height in-place, shift subsequent items ─────────\n// Called after an image loads. Avoids full reflow to prevent column reassignment.\n\nconst patchHeight = (globalIdx: number, newHeight: number) => {\n const old = measuredHeights.get(globalIdx) ?? props.estimatedHeight\n if (Math.abs(old - newHeight) < 2) return\n measuredHeights.set(globalIdx, newHeight)\n\n for (let ci = 0; ci < colPositions.value.length; ci++) {\n const col = colPositions.value[ci]\n const pos = col.findIndex(p => p.globalIdx === globalIdx)\n if (pos === -1) continue\n\n const delta = newHeight - col[pos].height\n col[pos].height = newHeight\n\n for (let j = pos + 1; j < col.length; j++) {\n col[j] = { ...col[j], top: col[j].top + delta }\n }\n\n colTotalHeights.value[ci] += delta\n break\n }\n}\n\n// ─── virtual visibility ───────────────────────────────────────────────────────\n\nconst visibleItems = computed(() => {\n const top = scrollTop.value - props.overscan\n const bottom = scrollTop.value + viewportHeight.value + props.overscan\n return colPositions.value.map(col =>\n col.filter(p => p.top + p.height >= top && p.top <= bottom)\n )\n})\n\n// ─── scroll listener ──────────────────────────────────────────────────────────\n\nlet scrollEl: Element | null = null\n\nconst findScrollParent = (el: Element): Element => {\n let cur: Element | null = el.parentElement\n while (cur) {\n const { overflow, overflowY } = getComputedStyle(cur)\n if (/auto|scroll/.test(overflow + overflowY)) return cur\n cur = cur.parentElement\n }\n return document.documentElement\n}\n\nconst onScroll = (e: Event) => {\n const st = (e.target as Element).scrollTop\n const containerOffset = containerRef.value\n ? (containerRef.value as HTMLElement).offsetTop\n : 0\n scrollTop.value = Math.max(0, st - containerOffset)\n}\n\n// ─── item resize observer ─────────────────────────────────────────────────────\n// One shared RO watches every .wf-item element.\n// el -> globalIdx mapping is stored in a WeakMap so we never leak.\n\nconst itemElMap = new WeakMap<Element, number>()\n\nconst itemRo = new ResizeObserver((entries) => {\n for (const entry of entries) {\n const globalIdx = itemElMap.get(entry.target)\n if (globalIdx === undefined) continue\n const h = entry.contentRect.height\n if (h > 0) patchHeight(globalIdx, h)\n }\n})\n\nconst observeItem = (el: Element, globalIdx: number) => {\n itemElMap.set(el, globalIdx)\n itemRo.observe(el)\n}\n\nconst unobserveItem = (el: Element) => {\n itemRo.unobserve(el)\n itemElMap.delete(el)\n}\n\n// ─── resize observer (container) ─────────────────────────────────────────────\n\nlet containerRo: ResizeObserver | null = null\n\n// ─── lifecycle ────────────────────────────────────────────────────────────────\n\nonMounted(async () => {\n await nextTick()\n if (!containerRef.value) return\n\n scrollEl = findScrollParent(containerRef.value)\n scrollEl.addEventListener('scroll', onScroll, { passive: true })\n viewportHeight.value = scrollEl === document.documentElement\n ? window.innerHeight\n : (scrollEl as HTMLElement).clientHeight\n\n containerRo = new ResizeObserver(() => {\n viewportHeight.value = scrollEl === document.documentElement\n ? window.innerHeight\n : (scrollEl as HTMLElement).clientHeight\n reflow()\n })\n containerRo.observe(containerRef.value)\n\n reflow()\n})\n\nonUnmounted(() => {\n scrollEl?.removeEventListener('scroll', onScroll)\n containerRo?.disconnect()\n itemRo.disconnect()\n})\n\nwatch(() => props.items.length, (newLen, oldLen) => {\n if (newLen < oldLen) measuredHeights.clear()\n reflow()\n})\n</script>\n\n<template>\n <div ref=\"containerRef\" class=\"wf-root\" :style=\"{ gap: `${gap}px` }\">\n <div\n v-for=\"(_col, ci) in colPositions\"\n :key=\"ci\"\n class=\"wf-col\"\n :style=\"{ height: `${colTotalHeights[ci]}px` }\"\n >\n <div\n v-for=\"{ item, globalIdx, top } in visibleItems[ci]\"\n :key=\"globalIdx\"\n :ref=\"(el) => { if (el) observeItem(el as Element, globalIdx) }\"\n class=\"wf-item\"\n :style=\"{ transform: `translateY(${top}px)` }\"\n @vue:unmounted=\"({ el }: any) => unobserveItem(el)\"\n >\n <slot :item=\"item\" />\n </div>\n </div>\n </div>\n</template>\n\n<style scoped>\n.wf-root {\n display: flex;\n align-items: flex-start;\n width: 100%;\n}\n\n.wf-col {\n flex: 1;\n position: relative;\n min-width: 0;\n}\n\n.wf-item {\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n}\n</style>\n","import type { App, Plugin } from 'vue'\n\nimport Waterfall from './components/Waterfall.vue'\n\nexport { Waterfall }\nexport type { WaterfallProps, WaterfallBreakpoint } from './components/Waterfall.vue'\n\nfunction install(app: App): void {\n app.component('TdWaterfall', Waterfall)\n}\n\nconst TudouWaterfall: Plugin = {\n install,\n}\n\nexport default TudouWaterfall\nexport { TudouWaterfall }\n"],"names":["ref","nextTick","computed","onMounted","onUnmounted","watch","_createElementBlock","_openBlock","_Fragment","_renderList","_normalizeStyle","_renderSlot"],"mappings":"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"}
@@ -0,0 +1,102 @@
1
+ import { ComponentOptionsMixin } from 'vue';
2
+ import { ComponentProvideOptions } from 'vue';
3
+ import { DefineComponent } from 'vue';
4
+ import { ExtractPropTypes } from 'vue';
5
+ import { Plugin as Plugin_2 } from 'vue';
6
+ import { PropType } from 'vue';
7
+ import { PublicProps } from 'vue';
8
+
9
+ declare const __VLS_component: DefineComponent<ExtractPropTypes<__VLS_WithDefaults<__VLS_TypePropsToRuntimeProps<WaterfallProps>, {
10
+ cols: number;
11
+ gap: number;
12
+ estimatedHeight: number;
13
+ overscan: number;
14
+ breakpoints: () => {
15
+ minWidth: number;
16
+ cols: number;
17
+ }[];
18
+ defaultCols: number;
19
+ }>>, {}, {}, {}, {}, ComponentOptionsMixin, ComponentOptionsMixin, {
20
+ reflow: () => void;
21
+ }, string, PublicProps, Readonly<ExtractPropTypes<__VLS_WithDefaults<__VLS_TypePropsToRuntimeProps<WaterfallProps>, {
22
+ cols: number;
23
+ gap: number;
24
+ estimatedHeight: number;
25
+ overscan: number;
26
+ breakpoints: () => {
27
+ minWidth: number;
28
+ cols: number;
29
+ }[];
30
+ defaultCols: number;
31
+ }>>> & Readonly<{
32
+ onReflow?: (() => any) | undefined;
33
+ }>, {
34
+ cols: number;
35
+ gap: number;
36
+ estimatedHeight: number;
37
+ overscan: number;
38
+ breakpoints: WaterfallBreakpoint[];
39
+ defaultCols: number;
40
+ }, {}, {}, {}, string, ComponentProvideOptions, true, {}, any>;
41
+
42
+ declare type __VLS_NonUndefinedable<T> = T extends undefined ? never : T;
43
+
44
+ declare type __VLS_Prettify<T> = {
45
+ [K in keyof T]: T[K];
46
+ } & {};
47
+
48
+ declare function __VLS_template(): {
49
+ default?(_: {
50
+ item: any;
51
+ }): any;
52
+ };
53
+
54
+ declare type __VLS_TypePropsToRuntimeProps<T> = {
55
+ [K in keyof T]-?: {} extends Pick<T, K> ? {
56
+ type: PropType<__VLS_NonUndefinedable<T[K]>>;
57
+ } : {
58
+ type: PropType<T[K]>;
59
+ required: true;
60
+ };
61
+ };
62
+
63
+ declare type __VLS_WithDefaults<P, D> = {
64
+ [K in keyof Pick<P, keyof P>]: K extends keyof D ? __VLS_Prettify<P[K] & {
65
+ default: D[K];
66
+ }> : P[K];
67
+ };
68
+
69
+ declare type __VLS_WithTemplateSlots<T, S> = T & {
70
+ new (): {
71
+ $slots: S;
72
+ };
73
+ };
74
+
75
+ declare const TudouWaterfall: Plugin_2;
76
+ export { TudouWaterfall }
77
+ export default TudouWaterfall;
78
+
79
+ export declare const Waterfall: __VLS_WithTemplateSlots<typeof __VLS_component, ReturnType<typeof __VLS_template>>;
80
+
81
+ export declare interface WaterfallBreakpoint {
82
+ minWidth: number;
83
+ cols: number;
84
+ }
85
+
86
+ export declare interface WaterfallProps {
87
+ items: any[];
88
+ cols?: number;
89
+ gap?: number;
90
+ estimatedHeight?: number;
91
+ overscan?: number;
92
+ /**
93
+ * Responsive breakpoints. Sorted descending by minWidth at runtime.
94
+ * Example: [{ minWidth: 1400, cols: 5 }, { minWidth: 900, cols: 3 }]
95
+ * Falls back to defaultCols when no breakpoint matches.
96
+ */
97
+ breakpoints?: WaterfallBreakpoint[];
98
+ /** Column count when no breakpoint matches (default: 2) */
99
+ defaultCols?: number;
100
+ }
101
+
102
+ export { }
package/dist/index.mjs ADDED
@@ -0,0 +1,182 @@
1
+ import { defineComponent, ref, computed, onMounted, nextTick, onUnmounted, watch, openBlock, createElementBlock, normalizeStyle, Fragment, renderList, renderSlot } from "vue";
2
+ const _sfc_main = /* @__PURE__ */ defineComponent({
3
+ __name: "Waterfall",
4
+ props: {
5
+ items: {},
6
+ cols: { default: 0 },
7
+ gap: { default: 15 },
8
+ estimatedHeight: { default: 220 },
9
+ overscan: { default: 600 },
10
+ breakpoints: { default: () => [
11
+ { minWidth: 1400, cols: 9 },
12
+ { minWidth: 1200, cols: 8 },
13
+ { minWidth: 900, cols: 7 },
14
+ { minWidth: 700, cols: 6 },
15
+ { minWidth: 500, cols: 5 }
16
+ ] },
17
+ defaultCols: { default: 2 }
18
+ },
19
+ emits: ["reflow"],
20
+ setup(__props, { emit: __emit }) {
21
+ const props = __props;
22
+ const emit = __emit;
23
+ const containerRef = ref(null);
24
+ const scrollTop = ref(0);
25
+ const viewportHeight = ref(0);
26
+ const colPositions = ref([]);
27
+ const colTotalHeights = ref([]);
28
+ const measuredHeights = /* @__PURE__ */ new Map();
29
+ const getColCount = () => {
30
+ var _a, _b;
31
+ if (props.cols > 0) return props.cols;
32
+ const width = ((_a = containerRef.value) == null ? void 0 : _a.clientWidth) ?? window.innerWidth;
33
+ const sorted = [...props.breakpoints].sort((a, b) => b.minWidth - a.minWidth);
34
+ return ((_b = sorted.find((bp) => width >= bp.minWidth)) == null ? void 0 : _b.cols) ?? props.defaultCols;
35
+ };
36
+ const reflow = async () => {
37
+ await nextTick();
38
+ const count = getColCount();
39
+ const cols = Array.from({ length: count }, () => []);
40
+ const colH = new Array(count).fill(0);
41
+ props.items.forEach((item, i) => {
42
+ const minIdx = colH.indexOf(Math.min(...colH));
43
+ const h = measuredHeights.get(i) ?? props.estimatedHeight;
44
+ cols[minIdx].push({ item, globalIdx: i, top: colH[minIdx], height: h });
45
+ colH[minIdx] += h + props.gap;
46
+ });
47
+ colPositions.value = cols;
48
+ colTotalHeights.value = colH;
49
+ emit("reflow");
50
+ };
51
+ const patchHeight = (globalIdx, newHeight) => {
52
+ const old = measuredHeights.get(globalIdx) ?? props.estimatedHeight;
53
+ if (Math.abs(old - newHeight) < 2) return;
54
+ measuredHeights.set(globalIdx, newHeight);
55
+ for (let ci = 0; ci < colPositions.value.length; ci++) {
56
+ const col = colPositions.value[ci];
57
+ const pos = col.findIndex((p) => p.globalIdx === globalIdx);
58
+ if (pos === -1) continue;
59
+ const delta = newHeight - col[pos].height;
60
+ col[pos].height = newHeight;
61
+ for (let j = pos + 1; j < col.length; j++) {
62
+ col[j] = { ...col[j], top: col[j].top + delta };
63
+ }
64
+ colTotalHeights.value[ci] += delta;
65
+ break;
66
+ }
67
+ };
68
+ const visibleItems = computed(() => {
69
+ const top = scrollTop.value - props.overscan;
70
+ const bottom = scrollTop.value + viewportHeight.value + props.overscan;
71
+ return colPositions.value.map(
72
+ (col) => col.filter((p) => p.top + p.height >= top && p.top <= bottom)
73
+ );
74
+ });
75
+ let scrollEl = null;
76
+ const findScrollParent = (el) => {
77
+ let cur = el.parentElement;
78
+ while (cur) {
79
+ const { overflow, overflowY } = getComputedStyle(cur);
80
+ if (/auto|scroll/.test(overflow + overflowY)) return cur;
81
+ cur = cur.parentElement;
82
+ }
83
+ return document.documentElement;
84
+ };
85
+ const onScroll = (e) => {
86
+ const st = e.target.scrollTop;
87
+ const containerOffset = containerRef.value ? containerRef.value.offsetTop : 0;
88
+ scrollTop.value = Math.max(0, st - containerOffset);
89
+ };
90
+ const itemElMap = /* @__PURE__ */ new WeakMap();
91
+ const itemRo = new ResizeObserver((entries) => {
92
+ for (const entry of entries) {
93
+ const globalIdx = itemElMap.get(entry.target);
94
+ if (globalIdx === void 0) continue;
95
+ const h = entry.contentRect.height;
96
+ if (h > 0) patchHeight(globalIdx, h);
97
+ }
98
+ });
99
+ const observeItem = (el, globalIdx) => {
100
+ itemElMap.set(el, globalIdx);
101
+ itemRo.observe(el);
102
+ };
103
+ const unobserveItem = (el) => {
104
+ itemRo.unobserve(el);
105
+ itemElMap.delete(el);
106
+ };
107
+ let containerRo = null;
108
+ onMounted(async () => {
109
+ await nextTick();
110
+ if (!containerRef.value) return;
111
+ scrollEl = findScrollParent(containerRef.value);
112
+ scrollEl.addEventListener("scroll", onScroll, { passive: true });
113
+ viewportHeight.value = scrollEl === document.documentElement ? window.innerHeight : scrollEl.clientHeight;
114
+ containerRo = new ResizeObserver(() => {
115
+ viewportHeight.value = scrollEl === document.documentElement ? window.innerHeight : scrollEl.clientHeight;
116
+ reflow();
117
+ });
118
+ containerRo.observe(containerRef.value);
119
+ reflow();
120
+ });
121
+ onUnmounted(() => {
122
+ scrollEl == null ? void 0 : scrollEl.removeEventListener("scroll", onScroll);
123
+ containerRo == null ? void 0 : containerRo.disconnect();
124
+ itemRo.disconnect();
125
+ });
126
+ watch(() => props.items.length, (newLen, oldLen) => {
127
+ if (newLen < oldLen) measuredHeights.clear();
128
+ reflow();
129
+ });
130
+ return (_ctx, _cache) => {
131
+ return openBlock(), createElementBlock("div", {
132
+ ref_key: "containerRef",
133
+ ref: containerRef,
134
+ class: "wf-root",
135
+ style: normalizeStyle({ gap: `${__props.gap}px` })
136
+ }, [
137
+ (openBlock(true), createElementBlock(Fragment, null, renderList(colPositions.value, (_col, ci) => {
138
+ return openBlock(), createElementBlock("div", {
139
+ key: ci,
140
+ class: "wf-col",
141
+ style: normalizeStyle({ height: `${colTotalHeights.value[ci]}px` })
142
+ }, [
143
+ (openBlock(true), createElementBlock(Fragment, null, renderList(visibleItems.value[ci], ({ item, globalIdx, top }) => {
144
+ return openBlock(), createElementBlock("div", {
145
+ key: globalIdx,
146
+ ref_for: true,
147
+ ref: (el) => {
148
+ if (el) observeItem(el, globalIdx);
149
+ },
150
+ class: "wf-item",
151
+ style: normalizeStyle({ transform: `translateY(${top}px)` }),
152
+ onVnodeUnmounted: _cache[0] || (_cache[0] = ({ el }) => unobserveItem(el))
153
+ }, [
154
+ renderSlot(_ctx.$slots, "default", { item }, void 0, true)
155
+ ], 4);
156
+ }), 128))
157
+ ], 4);
158
+ }), 128))
159
+ ], 4);
160
+ };
161
+ }
162
+ });
163
+ const _export_sfc = (sfc, props) => {
164
+ const target = sfc.__vccOpts || sfc;
165
+ for (const [key, val] of props) {
166
+ target[key] = val;
167
+ }
168
+ return target;
169
+ };
170
+ const Waterfall = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-946f6fbc"]]);
171
+ function install(app) {
172
+ app.component("TdWaterfall", Waterfall);
173
+ }
174
+ const TudouWaterfall = {
175
+ install
176
+ };
177
+ export {
178
+ TudouWaterfall,
179
+ Waterfall,
180
+ TudouWaterfall as default
181
+ };
182
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","sources":["../src/components/Waterfall.vue","../src/index.ts"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ref, computed, onMounted, onUnmounted, nextTick, watch } from 'vue'\n\nexport interface WaterfallBreakpoint {\n minWidth: number\n cols: number\n}\n\nexport interface WaterfallProps {\n items: any[]\n cols?: number\n gap?: number\n estimatedHeight?: number\n overscan?: number\n /**\n * Responsive breakpoints. Sorted descending by minWidth at runtime.\n * Example: [{ minWidth: 1400, cols: 5 }, { minWidth: 900, cols: 3 }]\n * Falls back to defaultCols when no breakpoint matches.\n */\n breakpoints?: WaterfallBreakpoint[]\n /** Column count when no breakpoint matches (default: 2) */\n defaultCols?: number\n}\n\nconst props = withDefaults(defineProps<WaterfallProps>(), {\n cols: 0,\n gap: 15,\n estimatedHeight: 220,\n overscan: 600,\n breakpoints: () => [\n { minWidth: 1400, cols: 9 },\n { minWidth: 1200, cols: 8 },\n { minWidth: 900, cols: 7 },\n { minWidth: 700, cols: 6 },\n { minWidth: 500, cols: 5 },\n ],\n defaultCols: 2,\n})\n\nconst emit = defineEmits<{ (e: 'reflow'): void }>()\n\n// ─── types ────────────────────────────────────────────────────────────────────\n\ninterface PositionedItem {\n item: any\n globalIdx: number\n top: number\n height: number\n}\n\n// ─── state ────────────────────────────────────────────────────────────────────\n\nconst containerRef = ref<HTMLElement | null>(null)\nconst scrollTop = ref(0)\nconst viewportHeight = ref(0)\n\n// colPositions[colIdx] = sorted array of positioned items\nconst colPositions = ref<PositionedItem[][]>([])\n// colTotalHeight[colIdx] = total height of that column (for the spacer div)\nconst colTotalHeights = ref<number[]>([])\n\n// globalIdx -> measured height (updated after image load)\nconst measuredHeights = new Map<number, number>()\n\n// ─── column count ─────────────────────────────────────────────────────────────\n\nconst getColCount = () => {\n if (props.cols > 0) return props.cols\n const width = containerRef.value?.clientWidth ?? window.innerWidth\n const sorted = [...props.breakpoints].sort((a, b) => b.minWidth - a.minWidth)\n return sorted.find(bp => width >= bp.minWidth)?.cols ?? props.defaultCols\n}\n\n// ─── full reflow: re-assign items to columns ──────────────────────────────────\n// Only called when items list changes or viewport width changes.\n// Does NOT re-assign on height updates to avoid item jumping between columns.\n\nconst reflow = async () => {\n await nextTick()\n const count = getColCount()\n const cols: PositionedItem[][] = Array.from({ length: count }, () => [])\n const colH = new Array(count).fill(0)\n\n props.items.forEach((item, i) => {\n const minIdx = colH.indexOf(Math.min(...colH))\n const h = measuredHeights.get(i) ?? props.estimatedHeight\n cols[minIdx].push({ item, globalIdx: i, top: colH[minIdx], height: h })\n colH[minIdx] += h + props.gap\n })\n\n colPositions.value = cols\n colTotalHeights.value = colH\n emit('reflow')\n}\n\n// ─── patch: update one item's height in-place, shift subsequent items ─────────\n// Called after an image loads. Avoids full reflow to prevent column reassignment.\n\nconst patchHeight = (globalIdx: number, newHeight: number) => {\n const old = measuredHeights.get(globalIdx) ?? props.estimatedHeight\n if (Math.abs(old - newHeight) < 2) return\n measuredHeights.set(globalIdx, newHeight)\n\n for (let ci = 0; ci < colPositions.value.length; ci++) {\n const col = colPositions.value[ci]\n const pos = col.findIndex(p => p.globalIdx === globalIdx)\n if (pos === -1) continue\n\n const delta = newHeight - col[pos].height\n col[pos].height = newHeight\n\n for (let j = pos + 1; j < col.length; j++) {\n col[j] = { ...col[j], top: col[j].top + delta }\n }\n\n colTotalHeights.value[ci] += delta\n break\n }\n}\n\n// ─── virtual visibility ───────────────────────────────────────────────────────\n\nconst visibleItems = computed(() => {\n const top = scrollTop.value - props.overscan\n const bottom = scrollTop.value + viewportHeight.value + props.overscan\n return colPositions.value.map(col =>\n col.filter(p => p.top + p.height >= top && p.top <= bottom)\n )\n})\n\n// ─── scroll listener ──────────────────────────────────────────────────────────\n\nlet scrollEl: Element | null = null\n\nconst findScrollParent = (el: Element): Element => {\n let cur: Element | null = el.parentElement\n while (cur) {\n const { overflow, overflowY } = getComputedStyle(cur)\n if (/auto|scroll/.test(overflow + overflowY)) return cur\n cur = cur.parentElement\n }\n return document.documentElement\n}\n\nconst onScroll = (e: Event) => {\n const st = (e.target as Element).scrollTop\n const containerOffset = containerRef.value\n ? (containerRef.value as HTMLElement).offsetTop\n : 0\n scrollTop.value = Math.max(0, st - containerOffset)\n}\n\n// ─── item resize observer ─────────────────────────────────────────────────────\n// One shared RO watches every .wf-item element.\n// el -> globalIdx mapping is stored in a WeakMap so we never leak.\n\nconst itemElMap = new WeakMap<Element, number>()\n\nconst itemRo = new ResizeObserver((entries) => {\n for (const entry of entries) {\n const globalIdx = itemElMap.get(entry.target)\n if (globalIdx === undefined) continue\n const h = entry.contentRect.height\n if (h > 0) patchHeight(globalIdx, h)\n }\n})\n\nconst observeItem = (el: Element, globalIdx: number) => {\n itemElMap.set(el, globalIdx)\n itemRo.observe(el)\n}\n\nconst unobserveItem = (el: Element) => {\n itemRo.unobserve(el)\n itemElMap.delete(el)\n}\n\n// ─── resize observer (container) ─────────────────────────────────────────────\n\nlet containerRo: ResizeObserver | null = null\n\n// ─── lifecycle ────────────────────────────────────────────────────────────────\n\nonMounted(async () => {\n await nextTick()\n if (!containerRef.value) return\n\n scrollEl = findScrollParent(containerRef.value)\n scrollEl.addEventListener('scroll', onScroll, { passive: true })\n viewportHeight.value = scrollEl === document.documentElement\n ? window.innerHeight\n : (scrollEl as HTMLElement).clientHeight\n\n containerRo = new ResizeObserver(() => {\n viewportHeight.value = scrollEl === document.documentElement\n ? window.innerHeight\n : (scrollEl as HTMLElement).clientHeight\n reflow()\n })\n containerRo.observe(containerRef.value)\n\n reflow()\n})\n\nonUnmounted(() => {\n scrollEl?.removeEventListener('scroll', onScroll)\n containerRo?.disconnect()\n itemRo.disconnect()\n})\n\nwatch(() => props.items.length, (newLen, oldLen) => {\n if (newLen < oldLen) measuredHeights.clear()\n reflow()\n})\n</script>\n\n<template>\n <div ref=\"containerRef\" class=\"wf-root\" :style=\"{ gap: `${gap}px` }\">\n <div\n v-for=\"(_col, ci) in colPositions\"\n :key=\"ci\"\n class=\"wf-col\"\n :style=\"{ height: `${colTotalHeights[ci]}px` }\"\n >\n <div\n v-for=\"{ item, globalIdx, top } in visibleItems[ci]\"\n :key=\"globalIdx\"\n :ref=\"(el) => { if (el) observeItem(el as Element, globalIdx) }\"\n class=\"wf-item\"\n :style=\"{ transform: `translateY(${top}px)` }\"\n @vue:unmounted=\"({ el }: any) => unobserveItem(el)\"\n >\n <slot :item=\"item\" />\n </div>\n </div>\n </div>\n</template>\n\n<style scoped>\n.wf-root {\n display: flex;\n align-items: flex-start;\n width: 100%;\n}\n\n.wf-col {\n flex: 1;\n position: relative;\n min-width: 0;\n}\n\n.wf-item {\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n}\n</style>\n","import type { App, Plugin } from 'vue'\n\nimport Waterfall from './components/Waterfall.vue'\n\nexport { Waterfall }\nexport type { WaterfallProps, WaterfallBreakpoint } from './components/Waterfall.vue'\n\nfunction install(app: App): void {\n app.component('TdWaterfall', Waterfall)\n}\n\nconst TudouWaterfall: Plugin = {\n install,\n}\n\nexport default TudouWaterfall\nexport { TudouWaterfall }\n"],"names":["_createElementBlock","_openBlock","_Fragment","_renderList","_normalizeStyle","_renderSlot"],"mappings":"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"}
package/dist/style.css ADDED
@@ -0,0 +1,17 @@
1
+
2
+ .wf-root[data-v-946f6fbc] {
3
+ display: flex;
4
+ align-items: flex-start;
5
+ width: 100%;
6
+ }
7
+ .wf-col[data-v-946f6fbc] {
8
+ flex: 1;
9
+ position: relative;
10
+ min-width: 0;
11
+ }
12
+ .wf-item[data-v-946f6fbc] {
13
+ position: absolute;
14
+ top: 0;
15
+ left: 0;
16
+ width: 100%;
17
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tudou-waterfall",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "A Vue 3 plugin with UI components, directives, and global methods",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -20,7 +20,8 @@
20
20
  "dev": "vite",
21
21
  "build": "vue-tsc --noEmit && vite build",
22
22
  "preview": "vite preview",
23
- "typecheck": "vue-tsc --noEmit"
23
+ "typecheck": "vue-tsc --noEmit",
24
+ "prepublishOnly": "npm run build"
24
25
  },
25
26
  "peerDependencies": {
26
27
  "vue": "^3.0.0"