[READ-ONLY] Mirror of https://github.com/probablykasper/k5kit. Utilities for TypeScript and Svelte
0

Configure Feed

Select the types of activity you want to include in your feed.

vgrid: Make this.columns stateful

Kasper (Jun 27, 2025, 11:14 PM +0200) 95f2b18a 0bf1b5e9

+21 -14
+20 -13
src/lib/virtual-grid.ts src/lib/virtual-grid.svelte.ts
··· 1 + import { untrack } from 'svelte' 2 + 1 3 export type Column = { 2 4 name: string 3 5 key: string ··· 170 172 }) 171 173 } 172 174 173 - columns: Column[] = [] 175 + /** Updating columns must be done via `set_columns` */ 176 + columns: Column[] = $state([]) 177 + #inner_columns: Column[] = [] 174 178 set_columns(columns: Column[]) { 175 179 const total_fixed_width = columns.reduce((sum, col) => sum + (col.is_pct ? 0 : col.width), 0) 176 180 const total_percent_pct = columns.reduce((sum, col) => sum + (col.is_pct ? col.width : 0), 0) ··· 189 193 }) 190 194 191 195 let resize_only = true 192 - if (this.columns.length !== new_columns.length) { 196 + if (this.#inner_columns.length !== new_columns.length) { 193 197 resize_only = false 194 198 } 195 - for (let i = 0; i < this.columns.length; i++) { 196 - if (new_columns[i].key !== this.columns[i].key) { 199 + for (let i = 0; i < this.#inner_columns.length; i++) { 200 + if (new_columns[i].key !== this.#inner_columns[i].key) { 197 201 resize_only = false 198 202 break 199 203 } 200 204 } 201 205 206 + this.#inner_columns = new_columns 202 207 this.columns = new_columns 203 208 if (resize_only) { 204 209 for (const row of this.rows) { 205 210 if (!row.element) { 206 211 throw new Error('Unexpected missing row element') 207 212 } 208 - for (let ci = 0; ci < this.columns.length; ci++) { 209 - const column = this.columns[ci] 213 + for (let ci = 0; ci < this.#inner_columns.length; ci++) { 214 + const column = this.#inner_columns[ci] 210 215 const cell = row.element.children[ci] as HTMLElement 211 216 cell.style.width = `${column.width}px` 212 217 cell.style.translate = `${column.offset}px 0` ··· 221 226 222 227 this.refresh(RefreshLevel.NewRows) 223 228 } 224 - return this.columns 229 + return this.#inner_columns 225 230 } 226 231 227 232 #render() { ··· 246 251 row.element = row_element 247 252 this.main_element?.appendChild(row_element) 248 253 249 - for (const column of this.columns) { 254 + for (const column of this.#inner_columns) { 250 255 const cell = document.createElement('div') 251 256 cell.className = `cell ${column.key}` 252 257 cell.style.width = `${column.width}px` ··· 266 271 row.element.style.translate = `0 ${row.index * this.row_height}px` 267 272 row.element.setAttribute('aria-rowindex', String(row.index + 1)) 268 273 const row_item = items[row.index] 269 - for (let ci = 0; ci < this.columns.length; ci++) { 270 - const column = this.columns[ci] 274 + for (let ci = 0; ci < this.#inner_columns.length; ci++) { 275 + const column = this.#inner_columns[ci] 271 276 const cell = row.element.children[ci] as HTMLElement 272 277 let cell_value = row_item[column.key] 273 278 if (cell_value === undefined || cell_value === null) { ··· 320 325 this.#update_viewport_size() 321 326 322 327 this.size_observer = new ResizeObserver(() => { 323 - this.set_columns(this.columns) 328 + this.set_columns(this.#inner_columns) 324 329 this.#update_viewport_size() 325 330 this.refresh(RefreshLevel.NewRows) 326 331 }) ··· 345 350 } 346 351 } 347 352 attach() { 348 - // This is a function in order to make `this` work 349 - return (node: HTMLElement) => this.setup(node) 353 + return untrack(() => { 354 + // This is a function in order to make `this` work 355 + return (node: HTMLElement) => this.setup(node) 356 + }) 350 357 } 351 358 }
+1 -1
src/routes/+page.svelte
··· 1 1 <script lang="ts"> 2 2 import { KSelection } from '$lib/selection-svelte.ts' 3 - import { RefreshLevel, VirtualGrid } from '$lib/virtual-grid.ts' 3 + import { RefreshLevel, VirtualGrid } from '$lib/virtual-grid.svelte.ts' 4 4 5 5 function generate_source_items(count: number) { 6 6 return Array.from({ length: count }, () => String(Math.random()).slice(2))