@react-native-harness/ui 1.0.0-alpha.23 → 1.0.0-alpha.25

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 (64) hide show
  1. package/README.md +25 -11
  2. package/android/src/main/java/com/harnessui/HarnessUIModule.kt +26 -16
  3. package/android/src/main/java/com/harnessui/UIHelperImpl.kt +136 -41
  4. package/android/src/main/java/com/harnessui/ViewQueryHelper.kt +36 -15
  5. package/android/src/main/java/com/harnessui/ViewRegistry.kt +51 -0
  6. package/dist/HarnessUI.d.ts +17 -0
  7. package/dist/HarnessUI.d.ts.map +1 -0
  8. package/dist/HarnessUI.js +2 -0
  9. package/dist/HarnessUI.web.d.ts +14 -0
  10. package/dist/HarnessUI.web.d.ts.map +1 -0
  11. package/dist/HarnessUI.web.js +46 -0
  12. package/dist/NativeHarness.d.ts +22 -0
  13. package/dist/NativeHarness.d.ts.map +1 -0
  14. package/dist/NativeHarness.js +2 -0
  15. package/dist/NativeHarnessUI.d.ts +10 -37
  16. package/dist/NativeHarnessUI.d.ts.map +1 -1
  17. package/dist/WebHarness.d.ts +14 -0
  18. package/dist/WebHarness.d.ts.map +1 -0
  19. package/dist/WebHarness.js +53 -0
  20. package/dist/WebHarnessUI.d.ts +15 -0
  21. package/dist/WebHarnessUI.d.ts.map +1 -0
  22. package/dist/WebHarnessUI.js +81 -0
  23. package/dist/harness/NativeHarness.d.ts +17 -0
  24. package/dist/harness/NativeHarness.d.ts.map +1 -0
  25. package/dist/harness/NativeHarness.js +2 -0
  26. package/dist/harness/WebHarness.d.ts +14 -0
  27. package/dist/harness/WebHarness.d.ts.map +1 -0
  28. package/dist/harness/WebHarness.js +53 -0
  29. package/dist/harness/index.d.ts +4 -0
  30. package/dist/harness/index.d.ts.map +1 -0
  31. package/dist/harness/index.js +8 -0
  32. package/dist/harness/native-harness.d.ts +17 -0
  33. package/dist/harness/native-harness.d.ts.map +1 -0
  34. package/dist/harness/native-harness.js +2 -0
  35. package/dist/harness/web-harness.d.ts +14 -0
  36. package/dist/harness/web-harness.d.ts.map +1 -0
  37. package/dist/harness/web-harness.js +53 -0
  38. package/dist/harness.d.ts +4 -0
  39. package/dist/harness.d.ts.map +1 -0
  40. package/dist/harness.js +8 -0
  41. package/dist/index.d.ts +1 -1
  42. package/dist/index.d.ts.map +1 -1
  43. package/dist/screen.d.ts +9 -7
  44. package/dist/screen.d.ts.map +1 -1
  45. package/dist/screen.js +50 -20
  46. package/dist/tsconfig.lib.tsbuildinfo +1 -1
  47. package/dist/types.d.ts +48 -0
  48. package/dist/types.d.ts.map +1 -0
  49. package/dist/types.js +1 -0
  50. package/dist/userEvent.d.ts.map +1 -1
  51. package/dist/userEvent.js +10 -19
  52. package/ios/HarnessUI.mm +58 -8
  53. package/ios/ViewQueryHelper.h +9 -0
  54. package/ios/ViewQueryHelper.mm +24 -1
  55. package/ios/ViewRegistry.h +8 -0
  56. package/ios/ViewRegistry.mm +33 -0
  57. package/package.json +2 -2
  58. package/src/NativeHarnessUI.ts +11 -45
  59. package/src/WebHarnessUI.ts +113 -0
  60. package/src/harness.ts +12 -0
  61. package/src/index.ts +1 -1
  62. package/src/screen.ts +64 -27
  63. package/src/types.ts +54 -0
  64. package/src/userEvent.ts +10 -19
@@ -0,0 +1,46 @@
1
+ const getElementViewInfo = (element) => {
2
+ const rect = element.getBoundingClientRect();
3
+ return {
4
+ x: rect.left,
5
+ y: rect.top,
6
+ width: rect.width,
7
+ height: rect.height,
8
+ };
9
+ };
10
+ const WebHarnessUI = {
11
+ simulatePress: async (x, y) => {
12
+ await window.__RN_HARNESS_SIMULATE_PRESS__(x, y);
13
+ },
14
+ queryByTestId: (testId) => {
15
+ const element = document.querySelector(`[data-testid="${testId}"]`);
16
+ return element ? getElementViewInfo(element) : null;
17
+ },
18
+ queryAllByTestId: (testId) => {
19
+ const elements = document.querySelectorAll(`[data-testid="${testId}"]`);
20
+ return Array.from(elements).map(getElementViewInfo);
21
+ },
22
+ queryByAccessibilityLabel: (label) => {
23
+ const element = document.querySelector(`[aria-label="${label}"]`);
24
+ return element ? getElementViewInfo(element) : null;
25
+ },
26
+ queryAllByAccessibilityLabel: (label) => {
27
+ const elements = document.querySelectorAll(`[aria-label="${label}"]`);
28
+ return Array.from(elements).map(getElementViewInfo);
29
+ },
30
+ captureScreenshot: async (bounds) => {
31
+ return await window.__RN_HARNESS_CAPTURE_SCREENSHOT__(bounds);
32
+ },
33
+ typeChar: async (character) => {
34
+ await window.__RN_HARNESS_TYPE_CHAR__(character);
35
+ },
36
+ blur: async (options) => {
37
+ // If there is a focused element, blur it directly in the DOM first
38
+ // to trigger local events, then call the runner-side bridge.
39
+ if (document.activeElement instanceof HTMLElement ||
40
+ document.activeElement instanceof SVGElement) {
41
+ document.activeElement.blur();
42
+ }
43
+ await window.__RN_HARNESS_BLUR__(options);
44
+ },
45
+ };
46
+ export default WebHarnessUI;
@@ -0,0 +1,22 @@
1
+ import { type TurboModule } from 'react-native';
2
+ export interface ViewInfo {
3
+ x: number;
4
+ y: number;
5
+ width: number;
6
+ height: number;
7
+ }
8
+ interface Spec extends TurboModule {
9
+ simulatePress(x: number, y: number): Promise<void>;
10
+ queryByTestId(testId: string): ViewInfo | null;
11
+ queryAllByTestId(testId: string): ViewInfo[];
12
+ queryByAccessibilityLabel(label: string): ViewInfo | null;
13
+ queryAllByAccessibilityLabel(label: string): ViewInfo[];
14
+ captureScreenshot(bounds: ViewInfo | null): Promise<string | null>;
15
+ typeChar(character: string): Promise<void>;
16
+ blur(options: {
17
+ submitEditing?: boolean;
18
+ }): Promise<void>;
19
+ }
20
+ declare const _default: Spec;
21
+ export default _default;
22
+ //# sourceMappingURL=NativeHarness.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NativeHarness.d.ts","sourceRoot":"","sources":["../src/NativeHarness.ts"],"names":[],"mappings":"AAAA,OAAO,EAAuB,KAAK,WAAW,EAAE,MAAM,cAAc,CAAC;AAGrE,MAAM,WAAW,QAAQ;IACvB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,UAAU,IAAK,SAAQ,WAAW;IAChC,aAAa,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACnD,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI,CAAC;IAC/C,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,QAAQ,EAAE,CAAC;IAC7C,yBAAyB,CAAC,KAAK,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI,CAAC;IAC1D,4BAA4B,CAAC,KAAK,EAAE,MAAM,GAAG,QAAQ,EAAE,CAAC;IACxD,iBAAiB,CAAC,MAAM,EAAE,QAAQ,GAAG,IAAI,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IACnE,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3C,IAAI,CAAC,OAAO,EAAE;QAAE,aAAa,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3D;;AAED,wBAAmE"}
@@ -0,0 +1,2 @@
1
+ import { TurboModuleRegistry } from 'react-native';
2
+ export default TurboModuleRegistry.getEnforcing('HarnessUI');
@@ -1,59 +1,32 @@
1
1
  import { type TurboModule } from 'react-native';
2
2
  /**
3
- * Represents the position and dimensions of a view in screen coordinates (points/dp).
3
+ * Represents a bounding box in screen coordinates (points/dp).
4
4
  */
5
- export interface ViewInfo {
5
+ export interface BoundingBox {
6
6
  x: number;
7
7
  y: number;
8
8
  width: number;
9
9
  height: number;
10
10
  }
11
+ /**
12
+ * Internal interface used for bridge communication.
13
+ * This needs to be exported for TurboModule codegen.
14
+ */
15
+ export interface ViewInfo extends BoundingBox {
16
+ nativeId: string;
17
+ }
11
18
  interface Spec extends TurboModule {
12
- /**
13
- * Simulates a native press at the specified screen coordinates.
14
- * Returns a promise that resolves when the press action is complete.
15
- */
16
- simulatePress(x: number, y: number): Promise<void>;
17
- /**
18
- * Finds a view by its testID (accessibilityIdentifier on iOS, tag on Android).
19
- * Returns null if no view is found.
20
- */
19
+ simulatePress(nativeId: string, x: number, y: number): Promise<void>;
21
20
  queryByTestId(testId: string): ViewInfo | null;
22
- /**
23
- * Finds all views by testID (accessibilityIdentifier on iOS, tag on Android).
24
- * Returns an empty array if no views are found.
25
- */
26
21
  queryAllByTestId(testId: string): ViewInfo[];
27
- /**
28
- * Finds a view by its accessibility label.
29
- * Returns null if no view is found.
30
- */
31
22
  queryByAccessibilityLabel(label: string): ViewInfo | null;
32
- /**
33
- * Finds all views by accessibility label.
34
- * Returns an empty array if no views are found.
35
- */
36
23
  queryAllByAccessibilityLabel(label: string): ViewInfo[];
37
- /**
38
- * Captures a screenshot of the app UI.
39
- * @param bounds Optional bounds to capture a specific region. Pass null to capture the entire window.
40
- * @returns Promise resolving to Base64 encoded string containing PNG data, or null on failure.
41
- */
42
24
  captureScreenshot(bounds: ViewInfo | null): Promise<string | null>;
43
- /**
44
- * Types a single character into the currently focused text input.
45
- * If no text input is focused, this is a no-op.
46
- */
47
25
  typeChar(character: string): Promise<void>;
48
- /**
49
- * Blurs (resigns first responder from) the currently focused element.
50
- * Optionally triggers submitEditing event before blur.
51
- */
52
26
  blur(options: {
53
27
  submitEditing?: boolean;
54
28
  }): Promise<void>;
55
29
  }
56
- export type HarnessUIModule = Spec;
57
30
  declare const _default: Spec;
58
31
  export default _default;
59
32
  //# sourceMappingURL=NativeHarnessUI.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"NativeHarnessUI.d.ts","sourceRoot":"","sources":["../src/NativeHarnessUI.ts"],"names":[],"mappings":"AAAA,OAAO,EAAuB,KAAK,WAAW,EAAE,MAAM,cAAc,CAAC;AAErE;;GAEG;AACH,MAAM,WAAW,QAAQ;IACvB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,UAAU,IAAK,SAAQ,WAAW;IAChC;;;OAGG;IACH,aAAa,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEnD;;;OAGG;IACH,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI,CAAC;IAE/C;;;OAGG;IACH,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,QAAQ,EAAE,CAAC;IAE7C;;;OAGG;IACH,yBAAyB,CAAC,KAAK,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI,CAAC;IAE1D;;;OAGG;IACH,4BAA4B,CAAC,KAAK,EAAE,MAAM,GAAG,QAAQ,EAAE,CAAC;IAExD;;;;OAIG;IACH,iBAAiB,CAAC,MAAM,EAAE,QAAQ,GAAG,IAAI,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAEnE;;;OAGG;IACH,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAE3C;;;OAGG;IACH,IAAI,CAAC,OAAO,EAAE;QAAE,aAAa,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3D;AAED,MAAM,MAAM,eAAe,GAAG,IAAI,CAAC;;AAEnC,wBAAmE"}
1
+ {"version":3,"file":"NativeHarnessUI.d.ts","sourceRoot":"","sources":["../src/NativeHarnessUI.ts"],"names":[],"mappings":"AAAA,OAAO,EAAuB,KAAK,WAAW,EAAE,MAAM,cAAc,CAAC;AAErE;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;GAGG;AACH,MAAM,WAAW,QAAS,SAAQ,WAAW;IAC3C,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,UAAU,IAAK,SAAQ,WAAW;IAChC,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACrE,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI,CAAC;IAC/C,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,QAAQ,EAAE,CAAC;IAC7C,yBAAyB,CAAC,KAAK,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI,CAAC;IAC1D,4BAA4B,CAAC,KAAK,EAAE,MAAM,GAAG,QAAQ,EAAE,CAAC;IACxD,iBAAiB,CAAC,MAAM,EAAE,QAAQ,GAAG,IAAI,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IACnE,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3C,IAAI,CAAC,OAAO,EAAE;QAAE,aAAa,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3D;;AAED,wBAAmE"}
@@ -0,0 +1,14 @@
1
+ import { type HarnessUIModule, type ViewInfo } from './types.js';
2
+ declare global {
3
+ interface Window {
4
+ __RN_HARNESS_CAPTURE_SCREENSHOT__: (bounds: ViewInfo | null) => Promise<string | null>;
5
+ __RN_HARNESS_SIMULATE_PRESS__: (x: number, y: number) => Promise<void>;
6
+ __RN_HARNESS_TYPE_CHAR__: (character: string) => Promise<void>;
7
+ __RN_HARNESS_BLUR__: (options: {
8
+ submitEditing?: boolean;
9
+ }) => Promise<void>;
10
+ }
11
+ }
12
+ declare const WebHarnessUI: HarnessUIModule;
13
+ export default WebHarnessUI;
14
+ //# sourceMappingURL=WebHarness.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"WebHarness.d.ts","sourceRoot":"","sources":["../src/WebHarness.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,eAAe,EAAE,KAAK,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEjE,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,MAAM;QACd,iCAAiC,EAAE,CACjC,MAAM,EAAE,QAAQ,GAAG,IAAI,KACpB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;QAC5B,6BAA6B,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;QACvE,wBAAwB,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;QAC/D,mBAAmB,EAAE,CAAC,OAAO,EAAE;YAC7B,aAAa,CAAC,EAAE,OAAO,CAAC;SACzB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;KACrB;CACF;AAYD,QAAA,MAAM,YAAY,EAAE,eAkDnB,CAAC;AAEF,eAAe,YAAY,CAAC"}
@@ -0,0 +1,53 @@
1
+ const getElementViewInfo = (element) => {
2
+ const rect = element.getBoundingClientRect();
3
+ return {
4
+ x: rect.left,
5
+ y: rect.top,
6
+ width: rect.width,
7
+ height: rect.height,
8
+ };
9
+ };
10
+ const WebHarnessUI = {
11
+ simulatePress: async (x, y) => {
12
+ await window.__RN_HARNESS_SIMULATE_PRESS__(x, y);
13
+ },
14
+ queryByTestId: (testId) => {
15
+ const element = document.querySelector(`[data-testid="${testId}"]`);
16
+ return element ? getElementViewInfo(element) : null;
17
+ },
18
+ queryAllByTestId: (testId) => {
19
+ const elements = document.querySelectorAll(`[data-testid="${testId}"]`);
20
+ return Array.from(elements).map(getElementViewInfo);
21
+ },
22
+ queryByAccessibilityLabel: (label) => {
23
+ const element = document.querySelector(`[aria-label="${label}"]`);
24
+ return element ? getElementViewInfo(element) : null;
25
+ },
26
+ queryAllByAccessibilityLabel: (label) => {
27
+ const elements = document.querySelectorAll(`[aria-label="${label}"]`);
28
+ return Array.from(elements).map(getElementViewInfo);
29
+ },
30
+ captureScreenshot: async (bounds) => {
31
+ return await window.__RN_HARNESS_CAPTURE_SCREENSHOT__(bounds);
32
+ },
33
+ typeChar: async (character) => {
34
+ await window.__RN_HARNESS_TYPE_CHAR__(character);
35
+ },
36
+ blur: async (options) => {
37
+ if (options.submitEditing) {
38
+ // If we want to submit, we must NOT blur before pressing Enter.
39
+ // We let the runner-side bridge handle both Enter and the subsequent blur.
40
+ await window.__RN_HARNESS_BLUR__(options);
41
+ }
42
+ else {
43
+ // If there is a focused element, blur it directly in the DOM first
44
+ // to trigger local events, then call the runner-side bridge.
45
+ if (document.activeElement instanceof HTMLElement ||
46
+ document.activeElement instanceof SVGElement) {
47
+ document.activeElement.blur();
48
+ }
49
+ await window.__RN_HARNESS_BLUR__(options);
50
+ }
51
+ },
52
+ };
53
+ export default WebHarnessUI;
@@ -0,0 +1,15 @@
1
+ import { type HarnessUIModule, type ViewInfo } from './types.js';
2
+ declare global {
3
+ interface Window {
4
+ __RN_HARNESS_CAPTURE_SCREENSHOT__: (bounds: ViewInfo | null) => Promise<string | null>;
5
+ __RN_HARNESS_SIMULATE_PRESS__: (x: number, y: number) => Promise<void>;
6
+ __RN_HARNESS_TYPE_CHAR__: (character: string) => Promise<void>;
7
+ __RN_HARNESS_BLUR__: (options: {
8
+ submitEditing?: boolean;
9
+ }) => Promise<void>;
10
+ __RN_HARNESS_VIEW_REGISTRY__: Map<string, Element>;
11
+ }
12
+ }
13
+ declare const WebHarnessUI: HarnessUIModule;
14
+ export default WebHarnessUI;
15
+ //# sourceMappingURL=WebHarnessUI.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"WebHarnessUI.d.ts","sourceRoot":"","sources":["../src/WebHarnessUI.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,eAAe,EAAE,KAAK,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEjE,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,MAAM;QACd,iCAAiC,EAAE,CACjC,MAAM,EAAE,QAAQ,GAAG,IAAI,KACpB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;QAC5B,6BAA6B,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;QACvE,wBAAwB,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;QAC/D,mBAAmB,EAAE,CAAC,OAAO,EAAE;YAC7B,aAAa,CAAC,EAAE,OAAO,CAAC;SACzB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;QACpB,4BAA4B,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;KACpD;CACF;AA2BD,QAAA,MAAM,YAAY,EAAE,eAqEnB,CAAC;AAEF,eAAe,YAAY,CAAC"}
@@ -0,0 +1,81 @@
1
+ if (!window.__RN_HARNESS_VIEW_REGISTRY__) {
2
+ window.__RN_HARNESS_VIEW_REGISTRY__ = new Map();
3
+ }
4
+ let nextId = 1;
5
+ const getElementViewInfo = (element) => {
6
+ const rect = element.getBoundingClientRect();
7
+ let nativeId = element.__harnessId;
8
+ if (!nativeId) {
9
+ nativeId = `view_${nextId++}`;
10
+ element.__harnessId = nativeId;
11
+ window.__RN_HARNESS_VIEW_REGISTRY__.set(nativeId, element);
12
+ }
13
+ return {
14
+ x: rect.left,
15
+ y: rect.top,
16
+ width: rect.width,
17
+ height: rect.height,
18
+ nativeId,
19
+ };
20
+ };
21
+ const WebHarnessUI = {
22
+ simulatePress: async (nativeId, x, y) => {
23
+ let targetX = x;
24
+ let targetY = y;
25
+ if (nativeId) {
26
+ const element = window.__RN_HARNESS_VIEW_REGISTRY__.get(nativeId);
27
+ if (element) {
28
+ const rect = element.getBoundingClientRect();
29
+ targetX = rect.left + rect.width / 2;
30
+ targetY = rect.top + rect.height / 2;
31
+ }
32
+ }
33
+ await window.__RN_HARNESS_SIMULATE_PRESS__(targetX, targetY);
34
+ },
35
+ queryByTestId: (testId) => {
36
+ const element = document.querySelector(`[data-testid="${testId}"]`);
37
+ return element ? getElementViewInfo(element) : null;
38
+ },
39
+ queryAllByTestId: (testId) => {
40
+ const elements = document.querySelectorAll(`[data-testid="${testId}"]`);
41
+ return Array.from(elements).map(getElementViewInfo);
42
+ },
43
+ queryByAccessibilityLabel: (label) => {
44
+ const element = document.querySelector(`[aria-label="${label}"]`);
45
+ return element ? getElementViewInfo(element) : null;
46
+ },
47
+ queryAllByAccessibilityLabel: (label) => {
48
+ const elements = document.querySelectorAll(`[aria-label="${label}"]`);
49
+ return Array.from(elements).map(getElementViewInfo);
50
+ },
51
+ captureScreenshot: async (bounds) => {
52
+ let captureBounds = bounds;
53
+ if (bounds?.nativeId && bounds.width === 0 && bounds.height === 0) {
54
+ const element = window.__RN_HARNESS_VIEW_REGISTRY__.get(bounds.nativeId);
55
+ if (element) {
56
+ captureBounds = getElementViewInfo(element);
57
+ }
58
+ }
59
+ return await window.__RN_HARNESS_CAPTURE_SCREENSHOT__(captureBounds);
60
+ },
61
+ typeChar: async (character) => {
62
+ await window.__RN_HARNESS_TYPE_CHAR__(character);
63
+ },
64
+ blur: async (options) => {
65
+ if (options.submitEditing) {
66
+ // If we want to submit, we must NOT blur before pressing Enter.
67
+ // We let the runner-side bridge handle both Enter and the subsequent blur.
68
+ await window.__RN_HARNESS_BLUR__(options);
69
+ }
70
+ else {
71
+ // If there is a focused element, blur it directly in the DOM first
72
+ // to trigger local events, then call the runner-side bridge.
73
+ if (document.activeElement instanceof HTMLElement ||
74
+ document.activeElement instanceof SVGElement) {
75
+ document.activeElement.blur();
76
+ }
77
+ await window.__RN_HARNESS_BLUR__(options);
78
+ }
79
+ },
80
+ };
81
+ export default WebHarnessUI;
@@ -0,0 +1,17 @@
1
+ import { type TurboModule } from 'react-native';
2
+ import { type ViewInfo } from '../types.js';
3
+ interface Spec extends TurboModule {
4
+ simulatePress(x: number, y: number): Promise<void>;
5
+ queryByTestId(testId: string): ViewInfo | null;
6
+ queryAllByTestId(testId: string): ViewInfo[];
7
+ queryByAccessibilityLabel(label: string): ViewInfo | null;
8
+ queryAllByAccessibilityLabel(label: string): ViewInfo[];
9
+ captureScreenshot(bounds: ViewInfo | null): Promise<string | null>;
10
+ typeChar(character: string): Promise<void>;
11
+ blur(options: {
12
+ submitEditing?: boolean;
13
+ }): Promise<void>;
14
+ }
15
+ declare const _default: Spec;
16
+ export default _default;
17
+ //# sourceMappingURL=NativeHarness.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NativeHarness.d.ts","sourceRoot":"","sources":["../../src/harness/NativeHarness.ts"],"names":[],"mappings":"AAAA,OAAO,EAAuB,KAAK,WAAW,EAAE,MAAM,cAAc,CAAC;AACrE,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,aAAa,CAAC;AAE5C,UAAU,IAAK,SAAQ,WAAW;IAChC,aAAa,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACnD,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI,CAAC;IAC/C,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,QAAQ,EAAE,CAAC;IAC7C,yBAAyB,CAAC,KAAK,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI,CAAC;IAC1D,4BAA4B,CAAC,KAAK,EAAE,MAAM,GAAG,QAAQ,EAAE,CAAC;IACxD,iBAAiB,CAAC,MAAM,EAAE,QAAQ,GAAG,IAAI,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IACnE,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3C,IAAI,CAAC,OAAO,EAAE;QAAE,aAAa,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3D;;AAED,wBAAmE"}
@@ -0,0 +1,2 @@
1
+ import { TurboModuleRegistry } from 'react-native';
2
+ export default TurboModuleRegistry.getEnforcing('HarnessUI');
@@ -0,0 +1,14 @@
1
+ import { type HarnessUIModule, type ViewInfo } from '../types.js';
2
+ declare global {
3
+ interface Window {
4
+ __RN_HARNESS_CAPTURE_SCREENSHOT__: (bounds: ViewInfo | null) => Promise<string | null>;
5
+ __RN_HARNESS_SIMULATE_PRESS__: (x: number, y: number) => Promise<void>;
6
+ __RN_HARNESS_TYPE_CHAR__: (character: string) => Promise<void>;
7
+ __RN_HARNESS_BLUR__: (options: {
8
+ submitEditing?: boolean;
9
+ }) => Promise<void>;
10
+ }
11
+ }
12
+ declare const WebHarnessUI: HarnessUIModule;
13
+ export default WebHarnessUI;
14
+ //# sourceMappingURL=WebHarness.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"WebHarness.d.ts","sourceRoot":"","sources":["../../src/harness/WebHarness.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,eAAe,EAAE,KAAK,QAAQ,EAAE,MAAM,aAAa,CAAC;AAElE,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,MAAM;QACd,iCAAiC,EAAE,CACjC,MAAM,EAAE,QAAQ,GAAG,IAAI,KACpB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;QAC5B,6BAA6B,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;QACvE,wBAAwB,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;QAC/D,mBAAmB,EAAE,CAAC,OAAO,EAAE;YAC7B,aAAa,CAAC,EAAE,OAAO,CAAC;SACzB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;KACrB;CACF;AAYD,QAAA,MAAM,YAAY,EAAE,eAkDnB,CAAC;AAEF,eAAe,YAAY,CAAC"}
@@ -0,0 +1,53 @@
1
+ const getElementViewInfo = (element) => {
2
+ const rect = element.getBoundingClientRect();
3
+ return {
4
+ x: rect.left,
5
+ y: rect.top,
6
+ width: rect.width,
7
+ height: rect.height,
8
+ };
9
+ };
10
+ const WebHarnessUI = {
11
+ simulatePress: async (x, y) => {
12
+ await window.__RN_HARNESS_SIMULATE_PRESS__(x, y);
13
+ },
14
+ queryByTestId: (testId) => {
15
+ const element = document.querySelector(`[data-testid="${testId}"]`);
16
+ return element ? getElementViewInfo(element) : null;
17
+ },
18
+ queryAllByTestId: (testId) => {
19
+ const elements = document.querySelectorAll(`[data-testid="${testId}"]`);
20
+ return Array.from(elements).map(getElementViewInfo);
21
+ },
22
+ queryByAccessibilityLabel: (label) => {
23
+ const element = document.querySelector(`[aria-label="${label}"]`);
24
+ return element ? getElementViewInfo(element) : null;
25
+ },
26
+ queryAllByAccessibilityLabel: (label) => {
27
+ const elements = document.querySelectorAll(`[aria-label="${label}"]`);
28
+ return Array.from(elements).map(getElementViewInfo);
29
+ },
30
+ captureScreenshot: async (bounds) => {
31
+ return await window.__RN_HARNESS_CAPTURE_SCREENSHOT__(bounds);
32
+ },
33
+ typeChar: async (character) => {
34
+ await window.__RN_HARNESS_TYPE_CHAR__(character);
35
+ },
36
+ blur: async (options) => {
37
+ if (options.submitEditing) {
38
+ // If we want to submit, we must NOT blur before pressing Enter.
39
+ // We let the runner-side bridge handle both Enter and the subsequent blur.
40
+ await window.__RN_HARNESS_BLUR__(options);
41
+ }
42
+ else {
43
+ // If there is a focused element, blur it directly in the DOM first
44
+ // to trigger local events, then call the runner-side bridge.
45
+ if (document.activeElement instanceof HTMLElement ||
46
+ document.activeElement instanceof SVGElement) {
47
+ document.activeElement.blur();
48
+ }
49
+ await window.__RN_HARNESS_BLUR__(options);
50
+ }
51
+ },
52
+ };
53
+ export default WebHarnessUI;
@@ -0,0 +1,4 @@
1
+ import { HarnessUIModule } from "../types.js";
2
+ declare const _default: HarnessUIModule;
3
+ export default _default;
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/harness/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;;AAU9C,wBAA8B"}
@@ -0,0 +1,8 @@
1
+ import { Platform } from "react-native";
2
+ const getHarnessUI = () => {
3
+ if (Platform.OS === 'web') {
4
+ return require('./WebHarness.js').default;
5
+ }
6
+ return require('./NativeHarness.js').default;
7
+ };
8
+ export default getHarnessUI();
@@ -0,0 +1,17 @@
1
+ import { type TurboModule } from 'react-native';
2
+ import { type ViewInfo } from '../types.js';
3
+ interface Spec extends TurboModule {
4
+ simulatePress(x: number, y: number): Promise<void>;
5
+ queryByTestId(testId: string): ViewInfo | null;
6
+ queryAllByTestId(testId: string): ViewInfo[];
7
+ queryByAccessibilityLabel(label: string): ViewInfo | null;
8
+ queryAllByAccessibilityLabel(label: string): ViewInfo[];
9
+ captureScreenshot(bounds: ViewInfo | null): Promise<string | null>;
10
+ typeChar(character: string): Promise<void>;
11
+ blur(options: {
12
+ submitEditing?: boolean;
13
+ }): Promise<void>;
14
+ }
15
+ declare const _default: Spec;
16
+ export default _default;
17
+ //# sourceMappingURL=native-harness.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"native-harness.d.ts","sourceRoot":"","sources":["../../src/harness/native-harness.ts"],"names":[],"mappings":"AAAA,OAAO,EAAuB,KAAK,WAAW,EAAE,MAAM,cAAc,CAAC;AACrE,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,aAAa,CAAC;AAE5C,UAAU,IAAK,SAAQ,WAAW;IAChC,aAAa,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACnD,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI,CAAC;IAC/C,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,QAAQ,EAAE,CAAC;IAC7C,yBAAyB,CAAC,KAAK,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI,CAAC;IAC1D,4BAA4B,CAAC,KAAK,EAAE,MAAM,GAAG,QAAQ,EAAE,CAAC;IACxD,iBAAiB,CAAC,MAAM,EAAE,QAAQ,GAAG,IAAI,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IACnE,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3C,IAAI,CAAC,OAAO,EAAE;QAAE,aAAa,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3D;;AAED,wBAAmE"}
@@ -0,0 +1,2 @@
1
+ import { TurboModuleRegistry } from 'react-native';
2
+ export default TurboModuleRegistry.getEnforcing('HarnessUI');
@@ -0,0 +1,14 @@
1
+ import { type HarnessUIModule, type ViewInfo } from '../types.js';
2
+ declare global {
3
+ interface Window {
4
+ __RN_HARNESS_CAPTURE_SCREENSHOT__: (bounds: ViewInfo | null) => Promise<string | null>;
5
+ __RN_HARNESS_SIMULATE_PRESS__: (x: number, y: number) => Promise<void>;
6
+ __RN_HARNESS_TYPE_CHAR__: (character: string) => Promise<void>;
7
+ __RN_HARNESS_BLUR__: (options: {
8
+ submitEditing?: boolean;
9
+ }) => Promise<void>;
10
+ }
11
+ }
12
+ declare const WebHarnessUI: HarnessUIModule;
13
+ export default WebHarnessUI;
14
+ //# sourceMappingURL=web-harness.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"web-harness.d.ts","sourceRoot":"","sources":["../../src/harness/web-harness.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,eAAe,EAAE,KAAK,QAAQ,EAAE,MAAM,aAAa,CAAC;AAElE,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,MAAM;QACd,iCAAiC,EAAE,CACjC,MAAM,EAAE,QAAQ,GAAG,IAAI,KACpB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;QAC5B,6BAA6B,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;QACvE,wBAAwB,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;QAC/D,mBAAmB,EAAE,CAAC,OAAO,EAAE;YAC7B,aAAa,CAAC,EAAE,OAAO,CAAC;SACzB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;KACrB;CACF;AAYD,QAAA,MAAM,YAAY,EAAE,eAkDnB,CAAC;AAEF,eAAe,YAAY,CAAC"}
@@ -0,0 +1,53 @@
1
+ const getElementViewInfo = (element) => {
2
+ const rect = element.getBoundingClientRect();
3
+ return {
4
+ x: rect.left,
5
+ y: rect.top,
6
+ width: rect.width,
7
+ height: rect.height,
8
+ };
9
+ };
10
+ const WebHarnessUI = {
11
+ simulatePress: async (x, y) => {
12
+ await window.__RN_HARNESS_SIMULATE_PRESS__(x, y);
13
+ },
14
+ queryByTestId: (testId) => {
15
+ const element = document.querySelector(`[data-testid="${testId}"]`);
16
+ return element ? getElementViewInfo(element) : null;
17
+ },
18
+ queryAllByTestId: (testId) => {
19
+ const elements = document.querySelectorAll(`[data-testid="${testId}"]`);
20
+ return Array.from(elements).map(getElementViewInfo);
21
+ },
22
+ queryByAccessibilityLabel: (label) => {
23
+ const element = document.querySelector(`[aria-label="${label}"]`);
24
+ return element ? getElementViewInfo(element) : null;
25
+ },
26
+ queryAllByAccessibilityLabel: (label) => {
27
+ const elements = document.querySelectorAll(`[aria-label="${label}"]`);
28
+ return Array.from(elements).map(getElementViewInfo);
29
+ },
30
+ captureScreenshot: async (bounds) => {
31
+ return await window.__RN_HARNESS_CAPTURE_SCREENSHOT__(bounds);
32
+ },
33
+ typeChar: async (character) => {
34
+ await window.__RN_HARNESS_TYPE_CHAR__(character);
35
+ },
36
+ blur: async (options) => {
37
+ if (options.submitEditing) {
38
+ // If we want to submit, we must NOT blur before pressing Enter.
39
+ // We let the runner-side bridge handle both Enter and the subsequent blur.
40
+ await window.__RN_HARNESS_BLUR__(options);
41
+ }
42
+ else {
43
+ // If there is a focused element, blur it directly in the DOM first
44
+ // to trigger local events, then call the runner-side bridge.
45
+ if (document.activeElement instanceof HTMLElement ||
46
+ document.activeElement instanceof SVGElement) {
47
+ document.activeElement.blur();
48
+ }
49
+ await window.__RN_HARNESS_BLUR__(options);
50
+ }
51
+ },
52
+ };
53
+ export default WebHarnessUI;
@@ -0,0 +1,4 @@
1
+ import { HarnessUIModule } from "./types.js";
2
+ declare const _default: HarnessUIModule;
3
+ export default _default;
4
+ //# sourceMappingURL=harness.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"harness.d.ts","sourceRoot":"","sources":["../src/harness.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;;AAU7C,wBAA8B"}
@@ -0,0 +1,8 @@
1
+ import { Platform } from "react-native";
2
+ const getHarnessUI = () => {
3
+ if (Platform.OS === 'web') {
4
+ return require('./WebHarnessUI.js').default;
5
+ }
6
+ return require('./NativeHarnessUI.js').default;
7
+ };
8
+ export default getHarnessUI();
package/dist/index.d.ts CHANGED
@@ -9,5 +9,5 @@
9
9
  */
10
10
  export { screen, type Screen, type ElementReference, type ScreenshotResult, } from './screen.js';
11
11
  export { userEvent, type UserEvent } from './userEvent.js';
12
- export type { ViewInfo } from './NativeHarnessUI.js';
12
+ export type { ViewInfo, BoundingBox } from './types.js';
13
13
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EACL,MAAM,EACN,KAAK,MAAM,EACX,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,GACtB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,SAAS,EAAE,KAAK,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3D,YAAY,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EACL,MAAM,EACN,KAAK,MAAM,EACX,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,GACtB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,SAAS,EAAE,KAAK,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3D,YAAY,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC"}
package/dist/screen.d.ts CHANGED
@@ -1,9 +1,11 @@
1
- import { type ViewInfo } from './NativeHarnessUI.js';
1
+ import { type BoundingBox } from './types.js';
2
2
  /**
3
- * Represents an element found on screen with its position and dimensions.
4
- * This can be used with userEvent.press() to interact with the element.
3
+ * Represents an element found on screen.
4
+ * This is an opaque reference that can be used with userEvent or screenshot.
5
5
  */
6
- export type ElementReference = ViewInfo;
6
+ export type ElementReference = {
7
+ readonly nativeId: string;
8
+ };
7
9
  /**
8
10
  * Screenshot result containing PNG image data.
9
11
  */
@@ -57,11 +59,11 @@ export type Screen = {
57
59
  */
58
60
  queryAllByAccessibilityLabel: (label: string) => ElementReference[];
59
61
  /**
60
- * Captures a screenshot of the entire app window or a specific element.
61
- * @param element Optional element reference to capture. If not provided, captures the entire window.
62
+ * Captures a screenshot of the entire app window, a specific element, or a region.
63
+ * @param target Optional element reference or bounding box to capture. If not provided, captures the entire window.
62
64
  * @returns Promise resolving to ScreenshotResult with PNG data, or null if capture fails.
63
65
  */
64
- screenshot: (element?: ElementReference) => Promise<ScreenshotResult | null>;
66
+ screenshot: (target?: ElementReference | BoundingBox) => Promise<ScreenshotResult | null>;
65
67
  };
66
68
  export declare const screen: Screen;
67
69
  //# sourceMappingURL=screen.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"screen.d.ts","sourceRoot":"","sources":["../src/screen.ts"],"names":[],"mappings":"AAAA,OAAwB,EAAE,KAAK,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAGtE;;;GAGG;AACH,MAAM,MAAM,gBAAgB,GAAG,QAAQ,CAAC;AAExC;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,sDAAsD;IACtD,IAAI,EAAE,UAAU,CAAC;IACjB,gEAAgE;IAChE,KAAK,EAAE,MAAM,CAAC;IACd,iEAAiE;IACjE,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,MAAM,MAAM,GAAG;IACnB;;;OAGG;IACH,YAAY,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,gBAAgB,CAAC,CAAC;IAE5D;;;OAGG;IACH,eAAe,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAAC;IAEjE;;;OAGG;IACH,aAAa,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,gBAAgB,GAAG,IAAI,CAAC;IAE3D;;;OAGG;IACH,gBAAgB,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,gBAAgB,EAAE,CAAC;IAEzD;;;OAGG;IACH,wBAAwB,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,gBAAgB,CAAC,CAAC;IAEvE;;;OAGG;IACH,2BAA2B,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAAC;IAE5E;;;OAGG;IACH,yBAAyB,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,gBAAgB,GAAG,IAAI,CAAC;IAEtE;;;OAGG;IACH,4BAA4B,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,gBAAgB,EAAE,CAAC;IAEpE;;;;OAIG;IACH,UAAU,EAAE,CAAC,OAAO,CAAC,EAAE,gBAAgB,KAAK,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAAC;CAC9E,CAAC;AAkGF,eAAO,MAAM,MAAM,QAAiB,CAAC"}
1
+ {"version":3,"file":"screen.d.ts","sourceRoot":"","sources":["../src/screen.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiB,KAAK,WAAW,EAAE,MAAM,YAAY,CAAC;AAI7D;;;GAGG;AACH,MAAM,MAAM,gBAAgB,GAAG;IAC7B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B,CAAC;AAMF;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,sDAAsD;IACtD,IAAI,EAAE,UAAU,CAAC;IACjB,gEAAgE;IAChE,KAAK,EAAE,MAAM,CAAC;IACd,iEAAiE;IACjE,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,MAAM,MAAM,GAAG;IACnB;;;OAGG;IACH,YAAY,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,gBAAgB,CAAC,CAAC;IAE5D;;;OAGG;IACH,eAAe,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAAC;IAEjE;;;OAGG;IACH,aAAa,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,gBAAgB,GAAG,IAAI,CAAC;IAE3D;;;OAGG;IACH,gBAAgB,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,gBAAgB,EAAE,CAAC;IAEzD;;;OAGG;IACH,wBAAwB,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,gBAAgB,CAAC,CAAC;IAEvE;;;OAGG;IACH,2BAA2B,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAAC;IAE5E;;;OAGG;IACH,yBAAyB,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,gBAAgB,GAAG,IAAI,CAAC;IAEtE;;;OAGG;IACH,4BAA4B,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,gBAAgB,EAAE,CAAC;IAEpE;;;;OAIG;IACH,UAAU,EAAE,CACV,MAAM,CAAC,EAAE,gBAAgB,GAAG,WAAW,KACpC,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAAC;CACvC,CAAC;AA8HF,eAAO,MAAM,MAAM,QAAiB,CAAC"}