Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions .fallowrc.jsonc
Original file line number Diff line number Diff line change
Expand Up @@ -437,6 +437,18 @@
// scopeRootSelectors handling shifts lines and re-flags both.
"packages/core/src/compiler/inlineSubCompositions.ts",
"packages/core/src/compiler/compositionScoping.test.ts",
// Studio flat-inspector redesign (Plans 2-4): each Flat*Section test file
// repeats the same renderInto/pointerdown-drag/reset-click scaffold as its
// sibling group's tests, added task-by-task across separate PRs on this
// branch. Pre-existing relative to Grade group (Plan 5) work; consistent
// with the norm above of leaving parallel arrange/act/assert test cases
// unabstracted where each case verifies a distinct control's behavior.
"packages/studio/src/components/editor/propertyPanelFlatMediaSection.test.tsx",
"packages/studio/src/components/editor/propertyPanelFlatMediaSection.tsx",
"packages/studio/src/components/editor/propertyPanelMediaSection.tsx",
"packages/studio/src/components/editor/PropertyPanel.test.tsx",
"packages/studio/src/components/editor/propertyPanelFlatStyleSections.test.tsx",
"packages/studio/src/components/editor/propertyPanelFlatMotionSection.test.tsx",
],
},
"health": {
Expand Down Expand Up @@ -616,6 +628,10 @@
"packages/core/src/compiler/inlineSubCompositions.ts",
"packages/core/src/compiler/htmlBundler.ts",
"packages/core/src/runtime/compositionLoader.ts",
// TextFieldEditor: pre-existing complexity from earlier Text-inspector
// work on this same branch (commits 444639d75, b57b31beb, 6f2e9848c,
// eba8a0fa2), unrelated to the Grade group (Plan 5) currently landing.
"packages/studio/src/components/editor/propertyPanelSections.tsx",
],
},
}
20 changes: 20 additions & 0 deletions packages/studio/src/components/editor/PropertyPanel.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -668,6 +668,26 @@ function flatGroupTitles(host: HTMLElement): string[] {
return [...open, ...collapsed];
}

describe("PropertyPanel — Grade group (flag on)", () => {
it(
"renders the Grade group with its accessory for a grade-editable (video) element",
async () => {
const { host, root } = await renderPanel(true, {
...baseElement(),
tagName: "video",
textFields: [],
});
const gradeCollapsedOrOpen =
host.querySelector('[data-flat-group-collapsed="true"]') ||
host.querySelector('[data-flat-group-open="true"]');
expect(host.textContent).toContain("Grade");
expect(gradeCollapsedOrOpen).not.toBeNull();
act(() => root.unmount());
},
RENDER_TIMEOUT_MS,
);
});

describe("PropertyPanel — Media group (Plan 4)", () => {
it(
"renders the flat Media group and not the legacy MediaSection, for a video element",
Expand Down
43 changes: 43 additions & 0 deletions packages/studio/src/components/editor/PropertyPanelFlat.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@ import { createGsapLivePreview } from "./gsapLivePreview";
import { formatTextFieldPreview, StyleSections } from "./propertyPanelSections";
import { STUDIO_GSAP_PANEL_ENABLED } from "./manualEditingAvailability";
import { ColorGradingSection } from "./propertyPanelColorGradingSection";
import { useColorGradingController } from "./useColorGradingController";
import {
FlatColorGradingAccessory,
FlatColorGradingSection,
} from "./propertyPanelFlatColorGradingSection";

type EditingSections = ReturnType<typeof resolveEditingSections>;

Expand Down Expand Up @@ -225,6 +230,20 @@ export function PropertyPanelFlat({
);
const [pinnedGroupIds, setPinnedGroupIds] = useState<string[]>([]);

// Grade group state. Called unconditionally (React rules-of-hooks) even when
// sections.colorGrading is false — unlike the legacy ColorGradingSection,
// which is only mounted when the section is active, PropertyPanelFlat is not
// remounted per-section so the hook must run every render. Shares one state
// object between the group's header accessory (compare/status/reset) and its
// body (the FlatColorGradingSection controls).
const colorGradingController = useColorGradingController({
projectId,
element,
previewIframeRef,
onSetAttributeLive,
onApplyScope: onApplyColorGradingScope,
});

const isTextEditable = isTextEditableSelection(element);
const elementKind = sections.media ? "media" : element.textFields.length > 0 ? "text" : "other";
const toggleOpen = (groupId: string) =>
Expand Down Expand Up @@ -415,6 +434,30 @@ export function PropertyPanelFlat({
/>
</FlatGroup>
)}
{sections.colorGrading && (
<FlatGroup
title="Grade"
isOpen={openGroupId === "grade" || pinnedGroupIds.includes("grade")}
isPinned={pinnedGroupIds.includes("grade")}
onToggleOpen={() => toggleOpen("grade")}
onTogglePin={() => togglePin("grade")}
accessory={<FlatColorGradingAccessory state={colorGradingController} />}
summary={`${colorGradingController.grading.preset ?? "neutral"} · ${Math.round(colorGradingController.grading.intensity * 100)}%`}
>
<FlatColorGradingSection
grading={colorGradingController.grading}
assets={assets}
onImportAssets={onImportAssets}
onCommitColorGrading={colorGradingController.commitColorGrading}
applyScope={colorGradingController.applyScope}
applyBusy={colorGradingController.applyBusy}
onSetApplyScope={colorGradingController.setApplyScope}
onApplyToScope={() => void colorGradingController.applyToScope()}
onApplyScopeAvailable={Boolean(onApplyColorGradingScope)}
mediaMetadata={colorGradingController.mediaMetadata}
/>
</FlatGroup>
)}
{sections.colorGrading && (
<ColorGradingSection
key={[
Expand Down
Loading
Loading