refactor(createFilterStore): move from store pattern to svelte 5 runes usage
This commit is contained in:
@@ -1,226 +0,0 @@
|
||||
import {
|
||||
type Readable,
|
||||
type Writable,
|
||||
derived,
|
||||
writable,
|
||||
} from 'svelte/store';
|
||||
|
||||
export interface Property {
|
||||
/**
|
||||
* Property identifier
|
||||
*/
|
||||
id: string;
|
||||
/**
|
||||
* Property name
|
||||
*/
|
||||
name: string;
|
||||
/**
|
||||
* Property selected state
|
||||
*/
|
||||
selected?: boolean;
|
||||
}
|
||||
|
||||
export interface FilterModel {
|
||||
/**
|
||||
* Search query
|
||||
*/
|
||||
searchQuery?: string;
|
||||
/**
|
||||
* Properties
|
||||
*/
|
||||
properties: Property[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Model for reusable filter store with search support and property selection
|
||||
*/
|
||||
export interface FilterStore<T extends FilterModel> extends Writable<T> {
|
||||
/**
|
||||
* Get the store.
|
||||
* @returns Readable store with filter data
|
||||
*/
|
||||
getStore: () => Readable<T>;
|
||||
/**
|
||||
* Get all properties.
|
||||
* @returns Readable store with properties
|
||||
*/
|
||||
getAllProperties: () => Readable<Property[]>;
|
||||
/**
|
||||
* Get the selected properties.
|
||||
* @returns Readable store with selected properties
|
||||
*/
|
||||
getSelectedProperties: () => Readable<Property[]>;
|
||||
/**
|
||||
* Get the filtered properties.
|
||||
* @returns Readable store with filtered properties
|
||||
*/
|
||||
getFilteredProperties: () => Readable<Property[]>;
|
||||
/**
|
||||
* Update the search query filter.
|
||||
*
|
||||
* @param searchQuery - Search text (undefined to clear)
|
||||
*/
|
||||
setSearchQuery: (searchQuery: string | undefined) => void;
|
||||
/**
|
||||
* Clear the search query filter.
|
||||
*/
|
||||
clearSearchQuery: () => void;
|
||||
/**
|
||||
* Select a property.
|
||||
*
|
||||
* @param property - Property to select
|
||||
*/
|
||||
selectProperty: (propertyId: string) => void;
|
||||
/**
|
||||
* Deselect a property.
|
||||
*
|
||||
* @param property - Property to deselect
|
||||
*/
|
||||
deselectProperty: (propertyId: string) => void;
|
||||
/**
|
||||
* Toggle a property.
|
||||
*
|
||||
* @param propertyId - Property ID
|
||||
*/
|
||||
toggleProperty: (propertyId: string) => void;
|
||||
/**
|
||||
* Select all properties.
|
||||
*/
|
||||
selectAllProperties: () => void;
|
||||
/**
|
||||
* Deselect all properties.
|
||||
*/
|
||||
deselectAllProperties: () => void;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a filter store.
|
||||
* @param initialState - Initial state of the filter store
|
||||
* @returns FilterStore<T>
|
||||
*/
|
||||
export function createFilterStore<T extends FilterModel>(
|
||||
initialState?: T,
|
||||
): FilterStore<T> {
|
||||
const { subscribe, set, update } = writable<T>(initialState);
|
||||
|
||||
return {
|
||||
/*
|
||||
* Expose subscribe, set, and update from Writable.
|
||||
* This makes FilterStore compatible with Writable interface.
|
||||
*/
|
||||
subscribe,
|
||||
set,
|
||||
update,
|
||||
/**
|
||||
* Get the current state of the filter store.
|
||||
*/
|
||||
getStore: () => {
|
||||
return {
|
||||
subscribe,
|
||||
};
|
||||
},
|
||||
/**
|
||||
* Get the filtered properties.
|
||||
*/
|
||||
getAllProperties: () => {
|
||||
return derived({ subscribe }, $store => {
|
||||
return $store.properties;
|
||||
});
|
||||
},
|
||||
/**
|
||||
* Get the selected properties.
|
||||
*/
|
||||
getSelectedProperties: () => {
|
||||
return derived({ subscribe }, $store => {
|
||||
return $store.properties.filter(property => property.selected);
|
||||
});
|
||||
},
|
||||
/**
|
||||
* Get the filtered properties.
|
||||
*/
|
||||
getFilteredProperties: () => {
|
||||
return derived({ subscribe }, $store => {
|
||||
return $store.properties.filter(property =>
|
||||
property.name.includes($store.searchQuery || '')
|
||||
);
|
||||
});
|
||||
},
|
||||
/**
|
||||
* Update the search query filter.
|
||||
*
|
||||
* @param searchQuery - Search text (undefined to clear)
|
||||
*/
|
||||
setSearchQuery: (searchQuery: string | undefined) => {
|
||||
update(state => ({
|
||||
...state,
|
||||
searchQuery: searchQuery || undefined,
|
||||
}));
|
||||
},
|
||||
/**
|
||||
* Clear the search query filter.
|
||||
*/
|
||||
clearSearchQuery: () => {
|
||||
update(state => ({
|
||||
...state,
|
||||
searchQuery: undefined,
|
||||
}));
|
||||
},
|
||||
/**
|
||||
* Select a property.
|
||||
*
|
||||
* @param propertyId - Property ID
|
||||
*/
|
||||
selectProperty: (propertyId: string) => {
|
||||
update(state => ({
|
||||
...state,
|
||||
properties: state.properties.map(c =>
|
||||
c.id === propertyId ? { ...c, selected: true } : c
|
||||
),
|
||||
}));
|
||||
},
|
||||
/**
|
||||
* Deselect a property.
|
||||
*
|
||||
* @param propertyId - Property ID
|
||||
*/
|
||||
deselectProperty: (propertyId: string) => {
|
||||
update(state => ({
|
||||
...state,
|
||||
properties: state.properties.map(c =>
|
||||
c.id === propertyId ? { ...c, selected: false } : c
|
||||
),
|
||||
}));
|
||||
},
|
||||
/**
|
||||
* Toggle a property.
|
||||
*
|
||||
* @param propertyId - Property ID
|
||||
*/
|
||||
toggleProperty: (propertyId: string) => {
|
||||
update(state => ({
|
||||
...state,
|
||||
properties: state.properties.map(c =>
|
||||
c.id === propertyId ? { ...c, selected: !c.selected } : c
|
||||
),
|
||||
}));
|
||||
},
|
||||
/**
|
||||
* Select all properties
|
||||
*/
|
||||
selectAllProperties: () => {
|
||||
update(state => ({
|
||||
...state,
|
||||
properties: state.properties.map(c => ({ ...c, selected: true })),
|
||||
}));
|
||||
},
|
||||
/**
|
||||
* Deselect all properties
|
||||
*/
|
||||
deselectAllProperties: () => {
|
||||
update(state => ({
|
||||
...state,
|
||||
properties: state.properties.map(c => ({ ...c, selected: false })),
|
||||
}));
|
||||
},
|
||||
};
|
||||
}
|
||||
120
src/shared/lib/utils/filter/createFilter/createFilter.svelte.ts
Normal file
120
src/shared/lib/utils/filter/createFilter/createFilter.svelte.ts
Normal file
@@ -0,0 +1,120 @@
|
||||
import { SvelteSet } from 'svelte/reactivity';
|
||||
|
||||
export interface Property {
|
||||
/**
|
||||
* Property identifier
|
||||
*/
|
||||
id: string;
|
||||
/**
|
||||
* Property name
|
||||
*/
|
||||
name: string;
|
||||
/**
|
||||
* Property selected state
|
||||
*/
|
||||
selected?: boolean;
|
||||
}
|
||||
|
||||
export interface FilterModel {
|
||||
/**
|
||||
* Search query
|
||||
*/
|
||||
searchQuery?: string;
|
||||
/**
|
||||
* Properties
|
||||
*/
|
||||
properties: Property[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a filter store.
|
||||
* @param initialState - Initial state of the filter store
|
||||
*/
|
||||
export function createFilter<T extends FilterModel>(
|
||||
initialState: T,
|
||||
) {
|
||||
let properties = $state(
|
||||
initialState.properties.map(p => ({
|
||||
...p,
|
||||
selected: p.selected ?? false,
|
||||
})),
|
||||
);
|
||||
|
||||
const selectedProperties = $derived.by(() => {
|
||||
const _ = properties;
|
||||
return properties.filter(p => p.selected);
|
||||
});
|
||||
|
||||
const selectedCount = $derived.by(() => {
|
||||
const _ = properties;
|
||||
return selectedProperties.length;
|
||||
});
|
||||
|
||||
return {
|
||||
/**
|
||||
* Get all properties.
|
||||
*/
|
||||
get properties() {
|
||||
return properties;
|
||||
},
|
||||
/**
|
||||
* Get selected properties.
|
||||
*/
|
||||
get selectedProperties() {
|
||||
return selectedProperties;
|
||||
},
|
||||
/**
|
||||
* Get selected count.
|
||||
*/
|
||||
get selectedCount() {
|
||||
return selectedCount;
|
||||
},
|
||||
/**
|
||||
* Toggle property selection.
|
||||
*/
|
||||
toggleProperty: (id: string) => {
|
||||
properties = properties.map(p => ({
|
||||
...p,
|
||||
selected: p.id === id ? !p.selected : p.selected,
|
||||
}));
|
||||
},
|
||||
/**
|
||||
* Select property.
|
||||
*/
|
||||
selectProperty(id: string) {
|
||||
properties = properties.map(p => ({
|
||||
...p,
|
||||
selected: p.id === id ? true : p.selected,
|
||||
}));
|
||||
},
|
||||
/**
|
||||
* Deselect property.
|
||||
*/
|
||||
deselectProperty(id: string) {
|
||||
properties = properties.map(p => ({
|
||||
...p,
|
||||
selected: p.id === id ? false : p.selected,
|
||||
}));
|
||||
},
|
||||
/**
|
||||
* Select all properties.
|
||||
*/
|
||||
selectAll: () => {
|
||||
properties = properties.map(p => ({
|
||||
...p,
|
||||
selected: true,
|
||||
}));
|
||||
},
|
||||
/**
|
||||
* Deselect all properties.
|
||||
*/
|
||||
deselectAll: () => {
|
||||
properties = properties.map(p => ({
|
||||
...p,
|
||||
selected: false,
|
||||
}));
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export type Filter = ReturnType<typeof createFilter>;
|
||||
@@ -7,4 +7,11 @@ export type {
|
||||
QueryParams,
|
||||
QueryParamValue,
|
||||
} from './buildQueryString';
|
||||
export { createVirtualizer } from './createVirtualizer/createVirtualizer';
|
||||
export {
|
||||
createVirtualizer,
|
||||
type Virtualizer,
|
||||
} from './createVirtualizer/createVirtualizer.svelte';
|
||||
export {
|
||||
createFilter,
|
||||
type Filter,
|
||||
} from './filter/createFilter/createFilter.svelte';
|
||||
|
||||
Reference in New Issue
Block a user