| name | gridlite-views-recipes |
| description | Common integration patterns: svelte-gridlite-kit integration, multiple grids, default view auto-load, group management, migration from svelte-table-views-tanstack, low-level SQL access. |
| user-invocable | true |
Gridlite Views Recipes
Integration with svelte-gridlite-kit
Both libraries share a single PGLite instance. Map GridLite's onStateChange to a ViewConfig for saving:
<script lang="ts">
import { GridLite } from '@shotleybuilder/svelte-gridlite-kit';
import { initViewStore, ViewSelector, SaveViewModal } from '@shotleybuilder/svelte-gridlite-views';
import type { ViewConfig, SavedView } from '@shotleybuilder/svelte-gridlite-views';
let viewStore = initViewStore(db, 'employees-grid');
let showSaveModal = false;
let capturedConfig: ViewConfig | null = null;
// Map GridLite state to ViewConfig
function captureConfig(gridState: any): ViewConfig {
return {
filters: gridState.filters ?? [],
filterLogic: gridState.filterLogic ?? 'and',
sorting: gridState.sorting ?? [],
grouping: gridState.grouping ?? [],
columnVisibility: gridState.columnVisibility ?? {},
columnOrder: gridState.columnOrder ?? [],
columnWidths: gridState.columnSizing ?? {},
pageSize: gridState.pagination?.pageSize
};
}
function handleViewSelected(e: CustomEvent<{ view: SavedView }>) {
const cfg = e.detail.view.config;
grid.setFilters(cfg.filters, cfg.filterLogic);
grid.setSorting(cfg.sorting);
grid.setGrouping(cfg.grouping);
}
let grid: GridLite;
</script>
<ViewSelector {viewStore} on:viewSelected={handleViewSelected} />
<GridLite
bind:this={grid}
{db}
table="employees"
onStateChange={(state) => viewStore.actions.markModified()}
features={{ filtering: true, sorting: true, grouping: true }}
/>
Multiple Grids with Independent View Stores
Each grid gets its own store scoped by gridId:
const employeeViews = initViewStore(db, 'employees');
const productViews = initViewStore(db, 'products');
Clean up both on destroy:
onDestroy(() => {
employeeViews.destroy();
productViews.destroy();
});
Default View Auto-Load on Mount
onMount(async () => {
const db = new PGlite({ extensions: { live } });
viewStore = initViewStore(db as any, 'my-grid');
await viewStore.actions.waitForReady();
const defaultView = await viewStore.actions.loadDefaultView();
if (defaultView) {
applyConfigToTable(defaultView.config);
console.log('Loaded default view:', defaultView.name);
}
});
Persistent Database (IndexedDB)
Views survive page refreshes when using a persistent PGLite instance:
const db = new PGlite({ extensions: { live } });
const db = new PGlite('idb://my-app', { extensions: { live } });
Migration from svelte-table-views-tanstack
Read existing views from localStorage and insert into PGLite:
import { initViewStore } from '@shotleybuilder/svelte-gridlite-views';
async function migrateViews(db: PGliteWithLive, gridId: string) {
const store = initViewStore(db, gridId);
await store.actions.waitForReady();
const raw = localStorage.getItem('svelte-table-views-saved-views');
if (!raw) return;
const oldViews = JSON.parse(raw);
for (const old of oldViews) {
await store.actions.save({
name: old.name,
description: old.description,
config: {
filters: old.config.filters ?? [],
filterLogic: 'and',
sorting: old.config.sort ? [{ column: old.config.sort.columnId, direction: old.config.sort.direction }] : [],
grouping: old.config.grouping?.map((g: string) => ({ column: g })) ?? [],
columnVisibility: Object.fromEntries(old.config.columns.map((c: string) => [c, true])),
columnOrder: old.config.columnOrder ?? [],
columnWidths: old.config.columnWidths ?? {},
pageSize: old.config.pageSize
}
});
}
localStorage.removeItem('svelte-table-views-saved-views');
}
Key API changes
| svelte-table-views-tanstack | svelte-gridlite-views |
|---|
import { viewActions } from '...' | viewStore.actions (from prop) |
import { savedViews } from '...' | viewStore.savedViews (from prop) |
viewActions.save(input) | viewStore.actions.save(input) |
| Global stores | Grid-scoped ViewStoreBundle |
TableConfig type | ViewConfig type |
config.sort: SortConfig | null | config.sorting: SortConfig[] |
config.columns: string[] | config.columnVisibility: Record<string, boolean> |
savedViewsReady store | viewStore.ready store |
Group Management
Create and manage view groups programmatically:
const viewStore = initViewStore(db, 'my-grid');
await viewStore.actions.waitForReady();
const safety = await viewStore.groupActions.createGroup({ name: 'Safety Cases', icon: '🛡️' });
const notices = await viewStore.groupActions.createGroup({ name: 'Notices', icon: '📋' });
const archived = await viewStore.groupActions.createGroup({ name: 'Archived', icon: '📦' });
await viewStore.groupActions.moveViewToGroup(viewId, safety.id);
await viewStore.groupActions.moveViewToGroup(viewId, null);
await viewStore.groupActions.renameGroup(archived.id, 'Old Views');
await viewStore.groupActions.deleteGroup(archived.id);
await viewStore.groupActions.reorderGroups([notices.id, safety.id]);
Seed Groups on First Load
onMount(async () => {
viewStore = initViewStore(db, 'my-grid');
await viewStore.actions.waitForReady();
const groups = get(viewStore.savedGroups);
if (groups.length === 0) {
await viewStore.groupActions.createGroup({ name: 'Active', icon: '🟢' });
await viewStore.groupActions.createGroup({ name: 'Archived', icon: '📦' });
}
});
Listen for Group Events on Sidebar
<ViewSidebar
{viewStore}
on:viewSelected={(e) => applyConfig(e.detail.view.config)}
on:groupCreated={(e) => console.log('Created group:', e.detail.group.name)}
on:groupDeleted={(e) => console.log('Deleted group:', e.detail.id)}
on:viewMoved={(e) => console.log('Moved view', e.detail.viewId, 'to group', e.detail.groupId)}
/>
Low-Level SQL Access
For advanced use cases, use the database functions directly:
import { saveView, loadViews, deleteView } from '@shotleybuilder/svelte-gridlite-views';
const views = await loadViews(db, 'my-grid');
await deleteView(db, viewId);
Note: Direct SQL calls won't trigger the live query callbacks. Use viewStore.actions for reactive updates.
Cleanup Pattern
<script>
import { onMount, onDestroy } from 'svelte';
let viewStore: ViewStoreBundle | null = null;
onMount(async () => {
viewStore = initViewStore(db, 'my-grid');
await viewStore.actions.waitForReady();
});
onDestroy(() => {
viewStore?.destroy(); // Unsubscribes live queries
});
</script>