mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-08 02:36:10 +00:00
Fixes issues raised in the Deepwork re-review of #2120-#2190 that weren't covered by #2225's earlier fix pass: - useColorGradingController: reset grading/compare/mediaMetadata state (and cancel pending persist/status timers) when selection changes to a different element — this hook is called unconditionally on every render (unlike legacy ColorGradingSection, remounted via a selectionIdentityKey React key), so switching selection reused the previous element's state. - useColorGradingController: stop permanently caching a non-OK /media/metadata response as null — a transient server error poisoned the HDR banner for that asset for the whole page lifetime. - FlatSelectRow: preserve a valid authored value outside the preset list (e.g. mix-blend-mode: difference, an arbitrary object-position) instead of silently misrepresenting it as the first preset — touching the control would overwrite real persisted state. - FlatSlider: the throttled trailing commit now reads onCommit through a ref updated every render instead of closing over it at schedule time — a caller whose onCommit spreads other current state (Grade's per-detail commits) could otherwise have a delayed commit revert whatever the user changed on a different control in the same 40ms window. - FlatSlider: flush a still-queued trailing commit on unmount instead of dropping it, and disable the reset button when the slider itself is disabled. - FlatSlider: add touch-action: none to the track so touch drags don't compete with page scroll. - FlatColorGradingAccessory: clean up the compare-hold's window listeners on unmount, not only on release — switching selection mid-hold used to leak them. - Align (flat Text): re-clicking the option already visually active for a logical start/end value no longer rewrites it to the physical left/right, preserving RTL semantics. - FlatSegmentedRow: give every option an accessible name and aria-pressed state — two visually-identical glyph buttons (upright/italic "A") had no way to be told apart by assistive tech. - PropertyPanelFlat: the panel body falls back to its own scroll when the collapsed group headers alone exceed the available height, so groups can't become permanently unreachable in a short pane. New regression tests for all of the above; full studio suite at the known pre-existing baseline (55 failures unrelated to this stack).
103 lines
3.3 KiB
TypeScript
103 lines
3.3 KiB
TypeScript
import {
|
|
buildInsetClipPathSides,
|
|
buildInsetClipPathValue,
|
|
formatNumericValue,
|
|
formatPxMetricValue,
|
|
getClipPathInsetPx,
|
|
inferClipPathPreset,
|
|
parseInsetClipPathSides,
|
|
parsePxMetricValue,
|
|
type ClipPathInsetSides,
|
|
} from "./propertyPanelHelpers";
|
|
import { FlatSlider } from "./propertyPanelFlatPrimitives";
|
|
import { MetricField } from "./propertyPanelPrimitives";
|
|
|
|
/* ------------------------------------------------------------------ */
|
|
/* Flat Mask inset — uniform slider + per-side fields */
|
|
/* (split out of propertyPanelFlatStyleSections.tsx to stay under the */
|
|
/* 600-line file-size gate) */
|
|
/* ------------------------------------------------------------------ */
|
|
|
|
export function FlatMaskInsetRows({
|
|
clipPathValue,
|
|
radiusValue,
|
|
disabled,
|
|
onSetStyle,
|
|
}: {
|
|
clipPathValue: string;
|
|
radiusValue: number;
|
|
disabled: boolean;
|
|
onSetStyle: (prop: string, value: string) => void | Promise<void>;
|
|
}) {
|
|
const clipPathPreset = inferClipPathPreset(clipPathValue);
|
|
const parsedClipInsets = parseInsetClipPathSides(clipPathValue);
|
|
const clipInsetValue = getClipPathInsetPx(clipPathValue);
|
|
const clipInsetSides = parsedClipInsets ?? {
|
|
top: clipInsetValue,
|
|
right: clipInsetValue,
|
|
bottom: clipInsetValue,
|
|
left: clipInsetValue,
|
|
radius: radiusValue,
|
|
};
|
|
const showClipInsetSides = clipPathPreset === "inset" || parsedClipInsets != null;
|
|
|
|
const commitClipInsetSide = (side: keyof ClipPathInsetSides, nextValue: string) => {
|
|
const next = parsePxMetricValue(nextValue);
|
|
if (next == null) return;
|
|
const sides: ClipPathInsetSides = {
|
|
top: clipInsetSides.top,
|
|
right: clipInsetSides.right,
|
|
bottom: clipInsetSides.bottom,
|
|
left: clipInsetSides.left,
|
|
};
|
|
sides[side] = next;
|
|
void onSetStyle("clip-path", buildInsetClipPathSides(sides, clipInsetSides.radius));
|
|
};
|
|
|
|
return (
|
|
<>
|
|
<FlatSlider
|
|
label="Mask inset"
|
|
value={clipInsetValue}
|
|
min={0}
|
|
max={Math.max(120, Math.ceil(clipInsetValue))}
|
|
step={1}
|
|
tier={clipInsetValue > 0 ? "explicitCustom" : "default"}
|
|
displayValue={`${formatNumericValue(clipInsetValue)}px`}
|
|
disabled={disabled}
|
|
onCommit={(next) =>
|
|
void onSetStyle("clip-path", buildInsetClipPathValue(next, radiusValue))
|
|
}
|
|
/>
|
|
{showClipInsetSides && (
|
|
<div className="grid grid-cols-4 gap-2">
|
|
<MetricField
|
|
label="T"
|
|
value={formatPxMetricValue(clipInsetSides.top)}
|
|
disabled={disabled}
|
|
onCommit={(next) => commitClipInsetSide("top", next)}
|
|
/>
|
|
<MetricField
|
|
label="R"
|
|
value={formatPxMetricValue(clipInsetSides.right)}
|
|
disabled={disabled}
|
|
onCommit={(next) => commitClipInsetSide("right", next)}
|
|
/>
|
|
<MetricField
|
|
label="B"
|
|
value={formatPxMetricValue(clipInsetSides.bottom)}
|
|
disabled={disabled}
|
|
onCommit={(next) => commitClipInsetSide("bottom", next)}
|
|
/>
|
|
<MetricField
|
|
label="L"
|
|
value={formatPxMetricValue(clipInsetSides.left)}
|
|
disabled={disabled}
|
|
onCommit={(next) => commitClipInsetSide("left", next)}
|
|
/>
|
|
</div>
|
|
)}
|
|
</>
|
|
);
|
|
}
|