Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit fedb180

Browse files
authored
chore: Change usage of ChooseOne (no final condition) (#4158)
* Change contract of Cond: no condition on default case * Handle no children case * Format
1 parent 21e6bea commit fedb180

File tree

3 files changed

+36
-13
lines changed

3 files changed

+36
-13
lines changed

site/src/components/Conditionals/ChooseOne.stories.tsx

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,26 +11,36 @@ export const FirstIsTrue: Story = () => (
1111
<ChooseOne>
1212
<Cond condition>The first one shows.</Cond>
1313
<Cond condition={false}>The second one does not show.</Cond>
14+
<Cond>The default does not show.</Cond>
1415
</ChooseOne>
1516
)
1617

1718
export const SecondIsTrue: Story = () => (
1819
<ChooseOne>
1920
<Cond condition={false}>The first one does not show.</Cond>
2021
<Cond condition>The second one shows.</Cond>
22+
<Cond>The default does not show.</Cond>
2123
</ChooseOne>
2224
)
2325

2426
export const AllAreTrue: Story = () => (
2527
<ChooseOne>
2628
<Cond condition>Only the first one shows.</Cond>
2729
<Cond condition>The second one does not show.</Cond>
30+
<Cond>The default does not show.</Cond>
2831
</ChooseOne>
2932
)
3033

3134
export const NoneAreTrue: Story = () => (
3235
<ChooseOne>
3336
<Cond condition={false}>The first one does not show.</Cond>
34-
<Cond condition={false}>The second shows because it is the fallback.</Cond>
37+
<Cond condition={false}>The second one does not show.</Cond>
38+
<Cond>The default shows.</Cond>
39+
</ChooseOne>
40+
)
41+
42+
export const OneCond: Story = () => (
43+
<ChooseOne>
44+
<Cond>An only child renders.</Cond>
3545
</ChooseOne>
3646
)
Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,42 @@
11
import { Children, PropsWithChildren } from "react"
22

33
export interface CondProps {
4-
condition: boolean
4+
condition?: boolean
55
}
66

77
/**
88
* Wrapper component that attaches a condition to a child component so that ChooseOne can
9-
* determine which child to render. The last Cond in a ChooseOne is the fallback case; set
10-
* its `condition` to `true` to avoid confusion.
11-
* @param condition boolean expression indicating whether the child should be rendered
9+
* determine which child to render. The last Cond in a ChooseOne is the fallback case and
10+
* should not have a condition.
11+
* @param condition boolean expression indicating whether the child should be rendered, or undefined
1212
* @returns child. Note that Cond alone does not enforce the condition; it should be used inside ChooseOne.
1313
*/
14-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
15-
export const Cond = ({ children, condition }: PropsWithChildren<CondProps>): JSX.Element => {
14+
export const Cond = ({ children }: PropsWithChildren<CondProps>): JSX.Element => {
1615
return <>{children}</>
1716
}
1817

1918
/**
2019
* Wrapper component for rendering exactly one of its children. Wrap each child in Cond to associate it
2120
* with a condition under which it should be rendered. If no conditions are met, the final child
2221
* will be rendered.
23-
* @returns one of its children
22+
* @returns one of its children, or null if there are no children
23+
* @throws an error if its last child has a condition prop, or any non-final children do not have a condition prop
2424
*/
25-
export const ChooseOne = ({ children }: PropsWithChildren): JSX.Element => {
25+
export const ChooseOne = ({ children }: PropsWithChildren): JSX.Element | null => {
2626
const childArray = Children.toArray(children) as JSX.Element[]
27-
const chosen = childArray.find((child) => child.props.condition)
28-
return chosen ?? childArray[childArray.length - 1]
27+
if (childArray.length === 0) {
28+
return null
29+
}
30+
const conditionedOptions = childArray.slice(0, childArray.length - 1)
31+
const defaultCase = childArray[childArray.length - 1]
32+
if (defaultCase.props.condition !== undefined) {
33+
throw new Error(
34+
"The last Cond in a ChooseOne was given a condition prop, but it is the default case.",
35+
)
36+
}
37+
if (conditionedOptions.some((cond) => cond.props.condition === undefined)) {
38+
throw new Error("A non-final Cond in a ChooseOne does not have a condition prop.")
39+
}
40+
const chosen = conditionedOptions.find((child) => child.props.condition)
41+
return chosen ?? defaultCase
2942
}

site/src/pages/TemplatesPage/TemplatesPageView.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ export const TemplatesPageView: FC<React.PropsWithChildren<TemplatesPageViewProp
139139
defaultMessage={t("errors.getTemplatesError")}
140140
/>
141141
</Cond>
142-
<Cond condition>
142+
<Cond>
143143
<TableContainer>
144144
<Table>
145145
<TableHead>
@@ -173,7 +173,7 @@ export const TemplatesPageView: FC<React.PropsWithChildren<TemplatesPageViewProp
173173
</TableCell>
174174
</TableRow>
175175
</Cond>
176-
<Cond condition>
176+
<Cond>
177177
{props.templates?.map((template) => {
178178
const templatePageLink = `/templates/${template.name}`
179179
const hasIcon = template.icon && template.icon !== ""

0 commit comments

Comments
 (0)