A lightweight, type-safe multi-dimensional filter store for Svelte 5 applications. This package provides a reactive way to handle complex filtering scenarios with multiple interdependent criteria.
Using Bun (recommended):
bunx jsr add @zshzebra/svelte-multi-filter
Using npm:
npx jsr add @zshzebra/svelte-multi-filter
Using pnpm:
pnpm dlx jsr add @zshzebra/svelte-multi-filter
import { createFilterStore, type FilterConfig } from '@zshzebra/svelte-multi-filter';
// Define your data structure
interface Product {
category: 'Shirt' | 'Pants' | 'Jacket';
color: 'Red' | 'Blue' | 'Black';
}
// Your data
const products = [
{ category: 'Shirt', color: 'Red' },
{ category: 'Pants', color: 'Blue' },
{ category: 'Shirt', color: 'Black' }
];
// Configure filter options
const config = {
category: ['Shirt', 'Pants', 'Jacket'],
color: ['Red', 'Blue', 'Black']
} satisfies FilterConfig<Product>;
// Create the filter store
const filter = createFilterStore(products, config);
<script lang="ts">
import {
createFilterStore,
type FilterConfig,
type FilterDimension
} from '@zshzebra/svelte-multi-filter';
interface Product {
category: 'Shirt' | 'Pants' | 'Jacket';
color: 'Red' | 'Blue' | 'Black';
}
const products = [
{ category: 'Shirt', color: 'Red' },
{ category: 'Pants', color: 'Blue' },
{ category: 'Shirt', color: 'Black' }
];
const config = {
category: ['Shirt', 'Pants', 'Jacket'],
color: ['Red', 'Blue', 'Black']
} satisfies FilterConfig<Product>;
const filter = createFilterStore(products, config);
// State for dimensions and results
let dimensions = $state<{
category: FilterDimension<string>;
color: FilterDimension<string>;
}>();
let results = $state<Product[]>([]);
let availableCategoryOptions = $state<string[]>([]);
let availableColorOptions = $state<string[]>([]);
// Subscribe to store changes
filter.subscribe((dims) => {
dimensions = dims;
});
// Subscribe to filtered items
filter.filteredItems.subscribe((items) => {
results = items;
});
// Subscribe to available options
filter.getAvailableOptions('category').subscribe((options) => {
availableCategoryOptions = options;
});
filter.getAvailableOptions('color').subscribe((options) => {
availableColorOptions = options;
});
</script>
<div class="filters">
<!-- Category Filter -->
<div class="filter-group">
<h3>Category</h3>
<label>
<input
type="radio"
name="category"
value="Any"
checked={dimensions?.category?.selected === 'Any'}
onchange={() => filter.select('category', 'Any')}
/>
Any
</label>
{#each config.category as option}
<label>
<input
type="radio"
name="category"
value={option}
checked={dimensions?.category?.selected === option}
disabled={!availableCategoryOptions.includes(option)}
onchange={() => filter.select('category', option)}
/>
{option}
</label>
{/each}
</div>
<!-- Color Filter -->
<div class="filter-group">
<h3>Color</h3>
<label>
<input
type="radio"
name="color"
value="Any"
checked={dimensions?.color?.selected === 'Any'}
onchange={() => filter.select('color', 'Any')}
/>
Any
</label>
{#each config.color as option}
<label>
<input
type="radio"
name="color"
value={option}
checked={dimensions?.color?.selected === option}
disabled={!availableColorOptions.includes(option)}
onchange={() => filter.select('color', option)}
/>
{option}
</label>
{/each}
</div>
</div>
<button onclick={() => filter.reset()}>Reset Filters</button>
<div class="results">
<h3>Results ({results.length})</h3>
{#each results as item}
<div>{JSON.stringify(item)}</div>
{/each}
</div>
createFilterStore<T>
Creates a new filter store for items of type T
.
function createFilterStore<T extends Record<string, any>>(
items: T[],
config: FilterConfig<T>
): FilterStore<T>;
items
: Array of items to filterconfig
: Configuration object containing arrays of possible values for each dimensionA filter store object with the following methods and properties:
subscribe
: Subscribe to dimension state changesselect
: Update a dimension's selected valuegetAvailableOptions
: Get a derived store of available options for a dimensionfilteredItems
: Derived store of filtered items based on current selectionsreset
: Reset all selections to 'Any'export type FilterDimension<T> = {
options: T[];
selected: T | 'Any';
};
export type FilterConfig<T extends Record<string, any>> = {
[K in keyof T]: T[K][];
};
The package is written in TypeScript and includes full type definitions. Generic types allow for type-safe filtering of your data structures.
Contributions are welcome! Please feel free to submit a Pull Request.
git checkout -b feature/AmazingFeature
)git commit -m 'Add some AmazingFeature'
)git push origin feature/AmazingFeature
)MIT License - see the LICENSE file for details