From e0d39d861fdc94d3d498dda5069404c9c7040a86 Mon Sep 17 00:00:00 2001 From: Ilia Mashkov Date: Sun, 24 May 2026 18:08:05 +0300 Subject: [PATCH] refactor(GetFonts): rename filters/filterManager to available/appliedFilterStore MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The 'filters' + 'filterManager' pair didn't reveal the schema-vs-selection split. Rename to reflect the actual roles: - FiltersStore / filtersStore → AvailableFilterStore / availableFilterStore - createFilterManager / FilterManager → createAppliedFilterStore / AppliedFilterStore - filterManager singleton → appliedFilterStore - mapManagerToParams → mapAppliedFiltersToParams Directories and file basenames follow the new singleton names. Public barrel signature updated; all consumers (Search, FontSearch, Filters, FilterControls) point at the new identifiers. --- src/features/GetFonts/index.ts | 16 +-- src/features/GetFonts/lib/index.ts | 2 +- ...t.ts => mapAppliedFiltersToParams.test.ts} | 42 +++---- ...Params.ts => mapAppliedFiltersToParams.ts} | 6 +- src/features/GetFonts/model/index.ts | 22 ++-- .../appliedFilterStore.svelte.ts} | 14 +-- .../appliedFilterStore.test.ts} | 108 +++++++++--------- .../availableFilterStore.svelte.ts} | 12 +- .../availableFilterStore.test.ts} | 20 ++-- .../GetFonts/model/store/bindings.svelte.ts | 18 +-- .../ui/Filters/Filters.stories.svelte | 2 +- .../GetFonts/ui/Filters/Filters.svelte | 4 +- .../ui/Filters/Filters.svelte.test.ts | 16 +-- .../FilterControls.stories.svelte | 2 +- .../ui/FiltersControl/FilterControls.svelte | 4 +- .../ComparisonView/ui/Search/Search.svelte | 6 +- .../ui/Search/Search.svelte.test.ts | 8 +- .../ui/FontSearch/FontSearch.svelte | 4 +- 18 files changed, 153 insertions(+), 153 deletions(-) rename src/features/GetFonts/lib/mapper/{mapManagerToParams.test.ts => mapAppliedFiltersToParams.test.ts} (70%) rename src/features/GetFonts/lib/mapper/{mapManagerToParams.ts => mapAppliedFiltersToParams.ts} (86%) rename src/features/GetFonts/model/store/{filterManager/filterManager.svelte.ts => appliedFilterStore/appliedFilterStore.svelte.ts} (87%) rename src/features/GetFonts/model/store/{filterManager/filterManager.test.ts => appliedFilterStore/appliedFilterStore.test.ts} (88%) rename src/features/GetFonts/model/store/{filters/filters.svelte.ts => availableFilterStore/availableFilterStore.svelte.ts} (90%) rename src/features/GetFonts/model/store/{filters/filters.test.ts => availableFilterStore/availableFilterStore.test.ts} (88%) diff --git a/src/features/GetFonts/index.ts b/src/features/GetFonts/index.ts index 5784ac7..bd666a3 100644 --- a/src/features/GetFonts/index.ts +++ b/src/features/GetFonts/index.ts @@ -1,16 +1,16 @@ -export { mapManagerToParams } from './lib'; +export { mapAppliedFiltersToParams } from './lib'; export { - /** - * Filter Manager - */ - createFilterManager, - type FilterManager, - filterManager, + type AppliedFilterStore, + appliedFilterStore, /** * Filter Store */ - filtersStore, + availableFilterStore, + /** + * Filter Manager + */ + createAppliedFilterStore, /** * Sort Store */ diff --git a/src/features/GetFonts/lib/index.ts b/src/features/GetFonts/lib/index.ts index 1b7ac28..1187ed3 100644 --- a/src/features/GetFonts/lib/index.ts +++ b/src/features/GetFonts/lib/index.ts @@ -1 +1 @@ -export { mapManagerToParams } from './mapper/mapManagerToParams'; +export { mapAppliedFiltersToParams } from './mapper/mapAppliedFiltersToParams'; diff --git a/src/features/GetFonts/lib/mapper/mapManagerToParams.test.ts b/src/features/GetFonts/lib/mapper/mapAppliedFiltersToParams.test.ts similarity index 70% rename from src/features/GetFonts/lib/mapper/mapManagerToParams.test.ts rename to src/features/GetFonts/lib/mapper/mapAppliedFiltersToParams.test.ts index 8bb73c0..fb1d904 100644 --- a/src/features/GetFonts/lib/mapper/mapManagerToParams.test.ts +++ b/src/features/GetFonts/lib/mapper/mapAppliedFiltersToParams.test.ts @@ -4,8 +4,8 @@ import { expect, it, } from 'vitest'; -import { createFilterManager } from '../../model/store/filterManager/filterManager.svelte'; -import { mapManagerToParams } from './mapManagerToParams'; +import { createAppliedFilterStore } from '../../model/store/appliedFilterStore/appliedFilterStore.svelte'; +import { mapAppliedFiltersToParams } from './mapAppliedFiltersToParams'; /** * Build a Property with explicit selection state. @@ -25,47 +25,47 @@ function group(id: string, props: Array<[string, boolean]>) { }; } -describe('mapManagerToParams', () => { +describe('mapAppliedFiltersToParams', () => { describe('search query', () => { it('omits q when query is empty', () => { - const manager = createFilterManager({ queryValue: '', groups: [] }); - expect(mapManagerToParams(manager).q).toBeUndefined(); + const manager = createAppliedFilterStore({ queryValue: '', groups: [] }); + expect(mapAppliedFiltersToParams(manager).q).toBeUndefined(); }); it('passes the debounced query through as q', () => { // Constructor seeds both immediate and debounced synchronously. - const manager = createFilterManager({ queryValue: 'roboto', groups: [] }); - expect(mapManagerToParams(manager).q).toBe('roboto'); + const manager = createAppliedFilterStore({ queryValue: 'roboto', groups: [] }); + expect(mapAppliedFiltersToParams(manager).q).toBe('roboto'); }); }); describe('group selections', () => { it('omits a group entirely when no group with that id exists', () => { - const manager = createFilterManager({ queryValue: '', groups: [] }); - const params = mapManagerToParams(manager); + const manager = createAppliedFilterStore({ queryValue: '', groups: [] }); + const params = mapAppliedFiltersToParams(manager); expect(params.providers).toBeUndefined(); expect(params.categories).toBeUndefined(); expect(params.subsets).toBeUndefined(); }); it('omits a group when it exists but has no selections', () => { - const manager = createFilterManager({ + const manager = createAppliedFilterStore({ queryValue: '', groups: [group('providers', [['google', false], ['fontshare', false]])], }); - expect(mapManagerToParams(manager).providers).toBeUndefined(); + expect(mapAppliedFiltersToParams(manager).providers).toBeUndefined(); }); it('returns the selected values for a single group', () => { - const manager = createFilterManager({ + const manager = createAppliedFilterStore({ queryValue: '', groups: [group('providers', [['google', true], ['fontshare', false]])], }); - expect(mapManagerToParams(manager).providers).toEqual(['google']); + expect(mapAppliedFiltersToParams(manager).providers).toEqual(['google']); }); it('returns multiple selected values in selection order', () => { - const manager = createFilterManager({ + const manager = createAppliedFilterStore({ queryValue: '', groups: [ group('categories', [ @@ -76,11 +76,11 @@ describe('mapManagerToParams', () => { ]), ], }); - expect(mapManagerToParams(manager).categories).toEqual(['serif', 'display', 'monospace']); + expect(mapAppliedFiltersToParams(manager).categories).toEqual(['serif', 'display', 'monospace']); }); it('maps each of the three recognized group ids independently', () => { - const manager = createFilterManager({ + const manager = createAppliedFilterStore({ queryValue: '', groups: [ group('providers', [['google', true]]), @@ -88,18 +88,18 @@ describe('mapManagerToParams', () => { group('subsets', [['latin', true]]), ], }); - const params = mapManagerToParams(manager); + const params = mapAppliedFiltersToParams(manager); expect(params.providers).toEqual(['google']); expect(params.categories).toEqual(['serif', 'sans-serif']); expect(params.subsets).toEqual(['latin']); }); it('ignores groups whose id does not match providers/categories/subsets', () => { - const manager = createFilterManager({ + const manager = createAppliedFilterStore({ queryValue: '', groups: [group('weights', [['400', true], ['700', true]])], }); - const params = mapManagerToParams(manager); + const params = mapAppliedFiltersToParams(manager); expect(params.providers).toBeUndefined(); expect(params.categories).toBeUndefined(); expect(params.subsets).toBeUndefined(); @@ -108,7 +108,7 @@ describe('mapManagerToParams', () => { describe('combined output', () => { it('produces a complete param object when query and selections coexist', () => { - const manager = createFilterManager({ + const manager = createAppliedFilterStore({ queryValue: 'inter', groups: [ group('providers', [['google', true]]), @@ -116,7 +116,7 @@ describe('mapManagerToParams', () => { group('subsets', [['latin', false]]), ], }); - expect(mapManagerToParams(manager)).toEqual({ + expect(mapAppliedFiltersToParams(manager)).toEqual({ q: 'inter', providers: ['google'], categories: ['sans-serif'], diff --git a/src/features/GetFonts/lib/mapper/mapManagerToParams.ts b/src/features/GetFonts/lib/mapper/mapAppliedFiltersToParams.ts similarity index 86% rename from src/features/GetFonts/lib/mapper/mapManagerToParams.ts rename to src/features/GetFonts/lib/mapper/mapAppliedFiltersToParams.ts index 6153bd2..d8b8739 100644 --- a/src/features/GetFonts/lib/mapper/mapManagerToParams.ts +++ b/src/features/GetFonts/lib/mapper/mapAppliedFiltersToParams.ts @@ -1,5 +1,5 @@ import type { ProxyFontsParams } from '$entities/Font/api'; -import type { FilterManager } from '../../model'; +import type { AppliedFilterStore } from '../../model'; /** * Maps filter manager to proxy API parameters. @@ -19,7 +19,7 @@ import type { FilterManager } from '../../model'; * // subsets: ['latin'] * // } * - * const params = mapManagerToParams(manager); + * const params = mapAppliedFiltersToParams(manager); * // Returns: { * // providers: ['google', 'fontshare'], * // categories: ['sans-serif', 'serif'], @@ -28,7 +28,7 @@ import type { FilterManager } from '../../model'; * // } * ``` */ -export function mapManagerToParams(manager: FilterManager): Partial { +export function mapAppliedFiltersToParams(manager: AppliedFilterStore): Partial { /** * Return the list of selected values for a group, or undefined when * the group is missing or has no selection — matches the API's diff --git a/src/features/GetFonts/model/index.ts b/src/features/GetFonts/model/index.ts index 0c91b4f..b37c7be 100644 --- a/src/features/GetFonts/model/index.ts +++ b/src/features/GetFonts/model/index.ts @@ -16,29 +16,29 @@ export { /** * Low-level property selection store */ - filtersStore, -} from './store/filters/filters.svelte'; + availableFilterStore, +} from './store/availableFilterStore/availableFilterStore.svelte'; /** * Main filter controller */ export { /** - * Factory for constructing a filter manager instance + * Reactive interface returned by `createAppliedFilterStore` */ - createFilterManager, - /** - * Reactive interface returned by `createFilterManager` - */ - type FilterManager, + type AppliedFilterStore, /** * High-level manager for syncing search and filters */ - filterManager, -} from './store/filterManager/filterManager.svelte'; + appliedFilterStore, + /** + * Factory for constructing a filter manager instance + */ + createAppliedFilterStore, +} from './store/appliedFilterStore/appliedFilterStore.svelte'; /** - * Side-effect import: installs the global filterManager+sortStore → fontStore + * Side-effect import: installs the global appliedFilterStore+sortStore → fontStore * bridge on first import of this feature barrel. No exports. */ import './store/bindings.svelte'; diff --git a/src/features/GetFonts/model/store/filterManager/filterManager.svelte.ts b/src/features/GetFonts/model/store/appliedFilterStore/appliedFilterStore.svelte.ts similarity index 87% rename from src/features/GetFonts/model/store/filterManager/filterManager.svelte.ts rename to src/features/GetFonts/model/store/appliedFilterStore/appliedFilterStore.svelte.ts index af4879c..f2e8258 100644 --- a/src/features/GetFonts/model/store/filterManager/filterManager.svelte.ts +++ b/src/features/GetFonts/model/store/appliedFilterStore/appliedFilterStore.svelte.ts @@ -5,12 +5,12 @@ * debounced search input. Provides reactive state for filter selections * and convenience methods for bulk operations. * - * The factory (`createFilterManager`) is exported for tests; the app - * consumes the `filterManager` singleton at the bottom of this file. + * The factory (`createAppliedFilterStore`) is exported for tests; the app + * consumes the `appliedFilterStore` singleton at the bottom of this file. * * @example * ```ts - * const manager = createFilterManager({ + * const manager = createAppliedFilterStore({ * queryValue: '', * groups: [ * { id: 'providers', label: 'Provider', properties: [...] }, @@ -39,7 +39,7 @@ import type { * @param config - Configuration with query value and filter groups * @returns Filter manager instance with reactive state and methods */ -export function createFilterManager(config: FilterConfig) { +export function createAppliedFilterStore(config: FilterConfig) { const search = createDebouncedState(config.queryValue ?? ''); // Create filter instances upfront @@ -125,16 +125,16 @@ export function createFilterManager(config: FilterConfig< }; } -export type FilterManager = ReturnType; +export type AppliedFilterStore = ReturnType; /** * App-wide filter manager singleton. * - * Constructed with empty groups; the filtersStore → filterManager wiring + * Constructed with empty groups; the availableFilterStore → appliedFilterStore wiring * lives in `./bindings.svelte` and populates groups once backend filter * metadata arrives. */ -export const filterManager = createFilterManager({ +export const appliedFilterStore = createAppliedFilterStore({ queryValue: '', groups: [], }); diff --git a/src/features/GetFonts/model/store/filterManager/filterManager.test.ts b/src/features/GetFonts/model/store/appliedFilterStore/appliedFilterStore.test.ts similarity index 88% rename from src/features/GetFonts/model/store/filterManager/filterManager.test.ts rename to src/features/GetFonts/model/store/appliedFilterStore/appliedFilterStore.test.ts index 731a011..c546ac1 100644 --- a/src/features/GetFonts/model/store/filterManager/filterManager.test.ts +++ b/src/features/GetFonts/model/store/appliedFilterStore/appliedFilterStore.test.ts @@ -7,10 +7,10 @@ import { it, vi, } from 'vitest'; -import { createFilterManager } from './filterManager.svelte'; +import { createAppliedFilterStore } from './appliedFilterStore.svelte'; /** - * Test Suite for createFilterManager Helper Function + * Test Suite for createAppliedFilterStore Helper Function * * This suite tests the filter manager logic including: * - Debounced query state (immediate vs delayed) @@ -54,9 +54,9 @@ function createTestGroups(count: number, propertiesPerGroup = 3) { })); } -describe('createFilterManager - Initialization', () => { +describe('createAppliedFilterStore - Initialization', () => { it('creates manager with empty query value', () => { - const manager = createFilterManager({ + const manager = createAppliedFilterStore({ queryValue: '', groups: createTestGroups(2), }); @@ -66,7 +66,7 @@ describe('createFilterManager - Initialization', () => { }); it('creates manager with initial query value', () => { - const manager = createFilterManager({ + const manager = createAppliedFilterStore({ queryValue: 'search term', groups: createTestGroups(1), }); @@ -76,7 +76,7 @@ describe('createFilterManager - Initialization', () => { }); it('creates manager with undefined query value (defaults to empty string)', () => { - const manager = createFilterManager({ + const manager = createAppliedFilterStore({ groups: createTestGroups(1), }); @@ -86,7 +86,7 @@ describe('createFilterManager - Initialization', () => { it('creates filter groups for each config group', () => { const groups = createTestGroups(3); - const manager = createFilterManager({ + const manager = createAppliedFilterStore({ queryValue: '', groups, }); @@ -99,7 +99,7 @@ describe('createFilterManager - Initialization', () => { it('creates filter instances for each group', () => { const groups = createTestGroups(2, 5); - const manager = createFilterManager({ + const manager = createAppliedFilterStore({ queryValue: '', groups, }); @@ -118,7 +118,7 @@ describe('createFilterManager - Initialization', () => { { id: 'providers', label: 'Providers', properties: createTestProperties(2) }, { id: 'categories', label: 'Categories', properties: createTestProperties(3) }, ]; - const manager = createFilterManager({ + const manager = createAppliedFilterStore({ queryValue: '', groups, }); @@ -129,7 +129,7 @@ describe('createFilterManager - Initialization', () => { it('handles single group', () => { const groups = createTestGroups(1); - const manager = createFilterManager({ + const manager = createAppliedFilterStore({ queryValue: '', groups, }); @@ -139,7 +139,7 @@ describe('createFilterManager - Initialization', () => { }); }); -describe('createFilterManager - Debounced Query', () => { +describe('createAppliedFilterStore - Debounced Query', () => { beforeEach(() => { vi.useFakeTimers(); }); @@ -149,7 +149,7 @@ describe('createFilterManager - Debounced Query', () => { }); it('immediate query value updates instantly', () => { - const manager = createFilterManager({ + const manager = createAppliedFilterStore({ queryValue: '', groups: createTestGroups(1), }); @@ -161,7 +161,7 @@ describe('createFilterManager - Debounced Query', () => { }); it('debounced query value updates after default delay (300ms)', () => { - const manager = createFilterManager({ + const manager = createAppliedFilterStore({ queryValue: '', groups: createTestGroups(1), }); @@ -178,7 +178,7 @@ describe('createFilterManager - Debounced Query', () => { }); it('rapid query changes reset the debounce timer', () => { - const manager = createFilterManager({ + const manager = createAppliedFilterStore({ queryValue: '', groups: createTestGroups(1), }); @@ -200,7 +200,7 @@ describe('createFilterManager - Debounced Query', () => { }); it('handles empty string in query', () => { - const manager = createFilterManager({ + const manager = createAppliedFilterStore({ queryValue: 'initial', groups: createTestGroups(1), }); @@ -213,7 +213,7 @@ describe('createFilterManager - Debounced Query', () => { }); it('preserves initial query value until changed', () => { - const manager = createFilterManager({ + const manager = createAppliedFilterStore({ queryValue: 'initial search', groups: createTestGroups(1), }); @@ -228,9 +228,9 @@ describe('createFilterManager - Debounced Query', () => { }); }); -describe('createFilterManager - hasAnySelection Derived State', () => { +describe('createAppliedFilterStore - hasAnySelection Derived State', () => { it('returns false when no filters are selected', () => { - const manager = createFilterManager({ + const manager = createAppliedFilterStore({ queryValue: '', groups: createTestGroups(3, 3), }); @@ -240,7 +240,7 @@ describe('createFilterManager - hasAnySelection Derived State', () => { it('returns true when one filter in one group is selected', () => { const groups = createTestGroups(2, 3); - const manager = createFilterManager({ + const manager = createAppliedFilterStore({ queryValue: '', groups, }); @@ -255,7 +255,7 @@ describe('createFilterManager - hasAnySelection Derived State', () => { it('returns true when multiple filters across groups are selected', () => { const groups = createTestGroups(3, 3); - const manager = createFilterManager({ + const manager = createAppliedFilterStore({ queryValue: '', groups, }); @@ -272,7 +272,7 @@ describe('createFilterManager - hasAnySelection Derived State', () => { it('returns false after deselecting all filters', () => { const groups = createTestGroups(2, 3); - const manager = createFilterManager({ + const manager = createAppliedFilterStore({ queryValue: '', groups, }); @@ -286,7 +286,7 @@ describe('createFilterManager - hasAnySelection Derived State', () => { it('reacts to selection changes in individual groups', () => { const groups = createTestGroups(2, 3); - const manager = createFilterManager({ + const manager = createAppliedFilterStore({ queryValue: '', groups, }); @@ -318,7 +318,7 @@ describe('createFilterManager - hasAnySelection Derived State', () => { properties: createTestProperties(3, []), }, ]; - const manager = createFilterManager({ + const manager = createAppliedFilterStore({ queryValue: '', groups, }); @@ -331,7 +331,7 @@ describe('createFilterManager - hasAnySelection Derived State', () => { { id: 'group-0', label: 'Group 0', properties: [] }, { id: 'group-1', label: 'Group 1', properties: [] }, ]; - const manager = createFilterManager({ + const manager = createAppliedFilterStore({ queryValue: '', groups, }); @@ -340,10 +340,10 @@ describe('createFilterManager - hasAnySelection Derived State', () => { }); }); -describe('createFilterManager - getGroup() Method', () => { +describe('createAppliedFilterStore - getGroup() Method', () => { it('returns the correct group by ID', () => { const groups = createTestGroups(3); - const manager = createFilterManager({ + const manager = createAppliedFilterStore({ queryValue: '', groups, }); @@ -357,7 +357,7 @@ describe('createFilterManager - getGroup() Method', () => { it('returns undefined for non-existent group ID', () => { const groups = createTestGroups(2); - const manager = createFilterManager({ + const manager = createAppliedFilterStore({ queryValue: '', groups, }); @@ -369,7 +369,7 @@ describe('createFilterManager - getGroup() Method', () => { it('returns group with accessible filter instance', () => { const groups = createTestGroups(2, 3); - const manager = createFilterManager({ + const manager = createAppliedFilterStore({ queryValue: '', groups, }); @@ -385,7 +385,7 @@ describe('createFilterManager - getGroup() Method', () => { it('returns first group when requested', () => { const groups = createTestGroups(3); - const manager = createFilterManager({ + const manager = createAppliedFilterStore({ queryValue: '', groups, }); @@ -398,7 +398,7 @@ describe('createFilterManager - getGroup() Method', () => { it('returns last group when requested', () => { const groups = createTestGroups(5); - const manager = createFilterManager({ + const manager = createAppliedFilterStore({ queryValue: '', groups, }); @@ -410,10 +410,10 @@ describe('createFilterManager - getGroup() Method', () => { }); }); -describe('createFilterManager - deselectAllGlobal() Method', () => { +describe('createAppliedFilterStore - deselectAllGlobal() Method', () => { it('deselects all filters across all groups', () => { const groups = createTestGroups(3, 3); - const manager = createFilterManager({ + const manager = createAppliedFilterStore({ queryValue: '', groups, }); @@ -436,7 +436,7 @@ describe('createFilterManager - deselectAllGlobal() Method', () => { it('handles deselecting when nothing is selected', () => { const groups = createTestGroups(2, 3); - const manager = createFilterManager({ + const manager = createAppliedFilterStore({ queryValue: '', groups, }); @@ -453,7 +453,7 @@ describe('createFilterManager - deselectAllGlobal() Method', () => { { id: 'group-0', label: 'Group 0', properties: [] }, { id: 'group-1', label: 'Group 1', properties: [] }, ]; - const manager = createFilterManager({ + const manager = createAppliedFilterStore({ queryValue: '', groups, }); @@ -464,7 +464,7 @@ describe('createFilterManager - deselectAllGlobal() Method', () => { it('can select filters after global deselect', () => { const groups = createTestGroups(2, 3); - const manager = createFilterManager({ + const manager = createAppliedFilterStore({ queryValue: '', groups, }); @@ -482,7 +482,7 @@ describe('createFilterManager - deselectAllGlobal() Method', () => { it('handles partially selected groups', () => { const groups = createTestGroups(3, 5); - const manager = createFilterManager({ + const manager = createAppliedFilterStore({ queryValue: '', groups, }); @@ -505,7 +505,7 @@ describe('createFilterManager - deselectAllGlobal() Method', () => { }); }); -describe('createFilterManager - Complex Scenarios', () => { +describe('createAppliedFilterStore - Complex Scenarios', () => { beforeEach(() => { vi.useFakeTimers(); }); @@ -516,7 +516,7 @@ describe('createFilterManager - Complex Scenarios', () => { it('handles query changes and filter selections together', () => { const groups = createTestGroups(2, 3); - const manager = createFilterManager({ + const manager = createAppliedFilterStore({ queryValue: '', groups, }); @@ -553,7 +553,7 @@ describe('createFilterManager - Complex Scenarios', () => { }, ]; - const manager = createFilterManager({ + const manager = createAppliedFilterStore({ queryValue: '', groups, }); @@ -582,7 +582,7 @@ describe('createFilterManager - Complex Scenarios', () => { it('manages multiple independent filter groups correctly', () => { const groups = createTestGroups(4, 5); - const manager = createFilterManager({ + const manager = createAppliedFilterStore({ queryValue: '', groups, }); @@ -607,7 +607,7 @@ describe('createFilterManager - Complex Scenarios', () => { it('handles toggle operations via getGroup', () => { const groups = createTestGroups(2, 3); - const manager = createFilterManager({ + const manager = createAppliedFilterStore({ queryValue: '', groups, }); @@ -623,9 +623,9 @@ describe('createFilterManager - Complex Scenarios', () => { }); }); -describe('createFilterManager - Interface Compliance', () => { +describe('createAppliedFilterStore - Interface Compliance', () => { it('exposes queryValue getter', () => { - const manager = createFilterManager({ + const manager = createAppliedFilterStore({ queryValue: 'test', groups: createTestGroups(1), }); @@ -636,7 +636,7 @@ describe('createFilterManager - Interface Compliance', () => { }); it('exposes queryValue setter', () => { - const manager = createFilterManager({ + const manager = createAppliedFilterStore({ queryValue: 'test', groups: createTestGroups(1), }); @@ -647,7 +647,7 @@ describe('createFilterManager - Interface Compliance', () => { }); it('exposes debouncedQueryValue getter', () => { - const manager = createFilterManager({ + const manager = createAppliedFilterStore({ queryValue: 'test', groups: createTestGroups(1), }); @@ -658,7 +658,7 @@ describe('createFilterManager - Interface Compliance', () => { }); it('exposes groups getter', () => { - const manager = createFilterManager({ + const manager = createAppliedFilterStore({ queryValue: '', groups: createTestGroups(1), }); @@ -669,7 +669,7 @@ describe('createFilterManager - Interface Compliance', () => { }); it('exposes hasAnySelection getter', () => { - const manager = createFilterManager({ + const manager = createAppliedFilterStore({ queryValue: '', groups: createTestGroups(1), }); @@ -680,7 +680,7 @@ describe('createFilterManager - Interface Compliance', () => { }); it('exposes getGroup method', () => { - const manager = createFilterManager({ + const manager = createAppliedFilterStore({ queryValue: '', groups: createTestGroups(1), }); @@ -689,7 +689,7 @@ describe('createFilterManager - Interface Compliance', () => { }); it('exposes deselectAllGlobal method', () => { - const manager = createFilterManager({ + const manager = createAppliedFilterStore({ queryValue: '', groups: createTestGroups(1), }); @@ -698,7 +698,7 @@ describe('createFilterManager - Interface Compliance', () => { }); it('does not expose debouncedQueryValue setter', () => { - const manager = createFilterManager({ + const manager = createAppliedFilterStore({ queryValue: '', groups: createTestGroups(1), }); @@ -708,7 +708,7 @@ describe('createFilterManager - Interface Compliance', () => { }); }); -describe('createFilterManager - Edge Cases', () => { +describe('createAppliedFilterStore - Edge Cases', () => { it('handles single property groups', () => { const groups: Array<{ id: string; @@ -722,7 +722,7 @@ describe('createFilterManager - Edge Cases', () => { }, ]; - const manager = createFilterManager({ + const manager = createAppliedFilterStore({ queryValue: '', groups, }); @@ -749,7 +749,7 @@ describe('createFilterManager - Edge Cases', () => { }, ]; - const manager = createFilterManager({ + const manager = createAppliedFilterStore({ queryValue: '', groups, }); @@ -773,7 +773,7 @@ describe('createFilterManager - Edge Cases', () => { }, ]; - const manager = createFilterManager({ + const manager = createAppliedFilterStore({ queryValue: '', groups, }); diff --git a/src/features/GetFonts/model/store/filters/filters.svelte.ts b/src/features/GetFonts/model/store/availableFilterStore/availableFilterStore.svelte.ts similarity index 90% rename from src/features/GetFonts/model/store/filters/filters.svelte.ts rename to src/features/GetFonts/model/store/availableFilterStore/availableFilterStore.svelte.ts index 642ddc6..c4bebb7 100644 --- a/src/features/GetFonts/model/store/filters/filters.svelte.ts +++ b/src/features/GetFonts/model/store/availableFilterStore/availableFilterStore.svelte.ts @@ -6,12 +6,12 @@ * * @example * ```ts - * import { filtersStore } from '$features/GetFonts'; + * import { availableFilterStore } from '$features/GetFonts'; * * // Access filters (reactive) - * $: filters = filtersStore.filters; - * $: isLoading = filtersStore.isLoading; - * $: error = filtersStore.error; + * $: filters = availableFilterStore.filters; + * $: isLoading = availableFilterStore.isLoading; + * $: error = availableFilterStore.error; * ``` */ @@ -31,7 +31,7 @@ import { * Fetches and caches filter metadata using fetchProxyFilters() * Provides reactive access to filter data */ -export class FiltersStore { +export class AvailableFilterStore { /** * TanStack Query result state */ @@ -125,4 +125,4 @@ export class FiltersStore { /** * Singleton instance */ -export const filtersStore = new FiltersStore(); +export const availableFilterStore = new AvailableFilterStore(); diff --git a/src/features/GetFonts/model/store/filters/filters.test.ts b/src/features/GetFonts/model/store/availableFilterStore/availableFilterStore.test.ts similarity index 88% rename from src/features/GetFonts/model/store/filters/filters.test.ts rename to src/features/GetFonts/model/store/availableFilterStore/availableFilterStore.test.ts index 5dad619..8f489d4 100644 --- a/src/features/GetFonts/model/store/filters/filters.test.ts +++ b/src/features/GetFonts/model/store/availableFilterStore/availableFilterStore.test.ts @@ -9,7 +9,7 @@ import { } from 'vitest'; import * as filtersApi from '../../../api/filters/filters'; import type { FilterMetadata } from '../../../api/filters/filters'; -import { FiltersStore } from './filters.svelte'; +import { AvailableFilterStore } from './availableFilterStore.svelte'; /** * Build a minimal FilterMetadata fixture for tests. @@ -29,8 +29,8 @@ function metadata(id: string, optionValues: string[] = []): FilterMetadata { } as FilterMetadata; } -describe('FiltersStore', () => { - let store: FiltersStore; +describe('AvailableFilterStore', () => { + let store: AvailableFilterStore; beforeEach(() => { queryClient.clear(); @@ -47,13 +47,13 @@ describe('FiltersStore', () => { describe('initial state', () => { it('starts with an empty filter list', () => { vi.spyOn(filtersApi, 'fetchProxyFilters').mockResolvedValue([]); - store = new FiltersStore(); + store = new AvailableFilterStore(); expect(store.filters).toEqual([]); }); it('reports null error before any failure', () => { vi.spyOn(filtersApi, 'fetchProxyFilters').mockResolvedValue([]); - store = new FiltersStore(); + store = new AvailableFilterStore(); expect(store.error).toBeNull(); }); }); @@ -66,7 +66,7 @@ describe('FiltersStore', () => { ]; vi.spyOn(filtersApi, 'fetchProxyFilters').mockResolvedValue(data); - store = new FiltersStore(); + store = new AvailableFilterStore(); await vi.waitFor(() => expect(store.filters).toEqual(data), { timeout: 1000 }); expect(store.isError).toBe(false); @@ -75,7 +75,7 @@ describe('FiltersStore', () => { it('calls fetchProxyFilters exactly once for the initial load', async () => { const spy = vi.spyOn(filtersApi, 'fetchProxyFilters').mockResolvedValue([]); - store = new FiltersStore(); + store = new AvailableFilterStore(); await vi.waitFor(() => expect(spy).toHaveBeenCalledTimes(1), { timeout: 1000 }); }); @@ -84,7 +84,7 @@ describe('FiltersStore', () => { describe('error handling', () => { it('flips isError and exposes the error message on fetch failure', async () => { vi.spyOn(filtersApi, 'fetchProxyFilters').mockRejectedValue(new Error('boom')); - store = new FiltersStore(); + store = new AvailableFilterStore(); await vi.waitFor(() => expect(store.isError).toBe(true), { timeout: 1000 }); expect(store.error).toBe('boom'); @@ -97,13 +97,13 @@ describe('FiltersStore', () => { const data = [metadata('providers', ['google'])]; const spy = vi.spyOn(filtersApi, 'fetchProxyFilters').mockResolvedValue(data); - store = new FiltersStore(); + store = new AvailableFilterStore(); await vi.waitFor(() => expect(store.filters).toEqual(data), { timeout: 1000 }); expect(spy).toHaveBeenCalledTimes(1); // A second observer on the same query key should reuse the cached // result rather than triggering a new request. - const second = new FiltersStore(); + const second = new AvailableFilterStore(); try { // Give the new observer a tick to potentially refetch (it shouldn't). await new Promise(r => setTimeout(r, 50)); diff --git a/src/features/GetFonts/model/store/bindings.svelte.ts b/src/features/GetFonts/model/store/bindings.svelte.ts index cf98c2a..d1ff7c7 100644 --- a/src/features/GetFonts/model/store/bindings.svelte.ts +++ b/src/features/GetFonts/model/store/bindings.svelte.ts @@ -1,5 +1,5 @@ /** - * Bridges feature-level UI state (filterManager + sortStore) to the + * Bridges feature-level UI state (appliedFilterStore + sortStore) to the * entity-level fontStore query params. * * Centralizing this here means consumers (Search, FontSearch, @@ -11,22 +11,22 @@ import { fontStore } from '$entities/Font'; import { untrack } from 'svelte'; -import { mapManagerToParams } from '../../lib/mapper/mapManagerToParams'; -import { filterManager } from './filterManager/filterManager.svelte'; -import { filtersStore } from './filters/filters.svelte'; +import { mapAppliedFiltersToParams } from '../../lib/mapper/mapAppliedFiltersToParams'; +import { appliedFilterStore } from './appliedFilterStore/appliedFilterStore.svelte'; +import { availableFilterStore } from './availableFilterStore/availableFilterStore.svelte'; import { sortStore } from './sortStore/sortStore.svelte'; $effect.root(() => { /** - * Populate filterManager groups when backend filter metadata resolves. - * filtersStore is async; until it loads, filterManager has empty groups + * Populate appliedFilterStore groups when backend filter metadata resolves. + * availableFilterStore is async; until it loads, appliedFilterStore has empty groups * and the UI renders nothing for them. */ $effect(() => { - const dynamicFilters = filtersStore.filters; + const dynamicFilters = availableFilterStore.filters; if (dynamicFilters.length > 0) { - filterManager.setGroups( + appliedFilterStore.setGroups( dynamicFilters.map(filter => ({ id: filter.id, label: filter.name, @@ -47,7 +47,7 @@ $effect.root(() => { * into this effect's dependency graph. */ $effect(() => { - const params = mapManagerToParams(filterManager); + const params = mapAppliedFiltersToParams(appliedFilterStore); untrack(() => fontStore.setParams(params)); }); diff --git a/src/features/GetFonts/ui/Filters/Filters.stories.svelte b/src/features/GetFonts/ui/Filters/Filters.stories.svelte index 45add6f..8df9a74 100644 --- a/src/features/GetFonts/ui/Filters/Filters.stories.svelte +++ b/src/features/GetFonts/ui/Filters/Filters.stories.svelte @@ -9,7 +9,7 @@ const { Story } = defineMeta({ docs: { description: { component: - 'Renders the full list of filter groups managed by filterManager. Each group maps to a collapsible FilterGroup with checkboxes. No props — reads directly from the filterManager singleton.', + 'Renders the full list of filter groups managed by appliedFilterStore. Each group maps to a collapsible FilterGroup with checkboxes. No props — reads directly from the appliedFilterStore singleton.', }, story: { inline: false }, }, diff --git a/src/features/GetFonts/ui/Filters/Filters.svelte b/src/features/GetFonts/ui/Filters/Filters.svelte index 5c7749c..b993c48 100644 --- a/src/features/GetFonts/ui/Filters/Filters.svelte +++ b/src/features/GetFonts/ui/Filters/Filters.svelte @@ -4,10 +4,10 @@ --> -{#each filterManager.groups as group (group.id)} +{#each appliedFilterStore.groups as group (group.id)} { beforeEach(() => { - // Clear groups and mock filtersStore to be empty so the auto-sync effect doesn't overwrite us - filterManager.setGroups([]); - vi.spyOn(filtersStore, 'filters', 'get').mockReturnValue([]); + // Clear groups and mock availableFilterStore to be empty so the auto-sync effect doesn't overwrite us + appliedFilterStore.setGroups([]); + vi.spyOn(availableFilterStore, 'filters', 'get').mockReturnValue([]); }); afterEach(() => { @@ -28,7 +28,7 @@ describe('Filters', () => { }); it('renders a label for each filter group', () => { - filterManager.setGroups([ + appliedFilterStore.setGroups([ { id: 'cat', label: 'Categories', properties: [] }, { id: 'prov', label: 'Font Providers', properties: [] }, ]); @@ -38,7 +38,7 @@ describe('Filters', () => { }); it('renders filter properties within groups', () => { - filterManager.setGroups([ + appliedFilterStore.setGroups([ { id: 'cat', label: 'Category', @@ -54,7 +54,7 @@ describe('Filters', () => { }); it('renders multiple groups with their properties', () => { - filterManager.setGroups([ + appliedFilterStore.setGroups([ { id: 'cat', label: 'Category', diff --git a/src/features/GetFonts/ui/FiltersControl/FilterControls.stories.svelte b/src/features/GetFonts/ui/FiltersControl/FilterControls.stories.svelte index e1643a6..f8b7c0a 100644 --- a/src/features/GetFonts/ui/FiltersControl/FilterControls.stories.svelte +++ b/src/features/GetFonts/ui/FiltersControl/FilterControls.stories.svelte @@ -10,7 +10,7 @@ const { Story } = defineMeta({ docs: { description: { component: - 'Sort options and Reset_Filters button rendered below the filter list. Reads sort state from sortStore and dispatches resets via filterManager. Requires responsive context — wrap with Providers.', + 'Sort options and Reset_Filters button rendered below the filter list. Reads sort state from sortStore and dispatches resets via appliedFilterStore. Requires responsive context — wrap with Providers.', }, story: { inline: false }, }, diff --git a/src/features/GetFonts/ui/FiltersControl/FilterControls.svelte b/src/features/GetFonts/ui/FiltersControl/FilterControls.svelte index e9af16b..f249f99 100644 --- a/src/features/GetFonts/ui/FiltersControl/FilterControls.svelte +++ b/src/features/GetFonts/ui/FiltersControl/FilterControls.svelte @@ -12,7 +12,7 @@ import RefreshCwIcon from '@lucide/svelte/icons/refresh-cw'; import { getContext } from 'svelte'; import { SORT_OPTIONS, - filterManager, + appliedFilterStore, sortStore, } from '../../model'; @@ -31,7 +31,7 @@ const responsive = getContext('responsive'); const isMobileOrTabletPortrait = $derived(responsive.isMobile || responsive.isTabletPortrait); function handleReset() { - filterManager.deselectAllGlobal(); + appliedFilterStore.deselectAllGlobal(); } diff --git a/src/widgets/ComparisonView/ui/Search/Search.svelte b/src/widgets/ComparisonView/ui/Search/Search.svelte index c496a1d..d2b9162 100644 --- a/src/widgets/ComparisonView/ui/Search/Search.svelte +++ b/src/widgets/ComparisonView/ui/Search/Search.svelte @@ -1,11 +1,11 @@ @@ -15,7 +15,7 @@ import { SearchBar } from '$shared/ui'; class="w-full" placeholder="Typeface Search" aria-label="Search typefaces" - bind:value={filterManager.queryValue} + bind:value={appliedFilterStore.queryValue} fullWidth /> diff --git a/src/widgets/ComparisonView/ui/Search/Search.svelte.test.ts b/src/widgets/ComparisonView/ui/Search/Search.svelte.test.ts index e5a89d2..4490af1 100644 --- a/src/widgets/ComparisonView/ui/Search/Search.svelte.test.ts +++ b/src/widgets/ComparisonView/ui/Search/Search.svelte.test.ts @@ -1,4 +1,4 @@ -import { filterManager } from '$features/GetFonts'; +import { appliedFilterStore } from '$features/GetFonts'; import { render, screen, @@ -7,7 +7,7 @@ import Search from './Search.svelte'; describe('Search', () => { beforeEach(() => { - filterManager.queryValue = ''; + appliedFilterStore.queryValue = ''; }); describe('Rendering', () => { @@ -23,8 +23,8 @@ describe('Search', () => { }); describe('Value binding', () => { - it('reflects filterManager.queryValue as initial value', () => { - filterManager.queryValue = 'Inter'; + it('reflects appliedFilterStore.queryValue as initial value', () => { + appliedFilterStore.queryValue = 'Inter'; render(Search); expect(screen.getByRole('textbox')).toHaveValue('Inter'); }); diff --git a/src/widgets/FontSearch/ui/FontSearch/FontSearch.svelte b/src/widgets/FontSearch/ui/FontSearch/FontSearch.svelte index 9b2fc73..07d25e5 100644 --- a/src/widgets/FontSearch/ui/FontSearch/FontSearch.svelte +++ b/src/widgets/FontSearch/ui/FontSearch/FontSearch.svelte @@ -6,7 +6,7 @@ import { FilterControls, Filters, - filterManager, + appliedFilterStore, } from '$features/GetFonts'; import { springySlideFade } from '$shared/lib'; import { @@ -58,7 +58,7 @@ function toggleFilters() { class="w-full" placeholder="Typeface Search" aria-label="Search typefaces" - bind:value={filterManager.queryValue} + bind:value={appliedFilterStore.queryValue} fullWidth />