@omnipad/core 0.1.1-alpha.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/dist/index.js ADDED
@@ -0,0 +1,1176 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key of __getOwnPropNames(from))
14
+ if (!__hasOwnProp.call(to, key) && key !== except)
15
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
+ }
17
+ return to;
18
+ };
19
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
20
+ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
21
+
22
+ // src/index.ts
23
+ var index_exports = {};
24
+ __export(index_exports, {
25
+ ACTION_TYPES: () => ACTION_TYPES,
26
+ BaseEntity: () => BaseEntity,
27
+ CONTEXT: () => CONTEXT,
28
+ InputManager: () => InputManager,
29
+ InputZoneCore: () => InputZoneCore,
30
+ KEYS: () => KEYS,
31
+ KeyboardButtonCore: () => KeyboardButtonCore,
32
+ OmniPad: () => OmniPad,
33
+ Registry: () => Registry,
34
+ RootLayerCore: () => RootLayerCore,
35
+ SimpleEmitter: () => SimpleEmitter,
36
+ TYPES: () => TYPES,
37
+ TargetZoneCore: () => TargetZoneCore,
38
+ addVec: () => addVec,
39
+ applyAxialDeadzone: () => applyAxialDeadzone,
40
+ applyRadialDeadzone: () => applyRadialDeadzone,
41
+ clamp: () => clamp,
42
+ clampVector: () => clampVector,
43
+ degToRad: () => degToRad,
44
+ dispatchKeyboardEvent: () => dispatchKeyboardEvent,
45
+ dispatchPointerEventAtPos: () => dispatchPointerEventAtPos,
46
+ exportProfile: () => exportProfile,
47
+ focusElement: () => focusElement,
48
+ generateUID: () => generateUID,
49
+ getAnchorPosition: () => getAnchorPosition,
50
+ getAngle: () => getAngle,
51
+ getDeadzoneScalar: () => getDeadzoneScalar,
52
+ getDeepActiveElement: () => getDeepActiveElement,
53
+ getDeepElement: () => getDeepElement,
54
+ getDistance: () => getDistance,
55
+ isGlobalID: () => isGlobalID,
56
+ isVec2Equal: () => isVec2Equal,
57
+ lerp: () => lerp,
58
+ lockTo4Directions: () => lockTo4Directions,
59
+ lockTo8Directions: () => lockTo8Directions,
60
+ normalizeVec: () => normalizeVec,
61
+ parseProfileJson: () => parseProfileJson,
62
+ parseProfileTree: () => parseProfileTree,
63
+ percentToPx: () => percentToPx,
64
+ pxToPercent: () => pxToPercent,
65
+ radToDeg: () => radToDeg,
66
+ radToVec: () => radToVec,
67
+ remap: () => remap,
68
+ resolveLayoutStyle: () => resolveLayoutStyle,
69
+ roundTo: () => roundTo,
70
+ scaleVec: () => scaleVec,
71
+ subVec: () => subVec
72
+ });
73
+ module.exports = __toCommonJS(index_exports);
74
+
75
+ // src/types/keys.ts
76
+ var STANDARD_KEYS = {
77
+ // --- System Controls (8-27) ---
78
+ Backspace: { key: "Backspace", code: "Backspace", keyCode: 8 },
79
+ Tab: { key: "Tab", code: "Tab", keyCode: 9 },
80
+ Enter: { key: "Enter", code: "Enter", keyCode: 13 },
81
+ ShiftLeft: { key: "Shift", code: "ShiftLeft", keyCode: 16 },
82
+ ControlLeft: { key: "Control", code: "ControlLeft", keyCode: 17 },
83
+ AltLeft: { key: "Alt", code: "AltLeft", keyCode: 18 },
84
+ Pause: { key: "Pause", code: "Pause", keyCode: 19 },
85
+ CapsLock: { key: "CapsLock", code: "CapsLock", keyCode: 20 },
86
+ Escape: { key: "Escape", code: "Escape", keyCode: 27 },
87
+ // --- Navigation & Editing (32-46) ---
88
+ Space: { key: " ", code: "Space", keyCode: 32 },
89
+ PageUp: { key: "PageUp", code: "PageUp", keyCode: 33 },
90
+ PageDown: { key: "PageDown", code: "PageDown", keyCode: 34 },
91
+ End: { key: "End", code: "End", keyCode: 35 },
92
+ Home: { key: "Home", code: "Home", keyCode: 36 },
93
+ ArrowLeft: { key: "ArrowLeft", code: "ArrowLeft", keyCode: 37 },
94
+ ArrowUp: { key: "ArrowUp", code: "ArrowUp", keyCode: 38 },
95
+ ArrowRight: { key: "ArrowRight", code: "ArrowRight", keyCode: 39 },
96
+ ArrowDown: { key: "ArrowDown", code: "ArrowDown", keyCode: 40 },
97
+ PrintScreen: { key: "PrintScreen", code: "PrintScreen", keyCode: 44 },
98
+ Insert: { key: "Insert", code: "Insert", keyCode: 45 },
99
+ Delete: { key: "Delete", code: "Delete", keyCode: 46 },
100
+ // --- Digit Keys 0-9 (48-57) ---
101
+ Digit0: { key: "0", code: "Digit0", keyCode: 48 },
102
+ Digit1: { key: "1", code: "Digit1", keyCode: 49 },
103
+ Digit2: { key: "2", code: "Digit2", keyCode: 50 },
104
+ Digit3: { key: "3", code: "Digit3", keyCode: 51 },
105
+ Digit4: { key: "4", code: "Digit4", keyCode: 52 },
106
+ Digit5: { key: "5", code: "Digit5", keyCode: 53 },
107
+ Digit6: { key: "6", code: "Digit6", keyCode: 54 },
108
+ Digit7: { key: "7", code: "Digit7", keyCode: 55 },
109
+ Digit8: { key: "8", code: "Digit8", keyCode: 56 },
110
+ Digit9: { key: "9", code: "Digit9", keyCode: 57 },
111
+ // --- Alpha Keys A-Z (65-90) ---
112
+ KeyA: { key: "a", code: "KeyA", keyCode: 65 },
113
+ KeyB: { key: "b", code: "KeyB", keyCode: 66 },
114
+ KeyC: { key: "c", code: "KeyC", keyCode: 67 },
115
+ KeyD: { key: "d", code: "KeyD", keyCode: 68 },
116
+ KeyE: { key: "e", code: "KeyE", keyCode: 69 },
117
+ KeyF: { key: "f", code: "KeyF", keyCode: 70 },
118
+ KeyG: { key: "g", code: "KeyG", keyCode: 71 },
119
+ KeyH: { key: "h", code: "KeyH", keyCode: 72 },
120
+ KeyI: { key: "i", code: "KeyI", keyCode: 73 },
121
+ KeyJ: { key: "j", code: "KeyJ", keyCode: 74 },
122
+ KeyK: { key: "k", code: "KeyK", keyCode: 75 },
123
+ KeyL: { key: "l", code: "KeyL", keyCode: 76 },
124
+ KeyM: { key: "m", code: "KeyM", keyCode: 77 },
125
+ KeyN: { key: "n", code: "KeyN", keyCode: 78 },
126
+ KeyO: { key: "o", code: "KeyO", keyCode: 79 },
127
+ KeyP: { key: "p", code: "KeyP", keyCode: 80 },
128
+ KeyQ: { key: "q", code: "KeyQ", keyCode: 81 },
129
+ KeyR: { key: "r", code: "KeyR", keyCode: 82 },
130
+ KeyS: { key: "s", code: "KeyS", keyCode: 83 },
131
+ KeyT: { key: "t", code: "KeyT", keyCode: 84 },
132
+ KeyU: { key: "u", code: "KeyU", keyCode: 85 },
133
+ KeyV: { key: "v", code: "KeyV", keyCode: 86 },
134
+ KeyW: { key: "w", code: "KeyW", keyCode: 87 },
135
+ KeyX: { key: "x", code: "KeyX", keyCode: 88 },
136
+ KeyY: { key: "y", code: "KeyY", keyCode: 89 },
137
+ KeyZ: { key: "z", code: "KeyZ", keyCode: 90 },
138
+ // --- Meta & Menu (91-93) ---
139
+ MetaLeft: { key: "Meta", code: "MetaLeft", keyCode: 91 },
140
+ ContextMenu: { key: "ContextMenu", code: "ContextMenu", keyCode: 93 },
141
+ // --- Numpad Digits (96-105) ---
142
+ Numpad0: { key: "0", code: "Numpad0", keyCode: 96 },
143
+ Numpad1: { key: "1", code: "Numpad1", keyCode: 97 },
144
+ Numpad2: { key: "2", code: "Numpad2", keyCode: 98 },
145
+ Numpad3: { key: "3", code: "Numpad3", keyCode: 99 },
146
+ Numpad4: { key: "4", code: "Numpad4", keyCode: 100 },
147
+ Numpad5: { key: "5", code: "Numpad5", keyCode: 101 },
148
+ Numpad6: { key: "6", code: "Numpad6", keyCode: 102 },
149
+ Numpad7: { key: "7", code: "Numpad7", keyCode: 103 },
150
+ Numpad8: { key: "8", code: "Numpad8", keyCode: 104 },
151
+ Numpad9: { key: "9", code: "Numpad9", keyCode: 105 },
152
+ // --- Numpad Symbols (106-111) ---
153
+ NumpadMultiply: { key: "*", code: "NumpadMultiply", keyCode: 106 },
154
+ NumpadAdd: { key: "+", code: "NumpadAdd", keyCode: 107 },
155
+ NumpadSubtract: { key: "-", code: "NumpadSubtract", keyCode: 109 },
156
+ NumpadDecimal: { key: ".", code: "NumpadDecimal", keyCode: 110 },
157
+ NumpadDivide: { key: "/", code: "NumpadDivide", keyCode: 111 },
158
+ // --- Function Keys (112-123) ---
159
+ F1: { key: "F1", code: "F1", keyCode: 112 },
160
+ F2: { key: "F2", code: "F2", keyCode: 113 },
161
+ F3: { key: "F3", code: "F3", keyCode: 114 },
162
+ F4: { key: "F4", code: "F4", keyCode: 115 },
163
+ F5: { key: "F5", code: "F5", keyCode: 116 },
164
+ F6: { key: "F6", code: "F6", keyCode: 117 },
165
+ F7: { key: "F7", code: "F7", keyCode: 118 },
166
+ F8: { key: "F8", code: "F8", keyCode: 119 },
167
+ F9: { key: "F9", code: "F9", keyCode: 120 },
168
+ F10: { key: "F10", code: "F10", keyCode: 121 },
169
+ F11: { key: "F11", code: "F11", keyCode: 122 },
170
+ F12: { key: "F12", code: "F12", keyCode: 123 },
171
+ // --- State Locks (144-145) ---
172
+ NumLock: { key: "NumLock", code: "NumLock", keyCode: 144 },
173
+ ScrollLock: { key: "ScrollLock", code: "ScrollLock", keyCode: 145 },
174
+ // --- Punctuation (186-222) ---
175
+ Semicolon: { key: ";", code: "Semicolon", keyCode: 186 },
176
+ Equal: { key: "=", code: "Equal", keyCode: 187 },
177
+ Comma: { key: ",", code: "Comma", keyCode: 188 },
178
+ Minus: { key: "-", code: "Minus", keyCode: 189 },
179
+ Period: { key: ".", code: "Period", keyCode: 190 },
180
+ Slash: { key: "/", code: "Slash", keyCode: 191 },
181
+ Backquote: { key: "`", code: "Backquote", keyCode: 192 },
182
+ BracketLeft: { key: "[", code: "BracketLeft", keyCode: 219 },
183
+ Backslash: { key: "\\", code: "Backslash", keyCode: 220 },
184
+ BracketRight: { key: "]", code: "BracketRight", keyCode: 221 },
185
+ Quote: { key: "'", code: "Quote", keyCode: 222 }
186
+ };
187
+ var KEYS = STANDARD_KEYS;
188
+
189
+ // src/types/index.ts
190
+ var TYPES = {
191
+ // --- Zones ---
192
+ /** Area responsible for capturing touches and spawning dynamic widgets */
193
+ INPUT_ZONE: "input-zone",
194
+ /** Area responsible for receiving signals and simulating DOM events */
195
+ TARGET_ZONE: "target-zone",
196
+ // --- Widgets ---
197
+ /** Simulates a physical keyboard key press */
198
+ KEYBOARD_BUTTON: "keyboard-button",
199
+ /** Simulates a mouse button click/hold */
200
+ MOUSE_BUTTON: "mouse-button",
201
+ /** A joystick that outputs 360-degree or locked direction vectors */
202
+ ANALOG_STICK: "analog-stick",
203
+ /** Classic 4/8-way directional pad */
204
+ D_PAD: "d-pad",
205
+ /** Trackpad-style relative movement area */
206
+ TRACKPAD: "trackpad",
207
+ // --- Virtual Helpers ---
208
+ /** Logic for the on-screen visual cursor */
209
+ VIRTUAL_CURSOR: "virtual-cursor",
210
+ /** The top-level managed container */
211
+ ROOT_LAYER: "root-layer"
212
+ };
213
+ var ACTION_TYPES = {
214
+ KEYDOWN: "keydown",
215
+ KEYUP: "keyup",
216
+ POINTER: "pointer",
217
+ POINTERMOVE: "pointermove",
218
+ POINTERDOWN: "pointerdown",
219
+ POINTERUP: "pointerup",
220
+ MOUSE: "mouse",
221
+ MOUSEMOVE: "mousemove",
222
+ MOUSEDOWN: "mousedown",
223
+ MOUSEUP: "mouseup",
224
+ CLICK: "click"
225
+ };
226
+ var CONTEXT = {
227
+ /** The key used to propagate Parent IDs through the component tree */
228
+ PARENT_ID_KEY: "omnipad-parent-id-link"
229
+ };
230
+
231
+ // src/utils/math.ts
232
+ var subVec = (v1, v2) => {
233
+ return { x: v1.x - v2.x, y: v1.y - v2.y };
234
+ };
235
+ var addVec = (v1, v2) => {
236
+ return { x: v1.x + v2.x, y: v1.y + v2.y };
237
+ };
238
+ var scaleVec = (v, s) => {
239
+ return { x: v.x * s, y: v.y * s };
240
+ };
241
+ var clamp = (val, min, max) => {
242
+ return Math.max(min, Math.min(max, val));
243
+ };
244
+ var lerp = (start, end, t) => {
245
+ return start + (end - start) * t;
246
+ };
247
+ var roundTo = (val, precision = 2) => {
248
+ const m = Math.pow(10, precision);
249
+ return Math.round(val * m) / m;
250
+ };
251
+ var getDistance = (p1, p2) => {
252
+ return Math.hypot(p2.x - p1.x, p2.y - p1.y);
253
+ };
254
+ var getAngle = (p1, p2) => {
255
+ return Math.atan2(p2.y - p1.y, p2.x - p1.x);
256
+ };
257
+ var radToDeg = (rad) => {
258
+ return rad * 180 / Math.PI;
259
+ };
260
+ var degToRad = (deg) => {
261
+ return deg * Math.PI / 180;
262
+ };
263
+ var clampVector = (origin, target, radius) => {
264
+ const dx = target.x - origin.x;
265
+ const dy = target.y - origin.y;
266
+ const dist = Math.hypot(dx, dy);
267
+ if (dist <= radius) return target;
268
+ const angle = Math.atan2(dy, dx);
269
+ return {
270
+ x: origin.x + Math.cos(angle) * radius,
271
+ y: origin.y + Math.sin(angle) * radius
272
+ };
273
+ };
274
+ var lockTo8Directions = (rad) => {
275
+ const step = Math.PI / 4;
276
+ return Math.round(rad / step) * step;
277
+ };
278
+ var lockTo4Directions = (rad) => {
279
+ const step = Math.PI / 2;
280
+ return Math.round(rad / step) * step;
281
+ };
282
+ var percentToPx = (percent, totalPx) => {
283
+ return roundTo(percent * totalPx / 100);
284
+ };
285
+ var pxToPercent = (px, totalPx) => {
286
+ if (totalPx === 0) return 0;
287
+ return roundTo(px * 100 / totalPx);
288
+ };
289
+ var normalizeVec = (v) => {
290
+ const magnitude = Math.hypot(v.x, v.y);
291
+ return magnitude === 0 ? { x: 0, y: 0 } : { x: v.x / magnitude, y: v.y / magnitude };
292
+ };
293
+ var radToVec = (rad) => ({
294
+ x: Math.cos(rad),
295
+ y: Math.sin(rad)
296
+ });
297
+ var remap = (val, inMin, inMax, outMin, outMax) => {
298
+ const t = (val - inMin) / (inMax - inMin);
299
+ return lerp(outMin, outMax, clamp(t, 0, 1));
300
+ };
301
+ var isVec2Equal = (v1, v2, epsilon = 1e-4) => {
302
+ return Math.abs(v1.x - v2.x) < epsilon && Math.abs(v1.y - v2.y) < epsilon;
303
+ };
304
+ var getDeadzoneScalar = (magnitude, threshold, max) => {
305
+ if (magnitude < threshold) return 0;
306
+ const scalar = (magnitude - threshold) / (max - threshold);
307
+ return clamp(scalar, 0, 1);
308
+ };
309
+ var applyRadialDeadzone = (v, radius, deadzonePercent) => {
310
+ const magnitude = Math.hypot(v.x, v.y);
311
+ const threshold = radius * deadzonePercent;
312
+ const scalar = getDeadzoneScalar(magnitude, threshold, radius);
313
+ if (scalar === 0) return { x: 0, y: 0 };
314
+ const direction = { x: v.x / magnitude, y: v.y / magnitude };
315
+ return scaleVec(direction, scalar);
316
+ };
317
+ var applyAxialDeadzone = (v, threshold, max) => {
318
+ return {
319
+ x: getDeadzoneScalar(Math.abs(v.x), threshold, max) * Math.sign(v.x),
320
+ y: getDeadzoneScalar(Math.abs(v.y), threshold, max) * Math.sign(v.y)
321
+ };
322
+ };
323
+
324
+ // src/utils/dom.ts
325
+ var getDeepElement = (x, y) => {
326
+ let el = document.elementFromPoint(x, y);
327
+ while (el && el.shadowRoot) {
328
+ const nested = el.shadowRoot.elementFromPoint(x, y);
329
+ if (!nested || nested === el) break;
330
+ el = nested;
331
+ }
332
+ return el;
333
+ };
334
+ var getDeepActiveElement = () => {
335
+ let el = document.activeElement;
336
+ while (el && el.shadowRoot && el.shadowRoot.activeElement) {
337
+ el = el.shadowRoot.activeElement;
338
+ }
339
+ return el;
340
+ };
341
+ var focusElement = (el) => {
342
+ if (getDeepActiveElement() === el) return;
343
+ if (!el.hasAttribute("tabindex")) {
344
+ el.setAttribute("tabindex", "-1");
345
+ }
346
+ el.focus();
347
+ };
348
+ var dispatchKeyboardEvent = (type, payload) => {
349
+ const ev = new KeyboardEvent(type, {
350
+ ...payload,
351
+ which: payload.keyCode,
352
+ // Support for legacy Flash engines
353
+ bubbles: true,
354
+ cancelable: true,
355
+ view: window
356
+ });
357
+ window.dispatchEvent(ev);
358
+ };
359
+ var dispatchPointerEventAtPos = (type, x, y, opts = {}) => {
360
+ const target = getDeepElement(x, y);
361
+ if (!target) return;
362
+ const commonProps = {
363
+ bubbles: true,
364
+ cancelable: true,
365
+ composed: true,
366
+ // Crucial for piercing Shadow DOM boundaries
367
+ clientX: x,
368
+ clientY: y,
369
+ view: window,
370
+ ...opts
371
+ };
372
+ if (type.startsWith("pointer")) {
373
+ target.dispatchEvent(
374
+ new PointerEvent(type, {
375
+ isPrimary: true,
376
+ pointerId: 1,
377
+ pointerType: "mouse",
378
+ // Emulate mouse behavior for Flash MouseOver/Down logic
379
+ ...commonProps
380
+ })
381
+ );
382
+ const mouseType = type.replace("pointer", "mouse");
383
+ target.dispatchEvent(new MouseEvent(mouseType, commonProps));
384
+ } else {
385
+ target.dispatchEvent(new MouseEvent(type, commonProps));
386
+ }
387
+ };
388
+ var getAnchorPosition = (rect, anchor) => {
389
+ const { left: l, top: t, width: w, height: h } = rect;
390
+ const map = {
391
+ "top-left": { x: l, y: t },
392
+ "top-center": { x: l + w / 2, y: t },
393
+ "top-right": { x: l + w, y: t },
394
+ "center-left": { x: l, y: t + h / 2 },
395
+ center: { x: l + w / 2, y: t + h / 2 },
396
+ "center-right": { x: l + w, y: t + h / 2 },
397
+ "bottom-left": { x: l, y: t + h },
398
+ "bottom-center": { x: l + w / 2, y: t + h },
399
+ "bottom-right": { x: l + w, y: t + h }
400
+ };
401
+ return map[anchor] || map["center"];
402
+ };
403
+
404
+ // src/utils/id.ts
405
+ var generateUID = (prefix = "omnipad") => {
406
+ const stamp = Date.now().toString(36);
407
+ const random = Math.random().toString(36).substring(2, 6);
408
+ return `${prefix}-${stamp}-${random}`;
409
+ };
410
+ function isGlobalID(id) {
411
+ return id.startsWith("$");
412
+ }
413
+
414
+ // src/utils/layout.ts
415
+ var resolveLayoutStyle = (layout) => {
416
+ if (!layout) return {};
417
+ const style = {};
418
+ style.position = "absolute";
419
+ const fields = ["left", "top", "right", "bottom", "width", "height"];
420
+ fields.forEach((field) => {
421
+ const val = layout[field];
422
+ if (val !== void 0) {
423
+ style[field] = typeof val === "number" ? `${val}px` : val;
424
+ }
425
+ });
426
+ if (layout.zIndex !== void 0) style.zIndex = layout.zIndex;
427
+ const anchorMap = {
428
+ "top-left": "translate(0, 0)",
429
+ "top-center": "translate(-50%, 0)",
430
+ "top-right": "translate(-100%, 0)",
431
+ "center-left": "translate(0, -50%)",
432
+ center: "translate(-50%, -50%)",
433
+ "center-right": "translate(-100%, -50%)",
434
+ "bottom-left": "translate(0, -100%)",
435
+ "bottom-center": "translate(-50%, -100%)",
436
+ "bottom-right": "translate(-100%, -100%)"
437
+ };
438
+ if (layout.anchor) {
439
+ style.transform = anchorMap[layout.anchor];
440
+ }
441
+ return style;
442
+ };
443
+
444
+ // src/utils/emitter.ts
445
+ var SimpleEmitter = class {
446
+ constructor() {
447
+ __publicField(this, "listeners", /* @__PURE__ */ new Set());
448
+ }
449
+ /**
450
+ * Registers a callback function to be executed whenever data is emitted.
451
+ *
452
+ * @param fn - The callback function.
453
+ * @returns A function that, when called, unsubscribes the listener.
454
+ */
455
+ subscribe(fn) {
456
+ this.listeners.add(fn);
457
+ return () => this.listeners.delete(fn);
458
+ }
459
+ /**
460
+ * Broadcasts the provided data to all registered listeners.
461
+ * Each listener is executed within a try-catch block to ensure that
462
+ * an error in one subscriber doesn't prevent others from receiving the signal.
463
+ *
464
+ * @param data - The payload to be sent to all subscribers.
465
+ */
466
+ emit(data) {
467
+ this.listeners.forEach((fn) => {
468
+ try {
469
+ fn(data);
470
+ } catch (error) {
471
+ console.error("[OmniPad-Core] Emitter callback error:", error);
472
+ }
473
+ });
474
+ }
475
+ /**
476
+ * Removes all listeners and clears the subscription set.
477
+ * Essential for preventing memory leaks when an Entity is destroyed.
478
+ */
479
+ clear() {
480
+ this.listeners.clear();
481
+ }
482
+ };
483
+
484
+ // src/entities/BaseEntity.ts
485
+ var BaseEntity = class {
486
+ constructor(uid, type, initialConfig, initialState) {
487
+ __publicField(this, "uid");
488
+ __publicField(this, "type");
489
+ __publicField(this, "config");
490
+ __publicField(this, "state");
491
+ __publicField(this, "rect", null);
492
+ // 内部状态发射器,负责处理状态订阅逻辑 / Internal emitter for state subscription logic
493
+ __publicField(this, "stateEmitter", new SimpleEmitter());
494
+ this.uid = uid;
495
+ this.type = type;
496
+ this.config = initialConfig;
497
+ this.state = initialState;
498
+ }
499
+ // --- IObservable Implementation ---
500
+ subscribe(cb) {
501
+ cb(this.state);
502
+ return this.stateEmitter.subscribe(cb);
503
+ }
504
+ // --- State Management ---
505
+ /**
506
+ * Updates the internal state and notifies all subscribers.
507
+ *
508
+ * @param partialState - Partial object containing updated state values.
509
+ */
510
+ setState(partialState) {
511
+ this.state = { ...this.state, ...partialState };
512
+ this.stateEmitter.emit(this.state);
513
+ }
514
+ // --- Lifecycle ---
515
+ destroy() {
516
+ this.reset();
517
+ this.stateEmitter.clear();
518
+ Registry.getInstance().unregister(this.uid);
519
+ }
520
+ updateRect(rect) {
521
+ this.rect = rect;
522
+ }
523
+ updateConfig(newConfig) {
524
+ this.config = { ...this.config, ...newConfig };
525
+ this.stateEmitter.emit(this.state);
526
+ }
527
+ getState() {
528
+ return this.state;
529
+ }
530
+ getConfig() {
531
+ return this.config;
532
+ }
533
+ };
534
+
535
+ // src/registry/index.ts
536
+ var import_meta = {};
537
+ var GLOBAL_REGISTRY_KEY = /* @__PURE__ */ Symbol.for("omnipad.registry.instance");
538
+ var Registry = class _Registry {
539
+ /**
540
+ * Private constructor to enforce singleton pattern.
541
+ */
542
+ constructor() {
543
+ /** Internal storage: Mapping of Entity UID to Entity Instance */
544
+ __publicField(this, "entities", /* @__PURE__ */ new Map());
545
+ if (import_meta.env?.DEV) {
546
+ console.log("[OmniPad-Core] Registry initialized.");
547
+ }
548
+ }
549
+ /**
550
+ * Retrieves the global instance of the Registry.
551
+ * Uses globalThis to ensure the instance is unique even if the library is loaded multiple times.
552
+ */
553
+ static getInstance() {
554
+ const globalObj = globalThis;
555
+ if (!globalObj[GLOBAL_REGISTRY_KEY]) {
556
+ globalObj[GLOBAL_REGISTRY_KEY] = new _Registry();
557
+ }
558
+ return globalObj[GLOBAL_REGISTRY_KEY];
559
+ }
560
+ register(entity) {
561
+ if (!entity.uid) {
562
+ console.warn("[OmniPad-Core] Registry: Attempted to register entity without UID.", entity);
563
+ return;
564
+ }
565
+ if (this.entities.has(entity.uid)) {
566
+ }
567
+ this.entities.set(entity.uid, entity);
568
+ }
569
+ unregister(uid) {
570
+ if (this.entities.has(uid)) {
571
+ this.entities.delete(uid);
572
+ }
573
+ }
574
+ getEntity(uid) {
575
+ return this.entities.get(uid);
576
+ }
577
+ getAllEntities() {
578
+ return Array.from(this.entities.values());
579
+ }
580
+ getEntitiesByRoot(rootUid) {
581
+ const all = this.getAllEntities();
582
+ if (!rootUid) return all;
583
+ const rootEntity = this.entities.get(rootUid);
584
+ if (!rootEntity) {
585
+ console.warn(`[OmniPad-Core] Registry: Root entity ${rootUid} not found.`);
586
+ return [];
587
+ }
588
+ const parentMap = /* @__PURE__ */ new Map();
589
+ all.forEach((entity) => {
590
+ if (entity instanceof BaseEntity) {
591
+ const config = entity.getConfig();
592
+ if (config.parentId) {
593
+ if (!parentMap.has(config.parentId)) {
594
+ parentMap.set(config.parentId, []);
595
+ }
596
+ parentMap.get(config.parentId).push(entity);
597
+ }
598
+ }
599
+ });
600
+ const result = [];
601
+ const queue = [rootUid];
602
+ const visited = /* @__PURE__ */ new Set();
603
+ while (queue.length > 0) {
604
+ const currentId = queue.shift();
605
+ if (visited.has(currentId)) continue;
606
+ visited.add(currentId);
607
+ const entity = this.entities.get(currentId);
608
+ if (entity) {
609
+ result.push(entity);
610
+ const children = parentMap.get(currentId);
611
+ if (children) {
612
+ children.forEach((child) => queue.push(child.uid));
613
+ }
614
+ }
615
+ }
616
+ return result;
617
+ }
618
+ destroyByRoot(rootUid) {
619
+ const entities = this.getEntitiesByRoot(rootUid);
620
+ for (let i = entities.length - 1; i >= 0; i--) {
621
+ const entity = entities[i];
622
+ try {
623
+ entity.destroy();
624
+ } catch (error) {
625
+ console.error(`[OmniPad-Core] Error during destroyByRoot at ${entity.uid}:`, error);
626
+ }
627
+ }
628
+ }
629
+ clear() {
630
+ this.entities.clear();
631
+ }
632
+ resetAll() {
633
+ this.entities.forEach((entity) => {
634
+ if ("reset" in entity) {
635
+ entity.reset();
636
+ }
637
+ });
638
+ }
639
+ debugGetSnapshot() {
640
+ return new Map(this.entities);
641
+ }
642
+ };
643
+
644
+ // src/utils/profile.ts
645
+ function parseProfileJson(raw) {
646
+ if (!raw || typeof raw !== "object") {
647
+ throw new Error("[OmniPad-Validation] Profile must be a valid JSON object.");
648
+ }
649
+ if (!raw.rootId) {
650
+ throw new Error('[OmniPad-Validation] Missing "rootId" in profile.');
651
+ }
652
+ if (!Array.isArray(raw.items)) {
653
+ throw new Error('[OmniPad-Validation] "items" must be an array.');
654
+ }
655
+ const meta = {
656
+ name: raw.meta?.name || "Untitled Profile",
657
+ version: raw.meta?.version || "1.0.0",
658
+ author: raw.meta?.author || "Unknown"
659
+ };
660
+ const items = raw.items.map((item, index) => {
661
+ if (!item.id || !item.type) {
662
+ throw new Error(`[OmniPad-Validation] Item at index ${index} is missing "id" or "type".`);
663
+ }
664
+ return {
665
+ id: String(item.id),
666
+ type: String(item.type),
667
+ parentId: item.parentId ? String(item.parentId) : void 0,
668
+ // 确保 config 存在,业务参数平铺于此
669
+ config: item.config || {}
670
+ };
671
+ });
672
+ return {
673
+ meta,
674
+ rootId: String(raw.rootId),
675
+ items
676
+ };
677
+ }
678
+ function parseProfileTree(profile) {
679
+ const { items, rootId } = profile;
680
+ const cidToUidMap = /* @__PURE__ */ new Map();
681
+ const getUid = (cid, type = "node") => {
682
+ if (isGlobalID(cid)) return cid;
683
+ if (!cidToUidMap.has(cid)) {
684
+ cidToUidMap.set(cid, generateUID(type));
685
+ }
686
+ return cidToUidMap.get(cid);
687
+ };
688
+ items.forEach((item) => getUid(item.id, item.type));
689
+ const childrenMap = /* @__PURE__ */ new Map();
690
+ items.forEach((item) => {
691
+ if (item.parentId) {
692
+ if (!childrenMap.has(item.parentId)) {
693
+ childrenMap.set(item.parentId, []);
694
+ }
695
+ childrenMap.get(item.parentId).push(item);
696
+ }
697
+ });
698
+ const buildNode = (item) => {
699
+ const runtimeConfig = { ...item.config };
700
+ if (runtimeConfig?.targetStageId) {
701
+ runtimeConfig.targetStageId = getUid(runtimeConfig.targetStageId);
702
+ }
703
+ if (runtimeConfig?.dynamicWidgetId) {
704
+ runtimeConfig.dynamicWidgetId = getUid(runtimeConfig.dynamicWidgetId);
705
+ }
706
+ const rawChildren = childrenMap.get(item.id) || [];
707
+ const children = rawChildren.map((child) => buildNode(child));
708
+ return {
709
+ uid: getUid(item.id),
710
+ type: item.type,
711
+ config: runtimeConfig,
712
+ children
713
+ };
714
+ };
715
+ const rootItem = items.find((i) => i.id === rootId);
716
+ if (!rootItem) {
717
+ throw new Error(`[OmniPad-Core] Root item with ID "${rootId}" not found in profile.`);
718
+ }
719
+ return buildNode(rootItem);
720
+ }
721
+ function exportProfile(meta, rootUid) {
722
+ const registry = Registry.getInstance();
723
+ const allEntities = registry.getEntitiesByRoot(rootUid);
724
+ const eidToCidMap = /* @__PURE__ */ new Map();
725
+ let cidCounter = 0;
726
+ const getNewCid = (eid) => {
727
+ if (isGlobalID(eid)) return eid;
728
+ if (!eidToCidMap.has(eid)) {
729
+ eidToCidMap.set(eid, `node_${++cidCounter}`);
730
+ }
731
+ return eidToCidMap.get(eid);
732
+ };
733
+ const items = allEntities.map((entity) => {
734
+ const config = entity.getConfig();
735
+ const currentEid = entity.uid;
736
+ const processedConfig = { ...config };
737
+ if (processedConfig.targetStageId) {
738
+ processedConfig.targetStageId = getNewCid(processedConfig.targetStageId);
739
+ }
740
+ if (processedConfig.dynamicWidgetId) {
741
+ processedConfig.dynamicWidgetId = getNewCid(processedConfig.dynamicWidgetId);
742
+ }
743
+ const { id, type, parentId, ...cleanConfig } = processedConfig;
744
+ return {
745
+ id: getNewCid(currentEid),
746
+ type: entity.type,
747
+ // 如果存在父级,将其 UID 转换回本次导出的新 CID
748
+ parentId: config.parentId ? getNewCid(config.parentId) : void 0,
749
+ config: cleanConfig
750
+ };
751
+ });
752
+ return {
753
+ meta,
754
+ rootId: getNewCid(rootUid),
755
+ items
756
+ };
757
+ }
758
+
759
+ // src/imputManager/index.ts
760
+ var import_meta2 = {};
761
+ var INPUT_MANAGER_KEY = /* @__PURE__ */ Symbol.for("omnipad.input_manager.instance");
762
+ var InputManager = class _InputManager {
763
+ constructor() {
764
+ /** Internal flag to prevent multiple event registrations */
765
+ __publicField(this, "_isListening", false);
766
+ /**
767
+ * Manually triggers a system-wide input reset via Registry.
768
+ */
769
+ __publicField(this, "handleGlobalReset", () => {
770
+ if (import_meta2.env?.DEV) {
771
+ console.debug("[OmniPad-Core] Safety reset triggered by environment change.");
772
+ }
773
+ Registry.getInstance().resetAll();
774
+ });
775
+ }
776
+ /**
777
+ * Retrieves the global instance of the InputManager.
778
+ * Ensures uniqueness across multiple bundles or modules.
779
+ */
780
+ static getInstance() {
781
+ const globalObj = globalThis;
782
+ if (!globalObj[INPUT_MANAGER_KEY]) {
783
+ globalObj[INPUT_MANAGER_KEY] = new _InputManager();
784
+ }
785
+ return globalObj[INPUT_MANAGER_KEY];
786
+ }
787
+ /**
788
+ * Initializes global safety listeners.
789
+ * Should be called once at the root component lifecycle (e.g., VirtualLayer).
790
+ */
791
+ init() {
792
+ if (this._isListening) return;
793
+ window.addEventListener("resize", this.handleGlobalReset);
794
+ window.addEventListener("blur", this.handleGlobalReset);
795
+ this._isListening = true;
796
+ if (import_meta2.env?.DEV) {
797
+ console.log("[OmniPad-Core] Global InputManager monitoring started.");
798
+ }
799
+ }
800
+ /**
801
+ * Toggle full-screen state of the page.
802
+ * @param element Target HTMLElement
803
+ */
804
+ async toggleFullscreen(element) {
805
+ const target = element || document.documentElement;
806
+ try {
807
+ if (!document.fullscreenElement) {
808
+ Registry.getInstance().resetAll();
809
+ await target.requestFullscreen();
810
+ } else {
811
+ Registry.getInstance().resetAll();
812
+ await document.exitFullscreen();
813
+ }
814
+ } catch (err) {
815
+ console.error(`[OmniPad-Core] Fullscreen toggle failed:`, err);
816
+ }
817
+ }
818
+ /**
819
+ * Full-screen status query provided to the UI layer.
820
+ */
821
+ isFullscreen() {
822
+ return !!document.fullscreenElement;
823
+ }
824
+ /**
825
+ * Detaches all global listeners.
826
+ */
827
+ destroy() {
828
+ window.removeEventListener("resize", this.handleGlobalReset);
829
+ window.removeEventListener("blur", this.handleGlobalReset);
830
+ this._isListening = false;
831
+ }
832
+ };
833
+
834
+ // src/entities/InputZoneCore.ts
835
+ var INITIAL_STATE = {
836
+ isDynamicActive: false,
837
+ dynamicPointerId: null,
838
+ dynamicPosition: { x: 0, y: 0 }
839
+ };
840
+ var InputZoneCore = class extends BaseEntity {
841
+ constructor(uid, config) {
842
+ super(uid, TYPES.INPUT_ZONE, config, INITIAL_STATE);
843
+ }
844
+ onPointerDown(e) {
845
+ if (this.state.isDynamicActive) return;
846
+ if (e.target !== e.currentTarget) return;
847
+ if (e.cancelable) e.preventDefault();
848
+ const pos = this.calculateRelativePosition(e.clientX, e.clientY);
849
+ this.setState({
850
+ isDynamicActive: true,
851
+ dynamicPointerId: e.pointerId,
852
+ dynamicPosition: pos
853
+ });
854
+ }
855
+ onPointerMove(e) {
856
+ if (!this.state.isDynamicActive || e.pointerId !== this.state.dynamicPointerId) return;
857
+ }
858
+ onPointerUp(e) {
859
+ this.handleRelease(e);
860
+ }
861
+ onPointerCancel(e) {
862
+ this.handleRelease(e);
863
+ }
864
+ /**
865
+ * Internal helper to handle pointer release and cleanup.
866
+ */
867
+ handleRelease(e) {
868
+ if (e.pointerId === this.state.dynamicPointerId) {
869
+ try {
870
+ e.currentTarget.releasePointerCapture(e.pointerId);
871
+ } catch (err) {
872
+ }
873
+ this.setState({
874
+ isDynamicActive: false,
875
+ dynamicPointerId: null
876
+ });
877
+ }
878
+ }
879
+ // --- Helper Calculations ---
880
+ /**
881
+ * Converts viewport pixels to percentage coordinates relative to the zone.
882
+ */
883
+ calculateRelativePosition(clientX, clientY) {
884
+ if (!this.rect) return { x: 0, y: 0 };
885
+ return {
886
+ x: pxToPercent(clientX - this.rect.left, this.rect.width),
887
+ y: pxToPercent(clientY - this.rect.top, this.rect.height)
888
+ };
889
+ }
890
+ /**
891
+ * Whether the interceptor layer should be enabled.
892
+ */
893
+ get isInterceptorRequired() {
894
+ return !!(this.config.dynamicWidgetId || this.config.preventFocusLoss);
895
+ }
896
+ reset() {
897
+ this.setState({
898
+ isDynamicActive: false,
899
+ dynamicPointerId: null
900
+ });
901
+ }
902
+ };
903
+
904
+ // src/entities/KeyboardButtonCore.ts
905
+ var import_meta3 = {};
906
+ var INITIAL_STATE2 = {
907
+ isActive: false,
908
+ isPressed: false,
909
+ pointerId: null,
910
+ value: 0
911
+ };
912
+ var KeyboardButtonCore = class extends BaseEntity {
913
+ /**
914
+ * Creates an instance of KeyboardButtonCore.
915
+ *
916
+ * @param uid - The unique entity ID.
917
+ * @param config - The flat configuration object for the button.
918
+ */
919
+ constructor(uid, config) {
920
+ super(uid, TYPES.KEYBOARD_BUTTON, config, INITIAL_STATE2);
921
+ }
922
+ // --- IPointerHandler Implementation ---
923
+ onPointerDown(e) {
924
+ if (e.cancelable) e.preventDefault();
925
+ e.target.setPointerCapture(e.pointerId);
926
+ this.setState({
927
+ isActive: true,
928
+ isPressed: true,
929
+ pointerId: e.pointerId
930
+ });
931
+ this.sendInputSignal(ACTION_TYPES.KEYDOWN);
932
+ }
933
+ onPointerUp(e) {
934
+ if (e.cancelable) e.preventDefault();
935
+ this.handleRelease(e);
936
+ }
937
+ onPointerCancel(e) {
938
+ this.handleRelease(e);
939
+ }
940
+ onPointerMove(e) {
941
+ if (e.cancelable) e.preventDefault();
942
+ }
943
+ // --- Internal Logic ---
944
+ /**
945
+ * Common logic for releasing the button state.
946
+ *
947
+ * @param e - The pointer event that triggered the release.
948
+ */
949
+ handleRelease(e) {
950
+ if (this.state.pointerId !== e.pointerId) return;
951
+ if (e.target.hasPointerCapture(e.pointerId)) {
952
+ e.target.releasePointerCapture(e.pointerId);
953
+ }
954
+ this.setState(INITIAL_STATE2);
955
+ this.sendInputSignal(ACTION_TYPES.KEYUP);
956
+ }
957
+ /**
958
+ * Dispatches input signals to the registered target stage.
959
+ *
960
+ * @param type - The action type (keydown or keyup).
961
+ */
962
+ sendInputSignal(type) {
963
+ const targetId = this.config.targetStageId;
964
+ if (!targetId) return;
965
+ const target = Registry.getInstance().getEntity(targetId);
966
+ if (target && typeof target.handleSignal === "function") {
967
+ const signal = {
968
+ targetStageId: targetId,
969
+ type,
970
+ payload: {
971
+ key: this.config.mapping.key,
972
+ code: this.config.mapping.code,
973
+ keyCode: this.config.mapping.keyCode
974
+ }
975
+ };
976
+ target.handleSignal(signal);
977
+ } else {
978
+ if (import_meta3.env?.DEV) {
979
+ console.warn(`[OmniPad-Core] Button ${this.uid} target not found: ${targetId}`);
980
+ }
981
+ }
982
+ }
983
+ // --- IResettable Implementation ---
984
+ reset() {
985
+ if (this.state.isPressed) {
986
+ this.sendInputSignal(ACTION_TYPES.KEYUP);
987
+ }
988
+ this.setState(INITIAL_STATE2);
989
+ }
990
+ };
991
+
992
+ // src/entities/RootLayerCore.ts
993
+ var INITIAL_STATE3 = {
994
+ isHighlighted: false
995
+ };
996
+ var RootLayerCore = class extends BaseEntity {
997
+ constructor(uid, config) {
998
+ super(uid, TYPES.ROOT_LAYER, config, INITIAL_STATE3);
999
+ }
1000
+ reset() {
1001
+ }
1002
+ };
1003
+
1004
+ // src/entities/TargetZoneCore.ts
1005
+ var INITIAL_STATE4 = {
1006
+ position: { x: 50, y: 50 },
1007
+ isVisible: false,
1008
+ isPointerDown: false,
1009
+ isFocusReturning: false
1010
+ };
1011
+ var TargetZoneCore = class extends BaseEntity {
1012
+ constructor(uid, config) {
1013
+ super(uid, TYPES.TARGET_ZONE, config, INITIAL_STATE4);
1014
+ __publicField(this, "hideTimer", null);
1015
+ __publicField(this, "focusFeedbackTimer", null);
1016
+ }
1017
+ // --- ISignalReceiver Implementation ---
1018
+ handleSignal(signal) {
1019
+ const { type, payload } = signal;
1020
+ this.ensureFocus();
1021
+ switch (type) {
1022
+ case ACTION_TYPES.KEYDOWN:
1023
+ case ACTION_TYPES.KEYUP:
1024
+ dispatchKeyboardEvent(type, payload);
1025
+ break;
1026
+ case ACTION_TYPES.MOUSEMOVE:
1027
+ if (payload.point) {
1028
+ this.updateCursorPosition(payload.point);
1029
+ if (this.config.cursorEnabled) this.showCursor();
1030
+ this.executeMouseAction(ACTION_TYPES.POINTERMOVE, payload);
1031
+ }
1032
+ break;
1033
+ case ACTION_TYPES.MOUSEDOWN:
1034
+ case ACTION_TYPES.MOUSEUP:
1035
+ case ACTION_TYPES.CLICK:
1036
+ if (this.config.cursorEnabled) this.showCursor();
1037
+ this.executeMouseAction(
1038
+ type.startsWith(ACTION_TYPES.MOUSE) ? type.replace(ACTION_TYPES.MOUSE, ACTION_TYPES.POINTER) : type,
1039
+ payload
1040
+ );
1041
+ break;
1042
+ }
1043
+ }
1044
+ // --- Mouse & Pointer Simulation ---
1045
+ /**
1046
+ * Calculates pixel coordinates and dispatches simulated pointer events to the deepest element.
1047
+ *
1048
+ * @param pointerType - The specific pointer event type (e.g., pointermove, pointerdown).
1049
+ * @param payload - Data containing point coordinates or button info.
1050
+ */
1051
+ executeMouseAction(pointerType, payload) {
1052
+ if (!this.rect) return;
1053
+ if (pointerType === ACTION_TYPES.POINTERDOWN) this.setState({ isPointerDown: true });
1054
+ if (pointerType === ACTION_TYPES.POINTERUP) this.setState({ isPointerDown: false });
1055
+ const target = payload.point || this.state.position;
1056
+ const px = this.rect.left + percentToPx(target.x, this.rect.width);
1057
+ const py = this.rect.top + percentToPx(target.y, this.rect.height);
1058
+ dispatchPointerEventAtPos(pointerType, px, py, {
1059
+ button: payload.button ?? 0,
1060
+ buttons: this.state.isPointerDown ? 1 : 0
1061
+ });
1062
+ }
1063
+ // --- Focus Management ---
1064
+ /**
1065
+ * Checks if the target element under the virtual cursor has focus, and reclaims it if lost.
1066
+ */
1067
+ ensureFocus() {
1068
+ if (!this.rect) return;
1069
+ const px = this.rect.left + percentToPx(this.state.position.x, this.rect.width);
1070
+ const py = this.rect.top + percentToPx(this.state.position.y, this.rect.height);
1071
+ const target = getDeepElement(px, py);
1072
+ if (!target) return;
1073
+ if (getDeepActiveElement() !== target) {
1074
+ focusElement(target);
1075
+ this.triggerFocusFeedback();
1076
+ }
1077
+ }
1078
+ /**
1079
+ * Activates a temporary visual feedback state to indicate a focus-reclaim event.
1080
+ */
1081
+ triggerFocusFeedback() {
1082
+ this.setState({ isFocusReturning: true });
1083
+ if (this.focusFeedbackTimer) clearTimeout(this.focusFeedbackTimer);
1084
+ this.focusFeedbackTimer = setTimeout(() => this.setState({ isFocusReturning: false }), 500);
1085
+ }
1086
+ // --- Cursor State Helpers ---
1087
+ /**
1088
+ * Updates the internal virtual cursor coordinates.
1089
+ */
1090
+ updateCursorPosition(point) {
1091
+ this.setState({ position: { ...point } });
1092
+ }
1093
+ /**
1094
+ * Makes the virtual cursor visible and sets a timeout for auto-hiding.
1095
+ */
1096
+ showCursor() {
1097
+ this.setState({ isVisible: true });
1098
+ if (this.hideTimer) clearTimeout(this.hideTimer);
1099
+ if (this.config.cursorAutoDelay && this.config.cursorAutoDelay > 0) {
1100
+ this.hideTimer = setTimeout(
1101
+ () => this.setState({ isVisible: false }),
1102
+ this.config.cursorAutoDelay
1103
+ );
1104
+ }
1105
+ }
1106
+ // --- IResettable Implementation ---
1107
+ reset() {
1108
+ if (this.state.isPointerDown) {
1109
+ this.executeMouseAction(ACTION_TYPES.POINTERUP, {});
1110
+ }
1111
+ if (this.hideTimer) clearTimeout(this.hideTimer);
1112
+ if (this.focusFeedbackTimer) clearTimeout(this.focusFeedbackTimer);
1113
+ this.setState({
1114
+ isVisible: false,
1115
+ isPointerDown: false,
1116
+ isFocusReturning: false
1117
+ });
1118
+ }
1119
+ };
1120
+
1121
+ // src/index.ts
1122
+ var OmniPad = {
1123
+ Context: CONTEXT,
1124
+ Keys: KEYS,
1125
+ Types: TYPES
1126
+ };
1127
+ // Annotate the CommonJS export names for ESM import in node:
1128
+ 0 && (module.exports = {
1129
+ ACTION_TYPES,
1130
+ BaseEntity,
1131
+ CONTEXT,
1132
+ InputManager,
1133
+ InputZoneCore,
1134
+ KEYS,
1135
+ KeyboardButtonCore,
1136
+ OmniPad,
1137
+ Registry,
1138
+ RootLayerCore,
1139
+ SimpleEmitter,
1140
+ TYPES,
1141
+ TargetZoneCore,
1142
+ addVec,
1143
+ applyAxialDeadzone,
1144
+ applyRadialDeadzone,
1145
+ clamp,
1146
+ clampVector,
1147
+ degToRad,
1148
+ dispatchKeyboardEvent,
1149
+ dispatchPointerEventAtPos,
1150
+ exportProfile,
1151
+ focusElement,
1152
+ generateUID,
1153
+ getAnchorPosition,
1154
+ getAngle,
1155
+ getDeadzoneScalar,
1156
+ getDeepActiveElement,
1157
+ getDeepElement,
1158
+ getDistance,
1159
+ isGlobalID,
1160
+ isVec2Equal,
1161
+ lerp,
1162
+ lockTo4Directions,
1163
+ lockTo8Directions,
1164
+ normalizeVec,
1165
+ parseProfileJson,
1166
+ parseProfileTree,
1167
+ percentToPx,
1168
+ pxToPercent,
1169
+ radToDeg,
1170
+ radToVec,
1171
+ remap,
1172
+ resolveLayoutStyle,
1173
+ roundTo,
1174
+ scaleVec,
1175
+ subVec
1176
+ });