react-ternary-be-gone 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Conditional.js +195 -0
- package/README.md +639 -0
- package/index.js +5 -0
- package/package.json +27 -0
- package/useConditionalHelpers.js +36 -0
package/Conditional.js
ADDED
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
import React, { useMemo, useEffect } from 'react';
|
|
2
|
+
|
|
3
|
+
const Conditional = ({
|
|
4
|
+
when,
|
|
5
|
+
each,
|
|
6
|
+
children,
|
|
7
|
+
fallback = null,
|
|
8
|
+
empty = null,
|
|
9
|
+
loading = false,
|
|
10
|
+
error = null,
|
|
11
|
+
keyExtractor = (item, index) => index,
|
|
12
|
+
// New features
|
|
13
|
+
filter = null,
|
|
14
|
+
sort = null,
|
|
15
|
+
limit = null,
|
|
16
|
+
reverse = false,
|
|
17
|
+
animate = false,
|
|
18
|
+
wrapper = React.Fragment,
|
|
19
|
+
debug = false,
|
|
20
|
+
onRender = null,
|
|
21
|
+
// Conditional rendering helpers
|
|
22
|
+
gt = null, // greater than
|
|
23
|
+
lt = null, // less than
|
|
24
|
+
eq = null, // equal
|
|
25
|
+
ne = null, // not equal
|
|
26
|
+
includes = null,
|
|
27
|
+
startsWith = null,
|
|
28
|
+
endsWith = null,
|
|
29
|
+
match = null, // regex match
|
|
30
|
+
}) => {
|
|
31
|
+
const hasCondition = when !== undefined;
|
|
32
|
+
const hasIteration = each !== undefined;
|
|
33
|
+
|
|
34
|
+
// Advanced condition evaluation
|
|
35
|
+
const evaluateCondition = useMemo(() => {
|
|
36
|
+
if (when !== undefined) return Boolean(when);
|
|
37
|
+
|
|
38
|
+
// Numerical comparisons
|
|
39
|
+
if (gt !== null && typeof gt === 'object') {
|
|
40
|
+
const { value, target } = gt;
|
|
41
|
+
return value > target;
|
|
42
|
+
}
|
|
43
|
+
if (lt !== null && typeof lt === 'object') {
|
|
44
|
+
const { value, target } = lt;
|
|
45
|
+
return value < target;
|
|
46
|
+
}
|
|
47
|
+
if (eq !== null && typeof eq === 'object') {
|
|
48
|
+
const { value, target } = eq;
|
|
49
|
+
return value === target;
|
|
50
|
+
}
|
|
51
|
+
if (ne !== null && typeof ne === 'object') {
|
|
52
|
+
const { value, target } = ne;
|
|
53
|
+
return value !== target;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// String operations
|
|
57
|
+
if (includes !== null && typeof includes === 'object') {
|
|
58
|
+
const { value, target } = includes;
|
|
59
|
+
return String(value).includes(target);
|
|
60
|
+
}
|
|
61
|
+
if (startsWith !== null && typeof startsWith === 'object') {
|
|
62
|
+
const { value, target } = startsWith;
|
|
63
|
+
return String(value).startsWith(target);
|
|
64
|
+
}
|
|
65
|
+
if (endsWith !== null && typeof endsWith === 'object') {
|
|
66
|
+
const { value, target } = endsWith;
|
|
67
|
+
return String(value).endsWith(target);
|
|
68
|
+
}
|
|
69
|
+
if (match !== null && typeof match === 'object') {
|
|
70
|
+
const { value, pattern } = match;
|
|
71
|
+
return new RegExp(pattern).test(String(value));
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return true;
|
|
75
|
+
}, [when, gt, lt, eq, ne, includes, startsWith, endsWith, match]);
|
|
76
|
+
|
|
77
|
+
// Array processing
|
|
78
|
+
const processedArray = useMemo(() => {
|
|
79
|
+
if (!hasIteration || !Array.isArray(each)) return [];
|
|
80
|
+
|
|
81
|
+
let result = [...each];
|
|
82
|
+
|
|
83
|
+
// Apply filter
|
|
84
|
+
if (filter && typeof filter === 'function') {
|
|
85
|
+
result = result.filter(filter);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Apply sort
|
|
89
|
+
if (sort && typeof sort === 'function') {
|
|
90
|
+
result = result.sort(sort);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Apply reverse
|
|
94
|
+
if (reverse) {
|
|
95
|
+
result = result.reverse();
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Apply limit
|
|
99
|
+
if (limit && typeof limit === 'number') {
|
|
100
|
+
result = result.slice(0, limit);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (debug) {
|
|
104
|
+
console.log('Conditional Debug:', {
|
|
105
|
+
original: each,
|
|
106
|
+
processed: result,
|
|
107
|
+
filter: !!filter,
|
|
108
|
+
sort: !!sort,
|
|
109
|
+
reverse,
|
|
110
|
+
limit
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return result;
|
|
115
|
+
}, [each, filter, sort, reverse, limit, hasIteration, debug]);
|
|
116
|
+
|
|
117
|
+
// Render callback
|
|
118
|
+
useEffect(() => {
|
|
119
|
+
if (onRender && typeof onRender === 'function') {
|
|
120
|
+
onRender({
|
|
121
|
+
condition: evaluateCondition,
|
|
122
|
+
itemCount: processedArray.length,
|
|
123
|
+
hasCondition,
|
|
124
|
+
hasIteration
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
}, [evaluateCondition, processedArray.length, hasCondition, hasIteration, onRender]);
|
|
128
|
+
|
|
129
|
+
// Loading state
|
|
130
|
+
if (loading) {
|
|
131
|
+
return fallback || <div className="conditional-loading">Loading...</div>;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// Error state
|
|
135
|
+
if (error) {
|
|
136
|
+
return <div className="conditional-error">Error: {error}</div>;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// Wrapper component
|
|
140
|
+
const WrapperComponent = wrapper;
|
|
141
|
+
|
|
142
|
+
// Only condition
|
|
143
|
+
if (hasCondition && !hasIteration) {
|
|
144
|
+
return evaluateCondition ? (
|
|
145
|
+
<WrapperComponent>
|
|
146
|
+
{children}
|
|
147
|
+
</WrapperComponent>
|
|
148
|
+
) : fallback;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// Only iteration
|
|
152
|
+
if (!hasCondition && hasIteration) {
|
|
153
|
+
if (processedArray.length === 0) {
|
|
154
|
+
return empty || fallback;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const elements = processedArray.map((item, index) => (
|
|
158
|
+
<React.Fragment key={keyExtractor(item, index)}>
|
|
159
|
+
{typeof children === 'function' ? children(item, index, processedArray) : children}
|
|
160
|
+
</React.Fragment>
|
|
161
|
+
));
|
|
162
|
+
|
|
163
|
+
return animate ? (
|
|
164
|
+
<WrapperComponent className="conditional-animated">
|
|
165
|
+
{elements}
|
|
166
|
+
</WrapperComponent>
|
|
167
|
+
) : (
|
|
168
|
+
<WrapperComponent>
|
|
169
|
+
{elements}
|
|
170
|
+
</WrapperComponent>
|
|
171
|
+
);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// Both condition and iteration
|
|
175
|
+
if (hasCondition && hasIteration) {
|
|
176
|
+
if (!evaluateCondition) return fallback;
|
|
177
|
+
if (processedArray.length === 0) return empty || fallback;
|
|
178
|
+
|
|
179
|
+
const elements = processedArray.map((item, index) => (
|
|
180
|
+
<React.Fragment key={keyExtractor(item, index)}>
|
|
181
|
+
{children(item, index, processedArray)}
|
|
182
|
+
</React.Fragment>
|
|
183
|
+
));
|
|
184
|
+
|
|
185
|
+
return (
|
|
186
|
+
<WrapperComponent>
|
|
187
|
+
{elements}
|
|
188
|
+
</WrapperComponent>
|
|
189
|
+
);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
return <WrapperComponent>{children}</WrapperComponent>;
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
export default Conditional;
|
package/README.md
ADDED
|
@@ -0,0 +1,639 @@
|
|
|
1
|
+
```markdown
|
|
2
|
+
# React Conditional Component
|
|
3
|
+
|
|
4
|
+
A React component designed to simplify conditional rendering and list iteration, providing a more readable and maintainable alternative to ternary operators and verbose conditional logic.
|
|
5
|
+
|
|
6
|
+
## Installation
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
npm install react-ternary-be-gone
|
|
10
|
+
# or
|
|
11
|
+
yarn add react-ternary-be-gone
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Usage
|
|
15
|
+
|
|
16
|
+
```javascript
|
|
17
|
+
import Conditional from 'react-ternary-be-gone';
|
|
18
|
+
|
|
19
|
+
// Basic conditional rendering
|
|
20
|
+
<Conditional when={true}>
|
|
21
|
+
<p>This will be rendered.</p>
|
|
22
|
+
</Conditional>
|
|
23
|
+
|
|
24
|
+
<Conditional when={55>33}>
|
|
25
|
+
<p>55 is bigger than 33</p>
|
|
26
|
+
</Conditional>
|
|
27
|
+
|
|
28
|
+
<Conditional when={false} fallback={<p>This is the fallback.</p>}>
|
|
29
|
+
<p>This will not be rendered.</p>
|
|
30
|
+
</Conditional>
|
|
31
|
+
|
|
32
|
+
// Iterating over a list
|
|
33
|
+
const items = ['Item 1', 'Item 2', 'Item 3'];
|
|
34
|
+
|
|
35
|
+
<Conditional each={items}>
|
|
36
|
+
{(item, index) => <p key={index}>{item}</p>}
|
|
37
|
+
</Conditional>
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Props
|
|
41
|
+
|
|
42
|
+
### `when`
|
|
43
|
+
|
|
44
|
+
A boolean value that determines whether the children should be rendered.
|
|
45
|
+
|
|
46
|
+
**Type:** `boolean`
|
|
47
|
+
|
|
48
|
+
**Example:**
|
|
49
|
+
|
|
50
|
+
```javascript
|
|
51
|
+
<Conditional when={isLoggedIn}>
|
|
52
|
+
<p>Welcome, user!</p>
|
|
53
|
+
</Conditional>
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### `each`
|
|
57
|
+
|
|
58
|
+
An array to iterate over and render children for each item.
|
|
59
|
+
|
|
60
|
+
**Type:** `array`
|
|
61
|
+
|
|
62
|
+
**Example:**
|
|
63
|
+
|
|
64
|
+
```javascript
|
|
65
|
+
const data = [{ id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }];
|
|
66
|
+
|
|
67
|
+
<Conditional each={data}>
|
|
68
|
+
{(item, index) => <p key={item.id}>{item.name}</p>}
|
|
69
|
+
</Conditional>
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### `children`
|
|
73
|
+
|
|
74
|
+
The content to be rendered based on the `when` condition or for each item in the `each` array. Can be a React node or a render prop function.
|
|
75
|
+
|
|
76
|
+
**Type:** `ReactNode | (item: any, index: number, array: any[]) => ReactNode`
|
|
77
|
+
|
|
78
|
+
**Example (ReactNode):**
|
|
79
|
+
|
|
80
|
+
```javascript
|
|
81
|
+
<Conditional when={true}>
|
|
82
|
+
<p>This is a simple paragraph.</p>
|
|
83
|
+
</Conditional>
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
**Example (Render Prop):**
|
|
87
|
+
|
|
88
|
+
```javascript
|
|
89
|
+
const items = ['A', 'B', 'C'];
|
|
90
|
+
|
|
91
|
+
<Conditional each={items}>
|
|
92
|
+
{(item, index) => <p key={index}>Item {index + 1}: {item}</p>}
|
|
93
|
+
</Conditional>
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### `fallback`
|
|
97
|
+
|
|
98
|
+
The content to be rendered if the `when` condition is false or the `each` array is empty.
|
|
99
|
+
|
|
100
|
+
**Type:** `ReactNode`
|
|
101
|
+
|
|
102
|
+
**Example:**
|
|
103
|
+
|
|
104
|
+
```javascript
|
|
105
|
+
<Conditional when={false} fallback={<p>Not logged in.</p>}>
|
|
106
|
+
<p>Welcome!</p>
|
|
107
|
+
</Conditional>
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### `empty`
|
|
111
|
+
|
|
112
|
+
The content to be rendered if the `each` array is empty. Overrides `fallback` when iterating.
|
|
113
|
+
|
|
114
|
+
**Type:** `ReactNode`
|
|
115
|
+
|
|
116
|
+
**Example:**
|
|
117
|
+
|
|
118
|
+
```javascript
|
|
119
|
+
const emptyList = [];
|
|
120
|
+
|
|
121
|
+
<Conditional each={emptyList} empty={<p>No items found.</p>}>
|
|
122
|
+
{(item) => <p>{item}</p>}
|
|
123
|
+
</Conditional>
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### `loading`
|
|
127
|
+
|
|
128
|
+
A boolean value indicating whether the component is in a loading state. If true, the `fallback` prop (or a default loading message) will be rendered.
|
|
129
|
+
|
|
130
|
+
**Type:** `boolean`
|
|
131
|
+
|
|
132
|
+
**Example:**
|
|
133
|
+
|
|
134
|
+
```javascript
|
|
135
|
+
<Conditional loading={isLoading} fallback={<p>Loading data...</p>}>
|
|
136
|
+
<p>Data loaded!</p>
|
|
137
|
+
</Conditional>
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### `error`
|
|
141
|
+
|
|
142
|
+
An error message to be displayed if an error occurs.
|
|
143
|
+
|
|
144
|
+
**Type:** `string`
|
|
145
|
+
|
|
146
|
+
**Example:**
|
|
147
|
+
|
|
148
|
+
```javascript
|
|
149
|
+
<Conditional error={errorMessage}>
|
|
150
|
+
<p>Content.</p>
|
|
151
|
+
</Conditional>
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### `keyExtractor`
|
|
155
|
+
|
|
156
|
+
A function to extract a unique key for each item when iterating over the `each` array.
|
|
157
|
+
|
|
158
|
+
**Type:** `(item: any, index: number) => string | number`
|
|
159
|
+
|
|
160
|
+
**Default:** `(item, index) => index`
|
|
161
|
+
|
|
162
|
+
**Example:**
|
|
163
|
+
|
|
164
|
+
```javascript
|
|
165
|
+
const users = [{ id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }];
|
|
166
|
+
|
|
167
|
+
<Conditional each={users} keyExtractor={(user) => user.id}>
|
|
168
|
+
{(user) => <p key={user.id}>{user.name}</p>}
|
|
169
|
+
</Conditional>
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
### `filter`
|
|
173
|
+
|
|
174
|
+
A function to filter the `each` array before rendering.
|
|
175
|
+
|
|
176
|
+
**Type:** `(item: any) => boolean`
|
|
177
|
+
|
|
178
|
+
**Example:**
|
|
179
|
+
|
|
180
|
+
```javascript
|
|
181
|
+
const numbers = [1, 2, 3, 4, 5, 6];
|
|
182
|
+
|
|
183
|
+
<Conditional each={numbers} filter={(num) => num % 2 === 0}>
|
|
184
|
+
{(num) => <p>{num}</p>} {/* Renders 2, 4, 6 */}
|
|
185
|
+
</Conditional>
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
### `sort`
|
|
189
|
+
|
|
190
|
+
A function to sort the `each` array before rendering.
|
|
191
|
+
|
|
192
|
+
**Type:** `(a: any, b: any) => number`
|
|
193
|
+
|
|
194
|
+
**Example:**
|
|
195
|
+
|
|
196
|
+
```javascript
|
|
197
|
+
const items = [{ name: 'Charlie' }, { name: 'Alice' }, { name: 'Bob' }];
|
|
198
|
+
|
|
199
|
+
<Conditional each={items} sort={(a, b) => a.name.localeCompare(b.name)}>
|
|
200
|
+
{(item) => <p>{item.name}</p>} {/* Renders Alice, Bob, Charlie */}
|
|
201
|
+
</Conditional>
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
### `limit`
|
|
205
|
+
|
|
206
|
+
A number to limit the number of items rendered from the `each` array.
|
|
207
|
+
|
|
208
|
+
**Type:** `number`
|
|
209
|
+
|
|
210
|
+
**Example:**
|
|
211
|
+
|
|
212
|
+
```javascript
|
|
213
|
+
const items = ['A', 'B', 'C', 'D', 'E'];
|
|
214
|
+
|
|
215
|
+
<Conditional each={items} limit={3}>
|
|
216
|
+
{(item) => <p>{item}</p>} {/* Renders A, B, C */}
|
|
217
|
+
</Conditional>
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
### `reverse`
|
|
221
|
+
|
|
222
|
+
A boolean value indicating whether to reverse the order of the `each` array before rendering.
|
|
223
|
+
|
|
224
|
+
**Type:** `boolean`
|
|
225
|
+
|
|
226
|
+
**Example:**
|
|
227
|
+
|
|
228
|
+
```javascript
|
|
229
|
+
const items = ['A', 'B', 'C'];
|
|
230
|
+
|
|
231
|
+
<Conditional each={items} reverse>
|
|
232
|
+
{(item) => <p>{item}</p>} {/* Renders C, B, A */}
|
|
233
|
+
</Conditional>
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
### `animate`
|
|
237
|
+
|
|
238
|
+
A boolean value indicating whether to add a CSS class for animation purposes. You'll need to define the `.conditional-animated` CSS class in your project.
|
|
239
|
+
|
|
240
|
+
**Type:** `boolean`
|
|
241
|
+
|
|
242
|
+
**Example:**
|
|
243
|
+
|
|
244
|
+
```javascript
|
|
245
|
+
<Conditional each={items} animate>
|
|
246
|
+
{(item) => <p>{item}</p>}
|
|
247
|
+
</Conditional>
|
|
248
|
+
|
|
249
|
+
/* CSS (Example) */
|
|
250
|
+
.conditional-animated {
|
|
251
|
+
/* Your animation styles here */
|
|
252
|
+
transition: all 0.3s ease-in-out;
|
|
253
|
+
}
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
### `wrapper`
|
|
257
|
+
|
|
258
|
+
A React component or element to wrap the rendered children. Defaults to `React.Fragment`.
|
|
259
|
+
|
|
260
|
+
**Type:** `React.ComponentType`
|
|
261
|
+
|
|
262
|
+
**Example:**
|
|
263
|
+
|
|
264
|
+
```javascript
|
|
265
|
+
<Conditional each={items} wrapper="ul">
|
|
266
|
+
{(item) => <li key={item}>{item}</li>}
|
|
267
|
+
</Conditional>
|
|
268
|
+
|
|
269
|
+
// Or with a custom component:
|
|
270
|
+
const MyWrapper = ({ children }) => <div className="my-wrapper">{children}</div>;
|
|
271
|
+
|
|
272
|
+
<Conditional each={items} wrapper={MyWrapper}>
|
|
273
|
+
{(item) => <p>{item}</p>}
|
|
274
|
+
</Conditional>
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
### `debug`
|
|
278
|
+
|
|
279
|
+
A boolean value that, when true, logs debugging information to the console, including the original and processed arrays.
|
|
280
|
+
|
|
281
|
+
**Type:** `boolean`
|
|
282
|
+
|
|
283
|
+
**Example:**
|
|
284
|
+
|
|
285
|
+
```javascript
|
|
286
|
+
<Conditional each={items} debug>
|
|
287
|
+
{(item) => <p>{item}</p>}
|
|
288
|
+
</Conditional>
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
### `onRender`
|
|
292
|
+
|
|
293
|
+
A callback function that is called after the component renders. Provides information about the condition, item count, and whether the component is rendering conditionally or iterating.
|
|
294
|
+
|
|
295
|
+
**Type:** `(data: { condition: boolean, itemCount: number, hasCondition: boolean, hasIteration: boolean }) => void`
|
|
296
|
+
|
|
297
|
+
**Example:**
|
|
298
|
+
|
|
299
|
+
```javascript
|
|
300
|
+
<Conditional
|
|
301
|
+
each={items}
|
|
302
|
+
onRender={({ itemCount }) => console.log(`Rendered ${itemCount} items`)}
|
|
303
|
+
>
|
|
304
|
+
{(item) => <p>{item}</p>}
|
|
305
|
+
</Conditional>
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
### Advanced Condition Evaluation Props
|
|
309
|
+
|
|
310
|
+
These props allow for more complex conditional checks without needing to define a separate `when` prop. Only one of these props should be used at a time.
|
|
311
|
+
|
|
312
|
+
#### `gt` (Greater Than)
|
|
313
|
+
|
|
314
|
+
Renders children if `value` is greater than `target`.
|
|
315
|
+
|
|
316
|
+
**Type:** `{ value: number, target: number }`
|
|
317
|
+
|
|
318
|
+
**Example:**
|
|
319
|
+
|
|
320
|
+
```javascript
|
|
321
|
+
<Conditional gt={{ value: 10, target: 5 }}>
|
|
322
|
+
<p>10 is greater than 5</p>
|
|
323
|
+
</Conditional>
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
#### `lt` (Less Than)
|
|
327
|
+
|
|
328
|
+
Renders children if `value` is less than `target`.
|
|
329
|
+
|
|
330
|
+
**Type:** `{ value: number, target: number }`
|
|
331
|
+
|
|
332
|
+
**Example:**
|
|
333
|
+
|
|
334
|
+
```javascript
|
|
335
|
+
<Conditional lt={{ value: 3, target: 7 }}>
|
|
336
|
+
<p>3 is less than 7</p>
|
|
337
|
+
</Conditional>
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
#### `eq` (Equal)
|
|
341
|
+
|
|
342
|
+
Renders children if `value` is equal to `target`.
|
|
343
|
+
|
|
344
|
+
**Type:** `{ value: any, target: any }`
|
|
345
|
+
|
|
346
|
+
**Example:**
|
|
347
|
+
|
|
348
|
+
```javascript
|
|
349
|
+
<Conditional eq={{ value: 'hello', target: 'hello' }}>
|
|
350
|
+
<p>The strings are equal</p>
|
|
351
|
+
</Conditional>
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
#### `ne` (Not Equal)
|
|
355
|
+
|
|
356
|
+
Renders children if `value` is not equal to `target`.
|
|
357
|
+
|
|
358
|
+
**Type:** `{ value: any, target: any }`
|
|
359
|
+
|
|
360
|
+
**Example:**
|
|
361
|
+
|
|
362
|
+
```javascript
|
|
363
|
+
<Conditional ne={{ value: 1, target: 2 }}>
|
|
364
|
+
<p>1 is not equal to 2</p>
|
|
365
|
+
</Conditional>
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
#### `includes`
|
|
369
|
+
|
|
370
|
+
Renders children if `value` (converted to a string) includes `target`.
|
|
371
|
+
|
|
372
|
+
**Type:** `{ value: string, target: string }`
|
|
373
|
+
|
|
374
|
+
**Example:**
|
|
375
|
+
|
|
376
|
+
```javascript
|
|
377
|
+
<Conditional includes={{ value: 'hello world', target: 'world' }}>
|
|
378
|
+
<p>The string includes "world"</p>
|
|
379
|
+
</Conditional>
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
#### `startsWith`
|
|
383
|
+
|
|
384
|
+
Renders children if `value` (converted to a string) starts with `target`.
|
|
385
|
+
|
|
386
|
+
**Type:** `{ value: string, target: string }`
|
|
387
|
+
|
|
388
|
+
**Example:**
|
|
389
|
+
|
|
390
|
+
```javascript
|
|
391
|
+
<Conditional startsWith={{ value: 'hello world', target: 'hello' }}>
|
|
392
|
+
<p>The string starts with "hello"</p>
|
|
393
|
+
</Conditional>
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
#### `endsWith`
|
|
397
|
+
|
|
398
|
+
Renders children if `value` (converted to a string) ends with `target`.
|
|
399
|
+
|
|
400
|
+
**Type:** `{ value: string, target: string }`
|
|
401
|
+
|
|
402
|
+
**Example:**
|
|
403
|
+
|
|
404
|
+
```javascript
|
|
405
|
+
<Conditional endsWith={{ value: 'hello world', target: 'world' }}>
|
|
406
|
+
<p>The string ends with "world"</p>
|
|
407
|
+
</Conditional>
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
#### `match`
|
|
411
|
+
|
|
412
|
+
Renders children if `value` (converted to a string) matches the provided regular expression `pattern`.
|
|
413
|
+
|
|
414
|
+
**Type:** `{ value: string, pattern: string }`
|
|
415
|
+
|
|
416
|
+
**Example:**
|
|
417
|
+
|
|
418
|
+
```javascript
|
|
419
|
+
<Conditional match={{ value: 'hello 123', pattern: '\\d+' }}>
|
|
420
|
+
<p>The string contains a number</p>
|
|
421
|
+
</Conditional>
|
|
422
|
+
```
|
|
423
|
+
|
|
424
|
+
---
|
|
425
|
+
|
|
426
|
+
## `useConditionalHelpers` Hook
|
|
427
|
+
|
|
428
|
+
A hook providing helper functions to simplify common conditional logic and array manipulation tasks.
|
|
429
|
+
|
|
430
|
+
### Usage
|
|
431
|
+
|
|
432
|
+
```javascript
|
|
433
|
+
import { useConditionalHelpers } from 'react-ternary-be-gone';
|
|
434
|
+
|
|
435
|
+
const MyComponent = () => {
|
|
436
|
+
const { isEmpty, isNotEmpty, hasLength, isEven, isOdd, sortBy, filterBy, unique } = useConditionalHelpers();
|
|
437
|
+
const myArray = [1, 2, 3];
|
|
438
|
+
|
|
439
|
+
return (
|
|
440
|
+
<>
|
|
441
|
+
<Conditional {...isEmpty(myArray)}>
|
|
442
|
+
<p>Array is empty</p>
|
|
443
|
+
</Conditional>
|
|
444
|
+
<Conditional {...isNotEmpty(myArray)}>
|
|
445
|
+
<p>Array is not empty</p>
|
|
446
|
+
</Conditional>
|
|
447
|
+
</>
|
|
448
|
+
);
|
|
449
|
+
};
|
|
450
|
+
```
|
|
451
|
+
|
|
452
|
+
### Helper Functions
|
|
453
|
+
|
|
454
|
+
#### `isEmpty(array)`
|
|
455
|
+
|
|
456
|
+
Checks if an array is empty or null/undefined. Returns an object suitable for the `when` prop.
|
|
457
|
+
|
|
458
|
+
**Parameters:**
|
|
459
|
+
|
|
460
|
+
* `array`: The array to check.
|
|
461
|
+
|
|
462
|
+
**Returns:** `{ when: boolean }`
|
|
463
|
+
|
|
464
|
+
**Example:**
|
|
465
|
+
|
|
466
|
+
```javascript
|
|
467
|
+
const { isEmpty } = useConditionalHelpers();
|
|
468
|
+
const emptyArray = [];
|
|
469
|
+
|
|
470
|
+
<Conditional {...isEmpty(emptyArray)}>
|
|
471
|
+
<p>This array is empty.</p>
|
|
472
|
+
</Conditional>
|
|
473
|
+
```
|
|
474
|
+
|
|
475
|
+
#### `isNotEmpty(array)`
|
|
476
|
+
|
|
477
|
+
Checks if an array is not empty. Returns an object suitable for the `when` prop.
|
|
478
|
+
|
|
479
|
+
**Parameters:**
|
|
480
|
+
|
|
481
|
+
* `array`: The array to check.
|
|
482
|
+
|
|
483
|
+
**Returns:** `{ when: boolean }`
|
|
484
|
+
|
|
485
|
+
**Example:**
|
|
486
|
+
|
|
487
|
+
```javascript
|
|
488
|
+
const { isNotEmpty } = useConditionalHelpers();
|
|
489
|
+
const myArray = [1, 2, 3];
|
|
490
|
+
|
|
491
|
+
<Conditional {...isNotEmpty(myArray)}>
|
|
492
|
+
<p>This array is not empty.</p>
|
|
493
|
+
</Conditional>
|
|
494
|
+
```
|
|
495
|
+
|
|
496
|
+
#### `hasLength(array, length)`
|
|
497
|
+
|
|
498
|
+
Checks if an array has a specific length. Returns an object suitable for the `when` prop.
|
|
499
|
+
|
|
500
|
+
**Parameters:**
|
|
501
|
+
|
|
502
|
+
* `array`: The array to check.
|
|
503
|
+
* `length`: The expected length.
|
|
504
|
+
|
|
505
|
+
**Returns:** `{ when: boolean }`
|
|
506
|
+
|
|
507
|
+
**Example:**
|
|
508
|
+
|
|
509
|
+
```javascript
|
|
510
|
+
const { hasLength } = useConditionalHelpers();
|
|
511
|
+
const myArray = [1, 2, 3];
|
|
512
|
+
|
|
513
|
+
<Conditional {...hasLength(myArray, 3)}>
|
|
514
|
+
<p>This array has a length of 3.</p>
|
|
515
|
+
</Conditional>
|
|
516
|
+
```
|
|
517
|
+
|
|
518
|
+
#### `isEven(num)`
|
|
519
|
+
|
|
520
|
+
Checks if a number is even. Returns an object suitable for the `when` prop.
|
|
521
|
+
|
|
522
|
+
**Parameters:**
|
|
523
|
+
|
|
524
|
+
* `num`: The number to check.
|
|
525
|
+
|
|
526
|
+
**Returns:** `{ when: boolean }`
|
|
527
|
+
|
|
528
|
+
**Example:**
|
|
529
|
+
|
|
530
|
+
```javascript
|
|
531
|
+
const { isEven } = useConditionalHelpers();
|
|
532
|
+
|
|
533
|
+
<Conditional {...isEven(4)}>
|
|
534
|
+
<p>4 is an even number.</p>
|
|
535
|
+
</Conditional>
|
|
536
|
+
```
|
|
537
|
+
|
|
538
|
+
#### `isOdd(num)`
|
|
539
|
+
|
|
540
|
+
Checks if a number is odd. Returns an object suitable for the `when` prop.
|
|
541
|
+
|
|
542
|
+
**Parameters:**
|
|
543
|
+
|
|
544
|
+
* `num`: The number to check.
|
|
545
|
+
|
|
546
|
+
**Returns:** `{ when: boolean }`
|
|
547
|
+
|
|
548
|
+
**Example:**
|
|
549
|
+
|
|
550
|
+
```javascript
|
|
551
|
+
const { isOdd } = useConditionalHelpers();
|
|
552
|
+
|
|
553
|
+
<Conditional {...isOdd(5)}>
|
|
554
|
+
<p>5 is an odd number.</p>
|
|
555
|
+
</Conditional>
|
|
556
|
+
```
|
|
557
|
+
|
|
558
|
+
#### `sortBy(field, order = 'asc')`
|
|
559
|
+
|
|
560
|
+
Returns a sort function to sort an array of objects by a specific field. Suitable for the `sort` prop.
|
|
561
|
+
|
|
562
|
+
**Parameters:**
|
|
563
|
+
|
|
564
|
+
* `field`: The field to sort by.
|
|
565
|
+
* `order`: The sort order ('asc' or 'desc'). Defaults to 'asc'.
|
|
566
|
+
|
|
567
|
+
**Returns:** `(a: any, b: any) => number`
|
|
568
|
+
|
|
569
|
+
**Example:**
|
|
570
|
+
|
|
571
|
+
```javascript
|
|
572
|
+
const { sortBy } = useConditionalHelpers();
|
|
573
|
+
const items = [{ name: 'Charlie' }, { name: 'Alice' }, { name: 'Bob' }];
|
|
574
|
+
|
|
575
|
+
<Conditional each={items} sort={sortBy('name')}>
|
|
576
|
+
{(item) => <p>{item.name}</p>} {/* Renders Alice, Bob, Charlie */}
|
|
577
|
+
</Conditional>
|
|
578
|
+
|
|
579
|
+
<Conditional each={items} sort={sortBy('name', 'desc')}>
|
|
580
|
+
{(item) => <p>{item.name}</p>} {/* Renders Charlie, Bob, Alice */}
|
|
581
|
+
</Conditional>
|
|
582
|
+
```
|
|
583
|
+
|
|
584
|
+
#### `filterBy(field, value)`
|
|
585
|
+
|
|
586
|
+
Returns a filter function to filter an array of objects by a specific field and value. Suitable for the `filter` prop.
|
|
587
|
+
|
|
588
|
+
**Parameters:**
|
|
589
|
+
|
|
590
|
+
* `field`: The field to filter by.
|
|
591
|
+
* `value`: The value to filter for.
|
|
592
|
+
|
|
593
|
+
**Returns:** `(item: any) => boolean`
|
|
594
|
+
|
|
595
|
+
**Example:**
|
|
596
|
+
|
|
597
|
+
```javascript
|
|
598
|
+
const { filterBy } = useConditionalHelpers();
|
|
599
|
+
const users = [{ id: 1, name: 'Alice', active: true }, { id: 2, name: 'Bob', active: false }];
|
|
600
|
+
|
|
601
|
+
<Conditional each={users} filter={filterBy('active', true)}>
|
|
602
|
+
{(user) => <p>{user.name}</p>} {/* Renders Alice */}
|
|
603
|
+
</Conditional>
|
|
604
|
+
```
|
|
605
|
+
|
|
606
|
+
#### `unique(array, key)`
|
|
607
|
+
|
|
608
|
+
Returns a new array with only unique items, based on a key or a key extractor function.
|
|
609
|
+
|
|
610
|
+
**Parameters:**
|
|
611
|
+
|
|
612
|
+
* `array`: The array to process.
|
|
613
|
+
* `key`: The key to use for uniqueness (string) or a function that extracts the key (function).
|
|
614
|
+
|
|
615
|
+
**Returns:** `any[]`
|
|
616
|
+
|
|
617
|
+
**Example:**
|
|
618
|
+
|
|
619
|
+
```javascript
|
|
620
|
+
const { unique } = useConditionalHelpers();
|
|
621
|
+
const items = [{ id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }, { id: 1, name: 'Charlie' }];
|
|
622
|
+
|
|
623
|
+
const uniqueItems = unique(items, 'id'); // Removes the duplicate ID 1
|
|
624
|
+
// uniqueItems will be: [{ id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }]
|
|
625
|
+
|
|
626
|
+
const items2 = [{name: "Apple", color: "red"}, {name: "Banana", color: "yellow"}, {name: "Cherry", color: "red"}];
|
|
627
|
+
const uniqueItems2 = unique(items2, (item) => item.color);
|
|
628
|
+
// uniqueItems2 will be: [{name: "Apple", color: "red"}, {name: "Banana", color: "yellow"}]
|
|
629
|
+
```
|
|
630
|
+
|
|
631
|
+
---
|
|
632
|
+
|
|
633
|
+
## Contributing
|
|
634
|
+
|
|
635
|
+
Contributions are welcome! Please fork the repository and submit a pull request.
|
|
636
|
+
|
|
637
|
+
## License
|
|
638
|
+
|
|
639
|
+
MIT
|
package/index.js
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "react-ternary-be-gone",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "A React component designed to simplify conditional rendering and list iteration, providing a more readable and maintainable alternative to ternary operators and verbose conditional logic.",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
8
|
+
},
|
|
9
|
+
"peerDependencies": {
|
|
10
|
+
"react": ">=16.8.0"
|
|
11
|
+
},
|
|
12
|
+
"repository": {
|
|
13
|
+
"type": "git",
|
|
14
|
+
"url": "git+https://github.com/sundowatch/react-ternary-be-gone.git"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [
|
|
17
|
+
"react",
|
|
18
|
+
"no",
|
|
19
|
+
"ternary"
|
|
20
|
+
],
|
|
21
|
+
"author": "Ibrahim Sanduvaç",
|
|
22
|
+
"license": "MIT",
|
|
23
|
+
"bugs": {
|
|
24
|
+
"url": "https://github.com/sundowatch/react-ternary-be-gone/issues"
|
|
25
|
+
},
|
|
26
|
+
"homepage": "https://github.com/sundowatch/react-ternary-be-gone#readme"
|
|
27
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { useMemo } from 'react';
|
|
2
|
+
|
|
3
|
+
export const useConditionalHelpers = () => {
|
|
4
|
+
return useMemo(() => ({
|
|
5
|
+
// Quick condition helpers
|
|
6
|
+
isEmpty: (array) => ({ when: !array || array.length === 0 }),
|
|
7
|
+
isNotEmpty: (array) => ({ when: array && array.length > 0 }),
|
|
8
|
+
hasLength: (array, length) => ({ when: array && array.length === length }),
|
|
9
|
+
isEven: (num) => ({ when: num % 2 === 0 }),
|
|
10
|
+
isOdd: (num) => ({ when: num % 2 !== 0 }),
|
|
11
|
+
|
|
12
|
+
// Array processing helpers
|
|
13
|
+
sortBy: (field, order = 'asc') => (a, b) => {
|
|
14
|
+
const aValue = a[field];
|
|
15
|
+
const bValue = b[field];
|
|
16
|
+
|
|
17
|
+
if (aValue < bValue) {
|
|
18
|
+
return order === 'asc' ? -1 : 1;
|
|
19
|
+
}
|
|
20
|
+
if (aValue > bValue) {
|
|
21
|
+
return order === 'asc' ? 1 : -1;
|
|
22
|
+
}
|
|
23
|
+
return 0;
|
|
24
|
+
},
|
|
25
|
+
filterBy: (field, value) => (item) => item[field] === value,
|
|
26
|
+
unique: (array, key) => {
|
|
27
|
+
const seen = new Set();
|
|
28
|
+
return array.filter(item => {
|
|
29
|
+
const keyValue = typeof key === 'function' ? key(item) : item[key];
|
|
30
|
+
const isNew = !seen.has(keyValue);
|
|
31
|
+
seen.add(keyValue);
|
|
32
|
+
return isNew;
|
|
33
|
+
});
|
|
34
|
+
},
|
|
35
|
+
}), []);
|
|
36
|
+
};
|