83
common/resources/client/ui/font-selector/font-selector-state.ts
Executable file
83
common/resources/client/ui/font-selector/font-selector-state.ts
Executable file
@@ -0,0 +1,83 @@
|
||||
import {useCallback, useEffect, useMemo, useState} from 'react';
|
||||
import {FontSelectorFilterValue} from '@common/ui/font-selector/font-selector-filters';
|
||||
import {FontConfig, useValueLists} from '@common/http/value-lists';
|
||||
import {useFilter} from '@common/i18n/use-filter';
|
||||
import {BrowserSafeFonts} from '@common/ui/font-picker/browser-safe-fonts';
|
||||
import {chunkArray} from '@common/utils/array/chunk-array';
|
||||
import {loadFonts} from '@common/ui/font-picker/load-fonts';
|
||||
|
||||
export interface FontSelectorState extends UseFontSelectorProps {
|
||||
fonts: FontConfig[];
|
||||
filteredFonts: FontConfig[];
|
||||
pages: FontConfig[][];
|
||||
isLoading: boolean;
|
||||
filters: FontSelectorFilterValue;
|
||||
setFilters: (filters: FontSelectorFilterValue) => void;
|
||||
currentPage: number;
|
||||
setCurrentPage: (page: number) => void;
|
||||
}
|
||||
|
||||
export interface UseFontSelectorProps {
|
||||
value?: FontConfig;
|
||||
onChange: (value: FontConfig) => void;
|
||||
}
|
||||
export function useFontSelectorState({
|
||||
value,
|
||||
onChange,
|
||||
}: UseFontSelectorProps): FontSelectorState {
|
||||
const {data, isLoading} = useValueLists(['googleFonts']);
|
||||
const [currentPage, setCurrentPage] = useState(0);
|
||||
|
||||
const [filters, setFilterState] = useState<FontSelectorFilterValue>({
|
||||
query: '',
|
||||
category: value?.category ?? '',
|
||||
});
|
||||
const {contains} = useFilter({
|
||||
sensitivity: 'base',
|
||||
});
|
||||
|
||||
const setFilters = useCallback((filters: FontSelectorFilterValue) => {
|
||||
setFilterState(filters);
|
||||
// reset to first page when searching or changing category
|
||||
setCurrentPage(0);
|
||||
}, []);
|
||||
|
||||
const allFonts = useMemo(() => {
|
||||
return BrowserSafeFonts.concat(data?.googleFonts ?? []);
|
||||
}, [data?.googleFonts]);
|
||||
|
||||
const filteredFonts = useMemo(() => {
|
||||
return allFonts.filter(font => {
|
||||
return (
|
||||
contains(font.family, filters.query) &&
|
||||
(!filters.category ||
|
||||
font.category?.toLowerCase() === filters.category.toLowerCase())
|
||||
);
|
||||
});
|
||||
}, [allFonts, filters, contains]);
|
||||
|
||||
const pages = useMemo(() => {
|
||||
return chunkArray(filteredFonts, 20);
|
||||
}, [filteredFonts]);
|
||||
const fonts = pages[currentPage];
|
||||
|
||||
useEffect(() => {
|
||||
const id = 'font-selector';
|
||||
if (fonts?.length) {
|
||||
loadFonts(fonts, {id});
|
||||
}
|
||||
}, [fonts, currentPage]);
|
||||
|
||||
return {
|
||||
fonts: fonts || [],
|
||||
currentPage,
|
||||
filteredFonts: filteredFonts || [],
|
||||
setCurrentPage,
|
||||
isLoading,
|
||||
filters,
|
||||
setFilters,
|
||||
value,
|
||||
onChange,
|
||||
pages,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user