@mobilewright/inspector 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json ADDED
@@ -0,0 +1,42 @@
1
+ {
2
+ "name": "@mobilewright/inspector",
3
+ "version": "0.0.1",
4
+ "description": "Browser-based element inspector for mobilewright",
5
+ "homepage": "https://mobilewright.dev",
6
+ "license": "Apache-2.0",
7
+ "engines": {
8
+ "node": ">=18"
9
+ },
10
+ "type": "module",
11
+ "main": "./dist/index.js",
12
+ "types": "./dist/index.d.ts",
13
+ "exports": {
14
+ ".": {
15
+ "types": "./dist/index.d.ts",
16
+ "default": "./dist/index.js"
17
+ }
18
+ },
19
+ "scripts": {
20
+ "build": "tsc -b",
21
+ "prepublishOnly": "tsc -b",
22
+ "test": "playwright test --config=../../tests/mobilewright.config.ts"
23
+ },
24
+ "repository": {
25
+ "type": "git",
26
+ "url": "git+https://github.com/mobile-next/mobilewright.git",
27
+ "directory": "packages/inspector"
28
+ },
29
+ "files": [
30
+ "dist",
31
+ "public"
32
+ ],
33
+ "dependencies": {
34
+ "@mobilewright/core": "^0.0.1",
35
+ "@mobilewright/protocol": "^0.0.1",
36
+ "express": "^5.2.1",
37
+ "open": "^10.2.0"
38
+ },
39
+ "devDependencies": {
40
+ "@types/express": "^5.0.6"
41
+ }
42
+ }
@@ -0,0 +1,453 @@
1
+ /* ---- Theme variables ---- */
2
+
3
+ :root, [data-theme="void"] {
4
+ --c-bg: #1a1a1a;
5
+ --c-surface: #252525;
6
+ --c-surface2: #1e1e1e;
7
+ --c-pane-bg: #111111;
8
+ --c-border: #333333;
9
+ --c-border2: #2a2a2a;
10
+ --c-text: #e0e0e0;
11
+ --c-text-muted: #888888;
12
+ --c-text-dim: #555555;
13
+ --c-text-strong: #ffffff;
14
+ --c-accent: #4a9eff;
15
+ --c-accent-dim: rgba(74,158,255,.15);
16
+ --c-accent-hover: rgba(74,158,255,.3);
17
+ --c-selected: #3ddc6e;
18
+ --c-selected-bg: #1a3020;
19
+ --c-selected-dim: rgba(50,205,90,.3);
20
+ --c-row-hover: #2a2a2a;
21
+ --c-status-loading: #4a9eff;
22
+ --c-status-error: #e05050;
23
+ --c-dup: #c8a030;
24
+ --c-badge-testid-bg: #1a3d1a; --c-badge-testid: #6dbb6d;
25
+ --c-badge-role-bg: #1a2d4a; --c-badge-role: #6aaeff;
26
+ --c-badge-label-bg: #3a2d00; --c-badge-label: #c8a030;
27
+ --c-badge-text-bg: #2d1a2d; --c-badge-text: #bb7dbb;
28
+ --c-badge-none-bg: #2a2a2a; --c-badge-none: #666666;
29
+ }
30
+
31
+ [data-theme="aurora"] {
32
+ --c-bg: #0d1117;
33
+ --c-surface: #161b22;
34
+ --c-surface2: #0d1117;
35
+ --c-pane-bg: #090d13;
36
+ --c-border: #21262d;
37
+ --c-border2: #1c2128;
38
+ --c-text: #cdd9e5;
39
+ --c-text-muted: #768390;
40
+ --c-text-dim: #444c56;
41
+ --c-text-strong: #e6edf3;
42
+ --c-accent: #58efb0;
43
+ --c-accent-dim: rgba(88,239,176,.12);
44
+ --c-accent-hover: rgba(88,239,176,.25);
45
+ --c-selected: #d2a8ff;
46
+ --c-selected-bg: #1f1040;
47
+ --c-selected-dim: rgba(210,168,255,.25);
48
+ --c-row-hover: #1c2128;
49
+ --c-status-loading: #58efb0;
50
+ --c-status-error: #ff7b72;
51
+ --c-dup: #ffa657;
52
+ --c-badge-testid-bg: #04281c; --c-badge-testid: #58efb0;
53
+ --c-badge-role-bg: #1a1040; --c-badge-role: #d2a8ff;
54
+ --c-badge-label-bg: #2d1f00; --c-badge-label: #ffa657;
55
+ --c-badge-text-bg: #2d1030; --c-badge-text: #f778ba;
56
+ --c-badge-none-bg: #21262d; --c-badge-none: #444c56;
57
+ }
58
+
59
+ [data-theme="crimson"] {
60
+ --c-bg: #100808;
61
+ --c-surface: #1a0e0e;
62
+ --c-surface2: #140a0a;
63
+ --c-pane-bg: #0c0606;
64
+ --c-border: #2d1414;
65
+ --c-border2: #1f0f0f;
66
+ --c-text: #e8d4d4;
67
+ --c-text-muted: #8a6060;
68
+ --c-text-dim: #4a2828;
69
+ --c-text-strong: #f5e8e8;
70
+ --c-accent: #e84040;
71
+ --c-accent-dim: rgba(232,64,64,.12);
72
+ --c-accent-hover: rgba(232,64,64,.25);
73
+ --c-selected: #f0b040;
74
+ --c-selected-bg: #281a00;
75
+ --c-selected-dim: rgba(240,176,64,.25);
76
+ --c-row-hover: #1f1010;
77
+ --c-status-loading: #e84040;
78
+ --c-status-error: #ff7070;
79
+ --c-dup: #f0b040;
80
+ --c-badge-testid-bg: #280808; --c-badge-testid: #e84040;
81
+ --c-badge-role-bg: #280e00; --c-badge-role: #f0b040;
82
+ --c-badge-label-bg: #1e1000; --c-badge-label: #d4903a;
83
+ --c-badge-text-bg: #1e0808; --c-badge-text: #c06060;
84
+ --c-badge-none-bg: #1f0f0f; --c-badge-none: #4a2828;
85
+ }
86
+
87
+ [data-theme="arctic"] {
88
+ --c-bg: #eceff4;
89
+ --c-surface: #e5e9f0;
90
+ --c-surface2: #f0f4f8;
91
+ --c-pane-bg: #dde3ee;
92
+ --c-border: #c8d0dc;
93
+ --c-border2: #d8dee9;
94
+ --c-text: #2e3440;
95
+ --c-text-muted: #4c566a;
96
+ --c-text-dim: #9aa0ad;
97
+ --c-text-strong: #2e3440;
98
+ --c-accent: #5e81ac;
99
+ --c-accent-dim: rgba(94,129,172,.15);
100
+ --c-accent-hover: rgba(94,129,172,.25);
101
+ --c-selected: #4c9a5e;
102
+ --c-selected-bg: #d8efdf;
103
+ --c-selected-dim: rgba(76,154,94,.2);
104
+ --c-row-hover: #dde3ee;
105
+ --c-status-loading: #5e81ac;
106
+ --c-status-error: #bf616a;
107
+ --c-dup: #d08770;
108
+ --c-badge-testid-bg: #d8efdf; --c-badge-testid: #2d7a3a;
109
+ --c-badge-role-bg: #dae4f0; --c-badge-role: #2e5280;
110
+ --c-badge-label-bg: #f0e6d0; --c-badge-label: #b45309;
111
+ --c-badge-text-bg: #ede0f0; --c-badge-text: #6b3a80;
112
+ --c-badge-none-bg: #e5e9f0; --c-badge-none: #9aa0ad;
113
+ }
114
+
115
+ [data-theme="synthwave"] {
116
+ --c-bg: #0d0020;
117
+ --c-surface: #150030;
118
+ --c-surface2: #100028;
119
+ --c-pane-bg: #080015;
120
+ --c-border: #2a0050;
121
+ --c-border2: #1a0038;
122
+ --c-text: #e0d0ff;
123
+ --c-text-muted: #8060a0;
124
+ --c-text-dim: #402060;
125
+ --c-text-strong: #f0e0ff;
126
+ --c-accent: #ff2d78;
127
+ --c-accent-dim: rgba(255,45,120,.12);
128
+ --c-accent-hover: rgba(255,45,120,.25);
129
+ --c-selected: #00ffcc;
130
+ --c-selected-bg: #00281e;
131
+ --c-selected-dim: rgba(0,255,204,.2);
132
+ --c-row-hover: #1a0038;
133
+ --c-status-loading: #ff2d78;
134
+ --c-status-error: #ff6060;
135
+ --c-dup: #ffd700;
136
+ --c-badge-testid-bg: #0a2818; --c-badge-testid: #00ffcc;
137
+ --c-badge-role-bg: #280040; --c-badge-role: #bf80ff;
138
+ --c-badge-label-bg: #281800; --c-badge-label: #ffd700;
139
+ --c-badge-text-bg: #280020; --c-badge-text: #ff2d78;
140
+ --c-badge-none-bg: #1a0038; --c-badge-none: #402060;
141
+ }
142
+
143
+ /* ---- Reset ---- */
144
+
145
+ *, *::before, *::after { box-sizing: border-box; }
146
+ [hidden] { display: none !important; }
147
+
148
+ body {
149
+ font-family: system-ui, -apple-system, sans-serif;
150
+ font-size: 13px;
151
+ margin: 0;
152
+ background: var(--c-bg);
153
+ color: var(--c-text);
154
+ height: 100vh;
155
+ display: flex;
156
+ flex-direction: column;
157
+ }
158
+
159
+ /* ---- Header ---- */
160
+
161
+ header {
162
+ display: flex;
163
+ align-items: center;
164
+ gap: 12px;
165
+ padding: 8px 14px;
166
+ background: var(--c-surface);
167
+ border-bottom: 1px solid var(--c-border);
168
+ flex-shrink: 0;
169
+ }
170
+
171
+ header h1 {
172
+ font-size: 14px;
173
+ font-weight: 600;
174
+ margin: 0;
175
+ letter-spacing: 0.03em;
176
+ color: var(--c-text-strong);
177
+ }
178
+
179
+ #device-picker select,
180
+ #auto-refresh-interval,
181
+ #theme-select {
182
+ background: var(--c-bg);
183
+ color: var(--c-text);
184
+ border: 1px solid var(--c-border);
185
+ border-radius: 4px;
186
+ padding: 4px 8px;
187
+ font-size: 12px;
188
+ cursor: pointer;
189
+ outline: none;
190
+ }
191
+
192
+ #device-picker select:focus,
193
+ #auto-refresh-interval:focus,
194
+ #theme-select:focus {
195
+ border-color: var(--c-accent);
196
+ }
197
+
198
+ #auto-refresh-interval:disabled {
199
+ opacity: 0.4;
200
+ cursor: default;
201
+ }
202
+
203
+ #refresh-controls {
204
+ display: flex;
205
+ align-items: center;
206
+ gap: 8px;
207
+ }
208
+
209
+ .auto-refresh-label {
210
+ display: flex;
211
+ align-items: center;
212
+ gap: 4px;
213
+ cursor: pointer;
214
+ color: var(--c-text-muted);
215
+ }
216
+
217
+ #refresh-btn {
218
+ background: var(--c-surface2);
219
+ color: var(--c-text);
220
+ border: 1px solid var(--c-text-dim);
221
+ border-radius: 4px;
222
+ padding: 4px 12px;
223
+ font-size: 12px;
224
+ cursor: pointer;
225
+ }
226
+
227
+ #refresh-btn:hover { background: var(--c-row-hover); }
228
+ #refresh-btn:active { background: var(--c-bg); }
229
+ #refresh-btn:disabled { opacity: 0.4; cursor: default; }
230
+
231
+ #theme-controls {
232
+ display: flex;
233
+ align-items: center;
234
+ gap: 6px;
235
+ }
236
+
237
+ #theme-controls label {
238
+ font-size: 11px;
239
+ color: var(--c-text-muted);
240
+ }
241
+
242
+ #status-bar {
243
+ margin-left: auto;
244
+ font-size: 11px;
245
+ color: var(--c-text-dim);
246
+ }
247
+
248
+ #status-bar.error { color: var(--c-status-error); }
249
+ #status-bar.loading { color: var(--c-status-loading); }
250
+
251
+ /* ---- Main layout ---- */
252
+
253
+ main {
254
+ display: flex;
255
+ flex: 1;
256
+ overflow: hidden;
257
+ }
258
+
259
+ /* ---- Screenshot pane ---- */
260
+
261
+ #screenshot-pane {
262
+ flex: 0 0 auto;
263
+ min-width: 300px;
264
+ max-width: 50%;
265
+ position: relative;
266
+ overflow: hidden;
267
+ border-right: 1px solid var(--c-border);
268
+ background: var(--c-pane-bg);
269
+ display: flex;
270
+ align-items: flex-start;
271
+ justify-content: center;
272
+ padding: 16px;
273
+ }
274
+
275
+ #screenshot-container {
276
+ position: relative;
277
+ display: inline-block;
278
+ }
279
+
280
+ #no-device-msg {
281
+ display: flex;
282
+ flex-direction: column;
283
+ align-items: center;
284
+ justify-content: center;
285
+ gap: 10px;
286
+ padding: 40px 24px;
287
+ text-align: center;
288
+ color: var(--c-text-dim);
289
+ }
290
+
291
+ .placeholder-icon {
292
+ width: 64px;
293
+ height: 64px;
294
+ color: var(--c-text-dim);
295
+ margin-bottom: 4px;
296
+ transition: color 0.3s;
297
+ }
298
+
299
+ #no-device-msg.loading .placeholder-icon {
300
+ color: var(--c-accent);
301
+ animation: placeholder-pulse 1.4s ease-in-out infinite;
302
+ }
303
+
304
+ @keyframes placeholder-pulse {
305
+ 0%, 100% { opacity: 1; }
306
+ 50% { opacity: 0.35; }
307
+ }
308
+
309
+ .placeholder-title {
310
+ margin: 0;
311
+ font-size: 14px;
312
+ font-weight: 600;
313
+ color: var(--c-text-muted);
314
+ }
315
+
316
+ .placeholder-sub {
317
+ margin: 0;
318
+ font-size: 12px;
319
+ color: var(--c-text-dim);
320
+ max-width: 200px;
321
+ line-height: 1.5;
322
+ }
323
+
324
+ #screenshot-img {
325
+ display: block;
326
+ max-width: 100%;
327
+ height: auto;
328
+ }
329
+
330
+ #highlight-overlay {
331
+ position: absolute;
332
+ top: 0;
333
+ left: 0;
334
+ width: 100%;
335
+ height: 100%;
336
+ pointer-events: none;
337
+ overflow: visible;
338
+ }
339
+
340
+ .highlight-rect {
341
+ fill: var(--c-accent-dim);
342
+ stroke: var(--c-accent);
343
+ stroke-width: 2;
344
+ pointer-events: all;
345
+ cursor: pointer;
346
+ transition: fill 0.1s;
347
+ }
348
+
349
+ .highlight-rect:hover,
350
+ .highlight-rect.hovered {
351
+ fill: var(--c-accent-hover);
352
+ }
353
+
354
+ .highlight-rect.selected {
355
+ fill: var(--c-selected-dim);
356
+ stroke: var(--c-selected);
357
+ stroke-width: 2.5;
358
+ }
359
+
360
+ /* ---- Elements pane ---- */
361
+
362
+ #elements-pane {
363
+ flex: 1;
364
+ overflow: auto;
365
+ background: var(--c-surface2);
366
+ }
367
+
368
+ #elements-list {
369
+ padding: 0;
370
+ }
371
+
372
+ .element-row {
373
+ display: flex;
374
+ align-items: center;
375
+ gap: 8px;
376
+ padding: 6px 12px;
377
+ border-bottom: 1px solid var(--c-border2);
378
+ cursor: pointer;
379
+ transition: background 0.1s;
380
+ }
381
+
382
+ .element-row:hover { background: var(--c-row-hover); }
383
+
384
+ .element-row.selected {
385
+ background: var(--c-selected-bg);
386
+ border-left: 3px solid var(--c-selected);
387
+ padding-left: 9px;
388
+ }
389
+
390
+ .element-row.no-locator { opacity: 0.5; }
391
+
392
+ .locator-badge {
393
+ display: inline-block;
394
+ font-size: 10px;
395
+ font-weight: 600;
396
+ padding: 2px 6px;
397
+ border-radius: 3px;
398
+ text-transform: uppercase;
399
+ letter-spacing: 0.05em;
400
+ flex-shrink: 0;
401
+ min-width: 52px;
402
+ text-align: center;
403
+ }
404
+
405
+ .badge-testId { background: var(--c-badge-testid-bg); color: var(--c-badge-testid); }
406
+ .badge-role { background: var(--c-badge-role-bg); color: var(--c-badge-role); }
407
+ .badge-label { background: var(--c-badge-label-bg); color: var(--c-badge-label); }
408
+ .badge-text { background: var(--c-badge-text-bg); color: var(--c-badge-text); }
409
+ .badge-none { background: var(--c-badge-none-bg); color: var(--c-badge-none); }
410
+
411
+ .locator-value {
412
+ font-family: 'SF Mono', Menlo, Monaco, monospace;
413
+ font-size: 12px;
414
+ color: var(--c-text);
415
+ white-space: nowrap;
416
+ overflow: hidden;
417
+ text-overflow: ellipsis;
418
+ flex: 1;
419
+ }
420
+
421
+ .element-type {
422
+ font-size: 10px;
423
+ color: var(--c-text-dim);
424
+ flex-shrink: 0;
425
+ }
426
+
427
+ .duplicate-warning {
428
+ font-size: 10px;
429
+ color: var(--c-dup);
430
+ flex-shrink: 0;
431
+ }
432
+
433
+ .vis-btn {
434
+ background: none;
435
+ border: none;
436
+ color: var(--c-text-dim);
437
+ cursor: pointer;
438
+ font-size: 13px;
439
+ padding: 0 2px;
440
+ flex-shrink: 0;
441
+ line-height: 1;
442
+ }
443
+
444
+ .vis-btn:hover { color: var(--c-text-muted); }
445
+
446
+ .element-row.element-hidden { opacity: 0.4; }
447
+ .element-row.element-hidden .vis-btn { color: var(--c-text-muted); }
448
+
449
+ .pane-message {
450
+ color: var(--c-text-dim);
451
+ padding: 40px 20px;
452
+ text-align: center;
453
+ }
@@ -0,0 +1,67 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <title>Mobilewright Inspector</title>
6
+ <link rel="stylesheet" href="/css/app.css" />
7
+ </head>
8
+ <body>
9
+ <header>
10
+ <h1>Mobilewright Inspector</h1>
11
+ <div id="device-picker">
12
+ <select id="device-select" aria-label="Device">
13
+ <option value="">No devices found</option>
14
+ </select>
15
+ </div>
16
+ <div id="refresh-controls">
17
+ <button id="refresh-btn">Refresh</button>
18
+ <label class="auto-refresh-label">
19
+ <input type="checkbox" id="auto-refresh-toggle" />
20
+ Auto-refresh
21
+ </label>
22
+ <select id="auto-refresh-interval" aria-label="Auto-refresh interval" disabled>
23
+ <option value="5000">5 s</option>
24
+ <option value="10000">10 s</option>
25
+ <option value="20000">20 s</option>
26
+ <option value="30000">30 s</option>
27
+ <option value="60000">1 min</option>
28
+ </select>
29
+ </div>
30
+ <div id="theme-controls">
31
+ <label for="theme-select">Theme</label>
32
+ <select id="theme-select">
33
+ <option value="void">Void</option>
34
+ <option value="aurora">Aurora</option>
35
+ <option value="crimson">Crimson</option>
36
+ <option value="arctic">Arctic</option>
37
+ <option value="synthwave">Synthwave</option>
38
+ </select>
39
+ </div>
40
+ <div id="status-bar" aria-live="polite"></div>
41
+ </header>
42
+
43
+ <main>
44
+ <section id="screenshot-pane">
45
+ <div id="screenshot-container">
46
+ <div id="no-device-msg">
47
+ <svg class="placeholder-icon" viewBox="0 0 64 64" fill="none" xmlns="http://www.w3.org/2000/svg">
48
+ <rect x="14" y="4" width="36" height="56" rx="6" stroke="currentColor" stroke-width="2.5"/>
49
+ <rect x="20" y="10" width="24" height="36" rx="2" stroke="currentColor" stroke-width="1.5" opacity="0.4"/>
50
+ <circle cx="32" cy="54" r="2.5" fill="currentColor" opacity="0.5"/>
51
+ <line x1="28" y1="7" x2="36" y2="7" stroke="currentColor" stroke-width="2" stroke-linecap="round" opacity="0.4"/>
52
+ </svg>
53
+ <p class="placeholder-title" id="placeholder-title">Select a device</p>
54
+ <p class="placeholder-sub" id="placeholder-sub">Pick a connected device or simulator above</p>
55
+ </div>
56
+ <img id="screenshot-img" alt="Device screenshot" hidden />
57
+ <svg id="highlight-overlay" hidden></svg>
58
+ </div>
59
+ </section>
60
+ <section id="elements-pane">
61
+ <div id="elements-list"></div>
62
+ </section>
63
+ </main>
64
+
65
+ <script src="/js/app.js" type="module"></script>
66
+ </body>
67
+ </html>