@hyperframes/studio 0.8.52 → 0.8.53

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.
Files changed (75) hide show
  1. package/dist/assets/{hyperframes-player-I5YRzB02.js → hyperframes-player-DKWM-Ons.js} +1 -1
  2. package/dist/assets/index-DrHQAuGO.css +1 -0
  3. package/dist/assets/index-HfP3sap2.js +390 -0
  4. package/dist/assets/{index-BTAfgesM.js → index-UvW6BEwf.js} +1 -1
  5. package/dist/assets/{index-Du5x7KUR.js → index-Y4OnpTEM.js} +1 -1
  6. package/dist/index.css +29 -0
  7. package/dist/index.css.map +1 -0
  8. package/dist/index.d.ts +13 -6
  9. package/dist/index.html +2 -2
  10. package/dist/index.js +7664 -7953
  11. package/dist/index.js.map +1 -1
  12. package/dist/styles.css +1 -0
  13. package/package.json +8 -7
  14. package/src/App.tsx +42 -48
  15. package/src/components/EditorShell.selectionSync.test.tsx +9 -4
  16. package/src/components/EditorShell.tsx +52 -56
  17. package/src/components/StudioHeader.dom.test.tsx +1 -1
  18. package/src/components/StudioHeader.test.ts +0 -12
  19. package/src/components/StudioHeader.tsx +10 -13
  20. package/src/components/StudioLeftPanels.tsx +202 -0
  21. package/src/components/{StudioRightPanel.tsx → StudioRightPanels.tsx} +57 -206
  22. package/src/components/{StudioRightPanel.types.ts → StudioRightPanels.types.ts} +4 -3
  23. package/src/components/dock/Dock.test.tsx +16 -2
  24. package/src/components/dock/Dock.tsx +13 -3
  25. package/src/components/dock/dockLayoutStore.test.ts +28 -0
  26. package/src/components/dock/dockLayoutStore.ts +21 -4
  27. package/src/components/editor/SnapToolbar.test.tsx +0 -3
  28. package/src/components/nle/NLEContext.tsx +0 -43
  29. package/src/components/nle/TimelinePane.tsx +46 -67
  30. package/src/components/panels/SlideshowPanel.tsx +1 -1
  31. package/src/components/panels/VariablesPanel.tsx +1 -1
  32. package/src/components/renders/RenderQueue.test.tsx +133 -25
  33. package/src/components/renders/RenderQueue.tsx +99 -92
  34. package/src/components/renders/RenderQueueItem.tsx +69 -64
  35. package/src/components/renders/RenderQueuePanel.tsx +1 -1
  36. package/src/components/sidebar/{LeftSidebar.masterComposition.test.tsx → CompositionsPanel.masterComposition.test.tsx} +6 -9
  37. package/src/components/sidebar/CompositionsPanel.tsx +15 -0
  38. package/src/components/sidebar/{LeftSidebar.lintBadge.test.tsx → SidebarLintButton.test.tsx} +6 -11
  39. package/src/components/sidebar/SidebarLintButton.tsx +50 -0
  40. package/src/components/ui/Select.tsx +4 -0
  41. package/src/contexts/PanelLayoutContext.tsx +3 -57
  42. package/src/headerExports.test.tsx +23 -0
  43. package/src/hooks/appHotkeysDispatch.ts +3 -4
  44. package/src/hooks/useAppHotkeys.previewForwarding.test.tsx +0 -2
  45. package/src/hooks/useAppHotkeys.test.ts +0 -1
  46. package/src/hooks/useAppHotkeys.textEditing.test.tsx +0 -3
  47. package/src/hooks/useAppHotkeys.ts +0 -4
  48. package/src/hooks/useDomEditPreviewSync.ts +4 -6
  49. package/src/hooks/useDomEditSession.ts +0 -7
  50. package/src/hooks/useDomEditWiring.ts +4 -9
  51. package/src/hooks/usePanelLayout.test.ts +108 -296
  52. package/src/hooks/usePanelLayout.ts +50 -255
  53. package/src/hooks/useRightPanelIntents.test.ts +181 -0
  54. package/src/hooks/useRightPanelIntents.ts +64 -0
  55. package/src/hooks/useSlideshowTabState.test.ts +9 -31
  56. package/src/hooks/useSlideshowTabState.ts +6 -19
  57. package/src/hooks/useStudioContextValue.test.ts +6 -18
  58. package/src/hooks/useStudioContextValue.ts +5 -26
  59. package/src/index.ts +2 -1
  60. package/src/main.tsx +26 -0
  61. package/src/player/components/Timeline.tsx +1 -1
  62. package/src/player/lib/timelinePerformanceDiagnostics.test.ts +3 -2
  63. package/src/player/lib/timelinePerformanceDiagnostics.ts +1 -1
  64. package/src/utils/studioHelpers.ts +0 -7
  65. package/src/utils/studioUiPreferences.test.ts +10 -16
  66. package/src/utils/studioUiPreferences.ts +0 -16
  67. package/dist/assets/index-CxAu_Okg.css +0 -1
  68. package/dist/assets/index-DocJlW2v.js +0 -376
  69. package/src/components/StudioLeftSidebar.tsx +0 -207
  70. package/src/components/nle/TimelineResizeDivider.tsx +0 -101
  71. package/src/components/sidebar/LeftSidebar.storage.test.ts +0 -28
  72. package/src/components/sidebar/LeftSidebar.tsx +0 -348
  73. package/src/hooks/useInspectorSplitResize.ts +0 -51
  74. package/src/utils/fitPanels.test.ts +0 -164
  75. package/src/utils/fitPanels.ts +0 -151
@@ -0,0 +1,50 @@
1
+ export function SidebarLintButton({
2
+ onLint,
3
+ linting,
4
+ findingCount,
5
+ hasError,
6
+ }: {
7
+ onLint: () => void;
8
+ linting: boolean;
9
+ findingCount?: number;
10
+ hasError?: boolean;
11
+ }) {
12
+ return (
13
+ <div className="border-t border-neutral-800 p-2 shrink-0">
14
+ <button
15
+ type="button"
16
+ onClick={onLint}
17
+ disabled={linting}
18
+ className="w-full flex items-center justify-center gap-1.5 px-2 py-1.5 rounded-md text-[11px] font-medium text-neutral-500 enabled:hover:text-amber-300 enabled:hover:bg-neutral-800 enabled:active:scale-[0.98] transition-colors disabled:opacity-40"
19
+ >
20
+ <svg
21
+ width="12"
22
+ height="12"
23
+ viewBox="0 0 24 24"
24
+ fill="none"
25
+ stroke="currentColor"
26
+ strokeWidth="2"
27
+ >
28
+ <path d="M9 11l3 3L22 4" />
29
+ <path d="M21 12v7a2 2 0 01-2 2H5a2 2 0 01-2-2V5a2 2 0 012-2h11" />
30
+ </svg>
31
+ {linting ? "Linting…" : "Lint"}
32
+ {!linting && findingCount != null && findingCount > 0 && (
33
+ <span
34
+ data-lint-badge={hasError ? "error" : "warning"}
35
+ className={
36
+ hasError
37
+ ? "ml-1 min-w-[16px] rounded-full bg-panel-danger/25 px-1 text-[9px] font-bold text-panel-danger animate-pulse motion-reduce:animate-none"
38
+ : "ml-1 min-w-[16px] rounded-full bg-amber-500/20 px-1 text-[9px] font-bold text-amber-400"
39
+ }
40
+ >
41
+ {findingCount}
42
+ <span className="sr-only">
43
+ {hasError ? " lint findings, including errors" : " lint findings, warnings only"}
44
+ </span>
45
+ </span>
46
+ )}
47
+ </button>
48
+ </div>
49
+ );
50
+ }
@@ -11,6 +11,8 @@ import type { PreviewState } from "./Button";
11
11
  export interface SelectOption {
12
12
  label: string;
13
13
  value: string;
14
+ /** Offered but not choosable; the label stays visible so the reason stays visible too. */
15
+ disabled?: boolean;
14
16
  }
15
17
 
16
18
  export interface SelectProps {
@@ -81,11 +83,13 @@ export function Select({
81
83
  <BaseSelect.Item
82
84
  key={option.value}
83
85
  value={option.value}
86
+ disabled={option.disabled}
84
87
  className={cn(
85
88
  "flex h-ctl-sm cursor-pointer select-none items-center gap-2 px-2.5",
86
89
  "text-step-11 text-text-2 outline-hidden",
87
90
  "data-[highlighted]:bg-hover data-[highlighted]:text-text-0",
88
91
  "data-[selected]:text-text-0",
92
+ "data-[disabled]:cursor-not-allowed data-[disabled]:opacity-40",
89
93
  )}
90
94
  >
91
95
  <BaseSelect.ItemText className="truncate">{option.label}</BaseSelect.ItemText>
@@ -13,69 +13,15 @@ export function usePanelLayoutContext(): PanelLayoutValue {
13
13
  }
14
14
 
15
15
  export function PanelLayoutProvider({
16
- value: {
17
- leftWidth,
18
- rightWidth,
19
- adjustPanelWidth,
20
- leftCollapsed,
21
- rightCollapsed,
22
- setRightCollapsed,
23
- effectiveLeftCollapsed,
24
- effectiveRightCollapsed,
25
- rightPanelTab,
26
- setRightPanelTab,
27
- rightInspectorPanes,
28
- toggleRightInspectorPane,
29
- setExclusiveRightInspectorPane,
30
- toggleLeftSidebar,
31
- handlePanelResizeStart,
32
- handlePanelResizeMove,
33
- handlePanelResizeEnd,
34
- },
16
+ value: { rightCollapsed, setRightCollapsed, rightPanelTab, setRightPanelTab },
35
17
  children,
36
18
  }: {
37
19
  value: PanelLayoutValue;
38
20
  children: ReactNode;
39
21
  }) {
40
22
  const stable = useMemo<PanelLayoutValue>(
41
- () => ({
42
- leftWidth,
43
- rightWidth,
44
- adjustPanelWidth,
45
- leftCollapsed,
46
- rightCollapsed,
47
- setRightCollapsed,
48
- effectiveLeftCollapsed,
49
- effectiveRightCollapsed,
50
- rightPanelTab,
51
- setRightPanelTab,
52
- rightInspectorPanes,
53
- toggleRightInspectorPane,
54
- setExclusiveRightInspectorPane,
55
- toggleLeftSidebar,
56
- handlePanelResizeStart,
57
- handlePanelResizeMove,
58
- handlePanelResizeEnd,
59
- }),
60
- [
61
- leftWidth,
62
- rightWidth,
63
- adjustPanelWidth,
64
- leftCollapsed,
65
- rightCollapsed,
66
- setRightCollapsed,
67
- effectiveLeftCollapsed,
68
- effectiveRightCollapsed,
69
- rightPanelTab,
70
- setRightPanelTab,
71
- rightInspectorPanes,
72
- toggleRightInspectorPane,
73
- setExclusiveRightInspectorPane,
74
- toggleLeftSidebar,
75
- handlePanelResizeStart,
76
- handlePanelResizeMove,
77
- handlePanelResizeEnd,
78
- ],
23
+ () => ({ rightCollapsed, setRightCollapsed, rightPanelTab, setRightPanelTab }),
24
+ [rightCollapsed, setRightCollapsed, rightPanelTab, setRightPanelTab],
79
25
  );
80
26
  return <PanelLayoutContext value={stable}>{children}</PanelLayoutContext>;
81
27
  }
@@ -0,0 +1,23 @@
1
+ // @vitest-environment happy-dom
2
+ // Imports the header logo and button size classes the way a host app does: by package name.
3
+ import { createRoot } from "react-dom/client";
4
+ import { act } from "react";
5
+ import { describe, expect, it } from "vitest";
6
+ import { HyperframesLogo, buttonSizes } from "@hyperframes/studio";
7
+
8
+ Object.assign(globalThis, { IS_REACT_ACT_ENVIRONMENT: true });
9
+
10
+ describe("header package exports", () => {
11
+ it("mounts the logo mark", async () => {
12
+ const el = document.createElement("div");
13
+ document.body.append(el);
14
+ const root = createRoot(el);
15
+ await act(async () => root.render(<HyperframesLogo />));
16
+ expect(el.querySelector("svg")).not.toBeNull();
17
+ await act(async () => root.unmount());
18
+ });
19
+
20
+ it("exposes the button size classes a host reuses for matching chrome", () => {
21
+ expect(buttonSizes.md).toEqual(expect.any(String));
22
+ });
23
+ });
@@ -2,7 +2,7 @@ import { automationOwnsKey } from "./useAutomationSelectionKeyboard";
2
2
  import { usePlayerStore } from "../player";
3
3
  import type { TimelineElement } from "../player";
4
4
  import type { DomEditSelection } from "../components/editor/domEditing";
5
- import type { LeftSidebarHandle } from "../components/sidebar/LeftSidebar";
5
+ import { useDockLayoutStore } from "../components/dock/dockLayoutStore";
6
6
  import { isTypingTarget } from "../utils/typingTarget";
7
7
  import { isEditableTarget } from "../utils/timelineDiscovery";
8
8
  import { shouldIgnoreHistoryShortcut } from "../utils/studioHelpers";
@@ -52,7 +52,6 @@ export interface HotkeyCallbacks {
52
52
  onToggleRecording?: () => void;
53
53
  onGroupSelection?: () => void;
54
54
  onUngroupSelection?: () => void;
55
- leftSidebarRef: React.RefObject<LeftSidebarHandle | null>;
56
55
  domEditSelectionRef: React.MutableRefObject<DomEditSelection | null>;
57
56
  showToast: (message: string, tone?: "error" | "info") => void;
58
57
  }
@@ -84,13 +83,13 @@ export function dispatchModifierKey(
84
83
  if (event.key === "1") {
85
84
  event.preventDefault();
86
85
  trackStudioEvent("keyboard_shortcut", { action: "tab_compositions" });
87
- cb.leftSidebarRef.current?.selectTab("compositions");
86
+ useDockLayoutStore.getState().activatePanel("compositions");
88
87
  return true;
89
88
  }
90
89
  if (event.key === "2") {
91
90
  event.preventDefault();
92
91
  trackStudioEvent("keyboard_shortcut", { action: "tab_assets" });
93
- cb.leftSidebarRef.current?.selectTab("assets");
92
+ useDockLayoutStore.getState().activatePanel("assets");
94
93
  return true;
95
94
  }
96
95
 
@@ -4,7 +4,6 @@ import React, { act, useRef } from "react";
4
4
  import type { Root } from "react-dom/client";
5
5
  import { afterEach, describe, expect, it, vi } from "vitest";
6
6
  import type { DomEditSelection } from "../components/editor/domEditing";
7
- import type { LeftSidebarHandle } from "../components/sidebar/LeftSidebar";
8
7
  import { usePlayerStore } from "../player/store/playerStore";
9
8
  import { useAppHotkeys } from "./useAppHotkeys";
10
9
  import { mountReactHarness } from "./domSelectionTestHarness";
@@ -46,7 +45,6 @@ function Harness() {
46
45
  showToast: vi.fn(),
47
46
  syncHistoryPreviewAfterApply: vi.fn(async () => undefined),
48
47
  waitForPendingDomEditSaves: vi.fn(async () => undefined),
49
- leftSidebarRef: useRef<LeftSidebarHandle | null>(null),
50
48
  handleCopy: vi.fn(() => false),
51
49
  handlePaste: vi.fn(() => false),
52
50
  handleCut: vi.fn(() => false),
@@ -33,7 +33,6 @@ function callbacks() {
33
33
  onResetKeyframes: vi.fn(() => true),
34
34
  onDeleteSelectedKeyframes: vi.fn(),
35
35
  showToast: vi.fn(),
36
- leftSidebarRef: { current: null },
37
36
  domEditSelectionRef: { current: null },
38
37
  };
39
38
  }
@@ -5,7 +5,6 @@ import { createRoot, type Root } from "react-dom/client";
5
5
  import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
6
6
  import { TextAreaField } from "../components/editor/propertyPanelSections";
7
7
  import type { DomEditSelection } from "../components/editor/domEditing";
8
- import type { LeftSidebarHandle } from "../components/sidebar/LeftSidebar";
9
8
  import { usePlayerStore } from "../player/store/playerStore";
10
9
  import { useAppHotkeys } from "./useAppHotkeys";
11
10
 
@@ -70,7 +69,6 @@ function Harness() {
70
69
  const [selectionRefreshed, setSelectionRefreshed] = useState(false);
71
70
  const selectionRef = useRef<DomEditSelection | null>(parentWithTextChild());
72
71
  const clearSelectionRef = useRef<() => void>(() => undefined);
73
- const leftSidebarRef = useRef<LeftSidebarHandle | null>(null);
74
72
 
75
73
  useAppHotkeys({
76
74
  handleTimelineElementsDelete: timelineDeleteMany,
@@ -89,7 +87,6 @@ function Harness() {
89
87
  showToast: vi.fn(),
90
88
  syncHistoryPreviewAfterApply: vi.fn(async () => undefined),
91
89
  waitForPendingDomEditSaves: vi.fn(async () => undefined),
92
- leftSidebarRef,
93
90
  handleCopy: vi.fn(() => false),
94
91
  handlePaste: vi.fn(async () => undefined),
95
92
  handleCut: vi.fn(async () => false),
@@ -2,7 +2,6 @@ import { useCallback, useEffect, useRef } from "react";
2
2
  import { usePlayerStore } from "../player";
3
3
  import type { TimelineElement } from "../player";
4
4
  import type { DomEditSelection } from "../components/editor/domEditing";
5
- import type { LeftSidebarHandle } from "../components/sidebar/LeftSidebar";
6
5
  import { isTypingTarget } from "../utils/typingTarget";
7
6
  import { useCaptionStore } from "../captions/store";
8
7
  import {
@@ -88,7 +87,6 @@ interface UseAppHotkeysParams {
88
87
  showToast: (message: string, tone?: "error" | "info") => void;
89
88
  syncHistoryPreviewAfterApply: UseEditHistoryActionsOptions["syncHistoryPreviewAfterApply"];
90
89
  waitForPendingDomEditSaves: () => Promise<void>;
91
- leftSidebarRef: React.RefObject<LeftSidebarHandle | null>;
92
90
  handleCopy: () => boolean;
93
91
  handlePaste: () => Promise<void>;
94
92
  handleCut: () => Promise<boolean>;
@@ -125,7 +123,6 @@ export function useAppHotkeys({
125
123
  showToast,
126
124
  syncHistoryPreviewAfterApply,
127
125
  waitForPendingDomEditSaves,
128
- leftSidebarRef,
129
126
  handleCopy,
130
127
  handlePaste,
131
128
  handleCut,
@@ -204,7 +201,6 @@ export function useAppHotkeys({
204
201
  onToggleRecording,
205
202
  onGroupSelection,
206
203
  onUngroupSelection,
207
- leftSidebarRef,
208
204
  domEditSelectionRef,
209
205
  showToast,
210
206
  };
@@ -6,7 +6,7 @@
6
6
  import { useEffect, useRef } from "react";
7
7
  import { findElementForSelection, type DomEditSelection } from "../components/editor/domEditing";
8
8
  import { reapplyPositionEditsAfterSeek } from "../components/editor/manualEdits";
9
- import type { SidebarTab } from "../components/sidebar/LeftSidebar";
9
+ import { useDockLayoutStore } from "../components/dock/dockLayoutStore";
10
10
  import type { PatchTarget } from "../utils/sourcePatcher";
11
11
  import { logSelect } from "../utils/selectDebug";
12
12
 
@@ -30,7 +30,6 @@ interface UseDomEditPreviewSyncParams {
30
30
  (iframe: HTMLIFrameElement) => Promise<void>
31
31
  >;
32
32
  openSourceForSelection?: (sourceFile: string, target: PatchTarget) => void;
33
- getSidebarTab?: () => SidebarTab;
34
33
  gsapCacheVersion?: number;
35
34
  }
36
35
 
@@ -48,7 +47,6 @@ export function useDomEditPreviewSync({
48
47
  syncPreviewHotkeys,
49
48
  applyStudioManualEditsToPreviewRef,
50
49
  openSourceForSelection,
51
- getSidebarTab,
52
50
  gsapCacheVersion,
53
51
  }: UseDomEditPreviewSyncParams): void {
54
52
  // Sync selection from preview document on load / refresh
@@ -142,15 +140,15 @@ export function useDomEditPreviewSync({
142
140
  useEffect(
143
141
  // fallow-ignore-next-line complexity
144
142
  () => {
145
- if (!domEditSelection || !openSourceRef.current || !getSidebarTab) return;
143
+ if (!domEditSelection || !openSourceRef.current) return;
146
144
  if (!domEditSelection.sourceFile) return;
147
- if (getSidebarTab() !== "code") return;
145
+ if (!useDockLayoutStore.getState().visiblePanels.has("code")) return;
148
146
  openSourceRef.current(domEditSelection.sourceFile, {
149
147
  id: domEditSelection.id,
150
148
  selector: domEditSelection.selector,
151
149
  selectorIndex: domEditSelection.selectorIndex,
152
150
  });
153
151
  },
154
- [domEditSelection, getSidebarTab],
152
+ [domEditSelection],
155
153
  );
156
154
  }
@@ -5,7 +5,6 @@ import type { TimelineElement } from "../player";
5
5
  import type { ImportedFontAsset } from "../components/editor/fontAssets";
6
6
  import type { RightPanelTab } from "../utils/studioHelpers";
7
7
  import type { PatchTarget } from "../utils/sourcePatcher";
8
- import type { SidebarTab } from "../components/sidebar/LeftSidebar";
9
8
  import type { Composition } from "@hyperframes/sdk";
10
9
  import { sdkCutoverPersist, sdkDeletePersist, type PublishSdkSession } from "../utils/sdkCutover";
11
10
  import { runResolverShadow, recordResolverParity } from "../utils/sdkResolverShadow";
@@ -53,8 +52,6 @@ export interface UseDomEditSessionParams extends DomEditTimelineParams {
53
52
  reloadPreview: () => void;
54
53
  setRefreshKey: React.Dispatch<React.SetStateAction<number>>;
55
54
  openSourceForSelection?: (sourceFile: string, target: PatchTarget) => void;
56
- selectSidebarTab?: (tab: SidebarTab) => void;
57
- getSidebarTab?: () => SidebarTab;
58
55
  sdkSession?: Composition | null;
59
56
  publishSdkSession?: PublishSdkSession;
60
57
  forceReloadSdkSession?: () => void;
@@ -97,8 +94,6 @@ export function useDomEditSession({
97
94
  reloadPreview,
98
95
  setRefreshKey: _setRefreshKey,
99
96
  openSourceForSelection,
100
- selectSidebarTab,
101
- getSidebarTab,
102
97
  sdkSession,
103
98
  publishSdkSession,
104
99
  forceReloadSdkSession,
@@ -430,8 +425,6 @@ export function useDomEditSession({
430
425
  applyDomSelection,
431
426
  buildDomSelectionFromTarget,
432
427
  openSourceForSelection,
433
- selectSidebarTab,
434
- getSidebarTab,
435
428
  updateGsapProperty,
436
429
  updateGsapMeta,
437
430
  deleteGsapAnimation,
@@ -16,7 +16,7 @@ import { useGsapAnimationFetchFallback } from "./useGsapAnimationFetchFallback";
16
16
  import { useGsapInteractionFailureTelemetry } from "./useGsapInteractionFailureTelemetry";
17
17
  import { useGsapSelectionHandlers } from "./useGsapSelectionHandlers";
18
18
  import type { PatchTarget } from "../utils/sourcePatcher";
19
- import type { SidebarTab } from "../components/sidebar/LeftSidebar";
19
+ import { useDockLayoutStore } from "../components/dock/dockLayoutStore";
20
20
 
21
21
  export interface UseDomEditWiringParams {
22
22
  projectId: string | null;
@@ -43,8 +43,6 @@ export interface UseDomEditWiringParams {
43
43
  ) => void;
44
44
  buildDomSelectionFromTarget: (element: HTMLElement) => Promise<DomEditSelection | null>;
45
45
  openSourceForSelection?: (sourceFile: string, target: PatchTarget) => void;
46
- selectSidebarTab?: (tab: SidebarTab) => void;
47
- getSidebarTab?: () => SidebarTab;
48
46
  // GSAP script commit ops (from useGsapScriptCommits)
49
47
  updateGsapProperty: (
50
48
  sel: DomEditSelection,
@@ -132,8 +130,6 @@ export function useDomEditWiring({
132
130
  applyDomSelection,
133
131
  buildDomSelectionFromTarget,
134
132
  openSourceForSelection,
135
- selectSidebarTab,
136
- getSidebarTab,
137
133
  updateGsapProperty,
138
134
  updateGsapMeta,
139
135
  deleteGsapAnimation,
@@ -157,16 +153,16 @@ export function useDomEditWiring({
157
153
 
158
154
  const onClickToSource = useCallback(
159
155
  (selection: DomEditSelection) => {
160
- if (!openSourceForSelection || !selectSidebarTab) return;
156
+ if (!openSourceForSelection) return;
161
157
  if (!selection.sourceFile) return;
162
- selectSidebarTab("code");
158
+ useDockLayoutStore.getState().activatePanel("code");
163
159
  openSourceForSelection(selection.sourceFile, {
164
160
  id: selection.id,
165
161
  selector: selection.selector,
166
162
  selectorIndex: selection.selectorIndex,
167
163
  });
168
164
  },
169
- [openSourceForSelection, selectSidebarTab],
165
+ [openSourceForSelection],
170
166
  );
171
167
 
172
168
  // ── DOM selection -> timeline element sync ──
@@ -267,7 +263,6 @@ export function useDomEditWiring({
267
263
  syncPreviewHotkeys,
268
264
  applyStudioManualEditsToPreviewRef,
269
265
  openSourceForSelection,
270
- getSidebarTab,
271
266
  gsapCacheVersion,
272
267
  });
273
268