@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.
Files changed (48) hide show
  1. package/README.md +326 -0
  2. package/dist/animations.css +160 -0
  3. package/dist/index.d.ts +20 -0
  4. package/dist/index.d.ts.map +1 -0
  5. package/dist/index.js +26 -0
  6. package/dist/src/animationBus.d.ts +30 -0
  7. package/dist/src/animationBus.d.ts.map +1 -0
  8. package/dist/src/animationBus.js +125 -0
  9. package/dist/src/appBuilder.d.ts +173 -0
  10. package/dist/src/appBuilder.d.ts.map +1 -0
  11. package/dist/src/appBuilder.js +957 -0
  12. package/dist/src/eventBus.d.ts +100 -0
  13. package/dist/src/eventBus.d.ts.map +1 -0
  14. package/dist/src/eventBus.js +326 -0
  15. package/dist/src/eventManager.d.ts +87 -0
  16. package/dist/src/eventManager.d.ts.map +1 -0
  17. package/dist/src/eventManager.js +455 -0
  18. package/dist/src/garbageCollector.d.ts +68 -0
  19. package/dist/src/garbageCollector.d.ts.map +1 -0
  20. package/dist/src/garbageCollector.js +169 -0
  21. package/dist/src/logger.d.ts +11 -0
  22. package/dist/src/logger.d.ts.map +1 -0
  23. package/dist/src/logger.js +15 -0
  24. package/dist/src/navigationManager.d.ts +105 -0
  25. package/dist/src/navigationManager.d.ts.map +1 -0
  26. package/dist/src/navigationManager.js +533 -0
  27. package/dist/src/screensaverManager.d.ts +66 -0
  28. package/dist/src/screensaverManager.d.ts.map +1 -0
  29. package/dist/src/screensaverManager.js +417 -0
  30. package/dist/src/settingsManager.d.ts +48 -0
  31. package/dist/src/settingsManager.d.ts.map +1 -0
  32. package/dist/src/settingsManager.js +317 -0
  33. package/dist/src/stateManager.d.ts +58 -0
  34. package/dist/src/stateManager.d.ts.map +1 -0
  35. package/dist/src/stateManager.js +278 -0
  36. package/dist/src/types.d.ts +32 -0
  37. package/dist/src/types.d.ts.map +1 -0
  38. package/dist/src/types.js +1 -0
  39. package/dist/utils/generateGuid.d.ts +2 -0
  40. package/dist/utils/generateGuid.d.ts.map +1 -0
  41. package/dist/utils/generateGuid.js +19 -0
  42. package/dist/utils/logger.d.ts +9 -0
  43. package/dist/utils/logger.d.ts.map +1 -0
  44. package/dist/utils/logger.js +42 -0
  45. package/dist/utils/template-helpers.d.ts +32 -0
  46. package/dist/utils/template-helpers.d.ts.map +1 -0
  47. package/dist/utils/template-helpers.js +24 -0
  48. package/package.json +59 -0
@@ -0,0 +1,317 @@
1
+ import { stateManager } from "./stateManager";
2
+ import { logger } from "./logger";
3
+ const log = logger;
4
+ export class SettingsManager {
5
+ eventBus;
6
+ orchestrator;
7
+ navigationManager;
8
+ config = null;
9
+ isSettingsActive = false;
10
+ lastActiveViewId = null;
11
+ touchSequenceState = {
12
+ step: 0,
13
+ lastTouchTime: 0,
14
+ };
15
+ lastEventTime = 0; // Track last event to prevent duplicates
16
+ touchListeners = [];
17
+ // Default configuration values
18
+ DEFAULT_CORNER_RADIUS = 100;
19
+ DEFAULT_TOUCH_TIMEOUT = 3000;
20
+ EVENT_DEBOUNCE_MS = 50; // Ignore events within 50ms of each other
21
+ constructor(orchestrator, navigationManager) {
22
+ this.orchestrator = orchestrator;
23
+ this.navigationManager = navigationManager;
24
+ this.eventBus = orchestrator.registerEventBus("settings-manager");
25
+ this.setupEventListeners();
26
+ this.initializeGlobalState();
27
+ }
28
+ initializeGlobalState() {
29
+ if (!stateManager.has("settings.isActive")) {
30
+ stateManager.set("settings.isActive", false);
31
+ }
32
+ if (!stateManager.has("settings.lastActiveViewId")) {
33
+ stateManager.set("settings.lastActiveViewId", null);
34
+ }
35
+ }
36
+ setupEventListeners() {
37
+ this.eventBus.on("register-settings", (e) => {
38
+ const { config } = e.detail;
39
+ this.registerSettings(config);
40
+ });
41
+ this.eventBus.on("activate-settings", () => {
42
+ this.activateSettings();
43
+ });
44
+ this.eventBus.on("deactivate-settings", () => {
45
+ this.deactivateSettings();
46
+ });
47
+ // Listen for navigation changes to track active views
48
+ const navBus = this.orchestrator.getEventBus("navigation-manager");
49
+ if (navBus) {
50
+ navBus.on("view-changed", (e) => {
51
+ const { newViewId } = e.detail;
52
+ if (!this.isSettingsActive && newViewId !== this.config?.view.componentId) {
53
+ this.lastActiveViewId = newViewId;
54
+ stateManager.set("settings.lastActiveViewId", newViewId);
55
+ }
56
+ });
57
+ }
58
+ }
59
+ registerSettings(config) {
60
+ this.validateConfig(config);
61
+ // Clean up existing settings if any
62
+ if (this.config) {
63
+ this.cleanup();
64
+ }
65
+ this.config = {
66
+ ...config,
67
+ exitBehavior: config.exitBehavior || "reset",
68
+ cornerTouchRadius: config.cornerTouchRadius || this.DEFAULT_CORNER_RADIUS,
69
+ touchTimeout: config.touchTimeout || this.DEFAULT_TOUCH_TIMEOUT,
70
+ debugMode: config.debugMode || false,
71
+ transitionConfig: config.transitionConfig || {
72
+ type: "fade",
73
+ duration: 500,
74
+ },
75
+ };
76
+ // Register the settings view with navigation manager
77
+ const navBus = this.orchestrator.getEventBus("navigation-manager");
78
+ if (navBus) {
79
+ navBus.emit("register-view", { view: this.config.view });
80
+ }
81
+ this.setupCornerTouchListeners();
82
+ this.resetTouchSequence();
83
+ log.trace(`Settings registered with corner touch activation (radius: ${this.config.cornerTouchRadius}px, timeout: ${this.config.touchTimeout}ms)`);
84
+ }
85
+ validateConfig(config) {
86
+ if (!config.view) {
87
+ throw new Error("Settings view is required");
88
+ }
89
+ if (config.exitBehavior === "reset" && !config.startingViewId) {
90
+ throw new Error('startingViewId is required when exitBehavior is "reset"');
91
+ }
92
+ if (config.exitBehavior && !["reset", "return"].includes(config.exitBehavior)) {
93
+ throw new Error('exitBehavior must be either "reset" or "return"');
94
+ }
95
+ if (config.cornerTouchRadius && config.cornerTouchRadius <= 0) {
96
+ throw new Error("cornerTouchRadius must be greater than 0");
97
+ }
98
+ if (config.touchTimeout && config.touchTimeout <= 0) {
99
+ throw new Error("touchTimeout must be greater than 0");
100
+ }
101
+ }
102
+ setupCornerTouchListeners() {
103
+ if (!this.config)
104
+ return;
105
+ const touchHandler = (event) => {
106
+ if (event instanceof TouchEvent || event instanceof MouseEvent) {
107
+ this.handleTouchAttempt(event);
108
+ }
109
+ };
110
+ // Add listeners for both touch and mouse events
111
+ const eventTypes = ["touchstart"];
112
+ eventTypes.forEach((eventType) => {
113
+ const listener = touchHandler.bind(this);
114
+ document.addEventListener(eventType, listener, { passive: true });
115
+ this.touchListeners.push({
116
+ element: document,
117
+ type: eventType,
118
+ listener,
119
+ });
120
+ });
121
+ }
122
+ handleTouchAttempt(event) {
123
+ if (!this.config)
124
+ return;
125
+ const now = Date.now();
126
+ // Prevent duplicate events (touchstart + mousedown on same interaction)
127
+ if (now - this.lastEventTime < this.EVENT_DEBOUNCE_MS) {
128
+ log.trace("Ignoring duplicate event within debounce window");
129
+ return;
130
+ }
131
+ this.lastEventTime = now;
132
+ // Get touch/click coordinates
133
+ let x, y;
134
+ if (event instanceof TouchEvent && event.touches.length > 0) {
135
+ x = event.touches[0].clientX;
136
+ y = event.touches[0].clientY;
137
+ }
138
+ else if (event instanceof MouseEvent) {
139
+ x = event.clientX;
140
+ y = event.clientY;
141
+ }
142
+ else {
143
+ return;
144
+ }
145
+ const timeSinceLastTouch = now - this.touchSequenceState.lastTouchTime;
146
+ // Check if timeout exceeded
147
+ if (this.touchSequenceState.step > 0 && timeSinceLastTouch > this.config.touchTimeout) {
148
+ log.trace("Touch sequence timed out, resetting");
149
+ this.resetTouchSequence();
150
+ }
151
+ const cornerDetected = this.detectCornerTouch(x, y);
152
+ if (cornerDetected === null) {
153
+ // Touch outside corner zones - reset sequence
154
+ if (this.touchSequenceState.step > 0) {
155
+ log.trace("Touch outside corner zones, resetting sequence");
156
+ this.resetTouchSequence();
157
+ }
158
+ return;
159
+ }
160
+ // Check if the correct corner was touched based on current step
161
+ const expectedCorner = this.getExpectedCorner();
162
+ if (cornerDetected === expectedCorner) {
163
+ log.trace(`Correct corner touched: ${cornerDetected} (step ${this.touchSequenceState.step + 1}/3)`);
164
+ this.touchSequenceState.step++;
165
+ this.touchSequenceState.lastTouchTime = now;
166
+ // Check if sequence is complete
167
+ if (this.touchSequenceState.step === 3) {
168
+ log.trace("Touch sequence complete! Activating settings...");
169
+ this.activateSettings();
170
+ this.resetTouchSequence();
171
+ }
172
+ }
173
+ else {
174
+ // Wrong corner touched - reset sequence
175
+ log.trace(`Wrong corner touched: expected ${expectedCorner}, got ${cornerDetected}. Resetting sequence.`);
176
+ this.resetTouchSequence();
177
+ }
178
+ }
179
+ detectCornerTouch(x, y) {
180
+ if (!this.config)
181
+ return null;
182
+ const radius = this.config.cornerTouchRadius;
183
+ const width = window.innerWidth;
184
+ const height = window.innerHeight;
185
+ // Top-left corner
186
+ if (x < radius && y < radius) {
187
+ log.trace("top-left touch", [x, y, radius]);
188
+ return "top-left";
189
+ }
190
+ // Top-right corner
191
+ if (x > width - radius && y < radius) {
192
+ log.trace("top-right touch");
193
+ return "top-right";
194
+ }
195
+ // Bottom-right corner
196
+ if (x > width - radius && y > height - radius) {
197
+ log.trace("bottom-right touch");
198
+ return "bottom-right";
199
+ }
200
+ return null;
201
+ }
202
+ getExpectedCorner() {
203
+ switch (this.touchSequenceState.step) {
204
+ case 0:
205
+ return "top-left";
206
+ case 1:
207
+ return "top-right";
208
+ case 2:
209
+ return "bottom-right";
210
+ default:
211
+ return "top-left";
212
+ }
213
+ }
214
+ resetTouchSequence() {
215
+ this.touchSequenceState = {
216
+ step: 0,
217
+ lastTouchTime: 0,
218
+ };
219
+ this.lastEventTime = 0; // Reset debounce timer as well
220
+ }
221
+ async activateSettings() {
222
+ if (!this.config || this.isSettingsActive)
223
+ return;
224
+ log.trace("Activating settings");
225
+ // Store the current view before switching to settings
226
+ const currentViewId = this.navigationManager.getCurrentViewId();
227
+ if (currentViewId && currentViewId !== this.config.view.componentId) {
228
+ this.lastActiveViewId = currentViewId;
229
+ stateManager.set("settings.lastActiveViewId", currentViewId);
230
+ }
231
+ this.isSettingsActive = true;
232
+ stateManager.set("settings.isActive", true);
233
+ try {
234
+ await this.navigationManager.navigateToView(this.config.view.componentId, this.config.transitionConfig);
235
+ this.eventBus.emit("settings-activated", {
236
+ viewId: this.config.view.componentId,
237
+ previousViewId: this.lastActiveViewId,
238
+ });
239
+ }
240
+ catch (error) {
241
+ log.error("Failed to activate settings:", error);
242
+ this.isSettingsActive = false;
243
+ stateManager.set("settings.isActive", false);
244
+ }
245
+ }
246
+ async handleSettingsExit() {
247
+ if (!this.config || !this.isSettingsActive)
248
+ return;
249
+ log.trace(`Exiting settings with '${this.config.exitBehavior}' behavior`);
250
+ this.isSettingsActive = false;
251
+ stateManager.set("settings.isActive", false);
252
+ let targetViewId = null;
253
+ if (this.config.exitBehavior === "return" && this.lastActiveViewId) {
254
+ targetViewId = this.lastActiveViewId;
255
+ }
256
+ else if (this.config.exitBehavior === "reset" && this.config.startingViewId) {
257
+ targetViewId = this.config.startingViewId;
258
+ }
259
+ if (targetViewId) {
260
+ try {
261
+ await this.navigationManager.navigateToView(targetViewId, this.config.transitionConfig);
262
+ this.eventBus.emit("settings-deactivated", {
263
+ targetViewId,
264
+ exitBehavior: this.config.exitBehavior,
265
+ });
266
+ }
267
+ catch (error) {
268
+ log.error("Failed to exit settings:", error);
269
+ // Reset state on error
270
+ this.isSettingsActive = true;
271
+ stateManager.set("settings.isActive", true);
272
+ }
273
+ }
274
+ else {
275
+ log.warn("No target view available for settings exit");
276
+ }
277
+ }
278
+ async deactivateSettings() {
279
+ await this.handleSettingsExit();
280
+ }
281
+ isActive() {
282
+ return this.isSettingsActive;
283
+ }
284
+ getCurrentConfig() {
285
+ return this.config;
286
+ }
287
+ getLastActiveViewId() {
288
+ return this.lastActiveViewId;
289
+ }
290
+ // Manual control methods
291
+ forceActivate() {
292
+ this.resetTouchSequence();
293
+ this.activateSettings();
294
+ }
295
+ forceDeactivate() {
296
+ this.deactivateSettings();
297
+ }
298
+ resetSequence() {
299
+ this.resetTouchSequence();
300
+ }
301
+ cleanup() {
302
+ // Remove all touch listeners
303
+ this.touchListeners.forEach(({ element, type, listener }) => {
304
+ element.removeEventListener(type, listener);
305
+ });
306
+ this.touchListeners.length = 0;
307
+ this.isSettingsActive = false;
308
+ stateManager.set("settings.isActive", false);
309
+ this.resetTouchSequence();
310
+ }
311
+ destroy() {
312
+ this.cleanup();
313
+ this.config = null;
314
+ this.lastActiveViewId = null;
315
+ log.trace("SettingsManager destroyed");
316
+ }
317
+ }
@@ -0,0 +1,58 @@
1
+ interface StoreParams {
2
+ mutations?: object;
3
+ state?: Store;
4
+ status?: string;
5
+ events?: object;
6
+ }
7
+ export interface StateSubscription {
8
+ unsubscribe: () => void;
9
+ }
10
+ export declare class Store {
11
+ private mutations;
12
+ private state;
13
+ private status;
14
+ private events;
15
+ private stateSubscriptions;
16
+ constructor(params: StoreParams);
17
+ getStateObject(): any;
18
+ getStateValue(key: string): any;
19
+ setStateValue(key: string, value: any): void;
20
+ subscribeToKey(key: string, callback: (value: any, key: string) => void): StateSubscription;
21
+ mutateStore(mutationKey: string, payload: any): boolean;
22
+ }
23
+ declare const globalStore: Store;
24
+ export declare class ComponentStateManager {
25
+ private localState;
26
+ private stateSubscriptions;
27
+ private onStateChange;
28
+ private stateProxy;
29
+ constructor(_: string, onStateChange: (key: string, value: any, isLocal: boolean) => void);
30
+ private createStateProxy;
31
+ getStateProxy(): any;
32
+ defineState(initialState: Record<string, any>): void;
33
+ useState<T>(key: string, initialValue: T): [T, (newValue: T) => void];
34
+ useGlobalState<T>(key: string, initialValue?: T): [T, (newValue: T) => void];
35
+ getLocalState(key: string): any;
36
+ destroy(): void;
37
+ }
38
+ export declare function createLocalStateStore(initialValue: any): any[];
39
+ export declare function getGlobalState(key: string): any;
40
+ export declare function setGlobalState(key: string, value: any): void;
41
+ export declare function subscribeToGlobalState(key: string, callback: (value: any, key: string) => void): StateSubscription;
42
+ export declare function useGlobalStateExternal<T>(key: string, initialValue?: T): [T, (newValue: T) => void];
43
+ export declare class ExternalStateManager {
44
+ private static instance;
45
+ private constructor();
46
+ static getInstance(): ExternalStateManager;
47
+ get<T>(key: string): T;
48
+ set<T>(key: string, value: T): void;
49
+ useState<T>(key: string, initialValue?: T): [T, (newValue: T) => void];
50
+ subscribe(key: string, callback: (value: any, key: string) => void): StateSubscription;
51
+ getAll(): any;
52
+ has(key: string): boolean;
53
+ remove(key: string): void;
54
+ clear(): void;
55
+ }
56
+ export declare const stateManager: ExternalStateManager;
57
+ export { globalStore };
58
+ //# sourceMappingURL=stateManager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stateManager.d.ts","sourceRoot":"","sources":["../../src/stateManager.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,278 @@
1
+ /* eslint-disable no-prototype-builtins */
2
+ /* eslint-disable @typescript-eslint/no-this-alias */
3
+ import { logger } from "./logger";
4
+ const log = logger;
5
+ class State {
6
+ events;
7
+ constructor() {
8
+ this.events = {};
9
+ }
10
+ subscribe(event, callback) {
11
+ const me = this;
12
+ if (!me.events.hasOwnProperty(event)) {
13
+ me.events[event] = [];
14
+ }
15
+ return me.events[event].push(callback);
16
+ }
17
+ publish(event, data = {}) {
18
+ const me = this;
19
+ if (!me.events.hasOwnProperty(event)) {
20
+ return [];
21
+ }
22
+ return me.events[event].map((callback) => callback(data));
23
+ }
24
+ unsubscribe(event, callbackIndex) {
25
+ if (this.events.hasOwnProperty(event) && this.events[event][callbackIndex - 1]) {
26
+ this.events[event].splice(callbackIndex - 1, 1);
27
+ }
28
+ }
29
+ }
30
+ export class Store {
31
+ mutations;
32
+ state;
33
+ status;
34
+ events;
35
+ stateSubscriptions = new Map();
36
+ constructor(params) {
37
+ const me = this;
38
+ if (params.hasOwnProperty("mutations")) {
39
+ this.mutations = params.mutations;
40
+ }
41
+ else {
42
+ this.mutations = {};
43
+ }
44
+ this.state = new Proxy(params.state || {}, {
45
+ set: function (state, key, value) {
46
+ const oldValue = state[key];
47
+ state[key] = value;
48
+ // Notify specific key subscribers
49
+ if (me.stateSubscriptions.has(key)) {
50
+ me.stateSubscriptions.get(key).forEach((callback) => {
51
+ callback(value, key);
52
+ });
53
+ }
54
+ // Notify general state change listeners
55
+ me.events.publish("stateChange", { key, value, oldValue, state: me.state });
56
+ if (me.status !== "mutation") {
57
+ log.warn(`You should use a mutation to set the value for state object ${key}.`);
58
+ }
59
+ me.status = "resting";
60
+ return true;
61
+ },
62
+ });
63
+ this.status = "resting";
64
+ this.events = new State();
65
+ }
66
+ getStateObject() {
67
+ return this.state;
68
+ }
69
+ getStateValue(key) {
70
+ return this.state[key];
71
+ }
72
+ setStateValue(key, value) {
73
+ this.status = "mutation";
74
+ this.state[key] = value;
75
+ }
76
+ subscribeToKey(key, callback) {
77
+ if (!this.stateSubscriptions.has(key)) {
78
+ this.stateSubscriptions.set(key, new Set());
79
+ }
80
+ this.stateSubscriptions.get(key).add(callback);
81
+ return {
82
+ unsubscribe: () => {
83
+ const subscribers = this.stateSubscriptions.get(key);
84
+ if (subscribers) {
85
+ subscribers.delete(callback);
86
+ if (subscribers.size === 0) {
87
+ this.stateSubscriptions.delete(key);
88
+ }
89
+ }
90
+ },
91
+ };
92
+ }
93
+ mutateStore(mutationKey, payload) {
94
+ const me = this;
95
+ if (typeof me.mutations[mutationKey] !== "function") {
96
+ log.warn(`Mutation with identifier ${mutationKey} does not exist`);
97
+ return false;
98
+ }
99
+ me.status = "mutation";
100
+ const newState = me.mutations[mutationKey](me.state, payload);
101
+ me.state = Object.assign(me.state, newState);
102
+ return true;
103
+ }
104
+ }
105
+ // Global store instance
106
+ const globalStore = new Store({});
107
+ // Component-level state management
108
+ export class ComponentStateManager {
109
+ localState = new Map();
110
+ stateSubscriptions = new Map();
111
+ onStateChange;
112
+ stateProxy = null;
113
+ constructor(_, onStateChange) {
114
+ this.onStateChange = onStateChange;
115
+ this.createStateProxy();
116
+ }
117
+ createStateProxy() {
118
+ this.stateProxy = new Proxy({}, {
119
+ get: (_, key) => {
120
+ return this.localState.get(key);
121
+ },
122
+ set: (_, key, value) => {
123
+ const oldValue = this.localState.get(key);
124
+ if (oldValue !== value) {
125
+ this.localState.set(key, value);
126
+ this.onStateChange(key, value, true);
127
+ }
128
+ return true;
129
+ },
130
+ has: (_, key) => {
131
+ return this.localState.has(key);
132
+ },
133
+ ownKeys: (_) => {
134
+ return Array.from(this.localState.keys());
135
+ },
136
+ getOwnPropertyDescriptor: (_, key) => {
137
+ if (this.localState.has(key)) {
138
+ return {
139
+ enumerable: true,
140
+ configurable: true,
141
+ value: this.localState.get(key),
142
+ };
143
+ }
144
+ return undefined;
145
+ },
146
+ });
147
+ }
148
+ getStateProxy() {
149
+ return this.stateProxy;
150
+ }
151
+ defineState(initialState) {
152
+ Object.entries(initialState).forEach(([key, value]) => {
153
+ if (!this.localState.has(key)) {
154
+ this.localState.set(key, value);
155
+ // Trigger initial state change to sync with component properties
156
+ this.onStateChange(key, value, true);
157
+ }
158
+ });
159
+ }
160
+ // Local state management
161
+ useState(key, initialValue) {
162
+ // Initialize if not exists
163
+ if (!this.localState.has(key)) {
164
+ this.localState.set(key, initialValue);
165
+ }
166
+ const currentValue = this.localState.get(key);
167
+ const setter = (newValue) => {
168
+ const oldValue = this.localState.get(key);
169
+ if (oldValue !== newValue) {
170
+ this.localState.set(key, newValue);
171
+ this.onStateChange(key, newValue, true);
172
+ }
173
+ };
174
+ return [currentValue, setter];
175
+ }
176
+ // Global state management
177
+ useGlobalState(key, initialValue) {
178
+ // Initialize global state if provided and doesn't exist
179
+ if (initialValue !== undefined && globalStore.getStateValue(key) === undefined) {
180
+ globalStore.setStateValue(key, initialValue);
181
+ }
182
+ const currentValue = globalStore.getStateValue(key);
183
+ // Subscribe to global state changes if not already subscribed
184
+ if (!this.stateSubscriptions.has(key)) {
185
+ const subscription = globalStore.subscribeToKey(key, (value) => {
186
+ this.onStateChange(key, value, false);
187
+ });
188
+ this.stateSubscriptions.set(key, subscription);
189
+ }
190
+ const setter = (newValue) => {
191
+ globalStore.setStateValue(key, newValue);
192
+ };
193
+ return [currentValue, setter];
194
+ }
195
+ getLocalState(key) {
196
+ return this.localState.get(key);
197
+ }
198
+ destroy() {
199
+ // Clean up all global state subscriptions
200
+ this.stateSubscriptions.forEach((subscription) => {
201
+ subscription.unsubscribe();
202
+ });
203
+ this.stateSubscriptions.clear();
204
+ this.localState.clear();
205
+ }
206
+ }
207
+ export function createLocalStateStore(initialValue) {
208
+ const id = crypto.randomUUID();
209
+ const setter = (newValue) => {
210
+ globalStore.setStateValue(id, newValue);
211
+ };
212
+ if (initialValue !== null) {
213
+ globalStore.setStateValue(id, initialValue);
214
+ }
215
+ return [globalStore.getStateValue(id), setter];
216
+ }
217
+ // External State Management Utilities
218
+ export function getGlobalState(key) {
219
+ return globalStore.getStateValue(key);
220
+ }
221
+ export function setGlobalState(key, value) {
222
+ globalStore.setStateValue(key, value);
223
+ }
224
+ export function subscribeToGlobalState(key, callback) {
225
+ return globalStore.subscribeToKey(key, callback);
226
+ }
227
+ export function useGlobalStateExternal(key, initialValue) {
228
+ // Initialize if provided and doesn't exist
229
+ if (initialValue !== undefined && globalStore.getStateValue(key) === undefined) {
230
+ globalStore.setStateValue(key, initialValue);
231
+ }
232
+ const currentValue = globalStore.getStateValue(key);
233
+ const setter = (newValue) => {
234
+ globalStore.setStateValue(key, newValue);
235
+ };
236
+ return [currentValue, setter];
237
+ }
238
+ // State Manager Singleton for external access
239
+ export class ExternalStateManager {
240
+ static instance;
241
+ constructor() { }
242
+ static getInstance() {
243
+ if (!ExternalStateManager.instance) {
244
+ ExternalStateManager.instance = new ExternalStateManager();
245
+ }
246
+ return ExternalStateManager.instance;
247
+ }
248
+ get(key) {
249
+ return globalStore.getStateValue(key);
250
+ }
251
+ set(key, value) {
252
+ globalStore.setStateValue(key, value);
253
+ }
254
+ useState(key, initialValue) {
255
+ return useGlobalStateExternal(key, initialValue);
256
+ }
257
+ subscribe(key, callback) {
258
+ return globalStore.subscribeToKey(key, callback);
259
+ }
260
+ getAll() {
261
+ return globalStore.getStateObject();
262
+ }
263
+ has(key) {
264
+ return globalStore.getStateValue(key) !== undefined;
265
+ }
266
+ remove(key) {
267
+ globalStore.setStateValue(key, undefined);
268
+ }
269
+ clear() {
270
+ const stateObj = globalStore.getStateObject();
271
+ Object.keys(stateObj).forEach((key) => {
272
+ globalStore.setStateValue(key, undefined);
273
+ });
274
+ }
275
+ }
276
+ // Convenience instance for immediate use
277
+ export const stateManager = ExternalStateManager.getInstance();
278
+ export { globalStore };
@@ -0,0 +1,32 @@
1
+ import { EventBus } from "./appBuilder";
2
+ import type { EventOrchestrator } from "./eventBus";
3
+ export interface EventBusRecord {
4
+ id: string;
5
+ eventBus: EventBus;
6
+ }
7
+ export interface EventListenerRecord {
8
+ eventName: string;
9
+ remove: () => void;
10
+ }
11
+ export interface PageProps {
12
+ id: string;
13
+ orchestrator: EventOrchestrator;
14
+ bubbleEvents: boolean;
15
+ }
16
+ export interface ViewProps {
17
+ id: string;
18
+ orchestrator: EventOrchestrator;
19
+ bubbleEvents: boolean;
20
+ }
21
+ export interface ComponentProps {
22
+ id: string;
23
+ orchestrator: EventOrchestrator;
24
+ bubbleEvents: boolean;
25
+ }
26
+ export interface RenderOptions {
27
+ fade?: {
28
+ enabled: boolean;
29
+ duration?: number;
30
+ };
31
+ }
32
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AACxC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AACpD,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,QAAQ,CAAC;CACpB;AACD,MAAM,WAAW,mBAAmB;IAClC,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,IAAI,CAAC;CACpB;AAED,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,YAAY,EAAE,iBAAiB,CAAC;IAChC,YAAY,EAAE,OAAO,CAAC;CACvB;AAED,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,YAAY,EAAE,iBAAiB,CAAC;IAChC,YAAY,EAAE,OAAO,CAAC;CACvB;AAED,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,YAAY,EAAE,iBAAiB,CAAC;IAChC,YAAY,EAAE,OAAO,CAAC;CACvB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,CAAC,EAAE;QACL,OAAO,EAAE,OAAO,CAAC;QACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;KACnB,CAAC;CACH"}
@@ -0,0 +1 @@
1
+ export {};