@designfever/web-review-kit 0.5.0 → 0.6.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.
@@ -294,6 +294,7 @@ function ensureReviewShellStyle() {
294
294
 
295
295
  .df-review-shell {
296
296
  --df-review-frame-gutter-x: var(--df-review-space-4);
297
+ position: relative;
297
298
  display: grid;
298
299
  grid-template-columns: minmax(0, 1fr) 0 48px;
299
300
  grid-template-rows: auto auto minmax(0, 1fr);
@@ -325,7 +326,7 @@ function ensureReviewShellStyle() {
325
326
 
326
327
  .df-review-address {
327
328
  display: grid;
328
- grid-template-columns: auto minmax(160px, 1fr) auto auto;
329
+ grid-template-columns: auto minmax(160px, 1fr) auto;
329
330
  align-items: stretch;
330
331
  gap: var(--df-review-space-2);
331
332
  width: 100%;
@@ -333,6 +334,13 @@ function ensureReviewShellStyle() {
333
334
  margin: 0 auto;
334
335
  }
335
336
 
337
+ .df-review-address-actions {
338
+ display: flex;
339
+ align-items: stretch;
340
+ gap: 4px;
341
+ min-width: 0;
342
+ }
343
+
336
344
  .df-review-address input {
337
345
  width: 100%;
338
346
  height: var(--df-review-control-height-md);
@@ -411,6 +419,24 @@ function ensureReviewShellStyle() {
411
419
  color: var(--df-review-accent);
412
420
  }
413
421
 
422
+ .df-review-address-refresh {
423
+ display: inline-grid;
424
+ place-items: center;
425
+ width: var(--df-review-control-height-md);
426
+ min-width: var(--df-review-control-height-md);
427
+ padding: 0;
428
+ }
429
+
430
+ .df-review-address-refresh svg {
431
+ width: 16px;
432
+ height: 16px;
433
+ fill: none;
434
+ stroke: currentColor;
435
+ stroke-linecap: round;
436
+ stroke-linejoin: round;
437
+ stroke-width: 1.9;
438
+ }
439
+
414
440
  .df-review-sitemap-button svg,
415
441
  .df-review-sitemap-header button svg {
416
442
  width: 18px;
@@ -1362,8 +1388,7 @@ function ensureReviewShellStyle() {
1362
1388
  }
1363
1389
 
1364
1390
  .df-review-presets,
1365
- .df-review-mode,
1366
- .df-review-overlays {
1391
+ .df-review-mode {
1367
1392
  display: flex;
1368
1393
  align-items: center;
1369
1394
  gap: var(--df-review-space-1-5);
@@ -1375,6 +1400,24 @@ function ensureReviewShellStyle() {
1375
1400
  background: var(--df-review-card);
1376
1401
  }
1377
1402
 
1403
+ .df-review-overlays {
1404
+ display: flex;
1405
+ align-items: center;
1406
+ gap: 4px;
1407
+ height: var(--df-review-control-height-md);
1408
+ min-height: var(--df-review-control-height-md);
1409
+ padding: 0;
1410
+ border: 0;
1411
+ border-radius: 0;
1412
+ background: transparent;
1413
+ box-shadow: none;
1414
+ }
1415
+
1416
+ .df-review-mode {
1417
+ gap: 3px;
1418
+ padding: 3px;
1419
+ }
1420
+
1378
1421
  .df-review-tool-divider,
1379
1422
  .df-review-mode-divider {
1380
1423
  display: inline-flex;
@@ -1494,6 +1537,35 @@ function ensureReviewShellStyle() {
1494
1537
  color: var(--df-review-muted);
1495
1538
  }
1496
1539
 
1540
+ .df-review-overlay-button {
1541
+ border: 1px solid var(--df-review-line-soft);
1542
+ border-radius: var(--df-review-radius-sm);
1543
+ background: var(--df-review-control);
1544
+ box-shadow: var(--df-review-shadow-control);
1545
+ }
1546
+
1547
+ .df-review-overlay-button:hover,
1548
+ .df-review-overlay-button:focus-visible {
1549
+ border-color: var(--df-review-accent);
1550
+ background: var(--df-review-control-hover);
1551
+ color: var(--df-review-text);
1552
+ outline: 0;
1553
+ }
1554
+
1555
+ .df-review-overlay-button.is-active {
1556
+ border-color: var(--df-review-accent);
1557
+ background: var(--df-review-accent-soft);
1558
+ box-shadow: inset 0 0 0 1px var(--df-review-accent-hover);
1559
+ color: var(--df-review-accent);
1560
+ }
1561
+
1562
+ .df-review-mode-button {
1563
+ width: calc(var(--df-review-control-height-md) - 6px);
1564
+ min-width: calc(var(--df-review-control-height-md) - 6px);
1565
+ height: calc(var(--df-review-control-height-md) - 6px);
1566
+ min-height: calc(var(--df-review-control-height-md) - 6px);
1567
+ }
1568
+
1497
1569
  .df-review-overlays-menu {
1498
1570
  position: relative;
1499
1571
  display: none;
@@ -1613,20 +1685,19 @@ function ensureReviewShellStyle() {
1613
1685
 
1614
1686
  .df-review-preset-select {
1615
1687
  display: block;
1616
- flex: 0 1 190px;
1617
- width: clamp(154px, 26vw, 190px);
1688
+ flex: 0 1 150px;
1689
+ min-width: 128px;
1690
+ width: clamp(128px, 20vw, 150px);
1618
1691
  }
1619
1692
 
1620
- .df-review-overlays {
1621
- display: none;
1622
- }
1623
-
1624
- .df-review-overlays-menu {
1625
- display: block;
1693
+ .df-review-tool-divider,
1694
+ .df-review-active-size {
1695
+ display: none;
1626
1696
  }
1627
- }
1628
1697
 
1629
- .df-review-side-rail {
1698
+ }
1699
+
1700
+ .df-review-side-rail {
1630
1701
  grid-column: 3;
1631
1702
  grid-row: 1 / span 3;
1632
1703
  position: relative;
@@ -1643,11 +1714,11 @@ function ensureReviewShellStyle() {
1643
1714
 
1644
1715
  .df-review-side-toggle {
1645
1716
  position: relative;
1646
- flex: 0 0 58px;
1717
+ flex: 0 0 48px;
1647
1718
  display: grid;
1648
1719
  place-items: center;
1649
1720
  width: 100%;
1650
- min-height: 58px;
1721
+ min-height: 48px;
1651
1722
  border: 0;
1652
1723
  border-radius: 0;
1653
1724
  padding: 0;
@@ -1666,9 +1737,9 @@ function ensureReviewShellStyle() {
1666
1737
 
1667
1738
  .df-review-side-toggle.is-active::after {
1668
1739
  position: absolute;
1669
- top: 12px;
1740
+ top: 9px;
1670
1741
  right: 0;
1671
- bottom: 12px;
1742
+ bottom: 9px;
1672
1743
  width: 3px;
1673
1744
  border-radius: 3px 0 0 3px;
1674
1745
  background: var(--df-review-accent);
@@ -1703,17 +1774,29 @@ function ensureReviewShellStyle() {
1703
1774
  stroke-width: 1.55;
1704
1775
  }
1705
1776
 
1777
+ .df-review-side-actions {
1778
+ display: flex;
1779
+ flex-direction: column;
1780
+ align-items: stretch;
1781
+ width: 100%;
1782
+ margin-top: auto;
1783
+ }
1784
+
1706
1785
  .df-review-presence-overlay {
1707
1786
  position: relative;
1708
1787
  margin-top: auto;
1709
1788
  }
1710
1789
 
1790
+ .df-review-side-actions .df-review-presence-overlay {
1791
+ margin-top: 0;
1792
+ }
1793
+
1711
1794
  .df-review-presence-button {
1712
1795
  position: relative;
1713
1796
  display: grid;
1714
1797
  place-items: center;
1715
1798
  width: 100%;
1716
- min-height: 58px;
1799
+ min-height: 48px;
1717
1800
  border: 0;
1718
1801
  border-radius: 0;
1719
1802
  padding: 0;
@@ -1748,8 +1831,8 @@ function ensureReviewShellStyle() {
1748
1831
 
1749
1832
  .df-review-presence-badge {
1750
1833
  position: absolute;
1751
- top: 10px;
1752
- right: 7px;
1834
+ top: 6px;
1835
+ right: 6px;
1753
1836
  display: grid;
1754
1837
  place-items: center;
1755
1838
  min-width: 17px;
@@ -1769,38 +1852,46 @@ function ensureReviewShellStyle() {
1769
1852
  position: absolute;
1770
1853
  right: calc(100% + 8px);
1771
1854
  bottom: 8px;
1772
- display: grid;
1855
+ display: flex;
1856
+ flex-direction: column;
1857
+ align-items: flex-end;
1773
1858
  gap: 5px;
1774
- min-width: 132px;
1859
+ width: max-content;
1860
+ min-width: 0;
1775
1861
  max-width: 220px;
1776
- border: 1px solid var(--df-review-line);
1777
- border-radius: var(--df-review-radius-md);
1778
- padding: 8px;
1779
- background: var(--df-review-panel);
1780
- box-shadow: var(--df-review-shadow-modal);
1781
1862
  }
1782
1863
 
1783
1864
  .df-review-presence-chip {
1784
1865
  --df-review-presence-color: var(--df-review-accent);
1785
- display: flex;
1866
+ display: inline-flex;
1786
1867
  align-items: center;
1868
+ width: fit-content;
1869
+ max-width: 180px;
1787
1870
  min-width: 0;
1788
- min-height: 24px;
1789
- border-left: 2px solid var(--df-review-presence-color);
1790
- border-radius: var(--df-review-radius-sm);
1791
- padding: 0 8px;
1871
+ min-height: 22px;
1872
+ justify-content: flex-end;
1873
+ border: 1px solid var(--df-review-line-soft);
1874
+ border-radius: var(--df-review-radius-pill);
1875
+ padding: 0 9px;
1792
1876
  color: var(--df-review-text);
1793
1877
  background: var(--df-review-control);
1794
1878
  font-size: var(--df-review-font-size-xs);
1795
1879
  font-weight: 500;
1796
1880
  line-height: 1.1;
1881
+ white-space: nowrap;
1882
+ }
1883
+
1884
+ .df-review-presence-chip span {
1885
+ min-width: 0;
1797
1886
  overflow: hidden;
1798
1887
  text-overflow: ellipsis;
1888
+ text-align: right;
1799
1889
  white-space: nowrap;
1800
1890
  }
1801
1891
 
1802
1892
  .df-review-presence-chip.is-self {
1803
1893
  color: var(--df-review-accent);
1894
+ border-color: var(--df-review-accent-soft);
1804
1895
  background: var(--df-review-accent-soft);
1805
1896
  }
1806
1897
 
@@ -1810,7 +1901,7 @@ function ensureReviewShellStyle() {
1810
1901
  position: relative;
1811
1902
  z-index: 600;
1812
1903
  display: grid;
1813
- grid-template-rows: minmax(0, 1fr);
1904
+ grid-template-rows: minmax(0, 1fr) auto;
1814
1905
  min-width: 0;
1815
1906
  min-height: 0;
1816
1907
  overflow: hidden;
@@ -1819,6 +1910,25 @@ function ensureReviewShellStyle() {
1819
1910
  linear-gradient(180deg, var(--df-review-panel), var(--df-review-bg));
1820
1911
  }
1821
1912
 
1913
+ .df-review-qa-draft-host {
1914
+ position: relative;
1915
+ z-index: 2;
1916
+ display: none;
1917
+ justify-self: end;
1918
+ width: calc(100% - var(--df-review-space-4));
1919
+ margin: 0 var(--df-review-space-2) var(--df-review-space-2) auto;
1920
+ min-width: 0;
1921
+ }
1922
+
1923
+ .df-review-qa-draft-host[data-has-draft-composer="true"] {
1924
+ display: block;
1925
+ }
1926
+
1927
+ .df-review-qa-panel[data-has-draft-composer="true"] .df-review-panel-body {
1928
+ opacity: 0.36;
1929
+ pointer-events: none;
1930
+ }
1931
+
1822
1932
  .df-review-shell:not(.is-list-visible) .df-review-qa-panel,
1823
1933
  .df-review-qa-panel[aria-hidden="true"] {
1824
1934
  visibility: hidden;
@@ -1903,13 +2013,14 @@ function ensureReviewShellStyle() {
1903
2013
  .df-review-list-meta span {
1904
2014
  min-width: 0;
1905
2015
  overflow: hidden;
2016
+ color: #fff;
1906
2017
  text-overflow: ellipsis;
1907
2018
  white-space: nowrap;
1908
2019
  }
1909
2020
 
1910
2021
  .df-review-list-meta strong {
1911
2022
  flex: 0 0 auto;
1912
- color: var(--df-review-muted);
2023
+ color: #fff;
1913
2024
  font-size: var(--df-review-font-size-xs);
1914
2025
  font-variant-numeric: tabular-nums;
1915
2026
  font-weight: 500;
@@ -1967,27 +2078,28 @@ function ensureReviewShellStyle() {
1967
2078
  display: flex;
1968
2079
  align-items: center;
1969
2080
  justify-self: end;
1970
- gap: var(--df-review-space-1-5);
1971
- height: var(--df-review-control-height-md);
1972
- min-height: var(--df-review-control-height-md);
2081
+ gap: 2px;
2082
+ height: 26px;
2083
+ min-height: 26px;
1973
2084
  padding: 0;
1974
- border: 1px solid var(--df-review-line-soft);
1975
- border-radius: var(--df-review-radius-md);
1976
- background: var(--df-review-card);
1977
- box-shadow: var(--df-review-shadow-control);
2085
+ border: 0;
2086
+ border-radius: 0;
2087
+ background: transparent;
2088
+ box-shadow: none;
1978
2089
  }
1979
2090
 
1980
2091
  .df-review-filter-tab {
1981
2092
  position: relative;
1982
2093
  display: grid;
1983
2094
  place-items: center;
1984
- width: var(--df-review-control-height-md);
1985
- min-width: var(--df-review-control-height-md);
1986
- height: var(--df-review-control-height-md);
2095
+ width: 26px;
2096
+ min-width: 26px;
2097
+ height: 26px;
1987
2098
  border: 0;
1988
- border-radius: var(--df-review-radius-sm);
2099
+ border-radius: 0;
1989
2100
  background: transparent;
1990
2101
  color: var(--df-review-subtle);
2102
+ opacity: 0.3;
1991
2103
  }
1992
2104
 
1993
2105
  .df-review-filter-icon {
@@ -2008,18 +2120,18 @@ function ensureReviewShellStyle() {
2008
2120
 
2009
2121
  .df-review-filter-tab:hover,
2010
2122
  .df-review-filter-tab.is-active {
2011
- background: var(--df-review-accent-soft);
2012
2123
  color: var(--df-review-text);
2124
+ opacity: 1;
2013
2125
  }
2014
2126
 
2015
2127
  .df-review-filter-tab.is-active {
2016
- box-shadow: inset 0 0 0 1px rgba(124, 199, 255, 0.42);
2128
+ box-shadow: none;
2017
2129
  color: var(--df-review-accent);
2018
2130
  }
2019
2131
 
2020
2132
  .df-review-filter-icon svg {
2021
- width: 18px;
2022
- height: 18px;
2133
+ width: 14px;
2134
+ height: 14px;
2023
2135
  fill: none;
2024
2136
  stroke: currentColor;
2025
2137
  stroke-linecap: round;
@@ -2165,9 +2277,21 @@ function ensureReviewShellStyle() {
2165
2277
  }
2166
2278
 
2167
2279
  .df-review-item-id {
2280
+ appearance: none;
2168
2281
  border-color: var(--df-review-line);
2169
2282
  background: rgba(255, 255, 255, 0.03);
2170
2283
  color: var(--df-review-text);
2284
+ cursor: copy;
2285
+ font-family: inherit;
2286
+ }
2287
+
2288
+ .df-review-item-id:hover,
2289
+ .df-review-item-id:focus-visible,
2290
+ .df-review-item-id.is-copied {
2291
+ border-color: var(--df-review-accent);
2292
+ background: var(--df-review-accent-soft);
2293
+ color: var(--df-review-accent);
2294
+ outline: none;
2171
2295
  }
2172
2296
 
2173
2297
  .df-review-item-scope {
@@ -2787,30 +2911,44 @@ function ensureReviewShellStyle() {
2787
2911
  var(--df-review-control-height-md)
2788
2912
  var(--df-review-control-height-md);
2789
2913
  align-items: center;
2790
- gap: 8px;
2914
+ gap: var(--df-review-space-2);
2791
2915
  min-width: 0;
2792
2916
  padding: var(--df-review-space-3) var(--df-review-frame-gutter-x);
2793
2917
  border-bottom: 1px solid var(--df-review-line-soft);
2794
2918
  background: var(--df-review-card);
2795
2919
  color: var(--df-review-muted);
2920
+ font-size: var(--df-review-font-size-sm);
2921
+ font-weight: 500;
2796
2922
  }
2797
2923
 
2798
- .df-review-section-outline-head span {
2924
+ .df-review-section-outline-summary {
2799
2925
  display: grid;
2800
- gap: 2px;
2926
+ grid-template-columns: minmax(0, 1fr) auto;
2927
+ align-items: center;
2928
+ gap: 8px;
2929
+ min-height: var(--df-review-control-height-md);
2930
+ min-width: 0;
2931
+ }
2932
+
2933
+ .df-review-section-outline-summary span {
2934
+ display: inline-flex;
2935
+ align-items: baseline;
2936
+ gap: 6px;
2801
2937
  min-width: 0;
2802
2938
  }
2803
2939
 
2804
2940
  .df-review-section-outline-head strong {
2805
2941
  overflow: hidden;
2806
2942
  color: var(--df-review-text);
2807
- font-size: var(--df-review-font-size-lg);
2943
+ font-size: inherit;
2808
2944
  font-weight: 600;
2945
+ line-height: 1;
2809
2946
  text-overflow: ellipsis;
2810
2947
  white-space: nowrap;
2811
2948
  }
2812
2949
 
2813
2950
  .df-review-section-outline-head small {
2951
+ flex: 0 0 auto;
2814
2952
  overflow: hidden;
2815
2953
  color: var(--df-review-muted);
2816
2954
  font-size: var(--df-review-font-size-xs);
@@ -2819,6 +2957,60 @@ function ensureReviewShellStyle() {
2819
2957
  white-space: nowrap;
2820
2958
  }
2821
2959
 
2960
+ .df-review-section-outline-meta-controls {
2961
+ display: inline-flex;
2962
+ align-items: center;
2963
+ justify-content: flex-end;
2964
+ gap: 2px;
2965
+ height: 26px;
2966
+ min-height: 26px;
2967
+ min-width: 0;
2968
+ border: 0;
2969
+ border-radius: 0;
2970
+ padding: 0;
2971
+ background: transparent;
2972
+ box-shadow: none;
2973
+ }
2974
+
2975
+ .df-review-section-outline-meta-toggle {
2976
+ display: inline-grid;
2977
+ place-items: center;
2978
+ width: 26px;
2979
+ min-width: 26px;
2980
+ height: 26px;
2981
+ border: 0;
2982
+ border-radius: 0;
2983
+ padding: 0;
2984
+ color: var(--df-review-subtle);
2985
+ background: transparent;
2986
+ box-shadow: none;
2987
+ cursor: pointer;
2988
+ opacity: 0.3;
2989
+ }
2990
+
2991
+ .df-review-section-outline-meta-toggle:hover,
2992
+ .df-review-section-outline-meta-toggle:focus-visible,
2993
+ .df-review-section-outline-meta-toggle.is-active {
2994
+ color: var(--df-review-text);
2995
+ opacity: 1;
2996
+ outline: 0;
2997
+ }
2998
+
2999
+ .df-review-section-outline-meta-toggle.is-active {
3000
+ box-shadow: none;
3001
+ color: var(--df-review-accent);
3002
+ }
3003
+
3004
+ .df-review-section-outline-meta-toggle svg {
3005
+ width: 14px;
3006
+ height: 14px;
3007
+ fill: none;
3008
+ stroke: currentColor;
3009
+ stroke-linecap: round;
3010
+ stroke-linejoin: round;
3011
+ stroke-width: 2;
3012
+ }
3013
+
2822
3014
  .df-review-section-outline-filter {
2823
3015
  display: grid;
2824
3016
  grid-template-columns: 18px minmax(0, 1fr) auto;
@@ -2829,7 +3021,7 @@ function ensureReviewShellStyle() {
2829
3021
  height: var(--df-review-control-height-md);
2830
3022
  min-height: var(--df-review-control-height-md);
2831
3023
  border: 1px solid var(--df-review-line-soft);
2832
- border-radius: var(--df-review-radius-md);
3024
+ border-radius: var(--df-review-radius-sm);
2833
3025
  padding: 0 7px 0 11px;
2834
3026
  color: var(--df-review-muted);
2835
3027
  background: var(--df-review-control);
@@ -2911,6 +3103,15 @@ function ensureReviewShellStyle() {
2911
3103
  display: grid;
2912
3104
  }
2913
3105
 
3106
+ .df-review-section-outline-entry-body {
3107
+ display: grid;
3108
+ border-radius: var(--df-review-radius-sm);
3109
+ }
3110
+
3111
+ .df-review-section-outline-entry-body:hover {
3112
+ background: var(--df-review-accent-soft);
3113
+ }
3114
+
2914
3115
  .df-review-section-outline-item.is-depth-1:not(:last-child) {
2915
3116
  margin-bottom: 7px;
2916
3117
  padding-bottom: 7px;
@@ -2926,10 +3127,6 @@ function ensureReviewShellStyle() {
2926
3127
  padding: 7px 6px;
2927
3128
  }
2928
3129
 
2929
- .df-review-section-outline-row:hover {
2930
- background: var(--df-review-accent-soft);
2931
- }
2932
-
2933
3130
  .df-review-section-outline-toggle {
2934
3131
  display: grid;
2935
3132
  place-items: center;
@@ -3001,44 +3198,124 @@ function ensureReviewShellStyle() {
3001
3198
  color: var(--df-review-accent);
3002
3199
  }
3003
3200
 
3004
- .df-review-section-outline-links {
3005
- display: inline-flex;
3006
- align-items: center;
3007
- justify-content: flex-end;
3008
- gap: 2px;
3201
+ .df-review-section-outline-meta {
3202
+ display: grid;
3203
+ gap: 3px;
3204
+ min-width: 0;
3205
+ padding: 0 6px 7px;
3009
3206
  }
3010
3207
 
3011
- .df-review-section-outline-divider {
3208
+ .df-review-section-outline-meta-row {
3209
+ display: grid;
3210
+ grid-template-columns: 52px minmax(0, 1fr);
3211
+ align-items: start;
3212
+ gap: 6px;
3213
+ min-width: 0;
3214
+ color: var(--df-review-muted);
3215
+ font-family: var(--df-review-font-mono);
3216
+ font-size: var(--df-review-font-size-2xs);
3217
+ line-height: 1.35;
3218
+ }
3219
+
3220
+ .df-review-section-outline-meta-row b {
3012
3221
  color: var(--df-review-subtle);
3013
- font-size: var(--df-review-font-size-xs);
3014
- line-height: 1;
3015
- user-select: none;
3222
+ font-weight: 600;
3016
3223
  }
3017
3224
 
3018
- .df-review-section-outline-link {
3019
- display: inline-grid;
3020
- place-items: center;
3021
- width: 26px;
3022
- height: 26px;
3023
- border: 1px solid transparent;
3024
- border-radius: var(--df-review-radius-sm);
3025
- padding: 0;
3225
+ .df-review-section-outline-meta-row code {
3226
+ min-width: 0;
3227
+ overflow-wrap: anywhere;
3026
3228
  color: var(--df-review-muted);
3027
- background: transparent;
3028
- cursor: pointer;
3029
- transition: border-color 140ms ease, background 140ms ease,
3030
- color 140ms ease, opacity 140ms ease;
3229
+ font-family: inherit;
3031
3230
  }
3032
3231
 
3033
- .df-review-section-outline-link.is-dom-select {
3034
- width: 26px;
3035
- min-width: 26px;
3036
- padding: 0;
3232
+ .df-review-section-outline-meta-row.is-text code {
3233
+ color: var(--df-review-text);
3037
3234
  }
3038
3235
 
3039
- .df-review-section-outline-link.is-dom-select svg {
3040
- width: 16px;
3041
- height: 16px;
3236
+ .df-review-section-outline-meta-row.is-media code {
3237
+ color: var(--df-review-accent);
3238
+ }
3239
+
3240
+ .df-review-section-outline-media-link {
3241
+ display: block;
3242
+ min-width: 0;
3243
+ color: var(--df-review-accent);
3244
+ text-decoration: none;
3245
+ }
3246
+
3247
+ .df-review-section-outline-media-link:hover,
3248
+ .df-review-section-outline-media-link:focus-visible {
3249
+ color: var(--df-review-text);
3250
+ outline: 0;
3251
+ }
3252
+
3253
+ .df-review-section-outline-meta-row.is-class code {
3254
+ color: var(--df-review-source-popover-data-subtle);
3255
+ }
3256
+
3257
+ .df-review-section-outline-meta-row.is-class {
3258
+ align-items: center;
3259
+ }
3260
+
3261
+ .df-review-section-outline-class-tags {
3262
+ display: flex;
3263
+ align-items: center;
3264
+ flex-wrap: wrap;
3265
+ gap: 3px;
3266
+ min-width: 0;
3267
+ }
3268
+
3269
+ .df-review-section-outline-class-tags code {
3270
+ display: inline-flex;
3271
+ align-items: center;
3272
+ max-width: 100%;
3273
+ min-height: 20px;
3274
+ border: 1px solid var(--df-review-line-soft);
3275
+ border-radius: var(--df-review-radius-pill);
3276
+ padding: 0 6px;
3277
+ background: var(--df-review-control);
3278
+ line-height: 1;
3279
+ }
3280
+
3281
+ .df-review-section-outline-links {
3282
+ display: inline-flex;
3283
+ align-items: center;
3284
+ justify-content: flex-end;
3285
+ gap: 2px;
3286
+ }
3287
+
3288
+ .df-review-section-outline-divider {
3289
+ color: var(--df-review-subtle);
3290
+ font-size: var(--df-review-font-size-xs);
3291
+ line-height: 1;
3292
+ user-select: none;
3293
+ }
3294
+
3295
+ .df-review-section-outline-link {
3296
+ display: inline-grid;
3297
+ place-items: center;
3298
+ width: 26px;
3299
+ height: 26px;
3300
+ border: 1px solid transparent;
3301
+ border-radius: var(--df-review-radius-sm);
3302
+ padding: 0;
3303
+ color: var(--df-review-muted);
3304
+ background: transparent;
3305
+ cursor: pointer;
3306
+ transition: border-color 140ms ease, background 140ms ease,
3307
+ color 140ms ease, opacity 140ms ease;
3308
+ }
3309
+
3310
+ .df-review-section-outline-link.is-dom-select {
3311
+ width: 26px;
3312
+ min-width: 26px;
3313
+ padding: 0;
3314
+ }
3315
+
3316
+ .df-review-section-outline-link.is-dom-select svg {
3317
+ width: 16px;
3318
+ height: 16px;
3042
3319
  }
3043
3320
 
3044
3321
  .df-review-section-outline-link:hover {
@@ -3498,24 +3775,16 @@ var __iconNode6 = [
3498
3775
  ];
3499
3776
  var Database = createLucideIcon("database", __iconNode6);
3500
3777
 
3501
- // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/ellipsis.mjs
3502
- var __iconNode7 = [
3503
- ["circle", { cx: "12", cy: "12", r: "1", key: "41hilf" }],
3504
- ["circle", { cx: "19", cy: "12", r: "1", key: "1wjl8i" }],
3505
- ["circle", { cx: "5", cy: "12", r: "1", key: "1pcz8c" }]
3506
- ];
3507
- var Ellipsis = createLucideIcon("ellipsis", __iconNode7);
3508
-
3509
3778
  // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/external-link.mjs
3510
- var __iconNode8 = [
3779
+ var __iconNode7 = [
3511
3780
  ["path", { d: "M15 3h6v6", key: "1q9fwt" }],
3512
3781
  ["path", { d: "M10 14 21 3", key: "gplh6r" }],
3513
3782
  ["path", { d: "M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6", key: "a6xqqp" }]
3514
3783
  ];
3515
- var ExternalLink = createLucideIcon("external-link", __iconNode8);
3784
+ var ExternalLink = createLucideIcon("external-link", __iconNode7);
3516
3785
 
3517
3786
  // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/eye-off.mjs
3518
- var __iconNode9 = [
3787
+ var __iconNode8 = [
3519
3788
  [
3520
3789
  "path",
3521
3790
  {
@@ -3533,10 +3802,10 @@ var __iconNode9 = [
3533
3802
  ],
3534
3803
  ["path", { d: "m2 2 20 20", key: "1ooewy" }]
3535
3804
  ];
3536
- var EyeOff = createLucideIcon("eye-off", __iconNode9);
3805
+ var EyeOff = createLucideIcon("eye-off", __iconNode8);
3537
3806
 
3538
3807
  // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/eye.mjs
3539
- var __iconNode10 = [
3808
+ var __iconNode9 = [
3540
3809
  [
3541
3810
  "path",
3542
3811
  {
@@ -3546,10 +3815,10 @@ var __iconNode10 = [
3546
3815
  ],
3547
3816
  ["circle", { cx: "12", cy: "12", r: "3", key: "1v7zrd" }]
3548
3817
  ];
3549
- var Eye = createLucideIcon("eye", __iconNode10);
3818
+ var Eye = createLucideIcon("eye", __iconNode9);
3550
3819
 
3551
3820
  // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/file-text.mjs
3552
- var __iconNode11 = [
3821
+ var __iconNode10 = [
3553
3822
  [
3554
3823
  "path",
3555
3824
  {
@@ -3562,43 +3831,43 @@ var __iconNode11 = [
3562
3831
  ["path", { d: "M16 13H8", key: "t4e002" }],
3563
3832
  ["path", { d: "M16 17H8", key: "z1uh3a" }]
3564
3833
  ];
3565
- var FileText = createLucideIcon("file-text", __iconNode11);
3834
+ var FileText = createLucideIcon("file-text", __iconNode10);
3566
3835
 
3567
3836
  // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/image.mjs
3568
- var __iconNode12 = [
3837
+ var __iconNode11 = [
3569
3838
  ["rect", { width: "18", height: "18", x: "3", y: "3", rx: "2", ry: "2", key: "1m3agn" }],
3570
3839
  ["circle", { cx: "9", cy: "9", r: "2", key: "af1f0g" }],
3571
3840
  ["path", { d: "m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21", key: "1xmnt7" }]
3572
3841
  ];
3573
- var Image = createLucideIcon("image", __iconNode12);
3842
+ var Image = createLucideIcon("image", __iconNode11);
3574
3843
 
3575
3844
  // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/layout-grid.mjs
3576
- var __iconNode13 = [
3845
+ var __iconNode12 = [
3577
3846
  ["rect", { width: "7", height: "7", x: "3", y: "3", rx: "1", key: "1g98yp" }],
3578
3847
  ["rect", { width: "7", height: "7", x: "14", y: "3", rx: "1", key: "6d4xhi" }],
3579
3848
  ["rect", { width: "7", height: "7", x: "14", y: "14", rx: "1", key: "nxv5o0" }],
3580
3849
  ["rect", { width: "7", height: "7", x: "3", y: "14", rx: "1", key: "1bb6yr" }]
3581
3850
  ];
3582
- var LayoutGrid = createLucideIcon("layout-grid", __iconNode13);
3851
+ var LayoutGrid = createLucideIcon("layout-grid", __iconNode12);
3583
3852
 
3584
3853
  // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/link-2.mjs
3585
- var __iconNode14 = [
3854
+ var __iconNode13 = [
3586
3855
  ["path", { d: "M9 17H7A5 5 0 0 1 7 7h2", key: "8i5ue5" }],
3587
3856
  ["path", { d: "M15 7h2a5 5 0 1 1 0 10h-2", key: "1b9ql8" }],
3588
3857
  ["line", { x1: "8", x2: "16", y1: "12", y2: "12", key: "1jonct" }]
3589
3858
  ];
3590
- var Link2 = createLucideIcon("link-2", __iconNode14);
3859
+ var Link2 = createLucideIcon("link-2", __iconNode13);
3591
3860
 
3592
3861
  // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/list-filter.mjs
3593
- var __iconNode15 = [
3862
+ var __iconNode14 = [
3594
3863
  ["path", { d: "M2 5h20", key: "1fs1ex" }],
3595
3864
  ["path", { d: "M6 12h12", key: "8npq4p" }],
3596
3865
  ["path", { d: "M9 19h6", key: "456am0" }]
3597
3866
  ];
3598
- var ListFilter = createLucideIcon("list-filter", __iconNode15);
3867
+ var ListFilter = createLucideIcon("list-filter", __iconNode14);
3599
3868
 
3600
3869
  // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/map.mjs
3601
- var __iconNode16 = [
3870
+ var __iconNode15 = [
3602
3871
  [
3603
3872
  "path",
3604
3873
  {
@@ -3609,27 +3878,27 @@ var __iconNode16 = [
3609
3878
  ["path", { d: "M15 5.764v15", key: "1pn4in" }],
3610
3879
  ["path", { d: "M9 3.236v15", key: "1uimfh" }]
3611
3880
  ];
3612
- var Map2 = createLucideIcon("map", __iconNode16);
3881
+ var Map2 = createLucideIcon("map", __iconNode15);
3613
3882
 
3614
3883
  // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/maximize-2.mjs
3615
- var __iconNode17 = [
3884
+ var __iconNode16 = [
3616
3885
  ["path", { d: "M15 3h6v6", key: "1q9fwt" }],
3617
3886
  ["path", { d: "m21 3-7 7", key: "1l2asr" }],
3618
3887
  ["path", { d: "m3 21 7-7", key: "tjx5ai" }],
3619
3888
  ["path", { d: "M9 21H3v-6", key: "wtvkvv" }]
3620
3889
  ];
3621
- var Maximize2 = createLucideIcon("maximize-2", __iconNode17);
3890
+ var Maximize2 = createLucideIcon("maximize-2", __iconNode16);
3622
3891
 
3623
3892
  // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/monitor.mjs
3624
- var __iconNode18 = [
3893
+ var __iconNode17 = [
3625
3894
  ["rect", { width: "20", height: "14", x: "2", y: "3", rx: "2", key: "48i651" }],
3626
3895
  ["line", { x1: "8", x2: "16", y1: "21", y2: "21", key: "1svkeh" }],
3627
3896
  ["line", { x1: "12", x2: "12", y1: "17", y2: "21", key: "vw1qmm" }]
3628
3897
  ];
3629
- var Monitor = createLucideIcon("monitor", __iconNode18);
3898
+ var Monitor = createLucideIcon("monitor", __iconNode17);
3630
3899
 
3631
3900
  // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/moon.mjs
3632
- var __iconNode19 = [
3901
+ var __iconNode18 = [
3633
3902
  [
3634
3903
  "path",
3635
3904
  {
@@ -3638,10 +3907,10 @@ var __iconNode19 = [
3638
3907
  }
3639
3908
  ]
3640
3909
  ];
3641
- var Moon = createLucideIcon("moon", __iconNode19);
3910
+ var Moon = createLucideIcon("moon", __iconNode18);
3642
3911
 
3643
3912
  // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/pencil.mjs
3644
- var __iconNode20 = [
3913
+ var __iconNode19 = [
3645
3914
  [
3646
3915
  "path",
3647
3916
  {
@@ -3651,25 +3920,25 @@ var __iconNode20 = [
3651
3920
  ],
3652
3921
  ["path", { d: "m15 5 4 4", key: "1mk7zo" }]
3653
3922
  ];
3654
- var Pencil = createLucideIcon("pencil", __iconNode20);
3923
+ var Pencil = createLucideIcon("pencil", __iconNode19);
3655
3924
 
3656
3925
  // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/rectangle-horizontal.mjs
3657
- var __iconNode21 = [
3926
+ var __iconNode20 = [
3658
3927
  ["rect", { width: "20", height: "12", x: "2", y: "6", rx: "2", key: "9lu3g6" }]
3659
3928
  ];
3660
- var RectangleHorizontal = createLucideIcon("rectangle-horizontal", __iconNode21);
3929
+ var RectangleHorizontal = createLucideIcon("rectangle-horizontal", __iconNode20);
3661
3930
 
3662
3931
  // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/refresh-cw.mjs
3663
- var __iconNode22 = [
3932
+ var __iconNode21 = [
3664
3933
  ["path", { d: "M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8", key: "v9h5vc" }],
3665
3934
  ["path", { d: "M21 3v5h-5", key: "1q7to0" }],
3666
3935
  ["path", { d: "M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16", key: "3uifl3" }],
3667
3936
  ["path", { d: "M8 16H3v5", key: "1cv678" }]
3668
3937
  ];
3669
- var RefreshCw = createLucideIcon("refresh-cw", __iconNode22);
3938
+ var RefreshCw = createLucideIcon("refresh-cw", __iconNode21);
3670
3939
 
3671
3940
  // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/ruler.mjs
3672
- var __iconNode23 = [
3941
+ var __iconNode22 = [
3673
3942
  [
3674
3943
  "path",
3675
3944
  {
@@ -3682,26 +3951,26 @@ var __iconNode23 = [
3682
3951
  ["path", { d: "m8.5 6.5 2-2", key: "vc6u1g" }],
3683
3952
  ["path", { d: "m17.5 15.5 2-2", key: "wo5hmg" }]
3684
3953
  ];
3685
- var Ruler = createLucideIcon("ruler", __iconNode23);
3954
+ var Ruler = createLucideIcon("ruler", __iconNode22);
3686
3955
 
3687
3956
  // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/scan.mjs
3688
- var __iconNode24 = [
3957
+ var __iconNode23 = [
3689
3958
  ["path", { d: "M3 7V5a2 2 0 0 1 2-2h2", key: "aa7l1z" }],
3690
3959
  ["path", { d: "M17 3h2a2 2 0 0 1 2 2v2", key: "4qcy5o" }],
3691
3960
  ["path", { d: "M21 17v2a2 2 0 0 1-2 2h-2", key: "6vwrx8" }],
3692
3961
  ["path", { d: "M7 21H5a2 2 0 0 1-2-2v-2", key: "ioqczr" }]
3693
3962
  ];
3694
- var Scan = createLucideIcon("scan", __iconNode24);
3963
+ var Scan = createLucideIcon("scan", __iconNode23);
3695
3964
 
3696
3965
  // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/search.mjs
3697
- var __iconNode25 = [
3966
+ var __iconNode24 = [
3698
3967
  ["path", { d: "m21 21-4.34-4.34", key: "14j7rj" }],
3699
3968
  ["circle", { cx: "11", cy: "11", r: "8", key: "4ej97u" }]
3700
3969
  ];
3701
- var Search = createLucideIcon("search", __iconNode25);
3970
+ var Search = createLucideIcon("search", __iconNode24);
3702
3971
 
3703
3972
  // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/settings.mjs
3704
- var __iconNode26 = [
3973
+ var __iconNode25 = [
3705
3974
  [
3706
3975
  "path",
3707
3976
  {
@@ -3711,14 +3980,31 @@ var __iconNode26 = [
3711
3980
  ],
3712
3981
  ["circle", { cx: "12", cy: "12", r: "3", key: "1v7zrd" }]
3713
3982
  ];
3714
- var Settings = createLucideIcon("settings", __iconNode26);
3983
+ var Settings = createLucideIcon("settings", __iconNode25);
3715
3984
 
3716
3985
  // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/smartphone.mjs
3717
- var __iconNode27 = [
3986
+ var __iconNode26 = [
3718
3987
  ["rect", { width: "14", height: "20", x: "5", y: "2", rx: "2", ry: "2", key: "1yt0o3" }],
3719
3988
  ["path", { d: "M12 18h.01", key: "mhygvu" }]
3720
3989
  ];
3721
- var Smartphone = createLucideIcon("smartphone", __iconNode27);
3990
+ var Smartphone = createLucideIcon("smartphone", __iconNode26);
3991
+
3992
+ // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/square-dashed.mjs
3993
+ var __iconNode27 = [
3994
+ ["path", { d: "M5 3a2 2 0 0 0-2 2", key: "y57alp" }],
3995
+ ["path", { d: "M19 3a2 2 0 0 1 2 2", key: "18rm91" }],
3996
+ ["path", { d: "M21 19a2 2 0 0 1-2 2", key: "1j7049" }],
3997
+ ["path", { d: "M5 21a2 2 0 0 1-2-2", key: "sbafld" }],
3998
+ ["path", { d: "M9 3h1", key: "1yesri" }],
3999
+ ["path", { d: "M9 21h1", key: "15o7lz" }],
4000
+ ["path", { d: "M14 3h1", key: "1ec4yj" }],
4001
+ ["path", { d: "M14 21h1", key: "v9vybs" }],
4002
+ ["path", { d: "M3 9v1", key: "1r0deq" }],
4003
+ ["path", { d: "M21 9v1", key: "mxsmne" }],
4004
+ ["path", { d: "M3 14v1", key: "vnatye" }],
4005
+ ["path", { d: "M21 14v1", key: "169vum" }]
4006
+ ];
4007
+ var SquareDashed = createLucideIcon("square-dashed", __iconNode27);
3722
4008
 
3723
4009
  // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/square-mouse-pointer.mjs
3724
4010
  var __iconNode28 = [
@@ -3760,27 +4046,36 @@ var __iconNode30 = [
3760
4046
  ];
3761
4047
  var Sun = createLucideIcon("sun", __iconNode30);
3762
4048
 
3763
- // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/upload.mjs
4049
+ // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/type.mjs
3764
4050
  var __iconNode31 = [
4051
+ ["path", { d: "M12 4v16", key: "1654pz" }],
4052
+ ["path", { d: "M4 7V5a1 1 0 0 1 1-1h14a1 1 0 0 1 1 1v2", key: "e0r10z" }],
4053
+ ["path", { d: "M9 20h6", key: "s66wpe" }]
4054
+ ];
4055
+ var Type = createLucideIcon("type", __iconNode31);
4056
+
4057
+ // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/upload.mjs
4058
+ var __iconNode32 = [
3765
4059
  ["path", { d: "M12 3v12", key: "1x0j5s" }],
3766
4060
  ["path", { d: "m17 8-5-5-5 5", key: "7q97r8" }],
3767
4061
  ["path", { d: "M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4", key: "ih7n3h" }]
3768
4062
  ];
3769
- var Upload = createLucideIcon("upload", __iconNode31);
4063
+ var Upload = createLucideIcon("upload", __iconNode32);
3770
4064
 
3771
- // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/user-round.mjs
3772
- var __iconNode32 = [
3773
- ["circle", { cx: "12", cy: "8", r: "5", key: "1hypcn" }],
3774
- ["path", { d: "M20 21a8 8 0 0 0-16 0", key: "rfgkzh" }]
4065
+ // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/workflow.mjs
4066
+ var __iconNode33 = [
4067
+ ["rect", { width: "8", height: "8", x: "3", y: "3", rx: "2", key: "by2w9f" }],
4068
+ ["path", { d: "M7 11v4a2 2 0 0 0 2 2h4", key: "xkn7yn" }],
4069
+ ["rect", { width: "8", height: "8", x: "13", y: "13", rx: "2", key: "1cgmvn" }]
3775
4070
  ];
3776
- var UserRound = createLucideIcon("user-round", __iconNode32);
4071
+ var Workflow = createLucideIcon("workflow", __iconNode33);
3777
4072
 
3778
4073
  // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/x.mjs
3779
- var __iconNode33 = [
4074
+ var __iconNode34 = [
3780
4075
  ["path", { d: "M18 6 6 18", key: "1bl5f8" }],
3781
4076
  ["path", { d: "m6 6 12 12", key: "d8bk6v" }]
3782
4077
  ];
3783
- var X = createLucideIcon("x", __iconNode33);
4078
+ var X = createLucideIcon("x", __iconNode34);
3784
4079
 
3785
4080
  // src/core/geometry.ts
3786
4081
  function rectanglesIntersect(a, b) {
@@ -3987,6 +4282,11 @@ var FIGMA_OVERLAY_UNAVAILABLE_MESSAGE = "\uD53C\uADF8\uB9C8 \uC624\uBC84\uB808\u
3987
4282
  var FIGMA_TOKEN_STORAGE_KEY = "figma-token";
3988
4283
  var REVIEW_USER_ID_STORAGE_KEY = "user-id";
3989
4284
  var REVIEW_THEME_STORAGE_KEY = "df-review-theme";
4285
+ var REVIEW_SIDE_PANEL_STORAGE_KEY = "df-review-side-panel";
4286
+ var REVIEW_SIDE_PANEL_VISIBLE_STORAGE_KEY = "df-review-side-panel-visible";
4287
+ var REVIEW_SOURCE_TREE_FILTER_STORAGE_KEY = "df-review-source-tree-filter";
4288
+ var REVIEW_SOURCE_TREE_META_STORAGE_KEY = "df-review-source-tree-meta-visibility";
4289
+ var REVIEW_QA_STATUS_FILTER_STORAGE_KEY = "df-review-qa-status-filter";
3990
4290
  var DEFAULT_REVIEW_THEME = "dark";
3991
4291
  var FIGMA_TOKEN_GUIDE_ID = "df-review-figma-token-guide";
3992
4292
  var DEFAULT_INITIAL_REVIEW_PROMPT = "You are fixing QA issues collected with df-web-review-kit. Use the copied QA prompt as the source of truth for page, viewport, selector, DOM metadata, coordinates, and user comment. Make the smallest code or CSS change that fixes the issue, preserve unrelated behavior, then verify the target viewport again.";
@@ -4412,7 +4712,35 @@ var PromptModal = ({
4412
4712
  };
4413
4713
 
4414
4714
  // src/react-shell/settings.ts
4715
+ var DEFAULT_SOURCE_TREE_META_VISIBILITY = {
4716
+ box: true,
4717
+ font: true,
4718
+ media: true,
4719
+ className: false
4720
+ };
4721
+ var REVIEW_QA_STATUS_FILTER_VALUES = /* @__PURE__ */ new Set([
4722
+ "all",
4723
+ "todo",
4724
+ "doing",
4725
+ "review",
4726
+ "hold",
4727
+ "done"
4728
+ ]);
4415
4729
  var normalizeReviewTheme = (value) => value === "light" || value === "system" || value === "dark" ? value : DEFAULT_REVIEW_THEME;
4730
+ var normalizeStoredReviewSidePanel = (value) => value === "source" ? "source" : "qa";
4731
+ var normalizeStoredReviewQaStatusFilter = (value) => value && REVIEW_QA_STATUS_FILTER_VALUES.has(value) ? value : "all";
4732
+ var normalizeStoredSourceTreeMetaVisibility = (value) => {
4733
+ if (!value || typeof value !== "object") {
4734
+ return DEFAULT_SOURCE_TREE_META_VISIBILITY;
4735
+ }
4736
+ const metaVisibility = value;
4737
+ return {
4738
+ box: typeof metaVisibility.box === "boolean" ? metaVisibility.box : DEFAULT_SOURCE_TREE_META_VISIBILITY.box,
4739
+ font: typeof metaVisibility.font === "boolean" ? metaVisibility.font : DEFAULT_SOURCE_TREE_META_VISIBILITY.font,
4740
+ media: typeof metaVisibility.media === "boolean" ? metaVisibility.media : DEFAULT_SOURCE_TREE_META_VISIBILITY.media,
4741
+ className: typeof metaVisibility.className === "boolean" ? metaVisibility.className : DEFAULT_SOURCE_TREE_META_VISIBILITY.className
4742
+ };
4743
+ };
4416
4744
  var getStoredFigmaToken = () => {
4417
4745
  if (typeof window === "undefined") return "";
4418
4746
  try {
@@ -4475,6 +4803,118 @@ var writeStoredReviewTheme = (theme) => {
4475
4803
  return;
4476
4804
  }
4477
4805
  };
4806
+ var getStoredReviewSidePanel = () => {
4807
+ if (typeof window === "undefined") return "qa";
4808
+ try {
4809
+ return normalizeStoredReviewSidePanel(
4810
+ window.localStorage.getItem(REVIEW_SIDE_PANEL_STORAGE_KEY)
4811
+ );
4812
+ } catch {
4813
+ return "qa";
4814
+ }
4815
+ };
4816
+ var writeStoredReviewSidePanel = (sidePanel) => {
4817
+ if (typeof window === "undefined") return;
4818
+ try {
4819
+ window.localStorage.setItem(
4820
+ REVIEW_SIDE_PANEL_STORAGE_KEY,
4821
+ normalizeStoredReviewSidePanel(sidePanel)
4822
+ );
4823
+ } catch {
4824
+ return;
4825
+ }
4826
+ };
4827
+ var getStoredReviewSidePanelVisible = () => {
4828
+ if (typeof window === "undefined") return true;
4829
+ try {
4830
+ const value = window.localStorage.getItem(
4831
+ REVIEW_SIDE_PANEL_VISIBLE_STORAGE_KEY
4832
+ );
4833
+ return value === null ? true : value === "true";
4834
+ } catch {
4835
+ return true;
4836
+ }
4837
+ };
4838
+ var writeStoredReviewSidePanelVisible = (isVisible) => {
4839
+ if (typeof window === "undefined") return;
4840
+ try {
4841
+ window.localStorage.setItem(
4842
+ REVIEW_SIDE_PANEL_VISIBLE_STORAGE_KEY,
4843
+ isVisible ? "true" : "false"
4844
+ );
4845
+ } catch {
4846
+ return;
4847
+ }
4848
+ };
4849
+ var getStoredReviewQaStatusFilter = () => {
4850
+ if (typeof window === "undefined") return "all";
4851
+ try {
4852
+ return normalizeStoredReviewQaStatusFilter(
4853
+ window.localStorage.getItem(REVIEW_QA_STATUS_FILTER_STORAGE_KEY)
4854
+ );
4855
+ } catch {
4856
+ return "all";
4857
+ }
4858
+ };
4859
+ var writeStoredReviewQaStatusFilter = (filter) => {
4860
+ if (typeof window === "undefined") return;
4861
+ try {
4862
+ const normalizedFilter = normalizeStoredReviewQaStatusFilter(filter);
4863
+ if (normalizedFilter === "all") {
4864
+ window.localStorage.removeItem(REVIEW_QA_STATUS_FILTER_STORAGE_KEY);
4865
+ } else {
4866
+ window.localStorage.setItem(
4867
+ REVIEW_QA_STATUS_FILTER_STORAGE_KEY,
4868
+ normalizedFilter
4869
+ );
4870
+ }
4871
+ } catch {
4872
+ return;
4873
+ }
4874
+ };
4875
+ var getStoredSourceTreeFilter = () => {
4876
+ if (typeof window === "undefined") return "";
4877
+ try {
4878
+ return window.localStorage.getItem(REVIEW_SOURCE_TREE_FILTER_STORAGE_KEY) ?? "";
4879
+ } catch {
4880
+ return "";
4881
+ }
4882
+ };
4883
+ var writeStoredSourceTreeFilter = (filter) => {
4884
+ if (typeof window === "undefined") return;
4885
+ try {
4886
+ if (filter) {
4887
+ window.localStorage.setItem(REVIEW_SOURCE_TREE_FILTER_STORAGE_KEY, filter);
4888
+ } else {
4889
+ window.localStorage.removeItem(REVIEW_SOURCE_TREE_FILTER_STORAGE_KEY);
4890
+ }
4891
+ } catch {
4892
+ return;
4893
+ }
4894
+ };
4895
+ var getStoredSourceTreeMetaVisibility = () => {
4896
+ if (typeof window === "undefined") return DEFAULT_SOURCE_TREE_META_VISIBILITY;
4897
+ try {
4898
+ const value = window.localStorage.getItem(
4899
+ REVIEW_SOURCE_TREE_META_STORAGE_KEY
4900
+ );
4901
+ if (!value) return DEFAULT_SOURCE_TREE_META_VISIBILITY;
4902
+ return normalizeStoredSourceTreeMetaVisibility(JSON.parse(value));
4903
+ } catch {
4904
+ return DEFAULT_SOURCE_TREE_META_VISIBILITY;
4905
+ }
4906
+ };
4907
+ var writeStoredSourceTreeMetaVisibility = (metaVisibility) => {
4908
+ if (typeof window === "undefined") return;
4909
+ try {
4910
+ window.localStorage.setItem(
4911
+ REVIEW_SOURCE_TREE_META_STORAGE_KEY,
4912
+ JSON.stringify(normalizeStoredSourceTreeMetaVisibility(metaVisibility))
4913
+ );
4914
+ } catch {
4915
+ return;
4916
+ }
4917
+ };
4478
4918
  var getSystemReviewTheme = () => {
4479
4919
  if (typeof window === "undefined" || !window.matchMedia) return "dark";
4480
4920
  return window.matchMedia("(prefers-color-scheme: light)").matches ? "light" : "dark";
@@ -5556,6 +5996,7 @@ var QaItemCard = ({
5556
5996
  onChangeItemStatus,
5557
5997
  onClearSelectedItem,
5558
5998
  onRemoveItem,
5999
+ onCopyItemLabel,
5559
6000
  onCopyItemLink,
5560
6001
  onCopyItemPrompt,
5561
6002
  onEditItem,
@@ -5571,8 +6012,10 @@ var QaItemCard = ({
5571
6012
  const itemComment = item.comment.trim() || getItemTitle(item);
5572
6013
  const itemAuthor = item.createdBy?.trim();
5573
6014
  const promptCopyKey = `qa:${item.id}`;
6015
+ const labelCopyKey = `label:${item.id}`;
5574
6016
  const linkCopyKey = `link:${item.id}`;
5575
6017
  const isPromptCopied = copiedPromptKey === promptCopyKey;
6018
+ const isLabelCopied = copiedPromptKey === labelCopyKey;
5576
6019
  const isLinkCopied = copiedPromptKey === linkCopyKey;
5577
6020
  const statusOptions = activeAdapterEntry.statusOptions;
5578
6021
  const isActive = item.id === selectedItemId;
@@ -5594,7 +6037,20 @@ var QaItemCard = ({
5594
6037
  /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "df-review-item-header", children: [
5595
6038
  /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "df-review-item-main", children: [
5596
6039
  /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("span", { className: "df-review-item-badges", children: [
5597
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "df-review-item-id", children: numberedItem.displayLabel }),
6040
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
6041
+ "button",
6042
+ {
6043
+ "aria-label": isLabelCopied ? "Copied QA number" : "Copy QA number",
6044
+ className: `df-review-item-id${isLabelCopied ? " is-copied" : ""}`,
6045
+ title: isLabelCopied ? "Copied QA number" : "Copy QA number",
6046
+ type: "button",
6047
+ onClick: (event) => {
6048
+ event.stopPropagation();
6049
+ onCopyItemLabel(numberedItem);
6050
+ },
6051
+ children: numberedItem.displayLabel
6052
+ }
6053
+ ),
5598
6054
  /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
5599
6055
  "span",
5600
6056
  {
@@ -5735,7 +6191,36 @@ var QaPanelHeader = ({
5735
6191
  }) => {
5736
6192
  const statusFilterOptions = getStatusFilterOptions(statusOptions);
5737
6193
  const hasActiveFilter = qaFilter !== "all" || qaStatusFilter !== "all";
6194
+ const displayLabel = getQaSourceDisplayLabel(label);
5738
6195
  return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "df-review-list-header", children: [
6196
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "df-review-list-title", children: [
6197
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("span", { className: "df-review-list-meta", children: [
6198
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { children: isAllQaVisible ? `${displayLabel} QA \xB7 All pages` : `${displayLabel} QA` }),
6199
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
6200
+ "strong",
6201
+ {
6202
+ title: `${activeRemainingItemCount} remaining of ${activeItemCount}`,
6203
+ children: !hasActiveFilter ? `${activeRemainingItemCount}/${activeItemCount}` : `${filteredItemCount}/${activeItemCount}`
6204
+ }
6205
+ )
6206
+ ] }),
6207
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "df-review-filter-tabs", "aria-label": "QA filters", children: REVIEW_QA_FILTERS.map((filter) => {
6208
+ const count = qaFilterCounts.get(filter.key) ?? 0;
6209
+ const isActive = qaFilter === filter.key;
6210
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
6211
+ "button",
6212
+ {
6213
+ "aria-label": `${filter.label} QA (${count})`,
6214
+ "aria-pressed": isActive,
6215
+ className: `df-review-filter-tab${isActive ? " is-active" : ""}`,
6216
+ type: "button",
6217
+ onClick: () => onQaFilterChange(filter.key),
6218
+ children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "df-review-filter-icon", children: filter.scope ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(ReviewScopeIcon, { scope: filter.scope }) : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(ListFilter, { "aria-hidden": "true" }) })
6219
+ },
6220
+ filter.key
6221
+ );
6222
+ }) })
6223
+ ] }),
5739
6224
  /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "df-review-list-toolbar", children: [
5740
6225
  /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "df-review-list-controls", children: [
5741
6226
  showSourceSelect && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
@@ -5774,37 +6259,12 @@ var QaPanelHeader = ({
5774
6259
  ]
5775
6260
  }
5776
6261
  )
5777
- ] }),
5778
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "df-review-list-title", children: [
5779
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("span", { className: "df-review-list-meta", children: [
5780
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { children: isAllQaVisible ? `${label} QA \xB7 All pages` : `${label} QA` }),
5781
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
5782
- "strong",
5783
- {
5784
- title: `${activeRemainingItemCount} remaining of ${activeItemCount}`,
5785
- children: !hasActiveFilter ? `${activeRemainingItemCount}/${activeItemCount}` : `${filteredItemCount}/${activeItemCount}`
5786
- }
5787
- )
5788
- ] }),
5789
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "df-review-filter-tabs", "aria-label": "QA filters", children: REVIEW_QA_FILTERS.map((filter) => {
5790
- const count = qaFilterCounts.get(filter.key) ?? 0;
5791
- const isActive = qaFilter === filter.key;
5792
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
5793
- "button",
5794
- {
5795
- "aria-label": `${filter.label} QA (${count})`,
5796
- "aria-pressed": isActive,
5797
- className: `df-review-filter-tab${isActive ? " is-active" : ""}`,
5798
- type: "button",
5799
- onClick: () => onQaFilterChange(filter.key),
5800
- children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "df-review-filter-icon", children: filter.scope ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(ReviewScopeIcon, { scope: filter.scope }) : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(ListFilter, { "aria-hidden": "true" }) })
5801
- },
5802
- filter.key
5803
- );
5804
- }) })
5805
6262
  ] })
5806
6263
  ] });
5807
6264
  };
6265
+ function getQaSourceDisplayLabel(label) {
6266
+ return label === "local" ? "Local" : label;
6267
+ }
5808
6268
  function getStatusFilterOptions(statusOptions) {
5809
6269
  const seen = /* @__PURE__ */ new Set();
5810
6270
  return statusOptions.flatMap((statusOption) => {
@@ -5844,6 +6304,7 @@ var ReviewQaPanel = ({
5844
6304
  onChangeItemStatus,
5845
6305
  onClearSelectedItem,
5846
6306
  onChangeReviewSource,
6307
+ onCopyItemLabel,
5847
6308
  onCopyItemLink,
5848
6309
  onCopyItemPrompt,
5849
6310
  onEditItem,
@@ -5856,78 +6317,104 @@ var ReviewQaPanel = ({
5856
6317
  onToggleItemOverlayVisibility
5857
6318
  }) => {
5858
6319
  const emptyMessage = isAllQaVisible ? `No ${activeAdapterEntry.label} QA.` : isRemoteSource ? `No ${activeAdapterEntry.label} QA on this page.` : "No QA on this page.";
5859
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("aside", { className: "df-review-qa-panel", "aria-hidden": !isListVisible, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "df-review-panel-body", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("section", { className: "df-review-item-list", children: [
5860
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
5861
- QaPanelHeader,
5862
- {
5863
- activeItemCount: activeItems.length,
5864
- activeRemainingItemCount,
5865
- filteredItemCount: filteredNumberedActiveItems.length,
5866
- isAllQaVisible,
5867
- label: activeAdapterEntry.label,
5868
- qaFilter,
5869
- qaFilterCounts,
5870
- qaStatusFilter,
5871
- qaStatusFilterCounts,
5872
- showSourceSelect,
5873
- source,
5874
- sourceEntries,
5875
- statusOptions: activeAdapterEntry.statusOptions,
5876
- onChangeReviewSource,
5877
- onQaFilterChange,
5878
- onQaStatusFilterChange,
5879
- onRefreshReviewData
5880
- }
5881
- ),
5882
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
5883
- "div",
5884
- {
5885
- className: "df-review-list-scroll",
5886
- onClick: (event) => {
5887
- if (event.target === event.currentTarget) {
5888
- onClearSelectedItem();
5889
- }
5890
- },
5891
- children: [
5892
- activeItems.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { className: "df-review-empty", children: emptyMessage }),
5893
- activeItems.length > 0 && filteredNumberedActiveItems.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { className: "df-review-empty", children: "No QA in this filter." }),
5894
- filteredNumberedActiveItems.map((numberedItem) => {
5895
- const { item } = numberedItem;
5896
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
5897
- QaItemCard,
5898
- {
5899
- activeAdapterEntry,
5900
- currentPresetScope,
5901
- getItemPresetScope,
5902
- isOverlayVisible: !hiddenOverlayItemIds.has(item.id),
5903
- isRemoteSource,
5904
- numberedItem,
5905
- remoteAdapterEntry,
5906
- copiedPromptKey,
5907
- selectedItemId,
5908
- onChangeItemStatus,
5909
- onClearSelectedItem,
5910
- onCopyItemLink,
5911
- onCopyItemPrompt,
5912
- onEditItem,
5913
- onRemoveItem,
5914
- onRestoreReviewItem,
5915
- onSubmitItem,
5916
- onToggleItemOverlayVisibility
5917
- },
5918
- item.id
5919
- );
5920
- })
5921
- ]
5922
- }
5923
- )
5924
- ] }) }) });
6320
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("aside", { className: "df-review-qa-panel", "aria-hidden": !isListVisible, children: [
6321
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "df-review-panel-body", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("section", { className: "df-review-item-list", children: [
6322
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
6323
+ QaPanelHeader,
6324
+ {
6325
+ activeItemCount: activeItems.length,
6326
+ activeRemainingItemCount,
6327
+ filteredItemCount: filteredNumberedActiveItems.length,
6328
+ isAllQaVisible,
6329
+ label: activeAdapterEntry.label,
6330
+ qaFilter,
6331
+ qaFilterCounts,
6332
+ qaStatusFilter,
6333
+ qaStatusFilterCounts,
6334
+ showSourceSelect,
6335
+ source,
6336
+ sourceEntries,
6337
+ statusOptions: activeAdapterEntry.statusOptions,
6338
+ onChangeReviewSource,
6339
+ onQaFilterChange,
6340
+ onQaStatusFilterChange,
6341
+ onRefreshReviewData
6342
+ }
6343
+ ),
6344
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
6345
+ "div",
6346
+ {
6347
+ className: "df-review-list-scroll",
6348
+ onClick: (event) => {
6349
+ if (event.target === event.currentTarget) {
6350
+ onClearSelectedItem();
6351
+ }
6352
+ },
6353
+ children: [
6354
+ activeItems.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { className: "df-review-empty", children: emptyMessage }),
6355
+ activeItems.length > 0 && filteredNumberedActiveItems.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { className: "df-review-empty", children: "No QA in this filter." }),
6356
+ filteredNumberedActiveItems.map((numberedItem) => {
6357
+ const { item } = numberedItem;
6358
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
6359
+ QaItemCard,
6360
+ {
6361
+ activeAdapterEntry,
6362
+ currentPresetScope,
6363
+ getItemPresetScope,
6364
+ isOverlayVisible: !hiddenOverlayItemIds.has(item.id),
6365
+ isRemoteSource,
6366
+ numberedItem,
6367
+ remoteAdapterEntry,
6368
+ copiedPromptKey,
6369
+ selectedItemId,
6370
+ onChangeItemStatus,
6371
+ onClearSelectedItem,
6372
+ onCopyItemLabel,
6373
+ onCopyItemLink,
6374
+ onCopyItemPrompt,
6375
+ onEditItem,
6376
+ onRemoveItem,
6377
+ onRestoreReviewItem,
6378
+ onSubmitItem,
6379
+ onToggleItemOverlayVisibility
6380
+ },
6381
+ item.id
6382
+ );
6383
+ })
6384
+ ]
6385
+ }
6386
+ )
6387
+ ] }) }),
6388
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "df-review-qa-draft-host" })
6389
+ ] });
5925
6390
  };
5926
6391
 
5927
6392
  // src/react-shell/presence/overlay.tsx
5928
6393
  var import_react6 = require("react");
5929
6394
  var import_jsx_runtime11 = require("react/jsx-runtime");
5930
6395
  var getPresenceName = (user) => user.displayName || user.userId;
6396
+ var PresenceUserIcon = () => /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("svg", { "aria-hidden": "true", viewBox: "0 0 30 30", children: [
6397
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
6398
+ "circle",
6399
+ {
6400
+ cx: "15",
6401
+ cy: "15",
6402
+ r: "12.5",
6403
+ fill: "none",
6404
+ stroke: "currentColor",
6405
+ strokeWidth: "2.6"
6406
+ }
6407
+ ),
6408
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("circle", { cx: "15", cy: "10.5", r: "3.4", fill: "currentColor", stroke: "none" }),
6409
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
6410
+ "path",
6411
+ {
6412
+ d: "M7.8 22.1c.9-4.1 3.4-6.1 7.2-6.1s6.3 2 7.2 6.1c-1.7 1.5-4.1 2.4-7.2 2.4s-5.5-.9-7.2-2.4z",
6413
+ fill: "currentColor",
6414
+ stroke: "none"
6415
+ }
6416
+ )
6417
+ ] });
5931
6418
  var PresenceOverlay = ({
5932
6419
  presenceSessionId,
5933
6420
  users
@@ -5949,7 +6436,7 @@ var PresenceOverlay = ({
5949
6436
  type: "button",
5950
6437
  onClick: () => setIsExpanded((current) => !current),
5951
6438
  children: [
5952
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(UserRound, { "aria-hidden": "true" }),
6439
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(PresenceUserIcon, {}),
5953
6440
  /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "df-review-presence-badge", children: users.length })
5954
6441
  ]
5955
6442
  }
@@ -5963,7 +6450,7 @@ var PresenceOverlay = ({
5963
6450
  "--df-review-presence-color": user.color
5964
6451
  },
5965
6452
  title: getPresenceName(user),
5966
- children: getPresenceName(user)
6453
+ children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { children: getPresenceName(user) })
5967
6454
  },
5968
6455
  user.sessionId
5969
6456
  )) })
@@ -6031,7 +6518,7 @@ var getSectionOutline = (root, options) => {
6031
6518
  if (source?.file) {
6032
6519
  addSourceFileCompareKey(seen, getOutlineSourceKey(source));
6033
6520
  }
6034
- return {
6521
+ return createSectionOutlineEntry({
6035
6522
  id: `${label}-${index}`,
6036
6523
  label,
6037
6524
  depth: 1,
@@ -6046,7 +6533,7 @@ var getSectionOutline = (root, options) => {
6046
6533
  seen,
6047
6534
  options
6048
6535
  )
6049
- };
6536
+ });
6050
6537
  });
6051
6538
  };
6052
6539
  function getSectionOutlineRoots(root, options) {
@@ -6076,7 +6563,7 @@ function getSectionOutlineChildren(parent, depth, maxDepth, seen, options) {
6076
6563
  if (source?.file && isNewSource) {
6077
6564
  const childSeen = new Set(seen);
6078
6565
  addSourceFileCompareKey(childSeen, sourceKey);
6079
- entries.push({
6566
+ entries.push(createSectionOutlineEntry({
6080
6567
  id: `${sourceKey}-${getElementOutlinePath(child)}-${entries.length}`,
6081
6568
  label,
6082
6569
  depth,
@@ -6091,7 +6578,7 @@ function getSectionOutlineChildren(parent, depth, maxDepth, seen, options) {
6091
6578
  childSeen,
6092
6579
  options
6093
6580
  )
6094
- });
6581
+ }));
6095
6582
  continue;
6096
6583
  }
6097
6584
  entries.push(
@@ -6109,6 +6596,114 @@ function getElementOutlinePath(element) {
6109
6596
  }
6110
6597
  return indices.join("-");
6111
6598
  }
6599
+ function createSectionOutlineEntry(entry) {
6600
+ return {
6601
+ ...entry,
6602
+ metadata: getSectionOutlineMetadata(entry.element, entry.label, entry.source)
6603
+ };
6604
+ }
6605
+ var truncateOutlineValue = (value, maxLength) => value.length > maxLength ? `${value.slice(0, maxLength - 1)}\u2026` : value;
6606
+ var normalizeOutlineValue = (value) => value?.replace(/\s+/g, " ").trim() ?? "";
6607
+ function getSectionOutlineMetadata(element, label, source) {
6608
+ const textElement = getPlacerTextElement(element, label, source?.file);
6609
+ return {
6610
+ rect: getSectionOutlineRect(element),
6611
+ textValue: textElement ? truncateOutlineValue(
6612
+ normalizeOutlineValue(textElement.textContent),
6613
+ 180
6614
+ ) : void 0,
6615
+ fontLabel: textElement ? getFontLabel(textElement) : void 0,
6616
+ mediaItems: getPlacerMediaItems(element, label, source?.file),
6617
+ classNames: getElementClassNames(element)
6618
+ };
6619
+ }
6620
+ function getSectionOutlineRect(element) {
6621
+ const rect = element.getBoundingClientRect();
6622
+ return {
6623
+ top: Math.round(rect.top),
6624
+ left: Math.round(rect.left),
6625
+ width: Math.round(rect.width),
6626
+ height: Math.round(rect.height)
6627
+ };
6628
+ }
6629
+ function getElementClassNames(element) {
6630
+ const classNames = Array.from(element.classList).filter(Boolean);
6631
+ return classNames.length > 0 ? classNames : void 0;
6632
+ }
6633
+ function getPlacerTextElement(element, label, file) {
6634
+ if (!isPlacerTextOutlineNode(label, file) && !element.hasAttribute("data-font")) {
6635
+ return null;
6636
+ }
6637
+ return element.hasAttribute("data-font") ? element : element.querySelector("[data-font]");
6638
+ }
6639
+ function isPlacerTextOutlineNode(label, file) {
6640
+ return `${label} ${file ?? ""}`.toLowerCase().includes("placertext");
6641
+ }
6642
+ function getFontLabel(element) {
6643
+ const dataFont = element.getAttribute("data-font");
6644
+ if (dataFont) {
6645
+ return dataFont.replace(/\bs\b/g, "sb").replace(/\bsemibold\b/g, "sb").replace(/\bregular\b/g, "r");
6646
+ }
6647
+ const style = window.getComputedStyle(element);
6648
+ return `${Math.round(parseFloat(style.fontSize))}px ${style.fontWeight}`;
6649
+ }
6650
+ function getPlacerMediaItems(element, label, file) {
6651
+ if (!isPlacerMediaOutlineNode(label, file)) return void 0;
6652
+ const mediaItems = [];
6653
+ const seen = /* @__PURE__ */ new Set();
6654
+ const addMediaItem = (target, type, url) => {
6655
+ const normalizedUrl = normalizeOutlineValue(url);
6656
+ if (!normalizedUrl) return;
6657
+ const variant = getPlacerMediaVariant(target, element);
6658
+ const key = `${variant}:${type}:${normalizedUrl}`;
6659
+ if (seen.has(key)) return;
6660
+ seen.add(key);
6661
+ mediaItems.push({ type, url: normalizedUrl, variant });
6662
+ };
6663
+ if (element instanceof HTMLVideoElement) {
6664
+ addMediaItem(element, "video", getVideoElementUrl(element));
6665
+ addMediaItem(element, "image", element.getAttribute("poster"));
6666
+ }
6667
+ if (element instanceof HTMLImageElement) {
6668
+ addMediaItem(element, "image", getMediaElementUrl(element));
6669
+ }
6670
+ if (element instanceof HTMLSourceElement) {
6671
+ addMediaItem(element, "video", getSourceElementUrl(element));
6672
+ }
6673
+ Array.from(element.querySelectorAll("video")).forEach((video) => {
6674
+ addMediaItem(video, "video", getVideoElementUrl(video));
6675
+ addMediaItem(video, "image", video.getAttribute("poster"));
6676
+ });
6677
+ Array.from(element.querySelectorAll("source")).forEach((source) => {
6678
+ addMediaItem(source, "video", getSourceElementUrl(source));
6679
+ });
6680
+ Array.from(element.querySelectorAll("img")).forEach((img) => {
6681
+ addMediaItem(img, "image", getMediaElementUrl(img));
6682
+ });
6683
+ return mediaItems.length > 0 ? mediaItems : void 0;
6684
+ }
6685
+ function isPlacerMediaOutlineNode(label, file) {
6686
+ return `${label} ${file ?? ""}`.toLowerCase().includes("placermedia");
6687
+ }
6688
+ function getPlacerMediaVariant(target, root) {
6689
+ let current = target;
6690
+ while (current) {
6691
+ if (current.classList.contains("d-block-pc")) return "desktop";
6692
+ if (current.classList.contains("d-block-m")) return "mobile";
6693
+ if (current === root) break;
6694
+ current = current.parentElement;
6695
+ }
6696
+ return "media";
6697
+ }
6698
+ function getVideoElementUrl(video) {
6699
+ return video.currentSrc || video.getAttribute("src") || video.querySelector("source")?.getAttribute("src") || video.getAttribute("poster") || video.src;
6700
+ }
6701
+ function getSourceElementUrl(source) {
6702
+ return source.getAttribute("src") || source.src;
6703
+ }
6704
+ function getMediaElementUrl(img) {
6705
+ return img.currentSrc || img.getAttribute("src") || img.src;
6706
+ }
6112
6707
  function getOutlineSourceKey(source) {
6113
6708
  return getSourceFileCompareKey(source.file);
6114
6709
  }
@@ -6726,7 +7321,7 @@ var getStoredOverlayState = (targetDocument, overlay) => {
6726
7321
  };
6727
7322
  var getTargetOverlayState = (targetDocument) => ({
6728
7323
  grid: Boolean(
6729
- targetDocument?.body.classList.contains("is-help") || targetDocument?.querySelector(".helper.onShow") || getStoredOverlayState(targetDocument, "grid")
7324
+ targetDocument?.body?.classList.contains("is-help") || targetDocument?.querySelector(".helper.onShow") || getStoredOverlayState(targetDocument, "grid")
6730
7325
  ),
6731
7326
  figma: Boolean(
6732
7327
  targetDocument?.querySelector(
@@ -6766,9 +7361,7 @@ var ReviewTopbar = ({
6766
7361
  onCopyCurrentUrl,
6767
7362
  onSizeChange,
6768
7363
  onToggleRuler,
6769
- onToggleTargetOverlay,
6770
- onOpenInitialPrompt,
6771
- onOpenSettings
7364
+ onToggleTargetOverlay
6772
7365
  }) => {
6773
7366
  const selectedPresetValue = getPresetSelectValue(size);
6774
7367
  const handlePresetSelectChange = (event) => {
@@ -6805,8 +7398,19 @@ var ReviewTopbar = ({
6805
7398
  onChange: (event) => onDraftTargetChange(event.target.value)
6806
7399
  }
6807
7400
  ),
6808
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("button", { type: "submit", children: "Load" }),
6809
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("button", { type: "button", onClick: onCopyCurrentUrl, children: copyLabel })
7401
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "df-review-address-actions", children: [
7402
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
7403
+ "button",
7404
+ {
7405
+ "aria-label": "Refresh target",
7406
+ className: "df-review-address-refresh",
7407
+ title: "Refresh target",
7408
+ type: "submit",
7409
+ children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(RefreshCw, { "aria-hidden": "true" })
7410
+ }
7411
+ ),
7412
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("button", { type: "button", onClick: onCopyCurrentUrl, children: copyLabel })
7413
+ ] })
6810
7414
  ]
6811
7415
  }
6812
7416
  ),
@@ -6872,100 +7476,21 @@ var ReviewTopbar = ({
6872
7476
  className: `df-review-overlay-button is-grid${targetOverlayState.grid ? " is-active" : ""}`,
6873
7477
  type: "button",
6874
7478
  onClick: () => onToggleTargetOverlay("grid"),
6875
- children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(LayoutGrid, { "aria-hidden": "true" })
6876
- }
6877
- ),
6878
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
6879
- "button",
6880
- {
6881
- "aria-disabled": !isFigmaOverlayAvailable,
6882
- "aria-label": isFigmaOverlayAvailable ? "Toggle Figma overlay" : FIGMA_OVERLAY_UNAVAILABLE_MESSAGE,
6883
- className: `df-review-overlay-button is-figma${targetOverlayState.figma ? " is-active" : ""}${isFigmaOverlayAvailable ? "" : " is-disabled"}`,
6884
- disabled: !isFigmaOverlayAvailable,
6885
- type: "button",
6886
- onClick: () => onToggleTargetOverlay("figma"),
6887
- children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(Image, { "aria-hidden": "true" })
6888
- }
6889
- ),
6890
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "df-review-tool-divider", "aria-hidden": "true", children: "|" }),
6891
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
6892
- "button",
6893
- {
6894
- "aria-label": "Open initial prompt",
6895
- className: "df-review-overlay-button is-prompt",
6896
- type: "button",
6897
- onClick: onOpenInitialPrompt,
6898
- children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(CircleQuestionMark, { "aria-hidden": "true" })
6899
- }
6900
- ),
6901
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
6902
- "button",
6903
- {
6904
- "aria-label": "Open settings",
6905
- className: "df-review-overlay-button is-settings",
6906
- type: "button",
6907
- onClick: onOpenSettings,
6908
- children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(Settings, { "aria-hidden": "true" })
6909
- }
6910
- )
6911
- ] }),
6912
- /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("details", { className: "df-review-overlays-menu", children: [
6913
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("summary", { "aria-label": "Open target tools", title: "Tools", children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(Ellipsis, { "aria-hidden": "true" }) }),
6914
- /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "df-review-overlays-popover", "aria-label": "Target tools", children: [
6915
- isRulerAvailable && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
6916
- "button",
6917
- {
6918
- "aria-label": "Toggle ruler",
6919
- className: `df-review-overlay-button is-ruler${isRulerVisible ? " is-active" : ""}`,
6920
- type: "button",
6921
- onClick: onToggleRuler,
6922
- children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(Ruler, { "aria-hidden": "true" })
6923
- }
6924
- ),
6925
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
6926
- "button",
6927
- {
6928
- "aria-label": "Toggle grid overlay",
6929
- className: `df-review-overlay-button is-grid${targetOverlayState.grid ? " is-active" : ""}`,
6930
- type: "button",
6931
- onClick: () => onToggleTargetOverlay("grid"),
6932
- children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(LayoutGrid, { "aria-hidden": "true" })
6933
- }
6934
- ),
6935
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
6936
- "button",
6937
- {
6938
- "aria-disabled": !isFigmaOverlayAvailable,
6939
- "aria-label": isFigmaOverlayAvailable ? "Toggle Figma overlay" : FIGMA_OVERLAY_UNAVAILABLE_MESSAGE,
6940
- className: `df-review-overlay-button is-figma${targetOverlayState.figma ? " is-active" : ""}${isFigmaOverlayAvailable ? "" : " is-disabled"}`,
6941
- disabled: !isFigmaOverlayAvailable,
6942
- type: "button",
6943
- onClick: () => onToggleTargetOverlay("figma"),
6944
- children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(Image, { "aria-hidden": "true" })
6945
- }
6946
- ),
6947
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "df-review-tool-divider", "aria-hidden": "true", children: "|" }),
6948
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
6949
- "button",
6950
- {
6951
- "aria-label": "Open initial prompt",
6952
- className: "df-review-overlay-button is-prompt",
6953
- type: "button",
6954
- onClick: onOpenInitialPrompt,
6955
- children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(CircleQuestionMark, { "aria-hidden": "true" })
6956
- }
6957
- ),
6958
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
6959
- "button",
6960
- {
6961
- "aria-label": "Open settings",
6962
- className: "df-review-overlay-button is-settings",
6963
- type: "button",
6964
- onClick: onOpenSettings,
6965
- children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(Settings, { "aria-hidden": "true" })
6966
- }
6967
- )
6968
- ] })
7479
+ children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(LayoutGrid, { "aria-hidden": "true" })
7480
+ }
7481
+ ),
7482
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
7483
+ "button",
7484
+ {
7485
+ "aria-disabled": !isFigmaOverlayAvailable,
7486
+ "aria-label": isFigmaOverlayAvailable ? "Toggle Figma overlay" : FIGMA_OVERLAY_UNAVAILABLE_MESSAGE,
7487
+ className: `df-review-overlay-button is-figma${targetOverlayState.figma ? " is-active" : ""}${isFigmaOverlayAvailable ? "" : " is-disabled"}`,
7488
+ disabled: !isFigmaOverlayAvailable,
7489
+ type: "button",
7490
+ onClick: () => onToggleTargetOverlay("figma"),
7491
+ children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(Image, { "aria-hidden": "true" })
7492
+ }
7493
+ )
6969
7494
  ] })
6970
7495
  ] })
6971
7496
  ] });
@@ -8214,6 +8739,14 @@ function createStyleElement() {
8214
8739
  cursor: default;
8215
8740
  }
8216
8741
 
8742
+ .dfwr-shell.is-docked-composer {
8743
+ position: relative;
8744
+ inset: auto;
8745
+ z-index: auto;
8746
+ padding: 0;
8747
+ pointer-events: auto;
8748
+ }
8749
+
8217
8750
  .dfwr-panel {
8218
8751
  position: fixed;
8219
8752
  right: 16px;
@@ -8714,6 +9247,20 @@ function createStyleElement() {
8714
9247
  border-color: rgba(99, 215, 199, 0.56);
8715
9248
  }
8716
9249
 
9250
+ .dfwr-shell.is-docked-composer .dfwr-note-popover.is-docked-composer,
9251
+ .dfwr-shell.is-docked-composer .dfwr-area-draft.is-docked-composer {
9252
+ position: relative;
9253
+ left: auto;
9254
+ right: auto;
9255
+ top: auto;
9256
+ z-index: auto;
9257
+ max-height: none;
9258
+ }
9259
+
9260
+ .dfwr-shell.is-docked-composer .dfwr-textarea {
9261
+ min-height: 184px;
9262
+ }
9263
+
8717
9264
  .dfwr-note-popover.is-dragging,
8718
9265
  .dfwr-area-draft.is-dragging {
8719
9266
  user-select: none;
@@ -8762,6 +9309,50 @@ function createStyleElement() {
8762
9309
  padding: 0;
8763
9310
  }
8764
9311
 
9312
+ .dfwr-actions.has-leading {
9313
+ align-items: center;
9314
+ justify-content: space-between;
9315
+ gap: 12px;
9316
+ }
9317
+
9318
+ .dfwr-actions-leading,
9319
+ .dfwr-actions-primary {
9320
+ display: flex;
9321
+ align-items: center;
9322
+ gap: 8px;
9323
+ min-width: 0;
9324
+ }
9325
+
9326
+ .dfwr-actions-primary {
9327
+ margin-left: auto;
9328
+ }
9329
+
9330
+ .dfwr-shell.is-docked-composer .dfwr-actions.has-leading {
9331
+ align-items: stretch;
9332
+ }
9333
+
9334
+ .dfwr-shell.is-docked-composer .dfwr-actions.has-leading .dfwr-button,
9335
+ .dfwr-shell.is-docked-composer .dfwr-actions.has-leading .dfwr-adjust-toggle {
9336
+ height: var(--df-review-control-height-md);
9337
+ min-height: var(--df-review-control-height-md);
9338
+ border-radius: var(--df-review-radius-sm);
9339
+ }
9340
+
9341
+ .dfwr-shell.is-docked-composer .dfwr-actions.has-leading .dfwr-button {
9342
+ min-width: 96px;
9343
+ padding: 0 12px;
9344
+ font-size: var(--df-review-font-size-sm);
9345
+ }
9346
+
9347
+ .dfwr-shell.is-docked-composer .dfwr-actions.has-leading .dfwr-adjust-toggle {
9348
+ width: var(--df-review-control-height-md);
9349
+ }
9350
+
9351
+ .dfwr-shell.is-docked-composer .dfwr-actions.has-leading .dfwr-adjust-toggle svg {
9352
+ width: 18px;
9353
+ height: 18px;
9354
+ }
9355
+
8765
9356
  .dfwr-note-actions {
8766
9357
  justify-content: flex-end;
8767
9358
  }
@@ -9086,10 +9677,12 @@ function createStyleElement() {
9086
9677
 
9087
9678
  @media (max-width: 520px) {
9088
9679
  .dfwr-panel {
9680
+ left: 8px;
9089
9681
  right: 8px;
9090
- top: 8px;
9091
- width: calc(100vw - 16px);
9092
- max-height: calc(100vh - 16px);
9682
+ top: auto;
9683
+ bottom: 8px;
9684
+ width: auto;
9685
+ max-height: min(70vh, calc(100vh - 16px));
9093
9686
  }
9094
9687
  }
9095
9688
  `;
@@ -9169,6 +9762,7 @@ var WebReviewKitView = class {
9169
9762
  }
9170
9763
  clearDraftPreview() {
9171
9764
  this.restoreDraftPreview();
9765
+ this.clearShellComposer();
9172
9766
  }
9173
9767
  render(shadow, hiddenItemsStyle) {
9174
9768
  const state = this.state;
@@ -9179,11 +9773,13 @@ var WebReviewKitView = class {
9179
9773
  shadow.append(createStyleElement());
9180
9774
  shadow.append(hiddenItemsStyle);
9181
9775
  const hasDismissableDraft = Boolean(state.noteDraft || state.areaDraft);
9776
+ const shouldDockComposer = this.config.options.ui?.panel === false && hasDismissableDraft && Boolean(this.getShellComposerHost());
9777
+ let dockedComposer;
9182
9778
  const shell = document.createElement("div");
9183
9779
  shell.className = [
9184
9780
  "dfwr-shell",
9185
9781
  state.isOpen ? "is-open" : "",
9186
- hasDismissableDraft ? "has-dismissible-draft" : ""
9782
+ hasDismissableDraft && !shouldDockComposer ? "has-dismissible-draft" : ""
9187
9783
  ].filter(Boolean).join(" ");
9188
9784
  shell.setAttribute("aria-hidden", state.isOpen ? "false" : "true");
9189
9785
  if (this.config.options.ui?.panel !== false) {
@@ -9200,13 +9796,21 @@ var WebReviewKitView = class {
9200
9796
  shell.append(panel);
9201
9797
  }
9202
9798
  shell.append(this.createMarkerLayer());
9203
- if (state.isOpen && hasDismissableDraft) {
9799
+ if (state.isOpen && hasDismissableDraft && !shouldDockComposer) {
9204
9800
  shell.append(this.createDraftCancelLayer());
9205
9801
  }
9206
9802
  if (state.isOpen && (state.mode === "note" || state.mode === "element")) {
9207
- shell.append(
9208
- state.noteDraft ? this.createNotePopover(state.noteDraft) : state.mode === "element" ? this.createElementLayer() : this.createNoteLayer()
9209
- );
9803
+ if (state.noteDraft) {
9804
+ const noteDraft = this.createNotePopover(state.noteDraft, {
9805
+ dockComposer: shouldDockComposer
9806
+ });
9807
+ shell.append(noteDraft.layer);
9808
+ dockedComposer = noteDraft.composer;
9809
+ } else {
9810
+ shell.append(
9811
+ state.mode === "element" ? this.createElementLayer() : this.createNoteLayer()
9812
+ );
9813
+ }
9210
9814
  }
9211
9815
  if (state.isOpen && state.mode === "area" && !state.areaDraft) {
9212
9816
  shell.append(this.createAreaLayer());
@@ -9215,32 +9819,73 @@ var WebReviewKitView = class {
9215
9819
  if (state.areaDraft.selection) {
9216
9820
  shell.append(this.createAreaDraftOverlay(state.areaDraft));
9217
9821
  }
9218
- shell.append(this.createAreaDraftPopover(state.areaDraft));
9822
+ const areaComposer = this.createAreaDraftPopover(state.areaDraft, {
9823
+ dockComposer: shouldDockComposer
9824
+ });
9825
+ if (shouldDockComposer) {
9826
+ dockedComposer = areaComposer;
9827
+ } else {
9828
+ shell.append(areaComposer);
9829
+ }
9219
9830
  }
9220
9831
  shadow.append(shell);
9832
+ this.renderShellComposer(dockedComposer);
9221
9833
  }
9222
9834
  get state() {
9223
9835
  return this.config.getState();
9224
9836
  }
9837
+ getShellComposerHost() {
9838
+ const environment = this.config.getEnvironment();
9839
+ if (this.config.options.ui?.panel !== false) return void 0;
9840
+ return environment?.composerHost ?? void 0;
9841
+ }
9842
+ renderShellComposer(composer) {
9843
+ const host = composer ? this.getShellComposerHost() : void 0;
9844
+ if (!host || !composer) {
9845
+ this.clearShellComposer();
9846
+ return;
9847
+ }
9848
+ if (this.shellComposerHost && this.shellComposerHost !== host) {
9849
+ this.clearShellComposer();
9850
+ }
9851
+ this.shellComposerHost = host;
9852
+ host.dataset.hasDraftComposer = "true";
9853
+ if (host.parentElement) {
9854
+ host.parentElement.dataset.hasDraftComposer = "true";
9855
+ }
9856
+ const shell = document.createElement("div");
9857
+ shell.className = "dfwr-shell is-open is-shell-draft is-docked-composer";
9858
+ shell.append(composer);
9859
+ host.replaceChildren(createStyleElement(), shell);
9860
+ }
9861
+ clearShellComposer() {
9862
+ const host = this.shellComposerHost;
9863
+ host?.replaceChildren();
9864
+ if (host) {
9865
+ delete host.dataset.hasDraftComposer;
9866
+ delete host.parentElement?.dataset.hasDraftComposer;
9867
+ }
9868
+ this.shellComposerHost = void 0;
9869
+ }
9225
9870
  createDraftCancelLayer() {
9226
9871
  const layer = document.createElement("div");
9227
9872
  layer.className = "dfwr-draft-cancel-layer";
9228
9873
  layer.setAttribute("aria-hidden", "true");
9229
- const cancel = (event) => {
9230
- event.preventDefault();
9231
- event.stopPropagation();
9232
- event.stopImmediatePropagation();
9233
- this.config.actions.setModeState("idle");
9234
- this.config.actions.clearDrafts();
9235
- this.config.actions.setSelectingArea(false);
9236
- this.config.actions.render();
9237
- };
9238
9874
  layer.addEventListener("pointerdown", (event) => {
9239
9875
  if (event.button !== 0) return;
9240
- cancel(event);
9876
+ this.cancelDraft(event);
9241
9877
  });
9242
9878
  return layer;
9243
9879
  }
9880
+ cancelDraft(event) {
9881
+ event?.preventDefault();
9882
+ event?.stopPropagation();
9883
+ event?.stopImmediatePropagation();
9884
+ this.config.actions.setModeState("idle");
9885
+ this.config.actions.clearDrafts();
9886
+ this.config.actions.setSelectingArea(false);
9887
+ this.config.actions.render();
9888
+ }
9244
9889
  getDraftAdjustmentMetrics(draft) {
9245
9890
  const adjustment = draft.adjustment;
9246
9891
  const x = adjustment?.x ?? 0;
@@ -9634,11 +10279,11 @@ ${adjustment}` : adjustment;
9634
10279
  empty.textContent = this.state.noteDraft ? "Write the note in the page box." : this.state.mode === "element" ? "Click an element to add QA." : "Click on the page to place a note.";
9635
10280
  return empty;
9636
10281
  }
9637
- createNotePopover(draft) {
10282
+ createNotePopover(draft, options = {}) {
9638
10283
  const environment = this.config.getEnvironment();
9639
10284
  const group = document.createElement("div");
9640
10285
  group.className = "dfwr-note-draft";
9641
- if (!environment) return group;
10286
+ if (!environment) return { layer: group, composer: void 0 };
9642
10287
  const isElementDraft = this.state.mode === "element" && Boolean(draft.selection);
9643
10288
  const hostPoint = toHostPoint(
9644
10289
  isElementDraft ? this.getAdjustedDraftPoint(draft.marker.viewport, draft) : draft.marker.viewport,
@@ -9662,8 +10307,14 @@ ${adjustment}` : adjustment;
9662
10307
  pin.style.top = `${hostPoint.y}px`;
9663
10308
  const popover = document.createElement("div");
9664
10309
  const position = getPopoverPosition(hostPoint, environment);
9665
- popover.className = `dfwr-note-popover${isElementDraft ? " is-composer" : ""}`;
9666
- if (isElementDraft) {
10310
+ popover.className = [
10311
+ "dfwr-note-popover",
10312
+ isElementDraft ? "is-composer" : "",
10313
+ options.dockComposer ? "is-docked-composer" : ""
10314
+ ].filter(Boolean).join(" ");
10315
+ if (options.dockComposer) {
10316
+ popover.style.width = "100%";
10317
+ } else if (isElementDraft) {
9667
10318
  const selection = draft.selection ? toHostSelection(
9668
10319
  this.getAdjustedDraftSelection(
9669
10320
  toViewportSelection(draft.selection.viewport),
@@ -9722,18 +10373,27 @@ ${adjustment}` : adjustment;
9722
10373
  pin,
9723
10374
  popover,
9724
10375
  selectionHighlight,
9725
- textarea
10376
+ textarea,
10377
+ dockToggle: options.dockComposer
9726
10378
  }) : void 0;
9727
- const actions = this.createFormActions("Save note", saveDraft);
10379
+ const actions = this.createFormActions("Save note", saveDraft, {
10380
+ leading: adjustmentControls?.actionButton ? [adjustmentControls.actionButton] : void 0
10381
+ });
9728
10382
  form.append(
9729
10383
  ...meta ? [meta] : [],
9730
10384
  ...adjustmentControls ? [adjustmentControls.panel] : [],
9731
10385
  textarea,
9732
10386
  actions
9733
10387
  );
9734
- const dragHandle = isElementDraft ? this.createDraftDragHandle("Move DOM composer") : void 0;
9735
- popover.append(...dragHandle ? [dragHandle] : [], form);
9736
- group.append(pin, popover);
10388
+ const dragHandle = isElementDraft && !options.dockComposer ? this.createDraftDragHandle("Move DOM composer") : void 0;
10389
+ popover.append(
10390
+ ...dragHandle ? [dragHandle] : [],
10391
+ form
10392
+ );
10393
+ group.append(pin);
10394
+ if (!options.dockComposer) {
10395
+ group.append(popover);
10396
+ }
9737
10397
  if (dragHandle) {
9738
10398
  this.attachDraftComposerDrag(popover, dragHandle, (composerPosition) => {
9739
10399
  const noteDraft = this.state.noteDraft ?? draft;
@@ -9746,18 +10406,23 @@ ${adjustment}` : adjustment;
9746
10406
  }
9747
10407
  this.attachDraftPinDrag(
9748
10408
  pin,
9749
- isElementDraft ? void 0 : popover,
10409
+ isElementDraft || options.dockComposer ? void 0 : popover,
9750
10410
  meta,
9751
10411
  textarea
9752
10412
  );
9753
- window.setTimeout(() => {
9754
- if (draft.adjustment?.isActive) {
9755
- adjustmentControls?.focusTarget.focus();
9756
- return;
9757
- }
9758
- textarea.focus();
9759
- }, 0);
9760
- return group;
10413
+ if (!options.dockComposer) {
10414
+ window.setTimeout(() => {
10415
+ if (draft.adjustment?.isActive) {
10416
+ adjustmentControls?.focusTarget.focus();
10417
+ return;
10418
+ }
10419
+ textarea.focus();
10420
+ }, 0);
10421
+ }
10422
+ return {
10423
+ layer: group,
10424
+ composer: options.dockComposer ? popover : void 0
10425
+ };
9761
10426
  }
9762
10427
  createDraftDragHandle(label) {
9763
10428
  const handle = document.createElement("button");
@@ -9849,7 +10514,8 @@ ${adjustment}` : adjustment;
9849
10514
  pin,
9850
10515
  popover,
9851
10516
  selectionHighlight,
9852
- textarea
10517
+ textarea,
10518
+ dockToggle
9853
10519
  }) {
9854
10520
  const panel = document.createElement("div");
9855
10521
  panel.className = "dfwr-adjust-panel is-dom-adjust-panel";
@@ -9925,12 +10591,16 @@ ${adjustment}` : adjustment;
9925
10591
  }
9926
10592
  }));
9927
10593
  });
9928
- header.append(help, adjust);
10594
+ header.append(help);
10595
+ if (!dockToggle) {
10596
+ header.append(adjust);
10597
+ }
9929
10598
  panel.append(header, xyStatus, scaleStatus);
9930
10599
  syncControls(draft);
9931
10600
  return {
9932
10601
  panel,
9933
- focusTarget: adjust
10602
+ focusTarget: adjust,
10603
+ actionButton: dockToggle ? adjust : void 0
9934
10604
  };
9935
10605
  }
9936
10606
  getAdjustmentKeyDelta(event) {
@@ -10056,11 +10726,17 @@ ${adjustment}` : adjustment;
10056
10726
  }
10057
10727
  return layer;
10058
10728
  }
10059
- createAreaDraftPopover(draft) {
10729
+ createAreaDraftPopover(draft, options = {}) {
10060
10730
  const environment = this.config.getEnvironment();
10061
10731
  const popover = document.createElement("div");
10062
- popover.className = "dfwr-area-draft is-composer";
10063
- if (environment && draft.selection) {
10732
+ popover.className = [
10733
+ "dfwr-area-draft",
10734
+ "is-composer",
10735
+ options.dockComposer ? "is-docked-composer" : ""
10736
+ ].filter(Boolean).join(" ");
10737
+ if (options.dockComposer) {
10738
+ popover.style.width = "100%";
10739
+ } else if (environment && draft.selection) {
10064
10740
  const selection = toHostSelection(
10065
10741
  toViewportSelection(draft.selection.viewport),
10066
10742
  environment
@@ -10076,15 +10752,20 @@ ${adjustment}` : adjustment;
10076
10752
  popover.style.width = `${composer.width}px`;
10077
10753
  popover.style.right = "auto";
10078
10754
  }
10079
- const dragHandle = this.createDraftDragHandle("Move area composer");
10080
- popover.append(dragHandle, this.createAreaForm());
10081
- this.attachDraftComposerDrag(popover, dragHandle, (composerPosition) => {
10082
- const areaDraft = this.state.areaDraft ?? draft;
10083
- this.config.actions.setAreaDraft({
10084
- ...areaDraft,
10085
- composerPosition
10755
+ const dragHandle = options.dockComposer ? void 0 : this.createDraftDragHandle("Move area composer");
10756
+ popover.append(
10757
+ ...dragHandle ? [dragHandle] : [],
10758
+ this.createAreaForm()
10759
+ );
10760
+ if (dragHandle) {
10761
+ this.attachDraftComposerDrag(popover, dragHandle, (composerPosition) => {
10762
+ const areaDraft = this.state.areaDraft ?? draft;
10763
+ this.config.actions.setAreaDraft({
10764
+ ...areaDraft,
10765
+ composerPosition
10766
+ });
10086
10767
  });
10087
- });
10768
+ }
10088
10769
  return popover;
10089
10770
  }
10090
10771
  createFormActions(saveLabel, onSave, options) {
@@ -10104,12 +10785,19 @@ ${adjustment}` : adjustment;
10104
10785
  cancel.type = "button";
10105
10786
  cancel.textContent = "Cancel";
10106
10787
  cancel.addEventListener("click", (event) => {
10107
- event.preventDefault();
10108
- event.stopPropagation();
10109
- this.config.actions.setModeState("idle");
10110
- this.config.actions.clearDrafts();
10111
- this.config.actions.render();
10788
+ this.cancelDraft(event);
10112
10789
  });
10790
+ if (options?.leading?.length) {
10791
+ actions.classList.add("has-leading");
10792
+ const leading = document.createElement("div");
10793
+ leading.className = "dfwr-actions-leading";
10794
+ leading.append(...options.leading);
10795
+ const primary = document.createElement("div");
10796
+ primary.className = "dfwr-actions-primary";
10797
+ primary.append(save, cancel);
10798
+ actions.append(leading, primary);
10799
+ return actions;
10800
+ }
10113
10801
  if (options?.beforeSave?.length || options?.className) {
10114
10802
  actions.append(cancel, ...options.beforeSave ?? [], save);
10115
10803
  return actions;
@@ -10538,9 +11226,10 @@ var WebReviewKitApp = class {
10538
11226
  this.toggle();
10539
11227
  };
10540
11228
  this.handleViewportChange = () => {
10541
- if (!this.isOpen || this.renderFrame) return;
11229
+ if (!this.isOpen || this.renderFrame || this.isDraftComposerFocused()) return;
10542
11230
  this.renderFrame = window.requestAnimationFrame(() => {
10543
11231
  this.renderFrame = void 0;
11232
+ if (this.isDraftComposerFocused()) return;
10544
11233
  this.render();
10545
11234
  });
10546
11235
  };
@@ -10717,6 +11406,14 @@ var WebReviewKitApp = class {
10717
11406
  this.render();
10718
11407
  return true;
10719
11408
  }
11409
+ isDraftComposerFocused() {
11410
+ if (!this.noteDraft && !this.areaDraft) return false;
11411
+ const composerHost = this.getEnvironment()?.composerHost;
11412
+ const activeElement = composerHost?.ownerDocument.activeElement;
11413
+ return Boolean(
11414
+ composerHost && activeElement && composerHost.contains(activeElement)
11415
+ );
11416
+ }
10720
11417
  getEnvironment() {
10721
11418
  const target = typeof this.options.target === "function" ? this.options.target() : this.options.target;
10722
11419
  if (!target) {
@@ -10745,6 +11442,7 @@ var WebReviewKitApp = class {
10745
11442
  height: target.window.innerHeight
10746
11443
  };
10747
11444
  const overlayRect = target.getOverlayRect?.() ?? rect;
11445
+ const composerHost = target.getComposerHost?.();
10748
11446
  return {
10749
11447
  window: target.window,
10750
11448
  document: target.document,
@@ -10759,7 +11457,8 @@ var WebReviewKitApp = class {
10759
11457
  top: overlayRect.top,
10760
11458
  width: overlayRect.width,
10761
11459
  height: overlayRect.height
10762
- }
11460
+ },
11461
+ composerHost
10763
11462
  };
10764
11463
  } catch {
10765
11464
  return void 0;
@@ -11130,7 +11829,8 @@ var getReviewKitTarget = ({
11130
11829
  width: Math.max(0, right - left),
11131
11830
  height: Math.max(0, bottom - top)
11132
11831
  };
11133
- }
11832
+ },
11833
+ getComposerHost: () => document.querySelector(".df-review-qa-draft-host")
11134
11834
  };
11135
11835
  };
11136
11836
 
@@ -12268,7 +12968,7 @@ var useReviewSettings = ({
12268
12968
  const nextToken = token.trim();
12269
12969
  const nextUserId = userId.trim();
12270
12970
  const nextTheme = normalizeReviewTheme(theme);
12271
- const shouldReload = nextToken !== getStoredFigmaToken() || nextUserId !== getStoredReviewUserId();
12971
+ const shouldReload = nextToken !== getStoredFigmaToken();
12272
12972
  writeStoredFigmaToken(nextToken);
12273
12973
  writeStoredReviewUserId(nextUserId);
12274
12974
  writeStoredReviewTheme(nextTheme);
@@ -12359,7 +13059,7 @@ var useReviewShellData = ({
12359
13059
  () => /* @__PURE__ */ new Set()
12360
13060
  );
12361
13061
  const [qaFilter, setQaFilter] = (0, import_react16.useState)("all");
12362
- const [qaStatusFilter, setQaStatusFilter] = (0, import_react16.useState)("all");
13062
+ const [qaStatusFilter, setQaStatusFilterState] = (0, import_react16.useState)(getStoredReviewQaStatusFilter);
12363
13063
  const [sitemapItems, setSitemapItems] = (0, import_react16.useState)(() => ({
12364
13064
  local: [],
12365
13065
  remote: []
@@ -12478,6 +13178,10 @@ var useReviewShellData = ({
12478
13178
  return counts;
12479
13179
  }, [activeItems, getItemPresetScope]);
12480
13180
  const currentPresetScope = getViewportPresetKind(size);
13181
+ const setQaStatusFilter = (0, import_react16.useCallback)((filter) => {
13182
+ setQaStatusFilterState(filter);
13183
+ writeStoredReviewQaStatusFilter(filter);
13184
+ }, []);
12481
13185
  const pageQaCounts = (0, import_react16.useMemo)(() => {
12482
13186
  const counts = /* @__PURE__ */ new Map();
12483
13187
  const addItems = (sourceKey, sourceItems) => {
@@ -12848,7 +13552,9 @@ var useReviewShellState = ({
12848
13552
  figma: false
12849
13553
  });
12850
13554
  const [selectedItemId, setSelectedItemId] = (0, import_react18.useState)(getInitialItemId());
12851
- const [isListVisible, setIsListVisible] = (0, import_react18.useState)(true);
13555
+ const [isListVisible, setIsListVisible] = (0, import_react18.useState)(
13556
+ getStoredReviewSidePanelVisible
13557
+ );
12852
13558
  const [isSitemapOpen, setIsSitemapOpen] = (0, import_react18.useState)(false);
12853
13559
  const [isInitialPromptOpen, setIsInitialPromptOpen] = (0, import_react18.useState)(false);
12854
13560
  const [copyLabel, setCopyLabel] = (0, import_react18.useState)("Copy URL");
@@ -12912,34 +13618,40 @@ var useReviewShellState = ({
12912
13618
  };
12913
13619
 
12914
13620
  // src/react-shell/review/shell.actions.ts
13621
+ var writeClipboardTextFallback = (value) => {
13622
+ const selection = document.getSelection();
13623
+ const activeElement = document.activeElement instanceof HTMLElement ? document.activeElement : null;
13624
+ const ranges = selection ? Array.from(
13625
+ { length: selection.rangeCount },
13626
+ (_, index) => selection.getRangeAt(index)
13627
+ ) : [];
13628
+ const textarea = document.createElement("textarea");
13629
+ textarea.value = value;
13630
+ textarea.setAttribute("readonly", "");
13631
+ textarea.style.position = "fixed";
13632
+ textarea.style.left = "-9999px";
13633
+ textarea.style.top = "0";
13634
+ document.body.appendChild(textarea);
13635
+ textarea.focus();
13636
+ textarea.select();
13637
+ const isCopied = document.execCommand("copy");
13638
+ textarea.remove();
13639
+ selection?.removeAllRanges();
13640
+ ranges.forEach((range) => selection?.addRange(range));
13641
+ activeElement?.focus();
13642
+ if (!isCopied) {
13643
+ throw new Error("Failed to copy to clipboard");
13644
+ }
13645
+ };
12915
13646
  var writeClipboardText = async (value) => {
12916
13647
  try {
12917
- await navigator.clipboard.writeText(value);
13648
+ writeClipboardTextFallback(value);
12918
13649
  return;
12919
- } catch {
12920
- const selection = document.getSelection();
12921
- const activeElement = document.activeElement instanceof HTMLElement ? document.activeElement : null;
12922
- const ranges = selection ? Array.from(
12923
- { length: selection.rangeCount },
12924
- (_, index) => selection.getRangeAt(index)
12925
- ) : [];
12926
- const textarea = document.createElement("textarea");
12927
- textarea.value = value;
12928
- textarea.setAttribute("readonly", "");
12929
- textarea.style.position = "fixed";
12930
- textarea.style.left = "-9999px";
12931
- textarea.style.top = "0";
12932
- document.body.appendChild(textarea);
12933
- textarea.focus();
12934
- textarea.select();
12935
- const isCopied = document.execCommand("copy");
12936
- textarea.remove();
12937
- selection?.removeAllRanges();
12938
- ranges.forEach((range) => selection?.addRange(range));
12939
- activeElement?.focus();
12940
- if (!isCopied) {
12941
- throw new Error("Failed to copy to clipboard");
13650
+ } catch (error) {
13651
+ if (!navigator.clipboard?.writeText) {
13652
+ throw error;
12942
13653
  }
13654
+ await navigator.clipboard.writeText(value);
12943
13655
  }
12944
13656
  };
12945
13657
  var listReviewItems = async ({
@@ -13227,12 +13939,10 @@ var getSectionOutlineEntryCount = (entries) => entries.reduce(
13227
13939
  (count, entry) => count + 1 + getSectionOutlineEntryCount(entry.children),
13228
13940
  0
13229
13941
  );
13230
- var DEFAULT_COLLAPSED_ROOT_LABELS = /* @__PURE__ */ new Set(["FrameHeader", "FrameFooter"]);
13231
13942
  var getDefaultCollapsedSectionOutlineIds = (entries) => {
13232
13943
  const collapsedIds = /* @__PURE__ */ new Set();
13233
13944
  const visit = (entry) => {
13234
- const shouldCollapseRoot = entry.depth === 1 && DEFAULT_COLLAPSED_ROOT_LABELS.has(entry.label);
13235
- if ((entry.depth >= 2 || shouldCollapseRoot) && entry.children.length > 0) {
13945
+ if (entry.children.length > 0) {
13236
13946
  collapsedIds.add(entry.id);
13237
13947
  }
13238
13948
  entry.children.forEach(visit);
@@ -13240,13 +13950,27 @@ var getDefaultCollapsedSectionOutlineIds = (entries) => {
13240
13950
  entries.forEach(visit);
13241
13951
  return collapsedIds;
13242
13952
  };
13953
+ var getLiveSectionOutlineRect = (entry) => {
13954
+ if (!entry.element.isConnected) return entry.metadata.rect;
13955
+ const rect = entry.element.getBoundingClientRect();
13956
+ return {
13957
+ top: Math.round(rect.top),
13958
+ left: Math.round(rect.left),
13959
+ width: Math.round(rect.width),
13960
+ height: Math.round(rect.height)
13961
+ };
13962
+ };
13243
13963
  var matchesSectionOutlineFilter = (entry, terms) => {
13244
13964
  if (terms.length === 0) return true;
13245
13965
  const text = [
13246
13966
  entry.label,
13247
13967
  entry.filePath,
13248
13968
  entry.source?.file,
13249
- entry.data?.file
13969
+ entry.data?.file,
13970
+ entry.metadata.textValue,
13971
+ entry.metadata.fontLabel,
13972
+ entry.metadata.mediaItems?.map((mediaItem) => `${mediaItem.variant} ${mediaItem.type} ${mediaItem.url}`).join(" "),
13973
+ entry.metadata.classNames?.join(" ")
13250
13974
  ].filter(Boolean).join(" ").toLowerCase();
13251
13975
  return terms.every((term) => text.includes(term));
13252
13976
  };
@@ -13331,10 +14055,16 @@ var ReviewShell = ({
13331
14055
  });
13332
14056
  const sourceShortcutCleanupRef = (0, import_react19.useRef)(null);
13333
14057
  const sourceInspectorInteractionRef = (0, import_react19.useRef)(false);
13334
- const [sidePanel, setSidePanel] = (0, import_react19.useState)("qa");
13335
14058
  const [sourceInspectorState, setSourceInspectorState] = (0, import_react19.useState)(null);
13336
14059
  const [sectionOutline, setSectionOutline] = (0, import_react19.useState)(null);
13337
- const [sectionOutlineFilter, setSectionOutlineFilter] = (0, import_react19.useState)("");
14060
+ const [sectionOutlineFilter, setSectionOutlineFilter] = (0, import_react19.useState)(
14061
+ () => getStoredSourceTreeFilter()
14062
+ );
14063
+ const [sectionOutlineMetaVisibility, setSectionOutlineMetaVisibility] = (0, import_react19.useState)(() => getStoredSourceTreeMetaVisibility());
14064
+ const isSectionOutlineBoxMetaVisible = sectionOutlineMetaVisibility.box;
14065
+ const isSectionOutlineFontMetaVisible = sectionOutlineMetaVisibility.font;
14066
+ const isSectionOutlineMediaMetaVisible = sectionOutlineMetaVisibility.media;
14067
+ const isSectionOutlineClassMetaVisible = sectionOutlineMetaVisibility.className;
13338
14068
  const [collapsedSectionOutlineIds, setCollapsedSectionOutlineIds] = (0, import_react19.useState)(() => /* @__PURE__ */ new Set());
13339
14069
  const [isAllQaVisible, setIsAllQaVisible] = (0, import_react19.useState)(false);
13340
14070
  const sourceOpenOptions = (0, import_react19.useMemo)(
@@ -13360,9 +14090,36 @@ var ReviewShell = ({
13360
14090
  [sourceInspector]
13361
14091
  );
13362
14092
  const isSourceInspectorEnabled = sourceInspector?.enabled !== false;
14093
+ const [sidePanel, setSidePanel] = (0, import_react19.useState)(
14094
+ () => isSourceInspectorEnabled ? getStoredReviewSidePanel() : "qa"
14095
+ );
13363
14096
  const isSourceTreeHoverOutlineEnabled = sourceInspector?.hoverOutline !== false;
13364
14097
  const isQaPanelVisible = isListVisible && sidePanel === "qa";
13365
14098
  const isSourceTreePanelVisible = isSourceInspectorEnabled && isListVisible && sidePanel === "source";
14099
+ (0, import_react19.useEffect)(() => {
14100
+ if (isSourceInspectorEnabled || sidePanel !== "source") return;
14101
+ setSidePanel("qa");
14102
+ }, [isSourceInspectorEnabled, sidePanel]);
14103
+ (0, import_react19.useEffect)(() => {
14104
+ writeStoredReviewSidePanel(sidePanel);
14105
+ }, [sidePanel]);
14106
+ (0, import_react19.useEffect)(() => {
14107
+ writeStoredReviewSidePanelVisible(isListVisible);
14108
+ }, [isListVisible]);
14109
+ const updateSectionOutlineFilter = (0, import_react19.useCallback)((nextFilter) => {
14110
+ setSectionOutlineFilter(nextFilter);
14111
+ writeStoredSourceTreeFilter(nextFilter);
14112
+ }, []);
14113
+ const updateSectionOutlineMetaVisibility = (0, import_react19.useCallback)(
14114
+ (key) => {
14115
+ setSectionOutlineMetaVisibility((current) => {
14116
+ const next = { ...current, [key]: !current[key] };
14117
+ writeStoredSourceTreeMetaVisibility(next);
14118
+ return next;
14119
+ });
14120
+ },
14121
+ []
14122
+ );
13366
14123
  const sectionOutlineFilterTerms = (0, import_react19.useMemo)(
13367
14124
  () => getSectionOutlineFilterTerms(sectionOutlineFilter),
13368
14125
  [sectionOutlineFilter]
@@ -13630,6 +14387,7 @@ var ReviewShell = ({
13630
14387
  parsedInput.height
13631
14388
  ) : sizeRef.current;
13632
14389
  const nextAdapter = sourceEntries.find((entry) => entry.label === nextSource) ?? activeAdapterEntry;
14390
+ const isCurrentTarget = targetRef.current === normalizedTarget && source === nextSource && sizeRef.current.width === nextSize.width && sizeRef.current.height === nextSize.height;
13633
14391
  if (parsedInput.itemId) {
13634
14392
  const item = await nextAdapter.adapter.get(parsedInput.itemId);
13635
14393
  if (item) {
@@ -13648,6 +14406,7 @@ var ReviewShell = ({
13648
14406
  setSize(nextSize);
13649
14407
  setTarget(normalizedTarget);
13650
14408
  updateShellUrl(normalizedTarget, nextSize, nextSource);
14409
+ if (isCurrentTarget) reloadTargetFrame();
13651
14410
  };
13652
14411
  const selectPage = (href) => {
13653
14412
  const normalizedTarget = normalizeTarget(href, reviewPathPrefix);
@@ -13668,6 +14427,10 @@ var ReviewShell = ({
13668
14427
  const writeMode = getReviewModeWriteMode(nextMode);
13669
14428
  if (writeMode && !activeAdapterEntry.writeModes.includes(writeMode)) return;
13670
14429
  closeRuler();
14430
+ if (writeMode && mode !== nextMode) {
14431
+ setSidePanel("qa");
14432
+ setIsListVisible(true);
14433
+ }
13671
14434
  setControllerReviewMode(nextMode);
13672
14435
  };
13673
14436
  useReviewShellHotkeys({
@@ -13717,7 +14480,6 @@ var ReviewShell = ({
13717
14480
  }, []);
13718
14481
  (0, import_react19.useEffect)(() => {
13719
14482
  clearSourceInspector();
13720
- setSectionOutlineFilter("");
13721
14483
  setCollapsedSectionOutlineIds(/* @__PURE__ */ new Set());
13722
14484
  setSectionOutline(null);
13723
14485
  }, [clearSourceInspector, targetSrc]);
@@ -13878,7 +14640,10 @@ var ReviewShell = ({
13878
14640
  } catch {
13879
14641
  frameDocument = null;
13880
14642
  }
13881
- return frameDocument ? getSectionOutline(frameDocument, sectionOutlineOptions) : [];
14643
+ if (!frameDocument || frameDocument.readyState !== "complete") {
14644
+ return null;
14645
+ }
14646
+ return getSectionOutline(frameDocument, sectionOutlineOptions);
13882
14647
  },
13883
14648
  [iframeRef, sectionOutlineOptions]
13884
14649
  );
@@ -13894,7 +14659,9 @@ var ReviewShell = ({
13894
14659
  (0, import_react19.useEffect)(() => {
13895
14660
  if (sidePanel !== "source" || !isListVisible) return void 0;
13896
14661
  const refreshSectionOutline = () => {
13897
- setSectionOutlineWithDefaultCollapse(getCurrentSectionOutline());
14662
+ const nextSectionOutline = getCurrentSectionOutline();
14663
+ if (!nextSectionOutline) return;
14664
+ setSectionOutlineWithDefaultCollapse(nextSectionOutline);
13898
14665
  };
13899
14666
  const animationFrame = window.requestAnimationFrame(refreshSectionOutline);
13900
14667
  const firstTimeout = window.setTimeout(refreshSectionOutline, 120);
@@ -13922,7 +14689,10 @@ var ReviewShell = ({
13922
14689
  return;
13923
14690
  }
13924
14691
  setSidePanel("source");
13925
- setSectionOutlineWithDefaultCollapse(getCurrentSectionOutline());
14692
+ const nextSectionOutline = getCurrentSectionOutline();
14693
+ if (nextSectionOutline) {
14694
+ setSectionOutlineWithDefaultCollapse(nextSectionOutline);
14695
+ }
13926
14696
  setIsListVisible(true);
13927
14697
  }, [
13928
14698
  getCurrentSectionOutline,
@@ -13975,7 +14745,8 @@ var ReviewShell = ({
13975
14745
  return;
13976
14746
  }
13977
14747
  clearSourceInspector();
13978
- setIsListVisible(false);
14748
+ setSidePanel("qa");
14749
+ setIsListVisible(true);
13979
14750
  let targetWindow = null;
13980
14751
  try {
13981
14752
  targetWindow = entry.element.ownerDocument.defaultView ?? iframeRef.current?.contentWindow ?? null;
@@ -14285,7 +15056,10 @@ var ReviewShell = ({
14285
15056
  );
14286
15057
  bindSourceOpenShortcut();
14287
15058
  if (sidePanel === "source" && isListVisible) {
14288
- setSectionOutlineWithDefaultCollapse(getCurrentSectionOutline());
15059
+ const nextSectionOutline = getCurrentSectionOutline();
15060
+ if (nextSectionOutline) {
15061
+ setSectionOutlineWithDefaultCollapse(nextSectionOutline);
15062
+ }
14289
15063
  }
14290
15064
  }, [
14291
15065
  bindSourceOpenShortcut,
@@ -14352,6 +15126,11 @@ var ReviewShell = ({
14352
15126
  `qa:${numberedItem.item.id}`,
14353
15127
  "QA prompt copied"
14354
15128
  );
15129
+ const copyItemLabel = (numberedItem) => copyPrompt(
15130
+ numberedItem.displayLabel,
15131
+ `label:${numberedItem.item.id}`,
15132
+ "QA number copied"
15133
+ );
14355
15134
  const copyItemLink = (numberedItem) => {
14356
15135
  const { item } = numberedItem;
14357
15136
  return copyPrompt(
@@ -14377,6 +15156,99 @@ var ReviewShell = ({
14377
15156
  onRefreshReviewData: refreshReviewData2,
14378
15157
  onToast: showToast
14379
15158
  });
15159
+ const renderSectionOutlineMeta = (entry) => {
15160
+ const { metadata } = entry;
15161
+ const rows = [];
15162
+ const metaPaddingLeft = Math.max(0, entry.depth - 1) * 12 + 29;
15163
+ const rect = getLiveSectionOutlineRect(entry);
15164
+ if (isSectionOutlineBoxMetaVisible) {
15165
+ rows.push(
15166
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("span", { className: "df-review-section-outline-meta-row", children: [
15167
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("b", { children: "box" }),
15168
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("code", { children: [
15169
+ "top ",
15170
+ rect.top,
15171
+ " / left ",
15172
+ rect.left,
15173
+ " / width ",
15174
+ rect.width,
15175
+ " / height",
15176
+ " ",
15177
+ rect.height
15178
+ ] })
15179
+ ] }, "box")
15180
+ );
15181
+ }
15182
+ if (metadata.textValue) {
15183
+ rows.push(
15184
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
15185
+ "span",
15186
+ {
15187
+ className: "df-review-section-outline-meta-row is-text",
15188
+ children: [
15189
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("b", { children: "text" }),
15190
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("code", { children: metadata.textValue })
15191
+ ]
15192
+ },
15193
+ "text"
15194
+ )
15195
+ );
15196
+ }
15197
+ if (isSectionOutlineFontMetaVisible && metadata.fontLabel) {
15198
+ rows.push(
15199
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("span", { className: "df-review-section-outline-meta-row", children: [
15200
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("b", { children: "font" }),
15201
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("code", { children: metadata.fontLabel })
15202
+ ] }, "font")
15203
+ );
15204
+ }
15205
+ if (isSectionOutlineMediaMetaVisible && metadata.mediaItems?.length) {
15206
+ metadata.mediaItems.forEach((mediaItem) => {
15207
+ const mediaKey = `${mediaItem.variant}:${mediaItem.type}:${mediaItem.url}`;
15208
+ const mediaLabel = mediaItem.variant === "media" ? mediaItem.type : mediaItem.variant;
15209
+ rows.push(
15210
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
15211
+ "span",
15212
+ {
15213
+ className: "df-review-section-outline-meta-row is-media",
15214
+ children: [
15215
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("b", { children: mediaLabel }),
15216
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
15217
+ "a",
15218
+ {
15219
+ className: "df-review-section-outline-media-link",
15220
+ href: mediaItem.url,
15221
+ rel: "noopener noreferrer",
15222
+ target: "_blank",
15223
+ title: `${mediaLabel} ${mediaItem.type}`,
15224
+ children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("code", { children: mediaItem.url })
15225
+ }
15226
+ )
15227
+ ]
15228
+ },
15229
+ mediaKey
15230
+ )
15231
+ );
15232
+ });
15233
+ }
15234
+ if (isSectionOutlineClassMetaVisible && metadata.classNames?.length) {
15235
+ rows.push(
15236
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("span", { className: "df-review-section-outline-meta-row is-class", children: [
15237
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("b", { children: "class" }),
15238
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "df-review-section-outline-class-tags", children: metadata.classNames.map((className) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("code", { children: className }, className)) })
15239
+ ] }, "class")
15240
+ );
15241
+ }
15242
+ if (rows.length === 0) return null;
15243
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
15244
+ "div",
15245
+ {
15246
+ className: "df-review-section-outline-meta",
15247
+ style: { paddingLeft: `${metaPaddingLeft}px` },
15248
+ children: rows
15249
+ }
15250
+ );
15251
+ };
14380
15252
  const renderSectionOutlineEntry = (entry) => {
14381
15253
  const hasChildren = entry.children.length > 0;
14382
15254
  const isCollapsed = !isSectionOutlineFiltering && collapsedSectionOutlineIds.has(entry.id);
@@ -14388,8 +15260,7 @@ var ReviewShell = ({
14388
15260
  /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
14389
15261
  "div",
14390
15262
  {
14391
- className: "df-review-section-outline-row",
14392
- style: { paddingLeft: `${Math.max(0, entry.depth - 1) * 12 + 6}px` },
15263
+ className: "df-review-section-outline-entry-body",
14393
15264
  onMouseEnter: () => showSourceOutlineForElement(entry.element),
14394
15265
  onMouseLeave: clearSourceOutlineHover,
14395
15266
  onMouseOver: () => showSourceOutlineForElement(entry.element),
@@ -14402,78 +15273,88 @@ var ReviewShell = ({
14402
15273
  onPointerEnter: () => showSourceOutlineForElement(entry.element),
14403
15274
  onPointerLeave: clearSourceOutlineHover,
14404
15275
  children: [
14405
- hasChildren ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
14406
- "button",
14407
- {
14408
- "aria-label": isCollapsed ? `Expand ${entry.label}` : `Collapse ${entry.label}`,
14409
- "aria-expanded": !isCollapsed,
14410
- className: `df-review-section-outline-toggle${isCollapsed ? " is-collapsed" : ""}`,
14411
- type: "button",
14412
- onClick: () => toggleSectionOutlineEntry(entry.id),
14413
- children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(ChevronDown, { "aria-hidden": "true" })
14414
- }
14415
- ) : /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
14416
- "span",
14417
- {
14418
- "aria-hidden": "true",
14419
- className: "df-review-section-outline-toggle is-placeholder"
14420
- }
14421
- ),
14422
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
14423
- "button",
15276
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
15277
+ "div",
14424
15278
  {
14425
- className: "df-review-section-outline-name",
14426
- type: "button",
14427
- onClick: () => scrollToSection(entry),
14428
- children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { children: entry.label })
15279
+ className: "df-review-section-outline-row",
15280
+ style: { paddingLeft: `${Math.max(0, entry.depth - 1) * 12 + 6}px` },
15281
+ children: [
15282
+ hasChildren ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
15283
+ "button",
15284
+ {
15285
+ "aria-label": isCollapsed ? `Expand ${entry.label}` : `Collapse ${entry.label}`,
15286
+ "aria-expanded": !isCollapsed,
15287
+ className: `df-review-section-outline-toggle${isCollapsed ? " is-collapsed" : ""}`,
15288
+ type: "button",
15289
+ onClick: () => toggleSectionOutlineEntry(entry.id),
15290
+ children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(ChevronDown, { "aria-hidden": "true" })
15291
+ }
15292
+ ) : /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
15293
+ "span",
15294
+ {
15295
+ "aria-hidden": "true",
15296
+ className: "df-review-section-outline-toggle is-placeholder"
15297
+ }
15298
+ ),
15299
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
15300
+ "button",
15301
+ {
15302
+ className: "df-review-section-outline-name",
15303
+ type: "button",
15304
+ onClick: () => scrollToSection(entry),
15305
+ children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { children: entry.label })
15306
+ }
15307
+ ),
15308
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("span", { className: "df-review-section-outline-links", children: [
15309
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
15310
+ "button",
15311
+ {
15312
+ "aria-label": `Open ${entry.label} data`,
15313
+ className: "df-review-section-outline-link",
15314
+ title: "Open data",
15315
+ type: "button",
15316
+ disabled: !entry.data?.file,
15317
+ onClick: () => openSectionData(entry),
15318
+ children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Database, { "aria-hidden": "true" })
15319
+ }
15320
+ ),
15321
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
15322
+ "button",
15323
+ {
15324
+ "aria-label": `Open ${entry.label} source`,
15325
+ className: "df-review-section-outline-link",
15326
+ title: "Open source",
15327
+ type: "button",
15328
+ disabled: !entry.source?.file,
15329
+ onClick: () => openSectionSource(entry),
15330
+ children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(CodeXml, { "aria-hidden": "true" })
15331
+ }
15332
+ ),
15333
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
15334
+ "span",
15335
+ {
15336
+ "aria-hidden": "true",
15337
+ className: "df-review-section-outline-divider",
15338
+ children: "|"
15339
+ }
15340
+ ),
15341
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
15342
+ "button",
15343
+ {
15344
+ "aria-label": `Start DOM QA for ${entry.label}`,
15345
+ className: "df-review-section-outline-link is-dom-select",
15346
+ title: "DOM select",
15347
+ type: "button",
15348
+ disabled: !canWriteDom,
15349
+ onClick: () => startSectionDomReview(entry),
15350
+ children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(SquareMousePointer, { "aria-hidden": "true" })
15351
+ }
15352
+ )
15353
+ ] })
15354
+ ]
14429
15355
  }
14430
15356
  ),
14431
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("span", { className: "df-review-section-outline-links", children: [
14432
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
14433
- "button",
14434
- {
14435
- "aria-label": `Open ${entry.label} data`,
14436
- className: "df-review-section-outline-link",
14437
- title: "Open data",
14438
- type: "button",
14439
- disabled: !entry.data?.file,
14440
- onClick: () => openSectionData(entry),
14441
- children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Database, { "aria-hidden": "true" })
14442
- }
14443
- ),
14444
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
14445
- "button",
14446
- {
14447
- "aria-label": `Open ${entry.label} source`,
14448
- className: "df-review-section-outline-link",
14449
- title: "Open source",
14450
- type: "button",
14451
- disabled: !entry.source?.file,
14452
- onClick: () => openSectionSource(entry),
14453
- children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(CodeXml, { "aria-hidden": "true" })
14454
- }
14455
- ),
14456
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
14457
- "span",
14458
- {
14459
- "aria-hidden": "true",
14460
- className: "df-review-section-outline-divider",
14461
- children: "|"
14462
- }
14463
- ),
14464
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
14465
- "button",
14466
- {
14467
- "aria-label": `Start DOM QA for ${entry.label}`,
14468
- className: "df-review-section-outline-link is-dom-select",
14469
- title: "DOM select",
14470
- type: "button",
14471
- disabled: !canWriteDom,
14472
- onClick: () => startSectionDomReview(entry),
14473
- children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(SquareMousePointer, { "aria-hidden": "true" })
14474
- }
14475
- )
14476
- ] })
15357
+ renderSectionOutlineMeta(entry)
14477
15358
  ]
14478
15359
  }
14479
15360
  ),
@@ -14506,11 +15387,7 @@ var ReviewShell = ({
14506
15387
  onCopyCurrentUrl: () => void copyCurrentUrl(),
14507
15388
  onSizeChange: setSize,
14508
15389
  onToggleRuler: toggleRuler,
14509
- onToggleTargetOverlay: toggleTargetOverlay,
14510
- onOpenInitialPrompt: () => {
14511
- setIsInitialPromptOpen(true);
14512
- },
14513
- onOpenSettings: openFigmaSettings
15390
+ onToggleTargetOverlay: toggleTargetOverlay
14514
15391
  }
14515
15392
  ),
14516
15393
  isSitemapOpen && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
@@ -14588,16 +15465,42 @@ var ReviewShell = ({
14588
15465
  type: "button",
14589
15466
  onClick: toggleSourceTreePanel,
14590
15467
  title: "Source Tree",
14591
- children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Search, {}) })
15468
+ children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Workflow, {}) })
14592
15469
  }
14593
15470
  ),
14594
- currentPagePresenceUsers.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
14595
- PresenceOverlay,
14596
- {
14597
- presenceSessionId,
14598
- users: currentPagePresenceUsers
14599
- }
14600
- )
15471
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "df-review-side-actions", children: [
15472
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
15473
+ "button",
15474
+ {
15475
+ "aria-label": "Open initial prompt",
15476
+ className: "df-review-side-toggle",
15477
+ type: "button",
15478
+ onClick: () => {
15479
+ setIsInitialPromptOpen(true);
15480
+ },
15481
+ title: "Help",
15482
+ children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(CircleQuestionMark, {}) })
15483
+ }
15484
+ ),
15485
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
15486
+ "button",
15487
+ {
15488
+ "aria-label": "Open settings",
15489
+ className: "df-review-side-toggle",
15490
+ type: "button",
15491
+ onClick: openFigmaSettings,
15492
+ title: "Settings",
15493
+ children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Settings, {}) })
15494
+ }
15495
+ ),
15496
+ currentPagePresenceUsers.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
15497
+ PresenceOverlay,
15498
+ {
15499
+ presenceSessionId,
15500
+ users: currentPagePresenceUsers
15501
+ }
15502
+ )
15503
+ ] })
14601
15504
  ] }),
14602
15505
  /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
14603
15506
  ReviewQaPanel,
@@ -14625,6 +15528,7 @@ var ReviewShell = ({
14625
15528
  onChangeItemStatus: changeItemStatus,
14626
15529
  onClearSelectedItem: clearSelectedReviewItem,
14627
15530
  onChangeReviewSource: changeReviewSource,
15531
+ onCopyItemLabel: (numberedItem) => void copyItemLabel(numberedItem),
14628
15532
  onCopyItemLink: (numberedItem) => void copyItemLink(numberedItem),
14629
15533
  onCopyItemPrompt: (numberedItem) => void copyItemPrompt(numberedItem),
14630
15534
  onEditItem: setEditingItem,
@@ -14644,9 +15548,61 @@ var ReviewShell = ({
14644
15548
  "aria-hidden": !isSourceTreePanelVisible,
14645
15549
  children: /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { id: "df-review-section-outline", className: "df-review-section-outline", children: [
14646
15550
  /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "df-review-section-outline-head", children: [
14647
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("span", { children: [
14648
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("strong", { children: "Source Tree" }),
14649
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("small", { children: isSectionOutlineFiltering ? `${filteredSectionOutlineCount} / ${sectionOutlineTotalCount} results` : `${sectionOutline?.length ?? 0} roots` })
15551
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "df-review-section-outline-summary", children: [
15552
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("span", { children: [
15553
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("strong", { children: "Component" }),
15554
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("small", { children: isSectionOutlineFiltering ? `${filteredSectionOutlineCount} / ${sectionOutlineTotalCount} results` : `${sectionOutline?.length ?? 0} ${sectionOutline?.length === 1 ? "root" : "roots"}` })
15555
+ ] }),
15556
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "df-review-section-outline-meta-controls", children: [
15557
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
15558
+ "button",
15559
+ {
15560
+ "aria-label": "Toggle source tree box metadata",
15561
+ "aria-pressed": isSectionOutlineBoxMetaVisible,
15562
+ className: `df-review-section-outline-meta-toggle${isSectionOutlineBoxMetaVisible ? " is-active" : ""}`,
15563
+ title: "top / left / width / height",
15564
+ type: "button",
15565
+ onClick: () => updateSectionOutlineMetaVisibility("box"),
15566
+ children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(SquareDashed, { "aria-hidden": "true" })
15567
+ }
15568
+ ),
15569
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
15570
+ "button",
15571
+ {
15572
+ "aria-label": "Toggle source tree font metadata",
15573
+ "aria-pressed": isSectionOutlineFontMetaVisible,
15574
+ className: `df-review-section-outline-meta-toggle${isSectionOutlineFontMetaVisible ? " is-active" : ""}`,
15575
+ title: "font size / weight",
15576
+ type: "button",
15577
+ onClick: () => updateSectionOutlineMetaVisibility("font"),
15578
+ children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Type, { "aria-hidden": "true" })
15579
+ }
15580
+ ),
15581
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
15582
+ "button",
15583
+ {
15584
+ "aria-label": "Toggle source tree media metadata",
15585
+ "aria-pressed": isSectionOutlineMediaMetaVisible,
15586
+ className: `df-review-section-outline-meta-toggle${isSectionOutlineMediaMetaVisible ? " is-active" : ""}`,
15587
+ title: "media urls",
15588
+ type: "button",
15589
+ onClick: () => updateSectionOutlineMetaVisibility("media"),
15590
+ children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Image, { "aria-hidden": "true" })
15591
+ }
15592
+ ),
15593
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
15594
+ "button",
15595
+ {
15596
+ "aria-label": "Toggle source tree class metadata",
15597
+ "aria-pressed": isSectionOutlineClassMetaVisible,
15598
+ className: `df-review-section-outline-meta-toggle${isSectionOutlineClassMetaVisible ? " is-active" : ""}`,
15599
+ title: "class names",
15600
+ type: "button",
15601
+ onClick: () => updateSectionOutlineMetaVisibility("className"),
15602
+ children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(CodeXml, { "aria-hidden": "true" })
15603
+ }
15604
+ )
15605
+ ] })
14650
15606
  ] }),
14651
15607
  /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "df-review-section-outline-filter", children: [
14652
15608
  /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Search, { "aria-hidden": "true" }),
@@ -14660,7 +15616,7 @@ var ReviewShell = ({
14660
15616
  autoComplete: "off",
14661
15617
  enterKeyHint: "search",
14662
15618
  spellCheck: false,
14663
- onChange: (event) => setSectionOutlineFilter(event.currentTarget.value)
15619
+ onChange: (event) => updateSectionOutlineFilter(event.currentTarget.value)
14664
15620
  }
14665
15621
  ),
14666
15622
  sectionOutlineFilter && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
@@ -14670,7 +15626,7 @@ var ReviewShell = ({
14670
15626
  className: "df-review-section-outline-filter-clear",
14671
15627
  type: "button",
14672
15628
  onMouseDown: (event) => event.preventDefault(),
14673
- onClick: () => setSectionOutlineFilter(""),
15629
+ onClick: () => updateSectionOutlineFilter(""),
14674
15630
  children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(X, { "aria-hidden": "true" })
14675
15631
  }
14676
15632
  )
@@ -14990,7 +15946,6 @@ lucide-react/dist/esm/icons/circle-question-mark.mjs:
14990
15946
  lucide-react/dist/esm/icons/code-xml.mjs:
14991
15947
  lucide-react/dist/esm/icons/copy.mjs:
14992
15948
  lucide-react/dist/esm/icons/database.mjs:
14993
- lucide-react/dist/esm/icons/ellipsis.mjs:
14994
15949
  lucide-react/dist/esm/icons/external-link.mjs:
14995
15950
  lucide-react/dist/esm/icons/eye-off.mjs:
14996
15951
  lucide-react/dist/esm/icons/eye.mjs:
@@ -15011,11 +15966,13 @@ lucide-react/dist/esm/icons/scan.mjs:
15011
15966
  lucide-react/dist/esm/icons/search.mjs:
15012
15967
  lucide-react/dist/esm/icons/settings.mjs:
15013
15968
  lucide-react/dist/esm/icons/smartphone.mjs:
15969
+ lucide-react/dist/esm/icons/square-dashed.mjs:
15014
15970
  lucide-react/dist/esm/icons/square-mouse-pointer.mjs:
15015
15971
  lucide-react/dist/esm/icons/sticky-note.mjs:
15016
15972
  lucide-react/dist/esm/icons/sun.mjs:
15973
+ lucide-react/dist/esm/icons/type.mjs:
15017
15974
  lucide-react/dist/esm/icons/upload.mjs:
15018
- lucide-react/dist/esm/icons/user-round.mjs:
15975
+ lucide-react/dist/esm/icons/workflow.mjs:
15019
15976
  lucide-react/dist/esm/icons/x.mjs:
15020
15977
  lucide-react/dist/esm/lucide-react.mjs:
15021
15978
  (**