@bycrux/editor 0.12.0 → 1.0.2
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/package.json +3 -1
- package/src/ControlsInfoModal.tsx +251 -61
- package/src/__tests__/ControlsInfoModal.test.tsx +43 -0
- package/src/__tests__/adapter.test.ts +59 -1
- package/src/__tests__/schema-assignability.test.ts +93 -0
- package/src/__tests__/schema.test.ts +15 -0
- package/src/__tests__/video-adapter-contract.test.ts +128 -5
- package/src/carousel/AddElementMenu.tsx +10 -4
- package/src/carousel/CarouselEditor.tsx +46 -8
- package/src/carousel/CarouselRenderModal.tsx +15 -10
- package/src/carousel/OverlayPicker.tsx +10 -3
- package/src/carousel/SlidePropertyPanel.tsx +43 -21
- package/src/components/FilmstripScrubber.tsx +277 -0
- package/src/components/__tests__/FilmstripScrubber.test.tsx +216 -0
- package/src/engine/__tests__/audio-clock.test.ts +655 -0
- package/src/engine/__tests__/audio-worklet-source.test.ts +316 -0
- package/src/engine/__tests__/batch-planner.test.ts +298 -0
- package/src/engine/__tests__/decode-worker-source.test.ts +249 -0
- package/src/engine/__tests__/demux-ranged.test.ts +495 -0
- package/src/engine/__tests__/demux-truncated.test.ts +136 -0
- package/src/engine/__tests__/demux.test.ts +305 -0
- package/src/engine/__tests__/eligibility.test.ts +146 -0
- package/src/engine/__tests__/engine-recovery.test.ts +263 -0
- package/src/engine/__tests__/engine.test.ts +326 -0
- package/src/engine/__tests__/frame-server-ranged.test.ts +261 -0
- package/src/engine/__tests__/frame-server.test.ts +326 -0
- package/src/engine/__tests__/media-loader-ranged.test.ts +289 -0
- package/src/engine/__tests__/media-loader.test.ts +100 -0
- package/src/engine/__tests__/scheduler-crop.test.ts +353 -0
- package/src/engine/__tests__/scheduler.test.ts +1310 -0
- package/src/engine/__tests__/scrub-resolve.test.ts +96 -0
- package/src/engine/__tests__/scrub-source.test.ts +195 -0
- package/src/engine/__tests__/source-host.test.ts +455 -0
- package/src/engine/__tests__/time-stretch.test.ts +182 -0
- package/src/engine/audio-clock.ts +1179 -0
- package/src/engine/audio-worklet-source.ts +160 -0
- package/src/engine/batch-planner.ts +308 -0
- package/src/engine/debug-hud.tsx +54 -0
- package/src/engine/decode-worker-source.ts +142 -0
- package/src/engine/demux.ts +900 -0
- package/src/engine/eligibility.ts +140 -0
- package/src/engine/frame-server.ts +644 -0
- package/src/engine/index.ts +950 -0
- package/src/engine/media-loader.ts +380 -0
- package/src/engine/mp4box.d.ts +214 -0
- package/src/engine/scheduler.ts +1324 -0
- package/src/engine/scrub-resolve.ts +66 -0
- package/src/engine/scrub-source.ts +496 -0
- package/src/engine/time-stretch.ts +224 -0
- package/src/index.ts +75 -1
- package/src/preview/OverlayPreview.tsx +2 -24
- package/src/schema.ts +134 -2
- package/src/state/__tests__/use-project-sync.test.tsx +56 -0
- package/src/state/use-project-sync.ts +17 -0
- package/src/test-setup.ts +32 -0
- package/src/text/FontPicker.tsx +85 -51
- package/src/text/TextFormattingToolbar.tsx +6 -1
- package/src/text/__tests__/FontPicker.options.test.ts +43 -0
- package/src/text/__tests__/TextFormattingToolbar.test.tsx +4 -4
- package/src/theme.ts +108 -3
- package/src/types.ts +586 -22
- package/src/ui/Loader.tsx +64 -0
- package/src/ui/NumberField.tsx +254 -0
- package/src/ui/Slider.tsx +128 -0
- package/src/ui/Tooltip.tsx +118 -0
- package/src/ui/__tests__/NumberField.test.tsx +298 -0
- package/src/ui/__tests__/Slider.test.tsx +150 -0
- package/src/ui/__tests__/Tooltip.test.tsx +105 -0
- package/src/ui/__tests__/usePersistentState.test.tsx +112 -0
- package/src/ui/badge.tsx +12 -4
- package/src/ui/index.ts +6 -0
- package/src/ui/input.tsx +1 -1
- package/src/ui/select.tsx +1 -1
- package/src/ui/switch.tsx +12 -2
- package/src/ui/textarea.tsx +1 -1
- package/src/ui/usePersistentState.ts +63 -0
- package/src/video/AudioPolishModal.tsx +983 -0
- package/src/video/CaptionListPanel.test.tsx +944 -0
- package/src/video/CaptionListPanel.tsx +1106 -0
- package/src/video/CaptionRegenModal.tsx +37 -9
- package/src/video/CaptionSpecimen.tsx +161 -0
- package/src/video/CaptionStyleGallery.tsx +466 -0
- package/src/video/CommandPalette.tsx +165 -0
- package/src/video/ImageToneMenu.tsx +6 -2
- package/src/video/OverlayInspector.tsx +977 -0
- package/src/video/RenderModal.tsx +1035 -62
- package/src/video/VersionCompare.tsx +258 -0
- package/src/video/VersionPanel.tsx +117 -42
- package/src/video/VideoEditor.tsx +2202 -251
- package/src/video/__tests__/AudioPolishModal.test.tsx +825 -0
- package/src/video/__tests__/CaptionListPanel.font.test.tsx +397 -0
- package/src/video/__tests__/CaptionListPanel.generate.test.tsx +153 -0
- package/src/video/__tests__/CaptionRegenModal.test.tsx +29 -0
- package/src/video/__tests__/CaptionSpecimen.test.tsx +213 -0
- package/src/video/__tests__/CaptionStyleGallery.test.tsx +362 -0
- package/src/video/__tests__/CommandPalette.test.tsx +119 -0
- package/src/video/__tests__/OverlayInspector.test.tsx +1367 -0
- package/src/video/__tests__/RenderModal.exportControls.test.tsx +319 -0
- package/src/video/__tests__/RenderModal.options.test.tsx +562 -0
- package/src/video/__tests__/RenderModal.progress.test.ts +65 -0
- package/src/video/__tests__/VersionCompare.test.tsx +182 -0
- package/src/video/__tests__/VersionPanel.test.tsx +279 -0
- package/src/video/__tests__/VideoEditor.audioPolish.test.tsx +241 -0
- package/src/video/__tests__/VideoEditor.captionDelete.test.tsx +147 -0
- package/src/video/__tests__/VideoEditor.captionGesture.test.tsx +170 -0
- package/src/video/__tests__/VideoEditor.captionSeam.test.tsx +134 -0
- package/src/video/__tests__/VideoEditor.clipKeyframes.test.tsx +59 -0
- package/src/video/__tests__/VideoEditor.context.test.tsx +44 -0
- package/src/video/__tests__/VideoEditor.editFocus.test.tsx +55 -0
- package/src/video/__tests__/VideoEditor.keymap.test.tsx +725 -0
- package/src/video/__tests__/VideoEditor.layout.test.tsx +338 -0
- package/src/video/__tests__/VideoEditor.propertiesPanel.test.tsx +765 -0
- package/src/video/__tests__/VideoEditor.rippleDeleteCaptions.test.tsx +159 -0
- package/src/video/__tests__/VideoEditor.sourcePreview.test.tsx +122 -0
- package/src/video/__tests__/VideoEditor.test.tsx +403 -50
- package/src/video/__tests__/audioMagnet.test.ts +158 -0
- package/src/video/__tests__/audioPolish.test.ts +1202 -0
- package/src/video/__tests__/captionActiveWord.test.ts +107 -0
- package/src/video/__tests__/captionLanes.test.ts +262 -0
- package/src/video/__tests__/captionPositioning.test.tsx +8 -3
- package/src/video/__tests__/captionWordFloor.test.ts +228 -0
- package/src/video/__tests__/clipboard-ops.test.ts +430 -0
- package/src/video/__tests__/cuts.insert.test.ts +244 -0
- package/src/video/__tests__/cuts.test.ts +1213 -34
- package/src/video/__tests__/export-limits.test.ts +195 -0
- package/src/video/__tests__/hover-scrub.test.ts +163 -0
- package/src/video/__tests__/keyframeOps.canKeyframeProp.test.ts +61 -0
- package/src/video/__tests__/keyframeOps.test.ts +643 -0
- package/src/video/__tests__/keymap.test.tsx +171 -0
- package/src/video/__tests__/render-progress.test.tsx +20 -4
- package/src/video/__tests__/shuttle.test.ts +210 -0
- package/src/video/__tests__/source-preview.test.ts +60 -0
- package/src/video/__tests__/timecode.test.ts +77 -0
- package/src/video/__tests__/use-report-context.test.tsx +101 -0
- package/src/video/audioMagnet.ts +72 -0
- package/src/video/audioPolish.ts +774 -0
- package/src/video/captionActiveWord.ts +74 -0
- package/src/video/captionLanes.ts +202 -0
- package/src/video/captionRepair.ts +9 -5
- package/src/video/captionStyleDefaults.ts +100 -0
- package/src/video/captionWordFloor.ts +83 -0
- package/src/video/clipboard-ops.ts +377 -0
- package/src/video/cuts.ts +713 -37
- package/src/video/export-limits.ts +102 -0
- package/src/video/hover-scrub.ts +102 -0
- package/src/video/keyframeOps.ts +384 -0
- package/src/video/keymap.ts +146 -0
- package/src/video/panels/ClipPropertiesPanel.tsx +706 -0
- package/src/video/panels/LeftPanelTabs.tsx +187 -0
- package/src/video/panels/OverlayContentPanel.tsx +351 -0
- package/src/video/panels/TabNav.tsx +60 -0
- package/src/video/panels/__tests__/ClipPropertiesPanel.test.tsx +645 -0
- package/src/video/panels/__tests__/LeftPanelTabs.test.tsx +189 -0
- package/src/video/panels/__tests__/OverlayContentPanel.test.tsx +222 -0
- package/src/video/panels/__tests__/TabNav.test.tsx +71 -0
- package/src/video/preview/CaptionPreview.tsx +57 -69
- package/src/video/preview/EngineSurface.tsx +103 -0
- package/src/video/preview/OverlayItemsLayer.tsx +315 -103
- package/src/video/preview/PreviewPlayer.tsx +337 -56
- package/src/video/preview/SocialPreviewMenu.tsx +214 -0
- package/src/video/preview/SocialSafeZoneOverlay.tsx +478 -0
- package/src/video/preview/__tests__/CaptionPreview.fonts.test.tsx +97 -0
- package/src/video/preview/__tests__/EngineSurface.test.tsx +114 -0
- package/src/video/preview/__tests__/OverlayItemsLayer.edit.test.tsx +4 -2
- package/src/video/preview/__tests__/OverlayItemsLayer.keyframes.test.tsx +363 -0
- package/src/video/preview/__tests__/OverlayItemsLayer.selection.test.tsx +329 -0
- package/src/video/preview/__tests__/PreviewPlayer.engine.test.tsx +139 -0
- package/src/video/preview/__tests__/SocialPreviewMenu.test.tsx +121 -0
- package/src/video/preview/__tests__/SocialSafeZoneOverlay.test.tsx +165 -0
- package/src/video/preview/__tests__/captionDragState.test.ts +120 -1
- package/src/video/preview/__tests__/latencyCompensation.test.tsx +451 -0
- package/src/video/preview/__tests__/proxySupport.test.ts +75 -0
- package/src/video/preview/__tests__/transformStyle.test.ts +29 -1
- package/src/video/preview/__tests__/useDragOverlay.perAxis.test.ts +197 -0
- package/src/video/preview/__tests__/useEnginePlayback.test.tsx +530 -0
- package/src/video/preview/__tests__/useVideoPlayback.corpus.test.ts +313 -0
- package/src/video/preview/__tests__/useVideoPlayback.test.ts +38 -5
- package/src/video/preview/__tests__/useVideoPlayback.trackAudio.test.ts +278 -0
- package/src/video/preview/audio-context.ts +111 -0
- package/src/video/preview/captionDragState.ts +91 -1
- package/src/video/preview/proxySupport.ts +86 -0
- package/src/video/preview/transformStyle.ts +22 -12
- package/src/video/preview/useDragOverlay.ts +92 -18
- package/src/video/preview/useEnginePlayback.ts +625 -0
- package/src/video/preview/useVideoPlayback.ts +211 -167
- package/src/video/sdrCurves.ts +56 -0
- package/src/video/shuttle.ts +159 -0
- package/src/video/source-preview.ts +66 -0
- package/src/video/timecode.ts +59 -0
- package/src/video/timeline/EditableSegment.tsx +1 -1
- package/src/video/timeline/Scrubber.tsx +46 -174
- package/src/video/timeline/SpeedControl.tsx +95 -0
- package/src/video/timeline/Timeline.tsx +1061 -328
- package/src/video/timeline/TimelineContext.ts +17 -10
- package/src/video/timeline/TrackGutter.tsx +560 -0
- package/src/video/timeline/TrackSettingsPopover.tsx +228 -0
- package/src/video/timeline/VolumeControl.tsx +113 -0
- package/src/video/timeline/__tests__/Timeline.backgroundClick.test.tsx +110 -0
- package/src/video/timeline/__tests__/Timeline.crossfade.test.tsx +104 -0
- package/src/video/timeline/__tests__/Timeline.fadeCurveMenu.test.tsx +174 -0
- package/src/video/timeline/__tests__/Timeline.keyframeDelete.test.tsx +273 -0
- package/src/video/timeline/__tests__/Timeline.keyframeFollow.test.tsx +215 -0
- package/src/video/timeline/__tests__/Timeline.keyframeMenu.test.tsx +253 -0
- package/src/video/timeline/__tests__/Timeline.keymap.test.tsx +372 -0
- package/src/video/timeline/__tests__/Timeline.subcutRegen.test.tsx +351 -0
- package/src/video/timeline/__tests__/TrackGutter.test.tsx +372 -0
- package/src/video/timeline/__tests__/_canvasSelect.test.tsx +273 -0
- package/src/video/timeline/__tests__/_canvasSelect.ts +414 -0
- package/src/video/timeline/__tests__/dragdrop-math.test.ts +135 -0
- package/src/video/timeline/__tests__/effectiveItemAudio.test.ts +50 -0
- package/src/video/timeline/__tests__/enabledTrackItems.test.ts +164 -0
- package/src/video/timeline/__tests__/moveItemAcrossTracks.test.ts +363 -0
- package/src/video/timeline/__tests__/multiSelectOps.test.ts +447 -0
- package/src/video/timeline/__tests__/placement.test.ts +278 -0
- package/src/video/timeline/__tests__/resizeWindowedItem.test.ts +140 -0
- package/src/video/timeline/__tests__/timeline-model.test.ts +576 -0
- package/src/video/timeline/__tests__/visualItemLabel.test.ts +69 -0
- package/src/video/timeline/canvas/TimelineCanvas.tsx +1447 -0
- package/src/video/timeline/canvas/__tests__/TimelineCanvas.drop.test.tsx +439 -0
- package/src/video/timeline/canvas/__tests__/TimelineCanvas.edgeScroll.test.tsx +346 -0
- package/src/video/timeline/canvas/__tests__/TimelineCanvas.panefill.test.tsx +122 -0
- package/src/video/timeline/canvas/__tests__/TimelineCanvas.pendingDrops.test.tsx +316 -0
- package/src/video/timeline/canvas/__tests__/TimelineCanvas.pointer.test.tsx +606 -0
- package/src/video/timeline/canvas/__tests__/TimelineCanvas.test.tsx +407 -0
- package/src/video/timeline/canvas/__tests__/clip-bands.test.ts +77 -0
- package/src/video/timeline/canvas/__tests__/draw.test.ts +2198 -0
- package/src/video/timeline/canvas/__tests__/fade-curve.test.ts +187 -0
- package/src/video/timeline/canvas/__tests__/filmstrips.test.ts +561 -0
- package/src/video/timeline/canvas/__tests__/hit-test.test.ts +818 -0
- package/src/video/timeline/canvas/__tests__/pending-drop.test.ts +210 -0
- package/src/video/timeline/canvas/__tests__/pointer-machine.test.ts +3358 -0
- package/src/video/timeline/canvas/__tests__/snap.test.ts +257 -0
- package/src/video/timeline/canvas/__tests__/viewport.test.ts +399 -0
- package/src/video/timeline/canvas/__tests__/waveforms.test.ts +946 -0
- package/src/video/timeline/canvas/clip-bands.ts +56 -0
- package/src/video/timeline/canvas/draw.ts +2187 -0
- package/src/video/timeline/canvas/fade-curve.ts +111 -0
- package/src/video/timeline/canvas/filmstrips.ts +418 -0
- package/src/video/timeline/canvas/hit-test.ts +501 -0
- package/src/video/timeline/canvas/keyframe-strip.ts +73 -0
- package/src/video/timeline/canvas/pointer-machine.ts +1828 -0
- package/src/video/timeline/canvas/snap.ts +232 -0
- package/src/video/timeline/canvas/viewport.ts +457 -0
- package/src/video/timeline/canvas/waveforms.ts +664 -0
- package/src/video/timeline/makeCaptionEdit.ts +5 -1
- package/src/video/timeline/multiSelectOps.ts +214 -55
- package/src/video/timeline/placement.ts +282 -0
- package/src/video/timeline/timeline-model.ts +919 -0
- package/src/video/timeline/useItemDragDrop.ts +151 -178
- package/src/video/timeline/useTimelineZoom.ts +25 -60
- package/src/video/timeline/utils.ts +0 -12
- package/src/video/use-report-context.ts +75 -0
- package/src/video/preview/OverlayPropsModal.tsx +0 -292
- package/src/video/preview/__tests__/OverlayPropsModal.test.tsx +0 -32
- package/src/video/timeline/AudioTrackRow.tsx +0 -404
- package/src/video/timeline/AudioWaveformLayer.tsx +0 -117
- package/src/video/timeline/CaptionTrackRow.tsx +0 -235
- package/src/video/timeline/PlayheadLine.tsx +0 -18
- package/src/video/timeline/TranscriptModal.tsx +0 -70
- package/src/video/timeline/TranscriptPanel.tsx +0 -273
- package/src/video/timeline/VisualTrackRow.tsx +0 -300
- package/src/video/timeline/__tests__/CaptionTrackRow.test.tsx +0 -241
- package/src/video/timeline/__tests__/PlayheadLine.test.tsx +0 -60
- package/src/video/timeline/__tests__/TranscriptModal.test.tsx +0 -41
- package/src/video/timeline/__tests__/TranscriptPanel.test.tsx +0 -184
- package/src/video/timeline/__tests__/useItemDragDrop.test.ts +0 -72
|
@@ -1,184 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, vi, afterEach } from 'vitest'
|
|
2
|
-
import { render, screen, fireEvent, cleanup } from '@testing-library/react'
|
|
3
|
-
import type { Project } from '../../../types'
|
|
4
|
-
import type { Captions } from '../../../schema'
|
|
5
|
-
import TranscriptPanel from '../TranscriptPanel'
|
|
6
|
-
|
|
7
|
-
afterEach(() => cleanup())
|
|
8
|
-
|
|
9
|
-
function makeProject(style: Captions['style'], extra: Partial<Captions> = {}): Project {
|
|
10
|
-
return { id: 'p1', captions: { style, segments: [], ...extra } } as unknown as Project
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
function renderPanel(
|
|
14
|
-
style: Captions['style'],
|
|
15
|
-
extra: Partial<Captions> = {},
|
|
16
|
-
opts: { selectedCaptionId?: string | null } = {},
|
|
17
|
-
) {
|
|
18
|
-
const onCaptionEdit = vi.fn()
|
|
19
|
-
const onProjectChange = vi.fn()
|
|
20
|
-
const onCaptionSegmentChange = vi.fn()
|
|
21
|
-
const project = makeProject(style, extra)
|
|
22
|
-
render(
|
|
23
|
-
<TranscriptPanel
|
|
24
|
-
project={project}
|
|
25
|
-
captionTrack={project.captions}
|
|
26
|
-
currentTime={0}
|
|
27
|
-
onCaptionEdit={onCaptionEdit}
|
|
28
|
-
onProjectChange={onProjectChange}
|
|
29
|
-
onCaptionSegmentChange={onCaptionSegmentChange}
|
|
30
|
-
selectedCaptionId={opts.selectedCaptionId ?? null}
|
|
31
|
-
onExpand={() => {}}
|
|
32
|
-
/>,
|
|
33
|
-
)
|
|
34
|
-
return { onCaptionEdit, onProjectChange, onCaptionSegmentChange }
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
describe('TranscriptPanel caption color controls', () => {
|
|
38
|
-
it('previews live on change and commits on blur, writing captions.color', () => {
|
|
39
|
-
const { onCaptionEdit, onProjectChange } = renderPanel('karaoke')
|
|
40
|
-
const input = screen.getByLabelText('Caption text color') as HTMLInputElement
|
|
41
|
-
|
|
42
|
-
fireEvent.change(input, { target: { value: '#76b900' } })
|
|
43
|
-
expect(onProjectChange).toHaveBeenCalledTimes(1)
|
|
44
|
-
expect(onProjectChange.mock.calls[0][0].captions.color).toBe('#76b900')
|
|
45
|
-
expect(onCaptionEdit).not.toHaveBeenCalled() // live preview must not persist
|
|
46
|
-
|
|
47
|
-
fireEvent.blur(input, { target: { value: '#76b900' } })
|
|
48
|
-
expect(onCaptionEdit).toHaveBeenCalledTimes(1)
|
|
49
|
-
expect(onCaptionEdit.mock.calls[0][0].captions.color).toBe('#76b900')
|
|
50
|
-
})
|
|
51
|
-
|
|
52
|
-
it('writes the accent to the field the active style actually reads', () => {
|
|
53
|
-
// karaoke → highlightColor
|
|
54
|
-
let h = renderPanel('karaoke')
|
|
55
|
-
fireEvent.blur(screen.getByLabelText('Caption highlight color'), { target: { value: '#111111' } })
|
|
56
|
-
expect(h.onCaptionEdit.mock.calls[0][0].captions.highlightColor).toBe('#111111')
|
|
57
|
-
cleanup()
|
|
58
|
-
|
|
59
|
-
// pop → activeColor
|
|
60
|
-
h = renderPanel('pop')
|
|
61
|
-
fireEvent.blur(screen.getByLabelText('Caption active color'), { target: { value: '#222222' } })
|
|
62
|
-
expect(h.onCaptionEdit.mock.calls[0][0].captions.activeColor).toBe('#222222')
|
|
63
|
-
cleanup()
|
|
64
|
-
|
|
65
|
-
// subtitle → backgroundColor
|
|
66
|
-
h = renderPanel('subtitle')
|
|
67
|
-
fireEvent.blur(screen.getByLabelText('Caption box color'), { target: { value: '#333333' } })
|
|
68
|
-
expect(h.onCaptionEdit.mock.calls[0][0].captions.backgroundColor).toBe('#333333')
|
|
69
|
-
cleanup()
|
|
70
|
-
|
|
71
|
-
// highlight-box → accentColor
|
|
72
|
-
h = renderPanel('highlight-box')
|
|
73
|
-
fireEvent.blur(screen.getByLabelText('Caption accent color'), { target: { value: '#444444' } })
|
|
74
|
-
expect(h.onCaptionEdit.mock.calls[0][0].captions.accentColor).toBe('#444444')
|
|
75
|
-
})
|
|
76
|
-
|
|
77
|
-
it('hides the accent swatch for styles with no accent', () => {
|
|
78
|
-
renderPanel('clean')
|
|
79
|
-
expect(screen.getByLabelText('Caption text color')).toBeTruthy()
|
|
80
|
-
expect(screen.queryByLabelText(/(accent|highlight|active|box) color/i)).toBeNull()
|
|
81
|
-
cleanup()
|
|
82
|
-
|
|
83
|
-
renderPanel('word-by-word')
|
|
84
|
-
expect(screen.queryByLabelText(/(accent|highlight|active|box) color/i)).toBeNull()
|
|
85
|
-
})
|
|
86
|
-
|
|
87
|
-
it('reflects the stored hex value on the swatch input', () => {
|
|
88
|
-
renderPanel('karaoke', { color: '#abcdef', highlightColor: '#00ff00' })
|
|
89
|
-
expect((screen.getByLabelText('Caption text color') as HTMLInputElement).value).toBe('#abcdef')
|
|
90
|
-
expect((screen.getByLabelText('Caption highlight color') as HTMLInputElement).value).toBe('#00ff00')
|
|
91
|
-
})
|
|
92
|
-
})
|
|
93
|
-
|
|
94
|
-
describe('TranscriptPanel per-segment caption color', () => {
|
|
95
|
-
it('no selection: base swatch is unchanged — still previews/commits the track-level color', () => {
|
|
96
|
-
const { onCaptionEdit, onProjectChange } = renderPanel('karaoke', {
|
|
97
|
-
segments: [{ id: 'cap-0', text: 'hi', start: 0, end: 2 }],
|
|
98
|
-
})
|
|
99
|
-
const input = screen.getByLabelText('Caption text color') as HTMLInputElement
|
|
100
|
-
|
|
101
|
-
fireEvent.change(input, { target: { value: '#76b900' } })
|
|
102
|
-
expect(onProjectChange).toHaveBeenCalledTimes(1)
|
|
103
|
-
expect(onProjectChange.mock.calls[0][0].captions.color).toBe('#76b900')
|
|
104
|
-
|
|
105
|
-
fireEvent.blur(input, { target: { value: '#76b900' } })
|
|
106
|
-
expect(onCaptionEdit).toHaveBeenCalledTimes(1)
|
|
107
|
-
expect(onCaptionEdit.mock.calls[0][0].captions.color).toBe('#76b900')
|
|
108
|
-
})
|
|
109
|
-
|
|
110
|
-
it('a selected segment: swatch previews live via onProjectChange (only that segment patched) and commits via onCaptionSegmentChange — never onCaptionEdit', () => {
|
|
111
|
-
const { onCaptionEdit, onProjectChange, onCaptionSegmentChange } = renderPanel('karaoke', {
|
|
112
|
-
color: '#ffffff',
|
|
113
|
-
segments: [
|
|
114
|
-
{ id: 'cap-0', text: 'hi', start: 0, end: 2 },
|
|
115
|
-
{ id: 'cap-1', text: 'there', start: 2, end: 4 },
|
|
116
|
-
],
|
|
117
|
-
}, { selectedCaptionId: 'cap-1' })
|
|
118
|
-
|
|
119
|
-
const input = screen.getByLabelText('Selected segment text color') as HTMLInputElement
|
|
120
|
-
|
|
121
|
-
// Live preview — onChange fires on every pick.
|
|
122
|
-
fireEvent.change(input, { target: { value: '#123456' } })
|
|
123
|
-
expect(onProjectChange).toHaveBeenCalledTimes(1)
|
|
124
|
-
const previewed = onProjectChange.mock.calls[0][0]
|
|
125
|
-
expect(previewed.captions.segments[1].color).toBe('#123456')
|
|
126
|
-
expect(previewed.captions.segments[0].color).toBeUndefined() // only the selected segment changes
|
|
127
|
-
expect(previewed.captions.color).toBe('#ffffff') // track-level color untouched
|
|
128
|
-
expect(onCaptionSegmentChange).not.toHaveBeenCalled()
|
|
129
|
-
expect(onCaptionEdit).not.toHaveBeenCalled()
|
|
130
|
-
|
|
131
|
-
// Commit — onBlur fires once, through the segment-patch channel, not
|
|
132
|
-
// the whole-track onCaptionEdit channel. One commit per gesture.
|
|
133
|
-
fireEvent.blur(input, { target: { value: '#123456' } })
|
|
134
|
-
expect(onCaptionSegmentChange).toHaveBeenCalledTimes(1)
|
|
135
|
-
expect(onCaptionSegmentChange).toHaveBeenCalledWith('cap-1', { color: '#123456' })
|
|
136
|
-
expect(onCaptionEdit).not.toHaveBeenCalled()
|
|
137
|
-
})
|
|
138
|
-
|
|
139
|
-
it("the swatch reflects the selected segment's own color when it has one", () => {
|
|
140
|
-
renderPanel('karaoke', {
|
|
141
|
-
color: '#abcdef',
|
|
142
|
-
segments: [{ id: 'cap-0', text: 'hi', start: 0, end: 2, color: '#00ff00' }],
|
|
143
|
-
}, { selectedCaptionId: 'cap-0' })
|
|
144
|
-
expect((screen.getByLabelText('Selected segment text color') as HTMLInputElement).value).toBe('#00ff00')
|
|
145
|
-
})
|
|
146
|
-
|
|
147
|
-
it('the swatch falls back to the track color when the selected segment has none of its own', () => {
|
|
148
|
-
renderPanel('karaoke', {
|
|
149
|
-
color: '#abcdef',
|
|
150
|
-
segments: [{ id: 'cap-0', text: 'hi', start: 0, end: 2 }],
|
|
151
|
-
}, { selectedCaptionId: 'cap-0' })
|
|
152
|
-
expect((screen.getByLabelText('Selected segment text color') as HTMLInputElement).value).toBe('#abcdef')
|
|
153
|
-
})
|
|
154
|
-
|
|
155
|
-
it('a selectedCaptionId that matches no segment falls back to track-level behavior', () => {
|
|
156
|
-
renderPanel('karaoke', {
|
|
157
|
-
segments: [{ id: 'cap-0', text: 'hi', start: 0, end: 2 }],
|
|
158
|
-
}, { selectedCaptionId: 'cap-does-not-exist' })
|
|
159
|
-
expect(screen.getByLabelText('Caption text color')).toBeTruthy()
|
|
160
|
-
expect(screen.queryByLabelText('Selected segment text color')).toBeNull()
|
|
161
|
-
})
|
|
162
|
-
})
|
|
163
|
-
|
|
164
|
-
describe('TranscriptPanel caption text edits', () => {
|
|
165
|
-
// Regression: makeCaptionEdit fires every callback it's given with the same
|
|
166
|
-
// updated project. TranscriptPanel used to pass BOTH onProjectChange and
|
|
167
|
-
// onCaptionEdit into makeCaptionEdit for a text edit, and — at this
|
|
168
|
-
// component's real call site (VideoEditor's ReviewSurface) — both land on
|
|
169
|
-
// sync.mutate, so one text edit produced two undo entries and two queued
|
|
170
|
-
// saves. Only onCaptionEdit (the commit channel) should fire.
|
|
171
|
-
it('a completed text edit produces exactly one commit, not two', () => {
|
|
172
|
-
const { onCaptionEdit, onProjectChange } = renderPanel('karaoke', {
|
|
173
|
-
segments: [{ id: 'cap-0', text: 'hello world', start: 0, end: 2 }],
|
|
174
|
-
})
|
|
175
|
-
|
|
176
|
-
const span = screen.getByText('hello world')
|
|
177
|
-
span.textContent = 'hello there'
|
|
178
|
-
fireEvent.blur(span)
|
|
179
|
-
|
|
180
|
-
expect(onCaptionEdit).toHaveBeenCalledTimes(1)
|
|
181
|
-
expect(onCaptionEdit.mock.calls[0][0].captions.segments[0].text).toBe('hello there')
|
|
182
|
-
expect(onProjectChange).not.toHaveBeenCalled()
|
|
183
|
-
})
|
|
184
|
-
})
|
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, vi, afterEach } from 'vitest'
|
|
2
|
-
import { renderHook } from '@testing-library/react'
|
|
3
|
-
import { useItemDragDrop } from '../useItemDragDrop'
|
|
4
|
-
|
|
5
|
-
// A press that drifts < 4px must stay a CLICK (so the timeline's click-to-select
|
|
6
|
-
// fires); only a press that travels past the threshold becomes a drag. Regression
|
|
7
|
-
// guard for the bug where any pixel of jitter suppressed clip selection.
|
|
8
|
-
|
|
9
|
-
const RECT = {
|
|
10
|
-
width: 1000, height: 100, left: 0, top: 0, right: 1000, bottom: 100, x: 0, y: 0,
|
|
11
|
-
toJSON: () => ({}),
|
|
12
|
-
} as DOMRect
|
|
13
|
-
|
|
14
|
-
function setup() {
|
|
15
|
-
const draggedFlagRef = { current: false }
|
|
16
|
-
const scrollRef = { current: { getBoundingClientRect: () => RECT } }
|
|
17
|
-
const { result } = renderHook(() =>
|
|
18
|
-
useItemDragDrop({
|
|
19
|
-
totalDuration: 100,
|
|
20
|
-
snapBoundaries: [],
|
|
21
|
-
scrollRef: scrollRef as unknown as React.RefObject<HTMLDivElement>,
|
|
22
|
-
draggedFlagRef: draggedFlagRef as unknown as React.MutableRefObject<boolean>,
|
|
23
|
-
}),
|
|
24
|
-
)
|
|
25
|
-
return { beginDrag: result.current.beginDrag, draggedFlagRef }
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
const ITEM = { id: 'a', start: 10, end: 20 }
|
|
29
|
-
|
|
30
|
-
function press(beginDrag: ReturnType<typeof setup>['beginDrag']) {
|
|
31
|
-
const onLivePreview = vi.fn()
|
|
32
|
-
const onCommit = vi.fn()
|
|
33
|
-
beginDrag(
|
|
34
|
-
{ stopPropagation: vi.fn(), clientX: 200, clientY: 200 } as unknown as React.MouseEvent,
|
|
35
|
-
ITEM,
|
|
36
|
-
{ onLivePreview, onCommit },
|
|
37
|
-
)
|
|
38
|
-
return { onLivePreview, onCommit }
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
afterEach(() => {
|
|
42
|
-
// ensure no stray listeners between tests
|
|
43
|
-
document.dispatchEvent(new MouseEvent('mouseup'))
|
|
44
|
-
vi.restoreAllMocks()
|
|
45
|
-
})
|
|
46
|
-
|
|
47
|
-
describe('useItemDragDrop — click vs drag threshold', () => {
|
|
48
|
-
it('sub-threshold drift stays a click: no drag flag, no move, no commit', () => {
|
|
49
|
-
const { beginDrag, draggedFlagRef } = setup()
|
|
50
|
-
const { onLivePreview, onCommit } = press(beginDrag)
|
|
51
|
-
|
|
52
|
-
// ~2.2px of jitter (hypot(2,1)) — under the 4px threshold
|
|
53
|
-
document.dispatchEvent(new MouseEvent('mousemove', { clientX: 202, clientY: 201 }))
|
|
54
|
-
document.dispatchEvent(new MouseEvent('mouseup'))
|
|
55
|
-
|
|
56
|
-
expect(draggedFlagRef.current).toBe(false) // click-to-select is NOT suppressed
|
|
57
|
-
expect(onLivePreview).not.toHaveBeenCalled()
|
|
58
|
-
expect(onCommit).not.toHaveBeenCalled()
|
|
59
|
-
})
|
|
60
|
-
|
|
61
|
-
it('moving past the threshold becomes a drag: flag set, move + commit fire', () => {
|
|
62
|
-
const { beginDrag, draggedFlagRef } = setup()
|
|
63
|
-
const { onLivePreview, onCommit } = press(beginDrag)
|
|
64
|
-
|
|
65
|
-
document.dispatchEvent(new MouseEvent('mousemove', { clientX: 240, clientY: 200 })) // 40px → drag
|
|
66
|
-
expect(draggedFlagRef.current).toBe(true)
|
|
67
|
-
expect(onLivePreview).toHaveBeenCalled()
|
|
68
|
-
|
|
69
|
-
document.dispatchEvent(new MouseEvent('mouseup'))
|
|
70
|
-
expect(onCommit).toHaveBeenCalled()
|
|
71
|
-
})
|
|
72
|
-
})
|