@omnipad/core 0.4.5 → 0.6.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.
@@ -1,21 +1,27 @@
1
- import { f as IPointerHandler, P as ParsedLength, N as LayoutBox, V as Vec2, v as ConfigTreeNode, G as GamepadMappingConfig, y as GamepadProfile } from '../index-CT1fDlB9.js';
1
+ import { c as AbstractPointerEvent, a as AbstractRect, L as LayoutBox, P as ParsedLength, o as FlexibleLength, V as Vec2 } from '../index-Dd0aHJaA.js';
2
2
 
3
3
  /**
4
4
  * Creates a provider wrapper that caches the result of a value-producing function.
5
- * * This utility implements a lazy-loading pattern with manual invalidation. The
5
+ *
6
+ * This utility implements a lazy-loading pattern with manual invalidation. The
6
7
  * provided function is only executed when the cache is "dirty" or empty,
7
8
  * ensuring expensive operations aren't repeated unnecessarily.
8
- * * @template T - The type of the value returned by the provider.
9
+ *
10
+ * @template T - The type of the value returned by the provider.
9
11
  * @param provider - A function that computes or retrieves the value to be cached.
10
12
  * @returns An object containing methods to access the value and invalidate the cache.
11
- * * @example
13
+ *
14
+ * @example
12
15
  * ```typescript
13
16
  * const userProvider = createCachedProvider(() => fetchUserData());
14
- * * // First call executes the provider
17
+ *
18
+ * // First call executes the provider
15
19
  * const data = userProvider.get();
16
- * * // Subsequent calls return the cached version
20
+ *
21
+ * // Subsequent calls return the cached version
17
22
  * const cachedData = userProvider.get();
18
- * * // Forces the provider to re-run on the next .get()
23
+ *
24
+ * // Forces the provider to re-run on the next .get()
19
25
  * userProvider.markDirty();
20
26
  * ```
21
27
  */
@@ -25,142 +31,39 @@ declare function createCachedProvider<T>(provider: () => T): {
25
31
  };
26
32
 
27
33
  /**
28
- * Compares two objects and extracts the properties that have changed.
29
- *
30
- * This function performs a shallow comparison of keys. For nested objects,
31
- * it performs a structural check to determine if
32
- * the contents have changed.
33
- *
34
- * @param oldObj - The previous state or snapshot of the object.
35
- * @param newObj - The new state of the object to compare against the old one.
36
- * @returns A partial record containing only the key-value pairs that differ from the original.
37
- */
38
- declare function getObjectDiff(oldObj: any, newObj: any): Record<string, any>;
39
-
40
- /**
41
- * Recursively penetrates Shadow DOM boundaries to find the deepest element at the
42
- * specified viewport coordinates.
34
+ * Distills a raw Rect-like object into a clean AbstractRect.
35
+ * Useful for converting live DOMRects into serialization-friendly POJOs.
43
36
  *
44
- * @param x - Viewport X coordinate (px)
45
- * @param y - Viewport Y coordinate (px)
46
- * @param ignoreClass - Style class of DOM elements to be ignored
47
- * @returns The deepmost Element or null if none found at the position.
37
+ * @param raw - Any object containing left, right, top, bottom, width, and height.
38
+ * @returns A sanitized AbstractRect object.
48
39
  */
49
- declare const getDeepElement: (x: number, y: number, ignoreClass?: string) => Element | null;
40
+ declare const distillRect: (raw: any) => AbstractRect;
50
41
  /**
51
- * Recursively finds the truly focused element by traversing Shadow DOM boundaries.
42
+ * Distills a PointerEvent-like object into a clean AbstractPointerEvent.
43
+ * Essential for stripping away heavy browser references before cross-origin postMessage transmission.
52
44
  *
53
- * @returns The deepmost active Element in focus or null.
45
+ * @param raw - Any object containing pointerId, clientX, clientY, and button.
46
+ * @returns A sanitized AbstractPointerEvent object.
54
47
  */
55
- declare const getDeepActiveElement: () => Element | null;
48
+ declare const distillPointer: (raw: any) => AbstractPointerEvent;
56
49
  /**
57
- * Forcefully focuses an element.
58
- * Automatically handles the 'tabindex' attribute to ensure non-focusable elements (like Canvas)
59
- * can receive focus.
50
+ * Dynamically distills a custom set of fields from a raw object.
60
51
  *
61
- * @param el - The target HTMLElement to focus.
52
+ * @template T - The target structure type.
53
+ * @param raw - The source data.
54
+ * @param fields - The list of fields to preserve.
55
+ * @returns The distilled object matching the target structure.
62
56
  */
63
- declare const focusElement: (el: HTMLElement) => void;
64
- /**
65
- * Dispatches a synthetic KeyboardEvent to the window object.
66
- *
67
- * @param type - The event type, e.g., 'keydown' or 'keyup'.
68
- * @param payload - Key mapping data including key, code, and legacy keyCode.
69
- */
70
- declare const dispatchKeyboardEvent: (type: string, payload: {
71
- key: string;
72
- code: string;
73
- keyCode: number;
74
- }) => void;
75
- /**
76
- * Dispatches a high-fidelity sequence of Pointer and Mouse events at specific pixel coordinates.
77
- * Finds the target element dynamically at the moment of dispatch.
78
- *
79
- * @param type - The event type (should start with 'pointer' for best compatibility).
80
- * @param x - Viewport X coordinate (px).
81
- * @param y - Viewport Y coordinate (px).
82
- * @param opts - Additional PointerEvent options (button, pressure, etc.).
83
- */
84
- declare const dispatchPointerEventAtPos: (type: string, x: number, y: number, opts: {
85
- button: number;
86
- buttons: number;
87
- pressure: number;
88
- }) => void;
89
- /**
90
- * Reclaims browser focus for the element located at the specified viewport coordinates.
91
- *
92
- * This utility identifies the deepest element (penetrating Shadow DOM) at the given position
93
- * and ensures it becomes the active element. It is essential for ensuring that
94
- * game engines (like Ruffle) receive keyboard events immediately after a virtual interaction.
95
- *
96
- * @param x - The horizontal coordinate relative to the viewport.
97
- * @param y - The vertical coordinate relative to the viewport.
98
- * @returns True if the focus was successfully moved to the target; false if it was already focused or no target found.
99
- */
100
- declare const reclaimFocusAtPos: (x: number, y: number, callback: () => void) => void;
101
- declare const supportsContainerQueries: () => boolean;
102
- /**
103
- * Safely sets pointer capture on an element.
104
- *
105
- * @param el - The target element to capture the pointer.
106
- * @param pointerId - The unique ID of the pointer (from PointerEvent).
107
- */
108
- declare const safeSetCapture: (el: EventTarget | null, pointerId: number) => void;
109
- /**
110
- * Safely releases pointer capture from an element.
111
- * Checks for current capture state and wraps in try-catch to prevent crashes.
112
- *
113
- * @param el - The target element.
114
- * @param pointerId - The unique ID of the pointer to release.
115
- */
116
- declare const safeReleaseCapture: (el: EventTarget | null, pointerId: number) => void;
117
- /**
118
- * Creates a standardized bridge between native DOM PointerEvents and Core abstract handlers.
119
- * Handles event prevention, stop propagation, pointer capture, and multi-touch filtering.
120
- *
121
- * @param coreHandler - The logic core instance that implements IPointerHandler.
122
- * @param getElement - A getter function to retrieve the DOM element for pointer capture.
123
- * @returns An object containing mapped event handlers for Vue/React template binding.
124
- */
125
- declare function createPointerBridge(coreHandler: IPointerHandler & {
126
- activePointerId?: number | null;
127
- }, options?: {
128
- /** Respond only to direct clicks (without responding to events bubbled up from child elements) */
129
- requireDirectHit?: boolean;
130
- }): {
131
- /**
132
- * Entry point for a pointer interaction.
133
- * Establishes capture and initializes core logic.
134
- */
135
- onPointerDown(e: PointerEvent): void;
136
- /**
137
- * Continuous movement handling.
138
- * Throttling should be handled within the core implementation.
139
- */
140
- onPointerMove(e: PointerEvent): void;
141
- /**
142
- * Successful interaction completion.
143
- * Filters by pointerId to ensure only the capturing finger triggers release.
144
- */
145
- onPointerUp(e: PointerEvent): void;
146
- /**
147
- * System-level interaction cancellation (e.g., alert popups, browser gestures).
148
- */
149
- onPointerCancel(e: PointerEvent): void;
150
- };
57
+ declare const distillCustom: <T extends object>(raw: any, fields: readonly (keyof T)[]) => T;
151
58
 
152
59
  /**
153
- * Generates a globally unique identifier (UID) for runtime entity management and DOM keys.
154
- *
155
- * The generated ID follows the format: `[prefix]-[timestamp_base36]-[random_string]`.
156
- * This ensures that components generated at different times or across multiple sessions
157
- * remain unique within the current page instance.
60
+ * Generates a unique identifier (UID).
158
61
  *
159
- * @param prefix - A string prefix for the ID, typically the component type (e.g., 'btn', 'joy'). Defaults to 'omnipad'.
160
- * @returns A unique string identifier.
62
+ * Uses the Web Crypto API to ensure cryptographic randomness if available,
63
+ * falling back to Math.random() in insecure or legacy environments.
161
64
  *
162
- * @example
163
- * generateUID('button') // returns "button-m7x8k1p2-f4k2"
65
+ * @param prefix - A prefix string to identify the entity type (e.g., 'btn').
66
+ * @returns A unique string formatted as `prefix-timestamp-random`.
164
67
  */
165
68
  declare const generateUID: (prefix?: string) => string;
166
69
  /**
@@ -185,7 +88,7 @@ declare function isGlobalID(id: string): boolean;
185
88
  * @param input - The raw length input.
186
89
  * @returns A sanitized ParsedLength.
187
90
  */
188
- declare function parseLength(input: string | number | undefined): ParsedLength;
91
+ declare function parseLength(input: FlexibleLength | undefined): ParsedLength | undefined;
189
92
  /**
190
93
  * Check the whitelist of verification units and sanitize ParsedLength.
191
94
  */
@@ -193,7 +96,28 @@ declare const sanitizeParsedLength: (parsed: ParsedLength) => ParsedLength;
193
96
  /**
194
97
  * Convert the ParsedLength back to a CSS string
195
98
  */
196
- declare const lengthToCss: (parsed: ParsedLength) => string;
99
+ declare const lengthToCss: (parsed: ParsedLength | undefined) => string | undefined;
100
+ /**
101
+ * Validate a raw LayoutBox config.
102
+ */
103
+ declare function validateLayoutBox(raw: LayoutBox): LayoutBox;
104
+ /**
105
+ * Compress layout properties into css strings.
106
+ */
107
+ declare function compressLayoutBox(raw: LayoutBox): LayoutBox;
108
+ /**
109
+ * Resolves a relative 'absolute' layout configuration into a 'fixed' pixel-based layout.
110
+ *
111
+ * **Transformation:**
112
+ * - **Input:** A `layout` defined relative to the `refRect` (similar to CSS `position: absolute`).
113
+ * - **Output:** A `layout` defined in the same coordinate space as the `refRect` (similar to CSS `position: fixed` or global coordinates).
114
+ *
115
+ * @param layout - The relative layout (e.g., `{ left: '10%' }` of the target).
116
+ * @param refRect - The reference rect used as the "container" for calculation.
117
+ * @param toPx - Optional converter for custom unit handling.
118
+ * @returns A normalized `LayoutBox` with fixed pixel strings.
119
+ */
120
+ declare function flattenRelativeLayout(layout: LayoutBox, refRect: AbstractRect, toPx?: (p: ParsedLength | undefined, base: number) => number): LayoutBox;
197
121
  /**
198
122
  * Converts a LayoutBox configuration into a CSS style object suitable for Vue/React.
199
123
  *
@@ -211,6 +135,26 @@ declare const lengthToCss: (parsed: ParsedLength) => string;
211
135
  * resolveLayoutStyle({ left: '50%', top: '50%', anchor: 'center' });
212
136
  */
213
137
  declare const resolveLayoutStyle: (layout: LayoutBox) => Record<string, string | number>;
138
+ /**
139
+ * Projects a normalized input vector (-1.0 to 1.0) onto a CSS layout box.
140
+ * Ideal for components that move relative to a center point, such as joystick handles.
141
+ *
142
+ * @param vec - The input vector where (0,0) is center and 1.0 is the boundary.
143
+ * @param size - The actual pixel dimensions of the container.
144
+ * @param useNativeCQ - If true, uses Container Query units (cqw/cqh) for responsive scaling.
145
+ * @returns A CSS-compatible object with width, height, x, and y properties.
146
+ */
147
+ declare const projectVectorToBox: (vec: Vec2, size: Vec2, useNativeCQ?: boolean) => Record<string, string>;
148
+ /**
149
+ * Projects percentage coordinates (0-100) onto a CSS layout box.
150
+ * Suitable for absolute positioning requirements like virtual cursors or stage markers.
151
+ *
152
+ * @param percent - The coordinate point in percentages.
153
+ * @param getSize - Lazy getter for current physical dimensions of the container.
154
+ * @param useNativeCQ - If true, returns responsive Container Query units.
155
+ * @returns A CSS-compatible object with width, height, x, and y properties.
156
+ */
157
+ declare const projectPercentToBox: (percent: Vec2, getSize: () => Vec2, useNativeCQ?: boolean) => Record<string, string>;
214
158
 
215
159
  /**
216
160
  * Subtracts vector v2 from v1.
@@ -313,56 +257,79 @@ declare const applyRadialDeadzone: (v: Vec2, radius: number, deadzonePercent: nu
313
257
  * Applies an axial deadzone to a vector.
314
258
  * Independently processes X and Y axes. Useful for D-Pads or precision directional inputs.
315
259
  * @param v - Input vector.
316
- * @param threshold - The deadzone threshold value.
317
260
  * @param max - Maximum value for the axis.
261
+ * @param threshold - The deadzone threshold value.
318
262
  */
319
- declare const applyAxialDeadzone: (v: Vec2, threshold: number, max: number) => Vec2;
263
+ declare const applyAxialDeadzone: (v: Vec2, max: number, threshold: number) => Vec2;
320
264
 
321
265
  /**
322
- * Validates and normalizes raw JSON data into a standard GamepadProfile.
323
- * Performs structural checks and injects default metadata.
266
+ * Filters an object by removing undefined values and specific excluded keys.
267
+ *
268
+ * @param obj - The source object.
269
+ * @param excludeKeys - A set of keys to be ignored.
270
+ * @returns A new object containing only allowed business properties.
271
+ */
272
+ declare function filterObjectByKeys(obj: Record<string, any>, excludeKeys: Set<string>): Record<string, any>;
273
+ /**
274
+ * Compares two objects and extracts the properties that have changed.
324
275
  *
325
- * @param raw - The raw JSON object from disk or network.
326
- * @returns A validated GamepadProfile object.
327
- * @throws Error if the core structure is invalid.
328
- */
329
- declare function parseProfileJson(raw: any): GamepadProfile;
330
- /**
331
- * The resulting structure after parsing a GamepadProfile.
332
- * Contains a map of root nodes and a runtime-ready gamepad mapping table.
333
- */
334
- interface ParsedProfileForest {
335
- /** Root nodes indexed by their original Config ID. */
336
- roots: Record<string, ConfigTreeNode>;
337
- /**
338
- * Processed gamepad mapping where all CIDs have been
339
- * translated into unique runtime UIDs.
340
- */
341
- runtimeGamepadMappings: GamepadMappingConfig[];
342
- }
343
- /**
344
- * Converts a flat GamepadProfile into a forest of ConfigTreeNodes for runtime rendering.
345
- * Automatically identifies all items without a parentId as root nodes.
276
+ * This function performs a shallow comparison of keys. For nested objects,
277
+ * it performs a structural check to determine if
278
+ * the contents have changed.
346
279
  *
347
- * @param profile - The normalized profile data.
348
- * @returns A record map of root nodes, keyed by their original configuration ID.
280
+ * @param oldObj - The previous state or snapshot of the object.
281
+ * @param newObj - The new state of the object to compare against the old one.
282
+ * @returns A partial record containing only the key-value pairs that differ from the original.
349
283
  */
350
- declare function parseProfileTrees(profile: GamepadProfile): ParsedProfileForest;
284
+ declare function getObjectDiff(oldObj: Record<string, any>, newObj: Record<string, any>): Record<string, any>;
351
285
  /**
352
- * Serializes the specified runtime entities into a flat GamepadProfile.
353
- * If no rootUids are provided, exports all entities currently in the registry.
286
+ * Merges multiple objects from left to right.
287
+ * Later objects will override properties of earlier ones.
354
288
  *
355
- * @param meta - Metadata for the exported profile.
356
- * @param rootUid - The Entity ID of the node to be treated as the root.
357
- * @param runtimeGamepadMapping - The current mapping from GamepadManager (using UIDs).
358
- * @returns A flat GamepadProfile ready for storage.
289
+ * @template T - The expected return type.
290
+ * @param objects - A list of objects to merge.
291
+ * @returns The merged object as type T.
359
292
  */
360
- declare function exportProfile(meta: GamepadProfile['meta'], rootUids?: string[], runtimeGamepadMappings?: Readonly<GamepadMappingConfig[]>): GamepadProfile;
293
+ declare function mergeObjects<T>(...objects: (Record<string, any> | undefined | null)[]): T;
294
+
361
295
  /**
362
- * Extract filtered business configurations.
363
- * @param props Original Props object (e.g. Vue's props)
364
- * @param skipKeys Ignore key set
296
+ * Simple DOM string sanitizer to prevent CSS/JS injection.
297
+ * Validates selectors and class names.
298
+ */
299
+ declare const PROTO_POLLUTION_KEYS: readonly ["__proto__", "constructor", "prototype"];
300
+ declare const XXS_DANGEROUS_KEYWORDS: readonly ["script", "javascript:", "onerror", "onload", "eval", "expression"];
301
+ /**
302
+ * Sanitizes a string intended for DOM use (selectors, classes, etc.)
303
+ * @param input - The raw string input to be sanitized.
304
+ * @param fallback - Returned if input is unsafe.
305
+ */
306
+ declare function sanitizeDomString(input: string | undefined, fallback?: string): string;
307
+ /**
308
+ * Specifically validates and cleans CSS class strings.
309
+ * Ensures it's just a space-separated list of valid class names.
310
+ * @param input - The raw string input to be sanitized.
311
+ */
312
+ declare function sanitizeCssClass(input: string | undefined): string;
313
+ /**
314
+ * Recursively sanitizes an object by stripping dangerous prototype-pollution keys.
315
+ *
316
+ * @remarks
317
+ * This function performs a deep traversal of the input and removes keys such as
318
+ * `__proto__`, `constructor`, and `prototype`. It uses an internal closure-based
319
+ * recursion and a pre-allocated `Set` to ensure optimal performance and memory
320
+ * efficiency during deep-tree processing.
321
+ *
322
+ * @param input - The raw data (usually from an untrusted JSON source) to be sanitized.
323
+ * @returns A new object/array cloned from the input, guaranteed to be free of
324
+ * prototype pollution vectors at any depth.
325
+ *
326
+ * @example
327
+ * ```typescript
328
+ * const tainted = JSON.parse('{"__proto__": {"admin": true}, "config": {"prototype": "bad"}}');
329
+ * const safe = sanitizePrototypePollution(tainted);
330
+ * // safe => { config: {} }
331
+ * ```
365
332
  */
366
- declare function getBusinessProps(props: Record<string, any>, skipKeys: Set<string>): Record<string, any>;
333
+ declare function sanitizePrototypePollution<T>(input: T): T;
367
334
 
368
- export { type ParsedProfileForest, addVec, applyAxialDeadzone, applyRadialDeadzone, clamp, clampVector, createCachedProvider, createPointerBridge, degToRad, dispatchKeyboardEvent, dispatchPointerEventAtPos, exportProfile, focusElement, generateUID, getAngle, getBusinessProps, getDeadzoneScalar, getDeepActiveElement, getDeepElement, getDistance, getObjectDiff, isGlobalID, isVec2Equal, lengthToCss, lerp, lockTo4Directions, lockTo8Directions, normalizeVec, parseLength, parseProfileJson, parseProfileTrees, percentToPx, pxToPercent, radToDeg, radToVec, reclaimFocusAtPos, remap, resolveLayoutStyle, roundTo, safeReleaseCapture, safeSetCapture, sanitizeParsedLength, scaleVec, subVec, supportsContainerQueries };
335
+ export { PROTO_POLLUTION_KEYS, XXS_DANGEROUS_KEYWORDS, addVec, applyAxialDeadzone, applyRadialDeadzone, clamp, clampVector, compressLayoutBox, createCachedProvider, degToRad, distillCustom, distillPointer, distillRect, filterObjectByKeys, flattenRelativeLayout, generateUID, getAngle, getDeadzoneScalar, getDistance, getObjectDiff, isGlobalID, isVec2Equal, lengthToCss, lerp, lockTo4Directions, lockTo8Directions, mergeObjects, normalizeVec, parseLength, percentToPx, projectPercentToBox, projectVectorToBox, pxToPercent, radToDeg, radToVec, remap, resolveLayoutStyle, roundTo, sanitizeCssClass, sanitizeDomString, sanitizeParsedLength, sanitizePrototypePollution, scaleVec, subVec, validateLayoutBox };
@@ -1 +1 @@
1
- import {e,h}from'../chunk-W7OR5ESR.mjs';export{j as addVec,D as applyAxialDeadzone,C as applyRadialDeadzone,l as clamp,s as clampVector,r as degToRad,p as getAngle,B as getDeadzoneScalar,o as getDistance,A as isVec2Equal,m as lerp,u as lockTo4Directions,t as lockTo8Directions,x as normalizeVec,v as percentToPx,w as pxToPercent,q as radToDeg,y as radToVec,z as remap,n as roundTo,k as scaleVec,i as subVec}from'../chunk-W7OR5ESR.mjs';function Z(t){let r=null,e=true;return {get:()=>((e||!r)&&(r=t(),e=false),r),markDirty:()=>{e=true;}}}function tt(t,r){let e={};return t?(Object.keys(r).forEach(o=>{let i=r[o],a=t[o];typeof i=="object"&&i!==null?JSON.stringify(i)!==JSON.stringify(a)&&(e[o]=i):i!==a&&(e[o]=i);}),e):{...r}}var v=(t,r,e="omnipad-prevent")=>{let i=document.elementsFromPoint(t,r).find(a=>!a.classList.contains(e));if(!i)return null;for(;i&&i.shadowRoot;){let c=i.shadowRoot.elementsFromPoint(t,r).find(f=>!f.classList.contains(e));if(!c||c===i)break;i=c;}return i},E=()=>{let t=document.activeElement;for(;t&&t.shadowRoot&&t.shadowRoot.activeElement;)t=t.shadowRoot.activeElement;return t},M=t=>{E()!==t&&(t.hasAttribute("tabindex")||t.setAttribute("tabindex","-1"),t.focus());},nt=(t,r)=>{let e=new KeyboardEvent(t,{...r,which:r.keyCode,bubbles:true,cancelable:true,view:window});window.dispatchEvent(e);},rt=(t,r,e,o)=>{let i=v(r,e);if(!i)return;let a={bubbles:true,cancelable:true,composed:true,clientX:r,clientY:e,view:window,...o};if(t.startsWith("pointer")){i.dispatchEvent(new PointerEvent(t,{isPrimary:true,pointerId:9999,pointerType:"mouse",...a}));let c=t.replace("pointer","mouse");i.dispatchEvent(new MouseEvent(c,a));}else i.dispatchEvent(new MouseEvent(t,a));},it=(t,r,e)=>{let o=v(t,r);if(!o)return;E()!==o&&(M(o),e());},g,ot=()=>(g!==void 0||(g=typeof window<"u"&&!!window.CSS?.supports?.("width: 1cqw")),g),T=(t,r)=>{if(t instanceof Element)try{t.setPointerCapture(r);}catch(e){import.meta.env?.DEV&&console.warn("[Omnipad-DOM] Failed to set pointer capture:",e);}},I=(t,r)=>{if(t instanceof Element&&t.hasPointerCapture(r))try{t.releasePointerCapture(r);}catch{}};function at(t,r={}){return {onPointerDown(e){if(!e.isTrusted||r?.requireDirectHit&&e.target!==e.currentTarget||t.activePointerId!=null)return;e.cancelable&&e.preventDefault(),e.stopPropagation();let o=e.currentTarget;o&&T(o,e.pointerId),t.onPointerDown(e);},onPointerMove(e){e.isTrusted&&(t.activePointerId!=null&&t.activePointerId!==e.pointerId||(e.cancelable&&e.preventDefault(),t.onPointerMove(e)));},onPointerUp(e){if(!e.isTrusted||t.activePointerId!=null&&t.activePointerId!==e.pointerId)return;e.cancelable&&e.preventDefault();let o=e.currentTarget;o&&I(o,e.pointerId),t.onPointerUp(e);},onPointerCancel(e){if(!e.isTrusted||t.activePointerId!=null&&t.activePointerId!==e.pointerId)return;let o=e.currentTarget;o&&I(o,e.pointerId),t.onPointerCancel(e);}}}var S=(t="omnipad")=>{let r=Date.now().toString(36),e=Math.random().toString(36).substring(2,6);return `${t}-${r}-${e}`};function m(t){return t.startsWith("$")}function k(t){if(t==null)return {value:0,unit:"px"};if(typeof t=="number")return {value:Number.isFinite(t)?t:0,unit:"px"};let r=t.trim(),e=parseFloat(r);if(isNaN(e))return {value:0,unit:"px"};let o=r.match(/[a-z%]+$/i),i=o?o[0].toLowerCase():"px";return C({value:e,unit:i})}var C=t=>{let{value:r,unit:e$1}=t;return e.includes(e$1)?{value:r,unit:e$1}:(console.warn(`[Omnipad-Core] Blocked invalid CSS unit: ${e$1}`),{value:r,unit:"px"})},x=t=>`${t.value}${t.unit}`,gt=t=>{if(Object.keys(t??{}).length===0)return {};let r={};r.position="absolute",t.isSquare&&(r.aspectRatio="1/1"),["left","top","right","bottom","width","height"].forEach(i=>{let a=t[i];if(a!=null){if(typeof a=="object"&&"unit"in a){let c=C(a);r[i]=x(c);}else if(typeof a=="string"||typeof a=="number"){let c=k(a);r[i]=x(c);}}}),t.zIndex!==void 0&&(r.zIndex=t.zIndex);let o={"top-left":"translate(0, 0)","top-center":"translate(-50%, 0)","top-right":"translate(-100%, 0)","center-left":"translate(0, -50%)",center:"translate(-50%, -50%)","center-right":"translate(-100%, -50%)","bottom-left":"translate(0, -100%)","bottom-center":"translate(-50%, -100%)","bottom-right":"translate(-100%, -100%)"};return t.anchor&&(r.transform=o[t.anchor]),r};function Pt(t){if(!t||typeof t!="object")throw new Error("[OmniPad-Validation] Profile must be a valid JSON object.");if(!Array.isArray(t.items))throw new Error('[OmniPad-Validation] "items" must be an array.');let r={name:t.meta?.name||"Untitled Profile",version:t.meta?.version||"1.0.0",author:t.meta?.author||"Unknown"},e=t.items.map((i,a)=>{if(!i.id||!i.type)throw new Error(`[OmniPad-Validation] Item at index ${a} is missing "id" or "type".`);return {id:String(i.id),type:String(i.type),parentId:i.parentId?String(i.parentId):void 0,config:i.config||{}}}),o=t.gamepadMappings;return {meta:r,items:e,gamepadMappings:o}}function yt(t){let{items:r,gamepadMappings:e}=t,o=new Map,i=(n,s="node")=>m(n)?n:(o.has(n)||o.set(n,S(s)),o.get(n));r.forEach(n=>i(n.id,n.type));let a=[];e&&e.forEach(n=>{let s={};if(n.buttons){s.buttons={};for(let[u,d]of Object.entries(n.buttons))s.buttons[u]=i(d);}n.dpad&&(s.dpad=i(n.dpad)),n.leftStick&&(s.leftStick=i(n.leftStick)),n.rightStick&&(s.rightStick=i(n.rightStick)),a.push(s);});let c=new Map,f=[];r.forEach(n=>{n.parentId?(c.has(n.parentId)||c.set(n.parentId,[]),c.get(n.parentId).push(n)):f.push(n);});let l=(n,s)=>{if(s.has(n.id))throw new Error(`[Omnipad-Core] Circular dependency detected at node: ${n.id}`);s.add(n.id);let u={...n.config};u?.targetStageId&&(u.targetStageId=i(u.targetStageId)),u?.dynamicWidgetId&&(u.dynamicWidgetId=i(u.dynamicWidgetId));let h=(c.get(n.id)||[]).map(b=>l(b,new Set(s)));return {uid:i(n.id),type:n.type,config:u,children:h}},p={};return f.forEach(n=>{p[n.id]=l(n,new Set);}),{roots:p,runtimeGamepadMappings:a}}function It(t,r,e){let o=h.getInstance(),i=[];if(!r||r.length===0)i=o.getAllEntities();else {let n=new Set;r.forEach(s=>{o.getEntitiesByRoot(s).forEach(d=>n.add(d));}),i=Array.from(n);}let a=new Map,c=0,f=n=>m(n)?n:(a.has(n)||a.set(n,`node_${++c}`),a.get(n)),l=i.map(n=>{let s=n.getConfig(),u=n.uid,d={...s};d.targetStageId&&(d.targetStageId=f(d.targetStageId)),d.dynamicWidgetId&&(d.dynamicWidgetId=f(d.dynamicWidgetId));let{id:h,parentId:b,...w}=d;return {id:f(u),type:n.type,parentId:s.parentId?f(s.parentId):void 0,config:w}}),p=[];return e&&e.forEach(n=>{let s={};if(n.buttons){s.buttons={};for(let[u,d]of Object.entries(n.buttons))a.has(d)&&(s.buttons[u]=a.get(d));}n.dpad&&a.has(n.dpad)&&(s.dpad=a.get(n.dpad)),n.leftStick&&a.has(n.leftStick)&&(s.leftStick=a.get(n.leftStick)),n.rightStick&&a.has(n.rightStick)&&(s.rightStick=a.get(n.rightStick)),Object.keys(s).length>0?p.push(s):p.push({});}),{meta:t,items:l,gamepadMappings:Object.keys(p).length>0?p:void 0}}function vt(t,r){let e={};for(let o in t)t[o]!==void 0&&!r.has(o)&&(e[o]=t[o]);return e}export{Z as createCachedProvider,at as createPointerBridge,nt as dispatchKeyboardEvent,rt as dispatchPointerEventAtPos,It as exportProfile,M as focusElement,S as generateUID,vt as getBusinessProps,E as getDeepActiveElement,v as getDeepElement,tt as getObjectDiff,m as isGlobalID,x as lengthToCss,k as parseLength,Pt as parseProfileJson,yt as parseProfileTrees,it as reclaimFocusAtPos,gt as resolveLayoutStyle,I as safeReleaseCapture,T as safeSetCapture,C as sanitizeParsedLength,ot as supportsContainerQueries};
1
+ export{a as filterObjectByKeys,b as getObjectDiff,c as mergeObjects}from'../chunk-AK3RL7NL.mjs';export{c as distillCustom,b as distillPointer,a as distillRect}from'../chunk-J5SVBM6K.mjs';export{i as PROTO_POLLUTION_KEYS,j as XXS_DANGEROUS_KEYWORDS,o as addVec,I as applyAxialDeadzone,H as applyRadialDeadzone,q as clamp,x as clampVector,N as compressLayoutBox,f as createCachedProvider,w as degToRad,O as flattenRelativeLayout,g as generateUID,u as getAngle,G as getDeadzoneScalar,t as getDistance,h as isGlobalID,F as isVec2Equal,L as lengthToCss,r as lerp,z as lockTo4Directions,y as lockTo8Directions,C as normalizeVec,J as parseLength,A as percentToPx,R as projectPercentToBox,Q as projectVectorToBox,B as pxToPercent,v as radToDeg,D as radToVec,E as remap,P as resolveLayoutStyle,s as roundTo,l as sanitizeCssClass,k as sanitizeDomString,K as sanitizeParsedLength,m as sanitizePrototypePollution,p as scaleVec,n as subVec,M as validateLayoutBox}from'../chunk-EYKCVOUA.mjs';import'../chunk-HQNUZXP5.mjs';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@omnipad/core",
3
- "version": "0.4.5",
3
+ "version": "0.6.0",
4
4
  "description": "",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -16,6 +16,16 @@
16
16
  "types": "./dist/utils/index.d.ts",
17
17
  "import": "./dist/utils/index.mjs",
18
18
  "require": "./dist/utils/index.cjs"
19
+ },
20
+ "./dom": {
21
+ "types": "./dist/dom/index.d.ts",
22
+ "import": "./dist/dom/index.mjs",
23
+ "require": "./dist/dom/index.cjs"
24
+ },
25
+ "./guest": {
26
+ "types": "./dist/guest/index.d.ts",
27
+ "import": "./dist/guest/index.mjs",
28
+ "require": "./dist/guest/index.cjs"
19
29
  }
20
30
  },
21
31
  "typesVersions": {
@@ -25,6 +35,12 @@
25
35
  ],
26
36
  "utils": [
27
37
  "./dist/utils/index.d.ts"
38
+ ],
39
+ "dom": [
40
+ "./dist/dom/index.d.ts"
41
+ ],
42
+ "guest": [
43
+ "./dist/guest/index.d.ts"
28
44
  ]
29
45
  }
30
46
  },
@@ -1 +0,0 @@
1
- 'use strict';var x=Object.defineProperty;var f=(t,e,o)=>e in t?x(t,e,{enumerable:true,configurable:true,writable:true,value:o}):t[e]=o;var m=(t,e,o)=>f(t,typeof e!="symbol"?e+"":e,o);var E={Backspace:{key:"Backspace",code:"Backspace",keyCode:8},Tab:{key:"Tab",code:"Tab",keyCode:9},Enter:{key:"Enter",code:"Enter",keyCode:13},ShiftLeft:{key:"Shift",code:"ShiftLeft",keyCode:16},ControlLeft:{key:"Control",code:"ControlLeft",keyCode:17},AltLeft:{key:"Alt",code:"AltLeft",keyCode:18},Pause:{key:"Pause",code:"Pause",keyCode:19},CapsLock:{key:"CapsLock",code:"CapsLock",keyCode:20},Escape:{key:"Escape",code:"Escape",keyCode:27},Space:{key:" ",code:"Space",keyCode:32},PageUp:{key:"PageUp",code:"PageUp",keyCode:33},PageDown:{key:"PageDown",code:"PageDown",keyCode:34},End:{key:"End",code:"End",keyCode:35},Home:{key:"Home",code:"Home",keyCode:36},ArrowLeft:{key:"ArrowLeft",code:"ArrowLeft",keyCode:37},ArrowUp:{key:"ArrowUp",code:"ArrowUp",keyCode:38},ArrowRight:{key:"ArrowRight",code:"ArrowRight",keyCode:39},ArrowDown:{key:"ArrowDown",code:"ArrowDown",keyCode:40},PrintScreen:{key:"PrintScreen",code:"PrintScreen",keyCode:44},Insert:{key:"Insert",code:"Insert",keyCode:45},Delete:{key:"Delete",code:"Delete",keyCode:46},Digit0:{key:"0",code:"Digit0",keyCode:48},Digit1:{key:"1",code:"Digit1",keyCode:49},Digit2:{key:"2",code:"Digit2",keyCode:50},Digit3:{key:"3",code:"Digit3",keyCode:51},Digit4:{key:"4",code:"Digit4",keyCode:52},Digit5:{key:"5",code:"Digit5",keyCode:53},Digit6:{key:"6",code:"Digit6",keyCode:54},Digit7:{key:"7",code:"Digit7",keyCode:55},Digit8:{key:"8",code:"Digit8",keyCode:56},Digit9:{key:"9",code:"Digit9",keyCode:57},KeyA:{key:"a",code:"KeyA",keyCode:65},KeyB:{key:"b",code:"KeyB",keyCode:66},KeyC:{key:"c",code:"KeyC",keyCode:67},KeyD:{key:"d",code:"KeyD",keyCode:68},KeyE:{key:"e",code:"KeyE",keyCode:69},KeyF:{key:"f",code:"KeyF",keyCode:70},KeyG:{key:"g",code:"KeyG",keyCode:71},KeyH:{key:"h",code:"KeyH",keyCode:72},KeyI:{key:"i",code:"KeyI",keyCode:73},KeyJ:{key:"j",code:"KeyJ",keyCode:74},KeyK:{key:"k",code:"KeyK",keyCode:75},KeyL:{key:"l",code:"KeyL",keyCode:76},KeyM:{key:"m",code:"KeyM",keyCode:77},KeyN:{key:"n",code:"KeyN",keyCode:78},KeyO:{key:"o",code:"KeyO",keyCode:79},KeyP:{key:"p",code:"KeyP",keyCode:80},KeyQ:{key:"q",code:"KeyQ",keyCode:81},KeyR:{key:"r",code:"KeyR",keyCode:82},KeyS:{key:"s",code:"KeyS",keyCode:83},KeyT:{key:"t",code:"KeyT",keyCode:84},KeyU:{key:"u",code:"KeyU",keyCode:85},KeyV:{key:"v",code:"KeyV",keyCode:86},KeyW:{key:"w",code:"KeyW",keyCode:87},KeyX:{key:"x",code:"KeyX",keyCode:88},KeyY:{key:"y",code:"KeyY",keyCode:89},KeyZ:{key:"z",code:"KeyZ",keyCode:90},MetaLeft:{key:"Meta",code:"MetaLeft",keyCode:91},ContextMenu:{key:"ContextMenu",code:"ContextMenu",keyCode:93},Numpad0:{key:"0",code:"Numpad0",keyCode:96},Numpad1:{key:"1",code:"Numpad1",keyCode:97},Numpad2:{key:"2",code:"Numpad2",keyCode:98},Numpad3:{key:"3",code:"Numpad3",keyCode:99},Numpad4:{key:"4",code:"Numpad4",keyCode:100},Numpad5:{key:"5",code:"Numpad5",keyCode:101},Numpad6:{key:"6",code:"Numpad6",keyCode:102},Numpad7:{key:"7",code:"Numpad7",keyCode:103},Numpad8:{key:"8",code:"Numpad8",keyCode:104},Numpad9:{key:"9",code:"Numpad9",keyCode:105},NumpadMultiply:{key:"*",code:"NumpadMultiply",keyCode:106},NumpadAdd:{key:"+",code:"NumpadAdd",keyCode:107},NumpadSubtract:{key:"-",code:"NumpadSubtract",keyCode:109},NumpadDecimal:{key:".",code:"NumpadDecimal",keyCode:110},NumpadDivide:{key:"/",code:"NumpadDivide",keyCode:111},F1:{key:"F1",code:"F1",keyCode:112},F2:{key:"F2",code:"F2",keyCode:113},F3:{key:"F3",code:"F3",keyCode:114},F4:{key:"F4",code:"F4",keyCode:115},F5:{key:"F5",code:"F5",keyCode:116},F6:{key:"F6",code:"F6",keyCode:117},F7:{key:"F7",code:"F7",keyCode:118},F8:{key:"F8",code:"F8",keyCode:119},F9:{key:"F9",code:"F9",keyCode:120},F10:{key:"F10",code:"F10",keyCode:121},F11:{key:"F11",code:"F11",keyCode:122},F12:{key:"F12",code:"F12",keyCode:123},NumLock:{key:"NumLock",code:"NumLock",keyCode:144},ScrollLock:{key:"ScrollLock",code:"ScrollLock",keyCode:145},Semicolon:{key:";",code:"Semicolon",keyCode:186},Equal:{key:"=",code:"Equal",keyCode:187},Comma:{key:",",code:"Comma",keyCode:188},Minus:{key:"-",code:"Minus",keyCode:189},Period:{key:".",code:"Period",keyCode:190},Slash:{key:"/",code:"Slash",keyCode:191},Backquote:{key:"`",code:"Backquote",keyCode:192},BracketLeft:{key:"[",code:"BracketLeft",keyCode:219},Backslash:{key:"\\",code:"Backslash",keyCode:220},BracketRight:{key:"]",code:"BracketRight",keyCode:221},Quote:{key:"'",code:"Quote",keyCode:222}},P=E;var A={INPUT_ZONE:"input-zone",TARGET_ZONE:"target-zone",BUTTON:"button",KEYBOARD_BUTTON:"keyboard-button",MOUSE_BUTTON:"mouse-button",JOYSTICK:"joystick",D_PAD:"d-pad",TRACKPAD:"trackpad",VIRTUAL_CURSOR:"virtual-cursor",ROOT_LAYER:"root-layer"},D={KEYDOWN:"keydown",KEYUP:"keyup",POINTER:"pointer",POINTERMOVE:"pointermove",POINTERDOWN:"pointerdown",POINTERUP:"pointerup",MOUSE:"mouse",MOUSEMOVE:"mousemove",MOUSEDOWN:"mousedown",MOUSEUP:"mouseup",CLICK:"click"},I=["px","%","vh","vw","rem","em"],M={PARENT_ID_KEY:"omnipad-parent-id-link"};var k=Symbol.for("omnipad.registry.instance"),s=null;function _(t){s=t;}var C=class t{constructor(){m(this,"entities",new Map);undefined?.DEV&&console.log("[OmniPad-Core] Registry initialized.");}static getInstance(){let e=globalThis;return e[k]||(e[k]=new t),e[k]}register(e){if(!e.uid){console.warn("[OmniPad-Core] Registry: Attempted to register entity without UID.",e);return}this.entities.has(e.uid),this.entities.set(e.uid,e);}unregister(e){this.entities.has(e)&&this.entities.delete(e);}getEntity(e){return this.entities.get(e)}getAllEntities(){return Array.from(this.entities.values())}getEntitiesByRoot(e){let o=this.getAllEntities();if(!e)return o;if(!this.entities.get(e))return console.warn(`[OmniPad-Core] Registry: Root entity ${e} not found.`),[];let r=new Map;o.forEach(d=>{let a=d;if(typeof a.getConfig=="function"){let i=a.getConfig();i.parentId&&(r.has(i.parentId)||r.set(i.parentId,[]),r.get(i.parentId).push(d));}});let y=[],c=[e],u=new Set;for(;c.length>0;){let d=c.shift();if(u.has(d))continue;u.add(d);let a=this.entities.get(d);if(a){y.push(a);let i=r.get(d);i&&i.forEach(b=>c.push(b.uid));}}return y}destroyByRoot(e){let o=this.getEntitiesByRoot(e);for(let n=o.length-1;n>=0;n--){let r=o[n];try{r.destroy();}catch(y){console.error(`[OmniPad-Core] Error during destroyByRoot at ${r.uid}:`,y);}}}clear(){this.entities.clear();}resetAll(){this.entities.forEach(e=>{"reset"in e&&e.reset();});}markAllRectDirty(){this.entities.forEach(e=>{"markRectDirty"in e&&e.markRectDirty();});}broadcastSignal(e){let o=this.getEntity(e.targetStageId);o&&"handleSignal"in o?o.handleSignal(e):s&&s(e);}};var B=(t,e)=>({x:t.x-e.x,y:t.y-e.y}),v=(t,e)=>({x:t.x+e.x,y:t.y+e.y}),h=(t,e)=>({x:t.x*e,y:t.y*e}),l=(t,e,o)=>Math.max(e,Math.min(o,t)),T=(t,e,o)=>t+(e-t)*o,g=(t,e=2)=>{let o=Math.pow(10,e);return Math.round(t*o)/o},z=(t,e)=>Math.hypot(e.x-t.x,e.y-t.y),Z=(t,e)=>Math.atan2(e.y-t.y,e.x-t.x),q=t=>t*180/Math.PI,G=t=>t*Math.PI/180,H=(t,e,o)=>{let n=e.x-t.x,r=e.y-t.y;if(Math.hypot(n,r)<=o)return e;let c=Math.atan2(r,n);return {x:t.x+Math.cos(c)*o,y:t.y+Math.sin(c)*o}},W=t=>{let e=Math.PI/4;return Math.round(t/e)*e},J=t=>{let e=Math.PI/2;return Math.round(t/e)*e},Q=(t,e)=>g(t*e/100),X=(t,e)=>e===0?0:g(t*100/e),j=t=>{let e=Math.hypot(t.x,t.y);return e===0?{x:0,y:0}:{x:t.x/e,y:t.y/e}},$=t=>({x:Math.cos(t),y:Math.sin(t)}),ee=(t,e,o,n,r)=>{let y=(t-e)/(o-e);return T(n,r,l(y,0,1))},te=(t,e,o=1e-4)=>Math.abs(t.x-e.x)<o&&Math.abs(t.y-e.y)<o,p=(t,e,o)=>{if(t<e)return 0;let n=(t-e)/(o-e);return l(n,0,1)},oe=(t,e,o)=>{let n=Math.hypot(t.x,t.y),r=e*o,y=p(n,r,e);if(y===0)return {x:0,y:0};let c={x:t.x/n,y:t.y/n};return h(c,y)},ne=(t,e,o)=>({x:p(Math.abs(t.x),e,o)*Math.sign(t.x),y:p(Math.abs(t.y),e,o)*Math.sign(t.y)});exports.A=te;exports.B=p;exports.C=oe;exports.D=ne;exports.a=m;exports.b=P;exports.c=A;exports.d=D;exports.e=I;exports.f=M;exports.g=_;exports.h=C;exports.i=B;exports.j=v;exports.k=h;exports.l=l;exports.m=T;exports.n=g;exports.o=z;exports.p=Z;exports.q=q;exports.r=G;exports.s=H;exports.t=W;exports.u=J;exports.v=Q;exports.w=X;exports.x=j;exports.y=$;exports.z=ee;
@@ -1 +0,0 @@
1
- var x=Object.defineProperty;var f=(t,e,o)=>e in t?x(t,e,{enumerable:true,configurable:true,writable:true,value:o}):t[e]=o;var m=(t,e,o)=>f(t,typeof e!="symbol"?e+"":e,o);var E={Backspace:{key:"Backspace",code:"Backspace",keyCode:8},Tab:{key:"Tab",code:"Tab",keyCode:9},Enter:{key:"Enter",code:"Enter",keyCode:13},ShiftLeft:{key:"Shift",code:"ShiftLeft",keyCode:16},ControlLeft:{key:"Control",code:"ControlLeft",keyCode:17},AltLeft:{key:"Alt",code:"AltLeft",keyCode:18},Pause:{key:"Pause",code:"Pause",keyCode:19},CapsLock:{key:"CapsLock",code:"CapsLock",keyCode:20},Escape:{key:"Escape",code:"Escape",keyCode:27},Space:{key:" ",code:"Space",keyCode:32},PageUp:{key:"PageUp",code:"PageUp",keyCode:33},PageDown:{key:"PageDown",code:"PageDown",keyCode:34},End:{key:"End",code:"End",keyCode:35},Home:{key:"Home",code:"Home",keyCode:36},ArrowLeft:{key:"ArrowLeft",code:"ArrowLeft",keyCode:37},ArrowUp:{key:"ArrowUp",code:"ArrowUp",keyCode:38},ArrowRight:{key:"ArrowRight",code:"ArrowRight",keyCode:39},ArrowDown:{key:"ArrowDown",code:"ArrowDown",keyCode:40},PrintScreen:{key:"PrintScreen",code:"PrintScreen",keyCode:44},Insert:{key:"Insert",code:"Insert",keyCode:45},Delete:{key:"Delete",code:"Delete",keyCode:46},Digit0:{key:"0",code:"Digit0",keyCode:48},Digit1:{key:"1",code:"Digit1",keyCode:49},Digit2:{key:"2",code:"Digit2",keyCode:50},Digit3:{key:"3",code:"Digit3",keyCode:51},Digit4:{key:"4",code:"Digit4",keyCode:52},Digit5:{key:"5",code:"Digit5",keyCode:53},Digit6:{key:"6",code:"Digit6",keyCode:54},Digit7:{key:"7",code:"Digit7",keyCode:55},Digit8:{key:"8",code:"Digit8",keyCode:56},Digit9:{key:"9",code:"Digit9",keyCode:57},KeyA:{key:"a",code:"KeyA",keyCode:65},KeyB:{key:"b",code:"KeyB",keyCode:66},KeyC:{key:"c",code:"KeyC",keyCode:67},KeyD:{key:"d",code:"KeyD",keyCode:68},KeyE:{key:"e",code:"KeyE",keyCode:69},KeyF:{key:"f",code:"KeyF",keyCode:70},KeyG:{key:"g",code:"KeyG",keyCode:71},KeyH:{key:"h",code:"KeyH",keyCode:72},KeyI:{key:"i",code:"KeyI",keyCode:73},KeyJ:{key:"j",code:"KeyJ",keyCode:74},KeyK:{key:"k",code:"KeyK",keyCode:75},KeyL:{key:"l",code:"KeyL",keyCode:76},KeyM:{key:"m",code:"KeyM",keyCode:77},KeyN:{key:"n",code:"KeyN",keyCode:78},KeyO:{key:"o",code:"KeyO",keyCode:79},KeyP:{key:"p",code:"KeyP",keyCode:80},KeyQ:{key:"q",code:"KeyQ",keyCode:81},KeyR:{key:"r",code:"KeyR",keyCode:82},KeyS:{key:"s",code:"KeyS",keyCode:83},KeyT:{key:"t",code:"KeyT",keyCode:84},KeyU:{key:"u",code:"KeyU",keyCode:85},KeyV:{key:"v",code:"KeyV",keyCode:86},KeyW:{key:"w",code:"KeyW",keyCode:87},KeyX:{key:"x",code:"KeyX",keyCode:88},KeyY:{key:"y",code:"KeyY",keyCode:89},KeyZ:{key:"z",code:"KeyZ",keyCode:90},MetaLeft:{key:"Meta",code:"MetaLeft",keyCode:91},ContextMenu:{key:"ContextMenu",code:"ContextMenu",keyCode:93},Numpad0:{key:"0",code:"Numpad0",keyCode:96},Numpad1:{key:"1",code:"Numpad1",keyCode:97},Numpad2:{key:"2",code:"Numpad2",keyCode:98},Numpad3:{key:"3",code:"Numpad3",keyCode:99},Numpad4:{key:"4",code:"Numpad4",keyCode:100},Numpad5:{key:"5",code:"Numpad5",keyCode:101},Numpad6:{key:"6",code:"Numpad6",keyCode:102},Numpad7:{key:"7",code:"Numpad7",keyCode:103},Numpad8:{key:"8",code:"Numpad8",keyCode:104},Numpad9:{key:"9",code:"Numpad9",keyCode:105},NumpadMultiply:{key:"*",code:"NumpadMultiply",keyCode:106},NumpadAdd:{key:"+",code:"NumpadAdd",keyCode:107},NumpadSubtract:{key:"-",code:"NumpadSubtract",keyCode:109},NumpadDecimal:{key:".",code:"NumpadDecimal",keyCode:110},NumpadDivide:{key:"/",code:"NumpadDivide",keyCode:111},F1:{key:"F1",code:"F1",keyCode:112},F2:{key:"F2",code:"F2",keyCode:113},F3:{key:"F3",code:"F3",keyCode:114},F4:{key:"F4",code:"F4",keyCode:115},F5:{key:"F5",code:"F5",keyCode:116},F6:{key:"F6",code:"F6",keyCode:117},F7:{key:"F7",code:"F7",keyCode:118},F8:{key:"F8",code:"F8",keyCode:119},F9:{key:"F9",code:"F9",keyCode:120},F10:{key:"F10",code:"F10",keyCode:121},F11:{key:"F11",code:"F11",keyCode:122},F12:{key:"F12",code:"F12",keyCode:123},NumLock:{key:"NumLock",code:"NumLock",keyCode:144},ScrollLock:{key:"ScrollLock",code:"ScrollLock",keyCode:145},Semicolon:{key:";",code:"Semicolon",keyCode:186},Equal:{key:"=",code:"Equal",keyCode:187},Comma:{key:",",code:"Comma",keyCode:188},Minus:{key:"-",code:"Minus",keyCode:189},Period:{key:".",code:"Period",keyCode:190},Slash:{key:"/",code:"Slash",keyCode:191},Backquote:{key:"`",code:"Backquote",keyCode:192},BracketLeft:{key:"[",code:"BracketLeft",keyCode:219},Backslash:{key:"\\",code:"Backslash",keyCode:220},BracketRight:{key:"]",code:"BracketRight",keyCode:221},Quote:{key:"'",code:"Quote",keyCode:222}},P=E;var A={INPUT_ZONE:"input-zone",TARGET_ZONE:"target-zone",BUTTON:"button",KEYBOARD_BUTTON:"keyboard-button",MOUSE_BUTTON:"mouse-button",JOYSTICK:"joystick",D_PAD:"d-pad",TRACKPAD:"trackpad",VIRTUAL_CURSOR:"virtual-cursor",ROOT_LAYER:"root-layer"},D={KEYDOWN:"keydown",KEYUP:"keyup",POINTER:"pointer",POINTERMOVE:"pointermove",POINTERDOWN:"pointerdown",POINTERUP:"pointerup",MOUSE:"mouse",MOUSEMOVE:"mousemove",MOUSEDOWN:"mousedown",MOUSEUP:"mouseup",CLICK:"click"},I=["px","%","vh","vw","rem","em"],M={PARENT_ID_KEY:"omnipad-parent-id-link"};var k=Symbol.for("omnipad.registry.instance"),s=null;function _(t){s=t;}var C=class t{constructor(){m(this,"entities",new Map);import.meta.env?.DEV&&console.log("[OmniPad-Core] Registry initialized.");}static getInstance(){let e=globalThis;return e[k]||(e[k]=new t),e[k]}register(e){if(!e.uid){console.warn("[OmniPad-Core] Registry: Attempted to register entity without UID.",e);return}this.entities.has(e.uid),this.entities.set(e.uid,e);}unregister(e){this.entities.has(e)&&this.entities.delete(e);}getEntity(e){return this.entities.get(e)}getAllEntities(){return Array.from(this.entities.values())}getEntitiesByRoot(e){let o=this.getAllEntities();if(!e)return o;if(!this.entities.get(e))return console.warn(`[OmniPad-Core] Registry: Root entity ${e} not found.`),[];let r=new Map;o.forEach(d=>{let a=d;if(typeof a.getConfig=="function"){let i=a.getConfig();i.parentId&&(r.has(i.parentId)||r.set(i.parentId,[]),r.get(i.parentId).push(d));}});let y=[],c=[e],u=new Set;for(;c.length>0;){let d=c.shift();if(u.has(d))continue;u.add(d);let a=this.entities.get(d);if(a){y.push(a);let i=r.get(d);i&&i.forEach(b=>c.push(b.uid));}}return y}destroyByRoot(e){let o=this.getEntitiesByRoot(e);for(let n=o.length-1;n>=0;n--){let r=o[n];try{r.destroy();}catch(y){console.error(`[OmniPad-Core] Error during destroyByRoot at ${r.uid}:`,y);}}}clear(){this.entities.clear();}resetAll(){this.entities.forEach(e=>{"reset"in e&&e.reset();});}markAllRectDirty(){this.entities.forEach(e=>{"markRectDirty"in e&&e.markRectDirty();});}broadcastSignal(e){let o=this.getEntity(e.targetStageId);o&&"handleSignal"in o?o.handleSignal(e):s&&s(e);}};var B=(t,e)=>({x:t.x-e.x,y:t.y-e.y}),v=(t,e)=>({x:t.x+e.x,y:t.y+e.y}),h=(t,e)=>({x:t.x*e,y:t.y*e}),l=(t,e,o)=>Math.max(e,Math.min(o,t)),T=(t,e,o)=>t+(e-t)*o,g=(t,e=2)=>{let o=Math.pow(10,e);return Math.round(t*o)/o},z=(t,e)=>Math.hypot(e.x-t.x,e.y-t.y),Z=(t,e)=>Math.atan2(e.y-t.y,e.x-t.x),q=t=>t*180/Math.PI,G=t=>t*Math.PI/180,H=(t,e,o)=>{let n=e.x-t.x,r=e.y-t.y;if(Math.hypot(n,r)<=o)return e;let c=Math.atan2(r,n);return {x:t.x+Math.cos(c)*o,y:t.y+Math.sin(c)*o}},W=t=>{let e=Math.PI/4;return Math.round(t/e)*e},J=t=>{let e=Math.PI/2;return Math.round(t/e)*e},Q=(t,e)=>g(t*e/100),X=(t,e)=>e===0?0:g(t*100/e),j=t=>{let e=Math.hypot(t.x,t.y);return e===0?{x:0,y:0}:{x:t.x/e,y:t.y/e}},$=t=>({x:Math.cos(t),y:Math.sin(t)}),ee=(t,e,o,n,r)=>{let y=(t-e)/(o-e);return T(n,r,l(y,0,1))},te=(t,e,o=1e-4)=>Math.abs(t.x-e.x)<o&&Math.abs(t.y-e.y)<o,p=(t,e,o)=>{if(t<e)return 0;let n=(t-e)/(o-e);return l(n,0,1)},oe=(t,e,o)=>{let n=Math.hypot(t.x,t.y),r=e*o,y=p(n,r,e);if(y===0)return {x:0,y:0};let c={x:t.x/n,y:t.y/n};return h(c,y)},ne=(t,e,o)=>({x:p(Math.abs(t.x),e,o)*Math.sign(t.x),y:p(Math.abs(t.y),e,o)*Math.sign(t.y)});export{te as A,p as B,oe as C,ne as D,m as a,P as b,A as c,D as d,I as e,M as f,_ as g,C as h,B as i,v as j,h as k,l,T as m,g as n,z as o,Z as p,q,G as r,H as s,W as t,J as u,Q as v,X as w,j as x,$ as y,ee as z};