diff --git a/core/README.md b/core/README.md
index 8ef3a57..71279e7 100644
--- a/core/README.md
+++ b/core/README.md
@@ -100,7 +100,7 @@ import { Switch, Case, Default } from '@uiw/react-only-when/switch'
preschool
- = 6}>primary school
+ = 6}>primary school
you graduated
```
@@ -113,11 +113,11 @@ export default function App() {
const [age, setAge] = useState(19)
return (
- setAge(Number(evn.target.value))} /> {age}
+ setAge(Number(evn.target.value))} /> {age}
Preschool
= 6 && age < 18}>Primary school
- = 18}>Went to college
+ = 18 && age < 60}>Went to college
you graduated
@@ -125,6 +125,29 @@ export default function App() {
}
```
+Defaults to specifying a wrapped HTML Element.
+
+```jsx mdx:preview&background=#fff&codePen=true
+import React, { useState, Fragment } from 'react';
+import { Switch, Case, Default } from '@uiw/react-only-when/switch'
+
+export default function App() {
+ const [age, setAge] = useState(19)
+ return (
+
+ setAge(Number(evn.target.value))} /> {age}
+
+
+ Preschool
+ = 6 && age < 18}>Primary school
+ = 18 && age < 60}>Went to college
+ you graduated
+
+
+ );
+}
+```
+
## `` props
| prop name | type | default | isRequired | description |
diff --git a/core/src/case.tsx b/core/src/case.tsx
new file mode 100644
index 0000000..145f602
--- /dev/null
+++ b/core/src/case.tsx
@@ -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 {
+ as?: T;
+ readonly condition?: boolean;
+}
+
+export type CaseProps = CaseElementProps & React.ComponentPropsWithoutRef;
+
+export const Case = (props: CaseProps) => {
+ const ids = useId();
+ const dispatch = useSwitchDispatch();
+ const { children, condition, as: Comp, ...reset } = props;
+ const Elm = Comp as TagType;
+ const child = Elm ? {children} : children;
+ const state: InitialState = { [ids]: child, active: { [ids]: !!condition } };
+ useEffect(() => dispatch(state), [state]);
+ return null;
+};
+
+export const Default = (props: CaseProps) => {
+ const dispatch = useSwitchDispatch();
+ const { children, as: Comp, ...reset } = props;
+ const Elm = Comp as TagType;
+ const child = Elm ? {children} : children;
+ useEffect(() => dispatch({ default: child }), [props]);
+ return null;
+};
diff --git a/core/src/switch.store.tsx b/core/src/switch.store.tsx
new file mode 100644
index 0000000..d3d76d8
--- /dev/null
+++ b/core/src/switch.store.tsx
@@ -0,0 +1,36 @@
+import { createContext, useContext, useReducer } from 'react';
+
+export type InitialState = {
+ [key: string]: React.ReactNode;
+} & {
+ default?: React.ReactNode;
+ active?: Record;
+};
+
+const initialState: InitialState = {};
+export const Context = createContext(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;
+export const DispatchSwitch = createContext(() => {});
+DispatchSwitch.displayName = 'OW.DispatchSwitch';
+
+export function useSwitchDispatch() {
+ return useContext(DispatchSwitch);
+}
diff --git a/core/src/switch.tsx b/core/src/switch.tsx
index 267b9d1..b7a2eb4 100644
--- a/core/src/switch.tsx
+++ b/core/src/switch.tsx
@@ -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> = ({ children }) => {
- let matchChild: ReactElement | null = null;
- let defaultCase: ReactElement | null = null;
- Children.forEach(Children.toArray(children) as ReactElement>[], (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 (
+
+ {childs}
+
+
+ );
};
-export interface CaseProps {
- readonly condition?: boolean;
-}
-
-export const Case: FC> = ({ children }) => children;
-export const Default: FC = ({ 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;
+};
diff --git a/test/switch.test.tsx b/test/switch.test.tsx
index 0471d29..9fd2a82 100644
--- a/test/switch.test.tsx
+++ b/test/switch.test.tsx
@@ -1,8 +1,7 @@
-/* eslint-disable jest/no-conditional-expect */
import renderer from 'react-test-renderer';
+import { render, screen } from '@testing-library/react';
import { Switch, Case, Default } from '../core/src/switch';
-
it('', () => {
const component = renderer.create(
@@ -12,46 +11,67 @@ it('', () => {
});
it('', () => {
- const component = renderer.create(
+ const { container } = render(
you graduated
);
- const only = component.toJSON();
- expect(only).toEqual('you graduated');
+ expect(container.innerHTML).toEqual('you graduated');
});
it('', () => {
- const component = renderer.create(
+ const { container } = render(
preschool
you graduated
);
- const only = component.toJSON();
- expect(only).toEqual('preschool');
+ expect(container.innerHTML).toEqual('preschool');
});
-it(' condition=true', () => {
- const component = renderer.create(
+it('', () => {
+ const { container } = render(
preschool
primary school
you graduated
);
- const only = component.toJSON();
- expect(only).toEqual('preschool');
+ expect(container.innerHTML).toEqual('preschool');
});
-it(' condition=false', () => {
- const component = renderer.create(
+it('', () => {
+ const { container } = render(
preschool
primary school
you graduated
);
- const only = component.toJSON();
- expect(only).toEqual('you graduated');
+ expect(container.innerHTML).toEqual('you graduated');
+});
+
+
+it('', () => {
+ render(
+
+ preschool
+
+ );
+ const span = screen.getByTestId('span');
+ expect(span.tagName).toEqual('SPAN');
+ expect(span.innerHTML).toEqual('preschool');
+});
+
+
+it('', () => {
+ render(
+
+ you graduated
+
+ );
+ const elm = screen.getByTestId('elm');
+ expect(elm.tagName).toEqual('P');
+ expect(elm.innerHTML).toEqual('you graduated');
+ expect(elm.title).toEqual('test case');
});