@designfever/web-review-kit 0.4.0 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,7 +3,7 @@ import {
3
3
  createWebReviewKit,
4
4
  getNumberedReviewItems,
5
5
  normalizeReviewItemStatus
6
- } from "./chunk-QFNYQCTA.js";
6
+ } from "./chunk-6L2KJ7XL.js";
7
7
 
8
8
  // src/react-shell.tsx
9
9
  import React2 from "react";
@@ -152,6 +152,7 @@ function ensureReviewShellStyle() {
152
152
 
153
153
  /* Semantic aliases consumed by the existing shell chrome. */
154
154
  --df-review-bg: var(--df-review-color-canvas);
155
+ --df-review-surface: var(--df-review-color-surface);
155
156
  --df-review-topbar: var(--df-review-color-surface);
156
157
  --df-review-panel: var(--df-review-color-panel);
157
158
  --df-review-panel-strong: var(--df-review-color-panel-strong);
@@ -506,10 +507,13 @@ function ensureReviewShellStyle() {
506
507
 
507
508
  .df-review-sitemap-list {
508
509
  --df-review-sitemap-grid-template: minmax(190px, 1fr) 74px 78px 64px minmax(108px, 160px);
510
+ position: relative;
509
511
  display: grid;
510
512
  align-content: start;
511
513
  min-height: 0;
512
- overflow: auto;
514
+ overflow-x: hidden;
515
+ overflow-y: auto;
516
+ overscroll-behavior: contain;
513
517
  padding: 8px;
514
518
  }
515
519
 
@@ -524,11 +528,14 @@ function ensureReviewShellStyle() {
524
528
  .df-review-sitemap-table-head {
525
529
  position: sticky;
526
530
  top: 0;
527
- z-index: 1;
531
+ z-index: 3;
528
532
  min-height: 32px;
529
533
  border-bottom: 1px solid var(--df-review-line);
530
534
  padding: 0 10px;
531
- background: var(--df-review-surface);
535
+ background: var(--df-review-panel);
536
+ box-shadow:
537
+ 0 -8px 0 0 var(--df-review-panel),
538
+ 0 1px 0 var(--df-review-line);
532
539
  color: var(--df-review-muted);
533
540
  font-size: var(--df-review-font-size-xs);
534
541
  font-weight: 720;
@@ -599,10 +606,13 @@ function ensureReviewShellStyle() {
599
606
  .df-review-sitemap-row.is-summary {
600
607
  position: sticky;
601
608
  bottom: 0;
602
- z-index: 1;
609
+ z-index: 3;
603
610
  border-top: 1px solid var(--df-review-line);
604
611
  border-bottom: 0;
605
- background: var(--df-review-surface);
612
+ background: var(--df-review-panel);
613
+ box-shadow:
614
+ 0 8px 0 0 var(--df-review-panel),
615
+ 0 -1px 0 var(--df-review-line);
606
616
  }
607
617
 
608
618
  .df-review-sitemap-row.is-folder {
@@ -2456,8 +2466,12 @@ function ensureReviewShellStyle() {
2456
2466
  .df-review-source-candidate-list {
2457
2467
  display: grid;
2458
2468
  gap: 0;
2469
+ max-height: min(220px, calc(100vh - 96px));
2459
2470
  min-height: 0;
2460
- overflow: auto;
2471
+ overflow-x: hidden;
2472
+ overflow-y: auto;
2473
+ padding-right: 2px;
2474
+ scrollbar-gutter: stable;
2461
2475
  }
2462
2476
 
2463
2477
  .df-review-source-candidate {
@@ -2771,7 +2785,7 @@ import {
2771
2785
  useCallback as useCallback11,
2772
2786
  useEffect as useEffect10,
2773
2787
  useMemo as useMemo7,
2774
- useRef as useRef4,
2788
+ useRef as useRef5,
2775
2789
  useState as useState10
2776
2790
  } from "react";
2777
2791
 
@@ -5614,6 +5628,97 @@ var FigmaIcon = () => /* @__PURE__ */ jsx15(
5614
5628
  }
5615
5629
  );
5616
5630
 
5631
+ // src/react-shell/target/target.ts
5632
+ var HIDE_SCROLLBAR_STYLE_ID = "df-review-hide-scrollbar";
5633
+ var FIGMA_POINTER_LOCK_STYLE_ID = "df-review-figma-pointer-lock";
5634
+ var setTargetScrollbarHidden = (targetDocument, hidden) => {
5635
+ if (!targetDocument) return;
5636
+ const existing = targetDocument.getElementById(HIDE_SCROLLBAR_STYLE_ID);
5637
+ if (hidden) {
5638
+ if (existing) return;
5639
+ const style = targetDocument.createElement("style");
5640
+ style.id = HIDE_SCROLLBAR_STYLE_ID;
5641
+ style.textContent = "html{scrollbar-width:none}html::-webkit-scrollbar,body::-webkit-scrollbar{width:0;height:0;display:none}";
5642
+ targetDocument.head?.appendChild(style);
5643
+ } else {
5644
+ existing?.remove();
5645
+ }
5646
+ };
5647
+ var setTargetFigmaOverlayLocked = (targetDocument, locked) => {
5648
+ if (!targetDocument) return;
5649
+ const existing = targetDocument.getElementById(FIGMA_POINTER_LOCK_STYLE_ID);
5650
+ if (locked) {
5651
+ if (existing) return;
5652
+ const style = targetDocument.createElement("style");
5653
+ style.id = FIGMA_POINTER_LOCK_STYLE_ID;
5654
+ style.textContent = [
5655
+ ".helper-figma-root,",
5656
+ ".helper-figma-root *,",
5657
+ ".helper-figma-loading-backdrop,",
5658
+ ".helper-figma-loading-backdrop * {",
5659
+ "pointer-events: none !important;",
5660
+ "}"
5661
+ ].join("\n");
5662
+ targetDocument.head?.appendChild(style);
5663
+ } else {
5664
+ existing?.remove();
5665
+ }
5666
+ };
5667
+ var isEditableEventTarget = (event) => {
5668
+ const path = event.composedPath?.() ?? [];
5669
+ const element = path[0] ?? event.target;
5670
+ if (!element || typeof element.tagName !== "string") return false;
5671
+ const tag = element.tagName;
5672
+ return tag === "INPUT" || tag === "TEXTAREA" || element.isContentEditable === true;
5673
+ };
5674
+ var TRUE_STORAGE_VALUES = /* @__PURE__ */ new Set([
5675
+ "1",
5676
+ "true",
5677
+ "on",
5678
+ "show",
5679
+ "shown",
5680
+ "visible",
5681
+ "enabled",
5682
+ "yes"
5683
+ ]);
5684
+ var OVERLAY_STORAGE_KEYS = {
5685
+ grid: ["isHelp", "df-review-grid-overlay", "dfReviewGridOverlay"],
5686
+ figma: ["isFigmaHelp", "df-review-figma-overlay", "dfReviewFigmaOverlay"]
5687
+ };
5688
+ var isStoredOverlayEnabled = (value) => TRUE_STORAGE_VALUES.has(value?.trim().toLowerCase() ?? "");
5689
+ var getCookieValue = (targetDocument, name) => {
5690
+ const cookies = targetDocument?.cookie ? targetDocument.cookie.split(";") : [];
5691
+ const prefix = `${name}=`;
5692
+ const match = cookies.map((cookie) => cookie.trim()).find((cookie) => cookie.startsWith(prefix));
5693
+ return match ? decodeURIComponent(match.slice(prefix.length)) : null;
5694
+ };
5695
+ var getStorageValue = (storage, key) => {
5696
+ try {
5697
+ return storage?.getItem(key) ?? null;
5698
+ } catch {
5699
+ return null;
5700
+ }
5701
+ };
5702
+ var getStoredOverlayState = (targetDocument, overlay) => {
5703
+ const targetWindow = targetDocument?.defaultView;
5704
+ return OVERLAY_STORAGE_KEYS[overlay].some((key) => {
5705
+ if (isStoredOverlayEnabled(getCookieValue(targetDocument, key))) {
5706
+ return true;
5707
+ }
5708
+ return isStoredOverlayEnabled(getStorageValue(targetWindow?.localStorage, key)) || isStoredOverlayEnabled(getStorageValue(targetWindow?.sessionStorage, key));
5709
+ });
5710
+ };
5711
+ var getTargetOverlayState = (targetDocument) => ({
5712
+ grid: Boolean(
5713
+ targetDocument?.body.classList.contains("is-help") || targetDocument?.querySelector(".helper.onShow") || getStoredOverlayState(targetDocument, "grid")
5714
+ ),
5715
+ figma: Boolean(
5716
+ targetDocument?.querySelector(
5717
+ ".helper-figma-root, .helper-figma-loading-backdrop"
5718
+ ) || getStoredOverlayState(targetDocument, "figma")
5719
+ )
5720
+ });
5721
+
5617
5722
  // src/react-shell/topbar.tsx
5618
5723
  import { jsx as jsx16, jsxs as jsxs14 } from "react/jsx-runtime";
5619
5724
  var ReviewScopeIcon2 = ({ scope }) => {
@@ -5955,39 +6060,6 @@ import {
5955
6060
  useEffect as useEffect2
5956
6061
  } from "react";
5957
6062
 
5958
- // src/react-shell/target/target.ts
5959
- var HIDE_SCROLLBAR_STYLE_ID = "df-review-hide-scrollbar";
5960
- var setTargetScrollbarHidden = (targetDocument, hidden) => {
5961
- if (!targetDocument) return;
5962
- const existing = targetDocument.getElementById(HIDE_SCROLLBAR_STYLE_ID);
5963
- if (hidden) {
5964
- if (existing) return;
5965
- const style = targetDocument.createElement("style");
5966
- style.id = HIDE_SCROLLBAR_STYLE_ID;
5967
- style.textContent = "html{scrollbar-width:none}html::-webkit-scrollbar,body::-webkit-scrollbar{width:0;height:0;display:none}";
5968
- targetDocument.head?.appendChild(style);
5969
- } else {
5970
- existing?.remove();
5971
- }
5972
- };
5973
- var isEditableEventTarget = (event) => {
5974
- const path = event.composedPath?.() ?? [];
5975
- const element = path[0] ?? event.target;
5976
- if (!element || typeof element.tagName !== "string") return false;
5977
- const tag = element.tagName;
5978
- return tag === "INPUT" || tag === "TEXTAREA" || element.isContentEditable === true;
5979
- };
5980
- var getTargetOverlayState = (targetDocument) => ({
5981
- grid: Boolean(
5982
- targetDocument?.body.classList.contains("is-help") || targetDocument?.querySelector(".helper.onShow")
5983
- ),
5984
- figma: Boolean(
5985
- targetDocument?.querySelector(
5986
- ".helper-figma-root, .helper-figma-loading-backdrop"
5987
- )
5988
- )
5989
- });
5990
-
5991
6063
  // src/react-shell/hooks/review.frame.navigation.ts
5992
6064
  var bindReviewFrameNavigation = ({
5993
6065
  pageTargets,
@@ -6250,18 +6322,33 @@ var useReviewKitLifecycle = ({
6250
6322
  };
6251
6323
 
6252
6324
  // src/react-shell/hooks/use.review.target.overlay.ts
6253
- import { useCallback as useCallback3, useEffect as useEffect3 } from "react";
6325
+ import { useCallback as useCallback3, useEffect as useEffect3, useRef } from "react";
6326
+ var TARGET_OVERLAY_REFRESH_DELAYS = [80, 240, 600];
6254
6327
  var useReviewTargetOverlay = ({
6255
6328
  iframeRef,
6256
6329
  isFigmaOverlayAvailable,
6257
6330
  targetOverlayState,
6258
6331
  onTargetOverlayStateChange
6259
6332
  }) => {
6260
- const refreshTargetOverlayState = useCallback3(() => {
6261
- onTargetOverlayStateChange(
6262
- getTargetOverlayState(iframeRef.current?.contentDocument ?? void 0)
6333
+ const refreshTimersRef = useRef([]);
6334
+ const clearRefreshTimers = useCallback3(() => {
6335
+ refreshTimersRef.current.forEach((timer) => window.clearTimeout(timer));
6336
+ refreshTimersRef.current = [];
6337
+ }, []);
6338
+ const updateTargetOverlayState = useCallback3(() => {
6339
+ const state = getTargetOverlayState(
6340
+ iframeRef.current?.contentDocument ?? void 0
6263
6341
  );
6342
+ onTargetOverlayStateChange(state);
6343
+ return state;
6264
6344
  }, [iframeRef, onTargetOverlayStateChange]);
6345
+ const refreshTargetOverlayState = useCallback3(() => {
6346
+ clearRefreshTimers();
6347
+ updateTargetOverlayState();
6348
+ refreshTimersRef.current = TARGET_OVERLAY_REFRESH_DELAYS.map(
6349
+ (delay) => window.setTimeout(updateTargetOverlayState, delay)
6350
+ );
6351
+ }, [clearRefreshTimers, updateTargetOverlayState]);
6265
6352
  const dispatchTargetOverlayHotkey = useCallback3(
6266
6353
  (overlay) => {
6267
6354
  const targetWindow = iframeRef.current?.contentWindow;
@@ -6297,19 +6384,17 @@ var useReviewTargetOverlay = ({
6297
6384
  );
6298
6385
  const closeTargetOverlay = useCallback3(
6299
6386
  (overlay) => {
6300
- const currentState = getTargetOverlayState(
6301
- iframeRef.current?.contentDocument ?? void 0
6302
- );
6303
- onTargetOverlayStateChange(currentState);
6387
+ const currentState = updateTargetOverlayState();
6304
6388
  if (!currentState[overlay]) return false;
6305
6389
  return dispatchTargetOverlayHotkey(overlay);
6306
6390
  },
6307
- [dispatchTargetOverlayHotkey, iframeRef, onTargetOverlayStateChange]
6391
+ [dispatchTargetOverlayHotkey, updateTargetOverlayState]
6308
6392
  );
6309
6393
  useEffect3(() => {
6310
6394
  if (isFigmaOverlayAvailable || !targetOverlayState.figma) return;
6311
6395
  closeTargetOverlay("figma");
6312
6396
  }, [closeTargetOverlay, isFigmaOverlayAvailable, targetOverlayState.figma]);
6397
+ useEffect3(() => clearRefreshTimers, [clearRefreshTimers]);
6313
6398
  return {
6314
6399
  closeTargetOverlay,
6315
6400
  refreshTargetOverlayState,
@@ -6544,7 +6629,7 @@ import {
6544
6629
  useCallback as useCallback6,
6545
6630
  useEffect as useEffect5,
6546
6631
  useMemo as useMemo3,
6547
- useRef,
6632
+ useRef as useRef2,
6548
6633
  useState as useState4
6549
6634
  } from "react";
6550
6635
 
@@ -6761,7 +6846,7 @@ var useReviewPresence = ({
6761
6846
  size,
6762
6847
  source
6763
6848
  }) => {
6764
- const presenceSessionRef = useRef(null);
6849
+ const presenceSessionRef = useRef2(null);
6765
6850
  const [presenceUsers, setPresenceUsers] = useState4([]);
6766
6851
  const [presenceSessionVersion, setPresenceSessionVersion] = useState4(0);
6767
6852
  const presenceSessionId = useMemo3(getReviewPresenceSessionId, []);
@@ -6842,7 +6927,7 @@ var useReviewPresence = ({
6842
6927
  source
6843
6928
  ]
6844
6929
  );
6845
- const getCurrentPresenceStateRef = useRef(getCurrentPresenceState);
6930
+ const getCurrentPresenceStateRef = useRef2(getCurrentPresenceState);
6846
6931
  getCurrentPresenceStateRef.current = getCurrentPresenceState;
6847
6932
  useEffect5(() => {
6848
6933
  if (!presence || !normalizedReviewUserId) {
@@ -6922,7 +7007,7 @@ import {
6922
7007
  useCallback as useCallback7,
6923
7008
  useEffect as useEffect6,
6924
7009
  useMemo as useMemo4,
6925
- useRef as useRef2,
7010
+ useRef as useRef3,
6926
7011
  useState as useState5
6927
7012
  } from "react";
6928
7013
 
@@ -6953,10 +7038,10 @@ var useReviewRulerDrag = ({
6953
7038
  size,
6954
7039
  targetSrc
6955
7040
  }) => {
6956
- const rulerOverlayRef = useRef2(null);
6957
- const rulerDragRectRef = useRef2(null);
6958
- const isRulerDraggingRef = useRef2(false);
6959
- const sizeRef = useRef2(size);
7041
+ const rulerOverlayRef = useRef3(null);
7042
+ const rulerDragRectRef = useRef3(null);
7043
+ const isRulerDraggingRef = useRef3(false);
7044
+ const sizeRef = useRef3(size);
6960
7045
  const [rulerStart, setRulerStart] = useState5(null);
6961
7046
  const [rulerPoint, setRulerPoint] = useState5(null);
6962
7047
  const [rulerHover, setRulerHover] = useState5(null);
@@ -7615,7 +7700,7 @@ var useReviewShellHotkeys = ({
7615
7700
  // src/react-shell/hooks/use.review.shell.state.ts
7616
7701
  import {
7617
7702
  useMemo as useMemo6,
7618
- useRef as useRef3,
7703
+ useRef as useRef4,
7619
7704
  useState as useState9
7620
7705
  } from "react";
7621
7706
 
@@ -7786,14 +7871,14 @@ var useReviewShellState = ({
7786
7871
  const canWriteArea = activeAdapterEntry.writeModes.includes("area");
7787
7872
  const canWriteDom = activeAdapterEntry.writeModes.includes("dom");
7788
7873
  const adapter = activeAdapterEntry.adapter;
7789
- const iframeRef = useRef3(null);
7790
- const frameScrollRef = useRef3(null);
7791
- const controllerRef = useRef3(null);
7792
- const cleanupTargetRef = useRef3(null);
7793
- const pendingRestoreRef = useRef3(null);
7794
- const pendingInitialItemIdRef = useRef3(getInitialItemId());
7795
- const selectedItemIdRef = useRef3(getInitialItemId());
7796
- const hiddenOverlayItemIdListRef = useRef3([]);
7874
+ const iframeRef = useRef4(null);
7875
+ const frameScrollRef = useRef4(null);
7876
+ const controllerRef = useRef4(null);
7877
+ const cleanupTargetRef = useRef4(null);
7878
+ const pendingRestoreRef = useRef4(null);
7879
+ const pendingInitialItemIdRef = useRef4(getInitialItemId());
7880
+ const selectedItemIdRef = useRef4(getInitialItemId());
7881
+ const hiddenOverlayItemIdListRef = useRef4([]);
7797
7882
  const [target, setTarget] = useState9(
7798
7883
  () => getInitialTarget(reviewPathPrefix)
7799
7884
  );
@@ -7818,8 +7903,8 @@ var useReviewShellState = ({
7818
7903
  const [copyLabel, setCopyLabel] = useState9("Copy URL");
7819
7904
  const [toastMessage, setToastMessage] = useState9("");
7820
7905
  const [copiedPromptKey, setCopiedPromptKey] = useState9(null);
7821
- const targetRef = useRef3(target);
7822
- const sizeRef = useRef3(size);
7906
+ const targetRef = useRef4(target);
7907
+ const sizeRef = useRef4(size);
7823
7908
  const isFigmaOverlayAvailable = getIsFigmaOverlayAvailable(size);
7824
7909
  return {
7825
7910
  activeAdapterEntry,
@@ -8187,8 +8272,8 @@ var ReviewShell = ({
8187
8272
  presets,
8188
8273
  reviewPathPrefix
8189
8274
  });
8190
- const sourceShortcutCleanupRef = useRef4(null);
8191
- const sourceInspectorInteractionRef = useRef4(false);
8275
+ const sourceShortcutCleanupRef = useRef5(null);
8276
+ const sourceInspectorInteractionRef = useRef5(false);
8192
8277
  const [sourceInspectorState, setSourceInspectorState] = useState10(null);
8193
8278
  const [isAllQaVisible, setIsAllQaVisible] = useState10(false);
8194
8279
  const sourceOpenOptions = useMemo7(
@@ -8350,7 +8435,6 @@ var ReviewShell = ({
8350
8435
  });
8351
8436
  const {
8352
8437
  clearSelectedItem,
8353
- closeTargetOverlay,
8354
8438
  initReviewKit,
8355
8439
  reloadReviewKit,
8356
8440
  restoreReviewItem,
@@ -8488,9 +8572,6 @@ var ReviewShell = ({
8488
8572
  const writeMode = getReviewModeWriteMode(nextMode);
8489
8573
  if (writeMode && !activeAdapterEntry.writeModes.includes(writeMode)) return;
8490
8574
  closeRuler();
8491
- if (nextMode === "element") {
8492
- closeTargetOverlay("figma");
8493
- }
8494
8575
  setControllerReviewMode(nextMode);
8495
8576
  };
8496
8577
  useReviewShellHotkeys({
@@ -8527,6 +8608,13 @@ var ReviewShell = ({
8527
8608
  );
8528
8609
  setTargetFigmaState(config ? { targetSrc, config } : null);
8529
8610
  }, [iframeRef, targetSrc]);
8611
+ useEffect10(() => {
8612
+ const targetDocument = iframeRef.current?.contentDocument;
8613
+ setTargetFigmaOverlayLocked(targetDocument, mode === "element");
8614
+ return () => {
8615
+ setTargetFigmaOverlayLocked(targetDocument, false);
8616
+ };
8617
+ }, [iframeRef, mode, targetSrc]);
8530
8618
  const clearSourceInspector = useCallback11(() => {
8531
8619
  sourceInspectorInteractionRef.current = false;
8532
8620
  setSourceInspectorState(null);
@@ -8673,6 +8761,13 @@ var ReviewShell = ({
8673
8761
  cursor: crosshair !important;
8674
8762
  }
8675
8763
 
8764
+ html[${optionAttribute}="true"] .helper-figma-root,
8765
+ html[${optionAttribute}="true"] .helper-figma-root *,
8766
+ html[${optionAttribute}="true"] .helper-figma-loading-backdrop,
8767
+ html[${optionAttribute}="true"] .helper-figma-loading-backdrop * {
8768
+ pointer-events: none !important;
8769
+ }
8770
+
8676
8771
  html[${optionAttribute}="true"] body::before {
8677
8772
  position: fixed !important;
8678
8773
  z-index: 2147483647 !important;
@@ -8899,8 +8994,18 @@ var ReviewShell = ({
8899
8994
  const loadTargetFrame = useCallback11(() => {
8900
8995
  initReviewKit();
8901
8996
  refreshTargetFigmaConfig();
8997
+ setTargetFigmaOverlayLocked(
8998
+ iframeRef.current?.contentDocument,
8999
+ mode === "element"
9000
+ );
8902
9001
  bindSourceOpenShortcut();
8903
- }, [bindSourceOpenShortcut, initReviewKit, refreshTargetFigmaConfig]);
9002
+ }, [
9003
+ bindSourceOpenShortcut,
9004
+ iframeRef,
9005
+ initReviewKit,
9006
+ mode,
9007
+ refreshTargetFigmaConfig
9008
+ ]);
8904
9009
  useEffect10(() => {
8905
9010
  const frame = window.requestAnimationFrame(bindSourceOpenShortcut);
8906
9011
  return () => window.cancelAnimationFrame(frame);