frontend-hamroun 1.1.46 → 1.1.48
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 +329 -149
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +82 -73
- package/dist/index.mjs.map +1 -1
- package/dist/server-renderer.d.ts +2 -1
- package/dist/templates/default.d.ts +11 -0
- package/dist/types.d.ts +3 -6
- package/package.json +1 -1
- package/templates/ssr-template/src/App.tsx +31 -21
- package/templates/ssr-template/src/client.tsx +19 -1
- package/templates/ssr-template/src/server.ts +34 -32
package/README.md
CHANGED
@@ -1,240 +1,420 @@
|
|
1
|
-
#
|
1
|
+
# Frontend Hamroun
|
2
2
|
|
3
|
-
A lightweight
|
3
|
+
A lightweight, modern frontend framework with hooks, virtual DOM, and server-side rendering capabilities.
|
4
4
|
|
5
|
-
##
|
6
|
-
|
7
|
-
```bash
|
8
|
-
npm install your-package-name
|
9
|
-
```
|
5
|
+
## Features
|
10
6
|
|
11
|
-
|
7
|
+
- 🚀 Fast Virtual DOM implementation
|
8
|
+
- 🎯 Hooks-based state management
|
9
|
+
- 🌐 Server-side rendering
|
10
|
+
- 📱 Router with dynamic routes
|
11
|
+
- 🔄 Context API
|
12
|
+
- 🛠️ TypeScript support
|
13
|
+
- 📦 Small bundle size (~12KB gzipped)
|
14
|
+
- ⚡ Code splitting support
|
12
15
|
|
13
|
-
|
16
|
+
## Installation
|
14
17
|
|
15
18
|
```bash
|
16
|
-
|
19
|
+
npm install frontend-hamroun
|
17
20
|
# or
|
18
|
-
|
19
|
-
```
|
20
|
-
Then:
|
21
|
-
|
22
|
-
```bash
|
23
|
-
cd my-app
|
24
|
-
npm install
|
25
|
-
npm run dev
|
21
|
+
yarn add frontend-hamroun
|
26
22
|
```
|
27
23
|
|
28
|
-
##
|
24
|
+
## Quick Start
|
29
25
|
|
30
|
-
```
|
31
|
-
import { render, useState } from '
|
26
|
+
```tsx
|
27
|
+
import { render, useState } from 'frontend-hamroun';
|
32
28
|
|
33
|
-
function
|
29
|
+
function Counter() {
|
34
30
|
const [count, setCount] = useState(0);
|
31
|
+
|
35
32
|
return (
|
36
|
-
<
|
37
|
-
|
38
|
-
|
39
|
-
</div>
|
33
|
+
<button onClick={() => setCount(count + 1)}>
|
34
|
+
Count: {count}
|
35
|
+
</button>
|
40
36
|
);
|
41
37
|
}
|
42
38
|
|
43
|
-
render(<
|
39
|
+
render(<Counter />, document.getElementById('root'));
|
44
40
|
```
|
45
41
|
|
46
|
-
## Features
|
47
|
-
|
48
|
-
- Virtual DOM with efficient diffing
|
49
|
-
- Hooks (useState, useEffect, useMemo, useRef)
|
50
|
-
- Context API
|
51
|
-
- Batch updates
|
52
|
-
- Hydration support
|
53
|
-
|
54
|
-
## Hooks
|
42
|
+
## Core Features
|
55
43
|
|
56
|
-
###
|
57
|
-
Manages component state.
|
44
|
+
### Hooks
|
58
45
|
|
59
46
|
```tsx
|
60
|
-
|
61
|
-
```
|
47
|
+
import { useState, useEffect, useMemo, useContext } from 'frontend-hamroun';
|
62
48
|
|
63
|
-
|
64
|
-
|
49
|
+
// State Management
|
50
|
+
const [state, setState] = useState(initialState);
|
65
51
|
|
66
|
-
|
52
|
+
// Side Effects
|
67
53
|
useEffect(() => {
|
68
54
|
// Effect code
|
69
55
|
return () => {
|
70
56
|
// Cleanup code
|
71
57
|
};
|
72
58
|
}, [dependencies]);
|
59
|
+
|
60
|
+
// Memoization
|
61
|
+
const memoizedValue = useMemo(() => computeExpensiveValue(deps), [deps]);
|
73
62
|
```
|
74
63
|
|
75
|
-
###
|
76
|
-
Memoizes expensive computations.
|
64
|
+
### Routing
|
77
65
|
|
78
66
|
```tsx
|
79
|
-
|
67
|
+
import { Link, useRouter } from 'frontend-hamroun';
|
68
|
+
|
69
|
+
function App() {
|
70
|
+
const router = useRouter();
|
71
|
+
|
72
|
+
return (
|
73
|
+
<div>
|
74
|
+
<nav>
|
75
|
+
<Link href="/">Home</Link>
|
76
|
+
<Link href="/about">About</Link>
|
77
|
+
</nav>
|
78
|
+
{router.pathname === '/' && <Home />}
|
79
|
+
{router.pathname === '/about' && <About />}
|
80
|
+
</div>
|
81
|
+
);
|
82
|
+
}
|
80
83
|
```
|
81
84
|
|
82
|
-
###
|
83
|
-
Creates a mutable reference.
|
85
|
+
### Context API
|
84
86
|
|
85
87
|
```tsx
|
86
|
-
|
88
|
+
import { createContext, useContext } from 'frontend-hamroun';
|
89
|
+
|
90
|
+
const ThemeContext = createContext('light');
|
91
|
+
|
92
|
+
function ThemedButton() {
|
93
|
+
const theme = useContext(ThemeContext);
|
94
|
+
return <button className={theme}>Click me</button>;
|
95
|
+
}
|
87
96
|
```
|
88
97
|
|
89
|
-
|
90
|
-
Handles component errors.
|
98
|
+
## Server-Side Rendering
|
91
99
|
|
100
|
+
### Quick Start
|
92
101
|
```tsx
|
93
|
-
|
102
|
+
// server.ts
|
103
|
+
import { renderToString } from 'frontend-hamroun';
|
104
|
+
|
105
|
+
const html = await renderToString(<App />, {
|
106
|
+
title: 'My SSR App',
|
107
|
+
description: 'A server-rendered application',
|
108
|
+
scripts: ['/client.js'],
|
109
|
+
initialState: {
|
110
|
+
user: { id: 1, name: 'John' }
|
111
|
+
}
|
112
|
+
});
|
94
113
|
```
|
95
114
|
|
96
|
-
|
115
|
+
### Complete SSR Setup
|
116
|
+
|
117
|
+
1. Server Setup:
|
118
|
+
```typescript
|
119
|
+
// server.ts
|
120
|
+
import express from 'express';
|
121
|
+
import { renderToString } from 'frontend-hamroun';
|
122
|
+
|
123
|
+
const app = express();
|
124
|
+
|
125
|
+
app.get('*', async (req, res) => {
|
126
|
+
try {
|
127
|
+
const html = await renderToString(<App />, {
|
128
|
+
title: 'My App',
|
129
|
+
description: 'Server-rendered app',
|
130
|
+
scripts: ['/client.js'],
|
131
|
+
styles: ['/styles.css'],
|
132
|
+
meta: {
|
133
|
+
'og:title': 'My App',
|
134
|
+
'theme-color': '#ffffff'
|
135
|
+
},
|
136
|
+
initialState: {
|
137
|
+
url: req.url,
|
138
|
+
user: req.user
|
139
|
+
},
|
140
|
+
bodyAttrs: { class: 'app-root' },
|
141
|
+
htmlAttrs: { lang: 'en' }
|
142
|
+
});
|
143
|
+
|
144
|
+
res.send(html);
|
145
|
+
} catch (error) {
|
146
|
+
res.status(500).send('Server Error');
|
147
|
+
}
|
148
|
+
});
|
149
|
+
```
|
97
150
|
|
98
|
-
|
151
|
+
2. Client Hydration:
|
152
|
+
```typescript
|
153
|
+
// client.tsx
|
154
|
+
import { hydrate } from 'frontend-hamroun';
|
155
|
+
|
156
|
+
// Type-safe state access
|
157
|
+
declare global {
|
158
|
+
interface Window {
|
159
|
+
__INITIAL_STATE__: {
|
160
|
+
url: string;
|
161
|
+
user?: { id: number; name: string };
|
162
|
+
}
|
163
|
+
}
|
164
|
+
}
|
99
165
|
|
100
|
-
|
101
|
-
const ThemeContext = createContext('light');
|
166
|
+
const { url, user } = window.__INITIAL_STATE__;
|
102
167
|
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
168
|
+
hydrate(<App url={url} user={user} />, document.getElementById('root')!);
|
169
|
+
```
|
170
|
+
|
171
|
+
3. Template Customization:
|
172
|
+
```typescript
|
173
|
+
// Custom template options
|
174
|
+
interface TemplateOptions {
|
175
|
+
title: string;
|
176
|
+
description?: string;
|
177
|
+
scripts?: string[];
|
178
|
+
styles?: string[];
|
179
|
+
meta?: Record<string, string>;
|
180
|
+
initialState?: any;
|
181
|
+
bodyAttrs?: Record<string, string>;
|
182
|
+
htmlAttrs?: Record<string, string>;
|
109
183
|
}
|
184
|
+
```
|
110
185
|
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
186
|
+
### SSR Features
|
187
|
+
|
188
|
+
- ✨ Full HTML document generation
|
189
|
+
- 🔄 Automatic state hydration
|
190
|
+
- 🎨 Customizable templates
|
191
|
+
- 📱 Meta tags for SEO
|
192
|
+
- 🛡️ XSS protection
|
193
|
+
- 🚀 Streaming support
|
194
|
+
- 📦 Asset optimization
|
195
|
+
- 🔍 Error handling
|
196
|
+
|
197
|
+
### Best Practices
|
198
|
+
|
199
|
+
1. State Management:
|
200
|
+
```typescript
|
201
|
+
// Shared types between server and client
|
202
|
+
interface AppState {
|
203
|
+
url: string;
|
204
|
+
user?: UserData;
|
205
|
+
settings: AppSettings;
|
115
206
|
}
|
207
|
+
|
208
|
+
// Server
|
209
|
+
const state: AppState = {
|
210
|
+
url: req.url,
|
211
|
+
user: await getUser(req),
|
212
|
+
settings: await getSettings()
|
213
|
+
};
|
214
|
+
|
215
|
+
// Client
|
216
|
+
const { url, user, settings } = window.__INITIAL_STATE__ as AppState;
|
116
217
|
```
|
117
218
|
|
118
|
-
|
219
|
+
2. Error Handling:
|
220
|
+
```typescript
|
221
|
+
// Server-side error boundary
|
222
|
+
try {
|
223
|
+
const html = await renderToString(<App />, options);
|
224
|
+
res.send(html);
|
225
|
+
} catch (error) {
|
226
|
+
const errorHtml = await renderToString(
|
227
|
+
<ErrorPage error={error} />,
|
228
|
+
{ title: 'Error' }
|
229
|
+
);
|
230
|
+
res.status(500).send(errorHtml);
|
231
|
+
}
|
232
|
+
```
|
119
233
|
|
120
|
-
|
121
|
-
|
234
|
+
3. Performance Optimization:
|
235
|
+
```typescript
|
236
|
+
// Caching
|
237
|
+
const cached = await cache.get(cacheKey);
|
238
|
+
if (cached) return cached;
|
239
|
+
|
240
|
+
const html = await renderToString(<App />, {
|
241
|
+
...options,
|
242
|
+
scripts: [
|
243
|
+
{ src: '/client.js', async: true, defer: true }
|
244
|
+
]
|
245
|
+
});
|
122
246
|
|
123
|
-
|
124
|
-
|
247
|
+
await cache.set(cacheKey, html, '1h');
|
248
|
+
```
|
125
249
|
|
126
|
-
|
127
|
-
|
128
|
-
|
250
|
+
### Basic SSR Setup
|
251
|
+
|
252
|
+
```typescript
|
253
|
+
// Server-side rendering with customization
|
254
|
+
const html = await renderToString(<App />, {
|
255
|
+
title: 'My App',
|
256
|
+
description: 'Server-rendered application',
|
257
|
+
scripts: ['/assets/client.js'],
|
258
|
+
styles: ['/assets/styles.css'],
|
259
|
+
meta: {
|
260
|
+
'theme-color': '#ffffff',
|
261
|
+
'og:title': 'My App',
|
262
|
+
'og:description': 'My awesome app'
|
263
|
+
},
|
264
|
+
initialState: {
|
265
|
+
user: { name: 'John' }
|
266
|
+
},
|
267
|
+
bodyAttrs: { class: 'dark-mode' },
|
268
|
+
htmlAttrs: { lang: 'en', dir: 'ltr' }
|
129
269
|
});
|
130
270
|
```
|
131
271
|
|
132
|
-
###
|
133
|
-
Prevent unnecessary re-renders.
|
272
|
+
### Express Server Integration
|
134
273
|
|
135
|
-
```
|
136
|
-
|
137
|
-
|
138
|
-
), [value]);
|
139
|
-
```
|
274
|
+
```typescript
|
275
|
+
import express from 'express';
|
276
|
+
import { renderToString } from 'frontend-hamroun';
|
140
277
|
|
141
|
-
|
278
|
+
const app = express();
|
142
279
|
|
143
|
-
|
144
|
-
|
280
|
+
app.get('*', async (req, res) => {
|
281
|
+
const initialState = {
|
282
|
+
url: req.url,
|
283
|
+
user: req.user // From your auth middleware
|
284
|
+
};
|
285
|
+
|
286
|
+
const html = await renderToString(<App />, {
|
287
|
+
title: 'My App',
|
288
|
+
scripts: ['/client.js'],
|
289
|
+
initialState
|
290
|
+
});
|
145
291
|
|
146
|
-
|
147
|
-
|
292
|
+
res.send(html);
|
293
|
+
});
|
148
294
|
```
|
149
295
|
|
150
|
-
|
296
|
+
### Client-Side Hydration
|
151
297
|
|
152
|
-
```
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
</button>
|
161
|
-
);
|
298
|
+
```typescript
|
299
|
+
import { hydrate } from 'frontend-hamroun';
|
300
|
+
|
301
|
+
// Access the server-provided state
|
302
|
+
declare global {
|
303
|
+
interface Window {
|
304
|
+
__INITIAL_STATE__: any;
|
305
|
+
}
|
162
306
|
}
|
307
|
+
|
308
|
+
const initialState = window.__INITIAL_STATE__;
|
309
|
+
|
310
|
+
hydrate(
|
311
|
+
<App initialState={initialState} />,
|
312
|
+
document.getElementById('root')!
|
313
|
+
);
|
163
314
|
```
|
164
315
|
|
165
|
-
##
|
316
|
+
## CLI Tools
|
166
317
|
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
color: 'blue',
|
172
|
-
padding: '20px'
|
173
|
-
}}>
|
174
|
-
Styled content
|
175
|
-
</div>
|
176
|
-
);
|
177
|
-
}
|
318
|
+
Create a new project:
|
319
|
+
|
320
|
+
```bash
|
321
|
+
npx create-frontend-app my-app
|
178
322
|
```
|
179
323
|
|
180
|
-
##
|
324
|
+
## Performance
|
181
325
|
|
182
|
-
|
183
|
-
|
326
|
+
- Initial bundle: 12KB gzipped
|
327
|
+
- Dynamic imports for code splitting
|
328
|
+
- Automatic batching for state updates
|
329
|
+
- Efficient virtual DOM diffing
|
330
|
+
|
331
|
+
## Security
|
332
|
+
|
333
|
+
- XSS protection
|
334
|
+
- Content Security Policy support
|
335
|
+
- Type-safe props
|
336
|
+
- Secure by default
|
337
|
+
|
338
|
+
## Browser Support
|
339
|
+
|
340
|
+
- Chrome (latest)
|
341
|
+
- Firefox (latest)
|
342
|
+
- Safari (latest)
|
343
|
+
- Edge (latest)
|
344
|
+
|
345
|
+
## Development Tools
|
346
|
+
|
347
|
+
- TypeScript support
|
348
|
+
- Hot Module Replacement
|
349
|
+
- Developer tools extension
|
350
|
+
- Error boundaries
|
351
|
+
- Performance monitoring
|
352
|
+
|
353
|
+
## Advanced Features
|
354
|
+
|
355
|
+
### Template Customization
|
356
|
+
```typescript
|
357
|
+
interface TemplateOptions {
|
358
|
+
title: string;
|
359
|
+
description?: string;
|
360
|
+
scripts?: string[];
|
361
|
+
styles?: string[];
|
362
|
+
meta?: Record<string, string>;
|
363
|
+
initialState?: any;
|
364
|
+
bodyAttrs?: Record<string, string>;
|
365
|
+
htmlAttrs?: Record<string, string>;
|
366
|
+
}
|
367
|
+
|
368
|
+
// Usage with custom template
|
369
|
+
const html = await renderToString(<App />, {
|
370
|
+
title: 'Custom Template',
|
371
|
+
styles: ['/styles.css'],
|
372
|
+
bodyAttrs: { 'data-theme': 'dark' }
|
373
|
+
});
|
374
|
+
```
|
375
|
+
|
376
|
+
### Error Handling
|
377
|
+
```typescript
|
378
|
+
// Error boundary component
|
379
|
+
function ErrorBoundary({ children }) {
|
184
380
|
const [error, resetError] = useErrorBoundary();
|
185
381
|
|
186
382
|
if (error) {
|
187
383
|
return (
|
188
|
-
<div>
|
189
|
-
<
|
384
|
+
<div role="alert">
|
385
|
+
<h2>Something went wrong</h2>
|
386
|
+
<pre>{error.message}</pre>
|
190
387
|
<button onClick={resetError}>Try again</button>
|
191
388
|
</div>
|
192
389
|
);
|
193
390
|
}
|
194
391
|
|
195
|
-
return
|
392
|
+
return children;
|
196
393
|
}
|
197
394
|
```
|
198
395
|
|
199
|
-
##
|
396
|
+
## Contributing
|
200
397
|
|
201
|
-
1.
|
202
|
-
2.
|
203
|
-
3.
|
204
|
-
4.
|
205
|
-
5.
|
206
|
-
6. Keep components small and focused
|
207
|
-
7. Use proper TypeScript types for better development experience
|
398
|
+
1. Fork the repository
|
399
|
+
2. Create your feature branch (`git checkout -b feature/amazing-feature`)
|
400
|
+
3. Commit your changes (`git commit -m 'Add amazing feature'`)
|
401
|
+
4. Push to the branch (`git push origin feature/amazing-feature`)
|
402
|
+
5. Open a Pull Request
|
208
403
|
|
209
|
-
##
|
404
|
+
## License
|
210
405
|
|
211
|
-
|
212
|
-
- `render(element, container)`
|
213
|
-
- `hydrate(element, container)`
|
214
|
-
- `createElement(vnode)`
|
406
|
+
MIT License - see the [LICENSE](LICENSE) file for details.
|
215
407
|
|
216
|
-
|
217
|
-
- `useState<T>(initial: T)`
|
218
|
-
- `useEffect(callback, deps?)`
|
219
|
-
- `useMemo(factory, deps)`
|
220
|
-
- `useRef(initial)`
|
221
|
-
- `useErrorBoundary()`
|
222
|
-
|
223
|
-
### Context
|
224
|
-
- `createContext(defaultValue)`
|
225
|
-
- `useContext(Context)`
|
226
|
-
- `Context.Provider`
|
227
|
-
- `Context.Consumer`
|
228
|
-
- `Context.useSelector`
|
229
|
-
|
230
|
-
### Performance
|
231
|
-
- `batchUpdates(callback)`
|
408
|
+
## Support
|
232
409
|
|
233
|
-
|
410
|
+
- Documentation: [Link to docs]
|
411
|
+
- Issues: [GitHub Issues]
|
412
|
+
- Discussions: [GitHub Discussions]
|
234
413
|
|
235
|
-
|
414
|
+
## Team
|
236
415
|
|
237
|
-
|
416
|
+
- Hamroun - Lead Developer
|
417
|
+
|
418
|
+
## Acknowledgments
|
238
419
|
|
239
|
-
|
240
|
-
`````
|
420
|
+
Special thanks to the open-source community and all contributors.
|
package/dist/index.js
CHANGED
@@ -1,2 +1,2 @@
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});let e=!1;const t=[];function n(n){if(e)t.push(n);else{e=!0;try{for(n();t.length>0;){const e=t.shift();null==e||e()}}finally{e=!1}}}let r=0;const o=new Map,s=new Map,
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});let e=!1;const t=[];function n(n){if(e)t.push(n);else{e=!0;try{for(n();t.length>0;){const e=t.shift();null==e||e()}}finally{e=!1}}}let r=0;const o=new Map,s=new Map,i=new Map,a=new Map,c=new Map;let l=null,p=null,u=null;const d="undefined"==typeof window,f=new Map;function h(t){if(!r)throw new Error("useState must be called within a render");if(d){f.has(r)||f.set(r,new Map);const e=f.get(r),n=s.get(r)||0;e.has(n)||e.set(n,t);const o=e.get(n),i=e=>{};return s.set(r,n+1),[o,i]}o.has(r)||o.set(r,[]);const i=o.get(r),a=s.get(r);a>=i.length&&i.push(t);const c=i[a];return s.set(r,a+1),[c,t=>{const o="function"==typeof t?t(i[a]):t;i[a]!==o&&(i[a]=o,e?n((()=>y(r))):y(r))}]}function w(e,t){if(!r)throw new Error("useEffect must be called within a render");const n=s.get(r);i.has(r)||i.set(r,[]);const o=i.get(r),a=o[n];a&&t&&a.deps&&!t.some(((e,t)=>e!==a.deps[t]))||((null==a?void 0:a.cleanup)&&a.cleanup(),queueMicrotask((()=>{const r=e()||void 0;o[n]={cleanup:r,deps:t}}))),s.set(r,n+1)}async function y(e){try{const t=i.get(e);t&&(t.forEach((e=>{e.cleanup&&e.cleanup()})),i.set(e,[])),l&&p&&u&&await l(u,p)}catch(t){console.error("Error during rerender:",t)}}function m(e,t){console.log("JSX Transform:",{type:e,props:t});const n={...t};return arguments.length>2&&(n.children=Array.prototype.slice.call(arguments,2)),{type:e,props:n}}async function g(e){var t;if(console.log("Creating element from:",e),null==e)return document.createTextNode("");if("boolean"==typeof e)return document.createTextNode("");if("number"==typeof e||"string"==typeof e)return document.createTextNode(String(e));if(Array.isArray(e)){const t=document.createDocumentFragment();for(const n of e){const e=await g(n);t.appendChild(e)}return t}if("type"in e&&void 0!==e.props){const{type:r,props:o}=e;if("function"==typeof r)try{const e=await r(o||{}),t=await g(e);return t instanceof Element&&t.setAttribute("data-component-id",r.name||r.toString()),t}catch(n){return console.error("Error rendering component:",n),document.createTextNode("")}const s=document.createElement(r);for(const[e,n]of Object.entries(o||{}))if("children"!==e)if(e.startsWith("on")&&"function"==typeof n){const r=e.toLowerCase().slice(2),o=null==(t=s.__events)?void 0:t[r];o&&s.removeEventListener(r,o),s.addEventListener(r,n),s.__events||(s.__events={}),s.__events[r]=n}else"style"===e&&"object"==typeof n?Object.assign(s.style,n):"className"===e?s.setAttribute("class",String(n)):"key"!==e&&"ref"!==e&&s.setAttribute(e,String(n));const i=null==o?void 0:o.children;if(null!=i){const e=Array.isArray(i)?i.flat():[i];for(const t of e){const e=await g(t);s.appendChild(e)}}return s}return document.createTextNode(String(e))}let b=!1;async function v(e,t){console.log("Rendering to:",t.id),n((async()=>{r++,s.set(r,0);try{!function(e,t,n){l=e,p=n,u=t}(v,e,t);const n=await g(e);b||(t.innerHTML=""),t.appendChild(n)}finally{d&&f.delete(r),r=0}}))}async function x(e){var t,n;if(null==e||"boolean"==typeof e)return"";if("number"==typeof e||"string"==typeof e)return $(String(e));if("function"==typeof e){return x(await e({}))}if(e.type){if("function"==typeof e.type){return x(await e.type(e.props||{}))}let r=`<${e.type}`;for(const[t,o]of Object.entries(e.props||{}))"children"!==t&&"key"!==t&&"ref"!==t&&("className"===t?r+=` class="${$(String(o))}"`:"style"===t&&"object"==typeof o&&null!==o?r+=` style="${n=o,Object.entries(n).map((([e,t])=>`${e}: ${t}`)).join("; ")}"`:t.startsWith("on")||(r+=` ${t}="${$(String(o))}"`));if(r+=">",null==(t=e.props)?void 0:t.children){const t=Array.isArray(e.props.children)?e.props.children:[e.props.children];for(const e of t)r+=await x(e)}return r+=`</${e.type}>`,r}return""}function $(e){return e.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'")}let S={pathname:"undefined"!=typeof window?window.location.pathname:"/",search:"undefined"!=typeof window?window.location.search:"",hash:"undefined"!=typeof window?window.location.hash:"",params:{}};const E=new Set;function j(e,t={}){"undefined"!=typeof window&&function(e,t={}){const n=new URL(e,window.location.origin),r={pathname:n.pathname,search:n.search,hash:n.hash,params:{}};t.replace?window.history.replaceState(r,"",n.toString()):window.history.pushState(r,"",n.toString()),S=r,E.forEach((e=>e(r))),t.scroll&&window.scrollTo(0,0)}(e,t)}exports.Fragment=({children:e})=>e,exports.Link=function({href:e,children:t,replace:n=!1,className:r,style:o,...s}){return{type:"a",props:{href:e,onClick:t=>{t.preventDefault(),j(e,{replace:n})},className:r,style:o,...s,children:t}}},exports.batchUpdates=n,exports.createContext=function(e){return{Provider:({value:e,children:t})=>t,Consumer:({children:t})=>t(e),_id:Symbol(),useSelector:t=>t(e)}},exports.hydrate=async function(e,t){b=!0;try{await v(e,t)}finally{b=!1}},exports.jsx=m,exports.jsxs=m,exports.render=v,exports.renderToString=async function(e,t={}){try{return function(e,t){const{title:n,description:r="",scripts:o=[],styles:s=[],initialState:i={},meta:a={},bodyAttrs:c={},htmlAttrs:l={lang:"en"}}=t,p=Object.entries(l).map((([e,t])=>`${e}="${t}"`)).join(" "),u=Object.entries(c).map((([e,t])=>`${e}="${t}"`)).join(" ");return`<!DOCTYPE html>\n<html ${p}>\n <head>\n <meta charset="UTF-8">\n <meta name="viewport" content="width=device-width, initial-scale=1.0">\n ${r?`<meta name="description" content="${r}">\n`:""}${Object.entries(a).map((([e,t])=>` <meta name="${e}" content="${t}">`)).join("\n")}\n <title>${n}</title>\n${s.map((e=>` <link rel="stylesheet" href="${e}">`)).join("\n")}\n <script>\n window.__INITIAL_STATE__ = ${JSON.stringify(i)};\n <\/script>\n </head>\n <body ${u}>\n <div id="root">${e}</div>\n${o.map((e=>` <script src="${e}" defer><\/script>`)).join("\n")}\n </body>\n</html>`}(await x(e),{title:"Frontend Hamroun App",...t})}catch(n){return console.error("Error during server rendering:",n),""}},exports.useContext=function(e){return e},exports.useEffect=w,exports.useErrorBoundary=function(){const[e,t]=h(null);return[e,()=>t(null)]},exports.useMemo=function(e,t){if(!r)throw new Error("useMemo must be called within a render");const n=s.get(r);a.has(r)||a.set(r,[]);const o=a.get(r),i=o[n];if(!i||t&&t.some(((e,t)=>!Object.is(e,i.deps[t])))){const i=e();return o[n]={value:i,deps:t},s.set(r,n+1),i}return s.set(r,n+1),i.value},exports.useRef=function(e){if(!r)throw new Error("useRef must be called within a render");const t=s.get(r);c.has(r)||c.set(r,[]);const n=c.get(r);if(t>=n.length){const o={current:e};return n.push(o),s.set(r,t+1),o}const o=n[t];return s.set(r,t+1),o},exports.useRouter=function(){const[e,t]=h(S);return w((()=>{const e=e=>{t(e)},n=()=>{S={pathname:window.location.pathname,search:window.location.search,hash:window.location.hash,params:{}},t(S)};return E.add(e),window.addEventListener("popstate",n),()=>{E.delete(e),window.removeEventListener("popstate",n)}}),[]),{...e,push:(e,t)=>j(e,t),replace:(e,t)=>j(e,{...t,replace:!0}),back:()=>window.history.back(),forward:()=>window.history.forward()}},exports.useState=h;
|
2
2
|
//# sourceMappingURL=index.js.map
|