Skip to content

Commit 79b3cfe

Browse files
authored
Refactor/renderers (#19)
* refactor: remove unnecessary renderer registry overrides * refactor: remove FormContainer renderer and destruct internal props before pass to html elements * refactor: remove function sanitizePropsForDOM * refactor: remove component registry overrides * refactor: rename registry dir to registries * refactor: extract defaultRenderers definition into a separate file * fix: type check fail
1 parent 4950b9a commit 79b3cfe

61 files changed

Lines changed: 433 additions & 330 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
"private": true,
66
"scripts": {
77
"build": "turbo build",
8-
"dev": "turbo dev",
8+
"showcases:dev": "turbo --filter showcases dev",
99
"test": "turbo test --filter='./packages/*'",
1010
"test:e2e": "playwright test --config=tests/playwright.config.ts",
1111
"test:e2e:ui": "playwright test --ui --config=tests/playwright.config.ts",
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import { ComponentSpec, ComponentType, RuntimeAdapter } from "../runtime/types";
2+
3+
/**
4+
* Renderer function - wraps component rendering with additional logic
5+
*/
6+
export type RendererFn = (
7+
componentSpec: ComponentSpec,
8+
props: Record<string, any>,
9+
runtime: RuntimeAdapter,
10+
children?: any[]
11+
) => any;
12+
13+
/**
14+
* Default renderers - pass props as is
15+
*/
16+
export const defaultRenderers: Record<ComponentType, RendererFn> = {
17+
field: (spec, props, runtime, children) => {
18+
const propsWithChildren = children && children.length > 0
19+
? { ...props, children }
20+
: props;
21+
return runtime.create(spec, propsWithChildren);
22+
},
23+
'field-wrapper': (spec, props, runtime, children) => {
24+
const propsWithChildren = children && children.length > 0
25+
? { ...props, children }
26+
: props;
27+
return runtime.create(spec, propsWithChildren);
28+
},
29+
'container': (spec, props, runtime, children) => {
30+
return runtime.create(spec, { ...props, children });
31+
},
32+
content: (spec, props, runtime, children) => {
33+
const propsWithChildren = children && children.length > 0
34+
? { ...props, children }
35+
: props;
36+
return runtime.create(spec, propsWithChildren);
37+
},
38+
addon: (spec, props, runtime) => {
39+
return runtime.create(spec, props);
40+
},
41+
'menu-item': (spec, props, runtime, children) => {
42+
const propsWithChildren = children && children.length > 0
43+
? { ...props, children }
44+
: props;
45+
return runtime.create(spec, propsWithChildren);
46+
},
47+
'menu-container': (spec, props, runtime, children) => {
48+
const propsWithChildren = children && children.length > 0
49+
? { ...props, children }
50+
: props;
51+
return runtime.create(spec, propsWithChildren);
52+
},
53+
54+
}

packages/core/src/index.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,10 @@ export * from './runtime/types';
1111
export * from './forms/types';
1212

1313
// Registry system
14-
export * from './registry/component-registry';
15-
export * from './registry/renderer-registry';
14+
export * from './registries/component-registry';
15+
export * from './registries/renderer-registry';
16+
17+
export * from './defaults/register-default-renderers'
1618

1719
// Orchestrator
1820
export * from './orchestrator/renderer-orchestrator';
@@ -34,7 +36,6 @@ export * from './provider';
3436

3537
// Utils
3638
export * from './utils/jexl-config';
37-
export * from './utils/sanitize-props';
3839

3940
// Validation
4041
export * from './validation';

packages/core/src/orchestrator/renderer-orchestrator.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@
88
import type { RuntimeAdapter, ComponentSpec, DebugContextValue } from '../runtime/types';
99
import type { FormAdapter } from '../forms/types';
1010
import type { MiddlewareFn, MiddlewareContext } from '../middleware/types';
11-
import { getComponentSpec } from '../registry/component-registry';
12-
import { getRendererForType } from '../registry/renderer-registry';
11+
import { getComponentSpec } from '../registries/component-registry';
12+
import { getRendererForType } from '../registries/renderer-registry';
1313
import { applyMiddlewares } from '../middleware/types';
1414
import { processValue } from '../expressions/template-processor';
1515
import { createDefaultResolver } from '../expressions/variable-resolver';
@@ -200,6 +200,16 @@ export function createRendererOrchestrator(
200200
// Parse schema (now using processed schema)
201201
const { 'x-component-props': componentProps = {} } = processedSchema;
202202

203+
// const componentSpec = getComponentSpec(componentKey, components, undefined, debug?.isEnabled);
204+
205+
// if(!componentSpec) {
206+
// if (debug?.isEnabled) {
207+
// console.warn(`Component not found: ${componentKey}`);
208+
// }
209+
// // Return error element (framework adapter will handle)
210+
// return null;
211+
// }
212+
203213
// Resolve component and renderer
204214
// Use processedSchema for x-component resolution (in case x-component has templates)
205215
// components already has provider components merged in the factory

packages/core/src/provider/provider.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { describe, it, expect } from 'vitest';
66
import { mergeProviderConfigs, resolveProviderConfig } from './provider';
77
import type { ProviderConfig } from './types';
88
import type { FormSchema } from '../schema/schema-types';
9-
import { createComponentSpec } from '../registry/component-registry';
9+
import { createComponentSpec } from '../registries/component-registry';
1010

1111
describe('Provider Utilities', () => {
1212
describe('mergeProviderConfigs', () => {

packages/core/src/provider/provider.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
import type { ProviderConfig } from './types';
88
import { defaultDebugConfig } from './types';
9-
import { getRendererRegistry } from '../registry/renderer-registry';
9+
import { getRendererRegistry } from '../registries/renderer-registry';
1010

1111
/**
1212
* Merge two provider configurations hierarchically

packages/core/src/provider/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
import type { ComponentSpec, ComponentType, DebugConfig } from '../runtime/types';
88
import type { FormSchema } from '../schema/schema-types';
99
import type { MiddlewareFn } from '../middleware/types';
10-
import type { RendererFn } from '../registry/renderer-registry';
10+
import { RendererFn } from '../defaults/register-default-renderers';
1111

1212
/**
1313
* Provider configuration

packages/core/src/registry/component-registry.ts renamed to packages/core/src/registries/component-registry.ts

Lines changed: 0 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ export const defaultTypeProps: Record<ComponentType, Record<string, any>> = {
1414
field: { fullWidth: true },
1515
'field-wrapper': {},
1616
'container': {},
17-
'FormContainer': {},
1817
content: {},
1918
addon: {},
2019
'menu-item': {},
@@ -54,21 +53,6 @@ export function getFactoryDefaultComponents(): Record<string, ComponentSpec> {
5453
return factoryDefaultComponents;
5554
}
5655

57-
/**
58-
* Registry overrides (global registrations)
59-
*/
60-
const registryOverrides = new Map<string, Partial<ComponentSpec>>();
61-
62-
/**
63-
* Register a component override globally
64-
*/
65-
export function registerComponent(name: string, config: Partial<ComponentSpec>): void {
66-
registryOverrides.set(name, {
67-
...registryOverrides.get(name),
68-
...config,
69-
});
70-
}
71-
7256
/**
7357
* Get unified component registry
7458
*
@@ -101,16 +85,6 @@ export function getComponentRegistry(
10185
});
10286
}
10387

104-
// Apply registry overrides
105-
for (const [name, override] of Array.from(registryOverrides.entries())) {
106-
const existing = merged[name];
107-
merged[name] = {
108-
...existing,
109-
...override,
110-
id: override.id || existing?.id || name,
111-
} as ComponentSpec;
112-
}
113-
11488
return merged;
11589
}
11690

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
/**
2+
* Renderer Registry
3+
*
4+
* Framework-agnostic renderer registration system.
5+
* Renderers are functions that wrap components with additional rendering logic.
6+
*/
7+
8+
import { defaultRenderers, RendererFn } from '../defaults/register-default-renderers';
9+
import type { ComponentType } from '../runtime/types';
10+
11+
12+
/**
13+
* Get unified renderer registry with hierarchical merging
14+
*
15+
* Priority order: local > global > default
16+
*/
17+
export function getRendererRegistry(
18+
globalRenderers?: Partial<Record<ComponentType, RendererFn>>,
19+
localRenderers?: Partial<Record<ComponentType, RendererFn>>
20+
): Record<ComponentType, RendererFn> {
21+
// Start with built-in renderers
22+
let merged = { ...defaultRenderers };
23+
24+
// Apply global renderers (from provider)
25+
if (globalRenderers) {
26+
Object.keys(globalRenderers).forEach(type => {
27+
const renderer = globalRenderers[type as ComponentType];
28+
if (renderer) {
29+
merged[type as ComponentType] = renderer;
30+
}
31+
});
32+
}
33+
34+
// Apply local renderers (maximum priority)
35+
if (localRenderers) {
36+
Object.keys(localRenderers).forEach(type => {
37+
const renderer = localRenderers[type as ComponentType];
38+
if (renderer) {
39+
merged[type as ComponentType] = renderer;
40+
}
41+
});
42+
}
43+
44+
return merged;
45+
}
46+
47+
/**
48+
* Get effective renderer for a component type
49+
* Includes debug logging
50+
*/
51+
export function getRendererForType(
52+
type: ComponentType,
53+
globalRenderers?: Partial<Record<ComponentType, RendererFn>>,
54+
localRenderers?: Partial<Record<ComponentType, RendererFn>>,
55+
debugEnabled?: boolean
56+
): RendererFn {
57+
// Local renderers have maximum priority
58+
if (localRenderers?.[type]) {
59+
if (debugEnabled) {
60+
console.log(`Renderer resolved from local: ${type}`);
61+
}
62+
return localRenderers[type]!;
63+
}
64+
65+
// Global renderers second priority
66+
if (globalRenderers?.[type]) {
67+
if (debugEnabled) {
68+
console.log(`Renderer resolved from global: ${type}`);
69+
}
70+
return globalRenderers[type]!;
71+
}
72+
73+
// Default renderer last
74+
if (debugEnabled) {
75+
console.log(`Renderer resolved from default: ${type}`);
76+
}
77+
return defaultRenderers[type];
78+
}
79+

0 commit comments

Comments
 (0)