summaryrefslogtreecommitdiff
path: root/apps/web/src/components/editor/panels/properties/hooks
diff options
context:
space:
mode:
authorMaze Winther <mazewinther@gmail.com>2026-04-13 04:40:38 +0200
committerMaze Winther <mazewinther@gmail.com>2026-04-13 05:01:51 +0200
commit108d3f4ecad4c0ead14941c2067a21546750fedc (patch)
tree8969775b3292ac2570b95e7848774958caadbc8b /apps/web/src/components/editor/panels/properties/hooks
parent8230faf082c405c9fd0fa640f4ce2284315782ae (diff)
downloadopencut-108d3f4ecad4c0ead14941c2067a21546750fedc.tar.gz
feat: position animated independently per axis
Made-with: Cursor
Diffstat (limited to 'apps/web/src/components/editor/panels/properties/hooks')
-rw-r--r--apps/web/src/components/editor/panels/properties/hooks/use-keyframed-vector-property.ts190
1 files changed, 0 insertions, 190 deletions
diff --git a/apps/web/src/components/editor/panels/properties/hooks/use-keyframed-vector-property.ts b/apps/web/src/components/editor/panels/properties/hooks/use-keyframed-vector-property.ts
deleted file mode 100644
index 7ee1f221..00000000
--- a/apps/web/src/components/editor/panels/properties/hooks/use-keyframed-vector-property.ts
+++ /dev/null
@@ -1,190 +0,0 @@
-import { useEditor } from "@/hooks/use-editor";
-import {
- getKeyframeAtTime,
- hasKeyframesForPath,
- upsertElementKeyframe,
-} from "@/lib/animation";
-import type {
- AnimationPropertyPath,
- ElementAnimations,
- VectorValue,
-} from "@/lib/animation/types";
-import type { TimelineElement } from "@/lib/timeline";
-import { snapToStep } from "@/utils/math";
-import { usePropertyDraft } from "./use-property-draft";
-
-export function useKeyframedVectorProperty({
- trackId,
- elementId,
- animations,
- propertyPath,
- localTime,
- isPlayheadWithinElementRange,
- resolvedValue,
- displayX,
- displayY,
- parseComponent,
- step,
- buildBaseUpdates,
-}: {
- trackId: string;
- elementId: string;
- animations: ElementAnimations | undefined;
- propertyPath: AnimationPropertyPath;
- localTime: number;
- isPlayheadWithinElementRange: boolean;
- resolvedValue: VectorValue;
- displayX: string;
- displayY: string;
- parseComponent: (input: string) => number | null;
- step?: number;
- buildBaseUpdates: ({
- value,
- }: {
- value: VectorValue;
- }) => Partial<TimelineElement>;
-}) {
- const editor = useEditor();
- const snapComponentValue = (value: number) =>
- step != null ? snapToStep({ value, step }) : value;
-
- const hasAnimatedKeyframes = hasKeyframesForPath({
- animations,
- propertyPath,
- });
- const keyframeAtTime = isPlayheadWithinElementRange
- ? getKeyframeAtTime({ animations, propertyPath, time: localTime })
- : null;
- const keyframeIdAtTime = keyframeAtTime?.id ?? null;
- const isKeyframedAtTime = keyframeAtTime !== null;
- const shouldUseAnimatedChannel =
- hasAnimatedKeyframes && isPlayheadWithinElementRange;
-
- const previewVector = ({ value }: { value: VectorValue }) => {
- const nextValue = {
- x: snapComponentValue(value.x),
- y: snapComponentValue(value.y),
- };
- if (shouldUseAnimatedChannel) {
- editor.timeline.previewElements({
- updates: [
- {
- trackId,
- elementId,
- updates: {
- animations: upsertElementKeyframe({
- animations,
- propertyPath,
- time: localTime,
- value: nextValue,
- }),
- },
- },
- ],
- });
- return;
- }
-
- editor.timeline.previewElements({
- updates: [{ trackId, elementId, updates: buildBaseUpdates({ value: nextValue }) }],
- });
- };
-
- const x = usePropertyDraft({
- displayValue: displayX,
- parse: (input) => {
- const parsedValue = parseComponent(input);
- return parsedValue === null ? null : snapComponentValue(parsedValue);
- },
- onPreview: (xVal) =>
- previewVector({ value: { x: xVal, y: resolvedValue.y } }),
- onCommit: () => editor.timeline.commitPreview(),
- });
-
- const y = usePropertyDraft({
- displayValue: displayY,
- parse: (input) => {
- const parsedValue = parseComponent(input);
- return parsedValue === null ? null : snapComponentValue(parsedValue);
- },
- onPreview: (yVal) =>
- previewVector({ value: { x: resolvedValue.x, y: yVal } }),
- onCommit: () => editor.timeline.commitPreview(),
- });
-
- const toggleKeyframe = () => {
- if (!isPlayheadWithinElementRange) return;
-
- if (keyframeIdAtTime) {
- editor.timeline.removeKeyframes({
- keyframes: [
- { trackId, elementId, propertyPath, keyframeId: keyframeIdAtTime },
- ],
- });
- return;
- }
-
- editor.timeline.upsertKeyframes({
- keyframes: [
- {
- trackId,
- elementId,
- propertyPath,
- time: localTime,
- value: resolvedValue,
- },
- ],
- });
- };
-
- const commitX = ({ value }: { value: number }) => {
- const vector: VectorValue = {
- x: snapComponentValue(value),
- y: snapComponentValue(resolvedValue.y),
- };
- if (shouldUseAnimatedChannel) {
- editor.timeline.upsertKeyframes({
- keyframes: [
- { trackId, elementId, propertyPath, time: localTime, value: vector },
- ],
- });
- return;
- }
- editor.timeline.updateElements({
- updates: [
- { trackId, elementId, patch: buildBaseUpdates({ value: vector }) },
- ],
- });
- };
-
- const commitY = ({ value }: { value: number }) => {
- const vector: VectorValue = {
- x: snapComponentValue(resolvedValue.x),
- y: snapComponentValue(value),
- };
- if (shouldUseAnimatedChannel) {
- editor.timeline.upsertKeyframes({
- keyframes: [
- { trackId, elementId, propertyPath, time: localTime, value: vector },
- ],
- });
- return;
- }
- editor.timeline.updateElements({
- updates: [
- { trackId, elementId, patch: buildBaseUpdates({ value: vector }) },
- ],
- });
- };
-
- return {
- x,
- y,
- hasAnimatedKeyframes,
- isKeyframedAtTime,
- keyframeIdAtTime,
- toggleKeyframe,
- commitX,
- commitY,
- };
-}