frontend-hamroun 1.2.88 → 1.2.90

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/hooks.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  export declare function setRenderCallback(callback: any, element: any, container: any): void;
2
- export declare function prepareRender(component?: any): number;
2
+ export declare function prepareRender(component?: any, isServerSideRender?: boolean): number;
3
3
  export declare function finishRender(): void;
4
4
  export declare function useState<T>(initial: T): [T, (newValue: T | ((prev: T) => T)) => void];
5
5
  export declare function useEffect(callback: () => void | (() => void), deps?: any[]): void;
@@ -1 +1 @@
1
- {"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../src/hooks.ts"],"names":[],"mappings":"AAkBA,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,SAAS,EAAE,GAAG,GAAG,IAAI,CAInF;AAED,wBAAgB,aAAa,CAAC,SAAS,GAAE,GAAU,GAAG,MAAM,CAK3D;AAED,wBAAgB,YAAY,IAAI,IAAI,CAGnC;AAED,wBAAgB,QAAQ,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,QAAQ,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,IAAI,CAAC,CAoCrF;AAED,wBAAgB,SAAS,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,CAAC,MAAM,IAAI,CAAC,EAAE,IAAI,CAAC,EAAE,GAAG,EAAE,GAAG,IAAI,CAyBjF;AAED,wBAAgB,OAAO,CAAC,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,EAAE,IAAI,CAAC,EAAE,GAAG,EAAE,GAAG,CAAC,CAqB5D;AAED,wBAAgB,MAAM,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,GAAG;IAAE,OAAO,EAAE,CAAC,CAAA;CAAE,CAqBpD;AAsBD,wBAAgB,gBAAgB,IAAI,CAAC,KAAK,GAAG,IAAI,EAAE,MAAM,IAAI,CAAC,CAG7D;AAGD,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC"}
1
+ {"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../src/hooks.ts"],"names":[],"mappings":"AAmBA,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,SAAS,EAAE,GAAG,GAAG,IAAI,CAInF;AAED,wBAAgB,aAAa,CAAC,SAAS,GAAE,GAAU,EAAE,kBAAkB,GAAE,OAAe,GAAG,MAAM,CAYhG;AAED,wBAAgB,YAAY,IAAI,IAAI,CAInC;AAED,wBAAgB,QAAQ,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,QAAQ,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,IAAI,CAAC,CAyCrF;AAED,wBAAgB,SAAS,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,CAAC,MAAM,IAAI,CAAC,EAAE,IAAI,CAAC,EAAE,GAAG,EAAE,GAAG,IAAI,CAgCjF;AAED,wBAAgB,OAAO,CAAC,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,EAAE,IAAI,CAAC,EAAE,GAAG,EAAE,GAAG,CAAC,CAqB5D;AAED,wBAAgB,MAAM,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,GAAG;IAAE,OAAO,EAAE,CAAC,CAAA;CAAE,CAqBpD;AA2BD,wBAAgB,gBAAgB,IAAI,CAAC,KAAK,GAAG,IAAI,EAAE,MAAM,IAAI,CAAC,CAG7D;AAGD,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC"}
package/dist/hooks.js CHANGED
@@ -2,6 +2,7 @@ import { batchUpdates, isBatching } from './batch.js';
2
2
  // Current render ID counter
3
3
  let currentRender = 0;
4
4
  let renderContext = null;
5
+ let isSSR = false;
5
6
  // State storage
6
7
  const states = new Map();
7
8
  const stateIndices = new Map();
@@ -17,15 +18,21 @@ export function setRenderCallback(callback, element, container) {
17
18
  globalContainer = container;
18
19
  currentElement = element;
19
20
  }
20
- export function prepareRender(component = null) {
21
+ export function prepareRender(component = null, isServerSideRender = false) {
21
22
  currentRender++;
22
23
  renderContext = component;
24
+ isSSR = isServerSideRender;
23
25
  stateIndices.set(currentRender, 0);
26
+ // Initialize state array for this render if it doesn't exist
27
+ if (!states.has(currentRender)) {
28
+ states.set(currentRender, []);
29
+ }
24
30
  return currentRender;
25
31
  }
26
32
  export function finishRender() {
27
33
  renderContext = null;
28
- currentRender = 0;
34
+ // Don't reset currentRender to 0 immediately to preserve state
35
+ // currentRender = 0;
29
36
  }
30
37
  export function useState(initial) {
31
38
  if (!currentRender) {
@@ -41,6 +48,10 @@ export function useState(initial) {
41
48
  }
42
49
  const state = componentStates[index];
43
50
  const setState = (newValue) => {
51
+ // For SSR, don't actually update state
52
+ if (isSSR) {
53
+ return;
54
+ }
44
55
  const nextValue = typeof newValue === 'function'
45
56
  ? newValue(componentStates[index])
46
57
  : newValue;
@@ -60,6 +71,12 @@ export function useState(initial) {
60
71
  export function useEffect(callback, deps) {
61
72
  if (!currentRender)
62
73
  throw new Error("useEffect must be called within a render");
74
+ // Skip effects during SSR
75
+ if (isSSR) {
76
+ const effectIndex = stateIndices.get(currentRender) || 0;
77
+ stateIndices.set(currentRender, effectIndex + 1);
78
+ return;
79
+ }
63
80
  const effectIndex = stateIndices.get(currentRender) || 0;
64
81
  if (!effects.has(currentRender)) {
65
82
  effects.set(currentRender, []);
@@ -116,6 +133,10 @@ export function useRef(initial) {
116
133
  }
117
134
  async function rerender(rendererId) {
118
135
  try {
136
+ // Skip rerender during SSR
137
+ if (isSSR) {
138
+ return;
139
+ }
119
140
  // Clean up effects
120
141
  const componentEffects = effects.get(rendererId);
121
142
  if (componentEffects) {
package/dist/index.cjs CHANGED
@@ -142,6 +142,7 @@ function useContext(context) {
142
142
 
143
143
  // Current render ID counter
144
144
  let currentRender = 0;
145
+ let isSSR = false;
145
146
  // State storage
146
147
  const states = new Map();
147
148
  const stateIndices = new Map();
@@ -157,13 +158,19 @@ function setRenderCallback(callback, element, container) {
157
158
  globalContainer = container;
158
159
  currentElement = element;
159
160
  }
160
- function prepareRender(component = null) {
161
+ function prepareRender(component = null, isServerSideRender = false) {
161
162
  currentRender++;
163
+ isSSR = isServerSideRender;
162
164
  stateIndices.set(currentRender, 0);
165
+ // Initialize state array for this render if it doesn't exist
166
+ if (!states.has(currentRender)) {
167
+ states.set(currentRender, []);
168
+ }
163
169
  return currentRender;
164
170
  }
165
171
  function finishRender() {
166
- currentRender = 0;
172
+ // Don't reset currentRender to 0 immediately to preserve state
173
+ // currentRender = 0;
167
174
  }
168
175
  function useState(initial) {
169
176
  if (!currentRender) {
@@ -179,6 +186,10 @@ function useState(initial) {
179
186
  }
180
187
  const state = componentStates[index];
181
188
  const setState = (newValue) => {
189
+ // For SSR, don't actually update state
190
+ if (isSSR) {
191
+ return;
192
+ }
182
193
  const nextValue = typeof newValue === 'function'
183
194
  ? newValue(componentStates[index])
184
195
  : newValue;
@@ -198,6 +209,12 @@ function useState(initial) {
198
209
  function useEffect(callback, deps) {
199
210
  if (!currentRender)
200
211
  throw new Error("useEffect must be called within a render");
212
+ // Skip effects during SSR
213
+ if (isSSR) {
214
+ const effectIndex = stateIndices.get(currentRender) || 0;
215
+ stateIndices.set(currentRender, effectIndex + 1);
216
+ return;
217
+ }
201
218
  const effectIndex = stateIndices.get(currentRender) || 0;
202
219
  if (!effects.has(currentRender)) {
203
220
  effects.set(currentRender, []);
@@ -254,6 +271,10 @@ function useRef(initial) {
254
271
  }
255
272
  async function rerender(rendererId) {
256
273
  try {
274
+ // Skip rerender during SSR
275
+ if (isSSR) {
276
+ return;
277
+ }
257
278
  // Clean up effects
258
279
  const componentEffects = effects.get(rendererId);
259
280
  if (componentEffects) {
@@ -304,8 +325,6 @@ async function render(element, container) {
304
325
  }
305
326
  catch (error) {
306
327
  console.error('Error during render:', error);
307
- // Clean up render context on error
308
- finishRender();
309
328
  throw error;
310
329
  }
311
330
  }
@@ -325,6 +344,123 @@ async function hydrate(element, container) {
325
344
  }
326
345
  }
327
346
 
347
+ async function renderToString(element) {
348
+ prepareRender(element); // Pass the element to establish render context
349
+ try {
350
+ const html = await renderNodeToString(element);
351
+ return html;
352
+ }
353
+ finally {
354
+ }
355
+ }
356
+ async function renderNodeToString(node) {
357
+ // Handle null, undefined, boolean
358
+ if (node == null || typeof node === 'boolean') {
359
+ return '';
360
+ }
361
+ // Handle primitives
362
+ if (typeof node === 'string' || typeof node === 'number') {
363
+ return escapeHtml(String(node));
364
+ }
365
+ // Handle arrays
366
+ if (Array.isArray(node)) {
367
+ const results = await Promise.all(node.map(child => renderNodeToString(child)));
368
+ return results.join('');
369
+ }
370
+ // Handle objects with type and props (React-like elements)
371
+ if (node && typeof node === 'object' && 'type' in node) {
372
+ const { type, props = {} } = node;
373
+ // Handle function components
374
+ if (typeof type === 'function') {
375
+ try {
376
+ // Set up a new render context for this component
377
+ const componentRenderId = prepareRender(type);
378
+ try {
379
+ const result = await type(props);
380
+ return await renderNodeToString(result);
381
+ }
382
+ finally {
383
+ finishRender();
384
+ }
385
+ }
386
+ catch (error) {
387
+ console.error('Error rendering component:', error);
388
+ return `<!-- Error rendering component: ${error.message} -->`;
389
+ }
390
+ }
391
+ // Handle DOM elements
392
+ if (typeof type === 'string') {
393
+ return await renderDOMElement(type, props);
394
+ }
395
+ }
396
+ // Fallback for other objects
397
+ if (typeof node === 'object') {
398
+ return escapeHtml(JSON.stringify(node));
399
+ }
400
+ return escapeHtml(String(node));
401
+ }
402
+ async function renderDOMElement(tagName, props) {
403
+ const { children, ...attrs } = props;
404
+ // Self-closing tags
405
+ const voidElements = new Set([
406
+ 'area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input',
407
+ 'link', 'meta', 'param', 'source', 'track', 'wbr'
408
+ ]);
409
+ // Build attributes string
410
+ const attributeString = Object.entries(attrs)
411
+ .filter(([key, value]) => {
412
+ // Filter out React-specific props and event handlers
413
+ if (key.startsWith('on') || key === 'key' || key === 'ref')
414
+ return false;
415
+ if (value == null || value === false)
416
+ return false;
417
+ return true;
418
+ })
419
+ .map(([key, value]) => {
420
+ // Handle className -> class
421
+ if (key === 'className')
422
+ key = 'class';
423
+ // Handle boolean attributes
424
+ if (value === true)
425
+ return key;
426
+ // Handle style objects
427
+ if (key === 'style' && typeof value === 'object' && value !== null) {
428
+ const styleString = Object.entries(value)
429
+ .map(([prop, val]) => `${kebabCase(prop)}:${val}`)
430
+ .join(';');
431
+ return `style="${escapeHtml(styleString)}"`;
432
+ }
433
+ return `${key}="${escapeHtml(String(value))}"`;
434
+ })
435
+ .join(' ');
436
+ const openTag = `<${tagName}${attributeString ? ' ' + attributeString : ''}>`;
437
+ // Self-closing elements
438
+ if (voidElements.has(tagName)) {
439
+ return openTag.slice(0, -1) + '/>';
440
+ }
441
+ // Elements with children
442
+ const closeTag = `</${tagName}>`;
443
+ if (children != null) {
444
+ const childrenString = await renderNodeToString(children);
445
+ return openTag + childrenString + closeTag;
446
+ }
447
+ return openTag + closeTag;
448
+ }
449
+ function escapeHtml(text) {
450
+ const htmlEscapes = {
451
+ '&': '&amp;',
452
+ '<': '&lt;',
453
+ '>': '&gt;',
454
+ '"': '&quot;',
455
+ "'": '&#x27;',
456
+ '/': '&#x2F;'
457
+ };
458
+ return text.replace(/[&<>"'/]/g, (match) => htmlEscapes[match]);
459
+ }
460
+ function kebabCase(str) {
461
+ return str.replace(/[A-Z]/g, (match) => `-${match.toLowerCase()}`);
462
+ }
463
+
328
464
  function arePropsEqual(oldProps, newProps) {
329
465
  const oldKeys = Object.keys(oldProps).filter(k => k !== 'children');
330
466
  const newKeys = Object.keys(newProps).filter(k => k !== 'children');
@@ -1026,6 +1162,7 @@ const frontendHamroun = {
1026
1162
  // Rendering
1027
1163
  render,
1028
1164
  hydrate,
1165
+ renderToString,
1029
1166
  // Hooks
1030
1167
  useState,
1031
1168
  useEffect,
@@ -1100,6 +1237,7 @@ exports.onComponentMounted = onComponentMounted;
1100
1237
  exports.onComponentUnmounted = onComponentUnmounted;
1101
1238
  exports.onComponentUpdated = onComponentUpdated;
1102
1239
  exports.render = render;
1240
+ exports.renderToString = renderToString;
1103
1241
  exports.shouldComponentUpdate = shouldComponentUpdate;
1104
1242
  exports.thunk = thunk;
1105
1243
  exports.useContext = useContext;
@@ -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;
@@ -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
@@ -138,6 +138,7 @@ function useContext(context) {
138
138
 
139
139
  // Current render ID counter
140
140
  let currentRender = 0;
141
+ let isSSR = false;
141
142
  // State storage
142
143
  const states = new Map();
143
144
  const stateIndices = new Map();
@@ -153,13 +154,19 @@ function setRenderCallback(callback, element, container) {
153
154
  globalContainer = container;
154
155
  currentElement = element;
155
156
  }
156
- function prepareRender(component = null) {
157
+ function prepareRender(component = null, isServerSideRender = false) {
157
158
  currentRender++;
159
+ isSSR = isServerSideRender;
158
160
  stateIndices.set(currentRender, 0);
161
+ // Initialize state array for this render if it doesn't exist
162
+ if (!states.has(currentRender)) {
163
+ states.set(currentRender, []);
164
+ }
159
165
  return currentRender;
160
166
  }
161
167
  function finishRender() {
162
- currentRender = 0;
168
+ // Don't reset currentRender to 0 immediately to preserve state
169
+ // currentRender = 0;
163
170
  }
164
171
  function useState(initial) {
165
172
  if (!currentRender) {
@@ -175,6 +182,10 @@ function useState(initial) {
175
182
  }
176
183
  const state = componentStates[index];
177
184
  const setState = (newValue) => {
185
+ // For SSR, don't actually update state
186
+ if (isSSR) {
187
+ return;
188
+ }
178
189
  const nextValue = typeof newValue === 'function'
179
190
  ? newValue(componentStates[index])
180
191
  : newValue;
@@ -194,6 +205,12 @@ function useState(initial) {
194
205
  function useEffect(callback, deps) {
195
206
  if (!currentRender)
196
207
  throw new Error("useEffect must be called within a render");
208
+ // Skip effects during SSR
209
+ if (isSSR) {
210
+ const effectIndex = stateIndices.get(currentRender) || 0;
211
+ stateIndices.set(currentRender, effectIndex + 1);
212
+ return;
213
+ }
197
214
  const effectIndex = stateIndices.get(currentRender) || 0;
198
215
  if (!effects.has(currentRender)) {
199
216
  effects.set(currentRender, []);
@@ -250,6 +267,10 @@ function useRef(initial) {
250
267
  }
251
268
  async function rerender(rendererId) {
252
269
  try {
270
+ // Skip rerender during SSR
271
+ if (isSSR) {
272
+ return;
273
+ }
253
274
  // Clean up effects
254
275
  const componentEffects = effects.get(rendererId);
255
276
  if (componentEffects) {
@@ -300,8 +321,6 @@ async function render(element, container) {
300
321
  }
301
322
  catch (error) {
302
323
  console.error('Error during render:', error);
303
- // Clean up render context on error
304
- finishRender();
305
324
  throw error;
306
325
  }
307
326
  }
@@ -321,6 +340,123 @@ async function hydrate(element, container) {
321
340
  }
322
341
  }
323
342
 
343
+ async function renderToString(element) {
344
+ prepareRender(element); // Pass the element to establish render context
345
+ try {
346
+ const html = await renderNodeToString(element);
347
+ return html;
348
+ }
349
+ finally {
350
+ }
351
+ }
352
+ async function renderNodeToString(node) {
353
+ // Handle null, undefined, boolean
354
+ if (node == null || typeof node === 'boolean') {
355
+ return '';
356
+ }
357
+ // Handle primitives
358
+ if (typeof node === 'string' || typeof node === 'number') {
359
+ return escapeHtml(String(node));
360
+ }
361
+ // Handle arrays
362
+ if (Array.isArray(node)) {
363
+ const results = await Promise.all(node.map(child => renderNodeToString(child)));
364
+ return results.join('');
365
+ }
366
+ // Handle objects with type and props (React-like elements)
367
+ if (node && typeof node === 'object' && 'type' in node) {
368
+ const { type, props = {} } = node;
369
+ // Handle function components
370
+ if (typeof type === 'function') {
371
+ try {
372
+ // Set up a new render context for this component
373
+ const componentRenderId = prepareRender(type);
374
+ try {
375
+ const result = await type(props);
376
+ return await renderNodeToString(result);
377
+ }
378
+ finally {
379
+ finishRender();
380
+ }
381
+ }
382
+ catch (error) {
383
+ console.error('Error rendering component:', error);
384
+ return `<!-- Error rendering component: ${error.message} -->`;
385
+ }
386
+ }
387
+ // Handle DOM elements
388
+ if (typeof type === 'string') {
389
+ return await renderDOMElement(type, props);
390
+ }
391
+ }
392
+ // Fallback for other objects
393
+ if (typeof node === 'object') {
394
+ return escapeHtml(JSON.stringify(node));
395
+ }
396
+ return escapeHtml(String(node));
397
+ }
398
+ async function renderDOMElement(tagName, props) {
399
+ const { children, ...attrs } = props;
400
+ // Self-closing tags
401
+ const voidElements = new Set([
402
+ 'area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input',
403
+ 'link', 'meta', 'param', 'source', 'track', 'wbr'
404
+ ]);
405
+ // Build attributes string
406
+ const attributeString = Object.entries(attrs)
407
+ .filter(([key, value]) => {
408
+ // Filter out React-specific props and event handlers
409
+ if (key.startsWith('on') || key === 'key' || key === 'ref')
410
+ return false;
411
+ if (value == null || value === false)
412
+ return false;
413
+ return true;
414
+ })
415
+ .map(([key, value]) => {
416
+ // Handle className -> class
417
+ if (key === 'className')
418
+ key = 'class';
419
+ // Handle boolean attributes
420
+ if (value === true)
421
+ return key;
422
+ // Handle style objects
423
+ if (key === 'style' && typeof value === 'object' && value !== null) {
424
+ const styleString = Object.entries(value)
425
+ .map(([prop, val]) => `${kebabCase(prop)}:${val}`)
426
+ .join(';');
427
+ return `style="${escapeHtml(styleString)}"`;
428
+ }
429
+ return `${key}="${escapeHtml(String(value))}"`;
430
+ })
431
+ .join(' ');
432
+ const openTag = `<${tagName}${attributeString ? ' ' + attributeString : ''}>`;
433
+ // Self-closing elements
434
+ if (voidElements.has(tagName)) {
435
+ return openTag.slice(0, -1) + '/>';
436
+ }
437
+ // Elements with children
438
+ const closeTag = `</${tagName}>`;
439
+ if (children != null) {
440
+ const childrenString = await renderNodeToString(children);
441
+ return openTag + childrenString + closeTag;
442
+ }
443
+ return openTag + closeTag;
444
+ }
445
+ function escapeHtml(text) {
446
+ const htmlEscapes = {
447
+ '&': '&amp;',
448
+ '<': '&lt;',
449
+ '>': '&gt;',
450
+ '"': '&quot;',
451
+ "'": '&#x27;',
452
+ '/': '&#x2F;'
453
+ };
454
+ return text.replace(/[&<>"'/]/g, (match) => htmlEscapes[match]);
455
+ }
456
+ function kebabCase(str) {
457
+ return str.replace(/[A-Z]/g, (match) => `-${match.toLowerCase()}`);
458
+ }
459
+
324
460
  function arePropsEqual(oldProps, newProps) {
325
461
  const oldKeys = Object.keys(oldProps).filter(k => k !== 'children');
326
462
  const newKeys = Object.keys(newProps).filter(k => k !== 'children');
@@ -1022,6 +1158,7 @@ const frontendHamroun = {
1022
1158
  // Rendering
1023
1159
  render,
1024
1160
  hydrate,
1161
+ renderToString,
1025
1162
  // Hooks
1026
1163
  useState,
1027
1164
  useEffect,
@@ -1054,5 +1191,5 @@ const frontendHamroun = {
1054
1191
  eventBus: globalEventBus
1055
1192
  };
1056
1193
 
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 };
1194
+ 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
1195
  //# 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":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"renderComponent.d.ts","sourceRoot":"","sources":["../src/renderComponent.ts"],"names":[],"mappings":"AAKA;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,KAAK,CAAC;CACf;AAED;;GAEG;AACH,wBAAsB,eAAe,CAAC,SAAS,EAAE,GAAG,EAAE,KAAK,GAAE,GAAQ,GAAG,OAAO,CAAC,YAAY,CAAC,CAqB5F;AAED,eAAe,eAAe,CAAC"}
1
+ {"version":3,"file":"renderComponent.d.ts","sourceRoot":"","sources":["../src/renderComponent.ts"],"names":[],"mappings":"AAMA;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,KAAK,CAAC;CACf;AAED;;GAEG;AACH,wBAAsB,eAAe,CAAC,SAAS,EAAE,GAAG,EAAE,KAAK,GAAE,GAAQ,GAAG,OAAO,CAAC,YAAY,CAAC,CA4B5F;AAED,eAAe,eAAe,CAAC"}
@@ -2,19 +2,27 @@
2
2
  * Utility for rendering components to strings and hydrating them
3
3
  */
4
4
  import { renderToString } from './server-renderer.js';
5
+ import { prepareRender, finishRender } from './hooks.js';
5
6
  /**
6
7
  * Renders a component to an HTML string with error handling
7
8
  */
8
9
  export async function renderComponent(Component, props = {}) {
9
10
  try {
10
- // Call the component function with props
11
- const element = Component(props);
12
- // Convert the element to an HTML string
13
- const html = await renderToString(element);
14
- return {
15
- html,
16
- success: true
17
- };
11
+ // Prepare render context for SSR
12
+ const renderId = prepareRender(Component, true);
13
+ try {
14
+ // Call the component function with props
15
+ const element = Component(props);
16
+ // Convert the element to an HTML string
17
+ const html = await renderToString(element);
18
+ return {
19
+ html,
20
+ success: true
21
+ };
22
+ }
23
+ finally {
24
+ finishRender();
25
+ }
18
26
  }
19
27
  catch (error) {
20
28
  console.error('Error rendering component:', error);
@@ -1,6 +1,6 @@
1
1
  import { prepareRender, finishRender } from './hooks.js';
2
2
  export async function renderToString(element) {
3
- const renderId = prepareRender(true); // Mark as SSR
3
+ const renderId = prepareRender(element); // Pass the element to establish render context
4
4
  try {
5
5
  const html = await renderNodeToString(element);
6
6
  return html;
@@ -29,8 +29,15 @@ async function renderNodeToString(node) {
29
29
  // Handle function components
30
30
  if (typeof type === 'function') {
31
31
  try {
32
- const result = await type(props);
33
- return await renderNodeToString(result);
32
+ // Set up a new render context for this component
33
+ const componentRenderId = prepareRender(type);
34
+ try {
35
+ const result = await type(props);
36
+ return await renderNodeToString(result);
37
+ }
38
+ finally {
39
+ finishRender();
40
+ }
34
41
  }
35
42
  catch (error) {
36
43
  console.error('Error rendering component:', error);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "frontend-hamroun",
3
- "version": "1.2.88",
3
+ "version": "1.2.90",
4
4
  "description": "A lightweight frontend JavaScript framework with React-like syntax",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.js",