@genesislcap/foundation-layout 14.368.0 → 14.370.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/dist/custom-elements.json +177 -9
  2. package/dist/dts/index.d.ts +2 -1
  3. package/dist/dts/index.d.ts.map +1 -1
  4. package/dist/dts/main/layout-item.d.ts +20 -0
  5. package/dist/dts/main/layout-item.d.ts.map +1 -1
  6. package/dist/dts/main/layout-main.d.ts +40 -8
  7. package/dist/dts/main/layout-main.d.ts.map +1 -1
  8. package/dist/dts/styles/constants.d.ts +1 -1
  9. package/dist/dts/styles/constants.d.ts.map +1 -1
  10. package/dist/dts/styles/layout.styles.d.ts.map +1 -1
  11. package/dist/dts/utils/constants.d.ts +2 -0
  12. package/dist/dts/utils/constants.d.ts.map +1 -1
  13. package/dist/dts/utils/factory-registry.d.ts +63 -0
  14. package/dist/dts/utils/factory-registry.d.ts.map +1 -0
  15. package/dist/dts/utils/index.d.ts +1 -0
  16. package/dist/dts/utils/index.d.ts.map +1 -1
  17. package/dist/dts/utils/types.d.ts +44 -3
  18. package/dist/dts/utils/types.d.ts.map +1 -1
  19. package/dist/esm/index.js +1 -0
  20. package/dist/esm/main/layout-item.js +26 -4
  21. package/dist/esm/main/layout-main.js +187 -47
  22. package/dist/esm/styles/constants.js +4 -3
  23. package/dist/esm/styles/layout.styles.js +15 -10
  24. package/dist/esm/utils/constants.js +11 -0
  25. package/dist/esm/utils/factory-registry.js +88 -0
  26. package/dist/esm/utils/index.js +1 -0
  27. package/dist/foundation-layout.api.json +206 -9
  28. package/dist/foundation-layout.d.ts +160 -9
  29. package/docs/FRAMEWORK_COMPONENTS.md +568 -0
  30. package/docs/api/foundation-layout.componentfactory.md +46 -0
  31. package/docs/api/foundation-layout.foundationlayout.md +2 -2
  32. package/docs/api/foundation-layout.foundationlayout.registeritem.md +31 -7
  33. package/docs/api/foundation-layout.foundationlayoutitem.md +2 -0
  34. package/docs/api/foundation-layout.foundationlayoutitem.registration.md +18 -0
  35. package/docs/api/foundation-layout.getfactory.md +56 -0
  36. package/docs/api/foundation-layout.md +59 -0
  37. package/docs/api/foundation-layout.registerfactory.md +94 -0
  38. package/docs/api/foundation-layout.unregisterfactory.md +63 -0
  39. package/docs/api-report.md.api.md +22 -7
  40. package/package.json +13 -12
@@ -0,0 +1,568 @@
1
+ # Framework Components in Foundation Layout
2
+
3
+ ## Overview
4
+
5
+ This document discusses patterns and future enhancements for using framework-rendered components (React, Angular, Vue, etc.) within the foundation-layout system.
6
+
7
+ ## Current State (JavaScript API)
8
+
9
+ The layout system now supports **factory functions** for registering components. This is the recommended approach for framework-rendered components because it allows each layout instance to create a fresh component rather than cloning existing DOM elements (which loses event listeners).
10
+
11
+ ### Factory Function Pattern
12
+
13
+ The factory function pattern is **framework-agnostic** and works with any framework:
14
+
15
+ #### React
16
+ ```typescript
17
+ layout.registerItem('my-component', (container) => {
18
+ const root = createRoot(container);
19
+ root.render(
20
+ <Provider store={store}>
21
+ <MyComponent />
22
+ </Provider>
23
+ );
24
+
25
+ // Optional: return cleanup function
26
+ return () => root.unmount();
27
+ });
28
+ ```
29
+
30
+ #### Angular
31
+ ```typescript
32
+ layout.registerItem('my-component', (container) => {
33
+ const componentRef = createComponent(MyComponent, {
34
+ environmentInjector: this.injector,
35
+ hostElement: container
36
+ });
37
+ componentRef.changeDetectorRef.detectChanges();
38
+
39
+ return () => componentRef.destroy();
40
+ });
41
+ ```
42
+
43
+ #### Vue
44
+ ```typescript
45
+ layout.registerItem('my-component', (container) => {
46
+ const app = createApp(MyComponent);
47
+ app.mount(container);
48
+
49
+ return () => app.unmount();
50
+ });
51
+ ```
52
+
53
+ ### Why Factory Functions?
54
+
55
+ The layout system needs to create multiple instances of registered components (e.g., when loading saved layouts, adding items multiple times, or handling popout windows). The original implementation used `cloneNode(true)`, which:
56
+
57
+ 1. ✅ Works great for native HTML elements
58
+ 2. ❌ **Loses JavaScript event listeners** (limitation of `cloneNode` API)
59
+ 3. ❌ **Loses framework bindings** (React event handlers, Angular directives, Vue reactivity)
60
+
61
+ Factory functions solve this by letting frameworks create fresh, fully-functional component instances.
62
+
63
+ ## Known Limitations
64
+
65
+ ### Component State Serialization
66
+
67
+ **Current Limitation:** Factory-based components do not support the `LayoutComponentWithState<T>` interface for saving and restoring component-specific state.
68
+
69
+ #### Why This Limitation Exists
70
+
71
+ The layout system's state management works by calling `getCurrentState()` and `applyState()` methods on DOM elements. For factory-based components:
72
+
73
+ 1. The factory creates a wrapper `div` that gets added to the layout
74
+ 2. Framework components (React/Angular/Vue) render **inside** this wrapper
75
+ 3. The wrapper is a plain `HTMLDivElement` without `getCurrentState()` or `applyState()` methods
76
+ 4. The framework components inside have no mechanism to expose these methods to the layout system
77
+
78
+ #### What Works vs What Doesn't
79
+
80
+ ✅ **Works:**
81
+ - Event listeners (click, input, change, etc.)
82
+ - Multiple instances of the same component
83
+ - Basic layout save/load (positions, sizes, tab order)
84
+ - Component cleanup via factory return value
85
+
86
+ ❌ **Doesn't Work:**
87
+ - Saving component-specific state (form values, scroll position, selected items, etc.)
88
+ - Restoring component state when loading a saved layout
89
+ - Using `LayoutComponentWithState<T>` interface with factory components
90
+
91
+ #### Workarounds
92
+
93
+ Until state management is implemented for factory components, use these approaches:
94
+
95
+ **1. External State Management (Recommended)**
96
+ Use your framework's state management solution:
97
+ - React: Redux, Context API, Zustand, Jotai
98
+ - Angular: Services with RxJS
99
+ - Vue: Vuex, Pinia
100
+
101
+ ```typescript
102
+ // React example with Redux
103
+ layout.registerItem('my-form', (container) => {
104
+ const root = createRoot(container);
105
+ root.render(
106
+ <Provider store={reduxStore}>
107
+ <MyFormComponent /> {/* State persisted in Redux */}
108
+ </Provider>
109
+ );
110
+ return () => root.unmount();
111
+ });
112
+ ```
113
+
114
+ **2. URL Parameters or Query Strings**
115
+ Store state in the URL for shareable/bookmarkable states:
116
+ ```typescript
117
+ // React example
118
+ const searchParams = new URLSearchParams(window.location.search);
119
+ const initialState = searchParams.get('formData');
120
+ ```
121
+
122
+ **3. LocalStorage/SessionStorage**
123
+ Manually persist state outside the layout system:
124
+ ```typescript
125
+ // React example with useEffect
126
+ useEffect(() => {
127
+ localStorage.setItem('myComponentState', JSON.stringify(state));
128
+ }, [state]);
129
+ ```
130
+
131
+ **4. Use Element-Based Registration**
132
+ If state management is critical and external solutions don't work, use element-based registration for those specific components (though you'll lose event listeners).
133
+
134
+ #### Proposed Solutions for Future Implementation
135
+
136
+ **Option 1: Extended Factory Return Type** (Recommended)
137
+ ```typescript
138
+ type ComponentFactory = (container: HTMLElement) => {
139
+ cleanup?: () => void;
140
+ getCurrentState?: () => unknown;
141
+ applyState?: (state: unknown) => void;
142
+ } | void | (() => void);
143
+ ```
144
+
145
+ Factory functions could return an object with state handlers:
146
+ ```typescript
147
+ layout.registerItem('my-component', (container) => {
148
+ const root = createRoot(container);
149
+ let componentState = null;
150
+
151
+ root.render(<MyComponent onStateChange={(s) => componentState = s} />);
152
+
153
+ return {
154
+ cleanup: () => root.unmount(),
155
+ getCurrentState: () => componentState,
156
+ applyState: (state) => componentState = state
157
+ };
158
+ });
159
+ ```
160
+
161
+ **Option 2: State Manager Callback**
162
+ ```typescript
163
+ type ComponentFactory = (
164
+ container: HTMLElement,
165
+ stateManager?: {
166
+ registerStateHandlers: (handlers: {
167
+ getCurrentState: () => unknown;
168
+ applyState: (state: unknown) => void;
169
+ }) => void;
170
+ }
171
+ ) => void | (() => void);
172
+ ```
173
+
174
+ Factory receives a callback to register state handlers:
175
+ ```typescript
176
+ layout.registerItem('my-component', (container, stateManager) => {
177
+ const root = createRoot(container);
178
+ let componentState = null;
179
+
180
+ root.render(<MyComponent onStateChange={(s) => componentState = s} />);
181
+
182
+ stateManager?.registerStateHandlers({
183
+ getCurrentState: () => componentState,
184
+ applyState: (state) => componentState = state
185
+ });
186
+
187
+ return () => root.unmount();
188
+ });
189
+ ```
190
+
191
+ **Option 3: Framework-Specific Wrappers**
192
+ Create helper functions that handle state automatically:
193
+ ```typescript
194
+ // React helper
195
+ function createReactLayoutComponent(Component, getStateFromProps, applyStateToProps) {
196
+ return (container) => {
197
+ const root = createRoot(container);
198
+ // ... state management logic
199
+ return { cleanup, getCurrentState, applyState };
200
+ };
201
+ }
202
+ ```
203
+
204
+ ## Declarative HTML API with Factory Functions
205
+
206
+ The `foundation-layout-item` component supports factory functions for the declarative HTML API, enabling framework components to work properly while preserving event listeners and lifecycle management.
207
+
208
+ ### Recommended Approach: Factory Registry Pattern
209
+
210
+ The factory registry uses the `registration` attribute as the lookup key for pre-registered factory functions. This provides a clean, unified API where the same name identifies the component in both the registry and the layout.
211
+
212
+ #### How It Works
213
+
214
+ 1. Register factory functions using `registerFactory(key, factory)`
215
+ 2. Use the same key as the `registration` attribute in your layout item
216
+ 3. The layout automatically looks up the factory when the item connects
217
+
218
+ ```typescript
219
+ // Simple and unified API:
220
+ registerFactory('my-component', factoryFunction);
221
+
222
+ // Then in HTML/JSX:
223
+ <rapid-layout-item registration="my-component" title="My Component" />
224
+ ```
225
+
226
+ **Priority order when layout item connects:**
227
+ 1. Factory from registry (using registration name) ✅
228
+ 2. Slotted content (backward compatible) ✅
229
+
230
+ ### React Example (Recommended)
231
+
232
+ Register factories **before** rendering using the same names as your layout item registrations:
233
+
234
+ ```tsx
235
+ import { registerFactory } from '@genesislcap/foundation-layout';
236
+ import { reactFactory, reactFactoryWithProvider } from './utils/react-layout-factory';
237
+ import { Provider } from 'react-redux';
238
+ import { TableComponent, TextFieldComponent } from './components';
239
+
240
+ // Register factories at module level using the same names as registrations
241
+ registerFactory('table', reactFactory(TableComponent));
242
+ registerFactory('table-with-redux', reactFactoryWithProvider(
243
+ TableComponent,
244
+ Provider,
245
+ { store: reduxStore }
246
+ ));
247
+ registerFactory('textfield', reactFactoryWithProvider(
248
+ TextFieldComponent,
249
+ Provider,
250
+ { store: reduxStore }
251
+ ));
252
+
253
+ function MyLayout() {
254
+ return (
255
+ <rapid-layout>
256
+ <rapid-layout-region>
257
+ {/* Simple component - registration name matches factory key */}
258
+ <rapid-layout-item
259
+ registration="table"
260
+ title="Table"
261
+ closable
262
+ />
263
+
264
+ {/* Component with Redux provider */}
265
+ <rapid-layout-item
266
+ registration="table-with-redux"
267
+ title="Table (with Redux)"
268
+ closable
269
+ />
270
+
271
+ {/* Component with custom size */}
272
+ <rapid-layout-item
273
+ registration="textfield"
274
+ title="Text Field"
275
+ size="33%"
276
+ />
277
+ </rapid-layout-region>
278
+ </rapid-layout>
279
+ );
280
+ }
281
+ ```
282
+
283
+ **Helper utility (`react-layout-factory.tsx`):**
284
+
285
+ ```typescript
286
+ import { ComponentFactory } from '@genesislcap/foundation-layout';
287
+ import { createRoot, Root } from 'react-dom/client';
288
+ import type { ComponentType, ReactElement } from 'react';
289
+
290
+ export function reactFactory<P = {}>(
291
+ Component: ComponentType<P>,
292
+ props?: P
293
+ ): ComponentFactory {
294
+ return (container: HTMLElement) => {
295
+ const root: Root = createRoot(container);
296
+ root.render(<Component {...(props || ({} as P))} />);
297
+ return () => root.unmount(); // Cleanup
298
+ };
299
+ }
300
+
301
+ export function reactFactoryWithProvider<CP = {}, WP = {}>(
302
+ Component: ComponentType<CP>,
303
+ Wrapper: ComponentType<WP & { children: ReactElement }>,
304
+ wrapperProps: WP,
305
+ componentProps?: CP
306
+ ): ComponentFactory {
307
+ return (container: HTMLElement) => {
308
+ const root: Root = createRoot(container);
309
+ root.render(
310
+ <Wrapper {...wrapperProps}>
311
+ <Component {...(componentProps || ({} as CP))} />
312
+ </Wrapper>
313
+ );
314
+ return () => root.unmount();
315
+ };
316
+ }
317
+ ```
318
+
319
+ ### Angular Example
320
+
321
+ Register factories in your component setup using the same names as registrations:
322
+
323
+ ```typescript
324
+ import { Component, OnInit, Injector } from '@angular/core';
325
+ import { registerFactory, ComponentFactory } from '@genesislcap/foundation-layout';
326
+ import { createComponent } from '@angular/core';
327
+ import { MyAngularComponent } from './my-angular.component';
328
+
329
+ @Component({
330
+ selector: 'app-layout',
331
+ template: `
332
+ <rapid-layout>
333
+ <rapid-layout-region>
334
+ <rapid-layout-item
335
+ registration="angular-comp"
336
+ title="Angular Component">
337
+ </rapid-layout-item>
338
+ </rapid-layout-region>
339
+ </rapid-layout>
340
+ `
341
+ })
342
+ export class LayoutComponent implements OnInit {
343
+ constructor(private injector: Injector) {}
344
+
345
+ ngOnInit() {
346
+ // Register factory using the same name as the registration
347
+ registerFactory('angular-comp', (container: HTMLElement) => {
348
+ const componentRef = createComponent(MyAngularComponent, {
349
+ environmentInjector: this.injector,
350
+ hostElement: container
351
+ });
352
+ componentRef.changeDetectorRef.detectChanges();
353
+
354
+ return () => componentRef.destroy();
355
+ });
356
+ }
357
+ }
358
+ ```
359
+
360
+ ### Vue 3 Example
361
+
362
+ Register factories before mounting using the same names as registrations:
363
+
364
+ ```typescript
365
+ import { createApp } from 'vue';
366
+ import { registerFactory } from '@genesislcap/foundation-layout';
367
+ import MyVueComponent from './MyVueComponent.vue';
368
+
369
+ // Register factory using the same name as the registration
370
+ registerFactory('vue-comp', (container: HTMLElement) => {
371
+ const app = createApp(MyVueComponent);
372
+ app.mount(container);
373
+
374
+ return () => app.unmount();
375
+ });
376
+ ```
377
+
378
+ Then in your template:
379
+
380
+ ```html
381
+ <rapid-layout>
382
+ <rapid-layout-region>
383
+ <rapid-layout-item
384
+ registration="vue-comp"
385
+ title="Vue Component">
386
+ </rapid-layout-item>
387
+ </rapid-layout-region>
388
+ </rapid-layout>
389
+ ```
390
+
391
+ ### FAST Bindings Example
392
+
393
+ Register factories in your setup code using the same names as registrations:
394
+
395
+ ```typescript
396
+ import { registerFactory } from '@genesislcap/foundation-layout';
397
+
398
+ registerFactory('grid', (container: HTMLElement) => {
399
+ const grid = document.createElement('rapid-grid');
400
+ // Configure grid...
401
+ container.appendChild(grid);
402
+
403
+ return () => grid.remove();
404
+ });
405
+ ```
406
+
407
+ Then use in your FAST template:
408
+
409
+ ```html
410
+ <rapid-layout>
411
+ <rapid-layout-region>
412
+ <rapid-layout-item
413
+ registration="grid"
414
+ title="Data Grid">
415
+ </rapid-layout-item>
416
+ </rapid-layout-region>
417
+ </rapid-layout>
418
+ ```
419
+
420
+ ### Factory Registry API
421
+
422
+ **`registerFactory(key: string, factory: ComponentFactory): void`**
423
+ - Registers a factory function with a unique key
424
+ - Key should be descriptive and unique across your application
425
+ - Logs a warning if key is already registered (will overwrite)
426
+
427
+ **`getFactory(key: string): ComponentFactory | undefined`**
428
+ - Retrieves a factory by its key
429
+ - Returns `undefined` if key not found
430
+ - Primarily for internal use by the layout system
431
+
432
+ **`unregisterFactory(key: string): boolean`**
433
+ - Removes a factory from the registry
434
+ - Returns `true` if factory was found and removed
435
+ - Useful for cleanup when components are unmounted
436
+
437
+ **Example:**
438
+ ```typescript
439
+ import { registerFactory, unregisterFactory } from '@genesislcap/foundation-layout';
440
+
441
+ // Register
442
+ registerFactory('my-component', myFactoryFunction);
443
+
444
+ // Later, cleanup
445
+ unregisterFactory('my-component');
446
+ ```
447
+
448
+ ### Validation Rules
449
+
450
+ The layout system enforces two important validation rules to prevent conflicts:
451
+
452
+ **Rule 1: Cannot register via JavaScript API if factory exists**
453
+ ```typescript
454
+ registerFactory('my-component', myFactory);
455
+ layout.registerItem('my-component', elements); // ❌ ERROR!
456
+ // LayoutRegistrationError: Registration "my-component" already has a factory registered
457
+ ```
458
+
459
+ **Rule 2: Cannot mix factory and slotted content**
460
+ ```typescript
461
+ registerFactory('my-component', myFactory);
462
+ // ❌ ERROR - Has both factory AND slotted content
463
+ <rapid-layout-item registration="my-component">
464
+ <div>Content</div>
465
+ </rapid-layout-item>
466
+ // LayoutUsageError: Cannot use both factory registration and slotted content
467
+ ```
468
+
469
+ **Valid Usage Patterns:**
470
+ ```typescript
471
+ // ✅ Declarative with factory
472
+ registerFactory('comp-1', myFactory);
473
+ <rapid-layout-item registration="comp-1" />
474
+
475
+ // ✅ Declarative with slotted content (no factory)
476
+ <rapid-layout-item registration="comp-2">
477
+ <div>Content</div>
478
+ </rapid-layout-item>
479
+
480
+ // ✅ JavaScript API (no factory in registry)
481
+ layout.registerItem('comp-3', elements);
482
+ ```
483
+
484
+ ### Key Points
485
+
486
+ ✅ **Unified API:**
487
+ - Use the `registration` attribute as both the component identifier and factory key
488
+ - Register factories with `registerFactory(name, factory)` before rendering
489
+ - Simpler API with no duplication between registration and factory-key
490
+ - Guarantees factory availability when custom element connects
491
+
492
+ ✅ **What Works:**
493
+ - Event listeners are preserved
494
+ - Framework lifecycle methods work correctly
495
+ - Multiple instances can be created
496
+ - Cleanup is handled automatically
497
+ - Works with React, Angular, Vue, FAST, and any other framework
498
+
499
+ ✅ **Backward Compatibility:**
500
+ - Slotted content still works when no factory is registered
501
+ - No breaking changes to existing code using slotted elements
502
+ - Priority order: factory (using registration name) → slotted content
503
+
504
+ ✅ **Validation:**
505
+ - Cannot register via JavaScript API if a factory exists with that name
506
+ - Cannot mix factory registration with slotted content
507
+ - Clear error messages guide proper usage
508
+
509
+ ### Comparison: JavaScript API vs Declarative API
510
+
511
+ | Aspect | JavaScript API | Declarative API (with factory registry) |
512
+ |--------|----------------|-------------------------------|
513
+ | **Usage** | Programmatic registration | HTML/JSX markup |
514
+ | **Setup** | Requires `useEffect` or lifecycle hooks | Register factories, then use in template |
515
+ | **Dynamic Items** | Easy to add/remove items | Static structure |
516
+ | **Type Safety** | Full TypeScript support | Depends on framework bindings |
517
+ | **Factory Approach** | Direct function passing | Registry with registration name as key |
518
+ | **When to Use** | Complex layouts with dynamic items | Simple, static layouts |
519
+
520
+ **Recommendation:** Use the JavaScript API for dynamic layouts where items are added/removed programmatically. Use the declarative API with factory registration for simpler layouts with a fixed set of items.
521
+
522
+ ## Best Practices
523
+
524
+ ### When to Use Factory Functions
525
+
526
+ Use factory functions when:
527
+ - Components have JavaScript event listeners
528
+ - Components use framework-specific features (React hooks, Angular services, Vue composition API)
529
+ - Components need to be instantiated multiple times
530
+ - Components need cleanup logic
531
+
532
+ ### When Element Arrays Are OK
533
+
534
+ Element arrays still work great for:
535
+ - Static HTML content
536
+ - Native web components without event listeners
537
+ - FAST components using FAST's binding system (these handle cloning correctly)
538
+
539
+ ### Example: Mixed Approach
540
+
541
+ ```typescript
542
+ // Factory for React component with events
543
+ layout.registerItem('interactive-form', (container) => {
544
+ const root = createRoot(container);
545
+ root.render(<FormComponent />);
546
+ return () => root.unmount();
547
+ });
548
+
549
+ // Element array for static content
550
+ const staticDiv = document.createElement('div');
551
+ staticDiv.innerHTML = '<h1>Static Content</h1>';
552
+ layout.registerItem('static-content', [staticDiv]);
553
+ ```
554
+
555
+ ## Questions or Issues?
556
+
557
+ If you encounter problems with framework components in the layout:
558
+ 1. Check if you're using the factory function pattern
559
+ 2. Verify cleanup functions are properly implemented
560
+ 3. Check browser console for React/Angular/Vue warnings
561
+ 4. File an issue with reproduction steps
562
+
563
+ ## Related Documentation
564
+
565
+ - [Layout README](../README.md)
566
+ - [API Documentation](./api/foundation-layout.foundationlayout.md)
567
+ - [Element Cloning Limitations](../README.md#binding-events-inline-in-the-declarative-api)
568
+
@@ -0,0 +1,46 @@
1
+ <!-- Do not edit this file. It is automatically generated by API Documenter. -->
2
+
3
+ [Home](./index.md) &gt; [@genesislcap/foundation-layout](./foundation-layout.md) &gt; [ComponentFactory](./foundation-layout.componentfactory.md)
4
+
5
+ ## ComponentFactory type
6
+
7
+ Factory function for creating component instances in the layout.
8
+
9
+ **Signature:**
10
+
11
+ ```typescript
12
+ export type ComponentFactory = (container: HTMLElement) => void | (() => void);
13
+ ```
14
+
15
+ ## Remarks
16
+
17
+ This is the recommended approach for framework-rendered components (React, Angular, Vue, etc.) because it allows each layout instance to create a fresh component rather than cloning existing DOM elements (which loses event listeners and framework bindings).
18
+
19
+ The factory function receives a container element and should render the component into it. Optionally, it can return a cleanup function that will be called when the component is removed from the layout.
20
+
21
+ ## Example 1
22
+
23
+ React example:
24
+
25
+ ```typescript
26
+ layout.registerItem('my-component', (container) => {
27
+ const root = createRoot(container);
28
+ root.render(<MyComponent />);
29
+ return () => root.unmount();
30
+ });
31
+ ```
32
+
33
+ ## Example 2
34
+
35
+ Angular example:
36
+
37
+ ```typescript
38
+ layout.registerItem('my-component', (container) => {
39
+ const componentRef = createComponent(MyComponent, {
40
+ environmentInjector: this.injector,
41
+ hostElement: container
42
+ });
43
+ return () => componentRef.destroy();
44
+ });
45
+ ```
46
+
@@ -342,7 +342,7 @@ Gets all of the currently registered names
342
342
  </td></tr>
343
343
  <tr><td>
344
344
 
345
- [registerItem(registration, elements)](./foundation-layout.foundationlayout.registeritem.md)
345
+ [registerItem(registration, elementsOrFactory)](./foundation-layout.foundationlayout.registeritem.md)
346
346
 
347
347
 
348
348
  </td><td>
@@ -350,7 +350,7 @@ Gets all of the currently registered names
350
350
 
351
351
  </td><td>
352
352
 
353
- Register a collection of `Element` and associate them with an `ID` with the layout system for later use.
353
+ Register a collection of `Element` or a factory function and associate them with an `ID` with the layout system for later use.
354
354
 
355
355
 
356
356
  </td></tr>
@@ -4,12 +4,12 @@
4
4
 
5
5
  ## FoundationLayout.registerItem() method
6
6
 
7
- Register a collection of `Element` and associate them with an `ID` with the layout system for later use.
7
+ Register a collection of `Element` or a factory function and associate them with an `ID` with the layout system for later use.
8
8
 
9
9
  **Signature:**
10
10
 
11
11
  ```typescript
12
- registerItem(registration: string, elements: Element[]): string;
12
+ registerItem(registration: string, elementsOrFactory: Element[] | ComponentFactory): string;
13
13
  ```
14
14
 
15
15
  ## Parameters
@@ -48,17 +48,17 @@ string of the registration ID
48
48
  </td></tr>
49
49
  <tr><td>
50
50
 
51
- elements
51
+ elementsOrFactory
52
52
 
53
53
 
54
54
  </td><td>
55
55
 
56
- Element\[\]
56
+ Element\[\] \| [ComponentFactory](./foundation-layout.componentfactory.md)
57
57
 
58
58
 
59
59
  </td><td>
60
60
 
61
- Elements\[\] containing the reference to the elements to register for later usage
61
+ Either Elements\[\] containing the reference to the elements to register, or a ComponentFactory function
62
62
 
63
63
 
64
64
  </td></tr>
@@ -78,7 +78,31 @@ string
78
78
 
79
79
  ## Remarks
80
80
 
81
- You would use this to register elements that you later want to load when using [FoundationLayout.loadLayout()](./foundation-layout.foundationlayout.loadlayout.md)<!-- -->. Use [FoundationLayout.layoutRequiredRegistrations()](./foundation-layout.foundationlayout.layoutrequiredregistrations.md) to see what components need to be registered for a certain config and then register them using this function before calling [FoundationLayout.loadLayout()](./foundation-layout.foundationlayout.loadlayout.md)<!-- -->.
81
+ You can register either an array of elements or a factory function.
82
82
 
83
- When registering an element it is moved by reference into the internals of the layout, so if you pass elements already in the DOM then they will disappear. If you want to avoid this you can pass copies using `element.cloneNode(true)`<!-- -->.
83
+ \*\*Element registration\*\*: Use this to register elements that you later want to load when using [FoundationLayout.loadLayout()](./foundation-layout.foundationlayout.loadlayout.md)<!-- -->. Use [FoundationLayout.layoutRequiredRegistrations()](./foundation-layout.foundationlayout.layoutrequiredregistrations.md) to see what components need to be registered for a certain config and then register them using this function before calling [FoundationLayout.loadLayout()](./foundation-layout.foundationlayout.loadlayout.md)<!-- -->. When registering an element it is moved by reference into the internals of the layout, so if you pass elements already in the DOM then they will disappear. If you want to avoid this you can pass copies using `element.cloneNode(true)`<!-- -->.
84
+
85
+ \*\*Factory registration\*\*: This is the recommended approach for framework-rendered components (React, Angular, Vue, etc.) because it allows each layout instance to create a fresh component rather than cloning existing DOM elements (which loses event listeners and framework bindings). The factory function will be called each time a new instance of the component is needed. It receives a container element and should render the component into it. Optionally, it can return a cleanup function that will be called when the component is removed from the layout.
86
+
87
+ ## Example 1
88
+
89
+ Element registration:
90
+
91
+ ```typescript
92
+ const div = document.createElement('div');
93
+ div.innerHTML = '<h1>Hello</h1>';
94
+ layout.registerItem('my-element', [div]);
95
+ ```
96
+
97
+ ## Example 2
98
+
99
+ Factory registration (React):
100
+
101
+ ```typescript
102
+ layout.registerItem('text-field', (container) => {
103
+ const root = createRoot(container);
104
+ root.render(<TextFieldComponent />);
105
+ return () => root.unmount();
106
+ });
107
+ ```
84
108