mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-03 04:38:33 +00:00
chore(studio): remove debug logging (#1765)
This commit is contained in:
@@ -133,12 +133,12 @@ export function TimelineToolbar({
|
||||
<Tooltip
|
||||
label={
|
||||
keyframeState === "active"
|
||||
? "Remove keyframe at playhead"
|
||||
? "Remove keyframe at playhead (K)"
|
||||
: keyframeState === "inactive"
|
||||
? keyframeWillExtend
|
||||
? "Add keyframe at playhead (extends animation)"
|
||||
: "Add keyframe at playhead"
|
||||
: "Enable keyframes"
|
||||
? "Add keyframe at playhead — extends animation (K)"
|
||||
: "Add keyframe at playhead (K)"
|
||||
: "Add keyframe (K)"
|
||||
}
|
||||
>
|
||||
<button
|
||||
|
||||
@@ -43,8 +43,8 @@ export function GestureRecordPanelButton({
|
||||
>
|
||||
<GestureRecordIcon recording={recording} />
|
||||
{recording
|
||||
? `Stop recording ${(recordingDuration ?? 0).toFixed(1)}s — press R`
|
||||
: "Record gesture (R) — move pointer to capture motion"}
|
||||
? `Stop recording ${(recordingDuration ?? 0).toFixed(1)}s -- press R`
|
||||
: "Record gesture (R) -- move pointer to capture motion"}
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -27,12 +27,15 @@ export function resolveGroupCapture(
|
||||
for (let n: HTMLElement | null = startEl; n; n = n.parentElement) {
|
||||
if (n.hasAttribute("data-hf-group")) groups.push(n);
|
||||
}
|
||||
if (!activeGroupElement) {
|
||||
const outermost = groups[groups.length - 1];
|
||||
return outermost ? { kind: "unit", element: outermost } : { kind: "child" };
|
||||
}
|
||||
const idx = groups.indexOf(activeGroupElement);
|
||||
if (idx === -1) return { kind: "out-of-scope" };
|
||||
const nestedInside = groups[idx - 1];
|
||||
return nestedInside ? { kind: "unit", element: nestedInside } : { kind: "child" };
|
||||
const result = ((): GroupCapture => {
|
||||
if (!activeGroupElement) {
|
||||
const outermost = groups[groups.length - 1];
|
||||
return outermost ? { kind: "unit", element: outermost } : { kind: "child" };
|
||||
}
|
||||
const idx = groups.indexOf(activeGroupElement);
|
||||
if (idx === -1) return { kind: "out-of-scope" };
|
||||
const nestedInside = groups[idx - 1];
|
||||
return nestedInside ? { kind: "unit", element: nestedInside } : { kind: "child" };
|
||||
})();
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import { shouldHandleTimelineToggleHotkey, isEditableTarget } from "../utils/tim
|
||||
import { shouldIgnoreHistoryShortcut } from "../utils/studioHelpers";
|
||||
import { canSplitElement } from "../utils/timelineElementSplit";
|
||||
import { STUDIO_RAZOR_TOOL_ENABLED } from "../components/editor/manualEditingAvailability";
|
||||
import { trackStudioEvent } from "../utils/studioTelemetry";
|
||||
|
||||
function iframeContentWindow(iframe: HTMLIFrameElement | null): Window | null {
|
||||
try {
|
||||
@@ -158,19 +159,27 @@ function dispatchModifierKey(event: KeyboardEvent, key: string, cb: HotkeyCallba
|
||||
!shouldIgnoreHistoryShortcut(event.target) &&
|
||||
handleUndoRedoKey(
|
||||
event,
|
||||
() => void cb.handleUndo(),
|
||||
() => void cb.handleRedo(),
|
||||
() => {
|
||||
trackStudioEvent("keyboard_shortcut", { action: "undo" });
|
||||
void cb.handleUndo();
|
||||
},
|
||||
() => {
|
||||
trackStudioEvent("keyboard_shortcut", { action: "redo" });
|
||||
void cb.handleRedo();
|
||||
},
|
||||
)
|
||||
)
|
||||
return true;
|
||||
|
||||
if (event.key === "1") {
|
||||
event.preventDefault();
|
||||
trackStudioEvent("keyboard_shortcut", { action: "tab_compositions" });
|
||||
cb.leftSidebarRef.current?.selectTab("compositions");
|
||||
return true;
|
||||
}
|
||||
if (event.key === "2") {
|
||||
event.preventDefault();
|
||||
trackStudioEvent("keyboard_shortcut", { action: "tab_assets" });
|
||||
cb.leftSidebarRef.current?.selectTab("assets");
|
||||
return true;
|
||||
}
|
||||
@@ -184,17 +193,22 @@ function dispatchModifierKey(event: KeyboardEvent, key: string, cb: HotkeyCallba
|
||||
|
||||
if (!event.shiftKey && !event.altKey && !isEditableTarget(event.target)) {
|
||||
if (key === "c") {
|
||||
if (cb.handleCopy()) event.preventDefault();
|
||||
if (cb.handleCopy()) {
|
||||
event.preventDefault();
|
||||
trackStudioEvent("keyboard_shortcut", { action: "copy" });
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (key === "v") {
|
||||
event.preventDefault();
|
||||
trackStudioEvent("keyboard_shortcut", { action: "paste" });
|
||||
void cb.handlePaste();
|
||||
return true;
|
||||
}
|
||||
if (key === "x") {
|
||||
if (usePlayerStore.getState().selectedElementId || cb.domEditSelectionRef.current) {
|
||||
event.preventDefault();
|
||||
trackStudioEvent("keyboard_shortcut", { action: "cut" });
|
||||
void cb.handleCut();
|
||||
}
|
||||
return true;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { useCallback } from "react";
|
||||
import { trackStudioEvent } from "../utils/studioTelemetry";
|
||||
import type { TimelineElement } from "../player";
|
||||
import type { ImportedFontAsset } from "../components/editor/fontAssets";
|
||||
import type { EditHistoryKind } from "../utils/editHistory";
|
||||
@@ -305,6 +306,7 @@ export function useDomEditSession({
|
||||
showToast("Select at least 2 elements to group", "info");
|
||||
return;
|
||||
}
|
||||
trackStudioEvent("group", { action: "create", count: members.length });
|
||||
void groupSelection(members);
|
||||
}, [domEditGroupSelectionsRef, domEditSelectionRef, groupSelection, showToast]);
|
||||
|
||||
@@ -315,6 +317,7 @@ export function useDomEditSession({
|
||||
return;
|
||||
}
|
||||
// Dissolving the group exits any drill-in (the wrapper is about to vanish).
|
||||
trackStudioEvent("group", { action: "ungroup" });
|
||||
setActiveGroupElement(null);
|
||||
void ungroupSelection(sel);
|
||||
}, [domEditSelectionRef, ungroupSelection, setActiveGroupElement, showToast]);
|
||||
|
||||
@@ -2,6 +2,7 @@ import { useCallback, useRef } from "react";
|
||||
import type { DomEditSelection } from "../components/editor/domEditing";
|
||||
import { usePlayerStore } from "../player";
|
||||
import { trackStudioSaveFailure } from "../utils/studioSaveDiagnostics";
|
||||
import { trackStudioEvent } from "../utils/studioTelemetry";
|
||||
|
||||
/**
|
||||
* Thin useCallback wrappers that guard on `domEditSelection` before
|
||||
@@ -136,6 +137,7 @@ export function useGsapSelectionHandlers({
|
||||
(targetSelector: string) => {
|
||||
const sel = domEditSelection ?? lastSelectionRef.current;
|
||||
if (!sel) return;
|
||||
trackStudioEvent("keyframe", { action: "delete_all" });
|
||||
deleteAllForSelector(sel, targetSelector);
|
||||
},
|
||||
[domEditSelection, deleteAllForSelector],
|
||||
@@ -206,6 +208,7 @@ export function useGsapSelectionHandlers({
|
||||
) => {
|
||||
const sel = selectionOverride ?? domEditSelection ?? lastSelectionRef.current;
|
||||
if (!sel) return;
|
||||
trackStudioEvent("keyframe", { action: "add", property });
|
||||
addKeyframe(sel, animId, percentage, property, value);
|
||||
},
|
||||
[domEditSelection, addKeyframe],
|
||||
@@ -224,6 +227,7 @@ export function useGsapSelectionHandlers({
|
||||
(animId: string, percentage: number, selectionOverride?: DomEditSelection | null) => {
|
||||
const sel = selectionOverride ?? domEditSelection ?? lastSelectionRef.current;
|
||||
if (!sel) return;
|
||||
trackStudioEvent("keyframe", { action: "remove" });
|
||||
removeKeyframe(sel, animId, percentage);
|
||||
},
|
||||
[domEditSelection, removeKeyframe],
|
||||
|
||||
@@ -3,6 +3,7 @@ import { liveTime, usePlayerStore } from "../player";
|
||||
import { pauseStudioPreviewPlayback } from "../utils/studioPreviewHelpers";
|
||||
import { STUDIO_PREVIEW_SELECTION_ENABLED } from "../components/editor/manualEditingAvailability";
|
||||
import { type DomEditSelection } from "../components/editor/domEditing";
|
||||
import { trackStudioEvent } from "../utils/studioTelemetry";
|
||||
|
||||
// ── Types ──
|
||||
|
||||
@@ -47,6 +48,12 @@ interface ClickCycleState {
|
||||
|
||||
const CYCLE_RADIUS_PX = 6;
|
||||
const CYCLE_WINDOW_MS = 600;
|
||||
// Manual double-click window. `e.detail` can't be trusted here: the first click
|
||||
// selects the group and re-renders the overlay, so the second click lands on a
|
||||
// fresh element and the browser's native click-counter resets to 1 — drill-in
|
||||
// (which keyed off `e.detail >= 2`) never fired. We track time+position instead.
|
||||
const DOUBLE_CLICK_MS = 400;
|
||||
const DOUBLE_CLICK_RADIUS_PX = 6;
|
||||
|
||||
// ── Hook ──
|
||||
|
||||
@@ -63,21 +70,34 @@ export function usePreviewInteraction({
|
||||
onClickToSource,
|
||||
}: UsePreviewInteractionParams) {
|
||||
const cycleRef = useRef<ClickCycleState | null>(null);
|
||||
const lastDownRef = useRef<{ t: number; x: number; y: number } | null>(null);
|
||||
|
||||
const handlePreviewCanvasMouseDown = useCallback(
|
||||
// fallow-ignore-next-line complexity
|
||||
async (e: React.MouseEvent<HTMLDivElement>, options?: { preferClipAncestor?: boolean }) => {
|
||||
if (!STUDIO_PREVIEW_SELECTION_ENABLED || captionEditMode || compositionLoading) return;
|
||||
|
||||
// Manual double-click detection (see DOUBLE_CLICK_MS): the first click
|
||||
// re-renders the overlay so `e.detail` never reaches 2 on the canvas.
|
||||
const downTs = Date.now();
|
||||
const lastDown = lastDownRef.current;
|
||||
const isDoubleClick =
|
||||
e.detail >= 2 ||
|
||||
(lastDown != null &&
|
||||
downTs - lastDown.t < DOUBLE_CLICK_MS &&
|
||||
Math.hypot(e.clientX - lastDown.x, e.clientY - lastDown.y) < DOUBLE_CLICK_RADIUS_PX);
|
||||
lastDownRef.current = { t: downTs, x: e.clientX, y: e.clientY };
|
||||
|
||||
// Double-click a group → drill into it and select the child under the
|
||||
// pointer (resolve with the group as the explicit drill-in scope, since the
|
||||
// activeGroupElement state hasn't re-rendered yet within this handler).
|
||||
if (e.detail >= 2 && !e.shiftKey) {
|
||||
if (isDoubleClick && !e.shiftKey) {
|
||||
const hit = await resolveDomSelectionFromPreviewPoint(e.clientX, e.clientY);
|
||||
if (hit?.element.hasAttribute("data-hf-group")) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
cycleRef.current = null;
|
||||
trackStudioEvent("group", { action: "drill_in" });
|
||||
setActiveGroupElement(hit.element);
|
||||
const child = await resolveDomSelectionFromPreviewPoint(e.clientX, e.clientY, {
|
||||
activeGroupElement: hit.element,
|
||||
@@ -121,9 +141,21 @@ export function usePreviewInteraction({
|
||||
}
|
||||
|
||||
// Fresh click — resolve topmost element
|
||||
const nextSelection = await resolveDomSelectionFromPreviewPoint(e.clientX, e.clientY, {
|
||||
let nextSelection = await resolveDomSelectionFromPreviewPoint(e.clientX, e.clientY, {
|
||||
preferClipAncestor: options?.preferClipAncestor ?? false,
|
||||
});
|
||||
// A null result while drilled into a group means the click landed OUTSIDE that
|
||||
// group (resolveGroupCapture → out-of-scope). Drill-in isn't sticky: exit it and
|
||||
// re-resolve at the top level so this click selects whatever's there (or the
|
||||
// group as a unit). Without this, a stale drill-in keeps selecting children and
|
||||
// the "first click selects the group" expectation breaks.
|
||||
if (!nextSelection) {
|
||||
setActiveGroupElement(null);
|
||||
nextSelection = await resolveDomSelectionFromPreviewPoint(e.clientX, e.clientY, {
|
||||
preferClipAncestor: options?.preferClipAncestor ?? false,
|
||||
activeGroupElement: null,
|
||||
});
|
||||
}
|
||||
if (!nextSelection) {
|
||||
cycleRef.current = null;
|
||||
applyDomSelection(null, { revealPanel: false });
|
||||
|
||||
Reference in New Issue
Block a user