uidex 0.7.0 → 0.8.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 +1024 -1041
  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 +1194 -322
  40. package/dist/scan/index.cjs.map +1 -1
  41. package/dist/scan/index.d.cts +274 -8
  42. package/dist/scan/index.d.ts +274 -8
  43. package/dist/scan/index.js +1185 -322
  44. package/dist/scan/index.js.map +1 -1
  45. package/package.json +27 -31
  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.cjs CHANGED
@@ -39,21 +39,16 @@ __export(src_exports, {
39
39
  Z_BASE: () => Z_BASE,
40
40
  Z_CHROME: () => Z_CHROME,
41
41
  Z_OVERLAY: () => Z_OVERLAY,
42
- Z_PIN_LAYER: () => Z_PIN_LAYER,
43
42
  assertEntityKind: () => assertEntityKind,
44
43
  buildDefaultViews: () => buildDefaultViews,
45
44
  componentDetailView: () => componentDetailView,
46
45
  createCommandPaletteView: () => createCommandPaletteView,
47
- createConsoleCapture: () => createConsoleCapture,
48
46
  createCursorTooltip: () => createCursorTooltip,
49
- createIngest: () => createIngest,
50
47
  createInspector: () => createInspector,
51
48
  createMenuBar: () => createMenuBar,
52
49
  createModeStore: () => createModeStore,
53
50
  createNavigationStore: () => createNavigationStore,
54
- createNetworkCapture: () => createNetworkCapture,
55
51
  createOverlay: () => createOverlay,
56
- createPinLayer: () => createPinLayer,
57
52
  createRegistry: () => createRegistry,
58
53
  createRouter: () => createRouter,
59
54
  createSession: () => createSession,
@@ -68,15 +63,11 @@ __export(src_exports, {
68
63
  flowDetailView: () => flowDetailView,
69
64
  formatShortcutLabel: () => formatShortcutLabel,
70
65
  isMetaKind: () => isMetaKind,
71
- nativeFetch: () => nativeFetch,
72
66
  pageDetailView: () => pageDetailView,
73
- pinSettingsView: () => pinSettingsView,
74
67
  prettify: () => prettify,
75
68
  primitiveDetailView: () => primitiveDetailView,
76
69
  regionDetailView: () => regionDetailView,
77
- reportView: () => reportView,
78
70
  resolveEntityElement: () => resolveEntityElement,
79
- resolveIngestOptions: () => resolveIngestOptions,
80
71
  resolveTheme: () => resolveTheme,
81
72
  widgetDetailView: () => widgetDetailView
82
73
  });
@@ -355,207 +346,6 @@ function displayName(entity, node) {
355
346
  return prettify(entity.id);
356
347
  }
357
348
 
358
- // src/browser/ingest/console.ts
359
- var DEFAULT_LIMIT = 50;
360
- var LEVELS = ["warn", "error"];
361
- function formatMessage(args) {
362
- return args.map((arg) => {
363
- if (typeof arg === "string") return arg;
364
- if (arg instanceof Error) return arg.stack ?? arg.message;
365
- try {
366
- return JSON.stringify(arg);
367
- } catch {
368
- return String(arg);
369
- }
370
- }).join(" ");
371
- }
372
- function createConsoleCapture(options = {}) {
373
- const limit = options.limit ?? DEFAULT_LIMIT;
374
- const target = options.target ?? console;
375
- const now = options.now ?? (() => /* @__PURE__ */ new Date());
376
- const buffer = [];
377
- const originals = {};
378
- let active = false;
379
- function record(level, args) {
380
- const entry = {
381
- level,
382
- message: formatMessage(args),
383
- timestamp: now().toISOString()
384
- };
385
- buffer.push(entry);
386
- if (buffer.length > limit) buffer.splice(0, buffer.length - limit);
387
- }
388
- function start() {
389
- if (active) return;
390
- for (const level of LEVELS) {
391
- const original = target[level];
392
- originals[level] = original;
393
- const wrapped = (...args) => {
394
- record(level, args);
395
- original.call(target, ...args);
396
- };
397
- target[level] = wrapped;
398
- }
399
- active = true;
400
- }
401
- function stop() {
402
- if (!active) return;
403
- for (const level of LEVELS) {
404
- const original = originals[level];
405
- if (original) {
406
- ;
407
- target[level] = original;
408
- }
409
- delete originals[level];
410
- }
411
- active = false;
412
- }
413
- return {
414
- start,
415
- stop,
416
- get isActive() {
417
- return active;
418
- },
419
- entries() {
420
- return buffer.slice();
421
- },
422
- clear() {
423
- buffer.length = 0;
424
- }
425
- };
426
- }
427
-
428
- // src/browser/ingest/native-fetch.ts
429
- var nativeFetch = typeof globalThis !== "undefined" && typeof globalThis.fetch === "function" ? globalThis.fetch.bind(globalThis) : void 0;
430
-
431
- // src/browser/ingest/network.ts
432
- var DEFAULT_LIMIT2 = 20;
433
- function resolveMethod(input, init) {
434
- if (init?.method) return init.method.toUpperCase();
435
- if (typeof input !== "string" && !(input instanceof URL) && "method" in input) {
436
- return input.method.toUpperCase();
437
- }
438
- return "GET";
439
- }
440
- function resolveUrl(input) {
441
- if (typeof input === "string") return input;
442
- if (input instanceof URL) return input.toString();
443
- return input.url;
444
- }
445
- function createNetworkCapture(options = {}) {
446
- const limit = options.limit ?? DEFAULT_LIMIT2;
447
- const target = options.target ?? globalThis;
448
- const now = options.now ?? (() => /* @__PURE__ */ new Date());
449
- const buffer = [];
450
- let original;
451
- let active = false;
452
- function push(entry) {
453
- buffer.push(entry);
454
- if (buffer.length > limit) buffer.splice(0, buffer.length - limit);
455
- }
456
- function start() {
457
- if (active) return;
458
- const baseline = target.fetch ?? nativeFetch;
459
- if (!baseline) return;
460
- original = baseline;
461
- const wrapped = async (input, init) => {
462
- const method = resolveMethod(input, init);
463
- const url = resolveUrl(input);
464
- try {
465
- const res = await baseline(input, init);
466
- if (res.status >= 400) {
467
- push({
468
- method,
469
- url,
470
- status: res.status,
471
- timestamp: now().toISOString()
472
- });
473
- }
474
- return res;
475
- } catch (err) {
476
- push({
477
- method,
478
- url,
479
- status: 0,
480
- timestamp: now().toISOString(),
481
- error: err instanceof Error ? err.message : String(err)
482
- });
483
- throw err;
484
- }
485
- };
486
- target.fetch = wrapped;
487
- active = true;
488
- }
489
- function stop() {
490
- if (!active) return;
491
- if (original) target.fetch = original;
492
- original = void 0;
493
- active = false;
494
- }
495
- return {
496
- start,
497
- stop,
498
- get isActive() {
499
- return active;
500
- },
501
- entries() {
502
- return buffer.slice();
503
- },
504
- clear() {
505
- buffer.length = 0;
506
- }
507
- };
508
- }
509
-
510
- // src/browser/ingest/index.ts
511
- function createIngest(options = {}) {
512
- const opts = options;
513
- const wantConsole = opts.captureConsole !== false;
514
- const wantNetwork = opts.captureNetwork !== false;
515
- const consoleCapture = wantConsole ? createConsoleCapture({
516
- limit: opts.consoleLimit,
517
- target: opts.consoleTarget,
518
- now: opts.now
519
- }) : null;
520
- const networkCapture = wantNetwork ? createNetworkCapture({
521
- limit: opts.networkLimit,
522
- target: opts.networkTarget,
523
- now: opts.now
524
- }) : null;
525
- let active = false;
526
- function start() {
527
- if (active) return;
528
- consoleCapture?.start();
529
- networkCapture?.start();
530
- active = Boolean(consoleCapture?.isActive || networkCapture?.isActive);
531
- }
532
- function stop() {
533
- if (!active) return;
534
- consoleCapture?.stop();
535
- networkCapture?.stop();
536
- active = false;
537
- }
538
- return {
539
- start,
540
- stop,
541
- get isActive() {
542
- return active;
543
- },
544
- console: consoleCapture,
545
- network: networkCapture
546
- };
547
- }
548
- function resolveIngestOptions(explicit, hasCloud) {
549
- if (explicit === null) return null;
550
- if (explicit === void 0) {
551
- return hasCloud ? { captureConsole: true, captureNetwork: true } : null;
552
- }
553
- if (explicit.captureConsole === false && explicit.captureNetwork === false) {
554
- return null;
555
- }
556
- return explicit;
557
- }
558
-
559
349
  // src/browser/internal/cleanup.ts
560
350
  function createCleanupStack() {
561
351
  const stack = [];
@@ -589,60 +379,6 @@ function composeCleanups(cleanups) {
589
379
  };
590
380
  }
591
381
 
592
- // src/browser/internal/dark-mode.ts
593
- function isDarkMode() {
594
- if (typeof document !== "undefined") {
595
- const root = document.documentElement;
596
- if (root?.classList.contains("dark")) return true;
597
- if (root?.classList.contains("light")) return false;
598
- }
599
- if (typeof window !== "undefined" && typeof window.matchMedia === "function") {
600
- return window.matchMedia("(prefers-color-scheme: dark)").matches;
601
- }
602
- return false;
603
- }
604
-
605
- // src/browser/internal/route-change.ts
606
- var ROUTE_CHANGE_EVENT = "uidex:routechange";
607
- var patched = false;
608
- function ensureHistoryPatched() {
609
- if (patched) return;
610
- if (typeof window === "undefined" || typeof history === "undefined") return;
611
- patched = true;
612
- const dispatch = () => {
613
- window.dispatchEvent(new Event(ROUTE_CHANGE_EVENT));
614
- };
615
- const origPush = history.pushState;
616
- history.pushState = function(...args) {
617
- const result = origPush.apply(
618
- this,
619
- args
620
- );
621
- dispatch();
622
- return result;
623
- };
624
- const origReplace = history.replaceState;
625
- history.replaceState = function(...args) {
626
- const result = origReplace.apply(
627
- this,
628
- args
629
- );
630
- dispatch();
631
- return result;
632
- };
633
- }
634
- function bindRouteChange(handler) {
635
- if (typeof window === "undefined") return () => {
636
- };
637
- ensureHistoryPatched();
638
- window.addEventListener("popstate", handler);
639
- window.addEventListener(ROUTE_CHANGE_EVENT, handler);
640
- return () => {
641
- window.removeEventListener("popstate", handler);
642
- window.removeEventListener(ROUTE_CHANGE_EVENT, handler);
643
- };
644
- }
645
-
646
382
  // src/browser/session/store.ts
647
383
  var import_vanilla3 = require("zustand/vanilla");
648
384
 
@@ -780,8 +516,7 @@ var defaultSnapshot = {
780
516
  pinnedHighlight: null,
781
517
  mode: "idle",
782
518
  theme: "auto",
783
- resolvedTheme: "light",
784
- user: null
519
+ resolvedTheme: "light"
785
520
  };
786
521
  function resolveTheme(preference, detect) {
787
522
  if (preference !== "auto") return preference;
@@ -871,8 +606,7 @@ function createSession(options = {}) {
871
606
  pinnedHighlight: null,
872
607
  mode: "idle",
873
608
  theme: initialPref,
874
- resolvedTheme: initialResolved,
875
- user: overrides.user ?? null
609
+ resolvedTheme: initialResolved
876
610
  }));
877
611
  nav.subscribe(() => {
878
612
  const { stack } = nav.getState();
@@ -916,8 +650,6 @@ var tailwind_built_default = `/*! tailwindcss v4.2.2 | MIT License | https://tai
916
650
  @layer theme, base, components, utilities;
917
651
  @layer theme {
918
652
  :root, :host {
919
- --font-sans: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI",
920
- Roboto, sans-serif;
921
653
  --color-red-400: oklch(70.4% 0.191 22.216);
922
654
  --color-red-500: oklch(63.7% 0.237 25.331);
923
655
  --color-red-700: oklch(50.5% 0.213 27.518);
@@ -970,7 +702,6 @@ var tailwind_built_default = `/*! tailwindcss v4.2.2 | MIT License | https://tai
970
702
  --color-black: #000;
971
703
  --color-white: #fff;
972
704
  --spacing: 0.25rem;
973
- --container-sm: 24rem;
974
705
  --container-xl: 36rem;
975
706
  --text-xs: 0.75rem;
976
707
  --text-xs--line-height: calc(1 / 0.75);
@@ -978,28 +709,22 @@ var tailwind_built_default = `/*! tailwindcss v4.2.2 | MIT License | https://tai
978
709
  --text-sm--line-height: calc(1.25 / 0.875);
979
710
  --text-base: 1rem;
980
711
  --text-base--line-height: calc(1.5 / 1);
981
- --text-xl: 1.25rem;
982
- --text-xl--line-height: calc(1.75 / 1.25);
983
712
  --font-weight-normal: 400;
984
713
  --font-weight-medium: 500;
985
714
  --font-weight-semibold: 600;
986
- --font-weight-bold: 700;
987
715
  --tracking-tight: -0.025em;
988
716
  --tracking-widest: 0.1em;
989
717
  --leading-relaxed: 1.625;
990
- --radius-md: calc(var(--radius) * 0.8);
991
718
  --radius-lg: var(--radius);
992
719
  --radius-xl: calc(var(--radius) * 1.4);
993
720
  --radius-2xl: calc(var(--radius) * 1.8);
994
721
  --ease-out: cubic-bezier(0, 0, 0.2, 1);
995
- --animate-spin: spin 1s linear infinite;
996
722
  --blur-sm: 8px;
997
723
  --default-transition-duration: 150ms;
998
724
  --default-transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
999
725
  --default-font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI",
1000
726
  Roboto, sans-serif;
1001
727
  --default-mono-font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
1002
- --color-muted: var(--muted);
1003
728
  --color-border: var(--border);
1004
729
  }
1005
730
  }
@@ -1167,17 +892,6 @@ var tailwind_built_default = `/*! tailwindcss v4.2.2 | MIT License | https://tai
1167
892
  .visible {
1168
893
  visibility: visible;
1169
894
  }
1170
- .sr-only {
1171
- position: absolute;
1172
- width: 1px;
1173
- height: 1px;
1174
- padding: 0;
1175
- margin: -1px;
1176
- overflow: hidden;
1177
- clip-path: inset(50%);
1178
- white-space: nowrap;
1179
- border-width: 0;
1180
- }
1181
895
  .absolute {
1182
896
  position: absolute;
1183
897
  }
@@ -1199,30 +913,12 @@ var tailwind_built_default = `/*! tailwindcss v4.2.2 | MIT License | https://tai
1199
913
  .end {
1200
914
  inset-inline-end: var(--spacing);
1201
915
  }
1202
- .-top-1 {
1203
- top: calc(var(--spacing) * -1);
1204
- }
1205
- .-right-1 {
1206
- right: calc(var(--spacing) * -1);
1207
- }
1208
- .right-0 {
1209
- right: calc(var(--spacing) * 0);
1210
- }
1211
- .bottom-full {
1212
- bottom: 100%;
1213
- }
1214
- .bottom-px {
1215
- bottom: 1px;
1216
- }
1217
916
  .z-1 {
1218
917
  z-index: 1;
1219
918
  }
1220
919
  .z-10 {
1221
920
  z-index: 10;
1222
921
  }
1223
- .z-\\[2147483647\\] {
1224
- z-index: 2147483647;
1225
- }
1226
922
  .container {
1227
923
  width: 100%;
1228
924
  @media (width >= 40rem) {
@@ -1256,12 +952,6 @@ var tailwind_built_default = `/*! tailwindcss v4.2.2 | MIT License | https://tai
1256
952
  .mt-1 {
1257
953
  margin-top: calc(var(--spacing) * 1);
1258
954
  }
1259
- .mb-2 {
1260
- margin-bottom: calc(var(--spacing) * 2);
1261
- }
1262
- .mb-6 {
1263
- margin-bottom: calc(var(--spacing) * 6);
1264
- }
1265
955
  .ml-auto {
1266
956
  margin-left: auto;
1267
957
  }
@@ -1280,19 +970,12 @@ var tailwind_built_default = `/*! tailwindcss v4.2.2 | MIT License | https://tai
1280
970
  .inline {
1281
971
  display: inline;
1282
972
  }
1283
- .inline-block {
1284
- display: inline-block;
1285
- }
1286
973
  .inline-flex {
1287
974
  display: inline-flex;
1288
975
  }
1289
976
  .table {
1290
977
  display: table;
1291
978
  }
1292
- .size-2 {
1293
- width: calc(var(--spacing) * 2);
1294
- height: calc(var(--spacing) * 2);
1295
- }
1296
979
  .size-3\\.5 {
1297
980
  width: calc(var(--spacing) * 3.5);
1298
981
  height: calc(var(--spacing) * 3.5);
@@ -1353,21 +1036,12 @@ var tailwind_built_default = `/*! tailwindcss v4.2.2 | MIT License | https://tai
1353
1036
  .h-full {
1354
1037
  height: 100%;
1355
1038
  }
1356
- .max-h-32 {
1357
- max-height: calc(var(--spacing) * 32);
1358
- }
1359
- .max-h-full {
1360
- max-height: 100%;
1361
- }
1362
1039
  .min-h-0 {
1363
1040
  min-height: calc(var(--spacing) * 0);
1364
1041
  }
1365
1042
  .min-h-8 {
1366
1043
  min-height: calc(var(--spacing) * 8);
1367
1044
  }
1368
- .min-h-20 {
1369
- min-height: calc(var(--spacing) * 20);
1370
- }
1371
1045
  .w-3\\.5 {
1372
1046
  width: calc(var(--spacing) * 3.5);
1373
1047
  }
@@ -1377,12 +1051,6 @@ var tailwind_built_default = `/*! tailwindcss v4.2.2 | MIT License | https://tai
1377
1051
  .w-12 {
1378
1052
  width: calc(var(--spacing) * 12);
1379
1053
  }
1380
- .w-20 {
1381
- width: calc(var(--spacing) * 20);
1382
- }
1383
- .w-36 {
1384
- width: calc(var(--spacing) * 36);
1385
- }
1386
1054
  .w-56 {
1387
1055
  width: calc(var(--spacing) * 56);
1388
1056
  }
@@ -1392,12 +1060,6 @@ var tailwind_built_default = `/*! tailwindcss v4.2.2 | MIT License | https://tai
1392
1060
  .w-px {
1393
1061
  width: 1px;
1394
1062
  }
1395
- .max-w-full {
1396
- max-width: 100%;
1397
- }
1398
- .max-w-sm {
1399
- max-width: var(--container-sm);
1400
- }
1401
1063
  .max-w-xl {
1402
1064
  max-width: var(--container-xl);
1403
1065
  }
@@ -1425,41 +1087,9 @@ var tailwind_built_default = `/*! tailwindcss v4.2.2 | MIT License | https://tai
1425
1087
  .shrink-0 {
1426
1088
  flex-shrink: 0;
1427
1089
  }
1428
- .origin-bottom-left {
1429
- transform-origin: 0 100%;
1430
- }
1431
- .origin-bottom-right {
1432
- transform-origin: 100% 100%;
1433
- }
1434
- .-translate-x-0\\.5 {
1435
- --tw-translate-x: calc(var(--spacing) * -0.5);
1436
- translate: var(--tw-translate-x) var(--tw-translate-y);
1437
- }
1438
- .translate-x-0\\.5 {
1439
- --tw-translate-x: calc(var(--spacing) * 0.5);
1440
- translate: var(--tw-translate-x) var(--tw-translate-y);
1441
- }
1442
- .scale-84 {
1443
- --tw-scale-x: 84%;
1444
- --tw-scale-y: 84%;
1445
- --tw-scale-z: 84%;
1446
- scale: var(--tw-scale-x) var(--tw-scale-y);
1447
- }
1448
- .-rotate-10 {
1449
- rotate: calc(10deg * -1);
1450
- }
1451
- .rotate-10 {
1452
- rotate: 10deg;
1453
- }
1454
1090
  .transform {
1455
1091
  transform: var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,);
1456
1092
  }
1457
- .animate-skeleton {
1458
- animation: skeleton 2s -1s infinite linear;
1459
- }
1460
- .animate-spin {
1461
- animation: var(--animate-spin);
1462
- }
1463
1093
  .cursor-pointer {
1464
1094
  cursor: pointer;
1465
1095
  }
@@ -1469,15 +1099,9 @@ var tailwind_built_default = `/*! tailwindcss v4.2.2 | MIT License | https://tai
1469
1099
  .scroll-py-2 {
1470
1100
  scroll-padding-block: calc(var(--spacing) * 2);
1471
1101
  }
1472
- .appearance-none {
1473
- appearance: none;
1474
- }
1475
1102
  .flex-col {
1476
1103
  flex-direction: column;
1477
1104
  }
1478
- .flex-row {
1479
- flex-direction: row;
1480
- }
1481
1105
  .items-center {
1482
1106
  align-items: center;
1483
1107
  }
@@ -1493,9 +1117,6 @@ var tailwind_built_default = `/*! tailwindcss v4.2.2 | MIT License | https://tai
1493
1117
  .gap-0 {
1494
1118
  gap: calc(var(--spacing) * 0);
1495
1119
  }
1496
- .gap-0\\.5 {
1497
- gap: calc(var(--spacing) * 0.5);
1498
- }
1499
1120
  .gap-1 {
1500
1121
  gap: calc(var(--spacing) * 1);
1501
1122
  }
@@ -1508,12 +1129,6 @@ var tailwind_built_default = `/*! tailwindcss v4.2.2 | MIT License | https://tai
1508
1129
  .gap-3 {
1509
1130
  gap: calc(var(--spacing) * 3);
1510
1131
  }
1511
- .gap-4 {
1512
- gap: calc(var(--spacing) * 4);
1513
- }
1514
- .gap-6 {
1515
- gap: calc(var(--spacing) * 6);
1516
- }
1517
1132
  .truncate {
1518
1133
  overflow: hidden;
1519
1134
  text-overflow: ellipsis;
@@ -1611,21 +1226,12 @@ var tailwind_built_default = `/*! tailwindcss v4.2.2 | MIT License | https://tai
1611
1226
  background-color: color-mix(in oklab, var(--color-black) 32%, transparent);
1612
1227
  }
1613
1228
  }
1614
- .bg-black\\/80 {
1615
- background-color: color-mix(in srgb, #000 80%, transparent);
1616
- @supports (color: color-mix(in lab, red, red)) {
1617
- background-color: color-mix(in oklab, var(--color-black) 80%, transparent);
1618
- }
1619
- }
1620
1229
  .bg-blue-50 {
1621
1230
  background-color: var(--color-blue-50);
1622
1231
  }
1623
1232
  .bg-border {
1624
1233
  background-color: var(--border);
1625
1234
  }
1626
- .bg-card {
1627
- background-color: var(--card);
1628
- }
1629
1235
  .bg-cyan-50 {
1630
1236
  background-color: var(--color-cyan-50);
1631
1237
  }
@@ -1641,15 +1247,9 @@ var tailwind_built_default = `/*! tailwindcss v4.2.2 | MIT License | https://tai
1641
1247
  .bg-emerald-50 {
1642
1248
  background-color: var(--color-emerald-50);
1643
1249
  }
1644
- .bg-emerald-500 {
1645
- background-color: var(--color-emerald-500);
1646
- }
1647
1250
  .bg-fuchsia-50 {
1648
1251
  background-color: var(--color-fuchsia-50);
1649
1252
  }
1650
- .bg-info {
1651
- background-color: var(--info);
1652
- }
1653
1253
  .bg-info\\/10 {
1654
1254
  background-color: var(--info);
1655
1255
  @supports (color: color-mix(in lab, red, red)) {
@@ -1701,18 +1301,6 @@ var tailwind_built_default = `/*! tailwindcss v4.2.2 | MIT License | https://tai
1701
1301
  .bg-clip-padding {
1702
1302
  background-clip: padding-box;
1703
1303
  }
1704
- .bg-\\[right_0\\.5rem_center\\] {
1705
- background-position: right 0.5rem center;
1706
- }
1707
- .bg-no-repeat {
1708
- background-repeat: no-repeat;
1709
- }
1710
- .object-cover {
1711
- object-fit: cover;
1712
- }
1713
- .object-top {
1714
- object-position: top;
1715
- }
1716
1304
  .p-1 {
1717
1305
  padding: calc(var(--spacing) * 1);
1718
1306
  }
@@ -1725,9 +1313,6 @@ var tailwind_built_default = `/*! tailwindcss v4.2.2 | MIT License | https://tai
1725
1313
  .p-4 {
1726
1314
  padding: calc(var(--spacing) * 4);
1727
1315
  }
1728
- .p-6 {
1729
- padding: calc(var(--spacing) * 6);
1730
- }
1731
1316
  .px-1 {
1732
1317
  padding-inline: calc(var(--spacing) * 1);
1733
1318
  }
@@ -1749,24 +1334,15 @@ var tailwind_built_default = `/*! tailwindcss v4.2.2 | MIT License | https://tai
1749
1334
  .px-4 {
1750
1335
  padding-inline: calc(var(--spacing) * 4);
1751
1336
  }
1752
- .px-6 {
1753
- padding-inline: calc(var(--spacing) * 6);
1754
- }
1755
1337
  .py-1 {
1756
1338
  padding-block: calc(var(--spacing) * 1);
1757
1339
  }
1758
1340
  .py-1\\.5 {
1759
1341
  padding-block: calc(var(--spacing) * 1.5);
1760
1342
  }
1761
- .py-2 {
1762
- padding-block: calc(var(--spacing) * 2);
1763
- }
1764
1343
  .py-4 {
1765
1344
  padding-block: calc(var(--spacing) * 4);
1766
1345
  }
1767
- .py-12 {
1768
- padding-block: calc(var(--spacing) * 12);
1769
- }
1770
1346
  .py-\\[max\\(1rem\\,4vh\\)\\] {
1771
1347
  padding-block: max(1rem, 4vh);
1772
1348
  }
@@ -1779,12 +1355,6 @@ var tailwind_built_default = `/*! tailwindcss v4.2.2 | MIT License | https://tai
1779
1355
  .pt-2 {
1780
1356
  padding-top: calc(var(--spacing) * 2);
1781
1357
  }
1782
- .pr-8 {
1783
- padding-right: calc(var(--spacing) * 8);
1784
- }
1785
- .pl-3 {
1786
- padding-left: calc(var(--spacing) * 3);
1787
- }
1788
1358
  .text-center {
1789
1359
  text-align: center;
1790
1360
  }
@@ -1802,18 +1372,10 @@ var tailwind_built_default = `/*! tailwindcss v4.2.2 | MIT License | https://tai
1802
1372
  font-size: var(--text-base);
1803
1373
  line-height: var(--tw-leading, var(--text-base--line-height));
1804
1374
  }
1805
- .text-base\\/4\\.5 {
1806
- font-size: var(--text-base);
1807
- line-height: calc(var(--spacing) * 4.5);
1808
- }
1809
1375
  .text-sm {
1810
1376
  font-size: var(--text-sm);
1811
1377
  line-height: var(--tw-leading, var(--text-sm--line-height));
1812
1378
  }
1813
- .text-xl {
1814
- font-size: var(--text-xl);
1815
- line-height: var(--tw-leading, var(--text-xl--line-height));
1816
- }
1817
1379
  .text-xs {
1818
1380
  font-size: var(--text-xs);
1819
1381
  line-height: var(--tw-leading, var(--text-xs--line-height));
@@ -1821,24 +1383,13 @@ var tailwind_built_default = `/*! tailwindcss v4.2.2 | MIT License | https://tai
1821
1383
  .text-\\[0\\.625rem\\] {
1822
1384
  font-size: 0.625rem;
1823
1385
  }
1824
- .text-\\[9px\\] {
1825
- font-size: 9px;
1826
- }
1827
1386
  .text-\\[11px\\] {
1828
1387
  font-size: 11px;
1829
1388
  }
1830
- .leading-none {
1831
- --tw-leading: 1;
1832
- line-height: 1;
1833
- }
1834
1389
  .leading-relaxed {
1835
1390
  --tw-leading: var(--leading-relaxed);
1836
1391
  line-height: var(--leading-relaxed);
1837
1392
  }
1838
- .font-bold {
1839
- --tw-font-weight: var(--font-weight-bold);
1840
- font-weight: var(--font-weight-bold);
1841
- }
1842
1393
  .font-medium {
1843
1394
  --tw-font-weight: var(--font-weight-medium);
1844
1395
  font-weight: var(--font-weight-medium);
@@ -1859,9 +1410,6 @@ var tailwind_built_default = `/*! tailwindcss v4.2.2 | MIT License | https://tai
1859
1410
  --tw-tracking: var(--tracking-widest);
1860
1411
  letter-spacing: var(--tracking-widest);
1861
1412
  }
1862
- .text-balance {
1863
- text-wrap: balance;
1864
- }
1865
1413
  .break-words {
1866
1414
  overflow-wrap: break-word;
1867
1415
  }
@@ -1886,9 +1434,6 @@ var tailwind_built_default = `/*! tailwindcss v4.2.2 | MIT License | https://tai
1886
1434
  .text-cyan-700 {
1887
1435
  color: var(--color-cyan-700);
1888
1436
  }
1889
- .text-destructive {
1890
- color: var(--destructive);
1891
- }
1892
1437
  .text-destructive-foreground {
1893
1438
  color: var(--destructive-foreground);
1894
1439
  }
@@ -1954,18 +1499,12 @@ var tailwind_built_default = `/*! tailwindcss v4.2.2 | MIT License | https://tai
1954
1499
  .line-through {
1955
1500
  text-decoration-line: line-through;
1956
1501
  }
1957
- .underline {
1958
- text-decoration-line: underline;
1959
- }
1960
1502
  .underline-offset-4 {
1961
1503
  text-underline-offset: 4px;
1962
1504
  }
1963
1505
  .accent-accent {
1964
1506
  accent-color: var(--accent);
1965
1507
  }
1966
- .accent-primary {
1967
- accent-color: var(--primary);
1968
- }
1969
1508
  .opacity-50 {
1970
1509
  opacity: 50%;
1971
1510
  }
@@ -1977,11 +1516,6 @@ var tailwind_built_default = `/*! tailwindcss v4.2.2 | MIT License | https://tai
1977
1516
  --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%));
1978
1517
  box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
1979
1518
  }
1980
- .shadow-sm\\/5 {
1981
- --tw-shadow-alpha: 5%;
1982
- --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%));
1983
- box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
1984
- }
1985
1519
  .shadow-xs\\/5 {
1986
1520
  --tw-shadow-alpha: 5%;
1987
1521
  --tw-shadow: 0 1px 2px 0 var(--tw-shadow-color, oklab(from rgb(0 0 0 / 0.05) l a b / 5%));
@@ -1991,14 +1525,6 @@ var tailwind_built_default = `/*! tailwindcss v4.2.2 | MIT License | https://tai
1991
1525
  --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));
1992
1526
  box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
1993
1527
  }
1994
- .shadow-lg {
1995
- --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));
1996
- box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
1997
- }
1998
- .shadow-none {
1999
- --tw-shadow: 0 0 #0000;
2000
- box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
2001
- }
2002
1528
  .shadow-xs {
2003
1529
  --tw-shadow: 0 1px 2px 0 var(--tw-shadow-color, rgb(0 0 0 / 0.05));
2004
1530
  box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
@@ -2098,15 +1624,6 @@ var tailwind_built_default = `/*! tailwindcss v4.2.2 | MIT License | https://tai
2098
1624
  -webkit-user-select: none;
2099
1625
  user-select: none;
2100
1626
  }
2101
- .\\[--skeleton-highlight\\:--alpha\\(var\\(--color-white\\)\\/64\\%\\)\\] {
2102
- --skeleton-highlight: color-mix(in srgb, #fff 64%, transparent);
2103
- @supports (color: color-mix(in lab, red, red)) {
2104
- --skeleton-highlight: color-mix(in oklab, var(--color-white) 64%, transparent);
2105
- }
2106
- }
2107
- .\\[background\\:linear-gradient\\(120deg\\,transparent_40\\%\\,var\\(--skeleton-highlight\\)\\,transparent_60\\%\\)_var\\(--color-muted\\)_0_0\\/200\\%_100\\%_fixed\\] {
2108
- background: linear-gradient(120deg,transparent 40%,var(--skeleton-highlight),transparent 60%) var(--color-muted) 0 0/200% 100% fixed;
2109
- }
2110
1627
  .\\[clip-path\\:inset\\(0_1px\\)\\] {
2111
1628
  clip-path: inset(0 1px);
2112
1629
  }
@@ -2190,12 +1707,6 @@ var tailwind_built_default = `/*! tailwindcss v4.2.2 | MIT License | https://tai
2190
1707
  border-radius: calc(var(--radius-lg) - 1px);
2191
1708
  }
2192
1709
  }
2193
- .before\\:rounded-\\[calc\\(var\\(--radius-md\\)-1px\\)\\] {
2194
- &::before {
2195
- content: var(--tw-content);
2196
- border-radius: calc(var(--radius-md) - 1px);
2197
- }
2198
- }
2199
1710
  .before\\:rounded-\\[calc\\(var\\(--radius-xl\\)-1px\\)\\] {
2200
1711
  &::before {
2201
1712
  content: var(--tw-content);
@@ -2325,36 +1836,17 @@ var tailwind_built_default = `/*! tailwindcss v4.2.2 | MIT License | https://tai
2325
1836
  outline-style: none;
2326
1837
  }
2327
1838
  }
2328
- .focus-visible\\:border-ring {
2329
- &:focus-visible {
2330
- border-color: var(--ring);
2331
- }
2332
- }
2333
1839
  .focus-visible\\:ring-2 {
2334
1840
  &:focus-visible {
2335
1841
  --tw-ring-shadow: var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color, currentcolor);
2336
1842
  box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
2337
1843
  }
2338
1844
  }
2339
- .focus-visible\\:ring-\\[3px\\] {
2340
- &:focus-visible {
2341
- --tw-ring-shadow: var(--tw-ring-inset,) 0 0 0 calc(3px + var(--tw-ring-offset-width)) var(--tw-ring-color, currentcolor);
2342
- box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
2343
- }
2344
- }
2345
1845
  .focus-visible\\:ring-ring {
2346
1846
  &:focus-visible {
2347
1847
  --tw-ring-color: var(--ring);
2348
1848
  }
2349
1849
  }
2350
- .focus-visible\\:ring-ring\\/30 {
2351
- &:focus-visible {
2352
- --tw-ring-color: var(--ring);
2353
- @supports (color: color-mix(in lab, red, red)) {
2354
- --tw-ring-color: color-mix(in oklab, var(--ring) 30%, transparent);
2355
- }
2356
- }
2357
- }
2358
1850
  .focus-visible\\:ring-offset-1 {
2359
1851
  &:focus-visible {
2360
1852
  --tw-ring-offset-width: 1px;
@@ -2381,24 +1873,6 @@ var tailwind_built_default = `/*! tailwindcss v4.2.2 | MIT License | https://tai
2381
1873
  opacity: 60%;
2382
1874
  }
2383
1875
  }
2384
- .aria-invalid\\:border-destructive\\/40 {
2385
- &[aria-invalid="true"] {
2386
- border-color: var(--destructive);
2387
- @supports (color: color-mix(in lab, red, red)) {
2388
- border-color: color-mix(in oklab, var(--destructive) 40%, transparent);
2389
- }
2390
- }
2391
- }
2392
- .aria-invalid\\:focus-visible\\:ring-destructive\\/20 {
2393
- &[aria-invalid="true"] {
2394
- &:focus-visible {
2395
- --tw-ring-color: var(--destructive);
2396
- @supports (color: color-mix(in lab, red, red)) {
2397
- --tw-ring-color: color-mix(in oklab, var(--destructive) 20%, transparent);
2398
- }
2399
- }
2400
- }
2401
- }
2402
1876
  .data-\\[disabled\\]\\:pointer-events-none {
2403
1877
  &[data-disabled] {
2404
1878
  pointer-events: none;
@@ -2435,12 +1909,6 @@ var tailwind_built_default = `/*! tailwindcss v4.2.2 | MIT License | https://tai
2435
1909
  line-height: var(--tw-leading, var(--text-sm--line-height));
2436
1910
  }
2437
1911
  }
2438
- .sm\\:text-sm\\/4 {
2439
- @media (width >= 40rem) {
2440
- font-size: var(--text-sm);
2441
- line-height: calc(var(--spacing) * 4);
2442
- }
2443
- }
2444
1912
  .dark\\:bg-amber-400\\/10 {
2445
1913
  &:is(.dark *, :host(.dark) *) {
2446
1914
  background-color: color-mix(in srgb, oklch(82.8% 0.189 84.429) 10%, transparent);
@@ -2654,14 +2122,6 @@ var tailwind_built_default = `/*! tailwindcss v4.2.2 | MIT License | https://tai
2654
2122
  }
2655
2123
  }
2656
2124
  }
2657
- .dark\\:\\[--skeleton-highlight\\:--alpha\\(var\\(--color-white\\)\\/4\\%\\)\\] {
2658
- &:is(.dark *, :host(.dark) *) {
2659
- --skeleton-highlight: color-mix(in srgb, #fff 4%, transparent);
2660
- @supports (color: color-mix(in lab, red, red)) {
2661
- --skeleton-highlight: color-mix(in oklab, var(--color-white) 4%, transparent);
2662
- }
2663
- }
2664
- }
2665
2125
  .dark\\:group-data-hover\\:bg-amber-400\\/20 {
2666
2126
  &:is(.dark *, :host(.dark) *) {
2667
2127
  &:is(:where(.group)[data-hover] *) {
@@ -2781,12 +2241,6 @@ var tailwind_built_default = `/*! tailwindcss v4.2.2 | MIT License | https://tai
2781
2241
  height: calc(var(--spacing) * 4);
2782
2242
  }
2783
2243
  }
2784
- .\\[\\&_svg\\:not\\(\\[class\\*\\=\\'size-\\'\\]\\)\\]\\:size-4\\.5 {
2785
- & svg:not([class*='size-']) {
2786
- width: calc(var(--spacing) * 4.5);
2787
- height: calc(var(--spacing) * 4.5);
2788
- }
2789
- }
2790
2244
  .\\[\\[data-kbd-nav\\]_\\&\\]\\:focus-within\\:bg-accent {
2791
2245
  [data-kbd-nav] & {
2792
2246
  &:focus-within {
@@ -3019,36 +2473,6 @@ var tailwind_built_default = `/*! tailwindcss v4.2.2 | MIT License | https://tai
3019
2473
  --warning: var(--color-amber-500);
3020
2474
  --warning-foreground: var(--color-amber-700);
3021
2475
  }
3022
- @property --tw-translate-x {
3023
- syntax: "*";
3024
- inherits: false;
3025
- initial-value: 0;
3026
- }
3027
- @property --tw-translate-y {
3028
- syntax: "*";
3029
- inherits: false;
3030
- initial-value: 0;
3031
- }
3032
- @property --tw-translate-z {
3033
- syntax: "*";
3034
- inherits: false;
3035
- initial-value: 0;
3036
- }
3037
- @property --tw-scale-x {
3038
- syntax: "*";
3039
- inherits: false;
3040
- initial-value: 1;
3041
- }
3042
- @property --tw-scale-y {
3043
- syntax: "*";
3044
- inherits: false;
3045
- initial-value: 1;
3046
- }
3047
- @property --tw-scale-z {
3048
- syntax: "*";
3049
- inherits: false;
3050
- initial-value: 1;
3051
- }
3052
2476
  @property --tw-rotate-x {
3053
2477
  syntax: "*";
3054
2478
  inherits: false;
@@ -3274,20 +2698,9 @@ var tailwind_built_default = `/*! tailwindcss v4.2.2 | MIT License | https://tai
3274
2698
  initial-value: "";
3275
2699
  inherits: false;
3276
2700
  }
3277
- @keyframes spin {
3278
- to {
3279
- transform: rotate(360deg);
3280
- }
3281
- }
3282
2701
  @layer properties {
3283
2702
  @supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))) {
3284
2703
  *, ::before, ::after, ::backdrop {
3285
- --tw-translate-x: 0;
3286
- --tw-translate-y: 0;
3287
- --tw-translate-z: 0;
3288
- --tw-scale-x: 1;
3289
- --tw-scale-y: 1;
3290
- --tw-scale-z: 1;
3291
2704
  --tw-rotate-x: initial;
3292
2705
  --tw-rotate-y: initial;
3293
2706
  --tw-rotate-z: initial;
@@ -3350,7 +2763,6 @@ var tailwind_built_default = `/*! tailwindcss v4.2.2 | MIT License | https://tai
3350
2763
  var SURFACE_HOST_CLASS = "uidex-surface-host";
3351
2764
  var Z_BASE = 2147483630;
3352
2765
  var Z_OVERLAY = 2147483635;
3353
- var Z_PIN_LAYER = 2147483640;
3354
2766
  var Z_CHROME = 2147483645;
3355
2767
  var SURFACE_IGNORE_SELECTOR = `.${SURFACE_HOST_CLASS}`;
3356
2768
  var UIDEX_ATTR_TO_KIND = [
@@ -3749,7 +3161,6 @@ function el(tag, options = {}, children = []) {
3749
3161
  var DEFAULT_SHORTCUT = { key: "k" };
3750
3162
  var ACTIONS_SHORTCUT = { key: "j" };
3751
3163
  var INSPECT_SHORTCUT = { key: "i" };
3752
- var PINS_SHORTCUT = { key: "u" };
3753
3164
  function formatShortcutLabel(shortcut) {
3754
3165
  const parts = [];
3755
3166
  if (shortcut.mod !== false) parts.push("\u2318");
@@ -3764,19 +3175,17 @@ function matchesShortcut(e, shortcut) {
3764
3175
  return hasMod === wantMod && e.shiftKey === wantShift && !e.altKey && e.key.toLowerCase() === shortcut.key.toLowerCase();
3765
3176
  }
3766
3177
  function bindShadowKeys(options) {
3767
- const { shadowRoot, session, getActionsPopup, getPinLayer } = options;
3178
+ const { shadowRoot, session, getActionsPopup } = options;
3768
3179
  const shortcut = options.shortcut ?? DEFAULT_SHORTCUT;
3769
- const escapeStack = [];
3770
3180
  const onKeydown = (e) => {
3771
3181
  const isMod = e.metaKey || e.ctrlKey;
3772
3182
  const isCmdK = matchesShortcut(e, shortcut);
3773
3183
  const isCmdDot = matchesShortcut(e, ACTIONS_SHORTCUT);
3774
3184
  const isCmdI = matchesShortcut(e, INSPECT_SHORTCUT);
3775
- const isCmdU = matchesShortcut(e, PINS_SHORTCUT);
3776
3185
  const isCmdBracket = isMod && !e.altKey && !e.shiftKey && e.key === "[";
3777
3186
  const isEsc = e.key === "Escape";
3778
3187
  const isPopKey = isEsc || isCmdBracket;
3779
- if (!isCmdK && !isCmdDot && !isCmdI && !isCmdU && !isPopKey) return;
3188
+ if (!isCmdK && !isCmdDot && !isCmdI && !isPopKey) return;
3780
3189
  const popup = getActionsPopup();
3781
3190
  if (popup?.isOpen()) {
3782
3191
  if (isPopKey || isCmdK || isCmdDot) {
@@ -3794,15 +3203,6 @@ function bindShadowKeys(options) {
3794
3203
  }
3795
3204
  return;
3796
3205
  }
3797
- if (isCmdU) {
3798
- const pinLayer = getPinLayer?.();
3799
- if (pinLayer) {
3800
- e.preventDefault();
3801
- e.stopPropagation();
3802
- pinLayer.setVisible(!pinLayer.visible);
3803
- }
3804
- return;
3805
- }
3806
3206
  if (isCmdI) {
3807
3207
  e.preventDefault();
3808
3208
  e.stopPropagation();
@@ -3824,14 +3224,6 @@ function bindShadowKeys(options) {
3824
3224
  }
3825
3225
  return;
3826
3226
  }
3827
- if (escapeStack.length > 0) {
3828
- const top = escapeStack[escapeStack.length - 1];
3829
- if (top()) {
3830
- e.preventDefault();
3831
- e.stopPropagation();
3832
- return;
3833
- }
3834
- }
3835
3227
  const { mode } = session.mode.getState();
3836
3228
  if (mode === "viewing") {
3837
3229
  e.preventDefault();
@@ -3866,13 +3258,6 @@ function bindShadowKeys(options) {
3866
3258
  capture: true
3867
3259
  }
3868
3260
  );
3869
- },
3870
- pushEscapeLayer(handler) {
3871
- escapeStack.push(handler);
3872
- return () => {
3873
- const idx = escapeStack.indexOf(handler);
3874
- if (idx >= 0) escapeStack.splice(idx, 1);
3875
- };
3876
3261
  }
3877
3262
  };
3878
3263
  }
@@ -3888,11 +3273,8 @@ function createMenuBar(options) {
3888
3273
  container,
3889
3274
  session,
3890
3275
  initialCorner = "bottom-right",
3891
- appTitle,
3892
- channel = null,
3893
- pinLayer: initialPinLayer = null
3276
+ appTitle
3894
3277
  } = options;
3895
- let activePinLayer = initialPinLayer;
3896
3278
  const root = el("div", {
3897
3279
  class: ROOT_CLASS,
3898
3280
  attrs: {
@@ -3957,108 +3339,6 @@ function createMenuBar(options) {
3957
3339
  inspectBtn.blur();
3958
3340
  });
3959
3341
  root.appendChild(inspectBtn);
3960
- const pinIcon = (0, import_lucide3.createElement)(import_lucide3.MapPin);
3961
- pinIcon.setAttribute("class", "size-3.5");
3962
- pinIcon.setAttribute("aria-hidden", "true");
3963
- const pinBtn = el(
3964
- "button",
3965
- {
3966
- class: BUTTON_CLASS,
3967
- attrs: {
3968
- type: "button",
3969
- "data-uidex-menubar-pins": "",
3970
- "aria-label": "Report pins"
3971
- }
3972
- },
3973
- pinIcon
3974
- );
3975
- const pinWrapper = el("div", {
3976
- class: "relative z-1 inline-flex items-center gap-0.5",
3977
- attrs: { "data-uidex-menubar-pin-wrapper": "" }
3978
- });
3979
- pinWrapper.hidden = true;
3980
- pinWrapper.appendChild(pinBtn);
3981
- root.appendChild(pinWrapper);
3982
- const updatePinUI = () => {
3983
- if (!activePinLayer) {
3984
- pinWrapper.hidden = true;
3985
- return;
3986
- }
3987
- const pinsVisible = activePinLayer.visible;
3988
- pinWrapper.hidden = false;
3989
- pinBtn.className = cn(BUTTON_CLASS, pinsVisible && BUTTON_ACTIVE_CLASS);
3990
- };
3991
- pinBtn.addEventListener("click", (e) => {
3992
- e.stopPropagation();
3993
- if (activePinLayer) {
3994
- activePinLayer.setVisible(!activePinLayer.visible);
3995
- }
3996
- });
3997
- let unsubscribePinFilter = activePinLayer?.onFilterChange(() => updatePinUI());
3998
- const presenceIcon = (0, import_lucide3.createElement)(import_lucide3.Users);
3999
- presenceIcon.setAttribute("class", "size-3.5");
4000
- presenceIcon.setAttribute("aria-hidden", "true");
4001
- const presenceBtn = el(
4002
- "button",
4003
- {
4004
- class: BUTTON_CLASS,
4005
- attrs: {
4006
- type: "button",
4007
- "data-uidex-menubar-presence": "",
4008
- "aria-label": "Online users"
4009
- }
4010
- },
4011
- presenceIcon
4012
- );
4013
- presenceBtn.hidden = true;
4014
- const presenceBadge = el("span", {
4015
- 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"
4016
- });
4017
- presenceBtn.appendChild(presenceBadge);
4018
- const presencePopover = el("div", {
4019
- 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"
4020
- });
4021
- presencePopover.hidden = true;
4022
- let presencePopoverVisible = false;
4023
- presenceBtn.addEventListener("click", (e) => {
4024
- e.stopPropagation();
4025
- presencePopoverVisible = !presencePopoverVisible;
4026
- presencePopover.hidden = !presencePopoverVisible;
4027
- });
4028
- const presenceWrapper = el("div", { class: "relative z-1 inline-flex" }, [
4029
- presenceBtn,
4030
- presencePopover
4031
- ]);
4032
- presenceWrapper.hidden = true;
4033
- root.appendChild(presenceWrapper);
4034
- let presenceUsers = [];
4035
- const updatePresenceUI = () => {
4036
- const localUserId = session.getState().user?.id ?? null;
4037
- const peers = localUserId ? presenceUsers.filter((u) => u.userId !== localUserId) : presenceUsers;
4038
- const count = peers.length;
4039
- presenceWrapper.hidden = count === 0;
4040
- presenceBadge.textContent = String(count);
4041
- presenceBtn.setAttribute(
4042
- "aria-label",
4043
- count === 1 ? "1 other user online" : `${count} other users online`
4044
- );
4045
- presencePopover.innerHTML = "";
4046
- for (const user of peers) {
4047
- const row = el("div", {
4048
- class: "flex items-center gap-2 rounded px-1.5 py-1"
4049
- });
4050
- const dot = el("span", {
4051
- class: "inline-block size-2 shrink-0 rounded-full bg-emerald-500"
4052
- });
4053
- const name = el("span", {
4054
- class: "truncate",
4055
- text: user.name || "Anonymous"
4056
- });
4057
- row.appendChild(dot);
4058
- row.appendChild(name);
4059
- presencePopover.appendChild(row);
4060
- }
4061
- };
4062
3342
  const paletteIcon = (0, import_lucide3.createElement)(import_lucide3.Command);
4063
3343
  paletteIcon.setAttribute("class", "size-3.5");
4064
3344
  paletteIcon.setAttribute("aria-hidden", "true");
@@ -4173,28 +3453,14 @@ function createMenuBar(options) {
4173
3453
  const vertical = y / (window.innerHeight || 1) < 0.5 ? "top" : "bottom";
4174
3454
  snapTo(`${vertical}-${horizontal}`);
4175
3455
  }
4176
- const unsubscribePresence = channel?.onPresence(
4177
- (users) => {
4178
- presenceUsers = users;
4179
- updatePresenceUI();
4180
- }
4181
- );
4182
3456
  return {
4183
3457
  destroy() {
4184
- unsubscribePinFilter?.();
4185
- unsubscribePresence?.();
4186
3458
  unsubscribeSession();
4187
3459
  root.removeEventListener("mousedown", onMouseDown);
4188
3460
  document.removeEventListener("mousemove", onMouseMove);
4189
3461
  document.removeEventListener("mouseup", onMouseUp);
4190
3462
  root.remove();
4191
3463
  },
4192
- setPinLayer(layer) {
4193
- unsubscribePinFilter?.();
4194
- activePinLayer = layer;
4195
- unsubscribePinFilter = layer.onFilterChange(() => updatePinUI());
4196
- updatePinUI();
4197
- },
4198
3464
  snapTo,
4199
3465
  snapToNearest,
4200
3466
  get corner() {
@@ -4552,9 +3818,7 @@ function createSurfaceShell(options) {
4552
3818
  container: host.chromeEl,
4553
3819
  session: options.session,
4554
3820
  initialCorner: options.initialCorner,
4555
- appTitle: options.appTitle,
4556
- channel: options.channel ?? null,
4557
- pinLayer: options.pinLayer ?? null
3821
+ appTitle: options.appTitle
4558
3822
  });
4559
3823
  cleanup.add(menuBar);
4560
3824
  return {
@@ -4569,539 +3833,6 @@ function createSurfaceShell(options) {
4569
3833
  };
4570
3834
  }
4571
3835
 
4572
- // src/browser/report/constants.ts
4573
- var TYPE_LABELS = {
4574
- bug: "Bug",
4575
- request: "Request",
4576
- suggestion: "Suggestion"
4577
- };
4578
- var SEVERITY_LABELS = {
4579
- critical: "Critical",
4580
- high: "High",
4581
- medium: "Medium",
4582
- low: "Low"
4583
- };
4584
- function authorLabel(rec) {
4585
- const name = rec.reporter?.name ?? rec.reporterName;
4586
- const email = rec.reporter?.email ?? rec.reporterEmail;
4587
- return name?.trim() || email?.trim() || "Anonymous";
4588
- }
4589
- function relativeTime(iso) {
4590
- const ms = Date.parse(iso);
4591
- if (!Number.isFinite(ms)) return "";
4592
- const s = Math.floor((Date.now() - ms) / 1e3);
4593
- if (s < 60) return "just now";
4594
- const m = Math.floor(s / 60);
4595
- if (m < 60) return `${m}m ago`;
4596
- const h = Math.floor(m / 60);
4597
- if (h < 24) return `${h}h ago`;
4598
- const d = Math.floor(h / 24);
4599
- if (d < 30) return `${d}d ago`;
4600
- return `${Math.floor(d / 30)}mo ago`;
4601
- }
4602
-
4603
- // src/browser/surface/pin-layer.ts
4604
- var import_lucide4 = require("lucide");
4605
- var KNOWN_KINDS = new Set(UIDEX_ATTR_TO_KIND.map(([, k]) => k));
4606
- function parseComponentRef(componentId) {
4607
- const colon = componentId.indexOf(":");
4608
- if (colon > 0) {
4609
- const maybeKind = componentId.slice(0, colon);
4610
- if (KNOWN_KINDS.has(maybeKind)) {
4611
- return { kind: maybeKind, id: componentId.slice(colon + 1) };
4612
- }
4613
- }
4614
- return { kind: "element", id: componentId };
4615
- }
4616
- var DOT = 28;
4617
- var BORDER = 2;
4618
- var ICON = 16;
4619
- var PAD = 10;
4620
- var CARD_W = 280;
4621
- var LINE_H = 17;
4622
- var HEADER_H = 16;
4623
- var BODY_MT = 2;
4624
- var CYCLE_H = 18;
4625
- var CARD_H = PAD + HEADER_H + BODY_MT + LINE_H * 2 + CYCLE_H + PAD;
4626
- var INSET = 4;
4627
- var TYPE_ICON = {
4628
- bug: import_lucide4.Bug,
4629
- request: import_lucide4.MessageSquarePlus,
4630
- suggestion: import_lucide4.Lightbulb,
4631
- feature: import_lucide4.Lightbulb,
4632
- improvement: import_lucide4.Sparkles,
4633
- question: import_lucide4.CircleHelp,
4634
- note: import_lucide4.StickyNote
4635
- };
4636
- var TYPE_COLOR = {
4637
- bug: {
4638
- bg: "color-mix(in srgb, var(--destructive) 10%, var(--background))",
4639
- fg: "var(--destructive-foreground)"
4640
- },
4641
- request: {
4642
- bg: "color-mix(in srgb, var(--info) 10%, var(--background))",
4643
- fg: "var(--info-foreground)"
4644
- },
4645
- suggestion: {
4646
- bg: "color-mix(in srgb, var(--warning) 10%, var(--background))",
4647
- fg: "var(--warning-foreground)"
4648
- },
4649
- feature: { bg: "var(--secondary)", fg: "var(--secondary-foreground)" },
4650
- improvement: {
4651
- bg: "color-mix(in srgb, var(--info) 10%, var(--background))",
4652
- fg: "var(--info-foreground)"
4653
- },
4654
- question: {
4655
- bg: "color-mix(in srgb, var(--warning) 10%, var(--background))",
4656
- fg: "var(--warning-foreground)"
4657
- },
4658
- note: {
4659
- bg: "color-mix(in srgb, var(--primary) 10%, var(--background))",
4660
- fg: "var(--primary)"
4661
- }
4662
- };
4663
- var FALLBACK_COLOR = {
4664
- bg: "var(--secondary)",
4665
- fg: "var(--secondary-foreground)"
4666
- };
4667
- function typeColors(t) {
4668
- return TYPE_COLOR[t] ?? FALLBACK_COLOR;
4669
- }
4670
- function typeIcon(t) {
4671
- return TYPE_ICON[t] ?? import_lucide4.StickyNote;
4672
- }
4673
- var EASE_OUT = "cubic-bezier(0.16, 1, 0.3, 1)";
4674
- var DUR_FADE = 120;
4675
- var DUR_EXPAND = 250;
4676
- var T_FADE = `opacity ${DUR_FADE}ms ease`;
4677
- function createPinLayer(options) {
4678
- const { container, onOpenPinDetail, onHoverPin, onPinsChanged } = options;
4679
- const layerEl = document.createElement("div");
4680
- layerEl.setAttribute("data-uidex-pin-layer", "");
4681
- Object.assign(layerEl.style, {
4682
- position: "fixed",
4683
- inset: "0",
4684
- zIndex: String(Z_PIN_LAYER),
4685
- pointerEvents: "none"
4686
- });
4687
- container.appendChild(layerEl);
4688
- let layerVisible = true;
4689
- const allPins = [];
4690
- const seenIds = /* @__PURE__ */ new Set();
4691
- const byComp = /* @__PURE__ */ new Map();
4692
- const indicators = /* @__PURE__ */ new Map();
4693
- const filterCbs = /* @__PURE__ */ new Set();
4694
- const notifyFilter = () => {
4695
- for (const cb of filterCbs) cb();
4696
- };
4697
- const rebuildFiltered = () => {
4698
- byComp.clear();
4699
- for (const p of allPins) {
4700
- const cid = p.entity ?? "";
4701
- const list = byComp.get(cid);
4702
- if (list) list.push(p);
4703
- else byComp.set(cid, [p]);
4704
- }
4705
- };
4706
- const rerender = () => {
4707
- rebuildFiltered();
4708
- for (const id of Array.from(indicators.keys())) {
4709
- if (!byComp.has(id)) removeIndicator(id);
4710
- }
4711
- for (const id of byComp.keys()) renderIndicator(id);
4712
- notifyFilter();
4713
- onPinsChanged?.();
4714
- };
4715
- let obs = null;
4716
- const repositioner = createRepositioner(() => posAll());
4717
- const attachObs = () => {
4718
- if (obs || typeof MutationObserver === "undefined") return;
4719
- obs = new MutationObserver((recs) => {
4720
- for (const r of recs) {
4721
- if (r.type === "childList" && (r.addedNodes.length || r.removedNodes.length)) {
4722
- refreshAnchors();
4723
- return;
4724
- }
4725
- }
4726
- });
4727
- obs.observe(document.body, { childList: true, subtree: true });
4728
- };
4729
- const detachObs = () => {
4730
- obs?.disconnect();
4731
- obs = null;
4732
- };
4733
- const refreshAnchors = () => {
4734
- let changed = false;
4735
- for (const s of indicators.values()) {
4736
- if (s.anchor && s.anchor.isConnected) continue;
4737
- s.anchor = resolveEntityElement(parseComponentRef(s.componentId));
4738
- changed = true;
4739
- }
4740
- if (changed) repositioner.schedule();
4741
- };
4742
- const expand = (st) => {
4743
- if (st.expanded) return;
4744
- st.expanded = true;
4745
- fillContent(st);
4746
- st.wrap.style.zIndex = "1";
4747
- st.iconEl.style.transition = T_FADE;
4748
- st.iconEl.style.opacity = "0";
4749
- st.badgeEl.style.visibility = "hidden";
4750
- st.el.style.transition = `width ${DUR_EXPAND}ms ${EASE_OUT} ${DUR_FADE}ms, height ${DUR_EXPAND}ms ${EASE_OUT} ${DUR_FADE}ms`;
4751
- st.el.style.width = `${CARD_W}px`;
4752
- st.el.style.height = `${CARD_H}px`;
4753
- st.contentEl.style.transition = `opacity ${DUR_FADE}ms ease ${DUR_FADE + DUR_EXPAND}ms`;
4754
- st.contentEl.style.opacity = "1";
4755
- if (st.anchor) onHoverPin?.(st.anchor, st.componentId);
4756
- };
4757
- const collapse = (st) => {
4758
- if (!st.expanded) return;
4759
- st.expanded = false;
4760
- st.contentEl.style.transition = T_FADE;
4761
- st.contentEl.style.opacity = "0";
4762
- st.el.style.transition = `width ${DUR_EXPAND}ms ${EASE_OUT} ${DUR_FADE}ms, height ${DUR_EXPAND}ms ${EASE_OUT} ${DUR_FADE}ms`;
4763
- st.el.style.width = `${DOT}px`;
4764
- st.el.style.height = `${DOT}px`;
4765
- st.iconEl.style.transition = `opacity ${DUR_FADE}ms ease ${DUR_FADE + DUR_EXPAND}ms`;
4766
- st.iconEl.style.opacity = "1";
4767
- st.badgeEl.style.visibility = "";
4768
- st.iconEl.addEventListener(
4769
- "transitionend",
4770
- () => {
4771
- if (!st.expanded) st.wrap.style.zIndex = "";
4772
- },
4773
- { once: true }
4774
- );
4775
- onHoverPin?.(null, null);
4776
- };
4777
- const fillContent = (st) => {
4778
- const pins = byComp.get(st.componentId);
4779
- if (!pins?.length) return;
4780
- const idx = Math.max(0, Math.min(st.pinIndex, pins.length - 1));
4781
- st.pinIndex = idx;
4782
- const pin = pins[idx];
4783
- st.contentEl.innerHTML = "";
4784
- const hdr = document.createElement("div");
4785
- hdr.style.display = "flex";
4786
- hdr.style.alignItems = "baseline";
4787
- hdr.style.gap = "6px";
4788
- const nm = document.createElement("span");
4789
- nm.style.fontWeight = "600";
4790
- nm.style.fontSize = "12px";
4791
- nm.textContent = authorLabel(pin);
4792
- hdr.appendChild(nm);
4793
- const tm = document.createElement("span");
4794
- tm.style.fontSize = "11px";
4795
- tm.style.opacity = "0.75";
4796
- tm.textContent = relativeTime(pin.createdAt);
4797
- hdr.appendChild(tm);
4798
- st.contentEl.appendChild(hdr);
4799
- const body = document.createElement("div");
4800
- Object.assign(body.style, {
4801
- fontSize: "12px",
4802
- lineHeight: "1.4",
4803
- marginTop: "2px",
4804
- whiteSpace: "pre-wrap",
4805
- overflow: "hidden",
4806
- display: "-webkit-box"
4807
- });
4808
- body.style.setProperty("-webkit-line-clamp", "2");
4809
- body.style.setProperty("-webkit-box-orient", "vertical");
4810
- body.textContent = pin.body;
4811
- st.contentEl.appendChild(body);
4812
- const ctr = document.createElement("div");
4813
- Object.assign(ctr.style, {
4814
- fontSize: "10px",
4815
- opacity: "0.5",
4816
- marginTop: "4px"
4817
- });
4818
- ctr.textContent = pins.length > 1 ? `${idx + 1} of ${pins.length} \xB7 right-click to cycle` : "click to open";
4819
- st.contentEl.appendChild(ctr);
4820
- };
4821
- const buildIndicator = (componentId) => {
4822
- const wrap = document.createElement("div");
4823
- wrap.setAttribute("data-uidex-pin-wrap", "");
4824
- Object.assign(wrap.style, {
4825
- position: "fixed",
4826
- display: "none",
4827
- pointerEvents: "none"
4828
- });
4829
- const el2 = document.createElement("button");
4830
- el2.type = "button";
4831
- el2.setAttribute("data-uidex-pin", "");
4832
- el2.setAttribute("data-uidex-pin-component", componentId);
4833
- el2.setAttribute("aria-label", `Open report for ${componentId}`);
4834
- Object.assign(el2.style, {
4835
- position: "relative",
4836
- width: `${DOT}px`,
4837
- height: `${DOT}px`,
4838
- borderRadius: `${DOT / 2}px`,
4839
- border: `${BORDER}px solid var(--background)`,
4840
- padding: "0",
4841
- margin: "0",
4842
- cursor: "pointer",
4843
- pointerEvents: "auto",
4844
- overflow: "hidden",
4845
- boxShadow: "0 2px 8px rgba(0,0,0,0.15), 0 0 0 1px rgba(0,0,0,0.05)",
4846
- fontFamily: "var(--font-sans)",
4847
- textAlign: "left",
4848
- float: "right"
4849
- });
4850
- wrap.appendChild(el2);
4851
- const iconEl = document.createElement("span");
4852
- iconEl.setAttribute("data-uidex-pin-icon", "");
4853
- Object.assign(iconEl.style, {
4854
- position: "absolute",
4855
- inset: "0",
4856
- display: "flex",
4857
- alignItems: "center",
4858
- justifyContent: "center"
4859
- });
4860
- el2.appendChild(iconEl);
4861
- const badgeEl = document.createElement("span");
4862
- badgeEl.setAttribute("data-uidex-pin-badge", "");
4863
- Object.assign(badgeEl.style, {
4864
- position: "absolute",
4865
- top: "-4px",
4866
- right: "-4px",
4867
- minWidth: "14px",
4868
- height: "14px",
4869
- borderRadius: "999px",
4870
- background: "var(--foreground)",
4871
- color: "var(--background)",
4872
- fontSize: "9px",
4873
- fontWeight: "600",
4874
- display: "none",
4875
- alignItems: "center",
4876
- justifyContent: "center",
4877
- padding: "0 3px",
4878
- lineHeight: "1",
4879
- zIndex: "2",
4880
- pointerEvents: "none"
4881
- });
4882
- wrap.appendChild(badgeEl);
4883
- const contentEl = document.createElement("div");
4884
- contentEl.setAttribute("data-uidex-pin-content", "");
4885
- Object.assign(contentEl.style, {
4886
- position: "absolute",
4887
- top: `${PAD}px`,
4888
- left: `${PAD}px`,
4889
- right: `${PAD}px`,
4890
- opacity: "0",
4891
- minWidth: "0"
4892
- });
4893
- el2.appendChild(contentEl);
4894
- const st = {
4895
- componentId,
4896
- wrap,
4897
- el: el2,
4898
- iconEl,
4899
- badgeEl,
4900
- contentEl,
4901
- anchor: null,
4902
- pinIndex: 0,
4903
- expanded: false,
4904
- lastType: null
4905
- };
4906
- el2.addEventListener("mouseenter", () => expand(st));
4907
- el2.addEventListener("mouseleave", () => collapse(st));
4908
- el2.addEventListener("click", (e) => {
4909
- e.stopPropagation();
4910
- e.preventDefault();
4911
- const pins = byComp.get(componentId);
4912
- const pin = pins?.[st.pinIndex];
4913
- if (pin) onOpenPinDetail?.(componentId, pin.id);
4914
- });
4915
- el2.addEventListener("contextmenu", (e) => {
4916
- e.stopPropagation();
4917
- e.preventDefault();
4918
- const pins = byComp.get(componentId);
4919
- if (!pins || pins.length <= 1) return;
4920
- st.pinIndex = (st.pinIndex + 1) % pins.length;
4921
- applyStyle(st);
4922
- if (st.expanded) fillContent(st);
4923
- });
4924
- layerEl.appendChild(wrap);
4925
- return st;
4926
- };
4927
- const applyStyle = (st) => {
4928
- const pins = byComp.get(st.componentId);
4929
- if (!pins?.length) return;
4930
- const idx = Math.max(0, Math.min(st.pinIndex, pins.length - 1));
4931
- st.pinIndex = idx;
4932
- const pin = pins[idx];
4933
- const c = typeColors(pin.type);
4934
- st.el.style.backgroundColor = "var(--background)";
4935
- st.el.style.backgroundImage = `linear-gradient(${c.bg}, ${c.bg})`;
4936
- st.el.style.color = c.fg;
4937
- if (st.lastType !== pin.type) {
4938
- st.lastType = pin.type;
4939
- st.iconEl.innerHTML = "";
4940
- const svg2 = (0, import_lucide4.createElement)(typeIcon(pin.type));
4941
- svg2.setAttribute("width", String(ICON));
4942
- svg2.setAttribute("height", String(ICON));
4943
- st.iconEl.appendChild(svg2);
4944
- }
4945
- if (pins.length > 1) {
4946
- st.badgeEl.textContent = String(pins.length);
4947
- st.badgeEl.style.display = "flex";
4948
- } else {
4949
- st.badgeEl.textContent = "";
4950
- st.badgeEl.style.display = "none";
4951
- }
4952
- };
4953
- const posIndicator = (st) => {
4954
- const a = st.anchor;
4955
- if (!a || !a.isConnected) {
4956
- st.wrap.style.display = "none";
4957
- return;
4958
- }
4959
- const r = a.getBoundingClientRect();
4960
- if (r.width === 0 && r.height === 0) {
4961
- st.wrap.style.display = "none";
4962
- return;
4963
- }
4964
- const vw = window.innerWidth;
4965
- st.wrap.style.top = `${r.top + INSET}px`;
4966
- st.wrap.style.right = `${vw - r.right + INSET}px`;
4967
- st.wrap.style.display = "";
4968
- };
4969
- const posAll = () => {
4970
- for (const st of indicators.values()) posIndicator(st);
4971
- };
4972
- const renderIndicator = (componentId) => {
4973
- const pins = byComp.get(componentId);
4974
- if (!pins?.length) {
4975
- removeIndicator(componentId);
4976
- return;
4977
- }
4978
- let st = indicators.get(componentId);
4979
- if (!st) {
4980
- st = buildIndicator(componentId);
4981
- indicators.set(componentId, st);
4982
- repositioner.attach();
4983
- attachObs();
4984
- }
4985
- if (st.pinIndex >= pins.length) st.pinIndex = 0;
4986
- applyStyle(st);
4987
- st.anchor = resolveEntityElement(parseComponentRef(componentId));
4988
- posIndicator(st);
4989
- };
4990
- const removeIndicator = (componentId) => {
4991
- const st = indicators.get(componentId);
4992
- if (!st) return;
4993
- st.wrap.remove();
4994
- indicators.delete(componentId);
4995
- if (indicators.size === 0) {
4996
- repositioner.detach();
4997
- detachObs();
4998
- }
4999
- };
5000
- const ingest = (pin) => {
5001
- const cid = pin.entity ?? "";
5002
- if (!cid || seenIds.has(pin.id)) return false;
5003
- seenIds.add(pin.id);
5004
- allPins.push(pin);
5005
- return true;
5006
- };
5007
- let activeRefresh = null;
5008
- const layer = {
5009
- setPins(pins) {
5010
- allPins.length = 0;
5011
- seenIds.clear();
5012
- for (const p of pins) ingest(p);
5013
- rerender();
5014
- },
5015
- addPin(pin) {
5016
- if (!ingest(pin)) return;
5017
- rerender();
5018
- },
5019
- removePin(reportId) {
5020
- const i = allPins.findIndex((p) => p.id === reportId);
5021
- if (i === -1) return;
5022
- allPins.splice(i, 1);
5023
- seenIds.delete(reportId);
5024
- rerender();
5025
- },
5026
- clear() {
5027
- allPins.length = 0;
5028
- seenIds.clear();
5029
- byComp.clear();
5030
- for (const id of Array.from(indicators.keys())) removeIndicator(id);
5031
- notifyFilter();
5032
- },
5033
- getPinsForElement: (id) => byComp.get(id) ?? [],
5034
- getAllPins: () => allPins.slice(),
5035
- attachChannel(channel) {
5036
- const offPin = channel.onPin((pin) => {
5037
- layer.addPin(pin);
5038
- });
5039
- const offArchived = channel.onPinArchived?.((reportId) => {
5040
- layer.removePin(reportId);
5041
- }) ?? (() => {
5042
- });
5043
- return () => {
5044
- offPin();
5045
- offArchived();
5046
- };
5047
- },
5048
- attachCloud(opts) {
5049
- const offCh = opts.channel ? layer.attachChannel(opts.channel) : () => {
5050
- };
5051
- const fetch2 = async () => {
5052
- try {
5053
- const mode = opts.getMatchMode();
5054
- let params;
5055
- if (mode === "component") {
5056
- params = { entities: opts.getVisibleEntities().join(",") };
5057
- } else if (mode === "pathname") {
5058
- params = { route: opts.getPathname() };
5059
- } else {
5060
- params = { route: opts.getRoute() };
5061
- }
5062
- layer.setPins(await opts.cloud.pins.list(params));
5063
- } catch (err) {
5064
- opts.onError?.(err);
5065
- }
5066
- };
5067
- void fetch2();
5068
- activeRefresh = fetch2;
5069
- return () => {
5070
- offCh();
5071
- if (activeRefresh === fetch2) activeRefresh = null;
5072
- };
5073
- },
5074
- async refresh() {
5075
- if (activeRefresh) await activeRefresh();
5076
- },
5077
- onFilterChange(cb) {
5078
- filterCbs.add(cb);
5079
- return () => {
5080
- filterCbs.delete(cb);
5081
- };
5082
- },
5083
- get visible() {
5084
- return layerVisible;
5085
- },
5086
- setVisible(v) {
5087
- if (layerVisible === v) return;
5088
- layerVisible = v;
5089
- layerEl.style.display = v ? "" : "none";
5090
- if (v) posAll();
5091
- notifyFilter();
5092
- },
5093
- destroy() {
5094
- layer.clear();
5095
- repositioner.detach();
5096
- detachObs();
5097
- layerEl.remove();
5098
- activeRefresh = null;
5099
- filterCbs.clear();
5100
- }
5101
- };
5102
- return layer;
5103
- }
5104
-
5105
3836
  // src/browser/views/core/types.ts
5106
3837
  var ViewValidationError = class extends Error {
5107
3838
  constructor(message) {
@@ -5256,7 +3987,7 @@ var import_ref = require("lit-html/directives/ref.js");
5256
3987
  // src/browser/internal/lit-icon.ts
5257
3988
  var import_lit_html = require("lit-html");
5258
3989
  var import_directive = require("lit-html/directive.js");
5259
- var import_lucide5 = require("lucide");
3990
+ var import_lucide4 = require("lucide");
5260
3991
  var LucideIconDirective = class extends import_directive.Directive {
5261
3992
  _icon;
5262
3993
  _class;
@@ -5271,13 +4002,13 @@ var LucideIconDirective = class extends import_directive.Directive {
5271
4002
  if (iconNode === this._icon && className === this._class) return import_lit_html.noChange;
5272
4003
  this._icon = iconNode;
5273
4004
  this._class = className;
5274
- this._el = (0, import_lucide5.createElement)(iconNode);
4005
+ this._el = (0, import_lucide4.createElement)(iconNode);
5275
4006
  this._el.setAttribute("aria-hidden", "true");
5276
4007
  if (className) this._el.setAttribute("class", className);
5277
4008
  return this._el;
5278
4009
  }
5279
4010
  render(iconNode, className) {
5280
- const el2 = (0, import_lucide5.createElement)(iconNode);
4011
+ const el2 = (0, import_lucide4.createElement)(iconNode);
5281
4012
  el2.setAttribute("aria-hidden", "true");
5282
4013
  if (className) el2.setAttribute("class", className);
5283
4014
  return el2;
@@ -5293,7 +4024,7 @@ function createChip(options = {}, children = []) {
5293
4024
  }
5294
4025
 
5295
4026
  // src/browser/views/primitives/kind-icon.ts
5296
- var import_lucide6 = require("lucide");
4027
+ var import_lucide5 = require("lucide");
5297
4028
 
5298
4029
  // src/browser/ui/cva.ts
5299
4030
  function cva(base, config = {}) {
@@ -5381,7 +4112,7 @@ function iconTileTpl(inner, options = {}) {
5381
4112
  // src/browser/views/primitives/kind-icon.ts
5382
4113
  function renderKindIcon(kind) {
5383
4114
  const style = KIND_STYLE[kind];
5384
- const svg2 = (0, import_lucide6.createElement)(style.icon);
4115
+ const svg2 = (0, import_lucide5.createElement)(style.icon);
5385
4116
  svg2.setAttribute("aria-hidden", "true");
5386
4117
  svg2.setAttribute("class", cn("h-4 w-4 shrink-0", style.tone));
5387
4118
  return svg2;
@@ -5477,7 +4208,7 @@ function createBindable(propsFn) {
5477
4208
  }
5478
4209
  };
5479
4210
  }
5480
- function createMachineHandle(zagMachine, connect4, normalize, props = {}) {
4211
+ function createMachineHandle(zagMachine, connect3, normalize, props = {}) {
5481
4212
  const runner = createMachineRunner(
5482
4213
  zagMachine,
5483
4214
  props
@@ -5485,12 +4216,12 @@ function createMachineHandle(zagMachine, connect4, normalize, props = {}) {
5485
4216
  runner.start();
5486
4217
  return {
5487
4218
  runner,
5488
- api: () => connect4(runner.service, normalize),
4219
+ api: () => connect3(runner.service, normalize),
5489
4220
  destroy: () => runner.stop()
5490
4221
  };
5491
4222
  }
5492
4223
  function createMachineRunner(machineArg, initialProps = {}) {
5493
- const machine4 = machineArg;
4224
+ const machine3 = machineArg;
5494
4225
  let userProps = initialProps;
5495
4226
  const unmountFns = [];
5496
4227
  const listeners = /* @__PURE__ */ new Set();
@@ -5507,7 +4238,7 @@ function createMachineRunner(machineArg, initialProps = {}) {
5507
4238
  };
5508
4239
  };
5509
4240
  const debug = (...args) => {
5510
- if (machine4.debug) {
4241
+ if (machine3.debug) {
5511
4242
  console.log(...args);
5512
4243
  }
5513
4244
  };
@@ -5515,7 +4246,7 @@ function createMachineRunner(machineArg, initialProps = {}) {
5515
4246
  const prop = (key) => propsRef.current[key];
5516
4247
  const refreshProps = () => {
5517
4248
  const scope = scopeRef.current;
5518
- const computedProps = machine4.props?.({
4249
+ const computedProps = machine3.props?.({
5519
4250
  props: (0, import_utils.compact)(userProps),
5520
4251
  scope
5521
4252
  }) ?? userProps;
@@ -5549,7 +4280,7 @@ function createMachineRunner(machineArg, initialProps = {}) {
5549
4280
  return values.some((v) => (0, import_core.matchesState)(state.ref.current, v));
5550
4281
  },
5551
4282
  hasTag(tag) {
5552
- return (0, import_core.hasTag)(machine4, state.ref.current, tag);
4283
+ return (0, import_core.hasTag)(machine3, state.ref.current, tag);
5553
4284
  }
5554
4285
  });
5555
4286
  const getParams = () => ({
@@ -5571,7 +4302,7 @@ function createMachineRunner(machineArg, initialProps = {}) {
5571
4302
  const strs = (0, import_utils.isFunction)(keys) ? keys(getParams()) : keys;
5572
4303
  if (!strs) return;
5573
4304
  const fns = strs.map((s) => {
5574
- const fn = machine4.implementations?.actions?.[s];
4305
+ const fn = machine3.implementations?.actions?.[s];
5575
4306
  if (!fn) (0, import_utils.warn)(`[uidex] No implementation found for action "${s}"`);
5576
4307
  return fn;
5577
4308
  });
@@ -5579,13 +4310,13 @@ function createMachineRunner(machineArg, initialProps = {}) {
5579
4310
  };
5580
4311
  const guard = (str) => {
5581
4312
  if ((0, import_utils.isFunction)(str)) return str(getParams());
5582
- return machine4.implementations?.guards?.[str](getParams());
4313
+ return machine3.implementations?.guards?.[str](getParams());
5583
4314
  };
5584
4315
  const effect = (keys) => {
5585
4316
  const strs = (0, import_utils.isFunction)(keys) ? keys(getParams()) : keys;
5586
4317
  if (!strs) return;
5587
4318
  const fns = strs.map((s) => {
5588
- const fn = machine4.implementations?.effects?.[s];
4319
+ const fn = machine3.implementations?.effects?.[s];
5589
4320
  if (!fn) (0, import_utils.warn)(`[uidex] No implementation found for effect "${s}"`);
5590
4321
  return fn;
5591
4322
  });
@@ -5606,10 +4337,10 @@ function createMachineRunner(machineArg, initialProps = {}) {
5606
4337
  });
5607
4338
  const computed = (key) => {
5608
4339
  (0, import_utils.ensure)(
5609
- machine4.computed,
4340
+ machine3.computed,
5610
4341
  () => `[uidex] No computed object found on machine`
5611
4342
  );
5612
- const fn = machine4.computed[key];
4343
+ const fn = machine3.computed[key];
5613
4344
  return fn({
5614
4345
  context: ctx,
5615
4346
  event: getEvent(),
@@ -5642,7 +4373,7 @@ function createMachineRunner(machineArg, initialProps = {}) {
5642
4373
  queueMicrotask(() => fn());
5643
4374
  };
5644
4375
  let contextFields = {};
5645
- const ctxContextFn = machine4.context;
4376
+ const ctxContextFn = machine3.context;
5646
4377
  if (ctxContextFn) {
5647
4378
  contextFields = ctxContextFn({
5648
4379
  prop,
@@ -5678,7 +4409,7 @@ function createMachineRunner(machineArg, initialProps = {}) {
5678
4409
  return contextFields[key]?.hash(current) ?? "";
5679
4410
  }
5680
4411
  };
5681
- const refsInit = machine4.refs?.({ prop, context: ctx }) ?? {};
4412
+ const refsInit = machine3.refs?.({ prop, context: ctx }) ?? {};
5682
4413
  const refsStore = { ...refsInit };
5683
4414
  const refs = {
5684
4415
  get(key) {
@@ -5689,14 +4420,14 @@ function createMachineRunner(machineArg, initialProps = {}) {
5689
4420
  }
5690
4421
  };
5691
4422
  const initialState = (0, import_core.resolveStateValue)(
5692
- machine4,
5693
- machine4.initialState({ prop })
4423
+ machine3,
4424
+ machine3.initialState({ prop })
5694
4425
  );
5695
4426
  const state = createBindable(() => ({
5696
4427
  defaultValue: initialState,
5697
4428
  onChange(nextState, prevState) {
5698
4429
  const { exiting, entering } = (0, import_core.getExitEnterStates)(
5699
- machine4,
4430
+ machine3,
5700
4431
  prevState,
5701
4432
  nextState,
5702
4433
  transitionRef?.reenter
@@ -5715,8 +4446,8 @@ function createMachineRunner(machineArg, initialProps = {}) {
5715
4446
  if (cleanup) effectsMap.set(item.path, cleanup);
5716
4447
  });
5717
4448
  if (prevState === import_core.INIT_STATE) {
5718
- action(machine4.entry);
5719
- const cleanup = effect(machine4.effects);
4449
+ action(machine3.entry);
4450
+ const cleanup = effect(machine3.effects);
5720
4451
  if (cleanup) effectsMap.set(import_core.INIT_STATE, cleanup);
5721
4452
  }
5722
4453
  entering.forEach((item) => {
@@ -5735,7 +4466,7 @@ function createMachineRunner(machineArg, initialProps = {}) {
5735
4466
  currentEvent = event;
5736
4467
  const currentState = getCurrentState();
5737
4468
  const { transitions, source } = (0, import_core.findTransition)(
5738
- machine4,
4469
+ machine3,
5739
4470
  currentState,
5740
4471
  event.type
5741
4472
  );
@@ -5743,7 +4474,7 @@ function createMachineRunner(machineArg, initialProps = {}) {
5743
4474
  if (!transition) return;
5744
4475
  transitionRef = transition;
5745
4476
  const target = (0, import_core.resolveStateValue)(
5746
- machine4,
4477
+ machine3,
5747
4478
  transition.target ?? currentState,
5748
4479
  source
5749
4480
  );
@@ -5763,7 +4494,7 @@ function createMachineRunner(machineArg, initialProps = {}) {
5763
4494
  }
5764
4495
  });
5765
4496
  };
5766
- machine4.watch?.(getParams());
4497
+ machine3.watch?.(getParams());
5767
4498
  const service = {
5768
4499
  state: getState(),
5769
4500
  send,
@@ -5804,7 +4535,7 @@ function createMachineRunner(machineArg, initialProps = {}) {
5804
4535
  while (unmountFns.length) unmountFns.pop()?.();
5805
4536
  listeners.clear();
5806
4537
  queueMicrotask(() => {
5807
- action(machine4.exit);
4538
+ action(machine3.exit);
5808
4539
  });
5809
4540
  },
5810
4541
  subscribe(listener) {
@@ -5882,9 +4613,6 @@ function applyProps(node, props) {
5882
4613
  }
5883
4614
 
5884
4615
  // src/browser/views/builder/spread-props.ts
5885
- function spreadProps(node, props) {
5886
- return applyProps(node, props);
5887
- }
5888
4616
  function createPersistentSpreads() {
5889
4617
  const map = /* @__PURE__ */ new Map();
5890
4618
  return {
@@ -6007,18 +4735,18 @@ function headingTpl(text, className) {
6007
4735
  }
6008
4736
 
6009
4737
  // src/browser/views/render/detail-actions.ts
6010
- var import_lucide7 = require("lucide");
4738
+ var import_lucide6 = require("lucide");
6011
4739
  var ICON_MAP = {
6012
- "archive-x": import_lucide7.ArchiveX,
6013
- copy: import_lucide7.Copy,
6014
- camera: import_lucide7.Camera,
6015
- inbox: import_lucide7.Inbox,
6016
- "message-circle-warning": import_lucide7.MessageCircleWarning,
6017
- "chevron-down": import_lucide7.ChevronDown,
6018
- highlighter: import_lucide7.Highlighter,
6019
- "sticky-note": import_lucide7.StickyNote,
6020
- "ticket-plus": import_lucide7.TicketPlus,
6021
- view: import_lucide7.View
4740
+ "archive-x": import_lucide6.ArchiveX,
4741
+ copy: import_lucide6.Copy,
4742
+ camera: import_lucide6.Camera,
4743
+ inbox: import_lucide6.Inbox,
4744
+ "message-circle-warning": import_lucide6.MessageCircleWarning,
4745
+ "chevron-down": import_lucide6.ChevronDown,
4746
+ highlighter: import_lucide6.Highlighter,
4747
+ "sticky-note": import_lucide6.StickyNote,
4748
+ "ticket-plus": import_lucide6.TicketPlus,
4749
+ view: import_lucide6.View
6022
4750
  };
6023
4751
  function iconFor(icon2) {
6024
4752
  return icon2 ? ICON_MAP[icon2] : null;
@@ -6057,7 +4785,7 @@ function renderActions(actions, ctx, root, heading) {
6057
4785
  let leading;
6058
4786
  const iconNode = iconFor(action.icon);
6059
4787
  if (iconNode) {
6060
- const svg2 = (0, import_lucide7.createElement)(iconNode);
4788
+ const svg2 = (0, import_lucide6.createElement)(iconNode);
6061
4789
  svg2.setAttribute("aria-hidden", "true");
6062
4790
  svg2.setAttribute("class", "h-4 w-4 shrink-0");
6063
4791
  const tile = el(
@@ -6793,858 +5521,84 @@ function renderDetailSurface(surface, ctx, root) {
6793
5521
  return mounted;
6794
5522
  }
6795
5523
 
6796
- // src/browser/views/render/form.ts
6797
- var import_lucide8 = require("lucide");
6798
-
6799
- // src/browser/machines/dialog.ts
6800
- var dialog = __toESM(require("@zag-js/dialog"), 1);
6801
- function createDialog(props = {}) {
6802
- return createMachineHandle(
6803
- dialog.machine,
6804
- dialog.connect,
6805
- normalizeProps,
6806
- props
6807
- );
6808
- }
5524
+ // src/browser/views/render/list.ts
5525
+ var import_lucide7 = require("lucide");
6809
5526
 
6810
- // src/browser/ui/screenshot-lightbox.ts
6811
- function createScreenshotLightbox(trigger, dataUrl, options) {
6812
- const cleanups = [];
6813
- const lightbox = createDialog({
6814
- id: "uidex-screenshot-lightbox",
6815
- modal: true,
6816
- closeOnInteractOutside: false,
6817
- closeOnEscape: false,
6818
- trapFocus: true,
6819
- preventScroll: true,
6820
- restoreFocus: true,
6821
- "aria-label": "Screenshot preview",
6822
- getRootNode: () => trigger.getRootNode()
6823
- });
6824
- cleanups.push(() => lightbox.destroy());
6825
- const backdropRef = (0, import_ref.createRef)();
6826
- const positionerRef = (0, import_ref.createRef)();
6827
- const contentRef = (0, import_ref.createRef)();
6828
- const fullImgRef = (0, import_ref.createRef)();
6829
- const mountTarget = (() => {
6830
- const rn = trigger.getRootNode();
6831
- return rn instanceof ShadowRoot ? rn : rn.body;
6832
- })();
6833
- const fragment = document.createDocumentFragment();
6834
- (0, import_lit_html2.render)(
6835
- import_lit_html2.html`
6836
- <div
6837
- ${(0, import_ref.ref)(backdropRef)}
6838
- class="fixed inset-0 z-[2147483647] cursor-pointer bg-black/80"
6839
- data-uidex-lightbox
6840
- hidden
6841
- ></div>
6842
- <div
6843
- ${(0, import_ref.ref)(positionerRef)}
6844
- class="fixed inset-0 z-[2147483647] flex cursor-pointer items-center justify-center p-6"
6845
- hidden
6846
- >
6847
- <div
6848
- ${(0, import_ref.ref)(contentRef)}
6849
- class="flex items-center justify-center outline-none"
6850
- >
6851
- <img
6852
- ${(0, import_ref.ref)(fullImgRef)}
6853
- class="max-h-full max-w-full rounded-lg"
6854
- src=${dataUrl}
6855
- alt="Screenshot"
6856
- />
6857
- </div>
6858
- </div>
6859
- `,
6860
- fragment
6861
- );
6862
- const backdropEl = backdropRef.value;
6863
- const positioner = positionerRef.value;
6864
- const content = contentRef.value;
6865
- const fullImg = fullImgRef.value;
6866
- mountTarget.append(fragment);
6867
- let spreadCleanups = [];
6868
- function applyLightboxProps() {
6869
- for (const c of spreadCleanups) c();
6870
- spreadCleanups = [];
6871
- const api = lightbox.api();
6872
- spreadCleanups.push(
6873
- spreadProps(
6874
- backdropEl,
6875
- api.getBackdropProps()
6876
- ),
6877
- spreadProps(
6878
- positioner,
6879
- api.getPositionerProps()
6880
- ),
6881
- spreadProps(content, api.getContentProps())
6882
- );
6883
- backdropEl.hidden = !api.open;
6884
- positioner.hidden = !api.open;
6885
- }
6886
- applyLightboxProps();
6887
- const unsubLightbox = lightbox.runner.subscribe(applyLightboxProps);
6888
- cleanups.push(() => {
6889
- unsubLightbox();
6890
- for (const c of spreadCleanups) c();
6891
- backdropEl.remove();
6892
- positioner.remove();
6893
- });
6894
- const closeLightbox = () => lightbox.api().setOpen(false);
6895
- if (options?.pushEscapeLayer) {
6896
- cleanups.push(
6897
- options.pushEscapeLayer(() => {
6898
- if (!lightbox.api().open) return false;
6899
- closeLightbox();
6900
- return true;
6901
- })
6902
- );
6903
- } else {
6904
- const onEscapeCapture = (e) => {
6905
- if (e.key !== "Escape") return;
6906
- if (!lightbox.api().open) return;
6907
- e.preventDefault();
6908
- e.stopPropagation();
6909
- e.stopImmediatePropagation();
6910
- closeLightbox();
6911
- };
6912
- window.addEventListener("keydown", onEscapeCapture, true);
6913
- cleanups.push(
6914
- () => window.removeEventListener("keydown", onEscapeCapture, true)
6915
- );
5527
+ // src/browser/views/render/list-controller.ts
5528
+ function createListController(opts) {
5529
+ let items = opts.items;
5530
+ let itemNodes = opts.itemNodes;
5531
+ let highlighted = null;
5532
+ let kbdMode = false;
5533
+ const subs = /* @__PURE__ */ new Set();
5534
+ const { contentEl, onSelect, onHighlightChange } = opts;
5535
+ contentEl.setAttribute("role", "listbox");
5536
+ contentEl.tabIndex = 0;
5537
+ contentEl.style.outline = "none";
5538
+ applyItemAria();
5539
+ if (opts.defaultHighlight && itemNodes.has(opts.defaultHighlight)) {
5540
+ setHighlight(opts.defaultHighlight, false);
6916
5541
  }
6917
- let suppressClickUntil = 0;
6918
- const onClickOutsideCapture = (e) => {
6919
- if (Date.now() < suppressClickUntil) {
6920
- e.preventDefault();
6921
- e.stopPropagation();
6922
- e.stopImmediatePropagation();
6923
- return;
6924
- }
6925
- if (!lightbox.api().open) return;
6926
- if (fullImg.contains(e.target)) return;
6927
- e.preventDefault();
6928
- e.stopPropagation();
6929
- e.stopImmediatePropagation();
6930
- closeLightbox();
6931
- suppressClickUntil = Date.now() + 100;
6932
- };
6933
- window.addEventListener("pointerdown", onClickOutsideCapture, true);
6934
- window.addEventListener("mousedown", onClickOutsideCapture, true);
6935
- window.addEventListener("click", onClickOutsideCapture, true);
6936
- cleanups.push(() => {
6937
- window.removeEventListener("pointerdown", onClickOutsideCapture, true);
6938
- window.removeEventListener("mousedown", onClickOutsideCapture, true);
6939
- window.removeEventListener("click", onClickOutsideCapture, true);
6940
- });
6941
- spreadProps(
6942
- trigger,
6943
- lightbox.api().getTriggerProps()
6944
- );
6945
- return {
6946
- destroy() {
6947
- for (const c of cleanups) c();
6948
- cleanups.length = 0;
6949
- }
6950
- };
6951
- }
6952
-
6953
- // src/browser/ui/button.ts
6954
- 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";
6955
- var buttonVariants = cva(buttonBase, {
6956
- defaultVariants: { size: "default", variant: "default" },
6957
- variants: {
6958
- size: {
6959
- default: "h-8 px-3",
6960
- sm: "h-7 gap-1.5 px-2.5",
6961
- xs: "h-6 gap-1 rounded-md px-2 text-xs",
6962
- lg: "h-9 px-3.5",
6963
- xl: "h-10 px-4 text-base",
6964
- icon: "size-8",
6965
- "icon-sm": "size-7",
6966
- "icon-lg": "size-9",
6967
- "icon-xs": "size-6 rounded-md"
6968
- },
6969
- variant: {
6970
- default: "border-primary bg-primary text-primary-foreground shadow-xs hover:bg-primary/90",
6971
- destructive: "border-destructive bg-destructive shadow-xs hover:bg-destructive/90 text-white",
6972
- "destructive-outline": "border-input bg-popover text-destructive-foreground shadow-xs/5 hover:border-destructive/30 hover:bg-destructive/5 dark:bg-input/30",
6973
- ghost: "text-foreground hover:bg-accent hover:text-accent-foreground border-transparent",
6974
- link: "text-foreground border-transparent underline-offset-4 hover:underline",
6975
- outline: "border-input bg-popover text-foreground shadow-xs/5 hover:bg-accent hover:text-accent-foreground dark:bg-input/30",
6976
- secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/90 border-transparent"
5542
+ function values() {
5543
+ return items.map((i) => i.value);
5544
+ }
5545
+ function notify() {
5546
+ for (const cb of subs) cb();
5547
+ }
5548
+ function applyItemAria() {
5549
+ for (const [value, el2] of itemNodes) {
5550
+ el2.setAttribute("role", "option");
5551
+ el2.id = `${opts.surfaceId}-item-${value}`;
6977
5552
  }
6978
5553
  }
6979
- });
6980
-
6981
- // src/browser/views/render/form.ts
6982
- var fieldSeq = 0;
6983
- var nextFieldId = () => `uidex-field-${++fieldSeq}`;
6984
- function issuePathRoot(issue) {
6985
- const seg = issue.path?.[0];
6986
- if (seg === void 0) return void 0;
6987
- if (typeof seg === "object" && seg !== null && "key" in seg) {
6988
- return String(seg.key);
6989
- }
6990
- return String(seg);
6991
- }
6992
- async function validateWithSchema(schema, values) {
6993
- const result = await schema["~standard"].validate(values);
6994
- if (!("issues" in result) || !result.issues) return null;
6995
- const out = {};
6996
- for (const issue of result.issues) {
6997
- const key = issuePathRoot(issue);
6998
- if (!key) continue;
6999
- if (out[key]) continue;
7000
- out[key] = issue.message;
7001
- }
7002
- return Object.keys(out).length > 0 ? out : null;
7003
- }
7004
- 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";
7005
- 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";
7006
- var FIELD_ROOT_CLASS = "flex flex-col items-start gap-2";
7007
- var FIELD_LABEL_CLASS = "text-base/4.5 text-foreground inline-flex items-center gap-2 font-medium sm:text-sm/4";
7008
- var FIELD_ERROR_CLASS = "text-destructive-foreground text-xs";
7009
- var CHECKBOX_CLASS = "border-input bg-popover size-4 cursor-pointer rounded-[0.25rem] border accent-primary";
7010
- function renderField(field, initial) {
7011
- const controlId = nextFieldId();
7012
- let control;
7013
- let read;
7014
- let reset;
7015
- switch (field.kind) {
7016
- case "select": {
7017
- const node = el("select", {
7018
- class: NATIVE_SELECT_CLASS,
7019
- attrs: {
7020
- "data-slot": "select",
7021
- name: field.name,
7022
- id: controlId,
7023
- required: field.required ?? false
7024
- }
7025
- });
7026
- for (const opt of field.options) {
7027
- node.append(
7028
- el("option", { attrs: { value: opt.value }, text: opt.label })
7029
- );
5554
+ function setHighlight(value, scroll = true) {
5555
+ if (value === highlighted) return;
5556
+ if (highlighted) {
5557
+ const prev = itemNodes.get(highlighted);
5558
+ if (prev) {
5559
+ prev.removeAttribute("data-highlighted");
5560
+ prev.removeAttribute("data-kbd-highlighted");
5561
+ prev.removeAttribute("aria-selected");
7030
5562
  }
7031
- const initialVal = typeof initial === "string" ? initial : typeof field.value === "string" ? field.value : field.options[0]?.value;
7032
- if (initialVal !== void 0) node.value = initialVal;
7033
- control = node;
7034
- read = () => node.value;
7035
- reset = () => {
7036
- if (initialVal !== void 0) node.value = initialVal;
7037
- };
7038
- break;
7039
- }
7040
- case "text":
7041
- case "email": {
7042
- const node = el("input", {
7043
- class: cn(FIELD_INPUT_CLASS, "h-8 px-3"),
7044
- attrs: {
7045
- "data-slot": "input",
7046
- type: field.kind === "email" ? "email" : "text",
7047
- name: field.name,
7048
- id: controlId,
7049
- placeholder: field.placeholder ?? "",
7050
- required: field.required ?? false
7051
- }
7052
- });
7053
- const initialVal = typeof initial === "string" ? initial : typeof field.value === "string" ? field.value : "";
7054
- node.value = initialVal;
7055
- control = node;
7056
- read = () => node.value;
7057
- reset = () => {
7058
- node.value = initialVal;
7059
- };
7060
- break;
7061
- }
7062
- case "textarea": {
7063
- const node = el("textarea", {
7064
- class: cn(FIELD_INPUT_CLASS, "min-h-20 px-3 py-2"),
7065
- attrs: {
7066
- "data-slot": "textarea",
7067
- name: field.name,
7068
- id: controlId,
7069
- placeholder: field.placeholder ?? "",
7070
- required: field.required ?? false,
7071
- rows: field.rows
7072
- }
7073
- });
7074
- const initialVal = typeof initial === "string" ? initial : typeof field.value === "string" ? field.value : "";
7075
- node.value = initialVal;
7076
- control = node;
7077
- read = () => node.value;
7078
- reset = () => {
7079
- node.value = initialVal;
7080
- };
7081
- break;
7082
- }
7083
- case "checkbox": {
7084
- const input = el("input", {
7085
- attrs: {
7086
- type: "checkbox",
7087
- name: field.name,
7088
- id: controlId
7089
- },
7090
- class: CHECKBOX_CLASS
7091
- });
7092
- const initialVal = typeof initial === "boolean" ? initial : typeof field.value === "boolean" ? field.value : false;
7093
- input.checked = initialVal;
7094
- control = input;
7095
- read = () => input.checked;
7096
- reset = () => {
7097
- input.checked = initialVal;
7098
- };
7099
- break;
7100
5563
  }
5564
+ highlighted = value;
5565
+ if (value) {
5566
+ const el2 = itemNodes.get(value);
5567
+ if (el2) {
5568
+ el2.setAttribute("data-highlighted", "");
5569
+ el2.setAttribute("aria-selected", "true");
5570
+ if (kbdMode) el2.setAttribute("data-kbd-highlighted", "");
5571
+ contentEl.setAttribute("aria-activedescendant", el2.id);
5572
+ if (scroll) el2.scrollIntoView({ block: "nearest" });
5573
+ }
5574
+ } else {
5575
+ contentEl.removeAttribute("aria-activedescendant");
5576
+ }
5577
+ onHighlightChange?.(value);
5578
+ notify();
7101
5579
  }
7102
- const errorNode = el("p", {
7103
- class: FIELD_ERROR_CLASS,
7104
- attrs: {
7105
- "data-slot": "field-error",
7106
- role: "alert",
7107
- "aria-live": "polite"
5580
+ function enterKbd() {
5581
+ if (kbdMode) return;
5582
+ kbdMode = true;
5583
+ contentEl.setAttribute("data-kbd-nav", "");
5584
+ }
5585
+ function exitKbd() {
5586
+ if (!kbdMode) return;
5587
+ kbdMode = false;
5588
+ contentEl.removeAttribute("data-kbd-nav");
5589
+ if (highlighted) {
5590
+ itemNodes.get(highlighted)?.removeAttribute("data-kbd-highlighted");
7108
5591
  }
7109
- });
7110
- errorNode.hidden = true;
7111
- const field$ = el("div", {
7112
- class: cn(
7113
- FIELD_ROOT_CLASS,
7114
- field.kind === "checkbox" ? "flex-row items-center gap-2" : ""
7115
- ),
7116
- attrs: {
7117
- "data-slot": "field",
7118
- "data-uidex-primitive": "field",
7119
- "data-uidex-field-name": field.name
7120
- }
7121
- });
7122
- const label = el("label", {
7123
- class: FIELD_LABEL_CLASS,
7124
- attrs: {
7125
- "data-slot": "field-label",
7126
- for: controlId
7127
- },
7128
- text: field.label
7129
- });
7130
- if (field.kind === "checkbox") {
7131
- field$.append(control, label);
7132
- } else {
7133
- field$.append(label, control);
7134
- }
7135
- field$.append(errorNode);
7136
- const setError = (message) => {
7137
- if (!message) {
7138
- errorNode.hidden = true;
7139
- errorNode.textContent = "";
7140
- control.removeAttribute("aria-invalid");
7141
- return;
7142
- }
7143
- errorNode.hidden = false;
7144
- errorNode.textContent = message;
7145
- control.setAttribute("aria-invalid", "true");
7146
- };
7147
- return {
7148
- name: field.name,
7149
- node: field$,
7150
- control,
7151
- errorNode,
7152
- read,
7153
- reset,
7154
- setError
7155
- };
7156
- }
7157
- 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%)]";
7158
- var ICON_TILE = ICON_TILE_BASE + " relative";
7159
- var ICON_TILE_GHOST = ICON_TILE_BASE + " pointer-events-none absolute bottom-px shadow-none scale-84";
7160
- 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";
7161
- 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%)]";
7162
- function iconMediaTpl(iconTpl) {
7163
- return import_lit_html2.html`
7164
- <div class="relative mb-6">
7165
- <div
7166
- class=${ICON_TILE_GHOST + " -rotate-10 origin-bottom-left -translate-x-0.5"}
7167
- aria-hidden="true"
7168
- ></div>
7169
- <div
7170
- class=${ICON_TILE_GHOST + " rotate-10 origin-bottom-right translate-x-0.5"}
7171
- aria-hidden="true"
7172
- ></div>
7173
- <div class=${ICON_TILE}>${iconTpl}</div>
7174
- </div>
7175
- `;
7176
- }
7177
- function loadingViewTpl(rootRef) {
7178
- return import_lit_html2.html`
7179
- <div class=${EMPTY_ROOT} aria-live="polite" hidden ${(0, import_ref.ref)(rootRef)}>
7180
- ${iconMediaTpl(icon(import_lucide8.Loader2, "animate-spin"))}
7181
- <div class="flex max-w-sm flex-col items-center text-center">
7182
- <div class=${SKELETON + " h-6 w-36 rounded-md"}></div>
7183
- </div>
7184
- <div
7185
- class="flex w-full min-w-0 max-w-sm flex-col items-center gap-4 text-balance text-sm"
7186
- >
7187
- <div class=${SKELETON + " h-7 w-20 rounded-lg"}></div>
7188
- </div>
7189
- </div>
7190
- `;
7191
- }
7192
- function successViewTpl(refs) {
7193
- return import_lit_html2.html`
7194
- <div class=${EMPTY_ROOT} hidden data-uidex-success-view ${(0, import_ref.ref)(refs.root)}>
7195
- ${iconMediaTpl(icon(import_lucide8.CircleCheck))}
7196
- <div class="flex max-w-sm flex-col items-center text-center">
7197
- <div
7198
- class="font-heading text-xl font-semibold"
7199
- data-uidex-success-title
7200
- ${(0, import_ref.ref)(refs.title)}
7201
- ></div>
7202
- </div>
7203
- <div
7204
- class="flex w-full min-w-0 max-w-sm flex-col items-center gap-4 text-balance text-sm"
7205
- data-uidex-success-actions
7206
- ${(0, import_ref.ref)(refs.actions)}
7207
- >
7208
- <a
7209
- class=${buttonVariants({ variant: "outline", size: "sm" })}
7210
- target="_blank"
7211
- rel="noreferrer"
7212
- data-uidex-success-link
7213
- ${(0, import_ref.ref)(refs.link)}
7214
- ></a>
7215
- </div>
7216
- </div>
7217
- `;
7218
- }
7219
- function errorViewTpl(refs) {
7220
- return import_lit_html2.html`
7221
- <div class=${EMPTY_ROOT} hidden data-uidex-error-view ${(0, import_ref.ref)(refs.root)}>
7222
- ${iconMediaTpl(icon(import_lucide8.CircleX))}
7223
- <div class="flex max-w-sm flex-col items-center gap-1 text-center">
7224
- <div
7225
- class="font-heading text-xl font-semibold"
7226
- data-uidex-error-title
7227
- ${(0, import_ref.ref)(refs.title)}
7228
- ></div>
7229
- <p
7230
- class="text-muted-foreground text-sm"
7231
- data-uidex-error-description
7232
- ${(0, import_ref.ref)(refs.description)}
7233
- ></p>
7234
- </div>
7235
- <div
7236
- class="flex w-full min-w-0 max-w-sm flex-col items-center gap-4 text-balance text-sm"
7237
- >
7238
- <button
7239
- type="button"
7240
- class=${buttonVariants({ variant: "outline", size: "sm" })}
7241
- data-slot="button"
7242
- data-uidex-retry-button
7243
- ${(0, import_ref.ref)(refs.retry)}
7244
- >
7245
- Try Again
7246
- </button>
7247
- </div>
7248
- </div>
7249
- `;
7250
- }
7251
- function renderFormSurface(surface, ctx, root) {
7252
- const cleanups = [];
7253
- const fields = surface.fields.map(
7254
- (field) => renderField(field, surface.initial?.[field.name])
7255
- );
7256
- const fieldByName = new Map(fields.map((f) => [f.name, f]));
7257
- const screenshotField = el("div", {
7258
- class: "flex flex-col gap-1.5",
7259
- attrs: { hidden: true }
7260
- });
7261
- const screenshotLabel = el("span", {
7262
- class: "text-muted-foreground text-xs font-medium",
7263
- text: "Screenshot"
7264
- });
7265
- const screenshotPreview = el("div", {
7266
- class: "cursor-pointer overflow-hidden rounded-md border"
7267
- });
7268
- screenshotField.append(screenshotLabel, screenshotPreview);
7269
- if (surface.screenshotPreview) {
7270
- surface.screenshotPreview.then((dataUrl) => {
7271
- if (!dataUrl) return;
7272
- const img = el("img", {
7273
- class: "max-h-32 w-full object-cover object-top",
7274
- attrs: { src: dataUrl, alt: "Screenshot preview" }
7275
- });
7276
- screenshotPreview.append(img);
7277
- screenshotField.hidden = false;
7278
- const handle = createScreenshotLightbox(screenshotPreview, dataUrl, {
7279
- pushEscapeLayer: ctx.pushEscapeLayer
7280
- });
7281
- cleanups.push(() => handle.destroy());
7282
- });
7283
- }
7284
- const formRef = (0, import_ref.createRef)();
7285
- const loadingRef = (0, import_ref.createRef)();
7286
- const successRef = (0, import_ref.createRef)();
7287
- const successTitleRef = (0, import_ref.createRef)();
7288
- const successLinkRef = (0, import_ref.createRef)();
7289
- const successActionsRef = (0, import_ref.createRef)();
7290
- const errorRef = (0, import_ref.createRef)();
7291
- const errorTitleRef = (0, import_ref.createRef)();
7292
- const errorDescriptionRef = (0, import_ref.createRef)();
7293
- const retryRef = (0, import_ref.createRef)();
7294
- (0, import_lit_html2.render)(
7295
- import_lit_html2.html`
7296
- <section
7297
- class="flex min-h-0 flex-1 flex-col p-4"
7298
- data-uidex-form-surface=${surface.id}
7299
- >
7300
- <form
7301
- ${(0, import_ref.ref)(formRef)}
7302
- class="flex w-full flex-col gap-4"
7303
- data-slot="form"
7304
- data-uidex-primitive="form"
7305
- novalidate
7306
- data-uidex-form=${surface.id}
7307
- ></form>
7308
- ${loadingViewTpl(loadingRef)}
7309
- ${successViewTpl({
7310
- root: successRef,
7311
- title: successTitleRef,
7312
- link: successLinkRef,
7313
- actions: successActionsRef
7314
- })}
7315
- ${errorViewTpl({
7316
- root: errorRef,
7317
- title: errorTitleRef,
7318
- description: errorDescriptionRef,
7319
- retry: retryRef
7320
- })}
7321
- </section>
7322
- `,
7323
- root
7324
- );
7325
- const form = formRef.value;
7326
- if (surface.screenshotPreview) {
7327
- form.append(screenshotField);
7328
- }
7329
- for (const f of fields) {
7330
- form.append(f.node);
7331
- }
7332
- const submit = el("button", {
7333
- class: cn(buttonVariants({ variant: "default" }), "sr-only"),
7334
- attrs: {
7335
- type: "submit",
7336
- "data-slot": "button",
7337
- "data-uidex-form-submit": ""
7338
- },
7339
- text: surface.submit.label
7340
- });
7341
- form.append(submit);
7342
- const status = el("p", {
7343
- class: "text-muted-foreground text-xs",
7344
- attrs: {
7345
- "data-uidex-form-status": "",
7346
- "aria-live": "polite"
7347
- }
7348
- });
7349
- form.append(status);
7350
- const loadingView = loadingRef.value;
7351
- const successView = successRef.value;
7352
- const successTitle = successTitleRef.value;
7353
- const successLink = successLinkRef.value;
7354
- const successActions = successActionsRef.value;
7355
- const errorView = errorRef.value;
7356
- const errorTitle = errorTitleRef.value;
7357
- const errorDescription = errorDescriptionRef.value;
7358
- const retryButton = retryRef.value;
7359
- function clearAllFieldErrors() {
7360
- for (const f of fields) f.setError(null);
7361
- }
7362
- function applyFieldErrors(errs) {
7363
- clearAllFieldErrors();
7364
- if (!errs) return;
7365
- for (const [name, message] of Object.entries(errs)) {
7366
- fieldByName.get(name)?.setError(message);
7367
- }
7368
- }
7369
- function setStatus(result) {
7370
- status.replaceChildren();
7371
- status.classList.remove("text-destructive-foreground");
7372
- status.classList.add("text-muted-foreground");
7373
- if (!result) return;
7374
- if (result.status === "error") {
7375
- status.classList.remove("text-muted-foreground");
7376
- status.classList.add("text-destructive-foreground");
7377
- if (!result.fieldErrors) {
7378
- status.textContent = result.message;
7379
- }
7380
- return;
7381
- }
7382
- if (result.link) {
7383
- status.append(
7384
- document.createTextNode(`${result.message ?? "Submitted."} `),
7385
- el("a", {
7386
- class: "text-foreground underline underline-offset-4",
7387
- attrs: {
7388
- href: result.link.url,
7389
- target: "_blank",
7390
- rel: "noreferrer"
7391
- },
7392
- text: result.link.label ?? "Open link"
7393
- })
7394
- );
7395
- } else {
7396
- status.textContent = result.message ?? "Submitted.";
7397
- }
7398
- }
7399
- function showView(state) {
7400
- form.hidden = state !== "form";
7401
- loadingView.hidden = state !== "loading";
7402
- successView.hidden = state !== "success";
7403
- errorView.hidden = state !== "error";
7404
- }
7405
- function populateSuccess(result) {
7406
- if (!result || result.status !== "success") return;
7407
- successTitle.textContent = result.message ?? "Submitted";
7408
- if (result.link) {
7409
- successLink.setAttribute("href", result.link.url);
7410
- successLink.textContent = result.link.label ?? "Open link";
7411
- successActions.hidden = false;
7412
- } else {
7413
- successActions.hidden = true;
7414
- }
7415
- }
7416
- function populateError(result) {
7417
- if (!result || result.status !== "error") return;
7418
- errorTitle.textContent = "Something went wrong";
7419
- errorDescription.textContent = result.message;
7420
- }
7421
- let formState = "idle";
7422
- let lastResult = null;
7423
- let lastFieldErrors = null;
7424
- const subscribers = /* @__PURE__ */ new Set();
7425
- const notify = () => {
7426
- for (const cb of subscribers) cb();
7427
- };
7428
- async function doSubmit(values) {
7429
- if (formState === "submitting") return;
7430
- formState = "submitting";
7431
- setStatus(null);
7432
- clearAllFieldErrors();
7433
- showView("form");
7434
- lastResult = null;
7435
- lastFieldErrors = null;
7436
- if (surface.schema) {
7437
- const errors = await validateWithSchema(surface.schema, values);
7438
- if (errors) {
7439
- lastFieldErrors = errors;
7440
- lastResult = {
7441
- status: "error",
7442
- message: "Please fix the errors above.",
7443
- fieldErrors: errors
7444
- };
7445
- formState = "error";
7446
- applyFieldErrors(errors);
7447
- setStatus(lastResult);
7448
- showView("form");
7449
- notify();
7450
- return;
7451
- }
7452
- }
7453
- submit.disabled = true;
7454
- submit.setAttribute("data-loading", "");
7455
- showView("loading");
7456
- notify();
7457
- try {
7458
- const result = await surface.submit.onSubmit(
7459
- values
7460
- ) ?? { status: "success" };
7461
- submit.disabled = false;
7462
- submit.removeAttribute("data-loading");
7463
- if (result.status === "success") {
7464
- lastResult = result;
7465
- formState = "success";
7466
- populateSuccess(result);
7467
- showView("success");
7468
- clearAllFieldErrors();
7469
- if (result.resetFields) {
7470
- for (const name of result.resetFields) {
7471
- fieldByName.get(name)?.reset();
7472
- }
7473
- }
7474
- } else {
7475
- lastResult = result;
7476
- lastFieldErrors = result.fieldErrors ?? null;
7477
- formState = "error";
7478
- const hasFieldErrors = lastFieldErrors && Object.keys(lastFieldErrors).length > 0;
7479
- if (hasFieldErrors) {
7480
- applyFieldErrors(lastFieldErrors ?? void 0);
7481
- setStatus(result);
7482
- showView("form");
7483
- } else {
7484
- populateError(result);
7485
- showView("error");
7486
- }
7487
- }
7488
- } catch (err) {
7489
- submit.disabled = false;
7490
- submit.removeAttribute("data-loading");
7491
- const message = err instanceof Error ? err.message : String(err);
7492
- lastResult = { status: "error", message };
7493
- formState = "error";
7494
- populateError(lastResult);
7495
- showView("error");
7496
- }
7497
- notify();
7498
- }
7499
- function retryFromError() {
7500
- formState = "idle";
7501
- lastResult = null;
7502
- lastFieldErrors = null;
7503
- setStatus(null);
7504
- clearAllFieldErrors();
7505
- showView("form");
7506
- notify();
7507
- }
7508
- const onSubmit = (e) => {
7509
- e.preventDefault();
7510
- if (formState === "success") return;
7511
- if (formState === "error") retryFromError();
7512
- const values = {};
7513
- surface.fields.forEach((field, i) => {
7514
- values[field.name] = fields[i].read();
7515
- });
7516
- void doSubmit(values);
7517
- };
7518
- form.addEventListener("submit", onSubmit);
7519
- cleanups.push(() => form.removeEventListener("submit", onSubmit));
7520
- const triggerSubmit = () => {
7521
- if (typeof form.requestSubmit === "function") form.requestSubmit();
7522
- else form.dispatchEvent(new Event("submit", { cancelable: true }));
7523
- };
7524
- const onFormKeyDown = (e) => {
7525
- if (e.key !== "Enter") return;
7526
- const isMod = e.metaKey || e.ctrlKey;
7527
- if (isMod) {
7528
- e.preventDefault();
7529
- if (formState === "success") {
7530
- ctx.close();
7531
- return;
7532
- }
7533
- if (formState !== "idle" && formState !== "error") return;
7534
- triggerSubmit();
7535
- return;
7536
- }
7537
- if (e.target instanceof HTMLInputElement && e.target.type !== "checkbox" && e.target.type !== "radio") {
7538
- e.preventDefault();
7539
- }
7540
- };
7541
- form.addEventListener("keydown", onFormKeyDown);
7542
- cleanups.push(() => form.removeEventListener("keydown", onFormKeyDown));
7543
- retryButton.addEventListener("click", retryFromError);
7544
- cleanups.push(() => retryButton.removeEventListener("click", retryFromError));
7545
- const resolveIntent = () => {
7546
- if (formState === "submitting") {
7547
- return { label: "Submitting\u2026", disabled: true, perform: () => {
7548
- } };
7549
- }
7550
- if (formState === "success") {
7551
- return { label: "Close", perform: () => ctx.close() };
7552
- }
7553
- if (formState === "error" && !lastFieldErrors) {
7554
- return { label: "Try Again", perform: retryFromError };
7555
- }
7556
- return { label: surface.submit.label, perform: triggerSubmit };
7557
- };
7558
- return {
7559
- cleanup: composeCleanups([...cleanups, () => root.replaceChildren()]),
7560
- submitIntent: {
7561
- get: resolveIntent,
7562
- subscribe: (cb) => {
7563
- subscribers.add(cb);
7564
- return () => subscribers.delete(cb);
7565
- }
7566
- }
7567
- };
7568
- }
7569
-
7570
- // src/browser/views/render/list.ts
7571
- var import_lucide9 = require("lucide");
7572
-
7573
- // src/browser/views/render/list-controller.ts
7574
- function createListController(opts) {
7575
- let items = opts.items;
7576
- let itemNodes = opts.itemNodes;
7577
- let highlighted = null;
7578
- let kbdMode = false;
7579
- const subs = /* @__PURE__ */ new Set();
7580
- const { contentEl, onSelect, onHighlightChange } = opts;
7581
- contentEl.setAttribute("role", "listbox");
7582
- contentEl.tabIndex = 0;
7583
- contentEl.style.outline = "none";
7584
- applyItemAria();
7585
- if (opts.defaultHighlight && itemNodes.has(opts.defaultHighlight)) {
7586
- setHighlight(opts.defaultHighlight, false);
7587
- }
7588
- function values() {
7589
- return items.map((i) => i.value);
7590
- }
7591
- function notify() {
7592
- for (const cb of subs) cb();
7593
- }
7594
- function applyItemAria() {
7595
- for (const [value, el2] of itemNodes) {
7596
- el2.setAttribute("role", "option");
7597
- el2.id = `${opts.surfaceId}-item-${value}`;
7598
- }
7599
- }
7600
- function setHighlight(value, scroll = true) {
7601
- if (value === highlighted) return;
7602
- if (highlighted) {
7603
- const prev = itemNodes.get(highlighted);
7604
- if (prev) {
7605
- prev.removeAttribute("data-highlighted");
7606
- prev.removeAttribute("data-kbd-highlighted");
7607
- prev.removeAttribute("aria-selected");
7608
- }
7609
- }
7610
- highlighted = value;
7611
- if (value) {
7612
- const el2 = itemNodes.get(value);
7613
- if (el2) {
7614
- el2.setAttribute("data-highlighted", "");
7615
- el2.setAttribute("aria-selected", "true");
7616
- if (kbdMode) el2.setAttribute("data-kbd-highlighted", "");
7617
- contentEl.setAttribute("aria-activedescendant", el2.id);
7618
- if (scroll) el2.scrollIntoView({ block: "nearest" });
7619
- }
7620
- } else {
7621
- contentEl.removeAttribute("aria-activedescendant");
7622
- }
7623
- onHighlightChange?.(value);
7624
- notify();
7625
- }
7626
- function enterKbd() {
7627
- if (kbdMode) return;
7628
- kbdMode = true;
7629
- contentEl.setAttribute("data-kbd-nav", "");
7630
- }
7631
- function exitKbd() {
7632
- if (!kbdMode) return;
7633
- kbdMode = false;
7634
- contentEl.removeAttribute("data-kbd-nav");
7635
- if (highlighted) {
7636
- itemNodes.get(highlighted)?.removeAttribute("data-kbd-highlighted");
7637
- }
7638
- }
7639
- function move(delta) {
7640
- const vals = values();
7641
- if (vals.length === 0) return;
7642
- enterKbd();
7643
- if (highlighted === null) {
7644
- setHighlight(delta > 0 ? vals[0] : vals[vals.length - 1]);
7645
- if (highlighted)
7646
- itemNodes.get(highlighted)?.setAttribute("data-kbd-highlighted", "");
7647
- return;
5592
+ }
5593
+ function move(delta) {
5594
+ const vals = values();
5595
+ if (vals.length === 0) return;
5596
+ enterKbd();
5597
+ if (highlighted === null) {
5598
+ setHighlight(delta > 0 ? vals[0] : vals[vals.length - 1]);
5599
+ if (highlighted)
5600
+ itemNodes.get(highlighted)?.setAttribute("data-kbd-highlighted", "");
5601
+ return;
7648
5602
  }
7649
5603
  const idx = vals.indexOf(highlighted);
7650
5604
  const next = (idx + delta + vals.length) % vals.length;
@@ -7664,7 +5618,7 @@ function createListController(opts) {
7664
5618
  e.preventDefault();
7665
5619
  move(-1);
7666
5620
  break;
7667
- case "Home":
5621
+ case "Home": {
7668
5622
  e.preventDefault();
7669
5623
  enterKbd();
7670
5624
  const first = values()[0];
@@ -7674,7 +5628,8 @@ function createListController(opts) {
7674
5628
  itemNodes.get(highlighted)?.setAttribute("data-kbd-highlighted", "");
7675
5629
  }
7676
5630
  break;
7677
- case "End":
5631
+ }
5632
+ case "End": {
7678
5633
  e.preventDefault();
7679
5634
  enterKbd();
7680
5635
  const vals = values();
@@ -7685,6 +5640,7 @@ function createListController(opts) {
7685
5640
  itemNodes.get(highlighted)?.setAttribute("data-kbd-highlighted", "");
7686
5641
  }
7687
5642
  break;
5643
+ }
7688
5644
  case "Enter":
7689
5645
  if (highlighted) {
7690
5646
  e.preventDefault();
@@ -7772,7 +5728,7 @@ function resolveLeadingTpl(item) {
7772
5728
  >${node}</span
7773
5729
  >`;
7774
5730
  }
7775
- return iconTileTpl(icon(import_lucide9.Circle, "size-3.5 opacity-80"));
5731
+ return iconTileTpl(icon(import_lucide7.Circle, "size-3.5 opacity-80"));
7776
5732
  }
7777
5733
  function renderShell(surface, root) {
7778
5734
  const scrollRootRef = (0, import_ref.createRef)();
@@ -8014,8 +5970,6 @@ function renderSurface(surface, ctx, root) {
8014
5970
  return renderListSurface(surface, ctx, root);
8015
5971
  case "detail":
8016
5972
  return renderDetailSurface(surface, ctx, root);
8017
- case "form":
8018
- return renderFormSurface(surface, ctx, root);
8019
5973
  }
8020
5974
  }
8021
5975
 
@@ -8074,8 +6028,6 @@ function mountEntry(entry, view, deps) {
8074
6028
  const ctx = {
8075
6029
  ref: entry.ref,
8076
6030
  registry: deps.registry,
8077
- cloud: deps.cloud,
8078
- user: deps.session.getState().user,
8079
6031
  views: deps.views,
8080
6032
  push: (target) => {
8081
6033
  if (!deps.views.get(target.id)) return;
@@ -8089,10 +6041,7 @@ function mountEntry(entry, view, deps) {
8089
6041
  pinHighlight: (r) => deps.session.highlight.pin(r),
8090
6042
  searchInput: deps.searchInput,
8091
6043
  highlight: deps.highlight,
8092
- getStack: () => deps.session.getState().stack,
8093
- pushEscapeLayer: deps.pushEscapeLayer,
8094
- onAfterSubmit: deps.onAfterSubmit,
8095
- getRoute: deps.getRoute
6044
+ getStack: () => deps.session.getState().stack
8096
6045
  };
8097
6046
  let surfaceResult;
8098
6047
  try {
@@ -8155,7 +6104,7 @@ function setEntryVisibility(entry, visible) {
8155
6104
  }
8156
6105
 
8157
6106
  // src/browser/views/core/shell.ts
8158
- var import_lucide10 = require("lucide");
6107
+ var import_lucide8 = require("lucide");
8159
6108
 
8160
6109
  // src/browser/machines/menu.ts
8161
6110
  var menu = __toESM(require("@zag-js/menu"), 1);
@@ -8420,14 +6369,14 @@ function createStackShell(container, callbacks, _opts) {
8420
6369
  hidden
8421
6370
  @click=${onBackClick}
8422
6371
  >
8423
- ${icon(import_lucide10.ArrowLeft, BACK_ICON_CLASS)}
6372
+ ${icon(import_lucide8.ArrowLeft, BACK_ICON_CLASS)}
8424
6373
  </button>
8425
6374
  <span
8426
6375
  ${(0, import_ref.ref)(searchIconRef)}
8427
6376
  data-uidex-view-stack-search-icon
8428
6377
  aria-hidden="true"
8429
6378
  class=${SEARCH_ICON_WRAP_CLASS}
8430
- >${icon(import_lucide10.Search, SEARCH_ICON_CLASS)}</span
6379
+ >${icon(import_lucide8.Search, SEARCH_ICON_CLASS)}</span
8431
6380
  >
8432
6381
  <input
8433
6382
  ${(0, import_ref.ref)(searchInputRef)}
@@ -8615,9 +6564,7 @@ function resolveProp(view, ctx, value, propName, fallback) {
8615
6564
  }
8616
6565
  function createViewStack(options) {
8617
6566
  const { container, views, session, registry, highlight } = options;
8618
- const cloud = options.cloud ?? null;
8619
6567
  const dev = options.dev ?? detectDev();
8620
- const onAfterSubmit = options.onAfterSubmit;
8621
6568
  const mounted = [];
8622
6569
  let shell = null;
8623
6570
  let warnedForDepth = 0;
@@ -8814,13 +6761,8 @@ function createViewStack(options) {
8814
6761
  views,
8815
6762
  session,
8816
6763
  registry,
8817
- cloud,
8818
6764
  highlight,
8819
- nextScrollSeq: () => ++scrollAreaSeq,
8820
- pushEscapeLayer: options.pushEscapeLayer ?? (() => () => {
8821
- }),
8822
- onAfterSubmit,
8823
- getRoute: options.getRoute
6765
+ nextScrollSeq: () => ++scrollAreaSeq
8824
6766
  });
8825
6767
  if (record) mounted.push(record);
8826
6768
  }
@@ -8875,20 +6817,13 @@ function createViewStack(options) {
8875
6817
 
8876
6818
  // src/browser/views/built-in/ids.ts
8877
6819
  var BUILT_IN_VIEW_IDS = {
8878
- closeReason: "close-reason",
8879
6820
  commandPalette: "command-palette",
8880
6821
  elements: "elements",
8881
- entityReports: "entity-reports",
8882
6822
  explorePage: "explore-page",
8883
6823
  features: "features",
8884
- report: "report",
8885
6824
  flows: "flows",
8886
6825
  glossary: "glossary",
8887
- jiraReport: "jira-report",
8888
6826
  pages: "pages",
8889
- pageReports: "page-reports",
8890
- reportDetail: "report-detail",
8891
- pinSettings: "pin-settings",
8892
6827
  primitives: "primitives",
8893
6828
  regions: "regions",
8894
6829
  widgets: "widgets"
@@ -8903,16 +6838,6 @@ var LIST_VIEW_FOR_KIND = {
8903
6838
  flow: BUILT_IN_VIEW_IDS.flows,
8904
6839
  route: BUILT_IN_VIEW_IDS.pages
8905
6840
  };
8906
- var DETAIL_VIEW_FOR_KIND = {
8907
- element: "component-detail",
8908
- feature: "feature-detail",
8909
- page: "page-detail",
8910
- widget: "widget-detail",
8911
- region: "region-detail",
8912
- primitive: "primitive-detail",
8913
- flow: "flow-detail",
8914
- route: "page-detail"
8915
- };
8916
6841
  var COMMAND_PALETTE_ENTRY2 = {
8917
6842
  id: BUILT_IN_VIEW_IDS.commandPalette,
8918
6843
  ref: null
@@ -8921,105 +6846,9 @@ function parentList(ref2) {
8921
6846
  if (!ref2) return COMMAND_PALETTE_ENTRY2;
8922
6847
  return { id: LIST_VIEW_FOR_KIND[ref2.kind], ref: null };
8923
6848
  }
8924
- function parentDetail(ref2) {
8925
- if (!ref2) return COMMAND_PALETTE_ENTRY2;
8926
- return { id: DETAIL_VIEW_FOR_KIND[ref2.kind], ref: ref2 };
8927
- }
8928
-
8929
- // src/browser/views/built-in/close-reason.ts
8930
- var import_lucide11 = require("lucide");
8931
- var pendingReportId = null;
8932
- var afterClose = null;
8933
- function setCloseTarget(reportId, onDone) {
8934
- pendingReportId = reportId;
8935
- afterClose = onDone;
8936
- }
8937
- function leadingIcon(iconNode) {
8938
- return () => {
8939
- const svg2 = (0, import_lucide11.createElement)(iconNode);
8940
- svg2.setAttribute("aria-hidden", "true");
8941
- return createIconTile(svg2);
8942
- };
8943
- }
8944
- function spinnerTile() {
8945
- const spinner = (0, import_lucide11.createElement)(import_lucide11.LoaderCircle);
8946
- spinner.setAttribute("class", "animate-spin");
8947
- return createIconTile(spinner);
8948
- }
8949
- var REASONS = [
8950
- { value: "fixed", label: "Resolved", icon: import_lucide11.CircleCheck },
8951
- { value: "not_a_bug", label: "Not a bug", icon: import_lucide11.BugOff },
8952
- { value: "duplicate", label: "Duplicate", icon: import_lucide11.Copy },
8953
- { value: "wont_fix", label: "Won't fix", icon: import_lucide11.Ban }
8954
- ];
8955
- var closeReasonView = {
8956
- id: BUILT_IN_VIEW_IDS.closeReason,
8957
- matches: () => false,
8958
- parent: (ref2) => ref2 ? { id: BUILT_IN_VIEW_IDS.reportDetail, ref: ref2 } : null,
8959
- title: "Close reason",
8960
- searchable: false,
8961
- focusTarget: (host) => host.querySelector("[data-uidex-list-content]"),
8962
- surface: () => ({ kind: "list", id: "unused", items: [] }),
8963
- render(ctx, root) {
8964
- let busy = false;
8965
- const items = REASONS.map((r) => ({
8966
- value: r.value,
8967
- label: r.label,
8968
- leading: leadingIcon(r.icon)
8969
- }));
8970
- const surface = {
8971
- kind: "list",
8972
- id: "uidex-close-reason",
8973
- searchable: false,
8974
- items,
8975
- emptyLabel: "No reasons available",
8976
- onSelect: async (item) => {
8977
- if (busy || !pendingReportId || !ctx.registry.closeReport) return;
8978
- busy = true;
8979
- const row = root.querySelector(
8980
- `[data-uidex-item-value="${item.value}"]`
8981
- );
8982
- const existingTile = row?.querySelector("[data-slot='icon-tile']");
8983
- if (row && existingTile) {
8984
- existingTile.replaceWith(spinnerTile());
8985
- row.style.opacity = "0.6";
8986
- row.style.pointerEvents = "none";
8987
- }
8988
- try {
8989
- await ctx.registry.closeReport(pendingReportId, item.value);
8990
- const done = afterClose;
8991
- pendingReportId = null;
8992
- afterClose = null;
8993
- done?.();
8994
- } catch {
8995
- busy = false;
8996
- if (row) {
8997
- row.style.opacity = "";
8998
- row.style.pointerEvents = "";
8999
- const reason = REASONS.find((r) => r.value === item.value);
9000
- if (reason) {
9001
- const tile = row.querySelector("[data-slot='icon-tile']");
9002
- if (tile)
9003
- tile.replaceWith(
9004
- createIconTile((0, import_lucide11.createElement)(reason.icon))
9005
- );
9006
- }
9007
- }
9008
- const error = document.createElement("p");
9009
- error.className = "text-destructive px-4 py-2 text-xs";
9010
- error.textContent = "Close failed \u2014 try again";
9011
- root.querySelector("[data-uidex-list-content]")?.prepend(error);
9012
- setTimeout(() => error.remove(), 3e3);
9013
- }
9014
- }
9015
- };
9016
- const mounted = renderListSurface(surface, ctx, root);
9017
- return mounted.cleanup;
9018
- }
9019
- };
9020
6849
 
9021
6850
  // src/browser/views/built-in/command-palette.ts
9022
- var import_lucide12 = require("lucide");
6851
+ var import_lucide9 = require("lucide");
9023
6852
 
9024
6853
  // src/browser/views/builder/format-location.ts
9025
6854
  function formatLocation(loc) {
@@ -9058,9 +6887,6 @@ function findCurrentRoute(registry) {
9058
6887
  function findCurrentPageId(ctx) {
9059
6888
  return findCurrentRoute(ctx.registry)?.page ?? null;
9060
6889
  }
9061
- function findCurrentRoutePath(registry) {
9062
- return findCurrentRoute(registry)?.path ?? null;
9063
- }
9064
6890
  function buildPageRouteMap(ctx) {
9065
6891
  const map = /* @__PURE__ */ new Map();
9066
6892
  for (const route of ctx.registry.list("route")) {
@@ -9111,7 +6937,7 @@ function openAction(onSelect) {
9111
6937
  return {
9112
6938
  id: "open",
9113
6939
  label: "Open",
9114
- icon: () => (0, import_lucide12.createElement)(import_lucide12.ExternalLink),
6940
+ icon: () => (0, import_lucide9.createElement)(import_lucide9.ExternalLink),
9115
6941
  perform: onSelect
9116
6942
  };
9117
6943
  }
@@ -9121,7 +6947,7 @@ function favoriteAction(ref2, ctx) {
9121
6947
  id: "toggle-favorite",
9122
6948
  label: isFav ? "Remove from Favorites" : "Add to Favorites",
9123
6949
  shortcut: "\u21E7\u2318F",
9124
- icon: () => (0, import_lucide12.createElement)(isFav ? import_lucide12.StarOff : import_lucide12.Star),
6950
+ icon: () => (0, import_lucide9.createElement)(isFav ? import_lucide9.StarOff : import_lucide9.Star),
9125
6951
  perform: () => {
9126
6952
  ctx.views.toggleFavorite(ref2);
9127
6953
  ctx.close();
@@ -9137,7 +6963,7 @@ function entityActions(ref2, entity, ctx, onSelect) {
9137
6963
  actions.push({
9138
6964
  id: "copy-path",
9139
6965
  label: "Copy Source Path",
9140
- icon: () => (0, import_lucide12.createElement)(import_lucide12.Copy),
6966
+ icon: () => (0, import_lucide9.createElement)(import_lucide9.Copy),
9141
6967
  async perform() {
9142
6968
  try {
9143
6969
  await navigator.clipboard.writeText(path);
@@ -9147,20 +6973,6 @@ function entityActions(ref2, entity, ctx, onSelect) {
9147
6973
  });
9148
6974
  }
9149
6975
  }
9150
- actions.push({
9151
- id: "submit-report",
9152
- label: "Report",
9153
- icon: () => (0, import_lucide12.createElement)(import_lucide12.MessageCircleWarning),
9154
- perform: () => ctx.push({ id: BUILT_IN_VIEW_IDS.report, ref: ref2 })
9155
- });
9156
- if (ctx.cloud?.integrations.getCachedConfig()?.hasJira) {
9157
- actions.push({
9158
- id: "create-jira-issue",
9159
- label: "Create Jira Ticket",
9160
- icon: () => (0, import_lucide12.createElement)(import_lucide12.TicketPlus),
9161
- perform: () => ctx.push({ id: BUILT_IN_VIEW_IDS.jiraReport, ref: ref2 })
9162
- });
9163
- }
9164
6976
  actions.push(favoriteAction(ref2, ctx));
9165
6977
  return actions;
9166
6978
  }
@@ -9193,7 +7005,7 @@ function explorePageRow(totalOnPage, ctx) {
9193
7005
  subtitle: totalOnPage === 1 ? "1 item" : `${totalOnPage} items`,
9194
7006
  group: CURRENT_PAGE_GROUP,
9195
7007
  tag: BUILT_IN_VIEW_IDS.explorePage,
9196
- leading: () => (0, import_lucide12.createElement)(import_lucide12.Compass),
7008
+ leading: () => (0, import_lucide9.createElement)(import_lucide9.Compass),
9197
7009
  actions: viewActions(onSelect),
9198
7010
  payload: { type: "view", id: BUILT_IN_VIEW_IDS.explorePage }
9199
7011
  };
@@ -9258,7 +7070,7 @@ function createCommandPaletteView(shortcut) {
9258
7070
  group: PALETTE_GROUPS.favorites,
9259
7071
  preview: ref2,
9260
7072
  entityChip: { entity },
9261
- leading: () => (0, import_lucide12.createElement)(style.icon),
7073
+ leading: () => (0, import_lucide9.createElement)(style.icon),
9262
7074
  actions: entityActions(ref2, entity, ctx, onSelect),
9263
7075
  payload: { type: "entity", ref: ref2 }
9264
7076
  });
@@ -9283,7 +7095,7 @@ function createCommandPaletteView(shortcut) {
9283
7095
  group: PALETTE_GROUPS.recents,
9284
7096
  preview: ref2,
9285
7097
  entityChip: { entity },
9286
- leading: () => (0, import_lucide12.createElement)(style.icon),
7098
+ leading: () => (0, import_lucide9.createElement)(style.icon),
9287
7099
  actions: entityActions(ref2, entity, ctx, onSelect),
9288
7100
  payload: { type: "entity", ref: ref2 }
9289
7101
  });
@@ -9365,14 +7177,14 @@ async function captureScreenshot(options = {}) {
9365
7177
  }
9366
7178
 
9367
7179
  // src/browser/report/capture.ts
9368
- function captureReportContext(opts) {
7180
+ function captureReportContext() {
9369
7181
  const nav = typeof navigator !== "undefined" ? navigator : void 0;
9370
7182
  const loc = typeof location !== "undefined" ? location : void 0;
9371
7183
  const win = typeof window !== "undefined" ? window : void 0;
9372
7184
  const doc = typeof document !== "undefined" ? document : void 0;
9373
7185
  return {
9374
7186
  url: loc?.href ?? "",
9375
- route: opts?.getRoute?.() ?? loc?.pathname,
7187
+ route: loc?.pathname,
9376
7188
  userAgent: nav?.userAgent ?? "",
9377
7189
  pageTitle: doc?.title,
9378
7190
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
@@ -9424,46 +7236,6 @@ function copyPathAction(ref2, loc) {
9424
7236
  intent: { kind: "external", describe: "clipboard" }
9425
7237
  };
9426
7238
  }
9427
- function reportAction(ref2) {
9428
- return {
9429
- id: "submit-report",
9430
- label: "Report",
9431
- icon: "message-circle-warning",
9432
- push: { id: BUILT_IN_VIEW_IDS.report, ref: ref2 },
9433
- intent: {
9434
- kind: "push",
9435
- viewId: BUILT_IN_VIEW_IDS.report,
9436
- refKind: ref2.kind
9437
- }
9438
- };
9439
- }
9440
- function viewReportsAction(ref2, count) {
9441
- return {
9442
- id: "view-reports",
9443
- label: "View Reports",
9444
- icon: "inbox",
9445
- hint: count != null ? count === 1 ? "1 item" : `${count} items` : void 0,
9446
- push: { id: BUILT_IN_VIEW_IDS.entityReports, ref: ref2 },
9447
- intent: {
9448
- kind: "push",
9449
- viewId: BUILT_IN_VIEW_IDS.entityReports,
9450
- refKind: ref2.kind
9451
- }
9452
- };
9453
- }
9454
- function jiraAction(ref2) {
9455
- return {
9456
- id: "create-jira-issue",
9457
- label: "Create Jira Ticket",
9458
- icon: "ticket-plus",
9459
- push: { id: BUILT_IN_VIEW_IDS.jiraReport, ref: ref2 },
9460
- intent: {
9461
- kind: "push",
9462
- viewId: BUILT_IN_VIEW_IDS.jiraReport,
9463
- refKind: ref2.kind
9464
- }
9465
- };
9466
- }
9467
7239
  function buildSnapshotMarkdown(ref2, loc) {
9468
7240
  const snapshot = captureReportContext();
9469
7241
  const sourcePath = formatLocation(loc);
@@ -9554,18 +7326,6 @@ function createEntityDetailView(config) {
9554
7326
  const metaEntity = entity ? entity : null;
9555
7327
  const meta = metaEntity?.meta;
9556
7328
  const actions = [];
9557
- const cloud = ctx.cloud;
9558
- actions.push({ ...reportAction(ctx.ref), group: "Report" });
9559
- const reportCount = ctx.registry.getReports(kind, ctx.ref.id).length;
9560
- if (reportCount > 0) {
9561
- actions.push({
9562
- ...viewReportsAction(ctx.ref, reportCount),
9563
- group: "Report"
9564
- });
9565
- }
9566
- if (cloud?.integrations.getCachedConfig()?.hasJira) {
9567
- actions.push({ ...jiraAction(ctx.ref), group: "Report" });
9568
- }
9569
7329
  if (DOM_BACKED_KINDS.has(kind) && resolveEntityElement(ctx.ref)) {
9570
7330
  actions.push({ ...highlightElementAction(ctx.ref), group: "Inspect" });
9571
7331
  actions.push({ ...copyScreenshotAction(ctx.ref), group: "Inspect" });
@@ -9751,157 +7511,8 @@ var primitivesView = createEntityKindListView(
9751
7511
  BUILT_IN_VIEW_IDS.primitives
9752
7512
  );
9753
7513
 
9754
- // src/browser/views/built-in/report-detail.ts
9755
- var selectedId = null;
9756
- function setSelectedReportId(id) {
9757
- selectedId = id;
9758
- }
9759
- function findReport(ctx) {
9760
- if (!ctx.ref || !selectedId) return null;
9761
- const reports = ctx.registry.getReports(ctx.ref.kind, ctx.ref.id);
9762
- return reports.find((r) => r.id === selectedId) ?? null;
9763
- }
9764
- var reportDetailView = {
9765
- id: BUILT_IN_VIEW_IDS.reportDetail,
9766
- matches: () => false,
9767
- parent: (ref2) => ({ id: BUILT_IN_VIEW_IDS.entityReports, ref: ref2 }),
9768
- searchable: false,
9769
- focusTarget: (host) => host.querySelector(
9770
- "[data-uidex-detail-actions] [data-uidex-detail-action]"
9771
- ),
9772
- surface: (ctx) => {
9773
- const report = findReport(ctx);
9774
- if (!report) {
9775
- return {
9776
- kind: "detail",
9777
- entityKind: ctx.ref?.kind ?? "element",
9778
- notFound: ctx.ref ?? void 0
9779
- };
9780
- }
9781
- const typeLabel = TYPE_LABELS[report.type] ?? report.type;
9782
- const sevLabel = SEVERITY_LABELS[report.severity] ?? report.severity;
9783
- const sections = [];
9784
- if (report.body) {
9785
- sections.push({ id: "description", text: report.body });
9786
- }
9787
- if (report.screenshot) {
9788
- sections.push({ id: "screenshot", url: report.screenshot });
9789
- } else {
9790
- const pins = ctx.cloud?.pins;
9791
- const fetchScreenshot = pins?.screenshot;
9792
- if (pins && fetchScreenshot) {
9793
- sections.push({
9794
- id: "screenshot",
9795
- load: () => fetchScreenshot.call(pins, report.id)
9796
- });
9797
- }
9798
- }
9799
- const metaEntries = [];
9800
- if (report.url) metaEntries.push({ label: "URL", value: report.url });
9801
- if (report.route) metaEntries.push({ label: "Route", value: report.route });
9802
- if (report.pageTitle)
9803
- metaEntries.push({ label: "Page", value: report.pageTitle });
9804
- if (metaEntries.length > 0) {
9805
- sections.push({ id: "metadata", entries: metaEntries });
9806
- }
9807
- const actions = [];
9808
- if (ctx.registry.closeReport) {
9809
- actions.push({
9810
- id: "close",
9811
- label: "Close",
9812
- icon: "archive-x",
9813
- run: () => {
9814
- setCloseTarget(report.id, () => ctx.pop());
9815
- ctx.push({ id: BUILT_IN_VIEW_IDS.closeReason });
9816
- }
9817
- });
9818
- }
9819
- if (report.url) {
9820
- actions.push({
9821
- id: "open-url",
9822
- label: "Open URL",
9823
- icon: "copy",
9824
- copy: report.url
9825
- });
9826
- }
9827
- return {
9828
- kind: "detail",
9829
- entityKind: ctx.ref?.kind ?? "element",
9830
- title: report.title || "(no title)",
9831
- subtitle: {
9832
- rawId: [
9833
- typeLabel,
9834
- sevLabel,
9835
- authorLabel(report),
9836
- relativeTime(report.createdAt)
9837
- ].filter(Boolean).join(" \xB7 ")
9838
- },
9839
- actions,
9840
- sections
9841
- };
9842
- }
9843
- };
9844
-
9845
- // src/browser/views/built-in/entity-reports.ts
9846
- function reportToItem(report, ctx) {
9847
- const typeLabel = TYPE_LABELS[report.type] ?? report.type;
9848
- const sevLabel = SEVERITY_LABELS[report.severity] ?? report.severity;
9849
- const raw = report.title || report.body;
9850
- const label = raw.length > 80 ? raw.slice(0, 80) + "\u2026" : raw;
9851
- const kind = ctx.ref?.kind ?? "element";
9852
- const actions = [];
9853
- if (ctx.registry.closeReport) {
9854
- actions.push({
9855
- id: `close-${report.id}`,
9856
- label: "Close",
9857
- perform: () => {
9858
- setCloseTarget(report.id, () => ctx.pop());
9859
- ctx.push({ id: BUILT_IN_VIEW_IDS.closeReason });
9860
- }
9861
- });
9862
- }
9863
- return {
9864
- value: `report:${report.id}`,
9865
- label: label || "(no description)",
9866
- subtitle: [
9867
- authorLabel(report),
9868
- typeLabel,
9869
- sevLabel,
9870
- relativeTime(report.createdAt)
9871
- ].filter(Boolean).join(" \xB7 "),
9872
- tag: `report:${report.id}`,
9873
- leading: () => renderKindIcon(kind),
9874
- actions
9875
- };
9876
- }
9877
- var entityReportsView = {
9878
- id: BUILT_IN_VIEW_IDS.entityReports,
9879
- matches: () => false,
9880
- parent: parentDetail,
9881
- title: "Reports",
9882
- searchable: true,
9883
- hints: [{ key: "\u21B5", label: "Select" }],
9884
- focusTarget: () => null,
9885
- surface: (ctx) => {
9886
- const ref2 = ctx.ref;
9887
- const reports = ref2 ? ctx.registry.getReports(ref2.kind, ref2.id) : [];
9888
- const items = reports.map((r) => reportToItem(r, ctx));
9889
- return {
9890
- kind: "list",
9891
- id: "uidex-entity-reports",
9892
- items,
9893
- emptyLabel: "No reports for this element",
9894
- filter: (item, query) => matchesQuery(`${item.label} ${item.subtitle ?? ""}`, query),
9895
- onSelect: (item) => {
9896
- setSelectedReportId(item.value.replace(/^report:/, ""));
9897
- ctx.push({ id: BUILT_IN_VIEW_IDS.reportDetail, ref: ref2 });
9898
- }
9899
- };
9900
- }
9901
- };
9902
-
9903
7514
  // src/browser/views/built-in/explore-page.ts
9904
- var import_lucide13 = require("lucide");
7515
+ var import_lucide10 = require("lucide");
9905
7516
  var KIND_ORDER = new Map(
9906
7517
  ENTITY_KINDS.map((kind, index) => [kind, index])
9907
7518
  );
@@ -9943,7 +7554,7 @@ var explorePageView = {
9943
7554
  palette: {
9944
7555
  label: "Explore Page",
9945
7556
  shortcut: "",
9946
- icon: () => (0, import_lucide13.createElement)(import_lucide13.Compass)
7557
+ icon: () => (0, import_lucide10.createElement)(import_lucide10.Compass)
9947
7558
  },
9948
7559
  title: "Explore Page",
9949
7560
  hints: [{ key: "\u21B5", label: "Select" }],
@@ -9978,332 +7589,6 @@ var explorePageView = {
9978
7589
  }
9979
7590
  };
9980
7591
 
9981
- // src/browser/internal/clipboard.ts
9982
- async function copyToClipboard(text) {
9983
- try {
9984
- if (typeof navigator !== "undefined" && navigator.clipboard?.writeText) {
9985
- await navigator.clipboard.writeText(text);
9986
- return true;
9987
- }
9988
- } catch {
9989
- }
9990
- try {
9991
- if (typeof document === "undefined") return false;
9992
- const textarea = document.createElement("textarea");
9993
- textarea.value = text;
9994
- textarea.setAttribute("readonly", "");
9995
- textarea.style.position = "fixed";
9996
- textarea.style.opacity = "0";
9997
- document.body.appendChild(textarea);
9998
- textarea.select();
9999
- const ok = document.execCommand("copy");
10000
- document.body.removeChild(textarea);
10001
- return ok;
10002
- } catch {
10003
- return false;
10004
- }
10005
- }
10006
-
10007
- // src/browser/views/built-in/report/markdown.ts
10008
- function capitalize2(s) {
10009
- return s.length === 0 ? s : s[0].toUpperCase() + s.slice(1);
10010
- }
10011
- function renderPayloadMarkdown(payload) {
10012
- const heading = payload.title ?? `${capitalize2(payload.type ?? "")} Report`;
10013
- const ctx = payload.context;
10014
- const lines = [
10015
- `# ${heading}`,
10016
- "",
10017
- `- **Type:** ${payload.type}`,
10018
- ...payload.severity ? [`- **Severity:** ${payload.severity}`] : [],
10019
- `- **Entity:** \`${payload.entity}\``,
10020
- "",
10021
- "#### Description",
10022
- payload.body || "_(no description)_",
10023
- "",
10024
- "#### Context",
10025
- `- **URL:** ${ctx?.url}`,
10026
- ...ctx?.pageTitle ? [`- **Page title:** ${ctx.pageTitle}`] : [],
10027
- `- **Viewport:** ${ctx?.viewport.w}\xD7${ctx?.viewport.h}`,
10028
- `- **User agent:** ${ctx?.userAgent}`,
10029
- `- **Timestamp:** ${ctx?.timestamp}`
10030
- ];
10031
- return lines.join("\n") + "\n";
10032
- }
10033
-
10034
- // src/browser/views/built-in/report/schema.ts
10035
- var import_zod = require("zod");
10036
- var reportSchema = import_zod.z.object({
10037
- type: import_zod.z.enum(["bug", "request", "suggestion"]),
10038
- severity: import_zod.z.enum(["low", "medium", "high", "critical"]).optional(),
10039
- title: import_zod.z.string().optional(),
10040
- body: import_zod.z.string().trim().min(1, { message: "Description is required." })
10041
- });
10042
- var reportFields = [
10043
- {
10044
- kind: "select",
10045
- name: "type",
10046
- label: "Type",
10047
- options: [
10048
- { value: "bug", label: "Bug" },
10049
- { value: "request", label: "Request" },
10050
- { value: "suggestion", label: "Suggestion" }
10051
- ]
10052
- },
10053
- {
10054
- kind: "select",
10055
- name: "severity",
10056
- label: "Severity",
10057
- value: "medium",
10058
- options: [
10059
- { value: "low", label: "Low" },
10060
- { value: "medium", label: "Medium" },
10061
- { value: "high", label: "High" },
10062
- { value: "critical", label: "Critical" }
10063
- ]
10064
- },
10065
- {
10066
- kind: "text",
10067
- name: "title",
10068
- label: "Title",
10069
- placeholder: "Short summary (optional)"
10070
- },
10071
- {
10072
- kind: "textarea",
10073
- name: "body",
10074
- label: "Description",
10075
- placeholder: "Describe what happened\u2026",
10076
- required: true
10077
- }
10078
- ];
10079
-
10080
- // src/browser/views/built-in/report/view-builder.ts
10081
- var KIND_TO_ATTR = new Map(
10082
- UIDEX_ATTR_TO_KIND.map(([attr, kind]) => [kind, attr])
10083
- );
10084
- function resolveElement(ref2) {
10085
- const attr = KIND_TO_ATTR.get(ref2.kind);
10086
- if (!attr) return null;
10087
- return document.querySelector(
10088
- `[${attr}="${CSS.escape(ref2.id)}"]`
10089
- );
10090
- }
10091
- function buildPayload(ctx, componentId, values, prefix, augmentPayload, screenshot) {
10092
- const context = captureReportContext({ getRoute: ctx.getRoute });
10093
- const title = String(values.title ?? "").trim();
10094
- const body = String(values.body ?? "").trim();
10095
- const reporter = ctx.user ? { id: ctx.user.id, name: ctx.user.name || void 0 } : void 0;
10096
- const payload = {
10097
- type: values.type ?? "bug",
10098
- severity: values.severity ?? "medium",
10099
- title: title || void 0,
10100
- body: prefix ? `${prefix}${body}` : body,
10101
- entity: componentId,
10102
- screenshot,
10103
- context,
10104
- reporter,
10105
- metadata: ctx.user ? { userId: ctx.user.id } : void 0
10106
- };
10107
- return augmentPayload ? augmentPayload(payload, ctx, values) : payload;
10108
- }
10109
- async function copyFallback(payload) {
10110
- const markdown = renderPayloadMarkdown(payload);
10111
- const copied = await copyToClipboard(markdown);
10112
- if (!copied) console.log("[uidex] report markdown:\n" + markdown);
10113
- return {
10114
- status: copied ? "success" : "error",
10115
- message: copied ? "Copied to clipboard" : "Copy failed"
10116
- };
10117
- }
10118
- function createReportView(config) {
10119
- const {
10120
- id,
10121
- resolveCloud,
10122
- componentId,
10123
- submitLabels,
10124
- successToast,
10125
- failureToast,
10126
- prependDescription,
10127
- baseFields,
10128
- extraFields,
10129
- augmentPayload,
10130
- successResult,
10131
- schema: schemaOverride
10132
- } = config;
10133
- return {
10134
- id,
10135
- matches: () => false,
10136
- parent: parentDetail,
10137
- searchable: false,
10138
- hints: (ctx) => [
10139
- {
10140
- key: "\u2318\u21B5",
10141
- label: resolveCloud(ctx) ? submitLabels.ready : submitLabels.noCloud
10142
- }
10143
- ],
10144
- focusTarget: (host) => host.querySelector(
10145
- "[data-uidex-form='report'] select, [data-uidex-form='report'] input, [data-uidex-form='report'] textarea"
10146
- ),
10147
- surface: (ctx) => {
10148
- const cloud = resolveCloud(ctx);
10149
- const extra = extraFields ? extraFields(ctx) : [];
10150
- const fields = [...extra, ...baseFields ?? reportFields];
10151
- const isDomBacked = ctx.ref != null && DOM_BACKED_KINDS.has(ctx.ref.kind);
10152
- const targetEl = ctx.ref && isDomBacked ? resolveElement(ctx.ref) : null;
10153
- const screenshotPromise = isDomBacked ? captureScreenshot({
10154
- target: targetEl ?? void 0,
10155
- maxWidth: 1280
10156
- }).catch(() => null) : null;
10157
- return {
10158
- kind: "form",
10159
- id: "report",
10160
- fields,
10161
- schema: schemaOverride ?? reportSchema,
10162
- screenshotPreview: screenshotPromise ? screenshotPromise : void 0,
10163
- submit: {
10164
- label: cloud ? submitLabels.ready : submitLabels.noCloud,
10165
- onSubmit: async (values) => {
10166
- const screenshot = await screenshotPromise ?? void 0;
10167
- const prefix = prependDescription ? prependDescription() : "";
10168
- const payload = buildPayload(
10169
- ctx,
10170
- componentId(ctx),
10171
- values,
10172
- prefix,
10173
- augmentPayload,
10174
- screenshot
10175
- );
10176
- if (!cloud) {
10177
- return copyFallback(payload);
10178
- }
10179
- try {
10180
- const result = await cloud.reports.submit(
10181
- payload
10182
- );
10183
- ctx.onAfterSubmit?.();
10184
- if (successResult) return successResult(result);
10185
- return {
10186
- status: "success",
10187
- message: successToast(result)
10188
- };
10189
- } catch (err) {
10190
- const message = err instanceof Error ? err.message : String(err);
10191
- return {
10192
- status: "error",
10193
- message: failureToast(err) ?? message
10194
- };
10195
- }
10196
- }
10197
- }
10198
- };
10199
- }
10200
- };
10201
- }
10202
-
10203
- // src/browser/views/built-in/report/host-report.ts
10204
- var reportView = createReportView({
10205
- id: BUILT_IN_VIEW_IDS.report,
10206
- resolveCloud: (ctx) => ctx.cloud,
10207
- componentId: (ctx) => ctx.ref ? `${ctx.ref.kind}:${ctx.ref.id}` : "unknown",
10208
- submitLabels: { ready: "Report", noCloud: "Copy Report" },
10209
- successToast: (result) => {
10210
- const ticketKey = result.externalLink?.ok && result.externalLink.key ? result.externalLink.key : null;
10211
- return ticketKey ? `Report submitted (${ticketKey})` : "Report submitted";
10212
- },
10213
- failureToast: (err) => {
10214
- const message = err instanceof Error ? err.message : String(err);
10215
- return `Failed: ${message}`;
10216
- }
10217
- });
10218
-
10219
- // src/browser/views/built-in/report/jira-report.ts
10220
- var jiraSchema = reportSchema.omit({ type: true });
10221
- var jiraBaseFields = reportFields.filter(
10222
- (f) => f.name !== "type" && f.name !== "severity"
10223
- );
10224
- function buildParentIssueField(config) {
10225
- const issues = config.parentIssues ?? [];
10226
- const options = [
10227
- { value: "", label: "None" }
10228
- ];
10229
- const byType = /* @__PURE__ */ new Map();
10230
- for (const issue of issues) {
10231
- const group = byType.get(issue.issueType) ?? [];
10232
- group.push(issue);
10233
- byType.set(issue.issueType, group);
10234
- }
10235
- for (const [type, group] of byType) {
10236
- for (const issue of group) {
10237
- options.push({
10238
- value: issue.key,
10239
- label: `[${type}] ${issue.key}: ${issue.summary}`
10240
- });
10241
- }
10242
- }
10243
- return {
10244
- kind: "select",
10245
- name: "parentIssue",
10246
- label: "Parent Issue",
10247
- options
10248
- };
10249
- }
10250
- var jiraReportView = createReportView({
10251
- id: BUILT_IN_VIEW_IDS.jiraReport,
10252
- resolveCloud: (ctx) => ctx.cloud,
10253
- componentId: (ctx) => ctx.ref ? `${ctx.ref.kind}:${ctx.ref.id}` : "unknown",
10254
- submitLabels: { ready: "Create Jira Ticket", noCloud: "Copy report" },
10255
- schema: jiraSchema,
10256
- baseFields: jiraBaseFields,
10257
- extraFields: (ctx) => {
10258
- const cloud = ctx.cloud;
10259
- const config = cloud?.integrations.getCachedConfig() ?? null;
10260
- if (!config?.hasJira) return [];
10261
- return [buildParentIssueField(config)];
10262
- },
10263
- augmentPayload: (payload, ctx, values) => {
10264
- const cloud = ctx.cloud;
10265
- const config = cloud?.integrations.getCachedConfig() ?? null;
10266
- if (!config?.hasJira || !config.integrationId) return payload;
10267
- const targetConfig = {};
10268
- const parentKey = values.parentIssue;
10269
- if (parentKey) {
10270
- const issue = config.parentIssues?.find((i) => i.key === parentKey);
10271
- if (issue) targetConfig.epicId = issue.id;
10272
- }
10273
- return {
10274
- ...payload,
10275
- type: "bug",
10276
- suggestedTarget: {
10277
- integrationId: config.integrationId,
10278
- targetConfig
10279
- }
10280
- };
10281
- },
10282
- successResult: (result) => {
10283
- const link = result.externalLink;
10284
- if (link?.ok && link.key) {
10285
- return {
10286
- status: "success",
10287
- message: `Created ${link.key}`,
10288
- link: link.url ? { url: link.url, label: link.key } : void 0
10289
- };
10290
- }
10291
- return {
10292
- status: "error",
10293
- message: "Report saved \u2014 Jira issue creation failed"
10294
- };
10295
- },
10296
- successToast: (result) => {
10297
- const link = result.externalLink;
10298
- if (link?.ok && link.key) return `Created ${link.key}`;
10299
- return "Report saved \u2014 Jira Bug failed";
10300
- },
10301
- failureToast: (err) => {
10302
- const message = err instanceof Error ? err.message : String(err);
10303
- return `Failed to create issue: ${message}`;
10304
- }
10305
- });
10306
-
10307
7592
  // src/browser/views/built-in/flow-detail.ts
10308
7593
  var STEP_KINDS = [
10309
7594
  "element",
@@ -10335,8 +7620,7 @@ var flowDetailView = {
10335
7620
  }
10336
7621
  const actions = [
10337
7622
  copyPathAction(ctx.ref, flow.loc),
10338
- copySnapshotAction(ctx.ref, flow.loc),
10339
- reportAction(ctx.ref)
7623
+ copySnapshotAction(ctx.ref, flow.loc)
10340
7624
  ];
10341
7625
  const sections = [
10342
7626
  flow.steps.length > 0 ? buildStepsSection(flow.steps, ctx.registry) : buildTouchesSection(flow, ctx.registry)
@@ -10426,7 +7710,7 @@ var flowsView = {
10426
7710
  };
10427
7711
 
10428
7712
  // src/browser/views/built-in/glossary.ts
10429
- var import_lucide14 = require("lucide");
7713
+ var import_lucide11 = require("lucide");
10430
7714
  var KIND_TO_VIEW = {
10431
7715
  element: BUILT_IN_VIEW_IDS.elements,
10432
7716
  widget: BUILT_IN_VIEW_IDS.widgets,
@@ -10463,7 +7747,7 @@ var glossaryView = {
10463
7747
  palette: {
10464
7748
  label: "Glossary",
10465
7749
  group: PALETTE_GROUPS.commands,
10466
- icon: () => (0, import_lucide14.createElement)(import_lucide14.BookOpen)
7750
+ icon: () => (0, import_lucide11.createElement)(import_lucide11.BookOpen)
10467
7751
  },
10468
7752
  title: "Glossary",
10469
7753
  hints: [{ key: "\u21B5", label: "Select" }],
@@ -10492,240 +7776,9 @@ var glossaryView = {
10492
7776
  }
10493
7777
  };
10494
7778
 
10495
- // src/browser/views/built-in/page-reports.ts
10496
- var import_lucide15 = require("lucide");
10497
- function collectPageReports(ctx) {
10498
- const items = [];
10499
- const seenReportIds = /* @__PURE__ */ new Set();
10500
- for (const kind of ENTITY_KINDS) {
10501
- for (const entity of ctx.registry.list(kind)) {
10502
- const id = "id" in entity ? entity.id : "";
10503
- if (!id) continue;
10504
- const reports = ctx.registry.getReports(kind, id);
10505
- seenReportIds.add(`${kind}:${id}`);
10506
- const ref2 = { kind, id };
10507
- for (const report of reports) {
10508
- const typeLabel = TYPE_LABELS[report.type] ?? report.type;
10509
- const sevLabel = SEVERITY_LABELS[report.severity] ?? report.severity;
10510
- const raw = report.title || report.body;
10511
- const label = raw.length > 80 ? raw.slice(0, 80) + "\u2026" : raw;
10512
- const entityName = displayName(entity);
10513
- items.push({
10514
- value: `report:${report.id}`,
10515
- label: label || "(no description)",
10516
- subtitle: [
10517
- entityName,
10518
- authorLabel(report),
10519
- typeLabel,
10520
- sevLabel,
10521
- relativeTime(report.createdAt)
10522
- ].filter(Boolean).join(" \xB7 "),
10523
- tag: `report:${report.id}`,
10524
- group: `${kind}: ${entityName}`,
10525
- leading: () => renderKindIcon(kind),
10526
- ref: ref2
10527
- });
10528
- }
10529
- }
10530
- }
10531
- for (const key of ctx.registry.listReportKeys()) {
10532
- if (seenReportIds.has(key)) continue;
10533
- const parsed = parseComponentRef(key);
10534
- if (ctx.registry.get(parsed.kind, parsed.id)) continue;
10535
- const reports = ctx.registry.getReports(parsed.kind, parsed.id);
10536
- const ref2 = parsed;
10537
- for (const report of reports) {
10538
- const typeLabel = TYPE_LABELS[report.type] ?? report.type;
10539
- const sevLabel = SEVERITY_LABELS[report.severity] ?? report.severity;
10540
- const raw = report.title || report.body;
10541
- const label = raw.length > 80 ? raw.slice(0, 80) + "\u2026" : raw;
10542
- items.push({
10543
- value: `report:${report.id}`,
10544
- label: label || "(no description)",
10545
- subtitle: [
10546
- `${parsed.kind}:${parsed.id}`,
10547
- authorLabel(report),
10548
- typeLabel,
10549
- sevLabel,
10550
- relativeTime(report.createdAt)
10551
- ].filter(Boolean).join(" \xB7 "),
10552
- tag: `report:${report.id}`,
10553
- group: "Orphaned",
10554
- leading: () => (0, import_lucide15.createElement)(import_lucide15.CircleOff),
10555
- ref: ref2
10556
- });
10557
- }
10558
- }
10559
- return items;
10560
- }
10561
- var pageReportsView = {
10562
- id: BUILT_IN_VIEW_IDS.pageReports,
10563
- matches: () => false,
10564
- parent: () => COMMAND_PALETTE_ENTRY2,
10565
- palette: {
10566
- label: "Page Reports",
10567
- group: "Current Page",
10568
- icon: () => (0, import_lucide15.createElement)(import_lucide15.Inbox)
10569
- },
10570
- title: "Page Reports",
10571
- searchable: true,
10572
- hints: [{ key: "\u21B5", label: "Select" }],
10573
- focusTarget: () => null,
10574
- surface: (ctx) => {
10575
- const items = collectPageReports(ctx);
10576
- return {
10577
- kind: "list",
10578
- id: "uidex-page-reports",
10579
- items,
10580
- emptyLabel: "No reports on this page",
10581
- filter: (item, query) => matchesQuery(
10582
- `${item.label} ${item.subtitle ?? ""} ${item.group ?? ""}`,
10583
- query
10584
- ),
10585
- onSelect: (item) => {
10586
- setSelectedReportId(item.value.replace(/^report:/, ""));
10587
- ctx.push({
10588
- id: BUILT_IN_VIEW_IDS.reportDetail,
10589
- ref: item.ref
10590
- });
10591
- }
10592
- };
10593
- }
10594
- };
10595
-
10596
- // src/browser/views/built-in/pin-settings.ts
10597
- var import_lucide16 = require("lucide");
10598
-
10599
- // src/browser/ui/toast.ts
10600
- function showCopiedToast(message) {
10601
- if (typeof document === "undefined") return;
10602
- const dark = isDarkMode();
10603
- const toast = document.createElement("div");
10604
- toast.setAttribute("data-uidex-toast", "");
10605
- Object.assign(toast.style, {
10606
- position: "fixed",
10607
- top: "50%",
10608
- left: "50%",
10609
- transform: "translate(-50%, -50%) scale(0.96)",
10610
- padding: "12px 20px",
10611
- fontSize: "14px",
10612
- fontFamily: "ui-sans-serif, system-ui, sans-serif",
10613
- fontWeight: "500",
10614
- color: dark ? "#0a0a0a" : "#fafafa",
10615
- background: dark ? "rgba(255, 255, 255, 0.98)" : "rgba(28, 28, 30, 0.95)",
10616
- border: dark ? "1px solid rgba(0, 0, 0, 0.08)" : "1px solid rgba(255, 255, 255, 0.08)",
10617
- borderRadius: "10px",
10618
- 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)",
10619
- zIndex: "2147483647",
10620
- pointerEvents: "none",
10621
- opacity: "0",
10622
- transition: "opacity 120ms ease-out, transform 160ms ease-out",
10623
- whiteSpace: "nowrap"
10624
- });
10625
- toast.textContent = message;
10626
- document.body.appendChild(toast);
10627
- requestAnimationFrame(() => {
10628
- toast.style.opacity = "1";
10629
- toast.style.transform = "translate(-50%, -50%) scale(1)";
10630
- });
10631
- setTimeout(() => {
10632
- toast.style.opacity = "0";
10633
- toast.style.transform = "translate(-50%, -50%) scale(0.96)";
10634
- setTimeout(() => toast.remove(), 200);
10635
- }, 1200);
10636
- }
10637
-
10638
- // src/browser/views/built-in/pin-settings.ts
10639
- var MATCH_MODE_KEY = "uidex:pin-match-mode";
10640
- function readMode() {
10641
- try {
10642
- const v = localStorage.getItem(MATCH_MODE_KEY);
10643
- if (v === "route" || v === "pathname" || v === "component") return v;
10644
- } catch {
10645
- }
10646
- return "route";
10647
- }
10648
- function writeMode(mode) {
10649
- try {
10650
- localStorage.setItem(MATCH_MODE_KEY, mode);
10651
- } catch {
10652
- }
10653
- }
10654
- var MODES = [
10655
- {
10656
- value: "route",
10657
- label: "By route",
10658
- description: "Pins from any URL matching this route pattern",
10659
- icon: import_lucide16.Globe
10660
- },
10661
- {
10662
- value: "pathname",
10663
- label: "By pathname",
10664
- description: "Pins from this exact URL path",
10665
- icon: import_lucide16.MapPin
10666
- },
10667
- {
10668
- value: "component",
10669
- label: "By component",
10670
- description: "All pins for components on this page",
10671
- icon: import_lucide16.Settings
10672
- }
10673
- ];
10674
- function leadingIcon2(iconNode, active) {
10675
- return () => {
10676
- const svg2 = (0, import_lucide16.createElement)(active ? import_lucide16.Check : iconNode);
10677
- svg2.setAttribute("aria-hidden", "true");
10678
- return createIconTile(svg2);
10679
- };
10680
- }
10681
- var pinSettingsView = {
10682
- id: BUILT_IN_VIEW_IDS.pinSettings,
10683
- matches: () => false,
10684
- parent: () => COMMAND_PALETTE_ENTRY2,
10685
- palette: {
10686
- label: "Pin settings",
10687
- group: PALETTE_GROUPS.commands,
10688
- icon: () => (0, import_lucide16.createElement)(import_lucide16.Settings)
10689
- },
10690
- title: "Pin settings",
10691
- searchable: false,
10692
- focusTarget: (host) => host.querySelector("[data-uidex-list-content]"),
10693
- surface: (ctx) => {
10694
- const current = readMode();
10695
- const items = MODES.map((m) => {
10696
- const active = m.value === current;
10697
- return {
10698
- value: m.value,
10699
- label: m.label,
10700
- subtitle: m.description,
10701
- leading: leadingIcon2(m.icon, active),
10702
- trailing: active ? import_lit_html2.html`<span class="text-muted-foreground ms-auto text-xs font-medium"
10703
- >Active</span
10704
- >` : void 0
10705
- };
10706
- });
10707
- return {
10708
- kind: "list",
10709
- id: "uidex-pin-settings",
10710
- searchable: false,
10711
- items,
10712
- emptyLabel: "No options available",
10713
- onSelect: (item) => {
10714
- const mode = item.value;
10715
- writeMode(mode);
10716
- ctx.onAfterSubmit?.();
10717
- const modeLabel = MODES.find((m) => m.value === mode).label;
10718
- showCopiedToast(`Pin mode set to "${modeLabel}"`);
10719
- ctx.pop();
10720
- }
10721
- };
10722
- }
10723
- };
10724
-
10725
7779
  // src/browser/views/built-in/index.ts
10726
7780
  function buildDefaultViews(shortcut) {
10727
7781
  return [
10728
- closeReasonView,
10729
7782
  createCommandPaletteView(shortcut),
10730
7783
  explorePageView,
10731
7784
  componentDetailView,
@@ -10742,43 +7795,15 @@ function buildDefaultViews(shortcut) {
10742
7795
  primitivesView,
10743
7796
  primitiveDetailView,
10744
7797
  regionDetailView,
10745
- entityReportsView,
10746
- reportView,
10747
- jiraReportView,
10748
- glossaryView,
10749
- pageReportsView,
10750
- pinSettingsView,
10751
- reportDetailView
7798
+ glossaryView
10752
7799
  ];
10753
7800
  }
10754
7801
 
10755
7802
  // src/browser/create-uidex.ts
10756
- function getVisibleEntities() {
10757
- if (typeof document === "undefined") return [];
10758
- const selector = UIDEX_ATTR_TO_KIND.map(([a]) => `[${a}]`).join(",");
10759
- const nodes = document.querySelectorAll(selector);
10760
- const ids = [];
10761
- const seen = /* @__PURE__ */ new Set();
10762
- for (const node of nodes) {
10763
- if (node.closest(SURFACE_IGNORE_SELECTOR)) continue;
10764
- for (const [attr, kind] of UIDEX_ATTR_TO_KIND) {
10765
- const id = node.getAttribute(attr);
10766
- if (!id) continue;
10767
- const key = `${kind}:${id}`;
10768
- if (!seen.has(key)) {
10769
- seen.add(key);
10770
- ids.push(key);
10771
- }
10772
- break;
10773
- }
10774
- }
10775
- return ids;
10776
- }
10777
7803
  function createUidex(options = {}) {
10778
7804
  const registry = createRegistry();
10779
7805
  const inspectorRef = { current: null };
10780
7806
  const overlayRef = { current: null };
10781
- const pinLayerRef = { current: null };
10782
7807
  const applyOverlay = (ctx) => {
10783
7808
  const overlay = overlayRef.current;
10784
7809
  if (!overlay) return;
@@ -10798,7 +7823,6 @@ function createUidex(options = {}) {
10798
7823
  const session = createSession({
10799
7824
  theme: options.theme,
10800
7825
  resolvedTheme: options.resolvedTheme,
10801
- user: options.user,
10802
7826
  onMountInspector: () => inspectorRef.current?.mount(),
10803
7827
  onDestroyInspector: () => inspectorRef.current?.destroy(),
10804
7828
  onShowOverlay: applyOverlay,
@@ -10806,9 +7830,6 @@ function createUidex(options = {}) {
10806
7830
  onUpdateOverlay: applyOverlay
10807
7831
  });
10808
7832
  const views = createRouter({ session });
10809
- const cloud = options.cloud ?? null;
10810
- const ingestOpts = resolveIngestOptions(options.ingest, cloud !== null);
10811
- const ingest = ingestOpts ? createIngest(ingestOpts) : null;
10812
7833
  if (options.defaultViews !== false) {
10813
7834
  for (const view of buildDefaultViews(options.shortcut)) views.add(view);
10814
7835
  }
@@ -10818,111 +7839,12 @@ function createUidex(options = {}) {
10818
7839
  let shadowRoot = null;
10819
7840
  const mountCleanup = createCleanupStack();
10820
7841
  let mounted = false;
10821
- function syncReportsToRegistry() {
10822
- const layer = pinLayerRef.current;
10823
- if (!layer) return;
10824
- const byEntity = /* @__PURE__ */ new Map();
10825
- for (const pin of layer.getAllPins()) {
10826
- const cid = pin.entity ?? "";
10827
- if (!cid) continue;
10828
- const list = byEntity.get(cid);
10829
- if (list) list.push(pin);
10830
- else byEntity.set(cid, [pin]);
10831
- }
10832
- for (const [cid, pins] of byEntity) {
10833
- const ref2 = parseComponentRef(cid);
10834
- registry.setReports(ref2.kind, ref2.id, pins);
10835
- }
10836
- }
10837
- function setupKeyBindings(root, viewStack) {
10838
- const bindings = bindShadowKeys({
10839
- shadowRoot: root,
10840
- session,
10841
- getActionsPopup: () => viewStack.getActionsPopup(),
10842
- getPinLayer: () => pinLayerRef.current,
10843
- shortcut: options.shortcut
10844
- });
10845
- mountCleanup.add(bindings);
10846
- return bindings;
10847
- }
10848
- function setupPinLayer(root, shell, channel, getCurrentRoute, getMatchMode, getPathname) {
10849
- if (cloud) {
10850
- registry.closeReport = async (reportId, status) => {
10851
- pinLayerRef.current?.removePin(reportId);
10852
- await cloud.pins.close(
10853
- reportId,
10854
- status
10855
- );
10856
- syncReportsToRegistry();
10857
- };
10858
- }
10859
- const pinLayer = createPinLayer({
10860
- container: root,
10861
- onOpenPinDetail: (componentId, reportId) => {
10862
- const ref2 = parseComponentRef(componentId);
10863
- setSelectedReportId(reportId);
10864
- const entry = { id: BUILT_IN_VIEW_IDS.reportDetail, ref: ref2 };
10865
- session.mode.transition.enterViewing(views.buildStack(entry));
10866
- },
10867
- onHoverPin: (anchor, componentId) => {
10868
- const overlay = overlayRef.current;
10869
- if (!overlay) return;
10870
- if (!anchor || !componentId) {
10871
- overlay.hide();
10872
- return;
10873
- }
10874
- overlay.show(anchor, {
10875
- color: isDarkMode() ? "#e4e4e7" : "#27272a"
10876
- });
10877
- },
10878
- onPinsChanged: syncReportsToRegistry
10879
- });
10880
- shell.menuBar.setPinLayer(pinLayer);
10881
- pinLayerRef.current = pinLayer;
10882
- mountCleanup.add(() => {
10883
- pinLayer.destroy();
10884
- pinLayerRef.current = null;
10885
- registry.closeReport = void 0;
10886
- });
10887
- if (cloud) {
10888
- const detach = pinLayer.attachCloud({
10889
- cloud,
10890
- channel,
10891
- getRoute: getCurrentRoute,
10892
- getPathname,
10893
- getVisibleEntities,
10894
- getMatchMode,
10895
- onError: (err) => console.warn("[uidex] pin fetch failed", err)
10896
- });
10897
- mountCleanup.add(detach);
10898
- if (channel && typeof window !== "undefined") {
10899
- const onRouteChange = () => {
10900
- const route = getCurrentRoute();
10901
- channel?.joinRoute(route);
10902
- void pinLayer.refresh();
10903
- };
10904
- const detachRoute = bindRouteChange(onRouteChange);
10905
- mountCleanup.add(detachRoute);
10906
- }
10907
- }
10908
- }
10909
7842
  function mount(target) {
10910
7843
  if (mounted) return;
10911
7844
  const mountTarget = target ?? (typeof document !== "undefined" ? document.body : null);
10912
7845
  if (!mountTarget) {
10913
7846
  throw new Error("createUidex: no mount target available");
10914
7847
  }
10915
- const getPathname = () => typeof location !== "undefined" ? location.pathname : "/";
10916
- const getCurrentRoute = () => options.getRoute?.() ?? findCurrentRoutePath(registry) ?? getPathname();
10917
- const getMatchMode = () => readMode();
10918
- let channel = null;
10919
- if (cloud && options.user) {
10920
- channel = cloud.realtime.connect({
10921
- user: options.user,
10922
- route: getCurrentRoute()
10923
- });
10924
- mountCleanup.add(() => channel?.disconnect());
10925
- }
10926
7848
  const shell = createSurfaceShell({
10927
7849
  mount: mountTarget,
10928
7850
  registry,
@@ -10930,7 +7852,6 @@ function createUidex(options = {}) {
10930
7852
  stylesheets: options.stylesheets,
10931
7853
  initialCorner: options.initialCorner,
10932
7854
  appTitle: options.appTitle,
10933
- channel,
10934
7855
  inspector: {
10935
7856
  onSelect: (match) => {
10936
7857
  const route = views.resolve(match.ref);
@@ -10966,38 +7887,23 @@ function createUidex(options = {}) {
10966
7887
  viewContainer.setAttribute("data-uidex-views", "");
10967
7888
  shell.host.chromeEl.appendChild(viewContainer);
10968
7889
  mountCleanup.add(() => viewContainer.remove());
10969
- let keyBindings = null;
10970
7890
  const viewStack = createViewStack({
10971
7891
  container: viewContainer,
10972
7892
  views,
10973
7893
  session,
10974
7894
  registry,
10975
- cloud,
10976
7895
  highlight,
10977
- shortcut: options.shortcut,
10978
- pushEscapeLayer: (handler) => {
10979
- if (!keyBindings) return () => {
10980
- };
10981
- return keyBindings.pushEscapeLayer(handler);
10982
- },
10983
- onAfterSubmit: () => pinLayerRef.current?.refresh(),
10984
- getRoute: getCurrentRoute
7896
+ shortcut: options.shortcut
10985
7897
  });
10986
7898
  mountCleanup.add(viewStack);
10987
7899
  if (shadowRoot) {
10988
- keyBindings = setupKeyBindings(shadowRoot, viewStack);
10989
- setupPinLayer(
7900
+ const keyBindings = bindShadowKeys({
10990
7901
  shadowRoot,
10991
- shell,
10992
- channel,
10993
- getCurrentRoute,
10994
- getMatchMode,
10995
- getPathname
10996
- );
10997
- }
10998
- if (ingest) {
10999
- ingest.start();
11000
- mountCleanup.add(() => ingest.stop());
7902
+ session,
7903
+ getActionsPopup: () => viewStack.getActionsPopup(),
7904
+ shortcut: options.shortcut
7905
+ });
7906
+ mountCleanup.add(keyBindings);
11001
7907
  }
11002
7908
  mounted = true;
11003
7909
  }
@@ -11013,8 +7919,6 @@ function createUidex(options = {}) {
11013
7919
  registry,
11014
7920
  session,
11015
7921
  views,
11016
- cloud,
11017
- ingest,
11018
7922
  get shadowRoot() {
11019
7923
  return shadowRoot;
11020
7924
  }
@@ -11031,21 +7935,16 @@ function createUidex(options = {}) {
11031
7935
  Z_BASE,
11032
7936
  Z_CHROME,
11033
7937
  Z_OVERLAY,
11034
- Z_PIN_LAYER,
11035
7938
  assertEntityKind,
11036
7939
  buildDefaultViews,
11037
7940
  componentDetailView,
11038
7941
  createCommandPaletteView,
11039
- createConsoleCapture,
11040
7942
  createCursorTooltip,
11041
- createIngest,
11042
7943
  createInspector,
11043
7944
  createMenuBar,
11044
7945
  createModeStore,
11045
7946
  createNavigationStore,
11046
- createNetworkCapture,
11047
7947
  createOverlay,
11048
- createPinLayer,
11049
7948
  createRegistry,
11050
7949
  createRouter,
11051
7950
  createSession,
@@ -11060,15 +7959,11 @@ function createUidex(options = {}) {
11060
7959
  flowDetailView,
11061
7960
  formatShortcutLabel,
11062
7961
  isMetaKind,
11063
- nativeFetch,
11064
7962
  pageDetailView,
11065
- pinSettingsView,
11066
7963
  prettify,
11067
7964
  primitiveDetailView,
11068
7965
  regionDetailView,
11069
- reportView,
11070
7966
  resolveEntityElement,
11071
- resolveIngestOptions,
11072
7967
  resolveTheme,
11073
7968
  widgetDetailView
11074
7969
  });