@bycrux/editor 1.2.2 → 1.4.0
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 +1 -1
- package/src/ControlsInfoModal.tsx +5 -5
- package/src/__tests__/no-opacity-modifier-on-editor-vars.test.ts +84 -0
- package/src/__tests__/node-shims.d.ts +19 -0
- package/src/__tests__/portal-roots-set-editor-text.test.ts +55 -0
- package/src/carousel/AddElementMenu.tsx +1 -1
- package/src/carousel/CarouselEditor.tsx +11 -11
- package/src/carousel/CarouselRenderModal.tsx +14 -14
- package/src/carousel/OverlayPicker.tsx +4 -4
- package/src/carousel/SlidePropertyPanel.tsx +6 -6
- package/src/carousel/__tests__/CarouselEditor.test.tsx +12 -0
- package/src/components/FilmstripScrubber.tsx +1 -1
- package/src/crop/VideoSourceCropModal.tsx +5 -5
- package/src/state/__tests__/use-project-sync.test.tsx +76 -0
- package/src/state/use-project-sync.ts +21 -1
- package/src/text/FontPicker.tsx +3 -3
- package/src/text/TextFormattingToolbar.tsx +3 -3
- package/src/types.ts +18 -0
- package/src/ui/Loader.tsx +1 -1
- package/src/ui/NumberField.tsx +3 -3
- package/src/ui/SwatchInput.tsx +1 -1
- package/src/ui/Tooltip.tsx +1 -1
- package/src/ui/input.tsx +1 -1
- package/src/ui/label.tsx +1 -1
- package/src/ui/textarea.tsx +1 -1
- package/src/video/AudioPolishModal.tsx +22 -22
- package/src/video/CaptionListPanel.test.tsx +8 -7
- package/src/video/CaptionListPanel.tsx +17 -17
- package/src/video/CaptionRegenModal.tsx +8 -8
- package/src/video/CaptionStyleGallery.tsx +1 -1
- package/src/video/CommandPalette.tsx +8 -8
- package/src/video/ImageToneMenu.tsx +13 -14
- package/src/video/OverlayInspector.tsx +7 -7
- package/src/video/RenderModal.tsx +76 -78
- package/src/video/VersionCompare.tsx +10 -10
- package/src/video/VersionPanel.tsx +2 -2
- package/src/video/VideoEditor.tsx +48 -23
- package/src/video/__tests__/RenderModal.hostTheme.test.tsx +85 -0
- package/src/video/__tests__/VideoEditor.context.test.tsx +6 -0
- package/src/video/__tests__/VideoEditor.pendingSurface.test.tsx +233 -0
- package/src/video/__tests__/VideoEditor.saveError.test.tsx +105 -0
- package/src/video/__tests__/export-limits.test.ts +27 -2
- package/src/video/__tests__/use-report-context.test.tsx +22 -1
- package/src/video/export-limits.ts +22 -1
- package/src/video/panels/ClipPropertiesPanel.tsx +4 -4
- package/src/video/panels/OverlayContentPanel.tsx +5 -5
- package/src/video/preview/OverlayItemsLayer.tsx +7 -2
- package/src/video/preview/PreviewPlayer.tsx +14 -0
- package/src/video/preview/SocialPreviewMenu.tsx +6 -6
- package/src/video/preview/__tests__/PreviewPlayer.playing.test.tsx +62 -0
- package/src/video/preview/__tests__/resolveOverlayPropPaths.test.ts +21 -0
- package/src/video/timeline/EditableSegment.tsx +1 -1
- package/src/video/timeline/Scrubber.tsx +2 -2
- package/src/video/timeline/SpeedControl.tsx +3 -3
- package/src/video/timeline/Timeline.tsx +3 -3
- package/src/video/timeline/TrackGutter.tsx +6 -6
- package/src/video/timeline/TrackSettingsPopover.tsx +4 -4
- package/src/video/timeline/VolumeControl.tsx +3 -3
- package/src/video/use-report-context.ts +10 -7
|
@@ -174,7 +174,7 @@ export default function TrackSettingsPopover({
|
|
|
174
174
|
ref={popoverRef}
|
|
175
175
|
role="dialog"
|
|
176
176
|
aria-label={title}
|
|
177
|
-
className="fixed z-[100] w-64 rounded-lg border border-[var(--editor-border)] bg-[var(--editor-surface)] shadow-2xl p-3 flex flex-col gap-3"
|
|
177
|
+
className="fixed z-[100] w-64 rounded-lg border border-[var(--editor-border)] bg-[var(--editor-surface)] shadow-2xl p-3 flex flex-col gap-3 text-[var(--editor-text)]"
|
|
178
178
|
style={{
|
|
179
179
|
left: position?.left ?? -9999,
|
|
180
180
|
top: position?.top ?? -9999,
|
|
@@ -186,7 +186,7 @@ export default function TrackSettingsPopover({
|
|
|
186
186
|
transform: position?.flipped ? 'translateY(-100%)' : undefined,
|
|
187
187
|
}}
|
|
188
188
|
>
|
|
189
|
-
<p className="text-xs font-semibold text-[var(--editor-text)]
|
|
189
|
+
<p className="text-xs font-semibold text-[color-mix(in_srgb,var(--editor-text)_90%,transparent)]">{title}</p>
|
|
190
190
|
|
|
191
191
|
{showVolume && (
|
|
192
192
|
<VolumeControl
|
|
@@ -211,14 +211,14 @@ export default function TrackSettingsPopover({
|
|
|
211
211
|
|
|
212
212
|
{showMute && (
|
|
213
213
|
<div className="flex items-center justify-between">
|
|
214
|
-
<span className="text-[11px] text-[var(--editor-text)]
|
|
214
|
+
<span className="text-[11px] text-[color-mix(in_srgb,var(--editor-text)_70%,transparent)]">Mute</span>
|
|
215
215
|
<Switch checked={!!muted} onCheckedChange={onMutedChange!} aria-label={muteAriaLabel} mode={mode} />
|
|
216
216
|
</div>
|
|
217
217
|
)}
|
|
218
218
|
|
|
219
219
|
{skip && (
|
|
220
220
|
<div className="flex items-center justify-between">
|
|
221
|
-
<span className="text-[11px] text-[var(--editor-text)]
|
|
221
|
+
<span className="text-[11px] text-[color-mix(in_srgb,var(--editor-text)_70%,transparent)]">Skip</span>
|
|
222
222
|
<Switch checked={skip.skipped} onCheckedChange={() => skip.onToggle()} aria-label={skip.ariaLabel} mode={mode} />
|
|
223
223
|
</div>
|
|
224
224
|
)}
|
|
@@ -69,9 +69,9 @@ export default function VolumeControl({
|
|
|
69
69
|
|
|
70
70
|
return (
|
|
71
71
|
<div className="flex flex-col gap-2">
|
|
72
|
-
<div className={`flex items-center text-[11px] text-[var(--editor-text)]
|
|
72
|
+
<div className={`flex items-center text-[11px] text-[color-mix(in_srgb,var(--editor-text)_70%,transparent)] ${label ? 'justify-between' : 'justify-end'}`}>
|
|
73
73
|
{label && <span>{label}</span>}
|
|
74
|
-
<span className="font-mono text-[10px] text-[var(--editor-text)]
|
|
74
|
+
<span className="font-mono text-[10px] text-[color-mix(in_srgb,var(--editor-text)_50%,transparent)]">
|
|
75
75
|
{value.toFixed(2)} ({volumeToDb(value)})
|
|
76
76
|
</span>
|
|
77
77
|
</div>
|
|
@@ -100,7 +100,7 @@ export default function VolumeControl({
|
|
|
100
100
|
className={`rounded-md border px-2 py-0.5 text-[11px] font-mono transition-colors focus:outline-none focus:ring-1 focus:ring-[var(--editor-accent)] ${
|
|
101
101
|
active
|
|
102
102
|
? 'border-[var(--editor-accent)] bg-[var(--editor-accent)] text-[var(--editor-accent-foreground)]'
|
|
103
|
-
: 'border-[var(--editor-border)] bg-[var(--editor-surface)] text-[var(--editor-text)]
|
|
103
|
+
: 'border-[var(--editor-border)] bg-[var(--editor-surface)] text-[color-mix(in_srgb,var(--editor-text)_70%,transparent)] hover:text-[var(--editor-text)] hover:border-[var(--editor-accent)]'
|
|
104
104
|
}`}
|
|
105
105
|
>
|
|
106
106
|
{Math.round(p * 100)}%
|
|
@@ -23,6 +23,8 @@ interface Options {
|
|
|
23
23
|
clock: PlaybackClock
|
|
24
24
|
selectedIds: string[]
|
|
25
25
|
selectedCaptionId: string | null
|
|
26
|
+
/** Transport state. Reported like selection: at once, on change. */
|
|
27
|
+
playing?: boolean
|
|
26
28
|
}
|
|
27
29
|
|
|
28
30
|
/**
|
|
@@ -36,12 +38,12 @@ interface Options {
|
|
|
36
38
|
* selection.
|
|
37
39
|
*/
|
|
38
40
|
export function useReportContext({
|
|
39
|
-
adapter, projectId, clock, selectedIds, selectedCaptionId,
|
|
41
|
+
adapter, projectId, clock, selectedIds, selectedCaptionId, playing = false,
|
|
40
42
|
}: Options): void {
|
|
41
43
|
// Kept in a ref so the interval effect never re-subscribes on a selection
|
|
42
44
|
// change — it always reads the latest values without depending on them.
|
|
43
|
-
const latest = useRef({ selectedIds, selectedCaptionId })
|
|
44
|
-
latest.current = { selectedIds, selectedCaptionId }
|
|
45
|
+
const latest = useRef({ selectedIds, selectedCaptionId, playing })
|
|
46
|
+
latest.current = { selectedIds, selectedCaptionId, playing }
|
|
45
47
|
|
|
46
48
|
const send = useRef<(ctx: EditorContext) => void>(() => {})
|
|
47
49
|
send.current = (ctx: EditorContext) => {
|
|
@@ -58,18 +60,19 @@ export function useReportContext({
|
|
|
58
60
|
playheadSec: clock.get(),
|
|
59
61
|
selectedIds: latest.current.selectedIds,
|
|
60
62
|
selectedCaptionId: latest.current.selectedCaptionId,
|
|
63
|
+
playing: latest.current.playing,
|
|
61
64
|
})
|
|
62
65
|
emit()
|
|
63
66
|
const id = setInterval(emit, REPORT_INTERVAL_MS)
|
|
64
67
|
return () => clearInterval(id)
|
|
65
68
|
}, [adapter, projectId, clock])
|
|
66
69
|
|
|
67
|
-
// Selection, immediately on change. Skips the mount emit
|
|
68
|
-
// against what the interval effect already sent.
|
|
70
|
+
// Selection and play/pause, immediately on change. Skips the mount emit
|
|
71
|
+
// above by comparing against what the interval effect already sent.
|
|
69
72
|
const mounted = useRef(false)
|
|
70
73
|
useEffect(() => {
|
|
71
74
|
if (!adapter.reportContext) return
|
|
72
75
|
if (!mounted.current) { mounted.current = true; return }
|
|
73
|
-
send.current({ playheadSec: clock.get(), selectedIds, selectedCaptionId })
|
|
74
|
-
}, [adapter, clock, selectedIds, selectedCaptionId])
|
|
76
|
+
send.current({ playheadSec: clock.get(), selectedIds, selectedCaptionId, playing })
|
|
77
|
+
}, [adapter, clock, selectedIds, selectedCaptionId, playing])
|
|
75
78
|
}
|