@uniweb/runtime 0.2.11 → 0.2.13

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uniweb/runtime",
3
- "version": "0.2.11",
3
+ "version": "0.2.13",
4
4
  "description": "Minimal runtime for loading Uniweb foundations",
5
5
  "type": "module",
6
6
  "exports": {
@@ -29,7 +29,7 @@
29
29
  "node": ">=20.19"
30
30
  },
31
31
  "dependencies": {
32
- "@uniweb/core": "0.1.8"
32
+ "@uniweb/core": "0.1.12"
33
33
  },
34
34
  "peerDependencies": {
35
35
  "react": "^18.0.0 || ^19.0.0",
@@ -2,10 +2,11 @@
2
2
  * BlockRenderer
3
3
  *
4
4
  * Bridges Block data to foundation components.
5
- * Handles theming and wrapper props.
5
+ * Handles theming, wrapper props, and runtime guarantees.
6
6
  */
7
7
 
8
8
  import React from 'react'
9
+ import { prepareProps, getComponentMeta } from '../prepare-props.js'
9
10
 
10
11
  /**
11
12
  * Convert hex color to rgba
@@ -82,34 +83,40 @@ export default function BlockRenderer({ block, pure = false, extra = {} }) {
82
83
  )
83
84
  }
84
85
 
85
- // Build content for component
86
- // Components expect content as a simple object with all data
86
+ // Build content and params with runtime guarantees
87
87
  // Sources:
88
- // 1. parsedContent.raw - simple PoC format (hardcoded content)
89
- // 2. parsedContent - semantic parser output (main.header, main.body, items, etc.)
88
+ // 1. parsedContent._isPoc - simple PoC format (hardcoded content)
89
+ // 2. parsedContent - semantic parser output (flat: title, paragraphs, links, etc.)
90
90
  // 3. block.properties - params from frontmatter (theme, alignment, etc.)
91
- let content
91
+ // 4. meta - defaults from component meta.js
92
+ let content, params
92
93
 
93
- if (block.parsedContent?.raw) {
94
+ if (block.parsedContent?._isPoc) {
94
95
  // Simple PoC format - content was passed directly
95
- content = block.parsedContent.raw
96
+ content = block.parsedContent._pocContent
97
+ params = block.properties
96
98
  } else {
97
- // Collected content - merge parsed content with frontmatter params
98
- // Parsed content goes first so components can access content.main.header, etc.
99
- // Frontmatter params overlay for things like content.title from YAML
99
+ // Get runtime metadata for this component (has defaults, data binding, etc.)
100
+ const meta = getComponentMeta(block.type)
101
+
102
+ // Prepare props with runtime guarantees:
103
+ // - Apply param defaults from meta.js
104
+ // - Guarantee content structure exists
105
+ const prepared = prepareProps(block, meta)
106
+ params = prepared.params
107
+
108
+ // Merge prepared content with raw access for components that need it
100
109
  content = {
101
- ...block.parsedContent, // Semantic parser output (main, items, etc.)
102
- ...block.properties, // Frontmatter params overlay
110
+ ...prepared.content,
111
+ ...block.properties, // Frontmatter params overlay (legacy support)
103
112
  _prosemirror: block.parsedContent // Keep original for components that need raw access
104
113
  }
105
114
  }
106
115
 
107
116
  const componentProps = {
108
117
  content,
109
- params: block.properties,
118
+ params,
110
119
  block,
111
- page: globalThis.uniweb?.activeWebsite?.activePage,
112
- website: globalThis.uniweb?.activeWebsite,
113
120
  input: block.input
114
121
  }
115
122
 
@@ -0,0 +1,137 @@
1
+ /**
2
+ * Props Preparation for Runtime Guarantees
3
+ *
4
+ * Prepares props for foundation components with:
5
+ * - Param defaults from runtime schema
6
+ * - Guaranteed content structure (no null checks needed)
7
+ *
8
+ * This enables simpler component code by ensuring predictable prop shapes.
9
+ */
10
+
11
+ /**
12
+ * Guarantee item has flat content structure
13
+ *
14
+ * @param {Object} item - Raw item from parser
15
+ * @returns {Object} Item with guaranteed flat structure
16
+ */
17
+ function guaranteeItemStructure(item) {
18
+ return {
19
+ title: item.title || '',
20
+ pretitle: item.pretitle || '',
21
+ subtitle: item.subtitle || '',
22
+ paragraphs: item.paragraphs || [],
23
+ links: item.links || [],
24
+ imgs: item.imgs || [],
25
+ lists: item.lists || [],
26
+ icons: item.icons || [],
27
+ videos: item.videos || [],
28
+ buttons: item.buttons || [],
29
+ properties: item.properties || {},
30
+ cards: item.cards || [],
31
+ documents: item.documents || [],
32
+ forms: item.forms || [],
33
+ quotes: item.quotes || [],
34
+ headings: item.headings || [],
35
+ }
36
+ }
37
+
38
+ /**
39
+ * Guarantee content structure exists
40
+ * Returns a flat content object with all standard fields guaranteed to exist
41
+ *
42
+ * @param {Object} parsedContent - Raw parsed content from semantic parser (flat structure)
43
+ * @returns {Object} Content with guaranteed flat structure
44
+ */
45
+ export function guaranteeContentStructure(parsedContent) {
46
+ const content = parsedContent || {}
47
+
48
+ return {
49
+ // Flat header fields
50
+ title: content.title || '',
51
+ pretitle: content.pretitle || '',
52
+ subtitle: content.subtitle || '',
53
+ subtitle2: content.subtitle2 || '',
54
+ alignment: content.alignment || null,
55
+
56
+ // Flat body fields
57
+ paragraphs: content.paragraphs || [],
58
+ links: content.links || [],
59
+ imgs: content.imgs || [],
60
+ lists: content.lists || [],
61
+ icons: content.icons || [],
62
+ videos: content.videos || [],
63
+ buttons: content.buttons || [],
64
+ properties: content.properties || {},
65
+ propertyBlocks: content.propertyBlocks || [],
66
+ cards: content.cards || [],
67
+ documents: content.documents || [],
68
+ forms: content.forms || [],
69
+ quotes: content.quotes || [],
70
+ headings: content.headings || [],
71
+
72
+ // Items with guaranteed structure
73
+ items: (content.items || []).map(guaranteeItemStructure),
74
+
75
+ // Sequence for ordered rendering
76
+ sequence: content.sequence || [],
77
+
78
+ // Preserve raw content if present
79
+ raw: content.raw,
80
+ }
81
+ }
82
+
83
+ /**
84
+ * Apply param defaults from runtime schema
85
+ *
86
+ * @param {Object} params - Params from frontmatter
87
+ * @param {Object} defaults - Default values from runtime schema
88
+ * @returns {Object} Merged params with defaults applied
89
+ */
90
+ export function applyDefaults(params, defaults) {
91
+ if (!defaults || Object.keys(defaults).length === 0) {
92
+ return params || {}
93
+ }
94
+
95
+ return {
96
+ ...defaults,
97
+ ...(params || {}),
98
+ }
99
+ }
100
+
101
+ /**
102
+ * Prepare props for a component with runtime guarantees
103
+ *
104
+ * @param {Object} block - The block instance
105
+ * @param {Object} meta - Runtime metadata for the component (from meta[componentName])
106
+ * @returns {Object} Prepared props: { content, params }
107
+ */
108
+ export function prepareProps(block, meta) {
109
+ // Apply param defaults
110
+ const defaults = meta?.defaults || {}
111
+ const params = applyDefaults(block.properties, defaults)
112
+
113
+ // Guarantee content structure
114
+ const content = guaranteeContentStructure(block.parsedContent)
115
+
116
+ return { content, params }
117
+ }
118
+
119
+ /**
120
+ * Get runtime metadata for a component from the global uniweb instance
121
+ *
122
+ * @param {string} componentName
123
+ * @returns {Object|null}
124
+ */
125
+ export function getComponentMeta(componentName) {
126
+ return globalThis.uniweb?.getComponentMeta?.(componentName) || null
127
+ }
128
+
129
+ /**
130
+ * Get default param values for a component
131
+ *
132
+ * @param {string} componentName
133
+ * @returns {Object}
134
+ */
135
+ export function getComponentDefaults(componentName) {
136
+ return globalThis.uniweb?.getComponentDefaults?.(componentName) || {}
137
+ }