humanjs-core 1.0.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/README.md ADDED
@@ -0,0 +1,655 @@
1
+ # 🦉 HumanJS Framework
2
+
3
+ **A framework built for humans, not machines.**
4
+
5
+ Simple. Readable. Easy to extend. Zero magic. No build tools required.
6
+
7
+ ---
8
+
9
+ ## 🌟 Philosophy
10
+
11
+ HumanJS prioritizes human understanding over machine optimization.
12
+
13
+ ### Core Principles
14
+
15
+ 1. **Zero Magic** - Every behavior is traceable in ~200 lines of code
16
+ 2. **Human-First API** - Read like English sentences
17
+ 3. **Minimal Abstractions** - Use native DOM APIs when possible
18
+ 4. **Easy to Extend** - Modify the source, don't fight it
19
+ 5. **No Heavy Dependencies** - Pure JavaScript (ES6+), browser APIs only
20
+
21
+ ---
22
+
23
+ ## 🚀 Quick Start
24
+
25
+ ### Install from npm
26
+
27
+ ```bash
28
+ npm install humanjs-core
29
+ ```
30
+
31
+ ```javascript
32
+ import { app, html, loadHuman } from 'humanjs-core';
33
+ ```
34
+
35
+ ### Create a new app
36
+
37
+ ```bash
38
+ npx humanjs-core create my-app
39
+ ```
40
+
41
+ Then:
42
+
43
+ ```bash
44
+ cd my-app
45
+ npm install
46
+ npm start
47
+ ```
48
+
49
+ Starter structure:
50
+
51
+ ```text
52
+ src/
53
+ api/
54
+ components/
55
+ layouts/
56
+ routes/
57
+ styles/
58
+ app.js
59
+ main.js
60
+ ```
61
+
62
+ It also uses the `@/` alias for local imports:
63
+
64
+ ```js
65
+ import { homeRoute } from '@/routes/home.js';
66
+ import { AppLayout } from '@/layouts/AppLayout.js';
67
+ ```
68
+
69
+ The generated starter now ships with:
70
+ - a real navbar
71
+ - a real footer
72
+ - branded HumanJS mark
73
+ - Dracula-inspired theme
74
+ - stronger default landing page
75
+
76
+ ### 1. Clone or Download
77
+
78
+ ```bash
79
+ git clone https://github.com/kaiserofthenight/humanjs.git
80
+ cd humanjs
81
+ ```
82
+
83
+ ### 2. Open in Browser
84
+
85
+ ```bash
86
+ npm start
87
+ ```
88
+
89
+ Then open `http://localhost:8000`.
90
+
91
+ ### 2. Host It
92
+
93
+ This repo is ready for static hosting.
94
+
95
+ - GitHub Pages: deploy the repository root as-is
96
+ - Netlify/Vercel static deploy: publish the repository root
97
+ - Shared demo URLs:
98
+ - `?example=human`
99
+ - `?example=routing`
100
+ - `?example=todo`
101
+ - `?example=api`
102
+
103
+ ### 3. Your First App
104
+
105
+ ```javascript
106
+ import { app } from './src/index.js';
107
+
108
+ app.simple({
109
+ state: { count: 0 },
110
+ template: `
111
+ <div style="padding: 40px; text-align: center;">
112
+ <h1>{count}</h1>
113
+ <button @click="count += 1">+1</button>
114
+ </div>
115
+ `
116
+ });
117
+ ```
118
+
119
+ **That's it!** No compilation, no bundling, no configuration.
120
+
121
+ ### 4. Lower-Level Control
122
+
123
+ ```javascript
124
+ app.create({
125
+ state: { count: 0 },
126
+ render: (state) => {
127
+ const element = html`<button id="increment">${state.count}</button>`;
128
+ const events = {
129
+ '#increment': {
130
+ click: () => state.count += 1
131
+ }
132
+ };
133
+ return { element, events };
134
+ }
135
+ });
136
+ ```
137
+
138
+ ### 5. Simple JS
139
+
140
+ HumanJS also supports the same low-boilerplate style directly inside `.js` files.
141
+
142
+ ```javascript
143
+ import { app } from 'humanjs-core';
144
+
145
+ app.simple({
146
+ state: { count: 0, step: 1 },
147
+ template: `
148
+ <div>
149
+ <h1>{count}</h1>
150
+ <button @click="count -= step">-</button>
151
+ <button @click="count = 0">reset</button>
152
+ <button @click="count += step">+</button>
153
+ </div>
154
+ `
155
+ });
156
+ ```
157
+
158
+ Run it directly in the browser:
159
+
160
+ ```javascript
161
+ import './examples/simple-js/app.js';
162
+ ```
163
+
164
+ In this repo, that example is already the default one loaded by `npm start`.
165
+
166
+ If you still want the file-based syntax:
167
+
168
+ ```bash
169
+ humanjs compile examples/human-counter/app.human examples/human-counter/app.js
170
+ ```
171
+
172
+ Routing example:
173
+
174
+ ```javascript
175
+ import './examples/routing/app.js';
176
+ ```
177
+
178
+ That example shows:
179
+ - reusable components with `component(...)`
180
+ - reusable layouts with `layout(...)`
181
+ - route-level layouts
182
+ - route params like `/user/:id`
183
+ - query params via `getParams()`
184
+ - redirects with `beforeEach`
185
+ - protected routes
186
+ - 404 handling
187
+
188
+ ---
189
+
190
+ ## 📚 Core Concepts
191
+
192
+ ### 1. Reactive State
193
+
194
+ ```javascript
195
+ import { createState } from './src/index.js';
196
+
197
+ const state = createState({ count: 0 }, (prop, value) => {
198
+ console.log(`${prop} changed to ${value}`);
199
+ });
200
+
201
+ state.count = 5; // Triggers callback
202
+ ```
203
+
204
+ **Advanced state features:**
205
+
206
+ ```javascript
207
+ // Watch specific properties
208
+ state.$watch('count', (newVal, oldVal) => {
209
+ console.log(`Count: ${oldVal} → ${newVal}`);
210
+ });
211
+
212
+ // Computed properties
213
+ state.$computed('double', function() {
214
+ return this.count * 2;
215
+ });
216
+
217
+ // Reset state
218
+ state.$reset({ count: 0 });
219
+
220
+ // Get raw state
221
+ const raw = state.$raw();
222
+ ```
223
+
224
+ ### 2. HTML Rendering
225
+
226
+ ```javascript
227
+ import { html } from './src/index.js';
228
+
229
+ // Simple
230
+ const greeting = html`<h1>Hello, World!</h1>`;
231
+
232
+ // With dynamic values
233
+ const count = 5;
234
+ const counter = html`<div>Count: ${count}</div>`;
235
+
236
+ // With arrays
237
+ const items = ['Apple', 'Banana', 'Orange'];
238
+ const list = html`
239
+ <ul>
240
+ ${items.map(item => html`<li>${item}</li>`)}
241
+ </ul>
242
+ `;
243
+ ```
244
+
245
+ **Conditional rendering:**
246
+
247
+ ```javascript
248
+ import { when } from './src/index.js';
249
+
250
+ when(
251
+ user.isLoggedIn,
252
+ () => html`<div>Welcome, ${user.name}!</div>`,
253
+ () => html`<div>Please log in</div>`
254
+ );
255
+ ```
256
+
257
+ **List rendering:**
258
+
259
+ ```javascript
260
+ import { each } from './src/index.js';
261
+
262
+ each(users, (user) => html`
263
+ <div class="user-card">
264
+ <h3>${user.name}</h3>
265
+ <p>${user.email}</p>
266
+ </div>
267
+ `);
268
+ ```
269
+
270
+ ### 3. Components
271
+
272
+ ```javascript
273
+ import { app, html, component, layout } from './src/index.js';
274
+
275
+ const Card = component(({ title, body }) => html`
276
+ <section>
277
+ <h2>${title}</h2>
278
+ <p>${body}</p>
279
+ </section>
280
+ `);
281
+
282
+ const Page = layout(({ children }) => html`
283
+ <main class="page-shell">${children}</main>
284
+ `);
285
+
286
+ app.human({
287
+ render: () => Page({
288
+ children: Card({
289
+ title: 'Hello',
290
+ body: 'Components are just functions.'
291
+ })
292
+ })
293
+ });
294
+ ```
295
+
296
+ ### 4. Event Handling
297
+
298
+ ```javascript
299
+ app.human({
300
+ state: { query: '' },
301
+ actions: {
302
+ save({ event }) {
303
+ event.preventDefault();
304
+ const form = new FormData(event.target);
305
+ console.log(Object.fromEntries(form.entries()));
306
+ },
307
+ setQuery({ state, event }) {
308
+ state.query = event.target.value;
309
+ }
310
+ },
311
+ render: ({ state }) => html`
312
+ <form data-submit="save">
313
+ <input
314
+ name="query"
315
+ value="${state.query}"
316
+ data-input="setQuery"
317
+ placeholder="Type here"
318
+ />
319
+ <button type="submit">Save</button>
320
+ </form>
321
+ `
322
+ });
323
+ ```
324
+
325
+ **Event helpers:**
326
+
327
+ ```javascript
328
+ import { on, debounce, throttle } from './src/index.js';
329
+
330
+ // Debounce search input
331
+ const handleSearch = debounce((e) => {
332
+ state.query = e.target.value;
333
+ }, 300);
334
+
335
+ // Throttle scroll events
336
+ const handleScroll = throttle(() => {
337
+ console.log('Scrolling...');
338
+ }, 100);
339
+ ```
340
+
341
+ ### 5. Routing
342
+
343
+ ```javascript
344
+ import { createRouter, Link } from './src/index.js';
345
+
346
+ const router = createRouter({
347
+ '/': () => html`<h1>Home Page</h1>`,
348
+ '/about': () => html`<h1>About Page</h1>`,
349
+ '/user/:id': (params) => html`<h1>User ${params.id}</h1>`,
350
+ '*': () => html`<h1>404 - Not Found</h1>`
351
+ }, {
352
+ beforeEach: (to, from, params) => {
353
+ console.log(`Navigating from ${from} to ${to}`);
354
+ },
355
+ afterEach: (to, from, params) => {
356
+ console.log(`Navigated to ${to}`);
357
+ }
358
+ });
359
+
360
+ // Navigate programmatically
361
+ router.navigate('/about');
362
+
363
+ // Create links
364
+ const link = Link('/about', 'About Us', 'nav-link');
365
+ ```
366
+
367
+ ---
368
+
369
+ ## 🔌 Plugins
370
+
371
+ ### Form Validation
372
+
373
+ ```javascript
374
+ import { createValidator, rules, displayErrors } from './src/plugins/validator.js';
375
+
376
+ const validator = createValidator({
377
+ email: [rules.required, rules.email],
378
+ password: [rules.required, rules.minLength(8)],
379
+ age: [rules.required, rules.number, rules.min(18)],
380
+ confirmPassword: [rules.required, rules.match('password', 'Password')]
381
+ });
382
+
383
+ const result = validator.validate(formData);
384
+
385
+ if (!result.isValid) {
386
+ displayErrors(formElement, result.errors);
387
+ } else {
388
+ // Submit form
389
+ }
390
+ ```
391
+
392
+ **Available rules:**
393
+ - `required` - Field must have a value
394
+ - `email` - Valid email format
395
+ - `minLength(n)` - Minimum length
396
+ - `maxLength(n)` - Maximum length
397
+ - `min(n)` - Minimum numeric value
398
+ - `max(n)` - Maximum numeric value
399
+ - `pattern(regex, msg)` - Custom regex
400
+ - `url` - Valid URL
401
+ - `number` - Numeric value
402
+ - `integer` - Integer value
403
+ - `match(field, name)` - Match another field
404
+ - `custom(fn, msg)` - Custom validation
405
+
406
+ ### HTTP Client
407
+
408
+ ```javascript
409
+ import { createHttp, http } from './src/plugins/http.js';
410
+
411
+ // Use default instance
412
+ const { data } = await http.get('/api/users');
413
+ await http.post('/api/users', { name: 'John' });
414
+ await http.put('/api/users/1', { name: 'Jane' });
415
+ await http.delete('/api/users/1');
416
+
417
+ // Custom instance
418
+ const api = createHttp({
419
+ baseURL: 'https://api.example.com',
420
+ headers: { 'Authorization': 'Bearer token' },
421
+ timeout: 10000,
422
+ onRequest: (config) => {
423
+ console.log('Request:', config);
424
+ },
425
+ onResponse: (response) => {
426
+ console.log('Response:', response);
427
+ },
428
+ onError: (error) => {
429
+ console.error('Error:', error);
430
+ }
431
+ });
432
+
433
+ const users = await api.get('/users');
434
+ ```
435
+
436
+ ### Storage
437
+
438
+ ```javascript
439
+ import { local, session, createNamespace } from './src/plugins/storage.js';
440
+
441
+ // LocalStorage (persists)
442
+ local.set('user', { name: 'John', age: 30 });
443
+ const user = local.get('user');
444
+ local.remove('user');
445
+ local.clear();
446
+
447
+ // SessionStorage (cleared on close)
448
+ session.set('token', 'abc123');
449
+ const token = session.get('token');
450
+
451
+ // Namespaced storage
452
+ const appStorage = createNamespace('myapp');
453
+ appStorage.local.set('settings', { theme: 'dark' });
454
+ ```
455
+
456
+ ---
457
+
458
+ ## 🛠️ Utilities
459
+
460
+ ```javascript
461
+ import { helpers } from './src/index.js';
462
+
463
+ // Generate unique ID
464
+ const id = helpers.uid('todo'); // 'todo_1234567890_abc'
465
+
466
+ // Deep clone
467
+ const copy = helpers.clone(originalObject);
468
+
469
+ // Deep merge
470
+ const merged = helpers.merge(obj1, obj2, obj3);
471
+
472
+ // Format date
473
+ const formatted = helpers.formatDate(new Date(), 'YYYY-MM-DD HH:mm');
474
+
475
+ // Sleep/delay
476
+ await helpers.sleep(1000); // Wait 1 second
477
+
478
+ // String utilities
479
+ helpers.capitalize('hello'); // 'Hello'
480
+ helpers.truncate('Long text...', 10); // 'Long text...'
481
+
482
+ // Array utilities
483
+ helpers.shuffle([1, 2, 3, 4, 5]);
484
+ helpers.unique([1, 2, 2, 3, 3]); // [1, 2, 3]
485
+ helpers.groupBy(users, 'role');
486
+
487
+ // Object utilities
488
+ helpers.get(obj, 'user.address.city', 'Unknown');
489
+ helpers.set(obj, 'user.name', 'John');
490
+ helpers.pick(obj, ['name', 'email']);
491
+ helpers.omit(obj, ['password', 'token']);
492
+
493
+ // Async utilities
494
+ await helpers.waitFor(() => element.isReady, 5000);
495
+ await helpers.retry(() => fetchData(), 3, 1000);
496
+ ```
497
+
498
+ ---
499
+
500
+ ## 📦 Project Structure
501
+
502
+ ```
503
+ humanjs-framework/
504
+ ├── index.html # Demo page
505
+ ├── README.md # This file
506
+
507
+ ├── src/ # Framework source
508
+ │ ├── core/ # Core modules
509
+ │ │ ├── state.js # Reactive state
510
+ │ │ ├── render.js # HTML rendering
511
+ │ │ ├── component.js # Components
512
+ │ │ ├── router.js # SPA routing
513
+ │ │ └── events.js # Event handling
514
+ │ │
515
+ │ ├── plugins/ # Optional plugins
516
+ │ │ ├── validator.js # Form validation
517
+ │ │ ├── http.js # HTTP client
518
+ │ │ └── storage.js # Storage wrapper
519
+ │ │
520
+ │ ├── utils/ # Utilities
521
+ │ │ └── helpers.js # Helper functions
522
+ │ │
523
+ │ └── index.js # Main entry point
524
+
525
+ └── examples/ # Example apps
526
+ ├── todo-app/
527
+ │ └── app.js
528
+ └── api-example/
529
+ └── app.js
530
+ ```
531
+
532
+ ---
533
+
534
+ ## 🎓 Examples
535
+
536
+ ### Todo App
537
+
538
+ A complete todo application with:
539
+ - Add, edit, delete todos
540
+ - Mark as complete
541
+ - Filter (all, active, completed)
542
+ - LocalStorage persistence
543
+ - Form validation
544
+
545
+ [View Source](./examples/todo-app/app.js)
546
+
547
+ ### API Integration
548
+
549
+ Demonstrates API usage with:
550
+ - Fetch users from API
551
+ - Loading states
552
+ - Error handling
553
+ - Search and filter
554
+ - Debounced input
555
+
556
+ [View Source](./examples/api-example/app.js)
557
+
558
+ ---
559
+
560
+ ## 🆚 Comparison with Other Frameworks
561
+
562
+ ### vs React
563
+
564
+ | Feature | HumanJS | React |
565
+ |---------|---------|-------|
566
+ | Learning curve | 1 day | 1-2 weeks |
567
+ | Setup | Open HTML file | Complex build setup |
568
+ | Bundle size | ~5KB | ~40KB (min) |
569
+ | Abstraction | Minimal | Heavy (JSX, virtual DOM) |
570
+ | Debugging | Trace in source | Complex stack traces |
571
+
572
+ ### vs Vue
573
+
574
+ | Feature | HumanJS | Vue |
575
+ |---------|---------|-----|
576
+ | Template syntax | Native HTML | Custom directives |
577
+ | Reactivity | Proxy (native) | Proxy + compiler |
578
+ | Components | Functions | Classes/objects |
579
+ | Build step | None | Required for SFC |
580
+
581
+ ### vs Svelte
582
+
583
+ | Feature | HumanJS | Svelte |
584
+ |---------|---------|--------|
585
+ | Compilation | None | Required |
586
+ | Runtime size | ~5KB | ~2KB |
587
+ | Learning curve | 1 day | 3-4 days |
588
+ | Debugging | Browser native | Compiled output |
589
+
590
+ ### When to use HumanJS
591
+
592
+ ✅ **Use when:**
593
+ - Building simple to medium apps
594
+ - Learning frontend concepts
595
+ - Prototyping quickly
596
+ - Want full control
597
+ - No build step desired
598
+
599
+ ❌ **Don't use when:**
600
+ - Building complex enterprise apps
601
+ - Need large ecosystem
602
+ - Team requires specific framework experience
603
+ - Need SSR or mobile apps
604
+
605
+ ---
606
+
607
+ ## 🔮 Future Improvements
608
+
609
+ ### Optional Enhancements
610
+
611
+ 1. **Virtual DOM** - For better performance
612
+ 2. **TypeScript** - Type definitions
613
+ 3. **SSR Support** - Server-side rendering
614
+ 4. **Dev Tools** - Browser extension
615
+ 5. **Plugin System** - Third-party plugins
616
+ 6. **CLI Tool** - Project scaffolding
617
+
618
+ ### How to Extend
619
+
620
+ The framework is designed to be modified:
621
+
622
+ 1. Fork the repository
623
+ 2. Modify `src/` files directly
624
+ 3. Add new plugins in `src/plugins/`
625
+ 4. Share your improvements!
626
+
627
+ ---
628
+
629
+ ## License
630
+
631
+ MIT License - do whatever you want with it!
632
+
633
+ ---
634
+
635
+ ## Contributing
636
+
637
+ Contributions welcome! Please:
638
+
639
+ 1. Keep it simple
640
+ 2. Maintain readability
641
+ 3. Add tests for new features
642
+ 4. Update documentation
643
+
644
+ ---
645
+
646
+ ## Support
647
+
648
+ - 📧 Email: abderrazzak.elouazghi@gmail.com
649
+ - 🐛 Issues: [GitHub Issues](https://github.com/kaiserofthenight/humanjs/issues)
650
+ - 💬 Discussions: [GitHub Discussions](https://github.com/kaiserofthenight/humanjs/discussions)
651
+ - ⭐ Star us on GitHub!
652
+
653
+ ---
654
+
655
+ **Remember: Frameworks are tools, not religions. Use what makes you productive!** 🚀