ladrillosjs 1.0.2 โ†’ 2.0.0-beta.1

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.
Files changed (37) hide show
  1. package/README.md +533 -105
  2. package/dist/cache/functionCache.d.ts +15 -0
  3. package/dist/cache/index.d.ts +16 -0
  4. package/dist/core/componentParser.d.ts +29 -0
  5. package/dist/core/componentSource.d.ts +12 -0
  6. package/dist/core/css/cssParser.d.ts +3 -0
  7. package/dist/core/eventBus.d.ts +41 -0
  8. package/dist/core/html/htmlRenderer.d.ts +18 -0
  9. package/dist/core/html/htmlparser.d.ts +16 -0
  10. package/dist/core/js/scriptParser.d.ts +3 -0
  11. package/dist/core/main.d.ts +4 -26
  12. package/dist/core/webcomponent.d.ts +2 -2
  13. package/dist/index-CXHidyhO.js +8 -0
  14. package/dist/index-CXHidyhO.js.map +1 -0
  15. package/dist/index-VkDZJVOR.mjs +361 -0
  16. package/dist/index-VkDZJVOR.mjs.map +1 -0
  17. package/dist/index.d.ts +56 -6
  18. package/dist/ladrillosjs.cjs.js +2 -1
  19. package/dist/ladrillosjs.cjs.js.map +1 -0
  20. package/dist/ladrillosjs.es.js +12 -4
  21. package/dist/ladrillosjs.es.js.map +1 -0
  22. package/dist/ladrillosjs.umd.js +76 -18
  23. package/dist/ladrillosjs.umd.js.map +1 -0
  24. package/dist/types/LadrilloTypes.d.ts +47 -14
  25. package/dist/utils/logger.d.ts +14 -11
  26. package/dist/utils/regex.d.ts +2 -0
  27. package/dist/webcomponent-CJ3lZBZb.mjs +703 -0
  28. package/dist/webcomponent-CJ3lZBZb.mjs.map +1 -0
  29. package/dist/webcomponent-i9W7LUiv.js +70 -0
  30. package/dist/webcomponent-i9W7LUiv.js.map +1 -0
  31. package/package.json +8 -4
  32. package/dist/core/store.d.ts +0 -6
  33. package/dist/index-D_dHFObN.mjs +0 -215
  34. package/dist/index-X9YN_DbT.js +0 -3
  35. package/dist/utils/stringify.d.ts +0 -7
  36. package/dist/webcomponent-Cga3h8cx.js +0 -16
  37. package/dist/webcomponent-UTcwAakf.mjs +0 -769
package/README.md CHANGED
@@ -4,12 +4,17 @@
4
4
 
5
5
  A lightweight, zero-dependency web component framework for building modular web applications.
6
6
 
7
+ **Version 2.0** - Now rewritten in TypeScript with enhanced performance, better developer experience, and powerful new features.
8
+
7
9
  "I designed this framework to empower developers with the ability to componentize their code efficiently and effectively, without the need for a full-scale framework. By focusing on simplicity and leveraging core web fundamentals, my goal was to create a lightweight and accessible solution that enhances development while staying true to the basics."
8
10
 
9
11
  ## Table of Contents
10
12
 
11
13
  - [Features](#features)
12
14
  - [Getting Started](#getting-started)
15
+ - [Prerequisites](#prerequisites)
16
+ - [What's New in v2.0](#whats-new-in-v20)
17
+ - [Example Applications](#example-applications)
13
18
  - [Installation](#installation)
14
19
  - [Your First Component](#your-first-component)
15
20
  - [Core Concepts](#core-concepts)
@@ -21,10 +26,15 @@ A lightweight, zero-dependency web component framework for building modular web
21
26
  - [Slots](#slots)
22
27
  - [Advanced Features](#advanced-features)
23
28
  - [External Scripts](#external-scripts)
24
- - [Global State Stores](#global-state-stores)
29
+ - [Global Event Bus](#global-event-bus)
25
30
  - [Shadow DOM](#shadow-dom)
31
+ - [Performance & Caching](#performance--caching)
26
32
  - [API Reference](#api-reference)
27
33
  - [Examples](#examples)
34
+ - [Component Communication](#component-communication)
35
+ - [Dynamic Component Creation](#dynamic-component-creation)
36
+ - [Passing Complex Data](#passing-complex-data)
37
+ - [Migration Guide (v1.x to v2.0)](#migration-guide-v1x-to-v20)
28
38
  - [Contributing](#contributing)
29
39
  - [License](#license)
30
40
 
@@ -32,25 +42,51 @@ A lightweight, zero-dependency web component framework for building modular web
32
42
 
33
43
  - ๐Ÿš€ **Zero Dependencies** - Pure JavaScript, no build tools required
34
44
  - ๐Ÿ“ฆ **Single-File Components** - HTML, CSS, and JavaScript in one file
35
- - โšก **Reactive State** - Automatic re-rendering on state changes
36
- - ๐ŸŽฏ **Event System** - Built-in event emission and listening
37
- - ๐Ÿ”„ **Two-Way Data Binding** - For form inputs and contenteditable elements
45
+ - โšก **Reactive State** - Automatic re-rendering on state changes with optimized proxies
46
+ - ๐ŸŽฏ **Event System** - Built-in event emission and global event bus for component communication
47
+ - ๐Ÿ”„ **Two-Way Data Binding** - Seamless binding for form inputs with `$bind`
38
48
  - ๐ŸŽจ **Scoped Styles** - Component styles with optional Shadow DOM
39
- - ๐Ÿช **State Management** - Simple store implementation for shared state
49
+ - ๐Ÿช **Global Event Bus** - Cross-component communication without prop drilling
40
50
  - ๐Ÿ”Œ **Slots Support** - Content projection with named and default slots
41
- - ๐Ÿ“ **TypeScript Support** - Includes type definitions
51
+ - ๐Ÿ“ **TypeScript Support** - Full type definitions and TypeScript source code
52
+ - ๐ŸŽญ **Conditional Rendering** - `data-if`, `data-else-if`, and `data-else` directives
53
+ - ๐Ÿš„ **Smart Caching** - LRU cache for components and compiled functions
54
+ - ๐Ÿ”ง **Framework Utilities** - `$state`, `$setState`, `$emit`, `$listen`, `$querySelector` helpers
55
+ - โš™๏ธ **Automatic Reactivity** - Variable assignments automatically trigger re-renders
56
+ - ๐Ÿงฉ **External Scripts** - Load and bind external JavaScript with your components
42
57
 
43
58
  ## Getting Started
44
59
 
60
+ ### Prerequisites
61
+
62
+ - **Node.js**: Version 20.19+ or 22.12+ is required for development
63
+ - **TypeScript**: v5.8+ (included in devDependencies)
64
+
65
+ ### What's New in v2.0
66
+
67
+ - **๐Ÿ”„ Complete TypeScript Rewrite** - Full type safety and improved IDE support
68
+ - **โšก Performance Enhancements** - LRU caching for components and compiled functions
69
+ - **๐ŸŽฏ Global Event Bus** - New `$emit` and `$listen` for cross-component communication
70
+ - **๐Ÿ”ง Framework Utilities** - New `$state`, `$setState`, `$querySelector` helpers
71
+ - **๐Ÿš€ Automatic Reactivity** - Variable assignments like `count++` automatically trigger re-renders
72
+ - **๐Ÿ“ฆ Better Build System** - Vite-powered builds with sourcemaps and multiple output formats (ESM, UMD, CJS)
73
+ - **๐Ÿงช Testing** - Vitest with coverage reporting
74
+ - **๐ŸŽญ Enhanced Conditionals** - More robust `data-if`, `data-else-if`, `data-else` rendering
75
+ - **๐Ÿ”„ Two-Way Binding** - Simplified with `$bind` prefix for automatic state synchronization
76
+ - **๐Ÿงน Memory Management** - Automatic cleanup of event listeners on component disconnect
77
+
78
+ ### Example Applications
79
+
45
80
  The repository includes several example applications that demonstrate various features:
46
81
 
47
82
  - **[Todo App](samples/apps/todo)** - Classic todo list with component composition
48
- - **[Notes App](samples/apps/notes)** - Multi-component app with global state management
83
+ - **[Notes App](samples/apps/notes)** - Multi-component app with global event bus
49
84
  - **[Markdown Editor](samples/apps/markdown)** - Real-time markdown preview
50
85
  - **[API Example](samples/apps/api)** - Fetching and displaying external data
51
- - **[Business Card](samples/apps/biz)** - Editable form with two-way data binding
86
+ - **[Business Card](samples/apps/biz)** - Editable form with two-way data binding using `$bind`
52
87
  - **[Button Game](samples/apps/button-game)** - Interactive game with component events
53
88
  - **[Slideshow](samples/apps/slideshow)** - Multi-slide presentation system
89
+ - **[Document Chat](samples/apps/document-chat)** - Chat interface with component communication
54
90
  - **[Docs](samples/apps/docs)** - Documentation viewer with syntax highlighting
55
91
 
56
92
  To run the examples:
@@ -60,11 +96,20 @@ To run the examples:
60
96
  git clone https://github.com/drubiodev/LadrillosJS.git
61
97
  cd LadrillosJS
62
98
 
63
- # Install dependencies (for dev server only)
99
+ # Install dependencies
64
100
  npm install
65
101
 
66
- # Start the development server
102
+ # Start the development server (Vite)
67
103
  npm run dev
104
+
105
+ # Build the library
106
+ npm run build
107
+
108
+ # Run tests
109
+ npm test
110
+
111
+ # Run tests with coverage
112
+ npm run test:coverage
68
113
  ```
69
114
 
70
115
  ## Installation
@@ -78,7 +123,18 @@ npm install ladrillosjs
78
123
  ### CDN
79
124
 
80
125
  ```html
81
- <script defer src="https://cdn.jsdelivr.net/npm/ladrillosjs"></script>
126
+ <!-- Latest version -->
127
+ <script type="module">
128
+ import { registerComponent } from "https://cdn.jsdelivr.net/npm/ladrillosjs/dist/ladrillosjs.es.js";
129
+ registerComponent("my-component", "./my-component.html");
130
+ </script>
131
+
132
+ <!-- UMD (for legacy browsers) -->
133
+ <script src="https://cdn.jsdelivr.net/npm/ladrillosjs/dist/ladrillosjs.umd.js"></script>
134
+ <script>
135
+ // Access via global ladrillosjs object
136
+ ladrillosjs.registerComponent("my-component", "./my-component.html");
137
+ </script>
82
138
  ```
83
139
 
84
140
  ## Your First Component
@@ -156,50 +212,67 @@ Register single or multiple components:
156
212
  ```javascript
157
213
  // Single component
158
214
  import { registerComponent } from "ladrillosjs";
159
- registerComponent("my-component", "./my-component.html");
215
+ await registerComponent("my-component", "./my-component.html");
160
216
 
161
- // Multiple components with concurrency control
217
+ // Multiple components (v2.0 feature - currently in development)
162
218
  import { registerComponents } from "ladrillosjs";
163
- await registerComponents(
164
- [
165
- { name: "app-header", path: "./components/header.html" },
166
- { name: "app-footer", path: "./components/footer.html" },
167
- { name: "user-card", path: "./components/user-card.html" },
168
- ],
169
- 10
170
- ); // Max 10 parallel fetches (default: 5)
219
+ await registerComponents([
220
+ { name: "app-header", path: "./components/header.html" },
221
+ { name: "app-footer", path: "./components/footer.html" },
222
+ { name: "user-card", path: "./components/user-card.html" },
223
+ ]);
171
224
 
172
225
  // Using CDN
173
226
  ladrillosjs.registerComponent("my-component", "./my-component.html");
174
227
  ```
175
228
 
229
+ **Note:** The `registerComponents` function is planned for v2.0 to enable bulk registration with concurrency control.
230
+
176
231
  ### State Management
177
232
 
178
- Components have reactive state that automatically triggers re-renders:
233
+ Components have reactive state that automatically triggers re-renders. In v2.0, variable assignments are automatically tracked and trigger reactivity:
179
234
 
180
235
  ```html
181
236
  <div>
182
237
  <h2>User: {user.name}</h2>
183
238
  <p>Score: {score}</p>
184
239
  <button onclick="updateScore">Add Point</button>
240
+ <button onclick="increment">Count: {count}</button>
185
241
  </div>
186
242
 
187
243
  <script>
188
- const date = new Date(Date.now());
189
- const formattedDate = date.toLocaleDateString("en-US"); // Format: MM/DD/YYYY
190
- // Initial state
244
+ // Initial state - automatically tracked
191
245
  let score = 0;
246
+ let count = 0;
192
247
  let user = {
193
248
  name: "Player 1",
194
249
  };
195
250
 
196
251
  const updateScore = () => {
197
- // Update state and trigger re-render
252
+ // Direct assignment triggers re-render automatically
198
253
  score++;
199
254
  };
255
+
256
+ const increment = () => {
257
+ // All these automatically trigger re-renders in v2.0
258
+ count++; // Increment
259
+ count += 5; // Compound assignment
260
+ count = count * 2; // Direct assignment
261
+ };
262
+
263
+ // You can also use the explicit setState method
264
+ const updateUser = () => {
265
+ $setState({ user: { name: "Jane", age: 30 } });
266
+ };
200
267
  </script>
201
268
  ```
202
269
 
270
+ **New in v2.0:**
271
+
272
+ - **Automatic Reactivity**: `count++`, `count += 5`, and direct assignments automatically trigger re-renders
273
+ - **`$state`**: Direct access to component state within scripts
274
+ - **`$setState(updates)`**: Explicit state updates (merges with existing state)
275
+
203
276
  ### Event Handling
204
277
 
205
278
  Multiple ways to handle events:
@@ -214,9 +287,12 @@ Multiple ways to handle events:
214
287
  <!-- Inline arrow function -->
215
288
  <button onclick="(e) => console.log(e.target)">Log Target</button>
216
289
 
290
+ <!-- Component communication with event bus (v2.0) -->
291
+ <button onclick="notifyOthers">Emit Event</button>
292
+
217
293
  <script>
218
- const count = 0;
219
- this.setState({ items: [] });
294
+ let count = 0;
295
+ let items = [];
220
296
 
221
297
  const handleClick = (event) => {
222
298
  console.log("Clicked!", event);
@@ -224,9 +300,92 @@ Multiple ways to handle events:
224
300
  };
225
301
 
226
302
  const addItem = (name, value) => {
227
- this.setState({ items: [...this.state.items, { name, value }] });
303
+ items = [...items, { name, value }];
228
304
  };
305
+
306
+ // v2.0: Use $emit to send events to other components
307
+ const notifyOthers = () => {
308
+ $emit("item-added", { count, timestamp: Date.now() });
309
+ };
310
+
311
+ // v2.0: Listen for events from other components
312
+ $listen("user-logged-in", (data) => {
313
+ console.log("User logged in:", data);
314
+ count = 0; // Reset count
315
+ });
316
+ </script>
317
+ ```
318
+
319
+ **New in v2.0:**
320
+
321
+ - **`$emit(eventName, data)`**: Send events to other components via global event bus
322
+ - **`$listen(eventName, callback)`**: Listen for events from any component
323
+ - **Automatic Cleanup**: Event listeners are automatically removed when component is disconnected
324
+
325
+ ### Data Binding
326
+
327
+ LadrillosJS supports both one-way and two-way data binding:
328
+
329
+ #### One-Way Binding (Template Interpolation)
330
+
331
+ ```html
332
+ <div>
333
+ <h1>{title}</h1>
334
+ <p>{user.name} - {user.email}</p>
335
+ <span>Items: {items.length}</span>
336
+ </div>
337
+
338
+ <script>
339
+ let title = "My App";
340
+ let user = { name: "John", email: "john@example.com" };
341
+ let items = [1, 2, 3];
342
+ </script>
343
+ ```
344
+
345
+ #### Two-Way Binding (v2.0 Enhanced)
346
+
347
+ Use the `$bind` prefix to create automatic two-way bindings with form inputs:
348
+
349
+ ```html
350
+ <div>
351
+ <h2>Hello, {$name}!</h2>
352
+ <input type="text" $bind="name" placeholder="Enter your name" />
353
+
354
+ <p>Email: {$email}</p>
355
+ <input type="email" $bind="email" />
356
+
357
+ <p>Bio: {$bio}</p>
358
+ <textarea $bind="bio"></textarea>
359
+
360
+ <p>Country: {$country}</p>
361
+ <select $bind="country">
362
+ <option value="us">United States</option>
363
+ <option value="uk">United Kingdom</option>
364
+ <option value="ca">Canada</option>
365
+ </select>
366
+ </div>
367
+
368
+ <script>
369
+ // Variables with $bind are automatically synced with inputs
370
+ let $name = "World";
371
+ let $email = "";
372
+ let $bio = "";
373
+ let $country = "us";
229
374
  </script>
375
+ ```
376
+
377
+ **New in v2.0:**
378
+
379
+ - **`$bind` attribute**: Simplified two-way binding syntax
380
+ - **Automatic State Sync**: Input changes automatically update component state
381
+ - **All Input Types**: Works with text inputs, textareas, selects, checkboxes, and radio buttons
382
+ - **Nested Paths**: Supports nested object bindings like `$bind="user.email"`
383
+
384
+ ### Conditional Rendering
385
+
386
+ Control element visibility with conditional directives:
387
+
388
+ ```html
230
389
  <div>
231
390
  <h1>Shopping Cart ({items.length} items)</h1>
232
391
 
@@ -245,20 +404,27 @@ Multiple ways to handle events:
245
404
  <button data-if="!isLoggedIn" onclick="login">Login</button>
246
405
  <button data-else onclick="logout">Logout</button>
247
406
  </div>
407
+
248
408
  <script>
249
- const items = ["apple", "banana", "orange"];
250
- const isLoggedIn = false;
409
+ let items = ["apple", "banana"];
410
+ let isLoggedIn = false;
251
411
 
252
- function login() {
412
+ const login = () => {
253
413
  isLoggedIn = true;
254
- }
414
+ };
255
415
 
256
- function logout() {
416
+ const logout = () => {
257
417
  isLoggedIn = false;
258
- }
418
+ };
259
419
  </script>
260
420
  ```
261
421
 
422
+ **Conditional Directives:**
423
+
424
+ - **`data-if="expression"`**: Show element if expression is truthy
425
+ - **`data-else-if="expression"`**: Chain multiple conditions
426
+ - **`data-else`**: Fallback when all previous conditions are false
427
+
262
428
  ### Slots
263
429
 
264
430
  Content projection using slots:
@@ -290,7 +456,7 @@ Content projection using slots:
290
456
 
291
457
  ### External Scripts
292
458
 
293
- Load external JavaScript with components:
459
+ Load external JavaScript with components and bind them to the component context:
294
460
 
295
461
  ```html
296
462
  <!-- With 'bind' attribute for component context -->
@@ -299,84 +465,156 @@ Load external JavaScript with components:
299
465
  <!-- ES modules with bind -->
300
466
  <script src="./component-logic.js" type="module" bind></script>
301
467
 
302
- <!-- Regular external script -->
468
+ <!-- Regular external script (global scope) -->
303
469
  <script src="https://cdn.example.com/library.js"></script>
304
470
  ```
305
471
 
306
- For modules with `bind`, export a default function:
472
+ For modules with `bind`, export a default function that receives the component context:
307
473
 
308
474
  ```javascript
309
475
  // component-logic.js
310
476
  export default function () {
311
477
  // 'this' refers to the component instance
478
+ // Access component utilities
479
+ const { $state, $setState, $emit, $listen } = this;
480
+
312
481
  this.formatDate = (date) => {
313
482
  return new Intl.DateTimeFormat("en-US").format(date);
314
483
  };
315
484
 
316
- this.init = () => {
317
- console.log("Component initialized");
485
+ this.loadData = async () => {
486
+ const response = await fetch("/api/data");
487
+ const data = await response.json();
488
+ $setState({ data });
318
489
  };
319
490
 
491
+ // Listen for events from other components
492
+ $listen("refresh-data", () => {
493
+ this.loadData();
494
+ });
495
+
320
496
  // Called automatically if defined
321
- this.init();
497
+ if (this.init) {
498
+ this.init();
499
+ }
322
500
  }
323
501
  ```
324
502
 
325
- ### Global State Stores
503
+ **New in v2.0:**
326
504
 
327
- Share state across components:
505
+ - **Better Context Binding**: External scripts get full access to component utilities
506
+ - **`$emit` and `$listen`**: Available in external scripts for event communication
507
+ - **Automatic Initialization**: Functions are auto-attached to component context
328
508
 
329
- ```javascript
330
- // stores/userStore.js
331
- import { createStore } from "ladrillosjs";
332
-
333
- export const userStore = createStore({
334
- user: null,
335
- isAuthenticated: false,
336
- });
509
+ ### Global Event Bus
337
510
 
338
- export function login(userData) {
339
- userStore.setState({
340
- user: userData,
341
- isAuthenticated: true,
342
- });
343
- }
511
+ **New in v2.0:** The global event bus enables cross-component communication without prop drilling or shared state.
344
512
 
345
- export function logout() {
346
- userStore.setState({
347
- user: null,
348
- isAuthenticated: false,
349
- });
350
- }
513
+ ```javascript
514
+ // In any component script
515
+ // Emit an event
516
+ $emit("user-logged-in", { userId: 123, username: "john" });
517
+
518
+ // Listen for events
519
+ $listen("user-logged-in", (data) => {
520
+ console.log(`User ${data.username} logged in`);
521
+ // Update local state
522
+ isLoggedIn = true;
523
+ currentUser = data;
524
+ });
351
525
  ```
352
526
 
527
+ #### Example: Header & Login Components
528
+
353
529
  ```html
354
530
  <!-- header.html -->
355
531
  <header>
356
- <span data-if="isAuthenticated">Welcome, {user.name}!</span>
532
+ <span data-if="isLoggedIn">Welcome, {username}!</span>
357
533
  <button data-else onclick="showLogin">Login</button>
358
534
  </header>
359
535
 
360
- <script type="module" src="./header-logic.js" bind></script>
536
+ <script>
537
+ let isLoggedIn = false;
538
+ let username = "";
539
+
540
+ // Listen for login event from other components
541
+ $listen("user-logged-in", (user) => {
542
+ isLoggedIn = true;
543
+ username = user.username;
544
+ });
545
+
546
+ const showLogin = () => {
547
+ $emit("show-login-modal");
548
+ };
549
+ </script>
361
550
  ```
362
551
 
363
- ```javascript
364
- // header-logic.js
365
- import { userStore } from "../stores/userStore.js";
552
+ ```html
553
+ <!-- login-form.html -->
554
+ <form onsubmit="handleLogin">
555
+ <input type="text" $bind="username" placeholder="Username" />
556
+ <input type="password" $bind="password" placeholder="Password" />
557
+ <button type="submit">Login</button>
558
+ </form>
366
559
 
367
- export default function () {
368
- // Subscribe to store changes
369
- userStore.subscribe((state) => {
370
- this.setState({
371
- user: state.user,
372
- isAuthenticated: state.isAuthenticated,
560
+ <script>
561
+ let $username = "";
562
+ let $password = "";
563
+
564
+ const handleLogin = (e) => {
565
+ e.preventDefault();
566
+
567
+ // Emit login success event
568
+ $emit("user-logged-in", {
569
+ userId: 123,
570
+ username: $username,
373
571
  });
374
- });
375
572
 
376
- this.showLogin = () => {
377
- this.emit("show-login");
573
+ // Clear form
574
+ $username = "";
575
+ $password = "";
378
576
  };
379
- }
577
+ </script>
578
+ ```
579
+
580
+ **Event Bus Benefits:**
581
+
582
+ - **No Prop Drilling**: Components can communicate directly
583
+ - **Decoupled Architecture**: Components don't need to know about each other
584
+ - **Automatic Cleanup**: Listeners are removed when components disconnect
585
+ - **Promise Support**: `$emit` returns a promise when listeners are async
586
+
587
+ ### Removed: Global State Stores
588
+
589
+ **Breaking Change in v2.0:** The `createStore` API has been removed in favor of the more powerful global event bus pattern. Instead of shared stores, use the event bus for cross-component communication:
590
+
591
+ **Before (v1.x with stores):**
592
+
593
+ ```javascript
594
+ import { createStore } from "ladrillosjs";
595
+
596
+ export const userStore = createStore({
597
+ user: null,
598
+ isAuthenticated: false,
599
+ });
600
+
601
+ userStore.subscribe((state) => {
602
+ this.setState(state);
603
+ });
604
+ ```
605
+
606
+ **After (v2.0 with event bus):**
607
+
608
+ ```javascript
609
+ // Emit events to notify components of changes
610
+ $emit("user-updated", { user: userData, isAuthenticated: true });
611
+
612
+ // Listen for changes in components that need them
613
+ $listen("user-updated", ({ user, isAuthenticated }) => {
614
+ // Update local component state
615
+ currentUser = user;
616
+ loggedIn = isAuthenticated;
617
+ });
380
618
  ```
381
619
 
382
620
  ### Shadow DOM
@@ -385,60 +623,125 @@ Components use Shadow DOM by default for style encapsulation. To disable:
385
623
 
386
624
  ```javascript
387
625
  // Disable Shadow DOM for a component
388
- registerComponent("my-component", "./my-component.html", false);
626
+ await registerComponent("my-component", "./my-component.html", false);
389
627
 
390
- // Multiple components
391
- registerComponents([
392
- { name: "global-styles", path: "./global.html", useShadowDOM: false },
393
- { name: "isolated-widget", path: "./widget.html", useShadowDOM: true },
394
- ]);
628
+ // With Shadow DOM enabled (default)
629
+ await registerComponent("isolated-widget", "./widget.html", true);
395
630
  ```
396
631
 
632
+ **Shadow DOM Benefits:**
633
+
634
+ - **Style Isolation**: Component styles don't leak to global scope
635
+ - **Encapsulation**: Internal DOM structure is hidden from parent
636
+ - **Cleaner DOM**: Styles and scripts are scoped to component
637
+
638
+ **When to Disable:**
639
+
640
+ - Need global CSS styles to apply
641
+ - Using third-party CSS frameworks
642
+ - Debugging with browser dev tools (easier without shadow DOM)
643
+
644
+ ### Performance & Caching
645
+
646
+ **New in v2.0:** LRU (Least Recently Used) caching for improved performance:
647
+
648
+ #### Component Caching
649
+
650
+ - **25 Components**: Automatically caches up to 25 component HTML files
651
+ - **LRU Eviction**: Least recently used components are removed when cache is full
652
+ - **Faster Re-renders**: Cached components load instantly on re-use
653
+
654
+ #### Function Caching
655
+
656
+ - **100 Functions**: Caches up to 100 compiled template expressions
657
+ - **Prevents Memory Leaks**: Reuses Function objects for identical expressions
658
+ - **Example**: `{formatName("John")}` compiles once and is reused on every render
659
+
660
+ **Performance Improvements:**
661
+
662
+ - Reduced HTTP requests for components
663
+ - Faster template rendering with cached functions
664
+ - Optimized state updates with change detection
665
+ - Efficient re-rendering with minimal DOM updates
666
+
397
667
  ## API Reference
398
668
 
399
669
  ### Component Methods
400
670
 
401
- | Method | Description |
402
- | --------------------------------- | -------------------------------------------- |
403
- | `this.setState(partial)` | Update component state and trigger re-render |
404
- | `this.emit(eventName, data?)` | Dispatch a custom event |
405
- | `this.listen(eventName, handler)` | Listen for custom events |
406
- | `this.querySelector(selector)` | Query element within component |
407
- | `this.querySelectorAll(selector)` | Query all elements within component |
671
+ | Method | Description |
672
+ | ------------------- | ------------------------------------------------------------------------- |
673
+ | `setState(partial)` | Update component state and trigger re-render (merges with existing state) |
674
+
675
+ ### Framework Utilities (v2.0)
676
+
677
+ Available within component `<script>` tags:
678
+
679
+ | Utility | Description |
680
+ | ------------------------------ | -------------------------------------------------------------------- |
681
+ | `$state` | Direct access to component state object |
682
+ | `$setState(updates)` | Update state explicitly (alternative to direct assignments) |
683
+ | `$emit(eventName, data?)` | Emit event to other components via global event bus |
684
+ | `$listen(eventName, callback)` | Listen for events from other components (auto-cleanup on disconnect) |
685
+ | `$querySelector(selector)` | Query element within component's DOM (respects Shadow DOM) |
686
+ | `$querySelectorAll(selector)` | Query all matching elements within component |
687
+
688
+ ### Component Attributes
408
689
 
409
- ### Store Methods
690
+ | Attribute | Description |
691
+ | --------------------------- | ----------------------------------------------------------------------------------- |
692
+ | `$bind="variableName"` | Create two-way data binding with form inputs |
693
+ | `data-if="expression"` | Conditionally render element if expression is truthy |
694
+ | `data-else-if="expression"` | Chain multiple conditional expressions |
695
+ | `data-else` | Render when all previous conditions are false |
696
+ | `onclick="handler"` (etc.) | Attach event handlers (supports method names, inline functions, or arrow functions) |
410
697
 
411
- | Method | Description |
412
- | --------------------------- | -------------------------- |
413
- | `createStore(initialState)` | Create a new store |
414
- | `store.getState()` | Get current store state |
415
- | `store.setState(partial)` | Update store state |
416
- | `store.subscribe(callback)` | Subscribe to state changes |
417
- | `store.reset()` | Reset to initial state |
698
+ ### Registration Functions
699
+
700
+ | Function | Description |
701
+ | ---------------------------------------------- | ------------------------------------------------------ |
702
+ | `registerComponent(name, path, useShadowDOM?)` | Register a single component (returns Promise) |
703
+ | `registerComponents(components)` | **Coming soon** - Register multiple components at once |
418
704
 
419
705
  ## Examples
420
706
 
421
707
  ### Component Communication
422
708
 
709
+ **v2.0 uses the global event bus instead of custom events:**
710
+
423
711
  ```html
424
712
  <!-- parent.html -->
425
713
  <div>
426
- <child-component data-message="Hello"></child-component>
714
+ <h2>Parent Component</h2>
715
+ <p>Messages received: {messageCount}</p>
716
+ <child-component></child-component>
427
717
  </div>
428
718
 
429
719
  <script>
430
- this.listen("child-event", (data) => {
720
+ let messageCount = 0;
721
+
722
+ // Listen for events from child
723
+ $listen("child-message", (data) => {
431
724
  console.log("Received from child:", data);
725
+ messageCount++;
432
726
  });
433
727
  </script>
728
+ ```
434
729
 
730
+ ```html
435
731
  <!-- child.html -->
436
- <button onclick="sendMessage">{data-message}</button>
732
+ <div>
733
+ <h3>Child Component</h3>
734
+ <button onclick="sendMessage">Send Message to Parent</button>
735
+ </div>
437
736
 
438
737
  <script>
738
+ let count = 0;
739
+
439
740
  const sendMessage = () => {
440
- this.emit("child-event", {
441
- message: this.state["data-message"],
741
+ count++;
742
+ // Emit event that parent (or any component) can listen to
743
+ $emit("child-message", {
744
+ message: `Hello from child! (${count})`,
442
745
  timestamp: Date.now(),
443
746
  });
444
747
  };
@@ -453,19 +756,144 @@ const createCard = (userData) => {
453
756
  const card = document.createElement("user-card");
454
757
  card.setAttribute("user-id", userData.id);
455
758
  card.setAttribute("name", userData.name);
759
+ card.setAttribute("email", userData.email);
456
760
  document.querySelector("#user-list").appendChild(card);
457
761
  };
458
762
 
459
- // Fetch and create
763
+ // Fetch and create multiple components
460
764
  fetch("/api/users")
461
765
  .then((res) => res.json())
462
766
  .then((users) => users.forEach(createCard));
463
767
  ```
464
768
 
769
+ ### Passing Complex Data
770
+
771
+ Use JSON.stringify for passing objects/arrays as attributes:
772
+
773
+ ```html
774
+ <!-- In parent component -->
775
+ <script>
776
+ const user = { id: 1, name: "John", roles: ["admin", "user"] };
777
+ const items = [1, 2, 3, 4, 5];
778
+
779
+ // Create HTML with stringified data
780
+ const cardHtml = `
781
+ <user-card data-user='${JSON.stringify(user)}'></user-card>
782
+ <list-component data-items='${JSON.stringify(items)}'></list-component>
783
+ `;
784
+
785
+ // Or use the built-in stringify helper in v2.0
786
+ const cardHtml2 = `
787
+ <user-card data-user="${this.stringify(user)}"></user-card>
788
+ `;
789
+ </script>
790
+ ```
791
+
792
+ ```html
793
+ <!-- In child component (user-card.html) -->
794
+ <div>
795
+ <h3>{user.name}</h3>
796
+ <p>ID: {user.id}</p>
797
+ <p>Roles: {user.roles.join(", ")}</p>
798
+ </div>
799
+
800
+ <script>
801
+ // data-user is automatically parsed from JSON
802
+ let user = this.state["data-user"];
803
+ </script>
804
+ ```
805
+
806
+ ## Migration Guide (v1.x to v2.0)
807
+
808
+ ### Breaking Changes
809
+
810
+ 1. **Global State Stores Removed**
811
+
812
+ - **Before:** `createStore()` API
813
+ - **After:** Use global event bus with `$emit` and `$listen`
814
+
815
+ 2. **Component Registration**
816
+
817
+ - **Before:** `registerComponent()` was synchronous
818
+ - **After:** Returns a Promise, use `await` or `.then()`
819
+
820
+ 3. **Framework Utilities**
821
+
822
+ - **Before:** `this.emit()`, `this.listen()`, `this.setState()`
823
+ - **After:** Use `$emit()`, `$listen()`, `$setState()` in scripts (legacy methods still available for compatibility)
824
+
825
+ 4. **Two-Way Binding**
826
+ - **Before:** No built-in support (manual implementation)
827
+ - **After:** Use `$bind` attribute for automatic two-way binding
828
+
829
+ ### New Features to Adopt
830
+
831
+ - โœ… Use `$bind` for two-way data binding instead of manual input handling
832
+ - โœ… Replace store subscriptions with `$emit`/`$listen` event patterns
833
+ - โœ… Direct variable assignments now trigger reactivity (`count++`)
834
+ - โœ… Use `$state` for direct state access in scripts
835
+ - โœ… Leverage conditional directives: `data-if`, `data-else-if`, `data-else`
836
+
465
837
  ## Contributing
466
838
 
467
839
  Contributions are welcome! Please feel free to submit a Pull Request.
468
840
 
841
+ ### Development
842
+
843
+ ```bash
844
+ # Install dependencies
845
+ npm install
846
+
847
+ # Run development server with hot reload
848
+ npm run dev
849
+
850
+ # Run tests
851
+ npm test
852
+
853
+ # Run tests with coverage
854
+ npm run test:coverage
855
+
856
+ # Build the library
857
+ npm run build
858
+
859
+ # Build TypeScript types
860
+ npm run build:types
861
+ ```
862
+
863
+ ### Project Structure
864
+
865
+ ```
866
+ src/
867
+ โ”œโ”€โ”€ index.ts # Main entry point
868
+ โ”œโ”€โ”€ core/
869
+ โ”‚ โ”œโ”€โ”€ main.ts # Core Ladrillos class
870
+ โ”‚ โ”œโ”€โ”€ webcomponent.ts # Web component definition
871
+ โ”‚ โ”œโ”€โ”€ componentParser.ts # Component file parser
872
+ โ”‚ โ”œโ”€โ”€ componentSource.ts # Component fetching with cache
873
+ โ”‚ โ”œโ”€โ”€ eventBus.ts # Global event bus
874
+ โ”‚ โ”œโ”€โ”€ css/
875
+ โ”‚ โ”‚ โ””โ”€โ”€ cssParser.ts
876
+ โ”‚ โ”œโ”€โ”€ html/
877
+ โ”‚ โ”‚ โ”œโ”€โ”€ htmlparser.ts
878
+ โ”‚ โ”‚ โ””โ”€โ”€ htmlRenderer.ts
879
+ โ”‚ โ””โ”€โ”€ js/
880
+ โ”‚ โ””โ”€โ”€ scriptParser.ts
881
+ โ”œโ”€โ”€ cache/
882
+ โ”‚ โ”œโ”€โ”€ index.ts # LRU cache for components
883
+ โ”‚ โ””โ”€โ”€ functionCache.ts # LRU cache for compiled functions
884
+ โ”œโ”€โ”€ types/
885
+ โ”‚ โ””โ”€โ”€ LadrilloTypes.ts # TypeScript type definitions
886
+ โ””โ”€โ”€ utils/
887
+ โ”œโ”€โ”€ logger.ts # Logging utilities
888
+ โ””โ”€โ”€ regex.ts # Regex patterns
889
+ ```
890
+
469
891
  ## License
470
892
 
471
893
  MIT License - see [LICENSE](LICENSE) file for details.
894
+
895
+ ---
896
+
897
+ **LadrillosJS v2.0** - Built with โค๏ธ by [Daniel Rubio](https://github.com/drubiodev)
898
+
899
+ Rewritten in TypeScript for better performance, developer experience, and maintainability.