mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-03 12:54:29 +00:00
feat(studio): add flat Shadow and Blend rows to the Style group
This commit is contained in:
@@ -214,3 +214,66 @@ describe("FlatStyleSection — Stroke and Radius", () => {
|
||||
act(() => root.unmount());
|
||||
});
|
||||
});
|
||||
|
||||
function getFlatSelectRow(host: HTMLElement, label: string) {
|
||||
const rows = Array.from(host.querySelectorAll<HTMLElement>(".group"));
|
||||
const row = rows.find((el) => el.querySelector("span")?.textContent === label);
|
||||
if (!row) throw new Error(`expected a select row for "${label}"`);
|
||||
const select = row.querySelector<HTMLSelectElement>("select");
|
||||
if (!select) throw new Error(`expected a select for "${label}"`);
|
||||
const resetButton = row.querySelector<HTMLButtonElement>('[data-flat-select-reset="true"]');
|
||||
return { row, select, resetButton };
|
||||
}
|
||||
|
||||
function changeFlatSelectRow(host: HTMLElement, label: string, nextValue: string) {
|
||||
const { select } = getFlatSelectRow(host, label);
|
||||
act(() => {
|
||||
select.value = nextValue;
|
||||
select.dispatchEvent(new Event("change", { bubbles: true }));
|
||||
});
|
||||
}
|
||||
|
||||
describe("FlatStyleSection — Shadow and Blend", () => {
|
||||
it("renders Shadow with the inferred preset and a reset when set, Blend with a plain select", () => {
|
||||
const { host, root } = renderSection({ "box-shadow": "0 8px 24px rgba(0,0,0,.35)" });
|
||||
expect(host.textContent).toContain("Shadow");
|
||||
expect(host.textContent).toContain("Blend");
|
||||
const selects = host.querySelectorAll("select");
|
||||
expect(selects.length).toBeGreaterThanOrEqual(2);
|
||||
act(() => root.unmount());
|
||||
});
|
||||
|
||||
it("commits a shadow preset change through onSetStyle", () => {
|
||||
const { host, root, onSetStyle } = renderSection({});
|
||||
changeFlatSelectRow(host, "Shadow", "soft");
|
||||
expect(onSetStyle).toHaveBeenCalledWith("box-shadow", expect.any(String));
|
||||
act(() => root.unmount());
|
||||
});
|
||||
|
||||
it("commits a blend mode change through onSetStyle", () => {
|
||||
const { host, root, onSetStyle } = renderSection({});
|
||||
changeFlatSelectRow(host, "Blend", "multiply");
|
||||
expect(onSetStyle).toHaveBeenCalledWith("mix-blend-mode", "multiply");
|
||||
act(() => root.unmount());
|
||||
});
|
||||
|
||||
it("resets the shadow preset back to none via the reset button", () => {
|
||||
const { host, root, onSetStyle } = renderSection({
|
||||
"box-shadow": "0 12px 36px rgba(0, 0, 0, 0.28)",
|
||||
});
|
||||
const { resetButton } = getFlatSelectRow(host, "Shadow");
|
||||
if (!resetButton) throw new Error("expected the shadow reset button");
|
||||
act(() => resetButton.dispatchEvent(new MouseEvent("click", { bubbles: true })));
|
||||
expect(onSetStyle).toHaveBeenCalledWith("box-shadow", "none");
|
||||
act(() => root.unmount());
|
||||
});
|
||||
|
||||
it("resets the blend mode back to normal via the reset button", () => {
|
||||
const { host, root, onSetStyle } = renderSection({ "mix-blend-mode": "multiply" });
|
||||
const { resetButton } = getFlatSelectRow(host, "Blend");
|
||||
if (!resetButton) throw new Error("expected the blend reset button");
|
||||
act(() => resetButton.dispatchEvent(new MouseEvent("click", { bubbles: true })));
|
||||
expect(onSetStyle).toHaveBeenCalledWith("mix-blend-mode", "normal");
|
||||
act(() => root.unmount());
|
||||
});
|
||||
});
|
||||
|
||||
@@ -6,16 +6,19 @@ import { Link as LinkIcon } from "../../icons/SystemIcons";
|
||||
import { BorderRadiusEditor } from "./BorderRadiusEditor";
|
||||
import { formatStrokeSummary, parseStrokeSummary } from "./propertyPanelFlatStyleHelpers";
|
||||
import {
|
||||
buildBoxShadowPresetValue,
|
||||
buildStrokeStyleUpdates,
|
||||
buildStrokeWidthStyleUpdates,
|
||||
extractBackgroundImageUrl,
|
||||
formatNumericValue,
|
||||
formatPxMetricValue,
|
||||
inferBoxShadowPreset,
|
||||
normalizePanelPxValue,
|
||||
parseNumericValue,
|
||||
parsePxMetricValue,
|
||||
type BoxShadowPreset,
|
||||
} from "./propertyPanelHelpers";
|
||||
import { FlatRow, FlatSegmentedRow } from "./propertyPanelFlatPrimitives";
|
||||
import { FlatRow, FlatSegmentedRow, FlatSelectRow } from "./propertyPanelFlatPrimitives";
|
||||
import { resolveValueTier } from "./propertyPanelValueTier";
|
||||
import { ColorField } from "./propertyPanelColor";
|
||||
import { GradientField, ImageFillField } from "./propertyPanelFill";
|
||||
@@ -268,6 +271,52 @@ function FlatRadiusRow({
|
||||
);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* Flat Shadow + Blend rows */
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
function FlatShadowBlendRows({
|
||||
styles,
|
||||
disabled,
|
||||
onSetStyle,
|
||||
}: {
|
||||
styles: Record<string, string>;
|
||||
disabled: boolean;
|
||||
onSetStyle: (prop: string, value: string) => void | Promise<void>;
|
||||
}) {
|
||||
const boxShadowPreset = inferBoxShadowPreset(styles["box-shadow"]);
|
||||
const blendValue = styles["mix-blend-mode"] || "normal";
|
||||
|
||||
return (
|
||||
<>
|
||||
<FlatSelectRow
|
||||
label="Shadow"
|
||||
value={boxShadowPreset}
|
||||
options={["none", "soft", "lift", "glow", "custom"]}
|
||||
tier={resolveValueTier(boxShadowPreset === "none" ? undefined : boxShadowPreset, "none")}
|
||||
disabled={disabled}
|
||||
onChange={(next) => {
|
||||
if (next === "custom") return;
|
||||
void onSetStyle(
|
||||
"box-shadow",
|
||||
buildBoxShadowPresetValue(next as BoxShadowPreset, styles["box-shadow"]),
|
||||
);
|
||||
}}
|
||||
onReset={() => void onSetStyle("box-shadow", "none")}
|
||||
/>
|
||||
<FlatSelectRow
|
||||
label="Blend"
|
||||
value={blendValue}
|
||||
options={["normal", "multiply", "screen", "overlay", "darken", "lighten"]}
|
||||
tier={resolveValueTier(styles["mix-blend-mode"], "normal")}
|
||||
disabled={disabled}
|
||||
onChange={(next) => void onSetStyle("mix-blend-mode", next)}
|
||||
onReset={() => void onSetStyle("mix-blend-mode", "normal")}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export function FlatStyleSection({
|
||||
projectId,
|
||||
element,
|
||||
@@ -303,6 +352,11 @@ export function FlatStyleSection({
|
||||
disabled={styleEditingDisabled}
|
||||
onSetStyle={onSetStyle}
|
||||
/>
|
||||
<FlatShadowBlendRows
|
||||
styles={styles}
|
||||
disabled={styleEditingDisabled}
|
||||
onSetStyle={onSetStyle}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user