Keep track of ICE and police locations in your city. Very much a work-in-progress and not ready yet, stay tuned I guess?
at main 142 lines 3.6 kB view raw
1import { 2 type RowData, 3 type TableOptions, 4 type TableOptionsResolved, 5 type TableState, 6 createTable, 7} from "@tanstack/table-core"; 8 9/** 10 * Creates a reactive TanStack table object for Svelte. 11 * @param options Table options to create the table with. 12 * @returns A reactive table object. 13 * @example 14 * ```svelte 15 * <script> 16 * const table = createSvelteTable({ ... }) 17 * </script> 18 * 19 * <table> 20 * <thead> 21 * {#each table.getHeaderGroups() as headerGroup} 22 * <tr> 23 * {#each headerGroup.headers as header} 24 * <th colspan={header.colSpan}> 25 * <FlexRender content={header.column.columnDef.header} context={header.getContext()} /> 26 * </th> 27 * {/each} 28 * </tr> 29 * {/each} 30 * </thead> 31 * <!-- ... --> 32 * </table> 33 * ``` 34 */ 35export function createSvelteTable<TData extends RowData>(options: TableOptions<TData>) { 36 const resolvedOptions: TableOptionsResolved<TData> = mergeObjects( 37 { 38 state: {}, 39 onStateChange() {}, 40 renderFallbackValue: null, 41 mergeOptions: ( 42 defaultOptions: TableOptions<TData>, 43 options: Partial<TableOptions<TData>> 44 ) => { 45 return mergeObjects(defaultOptions, options); 46 }, 47 }, 48 options 49 ); 50 51 const table = createTable(resolvedOptions); 52 let state = $state<Partial<TableState>>(table.initialState); 53 54 function updateOptions() { 55 table.setOptions((prev) => { 56 return mergeObjects(prev, options, { 57 state: mergeObjects(state, options.state || {}), 58 59 // eslint-disable-next-line @typescript-eslint/no-explicit-any 60 onStateChange: (updater: any) => { 61 if (updater instanceof Function) state = updater(state); 62 else state = mergeObjects(state, updater); 63 64 options.onStateChange?.(updater); 65 }, 66 }); 67 }); 68 } 69 70 updateOptions(); 71 72 $effect.pre(() => { 73 updateOptions(); 74 }); 75 76 return table; 77} 78 79type MaybeThunk<T extends object> = T | (() => T | null | undefined); 80type Intersection<T extends readonly unknown[]> = (T extends [infer H, ...infer R] 81 ? H & Intersection<R> 82 : unknown) & {}; 83 84/** 85 * Lazily merges several objects (or thunks) while preserving 86 * getter semantics from every source. 87 * 88 * Proxy-based to avoid known WebKit recursion issue. 89 */ 90// eslint-disable-next-line @typescript-eslint/no-explicit-any 91export function mergeObjects<Sources extends readonly MaybeThunk<any>[]>( 92 ...sources: Sources 93): Intersection<{ [K in keyof Sources]: Sources[K] }> { 94 const resolve = <T extends object>(src: MaybeThunk<T>): T | undefined => 95 typeof src === "function" ? (src() ?? undefined) : src; 96 97 const findSourceWithKey = (key: PropertyKey) => { 98 for (let i = sources.length - 1; i >= 0; i--) { 99 const obj = resolve(sources[i]); 100 if (obj && key in obj) return obj; 101 } 102 return undefined; 103 }; 104 105 return new Proxy(Object.create(null), { 106 get(_, key) { 107 const src = findSourceWithKey(key); 108 109 return src?.[key as never]; 110 }, 111 112 has(_, key) { 113 return !!findSourceWithKey(key); 114 }, 115 116 ownKeys(): (string | symbol)[] { 117 // eslint-disable-next-line svelte/prefer-svelte-reactivity 118 const all = new Set<string | symbol>(); 119 for (const s of sources) { 120 const obj = resolve(s); 121 if (obj) { 122 for (const k of Reflect.ownKeys(obj) as (string | symbol)[]) { 123 all.add(k); 124 } 125 } 126 } 127 return [...all]; 128 }, 129 130 getOwnPropertyDescriptor(_, key) { 131 const src = findSourceWithKey(key); 132 if (!src) return undefined; 133 return { 134 configurable: true, 135 enumerable: true, 136 // eslint-disable-next-line @typescript-eslint/no-explicit-any 137 value: (src as any)[key], 138 writable: true, 139 }; 140 }, 141 }) as Intersection<{ [K in keyof Sources]: Sources[K] }>; 142}