@twick/timeline 0.14.0 → 0.14.3

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.
@@ -2,66 +2,318 @@ import { TrackJSON } from '../../types';
2
2
  import { TrackElement } from '../elements/base.element';
3
3
  import { TrackFriend } from './track.friend';
4
4
 
5
+ /**
6
+ * Track class represents a timeline track that contains multiple elements.
7
+ * A track is a container for timeline elements (video, audio, text, etc.) that
8
+ * can be arranged sequentially or in parallel. Tracks provide validation,
9
+ * serialization, and element management capabilities.
10
+ *
11
+ * @example
12
+ * ```js
13
+ * import { Track, VideoElement, TextElement } from '@twick/timeline';
14
+ *
15
+ * // Create a new track
16
+ * const videoTrack = new Track("Video Track");
17
+ *
18
+ * // Add elements to the track
19
+ * const videoElement = new VideoElement({
20
+ * src: "video.mp4",
21
+ * start: 0,
22
+ * end: 10
23
+ * });
24
+ *
25
+ * videoTrack.createFriend().addElement(videoElement);
26
+ *
27
+ * // Serialize the track
28
+ * const trackData = videoTrack.serialize();
29
+ * ```
30
+ */
5
31
  export declare class Track {
6
32
  private id;
7
33
  private name;
8
34
  private type;
9
35
  private elements;
10
36
  private validator;
37
+ /**
38
+ * Creates a new Track instance.
39
+ *
40
+ * @param name - The display name for the track
41
+ * @param id - Optional unique identifier (auto-generated if not provided)
42
+ *
43
+ * @example
44
+ * ```js
45
+ * const track = new Track("My Video Track");
46
+ * const trackWithId = new Track("Audio Track", "audio-track-1");
47
+ * ```
48
+ */
11
49
  constructor(name: string, id?: string);
12
50
  /**
13
- * Create a friend instance for explicit access to protected methods
14
- * This implements the Friend Class Pattern
15
- * @returns TrackFriend instance
51
+ * Creates a friend instance for explicit access to protected methods.
52
+ * This implements the Friend Class Pattern to allow controlled access
53
+ * to protected methods while maintaining encapsulation.
54
+ *
55
+ * @returns TrackFriend instance that can access protected methods
56
+ *
57
+ * @example
58
+ * ```js
59
+ * const track = new Track("My Track");
60
+ * const friend = track.createFriend();
61
+ *
62
+ * // Use friend to add elements
63
+ * const element = new VideoElement({ src: "video.mp4", start: 0, end: 10 });
64
+ * friend.addElement(element);
65
+ * ```
16
66
  */
17
67
  createFriend(): TrackFriend;
18
68
  /**
19
- * Friend method to add element (called by TrackFriend)
20
- * @param element The element to add
21
- * @param skipValidation If true, skips validation
69
+ * Friend method to add element (called by TrackFriend).
70
+ * Provides controlled access to the protected addElement method.
71
+ *
72
+ * @param element - The element to add to the track
73
+ * @param skipValidation - If true, skips validation (use with caution)
22
74
  * @returns true if element was added successfully
75
+ *
76
+ * @example
77
+ * ```js
78
+ * const track = new Track("My Track");
79
+ * const friend = track.createFriend();
80
+ * const element = new VideoElement({ src: "video.mp4", start: 0, end: 10 });
81
+ *
82
+ * const success = track.addElementViaFriend(element);
83
+ * // success = true if element was added successfully
84
+ * ```
23
85
  */
24
86
  addElementViaFriend(element: TrackElement, skipValidation?: boolean): boolean;
25
87
  /**
26
- * Friend method to remove element (called by TrackFriend)
27
- * @param element The element to remove
88
+ * Friend method to remove element (called by TrackFriend).
89
+ * Provides controlled access to the protected removeElement method.
90
+ *
91
+ * @param element - The element to remove from the track
92
+ *
93
+ * @example
94
+ * ```js
95
+ * const track = new Track("My Track");
96
+ * const element = new VideoElement({ src: "video.mp4", start: 0, end: 10 });
97
+ *
98
+ * track.removeElementViaFriend(element);
99
+ * // Element is removed from the track
100
+ * ```
28
101
  */
29
102
  removeElementViaFriend(element: TrackElement): void;
30
103
  /**
31
- * Friend method to update element (called by TrackFriend)
32
- * @param element The element to update
104
+ * Friend method to update element (called by TrackFriend).
105
+ * Provides controlled access to the protected updateElement method.
106
+ *
107
+ * @param element - The updated element to replace the existing one
33
108
  * @returns true if element was updated successfully
109
+ *
110
+ * @example
111
+ * ```js
112
+ * const track = new Track("My Track");
113
+ * const element = new VideoElement({ src: "video.mp4", start: 0, end: 10 });
114
+ *
115
+ * // Update the element
116
+ * element.setEnd(15);
117
+ * const success = track.updateElementViaFriend(element);
118
+ * // success = true if element was updated successfully
119
+ * ```
34
120
  */
35
121
  updateElementViaFriend(element: TrackElement): boolean;
122
+ /**
123
+ * Gets the unique identifier of the track.
124
+ *
125
+ * @returns The track's unique ID string
126
+ *
127
+ * @example
128
+ * ```js
129
+ * const track = new Track("My Track", "track-123");
130
+ * const id = track.getId(); // "track-123"
131
+ * ```
132
+ */
36
133
  getId(): string;
134
+ /**
135
+ * Gets the display name of the track.
136
+ *
137
+ * @returns The track's display name
138
+ *
139
+ * @example
140
+ * ```js
141
+ * const track = new Track("Video Track");
142
+ * const name = track.getName(); // "Video Track"
143
+ * ```
144
+ */
37
145
  getName(): string;
146
+ /**
147
+ * Gets the type of the track.
148
+ *
149
+ * @returns The track's type string
150
+ *
151
+ * @example
152
+ * ```js
153
+ * const track = new Track("My Track");
154
+ * const type = track.getType(); // "element"
155
+ * ```
156
+ */
38
157
  getType(): string;
158
+ /**
159
+ * Gets a read-only array of all elements in the track.
160
+ * Returns a copy of the elements array to prevent external modification.
161
+ *
162
+ * @returns Read-only array of track elements
163
+ *
164
+ * @example
165
+ * ```js
166
+ * const track = new Track("My Track");
167
+ * const elements = track.getElements();
168
+ * // elements is a read-only array of TrackElement instances
169
+ *
170
+ * elements.forEach(element => {
171
+ * console.log(`Element: ${element.getId()}, Duration: ${element.getEnd() - element.getStart()}`);
172
+ * });
173
+ * ```
174
+ */
39
175
  getElements(): ReadonlyArray<TrackElement>;
40
176
  /**
41
- * Validates an element
42
- * @param element The element to validate
177
+ * Validates a single element using the track's validator.
178
+ * Checks if the element meets all validation requirements.
179
+ *
180
+ * @param element - The element to validate
43
181
  * @returns true if valid, throws ValidationError if invalid
182
+ *
183
+ * @example
184
+ * ```js
185
+ * const track = new Track("My Track");
186
+ * const element = new VideoElement({ src: "video.mp4", start: 0, end: 10 });
187
+ *
188
+ * try {
189
+ * const isValid = track.validateElement(element);
190
+ * console.log('Element is valid:', isValid);
191
+ * } catch (error) {
192
+ * if (error instanceof ValidationError) {
193
+ * console.log('Validation failed:', error.errors);
194
+ * }
195
+ * }
196
+ * ```
44
197
  */
45
198
  validateElement(element: TrackElement): boolean;
199
+ /**
200
+ * Gets the total duration of the track.
201
+ * Calculates the duration based on the end time of the last element.
202
+ *
203
+ * @returns The total duration of the track in seconds
204
+ *
205
+ * @example
206
+ * ```js
207
+ * const track = new Track("My Track");
208
+ * const duration = track.getTrackDuration(); // 0 if no elements
209
+ *
210
+ * // After adding elements
211
+ * const element = new VideoElement({ src: "video.mp4", start: 0, end: 30 });
212
+ * track.createFriend().addElement(element);
213
+ * const newDuration = track.getTrackDuration(); // 30
214
+ * ```
215
+ */
46
216
  getTrackDuration(): number;
47
217
  /**
48
- * Adds an element to the track with validation
49
- * @param element The element to add
50
- * @param skipValidation If true, skips validation (use with caution)
218
+ * Adds an element to the track with validation.
219
+ * Protected method that should be accessed through TrackFriend.
220
+ *
221
+ * @param element - The element to add to the track
222
+ * @param skipValidation - If true, skips validation (use with caution)
51
223
  * @returns true if element was added successfully, throws ValidationError if validation fails
224
+ *
225
+ * @example
226
+ * ```js
227
+ * const track = new Track("My Track");
228
+ * const element = new VideoElement({ src: "video.mp4", start: 0, end: 10 });
229
+ *
230
+ * // Use friend to access this protected method
231
+ * const friend = track.createFriend();
232
+ * const success = friend.addElement(element);
233
+ * ```
52
234
  */
53
235
  protected addElement(element: TrackElement, skipValidation?: boolean): boolean;
236
+ /**
237
+ * Removes an element from the track.
238
+ * Protected method that should be accessed through TrackFriend.
239
+ *
240
+ * @param element - The element to remove from the track
241
+ *
242
+ * @example
243
+ * ```js
244
+ * const track = new Track("My Track");
245
+ * const element = new VideoElement({ src: "video.mp4", start: 0, end: 10 });
246
+ *
247
+ * // Use friend to access this protected method
248
+ * const friend = track.createFriend();
249
+ * friend.removeElement(element);
250
+ * ```
251
+ */
54
252
  protected removeElement(element: TrackElement): void;
55
253
  /**
56
- * Updates an element in the track with validation
57
- * @param element The element to update
254
+ * Updates an element in the track with validation.
255
+ * Protected method that should be accessed through TrackFriend.
256
+ *
257
+ * @param element - The updated element to replace the existing one
58
258
  * @returns true if element was updated successfully, throws ValidationError if validation fails
259
+ *
260
+ * @example
261
+ * ```js
262
+ * const track = new Track("My Track");
263
+ * const element = new VideoElement({ src: "video.mp4", start: 0, end: 10 });
264
+ *
265
+ * // Use friend to access this protected method
266
+ * const friend = track.createFriend();
267
+ * element.setEnd(15);
268
+ * const success = friend.updateElement(element);
269
+ * ```
59
270
  */
60
271
  protected updateElement(element: TrackElement): boolean;
272
+ /**
273
+ * Finds an element in the track by its ID.
274
+ *
275
+ * @param id - The unique identifier of the element to find
276
+ * @returns The found element or undefined if not found
277
+ *
278
+ * @example
279
+ * ```js
280
+ * const track = new Track("My Track");
281
+ * const element = new VideoElement({ src: "video.mp4", start: 0, end: 10 });
282
+ * track.createFriend().addElement(element);
283
+ *
284
+ * const foundElement = track.getElementById(element.getId());
285
+ * // foundElement is the same element instance
286
+ * ```
287
+ */
61
288
  getElementById(id: string): Readonly<TrackElement> | undefined;
62
289
  /**
63
- * Validates all elements in the track and returns combined result and per-element status
290
+ * Validates all elements in the track and returns combined result and per-element status.
291
+ * Provides detailed validation information for each element including errors and warnings.
292
+ *
64
293
  * @returns Object with overall isValid and array of per-element validation results
294
+ *
295
+ * @example
296
+ * ```js
297
+ * const track = new Track("My Track");
298
+ * const element1 = new VideoElement({ src: "video.mp4", start: 0, end: 10 });
299
+ * const element2 = new TextElement({ text: "Hello", start: 5, end: 15 });
300
+ *
301
+ * track.createFriend().addElement(element1);
302
+ * track.createFriend().addElement(element2);
303
+ *
304
+ * const validation = track.validateAllElements();
305
+ * console.log('Overall valid:', validation.isValid);
306
+ *
307
+ * validation.results.forEach(result => {
308
+ * console.log(`Element ${result.element.getId()}: ${result.isValid ? 'Valid' : 'Invalid'}`);
309
+ * if (result.errors) {
310
+ * console.log('Errors:', result.errors);
311
+ * }
312
+ * if (result.warnings) {
313
+ * console.log('Warnings:', result.warnings);
314
+ * }
315
+ * });
316
+ * ```
65
317
  */
66
318
  validateAllElements(): {
67
319
  isValid: boolean;
@@ -72,6 +324,59 @@ export declare class Track {
72
324
  warnings?: string[];
73
325
  }>;
74
326
  };
327
+ /**
328
+ * Serializes the track and all its elements to JSON format.
329
+ * Converts the track structure to a format that can be stored or transmitted.
330
+ *
331
+ * @returns TrackJSON object representing the track and its elements
332
+ *
333
+ * @example
334
+ * ```js
335
+ * const track = new Track("My Track");
336
+ * const element = new VideoElement({ src: "video.mp4", start: 0, end: 10 });
337
+ * track.createFriend().addElement(element);
338
+ *
339
+ * const trackData = track.serialize();
340
+ * // trackData = {
341
+ * // id: "t-abc123",
342
+ * // name: "My Track",
343
+ * // type: "element",
344
+ * // elements: [{ ... }]
345
+ * // }
346
+ *
347
+ * // Save to localStorage
348
+ * localStorage.setItem('track-data', JSON.stringify(trackData));
349
+ * ```
350
+ */
75
351
  serialize(): TrackJSON;
352
+ /**
353
+ * Creates a Track instance from JSON data.
354
+ * Static factory method for deserializing track data.
355
+ *
356
+ * @param json - JSON object containing track data
357
+ * @returns New Track instance with loaded data
358
+ *
359
+ * @example
360
+ * ```js
361
+ * const trackData = {
362
+ * id: "t-abc123",
363
+ * name: "My Track",
364
+ * type: "element",
365
+ * elements: [
366
+ * {
367
+ * id: "e-def456",
368
+ * type: "video",
369
+ * src: "video.mp4",
370
+ * start: 0,
371
+ * end: 10
372
+ * }
373
+ * ]
374
+ * };
375
+ *
376
+ * const track = Track.fromJSON(trackData);
377
+ * console.log(track.getName()); // "My Track"
378
+ * console.log(track.getElements().length); // 1
379
+ * ```
380
+ */
76
381
  static fromJSON(json: any): Track;
77
382
  }
@@ -10,20 +10,140 @@ import { RectElement } from '../elements/rect.element';
10
10
  import { Track } from '../track/track';
11
11
 
12
12
  /**
13
- * ElementAdder visitor for adding elements to tracks
13
+ * ElementAdder visitor for adding elements to tracks.
14
14
  * Uses the visitor pattern to handle different element types
15
- * Implements the Friend Class Pattern for explicit access control
15
+ * and implements the Friend Class Pattern for explicit access control.
16
+ * Automatically calculates start and end times for elements based on
17
+ * existing track content.
16
18
  */
17
19
  export declare class ElementAdder implements ElementVisitor<Promise<boolean>> {
18
20
  private track;
19
21
  private trackFriend;
22
+ /**
23
+ * Creates a new ElementAdder instance for the specified track.
24
+ *
25
+ * @param track - The track to add elements to
26
+ *
27
+ * @example
28
+ * ```js
29
+ * const adder = new ElementAdder(track);
30
+ * const success = await adder.visitVideoElement(videoElement);
31
+ * ```
32
+ */
20
33
  constructor(track: Track);
34
+ /**
35
+ * Adds a video element to the track.
36
+ * Updates video metadata and calculates appropriate start/end times
37
+ * based on existing track elements.
38
+ *
39
+ * @param element - The video element to add
40
+ * @returns Promise resolving to true if element was added successfully
41
+ *
42
+ * @example
43
+ * ```js
44
+ * const success = await adder.visitVideoElement(videoElement);
45
+ * // success = true if element was added successfully
46
+ * ```
47
+ */
21
48
  visitVideoElement(element: VideoElement): Promise<boolean>;
49
+ /**
50
+ * Adds an audio element to the track.
51
+ * Updates audio metadata and calculates appropriate start/end times
52
+ * based on existing track elements.
53
+ *
54
+ * @param element - The audio element to add
55
+ * @returns Promise resolving to true if element was added successfully
56
+ *
57
+ * @example
58
+ * ```js
59
+ * const success = await adder.visitAudioElement(audioElement);
60
+ * // success = true if element was added successfully
61
+ * ```
62
+ */
22
63
  visitAudioElement(element: AudioElement): Promise<boolean>;
64
+ /**
65
+ * Adds an image element to the track.
66
+ * Updates image metadata and calculates appropriate start/end times
67
+ * based on existing track elements.
68
+ *
69
+ * @param element - The image element to add
70
+ * @returns Promise resolving to true if element was added successfully
71
+ *
72
+ * @example
73
+ * ```js
74
+ * const success = await adder.visitImageElement(imageElement);
75
+ * // success = true if element was added successfully
76
+ * ```
77
+ */
23
78
  visitImageElement(element: ImageElement): Promise<boolean>;
79
+ /**
80
+ * Adds a text element to the track.
81
+ * Calculates appropriate start/end times based on existing track elements.
82
+ *
83
+ * @param element - The text element to add
84
+ * @returns Promise resolving to true if element was added successfully
85
+ *
86
+ * @example
87
+ * ```js
88
+ * const success = await adder.visitTextElement(textElement);
89
+ * // success = true if element was added successfully
90
+ * ```
91
+ */
24
92
  visitTextElement(element: TextElement): Promise<boolean>;
93
+ /**
94
+ * Adds a caption element to the track.
95
+ * Calculates appropriate start/end times based on existing track elements.
96
+ *
97
+ * @param element - The caption element to add
98
+ * @returns Promise resolving to true if element was added successfully
99
+ *
100
+ * @example
101
+ * ```js
102
+ * const success = await adder.visitCaptionElement(captionElement);
103
+ * // success = true if element was added successfully
104
+ * ```
105
+ */
25
106
  visitCaptionElement(element: CaptionElement): Promise<boolean>;
107
+ /**
108
+ * Adds an icon element to the track.
109
+ * Calculates appropriate start/end times based on existing track elements.
110
+ *
111
+ * @param element - The icon element to add
112
+ * @returns Promise resolving to true if element was added successfully
113
+ *
114
+ * @example
115
+ * ```js
116
+ * const success = await adder.visitIconElement(iconElement);
117
+ * // success = true if element was added successfully
118
+ * ```
119
+ */
26
120
  visitIconElement(element: IconElement): Promise<boolean>;
121
+ /**
122
+ * Adds a circle element to the track.
123
+ * Calculates appropriate start/end times based on existing track elements.
124
+ *
125
+ * @param element - The circle element to add
126
+ * @returns Promise resolving to true if element was added successfully
127
+ *
128
+ * @example
129
+ * ```js
130
+ * const success = await adder.visitCircleElement(circleElement);
131
+ * // success = true if element was added successfully
132
+ * ```
133
+ */
27
134
  visitCircleElement(element: CircleElement): Promise<boolean>;
135
+ /**
136
+ * Adds a rectangle element to the track.
137
+ * Calculates appropriate start/end times based on existing track elements.
138
+ *
139
+ * @param element - The rectangle element to add
140
+ * @returns Promise resolving to true if element was added successfully
141
+ *
142
+ * @example
143
+ * ```js
144
+ * const success = await adder.visitRectElement(rectElement);
145
+ * // success = true if element was added successfully
146
+ * ```
147
+ */
28
148
  visitRectElement(element: RectElement): Promise<boolean>;
29
149
  }