@twick/timeline 0.14.2 → 0.14.4
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/README.md +86 -0
- package/dist/context/timeline-context.d.ts +111 -2
- package/dist/core/addOns/animation.d.ts +3 -0
- package/dist/core/editor/timeline.editor.d.ts +3 -3
- package/dist/core/elements/base.element.d.ts +4 -0
- package/dist/core/elements/circle.element.d.ts +4 -0
- package/dist/core/elements/icon.element.d.ts +8 -3
- package/dist/core/elements/rect.element.d.ts +8 -0
- package/dist/core/track/track.d.ts +325 -19
- package/dist/core/visitor/element-adder.d.ts +122 -2
- package/dist/index.js +562 -40
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +562 -40
- package/dist/index.mjs.map +1 -1
- package/dist/types/index.d.ts +12 -157
- package/dist/types.d.ts +128 -0
- package/dist/utils/constants.d.ts +172 -35
- package/dist/utils/timeline.utils.d.ts +112 -0
- package/package.json +4 -4
package/dist/index.mjs
CHANGED
|
@@ -4,13 +4,19 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
4
4
|
import { jsx } from "react/jsx-runtime";
|
|
5
5
|
import React, { useState, createContext, useContext, useRef, useMemo, useEffect } from "react";
|
|
6
6
|
const PLAYER_STATE = {
|
|
7
|
+
/** Player is refreshing/reloading content */
|
|
7
8
|
REFRESH: "Refresh",
|
|
9
|
+
/** Player is actively playing content */
|
|
8
10
|
PLAYING: "Playing",
|
|
11
|
+
/** Player is paused */
|
|
9
12
|
PAUSED: "Paused"
|
|
10
13
|
};
|
|
11
14
|
const CAPTION_STYLE = {
|
|
15
|
+
/** Highlights background of each word */
|
|
12
16
|
WORD_BG_HIGHLIGHT: "highlight_bg",
|
|
17
|
+
/** Animates text word by word */
|
|
13
18
|
WORD_BY_WORD: "word_by_word",
|
|
19
|
+
/** Animates text word by word with background highlighting */
|
|
14
20
|
WORD_BY_WORD_WITH_BG: "word_by_word_with_bg"
|
|
15
21
|
};
|
|
16
22
|
const CAPTION_STYLE_OPTIONS = {
|
|
@@ -28,34 +34,54 @@ const CAPTION_STYLE_OPTIONS = {
|
|
|
28
34
|
}
|
|
29
35
|
};
|
|
30
36
|
const CAPTION_FONT = {
|
|
37
|
+
/** Font size in pixels */
|
|
31
38
|
size: 40
|
|
32
39
|
};
|
|
33
40
|
const CAPTION_COLOR = {
|
|
41
|
+
/** Text color in hex format */
|
|
34
42
|
text: "#ffffff",
|
|
43
|
+
/** Highlight color in hex format */
|
|
35
44
|
highlight: "#ff4081",
|
|
45
|
+
/** Background color in hex format */
|
|
36
46
|
bgColor: "#8C52FF"
|
|
37
47
|
};
|
|
38
48
|
const WORDS_PER_PHRASE = 4;
|
|
39
49
|
const TIMELINE_ACTION = {
|
|
50
|
+
/** No action being performed */
|
|
40
51
|
NONE: "none",
|
|
52
|
+
/** Setting the player state (play/pause) */
|
|
41
53
|
SET_PLAYER_STATE: "setPlayerState",
|
|
54
|
+
/** Updating player data */
|
|
42
55
|
UPDATE_PLAYER_DATA: "updatePlayerData",
|
|
56
|
+
/** Player has been updated */
|
|
43
57
|
ON_PLAYER_UPDATED: "onPlayerUpdated"
|
|
44
58
|
};
|
|
45
59
|
const TIMELINE_ELEMENT_TYPE = {
|
|
60
|
+
/** Video element type */
|
|
46
61
|
VIDEO: "video",
|
|
62
|
+
/** Caption element type */
|
|
47
63
|
CAPTION: "caption",
|
|
64
|
+
/** Image element type */
|
|
48
65
|
IMAGE: "image",
|
|
66
|
+
/** Audio element type */
|
|
49
67
|
AUDIO: "audio",
|
|
68
|
+
/** Text element type */
|
|
50
69
|
TEXT: "text",
|
|
70
|
+
/** Rectangle element type */
|
|
51
71
|
RECT: "rect",
|
|
72
|
+
/** Circle element type */
|
|
52
73
|
CIRCLE: "circle",
|
|
74
|
+
/** Icon element type */
|
|
53
75
|
ICON: "icon"
|
|
54
76
|
};
|
|
55
77
|
const PROCESS_STATE = {
|
|
78
|
+
/** Process is idle */
|
|
56
79
|
IDLE: "Idle",
|
|
80
|
+
/** Process is currently running */
|
|
57
81
|
PROCESSING: "Processing",
|
|
82
|
+
/** Process has completed successfully */
|
|
58
83
|
COMPLETED: "Completed",
|
|
84
|
+
/** Process has failed */
|
|
59
85
|
FAILED: "Failed"
|
|
60
86
|
};
|
|
61
87
|
const imageDimensionsCache = {};
|
|
@@ -456,7 +482,9 @@ class TrackElement {
|
|
|
456
482
|
this.type = type;
|
|
457
483
|
this.props = {
|
|
458
484
|
x: 0,
|
|
459
|
-
y: 0
|
|
485
|
+
y: 0,
|
|
486
|
+
opacity: 1,
|
|
487
|
+
rotation: 0
|
|
460
488
|
};
|
|
461
489
|
}
|
|
462
490
|
getId() {
|
|
@@ -493,6 +521,12 @@ class TrackElement {
|
|
|
493
521
|
y: ((_b = this.props) == null ? void 0 : _b.y) ?? 0
|
|
494
522
|
};
|
|
495
523
|
}
|
|
524
|
+
getRotation() {
|
|
525
|
+
return this.props.rotation ?? 0;
|
|
526
|
+
}
|
|
527
|
+
getOpacity() {
|
|
528
|
+
return this.props.opacity ?? 1;
|
|
529
|
+
}
|
|
496
530
|
setId(id) {
|
|
497
531
|
this.id = id;
|
|
498
532
|
return this;
|
|
@@ -526,6 +560,14 @@ class TrackElement {
|
|
|
526
560
|
this.props.y = position.y;
|
|
527
561
|
return this;
|
|
528
562
|
}
|
|
563
|
+
setRotation(rotation) {
|
|
564
|
+
this.props.rotation = rotation;
|
|
565
|
+
return this;
|
|
566
|
+
}
|
|
567
|
+
setOpacity(opacity) {
|
|
568
|
+
this.props.opacity = opacity;
|
|
569
|
+
return this;
|
|
570
|
+
}
|
|
529
571
|
setProps(props) {
|
|
530
572
|
this.props = structuredClone(props);
|
|
531
573
|
return this;
|
|
@@ -1014,13 +1056,35 @@ class CaptionElement extends TrackElement {
|
|
|
1014
1056
|
}
|
|
1015
1057
|
}
|
|
1016
1058
|
class IconElement extends TrackElement {
|
|
1017
|
-
constructor(src, size) {
|
|
1059
|
+
constructor(src, size, fill = "#866bbf") {
|
|
1018
1060
|
super(TIMELINE_ELEMENT_TYPE.ICON);
|
|
1019
1061
|
this.props = {
|
|
1020
1062
|
src,
|
|
1063
|
+
fill,
|
|
1021
1064
|
size
|
|
1022
1065
|
};
|
|
1023
1066
|
}
|
|
1067
|
+
getSrc() {
|
|
1068
|
+
return this.props.src;
|
|
1069
|
+
}
|
|
1070
|
+
getFill() {
|
|
1071
|
+
return this.props.fill;
|
|
1072
|
+
}
|
|
1073
|
+
getSize() {
|
|
1074
|
+
return this.props.size;
|
|
1075
|
+
}
|
|
1076
|
+
setSrc(src) {
|
|
1077
|
+
this.props.src = src;
|
|
1078
|
+
return this;
|
|
1079
|
+
}
|
|
1080
|
+
setFill(fill) {
|
|
1081
|
+
this.props.fill = fill;
|
|
1082
|
+
return this;
|
|
1083
|
+
}
|
|
1084
|
+
setSize(size) {
|
|
1085
|
+
this.props.size = size;
|
|
1086
|
+
return this;
|
|
1087
|
+
}
|
|
1024
1088
|
accept(visitor) {
|
|
1025
1089
|
return visitor.visitIconElement(this);
|
|
1026
1090
|
}
|
|
@@ -1030,7 +1094,9 @@ class CircleElement extends TrackElement {
|
|
|
1030
1094
|
super(TIMELINE_ELEMENT_TYPE.CIRCLE);
|
|
1031
1095
|
this.props = {
|
|
1032
1096
|
radius,
|
|
1033
|
-
fill
|
|
1097
|
+
fill,
|
|
1098
|
+
strokeColor: fill,
|
|
1099
|
+
lineWidth: 1
|
|
1034
1100
|
};
|
|
1035
1101
|
}
|
|
1036
1102
|
getFill() {
|
|
@@ -1039,6 +1105,12 @@ class CircleElement extends TrackElement {
|
|
|
1039
1105
|
getRadius() {
|
|
1040
1106
|
return this.props.radius;
|
|
1041
1107
|
}
|
|
1108
|
+
getStrokeColor() {
|
|
1109
|
+
return this.props.strokeColor || this.props.fill;
|
|
1110
|
+
}
|
|
1111
|
+
getLineWidth() {
|
|
1112
|
+
return this.props.lineWidth ?? 0;
|
|
1113
|
+
}
|
|
1042
1114
|
setFill(fill) {
|
|
1043
1115
|
this.props.fill = fill;
|
|
1044
1116
|
return this;
|
|
@@ -1047,6 +1119,14 @@ class CircleElement extends TrackElement {
|
|
|
1047
1119
|
this.props.radius = radius;
|
|
1048
1120
|
return this;
|
|
1049
1121
|
}
|
|
1122
|
+
setStrokeColor(strokeColor) {
|
|
1123
|
+
this.props.strokeColor = strokeColor;
|
|
1124
|
+
return this;
|
|
1125
|
+
}
|
|
1126
|
+
setLineWidth(lineWidth) {
|
|
1127
|
+
this.props.lineWidth = lineWidth;
|
|
1128
|
+
return this;
|
|
1129
|
+
}
|
|
1050
1130
|
accept(visitor) {
|
|
1051
1131
|
return visitor.visitCircleElement(this);
|
|
1052
1132
|
}
|
|
@@ -1057,18 +1137,48 @@ class RectElement extends TrackElement {
|
|
|
1057
1137
|
this.props = {
|
|
1058
1138
|
width: size.width,
|
|
1059
1139
|
height: size.height,
|
|
1060
|
-
fill
|
|
1140
|
+
fill,
|
|
1141
|
+
radius: 0,
|
|
1142
|
+
strokeColor: fill,
|
|
1143
|
+
lineWidth: 1
|
|
1061
1144
|
};
|
|
1062
1145
|
}
|
|
1146
|
+
getFill() {
|
|
1147
|
+
return this.props.fill;
|
|
1148
|
+
}
|
|
1063
1149
|
setFill(fill) {
|
|
1064
1150
|
this.props.fill = fill;
|
|
1065
1151
|
return this;
|
|
1066
1152
|
}
|
|
1153
|
+
getSize() {
|
|
1154
|
+
return { width: this.props.width, height: this.props.height };
|
|
1155
|
+
}
|
|
1156
|
+
getCornerRadius() {
|
|
1157
|
+
return this.props.radius;
|
|
1158
|
+
}
|
|
1159
|
+
getStrokeColor() {
|
|
1160
|
+
return this.props.strokeColor || this.props.fill;
|
|
1161
|
+
}
|
|
1162
|
+
getLineWidth() {
|
|
1163
|
+
return this.props.lineWidth ?? 0;
|
|
1164
|
+
}
|
|
1067
1165
|
setSize(size) {
|
|
1068
1166
|
this.props.width = size.width;
|
|
1069
1167
|
this.props.height = size.height;
|
|
1070
1168
|
return this;
|
|
1071
1169
|
}
|
|
1170
|
+
setCornerRadius(cornerRadius) {
|
|
1171
|
+
this.props.radius = cornerRadius;
|
|
1172
|
+
return this;
|
|
1173
|
+
}
|
|
1174
|
+
setStrokeColor(strokeColor) {
|
|
1175
|
+
this.props.strokeColor = strokeColor;
|
|
1176
|
+
return this;
|
|
1177
|
+
}
|
|
1178
|
+
setLineWidth(lineWidth) {
|
|
1179
|
+
this.props.lineWidth = lineWidth;
|
|
1180
|
+
return this;
|
|
1181
|
+
}
|
|
1072
1182
|
accept(visitor) {
|
|
1073
1183
|
return visitor.visitRectElement(this);
|
|
1074
1184
|
}
|
|
@@ -1077,6 +1187,7 @@ class ElementAnimation {
|
|
|
1077
1187
|
constructor(name) {
|
|
1078
1188
|
__publicField(this, "name");
|
|
1079
1189
|
__publicField(this, "interval");
|
|
1190
|
+
__publicField(this, "duration");
|
|
1080
1191
|
__publicField(this, "intensity");
|
|
1081
1192
|
__publicField(this, "animate");
|
|
1082
1193
|
__publicField(this, "mode");
|
|
@@ -1089,6 +1200,9 @@ class ElementAnimation {
|
|
|
1089
1200
|
getInterval() {
|
|
1090
1201
|
return this.interval;
|
|
1091
1202
|
}
|
|
1203
|
+
getDuration() {
|
|
1204
|
+
return this.duration;
|
|
1205
|
+
}
|
|
1092
1206
|
getIntensity() {
|
|
1093
1207
|
return this.intensity;
|
|
1094
1208
|
}
|
|
@@ -1105,6 +1219,10 @@ class ElementAnimation {
|
|
|
1105
1219
|
this.interval = interval;
|
|
1106
1220
|
return this;
|
|
1107
1221
|
}
|
|
1222
|
+
setDuration(duration) {
|
|
1223
|
+
this.duration = duration;
|
|
1224
|
+
return this;
|
|
1225
|
+
}
|
|
1108
1226
|
setIntensity(intensity) {
|
|
1109
1227
|
this.intensity = intensity;
|
|
1110
1228
|
return this;
|
|
@@ -1125,6 +1243,7 @@ class ElementAnimation {
|
|
|
1125
1243
|
return {
|
|
1126
1244
|
name: this.name,
|
|
1127
1245
|
interval: this.interval,
|
|
1246
|
+
duration: this.duration,
|
|
1128
1247
|
intensity: this.intensity,
|
|
1129
1248
|
animate: this.animate,
|
|
1130
1249
|
mode: this.mode,
|
|
@@ -1134,6 +1253,7 @@ class ElementAnimation {
|
|
|
1134
1253
|
static fromJSON(json) {
|
|
1135
1254
|
const animation = new ElementAnimation(json.name);
|
|
1136
1255
|
animation.setInterval(json.interval);
|
|
1256
|
+
animation.setDuration(json.duration);
|
|
1137
1257
|
animation.setIntensity(json.intensity);
|
|
1138
1258
|
animation.setAnimate(json.animate);
|
|
1139
1259
|
animation.setMode(json.mode);
|
|
@@ -1219,7 +1339,7 @@ class ElementTextEffect {
|
|
|
1219
1339
|
return {
|
|
1220
1340
|
name: this.name,
|
|
1221
1341
|
delay: this.delay,
|
|
1222
|
-
duration: this.duration,
|
|
1342
|
+
duration: this.duration ?? 1,
|
|
1223
1343
|
bufferTime: this.bufferTime
|
|
1224
1344
|
};
|
|
1225
1345
|
}
|
|
@@ -1287,11 +1407,12 @@ class ElementDeserializer {
|
|
|
1287
1407
|
return captionElement;
|
|
1288
1408
|
}
|
|
1289
1409
|
static deserializeIconElement(json) {
|
|
1290
|
-
var _a, _b;
|
|
1291
|
-
const size = ((_a = json.props) == null ? void 0 : _a.size)
|
|
1410
|
+
var _a, _b, _c;
|
|
1411
|
+
const size = ((_a = json.props) == null ? void 0 : _a.size) ?? { width: 100, height: 100 };
|
|
1292
1412
|
const iconElement = new IconElement(
|
|
1293
1413
|
((_b = json.props) == null ? void 0 : _b.src) || "",
|
|
1294
|
-
size
|
|
1414
|
+
size,
|
|
1415
|
+
(_c = json.props) == null ? void 0 : _c.fill
|
|
1295
1416
|
);
|
|
1296
1417
|
ElementDeserializer.deserializeBaseElement(iconElement, json);
|
|
1297
1418
|
return iconElement;
|
|
@@ -1527,10 +1648,6 @@ class ElementValidator {
|
|
|
1527
1648
|
const basicValidation = this.validateBasicProperties(element);
|
|
1528
1649
|
const errors = [...basicValidation.errors];
|
|
1529
1650
|
const warnings = [...basicValidation.warnings];
|
|
1530
|
-
const props = element.getProps();
|
|
1531
|
-
if (!(props == null ? void 0 : props.icon)) {
|
|
1532
|
-
errors.push("Icon element must have an icon name");
|
|
1533
|
-
}
|
|
1534
1651
|
return { errors, warnings };
|
|
1535
1652
|
}
|
|
1536
1653
|
validateCircleElement(element) {
|
|
@@ -1682,7 +1799,20 @@ class TrackFriend {
|
|
|
1682
1799
|
}
|
|
1683
1800
|
}
|
|
1684
1801
|
class Track {
|
|
1685
|
-
|
|
1802
|
+
/**
|
|
1803
|
+
* Creates a new Track instance.
|
|
1804
|
+
*
|
|
1805
|
+
* @param name - The display name for the track
|
|
1806
|
+
* @param type - The type of the track
|
|
1807
|
+
* @param id - Optional unique identifier (auto-generated if not provided)
|
|
1808
|
+
*
|
|
1809
|
+
* @example
|
|
1810
|
+
* ```js
|
|
1811
|
+
* const track = new Track("My Video Track");
|
|
1812
|
+
* const trackWithId = new Track("Audio Track", "element", "video-track-1");
|
|
1813
|
+
* ```
|
|
1814
|
+
*/
|
|
1815
|
+
constructor(name, type = "element", id) {
|
|
1686
1816
|
__publicField(this, "id");
|
|
1687
1817
|
__publicField(this, "name");
|
|
1688
1818
|
__publicField(this, "type");
|
|
@@ -1690,71 +1820,215 @@ class Track {
|
|
|
1690
1820
|
__publicField(this, "validator");
|
|
1691
1821
|
this.name = name;
|
|
1692
1822
|
this.id = id ?? `t-${generateShortUuid}`;
|
|
1693
|
-
this.type =
|
|
1823
|
+
this.type = type;
|
|
1694
1824
|
this.elements = [];
|
|
1695
1825
|
this.validator = new ElementValidator();
|
|
1696
1826
|
}
|
|
1697
1827
|
/**
|
|
1698
|
-
*
|
|
1699
|
-
* This implements the Friend Class Pattern
|
|
1700
|
-
*
|
|
1828
|
+
* Creates a friend instance for explicit access to protected methods.
|
|
1829
|
+
* This implements the Friend Class Pattern to allow controlled access
|
|
1830
|
+
* to protected methods while maintaining encapsulation.
|
|
1831
|
+
*
|
|
1832
|
+
* @returns TrackFriend instance that can access protected methods
|
|
1833
|
+
*
|
|
1834
|
+
* @example
|
|
1835
|
+
* ```js
|
|
1836
|
+
* const track = new Track("My Track");
|
|
1837
|
+
* const friend = track.createFriend();
|
|
1838
|
+
*
|
|
1839
|
+
* // Use friend to add elements
|
|
1840
|
+
* const element = new VideoElement({ src: "video.mp4", start: 0, end: 10 });
|
|
1841
|
+
* friend.addElement(element);
|
|
1842
|
+
* ```
|
|
1701
1843
|
*/
|
|
1702
1844
|
createFriend() {
|
|
1703
1845
|
return new TrackFriend(this);
|
|
1704
1846
|
}
|
|
1705
1847
|
/**
|
|
1706
|
-
* Friend method to add element (called by TrackFriend)
|
|
1707
|
-
*
|
|
1708
|
-
*
|
|
1848
|
+
* Friend method to add element (called by TrackFriend).
|
|
1849
|
+
* Provides controlled access to the protected addElement method.
|
|
1850
|
+
*
|
|
1851
|
+
* @param element - The element to add to the track
|
|
1852
|
+
* @param skipValidation - If true, skips validation (use with caution)
|
|
1709
1853
|
* @returns true if element was added successfully
|
|
1854
|
+
*
|
|
1855
|
+
* @example
|
|
1856
|
+
* ```js
|
|
1857
|
+
* const track = new Track("My Track");
|
|
1858
|
+
* const friend = track.createFriend();
|
|
1859
|
+
* const element = new VideoElement({ src: "video.mp4", start: 0, end: 10 });
|
|
1860
|
+
*
|
|
1861
|
+
* const success = track.addElementViaFriend(element);
|
|
1862
|
+
* // success = true if element was added successfully
|
|
1863
|
+
* ```
|
|
1710
1864
|
*/
|
|
1711
1865
|
addElementViaFriend(element, skipValidation = false) {
|
|
1712
1866
|
return this.addElement(element, skipValidation);
|
|
1713
1867
|
}
|
|
1714
1868
|
/**
|
|
1715
|
-
* Friend method to remove element (called by TrackFriend)
|
|
1716
|
-
*
|
|
1869
|
+
* Friend method to remove element (called by TrackFriend).
|
|
1870
|
+
* Provides controlled access to the protected removeElement method.
|
|
1871
|
+
*
|
|
1872
|
+
* @param element - The element to remove from the track
|
|
1873
|
+
*
|
|
1874
|
+
* @example
|
|
1875
|
+
* ```js
|
|
1876
|
+
* const track = new Track("My Track");
|
|
1877
|
+
* const element = new VideoElement({ src: "video.mp4", start: 0, end: 10 });
|
|
1878
|
+
*
|
|
1879
|
+
* track.removeElementViaFriend(element);
|
|
1880
|
+
* // Element is removed from the track
|
|
1881
|
+
* ```
|
|
1717
1882
|
*/
|
|
1718
1883
|
removeElementViaFriend(element) {
|
|
1719
1884
|
this.removeElement(element);
|
|
1720
1885
|
}
|
|
1721
1886
|
/**
|
|
1722
|
-
* Friend method to update element (called by TrackFriend)
|
|
1723
|
-
*
|
|
1887
|
+
* Friend method to update element (called by TrackFriend).
|
|
1888
|
+
* Provides controlled access to the protected updateElement method.
|
|
1889
|
+
*
|
|
1890
|
+
* @param element - The updated element to replace the existing one
|
|
1724
1891
|
* @returns true if element was updated successfully
|
|
1892
|
+
*
|
|
1893
|
+
* @example
|
|
1894
|
+
* ```js
|
|
1895
|
+
* const track = new Track("My Track");
|
|
1896
|
+
* const element = new VideoElement({ src: "video.mp4", start: 0, end: 10 });
|
|
1897
|
+
*
|
|
1898
|
+
* // Update the element
|
|
1899
|
+
* element.setEnd(15);
|
|
1900
|
+
* const success = track.updateElementViaFriend(element);
|
|
1901
|
+
* // success = true if element was updated successfully
|
|
1902
|
+
* ```
|
|
1725
1903
|
*/
|
|
1726
1904
|
updateElementViaFriend(element) {
|
|
1727
1905
|
return this.updateElement(element);
|
|
1728
1906
|
}
|
|
1907
|
+
/**
|
|
1908
|
+
* Gets the unique identifier of the track.
|
|
1909
|
+
*
|
|
1910
|
+
* @returns The track's unique ID string
|
|
1911
|
+
*
|
|
1912
|
+
* @example
|
|
1913
|
+
* ```js
|
|
1914
|
+
* const track = new Track("My Track", "element", "track-123");
|
|
1915
|
+
* const id = track.getId(); // "track-123"
|
|
1916
|
+
* ```
|
|
1917
|
+
*/
|
|
1729
1918
|
getId() {
|
|
1730
1919
|
return this.id;
|
|
1731
1920
|
}
|
|
1921
|
+
/**
|
|
1922
|
+
* Gets the display name of the track.
|
|
1923
|
+
*
|
|
1924
|
+
* @returns The track's display name
|
|
1925
|
+
*
|
|
1926
|
+
* @example
|
|
1927
|
+
* ```js
|
|
1928
|
+
* const track = new Track("Video Track");
|
|
1929
|
+
* const name = track.getName(); // "Video Track"
|
|
1930
|
+
* ```
|
|
1931
|
+
*/
|
|
1732
1932
|
getName() {
|
|
1733
1933
|
return this.name;
|
|
1734
1934
|
}
|
|
1935
|
+
/**
|
|
1936
|
+
* Gets the type of the track.
|
|
1937
|
+
*
|
|
1938
|
+
* @returns The track's type string
|
|
1939
|
+
*
|
|
1940
|
+
* @example
|
|
1941
|
+
* ```js
|
|
1942
|
+
* const track = new Track("My Track");
|
|
1943
|
+
* const type = track.getType(); // "element"
|
|
1944
|
+
* ```
|
|
1945
|
+
*/
|
|
1735
1946
|
getType() {
|
|
1736
1947
|
return this.type;
|
|
1737
1948
|
}
|
|
1949
|
+
/**
|
|
1950
|
+
* Gets a read-only array of all elements in the track.
|
|
1951
|
+
* Returns a copy of the elements array to prevent external modification.
|
|
1952
|
+
*
|
|
1953
|
+
* @returns Read-only array of track elements
|
|
1954
|
+
*
|
|
1955
|
+
* @example
|
|
1956
|
+
* ```js
|
|
1957
|
+
* const track = new Track("My Track");
|
|
1958
|
+
* const elements = track.getElements();
|
|
1959
|
+
* // elements is a read-only array of TrackElement instances
|
|
1960
|
+
*
|
|
1961
|
+
* elements.forEach(element => {
|
|
1962
|
+
* console.log(`Element: ${element.getId()}, Duration: ${element.getEnd() - element.getStart()}`);
|
|
1963
|
+
* });
|
|
1964
|
+
* ```
|
|
1965
|
+
*/
|
|
1738
1966
|
getElements() {
|
|
1739
1967
|
return [...this.elements];
|
|
1740
1968
|
}
|
|
1741
1969
|
/**
|
|
1742
|
-
* Validates
|
|
1743
|
-
*
|
|
1970
|
+
* Validates a single element using the track's validator.
|
|
1971
|
+
* Checks if the element meets all validation requirements.
|
|
1972
|
+
*
|
|
1973
|
+
* @param element - The element to validate
|
|
1744
1974
|
* @returns true if valid, throws ValidationError if invalid
|
|
1975
|
+
*
|
|
1976
|
+
* @example
|
|
1977
|
+
* ```js
|
|
1978
|
+
* const track = new Track("My Track");
|
|
1979
|
+
* const element = new VideoElement({ src: "video.mp4", start: 0, end: 10 });
|
|
1980
|
+
*
|
|
1981
|
+
* try {
|
|
1982
|
+
* const isValid = track.validateElement(element);
|
|
1983
|
+
* console.log('Element is valid:', isValid);
|
|
1984
|
+
* } catch (error) {
|
|
1985
|
+
* if (error instanceof ValidationError) {
|
|
1986
|
+
* console.log('Validation failed:', error.errors);
|
|
1987
|
+
* }
|
|
1988
|
+
* }
|
|
1989
|
+
* ```
|
|
1745
1990
|
*/
|
|
1746
1991
|
validateElement(element) {
|
|
1747
1992
|
return element.accept(this.validator);
|
|
1748
1993
|
}
|
|
1994
|
+
/**
|
|
1995
|
+
* Gets the total duration of the track.
|
|
1996
|
+
* Calculates the duration based on the end time of the last element.
|
|
1997
|
+
*
|
|
1998
|
+
* @returns The total duration of the track in seconds
|
|
1999
|
+
*
|
|
2000
|
+
* @example
|
|
2001
|
+
* ```js
|
|
2002
|
+
* const track = new Track("My Track");
|
|
2003
|
+
* const duration = track.getTrackDuration(); // 0 if no elements
|
|
2004
|
+
*
|
|
2005
|
+
* // After adding elements
|
|
2006
|
+
* const element = new VideoElement({ src: "video.mp4", start: 0, end: 30 });
|
|
2007
|
+
* track.createFriend().addElement(element);
|
|
2008
|
+
* const newDuration = track.getTrackDuration(); // 30
|
|
2009
|
+
* ```
|
|
2010
|
+
*/
|
|
1749
2011
|
getTrackDuration() {
|
|
1750
2012
|
var _a;
|
|
1751
2013
|
return ((_a = this.elements) == null ? void 0 : _a.length) ? this.elements[this.elements.length - 1].getEnd() : 0;
|
|
1752
2014
|
}
|
|
1753
2015
|
/**
|
|
1754
|
-
* Adds an element to the track with validation
|
|
1755
|
-
*
|
|
1756
|
-
*
|
|
2016
|
+
* Adds an element to the track with validation.
|
|
2017
|
+
* Protected method that should be accessed through TrackFriend.
|
|
2018
|
+
*
|
|
2019
|
+
* @param element - The element to add to the track
|
|
2020
|
+
* @param skipValidation - If true, skips validation (use with caution)
|
|
1757
2021
|
* @returns true if element was added successfully, throws ValidationError if validation fails
|
|
2022
|
+
*
|
|
2023
|
+
* @example
|
|
2024
|
+
* ```js
|
|
2025
|
+
* const track = new Track("My Track");
|
|
2026
|
+
* const element = new VideoElement({ src: "video.mp4", start: 0, end: 10 });
|
|
2027
|
+
*
|
|
2028
|
+
* // Use friend to access this protected method
|
|
2029
|
+
* const friend = track.createFriend();
|
|
2030
|
+
* const success = friend.addElement(element);
|
|
2031
|
+
* ```
|
|
1758
2032
|
*/
|
|
1759
2033
|
addElement(element, skipValidation = false) {
|
|
1760
2034
|
element.setTrackId(this.id);
|
|
@@ -1776,6 +2050,22 @@ class Track {
|
|
|
1776
2050
|
}
|
|
1777
2051
|
return false;
|
|
1778
2052
|
}
|
|
2053
|
+
/**
|
|
2054
|
+
* Removes an element from the track.
|
|
2055
|
+
* Protected method that should be accessed through TrackFriend.
|
|
2056
|
+
*
|
|
2057
|
+
* @param element - The element to remove from the track
|
|
2058
|
+
*
|
|
2059
|
+
* @example
|
|
2060
|
+
* ```js
|
|
2061
|
+
* const track = new Track("My Track");
|
|
2062
|
+
* const element = new VideoElement({ src: "video.mp4", start: 0, end: 10 });
|
|
2063
|
+
*
|
|
2064
|
+
* // Use friend to access this protected method
|
|
2065
|
+
* const friend = track.createFriend();
|
|
2066
|
+
* friend.removeElement(element);
|
|
2067
|
+
* ```
|
|
2068
|
+
*/
|
|
1779
2069
|
removeElement(element) {
|
|
1780
2070
|
const index = this.elements.findIndex((e2) => e2.getId() === element.getId());
|
|
1781
2071
|
if (index !== -1) {
|
|
@@ -1783,9 +2073,22 @@ class Track {
|
|
|
1783
2073
|
}
|
|
1784
2074
|
}
|
|
1785
2075
|
/**
|
|
1786
|
-
* Updates an element in the track with validation
|
|
1787
|
-
*
|
|
2076
|
+
* Updates an element in the track with validation.
|
|
2077
|
+
* Protected method that should be accessed through TrackFriend.
|
|
2078
|
+
*
|
|
2079
|
+
* @param element - The updated element to replace the existing one
|
|
1788
2080
|
* @returns true if element was updated successfully, throws ValidationError if validation fails
|
|
2081
|
+
*
|
|
2082
|
+
* @example
|
|
2083
|
+
* ```js
|
|
2084
|
+
* const track = new Track("My Track");
|
|
2085
|
+
* const element = new VideoElement({ src: "video.mp4", start: 0, end: 10 });
|
|
2086
|
+
*
|
|
2087
|
+
* // Use friend to access this protected method
|
|
2088
|
+
* const friend = track.createFriend();
|
|
2089
|
+
* element.setEnd(15);
|
|
2090
|
+
* const success = friend.updateElement(element);
|
|
2091
|
+
* ```
|
|
1789
2092
|
*/
|
|
1790
2093
|
updateElement(element) {
|
|
1791
2094
|
try {
|
|
@@ -1807,14 +2110,55 @@ class Track {
|
|
|
1807
2110
|
}
|
|
1808
2111
|
return false;
|
|
1809
2112
|
}
|
|
2113
|
+
/**
|
|
2114
|
+
* Finds an element in the track by its ID.
|
|
2115
|
+
*
|
|
2116
|
+
* @param id - The unique identifier of the element to find
|
|
2117
|
+
* @returns The found element or undefined if not found
|
|
2118
|
+
*
|
|
2119
|
+
* @example
|
|
2120
|
+
* ```js
|
|
2121
|
+
* const track = new Track("My Track");
|
|
2122
|
+
* const element = new VideoElement({ src: "video.mp4", start: 0, end: 10 });
|
|
2123
|
+
* track.createFriend().addElement(element);
|
|
2124
|
+
*
|
|
2125
|
+
* const foundElement = track.getElementById(element.getId());
|
|
2126
|
+
* // foundElement is the same element instance
|
|
2127
|
+
* ```
|
|
2128
|
+
*/
|
|
1810
2129
|
getElementById(id) {
|
|
1811
2130
|
const element = this.elements.find((e2) => e2.getId() === id);
|
|
1812
2131
|
if (!element) return void 0;
|
|
1813
2132
|
return element;
|
|
1814
2133
|
}
|
|
1815
2134
|
/**
|
|
1816
|
-
* Validates all elements in the track and returns combined result and per-element status
|
|
2135
|
+
* Validates all elements in the track and returns combined result and per-element status.
|
|
2136
|
+
* Provides detailed validation information for each element including errors and warnings.
|
|
2137
|
+
*
|
|
1817
2138
|
* @returns Object with overall isValid and array of per-element validation results
|
|
2139
|
+
*
|
|
2140
|
+
* @example
|
|
2141
|
+
* ```js
|
|
2142
|
+
* const track = new Track("My Track");
|
|
2143
|
+
* const element1 = new VideoElement({ src: "video.mp4", start: 0, end: 10 });
|
|
2144
|
+
* const element2 = new TextElement({ text: "Hello", start: 5, end: 15 });
|
|
2145
|
+
*
|
|
2146
|
+
* track.createFriend().addElement(element1);
|
|
2147
|
+
* track.createFriend().addElement(element2);
|
|
2148
|
+
*
|
|
2149
|
+
* const validation = track.validateAllElements();
|
|
2150
|
+
* console.log('Overall valid:', validation.isValid);
|
|
2151
|
+
*
|
|
2152
|
+
* validation.results.forEach(result => {
|
|
2153
|
+
* console.log(`Element ${result.element.getId()}: ${result.isValid ? 'Valid' : 'Invalid'}`);
|
|
2154
|
+
* if (result.errors) {
|
|
2155
|
+
* console.log('Errors:', result.errors);
|
|
2156
|
+
* }
|
|
2157
|
+
* if (result.warnings) {
|
|
2158
|
+
* console.log('Warnings:', result.warnings);
|
|
2159
|
+
* }
|
|
2160
|
+
* });
|
|
2161
|
+
* ```
|
|
1818
2162
|
*/
|
|
1819
2163
|
validateAllElements() {
|
|
1820
2164
|
let validResult = true;
|
|
@@ -1844,6 +2188,30 @@ class Track {
|
|
|
1844
2188
|
});
|
|
1845
2189
|
return { isValid: validResult, results };
|
|
1846
2190
|
}
|
|
2191
|
+
/**
|
|
2192
|
+
* Serializes the track and all its elements to JSON format.
|
|
2193
|
+
* Converts the track structure to a format that can be stored or transmitted.
|
|
2194
|
+
*
|
|
2195
|
+
* @returns TrackJSON object representing the track and its elements
|
|
2196
|
+
*
|
|
2197
|
+
* @example
|
|
2198
|
+
* ```js
|
|
2199
|
+
* const track = new Track("My Track");
|
|
2200
|
+
* const element = new VideoElement({ src: "video.mp4", start: 0, end: 10 });
|
|
2201
|
+
* track.createFriend().addElement(element);
|
|
2202
|
+
*
|
|
2203
|
+
* const trackData = track.serialize();
|
|
2204
|
+
* // trackData = {
|
|
2205
|
+
* // id: "t-abc123",
|
|
2206
|
+
* // name: "My Track",
|
|
2207
|
+
* // type: "element",
|
|
2208
|
+
* // elements: [{ ... }]
|
|
2209
|
+
* // }
|
|
2210
|
+
*
|
|
2211
|
+
* // Save to localStorage
|
|
2212
|
+
* localStorage.setItem('track-data', JSON.stringify(trackData));
|
|
2213
|
+
* ```
|
|
2214
|
+
*/
|
|
1847
2215
|
serialize() {
|
|
1848
2216
|
const serializer = new ElementSerializer();
|
|
1849
2217
|
return {
|
|
@@ -1855,8 +2223,37 @@ class Track {
|
|
|
1855
2223
|
)
|
|
1856
2224
|
};
|
|
1857
2225
|
}
|
|
2226
|
+
/**
|
|
2227
|
+
* Creates a Track instance from JSON data.
|
|
2228
|
+
* Static factory method for deserializing track data.
|
|
2229
|
+
*
|
|
2230
|
+
* @param json - JSON object containing track data
|
|
2231
|
+
* @returns New Track instance with loaded data
|
|
2232
|
+
*
|
|
2233
|
+
* @example
|
|
2234
|
+
* ```js
|
|
2235
|
+
* const trackData = {
|
|
2236
|
+
* id: "t-abc123",
|
|
2237
|
+
* name: "My Track",
|
|
2238
|
+
* type: "element",
|
|
2239
|
+
* elements: [
|
|
2240
|
+
* {
|
|
2241
|
+
* id: "e-def456",
|
|
2242
|
+
* type: "video",
|
|
2243
|
+
* src: "video.mp4",
|
|
2244
|
+
* start: 0,
|
|
2245
|
+
* end: 10
|
|
2246
|
+
* }
|
|
2247
|
+
* ]
|
|
2248
|
+
* };
|
|
2249
|
+
*
|
|
2250
|
+
* const track = Track.fromJSON(trackData);
|
|
2251
|
+
* console.log(track.getName()); // "My Track"
|
|
2252
|
+
* console.log(track.getElements().length); // 1
|
|
2253
|
+
* ```
|
|
2254
|
+
*/
|
|
1858
2255
|
static fromJSON(json) {
|
|
1859
|
-
const track = new Track(json.name, json.id);
|
|
2256
|
+
const track = new Track(json.name, json.type ?? "element", json.id);
|
|
1860
2257
|
track.type = json.type;
|
|
1861
2258
|
track.elements = (json.elements || []).map(ElementDeserializer.fromJSON);
|
|
1862
2259
|
return track;
|
|
@@ -1934,12 +2331,37 @@ __publicField(_TimelineContextStore, "instance");
|
|
|
1934
2331
|
let TimelineContextStore = _TimelineContextStore;
|
|
1935
2332
|
const timelineContextStore = TimelineContextStore.getInstance();
|
|
1936
2333
|
class ElementAdder {
|
|
2334
|
+
/**
|
|
2335
|
+
* Creates a new ElementAdder instance for the specified track.
|
|
2336
|
+
*
|
|
2337
|
+
* @param track - The track to add elements to
|
|
2338
|
+
*
|
|
2339
|
+
* @example
|
|
2340
|
+
* ```js
|
|
2341
|
+
* const adder = new ElementAdder(track);
|
|
2342
|
+
* const success = await adder.visitVideoElement(videoElement);
|
|
2343
|
+
* ```
|
|
2344
|
+
*/
|
|
1937
2345
|
constructor(track) {
|
|
1938
2346
|
__publicField(this, "track");
|
|
1939
2347
|
__publicField(this, "trackFriend");
|
|
1940
2348
|
this.track = track;
|
|
1941
2349
|
this.trackFriend = track.createFriend();
|
|
1942
2350
|
}
|
|
2351
|
+
/**
|
|
2352
|
+
* Adds a video element to the track.
|
|
2353
|
+
* Updates video metadata and calculates appropriate start/end times
|
|
2354
|
+
* based on existing track elements.
|
|
2355
|
+
*
|
|
2356
|
+
* @param element - The video element to add
|
|
2357
|
+
* @returns Promise resolving to true if element was added successfully
|
|
2358
|
+
*
|
|
2359
|
+
* @example
|
|
2360
|
+
* ```js
|
|
2361
|
+
* const success = await adder.visitVideoElement(videoElement);
|
|
2362
|
+
* // success = true if element was added successfully
|
|
2363
|
+
* ```
|
|
2364
|
+
*/
|
|
1943
2365
|
async visitVideoElement(element) {
|
|
1944
2366
|
await element.updateVideoMeta();
|
|
1945
2367
|
const elements = this.track.getElements();
|
|
@@ -1952,6 +2374,20 @@ class ElementAdder {
|
|
|
1952
2374
|
}
|
|
1953
2375
|
return this.trackFriend.addElement(element);
|
|
1954
2376
|
}
|
|
2377
|
+
/**
|
|
2378
|
+
* Adds an audio element to the track.
|
|
2379
|
+
* Updates audio metadata and calculates appropriate start/end times
|
|
2380
|
+
* based on existing track elements.
|
|
2381
|
+
*
|
|
2382
|
+
* @param element - The audio element to add
|
|
2383
|
+
* @returns Promise resolving to true if element was added successfully
|
|
2384
|
+
*
|
|
2385
|
+
* @example
|
|
2386
|
+
* ```js
|
|
2387
|
+
* const success = await adder.visitAudioElement(audioElement);
|
|
2388
|
+
* // success = true if element was added successfully
|
|
2389
|
+
* ```
|
|
2390
|
+
*/
|
|
1955
2391
|
async visitAudioElement(element) {
|
|
1956
2392
|
await element.updateAudioMeta();
|
|
1957
2393
|
const elements = this.track.getElements();
|
|
@@ -1964,6 +2400,20 @@ class ElementAdder {
|
|
|
1964
2400
|
}
|
|
1965
2401
|
return this.trackFriend.addElement(element);
|
|
1966
2402
|
}
|
|
2403
|
+
/**
|
|
2404
|
+
* Adds an image element to the track.
|
|
2405
|
+
* Updates image metadata and calculates appropriate start/end times
|
|
2406
|
+
* based on existing track elements.
|
|
2407
|
+
*
|
|
2408
|
+
* @param element - The image element to add
|
|
2409
|
+
* @returns Promise resolving to true if element was added successfully
|
|
2410
|
+
*
|
|
2411
|
+
* @example
|
|
2412
|
+
* ```js
|
|
2413
|
+
* const success = await adder.visitImageElement(imageElement);
|
|
2414
|
+
* // success = true if element was added successfully
|
|
2415
|
+
* ```
|
|
2416
|
+
*/
|
|
1967
2417
|
async visitImageElement(element) {
|
|
1968
2418
|
await element.updateImageMeta();
|
|
1969
2419
|
const elements = this.track.getElements();
|
|
@@ -1976,6 +2426,19 @@ class ElementAdder {
|
|
|
1976
2426
|
}
|
|
1977
2427
|
return this.trackFriend.addElement(element);
|
|
1978
2428
|
}
|
|
2429
|
+
/**
|
|
2430
|
+
* Adds a text element to the track.
|
|
2431
|
+
* Calculates appropriate start/end times based on existing track elements.
|
|
2432
|
+
*
|
|
2433
|
+
* @param element - The text element to add
|
|
2434
|
+
* @returns Promise resolving to true if element was added successfully
|
|
2435
|
+
*
|
|
2436
|
+
* @example
|
|
2437
|
+
* ```js
|
|
2438
|
+
* const success = await adder.visitTextElement(textElement);
|
|
2439
|
+
* // success = true if element was added successfully
|
|
2440
|
+
* ```
|
|
2441
|
+
*/
|
|
1979
2442
|
async visitTextElement(element) {
|
|
1980
2443
|
const elements = this.track.getElements();
|
|
1981
2444
|
const lastEndtime = (elements == null ? void 0 : elements.length) ? elements[elements.length - 1].getEnd() : 0;
|
|
@@ -1987,6 +2450,19 @@ class ElementAdder {
|
|
|
1987
2450
|
}
|
|
1988
2451
|
return this.trackFriend.addElement(element);
|
|
1989
2452
|
}
|
|
2453
|
+
/**
|
|
2454
|
+
* Adds a caption element to the track.
|
|
2455
|
+
* Calculates appropriate start/end times based on existing track elements.
|
|
2456
|
+
*
|
|
2457
|
+
* @param element - The caption element to add
|
|
2458
|
+
* @returns Promise resolving to true if element was added successfully
|
|
2459
|
+
*
|
|
2460
|
+
* @example
|
|
2461
|
+
* ```js
|
|
2462
|
+
* const success = await adder.visitCaptionElement(captionElement);
|
|
2463
|
+
* // success = true if element was added successfully
|
|
2464
|
+
* ```
|
|
2465
|
+
*/
|
|
1990
2466
|
async visitCaptionElement(element) {
|
|
1991
2467
|
const elements = this.track.getElements();
|
|
1992
2468
|
const lastEndtime = (elements == null ? void 0 : elements.length) ? elements[elements.length - 1].getEnd() : 0;
|
|
@@ -1998,6 +2474,19 @@ class ElementAdder {
|
|
|
1998
2474
|
}
|
|
1999
2475
|
return this.trackFriend.addElement(element);
|
|
2000
2476
|
}
|
|
2477
|
+
/**
|
|
2478
|
+
* Adds an icon element to the track.
|
|
2479
|
+
* Calculates appropriate start/end times based on existing track elements.
|
|
2480
|
+
*
|
|
2481
|
+
* @param element - The icon element to add
|
|
2482
|
+
* @returns Promise resolving to true if element was added successfully
|
|
2483
|
+
*
|
|
2484
|
+
* @example
|
|
2485
|
+
* ```js
|
|
2486
|
+
* const success = await adder.visitIconElement(iconElement);
|
|
2487
|
+
* // success = true if element was added successfully
|
|
2488
|
+
* ```
|
|
2489
|
+
*/
|
|
2001
2490
|
async visitIconElement(element) {
|
|
2002
2491
|
const elements = this.track.getElements();
|
|
2003
2492
|
const lastEndtime = (elements == null ? void 0 : elements.length) ? elements[elements.length - 1].getEnd() : 0;
|
|
@@ -2009,6 +2498,19 @@ class ElementAdder {
|
|
|
2009
2498
|
}
|
|
2010
2499
|
return this.trackFriend.addElement(element);
|
|
2011
2500
|
}
|
|
2501
|
+
/**
|
|
2502
|
+
* Adds a circle element to the track.
|
|
2503
|
+
* Calculates appropriate start/end times based on existing track elements.
|
|
2504
|
+
*
|
|
2505
|
+
* @param element - The circle element to add
|
|
2506
|
+
* @returns Promise resolving to true if element was added successfully
|
|
2507
|
+
*
|
|
2508
|
+
* @example
|
|
2509
|
+
* ```js
|
|
2510
|
+
* const success = await adder.visitCircleElement(circleElement);
|
|
2511
|
+
* // success = true if element was added successfully
|
|
2512
|
+
* ```
|
|
2513
|
+
*/
|
|
2012
2514
|
async visitCircleElement(element) {
|
|
2013
2515
|
const elements = this.track.getElements();
|
|
2014
2516
|
const lastEndtime = (elements == null ? void 0 : elements.length) ? elements[elements.length - 1].getEnd() : 0;
|
|
@@ -2020,6 +2522,19 @@ class ElementAdder {
|
|
|
2020
2522
|
}
|
|
2021
2523
|
return this.trackFriend.addElement(element);
|
|
2022
2524
|
}
|
|
2525
|
+
/**
|
|
2526
|
+
* Adds a rectangle element to the track.
|
|
2527
|
+
* Calculates appropriate start/end times based on existing track elements.
|
|
2528
|
+
*
|
|
2529
|
+
* @param element - The rectangle element to add
|
|
2530
|
+
* @returns Promise resolving to true if element was added successfully
|
|
2531
|
+
*
|
|
2532
|
+
* @example
|
|
2533
|
+
* ```js
|
|
2534
|
+
* const success = await adder.visitRectElement(rectElement);
|
|
2535
|
+
* // success = true if element was added successfully
|
|
2536
|
+
* ```
|
|
2537
|
+
*/
|
|
2023
2538
|
async visitRectElement(element) {
|
|
2024
2539
|
const elements = this.track.getElements();
|
|
2025
2540
|
const lastEndtime = (elements == null ? void 0 : elements.length) ? elements[elements.length - 1].getEnd() : 0;
|
|
@@ -2160,7 +2675,8 @@ class ElementCloner {
|
|
|
2160
2675
|
visitIconElement(element) {
|
|
2161
2676
|
const clonedElement = new IconElement(
|
|
2162
2677
|
element.getProps().src,
|
|
2163
|
-
element.getProps().size
|
|
2678
|
+
element.getProps().size,
|
|
2679
|
+
element.getProps().fill
|
|
2164
2680
|
);
|
|
2165
2681
|
this.cloneElementProperties(element, clonedElement);
|
|
2166
2682
|
return clonedElement;
|
|
@@ -2349,10 +2865,10 @@ class TimelineEditor {
|
|
|
2349
2865
|
this.context.updateChangeLog();
|
|
2350
2866
|
return updatedTimelineData;
|
|
2351
2867
|
}
|
|
2352
|
-
addTrack(name) {
|
|
2868
|
+
addTrack(name, type = "element") {
|
|
2353
2869
|
const prevTimelineData = this.getTimelineData();
|
|
2354
2870
|
const id = `t-${generateShortUuid()}`;
|
|
2355
|
-
const track = new Track(name, id);
|
|
2871
|
+
const track = new Track(name, type, id);
|
|
2356
2872
|
const updatedTimelines = [...(prevTimelineData == null ? void 0 : prevTimelineData.tracks) || [], track];
|
|
2357
2873
|
this.setTimelineData(updatedTimelines);
|
|
2358
2874
|
return track;
|
|
@@ -2439,12 +2955,12 @@ class TimelineEditor {
|
|
|
2439
2955
|
/**
|
|
2440
2956
|
* Update an element in a specific track using the visitor pattern
|
|
2441
2957
|
* @param element The updated element
|
|
2442
|
-
* @returns
|
|
2958
|
+
* @returns TrackElement the updated element
|
|
2443
2959
|
*/
|
|
2444
2960
|
updateElement(element) {
|
|
2445
2961
|
const track = this.getTrackById(element.getTrackId());
|
|
2446
2962
|
if (!track) {
|
|
2447
|
-
return
|
|
2963
|
+
return element;
|
|
2448
2964
|
}
|
|
2449
2965
|
try {
|
|
2450
2966
|
const elementUpdater = new ElementUpdater(track);
|
|
@@ -2455,9 +2971,9 @@ class TimelineEditor {
|
|
|
2455
2971
|
this.setTimelineData(currentData.tracks);
|
|
2456
2972
|
}
|
|
2457
2973
|
}
|
|
2458
|
-
return
|
|
2974
|
+
return element;
|
|
2459
2975
|
} catch (error) {
|
|
2460
|
-
return
|
|
2976
|
+
return element;
|
|
2461
2977
|
}
|
|
2462
2978
|
}
|
|
2463
2979
|
/**
|
|
@@ -7270,6 +7786,7 @@ const TimelineContext = createContext(
|
|
|
7270
7786
|
const TimelineProviderInner = ({
|
|
7271
7787
|
contextId,
|
|
7272
7788
|
children,
|
|
7789
|
+
resolution,
|
|
7273
7790
|
initialData
|
|
7274
7791
|
}) => {
|
|
7275
7792
|
const [timelineAction, setTimelineActionState] = useState({
|
|
@@ -7279,6 +7796,7 @@ const TimelineProviderInner = ({
|
|
|
7279
7796
|
const [selectedItem, setSelectedItem] = useState(
|
|
7280
7797
|
null
|
|
7281
7798
|
);
|
|
7799
|
+
const [videoResolution, setVideoResolution] = useState(resolution ?? { width: 720, height: 1280 });
|
|
7282
7800
|
const [totalDuration, setTotalDuration] = useState(0);
|
|
7283
7801
|
const [changeLog, setChangeLog] = useState(0);
|
|
7284
7802
|
const undoRedoContext = useUndoRedo();
|
|
@@ -7333,9 +7851,11 @@ const TimelineProviderInner = ({
|
|
|
7333
7851
|
timelineAction,
|
|
7334
7852
|
totalDuration,
|
|
7335
7853
|
changeLog,
|
|
7854
|
+
videoResolution,
|
|
7336
7855
|
present: undoRedoContext.present,
|
|
7337
7856
|
canUndo: undoRedoContext.canUndo,
|
|
7338
7857
|
canRedo: undoRedoContext.canRedo,
|
|
7858
|
+
setVideoResolution,
|
|
7339
7859
|
setSelectedItem,
|
|
7340
7860
|
setTimelineAction,
|
|
7341
7861
|
editor
|
|
@@ -7346,6 +7866,7 @@ const TimelineProviderInner = ({
|
|
|
7346
7866
|
const TimelineProvider = ({
|
|
7347
7867
|
contextId,
|
|
7348
7868
|
children,
|
|
7869
|
+
resolution = { width: 720, height: 1280 },
|
|
7349
7870
|
initialData,
|
|
7350
7871
|
undoRedoPersistenceKey,
|
|
7351
7872
|
maxHistorySize
|
|
@@ -7367,6 +7888,7 @@ const TimelineProvider = ({
|
|
|
7367
7888
|
children: /* @__PURE__ */ jsx(
|
|
7368
7889
|
TimelineProviderInner,
|
|
7369
7890
|
{
|
|
7891
|
+
resolution,
|
|
7370
7892
|
initialData,
|
|
7371
7893
|
contextId,
|
|
7372
7894
|
undoRedoPersistenceKey,
|