tudou-waterfall 0.1.19 → 0.1.21

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 CHANGED
@@ -84,8 +84,8 @@ const _sfc_main = /* @__PURE__ */ vue.defineComponent({
84
84
  }
85
85
  return document.documentElement;
86
86
  };
87
- const onScroll = (e) => {
88
- const st = e.target.scrollTop;
87
+ const onScroll = () => {
88
+ const st = scrollEl === document.documentElement ? window.scrollY : scrollEl.scrollTop;
89
89
  const containerOffset = containerRef.value ? containerRef.value.offsetTop : 0;
90
90
  scrollTop.value = Math.max(0, st - containerOffset);
91
91
  };
@@ -111,7 +111,8 @@ const _sfc_main = /* @__PURE__ */ vue.defineComponent({
111
111
  await vue.nextTick();
112
112
  if (!containerRef.value) return;
113
113
  scrollEl = findScrollParent(containerRef.value);
114
- scrollEl.addEventListener("scroll", onScroll, { passive: true });
114
+ const scrollTarget = scrollEl === document.documentElement ? window : scrollEl;
115
+ scrollTarget.addEventListener("scroll", onScroll, { passive: true });
115
116
  viewportHeight.value = scrollEl === document.documentElement ? window.innerHeight : scrollEl.clientHeight;
116
117
  containerRo = new ResizeObserver(() => {
117
118
  viewportHeight.value = scrollEl === document.documentElement ? window.innerHeight : scrollEl.clientHeight;
@@ -121,16 +122,15 @@ const _sfc_main = /* @__PURE__ */ vue.defineComponent({
121
122
  reflow();
122
123
  });
123
124
  vue.onUnmounted(() => {
124
- scrollEl == null ? void 0 : scrollEl.removeEventListener("scroll", onScroll);
125
+ const scrollTarget = scrollEl === document.documentElement ? window : scrollEl;
126
+ scrollTarget == null ? void 0 : scrollTarget.removeEventListener("scroll", onScroll);
125
127
  containerRo == null ? void 0 : containerRo.disconnect();
126
128
  itemRo.disconnect();
127
129
  });
128
- vue.watch(() => props.items, (newItems, oldItems) => {
129
- const newLen = (newItems == null ? void 0 : newItems.length) ?? 0;
130
- const oldLen = (oldItems == null ? void 0 : oldItems.length) ?? 0;
130
+ vue.watch(() => props.items.length, (newLen, oldLen) => {
131
131
  if (newLen < oldLen) measuredHeights.clear();
132
132
  reflow();
133
- }, { deep: true });
133
+ });
134
134
  return (_ctx, _cache) => {
135
135
  return vue.openBlock(), vue.createElementBlock("div", {
136
136
  ref_key: "containerRef",
@@ -171,7 +171,7 @@ const _export_sfc = (sfc, props) => {
171
171
  }
172
172
  return target;
173
173
  };
174
- const Waterfall = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-2751506d"]]);
174
+ const Waterfall = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-6ba996fa"]]);
175
175
  function install(app) {
176
176
  app.component("TdWaterfall", Waterfall);
177
177
  }
@@ -1 +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, (newItems, oldItems) => {\n const newLen = newItems?.length ?? 0\n const oldLen = oldItems?.length ?? 0\n if (newLen < oldLen) measuredHeights.clear()\n reflow()\n}, { deep: true })\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'\nimport './assets/index.css'\n\nexport { Waterfall }\nexport type { WaterfallProps } 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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"}
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 = () => {\n const st = scrollEl === document.documentElement\n ? window.scrollY\n : scrollEl!.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 const scrollTarget = scrollEl === document.documentElement ? window : scrollEl\n scrollTarget.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 const scrollTarget = scrollEl === document.documentElement ? window : scrollEl\n scrollTarget?.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'\nimport './assets/index.css'\n\nexport { Waterfall }\nexport type { WaterfallProps } 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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"}
package/dist/index.mjs CHANGED
@@ -82,8 +82,8 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
82
82
  }
83
83
  return document.documentElement;
84
84
  };
85
- const onScroll = (e) => {
86
- const st = e.target.scrollTop;
85
+ const onScroll = () => {
86
+ const st = scrollEl === document.documentElement ? window.scrollY : scrollEl.scrollTop;
87
87
  const containerOffset = containerRef.value ? containerRef.value.offsetTop : 0;
88
88
  scrollTop.value = Math.max(0, st - containerOffset);
89
89
  };
@@ -109,7 +109,8 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
109
109
  await nextTick();
110
110
  if (!containerRef.value) return;
111
111
  scrollEl = findScrollParent(containerRef.value);
112
- scrollEl.addEventListener("scroll", onScroll, { passive: true });
112
+ const scrollTarget = scrollEl === document.documentElement ? window : scrollEl;
113
+ scrollTarget.addEventListener("scroll", onScroll, { passive: true });
113
114
  viewportHeight.value = scrollEl === document.documentElement ? window.innerHeight : scrollEl.clientHeight;
114
115
  containerRo = new ResizeObserver(() => {
115
116
  viewportHeight.value = scrollEl === document.documentElement ? window.innerHeight : scrollEl.clientHeight;
@@ -119,16 +120,15 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
119
120
  reflow();
120
121
  });
121
122
  onUnmounted(() => {
122
- scrollEl == null ? void 0 : scrollEl.removeEventListener("scroll", onScroll);
123
+ const scrollTarget = scrollEl === document.documentElement ? window : scrollEl;
124
+ scrollTarget == null ? void 0 : scrollTarget.removeEventListener("scroll", onScroll);
123
125
  containerRo == null ? void 0 : containerRo.disconnect();
124
126
  itemRo.disconnect();
125
127
  });
126
- watch(() => props.items, (newItems, oldItems) => {
127
- const newLen = (newItems == null ? void 0 : newItems.length) ?? 0;
128
- const oldLen = (oldItems == null ? void 0 : oldItems.length) ?? 0;
128
+ watch(() => props.items.length, (newLen, oldLen) => {
129
129
  if (newLen < oldLen) measuredHeights.clear();
130
130
  reflow();
131
- }, { deep: true });
131
+ });
132
132
  return (_ctx, _cache) => {
133
133
  return openBlock(), createElementBlock("div", {
134
134
  ref_key: "containerRef",
@@ -169,7 +169,7 @@ const _export_sfc = (sfc, props) => {
169
169
  }
170
170
  return target;
171
171
  };
172
- const Waterfall = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-2751506d"]]);
172
+ const Waterfall = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-6ba996fa"]]);
173
173
  function install(app) {
174
174
  app.component("TdWaterfall", Waterfall);
175
175
  }
@@ -1 +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, (newItems, oldItems) => {\n const newLen = newItems?.length ?? 0\n const oldLen = oldItems?.length ?? 0\n if (newLen < oldLen) measuredHeights.clear()\n reflow()\n}, { deep: true })\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'\nimport './assets/index.css'\n\nexport { Waterfall }\nexport type { WaterfallProps } 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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"}
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 = () => {\n const st = scrollEl === document.documentElement\n ? window.scrollY\n : scrollEl!.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 const scrollTarget = scrollEl === document.documentElement ? window : scrollEl\n scrollTarget.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 const scrollTarget = scrollEl === document.documentElement ? window : scrollEl\n scrollTarget?.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'\nimport './assets/index.css'\n\nexport { Waterfall }\nexport type { WaterfallProps } 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 CHANGED
@@ -1,15 +1,15 @@
1
1
 
2
- .wf-root[data-v-2751506d] {
2
+ .wf-root[data-v-6ba996fa] {
3
3
  display: flex;
4
4
  align-items: flex-start;
5
5
  width: 100%;
6
6
  }
7
- .wf-col[data-v-2751506d] {
7
+ .wf-col[data-v-6ba996fa] {
8
8
  flex: 1;
9
9
  position: relative;
10
10
  min-width: 0;
11
11
  }
12
- .wf-item[data-v-2751506d] {
12
+ .wf-item[data-v-6ba996fa] {
13
13
  position: absolute;
14
14
  top: 0;
15
15
  left: 0;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tudou-waterfall",
3
- "version": "0.1.19",
3
+ "version": "0.1.21",
4
4
  "description": "A Vue 3 plugin with UI components, directives, and global methods",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",