@uniweb/runtime 0.1.2 → 0.2.1

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/README.md CHANGED
@@ -1,10 +1,12 @@
1
1
  # @uniweb/runtime
2
2
 
3
- Runtime loader and Vite plugins for Uniweb sites.
3
+ Minimal runtime for loading Uniweb foundations and orchestrating rendering.
4
4
 
5
5
  ## Overview
6
6
 
7
- This package provides the runtime environment for Uniweb sites—content-driven websites that load Foundation components dynamically. It bridges site content with Foundation components and provides Vite plugins for development.
7
+ This package provides the browser-side runtime for Uniweb sites. It loads foundations dynamically and renders content using React Router.
8
+
9
+ For Vite build plugins, see [`@uniweb/build`](https://github.com/uniweb/build).
8
10
 
9
11
  ## Installation
10
12
 
@@ -12,13 +14,6 @@ This package provides the runtime environment for Uniweb sites—content-driven
12
14
  npm install @uniweb/runtime
13
15
  ```
14
16
 
15
- ## Features
16
-
17
- - **Foundation Loading** - Load Foundations via dynamic import or import maps
18
- - **Content Rendering** - Render pages from structured content (JSON/YAML)
19
- - **Vite Plugins** - Collect site content and serve foundations in development
20
- - **React Integration** - Built on React with React Router for navigation
21
-
22
17
  ## Usage
23
18
 
24
19
  ### Runtime Loading
@@ -26,7 +21,7 @@ npm install @uniweb/runtime
26
21
  Initialize the runtime with a Foundation URL:
27
22
 
28
23
  ```jsx
29
- import { initRuntime } from '@uniweb/runtime'
24
+ import initRuntime from '@uniweb/runtime'
30
25
 
31
26
  // Load foundation from URL
32
27
  initRuntime('/foundation/foundation.js', {
@@ -40,194 +35,76 @@ initRuntime({
40
35
  })
41
36
  ```
42
37
 
43
- ### Vite Plugins for Sites
44
-
45
- Use the Vite plugins to collect content and optionally serve a foundation:
46
-
47
- ```js
48
- // vite.config.js
49
- import { defineConfig } from 'vite'
50
- import react from '@vitejs/plugin-react'
51
- import { siteContentPlugin, foundationPlugin } from '@uniweb/runtime/vite'
52
-
53
- export default defineConfig({
54
- plugins: [
55
- react(),
56
-
57
- // Collect content from pages/ directory
58
- siteContentPlugin({
59
- sitePath: './',
60
- inject: true, // Inject into HTML
61
- }),
62
-
63
- // Optional: Serve foundation in dev mode
64
- foundationPlugin({
65
- name: 'my-foundation',
66
- path: '../my-foundation',
67
- serve: '/foundation',
68
- }),
69
- ]
70
- })
71
- ```
72
-
73
- ### Site Content Structure
74
-
75
- Sites use a pages/ directory structure:
76
-
77
- ```
78
- site/
79
- ├── site.yml # Site configuration
80
- ├── theme.yml # Theme configuration
81
- └── pages/
82
- ├── @header/ # Special: header section
83
- │ └── 1.md
84
- ├── @footer/ # Special: footer section
85
- │ └── 1.md
86
- ├── home/ # Home page (route: /)
87
- │ ├── page.yml # Page metadata
88
- │ ├── 1.md # First section
89
- │ └── 2.md # Second section
90
- └── about/ # About page (route: /about)
91
- ├── page.yml
92
- └── 1.md
93
- ```
94
-
95
- ### Section Markdown Format
96
-
97
- Each `.md` file is a section with YAML frontmatter for configuration and markdown body for content:
98
-
99
- ```markdown
100
- ---
101
- component: Hero
102
- preset: default
103
- theme: dark
104
- ---
38
+ ### Static Bundling
105
39
 
106
- # Welcome to Our Site
40
+ Foundation imported directly and bundled with the site:
107
41
 
108
- Building the future together.
42
+ ```jsx
43
+ import * as Foundation from '@my-org/my-foundation'
44
+ import initRuntime from '@uniweb/runtime'
109
45
 
110
- [Get Started](#features)
46
+ initRuntime(Foundation)
111
47
  ```
112
48
 
113
- The frontmatter specifies the component and configuration parameters. The markdown body contains the actual content, which is semantically parsed into structured data (headings → titles, paragraphs → descriptions, links → CTAs).
114
-
115
- ## API Reference
116
-
117
- ### Runtime Functions
118
-
119
- | Function | Description |
120
- |----------|-------------|
121
- | `initRuntime(source, options)` | Initialize runtime with foundation |
122
- | `initRTE(source, options)` | Alias for initRuntime |
123
-
124
- ### Exported Components
125
-
126
- | Component | Description |
127
- |-----------|-------------|
128
- | `Link` | Router-aware link component |
129
- | `SafeHtml` | Safe HTML rendering |
130
- | `ChildBlocks` | Render child sections |
131
- | `ErrorBoundary` | Error boundary wrapper |
132
-
133
- ### Vite Plugins
49
+ ## API
134
50
 
135
- | Plugin | Description |
136
- |--------|-------------|
137
- | `siteContentPlugin(options)` | Collect and inject site content |
138
- | `foundationPlugin(options)` | Build and serve foundation in dev |
139
- | `collectSiteContent(sitePath)` | Programmatic content collection |
51
+ ### initRuntime(source, options)
140
52
 
141
- ### Plugin Options
53
+ Initialize the runtime with a foundation.
142
54
 
143
- **siteContentPlugin:**
144
- ```js
145
- {
146
- sitePath: './', // Path to site directory
147
- pagesDir: 'pages', // Pages subdirectory
148
- inject: true, // Inject into HTML
149
- filename: 'site-content.json', // Output filename
150
- watch: true // Watch for changes (dev)
151
- }
152
- ```
55
+ **source** - One of:
56
+ - URL string to foundation module
57
+ - Object with `{ url, cssUrl }`
58
+ - Foundation module object (for static bundling)
153
59
 
154
- **foundationPlugin:**
60
+ **options:**
155
61
  ```js
156
62
  {
157
- name: 'foundation', // Foundation name (for logs)
158
- path: '../foundation', // Path to foundation package
159
- serve: '/foundation', // URL path to serve from
160
- watch: true, // Watch for changes
161
- buildOnStart: true // Build when dev server starts
63
+ development: false, // Enable dev mode (StrictMode, verbose errors)
64
+ configData: null, // Site content (or reads from DOM)
65
+ basename: undefined // React Router basename
162
66
  }
163
67
  ```
164
68
 
165
- ## Core Classes
166
-
167
- ### Uniweb
168
-
169
- The main runtime instance (available as `globalThis.uniweb`):
170
-
171
- ```js
172
- uniweb.getComponent(name) // Get component from foundation
173
- uniweb.listComponents() // List available components
174
- uniweb.activeWebsite // Current website instance
175
- ```
176
-
177
- ### Website
69
+ For core classes (`Uniweb`, `Website`, `Block`, etc.), import from [`@uniweb/core`](https://github.com/uniweb/core).
178
70
 
179
- Manages pages, theme, and localization:
71
+ ## Architecture
180
72
 
181
- ```js
182
- website.getPage(route) // Get page by route
183
- website.setActivePage(route) // Navigate to page
184
- website.localize(value) // Localize a value
185
- website.getLanguage() // Get current language
186
73
  ```
187
-
188
- ### Block
189
-
190
- Represents a section on a page:
191
-
192
- ```js
193
- block.initComponent() // Initialize foundation component
194
- block.getBlockContent() // Get structured content
195
- block.getBlockProperties() // Get configuration properties
196
- block.getBlockLinks() // Get links from content
74
+ @uniweb/runtime (browser)
75
+
76
+ ├── Loads foundation dynamically
77
+ ├── Creates Uniweb instance via @uniweb/core
78
+ └── Orchestrates React/Router rendering
197
79
  ```
198
80
 
199
- ## Two Loading Modes
81
+ Foundations should:
82
+ - Import components from `@uniweb/kit` (bundled)
83
+ - Mark `@uniweb/core` as external (provided by runtime)
200
84
 
201
- ### Runtime Loading (Import Maps)
85
+ ## Build Plugins
202
86
 
203
- Foundation loaded at runtime via dynamic import. React provided by host via import map.
87
+ Vite plugins have moved to `@uniweb/build`:
204
88
 
205
- ```html
206
- <script type="importmap">
207
- {
208
- "imports": {
209
- "react": "https://esm.sh/react@18",
210
- "react-dom": "https://esm.sh/react-dom@18"
211
- }
212
- }
213
- </script>
214
- ```
215
-
216
- ### Static Bundling
217
-
218
- Foundation imported directly and bundled with the site.
219
-
220
- ```jsx
221
- import * as Foundation from '@my-org/my-foundation'
222
- import { initRuntime } from '@uniweb/runtime'
89
+ ```js
90
+ // vite.config.js
91
+ import { siteContentPlugin } from '@uniweb/build/site'
92
+ import { foundationDevPlugin } from '@uniweb/build/dev'
223
93
 
224
- initRuntime(Foundation)
94
+ export default defineConfig({
95
+ plugins: [
96
+ siteContentPlugin({ sitePath: './', inject: true }),
97
+ foundationDevPlugin({ path: '../foundation', serve: '/foundation' }),
98
+ ]
99
+ })
225
100
  ```
226
101
 
227
102
  ## Related Packages
228
103
 
229
- - [`uniweb`](https://github.com/uniweb/cli) - CLI for creating Uniweb projects
230
- - [`@uniweb/build`](https://github.com/uniweb/build) - Foundation build tooling
104
+ - [`@uniweb/core`](https://github.com/uniweb/core) - Core classes (Uniweb, Website, Block)
105
+ - [`@uniweb/kit`](https://github.com/uniweb/kit) - Component library for foundations
106
+ - [`@uniweb/build`](https://github.com/uniweb/build) - Vite build plugins
107
+ - [`uniweb`](https://github.com/uniweb/cli) - CLI for creating projects
231
108
 
232
109
  ## License
233
110
 
package/package.json CHANGED
@@ -1,11 +1,10 @@
1
1
  {
2
2
  "name": "@uniweb/runtime",
3
- "version": "0.1.2",
4
- "description": "Runtime loader and Vite plugins for Uniweb sites",
3
+ "version": "0.2.1",
4
+ "description": "Minimal runtime for loading Uniweb foundations",
5
5
  "type": "module",
6
6
  "exports": {
7
- ".": "./src/index.jsx",
8
- "./vite": "./src/vite/index.js"
7
+ ".": "./src/index.jsx"
9
8
  },
10
9
  "files": [
11
10
  "src"
@@ -13,9 +12,8 @@
13
12
  "keywords": [
14
13
  "uniweb",
15
14
  "runtime",
16
- "vite",
17
15
  "react",
18
- "components"
16
+ "foundation"
19
17
  ],
20
18
  "author": "Proximify",
21
19
  "license": "Apache-2.0",
@@ -31,21 +29,11 @@
31
29
  "node": ">=20.19"
32
30
  },
33
31
  "dependencies": {
34
- "js-yaml": "^4.1.0",
35
- "@uniweb/semantic-parser": "1.0.1"
32
+ "@uniweb/core": "0.1.2"
36
33
  },
37
34
  "peerDependencies": {
38
- "react": "^18.0.0",
39
- "react-dom": "^18.0.0",
40
- "react-router-dom": "^6.0.0 || ^7.0.0",
41
- "vite": "^5.0.0 || ^6.0.0 || ^7.0.0"
42
- },
43
- "peerDependenciesMeta": {
44
- "vite": {
45
- "optional": true
46
- }
47
- },
48
- "optionalDependencies": {
49
- "@uniweb/content-reader": "1.0.1"
35
+ "react": "^18.0.0 || ^19.0.0",
36
+ "react-dom": "^18.0.0 || ^19.0.0",
37
+ "react-router-dom": "^6.0.0 || ^7.0.0"
50
38
  }
51
39
  }
package/src/index.jsx CHANGED
@@ -1,23 +1,21 @@
1
1
  /**
2
2
  * @uniweb/runtime - Main Entry Point
3
3
  *
4
- * This is the Vite/ESM-based runtime that loads foundations via dynamic import()
5
- * instead of Webpack Module Federation.
4
+ * Minimal runtime for loading foundations and orchestrating rendering.
5
+ * Foundations should import components from @uniweb/kit.
6
6
  */
7
7
 
8
8
  import React from 'react'
9
9
  import { createRoot } from 'react-dom/client'
10
- import { BrowserRouter, Routes, Route, useParams, useLocation, useNavigate } from 'react-router-dom'
10
+ import { BrowserRouter, Routes, Route } from 'react-router-dom'
11
11
 
12
12
  // Components
13
13
  import { ChildBlocks } from './components/PageRenderer.jsx'
14
- import Link from './components/Link.jsx'
15
- import SafeHtml from './components/SafeHtml.jsx'
16
14
  import WebsiteRenderer from './components/WebsiteRenderer.jsx'
17
15
  import ErrorBoundary from './components/ErrorBoundary.jsx'
18
16
 
19
- // Core
20
- import Uniweb from './core/uniweb.js'
17
+ // Core factory from @uniweb/core
18
+ import { createUniweb } from '@uniweb/core'
21
19
 
22
20
  /**
23
21
  * Load foundation CSS from URL
@@ -60,8 +58,10 @@ async function loadFoundation(source) {
60
58
  import(/* @vite-ignore */ url)
61
59
  ])
62
60
 
63
- console.log('[Runtime] Foundation loaded. Available components:',
64
- typeof foundation.listComponents === 'function' ? foundation.listComponents() : 'unknown')
61
+ console.log(
62
+ '[Runtime] Foundation loaded. Available components:',
63
+ typeof foundation.listComponents === 'function' ? foundation.listComponents() : 'unknown'
64
+ )
65
65
 
66
66
  return foundation
67
67
  } catch (error) {
@@ -76,23 +76,12 @@ async function loadFoundation(source) {
76
76
  * @returns {Uniweb}
77
77
  */
78
78
  function initUniweb(configData) {
79
- const uniwebInstance = new Uniweb(configData)
79
+ // Create singleton via @uniweb/core (also assigns to globalThis.uniweb)
80
+ const uniwebInstance = createUniweb(configData)
80
81
 
81
- // Global assignment for component access
82
- globalThis.uniweb = uniwebInstance
83
-
84
- // Set up child block renderer
82
+ // Set up child block renderer for nested blocks
85
83
  uniwebInstance.childBlockRenderer = ChildBlocks
86
84
 
87
- // Set up routing components for foundation components to use
88
- uniwebInstance.routingComponents = {
89
- Link,
90
- SafeHtml,
91
- useNavigate,
92
- useParams,
93
- useLocation
94
- }
95
-
96
85
  return uniwebInstance
97
86
  }
98
87
 
@@ -149,9 +138,10 @@ async function initRuntime(foundationSource, options = {}) {
149
138
  } = options
150
139
 
151
140
  // Get config data from options, DOM, or global
152
- const configData = providedConfig
153
- ?? JSON.parse(document.getElementById('__SITE_CONTENT__')?.textContent || 'null')
154
- ?? globalThis.__SITE_CONTENT__
141
+ const configData =
142
+ providedConfig ??
143
+ JSON.parse(document.getElementById('__SITE_CONTENT__')?.textContent || 'null') ??
144
+ globalThis.__SITE_CONTENT__
155
145
 
156
146
  if (!configData) {
157
147
  console.error('[Runtime] No site configuration found')
@@ -205,7 +195,7 @@ async function initRuntime(foundationSource, options = {}) {
205
195
  '%c<%c>%c Uniweb Runtime',
206
196
  'color: #FA8400; font-weight: bold; font-size: 18px;',
207
197
  'color: #00ADFE; font-weight: bold; font-size: 18px;',
208
- "color: #333; font-size: 18px; font-family: system-ui, sans-serif;"
198
+ 'color: #333; font-size: 18px; font-family: system-ui, sans-serif;'
209
199
  )
210
200
  }
211
201
  } catch (error) {
@@ -216,7 +206,15 @@ async function initRuntime(foundationSource, options = {}) {
216
206
  if (container) {
217
207
  const root = createRoot(container)
218
208
  root.render(
219
- <div style={{ padding: '2rem', margin: '1rem', background: '#fef2f2', borderRadius: '0.5rem', color: '#dc2626' }}>
209
+ <div
210
+ style={{
211
+ padding: '2rem',
212
+ margin: '1rem',
213
+ background: '#fef2f2',
214
+ borderRadius: '0.5rem',
215
+ color: '#dc2626'
216
+ }}
217
+ >
220
218
  <h2>Runtime Error</h2>
221
219
  <p>{error.message}</p>
222
220
  {development && <pre style={{ fontSize: '0.75rem', overflow: 'auto' }}>{error.stack}</pre>}
@@ -226,20 +224,5 @@ async function initRuntime(foundationSource, options = {}) {
226
224
  }
227
225
  }
228
226
 
229
- // Legacy alias
230
- const initRTE = initRuntime
231
-
232
- // Exports
233
- export {
234
- initRuntime,
235
- initRTE,
236
- // Components for external use
237
- Link,
238
- SafeHtml,
239
- ChildBlocks,
240
- ErrorBoundary,
241
- // Core classes
242
- Uniweb
243
- }
244
-
227
+ export { initRuntime }
245
228
  export default initRuntime
@@ -1,28 +0,0 @@
1
- /**
2
- * Link
3
- *
4
- * A wrapper around React Router's Link that integrates with the runtime.
5
- */
6
-
7
- import React from 'react'
8
- import { Link as RouterLink } from 'react-router-dom'
9
-
10
- export default function Link({ to, href, children, className, ...props }) {
11
- const target = to || href
12
-
13
- // External links
14
- if (target?.startsWith('http') || target?.startsWith('mailto:') || target?.startsWith('tel:')) {
15
- return (
16
- <a href={target} className={className} {...props}>
17
- {children}
18
- </a>
19
- )
20
- }
21
-
22
- // Internal links via React Router
23
- return (
24
- <RouterLink to={target || '/'} className={className} {...props}>
25
- {children}
26
- </RouterLink>
27
- )
28
- }
@@ -1,22 +0,0 @@
1
- /**
2
- * SafeHtml
3
- *
4
- * Safely render HTML content with sanitization.
5
- * TODO: Add DOMPurify for production use
6
- */
7
-
8
- import React from 'react'
9
-
10
- export default function SafeHtml({ html, className, as: Component = 'div', ...props }) {
11
- if (!html) return null
12
-
13
- // For now, render directly
14
- // TODO: Integrate DOMPurify for sanitization
15
- return (
16
- <Component
17
- className={className}
18
- dangerouslySetInnerHTML={{ __html: html }}
19
- {...props}
20
- />
21
- )
22
- }