Files
react/components/utils/use-context-state/create-geist-context.tsx
witt 6da0509316 release 2.1.0 (#451)
* feat: optimize fonts rendering on windows (#385)

* feat(styles): set Inter to highest font

* docs(fonts): add guide for fonts rendering on windows

* test: udpate snapshots

* chore: release v2.1.0-canary.0

* feat(table): add update row action to Table (#378)

* feat: add update to Table's actions. add test and doc

fix(table): fix comments

* feat(table): improve type for table actions

chore: update docs

chore: remove unused types

chore(table): improve docs

Co-authored-by: William Castandet <williamcastandet@williams-air.home>
Co-authored-by: unix <unix.bio@gmail.com>

* refactor(use-theme): move use-theme to the top directory (#397)

* refactor(use-theme): move use-theme to the top directory

* chore(jest): ignore use-theme of forwarding

* chore: release v2.1.0-canary.1

* feat(select): add clearable option to select multiple with test and english doc (#396)

* docs: add clearable option to select multiple with test and english doc

* fix: fix types for onClear

* fix: fix import path for use-theme

add more test for coverage

* docs(select): add chinese document

Co-authored-by: unix <unix.bio@gmail.com>

* chore: release v2.1.0-canary.2

* fix(tabs): scrollable (#404)

docs(tabs): scroll behavior

* feat(textarea): resize prop (#416)

* feat: add resize prop to textarea

* docs: add resize prop for textarea

* docs(textarea): improve docs and attributes for cn

* test(textarea): update snapshots

Co-authored-by: unix <unix.bio@gmail.com>

* fix(types): replace path aliases in type files (#432)

* fix(types): replace path aliases in type files

* chore(lint): upgrade eslint and optimize code style

* chore: fix type error for context handler

* test: update snapshots

* fix: use ttsc to identify aliases in type paths

* feat(hooks): add a tool hooks for react context (#439)

* feat(hooks): add a tool hooks for react context

* chore: move use-context-state to internal tools

style: fix lint warning

* chore: simplify the structure of the catalog

* refactor(themes): refactor theme module to keep multiple themes (#440)

* refactor(themes): refactor theme module to keep multiple themes

* chore: migrate APIs to be compatible with new theme system

* test: update snapshots

* chore: migrate the path of the theme module

* feat(themes): append static methods of themes

* chore: hide custom theme when no custom content in the context

* chore: manually add flush to preload styles in html

* docs(themes): update to fit the new theme system

* chore: release v2.1.0-canary.3 (#450)

* docs: add link to GH discussions

* chore: upgrade deps

* chore: update code style for prettier

* chore: release v2.1.0-canary.3

* chore(deps): upgrade babel

* chore: replace enzyme adapter with community repo to fit react.17

* test: updatee snapshots for auto typesetting

* test(config): ignore unexported parts of the tools

Co-authored-by: William <wcastand@gmail.com>
Co-authored-by: William Castandet <williamcastandet@williams-air.home>
Co-authored-by: Vaibhav Acharya <vaibhavacharya111@gmail.com>
Co-authored-by: Paul van Dyk <39598117+PaulPCIO@users.noreply.github.com>
2021-02-14 15:58:52 +08:00

77 lines
2.4 KiB
TypeScript

import React, { useImperativeHandle } from 'react'
import useContextState, {
ContextHandler,
ContextHandlerWhere,
ContextStateFilter,
ContextStateOnChange,
ContextStates,
} from './use-context-state'
import { capitalize } from '../collections'
const makeVirtualValues = <S,>(values: S): ContextStates<S> => {
const keys = Object.keys(values) as Array<keyof S>
const handlers = keys.reduce<ContextHandler<S>>((pre, current) => {
const updateHandler = {
// @ts-ignore
[`set${capitalize(current)}`]: (next: S[typeof current]) => {},
}
return { ...pre, ...updateHandler }
}, {} as ContextHandler<S>)
// @ts-ignore
const update: ContextHandlerWhere<S> = (key, next) => {}
return {
update,
...values,
...handlers,
}
}
export type GeistNamedContext<T, N> = {
[key in string as `use${Capitalize<string & N>}Context`]: () => T
}
export type GeistNamedProvider<T, N> = {
[key in string as `${Capitalize<string & N>}Provider`]: T
}
export const createGeistContext = <S extends Record<string, unknown>, N extends string>(
name: N,
initialStates: S,
) => {
const virtualValues = makeVirtualValues(initialStates)
const Context = React.createContext<ContextStates<S>>(virtualValues)
type GeistContextProps = {
defaultValues?: Partial<S> | (() => Partial<S>)
onChange?: ContextStateOnChange<S>
onChangeBefore?: ContextStateFilter<S>
}
const GeistContext = React.forwardRef<S, React.PropsWithChildren<GeistContextProps>>(
({ defaultValues, children, onChange, onChangeBefore }, ref) => {
const initialValues =
typeof defaultValues === 'function' ? (defaultValues as () => S)() : defaultValues
const mergedValues = {
...initialStates,
...initialValues,
} as Required<S>
const [states, , statesRef] = useContextState(mergedValues, {
onChange: onChange ? onChange : () => {},
filter: onChangeBefore ? onChangeBefore : () => true,
})
useImperativeHandle(ref, () => statesRef.current, [statesRef.current])
return <Context.Provider value={states}>{children}</Context.Provider>
},
)
type ResultType = GeistNamedProvider<typeof GeistContext, N> &
GeistNamedContext<ContextStates<S>, N>
return {
[`${capitalize(name)}Provider`]: GeistContext,
[`use${capitalize(name)}Context`]: () => React.useContext<ContextStates<S>>(Context),
} as ResultType
}