0
# React Compatibility Utilities
1
2
Additional utilities for React compatibility, including children manipulation, element validation, and element cloning functions. These utilities are provided through the compatibility layer and external packages to ensure full React API compatibility.
3
4
## Capabilities
5
6
### Children Utilities
7
8
Comprehensive utilities for working with component children, similar to React.Children.
9
10
```javascript { .api }
11
/**
12
* Children utility object with methods for manipulating component children
13
*/
14
const Children: {
15
/**
16
* Maps over children and returns a new array
17
* @param children - Component children to map over
18
* @param fn - Function to apply to each child
19
* @param ctx - Optional context for the function call
20
* @returns Array of mapped children
21
*/
22
map(children: RaxNode, fn: (child: RaxNode, index: number) => RaxNode, ctx?: any): RaxNode[];
23
24
/**
25
* Iterates over children without returning anything
26
* @param children - Component children to iterate over
27
* @param fn - Function to apply to each child
28
* @param ctx - Optional context for the function call
29
*/
30
forEach(children: RaxNode, fn: (child: RaxNode, index: number) => void, ctx?: any): void;
31
32
/**
33
* Counts the number of children
34
* @param children - Component children to count
35
* @returns Number of children
36
*/
37
count(children: RaxNode): number;
38
39
/**
40
* Ensures children contains only one child and returns it
41
* @param children - Component children (must be exactly one)
42
* @returns The single child element
43
* @throws Error if children count is not exactly 1
44
*/
45
only(children: RaxNode): RaxElement;
46
47
/**
48
* Converts children to a flat array
49
* @param children - Component children to convert
50
* @returns Array representation of children
51
*/
52
toArray(children: RaxNode): RaxNode[];
53
};
54
```
55
56
**Usage Examples:**
57
58
```javascript
59
import { createElement, Children } from 'rax/src/compat';
60
61
function List({ children }) {
62
// Map over children to add list item wrappers
63
const listItems = Children.map(children, (child, index) => {
64
return createElement('li', { key: index }, child);
65
});
66
67
return createElement('ul', null, ...listItems);
68
}
69
70
function TabContainer({ children }) {
71
// Ensure only one active tab
72
let activeChild = null;
73
74
Children.forEach(children, (child) => {
75
if (child.props && child.props.active) {
76
activeChild = child;
77
}
78
});
79
80
return createElement('div', { className: 'tab-container' },
81
activeChild || Children.only(children)
82
);
83
}
84
85
function ChildCounter({ children }) {
86
const count = Children.count(children);
87
const childArray = Children.toArray(children);
88
89
return createElement('div', null,
90
createElement('p', null, `This component has ${count} children`),
91
createElement('div', null, ...childArray)
92
);
93
}
94
95
// Usage
96
const app = createElement(List, null,
97
createElement('span', null, 'Item 1'),
98
createElement('span', null, 'Item 2'),
99
createElement('span', null, 'Item 3')
100
);
101
```
102
103
### Element Validation
104
105
Validates whether a value is a valid Rax element.
106
107
```javascript { .api }
108
/**
109
* Checks if a value is a valid Rax element
110
* @param object - Value to check
111
* @returns true if the value is a valid Rax element, false otherwise
112
*/
113
function isValidElement(object: any): boolean;
114
```
115
116
**Usage Examples:**
117
118
```javascript
119
import { createElement, isValidElement } from 'rax/src/compat';
120
121
function SafeRender({ content }) {
122
// Only render if content is a valid element
123
if (isValidElement(content)) {
124
return content;
125
}
126
127
// Fallback for non-element content
128
if (typeof content === 'string' || typeof content === 'number') {
129
return createElement('span', null, content);
130
}
131
132
return createElement('div', null, 'Invalid content');
133
}
134
135
function ElementChecker({ items }) {
136
const validItems = items.filter(isValidElement);
137
const invalidCount = items.length - validItems.length;
138
139
return createElement('div', null,
140
createElement('p', null, `Valid elements: ${validItems.length}`),
141
createElement('p', null, `Invalid items: ${invalidCount}`),
142
createElement('div', null, ...validItems)
143
);
144
}
145
146
// Usage examples
147
const validElement = createElement('div', null, 'Hello');
148
const invalidElement = { notAnElement: true };
149
150
console.log(isValidElement(validElement)); // true
151
console.log(isValidElement(invalidElement)); // false
152
console.log(isValidElement('string')); // false
153
console.log(isValidElement(42)); // false
154
```
155
156
### Element Factory
157
158
Creates a factory function for a specific element type, reducing the need to repeatedly specify the type.
159
160
```javascript { .api }
161
/**
162
* Creates a factory function for creating elements of a specific type
163
* @param type - Element type (string for DOM elements, function/class for components)
164
* @returns Factory function that creates elements of the specified type
165
*/
166
function createFactory(type: string | Function): Function;
167
```
168
169
**Usage Examples:**
170
171
```javascript
172
import { createFactory } from 'rax/src/compat';
173
174
// Create factories for commonly used elements
175
const div = createFactory('div');
176
const span = createFactory('span');
177
const button = createFactory('button');
178
179
// Create factory for custom component
180
function CustomButton(props) {
181
return button({
182
className: 'custom-button',
183
...props
184
}, props.children);
185
}
186
const customButton = createFactory(CustomButton);
187
188
// Using factories (more concise than createElement)
189
function App() {
190
return div({ className: 'app' },
191
div({ className: 'header' },
192
span(null, 'Welcome to the App')
193
),
194
div({ className: 'content' },
195
button({
196
onClick: () => alert('Clicked!')
197
}, 'Click Me'),
198
customButton({
199
variant: 'primary'
200
}, 'Custom Button')
201
)
202
);
203
}
204
205
// Factory functions accept (props, ...children) just like createElement
206
const navigation = div({ className: 'nav' },
207
button({ onClick: () => {} }, 'Home'),
208
button({ onClick: () => {} }, 'About'),
209
button({ onClick: () => {} }, 'Contact')
210
);
211
```
212
213
### Element Cloning
214
215
Clones existing elements with modified props and/or children.
216
217
```javascript { .api }
218
/**
219
* Clones a Rax element with new props and/or children
220
* @param element - Element to clone
221
* @param props - New props to merge with existing props
222
* @param children - New children to replace existing children
223
* @returns New cloned element with merged props and new children
224
*/
225
function cloneElement(element: RaxElement, props?: Object, ...children: RaxNode[]): RaxElement;
226
```
227
228
**Usage Examples:**
229
230
```javascript
231
import { createElement, cloneElement, Children } from 'rax/src/compat';
232
233
function EnhanceButton({ children, enhancement, ...props }) {
234
// Clone each child button with enhanced props
235
const enhancedChildren = Children.map(children, (child) => {
236
if (child.type === 'button') {
237
return cloneElement(child, {
238
className: `${child.props.className || ''} enhanced`,
239
'data-enhancement': enhancement,
240
onClick: (e) => {
241
// Call original onClick first
242
if (child.props.onClick) {
243
child.props.onClick(e);
244
}
245
// Add enhancement behavior
246
console.log(`Enhanced click: ${enhancement}`);
247
}
248
});
249
}
250
return child;
251
});
252
253
return createElement('div', props, ...enhancedChildren);
254
}
255
256
function Modal({ isOpen, children }) {
257
if (!isOpen) return null;
258
259
// Clone children with modal-specific props
260
const modalChildren = Children.map(children, (child) => {
261
return cloneElement(child, {
262
'data-in-modal': true,
263
className: `${child.props.className || ''} modal-content`
264
});
265
});
266
267
return createElement('div', { className: 'modal-overlay' },
268
createElement('div', { className: 'modal' }, ...modalChildren)
269
);
270
}
271
272
function FormField({ label, children }) {
273
// Clone input element to add form-specific props
274
const enhancedInput = cloneElement(children, {
275
id: label.toLowerCase().replace(/\s+/g, '-'),
276
'aria-label': label,
277
className: `${children.props.className || ''} form-input`
278
});
279
280
return createElement('div', { className: 'form-field' },
281
createElement('label', {
282
htmlFor: label.toLowerCase().replace(/\s+/g, '-')
283
}, label),
284
enhancedInput
285
);
286
}
287
288
// Usage
289
const originalButton = createElement('button', {
290
onClick: () => alert('Original')
291
}, 'Click Me');
292
293
const enhancedForm = createElement(FormField, { label: 'Email Address' },
294
createElement('input', {
295
type: 'email',
296
placeholder: 'Enter email'
297
})
298
);
299
```
300
301
### Compatibility Layer Integration
302
303
The compatibility layer integrates all utilities into a single default export that mimics React's API:
304
305
```javascript { .api }
306
/**
307
* Default export that provides React-like API
308
*/
309
const Rax: {
310
// All core Rax exports
311
createElement: Function;
312
render: Function;
313
Component: ComponentConstructor;
314
PureComponent: ComponentConstructor;
315
// ... all other core exports
316
317
// Additional compatibility utilities
318
Children: ChildrenUtilities;
319
isValidElement: Function;
320
createFactory: Function;
321
cloneElement: Function;
322
323
// React compatibility flag
324
Component.prototype.isReactComponent: {};
325
};
326
```
327
328
**Full Compatibility Usage:**
329
330
```javascript
331
// Import as default to get React-like API
332
import Rax from 'rax/src/compat';
333
334
class ReactLikeComponent extends Rax.Component {
335
render() {
336
const { children } = this.props;
337
338
// Use React-like APIs
339
const validChildren = Rax.Children.toArray(children)
340
.filter(Rax.isValidElement);
341
342
const enhancedChildren = Rax.Children.map(validChildren, (child, index) => {
343
return Rax.cloneElement(child, { key: index });
344
});
345
346
return Rax.createElement('div', null, ...enhancedChildren);
347
}
348
}
349
350
// Component has React compatibility flag
351
console.log(ReactLikeComponent.prototype.isReactComponent); // {}
352
```
353
354
## Types
355
356
```javascript { .api }
357
// Children utilities type
358
interface ChildrenUtilities {
359
map<T, C>(children: C, fn: (child: C, index: number) => T, ctx?: any): T[];
360
forEach<C>(children: C, fn: (child: C, index: number) => void, ctx?: any): void;
361
count(children: RaxNode): number;
362
only(children: RaxNode): RaxElement;
363
toArray(children: RaxNode): RaxNode[];
364
}
365
366
// Element validation type
367
type IsValidElementFunction = (object: any) => object is RaxElement;
368
369
// Factory function types
370
type ElementFactory<P = {}> = (props?: P, ...children: RaxNode[]) => RaxElement;
371
type CreateFactoryFunction = <P = {}>(type: string | ComponentType<P>) => ElementFactory<P>;
372
373
// Clone element types
374
type CloneElementFunction = <P = {}>(
375
element: RaxElement<P>,
376
props?: Partial<P>,
377
...children: RaxNode[]
378
) => RaxElement<P>;
379
380
// Compatibility layer type
381
interface RaxCompat {
382
[key: string]: any;
383
Children: ChildrenUtilities;
384
isValidElement: IsValidElementFunction;
385
createFactory: CreateFactoryFunction;
386
cloneElement: CloneElementFunction;
387
}
388
389
// Node types (children can be various types)
390
type RaxNode = RaxElement | string | number | boolean | null | undefined | RaxNode[];
391
```