ladrillosjs 2.0.0-beta.5.1 → 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.
Files changed (50) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +77 -12
  3. package/dist/core/cache/expressionCache.d.ts +80 -0
  4. package/dist/core/component/bindingParser.d.ts +2 -0
  5. package/dist/core/component/cache.d.ts +22 -0
  6. package/dist/core/component/extract.d.ts +2 -0
  7. package/dist/core/component/loader.d.ts +10 -0
  8. package/dist/core/component/webcomponent.d.ts +29 -0
  9. package/dist/core/configure.d.ts +28 -0
  10. package/dist/core/css/cssParser/cssParser.d.ts +3 -0
  11. package/dist/core/diff/listDiff.d.ts +83 -0
  12. package/dist/core/directives/directiveProcessor.d.ts +58 -0
  13. package/dist/core/events/eventBus.d.ts +136 -0
  14. package/dist/core/helpers/frameworkHelpers.d.ts +38 -0
  15. package/dist/core/html/htmlparser.d.ts +13 -0
  16. package/dist/core/js/moduleExecutor.d.ts +118 -0
  17. package/dist/core/js/reactivity.d.ts +52 -0
  18. package/dist/core/js/scriptParser.d.ts +48 -0
  19. package/dist/core/ladrillos.d.ts +68 -0
  20. package/dist/core/lazy/index.d.ts +6 -0
  21. package/dist/core/lazy/lazyLoader.d.ts +22 -0
  22. package/dist/core/lazy/lazyStrategies.d.ts +73 -0
  23. package/dist/core/reactivity/dependencyTracker.d.ts +120 -0
  24. package/dist/core/scheduler/batchScheduler.d.ts +97 -0
  25. package/dist/core.d.ts +15 -0
  26. package/dist/core.js +2 -0
  27. package/dist/core.js.map +1 -0
  28. package/dist/events.d.ts +20 -0
  29. package/dist/events.js +2 -0
  30. package/dist/events.js.map +1 -0
  31. package/dist/index.d.ts +11 -9
  32. package/dist/index.js +2 -1
  33. package/dist/index.js.map +1 -0
  34. package/dist/lazy.d.ts +17 -0
  35. package/dist/lazy.js +2 -0
  36. package/dist/lazy.js.map +1 -0
  37. package/dist/shared-CqJzci1Q.js +2 -0
  38. package/dist/shared-CqJzci1Q.js.map +1 -0
  39. package/dist/shared-DGGk2qBc.js +2 -0
  40. package/dist/shared-DGGk2qBc.js.map +1 -0
  41. package/dist/shared-DKFppTJL.js +2 -0
  42. package/dist/shared-DKFppTJL.js.map +1 -0
  43. package/dist/types/index.d.ts +171 -0
  44. package/dist/utils/devWarnings.d.ts +133 -0
  45. package/dist/utils/directives.d.ts +149 -0
  46. package/dist/utils/jsevents.d.ts +4 -0
  47. package/dist/utils/keyModifiers.d.ts +106 -0
  48. package/dist/utils/regex.d.ts +5 -0
  49. package/dist/utils/sandbox.d.ts +25 -0
  50. package/package.json +60 -12
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 src="https://cdn.jsdelivr.net/npm/ladrillosjs/dist/ladrillosjs.umd.js"></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
- ladrillosjs.registerComponent("my-counter", "./counter.html");
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
- <!-- Global (UMD) -->
113
- <script src="https://cdn.jsdelivr.net/npm/ladrillosjs/dist/ladrillosjs.umd.js"></script>
117
+ <!-- ES Module (recommended) -->
114
118
  <script type="module">
115
- ladrillosjs.registerComponent("my-component", "./component.html");
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
- <!-- ES Module -->
127
+ <!-- Also available on unpkg -->
119
128
  <script type="module">
120
- import { registerComponent } from "https://cdn.jsdelivr.net/npm/ladrillosjs/dist/ladrillosjs.es.js";
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
@@ -406,11 +432,19 @@ await registerComponents([
406
432
  | `lazyOnMedia` | Mobile/desktop specific components |
407
433
  | `lazyOnDelay` | Chat widgets, notifications |
408
434
 
435
+ ### Eager Override
436
+
437
+ Force a lazy component to load immediately by adding the `eager` attribute:
438
+
439
+ ```html
440
+ <lazy-footer eager></lazy-footer>
441
+ ```
442
+
409
443
  ---
410
444
 
411
445
  ## 📋 API Reference
412
446
 
413
- ### registerComponent
447
+ ### `registerComponent`
414
448
 
415
449
  ```javascript
416
450
  registerComponent(name, path, useShadowDOM?, lazy?)
@@ -434,7 +468,7 @@ registerComponent("my-nav", "./nav.html", false);
434
468
  registerComponent("my-footer", "./footer.html", true, lazyOnVisible());
435
469
  ```
436
470
 
437
- ### registerComponents
471
+ ### `registerComponents`
438
472
 
439
473
  Register multiple components with parallel fetching:
440
474
 
@@ -448,6 +482,37 @@ const result = await registerComponents([
448
482
  // Returns: { success: [...], failed: [...], skipped: [...] }
449
483
  ```
450
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
+
451
516
  ### Event Bus
452
517
 
453
518
  | Function | Description |
@@ -531,7 +596,7 @@ A complete CRUD example combining all directives:
531
596
 
532
597
  function toggleTodo(id) {
533
598
  todos = todos.map((t) =>
534
- t.id === id ? { ...t, completed: !t.completed } : t
599
+ t.id === id ? { ...t, completed: !t.completed } : t,
535
600
  );
536
601
  }
537
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,2 @@
1
+ import { BindingDescriptor } from '../../types';
2
+ export declare function analyzeBinding(raw: string): BindingDescriptor["bindings"][number];
@@ -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,2 @@
1
+ import { LadrillosComponent } from '../../types';
2
+ export declare function parseComponent(source: string, name: string, componentUrl?: string): Promise<LadrillosComponent>;
@@ -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,3 @@
1
+ type StyleTarget = HTMLElement | ShadowRoot;
2
+ export declare const loadStyles: (target: StyleTarget, cssText: string | undefined, useShadowDOM: boolean) => void;
3
+ export {};
@@ -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>;