@designfever/web-review-kit 0.2.0 → 0.3.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.
@@ -3,7 +3,7 @@ import {
3
3
  createWebReviewKit,
4
4
  getNumberedReviewItems,
5
5
  normalizeReviewItemStatus
6
- } from "./chunk-EJDROXJM.js";
6
+ } from "./chunk-I76WEDLA.js";
7
7
 
8
8
  // src/react-shell.tsx
9
9
  import React2 from "react";
@@ -128,17 +128,20 @@ function ensureReviewShellStyle() {
128
128
  --df-review-color-scrollbar-border: rgba(15, 18, 24, 0.92);
129
129
  --df-review-color-backdrop: rgba(2, 6, 12, 0.62);
130
130
  --df-review-color-ruler-surface: transparent;
131
- --df-review-color-ruler-label: transparent;
132
- --df-review-color-ruler-label-text: #e1d8ff;
133
- --df-review-color-ruler-tick-major: rgba(179, 149, 255, 0.75);
131
+ --df-review-color-ruler-label: rgba(15, 18, 24, 0.9);
132
+ --df-review-color-ruler-label-text: #f4efff;
133
+ --df-review-color-ruler-tick-major: rgba(201, 184, 255, 0.9);
134
134
  --df-review-color-ruler-tick-minor: rgba(237, 243, 251, 0.2);
135
- --df-review-color-ruler-guide: rgba(255, 255, 255, 0.74);
135
+ --df-review-color-ruler-guide: rgba(255, 255, 255, 0.86);
136
136
  --df-review-color-ruler-measure-border: #c9b8ff;
137
- --df-review-color-ruler-measure-bg: rgba(179, 149, 255, 0.16);
138
- --df-review-color-ruler-measure-shadow: rgba(20, 12, 40, 0.38);
139
- --df-review-color-ruler-popover-border: rgba(237, 243, 251, 0.22);
140
- --df-review-color-ruler-popover-bg: transparent;
141
- --df-review-color-ruler-popover-shadow: transparent;
137
+ --df-review-color-ruler-measure-bg: rgba(179, 149, 255, 0.18);
138
+ --df-review-color-ruler-measure-shadow: rgba(20, 12, 40, 0.52);
139
+ --df-review-color-ruler-popover-border: rgba(255, 255, 255, 0.34);
140
+ --df-review-color-ruler-popover-bg: rgba(15, 18, 24, 0.94);
141
+ --df-review-color-ruler-popover-text: #ffffff;
142
+ --df-review-color-ruler-popover-shadow: rgba(0, 0, 0, 0.42);
143
+ --df-review-color-ruler-coord-bg: #d7c9ff;
144
+ --df-review-color-ruler-coord-text: #14111f;
142
145
  --df-review-focus-ring: rgba(124, 199, 255, 0.58);
143
146
  --df-review-shadow-card: 0 14px 36px rgba(0, 0, 0, 0.34);
144
147
  --df-review-shadow-control: inset 0 1px 0 rgba(255, 255, 255, 0.04);
@@ -220,17 +223,20 @@ function ensureReviewShellStyle() {
220
223
  --df-review-color-scrollbar-border: rgba(244, 246, 249, 0.92);
221
224
  --df-review-color-backdrop: rgba(15, 23, 42, 0.32);
222
225
  --df-review-color-ruler-surface: transparent;
223
- --df-review-color-ruler-label: transparent;
224
- --df-review-color-ruler-label-text: #6543b8;
225
- --df-review-color-ruler-tick-major: rgba(101, 67, 184, 0.58);
226
- --df-review-color-ruler-tick-minor: rgba(23, 32, 44, 0.24);
227
- --df-review-color-ruler-guide: rgba(101, 67, 184, 0.58);
228
- --df-review-color-ruler-measure-border: #6543b8;
229
- --df-review-color-ruler-measure-bg: rgba(101, 67, 184, 0.1);
230
- --df-review-color-ruler-measure-shadow: rgba(101, 67, 184, 0.22);
231
- --df-review-color-ruler-popover-border: rgba(23, 32, 44, 0.16);
232
- --df-review-color-ruler-popover-bg: transparent;
233
- --df-review-color-ruler-popover-shadow: transparent;
226
+ --df-review-color-ruler-label: rgba(255, 255, 255, 0.94);
227
+ --df-review-color-ruler-label-text: #3b247e;
228
+ --df-review-color-ruler-tick-major: rgba(0, 95, 204, 0.92);
229
+ --df-review-color-ruler-tick-minor: rgba(23, 32, 44, 0.3);
230
+ --df-review-color-ruler-guide: rgba(0, 102, 255, 0.96);
231
+ --df-review-color-ruler-measure-border: #0066ff;
232
+ --df-review-color-ruler-measure-bg: rgba(0, 102, 255, 0.16);
233
+ --df-review-color-ruler-measure-shadow: rgba(0, 43, 120, 0.56);
234
+ --df-review-color-ruler-popover-border: rgba(255, 255, 255, 0.34);
235
+ --df-review-color-ruler-popover-bg: rgba(15, 18, 24, 0.94);
236
+ --df-review-color-ruler-popover-text: #ffffff;
237
+ --df-review-color-ruler-popover-shadow: rgba(0, 0, 0, 0.42);
238
+ --df-review-color-ruler-coord-bg: #005be8;
239
+ --df-review-color-ruler-coord-text: #ffffff;
234
240
  --df-review-focus-ring: rgba(23, 105, 170, 0.42);
235
241
  --df-review-shadow-card: 0 14px 36px rgba(15, 23, 42, 0.14);
236
242
  --df-review-shadow-control: inset 0 1px 0 rgba(255, 255, 255, 0.72);
@@ -341,6 +347,7 @@ function ensureReviewShellStyle() {
341
347
  .df-review-prompt-block-header button:hover,
342
348
  .df-review-item-actions button:hover,
343
349
  .df-review-item-visibility:hover,
350
+ .df-review-item-source-open:hover,
344
351
  .df-review-item-prompt-copy:hover,
345
352
  .df-review-item-delete:hover,
346
353
  .df-review-presets button.is-active,
@@ -904,6 +911,59 @@ function ensureReviewShellStyle() {
904
911
  color: var(--df-review-accent);
905
912
  }
906
913
 
914
+ .df-review-edit-modal {
915
+ position: fixed;
916
+ inset: 0;
917
+ z-index: 1003;
918
+ display: grid;
919
+ place-items: center;
920
+ padding: 24px;
921
+ }
922
+
923
+ .df-review-edit-dialog {
924
+ position: relative;
925
+ z-index: 1;
926
+ display: grid;
927
+ width: min(460px, calc(100vw - 48px));
928
+ overflow: hidden;
929
+ border: 1px solid var(--df-review-line);
930
+ border-radius: var(--df-review-radius-lg);
931
+ background: var(--df-review-panel);
932
+ box-shadow: var(--df-review-shadow-modal);
933
+ }
934
+
935
+ .df-review-edit-textarea {
936
+ min-height: 160px;
937
+ }
938
+
939
+ .df-review-edit-textarea textarea {
940
+ width: 100%;
941
+ min-height: 160px;
942
+ border: 0;
943
+ padding: 10px;
944
+ outline: 0;
945
+ background: transparent;
946
+ color: var(--df-review-text);
947
+ resize: vertical;
948
+ font-size: var(--df-review-font-size-md);
949
+ line-height: 1.5;
950
+ }
951
+
952
+ .df-review-edit-textarea textarea:focus {
953
+ outline: 0;
954
+ }
955
+
956
+ .df-review-edit-error {
957
+ margin: 0;
958
+ color: var(--df-review-danger);
959
+ font-size: var(--df-review-font-size-sm);
960
+ font-weight: 800;
961
+ }
962
+
963
+ .df-review-edit-actions {
964
+ grid-template-columns: minmax(0, 1fr) auto auto;
965
+ }
966
+
907
967
  .df-review-prompt-modal {
908
968
  position: fixed;
909
969
  inset: 0;
@@ -1906,7 +1966,9 @@ function ensureReviewShellStyle() {
1906
1966
  }
1907
1967
 
1908
1968
  .df-review-item-delete,
1969
+ .df-review-item-edit,
1909
1970
  .df-review-item-prompt-copy,
1971
+ .df-review-item-source-open,
1910
1972
  .df-review-item-visibility {
1911
1973
  display: inline-grid;
1912
1974
  place-items: center;
@@ -1917,10 +1979,13 @@ function ensureReviewShellStyle() {
1917
1979
  padding: 0;
1918
1980
  color: var(--df-review-muted);
1919
1981
  background: transparent;
1982
+ text-decoration: none;
1920
1983
  transition: border-color 140ms ease, background 140ms ease, color 140ms ease;
1921
1984
  }
1922
1985
 
1923
1986
  .df-review-item-visibility:hover,
1987
+ .df-review-item-edit:hover,
1988
+ .df-review-item-source-open:hover,
1924
1989
  .df-review-item-prompt-copy:hover {
1925
1990
  border-color: rgba(124, 199, 255, 0.34);
1926
1991
  color: var(--df-review-accent);
@@ -1947,7 +2012,9 @@ function ensureReviewShellStyle() {
1947
2012
  }
1948
2013
 
1949
2014
  .df-review-item-delete svg,
2015
+ .df-review-item-edit svg,
1950
2016
  .df-review-item-prompt-copy svg,
2017
+ .df-review-item-source-open svg,
1951
2018
  .df-review-item-visibility svg {
1952
2019
  width: 14px;
1953
2020
  height: 14px;
@@ -2193,37 +2260,42 @@ function ensureReviewShellStyle() {
2193
2260
  display: flex;
2194
2261
  align-items: center;
2195
2262
  gap: 6px;
2196
- padding: 3px 7px;
2197
- border-radius: 5px;
2263
+ padding: 4px 8px;
2264
+ border: 1px solid var(--df-review-color-ruler-popover-border);
2265
+ border-radius: var(--df-review-radius-sm);
2198
2266
  background: var(--df-review-color-ruler-label);
2199
2267
  line-height: 1;
2200
2268
  white-space: nowrap;
2269
+ box-shadow: 0 6px 18px var(--df-review-color-ruler-popover-shadow);
2201
2270
  }
2202
2271
 
2203
2272
  .df-review-ruler-frame-label strong {
2204
2273
  color: var(--df-review-color-ruler-label-text);
2205
- font-size: var(--df-review-font-size-2xs);
2274
+ font-size: var(--df-review-font-size-xs);
2206
2275
  font-weight: 900;
2207
2276
  }
2208
2277
 
2209
2278
  .df-review-ruler-frame-label span {
2210
- color: var(--df-review-muted);
2211
- font-size: var(--df-review-font-size-2xs);
2279
+ color: var(--df-review-color-ruler-label-text);
2280
+ font-size: var(--df-review-font-size-xs);
2212
2281
  font-weight: 900;
2282
+ opacity: 0.78;
2213
2283
  }
2214
2284
 
2215
2285
  .df-review-ruler-coord {
2216
2286
  position: absolute;
2217
2287
  z-index: 7;
2218
- padding: 2px 4px;
2219
- border-radius: 4px;
2220
- background: #b395ff;
2221
- color: #14111f;
2222
- font-size: var(--df-review-font-size-3xs);
2288
+ padding: 4px 6px;
2289
+ border: 1px solid var(--df-review-color-ruler-popover-border);
2290
+ border-radius: var(--df-review-radius-xs);
2291
+ background: var(--df-review-color-ruler-coord-bg);
2292
+ color: var(--df-review-color-ruler-coord-text);
2293
+ font-size: var(--df-review-font-size-xs);
2223
2294
  font-weight: 900;
2224
2295
  line-height: 1;
2225
2296
  white-space: nowrap;
2226
2297
  pointer-events: none;
2298
+ box-shadow: 0 6px 18px var(--df-review-color-ruler-popover-shadow);
2227
2299
  }
2228
2300
 
2229
2301
  .df-review-ruler-coord.is-x {
@@ -2258,47 +2330,53 @@ function ensureReviewShellStyle() {
2258
2330
  z-index: 2;
2259
2331
  pointer-events: none;
2260
2332
  background: var(--df-review-color-ruler-guide);
2261
- box-shadow: 0 0 0 1px rgba(87, 55, 166, 0.45);
2333
+ box-shadow: 0 0 0 1px var(--df-review-color-ruler-measure-shadow);
2262
2334
  }
2263
2335
 
2264
2336
  .df-review-ruler-guide.is-x {
2265
2337
  left: 0;
2266
2338
  right: 0;
2267
- height: 1px;
2339
+ height: 2px;
2268
2340
  }
2269
2341
 
2270
2342
  .df-review-ruler-guide.is-y {
2271
2343
  top: 0;
2272
2344
  bottom: 0;
2273
- width: 1px;
2345
+ width: 2px;
2274
2346
  }
2275
2347
 
2276
2348
  .df-review-ruler-selection {
2277
2349
  position: absolute;
2278
2350
  z-index: 3;
2279
2351
  pointer-events: none;
2280
- border: 1px solid var(--df-review-color-ruler-measure-border);
2352
+ border: 3px solid var(--df-review-color-ruler-measure-border);
2281
2353
  background: var(--df-review-color-ruler-measure-bg);
2282
2354
  box-shadow:
2283
2355
  inset 0 0 0 1px var(--df-review-color-ruler-measure-shadow),
2284
- 0 0 0 1px var(--df-review-color-ruler-measure-shadow);
2356
+ 0 0 0 1px rgba(255, 255, 255, 0.96),
2357
+ 0 0 0 4px var(--df-review-color-ruler-measure-shadow);
2285
2358
  }
2286
2359
 
2287
2360
  .df-review-ruler-label {
2288
2361
  position: absolute;
2289
2362
  z-index: 4;
2290
2363
  pointer-events: none;
2291
- min-width: 156px;
2292
- padding: 7px 8px;
2364
+ min-width: 124px;
2365
+ padding: 9px 11px;
2293
2366
  border: 1px solid var(--df-review-color-ruler-popover-border);
2294
- border-radius: var(--df-review-radius-sm);
2367
+ border-radius: var(--df-review-radius-md);
2295
2368
  background: var(--df-review-color-ruler-popover-bg);
2296
- color: var(--df-review-text);
2297
- font-size: var(--df-review-font-size-xs);
2369
+ color: var(--df-review-color-ruler-popover-text);
2370
+ font-family: var(--df-review-font-mono);
2371
+ font-size: var(--df-review-font-size-lg);
2298
2372
  font-weight: 900;
2299
2373
  line-height: 1;
2300
2374
  white-space: nowrap;
2301
- box-shadow: 0 8px 22px var(--df-review-color-ruler-popover-shadow);
2375
+ letter-spacing: -0.02em;
2376
+ text-align: center;
2377
+ box-shadow:
2378
+ 0 10px 26px var(--df-review-color-ruler-popover-shadow),
2379
+ inset 0 1px 0 rgba(255, 255, 255, 0.18);
2302
2380
  }
2303
2381
 
2304
2382
  @media (max-width: 860px) {
@@ -2360,7 +2438,9 @@ function ensureReviewShellStyle() {
2360
2438
  // src/react-shell/review/shell.tsx
2361
2439
  import {
2362
2440
  useCallback as useCallback11,
2363
- useEffect as useEffect9
2441
+ useEffect as useEffect10,
2442
+ useRef as useRef4,
2443
+ useState as useState8
2364
2444
  } from "react";
2365
2445
 
2366
2446
  // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/createLucideIcon.mjs
@@ -2524,8 +2604,23 @@ var __iconNode5 = [
2524
2604
  ];
2525
2605
  var Eye = createLucideIcon("eye", __iconNode5);
2526
2606
 
2527
- // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/grip-vertical.mjs
2607
+ // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/file-code-corner.mjs
2528
2608
  var __iconNode6 = [
2609
+ [
2610
+ "path",
2611
+ {
2612
+ d: "M4 12.15V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.706.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2h-3.35",
2613
+ key: "1wthlu"
2614
+ }
2615
+ ],
2616
+ ["path", { d: "M14 2v5a1 1 0 0 0 1 1h5", key: "wfsgrz" }],
2617
+ ["path", { d: "m5 16-3 3 3 3", key: "331omg" }],
2618
+ ["path", { d: "m9 22 3-3-3-3", key: "lsp7cz" }]
2619
+ ];
2620
+ var FileCodeCorner = createLucideIcon("file-code-corner", __iconNode6);
2621
+
2622
+ // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/grip-vertical.mjs
2623
+ var __iconNode7 = [
2529
2624
  ["circle", { cx: "9", cy: "12", r: "1", key: "1vctgf" }],
2530
2625
  ["circle", { cx: "9", cy: "5", r: "1", key: "hp0tcf" }],
2531
2626
  ["circle", { cx: "9", cy: "19", r: "1", key: "fkjjf6" }],
@@ -2533,35 +2628,35 @@ var __iconNode6 = [
2533
2628
  ["circle", { cx: "15", cy: "5", r: "1", key: "19l28e" }],
2534
2629
  ["circle", { cx: "15", cy: "19", r: "1", key: "f4zoj3" }]
2535
2630
  ];
2536
- var GripVertical = createLucideIcon("grip-vertical", __iconNode6);
2631
+ var GripVertical = createLucideIcon("grip-vertical", __iconNode7);
2537
2632
 
2538
2633
  // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/image.mjs
2539
- var __iconNode7 = [
2634
+ var __iconNode8 = [
2540
2635
  ["rect", { width: "18", height: "18", x: "3", y: "3", rx: "2", ry: "2", key: "1m3agn" }],
2541
2636
  ["circle", { cx: "9", cy: "9", r: "2", key: "af1f0g" }],
2542
2637
  ["path", { d: "m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21", key: "1xmnt7" }]
2543
2638
  ];
2544
- var Image = createLucideIcon("image", __iconNode7);
2639
+ var Image = createLucideIcon("image", __iconNode8);
2545
2640
 
2546
2641
  // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/layout-grid.mjs
2547
- var __iconNode8 = [
2642
+ var __iconNode9 = [
2548
2643
  ["rect", { width: "7", height: "7", x: "3", y: "3", rx: "1", key: "1g98yp" }],
2549
2644
  ["rect", { width: "7", height: "7", x: "14", y: "3", rx: "1", key: "6d4xhi" }],
2550
2645
  ["rect", { width: "7", height: "7", x: "14", y: "14", rx: "1", key: "nxv5o0" }],
2551
2646
  ["rect", { width: "7", height: "7", x: "3", y: "14", rx: "1", key: "1bb6yr" }]
2552
2647
  ];
2553
- var LayoutGrid = createLucideIcon("layout-grid", __iconNode8);
2648
+ var LayoutGrid = createLucideIcon("layout-grid", __iconNode9);
2554
2649
 
2555
2650
  // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/list-filter.mjs
2556
- var __iconNode9 = [
2651
+ var __iconNode10 = [
2557
2652
  ["path", { d: "M2 5h20", key: "1fs1ex" }],
2558
2653
  ["path", { d: "M6 12h12", key: "8npq4p" }],
2559
2654
  ["path", { d: "M9 19h6", key: "456am0" }]
2560
2655
  ];
2561
- var ListFilter = createLucideIcon("list-filter", __iconNode9);
2656
+ var ListFilter = createLucideIcon("list-filter", __iconNode10);
2562
2657
 
2563
2658
  // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/map.mjs
2564
- var __iconNode10 = [
2659
+ var __iconNode11 = [
2565
2660
  [
2566
2661
  "path",
2567
2662
  {
@@ -2572,42 +2667,55 @@ var __iconNode10 = [
2572
2667
  ["path", { d: "M15 5.764v15", key: "1pn4in" }],
2573
2668
  ["path", { d: "M9 3.236v15", key: "1uimfh" }]
2574
2669
  ];
2575
- var Map2 = createLucideIcon("map", __iconNode10);
2670
+ var Map2 = createLucideIcon("map", __iconNode11);
2576
2671
 
2577
2672
  // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/maximize-2.mjs
2578
- var __iconNode11 = [
2673
+ var __iconNode12 = [
2579
2674
  ["path", { d: "M15 3h6v6", key: "1q9fwt" }],
2580
2675
  ["path", { d: "m21 3-7 7", key: "1l2asr" }],
2581
2676
  ["path", { d: "m3 21 7-7", key: "tjx5ai" }],
2582
2677
  ["path", { d: "M9 21H3v-6", key: "wtvkvv" }]
2583
2678
  ];
2584
- var Maximize2 = createLucideIcon("maximize-2", __iconNode11);
2679
+ var Maximize2 = createLucideIcon("maximize-2", __iconNode12);
2585
2680
 
2586
2681
  // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/monitor.mjs
2587
- var __iconNode12 = [
2682
+ var __iconNode13 = [
2588
2683
  ["rect", { width: "20", height: "14", x: "2", y: "3", rx: "2", key: "48i651" }],
2589
2684
  ["line", { x1: "8", x2: "16", y1: "21", y2: "21", key: "1svkeh" }],
2590
2685
  ["line", { x1: "12", x2: "12", y1: "17", y2: "21", key: "vw1qmm" }]
2591
2686
  ];
2592
- var Monitor = createLucideIcon("monitor", __iconNode12);
2687
+ var Monitor = createLucideIcon("monitor", __iconNode13);
2688
+
2689
+ // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/pencil.mjs
2690
+ var __iconNode14 = [
2691
+ [
2692
+ "path",
2693
+ {
2694
+ d: "M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z",
2695
+ key: "1a8usu"
2696
+ }
2697
+ ],
2698
+ ["path", { d: "m15 5 4 4", key: "1mk7zo" }]
2699
+ ];
2700
+ var Pencil = createLucideIcon("pencil", __iconNode14);
2593
2701
 
2594
2702
  // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/rectangle-horizontal.mjs
2595
- var __iconNode13 = [
2703
+ var __iconNode15 = [
2596
2704
  ["rect", { width: "20", height: "12", x: "2", y: "6", rx: "2", key: "9lu3g6" }]
2597
2705
  ];
2598
- var RectangleHorizontal = createLucideIcon("rectangle-horizontal", __iconNode13);
2706
+ var RectangleHorizontal = createLucideIcon("rectangle-horizontal", __iconNode15);
2599
2707
 
2600
2708
  // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/refresh-cw.mjs
2601
- var __iconNode14 = [
2709
+ var __iconNode16 = [
2602
2710
  ["path", { d: "M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8", key: "v9h5vc" }],
2603
2711
  ["path", { d: "M21 3v5h-5", key: "1q7to0" }],
2604
2712
  ["path", { d: "M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16", key: "3uifl3" }],
2605
2713
  ["path", { d: "M8 16H3v5", key: "1cv678" }]
2606
2714
  ];
2607
- var RefreshCw = createLucideIcon("refresh-cw", __iconNode14);
2715
+ var RefreshCw = createLucideIcon("refresh-cw", __iconNode16);
2608
2716
 
2609
2717
  // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/ruler.mjs
2610
- var __iconNode15 = [
2718
+ var __iconNode17 = [
2611
2719
  [
2612
2720
  "path",
2613
2721
  {
@@ -2620,19 +2728,19 @@ var __iconNode15 = [
2620
2728
  ["path", { d: "m8.5 6.5 2-2", key: "vc6u1g" }],
2621
2729
  ["path", { d: "m17.5 15.5 2-2", key: "wo5hmg" }]
2622
2730
  ];
2623
- var Ruler = createLucideIcon("ruler", __iconNode15);
2731
+ var Ruler = createLucideIcon("ruler", __iconNode17);
2624
2732
 
2625
2733
  // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/scan.mjs
2626
- var __iconNode16 = [
2734
+ var __iconNode18 = [
2627
2735
  ["path", { d: "M3 7V5a2 2 0 0 1 2-2h2", key: "aa7l1z" }],
2628
2736
  ["path", { d: "M17 3h2a2 2 0 0 1 2 2v2", key: "4qcy5o" }],
2629
2737
  ["path", { d: "M21 17v2a2 2 0 0 1-2 2h-2", key: "6vwrx8" }],
2630
2738
  ["path", { d: "M7 21H5a2 2 0 0 1-2-2v-2", key: "ioqczr" }]
2631
2739
  ];
2632
- var Scan = createLucideIcon("scan", __iconNode16);
2740
+ var Scan = createLucideIcon("scan", __iconNode18);
2633
2741
 
2634
2742
  // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/settings.mjs
2635
- var __iconNode17 = [
2743
+ var __iconNode19 = [
2636
2744
  [
2637
2745
  "path",
2638
2746
  {
@@ -2642,17 +2750,17 @@ var __iconNode17 = [
2642
2750
  ],
2643
2751
  ["circle", { cx: "12", cy: "12", r: "3", key: "1v7zrd" }]
2644
2752
  ];
2645
- var Settings = createLucideIcon("settings", __iconNode17);
2753
+ var Settings = createLucideIcon("settings", __iconNode19);
2646
2754
 
2647
2755
  // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/smartphone.mjs
2648
- var __iconNode18 = [
2756
+ var __iconNode20 = [
2649
2757
  ["rect", { width: "14", height: "20", x: "5", y: "2", rx: "2", ry: "2", key: "1yt0o3" }],
2650
2758
  ["path", { d: "M12 18h.01", key: "mhygvu" }]
2651
2759
  ];
2652
- var Smartphone = createLucideIcon("smartphone", __iconNode18);
2760
+ var Smartphone = createLucideIcon("smartphone", __iconNode20);
2653
2761
 
2654
2762
  // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/square-mouse-pointer.mjs
2655
- var __iconNode19 = [
2763
+ var __iconNode21 = [
2656
2764
  [
2657
2765
  "path",
2658
2766
  {
@@ -2662,10 +2770,10 @@ var __iconNode19 = [
2662
2770
  ],
2663
2771
  ["path", { d: "M21 11V5a2 2 0 0 0-2-2H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h6", key: "14rsvq" }]
2664
2772
  ];
2665
- var SquareMousePointer = createLucideIcon("square-mouse-pointer", __iconNode19);
2773
+ var SquareMousePointer = createLucideIcon("square-mouse-pointer", __iconNode21);
2666
2774
 
2667
2775
  // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/sticky-note.mjs
2668
- var __iconNode20 = [
2776
+ var __iconNode22 = [
2669
2777
  [
2670
2778
  "path",
2671
2779
  {
@@ -2675,31 +2783,31 @@ var __iconNode20 = [
2675
2783
  ],
2676
2784
  ["path", { d: "M15 3v5a1 1 0 0 0 1 1h5", key: "6s6qgf" }]
2677
2785
  ];
2678
- var StickyNote = createLucideIcon("sticky-note", __iconNode20);
2786
+ var StickyNote = createLucideIcon("sticky-note", __iconNode22);
2679
2787
 
2680
2788
  // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/upload.mjs
2681
- var __iconNode21 = [
2789
+ var __iconNode23 = [
2682
2790
  ["path", { d: "M12 3v12", key: "1x0j5s" }],
2683
2791
  ["path", { d: "m17 8-5-5-5 5", key: "7q97r8" }],
2684
2792
  ["path", { d: "M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4", key: "ih7n3h" }]
2685
2793
  ];
2686
- var Upload = createLucideIcon("upload", __iconNode21);
2794
+ var Upload = createLucideIcon("upload", __iconNode23);
2687
2795
 
2688
2796
  // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/users.mjs
2689
- var __iconNode22 = [
2797
+ var __iconNode24 = [
2690
2798
  ["path", { d: "M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2", key: "1yyitq" }],
2691
2799
  ["path", { d: "M16 3.128a4 4 0 0 1 0 7.744", key: "16gr8j" }],
2692
2800
  ["path", { d: "M22 21v-2a4 4 0 0 0-3-3.87", key: "kshegd" }],
2693
2801
  ["circle", { cx: "9", cy: "7", r: "4", key: "nufk8" }]
2694
2802
  ];
2695
- var Users = createLucideIcon("users", __iconNode22);
2803
+ var Users = createLucideIcon("users", __iconNode24);
2696
2804
 
2697
2805
  // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/x.mjs
2698
- var __iconNode23 = [
2806
+ var __iconNode25 = [
2699
2807
  ["path", { d: "M18 6 6 18", key: "1bl5f8" }],
2700
2808
  ["path", { d: "m6 6 12 12", key: "d8bk6v" }]
2701
2809
  ];
2702
- var X = createLucideIcon("x", __iconNode23);
2810
+ var X = createLucideIcon("x", __iconNode25);
2703
2811
 
2704
2812
  // src/react-shell/constants.ts
2705
2813
  var REVIEW_QA_FILTERS = [
@@ -2919,6 +3027,8 @@ var formatPromptSourceHint = (item) => {
2919
3027
  return [
2920
3028
  `Component: ${source.component ?? "(unknown)"}`,
2921
3029
  `File: ${source.file ?? "(unknown)"}`,
3030
+ `Line: ${source.line ?? "(unknown)"}`,
3031
+ `Column: ${source.column ?? "(unknown)"}`,
2922
3032
  `Section index: ${source.sectionIndex ?? "(unknown)"}`,
2923
3033
  `Section id: ${source.sectionId ?? "(none)"}`
2924
3034
  ].join("\n");
@@ -3581,8 +3691,122 @@ var SitemapModal = ({
3581
3691
  );
3582
3692
  };
3583
3693
 
3584
- // src/react-shell/qa/item.remote.actions.tsx
3694
+ // src/react-shell/qa/item.edit.modal.tsx
3695
+ import { useEffect, useState } from "react";
3585
3696
  import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
3697
+ var QaItemEditModal = ({
3698
+ item,
3699
+ onClose,
3700
+ onSave
3701
+ }) => {
3702
+ const [commentDraft, setCommentDraft] = useState(item.comment);
3703
+ const [error, setError] = useState("");
3704
+ const [isSaving, setIsSaving] = useState(false);
3705
+ useEffect(() => {
3706
+ setCommentDraft(item.comment);
3707
+ setError("");
3708
+ setIsSaving(false);
3709
+ }, [item.id, item.comment]);
3710
+ const saveComment = async () => {
3711
+ const nextComment = commentDraft.trim();
3712
+ if (!nextComment) {
3713
+ setError("Comment is required.");
3714
+ return;
3715
+ }
3716
+ setError("");
3717
+ setIsSaving(true);
3718
+ try {
3719
+ await onSave(item, nextComment);
3720
+ } catch (error2) {
3721
+ setError(
3722
+ error2 instanceof Error ? error2.message : "Failed to update QA comment."
3723
+ );
3724
+ setIsSaving(false);
3725
+ }
3726
+ };
3727
+ return /* @__PURE__ */ jsxs4(
3728
+ "div",
3729
+ {
3730
+ "aria-modal": "true",
3731
+ className: "df-review-edit-modal",
3732
+ role: "dialog",
3733
+ "aria-labelledby": "df-review-edit-title",
3734
+ children: [
3735
+ /* @__PURE__ */ jsx4(
3736
+ "button",
3737
+ {
3738
+ "aria-label": "Close edit dialog",
3739
+ className: "df-review-settings-backdrop",
3740
+ type: "button",
3741
+ onClick: onClose
3742
+ }
3743
+ ),
3744
+ /* @__PURE__ */ jsxs4(
3745
+ "form",
3746
+ {
3747
+ className: "df-review-edit-dialog",
3748
+ onSubmit: (event) => {
3749
+ event.preventDefault();
3750
+ void saveComment();
3751
+ },
3752
+ children: [
3753
+ /* @__PURE__ */ jsxs4("header", { className: "df-review-settings-header", children: [
3754
+ /* @__PURE__ */ jsxs4("div", { className: "df-review-settings-title", children: [
3755
+ /* @__PURE__ */ jsx4("strong", { id: "df-review-edit-title", children: "Edit QA comment" }),
3756
+ /* @__PURE__ */ jsx4("span", { children: "Update the text shown on this QA item." })
3757
+ ] }),
3758
+ /* @__PURE__ */ jsx4("div", { className: "df-review-settings-header-actions", children: /* @__PURE__ */ jsx4(
3759
+ "button",
3760
+ {
3761
+ "aria-label": "Close edit dialog",
3762
+ type: "button",
3763
+ onClick: onClose,
3764
+ children: "x"
3765
+ }
3766
+ ) })
3767
+ ] }),
3768
+ /* @__PURE__ */ jsxs4("div", { className: "df-review-settings-body df-review-edit-body", children: [
3769
+ /* @__PURE__ */ jsxs4("label", { className: "df-review-settings-field", children: [
3770
+ /* @__PURE__ */ jsx4("span", { children: "Comment" }),
3771
+ /* @__PURE__ */ jsx4("div", { className: "df-review-settings-text-input df-review-edit-textarea", children: /* @__PURE__ */ jsx4(
3772
+ "textarea",
3773
+ {
3774
+ autoFocus: true,
3775
+ value: commentDraft,
3776
+ onChange: (event) => {
3777
+ setCommentDraft(event.target.value);
3778
+ if (error) setError("");
3779
+ },
3780
+ onKeyDown: (event) => {
3781
+ if (event.key === "Escape") {
3782
+ event.preventDefault();
3783
+ onClose();
3784
+ }
3785
+ if ((event.metaKey || event.ctrlKey) && event.key === "Enter") {
3786
+ event.preventDefault();
3787
+ void saveComment();
3788
+ }
3789
+ }
3790
+ }
3791
+ ) })
3792
+ ] }),
3793
+ error && /* @__PURE__ */ jsx4("p", { className: "df-review-edit-error", children: error }),
3794
+ /* @__PURE__ */ jsxs4("footer", { className: "df-review-settings-actions df-review-edit-actions", children: [
3795
+ /* @__PURE__ */ jsx4("span", {}),
3796
+ /* @__PURE__ */ jsx4("button", { disabled: isSaving, type: "button", onClick: onClose, children: "Cancel" }),
3797
+ /* @__PURE__ */ jsx4("button", { disabled: isSaving, type: "submit", children: isSaving ? "Saving\u2026" : "Save" })
3798
+ ] })
3799
+ ] })
3800
+ ]
3801
+ }
3802
+ )
3803
+ ]
3804
+ }
3805
+ );
3806
+ };
3807
+
3808
+ // src/react-shell/qa/item.remote.actions.tsx
3809
+ import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
3586
3810
  var QaItemRemoteActions = ({
3587
3811
  isRemoteSource,
3588
3812
  isSubmitted,
@@ -3596,13 +3820,13 @@ var QaItemRemoteActions = ({
3596
3820
  const canOpenRemoteIssue = !isRemoteSource && Boolean(item.externalIssueUrl);
3597
3821
  const hasRemoteActions = canSubmitToRemote || canOpenRemoteIssue;
3598
3822
  if (!hasRemoteActions) return null;
3599
- return /* @__PURE__ */ jsxs4(
3823
+ return /* @__PURE__ */ jsxs5(
3600
3824
  "div",
3601
3825
  {
3602
3826
  className: "df-review-item-remote-actions",
3603
3827
  onClick: (event) => event.stopPropagation(),
3604
3828
  children: [
3605
- canSubmitToRemote && remoteAdapterEntry && /* @__PURE__ */ jsxs4(
3829
+ canSubmitToRemote && remoteAdapterEntry && /* @__PURE__ */ jsxs5(
3606
3830
  "button",
3607
3831
  {
3608
3832
  "aria-label": "Submit to remote",
@@ -3611,12 +3835,12 @@ var QaItemRemoteActions = ({
3611
3835
  type: "button",
3612
3836
  onClick: () => void onSubmitItem(numberedItem),
3613
3837
  children: [
3614
- /* @__PURE__ */ jsx4(Upload, { "aria-hidden": "true" }),
3615
- /* @__PURE__ */ jsx4("span", { children: isSubmitted ? "Submitted" : isSubmitting ? "Submitting" : "Submit" })
3838
+ /* @__PURE__ */ jsx5(Upload, { "aria-hidden": "true" }),
3839
+ /* @__PURE__ */ jsx5("span", { children: isSubmitted ? "Submitted" : isSubmitting ? "Submitting" : "Submit" })
3616
3840
  ]
3617
3841
  }
3618
3842
  ),
3619
- canOpenRemoteIssue && /* @__PURE__ */ jsx4(
3843
+ canOpenRemoteIssue && /* @__PURE__ */ jsx5(
3620
3844
  "a",
3621
3845
  {
3622
3846
  "aria-label": "Open remote issue",
@@ -3624,7 +3848,7 @@ var QaItemRemoteActions = ({
3624
3848
  href: item.externalIssueUrl,
3625
3849
  rel: "noreferrer",
3626
3850
  target: "_blank",
3627
- children: /* @__PURE__ */ jsx4(ExternalLink, { "aria-hidden": "true" })
3851
+ children: /* @__PURE__ */ jsx5(ExternalLink, { "aria-hidden": "true" })
3628
3852
  }
3629
3853
  )
3630
3854
  ]
@@ -3633,7 +3857,7 @@ var QaItemRemoteActions = ({
3633
3857
  };
3634
3858
 
3635
3859
  // src/react-shell/qa/item.status.actions.tsx
3636
- import { jsx as jsx5 } from "react/jsx-runtime";
3860
+ import { jsx as jsx6 } from "react/jsx-runtime";
3637
3861
  var getStatusOption = (status, statusOptions) => {
3638
3862
  const normalizedStatus = normalizeReviewItemStatus(status);
3639
3863
  return statusOptions.find((statusOption) => statusOption.value === status) ?? statusOptions.find(
@@ -3651,12 +3875,12 @@ var QaItemStatusActions = ({
3651
3875
  const statusClassName = `is-status-${normalizeReviewItemStatus(
3652
3876
  currentStatusOption.value
3653
3877
  )}`;
3654
- return /* @__PURE__ */ jsx5(
3878
+ return /* @__PURE__ */ jsx6(
3655
3879
  "div",
3656
3880
  {
3657
3881
  className: "df-review-item-status-actions",
3658
3882
  onClick: (event) => event.stopPropagation(),
3659
- children: canUpdateStatus ? /* @__PURE__ */ jsx5(
3883
+ children: canUpdateStatus ? /* @__PURE__ */ jsx6(
3660
3884
  "select",
3661
3885
  {
3662
3886
  "aria-label": "QA status",
@@ -3666,9 +3890,9 @@ var QaItemStatusActions = ({
3666
3890
  item,
3667
3891
  event.currentTarget.value
3668
3892
  ),
3669
- children: statusOptions.map((statusOption) => /* @__PURE__ */ jsx5("option", { value: statusOption.value, children: statusOption.label }, statusOption.value))
3893
+ children: statusOptions.map((statusOption) => /* @__PURE__ */ jsx6("option", { value: statusOption.value, children: statusOption.label }, statusOption.value))
3670
3894
  }
3671
- ) : /* @__PURE__ */ jsx5("span", { className: `df-review-item-status-badge ${statusClassName}`, children: currentStatusOption.label })
3895
+ ) : /* @__PURE__ */ jsx6("span", { className: `df-review-item-status-badge ${statusClassName}`, children: currentStatusOption.label })
3672
3896
  }
3673
3897
  );
3674
3898
  };
@@ -3812,25 +4036,107 @@ var isScrollableReviewAnchorElement = (element) => {
3812
4036
  };
3813
4037
 
3814
4038
  // src/react-shell/review/item.icons.tsx
3815
- import { jsx as jsx6 } from "react/jsx-runtime";
4039
+ import { jsx as jsx7 } from "react/jsx-runtime";
3816
4040
  var ReviewScopeIcon = ({ scope }) => {
3817
- if (scope === "mobile") return /* @__PURE__ */ jsx6(Smartphone, { "aria-hidden": "true" });
3818
- if (scope === "tablet") return /* @__PURE__ */ jsx6(RectangleHorizontal, { "aria-hidden": "true" });
3819
- if (scope === "wide") return /* @__PURE__ */ jsx6(Maximize2, { "aria-hidden": "true" });
3820
- if (scope === "dom") return /* @__PURE__ */ jsx6(SquareMousePointer, { "aria-hidden": "true" });
3821
- return /* @__PURE__ */ jsx6(Monitor, { "aria-hidden": "true" });
4041
+ if (scope === "mobile") return /* @__PURE__ */ jsx7(Smartphone, { "aria-hidden": "true" });
4042
+ if (scope === "tablet") return /* @__PURE__ */ jsx7(RectangleHorizontal, { "aria-hidden": "true" });
4043
+ if (scope === "wide") return /* @__PURE__ */ jsx7(Maximize2, { "aria-hidden": "true" });
4044
+ if (scope === "dom") return /* @__PURE__ */ jsx7(SquareMousePointer, { "aria-hidden": "true" });
4045
+ return /* @__PURE__ */ jsx7(Monitor, { "aria-hidden": "true" });
3822
4046
  };
3823
4047
  var getReviewItemMode = (item) => isAnchorRestorableReviewItem(item) ? "dom" : item.kind;
3824
4048
  var ReviewItemModeIcon = ({
3825
4049
  mode
3826
4050
  }) => {
3827
- if (mode === "area") return /* @__PURE__ */ jsx6(Scan, { "aria-hidden": "true" });
3828
- if (mode === "dom") return /* @__PURE__ */ jsx6(SquareMousePointer, { "aria-hidden": "true" });
3829
- return /* @__PURE__ */ jsx6(StickyNote, { "aria-hidden": "true" });
4051
+ if (mode === "area") return /* @__PURE__ */ jsx7(Scan, { "aria-hidden": "true" });
4052
+ if (mode === "dom") return /* @__PURE__ */ jsx7(SquareMousePointer, { "aria-hidden": "true" });
4053
+ return /* @__PURE__ */ jsx7(StickyNote, { "aria-hidden": "true" });
3830
4054
  };
3831
4055
 
4056
+ // src/react-shell/source.open.ts
4057
+ var SOURCE_SELECTOR = [
4058
+ "[data-wrk-source-file]",
4059
+ "[data-wrk-source-component]",
4060
+ "[data-wrk-source-line]",
4061
+ "[data-wrk-source-column]",
4062
+ "[data-file]",
4063
+ "[data-component]",
4064
+ "[data-section-index]",
4065
+ "[data-section-id]"
4066
+ ].join(", ");
4067
+ var getSourceHintElement = (target) => {
4068
+ return getEventElement(target)?.closest(SOURCE_SELECTOR) ?? null;
4069
+ };
4070
+ var getElementSourceHint = (target) => {
4071
+ const sourceElement = getSourceHintElement(target);
4072
+ if (!sourceElement) return void 0;
4073
+ const source = {
4074
+ component: getSourceAttribute(
4075
+ sourceElement,
4076
+ "data-wrk-source-component",
4077
+ "data-component"
4078
+ ),
4079
+ file: getSourceAttribute(sourceElement, "data-wrk-source-file", "data-file"),
4080
+ line: getSourceAttribute(sourceElement, "data-wrk-source-line"),
4081
+ column: getSourceAttribute(sourceElement, "data-wrk-source-column"),
4082
+ sectionId: getSourceAttribute(sourceElement, "data-section-id"),
4083
+ sectionIndex: getSourceAttribute(sourceElement, "data-section-index")
4084
+ };
4085
+ return Object.values(source).some(Boolean) ? source : void 0;
4086
+ };
4087
+ var getSourceOpenUrl = (source, sourceRoot) => {
4088
+ const file = source?.file?.trim();
4089
+ if (!file) return null;
4090
+ const sourcePath = getSourcePath(file, sourceRoot);
4091
+ if (!sourcePath) return null;
4092
+ const line = getSourcePosition(source?.line);
4093
+ const column = getSourcePosition(source?.column);
4094
+ const encodedPath = encodeURI(sourcePath).replace(
4095
+ /[#?]/g,
4096
+ (match) => match === "#" ? "%23" : "%3F"
4097
+ );
4098
+ return `vscode://file/${encodedPath}:${line}:${column}`;
4099
+ };
4100
+ var openSourceInEditor = (source, sourceRoot) => {
4101
+ const url = getSourceOpenUrl(source, sourceRoot);
4102
+ if (!url) return false;
4103
+ window.open(url, "_blank", "noreferrer");
4104
+ return true;
4105
+ };
4106
+ function getSourceAttribute(element, ...names) {
4107
+ for (const name of names) {
4108
+ const value = element.getAttribute(name)?.trim();
4109
+ if (value) return value;
4110
+ }
4111
+ return void 0;
4112
+ }
4113
+ function getEventElement(target) {
4114
+ if (!target || typeof target !== "object") return null;
4115
+ const node = target;
4116
+ if (node.nodeType === 1 && typeof node.closest === "function") {
4117
+ return node;
4118
+ }
4119
+ if (node.parentElement && typeof node.parentElement.closest === "function") {
4120
+ return node.parentElement;
4121
+ }
4122
+ return null;
4123
+ }
4124
+ function getSourcePath(file, sourceRoot) {
4125
+ const normalizedFile = file.replace(/\\/g, "/");
4126
+ if (normalizedFile.startsWith("/") || /^[a-zA-Z]:\//.test(normalizedFile)) {
4127
+ return normalizedFile;
4128
+ }
4129
+ const normalizedRoot = sourceRoot?.trim().replace(/\\/g, "/").replace(/\/+$/, "");
4130
+ if (!normalizedRoot) return null;
4131
+ return `${normalizedRoot}/${normalizedFile.replace(/^\/+/, "")}`;
4132
+ }
4133
+ function getSourcePosition(value) {
4134
+ const position = Number(value);
4135
+ return Number.isInteger(position) && position > 0 ? position : 1;
4136
+ }
4137
+
3832
4138
  // src/react-shell/qa/item.card.tsx
3833
- import { jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
4139
+ import { jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
3834
4140
  var formatItemCardDate = (value) => {
3835
4141
  const date = new Date(value);
3836
4142
  if (Number.isNaN(date.getTime())) return value;
@@ -3851,10 +4157,12 @@ var QaItemCard = ({
3851
4157
  remoteAdapterEntry,
3852
4158
  copiedPromptKey,
3853
4159
  selectedItemId,
4160
+ sourceRoot,
3854
4161
  onChangeItemStatus,
3855
4162
  onClearSelectedItem,
3856
4163
  onRemoveItem,
3857
4164
  onCopyItemPrompt,
4165
+ onEditItem,
3858
4166
  onRestoreReviewItem,
3859
4167
  onSubmitItem,
3860
4168
  onToggleItemOverlayVisibility
@@ -3871,8 +4179,10 @@ var QaItemCard = ({
3871
4179
  const statusOptions = activeAdapterEntry.statusOptions;
3872
4180
  const isActive = item.id === selectedItemId;
3873
4181
  const canUpdateStatus = Boolean(activeAdapterEntry.updateStatus) && statusOptions.length > 0 && !isSubmitting;
4182
+ const canEditItem = activeAdapterEntry.canUpdate && !isSubmitting;
3874
4183
  const itemMeta = [formatItemCardDate(item.createdAt), itemAuthor].filter(Boolean).join(" | ");
3875
- return /* @__PURE__ */ jsxs5(
4184
+ const sourceOpenUrl = getSourceOpenUrl(item.anchor?.source, sourceRoot);
4185
+ return /* @__PURE__ */ jsxs6(
3876
4186
  "article",
3877
4187
  {
3878
4188
  className: `df-review-item-card${isActive ? " is-active" : ""}${getItemPresetScope(item) !== currentPresetScope ? " is-dim" : ""}${isOverlayVisible ? "" : " is-overlay-hidden"}`,
@@ -3884,46 +4194,58 @@ var QaItemCard = ({
3884
4194
  onRestoreReviewItem(item);
3885
4195
  },
3886
4196
  children: [
3887
- /* @__PURE__ */ jsxs5("div", { className: "df-review-item-header", children: [
3888
- /* @__PURE__ */ jsxs5("div", { className: "df-review-item-main", children: [
3889
- /* @__PURE__ */ jsxs5("span", { className: "df-review-item-badges", children: [
3890
- /* @__PURE__ */ jsx7("span", { className: "df-review-item-id", children: numberedItem.displayLabel }),
3891
- /* @__PURE__ */ jsxs5(
4197
+ /* @__PURE__ */ jsxs6("div", { className: "df-review-item-header", children: [
4198
+ /* @__PURE__ */ jsxs6("div", { className: "df-review-item-main", children: [
4199
+ /* @__PURE__ */ jsxs6("span", { className: "df-review-item-badges", children: [
4200
+ /* @__PURE__ */ jsx8("span", { className: "df-review-item-id", children: numberedItem.displayLabel }),
4201
+ /* @__PURE__ */ jsxs6(
3892
4202
  "span",
3893
4203
  {
3894
4204
  className: `df-review-item-scope is-scope-${numberedItem.scope}`,
3895
4205
  children: [
3896
- /* @__PURE__ */ jsx7(ReviewScopeIcon, { scope: numberedItem.scope }),
4206
+ /* @__PURE__ */ jsx8(ReviewScopeIcon, { scope: numberedItem.scope }),
3897
4207
  numberedItem.label
3898
4208
  ]
3899
4209
  }
3900
4210
  ),
3901
- /* @__PURE__ */ jsxs5("span", { className: `df-review-item-mode is-mode-${itemMode}`, children: [
3902
- /* @__PURE__ */ jsx7(ReviewItemModeIcon, { mode: itemMode }),
4211
+ /* @__PURE__ */ jsxs6("span", { className: `df-review-item-mode is-mode-${itemMode}`, children: [
4212
+ /* @__PURE__ */ jsx8(ReviewItemModeIcon, { mode: itemMode }),
3903
4213
  itemMode
3904
4214
  ] })
3905
4215
  ] }),
3906
- /* @__PURE__ */ jsx7("strong", { className: "df-review-item-comment", children: itemComment }),
3907
- /* @__PURE__ */ jsx7("small", { className: "df-review-item-meta", children: itemMeta }),
3908
- item.submitError && /* @__PURE__ */ jsx7("small", { className: "df-review-item-error", children: item.submitError })
4216
+ /* @__PURE__ */ jsx8("strong", { className: "df-review-item-comment", children: itemComment }),
4217
+ /* @__PURE__ */ jsx8("small", { className: "df-review-item-meta", children: itemMeta }),
4218
+ item.submitError && /* @__PURE__ */ jsx8("small", { className: "df-review-item-error", children: item.submitError })
3909
4219
  ] }),
3910
- /* @__PURE__ */ jsxs5(
4220
+ /* @__PURE__ */ jsxs6(
3911
4221
  "div",
3912
4222
  {
3913
4223
  className: "df-review-item-header-actions",
3914
4224
  onClick: (event) => event.stopPropagation(),
3915
4225
  children: [
3916
- /* @__PURE__ */ jsx7(
4226
+ /* @__PURE__ */ jsx8(
3917
4227
  "button",
3918
4228
  {
3919
4229
  "aria-label": isOverlayVisible ? "Hide QA overlay" : "Show QA overlay",
3920
4230
  className: `df-review-item-visibility${isOverlayVisible ? " is-visible" : " is-hidden"}`,
3921
4231
  type: "button",
3922
4232
  onClick: () => onToggleItemOverlayVisibility(item.id),
3923
- children: isOverlayVisible ? /* @__PURE__ */ jsx7(Eye, { "aria-hidden": "true" }) : /* @__PURE__ */ jsx7(EyeOff, { "aria-hidden": "true" })
4233
+ children: isOverlayVisible ? /* @__PURE__ */ jsx8(Eye, { "aria-hidden": "true" }) : /* @__PURE__ */ jsx8(EyeOff, { "aria-hidden": "true" })
4234
+ }
4235
+ ),
4236
+ sourceOpenUrl && /* @__PURE__ */ jsx8(
4237
+ "a",
4238
+ {
4239
+ "aria-label": "Open source in VS Code",
4240
+ className: "df-review-item-source-open",
4241
+ href: sourceOpenUrl,
4242
+ rel: "noreferrer",
4243
+ target: "_blank",
4244
+ title: "Open source in VS Code",
4245
+ children: /* @__PURE__ */ jsx8(FileCodeCorner, { "aria-hidden": "true" })
3924
4246
  }
3925
4247
  ),
3926
- /* @__PURE__ */ jsx7(
4248
+ /* @__PURE__ */ jsx8(
3927
4249
  "button",
3928
4250
  {
3929
4251
  "aria-label": isPromptCopied ? "Copied QA prompt" : "Copy QA prompt",
@@ -3931,25 +4253,36 @@ var QaItemCard = ({
3931
4253
  title: isPromptCopied ? "Copied QA prompt" : "Copy QA prompt",
3932
4254
  type: "button",
3933
4255
  onClick: () => onCopyItemPrompt(numberedItem),
3934
- children: /* @__PURE__ */ jsx7(Copy, { "aria-hidden": "true" })
4256
+ children: /* @__PURE__ */ jsx8(Copy, { "aria-hidden": "true" })
4257
+ }
4258
+ ),
4259
+ canEditItem && /* @__PURE__ */ jsx8(
4260
+ "button",
4261
+ {
4262
+ "aria-label": "Edit QA comment",
4263
+ className: "df-review-item-edit",
4264
+ title: "Edit QA comment",
4265
+ type: "button",
4266
+ onClick: () => onEditItem(item),
4267
+ children: /* @__PURE__ */ jsx8(Pencil, { "aria-hidden": "true" })
3935
4268
  }
3936
4269
  ),
3937
- canRemoveItem && /* @__PURE__ */ jsx7(
4270
+ canRemoveItem && /* @__PURE__ */ jsx8(
3938
4271
  "button",
3939
4272
  {
3940
4273
  "aria-label": "Delete QA",
3941
4274
  className: "df-review-item-delete",
3942
4275
  type: "button",
3943
4276
  onClick: () => void onRemoveItem(item),
3944
- children: /* @__PURE__ */ jsx7(X, { "aria-hidden": "true" })
4277
+ children: /* @__PURE__ */ jsx8(X, { "aria-hidden": "true" })
3945
4278
  }
3946
4279
  )
3947
4280
  ]
3948
4281
  }
3949
4282
  )
3950
4283
  ] }),
3951
- /* @__PURE__ */ jsxs5("div", { className: "df-review-item-actions", children: [
3952
- /* @__PURE__ */ jsx7(
4284
+ /* @__PURE__ */ jsxs6("div", { className: "df-review-item-actions", children: [
4285
+ /* @__PURE__ */ jsx8(
3953
4286
  QaItemStatusActions,
3954
4287
  {
3955
4288
  canUpdateStatus,
@@ -3958,7 +4291,7 @@ var QaItemCard = ({
3958
4291
  onChangeItemStatus
3959
4292
  }
3960
4293
  ),
3961
- /* @__PURE__ */ jsx7(
4294
+ /* @__PURE__ */ jsx8(
3962
4295
  QaItemRemoteActions,
3963
4296
  {
3964
4297
  isRemoteSource,
@@ -3977,19 +4310,19 @@ var QaItemCard = ({
3977
4310
  };
3978
4311
 
3979
4312
  // src/react-shell/presence/row.tsx
3980
- import { jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
4313
+ import { jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
3981
4314
  var PresenceRow = ({
3982
4315
  presenceSessionId,
3983
4316
  users
3984
4317
  }) => {
3985
4318
  if (users.length === 0) return null;
3986
- return /* @__PURE__ */ jsxs6("div", { "aria-label": "Review presence", className: "df-review-presence-row", children: [
3987
- /* @__PURE__ */ jsxs6("span", { className: "df-review-presence-label", children: [
3988
- /* @__PURE__ */ jsx8(Users, { "aria-hidden": "true" }),
4319
+ return /* @__PURE__ */ jsxs7("div", { "aria-label": "Review presence", className: "df-review-presence-row", children: [
4320
+ /* @__PURE__ */ jsxs7("span", { className: "df-review-presence-label", children: [
4321
+ /* @__PURE__ */ jsx9(Users, { "aria-hidden": "true" }),
3989
4322
  "online ",
3990
4323
  users.length
3991
4324
  ] }),
3992
- /* @__PURE__ */ jsx8("div", { className: "df-review-presence-list", children: users.map((user) => /* @__PURE__ */ jsxs6(
4325
+ /* @__PURE__ */ jsx9("div", { className: "df-review-presence-list", children: users.map((user) => /* @__PURE__ */ jsxs7(
3993
4326
  "span",
3994
4327
  {
3995
4328
  className: `df-review-presence-chip${user.sessionId === presenceSessionId ? " is-self" : ""}`,
@@ -3997,8 +4330,8 @@ var PresenceRow = ({
3997
4330
  "--df-review-presence-color": user.color
3998
4331
  },
3999
4332
  children: [
4000
- /* @__PURE__ */ jsx8("span", { className: "df-review-presence-dot", "aria-hidden": "true" }),
4001
- /* @__PURE__ */ jsx8("span", { className: "df-review-presence-name", children: user.userId })
4333
+ /* @__PURE__ */ jsx9("span", { className: "df-review-presence-dot", "aria-hidden": "true" }),
4334
+ /* @__PURE__ */ jsx9("span", { className: "df-review-presence-name", children: user.userId })
4002
4335
  ]
4003
4336
  },
4004
4337
  user.sessionId
@@ -4007,7 +4340,7 @@ var PresenceRow = ({
4007
4340
  };
4008
4341
 
4009
4342
  // src/react-shell/qa/panel.header.tsx
4010
- import { jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
4343
+ import { jsx as jsx10, jsxs as jsxs8 } from "react/jsx-runtime";
4011
4344
  var QaPanelHeader = ({
4012
4345
  activeItemCount,
4013
4346
  currentPagePresenceUsers,
@@ -4023,34 +4356,34 @@ var QaPanelHeader = ({
4023
4356
  onQaFilterChange,
4024
4357
  onRefreshReviewData
4025
4358
  }) => {
4026
- return /* @__PURE__ */ jsxs7("div", { className: "df-review-list-header", children: [
4027
- /* @__PURE__ */ jsxs7("div", { className: "df-review-list-toolbar", children: [
4028
- /* @__PURE__ */ jsxs7("div", { className: "df-review-list-controls", children: [
4029
- showSourceSelect && /* @__PURE__ */ jsx9(
4359
+ return /* @__PURE__ */ jsxs8("div", { className: "df-review-list-header", children: [
4360
+ /* @__PURE__ */ jsxs8("div", { className: "df-review-list-toolbar", children: [
4361
+ /* @__PURE__ */ jsxs8("div", { className: "df-review-list-controls", children: [
4362
+ showSourceSelect && /* @__PURE__ */ jsx10(
4030
4363
  "select",
4031
4364
  {
4032
4365
  "aria-label": "QA source",
4033
4366
  className: "df-review-source-select",
4034
4367
  value: source,
4035
4368
  onChange: (event) => onChangeReviewSource(event.currentTarget.value),
4036
- children: sourceEntries.map((entry) => /* @__PURE__ */ jsx9("option", { value: entry.label, children: entry.label }, entry.label))
4369
+ children: sourceEntries.map((entry) => /* @__PURE__ */ jsx10("option", { value: entry.label, children: entry.label }, entry.label))
4037
4370
  }
4038
4371
  ),
4039
- /* @__PURE__ */ jsx9(
4372
+ /* @__PURE__ */ jsx10(
4040
4373
  "button",
4041
4374
  {
4042
4375
  "aria-label": "Refresh QA",
4043
4376
  className: "df-review-source-refresh",
4044
4377
  type: "button",
4045
4378
  onClick: () => void onRefreshReviewData(),
4046
- children: /* @__PURE__ */ jsx9(RefreshCw, { "aria-hidden": "true" })
4379
+ children: /* @__PURE__ */ jsx10(RefreshCw, { "aria-hidden": "true" })
4047
4380
  }
4048
4381
  )
4049
4382
  ] }),
4050
- /* @__PURE__ */ jsx9("div", { className: "df-review-filter-tabs", "aria-label": "QA filters", children: REVIEW_QA_FILTERS.map((filter) => {
4383
+ /* @__PURE__ */ jsx10("div", { className: "df-review-filter-tabs", "aria-label": "QA filters", children: REVIEW_QA_FILTERS.map((filter) => {
4051
4384
  const count = qaFilterCounts.get(filter.key) ?? 0;
4052
4385
  const isActive = qaFilter === filter.key;
4053
- return /* @__PURE__ */ jsx9(
4386
+ return /* @__PURE__ */ jsx10(
4054
4387
  "button",
4055
4388
  {
4056
4389
  "aria-label": `${filter.label} QA (${count})`,
@@ -4058,23 +4391,23 @@ var QaPanelHeader = ({
4058
4391
  className: `df-review-filter-tab${isActive ? " is-active" : ""}`,
4059
4392
  type: "button",
4060
4393
  onClick: () => onQaFilterChange(filter.key),
4061
- children: /* @__PURE__ */ jsx9("span", { className: "df-review-filter-icon", children: filter.scope ? /* @__PURE__ */ jsx9(ReviewScopeIcon, { scope: filter.scope }) : /* @__PURE__ */ jsx9(ListFilter, { "aria-hidden": "true" }) })
4394
+ children: /* @__PURE__ */ jsx10("span", { className: "df-review-filter-icon", children: filter.scope ? /* @__PURE__ */ jsx10(ReviewScopeIcon, { scope: filter.scope }) : /* @__PURE__ */ jsx10(ListFilter, { "aria-hidden": "true" }) })
4062
4395
  },
4063
4396
  filter.key
4064
4397
  );
4065
4398
  }) })
4066
4399
  ] }),
4067
- /* @__PURE__ */ jsxs7("div", { className: "df-review-list-title", children: [
4068
- /* @__PURE__ */ jsxs7("span", { children: [
4400
+ /* @__PURE__ */ jsxs8("div", { className: "df-review-list-title", children: [
4401
+ /* @__PURE__ */ jsxs8("span", { children: [
4069
4402
  label,
4070
4403
  " QA"
4071
4404
  ] }),
4072
- /* @__PURE__ */ jsxs7("strong", { children: [
4405
+ /* @__PURE__ */ jsxs8("strong", { children: [
4073
4406
  filteredItemCount,
4074
4407
  qaFilter === "all" ? "" : `/${activeItemCount}`
4075
4408
  ] })
4076
4409
  ] }),
4077
- /* @__PURE__ */ jsx9(
4410
+ /* @__PURE__ */ jsx10(
4078
4411
  PresenceRow,
4079
4412
  {
4080
4413
  presenceSessionId,
@@ -4085,7 +4418,7 @@ var QaPanelHeader = ({
4085
4418
  };
4086
4419
 
4087
4420
  // src/react-shell/qa/panel.tsx
4088
- import { jsx as jsx10, jsxs as jsxs8 } from "react/jsx-runtime";
4421
+ import { jsx as jsx11, jsxs as jsxs9 } from "react/jsx-runtime";
4089
4422
  var ReviewQaPanel = ({
4090
4423
  activeAdapterEntry,
4091
4424
  activeItems,
@@ -4103,12 +4436,14 @@ var ReviewQaPanel = ({
4103
4436
  remoteAdapterEntry,
4104
4437
  selectedItemId,
4105
4438
  showSourceSelect,
4439
+ sourceRoot,
4106
4440
  source,
4107
4441
  sourceEntries,
4108
4442
  onChangeItemStatus,
4109
4443
  onClearSelectedItem,
4110
4444
  onChangeReviewSource,
4111
4445
  onCopyItemPrompt,
4446
+ onEditItem,
4112
4447
  onQaFilterChange,
4113
4448
  onRefreshReviewData,
4114
4449
  onRemoveItem,
@@ -4116,8 +4451,8 @@ var ReviewQaPanel = ({
4116
4451
  onSubmitItem,
4117
4452
  onToggleItemOverlayVisibility
4118
4453
  }) => {
4119
- return /* @__PURE__ */ jsx10("aside", { className: "df-review-qa-panel", "aria-hidden": !isListVisible, children: /* @__PURE__ */ jsx10("div", { className: "df-review-panel-body", children: /* @__PURE__ */ jsxs8("section", { className: "df-review-item-list", children: [
4120
- /* @__PURE__ */ jsx10(
4454
+ return /* @__PURE__ */ jsx11("aside", { className: "df-review-qa-panel", "aria-hidden": !isListVisible, children: /* @__PURE__ */ jsx11("div", { className: "df-review-panel-body", children: /* @__PURE__ */ jsxs9("section", { className: "df-review-item-list", children: [
4455
+ /* @__PURE__ */ jsx11(
4121
4456
  QaPanelHeader,
4122
4457
  {
4123
4458
  activeItemCount: activeItems.length,
@@ -4135,7 +4470,7 @@ var ReviewQaPanel = ({
4135
4470
  onRefreshReviewData
4136
4471
  }
4137
4472
  ),
4138
- /* @__PURE__ */ jsxs8(
4473
+ /* @__PURE__ */ jsxs9(
4139
4474
  "div",
4140
4475
  {
4141
4476
  className: "df-review-list-scroll",
@@ -4145,11 +4480,11 @@ var ReviewQaPanel = ({
4145
4480
  }
4146
4481
  },
4147
4482
  children: [
4148
- activeItems.length === 0 && /* @__PURE__ */ jsx10("p", { className: "df-review-empty", children: isRemoteSource ? `No ${activeAdapterEntry.label} QA on this page.` : "No QA on this page." }),
4149
- activeItems.length > 0 && filteredNumberedActiveItems.length === 0 && /* @__PURE__ */ jsx10("p", { className: "df-review-empty", children: "No QA in this filter." }),
4483
+ activeItems.length === 0 && /* @__PURE__ */ jsx11("p", { className: "df-review-empty", children: isRemoteSource ? `No ${activeAdapterEntry.label} QA on this page.` : "No QA on this page." }),
4484
+ activeItems.length > 0 && filteredNumberedActiveItems.length === 0 && /* @__PURE__ */ jsx11("p", { className: "df-review-empty", children: "No QA in this filter." }),
4150
4485
  filteredNumberedActiveItems.map((numberedItem) => {
4151
4486
  const { item } = numberedItem;
4152
- return /* @__PURE__ */ jsx10(
4487
+ return /* @__PURE__ */ jsx11(
4153
4488
  QaItemCard,
4154
4489
  {
4155
4490
  activeAdapterEntry,
@@ -4161,9 +4496,11 @@ var ReviewQaPanel = ({
4161
4496
  remoteAdapterEntry,
4162
4497
  copiedPromptKey,
4163
4498
  selectedItemId,
4499
+ sourceRoot,
4164
4500
  onChangeItemStatus,
4165
4501
  onClearSelectedItem,
4166
4502
  onCopyItemPrompt,
4503
+ onEditItem,
4167
4504
  onRemoveItem,
4168
4505
  onRestoreReviewItem,
4169
4506
  onSubmitItem,
@@ -4179,53 +4516,41 @@ var ReviewQaPanel = ({
4179
4516
  };
4180
4517
 
4181
4518
  // src/react-shell/review/mode.toolbar.tsx
4182
- import { jsx as jsx11, jsxs as jsxs9 } from "react/jsx-runtime";
4519
+ import { jsx as jsx12, jsxs as jsxs10 } from "react/jsx-runtime";
4183
4520
  var ReviewModeToolbar = ({
4184
- canWriteAny,
4185
4521
  canWriteArea,
4186
4522
  canWriteDom,
4187
- canWriteNote,
4188
4523
  mode,
4189
4524
  onSetReviewMode
4190
4525
  }) => {
4191
- if (!canWriteAny) return null;
4192
- return /* @__PURE__ */ jsxs9("div", { className: "df-review-mode", "aria-label": "Add QA", children: [
4193
- canWriteDom && /* @__PURE__ */ jsx11(
4526
+ if (!canWriteDom && !canWriteArea) return null;
4527
+ return /* @__PURE__ */ jsxs10("div", { className: "df-review-mode", "aria-label": "Add QA", children: [
4528
+ canWriteDom && /* @__PURE__ */ jsx12(
4194
4529
  "button",
4195
4530
  {
4196
4531
  "aria-label": "Element",
4197
4532
  className: `df-review-mode-button is-element${mode === "element" ? " is-active" : ""}`,
4198
4533
  type: "button",
4199
4534
  onClick: () => onSetReviewMode("element"),
4200
- children: /* @__PURE__ */ jsx11(SquareMousePointer, { "aria-hidden": "true" })
4535
+ children: /* @__PURE__ */ jsx12(SquareMousePointer, { "aria-hidden": "true" })
4201
4536
  }
4202
4537
  ),
4203
- canWriteDom && (canWriteNote || canWriteArea) && /* @__PURE__ */ jsx11("span", { className: "df-review-mode-divider", "aria-hidden": "true", children: "|" }),
4204
- canWriteNote && /* @__PURE__ */ jsx11(
4205
- "button",
4206
- {
4207
- "aria-label": "Note",
4208
- className: `df-review-mode-button is-note${mode === "note" ? " is-active" : ""}`,
4209
- type: "button",
4210
- onClick: () => onSetReviewMode("note"),
4211
- children: /* @__PURE__ */ jsx11(StickyNote, { "aria-hidden": "true" })
4212
- }
4213
- ),
4214
- canWriteArea && /* @__PURE__ */ jsx11(
4538
+ canWriteDom && canWriteArea && /* @__PURE__ */ jsx12("span", { className: "df-review-mode-divider", "aria-hidden": "true", children: "|" }),
4539
+ canWriteArea && /* @__PURE__ */ jsx12(
4215
4540
  "button",
4216
4541
  {
4217
4542
  "aria-label": "Area",
4218
4543
  className: `df-review-mode-button is-area${mode === "area" ? " is-active" : ""}`,
4219
4544
  type: "button",
4220
4545
  onClick: () => onSetReviewMode("area"),
4221
- children: /* @__PURE__ */ jsx11(Scan, { "aria-hidden": "true" })
4546
+ children: /* @__PURE__ */ jsx12(Scan, { "aria-hidden": "true" })
4222
4547
  }
4223
4548
  )
4224
4549
  ] });
4225
4550
  };
4226
4551
 
4227
4552
  // src/react-shell/ruler/gutters.tsx
4228
- import { Fragment as Fragment2, jsx as jsx12, jsxs as jsxs10 } from "react/jsx-runtime";
4553
+ import { Fragment as Fragment2, jsx as jsx13, jsxs as jsxs11 } from "react/jsx-runtime";
4229
4554
  var RulerGutters = ({
4230
4555
  rulerHover,
4231
4556
  rulerScaleX,
@@ -4233,9 +4558,9 @@ var RulerGutters = ({
4233
4558
  rulerUnit,
4234
4559
  size
4235
4560
  }) => {
4236
- return /* @__PURE__ */ jsxs10(Fragment2, { children: [
4237
- /* @__PURE__ */ jsx12("div", { className: "df-review-ruler-corner", "aria-hidden": "true" }),
4238
- /* @__PURE__ */ jsxs10(
4561
+ return /* @__PURE__ */ jsxs11(Fragment2, { children: [
4562
+ /* @__PURE__ */ jsx13("div", { className: "df-review-ruler-corner", "aria-hidden": "true" }),
4563
+ /* @__PURE__ */ jsxs11(
4239
4564
  "div",
4240
4565
  {
4241
4566
  className: "df-review-ruler-gutter is-x",
@@ -4243,15 +4568,15 @@ var RulerGutters = ({
4243
4568
  "--df-review-ruler-step-x": `${rulerScaleX * 20}px`
4244
4569
  },
4245
4570
  children: [
4246
- /* @__PURE__ */ jsxs10("div", { className: "df-review-ruler-frame-label", children: [
4247
- /* @__PURE__ */ jsx12("strong", { children: size.label }),
4248
- /* @__PURE__ */ jsxs10("span", { children: [
4571
+ /* @__PURE__ */ jsxs11("div", { className: "df-review-ruler-frame-label", children: [
4572
+ /* @__PURE__ */ jsx13("strong", { children: size.label }),
4573
+ /* @__PURE__ */ jsxs11("span", { children: [
4249
4574
  size.designWidth,
4250
4575
  size.designHeight ? `x${size.designHeight}` : "",
4251
4576
  rulerUnit
4252
4577
  ] })
4253
4578
  ] }),
4254
- rulerHover && /* @__PURE__ */ jsx12(
4579
+ rulerHover && /* @__PURE__ */ jsx13(
4255
4580
  "div",
4256
4581
  {
4257
4582
  className: "df-review-ruler-coord is-x",
@@ -4262,14 +4587,14 @@ var RulerGutters = ({
4262
4587
  ]
4263
4588
  }
4264
4589
  ),
4265
- /* @__PURE__ */ jsx12(
4590
+ /* @__PURE__ */ jsx13(
4266
4591
  "div",
4267
4592
  {
4268
4593
  className: "df-review-ruler-gutter is-y",
4269
4594
  style: {
4270
4595
  "--df-review-ruler-step-y": `${rulerScaleY * 20}px`
4271
4596
  },
4272
- children: rulerHover && /* @__PURE__ */ jsx12(
4597
+ children: rulerHover && /* @__PURE__ */ jsx13(
4273
4598
  "div",
4274
4599
  {
4275
4600
  className: "df-review-ruler-coord is-y",
@@ -4283,7 +4608,7 @@ var RulerGutters = ({
4283
4608
  };
4284
4609
 
4285
4610
  // src/react-shell/ruler/overlay.tsx
4286
- import { Fragment as Fragment3, jsx as jsx13, jsxs as jsxs11 } from "react/jsx-runtime";
4611
+ import { Fragment as Fragment3, jsx as jsx14, jsxs as jsxs12 } from "react/jsx-runtime";
4287
4612
  var RulerOverlay = ({
4288
4613
  iframeRef,
4289
4614
  isRulerDragging,
@@ -4293,7 +4618,7 @@ var RulerOverlay = ({
4293
4618
  rulerOverlayRef,
4294
4619
  size
4295
4620
  }) => {
4296
- return /* @__PURE__ */ jsxs11(
4621
+ return /* @__PURE__ */ jsxs12(
4297
4622
  "div",
4298
4623
  {
4299
4624
  ref: rulerOverlayRef,
@@ -4307,8 +4632,8 @@ var RulerOverlay = ({
4307
4632
  );
4308
4633
  },
4309
4634
  children: [
4310
- rulerHover && /* @__PURE__ */ jsxs11(Fragment3, { children: [
4311
- /* @__PURE__ */ jsx13(
4635
+ rulerHover && /* @__PURE__ */ jsxs12(Fragment3, { children: [
4636
+ /* @__PURE__ */ jsx14(
4312
4637
  "div",
4313
4638
  {
4314
4639
  className: "df-review-ruler-guide is-x",
@@ -4316,7 +4641,7 @@ var RulerOverlay = ({
4316
4641
  style: { top: `${rulerHover.y}px` }
4317
4642
  }
4318
4643
  ),
4319
- /* @__PURE__ */ jsx13(
4644
+ /* @__PURE__ */ jsx14(
4320
4645
  "div",
4321
4646
  {
4322
4647
  className: "df-review-ruler-guide is-y",
@@ -4325,8 +4650,8 @@ var RulerOverlay = ({
4325
4650
  }
4326
4651
  )
4327
4652
  ] }),
4328
- rulerMeasure && (rulerMeasure.width > 0 || rulerMeasure.height > 0) && /* @__PURE__ */ jsxs11(Fragment3, { children: [
4329
- /* @__PURE__ */ jsx13(
4653
+ rulerMeasure && (rulerMeasure.width > 0 || rulerMeasure.height > 0) && /* @__PURE__ */ jsxs12(Fragment3, { children: [
4654
+ /* @__PURE__ */ jsx14(
4330
4655
  "div",
4331
4656
  {
4332
4657
  className: "df-review-ruler-selection",
@@ -4339,7 +4664,7 @@ var RulerOverlay = ({
4339
4664
  }
4340
4665
  }
4341
4666
  ),
4342
- /* @__PURE__ */ jsx13(
4667
+ /* @__PURE__ */ jsx14(
4343
4668
  "div",
4344
4669
  {
4345
4670
  className: "df-review-ruler-label",
@@ -4363,12 +4688,10 @@ var RulerOverlay = ({
4363
4688
  };
4364
4689
 
4365
4690
  // src/react-shell/target/frame.tsx
4366
- import { jsx as jsx14, jsxs as jsxs12 } from "react/jsx-runtime";
4691
+ import { jsx as jsx15, jsxs as jsxs13 } from "react/jsx-runtime";
4367
4692
  var ReviewTargetFrame = ({
4368
- canWriteAny,
4369
4693
  canWriteArea,
4370
4694
  canWriteDom,
4371
- canWriteNote,
4372
4695
  frameScrollRef,
4373
4696
  iframeRef,
4374
4697
  isRulerAvailable,
@@ -4388,13 +4711,13 @@ var ReviewTargetFrame = ({
4388
4711
  onSetReviewMode
4389
4712
  }) => {
4390
4713
  const showRuler = isRulerVisible && isRulerAvailable;
4391
- return /* @__PURE__ */ jsx14("main", { className: "df-review-stage", children: /* @__PURE__ */ jsxs12("div", { className: "df-review-frame", children: [
4392
- /* @__PURE__ */ jsx14("div", { className: "df-review-frame-scroll", ref: frameScrollRef, children: /* @__PURE__ */ jsx14("div", { className: "df-review-frame-canvas", children: /* @__PURE__ */ jsxs12(
4714
+ return /* @__PURE__ */ jsx15("main", { className: "df-review-stage", children: /* @__PURE__ */ jsxs13("div", { className: "df-review-frame", children: [
4715
+ /* @__PURE__ */ jsx15("div", { className: "df-review-frame-scroll", ref: frameScrollRef, children: /* @__PURE__ */ jsx15("div", { className: "df-review-frame-canvas", children: /* @__PURE__ */ jsxs13(
4393
4716
  "div",
4394
4717
  {
4395
4718
  className: `df-review-device-frame${showRuler ? " is-ruler" : ""}`,
4396
4719
  children: [
4397
- showRuler && /* @__PURE__ */ jsx14(
4720
+ showRuler && /* @__PURE__ */ jsx15(
4398
4721
  RulerGutters,
4399
4722
  {
4400
4723
  rulerHover,
@@ -4404,7 +4727,7 @@ var ReviewTargetFrame = ({
4404
4727
  size
4405
4728
  }
4406
4729
  ),
4407
- /* @__PURE__ */ jsxs12(
4730
+ /* @__PURE__ */ jsxs13(
4408
4731
  "div",
4409
4732
  {
4410
4733
  className: "df-review-device",
@@ -4415,7 +4738,7 @@ var ReviewTargetFrame = ({
4415
4738
  minHeight: `${size.height}px`
4416
4739
  },
4417
4740
  children: [
4418
- /* @__PURE__ */ jsx14(
4741
+ /* @__PURE__ */ jsx15(
4419
4742
  "iframe",
4420
4743
  {
4421
4744
  ref: iframeRef,
@@ -4427,7 +4750,7 @@ var ReviewTargetFrame = ({
4427
4750
  },
4428
4751
  targetSrc
4429
4752
  ),
4430
- showRuler && /* @__PURE__ */ jsx14(
4753
+ showRuler && /* @__PURE__ */ jsx15(
4431
4754
  RulerOverlay,
4432
4755
  {
4433
4756
  iframeRef,
@@ -4445,13 +4768,11 @@ var ReviewTargetFrame = ({
4445
4768
  ]
4446
4769
  }
4447
4770
  ) }) }),
4448
- /* @__PURE__ */ jsx14("div", { className: "df-review-frame-actions", children: /* @__PURE__ */ jsx14(
4771
+ /* @__PURE__ */ jsx15("div", { className: "df-review-frame-actions", children: /* @__PURE__ */ jsx15(
4449
4772
  ReviewModeToolbar,
4450
4773
  {
4451
- canWriteAny,
4452
4774
  canWriteArea,
4453
4775
  canWriteDom,
4454
- canWriteNote,
4455
4776
  mode,
4456
4777
  onSetReviewMode
4457
4778
  }
@@ -4460,18 +4781,18 @@ var ReviewTargetFrame = ({
4460
4781
  };
4461
4782
 
4462
4783
  // src/react-shell/topbar.tsx
4463
- import { jsx as jsx15, jsxs as jsxs13 } from "react/jsx-runtime";
4784
+ import { jsx as jsx16, jsxs as jsxs14 } from "react/jsx-runtime";
4464
4785
  var ReviewScopeIcon2 = ({ scope }) => {
4465
- if (scope === "mobile") return /* @__PURE__ */ jsx15(Smartphone, { "aria-hidden": "true" });
4466
- if (scope === "tablet") return /* @__PURE__ */ jsx15(RectangleHorizontal, { "aria-hidden": "true" });
4467
- if (scope === "wide") return /* @__PURE__ */ jsx15(Maximize2, { "aria-hidden": "true" });
4468
- if (scope === "dom") return /* @__PURE__ */ jsx15(SquareMousePointer, { "aria-hidden": "true" });
4469
- return /* @__PURE__ */ jsx15(Monitor, { "aria-hidden": "true" });
4786
+ if (scope === "mobile") return /* @__PURE__ */ jsx16(Smartphone, { "aria-hidden": "true" });
4787
+ if (scope === "tablet") return /* @__PURE__ */ jsx16(RectangleHorizontal, { "aria-hidden": "true" });
4788
+ if (scope === "wide") return /* @__PURE__ */ jsx16(Maximize2, { "aria-hidden": "true" });
4789
+ if (scope === "dom") return /* @__PURE__ */ jsx16(SquareMousePointer, { "aria-hidden": "true" });
4790
+ return /* @__PURE__ */ jsx16(Monitor, { "aria-hidden": "true" });
4470
4791
  };
4471
4792
  var ViewportPresetIcon = ({
4472
4793
  preset
4473
4794
  }) => {
4474
- return /* @__PURE__ */ jsx15(ReviewScopeIcon2, { scope: getViewportPresetKind(preset) });
4795
+ return /* @__PURE__ */ jsx16(ReviewScopeIcon2, { scope: getViewportPresetKind(preset) });
4475
4796
  };
4476
4797
  var ReviewTopbar = ({
4477
4798
  draftTarget,
@@ -4493,8 +4814,8 @@ var ReviewTopbar = ({
4493
4814
  onOpenInitialPrompt,
4494
4815
  onOpenSettings
4495
4816
  }) => {
4496
- return /* @__PURE__ */ jsxs13("header", { className: "df-review-topbar", children: [
4497
- /* @__PURE__ */ jsxs13(
4817
+ return /* @__PURE__ */ jsxs14("header", { className: "df-review-topbar", children: [
4818
+ /* @__PURE__ */ jsxs14(
4498
4819
  "form",
4499
4820
  {
4500
4821
  className: "df-review-address",
@@ -4503,17 +4824,17 @@ var ReviewTopbar = ({
4503
4824
  onApplyTarget();
4504
4825
  },
4505
4826
  children: [
4506
- /* @__PURE__ */ jsx15(
4827
+ /* @__PURE__ */ jsx16(
4507
4828
  "button",
4508
4829
  {
4509
4830
  "aria-label": "Open sitemap",
4510
4831
  className: "df-review-sitemap-button",
4511
4832
  type: "button",
4512
4833
  onClick: onOpenSitemap,
4513
- children: /* @__PURE__ */ jsx15(Map2, { "aria-hidden": "true" })
4834
+ children: /* @__PURE__ */ jsx16(Map2, { "aria-hidden": "true" })
4514
4835
  }
4515
4836
  ),
4516
- /* @__PURE__ */ jsx15(
4837
+ /* @__PURE__ */ jsx16(
4517
4838
  "input",
4518
4839
  {
4519
4840
  "aria-label": "Path",
@@ -4521,56 +4842,56 @@ var ReviewTopbar = ({
4521
4842
  onChange: (event) => onDraftTargetChange(event.target.value)
4522
4843
  }
4523
4844
  ),
4524
- /* @__PURE__ */ jsx15("button", { type: "submit", children: "Load" }),
4525
- /* @__PURE__ */ jsx15("button", { type: "button", onClick: onCopyCurrentUrl, children: copyLabel })
4845
+ /* @__PURE__ */ jsx16("button", { type: "submit", children: "Load" }),
4846
+ /* @__PURE__ */ jsx16("button", { type: "button", onClick: onCopyCurrentUrl, children: copyLabel })
4526
4847
  ]
4527
4848
  }
4528
4849
  ),
4529
- /* @__PURE__ */ jsxs13("div", { className: "df-review-tools", children: [
4530
- /* @__PURE__ */ jsxs13("div", { className: "df-review-tool-controls", children: [
4531
- /* @__PURE__ */ jsx15("div", { className: "df-review-presets", "aria-label": "Viewport presets", children: viewportPresets.map((preset) => /* @__PURE__ */ jsxs13(
4850
+ /* @__PURE__ */ jsxs14("div", { className: "df-review-tools", children: [
4851
+ /* @__PURE__ */ jsxs14("div", { className: "df-review-tool-controls", children: [
4852
+ /* @__PURE__ */ jsx16("div", { className: "df-review-presets", "aria-label": "Viewport presets", children: viewportPresets.map((preset) => /* @__PURE__ */ jsxs14(
4532
4853
  "button",
4533
4854
  {
4534
4855
  className: preset.label === size.label ? "is-active" : "",
4535
4856
  type: "button",
4536
4857
  onClick: () => onSizeChange(preset),
4537
4858
  children: [
4538
- /* @__PURE__ */ jsx15(ViewportPresetIcon, { preset }),
4539
- /* @__PURE__ */ jsx15("span", { className: "df-review-preset-copy", children: /* @__PURE__ */ jsx15("strong", { children: preset.label }) }),
4540
- /* @__PURE__ */ jsx15("span", { className: "df-review-preset-count", children: presetScopeCounts.get(getViewportPresetKind(preset)) ?? 0 })
4859
+ /* @__PURE__ */ jsx16(ViewportPresetIcon, { preset }),
4860
+ /* @__PURE__ */ jsx16("span", { className: "df-review-preset-copy", children: /* @__PURE__ */ jsx16("strong", { children: preset.label }) }),
4861
+ /* @__PURE__ */ jsx16("span", { className: "df-review-preset-count", children: presetScopeCounts.get(getViewportPresetKind(preset)) ?? 0 })
4541
4862
  ]
4542
4863
  },
4543
4864
  preset.label
4544
4865
  )) }),
4545
- /* @__PURE__ */ jsx15("span", { className: "df-review-tool-divider", "aria-hidden": "true", children: "|" }),
4546
- /* @__PURE__ */ jsxs13("span", { className: "df-review-active-size", children: [
4866
+ /* @__PURE__ */ jsx16("span", { className: "df-review-tool-divider", "aria-hidden": "true", children: "|" }),
4867
+ /* @__PURE__ */ jsxs14("span", { className: "df-review-active-size", children: [
4547
4868
  size.width,
4548
4869
  "x",
4549
4870
  size.height
4550
4871
  ] })
4551
4872
  ] }),
4552
- /* @__PURE__ */ jsxs13("div", { className: "df-review-overlays", "aria-label": "Target overlays", children: [
4553
- isRulerAvailable && /* @__PURE__ */ jsx15(
4873
+ /* @__PURE__ */ jsxs14("div", { className: "df-review-overlays", "aria-label": "Target overlays", children: [
4874
+ isRulerAvailable && /* @__PURE__ */ jsx16(
4554
4875
  "button",
4555
4876
  {
4556
4877
  "aria-label": "Toggle ruler",
4557
4878
  className: `df-review-overlay-button is-ruler${isRulerVisible ? " is-active" : ""}`,
4558
4879
  type: "button",
4559
4880
  onClick: onToggleRuler,
4560
- children: /* @__PURE__ */ jsx15(Ruler, { "aria-hidden": "true" })
4881
+ children: /* @__PURE__ */ jsx16(Ruler, { "aria-hidden": "true" })
4561
4882
  }
4562
4883
  ),
4563
- /* @__PURE__ */ jsx15(
4884
+ /* @__PURE__ */ jsx16(
4564
4885
  "button",
4565
4886
  {
4566
4887
  "aria-label": "Toggle grid overlay",
4567
4888
  className: `df-review-overlay-button is-grid${targetOverlayState.grid ? " is-active" : ""}`,
4568
4889
  type: "button",
4569
4890
  onClick: () => onToggleTargetOverlay("grid"),
4570
- children: /* @__PURE__ */ jsx15(LayoutGrid, { "aria-hidden": "true" })
4891
+ children: /* @__PURE__ */ jsx16(LayoutGrid, { "aria-hidden": "true" })
4571
4892
  }
4572
4893
  ),
4573
- /* @__PURE__ */ jsx15(
4894
+ /* @__PURE__ */ jsx16(
4574
4895
  "button",
4575
4896
  {
4576
4897
  "aria-disabled": !isFigmaOverlayAvailable,
@@ -4578,28 +4899,28 @@ var ReviewTopbar = ({
4578
4899
  className: `df-review-overlay-button is-figma${targetOverlayState.figma ? " is-active" : ""}${isFigmaOverlayAvailable ? "" : " is-disabled"}`,
4579
4900
  type: "button",
4580
4901
  onClick: () => onToggleTargetOverlay("figma"),
4581
- children: /* @__PURE__ */ jsx15(Image, { "aria-hidden": "true" })
4902
+ children: /* @__PURE__ */ jsx16(Image, { "aria-hidden": "true" })
4582
4903
  }
4583
4904
  ),
4584
- /* @__PURE__ */ jsx15("span", { className: "df-review-tool-divider", "aria-hidden": "true", children: "|" }),
4585
- /* @__PURE__ */ jsx15(
4905
+ /* @__PURE__ */ jsx16("span", { className: "df-review-tool-divider", "aria-hidden": "true", children: "|" }),
4906
+ /* @__PURE__ */ jsx16(
4586
4907
  "button",
4587
4908
  {
4588
4909
  "aria-label": "Open initial prompt",
4589
4910
  className: "df-review-overlay-button is-prompt",
4590
4911
  type: "button",
4591
4912
  onClick: onOpenInitialPrompt,
4592
- children: /* @__PURE__ */ jsx15(CircleQuestionMark, { "aria-hidden": "true" })
4913
+ children: /* @__PURE__ */ jsx16(CircleQuestionMark, { "aria-hidden": "true" })
4593
4914
  }
4594
4915
  ),
4595
- /* @__PURE__ */ jsx15(
4916
+ /* @__PURE__ */ jsx16(
4596
4917
  "button",
4597
4918
  {
4598
4919
  "aria-label": "Open settings",
4599
4920
  className: "df-review-overlay-button is-settings",
4600
4921
  type: "button",
4601
4922
  onClick: onOpenSettings,
4602
- children: /* @__PURE__ */ jsx15(Settings, { "aria-hidden": "true" })
4923
+ children: /* @__PURE__ */ jsx16(Settings, { "aria-hidden": "true" })
4603
4924
  }
4604
4925
  )
4605
4926
  ] })
@@ -4745,7 +5066,7 @@ var useReviewItemRestore = ({
4745
5066
  // src/react-shell/hooks/use.review.kit.lifecycle.ts
4746
5067
  import {
4747
5068
  useCallback as useCallback2,
4748
- useEffect
5069
+ useEffect as useEffect2
4749
5070
  } from "react";
4750
5071
 
4751
5072
  // src/react-shell/target/target.ts
@@ -5022,13 +5343,13 @@ var useReviewKitLifecycle = ({
5022
5343
  },
5023
5344
  [controllerRef, onModeChange]
5024
5345
  );
5025
- useEffect(() => destroyReviewKit, [destroyReviewKit]);
5026
- useEffect(() => {
5346
+ useEffect2(() => destroyReviewKit, [destroyReviewKit]);
5347
+ useEffect2(() => {
5027
5348
  const frameDocument = iframeRef.current?.contentDocument;
5028
5349
  if (!frameDocument || frameDocument.readyState !== "complete") return;
5029
5350
  initReviewKit();
5030
5351
  }, [iframeRef, initReviewKit]);
5031
- useEffect(() => {
5352
+ useEffect2(() => {
5032
5353
  hiddenOverlayItemIdListRef.current = hiddenOverlayItemIdList;
5033
5354
  controllerRef.current?.setHiddenItemIds(hiddenOverlayItemIdList);
5034
5355
  }, [controllerRef, hiddenOverlayItemIdList, hiddenOverlayItemIdListRef]);
@@ -5041,7 +5362,7 @@ var useReviewKitLifecycle = ({
5041
5362
  };
5042
5363
 
5043
5364
  // src/react-shell/hooks/use.review.target.overlay.ts
5044
- import { useCallback as useCallback3, useEffect as useEffect2 } from "react";
5365
+ import { useCallback as useCallback3, useEffect as useEffect3 } from "react";
5045
5366
  var useReviewTargetOverlay = ({
5046
5367
  iframeRef,
5047
5368
  isFigmaOverlayAvailable,
@@ -5097,7 +5418,7 @@ var useReviewTargetOverlay = ({
5097
5418
  },
5098
5419
  [dispatchTargetOverlayHotkey, iframeRef, onTargetOverlayStateChange]
5099
5420
  );
5100
- useEffect2(() => {
5421
+ useEffect3(() => {
5101
5422
  if (isFigmaOverlayAvailable || !targetOverlayState.figma) return;
5102
5423
  closeTargetOverlay("figma");
5103
5424
  }, [closeTargetOverlay, isFigmaOverlayAvailable, targetOverlayState.figma]);
@@ -5111,7 +5432,7 @@ var useReviewTargetOverlay = ({
5111
5432
  // src/react-shell/hooks/use.review.target.sync.ts
5112
5433
  import {
5113
5434
  useCallback as useCallback4,
5114
- useEffect as useEffect3
5435
+ useEffect as useEffect4
5115
5436
  } from "react";
5116
5437
  var useReviewTargetSync = ({
5117
5438
  iframeRef,
@@ -5161,11 +5482,11 @@ var useReviewTargetSync = ({
5161
5482
  targetRef
5162
5483
  ]
5163
5484
  );
5164
- useEffect3(() => {
5485
+ useEffect4(() => {
5165
5486
  targetRef.current = target;
5166
5487
  onActiveRouteChange(target);
5167
5488
  }, [onActiveRouteChange, target, targetRef]);
5168
- useEffect3(() => {
5489
+ useEffect4(() => {
5169
5490
  sizeRef.current = size;
5170
5491
  if (selectedItemIdRef.current) {
5171
5492
  updateShellUrlForItem(
@@ -5331,10 +5652,10 @@ var useReviewController = ({
5331
5652
  // src/react-shell/hooks/use.review.presence.ts
5332
5653
  import {
5333
5654
  useCallback as useCallback6,
5334
- useEffect as useEffect4,
5655
+ useEffect as useEffect5,
5335
5656
  useMemo as useMemo2,
5336
5657
  useRef,
5337
- useState
5658
+ useState as useState2
5338
5659
  } from "react";
5339
5660
 
5340
5661
  // src/react-shell/presence/presence.ts
@@ -5551,8 +5872,8 @@ var useReviewPresence = ({
5551
5872
  source
5552
5873
  }) => {
5553
5874
  const presenceSessionRef = useRef(null);
5554
- const [presenceUsers, setPresenceUsers] = useState([]);
5555
- const [presenceSessionVersion, setPresenceSessionVersion] = useState(0);
5875
+ const [presenceUsers, setPresenceUsers] = useState2([]);
5876
+ const [presenceSessionVersion, setPresenceSessionVersion] = useState2(0);
5556
5877
  const presenceSessionId = useMemo2(getReviewPresenceSessionId, []);
5557
5878
  const normalizedReviewUserId = reviewUserId.trim();
5558
5879
  const presenceDisplayName = getReviewPresenceDisplayName(
@@ -5633,7 +5954,7 @@ var useReviewPresence = ({
5633
5954
  );
5634
5955
  const getCurrentPresenceStateRef = useRef(getCurrentPresenceState);
5635
5956
  getCurrentPresenceStateRef.current = getCurrentPresenceState;
5636
- useEffect4(() => {
5957
+ useEffect5(() => {
5637
5958
  if (!presence || !normalizedReviewUserId) {
5638
5959
  const session = presenceSessionRef.current;
5639
5960
  presenceSessionRef.current = null;
@@ -5683,7 +6004,7 @@ var useReviewPresence = ({
5683
6004
  presenceSessionId,
5684
6005
  projectId
5685
6006
  ]);
5686
- useEffect4(() => {
6007
+ useEffect5(() => {
5687
6008
  const session = presenceSessionRef.current;
5688
6009
  if (!session || !normalizedReviewUserId) return;
5689
6010
  void session.update(getCurrentPresenceState());
@@ -5702,17 +6023,17 @@ var useReviewPresence = ({
5702
6023
  // src/react-shell/hooks/use.review.ruler.ts
5703
6024
  import {
5704
6025
  useCallback as useCallback8,
5705
- useEffect as useEffect6,
5706
- useState as useState3
6026
+ useEffect as useEffect7,
6027
+ useState as useState4
5707
6028
  } from "react";
5708
6029
 
5709
6030
  // src/react-shell/hooks/use.review.ruler.drag.ts
5710
6031
  import {
5711
6032
  useCallback as useCallback7,
5712
- useEffect as useEffect5,
6033
+ useEffect as useEffect6,
5713
6034
  useMemo as useMemo3,
5714
6035
  useRef as useRef2,
5715
- useState as useState2
6036
+ useState as useState3
5716
6037
  } from "react";
5717
6038
 
5718
6039
  // src/react-shell/ruler/ruler.ts
@@ -5746,10 +6067,10 @@ var useReviewRulerDrag = ({
5746
6067
  const rulerDragRectRef = useRef2(null);
5747
6068
  const isRulerDraggingRef = useRef2(false);
5748
6069
  const sizeRef = useRef2(size);
5749
- const [rulerStart, setRulerStart] = useState2(null);
5750
- const [rulerPoint, setRulerPoint] = useState2(null);
5751
- const [rulerHover, setRulerHover] = useState2(null);
5752
- const [isRulerDragging, setIsRulerDragging] = useState2(false);
6070
+ const [rulerStart, setRulerStart] = useState3(null);
6071
+ const [rulerPoint, setRulerPoint] = useState3(null);
6072
+ const [rulerHover, setRulerHover] = useState3(null);
6073
+ const [isRulerDragging, setIsRulerDragging] = useState3(false);
5753
6074
  const rulerMeasure = useMemo3(
5754
6075
  () => getRulerMeasure(rulerStart, rulerPoint),
5755
6076
  [rulerPoint, rulerStart]
@@ -5781,10 +6102,10 @@ var useReviewRulerDrag = ({
5781
6102
  },
5782
6103
  []
5783
6104
  );
5784
- useEffect5(() => {
6105
+ useEffect6(() => {
5785
6106
  sizeRef.current = size;
5786
6107
  }, [size]);
5787
- useEffect5(() => {
6108
+ useEffect6(() => {
5788
6109
  if (!isRulerVisible || !isRulerAvailable) return void 0;
5789
6110
  const getRulerEventClientPoint = (event) => {
5790
6111
  const frame2 = iframeRef.current;
@@ -5898,7 +6219,7 @@ var useReviewRulerDrag = ({
5898
6219
  isRulerVisible,
5899
6220
  startRulerDrag
5900
6221
  ]);
5901
- useEffect5(() => {
6222
+ useEffect6(() => {
5902
6223
  clearRulerMeasure();
5903
6224
  }, [clearRulerMeasure, size.height, size.width, targetSrc]);
5904
6225
  return {
@@ -5919,7 +6240,7 @@ var useReviewRuler = ({
5919
6240
  onCancelReviewMode,
5920
6241
  onCloseTransientPanels
5921
6242
  }) => {
5922
- const [isRulerVisible, setIsRulerVisible] = useState3(false);
6243
+ const [isRulerVisible, setIsRulerVisible] = useState4(false);
5923
6244
  const isRulerAvailable = ruler?.enabled !== false && typeof size.designWidth === "number" && size.designWidth > 0;
5924
6245
  const rulerUnit = ruler?.unit ?? "px";
5925
6246
  const rulerScaleX = isRulerAvailable && size.designWidth ? size.width / size.designWidth : 1;
@@ -5937,9 +6258,9 @@ var useReviewRuler = ({
5937
6258
  size,
5938
6259
  targetSrc
5939
6260
  });
5940
- const rulerMeasureLabel = rulerMeasure ? `Figma ${Math.round(rulerMeasure.width / rulerScaleX)}x${Math.round(
6261
+ const rulerMeasureLabel = rulerMeasure ? `${Math.round(rulerMeasure.width / rulerScaleX)} \xD7 ${Math.round(
5941
6262
  rulerMeasure.height / rulerScaleY
5942
- )}${rulerUnit}` : "";
6263
+ )} ${rulerUnit}` : "";
5943
6264
  const closeRuler = useCallback8(() => {
5944
6265
  if (!isRulerVisible) return false;
5945
6266
  setIsRulerVisible(false);
@@ -5958,7 +6279,7 @@ var useReviewRuler = ({
5958
6279
  onCancelReviewMode,
5959
6280
  onCloseTransientPanels
5960
6281
  ]);
5961
- useEffect6(() => {
6282
+ useEffect7(() => {
5962
6283
  if (!isRulerVisible || isRulerAvailable) return;
5963
6284
  closeRuler();
5964
6285
  }, [closeRuler, isRulerAvailable, isRulerVisible]);
@@ -5979,25 +6300,25 @@ var useReviewRuler = ({
5979
6300
  };
5980
6301
 
5981
6302
  // src/react-shell/hooks/use.review.settings.ts
5982
- import { useCallback as useCallback9, useEffect as useEffect7, useState as useState4 } from "react";
6303
+ import { useCallback as useCallback9, useEffect as useEffect8, useState as useState5 } from "react";
5983
6304
  var useReviewSettings = ({
5984
6305
  onCancelReviewMode,
5985
6306
  onCloseInitialPrompt,
5986
6307
  onCloseSitemap,
5987
6308
  onReloadTargetFrame
5988
6309
  }) => {
5989
- const [figmaTokenDraft, setFigmaTokenDraft] = useState4(getStoredFigmaToken);
5990
- const [reviewUserId, setReviewUserId] = useState4(getStoredReviewUserId);
5991
- const [reviewUserIdDraft, setReviewUserIdDraft] = useState4(
6310
+ const [figmaTokenDraft, setFigmaTokenDraft] = useState5(getStoredFigmaToken);
6311
+ const [reviewUserId, setReviewUserId] = useState5(getStoredReviewUserId);
6312
+ const [reviewUserIdDraft, setReviewUserIdDraft] = useState5(
5992
6313
  getStoredReviewUserId
5993
6314
  );
5994
- const [reviewTheme, setReviewTheme] = useState4(getStoredReviewTheme);
5995
- const [reviewThemeDraft, setReviewThemeDraft] = useState4(getStoredReviewTheme);
5996
- const [systemReviewTheme, setSystemReviewTheme] = useState4(getSystemReviewTheme);
5997
- const [figmaSettingsStatus, setFigmaSettingsStatus] = useState4("");
5998
- const [isFigmaSettingsOpen, setIsFigmaSettingsOpen] = useState4(false);
5999
- const [isFigmaTokenVisible, setIsFigmaTokenVisible] = useState4(false);
6000
- const [isFigmaTokenGuideOpen, setIsFigmaTokenGuideOpen] = useState4(false);
6315
+ const [reviewTheme, setReviewTheme] = useState5(getStoredReviewTheme);
6316
+ const [reviewThemeDraft, setReviewThemeDraft] = useState5(getStoredReviewTheme);
6317
+ const [systemReviewTheme, setSystemReviewTheme] = useState5(getSystemReviewTheme);
6318
+ const [figmaSettingsStatus, setFigmaSettingsStatus] = useState5("");
6319
+ const [isFigmaSettingsOpen, setIsFigmaSettingsOpen] = useState5(false);
6320
+ const [isFigmaTokenVisible, setIsFigmaTokenVisible] = useState5(false);
6321
+ const [isFigmaTokenGuideOpen, setIsFigmaTokenGuideOpen] = useState5(false);
6001
6322
  const effectiveReviewTheme = reviewTheme === "system" ? systemReviewTheme : reviewTheme;
6002
6323
  const closeFigmaSettings = useCallback9(() => {
6003
6324
  setIsFigmaSettingsOpen(false);
@@ -6046,7 +6367,7 @@ var useReviewSettings = ({
6046
6367
  },
6047
6368
  [closeFigmaSettings, onReloadTargetFrame]
6048
6369
  );
6049
- useEffect7(() => {
6370
+ useEffect8(() => {
6050
6371
  if (typeof window === "undefined" || !window.matchMedia) return void 0;
6051
6372
  const query = window.matchMedia("(prefers-color-scheme: light)");
6052
6373
  const syncSystemTheme = () => {
@@ -6060,7 +6381,7 @@ var useReviewSettings = ({
6060
6381
  query.addListener(syncSystemTheme);
6061
6382
  return () => query.removeListener(syncSystemTheme);
6062
6383
  }, []);
6063
- useEffect7(() => {
6384
+ useEffect8(() => {
6064
6385
  document.body.classList.toggle(
6065
6386
  "df-review-theme-light",
6066
6387
  effectiveReviewTheme === "light"
@@ -6099,7 +6420,7 @@ var useReviewSettings = ({
6099
6420
  };
6100
6421
 
6101
6422
  // src/react-shell/hooks/use.review.shell.data.ts
6102
- import { useCallback as useCallback10, useMemo as useMemo4, useState as useState5 } from "react";
6423
+ import { useCallback as useCallback10, useMemo as useMemo4, useState as useState6 } from "react";
6103
6424
  var createEmptySitemapQaCount = () => ({
6104
6425
  local: 0,
6105
6426
  remote: 0
@@ -6114,12 +6435,12 @@ var useReviewShellData = ({
6114
6435
  target,
6115
6436
  viewportPresets
6116
6437
  }) => {
6117
- const [items, setItems] = useState5([]);
6118
- const [hiddenOverlayItemIds, setHiddenOverlayItemIds] = useState5(
6438
+ const [items, setItems] = useState6([]);
6439
+ const [hiddenOverlayItemIds, setHiddenOverlayItemIds] = useState6(
6119
6440
  () => /* @__PURE__ */ new Set()
6120
6441
  );
6121
- const [qaFilter, setQaFilter] = useState5("all");
6122
- const [sitemapItems, setSitemapItems] = useState5(() => ({
6442
+ const [qaFilter, setQaFilter] = useState6("all");
6443
+ const [sitemapItems, setSitemapItems] = useState6(() => ({
6123
6444
  local: [],
6124
6445
  remote: []
6125
6446
  }));
@@ -6131,7 +6452,7 @@ var useReviewShellData = ({
6131
6452
  [pages, reviewPathPrefix]
6132
6453
  );
6133
6454
  const activeItems = useMemo4(
6134
- () => items.filter((item) => getItemTarget(item, reviewPathPrefix) === activeRoute).sort((a, b) => b.updatedAt.localeCompare(a.updatedAt)),
6455
+ () => items.filter((item) => getItemTarget(item, reviewPathPrefix) === activeRoute).sort((a, b) => b.createdAt.localeCompare(a.createdAt)),
6135
6456
  [activeRoute, items, reviewPathPrefix]
6136
6457
  );
6137
6458
  const numberedActiveItems = useMemo4(
@@ -6220,7 +6541,7 @@ var useReviewShellData = ({
6220
6541
  };
6221
6542
 
6222
6543
  // src/react-shell/hooks/use.review.shell.hotkeys.ts
6223
- import { useEffect as useEffect8 } from "react";
6544
+ import { useEffect as useEffect9 } from "react";
6224
6545
  var useReviewShellHotkeys = ({
6225
6546
  isFigmaSettingsOpen,
6226
6547
  isInitialPromptOpen,
@@ -6237,7 +6558,7 @@ var useReviewShellHotkeys = ({
6237
6558
  onToggleRuler,
6238
6559
  onToggleTargetOverlay
6239
6560
  }) => {
6240
- useEffect8(() => {
6561
+ useEffect9(() => {
6241
6562
  if (mode === "idle" && !isRulerVisible && !isInitialPromptOpen && !isSitemapOpen && !isFigmaSettingsOpen) {
6242
6563
  return;
6243
6564
  }
@@ -6281,7 +6602,7 @@ var useReviewShellHotkeys = ({
6281
6602
  onCloseRuler,
6282
6603
  onCloseSitemap
6283
6604
  ]);
6284
- useEffect8(() => {
6605
+ useEffect9(() => {
6285
6606
  const handleHotkey = (event) => {
6286
6607
  if (event.metaKey || event.ctrlKey || event.altKey || event.shiftKey) {
6287
6608
  return;
@@ -6316,7 +6637,7 @@ var useReviewShellHotkeys = ({
6316
6637
  import {
6317
6638
  useMemo as useMemo5,
6318
6639
  useRef as useRef3,
6319
- useState as useState6
6640
+ useState as useState7
6320
6641
  } from "react";
6321
6642
 
6322
6643
  // src/react-shell/adapters.ts
@@ -6345,6 +6666,7 @@ function normalizeLegacyAdapterMap(adapters) {
6345
6666
  updateStatus: ({ id, status }) => adapters.local.update(id, { status }),
6346
6667
  syncSubmission: ({ id, patch }) => adapters.local.update(id, patch),
6347
6668
  writeModes: [...ALL_REVIEW_WRITE_MODES],
6669
+ canUpdate: true,
6348
6670
  canRemove: true
6349
6671
  };
6350
6672
  const remote = adapters.remote ? {
@@ -6353,6 +6675,7 @@ function normalizeLegacyAdapterMap(adapters) {
6353
6675
  statusOptions: [...REVIEW_WORKFLOW_STATUS_OPTIONS],
6354
6676
  updateStatus: ({ id, status }) => adapters.remote?.update(id, { status }) ?? Promise.reject(new Error("Remote adapter is not available.")),
6355
6677
  writeModes: [],
6678
+ canUpdate: true,
6356
6679
  canRemove: false,
6357
6680
  pageId: adapters.remotePageId
6358
6681
  } : null;
@@ -6378,6 +6701,7 @@ function normalizeShellAdapter(adapterConfig) {
6378
6701
  updateStatus,
6379
6702
  syncSubmission: adapterConfig.syncSubmission,
6380
6703
  writeModes,
6704
+ canUpdate: Boolean(updateAdapter),
6381
6705
  canRemove: Boolean(adapterConfig.remove),
6382
6706
  adapter: {
6383
6707
  get: adapterConfig.get,
@@ -6470,7 +6794,7 @@ var useReviewShellState = ({
6470
6794
  const remoteAdapterEntry = normalizedAdapters.remote;
6471
6795
  const sourceEntries = normalizedAdapters.sources;
6472
6796
  const defaultSource = sourceEntries[0]?.label ?? "local";
6473
- const [source, setSource] = useState6(() => {
6797
+ const [source, setSource] = useState7(() => {
6474
6798
  const initialSource = getInitialSource(remoteAdapterEntry?.label);
6475
6799
  return sourceEntries.some((entry) => entry.label === initialSource) ? initialSource : defaultSource;
6476
6800
  });
@@ -6480,10 +6804,8 @@ var useReviewShellState = ({
6480
6804
  remoteSource && activeAdapterEntry.label === remoteSource
6481
6805
  );
6482
6806
  const showSourceSelect = sourceEntries.length > 1;
6483
- const canWriteDom = activeAdapterEntry.writeModes.includes("dom");
6484
- const canWriteNote = activeAdapterEntry.writeModes.includes("note");
6485
6807
  const canWriteArea = activeAdapterEntry.writeModes.includes("area");
6486
- const canWriteAny = canWriteDom || canWriteNote || canWriteArea;
6808
+ const canWriteDom = activeAdapterEntry.writeModes.includes("dom");
6487
6809
  const adapter = activeAdapterEntry.adapter;
6488
6810
  const iframeRef = useRef3(null);
6489
6811
  const frameScrollRef = useRef3(null);
@@ -6493,30 +6815,30 @@ var useReviewShellState = ({
6493
6815
  const pendingInitialItemIdRef = useRef3(getInitialItemId());
6494
6816
  const selectedItemIdRef = useRef3(getInitialItemId());
6495
6817
  const hiddenOverlayItemIdListRef = useRef3([]);
6496
- const [target, setTarget] = useState6(
6818
+ const [target, setTarget] = useState7(
6497
6819
  () => getInitialTarget(reviewPathPrefix)
6498
6820
  );
6499
- const [draftTarget, setDraftTarget] = useState6(
6821
+ const [draftTarget, setDraftTarget] = useState7(
6500
6822
  () => getInitialTarget(reviewPathPrefix)
6501
6823
  );
6502
- const [activeRoute, setActiveRoute] = useState6(
6824
+ const [activeRoute, setActiveRoute] = useState7(
6503
6825
  () => getInitialTarget(reviewPathPrefix)
6504
6826
  );
6505
- const [size, setSize] = useState6(
6827
+ const [size, setSize] = useState7(
6506
6828
  () => getInitialSize(viewportPresets)
6507
6829
  );
6508
- const [mode, setMode] = useState6("idle");
6509
- const [targetOverlayState, setTargetOverlayState] = useState6({
6830
+ const [mode, setMode] = useState7("idle");
6831
+ const [targetOverlayState, setTargetOverlayState] = useState7({
6510
6832
  grid: false,
6511
6833
  figma: false
6512
6834
  });
6513
- const [selectedItemId, setSelectedItemId] = useState6(getInitialItemId());
6514
- const [isListVisible, setIsListVisible] = useState6(true);
6515
- const [isSitemapOpen, setIsSitemapOpen] = useState6(false);
6516
- const [isInitialPromptOpen, setIsInitialPromptOpen] = useState6(false);
6517
- const [copyLabel, setCopyLabel] = useState6("Copy URL");
6518
- const [toastMessage, setToastMessage] = useState6("");
6519
- const [copiedPromptKey, setCopiedPromptKey] = useState6(null);
6835
+ const [selectedItemId, setSelectedItemId] = useState7(getInitialItemId());
6836
+ const [isListVisible, setIsListVisible] = useState7(true);
6837
+ const [isSitemapOpen, setIsSitemapOpen] = useState7(false);
6838
+ const [isInitialPromptOpen, setIsInitialPromptOpen] = useState7(false);
6839
+ const [copyLabel, setCopyLabel] = useState7("Copy URL");
6840
+ const [toastMessage, setToastMessage] = useState7("");
6841
+ const [copiedPromptKey, setCopiedPromptKey] = useState7(null);
6520
6842
  const targetRef = useRef3(target);
6521
6843
  const sizeRef = useRef3(size);
6522
6844
  const isFigmaOverlayAvailable = getIsFigmaOverlayAvailable(size);
@@ -6524,10 +6846,8 @@ var useReviewShellState = ({
6524
6846
  activeAdapterEntry,
6525
6847
  activeRoute,
6526
6848
  adapter,
6527
- canWriteAny,
6528
6849
  canWriteArea,
6529
6850
  canWriteDom,
6530
- canWriteNote,
6531
6851
  cleanupTargetRef,
6532
6852
  controllerRef,
6533
6853
  copiedPromptKey,
@@ -6692,6 +7012,31 @@ var updateReviewItemStatus = async ({
6692
7012
  await onRefreshReviewData();
6693
7013
  onToast?.("QA status updated");
6694
7014
  };
7015
+ var updateReviewItemComment = async ({
7016
+ activeAdapterEntry,
7017
+ item,
7018
+ comment,
7019
+ onRefreshReviewData,
7020
+ onToast
7021
+ }) => {
7022
+ const nextComment = comment.trim();
7023
+ if (!nextComment) throw new Error("Comment is required.");
7024
+ if (!activeAdapterEntry.canUpdate) {
7025
+ throw new Error(
7026
+ `Review adapter "${activeAdapterEntry.label}" does not support edit.`
7027
+ );
7028
+ }
7029
+ if (nextComment === item.comment.trim()) {
7030
+ onToast?.("No QA comment changes");
7031
+ return item;
7032
+ }
7033
+ const updated = await activeAdapterEntry.adapter.update(item.id, {
7034
+ comment: nextComment
7035
+ });
7036
+ await onRefreshReviewData();
7037
+ onToast?.("QA comment updated");
7038
+ return updated;
7039
+ };
6695
7040
  var submitReviewItem = async ({
6696
7041
  localAdapterEntry,
6697
7042
  numberedItem,
@@ -6785,7 +7130,7 @@ var removeReviewItem = async ({
6785
7130
  };
6786
7131
 
6787
7132
  // src/react-shell/review/shell.tsx
6788
- import { jsx as jsx16, jsxs as jsxs14 } from "react/jsx-runtime";
7133
+ import { jsx as jsx17, jsxs as jsxs15 } from "react/jsx-runtime";
6789
7134
  var getReviewModeWriteMode = (mode) => {
6790
7135
  if (mode === "element") return "dom";
6791
7136
  if (mode === "note" || mode === "area") return mode;
@@ -6799,16 +7144,15 @@ var ReviewShell = ({
6799
7144
  ruler,
6800
7145
  initialPrompt = DEFAULT_INITIAL_REVIEW_PROMPT,
6801
7146
  reviewPathPrefix = DEFAULT_REVIEW_PATH_PREFIX,
7147
+ sourceRoot,
6802
7148
  presence
6803
7149
  }) => {
6804
7150
  const {
6805
7151
  activeAdapterEntry,
6806
7152
  activeRoute,
6807
7153
  adapter,
6808
- canWriteAny,
6809
7154
  canWriteArea,
6810
7155
  canWriteDom,
6811
- canWriteNote,
6812
7156
  cleanupTargetRef,
6813
7157
  controllerRef,
6814
7158
  copiedPromptKey,
@@ -6859,6 +7203,7 @@ var ReviewShell = ({
6859
7203
  presets,
6860
7204
  reviewPathPrefix
6861
7205
  });
7206
+ const sourceShortcutCleanupRef = useRef4(null);
6862
7207
  const {
6863
7208
  activeItems,
6864
7209
  currentPresetScope,
@@ -6887,6 +7232,7 @@ var ReviewShell = ({
6887
7232
  target,
6888
7233
  viewportPresets
6889
7234
  });
7235
+ const [editingItem, setEditingItem] = useState8(null);
6890
7236
  const initialPromptText = initialPrompt.trim();
6891
7237
  const refreshItems = useCallback11(
6892
7238
  () => refreshReviewItems({
@@ -7056,17 +7402,17 @@ var ReviewShell = ({
7056
7402
  return nextHiddenItemIds;
7057
7403
  });
7058
7404
  }, []);
7059
- useEffect9(() => {
7405
+ useEffect10(() => {
7060
7406
  void refreshItems();
7061
7407
  }, [refreshItems]);
7062
- useEffect9(() => {
7408
+ useEffect10(() => {
7063
7409
  void refreshSitemapItems();
7064
7410
  }, [refreshSitemapItems]);
7065
- useEffect9(() => {
7411
+ useEffect10(() => {
7066
7412
  if (!isSitemapOpen) return;
7067
7413
  void refreshSitemapItems();
7068
7414
  }, [isSitemapOpen, refreshSitemapItems]);
7069
- useEffect9(() => {
7415
+ useEffect10(() => {
7070
7416
  const frameScroll = frameScrollRef.current;
7071
7417
  if (!frameScroll) return void 0;
7072
7418
  const centerFrameScroll = () => {
@@ -7140,6 +7486,222 @@ var ReviewShell = ({
7140
7486
  },
7141
7487
  [setToastMessage]
7142
7488
  );
7489
+ const cleanupSourceOpenShortcut = useCallback11(() => {
7490
+ sourceShortcutCleanupRef.current?.();
7491
+ sourceShortcutCleanupRef.current = null;
7492
+ }, []);
7493
+ const bindSourceOpenShortcut = useCallback11(() => {
7494
+ cleanupSourceOpenShortcut();
7495
+ let frameDocument = null;
7496
+ try {
7497
+ frameDocument = iframeRef.current?.contentDocument ?? null;
7498
+ } catch {
7499
+ return;
7500
+ }
7501
+ if (!frameDocument) return;
7502
+ const hoverAttribute = "data-dfwr-source-hover";
7503
+ const optionAttribute = "data-dfwr-source-option";
7504
+ const fontOverlayAttribute = "data-dfwr-source-fonts";
7505
+ const style = frameDocument.createElement("style");
7506
+ style.dataset.dfwrSourceOpenShortcut = "true";
7507
+ style.textContent = `
7508
+ html[${optionAttribute}="true"],
7509
+ html[${optionAttribute}="true"] * {
7510
+ cursor: crosshair !important;
7511
+ }
7512
+
7513
+ html[${optionAttribute}="true"] body::before {
7514
+ position: fixed !important;
7515
+ z-index: 2147483647 !important;
7516
+ top: 10px !important;
7517
+ left: 50% !important;
7518
+ transform: translateX(-50%) !important;
7519
+ display: block !important;
7520
+ border: 1px solid rgba(124, 199, 255, 0.72) !important;
7521
+ border-radius: 999px !important;
7522
+ padding: 6px 10px !important;
7523
+ color: #ffffff !important;
7524
+ background: rgba(15, 23, 42, 0.86) !important;
7525
+ box-shadow: 0 10px 28px rgba(0, 0, 0, 0.24) !important;
7526
+ content: "Source select" !important;
7527
+ font: 700 12px/1 system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif !important;
7528
+ pointer-events: none !important;
7529
+ }
7530
+
7531
+ [${hoverAttribute}="true"] {
7532
+ outline: 2px solid rgba(124, 199, 255, 0.96) !important;
7533
+ outline-offset: 2px !important;
7534
+ }
7535
+
7536
+ [${fontOverlayAttribute}] {
7537
+ position: fixed !important;
7538
+ z-index: 2147483647 !important;
7539
+ display: flex !important;
7540
+ flex-direction: column !important;
7541
+ max-width: 180px !important;
7542
+ border: 1px solid rgba(124, 199, 255, 0.72) !important;
7543
+ border-radius: 6px !important;
7544
+ padding: 4px 6px !important;
7545
+ color: #ffffff !important;
7546
+ background: rgba(15, 23, 42, 0.9) !important;
7547
+ box-shadow: 0 8px 22px rgba(0, 0, 0, 0.28) !important;
7548
+ font: 800 11px/1.35 ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace !important;
7549
+ pointer-events: none !important;
7550
+ white-space: nowrap !important;
7551
+ }
7552
+
7553
+ [${fontOverlayAttribute}] > span {
7554
+ display: flex !important;
7555
+ justify-content: space-between !important;
7556
+ gap: 10px !important;
7557
+ }
7558
+
7559
+ [${fontOverlayAttribute}][hidden] {
7560
+ display: none !important;
7561
+ }
7562
+ `;
7563
+ (frameDocument.head ?? frameDocument.documentElement).append(style);
7564
+ const fontOverlay = frameDocument.createElement("div");
7565
+ fontOverlay.setAttribute(fontOverlayAttribute, "true");
7566
+ fontOverlay.hidden = true;
7567
+ (frameDocument.body ?? frameDocument.documentElement).append(fontOverlay);
7568
+ let hoveredElement = null;
7569
+ let lastSourceElement = null;
7570
+ let isSourceSelecting = false;
7571
+ const getFontHints = (element) => {
7572
+ if (!element) return [];
7573
+ const values = [];
7574
+ const addValue = (target2) => {
7575
+ const value = target2.getAttribute("data-font")?.trim();
7576
+ const tag = target2.tagName.toLowerCase();
7577
+ if (value && !values.some((item) => item.tag === tag && item.value === value)) {
7578
+ values.push({ tag, value });
7579
+ }
7580
+ };
7581
+ addValue(element);
7582
+ element.querySelectorAll("[data-font]").forEach(addValue);
7583
+ return values;
7584
+ };
7585
+ const updateFontOverlay = (element) => {
7586
+ const values = isSourceSelecting ? getFontHints(element) : [];
7587
+ if (!values.length || !element) {
7588
+ fontOverlay.hidden = true;
7589
+ return;
7590
+ }
7591
+ const rect = element.getBoundingClientRect();
7592
+ const frameWidth = frameDocument.documentElement.clientWidth;
7593
+ const showAbove = rect.top > 48;
7594
+ const left = Math.max(4, Math.min(rect.left, frameWidth - 96));
7595
+ const top = Math.max(4, showAbove ? rect.top : rect.bottom);
7596
+ fontOverlay.replaceChildren();
7597
+ fontOverlay.style.minWidth = "72px";
7598
+ const rows = values.map(({ tag, value }) => {
7599
+ const row = frameDocument.createElement("span");
7600
+ const tagText = frameDocument.createElement("span");
7601
+ const valueText = frameDocument.createElement("span");
7602
+ tagText.textContent = tag;
7603
+ valueText.textContent = value;
7604
+ row.append(tagText, valueText);
7605
+ return row;
7606
+ });
7607
+ fontOverlay.append(...rows);
7608
+ fontOverlay.style.left = `${left}px`;
7609
+ fontOverlay.style.top = `${top}px`;
7610
+ fontOverlay.style.transform = showAbove ? "translateY(calc(-100% - 6px))" : "translateY(6px)";
7611
+ fontOverlay.hidden = false;
7612
+ };
7613
+ const setHoveredElement = (element) => {
7614
+ if (hoveredElement !== element) {
7615
+ hoveredElement?.removeAttribute(hoverAttribute);
7616
+ hoveredElement = element;
7617
+ hoveredElement?.setAttribute(hoverAttribute, "true");
7618
+ }
7619
+ updateFontOverlay(element);
7620
+ };
7621
+ const setSourceSelecting = (isSelecting) => {
7622
+ isSourceSelecting = isSelecting;
7623
+ if (isSelecting) {
7624
+ frameDocument.documentElement.setAttribute(optionAttribute, "true");
7625
+ setHoveredElement(lastSourceElement);
7626
+ return;
7627
+ }
7628
+ setHoveredElement(null);
7629
+ fontOverlay.hidden = true;
7630
+ frameDocument.documentElement.removeAttribute(optionAttribute);
7631
+ };
7632
+ const handleMouseMove = (event) => {
7633
+ lastSourceElement = getSourceHintElement(event.target);
7634
+ if (event.altKey && !isSourceSelecting) {
7635
+ setSourceSelecting(true);
7636
+ }
7637
+ setHoveredElement(isSourceSelecting ? lastSourceElement : null);
7638
+ };
7639
+ const handleClick = (event) => {
7640
+ if (!isSourceSelecting && !event.altKey) return;
7641
+ event.preventDefault();
7642
+ event.stopPropagation();
7643
+ event.stopImmediatePropagation();
7644
+ const source2 = getElementSourceHint(event.target);
7645
+ if (!source2?.file) {
7646
+ showToast("Source hint not found");
7647
+ setSourceSelecting(false);
7648
+ return;
7649
+ }
7650
+ const didOpen = openSourceInEditor(source2, sourceRoot);
7651
+ showToast(didOpen ? "Source opened" : "Source root required");
7652
+ setSourceSelecting(false);
7653
+ };
7654
+ const isOptionKeyEvent = (event) => event.key === "Alt" || event.code === "AltLeft" || event.code === "AltRight" || event.altKey;
7655
+ const handleKeyDown = (event) => {
7656
+ if (!isOptionKeyEvent(event)) return;
7657
+ cancelReviewMode();
7658
+ setSourceSelecting(true);
7659
+ };
7660
+ const handleKeyUp = (event) => {
7661
+ if (isOptionKeyEvent(event) || !event.altKey) setSourceSelecting(false);
7662
+ };
7663
+ const handleBlur = () => {
7664
+ setSourceSelecting(false);
7665
+ };
7666
+ frameDocument.addEventListener("mousemove", handleMouseMove, true);
7667
+ frameDocument.addEventListener("click", handleClick, true);
7668
+ frameDocument.addEventListener("keydown", handleKeyDown, true);
7669
+ frameDocument.addEventListener("keyup", handleKeyUp, true);
7670
+ frameDocument.defaultView?.addEventListener("blur", handleBlur);
7671
+ window.addEventListener("keydown", handleKeyDown, true);
7672
+ window.addEventListener("keyup", handleKeyUp, true);
7673
+ window.addEventListener("blur", handleBlur);
7674
+ sourceShortcutCleanupRef.current = () => {
7675
+ frameDocument.removeEventListener("mousemove", handleMouseMove, true);
7676
+ frameDocument.removeEventListener("click", handleClick, true);
7677
+ frameDocument.removeEventListener("keydown", handleKeyDown, true);
7678
+ frameDocument.removeEventListener("keyup", handleKeyUp, true);
7679
+ frameDocument.defaultView?.removeEventListener("blur", handleBlur);
7680
+ window.removeEventListener("keydown", handleKeyDown, true);
7681
+ window.removeEventListener("keyup", handleKeyUp, true);
7682
+ window.removeEventListener("blur", handleBlur);
7683
+ setSourceSelecting(false);
7684
+ style.remove();
7685
+ fontOverlay.remove();
7686
+ };
7687
+ }, [
7688
+ cancelReviewMode,
7689
+ cleanupSourceOpenShortcut,
7690
+ iframeRef,
7691
+ showToast,
7692
+ sourceRoot
7693
+ ]);
7694
+ useEffect10(() => {
7695
+ return cleanupSourceOpenShortcut;
7696
+ }, [cleanupSourceOpenShortcut]);
7697
+ const loadTargetFrame = useCallback11(() => {
7698
+ initReviewKit();
7699
+ bindSourceOpenShortcut();
7700
+ }, [bindSourceOpenShortcut, initReviewKit]);
7701
+ useEffect10(() => {
7702
+ const frame = window.requestAnimationFrame(bindSourceOpenShortcut);
7703
+ return () => window.cancelAnimationFrame(frame);
7704
+ }, [bindSourceOpenShortcut, targetSrc]);
7143
7705
  const clearSelectedReviewItem = useCallback11(() => {
7144
7706
  clearSelectedItem();
7145
7707
  updateShellUrl(targetRef.current, sizeRef.current, source);
@@ -7159,6 +7721,16 @@ var ReviewShell = ({
7159
7721
  onRefreshReviewData: refreshReviewData2,
7160
7722
  onToast: showToast
7161
7723
  });
7724
+ const saveItemComment = async (item, comment) => {
7725
+ await updateReviewItemComment({
7726
+ activeAdapterEntry,
7727
+ item,
7728
+ comment,
7729
+ onRefreshReviewData: refreshReviewData2,
7730
+ onToast: showToast
7731
+ });
7732
+ setEditingItem(null);
7733
+ };
7162
7734
  const submitItem = (numberedItem) => submitReviewItem({
7163
7735
  localAdapterEntry,
7164
7736
  numberedItem,
@@ -7192,12 +7764,12 @@ var ReviewShell = ({
7192
7764
  onRefreshReviewData: refreshReviewData2,
7193
7765
  onToast: showToast
7194
7766
  });
7195
- return /* @__PURE__ */ jsxs14(
7767
+ return /* @__PURE__ */ jsxs15(
7196
7768
  "div",
7197
7769
  {
7198
7770
  className: `df-review-shell is-theme-${effectiveReviewTheme}${isListVisible ? " is-list-visible" : ""}`,
7199
7771
  children: [
7200
- /* @__PURE__ */ jsx16(
7772
+ /* @__PURE__ */ jsx17(
7201
7773
  ReviewTopbar,
7202
7774
  {
7203
7775
  draftTarget,
@@ -7222,7 +7794,7 @@ var ReviewShell = ({
7222
7794
  onOpenSettings: openFigmaSettings
7223
7795
  }
7224
7796
  ),
7225
- isSitemapOpen && /* @__PURE__ */ jsx16(
7797
+ isSitemapOpen && /* @__PURE__ */ jsx17(
7226
7798
  SitemapModal,
7227
7799
  {
7228
7800
  pages,
@@ -7234,7 +7806,7 @@ var ReviewShell = ({
7234
7806
  onSelectPage: selectPage
7235
7807
  }
7236
7808
  ),
7237
- isFigmaSettingsOpen && /* @__PURE__ */ jsx16(
7809
+ isFigmaSettingsOpen && /* @__PURE__ */ jsx17(
7238
7810
  ReviewSettingsModal,
7239
7811
  {
7240
7812
  figmaTokenDraft,
@@ -7253,7 +7825,7 @@ var ReviewShell = ({
7253
7825
  onSave: saveReviewSettings
7254
7826
  }
7255
7827
  ),
7256
- isInitialPromptOpen && /* @__PURE__ */ jsx16(
7828
+ isInitialPromptOpen && /* @__PURE__ */ jsx17(
7257
7829
  PromptModal,
7258
7830
  {
7259
7831
  initialPromptText,
@@ -7262,8 +7834,16 @@ var ReviewShell = ({
7262
7834
  onCopyPrompt: (text, key) => void copyPrompt(text, key)
7263
7835
  }
7264
7836
  ),
7265
- toastMessage && /* @__PURE__ */ jsx16("div", { className: "df-review-copy-toast", role: "status", children: toastMessage }),
7266
- /* @__PURE__ */ jsx16("div", { className: "df-review-side-rail", children: /* @__PURE__ */ jsxs14(
7837
+ editingItem && /* @__PURE__ */ jsx17(
7838
+ QaItemEditModal,
7839
+ {
7840
+ item: editingItem,
7841
+ onClose: () => setEditingItem(null),
7842
+ onSave: saveItemComment
7843
+ }
7844
+ ),
7845
+ toastMessage && /* @__PURE__ */ jsx17("div", { className: "df-review-copy-toast", role: "status", children: toastMessage }),
7846
+ /* @__PURE__ */ jsx17("div", { className: "df-review-side-rail", children: /* @__PURE__ */ jsxs15(
7267
7847
  "button",
7268
7848
  {
7269
7849
  "aria-label": isListVisible ? "Hide QA list" : "Show QA list",
@@ -7271,12 +7851,12 @@ var ReviewShell = ({
7271
7851
  type: "button",
7272
7852
  onClick: () => setIsListVisible((current) => !current),
7273
7853
  children: [
7274
- /* @__PURE__ */ jsx16("span", { "aria-hidden": "true", children: /* @__PURE__ */ jsx16(GripVertical, {}) }),
7275
- /* @__PURE__ */ jsx16("strong", { children: "QA" })
7854
+ /* @__PURE__ */ jsx17("span", { "aria-hidden": "true", children: /* @__PURE__ */ jsx17(GripVertical, {}) }),
7855
+ /* @__PURE__ */ jsx17("strong", { children: "QA" })
7276
7856
  ]
7277
7857
  }
7278
7858
  ) }),
7279
- /* @__PURE__ */ jsx16(
7859
+ /* @__PURE__ */ jsx17(
7280
7860
  ReviewQaPanel,
7281
7861
  {
7282
7862
  activeAdapterEntry,
@@ -7295,12 +7875,14 @@ var ReviewShell = ({
7295
7875
  remoteAdapterEntry,
7296
7876
  selectedItemId,
7297
7877
  showSourceSelect,
7878
+ sourceRoot,
7298
7879
  source,
7299
7880
  sourceEntries,
7300
7881
  onChangeItemStatus: changeItemStatus,
7301
7882
  onClearSelectedItem: clearSelectedReviewItem,
7302
7883
  onChangeReviewSource: changeReviewSource,
7303
7884
  onCopyItemPrompt: (numberedItem) => void copyItemPrompt(numberedItem),
7885
+ onEditItem: setEditingItem,
7304
7886
  onQaFilterChange: setQaFilter,
7305
7887
  onRefreshReviewData: refreshReviewData2,
7306
7888
  onRemoveItem: removeItem,
@@ -7309,13 +7891,11 @@ var ReviewShell = ({
7309
7891
  onToggleItemOverlayVisibility: toggleItemOverlayVisibility
7310
7892
  }
7311
7893
  ),
7312
- /* @__PURE__ */ jsx16(
7894
+ /* @__PURE__ */ jsx17(
7313
7895
  ReviewTargetFrame,
7314
7896
  {
7315
- canWriteAny,
7316
7897
  canWriteArea,
7317
7898
  canWriteDom,
7318
- canWriteNote,
7319
7899
  frameScrollRef,
7320
7900
  iframeRef,
7321
7901
  isRulerAvailable,
@@ -7331,7 +7911,7 @@ var ReviewShell = ({
7331
7911
  rulerUnit,
7332
7912
  size,
7333
7913
  targetSrc,
7334
- onLoadTarget: initReviewKit,
7914
+ onLoadTarget: loadTargetFrame,
7335
7915
  onSetReviewMode: setReviewMode
7336
7916
  }
7337
7917
  )
@@ -7514,7 +8094,7 @@ var createSupabasePresenceAdapter = ({
7514
8094
  });
7515
8095
 
7516
8096
  // src/react-shell.tsx
7517
- import { jsx as jsx17 } from "react/jsx-runtime";
8097
+ import { jsx as jsx18 } from "react/jsx-runtime";
7518
8098
  var mountReviewShell = (options) => {
7519
8099
  if (typeof document === "undefined" || !document.head) return;
7520
8100
  const { rootId = "root", ...shellProps } = options;
@@ -7525,7 +8105,7 @@ var mountReviewShell = (options) => {
7525
8105
  root.style.height = "100%";
7526
8106
  root.style.margin = "0";
7527
8107
  createRoot(root).render(
7528
- /* @__PURE__ */ jsx17(React2.StrictMode, { children: /* @__PURE__ */ jsx17(ReviewShell, { ...shellProps }) })
8108
+ /* @__PURE__ */ jsx18(React2.StrictMode, { children: /* @__PURE__ */ jsx18(ReviewShell, { ...shellProps }) })
7529
8109
  );
7530
8110
  };
7531
8111
  export {
@@ -7553,6 +8133,7 @@ lucide-react/dist/esm/icons/copy.mjs:
7553
8133
  lucide-react/dist/esm/icons/external-link.mjs:
7554
8134
  lucide-react/dist/esm/icons/eye-off.mjs:
7555
8135
  lucide-react/dist/esm/icons/eye.mjs:
8136
+ lucide-react/dist/esm/icons/file-code-corner.mjs:
7556
8137
  lucide-react/dist/esm/icons/grip-vertical.mjs:
7557
8138
  lucide-react/dist/esm/icons/image.mjs:
7558
8139
  lucide-react/dist/esm/icons/layout-grid.mjs:
@@ -7560,6 +8141,7 @@ lucide-react/dist/esm/icons/list-filter.mjs:
7560
8141
  lucide-react/dist/esm/icons/map.mjs:
7561
8142
  lucide-react/dist/esm/icons/maximize-2.mjs:
7562
8143
  lucide-react/dist/esm/icons/monitor.mjs:
8144
+ lucide-react/dist/esm/icons/pencil.mjs:
7563
8145
  lucide-react/dist/esm/icons/rectangle-horizontal.mjs:
7564
8146
  lucide-react/dist/esm/icons/refresh-cw.mjs:
7565
8147
  lucide-react/dist/esm/icons/ruler.mjs: