Skip to content

Commit

Permalink
Improved predicate clarity and flexibility
Browse files Browse the repository at this point in the history
  • Loading branch information
brickpop committed Aug 21, 2024
1 parent 346e4a6 commit c325114
Show file tree
Hide file tree
Showing 7 changed files with 1,168 additions and 269 deletions.
115 changes: 81 additions & 34 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,57 +1,104 @@
# If-Then-Else

The missing conditional renderer that the React team didn't ship.
The missing conditional renderer that React forgot to include.

Write clean UI components that can be read as a visual JS function.

## Render a simple child when true
```tsx
<If condition={a && b && c}>
<p>The condition is true</p>
</If>
```
## Rendering a simple child
Using a simple `<If>` block:

## Render a simple child when false
```tsx
<If not={a && b && c}>
<p>The condition is false</p>
<If true={ showGreeting }>
<p>This is a truthy condition</p>
</If>
<If not={ hideGreeting }>
<p>This is a falsy condition</p>
</If>
```

## Render the first child with a matching condition
## Rendering nested if-then-else clauses
Write readable nested conditions as you would in JavaScript.

```tsx
<If condition={a && b && c}>
```jsx
<If none={[ isLoggedIn, isMember, isAdmin ]}>
<Then>
<p>Condition 1 is true</p>
<p>You cannot access this section</p>
</Then>
<ElseIf condition={ d && e }>
<p>Condition 2 is true</p>
<ElseIf val={age} below={18}>
<p>You cannot use this service</p>
</ElseIf>
<ElseIf condition={ f || g }>
<p>Condition 3 is true</p>
<ElseIf not={isLoggedIn}>
<p>Please, log in</p>
</ElseIf>
<Else>
<p>The above conditions are false</p>
<p>Welcome to the service</p>
</Else>
</If>
```

With negated conditions:
```tsx
<If not={a && b && c}>
<Then>
<p>Condition 1 is false</p>
</Then>
<ElseIf condition={ d && e }>
<p>Condition 2 is true</p>
</ElseIf>
<ElseIf not={ f || g }>
<p>Condition 3 is false</p>
</ElseIf>
<Else>
<p>No conditions match</p>
</Else>
## Rendering a child when a comparison matches
Show content based on easy to read value comparisons:

```jsx
<If val={a} is={3}>
<p>a equals 3</p>
</If>
<If val={a} isNot={3}>
<p>a is not equal to 3</p>
</If>
<If val={a} above={3}>
<p>a is greater than 3</p>
</If>
<If val={a} below={3}>
<p>a is lower than 3</p>
</If>
<If val={a} atLeast={3}>
<p>a is greater or equal to 3</p>
</If>
<If val={a} atMost={3}>
<p>a is greater or equal to 3</p>
</If>
```

## Rendering a child given a list of conditions
Show content based on many conditions:

```jsx
<If all={[ isMember, isAdmin ] }>
<p>You are logged as an admin</p>
</If>
<If some={[ isMember, isGuest ]}>
<p>You are logged in</p>
</If>
<If notAll={[ isLoggedIn, isAdmin ]}>
<p>The content is unavailable</p>
</If>
<If none={[ isMember, isManager, isAdmin ]}>
<p>You are not logged in</p>
</If>
```

## Rendering given the length of an array
You can even show content based on the length of an array:

```jsx
<If lengthOf={ members } is={3}>
<p>There are 3 members</p>
</If>
<If lengthOf={ members } isNot={3}>
<p>There aren't 3 members</p>
</If>
<If lengthOf={ members } above={3}>
<p>There are more than 3 members</p>
</If>
<If lengthOf={ members } below={3}>
<p>There are less than 3 members</p>
</If>
<If lengthOf={ members } atLeast={3}>
<p>There are 3 or more members</p>
</If>
<If lengthOf={ members } atMost={3}>
<p>There are 3 or less members</p>
</If>
```
Expand Down
110 changes: 75 additions & 35 deletions example/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,55 +4,95 @@ import * as ReactDOM from 'react-dom';
import { If, Then, ElseIf, Else } from '../.';

const App = () => {
const a = false,
b = true,
c = false,
d = true,
e = true,
f = false,
g = false;
const a = 3;
const showGreeting = true,
hideGreeting = false;
const isLoggedIn = true,
isMember = true,
isAdmin = false,
isGuest = false,
isManager = true;
const age = 24;
const members = ['John', 'Jane', 'Jim'];

return (
<div>
<If condition={a && b && c}>
<p>The condition is true</p>
<h1>Rendering if true or false</h1>
<If true={showGreeting}>
<p>Showing the greeting</p>
</If>

<h1>Render a simple block when false</h1>
<If not={a && b && c}>
<p>The condition is false</p>
<If not={hideGreeting}>
<p>Still showing the greeting</p>
</If>

<h1>Render the first block with a condition that matches</h1>
<If condition={a && b && c}>
<h1>Rendering nested if, then, else if, else clauses</h1>
<If none={[isLoggedIn, isMember, isAdmin]}>
<Then>
<p>Condition 1 is true</p>
<p>You cannot access this section</p>
</Then>
<ElseIf condition={d && e}>
<p>Condition 2 is true</p>
<ElseIf val={age} below={18}>
<p>You cannot use this service</p>
</ElseIf>
<ElseIf condition={f || g}>
<p>Condition 3 is true</p>
<ElseIf not={isLoggedIn}>
<p>Please, log in</p>
</ElseIf>
<Else>
<p>All conditions are false</p>
<p>Welcome to the service</p>
</Else>
</If>

<h1>With negated conditions</h1>
<If not={a && b && c}>
<Then>
<p>Condition 1 is false</p>
</Then>
<ElseIf condition={d && e}>
<p>Condition 2 is true</p>
</ElseIf>
<ElseIf not={f || g}>
<p>Condition 3 is false</p>
</ElseIf>
<Else>
<p>No conditions matched</p>
</Else>
<h1>Rendering by comparing a value</h1>
<If val={a} is={3}>
<p>a equals 3</p>
</If>
<If val={a} isNot={3}>
<p>a is not equal to 3</p>
</If>
<If val={a} above={3}>
<p>a is greater than 3</p>
</If>
<If val={a} below={3}>
<p>a is lower than 3</p>
</If>
<If val={a} atLeast={3}>
<p>a is greater or equal to 3</p>
</If>
<If val={a} atMost={3}>
<p>a is greater or equal to 3</p>
</If>

<h1>Rendering based on many conditions</h1>
<If all={[isMember, isAdmin]}>
<p>You are logged as an admin</p>
</If>
<If some={[isMember, isGuest]}>
<p>You are logged in</p>
</If>
<If notAll={[isLoggedIn, isAdmin]}>
<p>The content is unavailable</p>
</If>
<If none={[isMember, isManager, isAdmin]}>
<p>You are not logged in</p>
</If>

<h1>Rendering given an array's length</h1>
<If lengthOf={members} is={3}>
<p>There are 3 members</p>
</If>
<If lengthOf={members} isNot={3}>
<p>There aren't 3 members</p>
</If>
<If lengthOf={members} above={3}>
<p>There are more than 3 members</p>
</If>
<If lengthOf={members} below={3}>
<p>There are less than 3 members</p>
</If>
<If lengthOf={members} atLeast={3}>
<p>There are 3 or more members</p>
</If>
<If lengthOf={members} atMost={3}>
<p>There are 3 or less members</p>
</If>
</div>
);
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"version": "0.10.1",
"version": "0.12.0",
"license": "MIT",
"main": "dist/index.js",
"typings": "dist/index.d.ts",
Expand All @@ -8,7 +8,7 @@
"src"
],
"engines": {
"node": ">=12"
"node": ">=16"
},
"scripts": {
"start": "tsdx watch",
Expand Down
35 changes: 35 additions & 0 deletions src/helpers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { IfProps } from './types';

export function resolveCondition(props: IfProps): boolean {
if ('true' in props) return !!props.true;
else if ('not' in props) return !props.not;
else if ('val' in props) {
if ('is' in props) return props.val === props.is;
else if ('isNot' in props) return props.val !== props.isNot;
else if ('above' in props) return (props.val as number) > props.above;
else if ('below' in props) return (props.val as number) < props.below;
else if ('atLeast' in props) return (props.val as number) >= props.atLeast;
else if ('atMost' in props) return (props.val as number) <= props.atMost;
} else if ('lengthOf' in props) {
if ('is' in props) return props.lengthOf.length === props.is;
else if ('isNot' in props) return props.lengthOf.length !== props.isNot;
else if ('above' in props) return props.lengthOf.length > props.above;
else if ('below' in props) return props.lengthOf.length < props.below;
else if ('atLeast' in props) return props.lengthOf.length >= props.atLeast;
else if ('atMost' in props) return props.lengthOf.length <= props.atMost;
} else if ('all' in props) {
for (const c of props.all) if (!c) return false;
return true;
} else if ('some' in props) {
for (const c of props.some) if (c) return true;
return false;
} else if ('notAll' in props) {
for (const c of props.notAll) if (!c) return true;
return false;
} else if ('none' in props) {
for (const c of props.none) if (c) return false;
return true;
}

return false;
}
Loading

0 comments on commit c325114

Please sign in to comment.