frontend-hamroun 1.2.88 → 1.2.89
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.cjs +113 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +113 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
@@ -325,6 +325,117 @@ async function hydrate(element, container) {
|
|
325
325
|
}
|
326
326
|
}
|
327
327
|
|
328
|
+
async function renderToString(element) {
|
329
|
+
prepareRender(true); // Mark as SSR
|
330
|
+
try {
|
331
|
+
const html = await renderNodeToString(element);
|
332
|
+
return html;
|
333
|
+
}
|
334
|
+
finally {
|
335
|
+
finishRender();
|
336
|
+
}
|
337
|
+
}
|
338
|
+
async function renderNodeToString(node) {
|
339
|
+
// Handle null, undefined, boolean
|
340
|
+
if (node == null || typeof node === 'boolean') {
|
341
|
+
return '';
|
342
|
+
}
|
343
|
+
// Handle primitives
|
344
|
+
if (typeof node === 'string' || typeof node === 'number') {
|
345
|
+
return escapeHtml(String(node));
|
346
|
+
}
|
347
|
+
// Handle arrays
|
348
|
+
if (Array.isArray(node)) {
|
349
|
+
const results = await Promise.all(node.map(child => renderNodeToString(child)));
|
350
|
+
return results.join('');
|
351
|
+
}
|
352
|
+
// Handle objects with type and props (React-like elements)
|
353
|
+
if (node && typeof node === 'object' && 'type' in node) {
|
354
|
+
const { type, props = {} } = node;
|
355
|
+
// Handle function components
|
356
|
+
if (typeof type === 'function') {
|
357
|
+
try {
|
358
|
+
const result = await type(props);
|
359
|
+
return await renderNodeToString(result);
|
360
|
+
}
|
361
|
+
catch (error) {
|
362
|
+
console.error('Error rendering component:', error);
|
363
|
+
return `<!-- Error rendering component: ${error.message} -->`;
|
364
|
+
}
|
365
|
+
}
|
366
|
+
// Handle DOM elements
|
367
|
+
if (typeof type === 'string') {
|
368
|
+
return await renderDOMElement(type, props);
|
369
|
+
}
|
370
|
+
}
|
371
|
+
// Fallback for other objects
|
372
|
+
if (typeof node === 'object') {
|
373
|
+
return escapeHtml(JSON.stringify(node));
|
374
|
+
}
|
375
|
+
return escapeHtml(String(node));
|
376
|
+
}
|
377
|
+
async function renderDOMElement(tagName, props) {
|
378
|
+
const { children, ...attrs } = props;
|
379
|
+
// Self-closing tags
|
380
|
+
const voidElements = new Set([
|
381
|
+
'area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input',
|
382
|
+
'link', 'meta', 'param', 'source', 'track', 'wbr'
|
383
|
+
]);
|
384
|
+
// Build attributes string
|
385
|
+
const attributeString = Object.entries(attrs)
|
386
|
+
.filter(([key, value]) => {
|
387
|
+
// Filter out React-specific props and event handlers
|
388
|
+
if (key.startsWith('on') || key === 'key' || key === 'ref')
|
389
|
+
return false;
|
390
|
+
if (value == null || value === false)
|
391
|
+
return false;
|
392
|
+
return true;
|
393
|
+
})
|
394
|
+
.map(([key, value]) => {
|
395
|
+
// Handle className -> class
|
396
|
+
if (key === 'className')
|
397
|
+
key = 'class';
|
398
|
+
// Handle boolean attributes
|
399
|
+
if (value === true)
|
400
|
+
return key;
|
401
|
+
// Handle style objects
|
402
|
+
if (key === 'style' && typeof value === 'object' && value !== null) {
|
403
|
+
const styleString = Object.entries(value)
|
404
|
+
.map(([prop, val]) => `${kebabCase(prop)}:${val}`)
|
405
|
+
.join(';');
|
406
|
+
return `style="${escapeHtml(styleString)}"`;
|
407
|
+
}
|
408
|
+
return `${key}="${escapeHtml(String(value))}"`;
|
409
|
+
})
|
410
|
+
.join(' ');
|
411
|
+
const openTag = `<${tagName}${attributeString ? ' ' + attributeString : ''}>`;
|
412
|
+
// Self-closing elements
|
413
|
+
if (voidElements.has(tagName)) {
|
414
|
+
return openTag.slice(0, -1) + '/>';
|
415
|
+
}
|
416
|
+
// Elements with children
|
417
|
+
const closeTag = `</${tagName}>`;
|
418
|
+
if (children != null) {
|
419
|
+
const childrenString = await renderNodeToString(children);
|
420
|
+
return openTag + childrenString + closeTag;
|
421
|
+
}
|
422
|
+
return openTag + closeTag;
|
423
|
+
}
|
424
|
+
function escapeHtml(text) {
|
425
|
+
const htmlEscapes = {
|
426
|
+
'&': '&',
|
427
|
+
'<': '<',
|
428
|
+
'>': '>',
|
429
|
+
'"': '"',
|
430
|
+
"'": ''',
|
431
|
+
'/': '/'
|
432
|
+
};
|
433
|
+
return text.replace(/[&<>"'/]/g, (match) => htmlEscapes[match]);
|
434
|
+
}
|
435
|
+
function kebabCase(str) {
|
436
|
+
return str.replace(/[A-Z]/g, (match) => `-${match.toLowerCase()}`);
|
437
|
+
}
|
438
|
+
|
328
439
|
function arePropsEqual(oldProps, newProps) {
|
329
440
|
const oldKeys = Object.keys(oldProps).filter(k => k !== 'children');
|
330
441
|
const newKeys = Object.keys(newProps).filter(k => k !== 'children');
|
@@ -1026,6 +1137,7 @@ const frontendHamroun = {
|
|
1026
1137
|
// Rendering
|
1027
1138
|
render,
|
1028
1139
|
hydrate,
|
1140
|
+
renderToString,
|
1029
1141
|
// Hooks
|
1030
1142
|
useState,
|
1031
1143
|
useEffect,
|
@@ -1100,6 +1212,7 @@ exports.onComponentMounted = onComponentMounted;
|
|
1100
1212
|
exports.onComponentUnmounted = onComponentUnmounted;
|
1101
1213
|
exports.onComponentUpdated = onComponentUpdated;
|
1102
1214
|
exports.render = render;
|
1215
|
+
exports.renderToString = renderToString;
|
1103
1216
|
exports.shouldComponentUpdate = shouldComponentUpdate;
|
1104
1217
|
exports.thunk = thunk;
|
1105
1218
|
exports.useContext = useContext;
|
package/dist/index.cjs.map
CHANGED
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"index.cjs","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
1
|
+
{"version":3,"file":"index.cjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
package/dist/index.d.ts
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
export { jsx, jsxs, jsxDEV, Fragment, createElement } from './jsx-runtime.js';
|
2
2
|
export { render, hydrate } from './renderer.js';
|
3
|
+
export { renderToString } from './server-renderer.js';
|
3
4
|
export { useState, useEffect, useMemo, useRef, useContext, useErrorBoundary } from './hooks.js';
|
4
5
|
export { createContext } from './context.js';
|
5
6
|
export { batchUpdates } from './batch.js';
|
@@ -12,6 +13,7 @@ export { createStore, StoreProvider, useSelector, useDispatch, useStore, logger,
|
|
12
13
|
export { LifecycleEvents, emitAppInit, emitAppMounted, emitAppUpdated, emitAppError, emitAppDestroyed, emitComponentCreated, emitComponentMounted, emitComponentUpdated, emitComponentError, emitComponentUnmounted, onAppInit, onAppMounted, onAppUpdated, onAppError, onAppDestroyed, onComponentCreated, onComponentMounted, onComponentUpdated, onComponentError, onComponentUnmounted } from './lifecycle-events.js';
|
13
14
|
import { jsx, createElement } from './jsx-runtime.js';
|
14
15
|
import { render, hydrate } from './renderer.js';
|
16
|
+
import { renderToString } from './server-renderer.js';
|
15
17
|
import { useState, useEffect, useMemo, useRef, useContext, useErrorBoundary } from './hooks.js';
|
16
18
|
import { createContext } from './context.js';
|
17
19
|
import { batchUpdates } from './batch.js';
|
@@ -37,6 +39,7 @@ declare const frontendHamroun: {
|
|
37
39
|
createElement: typeof createElement;
|
38
40
|
render: typeof render;
|
39
41
|
hydrate: typeof hydrate;
|
42
|
+
renderToString: typeof renderToString;
|
40
43
|
useState: typeof useState;
|
41
44
|
useEffect: typeof useEffect;
|
42
45
|
useMemo: typeof useMemo;
|
package/dist/index.d.ts.map
CHANGED
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
@@ -321,6 +321,117 @@ async function hydrate(element, container) {
|
|
321
321
|
}
|
322
322
|
}
|
323
323
|
|
324
|
+
async function renderToString(element) {
|
325
|
+
prepareRender(true); // Mark as SSR
|
326
|
+
try {
|
327
|
+
const html = await renderNodeToString(element);
|
328
|
+
return html;
|
329
|
+
}
|
330
|
+
finally {
|
331
|
+
finishRender();
|
332
|
+
}
|
333
|
+
}
|
334
|
+
async function renderNodeToString(node) {
|
335
|
+
// Handle null, undefined, boolean
|
336
|
+
if (node == null || typeof node === 'boolean') {
|
337
|
+
return '';
|
338
|
+
}
|
339
|
+
// Handle primitives
|
340
|
+
if (typeof node === 'string' || typeof node === 'number') {
|
341
|
+
return escapeHtml(String(node));
|
342
|
+
}
|
343
|
+
// Handle arrays
|
344
|
+
if (Array.isArray(node)) {
|
345
|
+
const results = await Promise.all(node.map(child => renderNodeToString(child)));
|
346
|
+
return results.join('');
|
347
|
+
}
|
348
|
+
// Handle objects with type and props (React-like elements)
|
349
|
+
if (node && typeof node === 'object' && 'type' in node) {
|
350
|
+
const { type, props = {} } = node;
|
351
|
+
// Handle function components
|
352
|
+
if (typeof type === 'function') {
|
353
|
+
try {
|
354
|
+
const result = await type(props);
|
355
|
+
return await renderNodeToString(result);
|
356
|
+
}
|
357
|
+
catch (error) {
|
358
|
+
console.error('Error rendering component:', error);
|
359
|
+
return `<!-- Error rendering component: ${error.message} -->`;
|
360
|
+
}
|
361
|
+
}
|
362
|
+
// Handle DOM elements
|
363
|
+
if (typeof type === 'string') {
|
364
|
+
return await renderDOMElement(type, props);
|
365
|
+
}
|
366
|
+
}
|
367
|
+
// Fallback for other objects
|
368
|
+
if (typeof node === 'object') {
|
369
|
+
return escapeHtml(JSON.stringify(node));
|
370
|
+
}
|
371
|
+
return escapeHtml(String(node));
|
372
|
+
}
|
373
|
+
async function renderDOMElement(tagName, props) {
|
374
|
+
const { children, ...attrs } = props;
|
375
|
+
// Self-closing tags
|
376
|
+
const voidElements = new Set([
|
377
|
+
'area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input',
|
378
|
+
'link', 'meta', 'param', 'source', 'track', 'wbr'
|
379
|
+
]);
|
380
|
+
// Build attributes string
|
381
|
+
const attributeString = Object.entries(attrs)
|
382
|
+
.filter(([key, value]) => {
|
383
|
+
// Filter out React-specific props and event handlers
|
384
|
+
if (key.startsWith('on') || key === 'key' || key === 'ref')
|
385
|
+
return false;
|
386
|
+
if (value == null || value === false)
|
387
|
+
return false;
|
388
|
+
return true;
|
389
|
+
})
|
390
|
+
.map(([key, value]) => {
|
391
|
+
// Handle className -> class
|
392
|
+
if (key === 'className')
|
393
|
+
key = 'class';
|
394
|
+
// Handle boolean attributes
|
395
|
+
if (value === true)
|
396
|
+
return key;
|
397
|
+
// Handle style objects
|
398
|
+
if (key === 'style' && typeof value === 'object' && value !== null) {
|
399
|
+
const styleString = Object.entries(value)
|
400
|
+
.map(([prop, val]) => `${kebabCase(prop)}:${val}`)
|
401
|
+
.join(';');
|
402
|
+
return `style="${escapeHtml(styleString)}"`;
|
403
|
+
}
|
404
|
+
return `${key}="${escapeHtml(String(value))}"`;
|
405
|
+
})
|
406
|
+
.join(' ');
|
407
|
+
const openTag = `<${tagName}${attributeString ? ' ' + attributeString : ''}>`;
|
408
|
+
// Self-closing elements
|
409
|
+
if (voidElements.has(tagName)) {
|
410
|
+
return openTag.slice(0, -1) + '/>';
|
411
|
+
}
|
412
|
+
// Elements with children
|
413
|
+
const closeTag = `</${tagName}>`;
|
414
|
+
if (children != null) {
|
415
|
+
const childrenString = await renderNodeToString(children);
|
416
|
+
return openTag + childrenString + closeTag;
|
417
|
+
}
|
418
|
+
return openTag + closeTag;
|
419
|
+
}
|
420
|
+
function escapeHtml(text) {
|
421
|
+
const htmlEscapes = {
|
422
|
+
'&': '&',
|
423
|
+
'<': '<',
|
424
|
+
'>': '>',
|
425
|
+
'"': '"',
|
426
|
+
"'": ''',
|
427
|
+
'/': '/'
|
428
|
+
};
|
429
|
+
return text.replace(/[&<>"'/]/g, (match) => htmlEscapes[match]);
|
430
|
+
}
|
431
|
+
function kebabCase(str) {
|
432
|
+
return str.replace(/[A-Z]/g, (match) => `-${match.toLowerCase()}`);
|
433
|
+
}
|
434
|
+
|
324
435
|
function arePropsEqual(oldProps, newProps) {
|
325
436
|
const oldKeys = Object.keys(oldProps).filter(k => k !== 'children');
|
326
437
|
const newKeys = Object.keys(newProps).filter(k => k !== 'children');
|
@@ -1022,6 +1133,7 @@ const frontendHamroun = {
|
|
1022
1133
|
// Rendering
|
1023
1134
|
render,
|
1024
1135
|
hydrate,
|
1136
|
+
renderToString,
|
1025
1137
|
// Hooks
|
1026
1138
|
useState,
|
1027
1139
|
useEffect,
|
@@ -1054,5 +1166,5 @@ const frontendHamroun = {
|
|
1054
1166
|
eventBus: globalEventBus
|
1055
1167
|
};
|
1056
1168
|
|
1057
|
-
export { Component, Fragment, LifecycleEvents, Link, Redirect, Route, RouterProvider, StoreProvider, Switch, batchUpdates, createContext, createElement, createEventBus, createStore, frontendHamroun as default, diff, emitAppDestroyed, emitAppError, emitAppInit, emitAppMounted, emitAppUpdated, emitComponentCreated, emitComponentError, emitComponentMounted, emitComponentUnmounted, emitComponentUpdated, globalEventBus as eventBus, hydrate, jsx, jsx as jsxDEV, jsx as jsxs, logger, onAppDestroyed, onAppError, onAppInit, onAppMounted, onAppUpdated, onComponentCreated, onComponentError, onComponentMounted, onComponentUnmounted, onComponentUpdated, render, shouldComponentUpdate, thunk, useContext, useDispatch, useEffect, useErrorBoundary, useEvent, useForm, useLocation, useMemo, useNavigate, useParams, useRef, useSelector, useState, useStore };
|
1169
|
+
export { Component, Fragment, LifecycleEvents, Link, Redirect, Route, RouterProvider, StoreProvider, Switch, batchUpdates, createContext, createElement, createEventBus, createStore, frontendHamroun as default, diff, emitAppDestroyed, emitAppError, emitAppInit, emitAppMounted, emitAppUpdated, emitComponentCreated, emitComponentError, emitComponentMounted, emitComponentUnmounted, emitComponentUpdated, globalEventBus as eventBus, hydrate, jsx, jsx as jsxDEV, jsx as jsxs, logger, onAppDestroyed, onAppError, onAppInit, onAppMounted, onAppUpdated, onComponentCreated, onComponentError, onComponentMounted, onComponentUnmounted, onComponentUpdated, render, renderToString, shouldComponentUpdate, thunk, useContext, useDispatch, useEffect, useErrorBoundary, useEvent, useForm, useLocation, useMemo, useNavigate, useParams, useRef, useSelector, useState, useStore };
|
1058
1170
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
1
|
+
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|