@hyperframes/studio 0.7.71 → 0.7.73
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/assets/{hyperframes-player-C1X90psg.js → hyperframes-player-DGlzhf_s.js} +1 -1
- package/dist/assets/index-B37rWXo4.css +1 -0
- package/dist/assets/{index-DzxDHPR1.js → index-CbVTOJ-E.js} +1 -1
- package/dist/assets/{index-nY4lLBqM.js → index-CcA5WVJv.js} +1 -1
- package/dist/assets/index-DXcLI2wu.js +428 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.html +2 -2
- package/dist/index.js +7762 -4261
- package/dist/index.js.map +1 -1
- package/package.json +7 -7
- package/src/App.tsx +4 -4
- package/src/components/StudioLeftSidebar.tsx +2 -3
- package/src/components/StudioRightPanel.tsx +10 -4
- package/src/components/editor/AnimationCard.test.tsx +100 -0
- package/src/components/editor/AnimationCard.tsx +5 -2
- package/src/components/editor/EaseCurveSection.test.tsx +348 -0
- package/src/components/editor/EaseCurveSection.tsx +444 -237
- package/src/components/editor/EaseParamFields.test.tsx +188 -0
- package/src/components/editor/EaseParamFields.tsx +246 -0
- package/src/components/editor/PropertyPanel.test.tsx +9 -7
- package/src/components/editor/PropertyPanelFlat.tsx +75 -88
- package/src/components/editor/colorGradingFrameAnalysis.test.ts +101 -0
- package/src/components/editor/colorGradingFrameAnalysis.ts +203 -0
- package/src/components/editor/colorGradingScopePatch.test.ts +3 -3
- package/src/components/editor/easeCurveSvg.tsx +65 -0
- package/src/components/editor/easePresetLibrary.test.ts +114 -0
- package/src/components/editor/easePresetLibrary.ts +49 -0
- package/src/components/editor/gsapAnimationConstants.ts +15 -13
- package/src/components/editor/propertyPanelColorCurveGraph.tsx +549 -0
- package/src/components/editor/propertyPanelColorCurves.test.tsx +158 -0
- package/src/components/editor/propertyPanelColorCurves.tsx +185 -0
- package/src/components/editor/propertyPanelColorGradingControls.tsx +115 -77
- package/src/components/editor/propertyPanelColorScopes.tsx +258 -0
- package/src/components/editor/propertyPanelColorSecondary.test.tsx +181 -0
- package/src/components/editor/propertyPanelColorSecondary.tsx +448 -0
- package/src/components/editor/propertyPanelColorWheels.test.tsx +119 -0
- package/src/components/editor/propertyPanelColorWheels.tsx +334 -0
- package/src/components/editor/propertyPanelFlatColorGradingAccessory.tsx +109 -0
- package/src/components/editor/propertyPanelFlatColorGradingSection.test.tsx +239 -41
- package/src/components/editor/propertyPanelFlatColorGradingSection.tsx +260 -300
- package/src/components/editor/propertyPanelFlatEffectControl.tsx +96 -0
- package/src/components/editor/propertyPanelFlatEffectSpecs.ts +305 -0
- package/src/components/editor/propertyPanelFlatEffectsSection.test.tsx +331 -0
- package/src/components/editor/propertyPanelFlatEffectsSection.tsx +503 -0
- package/src/components/editor/propertyPanelFlatOverlaysSection.test.tsx +113 -0
- package/src/components/editor/propertyPanelFlatOverlaysSection.tsx +108 -0
- package/src/components/editor/propertyPanelFlatPrimitives.tsx +2 -0
- package/src/components/editor/propertyPanelGradingNumberField.test.tsx +79 -0
- package/src/components/editor/propertyPanelGradingNumberField.tsx +116 -0
- package/src/components/editor/propertyPanelPresetPreview.ts +36 -0
- package/src/components/editor/propertyPanelTypes.ts +13 -0
- package/src/components/editor/useColorGradingController.test.ts +331 -10
- package/src/components/editor/useColorGradingController.ts +57 -90
- package/src/components/editor/useColorGradingPreviews.ts +350 -0
- package/src/components/editor/useColorGradingScopes.test.tsx +143 -0
- package/src/components/editor/useColorGradingScopes.ts +62 -0
- package/src/components/editor/useInspectorGestureTransaction.ts +30 -1
- package/src/components/nle/NLEContext.tsx +1 -1
- package/src/contexts/PanelLayoutContext.tsx +3 -6
- package/src/hooks/useBlockCatalog.ts +31 -13
- package/src/hooks/useBlockHandlers.ts +22 -0
- package/src/hooks/useGsapScriptCommits.test.tsx +15 -0
- package/src/hooks/useGsapScriptCommits.ts +14 -1
- package/src/hooks/usePanelLayout.test.ts +68 -1
- package/src/hooks/usePanelLayout.ts +72 -34
- package/src/icons/SystemIcons.tsx +4 -0
- package/src/player/components/PlayerControls.tsx +68 -229
- package/src/player/components/ShortcutsPanel.tsx +2 -4
- package/src/player/components/SpeedMenu.tsx +1 -2
- package/src/telemetry/events.test.ts +9 -0
- package/src/telemetry/events.ts +5 -0
- package/src/utils/blockInstaller.test.ts +67 -0
- package/src/utils/blockInstaller.ts +162 -109
- package/src/utils/studioUiPreferences.test.ts +5 -0
- package/src/utils/studioUiPreferences.ts +8 -0
- package/dist/assets/index-CSCh2Vrp.js +0 -428
- package/dist/assets/index-Ceyz8Qt2.css +0 -1
- package/src/player/components/PlayerControls.test.ts +0 -20
- package/src/player/components/useSeekBarDrag.ts +0 -169
|
@@ -7,7 +7,10 @@ import {
|
|
|
7
7
|
FlatColorGradingAccessory,
|
|
8
8
|
FlatColorGradingSection,
|
|
9
9
|
} from "./propertyPanelFlatColorGradingSection";
|
|
10
|
-
import {
|
|
10
|
+
import {
|
|
11
|
+
normalizeHfColorGrading,
|
|
12
|
+
type NormalizedHfColorGrading,
|
|
13
|
+
} from "@hyperframes/core/color-grading";
|
|
11
14
|
|
|
12
15
|
(globalThis as unknown as { IS_REACT_ACT_ENVIRONMENT: boolean }).IS_REACT_ACT_ENVIRONMENT = true;
|
|
13
16
|
|
|
@@ -215,39 +218,260 @@ function neutralPropsBase() {
|
|
|
215
218
|
grading: neutralGrading(),
|
|
216
219
|
assets: [] as string[],
|
|
217
220
|
onCommitColorGrading: vi.fn(),
|
|
221
|
+
onPreviewColorGrading: vi.fn(),
|
|
218
222
|
applyScope: "source-file" as const,
|
|
219
223
|
applyBusy: false,
|
|
220
224
|
onSetApplyScope: vi.fn(),
|
|
221
225
|
onApplyToScope: vi.fn(),
|
|
222
226
|
onApplyScopeAvailable: true,
|
|
223
227
|
mediaMetadata: null,
|
|
228
|
+
presetPreviews: {
|
|
229
|
+
status: "ready" as const,
|
|
230
|
+
images: { "bright-pop": "data:image/png;base64,bright" },
|
|
231
|
+
width: 160,
|
|
232
|
+
height: 90,
|
|
233
|
+
},
|
|
234
|
+
onRequestPresetPreviews: vi.fn(),
|
|
235
|
+
captureGradedFrame: vi.fn(async () => null),
|
|
224
236
|
};
|
|
225
237
|
}
|
|
226
238
|
|
|
227
239
|
describe("FlatColorGradingSection — Preset + LUT", () => {
|
|
228
|
-
it("
|
|
240
|
+
it("previews looks without committing, restores on leave, and commits only on click", () => {
|
|
229
241
|
const onCommitColorGrading = vi.fn();
|
|
242
|
+
const onPreviewColorGrading = vi.fn();
|
|
243
|
+
const base = neutralGrading();
|
|
244
|
+
const grading = {
|
|
245
|
+
...base,
|
|
246
|
+
intensity: 0.4,
|
|
247
|
+
adjust: { ...base.adjust, contrast: 0.3 },
|
|
248
|
+
wheels: {
|
|
249
|
+
...base.wheels,
|
|
250
|
+
shadows: { hue: 210, amount: 0.12, level: 0.04 },
|
|
251
|
+
},
|
|
252
|
+
curves: {
|
|
253
|
+
...base.curves,
|
|
254
|
+
master: [
|
|
255
|
+
[0, 0],
|
|
256
|
+
[0.5, 0.58],
|
|
257
|
+
[1, 1],
|
|
258
|
+
] as const,
|
|
259
|
+
},
|
|
260
|
+
hueCurves: {
|
|
261
|
+
...base.hueCurves,
|
|
262
|
+
hueVsSaturation: [
|
|
263
|
+
[0, 0],
|
|
264
|
+
[120, 0.1],
|
|
265
|
+
[240, 0],
|
|
266
|
+
] as const,
|
|
267
|
+
},
|
|
268
|
+
secondaries:
|
|
269
|
+
normalizeHfColorGrading({
|
|
270
|
+
secondaries: [
|
|
271
|
+
{
|
|
272
|
+
key: { hue: { center: 30, range: 15 } },
|
|
273
|
+
correction: { saturation: 0.08 },
|
|
274
|
+
},
|
|
275
|
+
],
|
|
276
|
+
})?.secondaries ?? [],
|
|
277
|
+
details: { ...base.details, vignette: 0.2 },
|
|
278
|
+
effects: { ...base.effects, pixelate: 0.5 },
|
|
279
|
+
palette: ["#112233", "#ffffff"],
|
|
280
|
+
lut: { src: "assets/luts/custom.cube", intensity: 0.6 },
|
|
281
|
+
};
|
|
230
282
|
const { host, root } = renderInto(
|
|
231
283
|
<FlatColorGradingSection
|
|
232
284
|
{...neutralPropsBase()}
|
|
285
|
+
grading={grading}
|
|
233
286
|
onCommitColorGrading={onCommitColorGrading}
|
|
287
|
+
onPreviewColorGrading={onPreviewColorGrading}
|
|
234
288
|
/>,
|
|
235
289
|
);
|
|
236
|
-
const
|
|
237
|
-
'[data-flat-grade-preset="
|
|
290
|
+
const brightPop = host.querySelector<HTMLButtonElement>(
|
|
291
|
+
'[data-flat-grade-preset="bright-pop"]',
|
|
238
292
|
);
|
|
239
|
-
if (!
|
|
240
|
-
expect(presetSelect.value).toBe("neutral");
|
|
241
|
-
// The visible "Preset" label is a sibling span outside FlatSelectRow
|
|
242
|
-
// (label="" there, to avoid rendering it twice) — the select still
|
|
243
|
-
// needs its own accessible name via the dedicated ariaLabel prop.
|
|
244
|
-
expect(presetSelect.getAttribute("aria-label")).toBe("Preset");
|
|
293
|
+
if (!brightPop) throw new Error("expected a Bright Pop look button");
|
|
245
294
|
act(() => {
|
|
246
|
-
|
|
247
|
-
|
|
295
|
+
brightPop.dispatchEvent(new MouseEvent("pointerover", { bubbles: true }));
|
|
296
|
+
});
|
|
297
|
+
expect(onPreviewColorGrading.mock.calls.at(-1)?.[0].preset).toBe("bright-pop");
|
|
298
|
+
expect(onPreviewColorGrading.mock.calls.at(-1)?.[1]).toEqual({
|
|
299
|
+
animatedPreview: { kind: "presets", id: "bright-pop" },
|
|
248
300
|
});
|
|
301
|
+
expect(onCommitColorGrading).not.toHaveBeenCalled();
|
|
302
|
+
act(() => brightPop.dispatchEvent(new MouseEvent("pointerout", { bubbles: true })));
|
|
303
|
+
expect(onPreviewColorGrading).toHaveBeenLastCalledWith(null);
|
|
304
|
+
act(() => brightPop.dispatchEvent(new MouseEvent("click", { bubbles: true })));
|
|
249
305
|
expect(onCommitColorGrading).toHaveBeenCalledTimes(1);
|
|
250
|
-
expect(onCommitColorGrading.mock.calls[0][0]
|
|
306
|
+
expect(onCommitColorGrading.mock.calls[0][0]).toMatchObject({
|
|
307
|
+
preset: "bright-pop",
|
|
308
|
+
intensity: 1,
|
|
309
|
+
effects: { pixelate: 0.5 },
|
|
310
|
+
palette: ["#112233", "#ffffff"],
|
|
311
|
+
lut: { src: "assets/luts/custom.cube", intensity: 0.6 },
|
|
312
|
+
});
|
|
313
|
+
expect(onCommitColorGrading.mock.calls[0][0].wheels.shadows.amount).toBe(0);
|
|
314
|
+
expect(onCommitColorGrading.mock.calls[0][0].curves.master).toEqual([
|
|
315
|
+
[0, 0],
|
|
316
|
+
[1, 1],
|
|
317
|
+
]);
|
|
318
|
+
expect(onCommitColorGrading.mock.calls[0][0].hueCurves.hueVsSaturation).toEqual([]);
|
|
319
|
+
expect(onCommitColorGrading.mock.calls[0][0].secondaries).toEqual([]);
|
|
320
|
+
expect(onCommitColorGrading.mock.calls[0][0].adjust.contrast).not.toBe(0.3);
|
|
321
|
+
expect(onCommitColorGrading.mock.calls[0][0].details.vignette).not.toBe(0.2);
|
|
322
|
+
act(() => root.unmount());
|
|
323
|
+
});
|
|
324
|
+
|
|
325
|
+
it("orders manual controls like the shader pipeline", () => {
|
|
326
|
+
const { host, root } = renderInto(<FlatColorGradingSection {...neutralPropsBase()} />);
|
|
327
|
+
const elements = [
|
|
328
|
+
host.querySelector('[data-flat-grade-adjust="true"]'),
|
|
329
|
+
host.querySelector('[data-color-wheels="true"]'),
|
|
330
|
+
host.querySelector('[data-color-curves="true"]'),
|
|
331
|
+
host.querySelector('[data-flat-grade-secondary="true"]'),
|
|
332
|
+
host.querySelector('[data-flat-grade-lut-toggle="true"]'),
|
|
333
|
+
];
|
|
334
|
+
expect(elements.every(Boolean)).toBe(true);
|
|
335
|
+
for (let index = 0; index < elements.length - 1; index += 1) {
|
|
336
|
+
const current = elements[index];
|
|
337
|
+
const next = elements[index + 1];
|
|
338
|
+
if (!current || !next) throw new Error("expected all grading sections");
|
|
339
|
+
expect(current.compareDocumentPosition(next) & Node.DOCUMENT_POSITION_FOLLOWING).not.toBe(0);
|
|
340
|
+
}
|
|
341
|
+
act(() => root.unmount());
|
|
342
|
+
});
|
|
343
|
+
|
|
344
|
+
it("samples the full-strength signal entering the secondary stage", async () => {
|
|
345
|
+
const base = neutralGrading();
|
|
346
|
+
const grading = normalizeHfColorGrading({
|
|
347
|
+
...base,
|
|
348
|
+
preset: "warm-polished",
|
|
349
|
+
intensity: 0.35,
|
|
350
|
+
adjust: { ...base.adjust, exposure: 0.2 },
|
|
351
|
+
wheels: {
|
|
352
|
+
...base.wheels,
|
|
353
|
+
shadows: { hue: 210, amount: 0.2, level: 0.05 },
|
|
354
|
+
},
|
|
355
|
+
curves: {
|
|
356
|
+
...base.curves,
|
|
357
|
+
master: [
|
|
358
|
+
[0, 0],
|
|
359
|
+
[0.5, 0.6],
|
|
360
|
+
[1, 1],
|
|
361
|
+
],
|
|
362
|
+
},
|
|
363
|
+
hueCurves: {
|
|
364
|
+
...base.hueCurves,
|
|
365
|
+
hueVsSaturation: [
|
|
366
|
+
[0, 0],
|
|
367
|
+
[120, 0.1],
|
|
368
|
+
[240, 0],
|
|
369
|
+
],
|
|
370
|
+
},
|
|
371
|
+
secondaries: [{ key: { hue: { center: 30, range: 15 } }, correction: {} }],
|
|
372
|
+
details: { ...base.details, vignette: 0.4, grain: 0.2 },
|
|
373
|
+
effects: { ...base.effects, pixelate: 0.5 },
|
|
374
|
+
lut: { src: "assets/luts/custom.cube", intensity: 0.8 },
|
|
375
|
+
});
|
|
376
|
+
if (!grading) throw new Error("expected a secondary grade");
|
|
377
|
+
const captureGradedFrame = vi.fn(
|
|
378
|
+
async (_options?: { grading?: NormalizedHfColorGrading }) => null,
|
|
379
|
+
);
|
|
380
|
+
const { host, root } = renderInto(
|
|
381
|
+
<FlatColorGradingSection
|
|
382
|
+
{...neutralPropsBase()}
|
|
383
|
+
grading={grading}
|
|
384
|
+
captureGradedFrame={captureGradedFrame}
|
|
385
|
+
/>,
|
|
386
|
+
);
|
|
387
|
+
|
|
388
|
+
await act(async () => {
|
|
389
|
+
const sample = Array.from(host.querySelectorAll<HTMLButtonElement>("button")).find((button) =>
|
|
390
|
+
button.textContent?.includes("Sample color from frame"),
|
|
391
|
+
);
|
|
392
|
+
sample?.dispatchEvent(new MouseEvent("click", { bubbles: true }));
|
|
393
|
+
await Promise.resolve();
|
|
394
|
+
});
|
|
395
|
+
|
|
396
|
+
expect(captureGradedFrame).toHaveBeenCalledTimes(1);
|
|
397
|
+
const options = captureGradedFrame.mock.calls[0]?.[0];
|
|
398
|
+
const sampledGrading = options?.grading;
|
|
399
|
+
if (!sampledGrading) throw new Error("expected the sampled grading input");
|
|
400
|
+
expect(sampledGrading).toMatchObject({
|
|
401
|
+
preset: null,
|
|
402
|
+
intensity: 1,
|
|
403
|
+
adjust: grading.adjust,
|
|
404
|
+
wheels: grading.wheels,
|
|
405
|
+
curves: grading.curves,
|
|
406
|
+
hueCurves: grading.hueCurves,
|
|
407
|
+
secondaries: [],
|
|
408
|
+
lut: null,
|
|
409
|
+
});
|
|
410
|
+
expect(sampledGrading.details.vignette).toBe(0);
|
|
411
|
+
expect(sampledGrading.details.grain).toBe(0);
|
|
412
|
+
expect(sampledGrading.effects.pixelate).toBe(0);
|
|
413
|
+
act(() => root.unmount());
|
|
414
|
+
});
|
|
415
|
+
|
|
416
|
+
it("keeps effect-bearing saved styles out of Grade", () => {
|
|
417
|
+
const { host, root } = renderInto(<FlatColorGradingSection {...neutralPropsBase()} />);
|
|
418
|
+
const presets = host.querySelector('[data-flat-grade-preset-group="presets"]');
|
|
419
|
+
expect(presets?.querySelector('[data-flat-grade-preset="bright-pop"]')).not.toBeNull();
|
|
420
|
+
expect(presets?.querySelector('[data-flat-grade-preset="vhs-playback"]')).toBeNull();
|
|
421
|
+
expect(presets?.querySelector('[data-flat-grade-preset="editorial-halftone"]')).toBeNull();
|
|
422
|
+
expect(host.querySelector('[data-flat-grade-preset="neutral"]')?.textContent).toContain(
|
|
423
|
+
"Neutral",
|
|
424
|
+
);
|
|
425
|
+
act(() => root.unmount());
|
|
426
|
+
});
|
|
427
|
+
|
|
428
|
+
it("shows ready selected-media preview images without requesting a duplicate batch", () => {
|
|
429
|
+
const onRequestPresetPreviews = vi.fn();
|
|
430
|
+
const { host, root } = renderInto(
|
|
431
|
+
<FlatColorGradingSection
|
|
432
|
+
{...neutralPropsBase()}
|
|
433
|
+
onRequestPresetPreviews={onRequestPresetPreviews}
|
|
434
|
+
/>,
|
|
435
|
+
);
|
|
436
|
+
expect(onRequestPresetPreviews).not.toHaveBeenCalled();
|
|
437
|
+
expect(
|
|
438
|
+
host.querySelector<HTMLImageElement>('[data-flat-grade-preview="bright-pop"]')?.src,
|
|
439
|
+
).toContain("data:image/png;base64,bright");
|
|
440
|
+
expect(host.textContent).not.toContain("VHS Playback");
|
|
441
|
+
act(() => root.unmount());
|
|
442
|
+
});
|
|
443
|
+
|
|
444
|
+
it("requests an idle preview batch once", () => {
|
|
445
|
+
const onRequestPresetPreviews = vi.fn();
|
|
446
|
+
const props = neutralPropsBase();
|
|
447
|
+
const { root } = renderInto(
|
|
448
|
+
<FlatColorGradingSection
|
|
449
|
+
{...props}
|
|
450
|
+
presetPreviews={{ ...props.presetPreviews, status: "idle", images: {} }}
|
|
451
|
+
onRequestPresetPreviews={onRequestPresetPreviews}
|
|
452
|
+
/>,
|
|
453
|
+
);
|
|
454
|
+
expect(onRequestPresetPreviews).toHaveBeenCalledTimes(1);
|
|
455
|
+
act(() => root.unmount());
|
|
456
|
+
});
|
|
457
|
+
|
|
458
|
+
it("requires an explicit retry after a preview failure", () => {
|
|
459
|
+
const onRequestPresetPreviews = vi.fn();
|
|
460
|
+
const props = neutralPropsBase();
|
|
461
|
+
const { host, root } = renderInto(
|
|
462
|
+
<FlatColorGradingSection
|
|
463
|
+
{...props}
|
|
464
|
+
presetPreviews={{ ...props.presetPreviews, status: "unavailable", images: {} }}
|
|
465
|
+
onRequestPresetPreviews={onRequestPresetPreviews}
|
|
466
|
+
/>,
|
|
467
|
+
);
|
|
468
|
+
expect(onRequestPresetPreviews).not.toHaveBeenCalled();
|
|
469
|
+
const retry = Array.from(host.querySelectorAll("button")).find(
|
|
470
|
+
(button) => button.textContent === "Retry look previews",
|
|
471
|
+
);
|
|
472
|
+
if (!retry) throw new Error("expected an explicit preview retry");
|
|
473
|
+
act(() => retry.dispatchEvent(new MouseEvent("click", { bubbles: true })));
|
|
474
|
+
expect(onRequestPresetPreviews).toHaveBeenCalledTimes(1);
|
|
251
475
|
act(() => root.unmount());
|
|
252
476
|
});
|
|
253
477
|
|
|
@@ -410,7 +634,7 @@ describe("FlatColorGradingSection — Adjust sliders", () => {
|
|
|
410
634
|
act(() => root.unmount());
|
|
411
635
|
});
|
|
412
636
|
|
|
413
|
-
it("does NOT force intensity to revive when the
|
|
637
|
+
it("does NOT force intensity to revive when the Amount slider itself is dragged — it writes the value directly", () => {
|
|
414
638
|
const onCommitColorGrading = vi.fn();
|
|
415
639
|
const grading = { ...neutralGrading(), intensity: 0 };
|
|
416
640
|
const { host, root } = renderInto(
|
|
@@ -420,7 +644,7 @@ describe("FlatColorGradingSection — Adjust sliders", () => {
|
|
|
420
644
|
onCommitColorGrading={onCommitColorGrading}
|
|
421
645
|
/>,
|
|
422
646
|
);
|
|
423
|
-
const strengthRow = findRowByText(host, "div", "
|
|
647
|
+
const strengthRow = findRowByText(host, "div", "Amount", "startsWith");
|
|
424
648
|
// min=0, max=100, step=1, ratio=0.4 -> raw=40 -> commit(40) -> intensity = 40/100 = 0.4
|
|
425
649
|
dragSliderTrack(strengthRow, 40, 100);
|
|
426
650
|
expect(onCommitColorGrading).toHaveBeenCalledTimes(1);
|
|
@@ -492,32 +716,6 @@ describe("FlatColorGradingSection — Vignette and Grain", () => {
|
|
|
492
716
|
});
|
|
493
717
|
});
|
|
494
718
|
|
|
495
|
-
describe("FlatColorGradingSection — Effects", () => {
|
|
496
|
-
it("renders Blur and Pixelate sliders under an Effects micro-label", () => {
|
|
497
|
-
const { host, root } = renderInto(<FlatColorGradingSection {...neutralPropsBase()} />);
|
|
498
|
-
expect(host.textContent).toContain("Effects");
|
|
499
|
-
const rows = host.querySelectorAll('[data-flat-grade-effect="true"]');
|
|
500
|
-
expect(rows).toHaveLength(2);
|
|
501
|
-
act(() => root.unmount());
|
|
502
|
-
});
|
|
503
|
-
|
|
504
|
-
it("commits a dragged Pixelate value on slider track pointerdown, scaled from percent to the 0..1 effect range", () => {
|
|
505
|
-
const onCommitColorGrading = vi.fn();
|
|
506
|
-
const { host, root } = renderInto(
|
|
507
|
-
<FlatColorGradingSection
|
|
508
|
-
{...neutralPropsBase()}
|
|
509
|
-
onCommitColorGrading={onCommitColorGrading}
|
|
510
|
-
/>,
|
|
511
|
-
);
|
|
512
|
-
const pixelateRow = findRowByText(host, '[data-flat-grade-effect="true"]', "Pixelate");
|
|
513
|
-
// min=0, max=100, step=1, ratio=0.75 -> raw=75 -> commit(75) -> effects.pixelate = 75/100 = 0.75
|
|
514
|
-
dragSliderTrack(pixelateRow, 75, 100);
|
|
515
|
-
expect(onCommitColorGrading).toHaveBeenCalledTimes(1);
|
|
516
|
-
expect(onCommitColorGrading.mock.calls[0][0].effects.pixelate).toBe(0.75);
|
|
517
|
-
act(() => root.unmount());
|
|
518
|
-
});
|
|
519
|
-
});
|
|
520
|
-
|
|
521
719
|
describe("FlatColorGradingSection — HDR banner and Apply scope", () => {
|
|
522
720
|
it("shows the HDR banner only when mediaMetadata reports an HDR source", () => {
|
|
523
721
|
const { host, root } = renderInto(
|