@cloudwerk/ui 0.1.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.
- package/LICENSE +21 -0
- package/dist/index.d.ts +270 -0
- package/dist/index.js +115 -0
- package/package.json +39 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Squirrelsoft Dev Tools
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @cloudwerk/ui - Type Definitions
|
|
3
|
+
*
|
|
4
|
+
* Core types for the renderer abstraction layer.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Renderer implementation interface.
|
|
8
|
+
*
|
|
9
|
+
* Each renderer (hono-jsx, react, preact) implements this interface.
|
|
10
|
+
* The renderer is responsible for converting JSX elements to HTML responses.
|
|
11
|
+
*/
|
|
12
|
+
interface Renderer {
|
|
13
|
+
/**
|
|
14
|
+
* Render a JSX element to an HTML Response.
|
|
15
|
+
*
|
|
16
|
+
* @param element - JSX element to render (type is unknown to support any JSX implementation)
|
|
17
|
+
* @param options - Render options
|
|
18
|
+
* @returns Response object (may be a Promise for async rendering)
|
|
19
|
+
*/
|
|
20
|
+
render(element: unknown, options?: RenderOptions): Response | Promise<Response>;
|
|
21
|
+
/**
|
|
22
|
+
* Create an HTML Response from a raw string.
|
|
23
|
+
*
|
|
24
|
+
* Useful for static HTML, templates, or pre-rendered content.
|
|
25
|
+
*
|
|
26
|
+
* @param content - Raw HTML string
|
|
27
|
+
* @param options - HTML response options
|
|
28
|
+
* @returns Response object
|
|
29
|
+
*/
|
|
30
|
+
html(content: string, options?: HtmlOptions): Response;
|
|
31
|
+
/**
|
|
32
|
+
* Hydrate a JSX element on the client.
|
|
33
|
+
*
|
|
34
|
+
* Only used for Client Components marked with 'use client'.
|
|
35
|
+
* This attaches event handlers to server-rendered HTML.
|
|
36
|
+
*
|
|
37
|
+
* @param element - JSX element to hydrate
|
|
38
|
+
* @param root - DOM element to hydrate into
|
|
39
|
+
*/
|
|
40
|
+
hydrate(element: unknown, root: Element): void;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Options for rendering JSX elements.
|
|
44
|
+
*/
|
|
45
|
+
interface RenderOptions {
|
|
46
|
+
/**
|
|
47
|
+
* HTTP status code for the response.
|
|
48
|
+
* @default 200
|
|
49
|
+
*/
|
|
50
|
+
status?: number;
|
|
51
|
+
/**
|
|
52
|
+
* Additional response headers.
|
|
53
|
+
* These are merged with the default Content-Type header.
|
|
54
|
+
*/
|
|
55
|
+
headers?: Record<string, string>;
|
|
56
|
+
/**
|
|
57
|
+
* Whether to include the <!DOCTYPE html> declaration.
|
|
58
|
+
* @default true
|
|
59
|
+
*/
|
|
60
|
+
doctype?: boolean;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Options for creating HTML responses from raw strings.
|
|
64
|
+
*/
|
|
65
|
+
interface HtmlOptions {
|
|
66
|
+
/**
|
|
67
|
+
* HTTP status code for the response.
|
|
68
|
+
* @default 200
|
|
69
|
+
*/
|
|
70
|
+
status?: number;
|
|
71
|
+
/**
|
|
72
|
+
* Additional response headers.
|
|
73
|
+
* These are merged with the default Content-Type header.
|
|
74
|
+
*/
|
|
75
|
+
headers?: Record<string, string>;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Props for components that receive children.
|
|
79
|
+
*
|
|
80
|
+
* Works with any JSX implementation (Hono JSX, React, Preact).
|
|
81
|
+
* The children type is `unknown` to allow any JSX element type.
|
|
82
|
+
*
|
|
83
|
+
* @example
|
|
84
|
+
* function Layout({ children }: PropsWithChildren) {
|
|
85
|
+
* return (
|
|
86
|
+
* <html>
|
|
87
|
+
* <body>{children}</body>
|
|
88
|
+
* </html>
|
|
89
|
+
* )
|
|
90
|
+
* }
|
|
91
|
+
*/
|
|
92
|
+
interface PropsWithChildren<_P = unknown> {
|
|
93
|
+
children?: unknown;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* @cloudwerk/ui - Renderer Selection
|
|
98
|
+
*
|
|
99
|
+
* Manages the active renderer and provides registration functionality.
|
|
100
|
+
*/
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Get the currently active renderer instance.
|
|
104
|
+
*
|
|
105
|
+
* @returns The active Renderer implementation
|
|
106
|
+
*
|
|
107
|
+
* @example
|
|
108
|
+
* const renderer = getActiveRenderer()
|
|
109
|
+
* const response = renderer.render(<App />)
|
|
110
|
+
*/
|
|
111
|
+
declare function getActiveRenderer(): Renderer;
|
|
112
|
+
/**
|
|
113
|
+
* Get the name of the currently active renderer.
|
|
114
|
+
*
|
|
115
|
+
* @returns The renderer name (e.g., 'hono-jsx', 'react', 'preact')
|
|
116
|
+
*
|
|
117
|
+
* @example
|
|
118
|
+
* console.log(`Using ${getActiveRendererName()} renderer`)
|
|
119
|
+
*/
|
|
120
|
+
declare function getActiveRendererName(): string;
|
|
121
|
+
/**
|
|
122
|
+
* Set the active renderer by name.
|
|
123
|
+
*
|
|
124
|
+
* Called during app initialization based on the `ui.renderer` config option.
|
|
125
|
+
* The renderer must be registered (either built-in or via registerRenderer).
|
|
126
|
+
*
|
|
127
|
+
* @param name - Renderer name from config (e.g., 'hono-jsx', 'react')
|
|
128
|
+
* @throws Error if renderer is not found
|
|
129
|
+
*
|
|
130
|
+
* @example
|
|
131
|
+
* // Initialize from config
|
|
132
|
+
* setActiveRenderer(config.ui?.renderer ?? 'hono-jsx')
|
|
133
|
+
*/
|
|
134
|
+
declare function setActiveRenderer(name: string): void;
|
|
135
|
+
/**
|
|
136
|
+
* Register a custom renderer.
|
|
137
|
+
*
|
|
138
|
+
* Allows third-party renderer implementations to be used.
|
|
139
|
+
* The renderer must implement the Renderer interface.
|
|
140
|
+
*
|
|
141
|
+
* @param name - Unique name for the renderer
|
|
142
|
+
* @param renderer - Renderer implementation
|
|
143
|
+
* @throws Error if a renderer with that name is already registered
|
|
144
|
+
*
|
|
145
|
+
* @example
|
|
146
|
+
* // Register a custom renderer
|
|
147
|
+
* registerRenderer('solid', solidRenderer)
|
|
148
|
+
*
|
|
149
|
+
* // Then use it in config
|
|
150
|
+
* // ui: { renderer: 'solid' }
|
|
151
|
+
*/
|
|
152
|
+
declare function registerRenderer(name: string, renderer: Renderer): void;
|
|
153
|
+
/**
|
|
154
|
+
* Get a list of all available renderer names.
|
|
155
|
+
*
|
|
156
|
+
* Useful for validation and error messages.
|
|
157
|
+
*
|
|
158
|
+
* @returns Array of registered renderer names
|
|
159
|
+
*
|
|
160
|
+
* @example
|
|
161
|
+
* const available = getAvailableRenderers()
|
|
162
|
+
* // ['hono-jsx']
|
|
163
|
+
*/
|
|
164
|
+
declare function getAvailableRenderers(): string[];
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* @cloudwerk/ui - Hono JSX Renderer
|
|
168
|
+
*
|
|
169
|
+
* Default renderer implementation using Hono JSX.
|
|
170
|
+
* Hono JSX elements have a toString() method that renders them to HTML.
|
|
171
|
+
*/
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Hono JSX renderer implementation.
|
|
175
|
+
*
|
|
176
|
+
* Uses hono/jsx for server-side rendering. This is the default renderer
|
|
177
|
+
* for Cloudwerk applications.
|
|
178
|
+
*
|
|
179
|
+
* Features:
|
|
180
|
+
* - Synchronous rendering via toString()
|
|
181
|
+
* - Automatic doctype handling
|
|
182
|
+
* - Proper Content-Type headers
|
|
183
|
+
*
|
|
184
|
+
* Note: Streaming support via renderToReadableStream will be added in issue #38.
|
|
185
|
+
*/
|
|
186
|
+
declare const honoJsxRenderer: Renderer;
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* @cloudwerk/ui
|
|
190
|
+
*
|
|
191
|
+
* UI rendering abstraction for Cloudwerk.
|
|
192
|
+
*
|
|
193
|
+
* This package provides a renderer-agnostic API for rendering JSX components
|
|
194
|
+
* to HTML responses. The default renderer uses Hono JSX, but custom renderers
|
|
195
|
+
* (React, Preact, etc.) can be registered and selected via configuration.
|
|
196
|
+
*
|
|
197
|
+
* @packageDocumentation
|
|
198
|
+
*/
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Render a JSX element to an HTML Response.
|
|
202
|
+
*
|
|
203
|
+
* Uses the currently active renderer (default: hono-jsx).
|
|
204
|
+
* Supports streaming for async components (via renderer implementation).
|
|
205
|
+
*
|
|
206
|
+
* @param element - JSX element to render
|
|
207
|
+
* @param options - Render options
|
|
208
|
+
* @returns Response object (may be Promise for async rendering)
|
|
209
|
+
*
|
|
210
|
+
* @example
|
|
211
|
+
* import { render } from '@cloudwerk/ui'
|
|
212
|
+
*
|
|
213
|
+
* // In a route handler
|
|
214
|
+
* app.get('/', (c) => {
|
|
215
|
+
* return render(<HomePage />)
|
|
216
|
+
* })
|
|
217
|
+
*
|
|
218
|
+
* @example
|
|
219
|
+
* // With options
|
|
220
|
+
* return render(<NotFoundPage />, { status: 404 })
|
|
221
|
+
*
|
|
222
|
+
* @example
|
|
223
|
+
* // With custom headers
|
|
224
|
+
* return render(<App />, {
|
|
225
|
+
* headers: { 'X-Custom-Header': 'value' }
|
|
226
|
+
* })
|
|
227
|
+
*/
|
|
228
|
+
declare function render(element: unknown, options?: RenderOptions): Response | Promise<Response>;
|
|
229
|
+
/**
|
|
230
|
+
* Create an HTML Response from a raw string.
|
|
231
|
+
*
|
|
232
|
+
* Useful for static HTML, templates, or pre-rendered content
|
|
233
|
+
* that doesn't need to go through JSX rendering.
|
|
234
|
+
*
|
|
235
|
+
* @param content - Raw HTML string
|
|
236
|
+
* @param options - HTML response options
|
|
237
|
+
* @returns Response object
|
|
238
|
+
*
|
|
239
|
+
* @example
|
|
240
|
+
* import { html } from '@cloudwerk/ui'
|
|
241
|
+
*
|
|
242
|
+
* // Return static HTML
|
|
243
|
+
* return html('<!DOCTYPE html><html><body>Hello</body></html>')
|
|
244
|
+
*
|
|
245
|
+
* @example
|
|
246
|
+
* // With custom status
|
|
247
|
+
* return html('<html><body>Not Found</body></html>', { status: 404 })
|
|
248
|
+
*/
|
|
249
|
+
declare function html(content: string, options?: HtmlOptions): Response;
|
|
250
|
+
/**
|
|
251
|
+
* Hydrate a JSX element on the client.
|
|
252
|
+
*
|
|
253
|
+
* Only used for Client Components marked with 'use client'.
|
|
254
|
+
* This attaches event handlers to server-rendered HTML.
|
|
255
|
+
*
|
|
256
|
+
* Note: This feature requires issue #39 to be implemented.
|
|
257
|
+
* Currently throws an informative error.
|
|
258
|
+
*
|
|
259
|
+
* @param element - JSX element to hydrate
|
|
260
|
+
* @param root - DOM element to hydrate into
|
|
261
|
+
*
|
|
262
|
+
* @example
|
|
263
|
+
* import { hydrate } from '@cloudwerk/ui'
|
|
264
|
+
*
|
|
265
|
+
* // Client-side entry point
|
|
266
|
+
* hydrate(<App />, document.getElementById('root')!)
|
|
267
|
+
*/
|
|
268
|
+
declare function hydrate(element: unknown, root: Element): void;
|
|
269
|
+
|
|
270
|
+
export { type HtmlOptions, type PropsWithChildren, type RenderOptions, type Renderer, getActiveRenderer, getActiveRendererName, getAvailableRenderers, honoJsxRenderer, html, hydrate, registerRenderer, render, setActiveRenderer };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
// src/renderers/hono-jsx.ts
|
|
2
|
+
var honoJsxRenderer = {
|
|
3
|
+
/**
|
|
4
|
+
* Render a JSX element to an HTML Response.
|
|
5
|
+
*
|
|
6
|
+
* Hono JSX elements implement toString() for rendering to HTML strings.
|
|
7
|
+
* This method wraps the output in a proper Response object with headers.
|
|
8
|
+
*
|
|
9
|
+
* @param element - Hono JSX element (has toString() method)
|
|
10
|
+
* @param options - Render options
|
|
11
|
+
* @returns Response object with HTML content
|
|
12
|
+
*/
|
|
13
|
+
render(element, options = {}) {
|
|
14
|
+
const { status = 200, headers = {}, doctype = true } = options;
|
|
15
|
+
const htmlString = String(element);
|
|
16
|
+
const body = doctype ? `<!DOCTYPE html>${htmlString}` : htmlString;
|
|
17
|
+
return new Response(body, {
|
|
18
|
+
status,
|
|
19
|
+
headers: {
|
|
20
|
+
"Content-Type": "text/html; charset=utf-8",
|
|
21
|
+
...headers
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
},
|
|
25
|
+
/**
|
|
26
|
+
* Create an HTML Response from a raw string.
|
|
27
|
+
*
|
|
28
|
+
* Useful for static HTML, templates, or pre-rendered content
|
|
29
|
+
* that doesn't need to go through JSX rendering.
|
|
30
|
+
*
|
|
31
|
+
* @param content - Raw HTML string
|
|
32
|
+
* @param options - HTML response options
|
|
33
|
+
* @returns Response object with HTML content
|
|
34
|
+
*/
|
|
35
|
+
html(content, options = {}) {
|
|
36
|
+
const { status = 200, headers = {} } = options;
|
|
37
|
+
return new Response(content, {
|
|
38
|
+
status,
|
|
39
|
+
headers: {
|
|
40
|
+
"Content-Type": "text/html; charset=utf-8",
|
|
41
|
+
...headers
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
},
|
|
45
|
+
/**
|
|
46
|
+
* Hydrate a JSX element on the client.
|
|
47
|
+
*
|
|
48
|
+
* This is a placeholder that throws an informative error.
|
|
49
|
+
* Client-side hydration will be implemented in issue #39.
|
|
50
|
+
*
|
|
51
|
+
* @param _element - JSX element (unused)
|
|
52
|
+
* @param _root - DOM element (unused)
|
|
53
|
+
* @throws Error with information about when this feature will be available
|
|
54
|
+
*/
|
|
55
|
+
hydrate(_element, _root) {
|
|
56
|
+
throw new Error(
|
|
57
|
+
"Client hydration requires hono/jsx/dom. This feature will be available after issue #39 is implemented."
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
// src/renderer.ts
|
|
63
|
+
var renderers = {
|
|
64
|
+
"hono-jsx": honoJsxRenderer
|
|
65
|
+
};
|
|
66
|
+
var activeRenderer = honoJsxRenderer;
|
|
67
|
+
var activeRendererName = "hono-jsx";
|
|
68
|
+
function getActiveRenderer() {
|
|
69
|
+
return activeRenderer;
|
|
70
|
+
}
|
|
71
|
+
function getActiveRendererName() {
|
|
72
|
+
return activeRendererName;
|
|
73
|
+
}
|
|
74
|
+
function setActiveRenderer(name) {
|
|
75
|
+
const renderer = renderers[name];
|
|
76
|
+
if (!renderer) {
|
|
77
|
+
const available = Object.keys(renderers).join(", ");
|
|
78
|
+
throw new Error(`Unknown renderer "${name}". Available renderers: ${available}`);
|
|
79
|
+
}
|
|
80
|
+
activeRenderer = renderer;
|
|
81
|
+
activeRendererName = name;
|
|
82
|
+
}
|
|
83
|
+
function registerRenderer(name, renderer) {
|
|
84
|
+
if (renderers[name]) {
|
|
85
|
+
throw new Error(
|
|
86
|
+
`Renderer "${name}" is already registered. Use a different name.`
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
renderers[name] = renderer;
|
|
90
|
+
}
|
|
91
|
+
function getAvailableRenderers() {
|
|
92
|
+
return Object.keys(renderers);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// src/index.ts
|
|
96
|
+
function render(element, options) {
|
|
97
|
+
return getActiveRenderer().render(element, options);
|
|
98
|
+
}
|
|
99
|
+
function html(content, options) {
|
|
100
|
+
return getActiveRenderer().html(content, options);
|
|
101
|
+
}
|
|
102
|
+
function hydrate(element, root) {
|
|
103
|
+
return getActiveRenderer().hydrate(element, root);
|
|
104
|
+
}
|
|
105
|
+
export {
|
|
106
|
+
getActiveRenderer,
|
|
107
|
+
getActiveRendererName,
|
|
108
|
+
getAvailableRenderers,
|
|
109
|
+
honoJsxRenderer,
|
|
110
|
+
html,
|
|
111
|
+
hydrate,
|
|
112
|
+
registerRenderer,
|
|
113
|
+
render,
|
|
114
|
+
setActiveRenderer
|
|
115
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@cloudwerk/ui",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "UI rendering abstraction for Cloudwerk",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "https://github.com/squirrelsoft-dev/cloudwerk.git",
|
|
8
|
+
"directory": "packages/ui"
|
|
9
|
+
},
|
|
10
|
+
"type": "module",
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"types": "./dist/index.d.ts",
|
|
14
|
+
"import": "./dist/index.js"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"files": [
|
|
18
|
+
"dist"
|
|
19
|
+
],
|
|
20
|
+
"dependencies": {},
|
|
21
|
+
"peerDependencies": {
|
|
22
|
+
"hono": "^4.0.0"
|
|
23
|
+
},
|
|
24
|
+
"devDependencies": {
|
|
25
|
+
"@vitest/coverage-v8": "^1.0.0",
|
|
26
|
+
"hono": "^4.7.4",
|
|
27
|
+
"tsup": "^8.0.0",
|
|
28
|
+
"typescript": "^5.0.0",
|
|
29
|
+
"vitest": "^1.0.0"
|
|
30
|
+
},
|
|
31
|
+
"scripts": {
|
|
32
|
+
"build": "tsup src/index.ts --format esm --dts",
|
|
33
|
+
"dev": "tsup src/index.ts --format esm --dts --watch",
|
|
34
|
+
"test": "vitest --run",
|
|
35
|
+
"test:watch": "vitest",
|
|
36
|
+
"test:coverage": "vitest --run --coverage",
|
|
37
|
+
"typecheck": "tsc --noEmit"
|
|
38
|
+
}
|
|
39
|
+
}
|