0
# Component Factory
1
2
Direct component creation without global registration, useful for dynamic components and programmatic component instantiation. This approach bypasses the global registry system.
3
4
## Capabilities
5
6
### Component Factory Function
7
8
Creates a component instance factory from a component wrapper without registering it globally.
9
10
```typescript { .api }
11
/**
12
* Helper method to create component without relying on registered components
13
* @param wrapper - Component implementation wrapper
14
* @returns Function that creates and mounts component instances
15
*/
16
function component<Props extends DefaultProps, State extends DefaultState, Component extends RiotComponent>(
17
wrapper: RiotComponentWrapper<Component>
18
): (
19
el: HTMLElement,
20
initialProps?: Props,
21
meta?: ComponentMeta
22
) => Component;
23
```
24
25
**Usage Example:**
26
27
```javascript
28
import { component } from "riot";
29
30
// Define component without registration
31
const createTimer = component({
32
css: "timer { display: block; color: blue; }",
33
template: (template, expressionTypes, bindingTypes) =>
34
template("<p>Time: { state.seconds }s</p>", [
35
// Template bindings
36
]),
37
exports: {
38
onBeforeMount(props) {
39
this.state = { seconds: props.start || 0 };
40
this.interval = setInterval(() => {
41
this.update({ seconds: this.state.seconds + 1 });
42
}, 1000);
43
},
44
onUnmounted() {
45
clearInterval(this.interval);
46
}
47
}
48
});
49
50
// Create and mount component instance
51
const element = document.getElementById("timer-container");
52
const timerComponent = createTimer(element, { start: 10 });
53
```
54
55
### Component Factory with Metadata
56
57
The factory function accepts optional metadata for advanced component features:
58
59
```typescript { .api }
60
interface ComponentMeta {
61
/** Slot data for child content */
62
slots?: TagSlotData[];
63
64
/** Attribute expression bindings */
65
attributes?: AttributeExpressionData[];
66
67
/** Parent scope for nested components */
68
parentScope?: any;
69
}
70
```
71
72
**Usage Example:**
73
74
```javascript
75
// Create component with slots and attributes
76
const element = document.getElementById("container");
77
const meta = {
78
slots: [
79
{
80
id: "header",
81
html: "<h2>Dynamic Header</h2>",
82
bindings: []
83
}
84
],
85
attributes: [
86
{
87
name: "data-theme",
88
evaluate: () => "dark"
89
}
90
]
91
};
92
93
const componentInstance = createMyComponent(element, { title: "Hello" }, meta);
94
```
95
96
## Enhanced Component Factory (riot+compiler)
97
98
The riot+compiler build provides an enhanced component factory that automatically handles runtime slot creation:
99
100
```typescript { .api }
101
/**
102
* Enhanced component factory that creates slots from DOM content
103
* @param wrapper - Component implementation wrapper
104
* @returns Enhanced factory function with automatic slot handling
105
*/
106
function component(wrapper: RiotComponentWrapper): (
107
el: HTMLElement,
108
props?: any,
109
meta?: ComponentMeta
110
) => RiotComponent;
111
```
112
113
**Usage Example:**
114
115
```javascript
116
import { component } from "riot+compiler";
117
118
const createWidget = component({
119
template: (template, expressionTypes, bindingTypes) =>
120
template(`
121
<div class="widget">
122
<slot name="content"></slot>
123
</div>
124
`, [
125
// Slot bindings are automatically handled
126
]),
127
exports: {
128
onMounted() {
129
console.log("Widget mounted with slots:", this.slots);
130
}
131
}
132
});
133
134
// HTML content becomes slots automatically
135
const element = document.querySelector(".widget-container");
136
// Any existing content in element becomes slot content
137
const widget = createWidget(element, { theme: "modern" });
138
```
139
140
## Dynamic Component Creation
141
142
Component factories are particularly useful for dynamic component creation:
143
144
```javascript
145
import { component } from "riot";
146
147
// Factory for creating different card types
148
function createCardComponent(cardType) {
149
return component({
150
css: `.card-${cardType} { border: 2px solid ${getCardColor(cardType)}; }`,
151
template: (template) => template(`
152
<div class="card-${cardType}">
153
<h3>{ props.title }</h3>
154
<p>{ props.content }</p>
155
</div>
156
`),
157
exports: {
158
onMounted() {
159
console.log(`${cardType} card mounted`);
160
}
161
}
162
});
163
}
164
165
// Create different card types dynamically
166
const createInfoCard = createCardComponent("info");
167
const createWarningCard = createCardComponent("warning");
168
169
// Use the factories
170
const infoCard = createInfoCard(document.getElementById("info"), {
171
title: "Information",
172
content: "This is an info card"
173
});
174
175
const warningCard = createWarningCard(document.getElementById("warning"), {
176
title: "Warning",
177
content: "This is a warning card"
178
});
179
```
180
181
## Types
182
183
```typescript { .api }
184
interface ComponentMeta {
185
slots?: TagSlotData[];
186
attributes?: AttributeExpressionData[];
187
parentScope?: any;
188
}
189
190
type TagSlotData = {
191
id: string;
192
html: string;
193
bindings: BindingData[];
194
};
195
196
type AttributeExpressionData = {
197
name: string;
198
evaluate: () => any;
199
};
200
201
type BindingData = {
202
selector: string;
203
type: number;
204
evaluate: () => any;
205
};
206
```