mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-03 04:38:33 +00:00
feat(studio): add flat Layer blur and Backdrop sliders to the Style group
This commit is contained in:
@@ -277,3 +277,60 @@ describe("FlatStyleSection — Shadow and Blend", () => {
|
||||
act(() => root.unmount());
|
||||
});
|
||||
});
|
||||
|
||||
describe("FlatStyleSection — blur sliders", () => {
|
||||
it("renders Layer blur and Backdrop sliders and commits through onSetStyle", () => {
|
||||
const onSetStyle = vi.fn();
|
||||
const host = document.createElement("div");
|
||||
document.body.append(host);
|
||||
const root = createRoot(host);
|
||||
act(() => {
|
||||
root.render(
|
||||
<FlatStyleSection
|
||||
projectId="proj-1"
|
||||
element={makeElement()}
|
||||
styles={{ filter: "blur(4px)" }}
|
||||
assets={[]}
|
||||
onSetStyle={onSetStyle}
|
||||
gsapBorderRadius={null}
|
||||
/>,
|
||||
);
|
||||
});
|
||||
expect(host.textContent).toContain("Layer blur");
|
||||
expect(host.textContent).toContain("Backdrop");
|
||||
expect(host.textContent).toContain("4px");
|
||||
const track = host.querySelectorAll('[data-flat-slider-track="true"]')[0];
|
||||
Object.defineProperty(track, "getBoundingClientRect", {
|
||||
value: () => ({ left: 0, width: 100, top: 0, height: 2, right: 100, bottom: 2 }),
|
||||
});
|
||||
act(() => {
|
||||
track.dispatchEvent(new MouseEvent("pointerdown", { bubbles: true, clientX: 50 }));
|
||||
});
|
||||
// filterBlurValue=4 -> max=Math.max(40, 4)=40; clientX=50 of width 100 -> ratio 0.5 -> 20px.
|
||||
expect(onSetStyle).toHaveBeenCalledWith("filter", "blur(20px)");
|
||||
act(() => root.unmount());
|
||||
});
|
||||
|
||||
it("renders the Backdrop slider from backdrop-filter and commits a new blur value on track click", () => {
|
||||
const { host, root, onSetStyle } = renderSection({ "backdrop-filter": "blur(6px)" });
|
||||
expect(host.textContent).toContain("Backdrop");
|
||||
expect(host.textContent).toContain("6px");
|
||||
const tracks = host.querySelectorAll('[data-flat-slider-track="true"]');
|
||||
const backdropTrack = tracks[tracks.length - 1];
|
||||
Object.defineProperty(backdropTrack, "getBoundingClientRect", {
|
||||
value: () => ({ left: 0, width: 100, top: 0, height: 2, right: 100, bottom: 2 }),
|
||||
});
|
||||
act(() => {
|
||||
backdropTrack.dispatchEvent(new MouseEvent("pointerdown", { bubbles: true, clientX: 50 }));
|
||||
});
|
||||
// backdropBlurValue=6 -> max=Math.max(60, 6)=60; clientX=50 of width 100 -> ratio 0.5 -> 30px.
|
||||
expect(onSetStyle).toHaveBeenCalledWith("backdrop-filter", "blur(30px)");
|
||||
act(() => root.unmount());
|
||||
});
|
||||
|
||||
it("does not render a fill/knob highlight for a zero-value blur (default tier)", () => {
|
||||
const { host, root } = renderSection({});
|
||||
expect(host.querySelectorAll('[data-flat-slider-fill="true"]')).toHaveLength(0);
|
||||
act(() => root.unmount());
|
||||
});
|
||||
});
|
||||
|
||||
@@ -12,13 +12,20 @@ import {
|
||||
extractBackgroundImageUrl,
|
||||
formatNumericValue,
|
||||
formatPxMetricValue,
|
||||
getCssFilterFunctionPx,
|
||||
inferBoxShadowPreset,
|
||||
normalizePanelPxValue,
|
||||
parseNumericValue,
|
||||
parsePxMetricValue,
|
||||
setCssFilterFunctionPx,
|
||||
type BoxShadowPreset,
|
||||
} from "./propertyPanelHelpers";
|
||||
import { FlatRow, FlatSegmentedRow, FlatSelectRow } from "./propertyPanelFlatPrimitives";
|
||||
import {
|
||||
FlatRow,
|
||||
FlatSegmentedRow,
|
||||
FlatSelectRow,
|
||||
FlatSlider,
|
||||
} from "./propertyPanelFlatPrimitives";
|
||||
import { resolveValueTier } from "./propertyPanelValueTier";
|
||||
import { ColorField } from "./propertyPanelColor";
|
||||
import { GradientField, ImageFillField } from "./propertyPanelFill";
|
||||
@@ -317,6 +324,55 @@ function FlatShadowBlendRows({
|
||||
);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* Flat Layer blur + Backdrop sliders */
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
function FlatBlurSliders({
|
||||
styles,
|
||||
disabled,
|
||||
onSetStyle,
|
||||
}: {
|
||||
styles: Record<string, string>;
|
||||
disabled: boolean;
|
||||
onSetStyle: (prop: string, value: string) => void | Promise<void>;
|
||||
}) {
|
||||
const filterBlurValue = getCssFilterFunctionPx(styles.filter, "blur");
|
||||
const backdropBlurValue = getCssFilterFunctionPx(styles["backdrop-filter"], "blur");
|
||||
|
||||
return (
|
||||
<>
|
||||
<FlatSlider
|
||||
label="Layer blur"
|
||||
value={filterBlurValue}
|
||||
min={0}
|
||||
max={Math.max(40, Math.ceil(filterBlurValue))}
|
||||
tier={filterBlurValue > 0 ? "explicitCustom" : "default"}
|
||||
displayValue={`${formatNumericValue(filterBlurValue)}px`}
|
||||
disabled={disabled}
|
||||
onCommit={(next) =>
|
||||
void onSetStyle("filter", setCssFilterFunctionPx(styles.filter, "blur", next))
|
||||
}
|
||||
/>
|
||||
<FlatSlider
|
||||
label="Backdrop"
|
||||
value={backdropBlurValue}
|
||||
min={0}
|
||||
max={Math.max(60, Math.ceil(backdropBlurValue))}
|
||||
tier={backdropBlurValue > 0 ? "explicitCustom" : "default"}
|
||||
displayValue={`${formatNumericValue(backdropBlurValue)}px`}
|
||||
disabled={disabled}
|
||||
onCommit={(next) =>
|
||||
void onSetStyle(
|
||||
"backdrop-filter",
|
||||
setCssFilterFunctionPx(styles["backdrop-filter"], "blur", next),
|
||||
)
|
||||
}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export function FlatStyleSection({
|
||||
projectId,
|
||||
element,
|
||||
@@ -357,6 +413,7 @@ export function FlatStyleSection({
|
||||
disabled={styleEditingDisabled}
|
||||
onSetStyle={onSetStyle}
|
||||
/>
|
||||
<FlatBlurSliders styles={styles} disabled={styleEditingDisabled} onSetStyle={onSetStyle} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user