-
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(Case): add
as
props & refactor code. (#45)
- Loading branch information
1 parent
7b9e5d8
commit 0cfc8b8
Showing
5 changed files
with
159 additions
and
39 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
import { useEffect, useId } from 'react'; | ||
import { type InitialState, useSwitchDispatch } from './switch.store'; | ||
|
||
type TagType = React.ElementType | keyof JSX.IntrinsicElements; | ||
interface CaseElementProps<T extends TagType> { | ||
as?: T; | ||
readonly condition?: boolean; | ||
} | ||
|
||
export type CaseProps<T extends TagType> = CaseElementProps<T> & React.ComponentPropsWithoutRef<T>; | ||
|
||
export const Case = <T extends TagType>(props: CaseProps<T>) => { | ||
const ids = useId(); | ||
const dispatch = useSwitchDispatch(); | ||
const { children, condition, as: Comp, ...reset } = props; | ||
const Elm = Comp as TagType; | ||
const child = Elm ? <Elm {...reset}>{children}</Elm> : children; | ||
const state: InitialState = { [ids]: child, active: { [ids]: !!condition } }; | ||
useEffect(() => dispatch(state), [state]); | ||
return null; | ||
}; | ||
|
||
export const Default = <T extends TagType>(props: CaseProps<T>) => { | ||
const dispatch = useSwitchDispatch(); | ||
const { children, as: Comp, ...reset } = props; | ||
const Elm = Comp as TagType; | ||
const child = Elm ? <Elm {...reset}>{children}</Elm> : children; | ||
useEffect(() => dispatch({ default: child }), [props]); | ||
return null; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
import { createContext, useContext, useReducer } from 'react'; | ||
|
||
export type InitialState = { | ||
[key: string]: React.ReactNode; | ||
} & { | ||
default?: React.ReactNode; | ||
active?: Record<string, boolean>; | ||
}; | ||
|
||
const initialState: InitialState = {}; | ||
export const Context = createContext<InitialState>(initialState); | ||
|
||
const reducer = (state: InitialState, action: InitialState) => { | ||
action.active = action.active ?? {}; | ||
action.active = { ...state.active, ...action.active }; | ||
return { | ||
...state, | ||
...action, | ||
}; | ||
}; | ||
|
||
export const useSwitchStore = () => { | ||
return useContext(Context); | ||
}; | ||
|
||
export function useSwitch() { | ||
return useReducer(reducer, initialState); | ||
} | ||
|
||
type Dispatch = React.Dispatch<InitialState>; | ||
export const DispatchSwitch = createContext<Dispatch>(() => {}); | ||
DispatchSwitch.displayName = 'OW.DispatchSwitch'; | ||
|
||
export function useSwitchDispatch() { | ||
return useContext(DispatchSwitch); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,26 +1,37 @@ | ||
import { ReactElement, Children } from 'react'; | ||
import { FC, PropsWithChildren } from 'react'; | ||
import { type FC, type PropsWithChildren } from 'react'; | ||
import { DispatchSwitch, Context, useSwitch, useSwitchStore } from './switch.store'; | ||
import { Case, Default } from './case'; | ||
|
||
export * from './case'; | ||
|
||
export const Switch: FC<PropsWithChildren<{}>> = ({ children }) => { | ||
let matchChild: ReactElement | null = null; | ||
let defaultCase: ReactElement | null = null; | ||
Children.forEach(Children.toArray(children) as ReactElement<PropsWithChildren<CaseProps>>[], (child) => { | ||
if (!matchChild && child.type === Case) { | ||
const { condition } = child.props; | ||
const conditionIsTrue = Boolean(condition); | ||
if (conditionIsTrue) { | ||
matchChild = child; | ||
const [state, dispatch] = useSwitch(); | ||
const filteredChildren = []; | ||
const childs = Array.isArray(children) ? children : children ? [children] : null; | ||
if (childs) { | ||
for (let i = 0; i < childs.length; i++) { | ||
const child = childs[i]; | ||
if (child && (child.type === Case || child.type === Default)) { | ||
filteredChildren.push(child); | ||
} | ||
} else if (!defaultCase && child.type === Default) { | ||
defaultCase = child; | ||
} | ||
}); | ||
return matchChild ?? defaultCase ?? null; | ||
} | ||
return ( | ||
<Context.Provider value={state}> | ||
<DispatchSwitch.Provider value={dispatch}>{childs}</DispatchSwitch.Provider> | ||
<Render /> | ||
</Context.Provider> | ||
); | ||
}; | ||
|
||
export interface CaseProps { | ||
readonly condition?: boolean; | ||
} | ||
|
||
export const Case: FC<PropsWithChildren<CaseProps>> = ({ children }) => children; | ||
export const Default: FC<PropsWithChildren> = ({ children }) => children; | ||
const Render = () => { | ||
const state = useSwitchStore(); | ||
let activeKey; | ||
for (var key in state.active) { | ||
if (state.active[key] === true) { | ||
activeKey = key; | ||
break; | ||
} | ||
} | ||
return state[activeKey ?? 'default'] ?? null; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters