@twick/video-editor 0.15.27 → 0.15.28
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 +6 -1
- package/dist/components/track/track-base.d.ts +5 -1
- package/dist/components/track/track-element-context-menu.d.ts +16 -0
- package/dist/components/track/track-element.d.ts +6 -0
- package/dist/helpers/types.d.ts +1 -0
- package/dist/index.js +649 -108
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +650 -109
- package/dist/index.mjs.map +1 -1
- package/package.json +5 -5
package/dist/index.mjs
CHANGED
|
@@ -3,8 +3,9 @@ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { en
|
|
|
3
3
|
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
4
4
|
import { jsxs, jsx } from "react/jsx-runtime";
|
|
5
5
|
import { useLivePlayerContext, PLAYER_STATE, LivePlayer } from "@twick/live-player";
|
|
6
|
-
import { ImageElement as ImageElement$1, AudioElement, VideoElement as VideoElement$1, useTimelineContext, TIMELINE_ACTION, ElementDeserializer, getCurrentElements, CaptionElement as CaptionElement$1, TIMELINE_ELEMENT_TYPE, getDecimalNumber, resolveIds, TrackElement, TRACK_TYPES,
|
|
6
|
+
import { ImageElement as ImageElement$1, AudioElement, VideoElement as VideoElement$1, useTimelineContext, TIMELINE_ACTION, ElementDeserializer, getCurrentElements, CaptionElement as CaptionElement$1, canSplitElement, TIMELINE_ELEMENT_TYPE, getDecimalNumber, resolveIds, TrackElement, TRACK_TYPES, Track, resolveId, getElementIdsInRange, ValidationError, VALIDATION_ERROR_CODE, formatTimeWithFrames } from "@twick/timeline";
|
|
7
7
|
import React, { useState, useRef, useCallback, useEffect, useMemo, forwardRef, createElement, createContext, useContext, useId, useLayoutEffect, useInsertionEffect, Fragment, Component } from "react";
|
|
8
|
+
import { createPortal } from "react-dom";
|
|
8
9
|
function t(t2, e3, s2) {
|
|
9
10
|
return (e3 = function(t3) {
|
|
10
11
|
var e4 = function(t4, e5) {
|
|
@@ -5943,6 +5944,9 @@ function ea() {
|
|
|
5943
5944
|
function sa() {
|
|
5944
5945
|
return !ta && (!(arguments.length > 0 && void 0 !== arguments[0]) || arguments[0]) && (ta = ea()), ta;
|
|
5945
5946
|
}
|
|
5947
|
+
function ia(t2) {
|
|
5948
|
+
ta = t2;
|
|
5949
|
+
}
|
|
5946
5950
|
const ra = ["filters", "resizeFilter", "src", "crossOrigin", "type"], na = ["cropX", "cropY"];
|
|
5947
5951
|
class oa extends Li {
|
|
5948
5952
|
static getDefaults() {
|
|
@@ -6470,13 +6474,7 @@ function Za(e3, s2) {
|
|
|
6470
6474
|
return tt.setClass(r2, e3), r2;
|
|
6471
6475
|
}
|
|
6472
6476
|
t(Qa, "type", "ColorMatrix"), t(Qa, "defaults", Ja), t(Qa, "uniformLocations", ["uColorMatrix", "uConstants"]), tt.setClass(Qa);
|
|
6473
|
-
Za("Brownie", [0.5997, 0.34553, -0.27082, 0, 0.186, -0.0377, 0.86095, 0.15059, 0, -0.1449, 0.24113, -0.07441, 0.44972, 0, -0.02965, 0, 0, 0, 1, 0]);
|
|
6474
|
-
Za("Vintage", [0.62793, 0.32021, -0.03965, 0, 0.03784, 0.02578, 0.64411, 0.03259, 0, 0.02926, 0.0466, -0.08512, 0.52416, 0, 0.02023, 0, 0, 0, 1, 0]);
|
|
6475
|
-
Za("Kodachrome", [1.12855, -0.39673, -0.03992, 0, 0.24991, -0.16404, 1.08352, -0.05498, 0, 0.09698, -0.16786, -0.56034, 1.60148, 0, 0.13972, 0, 0, 0, 1, 0]);
|
|
6476
|
-
Za("Technicolor", [1.91252, -0.85453, -0.09155, 0, 0.04624, -0.30878, 1.76589, -0.10601, 0, -0.27589, -0.2311, -0.75018, 1.84759, 0, 0.12137, 0, 0, 0, 1, 0]);
|
|
6477
|
-
Za("Polaroid", [1.438, -0.062, -0.062, 0, 0, -0.122, 1.378, -0.122, 0, 0, -0.016, -0.016, 1.483, 0, 0, 0, 0, 0, 1, 0]);
|
|
6478
|
-
Za("Sepia", [0.393, 0.769, 0.189, 0, 0, 0.349, 0.686, 0.168, 0, 0, 0.272, 0.534, 0.131, 0, 0, 0, 0, 0, 1, 0]);
|
|
6479
|
-
Za("BlackWhite", [1.5, 1.5, 1.5, 0, -1, 1.5, 1.5, 1.5, 0, -1, 1.5, 1.5, 1.5, 0, -1, 0, 0, 0, 1, 0]);
|
|
6477
|
+
const $a = Za("Brownie", [0.5997, 0.34553, -0.27082, 0, 0.186, -0.0377, 0.86095, 0.15059, 0, -0.1449, 0.24113, -0.07441, 0.44972, 0, -0.02965, 0, 0, 0, 1, 0]), th = Za("Vintage", [0.62793, 0.32021, -0.03965, 0, 0.03784, 0.02578, 0.64411, 0.03259, 0, 0.02926, 0.0466, -0.08512, 0.52416, 0, 0.02023, 0, 0, 0, 1, 0]), eh = Za("Kodachrome", [1.12855, -0.39673, -0.03992, 0, 0.24991, -0.16404, 1.08352, -0.05498, 0, 0.09698, -0.16786, -0.56034, 1.60148, 0, 0.13972, 0, 0, 0, 1, 0]), sh = Za("Technicolor", [1.91252, -0.85453, -0.09155, 0, 0.04624, -0.30878, 1.76589, -0.10601, 0, -0.27589, -0.2311, -0.75018, 1.84759, 0, 0.12137, 0, 0, 0, 1, 0]), ih = Za("Polaroid", [1.438, -0.062, -0.062, 0, 0, -0.122, 1.378, -0.122, 0, 0, -0.016, -0.016, 1.483, 0, 0, 0, 0, 0, 1, 0]), rh = Za("Sepia", [0.393, 0.769, 0.189, 0, 0, 0.349, 0.686, 0.168, 0, 0, 0.272, 0.534, 0.131, 0, 0, 0, 0, 0, 1, 0]), nh = Za("BlackWhite", [1.5, 1.5, 1.5, 0, -1, 1.5, 1.5, 1.5, 0, -1, 1.5, 1.5, 1.5, 0, -1, 0, 0, 0, 1, 0]);
|
|
6480
6478
|
class oh extends Va {
|
|
6481
6479
|
constructor() {
|
|
6482
6480
|
let t2 = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {};
|
|
@@ -6839,6 +6837,7 @@ class bh extends Va {
|
|
|
6839
6837
|
}
|
|
6840
6838
|
}
|
|
6841
6839
|
t(bh, "type", "Vibrance"), t(bh, "defaults", { vibrance: 0 }), t(bh, "uniformLocations", ["uVibrance"]), tt.setClass(bh);
|
|
6840
|
+
var Sh = Object.freeze({ __proto__: null, BaseFilter: Va, BlackWhite: nh, BlendColor: Ga, BlendImage: Ua, Blur: qa, Brightness: Ka, Brownie: $a, ColorMatrix: Qa, Composed: oh, Contrast: ah, Convolute: ch, Gamma: uh, Grayscale: gh, HueRotation: ph, Invert: mh, Kodachrome: eh, Noise: vh$1, Pixelate: yh, Polaroid: ih, RemoveColor: _h, Resize: xh, Saturation: Ch, Sepia: rh, Technicolor: sh, Vibrance: bh, Vintage: th });
|
|
6842
6841
|
var __defProp2 = Object.defineProperty;
|
|
6843
6842
|
var __defNormalProp2 = (obj, key, value) => key in obj ? __defProp2(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
6844
6843
|
var __publicField2 = (obj, key, value) => __defNormalProp2(obj, key + "", value);
|
|
@@ -6899,6 +6898,8 @@ const ELEMENT_TYPES = {
|
|
|
6899
6898
|
RECT: "rect",
|
|
6900
6899
|
/** Circle element type */
|
|
6901
6900
|
CIRCLE: "circle",
|
|
6901
|
+
/** Emoji sticker element type */
|
|
6902
|
+
EMOJI: "emoji",
|
|
6902
6903
|
/** Arrow annotation element type */
|
|
6903
6904
|
ARROW: "arrow",
|
|
6904
6905
|
/** Line annotation / shape element type */
|
|
@@ -7147,6 +7148,24 @@ const rotateControl = new ai({
|
|
|
7147
7148
|
/** Whether to show connection line */
|
|
7148
7149
|
withConnection: true
|
|
7149
7150
|
});
|
|
7151
|
+
const COLOR_FILTERS = {
|
|
7152
|
+
SATURATED: "saturated",
|
|
7153
|
+
BRIGHT: "bright",
|
|
7154
|
+
VIBRANT: "vibrant",
|
|
7155
|
+
RETRO: "retro",
|
|
7156
|
+
BLACK_WHITE: "blackWhite",
|
|
7157
|
+
SEPIA: "sepia",
|
|
7158
|
+
COOL: "cool",
|
|
7159
|
+
WARM: "warm",
|
|
7160
|
+
CINEMATIC: "cinematic",
|
|
7161
|
+
SOFT_GLOW: "softGlow",
|
|
7162
|
+
MOODY: "moody",
|
|
7163
|
+
DREAMY: "dreamy",
|
|
7164
|
+
INVERTED: "inverted",
|
|
7165
|
+
VINTAGE: "vintage",
|
|
7166
|
+
DRAMATIC: "dramatic",
|
|
7167
|
+
FADED: "faded"
|
|
7168
|
+
};
|
|
7150
7169
|
class LRUCache {
|
|
7151
7170
|
constructor(maxSize = 100) {
|
|
7152
7171
|
if (maxSize <= 0) {
|
|
@@ -7530,6 +7549,275 @@ const getObjectFitSize = (objectFit, elementSize, containerSize) => {
|
|
|
7530
7549
|
};
|
|
7531
7550
|
}
|
|
7532
7551
|
};
|
|
7552
|
+
const {
|
|
7553
|
+
Blur,
|
|
7554
|
+
Brightness,
|
|
7555
|
+
ColorMatrix,
|
|
7556
|
+
Contrast,
|
|
7557
|
+
Grayscale,
|
|
7558
|
+
HueRotation,
|
|
7559
|
+
Invert,
|
|
7560
|
+
Saturation,
|
|
7561
|
+
Sepia
|
|
7562
|
+
} = Sh;
|
|
7563
|
+
let canvas2dFilterBackendInstalled = false;
|
|
7564
|
+
function ensureCanvas2dImageFilterBackend() {
|
|
7565
|
+
if (canvas2dFilterBackendInstalled) return;
|
|
7566
|
+
canvas2dFilterBackendInstalled = true;
|
|
7567
|
+
ia(new Zo());
|
|
7568
|
+
}
|
|
7569
|
+
function getSourceBitmapSize(img) {
|
|
7570
|
+
const el = img.getElement();
|
|
7571
|
+
if (!el) return null;
|
|
7572
|
+
const w2 = "naturalWidth" in el && el.naturalWidth > 0 ? el.naturalWidth : el.width;
|
|
7573
|
+
const h2 = "naturalHeight" in el && el.naturalHeight > 0 ? el.naturalHeight : el.height;
|
|
7574
|
+
if (!w2 || !h2) return null;
|
|
7575
|
+
return { w: w2, h: h2 };
|
|
7576
|
+
}
|
|
7577
|
+
function applyFiltersSafe(img) {
|
|
7578
|
+
ensureCanvas2dImageFilterBackend();
|
|
7579
|
+
img.applyFilters();
|
|
7580
|
+
}
|
|
7581
|
+
const bright = (m2) => Math.min(1, Math.max(-1, (m2 - 1) * 0.48));
|
|
7582
|
+
const contr = (m2) => Math.min(1, Math.max(-1, (m2 - 1) * 0.55));
|
|
7583
|
+
const sat = (m2) => Math.min(1, Math.max(-1, (m2 - 1) * 0.72));
|
|
7584
|
+
const IDENTITY = [
|
|
7585
|
+
1,
|
|
7586
|
+
0,
|
|
7587
|
+
0,
|
|
7588
|
+
0,
|
|
7589
|
+
0,
|
|
7590
|
+
0,
|
|
7591
|
+
1,
|
|
7592
|
+
0,
|
|
7593
|
+
0,
|
|
7594
|
+
0,
|
|
7595
|
+
0,
|
|
7596
|
+
0,
|
|
7597
|
+
1,
|
|
7598
|
+
0,
|
|
7599
|
+
0,
|
|
7600
|
+
0,
|
|
7601
|
+
0,
|
|
7602
|
+
0,
|
|
7603
|
+
1,
|
|
7604
|
+
0
|
|
7605
|
+
];
|
|
7606
|
+
const SEPIA_MATRIX = [
|
|
7607
|
+
0.393,
|
|
7608
|
+
0.769,
|
|
7609
|
+
0.189,
|
|
7610
|
+
0,
|
|
7611
|
+
0,
|
|
7612
|
+
0.349,
|
|
7613
|
+
0.686,
|
|
7614
|
+
0.168,
|
|
7615
|
+
0,
|
|
7616
|
+
0,
|
|
7617
|
+
0.272,
|
|
7618
|
+
0.534,
|
|
7619
|
+
0.131,
|
|
7620
|
+
0,
|
|
7621
|
+
0,
|
|
7622
|
+
0,
|
|
7623
|
+
0,
|
|
7624
|
+
0,
|
|
7625
|
+
1,
|
|
7626
|
+
0
|
|
7627
|
+
];
|
|
7628
|
+
function sepiaMix(strength) {
|
|
7629
|
+
const t2 = Math.min(1, Math.max(0, strength));
|
|
7630
|
+
const m2 = IDENTITY.map((v2, i2) => v2 + (SEPIA_MATRIX[i2] - v2) * t2);
|
|
7631
|
+
return new ColorMatrix({ matrix: m2, colorsOnly: true });
|
|
7632
|
+
}
|
|
7633
|
+
const twickBlurToFabric = (v2) => Math.min(0.22, Math.max(0, v2 * 0.045));
|
|
7634
|
+
function buildFilters(filterType) {
|
|
7635
|
+
switch (filterType) {
|
|
7636
|
+
case COLOR_FILTERS.SATURATED:
|
|
7637
|
+
return {
|
|
7638
|
+
filters: [
|
|
7639
|
+
new Saturation({ saturation: sat(1.4) }),
|
|
7640
|
+
new Contrast({ contrast: contr(1.1) })
|
|
7641
|
+
],
|
|
7642
|
+
opacityFactor: 1
|
|
7643
|
+
};
|
|
7644
|
+
case COLOR_FILTERS.BRIGHT:
|
|
7645
|
+
return {
|
|
7646
|
+
filters: [
|
|
7647
|
+
new Brightness({ brightness: bright(1.3) }),
|
|
7648
|
+
new Contrast({ contrast: contr(1.05) })
|
|
7649
|
+
],
|
|
7650
|
+
opacityFactor: 1
|
|
7651
|
+
};
|
|
7652
|
+
case COLOR_FILTERS.VIBRANT:
|
|
7653
|
+
return {
|
|
7654
|
+
filters: [
|
|
7655
|
+
new Saturation({ saturation: sat(1.6) }),
|
|
7656
|
+
new Brightness({ brightness: bright(1.15) }),
|
|
7657
|
+
new Contrast({ contrast: contr(1.1) })
|
|
7658
|
+
],
|
|
7659
|
+
opacityFactor: 1
|
|
7660
|
+
};
|
|
7661
|
+
case COLOR_FILTERS.RETRO:
|
|
7662
|
+
return {
|
|
7663
|
+
filters: [
|
|
7664
|
+
sepiaMix(0.8),
|
|
7665
|
+
new Contrast({ contrast: contr(1.3) }),
|
|
7666
|
+
new Brightness({ brightness: bright(0.85) }),
|
|
7667
|
+
new Saturation({ saturation: sat(0.8) })
|
|
7668
|
+
],
|
|
7669
|
+
opacityFactor: 1
|
|
7670
|
+
};
|
|
7671
|
+
case COLOR_FILTERS.BLACK_WHITE:
|
|
7672
|
+
return {
|
|
7673
|
+
filters: [
|
|
7674
|
+
new Grayscale(),
|
|
7675
|
+
new Contrast({ contrast: contr(1.25) }),
|
|
7676
|
+
new Brightness({ brightness: bright(1.05) })
|
|
7677
|
+
],
|
|
7678
|
+
opacityFactor: 1
|
|
7679
|
+
};
|
|
7680
|
+
case COLOR_FILTERS.SEPIA:
|
|
7681
|
+
return {
|
|
7682
|
+
filters: [
|
|
7683
|
+
new Sepia(),
|
|
7684
|
+
new Contrast({ contrast: contr(1.08) })
|
|
7685
|
+
],
|
|
7686
|
+
opacityFactor: 1
|
|
7687
|
+
};
|
|
7688
|
+
case COLOR_FILTERS.COOL:
|
|
7689
|
+
return {
|
|
7690
|
+
filters: [
|
|
7691
|
+
new HueRotation({ rotation: 15 / 180 }),
|
|
7692
|
+
new Brightness({ brightness: bright(1.1) }),
|
|
7693
|
+
new Saturation({ saturation: sat(1.3) }),
|
|
7694
|
+
new Contrast({ contrast: contr(1.05) })
|
|
7695
|
+
],
|
|
7696
|
+
opacityFactor: 1
|
|
7697
|
+
};
|
|
7698
|
+
case COLOR_FILTERS.WARM:
|
|
7699
|
+
return {
|
|
7700
|
+
filters: [
|
|
7701
|
+
new HueRotation({ rotation: -15 / 180 }),
|
|
7702
|
+
new Brightness({ brightness: bright(1.15) }),
|
|
7703
|
+
new Saturation({ saturation: sat(1.3) }),
|
|
7704
|
+
new Contrast({ contrast: contr(1.05) })
|
|
7705
|
+
],
|
|
7706
|
+
opacityFactor: 1
|
|
7707
|
+
};
|
|
7708
|
+
case COLOR_FILTERS.CINEMATIC:
|
|
7709
|
+
return {
|
|
7710
|
+
filters: [
|
|
7711
|
+
new Contrast({ contrast: contr(1.4) }),
|
|
7712
|
+
new Brightness({ brightness: bright(0.95) }),
|
|
7713
|
+
new Saturation({ saturation: sat(0.85) }),
|
|
7714
|
+
sepiaMix(0.2)
|
|
7715
|
+
],
|
|
7716
|
+
opacityFactor: 1
|
|
7717
|
+
};
|
|
7718
|
+
case COLOR_FILTERS.SOFT_GLOW:
|
|
7719
|
+
return {
|
|
7720
|
+
filters: [
|
|
7721
|
+
new Brightness({ brightness: bright(1.2) }),
|
|
7722
|
+
new Contrast({ contrast: contr(0.95) }),
|
|
7723
|
+
new Blur({ blur: twickBlurToFabric(1.2) }),
|
|
7724
|
+
new Saturation({ saturation: sat(1.1) })
|
|
7725
|
+
],
|
|
7726
|
+
opacityFactor: 1
|
|
7727
|
+
};
|
|
7728
|
+
case COLOR_FILTERS.MOODY:
|
|
7729
|
+
return {
|
|
7730
|
+
filters: [
|
|
7731
|
+
new Brightness({ brightness: bright(1.05) }),
|
|
7732
|
+
new Contrast({ contrast: contr(1.4) }),
|
|
7733
|
+
new Saturation({ saturation: sat(0.65) }),
|
|
7734
|
+
sepiaMix(0.2)
|
|
7735
|
+
],
|
|
7736
|
+
opacityFactor: 1
|
|
7737
|
+
};
|
|
7738
|
+
case COLOR_FILTERS.DREAMY:
|
|
7739
|
+
return {
|
|
7740
|
+
filters: [
|
|
7741
|
+
new Brightness({ brightness: bright(1.3) }),
|
|
7742
|
+
new Blur({ blur: twickBlurToFabric(2) }),
|
|
7743
|
+
new Saturation({ saturation: sat(1.4) }),
|
|
7744
|
+
new Contrast({ contrast: contr(0.95) })
|
|
7745
|
+
],
|
|
7746
|
+
opacityFactor: 1
|
|
7747
|
+
};
|
|
7748
|
+
case COLOR_FILTERS.INVERTED:
|
|
7749
|
+
return {
|
|
7750
|
+
filters: [
|
|
7751
|
+
new Invert({ invert: true, alpha: false }),
|
|
7752
|
+
new HueRotation({ rotation: 1 })
|
|
7753
|
+
],
|
|
7754
|
+
opacityFactor: 1
|
|
7755
|
+
};
|
|
7756
|
+
case COLOR_FILTERS.VINTAGE:
|
|
7757
|
+
return {
|
|
7758
|
+
filters: [
|
|
7759
|
+
sepiaMix(0.4),
|
|
7760
|
+
new Saturation({ saturation: sat(1.4) }),
|
|
7761
|
+
new Contrast({ contrast: contr(1.2) }),
|
|
7762
|
+
new Brightness({ brightness: bright(1.1) })
|
|
7763
|
+
],
|
|
7764
|
+
opacityFactor: 1
|
|
7765
|
+
};
|
|
7766
|
+
case COLOR_FILTERS.DRAMATIC:
|
|
7767
|
+
return {
|
|
7768
|
+
filters: [
|
|
7769
|
+
new Contrast({ contrast: contr(1.5) }),
|
|
7770
|
+
new Brightness({ brightness: bright(0.9) }),
|
|
7771
|
+
new Saturation({ saturation: sat(1.2) })
|
|
7772
|
+
],
|
|
7773
|
+
opacityFactor: 1
|
|
7774
|
+
};
|
|
7775
|
+
case COLOR_FILTERS.FADED:
|
|
7776
|
+
return {
|
|
7777
|
+
filters: [
|
|
7778
|
+
new Brightness({ brightness: bright(1.2) }),
|
|
7779
|
+
new Saturation({ saturation: sat(0.8) }),
|
|
7780
|
+
new Contrast({ contrast: contr(0.9) })
|
|
7781
|
+
],
|
|
7782
|
+
opacityFactor: 0.9
|
|
7783
|
+
};
|
|
7784
|
+
default:
|
|
7785
|
+
return { filters: [], opacityFactor: 1 };
|
|
7786
|
+
}
|
|
7787
|
+
}
|
|
7788
|
+
function applyFabricMediaColorFilters(img, mediaFilter, elementOpacity) {
|
|
7789
|
+
const key = (mediaFilter == null ? void 0 : mediaFilter.trim()) || "none";
|
|
7790
|
+
if (key === "none") {
|
|
7791
|
+
img.filters = [];
|
|
7792
|
+
img.set("opacity", elementOpacity);
|
|
7793
|
+
applyFiltersSafe(img);
|
|
7794
|
+
return;
|
|
7795
|
+
}
|
|
7796
|
+
const { filters: filterList, opacityFactor } = buildFilters(key);
|
|
7797
|
+
if (filterList.length === 0) {
|
|
7798
|
+
img.filters = [];
|
|
7799
|
+
img.set("opacity", elementOpacity);
|
|
7800
|
+
applyFiltersSafe(img);
|
|
7801
|
+
return;
|
|
7802
|
+
}
|
|
7803
|
+
if (!getSourceBitmapSize(img)) {
|
|
7804
|
+
img.filters = [];
|
|
7805
|
+
img.set("opacity", elementOpacity);
|
|
7806
|
+
return;
|
|
7807
|
+
}
|
|
7808
|
+
img.filters = filterList;
|
|
7809
|
+
img.set("opacity", elementOpacity * opacityFactor);
|
|
7810
|
+
try {
|
|
7811
|
+
applyFiltersSafe(img);
|
|
7812
|
+
} catch {
|
|
7813
|
+
img.filters = [];
|
|
7814
|
+
img.set("opacity", elementOpacity);
|
|
7815
|
+
try {
|
|
7816
|
+
applyFiltersSafe(img);
|
|
7817
|
+
} catch {
|
|
7818
|
+
}
|
|
7819
|
+
}
|
|
7820
|
+
}
|
|
7533
7821
|
const MARGIN = 10;
|
|
7534
7822
|
const addTextElement = ({
|
|
7535
7823
|
element,
|
|
@@ -7620,7 +7908,7 @@ const setImageProps = ({
|
|
|
7620
7908
|
canvasMetadata,
|
|
7621
7909
|
lockAspectRatio = true
|
|
7622
7910
|
}) => {
|
|
7623
|
-
var _a, _b, _c, _d, _e2;
|
|
7911
|
+
var _a, _b, _c, _d, _e2, _f;
|
|
7624
7912
|
const width = (((_a = element.props) == null ? void 0 : _a.width) || 0) * canvasMetadata.scaleX || canvasMetadata.width;
|
|
7625
7913
|
const height = (((_b = element.props) == null ? void 0 : _b.height) || 0) * canvasMetadata.scaleY || canvasMetadata.height;
|
|
7626
7914
|
const { x: x2, y: y2 } = convertToCanvasPosition(
|
|
@@ -7634,11 +7922,15 @@ const setImageProps = ({
|
|
|
7634
7922
|
img.set("height", height);
|
|
7635
7923
|
img.set("left", x2);
|
|
7636
7924
|
img.set("top", y2);
|
|
7637
|
-
img.set("opacity", ((_e2 = element.props) == null ? void 0 : _e2.opacity) ?? 1);
|
|
7638
7925
|
img.set("selectable", true);
|
|
7639
7926
|
img.set("hasControls", true);
|
|
7640
7927
|
img.set("touchAction", "all");
|
|
7641
7928
|
img.set("lockUniScaling", lockAspectRatio);
|
|
7929
|
+
applyFabricMediaColorFilters(
|
|
7930
|
+
img,
|
|
7931
|
+
(_e2 = element.props) == null ? void 0 : _e2.mediaFilter,
|
|
7932
|
+
((_f = element.props) == null ? void 0 : _f.opacity) ?? 1
|
|
7933
|
+
);
|
|
7642
7934
|
};
|
|
7643
7935
|
const addCaptionElement = ({
|
|
7644
7936
|
element,
|
|
@@ -7648,48 +7940,52 @@ const addCaptionElement = ({
|
|
|
7648
7940
|
canvasMetadata,
|
|
7649
7941
|
lockAspectRatio = false
|
|
7650
7942
|
}) => {
|
|
7651
|
-
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
|
|
7652
|
-
const
|
|
7653
|
-
const
|
|
7943
|
+
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;
|
|
7944
|
+
const useTrackDefaults = ((_a = element.props) == null ? void 0 : _a.useTrackDefaults) ?? true;
|
|
7945
|
+
const trackColors = captionProps == null ? void 0 : captionProps.colors;
|
|
7946
|
+
const elementColors = (_b = element.props) == null ? void 0 : _b.colors;
|
|
7947
|
+
const resolvedColors = useTrackDefaults ? trackColors : { ...trackColors ?? {}, ...elementColors ?? {} };
|
|
7948
|
+
const captionTextColor = (resolvedColors == null ? void 0 : resolvedColors.text) ?? ((_c = captionProps == null ? void 0 : captionProps.color) == null ? void 0 : _c.text);
|
|
7654
7949
|
const { x: x2, y: y2 } = convertToCanvasPosition(
|
|
7655
|
-
(
|
|
7656
|
-
(
|
|
7950
|
+
(useTrackDefaults ? captionProps == null ? void 0 : captionProps.x : (_d = element.props) == null ? void 0 : _d.x) ?? (captionProps == null ? void 0 : captionProps.x) ?? 0,
|
|
7951
|
+
(useTrackDefaults ? captionProps == null ? void 0 : captionProps.y : (_e2 = element.props) == null ? void 0 : _e2.y) ?? (captionProps == null ? void 0 : captionProps.y) ?? 0,
|
|
7657
7952
|
canvasMetadata
|
|
7658
7953
|
);
|
|
7659
|
-
let width = ((
|
|
7660
|
-
if ((
|
|
7954
|
+
let width = ((_f = element.props) == null ? void 0 : _f.width) ? element.props.width * canvasMetadata.scaleX : canvasMetadata.width - 2 * MARGIN;
|
|
7955
|
+
if ((_g = element.props) == null ? void 0 : _g.maxWidth) {
|
|
7661
7956
|
width = Math.min(width, element.props.maxWidth * canvasMetadata.scaleX);
|
|
7662
7957
|
}
|
|
7663
|
-
const
|
|
7664
|
-
const resolvedFill = (applyToAll ? captionTextColor : ((_h2 = element.props) == null ? void 0 : _h2.fill) ?? (elementColors == null ? void 0 : elementColors.text) ?? captionTextColor) ?? DEFAULT_CAPTION_PROPS.fill;
|
|
7665
|
-
const trackColors = captionProps == null ? void 0 : captionProps.colors;
|
|
7958
|
+
const resolvedFill = (useTrackDefaults ? void 0 : (_h2 = element.props) == null ? void 0 : _h2.fill) ?? captionTextColor ?? DEFAULT_CAPTION_PROPS.fill;
|
|
7666
7959
|
const trackStroke = trackColors == null ? void 0 : trackColors.outlineColor;
|
|
7667
7960
|
const elementStroke = (elementColors == null ? void 0 : elementColors.outlineColor) ?? ((_i2 = element.props) == null ? void 0 : _i2.stroke);
|
|
7668
|
-
const resolvedStroke = (
|
|
7669
|
-
const
|
|
7961
|
+
const resolvedStroke = (useTrackDefaults ? trackStroke : elementStroke ?? trackStroke) ?? void 0;
|
|
7962
|
+
const trackFont = (captionProps == null ? void 0 : captionProps.font) ?? {};
|
|
7963
|
+
const elementFont = ((_j = element.props) == null ? void 0 : _j.font) ?? {};
|
|
7964
|
+
const resolvedFont = useTrackDefaults ? trackFont : { ...trackFont, ...elementFont };
|
|
7965
|
+
const caption = new Uo(((_k = element.props) == null ? void 0 : _k.text) || element.t || "", {
|
|
7670
7966
|
left: x2,
|
|
7671
7967
|
top: y2,
|
|
7672
7968
|
originX: "center",
|
|
7673
7969
|
originY: "center",
|
|
7674
|
-
angle: ((
|
|
7970
|
+
angle: ((_l = element.props) == null ? void 0 : _l.rotation) || 0,
|
|
7675
7971
|
fontSize: Math.round(
|
|
7676
|
-
((
|
|
7972
|
+
((resolvedFont == null ? void 0 : resolvedFont.size) ?? DEFAULT_CAPTION_PROPS.size) * canvasMetadata.scaleX
|
|
7677
7973
|
),
|
|
7678
|
-
fontFamily: (
|
|
7974
|
+
fontFamily: (resolvedFont == null ? void 0 : resolvedFont.family) ?? DEFAULT_CAPTION_PROPS.family,
|
|
7679
7975
|
fill: resolvedFill,
|
|
7680
|
-
fontWeight: (
|
|
7976
|
+
fontWeight: (resolvedFont == null ? void 0 : resolvedFont.weight) ?? DEFAULT_CAPTION_PROPS.fontWeight,
|
|
7681
7977
|
...resolvedStroke ? { stroke: resolvedStroke } : {},
|
|
7682
|
-
opacity: (
|
|
7978
|
+
opacity: (useTrackDefaults ? void 0 : (_m = element.props) == null ? void 0 : _m.opacity) ?? (captionProps == null ? void 0 : captionProps.opacity) ?? 1,
|
|
7683
7979
|
width,
|
|
7684
7980
|
splitByGrapheme: false,
|
|
7685
|
-
textAlign: ((
|
|
7981
|
+
textAlign: ((_n2 = element.props) == null ? void 0 : _n2.textAlign) ?? "center",
|
|
7686
7982
|
shadow: new Ds({
|
|
7687
|
-
offsetX: (
|
|
7688
|
-
offsetY: (
|
|
7689
|
-
blur: (
|
|
7690
|
-
color: (
|
|
7983
|
+
offsetX: (useTrackDefaults ? void 0 : (_p = (_o2 = element.props) == null ? void 0 : _o2.shadowOffset) == null ? void 0 : _p[0]) ?? ((_q = captionProps == null ? void 0 : captionProps.shadowOffset) == null ? void 0 : _q[0]) ?? ((_r2 = DEFAULT_CAPTION_PROPS.shadowOffset) == null ? void 0 : _r2[0]),
|
|
7984
|
+
offsetY: (useTrackDefaults ? void 0 : (_t2 = (_s2 = element.props) == null ? void 0 : _s2.shadowOffset) == null ? void 0 : _t2[1]) ?? ((_u = captionProps == null ? void 0 : captionProps.shadowOffset) == null ? void 0 : _u[1]) ?? ((_v = DEFAULT_CAPTION_PROPS.shadowOffset) == null ? void 0 : _v[1]),
|
|
7985
|
+
blur: (useTrackDefaults ? void 0 : (_w = element.props) == null ? void 0 : _w.shadowBlur) ?? (captionProps == null ? void 0 : captionProps.shadowBlur) ?? DEFAULT_CAPTION_PROPS.shadowBlur,
|
|
7986
|
+
color: (useTrackDefaults ? void 0 : (_x = element.props) == null ? void 0 : _x.shadowColor) ?? (captionProps == null ? void 0 : captionProps.shadowColor) ?? DEFAULT_CAPTION_PROPS.shadowColor
|
|
7691
7987
|
}),
|
|
7692
|
-
strokeWidth: ((
|
|
7988
|
+
strokeWidth: ((useTrackDefaults ? void 0 : (_y = element.props) == null ? void 0 : _y.lineWidth) ?? (captionProps == null ? void 0 : captionProps.lineWidth) ?? DEFAULT_CAPTION_PROPS.lineWidth) * 0.025
|
|
7693
7989
|
});
|
|
7694
7990
|
caption.set("id", element.id);
|
|
7695
7991
|
caption.set("zIndex", index);
|
|
@@ -7744,8 +8040,13 @@ const addImageElement = async ({
|
|
|
7744
8040
|
currentFrameEffect,
|
|
7745
8041
|
lockAspectRatio = true
|
|
7746
8042
|
}) => {
|
|
8043
|
+
var _a, _b;
|
|
7747
8044
|
try {
|
|
7748
|
-
const
|
|
8045
|
+
const rawSrc = imageUrl || element.props.src || "";
|
|
8046
|
+
const mediaFilter = (_b = (_a = element.props) == null ? void 0 : _a.mediaFilter) == null ? void 0 : _b.trim();
|
|
8047
|
+
const useFilter = !!mediaFilter && mediaFilter !== "none";
|
|
8048
|
+
const fromUrlOpts = useFilter && /^https?:\/\//i.test(rawSrc) ? { crossOrigin: "anonymous" } : {};
|
|
8049
|
+
const img = await oa.fromURL(rawSrc, fromUrlOpts);
|
|
7749
8050
|
img.set({
|
|
7750
8051
|
originX: "center",
|
|
7751
8052
|
originY: "center",
|
|
@@ -7782,7 +8083,7 @@ const addMediaGroup = ({
|
|
|
7782
8083
|
currentFrameEffect,
|
|
7783
8084
|
lockAspectRatio = true
|
|
7784
8085
|
}) => {
|
|
7785
|
-
var _a, _b, _c, _d, _e2, _f, _g, _h2, _i2, _j, _k, _l, _m, _n2;
|
|
8086
|
+
var _a, _b, _c, _d, _e2, _f, _g, _h2, _i2, _j, _k, _l, _m, _n2, _o2;
|
|
7786
8087
|
let frameSize;
|
|
7787
8088
|
let angle;
|
|
7788
8089
|
let framePosition;
|
|
@@ -7837,9 +8138,13 @@ const addMediaGroup = ({
|
|
|
7837
8138
|
originX: "center",
|
|
7838
8139
|
originY: "center",
|
|
7839
8140
|
scaleX: newSize.width / img.width,
|
|
7840
|
-
scaleY: newSize.height / img.height
|
|
7841
|
-
opacity: ((_n2 = element.props) == null ? void 0 : _n2.opacity) ?? 1
|
|
8141
|
+
scaleY: newSize.height / img.height
|
|
7842
8142
|
});
|
|
8143
|
+
applyFabricMediaColorFilters(
|
|
8144
|
+
img,
|
|
8145
|
+
(_n2 = element.props) == null ? void 0 : _n2.mediaFilter,
|
|
8146
|
+
((_o2 = element.props) == null ? void 0 : _o2.opacity) ?? 1
|
|
8147
|
+
);
|
|
7843
8148
|
const { x: x2, y: y2 } = convertToCanvasPosition(
|
|
7844
8149
|
(framePosition == null ? void 0 : framePosition.x) || 0,
|
|
7845
8150
|
(framePosition == null ? void 0 : framePosition.y) || 0,
|
|
@@ -8325,7 +8630,8 @@ const CaptionElement = {
|
|
|
8325
8630
|
context.canvasMetadata,
|
|
8326
8631
|
context.videoSize
|
|
8327
8632
|
);
|
|
8328
|
-
|
|
8633
|
+
const useTrackDefaults = ((_a = element.props) == null ? void 0 : _a.useTrackDefaults) ?? true;
|
|
8634
|
+
if (useTrackDefaults) {
|
|
8329
8635
|
return {
|
|
8330
8636
|
element,
|
|
8331
8637
|
operation: CANVAS_OPERATIONS.CAPTION_PROPS_UPDATED,
|
|
@@ -8542,6 +8848,72 @@ const EffectElement = {
|
|
|
8542
8848
|
return;
|
|
8543
8849
|
}
|
|
8544
8850
|
};
|
|
8851
|
+
const EmojiElement = {
|
|
8852
|
+
name: ELEMENT_TYPES.EMOJI,
|
|
8853
|
+
async add(params) {
|
|
8854
|
+
var _a;
|
|
8855
|
+
const { element, index, canvas, canvasMetadata, lockAspectRatio } = params;
|
|
8856
|
+
await addImageElement({
|
|
8857
|
+
element,
|
|
8858
|
+
index,
|
|
8859
|
+
canvas,
|
|
8860
|
+
canvasMetadata,
|
|
8861
|
+
lockAspectRatio: lockAspectRatio ?? ((_a = element.props) == null ? void 0 : _a.lockAspectRatio) ?? true
|
|
8862
|
+
});
|
|
8863
|
+
},
|
|
8864
|
+
updateFromFabricObject(object, element, context) {
|
|
8865
|
+
const canvasCenter = getObjectCanvasCenter(object);
|
|
8866
|
+
const { x: x2, y: y2 } = convertToVideoPosition(
|
|
8867
|
+
canvasCenter.x,
|
|
8868
|
+
canvasCenter.y,
|
|
8869
|
+
context.canvasMetadata,
|
|
8870
|
+
context.videoSize
|
|
8871
|
+
);
|
|
8872
|
+
if (object.type === "group") {
|
|
8873
|
+
const scaledW2 = (object.width ?? 0) * (object.scaleX ?? 1);
|
|
8874
|
+
const scaledH2 = (object.height ?? 0) * (object.scaleY ?? 1);
|
|
8875
|
+
const { width: fw, height: fh2 } = convertToVideoDimensions(
|
|
8876
|
+
scaledW2,
|
|
8877
|
+
scaledH2,
|
|
8878
|
+
context.canvasMetadata
|
|
8879
|
+
);
|
|
8880
|
+
const updatedFrameSize = [fw, fh2];
|
|
8881
|
+
const frame2 = element.frame;
|
|
8882
|
+
return {
|
|
8883
|
+
element: {
|
|
8884
|
+
...element,
|
|
8885
|
+
frame: {
|
|
8886
|
+
...frame2,
|
|
8887
|
+
rotation: getObjectCanvasAngle(object),
|
|
8888
|
+
size: updatedFrameSize,
|
|
8889
|
+
x: x2,
|
|
8890
|
+
y: y2
|
|
8891
|
+
}
|
|
8892
|
+
}
|
|
8893
|
+
};
|
|
8894
|
+
}
|
|
8895
|
+
const scaledW = (object.width ?? 0) * (object.scaleX ?? 1);
|
|
8896
|
+
const scaledH = (object.height ?? 0) * (object.scaleY ?? 1);
|
|
8897
|
+
const { width, height } = convertToVideoDimensions(
|
|
8898
|
+
scaledW,
|
|
8899
|
+
scaledH,
|
|
8900
|
+
context.canvasMetadata
|
|
8901
|
+
);
|
|
8902
|
+
return {
|
|
8903
|
+
element: {
|
|
8904
|
+
...element,
|
|
8905
|
+
props: {
|
|
8906
|
+
...element.props,
|
|
8907
|
+
rotation: getObjectCanvasAngle(object),
|
|
8908
|
+
width,
|
|
8909
|
+
height,
|
|
8910
|
+
x: x2,
|
|
8911
|
+
y: y2
|
|
8912
|
+
}
|
|
8913
|
+
}
|
|
8914
|
+
};
|
|
8915
|
+
}
|
|
8916
|
+
};
|
|
8545
8917
|
class ElementController {
|
|
8546
8918
|
constructor() {
|
|
8547
8919
|
__publicField2(this, "elements", /* @__PURE__ */ new Map());
|
|
@@ -8563,6 +8935,7 @@ function registerElements() {
|
|
|
8563
8935
|
elementController.register(RectElement);
|
|
8564
8936
|
elementController.register(CircleElement);
|
|
8565
8937
|
elementController.register(TextElement);
|
|
8938
|
+
elementController.register(EmojiElement);
|
|
8566
8939
|
elementController.register(CaptionElement);
|
|
8567
8940
|
elementController.register(WatermarkElement);
|
|
8568
8941
|
elementController.register(ArrowElement);
|
|
@@ -9147,6 +9520,8 @@ const DEFAULT_ELEMENT_COLORS = {
|
|
|
9147
9520
|
animation: "#4B9B78",
|
|
9148
9521
|
/** Icon element color - bright orchid */
|
|
9149
9522
|
icon: "#A76CD4",
|
|
9523
|
+
/** Emoji element color - warm amber */
|
|
9524
|
+
emoji: "#F59E0B",
|
|
9150
9525
|
/** Circle element color - deep byzantium */
|
|
9151
9526
|
circle: "#703D8B",
|
|
9152
9527
|
/** Effect element color - cyan accent for global effects */
|
|
@@ -19035,6 +19410,102 @@ const setElementColors = (colors) => {
|
|
|
19035
19410
|
...colors
|
|
19036
19411
|
};
|
|
19037
19412
|
};
|
|
19413
|
+
const VIEWPORT_MARGIN = 8;
|
|
19414
|
+
function clampMenuPosition(clientX, clientY, width, height) {
|
|
19415
|
+
const vw2 = window.innerWidth;
|
|
19416
|
+
const vh3 = window.innerHeight;
|
|
19417
|
+
const maxLeft = Math.max(VIEWPORT_MARGIN, vw2 - width - VIEWPORT_MARGIN);
|
|
19418
|
+
const maxTop = Math.max(VIEWPORT_MARGIN, vh3 - height - VIEWPORT_MARGIN);
|
|
19419
|
+
return {
|
|
19420
|
+
left: Math.min(Math.max(VIEWPORT_MARGIN, clientX), maxLeft),
|
|
19421
|
+
top: Math.min(Math.max(VIEWPORT_MARGIN, clientY), maxTop)
|
|
19422
|
+
};
|
|
19423
|
+
}
|
|
19424
|
+
const TrackElementContextMenu = ({
|
|
19425
|
+
x: x2,
|
|
19426
|
+
y: y2,
|
|
19427
|
+
canSplit,
|
|
19428
|
+
onSplit,
|
|
19429
|
+
onDelete,
|
|
19430
|
+
onClose
|
|
19431
|
+
}) => {
|
|
19432
|
+
const menuRef = useRef(null);
|
|
19433
|
+
const [position, setPosition] = useState(() => ({
|
|
19434
|
+
left: x2,
|
|
19435
|
+
top: y2
|
|
19436
|
+
}));
|
|
19437
|
+
const reposition = useCallback(() => {
|
|
19438
|
+
const el = menuRef.current;
|
|
19439
|
+
if (!el) return;
|
|
19440
|
+
const { width, height } = el.getBoundingClientRect();
|
|
19441
|
+
setPosition(clampMenuPosition(x2, y2, width, height));
|
|
19442
|
+
}, [x2, y2]);
|
|
19443
|
+
useLayoutEffect(() => {
|
|
19444
|
+
reposition();
|
|
19445
|
+
}, [reposition]);
|
|
19446
|
+
useEffect(() => {
|
|
19447
|
+
window.addEventListener("resize", reposition);
|
|
19448
|
+
return () => window.removeEventListener("resize", reposition);
|
|
19449
|
+
}, [reposition]);
|
|
19450
|
+
useEffect(() => {
|
|
19451
|
+
const handleClickOutside = (e3) => {
|
|
19452
|
+
if (menuRef.current && !menuRef.current.contains(e3.target)) {
|
|
19453
|
+
onClose();
|
|
19454
|
+
}
|
|
19455
|
+
};
|
|
19456
|
+
const handleEscape = (e3) => {
|
|
19457
|
+
if (e3.key === "Escape") onClose();
|
|
19458
|
+
};
|
|
19459
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
19460
|
+
document.addEventListener("keydown", handleEscape);
|
|
19461
|
+
return () => {
|
|
19462
|
+
document.removeEventListener("mousedown", handleClickOutside);
|
|
19463
|
+
document.removeEventListener("keydown", handleEscape);
|
|
19464
|
+
};
|
|
19465
|
+
}, [onClose]);
|
|
19466
|
+
const wrap = (fn2) => {
|
|
19467
|
+
fn2();
|
|
19468
|
+
onClose();
|
|
19469
|
+
};
|
|
19470
|
+
const menu = /* @__PURE__ */ jsxs(
|
|
19471
|
+
"div",
|
|
19472
|
+
{
|
|
19473
|
+
ref: menuRef,
|
|
19474
|
+
className: "twick-canvas-context-menu",
|
|
19475
|
+
style: { left: position.left, top: position.top },
|
|
19476
|
+
role: "menu",
|
|
19477
|
+
children: [
|
|
19478
|
+
/* @__PURE__ */ jsx(
|
|
19479
|
+
"button",
|
|
19480
|
+
{
|
|
19481
|
+
type: "button",
|
|
19482
|
+
className: "twick-canvas-context-menu-item",
|
|
19483
|
+
onClick: () => wrap(onSplit),
|
|
19484
|
+
disabled: !canSplit,
|
|
19485
|
+
role: "menuitem",
|
|
19486
|
+
style: !canSplit ? { opacity: 0.45, cursor: "not-allowed" } : void 0,
|
|
19487
|
+
children: "Split at playhead"
|
|
19488
|
+
}
|
|
19489
|
+
),
|
|
19490
|
+
/* @__PURE__ */ jsx("div", { className: "twick-canvas-context-menu-separator", role: "separator" }),
|
|
19491
|
+
/* @__PURE__ */ jsx(
|
|
19492
|
+
"button",
|
|
19493
|
+
{
|
|
19494
|
+
type: "button",
|
|
19495
|
+
className: "twick-canvas-context-menu-item twick-canvas-context-menu-item-danger",
|
|
19496
|
+
onClick: () => wrap(onDelete),
|
|
19497
|
+
role: "menuitem",
|
|
19498
|
+
children: "Delete"
|
|
19499
|
+
}
|
|
19500
|
+
)
|
|
19501
|
+
]
|
|
19502
|
+
}
|
|
19503
|
+
);
|
|
19504
|
+
if (typeof document === "undefined") {
|
|
19505
|
+
return null;
|
|
19506
|
+
}
|
|
19507
|
+
return createPortal(menu, document.body);
|
|
19508
|
+
};
|
|
19038
19509
|
const TrackElementView = ({
|
|
19039
19510
|
element,
|
|
19040
19511
|
parentWidth,
|
|
@@ -19047,13 +19518,20 @@ const TrackElementView = ({
|
|
|
19047
19518
|
onDrag,
|
|
19048
19519
|
allowOverlap = false,
|
|
19049
19520
|
onDragStateChange,
|
|
19050
|
-
elementColors
|
|
19521
|
+
elementColors,
|
|
19522
|
+
currentTime = 0,
|
|
19523
|
+
onContextMenuTarget,
|
|
19524
|
+
onDeleteElement,
|
|
19525
|
+
onSplitElement
|
|
19051
19526
|
}) => {
|
|
19052
19527
|
var _a, _b;
|
|
19053
19528
|
const ref = useRef(null);
|
|
19054
19529
|
const dragType = useRef(null);
|
|
19055
19530
|
const lastPosRef = useRef(null);
|
|
19056
19531
|
const [isDragging2, setIsDragging] = useState(false);
|
|
19532
|
+
const [clipMenu, setClipMenu] = useState(
|
|
19533
|
+
null
|
|
19534
|
+
);
|
|
19057
19535
|
const [position, setPosition] = useState({
|
|
19058
19536
|
start: 0,
|
|
19059
19537
|
end: 0
|
|
@@ -19083,6 +19561,7 @@ const TrackElementView = ({
|
|
|
19083
19561
|
newStart = nextStart - span;
|
|
19084
19562
|
}
|
|
19085
19563
|
}
|
|
19564
|
+
newStart = Math.max(0, Math.min(newStart, duration - span));
|
|
19086
19565
|
return {
|
|
19087
19566
|
start: newStart,
|
|
19088
19567
|
end: newStart + span
|
|
@@ -19105,6 +19584,7 @@ const TrackElementView = ({
|
|
|
19105
19584
|
if (prevEnd !== null && !allowOverlap && newStart < prevEnd) {
|
|
19106
19585
|
newStart = prevEnd;
|
|
19107
19586
|
}
|
|
19587
|
+
newStart = Math.max(0, Math.min(newStart, prev.end - MIN_DURATION));
|
|
19108
19588
|
return {
|
|
19109
19589
|
start: newStart,
|
|
19110
19590
|
end: prev.end
|
|
@@ -19129,6 +19609,7 @@ const TrackElementView = ({
|
|
|
19129
19609
|
newEnd = nextStart;
|
|
19130
19610
|
}
|
|
19131
19611
|
}
|
|
19612
|
+
newEnd = Math.max(prev.start + MIN_DURATION, Math.min(newEnd, duration));
|
|
19132
19613
|
return {
|
|
19133
19614
|
start: prev.start,
|
|
19134
19615
|
end: newEnd
|
|
@@ -19166,7 +19647,7 @@ const TrackElementView = ({
|
|
|
19166
19647
|
};
|
|
19167
19648
|
const getElementColor = (elementType) => {
|
|
19168
19649
|
const colors = elementColors || ELEMENT_COLORS;
|
|
19169
|
-
const key = elementType === TIMELINE_ELEMENT_TYPE.VIDEO ? "video" : elementType === TIMELINE_ELEMENT_TYPE.AUDIO ? "audio" : elementType === TIMELINE_ELEMENT_TYPE.IMAGE ? "image" : elementType === TIMELINE_ELEMENT_TYPE.TEXT ? "text" : elementType === TIMELINE_ELEMENT_TYPE.CAPTION ? "caption" : elementType === TIMELINE_ELEMENT_TYPE.RECT ? "rect" : elementType === TIMELINE_ELEMENT_TYPE.CIRCLE ? "circle" : elementType === TIMELINE_ELEMENT_TYPE.ICON ? "icon" : elementType === TIMELINE_ELEMENT_TYPE.EFFECT ? "effect" : "element";
|
|
19650
|
+
const key = elementType === TIMELINE_ELEMENT_TYPE.VIDEO ? "video" : elementType === TIMELINE_ELEMENT_TYPE.AUDIO ? "audio" : elementType === TIMELINE_ELEMENT_TYPE.IMAGE ? "image" : elementType === TIMELINE_ELEMENT_TYPE.TEXT ? "text" : elementType === TIMELINE_ELEMENT_TYPE.CAPTION ? "caption" : elementType === TIMELINE_ELEMENT_TYPE.RECT ? "rect" : elementType === TIMELINE_ELEMENT_TYPE.CIRCLE ? "circle" : elementType === TIMELINE_ELEMENT_TYPE.ICON ? "icon" : elementType === TIMELINE_ELEMENT_TYPE.EMOJI ? "emoji" : elementType === TIMELINE_ELEMENT_TYPE.EFFECT ? "effect" : "element";
|
|
19170
19651
|
if (key in colors) {
|
|
19171
19652
|
return colors[key];
|
|
19172
19653
|
}
|
|
@@ -19176,6 +19657,16 @@ const TrackElementView = ({
|
|
|
19176
19657
|
return selectedIds.has(element.getId());
|
|
19177
19658
|
}, [selectedIds, element]);
|
|
19178
19659
|
const hasHandles = (selectedItem == null ? void 0 : selectedItem.getId()) === element.getId();
|
|
19660
|
+
const contextActionsEnabled = Boolean(
|
|
19661
|
+
onDeleteElement && onSplitElement && onContextMenuTarget
|
|
19662
|
+
);
|
|
19663
|
+
const handleContextMenu = (e3) => {
|
|
19664
|
+
if (!contextActionsEnabled) return;
|
|
19665
|
+
e3.preventDefault();
|
|
19666
|
+
e3.stopPropagation();
|
|
19667
|
+
onContextMenuTarget == null ? void 0 : onContextMenuTarget(element);
|
|
19668
|
+
setClipMenu({ x: e3.clientX, y: e3.clientY });
|
|
19669
|
+
};
|
|
19179
19670
|
const motionProps = {
|
|
19180
19671
|
ref,
|
|
19181
19672
|
className: `twick-track-element ${isSelected ? "twick-track-element-selected" : "twick-track-element-default"} ${isDragging2 ? "twick-track-element-dragging" : ""}`,
|
|
@@ -19196,6 +19687,7 @@ const TrackElementView = ({
|
|
|
19196
19687
|
onSelection(element, e3);
|
|
19197
19688
|
}
|
|
19198
19689
|
},
|
|
19690
|
+
onContextMenu: handleContextMenu,
|
|
19199
19691
|
style: {
|
|
19200
19692
|
backgroundColor: getElementColor(element.getType()),
|
|
19201
19693
|
width: `${(position.end - position.start) / duration * 100}%`,
|
|
@@ -19203,39 +19695,52 @@ const TrackElementView = ({
|
|
|
19203
19695
|
touchAction: "none"
|
|
19204
19696
|
}
|
|
19205
19697
|
};
|
|
19206
|
-
return /* @__PURE__ */
|
|
19207
|
-
|
|
19208
|
-
|
|
19209
|
-
{
|
|
19210
|
-
style: { touchAction: "none", zIndex: isSelected ? 100 : 1 },
|
|
19211
|
-
...bindStartHandle(),
|
|
19212
|
-
className: "twick-track-element-handle twick-track-element-handle-start"
|
|
19213
|
-
}
|
|
19214
|
-
) : null,
|
|
19215
|
-
/* @__PURE__ */ jsx("div", { className: "twick-track-element-content", children: element.getType() === 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() }),
|
|
19216
|
-
hasHandles ? /* @__PURE__ */ jsx(
|
|
19217
|
-
"div",
|
|
19698
|
+
return /* @__PURE__ */ jsxs(motion.div, { ...motionProps, children: [
|
|
19699
|
+
clipMenu && contextActionsEnabled ? /* @__PURE__ */ jsx(
|
|
19700
|
+
TrackElementContextMenu,
|
|
19218
19701
|
{
|
|
19219
|
-
|
|
19220
|
-
|
|
19221
|
-
|
|
19702
|
+
x: clipMenu.x,
|
|
19703
|
+
y: clipMenu.y,
|
|
19704
|
+
canSplit: canSplitElement(element, currentTime),
|
|
19705
|
+
onSplit: () => onSplitElement == null ? void 0 : onSplitElement(element, currentTime),
|
|
19706
|
+
onDelete: () => onDeleteElement == null ? void 0 : onDeleteElement(element),
|
|
19707
|
+
onClose: () => setClipMenu(null)
|
|
19222
19708
|
}
|
|
19223
19709
|
) : null,
|
|
19224
|
-
|
|
19225
|
-
|
|
19710
|
+
/* @__PURE__ */ jsxs("div", { style: { touchAction: "none", height: "100%" }, ...bind(), children: [
|
|
19711
|
+
hasHandles ? /* @__PURE__ */ jsx(
|
|
19226
19712
|
"div",
|
|
19227
19713
|
{
|
|
19228
|
-
|
|
19229
|
-
|
|
19230
|
-
|
|
19231
|
-
|
|
19232
|
-
|
|
19233
|
-
|
|
19234
|
-
|
|
19235
|
-
|
|
19236
|
-
|
|
19237
|
-
|
|
19238
|
-
|
|
19714
|
+
style: { touchAction: "none", zIndex: isSelected ? 100 : 1 },
|
|
19715
|
+
...bindStartHandle(),
|
|
19716
|
+
className: "twick-track-element-handle twick-track-element-handle-start"
|
|
19717
|
+
}
|
|
19718
|
+
) : null,
|
|
19719
|
+
/* @__PURE__ */ jsx("div", { className: "twick-track-element-content", children: element.getType() === 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() }),
|
|
19720
|
+
hasHandles ? /* @__PURE__ */ jsx(
|
|
19721
|
+
"div",
|
|
19722
|
+
{
|
|
19723
|
+
style: { touchAction: "none", zIndex: isSelected ? 100 : 1 },
|
|
19724
|
+
...bindEndHandle(),
|
|
19725
|
+
className: "twick-track-element-handle twick-track-element-handle-end"
|
|
19726
|
+
}
|
|
19727
|
+
) : null,
|
|
19728
|
+
element.getFrameEffects ? element.getFrameEffects().map((frameEffect) => {
|
|
19729
|
+
return /* @__PURE__ */ jsx(
|
|
19730
|
+
"div",
|
|
19731
|
+
{
|
|
19732
|
+
className: "twick-track-element-frame-effect",
|
|
19733
|
+
style: {
|
|
19734
|
+
backgroundColor: getElementColor("frameEffect"),
|
|
19735
|
+
width: `${(frameEffect.e - frameEffect.s) / element.getDuration() * 100}%`,
|
|
19736
|
+
left: `${frameEffect.s / element.getDuration() * 100}%`
|
|
19737
|
+
}
|
|
19738
|
+
},
|
|
19739
|
+
frameEffect.s + frameEffect.e
|
|
19740
|
+
);
|
|
19741
|
+
}) : null
|
|
19742
|
+
] })
|
|
19743
|
+
] });
|
|
19239
19744
|
};
|
|
19240
19745
|
const TrackBase = ({
|
|
19241
19746
|
duration,
|
|
@@ -19248,11 +19753,21 @@ const TrackBase = ({
|
|
|
19248
19753
|
onDrag,
|
|
19249
19754
|
allowOverlap = false,
|
|
19250
19755
|
onDragStateChange,
|
|
19251
|
-
elementColors
|
|
19756
|
+
elementColors,
|
|
19757
|
+
currentTime,
|
|
19758
|
+
onContextMenuTarget,
|
|
19759
|
+
onDeleteElement,
|
|
19760
|
+
onSplitElement
|
|
19252
19761
|
}) => {
|
|
19253
19762
|
const trackRef = useRef(null);
|
|
19254
19763
|
const trackWidthStyle = `${Math.max(100, duration * zoom * 100)}px`;
|
|
19255
|
-
const elements = track.getElements()
|
|
19764
|
+
const elements = [...track.getElements()].sort((a2, b2) => {
|
|
19765
|
+
const byStart = a2.getStart() - b2.getStart();
|
|
19766
|
+
if (byStart !== 0) return byStart;
|
|
19767
|
+
const byEnd = a2.getEnd() - b2.getEnd();
|
|
19768
|
+
if (byEnd !== 0) return byEnd;
|
|
19769
|
+
return a2.getId().localeCompare(b2.getId());
|
|
19770
|
+
});
|
|
19256
19771
|
return /* @__PURE__ */ jsx(
|
|
19257
19772
|
"div",
|
|
19258
19773
|
{
|
|
@@ -19274,6 +19789,10 @@ const TrackBase = ({
|
|
|
19274
19789
|
onDrag,
|
|
19275
19790
|
onDragStateChange,
|
|
19276
19791
|
elementColors,
|
|
19792
|
+
currentTime,
|
|
19793
|
+
onContextMenuTarget,
|
|
19794
|
+
onDeleteElement,
|
|
19795
|
+
onSplitElement,
|
|
19277
19796
|
nextStart: index < elements.length - 1 ? elements[index + 1].getStart() : null,
|
|
19278
19797
|
prevEnd: index > 0 ? elements[index - 1].getEnd() : 0
|
|
19279
19798
|
},
|
|
@@ -19578,7 +20097,11 @@ function TimelineView({
|
|
|
19578
20097
|
onDropOnTimeline,
|
|
19579
20098
|
videoResolution,
|
|
19580
20099
|
enableDropOnTimeline = true,
|
|
19581
|
-
chapters = []
|
|
20100
|
+
chapters = [],
|
|
20101
|
+
currentTime = 0,
|
|
20102
|
+
onContextMenuTarget,
|
|
20103
|
+
onDeleteElement,
|
|
20104
|
+
onSplitElement
|
|
19582
20105
|
}) {
|
|
19583
20106
|
const containerRef = useRef(null);
|
|
19584
20107
|
const seekContainerRef = useRef(null);
|
|
@@ -19847,7 +20370,11 @@ function TimelineView({
|
|
|
19847
20370
|
onDragStateChange: (isDragging2, el) => {
|
|
19848
20371
|
setDraggingElementId(isDragging2 && el ? el.getId() : null);
|
|
19849
20372
|
},
|
|
19850
|
-
elementColors
|
|
20373
|
+
elementColors,
|
|
20374
|
+
currentTime,
|
|
20375
|
+
onContextMenuTarget,
|
|
20376
|
+
onDeleteElement,
|
|
20377
|
+
onSplitElement
|
|
19851
20378
|
}
|
|
19852
20379
|
)
|
|
19853
20380
|
] }),
|
|
@@ -19906,7 +20433,8 @@ const useTimelineManager = () => {
|
|
|
19906
20433
|
if (dragType === DRAG_TYPE.START) {
|
|
19907
20434
|
if (element instanceof VideoElement$1 || element instanceof AudioElement) {
|
|
19908
20435
|
const elementProps = element.getProps();
|
|
19909
|
-
const
|
|
20436
|
+
const playbackRate = (elementProps == null ? void 0 : elementProps.playbackRate) || 1;
|
|
20437
|
+
const delta = (updates.start - element.getStart()) * playbackRate;
|
|
19910
20438
|
if (element instanceof AudioElement) {
|
|
19911
20439
|
element.setStartAt(element.getStartAt() + delta);
|
|
19912
20440
|
} else {
|
|
@@ -20019,6 +20547,38 @@ const useTimelineManager = () => {
|
|
|
20019
20547
|
totalDuration
|
|
20020
20548
|
};
|
|
20021
20549
|
};
|
|
20550
|
+
const useTimelineControl = () => {
|
|
20551
|
+
const { editor, setSelectedItem, selectedIds } = useTimelineContext();
|
|
20552
|
+
const deleteItem = (item) => {
|
|
20553
|
+
var _a;
|
|
20554
|
+
const tracks = ((_a = editor.getTimelineData()) == null ? void 0 : _a.tracks) ?? [];
|
|
20555
|
+
const toDelete = item !== void 0 ? [item] : resolveIds(selectedIds, tracks);
|
|
20556
|
+
for (const el of toDelete) {
|
|
20557
|
+
if (el instanceof Track) {
|
|
20558
|
+
editor.removeTrack(el);
|
|
20559
|
+
} else if (el instanceof TrackElement) {
|
|
20560
|
+
editor.removeElement(el);
|
|
20561
|
+
}
|
|
20562
|
+
}
|
|
20563
|
+
setSelectedItem(null);
|
|
20564
|
+
};
|
|
20565
|
+
const splitElement = (element, currentTime) => {
|
|
20566
|
+
if (!canSplitElement(element, currentTime)) return;
|
|
20567
|
+
void editor.splitElement(element, currentTime);
|
|
20568
|
+
};
|
|
20569
|
+
const handleUndo = () => {
|
|
20570
|
+
editor.undo();
|
|
20571
|
+
};
|
|
20572
|
+
const handleRedo = () => {
|
|
20573
|
+
editor.redo();
|
|
20574
|
+
};
|
|
20575
|
+
return {
|
|
20576
|
+
splitElement,
|
|
20577
|
+
deleteItem,
|
|
20578
|
+
handleUndo,
|
|
20579
|
+
handleRedo
|
|
20580
|
+
};
|
|
20581
|
+
};
|
|
20022
20582
|
function useTimelineSelection() {
|
|
20023
20583
|
const { editor, selectedIds, setSelection, setSelectedItem } = useTimelineContext();
|
|
20024
20584
|
const handleItemSelect = useCallback(
|
|
@@ -20099,8 +20659,9 @@ const TimelineManager = ({
|
|
|
20099
20659
|
elementColors
|
|
20100
20660
|
}) => {
|
|
20101
20661
|
var _a, _b;
|
|
20102
|
-
const { playerState } = useLivePlayerContext();
|
|
20662
|
+
const { playerState, currentTime } = useLivePlayerContext();
|
|
20103
20663
|
const { followPlayheadEnabled, editor, videoResolution, setSelectedItem } = useTimelineContext();
|
|
20664
|
+
const { deleteItem, splitElement } = useTimelineControl();
|
|
20104
20665
|
const {
|
|
20105
20666
|
timelineData,
|
|
20106
20667
|
totalDuration,
|
|
@@ -20121,6 +20682,12 @@ const TimelineManager = ({
|
|
|
20121
20682
|
setPlayheadState(state);
|
|
20122
20683
|
}, []);
|
|
20123
20684
|
const isPlayheadActive = followPlayheadEnabled && playerState === PLAYER_STATE.PLAYING || playheadState.isDragging;
|
|
20685
|
+
const handleContextMenuTarget = useCallback(
|
|
20686
|
+
(element) => {
|
|
20687
|
+
setSelectedItem(element);
|
|
20688
|
+
},
|
|
20689
|
+
[setSelectedItem]
|
|
20690
|
+
);
|
|
20124
20691
|
const handleDropOnTimeline = useCallback(
|
|
20125
20692
|
async (params) => {
|
|
20126
20693
|
const { track, timeSec, type, url } = params;
|
|
@@ -20168,6 +20735,10 @@ const TimelineManager = ({
|
|
|
20168
20735
|
onEmptyClick: handleEmptyClick,
|
|
20169
20736
|
onMarqueeSelect: handleMarqueeSelect,
|
|
20170
20737
|
elementColors,
|
|
20738
|
+
currentTime,
|
|
20739
|
+
onContextMenuTarget: handleContextMenuTarget,
|
|
20740
|
+
onDeleteElement: (el) => deleteItem(el),
|
|
20741
|
+
onSplitElement: (el, t2) => splitElement(el, t2),
|
|
20171
20742
|
playheadPositionPx: playheadState.positionPx,
|
|
20172
20743
|
isPlayheadActive,
|
|
20173
20744
|
chapters: ((_a = timelineData == null ? void 0 : timelineData.metadata) == null ? void 0 : _a.chapters) ?? [],
|
|
@@ -20251,11 +20822,12 @@ const PlayerControls = ({
|
|
|
20251
20822
|
}
|
|
20252
20823
|
}, [selectedIds.size, onDelete]);
|
|
20253
20824
|
const hasSelection = selectedIds.size > 0;
|
|
20825
|
+
const canSplitSelected = selectedItem instanceof TrackElement ? canSplitElement(selectedItem, currentTime) : false;
|
|
20254
20826
|
const handleSplit = useCallback(() => {
|
|
20255
|
-
if (selectedItem instanceof TrackElement && onSplit) {
|
|
20827
|
+
if (selectedItem instanceof TrackElement && onSplit && canSplitSelected) {
|
|
20256
20828
|
onSplit(selectedItem, currentTime);
|
|
20257
20829
|
}
|
|
20258
|
-
}, [selectedItem, onSplit, currentTime]);
|
|
20830
|
+
}, [selectedItem, onSplit, currentTime, canSplitSelected]);
|
|
20259
20831
|
const handleZoomIn = useCallback(() => {
|
|
20260
20832
|
if (setZoomLevel && zoomLevel < MAX_ZOOM) {
|
|
20261
20833
|
setZoomLevel(zoomLevel + ZOOM_STEP);
|
|
@@ -20282,9 +20854,9 @@ const PlayerControls = ({
|
|
|
20282
20854
|
"button",
|
|
20283
20855
|
{
|
|
20284
20856
|
onClick: handleSplit,
|
|
20285
|
-
disabled: !
|
|
20857
|
+
disabled: !canSplitSelected,
|
|
20286
20858
|
title: "Split",
|
|
20287
|
-
className: `control-btn split-btn ${!
|
|
20859
|
+
className: `control-btn split-btn ${!canSplitSelected ? "btn-disabled" : ""}`,
|
|
20288
20860
|
children: /* @__PURE__ */ jsx(Scissors, { className: "icon-md" })
|
|
20289
20861
|
}
|
|
20290
20862
|
),
|
|
@@ -20398,37 +20970,6 @@ const usePlayerControl = () => {
|
|
|
20398
20970
|
togglePlayback
|
|
20399
20971
|
};
|
|
20400
20972
|
};
|
|
20401
|
-
const useTimelineControl = () => {
|
|
20402
|
-
const { editor, setSelectedItem, selectedIds } = useTimelineContext();
|
|
20403
|
-
const deleteItem = (item) => {
|
|
20404
|
-
var _a;
|
|
20405
|
-
const tracks = ((_a = editor.getTimelineData()) == null ? void 0 : _a.tracks) ?? [];
|
|
20406
|
-
const toDelete = item !== void 0 ? [item] : resolveIds(selectedIds, tracks);
|
|
20407
|
-
for (const el of toDelete) {
|
|
20408
|
-
if (el instanceof Track) {
|
|
20409
|
-
editor.removeTrack(el);
|
|
20410
|
-
} else if (el instanceof TrackElement) {
|
|
20411
|
-
editor.removeElement(el);
|
|
20412
|
-
}
|
|
20413
|
-
}
|
|
20414
|
-
setSelectedItem(null);
|
|
20415
|
-
};
|
|
20416
|
-
const splitElement = (element, currentTime) => {
|
|
20417
|
-
editor.splitElement(element, currentTime);
|
|
20418
|
-
};
|
|
20419
|
-
const handleUndo = () => {
|
|
20420
|
-
editor.undo();
|
|
20421
|
-
};
|
|
20422
|
-
const handleRedo = () => {
|
|
20423
|
-
editor.redo();
|
|
20424
|
-
};
|
|
20425
|
-
return {
|
|
20426
|
-
splitElement,
|
|
20427
|
-
deleteItem,
|
|
20428
|
-
handleUndo,
|
|
20429
|
-
handleRedo
|
|
20430
|
-
};
|
|
20431
|
-
};
|
|
20432
20973
|
function shouldIgnoreKeydown() {
|
|
20433
20974
|
const active = document.activeElement;
|
|
20434
20975
|
if (!active) return false;
|