import { createStoreContext } from '@o/use-store' import { HighlightOptions, selectDefined } from '@o/utils' import React, { useMemo } from 'react' import { useDebounceValue } from './hooks/useDebounce' import { Text, TextProps } from './text/Text' export type HighlightQueryProps = { query?: string maxSurroundChars?: number maxChars?: number } const defaultState: HighlightQueryProps = { query: '', maxSurroundChars: Infinity, maxChars: Infinity, } class HighlightQueryStore { props: HighlightQueryProps get state() { const res = { ...defaultState } for (const key in this.props) { res[key] = this.props[key] } return res } } const HighlightQueryStoreContext = createStoreContext(HighlightQueryStore) export type ProvideHighlightProps = HighlightQueryProps & { children?: React.ReactNode } export const ProvideHighlight = ({ children, ...props }: ProvideHighlightProps) => { const valueDebounced = useDebounceValue(JSON.stringify(props), 200) const value = useMemo(() => props, [valueDebounced]) return ( {children} ) } export type HighlightTextProps = TextProps & HighlightQueryProps export function HighlightText({ children, maxSurroundChars, maxChars, ...props }: HighlightTextProps) { const { state } = HighlightQueryStoreContext.useStore() const query = selectDefined(props.query, state.query) const words = query.split(' ') const text = words && (words.length > 1 || // avoid too short of words (words[0] && words[0].length > 1)) ? words.join(' ') : '' const highlight: HighlightOptions = useMemo( () => ({ maxSurroundChars: maxSurroundChars || state.maxSurroundChars, maxChars: maxChars || state.maxChars, words, text, }), [state.maxSurroundChars, state.maxChars, text, query, maxSurroundChars, maxChars], ) return ( {children} ) }