@designfever/web-review-kit 0.7.0 → 0.7.2

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.
@@ -69,6 +69,7 @@ type ReviewShellSyncSubmissionInput = {
69
69
  type ReviewShellAdapter = {
70
70
  label: ReviewSource;
71
71
  pageId?: string;
72
+ defaultUserId?: string;
72
73
  get: WebReviewKitAdapter['get'];
73
74
  list: WebReviewKitAdapter['list'];
74
75
  create?: WebReviewKitAdapter['create'];
@@ -87,6 +88,7 @@ type ReviewShellAdapterMap = {
87
88
  local: WebReviewKitAdapter;
88
89
  remote?: WebReviewKitAdapter | null;
89
90
  remotePageId?: string;
91
+ defaultUserId?: string;
90
92
  };
91
93
  type ReviewShellAdapters = ReviewShellAdapterMap | ReviewShellAdapter[];
92
94
  type ReviewPresenceStatus = 'idle' | 'reviewing' | 'editing';
@@ -69,6 +69,7 @@ type ReviewShellSyncSubmissionInput = {
69
69
  type ReviewShellAdapter = {
70
70
  label: ReviewSource;
71
71
  pageId?: string;
72
+ defaultUserId?: string;
72
73
  get: WebReviewKitAdapter['get'];
73
74
  list: WebReviewKitAdapter['list'];
74
75
  create?: WebReviewKitAdapter['create'];
@@ -87,6 +88,7 @@ type ReviewShellAdapterMap = {
87
88
  local: WebReviewKitAdapter;
88
89
  remote?: WebReviewKitAdapter | null;
89
90
  remotePageId?: string;
91
+ defaultUserId?: string;
90
92
  };
91
93
  type ReviewShellAdapters = ReviewShellAdapterMap | ReviewShellAdapter[];
92
94
  type ReviewPresenceStatus = 'idle' | 'reviewing' | 'editing';
@@ -5527,7 +5527,10 @@ var buildTargetSrc = (target) => {
5527
5527
  return `${url.pathname}${url.search}${url.hash}`;
5528
5528
  };
5529
5529
  var getFrameRouteTarget = (targetWindow, reviewPathPrefix) => {
5530
- return normalizeTarget(targetWindow.location.pathname, reviewPathPrefix);
5530
+ return normalizeTarget(
5531
+ `${targetWindow.location.pathname}${targetWindow.location.search}${targetWindow.location.hash}`,
5532
+ reviewPathPrefix
5533
+ );
5531
5534
  };
5532
5535
  var updateShellUrl = (target, size, source) => {
5533
5536
  const url = new URL(window.location.href);
@@ -5702,7 +5705,7 @@ var ABOUT_SECTIONS = [
5702
5705
  },
5703
5706
  {
5704
5707
  title: "Figma token",
5705
- body: "Add a browser-safe Figma token in Settings only when the host page already supports the Figma overlay helper. The package stores it in localStorage as figma-token and does not own a server-side Figma integration."
5708
+ body: "Project owners can set FIGMA_TOKEN on the server. Reviewers who cannot change env can add a browser-local Figma token in Settings; it is stored as figma-token and used only as an image-store fallback."
5706
5709
  },
5707
5710
  {
5708
5711
  title: "User ID",
@@ -6002,12 +6005,13 @@ var writeStoredFigmaToken = (token) => {
6002
6005
  return;
6003
6006
  }
6004
6007
  };
6005
- var getStoredReviewUserId = () => {
6006
- if (typeof window === "undefined") return "";
6008
+ var getStoredReviewUserId = (fallback = "") => {
6009
+ const normalizedFallback = fallback.trim();
6010
+ if (typeof window === "undefined") return normalizedFallback;
6007
6011
  try {
6008
- return window.localStorage.getItem(REVIEW_USER_ID_STORAGE_KEY) ?? "";
6012
+ return window.localStorage.getItem(REVIEW_USER_ID_STORAGE_KEY)?.trim() || normalizedFallback;
6009
6013
  } catch {
6010
- return "";
6014
+ return normalizedFallback;
6011
6015
  }
6012
6016
  };
6013
6017
  var writeStoredReviewUserId = (userId) => {
@@ -12955,15 +12959,18 @@ var useReviewFigmaImages = ({
12955
12959
  // src/react-shell/hooks/use.review.settings.ts
12956
12960
  import { useCallback as useCallback13, useEffect as useEffect11, useState as useState10 } from "react";
12957
12961
  var useReviewSettings = ({
12962
+ defaultReviewUserId = "",
12958
12963
  onCancelReviewMode,
12959
12964
  onCloseInitialPrompt,
12960
12965
  onCloseSitemap,
12961
12966
  onReloadTargetFrame
12962
12967
  }) => {
12963
12968
  const [figmaTokenDraft, setFigmaTokenDraft] = useState10(getStoredFigmaToken);
12964
- const [reviewUserId, setReviewUserId] = useState10(getStoredReviewUserId);
12969
+ const [reviewUserId, setReviewUserId] = useState10(
12970
+ () => getStoredReviewUserId(defaultReviewUserId)
12971
+ );
12965
12972
  const [reviewUserIdDraft, setReviewUserIdDraft] = useState10(
12966
- getStoredReviewUserId
12973
+ () => getStoredReviewUserId(defaultReviewUserId)
12967
12974
  );
12968
12975
  const [reviewTheme, setReviewTheme] = useState10(getStoredReviewTheme);
12969
12976
  const [reviewThemeDraft, setReviewThemeDraft] = useState10(getStoredReviewTheme);
@@ -12984,7 +12991,7 @@ var useReviewSettings = ({
12984
12991
  onCloseSitemap();
12985
12992
  onCloseInitialPrompt();
12986
12993
  setFigmaTokenDraft(getStoredFigmaToken());
12987
- setReviewUserIdDraft(getStoredReviewUserId());
12994
+ setReviewUserIdDraft(getStoredReviewUserId(defaultReviewUserId));
12988
12995
  setReviewThemeDraft(reviewTheme);
12989
12996
  setFigmaSettingsStatus("");
12990
12997
  setIsFigmaTokenVisible(false);
@@ -12994,6 +13001,7 @@ var useReviewSettings = ({
12994
13001
  onCancelReviewMode,
12995
13002
  onCloseInitialPrompt,
12996
13003
  onCloseSitemap,
13004
+ defaultReviewUserId,
12997
13005
  reviewTheme
12998
13006
  ]);
12999
13007
  const saveReviewSettings = useCallback13(
@@ -13020,6 +13028,12 @@ var useReviewSettings = ({
13020
13028
  },
13021
13029
  [closeFigmaSettings, onReloadTargetFrame]
13022
13030
  );
13031
+ useEffect11(() => {
13032
+ if (getStoredReviewUserId()) return;
13033
+ const nextDefaultUserId = defaultReviewUserId.trim();
13034
+ setReviewUserId(nextDefaultUserId);
13035
+ setReviewUserIdDraft(nextDefaultUserId);
13036
+ }, [defaultReviewUserId]);
13023
13037
  useEffect11(() => {
13024
13038
  if (typeof window === "undefined" || !window.matchMedia) return void 0;
13025
13039
  const query = window.matchMedia("(prefers-color-scheme: light)");
@@ -13424,6 +13438,7 @@ function normalizeLegacyAdapterMap(adapters) {
13424
13438
  statusOptions: [...REVIEW_WORKFLOW_STATUS_OPTIONS],
13425
13439
  assigneeTitle: DEFAULT_ASSIGNEE_TITLE,
13426
13440
  assigneeOptions: [],
13441
+ defaultUserId: adapters.defaultUserId?.trim() ?? "",
13427
13442
  updateStatus: ({ id, status }) => adapters.local.update(id, { status }),
13428
13443
  updateAssignee: ({ id, assigneeId, assigneeName }) => adapters.local.update(id, { assigneeId, assigneeName }),
13429
13444
  syncSubmission: ({ id, patch }) => adapters.local.update(id, patch),
@@ -13438,6 +13453,7 @@ function normalizeLegacyAdapterMap(adapters) {
13438
13453
  statusOptions: [...REVIEW_WORKFLOW_STATUS_OPTIONS],
13439
13454
  assigneeTitle: DEFAULT_ASSIGNEE_TITLE,
13440
13455
  assigneeOptions: [],
13456
+ defaultUserId: adapters.defaultUserId?.trim() ?? "",
13441
13457
  updateStatus: ({ id, status }) => adapters.remote?.update(id, { status }) ?? Promise.reject(new Error("Remote adapter is not available.")),
13442
13458
  updateAssignee: ({ id, assigneeId, assigneeName }) => adapters.remote?.update(id, { assigneeId, assigneeName }) ?? Promise.reject(new Error("Remote adapter is not available.")),
13443
13459
  writeModes: [],
@@ -13460,6 +13476,7 @@ function normalizeShellAdapter(adapterConfig) {
13460
13476
  };
13461
13477
  const assigneeTitle = adapterConfig.assigneeTitle?.trim() || DEFAULT_ASSIGNEE_TITLE;
13462
13478
  const assigneeOptions = [...adapterConfig.assigneeOptions ?? []];
13479
+ const defaultUserId = adapterConfig.defaultUserId?.trim() ?? "";
13463
13480
  const updateAdapter = adapterConfig.update;
13464
13481
  const updateStatus = adapterConfig.updateStatus ? adapterConfig.updateStatus : updateAdapter ? ({ id, status }) => updateAdapter(id, { status }) : void 0;
13465
13482
  const updateAssignee = adapterConfig.updateAssignee ? adapterConfig.updateAssignee : updateAdapter ? ({ id, assigneeId, assigneeName, assigneeOption }) => updateAdapter(id, {
@@ -13476,6 +13493,7 @@ function normalizeShellAdapter(adapterConfig) {
13476
13493
  statusOptions,
13477
13494
  assigneeTitle,
13478
13495
  assigneeOptions,
13496
+ defaultUserId,
13479
13497
  updateStatus,
13480
13498
  updateAssignee,
13481
13499
  syncSubmission: adapterConfig.syncSubmission,
@@ -14032,8 +14050,10 @@ var ReviewShell = ({
14032
14050
  });
14033
14051
  const sourceShortcutCleanupRef = useRef8(null);
14034
14052
  const sourceInspectorInteractionRef = useRef8(false);
14053
+ const sectionOutlineCountRef = useRef8(0);
14035
14054
  const [sourceInspectorState, setSourceInspectorState] = useState13(null);
14036
14055
  const [sectionOutline, setSectionOutline] = useState13(null);
14056
+ const [targetFrameLoadVersion, setTargetFrameLoadVersion] = useState13(0);
14037
14057
  const [sectionOutlineFilter, setSectionOutlineFilter] = useState13(
14038
14058
  () => getStoredSourceTreeFilter()
14039
14059
  );
@@ -14135,6 +14155,9 @@ var ReviewShell = ({
14135
14155
  [filteredSectionOutline]
14136
14156
  );
14137
14157
  const isSectionOutlineFiltering = sectionOutlineFilterTerms.length > 0;
14158
+ useEffect13(() => {
14159
+ sectionOutlineCountRef.current = sectionOutlineTotalCount;
14160
+ }, [sectionOutlineTotalCount]);
14138
14161
  const {
14139
14162
  activeItems,
14140
14163
  activeRemainingItemCount,
@@ -14286,6 +14309,7 @@ var ReviewShell = ({
14286
14309
  setReviewThemeDraft,
14287
14310
  setReviewUserIdDraft
14288
14311
  } = useReviewSettings({
14312
+ defaultReviewUserId: activeAdapterEntry.defaultUserId,
14289
14313
  onCancelReviewMode: cancelReviewMode,
14290
14314
  onCloseInitialPrompt: closePromptModal,
14291
14315
  onCloseSitemap: closeSitemap,
@@ -14715,32 +14739,78 @@ var ReviewShell = ({
14715
14739
  const setSectionOutlineWithDefaultCollapse = useCallback15(
14716
14740
  (nextSectionOutline) => {
14717
14741
  setSectionOutline(nextSectionOutline);
14742
+ sectionOutlineCountRef.current = getSectionOutlineEntryCount(nextSectionOutline);
14718
14743
  setCollapsedSectionOutlineIds(
14719
14744
  getDefaultCollapsedSectionOutlineIds(nextSectionOutline)
14720
14745
  );
14721
14746
  },
14722
14747
  []
14723
14748
  );
14749
+ const refreshCurrentSectionOutline = useCallback15(
14750
+ (resetCollapse = false) => {
14751
+ const nextSectionOutline = getCurrentSectionOutline();
14752
+ if (!nextSectionOutline) return false;
14753
+ setSectionOutline(nextSectionOutline);
14754
+ const nextCount = getSectionOutlineEntryCount(nextSectionOutline);
14755
+ const shouldResetCollapse = resetCollapse || sectionOutlineCountRef.current === 0;
14756
+ sectionOutlineCountRef.current = nextCount;
14757
+ if (shouldResetCollapse) {
14758
+ setCollapsedSectionOutlineIds(
14759
+ getDefaultCollapsedSectionOutlineIds(nextSectionOutline)
14760
+ );
14761
+ }
14762
+ return true;
14763
+ },
14764
+ [getCurrentSectionOutline]
14765
+ );
14724
14766
  useEffect13(() => {
14725
14767
  if (sidePanel !== "source" || !isListVisible) return void 0;
14726
14768
  const refreshSectionOutline = () => {
14727
- const nextSectionOutline = getCurrentSectionOutline();
14728
- if (!nextSectionOutline) return;
14729
- setSectionOutlineWithDefaultCollapse(nextSectionOutline);
14769
+ refreshCurrentSectionOutline(true);
14730
14770
  };
14731
14771
  const animationFrame = window.requestAnimationFrame(refreshSectionOutline);
14732
14772
  const firstTimeout = window.setTimeout(refreshSectionOutline, 120);
14733
14773
  const secondTimeout = window.setTimeout(refreshSectionOutline, 500);
14774
+ const thirdTimeout = window.setTimeout(refreshSectionOutline, 1200);
14734
14775
  return () => {
14735
14776
  window.cancelAnimationFrame(animationFrame);
14736
14777
  window.clearTimeout(firstTimeout);
14737
14778
  window.clearTimeout(secondTimeout);
14779
+ window.clearTimeout(thirdTimeout);
14738
14780
  };
14739
14781
  }, [
14740
- getCurrentSectionOutline,
14741
14782
  isListVisible,
14742
- setSectionOutlineWithDefaultCollapse,
14783
+ refreshCurrentSectionOutline,
14743
14784
  sidePanel,
14785
+ targetFrameLoadVersion,
14786
+ targetSrc
14787
+ ]);
14788
+ useEffect13(() => {
14789
+ if (sidePanel !== "source" || !isListVisible) return void 0;
14790
+ const frameDocument = iframeRef.current?.contentDocument;
14791
+ const body = frameDocument?.body;
14792
+ if (!body) return void 0;
14793
+ let refreshTimeout = null;
14794
+ const scheduleRefresh = () => {
14795
+ if (refreshTimeout) window.clearTimeout(refreshTimeout);
14796
+ refreshTimeout = window.setTimeout(() => {
14797
+ refreshTimeout = null;
14798
+ refreshCurrentSectionOutline(false);
14799
+ }, 80);
14800
+ };
14801
+ const observer = new MutationObserver(scheduleRefresh);
14802
+ observer.observe(body, { childList: true, subtree: true });
14803
+ scheduleRefresh();
14804
+ return () => {
14805
+ if (refreshTimeout) window.clearTimeout(refreshTimeout);
14806
+ observer.disconnect();
14807
+ };
14808
+ }, [
14809
+ iframeRef,
14810
+ isListVisible,
14811
+ refreshCurrentSectionOutline,
14812
+ sidePanel,
14813
+ targetFrameLoadVersion,
14744
14814
  targetSrc
14745
14815
  ]);
14746
14816
  const toggleQaPanel = useCallback15(() => {
@@ -14754,16 +14824,12 @@ var ReviewShell = ({
14754
14824
  return;
14755
14825
  }
14756
14826
  setSidePanel("source");
14757
- const nextSectionOutline = getCurrentSectionOutline();
14758
- if (nextSectionOutline) {
14759
- setSectionOutlineWithDefaultCollapse(nextSectionOutline);
14760
- }
14827
+ refreshCurrentSectionOutline(true);
14761
14828
  setIsListVisible(true);
14762
14829
  }, [
14763
- getCurrentSectionOutline,
14764
14830
  isListVisible,
14765
14831
  isSourceInspectorEnabled,
14766
- setSectionOutlineWithDefaultCollapse,
14832
+ refreshCurrentSectionOutline,
14767
14833
  setIsListVisible,
14768
14834
  sidePanel
14769
14835
  ]);
@@ -15070,6 +15136,7 @@ var ReviewShell = ({
15070
15136
  return cleanupSourceOpenShortcut;
15071
15137
  }, [cleanupSourceOpenShortcut]);
15072
15138
  const loadTargetFrame = useCallback15(() => {
15139
+ setTargetFrameLoadVersion((currentVersion) => currentVersion + 1);
15073
15140
  initReviewKit();
15074
15141
  refreshTargetFigmaConfig();
15075
15142
  setTargetFigmaOverlayLocked(
@@ -15078,20 +15145,16 @@ var ReviewShell = ({
15078
15145
  );
15079
15146
  bindSourceOpenShortcut();
15080
15147
  if (sidePanel === "source" && isListVisible) {
15081
- const nextSectionOutline = getCurrentSectionOutline();
15082
- if (nextSectionOutline) {
15083
- setSectionOutlineWithDefaultCollapse(nextSectionOutline);
15084
- }
15148
+ refreshCurrentSectionOutline(true);
15085
15149
  }
15086
15150
  }, [
15087
15151
  bindSourceOpenShortcut,
15088
- getCurrentSectionOutline,
15089
15152
  iframeRef,
15090
15153
  initReviewKit,
15091
15154
  isListVisible,
15092
15155
  mode,
15093
15156
  refreshTargetFigmaConfig,
15094
- setSectionOutlineWithDefaultCollapse,
15157
+ refreshCurrentSectionOutline,
15095
15158
  sidePanel
15096
15159
  ]);
15097
15160
  useEffect13(() => {