@designfever/web-review-kit 0.8.2 → 0.8.3

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.
@@ -492,6 +492,11 @@ var reviewShellSitemapStyle = `
492
492
  padding: 18px;
493
493
  }
494
494
 
495
+ /* \uB2EB\uC544\uB3C4 unmount \uD558\uC9C0 \uC54A\uACE0 \uC228\uAE34\uB2E4. visibility \uB294 \uB9AC\uC2A4\uD2B8 \uC2A4\uD06C\uB864 \uC704\uCE58\uB97C \uBCF4\uC874\uD55C\uB2E4. */
496
+ .df-review-sitemap-modal.is-hidden {
497
+ visibility: hidden;
498
+ }
499
+
495
500
  .df-review-sitemap-backdrop {
496
501
  position: absolute;
497
502
  inset: 0;
@@ -544,7 +549,7 @@ var reviewShellSitemapStyle = `
544
549
  font-weight: var(--df-review-font-weight-normal);
545
550
  }
546
551
 
547
- .df-review-sitemap-header button {
552
+ .df-review-sitemap-header > button {
548
553
  display: grid;
549
554
  place-items: center;
550
555
  width: 34px;
@@ -558,11 +563,36 @@ var reviewShellSitemapStyle = `
558
563
  font-weight: var(--df-review-font-weight-normal);
559
564
  }
560
565
 
561
- .df-review-sitemap-header button:hover {
566
+ .df-review-sitemap-header > button:hover {
562
567
  border-color: var(--df-review-accent);
563
568
  background: var(--df-review-control-hover);
564
569
  }
565
570
 
571
+ /* \uD5E4\uB354 \uC694\uC57D \uCE74\uC6B4\uD2B8\uB97C \uADF8\uB300\uB85C status filter \uD1A0\uAE00\uB85C \uC4F4\uB2E4. */
572
+ .df-review-sitemap-summary-filter {
573
+ display: inline;
574
+ border: 0;
575
+ padding: 0;
576
+ background: none;
577
+ color: var(--df-review-muted);
578
+ font: inherit;
579
+ cursor: pointer;
580
+ }
581
+
582
+ .df-review-sitemap-summary-filter:hover,
583
+ .df-review-sitemap-summary-filter:focus-visible {
584
+ color: var(--df-review-text);
585
+ text-decoration: underline;
586
+ text-underline-offset: 3px;
587
+ outline: none;
588
+ }
589
+
590
+ .df-review-sitemap-summary-filter.is-active {
591
+ color: var(--df-review-accent);
592
+ text-decoration: underline;
593
+ text-underline-offset: 3px;
594
+ }
595
+
566
596
  .df-review-sitemap-controls {
567
597
  display: flex;
568
598
  align-items: center;
@@ -2341,6 +2371,8 @@ var reviewShellQaPanelStyle = `
2341
2371
 
2342
2372
  .df-review-qa-draft-host[data-has-draft-composer="true"] {
2343
2373
  display: block;
2374
+ /* Source Tree \uD328\uB110(z 900) \uC704\uB85C \uC62C\uB824 draft composer \uAC00 \uAC00\uB824\uC9C0\uC9C0 \uC54A\uAC8C \uD55C\uB2E4. */
2375
+ z-index: 950;
2344
2376
  }
2345
2377
 
2346
2378
  .df-review-shell:not(.is-list-visible) .df-review-qa-panel,
@@ -6210,11 +6242,140 @@ function getReviewFigmaImageErrorMessage(error) {
6210
6242
  return error instanceof Error ? error.message : "Figma image request failed.";
6211
6243
  }
6212
6244
 
6213
- // src/react-shell/figma/image.overlay.controller.ts
6245
+ // src/react-shell/figma/image.overlay.state.ts
6246
+ var STORAGE_KEY_PREFIX = "df-review-figma-image-overlay-state:";
6247
+ var STORAGE_VERSION = 2;
6248
+ var DEFAULT_MODE = "normal";
6214
6249
  var DEFAULT_REVIEW_FIGMA_IMAGE_OVERLAY_OPACITY = 0.48;
6215
- var REVIEW_FIGMA_IMAGE_OVERLAY_STORAGE_KEY_PREFIX = "df-review-figma-image-overlay-state:";
6216
- var REVIEW_FIGMA_IMAGE_OVERLAY_STORAGE_VERSION = 2;
6217
- var DEFAULT_REVIEW_FIGMA_IMAGE_OVERLAY_MODE = "normal";
6250
+ var DEFAULT_REVIEW_FIGMA_IMAGE_OVERLAY_STATE = {
6251
+ selectedImageId: null,
6252
+ imageStates: {},
6253
+ lastVisibleImageIds: []
6254
+ };
6255
+ var DEFAULT_REVIEW_FIGMA_IMAGE_OVERLAY_ITEM_STATE = {
6256
+ isVisible: false,
6257
+ opacity: DEFAULT_REVIEW_FIGMA_IMAGE_OVERLAY_OPACITY,
6258
+ isLocked: false,
6259
+ mode: DEFAULT_MODE,
6260
+ offsetY: 0
6261
+ };
6262
+ function createReviewFigmaImageOverlayStorageKey(target) {
6263
+ return `${STORAGE_KEY_PREFIX}${createReviewFigmaImageTargetKey(target)}`;
6264
+ }
6265
+ function readStoredReviewFigmaImageOverlayState(storageKey) {
6266
+ if (typeof window === "undefined") {
6267
+ return DEFAULT_REVIEW_FIGMA_IMAGE_OVERLAY_STATE;
6268
+ }
6269
+ try {
6270
+ const value = window.localStorage.getItem(storageKey);
6271
+ if (!value) return DEFAULT_REVIEW_FIGMA_IMAGE_OVERLAY_STATE;
6272
+ return normalizeReviewFigmaImageOverlayState(JSON.parse(value));
6273
+ } catch {
6274
+ return DEFAULT_REVIEW_FIGMA_IMAGE_OVERLAY_STATE;
6275
+ }
6276
+ }
6277
+ function writeStoredReviewFigmaImageOverlayState(storageKey, state) {
6278
+ if (typeof window === "undefined") return;
6279
+ try {
6280
+ if (isDefaultReviewFigmaImageOverlayState(state)) {
6281
+ window.localStorage.removeItem(storageKey);
6282
+ return;
6283
+ }
6284
+ window.localStorage.setItem(
6285
+ storageKey,
6286
+ JSON.stringify({
6287
+ version: STORAGE_VERSION,
6288
+ ...state
6289
+ })
6290
+ );
6291
+ } catch {
6292
+ return;
6293
+ }
6294
+ }
6295
+ function normalizeReviewFigmaImageOverlayMode(value) {
6296
+ return value === "invert" ? "invert" : DEFAULT_MODE;
6297
+ }
6298
+ function normalizeReviewFigmaImageOverlayOffsetY(value) {
6299
+ if (typeof value !== "number" || !Number.isFinite(value)) return 0;
6300
+ return Math.round(value);
6301
+ }
6302
+ function clampReviewFigmaImageOverlayOpacity(value) {
6303
+ if (!Number.isFinite(value)) return DEFAULT_REVIEW_FIGMA_IMAGE_OVERLAY_OPACITY;
6304
+ return Math.min(1, Math.max(0, value));
6305
+ }
6306
+ function getReviewFigmaImageOverlayItemState(state, imageId) {
6307
+ return imageId ? state.imageStates[imageId] ?? DEFAULT_REVIEW_FIGMA_IMAGE_OVERLAY_ITEM_STATE : DEFAULT_REVIEW_FIGMA_IMAGE_OVERLAY_ITEM_STATE;
6308
+ }
6309
+ function updateSelectedReviewFigmaImageOverlayItemState(state, updater) {
6310
+ return state.selectedImageId ? updateReviewFigmaImageOverlayItemState(
6311
+ state.imageStates,
6312
+ state.selectedImageId,
6313
+ updater
6314
+ ) : state.imageStates;
6315
+ }
6316
+ function updateReviewFigmaImageOverlayItemState(imageStates, imageId, updater) {
6317
+ return {
6318
+ ...imageStates,
6319
+ [imageId]: updater(
6320
+ imageStates[imageId] ?? DEFAULT_REVIEW_FIGMA_IMAGE_OVERLAY_ITEM_STATE
6321
+ )
6322
+ };
6323
+ }
6324
+ function normalizeReviewFigmaImageOverlayState(value) {
6325
+ if (!value || typeof value !== "object") {
6326
+ return DEFAULT_REVIEW_FIGMA_IMAGE_OVERLAY_STATE;
6327
+ }
6328
+ const state = value;
6329
+ const selectedImageId = typeof state.selectedImageId === "string" ? state.selectedImageId : null;
6330
+ const lastVisibleImageIds = Array.isArray(state.lastVisibleImageIds) ? state.lastVisibleImageIds.filter(
6331
+ (imageId) => typeof imageId === "string"
6332
+ ) : [];
6333
+ const imageStates = normalizeReviewFigmaImageOverlayItemStateRecord(
6334
+ state.imageStates
6335
+ );
6336
+ if (Object.keys(imageStates).length === 0 && selectedImageId) {
6337
+ imageStates[selectedImageId] = normalizeReviewFigmaImageOverlayItemState(
6338
+ state
6339
+ );
6340
+ }
6341
+ return {
6342
+ selectedImageId,
6343
+ imageStates,
6344
+ lastVisibleImageIds
6345
+ };
6346
+ }
6347
+ function normalizeReviewFigmaImageOverlayItemStateRecord(value) {
6348
+ if (!value || typeof value !== "object") return {};
6349
+ return Object.fromEntries(
6350
+ Object.entries(value).flatMap(([imageId, itemState]) => {
6351
+ if (!imageId || typeof itemState !== "object") return [];
6352
+ return [
6353
+ [
6354
+ imageId,
6355
+ normalizeReviewFigmaImageOverlayItemState(
6356
+ itemState
6357
+ )
6358
+ ]
6359
+ ];
6360
+ })
6361
+ );
6362
+ }
6363
+ function normalizeReviewFigmaImageOverlayItemState(value) {
6364
+ return {
6365
+ isVisible: value.isVisible === true,
6366
+ opacity: clampReviewFigmaImageOverlayOpacity(
6367
+ typeof value.opacity === "number" ? value.opacity : DEFAULT_REVIEW_FIGMA_IMAGE_OVERLAY_OPACITY
6368
+ ),
6369
+ isLocked: value.isLocked === true,
6370
+ mode: normalizeReviewFigmaImageOverlayMode(value.mode),
6371
+ offsetY: normalizeReviewFigmaImageOverlayOffsetY(value.offsetY)
6372
+ };
6373
+ }
6374
+ function isDefaultReviewFigmaImageOverlayState(state) {
6375
+ return state.selectedImageId === null && Object.keys(state.imageStates).length === 0 && state.lastVisibleImageIds.length === 0;
6376
+ }
6377
+
6378
+ // src/react-shell/figma/image.overlay.controller.ts
6218
6379
  var useReviewFigmaImageOverlayController = ({
6219
6380
  images,
6220
6381
  isLoading,
@@ -6233,8 +6394,12 @@ var useReviewFigmaImageOverlayController = ({
6233
6394
  (updater) => {
6234
6395
  setStateContainer((currentContainer) => {
6235
6396
  const currentState = currentContainer.storageKey === storageKey ? currentContainer.state : readStoredReviewFigmaImageOverlayState(storageKey);
6397
+ const nextState = updater(currentState);
6398
+ if (currentContainer.storageKey === storageKey && nextState === currentState) {
6399
+ return currentContainer;
6400
+ }
6236
6401
  return {
6237
- state: updater(currentState),
6402
+ state: nextState,
6238
6403
  storageKey
6239
6404
  };
6240
6405
  });
@@ -6274,7 +6439,7 @@ var useReviewFigmaImageOverlayController = ({
6274
6439
  const lastVisibleImageIds = currentState.lastVisibleImageIds.filter(
6275
6440
  (imageId) => nextImageIds.has(imageId)
6276
6441
  );
6277
- if (selectedImageId === currentState.selectedImageId && imageStates === currentState.imageStates && lastVisibleImageIds.length === currentState.lastVisibleImageIds.length) {
6442
+ if (selectedImageId === currentState.selectedImageId && Object.keys(imageStates).length === Object.keys(currentState.imageStates).length && lastVisibleImageIds.length === currentState.lastVisibleImageIds.length) {
6278
6443
  return currentState;
6279
6444
  }
6280
6445
  return {
@@ -6471,78 +6636,54 @@ var useReviewFigmaImageOverlayController = ({
6471
6636
  };
6472
6637
  });
6473
6638
  }, [images, updateState]);
6639
+ const updateSelectedOverlayState = (0, import_react7.useCallback)(
6640
+ (updater) => {
6641
+ updateState((currentState) => ({
6642
+ ...currentState,
6643
+ imageStates: updateSelectedReviewFigmaImageOverlayItemState(
6644
+ currentState,
6645
+ updater
6646
+ )
6647
+ }));
6648
+ },
6649
+ [updateState]
6650
+ );
6474
6651
  const setOverlayOpacity = (0, import_react7.useCallback)((opacity) => {
6475
- updateState((currentState) => ({
6476
- ...currentState,
6477
- imageStates: updateSelectedReviewFigmaImageOverlayItemState(
6478
- currentState,
6479
- (itemState) => ({
6480
- ...itemState,
6481
- opacity: clampReviewFigmaImageOverlayOpacity(opacity)
6482
- })
6483
- )
6652
+ updateSelectedOverlayState((itemState) => ({
6653
+ ...itemState,
6654
+ opacity: clampReviewFigmaImageOverlayOpacity(opacity)
6484
6655
  }));
6485
- }, [updateState]);
6656
+ }, [updateSelectedOverlayState]);
6486
6657
  const setOverlayLocked = (0, import_react7.useCallback)((isLocked) => {
6487
- updateState((currentState) => ({
6488
- ...currentState,
6489
- imageStates: updateSelectedReviewFigmaImageOverlayItemState(
6490
- currentState,
6491
- (itemState) => ({
6492
- ...itemState,
6493
- isLocked
6494
- })
6495
- )
6658
+ updateSelectedOverlayState((itemState) => ({
6659
+ ...itemState,
6660
+ isLocked
6496
6661
  }));
6497
- }, [updateState]);
6662
+ }, [updateSelectedOverlayState]);
6498
6663
  const toggleOverlayLocked = (0, import_react7.useCallback)(() => {
6499
- updateState((currentState) => ({
6500
- ...currentState,
6501
- imageStates: updateSelectedReviewFigmaImageOverlayItemState(
6502
- currentState,
6503
- (itemState) => ({
6504
- ...itemState,
6505
- isLocked: !itemState.isLocked
6506
- })
6507
- )
6664
+ updateSelectedOverlayState((itemState) => ({
6665
+ ...itemState,
6666
+ isLocked: !itemState.isLocked
6508
6667
  }));
6509
- }, [updateState]);
6668
+ }, [updateSelectedOverlayState]);
6510
6669
  const setOverlayMode = (0, import_react7.useCallback)((mode) => {
6511
- updateState((currentState) => ({
6512
- ...currentState,
6513
- imageStates: updateSelectedReviewFigmaImageOverlayItemState(
6514
- currentState,
6515
- (itemState) => ({
6516
- ...itemState,
6517
- mode: normalizeReviewFigmaImageOverlayMode(mode)
6518
- })
6519
- )
6670
+ updateSelectedOverlayState((itemState) => ({
6671
+ ...itemState,
6672
+ mode: normalizeReviewFigmaImageOverlayMode(mode)
6520
6673
  }));
6521
- }, [updateState]);
6674
+ }, [updateSelectedOverlayState]);
6522
6675
  const toggleOverlayMode = (0, import_react7.useCallback)(() => {
6523
- updateState((currentState) => ({
6524
- ...currentState,
6525
- imageStates: updateSelectedReviewFigmaImageOverlayItemState(
6526
- currentState,
6527
- (itemState) => ({
6528
- ...itemState,
6529
- mode: itemState.mode === "invert" ? "normal" : "invert"
6530
- })
6531
- )
6676
+ updateSelectedOverlayState((itemState) => ({
6677
+ ...itemState,
6678
+ mode: itemState.mode === "invert" ? "normal" : "invert"
6532
6679
  }));
6533
- }, [updateState]);
6680
+ }, [updateSelectedOverlayState]);
6534
6681
  const setOverlayOffsetY = (0, import_react7.useCallback)((offsetY) => {
6535
- updateState((currentState) => ({
6536
- ...currentState,
6537
- imageStates: updateSelectedReviewFigmaImageOverlayItemState(
6538
- currentState,
6539
- (itemState) => ({
6540
- ...itemState,
6541
- offsetY: normalizeReviewFigmaImageOverlayOffsetY(offsetY)
6542
- })
6543
- )
6682
+ updateSelectedOverlayState((itemState) => ({
6683
+ ...itemState,
6684
+ offsetY: normalizeReviewFigmaImageOverlayOffsetY(offsetY)
6544
6685
  }));
6545
- }, [updateState]);
6686
+ }, [updateSelectedOverlayState]);
6546
6687
  const resetOverlay = (0, import_react7.useCallback)(() => {
6547
6688
  updateState((currentState) => ({
6548
6689
  ...currentState,
@@ -6583,160 +6724,29 @@ var useReviewFigmaImageOverlayController = ({
6583
6724
  toggleOverlayVisible
6584
6725
  };
6585
6726
  };
6586
- function createReviewFigmaImageOverlayStorageKey(target) {
6587
- return `${REVIEW_FIGMA_IMAGE_OVERLAY_STORAGE_KEY_PREFIX}${createReviewFigmaImageTargetKey(target)}`;
6727
+
6728
+ // src/react-shell/figma/image-panel.utils.ts
6729
+ var DEFAULT_FIGMA_IMAGE_LAYER_STATE = {
6730
+ isLocked: false,
6731
+ isVisible: false,
6732
+ mode: "normal",
6733
+ offsetY: 0,
6734
+ opacity: DEFAULT_REVIEW_FIGMA_IMAGE_OVERLAY_OPACITY
6735
+ };
6736
+ function getFigmaImageLabel(image, index) {
6737
+ return image.label?.trim() || `Image ${index + 1}`;
6588
6738
  }
6589
- function readStoredReviewFigmaImageOverlayState(storageKey) {
6590
- if (typeof window === "undefined") {
6591
- return DEFAULT_REVIEW_FIGMA_IMAGE_OVERLAY_STATE;
6592
- }
6593
- try {
6594
- const value = window.localStorage.getItem(storageKey);
6595
- if (!value) return DEFAULT_REVIEW_FIGMA_IMAGE_OVERLAY_STATE;
6596
- return normalizeReviewFigmaImageOverlayState(JSON.parse(value));
6597
- } catch {
6598
- return DEFAULT_REVIEW_FIGMA_IMAGE_OVERLAY_STATE;
6599
- }
6739
+ function getSnappedOpacityPercent(opacity) {
6740
+ const opacityPercent = Math.round(opacity * 100);
6741
+ if (!Number.isFinite(opacityPercent)) return 0;
6742
+ return Math.max(0, Math.min(100, Math.round(opacityPercent / 10) * 10));
6600
6743
  }
6601
- function writeStoredReviewFigmaImageOverlayState(storageKey, state) {
6602
- if (typeof window === "undefined") return;
6603
- if (isDefaultReviewFigmaImageOverlayState(state)) {
6604
- try {
6605
- window.localStorage.removeItem(storageKey);
6606
- } catch {
6607
- return;
6608
- }
6609
- return;
6610
- }
6611
- try {
6612
- window.localStorage.setItem(
6613
- storageKey,
6614
- JSON.stringify({
6615
- version: REVIEW_FIGMA_IMAGE_OVERLAY_STORAGE_VERSION,
6616
- ...state
6617
- })
6618
- );
6619
- } catch {
6620
- return;
6621
- }
6622
- }
6623
- var DEFAULT_REVIEW_FIGMA_IMAGE_OVERLAY_STATE = {
6624
- selectedImageId: null,
6625
- imageStates: {},
6626
- lastVisibleImageIds: []
6627
- };
6628
- var DEFAULT_REVIEW_FIGMA_IMAGE_OVERLAY_ITEM_STATE = {
6629
- isVisible: false,
6630
- opacity: DEFAULT_REVIEW_FIGMA_IMAGE_OVERLAY_OPACITY,
6631
- isLocked: false,
6632
- mode: DEFAULT_REVIEW_FIGMA_IMAGE_OVERLAY_MODE,
6633
- offsetY: 0
6634
- };
6635
- function normalizeReviewFigmaImageOverlayState(value) {
6636
- if (!value || typeof value !== "object") {
6637
- return DEFAULT_REVIEW_FIGMA_IMAGE_OVERLAY_STATE;
6638
- }
6639
- const state = value;
6640
- const selectedImageId = typeof state.selectedImageId === "string" ? state.selectedImageId : null;
6641
- const lastVisibleImageIds = Array.isArray(state.lastVisibleImageIds) ? state.lastVisibleImageIds.filter(
6642
- (imageId) => typeof imageId === "string"
6643
- ) : [];
6644
- const imageStates = normalizeReviewFigmaImageOverlayItemStateRecord(
6645
- state.imageStates
6646
- );
6647
- if (Object.keys(imageStates).length === 0 && selectedImageId) {
6648
- imageStates[selectedImageId] = normalizeReviewFigmaImageOverlayItemState(
6649
- state
6650
- );
6651
- }
6652
- return {
6653
- selectedImageId,
6654
- imageStates,
6655
- lastVisibleImageIds
6656
- };
6657
- }
6658
- function normalizeReviewFigmaImageOverlayItemStateRecord(value) {
6659
- if (!value || typeof value !== "object") return {};
6660
- return Object.fromEntries(
6661
- Object.entries(value).flatMap(([imageId, itemState]) => {
6662
- if (!imageId || typeof itemState !== "object") return [];
6663
- return [
6664
- [
6665
- imageId,
6666
- normalizeReviewFigmaImageOverlayItemState(
6667
- itemState
6668
- )
6669
- ]
6670
- ];
6671
- })
6672
- );
6673
- }
6674
- function normalizeReviewFigmaImageOverlayItemState(value) {
6675
- return {
6676
- isVisible: value.isVisible === true,
6677
- opacity: clampReviewFigmaImageOverlayOpacity(
6678
- typeof value.opacity === "number" ? value.opacity : DEFAULT_REVIEW_FIGMA_IMAGE_OVERLAY_OPACITY
6679
- ),
6680
- isLocked: value.isLocked === true,
6681
- mode: normalizeReviewFigmaImageOverlayMode(value.mode),
6682
- offsetY: normalizeReviewFigmaImageOverlayOffsetY(value.offsetY)
6683
- };
6684
- }
6685
- function normalizeReviewFigmaImageOverlayMode(value) {
6686
- return value === "invert" ? "invert" : DEFAULT_REVIEW_FIGMA_IMAGE_OVERLAY_MODE;
6687
- }
6688
- function normalizeReviewFigmaImageOverlayOffsetY(value) {
6689
- if (typeof value !== "number" || !Number.isFinite(value)) return 0;
6690
- return Math.round(value);
6691
- }
6692
- function clampReviewFigmaImageOverlayOpacity(value) {
6693
- if (!Number.isFinite(value)) return DEFAULT_REVIEW_FIGMA_IMAGE_OVERLAY_OPACITY;
6694
- return Math.min(1, Math.max(0, value));
6695
- }
6696
- function isDefaultReviewFigmaImageOverlayState(state) {
6697
- return state.selectedImageId === null && Object.keys(state.imageStates).length === 0 && state.lastVisibleImageIds.length === 0;
6698
- }
6699
- function getReviewFigmaImageOverlayItemState(state, imageId) {
6700
- return imageId ? state.imageStates[imageId] ?? DEFAULT_REVIEW_FIGMA_IMAGE_OVERLAY_ITEM_STATE : DEFAULT_REVIEW_FIGMA_IMAGE_OVERLAY_ITEM_STATE;
6701
- }
6702
- function updateSelectedReviewFigmaImageOverlayItemState(state, updater) {
6703
- return state.selectedImageId ? updateReviewFigmaImageOverlayItemState(
6704
- state.imageStates,
6705
- state.selectedImageId,
6706
- updater
6707
- ) : state.imageStates;
6708
- }
6709
- function updateReviewFigmaImageOverlayItemState(imageStates, imageId, updater) {
6710
- return {
6711
- ...imageStates,
6712
- [imageId]: updater(
6713
- imageStates[imageId] ?? DEFAULT_REVIEW_FIGMA_IMAGE_OVERLAY_ITEM_STATE
6714
- )
6715
- };
6716
- }
6717
-
6718
- // src/react-shell/figma/image-panel.utils.ts
6719
- var DEFAULT_FIGMA_IMAGE_LAYER_STATE = {
6720
- isLocked: false,
6721
- isVisible: false,
6722
- mode: "normal",
6723
- offsetY: 0,
6724
- opacity: DEFAULT_REVIEW_FIGMA_IMAGE_OVERLAY_OPACITY
6725
- };
6726
- function getFigmaImageLabel(image, index) {
6727
- return image.label?.trim() || `Image ${index + 1}`;
6728
- }
6729
- function getSnappedOpacityPercent(opacity) {
6730
- const opacityPercent = Math.round(opacity * 100);
6731
- if (!Number.isFinite(opacityPercent)) return 0;
6732
- return Math.max(0, Math.min(100, Math.round(opacityPercent / 10) * 10));
6733
- }
6734
- function getFigmaImageLayerStatusLabel(overlayState) {
6735
- return [
6736
- overlayState.isVisible ? "Visible" : "Hidden",
6737
- overlayState.mode === "invert" ? "Invert" : "",
6738
- overlayState.isLocked ? "Locked" : ""
6739
- ].filter(Boolean).join(" / ");
6744
+ function getFigmaImageLayerStatusLabel(overlayState) {
6745
+ return [
6746
+ overlayState.isVisible ? "Visible" : "Hidden",
6747
+ overlayState.mode === "invert" ? "Invert" : "",
6748
+ overlayState.isLocked ? "Locked" : ""
6749
+ ].filter(Boolean).join(" / ");
6740
6750
  }
6741
6751
  function getReorderedFigmaImageIds(images, draggedImageId, dropTargetImageId) {
6742
6752
  const currentImageIds = images.map((image) => image.id);
@@ -7571,11 +7581,19 @@ var updateShellUrl = (target, size, source) => {
7571
7581
  }
7572
7582
  url.searchParams.delete("item");
7573
7583
  url.searchParams.delete("panel");
7574
- window.history.replaceState(null, "", `${url.pathname}${url.search}`);
7584
+ window.history.replaceState(
7585
+ null,
7586
+ "",
7587
+ `${url.pathname}${url.search}${url.hash}`
7588
+ );
7575
7589
  };
7576
7590
  var updateShellUrlForItem = (target, size, itemId, source) => {
7577
7591
  const url = getShellUrlForItem(target, size, itemId, source);
7578
- window.history.replaceState(null, "", `${url.pathname}${url.search}`);
7592
+ window.history.replaceState(
7593
+ null,
7594
+ "",
7595
+ `${url.pathname}${url.search}${url.hash}`
7596
+ );
7579
7597
  };
7580
7598
  var getShellUrlForItem = (target, size, itemId, source) => {
7581
7599
  const url = new URL(window.location.href);
@@ -9850,6 +9868,26 @@ var REVIEW_QA_STATUS_FILTER_VALUES = /* @__PURE__ */ new Set([
9850
9868
  "hold",
9851
9869
  "done"
9852
9870
  ]);
9871
+ var readStorage = (key) => {
9872
+ if (typeof window === "undefined") return null;
9873
+ try {
9874
+ return window.localStorage.getItem(key);
9875
+ } catch {
9876
+ return null;
9877
+ }
9878
+ };
9879
+ var writeStorage = (key, value) => {
9880
+ if (typeof window === "undefined") return;
9881
+ try {
9882
+ if (value === null) {
9883
+ window.localStorage.removeItem(key);
9884
+ } else {
9885
+ window.localStorage.setItem(key, value);
9886
+ }
9887
+ } catch {
9888
+ return;
9889
+ }
9890
+ };
9853
9891
  var normalizeReviewTheme = (value) => value === "light" || value === "system" || value === "dark" ? value : DEFAULT_REVIEW_THEME;
9854
9892
  var normalizeReviewSidePanel = (value) => {
9855
9893
  if (value === "qa" || value === "source" || value === "figma-images") {
@@ -9888,100 +9926,35 @@ var normalizeStoredSourceTreeMetaVisibility = (value) => {
9888
9926
  className: typeof metaVisibility.className === "boolean" ? metaVisibility.className : DEFAULT_SOURCE_TREE_META_VISIBILITY.className
9889
9927
  };
9890
9928
  };
9891
- var getStoredFigmaToken = () => {
9892
- if (typeof window === "undefined") return "";
9893
- try {
9894
- return window.localStorage.getItem(FIGMA_TOKEN_STORAGE_KEY) ?? "";
9895
- } catch {
9896
- return "";
9897
- }
9898
- };
9929
+ var getStoredFigmaToken = () => readStorage(FIGMA_TOKEN_STORAGE_KEY) ?? "";
9899
9930
  var writeStoredFigmaToken = (token) => {
9900
- if (typeof window === "undefined") return;
9901
- try {
9902
- if (token) {
9903
- window.localStorage.setItem(FIGMA_TOKEN_STORAGE_KEY, token);
9904
- } else {
9905
- window.localStorage.removeItem(FIGMA_TOKEN_STORAGE_KEY);
9906
- }
9907
- } catch {
9908
- return;
9909
- }
9931
+ writeStorage(FIGMA_TOKEN_STORAGE_KEY, token || null);
9910
9932
  };
9911
9933
  var getStoredReviewUserId = (fallback = "") => {
9912
9934
  const normalizedFallback = fallback.trim();
9913
- if (typeof window === "undefined") return normalizedFallback;
9914
- try {
9915
- return window.localStorage.getItem(REVIEW_USER_ID_STORAGE_KEY)?.trim() || normalizedFallback;
9916
- } catch {
9917
- return normalizedFallback;
9918
- }
9935
+ return readStorage(REVIEW_USER_ID_STORAGE_KEY)?.trim() || normalizedFallback;
9919
9936
  };
9920
9937
  var writeStoredReviewUserId = (userId) => {
9921
- if (typeof window === "undefined") return;
9922
- try {
9923
- if (userId) {
9924
- window.localStorage.setItem(REVIEW_USER_ID_STORAGE_KEY, userId);
9925
- } else {
9926
- window.localStorage.removeItem(REVIEW_USER_ID_STORAGE_KEY);
9927
- }
9928
- } catch {
9929
- return;
9930
- }
9931
- };
9932
- var getStoredReviewTheme = () => {
9933
- if (typeof window === "undefined") return DEFAULT_REVIEW_THEME;
9934
- try {
9935
- return normalizeReviewTheme(
9936
- window.localStorage.getItem(REVIEW_THEME_STORAGE_KEY)
9937
- );
9938
- } catch {
9939
- return DEFAULT_REVIEW_THEME;
9940
- }
9938
+ writeStorage(REVIEW_USER_ID_STORAGE_KEY, userId || null);
9941
9939
  };
9940
+ var getStoredReviewTheme = () => normalizeReviewTheme(readStorage(REVIEW_THEME_STORAGE_KEY));
9942
9941
  var writeStoredReviewTheme = (theme) => {
9943
- if (typeof window === "undefined") return;
9944
- try {
9945
- if (theme === DEFAULT_REVIEW_THEME) {
9946
- window.localStorage.removeItem(REVIEW_THEME_STORAGE_KEY);
9947
- } else {
9948
- window.localStorage.setItem(REVIEW_THEME_STORAGE_KEY, theme);
9949
- }
9950
- } catch {
9951
- return;
9952
- }
9942
+ writeStorage(
9943
+ REVIEW_THEME_STORAGE_KEY,
9944
+ theme === DEFAULT_REVIEW_THEME ? null : theme
9945
+ );
9953
9946
  };
9954
9947
  var getStoredReviewTooltipsEnabled = () => {
9955
- if (typeof window === "undefined") return DEFAULT_REVIEW_TOOLTIPS_ENABLED;
9956
- try {
9957
- const value = window.localStorage.getItem(REVIEW_TOOLTIP_STORAGE_KEY);
9958
- return value === null ? DEFAULT_REVIEW_TOOLTIPS_ENABLED : value !== "false";
9959
- } catch {
9960
- return DEFAULT_REVIEW_TOOLTIPS_ENABLED;
9961
- }
9948
+ const value = readStorage(REVIEW_TOOLTIP_STORAGE_KEY);
9949
+ return value === null ? DEFAULT_REVIEW_TOOLTIPS_ENABLED : value !== "false";
9962
9950
  };
9963
9951
  var writeStoredReviewTooltipsEnabled = (isEnabled) => {
9964
- if (typeof window === "undefined") return;
9965
- try {
9966
- if (isEnabled === DEFAULT_REVIEW_TOOLTIPS_ENABLED) {
9967
- window.localStorage.removeItem(REVIEW_TOOLTIP_STORAGE_KEY);
9968
- } else {
9969
- window.localStorage.setItem(REVIEW_TOOLTIP_STORAGE_KEY, "false");
9970
- }
9971
- } catch {
9972
- return;
9973
- }
9974
- };
9975
- var getStoredReviewSidePanel = () => {
9976
- if (typeof window === "undefined") return "qa";
9977
- try {
9978
- return normalizeStoredReviewSidePanel(
9979
- window.localStorage.getItem(REVIEW_SIDE_PANEL_STORAGE_KEY)
9980
- );
9981
- } catch {
9982
- return "qa";
9983
- }
9952
+ writeStorage(
9953
+ REVIEW_TOOLTIP_STORAGE_KEY,
9954
+ isEnabled === DEFAULT_REVIEW_TOOLTIPS_ENABLED ? null : "false"
9955
+ );
9984
9956
  };
9957
+ var getStoredReviewSidePanel = () => normalizeStoredReviewSidePanel(readStorage(REVIEW_SIDE_PANEL_STORAGE_KEY));
9985
9958
  var getInitialReviewSidePanel = () => {
9986
9959
  if (typeof window === "undefined") return null;
9987
9960
  try {
@@ -9993,106 +9966,49 @@ var getInitialReviewSidePanel = () => {
9993
9966
  }
9994
9967
  };
9995
9968
  var writeStoredReviewSidePanel = (sidePanel) => {
9996
- if (typeof window === "undefined") return;
9997
- try {
9998
- window.localStorage.setItem(
9999
- REVIEW_SIDE_PANEL_STORAGE_KEY,
10000
- normalizeStoredReviewSidePanel(sidePanel)
10001
- );
10002
- } catch {
10003
- return;
10004
- }
9969
+ writeStorage(
9970
+ REVIEW_SIDE_PANEL_STORAGE_KEY,
9971
+ normalizeStoredReviewSidePanel(sidePanel)
9972
+ );
10005
9973
  };
10006
9974
  var getStoredReviewSidePanelVisible = () => {
10007
- if (typeof window === "undefined") return true;
10008
- try {
10009
- const value = window.localStorage.getItem(
10010
- REVIEW_SIDE_PANEL_VISIBLE_STORAGE_KEY
10011
- );
10012
- return value === null ? true : value === "true";
10013
- } catch {
10014
- return true;
10015
- }
9975
+ const value = readStorage(REVIEW_SIDE_PANEL_VISIBLE_STORAGE_KEY);
9976
+ return value === null ? true : value === "true";
10016
9977
  };
10017
9978
  var writeStoredReviewSidePanelVisible = (isVisible) => {
10018
- if (typeof window === "undefined") return;
10019
- try {
10020
- window.localStorage.setItem(
10021
- REVIEW_SIDE_PANEL_VISIBLE_STORAGE_KEY,
10022
- isVisible ? "true" : "false"
10023
- );
10024
- } catch {
10025
- return;
10026
- }
10027
- };
10028
- var getStoredReviewQaStatusFilters = () => {
10029
- if (typeof window === "undefined") return getDefaultReviewQaStatusFilters();
10030
- try {
10031
- return normalizeStoredReviewQaStatusFilters(
10032
- window.localStorage.getItem(REVIEW_QA_STATUS_FILTER_STORAGE_KEY)
10033
- );
10034
- } catch {
10035
- return getDefaultReviewQaStatusFilters();
10036
- }
9979
+ writeStorage(
9980
+ REVIEW_SIDE_PANEL_VISIBLE_STORAGE_KEY,
9981
+ isVisible ? "true" : "false"
9982
+ );
10037
9983
  };
9984
+ var getStoredReviewQaStatusFilters = () => normalizeStoredReviewQaStatusFilters(
9985
+ readStorage(REVIEW_QA_STATUS_FILTER_STORAGE_KEY)
9986
+ );
10038
9987
  var writeStoredReviewQaStatusFilters = (filters) => {
10039
- if (typeof window === "undefined") return;
10040
- try {
10041
- const normalizedFilters = normalizeReviewQaStatusFilters(filters);
10042
- if (isDefaultReviewQaStatusFilters(normalizedFilters)) {
10043
- window.localStorage.removeItem(REVIEW_QA_STATUS_FILTER_STORAGE_KEY);
10044
- } else {
10045
- window.localStorage.setItem(
10046
- REVIEW_QA_STATUS_FILTER_STORAGE_KEY,
10047
- JSON.stringify(normalizedFilters)
10048
- );
10049
- }
10050
- } catch {
10051
- return;
10052
- }
10053
- };
10054
- var getStoredSourceTreeFilter = () => {
10055
- if (typeof window === "undefined") return "";
10056
- try {
10057
- return window.localStorage.getItem(REVIEW_SOURCE_TREE_FILTER_STORAGE_KEY) ?? "";
10058
- } catch {
10059
- return "";
10060
- }
9988
+ const normalizedFilters = normalizeReviewQaStatusFilters(filters);
9989
+ writeStorage(
9990
+ REVIEW_QA_STATUS_FILTER_STORAGE_KEY,
9991
+ isDefaultReviewQaStatusFilters(normalizedFilters) ? null : JSON.stringify(normalizedFilters)
9992
+ );
10061
9993
  };
9994
+ var getStoredSourceTreeFilter = () => readStorage(REVIEW_SOURCE_TREE_FILTER_STORAGE_KEY) ?? "";
10062
9995
  var writeStoredSourceTreeFilter = (filter) => {
10063
- if (typeof window === "undefined") return;
10064
- try {
10065
- if (filter) {
10066
- window.localStorage.setItem(REVIEW_SOURCE_TREE_FILTER_STORAGE_KEY, filter);
10067
- } else {
10068
- window.localStorage.removeItem(REVIEW_SOURCE_TREE_FILTER_STORAGE_KEY);
10069
- }
10070
- } catch {
10071
- return;
10072
- }
9996
+ writeStorage(REVIEW_SOURCE_TREE_FILTER_STORAGE_KEY, filter || null);
10073
9997
  };
10074
9998
  var getStoredSourceTreeMetaVisibility = () => {
10075
- if (typeof window === "undefined") return DEFAULT_SOURCE_TREE_META_VISIBILITY;
9999
+ const value = readStorage(REVIEW_SOURCE_TREE_META_STORAGE_KEY);
10000
+ if (!value) return DEFAULT_SOURCE_TREE_META_VISIBILITY;
10076
10001
  try {
10077
- const value = window.localStorage.getItem(
10078
- REVIEW_SOURCE_TREE_META_STORAGE_KEY
10079
- );
10080
- if (!value) return DEFAULT_SOURCE_TREE_META_VISIBILITY;
10081
10002
  return normalizeStoredSourceTreeMetaVisibility(JSON.parse(value));
10082
10003
  } catch {
10083
10004
  return DEFAULT_SOURCE_TREE_META_VISIBILITY;
10084
10005
  }
10085
10006
  };
10086
10007
  var writeStoredSourceTreeMetaVisibility = (metaVisibility) => {
10087
- if (typeof window === "undefined") return;
10088
- try {
10089
- window.localStorage.setItem(
10090
- REVIEW_SOURCE_TREE_META_STORAGE_KEY,
10091
- JSON.stringify(normalizeStoredSourceTreeMetaVisibility(metaVisibility))
10092
- );
10093
- } catch {
10094
- return;
10095
- }
10008
+ writeStorage(
10009
+ REVIEW_SOURCE_TREE_META_STORAGE_KEY,
10010
+ JSON.stringify(normalizeStoredSourceTreeMetaVisibility(metaVisibility))
10011
+ );
10096
10012
  };
10097
10013
  var getSystemReviewTheme = () => {
10098
10014
  if (typeof window === "undefined" || !window.matchMedia) return "dark";
@@ -11070,6 +10986,73 @@ function getAdjustedDraftSelection(selection, draft, presets) {
11070
10986
  };
11071
10987
  }
11072
10988
 
10989
+ // src/core/hotkey.ts
10990
+ var HOTKEY_KEY_ALIASES = {
10991
+ q: ["\u3142", "\u3143"],
10992
+ w: ["\u3148", "\u3149"],
10993
+ e: ["\u3137", "\u3138"],
10994
+ r: ["\u3131", "\u3132"],
10995
+ t: ["\u3145", "\u3146"],
10996
+ y: ["\u315B"],
10997
+ u: ["\u3155"],
10998
+ i: ["\u3151"],
10999
+ o: ["\u3150", "\u3152"],
11000
+ p: ["\u3154", "\u3156"],
11001
+ a: ["\u3141"],
11002
+ s: ["\u3134"],
11003
+ d: ["\u3147"],
11004
+ f: ["\u3139"],
11005
+ g: ["\u314E"],
11006
+ h: ["\u3157"],
11007
+ j: ["\u3153"],
11008
+ k: ["\u314F"],
11009
+ l: ["\u3163"],
11010
+ z: ["\u314B"],
11011
+ x: ["\u314C"],
11012
+ c: ["\u314A"],
11013
+ v: ["\u314D"],
11014
+ b: ["\u3160"],
11015
+ n: ["\u315C"],
11016
+ m: ["\u3161"]
11017
+ };
11018
+ function isEditableEventTarget(event) {
11019
+ const path = event.composedPath?.() ?? [];
11020
+ const element = path[0] ?? event.target;
11021
+ if (!element || typeof element.tagName !== "string") return false;
11022
+ const tag = element.tagName;
11023
+ return tag === "INPUT" || tag === "TEXTAREA" || tag === "SELECT" || element.isContentEditable === true;
11024
+ }
11025
+ function isHotkey(event, hotkey) {
11026
+ const parts = hotkey.split("+").map((part) => part.trim().toLowerCase()).filter(Boolean);
11027
+ const key = parts.find(
11028
+ (part) => !["shift", "ctrl", "control", "alt", "meta", "cmd"].includes(part)
11029
+ );
11030
+ if (!key) return false;
11031
+ if (parts.includes("shift") !== event.shiftKey) return false;
11032
+ if ((parts.includes("ctrl") || parts.includes("control")) !== event.ctrlKey) {
11033
+ return false;
11034
+ }
11035
+ if (parts.includes("alt") !== event.altKey) return false;
11036
+ if ((parts.includes("meta") || parts.includes("cmd")) !== event.metaKey) {
11037
+ return false;
11038
+ }
11039
+ return isHotkeyKey(event, key);
11040
+ }
11041
+ function getHotkeyActionKey(event, keys) {
11042
+ return keys.find((key) => isHotkeyKey(event, key));
11043
+ }
11044
+ function isHotkeyKey(event, key) {
11045
+ const normalizedKey = key.toLowerCase();
11046
+ if (event.key.toLowerCase() === normalizedKey) return true;
11047
+ if (getHotkeyCode(normalizedKey) === event.code) return true;
11048
+ return HOTKEY_KEY_ALIASES[normalizedKey]?.includes(event.key) ?? false;
11049
+ }
11050
+ function getHotkeyCode(key) {
11051
+ if (/^[a-z]$/.test(key)) return `Key${key.toUpperCase()}`;
11052
+ if (/^[0-9]$/.test(key)) return `Digit${key}`;
11053
+ return void 0;
11054
+ }
11055
+
11073
11056
  // src/react-shell/source.open.ts
11074
11057
  var getSourceCandidates = (target, options) => {
11075
11058
  const startElement = getEventElement(target);
@@ -11155,7 +11138,7 @@ function createSourceCandidate(element, source, depth, kind, context) {
11155
11138
  const column = getSourcePosition(source.column);
11156
11139
  const position = line ? `:${line}${column ? `:${column}` : ""}` : "";
11157
11140
  return {
11158
- id: `${kind}:${getSourceCandidateKey(source)}:${repeatInfo?.index ?? 0}:${depth}`,
11141
+ id: `${kind}:${getSourceCandidateDedupeKey(source)}:${repeatInfo?.index ?? 0}:${depth}`,
11159
11142
  depth,
11160
11143
  element,
11161
11144
  filePath: getDisplaySourcePath(source.file) ?? fileName,
@@ -11185,16 +11168,6 @@ function takeVisibleSourceCandidates(candidates) {
11185
11168
  }
11186
11169
  return visible;
11187
11170
  }
11188
- function getSourceCandidateKey(source) {
11189
- return [
11190
- source.file,
11191
- source.component,
11192
- source.line,
11193
- source.column,
11194
- source.sectionId,
11195
- source.sectionIndex
11196
- ].filter(Boolean).join("|");
11197
- }
11198
11171
  function getSourceCandidateDedupeKey(source) {
11199
11172
  return [
11200
11173
  source.file,
@@ -11612,11 +11585,6 @@ var getSectionDomAdjustmentKeyDelta = (event) => {
11612
11585
  return null;
11613
11586
  };
11614
11587
  var isDomAdjustmentEmpty = (position) => position.x === 0 && position.y === 0;
11615
- var isEditableKeyTarget = (target) => {
11616
- if (!(target instanceof HTMLElement)) return false;
11617
- const tagName = target.tagName;
11618
- return tagName === "INPUT" || tagName === "TEXTAREA" || tagName === "SELECT" || target.isContentEditable;
11619
- };
11620
11588
  var COMPONENT_SELECTION_ACTION_SELECTOR = [
11621
11589
  "a",
11622
11590
  "button",
@@ -11786,7 +11754,7 @@ function useReviewSectionOutline({
11786
11754
  (0, import_react18.useEffect)(() => {
11787
11755
  if (!activeDomAdjustmentEntryId) return void 0;
11788
11756
  const handleKeyDown = (event) => {
11789
- if (isEditableKeyTarget(event.target)) return;
11757
+ if (isEditableEventTarget(event)) return;
11790
11758
  const delta = getSectionDomAdjustmentKeyDelta(event);
11791
11759
  if (!delta) return;
11792
11760
  const position = domAdjustmentManagerRef.current?.adjust(
@@ -13630,7 +13598,7 @@ var ReviewSettingsModal = ({
13630
13598
  // src/react-shell/sitemap/modal.tsx
13631
13599
  var import_react24 = require("react");
13632
13600
 
13633
- // src/react-shell/sitemap/tree.ts
13601
+ // src/react-shell/sitemap/count.ts
13634
13602
  var WORKFLOW_STATUSES = [
13635
13603
  "todo",
13636
13604
  "doing",
@@ -13654,33 +13622,11 @@ var createEmptySitemapQaCount = () => ({
13654
13622
  viewport: {}
13655
13623
  });
13656
13624
  var createSitemapViewportColumn = (preset, index) => ({
13625
+ // 크기가 같은 preset도 별도 열로 유지될 수 있게 순서를 key에 포함한다.
13657
13626
  key: `${index}:${preset.width}x${preset.height}`,
13658
13627
  label: preset.label,
13659
13628
  title: `${preset.label} ${preset.width}x${preset.height}`
13660
13629
  });
13661
- var normalizeSitemapHref = (href) => {
13662
- const [path = "/"] = href.split(/[?#]/);
13663
- const normalizedPath = path.startsWith("/") ? path : `/${path}`;
13664
- return normalizedPath || "/";
13665
- };
13666
- var getSitemapSegments = (href) => normalizeSitemapHref(href).split("/").map((segment) => segment.trim()).filter(Boolean);
13667
- var createSitemapNode = (href, label, isPage = false) => ({
13668
- href,
13669
- label,
13670
- isPage,
13671
- children: /* @__PURE__ */ new Map()
13672
- });
13673
- var mergeSitemapUsers = (users) => {
13674
- const userByKey = /* @__PURE__ */ new Map();
13675
- users.forEach((user) => {
13676
- const key = user.sessionId || user.userId;
13677
- const currentUser = userByKey.get(key);
13678
- if (!currentUser || Date.parse(user.updatedAt) >= Date.parse(currentUser.updatedAt)) {
13679
- userByKey.set(key, user);
13680
- }
13681
- });
13682
- return Array.from(userByKey.values());
13683
- };
13684
13630
  var addSitemapQaCounts = (first, second) => ({
13685
13631
  total: first.total + second.total,
13686
13632
  remaining: first.remaining + second.remaining,
@@ -13718,9 +13664,37 @@ var addSitemapQaCounts = (first, second) => ({
13718
13664
  {}
13719
13665
  )
13720
13666
  });
13667
+
13668
+ // src/react-shell/sitemap/tree.ts
13669
+ var SITEMAP_STATUS_FILTERS = ["todo", "review", "hold"];
13670
+ var normalizeSitemapHref = (href) => {
13671
+ const [path = "/"] = href.split(/[?#]/);
13672
+ const normalizedPath = path.startsWith("/") ? path : `/${path}`;
13673
+ return normalizedPath || "/";
13674
+ };
13675
+ var getSitemapSegments = (href) => normalizeSitemapHref(href).split("/").map((segment) => segment.trim()).filter(Boolean);
13676
+ var createSitemapNode = (href, label, isPage = false) => ({
13677
+ href,
13678
+ label,
13679
+ isPage,
13680
+ children: /* @__PURE__ */ new Map()
13681
+ });
13682
+ var mergeSitemapUsers = (users) => {
13683
+ const userByKey = /* @__PURE__ */ new Map();
13684
+ users.forEach((user) => {
13685
+ const key = user.sessionId || user.userId;
13686
+ const currentUser = userByKey.get(key);
13687
+ if (!currentUser || Date.parse(user.updatedAt) >= Date.parse(currentUser.updatedAt)) {
13688
+ userByKey.set(key, user);
13689
+ }
13690
+ });
13691
+ return Array.from(userByKey.values());
13692
+ };
13721
13693
  var createSitemapRows = (pages, activeRoute, pageQaCounts, pagePresenceUsers, getPageTarget, options = {}) => {
13722
13694
  const collapsedFolderHrefs = options.collapsedFolderHrefs ?? /* @__PURE__ */ new Set();
13723
13695
  const searchQuery = normalizeSitemapSearchQuery(options.searchQuery);
13696
+ const statusFilters = options.statusFilters ?? /* @__PURE__ */ new Set();
13697
+ const isStatusFiltering = statusFilters.size > 0;
13724
13698
  const sortKey = options.sortKey ?? "page";
13725
13699
  const sortDirection = options.sortDirection ?? "asc";
13726
13700
  const root = createSitemapNode("/", "/", false);
@@ -13774,23 +13748,25 @@ var createSitemapRows = (pages, activeRoute, pageQaCounts, pagePresenceUsers, ge
13774
13748
  node,
13775
13749
  directCount,
13776
13750
  directUsers,
13751
+ // folder는 하위 page 합계, 실제 page는 자신의 수치를 별도로 보존한다.
13777
13752
  count: node.isPage ? addSitemapQaCounts(directCount, childAggregate.count) : childAggregate.count,
13778
13753
  users: mergeSitemapUsers([...directUsers, ...childAggregate.users]),
13779
13754
  children
13780
13755
  };
13781
13756
  };
13782
- const getSortValue = (summary) => {
13783
- if (sortKey === "page") return summary.node.label;
13784
- if (sortKey === "todo") return summary.count.status.todo;
13785
- if (sortKey === "review") return summary.count.status.review;
13786
- if (sortKey === "hold") return summary.count.status.hold;
13787
- if (sortKey === "online") return summary.users.length;
13757
+ const getSortValueFor = (label, count, users) => {
13758
+ if (sortKey === "page") return label;
13759
+ if (sortKey === "todo") return count.status.todo;
13760
+ if (sortKey === "review") return count.status.review;
13761
+ if (sortKey === "hold") return count.status.hold;
13762
+ if (sortKey === "online") return users.length;
13788
13763
  if (sortKey.startsWith("viewport:")) {
13789
13764
  const viewportKey = sortKey.slice("viewport:".length);
13790
- return summary.count.viewport[viewportKey]?.remaining ?? 0;
13765
+ return count.viewport[viewportKey]?.remaining ?? 0;
13791
13766
  }
13792
13767
  return 0;
13793
13768
  };
13769
+ const getSortValue = (summary) => getSortValueFor(summary.node.label, summary.count, summary.users);
13794
13770
  const sortSummaries = (summaries) => {
13795
13771
  return [...summaries].sort((a, b) => {
13796
13772
  const firstValue = getSortValue(a);
@@ -13811,6 +13787,53 @@ var createSitemapRows = (pages, activeRoute, pageQaCounts, pagePresenceUsers, ge
13811
13787
  }
13812
13788
  return summary.children.some(summaryMatchesSearch);
13813
13789
  };
13790
+ const countMatchesStatusFilters = (count) => Array.from(statusFilters).some((status) => count.status[status] > 0);
13791
+ if (isStatusFiltering) {
13792
+ const flatEntries = [];
13793
+ const collectMatchingPages = (node) => {
13794
+ if (node.isPage) {
13795
+ const directCount = getDirectCount(node);
13796
+ if (countMatchesStatusFilters(directCount) && (!searchQuery || sitemapNodeMatchesSearch(node, searchQuery, getPageTarget))) {
13797
+ flatEntries.push({
13798
+ node,
13799
+ count: directCount,
13800
+ users: getDirectUsers(node)
13801
+ });
13802
+ }
13803
+ }
13804
+ node.children.forEach(collectMatchingPages);
13805
+ };
13806
+ collectMatchingPages(root);
13807
+ return flatEntries.sort((a, b) => {
13808
+ const firstValue = getSortValueFor(
13809
+ normalizeSitemapHref(a.node.href),
13810
+ a.count,
13811
+ a.users
13812
+ );
13813
+ const secondValue = getSortValueFor(
13814
+ normalizeSitemapHref(b.node.href),
13815
+ b.count,
13816
+ b.users
13817
+ );
13818
+ const valueDiff = typeof firstValue === "string" && typeof secondValue === "string" ? firstValue.localeCompare(secondValue) : Number(firstValue) - Number(secondValue);
13819
+ if (valueDiff !== 0) {
13820
+ return sortDirection === "asc" ? valueDiff : -valueDiff;
13821
+ }
13822
+ const remainingDiff = b.count.remaining - a.count.remaining;
13823
+ if (remainingDiff !== 0) return remainingDiff;
13824
+ return a.node.href.localeCompare(b.node.href);
13825
+ }).map((entry) => ({
13826
+ href: entry.node.href,
13827
+ label: normalizeSitemapHref(entry.node.href),
13828
+ depth: 0,
13829
+ hasChildren: false,
13830
+ isExpanded: false,
13831
+ isPage: true,
13832
+ isActive: getPageTarget(entry.node.href) === activeRoute,
13833
+ qaCount: entry.count,
13834
+ users: entry.users
13835
+ }));
13836
+ }
13814
13837
  const rows = [];
13815
13838
  const appendSummaryRows = (summary, depth) => {
13816
13839
  const { node } = summary;
@@ -13878,8 +13901,70 @@ function sitemapNodeMatchesSearch(node, searchQuery, getPageTarget) {
13878
13901
  ].join(" ").toLowerCase().includes(searchQuery);
13879
13902
  }
13880
13903
 
13904
+ // src/react-shell/sitemap/row.tsx
13905
+ var import_jsx_runtime28 = require("react/jsx-runtime");
13906
+ var getCountCellClassName = (status, count) => [
13907
+ "df-review-sitemap-cell",
13908
+ `is-${status}`,
13909
+ count === 0 ? "is-zero" : ""
13910
+ ].filter(Boolean).join(" ");
13911
+ var SitemapRowContent = ({
13912
+ depth,
13913
+ hasChildren,
13914
+ isExpanded,
13915
+ isPage,
13916
+ label,
13917
+ qaCount,
13918
+ users,
13919
+ onToggleFolder
13920
+ }) => /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(import_jsx_runtime28.Fragment, { children: [
13921
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(
13922
+ "span",
13923
+ {
13924
+ className: "df-review-sitemap-path",
13925
+ style: { "--df-review-sitemap-depth": depth },
13926
+ children: [
13927
+ hasChildren ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
13928
+ "button",
13929
+ {
13930
+ "aria-expanded": isExpanded,
13931
+ "aria-label": `${isExpanded ? "Collapse" : "Expand"} ${label}`,
13932
+ className: "df-review-sitemap-tree-toggle",
13933
+ type: "button",
13934
+ onClick: (event) => {
13935
+ event.stopPropagation();
13936
+ onToggleFolder?.();
13937
+ },
13938
+ children: isExpanded ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(ChevronDown, { "aria-hidden": "true" }) : /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(ChevronRight, { "aria-hidden": "true" })
13939
+ }
13940
+ ) : /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { className: "df-review-sitemap-tree-spacer", "aria-hidden": "true" }),
13941
+ isPage ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { className: "df-review-sitemap-page-label", children: label }) : /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { className: "df-review-sitemap-label", children: label })
13942
+ ]
13943
+ }
13944
+ ),
13945
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { className: getCountCellClassName("todo", qaCount.status.todo), children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("strong", { children: qaCount.status.todo }) }),
13946
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { className: getCountCellClassName("review", qaCount.status.review), children: qaCount.status.review }),
13947
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { className: getCountCellClassName("hold", qaCount.status.hold), children: qaCount.status.hold }),
13948
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { className: "df-review-sitemap-cell is-online", children: users.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { className: "df-review-sitemap-users", children: users.map((user) => /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
13949
+ "span",
13950
+ {
13951
+ className: "df-review-sitemap-user",
13952
+ style: {
13953
+ "--df-review-presence-color": user.color
13954
+ },
13955
+ children: user.userId
13956
+ },
13957
+ user.sessionId
13958
+ )) }) : null })
13959
+ ] });
13960
+
13881
13961
  // src/react-shell/sitemap/modal.tsx
13882
- var import_jsx_runtime28 = require("react/jsx-runtime");
13962
+ var import_jsx_runtime29 = require("react/jsx-runtime");
13963
+ var STATUS_FILTER_LABELS = {
13964
+ todo: "Todo",
13965
+ review: "Review",
13966
+ hold: "Hold"
13967
+ };
13883
13968
  var getNextSortDirection = (current, key) => {
13884
13969
  if (current.key !== key) return key === "page" ? "asc" : "desc";
13885
13970
  return current.direction === "desc" ? "asc" : "desc";
@@ -13888,11 +13973,6 @@ var getSortIndicator = (sort, key) => {
13888
13973
  if (sort.key !== key) return "";
13889
13974
  return sort.direction === "desc" ? "\u2193" : "\u2191";
13890
13975
  };
13891
- var getCountCellClassName = (status, count) => [
13892
- "df-review-sitemap-cell",
13893
- `is-${status}`,
13894
- count === 0 ? "is-zero" : ""
13895
- ].filter(Boolean).join(" ");
13896
13976
  var mergePresenceUsers = (users) => {
13897
13977
  const userByKey = /* @__PURE__ */ new Map();
13898
13978
  users.forEach((user) => {
@@ -13905,6 +13985,7 @@ var mergePresenceUsers = (users) => {
13905
13985
  return Array.from(userByKey.values());
13906
13986
  };
13907
13987
  var SitemapModal = ({
13988
+ isOpen,
13908
13989
  pages,
13909
13990
  activeRoute,
13910
13991
  allQaCount,
@@ -13924,7 +14005,11 @@ var SitemapModal = ({
13924
14005
  () => /* @__PURE__ */ new Set()
13925
14006
  );
13926
14007
  const [searchQuery, setSearchQuery] = (0, import_react24.useState)("");
14008
+ const [statusFilters, setStatusFilters] = (0, import_react24.useState)(
14009
+ () => /* @__PURE__ */ new Set()
14010
+ );
13927
14011
  const trimmedSearchQuery = searchQuery.trim();
14012
+ const isFiltering = Boolean(trimmedSearchQuery) || statusFilters.size > 0;
13928
14013
  const allQaUsers = (0, import_react24.useMemo)(
13929
14014
  () => mergePresenceUsers(Array.from(pagePresenceUsers.values()).flat()),
13930
14015
  [pagePresenceUsers]
@@ -13939,7 +14024,8 @@ var SitemapModal = ({
13939
14024
  collapsedFolderHrefs,
13940
14025
  searchQuery: trimmedSearchQuery,
13941
14026
  sortKey: sort.key,
13942
- sortDirection: sort.direction
14027
+ sortDirection: sort.direction,
14028
+ statusFilters
13943
14029
  }
13944
14030
  );
13945
14031
  const matchingPageCount = sitemapRows.filter((row) => row.isPage).length;
@@ -13959,6 +14045,17 @@ var SitemapModal = ({
13959
14045
  direction: getNextSortDirection(current, key)
13960
14046
  }));
13961
14047
  };
14048
+ const toggleStatusFilter = (status) => {
14049
+ setStatusFilters((currentFilters) => {
14050
+ const nextFilters = new Set(currentFilters);
14051
+ if (nextFilters.has(status)) {
14052
+ nextFilters.delete(status);
14053
+ } else {
14054
+ nextFilters.add(status);
14055
+ }
14056
+ return nextFilters;
14057
+ });
14058
+ };
13962
14059
  const toggleFolder = (href) => {
13963
14060
  setCollapsedFolderHrefs((currentHrefs) => {
13964
14061
  const nextHrefs = new Set(currentHrefs);
@@ -13970,15 +14067,15 @@ var SitemapModal = ({
13970
14067
  return nextHrefs;
13971
14068
  });
13972
14069
  };
13973
- return /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(
14070
+ return /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(
13974
14071
  "div",
13975
14072
  {
13976
14073
  "aria-label": "Sitemap",
13977
14074
  "aria-modal": "true",
13978
- className: "df-review-sitemap-modal",
14075
+ className: `df-review-sitemap-modal${isOpen ? "" : " is-hidden"}`,
13979
14076
  role: "dialog",
13980
14077
  children: [
13981
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
14078
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
13982
14079
  "button",
13983
14080
  {
13984
14081
  "aria-label": "Close sitemap",
@@ -13987,28 +14084,39 @@ var SitemapModal = ({
13987
14084
  onClick: onClose
13988
14085
  }
13989
14086
  ),
13990
- /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: "df-review-sitemap-dialog", children: [
13991
- /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: "df-review-sitemap-header", children: [
13992
- /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { children: [
13993
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("strong", { children: "Sitemap" }),
13994
- /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("span", { children: [
14087
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "df-review-sitemap-dialog", children: [
14088
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "df-review-sitemap-header", children: [
14089
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { children: [
14090
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("strong", { children: "Sitemap" }),
14091
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("span", { children: [
13995
14092
  pages.length,
13996
- " pages \xB7 ",
13997
- allQaCount.status.todo,
13998
- " todo \xB7",
13999
- " ",
14000
- allQaCount.status.review,
14001
- " review \xB7 ",
14002
- allQaCount.status.hold,
14003
- " hold"
14093
+ " pages",
14094
+ SITEMAP_STATUS_FILTERS.map((status) => /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(import_react24.Fragment, { children: [
14095
+ " \xB7 ",
14096
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(
14097
+ "button",
14098
+ {
14099
+ "aria-pressed": statusFilters.has(status),
14100
+ className: `df-review-sitemap-summary-filter${statusFilters.has(status) ? " is-active" : ""}`,
14101
+ title: `Show pages with ${STATUS_FILTER_LABELS[status]} QA`,
14102
+ type: "button",
14103
+ onClick: () => toggleStatusFilter(status),
14104
+ children: [
14105
+ allQaCount.status[status],
14106
+ " ",
14107
+ status
14108
+ ]
14109
+ }
14110
+ )
14111
+ ] }, status))
14004
14112
  ] })
14005
14113
  ] }),
14006
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("button", { "aria-label": "Close sitemap", type: "button", onClick: onClose, children: "x" })
14114
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("button", { "aria-label": "Close sitemap", type: "button", onClick: onClose, children: "x" })
14007
14115
  ] }),
14008
- /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: "df-review-sitemap-controls", children: [
14009
- /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("label", { className: "df-review-sitemap-search", children: [
14010
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(Search, { "aria-hidden": "true" }),
14011
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
14116
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "df-review-sitemap-controls", children: [
14117
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("label", { className: "df-review-sitemap-search", children: [
14118
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(Search, { "aria-hidden": "true" }),
14119
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
14012
14120
  "input",
14013
14121
  {
14014
14122
  "aria-label": "Search sitemap",
@@ -14020,20 +14128,20 @@ var SitemapModal = ({
14020
14128
  }
14021
14129
  )
14022
14130
  ] }),
14023
- trimmedSearchQuery && /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
14131
+ trimmedSearchQuery && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
14024
14132
  "button",
14025
14133
  {
14026
14134
  "aria-label": "Clear sitemap search",
14027
14135
  className: "df-review-sitemap-search-clear",
14028
14136
  type: "button",
14029
14137
  onClick: () => setSearchQuery(""),
14030
- children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(X, { "aria-hidden": "true" })
14138
+ children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(X, { "aria-hidden": "true" })
14031
14139
  }
14032
14140
  ),
14033
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { className: "df-review-sitemap-search-count", children: trimmedSearchQuery ? `${matchingPageCount} matches` : `${pages.length} pages` })
14141
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { className: "df-review-sitemap-search-count", children: isFiltering ? `${matchingPageCount} matches` : `${pages.length} pages` })
14034
14142
  ] }),
14035
- /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: "df-review-sitemap-list", style: gridStyle, children: [
14036
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("div", { className: "df-review-sitemap-table-head", role: "row", children: sortHeaders.map((header) => /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(
14143
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "df-review-sitemap-list", style: gridStyle, children: [
14144
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("div", { className: "df-review-sitemap-table-head", role: "row", children: sortHeaders.map((header) => /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(
14037
14145
  "button",
14038
14146
  {
14039
14147
  "aria-label": `Sort sitemap by ${header.title ?? header.label}`,
@@ -14046,7 +14154,7 @@ var SitemapModal = ({
14046
14154
  type: "button",
14047
14155
  onClick: () => setSortKey(header.key),
14048
14156
  children: [
14049
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
14157
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
14050
14158
  "span",
14051
14159
  {
14052
14160
  "aria-hidden": "true",
@@ -14054,7 +14162,7 @@ var SitemapModal = ({
14054
14162
  children: getSortIndicator(sort, header.key)
14055
14163
  }
14056
14164
  ),
14057
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { className: "df-review-sitemap-sort-label", children: header.label })
14165
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { className: "df-review-sitemap-sort-label", children: header.label })
14058
14166
  ]
14059
14167
  },
14060
14168
  header.key
@@ -14069,7 +14177,7 @@ var SitemapModal = ({
14069
14177
  row.isActive ? "is-active" : "",
14070
14178
  row.isPage ? "is-clickable" : ""
14071
14179
  ].filter(Boolean).join(" ");
14072
- const rowContent = /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
14180
+ const rowContent = /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
14073
14181
  SitemapRowContent,
14074
14182
  {
14075
14183
  depth: row.depth,
@@ -14082,7 +14190,7 @@ var SitemapModal = ({
14082
14190
  onToggleFolder: () => toggleFolder(row.href)
14083
14191
  }
14084
14192
  );
14085
- return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
14193
+ return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
14086
14194
  "div",
14087
14195
  {
14088
14196
  "aria-label": row.isPage ? `${row.href} / ${row.qaCount.status.todo} todo / ${row.qaCount.status.review} review / ${row.qaCount.status.hold} hold / ${row.users.length} online` : `${row.href} group / ${row.qaCount.status.todo} todo / ${row.qaCount.status.review} review / ${row.qaCount.status.hold} hold / ${row.users.length} online`,
@@ -14101,15 +14209,15 @@ var SitemapModal = ({
14101
14209
  row.href
14102
14210
  );
14103
14211
  }),
14104
- sitemapRows.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("div", { className: "df-review-sitemap-empty", role: "status", children: "No matching pages" }),
14105
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
14212
+ sitemapRows.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("div", { className: "df-review-sitemap-empty", role: "status", children: "No matching pages" }),
14213
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
14106
14214
  "button",
14107
14215
  {
14108
14216
  "aria-label": `All QA / ${allQaCount.status.todo} todo / ${allQaCount.status.review} review / ${allQaCount.status.hold} hold`,
14109
14217
  className: `df-review-sitemap-row is-summary${isAllQaVisible ? " is-active" : ""}`,
14110
14218
  type: "button",
14111
14219
  onClick: onSelectAllQa,
14112
- children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
14220
+ children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
14113
14221
  SitemapRowContent,
14114
14222
  {
14115
14223
  depth: 0,
@@ -14129,55 +14237,6 @@ var SitemapModal = ({
14129
14237
  }
14130
14238
  );
14131
14239
  };
14132
- var SitemapRowContent = ({
14133
- depth,
14134
- hasChildren,
14135
- isExpanded,
14136
- isPage,
14137
- label,
14138
- qaCount,
14139
- users,
14140
- onToggleFolder
14141
- }) => /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(import_jsx_runtime28.Fragment, { children: [
14142
- /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(
14143
- "span",
14144
- {
14145
- className: "df-review-sitemap-path",
14146
- style: { "--df-review-sitemap-depth": depth },
14147
- children: [
14148
- hasChildren ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
14149
- "button",
14150
- {
14151
- "aria-expanded": isExpanded,
14152
- "aria-label": `${isExpanded ? "Collapse" : "Expand"} ${label}`,
14153
- className: "df-review-sitemap-tree-toggle",
14154
- type: "button",
14155
- onClick: (event) => {
14156
- event.stopPropagation();
14157
- onToggleFolder?.();
14158
- },
14159
- children: isExpanded ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(ChevronDown, { "aria-hidden": "true" }) : /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(ChevronRight, { "aria-hidden": "true" })
14160
- }
14161
- ) : /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { className: "df-review-sitemap-tree-spacer", "aria-hidden": "true" }),
14162
- isPage ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { className: "df-review-sitemap-page-label", children: label }) : /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { className: "df-review-sitemap-label", children: label })
14163
- ]
14164
- }
14165
- ),
14166
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { className: getCountCellClassName("todo", qaCount.status.todo), children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("strong", { children: qaCount.status.todo }) }),
14167
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { className: getCountCellClassName("review", qaCount.status.review), children: qaCount.status.review }),
14168
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { className: getCountCellClassName("hold", qaCount.status.hold), children: qaCount.status.hold }),
14169
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { className: "df-review-sitemap-cell is-online", children: users.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { className: "df-review-sitemap-users", children: users.map((user) => /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
14170
- "span",
14171
- {
14172
- className: "df-review-sitemap-user",
14173
- style: {
14174
- "--df-review-presence-color": user.color
14175
- },
14176
- children: user.userId
14177
- },
14178
- user.sessionId
14179
- )) }) : null })
14180
- ] });
14181
14240
 
14182
14241
  // src/react-shell/hooks/use.review.shell.data.ts
14183
14242
  var import_react25 = require("react");
@@ -14334,7 +14393,7 @@ var useReviewShellData = () => {
14334
14393
  };
14335
14394
 
14336
14395
  // src/react-shell/review/shell.modals.container.tsx
14337
- var import_jsx_runtime29 = require("react/jsx-runtime");
14396
+ var import_jsx_runtime30 = require("react/jsx-runtime");
14338
14397
  var ReviewShellModalsContainer = () => {
14339
14398
  const { initialPrompt, pages } = useReviewShellConfig();
14340
14399
  const {
@@ -14391,6 +14450,10 @@ var ReviewShellModalsContainer = () => {
14391
14450
  (state) => state.setIsSitemapOpen
14392
14451
  );
14393
14452
  const showToast = useReviewToast();
14453
+ const [hasSitemapOpened, setHasSitemapOpened] = (0, import_react26.useState)(false);
14454
+ (0, import_react26.useEffect)(() => {
14455
+ if (isSitemapOpen) setHasSitemapOpened(true);
14456
+ }, [isSitemapOpen]);
14394
14457
  const initialPromptText = initialPrompt.trim();
14395
14458
  const copyInitialPrompt = (0, import_react26.useCallback)(
14396
14459
  (value, key) => copyReviewPrompt({
@@ -14401,10 +14464,11 @@ var ReviewShellModalsContainer = () => {
14401
14464
  }),
14402
14465
  [setCopiedPromptKey, showToast]
14403
14466
  );
14404
- return /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(import_jsx_runtime29.Fragment, { children: [
14405
- isSitemapOpen && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
14467
+ return /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(import_jsx_runtime30.Fragment, { children: [
14468
+ hasSitemapOpened && /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
14406
14469
  SitemapModal,
14407
14470
  {
14471
+ isOpen: isSitemapOpen,
14408
14472
  activeRoute,
14409
14473
  allQaCount,
14410
14474
  getPageTarget,
@@ -14417,7 +14481,7 @@ var ReviewShellModalsContainer = () => {
14417
14481
  onSelectPage: selectPage
14418
14482
  }
14419
14483
  ),
14420
- isFigmaSettingsOpen && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
14484
+ isFigmaSettingsOpen && /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
14421
14485
  ReviewSettingsModal,
14422
14486
  {
14423
14487
  areTooltipsEnabledDraft,
@@ -14438,8 +14502,8 @@ var ReviewShellModalsContainer = () => {
14438
14502
  onToggleFigmaTokenVisible: () => setIsFigmaTokenVisible((current) => !current)
14439
14503
  }
14440
14504
  ),
14441
- isInitialPromptOpen && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(PromptModal, { onClose: () => setIsInitialPromptOpen(false) }),
14442
- isInitialPromptScriptOpen && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
14505
+ isInitialPromptOpen && /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(PromptModal, { onClose: () => setIsInitialPromptOpen(false) }),
14506
+ isInitialPromptScriptOpen && /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
14443
14507
  InitialPromptModal,
14444
14508
  {
14445
14509
  copiedPromptKey,
@@ -14494,7 +14558,7 @@ var useReviewSourceInspectorState = () => {
14494
14558
  };
14495
14559
 
14496
14560
  // src/react-shell/review/shell.providers.tsx
14497
- var import_jsx_runtime30 = require("react/jsx-runtime");
14561
+ var import_jsx_runtime31 = require("react/jsx-runtime");
14498
14562
  var ReviewShellProviders = ({
14499
14563
  actions,
14500
14564
  children,
@@ -14504,17 +14568,17 @@ var ReviewShellProviders = ({
14504
14568
  ruler,
14505
14569
  settings,
14506
14570
  sourceInspector
14507
- }) => /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(ReviewShellActionsProvider, { value: actions, children: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(ReviewRulerProvider, { value: ruler, children: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(ReviewFigmaImagesProvider, { value: figmaImages, children: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(ReviewSourceInspectorProvider, { value: sourceInspector, children: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(ReviewSettingsProvider, { value: settings, children: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(ReviewPresenceProvider, { value: presence, children: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(ReviewFigmaOverlayProvider, { value: figmaOverlay, children }) }) }) }) }) }) });
14571
+ }) => /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(ReviewShellActionsProvider, { value: actions, children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(ReviewRulerProvider, { value: ruler, children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(ReviewFigmaImagesProvider, { value: figmaImages, children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(ReviewSourceInspectorProvider, { value: sourceInspector, children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(ReviewSettingsProvider, { value: settings, children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(ReviewPresenceProvider, { value: presence, children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(ReviewFigmaOverlayProvider, { value: figmaOverlay, children }) }) }) }) }) }) });
14508
14572
 
14509
14573
  // src/react-shell/review/source.inspector.overlay.tsx
14510
- var import_jsx_runtime31 = require("react/jsx-runtime");
14574
+ var import_jsx_runtime32 = require("react/jsx-runtime");
14511
14575
  var SourceInspectorOverlay = ({
14512
14576
  componentSelectionState,
14513
14577
  state
14514
14578
  }) => {
14515
14579
  const hoverState = state?.targetElement === componentSelectionState?.targetElement ? null : state;
14516
- return /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(import_jsx_runtime31.Fragment, { children: [
14517
- componentSelectionState ? /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
14580
+ return /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(import_jsx_runtime32.Fragment, { children: [
14581
+ componentSelectionState ? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
14518
14582
  "div",
14519
14583
  {
14520
14584
  className: "df-review-source-outline is-component-selection",
@@ -14526,7 +14590,7 @@ var SourceInspectorOverlay = ({
14526
14590
  }
14527
14591
  }
14528
14592
  ) : null,
14529
- hoverState ? /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
14593
+ hoverState ? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
14530
14594
  "div",
14531
14595
  {
14532
14596
  className: "df-review-source-outline is-hover",
@@ -14542,10 +14606,10 @@ var SourceInspectorOverlay = ({
14542
14606
  };
14543
14607
 
14544
14608
  // src/react-shell/review/source.inspector.overlay.container.tsx
14545
- var import_jsx_runtime32 = require("react/jsx-runtime");
14609
+ var import_jsx_runtime33 = require("react/jsx-runtime");
14546
14610
  var SourceInspectorOverlayContainer = () => {
14547
14611
  const { componentSelectionState, sourceInspectorState } = useReviewSourceInspectorState();
14548
- return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
14612
+ return /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
14549
14613
  SourceInspectorOverlay,
14550
14614
  {
14551
14615
  componentSelectionState,
@@ -14558,7 +14622,7 @@ var SourceInspectorOverlayContainer = () => {
14558
14622
  var import_react32 = require("react");
14559
14623
 
14560
14624
  // src/react-shell/review/mode.toolbar.tsx
14561
- var import_jsx_runtime33 = require("react/jsx-runtime");
14625
+ var import_jsx_runtime34 = require("react/jsx-runtime");
14562
14626
  var ReviewModeToolbar = ({
14563
14627
  canWriteArea,
14564
14628
  canWriteDom,
@@ -14566,8 +14630,8 @@ var ReviewModeToolbar = ({
14566
14630
  onSetReviewMode
14567
14631
  }) => {
14568
14632
  if (!canWriteDom && !canWriteArea) return null;
14569
- return /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("div", { className: "df-review-mode", "aria-label": "Add QA", children: [
14570
- canWriteDom && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
14633
+ return /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("div", { className: "df-review-mode", "aria-label": "Add QA", children: [
14634
+ canWriteDom && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
14571
14635
  "button",
14572
14636
  {
14573
14637
  "aria-label": "Element",
@@ -14575,11 +14639,11 @@ var ReviewModeToolbar = ({
14575
14639
  "data-review-tooltip": "Element QA",
14576
14640
  type: "button",
14577
14641
  onClick: () => onSetReviewMode("element"),
14578
- children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(SquareMousePointer, { "aria-hidden": "true" })
14642
+ children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(SquareMousePointer, { "aria-hidden": "true" })
14579
14643
  }
14580
14644
  ),
14581
- canWriteDom && canWriteArea && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("span", { className: "df-review-mode-divider", "aria-hidden": "true", children: "|" }),
14582
- canWriteArea && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
14645
+ canWriteDom && canWriteArea && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { className: "df-review-mode-divider", "aria-hidden": "true", children: "|" }),
14646
+ canWriteArea && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
14583
14647
  "button",
14584
14648
  {
14585
14649
  "aria-label": "Area",
@@ -14587,14 +14651,14 @@ var ReviewModeToolbar = ({
14587
14651
  "data-review-tooltip": "Area QA",
14588
14652
  type: "button",
14589
14653
  onClick: () => onSetReviewMode("area"),
14590
- children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(Scan, { "aria-hidden": "true" })
14654
+ children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(Scan, { "aria-hidden": "true" })
14591
14655
  }
14592
14656
  )
14593
14657
  ] });
14594
14658
  };
14595
14659
 
14596
14660
  // src/react-shell/ruler/gutters.tsx
14597
- var import_jsx_runtime34 = require("react/jsx-runtime");
14661
+ var import_jsx_runtime35 = require("react/jsx-runtime");
14598
14662
  var RulerGutters = () => {
14599
14663
  const size = useReviewShellStore((state) => state.size);
14600
14664
  const {
@@ -14603,9 +14667,9 @@ var RulerGutters = () => {
14603
14667
  rulerScaleY,
14604
14668
  rulerUnit
14605
14669
  } = useReviewRulerState();
14606
- return /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(import_jsx_runtime34.Fragment, { children: [
14607
- /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("div", { className: "df-review-ruler-corner", "aria-hidden": "true" }),
14608
- /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(
14670
+ return /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)(import_jsx_runtime35.Fragment, { children: [
14671
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("div", { className: "df-review-ruler-corner", "aria-hidden": "true" }),
14672
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)(
14609
14673
  "div",
14610
14674
  {
14611
14675
  className: "df-review-ruler-gutter is-x",
@@ -14613,15 +14677,15 @@ var RulerGutters = () => {
14613
14677
  "--df-review-ruler-step-x": `${rulerScaleX * 20}px`
14614
14678
  },
14615
14679
  children: [
14616
- /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("div", { className: "df-review-ruler-frame-label", children: [
14617
- /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("strong", { children: size.label }),
14618
- /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("span", { children: [
14680
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("div", { className: "df-review-ruler-frame-label", children: [
14681
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("strong", { children: size.label }),
14682
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("span", { children: [
14619
14683
  size.designWidth,
14620
14684
  size.designHeight ? `x${size.designHeight}` : "",
14621
14685
  rulerUnit
14622
14686
  ] })
14623
14687
  ] }),
14624
- rulerHover && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
14688
+ rulerHover && /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
14625
14689
  "div",
14626
14690
  {
14627
14691
  className: "df-review-ruler-coord is-x",
@@ -14632,14 +14696,14 @@ var RulerGutters = () => {
14632
14696
  ]
14633
14697
  }
14634
14698
  ),
14635
- /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
14699
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
14636
14700
  "div",
14637
14701
  {
14638
14702
  className: "df-review-ruler-gutter is-y",
14639
14703
  style: {
14640
14704
  "--df-review-ruler-step-y": `${rulerScaleY * 20}px`
14641
14705
  },
14642
- children: rulerHover && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
14706
+ children: rulerHover && /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
14643
14707
  "div",
14644
14708
  {
14645
14709
  className: "df-review-ruler-coord is-y",
@@ -14653,7 +14717,7 @@ var RulerGutters = () => {
14653
14717
  };
14654
14718
 
14655
14719
  // src/react-shell/ruler/overlay.tsx
14656
- var import_jsx_runtime35 = require("react/jsx-runtime");
14720
+ var import_jsx_runtime36 = require("react/jsx-runtime");
14657
14721
  var RulerOverlay = () => {
14658
14722
  const { iframeRef } = useReviewShellRefs();
14659
14723
  const size = useReviewShellStore((state) => state.size);
@@ -14664,7 +14728,7 @@ var RulerOverlay = () => {
14664
14728
  rulerMeasureLabel,
14665
14729
  rulerOverlayRef
14666
14730
  } = useReviewRulerState();
14667
- return /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)(
14731
+ return /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(
14668
14732
  "div",
14669
14733
  {
14670
14734
  ref: rulerOverlayRef,
@@ -14678,8 +14742,8 @@ var RulerOverlay = () => {
14678
14742
  );
14679
14743
  },
14680
14744
  children: [
14681
- rulerHover && /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)(import_jsx_runtime35.Fragment, { children: [
14682
- /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
14745
+ rulerHover && /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(import_jsx_runtime36.Fragment, { children: [
14746
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
14683
14747
  "div",
14684
14748
  {
14685
14749
  className: "df-review-ruler-guide is-x",
@@ -14687,7 +14751,7 @@ var RulerOverlay = () => {
14687
14751
  style: { top: `${rulerHover.y}px` }
14688
14752
  }
14689
14753
  ),
14690
- /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
14754
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
14691
14755
  "div",
14692
14756
  {
14693
14757
  className: "df-review-ruler-guide is-y",
@@ -14696,8 +14760,8 @@ var RulerOverlay = () => {
14696
14760
  }
14697
14761
  )
14698
14762
  ] }),
14699
- rulerMeasure && (rulerMeasure.width > 0 || rulerMeasure.height > 0) && /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)(import_jsx_runtime35.Fragment, { children: [
14700
- /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
14763
+ rulerMeasure && (rulerMeasure.width > 0 || rulerMeasure.height > 0) && /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(import_jsx_runtime36.Fragment, { children: [
14764
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
14701
14765
  "div",
14702
14766
  {
14703
14767
  className: "df-review-ruler-selection",
@@ -14710,7 +14774,7 @@ var RulerOverlay = () => {
14710
14774
  }
14711
14775
  }
14712
14776
  ),
14713
- /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
14777
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
14714
14778
  "div",
14715
14779
  {
14716
14780
  className: "df-review-ruler-label",
@@ -14836,13 +14900,6 @@ var setTargetFigmaSourceSelectLocked = (targetDocument, locked) => {
14836
14900
  locked
14837
14901
  );
14838
14902
  };
14839
- var isEditableEventTarget = (event) => {
14840
- const path = event.composedPath?.() ?? [];
14841
- const element = path[0] ?? event.target;
14842
- if (!element || typeof element.tagName !== "string") return false;
14843
- const tag = element.tagName;
14844
- return tag === "INPUT" || tag === "TEXTAREA" || element.isContentEditable === true;
14845
- };
14846
14903
  var TRUE_STORAGE_VALUES = /* @__PURE__ */ new Set([
14847
14904
  "1",
14848
14905
  "true",
@@ -15894,7 +15951,7 @@ function isDomReviewItem(item) {
15894
15951
  }
15895
15952
 
15896
15953
  // src/react-shell/target/outside.markers.tsx
15897
- var import_jsx_runtime36 = require("react/jsx-runtime");
15954
+ var import_jsx_runtime37 = require("react/jsx-runtime");
15898
15955
  var OUTSIDE_MARKER_HEIGHT = 22;
15899
15956
  var OUTSIDE_MARKER_CONNECTOR_TOP = 10;
15900
15957
  var OUTSIDE_MARKER_GAP = 6;
@@ -16072,7 +16129,7 @@ var ReviewOutsideMarkers = () => {
16072
16129
  size
16073
16130
  ]);
16074
16131
  if (markers.length === 0) return null;
16075
- return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("div", { className: "df-review-outside-marker-layer", "aria-label": "QA markers", children: markers.map((marker) => {
16132
+ return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("div", { className: "df-review-outside-marker-layer", "aria-label": "QA markers", children: markers.map((marker) => {
16076
16133
  const isActive = marker.item.id === selectedItemId;
16077
16134
  const style = {
16078
16135
  top: `${marker.top}px`,
@@ -16081,7 +16138,7 @@ var ReviewOutsideMarkers = () => {
16081
16138
  "--df-review-outside-marker-connector-stem-height": `${marker.connectorStemHeight}px`,
16082
16139
  "--df-review-outside-marker-z-index": isActive ? 2 : 1
16083
16140
  };
16084
- return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
16141
+ return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
16085
16142
  "button",
16086
16143
  {
16087
16144
  "aria-label": `Focus ${marker.label}`,
@@ -16103,7 +16160,7 @@ var ReviewOutsideMarkers = () => {
16103
16160
  };
16104
16161
 
16105
16162
  // src/react-shell/target/frame.tsx
16106
- var import_jsx_runtime37 = require("react/jsx-runtime");
16163
+ var import_jsx_runtime38 = require("react/jsx-runtime");
16107
16164
  var ReviewTargetFrame = () => {
16108
16165
  const {
16109
16166
  figmaImageOverlays,
@@ -16138,15 +16195,15 @@ var ReviewTargetFrame = () => {
16138
16195
  syncTargetFigmaImageOverlays();
16139
16196
  window.requestAnimationFrame(syncTargetFigmaImageOverlays);
16140
16197
  };
16141
- return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("main", { className: "df-review-stage", children: /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("div", { className: "df-review-frame", children: [
16142
- /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("div", { className: "df-review-frame-scroll", ref: frameScrollRef, children: /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("div", { className: "df-review-frame-canvas", children: /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("div", { className: "df-review-target-stack", children: /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)(
16198
+ return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("main", { className: "df-review-stage", children: /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("div", { className: "df-review-frame", children: [
16199
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("div", { className: "df-review-frame-scroll", ref: frameScrollRef, children: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("div", { className: "df-review-frame-canvas", children: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("div", { className: "df-review-target-stack", children: /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(
16143
16200
  "div",
16144
16201
  {
16145
16202
  className: `df-review-device-frame${showRuler ? " is-ruler" : ""}`,
16146
16203
  children: [
16147
- showRuler && /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(RulerGutters, {}),
16148
- /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(ReviewOutsideMarkers, {}),
16149
- /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)(
16204
+ showRuler && /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(RulerGutters, {}),
16205
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(ReviewOutsideMarkers, {}),
16206
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(
16150
16207
  "div",
16151
16208
  {
16152
16209
  className: "df-review-device",
@@ -16157,7 +16214,7 @@ var ReviewTargetFrame = () => {
16157
16214
  minHeight: `${size.height}px`
16158
16215
  },
16159
16216
  children: [
16160
- /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
16217
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
16161
16218
  "iframe",
16162
16219
  {
16163
16220
  ref: iframeRef,
@@ -16169,14 +16226,14 @@ var ReviewTargetFrame = () => {
16169
16226
  },
16170
16227
  `${frameTargetSrc}:${frameNavigationVersion}`
16171
16228
  ),
16172
- showRuler && /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(RulerOverlay, {})
16229
+ showRuler && /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(RulerOverlay, {})
16173
16230
  ]
16174
16231
  }
16175
16232
  )
16176
16233
  ]
16177
16234
  }
16178
16235
  ) }) }) }),
16179
- /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("div", { className: "df-review-frame-actions", children: /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
16236
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("div", { className: "df-review-frame-actions", children: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
16180
16237
  ReviewModeToolbar,
16181
16238
  {
16182
16239
  canWriteArea,
@@ -16192,18 +16249,18 @@ var ReviewTargetFrame = () => {
16192
16249
  var import_react33 = require("react");
16193
16250
 
16194
16251
  // src/react-shell/topbar.tsx
16195
- var import_jsx_runtime38 = require("react/jsx-runtime");
16252
+ var import_jsx_runtime39 = require("react/jsx-runtime");
16196
16253
  var ReviewScopeIcon2 = ({ scope }) => {
16197
- if (scope === "mobile") return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(Smartphone, { "aria-hidden": "true" });
16198
- if (scope === "tablet") return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(RectangleHorizontal, { "aria-hidden": "true" });
16199
- if (scope === "wide") return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(Maximize2, { "aria-hidden": "true" });
16200
- if (scope === "dom") return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(SquareMousePointer, { "aria-hidden": "true" });
16201
- return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(Monitor, { "aria-hidden": "true" });
16254
+ if (scope === "mobile") return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(Smartphone, { "aria-hidden": "true" });
16255
+ if (scope === "tablet") return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(RectangleHorizontal, { "aria-hidden": "true" });
16256
+ if (scope === "wide") return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(Maximize2, { "aria-hidden": "true" });
16257
+ if (scope === "dom") return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(SquareMousePointer, { "aria-hidden": "true" });
16258
+ return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(Monitor, { "aria-hidden": "true" });
16202
16259
  };
16203
16260
  var ViewportPresetIcon = ({
16204
16261
  preset
16205
16262
  }) => {
16206
- return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(ReviewScopeIcon2, { scope: getViewportPresetKind(preset) });
16263
+ return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(ReviewScopeIcon2, { scope: getViewportPresetKind(preset) });
16207
16264
  };
16208
16265
  var getPresetSelectValue = (preset) => `${preset.label}:${preset.width}x${preset.height}`;
16209
16266
  function getTargetOpenHref(targetSrc) {
@@ -16240,8 +16297,8 @@ var ReviewTopbar = ({
16240
16297
  );
16241
16298
  if (nextPreset) onSizeChange(nextPreset);
16242
16299
  };
16243
- return /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("header", { className: "df-review-topbar", children: [
16244
- /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(
16300
+ return /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("header", { className: "df-review-topbar", children: [
16301
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)(
16245
16302
  "form",
16246
16303
  {
16247
16304
  className: "df-review-address",
@@ -16250,7 +16307,7 @@ var ReviewTopbar = ({
16250
16307
  onApplyTarget();
16251
16308
  },
16252
16309
  children: [
16253
- /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
16310
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
16254
16311
  "button",
16255
16312
  {
16256
16313
  "aria-label": "Open sitemap",
@@ -16259,10 +16316,10 @@ var ReviewTopbar = ({
16259
16316
  "data-review-tooltip-placement": "bottom",
16260
16317
  type: "button",
16261
16318
  onClick: onOpenSitemap,
16262
- children: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(Map2, { "aria-hidden": "true" })
16319
+ children: /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(Map2, { "aria-hidden": "true" })
16263
16320
  }
16264
16321
  ),
16265
- /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
16322
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
16266
16323
  "input",
16267
16324
  {
16268
16325
  "aria-label": "Path",
@@ -16270,8 +16327,8 @@ var ReviewTopbar = ({
16270
16327
  onChange: (event) => onDraftTargetChange(event.target.value)
16271
16328
  }
16272
16329
  ),
16273
- /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("div", { className: "df-review-address-actions", children: [
16274
- /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
16330
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("div", { className: "df-review-address-actions", children: [
16331
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
16275
16332
  "button",
16276
16333
  {
16277
16334
  "aria-label": "Refresh target",
@@ -16280,10 +16337,10 @@ var ReviewTopbar = ({
16280
16337
  "data-review-tooltip-placement": "bottom",
16281
16338
  title: "Refresh target",
16282
16339
  type: "submit",
16283
- children: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(RefreshCw, { "aria-hidden": "true" })
16340
+ children: /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(RefreshCw, { "aria-hidden": "true" })
16284
16341
  }
16285
16342
  ),
16286
- /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
16343
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
16287
16344
  "button",
16288
16345
  {
16289
16346
  "aria-label": copyLabel,
@@ -16293,10 +16350,10 @@ var ReviewTopbar = ({
16293
16350
  title: copyLabel,
16294
16351
  type: "button",
16295
16352
  onClick: onCopyCurrentUrl,
16296
- children: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(Copy, { "aria-hidden": "true" })
16353
+ children: /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(Copy, { "aria-hidden": "true" })
16297
16354
  }
16298
16355
  ),
16299
- /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
16356
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
16300
16357
  "a",
16301
16358
  {
16302
16359
  "aria-label": "Open target page",
@@ -16307,30 +16364,30 @@ var ReviewTopbar = ({
16307
16364
  rel: "noreferrer",
16308
16365
  target: "_blank",
16309
16366
  title: "Open target page",
16310
- children: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(ExternalLink, { "aria-hidden": "true" })
16367
+ children: /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(ExternalLink, { "aria-hidden": "true" })
16311
16368
  }
16312
16369
  )
16313
16370
  ] })
16314
16371
  ]
16315
16372
  }
16316
16373
  ),
16317
- /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("div", { className: "df-review-tools", children: [
16318
- /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("div", { className: "df-review-tool-controls", children: [
16319
- /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("div", { className: "df-review-presets", "aria-label": "Viewport presets", children: viewportPresets.map((preset) => /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(
16374
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("div", { className: "df-review-tools", children: [
16375
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("div", { className: "df-review-tool-controls", children: [
16376
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("div", { className: "df-review-presets", "aria-label": "Viewport presets", children: viewportPresets.map((preset) => /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)(
16320
16377
  "button",
16321
16378
  {
16322
16379
  className: preset.label === size.label ? "is-active" : "",
16323
16380
  type: "button",
16324
16381
  onClick: () => onSizeChange(preset),
16325
16382
  children: [
16326
- /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(ViewportPresetIcon, { preset }),
16327
- /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("span", { className: "df-review-preset-copy", children: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("strong", { children: preset.label }) }),
16328
- /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("span", { className: "df-review-preset-count", children: presetScopeCounts.get(getViewportPresetKind(preset)) ?? 0 })
16383
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(ViewportPresetIcon, { preset }),
16384
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("span", { className: "df-review-preset-copy", children: /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("strong", { children: preset.label }) }),
16385
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("span", { className: "df-review-preset-count", children: presetScopeCounts.get(getViewportPresetKind(preset)) ?? 0 })
16329
16386
  ]
16330
16387
  },
16331
16388
  preset.label
16332
16389
  )) }),
16333
- /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
16390
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
16334
16391
  "select",
16335
16392
  {
16336
16393
  "aria-label": "Viewport preset",
@@ -16340,7 +16397,7 @@ var ReviewTopbar = ({
16340
16397
  children: viewportPresets.map((preset) => {
16341
16398
  const scope = getViewportPresetKind(preset);
16342
16399
  const count = presetScopeCounts.get(scope) ?? 0;
16343
- return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
16400
+ return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
16344
16401
  "option",
16345
16402
  {
16346
16403
  value: getPresetSelectValue(preset),
@@ -16351,15 +16408,15 @@ var ReviewTopbar = ({
16351
16408
  })
16352
16409
  }
16353
16410
  ),
16354
- /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("span", { className: "df-review-tool-divider", "aria-hidden": "true", children: "|" }),
16355
- /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("span", { className: "df-review-active-size", children: [
16411
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("span", { className: "df-review-tool-divider", "aria-hidden": "true", children: "|" }),
16412
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("span", { className: "df-review-active-size", children: [
16356
16413
  size.width,
16357
16414
  "x",
16358
16415
  size.height
16359
16416
  ] })
16360
16417
  ] }),
16361
- /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("div", { className: "df-review-overlays", "aria-label": "Target overlays", children: [
16362
- isRulerAvailable && /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
16418
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("div", { className: "df-review-overlays", "aria-label": "Target overlays", children: [
16419
+ isRulerAvailable && /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
16363
16420
  "button",
16364
16421
  {
16365
16422
  "aria-label": "Toggle ruler",
@@ -16368,10 +16425,10 @@ var ReviewTopbar = ({
16368
16425
  "data-review-tooltip-placement": "bottom",
16369
16426
  type: "button",
16370
16427
  onClick: onToggleRuler,
16371
- children: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(Ruler, { "aria-hidden": "true" })
16428
+ children: /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(Ruler, { "aria-hidden": "true" })
16372
16429
  }
16373
16430
  ),
16374
- /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
16431
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
16375
16432
  "button",
16376
16433
  {
16377
16434
  "aria-label": "Toggle grid overlay",
@@ -16380,10 +16437,10 @@ var ReviewTopbar = ({
16380
16437
  "data-review-tooltip-placement": "bottom",
16381
16438
  type: "button",
16382
16439
  onClick: () => onToggleTargetOverlay("grid"),
16383
- children: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(LayoutGrid, { "aria-hidden": "true" })
16440
+ children: /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(LayoutGrid, { "aria-hidden": "true" })
16384
16441
  }
16385
16442
  ),
16386
- /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
16443
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
16387
16444
  "button",
16388
16445
  {
16389
16446
  "aria-disabled": !isFigmaOverlayAvailable,
@@ -16394,7 +16451,7 @@ var ReviewTopbar = ({
16394
16451
  disabled: !isFigmaOverlayAvailable,
16395
16452
  type: "button",
16396
16453
  onClick: onToggleFigmaOverlay,
16397
- children: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(FigmaMarkIcon, {})
16454
+ children: /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(FigmaMarkIcon, {})
16398
16455
  }
16399
16456
  )
16400
16457
  ] })
@@ -16403,7 +16460,7 @@ var ReviewTopbar = ({
16403
16460
  };
16404
16461
 
16405
16462
  // src/react-shell/topbar.container.tsx
16406
- var import_jsx_runtime39 = require("react/jsx-runtime");
16463
+ var import_jsx_runtime40 = require("react/jsx-runtime");
16407
16464
  var TopbarContainer = () => {
16408
16465
  const {
16409
16466
  applyTarget,
@@ -16436,7 +16493,7 @@ var TopbarContainer = () => {
16436
16493
  const copyCurrentUrl = () => copyCurrentReviewUrl({
16437
16494
  onCopyLabelChange: setCopyLabel
16438
16495
  });
16439
- return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
16496
+ return /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
16440
16497
  ReviewTopbar,
16441
16498
  {
16442
16499
  draftTarget,
@@ -16463,11 +16520,11 @@ var TopbarContainer = () => {
16463
16520
  };
16464
16521
 
16465
16522
  // src/react-shell/review/toast.container.tsx
16466
- var import_jsx_runtime40 = require("react/jsx-runtime");
16523
+ var import_jsx_runtime41 = require("react/jsx-runtime");
16467
16524
  var ReviewToastContainer = () => {
16468
16525
  const toastMessage = useReviewShellStore((state) => state.toastMessage);
16469
16526
  if (!toastMessage) return null;
16470
- return /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("div", { className: "df-review-copy-toast", role: "status", children: toastMessage });
16527
+ return /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("div", { className: "df-review-copy-toast", role: "status", children: toastMessage });
16471
16528
  };
16472
16529
 
16473
16530
  // src/react-shell/hooks/use.review.shell.runtime.ts
@@ -16837,72 +16894,21 @@ function normalizeStoredReviewItem(value) {
16837
16894
  };
16838
16895
  }
16839
16896
 
16897
+ // src/core/error.ts
16898
+ function getErrorMessage(error, fallback) {
16899
+ if (error instanceof Error) return error.message;
16900
+ if (error && typeof error === "object" && "message" in error && typeof error.message === "string") {
16901
+ return error.message;
16902
+ }
16903
+ return fallback;
16904
+ }
16905
+
16840
16906
  // src/core/id.ts
16841
16907
  function createId() {
16842
16908
  if ("randomUUID" in crypto) return crypto.randomUUID();
16843
16909
  return `${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`;
16844
16910
  }
16845
16911
 
16846
- // src/core/hotkey.ts
16847
- var HOTKEY_KEY_ALIASES = {
16848
- q: ["\u3142", "\u3143"],
16849
- w: ["\u3148", "\u3149"],
16850
- e: ["\u3137", "\u3138"],
16851
- r: ["\u3131", "\u3132"],
16852
- t: ["\u3145", "\u3146"],
16853
- y: ["\u315B"],
16854
- u: ["\u3155"],
16855
- i: ["\u3151"],
16856
- o: ["\u3150", "\u3152"],
16857
- p: ["\u3154", "\u3156"],
16858
- a: ["\u3141"],
16859
- s: ["\u3134"],
16860
- d: ["\u3147"],
16861
- f: ["\u3139"],
16862
- g: ["\u314E"],
16863
- h: ["\u3157"],
16864
- j: ["\u3153"],
16865
- k: ["\u314F"],
16866
- l: ["\u3163"],
16867
- z: ["\u314B"],
16868
- x: ["\u314C"],
16869
- c: ["\u314A"],
16870
- v: ["\u314D"],
16871
- b: ["\u3160"],
16872
- n: ["\u315C"],
16873
- m: ["\u3161"]
16874
- };
16875
- function isHotkey(event, hotkey) {
16876
- const parts = hotkey.split("+").map((part) => part.trim().toLowerCase()).filter(Boolean);
16877
- const key = parts.find(
16878
- (part) => !["shift", "ctrl", "control", "alt", "meta", "cmd"].includes(part)
16879
- );
16880
- if (!key) return false;
16881
- if (parts.includes("shift") !== event.shiftKey) return false;
16882
- if ((parts.includes("ctrl") || parts.includes("control")) !== event.ctrlKey) {
16883
- return false;
16884
- }
16885
- if (parts.includes("alt") !== event.altKey) return false;
16886
- if ((parts.includes("meta") || parts.includes("cmd")) !== event.metaKey) {
16887
- return false;
16888
- }
16889
- return isHotkeyKey(event, key);
16890
- }
16891
- function getHotkeyActionKey(event, keys) {
16892
- return keys.find((key) => isHotkeyKey(event, key));
16893
- }
16894
- function isHotkeyKey(event, key) {
16895
- const normalizedKey = key.toLowerCase();
16896
- if (event.key.toLowerCase() === normalizedKey) return true;
16897
- if (getHotkeyCode(normalizedKey) === event.code) return true;
16898
- return HOTKEY_KEY_ALIASES[normalizedKey]?.includes(event.key) ?? false;
16899
- }
16900
- function getHotkeyCode(key) {
16901
- if (/^[a-z]$/.test(key)) return `Key${key.toUpperCase()}`;
16902
- if (/^[0-9]$/.test(key)) return `Digit${key}`;
16903
- return void 0;
16904
- }
16905
-
16906
16912
  // src/core/location.ts
16907
16913
  var INTERNAL_QUERY_PARAMS = ["__dfwr_target"];
16908
16914
  function getPageUrl(environment) {
@@ -20069,13 +20075,6 @@ var WebReviewKitView = class {
20069
20075
  // src/core/web.review.kit.app.ts
20070
20076
  var ROOT_ID = "df-web-review-kit-root";
20071
20077
  var VIEWPORT_SCROLL_OPTIONS = { capture: true, passive: true };
20072
- function isEditableEventTarget2(event) {
20073
- const path = event.composedPath?.() ?? [];
20074
- const element = path[0] ?? event.target;
20075
- if (!element || typeof element.tagName !== "string") return false;
20076
- const tag = element.tagName;
20077
- return tag === "INPUT" || tag === "TEXTAREA" || tag === "SELECT" || element.isContentEditable === true;
20078
- }
20079
20078
  function createWebReviewKit(options) {
20080
20079
  if (typeof window === "undefined" || typeof document === "undefined") {
20081
20080
  return createNoopController();
@@ -20120,7 +20119,7 @@ var WebReviewKitApp = class {
20120
20119
  event.stopPropagation();
20121
20120
  return;
20122
20121
  }
20123
- if (isEditableEventTarget2(event) || !isHotkey(event, this.hotkey)) return;
20122
+ if (isEditableEventTarget(event) || !isHotkey(event, this.hotkey)) return;
20124
20123
  event.preventDefault();
20125
20124
  event.stopPropagation();
20126
20125
  this.toggle();
@@ -20630,46 +20629,28 @@ var WebReviewKitApp = class {
20630
20629
  this.root.style.display = previousDisplay;
20631
20630
  }
20632
20631
  }
20633
- async captureDomDraft(input) {
20634
- if (this.isCapturingViewport) return;
20635
- const environment = this.getEnvironment();
20636
- const draft = this.domDraft;
20637
- if (!draft) return;
20638
- if (!environment?.captureViewport) {
20639
- this.draftError = "Viewport capture helper is not available.";
20640
- this.render();
20641
- return;
20642
- }
20643
- const captureInput = this.createViewportCaptureInput(
20644
- environment,
20632
+ captureDomDraft(input) {
20633
+ return this.captureDraft(
20645
20634
  input,
20646
- input.selection?.viewport
20635
+ () => this.domDraft,
20636
+ (draft) => {
20637
+ this.domDraft = draft;
20638
+ }
20639
+ );
20640
+ }
20641
+ captureAreaDraft(input) {
20642
+ return this.captureDraft(
20643
+ input,
20644
+ () => this.areaDraft,
20645
+ (draft) => {
20646
+ this.areaDraft = draft;
20647
+ }
20647
20648
  );
20648
- this.draftError = "";
20649
- this.isCapturingViewport = true;
20650
- this.render();
20651
- try {
20652
- const result = await environment.captureViewport(captureInput);
20653
- const attachment = this.createCaptureDraftAttachment(result, captureInput);
20654
- const currentDraft = this.domDraft ?? draft;
20655
- this.domDraft = {
20656
- ...currentDraft,
20657
- attachments: [...currentDraft.attachments ?? [], attachment]
20658
- };
20659
- } catch (error) {
20660
- this.draftError = this.getErrorMessage(
20661
- error,
20662
- "Failed to capture viewport."
20663
- );
20664
- } finally {
20665
- this.isCapturingViewport = false;
20666
- this.render();
20667
- }
20668
20649
  }
20669
- async captureAreaDraft(input) {
20650
+ async captureDraft(input, getDraft, setDraft) {
20670
20651
  if (this.isCapturingViewport) return;
20671
20652
  const environment = this.getEnvironment();
20672
- const draft = this.areaDraft;
20653
+ const draft = getDraft();
20673
20654
  if (!draft) return;
20674
20655
  if (!environment?.captureViewport) {
20675
20656
  this.draftError = "Viewport capture helper is not available.";
@@ -20687,16 +20668,13 @@ var WebReviewKitApp = class {
20687
20668
  try {
20688
20669
  const result = await environment.captureViewport(captureInput);
20689
20670
  const attachment = this.createCaptureDraftAttachment(result, captureInput);
20690
- const currentDraft = this.areaDraft ?? draft;
20691
- this.areaDraft = {
20671
+ const currentDraft = getDraft() ?? draft;
20672
+ setDraft({
20692
20673
  ...currentDraft,
20693
20674
  attachments: [...currentDraft.attachments ?? [], attachment]
20694
- };
20675
+ });
20695
20676
  } catch (error) {
20696
- this.draftError = this.getErrorMessage(
20697
- error,
20698
- "Failed to capture viewport."
20699
- );
20677
+ this.draftError = getErrorMessage(error, "Failed to capture viewport.");
20700
20678
  } finally {
20701
20679
  this.isCapturingViewport = false;
20702
20680
  this.render();
@@ -20835,17 +20813,10 @@ var WebReviewKitApp = class {
20835
20813
  );
20836
20814
  }
20837
20815
  getCreateItemErrorMessage(error, wasUploadingAttachments) {
20838
- const message = this.getErrorMessage(error, "Failed to save QA.");
20816
+ const message = getErrorMessage(error, "Failed to save QA.");
20839
20817
  const reason = error && typeof error === "object" && "reason" in error && typeof error.reason === "string" ? ` (${error.reason})` : "";
20840
20818
  return wasUploadingAttachments && reason ? `Attachment upload failed${reason}: ${message}` : message;
20841
20819
  }
20842
- getErrorMessage(error, fallback) {
20843
- if (error instanceof Error) return error.message;
20844
- if (error && typeof error === "object" && "message" in error && typeof error.message === "string") {
20845
- return error.message;
20846
- }
20847
- return fallback;
20848
- }
20849
20820
  async restoreItem(item) {
20850
20821
  this.setModeState("idle");
20851
20822
  this.clearDrafts();
@@ -21020,7 +20991,7 @@ async function captureIframeViewport(frame, input) {
21020
20991
  );
21021
20992
  } catch (error) {
21022
20993
  throw new Error(
21023
- `Selected region capture failed: ${getUnknownErrorMessage(error)}`
20994
+ `Selected region capture failed: ${getCaptureErrorMessage(error)}`
21024
20995
  );
21025
20996
  }
21026
20997
  }
@@ -21033,7 +21004,7 @@ async function captureIframeViewport(frame, input) {
21033
21004
  input
21034
21005
  );
21035
21006
  } catch (error) {
21036
- errors.push(`html2canvas: ${getUnknownErrorMessage(error)}`);
21007
+ errors.push(`html2canvas: ${getCaptureErrorMessage(error)}`);
21037
21008
  }
21038
21009
  const svg = createViewportSvg(targetDocument, targetWindow, viewport, input);
21039
21010
  const svgFile = new Blob([svg], { type: "image/svg+xml;charset=utf-8" });
@@ -21047,7 +21018,7 @@ async function captureIframeViewport(frame, input) {
21047
21018
  input
21048
21019
  );
21049
21020
  } catch (error) {
21050
- errors.push(`svg-canvas: ${getUnknownErrorMessage(error)}`);
21021
+ errors.push(`svg-canvas: ${getCaptureErrorMessage(error)}`);
21051
21022
  }
21052
21023
  return {
21053
21024
  file: svgFile,
@@ -21483,12 +21454,8 @@ function createMarkerSvg(x, y) {
21483
21454
  function formatCaptureTimestamp(timestamp) {
21484
21455
  return timestamp.replace(/[^0-9A-Za-z]+/g, "-").replace(/^-|-$/g, "");
21485
21456
  }
21486
- function getUnknownErrorMessage(error) {
21487
- if (error instanceof Error) return error.message;
21488
- if (error && typeof error === "object" && "message" in error && typeof error.message === "string") {
21489
- return error.message;
21490
- }
21491
- return "Capture was saved as SVG fallback.";
21457
+ function getCaptureErrorMessage(error) {
21458
+ return getErrorMessage(error, "Capture was saved as SVG fallback.");
21492
21459
  }
21493
21460
 
21494
21461
  // src/react-shell/hooks/review.kit.target.ts
@@ -24810,7 +24777,7 @@ var createReviewShellStore = (init) => (0, import_zustand2.createStore)()((...ar
24810
24777
  }));
24811
24778
 
24812
24779
  // src/react-shell/review/shell.tsx
24813
- var import_jsx_runtime41 = require("react/jsx-runtime");
24780
+ var import_jsx_runtime42 = require("react/jsx-runtime");
24814
24781
  var ReviewShell = (props) => {
24815
24782
  const config = (0, import_react57.useMemo)(
24816
24783
  () => createReviewShellConfig(props),
@@ -24830,23 +24797,23 @@ var ReviewShell = (props) => {
24830
24797
  () => createReviewShellStore({ target: getInitialTargetSliceState(config) })
24831
24798
  );
24832
24799
  const [refs] = (0, import_react57.useState)(createReviewShellRefs);
24833
- return /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(ReviewShellConfigProvider, { value: config, children: /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(ReviewShellStoreProvider, { value: store, children: /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(ReviewShellRefsProvider, { value: refs, children: /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(ReviewShellContent, { ...props }) }) }) });
24800
+ return /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(ReviewShellConfigProvider, { value: config, children: /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(ReviewShellStoreProvider, { value: store, children: /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(ReviewShellRefsProvider, { value: refs, children: /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(ReviewShellContent, { ...props }) }) }) });
24834
24801
  };
24835
24802
  var ReviewShellContent = (props) => {
24836
24803
  const runtime = useReviewShellRuntime(props);
24837
- return /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(ReviewShellProviders, { ...runtime, children: /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
24804
+ return /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(ReviewShellProviders, { ...runtime, children: /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
24838
24805
  ReviewShellFrameContainer,
24839
24806
  {
24840
24807
  slots: {
24841
- topbar: /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(TopbarContainer, {}),
24842
- modals: /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(ReviewShellModalsContainer, {}),
24843
- toast: /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(ReviewToastContainer, {}),
24844
- sideRail: /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(ReviewSideRailContainer, {}),
24845
- qaPanel: /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(QaPanelContainer, {}),
24846
- figmaImagesPanel: /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(FigmaImagesPanelContainer, {}),
24847
- sourceTreePanel: /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(SectionOutlineContainer, {}),
24848
- targetFrame: /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(ReviewTargetFrame, {}),
24849
- sourceInspector: /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(SourceInspectorOverlayContainer, {})
24808
+ topbar: /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(TopbarContainer, {}),
24809
+ modals: /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(ReviewShellModalsContainer, {}),
24810
+ toast: /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(ReviewToastContainer, {}),
24811
+ sideRail: /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(ReviewSideRailContainer, {}),
24812
+ qaPanel: /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(QaPanelContainer, {}),
24813
+ figmaImagesPanel: /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(FigmaImagesPanelContainer, {}),
24814
+ sourceTreePanel: /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(SectionOutlineContainer, {}),
24815
+ targetFrame: /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(ReviewTargetFrame, {}),
24816
+ sourceInspector: /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(SourceInspectorOverlayContainer, {})
24850
24817
  }
24851
24818
  }
24852
24819
  ) });
@@ -24855,7 +24822,7 @@ var ReviewShellContent = (props) => {
24855
24822
  // src/react-shell/figma/dev-overlay.tsx
24856
24823
  var import_react58 = __toESM(require("react"), 1);
24857
24824
  var import_client = require("react-dom/client");
24858
- var import_jsx_runtime42 = require("react/jsx-runtime");
24825
+ var import_jsx_runtime43 = require("react/jsx-runtime");
24859
24826
  var FIGMA_DEV_OVERLAY_ROOT_ID = "df-review-figma-dev-overlay-root";
24860
24827
  var FIGMA_DEV_OVERLAY_MOUNT_ID = "df-review-figma-dev-overlay-mount";
24861
24828
  var mountFigmaDevOverlay = (options) => {
@@ -24876,7 +24843,7 @@ var mountFigmaDevOverlay = (options) => {
24876
24843
  document.body.appendChild(host);
24877
24844
  const root = (0, import_client.createRoot)(mountNode);
24878
24845
  root.render(
24879
- /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(import_react58.default.StrictMode, { children: /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(FigmaDevOverlayWidget, { ...options }) })
24846
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(import_react58.default.StrictMode, { children: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(FigmaDevOverlayWidget, { ...options }) })
24880
24847
  );
24881
24848
  return {
24882
24849
  destroy() {
@@ -24967,7 +24934,7 @@ var FigmaDevOverlayWidget = ({
24967
24934
  );
24968
24935
  (0, import_react58.useEffect)(() => {
24969
24936
  const handleKeyDown = (event) => {
24970
- if (!isHotkey(event, "Shift+F") || isEditableFigmaDevOverlayEventTarget(event)) {
24937
+ if (!isHotkey(event, "Shift+F") || isEditableEventTarget(event)) {
24971
24938
  return;
24972
24939
  }
24973
24940
  event.preventDefault();
@@ -24989,21 +24956,21 @@ var FigmaDevOverlayWidget = ({
24989
24956
  setImageOverlayOpacity(selectedImage.id, opacityPercent / 100);
24990
24957
  }
24991
24958
  };
24992
- return /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)(
24959
+ return /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(
24993
24960
  "aside",
24994
24961
  {
24995
24962
  "aria-label": "Figma overlay",
24996
24963
  className: `df-review-figma-dev-widget${isPanelOpen ? " is-open" : ""}${isAnyImageOverlayVisible ? " is-active" : ""}`,
24997
24964
  children: [
24998
- isPanelOpen && /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "df-review-figma-dev-panel", children: [
24999
- /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "df-review-figma-dev-panel-header", children: [
25000
- /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("strong", { children: "Figma" }),
25001
- /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { children: matchedViewportMatch ? `${matchedViewportMatch.label} \xB7 ${matchedViewportMatch.rangeLabel}` : `${viewport.width}px` })
24965
+ isPanelOpen && /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", { className: "df-review-figma-dev-panel", children: [
24966
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", { className: "df-review-figma-dev-panel-header", children: [
24967
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("strong", { children: "Figma" }),
24968
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("span", { children: matchedViewportMatch ? `${matchedViewportMatch.label} \xB7 ${matchedViewportMatch.rangeLabel}` : `${viewport.width}px` })
25002
24969
  ] }),
25003
- selectedImage && /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "df-review-figma-dev-selected-controls", children: [
25004
- /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("label", { className: "df-review-figma-dev-opacity-control", children: [
25005
- /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { children: "Opacity" }),
25006
- /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
24970
+ selectedImage && /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", { className: "df-review-figma-dev-selected-controls", children: [
24971
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("label", { className: "df-review-figma-dev-opacity-control", children: [
24972
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("span", { children: "Opacity" }),
24973
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
25007
24974
  "input",
25008
24975
  {
25009
24976
  "aria-label": `${selectedImageLabel} overlay opacity`,
@@ -25016,11 +24983,11 @@ var FigmaDevOverlayWidget = ({
25016
24983
  onInput: (event) => updateSelectedImageOpacity(event.currentTarget.value)
25017
24984
  }
25018
24985
  ),
25019
- /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("strong", { children: selectedOpacityPercent })
24986
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("strong", { children: selectedOpacityPercent })
25020
24987
  ] }),
25021
- /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("label", { className: "df-review-figma-dev-y-control", children: [
25022
- /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(MoveVertical, { "aria-hidden": "true" }),
25023
- /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
24988
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("label", { className: "df-review-figma-dev-y-control", children: [
24989
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(MoveVertical, { "aria-hidden": "true" }),
24990
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
25024
24991
  "input",
25025
24992
  {
25026
24993
  "aria-label": `${selectedImageLabel} overlay Y offset`,
@@ -25050,14 +25017,14 @@ var FigmaDevOverlayWidget = ({
25050
25017
  )
25051
25018
  ] })
25052
25019
  ] }),
25053
- error && /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("p", { className: "df-review-figma-dev-status", children: error }),
25054
- !matchedViewport ? /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("p", { className: "df-review-figma-dev-empty", children: [
25020
+ error && /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("p", { className: "df-review-figma-dev-status", children: error }),
25021
+ !matchedViewport ? /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("p", { className: "df-review-figma-dev-empty", children: [
25055
25022
  "No Figma layers for this viewport.",
25056
25023
  viewportBoundaries ? ` Mobile ${viewportBoundaries.mobileRangeLabel} / Full width ${viewportBoundaries.fullWidthRangeLabel}` : ""
25057
- ] }) : isLoading ? /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("p", { className: "df-review-figma-dev-status", children: "Loading..." }) : images.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("p", { className: "df-review-figma-dev-empty", children: "No Figma layers for this viewport." }) : /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("div", { className: "df-review-figma-dev-list", children: images.map((image, index) => {
25024
+ ] }) : isLoading ? /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("p", { className: "df-review-figma-dev-status", children: "Loading..." }) : images.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("p", { className: "df-review-figma-dev-empty", children: "No Figma layers for this viewport." }) : /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("div", { className: "df-review-figma-dev-list", children: images.map((image, index) => {
25058
25025
  const imageLabel = getFigmaImageLabel(image, index);
25059
25026
  const overlayState = imageOverlayStates[image.id] ?? DEFAULT_FIGMA_IMAGE_LAYER_STATE;
25060
- return /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)(
25027
+ return /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(
25061
25028
  "article",
25062
25029
  {
25063
25030
  className: `df-review-figma-dev-row${image.id === selectedImageId ? " is-active" : ""}`,
@@ -25070,7 +25037,7 @@ var FigmaDevOverlayWidget = ({
25070
25037
  setSelectedImageId(image.id);
25071
25038
  },
25072
25039
  children: [
25073
- /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
25040
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
25074
25041
  FigmaImageLayerStateButtons,
25075
25042
  {
25076
25043
  imageLabel,
@@ -25082,9 +25049,9 @@ var FigmaDevOverlayWidget = ({
25082
25049
  onToggleVisible: () => toggleImageOverlayVisible(image.id)
25083
25050
  }
25084
25051
  ),
25085
- /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("span", { className: "df-review-figma-dev-row-main", children: [
25086
- /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("strong", { children: imageLabel }),
25087
- /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("small", { children: formatFigmaImageDate(image.updatedAt) })
25052
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("span", { className: "df-review-figma-dev-row-main", children: [
25053
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("strong", { children: imageLabel }),
25054
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("small", { children: formatFigmaImageDate(image.updatedAt) })
25088
25055
  ] })
25089
25056
  ]
25090
25057
  },
@@ -25092,7 +25059,7 @@ var FigmaDevOverlayWidget = ({
25092
25059
  );
25093
25060
  }) })
25094
25061
  ] }),
25095
- /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("div", { className: "df-review-figma-dev-bar", children: /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)(
25062
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("div", { className: "df-review-figma-dev-bar", children: /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(
25096
25063
  "button",
25097
25064
  {
25098
25065
  "aria-expanded": isPanelOpen,
@@ -25102,8 +25069,8 @@ var FigmaDevOverlayWidget = ({
25102
25069
  type: "button",
25103
25070
  onClick: () => setIsPanelOpen((isOpen) => !isOpen),
25104
25071
  children: [
25105
- /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(FigmaMarkIcon, {}),
25106
- /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "df-review-figma-dev-button-count", children: images.length })
25072
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(FigmaMarkIcon, {}),
25073
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("span", { className: "df-review-figma-dev-button-count", children: images.length })
25107
25074
  ]
25108
25075
  }
25109
25076
  ) })
@@ -25128,13 +25095,6 @@ function useCurrentPageUrl(pageUrl, reviewPathPrefix) {
25128
25095
  }, [pageUrl, reviewPathPrefix]);
25129
25096
  return currentPageUrl;
25130
25097
  }
25131
- function isEditableFigmaDevOverlayEventTarget(event) {
25132
- const path = event.composedPath?.() ?? [];
25133
- const element = path[0] ?? event.target;
25134
- if (!element || typeof element.tagName !== "string") return false;
25135
- const tagName = element.tagName;
25136
- return tagName === "INPUT" || tagName === "TEXTAREA" || tagName === "SELECT" || element.isContentEditable === true;
25137
- }
25138
25098
  function useCurrentViewport() {
25139
25099
  const [viewport, setViewport] = (0, import_react58.useState)(getCurrentViewportSize);
25140
25100
  (0, import_react58.useEffect)(() => {
@@ -25694,7 +25654,7 @@ var createSupabasePresenceAdapter = ({
25694
25654
  });
25695
25655
 
25696
25656
  // src/react-shell.tsx
25697
- var import_jsx_runtime43 = require("react/jsx-runtime");
25657
+ var import_jsx_runtime44 = require("react/jsx-runtime");
25698
25658
  var mountReviewShell = (options) => {
25699
25659
  if (typeof document === "undefined" || !document.head) return;
25700
25660
  const { rootId = "root", ...shellProps } = options;
@@ -25705,7 +25665,7 @@ var mountReviewShell = (options) => {
25705
25665
  root.style.height = "100%";
25706
25666
  root.style.margin = "0";
25707
25667
  (0, import_client2.createRoot)(root).render(
25708
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(import_react59.default.StrictMode, { children: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(ReviewShell, { ...shellProps }) })
25668
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(import_react59.default.StrictMode, { children: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(ReviewShell, { ...shellProps }) })
25709
25669
  );
25710
25670
  };
25711
25671
  // Annotate the CommonJS export names for ESM import in node: