@cloudwerk/ui 0.3.0 → 0.4.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/dist/index.d.ts CHANGED
@@ -75,7 +75,7 @@ interface HtmlOptions {
75
75
  headers?: Record<string, string>;
76
76
  }
77
77
  /**
78
- * Options for streaming render.
78
+ * Options for streaming render (loading-swap pattern).
79
79
  */
80
80
  interface StreamRenderOptions {
81
81
  /**
@@ -89,6 +89,29 @@ interface StreamRenderOptions {
89
89
  */
90
90
  headers?: Record<string, string>;
91
91
  }
92
+ /**
93
+ * Options for native progressive streaming render with Suspense boundaries.
94
+ *
95
+ * This is used by renderToStream() which uses Hono's renderToReadableStream
96
+ * for native progressive streaming with Suspense support.
97
+ */
98
+ interface RenderToStreamOptions {
99
+ /**
100
+ * HTTP status code for the response.
101
+ * @default 200
102
+ */
103
+ status?: number;
104
+ /**
105
+ * Additional response headers.
106
+ * These are merged with the default Content-Type header.
107
+ */
108
+ headers?: Record<string, string>;
109
+ /**
110
+ * Whether to include the <!DOCTYPE html> declaration.
111
+ * @default true
112
+ */
113
+ doctype?: boolean;
114
+ }
92
115
  /**
93
116
  * Props for components that receive children.
94
117
  *
@@ -202,7 +225,8 @@ declare function _resetRenderers(): void;
202
225
  * - Automatic doctype handling
203
226
  * - Proper Content-Type headers
204
227
  *
205
- * Note: Streaming support via renderToReadableStream will be added in issue #38.
228
+ * Native progressive streaming is available via renderToStream() using Hono's
229
+ * renderToReadableStream for Suspense boundary support.
206
230
  */
207
231
  declare const honoJsxRenderer: Renderer;
208
232
  /**
@@ -232,6 +256,46 @@ declare const honoJsxRenderer: Renderer;
232
256
  * return renderStream(loadingElement, contentPromise)
233
257
  */
234
258
  declare function renderStream(loadingElement: unknown, contentPromise: Promise<unknown>, options?: StreamRenderOptions): Response;
259
+ /**
260
+ * Render a JSX element to a streaming Response using native progressive streaming.
261
+ *
262
+ * This uses Hono's renderToReadableStream for native support of React-style
263
+ * Suspense boundaries. Content inside Suspense components will be progressively
264
+ * streamed as their async content resolves.
265
+ *
266
+ * Unlike renderStream() which uses a loading-swap pattern, this function
267
+ * provides true progressive streaming where:
268
+ * - The initial shell is sent immediately
269
+ * - Suspense fallbacks are shown while async content loads
270
+ * - Async content is streamed in-place as it resolves
271
+ * - No JavaScript is required for the initial render
272
+ *
273
+ * @param element - Hono JSX element to render (may contain Suspense boundaries)
274
+ * @param options - Render options
275
+ * @returns Promise resolving to Response with streaming HTML content
276
+ *
277
+ * @example
278
+ * // In a route handler
279
+ * import { Suspense } from 'hono/jsx/streaming'
280
+ *
281
+ * function Page() {
282
+ * return (
283
+ * <html>
284
+ * <body>
285
+ * <h1>Dashboard</h1>
286
+ * <Suspense fallback={<p>Loading stats...</p>}>
287
+ * <AsyncStats />
288
+ * </Suspense>
289
+ * </body>
290
+ * </html>
291
+ * )
292
+ * }
293
+ *
294
+ * export function GET() {
295
+ * return renderToStream(<Page />)
296
+ * }
297
+ */
298
+ declare function renderToStream(element: unknown, options?: RenderToStreamOptions): Promise<Response>;
235
299
 
236
300
  /**
237
301
  * @cloudwerk/ui
@@ -315,4 +379,4 @@ declare function html(content: string, options?: HtmlOptions): Response;
315
379
  */
316
380
  declare function hydrate(element: unknown, root: Element): void;
317
381
 
318
- export { type HtmlOptions, type PropsWithChildren, type RenderOptions, type Renderer, type StreamRenderOptions, _resetRenderers, getActiveRenderer, getActiveRendererName, getAvailableRenderers, honoJsxRenderer, html, hydrate, registerRenderer, render, renderStream, setActiveRenderer };
382
+ export { type HtmlOptions, type PropsWithChildren, type RenderOptions, type RenderToStreamOptions, type Renderer, type StreamRenderOptions, _resetRenderers, getActiveRenderer, getActiveRendererName, getAvailableRenderers, honoJsxRenderer, html, hydrate, registerRenderer, render, renderStream, renderToStream, setActiveRenderer };
package/dist/index.js CHANGED
@@ -1,4 +1,5 @@
1
1
  // src/renderers/hono-jsx.ts
2
+ import { renderToReadableStream } from "hono/jsx/streaming";
2
3
  var honoJsxRenderer = {
3
4
  /**
4
5
  * Render a JSX element to an HTML Response.
@@ -102,6 +103,34 @@ function renderStream(loadingElement, contentPromise, options = {}) {
102
103
  }
103
104
  });
104
105
  }
106
+ function prependDoctype(stream) {
107
+ const encoder = new TextEncoder();
108
+ const doctypeBytes = encoder.encode("<!DOCTYPE html>");
109
+ let doctypeSent = false;
110
+ return stream.pipeThrough(
111
+ new TransformStream({
112
+ transform(chunk, controller) {
113
+ if (!doctypeSent) {
114
+ controller.enqueue(doctypeBytes);
115
+ doctypeSent = true;
116
+ }
117
+ controller.enqueue(chunk);
118
+ }
119
+ })
120
+ );
121
+ }
122
+ async function renderToStream(element, options = {}) {
123
+ const { status = 200, headers = {}, doctype = true } = options;
124
+ const contentStream = renderToReadableStream(element);
125
+ const stream = doctype ? prependDoctype(contentStream) : contentStream;
126
+ return new Response(stream, {
127
+ status,
128
+ headers: {
129
+ "Content-Type": "text/html; charset=utf-8",
130
+ ...headers
131
+ }
132
+ });
133
+ }
105
134
 
106
135
  // src/renderer.ts
107
136
  var renderers = {
@@ -166,5 +195,6 @@ export {
166
195
  registerRenderer,
167
196
  render,
168
197
  renderStream,
198
+ renderToStream,
169
199
  setActiveRenderer
170
200
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cloudwerk/ui",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "description": "UI rendering abstraction for Cloudwerk",
5
5
  "repository": {
6
6
  "type": "git",