0
# Utilities
1
2
React-specific utility functions for element manipulation, type checking, and React component handling.
3
4
## Capabilities
5
6
### Element Utilities
7
8
Functions for working with React elements and their properties.
9
10
```typescript { .api }
11
/**
12
* Add key prop to React element for use in arrays
13
* @param element - React element to add key to
14
* @param key - Key value to add
15
* @returns Element with key prop added
16
*/
17
function addKeyToElement(element: ReactElement, key: string): ReactElement;
18
19
/**
20
* Extract props from JSX element
21
* @param element - React element to extract props from
22
* @returns Props object or empty object if not valid element
23
*/
24
function getElementProps(element: ReactElement): Record<string, any>;
25
```
26
27
**Usage Example:**
28
29
```typescript
30
import React from 'react';
31
import { addKeyToElement, getElementProps } from '@remirror/react';
32
33
function DynamicList({ items }) {
34
const elementList = items.map((item, index) => {
35
const element = <div>{item.content}</div>;
36
return addKeyToElement(element, `item-${index}`);
37
});
38
39
const firstElementProps = getElementProps(elementList[0]);
40
console.log('First element props:', firstElementProps);
41
42
return <div>{elementList}</div>;
43
}
44
```
45
46
### Type Checking Utilities
47
48
Functions for validating React elements and components.
49
50
```typescript { .api }
51
/**
52
* Check if value is a React DOM element (not a custom component)
53
* @param element - Value to check
54
* @returns True if element is a React DOM element
55
*/
56
function isReactDOMElement(element: unknown): element is ReactElement<any, string>;
57
58
/**
59
* Check if value is a React Fragment
60
* @param element - Value to check
61
* @returns True if element is a React Fragment
62
*/
63
function isReactFragment(element: unknown): element is ReactElement<any, typeof React.Fragment>;
64
65
/**
66
* Drop-in replacement for React.isValidElement with enhanced type checking
67
* @param element - Value to check
68
* @returns True if element is a valid React element
69
*/
70
function isValidElement(element: unknown): element is ReactElement;
71
```
72
73
**Usage Example:**
74
75
```typescript
76
import React from 'react';
77
import {
78
isReactDOMElement,
79
isReactFragment,
80
isValidElement
81
} from '@remirror/react';
82
83
function ElementAnalyzer({ children }) {
84
const analyzeChild = (child) => {
85
if (!isValidElement(child)) {
86
return 'Not a React element';
87
}
88
89
if (isReactFragment(child)) {
90
return 'React Fragment';
91
}
92
93
if (isReactDOMElement(child)) {
94
return `DOM Element: ${child.type}`;
95
}
96
97
return `Custom Component: ${child.type.name || 'Anonymous'}`;
98
};
99
100
return (
101
<div>
102
{React.Children.map(children, (child, index) => (
103
<div key={index}>
104
Child {index}: {analyzeChild(child)}
105
</div>
106
))}
107
</div>
108
);
109
}
110
```
111
112
### Prop Validation Utilities
113
114
Functions for validating component props and function props.
115
116
```typescript { .api }
117
/**
118
* Validate that a prop is a function, throws error if not
119
* @param prop - Property value to validate
120
* @param propName - Name of the property for error messages
121
* @throws Error if prop is not a function
122
*/
123
function propIsFunction(prop: unknown, propName: string): asserts prop is Function;
124
```
125
126
**Usage Example:**
127
128
```typescript
129
import React from 'react';
130
import { propIsFunction } from '@remirror/react';
131
132
interface CallbackComponentProps {
133
onAction: Function;
134
onError?: Function;
135
data: any;
136
}
137
138
function CallbackComponent({ onAction, onError, data }: CallbackComponentProps) {
139
// Validate required function props
140
propIsFunction(onAction, 'onAction');
141
142
// Validate optional function props
143
if (onError) {
144
propIsFunction(onError, 'onError');
145
}
146
147
const handleClick = () => {
148
try {
149
onAction(data);
150
} catch (error) {
151
onError?.(error);
152
}
153
};
154
155
return <button onClick={handleClick}>Execute Action</button>;
156
}
157
```
158
159
### Advanced Element Manipulation
160
161
More sophisticated utilities for working with React elements.
162
163
```typescript { .api }
164
/**
165
* Clone element with additional props, preserving existing props
166
* @param element - Element to clone
167
* @param additionalProps - Props to add or override
168
* @returns Cloned element with merged props
169
*/
170
function cloneElementWithProps(
171
element: ReactElement,
172
additionalProps: Record<string, any>
173
): ReactElement;
174
175
/**
176
* Recursively map over React children, including nested structures
177
* @param children - React children to map over
178
* @param mapFn - Function to apply to each child
179
* @returns Mapped children
180
*/
181
function deepMapChildren(
182
children: React.ReactNode,
183
mapFn: (child: ReactElement, index: number, depth: number) => ReactElement
184
): React.ReactNode;
185
186
/**
187
* Filter React children based on a predicate function
188
* @param children - React children to filter
189
* @param predicate - Function to test each child
190
* @returns Filtered children
191
*/
192
function filterChildren(
193
children: React.ReactNode,
194
predicate: (child: ReactElement, index: number) => boolean
195
): React.ReactNode;
196
197
/**
198
* Find first child element matching a predicate
199
* @param children - React children to search
200
* @param predicate - Function to test each child
201
* @returns First matching child or undefined
202
*/
203
function findChild(
204
children: React.ReactNode,
205
predicate: (child: ReactElement, index: number) => boolean
206
): ReactElement | undefined;
207
```
208
209
**Usage Example:**
210
211
```typescript
212
import React from 'react';
213
import {
214
cloneElementWithProps,
215
deepMapChildren,
216
filterChildren,
217
findChild
218
} from '@remirror/react';
219
220
function EnhancedContainer({ children, theme }) {
221
// Add theme prop to all child elements
222
const themedChildren = deepMapChildren(children, (child, index, depth) => {
223
return cloneElementWithProps(child, {
224
theme,
225
depth,
226
'data-index': index,
227
});
228
});
229
230
// Filter out hidden children
231
const visibleChildren = filterChildren(themedChildren, (child) => {
232
return child.props.hidden !== true;
233
});
234
235
// Find first button child
236
const firstButton = findChild(visibleChildren, (child) => {
237
return child.type === 'button' || child.type?.name === 'Button';
238
});
239
240
return (
241
<div className="enhanced-container">
242
{firstButton && (
243
<div className="primary-action">
244
{cloneElementWithProps(firstButton, { primary: true })}
245
</div>
246
)}
247
<div className="other-children">
248
{visibleChildren}
249
</div>
250
</div>
251
);
252
}
253
```
254
255
### Component Analysis Utilities
256
257
Functions for analyzing React component structures and hierarchies.
258
259
```typescript { .api }
260
/**
261
* Get the display name of a React component
262
* @param component - Component to get name from
263
* @returns Component display name or 'Anonymous'
264
*/
265
function getComponentName(component: ComponentType): string;
266
267
/**
268
* Check if component is a class component
269
* @param component - Component to check
270
* @returns True if component is a class component
271
*/
272
function isClassComponent(component: ComponentType): boolean;
273
274
/**
275
* Check if component is a function component
276
* @param component - Component to check
277
* @returns True if component is a function component
278
*/
279
function isFunctionComponent(component: ComponentType): boolean;
280
281
/**
282
* Check if component is a memo component
283
* @param component - Component to check
284
* @returns True if component is wrapped with React.memo
285
*/
286
function isMemoComponent(component: ComponentType): boolean;
287
288
/**
289
* Check if component is a forwardRef component
290
* @param component - Component to check
291
* @returns True if component is wrapped with React.forwardRef
292
*/
293
function isForwardRefComponent(component: ComponentType): boolean;
294
```
295
296
**Usage Example:**
297
298
```typescript
299
import React from 'react';
300
import {
301
getComponentName,
302
isClassComponent,
303
isFunctionComponent,
304
isMemoComponent,
305
isForwardRefComponent
306
} from '@remirror/react';
307
308
function ComponentInspector({ component }) {
309
const analysis = {
310
name: getComponentName(component),
311
isClass: isClassComponent(component),
312
isFunction: isFunctionComponent(component),
313
isMemo: isMemoComponent(component),
314
isForwardRef: isForwardRefComponent(component),
315
};
316
317
return (
318
<div className="component-analysis">
319
<h3>Component Analysis</h3>
320
<ul>
321
<li>Name: {analysis.name}</li>
322
<li>Type: {analysis.isClass ? 'Class' : 'Function'}</li>
323
<li>Memoized: {analysis.isMemo ? 'Yes' : 'No'}</li>
324
<li>Forward Ref: {analysis.isForwardRef ? 'Yes' : 'No'}</li>
325
</ul>
326
</div>
327
);
328
}
329
```
330
331
### Event Utilities
332
333
Helper functions for working with React events and event handlers.
334
335
```typescript { .api }
336
/**
337
* Create a debounced event handler
338
* @param handler - Original event handler
339
* @param delay - Debounce delay in milliseconds
340
* @returns Debounced event handler
341
*/
342
function debounceEventHandler<T extends (...args: any[]) => void>(
343
handler: T,
344
delay: number
345
): T;
346
347
/**
348
* Create a throttled event handler
349
* @param handler - Original event handler
350
* @param interval - Throttle interval in milliseconds
351
* @returns Throttled event handler
352
*/
353
function throttleEventHandler<T extends (...args: any[]) => void>(
354
handler: T,
355
interval: number
356
): T;
357
358
/**
359
* Combine multiple event handlers into one
360
* @param handlers - Array of event handlers
361
* @returns Combined event handler
362
*/
363
function combineEventHandlers<T extends (...args: any[]) => void>(
364
...handlers: (T | undefined)[]
365
): T;
366
367
/**
368
* Stop event propagation and prevent default
369
* @param event - React event or native event
370
*/
371
function stopEvent(event: React.SyntheticEvent | Event): void;
372
```
373
374
**Usage Example:**
375
376
```typescript
377
import React, { useState } from 'react';
378
import {
379
debounceEventHandler,
380
throttleEventHandler,
381
combineEventHandlers,
382
stopEvent
383
} from '@remirror/react';
384
385
function SmartInput({ onChange, onFocus, onBlur, onKeyDown }) {
386
const [value, setValue] = useState('');
387
388
// Debounce onChange to avoid excessive API calls
389
const debouncedOnChange = debounceEventHandler(onChange, 300);
390
391
// Throttle scroll event handler
392
const throttledScroll = throttleEventHandler((e) => {
393
console.log('Scroll position:', e.target.scrollTop);
394
}, 100);
395
396
// Combine multiple key handlers
397
const combinedKeyHandler = combineEventHandlers(
398
onKeyDown,
399
(e) => {
400
if (e.key === 'Escape') {
401
stopEvent(e);
402
setValue('');
403
}
404
}
405
);
406
407
const handleChange = (e) => {
408
setValue(e.target.value);
409
debouncedOnChange(e.target.value);
410
};
411
412
return (
413
<input
414
value={value}
415
onChange={handleChange}
416
onFocus={onFocus}
417
onBlur={onBlur}
418
onKeyDown={combinedKeyHandler}
419
onScroll={throttledScroll}
420
/>
421
);
422
}
423
```
424
425
## Type Definitions
426
427
```typescript { .api }
428
/**
429
* Generic component type that accepts any props
430
*/
431
type ComponentType<P = {}> = React.ComponentType<P>;
432
433
/**
434
* Props with children
435
*/
436
interface PropsWithChildren<P = {}> extends P {
437
children?: React.ReactNode;
438
}
439
440
/**
441
* Props with optional className
442
*/
443
interface PropsWithClassName<P = {}> extends P {
444
className?: string;
445
}
446
447
/**
448
* Element properties for HTML elements
449
*/
450
type HTMLElementProps<T = HTMLElement> = React.HTMLAttributes<T>;
451
452
/**
453
* Event handler type for React events
454
*/
455
type EventHandler<E = React.SyntheticEvent> = (event: E) => void;
456
457
/**
458
* Ref type for React elements
459
*/
460
type ElementRef<T = HTMLElement> = React.RefObject<T> | React.MutableRefObject<T>;
461
```
462
463
## Performance Utilities
464
465
```typescript { .api }
466
/**
467
* Memoize a component with custom comparison
468
* @param component - Component to memoize
469
* @param areEqual - Custom equality function
470
* @returns Memoized component
471
*/
472
function memoizeComponent<P>(
473
component: ComponentType<P>,
474
areEqual?: (prevProps: P, nextProps: P) => boolean
475
): React.MemoExoticComponent<ComponentType<P>>;
476
477
/**
478
* Create a stable callback that doesn't change on re-renders
479
* @param callback - Callback function
480
* @param deps - Dependency array
481
* @returns Stable callback
482
*/
483
function useStableCallback<T extends (...args: any[]) => any>(
484
callback: T,
485
deps: React.DependencyList
486
): T;
487
488
/**
489
* Lazy load a component with optional loading fallback
490
* @param importFn - Dynamic import function
491
* @param fallback - Loading component
492
* @returns Lazy component
493
*/
494
function lazyComponent<P>(
495
importFn: () => Promise<{ default: ComponentType<P> }>,
496
fallback?: ComponentType
497
): React.LazyExoticComponent<ComponentType<P>>;
498
```