react-native-tapline 0.0.0-stage → 1.1.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.
Files changed (88) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +86 -2
  3. package/TaplineNative.podspec +14 -0
  4. package/dist/actions.d.ts +203 -0
  5. package/dist/actions.js +1991 -0
  6. package/dist/actions.js.map +1 -0
  7. package/dist/agent.d.ts +117 -0
  8. package/dist/agent.js +352 -0
  9. package/dist/agent.js.map +1 -0
  10. package/dist/alerts.d.ts +35 -0
  11. package/dist/alerts.js +437 -0
  12. package/dist/alerts.js.map +1 -0
  13. package/dist/awake.d.ts +2 -0
  14. package/dist/awake.js +53 -0
  15. package/dist/awake.js.map +1 -0
  16. package/dist/checks.d.ts +35 -0
  17. package/dist/checks.js +501 -0
  18. package/dist/checks.js.map +1 -0
  19. package/dist/client.d.ts +111 -0
  20. package/dist/client.js +446 -0
  21. package/dist/client.js.map +1 -0
  22. package/dist/commands.d.ts +24 -0
  23. package/dist/commands.js +111 -0
  24. package/dist/commands.js.map +1 -0
  25. package/dist/events.d.ts +5 -0
  26. package/dist/events.js +22 -0
  27. package/dist/events.js.map +1 -0
  28. package/dist/feed.d.ts +117 -0
  29. package/dist/feed.js +440 -0
  30. package/dist/feed.js.map +1 -0
  31. package/dist/fiber.d.ts +43 -0
  32. package/dist/fiber.js +100 -0
  33. package/dist/fiber.js.map +1 -0
  34. package/dist/index.d.ts +50 -0
  35. package/dist/index.js +181 -0
  36. package/dist/index.js.map +1 -0
  37. package/dist/inspect.d.ts +249 -0
  38. package/dist/inspect.js +1354 -0
  39. package/dist/inspect.js.map +1 -0
  40. package/dist/keyboard.d.ts +10 -0
  41. package/dist/keyboard.js +63 -0
  42. package/dist/keyboard.js.map +1 -0
  43. package/dist/link.d.ts +21 -0
  44. package/dist/link.js +63 -0
  45. package/dist/link.js.map +1 -0
  46. package/dist/live.d.ts +30 -0
  47. package/dist/live.js +279 -0
  48. package/dist/live.js.map +1 -0
  49. package/dist/logs.d.ts +16 -0
  50. package/dist/logs.js +171 -0
  51. package/dist/logs.js.map +1 -0
  52. package/dist/methods.d.ts +3 -0
  53. package/dist/methods.js +49 -0
  54. package/dist/methods.js.map +1 -0
  55. package/dist/native.d.ts +34 -0
  56. package/dist/native.js +63 -0
  57. package/dist/native.js.map +1 -0
  58. package/dist/network.d.ts +27 -0
  59. package/dist/network.js +238 -0
  60. package/dist/network.js.map +1 -0
  61. package/dist/register.d.ts +24 -0
  62. package/dist/register.js +180 -0
  63. package/dist/register.js.map +1 -0
  64. package/dist/settle.d.ts +27 -0
  65. package/dist/settle.js +70 -0
  66. package/dist/settle.js.map +1 -0
  67. package/dist/source.d.ts +60 -0
  68. package/dist/source.js +214 -0
  69. package/dist/source.js.map +1 -0
  70. package/dist/storage.d.ts +10 -0
  71. package/dist/storage.js +45 -0
  72. package/dist/storage.js.map +1 -0
  73. package/dist/touches.d.ts +15 -0
  74. package/dist/touches.js +89 -0
  75. package/dist/touches.js.map +1 -0
  76. package/dist/types.d.ts +168 -0
  77. package/dist/types.js +32 -0
  78. package/dist/types.js.map +1 -0
  79. package/dist/wait.d.ts +8 -0
  80. package/dist/wait.js +99 -0
  81. package/dist/wait.js.map +1 -0
  82. package/expo-module.config.json +7 -0
  83. package/ios/TaplineNativeModule.swift +79 -0
  84. package/metro.d.ts +26 -0
  85. package/metro.js +146 -0
  86. package/package.json +100 -4
  87. package/register.d.ts +1 -0
  88. package/register.js +3 -0
package/dist/checks.js ADDED
@@ -0,0 +1,501 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AUDIT_TYPES = void 0;
4
+ exports.checkLayout = checkLayout;
5
+ exports.auditScreen = auditScreen;
6
+ const react_native_1 = require("react-native");
7
+ const fiber_1 = require("./fiber");
8
+ const inspect_1 = require("./inspect");
9
+ const types_1 = require("./types");
10
+ /** Apple's and Google's minimum tap target, in points. */
11
+ const MIN_TARGET = 44;
12
+ /** How far past a screen edge an element may run before it counts as cut off, in points. */
13
+ const EDGE_SLACK = 1;
14
+ /** Fraction of the smaller frame that two elements may share before they count as overlapping. */
15
+ const OVERLAP_LIMIT = 0.25;
16
+ const NORMAL_CONTRAST = 4.5;
17
+ const LARGE_CONTRAST = 3;
18
+ const DEFAULT_FONT_SIZE = 14;
19
+ /** Average glyph width as a fraction of the font size; a rough estimate on purpose. */
20
+ const AVERAGE_GLYPH_WIDTH = 0.5;
21
+ /* -------------------------------------------------------------------------- */
22
+ /* Helpers */
23
+ /* -------------------------------------------------------------------------- */
24
+ function num(value) {
25
+ return String(Number(value.toFixed(1)));
26
+ }
27
+ function flatStyle(style) {
28
+ if (style === undefined || style === null || typeof style === 'function')
29
+ return {};
30
+ try {
31
+ const flat = react_native_1.StyleSheet.flatten(style);
32
+ return (0, types_1.isRecord)(flat) ? flat : {};
33
+ }
34
+ catch {
35
+ return {};
36
+ }
37
+ }
38
+ function isTapTarget(entry) {
39
+ return entry.info.actions.some((action) => action === 'press' || action === 'longPress' || action === 'toggle');
40
+ }
41
+ function hitSlopOf(node) {
42
+ const raw = (0, inspect_1.findProp)(node, 'hitSlop');
43
+ if (typeof raw === 'number' && Number.isFinite(raw))
44
+ return { top: raw, bottom: raw, left: raw, right: raw };
45
+ const side = (key) => {
46
+ const value = (0, types_1.isRecord)(raw) ? raw[key] : undefined;
47
+ return typeof value === 'number' && Number.isFinite(value) ? value : 0;
48
+ };
49
+ return { top: side('top'), bottom: side('bottom'), left: side('left'), right: side('right') };
50
+ }
51
+ function isAncestor(nodes, ancestor, node) {
52
+ for (let p = node.parent; p >= 0;) {
53
+ if (p === ancestor.index)
54
+ return true;
55
+ const next = nodes[p];
56
+ if (!next)
57
+ return false;
58
+ p = next.parent;
59
+ }
60
+ return false;
61
+ }
62
+ function intersectionArea(a, b) {
63
+ const width = Math.min(a.x + a.width, b.x + b.width) - Math.max(a.x, b.x);
64
+ const height = Math.min(a.y + a.height, b.y + b.height) - Math.max(a.y, b.y);
65
+ return width > 0 && height > 0 ? width * height : 0;
66
+ }
67
+ const NAMED_COLORS = {
68
+ black: { r: 0, g: 0, b: 0, a: 1 },
69
+ white: { r: 255, g: 255, b: 255, a: 1 },
70
+ transparent: { r: 0, g: 0, b: 0, a: 0 },
71
+ red: { r: 255, g: 0, b: 0, a: 1 },
72
+ green: { r: 0, g: 128, b: 0, a: 1 },
73
+ blue: { r: 0, g: 0, b: 255, a: 1 },
74
+ gray: { r: 128, g: 128, b: 128, a: 1 },
75
+ grey: { r: 128, g: 128, b: 128, a: 1 },
76
+ };
77
+ function parseHex(hex) {
78
+ if (!/^[0-9a-f]+$/.test(hex))
79
+ return null;
80
+ const long = hex.length === 3 || hex.length === 4 ? hex.replace(/./g, (c) => c + c) : hex;
81
+ if (long.length !== 6 && long.length !== 8)
82
+ return null;
83
+ const byte = (i) => parseInt(long.slice(i, i + 2), 16);
84
+ return { r: byte(0), g: byte(2), b: byte(4), a: long.length === 8 ? byte(6) / 255 : 1 };
85
+ }
86
+ function parseFunctional(body) {
87
+ const parts = body.split(/[\s,/]+/).filter((part) => part !== '');
88
+ if (parts.length !== 3 && parts.length !== 4)
89
+ return null;
90
+ const channels = parts.slice(0, 3).map((part) => Number(part));
91
+ if (channels.some((value) => !Number.isFinite(value)))
92
+ return null;
93
+ let alpha = 1;
94
+ const rawAlpha = parts[3];
95
+ if (rawAlpha !== undefined) {
96
+ alpha = rawAlpha.endsWith('%') ? Number(rawAlpha.slice(0, -1)) / 100 : Number(rawAlpha);
97
+ if (!Number.isFinite(alpha))
98
+ return null;
99
+ }
100
+ const clamp = (value) => Math.min(255, Math.max(0, Math.round(value)));
101
+ return {
102
+ r: clamp(channels[0] ?? 0),
103
+ g: clamp(channels[1] ?? 0),
104
+ b: clamp(channels[2] ?? 0),
105
+ a: Math.min(1, Math.max(0, alpha)),
106
+ };
107
+ }
108
+ /** A colour as RGBA, or null when it is not one this module understands (PlatformColor, hsl(), ...). */
109
+ function parseColor(value) {
110
+ if (typeof value === 'number') {
111
+ if (!Number.isInteger(value) || value < -0x80000000 || value > 0xffffffff)
112
+ return null;
113
+ const argb = value >>> 0;
114
+ return { r: (argb >>> 16) & 0xff, g: (argb >>> 8) & 0xff, b: argb & 0xff, a: (argb >>> 24) / 255 };
115
+ }
116
+ if (typeof value !== 'string')
117
+ return null;
118
+ const text = value.trim().toLowerCase();
119
+ const named = NAMED_COLORS[text];
120
+ if (named)
121
+ return { ...named };
122
+ if (text.startsWith('#'))
123
+ return parseHex(text.slice(1));
124
+ const match = /^rgba?\(([^)]*)\)$/.exec(text);
125
+ return match && match[1] !== undefined ? parseFunctional(match[1]) : null;
126
+ }
127
+ function toHex(color) {
128
+ const byte = (value) => value.toString(16).padStart(2, '0');
129
+ return `#${byte(color.r)}${byte(color.g)}${byte(color.b)}`;
130
+ }
131
+ function luminance(color) {
132
+ const linear = (channel) => {
133
+ const c = channel / 255;
134
+ return c <= 0.03928 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);
135
+ };
136
+ return 0.2126 * linear(color.r) + 0.7152 * linear(color.g) + 0.0722 * linear(color.b);
137
+ }
138
+ /** WCAG 2.1 contrast ratio, 1 to 21. */
139
+ function contrastRatio(a, b) {
140
+ const [light, dark] = luminance(a) >= luminance(b) ? [luminance(a), luminance(b)] : [luminance(b), luminance(a)];
141
+ return (light + 0.05) / (dark + 0.05);
142
+ }
143
+ function over(foreground, background) {
144
+ if (foreground.a >= 1)
145
+ return foreground;
146
+ const mix = (f, b) => Math.round(foreground.a * f + (1 - foreground.a) * b);
147
+ return { r: mix(foreground.r, background.r), g: mix(foreground.g, background.g), b: mix(foreground.b, background.b), a: 1 };
148
+ }
149
+ /** A text style value on the text node, else inherited from the nearest enclosing Text. */
150
+ function inheritedTextStyle(nodes, node, key) {
151
+ for (let current = node; current && current.isText;) {
152
+ const value = flatStyle((0, inspect_1.findProp)(current, 'style'))[key];
153
+ if (value !== undefined)
154
+ return value;
155
+ current = current.parent >= 0 ? nodes[current.parent] : undefined;
156
+ }
157
+ return undefined;
158
+ }
159
+ /** The opaque background colour behind a node: nearest host (itself included) that sets one. */
160
+ function backgroundBehind(nodes, node) {
161
+ for (let current = node; current;) {
162
+ const raw = flatStyle((0, fiber_1.propsOf)(current.fiber).style).backgroundColor;
163
+ if (raw !== undefined && raw !== null) {
164
+ const color = parseColor(raw);
165
+ if (color === null)
166
+ return { found: false };
167
+ if (color.a >= 1)
168
+ return { found: true, color };
169
+ // Fully transparent shows whatever is behind it; translucent mixes with something unknown.
170
+ if (color.a > 0)
171
+ return { found: false };
172
+ }
173
+ current = current.parent >= 0 ? nodes[current.parent] : undefined;
174
+ }
175
+ return { found: false };
176
+ }
177
+ function isLargeText(fontSize, fontWeight) {
178
+ if (fontSize >= 18)
179
+ return true;
180
+ if (fontSize < 14)
181
+ return false;
182
+ if (fontWeight === 'bold')
183
+ return true;
184
+ const weight = typeof fontWeight === 'number' ? fontWeight : typeof fontWeight === 'string' ? Number(fontWeight) : NaN;
185
+ return weight >= 600 && weight <= 900;
186
+ }
187
+ function smallTarget(item) {
188
+ if (!isTapTarget(item.entry))
189
+ return null;
190
+ const { frame } = item;
191
+ const slop = hitSlopOf(item.entry.node);
192
+ const width = frame.width + slop.left + slop.right;
193
+ const height = frame.height + slop.top + slop.bottom;
194
+ if (width >= MIN_TARGET && height >= MIN_TARGET)
195
+ return null;
196
+ return `tap area ${num(frame.width)}x${num(frame.height)} pt is smaller than ${MIN_TARGET}x${MIN_TARGET}`;
197
+ }
198
+ function cutOff(item, screenWidth) {
199
+ const { frame } = item;
200
+ const parts = [];
201
+ if (frame.x < -EDGE_SLACK)
202
+ parts.push(`${num(-frame.x)} pt past the left edge`);
203
+ const overRight = frame.x + frame.width - screenWidth;
204
+ if (overRight > EDGE_SLACK)
205
+ parts.push(`${num(overRight)} pt past the right edge`);
206
+ return parts.length > 0 ? `runs ${parts.join(' and ')} of the screen` : null;
207
+ }
208
+ function noName(item) {
209
+ const { info } = item.entry;
210
+ if (!info.actions.includes('press') || info.actions.includes('type') || info.text !== '' || info.label !== null)
211
+ return null;
212
+ return 'button has no text or accessibility label; VoiceOver would read nothing';
213
+ }
214
+ function contrastOf(item, nodes) {
215
+ const { node } = item.entry;
216
+ if (!node.isText)
217
+ return null;
218
+ const foreground = parseColor(inheritedTextStyle(nodes, node, 'color'));
219
+ if (foreground === null)
220
+ return null;
221
+ const behind = backgroundBehind(nodes, node);
222
+ if (!behind.found)
223
+ return null;
224
+ const fontSizeRaw = inheritedTextStyle(nodes, node, 'fontSize');
225
+ const fontSize = typeof fontSizeRaw === 'number' ? fontSizeRaw : DEFAULT_FONT_SIZE;
226
+ const required = isLargeText(fontSize, inheritedTextStyle(nodes, node, 'fontWeight')) ? LARGE_CONTRAST : NORMAL_CONTRAST;
227
+ const ratio = contrastRatio(over(foreground, behind.color), behind.color);
228
+ if (ratio >= required)
229
+ return null;
230
+ return { ratio: Math.floor(ratio * 10) / 10, required, foreground: toHex(foreground), background: toHex(behind.color) };
231
+ }
232
+ function lowContrast(item, nodes) {
233
+ const c = contrastOf(item, nodes);
234
+ return c === null ? null : `contrast ${num(c.ratio)}:1 is below ${num(c.required)}:1 (${c.foreground} on ${c.background})`;
235
+ }
236
+ function maybeTruncated(item, nodes) {
237
+ const { node, info } = item.entry;
238
+ if (!node.isText || info.text === '')
239
+ return null;
240
+ const lines = (0, inspect_1.findProp)(node, 'numberOfLines');
241
+ if (typeof lines !== 'number' || !(lines > 0))
242
+ return null;
243
+ const sizeRaw = inheritedTextStyle(nodes, node, 'fontSize');
244
+ const fontSize = typeof sizeRaw === 'number' && sizeRaw > 0 ? sizeRaw : DEFAULT_FONT_SIZE;
245
+ const needed = info.text.length * fontSize * AVERAGE_GLYPH_WIDTH;
246
+ const room = item.frame.width * lines;
247
+ if (needed <= room)
248
+ return null;
249
+ return `text may be cut off: about ${num(needed)} pt of text, but numberOfLines=${lines} on ${num(item.frame.width)} pt fits about ${num(room)} pt`;
250
+ }
251
+ function overlapCandidate(entry) {
252
+ const { actions, text } = entry.info;
253
+ if (text === '' && actions.length === 0)
254
+ return false;
255
+ if (actions.includes('type'))
256
+ return false;
257
+ const pressy = actions.some((action) => action === 'press' || action === 'longPress' || action === 'toggle');
258
+ if (actions.includes('scroll') && !pressy)
259
+ return false;
260
+ return true;
261
+ }
262
+ /**
263
+ * `check_layout`: problems a person would notice on screen, found from the tree and frames.
264
+ * Refs are the ones from the latest `tree` call (they are not reset here).
265
+ */
266
+ async function checkLayout(_params) {
267
+ const snapshot = (0, inspect_1.takeSnapshot)();
268
+ // Native tabs are drawn by the OS: no frame to check.
269
+ const candidates = snapshot.entries.filter((entry) => entry.info.interesting && !entry.tab);
270
+ const frames = await Promise.all(candidates.map((entry) => (0, inspect_1.measureFiber)(entry.node.fiber)));
271
+ const measured = [];
272
+ candidates.forEach((entry, i) => {
273
+ const frame = frames[i] ?? null;
274
+ if (frame !== null && (0, inspect_1.isOnScreen)(frame, snapshot.screen))
275
+ measured.push({ entry, frame });
276
+ });
277
+ const tagged = [];
278
+ const add = (position, kind, fiberOwner, message, other) => {
279
+ const finding = { kind, ref: (0, inspect_1.refFor)(fiberOwner.node.fiber), message };
280
+ if (other)
281
+ finding.other = (0, inspect_1.refFor)(other.node.fiber);
282
+ tagged.push({ position, finding });
283
+ };
284
+ for (const item of measured) {
285
+ const position = item.entry.node.index;
286
+ const checks = [
287
+ ['small_target', smallTarget(item)],
288
+ ['cut_off', cutOff(item, snapshot.screen.width)],
289
+ ['no_name', noName(item)],
290
+ ['low_contrast', lowContrast(item, snapshot.nodes)],
291
+ ['maybe_truncated', maybeTruncated(item, snapshot.nodes)],
292
+ ];
293
+ for (const [kind, message] of checks)
294
+ if (message !== null)
295
+ add(position, kind, item.entry, message);
296
+ }
297
+ const overlapping = measured.filter((item) => overlapCandidate(item.entry));
298
+ for (let i = 0; i < overlapping.length; i++) {
299
+ const first = overlapping[i];
300
+ if (!first)
301
+ continue;
302
+ for (let j = i + 1; j < overlapping.length; j++) {
303
+ const second = overlapping[j];
304
+ if (!second)
305
+ continue;
306
+ const a = first.entry.node;
307
+ const b = second.entry.node;
308
+ if (isAncestor(snapshot.nodes, a, b) || isAncestor(snapshot.nodes, b, a))
309
+ continue;
310
+ const smaller = Math.min(first.frame.width * first.frame.height, second.frame.width * second.frame.height);
311
+ const shared = intersectionArea(first.frame, second.frame);
312
+ if (smaller <= 0 || shared <= smaller * OVERLAP_LIMIT)
313
+ continue;
314
+ const percent = Math.round((shared / smaller) * 100);
315
+ (0, inspect_1.refFor)(a.fiber); // name the first element first, so new refs follow tree order
316
+ const otherRef = (0, inspect_1.refFor)(b.fiber);
317
+ add(a.index, 'overlap', first.entry, `overlaps ${otherRef} by ${percent}% of the smaller element`, second.entry);
318
+ }
319
+ }
320
+ tagged.sort((x, y) => x.position - y.position);
321
+ return { findings: tagged.map((item) => item.finding) };
322
+ }
323
+ /* -------------------------------------------------------------------------- */
324
+ /* audit (AGENT-TOOLS 1.8 §10) */
325
+ /* -------------------------------------------------------------------------- */
326
+ /** The shared audit types Tapline checks; dynamic_type and element_detection are XCTest's own. */
327
+ exports.AUDIT_TYPES = ['contrast', 'hit_region', 'description', 'clipped_text', 'trait', 'overlap', 'duplicate_id'];
328
+ const STATEFUL_ROLES = new Set(['switch', 'checkbox', 'radio', 'togglebutton']);
329
+ function explicitRole(node) {
330
+ for (const key of ['role', 'accessibilityRole']) {
331
+ const value = (0, inspect_1.findProp)(node, key);
332
+ if (typeof value === 'string' && value !== '' && value !== 'none')
333
+ return value.toLowerCase();
334
+ }
335
+ return null;
336
+ }
337
+ /** A pressable without a role, or a switch-like element without a state: VoiceOver can't say what it is. */
338
+ /** The role set on the element, or on a host up to three levels above it (a library's pressable around its view). */
339
+ function roleAround(nodes, node) {
340
+ let current = node;
341
+ for (let level = 0; current && level < 4; level++) {
342
+ const role = explicitRole(current);
343
+ if (role !== null)
344
+ return role;
345
+ current = current.parent >= 0 ? nodes[current.parent] : undefined;
346
+ }
347
+ return null;
348
+ }
349
+ /** The nearest scroll view around a node (its index), or -1: content scrolls under bars outside it. */
350
+ function scrollContainer(nodes, entries, node) {
351
+ for (let p = node.parent; p >= 0;) {
352
+ if (entries.some((e) => e.node.index === p && e.info.actions.includes('scroll')))
353
+ return p;
354
+ const next = nodes[p];
355
+ if (!next)
356
+ return -1;
357
+ p = next.parent;
358
+ }
359
+ return -1;
360
+ }
361
+ function traitProblem(item, nodes) {
362
+ const { node, info } = item.entry;
363
+ const role = roleAround(nodes, node);
364
+ if (role !== null && STATEFUL_ROLES.has(role) && info.checked === null) {
365
+ return {
366
+ problem: `it's a ${role} without a state, so VoiceOver can't say whether it's on`,
367
+ fix: 'set accessibilityState={{ checked }}',
368
+ };
369
+ }
370
+ if (role !== null)
371
+ return null;
372
+ const presses = info.actions.includes('press') || info.actions.includes('longPress');
373
+ if (!presses || info.actions.includes('type') || info.actions.includes('toggle'))
374
+ return null;
375
+ // React Native's own Button and the text of a link set nothing either; a Text with onPress reads as text.
376
+ if (node.isText) {
377
+ return { problem: "it acts like a link but has no role, so VoiceOver reads it as plain text", fix: 'set accessibilityRole="link" (or "button")' };
378
+ }
379
+ return { problem: "it acts like a button but has no role, so VoiceOver doesn't say it's a button", fix: 'set accessibilityRole="button"' };
380
+ }
381
+ /** `button "TL" id=lab-edge-tl`: enough to know the other element without its list. */
382
+ function shortEntry(entry) {
383
+ const { info } = entry;
384
+ const name = info.label ?? (info.text !== '' ? info.text : null);
385
+ const role = info.role === 'textfield' ? 'input' : info.role === 'scrollview' ? 'scroll' : (info.role ?? 'other');
386
+ return [role, name !== null ? JSON.stringify(name.length > 40 ? `${name.slice(0, 39)}…` : name) : '', info.testID ? `id=${info.testID}` : '']
387
+ .filter((part) => part !== '')
388
+ .join(' ');
389
+ }
390
+ /** `audit`: the screen's accessibility problems, in the shared types (AGENT-TOOLS 1.8 §10). */
391
+ async function auditScreen(types) {
392
+ const snapshot = (0, inspect_1.takeSnapshot)();
393
+ const candidates = snapshot.entries.filter((entry) => entry.info.interesting && !entry.tab);
394
+ const frames = await Promise.all(candidates.map((entry) => (0, inspect_1.measureFiber)(entry.node.fiber)));
395
+ const measured = [];
396
+ candidates.forEach((entry, i) => {
397
+ const frame = frames[i] ?? null;
398
+ if (frame !== null && (0, inspect_1.isOnScreen)(frame, snapshot.screen))
399
+ measured.push({ entry, frame });
400
+ });
401
+ const out = [];
402
+ const add = (item, type, problem, fix) => {
403
+ if (types.has(type))
404
+ out.push({ type, entry: item.entry, frame: item.frame, problem, fix, position: item.entry.node.index });
405
+ };
406
+ for (const item of measured) {
407
+ // iOS's own switch (51x31 pt) takes touches around it: at its system size it isn't a small target.
408
+ const systemSwitch = item.entry.info.type === 'Switch' && item.frame.width >= 44 && item.frame.height >= 24;
409
+ if (smallTarget(item) !== null && !systemSwitch) {
410
+ add(item, 'hit_region', `too small to tap reliably (${num(item.frame.width)}x${num(item.frame.height)} pt)`, `make it at least ${MIN_TARGET}x${MIN_TARGET} pt`);
411
+ }
412
+ const contrast = contrastOf(item, snapshot.nodes);
413
+ if (contrast !== null) {
414
+ add(item, 'contrast', `the text is hard to read against its background (${num(contrast.ratio)}:1, ${contrast.foreground} on ${contrast.background})`, `raise the contrast to at least ${num(contrast.required)}:1`);
415
+ }
416
+ if (noName(item) !== null) {
417
+ add(item, 'description', 'no label, so VoiceOver says only "button"', 'give it an accessibility label');
418
+ }
419
+ const truncated = maybeTruncated(item, snapshot.nodes);
420
+ if (truncated !== null)
421
+ add(item, 'clipped_text', truncated, 'let it wrap, or give it more room');
422
+ const cut = cutOff(item, snapshot.screen.width);
423
+ if (cut !== null)
424
+ add(item, 'clipped_text', `it ${cut}`, 'keep it inside the screen');
425
+ const trait = traitProblem(item, snapshot.nodes);
426
+ if (trait !== null)
427
+ add(item, 'trait', trait.problem, trait.fix);
428
+ }
429
+ if (types.has('overlap')) {
430
+ // What shows of each element: its frame cut to the scroll view it sits in. A card scrolled under the
431
+ // tab bar is outside its list's visible area there, so it overlaps nothing; a button floating over
432
+ // the visible part of a list does.
433
+ const frameByNode = new Map(measured.map((item) => [item.entry.node.index, item.frame]));
434
+ const shown = (item) => {
435
+ const container = scrollContainer(snapshot.nodes, snapshot.entries, item.entry.node);
436
+ const area = container >= 0 ? frameByNode.get(container) : undefined;
437
+ if (area === undefined)
438
+ return item.frame;
439
+ const x = Math.max(item.frame.x, area.x);
440
+ const y = Math.max(item.frame.y, area.y);
441
+ const width = Math.min(item.frame.x + item.frame.width, area.x + area.width) - x;
442
+ const height = Math.min(item.frame.y + item.frame.height, area.y + area.height) - y;
443
+ return width > 0 && height > 0 ? { x, y, width, height } : null;
444
+ };
445
+ const overlapping = measured
446
+ .filter((item) => overlapCandidate(item.entry))
447
+ .map((item) => ({ ...item, visible: shown(item) }));
448
+ for (let i = 0; i < overlapping.length; i++) {
449
+ const first = overlapping[i];
450
+ if (!first)
451
+ continue;
452
+ for (let j = i + 1; j < overlapping.length; j++) {
453
+ const second = overlapping[j];
454
+ if (!second)
455
+ continue;
456
+ const a = first.entry.node;
457
+ const b = second.entry.node;
458
+ if (isAncestor(snapshot.nodes, a, b) || isAncestor(snapshot.nodes, b, a))
459
+ continue;
460
+ // One control drawn as two views with the same id isn't two things on top of each other.
461
+ const idA = first.entry.info.testID;
462
+ if (idA !== null && idA !== '' && idA === second.entry.info.testID)
463
+ continue;
464
+ const va = first.visible;
465
+ const vb = second.visible;
466
+ if (va === null || vb === null)
467
+ continue;
468
+ const smaller = Math.min(va.width * va.height, vb.width * vb.height);
469
+ const shared = intersectionArea(va, vb);
470
+ if (smaller <= 0 || shared <= smaller * OVERLAP_LIMIT)
471
+ continue;
472
+ (0, inspect_1.refFor)(a.fiber);
473
+ const otherRef = (0, inspect_1.refFor)(b.fiber);
474
+ add(first, 'overlap', `it covers ${Math.round((shared / smaller) * 100)}% of ${otherRef} ${shortEntry(second.entry)}`, 'move them apart, or make one of them not take touches');
475
+ }
476
+ }
477
+ }
478
+ if (types.has('duplicate_id')) {
479
+ const byId = new Map();
480
+ for (const item of measured) {
481
+ const id = item.entry.info.testID;
482
+ if (id === null || id === '')
483
+ continue;
484
+ byId.set(id, [...(byId.get(id) ?? []), item]);
485
+ }
486
+ // A view inside another with the same id is one control drawn twice (a library's pressable and its view): count it once.
487
+ for (const [id, items] of byId) {
488
+ byId.set(id, items.filter((item) => !items.some((other) => other !== item && isAncestor(snapshot.nodes, other.entry.node, item.entry.node))));
489
+ }
490
+ for (const [id, items] of byId) {
491
+ const first = items[0];
492
+ if (items.length < 2 || first === undefined)
493
+ continue;
494
+ const refs = items.map((item) => (0, inspect_1.refFor)(item.entry.node.fiber));
495
+ add(first, 'duplicate_id', `the id "${id}" is on ${items.length} elements (${refs.join(', ')})`, 'give each its own testID');
496
+ }
497
+ }
498
+ out.sort((x, y) => x.position - y.position);
499
+ return out.map(({ position: _position, ...finding }) => finding);
500
+ }
501
+ //# sourceMappingURL=checks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"checks.js","sourceRoot":"","sources":["../src/checks.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,111 @@
1
+ import { type MethodFn } from './methods';
2
+ import { type AppInfo, type DeviceInfo } from './types';
3
+ export declare const PING_INTERVAL_MS = 15000;
4
+ export declare const HOST_SILENCE_MS = 45000;
5
+ export declare const REQUEST_TIMEOUT_MS = 30000;
6
+ /** The slice of the WebSocket API Tapline uses (React Native provides it globally). */
7
+ export interface WebSocketLike {
8
+ onopen: ((event: unknown) => void) | null;
9
+ onmessage: ((event: {
10
+ data: unknown;
11
+ }) => void) | null;
12
+ onclose: ((event: {
13
+ code?: number;
14
+ reason?: string;
15
+ }) => void) | null;
16
+ onerror: ((event: unknown) => void) | null;
17
+ send(data: string): void;
18
+ close(code?: number, reason?: string): void;
19
+ }
20
+ export type WebSocketCtor = new (url: string) => WebSocketLike;
21
+ /** WebSocket close code for a token the host refused. */
22
+ export declare const CLOSE_BAD_TOKEN = 4001;
23
+ /** WebSocket close code for a pairing code the host refused (invalid, expired or used). */
24
+ export declare const CLOSE_BAD_PAIR_CODE = 4004;
25
+ export interface ClientOptions {
26
+ url: string;
27
+ /** The host's token (a paired app, or a direct connection). */
28
+ token?: string;
29
+ /** A one-time code from a pairing link, used instead of `token` until the host answers. */
30
+ pairCode?: string;
31
+ /** Random id of this app install, sent as `device.id`. */
32
+ deviceId?: string;
33
+ app?: AppInfo;
34
+ /** The host accepted `pairCode` and sent its token: remember it for later connections. */
35
+ onPaired?: (token: string) => void;
36
+ /** The host refused the pairing code (4004) or the token during the handshake (4001); the client has stopped. */
37
+ onRejected?: (code: number) => void;
38
+ }
39
+ export interface ClientDeps {
40
+ WebSocketCtor?: WebSocketCtor;
41
+ methods?: Record<string, MethodFn>;
42
+ device?: DeviceInfo;
43
+ capabilities?: string[];
44
+ /** Receives the one status line per connect/disconnect. */
45
+ log?: (line: string) => void;
46
+ /** Foreground/background changes. Default: React Native's AppState. */
47
+ appState?: AppStateLike;
48
+ /** Keep the screen on while connected. Default: expo-keep-awake when the app has it. */
49
+ keepAwake?: (on: boolean) => void;
50
+ }
51
+ export interface AppStateLike {
52
+ addEventListener: (type: 'change', listener: (state: string) => void) => {
53
+ remove: () => void;
54
+ } | undefined;
55
+ }
56
+ /**
57
+ * How long a connection try may take to open before it is dropped for a fresh one: 2 s, and 4 s on
58
+ * every fourth try, so a slow link that needs longer still gets through. iOS repeats an unanswered
59
+ * try after 1 s and 3 s, so with the 1 s wait between tries a host is never left unasked for more
60
+ * than about 2 s.
61
+ */
62
+ export declare function connectTimeoutMs(attempt: number): number;
63
+ export declare function backoffDelay(attempt: number): number;
64
+ export declare function normalizeUrl(url: string): string;
65
+ export declare function collectDeviceInfo(): DeviceInfo;
66
+ export declare function defaultCapabilities(): string[];
67
+ export declare class TaplineClient {
68
+ private readonly options;
69
+ private readonly deps;
70
+ private socket;
71
+ private reconnectTimer;
72
+ /** Gives up on a connection try that hasn't opened. */
73
+ private openTimer;
74
+ /** The current socket has opened. */
75
+ private opened;
76
+ private pingTimer;
77
+ private attempt;
78
+ private running;
79
+ private ready;
80
+ private everConnected;
81
+ private failureLogged;
82
+ private lastHeard;
83
+ private queue;
84
+ private token;
85
+ private pairCode;
86
+ private appStateSubscription;
87
+ private stopTouchWatch;
88
+ constructor(options: ClientOptions, deps?: ClientDeps);
89
+ get connected(): boolean;
90
+ start(): void;
91
+ stop(): void;
92
+ private status;
93
+ private setAwake;
94
+ private watchAppState;
95
+ /** Tells the host when the app goes to the background (iOS then pauses it), and reconnects at once when it's back. */
96
+ private onAppState;
97
+ private clearTimers;
98
+ private connect;
99
+ private safely;
100
+ private onOpen;
101
+ private onMessage;
102
+ private onWelcome;
103
+ private onPingTick;
104
+ private onClose;
105
+ private handleLoss;
106
+ private scheduleReconnect;
107
+ private send;
108
+ /** Requests run one at a time so refs and snapshots never interleave. */
109
+ private enqueue;
110
+ private handleRequest;
111
+ }