uidex 0.7.0 → 0.9.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 (51) hide show
  1. package/dist/cli/cli.cjs +1112 -1054
  2. package/dist/cli/cli.cjs.map +1 -1
  3. package/dist/headless/index.cjs +4 -448
  4. package/dist/headless/index.cjs.map +1 -1
  5. package/dist/headless/index.d.cts +41 -11
  6. package/dist/headless/index.d.ts +41 -11
  7. package/dist/headless/index.js +4 -450
  8. package/dist/headless/index.js.map +1 -1
  9. package/dist/index.cjs +147 -3252
  10. package/dist/index.cjs.map +1 -1
  11. package/dist/index.d.cts +43 -316
  12. package/dist/index.d.ts +43 -316
  13. package/dist/index.js +133 -3254
  14. package/dist/index.js.map +1 -1
  15. package/dist/playwright/index.cjs +175 -0
  16. package/dist/playwright/index.cjs.map +1 -1
  17. package/dist/playwright/index.d.cts +2 -0
  18. package/dist/playwright/index.d.ts +2 -0
  19. package/dist/playwright/index.js +167 -0
  20. package/dist/playwright/index.js.map +1 -1
  21. package/dist/playwright/states-reporter.cjs +123 -0
  22. package/dist/playwright/states-reporter.cjs.map +1 -0
  23. package/dist/playwright/states-reporter.d.cts +46 -0
  24. package/dist/playwright/states-reporter.d.ts +46 -0
  25. package/dist/playwright/states-reporter.js +88 -0
  26. package/dist/playwright/states-reporter.js.map +1 -0
  27. package/dist/playwright/states.cjs +118 -0
  28. package/dist/playwright/states.cjs.map +1 -0
  29. package/dist/playwright/states.d.cts +120 -0
  30. package/dist/playwright/states.d.ts +120 -0
  31. package/dist/playwright/states.js +88 -0
  32. package/dist/playwright/states.js.map +1 -0
  33. package/dist/react/index.cjs +163 -3255
  34. package/dist/react/index.cjs.map +1 -1
  35. package/dist/react/index.d.cts +62 -275
  36. package/dist/react/index.d.ts +62 -275
  37. package/dist/react/index.js +151 -3268
  38. package/dist/react/index.js.map +1 -1
  39. package/dist/scan/index.cjs +1292 -345
  40. package/dist/scan/index.cjs.map +1 -1
  41. package/dist/scan/index.d.cts +305 -12
  42. package/dist/scan/index.d.ts +305 -12
  43. package/dist/scan/index.js +1283 -345
  44. package/dist/scan/index.js.map +1 -1
  45. package/package.json +12 -16
  46. package/dist/cloud/index.cjs +0 -682
  47. package/dist/cloud/index.cjs.map +0 -1
  48. package/dist/cloud/index.d.cts +0 -270
  49. package/dist/cloud/index.d.ts +0 -270
  50. package/dist/cloud/index.js +0 -645
  51. package/dist/cloud/index.js.map +0 -1
package/dist/index.js CHANGED
@@ -280,207 +280,6 @@ function displayName(entity, node) {
280
280
  return prettify(entity.id);
281
281
  }
282
282
 
283
- // src/browser/ingest/console.ts
284
- var DEFAULT_LIMIT = 50;
285
- var LEVELS = ["warn", "error"];
286
- function formatMessage(args) {
287
- return args.map((arg) => {
288
- if (typeof arg === "string") return arg;
289
- if (arg instanceof Error) return arg.stack ?? arg.message;
290
- try {
291
- return JSON.stringify(arg);
292
- } catch {
293
- return String(arg);
294
- }
295
- }).join(" ");
296
- }
297
- function createConsoleCapture(options = {}) {
298
- const limit = options.limit ?? DEFAULT_LIMIT;
299
- const target = options.target ?? console;
300
- const now = options.now ?? (() => /* @__PURE__ */ new Date());
301
- const buffer = [];
302
- const originals = {};
303
- let active = false;
304
- function record(level, args) {
305
- const entry = {
306
- level,
307
- message: formatMessage(args),
308
- timestamp: now().toISOString()
309
- };
310
- buffer.push(entry);
311
- if (buffer.length > limit) buffer.splice(0, buffer.length - limit);
312
- }
313
- function start() {
314
- if (active) return;
315
- for (const level of LEVELS) {
316
- const original = target[level];
317
- originals[level] = original;
318
- const wrapped = (...args) => {
319
- record(level, args);
320
- original.call(target, ...args);
321
- };
322
- target[level] = wrapped;
323
- }
324
- active = true;
325
- }
326
- function stop() {
327
- if (!active) return;
328
- for (const level of LEVELS) {
329
- const original = originals[level];
330
- if (original) {
331
- ;
332
- target[level] = original;
333
- }
334
- delete originals[level];
335
- }
336
- active = false;
337
- }
338
- return {
339
- start,
340
- stop,
341
- get isActive() {
342
- return active;
343
- },
344
- entries() {
345
- return buffer.slice();
346
- },
347
- clear() {
348
- buffer.length = 0;
349
- }
350
- };
351
- }
352
-
353
- // src/browser/ingest/native-fetch.ts
354
- var nativeFetch = typeof globalThis !== "undefined" && typeof globalThis.fetch === "function" ? globalThis.fetch.bind(globalThis) : void 0;
355
-
356
- // src/browser/ingest/network.ts
357
- var DEFAULT_LIMIT2 = 20;
358
- function resolveMethod(input, init) {
359
- if (init?.method) return init.method.toUpperCase();
360
- if (typeof input !== "string" && !(input instanceof URL) && "method" in input) {
361
- return input.method.toUpperCase();
362
- }
363
- return "GET";
364
- }
365
- function resolveUrl(input) {
366
- if (typeof input === "string") return input;
367
- if (input instanceof URL) return input.toString();
368
- return input.url;
369
- }
370
- function createNetworkCapture(options = {}) {
371
- const limit = options.limit ?? DEFAULT_LIMIT2;
372
- const target = options.target ?? globalThis;
373
- const now = options.now ?? (() => /* @__PURE__ */ new Date());
374
- const buffer = [];
375
- let original;
376
- let active = false;
377
- function push(entry) {
378
- buffer.push(entry);
379
- if (buffer.length > limit) buffer.splice(0, buffer.length - limit);
380
- }
381
- function start() {
382
- if (active) return;
383
- const baseline = target.fetch ?? nativeFetch;
384
- if (!baseline) return;
385
- original = baseline;
386
- const wrapped = async (input, init) => {
387
- const method = resolveMethod(input, init);
388
- const url = resolveUrl(input);
389
- try {
390
- const res = await baseline(input, init);
391
- if (res.status >= 400) {
392
- push({
393
- method,
394
- url,
395
- status: res.status,
396
- timestamp: now().toISOString()
397
- });
398
- }
399
- return res;
400
- } catch (err) {
401
- push({
402
- method,
403
- url,
404
- status: 0,
405
- timestamp: now().toISOString(),
406
- error: err instanceof Error ? err.message : String(err)
407
- });
408
- throw err;
409
- }
410
- };
411
- target.fetch = wrapped;
412
- active = true;
413
- }
414
- function stop() {
415
- if (!active) return;
416
- if (original) target.fetch = original;
417
- original = void 0;
418
- active = false;
419
- }
420
- return {
421
- start,
422
- stop,
423
- get isActive() {
424
- return active;
425
- },
426
- entries() {
427
- return buffer.slice();
428
- },
429
- clear() {
430
- buffer.length = 0;
431
- }
432
- };
433
- }
434
-
435
- // src/browser/ingest/index.ts
436
- function createIngest(options = {}) {
437
- const opts = options;
438
- const wantConsole = opts.captureConsole !== false;
439
- const wantNetwork = opts.captureNetwork !== false;
440
- const consoleCapture = wantConsole ? createConsoleCapture({
441
- limit: opts.consoleLimit,
442
- target: opts.consoleTarget,
443
- now: opts.now
444
- }) : null;
445
- const networkCapture = wantNetwork ? createNetworkCapture({
446
- limit: opts.networkLimit,
447
- target: opts.networkTarget,
448
- now: opts.now
449
- }) : null;
450
- let active = false;
451
- function start() {
452
- if (active) return;
453
- consoleCapture?.start();
454
- networkCapture?.start();
455
- active = Boolean(consoleCapture?.isActive || networkCapture?.isActive);
456
- }
457
- function stop() {
458
- if (!active) return;
459
- consoleCapture?.stop();
460
- networkCapture?.stop();
461
- active = false;
462
- }
463
- return {
464
- start,
465
- stop,
466
- get isActive() {
467
- return active;
468
- },
469
- console: consoleCapture,
470
- network: networkCapture
471
- };
472
- }
473
- function resolveIngestOptions(explicit, hasCloud) {
474
- if (explicit === null) return null;
475
- if (explicit === void 0) {
476
- return hasCloud ? { captureConsole: true, captureNetwork: true } : null;
477
- }
478
- if (explicit.captureConsole === false && explicit.captureNetwork === false) {
479
- return null;
480
- }
481
- return explicit;
482
- }
483
-
484
283
  // src/browser/internal/cleanup.ts
485
284
  function createCleanupStack() {
486
285
  const stack = [];
@@ -514,60 +313,6 @@ function composeCleanups(cleanups) {
514
313
  };
515
314
  }
516
315
 
517
- // src/browser/internal/dark-mode.ts
518
- function isDarkMode() {
519
- if (typeof document !== "undefined") {
520
- const root = document.documentElement;
521
- if (root?.classList.contains("dark")) return true;
522
- if (root?.classList.contains("light")) return false;
523
- }
524
- if (typeof window !== "undefined" && typeof window.matchMedia === "function") {
525
- return window.matchMedia("(prefers-color-scheme: dark)").matches;
526
- }
527
- return false;
528
- }
529
-
530
- // src/browser/internal/route-change.ts
531
- var ROUTE_CHANGE_EVENT = "uidex:routechange";
532
- var patched = false;
533
- function ensureHistoryPatched() {
534
- if (patched) return;
535
- if (typeof window === "undefined" || typeof history === "undefined") return;
536
- patched = true;
537
- const dispatch = () => {
538
- window.dispatchEvent(new Event(ROUTE_CHANGE_EVENT));
539
- };
540
- const origPush = history.pushState;
541
- history.pushState = function(...args) {
542
- const result = origPush.apply(
543
- this,
544
- args
545
- );
546
- dispatch();
547
- return result;
548
- };
549
- const origReplace = history.replaceState;
550
- history.replaceState = function(...args) {
551
- const result = origReplace.apply(
552
- this,
553
- args
554
- );
555
- dispatch();
556
- return result;
557
- };
558
- }
559
- function bindRouteChange(handler) {
560
- if (typeof window === "undefined") return () => {
561
- };
562
- ensureHistoryPatched();
563
- window.addEventListener("popstate", handler);
564
- window.addEventListener(ROUTE_CHANGE_EVENT, handler);
565
- return () => {
566
- window.removeEventListener("popstate", handler);
567
- window.removeEventListener(ROUTE_CHANGE_EVENT, handler);
568
- };
569
- }
570
-
571
316
  // src/browser/session/store.ts
572
317
  import { createStore as createStore3 } from "zustand/vanilla";
573
318
 
@@ -705,8 +450,7 @@ var defaultSnapshot = {
705
450
  pinnedHighlight: null,
706
451
  mode: "idle",
707
452
  theme: "auto",
708
- resolvedTheme: "light",
709
- user: null
453
+ resolvedTheme: "light"
710
454
  };
711
455
  function resolveTheme(preference, detect) {
712
456
  if (preference !== "auto") return preference;
@@ -796,8 +540,7 @@ function createSession(options = {}) {
796
540
  pinnedHighlight: null,
797
541
  mode: "idle",
798
542
  theme: initialPref,
799
- resolvedTheme: initialResolved,
800
- user: overrides.user ?? null
543
+ resolvedTheme: initialResolved
801
544
  }));
802
545
  nav.subscribe(() => {
803
546
  const { stack } = nav.getState();
@@ -841,8 +584,6 @@ var tailwind_built_default = `/*! tailwindcss v4.2.2 | MIT License | https://tai
841
584
  @layer theme, base, components, utilities;
842
585
  @layer theme {
843
586
  :root, :host {
844
- --font-sans: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI",
845
- Roboto, sans-serif;
846
587
  --color-red-400: oklch(70.4% 0.191 22.216);
847
588
  --color-red-500: oklch(63.7% 0.237 25.331);
848
589
  --color-red-700: oklch(50.5% 0.213 27.518);
@@ -895,7 +636,6 @@ var tailwind_built_default = `/*! tailwindcss v4.2.2 | MIT License | https://tai
895
636
  --color-black: #000;
896
637
  --color-white: #fff;
897
638
  --spacing: 0.25rem;
898
- --container-sm: 24rem;
899
639
  --container-xl: 36rem;
900
640
  --text-xs: 0.75rem;
901
641
  --text-xs--line-height: calc(1 / 0.75);
@@ -903,28 +643,22 @@ var tailwind_built_default = `/*! tailwindcss v4.2.2 | MIT License | https://tai
903
643
  --text-sm--line-height: calc(1.25 / 0.875);
904
644
  --text-base: 1rem;
905
645
  --text-base--line-height: calc(1.5 / 1);
906
- --text-xl: 1.25rem;
907
- --text-xl--line-height: calc(1.75 / 1.25);
908
646
  --font-weight-normal: 400;
909
647
  --font-weight-medium: 500;
910
648
  --font-weight-semibold: 600;
911
- --font-weight-bold: 700;
912
649
  --tracking-tight: -0.025em;
913
650
  --tracking-widest: 0.1em;
914
651
  --leading-relaxed: 1.625;
915
- --radius-md: calc(var(--radius) * 0.8);
916
652
  --radius-lg: var(--radius);
917
653
  --radius-xl: calc(var(--radius) * 1.4);
918
654
  --radius-2xl: calc(var(--radius) * 1.8);
919
655
  --ease-out: cubic-bezier(0, 0, 0.2, 1);
920
- --animate-spin: spin 1s linear infinite;
921
656
  --blur-sm: 8px;
922
657
  --default-transition-duration: 150ms;
923
658
  --default-transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
924
659
  --default-font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI",
925
660
  Roboto, sans-serif;
926
661
  --default-mono-font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
927
- --color-muted: var(--muted);
928
662
  --color-border: var(--border);
929
663
  }
930
664
  }
@@ -1092,17 +826,6 @@ var tailwind_built_default = `/*! tailwindcss v4.2.2 | MIT License | https://tai
1092
826
  .visible {
1093
827
  visibility: visible;
1094
828
  }
1095
- .sr-only {
1096
- position: absolute;
1097
- width: 1px;
1098
- height: 1px;
1099
- padding: 0;
1100
- margin: -1px;
1101
- overflow: hidden;
1102
- clip-path: inset(50%);
1103
- white-space: nowrap;
1104
- border-width: 0;
1105
- }
1106
829
  .absolute {
1107
830
  position: absolute;
1108
831
  }
@@ -1124,30 +847,12 @@ var tailwind_built_default = `/*! tailwindcss v4.2.2 | MIT License | https://tai
1124
847
  .end {
1125
848
  inset-inline-end: var(--spacing);
1126
849
  }
1127
- .-top-1 {
1128
- top: calc(var(--spacing) * -1);
1129
- }
1130
- .-right-1 {
1131
- right: calc(var(--spacing) * -1);
1132
- }
1133
- .right-0 {
1134
- right: calc(var(--spacing) * 0);
1135
- }
1136
- .bottom-full {
1137
- bottom: 100%;
1138
- }
1139
- .bottom-px {
1140
- bottom: 1px;
1141
- }
1142
850
  .z-1 {
1143
851
  z-index: 1;
1144
852
  }
1145
853
  .z-10 {
1146
854
  z-index: 10;
1147
855
  }
1148
- .z-\\[2147483647\\] {
1149
- z-index: 2147483647;
1150
- }
1151
856
  .container {
1152
857
  width: 100%;
1153
858
  @media (width >= 40rem) {
@@ -1181,12 +886,6 @@ var tailwind_built_default = `/*! tailwindcss v4.2.2 | MIT License | https://tai
1181
886
  .mt-1 {
1182
887
  margin-top: calc(var(--spacing) * 1);
1183
888
  }
1184
- .mb-2 {
1185
- margin-bottom: calc(var(--spacing) * 2);
1186
- }
1187
- .mb-6 {
1188
- margin-bottom: calc(var(--spacing) * 6);
1189
- }
1190
889
  .ml-auto {
1191
890
  margin-left: auto;
1192
891
  }
@@ -1205,19 +904,12 @@ var tailwind_built_default = `/*! tailwindcss v4.2.2 | MIT License | https://tai
1205
904
  .inline {
1206
905
  display: inline;
1207
906
  }
1208
- .inline-block {
1209
- display: inline-block;
1210
- }
1211
907
  .inline-flex {
1212
908
  display: inline-flex;
1213
909
  }
1214
910
  .table {
1215
911
  display: table;
1216
912
  }
1217
- .size-2 {
1218
- width: calc(var(--spacing) * 2);
1219
- height: calc(var(--spacing) * 2);
1220
- }
1221
913
  .size-3\\.5 {
1222
914
  width: calc(var(--spacing) * 3.5);
1223
915
  height: calc(var(--spacing) * 3.5);
@@ -1278,21 +970,12 @@ var tailwind_built_default = `/*! tailwindcss v4.2.2 | MIT License | https://tai
1278
970
  .h-full {
1279
971
  height: 100%;
1280
972
  }
1281
- .max-h-32 {
1282
- max-height: calc(var(--spacing) * 32);
1283
- }
1284
- .max-h-full {
1285
- max-height: 100%;
1286
- }
1287
973
  .min-h-0 {
1288
974
  min-height: calc(var(--spacing) * 0);
1289
975
  }
1290
976
  .min-h-8 {
1291
977
  min-height: calc(var(--spacing) * 8);
1292
978
  }
1293
- .min-h-20 {
1294
- min-height: calc(var(--spacing) * 20);
1295
- }
1296
979
  .w-3\\.5 {
1297
980
  width: calc(var(--spacing) * 3.5);
1298
981
  }
@@ -1302,12 +985,6 @@ var tailwind_built_default = `/*! tailwindcss v4.2.2 | MIT License | https://tai
1302
985
  .w-12 {
1303
986
  width: calc(var(--spacing) * 12);
1304
987
  }
1305
- .w-20 {
1306
- width: calc(var(--spacing) * 20);
1307
- }
1308
- .w-36 {
1309
- width: calc(var(--spacing) * 36);
1310
- }
1311
988
  .w-56 {
1312
989
  width: calc(var(--spacing) * 56);
1313
990
  }
@@ -1317,12 +994,6 @@ var tailwind_built_default = `/*! tailwindcss v4.2.2 | MIT License | https://tai
1317
994
  .w-px {
1318
995
  width: 1px;
1319
996
  }
1320
- .max-w-full {
1321
- max-width: 100%;
1322
- }
1323
- .max-w-sm {
1324
- max-width: var(--container-sm);
1325
- }
1326
997
  .max-w-xl {
1327
998
  max-width: var(--container-xl);
1328
999
  }
@@ -1350,41 +1021,9 @@ var tailwind_built_default = `/*! tailwindcss v4.2.2 | MIT License | https://tai
1350
1021
  .shrink-0 {
1351
1022
  flex-shrink: 0;
1352
1023
  }
1353
- .origin-bottom-left {
1354
- transform-origin: 0 100%;
1355
- }
1356
- .origin-bottom-right {
1357
- transform-origin: 100% 100%;
1358
- }
1359
- .-translate-x-0\\.5 {
1360
- --tw-translate-x: calc(var(--spacing) * -0.5);
1361
- translate: var(--tw-translate-x) var(--tw-translate-y);
1362
- }
1363
- .translate-x-0\\.5 {
1364
- --tw-translate-x: calc(var(--spacing) * 0.5);
1365
- translate: var(--tw-translate-x) var(--tw-translate-y);
1366
- }
1367
- .scale-84 {
1368
- --tw-scale-x: 84%;
1369
- --tw-scale-y: 84%;
1370
- --tw-scale-z: 84%;
1371
- scale: var(--tw-scale-x) var(--tw-scale-y);
1372
- }
1373
- .-rotate-10 {
1374
- rotate: calc(10deg * -1);
1375
- }
1376
- .rotate-10 {
1377
- rotate: 10deg;
1378
- }
1379
1024
  .transform {
1380
1025
  transform: var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,);
1381
1026
  }
1382
- .animate-skeleton {
1383
- animation: skeleton 2s -1s infinite linear;
1384
- }
1385
- .animate-spin {
1386
- animation: var(--animate-spin);
1387
- }
1388
1027
  .cursor-pointer {
1389
1028
  cursor: pointer;
1390
1029
  }
@@ -1394,15 +1033,9 @@ var tailwind_built_default = `/*! tailwindcss v4.2.2 | MIT License | https://tai
1394
1033
  .scroll-py-2 {
1395
1034
  scroll-padding-block: calc(var(--spacing) * 2);
1396
1035
  }
1397
- .appearance-none {
1398
- appearance: none;
1399
- }
1400
1036
  .flex-col {
1401
1037
  flex-direction: column;
1402
1038
  }
1403
- .flex-row {
1404
- flex-direction: row;
1405
- }
1406
1039
  .items-center {
1407
1040
  align-items: center;
1408
1041
  }
@@ -1418,9 +1051,6 @@ var tailwind_built_default = `/*! tailwindcss v4.2.2 | MIT License | https://tai
1418
1051
  .gap-0 {
1419
1052
  gap: calc(var(--spacing) * 0);
1420
1053
  }
1421
- .gap-0\\.5 {
1422
- gap: calc(var(--spacing) * 0.5);
1423
- }
1424
1054
  .gap-1 {
1425
1055
  gap: calc(var(--spacing) * 1);
1426
1056
  }
@@ -1433,12 +1063,6 @@ var tailwind_built_default = `/*! tailwindcss v4.2.2 | MIT License | https://tai
1433
1063
  .gap-3 {
1434
1064
  gap: calc(var(--spacing) * 3);
1435
1065
  }
1436
- .gap-4 {
1437
- gap: calc(var(--spacing) * 4);
1438
- }
1439
- .gap-6 {
1440
- gap: calc(var(--spacing) * 6);
1441
- }
1442
1066
  .truncate {
1443
1067
  overflow: hidden;
1444
1068
  text-overflow: ellipsis;
@@ -1536,21 +1160,12 @@ var tailwind_built_default = `/*! tailwindcss v4.2.2 | MIT License | https://tai
1536
1160
  background-color: color-mix(in oklab, var(--color-black) 32%, transparent);
1537
1161
  }
1538
1162
  }
1539
- .bg-black\\/80 {
1540
- background-color: color-mix(in srgb, #000 80%, transparent);
1541
- @supports (color: color-mix(in lab, red, red)) {
1542
- background-color: color-mix(in oklab, var(--color-black) 80%, transparent);
1543
- }
1544
- }
1545
1163
  .bg-blue-50 {
1546
1164
  background-color: var(--color-blue-50);
1547
1165
  }
1548
1166
  .bg-border {
1549
1167
  background-color: var(--border);
1550
1168
  }
1551
- .bg-card {
1552
- background-color: var(--card);
1553
- }
1554
1169
  .bg-cyan-50 {
1555
1170
  background-color: var(--color-cyan-50);
1556
1171
  }
@@ -1566,15 +1181,9 @@ var tailwind_built_default = `/*! tailwindcss v4.2.2 | MIT License | https://tai
1566
1181
  .bg-emerald-50 {
1567
1182
  background-color: var(--color-emerald-50);
1568
1183
  }
1569
- .bg-emerald-500 {
1570
- background-color: var(--color-emerald-500);
1571
- }
1572
1184
  .bg-fuchsia-50 {
1573
1185
  background-color: var(--color-fuchsia-50);
1574
1186
  }
1575
- .bg-info {
1576
- background-color: var(--info);
1577
- }
1578
1187
  .bg-info\\/10 {
1579
1188
  background-color: var(--info);
1580
1189
  @supports (color: color-mix(in lab, red, red)) {
@@ -1626,18 +1235,6 @@ var tailwind_built_default = `/*! tailwindcss v4.2.2 | MIT License | https://tai
1626
1235
  .bg-clip-padding {
1627
1236
  background-clip: padding-box;
1628
1237
  }
1629
- .bg-\\[right_0\\.5rem_center\\] {
1630
- background-position: right 0.5rem center;
1631
- }
1632
- .bg-no-repeat {
1633
- background-repeat: no-repeat;
1634
- }
1635
- .object-cover {
1636
- object-fit: cover;
1637
- }
1638
- .object-top {
1639
- object-position: top;
1640
- }
1641
1238
  .p-1 {
1642
1239
  padding: calc(var(--spacing) * 1);
1643
1240
  }
@@ -1650,9 +1247,6 @@ var tailwind_built_default = `/*! tailwindcss v4.2.2 | MIT License | https://tai
1650
1247
  .p-4 {
1651
1248
  padding: calc(var(--spacing) * 4);
1652
1249
  }
1653
- .p-6 {
1654
- padding: calc(var(--spacing) * 6);
1655
- }
1656
1250
  .px-1 {
1657
1251
  padding-inline: calc(var(--spacing) * 1);
1658
1252
  }
@@ -1674,24 +1268,15 @@ var tailwind_built_default = `/*! tailwindcss v4.2.2 | MIT License | https://tai
1674
1268
  .px-4 {
1675
1269
  padding-inline: calc(var(--spacing) * 4);
1676
1270
  }
1677
- .px-6 {
1678
- padding-inline: calc(var(--spacing) * 6);
1679
- }
1680
1271
  .py-1 {
1681
1272
  padding-block: calc(var(--spacing) * 1);
1682
1273
  }
1683
1274
  .py-1\\.5 {
1684
1275
  padding-block: calc(var(--spacing) * 1.5);
1685
1276
  }
1686
- .py-2 {
1687
- padding-block: calc(var(--spacing) * 2);
1688
- }
1689
1277
  .py-4 {
1690
1278
  padding-block: calc(var(--spacing) * 4);
1691
1279
  }
1692
- .py-12 {
1693
- padding-block: calc(var(--spacing) * 12);
1694
- }
1695
1280
  .py-\\[max\\(1rem\\,4vh\\)\\] {
1696
1281
  padding-block: max(1rem, 4vh);
1697
1282
  }
@@ -1704,12 +1289,6 @@ var tailwind_built_default = `/*! tailwindcss v4.2.2 | MIT License | https://tai
1704
1289
  .pt-2 {
1705
1290
  padding-top: calc(var(--spacing) * 2);
1706
1291
  }
1707
- .pr-8 {
1708
- padding-right: calc(var(--spacing) * 8);
1709
- }
1710
- .pl-3 {
1711
- padding-left: calc(var(--spacing) * 3);
1712
- }
1713
1292
  .text-center {
1714
1293
  text-align: center;
1715
1294
  }
@@ -1727,18 +1306,10 @@ var tailwind_built_default = `/*! tailwindcss v4.2.2 | MIT License | https://tai
1727
1306
  font-size: var(--text-base);
1728
1307
  line-height: var(--tw-leading, var(--text-base--line-height));
1729
1308
  }
1730
- .text-base\\/4\\.5 {
1731
- font-size: var(--text-base);
1732
- line-height: calc(var(--spacing) * 4.5);
1733
- }
1734
1309
  .text-sm {
1735
1310
  font-size: var(--text-sm);
1736
1311
  line-height: var(--tw-leading, var(--text-sm--line-height));
1737
1312
  }
1738
- .text-xl {
1739
- font-size: var(--text-xl);
1740
- line-height: var(--tw-leading, var(--text-xl--line-height));
1741
- }
1742
1313
  .text-xs {
1743
1314
  font-size: var(--text-xs);
1744
1315
  line-height: var(--tw-leading, var(--text-xs--line-height));
@@ -1746,24 +1317,13 @@ var tailwind_built_default = `/*! tailwindcss v4.2.2 | MIT License | https://tai
1746
1317
  .text-\\[0\\.625rem\\] {
1747
1318
  font-size: 0.625rem;
1748
1319
  }
1749
- .text-\\[9px\\] {
1750
- font-size: 9px;
1751
- }
1752
1320
  .text-\\[11px\\] {
1753
1321
  font-size: 11px;
1754
1322
  }
1755
- .leading-none {
1756
- --tw-leading: 1;
1757
- line-height: 1;
1758
- }
1759
1323
  .leading-relaxed {
1760
1324
  --tw-leading: var(--leading-relaxed);
1761
1325
  line-height: var(--leading-relaxed);
1762
1326
  }
1763
- .font-bold {
1764
- --tw-font-weight: var(--font-weight-bold);
1765
- font-weight: var(--font-weight-bold);
1766
- }
1767
1327
  .font-medium {
1768
1328
  --tw-font-weight: var(--font-weight-medium);
1769
1329
  font-weight: var(--font-weight-medium);
@@ -1784,9 +1344,6 @@ var tailwind_built_default = `/*! tailwindcss v4.2.2 | MIT License | https://tai
1784
1344
  --tw-tracking: var(--tracking-widest);
1785
1345
  letter-spacing: var(--tracking-widest);
1786
1346
  }
1787
- .text-balance {
1788
- text-wrap: balance;
1789
- }
1790
1347
  .break-words {
1791
1348
  overflow-wrap: break-word;
1792
1349
  }
@@ -1811,9 +1368,6 @@ var tailwind_built_default = `/*! tailwindcss v4.2.2 | MIT License | https://tai
1811
1368
  .text-cyan-700 {
1812
1369
  color: var(--color-cyan-700);
1813
1370
  }
1814
- .text-destructive {
1815
- color: var(--destructive);
1816
- }
1817
1371
  .text-destructive-foreground {
1818
1372
  color: var(--destructive-foreground);
1819
1373
  }
@@ -1879,18 +1433,12 @@ var tailwind_built_default = `/*! tailwindcss v4.2.2 | MIT License | https://tai
1879
1433
  .line-through {
1880
1434
  text-decoration-line: line-through;
1881
1435
  }
1882
- .underline {
1883
- text-decoration-line: underline;
1884
- }
1885
1436
  .underline-offset-4 {
1886
1437
  text-underline-offset: 4px;
1887
1438
  }
1888
1439
  .accent-accent {
1889
1440
  accent-color: var(--accent);
1890
1441
  }
1891
- .accent-primary {
1892
- accent-color: var(--primary);
1893
- }
1894
1442
  .opacity-50 {
1895
1443
  opacity: 50%;
1896
1444
  }
@@ -1902,11 +1450,6 @@ var tailwind_built_default = `/*! tailwindcss v4.2.2 | MIT License | https://tai
1902
1450
  --tw-shadow: 0 10px 15px -3px var(--tw-shadow-color, oklab(from rgb(0 0 0 / 0.1) l a b / 5%)), 0 4px 6px -4px var(--tw-shadow-color, oklab(from rgb(0 0 0 / 0.1) l a b / 5%));
1903
1451
  box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
1904
1452
  }
1905
- .shadow-sm\\/5 {
1906
- --tw-shadow-alpha: 5%;
1907
- --tw-shadow: 0 1px 3px 0 var(--tw-shadow-color, oklab(from rgb(0 0 0 / 0.1) l a b / 5%)), 0 1px 2px -1px var(--tw-shadow-color, oklab(from rgb(0 0 0 / 0.1) l a b / 5%));
1908
- box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
1909
- }
1910
1453
  .shadow-xs\\/5 {
1911
1454
  --tw-shadow-alpha: 5%;
1912
1455
  --tw-shadow: 0 1px 2px 0 var(--tw-shadow-color, oklab(from rgb(0 0 0 / 0.05) l a b / 5%));
@@ -1916,14 +1459,6 @@ var tailwind_built_default = `/*! tailwindcss v4.2.2 | MIT License | https://tai
1916
1459
  --tw-shadow: 0 1px 3px 0 var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 1px 2px -1px var(--tw-shadow-color, rgb(0 0 0 / 0.1));
1917
1460
  box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
1918
1461
  }
1919
- .shadow-lg {
1920
- --tw-shadow: 0 10px 15px -3px var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 4px 6px -4px var(--tw-shadow-color, rgb(0 0 0 / 0.1));
1921
- box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
1922
- }
1923
- .shadow-none {
1924
- --tw-shadow: 0 0 #0000;
1925
- box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
1926
- }
1927
1462
  .shadow-xs {
1928
1463
  --tw-shadow: 0 1px 2px 0 var(--tw-shadow-color, rgb(0 0 0 / 0.05));
1929
1464
  box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
@@ -2023,15 +1558,6 @@ var tailwind_built_default = `/*! tailwindcss v4.2.2 | MIT License | https://tai
2023
1558
  -webkit-user-select: none;
2024
1559
  user-select: none;
2025
1560
  }
2026
- .\\[--skeleton-highlight\\:--alpha\\(var\\(--color-white\\)\\/64\\%\\)\\] {
2027
- --skeleton-highlight: color-mix(in srgb, #fff 64%, transparent);
2028
- @supports (color: color-mix(in lab, red, red)) {
2029
- --skeleton-highlight: color-mix(in oklab, var(--color-white) 64%, transparent);
2030
- }
2031
- }
2032
- .\\[background\\:linear-gradient\\(120deg\\,transparent_40\\%\\,var\\(--skeleton-highlight\\)\\,transparent_60\\%\\)_var\\(--color-muted\\)_0_0\\/200\\%_100\\%_fixed\\] {
2033
- background: linear-gradient(120deg,transparent 40%,var(--skeleton-highlight),transparent 60%) var(--color-muted) 0 0/200% 100% fixed;
2034
- }
2035
1561
  .\\[clip-path\\:inset\\(0_1px\\)\\] {
2036
1562
  clip-path: inset(0 1px);
2037
1563
  }
@@ -2115,12 +1641,6 @@ var tailwind_built_default = `/*! tailwindcss v4.2.2 | MIT License | https://tai
2115
1641
  border-radius: calc(var(--radius-lg) - 1px);
2116
1642
  }
2117
1643
  }
2118
- .before\\:rounded-\\[calc\\(var\\(--radius-md\\)-1px\\)\\] {
2119
- &::before {
2120
- content: var(--tw-content);
2121
- border-radius: calc(var(--radius-md) - 1px);
2122
- }
2123
- }
2124
1644
  .before\\:rounded-\\[calc\\(var\\(--radius-xl\\)-1px\\)\\] {
2125
1645
  &::before {
2126
1646
  content: var(--tw-content);
@@ -2250,36 +1770,17 @@ var tailwind_built_default = `/*! tailwindcss v4.2.2 | MIT License | https://tai
2250
1770
  outline-style: none;
2251
1771
  }
2252
1772
  }
2253
- .focus-visible\\:border-ring {
2254
- &:focus-visible {
2255
- border-color: var(--ring);
2256
- }
2257
- }
2258
1773
  .focus-visible\\:ring-2 {
2259
1774
  &:focus-visible {
2260
1775
  --tw-ring-shadow: var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color, currentcolor);
2261
1776
  box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
2262
1777
  }
2263
1778
  }
2264
- .focus-visible\\:ring-\\[3px\\] {
2265
- &:focus-visible {
2266
- --tw-ring-shadow: var(--tw-ring-inset,) 0 0 0 calc(3px + var(--tw-ring-offset-width)) var(--tw-ring-color, currentcolor);
2267
- box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
2268
- }
2269
- }
2270
1779
  .focus-visible\\:ring-ring {
2271
1780
  &:focus-visible {
2272
1781
  --tw-ring-color: var(--ring);
2273
1782
  }
2274
1783
  }
2275
- .focus-visible\\:ring-ring\\/30 {
2276
- &:focus-visible {
2277
- --tw-ring-color: var(--ring);
2278
- @supports (color: color-mix(in lab, red, red)) {
2279
- --tw-ring-color: color-mix(in oklab, var(--ring) 30%, transparent);
2280
- }
2281
- }
2282
- }
2283
1784
  .focus-visible\\:ring-offset-1 {
2284
1785
  &:focus-visible {
2285
1786
  --tw-ring-offset-width: 1px;
@@ -2306,24 +1807,6 @@ var tailwind_built_default = `/*! tailwindcss v4.2.2 | MIT License | https://tai
2306
1807
  opacity: 60%;
2307
1808
  }
2308
1809
  }
2309
- .aria-invalid\\:border-destructive\\/40 {
2310
- &[aria-invalid="true"] {
2311
- border-color: var(--destructive);
2312
- @supports (color: color-mix(in lab, red, red)) {
2313
- border-color: color-mix(in oklab, var(--destructive) 40%, transparent);
2314
- }
2315
- }
2316
- }
2317
- .aria-invalid\\:focus-visible\\:ring-destructive\\/20 {
2318
- &[aria-invalid="true"] {
2319
- &:focus-visible {
2320
- --tw-ring-color: var(--destructive);
2321
- @supports (color: color-mix(in lab, red, red)) {
2322
- --tw-ring-color: color-mix(in oklab, var(--destructive) 20%, transparent);
2323
- }
2324
- }
2325
- }
2326
- }
2327
1810
  .data-\\[disabled\\]\\:pointer-events-none {
2328
1811
  &[data-disabled] {
2329
1812
  pointer-events: none;
@@ -2360,12 +1843,6 @@ var tailwind_built_default = `/*! tailwindcss v4.2.2 | MIT License | https://tai
2360
1843
  line-height: var(--tw-leading, var(--text-sm--line-height));
2361
1844
  }
2362
1845
  }
2363
- .sm\\:text-sm\\/4 {
2364
- @media (width >= 40rem) {
2365
- font-size: var(--text-sm);
2366
- line-height: calc(var(--spacing) * 4);
2367
- }
2368
- }
2369
1846
  .dark\\:bg-amber-400\\/10 {
2370
1847
  &:is(.dark *, :host(.dark) *) {
2371
1848
  background-color: color-mix(in srgb, oklch(82.8% 0.189 84.429) 10%, transparent);
@@ -2579,14 +2056,6 @@ var tailwind_built_default = `/*! tailwindcss v4.2.2 | MIT License | https://tai
2579
2056
  }
2580
2057
  }
2581
2058
  }
2582
- .dark\\:\\[--skeleton-highlight\\:--alpha\\(var\\(--color-white\\)\\/4\\%\\)\\] {
2583
- &:is(.dark *, :host(.dark) *) {
2584
- --skeleton-highlight: color-mix(in srgb, #fff 4%, transparent);
2585
- @supports (color: color-mix(in lab, red, red)) {
2586
- --skeleton-highlight: color-mix(in oklab, var(--color-white) 4%, transparent);
2587
- }
2588
- }
2589
- }
2590
2059
  .dark\\:group-data-hover\\:bg-amber-400\\/20 {
2591
2060
  &:is(.dark *, :host(.dark) *) {
2592
2061
  &:is(:where(.group)[data-hover] *) {
@@ -2706,12 +2175,6 @@ var tailwind_built_default = `/*! tailwindcss v4.2.2 | MIT License | https://tai
2706
2175
  height: calc(var(--spacing) * 4);
2707
2176
  }
2708
2177
  }
2709
- .\\[\\&_svg\\:not\\(\\[class\\*\\=\\'size-\\'\\]\\)\\]\\:size-4\\.5 {
2710
- & svg:not([class*='size-']) {
2711
- width: calc(var(--spacing) * 4.5);
2712
- height: calc(var(--spacing) * 4.5);
2713
- }
2714
- }
2715
2178
  .\\[\\[data-kbd-nav\\]_\\&\\]\\:focus-within\\:bg-accent {
2716
2179
  [data-kbd-nav] & {
2717
2180
  &:focus-within {
@@ -2944,36 +2407,6 @@ var tailwind_built_default = `/*! tailwindcss v4.2.2 | MIT License | https://tai
2944
2407
  --warning: var(--color-amber-500);
2945
2408
  --warning-foreground: var(--color-amber-700);
2946
2409
  }
2947
- @property --tw-translate-x {
2948
- syntax: "*";
2949
- inherits: false;
2950
- initial-value: 0;
2951
- }
2952
- @property --tw-translate-y {
2953
- syntax: "*";
2954
- inherits: false;
2955
- initial-value: 0;
2956
- }
2957
- @property --tw-translate-z {
2958
- syntax: "*";
2959
- inherits: false;
2960
- initial-value: 0;
2961
- }
2962
- @property --tw-scale-x {
2963
- syntax: "*";
2964
- inherits: false;
2965
- initial-value: 1;
2966
- }
2967
- @property --tw-scale-y {
2968
- syntax: "*";
2969
- inherits: false;
2970
- initial-value: 1;
2971
- }
2972
- @property --tw-scale-z {
2973
- syntax: "*";
2974
- inherits: false;
2975
- initial-value: 1;
2976
- }
2977
2410
  @property --tw-rotate-x {
2978
2411
  syntax: "*";
2979
2412
  inherits: false;
@@ -3199,20 +2632,9 @@ var tailwind_built_default = `/*! tailwindcss v4.2.2 | MIT License | https://tai
3199
2632
  initial-value: "";
3200
2633
  inherits: false;
3201
2634
  }
3202
- @keyframes spin {
3203
- to {
3204
- transform: rotate(360deg);
3205
- }
3206
- }
3207
2635
  @layer properties {
3208
2636
  @supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))) {
3209
2637
  *, ::before, ::after, ::backdrop {
3210
- --tw-translate-x: 0;
3211
- --tw-translate-y: 0;
3212
- --tw-translate-z: 0;
3213
- --tw-scale-x: 1;
3214
- --tw-scale-y: 1;
3215
- --tw-scale-z: 1;
3216
2638
  --tw-rotate-x: initial;
3217
2639
  --tw-rotate-y: initial;
3218
2640
  --tw-rotate-z: initial;
@@ -3275,7 +2697,6 @@ var tailwind_built_default = `/*! tailwindcss v4.2.2 | MIT License | https://tai
3275
2697
  var SURFACE_HOST_CLASS = "uidex-surface-host";
3276
2698
  var Z_BASE = 2147483630;
3277
2699
  var Z_OVERLAY = 2147483635;
3278
- var Z_PIN_LAYER = 2147483640;
3279
2700
  var Z_CHROME = 2147483645;
3280
2701
  var SURFACE_IGNORE_SELECTOR = `.${SURFACE_HOST_CLASS}`;
3281
2702
  var UIDEX_ATTR_TO_KIND = [
@@ -3629,9 +3050,7 @@ function createInspector(options) {
3629
3050
  import {
3630
3051
  Command,
3631
3052
  Highlighter,
3632
- MapPin,
3633
3053
  MousePointerClick as MousePointerClick2,
3634
- Users,
3635
3054
  createElement as createLucideElement2
3636
3055
  } from "lucide";
3637
3056
 
@@ -3681,7 +3100,6 @@ function el(tag, options = {}, children = []) {
3681
3100
  var DEFAULT_SHORTCUT = { key: "k" };
3682
3101
  var ACTIONS_SHORTCUT = { key: "j" };
3683
3102
  var INSPECT_SHORTCUT = { key: "i" };
3684
- var PINS_SHORTCUT = { key: "u" };
3685
3103
  function formatShortcutLabel(shortcut) {
3686
3104
  const parts = [];
3687
3105
  if (shortcut.mod !== false) parts.push("\u2318");
@@ -3696,19 +3114,17 @@ function matchesShortcut(e, shortcut) {
3696
3114
  return hasMod === wantMod && e.shiftKey === wantShift && !e.altKey && e.key.toLowerCase() === shortcut.key.toLowerCase();
3697
3115
  }
3698
3116
  function bindShadowKeys(options) {
3699
- const { shadowRoot, session, getActionsPopup, getPinLayer } = options;
3117
+ const { shadowRoot, session, getActionsPopup } = options;
3700
3118
  const shortcut = options.shortcut ?? DEFAULT_SHORTCUT;
3701
- const escapeStack = [];
3702
3119
  const onKeydown = (e) => {
3703
3120
  const isMod = e.metaKey || e.ctrlKey;
3704
3121
  const isCmdK = matchesShortcut(e, shortcut);
3705
3122
  const isCmdDot = matchesShortcut(e, ACTIONS_SHORTCUT);
3706
3123
  const isCmdI = matchesShortcut(e, INSPECT_SHORTCUT);
3707
- const isCmdU = matchesShortcut(e, PINS_SHORTCUT);
3708
3124
  const isCmdBracket = isMod && !e.altKey && !e.shiftKey && e.key === "[";
3709
3125
  const isEsc = e.key === "Escape";
3710
3126
  const isPopKey = isEsc || isCmdBracket;
3711
- if (!isCmdK && !isCmdDot && !isCmdI && !isCmdU && !isPopKey) return;
3127
+ if (!isCmdK && !isCmdDot && !isCmdI && !isPopKey) return;
3712
3128
  const popup = getActionsPopup();
3713
3129
  if (popup?.isOpen()) {
3714
3130
  if (isPopKey || isCmdK || isCmdDot) {
@@ -3726,15 +3142,6 @@ function bindShadowKeys(options) {
3726
3142
  }
3727
3143
  return;
3728
3144
  }
3729
- if (isCmdU) {
3730
- const pinLayer = getPinLayer?.();
3731
- if (pinLayer) {
3732
- e.preventDefault();
3733
- e.stopPropagation();
3734
- pinLayer.setVisible(!pinLayer.visible);
3735
- }
3736
- return;
3737
- }
3738
3145
  if (isCmdI) {
3739
3146
  e.preventDefault();
3740
3147
  e.stopPropagation();
@@ -3756,14 +3163,6 @@ function bindShadowKeys(options) {
3756
3163
  }
3757
3164
  return;
3758
3165
  }
3759
- if (escapeStack.length > 0) {
3760
- const top = escapeStack[escapeStack.length - 1];
3761
- if (top()) {
3762
- e.preventDefault();
3763
- e.stopPropagation();
3764
- return;
3765
- }
3766
- }
3767
3166
  const { mode } = session.mode.getState();
3768
3167
  if (mode === "viewing") {
3769
3168
  e.preventDefault();
@@ -3798,13 +3197,6 @@ function bindShadowKeys(options) {
3798
3197
  capture: true
3799
3198
  }
3800
3199
  );
3801
- },
3802
- pushEscapeLayer(handler) {
3803
- escapeStack.push(handler);
3804
- return () => {
3805
- const idx = escapeStack.indexOf(handler);
3806
- if (idx >= 0) escapeStack.splice(idx, 1);
3807
- };
3808
3200
  }
3809
3201
  };
3810
3202
  }
@@ -3820,11 +3212,8 @@ function createMenuBar(options) {
3820
3212
  container,
3821
3213
  session,
3822
3214
  initialCorner = "bottom-right",
3823
- appTitle,
3824
- channel = null,
3825
- pinLayer: initialPinLayer = null
3215
+ appTitle
3826
3216
  } = options;
3827
- let activePinLayer = initialPinLayer;
3828
3217
  const root = el("div", {
3829
3218
  class: ROOT_CLASS,
3830
3219
  attrs: {
@@ -3889,108 +3278,6 @@ function createMenuBar(options) {
3889
3278
  inspectBtn.blur();
3890
3279
  });
3891
3280
  root.appendChild(inspectBtn);
3892
- const pinIcon = createLucideElement2(MapPin);
3893
- pinIcon.setAttribute("class", "size-3.5");
3894
- pinIcon.setAttribute("aria-hidden", "true");
3895
- const pinBtn = el(
3896
- "button",
3897
- {
3898
- class: BUTTON_CLASS,
3899
- attrs: {
3900
- type: "button",
3901
- "data-uidex-menubar-pins": "",
3902
- "aria-label": "Report pins"
3903
- }
3904
- },
3905
- pinIcon
3906
- );
3907
- const pinWrapper = el("div", {
3908
- class: "relative z-1 inline-flex items-center gap-0.5",
3909
- attrs: { "data-uidex-menubar-pin-wrapper": "" }
3910
- });
3911
- pinWrapper.hidden = true;
3912
- pinWrapper.appendChild(pinBtn);
3913
- root.appendChild(pinWrapper);
3914
- const updatePinUI = () => {
3915
- if (!activePinLayer) {
3916
- pinWrapper.hidden = true;
3917
- return;
3918
- }
3919
- const pinsVisible = activePinLayer.visible;
3920
- pinWrapper.hidden = false;
3921
- pinBtn.className = cn(BUTTON_CLASS, pinsVisible && BUTTON_ACTIVE_CLASS);
3922
- };
3923
- pinBtn.addEventListener("click", (e) => {
3924
- e.stopPropagation();
3925
- if (activePinLayer) {
3926
- activePinLayer.setVisible(!activePinLayer.visible);
3927
- }
3928
- });
3929
- let unsubscribePinFilter = activePinLayer?.onFilterChange(() => updatePinUI());
3930
- const presenceIcon = createLucideElement2(Users);
3931
- presenceIcon.setAttribute("class", "size-3.5");
3932
- presenceIcon.setAttribute("aria-hidden", "true");
3933
- const presenceBtn = el(
3934
- "button",
3935
- {
3936
- class: BUTTON_CLASS,
3937
- attrs: {
3938
- type: "button",
3939
- "data-uidex-menubar-presence": "",
3940
- "aria-label": "Online users"
3941
- }
3942
- },
3943
- presenceIcon
3944
- );
3945
- presenceBtn.hidden = true;
3946
- const presenceBadge = el("span", {
3947
- class: "absolute -top-1 -right-1 z-1 inline-flex size-3.5 items-center justify-center rounded-full bg-info text-[9px] font-bold leading-none text-info-foreground"
3948
- });
3949
- presenceBtn.appendChild(presenceBadge);
3950
- const presencePopover = el("div", {
3951
- class: "absolute bottom-full mb-2 right-0 min-w-32 rounded-lg border border-border bg-popover p-2 text-xs text-popover-foreground shadow-lg"
3952
- });
3953
- presencePopover.hidden = true;
3954
- let presencePopoverVisible = false;
3955
- presenceBtn.addEventListener("click", (e) => {
3956
- e.stopPropagation();
3957
- presencePopoverVisible = !presencePopoverVisible;
3958
- presencePopover.hidden = !presencePopoverVisible;
3959
- });
3960
- const presenceWrapper = el("div", { class: "relative z-1 inline-flex" }, [
3961
- presenceBtn,
3962
- presencePopover
3963
- ]);
3964
- presenceWrapper.hidden = true;
3965
- root.appendChild(presenceWrapper);
3966
- let presenceUsers = [];
3967
- const updatePresenceUI = () => {
3968
- const localUserId = session.getState().user?.id ?? null;
3969
- const peers = localUserId ? presenceUsers.filter((u) => u.userId !== localUserId) : presenceUsers;
3970
- const count = peers.length;
3971
- presenceWrapper.hidden = count === 0;
3972
- presenceBadge.textContent = String(count);
3973
- presenceBtn.setAttribute(
3974
- "aria-label",
3975
- count === 1 ? "1 other user online" : `${count} other users online`
3976
- );
3977
- presencePopover.innerHTML = "";
3978
- for (const user of peers) {
3979
- const row = el("div", {
3980
- class: "flex items-center gap-2 rounded px-1.5 py-1"
3981
- });
3982
- const dot = el("span", {
3983
- class: "inline-block size-2 shrink-0 rounded-full bg-emerald-500"
3984
- });
3985
- const name = el("span", {
3986
- class: "truncate",
3987
- text: user.name || "Anonymous"
3988
- });
3989
- row.appendChild(dot);
3990
- row.appendChild(name);
3991
- presencePopover.appendChild(row);
3992
- }
3993
- };
3994
3281
  const paletteIcon = createLucideElement2(Command);
3995
3282
  paletteIcon.setAttribute("class", "size-3.5");
3996
3283
  paletteIcon.setAttribute("aria-hidden", "true");
@@ -4105,28 +3392,14 @@ function createMenuBar(options) {
4105
3392
  const vertical = y / (window.innerHeight || 1) < 0.5 ? "top" : "bottom";
4106
3393
  snapTo(`${vertical}-${horizontal}`);
4107
3394
  }
4108
- const unsubscribePresence = channel?.onPresence(
4109
- (users) => {
4110
- presenceUsers = users;
4111
- updatePresenceUI();
4112
- }
4113
- );
4114
3395
  return {
4115
3396
  destroy() {
4116
- unsubscribePinFilter?.();
4117
- unsubscribePresence?.();
4118
3397
  unsubscribeSession();
4119
3398
  root.removeEventListener("mousedown", onMouseDown);
4120
3399
  document.removeEventListener("mousemove", onMouseMove);
4121
3400
  document.removeEventListener("mouseup", onMouseUp);
4122
3401
  root.remove();
4123
3402
  },
4124
- setPinLayer(layer) {
4125
- unsubscribePinFilter?.();
4126
- activePinLayer = layer;
4127
- unsubscribePinFilter = layer.onFilterChange(() => updatePinUI());
4128
- updatePinUI();
4129
- },
4130
3403
  snapTo,
4131
3404
  snapToNearest,
4132
3405
  get corner() {
@@ -4484,9 +3757,7 @@ function createSurfaceShell(options) {
4484
3757
  container: host.chromeEl,
4485
3758
  session: options.session,
4486
3759
  initialCorner: options.initialCorner,
4487
- appTitle: options.appTitle,
4488
- channel: options.channel ?? null,
4489
- pinLayer: options.pinLayer ?? null
3760
+ appTitle: options.appTitle
4490
3761
  });
4491
3762
  cleanup.add(menuBar);
4492
3763
  return {
@@ -4501,547 +3772,6 @@ function createSurfaceShell(options) {
4501
3772
  };
4502
3773
  }
4503
3774
 
4504
- // src/browser/report/constants.ts
4505
- var TYPE_LABELS = {
4506
- bug: "Bug",
4507
- request: "Request",
4508
- suggestion: "Suggestion"
4509
- };
4510
- var SEVERITY_LABELS = {
4511
- critical: "Critical",
4512
- high: "High",
4513
- medium: "Medium",
4514
- low: "Low"
4515
- };
4516
- function authorLabel(rec) {
4517
- const name = rec.reporter?.name ?? rec.reporterName;
4518
- const email = rec.reporter?.email ?? rec.reporterEmail;
4519
- return name?.trim() || email?.trim() || "Anonymous";
4520
- }
4521
- function relativeTime(iso) {
4522
- const ms = Date.parse(iso);
4523
- if (!Number.isFinite(ms)) return "";
4524
- const s = Math.floor((Date.now() - ms) / 1e3);
4525
- if (s < 60) return "just now";
4526
- const m = Math.floor(s / 60);
4527
- if (m < 60) return `${m}m ago`;
4528
- const h = Math.floor(m / 60);
4529
- if (h < 24) return `${h}h ago`;
4530
- const d = Math.floor(h / 24);
4531
- if (d < 30) return `${d}d ago`;
4532
- return `${Math.floor(d / 30)}mo ago`;
4533
- }
4534
-
4535
- // src/browser/surface/pin-layer.ts
4536
- import {
4537
- Bug,
4538
- CircleHelp,
4539
- Lightbulb,
4540
- MessageSquarePlus,
4541
- Sparkles as Sparkles2,
4542
- StickyNote,
4543
- createElement as createLucideElement3
4544
- } from "lucide";
4545
- var KNOWN_KINDS = new Set(UIDEX_ATTR_TO_KIND.map(([, k]) => k));
4546
- function parseComponentRef(componentId) {
4547
- const colon = componentId.indexOf(":");
4548
- if (colon > 0) {
4549
- const maybeKind = componentId.slice(0, colon);
4550
- if (KNOWN_KINDS.has(maybeKind)) {
4551
- return { kind: maybeKind, id: componentId.slice(colon + 1) };
4552
- }
4553
- }
4554
- return { kind: "element", id: componentId };
4555
- }
4556
- var DOT = 28;
4557
- var BORDER = 2;
4558
- var ICON = 16;
4559
- var PAD = 10;
4560
- var CARD_W = 280;
4561
- var LINE_H = 17;
4562
- var HEADER_H = 16;
4563
- var BODY_MT = 2;
4564
- var CYCLE_H = 18;
4565
- var CARD_H = PAD + HEADER_H + BODY_MT + LINE_H * 2 + CYCLE_H + PAD;
4566
- var INSET = 4;
4567
- var TYPE_ICON = {
4568
- bug: Bug,
4569
- request: MessageSquarePlus,
4570
- suggestion: Lightbulb,
4571
- feature: Lightbulb,
4572
- improvement: Sparkles2,
4573
- question: CircleHelp,
4574
- note: StickyNote
4575
- };
4576
- var TYPE_COLOR = {
4577
- bug: {
4578
- bg: "color-mix(in srgb, var(--destructive) 10%, var(--background))",
4579
- fg: "var(--destructive-foreground)"
4580
- },
4581
- request: {
4582
- bg: "color-mix(in srgb, var(--info) 10%, var(--background))",
4583
- fg: "var(--info-foreground)"
4584
- },
4585
- suggestion: {
4586
- bg: "color-mix(in srgb, var(--warning) 10%, var(--background))",
4587
- fg: "var(--warning-foreground)"
4588
- },
4589
- feature: { bg: "var(--secondary)", fg: "var(--secondary-foreground)" },
4590
- improvement: {
4591
- bg: "color-mix(in srgb, var(--info) 10%, var(--background))",
4592
- fg: "var(--info-foreground)"
4593
- },
4594
- question: {
4595
- bg: "color-mix(in srgb, var(--warning) 10%, var(--background))",
4596
- fg: "var(--warning-foreground)"
4597
- },
4598
- note: {
4599
- bg: "color-mix(in srgb, var(--primary) 10%, var(--background))",
4600
- fg: "var(--primary)"
4601
- }
4602
- };
4603
- var FALLBACK_COLOR = {
4604
- bg: "var(--secondary)",
4605
- fg: "var(--secondary-foreground)"
4606
- };
4607
- function typeColors(t) {
4608
- return TYPE_COLOR[t] ?? FALLBACK_COLOR;
4609
- }
4610
- function typeIcon(t) {
4611
- return TYPE_ICON[t] ?? StickyNote;
4612
- }
4613
- var EASE_OUT = "cubic-bezier(0.16, 1, 0.3, 1)";
4614
- var DUR_FADE = 120;
4615
- var DUR_EXPAND = 250;
4616
- var T_FADE = `opacity ${DUR_FADE}ms ease`;
4617
- function createPinLayer(options) {
4618
- const { container, onOpenPinDetail, onHoverPin, onPinsChanged } = options;
4619
- const layerEl = document.createElement("div");
4620
- layerEl.setAttribute("data-uidex-pin-layer", "");
4621
- Object.assign(layerEl.style, {
4622
- position: "fixed",
4623
- inset: "0",
4624
- zIndex: String(Z_PIN_LAYER),
4625
- pointerEvents: "none"
4626
- });
4627
- container.appendChild(layerEl);
4628
- let layerVisible = true;
4629
- const allPins = [];
4630
- const seenIds = /* @__PURE__ */ new Set();
4631
- const byComp = /* @__PURE__ */ new Map();
4632
- const indicators = /* @__PURE__ */ new Map();
4633
- const filterCbs = /* @__PURE__ */ new Set();
4634
- const notifyFilter = () => {
4635
- for (const cb of filterCbs) cb();
4636
- };
4637
- const rebuildFiltered = () => {
4638
- byComp.clear();
4639
- for (const p of allPins) {
4640
- const cid = p.entity ?? "";
4641
- const list = byComp.get(cid);
4642
- if (list) list.push(p);
4643
- else byComp.set(cid, [p]);
4644
- }
4645
- };
4646
- const rerender = () => {
4647
- rebuildFiltered();
4648
- for (const id of Array.from(indicators.keys())) {
4649
- if (!byComp.has(id)) removeIndicator(id);
4650
- }
4651
- for (const id of byComp.keys()) renderIndicator(id);
4652
- notifyFilter();
4653
- onPinsChanged?.();
4654
- };
4655
- let obs = null;
4656
- const repositioner = createRepositioner(() => posAll());
4657
- const attachObs = () => {
4658
- if (obs || typeof MutationObserver === "undefined") return;
4659
- obs = new MutationObserver((recs) => {
4660
- for (const r of recs) {
4661
- if (r.type === "childList" && (r.addedNodes.length || r.removedNodes.length)) {
4662
- refreshAnchors();
4663
- return;
4664
- }
4665
- }
4666
- });
4667
- obs.observe(document.body, { childList: true, subtree: true });
4668
- };
4669
- const detachObs = () => {
4670
- obs?.disconnect();
4671
- obs = null;
4672
- };
4673
- const refreshAnchors = () => {
4674
- let changed = false;
4675
- for (const s of indicators.values()) {
4676
- if (s.anchor && s.anchor.isConnected) continue;
4677
- s.anchor = resolveEntityElement(parseComponentRef(s.componentId));
4678
- changed = true;
4679
- }
4680
- if (changed) repositioner.schedule();
4681
- };
4682
- const expand = (st) => {
4683
- if (st.expanded) return;
4684
- st.expanded = true;
4685
- fillContent(st);
4686
- st.wrap.style.zIndex = "1";
4687
- st.iconEl.style.transition = T_FADE;
4688
- st.iconEl.style.opacity = "0";
4689
- st.badgeEl.style.visibility = "hidden";
4690
- st.el.style.transition = `width ${DUR_EXPAND}ms ${EASE_OUT} ${DUR_FADE}ms, height ${DUR_EXPAND}ms ${EASE_OUT} ${DUR_FADE}ms`;
4691
- st.el.style.width = `${CARD_W}px`;
4692
- st.el.style.height = `${CARD_H}px`;
4693
- st.contentEl.style.transition = `opacity ${DUR_FADE}ms ease ${DUR_FADE + DUR_EXPAND}ms`;
4694
- st.contentEl.style.opacity = "1";
4695
- if (st.anchor) onHoverPin?.(st.anchor, st.componentId);
4696
- };
4697
- const collapse = (st) => {
4698
- if (!st.expanded) return;
4699
- st.expanded = false;
4700
- st.contentEl.style.transition = T_FADE;
4701
- st.contentEl.style.opacity = "0";
4702
- st.el.style.transition = `width ${DUR_EXPAND}ms ${EASE_OUT} ${DUR_FADE}ms, height ${DUR_EXPAND}ms ${EASE_OUT} ${DUR_FADE}ms`;
4703
- st.el.style.width = `${DOT}px`;
4704
- st.el.style.height = `${DOT}px`;
4705
- st.iconEl.style.transition = `opacity ${DUR_FADE}ms ease ${DUR_FADE + DUR_EXPAND}ms`;
4706
- st.iconEl.style.opacity = "1";
4707
- st.badgeEl.style.visibility = "";
4708
- st.iconEl.addEventListener(
4709
- "transitionend",
4710
- () => {
4711
- if (!st.expanded) st.wrap.style.zIndex = "";
4712
- },
4713
- { once: true }
4714
- );
4715
- onHoverPin?.(null, null);
4716
- };
4717
- const fillContent = (st) => {
4718
- const pins = byComp.get(st.componentId);
4719
- if (!pins?.length) return;
4720
- const idx = Math.max(0, Math.min(st.pinIndex, pins.length - 1));
4721
- st.pinIndex = idx;
4722
- const pin = pins[idx];
4723
- st.contentEl.innerHTML = "";
4724
- const hdr = document.createElement("div");
4725
- hdr.style.display = "flex";
4726
- hdr.style.alignItems = "baseline";
4727
- hdr.style.gap = "6px";
4728
- const nm = document.createElement("span");
4729
- nm.style.fontWeight = "600";
4730
- nm.style.fontSize = "12px";
4731
- nm.textContent = authorLabel(pin);
4732
- hdr.appendChild(nm);
4733
- const tm = document.createElement("span");
4734
- tm.style.fontSize = "11px";
4735
- tm.style.opacity = "0.75";
4736
- tm.textContent = relativeTime(pin.createdAt);
4737
- hdr.appendChild(tm);
4738
- st.contentEl.appendChild(hdr);
4739
- const body = document.createElement("div");
4740
- Object.assign(body.style, {
4741
- fontSize: "12px",
4742
- lineHeight: "1.4",
4743
- marginTop: "2px",
4744
- whiteSpace: "pre-wrap",
4745
- overflow: "hidden",
4746
- display: "-webkit-box"
4747
- });
4748
- body.style.setProperty("-webkit-line-clamp", "2");
4749
- body.style.setProperty("-webkit-box-orient", "vertical");
4750
- body.textContent = pin.body;
4751
- st.contentEl.appendChild(body);
4752
- const ctr = document.createElement("div");
4753
- Object.assign(ctr.style, {
4754
- fontSize: "10px",
4755
- opacity: "0.5",
4756
- marginTop: "4px"
4757
- });
4758
- ctr.textContent = pins.length > 1 ? `${idx + 1} of ${pins.length} \xB7 right-click to cycle` : "click to open";
4759
- st.contentEl.appendChild(ctr);
4760
- };
4761
- const buildIndicator = (componentId) => {
4762
- const wrap = document.createElement("div");
4763
- wrap.setAttribute("data-uidex-pin-wrap", "");
4764
- Object.assign(wrap.style, {
4765
- position: "fixed",
4766
- display: "none",
4767
- pointerEvents: "none"
4768
- });
4769
- const el2 = document.createElement("button");
4770
- el2.type = "button";
4771
- el2.setAttribute("data-uidex-pin", "");
4772
- el2.setAttribute("data-uidex-pin-component", componentId);
4773
- el2.setAttribute("aria-label", `Open report for ${componentId}`);
4774
- Object.assign(el2.style, {
4775
- position: "relative",
4776
- width: `${DOT}px`,
4777
- height: `${DOT}px`,
4778
- borderRadius: `${DOT / 2}px`,
4779
- border: `${BORDER}px solid var(--background)`,
4780
- padding: "0",
4781
- margin: "0",
4782
- cursor: "pointer",
4783
- pointerEvents: "auto",
4784
- overflow: "hidden",
4785
- boxShadow: "0 2px 8px rgba(0,0,0,0.15), 0 0 0 1px rgba(0,0,0,0.05)",
4786
- fontFamily: "var(--font-sans)",
4787
- textAlign: "left",
4788
- float: "right"
4789
- });
4790
- wrap.appendChild(el2);
4791
- const iconEl = document.createElement("span");
4792
- iconEl.setAttribute("data-uidex-pin-icon", "");
4793
- Object.assign(iconEl.style, {
4794
- position: "absolute",
4795
- inset: "0",
4796
- display: "flex",
4797
- alignItems: "center",
4798
- justifyContent: "center"
4799
- });
4800
- el2.appendChild(iconEl);
4801
- const badgeEl = document.createElement("span");
4802
- badgeEl.setAttribute("data-uidex-pin-badge", "");
4803
- Object.assign(badgeEl.style, {
4804
- position: "absolute",
4805
- top: "-4px",
4806
- right: "-4px",
4807
- minWidth: "14px",
4808
- height: "14px",
4809
- borderRadius: "999px",
4810
- background: "var(--foreground)",
4811
- color: "var(--background)",
4812
- fontSize: "9px",
4813
- fontWeight: "600",
4814
- display: "none",
4815
- alignItems: "center",
4816
- justifyContent: "center",
4817
- padding: "0 3px",
4818
- lineHeight: "1",
4819
- zIndex: "2",
4820
- pointerEvents: "none"
4821
- });
4822
- wrap.appendChild(badgeEl);
4823
- const contentEl = document.createElement("div");
4824
- contentEl.setAttribute("data-uidex-pin-content", "");
4825
- Object.assign(contentEl.style, {
4826
- position: "absolute",
4827
- top: `${PAD}px`,
4828
- left: `${PAD}px`,
4829
- right: `${PAD}px`,
4830
- opacity: "0",
4831
- minWidth: "0"
4832
- });
4833
- el2.appendChild(contentEl);
4834
- const st = {
4835
- componentId,
4836
- wrap,
4837
- el: el2,
4838
- iconEl,
4839
- badgeEl,
4840
- contentEl,
4841
- anchor: null,
4842
- pinIndex: 0,
4843
- expanded: false,
4844
- lastType: null
4845
- };
4846
- el2.addEventListener("mouseenter", () => expand(st));
4847
- el2.addEventListener("mouseleave", () => collapse(st));
4848
- el2.addEventListener("click", (e) => {
4849
- e.stopPropagation();
4850
- e.preventDefault();
4851
- const pins = byComp.get(componentId);
4852
- const pin = pins?.[st.pinIndex];
4853
- if (pin) onOpenPinDetail?.(componentId, pin.id);
4854
- });
4855
- el2.addEventListener("contextmenu", (e) => {
4856
- e.stopPropagation();
4857
- e.preventDefault();
4858
- const pins = byComp.get(componentId);
4859
- if (!pins || pins.length <= 1) return;
4860
- st.pinIndex = (st.pinIndex + 1) % pins.length;
4861
- applyStyle(st);
4862
- if (st.expanded) fillContent(st);
4863
- });
4864
- layerEl.appendChild(wrap);
4865
- return st;
4866
- };
4867
- const applyStyle = (st) => {
4868
- const pins = byComp.get(st.componentId);
4869
- if (!pins?.length) return;
4870
- const idx = Math.max(0, Math.min(st.pinIndex, pins.length - 1));
4871
- st.pinIndex = idx;
4872
- const pin = pins[idx];
4873
- const c = typeColors(pin.type);
4874
- st.el.style.backgroundColor = "var(--background)";
4875
- st.el.style.backgroundImage = `linear-gradient(${c.bg}, ${c.bg})`;
4876
- st.el.style.color = c.fg;
4877
- if (st.lastType !== pin.type) {
4878
- st.lastType = pin.type;
4879
- st.iconEl.innerHTML = "";
4880
- const svg2 = createLucideElement3(typeIcon(pin.type));
4881
- svg2.setAttribute("width", String(ICON));
4882
- svg2.setAttribute("height", String(ICON));
4883
- st.iconEl.appendChild(svg2);
4884
- }
4885
- if (pins.length > 1) {
4886
- st.badgeEl.textContent = String(pins.length);
4887
- st.badgeEl.style.display = "flex";
4888
- } else {
4889
- st.badgeEl.textContent = "";
4890
- st.badgeEl.style.display = "none";
4891
- }
4892
- };
4893
- const posIndicator = (st) => {
4894
- const a = st.anchor;
4895
- if (!a || !a.isConnected) {
4896
- st.wrap.style.display = "none";
4897
- return;
4898
- }
4899
- const r = a.getBoundingClientRect();
4900
- if (r.width === 0 && r.height === 0) {
4901
- st.wrap.style.display = "none";
4902
- return;
4903
- }
4904
- const vw = window.innerWidth;
4905
- st.wrap.style.top = `${r.top + INSET}px`;
4906
- st.wrap.style.right = `${vw - r.right + INSET}px`;
4907
- st.wrap.style.display = "";
4908
- };
4909
- const posAll = () => {
4910
- for (const st of indicators.values()) posIndicator(st);
4911
- };
4912
- const renderIndicator = (componentId) => {
4913
- const pins = byComp.get(componentId);
4914
- if (!pins?.length) {
4915
- removeIndicator(componentId);
4916
- return;
4917
- }
4918
- let st = indicators.get(componentId);
4919
- if (!st) {
4920
- st = buildIndicator(componentId);
4921
- indicators.set(componentId, st);
4922
- repositioner.attach();
4923
- attachObs();
4924
- }
4925
- if (st.pinIndex >= pins.length) st.pinIndex = 0;
4926
- applyStyle(st);
4927
- st.anchor = resolveEntityElement(parseComponentRef(componentId));
4928
- posIndicator(st);
4929
- };
4930
- const removeIndicator = (componentId) => {
4931
- const st = indicators.get(componentId);
4932
- if (!st) return;
4933
- st.wrap.remove();
4934
- indicators.delete(componentId);
4935
- if (indicators.size === 0) {
4936
- repositioner.detach();
4937
- detachObs();
4938
- }
4939
- };
4940
- const ingest = (pin) => {
4941
- const cid = pin.entity ?? "";
4942
- if (!cid || seenIds.has(pin.id)) return false;
4943
- seenIds.add(pin.id);
4944
- allPins.push(pin);
4945
- return true;
4946
- };
4947
- let activeRefresh = null;
4948
- const layer = {
4949
- setPins(pins) {
4950
- allPins.length = 0;
4951
- seenIds.clear();
4952
- for (const p of pins) ingest(p);
4953
- rerender();
4954
- },
4955
- addPin(pin) {
4956
- if (!ingest(pin)) return;
4957
- rerender();
4958
- },
4959
- removePin(reportId) {
4960
- const i = allPins.findIndex((p) => p.id === reportId);
4961
- if (i === -1) return;
4962
- allPins.splice(i, 1);
4963
- seenIds.delete(reportId);
4964
- rerender();
4965
- },
4966
- clear() {
4967
- allPins.length = 0;
4968
- seenIds.clear();
4969
- byComp.clear();
4970
- for (const id of Array.from(indicators.keys())) removeIndicator(id);
4971
- notifyFilter();
4972
- },
4973
- getPinsForElement: (id) => byComp.get(id) ?? [],
4974
- getAllPins: () => allPins.slice(),
4975
- attachChannel(channel) {
4976
- const offPin = channel.onPin((pin) => {
4977
- layer.addPin(pin);
4978
- });
4979
- const offArchived = channel.onPinArchived?.((reportId) => {
4980
- layer.removePin(reportId);
4981
- }) ?? (() => {
4982
- });
4983
- return () => {
4984
- offPin();
4985
- offArchived();
4986
- };
4987
- },
4988
- attachCloud(opts) {
4989
- const offCh = opts.channel ? layer.attachChannel(opts.channel) : () => {
4990
- };
4991
- const fetch2 = async () => {
4992
- try {
4993
- const mode = opts.getMatchMode();
4994
- let params;
4995
- if (mode === "component") {
4996
- params = { entities: opts.getVisibleEntities().join(",") };
4997
- } else if (mode === "pathname") {
4998
- params = { route: opts.getPathname() };
4999
- } else {
5000
- params = { route: opts.getRoute() };
5001
- }
5002
- layer.setPins(await opts.cloud.pins.list(params));
5003
- } catch (err) {
5004
- opts.onError?.(err);
5005
- }
5006
- };
5007
- void fetch2();
5008
- activeRefresh = fetch2;
5009
- return () => {
5010
- offCh();
5011
- if (activeRefresh === fetch2) activeRefresh = null;
5012
- };
5013
- },
5014
- async refresh() {
5015
- if (activeRefresh) await activeRefresh();
5016
- },
5017
- onFilterChange(cb) {
5018
- filterCbs.add(cb);
5019
- return () => {
5020
- filterCbs.delete(cb);
5021
- };
5022
- },
5023
- get visible() {
5024
- return layerVisible;
5025
- },
5026
- setVisible(v) {
5027
- if (layerVisible === v) return;
5028
- layerVisible = v;
5029
- layerEl.style.display = v ? "" : "none";
5030
- if (v) posAll();
5031
- notifyFilter();
5032
- },
5033
- destroy() {
5034
- layer.clear();
5035
- repositioner.detach();
5036
- detachObs();
5037
- layerEl.remove();
5038
- activeRefresh = null;
5039
- filterCbs.clear();
5040
- }
5041
- };
5042
- return layer;
5043
- }
5044
-
5045
3775
  // src/browser/views/core/types.ts
5046
3776
  var ViewValidationError = class extends Error {
5047
3777
  constructor(message) {
@@ -5237,7 +3967,7 @@ function createChip(options = {}, children = []) {
5237
3967
  }
5238
3968
 
5239
3969
  // src/browser/views/primitives/kind-icon.ts
5240
- import { createElement as createLucideElement4 } from "lucide";
3970
+ import { createElement as createLucideElement3 } from "lucide";
5241
3971
 
5242
3972
  // src/browser/ui/cva.ts
5243
3973
  function cva(base, config = {}) {
@@ -5325,7 +4055,7 @@ function iconTileTpl(inner, options = {}) {
5325
4055
  // src/browser/views/primitives/kind-icon.ts
5326
4056
  function renderKindIcon(kind) {
5327
4057
  const style = KIND_STYLE[kind];
5328
- const svg2 = createLucideElement4(style.icon);
4058
+ const svg2 = createLucideElement3(style.icon);
5329
4059
  svg2.setAttribute("aria-hidden", "true");
5330
4060
  svg2.setAttribute("class", cn("h-4 w-4 shrink-0", style.tone));
5331
4061
  return svg2;
@@ -5437,7 +4167,7 @@ function createBindable(propsFn) {
5437
4167
  }
5438
4168
  };
5439
4169
  }
5440
- function createMachineHandle(zagMachine, connect4, normalize, props = {}) {
4170
+ function createMachineHandle(zagMachine, connect3, normalize, props = {}) {
5441
4171
  const runner = createMachineRunner(
5442
4172
  zagMachine,
5443
4173
  props
@@ -5445,12 +4175,12 @@ function createMachineHandle(zagMachine, connect4, normalize, props = {}) {
5445
4175
  runner.start();
5446
4176
  return {
5447
4177
  runner,
5448
- api: () => connect4(runner.service, normalize),
4178
+ api: () => connect3(runner.service, normalize),
5449
4179
  destroy: () => runner.stop()
5450
4180
  };
5451
4181
  }
5452
4182
  function createMachineRunner(machineArg, initialProps = {}) {
5453
- const machine4 = machineArg;
4183
+ const machine3 = machineArg;
5454
4184
  let userProps = initialProps;
5455
4185
  const unmountFns = [];
5456
4186
  const listeners = /* @__PURE__ */ new Set();
@@ -5467,7 +4197,7 @@ function createMachineRunner(machineArg, initialProps = {}) {
5467
4197
  };
5468
4198
  };
5469
4199
  const debug = (...args) => {
5470
- if (machine4.debug) {
4200
+ if (machine3.debug) {
5471
4201
  console.log(...args);
5472
4202
  }
5473
4203
  };
@@ -5475,7 +4205,7 @@ function createMachineRunner(machineArg, initialProps = {}) {
5475
4205
  const prop = (key) => propsRef.current[key];
5476
4206
  const refreshProps = () => {
5477
4207
  const scope = scopeRef.current;
5478
- const computedProps = machine4.props?.({
4208
+ const computedProps = machine3.props?.({
5479
4209
  props: compact(userProps),
5480
4210
  scope
5481
4211
  }) ?? userProps;
@@ -5509,7 +4239,7 @@ function createMachineRunner(machineArg, initialProps = {}) {
5509
4239
  return values.some((v) => matchesState(state.ref.current, v));
5510
4240
  },
5511
4241
  hasTag(tag) {
5512
- return hasTagFn(machine4, state.ref.current, tag);
4242
+ return hasTagFn(machine3, state.ref.current, tag);
5513
4243
  }
5514
4244
  });
5515
4245
  const getParams = () => ({
@@ -5531,7 +4261,7 @@ function createMachineRunner(machineArg, initialProps = {}) {
5531
4261
  const strs = isFunction(keys) ? keys(getParams()) : keys;
5532
4262
  if (!strs) return;
5533
4263
  const fns = strs.map((s) => {
5534
- const fn = machine4.implementations?.actions?.[s];
4264
+ const fn = machine3.implementations?.actions?.[s];
5535
4265
  if (!fn) warn(`[uidex] No implementation found for action "${s}"`);
5536
4266
  return fn;
5537
4267
  });
@@ -5539,13 +4269,13 @@ function createMachineRunner(machineArg, initialProps = {}) {
5539
4269
  };
5540
4270
  const guard = (str) => {
5541
4271
  if (isFunction(str)) return str(getParams());
5542
- return machine4.implementations?.guards?.[str](getParams());
4272
+ return machine3.implementations?.guards?.[str](getParams());
5543
4273
  };
5544
4274
  const effect = (keys) => {
5545
4275
  const strs = isFunction(keys) ? keys(getParams()) : keys;
5546
4276
  if (!strs) return;
5547
4277
  const fns = strs.map((s) => {
5548
- const fn = machine4.implementations?.effects?.[s];
4278
+ const fn = machine3.implementations?.effects?.[s];
5549
4279
  if (!fn) warn(`[uidex] No implementation found for effect "${s}"`);
5550
4280
  return fn;
5551
4281
  });
@@ -5566,10 +4296,10 @@ function createMachineRunner(machineArg, initialProps = {}) {
5566
4296
  });
5567
4297
  const computed = (key) => {
5568
4298
  ensure(
5569
- machine4.computed,
4299
+ machine3.computed,
5570
4300
  () => `[uidex] No computed object found on machine`
5571
4301
  );
5572
- const fn = machine4.computed[key];
4302
+ const fn = machine3.computed[key];
5573
4303
  return fn({
5574
4304
  context: ctx,
5575
4305
  event: getEvent(),
@@ -5602,7 +4332,7 @@ function createMachineRunner(machineArg, initialProps = {}) {
5602
4332
  queueMicrotask(() => fn());
5603
4333
  };
5604
4334
  let contextFields = {};
5605
- const ctxContextFn = machine4.context;
4335
+ const ctxContextFn = machine3.context;
5606
4336
  if (ctxContextFn) {
5607
4337
  contextFields = ctxContextFn({
5608
4338
  prop,
@@ -5638,7 +4368,7 @@ function createMachineRunner(machineArg, initialProps = {}) {
5638
4368
  return contextFields[key]?.hash(current) ?? "";
5639
4369
  }
5640
4370
  };
5641
- const refsInit = machine4.refs?.({ prop, context: ctx }) ?? {};
4371
+ const refsInit = machine3.refs?.({ prop, context: ctx }) ?? {};
5642
4372
  const refsStore = { ...refsInit };
5643
4373
  const refs = {
5644
4374
  get(key) {
@@ -5649,14 +4379,14 @@ function createMachineRunner(machineArg, initialProps = {}) {
5649
4379
  }
5650
4380
  };
5651
4381
  const initialState = resolveStateValue(
5652
- machine4,
5653
- machine4.initialState({ prop })
4382
+ machine3,
4383
+ machine3.initialState({ prop })
5654
4384
  );
5655
4385
  const state = createBindable(() => ({
5656
4386
  defaultValue: initialState,
5657
4387
  onChange(nextState, prevState) {
5658
4388
  const { exiting, entering } = getExitEnterStates(
5659
- machine4,
4389
+ machine3,
5660
4390
  prevState,
5661
4391
  nextState,
5662
4392
  transitionRef?.reenter
@@ -5675,8 +4405,8 @@ function createMachineRunner(machineArg, initialProps = {}) {
5675
4405
  if (cleanup) effectsMap.set(item.path, cleanup);
5676
4406
  });
5677
4407
  if (prevState === INIT_STATE) {
5678
- action(machine4.entry);
5679
- const cleanup = effect(machine4.effects);
4408
+ action(machine3.entry);
4409
+ const cleanup = effect(machine3.effects);
5680
4410
  if (cleanup) effectsMap.set(INIT_STATE, cleanup);
5681
4411
  }
5682
4412
  entering.forEach((item) => {
@@ -5695,7 +4425,7 @@ function createMachineRunner(machineArg, initialProps = {}) {
5695
4425
  currentEvent = event;
5696
4426
  const currentState = getCurrentState();
5697
4427
  const { transitions, source } = findTransition(
5698
- machine4,
4428
+ machine3,
5699
4429
  currentState,
5700
4430
  event.type
5701
4431
  );
@@ -5703,7 +4433,7 @@ function createMachineRunner(machineArg, initialProps = {}) {
5703
4433
  if (!transition) return;
5704
4434
  transitionRef = transition;
5705
4435
  const target = resolveStateValue(
5706
- machine4,
4436
+ machine3,
5707
4437
  transition.target ?? currentState,
5708
4438
  source
5709
4439
  );
@@ -5723,7 +4453,7 @@ function createMachineRunner(machineArg, initialProps = {}) {
5723
4453
  }
5724
4454
  });
5725
4455
  };
5726
- machine4.watch?.(getParams());
4456
+ machine3.watch?.(getParams());
5727
4457
  const service = {
5728
4458
  state: getState(),
5729
4459
  send,
@@ -5764,7 +4494,7 @@ function createMachineRunner(machineArg, initialProps = {}) {
5764
4494
  while (unmountFns.length) unmountFns.pop()?.();
5765
4495
  listeners.clear();
5766
4496
  queueMicrotask(() => {
5767
- action(machine4.exit);
4497
+ action(machine3.exit);
5768
4498
  });
5769
4499
  },
5770
4500
  subscribe(listener) {
@@ -5842,9 +4572,6 @@ function applyProps(node, props) {
5842
4572
  }
5843
4573
 
5844
4574
  // src/browser/views/builder/spread-props.ts
5845
- function spreadProps(node, props) {
5846
- return applyProps(node, props);
5847
- }
5848
4575
  function createPersistentSpreads() {
5849
4576
  const map = /* @__PURE__ */ new Map();
5850
4577
  return {
@@ -5975,10 +4702,10 @@ import {
5975
4702
  Highlighter as Highlighter2,
5976
4703
  Inbox,
5977
4704
  MessageCircleWarning,
5978
- StickyNote as StickyNote2,
4705
+ StickyNote,
5979
4706
  TicketPlus,
5980
4707
  View,
5981
- createElement as createLucideElement5
4708
+ createElement as createLucideElement4
5982
4709
  } from "lucide";
5983
4710
  var ICON_MAP = {
5984
4711
  "archive-x": ArchiveX,
@@ -5988,7 +4715,7 @@ var ICON_MAP = {
5988
4715
  "message-circle-warning": MessageCircleWarning,
5989
4716
  "chevron-down": ChevronDown,
5990
4717
  highlighter: Highlighter2,
5991
- "sticky-note": StickyNote2,
4718
+ "sticky-note": StickyNote,
5992
4719
  "ticket-plus": TicketPlus,
5993
4720
  view: View
5994
4721
  };
@@ -6029,7 +4756,7 @@ function renderActions(actions, ctx, root, heading) {
6029
4756
  let leading;
6030
4757
  const iconNode = iconFor(action.icon);
6031
4758
  if (iconNode) {
6032
- const svg2 = createLucideElement5(iconNode);
4759
+ const svg2 = createLucideElement4(iconNode);
6033
4760
  svg2.setAttribute("aria-hidden", "true");
6034
4761
  svg2.setAttribute("class", "h-4 w-4 shrink-0");
6035
4762
  const tile = el(
@@ -6768,858 +5495,84 @@ function renderDetailSurface(surface, ctx, root) {
6768
5495
  return mounted;
6769
5496
  }
6770
5497
 
6771
- // src/browser/views/render/form.ts
6772
- import { CircleCheck, CircleX, Loader2 } from "lucide";
6773
-
6774
- // src/browser/machines/dialog.ts
6775
- import * as dialog from "@zag-js/dialog";
6776
- function createDialog(props = {}) {
6777
- return createMachineHandle(
6778
- dialog.machine,
6779
- dialog.connect,
6780
- normalizeProps,
6781
- props
6782
- );
6783
- }
5498
+ // src/browser/views/render/list.ts
5499
+ import { Circle as Circle2 } from "lucide";
6784
5500
 
6785
- // src/browser/ui/screenshot-lightbox.ts
6786
- function createScreenshotLightbox(trigger, dataUrl, options) {
6787
- const cleanups = [];
6788
- const lightbox = createDialog({
6789
- id: "uidex-screenshot-lightbox",
6790
- modal: true,
6791
- closeOnInteractOutside: false,
6792
- closeOnEscape: false,
6793
- trapFocus: true,
6794
- preventScroll: true,
6795
- restoreFocus: true,
6796
- "aria-label": "Screenshot preview",
6797
- getRootNode: () => trigger.getRootNode()
6798
- });
6799
- cleanups.push(() => lightbox.destroy());
6800
- const backdropRef = createRef();
6801
- const positionerRef = createRef();
6802
- const contentRef = createRef();
6803
- const fullImgRef = createRef();
6804
- const mountTarget = (() => {
6805
- const rn = trigger.getRootNode();
6806
- return rn instanceof ShadowRoot ? rn : rn.body;
6807
- })();
6808
- const fragment = document.createDocumentFragment();
6809
- render(
6810
- html`
6811
- <div
6812
- ${ref(backdropRef)}
6813
- class="fixed inset-0 z-[2147483647] cursor-pointer bg-black/80"
6814
- data-uidex-lightbox
6815
- hidden
6816
- ></div>
6817
- <div
6818
- ${ref(positionerRef)}
6819
- class="fixed inset-0 z-[2147483647] flex cursor-pointer items-center justify-center p-6"
6820
- hidden
6821
- >
6822
- <div
6823
- ${ref(contentRef)}
6824
- class="flex items-center justify-center outline-none"
6825
- >
6826
- <img
6827
- ${ref(fullImgRef)}
6828
- class="max-h-full max-w-full rounded-lg"
6829
- src=${dataUrl}
6830
- alt="Screenshot"
6831
- />
6832
- </div>
6833
- </div>
6834
- `,
6835
- fragment
6836
- );
6837
- const backdropEl = backdropRef.value;
6838
- const positioner = positionerRef.value;
6839
- const content = contentRef.value;
6840
- const fullImg = fullImgRef.value;
6841
- mountTarget.append(fragment);
6842
- let spreadCleanups = [];
6843
- function applyLightboxProps() {
6844
- for (const c of spreadCleanups) c();
6845
- spreadCleanups = [];
6846
- const api = lightbox.api();
6847
- spreadCleanups.push(
6848
- spreadProps(
6849
- backdropEl,
6850
- api.getBackdropProps()
6851
- ),
6852
- spreadProps(
6853
- positioner,
6854
- api.getPositionerProps()
6855
- ),
6856
- spreadProps(content, api.getContentProps())
6857
- );
6858
- backdropEl.hidden = !api.open;
6859
- positioner.hidden = !api.open;
6860
- }
6861
- applyLightboxProps();
6862
- const unsubLightbox = lightbox.runner.subscribe(applyLightboxProps);
6863
- cleanups.push(() => {
6864
- unsubLightbox();
6865
- for (const c of spreadCleanups) c();
6866
- backdropEl.remove();
6867
- positioner.remove();
6868
- });
6869
- const closeLightbox = () => lightbox.api().setOpen(false);
6870
- if (options?.pushEscapeLayer) {
6871
- cleanups.push(
6872
- options.pushEscapeLayer(() => {
6873
- if (!lightbox.api().open) return false;
6874
- closeLightbox();
6875
- return true;
6876
- })
6877
- );
6878
- } else {
6879
- const onEscapeCapture = (e) => {
6880
- if (e.key !== "Escape") return;
6881
- if (!lightbox.api().open) return;
6882
- e.preventDefault();
6883
- e.stopPropagation();
6884
- e.stopImmediatePropagation();
6885
- closeLightbox();
6886
- };
6887
- window.addEventListener("keydown", onEscapeCapture, true);
6888
- cleanups.push(
6889
- () => window.removeEventListener("keydown", onEscapeCapture, true)
6890
- );
5501
+ // src/browser/views/render/list-controller.ts
5502
+ function createListController(opts) {
5503
+ let items = opts.items;
5504
+ let itemNodes = opts.itemNodes;
5505
+ let highlighted = null;
5506
+ let kbdMode = false;
5507
+ const subs = /* @__PURE__ */ new Set();
5508
+ const { contentEl, onSelect, onHighlightChange } = opts;
5509
+ contentEl.setAttribute("role", "listbox");
5510
+ contentEl.tabIndex = 0;
5511
+ contentEl.style.outline = "none";
5512
+ applyItemAria();
5513
+ if (opts.defaultHighlight && itemNodes.has(opts.defaultHighlight)) {
5514
+ setHighlight(opts.defaultHighlight, false);
6891
5515
  }
6892
- let suppressClickUntil = 0;
6893
- const onClickOutsideCapture = (e) => {
6894
- if (Date.now() < suppressClickUntil) {
6895
- e.preventDefault();
6896
- e.stopPropagation();
6897
- e.stopImmediatePropagation();
6898
- return;
6899
- }
6900
- if (!lightbox.api().open) return;
6901
- if (fullImg.contains(e.target)) return;
6902
- e.preventDefault();
6903
- e.stopPropagation();
6904
- e.stopImmediatePropagation();
6905
- closeLightbox();
6906
- suppressClickUntil = Date.now() + 100;
6907
- };
6908
- window.addEventListener("pointerdown", onClickOutsideCapture, true);
6909
- window.addEventListener("mousedown", onClickOutsideCapture, true);
6910
- window.addEventListener("click", onClickOutsideCapture, true);
6911
- cleanups.push(() => {
6912
- window.removeEventListener("pointerdown", onClickOutsideCapture, true);
6913
- window.removeEventListener("mousedown", onClickOutsideCapture, true);
6914
- window.removeEventListener("click", onClickOutsideCapture, true);
6915
- });
6916
- spreadProps(
6917
- trigger,
6918
- lightbox.api().getTriggerProps()
6919
- );
6920
- return {
6921
- destroy() {
6922
- for (const c of cleanups) c();
6923
- cleanups.length = 0;
6924
- }
6925
- };
6926
- }
6927
-
6928
- // src/browser/ui/button.ts
6929
- var buttonBase = "focus-visible:ring-ring focus-visible:ring-offset-background disabled:opacity-60 relative inline-flex shrink-0 cursor-pointer items-center justify-center gap-2 whitespace-nowrap rounded-lg border text-sm font-medium outline-none transition-shadow focus-visible:ring-2 focus-visible:ring-offset-1 disabled:pointer-events-none [&_svg:not([class*='size-'])]:size-4 [&_svg:not([class*='opacity-'])]:opacity-80 [&_svg]:pointer-events-none [&_svg]:shrink-0";
6930
- var buttonVariants = cva(buttonBase, {
6931
- defaultVariants: { size: "default", variant: "default" },
6932
- variants: {
6933
- size: {
6934
- default: "h-8 px-3",
6935
- sm: "h-7 gap-1.5 px-2.5",
6936
- xs: "h-6 gap-1 rounded-md px-2 text-xs",
6937
- lg: "h-9 px-3.5",
6938
- xl: "h-10 px-4 text-base",
6939
- icon: "size-8",
6940
- "icon-sm": "size-7",
6941
- "icon-lg": "size-9",
6942
- "icon-xs": "size-6 rounded-md"
6943
- },
6944
- variant: {
6945
- default: "border-primary bg-primary text-primary-foreground shadow-xs hover:bg-primary/90",
6946
- destructive: "border-destructive bg-destructive shadow-xs hover:bg-destructive/90 text-white",
6947
- "destructive-outline": "border-input bg-popover text-destructive-foreground shadow-xs/5 hover:border-destructive/30 hover:bg-destructive/5 dark:bg-input/30",
6948
- ghost: "text-foreground hover:bg-accent hover:text-accent-foreground border-transparent",
6949
- link: "text-foreground border-transparent underline-offset-4 hover:underline",
6950
- outline: "border-input bg-popover text-foreground shadow-xs/5 hover:bg-accent hover:text-accent-foreground dark:bg-input/30",
6951
- secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/90 border-transparent"
5516
+ function values() {
5517
+ return items.map((i) => i.value);
5518
+ }
5519
+ function notify() {
5520
+ for (const cb of subs) cb();
5521
+ }
5522
+ function applyItemAria() {
5523
+ for (const [value, el2] of itemNodes) {
5524
+ el2.setAttribute("role", "option");
5525
+ el2.id = `${opts.surfaceId}-item-${value}`;
6952
5526
  }
6953
5527
  }
6954
- });
6955
-
6956
- // src/browser/views/render/form.ts
6957
- var fieldSeq = 0;
6958
- var nextFieldId = () => `uidex-field-${++fieldSeq}`;
6959
- function issuePathRoot(issue) {
6960
- const seg = issue.path?.[0];
6961
- if (seg === void 0) return void 0;
6962
- if (typeof seg === "object" && seg !== null && "key" in seg) {
6963
- return String(seg.key);
6964
- }
6965
- return String(seg);
6966
- }
6967
- async function validateWithSchema(schema, values) {
6968
- const result = await schema["~standard"].validate(values);
6969
- if (!("issues" in result) || !result.issues) return null;
6970
- const out = {};
6971
- for (const issue of result.issues) {
6972
- const key = issuePathRoot(issue);
6973
- if (!key) continue;
6974
- if (out[key]) continue;
6975
- out[key] = issue.message;
6976
- }
6977
- return Object.keys(out).length > 0 ? out : null;
6978
- }
6979
- var FIELD_INPUT_CLASS = "border-input bg-popover text-foreground shadow-xs/5 placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/30 aria-invalid:border-destructive/40 aria-invalid:focus-visible:ring-destructive/20 dark:bg-input/30 inline-flex w-full rounded-lg border text-sm outline-none transition-shadow focus-visible:ring-[3px] disabled:pointer-events-none disabled:opacity-60";
6980
- var NATIVE_SELECT_CLASS = "border-input bg-popover text-foreground shadow-xs/5 focus-visible:border-ring focus-visible:ring-ring/30 aria-invalid:border-destructive/40 dark:bg-input/30 inline-flex h-8 w-full cursor-pointer appearance-none rounded-lg border bg-[right_0.5rem_center] bg-no-repeat pl-3 pr-8 text-sm outline-none transition-shadow focus-visible:ring-[3px] disabled:pointer-events-none disabled:opacity-60";
6981
- var FIELD_ROOT_CLASS = "flex flex-col items-start gap-2";
6982
- var FIELD_LABEL_CLASS = "text-base/4.5 text-foreground inline-flex items-center gap-2 font-medium sm:text-sm/4";
6983
- var FIELD_ERROR_CLASS = "text-destructive-foreground text-xs";
6984
- var CHECKBOX_CLASS = "border-input bg-popover size-4 cursor-pointer rounded-[0.25rem] border accent-primary";
6985
- function renderField(field, initial) {
6986
- const controlId = nextFieldId();
6987
- let control;
6988
- let read;
6989
- let reset;
6990
- switch (field.kind) {
6991
- case "select": {
6992
- const node = el("select", {
6993
- class: NATIVE_SELECT_CLASS,
6994
- attrs: {
6995
- "data-slot": "select",
6996
- name: field.name,
6997
- id: controlId,
6998
- required: field.required ?? false
6999
- }
7000
- });
7001
- for (const opt of field.options) {
7002
- node.append(
7003
- el("option", { attrs: { value: opt.value }, text: opt.label })
7004
- );
5528
+ function setHighlight(value, scroll = true) {
5529
+ if (value === highlighted) return;
5530
+ if (highlighted) {
5531
+ const prev = itemNodes.get(highlighted);
5532
+ if (prev) {
5533
+ prev.removeAttribute("data-highlighted");
5534
+ prev.removeAttribute("data-kbd-highlighted");
5535
+ prev.removeAttribute("aria-selected");
7005
5536
  }
7006
- const initialVal = typeof initial === "string" ? initial : typeof field.value === "string" ? field.value : field.options[0]?.value;
7007
- if (initialVal !== void 0) node.value = initialVal;
7008
- control = node;
7009
- read = () => node.value;
7010
- reset = () => {
7011
- if (initialVal !== void 0) node.value = initialVal;
7012
- };
7013
- break;
7014
- }
7015
- case "text":
7016
- case "email": {
7017
- const node = el("input", {
7018
- class: cn(FIELD_INPUT_CLASS, "h-8 px-3"),
7019
- attrs: {
7020
- "data-slot": "input",
7021
- type: field.kind === "email" ? "email" : "text",
7022
- name: field.name,
7023
- id: controlId,
7024
- placeholder: field.placeholder ?? "",
7025
- required: field.required ?? false
7026
- }
7027
- });
7028
- const initialVal = typeof initial === "string" ? initial : typeof field.value === "string" ? field.value : "";
7029
- node.value = initialVal;
7030
- control = node;
7031
- read = () => node.value;
7032
- reset = () => {
7033
- node.value = initialVal;
7034
- };
7035
- break;
7036
- }
7037
- case "textarea": {
7038
- const node = el("textarea", {
7039
- class: cn(FIELD_INPUT_CLASS, "min-h-20 px-3 py-2"),
7040
- attrs: {
7041
- "data-slot": "textarea",
7042
- name: field.name,
7043
- id: controlId,
7044
- placeholder: field.placeholder ?? "",
7045
- required: field.required ?? false,
7046
- rows: field.rows
7047
- }
7048
- });
7049
- const initialVal = typeof initial === "string" ? initial : typeof field.value === "string" ? field.value : "";
7050
- node.value = initialVal;
7051
- control = node;
7052
- read = () => node.value;
7053
- reset = () => {
7054
- node.value = initialVal;
7055
- };
7056
- break;
7057
- }
7058
- case "checkbox": {
7059
- const input = el("input", {
7060
- attrs: {
7061
- type: "checkbox",
7062
- name: field.name,
7063
- id: controlId
7064
- },
7065
- class: CHECKBOX_CLASS
7066
- });
7067
- const initialVal = typeof initial === "boolean" ? initial : typeof field.value === "boolean" ? field.value : false;
7068
- input.checked = initialVal;
7069
- control = input;
7070
- read = () => input.checked;
7071
- reset = () => {
7072
- input.checked = initialVal;
7073
- };
7074
- break;
7075
5537
  }
5538
+ highlighted = value;
5539
+ if (value) {
5540
+ const el2 = itemNodes.get(value);
5541
+ if (el2) {
5542
+ el2.setAttribute("data-highlighted", "");
5543
+ el2.setAttribute("aria-selected", "true");
5544
+ if (kbdMode) el2.setAttribute("data-kbd-highlighted", "");
5545
+ contentEl.setAttribute("aria-activedescendant", el2.id);
5546
+ if (scroll) el2.scrollIntoView({ block: "nearest" });
5547
+ }
5548
+ } else {
5549
+ contentEl.removeAttribute("aria-activedescendant");
5550
+ }
5551
+ onHighlightChange?.(value);
5552
+ notify();
7076
5553
  }
7077
- const errorNode = el("p", {
7078
- class: FIELD_ERROR_CLASS,
7079
- attrs: {
7080
- "data-slot": "field-error",
7081
- role: "alert",
7082
- "aria-live": "polite"
5554
+ function enterKbd() {
5555
+ if (kbdMode) return;
5556
+ kbdMode = true;
5557
+ contentEl.setAttribute("data-kbd-nav", "");
5558
+ }
5559
+ function exitKbd() {
5560
+ if (!kbdMode) return;
5561
+ kbdMode = false;
5562
+ contentEl.removeAttribute("data-kbd-nav");
5563
+ if (highlighted) {
5564
+ itemNodes.get(highlighted)?.removeAttribute("data-kbd-highlighted");
7083
5565
  }
7084
- });
7085
- errorNode.hidden = true;
7086
- const field$ = el("div", {
7087
- class: cn(
7088
- FIELD_ROOT_CLASS,
7089
- field.kind === "checkbox" ? "flex-row items-center gap-2" : ""
7090
- ),
7091
- attrs: {
7092
- "data-slot": "field",
7093
- "data-uidex-primitive": "field",
7094
- "data-uidex-field-name": field.name
7095
- }
7096
- });
7097
- const label = el("label", {
7098
- class: FIELD_LABEL_CLASS,
7099
- attrs: {
7100
- "data-slot": "field-label",
7101
- for: controlId
7102
- },
7103
- text: field.label
7104
- });
7105
- if (field.kind === "checkbox") {
7106
- field$.append(control, label);
7107
- } else {
7108
- field$.append(label, control);
7109
- }
7110
- field$.append(errorNode);
7111
- const setError = (message) => {
7112
- if (!message) {
7113
- errorNode.hidden = true;
7114
- errorNode.textContent = "";
7115
- control.removeAttribute("aria-invalid");
7116
- return;
7117
- }
7118
- errorNode.hidden = false;
7119
- errorNode.textContent = message;
7120
- control.setAttribute("aria-invalid", "true");
7121
- };
7122
- return {
7123
- name: field.name,
7124
- node: field$,
7125
- control,
7126
- errorNode,
7127
- read,
7128
- reset,
7129
- setError
7130
- };
7131
- }
7132
- var ICON_TILE_BASE = "bg-card text-foreground shadow-sm/5 not-dark:bg-clip-padding [&_svg:not([class*='size-'])]:size-4.5 flex size-9 shrink-0 items-center justify-center rounded-md border before:pointer-events-none before:absolute before:inset-0 before:rounded-[calc(var(--radius-md)-1px)] before:shadow-[0_1px_--theme(--color-black/4%)] dark:before:shadow-[0_-1px_--theme(--color-white/6%)]";
7133
- var ICON_TILE = ICON_TILE_BASE + " relative";
7134
- var ICON_TILE_GHOST = ICON_TILE_BASE + " pointer-events-none absolute bottom-px shadow-none scale-84";
7135
- var EMPTY_ROOT = "flex min-w-0 flex-1 flex-col items-center justify-center gap-6 text-balance px-6 py-12 text-center";
7136
- var SKELETON = "animate-skeleton rounded-sm [--skeleton-highlight:--alpha(var(--color-white)/64%)] [background:linear-gradient(120deg,transparent_40%,var(--skeleton-highlight),transparent_60%)_var(--color-muted)_0_0/200%_100%_fixed] dark:[--skeleton-highlight:--alpha(var(--color-white)/4%)]";
7137
- function iconMediaTpl(iconTpl) {
7138
- return html`
7139
- <div class="relative mb-6">
7140
- <div
7141
- class=${ICON_TILE_GHOST + " -rotate-10 origin-bottom-left -translate-x-0.5"}
7142
- aria-hidden="true"
7143
- ></div>
7144
- <div
7145
- class=${ICON_TILE_GHOST + " rotate-10 origin-bottom-right translate-x-0.5"}
7146
- aria-hidden="true"
7147
- ></div>
7148
- <div class=${ICON_TILE}>${iconTpl}</div>
7149
- </div>
7150
- `;
7151
- }
7152
- function loadingViewTpl(rootRef) {
7153
- return html`
7154
- <div class=${EMPTY_ROOT} aria-live="polite" hidden ${ref(rootRef)}>
7155
- ${iconMediaTpl(icon(Loader2, "animate-spin"))}
7156
- <div class="flex max-w-sm flex-col items-center text-center">
7157
- <div class=${SKELETON + " h-6 w-36 rounded-md"}></div>
7158
- </div>
7159
- <div
7160
- class="flex w-full min-w-0 max-w-sm flex-col items-center gap-4 text-balance text-sm"
7161
- >
7162
- <div class=${SKELETON + " h-7 w-20 rounded-lg"}></div>
7163
- </div>
7164
- </div>
7165
- `;
7166
- }
7167
- function successViewTpl(refs) {
7168
- return html`
7169
- <div class=${EMPTY_ROOT} hidden data-uidex-success-view ${ref(refs.root)}>
7170
- ${iconMediaTpl(icon(CircleCheck))}
7171
- <div class="flex max-w-sm flex-col items-center text-center">
7172
- <div
7173
- class="font-heading text-xl font-semibold"
7174
- data-uidex-success-title
7175
- ${ref(refs.title)}
7176
- ></div>
7177
- </div>
7178
- <div
7179
- class="flex w-full min-w-0 max-w-sm flex-col items-center gap-4 text-balance text-sm"
7180
- data-uidex-success-actions
7181
- ${ref(refs.actions)}
7182
- >
7183
- <a
7184
- class=${buttonVariants({ variant: "outline", size: "sm" })}
7185
- target="_blank"
7186
- rel="noreferrer"
7187
- data-uidex-success-link
7188
- ${ref(refs.link)}
7189
- ></a>
7190
- </div>
7191
- </div>
7192
- `;
7193
- }
7194
- function errorViewTpl(refs) {
7195
- return html`
7196
- <div class=${EMPTY_ROOT} hidden data-uidex-error-view ${ref(refs.root)}>
7197
- ${iconMediaTpl(icon(CircleX))}
7198
- <div class="flex max-w-sm flex-col items-center gap-1 text-center">
7199
- <div
7200
- class="font-heading text-xl font-semibold"
7201
- data-uidex-error-title
7202
- ${ref(refs.title)}
7203
- ></div>
7204
- <p
7205
- class="text-muted-foreground text-sm"
7206
- data-uidex-error-description
7207
- ${ref(refs.description)}
7208
- ></p>
7209
- </div>
7210
- <div
7211
- class="flex w-full min-w-0 max-w-sm flex-col items-center gap-4 text-balance text-sm"
7212
- >
7213
- <button
7214
- type="button"
7215
- class=${buttonVariants({ variant: "outline", size: "sm" })}
7216
- data-slot="button"
7217
- data-uidex-retry-button
7218
- ${ref(refs.retry)}
7219
- >
7220
- Try Again
7221
- </button>
7222
- </div>
7223
- </div>
7224
- `;
7225
- }
7226
- function renderFormSurface(surface, ctx, root) {
7227
- const cleanups = [];
7228
- const fields = surface.fields.map(
7229
- (field) => renderField(field, surface.initial?.[field.name])
7230
- );
7231
- const fieldByName = new Map(fields.map((f) => [f.name, f]));
7232
- const screenshotField = el("div", {
7233
- class: "flex flex-col gap-1.5",
7234
- attrs: { hidden: true }
7235
- });
7236
- const screenshotLabel = el("span", {
7237
- class: "text-muted-foreground text-xs font-medium",
7238
- text: "Screenshot"
7239
- });
7240
- const screenshotPreview = el("div", {
7241
- class: "cursor-pointer overflow-hidden rounded-md border"
7242
- });
7243
- screenshotField.append(screenshotLabel, screenshotPreview);
7244
- if (surface.screenshotPreview) {
7245
- surface.screenshotPreview.then((dataUrl) => {
7246
- if (!dataUrl) return;
7247
- const img = el("img", {
7248
- class: "max-h-32 w-full object-cover object-top",
7249
- attrs: { src: dataUrl, alt: "Screenshot preview" }
7250
- });
7251
- screenshotPreview.append(img);
7252
- screenshotField.hidden = false;
7253
- const handle = createScreenshotLightbox(screenshotPreview, dataUrl, {
7254
- pushEscapeLayer: ctx.pushEscapeLayer
7255
- });
7256
- cleanups.push(() => handle.destroy());
7257
- });
7258
- }
7259
- const formRef = createRef();
7260
- const loadingRef = createRef();
7261
- const successRef = createRef();
7262
- const successTitleRef = createRef();
7263
- const successLinkRef = createRef();
7264
- const successActionsRef = createRef();
7265
- const errorRef = createRef();
7266
- const errorTitleRef = createRef();
7267
- const errorDescriptionRef = createRef();
7268
- const retryRef = createRef();
7269
- render(
7270
- html`
7271
- <section
7272
- class="flex min-h-0 flex-1 flex-col p-4"
7273
- data-uidex-form-surface=${surface.id}
7274
- >
7275
- <form
7276
- ${ref(formRef)}
7277
- class="flex w-full flex-col gap-4"
7278
- data-slot="form"
7279
- data-uidex-primitive="form"
7280
- novalidate
7281
- data-uidex-form=${surface.id}
7282
- ></form>
7283
- ${loadingViewTpl(loadingRef)}
7284
- ${successViewTpl({
7285
- root: successRef,
7286
- title: successTitleRef,
7287
- link: successLinkRef,
7288
- actions: successActionsRef
7289
- })}
7290
- ${errorViewTpl({
7291
- root: errorRef,
7292
- title: errorTitleRef,
7293
- description: errorDescriptionRef,
7294
- retry: retryRef
7295
- })}
7296
- </section>
7297
- `,
7298
- root
7299
- );
7300
- const form = formRef.value;
7301
- if (surface.screenshotPreview) {
7302
- form.append(screenshotField);
7303
- }
7304
- for (const f of fields) {
7305
- form.append(f.node);
7306
- }
7307
- const submit = el("button", {
7308
- class: cn(buttonVariants({ variant: "default" }), "sr-only"),
7309
- attrs: {
7310
- type: "submit",
7311
- "data-slot": "button",
7312
- "data-uidex-form-submit": ""
7313
- },
7314
- text: surface.submit.label
7315
- });
7316
- form.append(submit);
7317
- const status = el("p", {
7318
- class: "text-muted-foreground text-xs",
7319
- attrs: {
7320
- "data-uidex-form-status": "",
7321
- "aria-live": "polite"
7322
- }
7323
- });
7324
- form.append(status);
7325
- const loadingView = loadingRef.value;
7326
- const successView = successRef.value;
7327
- const successTitle = successTitleRef.value;
7328
- const successLink = successLinkRef.value;
7329
- const successActions = successActionsRef.value;
7330
- const errorView = errorRef.value;
7331
- const errorTitle = errorTitleRef.value;
7332
- const errorDescription = errorDescriptionRef.value;
7333
- const retryButton = retryRef.value;
7334
- function clearAllFieldErrors() {
7335
- for (const f of fields) f.setError(null);
7336
- }
7337
- function applyFieldErrors(errs) {
7338
- clearAllFieldErrors();
7339
- if (!errs) return;
7340
- for (const [name, message] of Object.entries(errs)) {
7341
- fieldByName.get(name)?.setError(message);
7342
- }
7343
- }
7344
- function setStatus(result) {
7345
- status.replaceChildren();
7346
- status.classList.remove("text-destructive-foreground");
7347
- status.classList.add("text-muted-foreground");
7348
- if (!result) return;
7349
- if (result.status === "error") {
7350
- status.classList.remove("text-muted-foreground");
7351
- status.classList.add("text-destructive-foreground");
7352
- if (!result.fieldErrors) {
7353
- status.textContent = result.message;
7354
- }
7355
- return;
7356
- }
7357
- if (result.link) {
7358
- status.append(
7359
- document.createTextNode(`${result.message ?? "Submitted."} `),
7360
- el("a", {
7361
- class: "text-foreground underline underline-offset-4",
7362
- attrs: {
7363
- href: result.link.url,
7364
- target: "_blank",
7365
- rel: "noreferrer"
7366
- },
7367
- text: result.link.label ?? "Open link"
7368
- })
7369
- );
7370
- } else {
7371
- status.textContent = result.message ?? "Submitted.";
7372
- }
7373
- }
7374
- function showView(state) {
7375
- form.hidden = state !== "form";
7376
- loadingView.hidden = state !== "loading";
7377
- successView.hidden = state !== "success";
7378
- errorView.hidden = state !== "error";
7379
- }
7380
- function populateSuccess(result) {
7381
- if (!result || result.status !== "success") return;
7382
- successTitle.textContent = result.message ?? "Submitted";
7383
- if (result.link) {
7384
- successLink.setAttribute("href", result.link.url);
7385
- successLink.textContent = result.link.label ?? "Open link";
7386
- successActions.hidden = false;
7387
- } else {
7388
- successActions.hidden = true;
7389
- }
7390
- }
7391
- function populateError(result) {
7392
- if (!result || result.status !== "error") return;
7393
- errorTitle.textContent = "Something went wrong";
7394
- errorDescription.textContent = result.message;
7395
- }
7396
- let formState = "idle";
7397
- let lastResult = null;
7398
- let lastFieldErrors = null;
7399
- const subscribers = /* @__PURE__ */ new Set();
7400
- const notify = () => {
7401
- for (const cb of subscribers) cb();
7402
- };
7403
- async function doSubmit(values) {
7404
- if (formState === "submitting") return;
7405
- formState = "submitting";
7406
- setStatus(null);
7407
- clearAllFieldErrors();
7408
- showView("form");
7409
- lastResult = null;
7410
- lastFieldErrors = null;
7411
- if (surface.schema) {
7412
- const errors = await validateWithSchema(surface.schema, values);
7413
- if (errors) {
7414
- lastFieldErrors = errors;
7415
- lastResult = {
7416
- status: "error",
7417
- message: "Please fix the errors above.",
7418
- fieldErrors: errors
7419
- };
7420
- formState = "error";
7421
- applyFieldErrors(errors);
7422
- setStatus(lastResult);
7423
- showView("form");
7424
- notify();
7425
- return;
7426
- }
7427
- }
7428
- submit.disabled = true;
7429
- submit.setAttribute("data-loading", "");
7430
- showView("loading");
7431
- notify();
7432
- try {
7433
- const result = await surface.submit.onSubmit(
7434
- values
7435
- ) ?? { status: "success" };
7436
- submit.disabled = false;
7437
- submit.removeAttribute("data-loading");
7438
- if (result.status === "success") {
7439
- lastResult = result;
7440
- formState = "success";
7441
- populateSuccess(result);
7442
- showView("success");
7443
- clearAllFieldErrors();
7444
- if (result.resetFields) {
7445
- for (const name of result.resetFields) {
7446
- fieldByName.get(name)?.reset();
7447
- }
7448
- }
7449
- } else {
7450
- lastResult = result;
7451
- lastFieldErrors = result.fieldErrors ?? null;
7452
- formState = "error";
7453
- const hasFieldErrors = lastFieldErrors && Object.keys(lastFieldErrors).length > 0;
7454
- if (hasFieldErrors) {
7455
- applyFieldErrors(lastFieldErrors ?? void 0);
7456
- setStatus(result);
7457
- showView("form");
7458
- } else {
7459
- populateError(result);
7460
- showView("error");
7461
- }
7462
- }
7463
- } catch (err) {
7464
- submit.disabled = false;
7465
- submit.removeAttribute("data-loading");
7466
- const message = err instanceof Error ? err.message : String(err);
7467
- lastResult = { status: "error", message };
7468
- formState = "error";
7469
- populateError(lastResult);
7470
- showView("error");
7471
- }
7472
- notify();
7473
- }
7474
- function retryFromError() {
7475
- formState = "idle";
7476
- lastResult = null;
7477
- lastFieldErrors = null;
7478
- setStatus(null);
7479
- clearAllFieldErrors();
7480
- showView("form");
7481
- notify();
7482
- }
7483
- const onSubmit = (e) => {
7484
- e.preventDefault();
7485
- if (formState === "success") return;
7486
- if (formState === "error") retryFromError();
7487
- const values = {};
7488
- surface.fields.forEach((field, i) => {
7489
- values[field.name] = fields[i].read();
7490
- });
7491
- void doSubmit(values);
7492
- };
7493
- form.addEventListener("submit", onSubmit);
7494
- cleanups.push(() => form.removeEventListener("submit", onSubmit));
7495
- const triggerSubmit = () => {
7496
- if (typeof form.requestSubmit === "function") form.requestSubmit();
7497
- else form.dispatchEvent(new Event("submit", { cancelable: true }));
7498
- };
7499
- const onFormKeyDown = (e) => {
7500
- if (e.key !== "Enter") return;
7501
- const isMod = e.metaKey || e.ctrlKey;
7502
- if (isMod) {
7503
- e.preventDefault();
7504
- if (formState === "success") {
7505
- ctx.close();
7506
- return;
7507
- }
7508
- if (formState !== "idle" && formState !== "error") return;
7509
- triggerSubmit();
7510
- return;
7511
- }
7512
- if (e.target instanceof HTMLInputElement && e.target.type !== "checkbox" && e.target.type !== "radio") {
7513
- e.preventDefault();
7514
- }
7515
- };
7516
- form.addEventListener("keydown", onFormKeyDown);
7517
- cleanups.push(() => form.removeEventListener("keydown", onFormKeyDown));
7518
- retryButton.addEventListener("click", retryFromError);
7519
- cleanups.push(() => retryButton.removeEventListener("click", retryFromError));
7520
- const resolveIntent = () => {
7521
- if (formState === "submitting") {
7522
- return { label: "Submitting\u2026", disabled: true, perform: () => {
7523
- } };
7524
- }
7525
- if (formState === "success") {
7526
- return { label: "Close", perform: () => ctx.close() };
7527
- }
7528
- if (formState === "error" && !lastFieldErrors) {
7529
- return { label: "Try Again", perform: retryFromError };
7530
- }
7531
- return { label: surface.submit.label, perform: triggerSubmit };
7532
- };
7533
- return {
7534
- cleanup: composeCleanups([...cleanups, () => root.replaceChildren()]),
7535
- submitIntent: {
7536
- get: resolveIntent,
7537
- subscribe: (cb) => {
7538
- subscribers.add(cb);
7539
- return () => subscribers.delete(cb);
7540
- }
7541
- }
7542
- };
7543
- }
7544
-
7545
- // src/browser/views/render/list.ts
7546
- import { Circle as Circle2 } from "lucide";
7547
-
7548
- // src/browser/views/render/list-controller.ts
7549
- function createListController(opts) {
7550
- let items = opts.items;
7551
- let itemNodes = opts.itemNodes;
7552
- let highlighted = null;
7553
- let kbdMode = false;
7554
- const subs = /* @__PURE__ */ new Set();
7555
- const { contentEl, onSelect, onHighlightChange } = opts;
7556
- contentEl.setAttribute("role", "listbox");
7557
- contentEl.tabIndex = 0;
7558
- contentEl.style.outline = "none";
7559
- applyItemAria();
7560
- if (opts.defaultHighlight && itemNodes.has(opts.defaultHighlight)) {
7561
- setHighlight(opts.defaultHighlight, false);
7562
- }
7563
- function values() {
7564
- return items.map((i) => i.value);
7565
- }
7566
- function notify() {
7567
- for (const cb of subs) cb();
7568
- }
7569
- function applyItemAria() {
7570
- for (const [value, el2] of itemNodes) {
7571
- el2.setAttribute("role", "option");
7572
- el2.id = `${opts.surfaceId}-item-${value}`;
7573
- }
7574
- }
7575
- function setHighlight(value, scroll = true) {
7576
- if (value === highlighted) return;
7577
- if (highlighted) {
7578
- const prev = itemNodes.get(highlighted);
7579
- if (prev) {
7580
- prev.removeAttribute("data-highlighted");
7581
- prev.removeAttribute("data-kbd-highlighted");
7582
- prev.removeAttribute("aria-selected");
7583
- }
7584
- }
7585
- highlighted = value;
7586
- if (value) {
7587
- const el2 = itemNodes.get(value);
7588
- if (el2) {
7589
- el2.setAttribute("data-highlighted", "");
7590
- el2.setAttribute("aria-selected", "true");
7591
- if (kbdMode) el2.setAttribute("data-kbd-highlighted", "");
7592
- contentEl.setAttribute("aria-activedescendant", el2.id);
7593
- if (scroll) el2.scrollIntoView({ block: "nearest" });
7594
- }
7595
- } else {
7596
- contentEl.removeAttribute("aria-activedescendant");
7597
- }
7598
- onHighlightChange?.(value);
7599
- notify();
7600
- }
7601
- function enterKbd() {
7602
- if (kbdMode) return;
7603
- kbdMode = true;
7604
- contentEl.setAttribute("data-kbd-nav", "");
7605
- }
7606
- function exitKbd() {
7607
- if (!kbdMode) return;
7608
- kbdMode = false;
7609
- contentEl.removeAttribute("data-kbd-nav");
7610
- if (highlighted) {
7611
- itemNodes.get(highlighted)?.removeAttribute("data-kbd-highlighted");
7612
- }
7613
- }
7614
- function move(delta) {
7615
- const vals = values();
7616
- if (vals.length === 0) return;
7617
- enterKbd();
7618
- if (highlighted === null) {
7619
- setHighlight(delta > 0 ? vals[0] : vals[vals.length - 1]);
7620
- if (highlighted)
7621
- itemNodes.get(highlighted)?.setAttribute("data-kbd-highlighted", "");
7622
- return;
5566
+ }
5567
+ function move(delta) {
5568
+ const vals = values();
5569
+ if (vals.length === 0) return;
5570
+ enterKbd();
5571
+ if (highlighted === null) {
5572
+ setHighlight(delta > 0 ? vals[0] : vals[vals.length - 1]);
5573
+ if (highlighted)
5574
+ itemNodes.get(highlighted)?.setAttribute("data-kbd-highlighted", "");
5575
+ return;
7623
5576
  }
7624
5577
  const idx = vals.indexOf(highlighted);
7625
5578
  const next = (idx + delta + vals.length) % vals.length;
@@ -7639,7 +5592,7 @@ function createListController(opts) {
7639
5592
  e.preventDefault();
7640
5593
  move(-1);
7641
5594
  break;
7642
- case "Home":
5595
+ case "Home": {
7643
5596
  e.preventDefault();
7644
5597
  enterKbd();
7645
5598
  const first = values()[0];
@@ -7649,7 +5602,8 @@ function createListController(opts) {
7649
5602
  itemNodes.get(highlighted)?.setAttribute("data-kbd-highlighted", "");
7650
5603
  }
7651
5604
  break;
7652
- case "End":
5605
+ }
5606
+ case "End": {
7653
5607
  e.preventDefault();
7654
5608
  enterKbd();
7655
5609
  const vals = values();
@@ -7660,6 +5614,7 @@ function createListController(opts) {
7660
5614
  itemNodes.get(highlighted)?.setAttribute("data-kbd-highlighted", "");
7661
5615
  }
7662
5616
  break;
5617
+ }
7663
5618
  case "Enter":
7664
5619
  if (highlighted) {
7665
5620
  e.preventDefault();
@@ -7989,8 +5944,6 @@ function renderSurface(surface, ctx, root) {
7989
5944
  return renderListSurface(surface, ctx, root);
7990
5945
  case "detail":
7991
5946
  return renderDetailSurface(surface, ctx, root);
7992
- case "form":
7993
- return renderFormSurface(surface, ctx, root);
7994
5947
  }
7995
5948
  }
7996
5949
 
@@ -8049,8 +6002,6 @@ function mountEntry(entry, view, deps) {
8049
6002
  const ctx = {
8050
6003
  ref: entry.ref,
8051
6004
  registry: deps.registry,
8052
- cloud: deps.cloud,
8053
- user: deps.session.getState().user,
8054
6005
  views: deps.views,
8055
6006
  push: (target) => {
8056
6007
  if (!deps.views.get(target.id)) return;
@@ -8064,10 +6015,7 @@ function mountEntry(entry, view, deps) {
8064
6015
  pinHighlight: (r) => deps.session.highlight.pin(r),
8065
6016
  searchInput: deps.searchInput,
8066
6017
  highlight: deps.highlight,
8067
- getStack: () => deps.session.getState().stack,
8068
- pushEscapeLayer: deps.pushEscapeLayer,
8069
- onAfterSubmit: deps.onAfterSubmit,
8070
- getRoute: deps.getRoute
6018
+ getStack: () => deps.session.getState().stack
8071
6019
  };
8072
6020
  let surfaceResult;
8073
6021
  try {
@@ -8590,9 +6538,7 @@ function resolveProp(view, ctx, value, propName, fallback) {
8590
6538
  }
8591
6539
  function createViewStack(options) {
8592
6540
  const { container, views, session, registry, highlight } = options;
8593
- const cloud = options.cloud ?? null;
8594
6541
  const dev = options.dev ?? detectDev();
8595
- const onAfterSubmit = options.onAfterSubmit;
8596
6542
  const mounted = [];
8597
6543
  let shell = null;
8598
6544
  let warnedForDepth = 0;
@@ -8789,13 +6735,8 @@ function createViewStack(options) {
8789
6735
  views,
8790
6736
  session,
8791
6737
  registry,
8792
- cloud,
8793
6738
  highlight,
8794
- nextScrollSeq: () => ++scrollAreaSeq,
8795
- pushEscapeLayer: options.pushEscapeLayer ?? (() => () => {
8796
- }),
8797
- onAfterSubmit,
8798
- getRoute: options.getRoute
6739
+ nextScrollSeq: () => ++scrollAreaSeq
8799
6740
  });
8800
6741
  if (record) mounted.push(record);
8801
6742
  }
@@ -8850,20 +6791,13 @@ function createViewStack(options) {
8850
6791
 
8851
6792
  // src/browser/views/built-in/ids.ts
8852
6793
  var BUILT_IN_VIEW_IDS = {
8853
- closeReason: "close-reason",
8854
6794
  commandPalette: "command-palette",
8855
6795
  elements: "elements",
8856
- entityReports: "entity-reports",
8857
6796
  explorePage: "explore-page",
8858
6797
  features: "features",
8859
- report: "report",
8860
6798
  flows: "flows",
8861
6799
  glossary: "glossary",
8862
- jiraReport: "jira-report",
8863
6800
  pages: "pages",
8864
- pageReports: "page-reports",
8865
- reportDetail: "report-detail",
8866
- pinSettings: "pin-settings",
8867
6801
  primitives: "primitives",
8868
6802
  regions: "regions",
8869
6803
  widgets: "widgets"
@@ -8878,16 +6812,6 @@ var LIST_VIEW_FOR_KIND = {
8878
6812
  flow: BUILT_IN_VIEW_IDS.flows,
8879
6813
  route: BUILT_IN_VIEW_IDS.pages
8880
6814
  };
8881
- var DETAIL_VIEW_FOR_KIND = {
8882
- element: "component-detail",
8883
- feature: "feature-detail",
8884
- page: "page-detail",
8885
- widget: "widget-detail",
8886
- region: "region-detail",
8887
- primitive: "primitive-detail",
8888
- flow: "flow-detail",
8889
- route: "page-detail"
8890
- };
8891
6815
  var COMMAND_PALETTE_ENTRY2 = {
8892
6816
  id: BUILT_IN_VIEW_IDS.commandPalette,
8893
6817
  ref: null
@@ -8896,120 +6820,15 @@ function parentList(ref2) {
8896
6820
  if (!ref2) return COMMAND_PALETTE_ENTRY2;
8897
6821
  return { id: LIST_VIEW_FOR_KIND[ref2.kind], ref: null };
8898
6822
  }
8899
- function parentDetail(ref2) {
8900
- if (!ref2) return COMMAND_PALETTE_ENTRY2;
8901
- return { id: DETAIL_VIEW_FOR_KIND[ref2.kind], ref: ref2 };
8902
- }
8903
-
8904
- // src/browser/views/built-in/close-reason.ts
8905
- import {
8906
- Ban,
8907
- BugOff,
8908
- CircleCheck as CircleCheck2,
8909
- Copy as Copy2,
8910
- LoaderCircle,
8911
- createElement as createLucideElement6
8912
- } from "lucide";
8913
- var pendingReportId = null;
8914
- var afterClose = null;
8915
- function setCloseTarget(reportId, onDone) {
8916
- pendingReportId = reportId;
8917
- afterClose = onDone;
8918
- }
8919
- function leadingIcon(iconNode) {
8920
- return () => {
8921
- const svg2 = createLucideElement6(iconNode);
8922
- svg2.setAttribute("aria-hidden", "true");
8923
- return createIconTile(svg2);
8924
- };
8925
- }
8926
- function spinnerTile() {
8927
- const spinner = createLucideElement6(LoaderCircle);
8928
- spinner.setAttribute("class", "animate-spin");
8929
- return createIconTile(spinner);
8930
- }
8931
- var REASONS = [
8932
- { value: "fixed", label: "Resolved", icon: CircleCheck2 },
8933
- { value: "not_a_bug", label: "Not a bug", icon: BugOff },
8934
- { value: "duplicate", label: "Duplicate", icon: Copy2 },
8935
- { value: "wont_fix", label: "Won't fix", icon: Ban }
8936
- ];
8937
- var closeReasonView = {
8938
- id: BUILT_IN_VIEW_IDS.closeReason,
8939
- matches: () => false,
8940
- parent: (ref2) => ref2 ? { id: BUILT_IN_VIEW_IDS.reportDetail, ref: ref2 } : null,
8941
- title: "Close reason",
8942
- searchable: false,
8943
- focusTarget: (host) => host.querySelector("[data-uidex-list-content]"),
8944
- surface: () => ({ kind: "list", id: "unused", items: [] }),
8945
- render(ctx, root) {
8946
- let busy = false;
8947
- const items = REASONS.map((r) => ({
8948
- value: r.value,
8949
- label: r.label,
8950
- leading: leadingIcon(r.icon)
8951
- }));
8952
- const surface = {
8953
- kind: "list",
8954
- id: "uidex-close-reason",
8955
- searchable: false,
8956
- items,
8957
- emptyLabel: "No reasons available",
8958
- onSelect: async (item) => {
8959
- if (busy || !pendingReportId || !ctx.registry.closeReport) return;
8960
- busy = true;
8961
- const row = root.querySelector(
8962
- `[data-uidex-item-value="${item.value}"]`
8963
- );
8964
- const existingTile = row?.querySelector("[data-slot='icon-tile']");
8965
- if (row && existingTile) {
8966
- existingTile.replaceWith(spinnerTile());
8967
- row.style.opacity = "0.6";
8968
- row.style.pointerEvents = "none";
8969
- }
8970
- try {
8971
- await ctx.registry.closeReport(pendingReportId, item.value);
8972
- const done = afterClose;
8973
- pendingReportId = null;
8974
- afterClose = null;
8975
- done?.();
8976
- } catch {
8977
- busy = false;
8978
- if (row) {
8979
- row.style.opacity = "";
8980
- row.style.pointerEvents = "";
8981
- const reason = REASONS.find((r) => r.value === item.value);
8982
- if (reason) {
8983
- const tile = row.querySelector("[data-slot='icon-tile']");
8984
- if (tile)
8985
- tile.replaceWith(
8986
- createIconTile(createLucideElement6(reason.icon))
8987
- );
8988
- }
8989
- }
8990
- const error = document.createElement("p");
8991
- error.className = "text-destructive px-4 py-2 text-xs";
8992
- error.textContent = "Close failed \u2014 try again";
8993
- root.querySelector("[data-uidex-list-content]")?.prepend(error);
8994
- setTimeout(() => error.remove(), 3e3);
8995
- }
8996
- }
8997
- };
8998
- const mounted = renderListSurface(surface, ctx, root);
8999
- return mounted.cleanup;
9000
- }
9001
- };
9002
6823
 
9003
6824
  // src/browser/views/built-in/command-palette.ts
9004
6825
  import {
9005
6826
  Compass,
9006
- Copy as Copy3,
6827
+ Copy as Copy2,
9007
6828
  ExternalLink,
9008
- MessageCircleWarning as MessageCircleWarning2,
9009
6829
  Star,
9010
6830
  StarOff,
9011
- TicketPlus as TicketPlus2,
9012
- createElement as createLucideElement7
6831
+ createElement as createLucideElement5
9013
6832
  } from "lucide";
9014
6833
 
9015
6834
  // src/browser/views/builder/format-location.ts
@@ -9049,9 +6868,6 @@ function findCurrentRoute(registry) {
9049
6868
  function findCurrentPageId(ctx) {
9050
6869
  return findCurrentRoute(ctx.registry)?.page ?? null;
9051
6870
  }
9052
- function findCurrentRoutePath(registry) {
9053
- return findCurrentRoute(registry)?.path ?? null;
9054
- }
9055
6871
  function buildPageRouteMap(ctx) {
9056
6872
  const map = /* @__PURE__ */ new Map();
9057
6873
  for (const route of ctx.registry.list("route")) {
@@ -9102,7 +6918,7 @@ function openAction(onSelect) {
9102
6918
  return {
9103
6919
  id: "open",
9104
6920
  label: "Open",
9105
- icon: () => createLucideElement7(ExternalLink),
6921
+ icon: () => createLucideElement5(ExternalLink),
9106
6922
  perform: onSelect
9107
6923
  };
9108
6924
  }
@@ -9112,7 +6928,7 @@ function favoriteAction(ref2, ctx) {
9112
6928
  id: "toggle-favorite",
9113
6929
  label: isFav ? "Remove from Favorites" : "Add to Favorites",
9114
6930
  shortcut: "\u21E7\u2318F",
9115
- icon: () => createLucideElement7(isFav ? StarOff : Star),
6931
+ icon: () => createLucideElement5(isFav ? StarOff : Star),
9116
6932
  perform: () => {
9117
6933
  ctx.views.toggleFavorite(ref2);
9118
6934
  ctx.close();
@@ -9128,7 +6944,7 @@ function entityActions(ref2, entity, ctx, onSelect) {
9128
6944
  actions.push({
9129
6945
  id: "copy-path",
9130
6946
  label: "Copy Source Path",
9131
- icon: () => createLucideElement7(Copy3),
6947
+ icon: () => createLucideElement5(Copy2),
9132
6948
  async perform() {
9133
6949
  try {
9134
6950
  await navigator.clipboard.writeText(path);
@@ -9138,20 +6954,6 @@ function entityActions(ref2, entity, ctx, onSelect) {
9138
6954
  });
9139
6955
  }
9140
6956
  }
9141
- actions.push({
9142
- id: "submit-report",
9143
- label: "Report",
9144
- icon: () => createLucideElement7(MessageCircleWarning2),
9145
- perform: () => ctx.push({ id: BUILT_IN_VIEW_IDS.report, ref: ref2 })
9146
- });
9147
- if (ctx.cloud?.integrations.getCachedConfig()?.hasJira) {
9148
- actions.push({
9149
- id: "create-jira-issue",
9150
- label: "Create Jira Ticket",
9151
- icon: () => createLucideElement7(TicketPlus2),
9152
- perform: () => ctx.push({ id: BUILT_IN_VIEW_IDS.jiraReport, ref: ref2 })
9153
- });
9154
- }
9155
6957
  actions.push(favoriteAction(ref2, ctx));
9156
6958
  return actions;
9157
6959
  }
@@ -9184,7 +6986,7 @@ function explorePageRow(totalOnPage, ctx) {
9184
6986
  subtitle: totalOnPage === 1 ? "1 item" : `${totalOnPage} items`,
9185
6987
  group: CURRENT_PAGE_GROUP,
9186
6988
  tag: BUILT_IN_VIEW_IDS.explorePage,
9187
- leading: () => createLucideElement7(Compass),
6989
+ leading: () => createLucideElement5(Compass),
9188
6990
  actions: viewActions(onSelect),
9189
6991
  payload: { type: "view", id: BUILT_IN_VIEW_IDS.explorePage }
9190
6992
  };
@@ -9249,7 +7051,7 @@ function createCommandPaletteView(shortcut) {
9249
7051
  group: PALETTE_GROUPS.favorites,
9250
7052
  preview: ref2,
9251
7053
  entityChip: { entity },
9252
- leading: () => createLucideElement7(style.icon),
7054
+ leading: () => createLucideElement5(style.icon),
9253
7055
  actions: entityActions(ref2, entity, ctx, onSelect),
9254
7056
  payload: { type: "entity", ref: ref2 }
9255
7057
  });
@@ -9274,7 +7076,7 @@ function createCommandPaletteView(shortcut) {
9274
7076
  group: PALETTE_GROUPS.recents,
9275
7077
  preview: ref2,
9276
7078
  entityChip: { entity },
9277
- leading: () => createLucideElement7(style.icon),
7079
+ leading: () => createLucideElement5(style.icon),
9278
7080
  actions: entityActions(ref2, entity, ctx, onSelect),
9279
7081
  payload: { type: "entity", ref: ref2 }
9280
7082
  });
@@ -9356,14 +7158,14 @@ async function captureScreenshot(options = {}) {
9356
7158
  }
9357
7159
 
9358
7160
  // src/browser/report/capture.ts
9359
- function captureReportContext(opts) {
7161
+ function captureReportContext() {
9360
7162
  const nav = typeof navigator !== "undefined" ? navigator : void 0;
9361
7163
  const loc = typeof location !== "undefined" ? location : void 0;
9362
7164
  const win = typeof window !== "undefined" ? window : void 0;
9363
7165
  const doc = typeof document !== "undefined" ? document : void 0;
9364
7166
  return {
9365
7167
  url: loc?.href ?? "",
9366
- route: opts?.getRoute?.() ?? loc?.pathname,
7168
+ route: loc?.pathname,
9367
7169
  userAgent: nav?.userAgent ?? "",
9368
7170
  pageTitle: doc?.title,
9369
7171
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
@@ -9415,46 +7217,6 @@ function copyPathAction(ref2, loc) {
9415
7217
  intent: { kind: "external", describe: "clipboard" }
9416
7218
  };
9417
7219
  }
9418
- function reportAction(ref2) {
9419
- return {
9420
- id: "submit-report",
9421
- label: "Report",
9422
- icon: "message-circle-warning",
9423
- push: { id: BUILT_IN_VIEW_IDS.report, ref: ref2 },
9424
- intent: {
9425
- kind: "push",
9426
- viewId: BUILT_IN_VIEW_IDS.report,
9427
- refKind: ref2.kind
9428
- }
9429
- };
9430
- }
9431
- function viewReportsAction(ref2, count) {
9432
- return {
9433
- id: "view-reports",
9434
- label: "View Reports",
9435
- icon: "inbox",
9436
- hint: count != null ? count === 1 ? "1 item" : `${count} items` : void 0,
9437
- push: { id: BUILT_IN_VIEW_IDS.entityReports, ref: ref2 },
9438
- intent: {
9439
- kind: "push",
9440
- viewId: BUILT_IN_VIEW_IDS.entityReports,
9441
- refKind: ref2.kind
9442
- }
9443
- };
9444
- }
9445
- function jiraAction(ref2) {
9446
- return {
9447
- id: "create-jira-issue",
9448
- label: "Create Jira Ticket",
9449
- icon: "ticket-plus",
9450
- push: { id: BUILT_IN_VIEW_IDS.jiraReport, ref: ref2 },
9451
- intent: {
9452
- kind: "push",
9453
- viewId: BUILT_IN_VIEW_IDS.jiraReport,
9454
- refKind: ref2.kind
9455
- }
9456
- };
9457
- }
9458
7220
  function buildSnapshotMarkdown(ref2, loc) {
9459
7221
  const snapshot = captureReportContext();
9460
7222
  const sourcePath = formatLocation(loc);
@@ -9545,18 +7307,6 @@ function createEntityDetailView(config) {
9545
7307
  const metaEntity = entity ? entity : null;
9546
7308
  const meta = metaEntity?.meta;
9547
7309
  const actions = [];
9548
- const cloud = ctx.cloud;
9549
- actions.push({ ...reportAction(ctx.ref), group: "Report" });
9550
- const reportCount = ctx.registry.getReports(kind, ctx.ref.id).length;
9551
- if (reportCount > 0) {
9552
- actions.push({
9553
- ...viewReportsAction(ctx.ref, reportCount),
9554
- group: "Report"
9555
- });
9556
- }
9557
- if (cloud?.integrations.getCachedConfig()?.hasJira) {
9558
- actions.push({ ...jiraAction(ctx.ref), group: "Report" });
9559
- }
9560
7310
  if (DOM_BACKED_KINDS.has(kind) && resolveEntityElement(ctx.ref)) {
9561
7311
  actions.push({ ...highlightElementAction(ctx.ref), group: "Inspect" });
9562
7312
  actions.push({ ...copyScreenshotAction(ctx.ref), group: "Inspect" });
@@ -9742,157 +7492,8 @@ var primitivesView = createEntityKindListView(
9742
7492
  BUILT_IN_VIEW_IDS.primitives
9743
7493
  );
9744
7494
 
9745
- // src/browser/views/built-in/report-detail.ts
9746
- var selectedId = null;
9747
- function setSelectedReportId(id) {
9748
- selectedId = id;
9749
- }
9750
- function findReport(ctx) {
9751
- if (!ctx.ref || !selectedId) return null;
9752
- const reports = ctx.registry.getReports(ctx.ref.kind, ctx.ref.id);
9753
- return reports.find((r) => r.id === selectedId) ?? null;
9754
- }
9755
- var reportDetailView = {
9756
- id: BUILT_IN_VIEW_IDS.reportDetail,
9757
- matches: () => false,
9758
- parent: (ref2) => ({ id: BUILT_IN_VIEW_IDS.entityReports, ref: ref2 }),
9759
- searchable: false,
9760
- focusTarget: (host) => host.querySelector(
9761
- "[data-uidex-detail-actions] [data-uidex-detail-action]"
9762
- ),
9763
- surface: (ctx) => {
9764
- const report = findReport(ctx);
9765
- if (!report) {
9766
- return {
9767
- kind: "detail",
9768
- entityKind: ctx.ref?.kind ?? "element",
9769
- notFound: ctx.ref ?? void 0
9770
- };
9771
- }
9772
- const typeLabel = TYPE_LABELS[report.type] ?? report.type;
9773
- const sevLabel = SEVERITY_LABELS[report.severity] ?? report.severity;
9774
- const sections = [];
9775
- if (report.body) {
9776
- sections.push({ id: "description", text: report.body });
9777
- }
9778
- if (report.screenshot) {
9779
- sections.push({ id: "screenshot", url: report.screenshot });
9780
- } else {
9781
- const pins = ctx.cloud?.pins;
9782
- const fetchScreenshot = pins?.screenshot;
9783
- if (pins && fetchScreenshot) {
9784
- sections.push({
9785
- id: "screenshot",
9786
- load: () => fetchScreenshot.call(pins, report.id)
9787
- });
9788
- }
9789
- }
9790
- const metaEntries = [];
9791
- if (report.url) metaEntries.push({ label: "URL", value: report.url });
9792
- if (report.route) metaEntries.push({ label: "Route", value: report.route });
9793
- if (report.pageTitle)
9794
- metaEntries.push({ label: "Page", value: report.pageTitle });
9795
- if (metaEntries.length > 0) {
9796
- sections.push({ id: "metadata", entries: metaEntries });
9797
- }
9798
- const actions = [];
9799
- if (ctx.registry.closeReport) {
9800
- actions.push({
9801
- id: "close",
9802
- label: "Close",
9803
- icon: "archive-x",
9804
- run: () => {
9805
- setCloseTarget(report.id, () => ctx.pop());
9806
- ctx.push({ id: BUILT_IN_VIEW_IDS.closeReason });
9807
- }
9808
- });
9809
- }
9810
- if (report.url) {
9811
- actions.push({
9812
- id: "open-url",
9813
- label: "Open URL",
9814
- icon: "copy",
9815
- copy: report.url
9816
- });
9817
- }
9818
- return {
9819
- kind: "detail",
9820
- entityKind: ctx.ref?.kind ?? "element",
9821
- title: report.title || "(no title)",
9822
- subtitle: {
9823
- rawId: [
9824
- typeLabel,
9825
- sevLabel,
9826
- authorLabel(report),
9827
- relativeTime(report.createdAt)
9828
- ].filter(Boolean).join(" \xB7 ")
9829
- },
9830
- actions,
9831
- sections
9832
- };
9833
- }
9834
- };
9835
-
9836
- // src/browser/views/built-in/entity-reports.ts
9837
- function reportToItem(report, ctx) {
9838
- const typeLabel = TYPE_LABELS[report.type] ?? report.type;
9839
- const sevLabel = SEVERITY_LABELS[report.severity] ?? report.severity;
9840
- const raw = report.title || report.body;
9841
- const label = raw.length > 80 ? raw.slice(0, 80) + "\u2026" : raw;
9842
- const kind = ctx.ref?.kind ?? "element";
9843
- const actions = [];
9844
- if (ctx.registry.closeReport) {
9845
- actions.push({
9846
- id: `close-${report.id}`,
9847
- label: "Close",
9848
- perform: () => {
9849
- setCloseTarget(report.id, () => ctx.pop());
9850
- ctx.push({ id: BUILT_IN_VIEW_IDS.closeReason });
9851
- }
9852
- });
9853
- }
9854
- return {
9855
- value: `report:${report.id}`,
9856
- label: label || "(no description)",
9857
- subtitle: [
9858
- authorLabel(report),
9859
- typeLabel,
9860
- sevLabel,
9861
- relativeTime(report.createdAt)
9862
- ].filter(Boolean).join(" \xB7 "),
9863
- tag: `report:${report.id}`,
9864
- leading: () => renderKindIcon(kind),
9865
- actions
9866
- };
9867
- }
9868
- var entityReportsView = {
9869
- id: BUILT_IN_VIEW_IDS.entityReports,
9870
- matches: () => false,
9871
- parent: parentDetail,
9872
- title: "Reports",
9873
- searchable: true,
9874
- hints: [{ key: "\u21B5", label: "Select" }],
9875
- focusTarget: () => null,
9876
- surface: (ctx) => {
9877
- const ref2 = ctx.ref;
9878
- const reports = ref2 ? ctx.registry.getReports(ref2.kind, ref2.id) : [];
9879
- const items = reports.map((r) => reportToItem(r, ctx));
9880
- return {
9881
- kind: "list",
9882
- id: "uidex-entity-reports",
9883
- items,
9884
- emptyLabel: "No reports for this element",
9885
- filter: (item, query) => matchesQuery(`${item.label} ${item.subtitle ?? ""}`, query),
9886
- onSelect: (item) => {
9887
- setSelectedReportId(item.value.replace(/^report:/, ""));
9888
- ctx.push({ id: BUILT_IN_VIEW_IDS.reportDetail, ref: ref2 });
9889
- }
9890
- };
9891
- }
9892
- };
9893
-
9894
7495
  // src/browser/views/built-in/explore-page.ts
9895
- import { Compass as Compass2, createElement as createLucideElement8 } from "lucide";
7496
+ import { Compass as Compass2, createElement as createLucideElement6 } from "lucide";
9896
7497
  var KIND_ORDER = new Map(
9897
7498
  ENTITY_KINDS.map((kind, index) => [kind, index])
9898
7499
  );
@@ -9934,7 +7535,7 @@ var explorePageView = {
9934
7535
  palette: {
9935
7536
  label: "Explore Page",
9936
7537
  shortcut: "",
9937
- icon: () => createLucideElement8(Compass2)
7538
+ icon: () => createLucideElement6(Compass2)
9938
7539
  },
9939
7540
  title: "Explore Page",
9940
7541
  hints: [{ key: "\u21B5", label: "Select" }],
@@ -9969,332 +7570,6 @@ var explorePageView = {
9969
7570
  }
9970
7571
  };
9971
7572
 
9972
- // src/browser/internal/clipboard.ts
9973
- async function copyToClipboard(text) {
9974
- try {
9975
- if (typeof navigator !== "undefined" && navigator.clipboard?.writeText) {
9976
- await navigator.clipboard.writeText(text);
9977
- return true;
9978
- }
9979
- } catch {
9980
- }
9981
- try {
9982
- if (typeof document === "undefined") return false;
9983
- const textarea = document.createElement("textarea");
9984
- textarea.value = text;
9985
- textarea.setAttribute("readonly", "");
9986
- textarea.style.position = "fixed";
9987
- textarea.style.opacity = "0";
9988
- document.body.appendChild(textarea);
9989
- textarea.select();
9990
- const ok = document.execCommand("copy");
9991
- document.body.removeChild(textarea);
9992
- return ok;
9993
- } catch {
9994
- return false;
9995
- }
9996
- }
9997
-
9998
- // src/browser/views/built-in/report/markdown.ts
9999
- function capitalize2(s) {
10000
- return s.length === 0 ? s : s[0].toUpperCase() + s.slice(1);
10001
- }
10002
- function renderPayloadMarkdown(payload) {
10003
- const heading = payload.title ?? `${capitalize2(payload.type ?? "")} Report`;
10004
- const ctx = payload.context;
10005
- const lines = [
10006
- `# ${heading}`,
10007
- "",
10008
- `- **Type:** ${payload.type}`,
10009
- ...payload.severity ? [`- **Severity:** ${payload.severity}`] : [],
10010
- `- **Entity:** \`${payload.entity}\``,
10011
- "",
10012
- "#### Description",
10013
- payload.body || "_(no description)_",
10014
- "",
10015
- "#### Context",
10016
- `- **URL:** ${ctx?.url}`,
10017
- ...ctx?.pageTitle ? [`- **Page title:** ${ctx.pageTitle}`] : [],
10018
- `- **Viewport:** ${ctx?.viewport.w}\xD7${ctx?.viewport.h}`,
10019
- `- **User agent:** ${ctx?.userAgent}`,
10020
- `- **Timestamp:** ${ctx?.timestamp}`
10021
- ];
10022
- return lines.join("\n") + "\n";
10023
- }
10024
-
10025
- // src/browser/views/built-in/report/schema.ts
10026
- import { z } from "zod";
10027
- var reportSchema = z.object({
10028
- type: z.enum(["bug", "request", "suggestion"]),
10029
- severity: z.enum(["low", "medium", "high", "critical"]).optional(),
10030
- title: z.string().optional(),
10031
- body: z.string().trim().min(1, { message: "Description is required." })
10032
- });
10033
- var reportFields = [
10034
- {
10035
- kind: "select",
10036
- name: "type",
10037
- label: "Type",
10038
- options: [
10039
- { value: "bug", label: "Bug" },
10040
- { value: "request", label: "Request" },
10041
- { value: "suggestion", label: "Suggestion" }
10042
- ]
10043
- },
10044
- {
10045
- kind: "select",
10046
- name: "severity",
10047
- label: "Severity",
10048
- value: "medium",
10049
- options: [
10050
- { value: "low", label: "Low" },
10051
- { value: "medium", label: "Medium" },
10052
- { value: "high", label: "High" },
10053
- { value: "critical", label: "Critical" }
10054
- ]
10055
- },
10056
- {
10057
- kind: "text",
10058
- name: "title",
10059
- label: "Title",
10060
- placeholder: "Short summary (optional)"
10061
- },
10062
- {
10063
- kind: "textarea",
10064
- name: "body",
10065
- label: "Description",
10066
- placeholder: "Describe what happened\u2026",
10067
- required: true
10068
- }
10069
- ];
10070
-
10071
- // src/browser/views/built-in/report/view-builder.ts
10072
- var KIND_TO_ATTR = new Map(
10073
- UIDEX_ATTR_TO_KIND.map(([attr, kind]) => [kind, attr])
10074
- );
10075
- function resolveElement(ref2) {
10076
- const attr = KIND_TO_ATTR.get(ref2.kind);
10077
- if (!attr) return null;
10078
- return document.querySelector(
10079
- `[${attr}="${CSS.escape(ref2.id)}"]`
10080
- );
10081
- }
10082
- function buildPayload(ctx, componentId, values, prefix, augmentPayload, screenshot) {
10083
- const context = captureReportContext({ getRoute: ctx.getRoute });
10084
- const title = String(values.title ?? "").trim();
10085
- const body = String(values.body ?? "").trim();
10086
- const reporter = ctx.user ? { id: ctx.user.id, name: ctx.user.name || void 0 } : void 0;
10087
- const payload = {
10088
- type: values.type ?? "bug",
10089
- severity: values.severity ?? "medium",
10090
- title: title || void 0,
10091
- body: prefix ? `${prefix}${body}` : body,
10092
- entity: componentId,
10093
- screenshot,
10094
- context,
10095
- reporter,
10096
- metadata: ctx.user ? { userId: ctx.user.id } : void 0
10097
- };
10098
- return augmentPayload ? augmentPayload(payload, ctx, values) : payload;
10099
- }
10100
- async function copyFallback(payload) {
10101
- const markdown = renderPayloadMarkdown(payload);
10102
- const copied = await copyToClipboard(markdown);
10103
- if (!copied) console.log("[uidex] report markdown:\n" + markdown);
10104
- return {
10105
- status: copied ? "success" : "error",
10106
- message: copied ? "Copied to clipboard" : "Copy failed"
10107
- };
10108
- }
10109
- function createReportView(config) {
10110
- const {
10111
- id,
10112
- resolveCloud,
10113
- componentId,
10114
- submitLabels,
10115
- successToast,
10116
- failureToast,
10117
- prependDescription,
10118
- baseFields,
10119
- extraFields,
10120
- augmentPayload,
10121
- successResult,
10122
- schema: schemaOverride
10123
- } = config;
10124
- return {
10125
- id,
10126
- matches: () => false,
10127
- parent: parentDetail,
10128
- searchable: false,
10129
- hints: (ctx) => [
10130
- {
10131
- key: "\u2318\u21B5",
10132
- label: resolveCloud(ctx) ? submitLabels.ready : submitLabels.noCloud
10133
- }
10134
- ],
10135
- focusTarget: (host) => host.querySelector(
10136
- "[data-uidex-form='report'] select, [data-uidex-form='report'] input, [data-uidex-form='report'] textarea"
10137
- ),
10138
- surface: (ctx) => {
10139
- const cloud = resolveCloud(ctx);
10140
- const extra = extraFields ? extraFields(ctx) : [];
10141
- const fields = [...extra, ...baseFields ?? reportFields];
10142
- const isDomBacked = ctx.ref != null && DOM_BACKED_KINDS.has(ctx.ref.kind);
10143
- const targetEl = ctx.ref && isDomBacked ? resolveElement(ctx.ref) : null;
10144
- const screenshotPromise = isDomBacked ? captureScreenshot({
10145
- target: targetEl ?? void 0,
10146
- maxWidth: 1280
10147
- }).catch(() => null) : null;
10148
- return {
10149
- kind: "form",
10150
- id: "report",
10151
- fields,
10152
- schema: schemaOverride ?? reportSchema,
10153
- screenshotPreview: screenshotPromise ? screenshotPromise : void 0,
10154
- submit: {
10155
- label: cloud ? submitLabels.ready : submitLabels.noCloud,
10156
- onSubmit: async (values) => {
10157
- const screenshot = await screenshotPromise ?? void 0;
10158
- const prefix = prependDescription ? prependDescription() : "";
10159
- const payload = buildPayload(
10160
- ctx,
10161
- componentId(ctx),
10162
- values,
10163
- prefix,
10164
- augmentPayload,
10165
- screenshot
10166
- );
10167
- if (!cloud) {
10168
- return copyFallback(payload);
10169
- }
10170
- try {
10171
- const result = await cloud.reports.submit(
10172
- payload
10173
- );
10174
- ctx.onAfterSubmit?.();
10175
- if (successResult) return successResult(result);
10176
- return {
10177
- status: "success",
10178
- message: successToast(result)
10179
- };
10180
- } catch (err) {
10181
- const message = err instanceof Error ? err.message : String(err);
10182
- return {
10183
- status: "error",
10184
- message: failureToast(err) ?? message
10185
- };
10186
- }
10187
- }
10188
- }
10189
- };
10190
- }
10191
- };
10192
- }
10193
-
10194
- // src/browser/views/built-in/report/host-report.ts
10195
- var reportView = createReportView({
10196
- id: BUILT_IN_VIEW_IDS.report,
10197
- resolveCloud: (ctx) => ctx.cloud,
10198
- componentId: (ctx) => ctx.ref ? `${ctx.ref.kind}:${ctx.ref.id}` : "unknown",
10199
- submitLabels: { ready: "Report", noCloud: "Copy Report" },
10200
- successToast: (result) => {
10201
- const ticketKey = result.externalLink?.ok && result.externalLink.key ? result.externalLink.key : null;
10202
- return ticketKey ? `Report submitted (${ticketKey})` : "Report submitted";
10203
- },
10204
- failureToast: (err) => {
10205
- const message = err instanceof Error ? err.message : String(err);
10206
- return `Failed: ${message}`;
10207
- }
10208
- });
10209
-
10210
- // src/browser/views/built-in/report/jira-report.ts
10211
- var jiraSchema = reportSchema.omit({ type: true });
10212
- var jiraBaseFields = reportFields.filter(
10213
- (f) => f.name !== "type" && f.name !== "severity"
10214
- );
10215
- function buildParentIssueField(config) {
10216
- const issues = config.parentIssues ?? [];
10217
- const options = [
10218
- { value: "", label: "None" }
10219
- ];
10220
- const byType = /* @__PURE__ */ new Map();
10221
- for (const issue of issues) {
10222
- const group = byType.get(issue.issueType) ?? [];
10223
- group.push(issue);
10224
- byType.set(issue.issueType, group);
10225
- }
10226
- for (const [type, group] of byType) {
10227
- for (const issue of group) {
10228
- options.push({
10229
- value: issue.key,
10230
- label: `[${type}] ${issue.key}: ${issue.summary}`
10231
- });
10232
- }
10233
- }
10234
- return {
10235
- kind: "select",
10236
- name: "parentIssue",
10237
- label: "Parent Issue",
10238
- options
10239
- };
10240
- }
10241
- var jiraReportView = createReportView({
10242
- id: BUILT_IN_VIEW_IDS.jiraReport,
10243
- resolveCloud: (ctx) => ctx.cloud,
10244
- componentId: (ctx) => ctx.ref ? `${ctx.ref.kind}:${ctx.ref.id}` : "unknown",
10245
- submitLabels: { ready: "Create Jira Ticket", noCloud: "Copy report" },
10246
- schema: jiraSchema,
10247
- baseFields: jiraBaseFields,
10248
- extraFields: (ctx) => {
10249
- const cloud = ctx.cloud;
10250
- const config = cloud?.integrations.getCachedConfig() ?? null;
10251
- if (!config?.hasJira) return [];
10252
- return [buildParentIssueField(config)];
10253
- },
10254
- augmentPayload: (payload, ctx, values) => {
10255
- const cloud = ctx.cloud;
10256
- const config = cloud?.integrations.getCachedConfig() ?? null;
10257
- if (!config?.hasJira || !config.integrationId) return payload;
10258
- const targetConfig = {};
10259
- const parentKey = values.parentIssue;
10260
- if (parentKey) {
10261
- const issue = config.parentIssues?.find((i) => i.key === parentKey);
10262
- if (issue) targetConfig.epicId = issue.id;
10263
- }
10264
- return {
10265
- ...payload,
10266
- type: "bug",
10267
- suggestedTarget: {
10268
- integrationId: config.integrationId,
10269
- targetConfig
10270
- }
10271
- };
10272
- },
10273
- successResult: (result) => {
10274
- const link = result.externalLink;
10275
- if (link?.ok && link.key) {
10276
- return {
10277
- status: "success",
10278
- message: `Created ${link.key}`,
10279
- link: link.url ? { url: link.url, label: link.key } : void 0
10280
- };
10281
- }
10282
- return {
10283
- status: "error",
10284
- message: "Report saved \u2014 Jira issue creation failed"
10285
- };
10286
- },
10287
- successToast: (result) => {
10288
- const link = result.externalLink;
10289
- if (link?.ok && link.key) return `Created ${link.key}`;
10290
- return "Report saved \u2014 Jira Bug failed";
10291
- },
10292
- failureToast: (err) => {
10293
- const message = err instanceof Error ? err.message : String(err);
10294
- return `Failed to create issue: ${message}`;
10295
- }
10296
- });
10297
-
10298
7573
  // src/browser/views/built-in/flow-detail.ts
10299
7574
  var STEP_KINDS = [
10300
7575
  "element",
@@ -10326,8 +7601,7 @@ var flowDetailView = {
10326
7601
  }
10327
7602
  const actions = [
10328
7603
  copyPathAction(ctx.ref, flow.loc),
10329
- copySnapshotAction(ctx.ref, flow.loc),
10330
- reportAction(ctx.ref)
7604
+ copySnapshotAction(ctx.ref, flow.loc)
10331
7605
  ];
10332
7606
  const sections = [
10333
7607
  flow.steps.length > 0 ? buildStepsSection(flow.steps, ctx.registry) : buildTouchesSection(flow, ctx.registry)
@@ -10417,7 +7691,7 @@ var flowsView = {
10417
7691
  };
10418
7692
 
10419
7693
  // src/browser/views/built-in/glossary.ts
10420
- import { BookOpen, createElement as createLucideElement9 } from "lucide";
7694
+ import { BookOpen, createElement as createLucideElement7 } from "lucide";
10421
7695
  var KIND_TO_VIEW = {
10422
7696
  element: BUILT_IN_VIEW_IDS.elements,
10423
7697
  widget: BUILT_IN_VIEW_IDS.widgets,
@@ -10454,7 +7728,7 @@ var glossaryView = {
10454
7728
  palette: {
10455
7729
  label: "Glossary",
10456
7730
  group: PALETTE_GROUPS.commands,
10457
- icon: () => createLucideElement9(BookOpen)
7731
+ icon: () => createLucideElement7(BookOpen)
10458
7732
  },
10459
7733
  title: "Glossary",
10460
7734
  hints: [{ key: "\u21B5", label: "Select" }],
@@ -10483,246 +7757,9 @@ var glossaryView = {
10483
7757
  }
10484
7758
  };
10485
7759
 
10486
- // src/browser/views/built-in/page-reports.ts
10487
- import { CircleOff, Inbox as Inbox2, createElement as createLucideElement10 } from "lucide";
10488
- function collectPageReports(ctx) {
10489
- const items = [];
10490
- const seenReportIds = /* @__PURE__ */ new Set();
10491
- for (const kind of ENTITY_KINDS) {
10492
- for (const entity of ctx.registry.list(kind)) {
10493
- const id = "id" in entity ? entity.id : "";
10494
- if (!id) continue;
10495
- const reports = ctx.registry.getReports(kind, id);
10496
- seenReportIds.add(`${kind}:${id}`);
10497
- const ref2 = { kind, id };
10498
- for (const report of reports) {
10499
- const typeLabel = TYPE_LABELS[report.type] ?? report.type;
10500
- const sevLabel = SEVERITY_LABELS[report.severity] ?? report.severity;
10501
- const raw = report.title || report.body;
10502
- const label = raw.length > 80 ? raw.slice(0, 80) + "\u2026" : raw;
10503
- const entityName = displayName(entity);
10504
- items.push({
10505
- value: `report:${report.id}`,
10506
- label: label || "(no description)",
10507
- subtitle: [
10508
- entityName,
10509
- authorLabel(report),
10510
- typeLabel,
10511
- sevLabel,
10512
- relativeTime(report.createdAt)
10513
- ].filter(Boolean).join(" \xB7 "),
10514
- tag: `report:${report.id}`,
10515
- group: `${kind}: ${entityName}`,
10516
- leading: () => renderKindIcon(kind),
10517
- ref: ref2
10518
- });
10519
- }
10520
- }
10521
- }
10522
- for (const key of ctx.registry.listReportKeys()) {
10523
- if (seenReportIds.has(key)) continue;
10524
- const parsed = parseComponentRef(key);
10525
- if (ctx.registry.get(parsed.kind, parsed.id)) continue;
10526
- const reports = ctx.registry.getReports(parsed.kind, parsed.id);
10527
- const ref2 = parsed;
10528
- for (const report of reports) {
10529
- const typeLabel = TYPE_LABELS[report.type] ?? report.type;
10530
- const sevLabel = SEVERITY_LABELS[report.severity] ?? report.severity;
10531
- const raw = report.title || report.body;
10532
- const label = raw.length > 80 ? raw.slice(0, 80) + "\u2026" : raw;
10533
- items.push({
10534
- value: `report:${report.id}`,
10535
- label: label || "(no description)",
10536
- subtitle: [
10537
- `${parsed.kind}:${parsed.id}`,
10538
- authorLabel(report),
10539
- typeLabel,
10540
- sevLabel,
10541
- relativeTime(report.createdAt)
10542
- ].filter(Boolean).join(" \xB7 "),
10543
- tag: `report:${report.id}`,
10544
- group: "Orphaned",
10545
- leading: () => createLucideElement10(CircleOff),
10546
- ref: ref2
10547
- });
10548
- }
10549
- }
10550
- return items;
10551
- }
10552
- var pageReportsView = {
10553
- id: BUILT_IN_VIEW_IDS.pageReports,
10554
- matches: () => false,
10555
- parent: () => COMMAND_PALETTE_ENTRY2,
10556
- palette: {
10557
- label: "Page Reports",
10558
- group: "Current Page",
10559
- icon: () => createLucideElement10(Inbox2)
10560
- },
10561
- title: "Page Reports",
10562
- searchable: true,
10563
- hints: [{ key: "\u21B5", label: "Select" }],
10564
- focusTarget: () => null,
10565
- surface: (ctx) => {
10566
- const items = collectPageReports(ctx);
10567
- return {
10568
- kind: "list",
10569
- id: "uidex-page-reports",
10570
- items,
10571
- emptyLabel: "No reports on this page",
10572
- filter: (item, query) => matchesQuery(
10573
- `${item.label} ${item.subtitle ?? ""} ${item.group ?? ""}`,
10574
- query
10575
- ),
10576
- onSelect: (item) => {
10577
- setSelectedReportId(item.value.replace(/^report:/, ""));
10578
- ctx.push({
10579
- id: BUILT_IN_VIEW_IDS.reportDetail,
10580
- ref: item.ref
10581
- });
10582
- }
10583
- };
10584
- }
10585
- };
10586
-
10587
- // src/browser/views/built-in/pin-settings.ts
10588
- import {
10589
- Check,
10590
- Globe,
10591
- MapPin as MapPin2,
10592
- Settings,
10593
- createElement as createLucideElement11
10594
- } from "lucide";
10595
-
10596
- // src/browser/ui/toast.ts
10597
- function showCopiedToast(message) {
10598
- if (typeof document === "undefined") return;
10599
- const dark = isDarkMode();
10600
- const toast = document.createElement("div");
10601
- toast.setAttribute("data-uidex-toast", "");
10602
- Object.assign(toast.style, {
10603
- position: "fixed",
10604
- top: "50%",
10605
- left: "50%",
10606
- transform: "translate(-50%, -50%) scale(0.96)",
10607
- padding: "12px 20px",
10608
- fontSize: "14px",
10609
- fontFamily: "ui-sans-serif, system-ui, sans-serif",
10610
- fontWeight: "500",
10611
- color: dark ? "#0a0a0a" : "#fafafa",
10612
- background: dark ? "rgba(255, 255, 255, 0.98)" : "rgba(28, 28, 30, 0.95)",
10613
- border: dark ? "1px solid rgba(0, 0, 0, 0.08)" : "1px solid rgba(255, 255, 255, 0.08)",
10614
- borderRadius: "10px",
10615
- boxShadow: dark ? "0 8px 24px rgba(0, 0, 0, 0.35), 0 2px 6px rgba(0, 0, 0, 0.2)" : "0 8px 24px rgba(0, 0, 0, 0.35), 0 2px 6px rgba(0, 0, 0, 0.25)",
10616
- zIndex: "2147483647",
10617
- pointerEvents: "none",
10618
- opacity: "0",
10619
- transition: "opacity 120ms ease-out, transform 160ms ease-out",
10620
- whiteSpace: "nowrap"
10621
- });
10622
- toast.textContent = message;
10623
- document.body.appendChild(toast);
10624
- requestAnimationFrame(() => {
10625
- toast.style.opacity = "1";
10626
- toast.style.transform = "translate(-50%, -50%) scale(1)";
10627
- });
10628
- setTimeout(() => {
10629
- toast.style.opacity = "0";
10630
- toast.style.transform = "translate(-50%, -50%) scale(0.96)";
10631
- setTimeout(() => toast.remove(), 200);
10632
- }, 1200);
10633
- }
10634
-
10635
- // src/browser/views/built-in/pin-settings.ts
10636
- var MATCH_MODE_KEY = "uidex:pin-match-mode";
10637
- function readMode() {
10638
- try {
10639
- const v = localStorage.getItem(MATCH_MODE_KEY);
10640
- if (v === "route" || v === "pathname" || v === "component") return v;
10641
- } catch {
10642
- }
10643
- return "route";
10644
- }
10645
- function writeMode(mode) {
10646
- try {
10647
- localStorage.setItem(MATCH_MODE_KEY, mode);
10648
- } catch {
10649
- }
10650
- }
10651
- var MODES = [
10652
- {
10653
- value: "route",
10654
- label: "By route",
10655
- description: "Pins from any URL matching this route pattern",
10656
- icon: Globe
10657
- },
10658
- {
10659
- value: "pathname",
10660
- label: "By pathname",
10661
- description: "Pins from this exact URL path",
10662
- icon: MapPin2
10663
- },
10664
- {
10665
- value: "component",
10666
- label: "By component",
10667
- description: "All pins for components on this page",
10668
- icon: Settings
10669
- }
10670
- ];
10671
- function leadingIcon2(iconNode, active) {
10672
- return () => {
10673
- const svg2 = createLucideElement11(active ? Check : iconNode);
10674
- svg2.setAttribute("aria-hidden", "true");
10675
- return createIconTile(svg2);
10676
- };
10677
- }
10678
- var pinSettingsView = {
10679
- id: BUILT_IN_VIEW_IDS.pinSettings,
10680
- matches: () => false,
10681
- parent: () => COMMAND_PALETTE_ENTRY2,
10682
- palette: {
10683
- label: "Pin settings",
10684
- group: PALETTE_GROUPS.commands,
10685
- icon: () => createLucideElement11(Settings)
10686
- },
10687
- title: "Pin settings",
10688
- searchable: false,
10689
- focusTarget: (host) => host.querySelector("[data-uidex-list-content]"),
10690
- surface: (ctx) => {
10691
- const current = readMode();
10692
- const items = MODES.map((m) => {
10693
- const active = m.value === current;
10694
- return {
10695
- value: m.value,
10696
- label: m.label,
10697
- subtitle: m.description,
10698
- leading: leadingIcon2(m.icon, active),
10699
- trailing: active ? html`<span class="text-muted-foreground ms-auto text-xs font-medium"
10700
- >Active</span
10701
- >` : void 0
10702
- };
10703
- });
10704
- return {
10705
- kind: "list",
10706
- id: "uidex-pin-settings",
10707
- searchable: false,
10708
- items,
10709
- emptyLabel: "No options available",
10710
- onSelect: (item) => {
10711
- const mode = item.value;
10712
- writeMode(mode);
10713
- ctx.onAfterSubmit?.();
10714
- const modeLabel = MODES.find((m) => m.value === mode).label;
10715
- showCopiedToast(`Pin mode set to "${modeLabel}"`);
10716
- ctx.pop();
10717
- }
10718
- };
10719
- }
10720
- };
10721
-
10722
7760
  // src/browser/views/built-in/index.ts
10723
7761
  function buildDefaultViews(shortcut) {
10724
7762
  return [
10725
- closeReasonView,
10726
7763
  createCommandPaletteView(shortcut),
10727
7764
  explorePageView,
10728
7765
  componentDetailView,
@@ -10739,43 +7776,15 @@ function buildDefaultViews(shortcut) {
10739
7776
  primitivesView,
10740
7777
  primitiveDetailView,
10741
7778
  regionDetailView,
10742
- entityReportsView,
10743
- reportView,
10744
- jiraReportView,
10745
- glossaryView,
10746
- pageReportsView,
10747
- pinSettingsView,
10748
- reportDetailView
7779
+ glossaryView
10749
7780
  ];
10750
7781
  }
10751
7782
 
10752
7783
  // src/browser/create-uidex.ts
10753
- function getVisibleEntities() {
10754
- if (typeof document === "undefined") return [];
10755
- const selector = UIDEX_ATTR_TO_KIND.map(([a]) => `[${a}]`).join(",");
10756
- const nodes = document.querySelectorAll(selector);
10757
- const ids = [];
10758
- const seen = /* @__PURE__ */ new Set();
10759
- for (const node of nodes) {
10760
- if (node.closest(SURFACE_IGNORE_SELECTOR)) continue;
10761
- for (const [attr, kind] of UIDEX_ATTR_TO_KIND) {
10762
- const id = node.getAttribute(attr);
10763
- if (!id) continue;
10764
- const key = `${kind}:${id}`;
10765
- if (!seen.has(key)) {
10766
- seen.add(key);
10767
- ids.push(key);
10768
- }
10769
- break;
10770
- }
10771
- }
10772
- return ids;
10773
- }
10774
7784
  function createUidex(options = {}) {
10775
7785
  const registry = createRegistry();
10776
7786
  const inspectorRef = { current: null };
10777
7787
  const overlayRef = { current: null };
10778
- const pinLayerRef = { current: null };
10779
7788
  const applyOverlay = (ctx) => {
10780
7789
  const overlay = overlayRef.current;
10781
7790
  if (!overlay) return;
@@ -10795,7 +7804,6 @@ function createUidex(options = {}) {
10795
7804
  const session = createSession({
10796
7805
  theme: options.theme,
10797
7806
  resolvedTheme: options.resolvedTheme,
10798
- user: options.user,
10799
7807
  onMountInspector: () => inspectorRef.current?.mount(),
10800
7808
  onDestroyInspector: () => inspectorRef.current?.destroy(),
10801
7809
  onShowOverlay: applyOverlay,
@@ -10803,9 +7811,6 @@ function createUidex(options = {}) {
10803
7811
  onUpdateOverlay: applyOverlay
10804
7812
  });
10805
7813
  const views = createRouter({ session });
10806
- const cloud = options.cloud ?? null;
10807
- const ingestOpts = resolveIngestOptions(options.ingest, cloud !== null);
10808
- const ingest = ingestOpts ? createIngest(ingestOpts) : null;
10809
7814
  if (options.defaultViews !== false) {
10810
7815
  for (const view of buildDefaultViews(options.shortcut)) views.add(view);
10811
7816
  }
@@ -10815,111 +7820,12 @@ function createUidex(options = {}) {
10815
7820
  let shadowRoot = null;
10816
7821
  const mountCleanup = createCleanupStack();
10817
7822
  let mounted = false;
10818
- function syncReportsToRegistry() {
10819
- const layer = pinLayerRef.current;
10820
- if (!layer) return;
10821
- const byEntity = /* @__PURE__ */ new Map();
10822
- for (const pin of layer.getAllPins()) {
10823
- const cid = pin.entity ?? "";
10824
- if (!cid) continue;
10825
- const list = byEntity.get(cid);
10826
- if (list) list.push(pin);
10827
- else byEntity.set(cid, [pin]);
10828
- }
10829
- for (const [cid, pins] of byEntity) {
10830
- const ref2 = parseComponentRef(cid);
10831
- registry.setReports(ref2.kind, ref2.id, pins);
10832
- }
10833
- }
10834
- function setupKeyBindings(root, viewStack) {
10835
- const bindings = bindShadowKeys({
10836
- shadowRoot: root,
10837
- session,
10838
- getActionsPopup: () => viewStack.getActionsPopup(),
10839
- getPinLayer: () => pinLayerRef.current,
10840
- shortcut: options.shortcut
10841
- });
10842
- mountCleanup.add(bindings);
10843
- return bindings;
10844
- }
10845
- function setupPinLayer(root, shell, channel, getCurrentRoute, getMatchMode, getPathname) {
10846
- if (cloud) {
10847
- registry.closeReport = async (reportId, status) => {
10848
- pinLayerRef.current?.removePin(reportId);
10849
- await cloud.pins.close(
10850
- reportId,
10851
- status
10852
- );
10853
- syncReportsToRegistry();
10854
- };
10855
- }
10856
- const pinLayer = createPinLayer({
10857
- container: root,
10858
- onOpenPinDetail: (componentId, reportId) => {
10859
- const ref2 = parseComponentRef(componentId);
10860
- setSelectedReportId(reportId);
10861
- const entry = { id: BUILT_IN_VIEW_IDS.reportDetail, ref: ref2 };
10862
- session.mode.transition.enterViewing(views.buildStack(entry));
10863
- },
10864
- onHoverPin: (anchor, componentId) => {
10865
- const overlay = overlayRef.current;
10866
- if (!overlay) return;
10867
- if (!anchor || !componentId) {
10868
- overlay.hide();
10869
- return;
10870
- }
10871
- overlay.show(anchor, {
10872
- color: isDarkMode() ? "#e4e4e7" : "#27272a"
10873
- });
10874
- },
10875
- onPinsChanged: syncReportsToRegistry
10876
- });
10877
- shell.menuBar.setPinLayer(pinLayer);
10878
- pinLayerRef.current = pinLayer;
10879
- mountCleanup.add(() => {
10880
- pinLayer.destroy();
10881
- pinLayerRef.current = null;
10882
- registry.closeReport = void 0;
10883
- });
10884
- if (cloud) {
10885
- const detach = pinLayer.attachCloud({
10886
- cloud,
10887
- channel,
10888
- getRoute: getCurrentRoute,
10889
- getPathname,
10890
- getVisibleEntities,
10891
- getMatchMode,
10892
- onError: (err) => console.warn("[uidex] pin fetch failed", err)
10893
- });
10894
- mountCleanup.add(detach);
10895
- if (channel && typeof window !== "undefined") {
10896
- const onRouteChange = () => {
10897
- const route = getCurrentRoute();
10898
- channel?.joinRoute(route);
10899
- void pinLayer.refresh();
10900
- };
10901
- const detachRoute = bindRouteChange(onRouteChange);
10902
- mountCleanup.add(detachRoute);
10903
- }
10904
- }
10905
- }
10906
7823
  function mount(target) {
10907
7824
  if (mounted) return;
10908
7825
  const mountTarget = target ?? (typeof document !== "undefined" ? document.body : null);
10909
7826
  if (!mountTarget) {
10910
7827
  throw new Error("createUidex: no mount target available");
10911
7828
  }
10912
- const getPathname = () => typeof location !== "undefined" ? location.pathname : "/";
10913
- const getCurrentRoute = () => options.getRoute?.() ?? findCurrentRoutePath(registry) ?? getPathname();
10914
- const getMatchMode = () => readMode();
10915
- let channel = null;
10916
- if (cloud && options.user) {
10917
- channel = cloud.realtime.connect({
10918
- user: options.user,
10919
- route: getCurrentRoute()
10920
- });
10921
- mountCleanup.add(() => channel?.disconnect());
10922
- }
10923
7829
  const shell = createSurfaceShell({
10924
7830
  mount: mountTarget,
10925
7831
  registry,
@@ -10927,7 +7833,6 @@ function createUidex(options = {}) {
10927
7833
  stylesheets: options.stylesheets,
10928
7834
  initialCorner: options.initialCorner,
10929
7835
  appTitle: options.appTitle,
10930
- channel,
10931
7836
  inspector: {
10932
7837
  onSelect: (match) => {
10933
7838
  const route = views.resolve(match.ref);
@@ -10963,38 +7868,23 @@ function createUidex(options = {}) {
10963
7868
  viewContainer.setAttribute("data-uidex-views", "");
10964
7869
  shell.host.chromeEl.appendChild(viewContainer);
10965
7870
  mountCleanup.add(() => viewContainer.remove());
10966
- let keyBindings = null;
10967
7871
  const viewStack = createViewStack({
10968
7872
  container: viewContainer,
10969
7873
  views,
10970
7874
  session,
10971
7875
  registry,
10972
- cloud,
10973
7876
  highlight,
10974
- shortcut: options.shortcut,
10975
- pushEscapeLayer: (handler) => {
10976
- if (!keyBindings) return () => {
10977
- };
10978
- return keyBindings.pushEscapeLayer(handler);
10979
- },
10980
- onAfterSubmit: () => pinLayerRef.current?.refresh(),
10981
- getRoute: getCurrentRoute
7877
+ shortcut: options.shortcut
10982
7878
  });
10983
7879
  mountCleanup.add(viewStack);
10984
7880
  if (shadowRoot) {
10985
- keyBindings = setupKeyBindings(shadowRoot, viewStack);
10986
- setupPinLayer(
7881
+ const keyBindings = bindShadowKeys({
10987
7882
  shadowRoot,
10988
- shell,
10989
- channel,
10990
- getCurrentRoute,
10991
- getMatchMode,
10992
- getPathname
10993
- );
10994
- }
10995
- if (ingest) {
10996
- ingest.start();
10997
- mountCleanup.add(() => ingest.stop());
7883
+ session,
7884
+ getActionsPopup: () => viewStack.getActionsPopup(),
7885
+ shortcut: options.shortcut
7886
+ });
7887
+ mountCleanup.add(keyBindings);
10998
7888
  }
10999
7889
  mounted = true;
11000
7890
  }
@@ -11010,8 +7900,6 @@ function createUidex(options = {}) {
11010
7900
  registry,
11011
7901
  session,
11012
7902
  views,
11013
- cloud,
11014
- ingest,
11015
7903
  get shadowRoot() {
11016
7904
  return shadowRoot;
11017
7905
  }
@@ -11027,21 +7915,16 @@ export {
11027
7915
  Z_BASE,
11028
7916
  Z_CHROME,
11029
7917
  Z_OVERLAY,
11030
- Z_PIN_LAYER,
11031
7918
  assertEntityKind,
11032
7919
  buildDefaultViews,
11033
7920
  componentDetailView,
11034
7921
  createCommandPaletteView,
11035
- createConsoleCapture,
11036
7922
  createCursorTooltip,
11037
- createIngest,
11038
7923
  createInspector,
11039
7924
  createMenuBar,
11040
7925
  createModeStore,
11041
7926
  createNavigationStore,
11042
- createNetworkCapture,
11043
7927
  createOverlay,
11044
- createPinLayer,
11045
7928
  createRegistry,
11046
7929
  createRouter,
11047
7930
  createSession,
@@ -11056,15 +7939,11 @@ export {
11056
7939
  flowDetailView,
11057
7940
  formatShortcutLabel,
11058
7941
  isMetaKind,
11059
- nativeFetch,
11060
7942
  pageDetailView,
11061
- pinSettingsView,
11062
7943
  prettify,
11063
7944
  primitiveDetailView,
11064
7945
  regionDetailView,
11065
- reportView,
11066
7946
  resolveEntityElement,
11067
- resolveIngestOptions,
11068
7947
  resolveTheme,
11069
7948
  widgetDetailView
11070
7949
  };