@pixerate/editor-react 0.59.0 → 0.61.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/dist/{chunk-SYTV33TW.js → chunk-OSOGA2OJ.js} +90 -18
- package/dist/chunk-OSOGA2OJ.js.map +1 -0
- package/dist/image-editor/index.cjs +77 -8
- package/dist/image-editor/index.cjs.map +1 -1
- package/dist/image-editor/index.d.cts +9 -3
- package/dist/image-editor/index.d.ts +9 -3
- package/dist/image-editor/index.js +1 -1
- package/dist/index.cjs +77 -8
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1 -1
- package/dist/video-editor/index.cjs +36 -0
- package/dist/video-editor/index.cjs.map +1 -1
- package/dist/video-editor/index.d.cts +1 -11
- package/dist/video-editor/index.d.ts +1 -11
- package/dist/video-editor/index.js +37 -1
- package/dist/video-editor/index.js.map +1 -1
- package/package.json +3 -3
- package/dist/chunk-SYTV33TW.js.map +0 -1
|
@@ -77,6 +77,7 @@ interface VideoTransportProps {
|
|
|
77
77
|
/**
|
|
78
78
|
* Play / pause, a frame back and forward, the playhead and total length as timecode, and the
|
|
79
79
|
* edits that work on the playhead and the selection: split, delete, ripple delete, undo and redo.
|
|
80
|
+
* When any asset has proxies, a preview-size control picks what the preview plays (a view setting).
|
|
80
81
|
*/
|
|
81
82
|
declare function VideoTransport({ controller, editable, className }: VideoTransportProps): React__default.JSX.Element;
|
|
82
83
|
|
|
@@ -92,17 +93,6 @@ interface VideoTimelineProps {
|
|
|
92
93
|
waveforms?: VideoWaveformMode;
|
|
93
94
|
className?: string;
|
|
94
95
|
}
|
|
95
|
-
/**
|
|
96
|
-
* The tracks of a `VideoEditorController` laid out in time: a ruler with markers (click or drag it
|
|
97
|
-
* to scrub), a playhead, and one row per track with its toggles (mute, hide, lock) and its clips.
|
|
98
|
-
* Click a clip to select it (Shift / Cmd to add or remove it), drag it to move it (onto another
|
|
99
|
-
* track of the same kind too; hold Alt to insert, pushing later material along on every sync-locked
|
|
100
|
-
* track, or Shift to overwrite what is underneath), drag an edge to trim it (Alt to ripple). Moves snap to clip edges,
|
|
101
|
-
* markers, the playhead and frames. Every edit is one undo step; refused edits show why.
|
|
102
|
-
*
|
|
103
|
-
* Keyboard (when focused): Space plays, ←/→ step a frame, S splits at the playhead, Delete removes
|
|
104
|
-
* the selection (Shift to ripple), Cmd/Ctrl+Z undoes, Shift+Cmd/Ctrl+Z redoes.
|
|
105
|
-
*/
|
|
106
96
|
declare function VideoTimeline({ controller, pxPerSecond, onPxPerSecondChange, editable, waveforms, className }: VideoTimelineProps): React__default.JSX.Element;
|
|
107
97
|
|
|
108
98
|
interface ClipInspectorProps {
|
|
@@ -145,7 +145,7 @@ function VideoScopes({ controller, scopes = VIDEO_SCOPE_KINDS, width = 256, heig
|
|
|
145
145
|
}
|
|
146
146
|
|
|
147
147
|
// src/video-editor/VideoTransport.tsx
|
|
148
|
-
import { formatVideoTimecode } from "@pixerate/editor/video-editor";
|
|
148
|
+
import { formatVideoTimecode, parseVideoPreviewScale, VIDEO_PREVIEW_SCALE_OPTIONS, videoProjectHasProxies } from "@pixerate/editor/video-editor";
|
|
149
149
|
import { Fragment, jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
150
150
|
var btn = "rounded border border-border px-2 py-0.5 text-xs disabled:opacity-40";
|
|
151
151
|
function VideoTransport({ controller, editable = true, className = "" }) {
|
|
@@ -161,6 +161,18 @@ function VideoTransport({ controller, editable = true, className = "" }) {
|
|
|
161
161
|
" / ",
|
|
162
162
|
formatVideoTimecode(duration, project.fps)
|
|
163
163
|
] }),
|
|
164
|
+
videoProjectHasProxies(project) && /* @__PURE__ */ jsx3(
|
|
165
|
+
"select",
|
|
166
|
+
{
|
|
167
|
+
className: "rounded border border-border bg-transparent px-1 py-0.5 text-xs",
|
|
168
|
+
value: String(state.previewScale),
|
|
169
|
+
onChange: (e) => controller.setPreviewScale(parseVideoPreviewScale(e.target.value)),
|
|
170
|
+
"aria-label": "Preview size",
|
|
171
|
+
title: "Play proxies in the preview (the export always uses the originals)",
|
|
172
|
+
"data-preview-scale": "",
|
|
173
|
+
children: VIDEO_PREVIEW_SCALE_OPTIONS.map((o) => /* @__PURE__ */ jsx3("option", { value: o.value, children: o.label }, o.value))
|
|
174
|
+
}
|
|
175
|
+
),
|
|
164
176
|
editable && /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
165
177
|
/* @__PURE__ */ jsx3("span", { className: "mx-1 h-4 w-px bg-border" }),
|
|
166
178
|
/* @__PURE__ */ jsx3("button", { type: "button", className: btn, onClick: () => controller.splitAtPlayhead(), disabled: !canEdit, title: "Split at the playhead (S)", "data-split": "", children: "Split" }),
|
|
@@ -220,6 +232,27 @@ function ClipWaveform({ controller, clip, asset, width, height }) {
|
|
|
220
232
|
return /* @__PURE__ */ jsx4("svg", { className: "pointer-events-none absolute inset-0", width, height, "aria-hidden": "true", "data-waveform": clip.id, children: /* @__PURE__ */ jsx4("path", { d, fill: "currentColor", fillOpacity: 0.45 }) });
|
|
221
233
|
}
|
|
222
234
|
var isField = (el) => el instanceof HTMLElement && /^(INPUT|TEXTAREA|SELECT)$/.test(el.tagName);
|
|
235
|
+
function useCachedRanges(controller, project, px) {
|
|
236
|
+
const [ranges, setRanges] = useState2([]);
|
|
237
|
+
useEffect4(() => {
|
|
238
|
+
const cache = controller.frameCache;
|
|
239
|
+
if (!cache) return setRanges([]);
|
|
240
|
+
let timer = null;
|
|
241
|
+
const read = () => {
|
|
242
|
+
timer = null;
|
|
243
|
+
setRanges(cache.cachedRanges(project, { step: 2e3 / px }));
|
|
244
|
+
};
|
|
245
|
+
read();
|
|
246
|
+
const off = cache.subscribe(() => {
|
|
247
|
+
timer ??= setTimeout(read, 250);
|
|
248
|
+
});
|
|
249
|
+
return () => {
|
|
250
|
+
off();
|
|
251
|
+
if (timer) clearTimeout(timer);
|
|
252
|
+
};
|
|
253
|
+
}, [controller, project, px]);
|
|
254
|
+
return ranges;
|
|
255
|
+
}
|
|
223
256
|
function VideoTimeline({ controller, pxPerSecond, onPxPerSecondChange, editable = true, waveforms = "audio", className = "" }) {
|
|
224
257
|
const state = useVideoEditorState(controller);
|
|
225
258
|
const { project, duration, time, selection, readOnly, error } = state;
|
|
@@ -235,6 +268,7 @@ function VideoTimeline({ controller, pxPerSecond, onPxPerSecondChange, editable
|
|
|
235
268
|
const span = Math.max(duration + 5e3, 1e4);
|
|
236
269
|
const width = msToPx(span);
|
|
237
270
|
const ticks = videoRulerTicks(span, px, project.fps);
|
|
271
|
+
const cached = useCachedRanges(controller, project, px);
|
|
238
272
|
const seekAt = (clientX) => {
|
|
239
273
|
const box = ruler.current.getBoundingClientRect();
|
|
240
274
|
controller.seek(Math.max(0, (clientX - box.left) * 1e3 / px));
|
|
@@ -396,6 +430,7 @@ function VideoTimeline({ controller, pxPerSecond, onPxPerSecondChange, editable
|
|
|
396
430
|
},
|
|
397
431
|
children: [
|
|
398
432
|
ticks.map((t) => /* @__PURE__ */ jsx4("div", { className: `absolute bottom-0 w-px ${t.major ? "h-2.5 bg-muted-foreground/70" : "h-1 bg-muted-foreground/40"}`, style: { left: t.x }, "data-tick": t.time, children: t.label && /* @__PURE__ */ jsx4("span", { className: "absolute -top-3.5 left-1 whitespace-nowrap tabular-nums", children: t.label }) }, t.time)),
|
|
433
|
+
cached.map((r) => /* @__PURE__ */ jsx4("div", { className: "pointer-events-none absolute bottom-0 h-[3px] bg-emerald-500/70", style: { left: msToPx(r.start), width: Math.max(1, msToPx(r.end - r.start)) }, title: "Frames cached: plays and scrubs without waiting", "data-cached-range": "" }, r.start)),
|
|
399
434
|
(project.markers ?? []).map((m) => /* @__PURE__ */ jsx4(
|
|
400
435
|
"div",
|
|
401
436
|
{
|
|
@@ -930,6 +965,7 @@ function MediaBin({ controller, editable = true, fileToUrl, probe = probeVideoMe
|
|
|
930
965
|
project.assets.length ? /* @__PURE__ */ jsx6("ul", { className: "flex flex-col gap-1", "aria-label": "Media assets", children: project.assets.map((asset) => /* @__PURE__ */ jsxs5("li", { className: "flex items-center gap-2 text-xs", "data-asset": asset.id, children: [
|
|
931
966
|
/* @__PURE__ */ jsx6("span", { className: "rounded bg-muted px-1 text-[10px] uppercase text-muted-foreground", "data-asset-kind": "", children: asset.kind }),
|
|
932
967
|
/* @__PURE__ */ jsx6("span", { className: "min-w-0 flex-1 truncate", title: asset.src, children: asset.name ?? asset.id }),
|
|
968
|
+
asset.proxies?.length ? /* @__PURE__ */ jsx6("span", { className: "rounded bg-muted px-1 text-[10px] text-muted-foreground", title: `Proxies: ${asset.proxies.map((p) => `${p.scale * 100}%`).join(", ")} (the preview can play these; exports use the original)`, "data-asset-proxies": "", children: "proxy" }) : null,
|
|
933
969
|
asset.duration !== void 0 && /* @__PURE__ */ jsx6("span", { className: "tabular-nums text-muted-foreground", children: formatVideoSeconds3(asset.duration) }),
|
|
934
970
|
editable && /* @__PURE__ */ jsx6("button", { type: "button", className: btn3, disabled: !canEdit, onClick: () => addToTimeline(asset), "data-add-to-timeline": "", children: "Add to timeline" })
|
|
935
971
|
] }, asset.id)) }) : /* @__PURE__ */ jsxs5("p", { className: "text-xs text-muted-foreground", children: [
|