@twick/video-editor 0.15.19 → 0.15.21
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/components/timeline/timeline-view.d.ts +14 -3
- package/dist/components/track/track-base.d.ts +4 -9
- package/dist/components/track/track-element.d.ts +14 -8
- package/dist/helpers/types.d.ts +1 -0
- package/dist/hooks/use-edge-auto-scroll.d.ts +12 -0
- package/dist/hooks/use-player-manager.d.ts +1 -0
- package/dist/hooks/use-timeline-manager.d.ts +16 -4
- package/dist/index.js +551 -79
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +552 -80
- package/dist/index.mjs.map +1 -1
- package/dist/utils/drop-target.d.ts +12 -0
- package/package.json +5 -5
package/dist/index.js
CHANGED
|
@@ -6857,8 +6857,8 @@ const DEFAULT_TEXT_PROPS = {
|
|
|
6857
6857
|
lineWidth: 0
|
|
6858
6858
|
};
|
|
6859
6859
|
const DEFAULT_CAPTION_PROPS = {
|
|
6860
|
-
/** Font family for caption elements */
|
|
6861
|
-
family: "
|
|
6860
|
+
/** Font family for caption elements (matches highlight_bg default) */
|
|
6861
|
+
family: "Bangers",
|
|
6862
6862
|
/** Font size in pixels */
|
|
6863
6863
|
size: 48,
|
|
6864
6864
|
/** Text fill color */
|
|
@@ -6902,7 +6902,13 @@ const ELEMENT_TYPES = {
|
|
|
6902
6902
|
/** Rectangle element type */
|
|
6903
6903
|
RECT: "rect",
|
|
6904
6904
|
/** Circle element type */
|
|
6905
|
-
CIRCLE: "circle"
|
|
6905
|
+
CIRCLE: "circle",
|
|
6906
|
+
/** Arrow annotation element type */
|
|
6907
|
+
ARROW: "arrow",
|
|
6908
|
+
/** Line annotation / shape element type */
|
|
6909
|
+
LINE: "line",
|
|
6910
|
+
/** Global / adjustment-layer style effect element */
|
|
6911
|
+
EFFECT: "effect"
|
|
6906
6912
|
};
|
|
6907
6913
|
const isBrowser$2 = typeof window !== "undefined";
|
|
6908
6914
|
const isCanvasSupported = isBrowser$2 && !!window.HTMLCanvasElement;
|
|
@@ -7646,40 +7652,44 @@ const addCaptionElement = ({
|
|
|
7646
7652
|
canvasMetadata,
|
|
7647
7653
|
lockAspectRatio = false
|
|
7648
7654
|
}) => {
|
|
7649
|
-
var _a, _b, _c, _d, _e2, _f, _g, _h2, _i2, _j, _k, _l, _m, _n2, _o2, _p, _q, _r2, _s2, _t2, _u, _v, _w, _x, _y, _z, _A, _B, _C, _D, _E, _F, _G, _H, _I, _J;
|
|
7655
|
+
var _a, _b, _c, _d, _e2, _f, _g, _h2, _i2, _j, _k, _l, _m, _n2, _o2, _p, _q, _r2, _s2, _t2, _u, _v, _w, _x, _y, _z, _A, _B, _C, _D, _E, _F, _G, _H, _I, _J, _K, _L;
|
|
7656
|
+
const applyToAll = (captionProps == null ? void 0 : captionProps.applyToAll) ?? false;
|
|
7657
|
+
const captionTextColor = ((_a = captionProps == null ? void 0 : captionProps.colors) == null ? void 0 : _a.text) ?? ((_b = captionProps == null ? void 0 : captionProps.color) == null ? void 0 : _b.text);
|
|
7650
7658
|
const { x: x2, y: y2 } = convertToCanvasPosition(
|
|
7651
|
-
(
|
|
7652
|
-
(
|
|
7659
|
+
(applyToAll ? captionProps == null ? void 0 : captionProps.x : ((_c = element.props) == null ? void 0 : _c.x) ?? (captionProps == null ? void 0 : captionProps.x)) ?? 0,
|
|
7660
|
+
(applyToAll ? captionProps == null ? void 0 : captionProps.y : ((_d = element.props) == null ? void 0 : _d.y) ?? (captionProps == null ? void 0 : captionProps.y)) ?? 0,
|
|
7653
7661
|
canvasMetadata
|
|
7654
7662
|
);
|
|
7655
|
-
let width = ((
|
|
7656
|
-
if ((
|
|
7663
|
+
let width = ((_e2 = element.props) == null ? void 0 : _e2.width) ? element.props.width * canvasMetadata.scaleX : canvasMetadata.width - 2 * MARGIN;
|
|
7664
|
+
if ((_f = element.props) == null ? void 0 : _f.maxWidth) {
|
|
7657
7665
|
width = Math.min(width, element.props.maxWidth * canvasMetadata.scaleX);
|
|
7658
7666
|
}
|
|
7659
|
-
const
|
|
7667
|
+
const elementColors = (_g = element.props) == null ? void 0 : _g.colors;
|
|
7668
|
+
const resolvedFill = (applyToAll ? captionTextColor : ((_h2 = element.props) == null ? void 0 : _h2.fill) ?? (elementColors == null ? void 0 : elementColors.text) ?? captionTextColor) ?? DEFAULT_CAPTION_PROPS.fill;
|
|
7669
|
+
const caption = new Uo(((_i2 = element.props) == null ? void 0 : _i2.text) || element.t || "", {
|
|
7660
7670
|
left: x2,
|
|
7661
7671
|
top: y2,
|
|
7662
7672
|
originX: "center",
|
|
7663
7673
|
originY: "center",
|
|
7664
|
-
angle: ((
|
|
7674
|
+
angle: ((_j = element.props) == null ? void 0 : _j.rotation) || 0,
|
|
7665
7675
|
fontSize: Math.round(
|
|
7666
|
-
((
|
|
7676
|
+
((applyToAll ? (_k = captionProps == null ? void 0 : captionProps.font) == null ? void 0 : _k.size : ((_m = (_l = element.props) == null ? void 0 : _l.font) == null ? void 0 : _m.size) ?? ((_n2 = captionProps == null ? void 0 : captionProps.font) == null ? void 0 : _n2.size)) ?? DEFAULT_CAPTION_PROPS.size) * canvasMetadata.scaleX
|
|
7667
7677
|
),
|
|
7668
|
-
fontFamily: (
|
|
7669
|
-
fill:
|
|
7670
|
-
fontWeight: (
|
|
7671
|
-
stroke: (
|
|
7672
|
-
opacity: (
|
|
7678
|
+
fontFamily: (applyToAll ? (_o2 = captionProps == null ? void 0 : captionProps.font) == null ? void 0 : _o2.family : ((_q = (_p = element.props) == null ? void 0 : _p.font) == null ? void 0 : _q.family) ?? ((_r2 = captionProps == null ? void 0 : captionProps.font) == null ? void 0 : _r2.family)) ?? DEFAULT_CAPTION_PROPS.family,
|
|
7679
|
+
fill: resolvedFill,
|
|
7680
|
+
fontWeight: (applyToAll ? (_s2 = captionProps == null ? void 0 : captionProps.font) == null ? void 0 : _s2.weight : ((_u = (_t2 = element.props) == null ? void 0 : _t2.font) == null ? void 0 : _u.weight) ?? ((_v = captionProps == null ? void 0 : captionProps.font) == null ? void 0 : _v.weight)) ?? DEFAULT_CAPTION_PROPS.fontWeight,
|
|
7681
|
+
stroke: (applyToAll ? captionProps == null ? void 0 : captionProps.stroke : ((_w = element.props) == null ? void 0 : _w.stroke) ?? (captionProps == null ? void 0 : captionProps.stroke)) ?? DEFAULT_CAPTION_PROPS.stroke,
|
|
7682
|
+
opacity: (applyToAll ? captionProps == null ? void 0 : captionProps.opacity : ((_x = element.props) == null ? void 0 : _x.opacity) ?? (captionProps == null ? void 0 : captionProps.opacity)) ?? 1,
|
|
7673
7683
|
width,
|
|
7674
7684
|
splitByGrapheme: false,
|
|
7675
|
-
textAlign: ((
|
|
7685
|
+
textAlign: ((_y = element.props) == null ? void 0 : _y.textAlign) ?? "center",
|
|
7676
7686
|
shadow: new Ds({
|
|
7677
|
-
offsetX: (
|
|
7678
|
-
offsetY: (
|
|
7679
|
-
blur: (
|
|
7680
|
-
color: (
|
|
7687
|
+
offsetX: (applyToAll ? (_z = captionProps == null ? void 0 : captionProps.shadowOffset) == null ? void 0 : _z[0] : ((_B = (_A = element.props) == null ? void 0 : _A.shadowOffset) == null ? void 0 : _B[0]) ?? ((_C = captionProps == null ? void 0 : captionProps.shadowOffset) == null ? void 0 : _C[0])) ?? ((_D = DEFAULT_CAPTION_PROPS.shadowOffset) == null ? void 0 : _D[0]),
|
|
7688
|
+
offsetY: (applyToAll ? (_E = captionProps == null ? void 0 : captionProps.shadowOffset) == null ? void 0 : _E[1] : ((_G = (_F = element.props) == null ? void 0 : _F.shadowOffset) == null ? void 0 : _G[1]) ?? ((_H = captionProps == null ? void 0 : captionProps.shadowOffset) == null ? void 0 : _H[1])) ?? ((_I = DEFAULT_CAPTION_PROPS.shadowOffset) == null ? void 0 : _I[1]),
|
|
7689
|
+
blur: (applyToAll ? captionProps == null ? void 0 : captionProps.shadowBlur : ((_J = element.props) == null ? void 0 : _J.shadowBlur) ?? (captionProps == null ? void 0 : captionProps.shadowBlur)) ?? DEFAULT_CAPTION_PROPS.shadowBlur,
|
|
7690
|
+
color: (applyToAll ? captionProps == null ? void 0 : captionProps.shadowColor : ((_K = element.props) == null ? void 0 : _K.shadowColor) ?? (captionProps == null ? void 0 : captionProps.shadowColor)) ?? DEFAULT_CAPTION_PROPS.shadowColor
|
|
7681
7691
|
}),
|
|
7682
|
-
strokeWidth: (
|
|
7692
|
+
strokeWidth: (applyToAll ? captionProps == null ? void 0 : captionProps.lineWidth : ((_L = element.props) == null ? void 0 : _L.lineWidth) ?? (captionProps == null ? void 0 : captionProps.lineWidth)) ?? DEFAULT_CAPTION_PROPS.lineWidth
|
|
7683
7693
|
});
|
|
7684
7694
|
caption.set("id", element.id);
|
|
7685
7695
|
caption.set("zIndex", index);
|
|
@@ -8390,6 +8400,148 @@ const WatermarkElement = {
|
|
|
8390
8400
|
};
|
|
8391
8401
|
}
|
|
8392
8402
|
};
|
|
8403
|
+
const ArrowElement = {
|
|
8404
|
+
name: ELEMENT_TYPES.ARROW,
|
|
8405
|
+
async add(params) {
|
|
8406
|
+
var _a, _b, _c, _d, _e2, _f, _g, _h2, _i2;
|
|
8407
|
+
const { element, index, canvas, canvasMetadata, lockAspectRatio } = params;
|
|
8408
|
+
const baseWidth = ((_a = element.props) == null ? void 0 : _a.width) ?? 220;
|
|
8409
|
+
const baseHeight = ((_b = element.props) == null ? void 0 : _b.height) ?? 14;
|
|
8410
|
+
const { x: x2, y: y2 } = convertToCanvasPosition(
|
|
8411
|
+
((_c = element.props) == null ? void 0 : _c.x) ?? 0,
|
|
8412
|
+
((_d = element.props) == null ? void 0 : _d.y) ?? 0,
|
|
8413
|
+
canvasMetadata
|
|
8414
|
+
);
|
|
8415
|
+
const fill = ((_e2 = element.props) == null ? void 0 : _e2.fill) || "#f59e0b";
|
|
8416
|
+
const radius = (((_f = element.props) == null ? void 0 : _f.radius) ?? 4) * canvasMetadata.scaleX;
|
|
8417
|
+
const barWidth = baseWidth * canvasMetadata.scaleX;
|
|
8418
|
+
const barHeight = baseHeight * canvasMetadata.scaleY;
|
|
8419
|
+
const headSize = barHeight * 1.8;
|
|
8420
|
+
const barLength = barWidth - headSize * 0.5;
|
|
8421
|
+
const bar = new jr({
|
|
8422
|
+
left: -barWidth / 2,
|
|
8423
|
+
top: -barHeight / 2,
|
|
8424
|
+
originX: "left",
|
|
8425
|
+
originY: "top",
|
|
8426
|
+
width: barLength,
|
|
8427
|
+
height: barHeight,
|
|
8428
|
+
rx: radius,
|
|
8429
|
+
ry: radius,
|
|
8430
|
+
fill
|
|
8431
|
+
});
|
|
8432
|
+
const arrowHead = new yo({
|
|
8433
|
+
left: barWidth / 2 - headSize * 0.25,
|
|
8434
|
+
top: 0,
|
|
8435
|
+
originX: "center",
|
|
8436
|
+
originY: "center",
|
|
8437
|
+
width: headSize,
|
|
8438
|
+
height: headSize,
|
|
8439
|
+
fill,
|
|
8440
|
+
angle: 90
|
|
8441
|
+
});
|
|
8442
|
+
const opacity = ((_g = element.props) == null ? void 0 : _g.opacity) ?? 1;
|
|
8443
|
+
const group = new Ur([bar, arrowHead], {
|
|
8444
|
+
left: x2,
|
|
8445
|
+
top: y2,
|
|
8446
|
+
originX: "center",
|
|
8447
|
+
originY: "center",
|
|
8448
|
+
angle: ((_h2 = element.props) == null ? void 0 : _h2.rotation) || 0,
|
|
8449
|
+
opacity,
|
|
8450
|
+
selectable: true,
|
|
8451
|
+
hasControls: true
|
|
8452
|
+
});
|
|
8453
|
+
group.set(
|
|
8454
|
+
"lockUniScaling",
|
|
8455
|
+
lockAspectRatio ?? ((_i2 = element.props) == null ? void 0 : _i2.lockAspectRatio) ?? true
|
|
8456
|
+
);
|
|
8457
|
+
group.set("id", element.id);
|
|
8458
|
+
group.set("zIndex", index);
|
|
8459
|
+
canvas.add(group);
|
|
8460
|
+
},
|
|
8461
|
+
updateFromFabricObject(object, element, context) {
|
|
8462
|
+
var _a, _b, _c;
|
|
8463
|
+
const canvasCenter = getObjectCanvasCenter(object);
|
|
8464
|
+
const { x: x2, y: y2 } = convertToVideoPosition(
|
|
8465
|
+
canvasCenter.x,
|
|
8466
|
+
canvasCenter.y,
|
|
8467
|
+
context.canvasMetadata,
|
|
8468
|
+
context.videoSize
|
|
8469
|
+
);
|
|
8470
|
+
const baseWidth = ((_a = element.props) == null ? void 0 : _a.width) ?? 220;
|
|
8471
|
+
const baseHeight = ((_b = element.props) == null ? void 0 : _b.height) ?? 14;
|
|
8472
|
+
const opacity = object.opacity ?? ((_c = element.props) == null ? void 0 : _c.opacity) ?? 1;
|
|
8473
|
+
return {
|
|
8474
|
+
element: {
|
|
8475
|
+
...element,
|
|
8476
|
+
props: {
|
|
8477
|
+
...element.props,
|
|
8478
|
+
rotation: getObjectCanvasAngle(object),
|
|
8479
|
+
width: baseWidth * object.scaleX,
|
|
8480
|
+
height: baseHeight * object.scaleY,
|
|
8481
|
+
x: x2,
|
|
8482
|
+
y: y2,
|
|
8483
|
+
opacity
|
|
8484
|
+
}
|
|
8485
|
+
}
|
|
8486
|
+
};
|
|
8487
|
+
}
|
|
8488
|
+
};
|
|
8489
|
+
const LineElement = {
|
|
8490
|
+
name: ELEMENT_TYPES.LINE,
|
|
8491
|
+
async add(params) {
|
|
8492
|
+
var _a;
|
|
8493
|
+
const { element, index, canvas, canvasMetadata, lockAspectRatio } = params;
|
|
8494
|
+
const lineProps = element.props ?? {};
|
|
8495
|
+
const lineElement = {
|
|
8496
|
+
...element,
|
|
8497
|
+
props: {
|
|
8498
|
+
...lineProps,
|
|
8499
|
+
// Use fill as stroke color when a stroke is desired; otherwise rely
|
|
8500
|
+
// on fill-only rendering. Avoid the generic "#000000" fallback.
|
|
8501
|
+
stroke: lineProps.stroke ?? lineProps.fill,
|
|
8502
|
+
// If a specific lineWidth is provided, keep it; otherwise default to 0
|
|
8503
|
+
// so the stroke does not override the visual fill color.
|
|
8504
|
+
lineWidth: lineProps.lineWidth ?? 0
|
|
8505
|
+
}
|
|
8506
|
+
};
|
|
8507
|
+
await addRectElement({
|
|
8508
|
+
element: lineElement,
|
|
8509
|
+
index,
|
|
8510
|
+
canvas,
|
|
8511
|
+
canvasMetadata,
|
|
8512
|
+
lockAspectRatio: lockAspectRatio ?? ((_a = lineElement.props) == null ? void 0 : _a.lockAspectRatio)
|
|
8513
|
+
});
|
|
8514
|
+
},
|
|
8515
|
+
updateFromFabricObject(object, element, context) {
|
|
8516
|
+
var _a, _b;
|
|
8517
|
+
const canvasCenter = getObjectCanvasCenter(object);
|
|
8518
|
+
const { x: x2, y: y2 } = convertToVideoPosition(
|
|
8519
|
+
canvasCenter.x,
|
|
8520
|
+
canvasCenter.y,
|
|
8521
|
+
context.canvasMetadata,
|
|
8522
|
+
context.videoSize
|
|
8523
|
+
);
|
|
8524
|
+
return {
|
|
8525
|
+
element: {
|
|
8526
|
+
...element,
|
|
8527
|
+
props: {
|
|
8528
|
+
...element.props,
|
|
8529
|
+
rotation: getObjectCanvasAngle(object),
|
|
8530
|
+
width: (((_a = element.props) == null ? void 0 : _a.width) ?? 0) * object.scaleX,
|
|
8531
|
+
height: (((_b = element.props) == null ? void 0 : _b.height) ?? 0) * object.scaleY,
|
|
8532
|
+
x: x2,
|
|
8533
|
+
y: y2
|
|
8534
|
+
}
|
|
8535
|
+
}
|
|
8536
|
+
};
|
|
8537
|
+
}
|
|
8538
|
+
};
|
|
8539
|
+
const EffectElement = {
|
|
8540
|
+
name: ELEMENT_TYPES.EFFECT,
|
|
8541
|
+
async add() {
|
|
8542
|
+
return;
|
|
8543
|
+
}
|
|
8544
|
+
};
|
|
8393
8545
|
class ElementController {
|
|
8394
8546
|
constructor() {
|
|
8395
8547
|
__publicField2(this, "elements", /* @__PURE__ */ new Map());
|
|
@@ -8413,6 +8565,9 @@ function registerElements() {
|
|
|
8413
8565
|
elementController.register(TextElement);
|
|
8414
8566
|
elementController.register(CaptionElement);
|
|
8415
8567
|
elementController.register(WatermarkElement);
|
|
8568
|
+
elementController.register(ArrowElement);
|
|
8569
|
+
elementController.register(LineElement);
|
|
8570
|
+
elementController.register(EffectElement);
|
|
8416
8571
|
}
|
|
8417
8572
|
registerElements();
|
|
8418
8573
|
const useTwickCanvas = ({
|
|
@@ -8767,10 +8922,18 @@ const useTwickCanvas = ({
|
|
|
8767
8922
|
const sendToBack = (elementId) => applyZOrder(elementId, "back");
|
|
8768
8923
|
const bringForward = (elementId) => applyZOrder(elementId, "forward");
|
|
8769
8924
|
const sendBackward = (elementId) => applyZOrder(elementId, "backward");
|
|
8925
|
+
const setBackgroundColor = React.useCallback((color2) => {
|
|
8926
|
+
const canvas = twickCanvasRef.current;
|
|
8927
|
+
if (canvas) {
|
|
8928
|
+
canvas.backgroundColor = color2;
|
|
8929
|
+
canvas.requestRenderAll();
|
|
8930
|
+
}
|
|
8931
|
+
}, []);
|
|
8770
8932
|
return {
|
|
8771
8933
|
twickCanvas,
|
|
8772
8934
|
buildCanvas,
|
|
8773
8935
|
resizeCanvas,
|
|
8936
|
+
setBackgroundColor,
|
|
8774
8937
|
onVideoSizeChange,
|
|
8775
8938
|
addWatermarkToCanvas,
|
|
8776
8939
|
addElementToCanvas,
|
|
@@ -8985,7 +9148,9 @@ const DEFAULT_ELEMENT_COLORS = {
|
|
|
8985
9148
|
/** Icon element color - bright orchid */
|
|
8986
9149
|
icon: "#A76CD4",
|
|
8987
9150
|
/** Circle element color - deep byzantium */
|
|
8988
|
-
circle: "#703D8B"
|
|
9151
|
+
circle: "#703D8B",
|
|
9152
|
+
/** Effect element color - cyan accent for global effects */
|
|
9153
|
+
effect: "#22C3EE"
|
|
8989
9154
|
};
|
|
8990
9155
|
const AVAILABLE_TEXT_FONTS = {
|
|
8991
9156
|
// Google Fonts
|
|
@@ -9292,6 +9457,7 @@ const usePlayerManager = ({
|
|
|
9292
9457
|
twickCanvas,
|
|
9293
9458
|
buildCanvas,
|
|
9294
9459
|
resizeCanvas,
|
|
9460
|
+
setBackgroundColor,
|
|
9295
9461
|
setCanvasElements,
|
|
9296
9462
|
bringToFront,
|
|
9297
9463
|
sendToBack,
|
|
@@ -9368,7 +9534,7 @@ const usePlayerManager = ({
|
|
|
9368
9534
|
}
|
|
9369
9535
|
};
|
|
9370
9536
|
React.useEffect(() => {
|
|
9371
|
-
var _a, _b, _c, _d, _e2;
|
|
9537
|
+
var _a, _b, _c, _d, _e2, _f;
|
|
9372
9538
|
switch (timelineAction.type) {
|
|
9373
9539
|
case timeline.TIMELINE_ACTION.UPDATE_PLAYER_DATA:
|
|
9374
9540
|
if (videoProps) {
|
|
@@ -9378,11 +9544,12 @@ const usePlayerManager = ({
|
|
|
9378
9544
|
input: {
|
|
9379
9545
|
properties: videoProps,
|
|
9380
9546
|
tracks: ((_c = timelineAction.payload) == null ? void 0 : _c.tracks) ?? [],
|
|
9381
|
-
version: ((_d = timelineAction.payload) == null ? void 0 : _d.version) ?? 0
|
|
9547
|
+
version: ((_d = timelineAction.payload) == null ? void 0 : _d.version) ?? 0,
|
|
9548
|
+
backgroundColor: ((_e2 = timelineAction.payload) == null ? void 0 : _e2.backgroundColor) ?? "#000000"
|
|
9382
9549
|
}
|
|
9383
9550
|
};
|
|
9384
9551
|
setProjectData(_latestProjectData);
|
|
9385
|
-
if (((
|
|
9552
|
+
if (((_f = timelineAction.payload) == null ? void 0 : _f.version) === 1) {
|
|
9386
9553
|
setTimeout(() => {
|
|
9387
9554
|
setPlayerUpdating(false);
|
|
9388
9555
|
});
|
|
@@ -9400,6 +9567,7 @@ const usePlayerManager = ({
|
|
|
9400
9567
|
updateCanvas,
|
|
9401
9568
|
buildCanvas,
|
|
9402
9569
|
resizeCanvas,
|
|
9570
|
+
setBackgroundColor,
|
|
9403
9571
|
onPlayerUpdate,
|
|
9404
9572
|
playerUpdating,
|
|
9405
9573
|
handleDropOnCanvas,
|
|
@@ -9636,6 +9804,7 @@ const PlayerManager = ({
|
|
|
9636
9804
|
canvasMode,
|
|
9637
9805
|
canvasConfig
|
|
9638
9806
|
}) => {
|
|
9807
|
+
var _a;
|
|
9639
9808
|
const containerRef = React.useRef(null);
|
|
9640
9809
|
const canvasRef = React.useRef(null);
|
|
9641
9810
|
const durationRef = React.useRef(0);
|
|
@@ -9653,6 +9822,7 @@ const PlayerManager = ({
|
|
|
9653
9822
|
projectData,
|
|
9654
9823
|
updateCanvas,
|
|
9655
9824
|
resizeCanvas,
|
|
9825
|
+
setBackgroundColor,
|
|
9656
9826
|
playerUpdating,
|
|
9657
9827
|
onPlayerUpdate,
|
|
9658
9828
|
buildCanvas,
|
|
@@ -9672,6 +9842,7 @@ const PlayerManager = ({
|
|
|
9672
9842
|
enabled: !!handleDropOnCanvas && canvasMode
|
|
9673
9843
|
});
|
|
9674
9844
|
React.useEffect(() => {
|
|
9845
|
+
var _a2;
|
|
9675
9846
|
const container = containerRef.current;
|
|
9676
9847
|
const canvasSize = {
|
|
9677
9848
|
width: (container == null ? void 0 : container.clientWidth) ?? 0,
|
|
@@ -9679,7 +9850,7 @@ const PlayerManager = ({
|
|
|
9679
9850
|
};
|
|
9680
9851
|
if (canvasSize.width > 0 && canvasSize.height > 0) {
|
|
9681
9852
|
buildCanvas({
|
|
9682
|
-
backgroundColor: videoProps.backgroundColor,
|
|
9853
|
+
backgroundColor: videoProps.backgroundColor ?? ((_a2 = projectData == null ? void 0 : projectData.input) == null ? void 0 : _a2.backgroundColor) ?? "#000000",
|
|
9683
9854
|
videoSize: {
|
|
9684
9855
|
width: videoProps.width,
|
|
9685
9856
|
height: videoProps.height
|
|
@@ -9689,6 +9860,11 @@ const PlayerManager = ({
|
|
|
9689
9860
|
});
|
|
9690
9861
|
}
|
|
9691
9862
|
}, [videoProps]);
|
|
9863
|
+
React.useEffect(() => {
|
|
9864
|
+
var _a2;
|
|
9865
|
+
const color2 = ((_a2 = projectData == null ? void 0 : projectData.input) == null ? void 0 : _a2.backgroundColor) ?? videoProps.backgroundColor ?? "#000000";
|
|
9866
|
+
setBackgroundColor(color2);
|
|
9867
|
+
}, [(_a = projectData == null ? void 0 : projectData.input) == null ? void 0 : _a.backgroundColor, videoProps.backgroundColor, setBackgroundColor]);
|
|
9692
9868
|
const handleResize = React.useMemo(
|
|
9693
9869
|
() => throttle(() => {
|
|
9694
9870
|
const container = containerRef.current;
|
|
@@ -9720,10 +9896,10 @@ const PlayerManager = ({
|
|
|
9720
9896
|
React.useEffect(() => {
|
|
9721
9897
|
if (!twickCanvas || !canvasMode) return;
|
|
9722
9898
|
const onSelectionCreated = (e3) => {
|
|
9723
|
-
var
|
|
9899
|
+
var _a2, _b;
|
|
9724
9900
|
const ev = e3 == null ? void 0 : e3.e;
|
|
9725
9901
|
if (!ev) return;
|
|
9726
|
-
const id2 = (_b = (
|
|
9902
|
+
const id2 = (_b = (_a2 = e3.target) == null ? void 0 : _a2.get) == null ? void 0 : _b.call(_a2, "id");
|
|
9727
9903
|
if (id2) {
|
|
9728
9904
|
setContextMenu({ x: ev.clientX, y: ev.clientY, elementId: id2 });
|
|
9729
9905
|
}
|
|
@@ -11156,13 +11332,25 @@ function SeekTrack({
|
|
|
11156
11332
|
const containerRef = React.useRef(null);
|
|
11157
11333
|
const [isDragging2, setIsDragging] = React.useState(false);
|
|
11158
11334
|
const [dragPosition, setDragPosition] = React.useState(null);
|
|
11335
|
+
const [pendingSeekTime, setPendingSeekTime] = React.useState(null);
|
|
11159
11336
|
const pixelsPerSecond = 100 * zoom;
|
|
11160
11337
|
const totalWidth = duration * pixelsPerSecond;
|
|
11161
11338
|
const pinHeight = 2 + timelineCount * (2.75 + 0.5);
|
|
11339
|
+
React.useEffect(() => {
|
|
11340
|
+
if (pendingSeekTime === null) return;
|
|
11341
|
+
if (Math.abs(currentTime - pendingSeekTime) < 0.05) {
|
|
11342
|
+
setPendingSeekTime(null);
|
|
11343
|
+
}
|
|
11344
|
+
}, [currentTime, pendingSeekTime]);
|
|
11162
11345
|
const seekPosition = React.useMemo(() => {
|
|
11163
|
-
|
|
11164
|
-
|
|
11165
|
-
|
|
11346
|
+
if (isDragging2 && dragPosition !== null) {
|
|
11347
|
+
return Math.max(0, dragPosition);
|
|
11348
|
+
}
|
|
11349
|
+
if (pendingSeekTime !== null) {
|
|
11350
|
+
return Math.max(0, pendingSeekTime * pixelsPerSecond);
|
|
11351
|
+
}
|
|
11352
|
+
return Math.max(0, currentTime * pixelsPerSecond);
|
|
11353
|
+
}, [isDragging2, dragPosition, currentTime, pendingSeekTime, pixelsPerSecond]);
|
|
11166
11354
|
React.useEffect(() => {
|
|
11167
11355
|
onPlayheadUpdate == null ? void 0 : onPlayheadUpdate({
|
|
11168
11356
|
positionPx: seekPosition,
|
|
@@ -11251,6 +11439,7 @@ function SeekTrack({
|
|
|
11251
11439
|
setDragPosition(xPos);
|
|
11252
11440
|
} else {
|
|
11253
11441
|
setDragPosition(null);
|
|
11442
|
+
setPendingSeekTime(newTime);
|
|
11254
11443
|
seekToTime(newTime);
|
|
11255
11444
|
}
|
|
11256
11445
|
});
|
|
@@ -18849,8 +19038,10 @@ const TrackElementView = ({
|
|
|
18849
19038
|
onSelection,
|
|
18850
19039
|
onDrag,
|
|
18851
19040
|
allowOverlap = false,
|
|
19041
|
+
onDragStateChange,
|
|
18852
19042
|
elementColors
|
|
18853
19043
|
}) => {
|
|
19044
|
+
var _a, _b;
|
|
18854
19045
|
const ref = React.useRef(null);
|
|
18855
19046
|
const dragType = React.useRef(null);
|
|
18856
19047
|
const lastPosRef = React.useRef(null);
|
|
@@ -18868,7 +19059,10 @@ const TrackElementView = ({
|
|
|
18868
19059
|
const bind = useDrag(({ delta: [dx] }) => {
|
|
18869
19060
|
if (!parentWidth) return;
|
|
18870
19061
|
if (dx == 0) return;
|
|
18871
|
-
|
|
19062
|
+
if (!isDragging2) {
|
|
19063
|
+
setIsDragging(true);
|
|
19064
|
+
onDragStateChange == null ? void 0 : onDragStateChange(true, element);
|
|
19065
|
+
}
|
|
18872
19066
|
dragType.current = DRAG_TYPE.MOVE;
|
|
18873
19067
|
setPosition((prev) => {
|
|
18874
19068
|
const span = prev.end - prev.start;
|
|
@@ -18894,6 +19088,7 @@ const TrackElementView = ({
|
|
|
18894
19088
|
if (dx === 0) return;
|
|
18895
19089
|
if (isDragging2) {
|
|
18896
19090
|
setIsDragging(false);
|
|
19091
|
+
onDragStateChange == null ? void 0 : onDragStateChange(false, element);
|
|
18897
19092
|
}
|
|
18898
19093
|
dragType.current = DRAG_TYPE.START;
|
|
18899
19094
|
setPosition((prev) => {
|
|
@@ -18915,6 +19110,7 @@ const TrackElementView = ({
|
|
|
18915
19110
|
if (dx === 0) return;
|
|
18916
19111
|
if (isDragging2) {
|
|
18917
19112
|
setIsDragging(false);
|
|
19113
|
+
onDragStateChange == null ? void 0 : onDragStateChange(false, element);
|
|
18918
19114
|
}
|
|
18919
19115
|
dragType.current = DRAG_TYPE.END;
|
|
18920
19116
|
setPosition((prev) => {
|
|
@@ -18934,24 +19130,37 @@ const TrackElementView = ({
|
|
|
18934
19130
|
const setLastPos = () => {
|
|
18935
19131
|
lastPosRef.current = position;
|
|
18936
19132
|
};
|
|
18937
|
-
const sendUpdate = () => {
|
|
18938
|
-
var
|
|
19133
|
+
const sendUpdate = (e3) => {
|
|
19134
|
+
var _a2, _b2, _c;
|
|
19135
|
+
let dropPointer;
|
|
19136
|
+
if (e3) {
|
|
19137
|
+
if ("clientX" in e3) {
|
|
19138
|
+
dropPointer = { clientX: e3.clientX, clientY: e3.clientY };
|
|
19139
|
+
} else if ("changedTouches" in e3 && ((_a2 = e3.changedTouches) == null ? void 0 : _a2[0])) {
|
|
19140
|
+
const t2 = e3.changedTouches[0];
|
|
19141
|
+
dropPointer = { clientX: t2.clientX, clientY: t2.clientY };
|
|
19142
|
+
}
|
|
19143
|
+
}
|
|
18939
19144
|
setIsDragging(false);
|
|
18940
|
-
|
|
18941
|
-
|
|
18942
|
-
|
|
18943
|
-
|
|
18944
|
-
|
|
18945
|
-
|
|
18946
|
-
|
|
18947
|
-
|
|
18948
|
-
|
|
19145
|
+
onDragStateChange == null ? void 0 : onDragStateChange(false, element);
|
|
19146
|
+
const payload = {
|
|
19147
|
+
element,
|
|
19148
|
+
updates: {
|
|
19149
|
+
start: timeline.getDecimalNumber(position.start),
|
|
19150
|
+
end: timeline.getDecimalNumber(position.end)
|
|
19151
|
+
},
|
|
19152
|
+
dragType: dragType.current || ""
|
|
19153
|
+
};
|
|
19154
|
+
const didChange = ((_b2 = lastPosRef.current) == null ? void 0 : _b2.start) !== position.start || ((_c = lastPosRef.current) == null ? void 0 : _c.end) !== position.end;
|
|
19155
|
+
if (didChange || dropPointer) {
|
|
19156
|
+
onDrag(payload, dropPointer);
|
|
18949
19157
|
}
|
|
18950
19158
|
};
|
|
18951
19159
|
const getElementColor = (elementType) => {
|
|
18952
19160
|
const colors = elementColors || ELEMENT_COLORS;
|
|
18953
|
-
|
|
18954
|
-
|
|
19161
|
+
const key = elementType === timeline.TIMELINE_ELEMENT_TYPE.VIDEO ? "video" : elementType === timeline.TIMELINE_ELEMENT_TYPE.AUDIO ? "audio" : elementType === timeline.TIMELINE_ELEMENT_TYPE.IMAGE ? "image" : elementType === timeline.TIMELINE_ELEMENT_TYPE.TEXT ? "text" : elementType === timeline.TIMELINE_ELEMENT_TYPE.CAPTION ? "caption" : elementType === timeline.TIMELINE_ELEMENT_TYPE.RECT ? "rect" : elementType === timeline.TIMELINE_ELEMENT_TYPE.CIRCLE ? "circle" : elementType === timeline.TIMELINE_ELEMENT_TYPE.ICON ? "icon" : elementType === timeline.TIMELINE_ELEMENT_TYPE.EFFECT ? "effect" : "element";
|
|
19162
|
+
if (key in colors) {
|
|
19163
|
+
return colors[key];
|
|
18955
19164
|
}
|
|
18956
19165
|
return ELEMENT_COLORS.element;
|
|
18957
19166
|
};
|
|
@@ -18972,8 +19181,8 @@ const TrackElementView = ({
|
|
|
18972
19181
|
setLastPos();
|
|
18973
19182
|
}
|
|
18974
19183
|
},
|
|
18975
|
-
onMouseUp: sendUpdate,
|
|
18976
|
-
onTouchEnd: sendUpdate,
|
|
19184
|
+
onMouseUp: (e3) => sendUpdate(e3),
|
|
19185
|
+
onTouchEnd: (e3) => sendUpdate(e3),
|
|
18977
19186
|
onClick: (e3) => {
|
|
18978
19187
|
if (onSelection) {
|
|
18979
19188
|
onSelection(element, e3);
|
|
@@ -18995,7 +19204,7 @@ const TrackElementView = ({
|
|
|
18995
19204
|
className: "twick-track-element-handle twick-track-element-handle-start"
|
|
18996
19205
|
}
|
|
18997
19206
|
) : null,
|
|
18998
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "twick-track-element-content", children: element.getText ? element.getText() : element.getName() || element.getType() }),
|
|
19207
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "twick-track-element-content", children: element.getType() === timeline.TIMELINE_ELEMENT_TYPE.EFFECT ? ((_b = (_a = element.getProps) == null ? void 0 : _a.call(element)) == null ? void 0 : _b.effectKey) ?? "Effect" : element.getText ? element.getText() : element.getName() || element.getType() }),
|
|
18999
19208
|
hasHandles ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
19000
19209
|
"div",
|
|
19001
19210
|
{
|
|
@@ -19030,6 +19239,7 @@ const TrackBase = ({
|
|
|
19030
19239
|
onItemSelection,
|
|
19031
19240
|
onDrag,
|
|
19032
19241
|
allowOverlap = false,
|
|
19242
|
+
onDragStateChange,
|
|
19033
19243
|
elementColors
|
|
19034
19244
|
}) => {
|
|
19035
19245
|
const trackRef = React.useRef(null);
|
|
@@ -19054,6 +19264,7 @@ const TrackBase = ({
|
|
|
19054
19264
|
selectedIds,
|
|
19055
19265
|
onSelection: onItemSelection,
|
|
19056
19266
|
onDrag,
|
|
19267
|
+
onDragStateChange,
|
|
19057
19268
|
elementColors,
|
|
19058
19269
|
nextStart: index < elements.length - 1 ? elements[index + 1].getStart() : null,
|
|
19059
19270
|
prevEnd: index > 0 ? elements[index - 1].getEnd() : 0
|
|
@@ -19228,6 +19439,67 @@ function useMarqueeSelection({
|
|
|
19228
19439
|
);
|
|
19229
19440
|
return { marquee, handleMouseDown };
|
|
19230
19441
|
}
|
|
19442
|
+
function useEdgeAutoScroll({
|
|
19443
|
+
isActive,
|
|
19444
|
+
getMouseClientX,
|
|
19445
|
+
scrollContainerRef,
|
|
19446
|
+
contentWidth,
|
|
19447
|
+
edgeThreshold = 60,
|
|
19448
|
+
maxScrollSpeed = 20
|
|
19449
|
+
}) {
|
|
19450
|
+
const rafRef = React.useRef(null);
|
|
19451
|
+
React.useEffect(() => {
|
|
19452
|
+
if (!isActive) {
|
|
19453
|
+
if (rafRef.current) {
|
|
19454
|
+
cancelAnimationFrame(rafRef.current);
|
|
19455
|
+
rafRef.current = null;
|
|
19456
|
+
}
|
|
19457
|
+
return;
|
|
19458
|
+
}
|
|
19459
|
+
const step = () => {
|
|
19460
|
+
const el = scrollContainerRef.current;
|
|
19461
|
+
if (!el) {
|
|
19462
|
+
rafRef.current = requestAnimationFrame(step);
|
|
19463
|
+
return;
|
|
19464
|
+
}
|
|
19465
|
+
const rect = el.getBoundingClientRect();
|
|
19466
|
+
const mouseX = getMouseClientX();
|
|
19467
|
+
const xRelative = mouseX - rect.left;
|
|
19468
|
+
const viewportWidth = el.clientWidth;
|
|
19469
|
+
const scrollMax = Math.max(0, contentWidth - viewportWidth);
|
|
19470
|
+
let scrollSpeed = 0;
|
|
19471
|
+
if (xRelative < edgeThreshold && el.scrollLeft > 0) {
|
|
19472
|
+
const intensity = 1 - Math.max(0, xRelative) / edgeThreshold;
|
|
19473
|
+
scrollSpeed = -maxScrollSpeed * intensity;
|
|
19474
|
+
} else if (xRelative > viewportWidth - edgeThreshold && el.scrollLeft < scrollMax) {
|
|
19475
|
+
const intensity = 1 - Math.max(0, viewportWidth - edgeThreshold - xRelative) / edgeThreshold;
|
|
19476
|
+
scrollSpeed = maxScrollSpeed * intensity;
|
|
19477
|
+
}
|
|
19478
|
+
if (scrollSpeed !== 0) {
|
|
19479
|
+
const newScrollLeft = Math.max(
|
|
19480
|
+
0,
|
|
19481
|
+
Math.min(scrollMax, el.scrollLeft + scrollSpeed)
|
|
19482
|
+
);
|
|
19483
|
+
el.scrollLeft = newScrollLeft;
|
|
19484
|
+
}
|
|
19485
|
+
rafRef.current = requestAnimationFrame(step);
|
|
19486
|
+
};
|
|
19487
|
+
rafRef.current = requestAnimationFrame(step);
|
|
19488
|
+
return () => {
|
|
19489
|
+
if (rafRef.current) {
|
|
19490
|
+
cancelAnimationFrame(rafRef.current);
|
|
19491
|
+
rafRef.current = null;
|
|
19492
|
+
}
|
|
19493
|
+
};
|
|
19494
|
+
}, [
|
|
19495
|
+
isActive,
|
|
19496
|
+
getMouseClientX,
|
|
19497
|
+
scrollContainerRef,
|
|
19498
|
+
contentWidth,
|
|
19499
|
+
edgeThreshold,
|
|
19500
|
+
maxScrollSpeed
|
|
19501
|
+
]);
|
|
19502
|
+
}
|
|
19231
19503
|
function MarqueeOverlay({ marquee }) {
|
|
19232
19504
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
19233
19505
|
"div",
|
|
@@ -19258,8 +19530,25 @@ function MarqueeOverlay({ marquee }) {
|
|
|
19258
19530
|
}
|
|
19259
19531
|
);
|
|
19260
19532
|
}
|
|
19533
|
+
const SEPARATOR_HEIGHT$1 = 6;
|
|
19534
|
+
function getTrackOrSeparatorAt(clientY, containerTop, trackHeight) {
|
|
19535
|
+
const y2 = clientY - containerTop;
|
|
19536
|
+
if (y2 < 0) return null;
|
|
19537
|
+
const rowHeight = trackHeight + SEPARATOR_HEIGHT$1;
|
|
19538
|
+
if (y2 < SEPARATOR_HEIGHT$1) {
|
|
19539
|
+
return { type: "separator", separatorIndex: 0 };
|
|
19540
|
+
}
|
|
19541
|
+
const relativeY = y2 - SEPARATOR_HEIGHT$1;
|
|
19542
|
+
const index = Math.floor(relativeY / rowHeight);
|
|
19543
|
+
const remainder = relativeY % rowHeight;
|
|
19544
|
+
if (remainder < trackHeight) {
|
|
19545
|
+
return { type: "track", trackIndex: index };
|
|
19546
|
+
}
|
|
19547
|
+
return { type: "separator", separatorIndex: index + 1 };
|
|
19548
|
+
}
|
|
19261
19549
|
const LABEL_WIDTH = 40;
|
|
19262
19550
|
const TRACK_HEIGHT = 44;
|
|
19551
|
+
const SEPARATOR_HEIGHT = 6;
|
|
19263
19552
|
function TimelineView({
|
|
19264
19553
|
zoomLevel,
|
|
19265
19554
|
selectedItem,
|
|
@@ -19272,25 +19561,81 @@ function TimelineView({
|
|
|
19272
19561
|
onEmptyClick,
|
|
19273
19562
|
onMarqueeSelect,
|
|
19274
19563
|
onElementDrag,
|
|
19564
|
+
onElementDrop,
|
|
19565
|
+
onSeek,
|
|
19275
19566
|
elementColors,
|
|
19276
19567
|
selectedIds,
|
|
19277
19568
|
playheadPositionPx = 0,
|
|
19278
19569
|
isPlayheadActive = false,
|
|
19279
19570
|
onDropOnTimeline,
|
|
19280
19571
|
videoResolution,
|
|
19281
|
-
enableDropOnTimeline = true
|
|
19572
|
+
enableDropOnTimeline = true,
|
|
19573
|
+
chapters = []
|
|
19282
19574
|
}) {
|
|
19283
19575
|
const containerRef = React.useRef(null);
|
|
19284
19576
|
const seekContainerRef = React.useRef(null);
|
|
19285
19577
|
const timelineContentRef = React.useRef(null);
|
|
19286
19578
|
const [, setScrollLeft] = React.useState(0);
|
|
19579
|
+
const pointerRef = React.useRef(null);
|
|
19287
19580
|
const [draggedTimeline, setDraggedTimeline] = React.useState(null);
|
|
19581
|
+
const [draggingElementId, setDraggingElementId] = React.useState(null);
|
|
19582
|
+
const [activeDropTarget, setActiveDropTarget] = React.useState(null);
|
|
19288
19583
|
const { selectedTrackElement } = React.useMemo(() => {
|
|
19289
19584
|
if (selectedItem && "elements" in selectedItem) {
|
|
19290
19585
|
return { selectedTrackElement: null };
|
|
19291
19586
|
}
|
|
19292
19587
|
return { selectedTrackElement: selectedItem };
|
|
19293
19588
|
}, [selectedItem]);
|
|
19589
|
+
const handleDragWithDrop = React.useCallback(
|
|
19590
|
+
(payload, dropPointer) => {
|
|
19591
|
+
var _a;
|
|
19592
|
+
if (dropPointer && onElementDrop) {
|
|
19593
|
+
const rect = (_a = timelineContentRef.current) == null ? void 0 : _a.getBoundingClientRect();
|
|
19594
|
+
const dropTarget = rect ? getTrackOrSeparatorAt(dropPointer.clientY, rect.top, TRACK_HEIGHT) : null;
|
|
19595
|
+
onElementDrop({ ...payload, dropTarget });
|
|
19596
|
+
} else {
|
|
19597
|
+
onElementDrag(payload);
|
|
19598
|
+
}
|
|
19599
|
+
},
|
|
19600
|
+
[onElementDrag, onElementDrop]
|
|
19601
|
+
);
|
|
19602
|
+
useEdgeAutoScroll({
|
|
19603
|
+
isActive: !!draggingElementId,
|
|
19604
|
+
getMouseClientX: () => {
|
|
19605
|
+
var _a;
|
|
19606
|
+
return ((_a = pointerRef.current) == null ? void 0 : _a.clientX) ?? 0;
|
|
19607
|
+
},
|
|
19608
|
+
scrollContainerRef: containerRef,
|
|
19609
|
+
contentWidth: Math.max(100, duration * zoomLevel * 100)
|
|
19610
|
+
});
|
|
19611
|
+
React.useEffect(() => {
|
|
19612
|
+
if (!draggingElementId) return;
|
|
19613
|
+
const onMove = (e3) => {
|
|
19614
|
+
var _a;
|
|
19615
|
+
const pt2 = "touches" in e3 ? e3.touches[0] : e3;
|
|
19616
|
+
if (pt2) {
|
|
19617
|
+
pointerRef.current = { clientX: pt2.clientX, clientY: pt2.clientY };
|
|
19618
|
+
const rect = (_a = timelineContentRef.current) == null ? void 0 : _a.getBoundingClientRect();
|
|
19619
|
+
if (rect) {
|
|
19620
|
+
setActiveDropTarget(getTrackOrSeparatorAt(pt2.clientY, rect.top, TRACK_HEIGHT));
|
|
19621
|
+
}
|
|
19622
|
+
}
|
|
19623
|
+
};
|
|
19624
|
+
const onUp = () => {
|
|
19625
|
+
pointerRef.current = null;
|
|
19626
|
+
setActiveDropTarget(null);
|
|
19627
|
+
};
|
|
19628
|
+
document.addEventListener("mousemove", onMove);
|
|
19629
|
+
document.addEventListener("touchmove", onMove, { passive: true });
|
|
19630
|
+
document.addEventListener("mouseup", onUp);
|
|
19631
|
+
document.addEventListener("touchend", onUp);
|
|
19632
|
+
return () => {
|
|
19633
|
+
document.removeEventListener("mousemove", onMove);
|
|
19634
|
+
document.removeEventListener("touchmove", onMove);
|
|
19635
|
+
document.removeEventListener("mouseup", onUp);
|
|
19636
|
+
document.removeEventListener("touchend", onUp);
|
|
19637
|
+
};
|
|
19638
|
+
}, [draggingElementId]);
|
|
19294
19639
|
const timelineWidth = Math.max(100, duration * zoomLevel * 100);
|
|
19295
19640
|
const timelineWidthPx = `${timelineWidth}px`;
|
|
19296
19641
|
const handleScroll = (e3) => {
|
|
@@ -19387,9 +19732,36 @@ function TimelineView({
|
|
|
19387
19732
|
className: "twick-timeline-scroll-container",
|
|
19388
19733
|
onScroll: handleScroll,
|
|
19389
19734
|
children: [
|
|
19390
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { style: { width: timelineWidthPx }, children: seekTrack ? /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", position: "relative" }, children: [
|
|
19735
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { style: { width: timelineWidthPx }, children: seekTrack ? /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", position: "relative", minHeight: 34 }, children: [
|
|
19391
19736
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "twick-seek-track-empty-space", onClick: onAddTrack, children: /* @__PURE__ */ jsxRuntime.jsx(Plus, { color: "white", size: 20 }) }),
|
|
19392
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { style: { flexGrow: 1 }, children: seekTrack })
|
|
19737
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { style: { flexGrow: 1 }, children: seekTrack }),
|
|
19738
|
+
chapters.map((chapter) => {
|
|
19739
|
+
const left = LABEL_WIDTH + chapter.time / Math.max(duration, 1e-3) * (timelineWidth - LABEL_WIDTH);
|
|
19740
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
19741
|
+
"button",
|
|
19742
|
+
{
|
|
19743
|
+
className: "btn-ghost",
|
|
19744
|
+
title: chapter.title,
|
|
19745
|
+
onClick: (e3) => {
|
|
19746
|
+
e3.stopPropagation();
|
|
19747
|
+
onSeek(chapter.time);
|
|
19748
|
+
},
|
|
19749
|
+
style: {
|
|
19750
|
+
position: "absolute",
|
|
19751
|
+
left,
|
|
19752
|
+
top: 0,
|
|
19753
|
+
height: "100%",
|
|
19754
|
+
padding: "0 4px",
|
|
19755
|
+
borderRadius: 0,
|
|
19756
|
+
borderLeft: "1px solid rgba(255,255,255,0.4)",
|
|
19757
|
+
borderRight: "none",
|
|
19758
|
+
minWidth: 0
|
|
19759
|
+
},
|
|
19760
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontSize: 10, opacity: 0.9 }, children: chapter.title })
|
|
19761
|
+
},
|
|
19762
|
+
chapter.id
|
|
19763
|
+
);
|
|
19764
|
+
})
|
|
19393
19765
|
] }) : null }),
|
|
19394
19766
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
19395
19767
|
"div",
|
|
@@ -19415,34 +19787,61 @@ function TimelineView({
|
|
|
19415
19787
|
}
|
|
19416
19788
|
}
|
|
19417
19789
|
),
|
|
19418
|
-
/* @__PURE__ */ jsxRuntime.
|
|
19419
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "twick-timeline-header-container", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
19420
|
-
TrackHeader,
|
|
19421
|
-
{
|
|
19422
|
-
track,
|
|
19423
|
-
selectedIds,
|
|
19424
|
-
onSelect: handleItemSelection,
|
|
19425
|
-
onDragStart: handleTrackDragStart,
|
|
19426
|
-
onDragOver: handleTrackDragOver,
|
|
19427
|
-
onDrop: handleTrackDrop
|
|
19428
|
-
}
|
|
19429
|
-
) }),
|
|
19790
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: { position: "relative", zIndex: 10 }, children: [
|
|
19430
19791
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
19431
|
-
|
|
19792
|
+
"div",
|
|
19432
19793
|
{
|
|
19433
|
-
|
|
19434
|
-
|
|
19435
|
-
|
|
19436
|
-
|
|
19437
|
-
|
|
19438
|
-
allowOverlap: false,
|
|
19439
|
-
trackWidth: timelineWidth - LABEL_WIDTH,
|
|
19440
|
-
onItemSelection: handleItemSelection,
|
|
19441
|
-
onDrag: onElementDrag,
|
|
19442
|
-
elementColors
|
|
19794
|
+
className: "twick-timeline-separator",
|
|
19795
|
+
style: {
|
|
19796
|
+
height: SEPARATOR_HEIGHT,
|
|
19797
|
+
background: (activeDropTarget == null ? void 0 : activeDropTarget.type) === "separator" && activeDropTarget.separatorIndex === 0 ? "rgba(255,255,255,0.2)" : "transparent"
|
|
19798
|
+
}
|
|
19443
19799
|
}
|
|
19444
|
-
)
|
|
19445
|
-
|
|
19800
|
+
),
|
|
19801
|
+
(tracks || []).map((track, index) => /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
19802
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "twick-timeline-container", children: [
|
|
19803
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "twick-timeline-header-container", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
19804
|
+
TrackHeader,
|
|
19805
|
+
{
|
|
19806
|
+
track,
|
|
19807
|
+
selectedIds,
|
|
19808
|
+
onSelect: handleItemSelection,
|
|
19809
|
+
onDragStart: handleTrackDragStart,
|
|
19810
|
+
onDragOver: handleTrackDragOver,
|
|
19811
|
+
onDrop: handleTrackDrop
|
|
19812
|
+
}
|
|
19813
|
+
) }),
|
|
19814
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
19815
|
+
TrackBase,
|
|
19816
|
+
{
|
|
19817
|
+
track,
|
|
19818
|
+
duration,
|
|
19819
|
+
selectedItem: selectedTrackElement,
|
|
19820
|
+
selectedIds,
|
|
19821
|
+
zoom: zoomLevel,
|
|
19822
|
+
allowOverlap: false,
|
|
19823
|
+
trackWidth: timelineWidth - LABEL_WIDTH,
|
|
19824
|
+
onItemSelection: handleItemSelection,
|
|
19825
|
+
onDrag: handleDragWithDrop,
|
|
19826
|
+
onDragStateChange: (isDragging2, el) => {
|
|
19827
|
+
setDraggingElementId(isDragging2 && el ? el.getId() : null);
|
|
19828
|
+
},
|
|
19829
|
+
elementColors
|
|
19830
|
+
}
|
|
19831
|
+
)
|
|
19832
|
+
] }),
|
|
19833
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
19834
|
+
"div",
|
|
19835
|
+
{
|
|
19836
|
+
className: "twick-timeline-separator",
|
|
19837
|
+
style: {
|
|
19838
|
+
height: SEPARATOR_HEIGHT,
|
|
19839
|
+
background: (activeDropTarget == null ? void 0 : activeDropTarget.type) === "separator" && activeDropTarget.separatorIndex === index + 1 ? "rgba(255,255,255,0.2)" : "transparent"
|
|
19840
|
+
}
|
|
19841
|
+
}
|
|
19842
|
+
)
|
|
19843
|
+
] }, track.getId()))
|
|
19844
|
+
] })
|
|
19446
19845
|
]
|
|
19447
19846
|
}
|
|
19448
19847
|
)
|
|
@@ -19499,6 +19898,75 @@ const useTimelineManager = () => {
|
|
|
19499
19898
|
setSelectedItem(updatedElement);
|
|
19500
19899
|
editor.refresh();
|
|
19501
19900
|
};
|
|
19901
|
+
const isElementTrackType = (track) => track.getType() === timeline.TRACK_TYPES.ELEMENT;
|
|
19902
|
+
const wouldBeElementTrack = (el) => {
|
|
19903
|
+
const elType = el.getType().toLowerCase();
|
|
19904
|
+
return elType !== "video" && elType !== "image" && elType !== "audio";
|
|
19905
|
+
};
|
|
19906
|
+
const onElementDrop = async (params) => {
|
|
19907
|
+
var _a;
|
|
19908
|
+
const { element, dragType, updates, dropTarget } = params;
|
|
19909
|
+
const tracks = ((_a = editor.getTimelineData()) == null ? void 0 : _a.tracks) ?? [];
|
|
19910
|
+
if (!dropTarget) {
|
|
19911
|
+
return;
|
|
19912
|
+
}
|
|
19913
|
+
if (dropTarget.type === "separator") {
|
|
19914
|
+
if (!wouldBeElementTrack(element)) {
|
|
19915
|
+
return;
|
|
19916
|
+
}
|
|
19917
|
+
await editor.moveElementToNewTrackAt(
|
|
19918
|
+
element,
|
|
19919
|
+
dropTarget.separatorIndex,
|
|
19920
|
+
updates.start
|
|
19921
|
+
);
|
|
19922
|
+
setSelectedItem(element);
|
|
19923
|
+
editor.refresh();
|
|
19924
|
+
return;
|
|
19925
|
+
}
|
|
19926
|
+
const targetTrack = tracks[dropTarget.trackIndex];
|
|
19927
|
+
if (!targetTrack) {
|
|
19928
|
+
return;
|
|
19929
|
+
}
|
|
19930
|
+
if (!isElementTrackType(targetTrack)) {
|
|
19931
|
+
return;
|
|
19932
|
+
}
|
|
19933
|
+
const start = updates.start;
|
|
19934
|
+
const end = updates.end;
|
|
19935
|
+
const elementId = element.getId();
|
|
19936
|
+
const currentTrackId = element.getTrackId();
|
|
19937
|
+
let hasOverlap = false;
|
|
19938
|
+
const others = targetTrack.getElements().filter((el) => el.getId() !== elementId);
|
|
19939
|
+
for (const other of others) {
|
|
19940
|
+
const oStart = other.getStart();
|
|
19941
|
+
const oEnd = other.getEnd();
|
|
19942
|
+
if (start < oEnd && end > oStart) {
|
|
19943
|
+
hasOverlap = true;
|
|
19944
|
+
break;
|
|
19945
|
+
}
|
|
19946
|
+
}
|
|
19947
|
+
if (hasOverlap) {
|
|
19948
|
+
await editor.moveElementToNewTrackAt(
|
|
19949
|
+
element,
|
|
19950
|
+
dropTarget.trackIndex + 1,
|
|
19951
|
+
updates.start
|
|
19952
|
+
);
|
|
19953
|
+
setSelectedItem(element);
|
|
19954
|
+
editor.refresh();
|
|
19955
|
+
return;
|
|
19956
|
+
}
|
|
19957
|
+
if (currentTrackId === targetTrack.getId()) {
|
|
19958
|
+
onElementDrag({ element, dragType, updates });
|
|
19959
|
+
return;
|
|
19960
|
+
}
|
|
19961
|
+
editor.removeElement(element);
|
|
19962
|
+
element.setStart(updates.start);
|
|
19963
|
+
element.setEnd(updates.end);
|
|
19964
|
+
const added = await editor.addElementToTrack(targetTrack, element);
|
|
19965
|
+
if (added) {
|
|
19966
|
+
setSelectedItem(element);
|
|
19967
|
+
editor.refresh();
|
|
19968
|
+
}
|
|
19969
|
+
};
|
|
19502
19970
|
const timelineData = React.useMemo(() => editor.getTimelineData(), [changeLog]);
|
|
19503
19971
|
const { setSeekTime, setCurrentTime } = livePlayer.useLivePlayerContext();
|
|
19504
19972
|
const onReorder = (reorderedItems) => {
|
|
@@ -19521,6 +19989,7 @@ const useTimelineManager = () => {
|
|
|
19521
19989
|
timelineData,
|
|
19522
19990
|
onAddTrack,
|
|
19523
19991
|
onElementDrag,
|
|
19992
|
+
onElementDrop,
|
|
19524
19993
|
onReorder,
|
|
19525
19994
|
onSeek,
|
|
19526
19995
|
onSelectionChange,
|
|
@@ -19607,7 +20076,7 @@ const TimelineManager = ({
|
|
|
19607
20076
|
timelineTickConfigs,
|
|
19608
20077
|
elementColors
|
|
19609
20078
|
}) => {
|
|
19610
|
-
var _a;
|
|
20079
|
+
var _a, _b;
|
|
19611
20080
|
const { playerState } = livePlayer.useLivePlayerContext();
|
|
19612
20081
|
const { followPlayheadEnabled, editor, videoResolution, setSelectedItem } = timeline.useTimelineContext();
|
|
19613
20082
|
const {
|
|
@@ -19617,6 +20086,7 @@ const TimelineManager = ({
|
|
|
19617
20086
|
onAddTrack,
|
|
19618
20087
|
onReorder,
|
|
19619
20088
|
onElementDrag,
|
|
20089
|
+
onElementDrop,
|
|
19620
20090
|
onSeek
|
|
19621
20091
|
} = useTimelineManager();
|
|
19622
20092
|
const { selectedIds } = timeline.useTimelineContext();
|
|
@@ -19670,6 +20140,7 @@ const TimelineManager = ({
|
|
|
19670
20140
|
onAddTrack,
|
|
19671
20141
|
onReorder,
|
|
19672
20142
|
onElementDrag,
|
|
20143
|
+
onElementDrop,
|
|
19673
20144
|
onSeek,
|
|
19674
20145
|
onItemSelect: handleItemSelect,
|
|
19675
20146
|
onEmptyClick: handleEmptyClick,
|
|
@@ -19677,6 +20148,7 @@ const TimelineManager = ({
|
|
|
19677
20148
|
elementColors,
|
|
19678
20149
|
playheadPositionPx: playheadState.positionPx,
|
|
19679
20150
|
isPlayheadActive,
|
|
20151
|
+
chapters: ((_a = timelineData == null ? void 0 : timelineData.metadata) == null ? void 0 : _a.chapters) ?? [],
|
|
19680
20152
|
onDropOnTimeline: handleDropOnTimeline,
|
|
19681
20153
|
videoResolution,
|
|
19682
20154
|
enableDropOnTimeline: true,
|
|
@@ -19686,7 +20158,7 @@ const TimelineManager = ({
|
|
|
19686
20158
|
duration: totalDuration,
|
|
19687
20159
|
zoom: trackZoom,
|
|
19688
20160
|
onSeek,
|
|
19689
|
-
timelineCount: ((
|
|
20161
|
+
timelineCount: ((_b = timelineData == null ? void 0 : timelineData.tracks) == null ? void 0 : _b.length) ?? 0,
|
|
19690
20162
|
timelineTickConfigs,
|
|
19691
20163
|
onPlayheadUpdate: handlePlayheadUpdate
|
|
19692
20164
|
}
|