From 7ddf232e3a55ee28508b7572c7bc4fc1b263568e Mon Sep 17 00:00:00 2001 From: Ilia Mashkov Date: Tue, 2 Jun 2026 09:09:20 +0300 Subject: [PATCH] refactor(sample-list): replace layoutManager singleton with lazy accessor Convert the eager layoutManager singleton to getLayoutManager() (+ __resetLayoutManager for tests), so its persisted layout preference is read on first access rather than at module load. Update the model barrels and consumers (LayoutSwitch, SampleListSection, SampleList) with $derived reads; the LayoutSwitch test resolves via the accessor. --- src/widgets/SampleList/model/index.ts | 2 +- src/widgets/SampleList/model/stores/index.ts | 2 +- .../model/stores/layoutStore/layoutStore.svelte.ts | 14 ++++++++++++-- .../SampleList/ui/LayoutSwitch/LayoutSwitch.svelte | 9 ++++++--- .../ui/LayoutSwitch/LayoutSwitch.svelte.test.ts | 11 ++++++++++- .../SampleList/ui/SampleList/SampleList.svelte | 10 +++++++--- .../ui/SampleListSection/SampleListSection.svelte | 7 +++++-- 7 files changed, 42 insertions(+), 13 deletions(-) diff --git a/src/widgets/SampleList/model/index.ts b/src/widgets/SampleList/model/index.ts index 3209708..b99a59f 100644 --- a/src/widgets/SampleList/model/index.ts +++ b/src/widgets/SampleList/model/index.ts @@ -1,2 +1,2 @@ -export { layoutManager } from './stores'; +export { getLayoutManager } from './stores'; export type { LayoutMode } from './stores'; diff --git a/src/widgets/SampleList/model/stores/index.ts b/src/widgets/SampleList/model/stores/index.ts index 5ff5e64..9eedb6f 100644 --- a/src/widgets/SampleList/model/stores/index.ts +++ b/src/widgets/SampleList/model/stores/index.ts @@ -1,2 +1,2 @@ -export { layoutManager } from './layoutStore/layoutStore.svelte'; +export { getLayoutManager } from './layoutStore/layoutStore.svelte'; export type { LayoutMode } from './layoutStore/layoutStore.svelte'; diff --git a/src/widgets/SampleList/model/stores/layoutStore/layoutStore.svelte.ts b/src/widgets/SampleList/model/stores/layoutStore/layoutStore.svelte.ts index c1f4e8b..b40a19c 100644 --- a/src/widgets/SampleList/model/stores/layoutStore/layoutStore.svelte.ts +++ b/src/widgets/SampleList/model/stores/layoutStore/layoutStore.svelte.ts @@ -146,10 +146,20 @@ class LayoutManager { } } +let _layoutManager: LayoutManager | undefined; + /** - * Singleton layout manager instance + * App-wide layout manager, created on first access. Lazy so its persisted + * layout preference isn't read at module load. */ -export const layoutManager = new LayoutManager(); +export function getLayoutManager(): LayoutManager { + return (_layoutManager ??= new LayoutManager()); +} + +// test-only reset, so specs don't share persisted layout state +export function __resetLayoutManager() { + _layoutManager = undefined; +} // Export class for testing purposes export { LayoutManager }; diff --git a/src/widgets/SampleList/ui/LayoutSwitch/LayoutSwitch.svelte b/src/widgets/SampleList/ui/LayoutSwitch/LayoutSwitch.svelte index 0c17d32..b240375 100644 --- a/src/widgets/SampleList/ui/LayoutSwitch/LayoutSwitch.svelte +++ b/src/widgets/SampleList/ui/LayoutSwitch/LayoutSwitch.svelte @@ -7,7 +7,7 @@ import { ButtonGroup } from '$shared/ui'; import { IconButton } from '$shared/ui'; import GridIcon from '@lucide/svelte/icons/layout-grid'; import ListIcon from '@lucide/svelte/icons/stretch-horizontal'; -import { layoutManager } from '../../model'; +import { getLayoutManager } from '../../model'; interface Props { /** @@ -18,18 +18,21 @@ interface Props { const { class: className }: Props = $props(); +const layoutManager = getLayoutManager(); +const mode = $derived(layoutManager.mode); + function handleClick() { layoutManager.toggleMode(); } - + {#snippet icon()} {/snippet} - + {#snippet icon()} {/snippet} diff --git a/src/widgets/SampleList/ui/LayoutSwitch/LayoutSwitch.svelte.test.ts b/src/widgets/SampleList/ui/LayoutSwitch/LayoutSwitch.svelte.test.ts index bf591bb..576d6dc 100644 --- a/src/widgets/SampleList/ui/LayoutSwitch/LayoutSwitch.svelte.test.ts +++ b/src/widgets/SampleList/ui/LayoutSwitch/LayoutSwitch.svelte.test.ts @@ -4,14 +4,23 @@ import { screen, waitFor, } from '@testing-library/svelte'; -import { layoutManager } from '../../model'; +import { afterEach } from 'vitest'; +import { getLayoutManager } from '../../model'; +import { __resetLayoutManager } from '../../model/stores/layoutStore/layoutStore.svelte'; import LayoutSwitch from './LayoutSwitch.svelte'; describe('LayoutSwitch', () => { + let layoutManager: ReturnType; + beforeEach(() => { + layoutManager = getLayoutManager(); layoutManager.reset(); }); + afterEach(() => { + __resetLayoutManager(); + }); + describe('Rendering', () => { it('renders two icon buttons', () => { render(LayoutSwitch); diff --git a/src/widgets/SampleList/ui/SampleList/SampleList.svelte b/src/widgets/SampleList/ui/SampleList/SampleList.svelte index b7b0162..fab8af8 100644 --- a/src/widgets/SampleList/ui/SampleList/SampleList.svelte +++ b/src/widgets/SampleList/ui/SampleList/SampleList.svelte @@ -20,11 +20,15 @@ import { import { FontSampler } from '$features/DisplayFont'; import { throttle } from '$shared/lib/utils'; import { Skeleton } from '$shared/ui'; -import { layoutManager } from '../../model'; +import { getLayoutManager } from '../../model'; const fontCatalog = getFontCatalog(); const typographySettingsStore = getTypographySettingsStore(); const fontLifecycleManager = getFontLifecycleManager(); +const layoutManager = getLayoutManager(); + +const columns = $derived(layoutManager.columns); +const gap = $derived(layoutManager.gap); // FontSampler chrome heights — derived from Tailwind classes in FontSampler.svelte. // Header: py-3 (12+12px padding) + ~32px content row ≈ 56px. @@ -114,8 +118,8 @@ const fontRowHeight = $derived.by(() => itemHeight={fontRowHeight} useWindowScroll={true} weight={typographySettingsStore.weight} - columns={layoutManager.columns} - gap={layoutManager.gap} + {columns} + {gap} {skeleton} > {#snippet children({ item: font, index })} diff --git a/src/widgets/SampleList/ui/SampleListSection/SampleListSection.svelte b/src/widgets/SampleList/ui/SampleListSection/SampleListSection.svelte index fe312a4..6651fd4 100644 --- a/src/widgets/SampleList/ui/SampleListSection/SampleListSection.svelte +++ b/src/widgets/SampleList/ui/SampleListSection/SampleListSection.svelte @@ -12,7 +12,7 @@ import { Section, } from '$shared/ui'; import { getContext } from 'svelte'; -import { layoutManager } from '../../model'; +import { getLayoutManager } from '../../model'; import LayoutSwitch from '../LayoutSwitch/LayoutSwitch.svelte'; import SampleList from '../SampleList/SampleList.svelte'; @@ -29,6 +29,9 @@ const responsive = getContext('responsive'); const fontCatalog = getFontCatalog(); const total = $derived(fontCatalog?.pagination?.total); + +const layoutManager = getLayoutManager(); +const mode = $derived(layoutManager.mode); @@ -46,7 +49,7 @@ const total = $derived(fontCatalog?.pagination?.total);