@se-studio/core-ui 1.0.45 → 1.0.47

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 (86) hide show
  1. package/ANALYTICS.md +136 -0
  2. package/CHANGELOG.md +466 -0
  3. package/CMS_INFRASTRUCTURE.md +335 -0
  4. package/CONSENT.md +121 -0
  5. package/README.md +13 -8
  6. package/dist/cmsRegistration.d.ts +152 -0
  7. package/dist/cmsRegistration.d.ts.map +1 -0
  8. package/dist/cmsRegistration.js +145 -0
  9. package/dist/cmsRegistration.js.map +1 -0
  10. package/dist/components/CmsCollection.d.ts +2 -1
  11. package/dist/components/CmsCollection.d.ts.map +1 -1
  12. package/dist/components/CmsCollection.js +1 -1
  13. package/dist/components/CmsCollection.js.map +1 -1
  14. package/dist/components/CmsComponent.d.ts +2 -1
  15. package/dist/components/CmsComponent.d.ts.map +1 -1
  16. package/dist/components/CmsComponent.js.map +1 -1
  17. package/dist/index.d.ts +6 -4
  18. package/dist/index.d.ts.map +1 -1
  19. package/dist/index.js +6 -3
  20. package/dist/index.js.map +1 -1
  21. package/dist/showcase/components/AllViewPanel.d.ts +7 -0
  22. package/dist/showcase/components/AllViewPanel.d.ts.map +1 -0
  23. package/dist/showcase/components/AllViewPanel.js +35 -0
  24. package/dist/showcase/components/AllViewPanel.js.map +1 -0
  25. package/dist/showcase/components/Controls.d.ts +15 -0
  26. package/dist/showcase/components/Controls.d.ts.map +1 -0
  27. package/dist/showcase/components/Controls.js +74 -0
  28. package/dist/showcase/components/Controls.js.map +1 -0
  29. package/dist/showcase/components/ControlsWrapper.d.ts +13 -0
  30. package/dist/showcase/components/ControlsWrapper.d.ts.map +1 -0
  31. package/dist/showcase/components/ControlsWrapper.js +9 -0
  32. package/dist/showcase/components/ControlsWrapper.js.map +1 -0
  33. package/dist/showcase/components/PreviewPanel.d.ts +10 -0
  34. package/dist/showcase/components/PreviewPanel.d.ts.map +1 -0
  35. package/dist/showcase/components/PreviewPanel.js +42 -0
  36. package/dist/showcase/components/PreviewPanel.js.map +1 -0
  37. package/dist/showcase/components/ScaledIframe.d.ts +10 -0
  38. package/dist/showcase/components/ScaledIframe.d.ts.map +1 -0
  39. package/dist/showcase/components/ScaledIframe.js +16 -0
  40. package/dist/showcase/components/ScaledIframe.js.map +1 -0
  41. package/dist/showcase/components/ShowcaseAllRenderPage.d.ts +19 -0
  42. package/dist/showcase/components/ShowcaseAllRenderPage.d.ts.map +1 -0
  43. package/dist/showcase/components/ShowcaseAllRenderPage.js +46 -0
  44. package/dist/showcase/components/ShowcaseAllRenderPage.js.map +1 -0
  45. package/dist/showcase/components/ShowcasePage.d.ts +15 -0
  46. package/dist/showcase/components/ShowcasePage.d.ts.map +1 -0
  47. package/dist/showcase/components/ShowcasePage.js +16 -0
  48. package/dist/showcase/components/ShowcasePage.js.map +1 -0
  49. package/dist/showcase/components/ShowcaseRenderPage.d.ts +19 -0
  50. package/dist/showcase/components/ShowcaseRenderPage.d.ts.map +1 -0
  51. package/dist/showcase/components/ShowcaseRenderPage.js +51 -0
  52. package/dist/showcase/components/ShowcaseRenderPage.js.map +1 -0
  53. package/dist/showcase/components/TopBar.d.ts +11 -0
  54. package/dist/showcase/components/TopBar.d.ts.map +1 -0
  55. package/dist/showcase/components/TopBar.js +103 -0
  56. package/dist/showcase/components/TopBar.js.map +1 -0
  57. package/dist/showcase/index.d.ts +12 -0
  58. package/dist/showcase/index.d.ts.map +1 -0
  59. package/dist/showcase/index.js +12 -0
  60. package/dist/showcase/index.js.map +1 -0
  61. package/dist/showcase/mockFactory.d.ts +34 -0
  62. package/dist/showcase/mockFactory.d.ts.map +1 -0
  63. package/dist/showcase/mockFactory.js +352 -0
  64. package/dist/showcase/mockFactory.js.map +1 -0
  65. package/dist/showcase/types.d.ts +20 -0
  66. package/dist/showcase/types.d.ts.map +1 -0
  67. package/dist/showcase/types.js +18 -0
  68. package/dist/showcase/types.js.map +1 -0
  69. package/dist/utils/buildPageMetadata.d.ts +20 -1
  70. package/dist/utils/buildPageMetadata.d.ts.map +1 -1
  71. package/dist/utils/buildPageMetadata.js +37 -0
  72. package/dist/utils/buildPageMetadata.js.map +1 -1
  73. package/dist/utils/componentUtils.d.ts +39 -146
  74. package/dist/utils/componentUtils.d.ts.map +1 -1
  75. package/dist/utils/componentUtils.js +142 -101
  76. package/dist/utils/componentUtils.js.map +1 -1
  77. package/dist/utils/urlUtils.d.ts +5 -0
  78. package/dist/utils/urlUtils.d.ts.map +1 -1
  79. package/dist/utils/urlUtils.js +10 -0
  80. package/dist/utils/urlUtils.js.map +1 -1
  81. package/package.json +9 -6
  82. package/src/showcase/README.md +131 -0
  83. package/dist/__tests__/setup.d.ts +0 -2
  84. package/dist/__tests__/setup.d.ts.map +0 -1
  85. package/dist/__tests__/setup.js +0 -2
  86. package/dist/__tests__/setup.js.map +0 -1
@@ -0,0 +1,335 @@
1
+ # CMS Component Mapping Infrastructure
2
+
3
+ This document describes the CMS component mapping infrastructure extracted from the Point.me marketing-site project into the core-ui package.
4
+
5
+ ## Table of Contents
6
+
7
+ - [Overview](#overview)
8
+ - [Architecture](#architecture)
9
+ - [Core Concepts](#core-concepts)
10
+ - [File Structure](#file-structure)
11
+ - [Usage Guide](#usage-guide)
12
+ - [1. Create Your Renderer Configuration](#1-create-your-renderer-configuration)
13
+ - [2. Use CmsContent with Your Configuration](#2-use-cmscontent-with-your-configuration)
14
+ - [3. Use UnusedChecker for Development](#3-use-unusedchecker-for-development)
15
+ - [Configuration Composition](#configuration-composition)
16
+ - [Preview Mode Configuration](#preview-mode-configuration)
17
+ - [Environment-Specific Configurations](#environment-specific-configurations)
18
+ - [Embedded Context Configuration](#embedded-context-configuration)
19
+ - [Type System](#type-system)
20
+ - [BaseCmsConfig](#basecmsconfig)
21
+ - [CmsRendererConfig](#cmsrendererconfig)
22
+ - [Context Types](#context-types)
23
+ - [Development Features](#development-features)
24
+ - [Unknown Type Warnings](#unknown-type-warnings)
25
+ - [Generic Fallbacks](#generic-fallbacks)
26
+ - [Type Safety](#type-safety)
27
+ - [Benefits Over Ad-Hoc Rendering](#benefits-over-ad-hoc-rendering)
28
+ - [Migration from Marketing-Site](#migration-from-marketing-site)
29
+ - [Examples](#examples)
30
+ - [API Reference](#api-reference)
31
+ - [CmsContent Props](#cmscontent-props)
32
+ - [Future Enhancements](#future-enhancements)
33
+
34
+ ## Overview
35
+
36
+ The infrastructure provides a type-safe, extensible system for mapping CMS content types to React components. It supports:
37
+
38
+ - **Component/Collection Mapping**: Registry pattern for routing content types to renderers
39
+ - **Embedding System**: Components can be rendered in embedded contexts (like rich text)
40
+ - **Generic Fallbacks**: Automatic fallback rendering for unmapped types
41
+ - **Development Utilities**: Warnings for unused props and rendering errors
42
+
43
+ ## Architecture
44
+
45
+ ### Core Concepts
46
+
47
+ 1. **Content Routing**: `CmsContent` receives an array of mixed content types and routes each to the appropriate renderer
48
+ 2. **Type Mapping**: `ComponentMap` and `CollectionMap` define which React components render which content types
49
+ 3. **Embedded Rendering**: Components can be rendered in embedded contexts (like rich text)
50
+
51
+ ### File Structure
52
+
53
+ ```
54
+ packages/core-ui/src/
55
+ ├── components/
56
+ │ ├── CmsComponent.tsx # Component type router
57
+ │ ├── CmsCollection.tsx # Collection type router
58
+ │ ├── CmsContent.tsx # Main content renderer
59
+ │ ├── GenericComponent.tsx # Fallback component renderer
60
+ │ └── GenericCollection.tsx # Fallback collection renderer
61
+ ├── embeddable/
62
+ │ ├── EmbeddableContext.ts # Context types for embedded rendering
63
+ │ ├── BuildEmbed.tsx # Factory functions for embeddable components
64
+ │ └── EmbeddableMaps.ts # Type definitions for embeddable maps
65
+ └── utils/
66
+ ├── componentUtils.ts # Related content fetching
67
+ └── UnusedChecker.tsx # Development warning utility
68
+ ```
69
+
70
+ ## Usage Guide
71
+
72
+ ### 1. Create Your Renderer Configuration
73
+
74
+ The recommended approach is to create a single `CmsRendererConfig` object that bundles all your renderer maps and options:
75
+
76
+ ```tsx
77
+ import { createCmsRendererConfig } from "@se-studio/core-ui";
78
+ import type { MyProjectConfig } from "./types";
79
+
80
+ // Import your component renderers
81
+ import { HeroComponent } from "@/components/Hero";
82
+ import { CTAComponent } from "@/components/CTA";
83
+ import { ContentBlock } from "@/components/ContentBlock";
84
+
85
+ // Import your collection renderers
86
+ import { FAQCollection } from "@/components/FAQCollection";
87
+ import { RelatedArticles } from "@/components/RelatedArticles";
88
+
89
+ // Import special renderers (optional)
90
+ import { VisualRenderer } from "@/components/VisualRenderer";
91
+ import { InternalLinkRenderer } from "@/components/InternalLinkRenderer";
92
+
93
+ /**
94
+ * Main CMS renderer configuration for the project.
95
+ * Create this once and reuse it throughout your app.
96
+ */
97
+ export const rendererConfig = createCmsRendererConfig<MyProjectConfig>({
98
+ componentMap: {
99
+ "Hero": HeroComponent,
100
+ "CTA": CTAComponent,
101
+ "Content Block": ContentBlock,
102
+ },
103
+ collectionMap: {
104
+ "FAQs": FAQCollection,
105
+ "Related Articles": RelatedArticles,
106
+ },
107
+ // Optional: external components, visuals, links
108
+ externalComponentMap: {
109
+ "Contact Form": ContactFormRenderer,
110
+ },
111
+ visualComponentRenderer: VisualRenderer,
112
+ internalLinkRenderer: InternalLinkRenderer,
113
+ // Show errors in development mode
114
+ showUnknownTypeErrors: process.env.NODE_ENV === 'development',
115
+ showRenderErrors: process.env.NODE_ENV === 'development',
116
+ });
117
+ ```
118
+
119
+ ### 2. Use CmsContent with Your Configuration
120
+
121
+ ```tsx
122
+ import { CmsContent } from "@se-studio/core-ui";
123
+ import { rendererConfig } from "@/cms/rendererConfig";
124
+
125
+ export function PageRenderer({ page }) {
126
+ const pageContext = {
127
+ pageLink: { slug: page.slug, title: page.title },
128
+ };
129
+
130
+ return (
131
+ <CmsContent
132
+ rendererConfig={rendererConfig}
133
+ pageContext={pageContext}
134
+ contents={page.contents}
135
+ />
136
+ );
137
+ }
138
+ ```
139
+
140
+ **Benefits of this approach:**
141
+ - **Clean API**: Only 3 props instead of 7+ individual props
142
+ - **Single source of truth**: All renderer configuration in one place
143
+ - **Easy to extend**: Add new renderer types without touching every CmsContent call
144
+ - **Type-safe**: Full TypeScript support with generics
145
+ - **Composable**: Create variants with `mergeCmsRendererConfig()`
146
+
147
+ ### 3. Use UnusedChecker for Development
148
+
149
+ Catch unused CMS properties that aren't being rendered:
150
+
151
+ ```tsx
152
+ import { UnusedChecker } from "@se-studio/core-ui";
153
+
154
+ export const MyComponent = ({ information, contentContext }) => {
155
+ const { heading, body, links, ...unused } = information;
156
+
157
+ return (
158
+ <UnusedChecker
159
+ componentName="MyComponent"
160
+ unused={unused}
161
+ showWarnings={true}
162
+ >
163
+ <div>
164
+ <h2>{heading}</h2>
165
+ <p>{body}</p>
166
+ </div>
167
+ </UnusedChecker>
168
+ );
169
+ };
170
+ ```
171
+
172
+ ## Configuration Composition
173
+
174
+ The `mergeCmsRendererConfig()` utility allows you to create specialized configurations from a base config:
175
+
176
+ ### Preview Mode Configuration
177
+
178
+ ```tsx
179
+ import { mergeCmsRendererConfig } from "@se-studio/core-ui";
180
+
181
+ const baseConfig = createCmsRendererConfig({ ... });
182
+
183
+ // Preview config with all errors displayed
184
+ export const previewConfig = mergeCmsRendererConfig(baseConfig, {
185
+ showUnknownTypeErrors: true,
186
+ showRenderErrors: true,
187
+ });
188
+
189
+ // Use in preview routes
190
+ <CmsContent rendererConfig={previewConfig} ... />
191
+ ```
192
+
193
+ ### Environment-Specific Configurations
194
+
195
+ ```tsx
196
+ const productionConfig = createCmsRendererConfig({
197
+ componentMap: { ... },
198
+ collectionMap: { ... },
199
+ showUnknownTypeErrors: false,
200
+ showRenderErrors: false,
201
+ });
202
+
203
+ const developmentConfig = mergeCmsRendererConfig(productionConfig, {
204
+ showUnknownTypeErrors: true,
205
+ showRenderErrors: true,
206
+ });
207
+
208
+ export const rendererConfig =
209
+ process.env.NODE_ENV === 'production'
210
+ ? productionConfig
211
+ : developmentConfig;
212
+ ```
213
+
214
+ ### Embedded Context Configuration
215
+
216
+ ```tsx
217
+ // Different component map for embedded contexts
218
+ const embeddedConfig = mergeCmsRendererConfig(baseConfig, {
219
+ componentMap: {
220
+ ...baseConfig.componentMap,
221
+ "Hero": EmbeddedHeroComponent, // Use simplified version
222
+ },
223
+ });
224
+ ```
225
+
226
+ ## Type System
227
+
228
+ ### BaseCmsConfig
229
+
230
+ Projects must extend `BaseCmsConfig` to define their CMS-specific types:
231
+
232
+ ```tsx
233
+ import type { BaseCmsConfig } from "@se-studio/core-data-types";
234
+
235
+ export interface MyProjectConfig extends BaseCmsConfig {
236
+ ComponentType: "Hero" | "CTA" | "Content Block";
237
+ CollectionType: "FAQs" | "Related Articles";
238
+ ExternalComponentType: "ContactForm" | "Newsletter";
239
+ ColourName: "red" | "blue" | "green";
240
+ // ... other type overrides
241
+ }
242
+ ```
243
+
244
+ ### CmsRendererConfig
245
+
246
+ The main configuration type that bundles all renderer maps:
247
+
248
+ ```tsx
249
+ interface CmsRendererConfig<TConfig extends BaseCmsConfig> {
250
+ componentMap: ComponentMap<TConfig>;
251
+ collectionMap: CollectionMap<TConfig>;
252
+ externalComponentMap?: ExternalComponentMap<TConfig>;
253
+ visualComponentRenderer?: VisualComponentRenderer<TConfig>;
254
+ internalLinkRenderer?: InternalLinkRenderer<TConfig>;
255
+ showUnknownTypeErrors?: boolean;
256
+ showRenderErrors?: boolean;
257
+ }
258
+ ```
259
+
260
+ ### Context Types
261
+
262
+ - `IPageContext<TConfig>`: Page-level context (article, page, tag links)
263
+ - `IContentContext<TConfig>`: Content-level context (current, previous, next content)
264
+ - `IEmbeddableComponentContext<TConfig>`: Context for embedded components
265
+ - `IEmbeddableCollectionContext<TConfig>`: Context for embedded collections
266
+
267
+ ## Development Features
268
+
269
+ ### Unknown Type Warnings
270
+
271
+ In development mode, the infrastructure displays visual warnings for:
272
+ - Unmapped component/collection types
273
+ - Rendering errors
274
+ - Unused CMS properties
275
+
276
+ ### Generic Fallbacks
277
+
278
+ When a component/collection type isn't mapped:
279
+ 1. A warning is logged to console
280
+ 2. In dev mode, an error panel is displayed
281
+ 3. A generic fallback renderer is used
282
+ 4. The page continues to render (no crashes)
283
+
284
+ ### Type Safety
285
+
286
+ - Full TypeScript support with generic types
287
+ - Development warnings catch unused properties
288
+
289
+ ## Benefits Over Ad-Hoc Rendering
290
+
291
+ 1. **Centralized Mapping**: All component mappings in one place
292
+ 2. **Reusability**: Components work in multiple contexts (full-page, embedded)
293
+ 3. **Maintainability**: Changes to component structure are caught at compile-time
294
+ 4. **Development UX**: Clear warnings for mistakes
295
+ 5. **Fallback Handling**: Pages never break from unmapped types
296
+
297
+ ## Migration from Marketing-Site
298
+
299
+ To migrate an existing project:
300
+
301
+ 1. Install core-ui: `pnpm add @se-studio/core-ui`
302
+ 2. Create ComponentMap and CollectionMap
303
+ 3. Replace direct component rendering with CmsContent
304
+ 4. Test with `showUnknownTypeErrors={true}` to find missing mappings
305
+
306
+ ## Examples
307
+
308
+ See the example apps in this monorepo for complete working implementations:
309
+ - `apps/example-pointme`: Full Point.me-style implementation
310
+ - `apps/example-hsd`: Alternative implementation pattern
311
+
312
+ ## API Reference
313
+
314
+ ### CmsContent Props
315
+
316
+ - `pageContext`: Page-level context information
317
+ - `contents`: Array of content to render
318
+ - `componentMap`: Map of component types to renderers
319
+ - `collectionMap`: Map of collection types to renderers
320
+ - `externalComponentMap`: Map of external component types to renderers (optional)
321
+ - `visualComponentRenderer`: Renderer for Visual content types (optional)
322
+ - `internalLinkRenderer`: Renderer for Internal Link content types (optional)
323
+ - `showUnknownTypeErrors`: Show error panels for unknown types (default: false)
324
+ - `showRenderErrors`: Show error panels for rendering errors (default: false)
325
+
326
+ ## Future Enhancements
327
+
328
+ Potential improvements for future iterations:
329
+
330
+ - [ ] Async component loading for code splitting
331
+ - [ ] Component preview mode for CMS editors
332
+ - [ ] Performance monitoring hooks
333
+ - [ ] Server-side rendering optimizations
334
+ - [ ] Component analytics integration
335
+ - [ ] Rich text node renderer registration system
package/CONSENT.md ADDED
@@ -0,0 +1,121 @@
1
+ # Consent Management Guide
2
+
3
+ Core UI integrates with [Orejime](https://github.com/empreinte-digitale/orejime), an open-source consent management manager, to provide GDPR and CCPA compliance.
4
+
5
+ ## Overview
6
+
7
+ The consent system ensures that:
8
+ 1. Users are presented with a consent banner
9
+ 2. Cookies/Trackers are blocked until consent is given
10
+ 3. Analytics adapters only fire when allowed
11
+
12
+ ## Setup
13
+
14
+ ### 1. Configure Consent Provider
15
+
16
+ Wrap your application with `ConsentProvider` and provide configuration.
17
+
18
+ ```tsx
19
+ import { ConsentProvider } from '@se-studio/core-ui';
20
+
21
+ const config = {
22
+ apps: [
23
+ {
24
+ name: 'google-tag-manager',
25
+ title: 'Analytics',
26
+ purposes: ['analytics'],
27
+ cookies: ['_ga', '_gid'],
28
+ required: false,
29
+ default: true,
30
+ },
31
+ {
32
+ name: 'marketing-cookies',
33
+ title: 'Marketing',
34
+ purposes: ['marketing'],
35
+ required: false,
36
+ }
37
+ ],
38
+ privacyPolicy: '/privacy-policy',
39
+ };
40
+
41
+ // Styling theme (optional)
42
+ const theme = {
43
+ primaryColor: '#0070f3',
44
+ borderRadius: '8px',
45
+ };
46
+
47
+ export function AppProviders({ children }) {
48
+ return (
49
+ <ConsentProvider config={config} theme={theme}>
50
+ {children}
51
+ </ConsentProvider>
52
+ );
53
+ }
54
+ ```
55
+
56
+ ### 2. Connect to Analytics
57
+
58
+ Use `ConsentAwareAdapter` to gate analytics based on consent.
59
+
60
+ ```tsx
61
+ import { ConsentAwareAdapter, GoogleTagManagerAdapter, useConsent } from '@se-studio/core-ui';
62
+
63
+ function AnalyticsSetup() {
64
+ const { hasConsent } = useConsent();
65
+
66
+ const adapter = useMemo(() => {
67
+ const base = new GoogleTagManagerAdapter({ containerId: '...' });
68
+ // 'google-tag-manager' matches the app name in config
69
+ return new ConsentAwareAdapter(base, 'google-tag-manager', hasConsent);
70
+ }, [hasConsent]);
71
+
72
+ return <AnalyticsProvider adapter={adapter}>...</AnalyticsProvider>;
73
+ }
74
+ ```
75
+
76
+ ## Styling
77
+
78
+ Orejime styles can be customized via CSS variables or the `theme` prop.
79
+
80
+ ### Using Theme Prop
81
+
82
+ ```tsx
83
+ <ConsentProvider
84
+ theme={{
85
+ fontFamily: 'Inter, sans-serif',
86
+ primaryColor: '#ff0000',
87
+ backgroundColor: '#ffffff'
88
+ }}
89
+ >
90
+ ```
91
+
92
+ ### Using CSS Variables
93
+
94
+ In your global CSS:
95
+
96
+ ```css
97
+ :root {
98
+ --orejime-color-primary: #ff0000;
99
+ --orejime-border-radius: 4px;
100
+ --orejime-z-index: 50;
101
+ }
102
+ ```
103
+
104
+ ## Hook API
105
+
106
+ The `useConsent` hook provides access to consent state.
107
+
108
+ ```tsx
109
+ import { useConsent } from '@se-studio/core-ui';
110
+
111
+ function MyComponent() {
112
+ const { hasConsent, showConsentModal, resetConsent } = useConsent();
113
+
114
+ return (
115
+ <div>
116
+ {hasConsent('analytics') && <AnalyticsDashboard />}
117
+ <button onClick={showConsentModal}>Cookie Settings</button>
118
+ </div>
119
+ );
120
+ }
121
+ ```
package/README.md CHANGED
@@ -10,6 +10,7 @@ Shared React UI component library with Tailwind CSS v4 and CMS infrastructure fo
10
10
  - **Tailwind CSS v4** - Modern utility-first CSS framework with custom breakpoints
11
11
  - **Visual Components** - Optimized image, video, and animation components
12
12
  - **Rich Text Rendering** - RTF (Rich Text Field) support with embedded content
13
+ - **CMS Showcase** - Shared developer tools for testing and previewing CMS components
13
14
  - **Tree-shakeable** - Import only what you need
14
15
  - **Dual exports** - ESM and CJS support
15
16
  - **Fully tested** - Comprehensive test coverage with Vitest
@@ -237,6 +238,16 @@ import { UnusedChecker } from '@se-studio/core-ui';
237
238
  />
238
239
  ```
239
240
 
241
+ #### CMS Showcase
242
+
243
+ The library provides a set of components and utilities to build a CMS component showcase for your project.
244
+
245
+ - **`ShowcasePage`** - The main interface for selecting components and adjusting mock data.
246
+ - **`ShowcaseRenderPage`** - The renderer component for the preview iframe.
247
+ - **`mockFactory`** - Utilities for generating mock data from CMS registrations.
248
+
249
+ See the [CMS Showcase Infrastructure Guide](./src/showcase/README.md) for more details.
250
+
240
251
  ### Animation & Monitoring Components
241
252
 
242
253
  #### ClientMonitor
@@ -397,17 +408,12 @@ const previewConfig = mergeCmsRendererConfig(
397
408
  #### Utilities
398
409
  - **`buildPageMetadata`** - Generates Next.js metadata object from CMS page model
399
410
  - **`handleCmsError`** - Error handling utility for CMS operations
400
- - **`extractComponentInfo`** - Extract specific component information fields
401
- - **`extractCollectionInfo`** - Extract specific collection information fields
402
- - **`extractPageContext`** - Extract specific page context fields
411
+ - **`getRelatedArticles`** - Utility to fetch related articles for collections
412
+ - **`getRelatedPeople`** - Utility to fetch related people for collections
403
413
  - **`cn`** - Utility function for merging Tailwind CSS classes
404
414
 
405
415
  #### Types
406
416
  - **`CmsRendererConfig`** - Complete renderer configuration type
407
- - **`ComponentRenderer<T>`** - Type for component renderer functions
408
- - **`CollectionRenderer<T>`** - Type for collection renderer functions
409
- - **`ComponentConfig<T>`** - Type-safe component configuration
410
- - **`CollectionConfig<T>`** - Type-safe collection configuration
411
417
 
412
418
  For detailed JSDoc documentation on all exports, see the TypeScript declaration files (`.d.ts`) in the package.
413
419
 
@@ -417,7 +423,6 @@ For advanced CMS infrastructure usage, including:
417
423
  - Configuration composition patterns
418
424
  - Embeddable components
419
425
  - Context passing
420
- - Type-safe prop extraction
421
426
  - Preview mode setup
422
427
 
423
428
  See the [CMS Infrastructure Guide](./CMS_INFRASTRUCTURE.md).
@@ -0,0 +1,152 @@
1
+ /**
2
+ * CMS Registration System
3
+ *
4
+ * This module provides a unified registration pattern for CMS components and collections.
5
+ * Instead of updating multiple places when adding a new component, you can define a single
6
+ * registration object that contains all related pieces (renderer, embedded renderer, used fields).
7
+ *
8
+ * @example
9
+ * ```tsx
10
+ * // In your component file
11
+ * export const HeroRegistration = defineComponent({
12
+ * name: 'Hero',
13
+ * renderer: Hero,
14
+ * usedFields: USED_FIELDS,
15
+ * });
16
+ *
17
+ * // In cms.ts
18
+ * const componentRegistrations = [HeroRegistration, ...];
19
+ * const { componentMap, embeddedComponentMap, componentFieldsMap } =
20
+ * buildComponentMaps(componentRegistrations);
21
+ * ```
22
+ */
23
+ import type { ITyped } from '@se-studio/core-data-types';
24
+ import type { CollectionRenderer, EmbeddedCollectionRenderer } from './components/CmsCollection';
25
+ import type { ComponentRenderer, EmbeddedComponentRenderer } from './components/CmsComponent';
26
+ import type { EmbeddedExternalComponentRenderer, ExternalComponentRenderer } from './components/CmsExternalComponent';
27
+ export interface MockData {
28
+ visual?: {
29
+ width: number;
30
+ height: number;
31
+ };
32
+ [key: string]: string | number | boolean | {
33
+ width: number;
34
+ height: number;
35
+ } | undefined;
36
+ }
37
+ /**
38
+ * Registration for a CMS component.
39
+ * Components can optionally have an embedded variant for use in RTF/collections.
40
+ */
41
+ export interface ComponentRegistration<TName extends string = string, TComponent extends ITyped = ITyped> {
42
+ /** CMS component type name (e.g., 'Hero', 'Callout') */
43
+ name: TName;
44
+ /** Main renderer for page-level display */
45
+ renderer: ComponentRenderer<TComponent>;
46
+ /** Fields used by this component (for cms-showcase and unused field checking) */
47
+ usedFields: Set<string>;
48
+ /** Optional embedded renderer for RTF/collection contexts */
49
+ embeddedRenderer?: EmbeddedComponentRenderer<TComponent>;
50
+ /** Optional mock data configuration for the showcase */
51
+ mock?: MockData;
52
+ }
53
+ /**
54
+ * Registration for a CMS collection.
55
+ * Collections render arrays of content items.
56
+ */
57
+ export interface CollectionRegistration<TName extends string = string, TCollection extends ITyped = ITyped> {
58
+ /** CMS collection type name (e.g., 'Card grid', 'Icon cards') */
59
+ name: TName;
60
+ /** Main renderer for page-level display */
61
+ renderer: CollectionRenderer<TCollection>;
62
+ /** Fields used by this collection */
63
+ usedFields: Set<string>;
64
+ /** Optional embedded renderer for nested contexts */
65
+ embeddedRenderer?: EmbeddedCollectionRenderer<TCollection>;
66
+ /** Optional: fields used by card items within the collection */
67
+ cardUsedFields?: Set<string>;
68
+ /** Optional mock data configuration for the showcase (collection fields) */
69
+ mock?: MockData;
70
+ /** Optional mock data configuration for the showcase (card fields) */
71
+ cardMock?: MockData;
72
+ }
73
+ /**
74
+ * Registration for an external component (forms, iframes, third-party widgets).
75
+ */
76
+ export interface ExternalComponentRegistration<TName extends string = string, TExternal extends ITyped = ITyped> {
77
+ /** External component type name (e.g., 'iframe', 'Pardot form') */
78
+ name: TName;
79
+ /** Renderer for the external component */
80
+ renderer: ExternalComponentRenderer<TExternal>;
81
+ /** Optional embedded renderer */
82
+ embeddedRenderer?: EmbeddedExternalComponentRenderer<TExternal>;
83
+ }
84
+ /**
85
+ * Builds component maps from an array of registrations.
86
+ * Returns componentMap, embeddedComponentMap, and componentFieldsMap.
87
+ */
88
+ export declare function buildComponentMaps<TComponent extends ITyped>(registrations: ComponentRegistration<string, TComponent>[]): {
89
+ componentMap: Record<string, ComponentRenderer<TComponent>>;
90
+ embeddedComponentMap: Record<string, EmbeddedComponentRenderer<TComponent>>;
91
+ componentFieldsMap: Record<string, Set<string>>;
92
+ componentMockMap: Record<string, MockData>;
93
+ };
94
+ /**
95
+ * Builds collection maps from an array of registrations.
96
+ */
97
+ export declare function buildCollectionMaps<TCollection extends ITyped>(registrations: CollectionRegistration<string, TCollection>[]): {
98
+ collectionMap: Record<string, CollectionRenderer<TCollection>>;
99
+ embeddedCollectionMap: Record<string, EmbeddedCollectionRenderer<TCollection>>;
100
+ collectionFieldsMap: Record<string, Set<string>>;
101
+ collectionCardFieldsMap: Record<string, Set<string>>;
102
+ collectionMockMap: Record<string, MockData>;
103
+ collectionCardMockMap: Record<string, MockData>;
104
+ };
105
+ /**
106
+ * Builds external component maps from an array of registrations.
107
+ */
108
+ export declare function buildExternalComponentMaps<TExternal extends ITyped>(registrations: ExternalComponentRegistration<string, TExternal>[]): {
109
+ externalComponentMap: Record<string, ExternalComponentRenderer<TExternal>>;
110
+ embeddedExternalComponentMap: Record<string, EmbeddedExternalComponentRenderer<TExternal>>;
111
+ };
112
+ /**
113
+ * Helper to create a component registration with type inference.
114
+ * Use this in component files to get proper type checking.
115
+ *
116
+ * @example
117
+ * ```tsx
118
+ * export const HeroRegistration = defineComponent({
119
+ * name: 'Hero',
120
+ * renderer: Hero,
121
+ * usedFields: USED_FIELDS,
122
+ * });
123
+ * ```
124
+ */
125
+ export declare function defineComponent<TName extends string, TComponent extends ITyped>(registration: ComponentRegistration<TName, TComponent>): ComponentRegistration<TName, TComponent>;
126
+ /**
127
+ * Helper to create a collection registration with type inference.
128
+ *
129
+ * @example
130
+ * ```tsx
131
+ * export const CardGridRegistration = defineCollection({
132
+ * name: 'Card grid',
133
+ * renderer: CardGrid,
134
+ * usedFields: COLLECTION_USED_FIELDS,
135
+ * embeddedRenderer: EmbeddedCardGrid,
136
+ * });
137
+ * ```
138
+ */
139
+ export declare function defineCollection<TName extends string, TCollection extends ITyped>(registration: CollectionRegistration<TName, TCollection>): CollectionRegistration<TName, TCollection>;
140
+ /**
141
+ * Helper to create an external component registration with type inference.
142
+ *
143
+ * @example
144
+ * ```tsx
145
+ * export const IFrameRegistration = defineExternalComponent({
146
+ * name: 'iframe',
147
+ * renderer: ExternalIFrame,
148
+ * });
149
+ * ```
150
+ */
151
+ export declare function defineExternalComponent<TName extends string, TExternal extends ITyped>(registration: ExternalComponentRegistration<TName, TExternal>): ExternalComponentRegistration<TName, TExternal>;
152
+ //# sourceMappingURL=cmsRegistration.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cmsRegistration.d.ts","sourceRoot":"","sources":["../src/cmsRegistration.ts"],"names":[],"mappings":"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"}