@hawsen-the-first/interactiv 0.0.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/README.md +326 -0
- package/dist/animations.css +160 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +26 -0
- package/dist/src/animationBus.d.ts +30 -0
- package/dist/src/animationBus.d.ts.map +1 -0
- package/dist/src/animationBus.js +125 -0
- package/dist/src/appBuilder.d.ts +173 -0
- package/dist/src/appBuilder.d.ts.map +1 -0
- package/dist/src/appBuilder.js +957 -0
- package/dist/src/eventBus.d.ts +100 -0
- package/dist/src/eventBus.d.ts.map +1 -0
- package/dist/src/eventBus.js +326 -0
- package/dist/src/eventManager.d.ts +87 -0
- package/dist/src/eventManager.d.ts.map +1 -0
- package/dist/src/eventManager.js +455 -0
- package/dist/src/garbageCollector.d.ts +68 -0
- package/dist/src/garbageCollector.d.ts.map +1 -0
- package/dist/src/garbageCollector.js +169 -0
- package/dist/src/logger.d.ts +11 -0
- package/dist/src/logger.d.ts.map +1 -0
- package/dist/src/logger.js +15 -0
- package/dist/src/navigationManager.d.ts +105 -0
- package/dist/src/navigationManager.d.ts.map +1 -0
- package/dist/src/navigationManager.js +533 -0
- package/dist/src/screensaverManager.d.ts +66 -0
- package/dist/src/screensaverManager.d.ts.map +1 -0
- package/dist/src/screensaverManager.js +417 -0
- package/dist/src/settingsManager.d.ts +48 -0
- package/dist/src/settingsManager.d.ts.map +1 -0
- package/dist/src/settingsManager.js +317 -0
- package/dist/src/stateManager.d.ts +58 -0
- package/dist/src/stateManager.d.ts.map +1 -0
- package/dist/src/stateManager.js +278 -0
- package/dist/src/types.d.ts +32 -0
- package/dist/src/types.d.ts.map +1 -0
- package/dist/src/types.js +1 -0
- package/dist/utils/generateGuid.d.ts +2 -0
- package/dist/utils/generateGuid.d.ts.map +1 -0
- package/dist/utils/generateGuid.js +19 -0
- package/dist/utils/logger.d.ts +9 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +42 -0
- package/dist/utils/template-helpers.d.ts +32 -0
- package/dist/utils/template-helpers.d.ts.map +1 -0
- package/dist/utils/template-helpers.js +24 -0
- package/package.json +59 -0
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
export declare class EventBus<DetailType = any> {
|
|
2
|
+
private eventTarget;
|
|
3
|
+
private activeListeners;
|
|
4
|
+
private id;
|
|
5
|
+
constructor(description?: string);
|
|
6
|
+
on(type: string, listener: (event: CustomEvent<DetailType>) => void): void;
|
|
7
|
+
once(type: string, listener: (event: CustomEvent<DetailType>) => void): void;
|
|
8
|
+
remove(type: string): void;
|
|
9
|
+
/**
|
|
10
|
+
* Remove all listeners for this event bus
|
|
11
|
+
*/
|
|
12
|
+
removeAll(): void;
|
|
13
|
+
/**
|
|
14
|
+
* Get the count of active listeners
|
|
15
|
+
*/
|
|
16
|
+
getListenerCount(): number;
|
|
17
|
+
/**
|
|
18
|
+
* Destroy this event bus and clean up all listeners
|
|
19
|
+
*/
|
|
20
|
+
destroy(): void;
|
|
21
|
+
emit(type: string, detail?: DetailType): boolean | undefined;
|
|
22
|
+
private validateEventDispatch;
|
|
23
|
+
}
|
|
24
|
+
export declare class EventOrchestrator {
|
|
25
|
+
private eventBuses;
|
|
26
|
+
private eventQueue;
|
|
27
|
+
private abortCommand;
|
|
28
|
+
private globalStateStore;
|
|
29
|
+
private stateEventBus;
|
|
30
|
+
constructor();
|
|
31
|
+
run(): void;
|
|
32
|
+
registerEventBus<T>(name: string): EventBus<T>;
|
|
33
|
+
getEventBus(name: string): EventBus | null;
|
|
34
|
+
enqueue(event: string, forBus: string, priority?: string, params?: unknown, scheduleFor?: number, expiry?: number): string;
|
|
35
|
+
getQueuedEventById(id: string): ApplicationEventQueueItem;
|
|
36
|
+
private removeQueuedNavigationEvents;
|
|
37
|
+
rescheduleQueuedEvent(id: string, newSchedule: number): void;
|
|
38
|
+
destroy(): void;
|
|
39
|
+
useGlobalState(initalValue: any): any[];
|
|
40
|
+
private processNextQueueItem;
|
|
41
|
+
private getPrioritisedEventFromQueue;
|
|
42
|
+
/**
|
|
43
|
+
* Clean up expired events from the queue
|
|
44
|
+
* This is a safety net for expired events that weren't processed
|
|
45
|
+
*/
|
|
46
|
+
cleanupExpiredEvents(): number;
|
|
47
|
+
/**
|
|
48
|
+
* Get the current size of the event queue
|
|
49
|
+
*/
|
|
50
|
+
getQueueSize(): number;
|
|
51
|
+
/**
|
|
52
|
+
* Get the count of registered event buses
|
|
53
|
+
*/
|
|
54
|
+
getEventBusCount(): number;
|
|
55
|
+
/**
|
|
56
|
+
* Get total listener count across all event buses
|
|
57
|
+
*/
|
|
58
|
+
getTotalListenerCount(): number;
|
|
59
|
+
/**
|
|
60
|
+
* Navigate to a page with optional transition configuration
|
|
61
|
+
*
|
|
62
|
+
* @param pageId - The ID of the page to navigate to
|
|
63
|
+
* @param config - Optional transition configuration
|
|
64
|
+
* @param priority - Event priority: "immediate", "normal", or "low" (default: "immediate")
|
|
65
|
+
*/
|
|
66
|
+
navigateToPage(pageId: string, config?: {
|
|
67
|
+
type: "slide" | "fade" | "scale" | "flip" | "snap" | "custom";
|
|
68
|
+
direction?: "left" | "right" | "up" | "down";
|
|
69
|
+
duration?: number;
|
|
70
|
+
easing?: string;
|
|
71
|
+
customCSS?: string;
|
|
72
|
+
}, priority?: string): void;
|
|
73
|
+
/**
|
|
74
|
+
* Navigate to a view with optional transition configuration
|
|
75
|
+
*
|
|
76
|
+
* @param viewId - The ID of the view to navigate to
|
|
77
|
+
* @param config - Optional transition configuration
|
|
78
|
+
* @param priority - Event priority: "immediate", "normal", or "low" (default: "immediate")
|
|
79
|
+
*/
|
|
80
|
+
navigateToView(viewId: string, config?: {
|
|
81
|
+
type: "slide" | "fade" | "scale" | "flip" | "snap" | "custom";
|
|
82
|
+
direction?: "left" | "right" | "up" | "down";
|
|
83
|
+
duration?: number;
|
|
84
|
+
easing?: string;
|
|
85
|
+
customCSS?: string;
|
|
86
|
+
}, priority?: string): void;
|
|
87
|
+
}
|
|
88
|
+
declare class ApplicationEventQueueItem {
|
|
89
|
+
instanceIdentifier: string;
|
|
90
|
+
eventBusId: string;
|
|
91
|
+
eventId: string;
|
|
92
|
+
priority: string;
|
|
93
|
+
scheduleFor: number;
|
|
94
|
+
expiry?: number;
|
|
95
|
+
params?: unknown;
|
|
96
|
+
constructor(eventBusId: string, eventId: string, priority?: string, scheduleFor?: number, expiry?: number, params?: unknown);
|
|
97
|
+
}
|
|
98
|
+
export declare function createOrchestrator(): EventOrchestrator;
|
|
99
|
+
export {};
|
|
100
|
+
//# sourceMappingURL=eventBus.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"eventBus.d.ts","sourceRoot":"","sources":["../../src/eventBus.ts"],"names":[],"mappings":"AAMA,qBAAa,QAAQ,CAAC,UAAU,GAAG,GAAG;IACpC,OAAO,CAAC,WAAW,CAAc;IACjC,OAAO,CAAC,eAAe,CAA6B;IACpD,OAAO,CAAC,EAAE,CAAS;gBACP,WAAW,SAAc;IAIrC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,KAAK,EAAE,WAAW,CAAC,UAAU,CAAC,KAAK,IAAI;IAiBnE,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,KAAK,EAAE,WAAW,CAAC,UAAU,CAAC,KAAK,IAAI;IAiBrE,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAmB1B;;OAEG;IACH,SAAS,IAAI,IAAI;IAQjB;;OAEG;IACH,gBAAgB,IAAI,MAAM;IAI1B;;OAEG;IACH,OAAO,IAAI,IAAI;IASf,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,UAAU;IAgBtC,OAAO,CAAC,qBAAqB;CAO9B;AAED,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,UAAU,CAAwB;IAC1C,OAAO,CAAC,UAAU,CAAmC;IACrD,OAAO,CAAC,YAAY,CAAkB;IACtC,OAAO,CAAC,gBAAgB,CAAQ;IAChC,OAAO,CAAC,aAAa,CAAW;;IAUhC,GAAG;IAqBH,gBAAgB,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,QAAQ,CAAC,CAAC,CAAC;IAM9C,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI;IAI1C,OAAO,CACL,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EACd,QAAQ,GAAE,MAAkB,EAC5B,MAAM,CAAC,EAAE,OAAO,EAChB,WAAW,CAAC,EAAE,MAAM,EACpB,MAAM,CAAC,EAAE,MAAM;IAWjB,kBAAkB,CAAC,EAAE,EAAE,MAAM,GAAG,yBAAyB;IAIzD,OAAO,CAAC,4BAA4B;IAKpC,qBAAqB,CAAC,EAAE,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,IAAI;IAG5D,OAAO;IAIP,cAAc,CAAC,WAAW,EAAE,GAAG;IAY/B,OAAO,CAAC,oBAAoB;IAU5B,OAAO,CAAC,4BAA4B;IAwDpC;;;OAGG;IACI,oBAAoB,IAAI,MAAM;IAmBrC;;OAEG;IACI,YAAY,IAAI,MAAM;IAI7B;;OAEG;IACI,gBAAgB,IAAI,MAAM;IAIjC;;OAEG;IACI,qBAAqB,IAAI,MAAM;IAMtC;;;;;;OAMG;IACI,cAAc,CACnB,MAAM,EAAE,MAAM,EACd,MAAM,CAAC,EAAE;QACP,IAAI,EAAE,OAAO,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,QAAQ,CAAC;QAC9D,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,MAAM,CAAC;QAC7C,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB,EACD,QAAQ,GAAE,MAAoB,GAC7B,IAAI;IAOP;;;;;;OAMG;IACI,cAAc,CACnB,MAAM,EAAE,MAAM,EACd,MAAM,CAAC,EAAE;QACP,IAAI,EAAE,OAAO,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,QAAQ,CAAC;QAC9D,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,MAAM,CAAC;QAC7C,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB,EACD,QAAQ,GAAE,MAAoB,GAC7B,IAAI;CAMR;AACD,cAAM,yBAAyB;IACtB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,OAAO,CAAC;gBAGtB,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,MAAM,EACf,QAAQ,GAAE,MAAkB,EAC5B,WAAW,GAAE,MAAmB,EAChC,MAAM,CAAC,EAAE,MAAM,EACf,MAAM,CAAC,EAAE,OAAO;CAUnB;AAED,wBAAgB,kBAAkB,sBAEjC"}
|
|
@@ -0,0 +1,326 @@
|
|
|
1
|
+
import { logger } from "./logger.js";
|
|
2
|
+
import { Store } from "./stateManager.js";
|
|
3
|
+
import { generateGUID } from "../utils/generateGuid.js";
|
|
4
|
+
const log = logger;
|
|
5
|
+
export class EventBus {
|
|
6
|
+
eventTarget;
|
|
7
|
+
activeListeners = [];
|
|
8
|
+
id;
|
|
9
|
+
constructor(description = "event-bus") {
|
|
10
|
+
this.eventTarget = document.appendChild(document.createComment(description));
|
|
11
|
+
this.id = description;
|
|
12
|
+
}
|
|
13
|
+
on(type, listener) {
|
|
14
|
+
log.trace("Listener added", { type, listener });
|
|
15
|
+
try {
|
|
16
|
+
//this.validateNewListener(type);
|
|
17
|
+
const abortController = new AbortController();
|
|
18
|
+
this.eventTarget.addEventListener(type, listener, {
|
|
19
|
+
signal: abortController.signal,
|
|
20
|
+
});
|
|
21
|
+
this.activeListeners.push({
|
|
22
|
+
eventName: type,
|
|
23
|
+
remove: () => abortController.abort(),
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
catch (error) {
|
|
27
|
+
log.error(error.message, error);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
once(type, listener) {
|
|
31
|
+
try {
|
|
32
|
+
//this.validateNewListener(type);
|
|
33
|
+
const abortController = new AbortController();
|
|
34
|
+
this.eventTarget.addEventListener(type, listener, {
|
|
35
|
+
once: true,
|
|
36
|
+
signal: abortController.signal,
|
|
37
|
+
});
|
|
38
|
+
this.activeListeners.push({
|
|
39
|
+
eventName: type,
|
|
40
|
+
remove: () => abortController.abort(),
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
catch (error) {
|
|
44
|
+
log.error(error.message, error);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
remove(type) {
|
|
48
|
+
const listenersToRemove = this.activeListeners.filter((l) => l.eventName === type);
|
|
49
|
+
if (listenersToRemove.length === 0) {
|
|
50
|
+
log.warn(`No listener found for event type: ${type} on Event Bus ${this.id}`);
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
// Remove all listeners of this type
|
|
54
|
+
listenersToRemove.forEach((listener) => {
|
|
55
|
+
listener.remove();
|
|
56
|
+
});
|
|
57
|
+
// Clean up the activeListeners array
|
|
58
|
+
this.activeListeners = this.activeListeners.filter((l) => l.eventName !== type);
|
|
59
|
+
log.trace(`Event listener(s) ${type} removed from Event Bus ${this.id}. Remaining listeners: ${this.activeListeners.length}`);
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Remove all listeners for this event bus
|
|
63
|
+
*/
|
|
64
|
+
removeAll() {
|
|
65
|
+
this.activeListeners.forEach((listener) => {
|
|
66
|
+
listener.remove();
|
|
67
|
+
});
|
|
68
|
+
this.activeListeners = [];
|
|
69
|
+
log.trace(`All event listeners removed from Event Bus ${this.id}`);
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Get the count of active listeners
|
|
73
|
+
*/
|
|
74
|
+
getListenerCount() {
|
|
75
|
+
return this.activeListeners.length;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Destroy this event bus and clean up all listeners
|
|
79
|
+
*/
|
|
80
|
+
destroy() {
|
|
81
|
+
this.removeAll();
|
|
82
|
+
// Remove the comment node from DOM if it has a parent
|
|
83
|
+
if (this.eventTarget instanceof Node && this.eventTarget.parentNode) {
|
|
84
|
+
this.eventTarget.parentNode.removeChild(this.eventTarget);
|
|
85
|
+
}
|
|
86
|
+
log.trace(`Event Bus ${this.id} destroyed`);
|
|
87
|
+
}
|
|
88
|
+
emit(type, detail) {
|
|
89
|
+
try {
|
|
90
|
+
this.validateEventDispatch(type);
|
|
91
|
+
return this.eventTarget.dispatchEvent(new CustomEvent(type, { detail }));
|
|
92
|
+
}
|
|
93
|
+
catch (error) {
|
|
94
|
+
log.error(error.message, error);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
// private validateNewListener(type: string): void {
|
|
98
|
+
// // Allow multiple listeners for the same event type
|
|
99
|
+
// // This validation is too restrictive for our use case
|
|
100
|
+
// // Components may need to register multiple listeners for the same event
|
|
101
|
+
// return;
|
|
102
|
+
// }
|
|
103
|
+
validateEventDispatch(type) {
|
|
104
|
+
if (this.activeListeners.filter((l) => l.eventName === type).length === 0) {
|
|
105
|
+
throw new Error(`Failed to dispatch event. Event Bus with Id ${this.id} does not contain a listener for an event with the name ${type}`);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
export class EventOrchestrator {
|
|
110
|
+
eventBuses = [];
|
|
111
|
+
eventQueue = [];
|
|
112
|
+
abortCommand = false;
|
|
113
|
+
globalStateStore;
|
|
114
|
+
stateEventBus;
|
|
115
|
+
constructor() {
|
|
116
|
+
this.run();
|
|
117
|
+
this.globalStateStore = new Store({});
|
|
118
|
+
this.stateEventBus = this.registerEventBus("stateEvent");
|
|
119
|
+
this.stateEventBus.on("stateUpdate", (data) => {
|
|
120
|
+
this.globalStateStore.mutateStore(data.detail.id, data.detail.payload);
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
run() {
|
|
124
|
+
const processQueue = () => {
|
|
125
|
+
if (this.abortCommand)
|
|
126
|
+
return;
|
|
127
|
+
if (this.eventQueue.length > 0) {
|
|
128
|
+
this.processNextQueueItem();
|
|
129
|
+
// Process immediately if there are more events
|
|
130
|
+
if (this.eventQueue.length > 0) {
|
|
131
|
+
requestAnimationFrame(processQueue);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
// Always schedule the next check
|
|
135
|
+
if (!this.abortCommand) {
|
|
136
|
+
requestAnimationFrame(processQueue);
|
|
137
|
+
}
|
|
138
|
+
};
|
|
139
|
+
// Start the processing loop
|
|
140
|
+
requestAnimationFrame(processQueue);
|
|
141
|
+
}
|
|
142
|
+
registerEventBus(name) {
|
|
143
|
+
const eventBus = new EventBus(name);
|
|
144
|
+
this.eventBuses.push({ id: name, eventBus: eventBus });
|
|
145
|
+
return eventBus;
|
|
146
|
+
}
|
|
147
|
+
getEventBus(name) {
|
|
148
|
+
const busRecord = this.eventBuses.find((b) => b.id === name);
|
|
149
|
+
return busRecord ? busRecord.eventBus : null;
|
|
150
|
+
}
|
|
151
|
+
enqueue(event, forBus, priority = "default", params, scheduleFor, expiry) {
|
|
152
|
+
// For navigation events, remove any existing pending navigation events to prevent lag
|
|
153
|
+
if (forBus === "navigation-manager" && (event === "navigate-to-page" || event === "navigate-to-view")) {
|
|
154
|
+
this.removeQueuedNavigationEvents(event, forBus);
|
|
155
|
+
}
|
|
156
|
+
const item = new ApplicationEventQueueItem(forBus, event, priority, scheduleFor, expiry, params);
|
|
157
|
+
this.eventQueue.push(item);
|
|
158
|
+
return item.instanceIdentifier;
|
|
159
|
+
}
|
|
160
|
+
getQueuedEventById(id) {
|
|
161
|
+
return this.eventQueue.filter((e) => e.instanceIdentifier === id)[0];
|
|
162
|
+
}
|
|
163
|
+
removeQueuedNavigationEvents(eventId, eventBusId) {
|
|
164
|
+
// Remove all queued navigation events of the same type from the queue
|
|
165
|
+
// This prevents lag when rapidly switching between views/pages
|
|
166
|
+
this.eventQueue = this.eventQueue.filter((item) => !(item.eventBusId === eventBusId && item.eventId === eventId));
|
|
167
|
+
}
|
|
168
|
+
rescheduleQueuedEvent(id, newSchedule) {
|
|
169
|
+
this.eventQueue.filter((e) => e.instanceIdentifier === id)[0].scheduleFor = newSchedule;
|
|
170
|
+
}
|
|
171
|
+
destroy() {
|
|
172
|
+
this.abortCommand = true;
|
|
173
|
+
}
|
|
174
|
+
useGlobalState(initalValue) {
|
|
175
|
+
const id = generateGUID();
|
|
176
|
+
const setter = (newValue) => {
|
|
177
|
+
this.enqueue("stateUpdate", "stateEvent", "immediate", {
|
|
178
|
+
id,
|
|
179
|
+
payload: newValue,
|
|
180
|
+
});
|
|
181
|
+
};
|
|
182
|
+
setter(initalValue);
|
|
183
|
+
return [this.globalStateStore.getStateObject()[id], setter];
|
|
184
|
+
}
|
|
185
|
+
processNextQueueItem() {
|
|
186
|
+
const nextEvent = this.getPrioritisedEventFromQueue();
|
|
187
|
+
if (nextEvent) {
|
|
188
|
+
const filteredBusses = this.eventBuses.filter((b) => b.id === nextEvent.eventBusId);
|
|
189
|
+
if (filteredBusses.length >= 1) {
|
|
190
|
+
filteredBusses[0].eventBus.emit(nextEvent.eventId, nextEvent.params || {});
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
getPrioritisedEventFromQueue() {
|
|
195
|
+
const currentTime = Date.now();
|
|
196
|
+
// Filter out expired events and scheduled events that haven't reached their scheduled time yet
|
|
197
|
+
const availableEvents = this.eventQueue.filter((event) => {
|
|
198
|
+
// Remove expired events
|
|
199
|
+
if (event.expiry && event.expiry <= currentTime) {
|
|
200
|
+
log.trace(`Event expired and removed from queue: ${event.eventId} on bus ${event.eventBusId}`);
|
|
201
|
+
return false;
|
|
202
|
+
}
|
|
203
|
+
// Check scheduled events
|
|
204
|
+
if (event.priority === "scheduled") {
|
|
205
|
+
return event.scheduleFor <= currentTime;
|
|
206
|
+
}
|
|
207
|
+
return true;
|
|
208
|
+
});
|
|
209
|
+
if (availableEvents.length === 0) {
|
|
210
|
+
return null;
|
|
211
|
+
}
|
|
212
|
+
// Sort by priority, then by FIFO (earliest scheduleFor time first within each priority group)
|
|
213
|
+
availableEvents.sort((a, b) => {
|
|
214
|
+
// Define priority order
|
|
215
|
+
const priorityOrder = {
|
|
216
|
+
scheduled: 1,
|
|
217
|
+
immediate: 2,
|
|
218
|
+
animation: 3,
|
|
219
|
+
default: 4,
|
|
220
|
+
};
|
|
221
|
+
const aPriority = priorityOrder[a.priority] || 4; // Default to 4 if priority not found
|
|
222
|
+
const bPriority = priorityOrder[b.priority] || 4;
|
|
223
|
+
// First sort by priority
|
|
224
|
+
if (aPriority !== bPriority) {
|
|
225
|
+
return aPriority - bPriority;
|
|
226
|
+
}
|
|
227
|
+
// Within same priority group, sort by FIFO (earliest scheduleFor first)
|
|
228
|
+
return a.scheduleFor - b.scheduleFor;
|
|
229
|
+
});
|
|
230
|
+
// Get the highest priority event
|
|
231
|
+
const nextEvent = availableEvents[0];
|
|
232
|
+
// Remove it from the original queue
|
|
233
|
+
const eventIndex = this.eventQueue.indexOf(nextEvent);
|
|
234
|
+
if (eventIndex > -1) {
|
|
235
|
+
this.eventQueue.splice(eventIndex, 1);
|
|
236
|
+
}
|
|
237
|
+
return nextEvent;
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* Clean up expired events from the queue
|
|
241
|
+
* This is a safety net for expired events that weren't processed
|
|
242
|
+
*/
|
|
243
|
+
cleanupExpiredEvents() {
|
|
244
|
+
const currentTime = Date.now();
|
|
245
|
+
const beforeCount = this.eventQueue.length;
|
|
246
|
+
this.eventQueue = this.eventQueue.filter((event) => {
|
|
247
|
+
if (event.expiry && event.expiry <= currentTime) {
|
|
248
|
+
log.trace(`Expired event cleaned up: ${event.eventId} on bus ${event.eventBusId}`);
|
|
249
|
+
return false;
|
|
250
|
+
}
|
|
251
|
+
return true;
|
|
252
|
+
});
|
|
253
|
+
const removedCount = beforeCount - this.eventQueue.length;
|
|
254
|
+
if (removedCount > 0) {
|
|
255
|
+
log.trace(`Cleaned up ${removedCount} expired events. Remaining queue size: ${this.eventQueue.length}`);
|
|
256
|
+
}
|
|
257
|
+
return removedCount;
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* Get the current size of the event queue
|
|
261
|
+
*/
|
|
262
|
+
getQueueSize() {
|
|
263
|
+
return this.eventQueue.length;
|
|
264
|
+
}
|
|
265
|
+
/**
|
|
266
|
+
* Get the count of registered event buses
|
|
267
|
+
*/
|
|
268
|
+
getEventBusCount() {
|
|
269
|
+
return this.eventBuses.length;
|
|
270
|
+
}
|
|
271
|
+
/**
|
|
272
|
+
* Get total listener count across all event buses
|
|
273
|
+
*/
|
|
274
|
+
getTotalListenerCount() {
|
|
275
|
+
return this.eventBuses.reduce((total, busRecord) => {
|
|
276
|
+
return total + busRecord.eventBus.getListenerCount();
|
|
277
|
+
}, 0);
|
|
278
|
+
}
|
|
279
|
+
/**
|
|
280
|
+
* Navigate to a page with optional transition configuration
|
|
281
|
+
*
|
|
282
|
+
* @param pageId - The ID of the page to navigate to
|
|
283
|
+
* @param config - Optional transition configuration
|
|
284
|
+
* @param priority - Event priority: "immediate", "normal", or "low" (default: "immediate")
|
|
285
|
+
*/
|
|
286
|
+
navigateToPage(pageId, config, priority = "immediate") {
|
|
287
|
+
this.enqueue("navigate-to-page", "navigation-manager", priority, {
|
|
288
|
+
pageId,
|
|
289
|
+
config: config || { type: "snap" }
|
|
290
|
+
});
|
|
291
|
+
}
|
|
292
|
+
/**
|
|
293
|
+
* Navigate to a view with optional transition configuration
|
|
294
|
+
*
|
|
295
|
+
* @param viewId - The ID of the view to navigate to
|
|
296
|
+
* @param config - Optional transition configuration
|
|
297
|
+
* @param priority - Event priority: "immediate", "normal", or "low" (default: "immediate")
|
|
298
|
+
*/
|
|
299
|
+
navigateToView(viewId, config, priority = "immediate") {
|
|
300
|
+
this.enqueue("navigate-to-view", "navigation-manager", priority, {
|
|
301
|
+
viewId,
|
|
302
|
+
config: config || { type: "snap" }
|
|
303
|
+
});
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
class ApplicationEventQueueItem {
|
|
307
|
+
instanceIdentifier;
|
|
308
|
+
eventBusId;
|
|
309
|
+
eventId;
|
|
310
|
+
priority;
|
|
311
|
+
scheduleFor;
|
|
312
|
+
expiry;
|
|
313
|
+
params;
|
|
314
|
+
constructor(eventBusId, eventId, priority = "default", scheduleFor = Date.now(), expiry, params) {
|
|
315
|
+
this.instanceIdentifier = generateGUID();
|
|
316
|
+
this.eventBusId = eventBusId;
|
|
317
|
+
this.eventId = eventId;
|
|
318
|
+
this.priority = priority;
|
|
319
|
+
this.scheduleFor = scheduleFor;
|
|
320
|
+
this.expiry = expiry;
|
|
321
|
+
this.params = params;
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
export function createOrchestrator() {
|
|
325
|
+
return new EventOrchestrator();
|
|
326
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
export interface PointerEventData {
|
|
2
|
+
x: number;
|
|
3
|
+
y: number;
|
|
4
|
+
target: Element;
|
|
5
|
+
originalEvent: Event;
|
|
6
|
+
type: "mouse" | "touch";
|
|
7
|
+
}
|
|
8
|
+
export interface DragCallbacks {
|
|
9
|
+
start?: (data: PointerEventData) => void;
|
|
10
|
+
move?: (data: PointerEventData) => void;
|
|
11
|
+
end?: (data: PointerEventData) => void;
|
|
12
|
+
}
|
|
13
|
+
export interface HoverCallbacks {
|
|
14
|
+
enter?: (data: PointerEventData) => void;
|
|
15
|
+
leave?: (data: PointerEventData) => void;
|
|
16
|
+
}
|
|
17
|
+
export interface SwipeCallbacks {
|
|
18
|
+
left?: (data: PointerEventData) => void;
|
|
19
|
+
right?: (data: PointerEventData) => void;
|
|
20
|
+
up?: (data: PointerEventData) => void;
|
|
21
|
+
down?: (data: PointerEventData) => void;
|
|
22
|
+
}
|
|
23
|
+
export declare class EventManager {
|
|
24
|
+
private shadowRoot;
|
|
25
|
+
private abortController;
|
|
26
|
+
private eventListeners;
|
|
27
|
+
private selectorListeners;
|
|
28
|
+
private dragStates;
|
|
29
|
+
private swipeStates;
|
|
30
|
+
private longPressTimers;
|
|
31
|
+
private componentId;
|
|
32
|
+
constructor(shadowRoot: ShadowRoot, componentId: string);
|
|
33
|
+
/**
|
|
34
|
+
* Unified point interaction - handles both click and tap
|
|
35
|
+
*/
|
|
36
|
+
point(selector: string, callback: (data: PointerEventData) => void): void;
|
|
37
|
+
/**
|
|
38
|
+
* Un-point interaction - handles touch and click events on the background to de-select an active element
|
|
39
|
+
*/
|
|
40
|
+
unpoint(selector: string, callback: (data: PointerEventData) => void): void;
|
|
41
|
+
/**
|
|
42
|
+
* Drag interaction - handles both mouse drag and touch drag
|
|
43
|
+
*/
|
|
44
|
+
drag(selector: string, callbacks: DragCallbacks): void;
|
|
45
|
+
/**
|
|
46
|
+
* Hover interaction - mouse enter/leave with touch fallback
|
|
47
|
+
*/
|
|
48
|
+
hover(selector: string, callbacks: HoverCallbacks): void;
|
|
49
|
+
/**
|
|
50
|
+
* Long press interaction - works for both mouse and touch
|
|
51
|
+
*/
|
|
52
|
+
longPress(selector: string, callback: (data: PointerEventData) => void, duration?: number): void;
|
|
53
|
+
/**
|
|
54
|
+
* Swipe gesture detection
|
|
55
|
+
*/
|
|
56
|
+
swipe(selector: string, callbacks: SwipeCallbacks, threshold?: number): void;
|
|
57
|
+
/**
|
|
58
|
+
* Add a custom event listener with automatic cleanup
|
|
59
|
+
*/
|
|
60
|
+
addEventListener(element: Element | Document, type: string, listener: EventListener, options?: AddEventListenerOptions): void;
|
|
61
|
+
/**
|
|
62
|
+
* Add an event listener with tracking for selector and method
|
|
63
|
+
*/
|
|
64
|
+
private addEventListenerWithTracking;
|
|
65
|
+
/**
|
|
66
|
+
* Remove a specific event listener
|
|
67
|
+
*/
|
|
68
|
+
removeEventListener(element: Element, type: string, listener: EventListener): void;
|
|
69
|
+
/**
|
|
70
|
+
* Clean up listeners for a specific selector and method
|
|
71
|
+
*/
|
|
72
|
+
clearSelectorListeners(selector: string, method: string): void;
|
|
73
|
+
/**
|
|
74
|
+
* Clean up all event listeners
|
|
75
|
+
*/
|
|
76
|
+
destroy(): void;
|
|
77
|
+
private createPointerEventData;
|
|
78
|
+
private startDrag;
|
|
79
|
+
private handleDragMove;
|
|
80
|
+
private handleDragEnd;
|
|
81
|
+
private movementThresholdMet;
|
|
82
|
+
private startLongPress;
|
|
83
|
+
private cancelLongPress;
|
|
84
|
+
private startSwipe;
|
|
85
|
+
private endSwipe;
|
|
86
|
+
}
|
|
87
|
+
//# sourceMappingURL=eventManager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"eventManager.d.ts","sourceRoot":"","sources":["../../src/eventManager.ts"],"names":[],"mappings":"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"}
|