ladrillosjs 2.0.0-beta.6 → 2.0.0-rc.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.
- package/LICENSE +21 -0
- package/README.md +69 -12
- package/dist/core/cache/expressionCache.d.ts +80 -0
- package/dist/core/component/bindingParser.d.ts +2 -0
- package/dist/core/component/cache.d.ts +22 -0
- package/dist/core/component/extract.d.ts +2 -0
- package/dist/core/component/loader.d.ts +10 -0
- package/dist/core/component/webcomponent.d.ts +29 -0
- package/dist/core/configure.d.ts +28 -0
- package/dist/core/css/cssParser/cssParser.d.ts +3 -0
- package/dist/core/diff/listDiff.d.ts +83 -0
- package/dist/core/directives/directiveProcessor.d.ts +58 -0
- package/dist/core/events/eventBus.d.ts +136 -0
- package/dist/core/helpers/frameworkHelpers.d.ts +38 -0
- package/dist/core/html/htmlparser.d.ts +13 -0
- package/dist/core/js/moduleExecutor.d.ts +118 -0
- package/dist/core/js/reactivity.d.ts +52 -0
- package/dist/core/js/scriptParser.d.ts +48 -0
- package/dist/core/ladrillos.d.ts +68 -0
- package/dist/core/lazy/index.d.ts +6 -0
- package/dist/core/lazy/lazyLoader.d.ts +22 -0
- package/dist/core/lazy/lazyStrategies.d.ts +73 -0
- package/dist/core/reactivity/dependencyTracker.d.ts +120 -0
- package/dist/core/scheduler/batchScheduler.d.ts +97 -0
- package/dist/core.d.ts +10 -9
- package/dist/core.js +2 -1
- package/dist/core.js.map +1 -0
- package/dist/events.js +1 -0
- package/dist/events.js.map +1 -0
- package/dist/index.d.ts +11 -9
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -0
- package/dist/lazy.d.ts +1 -1
- package/dist/lazy.js +2 -1
- package/dist/lazy.js.map +1 -0
- package/dist/shared-CqJzci1Q.js +2 -0
- package/dist/shared-CqJzci1Q.js.map +1 -0
- package/dist/shared-DGGk2qBc.js +1 -0
- package/dist/shared-DGGk2qBc.js.map +1 -0
- package/dist/shared-DKFppTJL.js +2 -0
- package/dist/shared-DKFppTJL.js.map +1 -0
- package/dist/types/index.d.ts +171 -0
- package/dist/utils/devWarnings.d.ts +133 -0
- package/dist/utils/directives.d.ts +149 -0
- package/dist/utils/jsevents.d.ts +4 -0
- package/dist/utils/keyModifiers.d.ts +106 -0
- package/dist/utils/regex.d.ts +5 -0
- package/dist/utils/sandbox.d.ts +25 -0
- package/package.json +44 -13
- package/dist/shared-Dru_qCE_.js +0 -1
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Daniel Rubio
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -44,7 +44,10 @@
|
|
|
44
44
|
### 1. Add the Script
|
|
45
45
|
|
|
46
46
|
```html
|
|
47
|
-
<script
|
|
47
|
+
<script type="module">
|
|
48
|
+
import ladrillosjs from "https://cdn.jsdelivr.net/npm/ladrillosjs@2/dist/index.js";
|
|
49
|
+
window.ladrillosjs = ladrillosjs;
|
|
50
|
+
</script>
|
|
48
51
|
```
|
|
49
52
|
|
|
50
53
|
### 2. Create a Component
|
|
@@ -89,9 +92,9 @@ Save this as `counter.html`:
|
|
|
89
92
|
<!DOCTYPE html>
|
|
90
93
|
<html>
|
|
91
94
|
<head>
|
|
92
|
-
<script src="https://cdn.jsdelivr.net/npm/ladrillosjs/dist/ladrillosjs.umd.js"></script>
|
|
93
95
|
<script type="module">
|
|
94
|
-
|
|
96
|
+
import { registerComponent } from "https://cdn.jsdelivr.net/npm/ladrillosjs@2/dist/index.js";
|
|
97
|
+
registerComponent("my-counter", "./counter.html");
|
|
95
98
|
</script>
|
|
96
99
|
</head>
|
|
97
100
|
<body>
|
|
@@ -108,20 +111,27 @@ That's it! Your reactive component is ready. 🎉
|
|
|
108
111
|
|
|
109
112
|
### CDN (No Build Step)
|
|
110
113
|
|
|
114
|
+
LadrillosJS v2 is distributed as native ES modules. Import directly from a CDN:
|
|
115
|
+
|
|
111
116
|
```html
|
|
112
|
-
<!--
|
|
113
|
-
<script src="https://cdn.jsdelivr.net/npm/ladrillosjs/dist/ladrillosjs.umd.js"></script>
|
|
117
|
+
<!-- ES Module (recommended) -->
|
|
114
118
|
<script type="module">
|
|
115
|
-
|
|
119
|
+
import {
|
|
120
|
+
registerComponent,
|
|
121
|
+
registerComponents,
|
|
122
|
+
} from "https://cdn.jsdelivr.net/npm/ladrillosjs@2/dist/index.js";
|
|
123
|
+
|
|
124
|
+
registerComponent("my-component", "./component.html");
|
|
116
125
|
</script>
|
|
117
126
|
|
|
118
|
-
<!--
|
|
127
|
+
<!-- Also available on unpkg -->
|
|
119
128
|
<script type="module">
|
|
120
|
-
import { registerComponent } from "https://
|
|
121
|
-
registerComponent("my-component", "./component.html");
|
|
129
|
+
import { registerComponent } from "https://unpkg.com/ladrillosjs@2/dist/index.js";
|
|
122
130
|
</script>
|
|
123
131
|
```
|
|
124
132
|
|
|
133
|
+
> **Note:** LadrillosJS v2 is ESM-only. Legacy UMD/IIFE global builds are not published to npm.
|
|
134
|
+
|
|
125
135
|
### NPM (With Build Tools)
|
|
126
136
|
|
|
127
137
|
```bash
|
|
@@ -141,6 +151,22 @@ await registerComponents([
|
|
|
141
151
|
]);
|
|
142
152
|
```
|
|
143
153
|
|
|
154
|
+
### Granular Imports (Tree-Shaking)
|
|
155
|
+
|
|
156
|
+
```javascript
|
|
157
|
+
// Full API
|
|
158
|
+
import { registerComponent, $emit, $listen } from "ladrillosjs";
|
|
159
|
+
|
|
160
|
+
// Core only (no lazy loading, no event bus)
|
|
161
|
+
import { registerComponent } from "ladrillosjs/core";
|
|
162
|
+
|
|
163
|
+
// Lazy loading strategies only
|
|
164
|
+
import { lazyOnVisible, lazyOnIdle } from "ladrillosjs/lazy";
|
|
165
|
+
|
|
166
|
+
// Event bus only
|
|
167
|
+
import { $emit, $listen } from "ladrillosjs/events";
|
|
168
|
+
```
|
|
169
|
+
|
|
144
170
|
---
|
|
145
171
|
|
|
146
172
|
## 📖 Core Concepts
|
|
@@ -418,7 +444,7 @@ Force a lazy component to load immediately by adding the `eager` attribute:
|
|
|
418
444
|
|
|
419
445
|
## 📋 API Reference
|
|
420
446
|
|
|
421
|
-
### registerComponent
|
|
447
|
+
### `registerComponent`
|
|
422
448
|
|
|
423
449
|
```javascript
|
|
424
450
|
registerComponent(name, path, useShadowDOM?, lazy?)
|
|
@@ -442,7 +468,7 @@ registerComponent("my-nav", "./nav.html", false);
|
|
|
442
468
|
registerComponent("my-footer", "./footer.html", true, lazyOnVisible());
|
|
443
469
|
```
|
|
444
470
|
|
|
445
|
-
### registerComponents
|
|
471
|
+
### `registerComponents`
|
|
446
472
|
|
|
447
473
|
Register multiple components with parallel fetching:
|
|
448
474
|
|
|
@@ -456,6 +482,37 @@ const result = await registerComponents([
|
|
|
456
482
|
// Returns: { success: [...], failed: [...], skipped: [...] }
|
|
457
483
|
```
|
|
458
484
|
|
|
485
|
+
### `$use`
|
|
486
|
+
|
|
487
|
+
Infer the component tag name from the file path:
|
|
488
|
+
|
|
489
|
+
```javascript
|
|
490
|
+
await $use("./components/user-card.html"); // Registers as <user-card>
|
|
491
|
+
```
|
|
492
|
+
|
|
493
|
+
### `loadLazyComponent`
|
|
494
|
+
|
|
495
|
+
Force a lazy component to load immediately from JavaScript:
|
|
496
|
+
|
|
497
|
+
```javascript
|
|
498
|
+
import { loadLazyComponent } from "ladrillosjs";
|
|
499
|
+
|
|
500
|
+
await loadLazyComponent("my-lazy-footer");
|
|
501
|
+
```
|
|
502
|
+
|
|
503
|
+
### `configure`
|
|
504
|
+
|
|
505
|
+
Configure framework-level options (optional):
|
|
506
|
+
|
|
507
|
+
```javascript
|
|
508
|
+
import { configure } from "ladrillosjs";
|
|
509
|
+
|
|
510
|
+
configure({
|
|
511
|
+
cacheSize: 50, // Component LRU cache size (default: 25)
|
|
512
|
+
onError: (err) => telemetry.capture(err), // Custom error handler
|
|
513
|
+
});
|
|
514
|
+
```
|
|
515
|
+
|
|
459
516
|
### Event Bus
|
|
460
517
|
|
|
461
518
|
| Function | Description |
|
|
@@ -539,7 +596,7 @@ A complete CRUD example combining all directives:
|
|
|
539
596
|
|
|
540
597
|
function toggleTodo(id) {
|
|
541
598
|
todos = todos.map((t) =>
|
|
542
|
-
t.id === id ? { ...t, completed: !t.completed } : t
|
|
599
|
+
t.id === id ? { ...t, completed: !t.completed } : t,
|
|
543
600
|
);
|
|
544
601
|
}
|
|
545
602
|
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Expression Cache
|
|
3
|
+
*
|
|
4
|
+
* Caches compiled expression evaluators to avoid repeated Function() construction.
|
|
5
|
+
*
|
|
6
|
+
* Creating functions via new Function() is expensive:
|
|
7
|
+
* - Parsing the function body
|
|
8
|
+
* - JIT compilation
|
|
9
|
+
* - Memory allocation
|
|
10
|
+
*
|
|
11
|
+
* By caching the compiled functions, we only pay this cost once per unique expression.
|
|
12
|
+
*/
|
|
13
|
+
type ExpressionEvaluator = (context: Record<string, unknown>) => unknown;
|
|
14
|
+
/**
|
|
15
|
+
* Gets or creates a cached expression evaluator.
|
|
16
|
+
*
|
|
17
|
+
* @param expression - The expression to compile (e.g., "count + 1")
|
|
18
|
+
* @param contextKeys - Variable names available in scope
|
|
19
|
+
* @returns A function that evaluates the expression against a context
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* const evaluate = getCachedEvaluator("count * 2", ["count"]);
|
|
23
|
+
* const result = evaluate({ count: 5 }); // 10
|
|
24
|
+
*/
|
|
25
|
+
export declare function getCachedEvaluator(expression: string, contextKeys: string[]): ExpressionEvaluator;
|
|
26
|
+
/**
|
|
27
|
+
* Clears all expression caches.
|
|
28
|
+
* Useful for testing or when context shape changes dramatically.
|
|
29
|
+
*/
|
|
30
|
+
export declare function clearExpressionCache(): void;
|
|
31
|
+
/**
|
|
32
|
+
* Gets or creates a cached regex for variable boundary matching.
|
|
33
|
+
*
|
|
34
|
+
* @param variableName - The variable name to match
|
|
35
|
+
* @returns A regex that matches the variable as a whole word
|
|
36
|
+
*/
|
|
37
|
+
export declare function getCachedVariableRegex(variableName: string): RegExp;
|
|
38
|
+
/**
|
|
39
|
+
* Cached check if an expression depends on a variable.
|
|
40
|
+
*
|
|
41
|
+
* @param expression - The expression to check
|
|
42
|
+
* @param variableName - The variable to look for
|
|
43
|
+
* @returns true if the expression references the variable
|
|
44
|
+
*/
|
|
45
|
+
export declare function expressionDependsOnCached(expression: string, variableName: string): boolean;
|
|
46
|
+
/**
|
|
47
|
+
* Gets or creates a cached path array from a dot-notation string.
|
|
48
|
+
*
|
|
49
|
+
* @param pathString - The dot-notation path (e.g., "person.address.city")
|
|
50
|
+
* @returns Array of path segments
|
|
51
|
+
*
|
|
52
|
+
* @example
|
|
53
|
+
* getCachedPath("person.name") // ["person", "name"]
|
|
54
|
+
*/
|
|
55
|
+
export declare function getCachedPath(pathString: string): readonly string[];
|
|
56
|
+
/**
|
|
57
|
+
* Resolves a value from an object using a cached path.
|
|
58
|
+
*
|
|
59
|
+
* @param obj - The object to read from
|
|
60
|
+
* @param pathString - Dot-notation path
|
|
61
|
+
* @returns The value at the path, or undefined
|
|
62
|
+
*
|
|
63
|
+
* @example
|
|
64
|
+
* getByPath({ person: { name: "John" } }, "person.name") // "John"
|
|
65
|
+
*/
|
|
66
|
+
export declare function getByPath(obj: Record<string, unknown>, pathString: string): unknown;
|
|
67
|
+
/**
|
|
68
|
+
* Sets a value on an object using a cached path.
|
|
69
|
+
*
|
|
70
|
+
* @param obj - The object to write to
|
|
71
|
+
* @param pathString - Dot-notation path
|
|
72
|
+
* @param value - The value to set
|
|
73
|
+
*
|
|
74
|
+
* @example
|
|
75
|
+
* const obj = { person: { name: "John" } };
|
|
76
|
+
* setByPath(obj, "person.name", "Jane");
|
|
77
|
+
* // obj.person.name === "Jane"
|
|
78
|
+
*/
|
|
79
|
+
export declare function setByPath(obj: Record<string, unknown>, pathString: string, value: unknown): void;
|
|
80
|
+
export {};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Set the maximum number of component sources retained in the LRU cache.
|
|
3
|
+
* When the new size is smaller than the current cache, the least-recently
|
|
4
|
+
* used entries are evicted until the limit is satisfied.
|
|
5
|
+
*/
|
|
6
|
+
export declare const setCacheSize: (size: number) => void;
|
|
7
|
+
/**
|
|
8
|
+
* LRU Cache: Gets cached content and marks it as recently used
|
|
9
|
+
* Moves the accessed item to the end of the Map (most recently used position)
|
|
10
|
+
* This ensures frequently accessed components stay in cache longer
|
|
11
|
+
* @param path - The file path to retrieve from cache
|
|
12
|
+
* @returns The cached content or undefined if not found
|
|
13
|
+
*/
|
|
14
|
+
export declare const getCachedComponentSource: (path: string) => string | undefined;
|
|
15
|
+
/**
|
|
16
|
+
* LRU Cache: Stores content with automatic eviction of least recently used items
|
|
17
|
+
* Maintains cache size limit by removing oldest items when full
|
|
18
|
+
* Updates existing items without affecting cache size
|
|
19
|
+
* @param path - The file path to cache
|
|
20
|
+
* @param content - The content to store
|
|
21
|
+
*/
|
|
22
|
+
export declare const setCachedComponentSource: (path: string, content: string) => void;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Result of fetching a component source
|
|
3
|
+
*/
|
|
4
|
+
export interface FetchComponentResult {
|
|
5
|
+
/** The HTML source content */
|
|
6
|
+
source: string;
|
|
7
|
+
/** The actual resolved path (may differ from input for folder-as-component) */
|
|
8
|
+
resolvedPath: string;
|
|
9
|
+
}
|
|
10
|
+
export declare function fetchComponentSource(path: string): Promise<FetchComponentResult | undefined>;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { LadrillosComponent } from '../../types';
|
|
2
|
+
/**
|
|
3
|
+
* Creates a Web Component class from a Ladrillos component definition.
|
|
4
|
+
*
|
|
5
|
+
* This function creates the class but does NOT register it with customElements.
|
|
6
|
+
* Use createWebComponent() if you want to both create and register.
|
|
7
|
+
*
|
|
8
|
+
* Follows the Web Components specification:
|
|
9
|
+
* - Proper lifecycle callbacks (connectedCallback, disconnectedCallback, etc.)
|
|
10
|
+
* - Observed attributes with attributeChangedCallback
|
|
11
|
+
* - Shadow DOM encapsulation (optional)
|
|
12
|
+
* - Reactive state that syncs with the DOM
|
|
13
|
+
*
|
|
14
|
+
* - Attributes from HTML OVERRIDE script variable defaults
|
|
15
|
+
* - Script variables serve as DEFAULT values when no attribute is provided
|
|
16
|
+
*
|
|
17
|
+
* Example:
|
|
18
|
+
* <my-counter count="5"></my-counter> <!-- count = 5, not the default -->
|
|
19
|
+
* <my-counter></my-counter> <!-- count = 0 (script default) -->
|
|
20
|
+
*/
|
|
21
|
+
export declare function createWebComponentClass(component: LadrillosComponent, useShadowDOM: boolean): typeof HTMLElement;
|
|
22
|
+
/**
|
|
23
|
+
* Creates and registers a Web Component from a Ladrillos component.
|
|
24
|
+
*
|
|
25
|
+
* This is the main entry point that:
|
|
26
|
+
* 1. Creates the component class
|
|
27
|
+
* 2. Registers it with customElements.define
|
|
28
|
+
*/
|
|
29
|
+
export declare function createWebComponent(component: LadrillosComponent, useShadowDOM: boolean): void;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { LadrillosErrorHandler } from '../utils/devWarnings';
|
|
2
|
+
/**
|
|
3
|
+
* Options accepted by `configure()`.
|
|
4
|
+
*/
|
|
5
|
+
export interface LadrillosConfig {
|
|
6
|
+
/**
|
|
7
|
+
* Maximum number of component source files retained in the LRU cache.
|
|
8
|
+
* Defaults to 25. Must be a positive integer.
|
|
9
|
+
*/
|
|
10
|
+
cacheSize?: number;
|
|
11
|
+
/**
|
|
12
|
+
* Custom error handler. Called in addition to the framework's built-in
|
|
13
|
+
* console logging so embedders can route framework errors to telemetry.
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* configure({
|
|
17
|
+
* onError: (err) => telemetry.capture(err),
|
|
18
|
+
* });
|
|
19
|
+
*/
|
|
20
|
+
onError?: LadrillosErrorHandler | null;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Configure framework-level options.
|
|
24
|
+
*
|
|
25
|
+
* Safe to call at any time; subsequent calls override prior values. Pass
|
|
26
|
+
* `onError: null` to clear a previously registered handler.
|
|
27
|
+
*/
|
|
28
|
+
export declare function configure(config: LadrillosConfig): void;
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Keyed List Diffing Algorithm
|
|
3
|
+
*
|
|
4
|
+
* Uses a simplified LIS (Longest Increasing Subsequence) approach
|
|
5
|
+
* for optimal DOM operations.
|
|
6
|
+
*
|
|
7
|
+
* Benefits:
|
|
8
|
+
* - Minimizes DOM operations (moves instead of recreate)
|
|
9
|
+
* - Preserves element state (focus, scroll, animations)
|
|
10
|
+
* - O(n) best case, O(n log n) worst case
|
|
11
|
+
*
|
|
12
|
+
* Usage with $for:
|
|
13
|
+
* $for="item in items track by item.id"
|
|
14
|
+
* ^^^^^^^^^^^^^^
|
|
15
|
+
* Key expression for efficient diffing
|
|
16
|
+
*/
|
|
17
|
+
export interface DiffOperation {
|
|
18
|
+
type: "insert" | "remove" | "move" | "update";
|
|
19
|
+
/** Index in the old array (for remove/move/update) */
|
|
20
|
+
oldIndex?: number;
|
|
21
|
+
/** Index in the new array (for insert/move/update) */
|
|
22
|
+
newIndex?: number;
|
|
23
|
+
/** The item data */
|
|
24
|
+
item?: unknown;
|
|
25
|
+
/** Key for keyed operations */
|
|
26
|
+
key?: unknown;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Computes the minimal set of DOM operations to transform oldItems into newItems.
|
|
30
|
+
* Uses keys for identity matching - items with the same key are considered the same.
|
|
31
|
+
*
|
|
32
|
+
* @param oldItems - Previous array items
|
|
33
|
+
* @param newItems - New array items
|
|
34
|
+
* @param getKey - Function to extract a unique key from an item
|
|
35
|
+
* @returns Array of operations to perform
|
|
36
|
+
*
|
|
37
|
+
* @example
|
|
38
|
+
* const ops = diffKeyed(
|
|
39
|
+
* [{ id: 1, name: 'A' }, { id: 2, name: 'B' }],
|
|
40
|
+
* [{ id: 2, name: 'B' }, { id: 1, name: 'A' }, { id: 3, name: 'C' }],
|
|
41
|
+
* item => item.id
|
|
42
|
+
* );
|
|
43
|
+
* // ops = [
|
|
44
|
+
* // { type: 'move', oldIndex: 1, newIndex: 0, key: 2 },
|
|
45
|
+
* // { type: 'move', oldIndex: 0, newIndex: 1, key: 1 },
|
|
46
|
+
* // { type: 'insert', newIndex: 2, key: 3, item: { id: 3, name: 'C' } }
|
|
47
|
+
* // ]
|
|
48
|
+
*/
|
|
49
|
+
export declare function diffKeyed<T>(oldItems: T[], newItems: T[], getKey: (item: T, index: number) => unknown): DiffOperation[];
|
|
50
|
+
/**
|
|
51
|
+
* Simpler diff for non-keyed lists.
|
|
52
|
+
* Less efficient but works when items don't have stable identity.
|
|
53
|
+
*
|
|
54
|
+
* @param oldLength - Previous array length
|
|
55
|
+
* @param newLength - New array length
|
|
56
|
+
* @param newItems - New array items
|
|
57
|
+
* @returns Array of operations
|
|
58
|
+
*/
|
|
59
|
+
export declare function diffUnkeyed<T>(oldLength: number, newLength: number, newItems: T[]): DiffOperation[];
|
|
60
|
+
/**
|
|
61
|
+
* Creates a key getter function from a key expression.
|
|
62
|
+
*
|
|
63
|
+
* @param keyExpr - Key expression (e.g., "item.id" or just "id" if item is scope)
|
|
64
|
+
* @param itemName - The loop variable name (e.g., "item")
|
|
65
|
+
* @returns A function that extracts the key from an item
|
|
66
|
+
*
|
|
67
|
+
* @example
|
|
68
|
+
* const getKey = createKeyGetter("item.id", "item");
|
|
69
|
+
* getKey({ id: 123, name: "foo" }) // 123
|
|
70
|
+
*/
|
|
71
|
+
export declare function createKeyGetter<T>(keyExpr: string | undefined, itemName: string): (item: T, index: number) => unknown;
|
|
72
|
+
/**
|
|
73
|
+
* Applies diff operations to a list of DOM elements.
|
|
74
|
+
* This is the main integration point with the loop renderer.
|
|
75
|
+
*
|
|
76
|
+
* @param container - Parent element containing the list
|
|
77
|
+
* @param elements - Current rendered elements
|
|
78
|
+
* @param operations - Diff operations to apply
|
|
79
|
+
* @param createFn - Function to create a new element for an item
|
|
80
|
+
* @param updateFn - Function to update an existing element
|
|
81
|
+
* @returns The new array of elements
|
|
82
|
+
*/
|
|
83
|
+
export declare function applyDiffOperations<T>(container: Element | ShadowRoot, elements: Element[], operations: DiffOperation[], createFn: (item: T, index: number) => Element, updateFn: (element: Element, item: T, index: number) => void): Element[];
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { ConditionalDescriptor, LoopDescriptor, TwoWayBindingDescriptor } from '../../types';
|
|
2
|
+
export type RefMap = Map<string, HTMLElement>;
|
|
3
|
+
export type DirectiveContext = {
|
|
4
|
+
loops: LoopDescriptor[];
|
|
5
|
+
conditionals: ConditionalDescriptor[][];
|
|
6
|
+
twoWayBindings: TwoWayBindingDescriptor[];
|
|
7
|
+
refs: RefMap;
|
|
8
|
+
showElements: ShowDescriptor[];
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* Registry for two-way bindings.
|
|
12
|
+
* Maps state keys to the elements bound to them.
|
|
13
|
+
*/
|
|
14
|
+
export type TwoWayBindingRegistry = Map<string, Array<{
|
|
15
|
+
element: HTMLElement;
|
|
16
|
+
path: string[];
|
|
17
|
+
isContentEditable?: boolean;
|
|
18
|
+
}>>;
|
|
19
|
+
export type ShowDescriptor = {
|
|
20
|
+
element: HTMLElement;
|
|
21
|
+
expression: string;
|
|
22
|
+
originalDisplay: string;
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* Scans the template for all directives and returns descriptors for each.
|
|
26
|
+
* This should be called after the template HTML is injected into the DOM.
|
|
27
|
+
*/
|
|
28
|
+
export declare function scanDirectives(host: HTMLElement | ShadowRoot): DirectiveContext;
|
|
29
|
+
/**
|
|
30
|
+
* Scans the template for all directives and returns descriptors for each.
|
|
31
|
+
* This version accepts an existing refs Map to populate (used when refs
|
|
32
|
+
* need to be available before scripts run).
|
|
33
|
+
*/
|
|
34
|
+
export declare function scanDirectivesWithRefs(host: HTMLElement | ShadowRoot, existingRefs: RefMap): DirectiveContext;
|
|
35
|
+
/**
|
|
36
|
+
* Scans for $ref directives only and populates the refs Map.
|
|
37
|
+
* This can be called early (before scripts run) to make refs available.
|
|
38
|
+
*/
|
|
39
|
+
export declare function scanRefsOnly(host: HTMLElement | ShadowRoot, refs: RefMap): void;
|
|
40
|
+
/**
|
|
41
|
+
* Renders all loops with the current state.
|
|
42
|
+
*/
|
|
43
|
+
export declare function renderLoops(loops: LoopDescriptor[], state: Record<string, unknown>, evaluateExpression: (expr: string, context: Record<string, unknown>) => unknown): void;
|
|
44
|
+
/**
|
|
45
|
+
* Updates all conditionals with the current state.
|
|
46
|
+
*/
|
|
47
|
+
export declare function updateConditionals(conditionals: ConditionalDescriptor[][], state: Record<string, unknown>, evaluateExpression: (expr: string, context: Record<string, unknown>) => unknown): void;
|
|
48
|
+
/**
|
|
49
|
+
* Updates all $show elements with the current state.
|
|
50
|
+
*/
|
|
51
|
+
export declare function updateShowElements(showElements: ShowDescriptor[], state: Record<string, unknown>, evaluateExpression: (expr: string, context: Record<string, unknown>) => unknown): void;
|
|
52
|
+
/**
|
|
53
|
+
* Sets up two-way bindings and returns a registry for state→input sync.
|
|
54
|
+
*
|
|
55
|
+
* Returns a function that should be called when state changes to update
|
|
56
|
+
* all bound input elements with the new state values.
|
|
57
|
+
*/
|
|
58
|
+
export declare function setupTwoWayBindings(bindings: TwoWayBindingDescriptor[], state: Record<string, unknown>, evaluateExpression: (expr: string, context: Record<string, unknown>) => unknown): (changedKey?: string) => void;
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LadrillosJS Global Event Bus
|
|
3
|
+
*
|
|
4
|
+
* Provides cross-component communication without prop drilling.
|
|
5
|
+
*
|
|
6
|
+
* Usage:
|
|
7
|
+
* - $emit("event-name", data) - Emit an event to all listeners
|
|
8
|
+
* - $listen("event-name", callback) - Listen for events from any component
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```html
|
|
12
|
+
* <!-- Component A: Emitting events -->
|
|
13
|
+
* <script>
|
|
14
|
+
* const login = () => {
|
|
15
|
+
* $emit("user-logged-in", { userId: 123, username: "john" });
|
|
16
|
+
* };
|
|
17
|
+
* </script>
|
|
18
|
+
*
|
|
19
|
+
* <!-- Component B: Listening for events -->
|
|
20
|
+
* <script>
|
|
21
|
+
* let isLoggedIn = false;
|
|
22
|
+
* let username = "";
|
|
23
|
+
*
|
|
24
|
+
* $listen("user-logged-in", (user) => {
|
|
25
|
+
* isLoggedIn = true;
|
|
26
|
+
* username = user.username;
|
|
27
|
+
* });
|
|
28
|
+
* </script>
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
/**
|
|
32
|
+
* Event listener callback function type
|
|
33
|
+
*/
|
|
34
|
+
export type EventListener<T = unknown> = (data: T) => void;
|
|
35
|
+
/**
|
|
36
|
+
* Public alias for EventListener (for external API)
|
|
37
|
+
*/
|
|
38
|
+
export type EventCallback<T = unknown> = EventListener<T>;
|
|
39
|
+
/**
|
|
40
|
+
* Internal listener registration with metadata for cleanup
|
|
41
|
+
*/
|
|
42
|
+
interface ListenerRegistration {
|
|
43
|
+
callback: EventListener;
|
|
44
|
+
componentId?: string;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Unsubscribe function returned by $listen
|
|
48
|
+
*/
|
|
49
|
+
export type Unsubscribe = () => void;
|
|
50
|
+
/**
|
|
51
|
+
* Global event bus interface for type safety
|
|
52
|
+
*/
|
|
53
|
+
interface GlobalEventBus {
|
|
54
|
+
listeners: Map<string, Set<ListenerRegistration>>;
|
|
55
|
+
componentListeners: Map<string, Set<{
|
|
56
|
+
event: string;
|
|
57
|
+
registration: ListenerRegistration;
|
|
58
|
+
}>>;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Extend globalThis to include our event bus
|
|
62
|
+
*/
|
|
63
|
+
declare global {
|
|
64
|
+
var __ladrillosEventBus: GlobalEventBus | undefined;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Emit an event to all registered listeners.
|
|
68
|
+
*
|
|
69
|
+
* @param eventName - The name of the event to emit
|
|
70
|
+
* @param data - Optional data to pass to listeners
|
|
71
|
+
*
|
|
72
|
+
* @example
|
|
73
|
+
* ```js
|
|
74
|
+
* $emit("user-logged-in", { userId: 123, username: "john" });
|
|
75
|
+
* $emit("show-modal");
|
|
76
|
+
* $emit("item-added", { id: 1, name: "Product" });
|
|
77
|
+
* ```
|
|
78
|
+
*/
|
|
79
|
+
export declare function $emit<T = unknown>(eventName: string, data?: T): void;
|
|
80
|
+
/**
|
|
81
|
+
* Listen for events from any component.
|
|
82
|
+
*
|
|
83
|
+
* @param eventName - The name of the event to listen for
|
|
84
|
+
* @param callback - Function to call when the event is emitted
|
|
85
|
+
* @param componentId - Optional component ID for automatic cleanup
|
|
86
|
+
* @returns Unsubscribe function to remove the listener
|
|
87
|
+
*
|
|
88
|
+
* @example
|
|
89
|
+
* ```js
|
|
90
|
+
* // Basic usage
|
|
91
|
+
* $listen("user-logged-in", (user) => {
|
|
92
|
+
* console.log(`Welcome, ${user.username}!`);
|
|
93
|
+
* isLoggedIn = true;
|
|
94
|
+
* });
|
|
95
|
+
*
|
|
96
|
+
* // With unsubscribe
|
|
97
|
+
* const unsubscribe = $listen("notifications", handleNotification);
|
|
98
|
+
* // Later: unsubscribe();
|
|
99
|
+
* ```
|
|
100
|
+
*/
|
|
101
|
+
export declare function $listen<T = unknown>(eventName: string, callback: EventListener<T>, componentId?: string): Unsubscribe;
|
|
102
|
+
/**
|
|
103
|
+
* Remove all listeners registered by a specific component.
|
|
104
|
+
* Called automatically when a component is disconnected from the DOM.
|
|
105
|
+
*
|
|
106
|
+
* @param componentId - The component's unique ID
|
|
107
|
+
*/
|
|
108
|
+
export declare function cleanupComponentListeners(componentId: string): void;
|
|
109
|
+
/**
|
|
110
|
+
* Remove all event listeners (useful for testing)
|
|
111
|
+
*/
|
|
112
|
+
export declare function clearAllListeners(): void;
|
|
113
|
+
/**
|
|
114
|
+
* Get the count of listeners for an event (useful for debugging)
|
|
115
|
+
*/
|
|
116
|
+
export declare function getListenerCount(eventName: string): number;
|
|
117
|
+
/**
|
|
118
|
+
* Check if an event has any listeners
|
|
119
|
+
*/
|
|
120
|
+
export declare function hasListeners(eventName: string): boolean;
|
|
121
|
+
/**
|
|
122
|
+
* Creates event bus helpers bound to a specific component.
|
|
123
|
+
* This enables automatic cleanup when the component is disconnected.
|
|
124
|
+
*
|
|
125
|
+
* @param componentId - The unique ID of the component
|
|
126
|
+
* @returns Object containing bound $emit and $listen functions
|
|
127
|
+
*/
|
|
128
|
+
export declare function createEventBusHelpers(componentId: string): {
|
|
129
|
+
$emit: <T = unknown>(eventName: string, data?: T) => void;
|
|
130
|
+
$listen: <T = unknown>(eventName: string, callback: EventListener<T>) => Unsubscribe;
|
|
131
|
+
};
|
|
132
|
+
/**
|
|
133
|
+
* Names of event bus helpers (for Function parameter lists)
|
|
134
|
+
*/
|
|
135
|
+
export declare const eventBusHelperNames: string[];
|
|
136
|
+
export {};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { ComponentConfig, RegisterComponentsResult } from '../ladrillos';
|
|
2
|
+
import { LazyStrategy } from '../lazy';
|
|
3
|
+
/**
|
|
4
|
+
* Wraps a Map in a Proxy to allow cleaner dot notation access.
|
|
5
|
+
* Supports both $refs.inputEl and $refs.get("inputEl") syntax.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* const $refs = createRefsProxy(new Map());
|
|
9
|
+
* $refs.set("input", document.querySelector("input"));
|
|
10
|
+
* $refs.input.focus(); // Works!
|
|
11
|
+
* $refs.get("input").focus(); // Also works!
|
|
12
|
+
*/
|
|
13
|
+
export declare function createRefsProxy<T extends HTMLElement = HTMLElement>(map: Map<string, T>): Map<string, T> & Record<string, T>;
|
|
14
|
+
/**
|
|
15
|
+
* Creates framework helpers bound to a specific component's base URL.
|
|
16
|
+
* This ensures relative paths like "./buttons.html" resolve correctly
|
|
17
|
+
* relative to the component that calls registerComponent.
|
|
18
|
+
*
|
|
19
|
+
* @param componentUrl - The absolute URL of the component (e.g., "http://localhost/header/header.html")
|
|
20
|
+
* @returns Object containing bound helper functions
|
|
21
|
+
*/
|
|
22
|
+
export declare function createFrameworkHelpers(componentUrl: string): {
|
|
23
|
+
registerComponent: (name: string, path: string, useShadowDOM?: boolean, lazy?: boolean | LazyStrategy) => Promise<void>;
|
|
24
|
+
registerComponents: (configs: ComponentConfig[] | Record<string, string | Omit<ComponentConfig, "name">>) => Promise<RegisterComponentsResult>;
|
|
25
|
+
$use: (path: string, useShadowDOM?: boolean, lazy?: boolean | LazyStrategy) => Promise<void>;
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* Names of all framework helpers (for Function parameter lists)
|
|
29
|
+
*/
|
|
30
|
+
export declare const frameworkHelperNames: string[];
|
|
31
|
+
/**
|
|
32
|
+
* Default helpers for entry point usage (resolve relative to page URL).
|
|
33
|
+
* Inside components, use createFrameworkHelpers(componentUrl) instead.
|
|
34
|
+
*/
|
|
35
|
+
export declare function getFrameworkHelperValues(): ((...args: any[]) => any)[];
|
|
36
|
+
export declare const registerComponent: (name: string, path: string, useShadowDOM?: boolean, lazy?: boolean | LazyStrategy) => Promise<void>;
|
|
37
|
+
export declare const registerComponents: (configs: ComponentConfig[] | Record<string, string | Omit<ComponentConfig, "name">>) => Promise<RegisterComponentsResult>;
|
|
38
|
+
export declare const $use: (path: string, useShadowDOM?: boolean, lazy?: boolean | LazyStrategy) => Promise<void>;
|