Skip to content

Commit 27f115a

Browse files
committed
Add ref forwarding to SchemaRenderer and ButtonRenderer
Refactored SchemaRenderer and button form renderer to use React.forwardRef, enabling ref forwarding for better integration with libraries like Radix UI. Updated renderChildren to unwrap single children arrays for compatibility with 'asChild' patterns and improved key assignment for child elements.
1 parent f41f6d5 commit 27f115a

File tree

3 files changed

+21
-8
lines changed

3 files changed

+21
-8
lines changed

packages/components/src/lib/utils.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,13 @@ export function cn(...inputs: ClassValue[]) {
1010
export function renderChildren(children: any): React.ReactNode {
1111
if (!children) return null;
1212
if (Array.isArray(children)) {
13+
if (children.length === 0) return null;
14+
// Unwrap single child to support Radix UI 'asChild' pattern which expects a single ReactElement, not an array
15+
if (children.length === 1) {
16+
return <SchemaRenderer schema={children[0]} />;
17+
}
1318
return children.map((child, index) => (
14-
<SchemaRenderer key={index} schema={child} />
19+
<SchemaRenderer key={child.id || index} schema={child} />
1520
));
1621
}
1722
return <SchemaRenderer schema={children} />;

packages/components/src/renderers/form/button.tsx

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@ import { ComponentRegistry } from '@object-ui/core';
22
import type { ButtonSchema } from '@object-ui/types';
33
import { Button } from '../../ui';
44
import { renderChildren } from '../../lib/utils';
5+
import { forwardRef } from 'react';
56

6-
ComponentRegistry.register('button',
7-
({ schema, ...props }: { schema: ButtonSchema; [key: string]: any }) => {
7+
const ButtonRenderer = forwardRef<HTMLButtonElement, { schema: ButtonSchema; [key: string]: any }>(
8+
({ schema, ...props }, ref) => {
89
// Extract designer-related props
910
const {
1011
'data-obj-id': dataObjId,
@@ -15,6 +16,7 @@ ComponentRegistry.register('button',
1516

1617
return (
1718
<Button
19+
ref={ref}
1820
variant={schema.variant}
1921
size={schema.size}
2022
className={schema.className}
@@ -25,7 +27,11 @@ ComponentRegistry.register('button',
2527
{schema.label || renderChildren(schema.body)}
2628
</Button>
2729
);
28-
},
30+
}
31+
);
32+
ButtonRenderer.displayName = 'ButtonRenderer';
33+
34+
ComponentRegistry.register('button', ButtonRenderer,
2935
{
3036
label: 'Button',
3137
inputs: [

packages/react/src/SchemaRenderer.tsx

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
import React from 'react';
1+
import React, { forwardRef } from 'react';
22
import { SchemaNode, ComponentRegistry } from '@object-ui/core';
33

4-
export const SchemaRenderer: React.FC<{ schema: SchemaNode }> = ({ schema }) => {
4+
export const SchemaRenderer = forwardRef<any, { schema: SchemaNode }>(({ schema }, ref) => {
55
if (!schema) return null;
66
// If schema is just a string, render it as text
77
if (typeof schema === 'string') return <>{schema}</>;
@@ -23,6 +23,8 @@ export const SchemaRenderer: React.FC<{ schema: SchemaNode }> = ({ schema }) =>
2323
...(schema.props || {}),
2424
className: schema.className,
2525
'data-obj-id': schema.id,
26-
'data-obj-type': schema.type
26+
'data-obj-type': schema.type,
27+
ref
2728
});
28-
};
29+
});
30+
SchemaRenderer.displayName = 'SchemaRenderer';

0 commit comments

Comments
 (0)