From 751253f6cd1b02e0e45fbe60dd80a27b46295210 Mon Sep 17 00:00:00 2001 From: Comfy Org PR Bot Date: Thu, 22 Jan 2026 10:42:22 +0900 Subject: [PATCH] [backport cloud/1.37] feat: add maxColumns prop to VirtualGrid for responsive column capping (#8232) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Backport of #8210 to `cloud/1.37` Automatically created by backport workflow. ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-8232-backport-cloud-1-37-feat-add-maxColumns-prop-to-VirtualGrid-for-responsive-column-capp-2f06d73d36508149bdc2fdec700debac) by [Unito](https://www.unito.io) Co-authored-by: Alexander Brown --- src/components/common/VirtualGrid.vue | 63 +++++++++++++------- src/platform/assets/components/AssetGrid.vue | 19 +++++- 2 files changed, 58 insertions(+), 24 deletions(-) diff --git a/src/components/common/VirtualGrid.vue b/src/components/common/VirtualGrid.vue index 134778778a..fb6b4374c0 100644 --- a/src/components/common/VirtualGrid.vue +++ b/src/components/common/VirtualGrid.vue @@ -1,16 +1,20 @@ @@ -28,19 +32,22 @@ type GridState = { const { items, + gridStyle, bufferRows = 1, scrollThrottle = 64, resizeDebounce = 64, defaultItemHeight = 200, - defaultItemWidth = 200 + defaultItemWidth = 200, + maxColumns = Infinity } = defineProps<{ items: (T & { key: string })[] - gridStyle: Partial + gridStyle: CSSProperties bufferRows?: number scrollThrottle?: number resizeDebounce?: number defaultItemHeight?: number defaultItemWidth?: number + maxColumns?: number }>() const emit = defineEmits<{ @@ -59,7 +66,18 @@ const { y: scrollY } = useScroll(container, { eventListenerOptions: { passive: true } }) -const cols = computed(() => Math.floor(width.value / itemWidth.value) || 1) +const cols = computed(() => + Math.min(Math.floor(width.value / itemWidth.value) || 1, maxColumns) +) + +const mergedGridStyle = computed(() => { + if (maxColumns === Infinity) return gridStyle + return { + ...gridStyle, + gridTemplateColumns: `repeat(${maxColumns}, minmax(0, 1fr))` + } +}) + const viewRows = computed(() => Math.ceil(height.value / itemHeight.value)) const offsetRows = computed(() => Math.floor(scrollY.value / itemHeight.value)) const isValidGrid = computed(() => height.value && width.value && items?.length) @@ -83,6 +101,16 @@ const renderedItems = computed(() => isValidGrid.value ? items.slice(state.value.start, state.value.end) : [] ) +function rowsToHeight(rows: number): string { + return `${(rows / cols.value) * itemHeight.value}px` +} +const topSpacerStyle = computed(() => ({ + height: rowsToHeight(state.value.start) +})) +const bottomSpacerStyle = computed(() => ({ + height: rowsToHeight(items.length - state.value.end) +})) + whenever( () => state.value.isNearEnd, () => { @@ -109,15 +137,6 @@ const onResize = debounce(updateItemSize, resizeDebounce) watch([width, height], onResize, { flush: 'post' }) whenever(() => items, updateItemSize, { flush: 'post' }) onBeforeUnmount(() => { - onResize.cancel() // Clear pending debounced calls + onResize.cancel() }) - - diff --git a/src/platform/assets/components/AssetGrid.vue b/src/platform/assets/components/AssetGrid.vue index da3c609b01..6e91a67fad 100644 --- a/src/platform/assets/components/AssetGrid.vue +++ b/src/platform/assets/components/AssetGrid.vue @@ -26,9 +26,10 @@