@jasonshimmy/custom-elements-runtime 0.3.1 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +69 -58
- package/dist/custom-elements-runtime.cjs.js +36 -30
- package/dist/custom-elements-runtime.cjs.js.map +1 -1
- package/dist/custom-elements-runtime.es.js +2337 -1484
- package/dist/custom-elements-runtime.es.js.map +1 -1
- package/dist/custom-elements-runtime.umd.js +36 -30
- package/dist/custom-elements-runtime.umd.js.map +1 -1
- package/dist/index.d.ts +8 -6
- package/dist/runtime/component.d.ts +39 -2
- package/dist/runtime/event-manager.d.ts +58 -0
- package/dist/runtime/helpers.d.ts +19 -0
- package/dist/runtime/hooks.d.ts +113 -0
- package/dist/runtime/props.d.ts +13 -1
- package/dist/runtime/reactive-proxy-cache.d.ts +51 -0
- package/dist/runtime/reactive.d.ts +118 -0
- package/dist/runtime/render.d.ts +2 -2
- package/dist/runtime/secure-expression-evaluator.d.ts +30 -0
- package/dist/runtime/template-compiler.d.ts +4 -0
- package/dist/runtime/types.d.ts +2 -10
- package/dist/runtime/vdom.d.ts +10 -2
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Custom Elements Runtime
|
|
3
3
|
* Lightweight, strongly typed, functional custom element runtime for two-way binding, event, and prop support.
|
|
4
|
-
* Supports:
|
|
4
|
+
* Supports: reactive props, computed, events, style, render, lifecycle hooks, :model and @event attributes.
|
|
5
5
|
* No external dependencies. Mobile-first, secure, and developer friendly.
|
|
6
6
|
*/
|
|
7
|
-
export
|
|
7
|
+
export { component } from "./runtime/component";
|
|
8
|
+
export { useEmit, useOnConnected, useOnDisconnected, useOnAttributeChanged, useOnError, useStyle } from "./runtime/hooks";
|
|
9
|
+
export { ref, computed, watch } from "./runtime/reactive";
|
|
10
|
+
export { html } from "./runtime/template-compiler";
|
|
11
|
+
export { css } from "./runtime/style";
|
|
12
|
+
export { renderToString } from "./runtime/vdom";
|
|
13
|
+
export type { VNode } from "./runtime/types";
|
|
8
14
|
export * from "./directives";
|
|
9
15
|
export * from "./directive-enhancements";
|
|
10
16
|
export * from "./event-bus";
|
|
11
17
|
export * from "./store";
|
|
12
18
|
export * from "./router";
|
|
13
|
-
export { renderToString } from "./runtime/vdom";
|
|
14
|
-
export { component } from "./runtime/component";
|
|
15
|
-
export { css } from "./runtime/style";
|
|
16
|
-
export { html } from "./runtime/template-compiler";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ComponentConfig,
|
|
1
|
+
import type { ComponentConfig, VNode } from "./types";
|
|
2
2
|
/**
|
|
3
3
|
* @internal
|
|
4
4
|
* Runtime registry of component configs.
|
|
@@ -7,7 +7,44 @@ import type { ComponentConfig, ComponentContext } from "./types";
|
|
|
7
7
|
* internal tests only. Consumers should use the public `component` API.
|
|
8
8
|
*/
|
|
9
9
|
export declare const registry: Map<string, ComponentConfig<any, any, any>>;
|
|
10
|
-
export declare function component<S extends object = {}, C extends object = {}, P extends object = {}, T extends object = any>(tag: string, renderOrConfig: ((context: ComponentContext<S, C, P, T>) => any) | ComponentConfig<S, C, P, T>, config?: Partial<ComponentConfig<S, C, P, T>>): void;
|
|
11
10
|
export declare function createElementClass<S extends object, C extends object, P extends object, T extends object = any>(tag: string, config: ComponentConfig<S, C, P, T>): CustomElementConstructor | {
|
|
12
11
|
new (): object;
|
|
13
12
|
};
|
|
13
|
+
/**
|
|
14
|
+
* Streamlined functional component API with automatic reactive props and lifecycle hooks.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```ts
|
|
18
|
+
* // Simple component with no parameters
|
|
19
|
+
* component('simple-header', () => {
|
|
20
|
+
* return html`<h1>Hello World</h1>`;
|
|
21
|
+
* });
|
|
22
|
+
*
|
|
23
|
+
* // With props only
|
|
24
|
+
* component('with-props', ({ message = 'Hello' }) => {
|
|
25
|
+
* return html`<div>${message}</div>`;
|
|
26
|
+
* });
|
|
27
|
+
*
|
|
28
|
+
* // With props and hooks
|
|
29
|
+
* component('my-switch', ({
|
|
30
|
+
* modelValue = false,
|
|
31
|
+
* label = ''
|
|
32
|
+
* }, { emit, onConnected, onDisconnected }) => {
|
|
33
|
+
* onConnected(() => console.log('Switch connected!'));
|
|
34
|
+
* onDisconnected(() => console.log('Switch disconnected!'));
|
|
35
|
+
*
|
|
36
|
+
* return html`
|
|
37
|
+
* <label>
|
|
38
|
+
* ${label}
|
|
39
|
+
* <input
|
|
40
|
+
* type="checkbox"
|
|
41
|
+
* :checked="${modelValue}"
|
|
42
|
+
* @change="${(e) => emit('update:modelValue', e.target.checked)}"
|
|
43
|
+
* />
|
|
44
|
+
* </label>
|
|
45
|
+
* `;
|
|
46
|
+
* });
|
|
47
|
+
* ```
|
|
48
|
+
*/
|
|
49
|
+
export declare function component(tag: string, renderFn: () => VNode | VNode[] | Promise<VNode | VNode[]>): void;
|
|
50
|
+
export declare function component<TProps extends Record<string, any> = {}>(tag: string, renderFn: (props: TProps) => VNode | VNode[] | Promise<VNode | VNode[]>): void;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Event Manager for tracking and cleaning up event listeners
|
|
3
|
+
* Prevents memory leaks by maintaining cleanup functions
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Manages event listeners and their cleanup for elements
|
|
7
|
+
*/
|
|
8
|
+
declare class EventManager {
|
|
9
|
+
private static cleanupFunctions;
|
|
10
|
+
/**
|
|
11
|
+
* Add an event listener with automatic cleanup tracking
|
|
12
|
+
*/
|
|
13
|
+
static addListener(element: HTMLElement, event: string, handler: EventListener, options?: AddEventListenerOptions): void;
|
|
14
|
+
/**
|
|
15
|
+
* Remove a specific event listener
|
|
16
|
+
*/
|
|
17
|
+
static removeListener(element: HTMLElement, event: string, handler: EventListener, options?: EventListenerOptions): void;
|
|
18
|
+
/**
|
|
19
|
+
* Clean up all event listeners for an element
|
|
20
|
+
*/
|
|
21
|
+
static cleanup(element: HTMLElement): void;
|
|
22
|
+
/**
|
|
23
|
+
* Clean up all tracked event listeners (useful for testing)
|
|
24
|
+
*/
|
|
25
|
+
static cleanupAll(): void;
|
|
26
|
+
/**
|
|
27
|
+
* Check if an element has any tracked event listeners
|
|
28
|
+
*/
|
|
29
|
+
static hasListeners(element: HTMLElement): boolean;
|
|
30
|
+
/**
|
|
31
|
+
* Get the number of tracked event listeners for an element
|
|
32
|
+
*/
|
|
33
|
+
static getListenerCount(element: HTMLElement): number;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Enhanced event listener tracker that stores more metadata
|
|
37
|
+
* for better debugging and cleanup
|
|
38
|
+
*/
|
|
39
|
+
interface EventListenerMetadata {
|
|
40
|
+
event: string;
|
|
41
|
+
handler: EventListener;
|
|
42
|
+
options?: AddEventListenerOptions;
|
|
43
|
+
cleanup: () => void;
|
|
44
|
+
addedAt: number;
|
|
45
|
+
}
|
|
46
|
+
declare class DetailedEventManager {
|
|
47
|
+
private static listeners;
|
|
48
|
+
static addListener(element: HTMLElement, event: string, handler: EventListener, options?: AddEventListenerOptions): void;
|
|
49
|
+
static removeListener(element: HTMLElement, event: string, handler: EventListener, options?: EventListenerOptions): boolean;
|
|
50
|
+
static cleanup(element: HTMLElement): void;
|
|
51
|
+
static getListenerInfo(element: HTMLElement): EventListenerMetadata[];
|
|
52
|
+
static findStaleListeners(_maxAge?: number): Array<{
|
|
53
|
+
element: HTMLElement;
|
|
54
|
+
listeners: EventListenerMetadata[];
|
|
55
|
+
}>;
|
|
56
|
+
}
|
|
57
|
+
export { EventManager, DetailedEventManager };
|
|
58
|
+
export type { EventListenerMetadata };
|
|
@@ -1,4 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Convert camelCase to kebab-case with caching
|
|
3
|
+
*/
|
|
1
4
|
export declare function toKebab(str: string): string;
|
|
5
|
+
/**
|
|
6
|
+
* Convert kebab-case to camelCase with caching
|
|
7
|
+
*/
|
|
8
|
+
export declare function toCamel(str: string): string;
|
|
9
|
+
/**
|
|
10
|
+
* Clear string transformation caches (useful for testing)
|
|
11
|
+
*/
|
|
12
|
+
export declare function clearStringCaches(): void;
|
|
13
|
+
/**
|
|
14
|
+
* Get cache statistics for debugging
|
|
15
|
+
*/
|
|
16
|
+
export declare function getStringCacheStats(): {
|
|
17
|
+
kebabCacheSize: number;
|
|
18
|
+
camelCacheSize: number;
|
|
19
|
+
htmlEscapeCacheSize: number;
|
|
20
|
+
};
|
|
2
21
|
export declare function escapeHTML(str: string | number | boolean): string | number | boolean;
|
|
3
22
|
/**
|
|
4
23
|
* Get nested property value from object using dot notation
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Context-based hooks for functional components
|
|
3
|
+
* Provides React-like hooks with perfect TypeScript inference
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Set the current component context (called internally during render)
|
|
7
|
+
* @internal
|
|
8
|
+
*/
|
|
9
|
+
export declare function setCurrentComponentContext(context: any): void;
|
|
10
|
+
/**
|
|
11
|
+
* Clear the current component context (called internally after render)
|
|
12
|
+
* @internal
|
|
13
|
+
*/
|
|
14
|
+
export declare function clearCurrentComponentContext(): void;
|
|
15
|
+
/**
|
|
16
|
+
* Get the emit function for the current component
|
|
17
|
+
* Must be called during component render
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* ```ts
|
|
21
|
+
* component('my-button', ({ label = 'Click me' }) => {
|
|
22
|
+
* const emit = useEmit();
|
|
23
|
+
*
|
|
24
|
+
* return html`
|
|
25
|
+
* <button @click="${() => emit('button-click', { label })}">
|
|
26
|
+
* ${label}
|
|
27
|
+
* </button>
|
|
28
|
+
* `;
|
|
29
|
+
* });
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
export declare function useEmit(): (eventName: string, detail?: any) => boolean;
|
|
33
|
+
/**
|
|
34
|
+
* Register a callback to be called when component is connected to DOM
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* ```ts
|
|
38
|
+
* component('my-component', () => {
|
|
39
|
+
* useOnConnected(() => {
|
|
40
|
+
* console.log('Component mounted!');
|
|
41
|
+
* });
|
|
42
|
+
*
|
|
43
|
+
* return html`<div>Hello World</div>`;
|
|
44
|
+
* });
|
|
45
|
+
* ```
|
|
46
|
+
*/
|
|
47
|
+
export declare function useOnConnected(callback: () => void): void;
|
|
48
|
+
/**
|
|
49
|
+
* Register a callback to be called when component is disconnected from DOM
|
|
50
|
+
*
|
|
51
|
+
* @example
|
|
52
|
+
* ```ts
|
|
53
|
+
* component('my-component', () => {
|
|
54
|
+
* useOnDisconnected(() => {
|
|
55
|
+
* console.log('Component unmounted!');
|
|
56
|
+
* });
|
|
57
|
+
*
|
|
58
|
+
* return html`<div>Goodbye World</div>`;
|
|
59
|
+
* });
|
|
60
|
+
* ```
|
|
61
|
+
*/
|
|
62
|
+
export declare function useOnDisconnected(callback: () => void): void;
|
|
63
|
+
/**
|
|
64
|
+
* Register a callback to be called when an attribute changes
|
|
65
|
+
*
|
|
66
|
+
* @example
|
|
67
|
+
* ```ts
|
|
68
|
+
* component('my-component', () => {
|
|
69
|
+
* useOnAttributeChanged((name, oldValue, newValue) => {
|
|
70
|
+
* console.log(`Attribute ${name} changed from ${oldValue} to ${newValue}`);
|
|
71
|
+
* });
|
|
72
|
+
*
|
|
73
|
+
* return html`<div>Attribute watcher</div>`;
|
|
74
|
+
* });
|
|
75
|
+
* ```
|
|
76
|
+
*/
|
|
77
|
+
export declare function useOnAttributeChanged(callback: (name: string, oldValue: string | null, newValue: string | null) => void): void;
|
|
78
|
+
/**
|
|
79
|
+
* Register a callback to be called when an error occurs
|
|
80
|
+
*
|
|
81
|
+
* @example
|
|
82
|
+
* ```ts
|
|
83
|
+
* component('my-component', () => {
|
|
84
|
+
* useOnError((error) => {
|
|
85
|
+
* console.error('Component error:', error);
|
|
86
|
+
* });
|
|
87
|
+
*
|
|
88
|
+
* return html`<div>Error handler</div>`;
|
|
89
|
+
* });
|
|
90
|
+
* ```
|
|
91
|
+
*/
|
|
92
|
+
export declare function useOnError(callback: (error: Error) => void): void;
|
|
93
|
+
/**
|
|
94
|
+
* Register a style function that will be called during each render
|
|
95
|
+
* to provide reactive styles for the component
|
|
96
|
+
*
|
|
97
|
+
* @example
|
|
98
|
+
* ```ts
|
|
99
|
+
* import { css } from '@lib/style';
|
|
100
|
+
*
|
|
101
|
+
* component('my-component', ({ theme = 'light' }) => {
|
|
102
|
+
* useStyle(() => css`
|
|
103
|
+
* :host {
|
|
104
|
+
* background: ${theme === 'light' ? 'white' : 'black'};
|
|
105
|
+
* color: ${theme === 'light' ? 'black' : 'white'};
|
|
106
|
+
* }
|
|
107
|
+
* `);
|
|
108
|
+
*
|
|
109
|
+
* return html`<div>Styled component</div>`;
|
|
110
|
+
* });
|
|
111
|
+
* ```
|
|
112
|
+
*/
|
|
113
|
+
export declare function useStyle(callback: () => string): void;
|
package/dist/runtime/props.d.ts
CHANGED
|
@@ -1,6 +1,18 @@
|
|
|
1
1
|
import type { ComponentConfig, ComponentContext } from "./types";
|
|
2
|
+
export type PropDefinition = {
|
|
3
|
+
type: StringConstructor | NumberConstructor | BooleanConstructor | FunctionConstructor;
|
|
4
|
+
default?: string | number | boolean;
|
|
5
|
+
};
|
|
2
6
|
/**
|
|
3
|
-
* Applies props to the component context.
|
|
7
|
+
* Applies props to the component context using a direct prop definitions object.
|
|
8
|
+
* @param element - The custom element instance.
|
|
9
|
+
* @param propDefinitions - Object mapping prop names to their definitions.
|
|
10
|
+
* @param context - The component context.
|
|
11
|
+
*/
|
|
12
|
+
export declare function applyPropsFromDefinitions(element: HTMLElement, propDefinitions: Record<string, PropDefinition>, context: any): void;
|
|
13
|
+
/**
|
|
14
|
+
* Legacy function for ComponentConfig compatibility.
|
|
15
|
+
* Applies props to the component context using a ComponentConfig.
|
|
4
16
|
* @param element - The custom element instance.
|
|
5
17
|
* @param cfg - The component config.
|
|
6
18
|
* @param context - The component context.
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reactive proxy cache to optimize proxy creation and reuse
|
|
3
|
+
* Uses WeakMap for automatic garbage collection when objects are no longer referenced
|
|
4
|
+
*/
|
|
5
|
+
declare class ReactiveProxyCache {
|
|
6
|
+
private static cache;
|
|
7
|
+
private static arrayHandlerCache;
|
|
8
|
+
private static objectHandlerCache;
|
|
9
|
+
/**
|
|
10
|
+
* Get or create a reactive proxy for an object
|
|
11
|
+
*/
|
|
12
|
+
static getOrCreateProxy<T extends object>(obj: T, reactiveState: any, isArray?: boolean): T;
|
|
13
|
+
/**
|
|
14
|
+
* Get or create a cached array handler
|
|
15
|
+
*/
|
|
16
|
+
private static getOrCreateArrayHandler;
|
|
17
|
+
/**
|
|
18
|
+
* Get or create a cached object handler
|
|
19
|
+
*/
|
|
20
|
+
private static getOrCreateObjectHandler;
|
|
21
|
+
/**
|
|
22
|
+
* Check if an object already has a cached proxy
|
|
23
|
+
*/
|
|
24
|
+
static hasProxy(obj: object): boolean;
|
|
25
|
+
/**
|
|
26
|
+
* Clear all cached proxies (useful for testing)
|
|
27
|
+
*/
|
|
28
|
+
static clear(): void;
|
|
29
|
+
/**
|
|
30
|
+
* Get cache statistics (for debugging)
|
|
31
|
+
* Note: WeakMap doesn't provide size, so this is limited
|
|
32
|
+
*/
|
|
33
|
+
static getStats(): {
|
|
34
|
+
hasCachedProxies: boolean;
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Optimized proxy creation utilities
|
|
39
|
+
*/
|
|
40
|
+
declare class ProxyOptimizer {
|
|
41
|
+
private static contextCache;
|
|
42
|
+
/**
|
|
43
|
+
* Create an optimized reactive proxy with minimal overhead
|
|
44
|
+
*/
|
|
45
|
+
static createReactiveProxy<T extends object>(obj: T, onUpdate: () => void, makeReactive: (value: any) => any): T;
|
|
46
|
+
/**
|
|
47
|
+
* Mark an object as a proxy (for optimization)
|
|
48
|
+
*/
|
|
49
|
+
static markAsProxy(obj: any): void;
|
|
50
|
+
}
|
|
51
|
+
export { ReactiveProxyCache, ProxyOptimizer };
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Global reactive system for tracking dependencies and triggering updates
|
|
3
|
+
*/
|
|
4
|
+
declare class ReactiveSystem {
|
|
5
|
+
private currentComponent;
|
|
6
|
+
private componentDependencies;
|
|
7
|
+
private componentRenderFunctions;
|
|
8
|
+
private stateStorage;
|
|
9
|
+
private stateIndexCounter;
|
|
10
|
+
private trackingDisabled;
|
|
11
|
+
private lastWarningTime;
|
|
12
|
+
/**
|
|
13
|
+
* Set the current component being rendered for dependency tracking
|
|
14
|
+
*/
|
|
15
|
+
setCurrentComponent(componentId: string, renderFn: () => void): void;
|
|
16
|
+
/**
|
|
17
|
+
* Clear the current component after rendering
|
|
18
|
+
*/
|
|
19
|
+
clearCurrentComponent(): void;
|
|
20
|
+
/**
|
|
21
|
+
* Temporarily disable dependency tracking
|
|
22
|
+
*/
|
|
23
|
+
disableTracking(): void;
|
|
24
|
+
/**
|
|
25
|
+
* Re-enable dependency tracking
|
|
26
|
+
*/
|
|
27
|
+
enableTracking(): void;
|
|
28
|
+
/**
|
|
29
|
+
* Check if a component is currently rendering
|
|
30
|
+
*/
|
|
31
|
+
isRenderingComponent(): boolean;
|
|
32
|
+
/**
|
|
33
|
+
* Return whether we should emit a render-time warning for the current component.
|
|
34
|
+
* This throttles warnings to avoid spamming the console for legitimate rapid updates.
|
|
35
|
+
*/
|
|
36
|
+
shouldEmitRenderWarning(): boolean;
|
|
37
|
+
/**
|
|
38
|
+
* Execute a function with tracking disabled
|
|
39
|
+
*/
|
|
40
|
+
withoutTracking<T>(fn: () => T): T;
|
|
41
|
+
/**
|
|
42
|
+
* Get or create a state instance for the current component
|
|
43
|
+
*/
|
|
44
|
+
getOrCreateState<T>(initialValue: T): ReactiveState<T>;
|
|
45
|
+
/**
|
|
46
|
+
* Track a dependency for the current component
|
|
47
|
+
*/
|
|
48
|
+
trackDependency(state: ReactiveState<any>): void;
|
|
49
|
+
/**
|
|
50
|
+
* Trigger updates for all components that depend on a state
|
|
51
|
+
*/
|
|
52
|
+
triggerUpdate(state: ReactiveState<any>): void;
|
|
53
|
+
/**
|
|
54
|
+
* Clean up component dependencies when component is destroyed
|
|
55
|
+
*/
|
|
56
|
+
cleanup(componentId: string): void;
|
|
57
|
+
}
|
|
58
|
+
declare const reactiveSystem: ReactiveSystem;
|
|
59
|
+
export { reactiveSystem };
|
|
60
|
+
/**
|
|
61
|
+
* Internal reactive state class
|
|
62
|
+
*/
|
|
63
|
+
export declare class ReactiveState<T> {
|
|
64
|
+
private _value;
|
|
65
|
+
private dependents;
|
|
66
|
+
constructor(initialValue: T);
|
|
67
|
+
get value(): T;
|
|
68
|
+
set value(newValue: T);
|
|
69
|
+
addDependent(componentId: string): void;
|
|
70
|
+
removeDependent(componentId: string): void;
|
|
71
|
+
getDependents(): Set<string>;
|
|
72
|
+
private makeReactive;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Create reactive state that automatically triggers component re-renders
|
|
76
|
+
* when accessed during render and modified afterwards.
|
|
77
|
+
* Defaults to null if no initial value is provided (Vue-style ref).
|
|
78
|
+
*
|
|
79
|
+
* @example
|
|
80
|
+
* ```ts
|
|
81
|
+
* const counter = ref(0);
|
|
82
|
+
* const user = ref({ name: 'John', age: 30 });
|
|
83
|
+
* const emptyRef = ref(); // defaults to null
|
|
84
|
+
*
|
|
85
|
+
* // Usage in component
|
|
86
|
+
* counter.value++; // triggers re-render
|
|
87
|
+
* user.value.name = 'Jane'; // triggers re-render
|
|
88
|
+
* console.log(emptyRef.value); // null
|
|
89
|
+
* ```
|
|
90
|
+
*/
|
|
91
|
+
export declare function ref<T = null>(initialValue?: T): ReactiveState<T extends undefined ? null : T>;
|
|
92
|
+
/**
|
|
93
|
+
* Create computed state that derives from other reactive state
|
|
94
|
+
*
|
|
95
|
+
* @example
|
|
96
|
+
* ```ts
|
|
97
|
+
* const firstName = ref('John');
|
|
98
|
+
* const lastName = ref('Doe');
|
|
99
|
+
* const fullName = computed(() => `${firstName.value} ${lastName.value}`);
|
|
100
|
+
* ```
|
|
101
|
+
*/
|
|
102
|
+
export declare function computed<T>(fn: () => T): {
|
|
103
|
+
readonly value: T;
|
|
104
|
+
};
|
|
105
|
+
/**
|
|
106
|
+
* Create a watcher that runs when dependencies change
|
|
107
|
+
*
|
|
108
|
+
* @example
|
|
109
|
+
* ```ts
|
|
110
|
+
* const count = ref(0);
|
|
111
|
+
* watch(() => count.value, (newVal, oldVal) => {
|
|
112
|
+
* console.log(`Count changed from ${oldVal} to ${newVal}`);
|
|
113
|
+
* });
|
|
114
|
+
* ```
|
|
115
|
+
*/
|
|
116
|
+
export declare function watch<T>(source: () => T, callback: (newValue: T, oldValue: T) => void, options?: {
|
|
117
|
+
immediate?: boolean;
|
|
118
|
+
}): () => void;
|
package/dist/runtime/render.d.ts
CHANGED
|
@@ -9,10 +9,10 @@ export declare function renderComponent<S extends object, C extends object, P ex
|
|
|
9
9
|
*/
|
|
10
10
|
export declare function renderOutput<S extends object, C extends object, P extends object, T extends object>(shadowRoot: ShadowRoot | null, output: VNode | VNode[], context: ComponentContext<S, C, P, T>, refs: Refs["refs"], setHtmlString: (html: string) => void): void;
|
|
11
11
|
/**
|
|
12
|
-
* Debounced render request.
|
|
12
|
+
* Debounced render request with infinite loop protection.
|
|
13
13
|
*/
|
|
14
14
|
export declare function requestRender(renderFn: () => void, lastRenderTime: number, renderCount: number, setLastRenderTime: (t: number) => void, setRenderCount: (c: number) => void, renderTimeoutId: ReturnType<typeof setTimeout> | null, setRenderTimeoutId: (id: ReturnType<typeof setTimeout> | null) => void): void;
|
|
15
15
|
/**
|
|
16
16
|
* Applies styles to the shadowRoot.
|
|
17
17
|
*/
|
|
18
|
-
export declare function applyStyle<S extends object, C extends object, P extends object, T extends object>(shadowRoot: ShadowRoot | null,
|
|
18
|
+
export declare function applyStyle<S extends object, C extends object, P extends object, T extends object>(shadowRoot: ShadowRoot | null, context: ComponentContext<S, C, P, T>, htmlString: string, styleSheet: CSSStyleSheet | null, setStyleSheet: (sheet: CSSStyleSheet | null) => void): void;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Secure expression evaluator to replace unsafe Function() constructor
|
|
3
|
+
* Provides AST-based validation and caching for performance
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Secure expression evaluator with caching and AST validation
|
|
7
|
+
*/
|
|
8
|
+
declare class SecureExpressionEvaluator {
|
|
9
|
+
private static cache;
|
|
10
|
+
private static maxCacheSize;
|
|
11
|
+
private static dangerousPatterns;
|
|
12
|
+
static evaluate(expression: string, context: any): any;
|
|
13
|
+
private static createEvaluator;
|
|
14
|
+
private static hasDangerousPatterns;
|
|
15
|
+
private static createSafeEvaluator;
|
|
16
|
+
private static createObjectEvaluator;
|
|
17
|
+
private static parseObjectProperties;
|
|
18
|
+
private static createSimpleEvaluator;
|
|
19
|
+
/**
|
|
20
|
+
* Evaluate a very small, safe expression grammar without using eval/Function.
|
|
21
|
+
* Supports: numbers, string literals, true/false, null, arrays, unary !,
|
|
22
|
+
* arithmetic (+ - * / %), comparisons, logical && and ||, parentheses, and ternary `a ? b : c`.
|
|
23
|
+
*/
|
|
24
|
+
private static evaluateBasicExpression;
|
|
25
|
+
private static tokenize;
|
|
26
|
+
private static evaluateSimpleValue;
|
|
27
|
+
static clearCache(): void;
|
|
28
|
+
static getCacheSize(): number;
|
|
29
|
+
}
|
|
30
|
+
export { SecureExpressionEvaluator };
|
|
@@ -23,6 +23,10 @@ export declare function parseProps(str: string, values?: unknown[], context?: Re
|
|
|
23
23
|
* - Do not rewrap interpolated VNodes (preserve their keys); only fill in missing keys.
|
|
24
24
|
*/
|
|
25
25
|
export declare function htmlImpl(strings: TemplateStringsArray, values: unknown[], context?: Record<string, any>): VNode | VNode[];
|
|
26
|
+
/**
|
|
27
|
+
* Clear the template compile cache (useful for tests)
|
|
28
|
+
*/
|
|
29
|
+
export declare function clearTemplateCompileCache(): void;
|
|
26
30
|
/**
|
|
27
31
|
* Default export: plain html.
|
|
28
32
|
*/
|
package/dist/runtime/types.d.ts
CHANGED
|
@@ -14,6 +14,7 @@ export interface VNode {
|
|
|
14
14
|
arg?: string;
|
|
15
15
|
}>;
|
|
16
16
|
ref?: string;
|
|
17
|
+
reactiveRef?: any;
|
|
17
18
|
/** Compiler-provided hint: whether this VNode represents a custom element (contains a dash) */
|
|
18
19
|
isCustomElement?: boolean;
|
|
19
20
|
};
|
|
@@ -30,7 +31,7 @@ export interface AnchorBlockVNode extends VNode {
|
|
|
30
31
|
/**
|
|
31
32
|
* Runtime types
|
|
32
33
|
*/
|
|
33
|
-
export type LifecycleKeys = "onConnected" | "onDisconnected" | "onAttributeChanged" | "onError"
|
|
34
|
+
export type LifecycleKeys = "onConnected" | "onDisconnected" | "onAttributeChanged" | "onError";
|
|
34
35
|
export interface WatchOptions {
|
|
35
36
|
immediate?: boolean;
|
|
36
37
|
deep?: boolean;
|
|
@@ -64,24 +65,15 @@ export type ComponentContext<S extends object, C extends object, P extends objec
|
|
|
64
65
|
emit: <D = any>(eventName: string, detail?: D, options?: CustomEventInit) => boolean;
|
|
65
66
|
};
|
|
66
67
|
export type ComponentConfig<S extends object, C extends object = {}, P extends object = {}, T extends object = {}> = {
|
|
67
|
-
state?: S;
|
|
68
|
-
computed?: {
|
|
69
|
-
[K in keyof C]: (context: ComponentContext<S, C, P, T>) => C[K];
|
|
70
|
-
};
|
|
71
68
|
props?: Record<string, {
|
|
72
69
|
type: StringConstructor | NumberConstructor | BooleanConstructor | FunctionConstructor;
|
|
73
70
|
default?: string | number | boolean;
|
|
74
71
|
}>;
|
|
75
|
-
watch?: WatchConfig<ComponentContext<S, C, P, T>>;
|
|
76
|
-
style?: string | ((context: ComponentContext<S, C, P, T>) => string);
|
|
77
72
|
render: (context: ComponentContext<S, C, P, T>) => VNode | VNode[] | Promise<VNode | VNode[]>;
|
|
78
|
-
loadingTemplate?: (context: ComponentContext<S, C, P, T>) => VNode | VNode[];
|
|
79
|
-
errorTemplate?: (error: Error, context: ComponentContext<S, C, P, T>) => VNode | VNode[];
|
|
80
73
|
onConnected?: (context: ComponentContext<S, C, P, T>) => void;
|
|
81
74
|
onDisconnected?: (context: ComponentContext<S, C, P, T>) => void;
|
|
82
75
|
onAttributeChanged?: (name: string, oldValue: string | null, newValue: string | null, context: ComponentContext<S, C, P, T>) => void;
|
|
83
76
|
onError?: (error: Error | null, context: ComponentContext<S, C, P, T>) => void;
|
|
84
|
-
errorFallback?: (error: Error | null, context: ComponentContext<S, C, P, T>) => string;
|
|
85
77
|
} & {
|
|
86
78
|
[K in keyof T as K extends LifecycleKeys ? never : K]: T[K] extends Function ? T[K] : never;
|
|
87
79
|
};
|
package/dist/runtime/vdom.d.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import type { VNode, VDomRefs } from "./types";
|
|
7
7
|
/**
|
|
8
|
-
* Recursively clean up refs for all descendants of a node
|
|
8
|
+
* Recursively clean up refs and event listeners for all descendants of a node
|
|
9
9
|
* @param node The node to clean up.
|
|
10
10
|
* @param refs The refs to clean up.
|
|
11
11
|
* @returns
|
|
@@ -22,7 +22,7 @@ export declare function cleanupRefs(node: Node, refs?: VDomRefs): void;
|
|
|
22
22
|
* @param el
|
|
23
23
|
* @returns
|
|
24
24
|
*/
|
|
25
|
-
export declare function processModelDirective(value: string, modifiers: string[], props: Record<string, any>, attrs: Record<string, any>, listeners: Record<string, EventListener>, context?: any, el?: HTMLElement, arg?: string): void;
|
|
25
|
+
export declare function processModelDirective(value: string | any, modifiers: string[], props: Record<string, any>, attrs: Record<string, any>, listeners: Record<string, EventListener>, context?: any, el?: HTMLElement, arg?: string): void;
|
|
26
26
|
/**
|
|
27
27
|
* Process :bind directive for attribute/property binding
|
|
28
28
|
* @param value
|
|
@@ -49,6 +49,14 @@ export declare function processClassDirective(value: any, attrs: Record<string,
|
|
|
49
49
|
* @returns
|
|
50
50
|
*/
|
|
51
51
|
export declare function processStyleDirective(value: any, attrs: Record<string, any>, context?: any): void;
|
|
52
|
+
/**
|
|
53
|
+
* Process :ref directive for element references
|
|
54
|
+
* @param value
|
|
55
|
+
* @param props
|
|
56
|
+
* @param context
|
|
57
|
+
* @returns
|
|
58
|
+
*/
|
|
59
|
+
export declare function processRefDirective(value: any, props: Record<string, any>, context?: any): void;
|
|
52
60
|
/**
|
|
53
61
|
* Process directives and return merged props, attrs, and event listeners
|
|
54
62
|
* @param directives
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jasonshimmy/custom-elements-runtime",
|
|
3
3
|
"description": "A powerful, modern, and lightweight runtime for creating reactive web components with TypeScript",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "1.0.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"web-components",
|